|
|
@ -1306,114 +1306,278 @@ static const char *parse_object(cJSON *item, const char *value, const char **ep) |
|
|
|
} |
|
|
|
|
|
|
|
/* Render an object to text. */ |
|
|
|
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p) |
|
|
|
static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p) |
|
|
|
{ |
|
|
|
char **entries=0,**names=0; |
|
|
|
char *out=0,*ptr,*ret,*str;int len=7,i=0,j; |
|
|
|
cJSON *child=item->child; |
|
|
|
int numentries=0,fail=0; |
|
|
|
size_t tmplen=0; |
|
|
|
/* Count the number of entries. */ |
|
|
|
while (child) numentries++,child=child->next; |
|
|
|
/* Explicitly handle empty object case */ |
|
|
|
if (!numentries) |
|
|
|
{ |
|
|
|
if (p) out=ensure(p,fmt?depth+4:3); |
|
|
|
else out=(char*)cJSON_malloc(fmt?depth+4:3); |
|
|
|
if (!out) return 0; |
|
|
|
ptr=out;*ptr++='{'; |
|
|
|
if (fmt) {*ptr++='\n';for (i=0;i<depth;i++) *ptr++='\t';} |
|
|
|
*ptr++='}';*ptr++=0; |
|
|
|
return out; |
|
|
|
} |
|
|
|
if (p) |
|
|
|
{ |
|
|
|
/* Compose the output: */ |
|
|
|
i=p->offset; |
|
|
|
len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0; |
|
|
|
*ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; |
|
|
|
child=item->child;depth++; |
|
|
|
while (child) |
|
|
|
{ |
|
|
|
if (fmt) |
|
|
|
{ |
|
|
|
ptr=ensure(p,depth); if (!ptr) return 0; |
|
|
|
for (j=0;j<depth;j++) *ptr++='\t'; |
|
|
|
p->offset+=depth; |
|
|
|
} |
|
|
|
print_string_ptr(child->string,p); |
|
|
|
p->offset=update(p); |
|
|
|
|
|
|
|
len=fmt?2:1; |
|
|
|
ptr=ensure(p,len); if (!ptr) return 0; |
|
|
|
*ptr++=':';if (fmt) *ptr++='\t'; |
|
|
|
p->offset+=len; |
|
|
|
|
|
|
|
print_value(child,depth,fmt,p); |
|
|
|
p->offset=update(p); |
|
|
|
|
|
|
|
len=(fmt?1:0)+(child->next?1:0); |
|
|
|
ptr=ensure(p,len+1); if (!ptr) return 0; |
|
|
|
if (child->next) *ptr++=','; |
|
|
|
if (fmt) *ptr++='\n';*ptr=0; |
|
|
|
p->offset+=len; |
|
|
|
child=child->next; |
|
|
|
} |
|
|
|
ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0; |
|
|
|
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t'; |
|
|
|
*ptr++='}';*ptr=0; |
|
|
|
out=(p->buffer)+i; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
/* 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++;if (fmt) len+=depth; |
|
|
|
while (child && !fail) |
|
|
|
{ |
|
|
|
names[i]=str=print_string_ptr(child->string,0); |
|
|
|
entries[i++]=ret=print_value(child,depth,fmt,0); |
|
|
|
if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); 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]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);} |
|
|
|
cJSON_free(names);cJSON_free(entries); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* Compose the output: */ |
|
|
|
*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0; |
|
|
|
for (i=0;i<numentries;i++) |
|
|
|
{ |
|
|
|
if (fmt) for (j=0;j<depth;j++) *ptr++='\t'; |
|
|
|
tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen; |
|
|
|
*ptr++=':';if (fmt) *ptr++='\t'; |
|
|
|
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); |
|
|
|
if (i!=numentries-1) *ptr++=','; |
|
|
|
if (fmt) *ptr++='\n';*ptr=0; |
|
|
|
cJSON_free(names[i]);cJSON_free(entries[i]); |
|
|
|
} |
|
|
|
|
|
|
|
cJSON_free(names);cJSON_free(entries); |
|
|
|
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t'; |
|
|
|
*ptr++='}';*ptr++=0; |
|
|
|
} |
|
|
|
return out; |
|
|
|
char **entries = 0; |
|
|
|
char **names = 0; |
|
|
|
char *out = 0; |
|
|
|
char *ptr; |
|
|
|
char *ret; |
|
|
|
char *str; |
|
|
|
int len = 7; |
|
|
|
int i = 0; |
|
|
|
int j; |
|
|
|
cJSON *child = item->child; |
|
|
|
int numentries = 0; |
|
|
|
int fail = 0; |
|
|
|
size_t tmplen = 0; |
|
|
|
|
|
|
|
/* Count the number of entries. */ |
|
|
|
while (child) |
|
|
|
{ |
|
|
|
numentries++; |
|
|
|
child = child->next; |
|
|
|
} |
|
|
|
|
|
|
|
/* Explicitly handle empty object case */ |
|
|
|
if (!numentries) |
|
|
|
{ |
|
|
|
if (p) |
|
|
|
{ |
|
|
|
out = ensure(p, fmt ? depth + 4 : 3); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
out = (char*)cJSON_malloc(fmt ? depth + 4 : 3); |
|
|
|
} |
|
|
|
if (!out) |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
ptr = out; |
|
|
|
*ptr++ = '{'; |
|
|
|
if (fmt) { |
|
|
|
*ptr++ = '\n'; |
|
|
|
for (i = 0; i < depth; i++) |
|
|
|
{ |
|
|
|
*ptr++ = '\t'; |
|
|
|
} |
|
|
|
} |
|
|
|
*ptr++ = '}'; |
|
|
|
*ptr++ = '\0'; |
|
|
|
|
|
|
|
return out; |
|
|
|
} |
|
|
|
|
|
|
|
if (p) |
|
|
|
{ |
|
|
|
/* Compose the output: */ |
|
|
|
i = p->offset; |
|
|
|
len = fmt ? 2 : 1; /* fmt: {\n */ |
|
|
|
ptr = ensure(p, len + 1); |
|
|
|
if (!ptr) |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
*ptr++ = '{'; |
|
|
|
if (fmt) |
|
|
|
{ |
|
|
|
*ptr++ = '\n'; |
|
|
|
} |
|
|
|
*ptr = '\0'; |
|
|
|
p->offset += len; |
|
|
|
|
|
|
|
child = item->child; |
|
|
|
depth++; |
|
|
|
while (child) |
|
|
|
{ |
|
|
|
if (fmt) |
|
|
|
{ |
|
|
|
ptr = ensure(p, depth); |
|
|
|
if (!ptr) |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
for (j = 0; j < depth; j++) |
|
|
|
{ |
|
|
|
*ptr++ = '\t'; |
|
|
|
} |
|
|
|
p->offset += depth; |
|
|
|
} |
|
|
|
|
|
|
|
/* print key */ |
|
|
|
print_string_ptr(child->string, p); |
|
|
|
p->offset = update(p); |
|
|
|
|
|
|
|
len = fmt ? 2 : 1; |
|
|
|
ptr = ensure(p, len); |
|
|
|
if (!ptr) |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
*ptr++ = ':'; |
|
|
|
if (fmt) |
|
|
|
{ |
|
|
|
*ptr++ = '\t'; |
|
|
|
} |
|
|
|
p->offset+=len; |
|
|
|
|
|
|
|
/* print value */ |
|
|
|
print_value(child, depth, fmt, p); |
|
|
|
p->offset = update(p); |
|
|
|
|
|
|
|
/* print comma if not last */ |
|
|
|
len = (fmt ? 1 : 0) + (child->next ? 1 : 0); |
|
|
|
ptr = ensure(p, len + 1); |
|
|
|
if (!ptr) |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
if (child->next) |
|
|
|
{ |
|
|
|
*ptr++ = ','; |
|
|
|
} |
|
|
|
|
|
|
|
if (fmt) |
|
|
|
{ |
|
|
|
*ptr++ = '\n'; |
|
|
|
} |
|
|
|
*ptr = '\0'; |
|
|
|
p->offset += len; |
|
|
|
|
|
|
|
child = child->next; |
|
|
|
} |
|
|
|
|
|
|
|
ptr = ensure(p, fmt ? (depth + 1) : 2); |
|
|
|
if (!ptr) |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
if (fmt) |
|
|
|
{ |
|
|
|
for (i = 0; i < (depth - 1); i++) |
|
|
|
{ |
|
|
|
*ptr++ = '\t'; |
|
|
|
} |
|
|
|
} |
|
|
|
*ptr++ = '}'; |
|
|
|
*ptr = '\0'; |
|
|
|
out = (p->buffer) + i; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
/* 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++; |
|
|
|
if (fmt) |
|
|
|
{ |
|
|
|
len += depth; |
|
|
|
} |
|
|
|
while (child && !fail) |
|
|
|
{ |
|
|
|
names[i] = str = print_string_ptr(child->string, 0); /* print key */ |
|
|
|
entries[i++] = ret = print_value(child, depth, fmt, 0); |
|
|
|
if (str && ret) |
|
|
|
{ |
|
|
|
len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0); |
|
|
|
} |
|
|
|
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) |
|
|
|
{ |
|
|
|
/* free all the printed keys and values */ |
|
|
|
for (i = 0; i < numentries; i++) |
|
|
|
{ |
|
|
|
if (names[i]) |
|
|
|
{ |
|
|
|
cJSON_free(names[i]); |
|
|
|
} |
|
|
|
if (entries[i]) |
|
|
|
{ |
|
|
|
cJSON_free(entries[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
cJSON_free(names); |
|
|
|
cJSON_free(entries); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* Compose the output: */ |
|
|
|
*out = '{'; |
|
|
|
ptr = out + 1; |
|
|
|
if (fmt) |
|
|
|
{ |
|
|
|
*ptr++ = '\n'; |
|
|
|
} |
|
|
|
*ptr = 0; |
|
|
|
for (i = 0; i < numentries; i++) |
|
|
|
{ |
|
|
|
if (fmt) |
|
|
|
{ |
|
|
|
for (j = 0; j < depth; j++) |
|
|
|
{ |
|
|
|
*ptr++='\t'; |
|
|
|
} |
|
|
|
} |
|
|
|
tmplen = strlen(names[i]); |
|
|
|
memcpy(ptr, names[i], tmplen); |
|
|
|
ptr += tmplen; |
|
|
|
*ptr++ = ':'; |
|
|
|
if (fmt) |
|
|
|
{ |
|
|
|
*ptr++ = '\t'; |
|
|
|
} |
|
|
|
strcpy(ptr, entries[i]); |
|
|
|
ptr += strlen(entries[i]); |
|
|
|
if (i != (numentries - 1)) |
|
|
|
{ |
|
|
|
*ptr++ = ','; |
|
|
|
} |
|
|
|
if (fmt) |
|
|
|
{ |
|
|
|
*ptr++ = '\n'; |
|
|
|
} |
|
|
|
*ptr = 0; |
|
|
|
cJSON_free(names[i]); |
|
|
|
cJSON_free(entries[i]); |
|
|
|
} |
|
|
|
|
|
|
|
cJSON_free(names); |
|
|
|
cJSON_free(entries); |
|
|
|
if (fmt) |
|
|
|
{ |
|
|
|
for (i = 0; i < (depth - 1); i++) |
|
|
|
{ |
|
|
|
*ptr++ = '\t'; |
|
|
|
} |
|
|
|
} |
|
|
|
*ptr++ = '}'; |
|
|
|
*ptr++ = '\0'; |
|
|
|
} |
|
|
|
|
|
|
|
return out; |
|
|
|
} |
|
|
|
|
|
|
|
/* Get Array size/item / object item. */ |
|
|
|