c json保存整型数组_cjson源代码解读(三) 解析字符串、数字、数组、对象
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没有什么大的区别。
主要就是这四个。
更多推荐
所有评论(0)