• 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 /* define our own boolean type */
62 #ifdef true
63 #undef true
64 #endif
65 #define true ((cJSON_bool)1)
66 
67 #ifdef false
68 #undef false
69 #endif
70 #define false ((cJSON_bool)0)
71 
72 /* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
73 #ifndef isinf
74 #define isinf(d) (isnan((d - d)) && !isnan(d))
75 #endif
76 #ifndef isnan
77 #define isnan(d) (d != d)
78 #endif
79 
80 #ifndef NAN
81 #ifdef _WIN32
82 #define NAN sqrt(-1.0)
83 #else
84 #define NAN 0.0/0.0
85 #endif
86 #endif
87 
88 typedef struct {
89     const unsigned char *json;
90     size_t position;
91 } error;
92 static error global_error = { NULL, 0 };
93 
cJSON_GetErrorPtr(void)94 CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
95 {
96     return (const char*) (global_error.json + global_error.position);
97 }
98 
cJSON_GetStringValue(const cJSON * const item)99 CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
100 {
101     if (!cJSON_IsString(item))
102     {
103         return NULL;
104     }
105 
106     return item->valuestring;
107 }
108 
cJSON_GetNumberValue(const cJSON * const item)109 CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
110 {
111     if (!cJSON_IsNumber(item))
112     {
113         return (double) NAN;
114     }
115 
116     return item->valuedouble;
117 }
118 
119 /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
120 #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 15)
121     #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
122 #endif
123 
cJSON_Version(void)124 CJSON_PUBLIC(const char*) cJSON_Version(void)
125 {
126     static char version[15];
127     sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
128 
129     return version;
130 }
131 
132 /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
case_insensitive_strcmp(const unsigned char * string1,const unsigned char * string2)133 static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
134 {
135     if ((string1 == NULL) || (string2 == NULL))
136     {
137         return 1;
138     }
139 
140     if (string1 == string2)
141     {
142         return 0;
143     }
144 
145     for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
146     {
147         if (*string1 == '\0')
148         {
149             return 0;
150         }
151     }
152 
153     return tolower(*string1) - tolower(*string2);
154 }
155 
156 typedef struct internal_hooks
157 {
158     void *(CJSON_CDECL *allocate)(size_t size);
159     void (CJSON_CDECL *deallocate)(void *pointer);
160     void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
161 } internal_hooks;
162 
163 #if defined(_MSC_VER)
164 /* work around MSVC error C2322: '...' address of dllimport '...' is not static */
internal_malloc(size_t size)165 static void * CJSON_CDECL internal_malloc(size_t size)
166 {
167     return malloc(size);
168 }
internal_free(void * pointer)169 static void CJSON_CDECL internal_free(void *pointer)
170 {
171     free(pointer);
172 }
internal_realloc(void * pointer,size_t size)173 static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
174 {
175     return realloc(pointer, size);
176 }
177 #else
178 #define internal_malloc malloc
179 #define internal_free free
180 #define internal_realloc realloc
181 #endif
182 
183 /* strlen of character literals resolved at compile time */
184 #define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
185 
186 static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
187 
cJSON_strdup(const unsigned char * string,const internal_hooks * const hooks)188 static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
189 {
190     size_t length = 0;
191     unsigned char *copy = NULL;
192 
193     if (string == NULL)
194     {
195         return NULL;
196     }
197 
198     length = strlen((const char*)string) + sizeof("");
199     copy = (unsigned char*)hooks->allocate(length);
200     if (copy == NULL)
201     {
202         return NULL;
203     }
204     memcpy(copy, string, length);
205 
206     return copy;
207 }
208 
cJSON_InitHooks(cJSON_Hooks * hooks)209 CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
210 {
211     if (hooks == NULL)
212     {
213         /* Reset hooks */
214         global_hooks.allocate = malloc;
215         global_hooks.deallocate = free;
216         global_hooks.reallocate = realloc;
217         return;
218     }
219 
220     global_hooks.allocate = malloc;
221     if (hooks->malloc_fn != NULL)
222     {
223         global_hooks.allocate = hooks->malloc_fn;
224     }
225 
226     global_hooks.deallocate = free;
227     if (hooks->free_fn != NULL)
228     {
229         global_hooks.deallocate = hooks->free_fn;
230     }
231 
232     /* use realloc only if both free and malloc are used */
233     global_hooks.reallocate = NULL;
234     if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
235     {
236         global_hooks.reallocate = realloc;
237     }
238 }
239 
240 /* Internal constructor. */
cJSON_New_Item(const internal_hooks * const hooks)241 static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
242 {
243     cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
244     if (node)
245     {
246         memset(node, '\0', sizeof(cJSON));
247     }
248 
249     return node;
250 }
251 
252 /* Delete a cJSON structure. */
cJSON_Delete(cJSON * item)253 CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
254 {
255     cJSON *next = NULL;
256     while (item != NULL)
257     {
258         next = item->next;
259         if (!(item->type & cJSON_IsReference) && (item->child != NULL))
260         {
261             cJSON_Delete(item->child);
262         }
263         if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
264         {
265             global_hooks.deallocate(item->valuestring);
266         }
267         if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
268         {
269             global_hooks.deallocate(item->string);
270         }
271         global_hooks.deallocate(item);
272         item = next;
273     }
274 }
275 
276 /* get the decimal point character of the current locale */
get_decimal_point(void)277 static unsigned char get_decimal_point(void)
278 {
279 #ifdef ENABLE_LOCALES
280     struct lconv *lconv = localeconv();
281     return (unsigned char) lconv->decimal_point[0];
282 #else
283     return '.';
284 #endif
285 }
286 
287 typedef struct
288 {
289     const unsigned char *content;
290     size_t length;
291     size_t offset;
292     size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
293     internal_hooks hooks;
294 } parse_buffer;
295 
296 /* check if the given size is left to read in a given parse buffer (starting with 1) */
297 #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
298 /* check if the buffer can be accessed at the given index (starting with 0) */
299 #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
300 #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
301 /* get a pointer to the buffer at the position */
302 #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
303 
304 /* Parse the input text to generate a number, and populate the result into item. */
parse_number(cJSON * const item,parse_buffer * const input_buffer)305 static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
306 {
307     double number = 0;
308     unsigned char *after_end = NULL;
309     unsigned char number_c_string[64];
310     unsigned char decimal_point = get_decimal_point();
311     size_t i = 0;
312 
313     if ((input_buffer == NULL) || (input_buffer->content == NULL))
314     {
315         return false;
316     }
317 
318     /* copy the number into a temporary buffer and replace '.' with the decimal point
319      * of the current locale (for strtod)
320      * This also takes care of '\0' not necessarily being available for marking the end of the input */
321     for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
322     {
323         switch (buffer_at_offset(input_buffer)[i])
324         {
325             case '0':
326             case '1':
327             case '2':
328             case '3':
329             case '4':
330             case '5':
331             case '6':
332             case '7':
333             case '8':
334             case '9':
335             case '+':
336             case '-':
337             case 'e':
338             case 'E':
339                 number_c_string[i] = buffer_at_offset(input_buffer)[i];
340                 break;
341 
342             case '.':
343                 number_c_string[i] = decimal_point;
344                 break;
345 
346             default:
347                 goto loop_end;
348         }
349     }
350 loop_end:
351     number_c_string[i] = '\0';
352 
353     number = strtod((const char*)number_c_string, (char**)&after_end);
354     if (number_c_string == after_end)
355     {
356         return false; /* parse_error */
357     }
358 
359     item->valuedouble = number;
360 
361     /* use saturation in case of overflow */
362     if (number >= INT_MAX)
363     {
364         item->valueint = INT_MAX;
365     }
366     else if (number <= (double)INT_MIN)
367     {
368         item->valueint = INT_MIN;
369     }
370     else
371     {
372         item->valueint = (int)number;
373     }
374 
375     item->type = cJSON_Number;
376 
377     input_buffer->offset += (size_t)(after_end - number_c_string);
378     return true;
379 }
380 
381 /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
cJSON_SetNumberHelper(cJSON * object,double number)382 CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
383 {
384     if (number >= INT_MAX)
385     {
386         object->valueint = INT_MAX;
387     }
388     else if (number <= (double)INT_MIN)
389     {
390         object->valueint = INT_MIN;
391     }
392     else
393     {
394         object->valueint = (int)number;
395     }
396 
397     return object->valuedouble = number;
398 }
399 
cJSON_SetValuestring(cJSON * object,const char * valuestring)400 CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
401 {
402     char *copy = NULL;
403     /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
404     if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference))
405     {
406         return NULL;
407     }
408     if (strlen(valuestring) <= strlen(object->valuestring))
409     {
410         strcpy(object->valuestring, valuestring);
411         return object->valuestring;
412     }
413     copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
414     if (copy == NULL)
415     {
416         return NULL;
417     }
418     if (object->valuestring != NULL)
419     {
420         cJSON_free(object->valuestring);
421     }
422     object->valuestring = copy;
423 
424     return copy;
425 }
426 
427 typedef struct
428 {
429     unsigned char *buffer;
430     size_t length;
431     size_t offset;
432     size_t depth; /* current nesting depth (for formatted printing) */
433     cJSON_bool noalloc;
434     cJSON_bool format; /* is this print a formatted print */
435     internal_hooks hooks;
436 } printbuffer;
437 
438 /* realloc printbuffer if necessary to have at least "needed" bytes more */
ensure(printbuffer * const p,size_t needed)439 static unsigned char* ensure(printbuffer * const p, size_t needed)
440 {
441     unsigned char *newbuffer = NULL;
442     size_t newsize = 0;
443 
444     if ((p == NULL) || (p->buffer == NULL))
445     {
446         return NULL;
447     }
448 
449     if ((p->length > 0) && (p->offset >= p->length))
450     {
451         /* make sure that offset is valid */
452         return NULL;
453     }
454 
455     if (needed > INT_MAX)
456     {
457         /* sizes bigger than INT_MAX are currently not supported */
458         return NULL;
459     }
460 
461     needed += p->offset + 1;
462     if (needed <= p->length)
463     {
464         return p->buffer + p->offset;
465     }
466 
467     if (p->noalloc) {
468         return NULL;
469     }
470 
471     /* calculate new buffer size */
472     if (needed > (INT_MAX / 2))
473     {
474         /* overflow of int, use INT_MAX if possible */
475         if (needed <= INT_MAX)
476         {
477             newsize = INT_MAX;
478         }
479         else
480         {
481             return NULL;
482         }
483     }
484     else
485     {
486         newsize = needed * 2;
487     }
488 
489     if (p->hooks.reallocate != NULL)
490     {
491         /* reallocate with realloc if available */
492         newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
493         if (newbuffer == NULL)
494         {
495             p->hooks.deallocate(p->buffer);
496             p->length = 0;
497             p->buffer = NULL;
498 
499             return NULL;
500         }
501     }
502     else
503     {
504         /* otherwise reallocate manually */
505         newbuffer = (unsigned char*)p->hooks.allocate(newsize);
506         if (!newbuffer)
507         {
508             p->hooks.deallocate(p->buffer);
509             p->length = 0;
510             p->buffer = NULL;
511 
512             return NULL;
513         }
514 
515         memcpy(newbuffer, p->buffer, p->offset + 1);
516         p->hooks.deallocate(p->buffer);
517     }
518     p->length = newsize;
519     p->buffer = newbuffer;
520 
521     return newbuffer + p->offset;
522 }
523 
524 /* calculate the new length of the string in a printbuffer and update the offset */
update_offset(printbuffer * const buffer)525 static void update_offset(printbuffer * const buffer)
526 {
527     const unsigned char *buffer_pointer = NULL;
528     if ((buffer == NULL) || (buffer->buffer == NULL))
529     {
530         return;
531     }
532     buffer_pointer = buffer->buffer + buffer->offset;
533 
534     buffer->offset += strlen((const char*)buffer_pointer);
535 }
536 
537 /* securely comparison of floating-point variables */
compare_double(double a,double b)538 static cJSON_bool compare_double(double a, double b)
539 {
540     double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
541     return (fabs(a - b) <= maxVal * DBL_EPSILON);
542 }
543 
544 /* Render the number nicely from the given item into a string. */
print_number(const cJSON * const item,printbuffer * const output_buffer)545 static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
546 {
547     unsigned char *output_pointer = NULL;
548     double d = item->valuedouble;
549     int length = 0;
550     size_t i = 0;
551     unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
552     unsigned char decimal_point = get_decimal_point();
553     double test = 0.0;
554 
555     if (output_buffer == NULL)
556     {
557         return false;
558     }
559 
560     /* This checks for NaN and Infinity */
561     if (isnan(d) || isinf(d))
562     {
563         length = sprintf((char*)number_buffer, "null");
564     }
565     else
566     {
567         /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
568         length = sprintf((char*)number_buffer, "%1.15g", d);
569 
570         /* Check whether the original double can be recovered */
571         if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
572         {
573             /* If not, print with 17 decimal places of precision */
574             length = sprintf((char*)number_buffer, "%1.17g", d);
575         }
576     }
577 
578     /* sprintf failed or buffer overrun occurred */
579     if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
580     {
581         return false;
582     }
583 
584     /* reserve appropriate space in the output */
585     output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
586     if (output_pointer == NULL)
587     {
588         return false;
589     }
590 
591     /* copy the printed number to the output and replace locale
592      * dependent decimal point with '.' */
593     for (i = 0; i < ((size_t)length); i++)
594     {
595         if (number_buffer[i] == decimal_point)
596         {
597             output_pointer[i] = '.';
598             continue;
599         }
600 
601         output_pointer[i] = number_buffer[i];
602     }
603     output_pointer[i] = '\0';
604 
605     output_buffer->offset += (size_t)length;
606 
607     return true;
608 }
609 
610 /* parse 4 digit hexadecimal number */
parse_hex4(const unsigned char * const input)611 static unsigned parse_hex4(const unsigned char * const input)
612 {
613     unsigned int h = 0;
614     size_t i = 0;
615 
616     for (i = 0; i < 4; i++)
617     {
618         /* parse digit */
619         if ((input[i] >= '0') && (input[i] <= '9'))
620         {
621             h += (unsigned int) input[i] - '0';
622         }
623         else if ((input[i] >= 'A') && (input[i] <= 'F'))
624         {
625             h += (unsigned int) 10 + input[i] - 'A';
626         }
627         else if ((input[i] >= 'a') && (input[i] <= 'f'))
628         {
629             h += (unsigned int) 10 + input[i] - 'a';
630         }
631         else /* invalid */
632         {
633             return 0;
634         }
635 
636         if (i < 3)
637         {
638             /* shift left to make place for the next nibble */
639             h = h << 4;
640         }
641     }
642 
643     return h;
644 }
645 
646 /* converts a UTF-16 literal to UTF-8
647  * 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)648 static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
649 {
650     long unsigned int codepoint = 0;
651     unsigned int first_code = 0;
652     const unsigned char *first_sequence = input_pointer;
653     unsigned char utf8_length = 0;
654     unsigned char utf8_position = 0;
655     unsigned char sequence_length = 0;
656     unsigned char first_byte_mark = 0;
657 
658     if ((input_end - first_sequence) < 6)
659     {
660         /* input ends unexpectedly */
661         goto fail;
662     }
663 
664     /* get the first utf16 sequence */
665     first_code = parse_hex4(first_sequence + 2);
666 
667     /* check that the code is valid */
668     if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
669     {
670         goto fail;
671     }
672 
673     /* UTF16 surrogate pair */
674     if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
675     {
676         const unsigned char *second_sequence = first_sequence + 6;
677         unsigned int second_code = 0;
678         sequence_length = 12; /* \uXXXX\uXXXX */
679 
680         if ((input_end - second_sequence) < 6)
681         {
682             /* input ends unexpectedly */
683             goto fail;
684         }
685 
686         if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
687         {
688             /* missing second half of the surrogate pair */
689             goto fail;
690         }
691 
692         /* get the second utf16 sequence */
693         second_code = parse_hex4(second_sequence + 2);
694         /* check that the code is valid */
695         if ((second_code < 0xDC00) || (second_code > 0xDFFF))
696         {
697             /* invalid second half of the surrogate pair */
698             goto fail;
699         }
700 
701 
702         /* calculate the unicode codepoint from the surrogate pair */
703         codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
704     }
705     else
706     {
707         sequence_length = 6; /* \uXXXX */
708         codepoint = first_code;
709     }
710 
711     /* encode as UTF-8
712      * takes at maximum 4 bytes to encode:
713      * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
714     if (codepoint < 0x80)
715     {
716         /* normal ascii, encoding 0xxxxxxx */
717         utf8_length = 1;
718     }
719     else if (codepoint < 0x800)
720     {
721         /* two bytes, encoding 110xxxxx 10xxxxxx */
722         utf8_length = 2;
723         first_byte_mark = 0xC0; /* 11000000 */
724     }
725     else if (codepoint < 0x10000)
726     {
727         /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
728         utf8_length = 3;
729         first_byte_mark = 0xE0; /* 11100000 */
730     }
731     else if (codepoint <= 0x10FFFF)
732     {
733         /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
734         utf8_length = 4;
735         first_byte_mark = 0xF0; /* 11110000 */
736     }
737     else
738     {
739         /* invalid unicode codepoint */
740         goto fail;
741     }
742 
743     /* encode as utf8 */
744     for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
745     {
746         /* 10xxxxxx */
747         (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
748         codepoint >>= 6;
749     }
750     /* encode first byte */
751     if (utf8_length > 1)
752     {
753         (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
754     }
755     else
756     {
757         (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
758     }
759 
760     *output_pointer += utf8_length;
761 
762     return sequence_length;
763 
764 fail:
765     return 0;
766 }
767 
768 /* Parse the input text into an unescaped cinput, and populate item. */
parse_string(cJSON * const item,parse_buffer * const input_buffer)769 static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
770 {
771     const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
772     const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
773     unsigned char *output_pointer = NULL;
774     unsigned char *output = NULL;
775 
776     /* not a string */
777     if (buffer_at_offset(input_buffer)[0] != '\"')
778     {
779         goto fail;
780     }
781 
782     {
783         /* calculate approximate size of the output (overestimate) */
784         size_t allocation_length = 0;
785         size_t skipped_bytes = 0;
786         while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
787         {
788             /* is escape sequence */
789             if (input_end[0] == '\\')
790             {
791                 if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
792                 {
793                     /* prevent buffer overflow when last input character is a backslash */
794                     goto fail;
795                 }
796                 skipped_bytes++;
797                 input_end++;
798             }
799             input_end++;
800         }
801         if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
802         {
803             goto fail; /* string ended unexpectedly */
804         }
805 
806         /* This is at most how much we need for the output */
807         allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
808         output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
809         if (output == NULL)
810         {
811             goto fail; /* allocation failure */
812         }
813     }
814 
815     output_pointer = output;
816     /* loop through the string literal */
817     while (input_pointer < input_end)
818     {
819         if (*input_pointer != '\\')
820         {
821             *output_pointer++ = *input_pointer++;
822         }
823         /* escape sequence */
824         else
825         {
826             unsigned char sequence_length = 2;
827             if ((input_end - input_pointer) < 1)
828             {
829                 goto fail;
830             }
831 
832             switch (input_pointer[1])
833             {
834                 case 'b':
835                     *output_pointer++ = '\b';
836                     break;
837                 case 'f':
838                     *output_pointer++ = '\f';
839                     break;
840                 case 'n':
841                     *output_pointer++ = '\n';
842                     break;
843                 case 'r':
844                     *output_pointer++ = '\r';
845                     break;
846                 case 't':
847                     *output_pointer++ = '\t';
848                     break;
849                 case '\"':
850                 case '\\':
851                 case '/':
852                     *output_pointer++ = input_pointer[1];
853                     break;
854 
855                 /* UTF-16 literal */
856                 case 'u':
857                     sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
858                     if (sequence_length == 0)
859                     {
860                         /* failed to convert UTF16-literal to UTF-8 */
861                         goto fail;
862                     }
863                     break;
864 
865                 default:
866                     goto fail;
867             }
868             input_pointer += sequence_length;
869         }
870     }
871 
872     /* zero terminate the output */
873     *output_pointer = '\0';
874 
875     item->type = cJSON_String;
876     item->valuestring = (char*)output;
877 
878     input_buffer->offset = (size_t) (input_end - input_buffer->content);
879     input_buffer->offset++;
880 
881     return true;
882 
883 fail:
884     if (output != NULL)
885     {
886         input_buffer->hooks.deallocate(output);
887     }
888 
889     if (input_pointer != NULL)
890     {
891         input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
892     }
893 
894     return false;
895 }
896 
897 /* Render the cstring provided to an escaped version that can be printed. */
print_string_ptr(const unsigned char * const input,printbuffer * const output_buffer)898 static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
899 {
900     const unsigned char *input_pointer = NULL;
901     unsigned char *output = NULL;
902     unsigned char *output_pointer = NULL;
903     size_t output_length = 0;
904     /* numbers of additional characters needed for escaping */
905     size_t escape_characters = 0;
906 
907     if (output_buffer == NULL)
908     {
909         return false;
910     }
911 
912     /* empty string */
913     if (input == NULL)
914     {
915         output = ensure(output_buffer, sizeof("\"\""));
916         if (output == NULL)
917         {
918             return false;
919         }
920         strcpy((char*)output, "\"\"");
921 
922         return true;
923     }
924 
925     /* set "flag" to 1 if something needs to be escaped */
926     for (input_pointer = input; *input_pointer; input_pointer++)
927     {
928         switch (*input_pointer)
929         {
930             case '\"':
931             case '\\':
932             case '\b':
933             case '\f':
934             case '\n':
935             case '\r':
936             case '\t':
937                 /* one character escape sequence */
938                 escape_characters++;
939                 break;
940             default:
941                 if (*input_pointer < 32)
942                 {
943                     /* UTF-16 escape sequence uXXXX */
944                     escape_characters += 5;
945                 }
946                 break;
947         }
948     }
949     output_length = (size_t)(input_pointer - input) + escape_characters;
950 
951     output = ensure(output_buffer, output_length + sizeof("\"\""));
952     if (output == NULL)
953     {
954         return false;
955     }
956 
957     /* no characters have to be escaped */
958     if (escape_characters == 0)
959     {
960         output[0] = '\"';
961         memcpy(output + 1, input, output_length);
962         output[output_length + 1] = '\"';
963         output[output_length + 2] = '\0';
964 
965         return true;
966     }
967 
968     output[0] = '\"';
969     output_pointer = output + 1;
970     /* copy the string */
971     for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
972     {
973         if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
974         {
975             /* normal character, copy */
976             *output_pointer = *input_pointer;
977         }
978         else
979         {
980             /* character needs to be escaped */
981             *output_pointer++ = '\\';
982             switch (*input_pointer)
983             {
984                 case '\\':
985                     *output_pointer = '\\';
986                     break;
987                 case '\"':
988                     *output_pointer = '\"';
989                     break;
990                 case '\b':
991                     *output_pointer = 'b';
992                     break;
993                 case '\f':
994                     *output_pointer = 'f';
995                     break;
996                 case '\n':
997                     *output_pointer = 'n';
998                     break;
999                 case '\r':
1000                     *output_pointer = 'r';
1001                     break;
1002                 case '\t':
1003                     *output_pointer = 't';
1004                     break;
1005                 default:
1006                     /* escape and print as unicode codepoint */
1007                     sprintf((char*)output_pointer, "u%04x", *input_pointer);
1008                     output_pointer += 4;
1009                     break;
1010             }
1011         }
1012     }
1013     output[output_length + 1] = '\"';
1014     output[output_length + 2] = '\0';
1015 
1016     return true;
1017 }
1018 
1019 /* Invoke print_string_ptr (which is useful) on an item. */
print_string(const cJSON * const item,printbuffer * const p)1020 static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
1021 {
1022     return print_string_ptr((unsigned char*)item->valuestring, p);
1023 }
1024 
1025 /* Predeclare these prototypes. */
1026 static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
1027 static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
1028 static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
1029 static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
1030 static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
1031 static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
1032 
1033 /* Utility to jump whitespace and cr/lf */
buffer_skip_whitespace(parse_buffer * const buffer)1034 static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
1035 {
1036     if ((buffer == NULL) || (buffer->content == NULL))
1037     {
1038         return NULL;
1039     }
1040 
1041     if (cannot_access_at_index(buffer, 0))
1042     {
1043         return buffer;
1044     }
1045 
1046     while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
1047     {
1048        buffer->offset++;
1049     }
1050 
1051     if (buffer->offset == buffer->length)
1052     {
1053         buffer->offset--;
1054     }
1055 
1056     return buffer;
1057 }
1058 
1059 /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
skip_utf8_bom(parse_buffer * const buffer)1060 static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
1061 {
1062     if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
1063     {
1064         return NULL;
1065     }
1066 
1067     if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
1068     {
1069         buffer->offset += 3;
1070     }
1071 
1072     return buffer;
1073 }
1074 
cJSON_ParseWithOpts(const char * value,const char ** return_parse_end,cJSON_bool require_null_terminated)1075 CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
1076 {
1077     size_t buffer_length;
1078 
1079     if (NULL == value)
1080     {
1081         return NULL;
1082     }
1083 
1084     /* Adding null character size due to require_null_terminated. */
1085     buffer_length = strlen(value) + sizeof("");
1086 
1087     return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
1088 }
1089 
1090 /* Parse an object - create a new root, and populate. */
cJSON_ParseWithLengthOpts(const char * value,size_t buffer_length,const char ** return_parse_end,cJSON_bool require_null_terminated)1091 CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
1092 {
1093     parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
1094     cJSON *item = NULL;
1095 
1096     /* reset error position */
1097     global_error.json = NULL;
1098     global_error.position = 0;
1099 
1100     if (value == NULL || 0 == buffer_length)
1101     {
1102         goto fail;
1103     }
1104 
1105     buffer.content = (const unsigned char*)value;
1106     buffer.length = buffer_length;
1107     buffer.offset = 0;
1108     buffer.hooks = global_hooks;
1109 
1110     item = cJSON_New_Item(&global_hooks);
1111     if (item == NULL) /* memory fail */
1112     {
1113         goto fail;
1114     }
1115 
1116     if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
1117     {
1118         /* parse failure. ep is set. */
1119         goto fail;
1120     }
1121 
1122     /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
1123     if (require_null_terminated)
1124     {
1125         buffer_skip_whitespace(&buffer);
1126         if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
1127         {
1128             goto fail;
1129         }
1130     }
1131     if (return_parse_end)
1132     {
1133         *return_parse_end = (const char*)buffer_at_offset(&buffer);
1134     }
1135 
1136     return item;
1137 
1138 fail:
1139     if (item != NULL)
1140     {
1141         cJSON_Delete(item);
1142     }
1143 
1144     if (value != NULL)
1145     {
1146         error local_error;
1147         local_error.json = (const unsigned char*)value;
1148         local_error.position = 0;
1149 
1150         if (buffer.offset < buffer.length)
1151         {
1152             local_error.position = buffer.offset;
1153         }
1154         else if (buffer.length > 0)
1155         {
1156             local_error.position = buffer.length - 1;
1157         }
1158 
1159         if (return_parse_end != NULL)
1160         {
1161             *return_parse_end = (const char*)local_error.json + local_error.position;
1162         }
1163 
1164         global_error = local_error;
1165     }
1166 
1167     return NULL;
1168 }
1169 
1170 /* Default options for cJSON_Parse */
cJSON_Parse(const char * value)1171 CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
1172 {
1173     return cJSON_ParseWithOpts(value, 0, 0);
1174 }
1175 
cJSON_ParseWithLength(const char * value,size_t buffer_length)1176 CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
1177 {
1178     return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
1179 }
1180 
1181 #define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
1182 
print(const cJSON * const item,cJSON_bool format,const internal_hooks * const hooks)1183 static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
1184 {
1185     static const size_t default_buffer_size = 256;
1186     printbuffer buffer[1];
1187     unsigned char *printed = NULL;
1188 
1189     memset(buffer, 0, sizeof(buffer));
1190 
1191     /* create buffer */
1192     buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
1193     buffer->length = default_buffer_size;
1194     buffer->format = format;
1195     buffer->hooks = *hooks;
1196     if (buffer->buffer == NULL)
1197     {
1198         goto fail;
1199     }
1200 
1201     /* print the value */
1202     if (!print_value(item, buffer))
1203     {
1204         goto fail;
1205     }
1206     update_offset(buffer);
1207 
1208     /* check if reallocate is available */
1209     if (hooks->reallocate != NULL)
1210     {
1211         printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
1212         if (printed == NULL) {
1213             goto fail;
1214         }
1215         buffer->buffer = NULL;
1216     }
1217     else /* otherwise copy the JSON over to a new buffer */
1218     {
1219         printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
1220         if (printed == NULL)
1221         {
1222             goto fail;
1223         }
1224         memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
1225         printed[buffer->offset] = '\0'; /* just to be sure */
1226 
1227         /* free the buffer */
1228         hooks->deallocate(buffer->buffer);
1229     }
1230 
1231     return printed;
1232 
1233 fail:
1234     if (buffer->buffer != NULL)
1235     {
1236         hooks->deallocate(buffer->buffer);
1237     }
1238 
1239     if (printed != NULL)
1240     {
1241         hooks->deallocate(printed);
1242     }
1243 
1244     return NULL;
1245 }
1246 
1247 /* Render a cJSON item/entity/structure to text. */
cJSON_Print(const cJSON * item)1248 CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
1249 {
1250     return (char*)print(item, true, &global_hooks);
1251 }
1252 
cJSON_PrintUnformatted(const cJSON * item)1253 CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
1254 {
1255     return (char*)print(item, false, &global_hooks);
1256 }
1257 
cJSON_PrintBuffered(const cJSON * item,int prebuffer,cJSON_bool fmt)1258 CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
1259 {
1260     printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
1261 
1262     if (prebuffer < 0)
1263     {
1264         return NULL;
1265     }
1266 
1267     p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
1268     if (!p.buffer)
1269     {
1270         return NULL;
1271     }
1272 
1273     p.length = (size_t)prebuffer;
1274     p.offset = 0;
1275     p.noalloc = false;
1276     p.format = fmt;
1277     p.hooks = global_hooks;
1278 
1279     if (!print_value(item, &p))
1280     {
1281         global_hooks.deallocate(p.buffer);
1282         return NULL;
1283     }
1284 
1285     return (char*)p.buffer;
1286 }
1287 
cJSON_PrintPreallocated(cJSON * item,char * buffer,const int length,const cJSON_bool format)1288 CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
1289 {
1290     printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
1291 
1292     if ((length < 0) || (buffer == NULL))
1293     {
1294         return false;
1295     }
1296 
1297     p.buffer = (unsigned char*)buffer;
1298     p.length = (size_t)length;
1299     p.offset = 0;
1300     p.noalloc = true;
1301     p.format = format;
1302     p.hooks = global_hooks;
1303 
1304     return print_value(item, &p);
1305 }
1306 
1307 /* Parser core - when encountering text, process appropriately. */
parse_value(cJSON * const item,parse_buffer * const input_buffer)1308 static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
1309 {
1310     if ((input_buffer == NULL) || (input_buffer->content == NULL))
1311     {
1312         return false; /* no input */
1313     }
1314 
1315     /* parse the different types of values */
1316     /* null */
1317     if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
1318     {
1319         item->type = cJSON_NULL;
1320         input_buffer->offset += 4;
1321         return true;
1322     }
1323     /* false */
1324     if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
1325     {
1326         item->type = cJSON_False;
1327         input_buffer->offset += 5;
1328         return true;
1329     }
1330     /* true */
1331     if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
1332     {
1333         item->type = cJSON_True;
1334         item->valueint = 1;
1335         input_buffer->offset += 4;
1336         return true;
1337     }
1338     /* string */
1339     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
1340     {
1341         return parse_string(item, input_buffer);
1342     }
1343     /* number */
1344     if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
1345     {
1346         return parse_number(item, input_buffer);
1347     }
1348     /* array */
1349     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
1350     {
1351         return parse_array(item, input_buffer);
1352     }
1353     /* object */
1354     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
1355     {
1356         return parse_object(item, input_buffer);
1357     }
1358 
1359     return false;
1360 }
1361 
1362 /* Render a value to text. */
print_value(const cJSON * const item,printbuffer * const output_buffer)1363 static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
1364 {
1365     unsigned char *output = NULL;
1366 
1367     if ((item == NULL) || (output_buffer == NULL))
1368     {
1369         return false;
1370     }
1371 
1372     switch ((item->type) & 0xFF)
1373     {
1374         case cJSON_NULL:
1375             output = ensure(output_buffer, 5);
1376             if (output == NULL)
1377             {
1378                 return false;
1379             }
1380             strcpy((char*)output, "null");
1381             return true;
1382 
1383         case cJSON_False:
1384             output = ensure(output_buffer, 6);
1385             if (output == NULL)
1386             {
1387                 return false;
1388             }
1389             strcpy((char*)output, "false");
1390             return true;
1391 
1392         case cJSON_True:
1393             output = ensure(output_buffer, 5);
1394             if (output == NULL)
1395             {
1396                 return false;
1397             }
1398             strcpy((char*)output, "true");
1399             return true;
1400 
1401         case cJSON_Number:
1402             return print_number(item, output_buffer);
1403 
1404         case cJSON_Raw:
1405         {
1406             size_t raw_length = 0;
1407             if (item->valuestring == NULL)
1408             {
1409                 return false;
1410             }
1411 
1412             raw_length = strlen(item->valuestring) + sizeof("");
1413             output = ensure(output_buffer, raw_length);
1414             if (output == NULL)
1415             {
1416                 return false;
1417             }
1418             memcpy(output, item->valuestring, raw_length);
1419             return true;
1420         }
1421 
1422         case cJSON_String:
1423             return print_string(item, output_buffer);
1424 
1425         case cJSON_Array:
1426             return print_array(item, output_buffer);
1427 
1428         case cJSON_Object:
1429             return print_object(item, output_buffer);
1430 
1431         default:
1432             return false;
1433     }
1434 }
1435 
1436 /* Build an array from input text. */
parse_array(cJSON * const item,parse_buffer * const input_buffer)1437 static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
1438 {
1439     cJSON *head = NULL; /* head of the linked list */
1440     cJSON *current_item = NULL;
1441 
1442     if (input_buffer->depth >= CJSON_NESTING_LIMIT)
1443     {
1444         return false; /* to deeply nested */
1445     }
1446     input_buffer->depth++;
1447 
1448     if (buffer_at_offset(input_buffer)[0] != '[')
1449     {
1450         /* not an array */
1451         goto fail;
1452     }
1453 
1454     input_buffer->offset++;
1455     buffer_skip_whitespace(input_buffer);
1456     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
1457     {
1458         /* empty array */
1459         goto success;
1460     }
1461 
1462     /* check if we skipped to the end of the buffer */
1463     if (cannot_access_at_index(input_buffer, 0))
1464     {
1465         input_buffer->offset--;
1466         goto fail;
1467     }
1468 
1469     /* step back to character in front of the first element */
1470     input_buffer->offset--;
1471     /* loop through the comma separated array elements */
1472     do
1473     {
1474         /* allocate next item */
1475         cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
1476         if (new_item == NULL)
1477         {
1478             goto fail; /* allocation failure */
1479         }
1480 
1481         /* attach next item to list */
1482         if (head == NULL)
1483         {
1484             /* start the linked list */
1485             current_item = head = new_item;
1486         }
1487         else
1488         {
1489             /* add to the end and advance */
1490             current_item->next = new_item;
1491             new_item->prev = current_item;
1492             current_item = new_item;
1493         }
1494 
1495         /* parse next value */
1496         input_buffer->offset++;
1497         buffer_skip_whitespace(input_buffer);
1498         if (!parse_value(current_item, input_buffer))
1499         {
1500             goto fail; /* failed to parse value */
1501         }
1502         buffer_skip_whitespace(input_buffer);
1503     }
1504     while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1505 
1506     if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
1507     {
1508         goto fail; /* expected end of array */
1509     }
1510 
1511 success:
1512     input_buffer->depth--;
1513 
1514     if (head != NULL) {
1515         head->prev = current_item;
1516     }
1517 
1518     item->type = cJSON_Array;
1519     item->child = head;
1520 
1521     input_buffer->offset++;
1522 
1523     return true;
1524 
1525 fail:
1526     if (head != NULL)
1527     {
1528         cJSON_Delete(head);
1529     }
1530 
1531     return false;
1532 }
1533 
1534 /* Render an array to text */
print_array(const cJSON * const item,printbuffer * const output_buffer)1535 static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
1536 {
1537     unsigned char *output_pointer = NULL;
1538     size_t length = 0;
1539     cJSON *current_element = item->child;
1540 
1541     if (output_buffer == NULL)
1542     {
1543         return false;
1544     }
1545 
1546     /* Compose the output array. */
1547     /* opening square bracket */
1548     output_pointer = ensure(output_buffer, 1);
1549     if (output_pointer == NULL)
1550     {
1551         return false;
1552     }
1553 
1554     *output_pointer = '[';
1555     output_buffer->offset++;
1556     output_buffer->depth++;
1557 
1558     while (current_element != NULL)
1559     {
1560         if (!print_value(current_element, output_buffer))
1561         {
1562             return false;
1563         }
1564         update_offset(output_buffer);
1565         if (current_element->next)
1566         {
1567             length = (size_t) (output_buffer->format ? 2 : 1);
1568             output_pointer = ensure(output_buffer, length + 1);
1569             if (output_pointer == NULL)
1570             {
1571                 return false;
1572             }
1573             *output_pointer++ = ',';
1574             if(output_buffer->format)
1575             {
1576                 *output_pointer++ = ' ';
1577             }
1578             *output_pointer = '\0';
1579             output_buffer->offset += length;
1580         }
1581         current_element = current_element->next;
1582     }
1583 
1584     output_pointer = ensure(output_buffer, 2);
1585     if (output_pointer == NULL)
1586     {
1587         return false;
1588     }
1589     *output_pointer++ = ']';
1590     *output_pointer = '\0';
1591     output_buffer->depth--;
1592 
1593     return true;
1594 }
1595 
1596 /* Build an object from the text. */
parse_object(cJSON * const item,parse_buffer * const input_buffer)1597 static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
1598 {
1599     cJSON *head = NULL; /* linked list head */
1600     cJSON *current_item = NULL;
1601 
1602     if (input_buffer->depth >= CJSON_NESTING_LIMIT)
1603     {
1604         return false; /* to deeply nested */
1605     }
1606     input_buffer->depth++;
1607 
1608     if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
1609     {
1610         goto fail; /* not an object */
1611     }
1612 
1613     input_buffer->offset++;
1614     buffer_skip_whitespace(input_buffer);
1615     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
1616     {
1617         goto success; /* empty object */
1618     }
1619 
1620     /* check if we skipped to the end of the buffer */
1621     if (cannot_access_at_index(input_buffer, 0))
1622     {
1623         input_buffer->offset--;
1624         goto fail;
1625     }
1626 
1627     /* step back to character in front of the first element */
1628     input_buffer->offset--;
1629     /* loop through the comma separated array elements */
1630     do
1631     {
1632         /* allocate next item */
1633         cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
1634         if (new_item == NULL)
1635         {
1636             goto fail; /* allocation failure */
1637         }
1638 
1639         /* attach next item to list */
1640         if (head == NULL)
1641         {
1642             /* start the linked list */
1643             current_item = head = new_item;
1644         }
1645         else
1646         {
1647             /* add to the end and advance */
1648             current_item->next = new_item;
1649             new_item->prev = current_item;
1650             current_item = new_item;
1651         }
1652 
1653         /* parse the name of the child */
1654         input_buffer->offset++;
1655         buffer_skip_whitespace(input_buffer);
1656         if (!parse_string(current_item, input_buffer))
1657         {
1658             goto fail; /* failed to parse name */
1659         }
1660         buffer_skip_whitespace(input_buffer);
1661 
1662         /* swap valuestring and string, because we parsed the name */
1663         current_item->string = current_item->valuestring;
1664         current_item->valuestring = NULL;
1665 
1666         if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
1667         {
1668             goto fail; /* invalid object */
1669         }
1670 
1671         /* parse the value */
1672         input_buffer->offset++;
1673         buffer_skip_whitespace(input_buffer);
1674         if (!parse_value(current_item, input_buffer))
1675         {
1676             goto fail; /* failed to parse value */
1677         }
1678         buffer_skip_whitespace(input_buffer);
1679     }
1680     while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1681 
1682     if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
1683     {
1684         goto fail; /* expected end of object */
1685     }
1686 
1687 success:
1688     input_buffer->depth--;
1689 
1690     if (head != NULL) {
1691         head->prev = current_item;
1692     }
1693 
1694     item->type = cJSON_Object;
1695     item->child = head;
1696 
1697     input_buffer->offset++;
1698     return true;
1699 
1700 fail:
1701     if (head != NULL)
1702     {
1703         cJSON_Delete(head);
1704     }
1705 
1706     return false;
1707 }
1708 
1709 /* Render an object to text. */
print_object(const cJSON * const item,printbuffer * const output_buffer)1710 static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
1711 {
1712     unsigned char *output_pointer = NULL;
1713     size_t length = 0;
1714     cJSON *current_item = item->child;
1715 
1716     if (output_buffer == NULL)
1717     {
1718         return false;
1719     }
1720 
1721     /* Compose the output: */
1722     length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
1723     output_pointer = ensure(output_buffer, length + 1);
1724     if (output_pointer == NULL)
1725     {
1726         return false;
1727     }
1728 
1729     *output_pointer++ = '{';
1730     output_buffer->depth++;
1731     if (output_buffer->format)
1732     {
1733         *output_pointer++ = '\n';
1734     }
1735     output_buffer->offset += length;
1736 
1737     while (current_item)
1738     {
1739         if (output_buffer->format)
1740         {
1741             size_t i;
1742             output_pointer = ensure(output_buffer, output_buffer->depth);
1743             if (output_pointer == NULL)
1744             {
1745                 return false;
1746             }
1747             for (i = 0; i < output_buffer->depth; i++)
1748             {
1749                 *output_pointer++ = '\t';
1750             }
1751             output_buffer->offset += output_buffer->depth;
1752         }
1753 
1754         /* print key */
1755         if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
1756         {
1757             return false;
1758         }
1759         update_offset(output_buffer);
1760 
1761         length = (size_t) (output_buffer->format ? 2 : 1);
1762         output_pointer = ensure(output_buffer, length);
1763         if (output_pointer == NULL)
1764         {
1765             return false;
1766         }
1767         *output_pointer++ = ':';
1768         if (output_buffer->format)
1769         {
1770             *output_pointer++ = '\t';
1771         }
1772         output_buffer->offset += length;
1773 
1774         /* print value */
1775         if (!print_value(current_item, output_buffer))
1776         {
1777             return false;
1778         }
1779         update_offset(output_buffer);
1780 
1781         /* print comma if not last */
1782         length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
1783         output_pointer = ensure(output_buffer, length + 1);
1784         if (output_pointer == NULL)
1785         {
1786             return false;
1787         }
1788         if (current_item->next)
1789         {
1790             *output_pointer++ = ',';
1791         }
1792 
1793         if (output_buffer->format)
1794         {
1795             *output_pointer++ = '\n';
1796         }
1797         *output_pointer = '\0';
1798         output_buffer->offset += length;
1799 
1800         current_item = current_item->next;
1801     }
1802 
1803     output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
1804     if (output_pointer == NULL)
1805     {
1806         return false;
1807     }
1808     if (output_buffer->format)
1809     {
1810         size_t i;
1811         for (i = 0; i < (output_buffer->depth - 1); i++)
1812         {
1813             *output_pointer++ = '\t';
1814         }
1815     }
1816     *output_pointer++ = '}';
1817     *output_pointer = '\0';
1818     output_buffer->depth--;
1819 
1820     return true;
1821 }
1822 
1823 /* Get Array size/item / object item. */
cJSON_GetArraySize(const cJSON * array)1824 CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
1825 {
1826     cJSON *child = NULL;
1827     size_t size = 0;
1828 
1829     if (array == NULL)
1830     {
1831         return 0;
1832     }
1833 
1834     child = array->child;
1835 
1836     while(child != NULL)
1837     {
1838         size++;
1839         child = child->next;
1840     }
1841 
1842     /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
1843 
1844     return (int)size;
1845 }
1846 
get_array_item(const cJSON * array,size_t index)1847 static cJSON* get_array_item(const cJSON *array, size_t index)
1848 {
1849     cJSON *current_child = NULL;
1850 
1851     if (array == NULL)
1852     {
1853         return NULL;
1854     }
1855 
1856     current_child = array->child;
1857     while ((current_child != NULL) && (index > 0))
1858     {
1859         index--;
1860         current_child = current_child->next;
1861     }
1862 
1863     return current_child;
1864 }
1865 
cJSON_GetArrayItem(const cJSON * array,int index)1866 CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
1867 {
1868     if (index < 0)
1869     {
1870         return NULL;
1871     }
1872 
1873     return get_array_item(array, (size_t)index);
1874 }
1875 
get_object_item(const cJSON * const object,const char * const name,const cJSON_bool case_sensitive)1876 static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
1877 {
1878     cJSON *current_element = NULL;
1879 
1880     if ((object == NULL) || (name == NULL))
1881     {
1882         return NULL;
1883     }
1884 
1885     current_element = object->child;
1886     if (case_sensitive)
1887     {
1888         while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
1889         {
1890             current_element = current_element->next;
1891         }
1892     }
1893     else
1894     {
1895         while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
1896         {
1897             current_element = current_element->next;
1898         }
1899     }
1900 
1901     if ((current_element == NULL) || (current_element->string == NULL)) {
1902         return NULL;
1903     }
1904 
1905     return current_element;
1906 }
1907 
cJSON_GetObjectItem(const cJSON * const object,const char * const string)1908 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
1909 {
1910     return get_object_item(object, string, false);
1911 }
1912 
cJSON_GetObjectItemCaseSensitive(const cJSON * const object,const char * const string)1913 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
1914 {
1915     return get_object_item(object, string, true);
1916 }
1917 
cJSON_HasObjectItem(const cJSON * object,const char * string)1918 CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
1919 {
1920     return cJSON_GetObjectItem(object, string) ? 1 : 0;
1921 }
1922 
1923 /* Utility for array list handling. */
suffix_object(cJSON * prev,cJSON * item)1924 static void suffix_object(cJSON *prev, cJSON *item)
1925 {
1926     prev->next = item;
1927     item->prev = prev;
1928 }
1929 
1930 /* Utility for handling references. */
create_reference(const cJSON * item,const internal_hooks * const hooks)1931 static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
1932 {
1933     cJSON *reference = NULL;
1934     if (item == NULL)
1935     {
1936         return NULL;
1937     }
1938 
1939     reference = cJSON_New_Item(hooks);
1940     if (reference == NULL)
1941     {
1942         return NULL;
1943     }
1944 
1945     memcpy(reference, item, sizeof(cJSON));
1946     reference->string = NULL;
1947     reference->type |= cJSON_IsReference;
1948     reference->next = reference->prev = NULL;
1949     return reference;
1950 }
1951 
add_item_to_array(cJSON * array,cJSON * item)1952 static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
1953 {
1954     cJSON *child = NULL;
1955 
1956     if ((item == NULL) || (array == NULL) || (array == item))
1957     {
1958         return false;
1959     }
1960 
1961     child = array->child;
1962     /*
1963      * To find the last item in array quickly, we use prev in array
1964      */
1965     if (child == NULL)
1966     {
1967         /* list is empty, start new one */
1968         array->child = item;
1969         item->prev = item;
1970         item->next = NULL;
1971     }
1972     else
1973     {
1974         /* append to the end */
1975         if (child->prev)
1976         {
1977             suffix_object(child->prev, item);
1978             array->child->prev = item;
1979         }
1980     }
1981 
1982     return true;
1983 }
1984 
1985 /* Add item to array/object. */
cJSON_AddItemToArray(cJSON * array,cJSON * item)1986 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item)
1987 {
1988     return add_item_to_array(array, item);
1989 }
1990 
1991 #if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
1992     #pragma GCC diagnostic push
1993 #endif
1994 #ifdef __GNUC__
1995 #pragma GCC diagnostic ignored "-Wcast-qual"
1996 #endif
1997 /* helper function to cast away const */
cast_away_const(const void * string)1998 static void* cast_away_const(const void* string)
1999 {
2000     return (void*)string;
2001 }
2002 #if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
2003     #pragma GCC diagnostic pop
2004 #endif
2005 
2006 
add_item_to_object(cJSON * const object,const char * const string,cJSON * const item,const internal_hooks * const hooks,const cJSON_bool constant_key)2007 static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
2008 {
2009     char *new_key = NULL;
2010     int new_type = cJSON_Invalid;
2011 
2012     if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
2013     {
2014         return false;
2015     }
2016 
2017     if (constant_key)
2018     {
2019         new_key = (char*)cast_away_const(string);
2020         new_type = item->type | cJSON_StringIsConst;
2021     }
2022     else
2023     {
2024         new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
2025         if (new_key == NULL)
2026         {
2027             return false;
2028         }
2029 
2030         new_type = item->type & ~cJSON_StringIsConst;
2031     }
2032 
2033     if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
2034     {
2035         hooks->deallocate(item->string);
2036     }
2037 
2038     item->string = new_key;
2039     item->type = new_type;
2040 
2041     return add_item_to_array(object, item);
2042 }
2043 
cJSON_AddItemToObject(cJSON * object,const char * string,cJSON * item)2044 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
2045 {
2046     return add_item_to_object(object, string, item, &global_hooks, false);
2047 }
2048 
2049 /* Add an item to an object with constant string as key */
cJSON_AddItemToObjectCS(cJSON * object,const char * string,cJSON * item)2050 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
2051 {
2052     return add_item_to_object(object, string, item, &global_hooks, true);
2053 }
2054 
cJSON_AddItemReferenceToArray(cJSON * array,cJSON * item)2055 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
2056 {
2057     if (array == NULL)
2058     {
2059         return false;
2060     }
2061 
2062     return add_item_to_array(array, create_reference(item, &global_hooks));
2063 }
2064 
cJSON_AddItemReferenceToObject(cJSON * object,const char * string,cJSON * item)2065 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
2066 {
2067     if ((object == NULL) || (string == NULL))
2068     {
2069         return false;
2070     }
2071 
2072     return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
2073 }
2074 
cJSON_AddNullToObject(cJSON * const object,const char * const name)2075 CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
2076 {
2077     cJSON *null = cJSON_CreateNull();
2078     if (add_item_to_object(object, name, null, &global_hooks, false))
2079     {
2080         return null;
2081     }
2082 
2083     cJSON_Delete(null);
2084     return NULL;
2085 }
2086 
cJSON_AddTrueToObject(cJSON * const object,const char * const name)2087 CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
2088 {
2089     cJSON *true_item = cJSON_CreateTrue();
2090     if (add_item_to_object(object, name, true_item, &global_hooks, false))
2091     {
2092         return true_item;
2093     }
2094 
2095     cJSON_Delete(true_item);
2096     return NULL;
2097 }
2098 
cJSON_AddFalseToObject(cJSON * const object,const char * const name)2099 CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
2100 {
2101     cJSON *false_item = cJSON_CreateFalse();
2102     if (add_item_to_object(object, name, false_item, &global_hooks, false))
2103     {
2104         return false_item;
2105     }
2106 
2107     cJSON_Delete(false_item);
2108     return NULL;
2109 }
2110 
cJSON_AddBoolToObject(cJSON * const object,const char * const name,const cJSON_bool boolean)2111 CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
2112 {
2113     cJSON *bool_item = cJSON_CreateBool(boolean);
2114     if (add_item_to_object(object, name, bool_item, &global_hooks, false))
2115     {
2116         return bool_item;
2117     }
2118 
2119     cJSON_Delete(bool_item);
2120     return NULL;
2121 }
2122 
cJSON_AddNumberToObject(cJSON * const object,const char * const name,const double number)2123 CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
2124 {
2125     cJSON *number_item = cJSON_CreateNumber(number);
2126     if (add_item_to_object(object, name, number_item, &global_hooks, false))
2127     {
2128         return number_item;
2129     }
2130 
2131     cJSON_Delete(number_item);
2132     return NULL;
2133 }
2134 
cJSON_AddStringToObject(cJSON * const object,const char * const name,const char * const string)2135 CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
2136 {
2137     cJSON *string_item = cJSON_CreateString(string);
2138     if (add_item_to_object(object, name, string_item, &global_hooks, false))
2139     {
2140         return string_item;
2141     }
2142 
2143     cJSON_Delete(string_item);
2144     return NULL;
2145 }
2146 
cJSON_AddRawToObject(cJSON * const object,const char * const name,const char * const raw)2147 CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
2148 {
2149     cJSON *raw_item = cJSON_CreateRaw(raw);
2150     if (add_item_to_object(object, name, raw_item, &global_hooks, false))
2151     {
2152         return raw_item;
2153     }
2154 
2155     cJSON_Delete(raw_item);
2156     return NULL;
2157 }
2158 
cJSON_AddObjectToObject(cJSON * const object,const char * const name)2159 CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
2160 {
2161     cJSON *object_item = cJSON_CreateObject();
2162     if (add_item_to_object(object, name, object_item, &global_hooks, false))
2163     {
2164         return object_item;
2165     }
2166 
2167     cJSON_Delete(object_item);
2168     return NULL;
2169 }
2170 
cJSON_AddArrayToObject(cJSON * const object,const char * const name)2171 CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
2172 {
2173     cJSON *array = cJSON_CreateArray();
2174     if (add_item_to_object(object, name, array, &global_hooks, false))
2175     {
2176         return array;
2177     }
2178 
2179     cJSON_Delete(array);
2180     return NULL;
2181 }
2182 
cJSON_DetachItemViaPointer(cJSON * parent,cJSON * const item)2183 CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
2184 {
2185     if ((parent == NULL) || (item == NULL))
2186     {
2187         return NULL;
2188     }
2189 
2190     if (item != parent->child)
2191     {
2192         /* not the first element */
2193         item->prev->next = item->next;
2194     }
2195     if (item->next != NULL)
2196     {
2197         /* not the last element */
2198         item->next->prev = item->prev;
2199     }
2200 
2201     if (item == parent->child)
2202     {
2203         /* first element */
2204         parent->child = item->next;
2205     }
2206     else if (item->next == NULL)
2207     {
2208         /* last element */
2209         parent->child->prev = item->prev;
2210     }
2211 
2212     /* make sure the detached item doesn't point anywhere anymore */
2213     item->prev = NULL;
2214     item->next = NULL;
2215 
2216     return item;
2217 }
2218 
cJSON_DetachItemFromArray(cJSON * array,int which)2219 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
2220 {
2221     if (which < 0)
2222     {
2223         return NULL;
2224     }
2225 
2226     return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
2227 }
2228 
cJSON_DeleteItemFromArray(cJSON * array,int which)2229 CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
2230 {
2231     cJSON_Delete(cJSON_DetachItemFromArray(array, which));
2232 }
2233 
cJSON_DetachItemFromObject(cJSON * object,const char * string)2234 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
2235 {
2236     cJSON *to_detach = cJSON_GetObjectItem(object, string);
2237 
2238     return cJSON_DetachItemViaPointer(object, to_detach);
2239 }
2240 
cJSON_DetachItemFromObjectCaseSensitive(cJSON * object,const char * string)2241 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
2242 {
2243     cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
2244 
2245     return cJSON_DetachItemViaPointer(object, to_detach);
2246 }
2247 
cJSON_DeleteItemFromObject(cJSON * object,const char * string)2248 CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
2249 {
2250     cJSON_Delete(cJSON_DetachItemFromObject(object, string));
2251 }
2252 
cJSON_DeleteItemFromObjectCaseSensitive(cJSON * object,const char * string)2253 CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
2254 {
2255     cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
2256 }
2257 
2258 /* Replace array/object items with new ones. */
cJSON_InsertItemInArray(cJSON * array,int which,cJSON * newitem)2259 CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
2260 {
2261     cJSON *after_inserted = NULL;
2262 
2263     if (which < 0)
2264     {
2265         return false;
2266     }
2267 
2268     after_inserted = get_array_item(array, (size_t)which);
2269     if (after_inserted == NULL)
2270     {
2271         return add_item_to_array(array, newitem);
2272     }
2273 
2274     newitem->next = after_inserted;
2275     newitem->prev = after_inserted->prev;
2276     after_inserted->prev = newitem;
2277     if (after_inserted == array->child)
2278     {
2279         array->child = newitem;
2280     }
2281     else
2282     {
2283         newitem->prev->next = newitem;
2284     }
2285     return true;
2286 }
2287 
cJSON_ReplaceItemViaPointer(cJSON * const parent,cJSON * const item,cJSON * replacement)2288 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
2289 {
2290     if ((parent == NULL) || (replacement == NULL) || (item == NULL))
2291     {
2292         return false;
2293     }
2294 
2295     if (replacement == item)
2296     {
2297         return true;
2298     }
2299 
2300     replacement->next = item->next;
2301     replacement->prev = item->prev;
2302 
2303     if (replacement->next != NULL)
2304     {
2305         replacement->next->prev = replacement;
2306     }
2307     if (parent->child == item)
2308     {
2309         if (parent->child->prev == parent->child)
2310         {
2311             replacement->prev = replacement;
2312         }
2313         parent->child = replacement;
2314     }
2315     else
2316     {   /*
2317          * To find the last item in array quickly, we use prev in array.
2318          * We can't modify the last item's next pointer where this item was the parent's child
2319          */
2320         if (replacement->prev != NULL)
2321         {
2322             replacement->prev->next = replacement;
2323         }
2324         if (replacement->next == NULL)
2325         {
2326             parent->child->prev = replacement;
2327         }
2328     }
2329 
2330     item->next = NULL;
2331     item->prev = NULL;
2332     cJSON_Delete(item);
2333 
2334     return true;
2335 }
2336 
cJSON_ReplaceItemInArray(cJSON * array,int which,cJSON * newitem)2337 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
2338 {
2339     if (which < 0)
2340     {
2341         return false;
2342     }
2343 
2344     return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
2345 }
2346 
replace_item_in_object(cJSON * object,const char * string,cJSON * replacement,cJSON_bool case_sensitive)2347 static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
2348 {
2349     if ((replacement == NULL) || (string == NULL))
2350     {
2351         return false;
2352     }
2353 
2354     /* replace the name in the replacement */
2355     if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
2356     {
2357         cJSON_free(replacement->string);
2358     }
2359     replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
2360     replacement->type &= ~cJSON_StringIsConst;
2361 
2362     return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
2363 }
2364 
cJSON_ReplaceItemInObject(cJSON * object,const char * string,cJSON * newitem)2365 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
2366 {
2367     return replace_item_in_object(object, string, newitem, false);
2368 }
2369 
cJSON_ReplaceItemInObjectCaseSensitive(cJSON * object,const char * string,cJSON * newitem)2370 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
2371 {
2372     return replace_item_in_object(object, string, newitem, true);
2373 }
2374 
2375 /* Create basic types: */
cJSON_CreateNull(void)2376 CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
2377 {
2378     cJSON *item = cJSON_New_Item(&global_hooks);
2379     if(item)
2380     {
2381         item->type = cJSON_NULL;
2382     }
2383 
2384     return item;
2385 }
2386 
cJSON_CreateTrue(void)2387 CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
2388 {
2389     cJSON *item = cJSON_New_Item(&global_hooks);
2390     if(item)
2391     {
2392         item->type = cJSON_True;
2393     }
2394 
2395     return item;
2396 }
2397 
cJSON_CreateFalse(void)2398 CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
2399 {
2400     cJSON *item = cJSON_New_Item(&global_hooks);
2401     if(item)
2402     {
2403         item->type = cJSON_False;
2404     }
2405 
2406     return item;
2407 }
2408 
cJSON_CreateBool(cJSON_bool boolean)2409 CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
2410 {
2411     cJSON *item = cJSON_New_Item(&global_hooks);
2412     if(item)
2413     {
2414         item->type = boolean ? cJSON_True : cJSON_False;
2415     }
2416 
2417     return item;
2418 }
2419 
cJSON_CreateNumber(double num)2420 CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
2421 {
2422     cJSON *item = cJSON_New_Item(&global_hooks);
2423     if(item)
2424     {
2425         item->type = cJSON_Number;
2426         item->valuedouble = num;
2427 
2428         /* use saturation in case of overflow */
2429         if (num >= INT_MAX)
2430         {
2431             item->valueint = INT_MAX;
2432         }
2433         else if (num <= (double)INT_MIN)
2434         {
2435             item->valueint = INT_MIN;
2436         }
2437         else
2438         {
2439             item->valueint = (int)num;
2440         }
2441     }
2442 
2443     return item;
2444 }
2445 
cJSON_CreateString(const char * string)2446 CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
2447 {
2448     cJSON *item = cJSON_New_Item(&global_hooks);
2449     if(item)
2450     {
2451         item->type = cJSON_String;
2452         item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
2453         if(!item->valuestring)
2454         {
2455             cJSON_Delete(item);
2456             return NULL;
2457         }
2458     }
2459 
2460     return item;
2461 }
2462 
cJSON_CreateStringReference(const char * string)2463 CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
2464 {
2465     cJSON *item = cJSON_New_Item(&global_hooks);
2466     if (item != NULL)
2467     {
2468         item->type = cJSON_String | cJSON_IsReference;
2469         item->valuestring = (char*)cast_away_const(string);
2470     }
2471 
2472     return item;
2473 }
2474 
cJSON_CreateObjectReference(const cJSON * child)2475 CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
2476 {
2477     cJSON *item = cJSON_New_Item(&global_hooks);
2478     if (item != NULL) {
2479         item->type = cJSON_Object | cJSON_IsReference;
2480         item->child = (cJSON*)cast_away_const(child);
2481     }
2482 
2483     return item;
2484 }
2485 
cJSON_CreateArrayReference(const cJSON * child)2486 CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
2487     cJSON *item = cJSON_New_Item(&global_hooks);
2488     if (item != NULL) {
2489         item->type = cJSON_Array | cJSON_IsReference;
2490         item->child = (cJSON*)cast_away_const(child);
2491     }
2492 
2493     return item;
2494 }
2495 
cJSON_CreateRaw(const char * raw)2496 CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
2497 {
2498     cJSON *item = cJSON_New_Item(&global_hooks);
2499     if(item)
2500     {
2501         item->type = cJSON_Raw;
2502         item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
2503         if(!item->valuestring)
2504         {
2505             cJSON_Delete(item);
2506             return NULL;
2507         }
2508     }
2509 
2510     return item;
2511 }
2512 
cJSON_CreateArray(void)2513 CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
2514 {
2515     cJSON *item = cJSON_New_Item(&global_hooks);
2516     if(item)
2517     {
2518         item->type=cJSON_Array;
2519     }
2520 
2521     return item;
2522 }
2523 
cJSON_CreateObject(void)2524 CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
2525 {
2526     cJSON *item = cJSON_New_Item(&global_hooks);
2527     if (item)
2528     {
2529         item->type = cJSON_Object;
2530     }
2531 
2532     return item;
2533 }
2534 
2535 /* Create Arrays: */
cJSON_CreateIntArray(const int * numbers,int count)2536 CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
2537 {
2538     size_t i = 0;
2539     cJSON *n = NULL;
2540     cJSON *p = NULL;
2541     cJSON *a = NULL;
2542 
2543     if ((count < 0) || (numbers == NULL))
2544     {
2545         return NULL;
2546     }
2547 
2548     a = cJSON_CreateArray();
2549 
2550     for(i = 0; a && (i < (size_t)count); i++)
2551     {
2552         n = cJSON_CreateNumber(numbers[i]);
2553         if (!n)
2554         {
2555             cJSON_Delete(a);
2556             return NULL;
2557         }
2558         if(!i)
2559         {
2560             a->child = n;
2561         }
2562         else
2563         {
2564             suffix_object(p, n);
2565         }
2566         p = n;
2567     }
2568 
2569     if (a && a->child) {
2570         a->child->prev = n;
2571     }
2572 
2573     return a;
2574 }
2575 
cJSON_CreateFloatArray(const float * numbers,int count)2576 CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
2577 {
2578     size_t i = 0;
2579     cJSON *n = NULL;
2580     cJSON *p = NULL;
2581     cJSON *a = NULL;
2582 
2583     if ((count < 0) || (numbers == NULL))
2584     {
2585         return NULL;
2586     }
2587 
2588     a = cJSON_CreateArray();
2589 
2590     for(i = 0; a && (i < (size_t)count); i++)
2591     {
2592         n = cJSON_CreateNumber((double)numbers[i]);
2593         if(!n)
2594         {
2595             cJSON_Delete(a);
2596             return NULL;
2597         }
2598         if(!i)
2599         {
2600             a->child = n;
2601         }
2602         else
2603         {
2604             suffix_object(p, n);
2605         }
2606         p = n;
2607     }
2608 
2609     if (a && a->child) {
2610         a->child->prev = n;
2611     }
2612 
2613     return a;
2614 }
2615 
cJSON_CreateDoubleArray(const double * numbers,int count)2616 CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
2617 {
2618     size_t i = 0;
2619     cJSON *n = NULL;
2620     cJSON *p = NULL;
2621     cJSON *a = NULL;
2622 
2623     if ((count < 0) || (numbers == NULL))
2624     {
2625         return NULL;
2626     }
2627 
2628     a = cJSON_CreateArray();
2629 
2630     for(i = 0; a && (i < (size_t)count); i++)
2631     {
2632         n = cJSON_CreateNumber(numbers[i]);
2633         if(!n)
2634         {
2635             cJSON_Delete(a);
2636             return NULL;
2637         }
2638         if(!i)
2639         {
2640             a->child = n;
2641         }
2642         else
2643         {
2644             suffix_object(p, n);
2645         }
2646         p = n;
2647     }
2648 
2649     if (a && a->child) {
2650         a->child->prev = n;
2651     }
2652 
2653     return a;
2654 }
2655 
cJSON_CreateStringArray(const char * const * strings,int count)2656 CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count)
2657 {
2658     size_t i = 0;
2659     cJSON *n = NULL;
2660     cJSON *p = NULL;
2661     cJSON *a = NULL;
2662 
2663     if ((count < 0) || (strings == NULL))
2664     {
2665         return NULL;
2666     }
2667 
2668     a = cJSON_CreateArray();
2669 
2670     for (i = 0; a && (i < (size_t)count); i++)
2671     {
2672         n = cJSON_CreateString(strings[i]);
2673         if(!n)
2674         {
2675             cJSON_Delete(a);
2676             return NULL;
2677         }
2678         if(!i)
2679         {
2680             a->child = n;
2681         }
2682         else
2683         {
2684             suffix_object(p,n);
2685         }
2686         p = n;
2687     }
2688 
2689     if (a && a->child) {
2690         a->child->prev = n;
2691     }
2692 
2693     return a;
2694 }
2695 
2696 /* Duplication */
cJSON_Duplicate(const cJSON * item,cJSON_bool recurse)2697 CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
2698 {
2699     cJSON *newitem = NULL;
2700     cJSON *child = NULL;
2701     cJSON *next = NULL;
2702     cJSON *newchild = NULL;
2703 
2704     /* Bail on bad ptr */
2705     if (!item)
2706     {
2707         goto fail;
2708     }
2709     /* Create new item */
2710     newitem = cJSON_New_Item(&global_hooks);
2711     if (!newitem)
2712     {
2713         goto fail;
2714     }
2715     /* Copy over all vars */
2716     newitem->type = item->type & (~cJSON_IsReference);
2717     newitem->valueint = item->valueint;
2718     newitem->valuedouble = item->valuedouble;
2719     if (item->valuestring)
2720     {
2721         newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
2722         if (!newitem->valuestring)
2723         {
2724             goto fail;
2725         }
2726     }
2727     if (item->string)
2728     {
2729         newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
2730         if (!newitem->string)
2731         {
2732             goto fail;
2733         }
2734     }
2735     /* If non-recursive, then we're done! */
2736     if (!recurse)
2737     {
2738         return newitem;
2739     }
2740     /* Walk the ->next chain for the child. */
2741     child = item->child;
2742     while (child != NULL)
2743     {
2744         newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
2745         if (!newchild)
2746         {
2747             goto fail;
2748         }
2749         if (next != NULL)
2750         {
2751             /* If newitem->child already set, then crosswire ->prev and ->next and move on */
2752             next->next = newchild;
2753             newchild->prev = next;
2754             next = newchild;
2755         }
2756         else
2757         {
2758             /* Set newitem->child and move to it */
2759             newitem->child = newchild;
2760             next = newchild;
2761         }
2762         child = child->next;
2763     }
2764     if (newitem && newitem->child)
2765     {
2766         newitem->child->prev = newchild;
2767     }
2768 
2769     return newitem;
2770 
2771 fail:
2772     if (newitem != NULL)
2773     {
2774         cJSON_Delete(newitem);
2775     }
2776 
2777     return NULL;
2778 }
2779 
skip_oneline_comment(char ** input)2780 static void skip_oneline_comment(char **input)
2781 {
2782     *input += static_strlen("//");
2783 
2784     for (; (*input)[0] != '\0'; ++(*input))
2785     {
2786         if ((*input)[0] == '\n') {
2787             *input += static_strlen("\n");
2788             return;
2789         }
2790     }
2791 }
2792 
skip_multiline_comment(char ** input)2793 static void skip_multiline_comment(char **input)
2794 {
2795     *input += static_strlen("/*");
2796 
2797     for (; (*input)[0] != '\0'; ++(*input))
2798     {
2799         if (((*input)[0] == '*') && ((*input)[1] == '/'))
2800         {
2801             *input += static_strlen("*/");
2802             return;
2803         }
2804     }
2805 }
2806 
minify_string(char ** input,char ** output)2807 static void minify_string(char **input, char **output) {
2808     (*output)[0] = (*input)[0];
2809     *input += static_strlen("\"");
2810     *output += static_strlen("\"");
2811 
2812 
2813     for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
2814         (*output)[0] = (*input)[0];
2815 
2816         if ((*input)[0] == '\"') {
2817             (*output)[0] = '\"';
2818             *input += static_strlen("\"");
2819             *output += static_strlen("\"");
2820             return;
2821         } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
2822             (*output)[1] = (*input)[1];
2823             *input += static_strlen("\"");
2824             *output += static_strlen("\"");
2825         }
2826     }
2827 }
2828 
cJSON_Minify(char * json)2829 CJSON_PUBLIC(void) cJSON_Minify(char *json)
2830 {
2831     char *into = json;
2832 
2833     if (json == NULL)
2834     {
2835         return;
2836     }
2837 
2838     while (json[0] != '\0')
2839     {
2840         switch (json[0])
2841         {
2842             case ' ':
2843             case '\t':
2844             case '\r':
2845             case '\n':
2846                 json++;
2847                 break;
2848 
2849             case '/':
2850                 if (json[1] == '/')
2851                 {
2852                     skip_oneline_comment(&json);
2853                 }
2854                 else if (json[1] == '*')
2855                 {
2856                     skip_multiline_comment(&json);
2857                 } else {
2858                     json++;
2859                 }
2860                 break;
2861 
2862             case '\"':
2863                 minify_string(&json, (char**)&into);
2864                 break;
2865 
2866             default:
2867                 into[0] = json[0];
2868                 json++;
2869                 into++;
2870         }
2871     }
2872 
2873     /* and null-terminate. */
2874     *into = '\0';
2875 }
2876 
cJSON_IsInvalid(const cJSON * const item)2877 CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
2878 {
2879     if (item == NULL)
2880     {
2881         return false;
2882     }
2883 
2884     return (item->type & 0xFF) == cJSON_Invalid;
2885 }
2886 
cJSON_IsFalse(const cJSON * const item)2887 CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
2888 {
2889     if (item == NULL)
2890     {
2891         return false;
2892     }
2893 
2894     return (item->type & 0xFF) == cJSON_False;
2895 }
2896 
cJSON_IsTrue(const cJSON * const item)2897 CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
2898 {
2899     if (item == NULL)
2900     {
2901         return false;
2902     }
2903 
2904     return (item->type & 0xff) == cJSON_True;
2905 }
2906 
2907 
cJSON_IsBool(const cJSON * const item)2908 CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
2909 {
2910     if (item == NULL)
2911     {
2912         return false;
2913     }
2914 
2915     return (item->type & (cJSON_True | cJSON_False)) != 0;
2916 }
cJSON_IsNull(const cJSON * const item)2917 CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
2918 {
2919     if (item == NULL)
2920     {
2921         return false;
2922     }
2923 
2924     return (item->type & 0xFF) == cJSON_NULL;
2925 }
2926 
cJSON_IsNumber(const cJSON * const item)2927 CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
2928 {
2929     if (item == NULL)
2930     {
2931         return false;
2932     }
2933 
2934     return (item->type & 0xFF) == cJSON_Number;
2935 }
2936 
cJSON_IsString(const cJSON * const item)2937 CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
2938 {
2939     if (item == NULL)
2940     {
2941         return false;
2942     }
2943 
2944     return (item->type & 0xFF) == cJSON_String;
2945 }
2946 
cJSON_IsArray(const cJSON * const item)2947 CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
2948 {
2949     if (item == NULL)
2950     {
2951         return false;
2952     }
2953 
2954     return (item->type & 0xFF) == cJSON_Array;
2955 }
2956 
cJSON_IsObject(const cJSON * const item)2957 CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
2958 {
2959     if (item == NULL)
2960     {
2961         return false;
2962     }
2963 
2964     return (item->type & 0xFF) == cJSON_Object;
2965 }
2966 
cJSON_IsRaw(const cJSON * const item)2967 CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
2968 {
2969     if (item == NULL)
2970     {
2971         return false;
2972     }
2973 
2974     return (item->type & 0xFF) == cJSON_Raw;
2975 }
2976 
cJSON_Compare(const cJSON * const a,const cJSON * const b,const cJSON_bool case_sensitive)2977 CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
2978 {
2979     if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
2980     {
2981         return false;
2982     }
2983 
2984     /* check if type is valid */
2985     switch (a->type & 0xFF)
2986     {
2987         case cJSON_False:
2988         case cJSON_True:
2989         case cJSON_NULL:
2990         case cJSON_Number:
2991         case cJSON_String:
2992         case cJSON_Raw:
2993         case cJSON_Array:
2994         case cJSON_Object:
2995             break;
2996 
2997         default:
2998             return false;
2999     }
3000 
3001     /* identical objects are equal */
3002     if (a == b)
3003     {
3004         return true;
3005     }
3006 
3007     switch (a->type & 0xFF)
3008     {
3009         /* in these cases and equal type is enough */
3010         case cJSON_False:
3011         case cJSON_True:
3012         case cJSON_NULL:
3013             return true;
3014 
3015         case cJSON_Number:
3016             if (compare_double(a->valuedouble, b->valuedouble))
3017             {
3018                 return true;
3019             }
3020             return false;
3021 
3022         case cJSON_String:
3023         case cJSON_Raw:
3024             if ((a->valuestring == NULL) || (b->valuestring == NULL))
3025             {
3026                 return false;
3027             }
3028             if (strcmp(a->valuestring, b->valuestring) == 0)
3029             {
3030                 return true;
3031             }
3032 
3033             return false;
3034 
3035         case cJSON_Array:
3036         {
3037             cJSON *a_element = a->child;
3038             cJSON *b_element = b->child;
3039 
3040             for (; (a_element != NULL) && (b_element != NULL);)
3041             {
3042                 if (!cJSON_Compare(a_element, b_element, case_sensitive))
3043                 {
3044                     return false;
3045                 }
3046 
3047                 a_element = a_element->next;
3048                 b_element = b_element->next;
3049             }
3050 
3051             /* one of the arrays is longer than the other */
3052             if (a_element != b_element) {
3053                 return false;
3054             }
3055 
3056             return true;
3057         }
3058 
3059         case cJSON_Object:
3060         {
3061             cJSON *a_element = NULL;
3062             cJSON *b_element = NULL;
3063             cJSON_ArrayForEach(a_element, a)
3064             {
3065                 /* TODO This has O(n^2) runtime, which is horrible! */
3066                 b_element = get_object_item(b, a_element->string, case_sensitive);
3067                 if (b_element == NULL)
3068                 {
3069                     return false;
3070                 }
3071 
3072                 if (!cJSON_Compare(a_element, b_element, case_sensitive))
3073                 {
3074                     return false;
3075                 }
3076             }
3077 
3078             /* doing this twice, once on a and b to prevent true comparison if a subset of b
3079              * TODO: Do this the proper way, this is just a fix for now */
3080             cJSON_ArrayForEach(b_element, b)
3081             {
3082                 a_element = get_object_item(a, b_element->string, case_sensitive);
3083                 if (a_element == NULL)
3084                 {
3085                     return false;
3086                 }
3087 
3088                 if (!cJSON_Compare(b_element, a_element, case_sensitive))
3089                 {
3090                     return false;
3091                 }
3092             }
3093 
3094             return true;
3095         }
3096 
3097         default:
3098             return false;
3099     }
3100 }
3101 
cJSON_malloc(size_t size)3102 CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
3103 {
3104     return global_hooks.allocate(size);
3105 }
3106 
cJSON_free(void * object)3107 CJSON_PUBLIC(void) cJSON_free(void *object)
3108 {
3109     global_hooks.deallocate(object);
3110 }
3111