青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Que's C++ Studio

大道至簡
posts - 3, comments - 8, trackbacks - 0, articles - 0
理解和使用zlib庫 - 我的個人救贖
作者: 闕榮文
日期: 2016.6.2
0. 很多年以前我曾經寫過一篇文章(http://blog.csdn.net/querw/article/details/1452041)簡單介紹 zlib 的使用方法,老實說當時自己都不是很明白 zlib 是怎么回事,現在想起來那個時候年輕嘛,膽子大,臉皮厚...有時候想到自己這樣一篇半吊子的東西在網絡上傳播,心不自安,希望用一篇新的文章救贖少不更事的無知.
1. deflate算法, zlib 格式, gzip 格式
本文并不是一篇介紹壓縮算法的文章,請讀者自行查閱關于 LZ77 算法的詳情.deflate 是 LZ77 算法的一個增強版,對各種數據提供無損壓縮,是 zlib 目前唯一實現的壓縮算法.
一段數據經過 deflate 算法壓縮之后形成一段輸出數據,這段輸出數據就是純粹的壓縮數據,沒有任何額外信息如長度,校驗和等.可以直接存儲或者在網絡中傳輸原始壓縮數據并由 inflate 算法解壓縮,但是用戶要保證數據的完整性.
當然,我們也可以為這段原始數據額外添加一個 zlib 格式(rfc1950)的數據頭/尾,使用 adler32 校驗和,定義如下:
     +---+---+
     |CMF|FLG|    (more-->)
     +---+---+
     (if FLG.FDICT set)
     +-----+-----+-----+-----+
     |       DICTID          | (more-->)
     +-----+-----+-----+-----+
     +========================+----+-----+-----+----+
     | ...compressed data...  |        ADLER32      |
     +========================+----+-----+-----+----+
2個字節的 zlib 頭, 4個字節的字典(可選), deflate 原始壓縮數據, 4個字節的 adler32 校驗和. 這是一種非常簡潔的數據包裝格式.
gzip(rfc1952) 是不同于 zlib 的另外一種格式的數據頭/尾,使用 CRC32 校驗和,定義如下:
     +---+---+---+---+---+---+---+---+---+---+
     |ID1|ID2|CM |FLG|     MTIME     |XFL|OS | (more-->)
     +---+---+---+---+---+---+---+---+---+---+
     (if FLG.FEXTRA set)
     +---+---+=================================+
     | XLEN  |...XLEN bytes of "extra field"...| (more-->)
     +---+---+=================================+
     (if FLG.FNAME set)
     +=========================================+
     |...original file name, zero-terminated...| (more-->)
     +=========================================+
     (if FLG.FCOMMENT set)
     +===================================+
     |...file comment, zero-terminated...| (more-->)
     +===================================+
     (if FLG.FHCRC set)
     +---+---+
     | CRC16 |
     +---+---+
     +=======================+
     |...compressed blocks...| (more-->)
     +=======================+
     +---+---+---+---+---+---+---+---+
     |     CRC32     |     ISIZE     |
     +---+---+---+---+---+---+---+---+
一個 gzip 段落由 10 字節長度的頭,若干可選的附加段(由 gzip header中的 flag 字段標識是否存在),壓縮數據,和4字節的 CRC32 校驗和,4字節的原文長度組成.
解壓器根據壓縮數據可以知道壓縮數據流什么時候結束,所以沒必要在數據頭中包含壓縮后的數據長度字段, ISIZE 等于原文長度 % 2^32 (對于小于 4GB 的數據來說 ISIZE 就是原文的長度).
zip 也是一種包裝格式,應該說是一組格式約定,主要針對多個文件提供打包功能,所以 zip 格式中有很多關于文件目錄的信息,具體格式可以在網上搜一搜,并參考 zlib 源碼包中的 minizip 項目.
在 zlib 文檔中, "zlib" 這個詞有兩種意思(很奇怪的命名),一是表示 zlib 代碼庫本身, 二是表示對 deflate 原始壓縮數據的 "zlib" 包裝格式.為了便于區分,后面我用 "libzlib" 表示前者, 用 "zlib" 表示后者.
2. libzlib 設計思路 - 流
流的定義如下:
typedef struct z_stream_s {
    z_const Bytef *next_in;     /* next input byte */
    uInt     avail_in;  /* number of bytes available at next_in */
    uLong    total_in;  /* total number of input bytes read so far */
    Bytef    *next_out; /* next output byte should be put there */
    uInt     avail_out; /* remaining free space at next_out */
    uLong    total_out; /* total number of bytes output so far */
    z_const char *msg;  /* last error message, NULL if no error */
    struct internal_state FAR *state; /* not visible by applications */
    alloc_func zalloc;  /* used to allocate the internal state */
    free_func  zfree;   /* used to free the internal state */
    voidpf     opaque;  /* private data object passed to zalloc and zfree */
    int     data_type;  /* best guess about the data type: binary or text */
    uLong   adler;      /* adler32 value of the uncompressed data */
    uLong   reserved;   /* reserved for future use */
} z_stream;
由輸入數據 xxxx_in 和輸出數據 xxxx_out 組成,原始數據從輸入端流入,變為壓縮數據從輸出端流出(解壓縮反過來).
編程的時候,用戶不停的"喂"數據到 next_in 并指定它的長度 avail_in 調用壓縮函數,然后從 next_out 得到壓縮后的數據,長度是 avail_out.這就是整個 zlib 庫的接口的設計思路.
msg: 錯誤信息
zalloc / zfree / opaque: 類似于 C++ STL 中的 allocator 的作用,如果要定制內存管理可以自己編寫內存分配回收函數.
adler: adler32 / CRC32 校驗和.
3. libzlib 接口
根據前文對數據包裝格式的說明可以知道真正的壓縮數據其實都是相同的,由 deflate 算法計算得到,區別在于包裝格式的不同,所以 libzlib API 細節的微妙之處都在于如何配置壓縮器/解壓器以得到不同包裝格式的輸出數據.
3.1 基本 API
ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)):
初始化 z_stream, 如果要使用默認的內存管理函數必須把 zalloc / zfree / opaque 設置為 Z_NULL.輸出帶有 zlib 數據頭/尾的壓縮流.
用此函數初始化得到的壓縮器就默認輸出 zlib 格式的壓縮數據.如果我們希望得到 gzip 格式或者原始的壓縮數據怎么做呢? 于是引出另一個提供更多選項的壓縮器初始化函數:
ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
                                     int  level,
                                     int  method,
                                     int  windowBits,
                                     int  memLevel,
                                     int  strategy)):
