日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

cJSON源码及解析流程详解

發布時間:2024/2/28 javascript 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 cJSON源码及解析流程详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

cJSON簡介

cJSON.h

cJSON結構

cJSON結點的創建

cJSON解析

parse_objec( )

parse_array( )

parse_number( )

parse_string( )

cJSON打印

其他函數

?

cJSON簡介

JSON(JavaScript?Object Notation, JS 對象簡譜) 是一種輕量級的數據交換格式。它基于?ECMAScript?(歐洲計算機協會制定的js規范)的一個子集,采用完全獨立于編程語言的文本格式來存儲和表示數據。簡潔和清晰的層次結構使得 JSON 成為理想的數據交換語言。 易于人閱讀和編寫,同時也易于機器解析和生成,并有效地提升網絡傳輸效率。cJSON從名字可知,整個項目都是以極標準的C來寫的,意思說,可以跨各種平臺使用了。cJSON是一個超輕巧,攜帶方便,單文件,簡單的可以作為ANSI-C標準的JSON解析器。

cJSON官網下載:https://sourceforge.net/projects/cjson/

cJSON ?GitHub:https://github.com/DaveGamble/cJSON

說明:本篇博文分析的源碼是在官網下載的,最后更新時間是2016-9-23。GitHub上的源代碼更新,同時其代碼量也更大。但它們的核心代碼和思想差不多,各位可以根據自身需求選擇。

?

cJSON.h

因為頭文件的內容不是很多,所以我將其全部羅列出來,其中的核心函數是解析函數和打印函數。只要清楚cJSON的數據結構后,看相應的代碼才能比較簡單。頭文件中并沒有包含所有的函數,有的函數是在cJSON.c中定義的,一般是在解析過程中重復次數較多的函數。

#ifndef cJSON__h #define cJSON__h#ifdef __cplusplus extern "C" //extern "C"的主要作用就是為了能夠正確實現C++代碼調用其他C語言代碼。加上extern "C"后, //會指示編譯器這部分代碼按C語言的進行編譯,而不是C++的。由于C++支持函數重載,因此編譯 //器編譯函數的過程中會將函數的參數類型也加到編譯后的代碼中,而不僅僅是函數名;而C語言 //并不支持函數重載,因此編譯C語言代碼的函數時不會帶上函數的參數類型,一般之包括函數名。 { #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結構體: */ typedef struct cJSON {struct cJSON *next,*prev; /* next/prev結構體指針允許你遍歷數組/對象鏈。另外,使用GetArraySize 、 GetArrayItem 、 GetObjectItem方法獲取相應的項。 */struct cJSON *child; /* 數組或對象將有一個child指針指向數組/對象中的頭結點。 */int type; /* 項的類型 */char *valuestring; /* 如果type==cJSON_String,則是字符串。 */int valueint; /* 如果type==cJSON_Number,則是int。 */double valuedouble; /* 如果type==cJSON_Number,則是double。 */char *string; /* json對象的名稱。 */ } cJSON;/* 該結構體提供了分配和釋放空間的函數指針 */ typedef struct cJSON_Hooks {void *(*malloc_fn)(size_t sz);void (*free_fn)(void *ptr); } cJSON_Hooks;/* 向cJSON提供malloc和free函數 */ extern void cJSON_InitHooks(cJSON_Hooks* hooks);/* 提供一個JSON塊,然后返回一個可以查詢的cJSON對象。完成后調用cJSON_Delete。 */ extern cJSON *cJSON_Parse(const char *value); /* 將cJSON實體呈現為用于傳輸/存儲的文本。完成后釋放char*。 */ extern char *cJSON_Print(cJSON *item); /* 將cJSON實體呈現為用于傳輸/存儲的文本,而不進行任何格式化。完成后釋放char*。 */ extern char *cJSON_PrintUnformatted(cJSON *item); /* 使用緩沖策略將cJSON實體呈現為文本。預緩沖是對最終大小的猜測。猜測減少了重新分配。fmt=0表示無格式,=1表示有格式 */ extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt); /* 刪除一個cJSON實體和所有子實體。 */ extern void cJSON_Delete(cJSON *c);/* 返回數組(或對象)中的項數。 */ extern int cJSON_GetArraySize(cJSON *array); /* 從數組“數組”中檢索項目編號“項目”。如果不成功,返回NULL。 */ extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); /* 從對象中獲取項目"string"。不區分大小寫。 */ extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);/* 用于分析失敗的語法。這將返回一個指向解析錯誤的指針。 你可能需要回頭看幾個字才能理解它。當cJSON_Parse()返回0時定義。當cJSON_Parse()成功時為0。 */ extern const char *cJSON_GetErrorPtr(void);/* 這些調用創建適當Type的cJSON項。 */ 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);/* 根據count創建數組。 */ 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);/* 向指定的數組/對象追加項。 */ 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); /* 當字符串確實是常量(例如,是一個文本,或者與常量一樣好),并且肯定會在cJSON對象中存活時,就使用這個方法 */ /* 將對項的引用追加到指定的數組/對象。當您想要將現有的cJSON添加到新的cJSON中,但又不想破壞現有的cJSON時,可以使用此方法。 */ extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);/* 從數組/對象中刪除/分離項。 */ 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);/* 更新數組項 */ extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* 將已存在的項目向右移動。 */ extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);/* 復制一個cJSON項目 */ extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); /* Duplicate將在需要釋放的新內存中創建一個與傳遞的cJSON相同的新項目。 遞歸!=0,它將復制連接到該項的所有子元素。條目->next和->prev指針在從Duplicate返回時總是0。*//* ParseWithOpts允許您要求(并檢查)JSON是否以null結尾,并檢索指向解析后的最終字節的指針。 */ extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);extern void cJSON_Minify(char *json);/* 用于快速創建內容的宏。 */ #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))/* 在分配整數值時,也需要將其傳播到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結構

cjson的存儲結構整體可以簡單的看成一條鏈表(單向),同一級別下的兄弟結點之間通過prev和next指針連接起來(雙向),prev和next分別指向cjson對象的前驅和后繼child則指向下一級結點,這里通過名字也可以理解為指向孩子結點。以下是例子及其結構圖:

{"Asd": [{ "賬號":"a123456789" , "密碼":"asdasdasd123456" },{ "賬號":"b123456789" , "密碼":"qweqweqwe123456" }] }

