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