關於cjson的介紹和使用方法就不在這裏介紹了,詳情請查看上一篇博客cjson使用方法。node
JSON的內存結構像廣義表,能夠認爲是有層次的雙向鏈表。
linux
cJSON程序中的細節點以下:json
- 大量宏替換
- 大量靜態函數
- 錯誤處理機制
- 字符串處理時存在utf16轉utf9,編碼轉換
- 用函數指針封裝malloc,free,方便用於處理,好比在申請後初始化,或者釋放前進行一些處理等。
cJSON中的重要接口函數以下:數組
解析函數 cJSON * cJSON_Parse(const char *value); 打印函數 char * cJSON_Print(cJSON * item); 刪除函數 void cJSON_Delete(cJSON * c); 構造函數 create系列和add系列 解析字符串 char *parse_string(cJSON*item,const char *str) 解析數字 char *parse_number(cJSON *item,const char *num) 解析數組 char *parse_array(cJSON *item,const char *value) 解析對象 char *parse_object(cJSON *item,const char *value) ......
cjosn有兩個相關的文件,一個cJSON.c和cJSON.h。咱們先從頭文件開始分析。緩存
首先,咱們會看到頭文件的開頭和結尾這樣的語句:app
- #ifndef cJSON__h
- #define cJSON__h
-
- #ifdef __cplusplus
- extern "C"
- {
- #endif
...函數
...ui
- #ifdef __cplusplus
- }
- #endif
-
- #endif
#ifndef cJSON_h,#define cJSON_h,#endif . 這是爲了防止頭文件被重複引用。編碼
extern "C"的主要做用就是爲了可以正確實現C++代碼調用其餘C語言代碼。加上extern "C"後,會指示編譯器這部分代碼按C語言的進行編譯,而不是C++的。因爲C++支持函數重載,所以編譯器編譯函數的過程當中會將函數的參數類型也加到編譯後的代碼中,而不只僅是函數名;而C語言並不支持函數重載,所以編譯C語言代碼的函數時不會帶上函數的參數類型,通常之包括函數名。spa
接着往下看,就會看到cjson的結構體的定義,cjson對象存儲結構實際是一個結構體。
- typedef struct cJSON
- {
- struct cJSON *next,*prev;
- struct cJSON *child;
-
- int type;
-
- char *valuestring;
- int valueint;
- double valuedouble;
-
- char *string;
- } cJSON;
前面提到過,cjson的存儲結構像一個廣義表,其實也能夠說是一個樹,不過兄弟結點之間都經過prev和next兩個指針鏈接起來。
prev和next分別是cjson對象的前驅和後繼,屬於同一級別的對象。chid則指向孩子結點,而且是第一個孩子的指針。
示例圖以下:
cjson的類型宏定義:
- #define cJSON_False (1 << 0)
- #define cJSON_True (1 << 1)
- #define cJSON_NULL (1 << 2)
- #define cJSON_Number (1 << 3)
- #define cJSON_String (1 << 4)
- #define cJSON_Array (1 << 5)
- #define cJSON_Object (1 << 6)
-
- #define cJSON_IsReference 256
- #define cJSON_StringIsConst 512
這些宏定義是對結構體type的值定義,處理時只須要將type的值&255進行位運算,便可獲得json裏儲存的數據類型。
cjson的建立:
cjson的建立的過程就是建立一個cjson結構體,再經過add一系列函數將其餘孩子結點數據或同等級結點加入,將相關結點經過指針鏈起來。
cjson_create一系列函數:cJSON_CreateArray(),cJSON_CreateObject(),cJSON_CreateString()等函數,都是調用cJSON_New_Item()函數建立對應節點信息。函數返回一個json結構體指針。
相關函數以下:
- static cJSON *cJSON_New_Item(void)
- {
- cJSON *node = (cJSON *) cJSON_malloc(sizeof(cJSON));
-
- if (node)
- memset(node, 0, sizeof(cJSON));
- return node;
- }
- 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;
- }
建立完一個根結點結構體後,接下來就是向根結點中加入元素。
從頭文件咱們發現,
- #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
- #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
- #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
- #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
- #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
- #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
過程是調用cJSON_AddItemToObject()並結合不一樣的對象類型增長節點名稱和子節點。而後在其中調用cJSON_AddItemToArray()函數來添加信息,此函數中判斷對象孩子結點是否爲NULL,若是是NULL,則直接插入,不然找到最後一個孩子,調用suffix_object()函數添加到雙向鏈表的尾部。
示例圖以下:
相關代碼以下:
- 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);
- }
-
- static char* cJSON_strdup(const char* str)
- {
- size_t len;
- char* copy;
-
- len = strlen(str) + 1;
-
- if (!(copy = (char*)cJSON_malloc(len)))
- return 0;
-
- memcpy(copy,str,len);
-
- return copy;
- }
-
- 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);
- }
- }
-
- static void suffix_object(cJSON *prev,cJSON *item)
- {
-
- prev->next=item;
- item->prev=prev;
- }
cjson打印:
cjson打印就是從根對象的結構體開始遍歷,獲得每一個item結點的名稱和數據,並通過處理成特定的cjson字符串的輸出形式。
cJSON_Print(root)和cJSON_PrintUnformatted(root) 函數都是打印成json字符串的函數,二者的區別就是
cJSON_PrintUnformatted(root) 處理成的字符串裏沒有\t\n這類的格式,咱們在這裏以分析cJSON_Print(root)函數
爲例,進行分析。
相關函數結構圖以下:
相關函數以下:
- typedef struct {
- char *buffer;
- int length;
- int offset;
- } printbuffer;
-
-
-
- static int pow2gt(int x)
- {
- --x;
- x |= x >> 1;
- x |= x >> 2;
- x |= x >> 4;
- x |= x >> 8;
- x |= x >> 16;
- return x + 1;
- }
-
-
- static char* ensure(printbuffer *p,int needed)
- {
- char *newbuffer;int newsize;
- if (!p || !p->buffer) return 0;
- needed+=p->offset;
- if (needed<=p->length) return p->buffer+p->offset;
- newsize=pow2gt(needed);
- newbuffer=(char*)cJSON_malloc(newsize);
- if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}
- if (newbuffer) memcpy(newbuffer,p->buffer,p->length);
- cJSON_free(p->buffer);
- p->length=newsize;
- p->buffer=newbuffer;
- return newbuffer+p->offset;
- }
-
- char *cJSON_Print(cJSON * item)
- {
- return print_value(item, 0, 1, 0);
- }
-
- static char *print_value(cJSON * item, int depth, int fmt, printbuffer * p)
- {
- char *out = 0;
-
- if (!item)
- return 0;
- if (p) {
- switch ((item->type) & 255) {
- case cJSON_NULL:{
- out = ensure(p, 5);
- if (out)
- strcpy(out, "null");
- break;
- }
- case cJSON_False:{
- out = ensure(p, 6);
- if (out)
- strcpy(out, "false");
- break;
- }
- case cJSON_True:{
- out = ensure(p, 5);
- if (out)
- strcpy(out, "true");
- break;
- }
- case cJSON_Number:
- out = print_number(item, p);
- break;
- case cJSON_String:
- out = print_string(item, p);
- break;
- case cJSON_Array:
- out = print_array(item, depth, fmt, p);
- break;
- case cJSON_Object:
- out = print_object(item, depth, fmt, p);
- break;
- }
- } else {
- switch ((item->type) & 255) {
- 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, 0);
- break;
- case cJSON_String:
- out = print_string(item, 0);
- break;
- case cJSON_Array:
- out = print_array(item, depth, fmt, 0);
- break;
- case cJSON_Object:
- out = print_object(item, depth, fmt, 0);
- break;
- }
- }
- return out;
- }
-
-
- static char *print_number(cJSON * item, printbuffer * p)
- {
- char *str = 0;
- double d = item->valuedouble;
-
- if (d == 0) {
- if (p)
- str = ensure(p, 2);
- else
- str = (char *) cJSON_malloc(2);
- if (str)
- strcpy(str, "0");
- } else if (fabs(((double) item->valueint) - d) <= DBL_EPSILON
- && d <= INT_MAX && d >= INT_MIN) {
- if (p)
- str = ensure(p, 21);
- else
- str = (char *) cJSON_malloc(21);
- if (str)
- sprintf(str, "%d", item->valueint);
- } else {
- if (p)
- str = ensure(p, 64);
- else
- str = (char *) cJSON_malloc(64);
- if (str) {
- if (fpclassify(d) != FP_ZERO && !isnormal(d))
- sprintf(str, "null");
- else 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 char *print_string(cJSON * item, printbuffer * p)
- {
- return print_string_ptr(item->valuestring, p);
- }
-
- static char *print_string_ptr(const char *str, printbuffer * p)
- {
- const char *ptr;
- char *ptr2, *out;
- int len = 0, flag = 0;
- unsigned char token;
-
- if (!str) {
- if (p)
- out = ensure(p, 3);
- else
- out = (char *) cJSON_malloc(3);
- if (!out)
- return 0;
- strcpy(out, "\"\"");
- return out;
- }
-
- for (ptr = str; *ptr; ptr++)
- flag |= ((*ptr > 0 && *ptr < 32) || (*ptr == '\"')
- || (*ptr == '\\')) ? 1 : 0;
- if (!flag) {
- len = ptr - str;
- if (p)
- out = ensure(p, len + 3);
- else
- out = (char *) cJSON_malloc(len + 3);
- if (!out)
- return 0;
- ptr2 = out;
- *ptr2++ = '\"';
- strcpy(ptr2, str);
- ptr2[len] = '\"';
- ptr2[len + 1] = 0;
- return out;
- }
-
- ptr = str;
- while ((token = *ptr) && ++len) {
- if (strchr("\"\\\b\f\n\r\t", token))
- len++;
- else if (token < 32)
- len += 5;
- ptr++;
- }
-
- if (p)
- out = ensure(p, len + 3);
- else
- out = (char *) cJSON_malloc(len + 3);
- if (!out)
- return 0;
-
- ptr2 = out;
- ptr = str;
- *ptr2++ = '\"';
- while (*ptr) {
- if ((unsigned char) *ptr > 31 && *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 += 5;
- break;
- }
- }
- }
- *ptr2++ = '\"';
- *ptr2++ = 0;
- return out;
- }
-
-
- static char *print_array(cJSON * item, int depth, int fmt, printbuffer * p)
- {
- char **entries;
- char *out = 0, *ptr, *ret;
- int len = 5;
- cJSON *child = item->child;
- int numentries = 0, i = 0, fail = 0;
- size_t tmplen = 0;
-
-
- while (child)
- numentries++, child = child->next;
-
- if (!numentries) {
- if (p)
- out = ensure(p, 3);
- else
- out = (char *) cJSON_malloc(3);
- if (out)
- strcpy(out, "[]");
- return out;
- }
-
- if (p) {
-
- i = p->offset;
- ptr = ensure(p, 1);
- if (!ptr)
- return 0;
- *ptr = '[';
- p->offset++;
- child = item->child;
- while (child && !fail) {
- print_value(child, depth + 1, fmt, p);
- p->offset = update(p);
- if (child->next) {
- len = fmt ? 2 : 1;
- ptr = ensure(p, len + 1);
- if (!ptr)
- return 0;
- *ptr++ = ',';
- if (fmt)
- *ptr++ = ' ';
- *ptr = 0;
- p->offset += len;
- }
- child = child->next;
- }
- ptr = ensure(p, 2);
- if (!ptr)
- return 0;
- *ptr++ = ']';
- *ptr = 0;
- out = (p->buffer) + i;
- } else {
-
- entries =
- (char **) cJSON_malloc(numentries * sizeof(char *));
- if (!entries)
- return 0;
- memset(entries, 0, numentries * sizeof(char *));
-
- child = item->child;
- while (child && !fail) {
- ret = print_value(child, depth + 1, fmt, 0);
- entries[i++] = ret;
- if (ret)
- len += strlen(ret) + 2 + (fmt ? 1 : 0);
- else
- fail = 1;
- child = child->next;
- }
-
-
- if (!fail)
- out = (char *) cJSON_malloc(len);
-
- if (!out)
- fail = 1;
-
-
- if (fail) {
- for (i = 0; i < numentries; i++)
- if (entries[i])
- cJSON_free(entries[i]);
- cJSON_free(entries);
- return 0;
- }
-
-
- *out = '[';
- ptr = out + 1;
- *ptr = 0;
- for (i = 0; i < numentries; i++) {
- tmplen = strlen(entries[i]);
- memcpy(ptr, entries[i], tmplen);
- ptr += tmplen;
- if (i != numentries - 1) {
- *ptr++ = ',';
- if (fmt)
- *ptr++ = ' ';
- *ptr = 0;
- }
- cJSON_free(entries[i]);
- }
- cJSON_free(entries);
- *ptr++ = ']';
- *ptr++ = 0;
- }
- return out;
- }
-
- static char *print_object(cJSON * item, int depth, int fmt, printbuffer * p)
- {
- char **entries = 0, **names = 0;
- char *out = 0, *ptr, *ret, *str;
- int len = 7, i = 0, j;
- cJSON *child = item->child;
- int numentries = 0, fail = 0;
- size_t tmplen = 0;
-
-
- while (child)
- numentries++, child = child->next;
-
- if (!numentries) {
- if (p)
- out = ensure(p, fmt ? depth + 4 : 3);
- else
- out = (char *) cJSON_malloc(fmt ? depth + 4 : 3);
- if (!out)
- return 0;
- ptr = out;
- *ptr++ = '{';
- if (fmt) {
- *ptr++ = '\n';
- for (i = 0; i < depth; i++)
- *ptr++ = '\t';
- }
- *ptr++ = '}';
- *ptr++ = 0;
- return out;
- }
- if (p) {
-
- i = p->offset;
- len = fmt ? 2 : 1;
- ptr = ensure(p, len + 1);
- if (!ptr)
- return 0;
- *ptr++ = '{';
- if (fmt)
- *ptr++ = '\n';
- *ptr = 0;
- p->offset += len;
- child = item->child;
- depth++;
- while (child) {
- if (fmt) {
- ptr = ensure(p, depth);
- if (!ptr)
- return 0;
- for (j = 0; j < depth; j++)
- *ptr++ = '\t';
- p->offset += depth;
- }
- print_string_ptr(child->string, p);
- p->offset = update(p);
-
- len = fmt ? 2 : 1;
- ptr = ensure(p, len);
- if (!ptr)
- return 0;
- *ptr++ = ':';
- if (fmt)
- *ptr++ = '\t';
- p->offset += len;
-
- print_value(child, depth, fmt, p);
- p->offset = update(p);
-
- len = (fmt ? 1 : 0) + (child->next ? 1 : 0);
- ptr = ensure(p, len + 1);
- if (!ptr)
- return 0;
- if (child->next)
- *ptr++ = ',';
- if (fmt)
- *ptr++ = '\n';
- *ptr = 0;
- p->offset += len;
- child = child->next;
- }
- ptr = ensure(p, fmt ? (depth + 1) : 2);
- if (!ptr)
- return 0;
- if (fmt)
- for (i = 0; i < depth - 1; i++)
- *ptr++ = '\t';
- *ptr++ = '}';
- *ptr = 0;
- out = (p->buffer) + i;
- } else {
-
- entries =
- (char **) cJSON_malloc(numentries * sizeof(char *));
- if (!entries)
- return 0;
- names =
- (char **) cJSON_malloc(numentries * sizeof(char *));
- if (!names) {
- cJSON_free(entries);
- return 0;
- }
- memset(entries, 0, sizeof(char *) * numentries);
- memset(names, 0, sizeof(char *) * numentries);
-
-
- child = item->child;
- depth++;
- if (fmt)
- len += depth;
- while (child && !fail) {
- names[i] = str =
- print_string_ptr(child->string, 0);
- entries[i++] = ret =
- print_value(child, depth, fmt, 0);
- if (str && ret)
- len +=
- strlen(ret) + strlen(str) + 2 +
- (fmt ? 2 + depth : 0);
- else
- fail = 1;
- child = child->next;
- }
-
-
- if (!fail)
- out = (char *) cJSON_malloc(len);
- if (!out)
- fail = 1;
-
-
- if (fail) {
- for (i = 0; i < numentries; i++) {
- if (names[i])
- cJSON_free(names[i]);
- if (entries[i])
- cJSON_free(entries[i]);
- }
- cJSON_free(names);
- cJSON_free(entries);
- return 0;
- }
-
-
- *out = '{';
- ptr = out + 1;
- if (fmt)
- *ptr++ = '\n';
- *ptr = 0;
- for (i = 0; i < numentries; i++) {
- if (fmt)
- for (j = 0; j < depth; j++)
- *ptr++ = '\t';
- tmplen = strlen(names[i]);
- memcpy(ptr, names[i], tmplen);
- ptr += tmplen;
- *ptr++ = ':';
- if (fmt)
- *ptr++ = '\t';
- strcpy(ptr, entries[i]);
- ptr += strlen(entries[i]);
- if (i != numentries - 1)
- *ptr++ = ',';
- if (fmt)
- *ptr++ = '\n';
- *ptr = 0;
- cJSON_free(names[i]);
- cJSON_free(entries[i]);
- }
-
- cJSON_free(names);
- cJSON_free(entries);
- if (fmt)
- for (i = 0; i < depth - 1; i++)
- *ptr++ = '\t';
- *ptr++ = '}';
- *ptr++ = 0;
- }
- return out;
- }
cJSON解析:
首先,調用cJSON_Parse()函數,此函數是一個二次封裝函數,其內部爲cJSON_ParseWithOpts()函數,該函數用於提取更多的解析選項,若是須要,最後返回解析結束的位置。而在上面的函數中,調用parse_value()函數進行解析,而該函數首先建立cJSON_NewItem()建立節點,用於存放解析的JSON結構數據,而後根據不一樣的選項,調用解析函數,其爲parse_string(),parse_number(),parse_array(),parse_objec()等。
結構圖以下:
相關函數以下:
- cJSON *cJSON_Parse(const char *value)
- {
- return cJSON_ParseWithOpts(value,0,0);
- }
-
- 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;
-
- end=parse_value(c,skip(value));
- if (!end)
- {
- cJSON_Delete(c);
- return 0;
- }
-
-
- 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;
- }
-
- static const char *parse_value(cJSON *item,const char *value)
- {
- if (!value)
- return 0;
- 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;
- }
-
- 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;
- }
-
- while (*ptr!='\"' && *ptr && ++len)
- if (*ptr++ == '\\')
- ptr++;
-
- out=(char*)cJSON_malloc(len+1);
- if (!out)
- return 0;
-
- ptr=str+1;
- 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':
- uc=parse_hex4(ptr+1);
- ptr+=4;
-
- if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)
- break;
-
- if (uc>=0xD800 && uc<=0xDBFF)
- {
- if (ptr[1]!='\\' || ptr[2]!='u')
- break;
- uc2=parse_hex4(ptr+3);ptr+=6;
- if (uc2<0xDC00 || uc2>0xDFFF)
- break;
- 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 const char *skip(const char *in)
- {
- while (in && *in && (unsigned char)*in<=32)
- in++;
- return in;
- }
-
- 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++;
- if (*num=='0') num++;
- if (*num>='1' && *num<='9')
- do
- n=(n*10.0)+(*num++ -'0');
- while (*num>='0' && *num<='9');
- if (*num=='.' && num[1]>='0' && num[1]<='9')
- {
- num++;
- do
- n=(n*10.0)+(*num++ -'0'),scale--;
- while (*num>='0' && *num<='9');
- }
- if (*num=='e' || *num=='E')
- {
- num++;
- if (*num=='+')
- num++;
- else if (*num=='-')
- signsubscale=-1,num++;
- while (*num>='0' && *num<='9')
- subscale=(subscale*10)+(*num++ - '0');
- }
-
- n=sign*n*pow(10.0,(scale+subscale*signsubscale));
-
- item->valuedouble=n;
- item->valueint=(int)n;
- item->type=cJSON_Number;
- return num;
- }
-
- static const char *parse_array(cJSON *item,const char *value)
- {
- cJSON *child;
- if (*value!='[') {ep=value;return 0;}
-
- item->type=cJSON_Array;
- value=skip(value+1);
- if (*value==']') return value+1;
-
- item->child=child=cJSON_New_Item();
- if (!item->child) return 0;
- value=skip(parse_value(child,skip(value)));
- if (!value) return 0;
-
- while (*value==',')
- {
- cJSON *new_item;
- if (!(new_item=cJSON_New_Item())) return 0;
- child->next=new_item;new_item->prev=child;child=new_item;
- value=skip(parse_value(child,skip(value+1)));
- if (!value) return 0;
- }
-
- if (*value==']') return value+1;
- ep=value;return 0;
- }
- static const char *parse_object(cJSON *item,const char *value)
- {
- cJSON *child;
- if (*value!='{') {ep=value;return 0;}
-
- item->type=cJSON_Object;
- value=skip(value+1);
- if (*value=='}') return value+1;
-
- 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;}
- value=skip(parse_value(child,skip(value+1)));
- if (!value) return 0;
-
- while (*value==',')
- {
- cJSON *new_item;
- if (!(new_item=cJSON_New_Item())) return 0;
- 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;}
- value=skip(parse_value(child,skip(value+1)));
- if (!value) return 0;
- }
-
- if (*value=='}') return value+1;
- ep=value;return 0;
- }
-
- 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;
- }
cJSON內存管理:
hook管理函數:
在 c 語言中內存通常是 malloc 和 free 的。
爲了方便用戶自由的管理內存, cjson 使用 Hook 技術來讓使用者能夠自定義內存管理函數。
即用戶自定義 malloc 和 free.
具體實現方式能夠參考下面的代碼, 默認使用系統的 malloc 和 free 函數, 用過 cJSON_InitHooks 函數能夠替換成用戶自定義的 malloc 和 free 函數。
- typedef struct cJSON_Hooks
- {
- void *(*malloc_fn)(size_t sz);
- void (*free_fn)(void *ptr);
- } cJSON_Hooks;
-
- extern void cJSON_InitHooks(cJSON_Hooks* hooks);
-
- static void *(*cJSON_malloc)(size_t sz) = malloc;
- static void (*cJSON_free)(void *ptr) = free;
- void cJSON_InitHooks(cJSON_Hooks* hooks)
- {
-
- if (!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;
- }
cJSON的刪除:
刪除節點很簡單, 先刪除兒子,而後清理內存便可。
總結一下就是對於 object 和 array 須要先刪除兒子,而後刪除本身。
對於 字符串, 須要先釋放字符串的內存, 再釋放本身這塊內存。
對於其餘節點,直接釋放本身這塊內存。
- 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;
- }
- }
-
-
- 刪除也是從 array 和 object 中刪除,實現就比較簡潔了。
- void cJSON_DeleteItemFromArray(cJSON *array,int which) {
- cJSON_Delete(cJSON_DetachItemFromArray(array,which));
- }
- void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {
- cJSON_Delete(cJSON_DetachItemFromObject(object,string));
- }
Detach 又是什麼東西呢?
咱們把一個節點從 json 樹中刪除, 可是不釋放內存,而是先保留這個節點的指針, 這樣儲存在這個節點的信息都保留了下來。
接下來咱們就能夠作不少事了, 合適的時候添加到其餘對象中, 合適的時候釋放內存。
好比上面的 delete 函數, 就須要真實的刪除了, 這個時候咱們刪除便可。
而 detach 實現也比較簡單, 只是少了一步刪除操做。
- cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {
- cJSON *c=array->child;
- while (c && which>0) c=c->next,which--;
- if (!c) return 0;
- 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=0;
- return c;
- }
- cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {
- int i=0;
- cJSON *c=object->child;
- while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;
- if (c) return cJSON_DetachItemFromArray(object,i);
- return 0;
- }
其餘函數:
前面咱們已經將json功能分爲三大塊進行了解析,如今把剩餘的一些函數貼上,這些函數單獨分析便可。
- int cJSON_GetArraySize(cJSON *array)
- {
- cJSON *c=array->child;
- int i=0;
- while(c)
- i++,c=c->next;
- return i;
- }
-
- cJSON *cJSON_GetArrayItem(cJSON *array,int item)
- {
- cJSON *c=array->child;
- while (c && item>0)
- 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;
- }
-
- void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem)
- {
- cJSON *c=array->child;
-
- while (c && which>0)
- c=c->next,which--;
-
- if (!c)
- {
- cJSON_AddItemToArray(array,newitem);
- return;
- }
-
- newitem->next=c;
- newitem->prev=c->prev;
- c->prev=newitem;
-
- if (c==array->child)
- array->child=newitem;
- else
- newitem->prev->next=newitem;
- }
-
-
- void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)
- {
- cJSON *c=array->child;
-
- while (c && which>0)
- 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=0;
-
- cJSON_Delete(c);
- }
-
-
- void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem)
- {
- int i=0;
- 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);
- }
- }
-
-
- cJSON *cJSON_Duplicate(cJSON *item,int recurse)
- {
- cJSON *newitem,*cptr,*nptr=0,*newchild;
-
- if (!item)
- return 0;
-
- newitem=cJSON_New_Item();
- if (!newitem)
- return 0;
-
- 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 0;
- }
- }
- if (item->string)
- {
- newitem->string=cJSON_strdup(item->string);
- if (!newitem->string)
- {
- cJSON_Delete(newitem);
- return 0;
- }
- }
-
- if (!recurse)
- return newitem;
-
- cptr=item->child;
- while (cptr)
- {
- newchild=cJSON_Duplicate(cptr,1);
- if (!newchild)
- {
- cJSON_Delete(newitem);
- return 0;
- }
- if (nptr)
- {
- nptr->next=newchild,newchild->prev=nptr;
- nptr=newchild;
- }
- else
- {
- newitem->child=newchild;
- nptr=newchild;
- }
- cptr=cptr->next;
- }
- return newitem;
- }
原文出處