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

無我

讓內心永遠燃燒著偉大的光明的精神之火!
靈活的思考,嚴謹的實現
豪邁的氣魄、頑強的意志和周全的思考

eSNACC對長度的編碼和解碼

本文剖析asn-len.h/c,從源代碼來學習eSNACC對長度的編碼和解碼。

在正式引出源代碼之前,我覺得非常有必要強調幾點非常重要的知識:

1、eSNACC編譯器對數據的編碼設計是反序的,也就是先編碼數據并寫進緩沖區,以此而知道了編碼好的數據長度,然后再將本長度值編碼插到緩沖區前面。這樣設計的目的是減少性能的損失。而很多其他編譯器是開一個臨時緩沖區來完成這個工作,這就帶來了性能的損失。詳細的說明,請參加eSNACC文檔。我們要記住的是eSNACC編碼時反序的。

2、eSNACC既支持確定長度編碼也支持不確定長度編碼。原理是:確定長度編碼,那么在數據之前的若干字節來表面后面數據的長度;若為不確定長度編碼,那么數據前面的長度字節為0x80,此代表長度不確定,然后在數據最后用EOC(End-Of-Contents)來表示數據的結束。

3、eSNACC支持BER和DER編碼。不過BER允許不確定長度,但是DER只支持確定長度,所以在他們的編碼解碼函數上有所不同。

4、如果感覺代碼中的PROTO和PARAMS很陌生,請讀本系列中的《關于老式函數聲明》一文。

 

 

以下具體結合源碼分析。

typedef unsigned long AsnLen;
/*
 * BER Encoding/Decoding routines
 
*/

/* max unsigned value  - used for internal rep of indef len */
#define INDEFINITE_LEN        ~0L

以上說明,eSNACC長度用AsnLen類型來定義,而該類型也就是unsigned long。而不確定長度的標記就是INDEFINITE_LEN。

 

#ifdef USE_INDEF_LEN

#define BEncEocIfNec( b)    BEncEoc (b)

/*
 * include len for EOC  (2 must be first due to BEncIndefLen
 * - ack! ugly macros!)
 
*/

#define BEncConsLen( b, len)    2 + BEncIndefLen(b)


#else  /* use definite length - faster?/smaller encodings */

/* do nothing since only using definite lens */
#define BEncEocIfNec( b)

#define BEncConsLen( b, len)    BEncDefLen(b, len)

#endif

以上用ifdef來定義了BER編碼確定長度和不確定長度的2個宏:

BEncEocIfNec代表BER中編碼EOC標記,從代碼可見,若為不確定長度,那么就用BEncEoc來完成;若為確定長度,因為根本就不需要EOC,所以什么都不要做。

BEncConsLen代表BER中編碼內容的長度,代碼說明了,若為不確定長度,出了調用BEncIndefLen來編碼內容長度,因為內容之后還需要2個字節表示EOC,所以再前面加了2;若為確定長度,因為不需要EOC,所以就直接調用BEncDefLen來完成。

 

/*
 * writes indefinite length byte to buffer. 'returns' encoded len (1)
 
*/

#define BEncIndefLen( b)\
    
1;\
    BufPutByteRvs (b, 
0x80);

#ifndef _DEBUG
#define BEncEoc( b)\
    
2;\
    BufPutByteRvs (b, 
0);\
    BufPutByteRvs (b, 
0);
#endif

這一段說明了編碼不確定長度和編碼EOC的兩個宏,我們會發現這兩個宏很奇怪,因為與我們以前常見的不一樣,我當時看就感覺好像語法錯了一樣。是的,這些宏就是這樣設計的,我們先看看源文件開頭作者寫的說明:

 * Warning: many of these routines are MACROs for performance reasons
 
*          - be carful where you use them.  Don't use more than one per
 *          assignment statement -
 
*          (eg itemLen += BEncEoc (b) + BEncFoo (b) ..; this
 
*           will break the code)
 

 

/*
 * include len for EOC  (2 must be first due to BEncIndefLen
 * - ack! ugly macros!)
 
*/

看到了,作者深知這些宏的丑陋!也深知這些宏的弊端!他們不能像調用函數或變量那樣連接使用,否則會破壞代碼!這一切,嗨,都是為了性能,無所不用其極呀!

