• <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>

            無我

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

            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 閱讀(1608) 評論(0)  編輯 收藏 引用 所屬分類: eSNACC學習

            <2013年7月>
            30123456
            78910111213
            14151617181920
            21222324252627
            28293031123
            45678910

            導航

            統計

            公告

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

            留言簿(9)

            隨筆分類(173)

            IT

            Life

            搜索

            積分與排名

            最新隨筆

            最新評論

            閱讀排行榜

            一本色道久久综合| 久久这里只有精品久久| 久久精品国产久精国产| 精品久久久久久中文字幕大豆网| 久久精品国产色蜜蜜麻豆| 国产精品亚洲综合专区片高清久久久 | 99久久婷婷国产综合精品草原| 看久久久久久a级毛片| 一本色道久久99一综合| 伊人久久大香线蕉AV色婷婷色| 影音先锋女人AV鲁色资源网久久| 国内精品久久久久影院薰衣草| 无码人妻少妇久久中文字幕蜜桃 | 婷婷综合久久中文字幕| 久久精品9988| 久久精品国产欧美日韩| 亚洲午夜无码久久久久小说| 狠狠综合久久综合88亚洲| 久久精品www人人爽人人| 91精品国产综合久久婷婷| 久久福利青草精品资源站免费| 精品久久久久久国产免费了| 亚洲婷婷国产精品电影人久久| 久久久久久久波多野结衣高潮| 久久久久亚洲av无码专区导航| 久久亚洲高清观看| 久久毛片一区二区| 久久99久久99精品免视看动漫| 99久久99久久精品国产片| 伊人久久亚洲综合影院| 久久精品国产69国产精品亚洲| 久久久久亚洲爆乳少妇无| 国产亚洲精品久久久久秋霞| 天天爽天天爽天天片a久久网| 久久夜色精品国产噜噜亚洲a| 91精品国产色综合久久| 亚洲国产精品综合久久网络| 国产精品久久免费| 亚洲精品乱码久久久久66| 欧美久久久久久午夜精品| 72种姿势欧美久久久久大黄蕉|