標籤:
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沒有什麼大的區別。
主要就是這四個。
cjson原始碼解讀(三) 解析字串、數字、數組、對象