Kaynağa Gözat

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 yıl önce
ebeveyn
işleme
5cca4e2c57
2 değiştirilmiş dosya ile 82 ekleme ve 32 silme
  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;