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