blob: a7671c4a0097c2a6b45072175cb8c186b7d5b1d0 [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;
315 case 3:
316 *--ptr2 = ((uc | 0x80) & 0xBF);
317 uc >>= 6;
318 case 2:
319 *--ptr2 = ((uc | 0x80) & 0xBF);
320 uc >>= 6;
321 case 1:
322 *--ptr2 = ((unsigned char)uc | firstByteMark[len]);
323 }
324 ptr2 += len;
325 break;
326 default:
327 *ptr2++ = *ptr;
328 break;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700329 }
330 ptr++;
331 }
332 }
333 *ptr2 = 0;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700334 if (*ptr == '\"') ptr++;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700335 item->valuestring = out;
336 item->type = cJSON_String;
337 return ptr;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600338}
339
340/* Render the cstring provided to an escaped version that can be printed. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700341static char *print_string_ptr(const char *str, printbuffer *p) {
342 const char *ptr;
343 char *ptr2;
344 char *out;
345 size_t len = 0, flag = 0;
346 unsigned char token;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600347
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700348 for (ptr = str; *ptr; ptr++) flag |= ((*ptr > 0 && *ptr < 32) || (*ptr == '\"') || (*ptr == '\\')) ? 1 : 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700349 if (!flag) {
350 len = ptr - str;
351 if (p)
352 out = ensure(p, len + 3);
353 else
354 out = (char *)cJSON_malloc(len + 3);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700355 if (!out) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700356 ptr2 = out;
357 *ptr2++ = '\"';
358 strcpy(ptr2, str);
359 ptr2[len] = '\"';
360 ptr2[len + 1] = 0;
361 return out;
362 }
363
364 if (!str) {
365 if (p)
366 out = ensure(p, 3);
367 else
368 out = (char *)cJSON_malloc(3);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700369 if (!out) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700370 strcpy(out, "\"\"");
371 return out;
372 }
373 ptr = str;
374 while ((token = *ptr) && ++len) {
375 if (strchr("\"\\\b\f\n\r\t", token))
376 len++;
377 else if (token < 32)
378 len += 5;
379 ptr++;
380 }
381
382 if (p)
383 out = ensure(p, len + 3);
384 else
385 out = (char *)cJSON_malloc(len + 3);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700386 if (!out) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700387
388 ptr2 = out;
389 ptr = str;
390 *ptr2++ = '\"';
391 while (*ptr) {
392 if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\')
393 *ptr2++ = *ptr++;
394 else {
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700395 switch (token = *ptr++) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700396 case '\\':
397 *ptr2++ = '\\';
398 break;
399 case '\"':
400 *ptr2++ = '\"';
401 break;
402 case '\b':
403 *ptr2++ = '\b';
404 break;
405 case '\f':
406 *ptr2++ = '\f';
407 break;
408 case '\n':
409 *ptr2++ = '\n';
410 break;
411 case '\r':
412 *ptr2++ = '\r';
413 break;
414 case '\t':
415 *ptr2++ = '\t';
416 break;
417 default:
418 sprintf(ptr2, "u%04x", token);
419 ptr2 += 5;
420 break; /* escape and print */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700421 }
422 }
423 }
424 *ptr2++ = '\"';
425 *ptr2++ = 0;
426 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600427}
428/* Invote print_string_ptr (which is useful) on an item. */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700429static char *print_string(cJSON *item, printbuffer *p) { return print_string_ptr(item->valuestring, p); }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600430
431/* Predeclare these prototypes. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700432static const char *parse_value(cJSON *item, const char *value);
433static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p);
434static const char *parse_array(cJSON *item, const char *value);
435static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p);
436static const char *parse_object(cJSON *item, const char *value);
437static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600438
439/* Utility to jump whitespace and cr/lf */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700440static const char *skip(const char *in) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700441 while (in && *in && (unsigned char)*in <= 32) in++;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700442 return in;
443}
Jon Ashburn752e06e2015-06-29 11:25:34 -0600444
445/* Parse an object - create a new root, and populate. */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700446cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated) {
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700447 const char *end = 0;
448 cJSON *c = cJSON_New_Item();
449 ep = 0;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700450 if (!c) return 0; /* memory fail */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600451
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700452 end = parse_value(c, skip(value));
453 if (!end) {
454 cJSON_Delete(c);
455 return 0;
456 } /* parse failure. ep is set. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600457
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700458 /* if we require null-terminated JSON without appended garbage, skip and
459 * then check for a null terminator */
460 if (require_null_terminated) {
461 end = skip(end);
462 if (*end) {
463 cJSON_Delete(c);
464 ep = end;
465 return 0;
466 }
467 }
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700468 if (return_parse_end) *return_parse_end = end;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700469 return c;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600470}
471/* Default options for cJSON_Parse */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700472cJSON *cJSON_Parse(const char *value) { return cJSON_ParseWithOpts(value, 0, 0); }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600473
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700474/* Render a cJSON item/entity/structure to text. */
475char *cJSON_Print(cJSON *item) { return print_value(item, 0, 1, 0); }
476char *cJSON_PrintUnformatted(cJSON *item) { return print_value(item, 0, 0, 0); }
477
478char *cJSON_PrintBuffered(cJSON *item, int prebuffer, int fmt) {
479 printbuffer p;
480 p.buffer = (char *)cJSON_malloc(prebuffer);
481 p.length = prebuffer;
482 p.offset = 0;
483 return print_value(item, 0, fmt, &p);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700484}
Jon Ashburn752e06e2015-06-29 11:25:34 -0600485
486/* Parser core - when encountering text, process appropriately. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700487static const char *parse_value(cJSON *item, const char *value) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700488 if (!value) return 0; /* Fail on null. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700489 if (!strncmp(value, "null", 4)) {
490 item->type = cJSON_NULL;
491 return value + 4;
492 }
493 if (!strncmp(value, "false", 5)) {
494 item->type = cJSON_False;
495 return value + 5;
496 }
497 if (!strncmp(value, "true", 4)) {
498 item->type = cJSON_True;
499 item->valueint = 1;
500 return value + 4;
501 }
502 if (*value == '\"') {
503 return parse_string(item, value);
504 }
505 if (*value == '-' || (*value >= '0' && *value <= '9')) {
506 return parse_number(item, value);
507 }
508 if (*value == '[') {
509 return parse_array(item, value);
510 }
511 if (*value == '{') {
512 return parse_object(item, value);
513 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600514
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700515 ep = value;
516 return 0; /* failure. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600517}
518
519/* Render a value to text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700520static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p) {
521 char *out = 0;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700522 if (!item) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700523 if (p) {
524 switch ((item->type) & 255) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700525 case cJSON_NULL: {
526 out = ensure(p, 5);
527 if (out) strcpy(out, "null");
528 break;
529 }
530 case cJSON_False: {
531 out = ensure(p, 6);
532 if (out) strcpy(out, "false");
533 break;
534 }
535 case cJSON_True: {
536 out = ensure(p, 5);
537 if (out) strcpy(out, "true");
538 break;
539 }
540 case cJSON_Number:
541 out = print_number(item, p);
542 break;
543 case cJSON_String:
544 out = print_string(item, p);
545 break;
546 case cJSON_Array:
547 out = print_array(item, depth, fmt, p);
548 break;
549 case cJSON_Object:
550 out = print_object(item, depth, fmt, p);
551 break;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700552 }
553 } else {
554 switch ((item->type) & 255) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700555 case cJSON_NULL:
556 out = cJSON_strdup("null");
557 break;
558 case cJSON_False:
559 out = cJSON_strdup("false");
560 break;
561 case cJSON_True:
562 out = cJSON_strdup("true");
563 break;
564 case cJSON_Number:
565 out = print_number(item, 0);
566 break;
567 case cJSON_String:
568 out = print_string(item, 0);
569 break;
570 case cJSON_Array:
571 out = print_array(item, depth, fmt, 0);
572 break;
573 case cJSON_Object:
574 out = print_object(item, depth, fmt, 0);
575 break;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700576 }
577 }
578 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600579}
580
581/* Build an array from input text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700582static const char *parse_array(cJSON *item, const char *value) {
583 cJSON *child;
584 if (*value != '[') {
585 ep = value;
586 return 0;
587 } /* not an array! */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600588
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700589 item->type = cJSON_Array;
590 value = skip(value + 1);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700591 if (*value == ']') return value + 1; /* empty array. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600592
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700593 item->child = child = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700594 if (!item->child) return 0; /* memory fail */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700595 value = skip(parse_value(child, skip(value))); /* skip any spacing, get the value. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700596 if (!value) return 0;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600597
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700598 while (*value == ',') {
599 cJSON *new_item;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700600 if (!(new_item = cJSON_New_Item())) return 0; /* memory fail */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700601 child->next = new_item;
602 new_item->prev = child;
603 child = new_item;
604 value = skip(parse_value(child, skip(value + 1)));
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700605 if (!value) return 0; /* memory fail */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700606 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600607
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700608 if (*value == ']') return value + 1; /* end of array */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700609 ep = value;
610 return 0; /* malformed. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600611}
612
613/* Render an array to text */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700614static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p) {
615 char **entries;
616 char *out = 0, *ptr, *ret;
617 size_t len = 5;
618 cJSON *child = item->child;
619 int numentries = 0, fail = 0, j = 0;
620 size_t tmplen = 0, i = 0;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600621
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700622 /* How many entries in the array? */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700623 while (child) numentries++, child = child->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700624 /* Explicitly handle numentries==0 */
625 if (!numentries) {
626 if (p)
627 out = ensure(p, 3);
628 else
629 out = (char *)cJSON_malloc(3);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700630 if (out) strcpy(out, "[]");
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700631 return out;
632 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600633
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700634 if (p) {
635 /* Compose the output array. */
636 i = p->offset;
637 ptr = ensure(p, 1);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700638 if (!ptr) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700639 *ptr = '[';
640 p->offset++;
641 child = item->child;
642 while (child && !fail) {
643 print_value(child, depth + 1, fmt, p);
644 p->offset = update(p);
645 if (child->next) {
646 len = fmt ? 2 : 1;
647 ptr = ensure(p, len + 1);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700648 if (!ptr) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700649 *ptr++ = ',';
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700650 if (fmt) *ptr++ = ' ';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700651 *ptr = 0;
652 p->offset += len;
653 }
654 child = child->next;
655 }
656 ptr = ensure(p, 2);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700657 if (!ptr) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700658 *ptr++ = ']';
659 *ptr = 0;
660 out = (p->buffer) + i;
661 } else {
662 /* Allocate an array to hold the values for each */
663 entries = (char **)cJSON_malloc(numentries * sizeof(char *));
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700664 if (!entries) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700665 memset(entries, 0, numentries * sizeof(char *));
666 /* Retrieve all the results: */
667 child = item->child;
668 while (child && !fail) {
669 ret = print_value(child, depth + 1, fmt, 0);
670 entries[i++] = ret;
671 if (ret)
672 len += strlen(ret) + 2 + (fmt ? 1 : 0);
673 else
674 fail = 1;
675 child = child->next;
676 }
677
678 /* If we didn't fail, try to malloc the output string */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700679 if (!fail) out = (char *)cJSON_malloc(len);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700680 /* If that fails, we fail. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700681 if (!out) fail = 1;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700682
683 /* Handle failure. */
684 if (fail) {
685 for (j = 0; j < numentries; j++)
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700686 if (entries[j]) cJSON_free(entries[j]);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700687 cJSON_free(entries);
688 return 0;
689 }
690
691 /* Compose the output array. */
692 *out = '[';
693 ptr = out + 1;
694 *ptr = 0;
695 for (j = 0; j < numentries; j++) {
696 tmplen = strlen(entries[j]);
697 memcpy(ptr, entries[j], tmplen);
698 ptr += tmplen;
699 if (j != numentries - 1) {
700 *ptr++ = ',';
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700701 if (fmt) *ptr++ = ' ';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700702 *ptr = 0;
703 }
704 cJSON_free(entries[j]);
705 }
706 cJSON_free(entries);
707 *ptr++ = ']';
708 *ptr++ = 0;
709 }
710 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600711}
712
713/* Build an object from the text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700714static const char *parse_object(cJSON *item, const char *value) {
715 cJSON *child;
716 if (*value != '{') {
717 ep = value;
718 return 0;
719 } /* not an object! */
720
721 item->type = cJSON_Object;
722 value = skip(value + 1);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700723 if (*value == '}') return value + 1; /* empty array. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700724
725 item->child = child = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700726 if (!item->child) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700727 value = skip(parse_string(child, skip(value)));
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700728 if (!value) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700729 child->string = child->valuestring;
730 child->valuestring = 0;
731 if (*value != ':') {
732 ep = value;
733 return 0;
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700734 } /* fail! */
735 value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700736 if (!value) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700737
738 while (*value == ',') {
739 cJSON *new_item;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700740 if (!(new_item = cJSON_New_Item())) return 0; /* memory fail */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700741 child->next = new_item;
742 new_item->prev = child;
743 child = new_item;
744 value = skip(parse_string(child, skip(value + 1)));
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700745 if (!value) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700746 child->string = child->valuestring;
747 child->valuestring = 0;
748 if (*value != ':') {
749 ep = value;
750 return 0;
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700751 } /* fail! */
752 value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700753 if (!value) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700754 }
755
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700756 if (*value == '}') return value + 1; /* end of array */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700757 ep = value;
758 return 0; /* malformed. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600759}
760
761/* Render an object to text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700762static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p) {
763 char **entries = 0, **names = 0;
764 char *out = 0, *ptr, *ret, *str;
765 int j;
766 cJSON *child = item->child;
767 int numentries = 0, fail = 0, k;
768 size_t tmplen = 0, i = 0, len = 7;
769 /* Count the number of entries. */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700770 while (child) numentries++, child = child->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700771 /* Explicitly handle empty object case */
772 if (!numentries) {
773 if (p)
774 out = ensure(p, fmt ? depth + 4 : 3);
775 else
776 out = (char *)cJSON_malloc(fmt ? depth + 4 : 3);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700777 if (!out) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700778 ptr = out;
779 *ptr++ = '{';
780 if (fmt) {
781 *ptr++ = '\n';
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700782 for (j = 0; j < depth - 1; j++) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700783 }
784 *ptr++ = '}';
785 *ptr++ = 0;
786 return out;
787 }
788 if (p) {
789 /* Compose the output: */
790 i = p->offset;
791 len = fmt ? 2 : 1;
792 ptr = ensure(p, len + 1);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700793 if (!ptr) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700794 *ptr++ = '{';
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700795 if (fmt) *ptr++ = '\n';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700796 *ptr = 0;
797 p->offset += len;
798 child = item->child;
799 depth++;
800 while (child) {
801 if (fmt) {
802 ptr = ensure(p, depth);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700803 if (!ptr) return 0;
804 for (j = 0; j < depth; j++) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700805 p->offset += depth;
806 }
807 print_string_ptr(child->string, p);
808 p->offset = update(p);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600809
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700810 len = fmt ? 2 : 1;
811 ptr = ensure(p, len);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700812 if (!ptr) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700813 *ptr++ = ':';
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700814 if (fmt) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700815 p->offset += len;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600816
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700817 print_value(child, depth, fmt, p);
818 p->offset = update(p);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600819
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700820 len = (fmt ? 1 : 0) + (child->next ? 1 : 0);
821 ptr = ensure(p, len + 1);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700822 if (!ptr) return 0;
823 if (child->next) *ptr++ = ',';
824 if (fmt) *ptr++ = '\n';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700825 *ptr = 0;
826 p->offset += len;
827 child = child->next;
828 }
829 ptr = ensure(p, fmt ? (depth + 1) : 2);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700830 if (!ptr) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700831 if (fmt)
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700832 for (j = 0; j < depth - 1; j++) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700833 *ptr++ = '}';
834 *ptr = 0;
835 out = (p->buffer) + i;
836 } else {
837 /* Allocate space for the names and the objects */
838 entries = (char **)cJSON_malloc(numentries * sizeof(char *));
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700839 if (!entries) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700840 names = (char **)cJSON_malloc(numentries * sizeof(char *));
841 if (!names) {
842 cJSON_free(entries);
843 return 0;
844 }
845 memset(entries, 0, sizeof(char *) * numentries);
846 memset(names, 0, sizeof(char *) * numentries);
847
848 /* Collect all the results into our arrays: */
849 child = item->child;
850 depth++;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700851 if (fmt) len += depth;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700852 while (child) {
853 names[i] = str = print_string_ptr(child->string, 0);
854 entries[i++] = ret = print_value(child, depth, fmt, 0);
855 if (str && ret)
856 len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0);
857 else
858 fail = 1;
859 child = child->next;
860 }
861
862 /* Try to allocate the output string */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700863 if (!fail) out = (char *)cJSON_malloc(len);
864 if (!out) fail = 1;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700865
866 /* Handle failure */
867 if (fail) {
868 for (j = 0; j < numentries; j++) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700869 if (names[i]) cJSON_free(names[j]);
870 if (entries[j]) cJSON_free(entries[j]);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700871 }
872 cJSON_free(names);
873 cJSON_free(entries);
874 return 0;
875 }
876
877 /* Compose the output: */
878 *out = '{';
879 ptr = out + 1;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700880 if (fmt) *ptr++ = '\n';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700881 *ptr = 0;
882 for (j = 0; j < numentries; j++) {
883 if (fmt)
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700884 for (k = 0; k < depth; k++) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700885 tmplen = strlen(names[j]);
886 memcpy(ptr, names[j], tmplen);
887 ptr += tmplen;
888 *ptr++ = ':';
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700889 if (fmt) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700890 strcpy(ptr, entries[j]);
891 ptr += strlen(entries[j]);
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700892 if (j != numentries - 1) *ptr++ = ',';
893 if (fmt) *ptr++ = '\n';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700894 *ptr = 0;
895 cJSON_free(names[j]);
896 cJSON_free(entries[j]);
897 }
898
899 cJSON_free(names);
900 cJSON_free(entries);
901 if (fmt)
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700902 for (j = 0; j < depth - 1; j++) *ptr++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700903 *ptr++ = '}';
904 *ptr++ = 0;
905 }
906 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600907}
908
909/* Get Array size/item / object item. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700910int cJSON_GetArraySize(cJSON *array) {
911 cJSON *c = array->child;
912 int i = 0;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700913 while (c) i++, c = c->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700914 return i;
915}
916cJSON *cJSON_GetArrayItem(cJSON *array, int item) {
917 cJSON *c = array->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700918 while (c && item > 0) item--, c = c->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700919 return c;
920}
921cJSON *cJSON_GetObjectItem(cJSON *object, const char *string) {
922 cJSON *c = object->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700923 while (c && strcmp(c->string, string)) c = c->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700924 return c;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600925}
926
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700927/* Utility for array list handling. */
928static void suffix_object(cJSON *prev, cJSON *item) {
929 prev->next = item;
930 item->prev = prev;
931}
932/* Utility for handling references. */
933static cJSON *create_reference(cJSON *item) {
934 cJSON *ref = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700935 if (!ref) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700936 memcpy(ref, item, sizeof(cJSON));
937 ref->string = 0;
938 ref->type |= cJSON_IsReference;
939 ref->next = ref->prev = 0;
940 return ref;
941}
942
943/* Add item to array/object. */
944void cJSON_AddItemToArray(cJSON *array, cJSON *item) {
945 cJSON *c = array->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700946 if (!item) return;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700947 if (!c) {
948 array->child = item;
949 } else {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700950 while (c && c->next) c = c->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700951 suffix_object(c, item);
952 }
953}
954void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700955 if (!item) return;
956 if (item->string) cJSON_free(item->string);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700957 item->string = cJSON_strdup(string);
958 cJSON_AddItemToArray(object, item);
959}
960void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700961 if (!item) return;
962 if (!(item->type & cJSON_StringIsConst) && item->string) cJSON_free(item->string);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700963 item->string = (char *)string;
964 item->type |= cJSON_StringIsConst;
965 cJSON_AddItemToArray(object, item);
966}
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700967void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) { cJSON_AddItemToArray(array, create_reference(item)); }
968void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) {
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700969 cJSON_AddItemToObject(object, string, create_reference(item));
970}
971
972cJSON *cJSON_DetachItemFromArray(cJSON *array, int which) {
973 cJSON *c = array->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700974 while (c && which > 0) c = c->next, which--;
975 if (!c) return 0;
976 if (c->prev) c->prev->next = c->next;
977 if (c->next) c->next->prev = c->prev;
978 if (c == array->child) array->child = c->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700979 c->prev = c->next = 0;
980 return c;
981}
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700982void cJSON_DeleteItemFromArray(cJSON *array, int which) { cJSON_Delete(cJSON_DetachItemFromArray(array, which)); }
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700983cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string) {
984 int i = 0;
985 cJSON *c = object->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700986 while (c && strcmp(c->string, string)) i++, c = c->next;
987 if (c) return cJSON_DetachItemFromArray(object, i);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700988 return 0;
989}
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700990void cJSON_DeleteItemFromObject(cJSON *object, const char *string) { cJSON_Delete(cJSON_DetachItemFromObject(object, string)); }
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700991
992/* Replace array/object items with new ones. */
993void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) {
994 cJSON *c = array->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -0700995 while (c && which > 0) c = c->next, which--;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700996 if (!c) {
997 cJSON_AddItemToArray(array, newitem);
998 return;
999 }
1000 newitem->next = c;
1001 newitem->prev = c->prev;
1002 c->prev = newitem;
1003 if (c == array->child)
1004 array->child = newitem;
1005 else
1006 newitem->prev->next = newitem;
1007}
1008void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) {
1009 cJSON *c = array->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001010 while (c && which > 0) c = c->next, which--;
1011 if (!c) return;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001012 newitem->next = c->next;
1013 newitem->prev = c->prev;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001014 if (newitem->next) newitem->next->prev = newitem;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001015 if (c == array->child)
1016 array->child = newitem;
1017 else
1018 newitem->prev->next = newitem;
1019 c->next = c->prev = 0;
1020 cJSON_Delete(c);
1021}
Mark Lobodzinski91c10752017-01-26 12:16:30 -07001022void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) {
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001023 int i = 0;
1024 cJSON *c = object->child;
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001025 while (c && strcmp(c->string, string)) i++, c = c->next;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001026 if (c) {
1027 newitem->string = cJSON_strdup(string);
1028 cJSON_ReplaceItemInArray(object, i, newitem);
1029 }
1030}
1031
1032/* Create basic types: */
1033cJSON *cJSON_CreateNull(void) {
1034 cJSON *item = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001035 if (item) item->type = cJSON_NULL;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001036 return item;
1037}
1038cJSON *cJSON_CreateTrue(void) {
1039 cJSON *item = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001040 if (item) item->type = cJSON_True;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001041 return item;
1042}
1043cJSON *cJSON_CreateFalse(void) {
1044 cJSON *item = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001045 if (item) item->type = cJSON_False;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001046 return item;
1047}
1048cJSON *cJSON_CreateBool(int b) {
1049 cJSON *item = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001050 if (item) item->type = b ? cJSON_True : cJSON_False;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001051 return item;
1052}
1053cJSON *cJSON_CreateNumber(double num) {
1054 cJSON *item = cJSON_New_Item();
1055 if (item) {
1056 item->type = cJSON_Number;
1057 item->valuedouble = num;
1058 item->valueint = (int)num;
1059 }
1060 return item;
1061}
1062cJSON *cJSON_CreateString(const char *string) {
1063 cJSON *item = cJSON_New_Item();
1064 if (item) {
1065 item->type = cJSON_String;
1066 item->valuestring = cJSON_strdup(string);
1067 }
1068 return item;
1069}
1070cJSON *cJSON_CreateArray(void) {
1071 cJSON *item = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001072 if (item) item->type = cJSON_Array;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001073 return item;
1074}
1075cJSON *cJSON_CreateObject(void) {
1076 cJSON *item = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001077 if (item) item->type = cJSON_Object;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001078 return item;
1079}
1080
1081/* Create Arrays: */
1082cJSON *cJSON_CreateIntArray(const int *numbers, int count) {
1083 int i;
1084 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1085 for (i = 0; a && i < count; i++) {
1086 n = cJSON_CreateNumber(numbers[i]);
1087 if (!i)
1088 a->child = n;
1089 else
1090 suffix_object(p, n);
1091 p = n;
1092 }
1093 return a;
1094}
1095cJSON *cJSON_CreateFloatArray(const float *numbers, int count) {
1096 int i;
1097 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1098 for (i = 0; a && i < count; i++) {
1099 n = cJSON_CreateNumber(numbers[i]);
1100 if (!i)
1101 a->child = n;
1102 else
1103 suffix_object(p, n);
1104 p = n;
1105 }
1106 return a;
1107}
1108cJSON *cJSON_CreateDoubleArray(const double *numbers, int count) {
1109 int i;
1110 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1111 for (i = 0; a && i < count; i++) {
1112 n = cJSON_CreateNumber(numbers[i]);
1113 if (!i)
1114 a->child = n;
1115 else
1116 suffix_object(p, n);
1117 p = n;
1118 }
1119 return a;
1120}
1121cJSON *cJSON_CreateStringArray(const char **strings, int count) {
1122 int i;
1123 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1124 for (i = 0; a && i < count; i++) {
1125 n = cJSON_CreateString(strings[i]);
1126 if (!i)
1127 a->child = n;
1128 else
1129 suffix_object(p, n);
1130 p = n;
1131 }
1132 return a;
1133}
1134
1135/* Duplication */
1136cJSON *cJSON_Duplicate(cJSON *item, int recurse) {
1137 cJSON *newitem, *cptr, *nptr = 0, *newchild;
1138 /* Bail on bad ptr */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001139 if (!item) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001140 /* Create new item */
1141 newitem = cJSON_New_Item();
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001142 if (!newitem) return 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001143 /* Copy over all vars */
Mark Lobodzinski91c10752017-01-26 12:16:30 -07001144 newitem->type = item->type & (~cJSON_IsReference), newitem->valueint = item->valueint, newitem->valuedouble = item->valuedouble;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001145 if (item->valuestring) {
1146 newitem->valuestring = cJSON_strdup(item->valuestring);
1147 if (!newitem->valuestring) {
1148 cJSON_Delete(newitem);
1149 return 0;
1150 }
1151 }
1152 if (item->string) {
1153 newitem->string = cJSON_strdup(item->string);
1154 if (!newitem->string) {
1155 cJSON_Delete(newitem);
1156 return 0;
1157 }
1158 }
1159 /* If non-recursive, then we're done! */
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001160 if (!recurse) return newitem;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001161 /* Walk the ->next chain for the child. */
1162 cptr = item->child;
1163 while (cptr) {
Mark Lobodzinski91c10752017-01-26 12:16:30 -07001164 newchild = cJSON_Duplicate(cptr, 1); /* Duplicate (with recurse) each item in the ->next chain */
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001165 if (!newchild) {
1166 cJSON_Delete(newitem);
1167 return 0;
1168 }
1169 if (nptr) {
1170 nptr->next = newchild, newchild->prev = nptr;
1171 nptr = newchild;
1172 } /* If newitem->child already set, then crosswire ->prev and ->next and
1173 move on */
1174 else {
1175 newitem->child = newchild;
1176 nptr = newchild;
1177 } /* Set newitem->child and move to it */
1178 cptr = cptr->next;
1179 }
1180 return newitem;
1181}
1182
1183void cJSON_Minify(char *json) {
1184 char *into = json;
1185 while (*json) {
1186 if (*json == ' ')
1187 json++;
1188 else if (*json == '\t')
1189 json++; /* Whitespace characters. */
1190 else if (*json == '\r')
1191 json++;
1192 else if (*json == '\n')
1193 json++;
1194 else if (*json == '/' && json[1] == '/')
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001195 while (*json && *json != '\n') json++; /* double-slash comments, to end of line. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001196 else if (*json == '/' && json[1] == '*') {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001197 while (*json && !(*json == '*' && json[1] == '/')) json++;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001198 json += 2;
1199 } /* multiline comments. */
1200 else if (*json == '\"') {
1201 *into++ = *json++;
1202 while (*json && *json != '\"') {
Mark Lobodzinskie2859eb2017-01-26 13:34:13 -07001203 if (*json == '\\') *into++ = *json++;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001204 *into++ = *json++;
1205 }
1206 *into++ = *json++;
1207 } /* string literals, which are \" sensitive. */
1208 else
1209 *into++ = *json++; /* All other characters. */
1210 }
1211 *into = 0; /* and null-terminate. */
Jon Ashburn752e06e2015-06-29 11:25:34 -06001212}