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