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

隨筆 - 45  文章 - 129  trackbacks - 0
<2025年10月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

專注于C++ P2P STL GP OpenSource等
Google

常用鏈接

留言簿(10)

隨筆分類

隨筆檔案

相冊

朋友

  • .NET

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

摘要:本文在對各種資料整理后詳細介紹各種常見編碼的轉換算法。

一、通用字符集(UCS)

ISO/IEC 10646-1 [ISO-10646]定義了一種多于8比特字節的字符集,稱作通用字符集(UCS),它包含了世界上大多數可書寫的字符系統。 已定義了兩種多8比特字節編碼,對每一個字符采用四個8比特字節編碼的稱為UCS-4,對每一個字符采用兩個8比特字節編碼的稱為UCS-2。 它們僅能夠對UCS的前64K字符進行編址,超出此范圍的其它部分當前還沒有分配編址。

二、基本多語言面(BMP)

ISO 10646 定義了一個31位的字符集。 然而,在這巨大的編碼空間中,迄今為止只分配了前65534個碼位 (0x0000 到 0xFFFD)。 這個UCS的16位子集稱為 “基本多語言面 ”(Basic Multilingual Plane, BMP)。

三、Unicode編碼

歷史上, 有兩個獨立的, 創立單一字符集的嘗試。 一個是國際標準化組織(ISO)的 ISO 10646 項目; 另一個是由(一開始大多是美國的)多語言軟件制造商組成的協會組織的 Unicode 項目。幸運的是, 1991年前后, 兩個項目的參與者都認識到: 世界不需要兩個不同的單一字符集。它們合并雙方的工作成果,并為創立一個單一編碼表而協同工作。 兩個項目仍都存在并獨立地公布各自的標準, 但 Unicode 協會和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 標準的碼表兼容, 并緊密地共同調整任何未來的擴展。Unicode 標準額外定義了許多與字符有關的語義符號學, 一般而言是對于實現高質量的印刷出版系統的更好的參考。

四、UTF-8編碼

UCS-2和UCS-4編碼很難在許多當前的應用和協議中使用,這些應用和協議假定字符為一個8或7比特的字節。 即使新的可以處理16比特字符的系統,卻不能處理UCS-4數據。這種情況導致一種稱為UCS轉換格式(UTF)的發展,它每一種有不同的特征。 UTF-8(RFC 2279),使用了8比特字節的所有位,保持全部US-ASCII取值范圍的性質:US-ASCII字符用一個8比特字節編碼,采用通常的US-ASCII值, 因此,在此值下的任何一個8比特位字節僅僅代表一個US-ASCII字符,而不會為其他字符。它有如下的特性:

1)UTF-8向UCS-4,UCS-2兩者中任一個進行相互轉換比較容易。
2)多8比特字節序列的第一個8比特字節指明了系列中8比特字節的數目。
3)8比特字節值FE和FF永遠不會出現。
4)在8比特字符流中字符邊界從哪里開始較容易發現。

UTF-8定義:
在UTF-8中,字符采用1到6個8比特字節的序列進行編碼。僅僅一個8比特字節的一個序列中,字節的高位為0,其他的7位用于字符值編碼。n (n>1)個8比特字節的一個序列中,初始的8比特字節中高n位為1,接著一位為0,此字節余下的位包含被編碼字符值的位。接著的所有8比特字節的 最高位為1,接著下一位為0,余下每個字節6位包含被編碼字符的位。

下表總結了這些不同的8比特字節類型格式。字母x指出此位來自于進行編碼的UCS-4字符值。

 

   UCS-4范圍(16進制)     UTF-8 系列(二進制)
0000 0000<->0000 007F 0xxxxxxx
0000 0080<->0000 07FF 110xxxxx 10xxxxxx
0000 0800<->0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx

0001 0000<->001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0020 0000<->03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
0400 0000<->7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx

