cJSON_hacking
/******************************************************************************
* cJSON_hacking
*
* 1.这是cJSON中cJSON.c(主程序)的源码,源码不到1000行(除注释).
* 2.本文仅仅注释了源码中JSON解析部分,对链表的操作没有进行任何注释,通过
* 分析阅读该源码,可以一窥双向链表,字符串处理,里面几个地方使用到了递归,
* 而且用得很精妙,但在理解上可能会有点困难.
* 3.源码作者在解析JSON时参考了: http://www.json.org/fatfree.html
* 如果您要阅读本程序,请先阅读该网页内容,因为源码中几个重要的函数的处理
* 都参照了该网页上的处理算法.
* 4.知识量:
* 1.C语言;
* 2.2.Unix或类Unix系统编程;
* 3.对双向链表的数据结构清晰;
* 5.如何阅读该源码:
* 1.linux下使用vi/vim配和ctags,windows下使用Source Insight,当然你也
* 可以用其他文本编辑器看.
* 2.该源码无主函数,本人自己是从第一个函数开始阅读,然后慢慢的看懂,
* 并了解了整个源码的大局,但本人强烈建议您从该函数开始阅读:
* cJSON *cJSON_Parse( const char *value ).
* 主要是因为这是默认的解析函数.
* 3.对于有些函数,本人没有添加注释,或者说本人觉得没必要.
* 4.祝您好运. :)
*
*
* 6.cJSON下载url: http://sourceforge.net/projects/cjson/
*
* 如果您对本文有任何意见、提议,可以发邮件至zengjf42@163.com,会尽快回复.
* 本文的最终解释权归本人(曾剑锋)所有,仅供学习、讨论.
*
* 2015-3-3 阴 深圳 尚观 Var
*
******************************************************************************/ /*
* Copyright (c) 2009 Dave Gamble
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/ /* cJSON */
/* JSON parser in C. */ #include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
#include <limits.h>
#include <ctype.h>
#include "cJSON.h" /**
* 返回解析出错时对应的字符地址.
*/
static const char *ep; /* error pointer */
const char *cJSON_GetErrorPtr( void )
{
return(ep);
} /**
* 不分大小写字符串比较,感觉和原生的strcasecmp没什么区别.
*/
static int cJSON_strcasecmp( const char *s1, const char *s2 )
{
if ( !s1 )
return( (s1 == s2) ? : );
if ( !s2 )
return();
for (; tolower( *s1 ) == tolower( *s2 ); ++s1, ++s2 )
if ( *s1 == )
return();
return(tolower( *(const unsigned char *) s1 ) - tolower( *(const unsigned char *) s2 ));
} /**
* 定义cJSON中内存分配采用的方式,这里直接使用原生的malloc,free函数.
*/
static void *(*cJSON_malloc)(size_t sz) = malloc;
static void (*cJSON_free)( void *ptr ) = free; /**
* 定义cJSON中的字符串拷贝函数.
*/
static char* cJSON_strdup( const char* str )
{
size_t len;
char * copy; len = strlen( str ) + ;
if ( !(copy = (char *) cJSON_malloc( len )))
return();
memcpy( copy, str, len );
return(copy);
} /**
* 选择系统使用那种内存分配方式,这里使用原生的malloc、free函数.
*/
void cJSON_InitHooks( cJSON_Hooks* hooks )
{
if ( !hooks ) /* Reset hooks */
{
cJSON_malloc = malloc;
cJSON_free = free;
return;
} cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc;
cJSON_free = (hooks->free_fn) ? hooks->free_fn : free;
} /**
* 构造一个item,同时给item赋初始值为全0,item可以理解为一个节点.
*/
static cJSON *cJSON_New_Item( void )
{
cJSON* node = (cJSON *) cJSON_malloc( sizeof(cJSON));
if ( node )
memset( node, , sizeof(cJSON));
return(node);
} /**
* 释放链表,对于有子链表的链表,采用递归的方式进行内存释放.
* 目前还没找到为什么需要 c->type & cJSON_IsReference 判断.
*/
void cJSON_Delete( cJSON *c )
{
cJSON *next;
while ( c )
{
next = c->next;
if ( !(c->type & cJSON_IsReference) && c->child )
cJSON_Delete( c->child ); /* 递归释放内存 */
if ( !(c->type & cJSON_IsReference) && c->valuestring )
cJSON_free( c->valuestring );
if ( c->string )
cJSON_free( c->string );
cJSON_free( c );
c = next;
}
} /* Parse the input text to generate a number, and populate the result into item. */
/**
* 解析数字,并把数据保存在item中对应的的地方.
*/
static const char *parse_number( cJSON *item, const char *num )
{
/**
* 局部变量说明:
* 1.n : 用于保存数字;
* 2.sign : 数字部分的符号标志,如果是负数,就等于-1,如果是正数,就是1;
* 3.scale : 保存小数点后面有多少个数字的相反数;
* 4.subscale : 保存指数后面的数字;
* 5.signsubscale : 指数部分的符号标志,如果是负数,就等于-1,如果是正数,就是1.
*
* 如:
* num字符串: -1234.1234e4
* 1.n = 12341234;
* 2.sign = -1;
* 3.scale = -4;
* 4.subscale = 4;
* 5.signsubscale = 1;
*
* 结果公式 = sign * n * pow( 10.0, (scale + subscale * signsubscale))
* n = -1 * 12341234 * pow( 10.0, (-4 + 4 * 1))
* n = -12341234 * pow( 10.0, 0 )
* n = -12341234
*/
double n = , sign = , scale = ; int subscale = , signsubscale = ; if ( *num == '-' )
sign = -, num++; /* Has sign? */
if ( *num == '' )
num++; /* is zero */
if ( *num >= '' && *num <= '' )
do
n = (n * 10.0) + (*num++ - '');
while ( *num >= '' && *num <= '' ); /* Number? */
if ( *num == '.' && num[] >= '' && num[] <= '' )
{
num++;
do
n = (n * 10.0) + (*num++ - ''), scale--;
while ( *num >= '' && *num <= '' );
} /* Fractional part? --> 小数部分 */
if ( *num == 'e' || *num == 'E' ) /* Exponent? --> 指数部分 */
{
num++; if ( *num == '+' )
num++;
else if ( *num == '-' )
signsubscale = -, num++; /* With sign? */
while ( *num >= '' && *num <= '' )
subscale = (subscale * ) + (*num++ - ''); /* Number? */
} n = sign * n * pow( 10.0, (scale + subscale * signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ /**
* 以两种形式来保存数据,在下面的函数print_number()中输出数字的时候要比较这两个数据.
*/
item->valuedouble = n;
item->valueint = (int) n;
item->type = cJSON_Number;
return(num);
} /* Render the number nicely from the given item into a string. */
/**
* 下面代码中使用到DBL_EPSILON,其意思是双精度最小误差;
* 请参考url: http://blog.csdn.net/x356982611/article/details/19922453
*/
static char *print_number( cJSON *item )
{
/**
* 局部变量说明:
* 1.str : 用于指向输出的数字字符串;
* 2.d : 保存item中的double数字.
*/
char *str;
double d = item->valuedouble;
if ( fabs( ( (double) item->valueint) - d ) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN )
{
str = (char *) cJSON_malloc( ); /* 2^64+1 can be represented in 21 chars. */
if ( str )
sprintf( str, "%d", item->valueint );
}else {
str = (char *) cJSON_malloc( ); /* This is a nice tradeoff. */
if ( str )
{
if ( fabs( floor( d ) - d ) <= DBL_EPSILON && fabs( d ) < 1.0e60 )
sprintf( str, "%.0f", d );
else if ( fabs( d ) < 1.0e-6 || fabs( d ) > 1.0e9 )
sprintf( str, "%e", d );
else sprintf( str, "%f", d );
}
}
return(str);
} static unsigned parse_hex4( const char *str )
{
/**
* 局部变量说明:
* 1.h : 保存最终返回的数据
*/
unsigned h = ; if ( *str >= '' && *str <= '' )
h += (*str) - '';
else if ( *str >= 'A' && *str <= 'F' )
h += + (*str) - 'A';
else if ( *str >= 'a' && *str <= 'f' )
h += + (*str) - 'a';
else return(); h = h << ; str++; /* h = h << 4 <===> h = h * 16 */
if ( *str >= '' && *str <= '' )
h += (*str) - '';
else if ( *str >= 'A' && *str <= 'F' )
h += + (*str) - 'A';
else if ( *str >= 'a' && *str <= 'f' )
h += + (*str) - 'a';
else return(); h = h << ; str++;
if ( *str >= '' && *str <= '' )
h += (*str) - '';
else if ( *str >= 'A' && *str <= 'F' )
h += + (*str) - 'A';
else if ( *str >= 'a' && *str <= 'f' )
h += + (*str) - 'a';
else return(); h = h << ; str++;
if ( *str >= '' && *str <= '' )
h += (*str) - '';
else if ( *str >= 'A' && *str <= 'F' )
h += + (*str) - 'A';
else if ( *str >= 'a' && *str <= 'f' )
h += + (*str) - 'a';
else return();
return(h);
} /* Parse the input text into an unescaped cstring, and populate item. */
/* 将输入的文本分析到非转义cstring并填充item,目前不了解这里是什么情况 */
/* 不清楚这里的unicode编码格式字符的处理方式 */
static const unsigned char firstByteMark[] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
static const char *parse_string( cJSON *item, const char *str )
{
/**
* 局部变量说明:
* 1.ptr : 传入参数string的指针;
* 2.ptr2 : 指向输出字符串里的地址,主要用于从ptr字符串中拷贝字符到out中;
* 3.out : 指向动态分配的输出字符串的首地址;
* 4.len : 动态分配时需要的字符串的长度,分配时要在基础上+1;
* 5.uc : unicode编码格式字符;
* 6.uc2 : unicode编码格式字符.
*/
const char *ptr = str + ;
char *ptr2;
char *out;
int len = ;
unsigned uc, uc2; /* 判断第一个字符是否是"\"",如果不是,那么就不是字符串 */
if ( *str != '\"' ){ ep = str; return(); } /* not a string! */ /* 计算字符串的长度,为后面的的内存分配提供数据长度信息 */
while ( *ptr != '\"' && *ptr && ++len ) if ( *ptr++ == '\\' )
ptr++; /* Skip escaped quotes. */ out = (char *) cJSON_malloc( len + ); /* This is how long we need for the string, roughly. */
if ( !out )
return(); /* ptr指向'\"'后面那个字符,ptr2指向out的首地址,有利于数据拷贝 */
ptr = str + ; ptr2 = out;
while ( *ptr != '\"' && *ptr )
{
if ( *ptr != '\\' )
*ptr2++ = *ptr++;
else{
ptr++;
switch ( *ptr )
{
case 'b': *ptr2++ = '\b'; break;
case 'f': *ptr2++ = '\f'; break;
case 'n': *ptr2++ = '\n'; break;
case 'r': *ptr2++ = '\r'; break;
case 't': *ptr2++ = '\t'; break;
case 'u': /* transcode utf16 to utf8. */
uc = parse_hex4( ptr + ); ptr += ; /* get the unicode char. */ if ( (uc >= 0xDC00 && uc <= 0xDFFF) || uc == )
break; /* check for invalid. */ if ( uc >= 0xD800 && uc <= 0xDBFF ) /* UTF16 surrogate pairs. */
{
if ( ptr[] != '\\' || ptr[] != 'u' )
break; /* missing second-half of surrogate. */
uc2 = parse_hex4( ptr + ); ptr += ;
if ( uc2 < 0xDC00 || uc2 > 0xDFFF )
break; /* invalid second-half of surrogate. */
uc = 0x10000 + ( ( (uc & 0x3FF) << ) | (uc2 & 0x3FF));
} len = ; if ( uc < 0x80 )
len = ;
else if ( uc < 0x800 )
len = ;
else if ( uc < 0x10000 )
len = ;
ptr2 += len; switch ( len )
{
case : *--ptr2 = ( (uc | 0x80) & 0xBF); uc >>= ;
case : *--ptr2 = ( (uc | 0x80) & 0xBF); uc >>= ;
case : *--ptr2 = ( (uc | 0x80) & 0xBF); uc >>= ;
case : *--ptr2 = (uc | firstByteMark[len]);
}
ptr2 += len;
break;
default: *ptr2++ = *ptr; break;
}
ptr++;
}
}
*ptr2 = ;
if ( *ptr == '\"' )
ptr++;
item->valuestring = out;
item->type = cJSON_String;
return(ptr);
} /* Render the cstring provided to an escaped version that can be printed. */
static char *print_string_ptr( const char *str )
{
/**
* 局部变量说明:
* 1.ptr : 指向参数传入的str字符串;
* 2.ptr2 : 指向要输出的out字符串;
* 3.out : 输出字符串;
* 4.len : 输出字符串的长度,用于内存分配出输出字符串的空间大小;
* 5.token : 字符保存中间变量.
*/
const char *ptr;
char *ptr2, *out;
int len = ;
unsigned char token; if ( !str )
return(cJSON_strdup( "" ));
/* 计算字符串需要的长度 */
ptr = str;
while ( (token = *ptr) && ++len )
{
if ( strchr( "\"\\\b\f\n\r\t", token ))
len++;
else if ( token < )
/**
* 除了前面列出的空白字符,其他的空白都+5的长度,
* 不知道为什么,应该与unicode编码有关.
* 如:
* "\uxxxx",u再加4个字符就是5个字符,前面解析字符的时候是这么解析的.
*/
len += ;
ptr++;
} out = (char *) cJSON_malloc( len + );
if ( !out )
return(); ptr2 = out; ptr = str;
*ptr2++ = '\"';
while ( *ptr )
{
if ( (unsigned char) *ptr > && *ptr != '\"' && *ptr != '\\' )
*ptr2++ = *ptr++;
else{
*ptr2++ = '\\';
switch ( token = *ptr++ )
{
case '\\': *ptr2++ = '\\'; break;
case '\"': *ptr2++ = '\"'; break;
case '\b': *ptr2++ = 'b'; break;
case '\f': *ptr2++ = 'f'; break;
case '\n': *ptr2++ = 'n'; break;
case '\r': *ptr2++ = 'r'; break;
case '\t': *ptr2++ = 't'; break;
default: sprintf( ptr2, "u%04x", token ); ptr2 += ; break; /* escape and print */
}
}
}
*ptr2++ = '\"'; *ptr2++ = ;
return(out);
} /* Invote print_string_ptr (which is useful) on an item. */
static char *print_string( cJSON *item )
{
return(print_string_ptr( item->valuestring ));
} /* Predeclare these prototypes. --> 提前声明这些原型 */
static const char *parse_value( cJSON *item, const char *value );
static char *print_value( cJSON *item, int depth, int fmt );
static const char *parse_array( cJSON *item, const char *value );
static char *print_array( cJSON *item, int depth, int fmt );
static const char *parse_object( cJSON *item, const char *value );
static char *print_object( cJSON *item, int depth, int fmt ); /* Utility to jump whitespace and cr/lf --> 跳过不可见字符,这些字符都集中在ascii的前32个字符 */
static const char *skip( const char *in )
{
while ( in && *in && (unsigned char) *in <= )
in++;
return(in);
} /* Parse an object - create a new root, and populate. --> 创建一个根,并填充 */
cJSON *cJSON_ParseWithOpts( const char *value, const char **return_parse_end, int require_null_terminated )
{
/**
* 局部变量说明:
* 1.end : 当解析完整个字符串的时候,最后一个字符如果不是NULL,则代表这个输入的value字串
* 可能有问题;
* 2.c : cJSON节点,也是所谓的根节点.
*/
const char *end = ;
cJSON *c = cJSON_New_Item();
ep = ;
if ( !c )
return(); /* memory fail */ end = parse_value( c, skip( value ));
if ( !end )
{
cJSON_Delete( c ); return();
} /* parse failure. ep is set. */ /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
/* 检查是否是正常的JSON结束字符串 */
if ( require_null_terminated )
{
end = skip( end );
if ( *end )
{
cJSON_Delete( c ); ep = end; return();
}
}
if ( return_parse_end )
*return_parse_end = end;
return(c);
} /* Default options for cJSON_Parse, 默认不检查NULL终止符 */
cJSON *cJSON_Parse( const char *value )
{
return(cJSON_ParseWithOpts( value, , ));
} /* Render a cJSON item/entity/structure to text. */
/**
* print_value中的
* 第二个参数是代表JSON对象的深度;
* 地三个代码中的意思是逗号分割键值对后面是否要加空格,
*
* 如下是第三个参数事例:
* fmt = 0 : {"zjf":1,"jfz":2,"fjz":3}或[1,2,3,4]
* fmt = 1 : {"zjf":1, "jfz":2, "fjz":3}或[1, 2, 3, 4]
*
* 如上,这里提供了2中选择供我们选择使用.
*/
char *cJSON_Print( cJSON *item )
{
return(print_value( item, , ));
} char *cJSON_PrintUnformatted( cJSON *item )
{
return(print_value( item, , ));
} /* Parser core - when encountering text, process appropriately. */
/**
* 根据首字符的不同来决定采用哪种方式进行解析字符串
*/
static const char *parse_value( cJSON *item, const char *value )
{
if ( !value )
return(); /* Fail on null. */
if ( !strncmp( value, "null", )) { item->type = cJSON_NULL; return(value + ); }
if ( !strncmp( value, "false", )) { item->type = cJSON_False; return(value + ); }
if ( !strncmp( value, "true", )) {
item->type = cJSON_True; item->valueint = ; return(value + );
}
if ( *value == '\"' ) { return(parse_string( item, value )); }
if ( *value == '-' || (*value >= '' && *value <= '')) {
return(parse_number( item, value ));
}
if ( *value == '[' ) { return(parse_array( item, value )); }
if ( *value == '{' ) { return(parse_object( item, value )); } ep = value; return(); /* failure. */
} /* Render a value to text. */
/**
* 根据item的类型来选这使用哪种方式进行数据的输出格式
*/
static char *print_value( cJSON *item, int depth, int fmt )
{
char *out = ;
if ( !item )
return();
switch ( (item->type) & )
{
case cJSON_NULL: out = cJSON_strdup( "null" ); break;
case cJSON_False: out = cJSON_strdup( "false" ); break;
case cJSON_True: out = cJSON_strdup( "true" ); break;
case cJSON_Number: out = print_number( item ); break;
case cJSON_String: out = print_string( item ); break;
case cJSON_Array: out = print_array( item, depth, fmt ); break;
case cJSON_Object: out = print_object( item, depth, fmt ); break;
}
return(out);
} /* Build an array from input text. */
/**
* 以以下数据为格式分析:
* [
* [0, -1, 0],
* [1, 0, 0],
* [0, 0, 1]
* ]
*
* 1.先检测到[;
* 2.然后skip掉换行符,空白字符;
* 3.parse_value重新检测字符串,也就能再次检测又是一个数组了[0, -1, 0],
* 递归进入解析[0, -1, 0],并解析出0,-1,0,保存在节点中.
* 4.检测是否遇到','字符,如果遇到说明后面还有内容需要解析;
* 5.循环解析接下来的内容.
*/
static const char *parse_array( cJSON *item, const char *value )
{
cJSON *child;
if ( *value != '[' )
{
ep = value; return();
} /* not an array! */ item->type = cJSON_Array;
value = skip( value + );
if ( *value == ']' )
return(value + ); /* empty array. */ item->child = child = cJSON_New_Item();
if ( !item->child )
return(); /* memory fail */
value = skip( parse_value( child, skip( value ))); /* skip any spacing, get the value. */
if ( !value )
return(); while ( *value == ',' )
{
cJSON *new_item;
if ( !(new_item = cJSON_New_Item()))
return(); /* memory fail */
child->next = new_item; new_item->prev = child; child = new_item;
value = skip( parse_value( child, skip( value + )));
if ( !value )
return(); /* memory fail */
} if ( *value == ']' )
return(value + ); /* end of array */
ep = value; return(); /* malformed. --> 格式不正确 */
} /* Render an array to text */
static char *print_array( cJSON *item, int depth, int fmt )
{
/**
* 局部变量说明:
* 1.entries : 输出字符串数组,本来是保存在节点中的,被提取取来报存在字符串数组中;
* 2.out : 合并entries字符数组中的字符串,得到out;
* 3.ptr : 指向out的指针;
* 4.ret : 函数执行结果的返回值;
* 5.len : 用于统计总的字符长度;
* 6.child : 用于指向当前正要处理的节点;
* 7.numentries : 用于统计总共有多少个entries;
* 8.i : for循环计数;
* 9.fail : 处理出错标志.
*/
char **entries;
char *out = , *ptr, *ret;
int len = ;
cJSON *child = item->child;
int numentries = /*number entries*/, i = , fail = ; /* How many entries in the array? */
while ( child )
numentries++, child = child->next;
/* Explicitly handle numentries==0 --> 显示处理条目为0的情况 */
if ( !numentries )
{
out = (char *) cJSON_malloc( );
if ( out )
strcpy( out, "[]" );
return(out);
}
/* Allocate an array to hold the values for each */
entries = (char * *) cJSON_malloc( numentries * sizeof(char*));
if ( !entries )
return();
memset( entries, , numentries * sizeof(char*));
/* Retrieve all the results: --> 恢复结果 */
child = item->child;
while ( child && !fail )
{
ret = print_value( child, depth + , fmt );
entries[i++] = ret;
if ( ret )
/**
* 为什么要加2,目前只发现需要加1就够了,因为就加了一个逗号.
* 不知何故........
* 难道是为了给那对[]留下空间?
*/
len += strlen( ret ) + + (fmt ? : );
else fail = ;
child = child->next;
} /* If we didn't fail, try to malloc the output string */
if ( !fail )
out = (char *) cJSON_malloc( len );
/* If that fails, we fail. */
if ( !out )
fail = ; /* Handle failure. */
if ( fail )
{
for ( i = ; i < numentries; i++ )
if ( entries[i] )
cJSON_free( entries[i] );
cJSON_free( entries );
return();
} /* Compose the output array. --> 合成输出数组 */
*out = '[';
ptr = out + ; *ptr = ;
for ( i = ; i < numentries; i++ )
{
strcpy( ptr, entries[i] ); ptr += strlen( entries[i] );
if ( i != numentries - )
{
*ptr++ = ','; /* 字符和分割符 */
if ( fmt ) *ptr++ = ' '; /* 一个格式字符 */
*ptr = ; /* 每次都结束当前字符串,但是运行后续代码,又会被取代 */
}
cJSON_free( entries[i] );
}
cJSON_free( entries );
*ptr++ = ']'; *ptr++ = ;
return(out);
} /* Build an object from the text. */
/**
* 以下数据为格式分析:
* {
* "name": "Jack (\"Bee\") Nimble",
* "format": {
* "type": "rect",
* "width": 1920,
* "height": 1080,
* "interlace": false,
* "frame rate": 24
* }
* }
*
* 1.检测到'{';
* 2.跳过空白字符,换行符;
* 3.通过parse_string获取name;
* 4.判断键值对标识符':';
* 5.通过parse_value获取对应的value;
* 6.parse_value和前面的几个函数一样,是递归函数;
* 7.通过while循环解析剩下的键值对.
*/
static const char *parse_object( cJSON *item, const char *value )
{
cJSON *child;
if ( *value != '{' )
{
ep = value; return();
} /* not an object! */ item->type = cJSON_Object;
value = skip( value + );
if ( *value == '}' )
return(value + ); /* empty array. */ item->child = child = cJSON_New_Item();
if ( !item->child )
return();
value = skip( parse_string( child, skip( value )));
if ( !value )
return();
child->string = child->valuestring; child->valuestring = ;
if ( *value != ':' )
{
ep = value; return();
} /* fail! */
value = skip( parse_value( child, skip( value + ))); /* skip any spacing, get the value. */
if ( !value )
return(); while ( *value == ',' )
{
cJSON *new_item;
if ( !(new_item = cJSON_New_Item()))
return(); /* memory fail */
child->next = new_item; new_item->prev = child; child = new_item;
value = skip( parse_string( child, skip( value + )));
if ( !value )
return();
child->string = child->valuestring; child->valuestring = ;
if ( *value != ':' )
{
ep = value; return();
} /* fail! */
value = skip( parse_value( child, skip( value + ))); /* skip any spacing, get the value. */
if ( !value )
return();
} if ( *value == '}' )
return(value + ); /* end of array */
ep = value; return(); /* malformed. */
} /* Render an object to text. */
/* 该函数和前面的print_array()相似 */
static char *print_object( cJSON *item, int depth, int fmt )
{
/**
* 局部变量说明:
* 1.entries : 键值对的value;
* 2.names : 键值对的key;
* 3.out : 指向输出的字符串;
* 4.ptr : 指向out输出的字符串;
* 5.ret : 执行函数时返回的字符串地址;
* 6.str : 执行函数返回的字符串的地址;
* 7.len : 字符串的长度;
* 8.i : for循环用于计数的变量;
* 9.j : for循环用于计数的变量;
* 10.child : 指向节点的指针;
* 11.fail : 输出出错时的标志;
* 12.numentries : 用于统计当前结构深度层次上的节点个数
*/
char **entries = , **names = ;
char *out = , *ptr, *ret, *str;
int len = , i = , j;
cJSON *child = item->child;
int numentries = , fail = ;
/* Count the number of entries. */
while ( child )
numentries++, child = child->next;
/* Explicitly handle empty object case */
if ( !numentries )
{
out = (char *) cJSON_malloc( fmt ? depth + : );
if ( !out )
return();
ptr = out; *ptr++ = '{';
if ( fmt )
{
*ptr++ = '\n';
for ( i = ; i < depth - ; i++ )
*ptr++ = '\t';
}
*ptr++ = '}'; *ptr++ = ;
return(out);
}
/* Allocate space for the names and the objects */
entries = (char **) cJSON_malloc( numentries * sizeof(char*));
if ( !entries )
return();
names = (char **) cJSON_malloc( numentries * sizeof(char*));
if ( !names )
{
cJSON_free( entries ); return();
}
memset( entries, , sizeof(char*) * numentries );
memset( names, , sizeof(char*) * numentries ); /* Collect all the results into our arrays: */
child = item->child; depth++; if ( fmt )
len += depth;
while ( child )
{
names[i] = str = print_string_ptr( child->string );
entries[i++] = ret = print_value( child, depth, fmt );
if ( str && ret )
len += strlen( ret ) + strlen( str ) + + (fmt ? + depth : );
else fail = ;
child = child->next;
} /* Try to allocate the output string */
if ( !fail )
out = (char *) cJSON_malloc( len );
if ( !out )
fail = ; /* Handle failure */
if ( fail )
{
for ( i = ; i < numentries; i++ )
{
if ( names[i] )
cJSON_free( names[i] );
if ( entries[i] )
cJSON_free( entries[i] );
}
cJSON_free( names ); cJSON_free( entries );
return();
} /* Compose the output: */
*out = '{';
ptr = out + ;
if ( fmt )
*ptr++ = '\n';
*ptr = ;
for ( i = ; i < numentries; i++ )
{
if ( fmt )
for ( j = ; j < depth; j++ )
*ptr++ = '\t';
strcpy( ptr, names[i] );
ptr += strlen( names[i] );
*ptr++ = ':';
if ( fmt )
*ptr++ = '\t';
strcpy( ptr, entries[i] );
ptr += strlen( entries[i] );
if ( i != numentries - )
*ptr++ = ',';
if ( fmt )
*ptr++ = '\n';
*ptr = ;
cJSON_free( names[i] );
cJSON_free( entries[i] );
} cJSON_free( names );
cJSON_free( entries );
if ( fmt )
for ( i = ; i < depth - ; i++ )
*ptr++ = '\t';
*ptr++ = '}';
*ptr++ = ;
return(out);
} /* Get Array size/item / object item. */
int cJSON_GetArraySize( cJSON *array )
{
cJSON *c = array->child; int i = ; while ( c )
i++, c = c->next;
return(i);
} cJSON *cJSON_GetArrayItem( cJSON *array, int item )
{
cJSON *c = array->child; while ( c && item > )
item--, c = c->next;
return(c);
} cJSON *cJSON_GetObjectItem( cJSON *object, const char *string )
{
cJSON *c = object->child; while ( c && cJSON_strcasecmp( c->string, string ))
c = c->next;
return(c);
} /* Utility for array list handling. --> 在当前节点的后面添加一个节点 */
static void suffix_object( cJSON *prev, cJSON *item )
{
prev->next = item; item->prev = prev;
} /* Utility for handling references. */
static cJSON *create_reference( cJSON *item )
{
cJSON *ref = cJSON_New_Item();
if ( !ref )
return();
memcpy( ref, item, sizeof(cJSON));
ref->string = ;
ref->type |= cJSON_IsReference;
ref->next = ref->prev = ;
return(ref);
} /* Add item to array/object. */
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 );
}
} 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 );
} void cJSON_AddItemReferenceToArray( cJSON *array, cJSON *item )
{
cJSON_AddItemToArray( array, create_reference( item ));
} void cJSON_AddItemReferenceToObject( cJSON *object, const char *string, cJSON *item )
{
cJSON_AddItemToObject( object, string, create_reference( item ));
} cJSON *cJSON_DetachItemFromArray( cJSON *array, int which )
{
cJSON *c = array->child;
while ( c && which > )
c = c->next, which--; if ( !c )
return();
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 = ;
return(c);
} void cJSON_DeleteItemFromArray( cJSON *array, int which )
{
cJSON_Delete( cJSON_DetachItemFromArray( array, which ));
} cJSON *cJSON_DetachItemFromObject( cJSON *object, const char *string )
{
int i = ; cJSON *c = object->child;
while ( c && cJSON_strcasecmp( c->string, string ))
i++, c = c->next;
if ( c )
return(cJSON_DetachItemFromArray( object, i ));
return();
} void cJSON_DeleteItemFromObject( cJSON *object, const char *string )
{
cJSON_Delete( cJSON_DetachItemFromObject( object, string ));
} /* Replace array/object items with new ones. */
void cJSON_ReplaceItemInArray( cJSON *array, int which, cJSON *newitem )
{
cJSON *c = array->child;
while ( c && which > )
c = c->next, which--;
if ( !c )
return;
newitem->next = c->next;
newitem->prev = c->prev;
if ( newitem->next )
newitem->next->prev = newitem;
if ( c == array->child )
array->child = newitem;
else
newitem->prev->next = newitem;
c->next = c->prev = ;
cJSON_Delete( c );
} void cJSON_ReplaceItemInObject( cJSON *object, const char *string, cJSON *newitem )
{
int i = ;
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 );
}
} /* Create basic types: */
cJSON *cJSON_CreateNull( void )
{
cJSON *item = cJSON_New_Item();
if ( item )
item->type = cJSON_NULL;
return(item);
} cJSON *cJSON_CreateTrue( void )
{
cJSON *item = cJSON_New_Item();
if ( item )
item->type = cJSON_True;
return(item);
} cJSON *cJSON_CreateFalse( void )
{
cJSON *item = cJSON_New_Item();
if ( item )
item->type = cJSON_False;
return(item);
} cJSON *cJSON_CreateBool( int b )
{
cJSON *item = cJSON_New_Item();
if ( item )
item->type = b ? cJSON_True : cJSON_False;
return(item);
} cJSON *cJSON_CreateNumber( double num )
{
cJSON *item = cJSON_New_Item();
if ( item )
{
item->type = cJSON_Number;
item->valuedouble = num;
item->valueint = (int) num;
}
return(item);
} cJSON *cJSON_CreateString( const char *string )
{
cJSON *item = cJSON_New_Item();
if ( item )
{
item->type = cJSON_String;
item->valuestring = cJSON_strdup( string );
}
return(item);
} cJSON *cJSON_CreateArray( void )
{
cJSON *item = cJSON_New_Item();
if ( item )
item->type = cJSON_Array;
return(item);
} cJSON *cJSON_CreateObject( void )
{
cJSON *item = cJSON_New_Item();
if ( item )
item->type = cJSON_Object;
return(item);
} /* Create Arrays: */
cJSON *cJSON_CreateIntArray( const int *numbers, int count )
{
int i;
cJSON *n = , *p = , *a = cJSON_CreateArray();
for ( i = ; a && i < count; i++ )
{
n = cJSON_CreateNumber( numbers[i] );
if ( !i )
a->child = n;
else
suffix_object( p, n );
p = n;
}
return(a);
} cJSON *cJSON_CreateFloatArray( const float *numbers, int count )
{
int i;
cJSON *n = , *p = , *a = cJSON_CreateArray();
for ( i = ; a && i < count; i++ )
{
n = cJSON_CreateNumber( numbers[i] );
if ( !i )
a->child = n;
else
suffix_object( p, n );
p = n;
}
return(a);
} cJSON *cJSON_CreateDoubleArray( const double *numbers, int count )
{
int i;
cJSON *n = , *p = , *a = cJSON_CreateArray();
for ( i = ; a && i < count; i++ )
{
n = cJSON_CreateNumber( numbers[i] );
if ( !i )
a->child = n;
else
suffix_object( p, n );
p = n;
}
return(a);
} cJSON *cJSON_CreateStringArray( const char **strings, int count )
{
int i; cJSON *n = , *p = , *a = cJSON_CreateArray();
for ( i = ; a && i < count; i++ )
{
n = cJSON_CreateString( strings[i] );
if ( !i )
a->child = n;
else
suffix_object( p, n );
p = n;
}
return(a);
} /* Duplication */
cJSON *cJSON_Duplicate( cJSON *item, int recurse )
{
cJSON *newitem, *cptr, *nptr = , *newchild;
/* Bail on bad ptr */
if ( !item )
return();
/* Create new item */
newitem = cJSON_New_Item();
if ( !newitem )
return();
/* Copy over all vars */
newitem->type = item->type & (~cJSON_IsReference), newitem->valueint = item->valueint, newitem->valuedouble = item->valuedouble;
if ( item->valuestring )
{
newitem->valuestring = cJSON_strdup( item->valuestring ); if ( !newitem->valuestring )
{
cJSON_Delete( newitem ); return();
}
}
if ( item->string )
{
newitem->string = cJSON_strdup( item->string ); if ( !newitem->string )
{
cJSON_Delete( newitem ); return();
}
}
/* If non-recursive, then we're done! */
if ( !recurse )
return(newitem);
/* Walk the ->next chain for the child. */
cptr = item->child;
while ( cptr )
{
newchild = cJSON_Duplicate( cptr, ); /* Duplicate (with recurse) each item in the ->next chain */
if ( !newchild )
{
cJSON_Delete( newitem ); return();
}
if ( nptr )
{
nptr->next = newchild, newchild->prev = nptr; nptr = newchild;
} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
else { newitem->child = newchild; nptr = newchild; } /* Set newitem->child and move to it */
cptr = cptr->next;
}
return(newitem);
} void cJSON_Minify( char *json )
{
char *into = json;
while ( *json )
{
if ( *json == ' ' )
json++;
else if ( *json == '\t' )
json++; /* Whitespace characters. */
else if ( *json == '\r' )
json++;
else if ( *json == '\n' )
json++;
else if ( *json == '/' && json[] == '/' )
while ( *json && *json != '\n' )
json++;
/* double-slash comments, to end of line. */
else if ( *json == '/' && json[] == '*' )
{
while ( *json && !(*json == '*' && json[] == '/'))
json++;
json += ;
} /* multiline comments. */
else if ( *json == '\"' )
{
*into++ = *json++; while ( *json && *json != '\"' )
{
if ( *json == '\\' )
*into++ = *json++;
*into++ = *json++;
}
*into++ = *json++;
} /* string literals, which are \" sensitive. */
else *into++ = *json++; /* All other characters. */
}
*into = ; /* and null-terminate. */
}
cJSON_hacking的更多相关文章
随机推荐
- PHP可变长函数方法介绍
1.三个重要函数 func_num_args() 返回实参个数 func_get_arg(i) 返回某个实参的值 func_get_args() 以数组的形式返回实参 ...
- checkbox改成radio效果,单选,取消
$(function () { var allBox = $(":checkbox"); allBox.click(function ( ...
- J2EE开发实战基础系列一 HelloWorld【转】
开始咱们的第一个程序,首先是配置环境,按照上一章所描述的方式下载开发工具,然后配置Java环境变量,给大家看下具体的结构: 环境变量配置OK的提示,如上图. Eclipse和Tomcat的文件目录 ...
- 使用Vibrator控制手机振动
import android.os.Bundle;import android.os.Vibrator;import android.app.Activity;import android.app.S ...
- thinking in java 之Reference类的使用
Reference是java中的特殊引用类.描述的是特殊作用(主要是关于垃圾回收对象)的引用. 它有3个子类: 1.SoftReference; 2.WeakReference 3.PhantomRe ...
- 关于HTML5应用开发功耗调优化小结
HTML5的优化一直是困扰我的难题,特别是在移动端开发游戏和应用,所以对此进行了一些总结: 功耗优化点介绍 在移动设备中主要的功耗点在: 1. 网络的传输, 不管是3G网络还是WiFi传输都是移动设备 ...
- HDU 1394 树状数组求逆序对
Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java ...
- C语言中文件的读取和写入
在C语言中写文件 //获取文件指针 FILE *pFile = fopen("1.txt", //打开文件的名称 "w"); // 文件打开方式 如果原来有内容 ...
- Linux-设置环境变量
一般来说,配置交叉编译工具链的时候需要指定编译工具的路径,此时就需要设置环境变量.例如我的mips-linux-gcc编译器在“ /opt/au1200_rm/build_tools/bin”目录下, ...
- getBoundingClientRect() 来获取页面元素的位置
getBoundingClientRect() 来获取页面元素的位置 document.documentElement.getBoundingClientRect 下面这是MSDN的解释: Syn ...