Browse Source

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

Dave Gamble 15 years ago
parent
commit
5cca4e2c57
2 changed files with 82 additions and 32 deletions
  1. 82 31
      cJSON.c
  2. 0 1
      cJSON.h

+ 82 - 31
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;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
+		cJSON_free(entries);
+		return 0;
+	}
+	
+	// Compose the output array.
+	*out='[';
+	ptr=out+1;*ptr=0;
+	for (i=0;i<numentries;i++)
+	{
+		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
+		if (i!=numentries-1) {*ptr++=',';*ptr++=' ';*ptr=0;}
+		cJSON_free(entries[i]);
+	}
+	cJSON_free(entries);
 	*ptr++=']';*ptr++=0;
 	return out;	
 }
@@ -359,29 +383,56 @@ static const char *parse_object(cJSON *item,const char *value)
 // Render an object to text.
 static char *print_object(cJSON *item,int depth)
 {
-	char *out,*ptr,*ret,*str;int len=7,i;
+	char **entries=0,**names=0;
+	char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
 	cJSON *child=item->child;
-	
-	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;i<depth;i++) *ptr++='\t';
-		ptr+=sprintf(ptr,"%s",str);
+		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;
+	}
+	
+	// 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<numentries;i++) {if (names[i]) free(names[i]);if (entries[i]) free(entries[i]);}
+		free(names);free(entries);
+		return 0;
+	}
+	
+	// Compose the output:
+	*out='{';ptr=out+1;*ptr++='\n';*ptr=0;
+	for (i=0;i<numentries;i++)
+	{
+		for (j=0;j<depth;j++) *ptr++='\t';
+		strcpy(ptr,names[i]);ptr+=strlen(names[i]);
 		*ptr++=':';*ptr++='\t';
-		ptr+=sprintf(ptr,"%s",ret);
-		if (child->next) *ptr++=',';
+		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
+		if (i!=numentries-1) *ptr++=',';
 		*ptr++='\n';*ptr=0;
-		child=child->next;
-		cJSON_free(str);cJSON_free(ret);
+		cJSON_free(names[i]);cJSON_free(entries[i]);
 	}
+	
+	cJSON_free(names);cJSON_free(entries);
 	for (i=0;i<depth-1;i++) *ptr++='\t';
 	*ptr++='}';*ptr++=0;
 	return out;	

+ 0 - 1
cJSON.h

@@ -53,7 +53,6 @@ typedef struct 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;