yangyang

Dependents:   espyun espyun

Fork of WIZnetInterface by jiang hao

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers cJSON.c Source File

cJSON.c

00001 /*
00002   Copyright (c) 2009 Dave Gamble
00003 
00004   Permission is hereby granted, free of charge, to any person obtaining a copy
00005   of this software and associated documentation files (the "Software"), to deal
00006   in the Software without restriction, including without limitation the rights
00007   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008   copies of the Software, and to permit persons to whom the Software is
00009   furnished to do so, subject to the following conditions:
00010 
00011   The above copyright notice and this permission notice shall be included in
00012   all copies or substantial portions of the Software.
00013 
00014   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00020   THE SOFTWARE.
00021 */
00022 
00023 /* cJSON */
00024 /* JSON parser in C. */
00025 
00026 #include <string.h>
00027 #include <stdio.h>
00028 #include <math.h>
00029 #include <stdlib.h>
00030 #include <float.h>
00031 #include <limits.h>
00032 #include <ctype.h>
00033 #include "cJSON.h"
00034 
00035 static const char *ep;
00036 
00037 const char *cJSON_GetErrorPtr(void) {return ep;}
00038 
00039 static int cJSON_strcasecmp(const char *s1,const char *s2)
00040 {
00041     if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
00042     for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0)    return 0;
00043     return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
00044 }
00045 
00046 static void *(*cJSON_malloc)(size_t sz) = malloc;
00047 static void (*cJSON_free)(void *ptr) = free;
00048 
00049 static char* cJSON_strdup(const char* str)
00050 {
00051       size_t len;
00052       char* copy;
00053 
00054       len = strlen(str) + 1;
00055       if (!(copy = (char*)cJSON_malloc(len))) return 0;
00056       memcpy(copy,str,len);
00057       return copy;
00058 }
00059 
00060 void cJSON_InitHooks(cJSON_Hooks* hooks)
00061 {
00062     if (!hooks) { /* Reset hooks */
00063         cJSON_malloc = malloc;
00064         cJSON_free = free;
00065         return;
00066     }
00067 
00068     cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
00069     cJSON_free   = (hooks->free_fn)?hooks->free_fn:free;
00070 }
00071 
00072 /* Internal constructor. */
00073 static cJSON *cJSON_New_Item(void)
00074 {
00075     cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
00076     if (node) memset(node,0,sizeof(cJSON));
00077     return node;
00078 }
00079 
00080 /* Delete a cJSON structure. */
00081 void cJSON_Delete(cJSON *c)
00082 {
00083     cJSON *next;
00084     while (c)
00085     {
00086         next=c->next;
00087         if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
00088         if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
00089         if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);
00090         cJSON_free(c);
00091         c=next;
00092     }
00093 }
00094 
00095 /* Parse the input text to generate a number, and populate the result into item. */
00096 static const char *parse_number(cJSON *item,const char *num)
00097 {
00098     double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
00099 
00100     if (*num=='-') sign=-1,num++;   /* Has sign? */
00101     if (*num=='0') num++;           /* is zero */
00102     if (*num>='1' && *num<='9') do  n=(n*10.0)+(*num++ -'0');   while (*num>='0' && *num<='9'); /* Number? */
00103     if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;        do  n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}  /* Fractional part? */
00104     if (*num=='e' || *num=='E')     /* Exponent? */
00105     {   num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++;      /* With sign? */
00106         while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');   /* Number? */
00107     }
00108 
00109     n=sign*n*pow(10.0,(scale+subscale*signsubscale));   /* number = +/- number.fraction * 10^+/- exponent */
00110     
00111     item->valuedouble=n;
00112     item->valueint=(int)n;
00113     item->type=cJSON_Number;
00114     return num;
00115 }
00116 
00117 static int pow2gt (int x)   {   --x;    x|=x>>1;    x|=x>>2;    x|=x>>4;    x|=x>>8;    x|=x>>16;   return x+1; }
00118 
00119 typedef struct {char *buffer; int length; int offset; } printbuffer;
00120 
00121 static char* ensure(printbuffer *p,int needed)
00122 {
00123     char *newbuffer;int newsize;
00124     if (!p || !p->buffer) return 0;
00125     needed+=p->offset;
00126     if (needed<=p->length) return p->buffer+p->offset;
00127 
00128     newsize=pow2gt(needed);
00129     newbuffer=(char*)cJSON_malloc(newsize);
00130     if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}
00131     if (newbuffer) memcpy(newbuffer,p->buffer,p->length);
00132     cJSON_free(p->buffer);
00133     p->length=newsize;
00134     p->buffer=newbuffer;
00135     return newbuffer+p->offset;
00136 }
00137 
00138 static int update(printbuffer *p)
00139 {
00140     char *str;
00141     if (!p || !p->buffer) return 0;
00142     str=p->buffer+p->offset;
00143     return p->offset+strlen(str);
00144 }
00145 
00146 /* Render the number nicely from the given item into a string. */
00147 static char *print_number(cJSON *item,printbuffer *p)
00148 {
00149     char *str=0;
00150     double d=item->valuedouble;
00151     if (d==0)
00152     {
00153         if (p)  str=ensure(p,2);
00154         else    str=(char*)cJSON_malloc(2); /* special case for 0. */
00155         if (str) strcpy(str,"0");
00156     }
00157     else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
00158     {
00159         if (p)  str=ensure(p,21);
00160         else    str=(char*)cJSON_malloc(21);    /* 2^64+1 can be represented in 21 chars. */
00161         if (str)    sprintf(str,"%d",item->valueint);
00162     }
00163     else
00164     {
00165         if (p)  str=ensure(p,64);
00166         else    str=(char*)cJSON_malloc(64);    /* This is a nice tradeoff. */
00167         if (str)
00168         {
00169             if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
00170             else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)           sprintf(str,"%e",d);
00171             else                                                sprintf(str,"%f",d);
00172         }
00173     }
00174     return str;
00175 }
00176 
00177 static unsigned parse_hex4(const char *str)
00178 {
00179     unsigned h=0;
00180     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;
00181     h=h<<4;str++;
00182     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;
00183     h=h<<4;str++;
00184     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;
00185     h=h<<4;str++;
00186     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;
00187     return h;
00188 }
00189 
00190 /* Parse the input text into an unescaped cstring, and populate item. */
00191 static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
00192 static const char *parse_string(cJSON *item,const char *str)
00193 {
00194     const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
00195     if (*str!='\"') {ep=str;return 0;}  /* not a string! */
00196     
00197     while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;  /* Skip escaped quotes. */
00198     
00199     out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
00200     if (!out) return 0;
00201     
00202     ptr=str+1;ptr2=out;
00203     while (*ptr!='\"' && *ptr)
00204     {
00205         if (*ptr!='\\') *ptr2++=*ptr++;
00206         else
00207         {
00208             ptr++;
00209             switch (*ptr)
00210             {
00211                 case 'b': *ptr2++='\b'; break;
00212                 case 'f': *ptr2++='\f'; break;
00213                 case 'n': *ptr2++='\n'; break;
00214                 case 'r': *ptr2++='\r'; break;
00215                 case 't': *ptr2++='\t'; break;
00216                 case 'u':    /* transcode utf16 to utf8. */
00217                     uc=parse_hex4(ptr+1);ptr+=4;    /* get the unicode char. */
00218 
00219                     if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)    break;  /* check for invalid.   */
00220 
00221                     if (uc>=0xD800 && uc<=0xDBFF)   /* UTF16 surrogate pairs.   */
00222                     {
00223                         if (ptr[1]!='\\' || ptr[2]!='u')    break;  /* missing second-half of surrogate.    */
00224                         uc2=parse_hex4(ptr+3);ptr+=6;
00225                         if (uc2<0xDC00 || uc2>0xDFFF)       break;  /* invalid second-half of surrogate.    */
00226                         uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
00227                     }
00228 
00229                     len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
00230                     
00231                     switch (len) {
00232                         case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
00233                         case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
00234                         case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
00235                         case 1: *--ptr2 =(uc | firstByteMark[len]);
00236                     }
00237                     ptr2+=len;
00238                     break;
00239                 default:  *ptr2++=*ptr; break;
00240             }
00241             ptr++;
00242         }
00243     }
00244     *ptr2=0;
00245     if (*ptr=='\"') ptr++;
00246     item->valuestring=out;
00247     item->type=cJSON_String;
00248     return ptr;
00249 }
00250 
00251 
00252 static int escapable[256]={ 1,1,1,1,    1,1,1,1,    1,1,1,1,    1,1,1,1,    1,1,1,1,    1,1,1,1,    1,1,1,1,    1,1,1,1,
00253                             0,0,1,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,
00254                             0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    1,0,0,0,
00255                             0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,
00256                             0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,
00257                             0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,
00258                             0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,
00259                             0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0,    0,0,0,0};
00260 
00261 /* Render the cstring provided to an escaped version that can be printed. */
00262 static char *print_string_ptr(const char *str,printbuffer *p)
00263 {
00264     const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;
00265     
00266     ptr=str;while (*ptr) flag|=escapable[*ptr++];
00267     if (!flag)
00268     {
00269         len=ptr-str;
00270         if (p) out=ensure(p,len+3);
00271         else        out=(char*)cJSON_malloc(len+3);
00272         if (!out) return 0;
00273         ptr2=out;*ptr2++='\"';
00274         strcpy(ptr2,str);
00275         ptr2[len]='\"';
00276         ptr2[len+1]=0;
00277         return out;
00278     }
00279     
00280     if (!str)
00281     {
00282         if (p)  out=ensure(p,3);
00283         else    out=(char*)cJSON_malloc(3);
00284         if (!out) return 0;
00285         strcpy(out,"\"\"");
00286         return out;
00287     }
00288     ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
00289     
00290     if (p)  out=ensure(p,len+3);
00291     else    out=(char*)cJSON_malloc(len+3);
00292     if (!out) return 0;
00293 
00294     ptr2=out;ptr=str;
00295     *ptr2++='\"';
00296     while (*ptr)
00297     {
00298         if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
00299         else
00300         {
00301             *ptr2++='\\';
00302             switch (token=*ptr++)
00303             {
00304                 case '\\':  *ptr2++='\\';   break;
00305                 case '\"':  *ptr2++='\"';   break;
00306                 case '\b':  *ptr2++='b';    break;
00307                 case '\f':  *ptr2++='f';    break;
00308                 case '\n':  *ptr2++='n';    break;
00309                 case '\r':  *ptr2++='r';    break;
00310                 case '\t':  *ptr2++='t';    break;
00311                 default: sprintf(ptr2,"u%04x",token);ptr2+=5;   break;  /* escape and print */
00312             }
00313         }
00314     }
00315     *ptr2++='\"';*ptr2++=0;
00316     return out;
00317 }
00318 /* Invote print_string_ptr (which is useful) on an item. */
00319 static char *print_string(cJSON *item,printbuffer *p)   {return print_string_ptr(item->valuestring,p);}
00320 
00321 /* Predeclare these prototypes. */
00322 static const char *parse_value(cJSON *item,const char *value);
00323 static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
00324 static const char *parse_array(cJSON *item,const char *value);
00325 static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
00326 static const char *parse_object(cJSON *item,const char *value);
00327 static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);
00328 
00329 /* Utility to jump whitespace and cr/lf */
00330 static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
00331 
00332 /* Parse an object - create a new root, and populate. */
00333 cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
00334 {
00335     const char *end=0;
00336     cJSON *c=cJSON_New_Item();
00337     ep=0;
00338     if (!c) return 0;       /* memory fail */
00339 
00340     end=parse_value(c,skip(value));
00341     if (!end)   {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
00342 
00343     /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
00344     if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
00345     if (return_parse_end) *return_parse_end=end;
00346     return c;
00347 }
00348 /* Default options for cJSON_Parse */
00349 cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
00350 
00351 /* Render a cJSON item/entity/structure to text. */
00352 char *cJSON_Print(cJSON *item)              {return print_value(item,0,1,0);}
00353 char *cJSON_PrintUnformatted(cJSON *item)   {return print_value(item,0,0,0);}
00354 
00355 char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
00356 {
00357     printbuffer p;
00358     p.buffer=(char*)cJSON_malloc(prebuffer);
00359     p.length=prebuffer;
00360     p.offset=0;
00361     return print_value(item,0,fmt,&p);
00362     return p.buffer;
00363 }
00364 
00365 
00366 /* Parser core - when encountering text, process appropriately. */
00367 static const char *parse_value(cJSON *item,const char *value)
00368 {
00369     if (!value)                     return 0;   /* Fail on null. */
00370     if (!strncmp(value,"null",4))   { item->type=cJSON_NULL;  return value+4; }
00371     if (!strncmp(value,"false",5))  { item->type=cJSON_False; return value+5; }
00372     if (!strncmp(value,"true",4))   { item->type=cJSON_True; item->valueint=1;  return value+4; }
00373     if (*value=='\"')               { return parse_string(item,value); }
00374     if (*value=='-' || (*value>='0' && *value<='9'))    { return parse_number(item,value); }
00375     if (*value=='[')                { return parse_array(item,value); }
00376     if (*value=='{')                { return parse_object(item,value); }
00377 
00378     ep=value;return 0;  /* failure. */
00379 }
00380 
00381 /* Render a value to text. */
00382 static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
00383 {
00384     char *out=0;
00385     if (!item) return 0;
00386     if (p)
00387     {
00388         switch ((item->type)&255)
00389         {
00390             case cJSON_NULL:    {out=ensure(p,5);   if (out) strcpy(out,"null");    break;}
00391             case cJSON_False:   {out=ensure(p,6);   if (out) strcpy(out,"false");   break;}
00392             case cJSON_True:    {out=ensure(p,5);   if (out) strcpy(out,"true");    break;}
00393             case cJSON_Number:  out=print_number(item,p);break;
00394             case cJSON_String:  out=print_string(item,p);break;
00395             case cJSON_Array:   out=print_array(item,depth,fmt,p);break;
00396             case cJSON_Object:  out=print_object(item,depth,fmt,p);break;
00397         }
00398     }
00399     else
00400     {
00401         switch ((item->type)&255)
00402         {
00403             case cJSON_NULL:    out=cJSON_strdup("null");   break;
00404             case cJSON_False:   out=cJSON_strdup("false");break;
00405             case cJSON_True:    out=cJSON_strdup("true"); break;
00406             case cJSON_Number:  out=print_number(item,0);break;
00407             case cJSON_String:  out=print_string(item,0);break;
00408             case cJSON_Array:   out=print_array(item,depth,fmt,0);break;
00409             case cJSON_Object:  out=print_object(item,depth,fmt,0);break;
00410         }
00411     }
00412     return out;
00413 }
00414 
00415 /* Build an array from input text. */
00416 static const char *parse_array(cJSON *item,const char *value)
00417 {
00418     cJSON *child;
00419     if (*value!='[')    {ep=value;return 0;}    /* not an array! */
00420 
00421     item->type=cJSON_Array;
00422     value=skip(value+1);
00423     if (*value==']') return value+1;    /* empty array. */
00424 
00425     item->child=child=cJSON_New_Item();
00426     if (!item->child) return 0;      /* memory fail */
00427     value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
00428     if (!value) return 0;
00429 
00430     while (*value==',')
00431     {
00432         cJSON *new_item;
00433         if (!(new_item=cJSON_New_Item())) return 0;     /* memory fail */
00434         child->next=new_item;new_item->prev=child;child=new_item;
00435         value=skip(parse_value(child,skip(value+1)));
00436         if (!value) return 0;   /* memory fail */
00437     }
00438 
00439     if (*value==']') return value+1;    /* end of array */
00440     ep=value;return 0;  /* malformed. */
00441 }
00442 
00443 /* Render an array to text */
00444 static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
00445 {
00446     char **entries;
00447     char *out=0,*ptr,*ret;int len=5;
00448     cJSON *child=item->child;
00449     int numentries=0,i=0,fail=0;
00450     size_t tmplen=0;
00451     
00452     /* How many entries in the array? */
00453     while (child) numentries++,child=child->next;
00454     /* Explicitly handle numentries==0 */
00455     if (!numentries)
00456     {
00457         if (p)  out=ensure(p,3);
00458         else    out=(char*)cJSON_malloc(3);
00459         if (out) strcpy(out,"[]");
00460         return out;
00461     }
00462 
00463     if (p)
00464     {
00465         /* Compose the output array. */
00466         i=p->offset;
00467         ptr=ensure(p,1);if (!ptr) return 0; *ptr='[';   p->offset++;
00468         child=item->child;
00469         while (child && !fail)
00470         {
00471             print_value(child,depth+1,fmt,p);
00472             p->offset=update(p);
00473             if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;}
00474             child=child->next;
00475         }
00476         ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0;
00477         out=(p->buffer)+i;
00478     }
00479     else
00480     {
00481         /* Allocate an array to hold the values for each */
00482         entries=(char**)cJSON_malloc(numentries*sizeof(char*));
00483         if (!entries) return 0;
00484         memset(entries,0,numentries*sizeof(char*));
00485         /* Retrieve all the results: */
00486         child=item->child;
00487         while (child && !fail)
00488         {
00489             ret=print_value(child,depth+1,fmt,0);
00490             entries[i++]=ret;
00491             if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
00492             child=child->next;
00493         }
00494         
00495         /* If we didn't fail, try to malloc the output string */
00496         if (!fail)  out=(char*)cJSON_malloc(len);
00497         /* If that fails, we fail. */
00498         if (!out) fail=1;
00499 
00500         /* Handle failure. */
00501         if (fail)
00502         {
00503             for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
00504             cJSON_free(entries);
00505             return 0;
00506         }
00507         
00508         /* Compose the output array. */
00509         *out='[';
00510         ptr=out+1;*ptr=0;
00511         for (i=0;i<numentries;i++)
00512         {
00513             tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;
00514             if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
00515             cJSON_free(entries[i]);
00516         }
00517         cJSON_free(entries);
00518         *ptr++=']';*ptr++=0;
00519     }
00520     return out; 
00521 }
00522 
00523 /* Build an object from the text. */
00524 static const char *parse_object(cJSON *item,const char *value)
00525 {
00526     cJSON *child;
00527     if (*value!='{')    {ep=value;return 0;}    /* not an object! */
00528     
00529     item->type=cJSON_Object;
00530     value=skip(value+1);
00531     if (*value=='}') return value+1;    /* empty array. */
00532     
00533     item->child=child=cJSON_New_Item();
00534     if (!item->child) return 0;
00535     value=skip(parse_string(child,skip(value)));
00536     if (!value) return 0;
00537     child->string=child->valuestring;child->valuestring=0;
00538     if (*value!=':') {ep=value;return 0;}   /* fail! */
00539     value=skip(parse_value(child,skip(value+1)));   /* skip any spacing, get the value. */
00540     if (!value) return 0;
00541     
00542     while (*value==',')
00543     {
00544         cJSON *new_item;
00545         if (!(new_item=cJSON_New_Item()))   return 0; /* memory fail */
00546         child->next=new_item;new_item->prev=child;child=new_item;
00547         value=skip(parse_string(child,skip(value+1)));
00548         if (!value) return 0;
00549         child->string=child->valuestring;child->valuestring=0;
00550         if (*value!=':') {ep=value;return 0;}   /* fail! */
00551         value=skip(parse_value(child,skip(value+1)));   /* skip any spacing, get the value. */
00552         if (!value) return 0;
00553     }
00554     
00555     if (*value=='}') return value+1;    /* end of array */
00556     ep=value;return 0;  /* malformed. */
00557 }
00558 
00559 /* Render an object to text. */
00560 static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
00561 {
00562     char **entries=0,**names=0;
00563     char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
00564     cJSON *child=item->child;
00565     int numentries=0,fail=0;
00566     size_t tmplen=0;
00567     /* Count the number of entries. */
00568     while (child) numentries++,child=child->next;
00569     /* Explicitly handle empty object case */
00570     if (!numentries)
00571     {
00572         if (p) out=ensure(p,fmt?depth+4:3);
00573         else    out=(char*)cJSON_malloc(fmt?depth+4:3);
00574         if (!out)   return 0;
00575         ptr=out;*ptr++='{';
00576         if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
00577         *ptr++='}';*ptr++=0;
00578         return out;
00579     }
00580     if (p)
00581     {
00582         /* Compose the output: */
00583         i=p->offset;
00584         len=fmt?2:1;    ptr=ensure(p,len+1);    if (!ptr) return 0;
00585         *ptr++='{'; if (fmt) *ptr++='\n';   *ptr=0; p->offset+=len;
00586         child=item->child;depth++;
00587         while (child)
00588         {
00589             if (fmt)
00590             {
00591                 ptr=ensure(p,depth);    if (!ptr) return 0;
00592                 for (j=0;j<depth;j++) *ptr++='\t';
00593                 p->offset+=depth;
00594             }
00595             print_string_ptr(child->string,p);
00596             p->offset=update(p);
00597             
00598             len=fmt?2:1;
00599             ptr=ensure(p,len);  if (!ptr) return 0;
00600             *ptr++=':';if (fmt) *ptr++='\t';
00601             p->offset+=len;
00602             
00603             print_value(child,depth,fmt,p);
00604             p->offset=update(p);
00605 
00606             len=(fmt?1:0)+(child->next?1:0);
00607             ptr=ensure(p,len+1); if (!ptr) return 0;
00608             if (child->next) *ptr++=',';
00609             if (fmt) *ptr++='\n';*ptr=0;
00610             p->offset+=len;
00611             child=child->next;
00612         }
00613         ptr=ensure(p,fmt?(depth+1):2);   if (!ptr) return 0;
00614         if (fmt)    for (i=0;i<depth-1;i++) *ptr++='\t';
00615         *ptr++='}';*ptr=0;
00616         out=(p->buffer)+i;
00617     }
00618     else
00619     {
00620         /* Allocate space for the names and the objects */
00621         entries=(char**)cJSON_malloc(numentries*sizeof(char*));
00622         if (!entries) return 0;
00623         names=(char**)cJSON_malloc(numentries*sizeof(char*));
00624         if (!names) {cJSON_free(entries);return 0;}
00625         memset(entries,0,sizeof(char*)*numentries);
00626         memset(names,0,sizeof(char*)*numentries);
00627 
00628         /* Collect all the results into our arrays: */
00629         child=item->child;depth++;if (fmt) len+=depth;
00630         while (child)
00631         {
00632             names[i]=str=print_string_ptr(child->string,0);
00633             entries[i++]=ret=print_value(child,depth,fmt,0);
00634             if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
00635             child=child->next;
00636         }
00637         
00638         /* Try to allocate the output string */
00639         if (!fail)  out=(char*)cJSON_malloc(len);
00640         if (!out) fail=1;
00641 
00642         /* Handle failure */
00643         if (fail)
00644         {
00645             for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
00646             cJSON_free(names);cJSON_free(entries);
00647             return 0;
00648         }
00649         
00650         /* Compose the output: */
00651         *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
00652         for (i=0;i<numentries;i++)
00653         {
00654             if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
00655             tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;
00656             *ptr++=':';if (fmt) *ptr++='\t';
00657             strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
00658             if (i!=numentries-1) *ptr++=',';
00659             if (fmt) *ptr++='\n';*ptr=0;
00660             cJSON_free(names[i]);cJSON_free(entries[i]);
00661         }
00662         
00663         cJSON_free(names);cJSON_free(entries);
00664         if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
00665         *ptr++='}';*ptr++=0;
00666     }
00667     return out; 
00668 }
00669 
00670 /* Get Array size/item / object item. */
00671 int    cJSON_GetArraySize(cJSON *array)                         {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
00672 cJSON *cJSON_GetArrayItem(cJSON *array,int item)                {cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;}
00673 cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)    {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
00674 
00675 /* Utility for array list handling. */
00676 static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
00677 /* Utility for handling references. */
00678 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;}
00679 
00680 /* Add item to array/object. */
00681 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);}}
00682 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);}
00683 void   cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item)    {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);}
00684 void    cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)                        {cJSON_AddItemToArray(array,create_reference(item));}
00685 void    cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)    {cJSON_AddItemToObject(object,string,create_reference(item));}
00686 
00687 cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)            {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
00688     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;}
00689 void   cJSON_DeleteItemFromArray(cJSON *array,int which)            {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
00690 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;}
00691 void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
00692 
00693 /* Replace array/object items with new ones. */
00694 void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)      {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
00695     newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
00696     if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
00697 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);}}
00698 
00699 /* Create basic types: */
00700 cJSON *cJSON_CreateNull(void)                   {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
00701 cJSON *cJSON_CreateTrue(void)                   {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
00702 cJSON *cJSON_CreateFalse(void)                  {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
00703 cJSON *cJSON_CreateBool(int b)                  {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
00704 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;}
00705 cJSON *cJSON_CreateString(const char *string)   {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
00706 cJSON *cJSON_CreateArray(void)                  {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
00707 cJSON *cJSON_CreateObject(void)                 {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
00708 
00709 /* Create Arrays: */
00710 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;}
00711 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;}
00712 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;}
00713 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;}
00714 
00715 /* Duplication */
00716 cJSON *cJSON_Duplicate(cJSON *item,int recurse)
00717 {
00718     cJSON *newitem,*cptr,*nptr=0,*newchild;
00719     /* Bail on bad ptr */
00720     if (!item) return 0;
00721     /* Create new item */
00722     newitem=cJSON_New_Item();
00723     if (!newitem) return 0;
00724     /* Copy over all vars */
00725     newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
00726     if (item->valuestring)  {newitem->valuestring=cJSON_strdup(item->valuestring);  if (!newitem->valuestring)  {cJSON_Delete(newitem);return 0;}}
00727     if (item->string)       {newitem->string=cJSON_strdup(item->string);            if (!newitem->string)       {cJSON_Delete(newitem);return 0;}}
00728     /* If non-recursive, then we're done! */
00729     if (!recurse) return newitem;
00730     /* Walk the ->next chain for the child. */
00731     cptr=item->child;
00732     while (cptr)
00733     {
00734         newchild=cJSON_Duplicate(cptr,1);       /* Duplicate (with recurse) each item in the ->next chain */
00735         if (!newchild) {cJSON_Delete(newitem);return 0;}
00736         if (nptr)   {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}    /* If newitem->child already set, then crosswire ->prev and ->next and move on */
00737         else        {newitem->child=newchild;nptr=newchild;}                    /* Set newitem->child and move to it */
00738         cptr=cptr->next;
00739     }
00740     return newitem;
00741 }
00742 
00743 void cJSON_Minify(char *json)
00744 {
00745     char *into=json;
00746     while (*json)
00747     {
00748         if (*json==' ') json++;
00749         else if (*json=='\t') json++;   // Whitespace characters.
00750         else if (*json=='\r') json++;
00751         else if (*json=='\n') json++;
00752         else if (*json=='/' && json[1]=='/')  while (*json && *json!='\n') json++;  // double-slash comments, to end of line.
00753         else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;}   // multiline comments.
00754         else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} // string literals, which are \" sensitive.
00755         else *into++=*json++;           // All other characters.
00756     }
00757     *into=0;    // and null-terminate.
00758 }