From 805b652e51477778e50337d44581b279e90f93a9 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 26 Aug 2009 03:55:20 +0000 Subject: [PATCH 01/58] here it is, cJSON 1.0 git-svn-id: http://svn.code.sf.net/p/cjson/code@1 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++++++++ cJSON.h | 91 +++++++++++++ test.c | 148 +++++++++++++++++++++ tests/test1 | 22 ++++ tests/test2 | 11 ++ tests/test3 | 26 ++++ tests/test4 | 88 +++++++++++++ tests/test5 | 27 ++++ 8 files changed, 773 insertions(+) create mode 100644 cJSON.c create mode 100644 cJSON.h create mode 100644 test.c create mode 100644 tests/test1 create mode 100644 tests/test2 create mode 100644 tests/test3 create mode 100644 tests/test4 create mode 100644 tests/test5 diff --git a/cJSON.c b/cJSON.c new file mode 100644 index 0000000..bd534e2 --- /dev/null +++ b/cJSON.c @@ -0,0 +1,360 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +// cJSON +// JSON parser in C. + +#include +#include +#include +#include +#include +#include "cJSON.h" + +// Internal constructor. +static cJSON *cJSON_New_Item() { return (cJSON*)calloc(sizeof(cJSON),1); } + +// Delete a cJSON structure. +void cJSON_Delete(cJSON *c) +{ + cJSON *next; + while (c) + { + next=c->next; + if (c->child) cJSON_Delete(c->child); + if (c->valuestring) free(c->valuestring); + if (c->string) free(c->string); + free(c); + c=next; + } +} + +// Parse the input text to generate a number, and populate the result into item. +static const char *parse_number(cJSON *item,const char *num) +{ + double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; + + // Could use sscanf for this? + if (*num=='-') sign=-1,num++; // Has sign? + if (*num=='0') num++; // is zero + if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); // Number? + if (*num=='.') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} // Fractional part? + if (*num=='e' || *num=='E') // Exponent? + { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; // With sign? + while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); // Number? + } + + n=sign*n*pow(10.0,(scale+subscale*signsubscale)); // number = +/- number.fraction * 10^+/- exponent + + item->valuedouble=n; + item->valueint=(int)n; + item->type=cJSON_Number; + return num; +} + +// Render the number nicely from the given item into a string. +static char *print_number(cJSON *item) +{ + char *str; + double d=item->valuedouble; + if (fabs(((double)item->valueint)-d)<=DBL_EPSILON) + { + str=malloc(21); // 2^64+1 can be represented in 21 chars. + sprintf(str,"%d",item->valueint); + } + else + { + str=malloc(64); // This is a nice tradeoff. + if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); + else sprintf(str,"%f",d); + } + return str; +} + +// Parse the input text into an unescaped cstring, and populate item. +static const char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; +static const char *parse_string(cJSON *item,const char *str) +{ + const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; + if (*str!='\"') return 0; // not a string! + + while (*ptr!='\"' && *ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes. + + out=(char*)malloc(len+1); // This is how long we need for the string, roughly. + + ptr=str+1;ptr2=out; + while (*ptr!='\"' && *ptr>31) + { + if (*ptr!='\\') *ptr2++=*ptr++; + else + { + ptr++; + switch (*ptr) + { + case 'b': *ptr2++='\b'; break; + case 'f': *ptr2++='\f'; break; + case 'n': *ptr2++='\n'; break; + case 'r': *ptr2++='\r'; break; + case 't': *ptr2++='\t'; break; + case 'u': // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY. + sscanf(ptr+1,"%4x",&uc); // get the unicode char. + len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len; + + switch (len) { + case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 1: *--ptr2 =(uc | firstByteMark[len]); + } + ptr2+=len;ptr+=4; + break; + default: *ptr2++=*ptr; break; + } + ptr++; + } + } + *ptr2=0; + if (*ptr=='\"') ptr++; + item->valuestring=out; + item->type=cJSON_String; + return ptr; +} + +// Render the cstring provided to an escaped version that can be printed. +static char *print_string_ptr(const char *str) +{ + const char *ptr;char *ptr2,*out;int len=0; + + ptr=str;while (*ptr && ++len) {if (*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} + + out=(char*)malloc(len+3); + ptr2=out;ptr=str; + *ptr2++='\"'; + while (*ptr) + { + if (*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; + else + { + *ptr2++='\\'; + switch (*ptr++) + { + case '\\': *ptr2++='\\'; break; + case '\"': *ptr2++='\"'; break; + case '\b': *ptr2++='b'; break; + case '\f': *ptr2++='f'; break; + case '\n': *ptr2++='n'; break; + case '\r': *ptr2++='r'; break; + case '\t': *ptr2++='t'; break; + default: ptr2--; break; // eviscerate with prejudice. + } + } + } + *ptr2++='\"';*ptr2++=0; + return out; +} +// Invote print_string_ptr (which is useful) on an item. +static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} + +// Predeclare these prototypes. +static const char *parse_value(cJSON *item,const char *value); +static char *print_value(cJSON *item,int depth); +static const char *parse_array(cJSON *item,const char *value); +static char *print_array(cJSON *item,int depth); +static const char *parse_object(cJSON *item,const char *value); +static char *print_object(cJSON *item,int depth); + +// Parse an object - create a new root, and populate. +cJSON *cJSON_Parse(const char *value) {cJSON *c=cJSON_New_Item();parse_value(c,value);return c;} +// Render a cJSON item/entity/structure to text. +char *cJSON_Print(cJSON *item) {return print_value(item,0);} + +// Parser core - when encountering text, process appropriately. +static const char *parse_value(cJSON *item,const char *value) +{ + if (!value) return 0; // Fail on null. + if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } + if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } + if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } + if (*value=='\"') { return parse_string(item,value); } + if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } + if (*value=='[') { return parse_array(item,value); } + if (*value=='{') { return parse_object(item,value); } + + return 0; // failure. +} + +// Render a value to text. +static char *print_value(cJSON *item,int depth) +{ + char *out=0; + switch (item->type) + { + case cJSON_NULL: out=strdup("null"); break; + case cJSON_False: out=strdup("false");break; + case cJSON_True: out=strdup("true"); break; + case cJSON_Number: out=print_number(item);break; + case cJSON_String: out=print_string(item);break; + case cJSON_Array: out=print_array(item,depth);break; + case cJSON_Object: out=print_object(item,depth);break; + } + return out; +} + +// Utility to jump whitespace and cr/lf +static const char *skip(const char *in) {while (in && *in<=32) in++; return in;} + +// Build an array from input text. +static const char *parse_array(cJSON *item,const char *value) +{ + cJSON *child; + if (*value!='[') return 0; // not an array! + + item->type=cJSON_Array; + value=skip(value+1); + if (*value==']') return value+1; // empty array. + + item->child=child=cJSON_New_Item(); + value=skip(parse_value(child,skip(value))); // skip any spacing, get the value. + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; // memory fail + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_value(child,skip(value+1))); + } + + if (*value==']') return value+1; // end of array + return 0; // malformed. +} + +// Render an array to text +static char *print_array(cJSON *item,int depth) +{ + char *out,*ptr,*ret;int len=5; + cJSON *child=item->child; + + out=malloc(len);*out='['; + ptr=out+1;*ptr=0; + while (child) + { + ret=print_value(child,depth+1); + if (!ret) {free(out);return 0;} // Check for failure! + len+=strlen(ret)+3; + out=realloc(out,len); + ptr=out+strlen(out); + ptr+=sprintf(ptr,ret); + if (child->next) {*ptr++=',';*ptr++=' ';*ptr=0;} + child=child->next; + free(ret); + } + *ptr++=']';*ptr++=0; + return out; +} + +// Build an object from the text. +static const char *parse_object(cJSON *item,const char *value) +{ + cJSON *child; + if (*value!='{') return 0; // not an object! + + item->type=cJSON_Object; + value=skip(value+1); + if (*value=='}') return value+1; // empty array. + + item->child=child=cJSON_New_Item(); + value=skip(parse_string(child,skip(value))); + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') return 0; // fail! + value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; // memory fail + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_string(child,skip(value+1))); + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') return 0; // fail! + value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. + } + + if (*value=='}') return value+1; // end of array + return 0; // malformed. +} + +// Render an object to text. +static char *print_object(cJSON *item,int depth) +{ + char *out,*ptr,*ret,*str;int len=7,i; + cJSON *child=item->child; + + depth++;out=malloc(len+depth);*out='{'; + ptr=out+1;*ptr++='\n';*ptr=0; + while (child) + { + str=print_string_ptr(child->string); + if (!str) {free(out);return 0;} + ret=print_value(child,depth); + if (!ret) {free(out);return 0;} // Check for failure! + len+=strlen(ret)+strlen(str)+4+depth; + out=realloc(out,len); + ptr=out+strlen(out); + for (i=0;inext) *ptr++=','; + *ptr++='\n';*ptr=0; + child=child->next; + free(str);free(ret); + } + for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} +cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item) item--,c=c->next; return c;} +cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && strcasecmp(c->string,string)) c=c->next; return c;} + +// Utility for array list handling. +static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} + +// Add item to array/object. +void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} +void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) free(item->string);item->string=strdup(string);cJSON_AddItemToArray(object,item);} + +// Create basic types: +cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;} +cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();item->type=cJSON_True;return item;} +cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();item->type=cJSON_False;return item;} +cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;return item;} +cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();item->type=cJSON_String;item->valuestring=strdup(string);return item;} +cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();item->type=cJSON_Array;return item;} +cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();item->type=cJSON_Object;return item;} + +// Create Arrays: +cJSON *cJSON_CreateIntArray(int *numbers,int count) {cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(int i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateFloatArray(float *numbers,int count) {cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(int i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(int i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateStringArray(const char **strings,int count) {cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(int i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} diff --git a/cJSON.h b/cJSON.h new file mode 100644 index 0000000..e4df514 --- /dev/null +++ b/cJSON.h @@ -0,0 +1,91 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +// cJSON Types: +#define cJSON_False 0 +#define cJSON_True 1 +#define cJSON_NULL 2 +#define cJSON_Number 3 +#define cJSON_String 4 +#define cJSON_Array 5 +#define cJSON_Object 6 + +// The cJSON structure: +typedef struct cJSON { + struct cJSON *next,*prev; // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem + struct cJSON *child; // An array or object item will have a child pointer pointing to a chain of the items in the array/object. + + int type; // The type of the item, as above. + + char *valuestring; // The item's string, if type==cJSON_String + int valueint; // The item's number, if type==cJSON_Number + double valuedouble; // The item's number, if type==cJSON_Number + + char *string; // The item's name string, if this item is the child of, or is in the list of subitems of an object. +} cJSON; + +// Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. +extern cJSON *cJSON_Parse(const char *value); +// Render a cJSON entity to text for transfer/storage. Free the char* when finished. +extern char *cJSON_Print(cJSON *item); +// Delete a cJSON entity and all subentities. +extern void cJSON_Delete(cJSON *c); + +// Returns the number of items in an array (or object). +extern int cJSON_GetArraySize(cJSON *array); +// Retrieve item number "item" from array "array". Returns NULL if unsuccessful. +extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); +// Get item "string" from object. Case insensitive. +extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); + +// These calls create a cJSON item of the appropriate type. +extern cJSON *cJSON_CreateNull(); +extern cJSON *cJSON_CreateTrue(); +extern cJSON *cJSON_CreateFalse(); +extern cJSON *cJSON_CreateNumber(double num); +extern cJSON *cJSON_CreateString(const char *string); +extern cJSON *cJSON_CreateArray(); +extern cJSON *cJSON_CreateObject(); + +// These utilities create an Array of count items. +extern cJSON *cJSON_CreateIntArray(int *numbers,int count); +extern cJSON *cJSON_CreateFloatArray(float *numbers,int count); +extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); +extern cJSON *cJSON_CreateStringArray(const char **strings,int count); + +// Append item to the specified array/object. +extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test.c b/test.c new file mode 100644 index 0000000..dbd66e1 --- /dev/null +++ b/test.c @@ -0,0 +1,148 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include +#include "cJSON.h" + +// Parse text to JSON, then render back to text, and print! +void doit(char *text) +{ + char *out;cJSON *json; + + json=cJSON_Parse(text); + out=cJSON_Print(json); + cJSON_Delete(json); + printf("%s\n",out); + free(out); +} + +// Read a file, parse, render back, etc. +void dofile(char *filename) +{ + FILE *f=fopen(filename,"rb");fseek(f,0,SEEK_END);long len=ftell(f);fseek(f,0,SEEK_SET); + char *data=malloc(len+1);fread(data,1,len,f);fclose(f); + doit(data); + free(data); +} + +// Used by some code below as an example datatype. +struct record {const char *precision;double lat,lon;const char *address,*city,*state,*zip,*country; }; + +// Create a bunch of objects as demonstration. +void create_objects() +{ + cJSON *root,*fmt,*img,*thm,*fld;char *out;int i; // declare a few. + + // Here we construct some JSON standards, from the JSON site. + + // Our "Video" datatype: + root=cJSON_CreateObject(); + cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); + cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject()); + cJSON_AddItemToObject(fmt,"type", cJSON_CreateString("rect")); + cJSON_AddItemToObject(fmt,"width", cJSON_CreateNumber(1920)); + cJSON_AddItemToObject(fmt,"height", cJSON_CreateNumber(1080)); + cJSON_AddItemToObject(fmt,"interlace", cJSON_CreateFalse()); + cJSON_AddItemToObject(fmt,"frame rate", cJSON_CreateNumber(24)); + + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); // Print to text, Delete the cJSON, print it, release the string. + + // Our "days of the week" array: + const char *strings[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}; + root=cJSON_CreateStringArray(strings,7); + + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); + + // Our matrix: + int numbers[3][3]={{0,-1,0},{1,0,0},{0,0,1}}; + root=cJSON_CreateArray(); + for (i=0;i<3;i++) cJSON_AddItemToArray(root,cJSON_CreateIntArray(numbers[i],3)); + + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); + + + // Our "gallery" item: + int ids[4]={116,943,234,38793}; + root=cJSON_CreateObject(); + cJSON_AddItemToObject(root, "Image", img=cJSON_CreateObject()); + cJSON_AddItemToObject(img,"Width",cJSON_CreateNumber(800)); + cJSON_AddItemToObject(img,"Height",cJSON_CreateNumber(600)); + cJSON_AddItemToObject(img,"Title",cJSON_CreateString("View from 15th Floor")); + cJSON_AddItemToObject(img, "Thumbnail", thm=cJSON_CreateObject()); + cJSON_AddItemToObject(thm, "Url", cJSON_CreateString("http://www.example.com/image/481989943")); + cJSON_AddItemToObject(thm,"Height",cJSON_CreateNumber(125)); + cJSON_AddItemToObject(thm,"Width",cJSON_CreateString("100")); + cJSON_AddItemToObject(img,"IDs", cJSON_CreateIntArray(ids,4)); + + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); + + // Our array of "records": + struct record fields[2]={ + {"zip",37.7668,-1.223959e+2,"","SAN FRANCISCO","CA","94107","US"}, + {"zip",37.371991,-1.22026e+2,"","SUNNYVALE","CA","94085","US"}}; + + root=cJSON_CreateArray(); + for (int i=0;i<2;i++) + { + cJSON_AddItemToArray(root,fld=cJSON_CreateObject()); + cJSON_AddItemToObject(fld, "precision", cJSON_CreateString(fields[i].precision)); + cJSON_AddItemToObject(fld, "Latitude", cJSON_CreateNumber(fields[i].lat)); + cJSON_AddItemToObject(fld, "Longitude", cJSON_CreateNumber(fields[i].lon)); + cJSON_AddItemToObject(fld, "Address", cJSON_CreateString(fields[i].address)); + cJSON_AddItemToObject(fld, "City", cJSON_CreateString(fields[i].city)); + cJSON_AddItemToObject(fld, "State", cJSON_CreateString(fields[i].state)); + cJSON_AddItemToObject(fld, "Zip", cJSON_CreateString(fields[i].zip)); + cJSON_AddItemToObject(fld, "Country", cJSON_CreateString(fields[i].country)); + } + + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); + +} + +int main (int argc, const char * argv[]) { + // a bunch of json: + char text1[]="{\n\"name\": \"Jack (\\\"Bee\\\") Nimble\", \n\"format\": {\"type\": \"rect\", \n\"width\": 1920, \n\"height\": 1080, \n\"interlace\": false,\"frame rate\": 24\n}\n}"; + char text2[]="[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]"; + char text3[]="[\n [0, -1, 0],\n [1, 0, 0],\n [0, 0, 1]\n ]\n"; + char text4[]="{\n \"Image\": {\n \"Width\": 800,\n \"Height\": 600,\n \"Title\": \"View from 15th Floor\",\n \"Thumbnail\": {\n \"Url\": \"http://www.example.com/image/481989943\",\n \"Height\": 125,\n \"Width\": \"100\"\n },\n \"IDs\": [116, 943, 234, 38793]\n }\n }"; + char text5[]="[\n {\n \"precision\": \"zip\",\n \"Latitude\": 37.7668,\n \"Longitude\": -122.3959,\n \"Address\": \"\",\n \"City\": \"SAN FRANCISCO\",\n \"State\": \"CA\",\n \"Zip\": \"94107\",\n \"Country\": \"US\"\n },\n {\n \"precision\": \"zip\",\n \"Latitude\": 37.371991,\n \"Longitude\": -122.026020,\n \"Address\": \"\",\n \"City\": \"SUNNYVALE\",\n \"State\": \"CA\",\n \"Zip\": \"94085\",\n \"Country\": \"US\"\n }\n ]"; + + // Process each json textblock by parsing, then rebuilding: + doit(text1); + doit(text2); + doit(text3); + doit(text4); + doit(text5); + + // Parse standard testfiles: +// dofile("../../tests/test1"); +// dofile("../../tests/test2"); +// dofile("../../tests/test3"); +// dofile("../../tests/test4"); +// dofile("../../tests/test5"); + + // Now some samplecode for building objects concisely: + create_objects(); + + return 0; +} diff --git a/tests/test1 b/tests/test1 new file mode 100644 index 0000000..eacfbf5 --- /dev/null +++ b/tests/test1 @@ -0,0 +1,22 @@ +{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": ["GML", "XML"] + }, + "GlossSee": "markup" + } + } + } + } +} diff --git a/tests/test2 b/tests/test2 new file mode 100644 index 0000000..5600991 --- /dev/null +++ b/tests/test2 @@ -0,0 +1,11 @@ +{"menu": { + "id": "file", + "value": "File", + "popup": { + "menuitem": [ + {"value": "New", "onclick": "CreateNewDoc()"}, + {"value": "Open", "onclick": "OpenDoc()"}, + {"value": "Close", "onclick": "CloseDoc()"} + ] + } +}} diff --git a/tests/test3 b/tests/test3 new file mode 100644 index 0000000..5662b37 --- /dev/null +++ b/tests/test3 @@ -0,0 +1,26 @@ +{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}} \ No newline at end of file diff --git a/tests/test4 b/tests/test4 new file mode 100644 index 0000000..d540b57 --- /dev/null +++ b/tests/test4 @@ -0,0 +1,88 @@ +{"web-app": { + "servlet": [ + { + "servlet-name": "cofaxCDS", + "servlet-class": "org.cofax.cds.CDSServlet", + "init-param": { + "configGlossary:installationAt": "Philadelphia, PA", + "configGlossary:adminEmail": "ksm@pobox.com", + "configGlossary:poweredBy": "Cofax", + "configGlossary:poweredByIcon": "/images/cofax.gif", + "configGlossary:staticPath": "/content/static", + "templateProcessorClass": "org.cofax.WysiwygTemplate", + "templateLoaderClass": "org.cofax.FilesTemplateLoader", + "templatePath": "templates", + "templateOverridePath": "", + "defaultListTemplate": "listTemplate.htm", + "defaultFileTemplate": "articleTemplate.htm", + "useJSP": false, + "jspListTemplate": "listTemplate.jsp", + "jspFileTemplate": "articleTemplate.jsp", + "cachePackageTagsTrack": 200, + "cachePackageTagsStore": 200, + "cachePackageTagsRefresh": 60, + "cacheTemplatesTrack": 100, + "cacheTemplatesStore": 50, + "cacheTemplatesRefresh": 15, + "cachePagesTrack": 200, + "cachePagesStore": 100, + "cachePagesRefresh": 10, + "cachePagesDirtyRead": 10, + "searchEngineListTemplate": "forSearchEnginesList.htm", + "searchEngineFileTemplate": "forSearchEngines.htm", + "searchEngineRobotsDb": "WEB-INF/robots.db", + "useDataStore": true, + "dataStoreClass": "org.cofax.SqlDataStore", + "redirectionClass": "org.cofax.SqlRedirection", + "dataStoreName": "cofax", + "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", + "dataStoreUser": "sa", + "dataStorePassword": "dataStoreTestQuery", + "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", + "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", + "dataStoreInitConns": 10, + "dataStoreMaxConns": 100, + "dataStoreConnUsageLimit": 100, + "dataStoreLogLevel": "debug", + "maxUrlLength": 500}}, + { + "servlet-name": "cofaxEmail", + "servlet-class": "org.cofax.cds.EmailServlet", + "init-param": { + "mailHost": "mail1", + "mailHostOverride": "mail2"}}, + { + "servlet-name": "cofaxAdmin", + "servlet-class": "org.cofax.cds.AdminServlet"}, + + { + "servlet-name": "fileServlet", + "servlet-class": "org.cofax.cds.FileServlet"}, + { + "servlet-name": "cofaxTools", + "servlet-class": "org.cofax.cms.CofaxToolsServlet", + "init-param": { + "templatePath": "toolstemplates/", + "log": 1, + "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", + "logMaxSize": "", + "dataLog": 1, + "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", + "dataLogMaxSize": "", + "removePageCache": "/content/admin/remove?cache=pages&id=", + "removeTemplateCache": "/content/admin/remove?cache=templates&id=", + "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", + "lookInContext": 1, + "adminGroupID": 4, + "betaServer": true}}], + "servlet-mapping": { + "cofaxCDS": "/", + "cofaxEmail": "/cofaxutil/aemail/*", + "cofaxAdmin": "/admin/*", + "fileServlet": "/static/*", + "cofaxTools": "/tools/*"}, + + "taglib": { + "taglib-uri": "cofax.tld", + "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} \ No newline at end of file diff --git a/tests/test5 b/tests/test5 new file mode 100644 index 0000000..49980ca --- /dev/null +++ b/tests/test5 @@ -0,0 +1,27 @@ +{"menu": { + "header": "SVG Viewer", + "items": [ + {"id": "Open"}, + {"id": "OpenNew", "label": "Open New"}, + null, + {"id": "ZoomIn", "label": "Zoom In"}, + {"id": "ZoomOut", "label": "Zoom Out"}, + {"id": "OriginalView", "label": "Original View"}, + null, + {"id": "Quality"}, + {"id": "Pause"}, + {"id": "Mute"}, + null, + {"id": "Find", "label": "Find..."}, + {"id": "FindAgain", "label": "Find Again"}, + {"id": "Copy"}, + {"id": "CopyAgain", "label": "Copy Again"}, + {"id": "CopySVG", "label": "Copy SVG"}, + {"id": "ViewSVG", "label": "View SVG"}, + {"id": "ViewSource", "label": "View Source"}, + {"id": "SaveAs", "label": "Save As"}, + null, + {"id": "Help"}, + {"id": "About", "label": "About Adobe CVG Viewer..."} + ] +}} From a4a4e7cbffe7b413335e250a8b419c898bcc6112 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 26 Aug 2009 03:57:15 +0000 Subject: [PATCH 02/58] make these PROPERLY ansi-c compliant ;) git-svn-id: http://svn.code.sf.net/p/cjson/code@2 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 8 ++++---- test.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cJSON.c b/cJSON.c index bd534e2..86295ec 100644 --- a/cJSON.c +++ b/cJSON.c @@ -354,7 +354,7 @@ cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();item->type=cJSON_A cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();item->type=cJSON_Object;return item;} // Create Arrays: -cJSON *cJSON_CreateIntArray(int *numbers,int count) {cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(int i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateFloatArray(float *numbers,int count) {cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(int i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(int i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateStringArray(const char **strings,int count) {cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(int i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} diff --git a/test.c b/test.c index dbd66e1..a0d2360 100644 --- a/test.c +++ b/test.c @@ -102,7 +102,7 @@ void create_objects() {"zip",37.371991,-1.22026e+2,"","SUNNYVALE","CA","94085","US"}}; root=cJSON_CreateArray(); - for (int i=0;i<2;i++) + for (i=0;i<2;i++) { cJSON_AddItemToArray(root,fld=cJSON_CreateObject()); cJSON_AddItemToObject(fld, "precision", cJSON_CreateString(fields[i].precision)); From 5bd220c8dcc234e23ca4a37e1e1ce1f0c49d72be Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 26 Aug 2009 04:27:07 +0000 Subject: [PATCH 03/58] add macros. tighten code. git-svn-id: http://svn.code.sf.net/p/cjson/code@3 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.h | 8 +++++++- test.c | 38 +++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/cJSON.h b/cJSON.h index e4df514..9c137dd 100644 --- a/cJSON.h +++ b/cJSON.h @@ -83,7 +83,13 @@ extern cJSON *cJSON_CreateStringArray(const char **strings,int count); // Append item to the specified array/object. extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); - + +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) + #ifdef __cplusplus } #endif diff --git a/test.c b/test.c index a0d2360..a9f6697 100644 --- a/test.c +++ b/test.c @@ -59,11 +59,11 @@ void create_objects() root=cJSON_CreateObject(); cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject()); - cJSON_AddItemToObject(fmt,"type", cJSON_CreateString("rect")); - cJSON_AddItemToObject(fmt,"width", cJSON_CreateNumber(1920)); - cJSON_AddItemToObject(fmt,"height", cJSON_CreateNumber(1080)); - cJSON_AddItemToObject(fmt,"interlace", cJSON_CreateFalse()); - cJSON_AddItemToObject(fmt,"frame rate", cJSON_CreateNumber(24)); + cJSON_AddStringToObject(fmt,"type", "rect"); + cJSON_AddNumberToObject(fmt,"width", 1920); + cJSON_AddNumberToObject(fmt,"height", 1080); + cJSON_AddFalseToObject (fmt,"interlace"); + cJSON_AddNumberToObject(fmt,"frame rate", 24); out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); // Print to text, Delete the cJSON, print it, release the string. @@ -85,13 +85,13 @@ void create_objects() int ids[4]={116,943,234,38793}; root=cJSON_CreateObject(); cJSON_AddItemToObject(root, "Image", img=cJSON_CreateObject()); - cJSON_AddItemToObject(img,"Width",cJSON_CreateNumber(800)); - cJSON_AddItemToObject(img,"Height",cJSON_CreateNumber(600)); - cJSON_AddItemToObject(img,"Title",cJSON_CreateString("View from 15th Floor")); + cJSON_AddNumberToObject(img,"Width",800); + cJSON_AddNumberToObject(img,"Height",600); + cJSON_AddStringToObject(img,"Title","View from 15th Floor"); cJSON_AddItemToObject(img, "Thumbnail", thm=cJSON_CreateObject()); - cJSON_AddItemToObject(thm, "Url", cJSON_CreateString("http://www.example.com/image/481989943")); - cJSON_AddItemToObject(thm,"Height",cJSON_CreateNumber(125)); - cJSON_AddItemToObject(thm,"Width",cJSON_CreateString("100")); + cJSON_AddStringToObject(thm, "Url", "http://www.example.com/image/481989943"); + cJSON_AddNumberToObject(thm,"Height",125); + cJSON_AddStringToObject(thm,"Width","100"); cJSON_AddItemToObject(img,"IDs", cJSON_CreateIntArray(ids,4)); out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); @@ -105,14 +105,14 @@ void create_objects() for (i=0;i<2;i++) { cJSON_AddItemToArray(root,fld=cJSON_CreateObject()); - cJSON_AddItemToObject(fld, "precision", cJSON_CreateString(fields[i].precision)); - cJSON_AddItemToObject(fld, "Latitude", cJSON_CreateNumber(fields[i].lat)); - cJSON_AddItemToObject(fld, "Longitude", cJSON_CreateNumber(fields[i].lon)); - cJSON_AddItemToObject(fld, "Address", cJSON_CreateString(fields[i].address)); - cJSON_AddItemToObject(fld, "City", cJSON_CreateString(fields[i].city)); - cJSON_AddItemToObject(fld, "State", cJSON_CreateString(fields[i].state)); - cJSON_AddItemToObject(fld, "Zip", cJSON_CreateString(fields[i].zip)); - cJSON_AddItemToObject(fld, "Country", cJSON_CreateString(fields[i].country)); + cJSON_AddStringToObject(fld, "precision", fields[i].precision); + cJSON_AddNumberToObject(fld, "Latitude", fields[i].lat); + cJSON_AddNumberToObject(fld, "Longitude", fields[i].lon); + cJSON_AddStringToObject(fld, "Address", fields[i].address); + cJSON_AddStringToObject(fld, "City", fields[i].city); + cJSON_AddStringToObject(fld, "State", fields[i].state); + cJSON_AddStringToObject(fld, "Zip", fields[i].zip); + cJSON_AddStringToObject(fld, "Country", fields[i].country); } out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); From 733e62f9f443dc785bfee6391b8bb6aad61e6155 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 26 Aug 2009 04:58:08 +0000 Subject: [PATCH 04/58] a readme of documentation. git-svn-id: http://svn.code.sf.net/p/cjson/code@4 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- README | 247 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 README diff --git a/README b/README new file mode 100644 index 0000000..bbffb82 --- /dev/null +++ b/README @@ -0,0 +1,247 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +Welcome to cJSON. + +cJSON aims to be the dumbest possible parser that you can get your job done with. +It's a single file of C, and a single header file. + +JSON is described best here: http://www.json.org/ +It's like XML, but fat-free. You use it to move data around, store things, or just +generally represent your program's state. + + +First up, how do I build? +Add cJSON.c to your project, and put cJSON.h somewhere in the header search path. +For example, to build the test app: + +gcc cJSON.c test.c -o test +./test + + +As a library, cJSON exists to take away as much legwork as it can, but not get in your way. +As a point of pragmatism (i.e. ignoring the truth), I'm going to say that you can use it +in one of two modes: Auto and Manual. Let's have a quick run-through. + + +I lifted some JSON from this page: http://www.json.org/fatfree.html +That page inspired me to write cJSON, which is a parser that tries to share the same +philosophy as JSON itself. Simple, dumb, out of the way. + +Some JSON: +{ + "name": "Jack (\"Bee\") Nimble", + "format": { + "type": "rect", + "width": 1920, + "height": 1080, + "interlace": false, + "frame rate": 24 + } +} + +Assume that you got this from a file, a webserver, or magic JSON elves, whatever, +you have a char * to it. Everything is a cJSON struct. +Get it parsed: + cJSON *root = cJSON_Parse(my_json_string); + +This is an object. We're in C. We don't have objects. But we do have structs. +What's the framerate? + + cJSON *format = cJSON_GetObjectItem(root,"format"); + int framerate = cJSON_GetObjectItem(format,"frame rate")->valueint; + + +Want to change the framerate? + cJSON_GetObjectItem(format,"frame rate")->valueint=25; + +Back to disk? + char *rendered=cJSON_Print(root); + +Finished? Delete the root (this takes care of everything else). + cJSON_Delete(root); + +That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers +before you dereference them. If you want to see how you'd build this struct in code? + cJSON *root,*fmt; + root=cJSON_CreateObject(); + cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); + cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject()); + cJSON_AddStringToObject(fmt,"type", "rect"); + cJSON_AddNumberToObject(fmt,"width", 1920); + cJSON_AddNumberToObject(fmt,"height", 1080); + cJSON_AddFalseToObject (fmt,"interlace"); + cJSON_AddNumberToObject(fmt,"frame rate", 24); + +Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup. +Look at test.c for a bunch of nice examples, mostly all ripped off the json.org site, and +a few from elsewhere. + +What about manual mode? First up you need some detail. +Let's cover how the cJSON objects represent the JSON data. +cJSON doesn't distinguish arrays from objects in handling; just type. +Each cJSON has, potentially, a child, siblings, value, a name. + +The root object has: Object Type and a Child +The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling: +Sibling has type Object, name "format", and a child. +That child has type String, name "type", value "rect", and a sibling: +Sibling has type Number, name "width", value 1920, and a sibling: +Sibling has type Number, name "height", value 1080, and a sibling: +Sibling hs type False, name "interlace", and a sibling: +Sibling has type Number, name "frame rate", value 24 + +Here's the structure: +typedef struct cJSON { + struct cJSON *next,*prev; + struct cJSON *child; + + int type; + + char *valuestring; + int valueint; + double valuedouble; + + char *string; +} cJSON; + +By default all values are 0 unless set by virtue of being meaningful. + +next/prev is a doubly linked list of siblings. next takes you to your sibling, +prev takes you back from your sibling to you. +Only objects and arrays have a "child", and it's the head of the doubly linked list. +A "child" entry will have prev==0, but next potentially points on. The last sibling has next=0. +The type expresses Null/True/False/Number/String/Array/Object, all of which are #defined in +cJSON.h + +A Number has valueint and valuedouble. If you're expecting an int, read valueint, if not read +valuedouble. + +Any entry which is in the linked list which is the child of an object will have a "string" +which is the "name" of the entry. When I said "name" in the above example, that's "string". +"string" is the JSON name for the 'variable name' if you will. + +Now you can trivially walk the lists, recursively, and parse as you please. +You can invoke cJSON_Parse to get cJSON to parse for you, and then you can take +the root object, and traverse the structure (which is, formally, an N-tree), +and tokenise as you please. If you wanted to build a callback style parser, this is how +you'd do it (just an example, since these things are very specific): + +void parse_and_callback(cJSON *item,const char *prefix) +{ + while (item) + { + char *newprefix=malloc(strlen(prefix)+strlen(item->name)+2); + sprintf(newprefix,"%s/%s",prefix,item->name); + int dorecurse=callback(newprefix, item->type, item); + if (item->child && dorecurse) parse_and_callback(item->child,newprefix); + item=item->next; + free(newprefix); + } +} + +The prefix process will build you a separated list, to simplify your callback handling. +The 'dorecurse' flag would let the callback decide to handle sub-arrays on it's own, or +let you invoke it per-item. For the item above, your callback might look like this: + +int callback(const char *name,int type,cJSON *item) +{ + if (!strcmp(name,"name")) { /* populate name */ } + else if (!strcmp(name,"format/type") { /* handle "rect" */ } + else if (!strcmp(name,"format/width") { /* 800 */ } + else if (!strcmp(name,"format/height") { /* 600 */ } + else if (!strcmp(name,"format/interlace") { /* false */ } + else if (!strcmp(name,"format/frame rate") { /* 24 */ } + return 1; +} + +Alternatively, you might like to parse iteratively. +You'd use: + +void parse_object(cJSON *item) +{ + int i; for (i=0;ichild; + while (subitem) + { + // handle subitem + if (subitem->child) parse_object(subitem->child); + + subitem=subitem->next; + } +} + +Of course, this should look familiar, since this is just a stripped-down version +of the callback-parser. + +This should cover most uses you'll find for parsing. The rest should be possible +to infer.. and if in doubt, read the source! There's not a lot of it! ;) + + +In terms of constructing JSON data, the example code above is the right way to do it. +You can, of course, hand your sub-objects to other functions to populate. +Also, if you find a use for it, you can manually build the objects. +For instance, suppose you wanted to build an array of objects? + +cJSON *objects[24]; + +cJSON *Create_array_of_anything(cJSON **items,int num) +{ + int i;cJSON *prev, *root=cJSON_CreateArray(); + for (i=0;i<24;i++) + { + if (!i) root->child=objects[i]; + else prev->next=objects[i], objects[i]->prev=prev; + prev=objects[i]; + } + return root; +} + +and simply: Create_array_of_anything(objects,24); + +cJSON doesn't make any assumptions about what order you create things in. +You can attach the objects, as above, and later add children to each +of those objects. + +As soon as you call cJSON_Print, it renders the structure to text. + + + +The test.c code shows how to handle a bunch of typical cases. If you uncomment +the code, it'll load, parse and print a bunch of test files, also from json.org, +which are more complex than I'd care to try and stash into a const char array[]. + + +Enjoy cJSON! + + +- Dave Gamble, Aug 2009 \ No newline at end of file From 6d50358e261b7f1847e95a7da6ed8b89ac0c9b0d Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 9 Sep 2009 10:44:00 +0000 Subject: [PATCH 05/58] Windows/c++ support (with thanks to Ron Hall): added strcasecmp->stricmp added (char*) casts to all mallocs (as reqd by c++) added skip(value) to cJSON_Parse to allow for whitespace before the actual data git-svn-id: http://svn.code.sf.net/p/cjson/code@5 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/cJSON.c b/cJSON.c index 86295ec..63348a2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -30,6 +30,10 @@ #include #include "cJSON.h" +#ifdef WINDOWS +#define strcasecmp stricmp +#endif + // Internal constructor. static cJSON *cJSON_New_Item() { return (cJSON*)calloc(sizeof(cJSON),1); } @@ -78,12 +82,12 @@ static char *print_number(cJSON *item) double d=item->valuedouble; if (fabs(((double)item->valueint)-d)<=DBL_EPSILON) { - str=malloc(21); // 2^64+1 can be represented in 21 chars. + str=(char*)malloc(21); // 2^64+1 can be represented in 21 chars. sprintf(str,"%d",item->valueint); } else { - str=malloc(64); // This is a nice tradeoff. + str=(char*)malloc(64); // This is a nice tradeoff. if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); else sprintf(str,"%f",d); } @@ -181,8 +185,11 @@ static char *print_array(cJSON *item,int depth); static const char *parse_object(cJSON *item,const char *value); static char *print_object(cJSON *item,int depth); +// Utility to jump whitespace and cr/lf +static const char *skip(const char *in) {while (in && *in<=32) in++; return in;} + // Parse an object - create a new root, and populate. -cJSON *cJSON_Parse(const char *value) {cJSON *c=cJSON_New_Item();parse_value(c,value);return c;} +cJSON *cJSON_Parse(const char *value) {cJSON *c=cJSON_New_Item();parse_value(c,skip(value));return c;} // Render a cJSON item/entity/structure to text. char *cJSON_Print(cJSON *item) {return print_value(item,0);} @@ -218,9 +225,6 @@ static char *print_value(cJSON *item,int depth) return out; } -// Utility to jump whitespace and cr/lf -static const char *skip(const char *in) {while (in && *in<=32) in++; return in;} - // Build an array from input text. static const char *parse_array(cJSON *item,const char *value) { @@ -252,7 +256,7 @@ static char *print_array(cJSON *item,int depth) char *out,*ptr,*ret;int len=5; cJSON *child=item->child; - out=malloc(len);*out='['; + out=(char*)malloc(len);*out='['; ptr=out+1;*ptr=0; while (child) { @@ -307,7 +311,7 @@ static char *print_object(cJSON *item,int depth) char *out,*ptr,*ret,*str;int len=7,i; cJSON *child=item->child; - depth++;out=malloc(len+depth);*out='{'; + depth++;out=(char*)malloc(len+depth);*out='{'; ptr=out+1;*ptr++='\n';*ptr=0; while (child) { From e5fe65f58a62d8678b57e96c8e14a06d3ebcb20a Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 9 Sep 2009 18:56:31 +0000 Subject: [PATCH 06/58] ...try that again... better WINDOWS/WIN32/__WIN32__ (for Borland C) sentinelling also missed the casts on realloc() git-svn-id: http://svn.code.sf.net/p/cjson/code@6 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cJSON.c b/cJSON.c index 63348a2..909c6e5 100644 --- a/cJSON.c +++ b/cJSON.c @@ -30,7 +30,7 @@ #include #include "cJSON.h" -#ifdef WINDOWS +#if defined(WINDOWS) || defined(__WIN32__) || defined(WIN32) #define strcasecmp stricmp #endif @@ -263,7 +263,7 @@ static char *print_array(cJSON *item,int depth) ret=print_value(child,depth+1); if (!ret) {free(out);return 0;} // Check for failure! len+=strlen(ret)+3; - out=realloc(out,len); + out=(char*)realloc(out,len); ptr=out+strlen(out); ptr+=sprintf(ptr,ret); if (child->next) {*ptr++=',';*ptr++=' ';*ptr=0;} @@ -320,7 +320,7 @@ static char *print_object(cJSON *item,int depth) ret=print_value(child,depth); if (!ret) {free(out);return 0;} // Check for failure! len+=strlen(ret)+strlen(str)+4+depth; - out=realloc(out,len); + out=(char*)realloc(out,len); ptr=out+strlen(out); for (i=0;i Date: Wed, 28 Oct 2009 23:58:17 +0000 Subject: [PATCH 07/58] -lm may be necessary to compile. git-svn-id: http://svn.code.sf.net/p/cjson/code@7 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index bbffb82..7531c04 100644 --- a/README +++ b/README @@ -34,7 +34,7 @@ First up, how do I build? Add cJSON.c to your project, and put cJSON.h somewhere in the header search path. For example, to build the test app: -gcc cJSON.c test.c -o test +gcc cJSON.c test.c -o test -lm ./test @@ -244,4 +244,4 @@ which are more complex than I'd care to try and stash into a const char array[]. Enjoy cJSON! -- Dave Gamble, Aug 2009 \ No newline at end of file +- Dave Gamble, Aug 2009 From 75e170265989f038fb13687ee7c9426cc66ceefb Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 28 Oct 2009 23:59:05 +0000 Subject: [PATCH 08/58] fix bug: 2859459 (crash when printing JSON) handling of string length was incorrect. git-svn-id: http://svn.code.sf.net/p/cjson/code@8 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 909c6e5..4929fd3 100644 --- a/cJSON.c +++ b/cJSON.c @@ -311,7 +311,7 @@ static char *print_object(cJSON *item,int depth) char *out,*ptr,*ret,*str;int len=7,i; cJSON *child=item->child; - depth++;out=(char*)malloc(len+depth);*out='{'; + depth++;len+=depth;out=(char*)malloc(len);*out='{'; ptr=out+1;*ptr++='\n';*ptr=0; while (child) { From c052999a711a444598aaaa24b7a7f03bb86d1176 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Thu, 29 Oct 2009 00:06:15 +0000 Subject: [PATCH 09/58] fix bug: 2885206, whereby memory would leak in print_object if print_value failed. git-svn-id: http://svn.code.sf.net/p/cjson/code@9 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 4929fd3..ef7e6fe 100644 --- a/cJSON.c +++ b/cJSON.c @@ -318,7 +318,7 @@ static char *print_object(cJSON *item,int depth) str=print_string_ptr(child->string); if (!str) {free(out);return 0;} ret=print_value(child,depth); - if (!ret) {free(out);return 0;} // Check for failure! + if (!ret) {free(str);free(out);return 0;} // Check for failure! len+=strlen(ret)+strlen(str)+4+depth; out=(char*)realloc(out,len); ptr=out+strlen(out); From 7ca2c994a7e88104ff9744a03a62dea2c11954ab Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Thu, 29 Oct 2009 00:21:54 +0000 Subject: [PATCH 10/58] incorporate hooks feature from bug 2883206 also new errorhandling for memory failure cases. +I HAVE NOT CHECKED THIS FOR ABILITY TO LEAK!+ git-svn-id: http://svn.code.sf.net/p/cjson/code@10 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 101 ++++++++++++++++++++++++++++++++++++++++++-------------- cJSON.h | 10 ++++++ 2 files changed, 86 insertions(+), 25 deletions(-) diff --git a/cJSON.c b/cJSON.c index ef7e6fe..cbec753 100644 --- a/cJSON.c +++ b/cJSON.c @@ -30,12 +30,47 @@ #include #include "cJSON.h" -#if defined(WINDOWS) || defined(__WIN32__) || defined(WIN32) +#if defined(WINDOWS) || defined(__WIN32__) || defined(WIN32) || defined(_WIN32) #define strcasecmp stricmp +#define strdup _strdup #endif +static void *(*cJSON_malloc)(size_t sz) = malloc; +static void *(*cJSON_realloc)(void *ptr, size_t sz) = realloc; +static void (*cJSON_free)(void *ptr) = free; + +static char* cJSON_strdup(const char* str) +{ + size_t len; + char* copy; + + len = strlen(str) + 1; + if (!(copy = (char*)cJSON_malloc(len))) return 0; + memcpy(copy,str,len); + return copy; +} + +void cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (!hooks) { /* Reset hooks */ + cJSON_malloc = malloc; + cJSON_realloc = realloc; + cJSON_free = free; + return; + } + + cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; + cJSON_realloc= (hooks->realloc_fn)?hooks->realloc_fn:realloc; + cJSON_free = (hooks->free_fn)?hooks->free_fn:free; +} + // Internal constructor. -static cJSON *cJSON_New_Item() { return (cJSON*)calloc(sizeof(cJSON),1); } +static cJSON *cJSON_New_Item() +{ + cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); + if (node) memset(node,0,sizeof(cJSON)); + return node; +} // Delete a cJSON structure. void cJSON_Delete(cJSON *c) @@ -45,9 +80,9 @@ void cJSON_Delete(cJSON *c) { next=c->next; if (c->child) cJSON_Delete(c->child); - if (c->valuestring) free(c->valuestring); - if (c->string) free(c->string); - free(c); + if (c->valuestring) cJSON_free(c->valuestring); + if (c->string) cJSON_free(c->string); + cJSON_free(c); c=next; } } @@ -82,12 +117,12 @@ static char *print_number(cJSON *item) double d=item->valuedouble; if (fabs(((double)item->valueint)-d)<=DBL_EPSILON) { - str=(char*)malloc(21); // 2^64+1 can be represented in 21 chars. + str=(char*)cJSON_malloc(21); // 2^64+1 can be represented in 21 chars. sprintf(str,"%d",item->valueint); } else { - str=(char*)malloc(64); // This is a nice tradeoff. + str=(char*)cJSON_malloc(64); // This is a nice tradeoff. if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); else sprintf(str,"%f",d); } @@ -103,7 +138,8 @@ static const char *parse_string(cJSON *item,const char *str) while (*ptr!='\"' && *ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes. - out=(char*)malloc(len+1); // This is how long we need for the string, roughly. + out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly. + if (!out) return 0; ptr=str+1;ptr2=out; while (*ptr!='\"' && *ptr>31) @@ -149,7 +185,7 @@ static char *print_string_ptr(const char *str) ptr=str;while (*ptr && ++len) {if (*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} - out=(char*)malloc(len+3); + out=(char*)cJSON_malloc(len+3); ptr2=out;ptr=str; *ptr2++='\"'; while (*ptr) @@ -189,7 +225,15 @@ static char *print_object(cJSON *item,int depth); static const char *skip(const char *in) {while (in && *in<=32) in++; return in;} // Parse an object - create a new root, and populate. -cJSON *cJSON_Parse(const char *value) {cJSON *c=cJSON_New_Item();parse_value(c,skip(value));return c;} +cJSON *cJSON_Parse(const char *value) +{ + cJSON *c=cJSON_New_Item(); + if (!c) return 0; /* memory fail */ + + if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;} + return c; +} + // Render a cJSON item/entity/structure to text. char *cJSON_Print(cJSON *item) {return print_value(item,0);} @@ -214,9 +258,9 @@ static char *print_value(cJSON *item,int depth) char *out=0; switch (item->type) { - case cJSON_NULL: out=strdup("null"); break; - case cJSON_False: out=strdup("false");break; - case cJSON_True: out=strdup("true"); break; + case cJSON_NULL: out=cJSON_strdup("null"); break; + case cJSON_False: out=cJSON_strdup("false");break; + case cJSON_True: out=cJSON_strdup("true"); break; case cJSON_Number: out=print_number(item);break; case cJSON_String: out=print_string(item);break; case cJSON_Array: out=print_array(item,depth);break; @@ -236,14 +280,17 @@ static const char *parse_array(cJSON *item,const char *value) if (*value==']') return value+1; // empty array. item->child=child=cJSON_New_Item(); + if (!item->child) return 0; // memory fail value=skip(parse_value(child,skip(value))); // skip any spacing, get the value. + if (!value) return 0; while (*value==',') { cJSON *new_item; - if (!(new_item=cJSON_New_Item())) return 0; // memory fail + if (!(new_item=cJSON_New_Item())) return 0; // memory fail child->next=new_item;new_item->prev=child;child=new_item; value=skip(parse_value(child,skip(value+1))); + if (!value) return 0; // memory fail } if (*value==']') return value+1; // end of array @@ -256,19 +303,19 @@ static char *print_array(cJSON *item,int depth) char *out,*ptr,*ret;int len=5; cJSON *child=item->child; - out=(char*)malloc(len);*out='['; + out=(char*)cJSON_malloc(len);*out='['; ptr=out+1;*ptr=0; while (child) { ret=print_value(child,depth+1); - if (!ret) {free(out);return 0;} // Check for failure! + if (!ret) {cJSON_free(out);return 0;} // Check for failure! len+=strlen(ret)+3; - out=(char*)realloc(out,len); + out=(char*)cJSON_realloc(out,len); ptr=out+strlen(out); ptr+=sprintf(ptr,ret); if (child->next) {*ptr++=',';*ptr++=' ';*ptr=0;} child=child->next; - free(ret); + cJSON_free(ret); } *ptr++=']';*ptr++=0; return out; @@ -286,9 +333,11 @@ static const char *parse_object(cJSON *item,const char *value) item->child=child=cJSON_New_Item(); value=skip(parse_string(child,skip(value))); + if (!value) return 0; child->string=child->valuestring;child->valuestring=0; if (*value!=':') return 0; // fail! value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. + if (!value) return 0; while (*value==',') { @@ -296,9 +345,11 @@ static const char *parse_object(cJSON *item,const char *value) if (!(new_item=cJSON_New_Item())) return 0; // memory fail child->next=new_item;new_item->prev=child;child=new_item; value=skip(parse_string(child,skip(value+1))); + if (!value) return 0; child->string=child->valuestring;child->valuestring=0; if (*value!=':') return 0; // fail! value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. + if (!value) return 0; } if (*value=='}') return value+1; // end of array @@ -311,16 +362,16 @@ static char *print_object(cJSON *item,int depth) char *out,*ptr,*ret,*str;int len=7,i; cJSON *child=item->child; - depth++;len+=depth;out=(char*)malloc(len);*out='{'; + depth++;len+=depth;out=(char*)cJSON_malloc(len);*out='{'; ptr=out+1;*ptr++='\n';*ptr=0; while (child) { str=print_string_ptr(child->string); - if (!str) {free(out);return 0;} + if (!str) {cJSON_free(out);return 0;} ret=print_value(child,depth); - if (!ret) {free(str);free(out);return 0;} // Check for failure! + if (!ret) {cJSON_free(str);cJSON_free(out);return 0;} // Check for failure! len+=strlen(ret)+strlen(str)+4+depth; - out=(char*)realloc(out,len); + out=(char*)cJSON_realloc(out,len); ptr=out+strlen(out); for (i=0;inext) *ptr++=','; *ptr++='\n';*ptr=0; child=child->next; - free(str);free(ret); + cJSON_free(str);cJSON_free(ret); } for (i=0;inext=item;item->prev=p // Add item to array/object. void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} -void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) free(item->string);item->string=strdup(string);cJSON_AddItemToArray(object,item);} +void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} // Create basic types: cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;} cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();item->type=cJSON_True;return item;} cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();item->type=cJSON_False;return item;} cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;return item;} -cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();item->type=cJSON_String;item->valuestring=strdup(string);return item;} +cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();item->type=cJSON_String;item->valuestring=cJSON_strdup(string);return item;} cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();item->type=cJSON_Array;return item;} cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();item->type=cJSON_Object;return item;} diff --git a/cJSON.h b/cJSON.h index 9c137dd..376cecb 100644 --- a/cJSON.h +++ b/cJSON.h @@ -51,6 +51,16 @@ typedef struct cJSON { char *string; // The item's name string, if this item is the child of, or is in the list of subitems of an object. } cJSON; +typedef struct cJSON_Hooks { + void *(*malloc_fn)(size_t sz); + void *(*realloc_fn)(void *ptr, size_t sz); + void (*free_fn)(void *ptr); +} cJSON_Hooks; + +// Supply malloc, realloc and free functions to cJSON +extern void cJSON_InitHooks(cJSON_Hooks* hooks); + + // Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. extern cJSON *cJSON_Parse(const char *value); // Render a cJSON entity to text for transfer/storage. Free the char* when finished. From 37da1d2493d59122f7810650ce9d1c44215640b3 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Fri, 6 Nov 2009 15:41:44 +0000 Subject: [PATCH 11/58] Fix for printing values that contain % literals. Thanks to Jimmy Tam! git-svn-id: http://svn.code.sf.net/p/cjson/code@11 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cJSON.c b/cJSON.c index cbec753..b200467 100644 --- a/cJSON.c +++ b/cJSON.c @@ -312,7 +312,7 @@ static char *print_array(cJSON *item,int depth) len+=strlen(ret)+3; out=(char*)cJSON_realloc(out,len); ptr=out+strlen(out); - ptr+=sprintf(ptr,ret); + ptr+=sprintf(ptr,"%s",ret); if (child->next) {*ptr++=',';*ptr++=' ';*ptr=0;} child=child->next; cJSON_free(ret); @@ -374,9 +374,9 @@ static char *print_object(cJSON *item,int depth) out=(char*)cJSON_realloc(out,len); ptr=out+strlen(out); for (i=0;inext) *ptr++=','; *ptr++='\n';*ptr=0; child=child->next; From 5cca4e2c571793317b4094bc3a4066b61db99df1 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Tue, 10 Nov 2009 22:57:37 +0000 Subject: [PATCH 12/58] simplify the rendering code so there's no 'realloc' going on. That seemed horribly inefficient to me. Now we use multiple passes and can test for failure more carefully. git-svn-id: http://svn.code.sf.net/p/cjson/code@12 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 115 ++++++++++++++++++++++++++++++++++++++++---------------- cJSON.h | 1 - 2 files changed, 83 insertions(+), 33 deletions(-) diff --git a/cJSON.c b/cJSON.c index b200467..552cf46 100644 --- a/cJSON.c +++ b/cJSON.c @@ -36,7 +36,6 @@ #endif static void *(*cJSON_malloc)(size_t sz) = malloc; -static void *(*cJSON_realloc)(void *ptr, size_t sz) = realloc; static void (*cJSON_free)(void *ptr) = free; static char* cJSON_strdup(const char* str) @@ -54,13 +53,11 @@ void cJSON_InitHooks(cJSON_Hooks* hooks) { if (!hooks) { /* Reset hooks */ cJSON_malloc = malloc; - cJSON_realloc = realloc; cJSON_free = free; return; } cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; - cJSON_realloc= (hooks->realloc_fn)?hooks->realloc_fn:realloc; cJSON_free = (hooks->free_fn)?hooks->free_fn:free; } @@ -300,23 +297,50 @@ static const char *parse_array(cJSON *item,const char *value) // Render an array to text static char *print_array(cJSON *item,int depth) { - char *out,*ptr,*ret;int len=5; + char **entries; + char *out=0,*ptr,*ret;int len=5; cJSON *child=item->child; + int numentries=0,i=0,fail=0; - out=(char*)cJSON_malloc(len);*out='['; - ptr=out+1;*ptr=0; - while (child) + // How many entries in the array? + while (child) numentries++,child=child->next; + // Allocate an array to hold the values for each + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + memset(entries,0,numentries*sizeof(char*)); + // Retrieve all the results: + child=item->child; + while (child && !fail) { ret=print_value(child,depth+1); - if (!ret) {cJSON_free(out);return 0;} // Check for failure! - len+=strlen(ret)+3; - out=(char*)cJSON_realloc(out,len); - ptr=out+strlen(out); - ptr+=sprintf(ptr,"%s",ret); - if (child->next) {*ptr++=',';*ptr++=' ';*ptr=0;} + entries[i++]=ret; + if (ret) len+=strlen(ret)+3; else fail=1; child=child->next; - cJSON_free(ret); } + + // If we didn't fail, try to malloc the output string + if (!fail) out=cJSON_malloc(len); + // If that fails, we fail. + if (!out) fail=1; + + // Handle failure. + if (fail) + { + for (i=0;ichild; - - depth++;len+=depth;out=(char*)cJSON_malloc(len);*out='{'; - ptr=out+1;*ptr++='\n';*ptr=0; + int numentries=0,fail=0; + // Count the number of entries. + while (child) numentries++,child=child->next; + // Allocate space for the names and the objects + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + names=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!names) {cJSON_free(entries);return 0;} + memset(entries,0,sizeof(char*)*numentries); + memset(names,0,sizeof(char*)*numentries); + + // Collect all the results into our arrays: + child=item->child;depth++;len+=depth; while (child) { - str=print_string_ptr(child->string); - if (!str) {cJSON_free(out);return 0;} - ret=print_value(child,depth); - if (!ret) {cJSON_free(str);cJSON_free(out);return 0;} // Check for failure! - len+=strlen(ret)+strlen(str)+4+depth; - out=(char*)cJSON_realloc(out,len); - ptr=out+strlen(out); - for (i=0;inext) *ptr++=','; - *ptr++='\n';*ptr=0; + names[i]=str=print_string_ptr(child->string); + entries[i++]=ret=print_value(child,depth); + if (str && ret) len+=strlen(ret)+strlen(str)+4+depth; else fail=1; child=child->next; - cJSON_free(str);cJSON_free(ret); } + + // Try to allocate the output string + if (!fail) out=(char*)cJSON_malloc(len); + if (!out) fail=1; + + // Handle failure + if (fail) + { + for (i=0;i Date: Tue, 10 Nov 2009 23:32:11 +0000 Subject: [PATCH 13/58] prototype versions of ReplaceObject. Based on an idea from Daniel Harcek; these are designed to allow you to replace entries in an object or array with new values. The old values get deleted and the new ones are wired into place. This leads to a structure like this: cJSON_ReplaceItemInObject(myobject, "spooncount", cJSON_CreateNumber(24)); cJSON +NEVER+ type checks, so it's perfectly legal to replace an object with a string (to cJSON) though it may not be in your schema! git-svn-id: http://svn.code.sf.net/p/cjson/code@13 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 6 ++++++ cJSON.h | 10 +++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/cJSON.c b/cJSON.c index 552cf46..e6df5a7 100644 --- a/cJSON.c +++ b/cJSON.c @@ -450,6 +450,12 @@ static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=p void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} +// Replace array/object items with new ones. +void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; + newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; + if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;cJSON_Delete(c);} +void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && strcasecmp(c->string,string))i++,c=c->next;if(c)cJSON_ReplaceItemInArray(object,i,newitem);} + // Create basic types: cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;} cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();item->type=cJSON_True;return item;} diff --git a/cJSON.h b/cJSON.h index e760be2..4cf1e15 100644 --- a/cJSON.h +++ b/cJSON.h @@ -73,7 +73,7 @@ extern int cJSON_GetArraySize(cJSON *array); extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); // Get item "string" from object. Case insensitive. extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); - + // These calls create a cJSON item of the appropriate type. extern cJSON *cJSON_CreateNull(); extern cJSON *cJSON_CreateTrue(); @@ -90,8 +90,12 @@ extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); extern cJSON *cJSON_CreateStringArray(const char **strings,int count); // Append item to the specified array/object. -extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); -extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); +extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); + +// Update array items. +extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); +extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) From 991b57724766c7a19ff72b8a603af53c3bb93fdd Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Tue, 10 Nov 2009 23:50:43 +0000 Subject: [PATCH 14/58] fix the ReplaceObject functions; tighten them up, add some more checks for stability. git-svn-id: http://svn.code.sf.net/p/cjson/code@14 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cJSON.c b/cJSON.c index e6df5a7..28a50ba 100644 --- a/cJSON.c +++ b/cJSON.c @@ -180,6 +180,7 @@ static char *print_string_ptr(const char *str) { const char *ptr;char *ptr2,*out;int len=0; + if (!str) return cJSON_strdup(""); ptr=str;while (*ptr && ++len) {if (*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} out=(char*)cJSON_malloc(len+3); @@ -440,7 +441,7 @@ static char *print_object(cJSON *item,int depth) // Get Array size/item / object item. int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;} -cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item) item--,c=c->next; return c;} +cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && strcasecmp(c->string,string)) c=c->next; return c;} // Utility for array list handling. @@ -453,8 +454,8 @@ void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if ( // Replace array/object items with new ones. void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; - if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;cJSON_Delete(c);} -void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && strcasecmp(c->string,string))i++,c=c->next;if(c)cJSON_ReplaceItemInArray(object,i,newitem);} + if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} +void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} // Create basic types: cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;} From 6b51f927e9c7fe8216bb3f2439e5bf9c5de206e1 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Tue, 10 Nov 2009 23:51:15 +0000 Subject: [PATCH 15/58] two bizarre tweaks to demonstrate the replace functionality. git-svn-id: http://svn.code.sf.net/p/cjson/code@15 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test.c b/test.c index a9f6697..ccb82b1 100644 --- a/test.c +++ b/test.c @@ -78,6 +78,8 @@ void create_objects() root=cJSON_CreateArray(); for (i=0;i<3;i++) cJSON_AddItemToArray(root,cJSON_CreateIntArray(numbers[i],3)); + cJSON_ReplaceItemInArray(root,1,cJSON_CreateString("Replacement")); + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); @@ -115,6 +117,8 @@ void create_objects() cJSON_AddStringToObject(fld, "Country", fields[i].country); } + cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root,1),"City",cJSON_CreateIntArray(ids,4)); + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); } From 69dca155a94c92334e3371c569b20ddb23be7a94 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 11 Nov 2009 00:14:51 +0000 Subject: [PATCH 16/58] comment these out for clarity... git-svn-id: http://svn.code.sf.net/p/cjson/code@16 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.c b/test.c index ccb82b1..4c6d3dd 100644 --- a/test.c +++ b/test.c @@ -78,7 +78,7 @@ void create_objects() root=cJSON_CreateArray(); for (i=0;i<3;i++) cJSON_AddItemToArray(root,cJSON_CreateIntArray(numbers[i],3)); - cJSON_ReplaceItemInArray(root,1,cJSON_CreateString("Replacement")); +// cJSON_ReplaceItemInArray(root,1,cJSON_CreateString("Replacement")); out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); @@ -117,7 +117,7 @@ void create_objects() cJSON_AddStringToObject(fld, "Country", fields[i].country); } - cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root,1),"City",cJSON_CreateIntArray(ids,4)); +// cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root,1),"City",cJSON_CreateIntArray(ids,4)); out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); From 0dbe29ffe8a772c5b5990ce7da00ccddd596f3d4 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 11 Nov 2009 00:15:53 +0000 Subject: [PATCH 17/58] fix bug 2895595 from jshvrsn whereby values outside of INT_MIN/INT_MAX range are printed incorrectly as ints. git-svn-id: http://svn.code.sf.net/p/cjson/code@17 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 28a50ba..2ba22fd 100644 --- a/cJSON.c +++ b/cJSON.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "cJSON.h" #if defined(WINDOWS) || defined(__WIN32__) || defined(WIN32) || defined(_WIN32) @@ -112,7 +113,7 @@ static char *print_number(cJSON *item) { char *str; double d=item->valuedouble; - if (fabs(((double)item->valueint)-d)<=DBL_EPSILON) + if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) { str=(char*)cJSON_malloc(21); // 2^64+1 can be represented in 21 chars. sprintf(str,"%d",item->valueint); From 501ff3b3d0e977b964e8c0ae43c519daebdee707 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 25 Nov 2009 15:18:19 +0000 Subject: [PATCH 18/58] if it's a big number, but still an integer, print it exactly! git-svn-id: http://svn.code.sf.net/p/cjson/code@18 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index 2ba22fd..a429ee7 100644 --- a/cJSON.c +++ b/cJSON.c @@ -121,8 +121,9 @@ static char *print_number(cJSON *item) else { str=(char*)cJSON_malloc(64); // This is a nice tradeoff. - if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); - else sprintf(str,"%f",d); + if (fabs(floor(d)-d)<=DBL_EPSILON) sprintf(str,"%.0f",d); + else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); + else sprintf(str,"%f",d); } return str; } From c4e8954eb27c96190e2ffe8535b79a5e80e6dd68 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 25 Nov 2009 15:27:39 +0000 Subject: [PATCH 19/58] Feature request: 2903779. Unformatted output. :) git-svn-id: http://svn.code.sf.net/p/cjson/code@19 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 41 +++++++++++++++++++++-------------------- cJSON.h | 2 ++ 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/cJSON.c b/cJSON.c index a429ee7..e8eb608 100644 --- a/cJSON.c +++ b/cJSON.c @@ -215,11 +215,11 @@ static char *print_string(cJSON *item) {return print_string_ptr(item->valuestrin // Predeclare these prototypes. static const char *parse_value(cJSON *item,const char *value); -static char *print_value(cJSON *item,int depth); +static char *print_value(cJSON *item,int depth,int fmt); static const char *parse_array(cJSON *item,const char *value); -static char *print_array(cJSON *item,int depth); +static char *print_array(cJSON *item,int depth,int fmt); static const char *parse_object(cJSON *item,const char *value); -static char *print_object(cJSON *item,int depth); +static char *print_object(cJSON *item,int depth,int fmt); // Utility to jump whitespace and cr/lf static const char *skip(const char *in) {while (in && *in<=32) in++; return in;} @@ -235,7 +235,8 @@ cJSON *cJSON_Parse(const char *value) } // Render a cJSON item/entity/structure to text. -char *cJSON_Print(cJSON *item) {return print_value(item,0);} +char *cJSON_Print(cJSON *item) {return print_value(item,0,1);} +char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} // Parser core - when encountering text, process appropriately. static const char *parse_value(cJSON *item,const char *value) @@ -253,7 +254,7 @@ static const char *parse_value(cJSON *item,const char *value) } // Render a value to text. -static char *print_value(cJSON *item,int depth) +static char *print_value(cJSON *item,int depth,int fmt) { char *out=0; switch (item->type) @@ -263,8 +264,8 @@ static char *print_value(cJSON *item,int depth) case cJSON_True: out=cJSON_strdup("true"); break; case cJSON_Number: out=print_number(item);break; case cJSON_String: out=print_string(item);break; - case cJSON_Array: out=print_array(item,depth);break; - case cJSON_Object: out=print_object(item,depth);break; + case cJSON_Array: out=print_array(item,depth,fmt);break; + case cJSON_Object: out=print_object(item,depth,fmt);break; } return out; } @@ -298,7 +299,7 @@ static const char *parse_array(cJSON *item,const char *value) } // Render an array to text -static char *print_array(cJSON *item,int depth) +static char *print_array(cJSON *item,int depth,int fmt) { char **entries; char *out=0,*ptr,*ret;int len=5; @@ -315,9 +316,9 @@ static char *print_array(cJSON *item,int depth) child=item->child; while (child && !fail) { - ret=print_value(child,depth+1); + ret=print_value(child,depth+1,fmt); entries[i++]=ret; - if (ret) len+=strlen(ret)+3; else fail=1; + if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; child=child->next; } @@ -340,7 +341,7 @@ static char *print_array(cJSON *item,int depth) for (i=0;ichild;depth++;len+=depth; + child=item->child;depth++;if (fmt) len+=depth; while (child) { names[i]=str=print_string_ptr(child->string); - entries[i++]=ret=print_value(child,depth); - if (str && ret) len+=strlen(ret)+strlen(str)+4+depth; else fail=1; + entries[i++]=ret=print_value(child,depth,fmt); + if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; child=child->next; } @@ -423,20 +424,20 @@ static char *print_object(cJSON *item,int depth) } // Compose the output: - *out='{';ptr=out+1;*ptr++='\n';*ptr=0; + *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0; for (i=0;i Date: Wed, 25 Nov 2009 16:52:07 +0000 Subject: [PATCH 20/58] Feature Request: 2903802. If you need to add an existing cJSON to a new object, but the existing object must not be affected by this, use cJSON_AddItemReferenceTo. This will make a "reference" to the existing object (which is what you really mean to do), and allow you to use it with a new object without fear of names being corrupted or things being deleted. Think of it like a reference, since that's pretty much what it is. If you modify the resulting object (i.e. you AddItemReference, then retrieve with GetObjectItem, and then start adding/replacing) you'll modify the object you pass in (in other words, this doesn't clone everything, since that would probably end up being wasteful of space), however, if you add it, and treat it as if it were const, everything will be fine! git-svn-id: http://svn.code.sf.net/p/cjson/code@20 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 11 ++++++++--- cJSON.h | 8 +++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index e8eb608..72e8a1c 100644 --- a/cJSON.c +++ b/cJSON.c @@ -77,8 +77,8 @@ void cJSON_Delete(cJSON *c) while (c) { next=c->next; - if (c->child) cJSON_Delete(c->child); - if (c->valuestring) cJSON_free(c->valuestring); + if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); + if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); if (c->string) cJSON_free(c->string); cJSON_free(c); c=next; @@ -257,7 +257,7 @@ static const char *parse_value(cJSON *item,const char *value) static char *print_value(cJSON *item,int depth,int fmt) { char *out=0; - switch (item->type) + switch ((item->type)&255) { case cJSON_NULL: out=cJSON_strdup("null"); break; case cJSON_False: out=cJSON_strdup("false");break; @@ -449,10 +449,15 @@ cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->c // Utility for array list handling. static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} +// Utility for handling references. +static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} // Add item to array/object. void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} +void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} +void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} + // Replace array/object items with new ones. void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; diff --git a/cJSON.h b/cJSON.h index b0cb977..fbfb35f 100644 --- a/cJSON.h +++ b/cJSON.h @@ -36,6 +36,8 @@ extern "C" #define cJSON_String 4 #define cJSON_Array 5 #define cJSON_Object 6 + +#define cJSON_IsReference 256 // The cJSON structure: typedef struct cJSON { @@ -94,7 +96,11 @@ extern cJSON *cJSON_CreateStringArray(const char **strings,int count); // Append item to the specified array/object. extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); - +// Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. +extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); + + // Update array items. extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); From 79a796aed2c246abb7f39305fe19b75b9c33f3bc Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 25 Nov 2009 17:04:05 +0000 Subject: [PATCH 21/58] Detatch and Remove objects from Arrays/Objects. git-svn-id: http://svn.code.sf.net/p/cjson/code@21 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 5 +++++ cJSON.h | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 72e8a1c..409c1f1 100644 --- a/cJSON.c +++ b/cJSON.c @@ -458,6 +458,11 @@ void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if ( void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} +cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; + if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;return c;} +void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} +cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} +void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} // Replace array/object items with new ones. void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; diff --git a/cJSON.h b/cJSON.h index fbfb35f..3c28657 100644 --- a/cJSON.h +++ b/cJSON.h @@ -99,7 +99,12 @@ extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); // Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); - + +// Remove/Detatch items from Arrays/Objects. +extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); +extern void cJSON_DeleteItemFromArray(cJSON *array,int which); +extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); +extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); // Update array items. extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); From 341bb3c640d314669f4f5313d9d92bc1520e5a29 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 25 Nov 2009 17:06:26 +0000 Subject: [PATCH 22/58] oops! remember to kill dead pointers on Detach!! git-svn-id: http://svn.code.sf.net/p/cjson/code@22 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 409c1f1..c206a14 100644 --- a/cJSON.c +++ b/cJSON.c @@ -459,7 +459,7 @@ void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddIte void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; - if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;return c;} + 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;} void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} From 091c0676c1db6c6307988f81558bf69e39c01044 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 25 Nov 2009 19:33:40 +0000 Subject: [PATCH 23/58] return 0! git-svn-id: http://svn.code.sf.net/p/cjson/code@23 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index c206a14..56cc85b 100644 --- a/cJSON.c +++ b/cJSON.c @@ -458,7 +458,7 @@ void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if ( void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} -cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; +cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; 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;} void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} From 37963a72b9d84aee437bed2913fe85bfb1624600 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Thu, 26 Nov 2009 20:17:25 +0000 Subject: [PATCH 24/58] Don't crash if someone calls cJSON_Print(0); git-svn-id: http://svn.code.sf.net/p/cjson/code@24 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cJSON.c b/cJSON.c index 56cc85b..62d7bf2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -256,6 +256,7 @@ static const char *parse_value(cJSON *item,const char *value) // Render a value to text. static char *print_value(cJSON *item,int depth,int fmt) { + if (!item) return 0; char *out=0; switch ((item->type)&255) { From efe33fabbb849bc4337d9d96f09d230945f4b794 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 9 Dec 2009 12:31:32 +0000 Subject: [PATCH 25/58] ID: 2907153 declare variable first, so we're proper c ;) git-svn-id: http://svn.code.sf.net/p/cjson/code@25 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 62d7bf2..45be994 100644 --- a/cJSON.c +++ b/cJSON.c @@ -256,8 +256,8 @@ static const char *parse_value(cJSON *item,const char *value) // Render a value to text. static char *print_value(cJSON *item,int depth,int fmt) { - if (!item) return 0; char *out=0; + if (!item) return 0; switch ((item->type)&255) { case cJSON_NULL: out=cJSON_strdup("null"); break; From 6420cfe7c4d644961830128711848d28dacd33c6 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 9 Dec 2009 15:43:38 +0000 Subject: [PATCH 26/58] solve the stricmp/strcasecmp in a dumb way for good. I might make cJSON_strcasecmp hookable, depending on what feedback i get. There are now +NO+ #ifdef/#endif WINDOWS clauses, just neat ANSI C. Also, this DOES NOT represent an efficiency hit for parsing, since the casecmp code is ONLY used for retrieval of object values, which would be after the parse stage. git-svn-id: http://svn.code.sf.net/p/cjson/code@26 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cJSON.c b/cJSON.c index 45be994..1b7c085 100644 --- a/cJSON.c +++ b/cJSON.c @@ -31,10 +31,11 @@ #include #include "cJSON.h" -#if defined(WINDOWS) || defined(__WIN32__) || defined(WIN32) || defined(_WIN32) -#define strcasecmp stricmp -#define strdup _strdup -#endif +static int cJSON_strcasecmp(const char *s1,const char *s2) +{ + for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; + return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); +} static void *(*cJSON_malloc)(size_t sz) = malloc; static void (*cJSON_free)(void *ptr) = free; @@ -446,7 +447,7 @@ static char *print_object(cJSON *item,int depth,int fmt) // Get Array size/item / object item. int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;} cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} -cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && strcasecmp(c->string,string)) c=c->next; return c;} +cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} // Utility for array list handling. static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} @@ -462,14 +463,14 @@ void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; 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;} void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} -cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} +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;} void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} // Replace array/object items with new ones. void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} -void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} +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);}} // Create basic types: cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;} From ee4ce32ea8e09222cefadca7d2d37f6001f4a6b0 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Fri, 1 Jan 2010 23:13:31 +0000 Subject: [PATCH 27/58] make strcasecmp STABLE if passed a null string git-svn-id: http://svn.code.sf.net/p/cjson/code@27 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cJSON.c b/cJSON.c index 1b7c085..82eccbb 100644 --- a/cJSON.c +++ b/cJSON.c @@ -33,6 +33,7 @@ static int cJSON_strcasecmp(const char *s1,const char *s2) { + if (!s1) return (s1==s2)?0:1;if (!s2) return 1; for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); } From d9840479f52e4e99561d32a107d0ca1c8763cef4 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Thu, 7 Jan 2010 23:07:58 +0000 Subject: [PATCH 28/58] Include ctype.h for tolower() git-svn-id: http://svn.code.sf.net/p/cjson/code@28 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cJSON.c b/cJSON.c index 82eccbb..5bde16c 100644 --- a/cJSON.c +++ b/cJSON.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "cJSON.h" static int cJSON_strcasecmp(const char *s1,const char *s2) From 7dd9280267e4c8eec43d4ccd05004a9cc79fa859 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Sat, 23 Jan 2010 12:44:58 +0000 Subject: [PATCH 29/58] Fix handling of non-ascii characters! Many thanks to an anonymous submitter for this fix!! git-svn-id: http://svn.code.sf.net/p/cjson/code@29 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cJSON.c b/cJSON.c index 5bde16c..67c6c71 100644 --- a/cJSON.c +++ b/cJSON.c @@ -138,13 +138,13 @@ static const char *parse_string(cJSON *item,const char *str) const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; if (*str!='\"') return 0; // not a string! - while (*ptr!='\"' && *ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes. + while (*ptr!='\"' && (unsigned char)*ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes. out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly. if (!out) return 0; ptr=str+1;ptr2=out; - while (*ptr!='\"' && *ptr>31) + while (*ptr!='\"' && (unsigned char)*ptr>31) { if (*ptr!='\\') *ptr2++=*ptr++; else @@ -186,14 +186,14 @@ static char *print_string_ptr(const char *str) const char *ptr;char *ptr2,*out;int len=0; if (!str) return cJSON_strdup(""); - ptr=str;while (*ptr && ++len) {if (*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} + ptr=str;while (*ptr && ++len) {if ((unsigned char)*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} out=(char*)cJSON_malloc(len+3); ptr2=out;ptr=str; *ptr2++='\"'; while (*ptr) { - if (*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; + if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; else { *ptr2++='\\'; @@ -225,7 +225,7 @@ static const char *parse_object(cJSON *item,const char *value); static char *print_object(cJSON *item,int depth,int fmt); // Utility to jump whitespace and cr/lf -static const char *skip(const char *in) {while (in && *in<=32) in++; return in;} +static const char *skip(const char *in) {while (in && (unsigned char)*in<=32) in++; return in;} // Parse an object - create a new root, and populate. cJSON *cJSON_Parse(const char *value) From 3fb3989bb18df4538e1f38489743ae082157fdbd Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 27 Jan 2010 13:01:15 +0000 Subject: [PATCH 30/58] All memory allocations are now checked, and should fail gracefully in a low memory environment. git-svn-id: http://svn.code.sf.net/p/cjson/code@30 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/cJSON.c b/cJSON.c index 67c6c71..989f2a5 100644 --- a/cJSON.c +++ b/cJSON.c @@ -119,14 +119,17 @@ static char *print_number(cJSON *item) if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) { str=(char*)cJSON_malloc(21); // 2^64+1 can be represented in 21 chars. - sprintf(str,"%d",item->valueint); + if (str) sprintf(str,"%d",item->valueint); } else { str=(char*)cJSON_malloc(64); // This is a nice tradeoff. - if (fabs(floor(d)-d)<=DBL_EPSILON) sprintf(str,"%.0f",d); - else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); - else sprintf(str,"%f",d); + if (str) + { + if (fabs(floor(d)-d)<=DBL_EPSILON) sprintf(str,"%.0f",d); + else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); + else sprintf(str,"%f",d); + } } return str; } @@ -189,6 +192,8 @@ static char *print_string_ptr(const char *str) ptr=str;while (*ptr && ++len) {if ((unsigned char)*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} out=(char*)cJSON_malloc(len+3); + if (!out) return 0; + ptr2=out;ptr=str; *ptr2++='\"'; while (*ptr) @@ -364,6 +369,7 @@ static const char *parse_object(cJSON *item,const char *value) if (*value=='}') return value+1; // empty array. item->child=child=cJSON_New_Item(); + if (!item->child) return 0; value=skip(parse_string(child,skip(value))); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; @@ -454,11 +460,11 @@ cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->c // Utility for array list handling. static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} // Utility for handling references. -static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} +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;} // Add item to array/object. -void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} -void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} +void cJSON_AddItemToArray(cJSON *array, cJSON *item) {if (!item) return; cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} +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);} void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} @@ -475,16 +481,16 @@ void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON * 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);}} // Create basic types: -cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;} -cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();item->type=cJSON_True;return item;} -cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();item->type=cJSON_False;return item;} -cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;return item;} -cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();item->type=cJSON_String;item->valuestring=cJSON_strdup(string);return item;} -cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();item->type=cJSON_Array;return item;} -cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();item->type=cJSON_Object;return item;} +cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} +cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} +cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} +cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} +cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} +cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} +cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} // Create Arrays: -cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} From 6711153d412293db4334b8f083d5cb036e68ac12 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Fri, 12 Feb 2010 16:24:54 +0000 Subject: [PATCH 31/58] CreateBool, because it's useful ;) git-svn-id: http://svn.code.sf.net/p/cjson/code@31 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 1 + cJSON.h | 1 + 2 files changed, 2 insertions(+) diff --git a/cJSON.c b/cJSON.c index 989f2a5..1c1b472 100644 --- a/cJSON.c +++ b/cJSON.c @@ -484,6 +484,7 @@ void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} +cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} diff --git a/cJSON.h b/cJSON.h index 3c28657..a7b52c6 100644 --- a/cJSON.h +++ b/cJSON.h @@ -82,6 +82,7 @@ extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); extern cJSON *cJSON_CreateNull(); extern cJSON *cJSON_CreateTrue(); extern cJSON *cJSON_CreateFalse(); +extern cJSON *cJSON_CreateBool(int b); extern cJSON *cJSON_CreateNumber(double num); extern cJSON *cJSON_CreateString(const char *string); extern cJSON *cJSON_CreateArray(); From 149d01354304527bcf9857b433b4a8c08e4668ad Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Sat, 13 Feb 2010 22:32:15 +0000 Subject: [PATCH 32/58] Wrong order for variable declaration. git-svn-id: http://svn.code.sf.net/p/cjson/code@32 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 1c1b472..9c4ca28 100644 --- a/cJSON.c +++ b/cJSON.c @@ -463,7 +463,7 @@ static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=p 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;} // Add item to array/object. -void cJSON_AddItemToArray(cJSON *array, cJSON *item) {if (!item) return; cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} +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);}} 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);} void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} From de7afcc45812e41078d5ecdd3b76ef68446d4783 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Thu, 18 Feb 2010 10:40:37 +0000 Subject: [PATCH 33/58] change firstByteMark to unsigned to prevent constant overflow warning git-svn-id: http://svn.code.sf.net/p/cjson/code@33 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 9c4ca28..1307005 100644 --- a/cJSON.c +++ b/cJSON.c @@ -135,7 +135,7 @@ static char *print_number(cJSON *item) } // Parse the input text into an unescaped cstring, and populate item. -static const char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; +static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; static const char *parse_string(cJSON *item,const char *str) { const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; From 02d86ef778fc9bf1da5798dd7c9963aecbd03acb Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 2 Mar 2011 19:09:43 +0000 Subject: [PATCH 34/58] Update to permit compilation with gcc -ansi flag (changed all C++ // comments to C /* */ comments). git-svn-id: http://svn.code.sf.net/p/cjson/code@34 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 150 ++++++++++++++++++++++++++++---------------------------- cJSON.h | 46 ++++++++--------- test.c | 50 +++++++++---------- 3 files changed, 123 insertions(+), 123 deletions(-) diff --git a/cJSON.c b/cJSON.c index 1307005..0f6d5e9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -20,8 +20,8 @@ THE SOFTWARE. */ -// cJSON -// JSON parser in C. +/* cJSON */ +/* JSON parser in C. */ #include #include @@ -65,7 +65,7 @@ void cJSON_InitHooks(cJSON_Hooks* hooks) cJSON_free = (hooks->free_fn)?hooks->free_fn:free; } -// Internal constructor. +/* Internal constructor. */ static cJSON *cJSON_New_Item() { cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); @@ -73,7 +73,7 @@ static cJSON *cJSON_New_Item() return node; } -// Delete a cJSON structure. +/* Delete a cJSON structure. */ void cJSON_Delete(cJSON *c) { cJSON *next; @@ -88,22 +88,22 @@ void cJSON_Delete(cJSON *c) } } -// Parse the input text to generate a number, and populate the result into item. +/* Parse the input text to generate a number, and populate the result into item. */ static const char *parse_number(cJSON *item,const char *num) { double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; - // Could use sscanf for this? - if (*num=='-') sign=-1,num++; // Has sign? - if (*num=='0') num++; // is zero - if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); // Number? - if (*num=='.') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} // Fractional part? - if (*num=='e' || *num=='E') // Exponent? - { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; // With sign? - while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); // Number? + /* Could use sscanf for this? */ + if (*num=='-') sign=-1,num++; /* Has sign? */ + if (*num=='0') num++; /* is zero */ + if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ + if (*num=='.') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ + if (*num=='e' || *num=='E') /* Exponent? */ + { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ + while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ } - n=sign*n*pow(10.0,(scale+subscale*signsubscale)); // number = +/- number.fraction * 10^+/- exponent + n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ item->valuedouble=n; item->valueint=(int)n; @@ -111,19 +111,19 @@ static const char *parse_number(cJSON *item,const char *num) return num; } -// Render the number nicely from the given item into a string. +/* Render the number nicely from the given item into a string. */ static char *print_number(cJSON *item) { char *str; double d=item->valuedouble; if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) { - str=(char*)cJSON_malloc(21); // 2^64+1 can be represented in 21 chars. + str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ if (str) sprintf(str,"%d",item->valueint); } else { - str=(char*)cJSON_malloc(64); // This is a nice tradeoff. + str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ if (str) { if (fabs(floor(d)-d)<=DBL_EPSILON) sprintf(str,"%.0f",d); @@ -134,16 +134,16 @@ static char *print_number(cJSON *item) return str; } -// Parse the input text into an unescaped cstring, and populate item. +/* Parse the input text into an unescaped cstring, and populate item. */ static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; static const char *parse_string(cJSON *item,const char *str) { const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; - if (*str!='\"') return 0; // not a string! + if (*str!='\"') return 0; /* not a string! */ - while (*ptr!='\"' && (unsigned char)*ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes. + while (*ptr!='\"' && (unsigned char)*ptr>31 && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ - out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly. + out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ if (!out) return 0; ptr=str+1;ptr2=out; @@ -160,8 +160,8 @@ static const char *parse_string(cJSON *item,const char *str) case 'n': *ptr2++='\n'; break; case 'r': *ptr2++='\r'; break; case 't': *ptr2++='\t'; break; - case 'u': // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY. - sscanf(ptr+1,"%4x",&uc); // get the unicode char. + case 'u': /* transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY. */ + sscanf(ptr+1,"%4x",&uc); /* get the unicode char. */ len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len; switch (len) { @@ -183,7 +183,7 @@ static const char *parse_string(cJSON *item,const char *str) return ptr; } -// Render the cstring provided to an escaped version that can be printed. +/* Render the cstring provided to an escaped version that can be printed. */ static char *print_string_ptr(const char *str) { const char *ptr;char *ptr2,*out;int len=0; @@ -211,17 +211,17 @@ static char *print_string_ptr(const char *str) case '\n': *ptr2++='n'; break; case '\r': *ptr2++='r'; break; case '\t': *ptr2++='t'; break; - default: ptr2--; break; // eviscerate with prejudice. + default: ptr2--; break; /* eviscerate with prejudice. */ } } } *ptr2++='\"';*ptr2++=0; return out; } -// Invote print_string_ptr (which is useful) on an item. +/* Invote print_string_ptr (which is useful) on an item. */ static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} -// Predeclare these prototypes. +/* Predeclare these prototypes. */ static const char *parse_value(cJSON *item,const char *value); static char *print_value(cJSON *item,int depth,int fmt); static const char *parse_array(cJSON *item,const char *value); @@ -229,10 +229,10 @@ static char *print_array(cJSON *item,int depth,int fmt); static const char *parse_object(cJSON *item,const char *value); static char *print_object(cJSON *item,int depth,int fmt); -// Utility to jump whitespace and cr/lf +/* Utility to jump whitespace and cr/lf */ static const char *skip(const char *in) {while (in && (unsigned char)*in<=32) in++; return in;} -// Parse an object - create a new root, and populate. +/* Parse an object - create a new root, and populate. */ cJSON *cJSON_Parse(const char *value) { cJSON *c=cJSON_New_Item(); @@ -242,14 +242,14 @@ cJSON *cJSON_Parse(const char *value) return c; } -// Render a cJSON item/entity/structure to text. +/* Render a cJSON item/entity/structure to text. */ char *cJSON_Print(cJSON *item) {return print_value(item,0,1);} char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} -// Parser core - when encountering text, process appropriately. +/* Parser core - when encountering text, process appropriately. */ static const char *parse_value(cJSON *item,const char *value) { - if (!value) return 0; // Fail on null. + if (!value) return 0; /* Fail on null. */ if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } @@ -258,10 +258,10 @@ static const char *parse_value(cJSON *item,const char *value) if (*value=='[') { return parse_array(item,value); } if (*value=='{') { return parse_object(item,value); } - return 0; // failure. + return 0; /* failure. */ } -// Render a value to text. +/* Render a value to text. */ static char *print_value(cJSON *item,int depth,int fmt) { char *out=0; @@ -279,35 +279,35 @@ static char *print_value(cJSON *item,int depth,int fmt) return out; } -// Build an array from input text. +/* Build an array from input text. */ static const char *parse_array(cJSON *item,const char *value) { cJSON *child; - if (*value!='[') return 0; // not an array! + if (*value!='[') return 0; /* not an array! */ item->type=cJSON_Array; value=skip(value+1); - if (*value==']') return value+1; // empty array. + if (*value==']') return value+1; /* empty array. */ item->child=child=cJSON_New_Item(); - if (!item->child) return 0; // memory fail - value=skip(parse_value(child,skip(value))); // skip any spacing, get the value. + if (!item->child) return 0; /* memory fail */ + value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ if (!value) return 0; while (*value==',') { cJSON *new_item; - if (!(new_item=cJSON_New_Item())) return 0; // memory fail + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ child->next=new_item;new_item->prev=child;child=new_item; value=skip(parse_value(child,skip(value+1))); - if (!value) return 0; // memory fail + if (!value) return 0; /* memory fail */ } - if (*value==']') return value+1; // end of array - return 0; // malformed. + if (*value==']') return value+1; /* end of array */ + return 0; /* malformed. */ } -// Render an array to text +/* Render an array to text */ static char *print_array(cJSON *item,int depth,int fmt) { char **entries; @@ -315,13 +315,13 @@ static char *print_array(cJSON *item,int depth,int fmt) cJSON *child=item->child; int numentries=0,i=0,fail=0; - // How many entries in the array? + /* How many entries in the array? */ while (child) numentries++,child=child->next; - // Allocate an array to hold the values for each + /* Allocate an array to hold the values for each */ entries=(char**)cJSON_malloc(numentries*sizeof(char*)); if (!entries) return 0; memset(entries,0,numentries*sizeof(char*)); - // Retrieve all the results: + /* Retrieve all the results: */ child=item->child; while (child && !fail) { @@ -331,12 +331,12 @@ static char *print_array(cJSON *item,int depth,int fmt) child=child->next; } - // If we didn't fail, try to malloc the output string + /* If we didn't fail, try to malloc the output string */ if (!fail) out=cJSON_malloc(len); - // If that fails, we fail. + /* If that fails, we fail. */ if (!out) fail=1; - // Handle failure. + /* Handle failure. */ if (fail) { for (i=0;itype=cJSON_Object; value=skip(value+1); - if (*value=='}') return value+1; // empty array. + if (*value=='}') return value+1; /* empty array. */ item->child=child=cJSON_New_Item(); if (!item->child) return 0; value=skip(parse_string(child,skip(value))); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; - if (*value!=':') return 0; // fail! - value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. + if (*value!=':') return 0; /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ if (!value) return 0; while (*value==',') { cJSON *new_item; - if (!(new_item=cJSON_New_Item())) return 0; // memory fail + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ child->next=new_item;new_item->prev=child;child=new_item; value=skip(parse_string(child,skip(value+1))); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; - if (*value!=':') return 0; // fail! - value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. + if (*value!=':') return 0; /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ if (!value) return 0; } - if (*value=='}') return value+1; // end of array - return 0; // malformed. + if (*value=='}') return value+1; /* end of array */ + return 0; /* malformed. */ } -// Render an object to text. +/* Render an object to text. */ static char *print_object(cJSON *item,int depth,int fmt) { char **entries=0,**names=0; char *out=0,*ptr,*ret,*str;int len=7,i=0,j; cJSON *child=item->child; int numentries=0,fail=0; - // Count the number of entries. + /* Count the number of entries. */ while (child) numentries++,child=child->next; - // Allocate space for the names and the objects + /* Allocate space for the names and the objects */ entries=(char**)cJSON_malloc(numentries*sizeof(char*)); if (!entries) return 0; names=(char**)cJSON_malloc(numentries*sizeof(char*)); @@ -411,7 +411,7 @@ static char *print_object(cJSON *item,int depth,int fmt) memset(entries,0,sizeof(char*)*numentries); memset(names,0,sizeof(char*)*numentries); - // Collect all the results into our arrays: + /* Collect all the results into our arrays: */ child=item->child;depth++;if (fmt) len+=depth; while (child) { @@ -421,11 +421,11 @@ static char *print_object(cJSON *item,int depth,int fmt) child=child->next; } - // Try to allocate the output string + /* Try to allocate the output string */ if (!fail) out=(char*)cJSON_malloc(len); if (!out) fail=1; - // Handle failure + /* Handle failure */ if (fail) { for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} -// Utility for array list handling. +/* Utility for array list handling. */ static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} -// Utility for handling references. +/* Utility for handling references. */ 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;} -// Add item to array/object. +/* Add item to array/object. */ 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);}} 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);} void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} @@ -474,13 +474,13 @@ void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_D 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;} void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} -// Replace array/object items with new ones. +/* Replace array/object items with new ones. */ void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} 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);}} -// Create basic types: +/* Create basic types: */ cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} @@ -490,7 +490,7 @@ cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(i cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} -// Create Arrays: +/* Create Arrays: */ cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} diff --git a/cJSON.h b/cJSON.h index a7b52c6..2da0f44 100644 --- a/cJSON.h +++ b/cJSON.h @@ -28,7 +28,7 @@ extern "C" { #endif -// cJSON Types: +/* cJSON Types: */ #define cJSON_False 0 #define cJSON_True 1 #define cJSON_NULL 2 @@ -39,18 +39,18 @@ extern "C" #define cJSON_IsReference 256 -// The cJSON structure: +/* The cJSON structure: */ typedef struct cJSON { - struct cJSON *next,*prev; // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem - struct cJSON *child; // An array or object item will have a child pointer pointing to a chain of the items in the array/object. + struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ - int type; // The type of the item, as above. + int type; /* The type of the item, as above. */ - char *valuestring; // The item's string, if type==cJSON_String - int valueint; // The item's number, if type==cJSON_Number - double valuedouble; // The item's number, if type==cJSON_Number + char *valuestring; /* The item's string, if type==cJSON_String */ + int valueint; /* The item's number, if type==cJSON_Number */ + double valuedouble; /* The item's number, if type==cJSON_Number */ - char *string; // The item's name string, if this item is the child of, or is in the list of subitems of an object. + char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ } cJSON; typedef struct cJSON_Hooks { @@ -58,27 +58,27 @@ typedef struct cJSON_Hooks { void (*free_fn)(void *ptr); } cJSON_Hooks; -// Supply malloc, realloc and free functions to cJSON +/* Supply malloc, realloc and free functions to cJSON */ extern void cJSON_InitHooks(cJSON_Hooks* hooks); -// Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ extern cJSON *cJSON_Parse(const char *value); -// Render a cJSON entity to text for transfer/storage. Free the char* when finished. +/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ extern char *cJSON_Print(cJSON *item); -// Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. +/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ extern char *cJSON_PrintUnformatted(cJSON *item); -// Delete a cJSON entity and all subentities. +/* Delete a cJSON entity and all subentities. */ extern void cJSON_Delete(cJSON *c); -// Returns the number of items in an array (or object). +/* Returns the number of items in an array (or object). */ extern int cJSON_GetArraySize(cJSON *array); -// Retrieve item number "item" from array "array". Returns NULL if unsuccessful. +/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); -// Get item "string" from object. Case insensitive. +/* Get item "string" from object. Case insensitive. */ extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); -// These calls create a cJSON item of the appropriate type. +/* These calls create a cJSON item of the appropriate type. */ extern cJSON *cJSON_CreateNull(); extern cJSON *cJSON_CreateTrue(); extern cJSON *cJSON_CreateFalse(); @@ -88,26 +88,26 @@ extern cJSON *cJSON_CreateString(const char *string); extern cJSON *cJSON_CreateArray(); extern cJSON *cJSON_CreateObject(); -// These utilities create an Array of count items. +/* These utilities create an Array of count items. */ extern cJSON *cJSON_CreateIntArray(int *numbers,int count); extern cJSON *cJSON_CreateFloatArray(float *numbers,int count); extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); extern cJSON *cJSON_CreateStringArray(const char **strings,int count); -// Append item to the specified array/object. +/* Append item to the specified array/object. */ extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); -// Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); -// Remove/Detatch items from Arrays/Objects. +/* Remove/Detatch items from Arrays/Objects. */ extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); extern void cJSON_DeleteItemFromArray(cJSON *array,int which); extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); -// Update array items. +/* Update array items. */ extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); diff --git a/test.c b/test.c index 4c6d3dd..a435e9a 100644 --- a/test.c +++ b/test.c @@ -24,7 +24,7 @@ #include #include "cJSON.h" -// Parse text to JSON, then render back to text, and print! +/* Parse text to JSON, then render back to text, and print! */ void doit(char *text) { char *out;cJSON *json; @@ -36,7 +36,7 @@ void doit(char *text) free(out); } -// Read a file, parse, render back, etc. +/* Read a file, parse, render back, etc. */ void dofile(char *filename) { FILE *f=fopen(filename,"rb");fseek(f,0,SEEK_END);long len=ftell(f);fseek(f,0,SEEK_SET); @@ -45,17 +45,17 @@ void dofile(char *filename) free(data); } -// Used by some code below as an example datatype. +/* Used by some code below as an example datatype. */ struct record {const char *precision;double lat,lon;const char *address,*city,*state,*zip,*country; }; -// Create a bunch of objects as demonstration. +/* Create a bunch of objects as demonstration. */ void create_objects() { - cJSON *root,*fmt,*img,*thm,*fld;char *out;int i; // declare a few. + cJSON *root,*fmt,*img,*thm,*fld;char *out;int i; /* declare a few. */ - // Here we construct some JSON standards, from the JSON site. + /* Here we construct some JSON standards, from the JSON site. */ - // Our "Video" datatype: + /* Our "Video" datatype: */ root=cJSON_CreateObject(); cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject()); @@ -65,25 +65,25 @@ void create_objects() cJSON_AddFalseToObject (fmt,"interlace"); cJSON_AddNumberToObject(fmt,"frame rate", 24); - out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); // Print to text, Delete the cJSON, print it, release the string. + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); /* Print to text, Delete the cJSON, print it, release the string. - // Our "days of the week" array: + /* Our "days of the week" array: */ const char *strings[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}; root=cJSON_CreateStringArray(strings,7); out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); - // Our matrix: + /* Our matrix: */ int numbers[3][3]={{0,-1,0},{1,0,0},{0,0,1}}; root=cJSON_CreateArray(); for (i=0;i<3;i++) cJSON_AddItemToArray(root,cJSON_CreateIntArray(numbers[i],3)); -// cJSON_ReplaceItemInArray(root,1,cJSON_CreateString("Replacement")); +/* cJSON_ReplaceItemInArray(root,1,cJSON_CreateString("Replacement")); */ out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); - // Our "gallery" item: + /* Our "gallery" item: */ int ids[4]={116,943,234,38793}; root=cJSON_CreateObject(); cJSON_AddItemToObject(root, "Image", img=cJSON_CreateObject()); @@ -91,14 +91,14 @@ void create_objects() cJSON_AddNumberToObject(img,"Height",600); cJSON_AddStringToObject(img,"Title","View from 15th Floor"); cJSON_AddItemToObject(img, "Thumbnail", thm=cJSON_CreateObject()); - cJSON_AddStringToObject(thm, "Url", "http://www.example.com/image/481989943"); + cJSON_AddStringToObject(thm, "Url", "http:/*www.example.com/image/481989943"); cJSON_AddNumberToObject(thm,"Height",125); cJSON_AddStringToObject(thm,"Width","100"); cJSON_AddItemToObject(img,"IDs", cJSON_CreateIntArray(ids,4)); out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); - // Our array of "records": + /* Our array of "records": */ struct record fields[2]={ {"zip",37.7668,-1.223959e+2,"","SAN FRANCISCO","CA","94107","US"}, {"zip",37.371991,-1.22026e+2,"","SUNNYVALE","CA","94085","US"}}; @@ -117,35 +117,35 @@ void create_objects() cJSON_AddStringToObject(fld, "Country", fields[i].country); } -// cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root,1),"City",cJSON_CreateIntArray(ids,4)); +/* cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root,1),"City",cJSON_CreateIntArray(ids,4)); */ out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); } int main (int argc, const char * argv[]) { - // a bunch of json: + /* a bunch of json: */ char text1[]="{\n\"name\": \"Jack (\\\"Bee\\\") Nimble\", \n\"format\": {\"type\": \"rect\", \n\"width\": 1920, \n\"height\": 1080, \n\"interlace\": false,\"frame rate\": 24\n}\n}"; char text2[]="[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]"; char text3[]="[\n [0, -1, 0],\n [1, 0, 0],\n [0, 0, 1]\n ]\n"; - char text4[]="{\n \"Image\": {\n \"Width\": 800,\n \"Height\": 600,\n \"Title\": \"View from 15th Floor\",\n \"Thumbnail\": {\n \"Url\": \"http://www.example.com/image/481989943\",\n \"Height\": 125,\n \"Width\": \"100\"\n },\n \"IDs\": [116, 943, 234, 38793]\n }\n }"; + char text4[]="{\n \"Image\": {\n \"Width\": 800,\n \"Height\": 600,\n \"Title\": \"View from 15th Floor\",\n \"Thumbnail\": {\n \"Url\": \"http:/*www.example.com/image/481989943\",\n \"Height\": 125,\n \"Width\": \"100\"\n },\n \"IDs\": [116, 943, 234, 38793]\n }\n }"; char text5[]="[\n {\n \"precision\": \"zip\",\n \"Latitude\": 37.7668,\n \"Longitude\": -122.3959,\n \"Address\": \"\",\n \"City\": \"SAN FRANCISCO\",\n \"State\": \"CA\",\n \"Zip\": \"94107\",\n \"Country\": \"US\"\n },\n {\n \"precision\": \"zip\",\n \"Latitude\": 37.371991,\n \"Longitude\": -122.026020,\n \"Address\": \"\",\n \"City\": \"SUNNYVALE\",\n \"State\": \"CA\",\n \"Zip\": \"94085\",\n \"Country\": \"US\"\n }\n ]"; - // Process each json textblock by parsing, then rebuilding: + /* Process each json textblock by parsing, then rebuilding: */ doit(text1); doit(text2); doit(text3); doit(text4); doit(text5); - // Parse standard testfiles: -// dofile("../../tests/test1"); -// dofile("../../tests/test2"); -// dofile("../../tests/test3"); -// dofile("../../tests/test4"); -// dofile("../../tests/test5"); + /* Parse standard testfiles: +/* dofile("../../tests/test1"); */ +/* dofile("../../tests/test2"); */ +/* dofile("../../tests/test3"); */ +/* dofile("../../tests/test4"); */ +/* dofile("../../tests/test5"); */ - // Now some samplecode for building objects concisely: + /* Now some samplecode for building objects concisely: */ create_objects(); return 0; From 6f51f007a981a106011c6569bbbef4972d45a114 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 2 Mar 2011 19:12:29 +0000 Subject: [PATCH 35/58] cJSON_Parse("") should return 0. git-svn-id: http://svn.code.sf.net/p/cjson/code@35 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 0f6d5e9..3c819bd 100644 --- a/cJSON.c +++ b/cJSON.c @@ -230,7 +230,7 @@ static const char *parse_object(cJSON *item,const char *value); static char *print_object(cJSON *item,int depth,int fmt); /* Utility to jump whitespace and cr/lf */ -static const char *skip(const char *in) {while (in && (unsigned char)*in<=32) in++; return in;} +static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} /* Parse an object - create a new root, and populate. */ cJSON *cJSON_Parse(const char *value) From b5d2db4d9a6927a6e4359c118ce6d83ed2625be2 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 2 Mar 2011 19:15:06 +0000 Subject: [PATCH 36/58] print_object was calling free() rather than cJSON_free() under failure conditions! git-svn-id: http://svn.code.sf.net/p/cjson/code@36 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index 3c819bd..2f68785 100644 --- a/cJSON.c +++ b/cJSON.c @@ -428,8 +428,8 @@ static char *print_object(cJSON *item,int depth,int fmt) /* Handle failure */ if (fail) { - for (i=0;i Date: Wed, 2 Mar 2011 21:04:46 +0000 Subject: [PATCH 37/58] Handle control-chars. In a certain sense, we shouldn't be seeing them, but this way we at least handle them well. git-svn-id: http://svn.code.sf.net/p/cjson/code@37 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cJSON.c b/cJSON.c index 2f68785..ec728ca 100644 --- a/cJSON.c +++ b/cJSON.c @@ -141,13 +141,13 @@ static const char *parse_string(cJSON *item,const char *str) const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; if (*str!='\"') return 0; /* not a string! */ - while (*ptr!='\"' && (unsigned char)*ptr>31 && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ + while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ if (!out) return 0; ptr=str+1;ptr2=out; - while (*ptr!='\"' && (unsigned char)*ptr>31) + while (*ptr!='\"' && *ptr) { if (*ptr!='\\') *ptr2++=*ptr++; else @@ -186,10 +186,10 @@ static const char *parse_string(cJSON *item,const char *str) /* Render the cstring provided to an escaped version that can be printed. */ static char *print_string_ptr(const char *str) { - const char *ptr;char *ptr2,*out;int len=0; + const char *ptr;char *ptr2,*out;int len=0;unsigned char token; if (!str) return cJSON_strdup(""); - ptr=str;while (*ptr && ++len) {if ((unsigned char)*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} + ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} out=(char*)cJSON_malloc(len+3); if (!out) return 0; @@ -202,7 +202,7 @@ static char *print_string_ptr(const char *str) else { *ptr2++='\\'; - switch (*ptr++) + switch (token=*ptr++) { case '\\': *ptr2++='\\'; break; case '\"': *ptr2++='\"'; break; @@ -211,7 +211,7 @@ static char *print_string_ptr(const char *str) case '\n': *ptr2++='n'; break; case '\r': *ptr2++='r'; break; case '\t': *ptr2++='t'; break; - default: ptr2--; break; /* eviscerate with prejudice. */ + default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ } } } From 6a58ba528584781c2386894ccec8205f8f242499 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 2 Mar 2011 21:22:57 +0000 Subject: [PATCH 38/58] Include some analysis so that you can debug a failed parse. You really oughtn't go too far with this, because it's only loose information; as I've said before, cJSON +isn't+ a validating parser. But this might give you enough info to save yourself on some rare occasion ;) git-svn-id: http://svn.code.sf.net/p/cjson/code@38 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 21 +++++++++++++-------- cJSON.h | 3 +++ test.c | 12 ++++++++---- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/cJSON.c b/cJSON.c index ec728ca..461b332 100644 --- a/cJSON.c +++ b/cJSON.c @@ -32,6 +32,10 @@ #include #include "cJSON.h" +static const char *ep; + +const char *cJSON_GetErrorPtr() {return ep;} + static int cJSON_strcasecmp(const char *s1,const char *s2) { if (!s1) return (s1==s2)?0:1;if (!s2) return 1; @@ -139,7 +143,7 @@ static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0x static const char *parse_string(cJSON *item,const char *str) { const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; - if (*str!='\"') return 0; /* not a string! */ + if (*str!='\"') {ep=str;return 0;} /* not a string! */ while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ @@ -235,6 +239,7 @@ static const char *skip(const char *in) {while (in && *in && (unsigned char)*in< /* Parse an object - create a new root, and populate. */ cJSON *cJSON_Parse(const char *value) { + ep=0; cJSON *c=cJSON_New_Item(); if (!c) return 0; /* memory fail */ @@ -258,7 +263,7 @@ static const char *parse_value(cJSON *item,const char *value) if (*value=='[') { return parse_array(item,value); } if (*value=='{') { return parse_object(item,value); } - return 0; /* failure. */ + ep=value;return 0; /* failure. */ } /* Render a value to text. */ @@ -283,7 +288,7 @@ static char *print_value(cJSON *item,int depth,int fmt) static const char *parse_array(cJSON *item,const char *value) { cJSON *child; - if (*value!='[') return 0; /* not an array! */ + if (*value!='[') {ep=value;return 0;} /* not an array! */ item->type=cJSON_Array; value=skip(value+1); @@ -304,7 +309,7 @@ static const char *parse_array(cJSON *item,const char *value) } if (*value==']') return value+1; /* end of array */ - return 0; /* malformed. */ + ep=value;return 0; /* malformed. */ } /* Render an array to text */ @@ -362,7 +367,7 @@ static char *print_array(cJSON *item,int depth,int fmt) static const char *parse_object(cJSON *item,const char *value) { cJSON *child; - if (*value!='{') return 0; /* not an object! */ + if (*value!='{') {ep=value;return 0;} /* not an object! */ item->type=cJSON_Object; value=skip(value+1); @@ -373,7 +378,7 @@ static const char *parse_object(cJSON *item,const char *value) value=skip(parse_string(child,skip(value))); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; - if (*value!=':') return 0; /* fail! */ + if (*value!=':') {ep=value;return 0;} /* fail! */ value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ if (!value) return 0; @@ -385,13 +390,13 @@ static const char *parse_object(cJSON *item,const char *value) value=skip(parse_string(child,skip(value+1))); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; - if (*value!=':') return 0; /* fail! */ + if (*value!=':') {ep=value;return 0;} /* fail! */ value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ if (!value) return 0; } if (*value=='}') return value+1; /* end of array */ - return 0; /* malformed. */ + ep=value;return 0; /* malformed. */ } /* Render an object to text. */ diff --git a/cJSON.h b/cJSON.h index 2da0f44..b7a6cd3 100644 --- a/cJSON.h +++ b/cJSON.h @@ -77,6 +77,9 @@ extern int cJSON_GetArraySize(cJSON *array); extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); /* Get item "string" from object. Case insensitive. */ extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); + +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +extern const char *cJSON_GetErrorPtr(); /* These calls create a cJSON item of the appropriate type. */ extern cJSON *cJSON_CreateNull(); diff --git a/test.c b/test.c index a435e9a..2cab632 100644 --- a/test.c +++ b/test.c @@ -30,10 +30,14 @@ void doit(char *text) char *out;cJSON *json; json=cJSON_Parse(text); - out=cJSON_Print(json); - cJSON_Delete(json); - printf("%s\n",out); - free(out); + if (!json) {printf("Error before: [%s]\n",cJSON_GetErrorPtr());} + else + { + out=cJSON_Print(json); + cJSON_Delete(json); + printf("%s\n",out); + free(out); + } } /* Read a file, parse, render back, etc. */ From 15dada46b58a0cb96afd7777fbc11af31d9b8676 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Mon, 7 Mar 2011 16:35:13 +0000 Subject: [PATCH 39/58] Fix missing cast for compilation as c++!! git-svn-id: http://svn.code.sf.net/p/cjson/code@39 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 461b332..4f30e3a 100644 --- a/cJSON.c +++ b/cJSON.c @@ -337,7 +337,7 @@ static char *print_array(cJSON *item,int depth,int fmt) } /* If we didn't fail, try to malloc the output string */ - if (!fail) out=cJSON_malloc(len); + if (!fail) out=(char*)cJSON_malloc(len); /* If that fails, we fail. */ if (!out) fail=1; From 9061b7a7e774cc32cc196f8df82fddac90259dcf Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Mon, 14 Mar 2011 21:34:03 +0000 Subject: [PATCH 40/58] Fix c99 violation! git-svn-id: http://svn.code.sf.net/p/cjson/code@40 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 4f30e3a..f922ad6 100644 --- a/cJSON.c +++ b/cJSON.c @@ -239,8 +239,8 @@ static const char *skip(const char *in) {while (in && *in && (unsigned char)*in< /* Parse an object - create a new root, and populate. */ cJSON *cJSON_Parse(const char *value) { - ep=0; cJSON *c=cJSON_New_Item(); + ep=0; if (!c) return 0; /* memory fail */ if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;} From 0d268cfef79f07a56514afa5ee4630c1f0b2c710 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Mon, 10 Oct 2011 15:22:34 +0000 Subject: [PATCH 41/58] Update to cJSON! We now support UTF-16 surrogate pairs :) git-svn-id: http://svn.code.sf.net/p/cjson/code@41 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/cJSON.c b/cJSON.c index f922ad6..0e68a49 100644 --- a/cJSON.c +++ b/cJSON.c @@ -142,7 +142,7 @@ static char *print_number(cJSON *item) static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; static const char *parse_string(cJSON *item,const char *str) { - const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; + const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; if (*str!='\"') {ep=str;return 0;} /* not a string! */ while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ @@ -164,16 +164,28 @@ static const char *parse_string(cJSON *item,const char *str) case 'n': *ptr2++='\n'; break; case 'r': *ptr2++='\r'; break; case 't': *ptr2++='\t'; break; - case 'u': /* transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY. */ - sscanf(ptr+1,"%4x",&uc); /* get the unicode char. */ - len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len; + case 'u': /* transcode utf16 to utf8. */ + sscanf(ptr+1,"%4x",&uc);ptr+=4; /* get the unicode char. */ + + if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid. + + if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs. + { + if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate. + sscanf(ptr+3,"%4x",&uc2);ptr+=6; + if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate. + uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF); + } + + len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; switch (len) { + case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; case 1: *--ptr2 =(uc | firstByteMark[len]); } - ptr2+=len;ptr+=4; + ptr2+=len; break; default: *ptr2++=*ptr; break; } From fd1ac4f1791b403af1f7350b1195ac114f9b792b Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Mon, 10 Oct 2011 15:33:19 +0000 Subject: [PATCH 42/58] make parse_number more robust! git-svn-id: http://svn.code.sf.net/p/cjson/code@42 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 0e68a49..eb7c2f9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -101,7 +101,7 @@ static const char *parse_number(cJSON *item,const char *num) if (*num=='-') sign=-1,num++; /* Has sign? */ if (*num=='0') num++; /* is zero */ if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ - if (*num=='.') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ + if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ if (*num=='e' || *num=='E') /* Exponent? */ { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ From 4678f33b5c84728ec8549b4a0cb5a12ef35d5ab7 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Tue, 5 Feb 2013 17:00:31 +0000 Subject: [PATCH 43/58] Fix up ANSI issues. git-svn-id: http://svn.code.sf.net/p/cjson/code@43 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 22 +++++++++++----------- cJSON.h | 12 ++++++------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/cJSON.c b/cJSON.c index eb7c2f9..27c3385 100644 --- a/cJSON.c +++ b/cJSON.c @@ -34,7 +34,7 @@ static const char *ep; -const char *cJSON_GetErrorPtr() {return ep;} +const char *cJSON_GetErrorPtr(void) {return ep;} static int cJSON_strcasecmp(const char *s1,const char *s2) { @@ -70,7 +70,7 @@ void cJSON_InitHooks(cJSON_Hooks* hooks) } /* Internal constructor. */ -static cJSON *cJSON_New_Item() +static cJSON *cJSON_New_Item(void) { cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); if (node) memset(node,0,sizeof(cJSON)); @@ -167,13 +167,13 @@ static const char *parse_string(cJSON *item,const char *str) case 'u': /* transcode utf16 to utf8. */ sscanf(ptr+1,"%4x",&uc);ptr+=4; /* get the unicode char. */ - if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid. + if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ - if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs. + if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ { - if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate. + if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ sscanf(ptr+3,"%4x",&uc2);ptr+=6; - if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate. + if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF); } @@ -498,14 +498,14 @@ void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON * 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);}} /* Create basic types: */ -cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} -cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} -cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} +cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} +cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} +cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} -cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} -cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} +cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} +cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} /* Create Arrays: */ cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} diff --git a/cJSON.h b/cJSON.h index b7a6cd3..97d529a 100644 --- a/cJSON.h +++ b/cJSON.h @@ -79,17 +79,17 @@ extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ -extern const char *cJSON_GetErrorPtr(); +extern const char *cJSON_GetErrorPtr(void); /* These calls create a cJSON item of the appropriate type. */ -extern cJSON *cJSON_CreateNull(); -extern cJSON *cJSON_CreateTrue(); -extern cJSON *cJSON_CreateFalse(); +extern cJSON *cJSON_CreateNull(void); +extern cJSON *cJSON_CreateTrue(void); +extern cJSON *cJSON_CreateFalse(void); extern cJSON *cJSON_CreateBool(int b); extern cJSON *cJSON_CreateNumber(double num); extern cJSON *cJSON_CreateString(const char *string); -extern cJSON *cJSON_CreateArray(); -extern cJSON *cJSON_CreateObject(); +extern cJSON *cJSON_CreateArray(void); +extern cJSON *cJSON_CreateObject(void); /* These utilities create an Array of count items. */ extern cJSON *cJSON_CreateIntArray(int *numbers,int count); From 3ddf3a59112aa1723b0ff98c7d48b62b3ef641ef Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Tue, 5 Feb 2013 17:14:12 +0000 Subject: [PATCH 44/58] stable solution for printing arrays - based on patch donated by Jerome Lang. Resolves issue in case malloc(0)!=0. git-svn-id: http://svn.code.sf.net/p/cjson/code@44 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/cJSON.c b/cJSON.c index 27c3385..027f440 100644 --- a/cJSON.c +++ b/cJSON.c @@ -327,25 +327,28 @@ static const char *parse_array(cJSON *item,const char *value) /* Render an array to text */ static char *print_array(cJSON *item,int depth,int fmt) { - char **entries; + char **entries=0; char *out=0,*ptr,*ret;int len=5; cJSON *child=item->child; int numentries=0,i=0,fail=0; /* How many entries in the array? */ while (child) numentries++,child=child->next; - /* Allocate an array to hold the values for each */ - entries=(char**)cJSON_malloc(numentries*sizeof(char*)); - if (!entries) return 0; - memset(entries,0,numentries*sizeof(char*)); - /* Retrieve all the results: */ - child=item->child; - while (child && !fail) + if (numentries) { - ret=print_value(child,depth+1,fmt); - entries[i++]=ret; - if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; - child=child->next; + /* Allocate an array to hold the values for each */ + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + memset(entries,0,numentries*sizeof(char*)); + /* Retrieve all the results: */ + child=item->child; + while (child && !fail) + { + ret=print_value(child,depth+1,fmt); + entries[i++]=ret; + if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; + child=child->next; + } } /* If we didn't fail, try to malloc the output string */ @@ -357,7 +360,7 @@ static char *print_array(cJSON *item,int depth,int fmt) if (fail) { for (i=0;i Date: Tue, 5 Feb 2013 17:27:59 +0000 Subject: [PATCH 45/58] Revert last patch. Simpler fix for empty arrays/objects is to handle them explicitly and then bail. Saves plenty of unnecessary state-tracking. git-svn-id: http://svn.code.sf.net/p/cjson/code@45 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/cJSON.c b/cJSON.c index 027f440..9262cb4 100644 --- a/cJSON.c +++ b/cJSON.c @@ -327,28 +327,32 @@ static const char *parse_array(cJSON *item,const char *value) /* Render an array to text */ static char *print_array(cJSON *item,int depth,int fmt) { - char **entries=0; + char **entries; char *out=0,*ptr,*ret;int len=5; cJSON *child=item->child; int numentries=0,i=0,fail=0; /* How many entries in the array? */ while (child) numentries++,child=child->next; - if (numentries) + /* Explicitly handle numentries==0 */ + if (!numentries) { - /* Allocate an array to hold the values for each */ - entries=(char**)cJSON_malloc(numentries*sizeof(char*)); - if (!entries) return 0; - memset(entries,0,numentries*sizeof(char*)); - /* Retrieve all the results: */ - child=item->child; - while (child && !fail) - { - ret=print_value(child,depth+1,fmt); - entries[i++]=ret; - if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; - child=child->next; - } + out=(char*)cJSON_malloc(3); + if (out) strcpy(out,"[]"); + return out; + } + /* Allocate an array to hold the values for each */ + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + memset(entries,0,numentries*sizeof(char*)); + /* Retrieve all the results: */ + child=item->child; + while (child && !fail) + { + ret=print_value(child,depth+1,fmt); + entries[i++]=ret; + if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; + child=child->next; } /* If we didn't fail, try to malloc the output string */ @@ -360,7 +364,7 @@ static char *print_array(cJSON *item,int depth,int fmt) if (fail) { for (i=0;inext; + /* Explicitly handle empty object case */ + if (!numentries) + { + out=cJSON_malloc(fmt?depth+3:3); + if (!out) return 0; + ptr=out;*ptr++='{'; + if (fmt) {*ptr++='\n';for (i=0;i Date: Tue, 5 Feb 2013 17:38:48 +0000 Subject: [PATCH 46/58] fix handling of utf16 surrogate pairs! git-svn-id: http://svn.code.sf.net/p/cjson/code@46 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 9262cb4..dc98985 100644 --- a/cJSON.c +++ b/cJSON.c @@ -174,7 +174,7 @@ static const char *parse_string(cJSON *item,const char *str) if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ sscanf(ptr+3,"%4x",&uc2);ptr+=6; if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ - uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF); + uc=0x10000 + ((uc&0x3FF)<<10) | (uc2&0x3FF); } len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; From a7fe08778f4102d0045206bf0162981bf55286a3 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Tue, 5 Feb 2013 17:42:42 +0000 Subject: [PATCH 47/58] bracket logic (to quiet a warning). Fix for potential buffer overflow printing extremely large integers. git-svn-id: http://svn.code.sf.net/p/cjson/code@47 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index dc98985..595d4cd 100644 --- a/cJSON.c +++ b/cJSON.c @@ -130,9 +130,9 @@ static char *print_number(cJSON *item) str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ if (str) { - if (fabs(floor(d)-d)<=DBL_EPSILON) sprintf(str,"%.0f",d); - else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); - else sprintf(str,"%f",d); + if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); + else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); + else sprintf(str,"%f",d); } } return str; @@ -174,7 +174,7 @@ static const char *parse_string(cJSON *item,const char *str) if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ sscanf(ptr+3,"%4x",&uc2);ptr+=6; if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ - uc=0x10000 + ((uc&0x3FF)<<10) | (uc2&0x3FF); + uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); } len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; From 927aa631b82143ab5304087446f173819eb94543 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Tue, 5 Feb 2013 18:23:22 +0000 Subject: [PATCH 48/58] Added cJSON_Duplicate. With commentary git-svn-id: http://svn.code.sf.net/p/cjson/code@48 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 27 +++++++++++++++++++++++++++ cJSON.h | 6 ++++++ 2 files changed, 33 insertions(+) diff --git a/cJSON.c b/cJSON.c index 595d4cd..c56d44a 100644 --- a/cJSON.c +++ b/cJSON.c @@ -529,3 +529,30 @@ cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} + +/* Duplication */ +cJSON *cJSON_Duplicate(cJSON *item,int recurse) +{ + cJSON *newitem,*cptr,*nptr=0,*newchild; + /* Bail on bad ptr */ + if (!item) return 0; + /* Create new item */ + newitem=cJSON_New_Item(); + if (!newitem) return 0; + /* Copy over all vars */ + newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; + if (item->valuestring) newitem->valuestring=cJSON_strdup(item->valuestring); + if (item->string) newitem->string=cJSON_strdup(item->string); + /* If non-recursive, then we're done! */ + if (!recurse) return newitem; + /* Walk the ->next chain for the child. */ + cptr=item->child; + while (cptr) + { + newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ + if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ + cptr=cptr->next; + } + return newitem; +} diff --git a/cJSON.h b/cJSON.h index 97d529a..4df09a7 100644 --- a/cJSON.h +++ b/cJSON.h @@ -114,6 +114,12 @@ extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +/* Duplicate a cJSON item */ +extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will +need to be released. With recurse!=0, it will duplicate any children connected to the item. +The item->next and ->prev pointers are always zero on return from Duplicate. */ + #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) From d755436ba727b14ec74bf7ef6256b332b715c679 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Tue, 5 Feb 2013 18:26:51 +0000 Subject: [PATCH 49/58] tests for cJSON_Duplicate, so it will fail by returning 0 if anything fails to allocate git-svn-id: http://svn.code.sf.net/p/cjson/code@49 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index c56d44a..ff5bd85 100644 --- a/cJSON.c +++ b/cJSON.c @@ -541,8 +541,8 @@ cJSON *cJSON_Duplicate(cJSON *item,int recurse) if (!newitem) return 0; /* Copy over all vars */ newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; - if (item->valuestring) newitem->valuestring=cJSON_strdup(item->valuestring); - if (item->string) newitem->string=cJSON_strdup(item->string); + if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} + if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} /* If non-recursive, then we're done! */ if (!recurse) return newitem; /* Walk the ->next chain for the child. */ @@ -550,6 +550,7 @@ cJSON *cJSON_Duplicate(cJSON *item,int recurse) while (cptr) { newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) {cJSON_Delete(newitem);return 0;} if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ cptr=cptr->next; From 96c59f3e4993ef0396ff26105fb3340d12c7e204 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 6 Feb 2013 12:44:17 +0000 Subject: [PATCH 50/58] Wire in ParseWithOpts to allow detection of JSON with following garbage. git-svn-id: http://svn.code.sf.net/p/cjson/code@50 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 12 ++++++++++-- cJSON.h | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index ff5bd85..353b72d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -249,15 +249,23 @@ static char *print_object(cJSON *item,int depth,int fmt); static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} /* Parse an object - create a new root, and populate. */ -cJSON *cJSON_Parse(const char *value) +cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) { + const char *end=0; cJSON *c=cJSON_New_Item(); ep=0; if (!c) return 0; /* memory fail */ - if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;} + end=parse_value(c,skip(value)); + if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} + if (return_parse_end) *return_parse_end=end; return c; } +/* Default options for cJSON_Parse */ +cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} /* Render a cJSON item/entity/structure to text. */ char *cJSON_Print(cJSON *item) {return print_value(item,0,1);} diff --git a/cJSON.h b/cJSON.h index 4df09a7..d54a821 100644 --- a/cJSON.h +++ b/cJSON.h @@ -120,6 +120,10 @@ extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); need to be released. With recurse!=0, it will duplicate any children connected to the item. The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed */ +extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); + + #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) From 02a1e544f7e7661fcb0722d81329edc92517c952 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 6 Feb 2013 12:59:21 +0000 Subject: [PATCH 51/58] add cJSON_AddBoolToObject(). git-svn-id: http://svn.code.sf.net/p/cjson/code@51 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cJSON.h b/cJSON.h index d54a821..3469123 100644 --- a/cJSON.h +++ b/cJSON.h @@ -124,9 +124,10 @@ The item->next and ->prev pointers are always zero on return from Duplicate. */ extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); -#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) -#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) From 2c9474e9e386b7a0167aa2b5e8f3a83243c7a5c6 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Sat, 9 Feb 2013 12:55:11 +0000 Subject: [PATCH 52/58] fix non-explicit cast git-svn-id: http://svn.code.sf.net/p/cjson/code@52 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 353b72d..04b5079 100644 --- a/cJSON.c +++ b/cJSON.c @@ -438,7 +438,7 @@ static char *print_object(cJSON *item,int depth,int fmt) /* Explicitly handle empty object case */ if (!numentries) { - out=cJSON_malloc(fmt?depth+3:3); + out=(char*)cJSON_malloc(fmt?depth+3:3); if (!out) return 0; ptr=out;*ptr++='{'; if (fmt) {*ptr++='\n';for (i=0;i Date: Sat, 9 Feb 2013 12:56:01 +0000 Subject: [PATCH 53/58] Tidy comments. Add cJSON_SetIntValue. git-svn-id: http://svn.code.sf.net/p/cjson/code@53 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cJSON.h b/cJSON.h index 3469123..1aefe09 100644 --- a/cJSON.h +++ b/cJSON.h @@ -120,10 +120,10 @@ extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); need to be released. With recurse!=0, it will duplicate any children connected to the item. The item->next and ->prev pointers are always zero on return from Duplicate. */ -/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed */ +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); - +/* Macros for creating things quickly. */ #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) @@ -131,6 +131,9 @@ extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_en #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) + #ifdef __cplusplus } #endif From 46e3724aa8d0a0470d3f98066eb42a500822da77 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Sat, 9 Feb 2013 12:57:04 +0000 Subject: [PATCH 54/58] clean up test.c git-svn-id: http://svn.code.sf.net/p/cjson/code@54 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test.c b/test.c index 2cab632..b308a92 100644 --- a/test.c +++ b/test.c @@ -44,7 +44,7 @@ void doit(char *text) void dofile(char *filename) { FILE *f=fopen(filename,"rb");fseek(f,0,SEEK_END);long len=ftell(f);fseek(f,0,SEEK_SET); - char *data=malloc(len+1);fread(data,1,len,f);fclose(f); + char *data=(char*)malloc(len+1);fread(data,1,len,f);fclose(f); doit(data); free(data); } @@ -69,7 +69,7 @@ void create_objects() cJSON_AddFalseToObject (fmt,"interlace"); cJSON_AddNumberToObject(fmt,"frame rate", 24); - out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); /* Print to text, Delete the cJSON, print it, release the string. + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); /* Print to text, Delete the cJSON, print it, release the string. */ /* Our "days of the week" array: */ const char *strings[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}; @@ -142,7 +142,7 @@ int main (int argc, const char * argv[]) { doit(text4); doit(text5); - /* Parse standard testfiles: + /* Parse standard testfiles: */ /* dofile("../../tests/test1"); */ /* dofile("../../tests/test2"); */ /* dofile("../../tests/test3"); */ From 73cc8dd1c437189b5e3ad112ee283efbe8a14fd3 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 14 Aug 2013 12:58:13 +0000 Subject: [PATCH 55/58] cJSON_Minify (which strips comments), fixed buffer overflow const * for array creates git-svn-id: http://svn.code.sf.net/p/cjson/code@55 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 25 +++++++++++++++++++++---- cJSON.h | 8 +++++--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/cJSON.c b/cJSON.c index 04b5079..f1706df 100644 --- a/cJSON.c +++ b/cJSON.c @@ -438,7 +438,7 @@ static char *print_object(cJSON *item,int depth,int fmt) /* Explicitly handle empty object case */ if (!numentries) { - out=(char*)cJSON_malloc(fmt?depth+3:3); + out=(char*)cJSON_malloc(fmt?depth+4:3); if (!out) return 0; ptr=out;*ptr++='{'; if (fmt) {*ptr++='\n';for (i=0;it cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} /* Create Arrays: */ -cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} /* Duplication */ @@ -565,3 +565,20 @@ cJSON *cJSON_Duplicate(cJSON *item,int recurse) } return newitem; } + +void cJSON_Minify(char *json) +{ + char *into=json; + while (*json) + { + if (*json==' ') json++; + else if (*json=='\t') json++; // Whitespace characters. + else if (*json=='\r') json++; + else if (*json=='\n') json++; + else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; // double-slash comments, to end of line. + else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} // multiline comments. + else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} // string literals, which are \" sensitive. + else *into++=*json++; // All other characters. + } + *into=0; // and null-terminate. +} \ No newline at end of file diff --git a/cJSON.h b/cJSON.h index 1aefe09..867b7c3 100644 --- a/cJSON.h +++ b/cJSON.h @@ -92,9 +92,9 @@ extern cJSON *cJSON_CreateArray(void); extern cJSON *cJSON_CreateObject(void); /* These utilities create an Array of count items. */ -extern cJSON *cJSON_CreateIntArray(int *numbers,int count); -extern cJSON *cJSON_CreateFloatArray(float *numbers,int count); -extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); +extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); +extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); +extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); extern cJSON *cJSON_CreateStringArray(const char **strings,int count); /* Append item to the specified array/object. */ @@ -123,6 +123,8 @@ The item->next and ->prev pointers are always zero on return from Duplicate. */ /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); +extern void cJSON_Minify(char *json); + /* Macros for creating things quickly. */ #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) From 22e51c92f032bda0e3fef7cf0514d4d02f00f4d2 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 14 Aug 2013 13:16:18 +0000 Subject: [PATCH 56/58] license file separated out :) git-svn-id: http://svn.code.sf.net/p/cjson/code@56 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- LICENSE | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fa0a438 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + From c537515c171fa0c424c58eb3fbc7123801f99d1b Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Wed, 14 Aug 2013 13:20:42 +0000 Subject: [PATCH 57/58] inbuilt hex parser for unicode, which ought to be a lot faster. git-svn-id: http://svn.code.sf.net/p/cjson/code@57 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/cJSON.c b/cJSON.c index f1706df..6132cbc 100644 --- a/cJSON.c +++ b/cJSON.c @@ -97,7 +97,6 @@ static const char *parse_number(cJSON *item,const char *num) { double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; - /* Could use sscanf for this? */ if (*num=='-') sign=-1,num++; /* Has sign? */ if (*num=='0') num++; /* is zero */ if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ @@ -138,6 +137,19 @@ static char *print_number(cJSON *item) return str; } +static unsigned parse_hex4(const char *str) +{ + unsigned h=0; + 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; + h=(h&15)<<4;str++; + 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; + h=(h&15)<<4;str++; + 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; + h=(h&15)<<4;str++; + 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; + return h; +} + /* Parse the input text into an unescaped cstring, and populate item. */ static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; static const char *parse_string(cJSON *item,const char *str) @@ -165,14 +177,14 @@ static const char *parse_string(cJSON *item,const char *str) case 'r': *ptr2++='\r'; break; case 't': *ptr2++='\t'; break; case 'u': /* transcode utf16 to utf8. */ - sscanf(ptr+1,"%4x",&uc);ptr+=4; /* get the unicode char. */ + uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ { if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ - sscanf(ptr+3,"%4x",&uc2);ptr+=6; + uc2=parse_hex4(ptr+3);ptr+=6; if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); } From 28691956a607ccec14b1f31756c7f179d50a0d17 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Mon, 19 Aug 2013 14:49:06 +0000 Subject: [PATCH 58/58] fix \u parser git-svn-id: http://svn.code.sf.net/p/cjson/code@58 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cJSON.c b/cJSON.c index 6132cbc..31c43dd 100644 --- a/cJSON.c +++ b/cJSON.c @@ -141,11 +141,11 @@ static unsigned parse_hex4(const char *str) { unsigned h=0; 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; - h=(h&15)<<4;str++; + h=h<<4;str++; 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; - h=(h&15)<<4;str++; + h=h<<4;str++; 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; - h=(h&15)<<4;str++; + h=h<<4;str++; 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; return h; }