標籤:
先從test.c 開始說, 我們看到test.c 裡面有兩個函數用來測試, doit 和dofile, 一個是讀char* 一個是讀file, 肯定是讀字串的要簡單, 所以先看doit.
/* Parse text to JSON, then render back to text, and print! */void doit(char *text){ char *out;cJSON *json; json=cJSON_Parse(text); if (!json) {printf("Error before: [%s]\n",cJSON_GetErrorPtr());} else { out=cJSON_Print(json); cJSON_Delete(json); printf("%s\n",out); free(out); }}
先是申請了一個cJSON型的指標, 這個指標應該就是主要的儲存結構了. 那這個指標是什麼構成的呢?
typedef struct cJSON { struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ int type; /* The type of the item, as above. */ char *valuestring; /* The item‘s string, if type==cJSON_String */ int valueint; /* The item‘s number, if type==cJSON_Number */ double valuedouble; /* The item‘s number, if type==cJSON_Number */ char *string; /* The item‘s name string, if this item is the child of, or is in the list of subitems of an object. */} cJSON;
1) next和prev是兩個指向自己下一個和前一個的指標, 如果next==0 表明是末尾, prev==0表明是開頭.
2) string是自己的值, 也就是 {"name":"v1"} 中的name
3) type是當前節點value的類型, 也就是json預設定義的幾種.
4) 根據type的種類, 分別有對應的值 valuestring, valueint, valuedouble和 child. true和false還有null當然不需要定義, 因為他們本來值就是自己.
type定義在 <cJSON.h> 開頭
/* cJSON Types: */#define cJSON_False 0#define cJSON_True 1#define cJSON_NULL 2#define cJSON_Number 3#define cJSON_String 4#define cJSON_Array 5#define cJSON_Object 6
然後就是核心parse的過程了, 也就是函數 json=cJSON_Parse(text); 代碼如下:
/* Default options for cJSON_Parse */cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
竟然就這麼一行, 這不是糊弄我們嗎, 那就接著看cJSON_PaarseWithOpts函數.
定義:
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
實現:
/* Parse an object - create a new root, and populate. */cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated){ const char *end=0; cJSON *c=cJSON_New_Item(); ep=0; if (!c) return 0; /* memory fail */ end=parse_value(c,skip(value)); if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} if (return_parse_end) *return_parse_end=end; return c;}
不管後面兩個參數, 後面兩個參數都是0. (應該在子函數裡面有用)
先大致明確一下流程, 然後再看函數怎麼實現的(有一些是錯誤輸出, 暫不看):
1. cJSON *c = cJSON_New_Item(); 申請一個cJSON對象出來, 也就相當於new一個.
2. end=parse_value(c,skip(value)); 我們注意, 看doit代碼的時候只有一句parse, 也就是真正的parse在這個地方(腦補一下).
3. 剩下的都是錯誤處理.
那麼怎麼申請對象呢, 看cJSON_New_Item()函數.
/* Internal constructor. */static cJSON *cJSON_New_Item(void){ cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); if (node) memset(node,0,sizeof(cJSON)); return node;}
static void *(*cJSON_malloc)(size_t sz) = malloc;
申請一個sizeof(cJSON)結構體大小的空間. 然後將內容初始化.
下面看解析函數
/* Utility to jump whitespace and cr/lf */static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
這個非常好理解, 去除最前面的空格等字元.
/* Parser core - when encountering text, process appropriately. */static const char *parse_value(cJSON *item,const char *value){ if (!value) return 0; /* Fail on null. */ if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } if (*value==‘\"‘) { return parse_string(item,value); } if (*value==‘-‘ || (*value>=‘0‘ && *value<=‘9‘)) { return parse_number(item,value); } if (*value==‘[‘) { return parse_array(item,value); } if (*value==‘{‘) { return parse_object(item,value); } ep=value;return 0; /* failure. */}
1. 如果啥都沒有, 直接返回了.
2. 然後是只有一個null或false或true的情況.
3. 然後是逸出字元.
4. 然後是數字
5. 然後是數組或者字典.
看到這裡也能想明白了, value就是指json的單個value, 所以這個函數應該不止會調用一次的. 接下來就是數字, 字串, 數組, 字典的解析.
這個會在後面講.
cjson原始碼解讀 (二)解析流程