cJSON.c revision 18728fe0
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#if 0 27#include <string.h> 28#include <stdio.h> 29#include <math.h> 30#include <stdlib.h> 31#include <float.h> 32#endif 33 34#include "cJSON.h" 35 36#include <linux/module.h> 37#include <linux/slab.h> 38 39#if 0 40#if defined(WINDOWS) || defined(__WIN32__) || defined(WIN32) || defined(_WIN32) 41#define strcasecmp stricmp 42#define strdup _strdup 43#endif 44#endif 45 46 47#if 0 48static void *(*cJSON_malloc)(size_t sz) = malloc; 49static void *(*cJSON_realloc)(void *ptr, size_t sz) = realloc; 50static void (*cJSON_free)(void *ptr) = free; 51#endif 52 53static void *cJSON_malloc(size_t sz) { 54 return kmalloc(sz, GFP_KERNEL); 55} 56 57static void *cJSON_realloc(void *ptr, size_t sz) 58{ 59 return krealloc(ptr, sz, GFP_KERNEL); 60} 61 62static void cJSON_free(void *ptr) 63{ 64 kfree(ptr); 65} 66 67static char* cJSON_strdup(const char* str) 68{ 69 size_t len; 70 char* copy; 71 72 len = strlen(str) + 1; 73 if (!(copy = (char*)cJSON_malloc(len))) return 0; 74 memcpy(copy,str,len); 75 return copy; 76} 77 78#if 0 79void cJSON_InitHooks(cJSON_Hooks* hooks) 80{ 81 if (!hooks) { /* Reset hooks */ 82 cJSON_malloc = malloc; 83 cJSON_realloc = realloc; 84 cJSON_free = free; 85 return; 86 } 87 88 cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; 89 cJSON_realloc= (hooks->realloc_fn)?hooks->realloc_fn:realloc; 90 cJSON_free = (hooks->free_fn)?hooks->free_fn:free; 91} 92#endif 93 94// Internal constructor. 95static cJSON *cJSON_New_Item(void) 96{ 97 cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); 98 if (node) memset(node,0,sizeof(cJSON)); 99 return node; 100} 101 102// Delete a cJSON structure. 103void cJSON_Delete(cJSON *c) 104{ 105 cJSON *next; 106 while (c) 107 { 108 next=c->next; 109 if (c->child) cJSON_Delete(c->child); 110 if (c->valuestring) cJSON_free(c->valuestring); 111 if (c->string) cJSON_free(c->string); 112 cJSON_free(c); 113 c=next; 114 } 115} 116 117 118/* Parse the input text to generate a number, and populate the result into item. */ 119static const char *parse_number(cJSON *item,const char *num) 120{ 121 int n=0,sign=1; 122 123 if (*num=='-') sign=-1,num++; /* Has sign? */ 124 if (*num=='0') num++; /* is zero */ 125 if (*num>='1' && *num<='9') do n=(n*10)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ 126 item->valueint=(int)n; 127 item->type=cJSON_Number; 128 return num; 129} 130 131/* Render the number nicely from the given item into a string. */ 132static char *print_number(cJSON *item) 133{ 134 char *str; 135 str=(char*)cJSON_malloc(21); 136 if (str) 137 sprintf(str,"%d",item->valueint); 138 return str; 139} 140 141 142// Parse the input text into an unescaped cstring, and populate item. 143static const char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 144static const char *parse_string(cJSON *item,const char *str) 145{ 146 const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; 147 if (*str!='\"') return 0; // not a string! 148 149 while (*ptr!='\"' && *ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes. 150 151 out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly. 152 if (!out) return 0; 153 154 ptr=str+1;ptr2=out; 155 while (*ptr!='\"' && *ptr>31) 156 { 157 if (*ptr!='\\') *ptr2++=*ptr++; 158 else 159 { 160 ptr++; 161 switch (*ptr) 162 { 163 case 'b': *ptr2++='\b'; break; 164 case 'f': *ptr2++='\f'; break; 165 case 'n': *ptr2++='\n'; break; 166 case 'r': *ptr2++='\r'; break; 167 case 't': *ptr2++='\t'; break; 168 case 'u': // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY. 169 sscanf(ptr+1,"%4x",&uc); // get the unicode char. 170 len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len; 171 172 switch (len) { 173 case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 174 case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 175 case 1: *--ptr2 =(uc | firstByteMark[len]); 176 } 177 ptr2+=len;ptr+=4; 178 break; 179 default: *ptr2++=*ptr; break; 180 } 181 ptr++; 182 } 183 } 184 *ptr2=0; 185 if (*ptr=='\"') ptr++; 186 item->valuestring=out; 187 item->type=cJSON_String; 188 return ptr; 189} 190 191// Render the cstring provided to an escaped version that can be printed. 192static char *print_string_ptr(const char *str) 193{ 194 const char *ptr;char *ptr2,*out;int len=0; 195 196 ptr=str;while (*ptr && ++len) {if (*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} 197 198 out=(char*)cJSON_malloc(len+3); 199 ptr2=out;ptr=str; 200 *ptr2++='\"'; 201 while (*ptr) 202 { 203 if (*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; 204 else 205 { 206 *ptr2++='\\'; 207 switch (*ptr++) 208 { 209 case '\\': *ptr2++='\\'; break; 210 case '\"': *ptr2++='\"'; break; 211 case '\b': *ptr2++='b'; break; 212 case '\f': *ptr2++='f'; break; 213 case '\n': *ptr2++='n'; break; 214 case '\r': *ptr2++='r'; break; 215 case '\t': *ptr2++='t'; break; 216 default: ptr2--; break; // eviscerate with prejudice. 217 } 218 } 219 } 220 *ptr2++='\"';*ptr2++=0; 221 return out; 222} 223// Invote print_string_ptr (which is useful) on an item. 224static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} 225 226// Predeclare these prototypes. 227static const char *parse_value(cJSON *item,const char *value); 228static char *print_value(cJSON *item,int depth); 229static const char *parse_array(cJSON *item,const char *value); 230static char *print_array(cJSON *item,int depth); 231static const char *parse_object(cJSON *item,const char *value); 232static char *print_object(cJSON *item,int depth); 233 234// Utility to jump whitespace and cr/lf 235static const char *skip(const char *in) {while (in && *in<=32) in++; return in;} 236 237// Parse an object - create a new root, and populate. 238cJSON *cJSON_Parse(const char *value) 239{ 240 cJSON *c=cJSON_New_Item(); 241 if (!c) return 0; /* memory fail */ 242 243 if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;} 244 return c; 245} 246 247// Render a cJSON item/entity/structure to text. 248char *cJSON_Print(cJSON *item) {return print_value(item,0);} 249 250// Parser core - when encountering text, process appropriately. 251static const char *parse_value(cJSON *item,const char *value) 252{ 253 if (!value) return 0; // Fail on null. 254 if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } 255 if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } 256 if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } 257 if (*value=='\"') { return parse_string(item,value); } 258 if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } 259 if (*value=='[') { return parse_array(item,value); } 260 if (*value=='{') { return parse_object(item,value); } 261 262 return 0; // failure. 263} 264 265// Render a value to text. 266static char *print_value(cJSON *item,int depth) 267{ 268 char *out=0; 269 switch (item->type) 270 { 271 case cJSON_NULL: out=cJSON_strdup("null"); break; 272 case cJSON_False: out=cJSON_strdup("false");break; 273 case cJSON_True: out=cJSON_strdup("true"); break; 274 case cJSON_Number: out=print_number(item);break; 275 case cJSON_String: out=print_string(item);break; 276 case cJSON_Array: out=print_array(item,depth);break; 277 case cJSON_Object: out=print_object(item,depth);break; 278 } 279 return out; 280} 281 282// Build an array from input text. 283static const char *parse_array(cJSON *item,const char *value) 284{ 285 cJSON *child; 286 if (*value!='[') return 0; // not an array! 287 288 item->type=cJSON_Array; 289 value=skip(value+1); 290 if (*value==']') return value+1; // empty array. 291 292 item->child=child=cJSON_New_Item(); 293 if (!item->child) return 0; // memory fail 294 value=skip(parse_value(child,skip(value))); // skip any spacing, get the value. 295 if (!value) return 0; 296 297 while (*value==',') 298 { 299 cJSON *new_item; 300 if (!(new_item=cJSON_New_Item())) return 0; // memory fail 301 child->next=new_item;new_item->prev=child;child=new_item; 302 value=skip(parse_value(child,skip(value+1))); 303 if (!value) return 0; // memory fail 304 } 305 306 if (*value==']') return value+1; // end of array 307 return 0; // malformed. 308} 309 310// Render an array to text 311static char *print_array(cJSON *item,int depth) 312{ 313 char *out,*ptr,*ret;int len=5; 314 cJSON *child=item->child; 315 316 out=(char*)cJSON_malloc(len);*out='['; 317 ptr=out+1;*ptr=0; 318 while (child) 319 { 320 ret=print_value(child,depth+1); 321 if (!ret) {cJSON_free(out);return 0;} // Check for failure! 322 len+=strlen(ret)+3; 323 out=(char*)cJSON_realloc(out,len); 324 ptr=out+strlen(out); 325 ptr+=sprintf(ptr,ret); 326 if (child->next) {*ptr++=',';*ptr++=' ';*ptr=0;} 327 child=child->next; 328 cJSON_free(ret); 329 } 330 *ptr++=']';*ptr++=0; 331 return out; 332} 333 334// Build an object from the text. 335static const char *parse_object(cJSON *item,const char *value) 336{ 337 cJSON *child; 338 if (*value!='{') return 0; // not an object! 339 340 item->type=cJSON_Object; 341 value=skip(value+1); 342 if (*value=='}') return value+1; // empty array. 343 344 item->child=child=cJSON_New_Item(); 345 value=skip(parse_string(child,skip(value))); 346 if (!value) return 0; 347 child->string=child->valuestring;child->valuestring=0; 348 if (*value!=':') return 0; // fail! 349 value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. 350 if (!value) return 0; 351 352 while (*value==',') 353 { 354 cJSON *new_item; 355 if (!(new_item=cJSON_New_Item())) return 0; // memory fail 356 child->next=new_item;new_item->prev=child;child=new_item; 357 value=skip(parse_string(child,skip(value+1))); 358 if (!value) return 0; 359 child->string=child->valuestring;child->valuestring=0; 360 if (*value!=':') return 0; // fail! 361 value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. 362 if (!value) return 0; 363 } 364 365 if (*value=='}') return value+1; // end of array 366 return 0; // malformed. 367} 368 369// Render an object to text. 370static char *print_object(cJSON *item,int depth) 371{ 372 char *out,*ptr,*ret,*str;int len=7,i; 373 cJSON *child=item->child; 374 375 depth++;len+=depth;out=(char*)cJSON_malloc(len);*out='{'; 376 ptr=out+1;*ptr++='\n';*ptr=0; 377 while (child) 378 { 379 str=print_string_ptr(child->string); 380 if (!str) {cJSON_free(out);return 0;} 381 ret=print_value(child,depth); 382 if (!ret) {cJSON_free(str);cJSON_free(out);return 0;} // Check for failure! 383 len+=strlen(ret)+strlen(str)+4+depth; 384 out=(char*)cJSON_realloc(out,len); 385 ptr=out+strlen(out); 386 for (i=0;i<depth;i++) *ptr++='\t'; 387 ptr+=sprintf(ptr,str); 388 *ptr++=':';*ptr++='\t'; 389 ptr+=sprintf(ptr,ret); 390 if (child->next) *ptr++=','; 391 *ptr++='\n';*ptr=0; 392 child=child->next; 393 cJSON_free(str);cJSON_free(ret); 394 } 395 for (i=0;i<depth-1;i++) *ptr++='\t'; 396 *ptr++='}';*ptr++=0; 397 return out; 398} 399#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) 400 401static void skip_oneline_comment(char **input) 402{ 403 *input += static_strlen("//"); 404 405 for (; (*input)[0] != '\0'; ++(*input)) 406 { 407 if ((*input)[0] == '\n') { 408 *input += static_strlen("\n"); 409 return; 410 } 411 } 412} 413static void skip_multiline_comment(char **input) 414{ 415 *input += static_strlen("/*"); 416 417 for (; (*input)[0] != '\0'; ++(*input)) 418 { 419 if (((*input)[0] == '*') && ((*input)[1] == '/')) 420 { 421 *input += static_strlen("*/"); 422 return; 423 } 424 } 425} 426static void minify_string(char **input, char **output) { 427 (*output)[0] = (*input)[0]; 428 *input += static_strlen("\""); 429 *output += static_strlen("\""); 430 431 432 for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { 433 (*output)[0] = (*input)[0]; 434 435 if ((*input)[0] == '\"') { 436 (*output)[0] = '\"'; 437 *input += static_strlen("\""); 438 *output += static_strlen("\""); 439 return; 440 } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { 441 (*output)[1] = (*input)[1]; 442 *input += static_strlen("\""); 443 *output += static_strlen("\""); 444 } 445 } 446} 447 448void cJSON_Minify(char *json) 449{ 450 char *into = json; 451 452 if (json == NULL) 453 { 454 return; 455 } 456 457 while (json[0] != '\0') 458 { 459 switch (json[0]) 460 { 461 case ' ': 462 case '\t': 463 case '\r': 464 case '\n': 465 json++; 466 break; 467 468 case '/': 469 if (json[1] == '/') 470 { 471 skip_oneline_comment(&json); 472 } 473 else if (json[1] == '*') 474 { 475 skip_multiline_comment(&json); 476 } else { 477 json++; 478 } 479 break; 480 481 case '\"': 482 minify_string(&json, (char**)&into); 483 break; 484 485 default: 486 into[0] = json[0]; 487 json++; 488 into++; 489 } 490 } 491 492 /* and null-terminate. */ 493 *into = '\0'; 494} 495 496// Get Array size/item / object item. 497int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;} 498cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item) item--,c=c->next; return c;} 499cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && strcasecmp(c->string,string)) c=c->next; return c;} 500 501// Utility for array list handling. 502static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} 503 504// Add item to array/object. 505void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} 506void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} 507 508// Create basic types: 509cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;} 510cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();item->type=cJSON_True;return item;} 511cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();item->type=cJSON_False;return item;} 512cJSON *cJSON_CreateNumber(int num) {cJSON *item=cJSON_New_Item();item->type=cJSON_Number;item->valueint=(int)num;return item;} 513cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();item->type=cJSON_String;item->valuestring=cJSON_strdup(string);return item;} 514cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();item->type=cJSON_Array;return item;} 515cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();item->type=cJSON_Object;return item;} 516 517// Create Arrays: 518cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} 519cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} 520