1.  解析数字

static const char *parse_number(cJSON *item,const char *num)

{

double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;

if (*num=='-') sign=-1,num++;/* Has sign? */

if (*num=='0') num++;/* is zero */

if (*num>='1' && *num<='9')don=(n*10.0)+(*num++ -'0');while (*num>='0' && *num<='9');/* Number? */

if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;don=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}/* Fractional part? */

if (*num=='e' || *num=='E')/* Exponent? */

{num++;if (*num=='+') num++;else if (*num=='-') signsubscale=-1,num++;/* With sign? */

while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');/* Number? */

}

n=sign*n*pow(10.0,(scale+subscale*signsubscale));/* number = +/- number.fraction * 10^+/- exponent */

item->valuedouble=n;

item->valueint=(int)n;

item->type=cJSON_Number;

return num;

}

item是传进来的cjson object, num是起始数字。

1. 解析正负, 用sign 标记, -1 是负

2. 判断是不是0

3. 判断小数点前面的数字, 也就是 - 3.2 e 5  , 前面的3.2, 这个分为两部分, 小数点前和后

4. e或者E,即科学计数的后半部分, 这个时候需要处理一下科学计数的部分是不是正或者负的问题, 用signsubscale 记录。

5. 然后直接解析, 这里作者用了个小技巧, 作者直接在解析前面基数的部分, 解析出的是整数, 用scale记录, 最后用科学技术弄回来就OK了, 很巧妙。

6. 然后返回数字, 解析出来一个Object。

2. 解析字符串

static const char *parse_string(cJSON *item,const char *str)

{

const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;

if (*str!='\"') {ep=str;return 0;}/* not a string! */

while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;/* Skip escaped quotes. */ //跳到字符串最后一个去

out=(char*)cJSON_malloc(len+1);/* This is how long we need for the string, roughly. */ //预申请一个字符串空间大小的空间

if (!out) return 0; //申请不成功则退出

ptr=str+1;ptr2=out; //重新开始, 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. */ //unicode 则要单独处理

uc=parse_hex4(ptr+1);ptr+=4;/* get the unicode char. */ //parse hex 在后面, 就是把后四位都弄出来,

if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)break;/* check for invalid.*/

if (uc>=0xD800 && uc<=0xDBFF)/* UTF16 surrogate pairs.*/

{

if (ptr[1]!='\\' || ptr[2]!='u')break;/* missing second-half of surrogate.*/

uc2=parse_hex4(ptr+3);ptr+=6;

if (uc2<0xDC00 || uc2>0xDFFF)break;/* invalid second-half of surrogate.*/

uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));

}

len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;

switch (len) {

case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;

case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;

case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;

case 1: *--ptr2 =(uc | firstByteMark[len]);

}

ptr2+=len;

break;

default: *ptr2++=*ptr; break;

}

ptr++;

}

}

*ptr2=0;

if (*ptr=='\"') ptr++;

item->valuestring=out;

item->type=cJSON_String;

return ptr;

}

static unsigned parse_hex4(const char *str)

{

unsigned h=0;

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;

h=h<<4;str++;

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;

h=h<<4;str++;

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;

h=h<<4;str++;

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;

return h;

}

除了转码,剩下的都比较简单,就是申一个字符串, 然后拷过去。

3. 解析数组

static const char *parse_array(cJSON *item,const char *value)

{

cJSON *child;

if (*value!='['){ep=value;return 0;}/* not an array! */

item->type=cJSON_Array;

value=skip(value+1);

if (*value==']') return value+1;/* empty array. */

item->child=child=cJSON_New_Item();

if (!item->child) return 0; /* memory fail */

value=skip(parse_value(child,skip(value)));/* skip any spacing, get the value. */

if (!value) return 0;

while (*value==',')

{

cJSON *new_item;

if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */

child->next=new_item;new_item->prev=child;child=new_item;

value=skip(parse_value(child,skip(value+1)));

if (!value) return 0;/* memory fail */

}

if (*value==']') return value+1;/* end of array */

ep=value;return 0;/* malformed. */

}

如果内容不是空, 然后一直往下解析。 就OK了。

4. 解析对象,对象以{}表明

static const char *parse_object(cJSON *item,const char *value)

{

cJSON *child;

if (*value!='{'){ep=value;return 0;}/* not an object! */

item->type=cJSON_Object;

value=skip(value+1);

if (*value=='}') return value+1;/* empty array. */

item->child=child=cJSON_New_Item();

if (!item->child) return 0;

value=skip(parse_string(child,skip(value)));

if (!value) return 0;

child->string=child->valuestring;child->valuestring=0;

if (*value!=':') {ep=value;return 0;}/* fail! */

value=skip(parse_value(child,skip(value+1)));/* skip any spacing, get the value. */

if (!value) return 0;

while (*value==',')

{

cJSON *new_item;

if (!(new_item=cJSON_New_Item()))return 0; /* memory fail */

child->next=new_item;new_item->prev=child;child=new_item;

value=skip(parse_string(child,skip(value+1)));

if (!value) return 0;

child->string=child->valuestring;child->valuestring=0;

if (*value!=':') {ep=value;return 0;}/* fail! */

value=skip(parse_value(child,skip(value+1)));/* skip any spacing, get the value. */

if (!value) return 0;

}

if (*value=='}') return value+1;/* end of array */

ep=value;return 0;/* malformed. */

}

就是一个value,一个value往下滚, 然后自己的值用child记录, 前一个的位置也记录下来。 跟array没有什么大的区别。

主要就是这四个。

GitHub 加速计划 / cj / cJSON
10.45 K
3.16 K
下载
Ultralightweight JSON parser in ANSI C
最近提交(Master分支:2 个月前 )
424ce4ce This reverts commit 5b502cdbfb21fbe5f6cf9ffbd2b96e4281a741e6. Related to #860 4 个月前
32497300 - 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