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