LCOV - code coverage report
Current view: top level - src - cJSON.c (source / functions) Hit Total Coverage
Test: mkernel.info Lines: 343 1390 24.7 %
Date: 2024-12-05 21:00:54 Functions: 30 113 26.5 %

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

Generated by: LCOV version 1.16