1 /******************************************************************************
2 * cJSON_hacking
3 *
4 * 1.这是cJSON中cJSON.c(主程序)的源码,源码不到1000行(除注释).
5 * 2.本文仅仅注释了源码中JSON解析部分,对链表的操作没有进行任何注释,通过
6 * 分析阅读该源码,可以一窥双向链表,字符串处理,里面几个地方使用到了递归,
7 * 而且用得很精妙,但在理解上可能会有点困难.
8 * 3.源码作者在解析JSON时参考了: http://www.json.org/fatfree.html
9 * 如果您要阅读本程序,请先阅读该网页内容,因为源码中几个重要的函数的处理
10 * 都参照了该网页上的处理算法.
11 * 4.知识量:
12 * 1.C语言;
13 * 2.2.Unix或类Unix系统编程;
14 * 3.对双向链表的数据结构清晰;
15 * 5.如何阅读该源码:
16 * 1.linux下使用vi/vim配和ctags,windows下使用Source Insight,当然你也
17 * 可以用其他文本编辑器看.
18 * 2.该源码无主函数,本人自己是从第一个函数开始阅读,然后慢慢的看懂,
19 * 并了解了整个源码的大局,但本人强烈建议您从该函数开始阅读:
20 * cJSON *cJSON_Parse( const char *value ).
21 * 主要是因为这是默认的解析函数.
22 * 3.对于有些函数,本人没有添加注释,或者说本人觉得没必要.
23 * 4.祝您好运. :)
24 *
25 *
26 * 6.cJSON下载url: http://sourceforge.net/projects/cjson/
27 *
28 * 如果您对本文有任何意见、提议,可以发邮件至zengjf42@163.com,会尽快回复.
29 * 本文的最终解释权归本人(曾剑锋)所有,仅供学习、讨论.
30 *
31 * 2015-3-3 阴 深圳 尚观 Var
32 *
33 ******************************************************************************/
34
35
36 /*
37 * Copyright (c) 2009 Dave Gamble
38 *
39 * Permission is hereby granted, free of charge, to any person obtaining a copy
40 * of this software and associated documentation files (the "Software"), to deal
41 * in the Software without restriction, including without limitation the rights
42 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43 * copies of the Software, and to permit persons to whom the Software is
44 * furnished to do so, subject to the following conditions:
45 *
46 * The above copyright notice and this permission notice shall be included in
47 * all copies or substantial portions of the Software.
48 *
49 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
55 * THE SOFTWARE.
56 */
57
58 /* cJSON */
59 /* JSON parser in C. */
60
61 #include <string.h>
62 #include <stdio.h>
63 #include <math.h>
64 #include <stdlib.h>
65 #include <float.h>
66 #include <limits.h>
67 #include <ctype.h>
68 #include "cJSON.h"
69
70 /**
71 * 返回解析出错时对应的字符地址.
72 */
73 static const char *ep; /* error pointer */
74 const char *cJSON_GetErrorPtr( void )
75 {
76 return(ep);
77 }
78
79
80 /**
81 * 不分大小写字符串比较,感觉和原生的strcasecmp没什么区别.
82 */
83 static int cJSON_strcasecmp( const char *s1, const char *s2 )
84 {
85 if ( !s1 )
86 return( (s1 == s2) ? 0 : 1);
87 if ( !s2 )
88 return(1);
89 for (; tolower( *s1 ) == tolower( *s2 ); ++s1, ++s2 )
90 if ( *s1 == 0 )
91 return(0);
92 return(tolower( *(const unsigned char *) s1 ) - tolower( *(const unsigned char *) s2 ));
93 }
94
95
96 /**
97 * 定义cJSON中内存分配采用的方式,这里直接使用原生的malloc,free函数.
98 */
99 static void *(*cJSON_malloc)(size_t sz) = malloc;
100 static void (*cJSON_free)( void *ptr ) = free;
101
102
103 /**
104 * 定义cJSON中的字符串拷贝函数.
105 */
106 static char* cJSON_strdup( const char* str )
107 {
108 size_t len;
109 char * copy;
110
111 len = strlen( str ) + 1;
112 if ( !(copy = (char *) cJSON_malloc( len )))
113 return(0);
114 memcpy( copy, str, len );
115 return(copy);
116 }
117
118
119 /**
120 * 选择系统使用那种内存分配方式,这里使用原生的malloc、free函数.
121 */
122 void cJSON_InitHooks( cJSON_Hooks* hooks )
123 {
124 if ( !hooks ) /* Reset hooks */
125 {
126 cJSON_malloc = malloc;
127 cJSON_free = free;
128 return;
129 }
130
131 cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc;
132 cJSON_free = (hooks->free_fn) ? hooks->free_fn : free;
133 }
134
135
136 /**
137 * 构造一个item,同时给item赋初始值为全0,item可以理解为一个节点.
138 */
139 static cJSON *cJSON_New_Item( void )
140 {
141 cJSON* node = (cJSON *) cJSON_malloc( sizeof(cJSON));
142 if ( node )
143 memset( node, 0, sizeof(cJSON));
144 return(node);
145 }
146
147
148 /**
149 * 释放链表,对于有子链表的链表,采用递归的方式进行内存释放.
150 * 目前还没找到为什么需要 c->type & cJSON_IsReference 判断.
151 */
152 void cJSON_Delete( cJSON *c )
153 {
154 cJSON *next;
155 while ( c )
156 {
157 next = c->next;
158 if ( !(c->type & cJSON_IsReference) && c->child )
159 cJSON_Delete( c->child ); /* 递归释放内存 */
160 if ( !(c->type & cJSON_IsReference) && c->valuestring )
161 cJSON_free( c->valuestring );
162 if ( c->string )
163 cJSON_free( c->string );
164 cJSON_free( c );
165 c = next;
166 }
167 }
168
169
170 /* Parse the input text to generate a number, and populate the result into item. */
171 /**
172 * 解析数字,并把数据保存在item中对应的的地方.
173 */
174 static const char *parse_number( cJSON *item, const char *num )
175 {
176 /**
177 * 局部变量说明:
178 * 1.n : 用于保存数字;
179 * 2.sign : 数字部分的符号标志,如果是负数,就等于-1,如果是正数,就是1;
180 * 3.scale : 保存小数点后面有多少个数字的相反数;
181 * 4.subscale : 保存指数后面的数字;
182 * 5.signsubscale : 指数部分的符号标志,如果是负数,就等于-1,如果是正数,就是1.
183 *
184 * 如:
185 * num字符串: -1234.1234e4
186 * 1.n = 12341234;
187 * 2.sign = -1;
188 * 3.scale = -4;
189 * 4.subscale = 4;
190 * 5.signsubscale = 1;
191 *
192 * 结果公式 = sign * n * pow( 10.0, (scale + subscale * signsubscale))
193 * n = -1 * 12341234 * pow( 10.0, (-4 + 4 * 1))
194 * n = -12341234 * pow( 10.0, 0 )
195 * n = -12341234
196 */
197 double n = 0, sign = 1, scale = 0; int subscale = 0, signsubscale = 1;
198
199 if ( *num == '-' )
200 sign = -1, num++; /* Has sign? */
201 if ( *num == '0' )
202 num++; /* is zero */
203 if ( *num >= '1' && *num <= '9' )
204 do
205 n = (n * 10.0) + (*num++ - '0');
206 while ( *num >= '0' && *num <= '9' ); /* Number? */
207 if ( *num == '.' && num[1] >= '0' && num[1] <= '9' )
208 {
209 num++;
210 do
211 n = (n * 10.0) + (*num++ - '0'), scale--;
212 while ( *num >= '0' && *num <= '9' );
213 } /* Fractional part? --> 小数部分 */
214 if ( *num == 'e' || *num == 'E' ) /* Exponent? --> 指数部分 */
215 {
216 num++; if ( *num == '+' )
217 num++;
218 else if ( *num == '-' )
219 signsubscale = -1, num++; /* With sign? */
220 while ( *num >= '0' && *num <= '9' )
221 subscale = (subscale * 10) + (*num++ - '0'); /* Number? */
222 }
223
224 n = sign * n * pow( 10.0, (scale + subscale * signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
225
226 /**
227 * 以两种形式来保存数据,在下面的函数print_number()中输出数字的时候要比较这两个数据.
228 */
229 item->valuedouble = n;
230 item->valueint = (int) n;
231 item->type = cJSON_Number;
232 return(num);
233 }
234
235
236 /* Render the number nicely from the given item into a string. */
237 /**
238 * 下面代码中使用到DBL_EPSILON,其意思是双精度最小误差;
239 * 请参考url: http://blog.csdn.net/x356982611/article/details/19922453
240 */
241 static char *print_number( cJSON *item )
242 {
243 /**
244 * 局部变量说明:
245 * 1.str : 用于指向输出的数字字符串;
246 * 2.d : 保存item中的double数字.
247 */
248 char *str;
249 double d = item->valuedouble;
250 if ( fabs( ( (double) item->valueint) - d ) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN )
251 {
252 str = (char *) cJSON_malloc( 21 ); /* 2^64+1 can be represented in 21 chars. */
253 if ( str )
254 sprintf( str, "%d", item->valueint );
255 }else {
256 str = (char *) cJSON_malloc( 64 ); /* This is a nice tradeoff. */
257 if ( str )
258 {
259 if ( fabs( floor( d ) - d ) <= DBL_EPSILON && fabs( d ) < 1.0e60 )
260 sprintf( str, "%.0f", d );
261 else if ( fabs( d ) < 1.0e-6 || fabs( d ) > 1.0e9 )
262 sprintf( str, "%e", d );
263 else sprintf( str, "%f", d );
264 }
265 }
266 return(str);
267 }
268
269
270 static unsigned parse_hex4( const char *str )
271 {
272 /**
273 * 局部变量说明:
274 * 1.h : 保存最终返回的数据
275 */
276 unsigned h = 0;
277
278 if ( *str >= '0' && *str <= '9' )
279 h += (*str) - '0';
280 else if ( *str >= 'A' && *str <= 'F' )
281 h += 10 + (*str) - 'A';
282 else if ( *str >= 'a' && *str <= 'f' )
283 h += 10 + (*str) - 'a';
284 else return(0);
285
286 h = h << 4; str++; /* h = h << 4 <===> h = h * 16 */
287 if ( *str >= '0' && *str <= '9' )
288 h += (*str) - '0';
289 else if ( *str >= 'A' && *str <= 'F' )
290 h += 10 + (*str) - 'A';
291 else if ( *str >= 'a' && *str <= 'f' )
292 h += 10 + (*str) - 'a';
293 else return(0);
294
295 h = h << 4; str++;
296 if ( *str >= '0' && *str <= '9' )
297 h += (*str) - '0';
298 else if ( *str >= 'A' && *str <= 'F' )
299 h += 10 + (*str) - 'A';
300 else if ( *str >= 'a' && *str <= 'f' )
301 h += 10 + (*str) - 'a';
302 else return(0);
303
304 h = h << 4; str++;
305 if ( *str >= '0' && *str <= '9' )
306 h += (*str) - '0';
307 else if ( *str >= 'A' && *str <= 'F' )
308 h += 10 + (*str) - 'A';
309 else if ( *str >= 'a' && *str <= 'f' )
310 h += 10 + (*str) - 'a';
311 else return(0);
312 return(h);
313 }
314
315
316 /* Parse the input text into an unescaped cstring, and populate item. */
317 /* 将输入的文本分析到非转义cstring并填充item,目前不了解这里是什么情况 */
318 /* 不清楚这里的unicode编码格式字符的处理方式 */
319 static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
320 static const char *parse_string( cJSON *item, const char *str )
321 {
322 /**
323 * 局部变量说明:
324 * 1.ptr : 传入参数string的指针;
325 * 2.ptr2 : 指向输出字符串里的地址,主要用于从ptr字符串中拷贝字符到out中;
326 * 3.out : 指向动态分配的输出字符串的首地址;
327 * 4.len : 动态分配时需要的字符串的长度,分配时要在基础上+1;
328 * 5.uc : unicode编码格式字符;
329 * 6.uc2 : unicode编码格式字符.
330 */
331 const char *ptr = str + 1;
332 char *ptr2;
333 char *out;
334 int len = 0;
335 unsigned uc, uc2;
336
337 /* 判断第一个字符是否是"\"",如果不是,那么就不是字符串 */
338 if ( *str != '\"' ){ ep = str; return(0); } /* not a string! */
339
340 /* 计算字符串的长度,为后面的的内存分配提供数据长度信息 */
341 while ( *ptr != '\"' && *ptr && ++len ) if ( *ptr++ == '\\' )
342 ptr++; /* Skip escaped quotes. */
343
344 out = (char *) cJSON_malloc( len + 1 ); /* This is how long we need for the string, roughly. */
345 if ( !out )
346 return(0);
347
348 /* ptr指向'\"'后面那个字符,ptr2指向out的首地址,有利于数据拷贝 */
349 ptr = str + 1; ptr2 = out;
350 while ( *ptr != '\"' && *ptr )
351 {
352 if ( *ptr != '\\' )
353 *ptr2++ = *ptr++;
354 else{
355 ptr++;
356 switch ( *ptr )
357 {
358 case 'b': *ptr2++ = '\b'; break;
359 case 'f': *ptr2++ = '\f'; break;
360 case 'n': *ptr2++ = '\n'; break;
361 case 'r': *ptr2++ = '\r'; break;
362 case 't': *ptr2++ = '\t'; break;
363 case 'u': /* transcode utf16 to utf8. */
364 uc = parse_hex4( ptr + 1 ); ptr += 4; /* get the unicode char. */
365
366 if ( (uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0 )
367 break; /* check for invalid. */
368
369 if ( uc >= 0xD800 && uc <= 0xDBFF ) /* UTF16 surrogate pairs. */
370 {
371 if ( ptr[1] != '\\' || ptr[2] != 'u' )
372 break; /* missing second-half of surrogate. */
373 uc2 = parse_hex4( ptr + 3 ); ptr += 6;
374 if ( uc2 < 0xDC00 || uc2 > 0xDFFF )
375 break; /* invalid second-half of surrogate. */
376 uc = 0x10000 + ( ( (uc & 0x3FF) << 10) | (uc2 & 0x3FF));
377 }
378
379 len = 4; if ( uc < 0x80 )
380 len = 1;
381 else if ( uc < 0x800 )
382 len = 2;
383 else if ( uc < 0x10000 )
384 len = 3;
385 ptr2 += len;
386
387 switch ( len )
388 {
389 case 4: *--ptr2 = ( (uc | 0x80) & 0xBF); uc >>= 6;
390 case 3: *--ptr2 = ( (uc | 0x80) & 0xBF); uc >>= 6;
391 case 2: *--ptr2 = ( (uc | 0x80) & 0xBF); uc >>= 6;
392 case 1: *--ptr2 = (uc | firstByteMark[len]);
393 }
394 ptr2 += len;
395 break;
396 default: *ptr2++ = *ptr; break;
397 }
398 ptr++;
399 }
400 }
401 *ptr2 = 0;
402 if ( *ptr == '\"' )
403 ptr++;
404 item->valuestring = out;
405 item->type = cJSON_String;
406 return(ptr);
407 }
408
409
410 /* Render the cstring provided to an escaped version that can be printed. */
411 static char *print_string_ptr( const char *str )
412 {
413 /**
414 * 局部变量说明:
415 * 1.ptr : 指向参数传入的str字符串;
416 * 2.ptr2 : 指向要输出的out字符串;
417 * 3.out : 输出字符串;
418 * 4.len : 输出字符串的长度,用于内存分配出输出字符串的空间大小;
419 * 5.token : 字符保存中间变量.
420 */
421 const char *ptr;
422 char *ptr2, *out;
423 int len = 0;
424 unsigned char token;
425
426 if ( !str )
427 return(cJSON_strdup( "" ));
428 /* 计算字符串需要的长度 */
429 ptr = str;
430 while ( (token = *ptr) && ++len )
431 {
432 if ( strchr( "\"\\\b\f\n\r\t", token ))
433 len++;
434 else if ( token < 32 )
435 /**
436 * 除了前面列出的空白字符,其他的空白都+5的长度,
437 * 不知道为什么,应该与unicode编码有关.
438 * 如:
439 * "\uxxxx",u再加4个字符就是5个字符,前面解析字符的时候是这么解析的.
440 */
441 len += 5;
442 ptr++;
443 }
444
445 out = (char *) cJSON_malloc( len + 3 );
446 if ( !out )
447 return(0);
448
449 ptr2 = out; ptr = str;
450 *ptr2++ = '\"';
451 while ( *ptr )
452 {
453 if ( (unsigned char) *ptr > 31 && *ptr != '\"' && *ptr != '\\' )
454 *ptr2++ = *ptr++;
455 else{
456 *ptr2++ = '\\';
457 switch ( token = *ptr++ )
458 {
459 case '\\': *ptr2++ = '\\'; break;
460 case '\"': *ptr2++ = '\"'; break;
461 case '\b': *ptr2++ = 'b'; break;
462 case '\f': *ptr2++ = 'f'; break;
463 case '\n': *ptr2++ = 'n'; break;
464 case '\r': *ptr2++ = 'r'; break;
465 case '\t': *ptr2++ = 't'; break;
466 default: sprintf( ptr2, "u%04x", token ); ptr2 += 5; break; /* escape and print */
467 }
468 }
469 }
470 *ptr2++ = '\"'; *ptr2++ = 0;
471 return(out);
472 }
473
474
475 /* Invote print_string_ptr (which is useful) on an item. */
476 static char *print_string( cJSON *item )
477 {
478 return(print_string_ptr( item->valuestring ));
479 }
480
481
482 /* Predeclare these prototypes. --> 提前声明这些原型 */
483 static const char *parse_value( cJSON *item, const char *value );
484 static char *print_value( cJSON *item, int depth, int fmt );
485 static const char *parse_array( cJSON *item, const char *value );
486 static char *print_array( cJSON *item, int depth, int fmt );
487 static const char *parse_object( cJSON *item, const char *value );
488 static char *print_object( cJSON *item, int depth, int fmt );
489
490 /* Utility to jump whitespace and cr/lf --> 跳过不可见字符,这些字符都集中在ascii的前32个字符 */
491 static const char *skip( const char *in )
492 {
493 while ( in && *in && (unsigned char) *in <= 32 )
494 in++;
495 return(in);
496 }
497
498
499 /* Parse an object - create a new root, and populate. --> 创建一个根,并填充 */
500 cJSON *cJSON_ParseWithOpts( const char *value, const char **return_parse_end, int require_null_terminated )
501 {
502 /**
503 * 局部变量说明:
504 * 1.end : 当解析完整个字符串的时候,最后一个字符如果不是NULL,则代表这个输入的value字串
505 * 可能有问题;
506 * 2.c : cJSON节点,也是所谓的根节点.
507 */
508 const char *end = 0;
509 cJSON *c = cJSON_New_Item();
510 ep = 0;
511 if ( !c )
512 return(0); /* memory fail */
513
514 end = parse_value( c, skip( value ));
515 if ( !end )
516 {
517 cJSON_Delete( c ); return(0);
518 } /* parse failure. ep is set. */
519
520 /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
521 /* 检查是否是正常的JSON结束字符串 */
522 if ( require_null_terminated )
523 {
524 end = skip( end );
525 if ( *end )
526 {
527 cJSON_Delete( c ); ep = end; return(0);
528 }
529 }
530 if ( return_parse_end )
531 *return_parse_end = end;
532 return(c);
533 }
534
535
536 /* Default options for cJSON_Parse, 默认不检查NULL终止符 */
537 cJSON *cJSON_Parse( const char *value )
538 {
539 return(cJSON_ParseWithOpts( value, 0, 0 ));
540 }
541
542
543 /* Render a cJSON item/entity/structure to text. */
544 /**
545 * print_value中的
546 * 第二个参数是代表JSON对象的深度;
547 * 地三个代码中的意思是逗号分割键值对后面是否要加空格,
548 *
549 * 如下是第三个参数事例:
550 * fmt = 0 : {"zjf":1,"jfz":2,"fjz":3}或[1,2,3,4]
551 * fmt = 1 : {"zjf":1, "jfz":2, "fjz":3}或[1, 2, 3, 4]
552 *
553 * 如上,这里提供了2中选择供我们选择使用.
554 */
555 char *cJSON_Print( cJSON *item )
556 {
557 return(print_value( item, 0, 1 ));
558 }
559
560
561 char *cJSON_PrintUnformatted( cJSON *item )
562 {
563 return(print_value( item, 0, 0 ));
564 }
565
566
567 /* Parser core - when encountering text, process appropriately. */
568 /**
569 * 根据首字符的不同来决定采用哪种方式进行解析字符串
570 */
571 static const char *parse_value( cJSON *item, const char *value )
572 {
573 if ( !value )
574 return(0); /* Fail on null. */
575 if ( !strncmp( value, "null", 4 )) { item->type = cJSON_NULL; return(value + 4); }
576 if ( !strncmp( value, "false", 5 )) { item->type = cJSON_False; return(value + 5); }
577 if ( !strncmp( value, "true", 4 )) {
578 item->type = cJSON_True; item->valueint = 1; return(value + 4);
579 }
580 if ( *value == '\"' ) { return(parse_string( item, value )); }
581 if ( *value == '-' || (*value >= '0' && *value <= '9')) {
582 return(parse_number( item, value ));
583 }
584 if ( *value == '[' ) { return(parse_array( item, value )); }
585 if ( *value == '{' ) { return(parse_object( item, value )); }
586
587 ep = value; return(0); /* failure. */
588 }
589
590
591 /* Render a value to text. */
592 /**
593 * 根据item的类型来选这使用哪种方式进行数据的输出格式
594 */
595 static char *print_value( cJSON *item, int depth, int fmt )
596 {
597 char *out = 0;
598 if ( !item )
599 return(0);
600 switch ( (item->type) & 255 )
601 {
602 case cJSON_NULL: out = cJSON_strdup( "null" ); break;
603 case cJSON_False: out = cJSON_strdup( "false" ); break;
604 case cJSON_True: out = cJSON_strdup( "true" ); break;
605 case cJSON_Number: out = print_number( item ); break;
606 case cJSON_String: out = print_string( item ); break;
607 case cJSON_Array: out = print_array( item, depth, fmt ); break;
608 case cJSON_Object: out = print_object( item, depth, fmt ); break;
609 }
610 return(out);
611 }
612
613
614 /* Build an array from input text. */
615 /**
616 * 以以下数据为格式分析:
617 * [
618 * [0, -1, 0],
619 * [1, 0, 0],
620 * [0, 0, 1]
621 * ]
622 *
623 * 1.先检测到[;
624 * 2.然后skip掉换行符,空白字符;
625 * 3.parse_value重新检测字符串,也就能再次检测又是一个数组了[0, -1, 0],
626 * 递归进入解析[0, -1, 0],并解析出0,-1,0,保存在节点中.
627 * 4.检测是否遇到','字符,如果遇到说明后面还有内容需要解析;
628 * 5.循环解析接下来的内容.
629 */
630 static const char *parse_array( cJSON *item, const char *value )
631 {
632 cJSON *child;
633 if ( *value != '[' )
634 {
635 ep = value; return(0);
636 } /* not an array! */
637
638 item->type = cJSON_Array;
639 value = skip( value + 1 );
640 if ( *value == ']' )
641 return(value + 1); /* empty array. */
642
643 item->child = child = cJSON_New_Item();
644 if ( !item->child )
645 return(0); /* memory fail */
646 value = skip( parse_value( child, skip( value ))); /* skip any spacing, get the value. */
647 if ( !value )
648 return(0);
649
650 while ( *value == ',' )
651 {
652 cJSON *new_item;
653 if ( !(new_item = cJSON_New_Item()))
654 return(0); /* memory fail */
655 child->next = new_item; new_item->prev = child; child = new_item;
656 value = skip( parse_value( child, skip( value + 1 )));
657 if ( !value )
658 return(0); /* memory fail */
659 }
660
661 if ( *value == ']' )
662 return(value + 1); /* end of array */
663 ep = value; return(0); /* malformed. --> 格式不正确 */
664 }
665
666
667 /* Render an array to text */
668 static char *print_array( cJSON *item, int depth, int fmt )
669 {
670 /**
671 * 局部变量说明:
672 * 1.entries : 输出字符串数组,本来是保存在节点中的,被提取取来报存在字符串数组中;
673 * 2.out : 合并entries字符数组中的字符串,得到out;
674 * 3.ptr : 指向out的指针;
675 * 4.ret : 函数执行结果的返回值;
676 * 5.len : 用于统计总的字符长度;
677 * 6.child : 用于指向当前正要处理的节点;
678 * 7.numentries : 用于统计总共有多少个entries;
679 * 8.i : for循环计数;
680 * 9.fail : 处理出错标志.
681 */
682 char **entries;
683 char *out = 0, *ptr, *ret;
684 int len = 5;
685 cJSON *child = item->child;
686 int numentries = 0 /*number entries*/, i = 0, fail = 0;
687
688 /* How many entries in the array? */
689 while ( child )
690 numentries++, child = child->next;
691 /* Explicitly handle numentries==0 --> 显示处理条目为0的情况 */
692 if ( !numentries )
693 {
694 out = (char *) cJSON_malloc( 3 );
695 if ( out )
696 strcpy( out, "[]" );
697 return(out);
698 }
699 /* Allocate an array to hold the values for each */
700 entries = (char * *) cJSON_malloc( numentries * sizeof(char*));
701 if ( !entries )
702 return(0);
703 memset( entries, 0, numentries * sizeof(char*));
704 /* Retrieve all the results: --> 恢复结果 */
705 child = item->child;
706 while ( child && !fail )
707 {
708 ret = print_value( child, depth + 1, fmt );
709 entries[i++] = ret;
710 if ( ret )
711 /**
712 * 为什么要加2,目前只发现需要加1就够了,因为就加了一个逗号.
713 * 不知何故........
714 * 难道是为了给那对[]留下空间?
715 */
716 len += strlen( ret ) + 2 + (fmt ? 1 : 0);
717 else fail = 1;
718 child = child->next;
719 }
720
721 /* If we didn't fail, try to malloc the output string */
722 if ( !fail )
723 out = (char *) cJSON_malloc( len );
724 /* If that fails, we fail. */
725 if ( !out )
726 fail = 1;
727
728 /* Handle failure. */
729 if ( fail )
730 {
731 for ( i = 0; i < numentries; i++ )
732 if ( entries[i] )
733 cJSON_free( entries[i] );
734 cJSON_free( entries );
735 return(0);
736 }
737
738 /* Compose the output array. --> 合成输出数组 */
739 *out = '[';
740 ptr = out + 1; *ptr = 0;
741 for ( i = 0; i < numentries; i++ )
742 {
743 strcpy( ptr, entries[i] ); ptr += strlen( entries[i] );
744 if ( i != numentries - 1 )
745 {
746 *ptr++ = ','; /* 字符和分割符 */
747 if ( fmt ) *ptr++ = ' '; /* 一个格式字符 */
748 *ptr = 0; /* 每次都结束当前字符串,但是运行后续代码,又会被取代 */
749 }
750 cJSON_free( entries[i] );
751 }
752 cJSON_free( entries );
753 *ptr++ = ']'; *ptr++ = 0;
754 return(out);
755 }
756
757
758 /* Build an object from the text. */
759 /**
760 * 以下数据为格式分析:
761 * {
762 * "name": "Jack (\"Bee\") Nimble",
763 * "format": {
764 * "type": "rect",
765 * "width": 1920,
766 * "height": 1080,
767 * "interlace": false,
768 * "frame rate": 24
769 * }
770 * }
771 *
772 * 1.检测到'{';
773 * 2.跳过空白字符,换行符;
774 * 3.通过parse_string获取name;
775 * 4.判断键值对标识符':';
776 * 5.通过parse_value获取对应的value;
777 * 6.parse_value和前面的几个函数一样,是递归函数;
778 * 7.通过while循环解析剩下的键值对.
779 */
780 static const char *parse_object( cJSON *item, const char *value )
781 {
782 cJSON *child;
783 if ( *value != '{' )
784 {
785 ep = value; return(0);
786 } /* not an object! */
787
788 item->type = cJSON_Object;
789 value = skip( value + 1 );
790 if ( *value == '}' )
791 return(value + 1); /* empty array. */
792
793 item->child = child = cJSON_New_Item();
794 if ( !item->child )
795 return(0);
796 value = skip( parse_string( child, skip( value )));
797 if ( !value )
798 return(0);
799 child->string = child->valuestring; child->valuestring = 0;
800 if ( *value != ':' )
801 {
802 ep = value; return(0);
803 } /* fail! */
804 value = skip( parse_value( child, skip( value + 1 ))); /* skip any spacing, get the value. */
805 if ( !value )
806 return(0);
807
808 while ( *value == ',' )
809 {
810 cJSON *new_item;
811 if ( !(new_item = cJSON_New_Item()))
812 return(0); /* memory fail */
813 child->next = new_item; new_item->prev = child; child = new_item;
814 value = skip( parse_string( child, skip( value + 1 )));
815 if ( !value )
816 return(0);
817 child->string = child->valuestring; child->valuestring = 0;
818 if ( *value != ':' )
819 {
820 ep = value; return(0);
821 } /* fail! */
822 value = skip( parse_value( child, skip( value + 1 ))); /* skip any spacing, get the value. */
823 if ( !value )
824 return(0);
825 }
826
827 if ( *value == '}' )
828 return(value + 1); /* end of array */
829 ep = value; return(0); /* malformed. */
830 }
831
832
833 /* Render an object to text. */
834 /* 该函数和前面的print_array()相似 */
835 static char *print_object( cJSON *item, int depth, int fmt )
836 {
837 /**
838 * 局部变量说明:
839 * 1.entries : 键值对的value;
840 * 2.names : 键值对的key;
841 * 3.out : 指向输出的字符串;
842 * 4.ptr : 指向out输出的字符串;
843 * 5.ret : 执行函数时返回的字符串地址;
844 * 6.str : 执行函数返回的字符串的地址;
845 * 7.len : 字符串的长度;
846 * 8.i : for循环用于计数的变量;
847 * 9.j : for循环用于计数的变量;
848 * 10.child : 指向节点的指针;
849 * 11.fail : 输出出错时的标志;
850 * 12.numentries : 用于统计当前结构深度层次上的节点个数
851 */
852 char **entries = 0, **names = 0;
853 char *out = 0, *ptr, *ret, *str;
854 int len = 7, i = 0, j;
855 cJSON *child = item->child;
856 int numentries = 0, fail = 0;
857 /* Count the number of entries. */
858 while ( child )
859 numentries++, child = child->next;
860 /* Explicitly handle empty object case */
861 if ( !numentries )
862 {
863 out = (char *) cJSON_malloc( fmt ? depth + 4 : 3 );
864 if ( !out )
865 return(0);
866 ptr = out; *ptr++ = '{';
867 if ( fmt )
868 {
869 *ptr++ = '\n';
870 for ( i = 0; i < depth - 1; i++ )
871 *ptr++ = '\t';
872 }
873 *ptr++ = '}'; *ptr++ = 0;
874 return(out);
875 }
876 /* Allocate space for the names and the objects */
877 entries = (char **) cJSON_malloc( numentries * sizeof(char*));
878 if ( !entries )
879 return(0);
880 names = (char **) cJSON_malloc( numentries * sizeof(char*));
881 if ( !names )
882 {
883 cJSON_free( entries ); return(0);
884 }
885 memset( entries, 0, sizeof(char*) * numentries );
886 memset( names, 0, sizeof(char*) * numentries );
887
888 /* Collect all the results into our arrays: */
889 child = item->child; depth++; if ( fmt )
890 len += depth;
891 while ( child )
892 {
893 names[i] = str = print_string_ptr( child->string );
894 entries[i++] = ret = print_value( child, depth, fmt );
895 if ( str && ret )
896 len += strlen( ret ) + strlen( str ) + 2 + (fmt ? 2 + depth : 0);
897 else fail = 1;
898 child = child->next;
899 }
900
901 /* Try to allocate the output string */
902 if ( !fail )
903 out = (char *) cJSON_malloc( len );
904 if ( !out )
905 fail = 1;
906
907 /* Handle failure */
908 if ( fail )
909 {
910 for ( i = 0; i < numentries; i++ )
911 {
912 if ( names[i] )
913 cJSON_free( names[i] );
914 if ( entries[i] )
915 cJSON_free( entries[i] );
916 }
917 cJSON_free( names ); cJSON_free( entries );
918 return(0);
919 }
920
921 /* Compose the output: */
922 *out = '{';
923 ptr = out + 1;
924 if ( fmt )
925 *ptr++ = '\n';
926 *ptr = 0;
927 for ( i = 0; i < numentries; i++ )
928 {
929 if ( fmt )
930 for ( j = 0; j < depth; j++ )
931 *ptr++ = '\t';
932 strcpy( ptr, names[i] );
933 ptr += strlen( names[i] );
934 *ptr++ = ':';
935 if ( fmt )
936 *ptr++ = '\t';
937 strcpy( ptr, entries[i] );
938 ptr += strlen( entries[i] );
939 if ( i != numentries - 1 )
940 *ptr++ = ',';
941 if ( fmt )
942 *ptr++ = '\n';
943 *ptr = 0;
944 cJSON_free( names[i] );
945 cJSON_free( entries[i] );
946 }
947
948 cJSON_free( names );
949 cJSON_free( entries );
950 if ( fmt )
951 for ( i = 0; i < depth - 1; i++ )
952 *ptr++ = '\t';
953 *ptr++ = '}';
954 *ptr++ = 0;
955 return(out);
956 }
957
958
959 /* Get Array size/item / object item. */
960 int cJSON_GetArraySize( cJSON *array )
961 {
962 cJSON *c = array->child; int i = 0; while ( c )
963 i++, c = c->next;
964 return(i);
965 }
966
967
968 cJSON *cJSON_GetArrayItem( cJSON *array, int item )
969 {
970 cJSON *c = array->child; while ( c && item > 0 )
971 item--, c = c->next;
972 return(c);
973 }
974
975
976 cJSON *cJSON_GetObjectItem( cJSON *object, const char *string )
977 {
978 cJSON *c = object->child; while ( c && cJSON_strcasecmp( c->string, string ))
979 c = c->next;
980 return(c);
981 }
982
983
984 /* Utility for array list handling. --> 在当前节点的后面添加一个节点 */
985 static void suffix_object( cJSON *prev, cJSON *item )
986 {
987 prev->next = item; item->prev = prev;
988 }
989
990
991 /* Utility for handling references. */
992 static cJSON *create_reference( cJSON *item )
993 {
994 cJSON *ref = cJSON_New_Item();
995 if ( !ref )
996 return(0);
997 memcpy( ref, item, sizeof(cJSON));
998 ref->string = 0;
999 ref->type |= cJSON_IsReference;
1000 ref->next = ref->prev = 0;
1001 return(ref);
1002 }
1003
1004
1005 /* Add item to array/object. */
1006 void cJSON_AddItemToArray( cJSON *array, cJSON *item )
1007 {
1008 cJSON *c = array->child;
1009 if ( !item )
1010 return;
1011 if ( !c )
1012 {
1013 array->child = item;
1014 }
1015 else
1016 {
1017 while ( c && c->next )
1018 c = c->next;
1019 suffix_object( c, item );
1020 }
1021 }
1022
1023
1024 void cJSON_AddItemToObject( cJSON *object, const char *string, cJSON *item )
1025 {
1026 if ( !item )
1027 return;
1028 if ( item->string )
1029 cJSON_free( item->string );
1030 item->string = cJSON_strdup( string );
1031 cJSON_AddItemToArray( object, item );
1032 }
1033
1034
1035 void cJSON_AddItemReferenceToArray( cJSON *array, cJSON *item )
1036 {
1037 cJSON_AddItemToArray( array, create_reference( item ));
1038 }
1039
1040
1041 void cJSON_AddItemReferenceToObject( cJSON *object, const char *string, cJSON *item )
1042 {
1043 cJSON_AddItemToObject( object, string, create_reference( item ));
1044 }
1045
1046
1047 cJSON *cJSON_DetachItemFromArray( cJSON *array, int which )
1048 {
1049 cJSON *c = array->child;
1050 while ( c && which > 0 )
1051 c = c->next, which--;
1052
1053 if ( !c )
1054 return(0);
1055 if ( c->prev )
1056 c->prev->next = c->next;
1057 if ( c->next )
1058 c->next->prev = c->prev;
1059 if ( c == array->child )
1060 array->child = c->next;
1061 c->prev = c->next = 0;
1062 return(c);
1063 }
1064
1065
1066 void cJSON_DeleteItemFromArray( cJSON *array, int which )
1067 {
1068 cJSON_Delete( cJSON_DetachItemFromArray( array, which ));
1069 }
1070
1071
1072 cJSON *cJSON_DetachItemFromObject( cJSON *object, const char *string )
1073 {
1074 int i = 0; cJSON *c = object->child;
1075 while ( c && cJSON_strcasecmp( c->string, string ))
1076 i++, c = c->next;
1077 if ( c )
1078 return(cJSON_DetachItemFromArray( object, i ));
1079 return(0);
1080 }
1081
1082
1083 void cJSON_DeleteItemFromObject( cJSON *object, const char *string )
1084 {
1085 cJSON_Delete( cJSON_DetachItemFromObject( object, string ));
1086 }
1087
1088
1089 /* Replace array/object items with new ones. */
1090 void cJSON_ReplaceItemInArray( cJSON *array, int which, cJSON *newitem )
1091 {
1092 cJSON *c = array->child;
1093 while ( c && which > 0 )
1094 c = c->next, which--;
1095 if ( !c )
1096 return;
1097 newitem->next = c->next;
1098 newitem->prev = c->prev;
1099 if ( newitem->next )
1100 newitem->next->prev = newitem;
1101 if ( c == array->child )
1102 array->child = newitem;
1103 else
1104 newitem->prev->next = newitem;
1105 c->next = c->prev = 0;
1106 cJSON_Delete( c );
1107 }
1108
1109
1110 void cJSON_ReplaceItemInObject( cJSON *object, const char *string, cJSON *newitem )
1111 {
1112 int i = 0;
1113 cJSON *c = object->child;
1114 while ( c && cJSON_strcasecmp( c->string, string ))
1115 i++, c = c->next;
1116 if ( c )
1117 {
1118 newitem->string = cJSON_strdup( string );
1119 cJSON_ReplaceItemInArray( object, i, newitem );
1120 }
1121 }
1122
1123
1124 /* Create basic types: */
1125 cJSON *cJSON_CreateNull( void )
1126 {
1127 cJSON *item = cJSON_New_Item();
1128 if ( item )
1129 item->type = cJSON_NULL;
1130 return(item);
1131 }
1132
1133
1134 cJSON *cJSON_CreateTrue( void )
1135 {
1136 cJSON *item = cJSON_New_Item();
1137 if ( item )
1138 item->type = cJSON_True;
1139 return(item);
1140 }
1141
1142
1143 cJSON *cJSON_CreateFalse( void )
1144 {
1145 cJSON *item = cJSON_New_Item();
1146 if ( item )
1147 item->type = cJSON_False;
1148 return(item);
1149 }
1150
1151
1152 cJSON *cJSON_CreateBool( int b )
1153 {
1154 cJSON *item = cJSON_New_Item();
1155 if ( item )
1156 item->type = b ? cJSON_True : cJSON_False;
1157 return(item);
1158 }
1159
1160
1161 cJSON *cJSON_CreateNumber( double num )
1162 {
1163 cJSON *item = cJSON_New_Item();
1164 if ( item )
1165 {
1166 item->type = cJSON_Number;
1167 item->valuedouble = num;
1168 item->valueint = (int) num;
1169 }
1170 return(item);
1171 }
1172
1173
1174 cJSON *cJSON_CreateString( const char *string )
1175 {
1176 cJSON *item = cJSON_New_Item();
1177 if ( item )
1178 {
1179 item->type = cJSON_String;
1180 item->valuestring = cJSON_strdup( string );
1181 }
1182 return(item);
1183 }
1184
1185
1186 cJSON *cJSON_CreateArray( void )
1187 {
1188 cJSON *item = cJSON_New_Item();
1189 if ( item )
1190 item->type = cJSON_Array;
1191 return(item);
1192 }
1193
1194
1195 cJSON *cJSON_CreateObject( void )
1196 {
1197 cJSON *item = cJSON_New_Item();
1198 if ( item )
1199 item->type = cJSON_Object;
1200 return(item);
1201 }
1202
1203
1204 /* Create Arrays: */
1205 cJSON *cJSON_CreateIntArray( const int *numbers, int count )
1206 {
1207 int i;
1208 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1209 for ( i = 0; a && i < count; i++ )
1210 {
1211 n = cJSON_CreateNumber( numbers[i] );
1212 if ( !i )
1213 a->child = n;
1214 else
1215 suffix_object( p, n );
1216 p = n;
1217 }
1218 return(a);
1219 }
1220
1221
1222 cJSON *cJSON_CreateFloatArray( const float *numbers, int count )
1223 {
1224 int i;
1225 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1226 for ( i = 0; a && i < count; i++ )
1227 {
1228 n = cJSON_CreateNumber( numbers[i] );
1229 if ( !i )
1230 a->child = n;
1231 else
1232 suffix_object( p, n );
1233 p = n;
1234 }
1235 return(a);
1236 }
1237
1238
1239 cJSON *cJSON_CreateDoubleArray( const double *numbers, int count )
1240 {
1241 int i;
1242 cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1243 for ( i = 0; a && i < count; i++ )
1244 {
1245 n = cJSON_CreateNumber( numbers[i] );
1246 if ( !i )
1247 a->child = n;
1248 else
1249 suffix_object( p, n );
1250 p = n;
1251 }
1252 return(a);
1253 }
1254
1255
1256 cJSON *cJSON_CreateStringArray( const char **strings, int count )
1257 {
1258 int i; cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1259 for ( i = 0; a && i < count; i++ )
1260 {
1261 n = cJSON_CreateString( strings[i] );
1262 if ( !i )
1263 a->child = n;
1264 else
1265 suffix_object( p, n );
1266 p = n;
1267 }
1268 return(a);
1269 }
1270
1271
1272 /* Duplication */
1273 cJSON *cJSON_Duplicate( cJSON *item, int recurse )
1274 {
1275 cJSON *newitem, *cptr, *nptr = 0, *newchild;
1276 /* Bail on bad ptr */
1277 if ( !item )
1278 return(0);
1279 /* Create new item */
1280 newitem = cJSON_New_Item();
1281 if ( !newitem )
1282 return(0);
1283 /* Copy over all vars */
1284 newitem->type = item->type & (~cJSON_IsReference), newitem->valueint = item->valueint, newitem->valuedouble = item->valuedouble;
1285 if ( item->valuestring )
1286 {
1287 newitem->valuestring = cJSON_strdup( item->valuestring ); if ( !newitem->valuestring )
1288 {
1289 cJSON_Delete( newitem ); return(0);
1290 }
1291 }
1292 if ( item->string )
1293 {
1294 newitem->string = cJSON_strdup( item->string ); if ( !newitem->string )
1295 {
1296 cJSON_Delete( newitem ); return(0);
1297 }
1298 }
1299 /* If non-recursive, then we're done! */
1300 if ( !recurse )
1301 return(newitem);
1302 /* Walk the ->next chain for the child. */
1303 cptr = item->child;
1304 while ( cptr )
1305 {
1306 newchild = cJSON_Duplicate( cptr, 1 ); /* Duplicate (with recurse) each item in the ->next chain */
1307 if ( !newchild )
1308 {
1309 cJSON_Delete( newitem ); return(0);
1310 }
1311 if ( nptr )
1312 {
1313 nptr->next = newchild, newchild->prev = nptr; nptr = newchild;
1314 } /* If newitem->child already set, then crosswire ->prev and ->next and move on */
1315 else { newitem->child = newchild; nptr = newchild; } /* Set newitem->child and move to it */
1316 cptr = cptr->next;
1317 }
1318 return(newitem);
1319 }
1320
1321
1322 void cJSON_Minify( char *json )
1323 {
1324 char *into = json;
1325 while ( *json )
1326 {
1327 if ( *json == ' ' )
1328 json++;
1329 else if ( *json == '\t' )
1330 json++; /* Whitespace characters. */
1331 else if ( *json == '\r' )
1332 json++;
1333 else if ( *json == '\n' )
1334 json++;
1335 else if ( *json == '/' && json[1] == '/' )
1336 while ( *json && *json != '\n' )
1337 json++;
1338 /* double-slash comments, to end of line. */
1339 else if ( *json == '/' && json[1] == '*' )
1340 {
1341 while ( *json && !(*json == '*' && json[1] == '/'))
1342 json++;
1343 json += 2;
1344 } /* multiline comments. */
1345 else if ( *json == '\"' )
1346 {
1347 *into++ = *json++; while ( *json && *json != '\"' )
1348 {
1349 if ( *json == '\\' )
1350 *into++ = *json++;
1351 *into++ = *json++;
1352 }
1353 *into++ = *json++;
1354 } /* string literals, which are \" sensitive. */
1355 else *into++ = *json++; /* All other characters. */
1356 }
1357 *into = 0; /* and null-terminate. */
1358 }