diff options
author | Guillaume Friloux <guillaume.friloux@gmail.com> | 2013-12-26 13:54:59 +0100 |
---|---|---|
committer | Guillaume Friloux <guillaume.friloux@gmail.com> | 2013-12-26 13:54:59 +0100 |
commit | 5ef188c4ba84603c808ea1b31c2ae5ef84f5aaf4 (patch) | |
tree | 22e809e74f4abf595bcd7ed72b36e21cf83582e4 /src | |
parent | 82ce483a36849e86449e26344c66c3b71b70afce (diff) |
Adding JSON library.
Diffstat (limited to 'src')
-rw-r--r-- | src/include/extras/cJSON.h | 127 | ||||
-rw-r--r-- | src/lib/extras/cJSON.c | 514 |
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 | ||
27 | extern "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: */ | ||
43 | typedef 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 | |||
56 | typedef 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 */ | ||
62 | extern 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. */ | ||
66 | extern cJSON *cJSON_Parse(const char *value); | ||
67 | /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ | ||
68 | extern char *cJSON_Print(cJSON *item); | ||
69 | /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ | ||
70 | extern char *cJSON_PrintUnformatted(cJSON *item); | ||
71 | /* Delete a cJSON entity and all subentities. */ | ||
72 | extern void cJSON_Delete(cJSON *c); | ||
73 | |||
74 | /* Returns the number of items in an array (or object). */ | ||
75 | extern int cJSON_GetArraySize(cJSON *array); | ||
76 | /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ | ||
77 | extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); | ||
78 | /* Get item "string" from object. Case insensitive. */ | ||
79 | extern 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. */ | ||
82 | extern const char *cJSON_GetErrorPtr(); | ||
83 | |||
84 | /* These calls create a cJSON item of the appropriate type. */ | ||
85 | extern cJSON *cJSON_CreateNull(); | ||
86 | extern cJSON *cJSON_CreateTrue(); | ||
87 | extern cJSON *cJSON_CreateFalse(); | ||
88 | extern cJSON *cJSON_CreateBool(int b); | ||
89 | extern cJSON *cJSON_CreateNumber(double num); | ||
90 | extern cJSON *cJSON_CreateString(const char *string); | ||
91 | extern cJSON *cJSON_CreateArray(); | ||
92 | extern cJSON *cJSON_CreateObject(); | ||
93 | |||
94 | /* These utilities create an Array of count items. */ | ||
95 | extern cJSON *cJSON_CreateIntArray(int *numbers,int count); | ||
96 | extern cJSON *cJSON_CreateFloatArray(float *numbers,int count); | ||
97 | extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); | ||
98 | extern cJSON *cJSON_CreateStringArray(const char **strings,int count); | ||
99 | |||
100 | /* Append item to the specified array/object. */ | ||
101 | extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); | ||
102 | extern 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. */ | ||
104 | extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); | ||
105 | extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); | ||
106 | |||
107 | /* Remove/Detatch items from Arrays/Objects. */ | ||
108 | extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); | ||
109 | extern void cJSON_DeleteItemFromArray(cJSON *array,int which); | ||
110 | extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); | ||
111 | extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); | ||
112 | |||
113 | /* Update array items. */ | ||
114 | extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); | ||
115 | extern 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 | |||
35 | static const char *ep; | ||
36 | |||
37 | const char *cJSON_GetErrorPtr() {return ep;} | ||
38 | |||
39 | static 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 | |||
46 | static void *(*cJSON_malloc)(size_t sz) = malloc; | ||
47 | static void (*cJSON_free)(void *ptr) = free; | ||
48 | |||
49 | static 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 | |||
60 | void 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. */ | ||
73 | static 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. */ | ||
81 | void 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. */ | ||
96 | static 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. */ | ||
119 | static 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. */ | ||
142 | static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; | ||
143 | static 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. */ | ||
203 | static 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. */ | ||
238 | static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} | ||
239 | |||
240 | /* Predeclare these prototypes. */ | ||
241 | static const char *parse_value(cJSON *item,const char *value); | ||
242 | static char *print_value(cJSON *item,int depth,int fmt); | ||
243 | static const char *parse_array(cJSON *item,const char *value); | ||
244 | static char *print_array(cJSON *item,int depth,int fmt); | ||
245 | static const char *parse_object(cJSON *item,const char *value); | ||
246 | static char *print_object(cJSON *item,int depth,int fmt); | ||
247 | |||
248 | /* Utility to jump whitespace and cr/lf */ | ||
249 | static 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. */ | ||
252 | cJSON *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. */ | ||
263 | char *cJSON_Print(cJSON *item) {return print_value(item,0,1);} | ||
264 | char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} | ||
265 | |||
266 | /* Parser core - when encountering text, process appropriately. */ | ||
267 | static 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. */ | ||
282 | static 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. */ | ||
300 | static 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 */ | ||
328 | static 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. */ | ||
379 | static 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. */ | ||
415 | static 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. */ | ||
473 | int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;} | ||
474 | cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} | ||
475 | cJSON *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. */ | ||
478 | static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} | ||
479 | /* Utility for handling references. */ | ||
480 | static 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. */ | ||
483 | void 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);}} | ||
484 | void 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);} | ||
485 | void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} | ||
486 | void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} | ||
487 | |||
488 | cJSON *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;} | ||
490 | void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} | ||
491 | cJSON *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;} | ||
492 | void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} | ||
493 | |||
494 | /* Replace array/object items with new ones. */ | ||
495 | void 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);} | ||
498 | void 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: */ | ||
501 | cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} | ||
502 | cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} | ||
503 | cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} | ||
504 | cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} | ||
505 | cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} | ||
506 | cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} | ||
507 | cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} | ||
508 | cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} | ||
509 | |||
510 | /* Create Arrays: */ | ||
511 | cJSON *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;} | ||
512 | cJSON *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;} | ||
513 | cJSON *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;} | ||
514 | cJSON *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;} | ||