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