不同包裝格式的數據輸出由 windowBits 這個參數控制:
8 ~ 15: 輸出 zlib 數據頭/尾, deflateInit() 中這個參數值固定為 15, 就是 zconf.h 中定義的 MAX_WBITS 的值.
-8 ~ -15: 輸出原始的壓縮數據不含任何數據頭/尾. 如果沒有特殊要求,使用 -15 就可以,表示內部使用 32K 的 LZ77 滑動窗口.
24 ~ 31: 輸出 gzip 格式的數據,默認提供一個所有設置都清零的 gzip 數據頭,如果要自定義這個數據頭,可以在初始化之后, deflate() 之前調用 deflateSetHeader().
level: 壓縮級別 0 ~ 9. 0 表示不壓縮, 1 表示速度最快, 9 表示壓縮比最高. Z_DEFAULT_COMPRESSION (-1) 表示使用默認設置.
method: Z_DEFLATED(8) 只是唯一支持的壓縮算法.
memLevel: 控制 libzlib 內部使用內存的大小, 1 ~ 9 數字越小內存用量也越小,花費時間越多.默認值是8.
strategy: 內部壓縮算法的編碼策略,如果沒有特殊要求,設置為 Z_DEFAULT_STRATEGY 就可以了(如果你有特殊要求,那你自然知道其余選項 Z_FILTERED / Z_HUFFMAN_ONLY / Z_RLE / Z_FIXED 是什么意思).
ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)):
flush: 如果沒有特殊需求,我們可以先以 flush = Z_NO_FLUSH 調用 deflate(),在輸入數據壓縮完成之后,還需要以 flush = Z_FINISH 調用并確認 deflate() 返回 Z_STREAM_END 表示所有數據都已經寫入到輸出緩沖,一個流結束.如果一次性輸入所有原文,那么也可以直接以 flush = Z_FINISH 調用 deflate(),這正是 compress() 的做法.
用戶通過設置 z_stream 中 next_in / avail_in 指定的輸入把數據壓縮并更新 next_out / avail_out.輸入輸出緩沖區都由用戶分配. 還是舉個例子說明: 輸入緩沖區為 byte inbuf[1024] 那么 next_in = inbuf, avail_in = 1024. 因為在壓縮完成之前,用戶不可能知道壓縮后的數據長度,所以無法準確分配(除非調用 deflateBound()計算)輸出緩沖區.用戶可以分配一個任意長度(大于6)的輸出緩沖,比如 byte outbuf[128], 那么 next_out = outbuf, avail_out = 128. 接下來調用 deflate,然后檢查 avail_in 表示輸入緩沖內尚未被處理的數據長度,換而言之 1024 - avail_in 就得到了本次被處理的數據的長度.avail_out 表示輸出緩沖區的剩余空間, 128 - avail_out 就是本次得到的壓縮數據的長度, 只要 avail_in != 0 就重新設置avail_out 繼續壓縮,一旦 avail_in == 0 表示數據都已經提交完畢,然后以參數 Z_FINISH 調用 deflate(strm, Z_FINISH) 指示壓縮器,數據已經提交完畢,請輸出 zlib 或者 gzip 的數據尾, 如果 deflate 返回 Z_STREAM_END 就表示數據尾也已經輸出了,工作完成.即使配置壓縮器為輸出原始壓縮數據而不使用包裝格式,我們也要按照這個流程調用 deflate 確保得到完整的輸出數據.
ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)):
釋放 z_stream.
ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, uLong sourceLen));
計算壓縮后的數據的長度,如果需要一次性壓縮一段內存緩沖,可以調用它來估算輸出緩沖的最大長度.
ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, gz_headerp head));
設置自定義 gzip 頭,應該在 deflateInit / deflateInit2 之后, deflate 之前調用.
ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)):
和 deflateInit 類似,使用默認參數初始化解壓器. zlib 或者 gzip 數據頭會被丟棄,如果需要保留數據頭信息應該在 inflateInit2() 之后, inflate()之前,調用 inflateGetHeader() 提供一個 gzip 頭結構 struct gz_header,一旦 libzlib 讀取到一個完整的 gzip 頭就會把信息填入到這個結構中, inflate() 返回后,檢查 gz_header 結構的 done 字段, 1 表示數據頭讀取完畢; 0 表示正在解壓; -1 表示沒有 gzip 頭,對一個 zlib 格式的壓縮流使用這個函數就會得到 -1.
ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)):
解壓縮,和 deflate 的調用流程一樣,最后應該以參數 flush = Z_FINISH 調用 infate,返回 Z_STREAM_END 表示解壓縮完成,并且校驗和匹配.
ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)):
釋放 z_stream.
ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int  windowBits)):
和 deflateInit2 對應,通常用相同的 windowBits 值就可以了.把 windowBits + 32 可以使解壓器自動識別 zlib 或者 gzip 包裝格式.
libzlib 還提供以回調方式處理解壓縮的 API: inflateBackInit / inflateBack / inflateBackEnd.
3.2 工具函數
compress / compress2 / compressBound / uncompress 是對基本 API 的組合使用,也是如何調用基本 API 的范本,我們應該仔細閱讀 compress.c 和 uncompr.c.
可以用 compressBound() 來估算壓縮后的數據長度,但是沒有任何方法估算解壓后的原文長度,所以用戶應該通過其它渠道得到原文長度,分配足夠的緩沖區以調用 uncompress().
3.3 其它 API
讀我的文章是不能直接通過復制粘貼來寫代碼的,但是看過之后應該能理解 libzlib 的使用原理(至少我希望達到這個目的),不僅僅知道要調用哪些函數,還要理解所以然.具體編寫代碼還是應該查看 libzlib 的文檔.
4. Windows平臺下編譯
既然是一個自由庫,我們還是下載 zlib 的源碼自己編譯,不要使用已經編譯好的 DLL 庫,訪問 http://www.zlib.net/ 下載 ".zip" 格式的源碼包.
打開 "README", 看到 "For Windows, use one of the special makefiles in win32/ or contrib/vstudio/ ." 切換到 contrib/vstudio/ 目錄,又發現一個 readme.txt 是關于不同版本的 VS 的一些細節, 根據自己安裝的 VS 版本打開對于的工程文件(耐心閱讀 readme 很有必要,少走好多彎路.)
方法1 使用 Visual Studio IDE: 由于我已經安裝了 Visual Studio 2013 所以直接用 VS2013 打開 /contrib/vstudio/vc11/zlibvc.sln (這其實是 VS2012 的工程文件). 編譯 "zlibvc" 這是最基本的動態庫 DLL 工程,提示 3 個鏈接錯誤:
1>match686.obj : error LNK2026: module unsafe for SAFESEH image.
1>inffas32.obj : error LNK2026: module unsafe for SAFESEH image.
1>.\zlibvc.def(4): fatal error LNK1118: syntax error in 'VERSION' statement
先看看 LNK1118 錯誤: 在 StackOverflow (http://stackoverflow.com/questions/20021950/def-file-syntax-error-in-visual-studio-2012) 看到原來是 .def 中 VERSION 定義的語法改了(其實是修正了)只允許兩個數字的版本號:主版本號和副版本號.所以要么把 "VERSION 1.2.8" 改為兩個數字的版本號,要么創建一個 VERSION 類型的資源.事實上 version 1.2.8 的資源已經包含在工程中,所以我們只要簡單的在 zlibvc.def 中把 VERSION 這行注釋掉就好了.
再看 LNK2026 錯誤: SAFESEH 按字面上理解應該是 SAFE SEH - 安全的結構化異常處理, SEH 是windows平臺的結構化異常處理機制,通過擴展 C 編譯器 __try, __finally 關鍵字來控制程序流程<<Windows核心編程>>有相關內容介紹. libzlib 大概是不會使用 SEH 的.也許是因為 VS2013 把這個選項的默認設置改變了,具體什么原因導致不兼容我不知道.總之把 SAFESEH 關閉吧: 工程屬性 -> Linker -> Advanced -> Image Has Safe Exception Handlers 改為 NO,重新編譯,發現 testzlib 也有同樣的問題,關閉 SAFESEH 再次編譯就好了.
庫文件: zlibwapi.lib, zlibwapi.dll, zlibstat.lib(靜態庫)
頭文件: zconf.h, zlib.h
微軟這種更新一個版本就使舊工程無法編譯鏈接的做法真是不可理喻.
方法2 使用 nmake, 把 win32/Makefile.msc 復制到上一層源碼目錄,啟動 "Developer Command Prompt for VS2013" (在開始菜單里), 用 CD 命令切換到 zlib 1.2.8 源碼目錄,輸入 "nmake /f Makefile.msc" 編譯完成.
庫文件: zdll.lib, zlib1.dll, zlib.lib(靜態庫)
頭文件: zconf.h, zlib.h
5. demo
  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <assert.h>
  4 
  5 extern "C"
  6 {
  7     #include "zlib.h"
  8 }
  9 #pragma comment(lib, "zlib.lib")
 10 
 11 int dump_buffer(const Bytef* buf, size_t len)
 12 {
 13     for(size_t i = 0; i < len; ++i)
 14     {
 15         printf("%02x", buf[i]);
 16     }
 17     return 0;
 18 }
 19 
 20 int _tmain(int argc, _TCHAR* argv[])
 21 {
 22     const char* inBuf = "1234,abcd,ABCD,^#@!.";
 23     Bytef outBuf[1024= {0};
 24     Bytef restoreBuf[1024= {0};
 25     int outLen = 0;
 26     int restoreLen = 0;
 27     int err = 0;
 28     z_stream stream;
 29     int fmt = 2// 0: zlib; 1: gzip; 2: raw
 30 
 31     printf("source string:%s\r\n", inBuf);
 32 
 33     // 壓縮
 34     stream.next_in = (z_const Bytef *)inBuf;
 35     stream.avail_in = (uInt)strlen(inBuf);
 36 
 37     stream.next_out = (Bytef *)outBuf;
 38     stream.avail_out = 1024;
 39 
 40     stream.zalloc = (alloc_func)0;
 41     stream.zfree = (free_func)0;
 42     stream.opaque = (voidpf)0;
 43 
 44     if(0 == fmt)
 45     {
 46         // zlib
 47         err = deflateInit(&stream, Z_DEFAULT_COMPRESSION);
 48         assert(Z_OK == err);
 49 
 50         err = deflate(&stream, Z_FINISH);
 51         assert(err == Z_STREAM_END);
 52 
 53         outLen = stream.total_out;
 54 
 55         err = deflateEnd(&stream);
 56 
 57         printf("zlib string(HEX):");
 58     }
 59     else if(1 == fmt)
 60     {
 61         // gzip
 62         err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 168, Z_DEFAULT_STRATEGY);
 63         assert(Z_OK == err);
 64 
 65         err = deflate(&stream, Z_FINISH);
 66         assert(err == Z_STREAM_END);
 67 
 68         outLen = stream.total_out;
 69 
 70         err = deflateEnd(&stream);
 71 
 72         printf("gzip string(HEX):");
 73     }
 74     else if(2 == fmt)
 75     {
 76         // raw
 77         err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS * -18, Z_DEFAULT_STRATEGY);
 78         assert(Z_OK == err);
 79 
 80         err = deflate(&stream, Z_FINISH);
 81         assert(err == Z_STREAM_END);
 82 
 83         outLen = stream.total_out;
 84 
 85         err = deflateEnd(&stream);
 86 
 87         printf("raw deflate string(HEX):");
 88     }
 89     else
 90     {
 91         assert(0);
 92     }
 93 
 94     dump_buffer(outBuf, outLen);
 95     printf("\r\n");
 96 
 97     // 解壓縮
 98     stream.next_in = (z_const Bytef *)outBuf;
 99     stream.avail_in = (uInt)outLen;
100 
101     stream.next_out = (Bytef *)restoreBuf;
102     stream.avail_out = 1024;
103 
104     stream.zalloc = (alloc_func)0;
105     stream.zfree = (free_func)0;
106     stream.opaque = (voidpf)0;
107 
108     if(0 == fmt)
109     {
110         // zlib
111         err = inflateInit(&stream);
112         assert(Z_OK == err);
113 
114         err = inflate(&stream, Z_FINISH);
115         assert(err == Z_STREAM_END);
116 
117         restoreLen = stream.total_out;
118 
119         err = inflateEnd(&stream);
120     }
121     else if(1 == fmt)
122     {
123         // gzip
124         err = inflateInit2(&stream, MAX_WBITS + 16);
125         assert(Z_OK == err);
126 
127         err = inflate(&stream, Z_FINISH);
128         assert(err == Z_STREAM_END);
129 
130         restoreLen = stream.total_out;
131 
132         err = inflateEnd(&stream);
133     }
134     else if(2 == fmt)
135     {
136         // raw
137         err = inflateInit2(&stream, MAX_WBITS * -1);
138         assert(Z_OK == err);
139 
140         err = inflate(&stream, Z_FINISH);
141         assert(err == Z_STREAM_END);
142 
143         restoreLen = stream.total_out;
144 
145         err = inflateEnd(&stream);
146     }
147     else
148     {
149         assert(0);
150     }
151 
152     printf("restored string:%s\r\n", (char*)restoreBuf);
153 
154     printf("Press Enter to continue");
155     getchar();
156     return err;
157 }
fmt 分別設置為 0, 1, 2 時的運行結果:
source string:1234,abcd,ABCD,^#@!.
zlib string(HEX):789c33343236d1494c4a4ed171747276d189537650d40300357804f3
restored string:1234,abcd,ABCD,^#@!.
source string:1234,abcd,ABCD,^#@!.
gzip string(HEX):1f8b080000000000000b33343236d1494c4a4ed171747276d189537650d4030065d6b0c314000000
restored string:1234,abcd,ABCD,^#@!.
source string:1234,abcd,ABCD,^#@!.
raw deflate string(HEX):33343236d1494c4a4ed171747276d189537650d40300
restored string:1234,abcd,ABCD,^#@!.
可以看到中間的壓縮數據都是相同的,只是頭尾不同.
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            影音先锋中文字幕一区| 欧美国产日韩a欧美在线观看| 国产欧美日韩激情| 国产精品你懂的在线| 国产伦精品免费视频| 国产精品一区二区三区四区| 国产三级精品在线不卡| 精品av久久久久电影| 亚洲国产成人porn| 亚洲日本成人在线观看| 国产精品99久久久久久久女警 | 欧美在线观看一区二区| 亚洲欧美精品在线观看| 欧美一级大片在线观看| 久久久久高清| 亚洲福利免费| 亚洲国产cao| 亚洲综合色激情五月| 久久国产加勒比精品无码| 久久青青草原一区二区| 欧美日韩一区二区三区视频| 国产伦精品一区二区三区高清| 精品不卡视频| 亚洲天堂免费观看| 免费在线亚洲欧美| 亚洲午夜精品一区二区三区他趣| 久久精品一区蜜桃臀影院| 欧美精品免费看| 国产嫩草一区二区三区在线观看 | 欧美自拍偷拍午夜视频| 久久久久久一区二区| 亚洲毛片在线看| 久久国产免费看| 欧美性猛交视频| 在线色欧美三级视频| 亚洲欧美春色| 欧美国产日韩xxxxx| 亚洲欧美在线播放| 欧美日韩免费观看一区三区 | 亚洲一区在线免费观看| 卡通动漫国产精品| 中文精品一区二区三区| 欧美mv日韩mv国产网站| 国产免费亚洲高清| 亚洲神马久久| 欧美激情精品久久久久久久变态| 亚洲在线观看免费| 欧美视频在线一区| 夜久久久久久| 亚洲日本成人| 欧美 日韩 国产精品免费观看| 国产亚洲精品久久久久久| 亚洲在线观看视频网站| 亚洲精品婷婷| 欧美激情一区二区在线| 亚洲国产第一| 欧美+日本+国产+在线a∨观看| 午夜精品久久久久久久蜜桃app| 欧美日韩精品国产| 99riav久久精品riav| 亚洲国产午夜| 欧美有码在线观看视频| 美女国产一区| 最新日韩在线| 久久成人综合网| 国产精品国产精品国产专区不蜜| 91久久久一线二线三线品牌| 久久久久国产精品一区| 亚洲欧美日韩视频一区| 欧美午夜精品久久久久久久| av不卡在线| 最新成人av网站| 欧美国产日韩亚洲一区| 亚洲国产小视频| 亚洲电影免费观看高清完整版在线观看| 欧美一区二视频在线免费观看| 亚洲精品久久| 欧美日韩国产首页在线观看| 亚洲精品乱码久久久久| 91久久久久久| 欧美色图一区二区三区| 亚洲一区欧美激情| 亚洲一区二区精品视频| 国产一区二区久久| 欧美成人一二三| 欧美巨乳波霸| 亚洲欧美一区二区三区在线| 午夜精品一区二区三区在线播放| 国产麻豆午夜三级精品| 欧美伊人久久| 美女脱光内衣内裤视频久久影院| 99re热这里只有精品视频| 一本一本久久a久久精品综合麻豆| 国产精品久久久久77777| 久久九九精品| 欧美超级免费视 在线| 亚洲视频综合| 久久精品国产一区二区三区免费看| 亚洲风情亚aⅴ在线发布| 亚洲精品久久久久中文字幕欢迎你| 欧美私人啪啪vps| 欧美制服第一页| 玖玖国产精品视频| 亚洲欧美一区在线| 久久亚洲捆绑美女| 亚洲欧美久久| 老司机成人网| 性欧美暴力猛交69hd| 美国成人直播| 欧美亚洲视频| 欧美精品情趣视频| 久久婷婷久久| 欧美性生交xxxxx久久久| 老鸭窝91久久精品色噜噜导演| 欧美精品亚洲精品| 久久五月激情| 国产精品主播| 一本久久综合| 亚洲卡通欧美制服中文| 欧美一区二区福利在线| 99精品视频一区| 亚洲蜜桃精久久久久久久| 亚洲麻豆国产自偷在线| 激情亚洲成人| 亚洲欧美日韩在线一区| 夜夜爽av福利精品导航 | 欧美 日韩 国产精品免费观看| 亚洲午夜日本在线观看| 玖玖精品视频| 久久婷婷人人澡人人喊人人爽| 欧美色网在线| 亚洲国产成人av| 欧美激情视频一区二区三区在线播放 | 韩曰欧美视频免费观看| 亚洲视频一区| 亚洲一区二区精品| 欧美日本一区| 亚洲精品国产系列| 一本一本大道香蕉久在线精品| 女人香蕉久久**毛片精品| 欧美不卡在线| 在线国产亚洲欧美| 久久精品一区二区三区四区| 久久久久久久91| 韩国精品在线观看| 久久精品国产99国产精品| 久久久天天操| 亚洲高清在线| 欧美大片第1页| 亚洲美女区一区| 亚洲在线中文字幕| 国产欧美日韩麻豆91| 午夜精品理论片| 久久免费国产精品1| 激情伊人五月天久久综合| 久久久久一区二区三区| 欧美成人黑人xx视频免费观看| 亚洲电影免费在线观看| 欧美承认网站| 99热精品在线| 欧美中文字幕久久| 在线不卡亚洲| 欧美乱妇高清无乱码| 一本色道88久久加勒比精品 | 亚洲欧洲日本专区| 欧美激情自拍| 亚洲淫性视频| 美女黄毛**国产精品啪啪| 亚洲激情欧美激情| 欧美韩日一区二区| 亚洲欧美精品一区| 久久综合九九| 国产一区二区三区无遮挡| 欧美亚洲综合另类| 免费高清在线视频一区·| 日韩亚洲视频在线| 国产精品午夜在线| 美女黄网久久| 亚洲视频在线观看| 老司机亚洲精品| 亚洲男人第一av网站| 一区在线观看视频| 欧美日韩一区二区在线观看| 国产麻豆一精品一av一免费| 免播放器亚洲一区| 99re8这里有精品热视频免费| 久久国产夜色精品鲁鲁99| 亚洲国产精品悠悠久久琪琪 | 亚洲欧美大片| 欧美激情亚洲视频| 欧美在线视屏| 一区二区日韩| 在线电影院国产精品| 国产精品久久久久久影视 | 国产精品一区一区| 欧美成人黑人xx视频免费观看| 午夜日韩在线观看| avtt综合网| 亚洲国产婷婷综合在线精品| 久久久久国产精品www|