LCOV - code coverage report
Current view: top level - ballet/json - cJSON.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 315 2235 14.1 %
Date: 2024-11-13 11:58:15 Functions: 18 112 16.1 %

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

Generated by: LCOV version 1.14