• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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