Line data Source code
1 : /* cJSON.c - JSON parser in C.
2 : * Copyright (c) 2009 Dave Gamble
3 : *
4 : * Permission is hereby granted, free of charge, to any person obtaining a copy
5 : * of this software and associated documentation files (the "Software"), to deal
6 : * in the Software without restriction, including without limitation the rights
7 : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : * copies of the Software, and to permit persons to whom the Software is
9 : * furnished to do so, subject to the following conditions:
10 : *
11 : * The above copyright notice and this permission notice shall be included in
12 : * all copies or substantial portions of the Software.
13 : *
14 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : * THE SOFTWARE.
21 : *
22 : * SPDX-License-Identifier: MIT
23 : *
24 : * Note that this code has been modified from the original code taken
25 : * from cjson-code-58.zip before 2014 (my first local commit was in
26 : * 2014 but I may used the code even earlier). Since 2016 the project
27 : * was revived and moved to https://github.com/DaveGamble/cJSON.git.
28 : * It is now a lot more complex and has substantial changes so that it
29 : * is not possible to merge them directly. In any case we only need a
30 : * simple parser and not a complete library. I have looked through
31 : * the commits and fixed a few things which should apply; I also added
32 : * a few references to the upstream code. Regression test are missing!
33 : */
34 :
35 : #ifdef HAVE_CONFIG_H
36 : # include <config.h>
37 : #endif
38 :
39 : #include <string.h>
40 : #include <stdio.h>
41 : #include <math.h>
42 : #include <stdlib.h>
43 : #include <float.h>
44 : #include <limits.h>
45 : #include <ctype.h>
46 : #include <errno.h>
47 :
48 : #include <gpg-error.h>
49 :
50 : #include "cJSON.h"
51 :
52 : /* Only use calloc. */
53 : #define CALLOC_ONLY 1
54 :
55 : /* To avoid that a compiler optimizes certain memset calls away, these
56 : macros may be used instead. */
57 : #define wipememory2(_ptr,_set,_len) do { \
58 : volatile char *_vptr=(volatile char *)(_ptr); \
59 : size_t _vlen=(_len); \
60 : while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
61 : } while(0)
62 : #define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
63 :
64 : /* We use malloc function wrappers from gpgrt (aka libgpg-error). */
65 : #if GPGRT_VERSION_NUMBER >= 0x011c00 /* 1.28 */
66 : # include <gpgrt.h>
67 : # define xtrycalloc(a,b) gpgrt_calloc ((a), (b))
68 : # define xtrystrdup(a) gpgrt_strdup ((a))
69 : # define xfree(a) gpgrt_free ((a))
70 : # if CALLOC_ONLY
71 : # define xtrymalloc(a) gpgrt_calloc (1, (a))
72 : # else
73 : # define xtrymalloc(a) gpgrt_malloc ((a))
74 : # endif
75 : #else /* Without gpgrt (aka libgpg-error). */
76 : # define xtrycalloc(a,b) calloc ((a), (b))
77 : # define xtrystrdup(a) strdup ((a))
78 : # define xfree(a) free ((a))
79 : # if CALLOC_ONLY
80 : # define xtrymalloc(a) calloc (1, (a))
81 : # else
82 : # define xtrymalloc(a) malloc ((a))
83 : # endif
84 : #endif
85 :
86 :
87 : static int
88 0 : cJSON_strcasecmp (const char *s1, const char *s2)
89 : {
90 0 : if (!s1)
91 0 : return (s1 == s2) ? 0 : 1;
92 0 : if (!s2)
93 0 : return 1;
94 0 : for (; tolower (*(const unsigned char *)s1)
95 0 : == tolower (*(const unsigned char *) s2); ++s1, ++s2)
96 0 : if (*s1 == 0)
97 0 : return 0;
98 0 : return tolower (*(const unsigned char *) s1) -
99 0 : tolower (*(const unsigned char *) s2);
100 : }
101 :
102 : /* Internal constructor. */
103 : static cJSON *
104 0 : cJSON_New_Item (void)
105 : {
106 0 : return xtrycalloc (1, sizeof (cJSON));
107 : }
108 :
109 : /* Delete a cJSON structure. (Does not clobber ERRNO). */
110 : void
111 0 : cJSON_Delete (cJSON * c)
112 : {
113 : cJSON *next;
114 : int save_errno;
115 :
116 0 : if (!c)
117 0 : return;
118 :
119 0 : save_errno = errno;
120 0 : while (c)
121 : {
122 0 : next = c->next;
123 0 : if (!(c->type & cJSON_IsReference) && c->child)
124 0 : cJSON_Delete (c->child);
125 0 : if (!(c->type & cJSON_IsReference) && c->valuestring)
126 : {
127 0 : wipememory (c->valuestring, strlen (c->valuestring));
128 0 : xfree (c->valuestring);
129 : }
130 0 : if (c->string)
131 : {
132 0 : wipememory (c->string, strlen (c->string));
133 0 : xfree (c->string);
134 : }
135 0 : xfree (c);
136 0 : c = next;
137 : }
138 0 : errno = save_errno;
139 : }
140 :
141 : /* Parse the input text to generate a number, and populate the result
142 : * into item. */
143 : static const char *
144 0 : parse_number (cJSON * item, const char *num)
145 : {
146 0 : double n = 0, sign = 1, scale = 0;
147 0 : int subscale = 0, signsubscale = 1;
148 :
149 0 : if (*num == '-')
150 0 : sign = -1, num++; /* Has sign? */
151 0 : if (*num == '0')
152 0 : num++; /* is zero */
153 0 : if (*num >= '1' && *num <= '9')
154 : do
155 0 : n = (n * 10.0) + (*num++ - '0');
156 0 : while (*num >= '0' && *num <= '9'); /* Number? */
157 0 : if (*num == '.' && num[1] >= '0' && num[1] <= '9')
158 : {
159 0 : num++;
160 : do
161 0 : n = (n * 10.0) + (*num++ - '0'), scale--;
162 0 : while (*num >= '0' && *num <= '9');
163 : } /* Fractional part? */
164 0 : if (*num == 'e' || *num == 'E') /* Exponent? */
165 : {
166 0 : num++;
167 0 : if (*num == '+')
168 0 : num++;
169 0 : else if (*num == '-')
170 0 : signsubscale = -1, num++; /* With sign? */
171 0 : while (*num >= '0' && *num <= '9')
172 0 : subscale = (subscale * 10) + (*num++ - '0'); /* Number? */
173 : }
174 :
175 : /* number = +/- number.fraction * 10^+/- exponent */
176 0 : n = sign * n * pow (10.0, (scale + subscale * signsubscale));
177 :
178 0 : item->valuedouble = n;
179 0 : item->valueint = (int) n;
180 0 : item->type = cJSON_Number;
181 0 : return num;
182 : }
183 :
184 : /* Render the number nicely from the given item into a string. */
185 : static char *
186 0 : print_number (cJSON * item)
187 : {
188 : char *str;
189 0 : double d = item->valuedouble;
190 0 : if (fabs (((double) item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX
191 0 : && d >= INT_MIN)
192 : {
193 : /* 2^64+1 can be represented in 21 chars. */
194 0 : str = xtrymalloc (21);
195 0 : if (str)
196 0 : sprintf (str, "%d", item->valueint);
197 : }
198 : else
199 : {
200 0 : str = xtrymalloc (64); /* This is a nice tradeoff. */
201 0 : if (str)
202 : {
203 0 : if (fabs (floor (d) - d) <= DBL_EPSILON && fabs (d) < 1.0e60)
204 0 : sprintf (str, "%.0f", d);
205 0 : else if (fabs (d) < 1.0e-6 || fabs (d) > 1.0e9)
206 0 : sprintf (str, "%e", d);
207 : else
208 0 : sprintf (str, "%f", d);
209 : }
210 : }
211 0 : return str;
212 : }
213 :
214 : static unsigned
215 0 : parse_hex4 (const char *str)
216 : {
217 0 : unsigned h = 0;
218 0 : if (*str >= '0' && *str <= '9')
219 0 : h += (*str) - '0';
220 0 : else if (*str >= 'A' && *str <= 'F')
221 0 : h += 10 + (*str) - 'A';
222 0 : else if (*str >= 'a' && *str <= 'f')
223 0 : h += 10 + (*str) - 'a';
224 : else
225 0 : return 0;
226 0 : h = h << 4;
227 0 : str++;
228 0 : if (*str >= '0' && *str <= '9')
229 0 : h += (*str) - '0';
230 0 : else if (*str >= 'A' && *str <= 'F')
231 0 : h += 10 + (*str) - 'A';
232 0 : else if (*str >= 'a' && *str <= 'f')
233 0 : h += 10 + (*str) - 'a';
234 : else
235 0 : return 0;
236 0 : h = h << 4;
237 0 : str++;
238 0 : if (*str >= '0' && *str <= '9')
239 0 : h += (*str) - '0';
240 0 : else if (*str >= 'A' && *str <= 'F')
241 0 : h += 10 + (*str) - 'A';
242 0 : else if (*str >= 'a' && *str <= 'f')
243 0 : h += 10 + (*str) - 'a';
244 : else
245 0 : return 0;
246 0 : h = h << 4;
247 0 : str++;
248 0 : if (*str >= '0' && *str <= '9')
249 0 : h += (*str) - '0';
250 0 : else if (*str >= 'A' && *str <= 'F')
251 0 : h += 10 + (*str) - 'A';
252 0 : else if (*str >= 'a' && *str <= 'f')
253 0 : h += 10 + (*str) - 'a';
254 : else
255 0 : return 0;
256 0 : return h;
257 : }
258 :
259 : /* Parse the input text into an unescaped cstring, and populate item. */
260 : static const unsigned char firstByteMark[7] =
261 : { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
262 : static const char *
263 0 : parse_string (cJSON * item, const char *str, const char **ep)
264 : {
265 0 : const char *ptr = str + 1;
266 : char *ptr2;
267 : char *out;
268 0 : int len = 0;
269 : unsigned uc, uc2;
270 :
271 : /* FIXME: We should consider eary failure like it is done with
272 : * commit 8656386c4f4a12f1cf3d6b26158407fd05e65029 in upstream. */
273 0 : if (*str != '\"')
274 : {
275 0 : *ep = str;
276 0 : return 0;
277 : } /* not a string! */
278 :
279 0 : while (*ptr != '\"' && *ptr && ++len)
280 0 : if (*ptr++ == '\\' && *ptr)
281 0 : ptr++; /* Skip escaped quotes. */
282 :
283 0 : out = xtrymalloc (len + 2); /* This is how long we need for the
284 : * string, roughly. We add one extra
285 : * byte in case the last input
286 : * character is a backslash. */
287 0 : if (!out)
288 0 : return 0;
289 :
290 0 : ptr = str + 1;
291 0 : ptr2 = out;
292 0 : while (*ptr != '\"' && *ptr)
293 : {
294 0 : if (*ptr != '\\')
295 0 : *ptr2++ = *ptr++;
296 : else
297 : {
298 0 : ptr++;
299 0 : if (!*ptr)
300 0 : break;
301 0 : switch (*ptr)
302 : {
303 : case 'b':
304 0 : *ptr2++ = '\b';
305 0 : break;
306 : case 'f':
307 0 : *ptr2++ = '\f';
308 0 : break;
309 : case 'n':
310 0 : *ptr2++ = '\n';
311 0 : break;
312 : case 'r':
313 0 : *ptr2++ = '\r';
314 0 : break;
315 : case 't':
316 0 : *ptr2++ = '\t';
317 0 : break;
318 : case 'u': /* transcode utf16 to utf8. */
319 0 : uc = parse_hex4 (ptr + 1);
320 0 : if (!uc)
321 0 : break; /* Bad hex; continue right after the 'u'. */
322 0 : ptr += 4; /* get the unicode char. */
323 :
324 0 : if ((uc >= 0xDC00 && uc <= 0xDFFF))
325 0 : break; /* check for invalid. */
326 :
327 0 : if (uc >= 0xD800 && uc <= 0xDBFF) /* UTF16 surrogate pairs. */
328 : {
329 0 : if (ptr[1] != '\\' || ptr[2] != 'u')
330 : break; /* missing second-half of surrogate. */
331 0 : ptr += 2;
332 0 : uc2 = parse_hex4 (ptr + 1);
333 0 : if (!uc2)
334 0 : break; /* Bad hex; continue right after the 'u'. */
335 0 : ptr += 4;
336 0 : if (uc2 < 0xDC00 || uc2 > 0xDFFF)
337 : break; /* invalid second-half of surrogate. */
338 0 : uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));
339 : }
340 :
341 0 : len = 4;
342 0 : if (uc < 0x80)
343 0 : len = 1;
344 0 : else if (uc < 0x800)
345 0 : len = 2;
346 0 : else if (uc < 0x10000)
347 0 : len = 3;
348 0 : ptr2 += len;
349 :
350 0 : switch (len)
351 : {
352 : case 4:
353 0 : *--ptr2 = ((uc | 0x80) & 0xBF);
354 0 : uc >>= 6;
355 : case 3:
356 0 : *--ptr2 = ((uc | 0x80) & 0xBF);
357 0 : uc >>= 6;
358 : case 2:
359 0 : *--ptr2 = ((uc | 0x80) & 0xBF);
360 0 : uc >>= 6;
361 : case 1:
362 0 : *--ptr2 = (uc | firstByteMark[len]);
363 : }
364 0 : ptr2 += len;
365 0 : break;
366 : default:
367 : /* Fixme: Should we fail here: See
368 : * https://github.com/DaveGamble/cJSON/issues/10 */
369 0 : *ptr2++ = *ptr;
370 0 : break;
371 : }
372 0 : ptr++;
373 : }
374 : }
375 0 : *ptr2 = 0;
376 0 : if (*ptr == '\"')
377 0 : ptr++;
378 0 : item->valuestring = out;
379 0 : item->type = cJSON_String;
380 0 : return ptr;
381 : }
382 :
383 : /* Render the cstring provided to an escaped version that can be printed. */
384 : static char *
385 0 : print_string_ptr (const char *str)
386 : {
387 : const char *ptr;
388 : char *ptr2, *out;
389 0 : int len = 0;
390 : unsigned char token;
391 :
392 0 : if (!str)
393 0 : return xtrystrdup ("");
394 0 : ptr = str;
395 0 : while ((token = *ptr) && ++len)
396 : {
397 0 : if (strchr ("\"\\\b\f\n\r\t", token))
398 0 : len++;
399 0 : else if (token < 32)
400 0 : len += 5;
401 0 : ptr++;
402 : }
403 :
404 0 : out = xtrymalloc (len + 3);
405 0 : if (!out)
406 0 : return 0;
407 :
408 0 : ptr2 = out;
409 0 : ptr = str;
410 0 : *ptr2++ = '\"';
411 0 : while (*ptr)
412 : {
413 0 : if ((unsigned char) *ptr > 31 && *ptr != '\"' && *ptr != '\\')
414 0 : *ptr2++ = *ptr++;
415 : else
416 : {
417 0 : *ptr2++ = '\\';
418 0 : switch (token = *ptr++)
419 : {
420 : case '\\':
421 0 : *ptr2++ = '\\';
422 0 : break;
423 : case '\"':
424 0 : *ptr2++ = '\"';
425 0 : break;
426 : case '\b':
427 0 : *ptr2++ = 'b';
428 0 : break;
429 : case '\f':
430 0 : *ptr2++ = 'f';
431 0 : break;
432 : case '\n':
433 0 : *ptr2++ = 'n';
434 0 : break;
435 : case '\r':
436 0 : *ptr2++ = 'r';
437 0 : break;
438 : case '\t':
439 0 : *ptr2++ = 't';
440 0 : break;
441 : default:
442 0 : sprintf (ptr2, "u%04x", token);
443 0 : ptr2 += 5;
444 0 : break; /* escape and print */
445 : }
446 : }
447 : }
448 0 : *ptr2++ = '\"';
449 0 : *ptr2++ = 0;
450 0 : return out;
451 : }
452 :
453 : /* Invote print_string_ptr (which is useful) on an item. */
454 : static char *
455 0 : print_string (cJSON * item)
456 : {
457 0 : return print_string_ptr (item->valuestring);
458 : }
459 :
460 : /* Predeclare these prototypes. */
461 : static const char *parse_value (cJSON * item, const char *value,
462 : const char **ep);
463 : static char *print_value (cJSON * item, int depth, int fmt);
464 : static const char *parse_array (cJSON * item, const char *value,
465 : const char **ep);
466 : static char *print_array (cJSON * item, int depth, int fmt);
467 : static const char *parse_object (cJSON * item, const char *value,
468 : const char **ep);
469 : static char *print_object (cJSON * item, int depth, int fmt);
470 :
471 : /* Utility to jump whitespace and cr/lf */
472 : static const char *
473 0 : skip (const char *in)
474 : {
475 0 : while (in && *in && (unsigned char) *in <= 32)
476 0 : in++;
477 0 : return in;
478 : }
479 :
480 : /* Parse an object - create a new root, and populate. */
481 : cJSON *
482 0 : cJSON_ParseWithOpts (const char *value, const char **return_parse_end,
483 : int require_null_terminated, size_t *r_erroff)
484 : {
485 0 : const char *end = 0;
486 0 : const char *ep = 0;
487 : cJSON *c;
488 :
489 0 : if (r_erroff)
490 0 : *r_erroff = 0;
491 :
492 0 : c = cJSON_New_Item ();
493 0 : if (!c)
494 0 : return NULL; /* memory fail */
495 :
496 0 : end = parse_value (c, skip (value), &ep);
497 0 : if (!end)
498 : {
499 0 : cJSON_Delete (c);
500 0 : errno = EINVAL;
501 0 : if (r_erroff)
502 0 : *r_erroff = ep - value;
503 0 : return 0;
504 : } /* parse failure. ep is set. */
505 :
506 : /* if we require null-terminated JSON without appended garbage, skip
507 : and then check for a null terminator */
508 0 : if (require_null_terminated)
509 : {
510 0 : end = skip (end);
511 0 : if (*end)
512 : {
513 0 : cJSON_Delete (c);
514 0 : ep = end;
515 0 : errno = EINVAL;
516 0 : if (r_erroff)
517 0 : *r_erroff = ep - value;
518 0 : return 0;
519 : }
520 : }
521 0 : if (return_parse_end)
522 0 : *return_parse_end = end;
523 0 : return c;
524 : }
525 :
526 : /* Default options for cJSON_Parse */
527 : cJSON *
528 0 : cJSON_Parse (const char *value, size_t *r_erroff)
529 : {
530 0 : return cJSON_ParseWithOpts (value, 0, 0, r_erroff);
531 : }
532 :
533 : /* Render a cJSON item/entity/structure to text. */
534 : char *
535 0 : cJSON_Print (cJSON * item)
536 : {
537 0 : return print_value (item, 0, 1);
538 : }
539 :
540 : char *
541 0 : cJSON_PrintUnformatted (cJSON * item)
542 : {
543 0 : return print_value (item, 0, 0);
544 : }
545 :
546 : /* Parser core - when encountering text, process appropriately. */
547 : static const char *
548 0 : parse_value (cJSON * item, const char *value, const char **ep)
549 : {
550 0 : if (!value)
551 0 : return 0; /* Fail on null. */
552 0 : if (!strncmp (value, "null", 4))
553 : {
554 0 : item->type = cJSON_NULL;
555 0 : return value + 4;
556 : }
557 0 : if (!strncmp (value, "false", 5))
558 : {
559 0 : item->type = cJSON_False;
560 0 : return value + 5;
561 : }
562 0 : if (!strncmp (value, "true", 4))
563 : {
564 0 : item->type = cJSON_True;
565 0 : item->valueint = 1;
566 0 : return value + 4;
567 : }
568 0 : if (*value == '\"')
569 : {
570 0 : return parse_string (item, value, ep);
571 : }
572 0 : if (*value == '-' || (*value >= '0' && *value <= '9'))
573 : {
574 0 : return parse_number (item, value);
575 : }
576 0 : if (*value == '[')
577 : {
578 0 : return parse_array (item, value, ep);
579 : }
580 0 : if (*value == '{')
581 : {
582 0 : return parse_object (item, value, ep);
583 : }
584 :
585 0 : *ep = value;
586 0 : return 0; /* failure. */
587 : }
588 :
589 : /* Render a value to text. */
590 : static char *
591 0 : print_value (cJSON * item, int depth, int fmt)
592 : {
593 0 : char *out = 0;
594 0 : if (!item)
595 0 : return 0;
596 0 : switch ((item->type) & 255)
597 : {
598 : case cJSON_NULL:
599 0 : out = xtrystrdup ("null");
600 0 : break;
601 : case cJSON_False:
602 0 : out = xtrystrdup ("false");
603 0 : break;
604 : case cJSON_True:
605 0 : out = xtrystrdup ("true");
606 0 : break;
607 : case cJSON_Number:
608 0 : out = print_number (item);
609 0 : break;
610 : case cJSON_String:
611 0 : out = print_string (item);
612 0 : break;
613 : case cJSON_Array:
614 0 : out = print_array (item, depth, fmt);
615 0 : break;
616 : case cJSON_Object:
617 0 : out = print_object (item, depth, fmt);
618 0 : break;
619 : }
620 0 : return out;
621 : }
622 :
623 : /* Build an array from input text. */
624 : static const char *
625 0 : parse_array (cJSON * item, const char *value, const char **ep)
626 : {
627 : cJSON *child;
628 0 : if (*value != '[')
629 : {
630 0 : *ep = value;
631 0 : return 0;
632 : } /* not an array! */
633 :
634 0 : item->type = cJSON_Array;
635 0 : value = skip (value + 1);
636 0 : if (*value == ']')
637 0 : return value + 1; /* empty array. */
638 :
639 0 : item->child = child = cJSON_New_Item ();
640 0 : if (!item->child)
641 0 : return 0; /* memory fail */
642 : /* skip any spacing, get the value. */
643 0 : value = skip (parse_value (child, skip (value), ep));
644 0 : if (!value)
645 0 : return 0;
646 :
647 0 : while (*value == ',')
648 : {
649 : cJSON *new_item;
650 0 : if (!(new_item = cJSON_New_Item ()))
651 0 : return 0; /* memory fail */
652 0 : child->next = new_item;
653 0 : new_item->prev = child;
654 0 : child = new_item;
655 0 : value = skip (parse_value (child, skip (value + 1), ep));
656 0 : if (!value)
657 0 : return 0; /* memory fail */
658 : }
659 :
660 0 : if (*value == ']')
661 0 : return value + 1; /* end of array */
662 0 : *ep = value;
663 0 : return 0; /* malformed. */
664 : }
665 :
666 : /* Render an array to text */
667 : static char *
668 0 : print_array (cJSON * item, int depth, int fmt)
669 : {
670 : char **entries;
671 0 : char *out = 0, *ptr, *ret;
672 0 : int len = 5;
673 0 : cJSON *child = item->child;
674 0 : int numentries = 0, i = 0, fail = 0;
675 :
676 : /* How many entries in the array? */
677 0 : while (child)
678 0 : numentries++, child = child->next;
679 : /* Explicitly handle numentries==0 */
680 0 : if (!numentries)
681 : {
682 0 : out = xtrymalloc (3);
683 0 : if (out)
684 0 : strcpy (out, "[]");
685 0 : return out;
686 : }
687 : /* Allocate an array to hold the values for each */
688 0 : entries = xtrymalloc (numentries * sizeof (char *));
689 0 : if (!entries)
690 0 : return 0;
691 0 : memset (entries, 0, numentries * sizeof (char *));
692 : /* Retrieve all the results: */
693 0 : child = item->child;
694 0 : while (child && !fail)
695 : {
696 0 : ret = print_value (child, depth + 1, fmt);
697 0 : entries[i++] = ret;
698 0 : if (ret)
699 0 : len += strlen (ret) + 2 + (fmt ? 1 : 0);
700 : else
701 0 : fail = 1;
702 0 : child = child->next;
703 : }
704 :
705 : /* If we didn't fail, try to xtrymalloc the output string */
706 0 : if (!fail)
707 0 : out = xtrymalloc (len);
708 : /* If that fails, we fail. */
709 0 : if (!out)
710 0 : fail = 1;
711 :
712 : /* Handle failure. */
713 0 : if (fail)
714 : {
715 0 : for (i = 0; i < numentries; i++)
716 0 : if (entries[i])
717 0 : xfree (entries[i]);
718 0 : xfree (entries);
719 0 : return 0;
720 : }
721 :
722 : /* Compose the output array. */
723 0 : *out = '[';
724 0 : ptr = out + 1;
725 0 : *ptr = 0;
726 0 : for (i = 0; i < numentries; i++)
727 : {
728 0 : strcpy (ptr, entries[i]);
729 0 : ptr += strlen (entries[i]);
730 0 : if (i != numentries - 1)
731 : {
732 0 : *ptr++ = ',';
733 0 : if (fmt)
734 0 : *ptr++ = ' ';
735 0 : *ptr = 0;
736 : }
737 0 : xfree (entries[i]);
738 : }
739 0 : xfree (entries);
740 0 : *ptr++ = ']';
741 0 : *ptr++ = 0;
742 0 : return out;
743 : }
744 :
745 : /* Build an object from the text. */
746 : static const char *
747 0 : parse_object (cJSON * item, const char *value, const char **ep)
748 : {
749 : cJSON *child;
750 0 : if (*value != '{')
751 : {
752 0 : *ep = value;
753 0 : return 0;
754 : } /* not an object! */
755 :
756 0 : item->type = cJSON_Object;
757 0 : value = skip (value + 1);
758 0 : if (*value == '}')
759 0 : return value + 1; /* empty array. */
760 :
761 0 : item->child = child = cJSON_New_Item ();
762 0 : if (!item->child)
763 0 : return 0;
764 0 : value = skip (parse_string (child, skip (value), ep));
765 0 : if (!value)
766 0 : return 0;
767 0 : child->string = child->valuestring;
768 0 : child->valuestring = 0;
769 0 : if (*value != ':')
770 : {
771 0 : *ep = value;
772 0 : return 0;
773 : } /* fail! */
774 : /* skip any spacing, get the value. */
775 0 : value = skip (parse_value (child, skip (value + 1), ep));
776 0 : if (!value)
777 0 : return 0;
778 :
779 0 : while (*value == ',')
780 : {
781 : cJSON *new_item;
782 0 : if (!(new_item = cJSON_New_Item ()))
783 0 : return 0; /* memory fail */
784 0 : child->next = new_item;
785 0 : new_item->prev = child;
786 0 : child = new_item;
787 0 : value = skip (parse_string (child, skip (value + 1), ep));
788 0 : if (!value)
789 0 : return 0;
790 0 : child->string = child->valuestring;
791 0 : child->valuestring = 0;
792 0 : if (*value != ':')
793 : {
794 0 : *ep = value;
795 0 : return 0;
796 : } /* fail! */
797 : /* skip any spacing, get the value. */
798 0 : value = skip (parse_value (child, skip (value + 1), ep));
799 0 : if (!value)
800 0 : return 0;
801 : }
802 :
803 0 : if (*value == '}')
804 0 : return value + 1; /* end of array */
805 0 : *ep = value;
806 0 : return 0; /* malformed. */
807 : }
808 :
809 : /* Render an object to text. */
810 : static char *
811 0 : print_object (cJSON * item, int depth, int fmt)
812 : {
813 0 : char **entries = 0, **names = 0;
814 0 : char *out = 0, *ptr, *ret, *str;
815 0 : int len = 7, i = 0, j;
816 0 : cJSON *child = item->child;
817 0 : int numentries = 0, fail = 0;
818 : /* Count the number of entries. */
819 0 : while (child)
820 0 : numentries++, child = child->next;
821 : /* Explicitly handle empty object case */
822 0 : if (!numentries)
823 : {
824 0 : out = xtrymalloc (fmt ? depth + 4 : 3);
825 0 : if (!out)
826 0 : return 0;
827 0 : ptr = out;
828 0 : *ptr++ = '{';
829 0 : if (fmt)
830 : {
831 0 : *ptr++ = '\n';
832 0 : for (i = 0; i < depth - 1; i++)
833 0 : *ptr++ = '\t';
834 : }
835 0 : *ptr++ = '}';
836 0 : *ptr++ = 0;
837 0 : return out;
838 : }
839 : /* Allocate space for the names and the objects */
840 0 : entries = xtrymalloc (numentries * sizeof (char *));
841 0 : if (!entries)
842 0 : return 0;
843 0 : names = xtrymalloc (numentries * sizeof (char *));
844 0 : if (!names)
845 : {
846 0 : xfree (entries);
847 0 : return 0;
848 : }
849 0 : memset (entries, 0, sizeof (char *) * numentries);
850 0 : memset (names, 0, sizeof (char *) * numentries);
851 :
852 : /* Collect all the results into our arrays: */
853 0 : child = item->child;
854 0 : depth++;
855 0 : if (fmt)
856 0 : len += depth;
857 0 : while (child)
858 : {
859 0 : names[i] = str = print_string_ptr (child->string);
860 0 : entries[i++] = ret = print_value (child, depth, fmt);
861 0 : if (str && ret)
862 0 : len += strlen (ret) + strlen (str) + 2 + (fmt ? 2 + depth : 0);
863 : else
864 0 : fail = 1;
865 0 : child = child->next;
866 : }
867 :
868 : /* Try to allocate the output string */
869 0 : if (!fail)
870 0 : out = xtrymalloc (len);
871 0 : if (!out)
872 0 : fail = 1;
873 :
874 : /* Handle failure */
875 0 : if (fail)
876 : {
877 0 : for (i = 0; i < numentries; i++)
878 : {
879 0 : if (names[i])
880 0 : xfree (names[i]);
881 0 : if (entries[i])
882 0 : xfree (entries[i]);
883 : }
884 0 : xfree (names);
885 0 : xfree (entries);
886 0 : return 0;
887 : }
888 :
889 : /* Compose the output: */
890 0 : *out = '{';
891 0 : ptr = out + 1;
892 0 : if (fmt)
893 0 : *ptr++ = '\n';
894 0 : *ptr = 0;
895 0 : for (i = 0; i < numentries; i++)
896 : {
897 0 : if (fmt)
898 0 : for (j = 0; j < depth; j++)
899 0 : *ptr++ = '\t';
900 0 : strcpy (ptr, names[i]);
901 0 : ptr += strlen (names[i]);
902 0 : *ptr++ = ':';
903 0 : if (fmt)
904 0 : *ptr++ = '\t';
905 0 : strcpy (ptr, entries[i]);
906 0 : ptr += strlen (entries[i]);
907 0 : if (i != numentries - 1)
908 0 : *ptr++ = ',';
909 0 : if (fmt)
910 0 : *ptr++ = '\n';
911 0 : *ptr = 0;
912 0 : xfree (names[i]);
913 0 : xfree (entries[i]);
914 : }
915 :
916 0 : xfree (names);
917 0 : xfree (entries);
918 0 : if (fmt)
919 0 : for (i = 0; i < depth - 1; i++)
920 0 : *ptr++ = '\t';
921 0 : *ptr++ = '}';
922 0 : *ptr++ = 0;
923 0 : return out;
924 : }
925 :
926 : /* Get Array size/item / object item. */
927 : int
928 0 : cJSON_GetArraySize (cJSON * array)
929 : {
930 0 : cJSON *c = array->child;
931 0 : int i = 0;
932 0 : while (c)
933 0 : i++, c = c->next;
934 0 : return i;
935 : }
936 :
937 : cJSON *
938 0 : cJSON_GetArrayItem (cJSON * array, int item)
939 : {
940 0 : cJSON *c = array->child;
941 0 : while (c && item > 0)
942 0 : item--, c = c->next;
943 0 : return c;
944 : }
945 :
946 : cJSON *
947 0 : cJSON_GetObjectItem (cJSON * object, const char *string)
948 : {
949 0 : cJSON *c = object->child;
950 0 : while (c && cJSON_strcasecmp (c->string, string))
951 0 : c = c->next;
952 0 : return c;
953 : }
954 :
955 : /* Utility for array list handling. */
956 : static void
957 0 : suffix_object (cJSON * prev, cJSON * item)
958 : {
959 0 : prev->next = item;
960 0 : item->prev = prev;
961 0 : }
962 :
963 : /* Utility for handling references. */
964 : static cJSON *
965 0 : create_reference (cJSON * item)
966 : {
967 0 : cJSON *ref = cJSON_New_Item ();
968 0 : if (!ref)
969 0 : return 0;
970 0 : memcpy (ref, item, sizeof (cJSON));
971 0 : ref->string = 0;
972 0 : ref->type |= cJSON_IsReference;
973 0 : ref->next = ref->prev = 0;
974 0 : return ref;
975 : }
976 :
977 : /* Add item to array/object. */
978 : void
979 0 : cJSON_AddItemToArray (cJSON * array, cJSON * item)
980 : {
981 : cJSON *c;
982 :
983 0 : if (!item || !array)
984 0 : return;
985 0 : c = array->child;
986 0 : if (!c)
987 : {
988 0 : array->child = item;
989 : }
990 : else
991 : {
992 0 : while (c && c->next)
993 0 : c = c->next;
994 0 : suffix_object (c, item);
995 : }
996 : }
997 :
998 : cJSON *
999 0 : cJSON_AddItemToObject (cJSON * object, const char *string, cJSON * item)
1000 : {
1001 : char *tmp;
1002 :
1003 0 : if (!item)
1004 0 : return 0;
1005 0 : tmp = xtrystrdup (string);
1006 0 : if (!tmp)
1007 0 : return NULL;
1008 :
1009 0 : if (item->string)
1010 0 : xfree (item->string);
1011 0 : item->string = tmp;
1012 0 : cJSON_AddItemToArray (object, item);
1013 0 : return object;
1014 : }
1015 :
1016 : cJSON *
1017 0 : cJSON_AddNullToObject (cJSON *object, const char *name)
1018 : {
1019 : cJSON *obj, *tmp;
1020 :
1021 0 : tmp = cJSON_CreateNull ();
1022 0 : if (!tmp)
1023 0 : return NULL;
1024 0 : obj = cJSON_AddItemToObject(object, name, tmp);
1025 0 : if (!obj)
1026 0 : cJSON_Delete (tmp);
1027 0 : return obj;
1028 : }
1029 :
1030 : cJSON *
1031 0 : cJSON_AddTrueToObject (cJSON *object, const char *name)
1032 : {
1033 : cJSON *obj, *tmp;
1034 :
1035 0 : tmp = cJSON_CreateTrue ();
1036 0 : if (!tmp)
1037 0 : return NULL;
1038 0 : obj = cJSON_AddItemToObject(object, name, tmp);
1039 0 : if (!obj)
1040 0 : cJSON_Delete (tmp);
1041 0 : return obj;
1042 : }
1043 :
1044 : cJSON *
1045 0 : cJSON_AddFalseToObject (cJSON *object, const char *name)
1046 : {
1047 : cJSON *obj, *tmp;
1048 :
1049 0 : tmp = cJSON_CreateFalse ();
1050 0 : if (!tmp)
1051 0 : return NULL;
1052 0 : obj = cJSON_AddItemToObject(object, name, tmp);
1053 0 : if (!obj)
1054 0 : cJSON_Delete (tmp);
1055 0 : return obj;
1056 : }
1057 :
1058 : cJSON *
1059 0 : cJSON_AddBoolToObject (cJSON *object, const char *name, int b)
1060 : {
1061 : cJSON *obj, *tmp;
1062 :
1063 0 : tmp = cJSON_CreateBool (b);
1064 0 : if (!tmp)
1065 0 : return NULL;
1066 0 : obj = cJSON_AddItemToObject(object, name, tmp);
1067 0 : if (!obj)
1068 0 : cJSON_Delete (tmp);
1069 0 : return obj;
1070 : }
1071 :
1072 : cJSON *
1073 0 : cJSON_AddNumberToObject (cJSON *object, const char *name, double num)
1074 : {
1075 : cJSON *obj, *tmp;
1076 :
1077 0 : tmp = cJSON_CreateNumber (num);
1078 0 : if (!tmp)
1079 0 : return NULL;
1080 0 : obj = cJSON_AddItemToObject(object, name, tmp);
1081 0 : if (!obj)
1082 0 : cJSON_Delete (tmp);
1083 0 : return obj;
1084 : }
1085 :
1086 : cJSON *
1087 0 : cJSON_AddStringToObject (cJSON *object, const char *name, const char *string)
1088 : {
1089 : cJSON *obj, *tmp;
1090 :
1091 0 : tmp = cJSON_CreateString (string);
1092 0 : if (!tmp)
1093 0 : return NULL;
1094 0 : obj = cJSON_AddItemToObject(object, name, tmp);
1095 0 : if (!obj)
1096 0 : cJSON_Delete (tmp);
1097 0 : return obj;
1098 : }
1099 :
1100 : void
1101 0 : cJSON_AddItemReferenceToArray (cJSON * array, cJSON * item)
1102 : {
1103 0 : cJSON_AddItemToArray (array, create_reference (item));
1104 0 : }
1105 :
1106 : void
1107 0 : cJSON_AddItemReferenceToObject (cJSON * object, const char *string,
1108 : cJSON * item)
1109 : {
1110 0 : cJSON_AddItemToObject (object, string, create_reference (item));
1111 0 : }
1112 :
1113 : cJSON *
1114 0 : cJSON_DetachItemFromArray (cJSON * array, int which)
1115 : {
1116 0 : cJSON *c = array->child;
1117 0 : while (c && which > 0)
1118 0 : c = c->next, which--;
1119 0 : if (!c)
1120 0 : return 0;
1121 0 : if (c->prev)
1122 0 : c->prev->next = c->next;
1123 0 : if (c->next)
1124 0 : c->next->prev = c->prev;
1125 0 : if (c == array->child)
1126 0 : array->child = c->next;
1127 0 : c->prev = c->next = 0;
1128 0 : return c;
1129 : }
1130 :
1131 : void
1132 0 : cJSON_DeleteItemFromArray (cJSON * array, int which)
1133 : {
1134 0 : cJSON_Delete (cJSON_DetachItemFromArray (array, which));
1135 0 : }
1136 :
1137 : cJSON *
1138 0 : cJSON_DetachItemFromObject (cJSON * object, const char *string)
1139 : {
1140 0 : int i = 0;
1141 0 : cJSON *c = object->child;
1142 0 : while (c && cJSON_strcasecmp (c->string, string))
1143 0 : i++, c = c->next;
1144 0 : if (c)
1145 0 : return cJSON_DetachItemFromArray (object, i);
1146 0 : return 0;
1147 : }
1148 :
1149 : void
1150 0 : cJSON_DeleteItemFromObject (cJSON * object, const char *string)
1151 : {
1152 0 : cJSON_Delete (cJSON_DetachItemFromObject (object, string));
1153 0 : }
1154 :
1155 : /* Replace array/object items with new ones. */
1156 : void
1157 0 : cJSON_ReplaceItemInArray (cJSON * array, int which, cJSON * newitem)
1158 : {
1159 0 : cJSON *c = array->child;
1160 0 : while (c && which > 0)
1161 0 : c = c->next, which--;
1162 0 : if (!c)
1163 0 : return;
1164 0 : newitem->next = c->next;
1165 0 : newitem->prev = c->prev;
1166 0 : if (newitem->next)
1167 0 : newitem->next->prev = newitem;
1168 0 : if (c == array->child)
1169 0 : array->child = newitem;
1170 : else
1171 0 : newitem->prev->next = newitem;
1172 0 : c->next = c->prev = 0;
1173 0 : cJSON_Delete (c);
1174 : }
1175 :
1176 : void
1177 0 : cJSON_ReplaceItemInObject (cJSON * object, const char *string,
1178 : cJSON * newitem)
1179 : {
1180 0 : int i = 0;
1181 0 : cJSON *c = object->child;
1182 0 : while (c && cJSON_strcasecmp (c->string, string))
1183 0 : i++, c = c->next;
1184 0 : if (c)
1185 : {
1186 : /* FIXME: I guess we should free newitem->string here. See
1187 : * upstream commit 0d10e279c8b604f71829b5d49d092719f4ae96b6. */
1188 0 : newitem->string = xtrystrdup (string);
1189 0 : cJSON_ReplaceItemInArray (object, i, newitem);
1190 : }
1191 0 : }
1192 :
1193 : /* Create basic types: */
1194 : cJSON *
1195 0 : cJSON_CreateNull (void)
1196 : {
1197 0 : cJSON *item = cJSON_New_Item ();
1198 0 : if (item)
1199 0 : item->type = cJSON_NULL;
1200 0 : return item;
1201 : }
1202 :
1203 : cJSON *
1204 0 : cJSON_CreateTrue (void)
1205 : {
1206 0 : cJSON *item = cJSON_New_Item ();
1207 0 : if (item)
1208 0 : item->type = cJSON_True;
1209 0 : return item;
1210 : }
1211 :
1212 : cJSON *
1213 0 : cJSON_CreateFalse (void)
1214 : {
1215 0 : cJSON *item = cJSON_New_Item ();
1216 0 : if (item)
1217 0 : item->type = cJSON_False;
1218 0 : return item;
1219 : }
1220 :
1221 : cJSON *
1222 0 : cJSON_CreateBool (int b)
1223 : {
1224 0 : cJSON *item = cJSON_New_Item ();
1225 0 : if (item)
1226 0 : item->type = b ? cJSON_True : cJSON_False;
1227 0 : return item;
1228 : }
1229 :
1230 : cJSON *
1231 0 : cJSON_CreateNumber (double num)
1232 : {
1233 0 : cJSON *item = cJSON_New_Item ();
1234 0 : if (item)
1235 : {
1236 0 : item->type = cJSON_Number;
1237 0 : item->valuedouble = num;
1238 0 : item->valueint = (int) num;
1239 : }
1240 0 : return item;
1241 : }
1242 :
1243 : cJSON *
1244 0 : cJSON_CreateString (const char *string)
1245 : {
1246 0 : cJSON *item = cJSON_New_Item ();
1247 0 : if (item)
1248 : {
1249 0 : item->type = cJSON_String;
1250 0 : item->valuestring = xtrystrdup (string);
1251 : }
1252 0 : return item;
1253 : }
1254 :
1255 : cJSON *
1256 0 : cJSON_CreateStringConvey (char *string)
1257 : {
1258 0 : cJSON *item = cJSON_New_Item ();
1259 0 : if (item)
1260 : {
1261 0 : item->type = cJSON_String;
1262 0 : item->valuestring = string;
1263 : }
1264 0 : return item;
1265 : }
1266 :
1267 : cJSON *
1268 0 : cJSON_CreateArray (void)
1269 : {
1270 0 : cJSON *item = cJSON_New_Item ();
1271 0 : if (item)
1272 0 : item->type = cJSON_Array;
1273 0 : return item;
1274 : }
1275 :
1276 : cJSON *
1277 0 : cJSON_CreateObject (void)
1278 : {
1279 0 : cJSON *item = cJSON_New_Item ();
1280 0 : if (item)
1281 0 : item->type = cJSON_Object;
1282 0 : return item;
1283 : }
1284 :
1285 : /* Create Arrays: */
1286 : cJSON *
1287 0 : cJSON_CreateIntArray (const int *numbers, int count)
1288 : {
1289 : int i;
1290 0 : cJSON *n = 0, *p = 0, *a = cJSON_CreateArray ();
1291 0 : for (i = 0; a && i < count; i++)
1292 : {
1293 0 : n = cJSON_CreateNumber (numbers[i]);
1294 0 : if (!i)
1295 0 : a->child = n;
1296 : else
1297 0 : suffix_object (p, n);
1298 0 : p = n;
1299 : }
1300 0 : return a;
1301 : }
1302 :
1303 : cJSON *
1304 0 : cJSON_CreateFloatArray (const float *numbers, int count)
1305 : {
1306 : int i;
1307 0 : cJSON *n = 0, *p = 0, *a = cJSON_CreateArray ();
1308 0 : for (i = 0; a && i < count; i++)
1309 : {
1310 0 : n = cJSON_CreateNumber (numbers[i]);
1311 0 : if (!i)
1312 0 : a->child = n;
1313 : else
1314 0 : suffix_object (p, n);
1315 0 : p = n;
1316 : }
1317 0 : return a;
1318 : }
1319 :
1320 : cJSON *
1321 0 : cJSON_CreateDoubleArray (const double *numbers, int count)
1322 : {
1323 : int i;
1324 0 : cJSON *n = 0, *p = 0, *a = cJSON_CreateArray ();
1325 0 : for (i = 0; a && i < count; i++)
1326 : {
1327 0 : n = cJSON_CreateNumber (numbers[i]);
1328 0 : if (!i)
1329 0 : a->child = n;
1330 : else
1331 0 : suffix_object (p, n);
1332 0 : p = n;
1333 : }
1334 0 : return a;
1335 : }
1336 :
1337 : cJSON *
1338 0 : cJSON_CreateStringArray (const char **strings, int count)
1339 : {
1340 : int i;
1341 0 : cJSON *n = 0, *p = 0, *a = cJSON_CreateArray ();
1342 0 : for (i = 0; a && i < count; i++)
1343 : {
1344 0 : n = cJSON_CreateString (strings[i]);
1345 0 : if (!i)
1346 0 : a->child = n;
1347 : else
1348 0 : suffix_object (p, n);
1349 0 : p = n;
1350 : }
1351 0 : return a;
1352 : }
1353 :
1354 : /* Duplication */
1355 : cJSON *
1356 0 : cJSON_Duplicate (cJSON * item, int recurse)
1357 : {
1358 0 : cJSON *newitem, *cptr, *nptr = 0, *newchild;
1359 : /* Bail on bad ptr */
1360 0 : if (!item)
1361 0 : return 0;
1362 : /* Create new item */
1363 0 : newitem = cJSON_New_Item ();
1364 0 : if (!newitem)
1365 0 : return 0;
1366 : /* Copy over all vars */
1367 0 : newitem->type = item->type & (~cJSON_IsReference), newitem->valueint =
1368 0 : item->valueint, newitem->valuedouble = item->valuedouble;
1369 0 : if (item->valuestring)
1370 : {
1371 0 : newitem->valuestring = xtrystrdup (item->valuestring);
1372 0 : if (!newitem->valuestring)
1373 : {
1374 0 : cJSON_Delete (newitem);
1375 0 : return 0;
1376 : }
1377 : }
1378 0 : if (item->string)
1379 : {
1380 0 : newitem->string = xtrystrdup (item->string);
1381 0 : if (!newitem->string)
1382 : {
1383 0 : cJSON_Delete (newitem);
1384 0 : return 0;
1385 : }
1386 : }
1387 : /* If non-recursive, then we're done! */
1388 0 : if (!recurse)
1389 0 : return newitem;
1390 : /* Walk the ->next chain for the child. */
1391 0 : cptr = item->child;
1392 0 : while (cptr)
1393 : {
1394 : /* Duplicate (with recurse) each item in the ->next chain */
1395 0 : newchild = cJSON_Duplicate (cptr, 1);
1396 0 : if (!newchild)
1397 : {
1398 0 : cJSON_Delete (newitem);
1399 0 : return 0;
1400 : }
1401 0 : if (nptr)
1402 : {
1403 : /* If newitem->child already set,
1404 : * then crosswire ->prev and ->next and move on. */
1405 0 : nptr->next = newchild, newchild->prev = nptr;
1406 0 : nptr = newchild;
1407 : }
1408 : else
1409 : {
1410 : /* Set newitem->child and move to it. */
1411 0 : newitem->child = newchild;
1412 0 : nptr = newchild;
1413 : }
1414 0 : cptr = cptr->next;
1415 : }
1416 0 : return newitem;
1417 : }
1418 :
1419 : void
1420 0 : cJSON_Minify (char *json)
1421 : {
1422 0 : char *into = json;
1423 0 : while (*json)
1424 : {
1425 0 : if (*json == ' ')
1426 0 : json++;
1427 0 : else if (*json == '\t')
1428 0 : json++; /* Whitespace characters. */
1429 0 : else if (*json == '\r')
1430 0 : json++;
1431 0 : else if (*json == '\n')
1432 0 : json++;
1433 0 : else if (*json == '/' && json[1] == '/')
1434 0 : while (*json && *json != '\n')
1435 0 : json++; /* Double-slash comments, to end of line. */
1436 0 : else if (*json == '/' && json[1] == '*')
1437 : {
1438 0 : while (*json && !(*json == '*' && json[1] == '/'))
1439 0 : json++;
1440 0 : json += 2;
1441 : } /* Multiline comments. */
1442 0 : else if (*json == '\"')
1443 : {
1444 0 : *into++ = *json++;
1445 0 : while (*json && *json != '\"')
1446 : {
1447 0 : if (*json == '\\')
1448 0 : *into++ = *json++;
1449 0 : if (*json)
1450 0 : *into++ = *json++;
1451 : }
1452 0 : if (*json)
1453 0 : *into++ = *json++;
1454 : } /* String literals, which are \" sensitive. */
1455 : else
1456 0 : *into++ = *json++; /* All other characters. */
1457 : }
1458 0 : *into = 0; /* and null-terminate. */
1459 0 : }
|