從UCS-4 到 UTF-8編碼規則如下:
1)從字符值和上表第一列中決定需要的8比特字節數目。著重指出的是上表中的行是相互排斥的,也就是說,對于一個給定的UCS-4字符,僅僅有一個有效的編碼。
2)按照上表中第二列每行那樣準備8比特字節的高位。
3)將UCS字符值的位,從低位起填充在標記為x地方。從UTF8序列中最后一個字節填起,然后剩下的字符值依次放到前一個字節中,如此重復,直到所有標記位x的位都進行了填充。

這里我們僅僅實現Unicode到UTF8的轉換,Unicode都是兩個字節,定義為:
typedef usigned short WCHAR

// 輸出的UTF8編碼至多是3個字節。

int UnicodeToUTF8(WCHAR ucs2, unsigned char *buffer)
{
    memset(buffer, 
04);
    
if ((0x0000 <= ucs2) && (ucs2 <= 0x007f))  // one char of UTF8
    {
       buffer[
0= (char)ucs2;
       
return 1;
    }
    
if ((0x0080 <= ucs2) && (ucs2 <= 0x07ff))  // two char of UTF8
    {
       buffer[
1= 0x80 | char(ucs2 & 0x003f);
       buffer[
0= 0xc0 | char((ucs2 >> 6& 0x001f);
       
return 2;
    }
    
if ((0x0800 <= ucs2) && (ucs2 <= 0xffff))  // three char of UTF8
    {
       buffer[
2= 0x80 | char(ucs2 & 0x003f);
       buffer[
1= 0x80 | char((ucs2 >> 6& 0x003f);
       buffer[
0= 0xe0 | char((ucs2 >> 12& 0x001f);
       
return 3;
    }
    
return 0;
}  


理論上,簡單的通過用2個0值的8比特字節來擴展每個UCS-2字符,則從UCS-2到UTF-8編碼的算法可以從上面得到。然而,從D800到DFFF 間的UCS-2值對(用Unicode說法是代理對),實際上是通過UTF-16來進行UCS-4字符轉換,因此需要特別對待:UTF-16轉換必須未完 成,先轉換到于UCS-4字符,然后按照上面過程進行轉換。

從UTF-8到UCS-4解碼過程如下:
1)初始化UCS-4字符4個8比特字節的所有位為0。
2)根據序列中8比特字節數和上表中第二列(標記為x位)來決定哪些位編碼用于字符值。
3)從編碼序列分配位到UCS-4字符。首先從序列最后一個8比特字節的最低位開始,接著向左進行,直到所有標記為x的位完成。如果UTF-8序列長度不大于3個8比特字節,解碼過程可以直接賦予UCS-2。

WCHAR UTF8ToUnicode(unsigned char *buffer)
{
    WCHAR temp 
= 0;
    
if (buffer[0< 0x80)                                   // one char of UTF8
    { 
       temp 
= buffer[0];
    }
    
if ((0xc0 <= buffer[0]) && (buffer[0< 0xe0))          // two char of UTF8
    {
       temp 
= buffer[0& 0x1f;
       temp 
= temp << 6;
       temp 
= temp | (buffer[1& 0x3f);
    }
    
if ((0xe0 <= buffer[0]) && (buffer[0< 0xf0))          // three char of UTF8
    {
       temp 
= buffer[0& 0x0f;
       temp 
= temp << 6;
       temp 
= temp | (buffer[1& 0x3f);
       temp 
= temp << 6;
       temp 
= temp | (buffer[2& 0x3f);
    }
    
if ((0x80 <= buffer[0]) && (buffer[0< 0xc0))          // not the first byte of UTF8 character
       return 0xfeff;                                       // 0xfeff will never appear in usual

    
return temp;                                            // more than 3-bytes return 0
}


注意:上面解碼算法的實際實現應該進行安全保護,以便處理解碼無效的系列。例如:實現可能(錯誤)解碼無效的UTF-8系列0xC0 0x80為字符U+0000,它可能導致安全問題或其他問題(比如把0當作數組結束標志)。更詳細的算法和公式可以在[FSS_UTF], [UNICODE] 或[ISO-10646]附錄R中找到。

五、UTF-7編碼

UTF-7:A Mail-Safe Transformation Format of Unicode(RFC1642)。這是一種使用 7 位 ASCII 碼對 Unicode 碼進行轉換的編碼。它的設計目的仍然是為了在只能傳遞 7 為編碼的郵件網關中傳遞信息。 UTF-7 對英語字母、數字和常見符號直接顯示,而對其他符號用修正的 Base64 編碼。符號 + 和 - 號控制編碼過程的開始和暫停。所以亂碼中如果夾有英文單詞,并且相伴有 + 號和 - 號,這就有可能是 UTF-7 編碼。

協議中定義的轉換規則:
1)集合D中的Unicode字符可以直接的編碼為ASCII的等值字節。集合O中的字符可以有有選擇的的直接編碼為ASCII的等值字節,但要記得其中的很多的字符在報頭字段是不合法的,或者不能正確的穿過郵件網關。
2)通過在前面加上轉換字符"+",任何一個Unicode序列都可以使用集合B(更改過的base64)中的字符編碼。"+"意味著后面的字節將被作為 更改過的BASE64字母表中的元素解析,直到遇到一個不是字母表中的字符為止。這些字符中會包含控制字符,比如回車和換行;因此,一個Unicode轉 換序列總是在一行上結束。注釋:有兩個特殊的情形:"+-"表示''+'',"+ …… --"表示有一個真正的''-''字符出現了。多數情況是沒有''-''標記結束。
3)空格、tab、回車和換行字符可以直接使用ASCII等價字節表示。

那么我們就可以定義算法了,我們先定義字符集的相關數組:
typedef unsigned char byte

// 64 characters for base64 coding
byte base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";  

// 8 characters are safe just as base64 characters for MAIL gates
byte safeChars[] = "''(),-.:?";    

// 4 characters all means space
byte spaceChars[] = " \t\n\r";    

注:在編碼處理時候,我們需要對一個字節判斷屬于哪類字符,以便確定處理規則,如果簡單的使用范圍比較的方式,效率很低,我們采用哈希表的思路:建立一個256長的數組,那么對于每一個字節的值,就可以定義一個類型。判斷時候,對每個字符都直接取數組的值。

// mask value defined for indentify the type of a byte
#define    BASE64        0x01
#define    SAFE        0x02
#define    SPACE        0x04
byte byteType[256];        // hash table used for find the type of a byte
bool firstTime = true;     // the first time to use the lib, wait for init the table

// 注:為了解碼base64編碼部分的字符,需要一個哈希表,對一個base64字符都可以直接得到0-64之間的一個數:
byte base64Value[128];

這兩個哈希表在使用前要初始化:

void initUTF7Tables()
{
    
byte *s;
    
if(!firstTime)
    
return;
    
// not necessary, but should do it to be robust
    memset(byteType, 0256);
    memset(base64Value, 
0128);
    
    
for(s=base64Chars; *s!=''\0''; s++)
    {
       byteType[
*s] |= BASE64;
       base64Value[
*s] = s - base64Chars; // the offset, it is a 6bits value,0-64
    }
    
    
for(s=safeChars; *s!=''\0''; s++)
       byteType[
*s] |= SAFE;
       
    
for(s=spaceChars; *s!=''\0''; s++)
       byteType[
*s] |= SPACE; 

    firstTime 
= false;
}

UTF-7編碼轉換時候,是與當前字符是與狀態有關的,也就是說:
1)正處于Base64編碼狀態中
2)正處于直接編碼狀態中
3)現在UTF-7的緩沖區里,當前的字符是轉換開關"+"

所以要定義相關的字段:

// the state of current character 
#define    IN_ASCII    0
#define    IN_BASE64    1
#define AFTER_PLUS    2

在使用規則2進行編碼時候,需要使用base64的方法,也就需要2個全局的輔助變量:

int state;                 // state in which  we are working
int nbits;                 // number of bits in the bit buffer
unsigned long bitBuffer;   // used for base64 coding

把一個Unicode字符轉化為一個UTF-7序列:返回寫到緩沖區里的字節數目,函數影響了state,nbits,bitBuffer三個全局變量。 這里先實現了一個簡單的輔助函數,功能是把一個Unicode字符轉變后寫到提供的緩沖區中,返回寫入的字節個數。在開始編碼Unicode字符數組中第 一個字符的時候,state,nbits,bitBuffer三個全局變量需要被初始化:

state = IN_ASCII;
nbits 
= 0;
bitBuffer 
= 0;

int UnicodeToUTF7(WCHAR ucs2, byte *buffer)
{
    
byte *head = buffer;
    
int index;    
    
    
// is an ASCII and is a byte in char set defined
    if (((ucs2 & 0xff80== 0)) && (byteType[(byte)u2] & (BASE64|SAFE|SPACE))) 
    {    
       
byte temp = (byte)ucs2;
       
       
if (state == IN_BASE64) // should switch out from base64 coding here
       {
          
if (nbits > 0)       // if some bits in buffer, then output them
          {
             index 
= (bitBuffer << (6 - nbits)) & 0x3f;
             
*s++ = base64[index];
          }
          
if ((byteType[temp] & BASE64) || (temp == ''-''))
             
*s++ = ''-'';
      state 
= IN_ASCII;
       }
       
*s++ = temp;
       
       
if (temp == ''+'')
          
*s++ = ''-'';
    }
    
else
    {
       
if (state == IN_ASCII) 
       {
          
*s++ = ''+'';
          state 
= IN_BASE64;          // begins base64 coding here
          nbits = 0;
          bitBuffer 
= 0;
       }
       bitBuffer 
<<= 16;
       bitBuffer 
|= ucs2;
       nbits 
+= 16;
       
       
while(nbits >= 6
       {
          nbits 
-= 6;
          index 
= (bitBuffer >> nbits) & 0x3f;   // output the high 6 bits
          *s++ = base64[index];
       }
    }
    
return (s - head);
}


說明:對于合法的Unicode字符數組,可以通過逐個輸入數組中的字符,連續調用上面的函數,得到一個UTF-7字節序列。需要說明的是:最后一個Unicode字符應該是上面三個字節數組中某個字符的等值。

下面,我們實現一個簡單的說明函數,功能是:輸入一個UTF-7字節,可能得到并返回一個合法Unicode字符;也可能不能得到,比如遇到''+''或者因為還沒有完成一個字符的拼裝,這時返回一個標志字符0xfeff,這個字符常用來標志Unicode編碼。

注:函數影響了state,nbits,bitBuffer三個全局變量。在開始處理第一個字節時候,變量需要被初始化為:

state = IN_ASCII;
nbits 
= 0;
bitBuffer 
= 0;

#define RET0 0xfeff

WCHAR UTF7ToUnicode(
byte c)
{
    
if(state == IN_ASCII) 
    {
       
if (c == ''+''
       {
          state 
= AFTER_PLUS;
          
return RET0;
       } 
       
else 
        
return (WCHAR)c;
    }
    
if (state == AFTER_PLUS) 
    {
       
if (c == ''-''
       {
          
return (WCHAR)''+'';
       } 
       
else 
       {
          state 
= IN_BASE64;
          nbits 
= 0;
          bitBuffer 
= 0;  // it is not necessary
          
// don''t return yet, continue to the IN_BASE64 mode
       }
     }
     
    
// state == Base64 
    if (byteType[c] & BASE64) 
    {
       bitBuffer 
<<= 6;
       bitBuffer 
|= base64Value[c];
       nbits 
+= 6;
       
if (nbits >= 16
       {
          nbits 
-= 16;
      
return (WCHAR)((bitBuffer >> nbits) & 0x0000ffff);
       }
       
return RET0;
    }
    
// encount a byte which is not in base64 character set, switch out of base64 coding
    state = IN_ASCII;
    
if (c != ''-''
    {
       
return (WCHAR)c;
    }
    
return RET0;
}


說明:對于一個UTF-7序列,可以通過連續輸入字節并調用上面的函數,判斷返回值,得到一個Unicode字符數組。

六、GB2312編碼中漢字的確定

最早,表示漢字的區位碼中,分為94個區,每個區94個漢字,1-15區是西文字符,圖形等,16-5為一級漢字,56-87為二級漢字,87區以上為新 字用。而我們在Windows默認的編碼,GB2312(1981年國家頒布的《信息交換用漢字編碼字符集基本集》)國標碼,和區位碼的換算為:

國標碼 = 區位碼 + 2020H

而在漢字在計算機內表示的時候為保證ASCII碼和漢字編碼的不混淆,又做了一個換算:

漢字機內碼 = 國標碼 + 8080H

所以,真正的在Windows上的GB2312漢字編碼是機內碼,從上邊的兩個公式可以得到的就是:

漢字機內碼 = 區位碼 + a0a0H

一個漢字的編碼最少要a0a0H,因此我們在CString中辨別漢字的時候可以認為:當一個字符的編碼大于a0的時候它應該是漢字的一個部分。但是也有 特殊的情況的,不是每個漢字的兩個字節編碼都是大于a0H的,例如‘镕’的編碼是 ‘E946’,后面的部分就不滿足大于a0H的條件。

七、Windows下多字節編碼和Unicode的轉換

Windows提供了API函數,可以把Unicode字符數組轉換為GB2312字符串。其中,Unicode數組在傳入時候最后一個為0,也就是所謂 的null termidated字符串。在函數內部得到要返回字節串的大小,請求空間,進行真正的轉換操作,指針在外部使用后釋放,或者在類中加如其他的操作來處 理,比如析構函數中釋放。返回值為寫到字節串里數目。

	
int StringEncode::UnicodeToGB2312(char **dest, const WCHAR *src)
{
    
char* buffer;
    
int size = ::WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);  
    
// null termidated wchar''s buffer
    buffer = new char[size];
    
int ret = ::WideCharToMultiByte(CP_ACP, NULL, src, -1, buffer, size + 1, NULL, NULL);

    
if (*dest != 0)
        delete 
*dest;
    
*dest = buffer;

    
return ret;
}


注:其中見到有人在使用的時候,申請緩沖區空間時候是申請了(zise + 1)個來,最后一個字節寫''\0'',結束字符串。但是在我調試時候發現:系統給的size已經包含了一個寫入''\0''的字節,而且最后得到的串 中,''\0''是已經被系統API寫入了。(也許我的實驗有錯誤,有待驗證)。把Unicode字符數組轉換為UTF-8和UTF-7的方法類似,只要 是WideCharToMultiByte函數的第一個表示代碼頁參數改為CP_UTF7(65000)和CP_UTF8(65001)。

同樣道理,把多字節轉換為Unicode字符數組,也有相應的函數。和上面的函數類似,可以通過先提供一個空緩沖區而先得到需要的大小,然后開辟空間得到 最后的字符數組。但是考慮到效率,可以適當犧牲一些空間,提供一個足夠大的字符數組,數組大小在極端的情況下(全是ASCII)是和字節數組大小一樣的。

int StringEncode::Gb2312ToUnicode(WCHAR **dest, const char *src)
{
    
int length = strlen(src);                // null terminated buffer
    WCHAR *buffer = new WCHAR[length + 1];   // WCHAR means unsinged short, 2 bytes
                                           
// provide enough buffer size for Unicodes

    
int ret = ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, src, length, buffer, length);
    buffer[ret] 
= 0;

    
if (*dest != 0)
        delete 
*dest;
    
*dest = buffer;

    
return ret;
}


注:刪除以前的緩沖區時候的操作,其實沒有必要判斷是不是為空,因為刪除空指針是沒有問題的,因為delete內部提供了這樣的機制。

八、URL 解碼

用IE發送GET請求的時候,URL是用UTF-8編碼的,當對截包數據分析時候就需要對數據解碼,下面的函數是一個簡單的實現:

CString CTestUrlDlg::UrlToString(CString url)
{
    CString  str 
= "";
    
int n = url.GetLength();
    url.MakeLower();
    BYTE a, b1, b2;
    
for (int i=0; i< 3)    // 后面沒有兩個字符了,錯誤
                return "";
            b1 
= charToHex( url.GetAt(i+1) );
            b1 
= (b1 << 4& 0xf0;
            b2 
= charToHex( url.GetAt(i+2) ) & 0x0f;
            a 
= b1 | b2;
            str 
+= a;
            i 
+= 2;
        }
        
else
        {
            str 
+= url.GetAt(i);
        }
    }
    
return str;
    
    }
    
static WCHAR UTF8ToUnicode(unsigned char *buf, int &t)
{
    WCHAR temp 
= 0;
    unsigned 
char *buffer = buf + t;
    
if (buffer[0< 0x80)                                   // one char of UTF8
    { 
       temp 
= buffer[0];
       t 
+= 1;
    }
    
if ((0xc0 <= buffer[0]) && (buffer[0< 0xe0))          // two char of UTF8
    {
       temp 
= buffer[0& 0x1f;
       temp 
= temp << 6;
       temp 
= temp | (buffer[1& 0x3f);
       t 
+= 2;
    }
    
if ((0xe0 <= buffer[0]) && (buffer[0< 0xf0))          // three char of UTF8
    {
       temp 
= buffer[0& 0x0f;
       temp 
= temp << 6;
       temp 
= temp | (buffer[1& 0x3f);
       temp 
= temp << 6;
       temp 
= temp | (buffer[2& 0x3f);
       t 
+= 3;
    }
    
if ((0x80 <= buffer[0]) && (buffer[0< 0xc0))          // not the first byte of UTF8 character
       return 0xfeff;                                       // 0xfeff will never appear in usual

    
return temp;                                            // more than 3-bytes return 0
}


static unsigned char charToHex(char c)
{
    unsigned 
char d;
    
if ((c >= ''0''&& (c <= ''9''))
        d 
= c - ''0'';
    
else if ((c >= ''a''&& (c <= ''f''))
    {
        d 
= c - ''a'' + 10;
    }
    
else if ((c >= ''A''&& (c <= ''F''))
    {
        d 
= c - ''A'' + 10;
    }
    
else
        d 
= 0;

    
return d;    
}


static void UnicodeToGB2312(const WCHAR unicode, char* buffer)
{
//    int size = ::WideCharToMultiByte(CP_ACP, 0, unicode, -1, NULL, 0, NULL, NULL);  

    
int ret = ::WideCharToMultiByte(CP_ACP, NULL, &unicode, -1, buffer, 3, NULL, NULL);
}

CString CTestUrlDlg::Uft8ToGB(CString url)
{
    CString  str 
= "";
    
char buffer[3];
    WCHAR unicode;
    
    unsigned 
char * p = (unsigned char *)(LPCTSTR)url;
    
int n = url.GetLength();
    
int t = 0;
    
while (t < n)
    {
        unicode 
= UTF8ToUnicode(p, t);
        UnicodeToGB2312(unicode, buffer);
        buffer[
2= 0;
        str 
+= buffer;
    }

    
return str;
}


示例:
CString str = "/MFC%E8%8B%B1%E6%96%87%E6%89%8B%E5%86%8C.chm";
CString ret 
= UrlToString(str);
ret 
= Uft8ToGB(ret);   // MFC英文手冊.chm



九、總結
常見算法還有MIME等,由于篇幅限制,并且網上已經有很多帖子,在此不再贅述。
對于本文,由于個人能力有限,難免有疏漏的地方,還望指教,共同進步。
posted on 2007-07-24 12:43 CPP&&設計模式小屋 閱讀(3074) 評論(7)  編輯 收藏 引用 所屬分類: 讀書筆記

FeedBack:
# re: 常用編碼詳解(轉自VCKBASE)作者:李靜南 2007-07-24 13:15 go
good..  回復  更多評論
  
# re: 常用編碼詳解(轉自VCKBASE)作者:李靜南 2007-07-24 13:28 CPP&&設計模式小屋
我也覺得總結的不錯 和大家分享一下。  回復  更多評論
  
# re: 常用編碼詳解(轉自VCKBASE)作者:李靜南 2007-07-24 15:55 pass86
不錯不錯,支持。  回復  更多評論
  
# re: 常用編碼詳解(轉自VCKBASE)作者:李靜南 2007-07-26 19:49 黃大仙
正需要這方面的資料  回復  更多評論
  
# re: 常用編碼詳解(轉自VCKBASE)作者:李靜南 2007-08-06 19:51 ouyang2008
i need too ,3ks.  回復  更多評論
  
# re: 常用編碼詳解(轉自VCKBASE)作者:李靜南 2007-09-09 11:19 vernon
好文章  回復  更多評論
  
# re: 常用編碼詳解(轉自VCKBASE)作者:李靜南 2007-09-14 08:22 螞蟻終結者
不錯,先收藏了  回復  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
              欧美国产亚洲精品久久久8v| 久久久亚洲综合| 蜜臀久久99精品久久久画质超高清| 国产精品视频| 亚洲一区免费网站| 亚洲无人区一区| 国产精品色在线| 久久久久久亚洲精品中文字幕| 欧美一级日韩一级| 在线观看一区视频| 亚洲第一中文字幕在线观看| 久久人人精品| 夜色激情一区二区| 中文国产一区| 国内精品美女在线观看| 欧美韩日精品| 国产精品a级| 久久精品在线播放| 久久免费高清视频| 亚洲图片欧洲图片av| 午夜伦欧美伦电影理论片| 亚洲国产经典视频| 亚洲最黄网站| 黄色国产精品| 日韩午夜激情av| 国产视频久久久久| 欧美日韩的一区二区| 一区二区三区高清在线| 午夜精品在线观看| 亚洲精品自在久久| 亚洲欧美日韩综合aⅴ视频| 亚洲国产欧美一区二区三区久久| 99精品视频免费观看视频| 国一区二区在线观看| 日韩午夜av在线| 狠狠色狠色综合曰曰| 夜夜狂射影院欧美极品| 亚洲国产婷婷| 欧美亚洲三区| 亚洲综合视频一区| 欧美α欧美αv大片| 欧美一区二区三区视频免费播放| 久久资源在线| 久久精品国产欧美亚洲人人爽| 欧美日韩国产一中文字不卡| 老司机精品导航| 国产精品一区二区三区四区| 亚洲国产另类精品专区| 国产一区二区主播在线| 亚洲天堂成人在线观看| 在线亚洲伦理| 欧美激情小视频| 欧美激情性爽国产精品17p| 国产在线观看91精品一区| 国产精品99久久99久久久二8| 亚洲视频在线免费观看| 久久天天躁夜夜躁狠狠躁2022| 亚洲一区二区在线| 欧美日韩精品免费观看视频完整 | 欧美电影免费| 久久先锋资源| 狠狠色伊人亚洲综合网站色| 亚洲伊人网站| 欧美呦呦网站| 国产日韩三区| 欧美一级精品大片| 久久久综合精品| 国产亚洲欧洲一区高清在线观看 | 99视频热这里只有精品免费| 99国产精品| 欧美日韩国产黄| 日韩视频在线你懂得| 亚洲夜晚福利在线观看| 欧美视频免费在线| 亚洲婷婷综合久久一本伊一区| 亚洲一区免费在线观看| 国产精品午夜在线观看| 亚洲欧美综合国产精品一区| 久久aⅴ国产紧身牛仔裤| 国产一区二区三区四区hd| 欧美一区高清| 欧美高清视频一二三区| 亚洲理伦在线| 国产精品老牛| 久久精品91| 亚洲国产日韩欧美一区二区三区| 99re亚洲国产精品| 国产精品久久久久影院亚瑟| 欧美一级成年大片在线观看| 老司机凹凸av亚洲导航| 一区二区精品在线| 国产视频综合在线| 久久在线免费| 在线中文字幕不卡| 久久久久久久久久久一区 | 欧美激情视频在线免费观看 欧美视频免费一 | 国产亚洲精品7777| 欧美成人免费大片| 亚洲无限av看| 亚洲高清三级视频| 午夜在线不卡| 亚洲国产成人av好男人在线观看| 欧美日本亚洲视频| 久久成人18免费观看| 亚洲欧洲精品一区二区三区波多野1战4| 亚洲一区二区三区777| 激情欧美一区| 国产精品久久久久毛片软件| 麻豆成人在线| 性欧美激情精品| 91久久国产综合久久| 欧美在线不卡| 亚洲一二三区精品| 亚洲国产专区| 国产综合久久久久影院| 欧美区亚洲区| 久久综合九色99| 午夜激情综合网| 亚洲国产欧美国产综合一区| 好看的日韩av电影| 免费欧美日韩| 久久久亚洲成人| 亚洲自拍另类| 一本色道久久88综合日韩精品| 欧美~级网站不卡| 亚洲欧美精品在线| 日韩视频免费在线| 影音欧美亚洲| 国外成人在线视频| 国产无遮挡一区二区三区毛片日本| 欧美韩日一区| 老司机成人网| 久久亚洲春色中文字幕| 亚洲欧美在线x视频| 国产精品99久久久久久人| 亚洲欧洲日韩在线| 亚洲经典三级| 亚洲韩国日本中文字幕| 久久精品视频在线| 日韩一级精品视频在线观看| 亚洲激情自拍| 亚洲激情欧美激情| 亚洲国产精彩中文乱码av在线播放| 黄色综合网站| 极品少妇一区二区| 在线成人亚洲| 亚洲国产福利在线| 亚洲成色www8888| 亚洲国产精品一区二区第四页av | 国产欧美日韩| 国产伦精品一区二区三区照片91 | 亚洲一区二区三区在线看| 中文日韩电影网站| 亚洲一区观看| 欧美一区二区视频在线观看| 亚洲欧美日韩一区二区三区在线观看 | 久久漫画官网| 麻豆成人在线观看| 亚洲二区免费| 亚洲精品欧美日韩专区| 一区二区三区国产在线| 亚洲一区二区三区在线| 亚洲综合二区| 久久尤物视频| 欧美婷婷久久| 国产真实精品久久二三区| 激情成人中文字幕| 亚洲国产婷婷香蕉久久久久久| 99re视频这里只有精品| 欧美一级视频一区二区| 美女福利精品视频| 亚洲欧洲另类| 欧美一区二区三区在线| 久久久久亚洲综合| 欧美日韩成人综合| 国产亚洲成精品久久| 亚洲欧洲日韩女同| 亚洲欧美在线一区| 欧美成人中文字幕| 在线一区二区三区四区| 久久伊人精品天天| 欧美日韩亚洲一区二区三区在线| 国产欧美日韩亚洲一区二区三区| 伊人成人开心激情综合网| 一区电影在线观看| 欧美黄色视屏| 中文在线资源观看网站视频免费不卡| 欧美另类69精品久久久久9999| 欧美日韩在线一区二区三区| 国产在线麻豆精品观看| 一本久久精品一区二区| 欧美一级免费视频| 亚洲人成人99网站| 久久精品中文字幕免费mv| 欧美午夜在线| 亚洲精品在线观| 欧美极品一区二区三区| 欧美国产日韩一区| 激情综合亚洲| 欧美专区18|