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