📄 description
字号:
entry type formed by removing the starting `S'. The above forms would do to handle ASN.1 but we also have to be compatible with the C data structures generated by _p_o_s_y. The implementors decided to optimise the C data structures generated a little means we have to have all these S type entries. If a type was a single field in most cases they produced a #define which elim- inates the need to have a whole structure just for that type. In all the places where this type is used the field of the C structure is changed from a pointer to field which holds the value directly in the structure. See the ISODE reference given above for more details. We handle this by generating the same tables that would January 23, 1990 - 12 -be generated with out the optimisation, except the optimisedtypes the S-type of entries instead of the normal ones. Forexample an optimised OCTET STRING would have the type fieldof its entry as SOCTETSTRING instead of OCTETSTRING. Theonly difference in how S type and its corresponding normalare handle is how they find the C data structure for thatentry. That difference is that there is no indirectionthrough pointers.Flags field Besides the encoding the class the pe_flags field also contains a few possible flags. Mainly FL_OPTIONAL which means the ASN.1 type corresponding to this flag is OPTIONAL. Consequently when encoding it has to determine if the type is present in the user data pos- sibly using the bit map as described under the OPTL entry. Likewise when decoding it may have to set a bit in the bit map appropriately. The other flag at the moment is FL_DEFAULT which means the entry corresponds to an ASN.1 DEFAULT type. This bit is still needed as not all types have DFLT_* entries implmented for them at the moment. In particular compound value things like SEQUENCE and SET can't have thier default value specified. This is consistent with ISODE, if fact implementing that may even break existing ISODE code. This last flag FL_IMPLICIT is obsolete and not not used any where._1._2. _W_a_l_k _t_h_r_o_u_g_h _o_f _p_e_p_s_y _l_i_b_r_a_r_y _r_o_u_t_i_n_e_s. Here we walk through all the pepsy library routines atleast briefly. If any new routines are added or a routinechanged this documentation is the most likely part that willneed changing. First we give some theory as to how the taskhave have been brocken into routines then describe eachfunction in detail. We assume you are familiar with ISODE'sPE data structure manipulation routines. if not they aredocumented in the ISODE manuals, Volume one, chapter 5,"Encoding of Data-Structures" (It actually covers decodingas well)._1._2._1. _O_v_e_r_v_i_e_w _o_f _p_e_p_s_y _l_i_b_r_a_r_y Each seperate task is put into a different file. Soall the encoding stuff is in _e_n_c._c, all the decoding stuffis in _d_e_c._c, printing stuff in _p_r_n_t._c and freeing stuff in_f_r_e._c. Actually it breaks down a little in practice, someof the routines for moving around the tables are used inboth _e_n_c._c and _d_e_c._c for example. Probably they shoulddefined in _u_t_i_l._c so that linking one of the files from thelibrary doesn't force linking any other except _u_t_i_l._o. There is a common structure to each of the major files January 23, 1990 - 13 -as well. There is a main routine which the user calls toobtain the services provided by that file's routines. Asall the files revolve about processing the table entriestheir structure is based on running through the tableentries. We shall call each array of entries a table or anobject. There is a routine, usually with a name ending in_obj, which is designed to process an object. For exampleen_obj is the routine called to generated an encoded object.Then there are routines to call on each compound type suchas en_seq for encode a SEQUENCE. Finally all the primitivesare handled by a one function that ends in _type. This letseach routine concentrate on handling the features particularto its type and call the appropriate routine to handle eachtype it finds with in its compound type. Most of these table processing routines have just threearguements: which are called parm, p, mod. The parm is char* or char ** in the encoding and decoding routines respec-tively. This points to the user's C structure that data tobe encoded is taken from when encoding. When decoding it isthe address of a pointer which is made to point the C struc-ture filled with the decode data. The freeing, which isbased on the decoding routines, has a char ** while theprinting routines don't look at the user's data and so don'thave such a pointer. The p points to the current tableentry we are up to processing and the mod arguement pointsto the modtyp structure for the current module we are pro-cessing. All these processing routines return a PE type, whichis defined in ISODE's file _h/_p_s_a_p._h, and to return zero ifthey have an error, but not always. In fact the error han-dling is needs some work and has not been tested very well.Generally it tries to print out the table entry where some-thing went wrong and the name of the function it was in. Itthen sometimes does an exit which may not be very pleasentfor the user._1._2._2. _T_h_e _e_n_c_o_d_i_n_g _r_o_u_t_i_n_e_s - _e_n_c._cenc_fThis is the the routine made available to the user for the encoding routines. It is fairly simple as it leaves all the hard things up to other routines. All it does is use the type number and modtyp pointer to get a pointer to the table for encoding that type. Then it calls the table or object encoding routine, en_obj, on that object. It first does a consistency check of making sure the first entry in the table is a PE_start. Note that it returns an integer (OK or NOTOK) instead of a PE pointer. This is to be consi- tent with ISODE functions. January 23, 1990 - 14 -en_objWe loop through the entries until we come to the end of the table and then we return the PE we have built up from the user's data which is pointed to by parm. In looping through each entry we call the appropriate rou- tine to encode its data. The default case is handled by calling en_type which takes care of all the primi- tive types. The macro NEXT_TPE sets its arguement to point to thenext type in the table, counting compound types as one type.Thus if NEXT_TPE is called on a SET_START it will skip allthe entries up to and including the matching PE_END. Asmany objects consist of one compound type and its componentsthe main loop will only be run through once. Even when theobject is not based on a compound type it will then consistof one simple type which is processed by en_type, againprobably going through the loop only once. In fact the onlyway it can go through the loop more than once is to processentries that subsidary to the main type, e.g. ETAG entriesand things like that. To double check this is the casethere is some code that looks for the processing of morethan one data generating entry. Much of that testing could probably be eliminated withno loss. Similarly prehaps the IMP_OBJ and ETAG could behandled by the default action of calling en_type. As theseroutines have evolved after many changes there are thingslike that which really need to be looked at closely beforetrying. The comment /*SUPRESS 288*/ means suppress warning288 to saber C debugging tool that we use.en_type This is one of the longest functions as it has so many cases to handle. It again is structure as a loop over the types until PE_END but it actually returns as soon as it has encoded the next type. We can now look at the encoding of the primative ASN.1 types in detail.DFLT_FBecause we have arranged that for encoding tables, that we precede the entry with a DFLT_F entry we can neatly handle all the default cases. All we do is check if the parameter passed in the user data, in parm, is the same as the default value specified in the DFLT_F entry. The function same performs this check. If it is the same don't encode anything just return, otherwise continue on and encode it.ETAG To handle explicit tags we merely allocate a PE with the right tag and call en_etype to encode its contents, which are in the following entries. The switch on the pe_ucode field use to make a difference but now it is meaningless and should be cleaned up.SEQ_START, SEQOF_START, SET_START, SETOF_START January 23, 1990 - 15 - We merely call the appropriate function handle them. Note one _i_m_p_o_r_t_a_n_t difference in the way they are called here from that in enc_obj, the parm arguement is used as a base to index off and fetch a new pointer to pass the next function. This seemly bizarre action is quite straight forward when seen written as it is nor- mally in C, "parm->offset". Where the field offset is a pointer which has an offset from the start of the structure of p->pe_ucode bytes. This is the magic of how we access all the differentfields of the C data structures with the one piece of code.It is also prehaps the most critical dependency of the wholesystem on the implementation of the C language. As the BGNUC compiler supports this feature then it is compilerable onmost machines. But any porters should pay attention to thisto ensure that thier compiler is happy generating theseoffsets and compiling these casts properly. The reason why this is different from the calls inen_obj is that this is not the first compound type in thetable. The first and only the first does not have an offsetand does not need to be indirected through any pointers.All the compound types inside this type will have as theirfield a pointer which points to a structure. From here onwe shall say _i_n_d_i_r_e_c_t_i_o_n to mean this adding the pe_ucodefield to the pointer to the structure and using it to refer-ence a pointer. Whether to use _i_n_d_i_r_e_c_t_i_o_n or not is veryimportant matter that really needs to be understood tounderstand how the routines are structured.IMP_OBJ Here we have to handle the case where we can encode the object then have to change its tag and class after encoding. At the end of this entry this is done very simply by assigning the right values to the appropriate fields after the object has been built. This means that if the intermeadiate form is altered this piece of code may have to be altered as well. There seems to be no better way of handling this. The complication in handling this field is the handlingof all the possible types of object. If it is an externalobject we have to perform a call to enc_f with all the rightarguements where a normal OBJECT, the last else branch,requires a normal call to en_obj. Note the case of SOBJECTis the same as OBJECT _e_x_c_e_p_t _t_h_e_r_e _i_s _n_o _i_n_d_i_r_e_c_t_i_o_n.SOBJECT and OBJECT Here is the code that handles the two cases sperately. It is exactly as in the IMP_OBJ case except seperated out. Note the only difference between the two cases is lack of indirection in the SOBJECT case. January 23, 1990 - 16 -CHOICE_START This is exactly as all other compound types, like SEQ_START and OBJECT, we call the appropriate routine with indirection. From reading the ISODE manuals that the ASN.1 CHOICE type is handled by a structure of its own like the other compund types.EXTOBJ and SEXTOBJ January 23, 1990
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -