javascript
cJSON源码及解析流程详解
目錄
cJSON簡介
cJSON.h
cJSON結(jié)構(gòu)
cJSON結(jié)點(diǎn)的創(chuàng)建
cJSON解析
parse_objec( )
parse_array( )
parse_number( )
parse_string( )
cJSON打印
print_object( )
print_array( )
print_number( )
print_string( )&print_string_ptr( )
其他函數(shù)
?
cJSON簡介
JSON(JavaScript?Object Notation, JS 對象簡譜) 是一種輕量級的數(shù)據(jù)交換格式。它基于?ECMAScript?(歐洲計(jì)算機(jī)協(xié)會制定的js規(guī)范)的一個(gè)子集,采用完全獨(dú)立于編程語言的文本格式來存儲和表示數(shù)據(jù)。簡潔和清晰的層次結(jié)構(gòu)使得 JSON 成為理想的數(shù)據(jù)交換語言。 易于人閱讀和編寫,同時(shí)也易于機(jī)器解析和生成,并有效地提升網(wǎng)絡(luò)傳輸效率。cJSON從名字可知,整個(gè)項(xiàng)目都是以極標(biāo)準(zhǔn)的C來寫的,意思說,可以跨各種平臺使用了。cJSON是一個(gè)超輕巧,攜帶方便,單文件,簡單的可以作為ANSI-C標(biāo)準(zhǔn)的JSON解析器。
cJSON官網(wǎng)下載:https://sourceforge.net/projects/cjson/
cJSON ?GitHub:https://github.com/DaveGamble/cJSON
說明:本篇博文分析的源碼是在官網(wǎng)下載的,最后更新時(shí)間是2016-9-23。GitHub上的源代碼更新,同時(shí)其代碼量也更大。但它們的核心代碼和思想差不多,各位可以根據(jù)自身需求選擇。
?
cJSON.h
因?yàn)轭^文件的內(nèi)容不是很多,所以我將其全部羅列出來,其中的核心函數(shù)是解析函數(shù)和打印函數(shù)。只要清楚cJSON的數(shù)據(jù)結(jié)構(gòu)后,看相應(yīng)的代碼才能比較簡單。頭文件中并沒有包含所有的函數(shù),有的函數(shù)是在cJSON.c中定義的,一般是在解析過程中重復(fù)次數(shù)較多的函數(shù)。
#ifndef cJSON__h #define cJSON__h#ifdef __cplusplus extern "C" //extern "C"的主要作用就是為了能夠正確實(shí)現(xiàn)C++代碼調(diào)用其他C語言代碼。加上extern "C"后, //會指示編譯器這部分代碼按C語言的進(jìn)行編譯,而不是C++的。由于C++支持函數(shù)重載,因此編譯 //器編譯函數(shù)的過程中會將函數(shù)的參數(shù)類型也加到編譯后的代碼中,而不僅僅是函數(shù)名;而C語言 //并不支持函數(shù)重載,因此編譯C語言代碼的函數(shù)時(shí)不會帶上函數(shù)的參數(shù)類型,一般之包括函數(shù)名。 { #endif/* 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#define cJSON_IsReference 256 #define cJSON_StringIsConst 512/* cJSON結(jié)構(gòu)體: */ typedef struct cJSON {struct cJSON *next,*prev; /* next/prev結(jié)構(gòu)體指針允許你遍歷數(shù)組/對象鏈。另外,使用GetArraySize 、 GetArrayItem 、 GetObjectItem方法獲取相應(yīng)的項(xiàng)。 */struct cJSON *child; /* 數(shù)組或?qū)ο髮⒂幸粋€(gè)child指針指向數(shù)組/對象中的頭結(jié)點(diǎn)。 */int type; /* 項(xiàng)的類型 */char *valuestring; /* 如果type==cJSON_String,則是字符串。 */int valueint; /* 如果type==cJSON_Number,則是int。 */double valuedouble; /* 如果type==cJSON_Number,則是double。 */char *string; /* json對象的名稱。 */ } cJSON;/* 該結(jié)構(gòu)體提供了分配和釋放空間的函數(shù)指針 */ typedef struct cJSON_Hooks {void *(*malloc_fn)(size_t sz);void (*free_fn)(void *ptr); } cJSON_Hooks;/* 向cJSON提供malloc和free函數(shù) */ extern void cJSON_InitHooks(cJSON_Hooks* hooks);/* 提供一個(gè)JSON塊,然后返回一個(gè)可以查詢的cJSON對象。完成后調(diào)用cJSON_Delete。 */ extern cJSON *cJSON_Parse(const char *value); /* 將cJSON實(shí)體呈現(xiàn)為用于傳輸/存儲的文本。完成后釋放char*。 */ extern char *cJSON_Print(cJSON *item); /* 將cJSON實(shí)體呈現(xiàn)為用于傳輸/存儲的文本,而不進(jìn)行任何格式化。完成后釋放char*。 */ extern char *cJSON_PrintUnformatted(cJSON *item); /* 使用緩沖策略將cJSON實(shí)體呈現(xiàn)為文本。預(yù)緩沖是對最終大小的猜測。猜測減少了重新分配。fmt=0表示無格式,=1表示有格式 */ extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt); /* 刪除一個(gè)cJSON實(shí)體和所有子實(shí)體。 */ extern void cJSON_Delete(cJSON *c);/* 返回?cái)?shù)組(或?qū)ο?中的項(xiàng)數(shù)。 */ extern int cJSON_GetArraySize(cJSON *array); /* 從數(shù)組“數(shù)組”中檢索項(xiàng)目編號“項(xiàng)目”。如果不成功,返回NULL。 */ extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); /* 從對象中獲取項(xiàng)目"string"。不區(qū)分大小寫。 */ extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);/* 用于分析失敗的語法。這將返回一個(gè)指向解析錯(cuò)誤的指針。 你可能需要回頭看幾個(gè)字才能理解它。當(dāng)cJSON_Parse()返回0時(shí)定義。當(dāng)cJSON_Parse()成功時(shí)為0。 */ extern const char *cJSON_GetErrorPtr(void);/* 這些調(diào)用創(chuàng)建適當(dāng)Type的cJSON項(xiàng)。 */ extern cJSON *cJSON_CreateNull(void); extern cJSON *cJSON_CreateTrue(void); extern cJSON *cJSON_CreateFalse(void); extern cJSON *cJSON_CreateBool(int b); extern cJSON *cJSON_CreateNumber(double num); extern cJSON *cJSON_CreateString(const char *string); extern cJSON *cJSON_CreateArray(void); extern cJSON *cJSON_CreateObject(void);/* 根據(jù)count創(chuàng)建數(shù)組。 */ extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); extern cJSON *cJSON_CreateStringArray(const char **strings,int count);/* 向指定的數(shù)組/對象追加項(xiàng)。 */ extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* 當(dāng)字符串確實(shí)是常量(例如,是一個(gè)文本,或者與常量一樣好),并且肯定會在cJSON對象中存活時(shí),就使用這個(gè)方法 */ /* 將對項(xiàng)的引用追加到指定的數(shù)組/對象。當(dāng)您想要將現(xiàn)有的cJSON添加到新的cJSON中,但又不想破壞現(xiàn)有的cJSON時(shí),可以使用此方法。 */ extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);/* 從數(shù)組/對象中刪除/分離項(xiàng)。 */ extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); extern void cJSON_DeleteItemFromArray(cJSON *array,int which); extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);/* 更新數(shù)組項(xiàng) */ extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* 將已存在的項(xiàng)目向右移動。 */ extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);/* 復(fù)制一個(gè)cJSON項(xiàng)目 */ extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); /* Duplicate將在需要釋放的新內(nèi)存中創(chuàng)建一個(gè)與傳遞的cJSON相同的新項(xiàng)目。 遞歸!=0,它將復(fù)制連接到該項(xiàng)的所有子元素。條目->next和->prev指針在從Duplicate返回時(shí)總是0。*//* ParseWithOpts允許您要求(并檢查)JSON是否以null結(jié)尾,并檢索指向解析后的最終字節(jié)的指針。 */ extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);extern void cJSON_Minify(char *json);/* 用于快速創(chuàng)建內(nèi)容的宏。 */ #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))/* 在分配整數(shù)值時(shí),也需要將其傳播到valuedouble。 */ #define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) #define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))#ifdef __cplusplus } #endif#endif?
?
cJSON結(jié)構(gòu)
cjson的存儲結(jié)構(gòu)整體可以簡單的看成一條鏈表(單向),同一級別下的兄弟結(jié)點(diǎn)之間是通過prev和next指針連接起來(雙向),prev和next分別指向cjson對象的前驅(qū)和后繼。child則指向下一級結(jié)點(diǎn),這里通過名字也可以理解為指向孩子結(jié)點(diǎn)。以下是例子及其結(jié)構(gòu)圖:
{"Asd": [{ "賬號":"a123456789" , "密碼":"asdasdasd123456" },{ "賬號":"b123456789" , "密碼":"qweqweqwe123456" }] }例子中的Asd是一個(gè)數(shù)組,里面存儲的內(nèi)容是對象。對象存儲的內(nèi)容是賬號和密碼,賬號結(jié)點(diǎn)和密碼結(jié)點(diǎn)的類型都是string,而string的值分別賦予了賬號和密碼意義。這里直接將cJSON結(jié)構(gòu)圖列出,是為了方便大家閱讀源代碼時(shí)方便理解。
?
cJSON結(jié)點(diǎn)的創(chuàng)建
結(jié)點(diǎn)創(chuàng)建函數(shù)很簡單,就是為cJSON結(jié)構(gòu)體申請空間并用memset進(jìn)行初始化,然而沒有設(shè)置結(jié)構(gòu)體內(nèi)的成員,后續(xù)根據(jù)需求再對結(jié)構(gòu)體中的類型進(jìn)行設(shè)置。可以看到下面的創(chuàng)建基本類型函數(shù),都是先調(diào)用cJSON_New_Item( ),再進(jìn)行成員設(shè)置。
/* 內(nèi)部構(gòu)造函數(shù),創(chuàng)建一個(gè)新的Item */ static cJSON *cJSON_New_Item(void) {cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));if (node) memset(node,0,sizeof(cJSON)); //memset是計(jì)算機(jī)中C/C++語言初始化函數(shù)。作用是將某一塊內(nèi)存中的內(nèi)容全部設(shè)置為指定的值//這個(gè)函數(shù)通常為新申請的內(nèi)存做初始化工作。 原型:void *memset(void *s, int ch, size_t n);return node; } /* 創(chuàng)建基本類型: */ // 通過調(diào)用cJSON_New_Item()函數(shù)創(chuàng)建cJSON結(jié)構(gòu)體,再根據(jù)需求設(shè)置相應(yīng)的type,最后返回item。 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;}/* 頭文件中快速創(chuàng)建內(nèi)容的宏 */ /* 用于快速創(chuàng)建內(nèi)容的宏。 */ #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解析
解析代碼是cJSON項(xiàng)目的核心代碼,它的流程圖如下:
cJSON解析的二次封裝:
/* cJSON_Parse的默認(rèn)選項(xiàng),用于將文本解析為JSON */ cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} /* 解析一個(gè)對象,創(chuàng)建一個(gè)新的根,然后填充。 */ cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) {const char *end=0;cJSON *c=cJSON_New_Item(); //只是創(chuàng)建了一個(gè)cJSON結(jié)構(gòu)體,沒有其他操作。ep=0;if (!c) return 0; /* 內(nèi)存分配失敗,返回0 */end=parse_value(c,skip(value)); //skip只跳過開頭的控制字符 if (!end) {cJSON_Delete(c);return 0;} /* 解析失敗 *//* 如果我們需要沒有附加以null結(jié)尾的JSON,跳過,然后檢查是否有null終止符 *///函數(shù)中參數(shù)中提供了require_null_terminated是為了確保json字符串必須以'\0'字符作為結(jié)尾。//若參數(shù)提供了return_parse_end,將返回json字符串解析完成后剩余的部分。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; } /* 解析器核心——遇到文本時(shí),適當(dāng)?shù)靥幚怼?*/ static const char *parse_value(cJSON *item,const char *value) {if (!value) return 0; /* 不能為空,若為空,返回0 *///strncmp函數(shù)為字符串比較函數(shù),函數(shù)聲明為int strncmp ( const char * str1, const char * str2, size_t n );//若str1與str2的前n個(gè)字符相同,則返回0;若s1大于s2,則返回大于0的值;若s1 小于s2,則返回小于0的值。//對于json為null、true或者false的情況,直接將type置為對應(yīng)的類型即可。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; }//以下需要了解JSON的結(jié)構(gòu)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; /* 失敗 */ }前三步很簡單,調(diào)用cJSON_Parse(),其內(nèi)部為cJSON_ParseWithOpts(),它調(diào)用parse_value()函數(shù)進(jìn)行解析,這里函數(shù)首先調(diào)用cJSON_NewItem()創(chuàng)建節(jié)點(diǎn),用于存放解析的JSON結(jié)構(gòu)數(shù)據(jù)。然后根據(jù)不同的Type,再調(diào)用相應(yīng)的parse_string(),parse_number(),parse_array()或parse_objec()。對應(yīng)上面提到的cJSON的結(jié)構(gòu)圖,若是同一級下的結(jié)點(diǎn),會形成一個(gè)雙向鏈表,用于連接該級下的兄弟結(jié)點(diǎn)。若不是同一級,則會讓上一次結(jié)點(diǎn)的child指針指向新的結(jié)點(diǎn)。
?
parse_objec( )
接下來的代碼分析需要結(jié)合官方圖表才能更好的理解其原理。先說一下圖表,對于一個(gè)object而言,一定是從 " { " 開始, " } "結(jié)束。程序會先判斷該對象是不是為空,即" { " 后除了控制字符外,是不是只剩下?" } "。若是,則說明這個(gè)對象是空的。若不是,接下來會遇到whitespace和字符串。程序用skip() 巧妙地跳過了控制字符,方便了對象內(nèi)容的解析。你會發(fā)現(xiàn)代碼中有一段代碼是 value=skip(parse_string(child,skip(value))); ,這是因?yàn)樘^whitespace后,會直接遇到string類型的數(shù)據(jù)。而后會遇到 " :?",代碼中也進(jìn)行了相應(yīng)的處理,即value=skip(parse_value(child,skip(value+1)));?。當(dāng)string和value都處理完了后,可能還有別的內(nèi)容。這里的判斷條件是如果遇到 " , ",說明后續(xù)還有內(nèi)容,所以在while循環(huán)內(nèi)的代碼重復(fù)了上述的工作。在while中,會調(diào)用cJSON_New_Item( )創(chuàng)建新的結(jié)點(diǎn),然后將它們連接在一起(此時(shí)的內(nèi)容是同級的)。這里是對圖片和代碼的一個(gè)講解,大家可以先看看圖片,再去看代碼,這樣思路會清晰很多。
/* 跳轉(zhuǎn)空格和cr/lf的實(shí)用程序,但只會跳過第一個(gè)能顯示的字符之前的控制字符 */ // ASCII碼值小于32的為控制字符 static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}/* 從文本構(gòu)建一個(gè)對象。 */ static const char *parse_object(cJSON *item,const char *value) {cJSON *child;if (*value!='{') {ep=value;return 0;} /* 不是一個(gè)對象! */item->type=cJSON_Object; //類型置為對象value=skip(value+1); //開始找{后的非控制字符if (*value=='}') return value+1; /* 若第一個(gè)非控制字符為},則內(nèi)容為空,即{}。 */item->child=child=cJSON_New_Item(); //為child分配空間,用child指向下一層結(jié)點(diǎn) if (!item->child) return 0; value=skip(parse_string(child,skip(value))); //由JSON的object結(jié)構(gòu)可知,在排除內(nèi)容為空的前提下,{后遇到的可能是//空格或字符串,所以用skip跳過空格,那么第一個(gè)直接遇到的就是字符串//所以直接調(diào)用parse_string()函數(shù)。最外層的skip函數(shù)可以直接指向':'。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==',') //','表明后面還有內(nèi)容,那么就將上述操作再進(jìn)行多次即可。{ cJSON *new_item;if (!(new_item=cJSON_New_Item())) return 0; /* 內(nèi)存錯(cuò)誤。 */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; /* 數(shù)組尾部 */ep=value;return 0; }?
parse_array( )
同理對于一個(gè)array而言,一定是從 " [ " 開始, " ]?"結(jié)束。程序會先判斷該數(shù)組是不是為空,即" [?" 后除了控制字符外,是不是只剩下?" ]?"。若是,則說明這個(gè)數(shù)組是空的。若不是,接下來會遇到value。程序用skip() 跳過了控制字符,方便數(shù)組內(nèi)容的解析。這里的操作流程和思想和上述parse_objec()很像,而且array相對于object更簡單點(diǎn)。
/* 從輸入文本構(gòu)建一個(gè)數(shù)組。 */ static const char *parse_array(cJSON *item,const char *value) {//解析數(shù)組時(shí),其基本思想是對數(shù)組中每一個(gè)元素遞歸調(diào)用parse_value,再將這些元素連接形成一個(gè)鏈表。cJSON *child;if (*value!='[') {ep=value;return 0;} /* 不是一個(gè)數(shù)組! */item->type=cJSON_Array; //置類型為itemvalue=skip(value+1);if (*value==']') return value+1; /* 若為[],則為空數(shù)組。 */item->child=child=cJSON_New_Item();if (!item->child) return 0; /* 內(nèi)存錯(cuò)誤 */value=skip(parse_value(child,skip(value))); /* 跳過任何間距,獲取值。 */if (!value) return 0;while (*value==',') //','表明后面還有內(nèi)容,那么就將上述操作再進(jìn)行多次即可。 { //這一部分相對于parse_object()簡單的原因是','后是value。cJSON *new_item;if (!(new_item=cJSON_New_Item())) return 0; /* 內(nèi)存錯(cuò)誤 */child->next=new_item;new_item->prev=child;child=new_item;value=skip(parse_value(child,skip(value+1)));if (!value) return 0; /* 內(nèi)存錯(cuò)誤 */}if (*value==']') return value+1; /* 數(shù)組的尾部 */ep=value;return 0; }?
parse_number( )
這一部分,函數(shù)比較簡單,反而是圖比較復(fù)雜,建議直接看代碼。
/* 解析輸入文本以生成數(shù)字,并將結(jié)果填充到項(xiàng)中。 */ 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++; /* 有標(biāo)志? */if (*num=='0') num++; /* 是0 */if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* 數(shù)字? */if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* 小數(shù)部分? */if (*num=='e' || *num=='E') /* 指數(shù)? */{ num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* 帶標(biāo)志? */while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* 數(shù)字? */}n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent *///double pow(double x, double y); 返回 x 的 y 次冪,即x^y。item->valuedouble=n;item->valueint=(int)n;item->type=cJSON_Number;return num; }?
parse_string( )
對string的處理思想和上面的基本一樣,不同的是判斷條件的不一樣。因?yàn)樵创a中有一句注釋 /* UTF16 surrogate pairs。 */。百度后才知道它是什么意思,字面意義是:代理對。實(shí)際上是指:對于一個(gè)UTF16編碼改用兩個(gè)UTF16編碼來代替。本來一個(gè)字符用一個(gè)UTF16編碼(兩個(gè)字節(jié))來表示即可,但是由于需要被編碼的字符越來越多,只用一個(gè)UTF16編碼已經(jīng)不足于表示所有的字符。因此,就需要考慮使用2個(gè)UTF16來表示一個(gè)字符(四個(gè)字節(jié))。
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; } /* 將輸入文本解析為未轉(zhuǎn)義的cstring,并填充項(xiàng)。 */ static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 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;} /* 若開頭不是'"',則不是一個(gè)字符串! *///由定義ptr=str+1;可知,ptr指向字符串的第個(gè)字符while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* 跳過了引號。 */// "Asd qwe zxc!" 長度為12,"Asd \"qwe\" zxc!"長度為14。/* 除“或\或控制字符外的任何代碼點(diǎn) */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; //水平tabcase 'u': /* utf16轉(zhuǎn)換utf8。 */uc=parse_hex4(ptr+1);ptr+=4; /* 獲取unicode字符。 */if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* 檢查無效的。 */if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs。 字面意義是:代理對。實(shí)際上是指:對于一個(gè)UTF16編碼改用兩個(gè)UTF16編碼來代替。*/{ //本來一個(gè)字符用一個(gè)UTF16編碼(兩個(gè)字節(jié))來表示即可,但是由于需要被編碼的字符越來越多,//只用一個(gè)UTF16編碼已經(jīng)不足于表示所有的字符。因此,就需要考慮使用2個(gè)UTF16來表示一個(gè)字符(四個(gè)字節(jié))。if (ptr[1]!='\\' || ptr[2]!='u') break; /* surrogate的下半部分不見了。 */uc2=parse_hex4(ptr+3);ptr+=6;if (uc2<0xDC00 || uc2>0xDFFF) break; /* 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; }?
?
cJSON打印
打印的過程類似于鏈表的遍歷,它的流程圖如下:
/* 將cJSON項(xiàng)/實(shí)體/結(jié)構(gòu)呈現(xiàn)為文本。 */ char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);} char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);} //cjson打印就是從根對象的結(jié)構(gòu)體開始遍歷,得到每個(gè)item結(jié)點(diǎn)的名稱和數(shù)據(jù),并經(jīng)過處理成特定的cjson字符串的輸出形式。 //cJSON_Print(root)和cJSON_PrintUnformatted(root)函數(shù)都是打印成json字符串的函數(shù),兩者的區(qū)別就是 //cJSON_PrintUnformatted(root)處理過的字符串里沒有\(zhòng)t\n這類格式我用官方給實(shí)例代碼運(yùn)行程序時(shí),因?yàn)闆]有涉及到printbuffer(即令該值為0),所以程序走的都是else內(nèi)的操作。
/* 為文本呈現(xiàn)一個(gè)值。 */ static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) { // fmt傳入時(shí)值為1char *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; }?
print_object( )
該函數(shù),開始使用numentries記錄對象的數(shù)量。因?yàn)樯厦嫣岬搅藀rintbuffer *p = 0,所以在組成輸出格式的時(shí)候,分配2個(gè)指針數(shù)組存儲對象里的鍵和值。最后通過對兩個(gè)指針數(shù)組的內(nèi)容的拼接,將數(shù)據(jù)組成輸出的格式。可以看到代碼末端" { " 和 " } "之間的代碼都是拼接操作。這部分的代碼,要先將else內(nèi)的邏輯流程看懂。
/* 將對象呈現(xiàn)為文本。 */ 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;/* numentries記錄對象的數(shù)量。 */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-1;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{//分配2個(gè)指針數(shù)組存儲對象里的鍵和值。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);/* 收集所有結(jié)果到我們的數(shù)組: */child=item->child;depth++;if (fmt) len+=depth;while (child){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; }?
print_array( )
該函數(shù),開始使用numentries記錄數(shù)組中元素的數(shù)量。這里的printbuffer *p = 0,在組成輸出格式的時(shí)候,分配一個(gè)指針數(shù)組存儲數(shù)組里的每一個(gè)元素的打印結(jié)果。這里多的一個(gè)操作是,數(shù)組內(nèi)容可能是對象,所以要調(diào)用print_value()打印相應(yīng)內(nèi)容。可以在源代碼中看到ret=print_value(child,depth+1,fmt,0);??。獲取數(shù)據(jù)后,接下來組成數(shù)組的輸出形式。代碼末端" [?" 和 " ]?"之間的代碼都是拼接操作。
/* 將數(shù)組呈現(xiàn)為文本 */ 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;/* numentries記錄數(shù)組中有多少元素 */while (child) numentries++,child=child->next;/* 處理numentries == 0 */if (!numentries){if (p) out=ensure(p,3);else out=(char*)cJSON_malloc(3);if (out) strcpy(out,"[]");return out;}if (p){/* 組合輸出數(shù)組。*/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{/* 分配一個(gè)指針數(shù)組存儲數(shù)組里的每一個(gè)元素的打印結(jié)果。 */entries=(char**)cJSON_malloc(numentries*sizeof(char*));if (!entries) return 0;memset(entries,0,numentries*sizeof(char*));/* 檢索所有結(jié)果: */child=item->child;while (child && !fail){ret=print_value(child,depth+1,fmt,0); //數(shù)組內(nèi)容可能是對象,所以要調(diào)用print_value打印相應(yīng)內(nèi)容。返回值為char*entries[i++]=ret;if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;child=child->next;}/* 如果沒有失敗,嘗試malloc輸出字符串 */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;}/* 數(shù)據(jù)已經(jīng)獲取了,接下來組成數(shù)組的輸出形式。*/*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; }?
print_number( )
在看這部分代碼時(shí),我一直在糾結(jié)ensure(),最后發(fā)現(xiàn)它是一個(gè)協(xié)助printbuffer分配內(nèi)存的函數(shù),而代碼中的printbuffer *p = 0。所以只需要跳過相應(yīng)的代碼就可以理解它的邏輯流程了。這里遇到不懂的是DBL_EPSILON和sprintf(str,"%d",item->valueint);,這兩個(gè)問題的解釋在注釋中。
/* 將給定項(xiàng)中的數(shù)字漂亮地呈現(xiàn)為字符串。 */ 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); /* 0的特殊情況。 */if (str) strcpy(str,"0");}else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN){ //fabs 作用是求浮點(diǎn)數(shù)的絕對值。 double fabs(double x );//DBL_EPSILON和 FLT_EPSILON主要用于單精度和雙精度的比較當(dāng)中:if (p) str=ensure(p,21);else str=(char*)cJSON_malloc(21); /* 2^64+1 可以用21個(gè)字符表示。 */if (str) sprintf(str,"%d",item->valueint); //函數(shù)功能:格式化字符串,將格式化的數(shù)據(jù)寫入字符串中。//函數(shù)原型:int sprintf(char *buffer, const char *format, [argument]…)//格式化數(shù)字字符串:在這點(diǎn)上sprintf和printf的用法一樣,只是打印到的位置不同而已,前者打印給buffer字符串//后者打印給標(biāo)準(zhǔn)輸出,所以sprintf也可以用來將整型轉(zhuǎn)化為字符串//比itoa效率高且簡便,比如:sprintf(buffer, "%d", 123456);執(zhí)行后buffer即指向字符串"123456"。}else{if (p) str=ensure(p,64);else str=(char*)cJSON_malloc(64); /* 這是一個(gè)很好的權(quán)衡。 */if (str){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; }?
print_string( )&print_string_ptr( )
這里主要看print_string_ptr()中while里的內(nèi)容。
/* 引用print_string_ptr()函數(shù)。 */ static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);} /* 將提供的cstring呈現(xiàn)給一個(gè)可以打印的轉(zhuǎn)義版本。 */ static char *print_string_ptr(const char *str,printbuffer *p) {const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;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;}if (!str){if (p) out=ensure(p,3);else out=(char*)cJSON_malloc(3);if (!out) return 0;strcpy(out,"\"\"");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; /* escape and print */}}}*ptr2++='\"';*ptr2++=0;return out; }?
?
其他函數(shù)
聲明函數(shù)指針,方便分配和釋放空間。以下代碼就不細(xì)講了,注釋中有相應(yīng)的解釋。
static void *(*cJSON_malloc)(size_t sz) = malloc; //聲明函數(shù)指針,例如:double (*pf)(int); static void (*cJSON_free)(void *ptr) = free; //這兩個(gè)函數(shù)返回值都是void * /* 該結(jié)構(gòu)體提供了分配和釋放空間的函數(shù)指針 */ typedef struct cJSON_Hooks {void *(*malloc_fn)(size_t sz);void (*free_fn)(void *ptr); } cJSON_Hooks;void cJSON_InitHooks(cJSON_Hooks* hooks) {if (!hooks) { /* 若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_strcasecmp()
static int cJSON_strcasecmp(const char *s1,const char *s2) //功能和strcasecmp一樣,忽略大小寫比較字符串。 {if (!s1) return (s1==s2)?0:1; //s1若為空,根據(jù)s1和s2是否相等返回0或者1。if (!s2) return 1; //s2若為空,返回1。for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) //tolower的功能是把字母字符轉(zhuǎn)換成小寫,非字母字符不做出處理。if(*s1 == 0) //函數(shù)說明:若參數(shù) c 為大寫字母則將該對應(yīng)的小寫字母返回。return 0; //返回值:返回轉(zhuǎn)換后的小寫字母,若不須轉(zhuǎn)換則將參數(shù)c 值返回。return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); }?
cJSON_strdup()
static char* cJSON_strdup(const char* str) //cJSON的字符串拷貝函數(shù) { //strdup()函數(shù)是c語言中常用的一種字符串拷貝庫函數(shù),一般和free()函數(shù)成對出現(xiàn)。size_t len; //strdup()在內(nèi)部調(diào)用了malloc()為變量分配內(nèi)存,不需要使用返回的字符串時(shí)char* copy; //需要用free()釋放相應(yīng)的內(nèi)存空間,否則會造成內(nèi)存泄漏。len = strlen(str) + 1;if (!(copy = (char*)cJSON_malloc(len))) return 0;memcpy(copy,str,len); //memcpy指的是C和C++使用的內(nèi)存拷貝函數(shù)return copy; //函數(shù)原型為void *memcpy(void *destin, void *source, unsigned n); } //函數(shù)的功能是從源內(nèi)存地址的起始位置開始拷貝若干個(gè)字節(jié)到目標(biāo)內(nèi)存地址中。?
cJSON_Delete()
/* 刪除cJSON結(jié)構(gòu)體 */ void cJSON_Delete(cJSON *c) {cJSON *next;while (c){next=c->next;//遞歸刪除結(jié)點(diǎn)if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);cJSON_free(c);c=next;} }?
ensure()
/* 例如x = 6或8,則返回8。 x = 12或13,則返回16。 總結(jié):返回 >= x的最小2的n次方。 */ static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; }typedef struct {char *buffer; int length; int offset; } printbuffer; //printbuffer的數(shù)據(jù)結(jié)構(gòu):地址、長度和偏移量。static char* ensure(printbuffer *p,int needed) //ensure 函數(shù)是一個(gè)協(xié)助printbuffer分配內(nèi)存的一個(gè)函數(shù) //p->length表示當(dāng)前字符串的長度 {char *newbuffer;int newsize;if (!p || !p->buffer) return 0; //p空或p->buffer空,則返回0。needed+=p->offset; //需要額外分配的內(nèi)存,也就是偏移量if (needed<=p->length) return p->buffer+p->offset;newsize=pow2gt(needed); //pow2gt返回newsize所需要的空間。newbuffer=(char*)cJSON_malloc(newsize); //malloc出新內(nèi)存 放buffer里面的內(nèi)容。if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}if (newbuffer) memcpy(newbuffer,p->buffer,p->length); //分配成功就將原先的p的內(nèi)容復(fù)制過去。cJSON_free(p->buffer);p->length=newsize;p->buffer=newbuffer;return newbuffer+p->offset; }?
創(chuàng)建數(shù)組的一些列函數(shù)
/* 用于數(shù)組列表處理的實(shí)用工具。 */ // prev->next指向item,item->prev指向prev。 static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}/* 創(chuàng)建數(shù)組: */ cJSON *cJSON_CreateIntArray(const int *numbers,int count) { int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i) //若i為0。a->child=n;else suffix_object(p,n); // p->next指向n,n->prev指向p。p=n;}return a; } cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}?
添加項(xiàng)到數(shù)組/對象中
/* 用于數(shù)組列表處理的實(shí)用工具。 */ // prev->next指向item,item->prev指向prev。 static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}/* 將項(xiàng)目添加到數(shù)組/對象中。 */ 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); //c->next指向item,item->prev指向c。} }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);} void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);} void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}?
總結(jié)
以上是生活随笔為你收集整理的cJSON源码及解析流程详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TED演讲——人生的12条法则
- 下一篇: Google Chubby 论文翻译