blob: 9c800e188c7943d108b8b1f2c9e69ac87430d518 [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;
50 if (!(copy = (char *)cJSON_malloc(len)))
51 return 0;
52 memcpy(copy, str, len);
53 return copy;
Jon Ashburn752e06e2015-06-29 11:25:34 -060054}
55
Jon Ashburn1c75aec2016-02-02 17:47:28 -070056void cJSON_InitHooks(cJSON_Hooks *hooks) {
Jon Ashburn752e06e2015-06-29 11:25:34 -060057 if (!hooks) { /* Reset hooks */
58 cJSON_malloc = malloc;
59 cJSON_free = free;
60 return;
61 }
62
Jon Ashburn1c75aec2016-02-02 17:47:28 -070063 cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc;
64 cJSON_free = (hooks->free_fn) ? hooks->free_fn : free;
Jon Ashburn752e06e2015-06-29 11:25:34 -060065}
66
67/* Internal constructor. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -070068static cJSON *cJSON_New_Item(void) {
69 cJSON *node = (cJSON *)cJSON_malloc(sizeof(cJSON));
70 if (node)
71 memset(node, 0, sizeof(cJSON));
72 return node;
Jon Ashburn752e06e2015-06-29 11:25:34 -060073}
74
75/* Delete a cJSON structure. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -070076void cJSON_Delete(cJSON *c) {
77 cJSON *next;
78 while (c) {
79 next = c->next;
80 if (!(c->type & cJSON_IsReference) && c->child)
81 cJSON_Delete(c->child);
82 if (!(c->type & cJSON_IsReference) && c->valuestring)
83 cJSON_free(c->valuestring);
84 if (!(c->type & cJSON_StringIsConst) && c->string)
85 cJSON_free(c->string);
86 cJSON_free(c);
87 c = next;
88 }
Jon Ashburn752e06e2015-06-29 11:25:34 -060089}
90
Mark Lobodzinski91c10752017-01-26 12:16:30 -070091void cJSON_Free(void *p) { cJSON_free(p); }
Mark Young74dd5d12016-06-30 13:02:42 -060092
Jon Ashburn1c75aec2016-02-02 17:47:28 -070093/* Parse the input text to generate a number, and populate the result into item.
94 */
95static const char *parse_number(cJSON *item, const char *num) {
96 double n = 0, sign = 1, scale = 0;
97 int subscale = 0, signsubscale = 1;
Jon Ashburn752e06e2015-06-29 11:25:34 -060098
Jon Ashburn1c75aec2016-02-02 17:47:28 -070099 if (*num == '-')
100 sign = -1, num++; /* Has sign? */
101 if (*num == '0')
102 num++; /* is zero */
103 if (*num >= '1' && *num <= '9')
104 do
105 n = (n * 10.0) + (*num++ - '0');
106 while (*num >= '0' && *num <= '9'); /* Number? */
107 if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
108 num++;
109 do
110 n = (n * 10.0) + (*num++ - '0'), scale--;
111 while (*num >= '0' && *num <= '9');
112 } /* Fractional part? */
113 if (*num == 'e' || *num == 'E') /* Exponent? */
114 {
115 num++;
116 if (*num == '+')
117 num++;
118 else if (*num == '-')
119 signsubscale = -1, num++; /* With sign? */
120 while (*num >= '0' && *num <= '9')
121 subscale = (subscale * 10) + (*num++ - '0'); /* Number? */
122 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600123
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700124 n = sign * n * pow(10.0, (scale + subscale * signsubscale)); /* number = +/-
125 number.fraction *
126 10^+/- exponent */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700127
128 item->valuedouble = n;
129 item->valueint = (int)n;
130 item->type = cJSON_Number;
131 return num;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600132}
133
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700134static size_t pow2gt(size_t x) {
135 --x;
136 x |= x >> 1;
137 x |= x >> 2;
138 x |= x >> 4;
139 x |= x >> 8;
140 x |= x >> 16;
141 return x + 1;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600142}
143
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700144typedef struct {
145 char *buffer;
146 size_t length;
147 size_t offset;
148} printbuffer;
149
150static char *ensure(printbuffer *p, size_t needed) {
151 char *newbuffer;
152 size_t newsize;
153 if (!p || !p->buffer)
154 return 0;
155 needed += p->offset;
156 if (needed <= p->length)
157 return p->buffer + p->offset;
158
159 newsize = pow2gt(needed);
160 newbuffer = (char *)cJSON_malloc(newsize);
161 if (!newbuffer) {
162 cJSON_free(p->buffer);
163 p->length = 0, p->buffer = 0;
164 return 0;
165 }
166 if (newbuffer)
167 memcpy(newbuffer, p->buffer, p->length);
168 cJSON_free(p->buffer);
169 p->length = newsize;
170 p->buffer = newbuffer;
171 return newbuffer + p->offset;
172}
173
174static size_t update(printbuffer *p) {
175 char *str;
176 if (!p || !p->buffer)
177 return 0;
178 str = p->buffer + p->offset;
179 return p->offset + strlen(str);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600180}
181
182/* Render the number nicely from the given item into a string. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700183static char *print_number(cJSON *item, printbuffer *p) {
184 char *str = 0;
185 double d = item->valuedouble;
186 if (d == 0) {
187 if (p)
188 str = ensure(p, 2);
189 else
190 str = (char *)cJSON_malloc(2); /* special case for 0. */
191 if (str)
192 strcpy(str, "0");
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700193 } else if (fabs(((double)item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN) {
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700194 if (p)
195 str = ensure(p, 21);
196 else
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700197 str = (char *)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700198 if (str)
199 sprintf(str, "%d", item->valueint);
200 } else {
201 if (p)
202 str = ensure(p, 64);
203 else
204 str = (char *)cJSON_malloc(64); /* This is a nice tradeoff. */
205 if (str) {
206 if (fabs(floor(d) - d) <= DBL_EPSILON && fabs(d) < 1.0e60)
207 sprintf(str, "%.0f", d);
208 else if (fabs(d) < 1.0e-6 || fabs(d) > 1.0e9)
209 sprintf(str, "%e", d);
210 else
211 sprintf(str, "%f", d);
212 }
213 }
214 return str;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600215}
216
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700217static unsigned parse_hex4(const char *str) {
218 unsigned h = 0;
219 if (*str >= '0' && *str <= '9')
220 h += (*str) - '0';
221 else if (*str >= 'A' && *str <= 'F')
222 h += 10 + (*str) - 'A';
223 else if (*str >= 'a' && *str <= 'f')
224 h += 10 + (*str) - 'a';
225 else
226 return 0;
227 h = h << 4;
228 str++;
229 if (*str >= '0' && *str <= '9')
230 h += (*str) - '0';
231 else if (*str >= 'A' && *str <= 'F')
232 h += 10 + (*str) - 'A';
233 else if (*str >= 'a' && *str <= 'f')
234 h += 10 + (*str) - 'a';
235 else
236 return 0;
237 h = h << 4;
238 str++;
239 if (*str >= '0' && *str <= '9')
240 h += (*str) - '0';
241 else if (*str >= 'A' && *str <= 'F')
242 h += 10 + (*str) - 'A';
243 else if (*str >= 'a' && *str <= 'f')
244 h += 10 + (*str) - 'a';
245 else
246 return 0;
247 h = h << 4;
248 str++;
249 if (*str >= '0' && *str <= '9')
250 h += (*str) - '0';
251 else if (*str >= 'A' && *str <= 'F')
252 h += 10 + (*str) - 'A';
253 else if (*str >= 'a' && *str <= 'f')
254 h += 10 + (*str) - 'a';
255 else
256 return 0;
257 return h;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600258}
259
260/* Parse the input text into an unescaped cstring, and populate item. */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700261static const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700262static const char *parse_string(cJSON *item, const char *str) {
263 const char *ptr = str + 1;
264 char *ptr2;
265 char *out;
266 int len = 0;
267 unsigned uc, uc2;
268 if (*str != '\"') {
269 ep = str;
270 return 0;
271 } /* not a string! */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600272
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700273 while (*ptr != '\"' && *ptr && ++len)
274 if (*ptr++ == '\\')
275 ptr++; /* Skip escaped quotes. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600276
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700277 out = (char *)cJSON_malloc(len + 1); /* This is how long we need for the string, roughly. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700278 if (!out)
279 return 0;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600280
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700281 ptr = str + 1;
282 ptr2 = out;
283 while (*ptr != '\"' && *ptr) {
284 if (*ptr != '\\')
285 *ptr2++ = *ptr++;
286 else {
287 ptr++;
288 switch (*ptr) {
289 case 'b':
290 *ptr2++ = '\b';
291 break;
292 case 'f':
293 *ptr2++ = '\f';
294 break;
295 case 'n':
296 *ptr2++ = '\n';
297 break;
298 case 'r':
299 *ptr2++ = '\r';
300 break;
301 case 't':
302 *ptr2++ = '\t';
303 break;
304 case 'u': /* transcode utf16 to utf8. */
305 uc = parse_hex4(ptr + 1);
306 ptr += 4; /* get the unicode char. */
307
308 if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0)
309 break; /* check for invalid. */
310
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700311 if (uc >= 0xD800 && uc <= 0xDBFF) /* UTF16 surrogate pairs. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700312 {
313 if (ptr[1] != '\\' || ptr[2] != 'u')
314 break; /* missing second-half of surrogate. */
315 uc2 = parse_hex4(ptr + 3);
316 ptr += 6;
317 if (uc2 < 0xDC00 || uc2 > 0xDFFF)
318 break; /* invalid second-half of surrogate. */
319 uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));
320 }
321
322 len = 4;
323 if (uc < 0x80)
324 len = 1;
325 else if (uc < 0x800)
326 len = 2;
327 else if (uc < 0x10000)
328 len = 3;
329 ptr2 += len;
330
331 switch (len) {
332 case 4:
333 *--ptr2 = ((uc | 0x80) & 0xBF);
334 uc >>= 6;
335 case 3:
336 *--ptr2 = ((uc | 0x80) & 0xBF);
337 uc >>= 6;
338 case 2:
339 *--ptr2 = ((uc | 0x80) & 0xBF);
340 uc >>= 6;
341 case 1:
Karl Schultz3fd3d092016-02-24 14:39:39 -0700342 *--ptr2 = ((unsigned char)uc | firstByteMark[len]);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700343 }
344 ptr2 += len;
345 break;
346 default:
347 *ptr2++ = *ptr;
348 break;
349 }
350 ptr++;
351 }
352 }
353 *ptr2 = 0;
354 if (*ptr == '\"')
355 ptr++;
356 item->valuestring = out;
357 item->type = cJSON_String;
358 return ptr;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600359}
360
361/* Render the cstring provided to an escaped version that can be printed. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700362static char *print_string_ptr(const char *str, printbuffer *p) {
363 const char *ptr;
364 char *ptr2;
365 char *out;
366 size_t len = 0, flag = 0;
367 unsigned char token;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600368
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700369 for (ptr = str; *ptr; ptr++)
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700370 flag |= ((*ptr > 0 && *ptr < 32) || (*ptr == '\"') || (*ptr == '\\')) ? 1 : 0;
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700371 if (!flag) {
372 len = ptr - str;
373 if (p)
374 out = ensure(p, len + 3);
375 else
376 out = (char *)cJSON_malloc(len + 3);
377 if (!out)
378 return 0;
379 ptr2 = out;
380 *ptr2++ = '\"';
381 strcpy(ptr2, str);
382 ptr2[len] = '\"';
383 ptr2[len + 1] = 0;
384 return out;
385 }
386
387 if (!str) {
388 if (p)
389 out = ensure(p, 3);
390 else
391 out = (char *)cJSON_malloc(3);
392 if (!out)
393 return 0;
394 strcpy(out, "\"\"");
395 return out;
396 }
397 ptr = str;
398 while ((token = *ptr) && ++len) {
399 if (strchr("\"\\\b\f\n\r\t", token))
400 len++;
401 else if (token < 32)
402 len += 5;
403 ptr++;
404 }
405
406 if (p)
407 out = ensure(p, len + 3);
408 else
409 out = (char *)cJSON_malloc(len + 3);
410 if (!out)
411 return 0;
412
413 ptr2 = out;
414 ptr = str;
415 *ptr2++ = '\"';
416 while (*ptr) {
417 if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\')
418 *ptr2++ = *ptr++;
419 else {
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700420 switch (token = *ptr++) {
421 case '\\':
422 *ptr2++ = '\\';
423 break;
424 case '\"':
425 *ptr2++ = '\"';
426 break;
427 case '\b':
Mark Young64d6ee12016-06-14 14:59:44 -0600428 *ptr2++ = '\b';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700429 break;
430 case '\f':
Mark Young64d6ee12016-06-14 14:59:44 -0600431 *ptr2++ = '\f';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700432 break;
433 case '\n':
Mark Young64d6ee12016-06-14 14:59:44 -0600434 *ptr2++ = '\n';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700435 break;
436 case '\r':
Mark Young64d6ee12016-06-14 14:59:44 -0600437 *ptr2++ = '\r';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700438 break;
439 case '\t':
Mark Young64d6ee12016-06-14 14:59:44 -0600440 *ptr2++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700441 break;
442 default:
443 sprintf(ptr2, "u%04x", token);
444 ptr2 += 5;
445 break; /* escape and print */
446 }
447 }
448 }
449 *ptr2++ = '\"';
450 *ptr2++ = 0;
451 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600452}
453/* Invote print_string_ptr (which is useful) on an item. */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700454static char *print_string(cJSON *item, printbuffer *p) { return print_string_ptr(item->valuestring, p); }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600455
456/* Predeclare these prototypes. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700457static const char *parse_value(cJSON *item, const char *value);
458static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p);
459static const char *parse_array(cJSON *item, const char *value);
460static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p);
461static const char *parse_object(cJSON *item, const char *value);
462static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600463
464/* Utility to jump whitespace and cr/lf */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700465static const char *skip(const char *in) {
466 while (in && *in && (unsigned char)*in <= 32)
467 in++;
468 return in;
469}
Jon Ashburn752e06e2015-06-29 11:25:34 -0600470
471/* Parse an object - create a new root, and populate. */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700472cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated) {
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700473 const char *end = 0;
474 cJSON *c = cJSON_New_Item();
475 ep = 0;
476 if (!c)
477 return 0; /* memory fail */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600478
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700479 end = parse_value(c, skip(value));
480 if (!end) {
481 cJSON_Delete(c);
482 return 0;
483 } /* parse failure. ep is set. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600484
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700485 /* if we require null-terminated JSON without appended garbage, skip and
486 * then check for a null terminator */
487 if (require_null_terminated) {
488 end = skip(end);
489 if (*end) {
490 cJSON_Delete(c);
491 ep = end;
492 return 0;
493 }
494 }
495 if (return_parse_end)
496 *return_parse_end = end;
497 return c;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600498}
499/* Default options for cJSON_Parse */
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700500cJSON *cJSON_Parse(const char *value) { return cJSON_ParseWithOpts(value, 0, 0); }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600501
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700502/* Render a cJSON item/entity/structure to text. */
503char *cJSON_Print(cJSON *item) { return print_value(item, 0, 1, 0); }
504char *cJSON_PrintUnformatted(cJSON *item) { return print_value(item, 0, 0, 0); }
505
506char *cJSON_PrintBuffered(cJSON *item, int prebuffer, int fmt) {
507 printbuffer p;
508 p.buffer = (char *)cJSON_malloc(prebuffer);
509 p.length = prebuffer;
510 p.offset = 0;
511 return print_value(item, 0, fmt, &p);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700512}
Jon Ashburn752e06e2015-06-29 11:25:34 -0600513
514/* Parser core - when encountering text, process appropriately. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700515static const char *parse_value(cJSON *item, const char *value) {
516 if (!value)
517 return 0; /* Fail on null. */
518 if (!strncmp(value, "null", 4)) {
519 item->type = cJSON_NULL;
520 return value + 4;
521 }
522 if (!strncmp(value, "false", 5)) {
523 item->type = cJSON_False;
524 return value + 5;
525 }
526 if (!strncmp(value, "true", 4)) {
527 item->type = cJSON_True;
528 item->valueint = 1;
529 return value + 4;
530 }
531 if (*value == '\"') {
532 return parse_string(item, value);
533 }
534 if (*value == '-' || (*value >= '0' && *value <= '9')) {
535 return parse_number(item, value);
536 }
537 if (*value == '[') {
538 return parse_array(item, value);
539 }
540 if (*value == '{') {
541 return parse_object(item, value);
542 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600543
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700544 ep = value;
545 return 0; /* failure. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600546}
547
548/* Render a value to text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700549static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p) {
550 char *out = 0;
551 if (!item)
552 return 0;
553 if (p) {
554 switch ((item->type) & 255) {
555 case cJSON_NULL: {
556 out = ensure(p, 5);
557 if (out)
558 strcpy(out, "null");
559 break;
560 }
561 case cJSON_False: {
562 out = ensure(p, 6);
563 if (out)
564 strcpy(out, "false");
565 break;
566 }
567 case cJSON_True: {
568 out = ensure(p, 5);
569 if (out)
570 strcpy(out, "true");
571 break;
572 }
573 case cJSON_Number:
574 out = print_number(item, p);
575 break;
576 case cJSON_String:
577 out = print_string(item, p);
578 break;
579 case cJSON_Array:
580 out = print_array(item, depth, fmt, p);
581 break;
582 case cJSON_Object:
583 out = print_object(item, depth, fmt, p);
584 break;
585 }
586 } else {
587 switch ((item->type) & 255) {
588 case cJSON_NULL:
589 out = cJSON_strdup("null");
590 break;
591 case cJSON_False:
592 out = cJSON_strdup("false");
593 break;
594 case cJSON_True:
595 out = cJSON_strdup("true");
596 break;
597 case cJSON_Number:
598 out = print_number(item, 0);
599 break;
600 case cJSON_String:
601 out = print_string(item, 0);
602 break;
603 case cJSON_Array:
604 out = print_array(item, depth, fmt, 0);
605 break;
606 case cJSON_Object:
607 out = print_object(item, depth, fmt, 0);
608 break;
609 }
610 }
611 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600612}
613
614/* Build an array from input text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700615static const char *parse_array(cJSON *item, const char *value) {
616 cJSON *child;
617 if (*value != '[') {
618 ep = value;
619 return 0;
620 } /* not an array! */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600621
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700622 item->type = cJSON_Array;
623 value = skip(value + 1);
624 if (*value == ']')
625 return value + 1; /* empty array. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600626
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700627 item->child = child = cJSON_New_Item();
628 if (!item->child)
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700629 return 0; /* memory fail */
630 value = skip(parse_value(child, skip(value))); /* skip any spacing, get the value. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700631 if (!value)
632 return 0;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600633
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700634 while (*value == ',') {
635 cJSON *new_item;
636 if (!(new_item = cJSON_New_Item()))
637 return 0; /* memory fail */
638 child->next = new_item;
639 new_item->prev = child;
640 child = new_item;
641 value = skip(parse_value(child, skip(value + 1)));
642 if (!value)
643 return 0; /* memory fail */
644 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600645
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700646 if (*value == ']')
647 return value + 1; /* end of array */
648 ep = value;
649 return 0; /* malformed. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600650}
651
652/* Render an array to text */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700653static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p) {
654 char **entries;
655 char *out = 0, *ptr, *ret;
656 size_t len = 5;
657 cJSON *child = item->child;
658 int numentries = 0, fail = 0, j = 0;
659 size_t tmplen = 0, i = 0;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600660
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700661 /* How many entries in the array? */
662 while (child)
663 numentries++, child = child->next;
664 /* Explicitly handle numentries==0 */
665 if (!numentries) {
666 if (p)
667 out = ensure(p, 3);
668 else
669 out = (char *)cJSON_malloc(3);
670 if (out)
671 strcpy(out, "[]");
672 return out;
673 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600674
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700675 if (p) {
676 /* Compose the output array. */
677 i = p->offset;
678 ptr = ensure(p, 1);
679 if (!ptr)
680 return 0;
681 *ptr = '[';
682 p->offset++;
683 child = item->child;
684 while (child && !fail) {
685 print_value(child, depth + 1, fmt, p);
686 p->offset = update(p);
687 if (child->next) {
688 len = fmt ? 2 : 1;
689 ptr = ensure(p, len + 1);
690 if (!ptr)
691 return 0;
692 *ptr++ = ',';
693 if (fmt)
694 *ptr++ = ' ';
695 *ptr = 0;
696 p->offset += len;
697 }
698 child = child->next;
699 }
700 ptr = ensure(p, 2);
701 if (!ptr)
702 return 0;
703 *ptr++ = ']';
704 *ptr = 0;
705 out = (p->buffer) + i;
706 } else {
707 /* Allocate an array to hold the values for each */
708 entries = (char **)cJSON_malloc(numentries * sizeof(char *));
709 if (!entries)
710 return 0;
711 memset(entries, 0, numentries * sizeof(char *));
712 /* Retrieve all the results: */
713 child = item->child;
714 while (child && !fail) {
715 ret = print_value(child, depth + 1, fmt, 0);
716 entries[i++] = ret;
717 if (ret)
718 len += strlen(ret) + 2 + (fmt ? 1 : 0);
719 else
720 fail = 1;
721 child = child->next;
722 }
723
724 /* If we didn't fail, try to malloc the output string */
725 if (!fail)
726 out = (char *)cJSON_malloc(len);
727 /* If that fails, we fail. */
728 if (!out)
729 fail = 1;
730
731 /* Handle failure. */
732 if (fail) {
733 for (j = 0; j < numentries; j++)
734 if (entries[j])
735 cJSON_free(entries[j]);
736 cJSON_free(entries);
737 return 0;
738 }
739
740 /* Compose the output array. */
741 *out = '[';
742 ptr = out + 1;
743 *ptr = 0;
744 for (j = 0; j < numentries; j++) {
745 tmplen = strlen(entries[j]);
746 memcpy(ptr, entries[j], tmplen);
747 ptr += tmplen;
748 if (j != numentries - 1) {
749 *ptr++ = ',';
750 if (fmt)
751 *ptr++ = ' ';
752 *ptr = 0;
753 }
754 cJSON_free(entries[j]);
755 }
756 cJSON_free(entries);
757 *ptr++ = ']';
758 *ptr++ = 0;
759 }
760 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600761}
762
763/* Build an object from the text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700764static const char *parse_object(cJSON *item, const char *value) {
765 cJSON *child;
766 if (*value != '{') {
767 ep = value;
768 return 0;
769 } /* not an object! */
770
771 item->type = cJSON_Object;
772 value = skip(value + 1);
773 if (*value == '}')
774 return value + 1; /* empty array. */
775
776 item->child = child = cJSON_New_Item();
777 if (!item->child)
778 return 0;
779 value = skip(parse_string(child, skip(value)));
780 if (!value)
781 return 0;
782 child->string = child->valuestring;
783 child->valuestring = 0;
784 if (*value != ':') {
785 ep = value;
786 return 0;
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700787 } /* fail! */
788 value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700789 if (!value)
790 return 0;
791
792 while (*value == ',') {
793 cJSON *new_item;
794 if (!(new_item = cJSON_New_Item()))
795 return 0; /* memory fail */
796 child->next = new_item;
797 new_item->prev = child;
798 child = new_item;
799 value = skip(parse_string(child, skip(value + 1)));
800 if (!value)
801 return 0;
802 child->string = child->valuestring;
803 child->valuestring = 0;
804 if (*value != ':') {
805 ep = value;
806 return 0;
Mark Lobodzinski91c10752017-01-26 12:16:30 -0700807 } /* fail! */
808 value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700809 if (!value)
810 return 0;
811 }
812
813 if (*value == '}')
814 return value + 1; /* end of array */
815 ep = value;
816 return 0; /* malformed. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600817}
818
819/* Render an object to text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700820static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p) {
821 char **entries = 0, **names = 0;
822 char *out = 0, *ptr, *ret, *str;
823 int j;
824 cJSON *child = item->child;
825 int numentries = 0, fail = 0, k;
826 size_t tmplen = 0, i = 0, len = 7;
827 /* Count the number of entries. */
828 while (child)
829 numentries++, child = child->next;
830 /* Explicitly handle empty object case */
831 if (!numentries) {
832 if (p)
833 out = ensure(p, fmt ? depth + 4 : 3);
834 else
835 out = (char *)cJSON_malloc(fmt ? depth + 4 : 3);
836 if (!out)
837 return 0;
838 ptr = out;
839 *ptr++ = '{';
840 if (fmt) {
841 *ptr++ = '\n';
842 for (j = 0; j < depth - 1; j++)
843 *ptr++ = '\t';
844 }
845 *ptr++ = '}';
846 *ptr++ = 0;
847 return out;
848 }
849 if (p) {
850 /* Compose the output: */
851 i = p->offset;
852 len = fmt ? 2 : 1;
853 ptr = ensure(p, len + 1);
854 if (!ptr)
855 return 0;
856 *ptr++ = '{';
857 if (fmt)
858 *ptr++ = '\n';
859 *ptr = 0;
860 p->offset += len;
861 child = item->child;
862 depth++;
863 while (child) {
864 if (fmt) {
865 ptr = ensure(p, depth);
866 if (!ptr)
867 return 0;
868 for (j = 0; j < depth; j++)
869 *ptr++ = '\t';
870 p->offset += depth;
871 }
872 print_string_ptr(child->string, p);
873 p->offset = update(p);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600874
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700875 len = fmt ? 2 : 1;
876 ptr = ensure(p, len);
877 if (!ptr)
878 return 0;
879 *ptr++ = ':';
880 if (fmt)
881 *ptr++ = '\t';
882 p->offset += len;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600883
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700884 print_value(child, depth, fmt, p);
885 p->offset = update(p);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600886
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700887 len = (fmt ? 1 : 0) + (child->next ? 1 : 0);
888 ptr = ensure(p, len + 1);
889 if (!ptr)
890 return 0;
891 if (child->next)
892 *ptr++ = ',';
893 if (fmt)
894 *ptr++ = '\n';
895 *ptr = 0;
896 p->offset += len;
897 child = child->next;
898 }
899 ptr = ensure(p, fmt ? (depth + 1) : 2);
900 if (!ptr)
901 return 0;
902 if (fmt)
903 for (j = 0; j < depth - 1; j++)
904 *ptr++ = '\t';
905 *ptr++ = '}';
906 *ptr = 0;
907 out = (p->buffer) + i;
908 } else {
909 /* Allocate space for the names and the objects */
910 entries = (char **)cJSON_malloc(numentries * sizeof(char *));
911 if (!entries)
912 return 0;
913 names = (char **)cJSON_malloc(numentries * sizeof(char *));
914 if (!names) {
915 cJSON_free(entries);
916 return 0;
917 }
918 memset(entries, 0, sizeof(char *) * numentries);
919 memset(names, 0, sizeof(char *) * numentries);
920
921 /* Collect all the results into our arrays: */
922 child = item->child;
923 depth++;
924 if (fmt)
925 len += depth;
926 while (child) {
927 names[i] = str = print_string_ptr(child->string, 0);
928 entries[i++] = ret = print_value(child, depth, fmt, 0);
929 if (str && ret)
930 len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0);
931 else
932 fail = 1;
933 child = child->next;
934 }
935
936 /* Try to allocate the output string */
937 if (!fail)
938 out = (char *)cJSON_malloc(len);
939 if (!out)
940 fail = 1;
941
942 /* Handle failure */
943 if (fail) {
944 for (j = 0; j < numentries; j++) {
945 if (names[i])
946 cJSON_free(names[j]);
947 if (entries[j])
948 cJSON_free(entries[j]);
949 }
950 cJSON_free(names);
951 cJSON_free(entries);
952 return 0;
953 }
954
955 /* Compose the output: */
956 *out = '{';
957 ptr = out + 1;
958 if (fmt)
959 *ptr++ = '\n';
960 *ptr = 0;
961 for (j = 0; j < numentries; j++) {
962 if (fmt)
963 for (k = 0; k < depth; k++)
964 *ptr++ = '\t';
965 tmplen = strlen(names[j]);
966 memcpy(ptr, names[j], tmplen);
967 ptr += tmplen;
968 *ptr++ = ':';
969 if (fmt)
970 *ptr++ = '\t';
971 strcpy(ptr, entries[j]);
972 ptr += strlen(entries[j]);
973 if (j != numentries - 1)
974 *ptr++ = ',';
975 if (fmt)
976 *ptr++ = '\n';
977 *ptr = 0;
978 cJSON_free(names[j]);
979 cJSON_free(entries[j]);
980 }
981
982 cJSON_free(names);
983 cJSON_free(entries);
984 if (fmt)
985 for (j = 0; j < depth - 1; j++)
986 *ptr++ = '\t';
987 *ptr++ = '}';
988 *ptr++ = 0;
989 }
990 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600991}
992
993/* Get Array size/item / object item. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700994int cJSON_GetArraySize(cJSON *array) {
995 cJSON *c = array->child;
996 int i = 0;
997 while (c)
998 i++, c = c->next;
999 return i;
1000}
1001cJSON *cJSON_GetArrayItem(cJSON *array, int item) {
1002 cJSON *c = array->child;
1003 while (c && item > 0)
1004 item--, c = c->next;
1005 return c;
1006}
1007cJSON *cJSON_GetObjectItem(cJSON *object, const char *string) {
1008 cJSON *c = object->child;
1009 while (c && strcmp(c->string, string))
1010 c = c->next;
1011 return c;
Jon Ashburn752e06e2015-06-29 11:25:34 -06001012}
1013
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001014/* Utility for array list handling. */
1015static void suffix_object(cJSON *prev, cJSON *item) {
1016 prev->next = item;
1017 item->prev = prev;
1018}
1019/* Utility for handling references. */
1020static cJSON *create_reference(cJSON *item) {
1021 cJSON *ref = cJSON_New_Item();
1022 if (!ref)
1023 return 0;
1024 memcpy(ref, item, sizeof(cJSON));
1025 ref->string = 0;
1026 ref->type |= cJSON_IsReference;
1027 ref->next = ref->prev = 0;
1028 return ref;
1029}
1030
1031/* Add item to array/object. */
1032void cJSON_AddItemToArray(cJSON *array, cJSON *item) {
1033 cJSON *c = array->child;
1034 if (!item)
1035 return;
1036 if (!c) {
1037 array->child = item;
1038 } else {
1039 while (c && c->next)
1040 c = c->next;
1041 suffix_object(c, item);
1042 }
1043}
1044void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) {
1045 if (!item)
1046 return;
1047 if (item->string)
1048 cJSON_free(item->string);
1049 item->string = cJSON_strdup(string);
1050 cJSON_AddItemToArray(object, item);
1051}
1052void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) {
1053 if (!item)
1054 return;
1055 if (!(item->type & cJSON_StringIsConst) && item->string)
1056 cJSON_free(item->string);
1057 item->string = (char *)string;
1058 item->type |= cJSON_StringIsConst;
1059 cJSON_AddItemToArray(object, item);
1060}
Mark Lobodzinski91c10752017-01-26 12:16:30 -07001061void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) { cJSON_AddItemToArray(array, create_reference(item)); }
1062void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) {
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001063 cJSON_AddItemToObject(object, string, create_reference(item));
1064}
1065
1066cJSON *cJSON_DetachItemFromArray(cJSON *array, int which) {
1067 cJSON *c = array->child;
1068 while (c && which > 0)
1069 c = c->next, which--;
1070 if (!c)
1071 return 0;
1072 if (c->prev)
1073 c->prev->next = c->next;
1074 if (c->next)
1075 c->next->prev = c->prev;
1076 if (c == array->child)
1077 array->child = c->next;
1078 c->prev = c->next = 0;
1079 return c;
1080}
Mark Lobodzinski91c10752017-01-26 12:16:30 -07001081void cJSON_DeleteItemFromArray(cJSON *array, int which) { cJSON_Delete(cJSON_DetachItemFromArray(array, which)); }
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001082cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string) {
1083 int i = 0;
1084 cJSON *c = object->child;
1085 while (c && strcmp(c->string, string))
1086 i++, c = c->next;
1087 if (c)
1088 return cJSON_DetachItemFromArray(object, i);
1089 return 0;
1090}
Mark Lobodzinski91c10752017-01-26 12:16:30 -07001091void cJSON_DeleteItemFromObject(cJSON *object, const char *string) { cJSON_Delete(cJSON_DetachItemFromObject(object, string)); }
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001092
1093/* Replace array/object items with new ones. */
1094void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) {
1095 cJSON *c = array->child;
1096 while (c && which > 0)
1097 c = c->next, which--;
1098 if (!c) {
1099 cJSON_AddItemToArray(array, newitem);
1100 return;
1101 }
1102 newitem->next = c;
1103 newitem->prev = c->prev;
1104 c->prev = newitem;
1105 if (c == array->child)
1106 array->child = newitem;
1107 else
1108 newitem->prev->next = newitem;
1109}
1110void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) {
1111 cJSON *c = array->child;
1112 while (c && which > 0)
1113 c = c->next, which--;
1114 if (!c)
1115 return;
1116 newitem->next = c->next;
1117 newitem->prev = c->prev;
1118 if (newitem->next)
1119 newitem->next->prev = newitem;
1120 if (c == array->child)
1121 array->child = newitem;
1122 else
1123 newitem->prev->next = newitem;
1124 c->next = c->prev = 0;
1125 cJSON_Delete(c);
1126}
Mark Lobodzinski91c10752017-01-26 12:16:30 -07001127void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) {
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001128 int i = 0;
1129 cJSON *c = object->child;
1130 while (c && strcmp(c->string, string))
1131 i++, c = c->next;
1132 if (c) {
1133 newitem->string = cJSON_strdup(string);
1134 cJSON_ReplaceItemInArray(object, i, newitem);
1135 }
1136}
1137
1138/* Create basic types: */
1139cJSON *cJSON_CreateNull(void) {
1140 cJSON *item = cJSON_New_Item();
1141 if (item)
1142 item->type = cJSON_NULL;
1143 return item;
1144}
1145cJSON *cJSON_CreateTrue(void) {
1146 cJSON *item = cJSON_New_Item();
1147 if (item)
1148 item->type = cJSON_True;
1149 return item;
1150}
1151cJSON *cJSON_CreateFalse(void) {
1152 cJSON *item = cJSON_New_Item();
1153 if (item)
1154 item->type = cJSON_False;
1155 return item;
1156}
1157cJSON *cJSON_CreateBool(int b) {
1158 cJSON *item = cJSON_New_Item();
1159 if (item)
1160 item->type = b ? cJSON_True : cJSON_False;
1161 return item;
1162}
1163cJSON *cJSON_CreateNumber(double num) {
1164 cJSON *item = cJSON_New_Item();
1165 if (item) {
1166 item->type = cJSON_Number;
1167 item->valuedouble = num;
1168 item->valueint = (int)num;
1169 }
1170 return item;
1171}
1172cJSON *cJSON_CreateString(const char *string) {
1173 cJSON *item = cJSON_New_Item();
1174 if (item) {
1175 item->type = cJSON_String;
1176 item->valuestring = cJSON_strdup(string);
1177 }
1178 return item;
1179}
1180cJSON *cJSON_CreateArray(void) {
1181 cJSON *item = cJSON_New_Item();
1182 if (item)
1183 item->type = cJSON_Array;
1184 return item;
1185}
1186cJSON *cJSON_CreateObject(void) {
1187 cJSON *item = cJSON_New_Item();
1188 if (item)
1189 item->type = cJSON_Object;
1190 return item;
1191}
1192
1193/* Create Arrays: */
1194cJSON *cJSON_CreateIntArray(const int *numbers, int count) {
1195 int i;
1196 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1197 for (i = 0; a && i < count; i++) {
1198 n = cJSON_CreateNumber(numbers[i]);
1199 if (!i)
1200 a->child = n;
1201 else
1202 suffix_object(p, n);
1203 p = n;
1204 }
1205 return a;
1206}
1207cJSON *cJSON_CreateFloatArray(const float *numbers, int count) {
1208 int i;
1209 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1210 for (i = 0; a && i < count; i++) {
1211 n = cJSON_CreateNumber(numbers[i]);
1212 if (!i)
1213 a->child = n;
1214 else
1215 suffix_object(p, n);
1216 p = n;
1217 }
1218 return a;
1219}
1220cJSON *cJSON_CreateDoubleArray(const double *numbers, int count) {
1221 int i;
1222 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1223 for (i = 0; a && i < count; i++) {
1224 n = cJSON_CreateNumber(numbers[i]);
1225 if (!i)
1226 a->child = n;
1227 else
1228 suffix_object(p, n);
1229 p = n;
1230 }
1231 return a;
1232}
1233cJSON *cJSON_CreateStringArray(const char **strings, int count) {
1234 int i;
1235 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1236 for (i = 0; a && i < count; i++) {
1237 n = cJSON_CreateString(strings[i]);
1238 if (!i)
1239 a->child = n;
1240 else
1241 suffix_object(p, n);
1242 p = n;
1243 }
1244 return a;
1245}
1246
1247/* Duplication */
1248cJSON *cJSON_Duplicate(cJSON *item, int recurse) {
1249 cJSON *newitem, *cptr, *nptr = 0, *newchild;
1250 /* Bail on bad ptr */
1251 if (!item)
1252 return 0;
1253 /* Create new item */
1254 newitem = cJSON_New_Item();
1255 if (!newitem)
1256 return 0;
1257 /* Copy over all vars */
Mark Lobodzinski91c10752017-01-26 12:16:30 -07001258 newitem->type = item->type & (~cJSON_IsReference), newitem->valueint = item->valueint, newitem->valuedouble = item->valuedouble;
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001259 if (item->valuestring) {
1260 newitem->valuestring = cJSON_strdup(item->valuestring);
1261 if (!newitem->valuestring) {
1262 cJSON_Delete(newitem);
1263 return 0;
1264 }
1265 }
1266 if (item->string) {
1267 newitem->string = cJSON_strdup(item->string);
1268 if (!newitem->string) {
1269 cJSON_Delete(newitem);
1270 return 0;
1271 }
1272 }
1273 /* If non-recursive, then we're done! */
1274 if (!recurse)
1275 return newitem;
1276 /* Walk the ->next chain for the child. */
1277 cptr = item->child;
1278 while (cptr) {
Mark Lobodzinski91c10752017-01-26 12:16:30 -07001279 newchild = cJSON_Duplicate(cptr, 1); /* Duplicate (with recurse) each item in the ->next chain */
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001280 if (!newchild) {
1281 cJSON_Delete(newitem);
1282 return 0;
1283 }
1284 if (nptr) {
1285 nptr->next = newchild, newchild->prev = nptr;
1286 nptr = newchild;
1287 } /* If newitem->child already set, then crosswire ->prev and ->next and
1288 move on */
1289 else {
1290 newitem->child = newchild;
1291 nptr = newchild;
1292 } /* Set newitem->child and move to it */
1293 cptr = cptr->next;
1294 }
1295 return newitem;
1296}
1297
1298void cJSON_Minify(char *json) {
1299 char *into = json;
1300 while (*json) {
1301 if (*json == ' ')
1302 json++;
1303 else if (*json == '\t')
1304 json++; /* Whitespace characters. */
1305 else if (*json == '\r')
1306 json++;
1307 else if (*json == '\n')
1308 json++;
1309 else if (*json == '/' && json[1] == '/')
1310 while (*json && *json != '\n')
1311 json++; /* double-slash comments, to end of line. */
1312 else if (*json == '/' && json[1] == '*') {
1313 while (*json && !(*json == '*' && json[1] == '/'))
1314 json++;
1315 json += 2;
1316 } /* multiline comments. */
1317 else if (*json == '\"') {
1318 *into++ = *json++;
1319 while (*json && *json != '\"') {
1320 if (*json == '\\')
1321 *into++ = *json++;
1322 *into++ = *json++;
1323 }
1324 *into++ = *json++;
1325 } /* string literals, which are \" sensitive. */
1326 else
1327 *into++ = *json++; /* All other characters. */
1328 }
1329 *into = 0; /* and null-terminate. */
Jon Ashburn752e06e2015-06-29 11:25:34 -06001330}