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

            無我

            讓內(nèi)心永遠(yuǎn)燃燒著偉大的光明的精神之火!
            靈活的思考,嚴(yán)謹(jǐn)?shù)膶?shí)現(xiàn)
            豪邁的氣魄、頑強(qiáng)的意志和周全的思考

            eSNACC對(duì)OCTET STRING 的編碼和解碼

            本文剖析asn-octs.h/c,從源代碼來學(xué)習(xí)eSNACC對(duì)OCTET STRING的編碼和解碼。

            eSNACC對(duì)字節(jié)串OCTET STRING的處理與上一篇描述的比特串的方法類似,而且字節(jié)串的處理更加簡(jiǎn)單。所以在上一篇的基礎(chǔ)上,我們專門分析上一篇中對(duì)連接型串解碼時(shí)沒有展開講的函數(shù),也作為上一篇的補(bǔ)充。上一篇可以參見eSNACC對(duì)BIT STRING的編碼和解碼

             

            先看看eSNACC對(duì)字節(jié)串的表示方法:

            typedef struct AsnOcts
            {
              unsigned 
            long octetLen;
              
            char            *octs;
            }
             AsnOcts;

            可以看到與比特串很類似,唯一不同的是octetLen的類型,對(duì)字節(jié)串的是unsigned long;而比特串的是int。為什么要這樣設(shè)計(jì)呢?因?yàn)殚L度肯定不可能是負(fù)數(shù),所以設(shè)計(jì)成unsigned的是我們認(rèn)為合理的。而對(duì)比特串的想法,我不太清楚,這其實(shí)也可以說是對(duì)那個(gè)模塊的另一個(gè)設(shè)計(jì)問題。

            octetLen代表該字節(jié)串的長度,但不包含串末尾的null字節(jié)。

            octs是指向字節(jié)串的指針,分配的字節(jié)串長度為octetLen+1,在解碼時(shí)會(huì)主動(dòng)給末尾設(shè)為null。千萬要注意:這個(gè)char*與比特串的char*有很大的不同:字節(jié)串的char*是一個(gè)字符指針,其指向的是一個(gè)由null終結(jié)的字符串。而比特串的就是一串比特位,最末尾也沒有null。

             

            好了,看字節(jié)串的編碼和解碼,我們發(fā)現(xiàn)他的操作很簡(jiǎn)單,只是一個(gè)內(nèi)存拷貝的過程,編碼的時(shí)候也不需要專門來存len信息,也更不需要像比特串那樣做若干操作來處理字節(jié)填充、未使用位數(shù)計(jì)算等等。所以解碼的時(shí)候也不需要判斷這些。僅僅一個(gè)要記住的是:len是不包括字節(jié)串末尾的null字符的,只是在解碼時(shí)多分配了一個(gè)字節(jié),主動(dòng)使其為null結(jié)束。

             

            上面這些都很簡(jiǎn)單,我想本文就主要分析對(duì)連接型字節(jié)串的解碼過程。這是兩個(gè)靜態(tài)函數(shù),不夠在分析這些代碼之前,我覺得應(yīng)該下說明一下他的設(shè)計(jì)方法:

            由于連接型串就是有多個(gè)字節(jié)串嵌套構(gòu)造而成的。也就是

            連接串 => 連接串 + 原生串

            這樣的話,在解碼時(shí),勢(shì)必產(chǎn)生很多夾雜其中的原生串碎片。如果讓用戶來管理這些碎片是很麻煩的事,我們更喜歡把一個(gè)連接串也存為一串整體的內(nèi)存中,就如同操作一個(gè)原生串一樣。正是基于這個(gè)原因,eSNACC就為我們做好封裝,他自己判斷串類型,然后做不同的解碼,最后都是返回給用戶一塊連續(xù)的內(nèi)存。

            我們先看看用于管理串碎片的方案:結(jié)構(gòu)體加宏

            typedef struct StrStkElmt
            {
                
            char *str;
                unsigned 
            long len;
            }
             StrStkElmt;

            typedef 
            struct StrStk
            {
                StrStkElmt 
            *stk; /* ptr to array of SSElmts with 'size' elmts */
                unsigned 
            long initialNumElmts;
                unsigned 
            long numElmts;  /* total # of elements in str stk */
                unsigned 
            long growElmts; /* # elmts to increase size by when nec */
                unsigned 
            long nextFreeElmt; /* index of next free element */
                unsigned 
            long totalByteLen; /* octet len of string stored in stk */
            }
             StrStk;

            extern StrStk strStkG;
            /*
             * initializes stk (Allocates if nec.)
             * once stk is enlarged, it doesn't shrink
             
            */

            #define RESET_STR_STK()\
            {\
                strStkG.nextFreeElmt 
            = 0;\
                strStkG.totalByteLen 
            = 0;\
                
            if (strStkG.stk == NULL){\
                   strStkG.stk 
            = (StrStkElmt*) malloc ((strStkG.initialNumElmts) *sizeof (StrStkElmt));\
                   strStkG.numElmts 
            = strStkG.initialNumElmts;}
            \
            }


            /*
             * add a char*,len pair to top of stack.
             * grows stack if necessary using realloc (!)
             
            */

            #define PUSH_STR(strPtr, strsLen, env)\
            {\
                
            if (strStkG.nextFreeElmt >= strStkG.numElmts)\
                
            {\
                   strStkG.stk 
            = (StrStkElmt*) realloc (strStkG.stk, (strStkG.numElmts + strStkG.growElmts) *sizeof (StrStkElmt));\
                   strStkG.numElmts 
            += strStkG.growElmts;\
                }
            \
                strStkG.totalByteLen 
            += strsLen;\
                strStkG.stk[strStkG.nextFreeElmt].str 
            = strPtr;\
                strStkG.stk[strStkG.nextFreeElmt].len 
            = strsLen;\
                strStkG.nextFreeElmt
            ++;\
            }

            /*
             * Set up size values for the stack that is used for merging constructed
             * octet or bit string into single strings.
             * ****  Call this before decoding anything. *****
             * Note: you don't have to call this if the default values
             * for initialStkSizeG and stkGrowSizeG are acceptable
             
            */

            #define SetupConsBitsOctsStringStk (initialNumberOfElmts, numberOfElmtsToGrowBy)\
            {\
                strStkG.initialNumElmts 
            = initialNumberOfElmts; \
                strStkG.growElmts 
            = numberOfElmtsToGrowBy;\
            }

            可以看到用于管理每一塊比特串或字節(jié)串碎片的結(jié)構(gòu)StrStkElmt與我們定義的AsnBits/AsnOcts非常類似:基本就是定義字段的順序不同。

            而結(jié)構(gòu)體StrStk就是用來管理若干碎片的,使得我們?cè)诮獯a時(shí)不需要處理這些煩人的片段,他內(nèi)部將這些都解碼好并且最后拷貝到一個(gè)整體的內(nèi)存塊中返回,真是功德無限呀!我們就來認(rèn)識(shí)一下這個(gè)活佛吧:

            StrStkElmt *stk:指向碎片串的指針。

            unsigned long initialNumElmts:首次分配StrStkElmt的數(shù)目。
            unsigned long numElmts:stk中擁有的總的StrStkElmt數(shù)。
            unsigned long growElmts:當(dāng)首次分配的initialNumElmts不夠用,而需要再次分配時(shí),默認(rèn)的增長數(shù)。
            unsigned long nextFreeElmt:stk中可用存放StrStkElmt的序號(hào)。
            unsigned long totalByteLen:stk存放的串的總字節(jié)數(shù)。

            然后聲明了一個(gè)變量strStkG,具體定義在實(shí)現(xiàn)文件中。后面就是定義了幾個(gè)宏來操作這個(gè)變量:

            RESET_STR_STK:用于給stk分配內(nèi)存,并且初始化numElmts值。

            PUSH_STR:將char*,len對(duì)加到stk串中。如果空間不夠會(huì)自動(dòng)增長。

            SetupConsBitsOctsStringStk:如果你對(duì)他提供的initialNumElmts和growElmts不滿意,請(qǐng)?jiān)谧鋈魏谓獯a操作之前調(diào)用這個(gè)宏來定義自己的需求。

             

            對(duì)于這種方案,有幾點(diǎn)說明是:

            1、一旦stk擴(kuò)容了,那么就無法縮水。

            2、如果由于數(shù)量不夠而需要增長,這可能會(huì)導(dǎo)致內(nèi)存的重分配和拷貝,一定程度影響性能。

            在該模塊的實(shí)現(xiàn)文件中只有結(jié)構(gòu)體變量strStkG的定義:

            /* global for use by AsnBits and AsnOcts */
            StrStk strStkG 
            = { NULL, 12806400 };

            也就是strStkG的初始值為:StrStkElmt指針為空,默認(rèn)會(huì)分配的128個(gè)指針空間。因?yàn)楫?dāng)前還沒分配內(nèi)存,所以總數(shù)為0.當(dāng)不夠用時(shí)一次增長64個(gè)。然后后面兩個(gè)量都初始化為0.

             

            好了,有了對(duì)這個(gè)輔助體的全面的認(rèn)識(shí),那么最上面的兩個(gè)解碼函數(shù)也就迎刃而解了。

            先看解碼連續(xù)字節(jié)串的入口:

            /*
             * Decodes a seq of universally tagged octets strings until either EOC is
             * encountered or the given len is decoded.  Merges them into a single
             * string. puts a NULL terminator on the string but does not include
             * this in the length.
             
            */

            static void
            BDecConsAsnOcts PARAMS ((b, len, result, bytesDecoded, env),
                GenBuf 
            *b _AND_
                AsnLen len _AND_
                AsnOcts 
            *result _AND_
                AsnLen 
            *bytesDecoded _AND_
                jmp_buf env)
            {
                
            char *bufCurr;
                unsigned 
            long curr;

                RESET_STR_STK();

                
            /*
                 * decode each piece of the octet string, puting
                 * an entry in the octet string stack for each
                 
            */

                FillOctetStringStk (b, len, bytesDecoded, env);

                result
            ->octetLen = strStkG.totalByteLen;

                
            /* alloc str for all octs pieces with extra byte for null terminator */
                bufCurr 
            = result->octs = Asn1Alloc (strStkG.totalByteLen +1);
                CheckAsn1Alloc (result
            ->octs, env);

                
            /* copy octet str pieces into single blk */
                
            for (curr = 0; curr < strStkG.nextFreeElmt; curr++)
                
            {
                    memcpy (bufCurr, strStkG.stk[curr].str, strStkG.stk[curr].len);
                    bufCurr 
            += strStkG.stk[curr].len;
                }


                
            /* add null terminator - this is not included in the str's len */
                
            *bufCurr = '\0';

            }
              /* BDecConsAsnOcts */

            首先函數(shù)注釋說明了解碼一串連接字節(jié)串,直到指定長度或者遇到EOC。最后把這些分散的碎片整合到一個(gè)字符串中。與比特串不同的是,會(huì)在串最后添加null字符。

            邏輯上,首先調(diào)用RESET_STR_STK()給完成strStkG的指針內(nèi)存分配。然后調(diào)用FillOctetStringStk來完成真正的碎片解碼,該函數(shù)完成操作后,各個(gè)碎片都可以通過strStkG的成員變量來訪問了。正如我們看到的,他分配了一個(gè)strStkG.totalByteLen +1的空間,多1是為了存放null。然后遍歷每一個(gè)有效的指針,將值拷貝到分配這一整塊內(nèi)存中。最后在末尾附上null。

            FillOctetStringStk具體定義如下:

            /*
             * Used for decoding constructed OCTET STRING values into
             * a contiguous local rep.
             * fills string stack with references to the pieces of a
             * construced octet string
             
            */

            static void
            FillOctetStringStk PARAMS ((b, elmtLen0, bytesDecoded, env),
                GenBuf 
            *b _AND_
                AsnLen elmtLen0 _AND_
                AsnLen 
            *bytesDecoded _AND_
                jmp_buf env)
            {
                unsigned 
            long refdLen;
                unsigned 
            long totalRefdLen;
                
            char *strPtr;
                unsigned 
            long totalElmtsLen1 = 0;
                unsigned 
            long tagId1;
                unsigned 
            long elmtLen1;

                
            for (; (totalElmtsLen1 < elmtLen0) || (elmtLen0 == INDEFINITE_LEN); )
                
            {
                    tagId1 
            = BDecTag (b, &totalElmtsLen1, env);

                    
            if ((tagId1 == EOC_TAG_ID) && (elmtLen0 == INDEFINITE_LEN))
                    
            {
                        BDEC_2ND_EOC_OCTET (b, 
            &totalElmtsLen1, env);
                        
            break;
                    }


                    elmtLen1 
            = BDecLen (b, &totalElmtsLen1, env);
                    
            if (tagId1 == MAKE_TAG_ID (UNIV, PRIM, OCTETSTRING_TAG_CODE))
                    
            {
                        
            /*
                         * primitive part of string, put references to piece (s) in
                         * str stack
                         
            */

                        totalRefdLen 
            = 0;
                        refdLen 
            = elmtLen1;
                        
            while (1)
                        
            {
                            strPtr 
            = (char *)BufGetSeg (b, &refdLen);

                            PUSH_STR (strPtr, refdLen, env);
                            totalRefdLen 
            += refdLen;
                            
            if (totalRefdLen == elmtLen1)
                                
            break/* exit this while loop */

                            
            if (refdLen == 0/* end of data */
                            
            {
                                Asn1Error (
            "BDecConsOctetString: ERROR - attempt to decode past end of data\n");
                                longjmp (env, 
            -18);
                            }

                            refdLen 
            = elmtLen1 - totalRefdLen;
                        }

                        totalElmtsLen1 
            += elmtLen1;
                    }



                    
            else if (tagId1 == MAKE_TAG_ID (UNIV, CONS, OCTETSTRING_TAG_CODE))
                    
            {
                        
            /*
                         * constructed octets string embedding in this constructed
                         * octet string. decode it.
                         
            */

                        FillOctetStringStk (b, elmtLen1, 
            &totalElmtsLen1, env);
                    }

                    
            else  /* wrong tag */
                    
            {
                        Asn1Error (
            "BDecConsOctetString: ERROR - decoded non-OCTET STRING tag inside a constructed OCTET STRING\n");
                        longjmp (env, 
            -19);
                    }

                }
             /* end of for */

                (
            *bytesDecoded) += totalElmtsLen1;

            }
              /* FillOctetStringStk */

            在FillOctetStringStk中,判斷當(dāng)前串碎片是什么類型,如果是原生類型,就直接分配內(nèi)存存放緩沖區(qū)的內(nèi)容;如果還是連接類型,那就遞歸調(diào)用本函數(shù),否則報(bào)錯(cuò)。

             

            好了,字節(jié)串編碼解碼的分析就到此了。

            posted on 2012-04-23 16:22 Tim 閱讀(3258) 評(píng)論(0)  編輯 收藏 引用 所屬分類: eSNACC學(xué)習(xí)

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

            導(dǎo)航

            統(tǒng)計(jì)

            公告

            本博客原創(chuàng)文章,歡迎轉(zhuǎn)載和交流。不過請(qǐng)注明以下信息:
            作者:TimWu
            郵箱:timfly@yeah.net
            來源:m.shnenglu.com/Tim
            感謝您對(duì)我的支持!

            留言簿(9)

            隨筆分類(173)

            IT

            Life

            搜索

            積分與排名

            最新隨筆

            最新評(píng)論

            閱讀排行榜

            午夜精品久久久久久| 国产精品美女久久久久久2018| 国产婷婷成人久久Av免费高清| 国产精品久久久久久久| 久久精品成人影院| 久久综合噜噜激激的五月天| 成人久久久观看免费毛片| 久久久噜噜噜久久| 无码精品久久久久久人妻中字| 国产精品99久久久久久猫咪| 欧美牲交A欧牲交aⅴ久久| 国产真实乱对白精彩久久| 亚洲AV无一区二区三区久久| 国产真实乱对白精彩久久| 久久久久亚洲av无码专区喷水 | 亚洲午夜久久久久久久久久| 91精品国产综合久久精品| 久久国产AVJUST麻豆| 青青草原综合久久| 欧美一区二区三区久久综| 人人狠狠综合久久亚洲高清| 狠狠狠色丁香婷婷综合久久五月 | 亚洲va久久久噜噜噜久久男同| 久久综合九色综合97_久久久| 久久综合亚洲鲁鲁五月天| 久久国产成人精品国产成人亚洲| 99久久777色| 久久99免费视频| AV狠狠色丁香婷婷综合久久| 久久精品一区二区三区AV| 久久精品无码av| 久久婷婷五月综合成人D啪| 国产午夜福利精品久久| www.久久热.com| 色综合久久综精品| 91精品国产色综久久 | 91久久精品无码一区二区毛片| 伊人久久大香线蕉av一区| 久久亚洲中文字幕精品有坂深雪| 久久精品国产99国产精品导航| 久久只有这精品99|