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
This commit is contained in:
Dave Gamble 2009-10-29 00:21:54 +00:00
parent c052999a71
commit 7ca2c994a7
2 changed files with 86 additions and 25 deletions

101
cJSON.c
View File

@ -30,12 +30,47 @@
#include <float.h>
#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;i<depth;i++) *ptr++='\t';
ptr+=sprintf(ptr,str);
@ -329,7 +380,7 @@ static char *print_object(cJSON *item,int depth)
if (child->next) *ptr++=',';
*ptr++='\n';*ptr=0;
child=child->next;
free(str);free(ret);
cJSON_free(str);cJSON_free(ret);
}
for (i=0;i<depth-1;i++) *ptr++='\t';
*ptr++='}';*ptr++=0;
@ -346,14 +397,14 @@ static void suffix_object(cJSON *prev,cJSON *item) {prev->next=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;}

10
cJSON.h
View File

@ -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.