1 /*
2 Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23 /* cJSON */
24 /* JSON parser in C. */
25
26 /* disable warnings about old C89 functions in MSVC */
27 #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
28 #define _CRT_SECURE_NO_DEPRECATE
29 #endif
30
31 #ifdef __GNUC__
32 #pragma GCC visibility push(default)
33 #endif
34 #if defined(_MSC_VER)
35 #pragma warning(push)
36 /* disable warning about single line comments in system headers */
37 #pragma warning(disable : 4001)
38 #endif
39
40 #include <string.h>
41 #include <stdio.h>
42 #include <math.h>
43 #include <stdlib.h>
44 #include <limits.h>
45 #include <ctype.h>
46 #include <float.h>
47
48 #ifdef ENABLE_LOCALES
49 #include <locale.h>
50 #endif
51
52 #if defined(_MSC_VER)
53 #pragma warning(pop)
54 #endif
55 #ifdef __GNUC__
56 #pragma GCC visibility pop
57 #endif
58
59 #include "cJSON.h"
60
61 #include <vulkan/vulkan_core.h>
62
63 #include "allocation.h"
64
65 /* define our own boolean type */
66 #ifdef true
67 #undef true
68 #endif
69 #define true ((cJSON_bool)1)
70
71 #ifdef false
72 #undef false
73 #endif
74 #define false ((cJSON_bool)0)
75
76 /* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
77 #ifndef isinf
78 #define isinf(d) (isnan((d - d)) && !isnan(d))
79 #endif
80 #ifndef isnan
81 #define isnan(d) (d != d)
82 #endif
83
84 #ifndef NAN
85 #ifdef _WIN32
86 #define NAN sqrt(-1.0)
87 #else
88 #define NAN 0.0 / 0.0
89 #endif
90 #endif
91
92 typedef struct {
93 const unsigned char *json;
94 size_t position;
95 } error;
96 static error global_error = {NULL, 0};
97
cJSON_GetErrorPtr(void)98 CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) { return (const char *)(global_error.json + global_error.position); }
99
loader_cJSON_GetStringValue(const cJSON * const item)100 CJSON_PUBLIC(char *) loader_cJSON_GetStringValue(const cJSON *const item) {
101 if (!loader_cJSON_IsString(item)) {
102 return NULL;
103 }
104
105 return item->valuestring;
106 }
107
loader_cJSON_GetNumberValue(const cJSON * const item)108 CJSON_PUBLIC(double) loader_cJSON_GetNumberValue(const cJSON *const item) {
109 if (!loader_cJSON_IsNumber(item)) {
110 return (double)NAN;
111 }
112
113 return item->valuedouble;
114 }
115
116 /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
117 #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 18)
118 #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
119 #endif
120
121 /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
case_insensitive_strcmp(const unsigned char * string1,const unsigned char * string2)122 static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) {
123 if ((string1 == NULL) || (string2 == NULL)) {
124 return 1;
125 }
126
127 if (string1 == string2) {
128 return 0;
129 }
130
131 for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++) {
132 if (*string1 == '\0') {
133 return 0;
134 }
135 }
136
137 return tolower(*string1) - tolower(*string2);
138 }
139
140 /* strlen of character literals resolved at compile time */
141 #define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
142
143 /* Internal constructor. */
cJSON_New_Item(const VkAllocationCallbacks * pAllocator)144 static cJSON *cJSON_New_Item(const VkAllocationCallbacks *pAllocator) {
145 cJSON *node = (cJSON *)loader_calloc(pAllocator, sizeof(cJSON), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
146 if (NULL != node) {
147 node->pAllocator = pAllocator;
148 }
149 return node;
150 }
151
152 /* Delete a cJSON structure. */
CJSON_PUBLIC(void)153 TEST_FUNCTION_EXPORT CJSON_PUBLIC(void) loader_cJSON_Delete(cJSON *item) {
154 cJSON *next = NULL;
155 while (item != NULL) {
156 next = item->next;
157 if (!(item->type & cJSON_IsReference) && (item->child != NULL)) {
158 loader_cJSON_Delete(item->child);
159 }
160 if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) {
161 loader_free(item->pAllocator, item->valuestring);
162 item->valuestring = NULL;
163 }
164 if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) {
165 loader_free(item->pAllocator, item->string);
166 item->string = NULL;
167 }
168 loader_free(item->pAllocator, item);
169 item = next;
170 }
171 }
172
173 /* get the decimal point character of the current locale */
get_decimal_point(void)174 static unsigned char get_decimal_point(void) {
175 #ifdef ENABLE_LOCALES
176 struct lconv *lconv = localeconv();
177 return (unsigned char)lconv->decimal_point[0];
178 #else
179 return '.';
180 #endif
181 }
182
183 typedef struct {
184 const unsigned char *content;
185 size_t length;
186 size_t offset;
187 size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
188 const VkAllocationCallbacks *pAllocator;
189 } parse_buffer;
190
191 /* check if the given size is left to read in a given parse buffer (starting with 1) */
192 #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
193 /* check if the buffer can be accessed at the given index (starting with 0) */
194 #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
195 #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
196 /* get a pointer to the buffer at the position */
197 #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
198
199 /* Parse the input text to generate a number, and populate the result into item. */
parse_number(cJSON * const item,parse_buffer * const input_buffer)200 static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer) {
201 double number = 0;
202 unsigned char *after_end = NULL;
203 unsigned char number_c_string[64];
204 unsigned char decimal_point = get_decimal_point();
205 size_t i = 0;
206
207 if ((input_buffer == NULL) || (input_buffer->content == NULL)) {
208 return false;
209 }
210
211 /* copy the number into a temporary buffer and replace '.' with the decimal point
212 * of the current locale (for strtod)
213 * This also takes care of '\0' not necessarily being available for marking the end of the input */
214 for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) {
215 switch (buffer_at_offset(input_buffer)[i]) {
216 case '0':
217 case '1':
218 case '2':
219 case '3':
220 case '4':
221 case '5':
222 case '6':
223 case '7':
224 case '8':
225 case '9':
226 case '+':
227 case '-':
228 case 'e':
229 case 'E':
230 number_c_string[i] = buffer_at_offset(input_buffer)[i];
231 break;
232
233 case '.':
234 number_c_string[i] = decimal_point;
235 break;
236
237 default:
238 goto loop_end;
239 }
240 }
241 loop_end:
242 number_c_string[i] = '\0';
243
244 number = strtod((const char *)number_c_string, (char **)&after_end);
245 if (number_c_string == after_end) {
246 return false; /* parse_error */
247 }
248
249 item->valuedouble = number;
250
251 /* use saturation in case of overflow */
252 if (number >= INT_MAX) {
253 item->valueint = INT_MAX;
254 } else if (number <= (double)INT_MIN) {
255 item->valueint = INT_MIN;
256 } else {
257 item->valueint = (int)number;
258 }
259
260 item->type = cJSON_Number;
261
262 input_buffer->offset += (size_t)(after_end - number_c_string);
263 return true;
264 }
265
266 typedef struct {
267 unsigned char *buffer;
268 size_t length;
269 size_t offset;
270 size_t depth; /* current nesting depth (for formatted printing) */
271 cJSON_bool noalloc;
272 cJSON_bool format; /* is this print a formatted print */
273 const VkAllocationCallbacks *pAllocator;
274 } printbuffer;
275
276 /* realloc printbuffer if necessary to have at least "needed" bytes more */
ensure(printbuffer * const p,size_t needed,bool * out_of_memory)277 static unsigned char *ensure(printbuffer *const p, size_t needed, bool *out_of_memory) {
278 unsigned char *newbuffer = NULL;
279 size_t newsize = 0;
280
281 if ((p == NULL) || (p->buffer == NULL)) {
282 return NULL;
283 }
284
285 if ((p->length > 0) && (p->offset >= p->length)) {
286 /* make sure that offset is valid */
287 return NULL;
288 }
289
290 if (needed > INT_MAX) {
291 /* sizes bigger than INT_MAX are currently not supported */
292 return NULL;
293 }
294
295 needed += p->offset + 1;
296 if (needed <= p->length) {
297 return p->buffer + p->offset;
298 }
299
300 if (p->noalloc) {
301 return NULL;
302 }
303
304 /* calculate new buffer size */
305 if (needed > (INT_MAX / 2)) {
306 /* overflow of int, use INT_MAX if possible */
307 if (needed <= INT_MAX) {
308 newsize = INT_MAX;
309 } else {
310 return NULL;
311 }
312 } else {
313 newsize = needed * 2;
314 }
315
316 newbuffer = (unsigned char *)loader_realloc(p->pAllocator, p->buffer, p->length, newsize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
317 if (newbuffer == NULL) {
318 *out_of_memory = true;
319 loader_free(p->pAllocator, p->buffer);
320 p->length = 0;
321 p->buffer = NULL;
322
323 return NULL;
324 }
325
326 p->length = newsize;
327 p->buffer = newbuffer;
328
329 return newbuffer + p->offset;
330 }
331
332 /* calculate the new length of the string in a printbuffer and update the offset */
update_offset(printbuffer * const buffer)333 static void update_offset(printbuffer *const buffer) {
334 const unsigned char *buffer_pointer = NULL;
335 if ((buffer == NULL) || (buffer->buffer == NULL)) {
336 return;
337 }
338 buffer_pointer = buffer->buffer + buffer->offset;
339
340 buffer->offset += strlen((const char *)buffer_pointer);
341 }
342
343 /* securely comparison of floating-point variables */
compare_double(double a,double b)344 static cJSON_bool compare_double(double a, double b) {
345 double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
346 return (fabs(a - b) <= maxVal * DBL_EPSILON);
347 }
348
349 /* Render the number nicely from the given item into a string. */
print_number(const cJSON * const item,printbuffer * const output_buffer,bool * out_of_memory)350 static cJSON_bool print_number(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
351 unsigned char *output_pointer = NULL;
352 double d = item->valuedouble;
353 int length = 0;
354 size_t i = 0;
355 unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
356 unsigned char decimal_point = get_decimal_point();
357 double test = 0.0;
358
359 if (output_buffer == NULL) {
360 return false;
361 }
362
363 /* This checks for NaN and Infinity */
364 if (isnan(d) || isinf(d)) {
365 length = snprintf((char *)number_buffer, 26, "null");
366 } else if (d == (double)item->valueint) {
367 length = snprintf((char *)number_buffer, 26, "%d", item->valueint);
368 } else {
369 /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
370 length = snprintf((char *)number_buffer, 26, "%1.15g", d);
371
372 /* Check whether the original double can be recovered */
373 if ((sscanf((char *)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) {
374 /* If not, print with 17 decimal places of precision */
375 length = snprintf((char *)number_buffer, 26, "%1.17g", d);
376 }
377 }
378
379 /* snprintf failed or buffer overrun occurred */
380 if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) {
381 return false;
382 }
383
384 /* reserve appropriate space in the output */
385 output_pointer = ensure(output_buffer, (size_t)length + sizeof(""), out_of_memory);
386 if (output_pointer == NULL) {
387 return false;
388 }
389
390 /* copy the printed number to the output and replace locale
391 * dependent decimal point with '.' */
392 for (i = 0; i < ((size_t)length); i++) {
393 if (number_buffer[i] == decimal_point) {
394 output_pointer[i] = '.';
395 continue;
396 }
397
398 output_pointer[i] = number_buffer[i];
399 }
400 output_pointer[i] = '\0';
401
402 output_buffer->offset += (size_t)length;
403
404 return true;
405 }
406
407 /* parse 4 digit hexadecimal number */
parse_hex4(const unsigned char * const input)408 static unsigned parse_hex4(const unsigned char *const input) {
409 unsigned int h = 0;
410 size_t i = 0;
411
412 for (i = 0; i < 4; i++) {
413 /* parse digit */
414 if ((input[i] >= '0') && (input[i] <= '9')) {
415 h += (unsigned int)input[i] - '0';
416 } else if ((input[i] >= 'A') && (input[i] <= 'F')) {
417 h += (unsigned int)10 + input[i] - 'A';
418 } else if ((input[i] >= 'a') && (input[i] <= 'f')) {
419 h += (unsigned int)10 + input[i] - 'a';
420 } else /* invalid */
421 {
422 return 0;
423 }
424
425 if (i < 3) {
426 /* shift left to make place for the next nibble */
427 h = h << 4;
428 }
429 }
430
431 return h;
432 }
433
434 /* converts a UTF-16 literal to UTF-8
435 * A literal can be one or two sequences of the form \uXXXX */
utf16_literal_to_utf8(const unsigned char * const input_pointer,const unsigned char * const input_end,unsigned char ** output_pointer)436 static unsigned char utf16_literal_to_utf8(const unsigned char *const input_pointer, const unsigned char *const input_end,
437 unsigned char **output_pointer) {
438 long unsigned int codepoint = 0;
439 unsigned int first_code = 0;
440 const unsigned char *first_sequence = input_pointer;
441 unsigned char utf8_length = 0;
442 unsigned char utf8_position = 0;
443 unsigned char sequence_length = 0;
444 unsigned char first_byte_mark = 0;
445
446 if ((input_end - first_sequence) < 6) {
447 /* input ends unexpectedly */
448 goto fail;
449 }
450
451 /* get the first utf16 sequence */
452 first_code = parse_hex4(first_sequence + 2);
453
454 /* check that the code is valid */
455 if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) {
456 goto fail;
457 }
458
459 /* UTF16 surrogate pair */
460 if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) {
461 const unsigned char *second_sequence = first_sequence + 6;
462 unsigned int second_code = 0;
463 sequence_length = 12; /* \uXXXX\uXXXX */
464
465 if ((input_end - second_sequence) < 6) {
466 /* input ends unexpectedly */
467 goto fail;
468 }
469
470 if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) {
471 /* missing second half of the surrogate pair */
472 goto fail;
473 }
474
475 /* get the second utf16 sequence */
476 second_code = parse_hex4(second_sequence + 2);
477 /* check that the code is valid */
478 if ((second_code < 0xDC00) || (second_code > 0xDFFF)) {
479 /* invalid second half of the surrogate pair */
480 goto fail;
481 }
482
483 /* calculate the unicode codepoint from the surrogate pair */
484 codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
485 } else {
486 sequence_length = 6; /* \uXXXX */
487 codepoint = first_code;
488 }
489
490 /* encode as UTF-8
491 * takes at maximum 4 bytes to encode:
492 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
493 if (codepoint < 0x80) {
494 /* normal ascii, encoding 0xxxxxxx */
495 utf8_length = 1;
496 } else if (codepoint < 0x800) {
497 /* two bytes, encoding 110xxxxx 10xxxxxx */
498 utf8_length = 2;
499 first_byte_mark = 0xC0; /* 11000000 */
500 } else if (codepoint < 0x10000) {
501 /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
502 utf8_length = 3;
503 first_byte_mark = 0xE0; /* 11100000 */
504 } else if (codepoint <= 0x10FFFF) {
505 /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
506 utf8_length = 4;
507 first_byte_mark = 0xF0; /* 11110000 */
508 } else {
509 /* invalid unicode codepoint */
510 goto fail;
511 }
512
513 /* encode as utf8 */
514 for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) {
515 /* 10xxxxxx */
516 (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
517 codepoint >>= 6;
518 }
519 /* encode first byte */
520 if (utf8_length > 1) {
521 (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
522 } else {
523 (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
524 }
525
526 *output_pointer += utf8_length;
527
528 return sequence_length;
529
530 fail:
531 return 0;
532 }
533
534 /* Parse the input text into an unescaped cinput, and populate item. */
parse_string(cJSON * const item,parse_buffer * const input_buffer,bool * out_of_memory)535 static cJSON_bool parse_string(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
536 const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
537 const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
538 unsigned char *output_pointer = NULL;
539 unsigned char *output = NULL;
540
541 /* not a string */
542 if (buffer_at_offset(input_buffer)[0] != '\"') {
543 goto fail;
544 }
545
546 {
547 /* calculate approximate size of the output (overestimate) */
548 size_t allocation_length = 0;
549 size_t skipped_bytes = 0;
550 while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) {
551 /* is escape sequence */
552 if (input_end[0] == '\\') {
553 if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) {
554 /* prevent buffer overflow when last input character is a backslash */
555 goto fail;
556 }
557 skipped_bytes++;
558 input_end++;
559 }
560 input_end++;
561 }
562 if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) {
563 goto fail; /* string ended unexpectedly */
564 }
565
566 /* This is at most how much we need for the output */
567 allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
568 output = (unsigned char *)loader_calloc(input_buffer->pAllocator, allocation_length + sizeof(""),
569 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
570 if (output == NULL) {
571 *out_of_memory = true;
572 goto fail; /* allocation failure */
573 }
574 }
575
576 output_pointer = output;
577 /* loop through the string literal */
578 while (input_pointer < input_end) {
579 if (*input_pointer != '\\') {
580 *output_pointer++ = *input_pointer++;
581 }
582 /* escape sequence */
583 else {
584 unsigned char sequence_length = 2;
585 if ((input_end - input_pointer) < 1) {
586 goto fail;
587 }
588
589 switch (input_pointer[1]) {
590 case 'b':
591 *output_pointer++ = '\b';
592 break;
593 case 'f':
594 *output_pointer++ = '\f';
595 break;
596 case 'n':
597 *output_pointer++ = '\n';
598 break;
599 case 'r':
600 *output_pointer++ = '\r';
601 break;
602 case 't':
603 *output_pointer++ = '\t';
604 break;
605 case '\"':
606 case '\\':
607 case '/':
608 *output_pointer++ = input_pointer[1];
609 break;
610
611 /* UTF-16 literal */
612 case 'u':
613 sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
614 if (sequence_length == 0) {
615 /* failed to convert UTF16-literal to UTF-8 */
616 goto fail;
617 }
618 break;
619
620 default:
621 goto fail;
622 }
623 input_pointer += sequence_length;
624 }
625 }
626
627 /* zero terminate the output */
628 *output_pointer = '\0';
629
630 item->type = cJSON_String;
631 item->valuestring = (char *)output;
632
633 input_buffer->offset = (size_t)(input_end - input_buffer->content);
634 input_buffer->offset++;
635
636 return true;
637
638 fail:
639 if (output != NULL) {
640 loader_free(input_buffer->pAllocator, output);
641 output = NULL;
642 }
643
644 if (input_pointer != NULL) {
645 input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
646 }
647
648 return false;
649 }
650
651 /* Render the cstring provided to an escaped version that can be printed. */
print_string_ptr(const unsigned char * const input,printbuffer * const output_buffer,bool * out_of_memory)652 static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer, bool *out_of_memory) {
653 const unsigned char *input_pointer = NULL;
654 unsigned char *output = NULL;
655 unsigned char *output_pointer = NULL;
656 size_t output_length = 0;
657 /* numbers of additional characters needed for escaping */
658 size_t escape_characters = 0;
659
660 if (output_buffer == NULL) {
661 return false;
662 }
663
664 /* empty string */
665 if (input == NULL) {
666 output = ensure(output_buffer, sizeof(""), out_of_memory);
667 if (output == NULL) {
668 return false;
669 }
670
671 return true;
672 }
673
674 /* set "flag" to 1 if something needs to be escaped */
675 for (input_pointer = input; *input_pointer; input_pointer++) {
676 switch (*input_pointer) {
677 case '\"':
678 case '\\':
679 case '\b':
680 case '\f':
681 case '\n':
682 case '\r':
683 case '\t':
684 /* one character escape sequence */
685 escape_characters++;
686 break;
687 default:
688 if (*input_pointer < 32) {
689 /* UTF-16 escape sequence uXXXX */
690 escape_characters += 5;
691 }
692 break;
693 }
694 }
695 output_length = (size_t)(input_pointer - input) + escape_characters;
696
697 output = ensure(output_buffer, output_length + sizeof(""), out_of_memory);
698 if (output == NULL) {
699 return false;
700 }
701
702 /* no characters have to be escaped */
703 if (escape_characters == 0) {
704 memcpy(output, input, output_length);
705 output[output_length] = '\0';
706
707 return true;
708 }
709
710 output_pointer = output;
711 /* copy the string */
712 for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) {
713 if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) {
714 /* normal character, copy */
715 *output_pointer = *input_pointer;
716 } else {
717 // Loader specific modification - don't add a backslash because that will 'double up' any existing back slashes.
718 // This change was added right after vulkan's public release, so while it may not be a problem, there are plenty
719 // of API calls made which might not work if the paths have "\\"" in them
720 /* character needs to be escaped */
721 //*output_pointer++ = '\\';
722 switch (*input_pointer) {
723 case '\\':
724 *output_pointer = '\\';
725 break;
726 case '\"':
727 *output_pointer = '\"';
728 break;
729 case '\b':
730 *output_pointer = '\b';
731 break;
732 case '\f':
733 *output_pointer = '\f';
734 break;
735 case '\n':
736 *output_pointer = '\n';
737 break;
738 case '\r':
739 *output_pointer = '\r';
740 break;
741 case '\t':
742 *output_pointer = '\t';
743 break;
744 default:
745 /* escape and print as unicode codepoint */
746 snprintf((char *)output_pointer, output_length - (size_t)(output_pointer - output), "u%04x", *input_pointer);
747 output_pointer += 4;
748 break;
749 }
750 }
751 }
752 output[output_length] = '\0';
753
754 return true;
755 }
756
757 /* Invoke print_string_ptr (which is useful) on an item. */
print_string(const cJSON * const item,printbuffer * const p,bool * out_of_memory)758 static cJSON_bool print_string(const cJSON *const item, printbuffer *const p, bool *out_of_memory) {
759 return print_string_ptr((unsigned char *)item->valuestring, p, out_of_memory);
760 }
761
762 /* Predeclare these prototypes. */
763 static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory);
764 static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory);
765 static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory);
766 static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory);
767 static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory);
768 static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory);
769
770 /* Utility to jump whitespace and cr/lf */
buffer_skip_whitespace(parse_buffer * const buffer)771 static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer) {
772 if ((buffer == NULL) || (buffer->content == NULL)) {
773 return NULL;
774 }
775
776 if (cannot_access_at_index(buffer, 0)) {
777 return buffer;
778 }
779
780 while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) {
781 buffer->offset++;
782 }
783
784 if (buffer->offset == buffer->length) {
785 buffer->offset--;
786 }
787
788 return buffer;
789 }
790
791 /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
skip_utf8_bom(parse_buffer * const buffer)792 static parse_buffer *skip_utf8_bom(parse_buffer *const buffer) {
793 if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) {
794 return NULL;
795 }
796
797 if (can_access_at_index(buffer, 4) && (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) {
798 buffer->offset += 3;
799 }
800
801 return buffer;
802 }
803
804 CJSON_PUBLIC(cJSON *)
loader_cJSON_ParseWithOpts(const VkAllocationCallbacks * pAllocator,const char * value,const char ** return_parse_end,cJSON_bool require_null_terminated,bool * out_of_memory)805 loader_cJSON_ParseWithOpts(const VkAllocationCallbacks *pAllocator, const char *value, const char **return_parse_end,
806 cJSON_bool require_null_terminated, bool *out_of_memory) {
807 size_t buffer_length;
808
809 if (NULL == value) {
810 return NULL;
811 }
812
813 /* Adding null character size due to require_null_terminated. */
814 buffer_length = strlen(value) + sizeof("");
815
816 return loader_cJSON_ParseWithLengthOpts(pAllocator, value, buffer_length, return_parse_end, require_null_terminated,
817 out_of_memory);
818 }
819
820 /* Parse an object - create a new root, and populate. */
821 CJSON_PUBLIC(cJSON *)
loader_cJSON_ParseWithLengthOpts(const VkAllocationCallbacks * pAllocator,const char * value,size_t buffer_length,const char ** return_parse_end,cJSON_bool require_null_terminated,bool * out_of_memory)822 loader_cJSON_ParseWithLengthOpts(const VkAllocationCallbacks *pAllocator, const char *value, size_t buffer_length,
823 const char **return_parse_end, cJSON_bool require_null_terminated, bool *out_of_memory) {
824 parse_buffer buffer = {0, 0, 0, 0, 0};
825 cJSON *item = NULL;
826
827 /* reset error position */
828 global_error.json = NULL;
829 global_error.position = 0;
830
831 if (value == NULL || 0 == buffer_length) {
832 goto fail;
833 }
834
835 buffer.content = (const unsigned char *)value;
836 buffer.length = buffer_length;
837 buffer.offset = 0;
838 buffer.pAllocator = pAllocator;
839
840 item = cJSON_New_Item(pAllocator);
841 if (item == NULL) /* memory fail */
842 {
843 *out_of_memory = true;
844 goto fail;
845 }
846
847 if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)), out_of_memory)) {
848 /* parse failure. ep is set. */
849 goto fail;
850 }
851
852 /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
853 if (require_null_terminated) {
854 buffer_skip_whitespace(&buffer);
855 if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') {
856 goto fail;
857 }
858 }
859 if (return_parse_end) {
860 *return_parse_end = (const char *)buffer_at_offset(&buffer);
861 }
862
863 return item;
864
865 fail:
866 if (item != NULL) {
867 loader_cJSON_Delete(item);
868 }
869
870 if (value != NULL) {
871 error local_error;
872 local_error.json = (const unsigned char *)value;
873 local_error.position = 0;
874
875 if (buffer.offset < buffer.length) {
876 local_error.position = buffer.offset;
877 } else if (buffer.length > 0) {
878 local_error.position = buffer.length - 1;
879 }
880
881 if (return_parse_end != NULL) {
882 *return_parse_end = (const char *)local_error.json + local_error.position;
883 }
884
885 global_error = local_error;
886 }
887
888 return NULL;
889 }
890
891 /* Default options for loader_cJSON_Parse */
loader_cJSON_Parse(const VkAllocationCallbacks * pAllocator,const char * value,bool * out_of_memory)892 CJSON_PUBLIC(cJSON *) loader_cJSON_Parse(const VkAllocationCallbacks *pAllocator, const char *value, bool *out_of_memory) {
893 return loader_cJSON_ParseWithOpts(pAllocator, value, 0, 0, out_of_memory);
894 }
895
896 CJSON_PUBLIC(cJSON *)
loader_cJSON_ParseWithLength(const VkAllocationCallbacks * pAllocator,const char * value,size_t buffer_length,bool * out_of_memory)897 loader_cJSON_ParseWithLength(const VkAllocationCallbacks *pAllocator, const char *value, size_t buffer_length,
898 bool *out_of_memory) {
899 return loader_cJSON_ParseWithLengthOpts(pAllocator, value, buffer_length, 0, 0, out_of_memory);
900 }
901
902 #define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
903
print(const cJSON * const item,cJSON_bool format,bool * out_of_memory)904 static unsigned char *print(const cJSON *const item, cJSON_bool format, bool *out_of_memory) {
905 static const size_t default_buffer_size = 256;
906 printbuffer buffer[1];
907 unsigned char *printed = NULL;
908
909 memset(buffer, 0, sizeof(buffer));
910
911 /* create buffer */
912 buffer->buffer = (unsigned char *)loader_calloc(item->pAllocator, default_buffer_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
913 buffer->length = default_buffer_size;
914 buffer->format = format;
915 buffer->pAllocator = item->pAllocator;
916 if (buffer->buffer == NULL) {
917 *out_of_memory = true;
918 goto fail;
919 }
920
921 /* print the value */
922 if (!print_value(item, buffer, out_of_memory)) {
923 goto fail;
924 }
925 update_offset(buffer);
926
927 printed = (unsigned char *)loader_realloc(item->pAllocator, buffer->buffer, buffer->length, buffer->offset + 1,
928 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
929 if (printed == NULL) {
930 *out_of_memory = true;
931 goto fail;
932 }
933 buffer->buffer = NULL;
934
935 return printed;
936
937 fail:
938 if (buffer->buffer != NULL) {
939 loader_free(item->pAllocator, buffer->buffer);
940 buffer->buffer = NULL;
941 }
942
943 if (printed != NULL) {
944 loader_free(item->pAllocator, printed);
945 printed = NULL;
946 }
947
948 return NULL;
949 }
950
951 /* Render a cJSON item/entity/structure to text. */
CJSON_PUBLIC(char *)952 TEST_FUNCTION_EXPORT CJSON_PUBLIC(char *) loader_cJSON_Print(const cJSON *item, bool *out_of_memory) {
953 return (char *)print(item, true, out_of_memory);
954 }
955
loader_cJSON_PrintUnformatted(const cJSON * item,bool * out_of_memory)956 CJSON_PUBLIC(char *) loader_cJSON_PrintUnformatted(const cJSON *item, bool *out_of_memory) {
957 return (char *)print(item, false, out_of_memory);
958 }
959
960 CJSON_PUBLIC(char *)
loader_cJSON_PrintBuffered(const cJSON * item,int prebuffer,cJSON_bool fmt,bool * out_of_memory)961 loader_cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt, bool *out_of_memory) {
962 printbuffer p = {0, 0, 0, 0, 0, 0, 0};
963
964 if (prebuffer < 0) {
965 return NULL;
966 }
967
968 p.buffer = (unsigned char *)loader_alloc(item->pAllocator, (size_t)prebuffer, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
969 if (!p.buffer) {
970 return NULL;
971 }
972
973 p.length = (size_t)prebuffer;
974 p.offset = 0;
975 p.noalloc = false;
976 p.format = fmt;
977 p.pAllocator = item->pAllocator;
978
979 if (!print_value(item, &p, out_of_memory)) {
980 loader_free(item->pAllocator, p.buffer);
981 p.buffer = NULL;
982 return NULL;
983 }
984
985 return (char *)p.buffer;
986 }
987
988 CJSON_PUBLIC(cJSON_bool)
loader_cJSON_PrintPreallocated(cJSON * item,char * buffer,const int length,const cJSON_bool format)989 loader_cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) {
990 printbuffer p = {0, 0, 0, 0, 0, 0, 0};
991
992 if ((length < 0) || (buffer == NULL)) {
993 return false;
994 }
995
996 p.buffer = (unsigned char *)buffer;
997 p.length = (size_t)length;
998 p.offset = 0;
999 p.noalloc = true;
1000 p.format = format;
1001 p.pAllocator = item->pAllocator;
1002 bool out_of_memory = false;
1003 return print_value(item, &p, &out_of_memory);
1004 }
1005
1006 /* Parser core - when encountering text, process appropriately. */
parse_value(cJSON * const item,parse_buffer * const input_buffer,bool * out_of_memory)1007 static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1008 if ((input_buffer == NULL) || (input_buffer->content == NULL)) {
1009 return false; /* no input */
1010 }
1011
1012 /* parse the different types of values */
1013 /* null */
1014 if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)) {
1015 item->type = cJSON_NULL;
1016 input_buffer->offset += 4;
1017 return true;
1018 }
1019 /* false */
1020 if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)) {
1021 item->type = cJSON_False;
1022 input_buffer->offset += 5;
1023 return true;
1024 }
1025 /* true */
1026 if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)) {
1027 item->type = cJSON_True;
1028 item->valueint = 1;
1029 input_buffer->offset += 4;
1030 return true;
1031 }
1032 /* string */
1033 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) {
1034 return parse_string(item, input_buffer, out_of_memory);
1035 }
1036 /* number */
1037 if (can_access_at_index(input_buffer, 0) &&
1038 ((buffer_at_offset(input_buffer)[0] == '-') ||
1039 ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) {
1040 return parse_number(item, input_buffer);
1041 }
1042 /* array */
1043 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) {
1044 return parse_array(item, input_buffer, out_of_memory);
1045 }
1046 /* object */
1047 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) {
1048 return parse_object(item, input_buffer, out_of_memory);
1049 }
1050
1051 return false;
1052 }
1053
1054 /* Render a value to text. */
print_value(const cJSON * const item,printbuffer * const output_buffer,bool * out_of_memory)1055 static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1056 unsigned char *output = NULL;
1057
1058 if ((item == NULL) || (output_buffer == NULL)) {
1059 return false;
1060 }
1061
1062 switch ((item->type) & 0xFF) {
1063 case cJSON_NULL:
1064 output = ensure(output_buffer, 5, out_of_memory);
1065 if (output == NULL) {
1066 return false;
1067 }
1068 strcpy((char *)output, "null");
1069 return true;
1070
1071 case cJSON_False:
1072 output = ensure(output_buffer, 6, out_of_memory);
1073 if (output == NULL) {
1074 return false;
1075 }
1076 strcpy((char *)output, "false");
1077 return true;
1078
1079 case cJSON_True:
1080 output = ensure(output_buffer, 5, out_of_memory);
1081 if (output == NULL) {
1082 return false;
1083 }
1084 strcpy((char *)output, "true");
1085 return true;
1086
1087 case cJSON_Number:
1088 return print_number(item, output_buffer, out_of_memory);
1089
1090 case cJSON_Raw: {
1091 size_t raw_length = 0;
1092 if (item->valuestring == NULL) {
1093 return false;
1094 }
1095
1096 raw_length = strlen(item->valuestring) + sizeof("");
1097 output = ensure(output_buffer, raw_length, out_of_memory);
1098 if (output == NULL) {
1099 return false;
1100 }
1101 memcpy(output, item->valuestring, raw_length);
1102 return true;
1103 }
1104
1105 case cJSON_String:
1106 return print_string(item, output_buffer, out_of_memory);
1107
1108 case cJSON_Array:
1109 return print_array(item, output_buffer, out_of_memory);
1110
1111 case cJSON_Object:
1112 return print_object(item, output_buffer, out_of_memory);
1113
1114 default:
1115 return false;
1116 }
1117 }
1118
1119 /* Build an array from input text. */
parse_array(cJSON * const item,parse_buffer * const input_buffer,bool * out_of_memory)1120 static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1121 cJSON *head = NULL; /* head of the linked list */
1122 cJSON *current_item = NULL;
1123
1124 if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1125 return false; /* to deeply nested */
1126 }
1127 input_buffer->depth++;
1128
1129 if (buffer_at_offset(input_buffer)[0] != '[') {
1130 /* not an array */
1131 goto fail;
1132 }
1133
1134 input_buffer->offset++;
1135 buffer_skip_whitespace(input_buffer);
1136 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) {
1137 /* empty array */
1138 goto success;
1139 }
1140
1141 /* check if we skipped to the end of the buffer */
1142 if (cannot_access_at_index(input_buffer, 0)) {
1143 input_buffer->offset--;
1144 goto fail;
1145 }
1146
1147 /* step back to character in front of the first element */
1148 input_buffer->offset--;
1149 /* loop through the comma separated array elements */
1150 do {
1151 /* allocate next item */
1152 cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1153 if (new_item == NULL) {
1154 *out_of_memory = true;
1155 goto fail; /* allocation failure */
1156 }
1157
1158 /* attach next item to list */
1159 if (head == NULL) {
1160 /* start the linked list */
1161 current_item = head = new_item;
1162 } else {
1163 /* add to the end and advance */
1164 current_item->next = new_item;
1165 new_item->prev = current_item;
1166 current_item = new_item;
1167 }
1168
1169 /* parse next value */
1170 input_buffer->offset++;
1171 buffer_skip_whitespace(input_buffer);
1172 if (!parse_value(current_item, input_buffer, out_of_memory)) {
1173 goto fail; /* failed to parse value */
1174 }
1175 buffer_skip_whitespace(input_buffer);
1176 } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1177
1178 if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') {
1179 goto fail; /* expected end of array */
1180 }
1181
1182 success:
1183 input_buffer->depth--;
1184
1185 if (head != NULL) {
1186 head->prev = current_item;
1187 }
1188
1189 item->type = cJSON_Array;
1190 item->child = head;
1191
1192 input_buffer->offset++;
1193
1194 return true;
1195
1196 fail:
1197 if (head != NULL) {
1198 loader_cJSON_Delete(head);
1199 }
1200
1201 return false;
1202 }
1203
1204 /* Render an array to text */
print_array(const cJSON * const item,printbuffer * const output_buffer,bool * out_of_memory)1205 static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1206 unsigned char *output_pointer = NULL;
1207 size_t length = 0;
1208 cJSON *current_element = item->child;
1209
1210 if (output_buffer == NULL) {
1211 return false;
1212 }
1213
1214 /* Compose the output array. */
1215 /* opening square bracket */
1216 output_pointer = ensure(output_buffer, 1, out_of_memory);
1217 if (output_pointer == NULL) {
1218 return false;
1219 }
1220
1221 *output_pointer = '[';
1222 output_buffer->offset++;
1223 output_buffer->depth++;
1224
1225 while (current_element != NULL) {
1226 if (!print_value(current_element, output_buffer, out_of_memory)) {
1227 return false;
1228 }
1229 update_offset(output_buffer);
1230 if (current_element->next) {
1231 length = (size_t)(output_buffer->format ? 2 : 1);
1232 output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1233 if (output_pointer == NULL) {
1234 return false;
1235 }
1236 *output_pointer++ = ',';
1237 if (output_buffer->format) {
1238 *output_pointer++ = ' ';
1239 }
1240 *output_pointer = '\0';
1241 output_buffer->offset += length;
1242 }
1243 current_element = current_element->next;
1244 }
1245
1246 output_pointer = ensure(output_buffer, 2, out_of_memory);
1247 if (output_pointer == NULL) {
1248 return false;
1249 }
1250 *output_pointer++ = ']';
1251 *output_pointer = '\0';
1252 output_buffer->depth--;
1253
1254 return true;
1255 }
1256
1257 /* Build an object from the text. */
parse_object(cJSON * const item,parse_buffer * const input_buffer,bool * out_of_memory)1258 static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer, bool *out_of_memory) {
1259 cJSON *head = NULL; /* linked list head */
1260 cJSON *current_item = NULL;
1261
1262 if (input_buffer->depth >= CJSON_NESTING_LIMIT) {
1263 return false; /* to deeply nested */
1264 }
1265 input_buffer->depth++;
1266
1267 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) {
1268 goto fail; /* not an object */
1269 }
1270
1271 input_buffer->offset++;
1272 buffer_skip_whitespace(input_buffer);
1273 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) {
1274 goto success; /* empty object */
1275 }
1276
1277 /* check if we skipped to the end of the buffer */
1278 if (cannot_access_at_index(input_buffer, 0)) {
1279 input_buffer->offset--;
1280 goto fail;
1281 }
1282
1283 /* step back to character in front of the first element */
1284 input_buffer->offset--;
1285 /* loop through the comma separated array elements */
1286 do {
1287 /* allocate next item */
1288 cJSON *new_item = cJSON_New_Item(input_buffer->pAllocator);
1289 if (new_item == NULL) {
1290 *out_of_memory = true;
1291 goto fail; /* allocation failure */
1292 }
1293
1294 /* attach next item to list */
1295 if (head == NULL) {
1296 /* start the linked list */
1297 current_item = head = new_item;
1298 } else {
1299 /* add to the end and advance */
1300 current_item->next = new_item;
1301 new_item->prev = current_item;
1302 current_item = new_item;
1303 }
1304
1305 if (cannot_access_at_index(input_buffer, 1)) {
1306 goto fail; /* nothing comes after the comma */
1307 }
1308
1309 /* parse the name of the child */
1310 input_buffer->offset++;
1311 buffer_skip_whitespace(input_buffer);
1312 if (!parse_string(current_item, input_buffer, out_of_memory)) {
1313 goto fail; /* failed to parse name */
1314 }
1315 buffer_skip_whitespace(input_buffer);
1316
1317 /* swap valuestring and string, because we parsed the name */
1318 current_item->string = current_item->valuestring;
1319 current_item->valuestring = NULL;
1320
1321 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) {
1322 goto fail; /* invalid object */
1323 }
1324
1325 /* parse the value */
1326 input_buffer->offset++;
1327 buffer_skip_whitespace(input_buffer);
1328 if (!parse_value(current_item, input_buffer, out_of_memory)) {
1329 goto fail; /* failed to parse value */
1330 }
1331 buffer_skip_whitespace(input_buffer);
1332 } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1333
1334 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) {
1335 goto fail; /* expected end of object */
1336 }
1337
1338 success:
1339 input_buffer->depth--;
1340
1341 if (head != NULL) {
1342 head->prev = current_item;
1343 }
1344
1345 item->type = cJSON_Object;
1346 item->child = head;
1347
1348 input_buffer->offset++;
1349 return true;
1350
1351 fail:
1352 if (head != NULL) {
1353 loader_cJSON_Delete(head);
1354 }
1355
1356 return false;
1357 }
1358
1359 /* Render an object to text. */
print_object(const cJSON * const item,printbuffer * const output_buffer,bool * out_of_memory)1360 static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer, bool *out_of_memory) {
1361 unsigned char *output_pointer = NULL;
1362 size_t length = 0;
1363 cJSON *current_item = item->child;
1364
1365 if (output_buffer == NULL) {
1366 return false;
1367 }
1368
1369 /* Compose the output: */
1370 length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */
1371 output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1372 if (output_pointer == NULL) {
1373 return false;
1374 }
1375
1376 *output_pointer++ = '{';
1377 output_buffer->depth++;
1378 if (output_buffer->format) {
1379 *output_pointer++ = '\n';
1380 }
1381 output_buffer->offset += length;
1382
1383 while (current_item) {
1384 if (output_buffer->format) {
1385 size_t i;
1386 output_pointer = ensure(output_buffer, output_buffer->depth, out_of_memory);
1387 if (output_pointer == NULL) {
1388 return false;
1389 }
1390 for (i = 0; i < output_buffer->depth; i++) {
1391 *output_pointer++ = '\t';
1392 }
1393 output_buffer->offset += output_buffer->depth;
1394 }
1395
1396 /* print key */
1397 if (!print_string_ptr((unsigned char *)current_item->string, output_buffer, out_of_memory)) {
1398 return false;
1399 }
1400 update_offset(output_buffer);
1401
1402 length = (size_t)(output_buffer->format ? 2 : 1);
1403 output_pointer = ensure(output_buffer, length, out_of_memory);
1404 if (output_pointer == NULL) {
1405 return false;
1406 }
1407 *output_pointer++ = ':';
1408 if (output_buffer->format) {
1409 *output_pointer++ = '\t';
1410 }
1411 output_buffer->offset += length;
1412
1413 /* print value */
1414 if (!print_value(current_item, output_buffer, out_of_memory)) {
1415 return false;
1416 }
1417 update_offset(output_buffer);
1418
1419 /* print comma if not last */
1420 length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
1421 output_pointer = ensure(output_buffer, length + 1, out_of_memory);
1422 if (output_pointer == NULL) {
1423 return false;
1424 }
1425 if (current_item->next) {
1426 *output_pointer++ = ',';
1427 }
1428
1429 if (output_buffer->format) {
1430 *output_pointer++ = '\n';
1431 }
1432 *output_pointer = '\0';
1433 output_buffer->offset += length;
1434
1435 current_item = current_item->next;
1436 }
1437
1438 output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2, out_of_memory);
1439 if (output_pointer == NULL) {
1440 return false;
1441 }
1442 if (output_buffer->format) {
1443 size_t i;
1444 for (i = 0; i < (output_buffer->depth - 1); i++) {
1445 *output_pointer++ = '\t';
1446 }
1447 }
1448 *output_pointer++ = '}';
1449 *output_pointer = '\0';
1450 output_buffer->depth--;
1451
1452 return true;
1453 }
1454
1455 /* Get Array size/item / object item. */
loader_cJSON_GetArraySize(const cJSON * array)1456 CJSON_PUBLIC(int) loader_cJSON_GetArraySize(const cJSON *array) {
1457 cJSON *child = NULL;
1458 size_t size = 0;
1459
1460 if (array == NULL) {
1461 return 0;
1462 }
1463
1464 child = array->child;
1465
1466 while (child != NULL) {
1467 size++;
1468 child = child->next;
1469 }
1470
1471 /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
1472
1473 return (int)size;
1474 }
1475
get_array_item(const cJSON * array,size_t index)1476 static cJSON *get_array_item(const cJSON *array, size_t index) {
1477 cJSON *current_child = NULL;
1478
1479 if (array == NULL) {
1480 return NULL;
1481 }
1482
1483 current_child = array->child;
1484 while ((current_child != NULL) && (index > 0)) {
1485 index--;
1486 current_child = current_child->next;
1487 }
1488
1489 return current_child;
1490 }
1491
loader_cJSON_GetArrayItem(const cJSON * array,int index)1492 CJSON_PUBLIC(cJSON *) loader_cJSON_GetArrayItem(const cJSON *array, int index) {
1493 if (index < 0) {
1494 return NULL;
1495 }
1496
1497 return get_array_item(array, (size_t)index);
1498 }
1499
get_object_item(const cJSON * const object,const char * const name,const cJSON_bool case_sensitive)1500 static cJSON *get_object_item(const cJSON *const object, const char *const name, const cJSON_bool case_sensitive) {
1501 cJSON *current_element = NULL;
1502
1503 if ((object == NULL) || (name == NULL)) {
1504 return NULL;
1505 }
1506
1507 current_element = object->child;
1508 if (case_sensitive) {
1509 while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) {
1510 current_element = current_element->next;
1511 }
1512 } else {
1513 while ((current_element != NULL) &&
1514 (case_insensitive_strcmp((const unsigned char *)name, (const unsigned char *)(current_element->string)) != 0)) {
1515 current_element = current_element->next;
1516 }
1517 }
1518
1519 if ((current_element == NULL) || (current_element->string == NULL)) {
1520 return NULL;
1521 }
1522
1523 return current_element;
1524 }
1525
loader_cJSON_GetObjectItem(const cJSON * const object,const char * const string)1526 CJSON_PUBLIC(cJSON *) loader_cJSON_GetObjectItem(const cJSON *const object, const char *const string) {
1527 return get_object_item(object, string, false);
1528 }
1529
loader_cJSON_GetObjectItemCaseSensitive(const cJSON * const object,const char * const string)1530 CJSON_PUBLIC(cJSON *) loader_cJSON_GetObjectItemCaseSensitive(const cJSON *const object, const char *const string) {
1531 return get_object_item(object, string, true);
1532 }
1533
loader_cJSON_HasObjectItem(const cJSON * object,const char * string)1534 CJSON_PUBLIC(cJSON_bool) loader_cJSON_HasObjectItem(const cJSON *object, const char *string) {
1535 return loader_cJSON_GetObjectItem(object, string) ? 1 : 0;
1536 }
1537
skip_oneline_comment(char ** input)1538 static void skip_oneline_comment(char **input) {
1539 *input += static_strlen("//");
1540
1541 for (; (*input)[0] != '\0'; ++(*input)) {
1542 if ((*input)[0] == '\n') {
1543 *input += static_strlen("\n");
1544 return;
1545 }
1546 }
1547 }
1548
skip_multiline_comment(char ** input)1549 static void skip_multiline_comment(char **input) {
1550 *input += static_strlen("/*");
1551
1552 for (; (*input)[0] != '\0'; ++(*input)) {
1553 if (((*input)[0] == '*') && ((*input)[1] == '/')) {
1554 *input += static_strlen("*/");
1555 return;
1556 }
1557 }
1558 }
1559
minify_string(char ** input,char ** output)1560 static void minify_string(char **input, char **output) {
1561 (*output)[0] = (*input)[0];
1562 *input += static_strlen("\"");
1563 *output += static_strlen("\"");
1564
1565 for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
1566 (*output)[0] = (*input)[0];
1567
1568 if ((*input)[0] == '\"') {
1569 (*output)[0] = '\"';
1570 *input += static_strlen("\"");
1571 *output += static_strlen("\"");
1572 return;
1573 } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
1574 (*output)[1] = (*input)[1];
1575 *input += static_strlen("\"");
1576 *output += static_strlen("\"");
1577 }
1578 }
1579 }
1580
loader_cJSON_Minify(char * json)1581 CJSON_PUBLIC(void) loader_cJSON_Minify(char *json) {
1582 char *into = json;
1583
1584 if (json == NULL) {
1585 return;
1586 }
1587
1588 while (json[0] != '\0') {
1589 switch (json[0]) {
1590 case ' ':
1591 case '\t':
1592 case '\r':
1593 case '\n':
1594 json++;
1595 break;
1596
1597 case '/':
1598 if (json[1] == '/') {
1599 skip_oneline_comment(&json);
1600 } else if (json[1] == '*') {
1601 skip_multiline_comment(&json);
1602 } else {
1603 json++;
1604 }
1605 break;
1606
1607 case '\"':
1608 minify_string(&json, (char **)&into);
1609 break;
1610
1611 default:
1612 into[0] = json[0];
1613 json++;
1614 into++;
1615 }
1616 }
1617
1618 /* and null-terminate. */
1619 *into = '\0';
1620 }
1621
loader_cJSON_IsInvalid(const cJSON * const item)1622 CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsInvalid(const cJSON *const item) {
1623 if (item == NULL) {
1624 return false;
1625 }
1626
1627 return (item->type & 0xFF) == cJSON_Invalid;
1628 }
1629
loader_cJSON_IsFalse(const cJSON * const item)1630 CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsFalse(const cJSON *const item) {
1631 if (item == NULL) {
1632 return false;
1633 }
1634
1635 return (item->type & 0xFF) == cJSON_False;
1636 }
1637
loader_cJSON_IsTrue(const cJSON * const item)1638 CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsTrue(const cJSON *const item) {
1639 if (item == NULL) {
1640 return false;
1641 }
1642
1643 return (item->type & 0xff) == cJSON_True;
1644 }
1645
loader_cJSON_IsBool(const cJSON * const item)1646 CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsBool(const cJSON *const item) {
1647 if (item == NULL) {
1648 return false;
1649 }
1650
1651 return (item->type & (cJSON_True | cJSON_False)) != 0;
1652 }
loader_cJSON_IsNull(const cJSON * const item)1653 CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsNull(const cJSON *const item) {
1654 if (item == NULL) {
1655 return false;
1656 }
1657
1658 return (item->type & 0xFF) == cJSON_NULL;
1659 }
1660
loader_cJSON_IsNumber(const cJSON * const item)1661 CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsNumber(const cJSON *const item) {
1662 if (item == NULL) {
1663 return false;
1664 }
1665
1666 return (item->type & 0xFF) == cJSON_Number;
1667 }
1668
loader_cJSON_IsString(const cJSON * const item)1669 CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsString(const cJSON *const item) {
1670 if (item == NULL) {
1671 return false;
1672 }
1673
1674 return (item->type & 0xFF) == cJSON_String;
1675 }
1676
loader_cJSON_IsArray(const cJSON * const item)1677 CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsArray(const cJSON *const item) {
1678 if (item == NULL) {
1679 return false;
1680 }
1681
1682 return (item->type & 0xFF) == cJSON_Array;
1683 }
1684
cJSON_IsObject(const cJSON * const item)1685 CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON *const item) {
1686 if (item == NULL) {
1687 return false;
1688 }
1689
1690 return (item->type & 0xFF) == cJSON_Object;
1691 }
1692
loader_cJSON_IsRaw(const cJSON * const item)1693 CJSON_PUBLIC(cJSON_bool) loader_cJSON_IsRaw(const cJSON *const item) {
1694 if (item == NULL) {
1695 return false;
1696 }
1697
1698 return (item->type & 0xFF) == cJSON_Raw;
1699 }
1700
loader_cJSON_Compare(const cJSON * const a,const cJSON * const b,const cJSON_bool case_sensitive)1701 CJSON_PUBLIC(cJSON_bool) loader_cJSON_Compare(const cJSON *const a, const cJSON *const b, const cJSON_bool case_sensitive) {
1702 if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) {
1703 return false;
1704 }
1705
1706 /* check if type is valid */
1707 switch (a->type & 0xFF) {
1708 case cJSON_False:
1709 case cJSON_True:
1710 case cJSON_NULL:
1711 case cJSON_Number:
1712 case cJSON_String:
1713 case cJSON_Raw:
1714 case cJSON_Array:
1715 case cJSON_Object:
1716 break;
1717
1718 default:
1719 return false;
1720 }
1721
1722 /* identical objects are equal */
1723 if (a == b) {
1724 return true;
1725 }
1726
1727 switch (a->type & 0xFF) {
1728 /* in these cases and equal type is enough */
1729 case cJSON_False:
1730 case cJSON_True:
1731 case cJSON_NULL:
1732 return true;
1733
1734 case cJSON_Number:
1735 if (compare_double(a->valuedouble, b->valuedouble)) {
1736 return true;
1737 }
1738 return false;
1739
1740 case cJSON_String:
1741 case cJSON_Raw:
1742 if ((a->valuestring == NULL) || (b->valuestring == NULL)) {
1743 return false;
1744 }
1745 if (strcmp(a->valuestring, b->valuestring) == 0) {
1746 return true;
1747 }
1748
1749 return false;
1750
1751 case cJSON_Array: {
1752 cJSON *a_element = a->child;
1753 cJSON *b_element = b->child;
1754
1755 for (; (a_element != NULL) && (b_element != NULL);) {
1756 if (!loader_cJSON_Compare(a_element, b_element, case_sensitive)) {
1757 return false;
1758 }
1759
1760 a_element = a_element->next;
1761 b_element = b_element->next;
1762 }
1763
1764 /* one of the arrays is longer than the other */
1765 if (a_element != b_element) {
1766 return false;
1767 }
1768
1769 return true;
1770 }
1771
1772 case cJSON_Object: {
1773 cJSON *a_element = NULL;
1774 cJSON *b_element = NULL;
1775 cJSON_ArrayForEach(a_element, a) {
1776 /* TODO This has O(n^2) runtime, which is horrible! */
1777 b_element = get_object_item(b, a_element->string, case_sensitive);
1778 if (b_element == NULL) {
1779 return false;
1780 }
1781
1782 if (!loader_cJSON_Compare(a_element, b_element, case_sensitive)) {
1783 return false;
1784 }
1785 }
1786
1787 /* doing this twice, once on a and b to prevent true comparison if a subset of b
1788 * TODO: Do this the proper way, this is just a fix for now */
1789 cJSON_ArrayForEach(b_element, b) {
1790 a_element = get_object_item(a, b_element->string, case_sensitive);
1791 if (a_element == NULL) {
1792 return false;
1793 }
1794
1795 if (!loader_cJSON_Compare(b_element, a_element, case_sensitive)) {
1796 return false;
1797 }
1798 }
1799
1800 return true;
1801 }
1802
1803 default:
1804 return false;
1805 }
1806 }
1807