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