comparison src/json.c @ 12:dd427b7cc459 default tip

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