2 Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
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:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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
24 /* JSON parser in C. */
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
32 #pragma GCC visibility push(default)
35 #pragma warning (push)
36 /* disable warning about single line comments in system headers */
37 #pragma warning (disable : 4001)
56 #pragma GCC visibility pop
61 /* define our own boolean type */
62 #define true ((cJSON_bool)1)
63 #define false ((cJSON_bool)0)
66 const unsigned char *json;
69 static error global_error = { NULL, 0 };
71 CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
73 return (const char*) (global_error.json + global_error.position);
76 CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) {
77 if (!cJSON_IsString(item)) {
81 return item->valuestring;
84 /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
85 #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 1)
86 #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
89 CJSON_PUBLIC(const char*) cJSON_Version(void)
91 static char version[15];
92 sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
97 /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
98 static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
100 if ((string1 == NULL) || (string2 == NULL))
105 if (string1 == string2)
110 for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
112 if (*string1 == '\0')
118 return tolower(*string1) - tolower(*string2);
121 typedef struct internal_hooks
123 void *(*allocate)(size_t size);
124 void (*deallocate)(void *pointer);
125 void *(*reallocate)(void *pointer, size_t size);
128 #if defined(_MSC_VER)
129 /* work around MSVC error C2322: '...' address of dillimport '...' is not static */
130 static void *internal_malloc(size_t size)
134 static void internal_free(void *pointer)
138 static void *internal_realloc(void *pointer, size_t size)
140 return realloc(pointer, size);
143 #define internal_malloc malloc
144 #define internal_free free
145 #define internal_realloc realloc
148 static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
150 static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
153 unsigned char *copy = NULL;
160 length = strlen((const char*)string) + sizeof("");
161 copy = (unsigned char*)hooks->allocate(length);
166 memcpy(copy, string, length);
171 CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
176 global_hooks.allocate = malloc;
177 global_hooks.deallocate = free;
178 global_hooks.reallocate = realloc;
182 global_hooks.allocate = malloc;
183 if (hooks->malloc_fn != NULL)
185 global_hooks.allocate = hooks->malloc_fn;
188 global_hooks.deallocate = free;
189 if (hooks->free_fn != NULL)
191 global_hooks.deallocate = hooks->free_fn;
194 /* use realloc only if both free and malloc are used */
195 global_hooks.reallocate = NULL;
196 if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
198 global_hooks.reallocate = realloc;
202 /* Internal constructor. */
203 static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
205 cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
208 memset(node, '\0', sizeof(cJSON));
214 /* Delete a cJSON structure. */
215 CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
221 if (!(item->type & cJSON_IsReference) && (item->child != NULL))
223 cJSON_Delete(item->child);
225 if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
227 global_hooks.deallocate(item->valuestring);
229 if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
231 global_hooks.deallocate(item->string);
233 global_hooks.deallocate(item);
238 /* get the decimal point character of the current locale */
239 static unsigned char get_decimal_point(void)
241 #ifdef ENABLE_LOCALES
242 struct lconv *lconv = localeconv();
243 return (unsigned char) lconv->decimal_point[0];
251 const unsigned char *content;
254 size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
255 internal_hooks hooks;
258 /* check if the given size is left to read in a given parse buffer (starting with 1) */
259 #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
260 /* check if the buffer can be accessed at the given index (starting with 0) */
261 #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
262 #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
263 /* get a pointer to the buffer at the position */
264 #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
266 /* Parse the input text to generate a number, and populate the result into item. */
267 static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
270 unsigned char *after_end = NULL;
271 unsigned char number_c_string[64];
272 unsigned char decimal_point = get_decimal_point();
275 if ((input_buffer == NULL) || (input_buffer->content == NULL))
280 /* copy the number into a temporary buffer and replace '.' with the decimal point
281 * of the current locale (for strtod)
282 * This also takes care of '\0' not necessarily being available for marking the end of the input */
283 for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
285 switch (buffer_at_offset(input_buffer)[i])
301 number_c_string[i] = buffer_at_offset(input_buffer)[i];
305 number_c_string[i] = decimal_point;
313 number_c_string[i] = '\0';
315 number = strtod((const char*)number_c_string, (char**)&after_end);
316 if (number_c_string == after_end)
318 return false; /* parse_error */
321 item->valuedouble = number;
323 /* use saturation in case of overflow */
324 if (number >= INT_MAX)
326 item->valueint = INT_MAX;
328 else if (number <= INT_MIN)
330 item->valueint = INT_MIN;
334 item->valueint = (int)number;
337 item->type = cJSON_Number;
339 input_buffer->offset += (size_t)(after_end - number_c_string);
343 /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
344 CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
346 if (number >= INT_MAX)
348 object->valueint = INT_MAX;
350 else if (number <= INT_MIN)
352 object->valueint = INT_MIN;
356 object->valueint = (int)number;
359 return object->valuedouble = number;
364 unsigned char *buffer;
367 size_t depth; /* current nesting depth (for formatted printing) */
369 cJSON_bool format; /* is this print a formatted print */
370 internal_hooks hooks;
373 /* realloc printbuffer if necessary to have at least "needed" bytes more */
374 static unsigned char* ensure(printbuffer * const p, size_t needed)
376 unsigned char *newbuffer = NULL;
379 if ((p == NULL) || (p->buffer == NULL))
384 if ((p->length > 0) && (p->offset >= p->length))
386 /* make sure that offset is valid */
390 if (needed > INT_MAX)
392 /* sizes bigger than INT_MAX are currently not supported */
396 needed += p->offset + 1;
397 if (needed <= p->length)
399 return p->buffer + p->offset;
406 /* calculate new buffer size */
407 if (needed > (INT_MAX / 2))
409 /* overflow of int, use INT_MAX if possible */
410 if (needed <= INT_MAX)
421 newsize = needed * 2;
424 if (p->hooks.reallocate != NULL)
426 /* reallocate with realloc if available */
427 newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
428 if (newbuffer == NULL)
430 p->hooks.deallocate(p->buffer);
439 /* otherwise reallocate manually */
440 newbuffer = (unsigned char*)p->hooks.allocate(newsize);
443 p->hooks.deallocate(p->buffer);
451 memcpy(newbuffer, p->buffer, p->offset + 1);
453 p->hooks.deallocate(p->buffer);
456 p->buffer = newbuffer;
458 return newbuffer + p->offset;
461 /* calculate the new length of the string in a printbuffer and update the offset */
462 static void update_offset(printbuffer * const buffer)
464 const unsigned char *buffer_pointer = NULL;
465 if ((buffer == NULL) || (buffer->buffer == NULL))
469 buffer_pointer = buffer->buffer + buffer->offset;
471 buffer->offset += strlen((const char*)buffer_pointer);
474 /* Render the number nicely from the given item into a string. */
475 static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
477 unsigned char *output_pointer = NULL;
478 double d = item->valuedouble;
481 unsigned char number_buffer[26]; /* temporary buffer to print the number into */
482 unsigned char decimal_point = get_decimal_point();
485 if (output_buffer == NULL)
490 /* This checks for NaN and Infinity */
493 length = sprintf((char*)number_buffer, "null");
497 /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
498 length = sprintf((char*)number_buffer, "%1.15g", d);
500 /* Check whether the original double can be recovered */
501 if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d))
503 /* If not, print with 17 decimal places of precision */
504 length = sprintf((char*)number_buffer, "%1.17g", d);
508 /* sprintf failed or buffer overrun occured */
509 if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
514 /* reserve appropriate space in the output */
515 output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
516 if (output_pointer == NULL)
521 /* copy the printed number to the output and replace locale
522 * dependent decimal point with '.' */
523 for (i = 0; i < ((size_t)length); i++)
525 if (number_buffer[i] == decimal_point)
527 output_pointer[i] = '.';
531 output_pointer[i] = number_buffer[i];
533 output_pointer[i] = '\0';
535 output_buffer->offset += (size_t)length;
540 /* parse 4 digit hexadecimal number */
541 static unsigned parse_hex4(const unsigned char * const input)
546 for (i = 0; i < 4; i++)
549 if ((input[i] >= '0') && (input[i] <= '9'))
551 h += (unsigned int) input[i] - '0';
553 else if ((input[i] >= 'A') && (input[i] <= 'F'))
555 h += (unsigned int) 10 + input[i] - 'A';
557 else if ((input[i] >= 'a') && (input[i] <= 'f'))
559 h += (unsigned int) 10 + input[i] - 'a';
568 /* shift left to make place for the next nibble */
576 /* converts a UTF-16 literal to UTF-8
577 * A literal can be one or two sequences of the form \uXXXX */
578 static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
580 long unsigned int codepoint = 0;
581 unsigned int first_code = 0;
582 const unsigned char *first_sequence = input_pointer;
583 unsigned char utf8_length = 0;
584 unsigned char utf8_position = 0;
585 unsigned char sequence_length = 0;
586 unsigned char first_byte_mark = 0;
588 if ((input_end - first_sequence) < 6)
590 /* input ends unexpectedly */
594 /* get the first utf16 sequence */
595 first_code = parse_hex4(first_sequence + 2);
597 /* check that the code is valid */
598 if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
603 /* UTF16 surrogate pair */
604 if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
606 const unsigned char *second_sequence = first_sequence + 6;
607 unsigned int second_code = 0;
608 sequence_length = 12; /* \uXXXX\uXXXX */
610 if ((input_end - second_sequence) < 6)
612 /* input ends unexpectedly */
616 if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
618 /* missing second half of the surrogate pair */
622 /* get the second utf16 sequence */
623 second_code = parse_hex4(second_sequence + 2);
624 /* check that the code is valid */
625 if ((second_code < 0xDC00) || (second_code > 0xDFFF))
627 /* invalid second half of the surrogate pair */
632 /* calculate the unicode codepoint from the surrogate pair */
633 codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
637 sequence_length = 6; /* \uXXXX */
638 codepoint = first_code;
642 * takes at maximum 4 bytes to encode:
643 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
644 if (codepoint < 0x80)
646 /* normal ascii, encoding 0xxxxxxx */
649 else if (codepoint < 0x800)
651 /* two bytes, encoding 110xxxxx 10xxxxxx */
653 first_byte_mark = 0xC0; /* 11000000 */
655 else if (codepoint < 0x10000)
657 /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
659 first_byte_mark = 0xE0; /* 11100000 */
661 else if (codepoint <= 0x10FFFF)
663 /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
665 first_byte_mark = 0xF0; /* 11110000 */
669 /* invalid unicode codepoint */
674 for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
677 (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
680 /* encode first byte */
683 (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
687 (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
690 *output_pointer += utf8_length;
692 return sequence_length;
698 /* Parse the input text into an unescaped cinput, and populate item. */
699 static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
701 const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
702 const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
703 unsigned char *output_pointer = NULL;
704 unsigned char *output = NULL;
707 if (buffer_at_offset(input_buffer)[0] != '\"')
713 /* calculate approximate size of the output (overestimate) */
714 size_t allocation_length = 0;
715 size_t skipped_bytes = 0;
716 while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
718 /* is escape sequence */
719 if (input_end[0] == '\\')
721 if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
723 /* prevent buffer overflow when last input character is a backslash */
731 if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
733 goto fail; /* string ended unexpectedly */
736 /* This is at most how much we need for the output */
737 allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
738 output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
741 goto fail; /* allocation failure */
745 output_pointer = output;
746 /* loop through the string literal */
747 while (input_pointer < input_end)
749 if (*input_pointer != '\\')
751 *output_pointer++ = *input_pointer++;
753 /* escape sequence */
756 unsigned char sequence_length = 2;
757 if ((input_end - input_pointer) < 1)
762 switch (input_pointer[1])
765 *output_pointer++ = '\b';
768 *output_pointer++ = '\f';
771 *output_pointer++ = '\n';
774 *output_pointer++ = '\r';
777 *output_pointer++ = '\t';
782 *output_pointer++ = input_pointer[1];
787 sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
788 if (sequence_length == 0)
790 /* failed to convert UTF16-literal to UTF-8 */
798 input_pointer += sequence_length;
802 /* zero terminate the output */
803 *output_pointer = '\0';
805 item->type = cJSON_String;
806 item->valuestring = (char*)output;
808 input_buffer->offset = (size_t) (input_end - input_buffer->content);
809 input_buffer->offset++;
816 input_buffer->hooks.deallocate(output);
819 if (input_pointer != NULL)
821 input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
827 /* Render the cstring provided to an escaped version that can be printed. */
828 static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
830 const unsigned char *input_pointer = NULL;
831 unsigned char *output = NULL;
832 unsigned char *output_pointer = NULL;
833 size_t output_length = 0;
834 /* numbers of additional characters needed for escaping */
835 size_t escape_characters = 0;
837 if (output_buffer == NULL)
845 output = ensure(output_buffer, sizeof("\"\""));
850 strcpy((char*)output, "\"\"");
855 /* set "flag" to 1 if something needs to be escaped */
856 for (input_pointer = input; *input_pointer; input_pointer++)
858 switch (*input_pointer)
867 /* one character escape sequence */
871 if (*input_pointer < 32)
873 /* UTF-16 escape sequence uXXXX */
874 escape_characters += 5;
879 output_length = (size_t)(input_pointer - input) + escape_characters;
881 output = ensure(output_buffer, output_length + sizeof("\"\""));
887 /* no characters have to be escaped */
888 if (escape_characters == 0)
891 memcpy(output + 1, input, output_length);
892 output[output_length + 1] = '\"';
893 output[output_length + 2] = '\0';
899 output_pointer = output + 1;
900 /* copy the string */
901 for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
903 if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
905 /* normal character, copy */
906 *output_pointer = *input_pointer;
910 /* character needs to be escaped */
911 *output_pointer++ = '\\';
912 switch (*input_pointer)
915 *output_pointer = '\\';
918 *output_pointer = '\"';
921 *output_pointer = 'b';
924 *output_pointer = 'f';
927 *output_pointer = 'n';
930 *output_pointer = 'r';
933 *output_pointer = 't';
936 /* escape and print as unicode codepoint */
937 sprintf((char*)output_pointer, "u%04x", *input_pointer);
943 output[output_length + 1] = '\"';
944 output[output_length + 2] = '\0';
949 /* Invoke print_string_ptr (which is useful) on an item. */
950 static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
952 return print_string_ptr((unsigned char*)item->valuestring, p);
955 /* Predeclare these prototypes. */
956 static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
957 static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
958 static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
959 static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
960 static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
961 static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
963 /* Utility to jump whitespace and cr/lf */
964 static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
966 if ((buffer == NULL) || (buffer->content == NULL))
971 while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
976 if (buffer->offset == buffer->length)
984 /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
985 static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
987 if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
992 if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
1000 /* Parse an object - create a new root, and populate. */
1001 CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
1003 parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
1006 /* reset error position */
1007 global_error.json = NULL;
1008 global_error.position = 0;
1015 buffer.content = (const unsigned char*)value;
1016 buffer.length = strlen((const char*)value) + sizeof("");
1018 buffer.hooks = global_hooks;
1020 item = cJSON_New_Item(&global_hooks);
1021 if (item == NULL) /* memory fail */
1026 if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
1028 /* parse failure. ep is set. */
1032 /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
1033 if (require_null_terminated)
1035 buffer_skip_whitespace(&buffer);
1036 if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
1041 if (return_parse_end)
1043 *return_parse_end = (const char*)buffer_at_offset(&buffer);
1057 local_error.json = (const unsigned char*)value;
1058 local_error.position = 0;
1060 if (buffer.offset < buffer.length)
1062 local_error.position = buffer.offset;
1064 else if (buffer.length > 0)
1066 local_error.position = buffer.length - 1;
1069 if (return_parse_end != NULL)
1071 *return_parse_end = (const char*)local_error.json + local_error.position;
1074 global_error = local_error;
1080 /* Default options for cJSON_Parse */
1081 CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
1083 return cJSON_ParseWithOpts(value, 0, 0);
1086 #define cjson_min(a, b) ((a < b) ? a : b)
1088 static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
1090 static const size_t default_buffer_size = 256;
1091 printbuffer buffer[1];
1092 unsigned char *printed = NULL;
1094 memset(buffer, 0, sizeof(buffer));
1097 buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
1098 buffer->length = default_buffer_size;
1099 buffer->format = format;
1100 buffer->hooks = *hooks;
1101 if (buffer->buffer == NULL)
1106 /* print the value */
1107 if (!print_value(item, buffer))
1111 update_offset(buffer);
1113 /* check if reallocate is available */
1114 if (hooks->reallocate != NULL)
1116 printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
1117 buffer->buffer = NULL;
1118 if (printed == NULL) {
1122 else /* otherwise copy the JSON over to a new buffer */
1124 printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
1125 if (printed == NULL)
1129 memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
1130 printed[buffer->offset] = '\0'; /* just to be sure */
1132 /* free the buffer */
1133 hooks->deallocate(buffer->buffer);
1139 if (buffer->buffer != NULL)
1141 hooks->deallocate(buffer->buffer);
1144 if (printed != NULL)
1146 hooks->deallocate(printed);
1152 /* Render a cJSON item/entity/structure to text. */
1153 CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
1155 return (char*)print(item, true, &global_hooks);
1158 CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
1160 return (char*)print(item, false, &global_hooks);
1163 CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
1165 printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
1172 p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
1178 p.length = (size_t)prebuffer;
1182 p.hooks = global_hooks;
1184 if (!print_value(item, &p))
1186 global_hooks.deallocate(p.buffer);
1190 return (char*)p.buffer;
1193 CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt)
1195 printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
1197 if ((len < 0) || (buf == NULL))
1202 p.buffer = (unsigned char*)buf;
1203 p.length = (size_t)len;
1207 p.hooks = global_hooks;
1209 return print_value(item, &p);
1212 /* Parser core - when encountering text, process appropriately. */
1213 static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
1215 if ((input_buffer == NULL) || (input_buffer->content == NULL))
1217 return false; /* no input */
1220 /* parse the different types of values */
1222 if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
1224 item->type = cJSON_NULL;
1225 input_buffer->offset += 4;
1229 if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
1231 item->type = cJSON_False;
1232 input_buffer->offset += 5;
1236 if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
1238 item->type = cJSON_True;
1240 input_buffer->offset += 4;
1244 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
1246 return parse_string(item, input_buffer);
1249 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'))))
1251 return parse_number(item, input_buffer);
1254 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
1256 return parse_array(item, input_buffer);
1259 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
1261 return parse_object(item, input_buffer);
1267 /* Render a value to text. */
1268 static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
1270 unsigned char *output = NULL;
1272 if ((item == NULL) || (output_buffer == NULL))
1277 switch ((item->type) & 0xFF)
1280 output = ensure(output_buffer, 5);
1285 strcpy((char*)output, "null");
1289 output = ensure(output_buffer, 6);
1294 strcpy((char*)output, "false");
1298 output = ensure(output_buffer, 5);
1303 strcpy((char*)output, "true");
1307 return print_number(item, output_buffer);
1311 size_t raw_length = 0;
1312 if (item->valuestring == NULL)
1314 if (!output_buffer->noalloc)
1316 output_buffer->hooks.deallocate(output_buffer->buffer);
1321 raw_length = strlen(item->valuestring) + sizeof("");
1322 output = ensure(output_buffer, raw_length);
1327 memcpy(output, item->valuestring, raw_length);
1332 return print_string(item, output_buffer);
1335 return print_array(item, output_buffer);
1338 return print_object(item, output_buffer);
1345 /* Build an array from input text. */
1346 static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
1348 cJSON *head = NULL; /* head of the linked list */
1349 cJSON *current_item = NULL;
1351 if (input_buffer->depth >= CJSON_NESTING_LIMIT)
1353 return false; /* to deeply nested */
1355 input_buffer->depth++;
1357 if (buffer_at_offset(input_buffer)[0] != '[')
1363 input_buffer->offset++;
1364 buffer_skip_whitespace(input_buffer);
1365 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
1371 /* check if we skipped to the end of the buffer */
1372 if (cannot_access_at_index(input_buffer, 0))
1374 input_buffer->offset--;
1378 /* step back to character in front of the first element */
1379 input_buffer->offset--;
1380 /* loop through the comma separated array elements */
1383 /* allocate next item */
1384 cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
1385 if (new_item == NULL)
1387 goto fail; /* allocation failure */
1390 /* attach next item to list */
1393 /* start the linked list */
1394 current_item = head = new_item;
1398 /* add to the end and advance */
1399 current_item->next = new_item;
1400 new_item->prev = current_item;
1401 current_item = new_item;
1404 /* parse next value */
1405 input_buffer->offset++;
1406 buffer_skip_whitespace(input_buffer);
1407 if (!parse_value(current_item, input_buffer))
1409 goto fail; /* failed to parse value */
1411 buffer_skip_whitespace(input_buffer);
1413 while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1415 if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
1417 goto fail; /* expected end of array */
1421 input_buffer->depth--;
1423 item->type = cJSON_Array;
1426 input_buffer->offset++;
1439 /* Render an array to text */
1440 static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
1442 unsigned char *output_pointer = NULL;
1444 cJSON *current_element = item->child;
1446 if (output_buffer == NULL)
1451 /* Compose the output array. */
1452 /* opening square bracket */
1453 output_pointer = ensure(output_buffer, 1);
1454 if (output_pointer == NULL)
1459 *output_pointer = '[';
1460 output_buffer->offset++;
1461 output_buffer->depth++;
1463 while (current_element != NULL)
1465 if (!print_value(current_element, output_buffer))
1469 update_offset(output_buffer);
1470 if (current_element->next)
1472 length = (size_t) (output_buffer->format ? 2 : 1);
1473 output_pointer = ensure(output_buffer, length + 1);
1474 if (output_pointer == NULL)
1478 *output_pointer++ = ',';
1479 if(output_buffer->format)
1481 *output_pointer++ = ' ';
1483 *output_pointer = '\0';
1484 output_buffer->offset += length;
1486 current_element = current_element->next;
1489 output_pointer = ensure(output_buffer, 2);
1490 if (output_pointer == NULL)
1494 *output_pointer++ = ']';
1495 *output_pointer = '\0';
1496 output_buffer->depth--;
1501 /* Build an object from the text. */
1502 static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
1504 cJSON *head = NULL; /* linked list head */
1505 cJSON *current_item = NULL;
1507 if (input_buffer->depth >= CJSON_NESTING_LIMIT)
1509 return false; /* to deeply nested */
1511 input_buffer->depth++;
1513 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
1515 goto fail; /* not an object */
1518 input_buffer->offset++;
1519 buffer_skip_whitespace(input_buffer);
1520 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
1522 goto success; /* empty object */
1525 /* check if we skipped to the end of the buffer */
1526 if (cannot_access_at_index(input_buffer, 0))
1528 input_buffer->offset--;
1532 /* step back to character in front of the first element */
1533 input_buffer->offset--;
1534 /* loop through the comma separated array elements */
1537 /* allocate next item */
1538 cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
1539 if (new_item == NULL)
1541 goto fail; /* allocation failure */
1544 /* attach next item to list */
1547 /* start the linked list */
1548 current_item = head = new_item;
1552 /* add to the end and advance */
1553 current_item->next = new_item;
1554 new_item->prev = current_item;
1555 current_item = new_item;
1558 /* parse the name of the child */
1559 input_buffer->offset++;
1560 buffer_skip_whitespace(input_buffer);
1561 if (!parse_string(current_item, input_buffer))
1563 goto fail; /* faile to parse name */
1565 buffer_skip_whitespace(input_buffer);
1567 /* swap valuestring and string, because we parsed the name */
1568 current_item->string = current_item->valuestring;
1569 current_item->valuestring = NULL;
1571 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
1573 goto fail; /* invalid object */
1576 /* parse the value */
1577 input_buffer->offset++;
1578 buffer_skip_whitespace(input_buffer);
1579 if (!parse_value(current_item, input_buffer))
1581 goto fail; /* failed to parse value */
1583 buffer_skip_whitespace(input_buffer);
1585 while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1587 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
1589 goto fail; /* expected end of object */
1593 input_buffer->depth--;
1595 item->type = cJSON_Object;
1598 input_buffer->offset++;
1610 /* Render an object to text. */
1611 static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
1613 unsigned char *output_pointer = NULL;
1615 cJSON *current_item = item->child;
1617 if (output_buffer == NULL)
1622 /* Compose the output: */
1623 length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
1624 output_pointer = ensure(output_buffer, length + 1);
1625 if (output_pointer == NULL)
1630 *output_pointer++ = '{';
1631 output_buffer->depth++;
1632 if (output_buffer->format)
1634 *output_pointer++ = '\n';
1636 output_buffer->offset += length;
1638 while (current_item)
1640 if (output_buffer->format)
1643 output_pointer = ensure(output_buffer, output_buffer->depth);
1644 if (output_pointer == NULL)
1648 for (i = 0; i < output_buffer->depth; i++)
1650 *output_pointer++ = '\t';
1652 output_buffer->offset += output_buffer->depth;
1656 if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
1660 update_offset(output_buffer);
1662 length = (size_t) (output_buffer->format ? 2 : 1);
1663 output_pointer = ensure(output_buffer, length);
1664 if (output_pointer == NULL)
1668 *output_pointer++ = ':';
1669 if (output_buffer->format)
1671 *output_pointer++ = '\t';
1673 output_buffer->offset += length;
1676 if (!print_value(current_item, output_buffer))
1680 update_offset(output_buffer);
1682 /* print comma if not last */
1683 length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0));
1684 output_pointer = ensure(output_buffer, length + 1);
1685 if (output_pointer == NULL)
1689 if (current_item->next)
1691 *output_pointer++ = ',';
1694 if (output_buffer->format)
1696 *output_pointer++ = '\n';
1698 *output_pointer = '\0';
1699 output_buffer->offset += length;
1701 current_item = current_item->next;
1704 output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
1705 if (output_pointer == NULL)
1709 if (output_buffer->format)
1712 for (i = 0; i < (output_buffer->depth - 1); i++)
1714 *output_pointer++ = '\t';
1717 *output_pointer++ = '}';
1718 *output_pointer = '\0';
1719 output_buffer->depth--;
1724 /* Get Array size/item / object item. */
1725 CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
1727 cJSON *child = NULL;
1735 child = array->child;
1737 while(child != NULL)
1740 child = child->next;
1743 /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
1748 static cJSON* get_array_item(const cJSON *array, size_t index)
1750 cJSON *current_child = NULL;
1757 current_child = array->child;
1758 while ((current_child != NULL) && (index > 0))
1761 current_child = current_child->next;
1764 return current_child;
1767 CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
1774 return get_array_item(array, (size_t)index);
1777 static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
1779 cJSON *current_element = NULL;
1781 if ((object == NULL) || (name == NULL))
1786 current_element = object->child;
1789 while ((current_element != NULL) && (strcmp(name, current_element->string) != 0))
1791 current_element = current_element->next;
1796 while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
1798 current_element = current_element->next;
1802 return current_element;
1805 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
1807 return get_object_item(object, string, false);
1810 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
1812 return get_object_item(object, string, true);
1815 CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
1817 return cJSON_GetObjectItem(object, string) ? 1 : 0;
1820 /* Utility for array list handling. */
1821 static void suffix_object(cJSON *prev, cJSON *item)
1827 /* Utility for handling references. */
1828 static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
1830 cJSON *reference = NULL;
1836 reference = cJSON_New_Item(hooks);
1837 if (reference == NULL)
1842 memcpy(reference, item, sizeof(cJSON));
1843 reference->string = NULL;
1844 reference->type |= cJSON_IsReference;
1845 reference->next = reference->prev = NULL;
1849 static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
1851 cJSON *child = NULL;
1853 if ((item == NULL) || (array == NULL))
1858 child = array->child;
1862 /* list is empty, start new one */
1863 array->child = item;
1867 /* append to the end */
1870 child = child->next;
1872 suffix_object(child, item);
1878 /* Add item to array/object. */
1879 CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item)
1881 add_item_to_array(array, item);
1884 #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
1885 #pragma GCC diagnostic push
1888 #pragma GCC diagnostic ignored "-Wcast-qual"
1890 /* helper function to cast away const */
1891 static void* cast_away_const(const void* string)
1893 return (void*)string;
1895 #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
1896 #pragma GCC diagnostic pop
1900 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)
1902 if ((object == NULL) || (string == NULL) || (item == NULL))
1907 if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
1909 hooks->deallocate(item->string);
1914 item->string = (char*)cast_away_const(string);
1915 item->type |= cJSON_StringIsConst;
1919 char *key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
1926 item->type &= ~cJSON_StringIsConst;
1929 return add_item_to_array(object, item);
1932 CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
1934 add_item_to_object(object, string, item, &global_hooks, false);
1937 /* Add an item to an object with constant string as key */
1938 CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
1940 add_item_to_object(object, string, item, &global_hooks, true);
1943 CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
1950 add_item_to_array(array, create_reference(item, &global_hooks));
1953 CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
1955 if ((object == NULL) || (string == NULL))
1960 add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
1963 CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
1965 cJSON *null = cJSON_CreateNull();
1966 if (add_item_to_object(object, name, null, &global_hooks, false))
1975 CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
1977 cJSON *true_item = cJSON_CreateTrue();
1978 if (add_item_to_object(object, name, true_item, &global_hooks, false))
1983 cJSON_Delete(true_item);
1987 CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
1989 cJSON *false_item = cJSON_CreateFalse();
1990 if (add_item_to_object(object, name, false_item, &global_hooks, false))
1995 cJSON_Delete(false_item);
1999 CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
2001 cJSON *bool_item = cJSON_CreateBool(boolean);
2002 if (add_item_to_object(object, name, bool_item, &global_hooks, false))
2007 cJSON_Delete(bool_item);
2011 CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
2013 cJSON *number_item = cJSON_CreateNumber(number);
2014 if (add_item_to_object(object, name, number_item, &global_hooks, false))
2019 cJSON_Delete(number_item);
2023 CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
2025 cJSON *string_item = cJSON_CreateString(string);
2026 if (add_item_to_object(object, name, string_item, &global_hooks, false))
2031 cJSON_Delete(string_item);
2035 CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
2037 cJSON *raw_item = cJSON_CreateRaw(raw);
2038 if (add_item_to_object(object, name, raw_item, &global_hooks, false))
2043 cJSON_Delete(raw_item);
2047 CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
2049 cJSON *object_item = cJSON_CreateObject();
2050 if (add_item_to_object(object, name, object_item, &global_hooks, false))
2055 cJSON_Delete(object_item);
2059 CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
2061 cJSON *array = cJSON_CreateArray();
2062 if (add_item_to_object(object, name, array, &global_hooks, false))
2067 cJSON_Delete(array);
2071 CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
2073 if ((parent == NULL) || (item == NULL))
2078 if (item->prev != NULL)
2080 /* not the first element */
2081 item->prev->next = item->next;
2083 if (item->next != NULL)
2085 /* not the last element */
2086 item->next->prev = item->prev;
2089 if (item == parent->child)
2092 parent->child = item->next;
2094 /* make sure the detached item doesn't point anywhere anymore */
2101 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
2108 return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
2111 CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
2113 cJSON_Delete(cJSON_DetachItemFromArray(array, which));
2116 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
2118 cJSON *to_detach = cJSON_GetObjectItem(object, string);
2120 return cJSON_DetachItemViaPointer(object, to_detach);
2123 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
2125 cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
2127 return cJSON_DetachItemViaPointer(object, to_detach);
2130 CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
2132 cJSON_Delete(cJSON_DetachItemFromObject(object, string));
2135 CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
2137 cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
2140 /* Replace array/object items with new ones. */
2141 CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
2143 cJSON *after_inserted = NULL;
2150 after_inserted = get_array_item(array, (size_t)which);
2151 if (after_inserted == NULL)
2153 add_item_to_array(array, newitem);
2157 newitem->next = after_inserted;
2158 newitem->prev = after_inserted->prev;
2159 after_inserted->prev = newitem;
2160 if (after_inserted == array->child)
2162 array->child = newitem;
2166 newitem->prev->next = newitem;
2170 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
2172 if ((parent == NULL) || (replacement == NULL) || (item == NULL))
2177 if (replacement == item)
2182 replacement->next = item->next;
2183 replacement->prev = item->prev;
2185 if (replacement->next != NULL)
2187 replacement->next->prev = replacement;
2189 if (replacement->prev != NULL)
2191 replacement->prev->next = replacement;
2193 if (parent->child == item)
2195 parent->child = replacement;
2205 CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
2212 cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
2215 static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
2217 if ((replacement == NULL) || (string == NULL))
2222 /* replace the name in the replacement */
2223 if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
2225 cJSON_free(replacement->string);
2227 replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
2228 replacement->type &= ~cJSON_StringIsConst;
2230 cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
2235 CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
2237 replace_item_in_object(object, string, newitem, false);
2240 CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
2242 replace_item_in_object(object, string, newitem, true);
2245 /* Create basic types: */
2246 CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
2248 cJSON *item = cJSON_New_Item(&global_hooks);
2251 item->type = cJSON_NULL;
2257 CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
2259 cJSON *item = cJSON_New_Item(&global_hooks);
2262 item->type = cJSON_True;
2268 CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
2270 cJSON *item = cJSON_New_Item(&global_hooks);
2273 item->type = cJSON_False;
2279 CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b)
2281 cJSON *item = cJSON_New_Item(&global_hooks);
2284 item->type = b ? cJSON_True : cJSON_False;
2290 CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
2292 cJSON *item = cJSON_New_Item(&global_hooks);
2295 item->type = cJSON_Number;
2296 item->valuedouble = num;
2298 /* use saturation in case of overflow */
2301 item->valueint = INT_MAX;
2303 else if (num <= INT_MIN)
2305 item->valueint = INT_MIN;
2309 item->valueint = (int)num;
2316 CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
2318 cJSON *item = cJSON_New_Item(&global_hooks);
2321 item->type = cJSON_String;
2322 item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
2323 if(!item->valuestring)
2333 CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
2335 cJSON *item = cJSON_New_Item(&global_hooks);
2338 item->type = cJSON_String | cJSON_IsReference;
2339 item->valuestring = (char*)cast_away_const(string);
2345 CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
2347 cJSON *item = cJSON_New_Item(&global_hooks);
2349 item->type = cJSON_Object | cJSON_IsReference;
2350 item->child = (cJSON*)cast_away_const(child);
2356 CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
2357 cJSON *item = cJSON_New_Item(&global_hooks);
2359 item->type = cJSON_Array | cJSON_IsReference;
2360 item->child = (cJSON*)cast_away_const(child);
2366 CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
2368 cJSON *item = cJSON_New_Item(&global_hooks);
2371 item->type = cJSON_Raw;
2372 item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
2373 if(!item->valuestring)
2383 CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
2385 cJSON *item = cJSON_New_Item(&global_hooks);
2388 item->type=cJSON_Array;
2394 CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
2396 cJSON *item = cJSON_New_Item(&global_hooks);
2399 item->type = cJSON_Object;
2405 /* Create Arrays: */
2406 CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
2413 if ((count < 0) || (numbers == NULL))
2418 a = cJSON_CreateArray();
2419 for(i = 0; a && (i < (size_t)count); i++)
2421 n = cJSON_CreateNumber(numbers[i]);
2433 suffix_object(p, n);
2441 CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
2448 if ((count < 0) || (numbers == NULL))
2453 a = cJSON_CreateArray();
2455 for(i = 0; a && (i < (size_t)count); i++)
2457 n = cJSON_CreateNumber((double)numbers[i]);
2469 suffix_object(p, n);
2477 CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
2484 if ((count < 0) || (numbers == NULL))
2489 a = cJSON_CreateArray();
2491 for(i = 0;a && (i < (size_t)count); i++)
2493 n = cJSON_CreateNumber(numbers[i]);
2505 suffix_object(p, n);
2513 CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
2520 if ((count < 0) || (strings == NULL))
2525 a = cJSON_CreateArray();
2527 for (i = 0; a && (i < (size_t)count); i++)
2529 n = cJSON_CreateString(strings[i]);
2550 CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
2552 cJSON *newitem = NULL;
2553 cJSON *child = NULL;
2555 cJSON *newchild = NULL;
2557 /* Bail on bad ptr */
2562 /* Create new item */
2563 newitem = cJSON_New_Item(&global_hooks);
2568 /* Copy over all vars */
2569 newitem->type = item->type & (~cJSON_IsReference);
2570 newitem->valueint = item->valueint;
2571 newitem->valuedouble = item->valuedouble;
2572 if (item->valuestring)
2574 newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
2575 if (!newitem->valuestring)
2582 newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
2583 if (!newitem->string)
2588 /* If non-recursive, then we're done! */
2593 /* Walk the ->next chain for the child. */
2594 child = item->child;
2595 while (child != NULL)
2597 newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
2604 /* If newitem->child already set, then crosswire ->prev and ->next and move on */
2605 next->next = newchild;
2606 newchild->prev = next;
2611 /* Set newitem->child and move to it */
2612 newitem->child = newchild;
2615 child = child->next;
2621 if (newitem != NULL)
2623 cJSON_Delete(newitem);
2629 CJSON_PUBLIC(void) cJSON_Minify(char *json)
2631 unsigned char *into = (unsigned char*)json;
2644 else if (*json == '\t')
2646 /* Whitespace characters. */
2649 else if (*json == '\r')
2653 else if (*json=='\n')
2657 else if ((*json == '/') && (json[1] == '/'))
2659 /* double-slash comments, to end of line. */
2660 while (*json && (*json != '\n'))
2665 else if ((*json == '/') && (json[1] == '*'))
2667 /* multiline comments. */
2668 while (*json && !((*json == '*') && (json[1] == '/')))
2674 else if (*json == '\"')
2676 /* string literals, which are \" sensitive. */
2677 *into++ = (unsigned char)*json++;
2678 while (*json && (*json != '\"'))
2682 *into++ = (unsigned char)*json++;
2684 *into++ = (unsigned char)*json++;
2686 *into++ = (unsigned char)*json++;
2690 /* All other characters. */
2691 *into++ = (unsigned char)*json++;
2695 /* and null-terminate. */
2699 CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
2706 return (item->type & 0xFF) == cJSON_Invalid;
2709 CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
2716 return (item->type & 0xFF) == cJSON_False;
2719 CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
2726 return (item->type & 0xff) == cJSON_True;
2730 CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
2737 return (item->type & (cJSON_True | cJSON_False)) != 0;
2739 CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
2746 return (item->type & 0xFF) == cJSON_NULL;
2749 CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
2756 return (item->type & 0xFF) == cJSON_Number;
2759 CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
2766 return (item->type & 0xFF) == cJSON_String;
2769 CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
2776 return (item->type & 0xFF) == cJSON_Array;
2779 CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
2786 return (item->type & 0xFF) == cJSON_Object;
2789 CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
2796 return (item->type & 0xFF) == cJSON_Raw;
2799 CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
2801 if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))
2806 /* check if type is valid */
2807 switch (a->type & 0xFF)
2823 /* identical objects are equal */
2829 switch (a->type & 0xFF)
2831 /* in these cases and equal type is enough */
2838 if (a->valuedouble == b->valuedouble)
2846 if ((a->valuestring == NULL) || (b->valuestring == NULL))
2850 if (strcmp(a->valuestring, b->valuestring) == 0)
2859 cJSON *a_element = a->child;
2860 cJSON *b_element = b->child;
2862 for (; (a_element != NULL) && (b_element != NULL);)
2864 if (!cJSON_Compare(a_element, b_element, case_sensitive))
2869 a_element = a_element->next;
2870 b_element = b_element->next;
2873 /* one of the arrays is longer than the other */
2874 if (a_element != b_element) {
2883 cJSON *a_element = NULL;
2884 cJSON *b_element = NULL;
2885 cJSON_ArrayForEach(a_element, a)
2887 /* TODO This has O(n^2) runtime, which is horrible! */
2888 b_element = get_object_item(b, a_element->string, case_sensitive);
2889 if (b_element == NULL)
2894 if (!cJSON_Compare(a_element, b_element, case_sensitive))
2900 /* doing this twice, once on a and b to prevent true comparison if a subset of b
2901 * TODO: Do this the proper way, this is just a fix for now */
2902 cJSON_ArrayForEach(b_element, b)
2904 a_element = get_object_item(a, b_element->string, case_sensitive);
2905 if (a_element == NULL)
2910 if (!cJSON_Compare(b_element, a_element, case_sensitive))
2924 CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
2926 return global_hooks.allocate(size);
2929 CJSON_PUBLIC(void) cJSON_free(void *object)
2931 global_hooks.deallocate(object);