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