例子中的Asd是一個數組,里面存儲的內容是對象。對象存儲的內容是賬號和密碼,賬號結點和密碼結點的類型都是string,而string的值分別賦予了賬號和密碼意義。這里直接將cJSON結構圖列出,是為了方便大家閱讀源代碼時方便理解。

?

cJSON結點的創建

結點創建函數很簡單,就是為cJSON結構體申請空間并用memset進行初始化,然而沒有設置結構體內的成員,后續根據需求再對結構體中的類型進行設置。可以看到下面的創建基本類型函數,都是先調用cJSON_New_Item( ),再進行成員設置。

/* 內部構造函數,創建一個新的Item */ static cJSON *cJSON_New_Item(void) {cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));if (node) memset(node,0,sizeof(cJSON)); //memset是計算機中C/C++語言初始化函數。作用是將某一塊內存中的內容全部設置為指定的值//這個函數通常為新申請的內存做初始化工作。 原型:void *memset(void *s, int ch, size_t n);return node; } /* 創建基本類型: */ // 通過調用cJSON_New_Item()函數創建cJSON結構體,再根據需求設置相應的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;}/* 頭文件中快速創建內容的宏 */ /* 用于快速創建內容的宏。 */ #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項目的核心代碼,它的流程圖如下:

cJSON解析的二次封裝:

/* cJSON_Parse的默認選項,用于將文本解析為JSON */ 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(); //只是創建了一個cJSON結構體,沒有其他操作。ep=0;if (!c) return 0; /* 內存分配失敗,返回0 */end=parse_value(c,skip(value)); //skip只跳過開頭的控制字符 if (!end) {cJSON_Delete(c);return 0;} /* 解析失敗 *//* 如果我們需要沒有附加以null結尾的JSON,跳過,然后檢查是否有null終止符 *///函數中參數中提供了require_null_terminated是為了確保json字符串必須以'\0'字符作為結尾。//若參數提供了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; } /* 解析器核心——遇到文本時,適當地處理。 */ static const char *parse_value(cJSON *item,const char *value) {if (!value) return 0; /* 不能為空,若為空,返回0 *///strncmp函數為字符串比較函數,函數聲明為int strncmp ( const char * str1, const char * str2, size_t n );//若str1與str2的前n個字符相同,則返回0;若s1大于s2,則返回大于0的值;若s1 小于s2,則返回小于0的值。//對于json為null、true或者false的情況,直接將type置為對應的類型即可。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的結構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; /* 失敗 */ }

前三步很簡單,調用cJSON_Parse(),其內部為cJSON_ParseWithOpts(),它調用parse_value()函數進行解析,這里函數首先調用cJSON_NewItem()創建節點,用于存放解析的JSON結構數據。然后根據不同的Type,再調用相應的parse_string(),parse_number(),parse_array()或parse_objec()。對應上面提到的cJSON的結構圖,若是同一級下的結點,會形成一個雙向鏈表,用于連接該級下的兄弟結點。若不是同一級,則會讓上一次結點的child指針指向新的結點。

?

parse_objec( )

接下來的代碼分析需要結合官方圖表才能更好的理解其原理。先說一下圖表,對于一個object而言,一定是從 " { " 開始, " } "結束。程序會先判斷該對象是不是為空,即" { " 后除了控制字符外,是不是只剩下?" } "。若是,則說明這個對象是空的。若不是,接下來會遇到whitespace和字符串。程序用skip() 巧妙地跳過了控制字符,方便了對象內容的解析。你會發現代碼中有一段代碼是 value=skip(parse_string(child,skip(value))); ,這是因為跳過whitespace后,會直接遇到string類型的數據。而后會遇到 " :?",代碼中也進行了相應的處理,即value=skip(parse_value(child,skip(value+1)));?。當string和value都處理完了后,可能還有別的內容。這里的判斷條件是如果遇到 " , ",說明后續還有內容,所以在while循環內的代碼重復了上述的工作。在while中,會調用cJSON_New_Item( )創建新的結點,然后將它們連接在一起(此時的內容是同級的)。這里是對圖片和代碼的一個講解,大家可以先看看圖片,再去看代碼,這樣思路會清晰很多。

/* 跳轉空格和cr/lf的實用程序,但只會跳過第一個能顯示的字符之前的控制字符 */ // ASCII碼值小于32的為控制字符 static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}/* 從文本構建一個對象。 */ 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(); //為child分配空間,用child指向下一層結點 if (!item->child) return 0; value=skip(parse_string(child,skip(value))); //由JSON的object結構可知,在排除內容為空的前提下,{后遇到的可能是//空格或字符串,所以用skip跳過空格,那么第一個直接遇到的就是字符串//所以直接調用parse_string()函數。最外層的skip函數可以直接指向':'。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; }

?

parse_array( )

同理對于一個array而言,一定是從 " [ " 開始, " ]?"結束。程序會先判斷該數組是不是為空,即" [?" 后除了控制字符外,是不是只剩下?" ]?"。若是,則說明這個數組是空的。若不是,接下來會遇到value。程序用skip() 跳過了控制字符,方便數組內容的解析。這里的操作流程和思想和上述parse_objec()很像,而且array相對于object更簡單點。

/* 從輸入文本構建一個數組。 */ static const char *parse_array(cJSON *item,const char *value) {//解析數組時,其基本思想是對數組中每一個元素遞歸調用parse_value,再將這些元素連接形成一個鏈表。cJSON *child;if (*value!='[') {ep=value;return 0;} /* 不是一個數組! */item->type=cJSON_Array; //置類型為itemvalue=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==',') //','表明后面還有內容,那么就將上述操作再進行多次即可。 { //這一部分相對于parse_object()簡單的原因是','后是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; }

?

parse_number( )

這一部分,函數比較簡單,反而是圖比較復雜,建議直接看代碼。

/* 解析輸入文本以生成數字,并將結果填充到項中。 */ 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++; /* 是0 */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)); /* 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的處理思想和上面的基本一樣,不同的是判斷條件的不一樣。因為源代碼中有一句注釋 /* UTF16 surrogate pairs。 */。百度后才知道它是什么意思,字面意義是:代理對。實際上是指:對于一個UTF16編碼改用兩個UTF16編碼來代替。本來一個字符用一個UTF16編碼(兩個字節)來表示即可,但是由于需要被編碼的字符越來越多,只用一個UTF16編碼已經不足于表示所有的字符。因此,就需要考慮使用2個UTF16來表示一個字符(四個字節)。

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; } /* 將輸入文本解析為未轉義的cstring,并填充項。 */ 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;} /* 若開頭不是'"',則不是一個字符串! *///由定義ptr=str+1;可知,ptr指向字符串的第個字符while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* 跳過了引號。 */// "Asd qwe zxc!" 長度為12,"Asd \"qwe\" zxc!"長度為14。/* 除“或\或控制字符外的任何代碼點 */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轉換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。 字面意義是:代理對。實際上是指:對于一個UTF16編碼改用兩個UTF16編碼來代替。*/{ //本來一個字符用一個UTF16編碼(兩個字節)來表示即可,但是由于需要被編碼的字符越來越多,//只用一個UTF16編碼已經不足于表示所有的字符。因此,就需要考慮使用2個UTF16來表示一個字符(四個字節)。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項/實體/結構呈現為文本。 */ 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打印就是從根對象的結構體開始遍歷,得到每個item結點的名稱和數據,并經過處理成特定的cjson字符串的輸出形式。 //cJSON_Print(root)和cJSON_PrintUnformatted(root)函數都是打印成json字符串的函數,兩者的區別就是 //cJSON_PrintUnformatted(root)處理過的字符串里沒有\t\n這類格式

