From 9bf65af6defb807460f29a22258950d00b0626fa Mon Sep 17 00:00:00 2001 From: Jinliang Li Date: Sat, 5 Mar 2022 22:08:37 +0800 Subject: [PATCH] cjson: upgrade cjson to 1.7.15 from 1.7.8 Signed-off-by: Jinliang Li --- components/utility/cjson/cJSON.c | 2176 +++++++++++++++------- components/utility/cjson/include/cJSON.h | 310 +-- 2 files changed, 1694 insertions(+), 792 deletions(-) diff --git a/components/utility/cjson/cJSON.c b/components/utility/cjson/cJSON.c index 2152fa6431..a8c66ca6a2 100644 --- a/components/utility/cjson/cJSON.c +++ b/components/utility/cjson/cJSON.c @@ -25,35 +25,35 @@ /* disable warnings about old C89 functions in MSVC */ #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) - #define _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE #endif #ifdef __GNUC__ - #pragma GCC visibility push(default) +#pragma GCC visibility push(default) #endif #if defined(_MSC_VER) - #pragma warning (push) - /* disable warning about single line comments in system headers */ - #pragma warning (disable : 4001) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) #endif #include #include #include #include -#include #include #include +#include #ifdef ENABLE_LOCALES - #include +#include #endif #if defined(_MSC_VER) - #pragma warning (pop) +#pragma warning (pop) #endif #ifdef __GNUC__ - #pragma GCC visibility pop +#pragma GCC visibility pop #endif #include "cJSON.h" @@ -69,19 +69,55 @@ #endif #define false ((cJSON_bool)0) +/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ +#ifndef isinf +#define isinf(d) (isnan((d - d)) && !isnan(d)) +#endif +#ifndef isnan +#define isnan(d) (d != d) +#endif + +#ifndef NAN +#ifdef _WIN32 +#define NAN sqrt(-1.0) +#else +#define NAN 0.0/0.0 +#endif +#endif + typedef struct { - const unsigned char* json; + const unsigned char *json; size_t position; } error; static error global_error = { NULL, 0 }; -CJSON_PUBLIC(const char*) cJSON_GetErrorPtr(void) +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) +{ + if (!cJSON_IsString(item)) + { + return NULL; + } + + return item->valuestring; +} + +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) { - return (const char*)(global_error.json + global_error.position); + if (!cJSON_IsNumber(item)) + { + return (double) NAN; + } + + return item->valuedouble; } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 6) || (CJSON_VERSION_PATCH != 0) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 15) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif @@ -92,65 +128,79 @@ CJSON_PUBLIC(const char*) cJSON_Version(void) return version; } -#ifndef CJSON_STRING_ZEROCOPY + /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ -static int case_insensitive_strcmp(const unsigned char* string1, const unsigned char* string2) +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) { if ((string1 == NULL) || (string2 == NULL)) + { return 1; + } if (string1 == string2) + { return 0; + } - for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++) { + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { if (*string1 == '\0') + { return 0; + } } return tolower(*string1) - tolower(*string2); } -#endif -typedef struct internal_hooks { - void* (*allocate)(size_t size); - void (*deallocate)(void* pointer); - void* (*reallocate)(void* pointer, size_t size); + +typedef struct internal_hooks +{ + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); } internal_hooks; #if defined(_MSC_VER) -/* work around MSVC error C2322: '...' address of dillimport '...' is not static */ -static void* internal_malloc(size_t size) +/* work around MSVC error C2322: '...' address of dllimport '...' is not static */ +static void * CJSON_CDECL internal_malloc(size_t size) { return malloc(size); } -static void internal_free(void* pointer) +static void CJSON_CDECL internal_free(void *pointer) { free(pointer); } -static void* internal_realloc(void* pointer, size_t size) +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) { return realloc(pointer, size); } #else -#include "aos/kernel.h" -#define internal_malloc aos_malloc -#define internal_free aos_free -#define internal_realloc aos_realloc +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc #endif +/* strlen of character literals resolved at compile time */ +#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) + static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; -static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks* const hooks) +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) { size_t length = 0; - unsigned char* copy = NULL; + unsigned char *copy = NULL; if (string == NULL) + { return NULL; + } length = strlen((const char*)string) + sizeof(""); copy = (unsigned char*)hooks->allocate(length); if (copy == NULL) + { return NULL; + } memcpy(copy, string, length); return copy; @@ -158,7 +208,8 @@ static unsigned char* cJSON_strdup(const unsigned char* string, const internal_h CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) { - if (hooks == NULL) { + if (hooks == NULL) + { /* Reset hooks */ global_hooks.allocate = malloc; global_hooks.deallocate = free; @@ -168,45 +219,54 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) global_hooks.allocate = malloc; if (hooks->malloc_fn != NULL) + { global_hooks.allocate = hooks->malloc_fn; + } global_hooks.deallocate = free; if (hooks->free_fn != NULL) + { global_hooks.deallocate = hooks->free_fn; + } /* use realloc only if both free and malloc are used */ global_hooks.reallocate = NULL; if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { global_hooks.reallocate = realloc; + } } /* Internal constructor. */ -static cJSON* cJSON_New_Item(const internal_hooks* const hooks) +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) { cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); if (node) + { memset(node, '\0', sizeof(cJSON)); + } return node; } /* Delete a cJSON structure. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON* item) +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) { - cJSON* next = NULL; - while (item != NULL) { + cJSON *next = NULL; + while (item != NULL) + { next = item->next; if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { cJSON_Delete(item->child); - if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { -#ifndef CJSON_STRING_ZEROCOPY + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { global_hooks.deallocate(item->valuestring); -#endif } - if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { -#ifndef CJSON_STRING_ZEROCOPY + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { global_hooks.deallocate(item->string); -#endif } global_hooks.deallocate(item); item = next; @@ -217,15 +277,16 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON* item) static unsigned char get_decimal_point(void) { #ifdef ENABLE_LOCALES - struct lconv* lconv = localeconv(); + struct lconv *lconv = localeconv(); return (unsigned char) lconv->decimal_point[0]; #else return '.'; #endif } -typedef struct { - const unsigned char* content; +typedef struct +{ + const unsigned char *content; size_t length; size_t offset; size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ @@ -241,52 +302,57 @@ typedef struct { #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) /* Parse the input text to generate a number, and populate the result into item. */ -static cJSON_bool parse_number(cJSON* const item, parse_buffer* const input_buffer) +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) { double number = 0; - unsigned char* after_end = NULL; + unsigned char *after_end = NULL; unsigned char number_c_string[64]; unsigned char decimal_point = get_decimal_point(); size_t i = 0; if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { return false; + } /* copy the number into a temporary buffer and replace '.' with the decimal point * of the current locale (for strtod) * This also takes care of '\0' not necessarily being available for marking the end of the input */ - for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) { - switch (buffer_at_offset(input_buffer)[i]) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '+': - case '-': - case 'e': - case 'E': - number_c_string[i] = buffer_at_offset(input_buffer)[i]; - break; + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; - case '.': - number_c_string[i] = decimal_point; - break; + case '.': + number_c_string[i] = decimal_point; + break; - default: - goto loop_end; + default: + goto loop_end; } } loop_end: number_c_string[i] = '\0'; number = strtod((const char*)number_c_string, (char**)&after_end); - if (number_c_string == after_end) { + if (number_c_string == after_end) + { return false; /* parse_error */ } @@ -294,11 +360,17 @@ loop_end: /* use saturation in case of overflow */ if (number >= INT_MAX) + { item->valueint = INT_MAX; - else if (number <= INT_MIN) + } + else if (number <= (double)INT_MIN) + { item->valueint = INT_MIN; + } else + { item->valueint = (int)number; + } item->type = cJSON_Number; @@ -307,20 +379,54 @@ loop_end: } /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ -CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON* object, double number) +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) { if (number >= INT_MAX) + { object->valueint = INT_MAX; - else if (number <= INT_MIN) + } + else if (number <= (double)INT_MIN) + { object->valueint = INT_MIN; + } else + { object->valueint = (int)number; + } return object->valuedouble = number; } -typedef struct { - unsigned char* buffer; +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) +{ + char *copy = NULL; + /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ + if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) + { + return NULL; + } + if (strlen(valuestring) <= strlen(object->valuestring)) + { + strcpy(object->valuestring, valuestring); + return object->valuestring; + } + copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); + if (copy == NULL) + { + return NULL; + } + if (object->valuestring != NULL) + { + cJSON_free(object->valuestring); + } + object->valuestring = copy; + + return copy; +} + +typedef struct +{ + unsigned char *buffer; size_t length; size_t offset; size_t depth; /* current nesting depth (for formatted printing) */ @@ -330,63 +436,83 @@ typedef struct { } printbuffer; /* realloc printbuffer if necessary to have at least "needed" bytes more */ -static unsigned char* ensure(printbuffer* const p, size_t needed) +static unsigned char* ensure(printbuffer * const p, size_t needed) { - unsigned char* newbuffer = NULL; + unsigned char *newbuffer = NULL; size_t newsize = 0; if ((p == NULL) || (p->buffer == NULL)) + { return NULL; + } - if ((p->length > 0) && (p->offset >= p->length)) { + if ((p->length > 0) && (p->offset >= p->length)) + { /* make sure that offset is valid */ return NULL; } - if (needed > INT_MAX) { + if (needed > INT_MAX) + { /* sizes bigger than INT_MAX are currently not supported */ return NULL; } needed += p->offset + 1; if (needed <= p->length) + { return p->buffer + p->offset; + } - if (p->noalloc) + if (p->noalloc) { return NULL; + } /* calculate new buffer size */ - if (needed > (INT_MAX / 2)) { + if (needed > (INT_MAX / 2)) + { /* overflow of int, use INT_MAX if possible */ if (needed <= INT_MAX) + { newsize = INT_MAX; + } else + { return NULL; - } else + } + } + else + { newsize = needed * 2; + } - if (p->hooks.reallocate != NULL) { + if (p->hooks.reallocate != NULL) + { /* reallocate with realloc if available */ newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); - if (newbuffer == NULL) { + if (newbuffer == NULL) + { p->hooks.deallocate(p->buffer); p->length = 0; p->buffer = NULL; return NULL; } - } else { + } + else + { /* otherwise reallocate manually */ newbuffer = (unsigned char*)p->hooks.allocate(newsize); - if (!newbuffer) { + if (!newbuffer) + { p->hooks.deallocate(p->buffer); p->length = 0; p->buffer = NULL; return NULL; } - if (newbuffer) - memcpy(newbuffer, p->buffer, p->offset + 1); + + memcpy(newbuffer, p->buffer, p->offset + 1); p->hooks.deallocate(p->buffer); } p->length = newsize; @@ -396,57 +522,78 @@ static unsigned char* ensure(printbuffer* const p, size_t needed) } /* calculate the new length of the string in a printbuffer and update the offset */ -static void update_offset(printbuffer* const buffer) +static void update_offset(printbuffer * const buffer) { - const unsigned char* buffer_pointer = NULL; + const unsigned char *buffer_pointer = NULL; if ((buffer == NULL) || (buffer->buffer == NULL)) + { return; + } buffer_pointer = buffer->buffer + buffer->offset; buffer->offset += strlen((const char*)buffer_pointer); } +/* securely comparison of floating-point variables */ +static cJSON_bool compare_double(double a, double b) +{ + double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); + return (fabs(a - b) <= maxVal * DBL_EPSILON); +} + /* Render the number nicely from the given item into a string. */ -static cJSON_bool print_number(const cJSON* const item, printbuffer* const output_buffer) +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) { - unsigned char* output_pointer = NULL; + unsigned char *output_pointer = NULL; double d = item->valuedouble; int length = 0; size_t i = 0; - unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ unsigned char decimal_point = get_decimal_point(); - double test; + double test = 0.0; if (output_buffer == NULL) + { return false; + } /* This checks for NaN and Infinity */ - if ((d * 0) != 0) + if (isnan(d) || isinf(d)) + { length = sprintf((char*)number_buffer, "null"); - else { + } + else + { /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ length = sprintf((char*)number_buffer, "%1.15g", d); /* Check whether the original double can be recovered */ - if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) { + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) + { /* If not, print with 17 decimal places of precision */ length = sprintf((char*)number_buffer, "%1.17g", d); } } - /* sprintf failed or buffer overrun occured */ + /* sprintf failed or buffer overrun occurred */ if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { return false; + } /* reserve appropriate space in the output */ - output_pointer = ensure(output_buffer, (size_t)length); + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); if (output_pointer == NULL) + { return false; + } /* copy the printed number to the output and replace locale * dependent decimal point with '.' */ - for (i = 0; i < ((size_t)length); i++) { - if (number_buffer[i] == decimal_point) { + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { output_pointer[i] = '.'; continue; } @@ -459,25 +606,35 @@ static cJSON_bool print_number(const cJSON* const item, printbuffer* const outpu return true; } -#ifndef CJSON_STRING_ZEROCOPY + /* parse 4 digit hexadecimal number */ -static unsigned parse_hex4(const unsigned char* const input) +static unsigned parse_hex4(const unsigned char * const input) { unsigned int h = 0; size_t i = 0; - for (i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) + { /* parse digit */ if ((input[i] >= '0') && (input[i] <= '9')) + { h += (unsigned int) input[i] - '0'; + } else if ((input[i] >= 'A') && (input[i] <= 'F')) + { h += (unsigned int) 10 + input[i] - 'A'; + } else if ((input[i] >= 'a') && (input[i] <= 'f')) + { h += (unsigned int) 10 + input[i] - 'a'; + } else /* invalid */ + { return 0; + } - if (i < 3) { + if (i < 3) + { /* shift left to make place for the next nibble */ h = h << 4; } @@ -488,17 +645,18 @@ static unsigned parse_hex4(const unsigned char* const input) /* converts a UTF-16 literal to UTF-8 * A literal can be one or two sequences of the form \uXXXX */ -static unsigned char utf16_literal_to_utf8(const unsigned char* const input_pointer, const unsigned char* const input_end, unsigned char** output_pointer) +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) { long unsigned int codepoint = 0; unsigned int first_code = 0; - const unsigned char* first_sequence = input_pointer; + const unsigned char *first_sequence = input_pointer; unsigned char utf8_length = 0; unsigned char utf8_position = 0; unsigned char sequence_length = 0; unsigned char first_byte_mark = 0; - if ((input_end - first_sequence) < 6) { + if ((input_end - first_sequence) < 6) + { /* input ends unexpectedly */ goto fail; } @@ -508,20 +666,25 @@ static unsigned char utf16_literal_to_utf8(const unsigned char* const input_poin /* check that the code is valid */ if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { goto fail; + } /* UTF16 surrogate pair */ - if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) { - const unsigned char* second_sequence = first_sequence + 6; + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; unsigned int second_code = 0; sequence_length = 12; /* \uXXXX\uXXXX */ - if ((input_end - second_sequence) < 6) { + if ((input_end - second_sequence) < 6) + { /* input ends unexpectedly */ goto fail; } - if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) { + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { /* missing second half of the surrogate pair */ goto fail; } @@ -529,7 +692,8 @@ static unsigned char utf16_literal_to_utf8(const unsigned char* const input_poin /* get the second utf16 sequence */ second_code = parse_hex4(second_sequence + 2); /* check that the code is valid */ - if ((second_code < 0xDC00) || (second_code > 0xDFFF)) { + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { /* invalid second half of the surrogate pair */ goto fail; } @@ -537,7 +701,9 @@ static unsigned char utf16_literal_to_utf8(const unsigned char* const input_poin /* calculate the unicode codepoint from the surrogate pair */ codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); - } else { + } + else + { sequence_length = 6; /* \uXXXX */ codepoint = first_code; } @@ -545,37 +711,51 @@ static unsigned char utf16_literal_to_utf8(const unsigned char* const input_poin /* encode as UTF-8 * takes at maximum 4 bytes to encode: * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - if (codepoint < 0x80) { + if (codepoint < 0x80) + { /* normal ascii, encoding 0xxxxxxx */ utf8_length = 1; - } else if (codepoint < 0x800) { + } + else if (codepoint < 0x800) + { /* two bytes, encoding 110xxxxx 10xxxxxx */ utf8_length = 2; first_byte_mark = 0xC0; /* 11000000 */ - } else if (codepoint < 0x10000) { + } + else if (codepoint < 0x10000) + { /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ utf8_length = 3; first_byte_mark = 0xE0; /* 11100000 */ - } else if (codepoint <= 0x10FFFF) { + } + else if (codepoint <= 0x10FFFF) + { /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ utf8_length = 4; first_byte_mark = 0xF0; /* 11110000 */ - } else { + } + else + { /* invalid unicode codepoint */ goto fail; } /* encode as utf8 */ - for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) { + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { /* 10xxxxxx */ (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); codepoint >>= 6; } /* encode first byte */ if (utf8_length > 1) + { (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } else + { (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } *output_pointer += utf8_length; @@ -584,31 +764,32 @@ static unsigned char utf16_literal_to_utf8(const unsigned char* const input_poin fail: return 0; } -#endif + /* Parse the input text into an unescaped cinput, and populate item. */ -static cJSON_bool parse_string(cJSON* const item, parse_buffer* const input_buffer) +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) { - const unsigned char* input_pointer = buffer_at_offset(input_buffer) + 1; - const unsigned char* input_end = buffer_at_offset(input_buffer) + 1; -#ifndef CJSON_STRING_ZEROCOPY - unsigned char* output_pointer = NULL; -#endif - unsigned char* output = NULL; + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; /* not a string */ if (buffer_at_offset(input_buffer)[0] != '\"') + { goto fail; + } { /* calculate approximate size of the output (overestimate) */ -#ifndef CJSON_STRING_ZEROCOPY size_t allocation_length = 0; -#endif size_t skipped_bytes = 0; - while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) { + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { /* is escape sequence */ - if (input_end[0] == '\\') { - if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) { + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { /* prevent buffer overflow when last input character is a backslash */ goto fail; } @@ -617,64 +798,72 @@ static cJSON_bool parse_string(cJSON* const item, parse_buffer* const input_buff } input_end++; } - if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) { + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { goto fail; /* string ended unexpectedly */ } -#ifndef CJSON_STRING_ZEROCOPY - /* This is at most how much we need for the output */ - allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); - if (output == NULL) { + if (output == NULL) + { goto fail; /* allocation failure */ } -#endif } -#ifndef CJSON_STRING_ZEROCOPY + output_pointer = output; /* loop through the string literal */ - while (input_pointer < input_end) { + while (input_pointer < input_end) + { if (*input_pointer != '\\') + { *output_pointer++ = *input_pointer++; + } /* escape sequence */ - else { + else + { unsigned char sequence_length = 2; if ((input_end - input_pointer) < 1) + { goto fail; + } - switch (input_pointer[1]) { - case 'b': - *output_pointer++ = '\b'; - break; - case 'f': - *output_pointer++ = '\f'; - break; - case 'n': - *output_pointer++ = '\n'; - break; - case 'r': - *output_pointer++ = '\r'; - break; - case 't': - *output_pointer++ = '\t'; - break; - case '\"': - case '\\': - case '/': - *output_pointer++ = input_pointer[1]; - break; - - /* UTF-16 literal */ - case 'u': - sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); - if (sequence_length == 0) { - /* failed to convert UTF16-literal to UTF-8 */ + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: goto fail; - } - break; - - default: - goto fail; } input_pointer += sequence_length; } @@ -682,83 +871,92 @@ static cJSON_bool parse_string(cJSON* const item, parse_buffer* const input_buff /* zero terminate the output */ *output_pointer = '\0'; -#else - output = (unsigned char*)input_pointer; -#endif + item->type = cJSON_String; item->valuestring = (char*)output; -#ifdef CJSON_STRING_ZEROCOPY - item->valuestring_length = input_end - output; -#else -#endif - input_buffer->offset = (size_t)(input_end - input_buffer->content); + + input_buffer->offset = (size_t) (input_end - input_buffer->content); input_buffer->offset++; return true; fail: -#ifndef CJSON_STRING_ZEROCOPY if (output != NULL) + { input_buffer->hooks.deallocate(output); -#endif + } + if (input_pointer != NULL) + { input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } return false; } /* Render the cstring provided to an escaped version that can be printed. */ -static cJSON_bool print_string_ptr(const unsigned char* const input, printbuffer* const output_buffer) +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) { - const unsigned char* input_pointer = NULL; - unsigned char* output = NULL; - unsigned char* output_pointer = NULL; + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; size_t output_length = 0; /* numbers of additional characters needed for escaping */ size_t escape_characters = 0; if (output_buffer == NULL) + { return false; + } /* empty string */ - if (input == NULL) { + if (input == NULL) + { output = ensure(output_buffer, sizeof("\"\"")); if (output == NULL) + { return false; + } strcpy((char*)output, "\"\""); return true; } /* set "flag" to 1 if something needs to be escaped */ - for (input_pointer = input; *input_pointer; input_pointer++) { - switch (*input_pointer) { - case '\"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - /* one character escape sequence */ - escape_characters++; - break; - default: - if (*input_pointer < 32) { - /* UTF-16 escape sequence uXXXX */ - escape_characters += 5; - } - break; + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; } } output_length = (size_t)(input_pointer - input) + escape_characters; output = ensure(output_buffer, output_length + sizeof("\"\"")); if (output == NULL) + { return false; + } /* no characters have to be escaped */ - if (escape_characters == 0) { + if (escape_characters == 0) + { output[0] = '\"'; memcpy(output + 1, input, output_length); output[output_length + 1] = '\"'; @@ -770,40 +968,45 @@ static cJSON_bool print_string_ptr(const unsigned char* const input, printbuffer output[0] = '\"'; output_pointer = output + 1; /* copy the string */ - for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) { - if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) { + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { /* normal character, copy */ *output_pointer = *input_pointer; - } else { + } + else + { /* character needs to be escaped */ *output_pointer++ = '\\'; - switch (*input_pointer) { - case '\\': - *output_pointer = '\\'; - break; - case '\"': - *output_pointer = '\"'; - break; - case '\b': - *output_pointer = 'b'; - break; - case '\f': - *output_pointer = 'f'; - break; - case '\n': - *output_pointer = 'n'; - break; - case '\r': - *output_pointer = 'r'; - break; - case '\t': - *output_pointer = 't'; - break; - default: - /* escape and print as unicode codepoint */ - sprintf((char*)output_pointer, "u%04x", *input_pointer); - output_pointer += 4; - break; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; } } } @@ -814,100 +1017,149 @@ static cJSON_bool print_string_ptr(const unsigned char* const input, printbuffer } /* Invoke print_string_ptr (which is useful) on an item. */ -static cJSON_bool print_string(const cJSON* const item, printbuffer* const p) +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) { return print_string_ptr((unsigned char*)item->valuestring, p); } /* Predeclare these prototypes. */ -static cJSON_bool parse_value(cJSON* const item, parse_buffer* const input_buffer); -static cJSON_bool print_value(const cJSON* const item, printbuffer* const output_buffer); -static cJSON_bool parse_array(cJSON* const item, parse_buffer* const input_buffer); -static cJSON_bool print_array(const cJSON* const item, printbuffer* const output_buffer); -static cJSON_bool parse_object(cJSON* const item, parse_buffer* const input_buffer); -static cJSON_bool print_object(const cJSON* const item, printbuffer* const output_buffer); +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); /* Utility to jump whitespace and cr/lf */ -static parse_buffer* buffer_skip_whitespace(parse_buffer* const buffer) +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) { if ((buffer == NULL) || (buffer->content == NULL)) + { return NULL; + } + + if (cannot_access_at_index(buffer, 0)) + { + return buffer; + } while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) - buffer->offset++; + { + buffer->offset++; + } if (buffer->offset == buffer->length) + { buffer->offset--; + } return buffer; } /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ -static parse_buffer* skip_utf8_bom(parse_buffer* const buffer) +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) { if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { return NULL; + } if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { buffer->offset += 3; + } return buffer; } +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + size_t buffer_length; + + if (NULL == value) + { + return NULL; + } + + /* Adding null character size due to require_null_terminated. */ + buffer_length = strlen(value) + sizeof(""); + + return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); +} + /* Parse an object - create a new root, and populate. */ -CJSON_PUBLIC(cJSON*) cJSON_ParseWithOpts(const char* value, const char** return_parse_end, cJSON_bool require_null_terminated) +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) { parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; - cJSON* item = NULL; + cJSON *item = NULL; /* reset error position */ global_error.json = NULL; global_error.position = 0; - if (value == NULL) + if (value == NULL || 0 == buffer_length) + { goto fail; + } buffer.content = (const unsigned char*)value; - buffer.length = strlen((const char*)value) + sizeof(""); + buffer.length = buffer_length; buffer.offset = 0; buffer.hooks = global_hooks; item = cJSON_New_Item(&global_hooks); if (item == NULL) /* memory fail */ + { goto fail; + } - if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) { + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { /* parse failure. ep is set. */ goto fail; } /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ - if (require_null_terminated) { + if (require_null_terminated) + { buffer_skip_whitespace(&buffer); if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { goto fail; + } } if (return_parse_end) + { *return_parse_end = (const char*)buffer_at_offset(&buffer); + } return item; fail: if (item != NULL) + { cJSON_Delete(item); + } - if (value != NULL) { + if (value != NULL) + { error local_error; local_error.json = (const unsigned char*)value; local_error.position = 0; if (buffer.offset < buffer.length) + { local_error.position = buffer.offset; + } else if (buffer.length > 0) + { local_error.position = buffer.length - 1; + } if (return_parse_end != NULL) + { *return_parse_end = (const char*)local_error.json + local_error.position; + } global_error = local_error; } @@ -916,42 +1168,59 @@ fail: } /* Default options for cJSON_Parse */ -CJSON_PUBLIC(cJSON*) cJSON_Parse(const char* value) +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) { return cJSON_ParseWithOpts(value, 0, 0); } -#define cjson_min(a, b) ((a < b) ? a : b) +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) +{ + return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); +} + +#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) -static unsigned char* print(const cJSON* const item, cJSON_bool format, const internal_hooks* const hooks) +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) { + static const size_t default_buffer_size = 256; printbuffer buffer[1]; - unsigned char* printed = NULL; + unsigned char *printed = NULL; memset(buffer, 0, sizeof(buffer)); /* create buffer */ - buffer->buffer = (unsigned char*) hooks->allocate(256); + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; buffer->format = format; buffer->hooks = *hooks; if (buffer->buffer == NULL) + { goto fail; + } /* print the value */ if (!print_value(item, buffer)) + { goto fail; + } update_offset(buffer); /* check if reallocate is available */ - if (hooks->reallocate != NULL) { - printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->length); - buffer->buffer = NULL; - if (printed == NULL) + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { goto fail; - } else { /* otherwise copy the JSON over to a new buffer */ + } + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { printed = (unsigned char*) hooks->allocate(buffer->offset + 1); if (printed == NULL) + { goto fail; + } memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); printed[buffer->offset] = '\0'; /* just to be sure */ @@ -963,35 +1232,43 @@ static unsigned char* print(const cJSON* const item, cJSON_bool format, const in fail: if (buffer->buffer != NULL) + { hooks->deallocate(buffer->buffer); + } if (printed != NULL) + { hooks->deallocate(printed); + } return NULL; } /* Render a cJSON item/entity/structure to text. */ -CJSON_PUBLIC(char*) cJSON_Print(const cJSON* item) +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) { return (char*)print(item, true, &global_hooks); } -CJSON_PUBLIC(char*) cJSON_PrintUnformatted(const cJSON* item) +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) { return (char*)print(item, false, &global_hooks); } -CJSON_PUBLIC(char*) cJSON_PrintBuffered(const cJSON* item, int prebuffer, cJSON_bool fmt) +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) { printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; if (prebuffer < 0) + { return NULL; + } p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); if (!p.buffer) + { return NULL; + } p.length = (size_t)prebuffer; p.offset = 0; @@ -999,7 +1276,8 @@ CJSON_PUBLIC(char*) cJSON_PrintBuffered(const cJSON* item, int prebuffer, cJSON_ p.format = fmt; p.hooks = global_hooks; - if (!print_value(item, &p)) { + if (!print_value(item, &p)) + { global_hooks.deallocate(p.buffer); return NULL; } @@ -1007,45 +1285,51 @@ CJSON_PUBLIC(char*) cJSON_PrintBuffered(const cJSON* item, int prebuffer, cJSON_ return (char*)p.buffer; } -CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON* item, char* buf, const int len, const cJSON_bool fmt) +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) { printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - if ((len < 0) || (buf == NULL)) + if ((length < 0) || (buffer == NULL)) + { return false; + } - p.buffer = (unsigned char*)buf; - p.length = (size_t)len; + p.buffer = (unsigned char*)buffer; + p.length = (size_t)length; p.offset = 0; p.noalloc = true; - p.format = fmt; + p.format = format; p.hooks = global_hooks; return print_value(item, &p); } /* Parser core - when encountering text, process appropriately. */ -static cJSON_bool parse_value(cJSON* const item, parse_buffer* const input_buffer) +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) { - if ((input_buffer == NULL) || (input_buffer->content == NULL)) { + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { return false; /* no input */ } /* parse the different types of values */ /* null */ - if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) { + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { item->type = cJSON_NULL; input_buffer->offset += 4; return true; } /* false */ - if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) { + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { item->type = cJSON_False; input_buffer->offset += 5; return true; } /* true */ - if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) { + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { item->type = cJSON_True; item->valueint = 1; input_buffer->offset += 4; @@ -1053,109 +1337,131 @@ static cJSON_bool parse_value(cJSON* const item, parse_buffer* const input_buffe } /* string */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { return parse_string(item, input_buffer); + } /* number */ - 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')))) + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { return parse_number(item, input_buffer); + } /* array */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { return parse_array(item, input_buffer); + } /* object */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { return parse_object(item, input_buffer); + } return false; } /* Render a value to text. */ -static cJSON_bool print_value(const cJSON* const item, printbuffer* const output_buffer) +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) { - unsigned char* output = NULL; + unsigned char *output = NULL; if ((item == NULL) || (output_buffer == NULL)) + { return false; + } - switch ((item->type) & 0xFF) { - case cJSON_NULL: - output = ensure(output_buffer, 5); - if (output == NULL) - return false; - strcpy((char*)output, "null"); - return true; + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; - case cJSON_False: - output = ensure(output_buffer, 6); - if (output == NULL) - return false; - strcpy((char*)output, "false"); - return true; + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; - case cJSON_True: - output = ensure(output_buffer, 5); - if (output == NULL) - return false; - strcpy((char*)output, "true"); - return true; + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; - case cJSON_Number: - return print_number(item, output_buffer); + case cJSON_Number: + return print_number(item, output_buffer); - case cJSON_Raw: { - size_t raw_length = 0; - if (item->valuestring == NULL) { - if (!output_buffer->noalloc) - output_buffer->hooks.deallocate(output_buffer->buffer); - return false; - } + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + return false; + } - raw_length = strlen(item->valuestring) + sizeof(""); - output = ensure(output_buffer, raw_length); - if (output == NULL) - return false; - memcpy(output, item->valuestring, raw_length); - return true; - } + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } - case cJSON_String: - return print_string(item, output_buffer); + case cJSON_String: + return print_string(item, output_buffer); - case cJSON_Array: - return print_array(item, output_buffer); + case cJSON_Array: + return print_array(item, output_buffer); - case cJSON_Object: - return print_object(item, output_buffer); + case cJSON_Object: + return print_object(item, output_buffer); - default: - return false; + default: + return false; } } /* Build an array from input text. */ -static cJSON_bool parse_array(cJSON* const item, parse_buffer* const input_buffer) +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) { - cJSON* head = NULL; /* head of the linked list */ - cJSON* current_item = NULL; + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; - if (input_buffer->depth >= CJSON_NESTING_LIMIT) { + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { return false; /* to deeply nested */ } input_buffer->depth++; - if (buffer_at_offset(input_buffer)[0] != '[') { + if (buffer_at_offset(input_buffer)[0] != '[') + { /* not an array */ goto fail; } input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) { + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { /* empty array */ goto success; } /* check if we skipped to the end of the buffer */ - if (cannot_access_at_index(input_buffer, 0)) { + if (cannot_access_at_index(input_buffer, 0)) + { input_buffer->offset--; goto fail; } @@ -1163,18 +1469,23 @@ static cJSON_bool parse_array(cJSON* const item, parse_buffer* const input_buffe /* step back to character in front of the first element */ input_buffer->offset--; /* loop through the comma separated array elements */ - do { + do + { /* allocate next item */ - cJSON* new_item = cJSON_New_Item(&(input_buffer->hooks)); - if (new_item == NULL) { + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { goto fail; /* allocation failure */ } /* attach next item to list */ - if (head == NULL) { + if (head == NULL) + { /* start the linked list */ current_item = head = new_item; - } else { + } + else + { /* add to the end and advance */ current_item->next = new_item; new_item->prev = current_item; @@ -1184,19 +1495,26 @@ static cJSON_bool parse_array(cJSON* const item, parse_buffer* const input_buffe /* parse next value */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) { + if (!parse_value(current_item, input_buffer)) + { goto fail; /* failed to parse value */ } buffer_skip_whitespace(input_buffer); - } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') { + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { goto fail; /* expected end of array */ } success: input_buffer->depth--; + if (head != NULL) { + head->prev = current_item; + } + item->type = cJSON_Array; item->child = head; @@ -1206,43 +1524,57 @@ success: fail: if (head != NULL) + { cJSON_Delete(head); + } return false; } /* Render an array to text */ -static cJSON_bool print_array(const cJSON* const item, printbuffer* const output_buffer) +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) { - unsigned char* output_pointer = NULL; + unsigned char *output_pointer = NULL; size_t length = 0; - cJSON* current_element = item->child; + cJSON *current_element = item->child; if (output_buffer == NULL) + { return false; + } /* Compose the output array. */ /* opening square bracket */ output_pointer = ensure(output_buffer, 1); if (output_pointer == NULL) + { return false; + } *output_pointer = '['; output_buffer->offset++; output_buffer->depth++; - while (current_element != NULL) { + while (current_element != NULL) + { if (!print_value(current_element, output_buffer)) + { return false; + } update_offset(output_buffer); - if (current_element->next) { - length = (size_t)(output_buffer->format ? 2 : 1); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) + { return false; + } *output_pointer++ = ','; - if (output_buffer->format) + if(output_buffer->format) + { *output_pointer++ = ' '; + } *output_pointer = '\0'; output_buffer->offset += length; } @@ -1251,7 +1583,9 @@ static cJSON_bool print_array(const cJSON* const item, printbuffer* const output output_pointer = ensure(output_buffer, 2); if (output_pointer == NULL) + { return false; + } *output_pointer++ = ']'; *output_pointer = '\0'; output_buffer->depth--; @@ -1260,28 +1594,32 @@ static cJSON_bool print_array(const cJSON* const item, printbuffer* const output } /* Build an object from the text. */ -static cJSON_bool parse_object(cJSON* const item, parse_buffer* const input_buffer) +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) { - cJSON* head = NULL; /* linked list head */ - cJSON* current_item = NULL; + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; - if (input_buffer->depth >= CJSON_NESTING_LIMIT) { + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { return false; /* to deeply nested */ } input_buffer->depth++; - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) { + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { goto fail; /* not an object */ } input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) { + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { goto success; /* empty object */ } /* check if we skipped to the end of the buffer */ - if (cannot_access_at_index(input_buffer, 0)) { + if (cannot_access_at_index(input_buffer, 0)) + { input_buffer->offset--; goto fail; } @@ -1289,18 +1627,23 @@ static cJSON_bool parse_object(cJSON* const item, parse_buffer* const input_buff /* step back to character in front of the first element */ input_buffer->offset--; /* loop through the comma separated array elements */ - do { + do + { /* allocate next item */ - cJSON* new_item = cJSON_New_Item(&(input_buffer->hooks)); - if (new_item == NULL) { + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { goto fail; /* allocation failure */ } /* attach next item to list */ - if (head == NULL) { + if (head == NULL) + { /* start the linked list */ current_item = head = new_item; - } else { + } + else + { /* add to the end and advance */ current_item->next = new_item; new_item->prev = current_item; @@ -1310,38 +1653,44 @@ static cJSON_bool parse_object(cJSON* const item, parse_buffer* const input_buff /* parse the name of the child */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (!parse_string(current_item, input_buffer)) { - goto fail; /* faile to parse name */ + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* failed to parse name */ } buffer_skip_whitespace(input_buffer); /* swap valuestring and string, because we parsed the name */ current_item->string = current_item->valuestring; -#ifdef CJSON_STRING_ZEROCOPY - current_item->string_length = current_item->valuestring_length; -#endif current_item->valuestring = NULL; - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) { + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { goto fail; /* invalid object */ } /* parse the value */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) { + if (!parse_value(current_item, input_buffer)) + { goto fail; /* failed to parse value */ } buffer_skip_whitespace(input_buffer); - } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) { + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { goto fail; /* expected end of object */ } success: input_buffer->depth--; + if (head != NULL) { + head->prev = current_item; + } + item->type = cJSON_Object; item->child = head; @@ -1350,73 +1699,101 @@ success: fail: if (head != NULL) + { cJSON_Delete(head); + } return false; } /* Render an object to text. */ -static cJSON_bool print_object(const cJSON* const item, printbuffer* const output_buffer) +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) { - unsigned char* output_pointer = NULL; + unsigned char *output_pointer = NULL; size_t length = 0; - cJSON* current_item = item->child; + cJSON *current_item = item->child; if (output_buffer == NULL) + { return false; + } /* Compose the output: */ - length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) + { return false; + } *output_pointer++ = '{'; output_buffer->depth++; if (output_buffer->format) + { *output_pointer++ = '\n'; + } output_buffer->offset += length; - while (current_item) { - if (output_buffer->format) { + while (current_item) + { + if (output_buffer->format) + { size_t i; output_pointer = ensure(output_buffer, output_buffer->depth); if (output_pointer == NULL) + { return false; + } for (i = 0; i < output_buffer->depth; i++) + { *output_pointer++ = '\t'; + } output_buffer->offset += output_buffer->depth; } /* print key */ if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { return false; + } update_offset(output_buffer); - length = (size_t)(output_buffer->format ? 2 : 1); + length = (size_t) (output_buffer->format ? 2 : 1); output_pointer = ensure(output_buffer, length); if (output_pointer == NULL) + { return false; + } *output_pointer++ = ':'; if (output_buffer->format) + { *output_pointer++ = '\t'; + } output_buffer->offset += length; /* print value */ if (!print_value(current_item, output_buffer)) + { return false; + } update_offset(output_buffer); /* print comma if not last */ - length = (size_t)((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0)); + length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) + { return false; + } if (current_item->next) + { *output_pointer++ = ','; + } if (output_buffer->format) + { *output_pointer++ = '\n'; + } *output_pointer = '\0'; output_buffer->offset += length; @@ -1425,11 +1802,16 @@ static cJSON_bool print_object(const cJSON* const item, printbuffer* const outpu output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); if (output_pointer == NULL) + { return false; - if (output_buffer->format) { + } + if (output_buffer->format) + { size_t i; for (i = 0; i < (output_buffer->depth - 1); i++) + { *output_pointer++ = '\t'; + } } *output_pointer++ = '}'; *output_pointer = '\0'; @@ -1439,17 +1821,20 @@ static cJSON_bool print_object(const cJSON* const item, printbuffer* const outpu } /* Get Array size/item / object item. */ -CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON* array) +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) { - cJSON* child = NULL; + cJSON *child = NULL; size_t size = 0; if (array == NULL) + { return 0; + } child = array->child; - while (child != NULL) { + while(child != NULL) + { size++; child = child->next; } @@ -1459,15 +1844,18 @@ CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON* array) return (int)size; } -static cJSON* get_array_item(const cJSON* array, size_t index) +static cJSON* get_array_item(const cJSON *array, size_t index) { - cJSON* current_child = NULL; + cJSON *current_child = NULL; if (array == NULL) + { return NULL; + } current_child = array->child; - while ((current_child != NULL) && (index > 0)) { + while ((current_child != NULL) && (index > 0)) + { index--; current_child = current_child->next; } @@ -1475,71 +1863,84 @@ static cJSON* get_array_item(const cJSON* array, size_t index) return current_child; } -CJSON_PUBLIC(cJSON*) cJSON_GetArrayItem(const cJSON* array, int index) +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) { if (index < 0) + { return NULL; + } return get_array_item(array, (size_t)index); } -static cJSON* get_object_item(const cJSON* const object, const char* const name, const cJSON_bool case_sensitive) +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) { - cJSON* current_element = NULL; + cJSON *current_element = NULL; if ((object == NULL) || (name == NULL)) + { return NULL; + } current_element = object->child; - if (case_sensitive) { - while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) + if (case_sensitive) + { + while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) + { current_element = current_element->next; - } else { -#ifndef CJSON_STRING_ZEROCOPY + } + } + else + { while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) -#else - while ((current_element != NULL) && (strncmp((const char*)name, (const char*)(current_element->string), current_element->string_length) != 0)) -#endif { current_element = current_element->next; } } + if ((current_element == NULL) || (current_element->string == NULL)) { + return NULL; + } + return current_element; } -CJSON_PUBLIC(cJSON*) cJSON_GetObjectItem(const cJSON* const object, const char* const string) +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) { return get_object_item(object, string, false); } -CJSON_PUBLIC(cJSON*) cJSON_GetObjectItemCaseSensitive(const cJSON* const object, const char* const string) +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) { return get_object_item(object, string, true); } -CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON* object, const char* string) +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) { return cJSON_GetObjectItem(object, string) ? 1 : 0; } /* Utility for array list handling. */ -static void suffix_object(cJSON* prev, cJSON* item) +static void suffix_object(cJSON *prev, cJSON *item) { prev->next = item; item->prev = prev; } /* Utility for handling references. */ -static cJSON* create_reference(const cJSON* item, const internal_hooks* const hooks) +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) { - cJSON* reference = NULL; + cJSON *reference = NULL; if (item == NULL) + { return NULL; + } reference = cJSON_New_Item(hooks); if (reference == NULL) + { return NULL; + } memcpy(reference, item, sizeof(cJSON)); reference->string = NULL; @@ -1548,94 +1949,266 @@ static cJSON* create_reference(const cJSON* item, const internal_hooks* const ho return reference; } -/* Add item to array/object. */ -CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON* array, cJSON* item) +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) { - cJSON* child = NULL; + cJSON *child = NULL; - if ((item == NULL) || (array == NULL)) - return; + if ((item == NULL) || (array == NULL) || (array == item)) + { + return false; + } child = array->child; - - if (child == NULL) { + /* + * To find the last item in array quickly, we use prev in array + */ + if (child == NULL) + { /* list is empty, start new one */ array->child = item; - } else { + item->prev = item; + item->next = NULL; + } + else + { /* append to the end */ - while (child->next) - child = child->next; - suffix_object(child, item); + if (child->prev) + { + suffix_object(child->prev, item); + array->child->prev = item; + } } + + return true; } -CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON* object, const char* string, cJSON* item) +/* Add item to array/object. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) { - if (item == NULL) - return; - - /* call cJSON_AddItemToObjectCS for code reuse */ - cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item); - /* remove cJSON_StringIsConst flag */ - item->type &= ~cJSON_StringIsConst; + return add_item_to_array(array, item); } #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) #pragma GCC diagnostic push #endif #ifdef __GNUC__ - #pragma GCC diagnostic ignored "-Wcast-qual" +#pragma GCC diagnostic ignored "-Wcast-qual" #endif - -/* Add an item to an object with constant string as key */ -CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON* object, const char* string, cJSON* item) +/* helper function to cast away const */ +static void* cast_away_const(const void* string) { - if ((item == NULL) || (string == NULL)) - return; - if (!(item->type & cJSON_StringIsConst) && item->string) - global_hooks.deallocate(item->string); - item->string = (char*)string; - item->type |= cJSON_StringIsConst; - cJSON_AddItemToArray(object, item); + return (void*)string; } #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) #pragma GCC diagnostic pop #endif -CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON* array, cJSON* item) + +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) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) + { + return false; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) { if (array == NULL) - return; + { + return false; + } - cJSON_AddItemToArray(array, create_reference(item, &global_hooks)); + return add_item_to_array(array, create_reference(item, &global_hooks)); } -CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON* object, const char* string, cJSON* item) +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) { if ((object == NULL) || (string == NULL)) - return; + { + return false; + } + + return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} - cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks)); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; } -CJSON_PUBLIC(cJSON*) cJSON_DetachItemViaPointer(cJSON* parent, cJSON* const item) +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) { if ((parent == NULL) || (item == NULL)) + { return NULL; + } - if (item->prev != NULL) { + if (item != parent->child) + { /* not the first element */ item->prev->next = item->next; } - if (item->next != NULL) { + if (item->next != NULL) + { /* not the last element */ item->next->prev = item->prev; } - if (item == parent->child) { + if (item == parent->child) + { /* first element */ parent->child = item->next; } + else if (item->next == NULL) + { + /* last element */ + parent->child->prev = item->prev; + } + /* make sure the detached item doesn't point anywhere anymore */ item->prev = NULL; item->next = NULL; @@ -1643,83 +2216,116 @@ CJSON_PUBLIC(cJSON*) cJSON_DetachItemViaPointer(cJSON* parent, cJSON* const item return item; } -CJSON_PUBLIC(cJSON*) cJSON_DetachItemFromArray(cJSON* array, int which) +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) { if (which < 0) + { return NULL; + } return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); } -CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON* array, int which) +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) { cJSON_Delete(cJSON_DetachItemFromArray(array, which)); } -CJSON_PUBLIC(cJSON*) cJSON_DetachItemFromObject(cJSON* object, const char* string) +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) { - cJSON* to_detach = cJSON_GetObjectItem(object, string); + cJSON *to_detach = cJSON_GetObjectItem(object, string); return cJSON_DetachItemViaPointer(object, to_detach); } -CJSON_PUBLIC(cJSON*) cJSON_DetachItemFromObjectCaseSensitive(cJSON* object, const char* string) +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) { - cJSON* to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); return cJSON_DetachItemViaPointer(object, to_detach); } -CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON* object, const char* string) +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) { cJSON_Delete(cJSON_DetachItemFromObject(object, string)); } -CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON* object, const char* string) +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) { cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); } /* Replace array/object items with new ones. */ -CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON* array, int which, cJSON* newitem) +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) { - cJSON* after_inserted = NULL; + cJSON *after_inserted = NULL; if (which < 0) - return; + { + return false; + } after_inserted = get_array_item(array, (size_t)which); - if (after_inserted == NULL) { - cJSON_AddItemToArray(array, newitem); - return; + if (after_inserted == NULL) + { + return add_item_to_array(array, newitem); } newitem->next = after_inserted; newitem->prev = after_inserted->prev; after_inserted->prev = newitem; if (after_inserted == array->child) + { array->child = newitem; + } else + { newitem->prev->next = newitem; + } + return true; } -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON* const parent, cJSON* const item, cJSON* replacement) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) { if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { return false; + } if (replacement == item) + { return true; + } replacement->next = item->next; replacement->prev = item->prev; if (replacement->next != NULL) + { replacement->next->prev = replacement; - if (replacement->prev != NULL) - replacement->prev->next = replacement; + } if (parent->child == item) + { + if (parent->child->prev == parent->child) + { + replacement->prev = replacement; + } parent->child = replacement; + } + else + { /* + * To find the last item in array quickly, we use prev in array. + * We can't modify the last item's next pointer where this item was the parent's child + */ + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (replacement->next == NULL) + { + parent->child->prev = replacement; + } + } item->next = NULL; item->prev = NULL; @@ -1728,103 +2334,124 @@ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON* const parent, cJSON* return true; } -CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON* array, int which, cJSON* newitem) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) { if (which < 0) - return; + { + return false; + } - cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); + return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); } -static cJSON_bool replace_item_in_object(cJSON* object, const char* string, cJSON* replacement, cJSON_bool case_sensitive) +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) { if ((replacement == NULL) || (string == NULL)) + { return false; + } /* replace the name in the replacement */ if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { cJSON_free(replacement->string); + } replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); replacement->type &= ~cJSON_StringIsConst; - cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); - - return true; + return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); } -CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON* object, const char* string, cJSON* newitem) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) { - replace_item_in_object(object, string, newitem, false); + return replace_item_in_object(object, string, newitem, false); } -CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON* object, const char* string, cJSON* newitem) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) { - replace_item_in_object(object, string, newitem, true); + return replace_item_in_object(object, string, newitem, true); } /* Create basic types: */ -CJSON_PUBLIC(cJSON*) cJSON_CreateNull(void) +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) { - cJSON* item = cJSON_New_Item(&global_hooks); - if (item) + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { item->type = cJSON_NULL; + } return item; } -CJSON_PUBLIC(cJSON*) cJSON_CreateTrue(void) +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) { - cJSON* item = cJSON_New_Item(&global_hooks); - if (item) + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { item->type = cJSON_True; + } return item; } -CJSON_PUBLIC(cJSON*) cJSON_CreateFalse(void) +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) { - cJSON* item = cJSON_New_Item(&global_hooks); - if (item) + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { item->type = cJSON_False; + } return item; } -CJSON_PUBLIC(cJSON*) cJSON_CreateBool(cJSON_bool b) +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) { - cJSON* item = cJSON_New_Item(&global_hooks); - if (item) - item->type = b ? cJSON_True : cJSON_False; + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = boolean ? cJSON_True : cJSON_False; + } return item; } -CJSON_PUBLIC(cJSON*) cJSON_CreateNumber(double num) +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) { - cJSON* item = cJSON_New_Item(&global_hooks); - if (item) { + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { item->type = cJSON_Number; item->valuedouble = num; /* use saturation in case of overflow */ if (num >= INT_MAX) + { item->valueint = INT_MAX; - else if (num <= INT_MIN) + } + else if (num <= (double)INT_MIN) + { item->valueint = INT_MIN; + } else + { item->valueint = (int)num; + } } return item; } -CJSON_PUBLIC(cJSON*) cJSON_CreateString(const char* string) +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) { - cJSON* item = cJSON_New_Item(&global_hooks); - if (item) { + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { item->type = cJSON_String; item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - if (!item->valuestring) { + if(!item->valuestring) + { cJSON_Delete(item); return NULL; } @@ -1833,13 +2460,48 @@ CJSON_PUBLIC(cJSON*) cJSON_CreateString(const char* string) return item; } -CJSON_PUBLIC(cJSON*) cJSON_CreateRaw(const char* raw) +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) { - cJSON* item = cJSON_New_Item(&global_hooks); - if (item) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { item->type = cJSON_Raw; item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); - if (!item->valuestring) { + if(!item->valuestring) + { cJSON_Delete(item); return NULL; } @@ -1848,234 +2510,363 @@ CJSON_PUBLIC(cJSON*) cJSON_CreateRaw(const char* raw) return item; } -CJSON_PUBLIC(cJSON*) cJSON_CreateArray(void) +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) { - cJSON* item = cJSON_New_Item(&global_hooks); - if (item) - item->type = cJSON_Array; + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } return item; } -CJSON_PUBLIC(cJSON*) cJSON_CreateObject(void) +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) { - cJSON* item = cJSON_New_Item(&global_hooks); + cJSON *item = cJSON_New_Item(&global_hooks); if (item) + { item->type = cJSON_Object; + } return item; } /* Create Arrays: */ -CJSON_PUBLIC(cJSON*) cJSON_CreateIntArray(const int* numbers, int count) +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) { size_t i = 0; - cJSON* n = NULL; - cJSON* p = NULL; - cJSON* a = NULL; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; if ((count < 0) || (numbers == NULL)) + { return NULL; + } a = cJSON_CreateArray(); - for (i = 0; a && (i < (size_t)count); i++) { + + for(i = 0; a && (i < (size_t)count); i++) + { n = cJSON_CreateNumber(numbers[i]); - if (!n) { + if (!n) + { cJSON_Delete(a); return NULL; } - if (!i) + if(!i) + { a->child = n; + } else + { suffix_object(p, n); + } p = n; } + if (a && a->child) { + a->child->prev = n; + } + return a; } -CJSON_PUBLIC(cJSON*) cJSON_CreateFloatArray(const float* numbers, int count) +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) { size_t i = 0; - cJSON* n = NULL; - cJSON* p = NULL; - cJSON* a = NULL; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; if ((count < 0) || (numbers == NULL)) + { return NULL; + } a = cJSON_CreateArray(); - for (i = 0; a && (i < (size_t)count); i++) { + for(i = 0; a && (i < (size_t)count); i++) + { n = cJSON_CreateNumber((double)numbers[i]); - if (!n) { + if(!n) + { cJSON_Delete(a); return NULL; } - if (!i) + if(!i) + { a->child = n; + } else + { suffix_object(p, n); + } p = n; } + if (a && a->child) { + a->child->prev = n; + } + return a; } -CJSON_PUBLIC(cJSON*) cJSON_CreateDoubleArray(const double* numbers, int count) +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) { size_t i = 0; - cJSON* n = NULL; - cJSON* p = NULL; - cJSON* a = NULL; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; if ((count < 0) || (numbers == NULL)) + { return NULL; + } a = cJSON_CreateArray(); - for (i = 0; a && (i < (size_t)count); i++) { + for(i = 0; a && (i < (size_t)count); i++) + { n = cJSON_CreateNumber(numbers[i]); - if (!n) { + if(!n) + { cJSON_Delete(a); return NULL; } - if (!i) + if(!i) + { a->child = n; + } else + { suffix_object(p, n); + } p = n; } + if (a && a->child) { + a->child->prev = n; + } + return a; } -CJSON_PUBLIC(cJSON*) cJSON_CreateStringArray(const char** strings, int count) +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) { size_t i = 0; - cJSON* n = NULL; - cJSON* p = NULL; - cJSON* a = NULL; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; if ((count < 0) || (strings == NULL)) + { return NULL; + } a = cJSON_CreateArray(); - for (i = 0; a && (i < (size_t)count); i++) { + for (i = 0; a && (i < (size_t)count); i++) + { n = cJSON_CreateString(strings[i]); - if (!n) { + if(!n) + { cJSON_Delete(a); return NULL; } - if (!i) + if(!i) + { a->child = n; + } else - suffix_object(p, n); + { + suffix_object(p,n); + } p = n; } + if (a && a->child) { + a->child->prev = n; + } + return a; } /* Duplication */ -CJSON_PUBLIC(cJSON*) cJSON_Duplicate(const cJSON* item, cJSON_bool recurse) +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) { - cJSON* newitem = NULL; - cJSON* child = NULL; - cJSON* next = NULL; - cJSON* newchild = NULL; + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; /* Bail on bad ptr */ if (!item) + { goto fail; + } /* Create new item */ newitem = cJSON_New_Item(&global_hooks); if (!newitem) + { goto fail; + } /* Copy over all vars */ newitem->type = item->type & (~cJSON_IsReference); newitem->valueint = item->valueint; newitem->valuedouble = item->valuedouble; - if (item->valuestring) { + if (item->valuestring) + { newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); if (!newitem->valuestring) + { goto fail; + } } - if (item->string) { - newitem->string = (item->type & cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); if (!newitem->string) + { goto fail; + } } /* If non-recursive, then we're done! */ if (!recurse) + { return newitem; + } /* Walk the ->next chain for the child. */ child = item->child; - while (child != NULL) { + while (child != NULL) + { newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ if (!newchild) + { goto fail; - if (next != NULL) { + } + if (next != NULL) + { /* If newitem->child already set, then crosswire ->prev and ->next and move on */ next->next = newchild; newchild->prev = next; next = newchild; - } else { + } + else + { /* Set newitem->child and move to it */ newitem->child = newchild; next = newchild; } child = child->next; } + if (newitem && newitem->child) + { + newitem->child->prev = newchild; + } return newitem; fail: if (newitem != NULL) + { cJSON_Delete(newitem); + } return NULL; } -CJSON_PUBLIC(void) cJSON_Minify(char* json) +static void skip_oneline_comment(char **input) +{ + *input += static_strlen("//"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if ((*input)[0] == '\n') { + *input += static_strlen("\n"); + return; + } + } +} + +static void skip_multiline_comment(char **input) { - unsigned char* into = (unsigned char*)json; + *input += static_strlen("/*"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if (((*input)[0] == '*') && ((*input)[1] == '/')) + { + *input += static_strlen("*/"); + return; + } + } +} + +static void minify_string(char **input, char **output) { + (*output)[0] = (*input)[0]; + *input += static_strlen("\""); + *output += static_strlen("\""); + + + for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { + (*output)[0] = (*input)[0]; + + if ((*input)[0] == '\"') { + (*output)[0] = '\"'; + *input += static_strlen("\""); + *output += static_strlen("\""); + return; + } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { + (*output)[1] = (*input)[1]; + *input += static_strlen("\""); + *output += static_strlen("\""); + } + } +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + char *into = json; if (json == NULL) + { return; + } - while (*json) { - if (*json == ' ') - json++; - else if (*json == '\t') { - /* Whitespace characters. */ - json++; - } else if (*json == '\r') - json++; - else if (*json == '\n') - json++; - else if ((*json == '/') && (json[1] == '/')) { - /* double-slash comments, to end of line. */ - while (*json && (*json != '\n')) + while (json[0] != '\0') + { + switch (json[0]) + { + case ' ': + case '\t': + case '\r': + case '\n': json++; - } else if ((*json == '/') && (json[1] == '*')) { - /* multiline comments. */ - while (*json && !((*json == '*') && (json[1] == '/'))) + break; + + case '/': + if (json[1] == '/') + { + skip_oneline_comment(&json); + } + else if (json[1] == '*') + { + skip_multiline_comment(&json); + } else { + json++; + } + break; + + case '\"': + minify_string(&json, (char**)&into); + break; + + default: + into[0] = json[0]; json++; - json += 2; - } else if (*json == '\"') { - /* string literals, which are \" sensitive. */ - *into++ = (unsigned char) * json++; - while (*json && (*json != '\"')) { - if (*json == '\\') - *into++ = (unsigned char) * json++; - *into++ = (unsigned char) * json++; - } - *into++ = (unsigned char) * json++; - } else { - /* All other characters. */ - *into++ = (unsigned char) * json++; + into++; } } @@ -2083,189 +2874,272 @@ CJSON_PUBLIC(void) cJSON_Minify(char* json) *into = '\0'; } -CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON* const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) { if (item == NULL) + { return false; + } return (item->type & 0xFF) == cJSON_Invalid; } -CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON* const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) { if (item == NULL) + { return false; + } return (item->type & 0xFF) == cJSON_False; } -CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON* const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) { if (item == NULL) + { return false; + } return (item->type & 0xff) == cJSON_True; } -CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON* const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) { if (item == NULL) + { return false; + } return (item->type & (cJSON_True | cJSON_False)) != 0; } -CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON* const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) { if (item == NULL) + { return false; + } return (item->type & 0xFF) == cJSON_NULL; } -CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON* const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) { if (item == NULL) + { return false; + } return (item->type & 0xFF) == cJSON_Number; } -CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON* const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) { if (item == NULL) + { return false; + } return (item->type & 0xFF) == cJSON_String; } -CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON* const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) { if (item == NULL) + { return false; + } return (item->type & 0xFF) == cJSON_Array; } -CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON* const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) { if (item == NULL) + { return false; + } return (item->type & 0xFF) == cJSON_Object; } -CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON* const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) { if (item == NULL) + { return false; + } return (item->type & 0xFF) == cJSON_Raw; } -CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON* const a, const cJSON* const b, const cJSON_bool case_sensitive) +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) { - if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) + { return false; + } /* check if type is valid */ - switch (a->type & 0xFF) { - case cJSON_False: - case cJSON_True: - case cJSON_NULL: - case cJSON_Number: - case cJSON_String: - case cJSON_Raw: - case cJSON_Array: - case cJSON_Object: - break; - - default: - return false; + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; } /* identical objects are equal */ if (a == b) + { return true; + } - switch (a->type & 0xFF) { - /* in these cases and equal type is enough */ - case cJSON_False: - case cJSON_True: - case cJSON_NULL: - return true; - - case cJSON_Number: - if (a->valuedouble == b->valuedouble) + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: return true; - return false; - case cJSON_String: - case cJSON_Raw: - if ((a->valuestring == NULL) || (b->valuestring == NULL)) + case cJSON_Number: + if (compare_double(a->valuedouble, b->valuedouble)) + { + return true; + } return false; - if (strcmp(a->valuestring, b->valuestring) == 0) - return true; - - return false; - case cJSON_Array: { - cJSON* a_element = a->child; - cJSON* b_element = b->child; - - for (; (a_element != NULL) && (b_element != NULL);) { - if (!cJSON_Compare(a_element, b_element, case_sensitive)) + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } - a_element = a_element->next; - b_element = b_element->next; - } - - /* one of the arrays is longer than the other */ - if (a_element != b_element) return false; - return true; - } + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } - case cJSON_Object: { - cJSON* a_element = NULL; - cJSON* b_element = NULL; - cJSON_ArrayForEach(a_element, a) { - /* TODO This has O(n^2) runtime, which is horrible! */ - b_element = get_object_item(b, a_element->string, case_sensitive); - if (b_element == NULL) - return false; + a_element = a_element->next; + b_element = b_element->next; + } - if (!cJSON_Compare(a_element, b_element, case_sensitive)) + /* one of the arrays is longer than the other */ + if (a_element != b_element) { return false; + } + + return true; } - /* doing this twice, once on a and b to prevent true comparison if a subset of b - * TODO: Do this the proper way, this is just a fix for now */ - cJSON_ArrayForEach(b_element, b) { - a_element = get_object_item(a, b_element->string, case_sensitive); - if (a_element == NULL) - return false; + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } - if (!cJSON_Compare(b_element, a_element, case_sensitive)) - return false; - } + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } - return true; - } + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } - default: - return false; + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; } } -CJSON_PUBLIC(void*) cJSON_malloc(size_t size) +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) { return global_hooks.allocate(size); } -CJSON_PUBLIC(void) cJSON_free(void* object) +CJSON_PUBLIC(void) cJSON_free(void *object) { global_hooks.deallocate(object); } + +/* add by hge */ +cJSON *cJSON_GetObjectItemByPath(cJSON *object, const char *path) +{ + if (object == NULL) { + return NULL; + } + + char *dup_path = strdup(path); + char *saveptr = NULL; + char *next = strtok_r(dup_path, ".", &saveptr); + + cJSON *item = object; + while (next) { + char *arr_ptr = strchr(next, '['); + if (arr_ptr) { + *arr_ptr++ = '\0'; + item = cJSON_GetObjectItem(item, next); + if (item) { + item = cJSON_GetArrayItem(item, atoi(arr_ptr)); + } + } else { + item = cJSON_GetObjectItem(item, next); + } + if (item == NULL) { + break; + } + + next = strtok_r(NULL, ".", &saveptr); + } + + free(dup_path); + + return item; +} diff --git a/components/utility/cjson/include/cJSON.h b/components/utility/cjson/include/cJSON.h index 524e8171a1..ebc27614b8 100644 --- a/components/utility/cjson/include/cJSON.h +++ b/components/utility/cjson/include/cJSON.h @@ -24,71 +24,17 @@ #define cJSON__h #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* project version */ -#define CJSON_VERSION_MAJOR 1 -#define CJSON_VERSION_MINOR 6 -#define CJSON_VERSION_PATCH 0 - -#include - -/* cJSON Types: */ -#define cJSON_Invalid (0) -#define cJSON_False (1 << 0) -#define cJSON_True (1 << 1) -#define cJSON_NULL (1 << 2) -#define cJSON_Number (1 << 3) -#define cJSON_String (1 << 4) -#define cJSON_Array (1 << 5) -#define cJSON_Object (1 << 6) -#define cJSON_Raw (1 << 7) /* raw json */ - -#define cJSON_IsReference 256 -#define cJSON_StringIsConst 512 - -/* The cJSON structure: */ -typedef struct cJSON { - /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ - struct cJSON* next; - struct cJSON* prev; - /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ - struct cJSON* child; - - /* The type of the item, as above. */ - int type; - - /* The item's string, if type==cJSON_String and type == cJSON_Raw */ - char* valuestring; -#ifdef CJSON_STRING_ZEROCOPY - size_t valuestring_length; -#endif - /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ - int valueint; - - /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ - char* string; -#ifdef CJSON_STRING_ZEROCOPY - size_t string_length; -#endif - /* The item's number, if type==cJSON_Number */ - double valuedouble; -} cJSON; - -typedef struct cJSON_Hooks { - void* (*malloc_fn)(size_t sz); - void (*free_fn)(void* ptr); -} cJSON_Hooks; - -typedef int cJSON_bool; - #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) #define __WINDOWS__ #endif + #ifdef __WINDOWS__ -/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) @@ -106,19 +52,25 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ */ +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + /* export symbols by default, this is necessary for copy pasting the C and header file */ #if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) #define CJSON_EXPORT_SYMBOLS #endif #if defined(CJSON_HIDE_SYMBOLS) -#define CJSON_PUBLIC(type) type __stdcall +#define CJSON_PUBLIC(type) type CJSON_STDCALL #elif defined(CJSON_EXPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL #elif defined(CJSON_IMPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL #endif -#else /* !WIN32 */ +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + #if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) #define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type #else @@ -126,6 +78,59 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ #endif #endif +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 15 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. * This is to prevent stack overflows. */ #ifndef CJSON_NESTING_LIMIT @@ -140,126 +145,149 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ -CJSON_PUBLIC(cJSON*) cJSON_Parse(const char* value); +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ -CJSON_PUBLIC(cJSON*) cJSON_ParseWithOpts(const char* value, const char** return_parse_end, - cJSON_bool require_null_terminated); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); /* Render a cJSON entity to text for transfer/storage. */ -CJSON_PUBLIC(char*) cJSON_Print(const cJSON* item); +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); /* Render a cJSON entity to text for transfer/storage without any formatting. */ -CJSON_PUBLIC(char*) cJSON_PrintUnformatted(const cJSON* item); +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ -CJSON_PUBLIC(char*) cJSON_PrintBuffered(const cJSON* item, int prebuffer, cJSON_bool fmt); +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ -CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON* item, char* buffer, const int length, const cJSON_bool format); +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); /* Delete a cJSON entity and all subentities. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON* c); +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); /* Returns the number of items in an array (or object). */ -CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON* array); -/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ -CJSON_PUBLIC(cJSON*) cJSON_GetArrayItem(const cJSON* array, int index); +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); /* Get item "string" from object. Case insensitive. */ -CJSON_PUBLIC(cJSON*) cJSON_GetObjectItem(const cJSON* const object, const char* const string); -CJSON_PUBLIC(cJSON*) cJSON_GetObjectItemCaseSensitive(const cJSON* const object, const char* const string); -CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON* object, const char* string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ -CJSON_PUBLIC(const char*) cJSON_GetErrorPtr(void); +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* Check item type and return its value */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); /* These functions check the type of an item */ -CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON* const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON* const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON* const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON* const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON* const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON* const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON* const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON* const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON* const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON* const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); /* These calls create a cJSON item of the appropriate type. */ -CJSON_PUBLIC(cJSON*) cJSON_CreateNull(void); -CJSON_PUBLIC(cJSON*) cJSON_CreateTrue(void); -CJSON_PUBLIC(cJSON*) cJSON_CreateFalse(void); -CJSON_PUBLIC(cJSON*) cJSON_CreateBool(cJSON_bool boolean); -CJSON_PUBLIC(cJSON*) cJSON_CreateNumber(double num); -CJSON_PUBLIC(cJSON*) cJSON_CreateString(const char* string); +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); /* raw json */ -CJSON_PUBLIC(cJSON*) cJSON_CreateRaw(const char* raw); -CJSON_PUBLIC(cJSON*) cJSON_CreateArray(void); -CJSON_PUBLIC(cJSON*) cJSON_CreateObject(void); - -/* These utilities create an Array of count items. */ -CJSON_PUBLIC(cJSON*) cJSON_CreateIntArray(const int* numbers, int count); -CJSON_PUBLIC(cJSON*) cJSON_CreateFloatArray(const float* numbers, int count); -CJSON_PUBLIC(cJSON*) cJSON_CreateDoubleArray(const double* numbers, int count); -CJSON_PUBLIC(cJSON*) cJSON_CreateStringArray(const char** strings, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/array that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. + * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); /* Append item to the specified array/object. */ -CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON* array, cJSON* item); -CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON* object, const char* string, cJSON* item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before * writing to `item->string` */ -CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON* object, const char* string, cJSON* item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ -CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON* array, cJSON* item); -CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON* object, const char* string, cJSON* item); - -/* Remove/Detatch items from Arrays/Objects. */ -CJSON_PUBLIC(cJSON*) cJSON_DetachItemViaPointer(cJSON* parent, cJSON* const item); -CJSON_PUBLIC(cJSON*) cJSON_DetachItemFromArray(cJSON* array, int which); -CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON* array, int which); -CJSON_PUBLIC(cJSON*) cJSON_DetachItemFromObject(cJSON* object, const char* string); -CJSON_PUBLIC(cJSON*) cJSON_DetachItemFromObjectCaseSensitive(cJSON* object, const char* string); -CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON* object, const char* string); -CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON* object, const char* string); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detach items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); /* Update array items. */ -CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON* array, int which, - cJSON* newitem); /* Shifts pre-existing items to the right. */ -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON* const parent, cJSON* const item, cJSON* replacement); -CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON* array, int which, cJSON* newitem); -CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON* object, const char* string, cJSON* newitem); -CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON* object, const char* string, cJSON* newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); /* Duplicate a cJSON item */ -CJSON_PUBLIC(cJSON*) cJSON_Duplicate(const cJSON* item, cJSON_bool recurse); +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will -need to be released. With recurse!=0, it will duplicate any children connected to the item. -The item->next and ->prev pointers are always zero on return from Duplicate. */ + * need to be released. With recurse!=0, it will duplicate any children connected to the item. + * The item->next and ->prev pointers are always zero on return from Duplicate. */ /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ -CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON* const a, const cJSON* const b, const cJSON_bool case_sensitive); - - -CJSON_PUBLIC(void) cJSON_Minify(char* json); - -/* Macros for creating things quickly. */ -#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) -#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) -#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) -#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) -#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) -#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) -#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s)) +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. + * The input pointer json cannot point to a read-only address area, such as a string constant, + * but should point to a readable and writable address area. */ +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); /* When assigning an integer value, it needs to be propagated to valuedouble too. */ #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) /* helper for the cJSON_SetNumberValue macro */ -CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON* object, double number); +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) +/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); /* Macro for iterating over an array or object */ #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ -CJSON_PUBLIC(void*) cJSON_malloc(size_t size); -CJSON_PUBLIC(void) cJSON_free(void* object); +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +cJSON *cJSON_GetObjectItemByPath(cJSON *object, const char *path); +cJSON *cJSON_Path(cJSON *jsroot, const char *jpath); #ifdef __cplusplus } -- Gitee