好吧,引入上面這些就是提醒大家在用這些宏時要高度警惕。下面分析這些宏:

首先,這些宏要編碼長度。其次,他還要返回編碼好的長度的值。就是因為要實現這兩個功能,才被迫寫成這樣:

這兩個宏的第一個分號前的數值就是返回值。

而后面的就是把編碼的值壓到緩沖區里面去,實現真正的編碼。

就是這么簡單了。

 

///***************************************休息一下*************************

 

為了更好的說明.h文件的后面一點點,下面我們先跳到.c中分析具體的函數實現: 

/* 
 * BER encode/decode routines
 
*/

AsnLen
BEncDefLen PARAMS ((b, len),
    GenBuf 
*b _AND_
    AsnLen len)
{
    
/*
     * unrolled for efficiency
     * check each possibitlity of the 4 byte integer
     
*/

    
if (len < 128)
    
{
        BufPutByteRvs (b, (unsigned 
char)len);
        
return 1;
    }

    
else if (len < 256)
    
{
        BufPutByteRvs (b, (unsigned 
char)len);
        BufPutByteRvs (b, 
0x81);
        
return 2;
    }

    
else if (len < 65536)
    
{
        BufPutByteRvs (b, (unsigned 
char)len);
        BufPutByteRvs (b, (unsigned 
char)(len >> 8));
        BufPutByteRvs (b, 
0x82);
        
return 3;
    }

    
else if (len < 16777126)
    
{
        BufPutByteRvs (b, (unsigned 
char)len);
        BufPutByteRvs (b, (unsigned 
char)(len >> 8));
        BufPutByteRvs (b, (unsigned 
char)(len >> 16));
        BufPutByteRvs (b, 
0x83);
        
return 4;
    }

    
else
    
{
        BufPutByteRvs (b, (unsigned 
char)len);
        BufPutByteRvs (b, (unsigned 
char)(len >> 8));
        BufPutByteRvs (b, (unsigned 
char)(len >> 16));
        BufPutByteRvs (b, (unsigned 
char)(len >> 24));
        BufPutByteRvs (b, 
0x84);
        
return 5;
    }

}
 /*  BEncDefLen */

仔細理解,我們發現本函數就是做了這樣一件事情:把長度值的有效字節壓到緩沖區,然后把有效字節的值壓到緩沖區,最后返回編碼的長度的字節數。

而這一切,都是通過BufPutByteRvs完成。之所以這樣,是因為長度值本身是用一個AsnLen(也就是unsigned long)來表示的,這用了4個字節。如果長度值小,比如小于128,僅僅一個字節表示就夠了,所以壓縮一下而已。

 

下面我們看解碼: 

/*
 * decodes and returns an ASN.1 length
 
*/