我用官方給實例代碼運行程序時,因為沒有涉及到printbuffer(即令該值為0),所以程序走的都是else內的操作。

/* 為文本呈現一個值。 */ static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) { // fmt傳入時值為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; }

?

該函數,開始使用numentries記錄對象的數量。因為上面提到了printbuffer *p = 0,所以在組成輸出格式的時候,分配2個指針數組存儲對象里的鍵和值。最后通過對兩個指針數組的內容的拼接,將數據組成輸出的格式。可以看到代碼末端" { " 和 " } "之間的代碼都是拼接操作。這部分的代碼,要先將else內的邏輯流程看懂。

/* 將對象呈現為文本。 */ 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記錄對象的數量。 */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個指針數組存儲對象里的鍵和值。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){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; }

?

該函數,開始使用numentries記錄數組中元素的數量。這里的printbuffer *p = 0,在組成輸出格式的時候,分配一個指針數組存儲數組里的每一個元素的打印結果。這里多的一個操作是,數組內容可能是對象,所以要調用print_value()打印相應內容。可以在源代碼中看到ret=print_value(child,depth+1,fmt,0);??。獲取數據后,接下來組成數組的輸出形式。代碼末端" [?" 和 " ]?"之間的代碼都是拼接操作。

/* 將數組呈現為文本 */ 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記錄數組中有多少元素 */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){/* 組合輸出數組。*/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); //數組內容可能是對象,所以要調用print_value打印相應內容。返回值為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;}/* 數據已經獲取了,接下來組成數組的輸出形式。*/*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; }

?

在看這部分代碼時,我一直在糾結ensure(),最后發現它是一個協助printbuffer分配內存的函數,而代碼中的printbuffer *p = 0。所以只需要跳過相應的代碼就可以理解它的邏輯流程了。這里遇到不懂的是DBL_EPSILON和sprintf(str,"%d",item->valueint);,這兩個問題的解釋在注釋中。

/* 將給定項中的數字漂亮地呈現為字符串。 */ 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 作用是求浮點數的絕對值。 double fabs(double x );//DBL_EPSILON和 FLT_EPSILON主要用于單精度和雙精度的比較當中:if (p) str=ensure(p,21);else str=(char*)cJSON_malloc(21); /* 2^64+1 可以用21個字符表示。 */if (str) sprintf(str,"%d",item->valueint); //函數功能:格式化字符串,將格式化的數據寫入字符串中。//函數原型:int sprintf(char *buffer, const char *format, [argument]…)//格式化數字字符串:在這點上sprintf和printf的用法一樣,只是打印到的位置不同而已,前者打印給buffer字符串//后者打印給標準輸出,所以sprintf也可以用來將整型轉化為字符串//比itoa效率高且簡便,比如:sprintf(buffer, "%d", 123456);執行后buffer即指向字符串"123456"。}else{if (p) str=ensure(p,64);else str=(char*)cJSON_malloc(64); /* 這是一個很好的權衡。 */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_ptr()中while里的內容。

/* 引用print_string_ptr()函數。 */ static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);} /* 將提供的cstring呈現給一個可以打印的轉義版本。 */ 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; }

?

?

其他函數

聲明函數指針,方便分配和釋放空間。以下代碼就不細講了,注釋中有相應的解釋。

static void *(*cJSON_malloc)(size_t sz) = malloc; //聲明函數指針,例如:double (*pf)(int); static void (*cJSON_free)(void *ptr) = free; //這兩個函數返回值都是void * /* 該結構體提供了分配和釋放空間的函數指針 */ 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若為空,根據s1和s2是否相等返回0或者1。if (!s2) return 1; //s2若為空,返回1。for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) //tolower的功能是把字母字符轉換成小寫,非字母字符不做出處理。if(*s1 == 0) //函數說明:若參數 c 為大寫字母則將該對應的小寫字母返回。return 0; //返回值:返回轉換后的小寫字母,若不須轉換則將參數c 值返回。return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); }

?

cJSON_strdup()

static char* cJSON_strdup(const char* str) //cJSON的字符串拷貝函數 { //strdup()函數是c語言中常用的一種字符串拷貝庫函數,一般和free()函數成對出現。size_t len; //strdup()在內部調用了malloc()為變量分配內存,不需要使用返回的字符串時char* copy; //需要用free()釋放相應的內存空間,否則會造成內存泄漏。len = strlen(str) + 1;if (!(copy = (char*)cJSON_malloc(len))) return 0;memcpy(copy,str,len); //memcpy指的是C和C++使用的內存拷貝函數return copy; //函數原型為void *memcpy(void *destin, void *source, unsigned n); } //函數的功能是從源內存地址的起始位置開始拷貝若干個字節到目標內存地址中。

?

cJSON_Delete()

/* 刪除cJSON結構體 */ 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->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);cJSON_free(c);c=next;} }

?

ensure()

