mirror of
https://github.com/DaveGamble/cJSON.git
synced 2023-08-10 21:13:26 +03:00
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:
parent
c052999a71
commit
7ca2c994a7
101
cJSON.c
101
cJSON.c
@ -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
10
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.
|
||||
|
Loading…
Reference in New Issue
Block a user