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