1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun Copyright (c) 2009 Dave Gamble
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun Permission is hereby granted, free of charge, to any person obtaining a copy
5*4882a593Smuzhiyun of this software and associated documentation files (the "Software"), to deal
6*4882a593Smuzhiyun in the Software without restriction, including without limitation the rights
7*4882a593Smuzhiyun to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8*4882a593Smuzhiyun copies of the Software, and to permit persons to whom the Software is
9*4882a593Smuzhiyun furnished to do so, subject to the following conditions:
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun The above copyright notice and this permission notice shall be included in
12*4882a593Smuzhiyun all copies or substantial portions of the Software.
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*4882a593Smuzhiyun IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*4882a593Smuzhiyun FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17*4882a593Smuzhiyun AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18*4882a593Smuzhiyun LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19*4882a593Smuzhiyun OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20*4882a593Smuzhiyun THE SOFTWARE.
21*4882a593Smuzhiyun */
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun /* cJSON */
24*4882a593Smuzhiyun /* JSON parser in C. */
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include <string.h>
27*4882a593Smuzhiyun #include <stdio.h>
28*4882a593Smuzhiyun #include <math.h>
29*4882a593Smuzhiyun #include <stdlib.h>
30*4882a593Smuzhiyun #include <float.h>
31*4882a593Smuzhiyun #include <limits.h>
32*4882a593Smuzhiyun #include <ctype.h>
33*4882a593Smuzhiyun #include "cJSON.h"
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun static const char *ep;
36*4882a593Smuzhiyun
cJSON_GetErrorPtr(void)37*4882a593Smuzhiyun const char *cJSON_GetErrorPtr(void) {return ep;}
38*4882a593Smuzhiyun
cJSON_strcasecmp(const char * s1,const char * s2)39*4882a593Smuzhiyun static int cJSON_strcasecmp(const char *s1,const char *s2)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
42*4882a593Smuzhiyun for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
43*4882a593Smuzhiyun return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun static void *(*cJSON_malloc)(size_t sz) = malloc;
47*4882a593Smuzhiyun static void (*cJSON_free)(void *ptr) = free;
48*4882a593Smuzhiyun
cJSON_strdup(const char * str)49*4882a593Smuzhiyun static char* cJSON_strdup(const char* str)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun size_t len;
52*4882a593Smuzhiyun char* copy;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun len = strlen(str) + 1;
55*4882a593Smuzhiyun if (!(copy = (char*)cJSON_malloc(len))) return 0;
56*4882a593Smuzhiyun memcpy(copy,str,len);
57*4882a593Smuzhiyun return copy;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
cJSON_InitHooks(cJSON_Hooks * hooks)60*4882a593Smuzhiyun void cJSON_InitHooks(cJSON_Hooks* hooks)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun if (!hooks) { /* Reset hooks */
63*4882a593Smuzhiyun cJSON_malloc = malloc;
64*4882a593Smuzhiyun cJSON_free = free;
65*4882a593Smuzhiyun return;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
69*4882a593Smuzhiyun cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* Internal constructor. */
cJSON_New_Item(void)73*4882a593Smuzhiyun static cJSON *cJSON_New_Item(void)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
76*4882a593Smuzhiyun if (node) memset(node,0,sizeof(cJSON));
77*4882a593Smuzhiyun return node;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /* Delete a cJSON structure. */
cJSON_Delete(cJSON * c)81*4882a593Smuzhiyun void cJSON_Delete(cJSON *c)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun cJSON *next;
84*4882a593Smuzhiyun while (c)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun next=c->next;
87*4882a593Smuzhiyun if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
88*4882a593Smuzhiyun if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
89*4882a593Smuzhiyun if (c->string) cJSON_free(c->string);
90*4882a593Smuzhiyun cJSON_free(c);
91*4882a593Smuzhiyun c=next;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* Parse the input text to generate a number, and populate the result into item. */
parse_number(cJSON * item,const char * num)96*4882a593Smuzhiyun static const char *parse_number(cJSON *item,const char *num)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun if (*num=='-') sign=-1,num++; /* Has sign? */
101*4882a593Smuzhiyun if (*num=='0') num++; /* is zero */
102*4882a593Smuzhiyun if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
103*4882a593Smuzhiyun if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
104*4882a593Smuzhiyun if (*num=='e' || *num=='E') /* Exponent? */
105*4882a593Smuzhiyun { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
106*4882a593Smuzhiyun while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun item->valuedouble=n;
112*4882a593Smuzhiyun item->valueint=(int)n;
113*4882a593Smuzhiyun item->type=cJSON_Number;
114*4882a593Smuzhiyun return num;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /* Render the number nicely from the given item into a string. */
print_number(cJSON * item)118*4882a593Smuzhiyun static char *print_number(cJSON *item)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun char *str;
121*4882a593Smuzhiyun double d=item->valuedouble;
122*4882a593Smuzhiyun if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
125*4882a593Smuzhiyun if (str) sprintf(str,"%d",item->valueint);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun else
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
130*4882a593Smuzhiyun if (str)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
133*4882a593Smuzhiyun else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
134*4882a593Smuzhiyun else sprintf(str,"%f",d);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun return str;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
parse_hex4(const char * str)140*4882a593Smuzhiyun static unsigned parse_hex4(const char *str)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun unsigned h=0;
143*4882a593Smuzhiyun if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
144*4882a593Smuzhiyun h=h<<4;str++;
145*4882a593Smuzhiyun if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
146*4882a593Smuzhiyun h=h<<4;str++;
147*4882a593Smuzhiyun if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
148*4882a593Smuzhiyun h=h<<4;str++;
149*4882a593Smuzhiyun if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
150*4882a593Smuzhiyun return h;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun /* Parse the input text into an unescaped cstring, and populate item. */
154*4882a593Smuzhiyun static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
parse_string(cJSON * item,const char * str)155*4882a593Smuzhiyun static const char *parse_string(cJSON *item,const char *str)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
158*4882a593Smuzhiyun if (*str!='\"') {ep=str;return 0;} /* not a string! */
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
163*4882a593Smuzhiyun if (!out) return 0;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun ptr=str+1;ptr2=out;
166*4882a593Smuzhiyun while (*ptr!='\"' && *ptr)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun if (*ptr!='\\') *ptr2++=*ptr++;
169*4882a593Smuzhiyun else
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun ptr++;
172*4882a593Smuzhiyun switch (*ptr)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun case 'b': *ptr2++='\b'; break;
175*4882a593Smuzhiyun case 'f': *ptr2++='\f'; break;
176*4882a593Smuzhiyun case 'n': *ptr2++='\n'; break;
177*4882a593Smuzhiyun case 'r': *ptr2++='\r'; break;
178*4882a593Smuzhiyun case 't': *ptr2++='\t'; break;
179*4882a593Smuzhiyun case 'u': /* transcode utf16 to utf8. */
180*4882a593Smuzhiyun uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
187*4882a593Smuzhiyun uc2=parse_hex4(ptr+3);ptr+=6;
188*4882a593Smuzhiyun if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
189*4882a593Smuzhiyun uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun switch (len) {
195*4882a593Smuzhiyun case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
196*4882a593Smuzhiyun case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
197*4882a593Smuzhiyun case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
198*4882a593Smuzhiyun case 1: *--ptr2 =(uc | firstByteMark[len]);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun ptr2+=len;
201*4882a593Smuzhiyun break;
202*4882a593Smuzhiyun default: *ptr2++=*ptr; break;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun ptr++;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun *ptr2=0;
208*4882a593Smuzhiyun if (*ptr=='\"') ptr++;
209*4882a593Smuzhiyun item->valuestring=out;
210*4882a593Smuzhiyun item->type=cJSON_String;
211*4882a593Smuzhiyun return ptr;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun /* Render the cstring provided to an escaped version that can be printed. */
print_string_ptr(const char * str)215*4882a593Smuzhiyun static char *print_string_ptr(const char *str)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun if (!str) return cJSON_strdup("");
220*4882a593Smuzhiyun ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun out=(char*)cJSON_malloc(len+3);
223*4882a593Smuzhiyun if (!out) return 0;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun ptr2=out;ptr=str;
226*4882a593Smuzhiyun *ptr2++='\"';
227*4882a593Smuzhiyun while (*ptr)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
230*4882a593Smuzhiyun else
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun *ptr2++='\\';
233*4882a593Smuzhiyun switch (token=*ptr++)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun case '\\': *ptr2++='\\'; break;
236*4882a593Smuzhiyun case '\"': *ptr2++='\"'; break;
237*4882a593Smuzhiyun case '\b': *ptr2++='b'; break;
238*4882a593Smuzhiyun case '\f': *ptr2++='f'; break;
239*4882a593Smuzhiyun case '\n': *ptr2++='n'; break;
240*4882a593Smuzhiyun case '\r': *ptr2++='r'; break;
241*4882a593Smuzhiyun case '\t': *ptr2++='t'; break;
242*4882a593Smuzhiyun default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun *ptr2++='\"';*ptr2++=0;
247*4882a593Smuzhiyun return out;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun /* Invote print_string_ptr (which is useful) on an item. */
print_string(cJSON * item)250*4882a593Smuzhiyun static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun /* Predeclare these prototypes. */
253*4882a593Smuzhiyun static const char *parse_value(cJSON *item,const char *value);
254*4882a593Smuzhiyun static char *print_value(cJSON *item,int depth,int fmt);
255*4882a593Smuzhiyun static const char *parse_array(cJSON *item,const char *value);
256*4882a593Smuzhiyun static char *print_array(cJSON *item,int depth,int fmt);
257*4882a593Smuzhiyun static const char *parse_object(cJSON *item,const char *value);
258*4882a593Smuzhiyun static char *print_object(cJSON *item,int depth,int fmt);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /* Utility to jump whitespace and cr/lf */
skip(const char * in)261*4882a593Smuzhiyun static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun /* Parse an object - create a new root, and populate. */
cJSON_ParseWithOpts(const char * value,const char ** return_parse_end,int require_null_terminated)264*4882a593Smuzhiyun cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun const char *end=0;
267*4882a593Smuzhiyun cJSON *c=cJSON_New_Item();
268*4882a593Smuzhiyun ep=0;
269*4882a593Smuzhiyun if (!c) return 0; /* memory fail */
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun end=parse_value(c,skip(value));
272*4882a593Smuzhiyun if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
275*4882a593Smuzhiyun if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
276*4882a593Smuzhiyun if (return_parse_end) *return_parse_end=end;
277*4882a593Smuzhiyun return c;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun /* Default options for cJSON_Parse */
cJSON_Parse(const char * value)280*4882a593Smuzhiyun cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun /* Render a cJSON item/entity/structure to text. */
cJSON_Print(cJSON * item)283*4882a593Smuzhiyun char *cJSON_Print(cJSON *item) {return print_value(item,0,1);}
cJSON_PrintUnformatted(cJSON * item)284*4882a593Smuzhiyun char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);}
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /* Parser core - when encountering text, process appropriately. */
parse_value(cJSON * item,const char * value)287*4882a593Smuzhiyun static const char *parse_value(cJSON *item,const char *value)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun if (!value) return 0; /* Fail on null. */
290*4882a593Smuzhiyun if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
291*4882a593Smuzhiyun if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
292*4882a593Smuzhiyun if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
293*4882a593Smuzhiyun if (*value=='\"') { return parse_string(item,value); }
294*4882a593Smuzhiyun if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
295*4882a593Smuzhiyun if (*value=='[') { return parse_array(item,value); }
296*4882a593Smuzhiyun if (*value=='{') { return parse_object(item,value); }
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun ep=value;return 0; /* failure. */
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /* Render a value to text. */
print_value(cJSON * item,int depth,int fmt)302*4882a593Smuzhiyun static char *print_value(cJSON *item,int depth,int fmt)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun char *out=0;
305*4882a593Smuzhiyun if (!item) return 0;
306*4882a593Smuzhiyun switch ((item->type)&255)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun case cJSON_NULL: out=cJSON_strdup("null"); break;
309*4882a593Smuzhiyun case cJSON_False: out=cJSON_strdup("false");break;
310*4882a593Smuzhiyun case cJSON_True: out=cJSON_strdup("true"); break;
311*4882a593Smuzhiyun case cJSON_Number: out=print_number(item);break;
312*4882a593Smuzhiyun case cJSON_String: out=print_string(item);break;
313*4882a593Smuzhiyun case cJSON_Array: out=print_array(item,depth,fmt);break;
314*4882a593Smuzhiyun case cJSON_Object: out=print_object(item,depth,fmt);break;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun return out;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun /* Build an array from input text. */
parse_array(cJSON * item,const char * value)320*4882a593Smuzhiyun static const char *parse_array(cJSON *item,const char *value)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun cJSON *child;
323*4882a593Smuzhiyun if (*value!='[') {ep=value;return 0;} /* not an array! */
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun item->type=cJSON_Array;
326*4882a593Smuzhiyun value=skip(value+1);
327*4882a593Smuzhiyun if (*value==']') return value+1; /* empty array. */
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun item->child=child=cJSON_New_Item();
330*4882a593Smuzhiyun if (!item->child) return 0; /* memory fail */
331*4882a593Smuzhiyun value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
332*4882a593Smuzhiyun if (!value) return 0;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun while (*value==',')
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun cJSON *new_item;
337*4882a593Smuzhiyun if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
338*4882a593Smuzhiyun child->next=new_item;new_item->prev=child;child=new_item;
339*4882a593Smuzhiyun value=skip(parse_value(child,skip(value+1)));
340*4882a593Smuzhiyun if (!value) return 0; /* memory fail */
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun if (*value==']') return value+1; /* end of array */
344*4882a593Smuzhiyun ep=value;return 0; /* malformed. */
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun /* Render an array to text */
print_array(cJSON * item,int depth,int fmt)348*4882a593Smuzhiyun static char *print_array(cJSON *item,int depth,int fmt)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun char **entries;
351*4882a593Smuzhiyun char *out=0,*ptr,*ret;int len=5;
352*4882a593Smuzhiyun cJSON *child=item->child;
353*4882a593Smuzhiyun int numentries=0,i=0,fail=0;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun /* How many entries in the array? */
356*4882a593Smuzhiyun while (child) numentries++,child=child->next;
357*4882a593Smuzhiyun /* Explicitly handle numentries==0 */
358*4882a593Smuzhiyun if (!numentries)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun out=(char*)cJSON_malloc(3);
361*4882a593Smuzhiyun if (out) strcpy(out,"[]");
362*4882a593Smuzhiyun return out;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun /* Allocate an array to hold the values for each */
365*4882a593Smuzhiyun entries=(char**)cJSON_malloc(numentries*sizeof(char*));
366*4882a593Smuzhiyun if (!entries) return 0;
367*4882a593Smuzhiyun memset(entries,0,numentries*sizeof(char*));
368*4882a593Smuzhiyun /* Retrieve all the results: */
369*4882a593Smuzhiyun child=item->child;
370*4882a593Smuzhiyun while (child && !fail)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun ret=print_value(child,depth+1,fmt);
373*4882a593Smuzhiyun entries[i++]=ret;
374*4882a593Smuzhiyun if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
375*4882a593Smuzhiyun child=child->next;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun /* If we didn't fail, try to malloc the output string */
379*4882a593Smuzhiyun if (!fail) out=(char*)cJSON_malloc(len);
380*4882a593Smuzhiyun /* If that fails, we fail. */
381*4882a593Smuzhiyun if (!out) fail=1;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun /* Handle failure. */
384*4882a593Smuzhiyun if (fail)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
387*4882a593Smuzhiyun cJSON_free(entries);
388*4882a593Smuzhiyun return 0;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun /* Compose the output array. */
392*4882a593Smuzhiyun *out='[';
393*4882a593Smuzhiyun ptr=out+1;*ptr=0;
394*4882a593Smuzhiyun for (i=0;i<numentries;i++)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
397*4882a593Smuzhiyun if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
398*4882a593Smuzhiyun cJSON_free(entries[i]);
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun cJSON_free(entries);
401*4882a593Smuzhiyun *ptr++=']';*ptr++=0;
402*4882a593Smuzhiyun return out;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun /* Build an object from the text. */
parse_object(cJSON * item,const char * value)406*4882a593Smuzhiyun static const char *parse_object(cJSON *item,const char *value)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun cJSON *child;
409*4882a593Smuzhiyun if (*value!='{') {ep=value;return 0;} /* not an object! */
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun item->type=cJSON_Object;
412*4882a593Smuzhiyun value=skip(value+1);
413*4882a593Smuzhiyun if (*value=='}') return value+1; /* empty array. */
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun item->child=child=cJSON_New_Item();
416*4882a593Smuzhiyun if (!item->child) return 0;
417*4882a593Smuzhiyun value=skip(parse_string(child,skip(value)));
418*4882a593Smuzhiyun if (!value) return 0;
419*4882a593Smuzhiyun child->string=child->valuestring;child->valuestring=0;
420*4882a593Smuzhiyun if (*value!=':') {ep=value;return 0;} /* fail! */
421*4882a593Smuzhiyun value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
422*4882a593Smuzhiyun if (!value) return 0;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun while (*value==',')
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun cJSON *new_item;
427*4882a593Smuzhiyun if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
428*4882a593Smuzhiyun child->next=new_item;new_item->prev=child;child=new_item;
429*4882a593Smuzhiyun value=skip(parse_string(child,skip(value+1)));
430*4882a593Smuzhiyun if (!value) return 0;
431*4882a593Smuzhiyun child->string=child->valuestring;child->valuestring=0;
432*4882a593Smuzhiyun if (*value!=':') {ep=value;return 0;} /* fail! */
433*4882a593Smuzhiyun value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
434*4882a593Smuzhiyun if (!value) return 0;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun if (*value=='}') return value+1; /* end of array */
438*4882a593Smuzhiyun ep=value;return 0; /* malformed. */
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun /* Render an object to text. */
print_object(cJSON * item,int depth,int fmt)442*4882a593Smuzhiyun static char *print_object(cJSON *item,int depth,int fmt)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun char **entries=0,**names=0;
445*4882a593Smuzhiyun char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
446*4882a593Smuzhiyun cJSON *child=item->child;
447*4882a593Smuzhiyun int numentries=0,fail=0;
448*4882a593Smuzhiyun /* Count the number of entries. */
449*4882a593Smuzhiyun while (child) numentries++,child=child->next;
450*4882a593Smuzhiyun /* Explicitly handle empty object case */
451*4882a593Smuzhiyun if (!numentries)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun out=(char*)cJSON_malloc(fmt?depth+4:3);
454*4882a593Smuzhiyun if (!out) return 0;
455*4882a593Smuzhiyun ptr=out;*ptr++='{';
456*4882a593Smuzhiyun if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
457*4882a593Smuzhiyun *ptr++='}';*ptr++=0;
458*4882a593Smuzhiyun return out;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun /* Allocate space for the names and the objects */
461*4882a593Smuzhiyun entries=(char**)cJSON_malloc(numentries*sizeof(char*));
462*4882a593Smuzhiyun if (!entries) return 0;
463*4882a593Smuzhiyun names=(char**)cJSON_malloc(numentries*sizeof(char*));
464*4882a593Smuzhiyun if (!names) {cJSON_free(entries);return 0;}
465*4882a593Smuzhiyun memset(entries,0,sizeof(char*)*numentries);
466*4882a593Smuzhiyun memset(names,0,sizeof(char*)*numentries);
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun /* Collect all the results into our arrays: */
469*4882a593Smuzhiyun child=item->child;depth++;if (fmt) len+=depth;
470*4882a593Smuzhiyun while (child)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun names[i]=str=print_string_ptr(child->string);
473*4882a593Smuzhiyun entries[i++]=ret=print_value(child,depth,fmt);
474*4882a593Smuzhiyun if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
475*4882a593Smuzhiyun child=child->next;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun /* Try to allocate the output string */
479*4882a593Smuzhiyun if (!fail) out=(char*)cJSON_malloc(len);
480*4882a593Smuzhiyun if (!out) fail=1;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun /* Handle failure */
483*4882a593Smuzhiyun if (fail)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
486*4882a593Smuzhiyun cJSON_free(names);cJSON_free(entries);
487*4882a593Smuzhiyun return 0;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun /* Compose the output: */
491*4882a593Smuzhiyun *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
492*4882a593Smuzhiyun for (i=0;i<numentries;i++)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
495*4882a593Smuzhiyun strcpy(ptr,names[i]);ptr+=strlen(names[i]);
496*4882a593Smuzhiyun *ptr++=':';if (fmt) *ptr++='\t';
497*4882a593Smuzhiyun strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
498*4882a593Smuzhiyun if (i!=numentries-1) *ptr++=',';
499*4882a593Smuzhiyun if (fmt) *ptr++='\n';*ptr=0;
500*4882a593Smuzhiyun cJSON_free(names[i]);cJSON_free(entries[i]);
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun cJSON_free(names);cJSON_free(entries);
504*4882a593Smuzhiyun if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
505*4882a593Smuzhiyun *ptr++='}';*ptr++=0;
506*4882a593Smuzhiyun return out;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun /* Get Array size/item / object item. */
cJSON_GetArraySize(cJSON * array)510*4882a593Smuzhiyun int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
cJSON_GetArrayItem(cJSON * array,int item)511*4882a593Smuzhiyun cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
cJSON_GetObjectItem(cJSON * object,const char * string)512*4882a593Smuzhiyun cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun /* Utility for array list handling. */
suffix_object(cJSON * prev,cJSON * item)515*4882a593Smuzhiyun static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
516*4882a593Smuzhiyun /* Utility for handling references. */
create_reference(cJSON * item)517*4882a593Smuzhiyun static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun /* Add item to array/object. */
cJSON_AddItemToArray(cJSON * array,cJSON * item)520*4882a593Smuzhiyun void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
cJSON_AddItemToObject(cJSON * object,const char * string,cJSON * item)521*4882a593Smuzhiyun void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
cJSON_AddItemReferenceToArray(cJSON * array,cJSON * item)522*4882a593Smuzhiyun void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
cJSON_AddItemReferenceToObject(cJSON * object,const char * string,cJSON * item)523*4882a593Smuzhiyun void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
524*4882a593Smuzhiyun
cJSON_DetachItemFromArray(cJSON * array,int which)525*4882a593Smuzhiyun cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
526*4882a593Smuzhiyun if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
cJSON_DeleteItemFromArray(cJSON * array,int which)527*4882a593Smuzhiyun void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
cJSON_DetachItemFromObject(cJSON * object,const char * string)528*4882a593Smuzhiyun cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
cJSON_DeleteItemFromObject(cJSON * object,const char * string)529*4882a593Smuzhiyun void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun /* Replace array/object items with new ones. */
cJSON_ReplaceItemInArray(cJSON * array,int which,cJSON * newitem)532*4882a593Smuzhiyun void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
533*4882a593Smuzhiyun newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
534*4882a593Smuzhiyun if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
cJSON_ReplaceItemInObject(cJSON * object,const char * string,cJSON * newitem)535*4882a593Smuzhiyun void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun /* Create basic types: */
cJSON_CreateNull(void)538*4882a593Smuzhiyun cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
cJSON_CreateTrue(void)539*4882a593Smuzhiyun cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
cJSON_CreateFalse(void)540*4882a593Smuzhiyun cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
cJSON_CreateBool(int b)541*4882a593Smuzhiyun cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
cJSON_CreateNumber(double num)542*4882a593Smuzhiyun cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
cJSON_CreateString(const char * string)543*4882a593Smuzhiyun cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
cJSON_CreateArray(void)544*4882a593Smuzhiyun cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
cJSON_CreateObject(void)545*4882a593Smuzhiyun cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun /* Create Arrays: */
cJSON_CreateIntArray(const int * numbers,int count)548*4882a593Smuzhiyun cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON_CreateFloatArray(const float * numbers,int count)549*4882a593Smuzhiyun cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON_CreateDoubleArray(const double * numbers,int count)550*4882a593Smuzhiyun cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON_CreateStringArray(const char ** strings,int count)551*4882a593Smuzhiyun cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun /* Duplication */
cJSON_Duplicate(cJSON * item,int recurse)554*4882a593Smuzhiyun cJSON *cJSON_Duplicate(cJSON *item,int recurse)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun cJSON *newitem,*cptr,*nptr=0,*newchild;
557*4882a593Smuzhiyun /* Bail on bad ptr */
558*4882a593Smuzhiyun if (!item) return 0;
559*4882a593Smuzhiyun /* Create new item */
560*4882a593Smuzhiyun newitem=cJSON_New_Item();
561*4882a593Smuzhiyun if (!newitem) return 0;
562*4882a593Smuzhiyun /* Copy over all vars */
563*4882a593Smuzhiyun newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
564*4882a593Smuzhiyun if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}}
565*4882a593Smuzhiyun if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
566*4882a593Smuzhiyun /* If non-recursive, then we're done! */
567*4882a593Smuzhiyun if (!recurse) return newitem;
568*4882a593Smuzhiyun /* Walk the ->next chain for the child. */
569*4882a593Smuzhiyun cptr=item->child;
570*4882a593Smuzhiyun while (cptr)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
573*4882a593Smuzhiyun if (!newchild) {cJSON_Delete(newitem);return 0;}
574*4882a593Smuzhiyun if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
575*4882a593Smuzhiyun else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
576*4882a593Smuzhiyun cptr=cptr->next;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun return newitem;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun
cJSON_Minify(char * json)581*4882a593Smuzhiyun void cJSON_Minify(char *json)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun char *into=json;
584*4882a593Smuzhiyun while (*json)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun if (*json==' ') json++;
587*4882a593Smuzhiyun else if (*json=='\t') json++; // Whitespace characters.
588*4882a593Smuzhiyun else if (*json=='\r') json++;
589*4882a593Smuzhiyun else if (*json=='\n') json++;
590*4882a593Smuzhiyun else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; // double-slash comments, to end of line.
591*4882a593Smuzhiyun else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} // multiline comments.
592*4882a593Smuzhiyun else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} // string literals, which are \" sensitive.
593*4882a593Smuzhiyun else *into++=*json++; // All other characters.
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun *into=0; // and null-terminate.
596*4882a593Smuzhiyun }
597