blob: 8da6d83c329e774cc1997b74331f73b720ab4f0f [file] [log] [blame]
Jon Ashburn752e06e2015-06-29 11:25:34 -06001/*
2 Copyright (c) 2009 Dave Gamble
Jon Ashburn1c75aec2016-02-02 17:47:28 -07003 Copyright (c) 2015-2016 The Khronos Group Inc.
4 Copyright (c) 2015-2016 Valve Corporation
5 Copyright (c) 2015-2016 LunarG, Inc.
Jon Ashburn752e06e2015-06-29 11:25:34 -06006
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 THE SOFTWARE.
24*/
25
26/* cJSON */
27/* JSON parser in C. */
28
29#include <string.h>
30#include <stdio.h>
31#include <math.h>
32#include <stdlib.h>
33#include <float.h>
34#include <limits.h>
35#include <ctype.h>
36#include "cJSON.h"
37
38static const char *ep;
39
Jon Ashburn1c75aec2016-02-02 17:47:28 -070040const char *cJSON_GetErrorPtr(void) { return ep; }
Jon Ashburn752e06e2015-06-29 11:25:34 -060041
Jon Ashburn752e06e2015-06-29 11:25:34 -060042static void *(*cJSON_malloc)(size_t sz) = malloc;
43static void (*cJSON_free)(void *ptr) = free;
44
Jon Ashburn1c75aec2016-02-02 17:47:28 -070045static char *cJSON_strdup(const char *str) {
46 size_t len;
47 char *copy;
Jon Ashburn752e06e2015-06-29 11:25:34 -060048
Jon Ashburn1c75aec2016-02-02 17:47:28 -070049 len = strlen(str) + 1;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -070050 if (!(copy = (char *)cJSON_malloc(len))) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -070051 memcpy(copy, str, len);
52 return copy;
Jon Ashburn752e06e2015-06-29 11:25:34 -060053}
54
Jon Ashburn1c75aec2016-02-02 17:47:28 -070055void cJSON_InitHooks(cJSON_Hooks *hooks) {
Jon Ashburn752e06e2015-06-29 11:25:34 -060056 if (!hooks) { /* Reset hooks */
57 cJSON_malloc = malloc;
58 cJSON_free = free;
59 return;
60 }
61
Jon Ashburn1c75aec2016-02-02 17:47:28 -070062 cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc;
63 cJSON_free = (hooks->free_fn) ? hooks->free_fn : free;
Jon Ashburn752e06e2015-06-29 11:25:34 -060064}
65
66/* Internal constructor. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -070067static cJSON *cJSON_New_Item(void) {
68 cJSON *node = (cJSON *)cJSON_malloc(sizeof(cJSON));
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -070069 if (node) memset(node, 0, sizeof(cJSON));
Jon Ashburn1c75aec2016-02-02 17:47:28 -070070 return node;
Jon Ashburn752e06e2015-06-29 11:25:34 -060071}
72
73/* Delete a cJSON structure. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -070074void cJSON_Delete(cJSON *c) {
75 cJSON *next;
76 while (c) {
77 next = c->next;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -070078 if (!(c->type & cJSON_IsReference) && c->child) cJSON_Delete(c->child);
79 if (!(c->type & cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
80 if (!(c->type & cJSON_StringIsConst) && c->string) cJSON_free(c->string);
Jon Ashburn1c75aec2016-02-02 17:47:28 -070081 cJSON_free(c);
82 c = next;
83 }
Jon Ashburn752e06e2015-06-29 11:25:34 -060084}
85
Mark Lobodzinski91c10752017-01-26 12:16:30 -070086void cJSON_Free(void *p) { cJSON_free(p); }
Mark Young74dd5d12016-06-30 13:02:42 -060087
Jon Ashburn1c75aec2016-02-02 17:47:28 -070088/* Parse the input text to generate a number, and populate the result into item.
89 */
90static const char *parse_number(cJSON *item, const char *num) {
91 double n = 0, sign = 1, scale = 0;
92 int subscale = 0, signsubscale = 1;
Jon Ashburn752e06e2015-06-29 11:25:34 -060093
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -070094 if (*num == '-') sign = -1, num++; /* Has sign? */
95 if (*num == '0') num++; /* is zero */
96 if (*num >= '1' && *num <= '9') do
Jon Ashburn1c75aec2016-02-02 17:47:28 -070097 n = (n * 10.0) + (*num++ - '0');
98 while (*num >= '0' && *num <= '9'); /* Number? */
99 if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
100 num++;
101 do
102 n = (n * 10.0) + (*num++ - '0'), scale--;
103 while (*num >= '0' && *num <= '9');
104 } /* Fractional part? */
105 if (*num == 'e' || *num == 'E') /* Exponent? */
106 {
107 num++;
108 if (*num == '+')
109 num++;
110 else if (*num == '-')
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700111 signsubscale = -1, num++; /* With sign? */
112 while (*num >= '0' && *num <= '9') subscale = (subscale * 10) + (*num++ - '0'); /* Number? */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700113 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600114
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700115 n = sign * n * pow(10.0, (scale + subscale * signsubscale)); /* number = +/-
116 number.fraction *
117 10^+/- exponent */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700118
119 item->valuedouble = n;
120 item->valueint = (int)n;
121 item->type = cJSON_Number;
122 return num;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600123}
124
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700125static size_t pow2gt(size_t x) {
126 --x;
127 x |= x >> 1;
128 x |= x >> 2;
129 x |= x >> 4;
130 x |= x >> 8;
131 x |= x >> 16;
132 return x + 1;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600133}
134
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700135typedef struct {
136 char *buffer;
137 size_t length;
138 size_t offset;
139} printbuffer;
140
141static char *ensure(printbuffer *p, size_t needed) {
142 char *newbuffer;
143 size_t newsize;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700144 if (!p || !p->buffer) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700145 needed += p->offset;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700146 if (needed <= p->length) return p->buffer + p->offset;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700147
148 newsize = pow2gt(needed);
149 newbuffer = (char *)cJSON_malloc(newsize);
150 if (!newbuffer) {
151 cJSON_free(p->buffer);
152 p->length = 0, p->buffer = 0;
153 return 0;
154 }
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700155 if (newbuffer) memcpy(newbuffer, p->buffer, p->length);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700156 cJSON_free(p->buffer);
157 p->length = newsize;
158 p->buffer = newbuffer;
159 return newbuffer + p->offset;
160}
161
162static size_t update(printbuffer *p) {
163 char *str;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700164 if (!p || !p->buffer) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700165 str = p->buffer + p->offset;
166 return p->offset + strlen(str);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600167}
168
169/* Render the number nicely from the given item into a string. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700170static char *print_number(cJSON *item, printbuffer *p) {
171 char *str = 0;
172 double d = item->valuedouble;
173 if (d == 0) {
174 if (p)
175 str = ensure(p, 2);
176 else
177 str = (char *)cJSON_malloc(2); /* special case for 0. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700178 if (str) strcpy(str, "0");
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700179 } else if (fabs(((double)item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN) {
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700180 if (p)
181 str = ensure(p, 21);
182 else
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700183 str = (char *)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700184 if (str) sprintf(str, "%d", item->valueint);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700185 } else {
186 if (p)
187 str = ensure(p, 64);
188 else
189 str = (char *)cJSON_malloc(64); /* This is a nice tradeoff. */
190 if (str) {
191 if (fabs(floor(d) - d) <= DBL_EPSILON && fabs(d) < 1.0e60)
192 sprintf(str, "%.0f", d);
193 else if (fabs(d) < 1.0e-6 || fabs(d) > 1.0e9)
194 sprintf(str, "%e", d);
195 else
196 sprintf(str, "%f", d);
197 }
198 }
199 return str;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600200}
201
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700202static unsigned parse_hex4(const char *str) {
203 unsigned h = 0;
204 if (*str >= '0' && *str <= '9')
205 h += (*str) - '0';
206 else if (*str >= 'A' && *str <= 'F')
207 h += 10 + (*str) - 'A';
208 else if (*str >= 'a' && *str <= 'f')
209 h += 10 + (*str) - 'a';
210 else
211 return 0;
212 h = h << 4;
213 str++;
214 if (*str >= '0' && *str <= '9')
215 h += (*str) - '0';
216 else if (*str >= 'A' && *str <= 'F')
217 h += 10 + (*str) - 'A';
218 else if (*str >= 'a' && *str <= 'f')
219 h += 10 + (*str) - 'a';
220 else
221 return 0;
222 h = h << 4;
223 str++;
224 if (*str >= '0' && *str <= '9')
225 h += (*str) - '0';
226 else if (*str >= 'A' && *str <= 'F')
227 h += 10 + (*str) - 'A';
228 else if (*str >= 'a' && *str <= 'f')
229 h += 10 + (*str) - 'a';
230 else
231 return 0;
232 h = h << 4;
233 str++;
234 if (*str >= '0' && *str <= '9')
235 h += (*str) - '0';
236 else if (*str >= 'A' && *str <= 'F')
237 h += 10 + (*str) - 'A';
238 else if (*str >= 'a' && *str <= 'f')
239 h += 10 + (*str) - 'a';
240 else
241 return 0;
242 return h;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600243}
244
245/* Parse the input text into an unescaped cstring, and populate item. */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700246static const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700247static const char *parse_string(cJSON *item, const char *str) {
248 const char *ptr = str + 1;
249 char *ptr2;
250 char *out;
251 int len = 0;
252 unsigned uc, uc2;
253 if (*str != '\"') {
254 ep = str;
255 return 0;
256 } /* not a string! */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600257
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700258 while (*ptr != '\"' && *ptr && ++len)
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700259 if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600260
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700261 out = (char *)cJSON_malloc(len + 1); /* This is how long we need for the string, roughly. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700262 if (!out) return 0;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600263
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700264 ptr = str + 1;
265 ptr2 = out;
266 while (*ptr != '\"' && *ptr) {
267 if (*ptr != '\\')
268 *ptr2++ = *ptr++;
269 else {
270 ptr++;
271 switch (*ptr) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700272 case 'b':
273 *ptr2++ = '\b';
274 break;
275 case 'f':
276 *ptr2++ = '\f';
277 break;
278 case 'n':
279 *ptr2++ = '\n';
280 break;
281 case 'r':
282 *ptr2++ = '\r';
283 break;
284 case 't':
285 *ptr2++ = '\t';
286 break;
287 case 'u': /* transcode utf16 to utf8. */
288 uc = parse_hex4(ptr + 1);
289 ptr += 4; /* get the unicode char. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700290
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700291 if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) break; /* check for invalid. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700292
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700293 if (uc >= 0xD800 && uc <= 0xDBFF) /* UTF16 surrogate pairs. */
294 {
295 if (ptr[1] != '\\' || ptr[2] != 'u') break; /* missing second-half of surrogate. */
296 uc2 = parse_hex4(ptr + 3);
297 ptr += 6;
298 if (uc2 < 0xDC00 || uc2 > 0xDFFF) break; /* invalid second-half of surrogate. */
299 uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));
300 }
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700301
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700302 len = 4;
303 if (uc < 0x80)
304 len = 1;
305 else if (uc < 0x800)
306 len = 2;
307 else if (uc < 0x10000)
308 len = 3;
309 ptr2 += len;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700310
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700311 switch (len) {
312 case 4:
313 *--ptr2 = ((uc | 0x80) & 0xBF);
314 uc >>= 6;
Tobin Ehlisa60f4ed2018-04-17 10:05:20 -0600315 // fall through
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700316 case 3:
317 *--ptr2 = ((uc | 0x80) & 0xBF);
318 uc >>= 6;
Tobin Ehlisa60f4ed2018-04-17 10:05:20 -0600319 // fall through
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700320 case 2:
321 *--ptr2 = ((uc | 0x80) & 0xBF);
322 uc >>= 6;
Tobin Ehlisa60f4ed2018-04-17 10:05:20 -0600323 // fall through
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700324 case 1:
325 *--ptr2 = ((unsigned char)uc | firstByteMark[len]);
326 }
327 ptr2 += len;
328 break;
329 default:
330 *ptr2++ = *ptr;
331 break;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700332 }
333 ptr++;
334 }
335 }
336 *ptr2 = 0;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700337 if (*ptr == '\"') ptr++;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700338 item->valuestring = out;
339 item->type = cJSON_String;
340 return ptr;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600341}
342
343/* Render the cstring provided to an escaped version that can be printed. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700344static char *print_string_ptr(const char *str, printbuffer *p) {
345 const char *ptr;
346 char *ptr2;
347 char *out;
348 size_t len = 0, flag = 0;
349 unsigned char token;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600350
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700351 for (ptr = str; *ptr; ptr++) flag |= ((*ptr > 0 && *ptr < 32) || (*ptr == '\"') || (*ptr == '\\')) ? 1 : 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700352 if (!flag) {
353 len = ptr - str;
354 if (p)
355 out = ensure(p, len + 3);
356 else
357 out = (char *)cJSON_malloc(len + 3);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700358 if (!out) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700359 ptr2 = out;
360 *ptr2++ = '\"';
361 strcpy(ptr2, str);
362 ptr2[len] = '\"';
363 ptr2[len + 1] = 0;
364 return out;
365 }
366
367 if (!str) {
368 if (p)
369 out = ensure(p, 3);
370 else
371 out = (char *)cJSON_malloc(3);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700372 if (!out) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700373 strcpy(out, "\"\"");
374 return out;
375 }
376 ptr = str;
377 while ((token = *ptr) && ++len) {
378 if (strchr("\"\\\b\f\n\r\t", token))
379 len++;
380 else if (token < 32)
381 len += 5;
382 ptr++;
383 }
384
385 if (p)
386 out = ensure(p, len + 3);
387 else
388 out = (char *)cJSON_malloc(len + 3);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700389 if (!out) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700390
391 ptr2 = out;
392 ptr = str;
393 *ptr2++ = '\"';
394 while (*ptr) {
395 if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\')
396 *ptr2++ = *ptr++;
397 else {
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700398 switch (token = *ptr++) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700399 case '\\':
400 *ptr2++ = '\\';
401 break;
402 case '\"':
403 *ptr2++ = '\"';
404 break;
405 case '\b':
406 *ptr2++ = '\b';
407 break;
408 case '\f':
409 *ptr2++ = '\f';
410 break;
411 case '\n':
412 *ptr2++ = '\n';
413 break;
414 case '\r':
415 *ptr2++ = '\r';
416 break;
417 case '\t':
418 *ptr2++ = '\t';
419 break;
420 default:
421 sprintf(ptr2, "u%04x", token);
422 ptr2 += 5;
423 break; /* escape and print */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700424 }
425 }
426 }
427 *ptr2++ = '\"';
428 *ptr2++ = 0;
429 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600430}
431/* Invote print_string_ptr (which is useful) on an item. */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700432static char *print_string(cJSON *item, printbuffer *p) { return print_string_ptr(item->valuestring, p); }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600433
434/* Predeclare these prototypes. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700435static const char *parse_value(cJSON *item, const char *value);
436static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p);
437static const char *parse_array(cJSON *item, const char *value);
438static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p);
439static const char *parse_object(cJSON *item, const char *value);
440static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600441
442/* Utility to jump whitespace and cr/lf */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700443static const char *skip(const char *in) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700444 while (in && *in && (unsigned char)*in <= 32) in++;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700445 return in;
446}
Jon Ashburn752e06e2015-06-29 11:25:34 -0600447
448/* Parse an object - create a new root, and populate. */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700449cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated) {
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700450 const char *end = 0;
451 cJSON *c = cJSON_New_Item();
452 ep = 0;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700453 if (!c) return 0; /* memory fail */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600454
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700455 end = parse_value(c, skip(value));
456 if (!end) {
457 cJSON_Delete(c);
458 return 0;
459 } /* parse failure. ep is set. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600460
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700461 /* if we require null-terminated JSON without appended garbage, skip and
462 * then check for a null terminator */
463 if (require_null_terminated) {
464 end = skip(end);
465 if (*end) {
466 cJSON_Delete(c);
467 ep = end;
468 return 0;
469 }
470 }
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700471 if (return_parse_end) *return_parse_end = end;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700472 return c;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600473}
474/* Default options for cJSON_Parse */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700475cJSON *cJSON_Parse(const char *value) { return cJSON_ParseWithOpts(value, 0, 0); }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600476
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700477/* Render a cJSON item/entity/structure to text. */
478char *cJSON_Print(cJSON *item) { return print_value(item, 0, 1, 0); }
479char *cJSON_PrintUnformatted(cJSON *item) { return print_value(item, 0, 0, 0); }
480
481char *cJSON_PrintBuffered(cJSON *item, int prebuffer, int fmt) {
482 printbuffer p;
483 p.buffer = (char *)cJSON_malloc(prebuffer);
484 p.length = prebuffer;
485 p.offset = 0;
486 return print_value(item, 0, fmt, &p);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700487}
Jon Ashburn752e06e2015-06-29 11:25:34 -0600488
489/* Parser core - when encountering text, process appropriately. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700490static const char *parse_value(cJSON *item, const char *value) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700491 if (!value) return 0; /* Fail on null. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700492 if (!strncmp(value, "null", 4)) {
493 item->type = cJSON_NULL;
494 return value + 4;
495 }
496 if (!strncmp(value, "false", 5)) {
497 item->type = cJSON_False;
498 return value + 5;
499 }
500 if (!strncmp(value, "true", 4)) {
501 item->type = cJSON_True;
502 item->valueint = 1;
503 return value + 4;
504 }
505 if (*value == '\"') {
506 return parse_string(item, value);
507 }
508 if (*value == '-' || (*value >= '0' && *value <= '9')) {
509 return parse_number(item, value);
510 }
511 if (*value == '[') {
512 return parse_array(item, value);
513 }
514 if (*value == '{') {
515 return parse_object(item, value);
516 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600517
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700518 ep = value;
519 return 0; /* failure. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600520}
521
522/* Render a value to text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700523static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p) {
524 char *out = 0;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700525 if (!item) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700526 if (p) {
527 switch ((item->type) & 255) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700528 case cJSON_NULL: {
529 out = ensure(p, 5);
530 if (out) strcpy(out, "null");
531 break;
532 }
533 case cJSON_False: {
534 out = ensure(p, 6);
535 if (out) strcpy(out, "false");
536 break;
537 }
538 case cJSON_True: {
539 out = ensure(p, 5);
540 if (out) strcpy(out, "true");
541 break;
542 }
543 case cJSON_Number:
544 out = print_number(item, p);
545 break;
546 case cJSON_String:
547 out = print_string(item, p);
548 break;
549 case cJSON_Array:
550 out = print_array(item, depth, fmt, p);
551 break;
552 case cJSON_Object:
553 out = print_object(item, depth, fmt, p);
554 break;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700555 }
556 } else {
557 switch ((item->type) & 255) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700558 case cJSON_NULL:
559 out = cJSON_strdup("null");
560 break;
561 case cJSON_False:
562 out = cJSON_strdup("false");
563 break;
564 case cJSON_True:
565 out = cJSON_strdup("true");
566 break;
567 case cJSON_Number:
568 out = print_number(item, 0);
569 break;
570 case cJSON_String:
571 out = print_string(item, 0);
572 break;
573 case cJSON_Array:
574 out = print_array(item, depth, fmt, 0);
575 break;
576 case cJSON_Object:
577 out = print_object(item, depth, fmt, 0);
578 break;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700579 }
580 }
581 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600582}
583
584/* Build an array from input text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700585static const char *parse_array(cJSON *item, const char *value) {
586 cJSON *child;
587 if (*value != '[') {
588 ep = value;
589 return 0;
590 } /* not an array! */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600591
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700592 item->type = cJSON_Array;
593 value = skip(value + 1);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700594 if (*value == ']') return value + 1; /* empty array. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600595
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700596 item->child = child = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700597 if (!item->child) return 0; /* memory fail */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700598 value = skip(parse_value(child, skip(value))); /* skip any spacing, get the value. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700599 if (!value) return 0;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600600
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700601 while (*value == ',') {
602 cJSON *new_item;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700603 if (!(new_item = cJSON_New_Item())) return 0; /* memory fail */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700604 child->next = new_item;
605 new_item->prev = child;
606 child = new_item;
607 value = skip(parse_value(child, skip(value + 1)));
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700608 if (!value) return 0; /* memory fail */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700609 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600610
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700611 if (*value == ']') return value + 1; /* end of array */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700612 ep = value;
613 return 0; /* malformed. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600614}
615
616/* Render an array to text */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700617static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p) {
618 char **entries;
619 char *out = 0, *ptr, *ret;
620 size_t len = 5;
621 cJSON *child = item->child;
622 int numentries = 0, fail = 0, j = 0;
623 size_t tmplen = 0, i = 0;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600624
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700625 /* How many entries in the array? */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700626 while (child) numentries++, child = child->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700627 /* Explicitly handle numentries==0 */
628 if (!numentries) {
629 if (p)
630 out = ensure(p, 3);
631 else
632 out = (char *)cJSON_malloc(3);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700633 if (out) strcpy(out, "[]");
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700634 return out;
635 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600636
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700637 if (p) {
638 /* Compose the output array. */
639 i = p->offset;
640 ptr = ensure(p, 1);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700641 if (!ptr) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700642 *ptr = '[';
643 p->offset++;
644 child = item->child;
645 while (child && !fail) {
646 print_value(child, depth + 1, fmt, p);
647 p->offset = update(p);
648 if (child->next) {
649 len = fmt ? 2 : 1;
650 ptr = ensure(p, len + 1);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700651 if (!ptr) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700652 *ptr++ = ',';
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700653 if (fmt) *ptr++ = ' ';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700654 *ptr = 0;
655 p->offset += len;
656 }
657 child = child->next;
658 }
659 ptr = ensure(p, 2);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700660 if (!ptr) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700661 *ptr++ = ']';
662 *ptr = 0;
663 out = (p->buffer) + i;
664 } else {
665 /* Allocate an array to hold the values for each */
666 entries = (char **)cJSON_malloc(numentries * sizeof(char *));
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700667 if (!entries) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700668 memset(entries, 0, numentries * sizeof(char *));
669 /* Retrieve all the results: */
670 child = item->child;
671 while (child && !fail) {
672 ret = print_value(child, depth + 1, fmt, 0);
673 entries[i++] = ret;
674 if (ret)
675 len += strlen(ret) + 2 + (fmt ? 1 : 0);
676 else
677 fail = 1;
678 child = child->next;
679 }
680
681 /* If we didn't fail, try to malloc the output string */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700682 if (!fail) out = (char *)cJSON_malloc(len);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700683 /* If that fails, we fail. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700684 if (!out) fail = 1;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700685
686 /* Handle failure. */
687 if (fail) {
688 for (j = 0; j < numentries; j++)
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700689 if (entries[j]) cJSON_free(entries[j]);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700690 cJSON_free(entries);
691 return 0;
692 }
693
694 /* Compose the output array. */
695 *out = '[';
696 ptr = out + 1;
697 *ptr = 0;
698 for (j = 0; j < numentries; j++) {
699 tmplen = strlen(entries[j]);
700 memcpy(ptr, entries[j], tmplen);
701 ptr += tmplen;
702 if (j != numentries - 1) {
703 *ptr++ = ',';
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700704 if (fmt) *ptr++ = ' ';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700705 *ptr = 0;
706 }
707 cJSON_free(entries[j]);
708 }
709 cJSON_free(entries);
710 *ptr++ = ']';
711 *ptr++ = 0;
712 }
713 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600714}
715
716/* Build an object from the text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700717static const char *parse_object(cJSON *item, const char *value) {
718 cJSON *child;
719 if (*value != '{') {
720 ep = value;
721 return 0;
722 } /* not an object! */
723
724 item->type = cJSON_Object;
725 value = skip(value + 1);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700726 if (*value == '}') return value + 1; /* empty array. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700727
728 item->child = child = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700729 if (!item->child) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700730 value = skip(parse_string(child, skip(value)));
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700731 if (!value) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700732 child->string = child->valuestring;
733 child->valuestring = 0;
734 if (*value != ':') {
735 ep = value;
736 return 0;
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700737 } /* fail! */
738 value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700739 if (!value) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700740
741 while (*value == ',') {
742 cJSON *new_item;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700743 if (!(new_item = cJSON_New_Item())) return 0; /* memory fail */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700744 child->next = new_item;
745 new_item->prev = child;
746 child = new_item;
747 value = skip(parse_string(child, skip(value + 1)));
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700748 if (!value) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700749 child->string = child->valuestring;
750 child->valuestring = 0;
751 if (*value != ':') {
752 ep = value;
753 return 0;
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700754 } /* fail! */
755 value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700756 if (!value) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700757 }
758
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700759 if (*value == '}') return value + 1; /* end of array */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700760 ep = value;
761 return 0; /* malformed. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600762}
763
764/* Render an object to text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700765static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p) {
766 char **entries = 0, **names = 0;
767 char *out = 0, *ptr, *ret, *str;
768 int j;
769 cJSON *child = item->child;
770 int numentries = 0, fail = 0, k;
771 size_t tmplen = 0, i = 0, len = 7;
772 /* Count the number of entries. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700773 while (child) numentries++, child = child->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700774 /* Explicitly handle empty object case */
775 if (!numentries) {
776 if (p)
777 out = ensure(p, fmt ? depth + 4 : 3);
778 else
779 out = (char *)cJSON_malloc(fmt ? depth + 4 : 3);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700780 if (!out) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700781 ptr = out;
782 *ptr++ = '{';
783 if (fmt) {
784 *ptr++ = '\n';
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700785 for (j = 0; j < depth - 1; j++) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700786 }
787 *ptr++ = '}';
788 *ptr++ = 0;
789 return out;
790 }
791 if (p) {
792 /* Compose the output: */
793 i = p->offset;
794 len = fmt ? 2 : 1;
795 ptr = ensure(p, len + 1);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700796 if (!ptr) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700797 *ptr++ = '{';
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700798 if (fmt) *ptr++ = '\n';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700799 *ptr = 0;
800 p->offset += len;
801 child = item->child;
802 depth++;
803 while (child) {
804 if (fmt) {
805 ptr = ensure(p, depth);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700806 if (!ptr) return 0;
807 for (j = 0; j < depth; j++) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700808 p->offset += depth;
809 }
810 print_string_ptr(child->string, p);
811 p->offset = update(p);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600812
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700813 len = fmt ? 2 : 1;
814 ptr = ensure(p, len);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700815 if (!ptr) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700816 *ptr++ = ':';
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700817 if (fmt) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700818 p->offset += len;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600819
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700820 print_value(child, depth, fmt, p);
821 p->offset = update(p);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600822
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700823 len = (fmt ? 1 : 0) + (child->next ? 1 : 0);
824 ptr = ensure(p, len + 1);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700825 if (!ptr) return 0;
826 if (child->next) *ptr++ = ',';
827 if (fmt) *ptr++ = '\n';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700828 *ptr = 0;
829 p->offset += len;
830 child = child->next;
831 }
832 ptr = ensure(p, fmt ? (depth + 1) : 2);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700833 if (!ptr) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700834 if (fmt)
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700835 for (j = 0; j < depth - 1; j++) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700836 *ptr++ = '}';
837 *ptr = 0;
838 out = (p->buffer) + i;
839 } else {
840 /* Allocate space for the names and the objects */
841 entries = (char **)cJSON_malloc(numentries * sizeof(char *));
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700842 if (!entries) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700843 names = (char **)cJSON_malloc(numentries * sizeof(char *));
844 if (!names) {
845 cJSON_free(entries);
846 return 0;
847 }
848 memset(entries, 0, sizeof(char *) * numentries);
849 memset(names, 0, sizeof(char *) * numentries);
850
851 /* Collect all the results into our arrays: */
852 child = item->child;
853 depth++;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700854 if (fmt) len += depth;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700855 while (child) {
856 names[i] = str = print_string_ptr(child->string, 0);
857 entries[i++] = ret = print_value(child, depth, fmt, 0);
858 if (str && ret)
859 len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0);
860 else
861 fail = 1;
862 child = child->next;
863 }
864
865 /* Try to allocate the output string */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700866 if (!fail) out = (char *)cJSON_malloc(len);
867 if (!out) fail = 1;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700868
869 /* Handle failure */
870 if (fail) {
871 for (j = 0; j < numentries; j++) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700872 if (names[i]) cJSON_free(names[j]);
873 if (entries[j]) cJSON_free(entries[j]);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700874 }
875 cJSON_free(names);
876 cJSON_free(entries);
877 return 0;
878 }
879
880 /* Compose the output: */
881 *out = '{';
882 ptr = out + 1;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700883 if (fmt) *ptr++ = '\n';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700884 *ptr = 0;
885 for (j = 0; j < numentries; j++) {
886 if (fmt)
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700887 for (k = 0; k < depth; k++) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700888 tmplen = strlen(names[j]);
889 memcpy(ptr, names[j], tmplen);
890 ptr += tmplen;
891 *ptr++ = ':';
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700892 if (fmt) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700893 strcpy(ptr, entries[j]);
894 ptr += strlen(entries[j]);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700895 if (j != numentries - 1) *ptr++ = ',';
896 if (fmt) *ptr++ = '\n';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700897 *ptr = 0;
898 cJSON_free(names[j]);
899 cJSON_free(entries[j]);
900 }
901
902 cJSON_free(names);
903 cJSON_free(entries);
904 if (fmt)
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700905 for (j = 0; j < depth - 1; j++) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700906 *ptr++ = '}';
907 *ptr++ = 0;
908 }
909 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600910}
911
912/* Get Array size/item / object item. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700913int cJSON_GetArraySize(cJSON *array) {
914 cJSON *c = array->child;
915 int i = 0;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700916 while (c) i++, c = c->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700917 return i;
918}
919cJSON *cJSON_GetArrayItem(cJSON *array, int item) {
920 cJSON *c = array->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700921 while (c && item > 0) item--, c = c->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700922 return c;
923}
924cJSON *cJSON_GetObjectItem(cJSON *object, const char *string) {
925 cJSON *c = object->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700926 while (c && strcmp(c->string, string)) c = c->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700927 return c;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600928}
929
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700930/* Utility for array list handling. */
931static void suffix_object(cJSON *prev, cJSON *item) {
932 prev->next = item;
933 item->prev = prev;
934}
935/* Utility for handling references. */
936static cJSON *create_reference(cJSON *item) {
937 cJSON *ref = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700938 if (!ref) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700939 memcpy(ref, item, sizeof(cJSON));
940 ref->string = 0;
941 ref->type |= cJSON_IsReference;
942 ref->next = ref->prev = 0;
943 return ref;
944}
945
946/* Add item to array/object. */
947void cJSON_AddItemToArray(cJSON *array, cJSON *item) {
948 cJSON *c = array->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700949 if (!item) return;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700950 if (!c) {
951 array->child = item;
952 } else {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700953 while (c && c->next) c = c->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700954 suffix_object(c, item);
955 }
956}
957void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700958 if (!item) return;
959 if (item->string) cJSON_free(item->string);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700960 item->string = cJSON_strdup(string);
961 cJSON_AddItemToArray(object, item);
962}
963void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700964 if (!item) return;
965 if (!(item->type & cJSON_StringIsConst) && item->string) cJSON_free(item->string);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700966 item->string = (char *)string;
967 item->type |= cJSON_StringIsConst;
968 cJSON_AddItemToArray(object, item);
969}
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700970void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) { cJSON_AddItemToArray(array, create_reference(item)); }
971void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) {
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700972 cJSON_AddItemToObject(object, string, create_reference(item));
973}
974
975cJSON *cJSON_DetachItemFromArray(cJSON *array, int which) {
976 cJSON *c = array->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700977 while (c && which > 0) c = c->next, which--;
978 if (!c) return 0;
979 if (c->prev) c->prev->next = c->next;
980 if (c->next) c->next->prev = c->prev;
981 if (c == array->child) array->child = c->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700982 c->prev = c->next = 0;
983 return c;
984}
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700985void cJSON_DeleteItemFromArray(cJSON *array, int which) { cJSON_Delete(cJSON_DetachItemFromArray(array, which)); }
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700986cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string) {
987 int i = 0;
988 cJSON *c = object->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700989 while (c && strcmp(c->string, string)) i++, c = c->next;
990 if (c) return cJSON_DetachItemFromArray(object, i);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700991 return 0;
992}
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700993void cJSON_DeleteItemFromObject(cJSON *object, const char *string) { cJSON_Delete(cJSON_DetachItemFromObject(object, string)); }
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700994
995/* Replace array/object items with new ones. */
996void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) {
997 cJSON *c = array->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700998 while (c && which > 0) c = c->next, which--;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700999 if (!c) {
1000 cJSON_AddItemToArray(array, newitem);
1001 return;
1002 }
1003 newitem->next = c;
1004 newitem->prev = c->prev;
1005 c->prev = newitem;
1006 if (c == array->child)
1007 array->child = newitem;
1008 else
1009 newitem->prev->next = newitem;
1010}
1011void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) {
1012 cJSON *c = array->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001013 while (c && which > 0) c = c->next, which--;
1014 if (!c) return;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001015 newitem->next = c->next;
1016 newitem->prev = c->prev;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001017 if (newitem->next) newitem->next->prev = newitem;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001018 if (c == array->child)
1019 array->child = newitem;
1020 else
1021 newitem->prev->next = newitem;
1022 c->next = c->prev = 0;
1023 cJSON_Delete(c);
1024}
Mark Lobodzinski91c10752017-01-26 12:16:30 -07001025void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) {
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001026 int i = 0;
1027 cJSON *c = object->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001028 while (c && strcmp(c->string, string)) i++, c = c->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001029 if (c) {
1030 newitem->string = cJSON_strdup(string);
1031 cJSON_ReplaceItemInArray(object, i, newitem);
1032 }
1033}
1034
1035/* Create basic types: */
1036cJSON *cJSON_CreateNull(void) {
1037 cJSON *item = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001038 if (item) item->type = cJSON_NULL;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001039 return item;
1040}
1041cJSON *cJSON_CreateTrue(void) {
1042 cJSON *item = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001043 if (item) item->type = cJSON_True;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001044 return item;
1045}
1046cJSON *cJSON_CreateFalse(void) {
1047 cJSON *item = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001048 if (item) item->type = cJSON_False;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001049 return item;
1050}
1051cJSON *cJSON_CreateBool(int b) {
1052 cJSON *item = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001053 if (item) item->type = b ? cJSON_True : cJSON_False;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001054 return item;
1055}
1056cJSON *cJSON_CreateNumber(double num) {
1057 cJSON *item = cJSON_New_Item();
1058 if (item) {
1059 item->type = cJSON_Number;
1060 item->valuedouble = num;
1061 item->valueint = (int)num;
1062 }
1063 return item;
1064}
1065cJSON *cJSON_CreateString(const char *string) {
1066 cJSON *item = cJSON_New_Item();
1067 if (item) {
1068 item->type = cJSON_String;
1069 item->valuestring = cJSON_strdup(string);
1070 }
1071 return item;
1072}
1073cJSON *cJSON_CreateArray(void) {
1074 cJSON *item = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001075 if (item) item->type = cJSON_Array;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001076 return item;
1077}
1078cJSON *cJSON_CreateObject(void) {
1079 cJSON *item = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001080 if (item) item->type = cJSON_Object;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001081 return item;
1082}
1083
1084/* Create Arrays: */
1085cJSON *cJSON_CreateIntArray(const int *numbers, int count) {
1086 int i;
1087 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1088 for (i = 0; a && i < count; i++) {
1089 n = cJSON_CreateNumber(numbers[i]);
1090 if (!i)
1091 a->child = n;
1092 else
1093 suffix_object(p, n);
1094 p = n;
1095 }
1096 return a;
1097}
1098cJSON *cJSON_CreateFloatArray(const float *numbers, int count) {
1099 int i;
1100 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1101 for (i = 0; a && i < count; i++) {
1102 n = cJSON_CreateNumber(numbers[i]);
1103 if (!i)
1104 a->child = n;
1105 else
1106 suffix_object(p, n);
1107 p = n;
1108 }
1109 return a;
1110}
1111cJSON *cJSON_CreateDoubleArray(const double *numbers, int count) {
1112 int i;
1113 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1114 for (i = 0; a && i < count; i++) {
1115 n = cJSON_CreateNumber(numbers[i]);
1116 if (!i)
1117 a->child = n;
1118 else
1119 suffix_object(p, n);
1120 p = n;
1121 }
1122 return a;
1123}
1124cJSON *cJSON_CreateStringArray(const char **strings, int count) {
1125 int i;
1126 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1127 for (i = 0; a && i < count; i++) {
1128 n = cJSON_CreateString(strings[i]);
1129 if (!i)
1130 a->child = n;
1131 else
1132 suffix_object(p, n);
1133 p = n;
1134 }
1135 return a;
1136}
1137
1138/* Duplication */
1139cJSON *cJSON_Duplicate(cJSON *item, int recurse) {
1140 cJSON *newitem, *cptr, *nptr = 0, *newchild;
1141 /* Bail on bad ptr */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001142 if (!item) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001143 /* Create new item */
1144 newitem = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001145 if (!newitem) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001146 /* Copy over all vars */
Mark Lobodzinski91c10752017-01-26 12:16:30 -07001147 newitem->type = item->type & (~cJSON_IsReference), newitem->valueint = item->valueint, newitem->valuedouble = item->valuedouble;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001148 if (item->valuestring) {
1149 newitem->valuestring = cJSON_strdup(item->valuestring);
1150 if (!newitem->valuestring) {
1151 cJSON_Delete(newitem);
1152 return 0;
1153 }
1154 }
1155 if (item->string) {
1156 newitem->string = cJSON_strdup(item->string);
1157 if (!newitem->string) {
1158 cJSON_Delete(newitem);
1159 return 0;
1160 }
1161 }
1162 /* If non-recursive, then we're done! */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001163 if (!recurse) return newitem;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001164 /* Walk the ->next chain for the child. */
1165 cptr = item->child;
1166 while (cptr) {
Mark Lobodzinski91c10752017-01-26 12:16:30 -07001167 newchild = cJSON_Duplicate(cptr, 1); /* Duplicate (with recurse) each item in the ->next chain */
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001168 if (!newchild) {
1169 cJSON_Delete(newitem);
1170 return 0;
1171 }
1172 if (nptr) {
1173 nptr->next = newchild, newchild->prev = nptr;
1174 nptr = newchild;
1175 } /* If newitem->child already set, then crosswire ->prev and ->next and
1176 move on */
1177 else {
1178 newitem->child = newchild;
1179 nptr = newchild;
1180 } /* Set newitem->child and move to it */
1181 cptr = cptr->next;
1182 }
1183 return newitem;
1184}
1185
1186void cJSON_Minify(char *json) {
1187 char *into = json;
1188 while (*json) {
1189 if (*json == ' ')
1190 json++;
1191 else if (*json == '\t')
1192 json++; /* Whitespace characters. */
1193 else if (*json == '\r')
1194 json++;
1195 else if (*json == '\n')
1196 json++;
1197 else if (*json == '/' && json[1] == '/')
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001198 while (*json && *json != '\n') json++; /* double-slash comments, to end of line. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001199 else if (*json == '/' && json[1] == '*') {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001200 while (*json && !(*json == '*' && json[1] == '/')) json++;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001201 json += 2;
1202 } /* multiline comments. */
1203 else if (*json == '\"') {
1204 *into++ = *json++;
1205 while (*json && *json != '\"') {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001206 if (*json == '\\') *into++ = *json++;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001207 *into++ = *json++;
1208 }
1209 *into++ = *json++;
1210 } /* string literals, which are \" sensitive. */
1211 else
1212 *into++ = *json++; /* All other characters. */
1213 }
1214 *into = 0; /* and null-terminate. */
Jon Ashburn752e06e2015-06-29 11:25:34 -06001215}