Browse Source

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

Dave Gamble 15 years ago
parent
commit
7ca2c994a7
2 changed files with 86 additions and 25 deletions
  1. 76 25
      cJSON.c
  2. 10 0
      cJSON.h

+ 76 - 25
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 - 0
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.