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