AsnLen
BDecLen PARAMS ((b, bytesDecoded, env),
    GenBuf 
*b _AND_
    unsigned 
long  *bytesDecoded _AND_
    jmp_buf env)
{
    AsnLen len;
    AsnLen 
byte;
    
int lenBytes;

    
byte = (unsigned long) BufGetByte (b);

    
if (BufReadError (b))
    
{
        Asn1Error (
"BDecLen: ERROR - decoded past end of data\n");
        longjmp (env, 
-13);
    }


    (
*bytesDecoded)++;
    
if (byte < 128)   /* short length */
        
return byte;

    
else if (byte == (AsnLen) 0x080)  /* indef len indicator */
        
return (unsigned long)INDEFINITE_LEN;

    
else  /* long len form */
    
{
        
/*
         * strip high bit to get # bytes left in len
         
*/

        lenBytes 
= byte & (AsnLen) 0x7f;

        
if (lenBytes > sizeof (AsnLen))
        
{
            Asn1Error (
"BDecLen: ERROR - length overflow\n");
            longjmp (env, 
-14);
        }


        (
*bytesDecoded) += lenBytes;

        
for (len = 0; lenBytes > 0; lenBytes--)
            len 
= (len << 8| (AsnLen) BufGetByte (b);


        
if (BufReadError (b))
        
{
            Asn1Error (
"BDecLen: ERROR - decoded past end of data\n");
            longjmp (env, 
-15);
        }


        
return len;
    }

    
/* not reached */
}
 /* BDecLen */

首先用BufGetByte從緩沖區讀取第一個字節,這讀出來的是什么呢?是關于長度嗎?當然是的了!但是細心的你就會說:在前面的編碼函數BEncDefLen中長度不是最后才被壓進緩沖區的嗎?哈哈,這個就得想起本文開始提到的第一條:反序編碼。當然實現是在BufPutByteRvs里面,這個以后再講,不過我想我這樣一說,大家也已經明白了。是嗎?

然后判斷讀出來的值,如果小于128,那很好,長度就是他了!而如果為0x80,那就是不確定長度了(最上面第2條)。其他的情況,那么這個值就是長度的有效字節數,這樣就很簡單了,依次讀取解析就可以了。

當然,本函數內部有兩種情況會進行出錯處理,此處就不展開了。

 

#ifdef _DEBUG
AsnLen
BEncEoc PARAMS ((b),
    GenBuf 
*b)
{
    BufPutByteRvs (b, 
0);
    BufPutByteRvs (b, 
0);
    
return 2;
}
   /* BEncEoc */
#endif
/*
 * Decodes an End of Contents (EOC) marker from the given buffer.
 * Flags and error if the octets are non-zero or if a read error
 * occurs.  Increments bytesDecoded by the length of the EOC marker.
 
*/


void
BDecEoc PARAMS ((b, bytesDecoded, env),
    GenBuf 
*b _AND_
    AsnLen 
*bytesDecoded _AND_
    jmp_buf env)
{
    
if ((BufGetByte (b) != 0|| (BufGetByte (b) != 0|| BufReadError (b))
    
{
        Asn1Error (
"BDecEoc: ERROR - non zero byte in EOC or end of data reached\n");
        longjmp (env, 
-16);
    }

    (
*bytesDecoded) += 2;

}
  /* BDecEoc */

上面的代碼說明了對EOC的編碼和解碼實現,可以發現EOC就是以連續的兩個全0字節表示的。

 

實現文件的最后還有這樣一個函數: 

/*
 * decodes and returns a DER encoded ASN.1 length
 
*/

AsnLen
DDecLen PARAMS ((b, bytesDecoded, env),
    GenBuf 
*b _AND_
    unsigned 
long  *bytesDecoded _AND_
    jmp_buf env)
{
    AsnLen len;
    AsnLen 
byte;
    
int lenBytes;

    
byte = (AsnLen) BufGetByte (b);

    
if (BufReadError (b))
    
{
        Asn1Error (
"DDecLen: ERROR - decoded past end of data\n");
        longjmp (env, 
-13);
    }


    (
*bytesDecoded)++;
    
if (byte < 128)   /* short length */
        
return byte;

    
else if (byte == (AsnLen) 0x080)  {/* indef len indicator */
      Asn1Error(
"DDecLen: ERROR - Indefinite length decoded");
      longjmp(env, 
-666);
    }


    
else  /* long len form */
    
{
        
/*
         * strip high bit to get # bytes left in len
         
*/

        lenBytes 
= byte & (AsnLen) 0x7f;

        
if (lenBytes > sizeof (AsnLen))
        
{
            Asn1Error (
"DDecLen: ERROR - length overflow\n");
            longjmp (env, 
-14);
        }


        (
*bytesDecoded) += lenBytes;

        
for (len = 0; lenBytes > 0; lenBytes--)
            len 
= (len << 8| (AsnLen) BufGetByte (b);


        
if (BufReadError (b))
        
{
            Asn1Error (
"DDecLen: ERROR - decoded past end of data\n");
            longjmp (env, 
-15);
        }


        
return len;
    }

    
/* not reached */
}
 /* DDecLen */

這是對應DER編碼的解碼函數,其實現與BER編碼基本一樣,唯一不同的是因為DER編碼不允許不確定長度,所以如果長度字節為0x80,那么人家就直接罷工了。

 

到此,編碼解碼的具體實現都明白了,那.h文件中還剩下什么了呢?除了上面函數的一些聲明,我們還發現一樣感興趣的東西:

/*
 * use if you know the encoded length will be 0 >= len <= 127
 * Eg for booleans, nulls, any resonable integers and reals
 *
 * NOTE: this particular Encode Routine does NOT return the length
 * encoded (1).
 
*/

#define BEncDefLenTo127( b, len)\
    BufPutByteRvs (b, (unsigned 
char) len)

是的,這里有這樣一個宏,在eSNACC文檔中也專門提了。這其實也是為了效率考慮而加的:當你確定長度小于127時,就應當直接調用這個宏,而不要調用前面講的編碼函數。(其實我們可以看到編碼函數做的就是同樣的事情,除了多了一些判斷,當然關鍵是省卻函數調用的過程,又見無所不用其極。)

注意:這個宏只做了編碼,而沒有返回長度(也就是1個字節)!

 

好了,eSNACC支持BER和DER編碼解碼,他們的一些聲明也都類似,就不在敖述了。記住本文開始提到的第三點,其他代碼也就一目了然了。

到此,asn-len.h/c的剖析勝利完成!

posted on 2012-04-20 11:00 Tim 閱讀(1645) 評論(0)  編輯 收藏 引用 所屬分類: eSNACC學習

<2012年4月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

導航

統計

公告

本博客原創文章,歡迎轉載和交流。不過請注明以下信息:
作者:TimWu
郵箱:timfly@yeah.net
來源:www.shnenglu.com/Tim
感謝您對我的支持!

留言簿(9)

隨筆分類(173)

IT

Life

搜索

積分與排名

最新隨筆

最新評論

閱讀排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            在线 亚洲欧美在线综合一区| 美女国产一区| 欧美经典一区二区三区| 久久精品九九| 国产精品高潮久久| 亚洲国产精品成人va在线观看| 国产精品性做久久久久久| 亚洲二区在线| 在线精品视频一区二区三四| 欧美亚洲在线观看| 亚洲一区二区三区中文字幕| 欧美精品激情在线观看| 欧美成人亚洲| 1024亚洲| 媚黑女一区二区| 老巨人导航500精品| 国产欧美视频一区二区三区| 亚洲影音一区| 午夜在线电影亚洲一区| 国产精品国产精品| 这里只有精品视频在线| 一本色道**综合亚洲精品蜜桃冫| 欧美成人午夜激情在线| 欧美福利影院| 亚洲精品国产精品久久清纯直播| 免费亚洲一区二区| 欧美成人三级在线| 亚洲激情不卡| 欧美精品成人91久久久久久久| 91久久精品一区二区别| 99国产欧美久久久精品| 欧美精品麻豆| 中文在线资源观看网站视频免费不卡 | 久久精品青青大伊人av| 久久人人97超碰人人澡爱香蕉| 国产亚洲欧美一区二区三区| 久久精品国产一区二区三区| 噜噜噜91成人网| 亚洲欧洲精品一区二区精品久久久| 免费不卡中文字幕视频| 亚洲激情一区二区| 亚洲免费在线视频| 国产精品一区二区三区四区| 香蕉久久一区二区不卡无毒影院| 久久免费午夜影院| 亚洲欧洲一区二区三区久久| 欧美日韩一区在线播放| 香蕉久久a毛片| 欧美福利影院| 亚洲在线不卡| 伊人狠狠色丁香综合尤物| 欧美电影打屁股sp| 亚洲一二三区精品| 欧美成人免费va影院高清| 一区二区三区日韩精品视频| 国产欧美一区二区精品忘忧草| 久久久综合精品| 9人人澡人人爽人人精品| 久久国产精品99久久久久久老狼| 精品成人a区在线观看| 欧美啪啪一区| 久久精品中文字幕一区| 亚洲看片免费| 久久综合久久久久88| 99视频超级精品| 国产自产2019最新不卡| 欧美美女操人视频| 久久久精彩视频| 亚洲天堂免费在线观看视频| 亚洲成色777777在线观看影院| 亚洲一区二区三区四区五区黄 | 国产精品二区二区三区| 久久久99爱| 亚洲淫性视频| 亚洲另类春色国产| 巨胸喷奶水www久久久免费动漫| 一区二区三区四区国产精品| 在线国产精品一区| 国产精品久久久久7777婷婷| 麻豆freexxxx性91精品| 午夜视频一区在线观看| 99热免费精品| 亚洲国产91| 老色鬼久久亚洲一区二区| 亚洲欧美区自拍先锋| 亚洲人成人一区二区在线观看| 国产三级欧美三级| 欧美日韩免费在线观看| 欧美成人伊人久久综合网| 欧美一区在线看| 亚洲综合二区| 亚洲一区二区三区高清| 亚洲精品视频在线播放| 欧美黄色小视频| 老司机一区二区三区| 欧美一区二区在线播放| 亚洲欧美一区二区三区久久 | 中文国产成人精品| 亚洲精品在线免费| 亚洲国产日韩在线一区模特| 欧美成人在线网站| 麻豆国产精品777777在线| 久久久久久免费| 久久精品天堂| 久久久亚洲人| 久久综合国产精品| 老鸭窝毛片一区二区三区| 久久躁日日躁aaaaxxxx| 可以免费看不卡的av网站| 久久久噜噜噜久久中文字幕色伊伊| 欧美中文在线字幕| 久久久99久久精品女同性 | 亚洲欧美成人综合| 亚洲中字黄色| 欧美亚洲综合网| 久久精品国产一区二区三区免费看 | 久久久久一区二区三区| 久久午夜电影网| 欧美aaaaaaaa牛牛影院| 亚洲国产一二三| 亚洲激情在线激情| 99re6热只有精品免费观看| 一区二区三区四区在线| 亚洲午夜未删减在线观看| 午夜国产一区| 久久免费精品视频| 免费观看成人网| 欧美三级韩国三级日本三斤| 国产女优一区| 在线日本高清免费不卡| 亚洲精品视频免费在线观看| 亚洲校园激情| 久久激情五月激情| 欧美mv日韩mv亚洲| 日韩午夜黄色| 欧美一区二区三区另类| 免费不卡在线观看av| 欧美午夜久久| 狠狠色2019综合网| 亚洲精品中文字幕有码专区| 午夜欧美视频| 欧美成人三级在线| 一区二区三区四区五区在线| 久久国产精彩视频| 欧美精品自拍| 国内精品免费在线观看| 一区二区三区免费在线观看| 久久精品三级| 日韩亚洲精品视频| 久久久女女女女999久久| 欧美视频一二三区| 亚洲国产成人在线播放| 亚洲综合大片69999| 欧美夫妇交换俱乐部在线观看| 亚洲视频二区| 欧美高清视频一区二区三区在线观看| 国产精品美女在线观看| 亚洲国产精品小视频| 午夜精品影院| 亚洲巨乳在线| 男男成人高潮片免费网站| 国产模特精品视频久久久久 | 欧美丰满少妇xxxbbb| 亚洲影视在线播放| 欧美精品在欧美一区二区少妇| 国产香蕉久久精品综合网| 日韩视频一区二区| 久久久久国产精品一区二区| 99xxxx成人网| 欧美国产日本韩| 影音先锋成人资源站| 久久国产精品99国产精| 亚洲一区二区精品在线| 欧美乱大交xxxxx| 亚洲人成网站在线观看播放| 久久一二三国产| 欧美一区二区三区免费看| 国产精品久久国产三级国电话系列| 亚洲美女黄网| 亚洲高清精品中出| 蜜臀va亚洲va欧美va天堂 | 亚洲一本大道在线| 噜噜噜91成人网| 久久国产视频网站| 国产日韩一区二区三区在线播放| 亚洲男人的天堂在线观看| 亚洲美女精品久久| 欧美—级a级欧美特级ar全黄| 亚洲激情一区| 欧美激情成人在线| 美女精品自拍一二三四| 亚洲国产成人精品女人久久久| 另类成人小视频在线| 久久精品一区蜜桃臀影院| 精东粉嫩av免费一区二区三区| 久久久久国色av免费观看性色| 欧美一级大片在线免费观看| 国产九九视频一区二区三区| 欧美一区二区三区视频免费播放 | 影音先锋日韩资源|