Annotation of embedaddon/iperf/src/cjson.c, revision 1.1

1.1     ! misho       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: #ifdef HAVE_STDINT_H
        !            34: #include <stdint.h> 
        !            35: #endif
        !            36: #include <sys/types.h>
        !            37: #include "cjson.h"
        !            38: 
        !            39: #ifndef LLONG_MAX
        !            40: #define LLONG_MAX 9223372036854775807LL
        !            41: #endif
        !            42: #ifndef LLONG_MIN
        !            43: #define LLONG_MIN (-LLONG_MAX - 1LL)
        !            44: #endif
        !            45: static const char *global_ep;
        !            46: 
        !            47: const char *cJSON_GetErrorPtr(void) {return global_ep;}
        !            48: 
        !            49: static int cJSON_strcasecmp(const char *s1,const char *s2)
        !            50: {
        !            51:        if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
        !            52:        for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0)    return 0;
        !            53:        return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
        !            54: }
        !            55: 
        !            56: static void *(*cJSON_malloc)(size_t sz) = malloc;
        !            57: static void (*cJSON_free)(void *ptr) = free;
        !            58: 
        !            59: static char* cJSON_strdup(const char* str)
        !            60: {
        !            61:       size_t len;
        !            62:       char* copy;
        !            63: 
        !            64:       len = strlen(str) + 1;
        !            65:       if (!(copy = (char*)cJSON_malloc(len))) return 0;
        !            66:       memcpy(copy,str,len);
        !            67:       return copy;
        !            68: }
        !            69: 
        !            70: void cJSON_InitHooks(cJSON_Hooks* hooks)
        !            71: {
        !            72:     if (!hooks) { /* Reset hooks */
        !            73:         cJSON_malloc = malloc;
        !            74:         cJSON_free = free;
        !            75:         return;
        !            76:     }
        !            77: 
        !            78:        cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
        !            79:        cJSON_free       = (hooks->free_fn)?hooks->free_fn:free;
        !            80: }
        !            81: 
        !            82: /* Internal constructor. */
        !            83: static cJSON *cJSON_New_Item(void)
        !            84: {
        !            85:        cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
        !            86:        if (node) memset(node,0,sizeof(cJSON));
        !            87:        return node;
        !            88: }
        !            89: 
        !            90: /* Delete a cJSON structure. */
        !            91: void cJSON_Delete(cJSON *c)
        !            92: {
        !            93:        cJSON *next;
        !            94:        while (c)
        !            95:        {
        !            96:                next=c->next;
        !            97:                if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
        !            98:                if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
        !            99:                if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);
        !           100:                cJSON_free(c);
        !           101:                c=next;
        !           102:        }
        !           103: }
        !           104: 
        !           105: /* Parse the input text to generate a number, and populate the result into item. */
        !           106: static const char *parse_number(cJSON *item,const char *num)
        !           107: {
        !           108:        double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
        !           109: 
        !           110:        if (*num=='-') sign=-1,num++;   /* Has sign? */
        !           111:        if (*num=='0') num++;                   /* is zero */
        !           112:        if (*num>='1' && *num<='9')     do      n=(n*10.0)+(*num++ -'0');       while (*num>='0' && *num<='9'); /* Number? */
        !           113:        if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;            do      n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}      /* Fractional part? */
        !           114:        if (*num=='e' || *num=='E')             /* Exponent? */
        !           115:        {       num++;if (*num=='+') num++;     else if (*num=='-') signsubscale=-1,num++;              /* With sign? */
        !           116:                while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');   /* Number? */
        !           117:        }
        !           118: 
        !           119:        n=sign*n*pow(10.0,(scale+subscale*signsubscale));       /* number = +/- number.fraction * 10^+/- exponent */
        !           120:        
        !           121:        item->valuedouble=n;
        !           122:        item->valueint=(int64_t)n;
        !           123:        item->type=cJSON_Number;
        !           124:        return num;
        !           125: }
        !           126: 
        !           127: static int pow2gt (int x)      {       --x;    x|=x>>1;        x|=x>>2;        x|=x>>4;        x|=x>>8;        x|=x>>16;       return x+1;     }
        !           128: 
        !           129: typedef struct {char *buffer; int length; int offset; } printbuffer;
        !           130: 
        !           131: static char* ensure(printbuffer *p,int needed)
        !           132: {
        !           133:        char *newbuffer;int newsize;
        !           134:        if (!p || !p->buffer) return 0;
        !           135:        needed+=p->offset;
        !           136:        if (needed<=p->length) return p->buffer+p->offset;
        !           137: 
        !           138:        newsize=pow2gt(needed);
        !           139:        newbuffer=(char*)cJSON_malloc(newsize);
        !           140:        if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}
        !           141:        if (newbuffer) memcpy(newbuffer,p->buffer,p->length);
        !           142:        cJSON_free(p->buffer);
        !           143:        p->length=newsize;
        !           144:        p->buffer=newbuffer;
        !           145:        return newbuffer+p->offset;
        !           146: }
        !           147: 
        !           148: static int update(printbuffer *p)
        !           149: {
        !           150:        char *str;
        !           151:        if (!p || !p->buffer) return 0;
        !           152:        str=p->buffer+p->offset;
        !           153:        return p->offset+strlen(str);
        !           154: }
        !           155: 
        !           156: /* Render the number nicely from the given item into a string. */
        !           157: static char *print_number(cJSON *item,printbuffer *p)
        !           158: {
        !           159:        char *str=0;
        !           160:        double d=item->valuedouble;
        !           161:        if (d==0)
        !           162:        {
        !           163:                if (p)  str=ensure(p,2);
        !           164:                else    str=(char*)cJSON_malloc(2);     /* special case for 0. */
        !           165:                if (str) strcpy(str,"0");
        !           166:        }
        !           167:        else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=LLONG_MAX && d>=LLONG_MIN)
        !           168:        {
        !           169:                if (p)  str=ensure(p,64);
        !           170:                else    str=(char*)cJSON_malloc(64);
        !           171:                if (str)        sprintf(str,"%lld",(long long) item->valueint);
        !           172:        }
        !           173:        else
        !           174:        {
        !           175:                if (p)  str=ensure(p,64);
        !           176:                else    str=(char*)cJSON_malloc(64);    /* This is a nice tradeoff. */
        !           177:                if (str)
        !           178:                {
        !           179:                        if (fpclassify(d) != FP_ZERO && !isnormal(d))                           sprintf(str,"null");
        !           180:                        else if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)       sprintf(str,"%.0f",d);
        !           181:                        else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)                                       sprintf(str,"%e",d);
        !           182:                        else                                                                                                            sprintf(str,"%f",d);
        !           183:                }
        !           184:        }
        !           185:        return str;
        !           186: }
        !           187: 
        !           188: static unsigned parse_hex4(const char *str)
        !           189: {
        !           190:        unsigned h=0;
        !           191:        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;
        !           192:        h=h<<4;str++;
        !           193:        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;
        !           194:        h=h<<4;str++;
        !           195:        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;
        !           196:        h=h<<4;str++;
        !           197:        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;
        !           198:        return h;
        !           199: }
        !           200: 
        !           201: /* Parse the input text into an unescaped cstring, and populate item. */
        !           202: static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
        !           203: static const char *parse_string(cJSON *item,const char *str,const char **ep)
        !           204: {
        !           205:        const char *ptr=str+1,*end_ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
        !           206:        if (*str!='\"') {*ep=str;return 0;}     /* not a string! */
        !           207:        
        !           208:        while (*end_ptr!='\"' && *end_ptr && ++len) if (*end_ptr++ == '\\') end_ptr++;  /* Skip escaped quotes. */
        !           209:        
        !           210:        out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
        !           211:        if (!out) return 0;
        !           212:        item->valuestring=out; /* assign here so out will be deleted during cJSON_Delete() later */
        !           213:        item->type=cJSON_String;
        !           214:        
        !           215:        ptr=str+1;ptr2=out;
        !           216:        while (ptr < end_ptr)
        !           217:        {
        !           218:                if (*ptr!='\\') *ptr2++=*ptr++;
        !           219:                else
        !           220:                {
        !           221:                        ptr++;
        !           222:                        switch (*ptr)
        !           223:                        {
        !           224:                                case 'b': *ptr2++='\b'; break;
        !           225:                                case 'f': *ptr2++='\f'; break;
        !           226:                                case 'n': *ptr2++='\n'; break;
        !           227:                                case 'r': *ptr2++='\r'; break;
        !           228:                                case 't': *ptr2++='\t'; break;
        !           229:                                case 'u':        /* transcode utf16 to utf8. */
        !           230:                                        uc=parse_hex4(ptr+1);ptr+=4;    /* get the unicode char. */
        !           231:                                        if (ptr >= end_ptr) {*ep=str;return 0;} /* invalid */
        !           232:                                        
        !           233:                                        if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)    {*ep=str;return 0;} /* check for invalid.   */
        !           234:                                        
        !           235:                                        if (uc>=0xD800 && uc<=0xDBFF)   /* UTF16 surrogate pairs.       */
        !           236:                                        {
        !           237:                                                if (ptr+6 > end_ptr)    {*ep=str;return 0;}     /* invalid */
        !           238:                                                if (ptr[1]!='\\' || ptr[2]!='u')    {*ep=str;return 0;} /* missing second-half of surrogate.    */
        !           239:                                                uc2=parse_hex4(ptr+3);ptr+=6;
        !           240:                                                if (uc2<0xDC00 || uc2>0xDFFF)       {*ep=str;return 0;} /* invalid second-half of surrogate.    */
        !           241:                                                uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
        !           242:                                        }
        !           243: 
        !           244:                                        len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
        !           245:                                        
        !           246:                                        switch (len) {
        !           247:                                                case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
        !           248:                                                case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
        !           249:                                                case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
        !           250:                                                case 1: *--ptr2 =(uc | firstByteMark[len]);
        !           251:                                        }
        !           252:                                        ptr2+=len;
        !           253:                                        break;
        !           254:                                default:  *ptr2++=*ptr; break;
        !           255:                        }
        !           256:                        ptr++;
        !           257:                }
        !           258:        }
        !           259:        *ptr2=0;
        !           260:        if (*ptr=='\"') ptr++;
        !           261:        return ptr;
        !           262: }
        !           263: 
        !           264: /* Render the cstring provided to an escaped version that can be printed. */
        !           265: static char *print_string_ptr(const char *str,printbuffer *p)
        !           266: {
        !           267:        const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;
        !           268: 
        !           269:        if (!str)
        !           270:        {
        !           271:                if (p)  out=ensure(p,3);
        !           272:                else    out=(char*)cJSON_malloc(3);
        !           273:                if (!out) return 0;
        !           274:                strcpy(out,"\"\"");
        !           275:                return out;
        !           276:        }
        !           277:        
        !           278:        for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0;
        !           279:        if (!flag)
        !           280:        {
        !           281:                len=ptr-str;
        !           282:                if (p) out=ensure(p,len+3);
        !           283:                else            out=(char*)cJSON_malloc(len+3);
        !           284:                if (!out) return 0;
        !           285:                ptr2=out;*ptr2++='\"';
        !           286:                strcpy(ptr2,str);
        !           287:                ptr2[len]='\"';
        !           288:                ptr2[len+1]=0;
        !           289:                return out;
        !           290:        }
        !           291:        
        !           292:        ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
        !           293:        
        !           294:        if (p)  out=ensure(p,len+3);
        !           295:        else    out=(char*)cJSON_malloc(len+3);
        !           296:        if (!out) return 0;
        !           297: 
        !           298:        ptr2=out;ptr=str;
        !           299:        *ptr2++='\"';
        !           300:        while (*ptr)
        !           301:        {
        !           302:                if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
        !           303:                else
        !           304:                {
        !           305:                        *ptr2++='\\';
        !           306:                        switch (token=*ptr++)
        !           307:                        {
        !           308:                                case '\\':      *ptr2++='\\';   break;
        !           309:                                case '\"':      *ptr2++='\"';   break;
        !           310:                                case '\b':      *ptr2++='b';    break;
        !           311:                                case '\f':      *ptr2++='f';    break;
        !           312:                                case '\n':      *ptr2++='n';    break;
        !           313:                                case '\r':      *ptr2++='r';    break;
        !           314:                                case '\t':      *ptr2++='t';    break;
        !           315:                                default: sprintf(ptr2,"u%04x",token);ptr2+=5;   break;  /* escape and print */
        !           316:                        }
        !           317:                }
        !           318:        }
        !           319:        *ptr2++='\"';*ptr2++=0;
        !           320:        return out;
        !           321: }
        !           322: /* Invote print_string_ptr (which is useful) on an item. */
        !           323: static char *print_string(cJSON *item,printbuffer *p)  {return print_string_ptr(item->valuestring,p);}
        !           324: 
        !           325: /* Predeclare these prototypes. */
        !           326: static const char *parse_value(cJSON *item,const char *value,const char **ep);
        !           327: static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
        !           328: static const char *parse_array(cJSON *item,const char *value,const char **ep);
        !           329: static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
        !           330: static const char *parse_object(cJSON *item,const char *value,const char **ep);
        !           331: static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);
        !           332: 
        !           333: /* Utility to jump whitespace and cr/lf */
        !           334: static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
        !           335: 
        !           336: /* Parse an object - create a new root, and populate. */
        !           337: cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
        !           338: {
        !           339:        const char *end=0,**ep=return_parse_end?return_parse_end:&global_ep;
        !           340:        cJSON *c=cJSON_New_Item();
        !           341:        *ep=0;
        !           342:        if (!c) return 0;       /* memory fail */
        !           343: 
        !           344:        end=parse_value(c,skip(value),ep);
        !           345:        if (!end)       {cJSON_Delete(c);return 0;}     /* parse failure. ep is set. */
        !           346: 
        !           347:        /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
        !           348:        if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);*ep=end;return 0;}}
        !           349:        if (return_parse_end) *return_parse_end=end;
        !           350:        return c;
        !           351: }
        !           352: /* Default options for cJSON_Parse */
        !           353: cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
        !           354: 
        !           355: /* Render a cJSON item/entity/structure to text. */
        !           356: char *cJSON_Print(cJSON *item)                         {return print_value(item,0,1,0);}
        !           357: char *cJSON_PrintUnformatted(cJSON *item)      {return print_value(item,0,0,0);}
        !           358: 
        !           359: char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
        !           360: {
        !           361:        printbuffer p;
        !           362:        p.buffer=(char*)cJSON_malloc(prebuffer);
        !           363:        p.length=prebuffer;
        !           364:        p.offset=0;
        !           365:        return print_value(item,0,fmt,&p);
        !           366: }
        !           367: 
        !           368: 
        !           369: /* Parser core - when encountering text, process appropriately. */
        !           370: static const char *parse_value(cJSON *item,const char *value,const char **ep)
        !           371: {
        !           372:        if (!value)                                             return 0;       /* Fail on null. */
        !           373:        if (!strncmp(value,"null",4))   { item->type=cJSON_NULL;  return value+4; }
        !           374:        if (!strncmp(value,"false",5))  { item->type=cJSON_False; return value+5; }
        !           375:        if (!strncmp(value,"true",4))   { item->type=cJSON_True; item->valueint=1;      return value+4; }
        !           376:        if (*value=='\"')                               { return parse_string(item,value,ep); }
        !           377:        if (*value=='-' || (*value>='0' && *value<='9'))        { return parse_number(item,value); }
        !           378:        if (*value=='[')                                { return parse_array(item,value,ep); }
        !           379:        if (*value=='{')                                { return parse_object(item,value,ep); }
        !           380: 
        !           381:        *ep=value;return 0;     /* failure. */
        !           382: }
        !           383: 
        !           384: /* Render a value to text. */
        !           385: static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
        !           386: {
        !           387:        char *out=0;
        !           388:        if (!item) return 0;
        !           389:        if (p)
        !           390:        {
        !           391:                switch ((item->type)&255)
        !           392:                {
        !           393:                        case cJSON_NULL:        {out=ensure(p,5);       if (out) strcpy(out,"null");    break;}
        !           394:                        case cJSON_False:       {out=ensure(p,6);       if (out) strcpy(out,"false");   break;}
        !           395:                        case cJSON_True:        {out=ensure(p,5);       if (out) strcpy(out,"true");    break;}
        !           396:                        case cJSON_Number:      out=print_number(item,p);break;
        !           397:                        case cJSON_String:      out=print_string(item,p);break;
        !           398:                        case cJSON_Array:       out=print_array(item,depth,fmt,p);break;
        !           399:                        case cJSON_Object:      out=print_object(item,depth,fmt,p);break;
        !           400:                }
        !           401:        }
        !           402:        else
        !           403:        {
        !           404:                switch ((item->type)&255)
        !           405:                {
        !           406:                        case cJSON_NULL:        out=cJSON_strdup("null");       break;
        !           407:                        case cJSON_False:       out=cJSON_strdup("false");break;
        !           408:                        case cJSON_True:        out=cJSON_strdup("true"); break;
        !           409:                        case cJSON_Number:      out=print_number(item,0);break;
        !           410:                        case cJSON_String:      out=print_string(item,0);break;
        !           411:                        case cJSON_Array:       out=print_array(item,depth,fmt,0);break;
        !           412:                        case cJSON_Object:      out=print_object(item,depth,fmt,0);break;
        !           413:                }
        !           414:        }
        !           415:        return out;
        !           416: }
        !           417: 
        !           418: /* Build an array from input text. */
        !           419: static const char *parse_array(cJSON *item,const char *value,const char **ep)
        !           420: {
        !           421:        cJSON *child;
        !           422:        if (*value!='[')        {*ep=value;return 0;}   /* not an array! */
        !           423: 
        !           424:        item->type=cJSON_Array;
        !           425:        value=skip(value+1);
        !           426:        if (*value==']') return value+1;        /* empty array. */
        !           427: 
        !           428:        item->child=child=cJSON_New_Item();
        !           429:        if (!item->child) return 0;              /* memory fail */
        !           430:        value=skip(parse_value(child,skip(value),ep));  /* skip any spacing, get the value. */
        !           431:        if (!value) return 0;
        !           432: 
        !           433:        while (*value==',')
        !           434:        {
        !           435:                cJSON *new_item;
        !           436:                if (!(new_item=cJSON_New_Item())) return 0;     /* memory fail */
        !           437:                child->next=new_item;new_item->prev=child;child=new_item;
        !           438:                value=skip(parse_value(child,skip(value+1),ep));
        !           439:                if (!value) return 0;   /* memory fail */
        !           440:        }
        !           441: 
        !           442:        if (*value==']') return value+1;        /* end of array */
        !           443:        *ep=value;return 0;     /* malformed. */
        !           444: }
        !           445: 
        !           446: /* Render an array to text */
        !           447: static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
        !           448: {
        !           449:        char **entries;
        !           450:        char *out=0,*ptr,*ret;int len=5;
        !           451:        cJSON *child=item->child;
        !           452:        int numentries=0,i=0,fail=0;
        !           453:        size_t tmplen=0;
        !           454:        
        !           455:        /* How many entries in the array? */
        !           456:        while (child) numentries++,child=child->next;
        !           457:        /* Explicitly handle numentries==0 */
        !           458:        if (!numentries)
        !           459:        {
        !           460:                if (p)  out=ensure(p,3);
        !           461:                else    out=(char*)cJSON_malloc(3);
        !           462:                if (out) strcpy(out,"[]");
        !           463:                return out;
        !           464:        }
        !           465: 
        !           466:        if (p)
        !           467:        {
        !           468:                /* Compose the output array. */
        !           469:                i=p->offset;
        !           470:                ptr=ensure(p,1);if (!ptr) return 0;     *ptr='[';       p->offset++;
        !           471:                child=item->child;
        !           472:                while (child && !fail)
        !           473:                {
        !           474:                        print_value(child,depth+1,fmt,p);
        !           475:                        p->offset=update(p);
        !           476:                        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;}
        !           477:                        child=child->next;
        !           478:                }
        !           479:                ptr=ensure(p,2);if (!ptr) return 0;     *ptr++=']';*ptr=0;
        !           480:                out=(p->buffer)+i;
        !           481:        }
        !           482:        else
        !           483:        {
        !           484:                /* Allocate an array to hold the values for each */
        !           485:                entries=(char**)cJSON_malloc(numentries*sizeof(char*));
        !           486:                if (!entries) return 0;
        !           487:                memset(entries,0,numentries*sizeof(char*));
        !           488:                /* Retrieve all the results: */
        !           489:                child=item->child;
        !           490:                while (child && !fail)
        !           491:                {
        !           492:                        ret=print_value(child,depth+1,fmt,0);
        !           493:                        entries[i++]=ret;
        !           494:                        if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
        !           495:                        child=child->next;
        !           496:                }
        !           497:                
        !           498:                /* If we didn't fail, try to malloc the output string */
        !           499:                if (!fail)      out=(char*)cJSON_malloc(len);
        !           500:                /* If that fails, we fail. */
        !           501:                if (!out) fail=1;
        !           502: 
        !           503:                /* Handle failure. */
        !           504:                if (fail)
        !           505:                {
        !           506:                        for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
        !           507:                        cJSON_free(entries);
        !           508:                        return 0;
        !           509:                }
        !           510:                
        !           511:                /* Compose the output array. */
        !           512:                *out='[';
        !           513:                ptr=out+1;*ptr=0;
        !           514:                for (i=0;i<numentries;i++)
        !           515:                {
        !           516:                        tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;
        !           517:                        if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
        !           518:                        cJSON_free(entries[i]);
        !           519:                }
        !           520:                cJSON_free(entries);
        !           521:                *ptr++=']';*ptr++=0;
        !           522:        }
        !           523:        return out;     
        !           524: }
        !           525: 
        !           526: /* Build an object from the text. */
        !           527: static const char *parse_object(cJSON *item,const char *value,const char **ep)
        !           528: {
        !           529:        cJSON *child;
        !           530:        if (*value!='{')        {*ep=value;return 0;}   /* not an object! */
        !           531:        
        !           532:        item->type=cJSON_Object;
        !           533:        value=skip(value+1);
        !           534:        if (*value=='}') return value+1;        /* empty array. */
        !           535:        
        !           536:        item->child=child=cJSON_New_Item();
        !           537:        if (!item->child) return 0;
        !           538:        value=skip(parse_string(child,skip(value),ep));
        !           539:        if (!value) return 0;
        !           540:        child->string=child->valuestring;child->valuestring=0;
        !           541:        if (*value!=':') {*ep=value;return 0;}  /* fail! */
        !           542:        value=skip(parse_value(child,skip(value+1),ep));        /* skip any spacing, get the value. */
        !           543:        if (!value) return 0;
        !           544:        
        !           545:        while (*value==',')
        !           546:        {
        !           547:                cJSON *new_item;
        !           548:                if (!(new_item=cJSON_New_Item()))       return 0; /* memory fail */
        !           549:                child->next=new_item;new_item->prev=child;child=new_item;
        !           550:                value=skip(parse_string(child,skip(value+1),ep));
        !           551:                if (!value) return 0;
        !           552:                child->string=child->valuestring;child->valuestring=0;
        !           553:                if (*value!=':') {*ep=value;return 0;}  /* fail! */
        !           554:                value=skip(parse_value(child,skip(value+1),ep));        /* skip any spacing, get the value. */
        !           555:                if (!value) return 0;
        !           556:        }
        !           557:        
        !           558:        if (*value=='}') return value+1;        /* end of array */
        !           559:        *ep=value;return 0;     /* malformed. */
        !           560: }
        !           561: 
        !           562: /* Render an object to text. */
        !           563: static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
        !           564: {
        !           565:        char **entries=0,**names=0;
        !           566:        char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
        !           567:        cJSON *child=item->child;
        !           568:        int numentries=0,fail=0;
        !           569:        size_t tmplen=0;
        !           570:        /* Count the number of entries. */
        !           571:        while (child) numentries++,child=child->next;
        !           572:        /* Explicitly handle empty object case */
        !           573:        if (!numentries)
        !           574:        {
        !           575:                if (p) out=ensure(p,fmt?depth+4:3);
        !           576:                else    out=(char*)cJSON_malloc(fmt?depth+4:3);
        !           577:                if (!out)       return 0;
        !           578:                ptr=out;*ptr++='{';
        !           579:                if (fmt) {*ptr++='\n';for (i=0;i<depth;i++) *ptr++='\t';}
        !           580:                *ptr++='}';*ptr++=0;
        !           581:                return out;
        !           582:        }
        !           583:        if (p)
        !           584:        {
        !           585:                /* Compose the output: */
        !           586:                i=p->offset;
        !           587:                len=fmt?2:1;    ptr=ensure(p,len+1);    if (!ptr) return 0;
        !           588:                *ptr++='{';     if (fmt) *ptr++='\n';   *ptr=0; p->offset+=len;
        !           589:                child=item->child;depth++;
        !           590:                while (child)
        !           591:                {
        !           592:                        if (fmt)
        !           593:                        {
        !           594:                                ptr=ensure(p,depth);    if (!ptr) return 0;
        !           595:                                for (j=0;j<depth;j++) *ptr++='\t';
        !           596:                                p->offset+=depth;
        !           597:                        }
        !           598:                        print_string_ptr(child->string,p);
        !           599:                        p->offset=update(p);
        !           600:                        
        !           601:                        len=fmt?2:1;
        !           602:                        ptr=ensure(p,len);      if (!ptr) return 0;
        !           603:                        *ptr++=':';if (fmt) *ptr++='\t';
        !           604:                        p->offset+=len;
        !           605:                        
        !           606:                        print_value(child,depth,fmt,p);
        !           607:                        p->offset=update(p);
        !           608: 
        !           609:                        len=(fmt?1:0)+(child->next?1:0);
        !           610:                        ptr=ensure(p,len+1); if (!ptr) return 0;
        !           611:                        if (child->next) *ptr++=',';
        !           612:                        if (fmt) *ptr++='\n';*ptr=0;
        !           613:                        p->offset+=len;
        !           614:                        child=child->next;
        !           615:                }
        !           616:                ptr=ensure(p,fmt?(depth+1):2);   if (!ptr) return 0;
        !           617:                if (fmt)        for (i=0;i<depth-1;i++) *ptr++='\t';
        !           618:                *ptr++='}';*ptr=0;
        !           619:                out=(p->buffer)+i;
        !           620:        }
        !           621:        else
        !           622:        {
        !           623:                /* Allocate space for the names and the objects */
        !           624:                entries=(char**)cJSON_malloc(numentries*sizeof(char*));
        !           625:                if (!entries) return 0;
        !           626:                names=(char**)cJSON_malloc(numentries*sizeof(char*));
        !           627:                if (!names) {cJSON_free(entries);return 0;}
        !           628:                memset(entries,0,sizeof(char*)*numentries);
        !           629:                memset(names,0,sizeof(char*)*numentries);
        !           630: 
        !           631:                /* Collect all the results into our arrays: */
        !           632:                child=item->child;depth++;if (fmt) len+=depth;
        !           633:                while (child && !fail)
        !           634:                {
        !           635:                        names[i]=str=print_string_ptr(child->string,0);
        !           636:                        entries[i++]=ret=print_value(child,depth,fmt,0);
        !           637:                        if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
        !           638:                        child=child->next;
        !           639:                }
        !           640:                
        !           641:                /* Try to allocate the output string */
        !           642:                if (!fail)      out=(char*)cJSON_malloc(len);
        !           643:                if (!out) fail=1;
        !           644: 
        !           645:                /* Handle failure */
        !           646:                if (fail)
        !           647:                {
        !           648:                        for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
        !           649:                        cJSON_free(names);cJSON_free(entries);
        !           650:                        return 0;
        !           651:                }
        !           652:                
        !           653:                /* Compose the output: */
        !           654:                *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
        !           655:                for (i=0;i<numentries;i++)
        !           656:                {
        !           657:                        if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
        !           658:                        tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;
        !           659:                        *ptr++=':';if (fmt) *ptr++='\t';
        !           660:                        strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
        !           661:                        if (i!=numentries-1) *ptr++=',';
        !           662:                        if (fmt) *ptr++='\n';*ptr=0;
        !           663:                        cJSON_free(names[i]);cJSON_free(entries[i]);
        !           664:                }
        !           665:                
        !           666:                cJSON_free(names);cJSON_free(entries);
        !           667:                if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
        !           668:                *ptr++='}';*ptr++=0;
        !           669:        }
        !           670:        return out;     
        !           671: }
        !           672: 
        !           673: /* Get Array size/item / object item. */
        !           674: int    cJSON_GetArraySize(cJSON *array)                                                        {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
        !           675: cJSON *cJSON_GetArrayItem(cJSON *array,int item)                               {cJSON *c=array?array->child:0;while (c && item>0) item--,c=c->next; return c;}
        !           676: cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)   {cJSON *c=object?object->child:0;while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
        !           677: int cJSON_HasObjectItem(cJSON *object,const char *string)              {return cJSON_GetObjectItem(object,string)?1:0;}
        !           678: 
        !           679: /* Utility for array list handling. */
        !           680: static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
        !           681: /* Utility for handling references. */
        !           682: 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;}
        !           683: 
        !           684: /* Add item to array/object. */
        !           685: 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);}}
        !           686: 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);}
        !           687: 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);}
        !           688: void   cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)                                                {cJSON_AddItemToArray(array,create_reference(item));}
        !           689: void   cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)    {cJSON_AddItemToObject(object,string,create_reference(item));}
        !           690: 
        !           691: cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)                       {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
        !           692:        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;}
        !           693: void   cJSON_DeleteItemFromArray(cJSON *array,int which)                       {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
        !           694: 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;}
        !           695: void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
        !           696: 
        !           697: /* Replace array/object items with new ones. */
        !           698: void   cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem)          {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;}
        !           699:        newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;}
        !           700: void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)         {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
        !           701:        newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
        !           702:        if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
        !           703: 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);}}
        !           704: 
        !           705: /* Create basic types: */
        !           706: cJSON *cJSON_CreateNull(void)                                  {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
        !           707: cJSON *cJSON_CreateTrue(void)                                  {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
        !           708: cJSON *cJSON_CreateFalse(void)                                 {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
        !           709: cJSON *cJSON_CreateBool(int b)                                 {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
        !           710: cJSON *cJSON_CreateNumber(double num)                  {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int64_t)num;}return item;}
        !           711: cJSON *cJSON_CreateString(const char *string)  {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);if(!item->valuestring){cJSON_Delete(item);return 0;}}return item;}
        !           712: cJSON *cJSON_CreateArray(void)                                 {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
        !           713: cJSON *cJSON_CreateObject(void)                                        {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
        !           714: 
        !           715: /* Create Arrays: */
        !           716: 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(!n){cJSON_Delete(a);return 0;}if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
        !           717: 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(!n){cJSON_Delete(a);return 0;}if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
        !           718: 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(!n){cJSON_Delete(a);return 0;}if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
        !           719: 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(!n){cJSON_Delete(a);return 0;}if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
        !           720: 
        !           721: /* Duplication */
        !           722: cJSON *cJSON_Duplicate(cJSON *item,int recurse)
        !           723: {
        !           724:        cJSON *newitem,*cptr,*nptr=0,*newchild;
        !           725:        /* Bail on bad ptr */
        !           726:        if (!item) return 0;
        !           727:        /* Create new item */
        !           728:        newitem=cJSON_New_Item();
        !           729:        if (!newitem) return 0;
        !           730:        /* Copy over all vars */
        !           731:        newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
        !           732:        if (item->valuestring)  {newitem->valuestring=cJSON_strdup(item->valuestring);  if (!newitem->valuestring)      {cJSON_Delete(newitem);return 0;}}
        !           733:        if (item->string)               {newitem->string=cJSON_strdup(item->string);                    if (!newitem->string)           {cJSON_Delete(newitem);return 0;}}
        !           734:        /* If non-recursive, then we're done! */
        !           735:        if (!recurse) return newitem;
        !           736:        /* Walk the ->next chain for the child. */
        !           737:        cptr=item->child;
        !           738:        while (cptr)
        !           739:        {
        !           740:                newchild=cJSON_Duplicate(cptr,1);               /* Duplicate (with recurse) each item in the ->next chain */
        !           741:                if (!newchild) {cJSON_Delete(newitem);return 0;}
        !           742:                if (nptr)       {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}        /* If newitem->child already set, then crosswire ->prev and ->next and move on */
        !           743:                else            {newitem->child=newchild;nptr=newchild;}                                        /* Set newitem->child and move to it */
        !           744:                cptr=cptr->next;
        !           745:        }
        !           746:        return newitem;
        !           747: }
        !           748: 
        !           749: void cJSON_Minify(char *json)
        !           750: {
        !           751:        char *into=json;
        !           752:        while (*json)
        !           753:        {
        !           754:                if (*json==' ') json++;
        !           755:                else if (*json=='\t') json++;   /* Whitespace characters. */
        !           756:                else if (*json=='\r') json++;
        !           757:                else if (*json=='\n') json++;
        !           758:                else if (*json=='/' && json[1]=='/')  while (*json && *json!='\n') json++;      /* double-slash comments, to end of line. */
        !           759:                else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;}   /* multiline comments. */
        !           760:                else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */
        !           761:                else *into++=*json++;                   /* All other characters. */
        !           762:        }
        !           763:        *into=0;        /* and null-terminate. */
        !           764: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>