/* 例如x = 6或8,則返回8。 x = 12或13,則返回16。 總結:返回 >= 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的數據結構:地址、長度和偏移量。static char* ensure(printbuffer *p,int needed) //ensure 函數是一個協助printbuffer分配內存的一個函數 //p->length表示當前字符串的長度 {char *newbuffer;int newsize;if (!p || !p->buffer) return 0; //p空或p->buffer空,則返回0。needed+=p->offset; //需要額外分配的內存,也就是偏移量if (needed<=p->length) return p->buffer+p->offset;newsize=pow2gt(needed); //pow2gt返回newsize所需要的空間。newbuffer=(char*)cJSON_malloc(newsize); //malloc出新內存 放buffer里面的內容。if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}if (newbuffer) memcpy(newbuffer,p->buffer,p->length); //分配成功就將原先的p的內容復制過去。cJSON_free(p->buffer);p->length=newsize;p->buffer=newbuffer;return newbuffer+p->offset; }

?

創建數組的一些列函數

/* 用于數組列表處理的實用工具。 */ // prev->next指向item,item->prev指向prev。 static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}/* 創建數組: */ 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;}

?

添加項到數組/對象中

/* 用于數組列表處理的實用工具。 */ // prev->next指向item,item->prev指向prev。 static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}/* 將項目添加到數組/對象中。 */ 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));}

?

總結

以上是生活随笔為你收集整理的cJSON源码及解析流程详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

