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