summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Friloux <guillaume.friloux@gmail.com>2013-12-26 13:54:59 +0100
committerGuillaume Friloux <guillaume.friloux@gmail.com>2013-12-26 13:54:59 +0100
commit5ef188c4ba84603c808ea1b31c2ae5ef84f5aaf4 (patch)
tree22e809e74f4abf595bcd7ed72b36e21cf83582e4
parent82ce483a36849e86449e26344c66c3b71b70afce (diff)
Adding JSON library.
-rw-r--r--src/include/extras/cJSON.h127
-rw-r--r--src/lib/extras/cJSON.c514
2 files changed, 641 insertions, 0 deletions
diff --git a/src/include/extras/cJSON.h b/src/include/extras/cJSON.h
new file mode 100644
index 0000000..b7a6cd3
--- /dev/null
+++ b/src/include/extras/cJSON.h
@@ -0,0 +1,127 @@
1/*
2 Copyright (c) 2009 Dave Gamble
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21*/
22
23#ifndef cJSON__h
24#define cJSON__h
25
26#ifdef __cplusplus
27extern "C"
28{
29#endif
30
31/* cJSON Types: */
32#define cJSON_False 0
33#define cJSON_True 1
34#define cJSON_NULL 2
35#define cJSON_Number 3
36#define cJSON_String 4
37#define cJSON_Array 5
38#define cJSON_Object 6
39
40#define cJSON_IsReference 256
41
42/* The cJSON structure: */
43typedef struct cJSON {
44 struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
45 struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
46
47 int type; /* The type of the item, as above. */
48
49 char *valuestring; /* The item's string, if type==cJSON_String */
50 int valueint; /* The item's number, if type==cJSON_Number */
51 double valuedouble; /* The item's number, if type==cJSON_Number */
52
53 char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
54} cJSON;
55
56typedef struct cJSON_Hooks {
57 void *(*malloc_fn)(size_t sz);
58 void (*free_fn)(void *ptr);
59} cJSON_Hooks;
60
61/* Supply malloc, realloc and free functions to cJSON */
62extern void cJSON_InitHooks(cJSON_Hooks* hooks);
63
64
65/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
66extern cJSON *cJSON_Parse(const char *value);
67/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
68extern char *cJSON_Print(cJSON *item);
69/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
70extern char *cJSON_PrintUnformatted(cJSON *item);
71/* Delete a cJSON entity and all subentities. */
72extern void cJSON_Delete(cJSON *c);
73
74/* Returns the number of items in an array (or object). */
75extern int cJSON_GetArraySize(cJSON *array);
76/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
77extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
78/* Get item "string" from object. Case insensitive. */
79extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
80
81/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
82extern const char *cJSON_GetErrorPtr();
83
84/* These calls create a cJSON item of the appropriate type. */
85extern cJSON *cJSON_CreateNull();
86extern cJSON *cJSON_CreateTrue();
87extern cJSON *cJSON_CreateFalse();
88extern cJSON *cJSON_CreateBool(int b);
89extern cJSON *cJSON_CreateNumber(double num);
90extern cJSON *cJSON_CreateString(const char *string);
91extern cJSON *cJSON_CreateArray();
92extern cJSON *cJSON_CreateObject();
93
94/* These utilities create an Array of count items. */
95extern cJSON *cJSON_CreateIntArray(int *numbers,int count);
96extern cJSON *cJSON_CreateFloatArray(float *numbers,int count);
97extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count);
98extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
99
100/* Append item to the specified array/object. */
101extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
102extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
103/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
104extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
105extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
106
107/* Remove/Detatch items from Arrays/Objects. */
108extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
109extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
110extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
111extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
112
113/* Update array items. */
114extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
115extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
116
117#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
118#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
119#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
120#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
121#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
122
123#ifdef __cplusplus
124}
125#endif
126
127#endif
diff --git a/src/lib/extras/cJSON.c b/src/lib/extras/cJSON.c
new file mode 100644
index 0000000..eb7c2f9
--- /dev/null
+++ b/src/lib/extras/cJSON.c
@@ -0,0 +1,514 @@
1/*
2 Copyright (c) 2009 Dave Gamble
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21*/
22
23/* cJSON */
24/* JSON parser in C. */
25
26#include <string.h>
27#include <stdio.h>
28#include <math.h>
29#include <stdlib.h>
30#include <float.h>
31#include <limits.h>
32#include <ctype.h>
33#include "cJSON.h"
34
35static const char *ep;
36
37const char *cJSON_GetErrorPtr() {return ep;}
38
39static int cJSON_strcasecmp(const char *s1,const char *s2)
40{
41 if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
42 for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
43 return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
44}
45
46static void *(*cJSON_malloc)(size_t sz) = malloc;
47static void (*cJSON_free)(void *ptr) = free;
48
49static char* cJSON_strdup(const char* str)
50{
51 size_t len;
52 char* copy;
53
54 len = strlen(str) + 1;
55 if (!(copy = (char*)cJSON_malloc(len))) return 0;
56 memcpy(copy,str,len);
57 return copy;
58}
59
60void cJSON_InitHooks(cJSON_Hooks* hooks)
61{
62 if (!hooks) { /* Reset hooks */
63 cJSON_malloc = malloc;
64 cJSON_free = free;
65 return;
66 }
67
68 cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
69 cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
70}
71
72/* Internal constructor. */
73static cJSON *cJSON_New_Item()
74{
75 cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
76 if (node) memset(node,0,sizeof(cJSON));
77 return node;
78}
79
80/* Delete a cJSON structure. */
81void cJSON_Delete(cJSON *c)
82{
83 cJSON *next;
84 while (c)
85 {
86 next=c->next;
87 if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
88 if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
89 if (c->string) cJSON_free(c->string);
90 cJSON_free(c);
91 c=next;
92 }
93}
94
95/* Parse the input text to generate a number, and populate the result into item. */
96static const char *parse_number(cJSON *item,const char *num)
97{
98 double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
99
100 /* Could use sscanf for this? */
101 if (*num=='-') sign=-1,num++; /* Has sign? */
102 if (*num=='0') num++; /* is zero */
103 if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
104 if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
105 if (*num=='e' || *num=='E') /* Exponent? */
106 { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
107 while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
108 }
109
110 n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
111
112 item->valuedouble=n;
113 item->valueint=(int)n;
114 item->type=cJSON_Number;
115 return num;
116}
117
118/* Render the number nicely from the given item into a string. */
119static char *print_number(cJSON *item)
120{
121 char *str;
122 double d=item->valuedouble;
123 if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
124 {
125 str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
126 if (str) sprintf(str,"%d",item->valueint);
127 }
128 else
129 {
130 str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
131 if (str)
132 {
133 if (fabs(floor(d)-d)<=DBL_EPSILON) sprintf(str,"%.0f",d);
134 else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
135 else sprintf(str,"%f",d);
136 }
137 }
138 return str;
139}
140
141/* Parse the input text into an unescaped cstring, and populate item. */
142static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
143static const char *parse_string(cJSON *item,const char *str)
144{
145 const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
146 if (*str!='\"') {ep=str;return 0;} /* not a string! */
147
148 while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
149
150 out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
151 if (!out) return 0;
152
153 ptr=str+1;ptr2=out;
154 while (*ptr!='\"' && *ptr)
155 {
156 if (*ptr!='\\') *ptr2++=*ptr++;
157 else
158 {
159 ptr++;
160 switch (*ptr)
161 {
162 case 'b': *ptr2++='\b'; break;
163 case 'f': *ptr2++='\f'; break;
164 case 'n': *ptr2++='\n'; break;
165 case 'r': *ptr2++='\r'; break;
166 case 't': *ptr2++='\t'; break;
167 case 'u': /* transcode utf16 to utf8. */
168 sscanf(ptr+1,"%4x",&uc);ptr+=4; /* get the unicode char. */
169
170 if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid.
171
172 if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs.
173 {
174 if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate.
175 sscanf(ptr+3,"%4x",&uc2);ptr+=6;
176 if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate.
177 uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF);
178 }
179
180 len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
181
182 switch (len) {
183 case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
184 case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
185 case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
186 case 1: *--ptr2 =(uc | firstByteMark[len]);
187 }
188 ptr2+=len;
189 break;
190 default: *ptr2++=*ptr; break;
191 }
192 ptr++;
193 }
194 }
195 *ptr2=0;
196 if (*ptr=='\"') ptr++;
197 item->valuestring=out;
198 item->type=cJSON_String;
199 return ptr;
200}
201
202/* Render the cstring provided to an escaped version that can be printed. */
203static char *print_string_ptr(const char *str)
204{
205 const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
206
207 if (!str) return cJSON_strdup("");
208 ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
209
210 out=(char*)cJSON_malloc(len+3);
211 if (!out) return 0;
212
213 ptr2=out;ptr=str;
214 *ptr2++='\"';
215 while (*ptr)
216 {
217 if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
218 else
219 {
220 *ptr2++='\\';
221 switch (token=*ptr++)
222 {
223 case '\\': *ptr2++='\\'; break;
224 case '\"': *ptr2++='\"'; break;
225 case '\b': *ptr2++='b'; break;
226 case '\f': *ptr2++='f'; break;
227 case '\n': *ptr2++='n'; break;
228 case '\r': *ptr2++='r'; break;
229 case '\t': *ptr2++='t'; break;
230 default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
231 }
232 }
233 }
234 *ptr2++='\"';*ptr2++=0;
235 return out;
236}
237/* Invote print_string_ptr (which is useful) on an item. */
238static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
239
240/* Predeclare these prototypes. */
241static const char *parse_value(cJSON *item,const char *value);
242static char *print_value(cJSON *item,int depth,int fmt);
243static const char *parse_array(cJSON *item,const char *value);
244static char *print_array(cJSON *item,int depth,int fmt);
245static const char *parse_object(cJSON *item,const char *value);
246static char *print_object(cJSON *item,int depth,int fmt);
247
248/* Utility to jump whitespace and cr/lf */
249static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
250
251/* Parse an object - create a new root, and populate. */
252cJSON *cJSON_Parse(const char *value)
253{
254 cJSON *c=cJSON_New_Item();
255 ep=0;
256 if (!c) return 0; /* memory fail */
257
258 if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;}
259 return c;
260}
261
262/* Render a cJSON item/entity/structure to text. */
263char *cJSON_Print(cJSON *item) {return print_value(item,0,1);}
264char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);}
265
266/* Parser core - when encountering text, process appropriately. */
267static const char *parse_value(cJSON *item,const char *value)
268{
269 if (!value) return 0; /* Fail on null. */
270 if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
271 if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
272 if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
273 if (*value=='\"') { return parse_string(item,value); }
274 if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
275 if (*value=='[') { return parse_array(item,value); }
276 if (*value=='{') { return parse_object(item,value); }
277
278 ep=value;return 0; /* failure. */
279}
280
281/* Render a value to text. */
282static char *print_value(cJSON *item,int depth,int fmt)
283{
284 char *out=0;
285 if (!item) return 0;
286 switch ((item->type)&255)
287 {
288 case cJSON_NULL: out=cJSON_strdup("null"); break;
289 case cJSON_False: out=cJSON_strdup("false");break;
290 case cJSON_True: out=cJSON_strdup("true"); break;
291 case cJSON_Number: out=print_number(item);break;
292 case cJSON_String: out=print_string(item);break;
293 case cJSON_Array: out=print_array(item,depth,fmt);break;
294 case cJSON_Object: out=print_object(item,depth,fmt);break;
295 }
296 return out;
297}
298
299/* Build an array from input text. */
300static const char *parse_array(cJSON *item,const char *value)
301{
302 cJSON *child;
303 if (*value!='[') {ep=value;return 0;} /* not an array! */
304
305 item->type=cJSON_Array;
306 value=skip(value+1);
307 if (*value==']') return value+1; /* empty array. */
308
309 item->child=child=cJSON_New_Item();
310 if (!item->child) return 0; /* memory fail */
311 value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
312 if (!value) return 0;
313
314 while (*value==',')
315 {
316 cJSON *new_item;
317 if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
318 child->next=new_item;new_item->prev=child;child=new_item;
319 value=skip(parse_value(child,skip(value+1)));
320 if (!value) return 0; /* memory fail */
321 }
322
323 if (*value==']') return value+1; /* end of array */
324 ep=value;return 0; /* malformed. */
325}
326
327/* Render an array to text */
328static char *print_array(cJSON *item,int depth,int fmt)
329{
330 char **entries;
331 char *out=0,*ptr,*ret;int len=5;
332 cJSON *child=item->child;
333 int numentries=0,i=0,fail=0;
334
335 /* How many entries in the array? */
336 while (child) numentries++,child=child->next;
337 /* Allocate an array to hold the values for each */
338 entries=(char**)cJSON_malloc(numentries*sizeof(char*));
339 if (!entries) return 0;
340 memset(entries,0,numentries*sizeof(char*));
341 /* Retrieve all the results: */
342 child=item->child;
343 while (child && !fail)
344 {
345 ret=print_value(child,depth+1,fmt);
346 entries[i++]=ret;
347 if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
348 child=child->next;
349 }
350
351 /* If we didn't fail, try to malloc the output string */
352 if (!fail) out=(char*)cJSON_malloc(len);
353 /* If that fails, we fail. */
354 if (!out) fail=1;
355
356 /* Handle failure. */
357 if (fail)
358 {
359 for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
360 cJSON_free(entries);
361 return 0;
362 }
363
364 /* Compose the output array. */
365 *out='[';
366 ptr=out+1;*ptr=0;
367 for (i=0;i<numentries;i++)
368 {
369 strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
370 if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
371 cJSON_free(entries[i]);
372 }
373 cJSON_free(entries);
374 *ptr++=']';*ptr++=0;
375 return out;
376}
377
378/* Build an object from the text. */
379static const char *parse_object(cJSON *item,const char *value)
380{
381 cJSON *child;
382 if (*value!='{') {ep=value;return 0;} /* not an object! */
383
384 item->type=cJSON_Object;
385 value=skip(value+1);
386 if (*value=='}') return value+1; /* empty array. */
387
388 item->child=child=cJSON_New_Item();
389 if (!item->child) return 0;
390 value=skip(parse_string(child,skip(value)));
391 if (!value) return 0;
392 child->string=child->valuestring;child->valuestring=0;
393 if (*value!=':') {ep=value;return 0;} /* fail! */
394 value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
395 if (!value) return 0;
396
397 while (*value==',')
398 {
399 cJSON *new_item;
400 if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
401 child->next=new_item;new_item->prev=child;child=new_item;
402 value=skip(parse_string(child,skip(value+1)));
403 if (!value) return 0;
404 child->string=child->valuestring;child->valuestring=0;
405 if (*value!=':') {ep=value;return 0;} /* fail! */
406 value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
407 if (!value) return 0;
408 }
409
410 if (*value=='}') return value+1; /* end of array */
411 ep=value;return 0; /* malformed. */
412}
413
414/* Render an object to text. */
415static char *print_object(cJSON *item,int depth,int fmt)
416{
417 char **entries=0,**names=0;
418 char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
419 cJSON *child=item->child;
420 int numentries=0,fail=0;
421 /* Count the number of entries. */
422 while (child) numentries++,child=child->next;
423 /* Allocate space for the names and the objects */
424 entries=(char**)cJSON_malloc(numentries*sizeof(char*));
425 if (!entries) return 0;
426 names=(char**)cJSON_malloc(numentries*sizeof(char*));
427 if (!names) {cJSON_free(entries);return 0;}
428 memset(entries,0,sizeof(char*)*numentries);
429 memset(names,0,sizeof(char*)*numentries);
430
431 /* Collect all the results into our arrays: */
432 child=item->child;depth++;if (fmt) len+=depth;
433 while (child)
434 {
435 names[i]=str=print_string_ptr(child->string);
436 entries[i++]=ret=print_value(child,depth,fmt);
437 if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
438 child=child->next;
439 }
440
441 /* Try to allocate the output string */
442 if (!fail) out=(char*)cJSON_malloc(len);
443 if (!out) fail=1;
444
445 /* Handle failure */
446 if (fail)
447 {
448 for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
449 cJSON_free(names);cJSON_free(entries);
450 return 0;
451 }
452
453 /* Compose the output: */
454 *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
455 for (i=0;i<numentries;i++)
456 {
457 if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
458 strcpy(ptr,names[i]);ptr+=strlen(names[i]);
459 *ptr++=':';if (fmt) *ptr++='\t';
460 strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
461 if (i!=numentries-1) *ptr++=',';
462 if (fmt) *ptr++='\n';*ptr=0;
463 cJSON_free(names[i]);cJSON_free(entries[i]);
464 }
465
466 cJSON_free(names);cJSON_free(entries);
467 if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
468 *ptr++='}';*ptr++=0;
469 return out;
470}
471
472/* Get Array size/item / object item. */
473int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
474cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
475cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
476
477/* Utility for array list handling. */
478static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
479/* Utility for handling references. */
480static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
481
482/* Add item to array/object. */
483void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
484void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
485void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
486void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
487
488cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
489 if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
490void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
491cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
492void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
493
494/* Replace array/object items with new ones. */
495void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
496 newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
497 if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
498void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
499
500/* Create basic types: */
501cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
502cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
503cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
504cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
505cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
506cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
507cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
508cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
509
510/* Create Arrays: */
511cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
512cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
513cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
514cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}