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