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.