blob: fc3ba049423f39f8564ccf2a841c69fd6fcb3ace [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
Jon Ashburn1c75aec2016-02-02 17:47:28 -070091/* Parse the input text to generate a number, and populate the result into item.
92 */
93static const char *parse_number(cJSON *item, const char *num) {
94 double n = 0, sign = 1, scale = 0;
95 int subscale = 0, signsubscale = 1;
Jon Ashburn752e06e2015-06-29 11:25:34 -060096
Jon Ashburn1c75aec2016-02-02 17:47:28 -070097 if (*num == '-')
98 sign = -1, num++; /* Has sign? */
99 if (*num == '0')
100 num++; /* is zero */
101 if (*num >= '1' && *num <= '9')
102 do
103 n = (n * 10.0) + (*num++ - '0');
104 while (*num >= '0' && *num <= '9'); /* Number? */
105 if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
106 num++;
107 do
108 n = (n * 10.0) + (*num++ - '0'), scale--;
109 while (*num >= '0' && *num <= '9');
110 } /* Fractional part? */
111 if (*num == 'e' || *num == 'E') /* Exponent? */
112 {
113 num++;
114 if (*num == '+')
115 num++;
116 else if (*num == '-')
117 signsubscale = -1, num++; /* With sign? */
118 while (*num >= '0' && *num <= '9')
119 subscale = (subscale * 10) + (*num++ - '0'); /* Number? */
120 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600121
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700122 n = sign * n *
123 pow(10.0, (scale + subscale * signsubscale)); /* number = +/-
124 number.fraction *
125 10^+/- exponent */
126
127 item->valuedouble = n;
128 item->valueint = (int)n;
129 item->type = cJSON_Number;
130 return num;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600131}
132
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700133static size_t pow2gt(size_t x) {
134 --x;
135 x |= x >> 1;
136 x |= x >> 2;
137 x |= x >> 4;
138 x |= x >> 8;
139 x |= x >> 16;
140 return x + 1;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600141}
142
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700143typedef struct {
144 char *buffer;
145 size_t length;
146 size_t offset;
147} printbuffer;
148
149static char *ensure(printbuffer *p, size_t needed) {
150 char *newbuffer;
151 size_t newsize;
152 if (!p || !p->buffer)
153 return 0;
154 needed += p->offset;
155 if (needed <= p->length)
156 return p->buffer + p->offset;
157
158 newsize = pow2gt(needed);
159 newbuffer = (char *)cJSON_malloc(newsize);
160 if (!newbuffer) {
161 cJSON_free(p->buffer);
162 p->length = 0, p->buffer = 0;
163 return 0;
164 }
165 if (newbuffer)
166 memcpy(newbuffer, p->buffer, p->length);
167 cJSON_free(p->buffer);
168 p->length = newsize;
169 p->buffer = newbuffer;
170 return newbuffer + p->offset;
171}
172
173static size_t update(printbuffer *p) {
174 char *str;
175 if (!p || !p->buffer)
176 return 0;
177 str = p->buffer + p->offset;
178 return p->offset + strlen(str);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600179}
180
181/* Render the number nicely from the given item into a string. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700182static char *print_number(cJSON *item, printbuffer *p) {
183 char *str = 0;
184 double d = item->valuedouble;
185 if (d == 0) {
186 if (p)
187 str = ensure(p, 2);
188 else
189 str = (char *)cJSON_malloc(2); /* special case for 0. */
190 if (str)
191 strcpy(str, "0");
192 } else if (fabs(((double)item->valueint) - d) <= DBL_EPSILON &&
193 d <= INT_MAX && d >= INT_MIN) {
194 if (p)
195 str = ensure(p, 21);
196 else
197 str = (char *)cJSON_malloc(
198 21); /* 2^64+1 can be represented in 21 chars. */
199 if (str)
200 sprintf(str, "%d", item->valueint);
201 } else {
202 if (p)
203 str = ensure(p, 64);
204 else
205 str = (char *)cJSON_malloc(64); /* This is a nice tradeoff. */
206 if (str) {
207 if (fabs(floor(d) - d) <= DBL_EPSILON && fabs(d) < 1.0e60)
208 sprintf(str, "%.0f", d);
209 else if (fabs(d) < 1.0e-6 || fabs(d) > 1.0e9)
210 sprintf(str, "%e", d);
211 else
212 sprintf(str, "%f", d);
213 }
214 }
215 return str;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600216}
217
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700218static unsigned parse_hex4(const char *str) {
219 unsigned h = 0;
220 if (*str >= '0' && *str <= '9')
221 h += (*str) - '0';
222 else if (*str >= 'A' && *str <= 'F')
223 h += 10 + (*str) - 'A';
224 else if (*str >= 'a' && *str <= 'f')
225 h += 10 + (*str) - 'a';
226 else
227 return 0;
228 h = h << 4;
229 str++;
230 if (*str >= '0' && *str <= '9')
231 h += (*str) - '0';
232 else if (*str >= 'A' && *str <= 'F')
233 h += 10 + (*str) - 'A';
234 else if (*str >= 'a' && *str <= 'f')
235 h += 10 + (*str) - 'a';
236 else
237 return 0;
238 h = h << 4;
239 str++;
240 if (*str >= '0' && *str <= '9')
241 h += (*str) - '0';
242 else if (*str >= 'A' && *str <= 'F')
243 h += 10 + (*str) - 'A';
244 else if (*str >= 'a' && *str <= 'f')
245 h += 10 + (*str) - 'a';
246 else
247 return 0;
248 h = h << 4;
249 str++;
250 if (*str >= '0' && *str <= '9')
251 h += (*str) - '0';
252 else if (*str >= 'A' && *str <= 'F')
253 h += 10 + (*str) - 'A';
254 else if (*str >= 'a' && *str <= 'f')
255 h += 10 + (*str) - 'a';
256 else
257 return 0;
258 return h;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600259}
260
261/* Parse the input text into an unescaped cstring, and populate item. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700262static const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0,
263 0xF0, 0xF8, 0xFC};
264static const char *parse_string(cJSON *item, const char *str) {
265 const char *ptr = str + 1;
266 char *ptr2;
267 char *out;
268 int len = 0;
269 unsigned uc, uc2;
270 if (*str != '\"') {
271 ep = str;
272 return 0;
273 } /* not a string! */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600274
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700275 while (*ptr != '\"' && *ptr && ++len)
276 if (*ptr++ == '\\')
277 ptr++; /* Skip escaped quotes. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600278
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700279 out = (char *)cJSON_malloc(
280 len + 1); /* This is how long we need for the string, roughly. */
281 if (!out)
282 return 0;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600283
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700284 ptr = str + 1;
285 ptr2 = out;
286 while (*ptr != '\"' && *ptr) {
287 if (*ptr != '\\')
288 *ptr2++ = *ptr++;
289 else {
290 ptr++;
291 switch (*ptr) {
292 case 'b':
293 *ptr2++ = '\b';
294 break;
295 case 'f':
296 *ptr2++ = '\f';
297 break;
298 case 'n':
299 *ptr2++ = '\n';
300 break;
301 case 'r':
302 *ptr2++ = '\r';
303 break;
304 case 't':
305 *ptr2++ = '\t';
306 break;
307 case 'u': /* transcode utf16 to utf8. */
308 uc = parse_hex4(ptr + 1);
309 ptr += 4; /* get the unicode char. */
310
311 if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0)
312 break; /* check for invalid. */
313
314 if (uc >= 0xD800 &&
315 uc <= 0xDBFF) /* UTF16 surrogate pairs. */
316 {
317 if (ptr[1] != '\\' || ptr[2] != 'u')
318 break; /* missing second-half of surrogate. */
319 uc2 = parse_hex4(ptr + 3);
320 ptr += 6;
321 if (uc2 < 0xDC00 || uc2 > 0xDFFF)
322 break; /* invalid second-half of surrogate. */
323 uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));
324 }
325
326 len = 4;
327 if (uc < 0x80)
328 len = 1;
329 else if (uc < 0x800)
330 len = 2;
331 else if (uc < 0x10000)
332 len = 3;
333 ptr2 += len;
334
335 switch (len) {
336 case 4:
337 *--ptr2 = ((uc | 0x80) & 0xBF);
338 uc >>= 6;
339 case 3:
340 *--ptr2 = ((uc | 0x80) & 0xBF);
341 uc >>= 6;
342 case 2:
343 *--ptr2 = ((uc | 0x80) & 0xBF);
344 uc >>= 6;
345 case 1:
Karl Schultz3fd3d092016-02-24 14:39:39 -0700346 *--ptr2 = ((unsigned char)uc | firstByteMark[len]);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700347 }
348 ptr2 += len;
349 break;
350 default:
351 *ptr2++ = *ptr;
352 break;
353 }
354 ptr++;
355 }
356 }
357 *ptr2 = 0;
358 if (*ptr == '\"')
359 ptr++;
360 item->valuestring = out;
361 item->type = cJSON_String;
362 return ptr;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600363}
364
365/* Render the cstring provided to an escaped version that can be printed. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700366static char *print_string_ptr(const char *str, printbuffer *p) {
367 const char *ptr;
368 char *ptr2;
369 char *out;
370 size_t len = 0, flag = 0;
371 unsigned char token;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600372
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700373 for (ptr = str; *ptr; ptr++)
374 flag |= ((*ptr > 0 && *ptr < 32) || (*ptr == '\"') || (*ptr == '\\'))
375 ? 1
376 : 0;
377 if (!flag) {
378 len = ptr - str;
379 if (p)
380 out = ensure(p, len + 3);
381 else
382 out = (char *)cJSON_malloc(len + 3);
383 if (!out)
384 return 0;
385 ptr2 = out;
386 *ptr2++ = '\"';
387 strcpy(ptr2, str);
388 ptr2[len] = '\"';
389 ptr2[len + 1] = 0;
390 return out;
391 }
392
393 if (!str) {
394 if (p)
395 out = ensure(p, 3);
396 else
397 out = (char *)cJSON_malloc(3);
398 if (!out)
399 return 0;
400 strcpy(out, "\"\"");
401 return out;
402 }
403 ptr = str;
404 while ((token = *ptr) && ++len) {
405 if (strchr("\"\\\b\f\n\r\t", token))
406 len++;
407 else if (token < 32)
408 len += 5;
409 ptr++;
410 }
411
412 if (p)
413 out = ensure(p, len + 3);
414 else
415 out = (char *)cJSON_malloc(len + 3);
416 if (!out)
417 return 0;
418
419 ptr2 = out;
420 ptr = str;
421 *ptr2++ = '\"';
422 while (*ptr) {
423 if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\')
424 *ptr2++ = *ptr++;
425 else {
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700426 switch (token = *ptr++) {
427 case '\\':
428 *ptr2++ = '\\';
429 break;
430 case '\"':
431 *ptr2++ = '\"';
432 break;
433 case '\b':
Mark Young64d6ee12016-06-14 14:59:44 -0600434 *ptr2++ = '\b';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700435 break;
436 case '\f':
Mark Young64d6ee12016-06-14 14:59:44 -0600437 *ptr2++ = '\f';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700438 break;
439 case '\n':
Mark Young64d6ee12016-06-14 14:59:44 -0600440 *ptr2++ = '\n';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700441 break;
442 case '\r':
Mark Young64d6ee12016-06-14 14:59:44 -0600443 *ptr2++ = '\r';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700444 break;
445 case '\t':
Mark Young64d6ee12016-06-14 14:59:44 -0600446 *ptr2++ = '\t';
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700447 break;
448 default:
449 sprintf(ptr2, "u%04x", token);
450 ptr2 += 5;
451 break; /* escape and print */
452 }
453 }
454 }
455 *ptr2++ = '\"';
456 *ptr2++ = 0;
457 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600458}
459/* Invote print_string_ptr (which is useful) on an item. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700460static char *print_string(cJSON *item, printbuffer *p) {
461 return print_string_ptr(item->valuestring, p);
462}
Jon Ashburn752e06e2015-06-29 11:25:34 -0600463
464/* Predeclare these prototypes. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700465static const char *parse_value(cJSON *item, const char *value);
466static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p);
467static const char *parse_array(cJSON *item, const char *value);
468static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p);
469static const char *parse_object(cJSON *item, const char *value);
470static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600471
472/* Utility to jump whitespace and cr/lf */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700473static const char *skip(const char *in) {
474 while (in && *in && (unsigned char)*in <= 32)
475 in++;
476 return in;
477}
Jon Ashburn752e06e2015-06-29 11:25:34 -0600478
479/* Parse an object - create a new root, and populate. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700480cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end,
481 int require_null_terminated) {
482 const char *end = 0;
483 cJSON *c = cJSON_New_Item();
484 ep = 0;
485 if (!c)
486 return 0; /* memory fail */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600487
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700488 end = parse_value(c, skip(value));
489 if (!end) {
490 cJSON_Delete(c);
491 return 0;
492 } /* parse failure. ep is set. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600493
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700494 /* if we require null-terminated JSON without appended garbage, skip and
495 * then check for a null terminator */
496 if (require_null_terminated) {
497 end = skip(end);
498 if (*end) {
499 cJSON_Delete(c);
500 ep = end;
501 return 0;
502 }
503 }
504 if (return_parse_end)
505 *return_parse_end = end;
506 return c;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600507}
508/* Default options for cJSON_Parse */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700509cJSON *cJSON_Parse(const char *value) {
510 return cJSON_ParseWithOpts(value, 0, 0);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600511}
512
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700513/* Render a cJSON item/entity/structure to text. */
514char *cJSON_Print(cJSON *item) { return print_value(item, 0, 1, 0); }
515char *cJSON_PrintUnformatted(cJSON *item) { return print_value(item, 0, 0, 0); }
516
517char *cJSON_PrintBuffered(cJSON *item, int prebuffer, int fmt) {
518 printbuffer p;
519 p.buffer = (char *)cJSON_malloc(prebuffer);
520 p.length = prebuffer;
521 p.offset = 0;
522 return print_value(item, 0, fmt, &p);
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700523}
Jon Ashburn752e06e2015-06-29 11:25:34 -0600524
525/* Parser core - when encountering text, process appropriately. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700526static const char *parse_value(cJSON *item, const char *value) {
527 if (!value)
528 return 0; /* Fail on null. */
529 if (!strncmp(value, "null", 4)) {
530 item->type = cJSON_NULL;
531 return value + 4;
532 }
533 if (!strncmp(value, "false", 5)) {
534 item->type = cJSON_False;
535 return value + 5;
536 }
537 if (!strncmp(value, "true", 4)) {
538 item->type = cJSON_True;
539 item->valueint = 1;
540 return value + 4;
541 }
542 if (*value == '\"') {
543 return parse_string(item, value);
544 }
545 if (*value == '-' || (*value >= '0' && *value <= '9')) {
546 return parse_number(item, value);
547 }
548 if (*value == '[') {
549 return parse_array(item, value);
550 }
551 if (*value == '{') {
552 return parse_object(item, value);
553 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600554
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700555 ep = value;
556 return 0; /* failure. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600557}
558
559/* Render a value to text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700560static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p) {
561 char *out = 0;
562 if (!item)
563 return 0;
564 if (p) {
565 switch ((item->type) & 255) {
566 case cJSON_NULL: {
567 out = ensure(p, 5);
568 if (out)
569 strcpy(out, "null");
570 break;
571 }
572 case cJSON_False: {
573 out = ensure(p, 6);
574 if (out)
575 strcpy(out, "false");
576 break;
577 }
578 case cJSON_True: {
579 out = ensure(p, 5);
580 if (out)
581 strcpy(out, "true");
582 break;
583 }
584 case cJSON_Number:
585 out = print_number(item, p);
586 break;
587 case cJSON_String:
588 out = print_string(item, p);
589 break;
590 case cJSON_Array:
591 out = print_array(item, depth, fmt, p);
592 break;
593 case cJSON_Object:
594 out = print_object(item, depth, fmt, p);
595 break;
596 }
597 } else {
598 switch ((item->type) & 255) {
599 case cJSON_NULL:
600 out = cJSON_strdup("null");
601 break;
602 case cJSON_False:
603 out = cJSON_strdup("false");
604 break;
605 case cJSON_True:
606 out = cJSON_strdup("true");
607 break;
608 case cJSON_Number:
609 out = print_number(item, 0);
610 break;
611 case cJSON_String:
612 out = print_string(item, 0);
613 break;
614 case cJSON_Array:
615 out = print_array(item, depth, fmt, 0);
616 break;
617 case cJSON_Object:
618 out = print_object(item, depth, fmt, 0);
619 break;
620 }
621 }
622 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600623}
624
625/* Build an array from input text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700626static const char *parse_array(cJSON *item, const char *value) {
627 cJSON *child;
628 if (*value != '[') {
629 ep = value;
630 return 0;
631 } /* not an array! */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600632
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700633 item->type = cJSON_Array;
634 value = skip(value + 1);
635 if (*value == ']')
636 return value + 1; /* empty array. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600637
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700638 item->child = child = cJSON_New_Item();
639 if (!item->child)
640 return 0; /* memory fail */
641 value = skip(
642 parse_value(child, skip(value))); /* skip any spacing, get the value. */
643 if (!value)
644 return 0;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600645
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700646 while (*value == ',') {
647 cJSON *new_item;
648 if (!(new_item = cJSON_New_Item()))
649 return 0; /* memory fail */
650 child->next = new_item;
651 new_item->prev = child;
652 child = new_item;
653 value = skip(parse_value(child, skip(value + 1)));
654 if (!value)
655 return 0; /* memory fail */
656 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600657
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700658 if (*value == ']')
659 return value + 1; /* end of array */
660 ep = value;
661 return 0; /* malformed. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600662}
663
664/* Render an array to text */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700665static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p) {
666 char **entries;
667 char *out = 0, *ptr, *ret;
668 size_t len = 5;
669 cJSON *child = item->child;
670 int numentries = 0, fail = 0, j = 0;
671 size_t tmplen = 0, i = 0;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600672
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700673 /* How many entries in the array? */
674 while (child)
675 numentries++, child = child->next;
676 /* Explicitly handle numentries==0 */
677 if (!numentries) {
678 if (p)
679 out = ensure(p, 3);
680 else
681 out = (char *)cJSON_malloc(3);
682 if (out)
683 strcpy(out, "[]");
684 return out;
685 }
Jon Ashburn752e06e2015-06-29 11:25:34 -0600686
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700687 if (p) {
688 /* Compose the output array. */
689 i = p->offset;
690 ptr = ensure(p, 1);
691 if (!ptr)
692 return 0;
693 *ptr = '[';
694 p->offset++;
695 child = item->child;
696 while (child && !fail) {
697 print_value(child, depth + 1, fmt, p);
698 p->offset = update(p);
699 if (child->next) {
700 len = fmt ? 2 : 1;
701 ptr = ensure(p, len + 1);
702 if (!ptr)
703 return 0;
704 *ptr++ = ',';
705 if (fmt)
706 *ptr++ = ' ';
707 *ptr = 0;
708 p->offset += len;
709 }
710 child = child->next;
711 }
712 ptr = ensure(p, 2);
713 if (!ptr)
714 return 0;
715 *ptr++ = ']';
716 *ptr = 0;
717 out = (p->buffer) + i;
718 } else {
719 /* Allocate an array to hold the values for each */
720 entries = (char **)cJSON_malloc(numentries * sizeof(char *));
721 if (!entries)
722 return 0;
723 memset(entries, 0, numentries * sizeof(char *));
724 /* Retrieve all the results: */
725 child = item->child;
726 while (child && !fail) {
727 ret = print_value(child, depth + 1, fmt, 0);
728 entries[i++] = ret;
729 if (ret)
730 len += strlen(ret) + 2 + (fmt ? 1 : 0);
731 else
732 fail = 1;
733 child = child->next;
734 }
735
736 /* If we didn't fail, try to malloc the output string */
737 if (!fail)
738 out = (char *)cJSON_malloc(len);
739 /* If that fails, we fail. */
740 if (!out)
741 fail = 1;
742
743 /* Handle failure. */
744 if (fail) {
745 for (j = 0; j < numentries; j++)
746 if (entries[j])
747 cJSON_free(entries[j]);
748 cJSON_free(entries);
749 return 0;
750 }
751
752 /* Compose the output array. */
753 *out = '[';
754 ptr = out + 1;
755 *ptr = 0;
756 for (j = 0; j < numentries; j++) {
757 tmplen = strlen(entries[j]);
758 memcpy(ptr, entries[j], tmplen);
759 ptr += tmplen;
760 if (j != numentries - 1) {
761 *ptr++ = ',';
762 if (fmt)
763 *ptr++ = ' ';
764 *ptr = 0;
765 }
766 cJSON_free(entries[j]);
767 }
768 cJSON_free(entries);
769 *ptr++ = ']';
770 *ptr++ = 0;
771 }
772 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600773}
774
775/* Build an object from the text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700776static const char *parse_object(cJSON *item, const char *value) {
777 cJSON *child;
778 if (*value != '{') {
779 ep = value;
780 return 0;
781 } /* not an object! */
782
783 item->type = cJSON_Object;
784 value = skip(value + 1);
785 if (*value == '}')
786 return value + 1; /* empty array. */
787
788 item->child = child = cJSON_New_Item();
789 if (!item->child)
790 return 0;
791 value = skip(parse_string(child, skip(value)));
792 if (!value)
793 return 0;
794 child->string = child->valuestring;
795 child->valuestring = 0;
796 if (*value != ':') {
797 ep = value;
798 return 0;
799 } /* fail! */
800 value = skip(parse_value(
801 child, skip(value + 1))); /* skip any spacing, get the value. */
802 if (!value)
803 return 0;
804
805 while (*value == ',') {
806 cJSON *new_item;
807 if (!(new_item = cJSON_New_Item()))
808 return 0; /* memory fail */
809 child->next = new_item;
810 new_item->prev = child;
811 child = new_item;
812 value = skip(parse_string(child, skip(value + 1)));
813 if (!value)
814 return 0;
815 child->string = child->valuestring;
816 child->valuestring = 0;
817 if (*value != ':') {
818 ep = value;
819 return 0;
820 } /* fail! */
821 value = skip(parse_value(
822 child, skip(value + 1))); /* skip any spacing, get the value. */
823 if (!value)
824 return 0;
825 }
826
827 if (*value == '}')
828 return value + 1; /* end of array */
829 ep = value;
830 return 0; /* malformed. */
Jon Ashburn752e06e2015-06-29 11:25:34 -0600831}
832
833/* Render an object to text. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700834static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p) {
835 char **entries = 0, **names = 0;
836 char *out = 0, *ptr, *ret, *str;
837 int j;
838 cJSON *child = item->child;
839 int numentries = 0, fail = 0, k;
840 size_t tmplen = 0, i = 0, len = 7;
841 /* Count the number of entries. */
842 while (child)
843 numentries++, child = child->next;
844 /* Explicitly handle empty object case */
845 if (!numentries) {
846 if (p)
847 out = ensure(p, fmt ? depth + 4 : 3);
848 else
849 out = (char *)cJSON_malloc(fmt ? depth + 4 : 3);
850 if (!out)
851 return 0;
852 ptr = out;
853 *ptr++ = '{';
854 if (fmt) {
855 *ptr++ = '\n';
856 for (j = 0; j < depth - 1; j++)
857 *ptr++ = '\t';
858 }
859 *ptr++ = '}';
860 *ptr++ = 0;
861 return out;
862 }
863 if (p) {
864 /* Compose the output: */
865 i = p->offset;
866 len = fmt ? 2 : 1;
867 ptr = ensure(p, len + 1);
868 if (!ptr)
869 return 0;
870 *ptr++ = '{';
871 if (fmt)
872 *ptr++ = '\n';
873 *ptr = 0;
874 p->offset += len;
875 child = item->child;
876 depth++;
877 while (child) {
878 if (fmt) {
879 ptr = ensure(p, depth);
880 if (!ptr)
881 return 0;
882 for (j = 0; j < depth; j++)
883 *ptr++ = '\t';
884 p->offset += depth;
885 }
886 print_string_ptr(child->string, p);
887 p->offset = update(p);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600888
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700889 len = fmt ? 2 : 1;
890 ptr = ensure(p, len);
891 if (!ptr)
892 return 0;
893 *ptr++ = ':';
894 if (fmt)
895 *ptr++ = '\t';
896 p->offset += len;
Jon Ashburn752e06e2015-06-29 11:25:34 -0600897
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700898 print_value(child, depth, fmt, p);
899 p->offset = update(p);
Jon Ashburn752e06e2015-06-29 11:25:34 -0600900
Jon Ashburn1c75aec2016-02-02 17:47:28 -0700901 len = (fmt ? 1 : 0) + (child->next ? 1 : 0);
902 ptr = ensure(p, len + 1);
903 if (!ptr)
904 return 0;
905 if (child->next)
906 *ptr++ = ',';
907 if (fmt)
908 *ptr++ = '\n';
909 *ptr = 0;
910 p->offset += len;
911 child = child->next;
912 }
913 ptr = ensure(p, fmt ? (depth + 1) : 2);
914 if (!ptr)
915 return 0;
916 if (fmt)
917 for (j = 0; j < depth - 1; j++)
918 *ptr++ = '\t';
919 *ptr++ = '}';
920 *ptr = 0;
921 out = (p->buffer) + i;
922 } else {
923 /* Allocate space for the names and the objects */
924 entries = (char **)cJSON_malloc(numentries * sizeof(char *));
925 if (!entries)
926 return 0;
927 names = (char **)cJSON_malloc(numentries * sizeof(char *));
928 if (!names) {
929 cJSON_free(entries);
930 return 0;
931 }
932 memset(entries, 0, sizeof(char *) * numentries);
933 memset(names, 0, sizeof(char *) * numentries);
934
935 /* Collect all the results into our arrays: */
936 child = item->child;
937 depth++;
938 if (fmt)
939 len += depth;
940 while (child) {
941 names[i] = str = print_string_ptr(child->string, 0);
942 entries[i++] = ret = print_value(child, depth, fmt, 0);
943 if (str && ret)
944 len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0);
945 else
946 fail = 1;
947 child = child->next;
948 }
949
950 /* Try to allocate the output string */
951 if (!fail)
952 out = (char *)cJSON_malloc(len);
953 if (!out)
954 fail = 1;
955
956 /* Handle failure */
957 if (fail) {
958 for (j = 0; j < numentries; j++) {
959 if (names[i])
960 cJSON_free(names[j]);
961 if (entries[j])
962 cJSON_free(entries[j]);
963 }
964 cJSON_free(names);
965 cJSON_free(entries);
966 return 0;
967 }
968
969 /* Compose the output: */
970 *out = '{';
971 ptr = out + 1;
972 if (fmt)
973 *ptr++ = '\n';
974 *ptr = 0;
975 for (j = 0; j < numentries; j++) {
976 if (fmt)
977 for (k = 0; k < depth; k++)
978 *ptr++ = '\t';
979 tmplen = strlen(names[j]);
980 memcpy(ptr, names[j], tmplen);
981 ptr += tmplen;
982 *ptr++ = ':';
983 if (fmt)
984 *ptr++ = '\t';
985 strcpy(ptr, entries[j]);
986 ptr += strlen(entries[j]);
987 if (j != numentries - 1)
988 *ptr++ = ',';
989 if (fmt)
990 *ptr++ = '\n';
991 *ptr = 0;
992 cJSON_free(names[j]);
993 cJSON_free(entries[j]);
994 }
995
996 cJSON_free(names);
997 cJSON_free(entries);
998 if (fmt)
999 for (j = 0; j < depth - 1; j++)
1000 *ptr++ = '\t';
1001 *ptr++ = '}';
1002 *ptr++ = 0;
1003 }
1004 return out;
Jon Ashburn752e06e2015-06-29 11:25:34 -06001005}
1006
1007/* Get Array size/item / object item. */
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001008int cJSON_GetArraySize(cJSON *array) {
1009 cJSON *c = array->child;
1010 int i = 0;
1011 while (c)
1012 i++, c = c->next;
1013 return i;
1014}
1015cJSON *cJSON_GetArrayItem(cJSON *array, int item) {
1016 cJSON *c = array->child;
1017 while (c && item > 0)
1018 item--, c = c->next;
1019 return c;
1020}
1021cJSON *cJSON_GetObjectItem(cJSON *object, const char *string) {
1022 cJSON *c = object->child;
1023 while (c && strcmp(c->string, string))
1024 c = c->next;
1025 return c;
Jon Ashburn752e06e2015-06-29 11:25:34 -06001026}
1027
Jon Ashburn1c75aec2016-02-02 17:47:28 -07001028/* Utility for array list handling. */
1029static void suffix_object(cJSON *prev, cJSON *item) {
1030 prev->next = item;
1031 item->prev = prev;
1032}
1033/* Utility for handling references. */
1034static cJSON *create_reference(cJSON *item) {
1035 cJSON *ref = cJSON_New_Item();
1036 if (!ref)
1037 return 0;
1038 memcpy(ref, item, sizeof(cJSON));
1039 ref->string = 0;
1040 ref->type |= cJSON_IsReference;
1041 ref->next = ref->prev = 0;
1042 return ref;
1043}
1044
1045/* Add item to array/object. */
1046void cJSON_AddItemToArray(cJSON *array, cJSON *item) {
1047 cJSON *c = array->child;
1048 if (!item)
1049 return;
1050 if (!c) {
1051 array->child = item;
1052 } else {
1053 while (c && c->next)
1054 c = c->next;
1055 suffix_object(c, item);
1056 }
1057}
1058void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) {
1059 if (!item)
1060 return;
1061 if (item->string)
1062 cJSON_free(item->string);
1063 item->string = cJSON_strdup(string);
1064 cJSON_AddItemToArray(object, item);
1065}
1066void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) {
1067 if (!item)
1068 return;
1069 if (!(item->type & cJSON_StringIsConst) && item->string)
1070 cJSON_free(item->string);
1071 item->string = (char *)string;
1072 item->type |= cJSON_StringIsConst;
1073 cJSON_AddItemToArray(object, item);
1074}
1075void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {
1076 cJSON_AddItemToArray(array, create_reference(item));
1077}
1078void cJSON_AddItemReferenceToObject(cJSON *object, const char *string,
1079 cJSON *item) {
1080 cJSON_AddItemToObject(object, string, create_reference(item));
1081}
1082
1083cJSON *cJSON_DetachItemFromArray(cJSON *array, int which) {
1084 cJSON *c = array->child;
1085 while (c && which > 0)
1086 c = c->next, which--;
1087 if (!c)
1088 return 0;
1089 if (c->prev)
1090 c->prev->next = c->next;
1091 if (c->next)
1092 c->next->prev = c->prev;
1093 if (c == array->child)
1094 array->child = c->next;
1095 c->prev = c->next = 0;
1096 return c;
1097}
1098void cJSON_DeleteItemFromArray(cJSON *array, int which) {
1099 cJSON_Delete(cJSON_DetachItemFromArray(array, which));
1100}
1101cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string) {
1102 int i = 0;
1103 cJSON *c = object->child;
1104 while (c && strcmp(c->string, string))
1105 i++, c = c->next;
1106 if (c)
1107 return cJSON_DetachItemFromArray(object, i);
1108 return 0;
1109}
1110void cJSON_DeleteItemFromObject(cJSON *object, const char *string) {
1111 cJSON_Delete(cJSON_DetachItemFromObject(object, string));
1112}
1113
1114/* Replace array/object items with new ones. */
1115void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) {
1116 cJSON *c = array->child;
1117 while (c && which > 0)
1118 c = c->next, which--;
1119 if (!c) {
1120 cJSON_AddItemToArray(array, newitem);
1121 return;
1122 }
1123 newitem->next = c;
1124 newitem->prev = c->prev;
1125 c->prev = newitem;
1126 if (c == array->child)
1127 array->child = newitem;
1128 else
1129 newitem->prev->next = newitem;
1130}
1131void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) {
1132 cJSON *c = array->child;
1133 while (c && which > 0)
1134 c = c->next, which--;
1135 if (!c)
1136 return;
1137 newitem->next = c->next;
1138 newitem->prev = c->prev;
1139 if (newitem->next)
1140 newitem->next->prev = newitem;
1141 if (c == array->child)
1142 array->child = newitem;
1143 else
1144 newitem->prev->next = newitem;
1145 c->next = c->prev = 0;
1146 cJSON_Delete(c);
1147}
1148void cJSON_ReplaceItemInObject(cJSON *object, const char *string,
1149 cJSON *newitem) {
1150 int i = 0;
1151 cJSON *c = object->child;
1152 while (c && strcmp(c->string, string))
1153 i++, c = c->next;
1154 if (c) {
1155 newitem->string = cJSON_strdup(string);
1156 cJSON_ReplaceItemInArray(object, i, newitem);
1157 }
1158}
1159
1160/* Create basic types: */
1161cJSON *cJSON_CreateNull(void) {
1162 cJSON *item = cJSON_New_Item();
1163 if (item)
1164 item->type = cJSON_NULL;
1165 return item;
1166}
1167cJSON *cJSON_CreateTrue(void) {
1168 cJSON *item = cJSON_New_Item();
1169 if (item)
1170 item->type = cJSON_True;
1171 return item;
1172}
1173cJSON *cJSON_CreateFalse(void) {
1174 cJSON *item = cJSON_New_Item();
1175 if (item)
1176 item->type = cJSON_False;
1177 return item;
1178}
1179cJSON *cJSON_CreateBool(int b) {
1180 cJSON *item = cJSON_New_Item();
1181 if (item)
1182 item->type = b ? cJSON_True : cJSON_False;
1183 return item;
1184}
1185cJSON *cJSON_CreateNumber(double num) {
1186 cJSON *item = cJSON_New_Item();
1187 if (item) {
1188 item->type = cJSON_Number;
1189 item->valuedouble = num;
1190 item->valueint = (int)num;
1191 }
1192 return item;
1193}
1194cJSON *cJSON_CreateString(const char *string) {
1195 cJSON *item = cJSON_New_Item();
1196 if (item) {
1197 item->type = cJSON_String;
1198 item->valuestring = cJSON_strdup(string);
1199 }
1200 return item;
1201}
1202cJSON *cJSON_CreateArray(void) {
1203 cJSON *item = cJSON_New_Item();
1204 if (item)
1205 item->type = cJSON_Array;
1206 return item;
1207}
1208cJSON *cJSON_CreateObject(void) {
1209 cJSON *item = cJSON_New_Item();
1210 if (item)
1211 item->type = cJSON_Object;
1212 return item;
1213}
1214
1215/* Create Arrays: */
1216cJSON *cJSON_CreateIntArray(const int *numbers, int count) {
1217 int i;
1218 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1219 for (i = 0; a && i < count; i++) {
1220 n = cJSON_CreateNumber(numbers[i]);
1221 if (!i)
1222 a->child = n;
1223 else
1224 suffix_object(p, n);
1225 p = n;
1226 }
1227 return a;
1228}
1229cJSON *cJSON_CreateFloatArray(const float *numbers, int count) {
1230 int i;
1231 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1232 for (i = 0; a && i < count; i++) {
1233 n = cJSON_CreateNumber(numbers[i]);
1234 if (!i)
1235 a->child = n;
1236 else
1237 suffix_object(p, n);
1238 p = n;
1239 }
1240 return a;
1241}
1242cJSON *cJSON_CreateDoubleArray(const double *numbers, int count) {
1243 int i;
1244 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1245 for (i = 0; a && i < count; i++) {
1246 n = cJSON_CreateNumber(numbers[i]);
1247 if (!i)
1248 a->child = n;
1249 else
1250 suffix_object(p, n);
1251 p = n;
1252 }
1253 return a;
1254}
1255cJSON *cJSON_CreateStringArray(const char **strings, int count) {
1256 int i;
1257 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1258 for (i = 0; a && i < count; i++) {
1259 n = cJSON_CreateString(strings[i]);
1260 if (!i)
1261 a->child = n;
1262 else
1263 suffix_object(p, n);
1264 p = n;
1265 }
1266 return a;
1267}
1268
1269/* Duplication */
1270cJSON *cJSON_Duplicate(cJSON *item, int recurse) {
1271 cJSON *newitem, *cptr, *nptr = 0, *newchild;
1272 /* Bail on bad ptr */
1273 if (!item)
1274 return 0;
1275 /* Create new item */
1276 newitem = cJSON_New_Item();
1277 if (!newitem)
1278 return 0;
1279 /* Copy over all vars */
1280 newitem->type = item->type & (~cJSON_IsReference),
1281 newitem->valueint = item->valueint,
1282 newitem->valuedouble = item->valuedouble;
1283 if (item->valuestring) {
1284 newitem->valuestring = cJSON_strdup(item->valuestring);
1285 if (!newitem->valuestring) {
1286 cJSON_Delete(newitem);
1287 return 0;
1288 }
1289 }
1290 if (item->string) {
1291 newitem->string = cJSON_strdup(item->string);
1292 if (!newitem->string) {
1293 cJSON_Delete(newitem);
1294 return 0;
1295 }
1296 }
1297 /* If non-recursive, then we're done! */
1298 if (!recurse)
1299 return newitem;
1300 /* Walk the ->next chain for the child. */
1301 cptr = item->child;
1302 while (cptr) {
1303 newchild = cJSON_Duplicate(
1304 cptr,
1305 1); /* Duplicate (with recurse) each item in the ->next chain */
1306 if (!newchild) {
1307 cJSON_Delete(newitem);
1308 return 0;
1309 }
1310 if (nptr) {
1311 nptr->next = newchild, newchild->prev = nptr;
1312 nptr = newchild;
1313 } /* If newitem->child already set, then crosswire ->prev and ->next and
1314 move on */
1315 else {
1316 newitem->child = newchild;
1317 nptr = newchild;
1318 } /* Set newitem->child and move to it */
1319 cptr = cptr->next;
1320 }
1321 return newitem;
1322}
1323
1324void cJSON_Minify(char *json) {
1325 char *into = json;
1326 while (*json) {
1327 if (*json == ' ')
1328 json++;
1329 else if (*json == '\t')
1330 json++; /* Whitespace characters. */
1331 else if (*json == '\r')
1332 json++;
1333 else if (*json == '\n')
1334 json++;
1335 else if (*json == '/' && json[1] == '/')
1336 while (*json && *json != '\n')
1337 json++; /* double-slash comments, to end of line. */
1338 else if (*json == '/' && json[1] == '*') {
1339 while (*json && !(*json == '*' && json[1] == '/'))
1340 json++;
1341 json += 2;
1342 } /* multiline comments. */
1343 else if (*json == '\"') {
1344 *into++ = *json++;
1345 while (*json && *json != '\"') {
1346 if (*json == '\\')
1347 *into++ = *json++;
1348 *into++ = *json++;
1349 }
1350 *into++ = *json++;
1351 } /* string literals, which are \" sensitive. */
1352 else
1353 *into++ = *json++; /* All other characters. */
1354 }
1355 *into = 0; /* and null-terminate. */
Jon Ashburn752e06e2015-06-29 11:25:34 -06001356}