]>
Commit | Line | Data |
---|---|---|
3a2b2b45 | 1 | |
2 | /* | |
3 | Copyright (c) 2009 Dave Gamble | |
4 | ||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
6 | of this software and associated documentation files (the "Software"), to deal | |
7 | in the Software without restriction, including without limitation the rights | |
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
9 | copies of the Software, and to permit persons to whom the Software is | |
10 | furnished to do so, subject to the following conditions: | |
11 | ||
12 | The above copyright notice and this permission notice shall be included in | |
13 | all copies or substantial portions of the Software. | |
14 | ||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
21 | THE SOFTWARE. | |
22 | */ | |
23 | ||
24 | /* cJSON */ | |
25 | /* JSON parser in C. */ | |
26 | #include <math.h> | |
27 | ||
c23b9ce3 | 28 | #include "cJSON.h" |
3a2b2b45 | 29 | |
30 | #ifndef DBL_EPSILON | |
31 | #define DBL_EPSILON 2.2204460492503131E-16 | |
32 | #endif | |
33 | ||
34 | static const char *ep; | |
35 | ||
36 | long stripquotes(char *str) | |
37 | { | |
38 | long len,offset; | |
39 | if ( str == 0 ) | |
40 | return(0); | |
41 | len = strlen(str); | |
42 | if ( str[0] == '"' && str[len-1] == '"' ) | |
43 | str[len-1] = 0, offset = 1; | |
44 | else offset = 0; | |
45 | return(offset); | |
46 | } | |
47 | ||
48 | const char *cJSON_GetErrorPtr(void) {return ep;} | |
49 | ||
50 | static int32_t cJSON_strcasecmp(const char *s1,const char *s2) | |
51 | { | |
52 | if (!s1) return (s1==s2)?0:1;if (!s2) return 1; | |
53 | for(; tolower((int32_t)(*s1)) == tolower((int32_t)(*s2)); ++s1, ++s2) if(*s1 == 0) return 0; | |
54 | return tolower((int32_t)(*(const unsigned char *)s1)) - tolower((int32_t)(*(const unsigned char *)s2)); | |
55 | } | |
56 | ||
57 | static void *(*cJSON_malloc)(size_t sz) = malloc; | |
58 | static void (*cJSON_free)(void *ptr) = free; | |
59 | ||
60 | static char* cJSON_strdup(const char* str) | |
61 | { | |
62 | size_t len; | |
63 | char* copy; | |
64 | ||
65 | len = strlen(str) + 1; | |
66 | if (!(copy = (char*)cJSON_malloc(len+1))) return 0; | |
67 | memcpy(copy,str,len); | |
68 | return copy; | |
69 | } | |
70 | ||
71 | void cJSON_InitHooks(cJSON_Hooks* hooks) | |
72 | { | |
73 | if (!hooks) { /* Reset hooks */ | |
74 | cJSON_malloc = malloc; | |
75 | cJSON_free = free; | |
76 | return; | |
77 | } | |
78 | ||
79 | cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; | |
80 | cJSON_free = (hooks->free_fn)?hooks->free_fn:free; | |
81 | } | |
82 | ||
83 | /* Internal constructor. */ | |
84 | static cJSON *cJSON_New_Item(void) | |
85 | { | |
86 | cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); | |
87 | if (node) memset(node,0,sizeof(cJSON)); | |
88 | return node; | |
89 | } | |
90 | ||
91 | /* Delete a cJSON structure. */ | |
92 | void cJSON_Delete(cJSON *c) | |
93 | { | |
94 | cJSON *next; | |
95 | while (c) | |
96 | { | |
97 | next=c->next; | |
98 | if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); | |
99 | if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); | |
100 | if (c->string) cJSON_free(c->string); | |
101 | cJSON_free(c); | |
102 | c=next; | |
103 | } | |
104 | } | |
105 | ||
106 | /* Parse the input text to generate a number, and populate the result into item. */ | |
107 | static const char *parse_number(cJSON *item,const char *num) | |
108 | { | |
109 | double n=0,sign=1,scale=0;int32_t subscale=0,signsubscale=1; | |
110 | ||
111 | if (*num=='-') sign=-1,num++; /* Has sign? */ | |
112 | if (*num=='0') num++; /* is zero */ | |
113 | if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ | |
114 | if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ | |
115 | if (*num=='e' || *num=='E') /* Exponent? */ | |
116 | { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ | |
117 | while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ | |
118 | } | |
119 | ||
120 | n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ | |
121 | ||
122 | item->valuedouble=n; | |
123 | item->valueint=(int64_t)n; | |
124 | item->type=cJSON_Number; | |
125 | return num; | |
126 | } | |
127 | ||
128 | /* Render the number nicely from the given item into a string. */ | |
129 | static char *print_number(cJSON *item) | |
130 | { | |
131 | char *str; | |
132 | double d = item->valuedouble; | |
133 | if ( fabs(((double)item->valueint) - d) <= DBL_EPSILON && d >= (1. - DBL_EPSILON) && d < (1LL << 62) )//d <= INT_MAX && d >= INT_MIN ) | |
134 | { | |
135 | str = (char *)cJSON_malloc(24); /* 2^64+1 can be represented in 21 chars + sign. */ | |
136 | if ( str != 0 ) | |
137 | sprintf(str,"%lld",(long long)item->valueint); | |
138 | } | |
139 | else | |
140 | { | |
141 | str = (char *)cJSON_malloc(66); /* This is a nice tradeoff. */ | |
142 | if ( str != 0 ) | |
143 | { | |
144 | if ( fabs(floor(d) - d) <= DBL_EPSILON && fabs(d) < 1.0e60 ) | |
145 | sprintf(str,"%.0f",d); | |
146 | //else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); | |
147 | else | |
148 | sprintf(str,"%.8f",d); | |
149 | } | |
150 | } | |
151 | return str; | |
152 | } | |
153 | ||
154 | static unsigned parse_hex4(const char *str) | |
155 | { | |
156 | unsigned h=0; | |
157 | if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; | |
158 | h=h<<4;str++; | |
159 | if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; | |
160 | h=h<<4;str++; | |
161 | if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; | |
162 | h=h<<4;str++; | |
163 | if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; | |
164 | return h; | |
165 | } | |
166 | ||
167 | /* Parse the input text into an unescaped cstring, and populate item. */ | |
168 | static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; | |
169 | static const char *parse_string(cJSON *item,const char *str) | |
170 | { | |
171 | const char *ptr=str+1;char *ptr2;char *out;int32_t len=0;unsigned uc,uc2; | |
172 | if (*str!='\"') {ep=str;return 0;} /* not a string! */ | |
173 | ||
174 | while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes | |
175 | ||
176 | out=(char*)cJSON_malloc(len+2); /* This is how long we need for the string, roughly. */ | |
177 | if (!out) return 0; | |
178 | ||
179 | ptr=str+1;ptr2=out; | |
180 | while (*ptr!='\"' && *ptr) | |
181 | { | |
182 | if (*ptr!='\\') | |
183 | { | |
184 | if ( *ptr == '%' && is_hexstr((char *)&ptr[1],2) && isprint(_decode_hex((char *)&ptr[1])) != 0 ) | |
185 | *ptr2++ = _decode_hex((char *)&ptr[1]), ptr += 3; | |
186 | else *ptr2++ = *ptr++; | |
187 | } | |
188 | else | |
189 | { | |
190 | ptr++; | |
191 | switch (*ptr) | |
192 | { | |
193 | case 'b': *ptr2++='\b'; break; | |
194 | case 'f': *ptr2++='\f'; break; | |
195 | case 'n': *ptr2++='\n'; break; | |
196 | case 'r': *ptr2++='\r'; break; | |
197 | case 't': *ptr2++='\t'; break; | |
198 | case 'u': // transcode utf16 to utf8 | |
199 | uc=parse_hex4(ptr+1);ptr+=4; // get the unicode char | |
200 | ||
201 | if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid | |
202 | ||
203 | if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs | |
204 | { | |
205 | if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate. | |
206 | uc2=parse_hex4(ptr+3);ptr+=6; | |
207 | if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate | |
208 | uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); | |
209 | } | |
210 | ||
211 | len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; | |
212 | ||
213 | switch (len) { | |
214 | case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | |
215 | case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | |
216 | case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | |
217 | case 1: *--ptr2 =(uc | firstByteMark[len]); | |
218 | } | |
219 | ptr2+=len; | |
220 | break; | |
221 | default: *ptr2++=*ptr; break; | |
222 | } | |
223 | ptr++; | |
224 | } | |
225 | } | |
226 | *ptr2=0; | |
227 | if (*ptr=='\"') ptr++; | |
228 | item->valuestring=out; | |
229 | item->type=cJSON_String; | |
230 | return ptr; | |
231 | } | |
232 | ||
233 | /* Render the cstring provided to an escaped version that can be printed. */ | |
234 | static char *print_string_ptr(const char *str) | |
235 | { | |
236 | const char *ptr;char *ptr2,*out;int32_t len=0;unsigned char token; | |
237 | ||
238 | if (!str) return cJSON_strdup(""); | |
239 | ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} | |
240 | ||
241 | out=(char*)cJSON_malloc(len+3+1); | |
242 | if (!out) return 0; | |
243 | ||
244 | ptr2=out;ptr=str; | |
245 | *ptr2++='\"'; | |
246 | while (*ptr) | |
247 | { | |
248 | if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; | |
249 | else | |
250 | { | |
251 | *ptr2++='\\'; | |
252 | switch (token=*ptr++) | |
253 | { | |
254 | case '\\': *ptr2++='\\'; break; | |
255 | case '\"': *ptr2++='\"'; break; | |
256 | case '\b': *ptr2++='b'; break; | |
257 | case '\f': *ptr2++='f'; break; | |
258 | case '\n': *ptr2++='n'; break; | |
259 | case '\r': *ptr2++='r'; break; | |
260 | case '\t': *ptr2++='t'; break; | |
261 | default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ | |
262 | } | |
263 | } | |
264 | } | |
265 | *ptr2++='\"';*ptr2++=0; | |
266 | return out; | |
267 | } | |
268 | /* Invote print_string_ptr (which is useful) on an item. */ | |
269 | static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} | |
270 | ||
271 | /* Predeclare these prototypes. */ | |
272 | static const char *parse_value(cJSON *item,const char *value); | |
273 | static char *print_value(cJSON *item,int32_t depth,int32_t fmt); | |
274 | static const char *parse_array(cJSON *item,const char *value); | |
275 | static char *print_array(cJSON *item,int32_t depth,int32_t fmt); | |
276 | static const char *parse_object(cJSON *item,const char *value); | |
277 | static char *print_object(cJSON *item,int32_t depth,int32_t fmt); | |
278 | ||
279 | /* Utility to jump whitespace and cr/lf */ | |
280 | static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} | |
281 | ||
282 | /* Parse an object - create a new root, and populate. */ | |
283 | cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int32_t require_null_terminated) | |
284 | { | |
285 | const char *end=0; | |
286 | cJSON *c=cJSON_New_Item(); | |
287 | ep=0; | |
288 | if (!c) return 0; /* memory fail */ | |
289 | ||
290 | end=parse_value(c,skip(value)); | |
291 | if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ | |
292 | ||
293 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ | |
294 | if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} | |
295 | if (return_parse_end) *return_parse_end=end; | |
296 | return c; | |
297 | } | |
298 | /* Default options for cJSON_Parse */ | |
299 | cJSON *cJSON_Parse(const char *value) | |
300 | { | |
301 | return(cJSON_ParseWithOpts(value,0,0)); | |
302 | } | |
303 | ||
304 | /* Render a cJSON item/entity/structure to text. */ | |
305 | char *cJSON_Print(cJSON *item) | |
306 | { | |
307 | return(print_value(item,0,1)); | |
308 | } | |
309 | char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} | |
310 | ||
311 | /* Parser core - when encountering text, process appropriately. */ | |
312 | static const char *parse_value(cJSON *item,const char *value) | |
313 | { | |
314 | if (!value) return 0; /* Fail on null. */ | |
315 | if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } | |
316 | if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } | |
317 | if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } | |
318 | if (*value=='\"') { return parse_string(item,value); } | |
319 | if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } | |
320 | if (*value=='[') { return parse_array(item,value); } | |
321 | if (*value=='{') { return parse_object(item,value); } | |
322 | ||
323 | ep=value;return 0; /* failure. */ | |
324 | } | |
325 | ||
326 | /* Render a value to text. */ | |
327 | static char *print_value(cJSON *item,int32_t depth,int32_t fmt) | |
328 | { | |
329 | char *out=0; | |
330 | if (!item) return 0; | |
331 | switch ((item->type)&255) | |
332 | { | |
333 | case cJSON_NULL: out=cJSON_strdup("null"); break; | |
334 | case cJSON_False: out=cJSON_strdup("false");break; | |
335 | case cJSON_True: out=cJSON_strdup("true"); break; | |
336 | case cJSON_Number: out=print_number(item);break; | |
337 | case cJSON_String: out=print_string(item);break; | |
338 | case cJSON_Array: out=print_array(item,depth,fmt);break; | |
339 | case cJSON_Object: out=print_object(item,depth,fmt);break; | |
340 | } | |
341 | return out; | |
342 | } | |
343 | ||
344 | /* Build an array from input text. */ | |
345 | static const char *parse_array(cJSON *item,const char *value) | |
346 | { | |
347 | cJSON *child; | |
348 | if (*value!='[') {ep=value;return 0;} /* not an array! */ | |
349 | ||
350 | item->type=cJSON_Array; | |
351 | value=skip(value+1); | |
352 | if (*value==']') return value+1; /* empty array. */ | |
353 | ||
354 | item->child=child=cJSON_New_Item(); | |
355 | if (!item->child) return 0; /* memory fail */ | |
356 | value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ | |
357 | if (!value) return 0; | |
358 | ||
359 | while (*value==',') | |
360 | { | |
361 | cJSON *new_item; | |
362 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ | |
363 | child->next=new_item;new_item->prev=child;child=new_item; | |
364 | value=skip(parse_value(child,skip(value+1))); | |
365 | if (!value) return 0; /* memory fail */ | |
366 | } | |
367 | ||
368 | if (*value==']') return value+1; /* end of array */ | |
369 | ep=value;return 0; /* malformed. */ | |
370 | } | |
371 | ||
372 | /* Render an array to text */ | |
373 | static char *print_array(cJSON *item,int32_t depth,int32_t fmt) | |
374 | { | |
375 | char **entries; | |
376 | char *out=0,*ptr,*ret;int32_t len=5; | |
377 | cJSON *child=item->child; | |
378 | int32_t numentries=0,i=0,fail=0; | |
379 | ||
380 | /* How many entries in the array? */ | |
381 | while (child) numentries++,child=child->next; | |
382 | /* Explicitly handle numentries==0 */ | |
383 | if (!numentries) | |
384 | { | |
385 | out=(char*)cJSON_malloc(3+1); | |
386 | if (out) strcpy(out,"[]"); | |
387 | return out; | |
388 | } | |
389 | /* Allocate an array to hold the values for each */ | |
390 | entries=(char**)cJSON_malloc((1+numentries)*sizeof(char*)); | |
391 | if (!entries) return 0; | |
392 | memset(entries,0,numentries*sizeof(char*)); | |
393 | /* Retrieve all the results: */ | |
394 | child=item->child; | |
395 | while (child && !fail) | |
396 | { | |
397 | ret=print_value(child,depth+1,fmt); | |
398 | entries[i++]=ret; | |
399 | if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; | |
400 | child=child->next; | |
401 | } | |
402 | ||
403 | /* If we didn't fail, try to malloc the output string */ | |
404 | if (!fail) out=(char*)cJSON_malloc(len+1); | |
405 | /* If that fails, we fail. */ | |
406 | if (!out) fail=1; | |
407 | ||
408 | /* Handle failure. */ | |
409 | if (fail) | |
410 | { | |
411 | for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]); | |
412 | cJSON_free(entries); | |
413 | return 0; | |
414 | } | |
415 | ||
416 | /* Compose the output array. */ | |
417 | *out='['; | |
418 | ptr=out+1;*ptr=0; | |
419 | for (i=0;i<numentries;i++) | |
420 | { | |
421 | strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); | |
422 | if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;} | |
423 | cJSON_free(entries[i]); | |
424 | } | |
425 | cJSON_free(entries); | |
426 | *ptr++=']';*ptr++=0; | |
427 | return out; | |
428 | } | |
429 | ||
430 | /* Build an object from the text. */ | |
431 | static const char *parse_object(cJSON *item,const char *value) | |
432 | { | |
433 | cJSON *child; | |
434 | if (*value!='{') {ep=value;return 0;} /* not an object! */ | |
435 | ||
436 | item->type=cJSON_Object; | |
437 | value=skip(value+1); | |
438 | if (*value=='}') return value+1; /* empty array. */ | |
439 | ||
440 | item->child=child=cJSON_New_Item(); | |
441 | if (!item->child) return 0; | |
442 | value=skip(parse_string(child,skip(value))); | |
443 | if (!value) return 0; | |
444 | child->string=child->valuestring;child->valuestring=0; | |
445 | if (*value!=':') {ep=value;return 0;} /* fail! */ | |
446 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ | |
447 | if (!value) return 0; | |
448 | ||
449 | while (*value==',') | |
450 | { | |
451 | cJSON *new_item; | |
452 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ | |
453 | child->next=new_item;new_item->prev=child;child=new_item; | |
454 | value=skip(parse_string(child,skip(value+1))); | |
455 | if (!value) return 0; | |
456 | child->string=child->valuestring;child->valuestring=0; | |
457 | if (*value!=':') {ep=value;return 0;} /* fail! */ | |
458 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ | |
459 | if (!value) return 0; | |
460 | } | |
461 | ||
462 | if (*value=='}') return value+1; /* end of array */ | |
463 | ep=value;return 0; /* malformed. */ | |
464 | } | |
465 | ||
466 | /* Render an object to text. */ | |
467 | static char *print_object(cJSON *item,int32_t depth,int32_t fmt) | |
468 | { | |
469 | char **entries=0,**names=0; | |
470 | char *out=0,*ptr,*ret,*str;int32_t len=7,i=0,j; | |
471 | cJSON *child=item->child,*firstchild; | |
472 | int32_t numentries=0,fail=0; | |
473 | // Count the number of entries | |
474 | firstchild = child; | |
475 | while ( child ) | |
476 | { | |
477 | numentries++; | |
478 | child = child->next; | |
479 | if ( child == firstchild ) | |
480 | { | |
481 | printf("cJSON infinite loop detected\n"); | |
482 | break; | |
483 | } | |
484 | } | |
485 | /* Explicitly handle empty object case */ | |
486 | if (!numentries) | |
487 | { | |
488 | out=(char*)cJSON_malloc(fmt?depth+4+1:3+1); | |
489 | if (!out) return 0; | |
490 | ptr=out;*ptr++='{'; | |
491 | if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';} | |
492 | *ptr++='}';*ptr++=0; | |
493 | return out; | |
494 | } | |
495 | /* Allocate space for the names and the objects */ | |
496 | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); | |
497 | if (!entries) return 0; | |
498 | names=(char**)cJSON_malloc(numentries*sizeof(char*)); | |
499 | if (!names) {cJSON_free(entries);return 0;} | |
500 | memset(entries,0,sizeof(char*)*numentries); | |
501 | memset(names,0,sizeof(char*)*numentries); | |
502 | ||
503 | /* Collect all the results into our arrays: */ | |
504 | child=item->child;depth++;if (fmt) len+=depth; | |
505 | while ( child ) | |
506 | { | |
507 | names[i]=str=print_string_ptr(child->string); | |
508 | entries[i++]=ret=print_value(child,depth,fmt); | |
509 | if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; | |
510 | child=child->next; | |
511 | if ( child == firstchild ) | |
512 | break; | |
513 | } | |
514 | ||
515 | /* Try to allocate the output string */ | |
516 | if (!fail) out=(char*)cJSON_malloc(len+1); | |
517 | if (!out) fail=1; | |
518 | ||
519 | /* Handle failure */ | |
520 | if (fail) | |
521 | { | |
522 | for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);} | |
523 | cJSON_free(names);cJSON_free(entries); | |
524 | return 0; | |
525 | } | |
526 | ||
527 | /* Compose the output: */ | |
528 | *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0; | |
529 | for (i=0;i<numentries;i++) | |
530 | { | |
531 | if (fmt) for (j=0;j<depth;j++) *ptr++='\t'; | |
532 | strcpy(ptr,names[i]);ptr+=strlen(names[i]); | |
533 | *ptr++=':';if (fmt) *ptr++='\t'; | |
534 | strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); | |
535 | if (i!=numentries-1) *ptr++=','; | |
536 | if (fmt) *ptr++='\n';*ptr=0; | |
537 | cJSON_free(names[i]);cJSON_free(entries[i]); | |
538 | } | |
539 | ||
540 | cJSON_free(names);cJSON_free(entries); | |
541 | if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t'; | |
542 | *ptr++='}';*ptr++=0; | |
543 | return out; | |
544 | } | |
545 | ||
546 | /* Get Array size/item / object item. */ | |
547 | int32_t cJSON_GetArraySize(cJSON *array) {cJSON *c; if ( array == 0 ) return(0); c=array->child;int32_t i=0;while(c)i++,c=c->next;return i;} | |
548 | cJSON *cJSON_GetArrayItem(cJSON *array,int32_t item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} | |
549 | cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} | |
550 | ||
551 | /* Utility for array list handling. */ | |
552 | static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} | |
553 | /* Utility for handling references. */ | |
554 | 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;} | |
555 | ||
556 | /* Add item to array/object. */ | |
557 | 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);}} | |
558 | 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);} | |
559 | void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} | |
560 | void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} | |
561 | ||
562 | cJSON *cJSON_DetachItemFromArray(cJSON *array,int32_t which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; | |
563 | 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;} | |
564 | void cJSON_DeleteItemFromArray(cJSON *array,int32_t which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} | |
565 | cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int32_t 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;} | |
566 | void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} | |
567 | ||
568 | /* Replace array/object items with new ones. */ | |
569 | void cJSON_ReplaceItemInArray(cJSON *array,int32_t which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; | |
570 | newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; | |
571 | if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} | |
572 | void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int32_t 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);}} | |
573 | ||
574 | /* Create basic types: */ | |
575 | cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} | |
576 | cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} | |
577 | cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} | |
578 | cJSON *cJSON_CreateBool(int32_t b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} | |
579 | cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int64_t)num;}return item;} | |
580 | cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} | |
581 | cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} | |
582 | cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} | |
583 | ||
584 | /* Create Arrays: */ | |
585 | cJSON *cJSON_CreateIntArray(int64_t *numbers,int32_t count) {int32_t i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber((double)numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | |
586 | cJSON *cJSON_CreateFloatArray(float *numbers,int32_t count) {int32_t 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;} | |
587 | cJSON *cJSON_CreateDoubleArray(double *numbers,int32_t count) {int32_t 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;} | |
588 | cJSON *cJSON_CreateStringArray(char **strings,int32_t count) {int32_t 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;} | |
589 | ||
590 | /* Duplication */ | |
591 | cJSON *cJSON_Duplicate(cJSON *item,int32_t recurse) | |
592 | { | |
593 | cJSON *newitem,*cptr,*nptr=0,*newchild; | |
594 | /* Bail on bad ptr */ | |
595 | if (!item) return 0; | |
596 | /* Create new item */ | |
597 | newitem=cJSON_New_Item(); | |
598 | if (!newitem) return 0; | |
599 | /* Copy over all vars */ | |
600 | newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; | |
601 | if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} | |
602 | if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} | |
603 | /* If non-recursive, then we're done! */ | |
604 | if (!recurse) return newitem; | |
605 | /* Walk the ->next chain for the child. */ | |
606 | cptr=item->child; | |
607 | while (cptr) | |
608 | { | |
609 | newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ | |
610 | if (!newchild) {cJSON_Delete(newitem);return 0;} | |
611 | if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ | |
612 | else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ | |
613 | cptr=cptr->next; | |
614 | } | |
615 | return newitem; | |
616 | } | |
617 | ||
618 | void cJSON_Minify(char *json) | |
619 | { | |
620 | char *into=json; | |
621 | while (*json) | |
622 | { | |
623 | if (*json==' ') json++; | |
624 | else if (*json=='\t') json++; // Whitespace characters. | |
625 | else if (*json=='\r') json++; | |
626 | else if (*json=='\n') json++; | |
627 | else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; // double-slash comments, to end of line. | |
628 | else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} // multiline comments. | |
629 | else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} // string literals, which are \" sensitive. | |
630 | else *into++=*json++; // All other characters. | |
631 | } | |
632 | *into=0; // and null-terminate. | |
633 | } | |
634 | ||
635 | // the following written by jl777 | |
636 | /****************************************************************************** | |
637 | * Copyright © 2014-2016 The SuperNET Developers. * | |
638 | * * | |
639 | * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * | |
640 | * the top-level directory of this distribution for the individual copyright * | |
641 | * holder information and the developer policies on copyright and licensing. * | |
642 | * * | |
643 | * Unless otherwise agreed in a custom licensing agreement, no part of the * | |
644 | * SuperNET software, including this file may be copied, modified, propagated * | |
645 | * or distributed except according to the terms contained in the LICENSE file * | |
646 | * * | |
647 | * Removal or modification of this copyright notice is prohibited. * | |
648 | * * | |
649 | ******************************************************************************/ | |
650 | ||
651 | void copy_cJSON(struct destbuf *dest,cJSON *obj) | |
652 | { | |
653 | char *str; | |
654 | int i; | |
655 | long offset; | |
656 | dest->buf[0] = 0; | |
657 | if ( obj != 0 ) | |
658 | { | |
659 | str = cJSON_Print(obj); | |
660 | if ( str != 0 ) | |
661 | { | |
662 | offset = stripquotes(str); | |
663 | //strcpy(dest,str+offset); | |
664 | for (i=0; i<MAX_JSON_FIELD-1; i++) | |
665 | if ( (dest->buf[i]= str[offset+i]) == 0 ) | |
666 | break; | |
667 | dest->buf[i] = 0; | |
668 | free(str); | |
669 | } | |
670 | } | |
671 | } | |
672 | ||
673 | void copy_cJSON2(char *dest,int32_t maxlen,cJSON *obj) | |
674 | { | |
675 | struct destbuf tmp; | |
676 | maxlen--; | |
677 | dest[0] = 0; | |
678 | if ( maxlen > sizeof(tmp.buf) ) | |
679 | maxlen = sizeof(tmp.buf); | |
680 | copy_cJSON(&tmp,obj); | |
681 | if ( strlen(tmp.buf) < maxlen ) | |
682 | strcpy(dest,tmp.buf); | |
683 | else dest[0] = 0; | |
684 | } | |
685 | ||
686 | int64_t _get_cJSON_int(cJSON *json) | |
687 | { | |
688 | struct destbuf tmp; | |
689 | if ( json != 0 ) | |
690 | { | |
691 | copy_cJSON(&tmp,json); | |
692 | if ( tmp.buf[0] != 0 ) | |
693 | return(calc_nxt64bits(tmp.buf)); | |
694 | } | |
695 | return(0); | |
696 | } | |
697 | ||
698 | int64_t get_cJSON_int(cJSON *json,char *field) | |
699 | { | |
700 | cJSON *numjson; | |
701 | if ( json != 0 ) | |
702 | { | |
703 | numjson = cJSON_GetObjectItem(json,field); | |
704 | if ( numjson != 0 ) | |
705 | return(_get_cJSON_int(numjson)); | |
706 | } | |
707 | return(0); | |
708 | } | |
709 | ||
f3d5295c | 710 | int64_t conv_floatstr(char *numstr) |
711 | { | |
712 | double val,corr; | |
713 | val = atof(numstr); | |
714 | corr = (val < 0.) ? -0.50000000001 : 0.50000000001; | |
715 | return((int64_t)(val * SATOSHIDEN + corr)); | |
716 | } | |
717 | ||
3a2b2b45 | 718 | int64_t _conv_cJSON_float(cJSON *json) |
719 | { | |
720 | int64_t conv_floatstr(char *); | |
721 | struct destbuf tmp; | |
722 | if ( json != 0 ) | |
723 | { | |
724 | copy_cJSON(&tmp,json); | |
725 | return(conv_floatstr(tmp.buf)); | |
726 | } | |
727 | return(0); | |
728 | } | |
729 | ||
730 | int64_t conv_cJSON_float(cJSON *json,char *field) | |
731 | { | |
732 | if ( json != 0 ) | |
733 | return(_conv_cJSON_float(cJSON_GetObjectItem(json,field))); | |
734 | return(0); | |
735 | } | |
736 | ||
737 | int32_t extract_cJSON_str(char *dest,int32_t max,cJSON *json,char *field) | |
738 | { | |
739 | int32_t safecopy(char *dest,char *src,long len); | |
740 | char *str; | |
741 | cJSON *obj; | |
742 | int32_t len; | |
743 | long offset; | |
744 | dest[0] = 0; | |
745 | obj = cJSON_GetObjectItem(json,field); | |
746 | if ( obj != 0 ) | |
747 | { | |
748 | str = cJSON_Print(obj); | |
749 | offset = stripquotes(str); | |
750 | len = safecopy(dest,str+offset,max); | |
751 | free(str); | |
752 | return(len); | |
753 | } | |
754 | return(0); | |
755 | } | |
756 | ||
757 | cJSON *gen_list_json(char **list) | |
758 | { | |
759 | cJSON *array,*item; | |
760 | array = cJSON_CreateArray(); | |
761 | while ( list != 0 && *list != 0 && *list[0] != 0 ) | |
762 | { | |
763 | item = cJSON_CreateString(*list++); | |
764 | cJSON_AddItemToArray(array,item); | |
765 | } | |
766 | return(array); | |
767 | } | |
768 | ||
769 | uint64_t get_API_nxt64bits(cJSON *obj) | |
770 | { | |
771 | uint64_t nxt64bits = 0; | |
772 | struct destbuf tmp; | |
773 | if ( obj != 0 ) | |
774 | { | |
775 | if ( is_cJSON_Number(obj) != 0 ) | |
776 | return((uint64_t)obj->valuedouble); | |
777 | copy_cJSON(&tmp,obj); | |
778 | nxt64bits = calc_nxt64bits(tmp.buf); | |
779 | } | |
780 | return(nxt64bits); | |
781 | } | |
782 | uint64_t j64bits(cJSON *json,char *field) { if ( field == 0 ) return(get_API_nxt64bits(json)); return(get_API_nxt64bits(cJSON_GetObjectItem(json,field))); } | |
783 | uint64_t j64bitsi(cJSON *json,int32_t i) { return(get_API_nxt64bits(cJSON_GetArrayItem(json,i))); } | |
784 | ||
785 | uint64_t get_satoshi_obj(cJSON *json,char *field) | |
786 | { | |
787 | int32_t i,n; | |
788 | uint64_t prev,satoshis,mult = 1; | |
789 | struct destbuf numstr,checkstr; | |
790 | cJSON *numjson; | |
791 | numjson = cJSON_GetObjectItem(json,field); | |
792 | copy_cJSON(&numstr,numjson); | |
793 | satoshis = prev = 0; mult = 1; n = (int32_t)strlen(numstr.buf); | |
794 | for (i=n-1; i>=0; i--,mult*=10) | |
795 | { | |
796 | satoshis += (mult * (numstr.buf[i] - '0')); | |
797 | if ( satoshis < prev ) | |
798 | printf("get_satoshi_obj numstr.(%s) i.%d prev.%llu vs satoshis.%llu\n",numstr.buf,i,(unsigned long long)prev,(unsigned long long)satoshis); | |
799 | prev = satoshis; | |
800 | } | |
801 | sprintf(checkstr.buf,"%llu",(long long)satoshis); | |
802 | if ( strcmp(checkstr.buf,numstr.buf) != 0 ) | |
803 | { | |
804 | printf("SATOSHI GREMLIN?? numstr.(%s) -> %.8f -> (%s)\n",numstr.buf,dstr(satoshis),checkstr.buf); | |
805 | } | |
806 | return(satoshis); | |
807 | } | |
808 | ||
809 | void add_satoshis_json(cJSON *json,char *field,uint64_t satoshis) | |
810 | { | |
811 | cJSON *obj; | |
812 | char numstr[64]; | |
813 | sprintf(numstr,"%lld",(long long)satoshis); | |
814 | obj = cJSON_CreateString(numstr); | |
815 | cJSON_AddItemToObject(json,field,obj); | |
816 | if ( satoshis != get_satoshi_obj(json,field) ) | |
817 | printf("error adding satoshi obj %ld -> %ld\n",(unsigned long)satoshis,(unsigned long)get_satoshi_obj(json,field)); | |
818 | } | |
819 | ||
820 | char *cJSON_str(cJSON *json) | |
821 | { | |
822 | if ( json != 0 && is_cJSON_String(json) != 0 ) | |
823 | return(json->valuestring); | |
824 | return(0); | |
825 | } | |
826 | ||
827 | void jadd(cJSON *json,char *field,cJSON *item) { if ( json != 0 )cJSON_AddItemToObject(json,field,item); } | |
828 | void jaddstr(cJSON *json,char *field,char *str) { if ( json != 0 && str != 0 ) cJSON_AddItemToObject(json,field,cJSON_CreateString(str)); } | |
829 | void jaddnum(cJSON *json,char *field,double num) { if ( json != 0 )cJSON_AddItemToObject(json,field,cJSON_CreateNumber(num)); } | |
830 | void jadd64bits(cJSON *json,char *field,uint64_t nxt64bits) { char numstr[64]; sprintf(numstr,"%llu",(long long)nxt64bits), jaddstr(json,field,numstr); } | |
831 | void jaddi(cJSON *json,cJSON *item) { if ( json != 0 ) cJSON_AddItemToArray(json,item); } | |
832 | void jaddistr(cJSON *json,char *str) { if ( json != 0 ) cJSON_AddItemToArray(json,cJSON_CreateString(str)); } | |
833 | void jaddinum(cJSON *json,double num) { if ( json != 0 ) cJSON_AddItemToArray(json,cJSON_CreateNumber(num)); } | |
834 | void jaddi64bits(cJSON *json,uint64_t nxt64bits) { char numstr[64]; sprintf(numstr,"%llu",(long long)nxt64bits), jaddistr(json,numstr); } | |
835 | char *jstr(cJSON *json,char *field) { if ( json == 0 ) return(0); if ( field == 0 ) return(cJSON_str(json)); return(cJSON_str(cJSON_GetObjectItem(json,field))); } | |
836 | ||
837 | char *jstri(cJSON *json,int32_t i) { return(cJSON_str(cJSON_GetArrayItem(json,i))); } | |
838 | char *jprint(cJSON *json,int32_t freeflag) | |
839 | { | |
840 | char *str; | |
841 | /*static portable_mutex_t mutex; static int32_t initflag; | |
842 | if ( initflag == 0 ) | |
843 | { | |
844 | portable_mutex_init(&mutex); | |
845 | initflag = 1; | |
846 | }*/ | |
847 | if ( json == 0 ) | |
34c42c40 | 848 | return(clonestr((char *)"{}")); |
3a2b2b45 | 849 | //portable_mutex_lock(&mutex); |
850 | //usleep(5000); | |
851 | str = cJSON_Print(json), _stripwhite(str,' '); | |
852 | if ( freeflag != 0 ) | |
853 | free_json(json); | |
854 | //portable_mutex_unlock(&mutex); | |
855 | return(str); | |
856 | } | |
857 | ||
858 | bits256 get_API_bits256(cJSON *obj) | |
859 | { | |
860 | bits256 hash; char *str; | |
861 | memset(hash.bytes,0,sizeof(hash)); | |
862 | if ( obj != 0 ) | |
863 | { | |
864 | if ( is_cJSON_String(obj) != 0 && (str= obj->valuestring) != 0 && strlen(str) == 64 ) | |
865 | decode_hex(hash.bytes,sizeof(hash),str); | |
866 | } | |
867 | return(hash); | |
868 | } | |
869 | bits256 jbits256(cJSON *json,char *field) { if ( field == 0 ) return(get_API_bits256(json)); return(get_API_bits256(cJSON_GetObjectItem(json,field))); } | |
870 | bits256 jbits256i(cJSON *json,int32_t i) { return(get_API_bits256(cJSON_GetArrayItem(json,i))); } | |
871 | void jaddbits256(cJSON *json,char *field,bits256 hash) { char str[65]; bits256_str(str,hash), jaddstr(json,field,str); } | |
872 | void jaddibits256(cJSON *json,bits256 hash) { char str[65]; bits256_str(str,hash), jaddistr(json,str); } | |
873 | ||
874 | char *get_cJSON_fieldname(cJSON *obj) | |
875 | { | |
876 | if ( obj != 0 ) | |
877 | { | |
878 | if ( obj->child != 0 && obj->child->string != 0 ) | |
879 | return(obj->child->string); | |
880 | else if ( obj->string != 0 ) | |
881 | return(obj->string); | |
882 | } | |
883 | return((char *)"<no cJSON string field>"); | |
884 | } | |
885 | ||
886 | int32_t jnum(cJSON *obj,char *field) | |
887 | { | |
888 | char *str; int32_t polarity = 1; | |
889 | if ( field != 0 ) | |
890 | obj = jobj(obj,field); | |
891 | if ( obj != 0 ) | |
892 | { | |
893 | if ( is_cJSON_Number(obj) != 0 ) | |
894 | return(obj->valuedouble); | |
895 | else if ( is_cJSON_String(obj) != 0 && (str= jstr(obj,0)) != 0 ) | |
896 | { | |
897 | if ( str[0] == '-' ) | |
898 | polarity = -1, str++; | |
899 | return(polarity * (int32_t)calc_nxt64bits(str)); | |
900 | } | |
901 | } | |
902 | return(0); | |
903 | } | |
904 | ||
905 | void ensure_jsonitem(cJSON *json,char *field,char *value) | |
906 | { | |
907 | cJSON *obj = cJSON_GetObjectItem(json,field); | |
908 | if ( obj == 0 ) | |
909 | cJSON_AddItemToObject(json,field,cJSON_CreateString(value)); | |
910 | else cJSON_ReplaceItemInObject(json,field,cJSON_CreateString(value)); | |
911 | } | |
912 | ||
913 | int32_t in_jsonarray(cJSON *array,char *value) | |
914 | { | |
915 | int32_t i,n; | |
916 | struct destbuf remote; | |
917 | if ( array != 0 && is_cJSON_Array(array) != 0 ) | |
918 | { | |
919 | n = cJSON_GetArraySize(array); | |
920 | for (i=0; i<n; i++) | |
921 | { | |
922 | if ( array == 0 || n == 0 ) | |
923 | break; | |
924 | copy_cJSON(&remote,cJSON_GetArrayItem(array,i)); | |
925 | if ( strcmp(remote.buf,value) == 0 ) | |
926 | return(1); | |
927 | } | |
928 | } | |
929 | return(0); | |
930 | } | |
931 | ||
932 | int32_t myatoi(char *str,int32_t range) | |
933 | { | |
934 | long x; char *ptr; | |
935 | x = strtol(str,&ptr,10); | |
936 | if ( range != 0 && x >= range ) | |
937 | x = (range - 1); | |
938 | return((int32_t)x); | |
939 | } | |
940 | ||
941 | int32_t get_API_int(cJSON *obj,int32_t val) | |
942 | { | |
943 | struct destbuf buf; | |
944 | if ( obj != 0 ) | |
945 | { | |
946 | if ( is_cJSON_Number(obj) != 0 ) | |
947 | return((int32_t)obj->valuedouble); | |
948 | copy_cJSON(&buf,obj); | |
949 | val = myatoi(buf.buf,0); | |
950 | if ( val < 0 ) | |
951 | val = 0; | |
952 | } | |
953 | return(val); | |
954 | } | |
955 | int32_t jint(cJSON *json,char *field) { if ( json == 0 ) return(0); if ( field == 0 ) return(get_API_int(json,0)); return(get_API_int(cJSON_GetObjectItem(json,field),0)); } | |
956 | int32_t jinti(cJSON *json,int32_t i) { if ( json == 0 ) return(0); return(get_API_int(cJSON_GetArrayItem(json,i),0)); } | |
957 | ||
958 | uint32_t get_API_uint(cJSON *obj,uint32_t val) | |
959 | { | |
960 | struct destbuf buf; | |
961 | if ( obj != 0 ) | |
962 | { | |
963 | if ( is_cJSON_Number(obj) != 0 ) | |
964 | return((uint32_t)obj->valuedouble); | |
965 | copy_cJSON(&buf,obj); | |
966 | val = myatoi(buf.buf,0); | |
967 | } | |
968 | return(val); | |
969 | } | |
970 | uint32_t juint(cJSON *json,char *field) { if ( json == 0 ) return(0); if ( field == 0 ) return(get_API_uint(json,0)); return(get_API_uint(cJSON_GetObjectItem(json,field),0)); } | |
971 | uint32_t juinti(cJSON *json,int32_t i) { if ( json == 0 ) return(0); return(get_API_uint(cJSON_GetArrayItem(json,i),0)); } | |
972 | ||
973 | double get_API_float(cJSON *obj) | |
974 | { | |
975 | double val = 0.; | |
976 | struct destbuf buf; | |
977 | if ( obj != 0 ) | |
978 | { | |
979 | if ( is_cJSON_Number(obj) != 0 ) | |
980 | return(obj->valuedouble); | |
981 | copy_cJSON(&buf,obj); | |
982 | val = atof(buf.buf); | |
983 | } | |
984 | return(val); | |
985 | } | |
986 | ||
987 | double jdouble(cJSON *json,char *field) | |
988 | { | |
989 | if ( json != 0 ) | |
990 | { | |
991 | if ( field == 0 ) | |
992 | return(get_API_float(json)); | |
993 | else return(get_API_float(cJSON_GetObjectItem(json,field))); | |
994 | } else return(0.); | |
995 | } | |
996 | ||
997 | double jdoublei(cJSON *json,int32_t i) | |
998 | { | |
999 | if ( json != 0 ) | |
1000 | return(get_API_float(cJSON_GetArrayItem(json,i))); | |
1001 | else return(0.); | |
1002 | } | |
1003 | ||
1004 | cJSON *jobj(cJSON *json,char *field) { if ( json != 0 ) return(cJSON_GetObjectItem(json,field)); return(0); } | |
1005 | ||
1006 | void jdelete(cJSON *json,char *field) | |
1007 | { | |
1008 | if ( jobj(json,field) != 0 ) | |
1009 | cJSON_DeleteItemFromObject(json,field); | |
1010 | } | |
1011 | ||
1012 | cJSON *jduplicate(cJSON *json) { return(cJSON_Duplicate(json,1)); } | |
1013 | ||
1014 | cJSON *jitem(cJSON *array,int32_t i) { if ( array != 0 && is_cJSON_Array(array) != 0 && cJSON_GetArraySize(array) > i ) return(cJSON_GetArrayItem(array,i)); return(0); } | |
1015 | cJSON *jarray(int32_t *nump,cJSON *json,char *field) | |
1016 | { | |
1017 | cJSON *array; | |
1018 | if ( json != 0 ) | |
1019 | { | |
1020 | if ( field == 0 ) | |
1021 | array = json; | |
1022 | else array = cJSON_GetObjectItem(json,field); | |
1023 | if ( array != 0 && is_cJSON_Array(array) != 0 && (*nump= cJSON_GetArraySize(array)) > 0 ) | |
1024 | return(array); | |
1025 | } | |
1026 | *nump = 0; | |
1027 | return(0); | |
1028 | } | |
1029 | ||
1030 | int32_t expand_nxt64bits(char *NXTaddr,uint64_t nxt64bits) | |
1031 | { | |
1032 | int32_t i,n; | |
1033 | uint64_t modval; | |
1034 | char rev[64]; | |
1035 | for (i=0; nxt64bits!=0; i++) | |
1036 | { | |
1037 | modval = nxt64bits % 10; | |
1038 | rev[i] = (char)(modval + '0'); | |
1039 | nxt64bits /= 10; | |
1040 | } | |
1041 | n = i; | |
1042 | for (i=0; i<n; i++) | |
1043 | NXTaddr[i] = rev[n-1-i]; | |
1044 | NXTaddr[i] = 0; | |
1045 | return(n); | |
1046 | } | |
1047 | ||
1048 | char *nxt64str(uint64_t nxt64bits) | |
1049 | { | |
1050 | static char NXTaddr[64]; | |
1051 | expand_nxt64bits(NXTaddr,nxt64bits); | |
1052 | return(NXTaddr); | |
1053 | } | |
1054 | ||
1055 | char *nxt64str2(uint64_t nxt64bits) | |
1056 | { | |
1057 | static char NXTaddr[64]; | |
1058 | expand_nxt64bits(NXTaddr,nxt64bits); | |
1059 | return(NXTaddr); | |
1060 | } | |
1061 | ||
1062 | int32_t cmp_nxt64bits(const char *str,uint64_t nxt64bits) | |
1063 | { | |
1064 | char expanded[64]; | |
1065 | if ( str == 0 )//|| str[0] == 0 || nxt64bits == 0 ) | |
1066 | return(-1); | |
1067 | if ( nxt64bits == 0 && str[0] == 0 ) | |
1068 | return(0); | |
1069 | expand_nxt64bits(expanded,nxt64bits); | |
1070 | return(strcmp(str,expanded)); | |
1071 | } | |
1072 | ||
1073 | uint64_t calc_nxt64bits(const char *NXTaddr) | |
1074 | { | |
1075 | int32_t c; | |
1076 | int64_t n,i,polarity = 1; | |
1077 | uint64_t lastval,mult,nxt64bits = 0; | |
1078 | if ( NXTaddr == 0 ) | |
1079 | { | |
1080 | printf("calling calc_nxt64bits with null ptr!\n"); | |
1081 | return(0); | |
1082 | } | |
1083 | n = strlen(NXTaddr); | |
1084 | if ( n >= 22 ) | |
1085 | { | |
1086 | printf("calc_nxt64bits: illegal NXTaddr.(%s) too long\n",NXTaddr); | |
1087 | return(0); | |
1088 | } | |
1089 | else if ( strcmp(NXTaddr,"0") == 0 || strcmp(NXTaddr,"false") == 0 ) | |
1090 | { | |
1091 | // printf("zero address?\n"); getchar(); | |
1092 | return(0); | |
1093 | } | |
1094 | if ( NXTaddr[0] == '-' ) | |
1095 | polarity = -1, NXTaddr++, n--; | |
1096 | mult = 1; | |
1097 | lastval = 0; | |
1098 | for (i=n-1; i>=0; i--,mult*=10) | |
1099 | { | |
1100 | c = NXTaddr[i]; | |
1101 | if ( c < '0' || c > '9' ) | |
1102 | { | |
1103 | printf("calc_nxt64bits: illegal char.(%c %d) in (%s).%d\n",c,c,NXTaddr,(int32_t)i); | |
1104 | #ifdef __APPLE__ | |
1105 | //while ( 1 ) | |
1106 | { | |
1107 | //sleep(60); | |
1108 | printf("calc_nxt64bits: illegal char.(%c %d) in (%s).%d\n",c,c,NXTaddr,(int32_t)i); | |
1109 | } | |
1110 | #endif | |
1111 | return(0); | |
1112 | } | |
1113 | nxt64bits += mult * (c - '0'); | |
1114 | if ( nxt64bits < lastval ) | |
1115 | printf("calc_nxt64bits: warning: 64bit overflow %llx < %llx\n",(long long)nxt64bits,(long long)lastval); | |
1116 | lastval = nxt64bits; | |
1117 | } | |
1118 | while ( *NXTaddr == '0' && *NXTaddr != 0 ) | |
1119 | NXTaddr++; | |
1120 | if ( cmp_nxt64bits(NXTaddr,nxt64bits) != 0 ) | |
1121 | printf("error calculating nxt64bits: %s -> %llx -> %s\n",NXTaddr,(long long)nxt64bits,nxt64str(nxt64bits)); | |
1122 | if ( polarity < 0 ) | |
1123 | return(-(int64_t)nxt64bits); | |
1124 | return(nxt64bits); | |
1125 | } | |
1126 | ||
1127 | cJSON *addrs_jsonarray(uint64_t *addrs,int32_t num) | |
1128 | { | |
1129 | int32_t j; cJSON *array; | |
1130 | array = cJSON_CreateArray(); | |
1131 | for (j=0; j<num; j++) | |
1132 | jaddi64bits(array,addrs[j]); | |
1133 | return(array); | |
1134 | } | |
1135 | ||
1136 | void free_json(cJSON *json) { if ( json != 0 ) cJSON_Delete(json); } |