精品久久中文 | 日韩精品免费一区二区在线观看 | 国产精品一区二区久久久 | 手机av永久免费 | 久久91网| 色婷婷骚婷婷 | 探花系列在线 | 久久久久国产精品厨房 | www天天干com | 欧美久久久久久久久中文字幕 | 天天av天天| 久久一区精品 | 91精品推荐 | 91探花系列在线播放 | 免费看十八岁美女 | 亚洲最新合集 | 久久精品中文字幕免费mv | 国产成人av在线 | 免费日韩 精品中文字幕视频在线 | 天天操天天操一操 | 亚洲成aⅴ人片久久青草影院 | 精品视频999 | 美女免费av| 天天爱天天射天天干天天 | 91看片在线观看 | 99久久综合狠狠综合久久 | 草久久久久 | 五月天综合网 | 99久久精品免费看国产免费软件 | 青青射| 亚洲成av人片一区二区梦乃 | 91最新中文字幕 | 91视频在线自拍 | 成人a在线观看高清电影 | 成人在线免费视频 | 五月婷婷六月丁香在线观看 | 亚洲精品乱码久久久久v最新版 | 国产精品久久久久婷婷二区次 | 九九精品在线观看 | 亚洲午夜久久久久久久久 | 国产系列在线观看 | 中文字幕亚洲国产 | 综合色站导航 | 欧美91视频 | 国产黄色片一级三级 | av网在线观看 | 久久精品久久久久电影 | 成人黄色大片在线免费观看 | 日韩区欠美精品av视频 | 9999在线视频 | 欧美巨乳网 | 毛片永久新网址首页 | 日韩欧美高清 | 99国产视频在线 | av电影不卡 | 免费观看一级 | 亚洲欧美日韩在线看 | 亚洲精品视频在线 | 国产精品久久久久久久久岛 | 97在线超碰 | 激情五月婷婷综合网 | 97香蕉久久超级碰碰高清版 | 天天干天天做 | 国产在线播放一区二区 | 波多野结衣一区二区三区中文字幕 | 激情五月婷婷激情 | 97综合在线 | 成人黄在线观看 | 国产精品国内免费一区二区三区 | 中文久久精品 | 狠狠色噜噜狠狠狠狠 | 国产精品久久久久久久电影 | 五月天婷婷视频 | 亚洲高清在线视频 | 91免费试看| 五月婷婷久久综合 | 毛片无卡免费无播放器 | 免费视频久久久久久久 | 在线视频观看你懂的 | 在线亚洲成人 | 国产精品久久久久久久久免费看 | 日韩在线视频在线观看 | 亚洲精品麻豆 | 99在线国产 | 国产在线观看你懂得 | 久久伊人综合 | 色狠狠综合天天综合综合 | 国产亚洲精品久久久久久 | 久久久九九 | www..com黄色片 | www.久久com | 五月婷婷六月丁香在线观看 | 亚洲综合激情 | 中国一级片在线观看 | 激情五月亚洲 | 中文字幕国产一区二区 | 亚洲精品看片 | 天天干天天干天天 | 久草在在线 | 麻豆91在线| 久草视频在线资源站 | 在线免费黄色片 | 综合婷婷 | 我爱av激情网 | 国产亚洲精品女人久久久久久 | 极品嫩模被强到高潮呻吟91 | 日韩欧美视频在线观看免费 | 精品视频免费播放 | 久久久资源网 | 精品久久久亚洲 | 日韩精品久久一区二区三区 | 日韩av一区二区三区 | 麻豆播放| 99色在线播放 | 欧美巨乳波霸 | 午夜精品电影一区二区在线 | 97偷拍视频 | 探花视频在线观看免费 | 亚洲电影在线看 | 丁香六月婷婷激情 | 中文一区二区三区在线观看 | 又紧又大又爽精品一区二区 | 亚洲欧美日韩国产一区二区三区 | 看黄色.com| 国产精品毛片久久久久久久久久99999999 | 欧美激情视频一区二区三区免费 | 国产高清第一页 | 亚洲一二三区精品 | 国产日产高清dvd碟片 | 欧美日韩精品网站 | 一区二区三区久久精品 | 日本久久中文字幕 | 成年人在线视频观看 | 久久婷婷开心 | 99中文在线| 激情婷婷久久 | 国产亚洲精品久久久久久久久久久久 | 中文av日韩| 综合网伊人 | 久久亚洲美女 | 四虎成人免费观看 | 亚洲综合小说电影qvod | 探花视频免费观看 | 97视频免费在线 | 国产女人免费看a级丨片 | 一级成人免费视频 | 国产人成看黄久久久久久久久 | 久草在线观看资源 | 国产成人av福利 | 国产二区免费视频 | 久久久久久久久久久成人 | 色丁香综合 | 中文字幕久久网 | 又紧又大又爽精品一区二区 | 人人插人人爱 | 香蕉日日 | av在线等| 色偷偷88欧美精品久久久 | 一区二区久久久久 | 色播亚洲婷婷 | 美女性爽视频国产免费app | 国产一级黄色av | 91视频亚洲| 欧美在线视频免费 | 最新一区二区三区 | 91在线观看黄 | 国产高清视频免费最新在线 | 毛片网站观看 | 欧美亚洲国产日韩 | 黄污在线观看 | 日韩天堂在线观看 | 国产精品久久久影视 | 日韩动漫免费观看高清完整版在线观看 | 免费看黄色大全 | 久草视频国产 | 精品久久久久一区二区国产 | 超碰人人在线 | 中文字幕精品一区二区三区电影 | 亚洲人成在线电影 | 国产视频午夜 | 伊人亚洲精品 | 久久久人人爽 | 97福利在线观看 | 亚洲精品国产欧美在线观看 | 欧美在线观看小视频 | 日韩啪视频 | 成人福利av | av成人在线观看 | 精品日韩视频 | 久久免费视频4 | 日日成人网 | 91自拍视频在线观看 | 中文字幕精品一区二区精品 | 91麻豆看国产在线紧急地址 | 欧美成人精品欧美一级乱黄 | 国产资源在线观看 | 亚洲久在线 | 精品美女国产在线 | 日韩精品一区二区三区在线视频 | 五月精品| www蜜桃视频 | 五月开心激情网 | 国产成视频在线观看 | 亚洲少妇xxxx | 97av在线视频免费播放 | av免费看在线 | 超碰在线9| 久99精品 | 精品一区二区日韩 | 在线高清一区 | 久久高清国产视频 | 亚洲国产精品成人精品 | 91视频免费看| 久久久精品视频成人 | 九色精品在线 | 天天操天天操天天操天天操天天操 | 一区二区三区四区不卡 | 午夜免费电影院 | 亚洲一级片在线看 | 成人小视频免费在线观看 | 日韩精品久久久久久中文字幕8 | 91精品国产91久久久久福利 | 久久草草热国产精品直播 | 日韩av在线看 | 在线精品视频在线观看高清 | 欧美激情在线网站 | 精品免费视频 | 免费 在线 中文 日本 | 免费av 在线 | 一级淫片在线观看 | 东方av在线免费观看 | 国产偷v国产偷∨精品视频 在线草 | 亚洲黄色激情小说 | 日韩最新在线 | 九九热中文字幕 | 美女视频黄免费网站 | 国产理伦在线 | 精品免费久久 | 久草视频在线免费看 | 激情欧美一区二区三区免费看 | 亚洲永久字幕 | 在线电影日韩 | 久草视频免费在线播放 | 欧美精品国产综合久久 | 天天综合视频在线观看 | 成人av在线电影 | 天天干天天干天天干天天干天天干天天干 | 亚洲精品资源在线 | 超碰在线人人 | 人人爽久久涩噜噜噜网站 | 色视频 在线 | 国产字幕在线观看 | 久久久久久免费毛片精品 | 五月天九九| 欧美专区亚洲专区 | 在线av资源| 国内视频一区二区 | 狠狠色丁香久久婷婷综合五月 | 久久精品国产一区二区 | 福利视频区 | 国产亚洲精品久久久久动 | 欧美日韩亚洲国产一区 | 免费在线观看日韩视频 | 国产va精品免费观看 | 国产中文在线观看 | 日韩电影在线一区 | 亚洲伊人天堂 | 亚洲欧美成人 | 久久伊人国产精品 | 婷婷丁香狠狠爱 | 天天综合成人网 | 欧美久久久久久 | 国产精品九九九 | 手机看国产毛片 | 日韩欧美国产视频 | 久久久久亚洲精品成人网小说 | 亚洲精品在线观看中文字幕 | 亚洲精品综合一二三区在线观看 | 国产成人av电影在线观看 | 国产高清av在线播放 | 中文字幕 国产视频 | 国产精品18久久久久vr手机版特色 | 狠狠干我| 国产原创91 | 丁香综合| 成人免费xxxxxx视频 | 久久久久久久久黄色 | 精品久久精品久久 | 狠狠色狠狠色综合系列 | 成人黄色小视频 | 婷婷久久五月 | 久久国际影院 | 最近能播放的中文字幕 | 黄色免费网站 | 亚洲国产精品小视频 | 人人要人人澡人人爽人人dvd | 日韩精品久久一区二区 | 国产资源在线播放 | 日韩动漫免费观看高清完整版在线观看 | 久久久国产精品麻豆 | 911在线| 九九视频在线观看视频6 | 亚洲黄色av一区 | www.99久久.com | 日韩免费在线观看视频 | 久久久精品免费观看 | 不卡的av在线播放 | www.五月天婷婷 | 欧美精品一区二区在线播放 | 久久国产午夜精品理论片最新版本 | av.com在线| 精品999在线观看 | 国产精品高清在线观看 | 超碰日韩在线 | 日韩免 | 亚洲一区二区三区四区精品 | 在线国产一区二区 | 综合亚洲视频 | 久9在线 | 欧美日韩首页 | 婷婷中文字幕在线观看 | 欧美少妇影院 | 福利网在线 | 狠狠狠操| 日韩欧美一区二区在线观看 | 在线精品亚洲一区二区 | 欧美韩日视频 | 国产精品专区h在线观看 | 国产精品久久久久永久免费看 | 中文字幕4 | 麻豆免费精品视频 | 久久精品视频在线观看免费 | 久久99操| 国产第一福利 | 国产一级视频免费看 | 五月天久久婷 | 在线播放国产一区二区三区 | 日韩黄色免费在线观看 | 国产一区二区在线免费播放 | 国产网红在线 | 天堂在线一区二区三区 | 国产综合香蕉五月婷在线 | 五月婷婷中文 | av三级在线看 | 成人一区二区三区中文字幕 | 久久最新视频 | 午夜电影久久久 | 免费日韩 精品中文字幕视频在线 | 91激情视频在线 | a黄色影院| 中文亚洲欧美日韩 | 99精品国产福利在线观看免费 | 久久99热国产| 久久久久福利视频 | 国产一级片一区二区三区 | 一区 在线 影院 | 在线免费视频a | 国产精品视频专区 | 日本3级在线观看 | 91精品啪在线观看国产线免费 | 激情婷婷在线观看 | 国产不卡av在线 | 欧美一级在线观看视频 | 国产色网 | 成年人看片| 91桃色在线免费观看 | 婷婷丁香社区 | 91精品一区二区在线观看 | 日韩电影一区二区三区 | 99久久免费看 | 一区二区三区四区免费视频 | 亚洲成人黄色在线 | 国产成人99av超碰超爽 | 国产私拍在线 | 婷婷丁香视频 | 男女激情片在线观看 | av高清在线| 国内免费久久久久久久久久久 | 精品国产乱码久久久久久1区二区 | 精品一区电影 | www.久久久 | 欧美日韩久久 | 色综合激情网 | 三级黄色理论片 | 九九久久免费视频 | 色a4yy| 91九色最新地址 | 91人人澡人人爽 | 国产成人精品亚洲日本在线观看 | 日韩欧美视频免费看 | 黄色av电影一级片 | 视频在线在亚洲 | 国产精品毛片一区二区在线 | 免费av片在线 | 免费黄色在线 | 久久尤物电影视频在线观看 | 99亚洲国产 | 精品一区二区视频 | 黄a在线| 91在线视频精品 | 久久伊人精品天天 | 播五月综合 | 国产成人精品999 | 国产 日韩 欧美 中文 在线播放 | 国产一区在线精品 | 日日夜夜天天 | 免费高清在线视频一区· | 久久第四色 | 中文字幕资源网 国产 | 日韩成人精品 | 亚洲国产精品久久久久婷婷884 | 免费成人在线观看视频 | www免费黄色 | 久久av一区二区三区亚洲 | 13日本xxxxxⅹxxx20| 麻豆mv在线观看 | 开心色停停 | 特级西西444www大胆高清无视频 | 美女黄频 | 成人av影视观看 | 免费av免费观看 | 99久久这里有精品 | 亚洲在线成人精品 | 国产成人精品亚洲 | 久久久蜜桃 | 免费av电影网站 | 免费看色视频 | 国产精品久久久久久久久大全 | 在线视频欧美精品 | 久久精品激情 | 色av色av色av| 婷婷丁香在线视频 | 久久人人看 | av资源中文字幕 | 国产精品自产拍在线观看网站 | 天天干天天操 | 91精品视频在线观看免费 | 国产成人久久精品77777综合 | 成人xxxx | 99热最新在线| 香蕉视频在线免费看 | 亚洲高清视频一区二区三区 | 操操日| 亚洲欧美日韩国产 | 国产69精品久久99的直播节目 | 色婷婷电影 | 国产在线不卡精品 | av中文字幕在线看 | 人人爽人人插 | www国产亚洲精品久久网站 | 伊人五月天婷婷 | 亚洲区色| 久久久亚洲精华液 | 黄色在线看网站 | 亚洲国产理论片 | 狠日日| 婷婷五月色综合 | 夜夜躁日日躁狠狠久久88av | 国产精品黄色在线观看 | 亚洲成人精品影院 | 国产成人久久77777精品 | 人人爽人人爽人人 | 夜色成人网 | 又黄又爽又无遮挡免费的网站 | 国产理论片在线观看 | 中文字幕第一 | 就操操久久 | 亚洲国产午夜视频 | 国产一区自拍视频 | 在线欧美国产 | 性色在线视频 | 日日射av| 久久精品一区二区三区视频 | 天天干夜夜干 | 精品一区二区三区香蕉蜜桃 | 精品久久久久久久久久岛国gif | 国产精品久久久久久久久久久久午 | 国产欧美精品一区aⅴ影院 99视频国产精品免费观看 | 人人添人人 | 国内精品久久久久影院一蜜桃 | 日韩高清不卡一区二区三区 | 97久久精品午夜一区二区 | 91九色蝌蚪在线 | 波多野结衣久久资源 | 日韩美在线观看 | 久久视频精品 | 色婷婷亚洲综合 | 激情深爱.com | 麻豆传媒在线免费看 | 免费婷婷 | 66av99精品福利视频在线 | 色大片免费看 | 99久久精品免费看国产免费软件 | 91人人澡人人爽人人精品 | av大片免费 | 四川妇女搡bbbb搡bbbb搡 | www婷婷| 免费的国产精品 | 97超碰国产精品女人人人爽 | 国产欧美最新羞羞视频在线观看 | 亚洲国产电影在线观看 | 97超碰免费 | 九九九视频精品 | 婷婷色av | 婷婷久月 | 夜夜操网站 | 香蕉在线观看 | 色黄www小说 | 色狠狠婷婷 | 99久久久久 | 免费在线观看av的网站 | 国产精品麻豆一区二区三区 | 国产美女精品久久久 | 亚洲网站在线看 | 五月亚洲 | 奇人奇案qvod | 亚州精品在线视频 | 日日干日日色 | 亚洲成a人片在线观看中文 中文字幕在线视频第一页 狠狠色丁香婷婷综合 | 国产一区久久 | 九九热久久免费视频 | 色偷偷88欧美精品久久久 | 欧美伦理一区二区三区 | 五月婷婷视频在线 | 久久国产一区二区三区 | 成人在线一区二区三区 | 亚洲视频综合 | 蜜桃av观看 | 久久99国产精品免费 | 欧美日韩aa | 国产精品中文在线 | 久久精品9 | 欧美一级欧美一级 | 日韩精品亚洲专区在线观看 | 婷婷久久一区二区三区 | 国产一区播放 | 91探花国产综合在线精品 | 中文字幕资源在线观看 | 中文字幕在线观看完整版电影 | 在线免费观看黄 | 欧美精品999| 美女网站在线 | 欧美性脚交 | 欧美日韩一级视频 | 九九爱免费视频 | 日韩精品在线观看av | 99久久久| 久久99精品国产99久久6尤 | 欧美va日韩va | 欧洲色综合 | 91人网站| 国产日本三级 | 亚洲九九九在线观看 | 国产 日韩 欧美 中文 在线播放 | 91中文字幕一区 | 九九九热精品免费视频观看 | 色视频网站在线观看一=区 a视频免费在线观看 | 天天操天天爱天天干 | 99久久精品久久久久久清纯 | 99精品久久只有精品 | 国产精品久久久久久久久大全 | 国产精品免费大片视频 | 天天艹天天 | 免费视频91| 国产999| 在线免费看片 | 天天射天天舔天天干 | 日韩欧美视频免费看 | 免费av成人在线 | 国产成人性色生活片 | 久99久视频| 黄色网中文字幕 | 日韩高清www | 国产又黄又猛又粗 | 在线天堂中文在线资源网 | 在线免费观看国产 | 丁香六月婷 | 色夜影院 | 久久狠狠亚洲综合 | 日韩午夜精品福利 | 国产打女人屁股调教97 | 99久久精品午夜一区二区小说 | 国产九色在线播放九色 | 在线视频一二区 | 亚洲免费不卡 | 午夜精品久久久久久中宇69 | 成人97视频 | 国产一区二区免费在线观看 | 欧美激情va永久在线播放 | 天天干天天搞天天射 | 国产手机在线视频 | 97精品国产97久久久久久春色 | 亚洲午夜精品一区 | 久久精品影视 | 日韩毛片在线免费观看 | 四虎影院在线观看av | 91亚洲精品久久久蜜桃 | 国产不卡视频在线播放 | 麻豆久久精品 | 亚洲国产视频直播 | 亚洲视频,欧洲视频 | 国产又粗又猛又色又黄视频 | 在线视频观看国产 | 国产精品6| 午夜久久久久久久久久影院 | 天堂v中文 | 免费a级大片 | 亚洲成人资源网 | 一区二区三区免费网站 | 嫩草av在线 | 美女搞黄国产视频网站 | av福利在线播放 | 午夜精品久久久久久中宇69 | 8x成人免费视频 | a级黄色片视频 | a视频免费 | 黄色在线观看污 | 韩国一区二区三区在线观看 | 日韩理论在线 | 久久综合久色欧美综合狠狠 | 欧美 日韩 国产 成人 在线 | 亚洲国产一区二区精品专区 | 麻豆视频在线免费 | 欧美久久久久久久久久 | 在线观看免费黄视频 | 亚洲黄网站 | 国产亚洲午夜高清国产拍精品 | www.av中文字幕.com | 青青草在久久免费久久免费 | 黄p网站在线观看 | 在线va视频 | 日韩欧美网站 | 国产成人中文字幕 | 懂色av一区二区三区蜜臀 | 久久精品国产久精国产 | 岛国av在线免费 | 91在线视频免费 | 国产成人精品在线 | 91视频下载 | 亚洲精品影视在线观看 | 国产精品久久av | 欧美性色综合网 | 婷婷色吧 | 青春草免费视频 | 久久久久女人精品毛片 | 亚洲国产大片 | 精品一区二区三区四区在线 | 欧美中文字幕久久 | 在线看的毛片 | 日韩在线国产 | 人人爽人人插 | 国产精品免费在线播放 | 久久久久免费精品国产小说色大师 | 一区二区精品国产 | 亚洲精品国产精品国自产观看浪潮 | 国产三级精品三级在线观看 | 一区二区三区四区五区在线 | 日韩免费看片 | 日韩av成人在线观看 | 国产免费午夜 | 麻豆影视网 | 狠狠插狠狠干 | 亚洲国产精品激情在线观看 | 9999亚洲| 开心激情婷婷 | 日韩激情在线视频 | 丁香婷婷激情国产高清秒播 | 在线观看视频中文字幕 | 国产美女被啪进深处喷白浆视频 | 青青草国产精品 | 精品日韩视频 | 国产伦精品一区二区三区无广告 | 99日精品| 天堂网中文在线 | av福利在线播放 | 国产精品毛片一区视频播不卡 | 日韩久久久 | 日韩激情片在线观看 | avav片| 国产亚洲精品xxoo | 久久久麻豆| 欧美一级电影在线观看 | 成人免费 在线播放 | 天天插天天 | 国产91精品一区二区麻豆网站 | 伊人干综合| 91成人精品国产刺激国语对白 | 免费观看91视频 | 欧美一级大片在线观看 | 91麻豆.com| 国产精品一区二区62 | 中文字幕在线免费看 | 婷婷六月天丁香 | 日韩成人免费在线观看 | 亚洲高清在线 | 91精品天码美女少妇 | 久久精品国产99国产 | 久久福利剧场 | 日韩在线电影 | 97手机电影网 | 中文视频在线 | 欧美性大胆 | 精品麻豆入口免费 | 国产色网 | 成人在线播放视频 | 日韩精品中文字幕一区二区 | 久久全国免费视频 | 日韩电影久久久 | 久久超碰97| 久久91久久久久麻豆精品 | 99在线精品视频在线观看 | 国产精品丝袜在线 | 天天射天天干天天插 | 亚洲精品黄色在线观看 | 伊人午夜视频 | 精品人人爽| 久久中文字幕在线视频 | 亚洲美女在线一区 | 成人黄大片 | 天天插天天干 | 97超碰在 | 国产在线一线 | 99热99re6国产在线播放 | 91九色porny在线 | 日韩动漫免费观看高清完整版在线观看 | 国产精品女同一区二区三区久久夜 | 91九色蝌蚪在线 | 99热在线这里只有精品 | 免费手机黄色网址 | 在线亚洲高清视频 | 国产精品免费在线视频 | 久久婷亚洲五月一区天天躁 | 亚洲视频在线观看网站 | 亚洲欧美日韩精品久久久 | 色在线最新 | 99视频国产精品 | 中文字幕乱码电影 | 日本黄色免费电影网站 | 日韩高清精品免费观看 | 午夜精品一区二区三区免费视频 | 久久久三级视频 | 欧美一区二区三区四区夜夜大片 | 久久精品91久久久久久再现 | 成年人在线免费看视频 | 久久精品超碰 | 亚洲春色综合另类校园电影 | 伊人干综合 | 国产一级片网站 | 精品主播网红福利资源观看 | 人人爱爱人人 | 国产成人精品久久二区二区 | 国产69精品久久app免费版 | 最新色站 | 夜夜骑首页 | 日韩免费在线观看 | 色综合五月 | 精品一区二区综合 | 日韩有码在线播放 | 午夜18视频在线观看 | 99爱视频在线观看 | 视频二区在线 | 99色在线观看视频 | 国产亚洲高清视频 | 日本九九视频 | 婷婷色伊人 | 一区二区三区日韩视频在线观看 | 亚洲永久av | 色 中文字幕 | 有码中文在线 | 天天射天天射 | 日本精品一区二区三区在线播放视频 | 欧美精品中文 | 91豆麻精品91久久久久久 | 国产日韩欧美在线一区 | 麻豆国产在线播放 | 婷婷久久久 | 毛片1000部免费看 | 极品嫩模被强到高潮呻吟91 | 丁香激情综合 | 国产视频1区2区 | zzijzzij日本成熟少妇 | 夜色资源站wwwcom | 九九久久视频 | 色偷偷88888欧美精品久久久 | 久久的色 | 久久性生活片 | 91热精品视频 | 久久精品国产99 | 狠狠色2019综合网 | 日韩中文久久 | 狠狠干在线| 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 久久精品这里热有精品 | 蜜臀av性久久久久蜜臀aⅴ四虎 | 婷婷激情在线观看 | 成人黄大片视频在线观看 | 精久久久久 | 99久久这里只有精品 | 成人精品99 | 亚洲一本视频 | 91在线免费看片 | 亚洲视屏在线播放 | 91观看视频| 精品国产诱惑 | 天天爽天天射 | 伊人视频 | 天天艹天天操 | 欧美福利视频 | japanesexxxhd奶水 91在线精品一区二区 | 国产精品高清免费在线观看 | 美女视频久久久 | 在线观看完整版免费 | 天天干,夜夜爽 | www.婷婷色 | 欧美福利久久 | 日本女人逼 | 精品福利网站 | 欧美国产大片 | 亚洲激情综合 | 91福利视频久久久久 | 中文字幕欧美日韩va免费视频 | 亚洲免费在线观看视频 | 国产日韩在线播放 | 涩涩资源网 | 天堂在线视频免费观看 | 毛片一区二区 | 丝袜美女视频网站 | 免费在线色视频 | 日本黄色片一区二区 | 欧美永久视频 | 深夜男人影院 | 国产九九在线 | 国产香蕉97碰碰久久人人 | 免费观看mv大片高清 | 久久久久久久免费观看 | 91亚瑟视频 | 久久久99精品免费观看乱色 | 欧美日韩亚洲国产一区 | 欧美久久影院 | 亚洲麻豆精品 | 亚洲va综合va国产va中文 | 伊人婷婷网 | 4438全国亚洲精品在线观看视频 | 国产.精品.日韩.另类.中文.在线.播放 | 嫩模bbw搡bbbb搡bbbb | 中文字幕丝袜美腿 | 国产视频欧美视频 | 91久久久国产精品 | 亚洲精品婷婷 | 日韩在线观看高清 | 久久国产一二区 | 综合色播 | 日本少妇久久久 | 日韩三级在线观看 | 欧美日韩免费在线观看视频 | 国产一级视频在线免费观看 | 天天操天天干天天操天天干 | 国产精品免费久久久久 | 日韩在线免费视频观看 | 国产成人免费高清 | 在线中文字幕视频 | 911久久| 日韩中文在线电影 | 在线精品亚洲 | 91成熟丰满女人少妇 | 伊人婷婷色| 国产欧美日韩精品一区二区免费 | 免费观看一区二区三区视频 | 在线国产黄色 | 久久精品国产99国产 | 中文字幕亚洲欧美日韩 | 日韩网页| 国产成人一区二区三区电影 | 99精品国产高清在线观看 | 日本黄区免费视频观看 | 91在线成人 | 国产精品一区二区中文字幕 | www.狠狠操.com | 一级一片免费视频 | 成人亚洲精品久久久久 | 五月情婷婷 | 日韩欧美一区二区在线 | 草草草影院 | 麻豆传媒一区二区 | 成人av影视观看 | 激情欧美一区二区三区免费看 | 一 级 黄 色 片免费看的 | 国产亚州精品视频 | 91精品久久久久久久久久入口 | 久久久久国产精品午夜一区 | 日韩色在线 | 日韩视频在线一区 | 97香蕉久久超级碰碰高清版 | 成年人免费电影 | 国产精品video爽爽爽爽 | 久久这里精品视频 | 中文字幕在线观看完整版 | 国产成人精品一区二区在线观看 | 色综合久久久久综合99 | 看国产黄色片 | www.黄色小说.com | 久久久久亚洲精品 | 欧美男女爱爱视频 | 人人爱爱人人 | 九九免费在线观看视频 | 中文字幕中文字幕中文字幕 | av一级在线观看 | 在线观看视频国产 | 色婷婷播放 | 久久综合久久综合久久综合 | 尤物九九久久国产精品的分类 | 亚洲高清久久久 | 日韩一区二区三 | 国产又粗又猛又爽 | 99综合影院在线 | 久久精品www人人爽人人 | 日韩电影一区二区三区在线观看 | 精品视频在线观看 | 久久国产精品99国产 | 大型av综合网站 | 欧美精品在线视频 | 日韩 在线观看 | 国产精品a级 | 亚洲成人av一区 | 视频在线日韩 | 国产一级大片在线观看 | 日三级在线 | 久久久久精 | 九九九九热精品免费视频点播观看 | 日韩一区二区三 | 色婷婷狠狠五月综合天色拍 | 亚洲乱亚洲乱亚洲 | 免费欧美高清视频 | 日韩一级电影在线 | 国产日产精品久久久久快鸭 | 久久精品国产亚洲 | 五月天久久精品 | 午夜免费视频网站 | 在线v片免费观看视频 | 亚洲精品日韩在线观看 | 久久综合中文色婷婷 | 亚洲成人精品影院 | 狠狠综合 | 国产96在线观看 | 美女网站视频久久 | 韩国精品一区二区三区六区色诱 | 五月天电影免费在线观看一区 | 91成人黄色 | 蜜桃视频精品 | 色婷婷一 | 久久久久欧美精品 | 中文字幕美女免费在线 | 国产伦理一区二区 | 国产精品久久久久久欧美 | 奇米影视在线99精品 | 亚洲精品午夜一区人人爽 | 在线观看视频h | 日日干日日 | 91中文字幕 | 国产成人一区二区三区电影 | 成人久久网| 亚洲国产精品视频在线观看 | 国产成人精品在线观看 | 久久av中文字幕片 | 中文字幕在线观看完整版 | 在线激情av电影 | 国产精品国产精品 | 又黄又爽的视频在线观看网站 | 在线观看 国产 | 国产字幕av | 奇米网网址 | 欧美一区二区在线看 | www.天天草 | av午夜电影| 婷婷色在线播放 | 天天色成人 | 欧美视频日韩视频 | www.人人草 | 91最新在线 | 香蕉91视频| 成人永久在线 | 4438全国亚洲精品在线观看视频 | 亚洲精品视频第一页 | 久草在线免费资源 | 久久天天操 | 青青河边草免费观看 | 国产资源网站 | 欧美日韩亚洲在线观看 | 一区二区日韩av | 四虎在线永久免费观看 | 9在线观看免费高清完整版在线观看明 | 久久九九影视网 | 韩国av免费观看 | 久久久久女教师免费一区 | 中文字幕精品www乱入免费视频 | 日日干美女 | 国产不卡精品 | 射射射综合网 |