|
|
1.1 ! root 1: ! 2: ! 3: ! 4: ! 5: ! 6: ! 7: _1. _O_v_e_r_v_i_e_w _o_f _p_e_p_s_y _s_y_s_t_e_m ! 8: ! 9: This section describes how the various parts fit ! 10: together to make the system work. The principle behind ! 11: pepsy is fairly simple. The ASN.1 is summarised as tables ! 12: of integers. These tables are read by driver routines which ! 13: encode or decode data to or from the internal format that ! 14: ISODE OSI implementation uses. In ISODE specific functions ! 15: are generated for each ASN.1 type defined in contrast the ! 16: pepsy merely generates a new table of data which is far far ! 17: smaller. ! 18: ! 19: As there is a great deal of effort invested in the ! 20: ISODE interface to the encoding/decoding routines pepsy ! 21: automatically provides macros which map the original func- ! 22: tions into the appropriate function call of a driver. This ! 23: allows existing posy using code to switch to the pepsy sys- ! 24: tem with no changes to the code provided no function ! 25: pointers are used to the original ISODE functions. Even ! 26: when there are function pointers used the changes are very ! 27: simple and take only a few hours to implement. ! 28: ! 29: _1._1. _B_r_i_e_f _d_e_s_c_r_i_p_t_i_o_n _o_f _t_h_e _u_s_e _o_f _t_h_e _p_e_p_s_y _s_y_s_t_e_m. ! 30: ! 31: _1._1._1. _O_u_t_l_i_n_e _o_f _t_h_e _f_i_l_e_s _p_r_o_d_u_c_e_d _u_n_d_e_r _t_h_e _p_e_p_s_y _s_y_s_- ! 32: _t_e_m. ! 33: ! 34: The pepsy system consists of a program called _p_o_s_y ! 35: which translates ASN.1 modules into a set of tables, called ! 36: _p_o_s_y at the moment, and library of driver routines, called ! 37: _l_i_b_p_e_p_s_y._a. Running this _p_o_s_y program on the ASN.1 file ! 38: will produce several files. If the name of the ASN.1 module ! 39: is MODULE the following files are generated: ! 40: ! 41: MODULE-types.h ! 42: which contains C structure definitions. The user of ! 43: the library provides data as a linked list of these C ! 44: data structures and expects to receive data back as a ! 45: similar linked list. These data structures are exactly ! 46: the same as those produced by the original ISODE _p_o_s_y ! 47: so that existing software written for the old _p_o_s_y pro- ! 48: gram needs no change. For details on the C data struc- ! 49: tures types generated see the documentation of the ori- ! 50: ginal _p_o_s_y program in volume 4 Chapter 5 of the ISODE ! 51: manuals. ! 52: ! 53: MODULE_tables.c ! 54: This file contains the tables generated by the new _p_o_s_y ! 55: program. These tables consist of three parts, the ! 56: first which contains the summary of ASN.1 types. Each ! 57: type is summarised as an array of a primitive type, ! 58: struct pte, for encoding and decoding, and struct ptpe ! 59: for printing. As implied there is one array for each ! 60: type for each of encoding, decoding and printing as ! 61: ! 62: ! 63: ! 64: January 23, 1990 ! 65: ! 66: ! 67: ! 68: ! 69: ! 70: - 2 - ! 71: ! 72: ! 73: specified when _p_o_s_y is run. The next part contains up ! 74: to three tables of pointers to these arrays. Each of ! 75: the three different types of arrays, encoding, decoding ! 76: and printing, has its own table of pointers. Finally ! 77: there is the module type definition which contains con- ! 78: tains pointers to these tables and some other useful ! 79: information about the module such as its name. This ! 80: module type structure, which is typedefed to modtyp, is ! 81: the only piece of data which is global, all the rest of ! 82: the data is static and is only addressable via the mod- ! 83: typ data structure. This provides a kind of object ! 84: oriented approach to handling the tables. Once you are ! 85: passed a pointer to an ASN.1's modtyp structure you can ! 86: encode, decode and print any of its types by calling ! 87: the appropriate libpepsy.a routine with its type ! 88: number. ! 89: ! 90: MODULE_pre_defs.h ! 91: This file contains #defines symbol of each of the ASN.1 ! 92: types to its type number, which is used when calling a ! 93: libpepsy.a routine. Each symbol is _Ztype-nameMODULE ! 94: where _t_y_p_e-_n_a_m_e is the name of the type with dashes (-) ! 95: turned into underscores (_) and _M_O_D_U_L_E is the name of ! 96: the module. For example of the ASN.1 universal type ! 97: _G_r_a_p_h_i_c_S_t_r_i_n_g would have the #define symbol _ZGra- ! 98: phicStringUNIV. The __Z is prepended to try to make the ! 99: symbols unique. This file also contains and extern ! 100: declaration for the modtyp data for its module. ! 101: ! 102: MODULE_defs.h ! 103: This file contains macros for all the encoding, decod- ! 104: ing and printing functions that the _p_e_p_y program would ! 105: have for these ASN.1 types. This allows much of the ! 106: code that uses the routines generated by running the ! 107: old _p_o_s_y program and taking its output and running _p_e_p_y ! 108: on augmented ASN.1 output can be recompiled unchanged. ! 109: If the code used pointers to these functions it is ! 110: necessary to change it to pass around the type numbers ! 111: instead and to call appropriately call a libpepsy.a ! 112: library routine with the type number. As pointers to ! 113: the printing routines in ISODE are passed as arguments ! 114: a #define is provided to turn the argument into the ! 115: pair of arguments, type number and pointer to modtyp ! 116: structure, which are needed to allow the diagnostic ! 117: printing code to work with no change for the current ! 118: ISODE stack. This file also contains a #include of the ! 119: _M_O_D_U_L_E__p_r_e__d_e_f_s._h file. ! 120: ! 121: As the _M_O_D_U_L_E-_t_y_p_e_s._h file #include's the _M_O_D_U_L_E__d_e_f_s._h ! 122: file no further #includes need to be added to the files ! 123: using the encoding/decoding/printing functions. This means ! 124: that code written to use posy/pepy system may need no change ! 125: at all and the only effort required is to change the ! 126: Makefile to use the pepsy system. If there is code changes ! 127: ! 128: ! 129: ! 130: January 23, 1990 ! 131: ! 132: ! 133: ! 134: ! 135: ! 136: - 3 - ! 137: ! 138: ! 139: required it would most likely be because function pointers ! 140: are used to reference the functions generated by posy. If ! 141: only the _p_e_p_y system was used, not posy then pepy, with code ! 142: placed inside action statements then quite a large amount of ! 143: work may be needed to change over to the new system, depend- ! 144: ing on how large and complex the _p_e_p_y module is. ! 145: ! 146: _1._1._2. _O_u_t_l_i_n_e _o_f _t_h_e _p_e_p_s_y _l_i_b_r_a_r_y. ! 147: ! 148: enc.cThis contains the routines that encode data from the C ! 149: data structures into ISODE's PElement linked list data ! 150: structure which it uses for all presentation data. The ! 151: most important function to pepsy users is enc_f which ! 152: called to encode a particular type. It is passed the ! 153: type number and a pointer to modtyp structure for that ! 154: module and then the rest of the arguments which are ! 155: passed to an encode function generated by _p_o_s_y/_p_e_p_y ! 156: system. See the documentation in Volume 4, "The Appli- ! 157: cations Cookbook", Section 6.4 called "Pepy Environ- ! 158: ment". Most of these latter arguments are ignored, ! 159: only parm and pe, are used. ! 160: ! 161: Contrary to what the ISODE documentation says these ! 162: ignored parameters are hardly ever used by existing code. ! 163: We have not found a single case where used for encoding a ! 164: named type, which is all that the user can reference anyway, ! 165: so we don't see any problems with ignoring these other ! 166: parameters. Hopefully one day they can be thrown away ! 167: entirely, until then they are actually passed the the encod- ! 168: ing function. ! 169: ! 170: The rest of the functions are mostly recursive routines ! 171: which encode a particular type of table entry. For example ! 172: SEQUENCE is encoded by en_seq which may call itself or oth- ! 173: ers to encode the types from which it is built up. The ! 174: function en_type builds up a simple type and en_obj encodes ! 175: a new type (object) and so on with other functions. There ! 176: are a few utility routines in the file such as same which ! 177: determines whether the value is the same as the default ! 178: value also. ! 179: ! 180: dec.cThis file contains the decoding routines that translate ! 181: presentation data into C data structures defined in the ! 182: MODULE-types.h is like _e_n_c._c. It is very much like the ! 183: file _e_n_c._c except the routines do the reverse tasks The ! 184: routines are structured in a very similar way. We have ! 185: dec_f which is called by the user to decode a type and ! 186: like enc_f takes the same arguments as the decoding ! 187: functions generated by _p_o_s_y with two additions, the ! 188: type number and a pointer to the modtyp structure for ! 189: that module. Likewise the other functions are very ! 190: much like those of enc.c ! 191: ! 192: prnt.cThis file contains the routines that print the ! 193: ! 194: ! 195: ! 196: January 23, 1990 ! 197: ! 198: ! 199: ! 200: ! 201: ! 202: - 4 - ! 203: ! 204: ! 205: presentation data in a format similar to that generated ! 206: by _p_e_p_y's printing functions. It's main function ! 207: prnt_f is takes the same arguments as the printing ! 208: function generated by _p_e_p_y as well as the now familiar ! 209: type number and modtyp pointer. The functions are ! 210: modeled on the decoding routines as it has similar job ! 211: to. The only difference is that instead of storing the ! 212: decoded data into a C data structure it is nicely ! 213: printed out. ! 214: ! 215: fr.c This file contains code to free the data structures ! 216: defined in MODULE-types.h. Likewise if the -f flag is ! 217: given when generating the types file it also includes ! 218: macros in the types file which replace the freeing ! 219: functions generated by ISODE's _p_o_s_y. The function that ! 220: the user calls us fre_obj which takes a pointer to the ! 221: data structure, its decoding table entry and a pointer ! 222: to the modtyp structure for the module. The freeing is ! 223: based on the decoding routines except instead of decod- ! 224: ing all it does is free each part of the data struc- ! 225: ture, which might involve recursive calls, then it ! 226: frees the data structure at the end. ! 227: ! 228: util.cThis contains the utility routines used by more than ! 229: one of the above files. This is mostly diagnostic rou- ! 230: tines at the moment, more general routines could be ! 231: included in here. If there is an error at the moment ! 232: which it can't recover from it just prints out a mes- ! 233: sage on standard error and calls exit. Not perfect and ! 234: this is something that will need work. ! 235: ! 236: main.cThis contains code to perform a series of tests on the ! 237: _p_e_p_s_y library which is a useful check to see whether ! 238: any of the routines has been broken by any changes ! 239: made. It basically loops through a whole series of ! 240: test cases. Each test case is encoded from some built ! 241: in test data and then decoded and checked to see if the ! 242: data has changed in the transfer. If it is compiled ! 243: with -_D_P_R_N_T=_1 the encoded data is also printed out to ! 244: check the printing routines which generates a vast ! 245: amount of output. Finally the free routines are used ! 246: to free the allocated data, although it can not ! 247: directly check the free routines to see if they work, ! 248: it can be used with a malloc tracing package to check ! 249: that the routines work. ! 250: ! 251: test_table.h ! 252: This contains the test cases that _m_a_i_n._c program runs. ! 253: Each entry in the table corresponds to a type. One of ! 254: the fields is count of how many times that type is to ! 255: be tested to try out the different possibly data values ! 256: it might have. ! 257: ! 258: pep.h and pepdefs.h ! 259: ! 260: ! 261: ! 262: January 23, 1990 ! 263: ! 264: ! 265: ! 266: ! 267: ! 268: - 5 - ! 269: ! 270: ! 271: These files contain the definition of types used for ! 272: the tables that drive the encoding/decoding/printing ! 273: routines. All the constants used in that table are ! 274: defined here via #defines. The modtyp structure is ! 275: defined in _p_e_p_d_e_f_s._h. ! 276: ! 277: t1.py and t2.py ! 278: These are test ASN.1 modules that are used by _m_a_i_n._c ! 279: routines to check the _p_e_p_s_y library. The file _t_1._p_y ! 280: contains the majority of different types with a few of ! 281: a different module provided in _t_2._p_y. This allows the ! 282: testing of the code for handling ASN.1 external refer- ! 283: ences, i.e. references to types defined in other, ! 284: external, modules. ! 285: ! 286: _1._1._3. _N_e_w _f_i_l_e_s _i_n _t_h_e _p_e_p_y _d_i_r_e_c_t_o_r_y ! 287: ! 288: etabs.c, dtabs.c and ptabs.c ! 289: These files contain the code to generate the ! 290: encoding/decoding/printing tables. The main routine in ! 291: _e_t_a_b_s._c is tenc_typ which is called on each ASN.1 type ! 292: to generate an array of entries which describe how to ! 293: encode that type. See the details section for more ! 294: information about how the table entries function. ! 295: Similarly _d_t_a_b_s._c contains the routine tdec_typ which ! 296: is called on each type to generate its decoding table ! 297: entries. Likewise tprnt_typ routine generates the ! 298: arrays of table entries for the printing tables. This ! 299: function is in _p_t_a_b_s._c. ! 300: ! 301: dfns.cThis file contains miscellaneous string handling rou- ! 302: tines and hash table routines that don't really belong ! 303: anywhere else. Some of the routines could be cleaned ! 304: up in that they tend not to free memory they use. ! 305: ! 306: mine.hThis file contains the definitions for the hash ! 307: table(s) that are used to keep track of the ASN.1 ! 308: types. This could probably be done with out a hash ! 309: table, should anyone want to clean this up, feel wel- ! 310: come. The lookup function is in _d_f_n_s._c. ! 311: ! 312: pass2.h ! 313: This file has most of the #defines for the table gen- ! 314: erating program. Most of the prefixes and suffixes of ! 315: function names and files names are defined here so, ! 316: hopefully, the names can be changed by merely changing ! 317: the definition. This contains most of the important ! 318: definitions needed by the changes to the _p_o_s_y program ! 319: needed to generate tables. ! 320: ! 321: posy.hThis contains the definition of a symbol which is now ! 322: needed outside of the the main routine and the yacc ! 323: file. By putting it here we can include it any file ! 324: that needs to know it with out putting in any that ! 325: ! 326: ! 327: ! 328: January 23, 1990 ! 329: ! 330: ! 331: ! 332: ! 333: ! 334: - 6 - ! 335: ! 336: ! 337: doesn't need it and with out including all the other ! 338: definitions that occur in _p_e_p_y._h. The structure and ! 339: meaning of the tables generated from the ASN.1 grammar ! 340: ! 341: Each collection of ASN.1 grammar is called a module. ! 342: (See ASN.1 ) Each ASN.1 module is completely specified in ! 343: the program by a single C structure of type modtyp and the ! 344: data which it references. See the _p_e_p_d_e_f_s._h file in the ! 345: _p_e_p_s_y directory. For each ASN.1 module there are three ! 346: tables that are generated fromASN.1 grammar. These initial- ! 347: ised arrays which we call tables are called the encoding, ! 348: decoding and printing tables. Each of these tables is ! 349: referenced through a different pointer of the modtyp struc- ! 350: ture. ! 351: ! 352: Each of these pointers references an array of pointers, ! 353: one pointer for each ASN.1 type defined in the module. The ! 354: position of one of these pointers is the unique type number ! 355: we give to its corresponding type. The pointer references ! 356: an array of type tpe or ptpe, depending whether it is an ! 357: entry in the decoding/encoding tables or printing tables ! 358: respectively. See _p_e_p._h in the _p_e_p_s_y directory. This array ! 359: actually contains the necessary information to ! 360: encode/decode/print that ASN.1 type. So given the modtyp ! 361: structure of an ASN.1 module and its type number you can ! 362: call a routine to encode, decode or print that type. ! 363: ! 364: The rest of this document assumes a good knowledge of ! 365: ASN.1 notation so go read a copy if you haven't already. ! 366: From here on I shall mention only tpe and this means tpe in ! 367: the case of encoding or decoding and ptpe in the case of ! 368: printing, unless otherwise stated. Each type is represented ! 369: by an array of tpe (or ptpe for printing). The basic ele- ! 370: ment consists of four integer fields, the printing table is ! 371: the same with an addition char pointer field which contains ! 372: the name corresponding to that entry in the ASN.1 grammar. ! 373: The first specifies the type of the entry and determines how ! 374: the rest are interpreted. The possible types are listed in ! 375: _p_e_p_s_y/_p_e_p._h. Each type is an array which starts with an ! 376: entry of type PE_START and ends with one of type PE_END. ! 377: Each primitive type requires one entry to specify it, apart ! 378: from possible PE_START and PE_END used to specify the start ! 379: and end of the type. Constructed types are represented by a ! 380: list of entries terminated by an entry of type PE_END. As ! 381: ASN.1 types can be nested inside so will the representation ! 382: in tpe entries be nested. For example the ASN.1 type defin- ! 383: ition: ! 384: Example1 ::= ! 385: SEQUENCE { ! 386: seq1 SEQUENCE { ! 387: an-i INTEGER, ! 388: an-ostring OCTET STRING ! 389: }, ! 390: a-bool IMPLICIT [0] BOOLEAN ! 391: ! 392: ! 393: ! 394: January 23, 1990 ! 395: ! 396: ! 397: ! 398: ! 399: ! 400: - 7 - ! 401: ! 402: ! 403: } ! 404: Will generate an encoding array: ! 405: static tpe et_Example1Test[] = { ! 406: { PE_START, 0, 0, 0 }, ! 407: { SEQ_START, 0, 16, FL_UNIVERSAL }, ! 408: { SEQ_START, OFFSET(struct type_Test_Example1, seq1), 16, FL_UNIVERSAL }, ! 409: { INTEGER, OFFSET(struct element_Test_0, an__i), 2, FL_UNIVERSAL }, ! 410: { OCTETSTRING, OFFSET(struct element_Test_0, an__ostring), 4, FL_UNIVERSAL }, ! 411: { PE_END, 0, 0, 0 }, ! 412: { BOOLEAN, OFFSET(struct type_Test_Example1, a__bool), 0, FL_CONTEXT }, ! 413: { PE_END, 0, 0, 0 }, ! 414: { PE_END, 0, 0, 0 } ! 415: }; ! 416: ! 417: ! 418: Here the second last PE_END matches and closes off the ! 419: first SEQ_START. The entries which correspond to the other ! 420: primative types are pretty obvious, with the INTEGER entry ! 421: corresponding to the primative INTEGER. For fields that ! 422: generate data the general interpretation of the other three ! 423: fields is offset, tag and flags/class fields respectively. ! 424: ! 425: offsetThe second field gives the offset in a C data struc- ! 426: ture needed to reference the data that corresponds to ! 427: this table entry. Each ASN.1 type has C structure ! 428: types generated as described in the ISODE manuals, ! 429: volume 4 "The applications Cookbook" Section 5.2, "POSY ! 430: Environment". As this offset may have to be determined ! 431: in a compiler dependent manner a C preprocessor macro ! 432: is used hide the actual details. ! 433: ! 434: tag This is the tag associated with the ASN.1 type for that ! 435: entry. Notice that in the example the [0] IMPLICIT ! 436: which changes the tag associated with the BOOLEAN entry ! 437: actually has the correct tag of 0 in the table. Like- ! 438: wise SEQUENCE has the correct tag of 16 in its ! 439: SEQ_START entry and so on for the others. ! 440: ! 441: flags/class ! 442: This contains the ASN.1 class associated with the ! 443: entry's type. That is UNIVERSAL for all except the ! 444: BOOLEAN type which is CONTEXT class. This fourth can ! 445: also contain flags that specify if the type is OPTIONAL ! 446: or DEFAULT. There is plenty of room here as there is ! 447: only four possibly classes. ! 448: ! 449: Now that you have some idea of how these arrays are ! 450: arranged for a type definition I will proceed to go through ! 451: the possible type of entries and describe what they do and ! 452: how they work. These values are defined in _p_e_p_s_y/_p_e_p._h. ! 453: Those entries with a value below TYPE_DATA are entries that ! 454: don't correspond to data to be encoded/decoded and are for ! 455: other book keeping type purposes. ! 456: ! 457: ! 458: ! 459: ! 460: January 23, 1990 ! 461: ! 462: ! 463: ! 464: ! 465: ! 466: - 8 - ! 467: ! 468: ! 469: PE_START and PE_END ! 470: As explained above PE_START starts the beginning of a ! 471: ASN.1 type's array. It probably isn't necessary but ! 472: the size of the tables is so small it isn't much of an ! 473: over head to keep around for cosmetic reasons. The ! 474: entry type PE_END is necessary to mark the end of some ! 475: compound type as well as the end of ASN.1 data type. ! 476: ! 477: XOBJECT and UCODE ! 478: These are obsolete types and probably should be ! 479: removed. They were to allow C code written directly by ! 480: the user to be incorporated into the encoding/decoding ! 481: but it was found unnecessary. Prehaps some brave soul ! 482: would like to use them in an attempt to implement a ! 483: similar system based on _p_e_p_y which is what we first ! 484: attempted to do until we found this to be much easier. ! 485: ! 486: MALLOCThis field only occurs in the decoding tables. It ! 487: specifies how much space to malloc out for the current ! 488: C structure it is just inside of. For instance in the ! 489: example above the decoding table has the following ! 490: entry: ! 491: ! 492: { MALLOC, 0, sizeof (struct type_Test_Example1), 0 }, ! 493: ! 494: just after the first SEQ_START entry. It tells it to ! 495: malloc out a struct type_Test_Example1 structure to ! 496: hold the data from the sequence when it is decoded. ! 497: ! 498: SCTRLThis entry is used in handling the ASN.1 CHOICE type. ! 499: The C type generated for ASN.1 CHOICE type is a struc- ! 500: ture with an offset field in it and a union of all the ! 501: C types present in the CHOICE. Each ASN.1 type in the ! 502: CHOICE of types has a C type definition generated for ! 503: it. The union is of all these types, which is quite a ! 504: logical way to implement a CHOICE type. The offset ! 505: field specifies which possibility of interpreting the ! 506: union should be used (which _m_e_m_b_e_r should selected). ! 507: As such it needs to be read by the encoding routines ! 508: when encoding the data from the C data structures and ! 509: to be set by the decoding routines when it is decoding ! 510: the data into the C data structures. There is one such ! 511: entry for each CHOICE type to specify where the offset ! 512: field is. ! 513: ! 514: CH_ACTAnother redundant entry type. I think this was also ! 515: used in code to handle C statements or actions speci- ! 516: fied by the user. It probably should be removed. ! 517: ! 518: OPTL This is used to handle the optionals field that is gen- ! 519: erated by posy when optional types that are _n_o_t imple- ! 520: mented by pointers are present in the ASN.1 type. For ! 521: example if an ASN.1 type has an optional integer field ! 522: how does the encoding routine determine if the integer ! 523: ! 524: ! 525: ! 526: January 23, 1990 ! 527: ! 528: ! 529: ! 530: ! 531: ! 532: - 9 - ! 533: ! 534: ! 535: is to be present or not? If it was implemented as a ! 536: pointer it could use a NULL (zero) pointer to mean that ! 537: the type was not present because NULL is guaranteed to ! 538: never occur as a legal pointer to a real object. But ! 539: all the possible values for integer could be legally ! 540: passed so instead for these types which are not ! 541: pointers and are optional a bit map is allocated in the ! 542: structure. Each non pointer optional type a bit from ! 543: the bit map is allocated. ! 544: ! 545: If that bit is set the corresponding type is present ! 546: and it is not present if the bit is not set. Each bit has a ! 547: #define generated for it. The bit map is merely an integer ! 548: field called "optionals" limiting maximum number of such ! 549: optionals to 32 on Sun machines, 16 on some others. (An ! 550: array of char as BSD fd_sets would have avoid all such lim- ! 551: its, not that this limit is expected to be exceeded very ! 552: often !) Like the SCTRL entry this entry merely serves to ! 553: specify where this field is so it can be test and set by the ! 554: encoding and decoding routines respectively. ! 555: ! 556: ANY and CONS_ANY ! 557: The C type corresponding to the entry is a PE pointer. ! 558: To conform with _p_e_p_y the tag and class of this entry ! 559: are ignored, which may or may not be the most sensible ! 560: thing. The CONS_ANY is a redundant symbol which means ! 561: the same thing but is not used. This should be clean ! 562: up and removed. ! 563: ! 564: INTEGER, BOOLEAN, BITSTRING, OCTETSTRING and OBJID ! 565: These are just as described in the first article. See ! 566: the ISODE manual to find out what they are allocated as ! 567: a C data type to implement them. The offset fields ! 568: says where to find this data type with in the current ! 569: structure. ! 570: ! 571: SET_START, SETOF_START, SEQ_START and SEQOF_START ! 572: These compound entries differ from the above in that ! 573: they group all the following entries together up to the ! 574: matching PE_END. The entries with OF in them ! 575: correspond to the ASN.1 types which have OF in them ! 576: e.g. SET OF. Allowing the OF items to have an arbi- ! 577: trary number of entries is excessive flexibility, they ! 578: can only have one type by the ASN.1 grammar rules. The ! 579: C data type corresponding to them is either a structure ! 580: if it is the first such type in the array or a pointer ! 581: to a structure is isn't. This complicates the process- ! 582: ing of these structures a little but not greatly. The ! 583: OF types differ one other important way, they may occur ! 584: zero, one or more times, with no upper bound. To cope ! 585: with this the C data type is a linked list structure. ! 586: The pointer to the data structure determines whether or ! 587: not there is another occurrence of the type, if it is ! 588: NULL there isn't. Thus each data structure has this ! 589: ! 590: ! 591: ! 592: January 23, 1990 ! 593: ! 594: ! 595: ! 596: ! 597: ! 598: - 10 - ! 599: ! 600: ! 601: pointer to the next occurrence, the offset of this ! 602: pointer is placed in the PE_END field where it can con- ! 603: veniently be used to determine whether or not to make ! 604: another pass through the table entry. ! 605: ! 606: OBJECTWhen one type references another it generates an ! 607: OBJECT entry. This specifies the type number of the ! 608: type which is present in the 3rd field of the tpe ! 609: structure, pe_tag. The 2nd field still gives the ! 610: offset in the C data structure which specifies where ! 611: the user's data for that type is to be found. Usually ! 612: this a pointer to the C data structure for that type. ! 613: ! 614: T_NULLThis entry means the ASN.1 primative type NULL. It ! 615: doesn't have any body and consequently has no offset as ! 616: it cannot carry data directly. Only its absence or ! 617: presence can mean anything so if it is optional it sets ! 618: or clears a bit in the bit map as described earlier for ! 619: OPTL entry. ! 620: ! 621: T_OIDThis use to be used for Object Identifiers and now is ! 622: unused, it should be got rid. ! 623: ! 624: OBJIDThis corresponds to the Object Identifier ASN.1 type ! 625: primitive. It is implemented the same as other prima- ! 626: tive types like INTEGER and OCTET STRING. ! 627: ! 628: ETAG This entry gives the explicit tag of the following ! 629: entry. The usual fields which define class and tag are ! 630: the only ones which have meaning in this entry. By ! 631: concatenating successive ETAG entries it is possibly to ! 632: build up an limited number explicit tags, although this ! 633: hasn't been tested yet. ! 634: ! 635: IMP_OBJ ! 636: If a type has an implicit tag usually all we have to do ! 637: is set its tag and class appropriately in its entry. ! 638: This works for all but one important case, the refer- ! 639: ence of another type. This is messy because we can't ! 640: alter the definition of the type with out wrecking it ! 641: for the other uses. So what we do for encoding is ! 642: build the type normally and then afterward it is built ! 643: change its tag and class to be the values we want. ! 644: Similarly for decoding we match the tag and class up ! 645: and then decode the body of the type. We can't use a ! 646: OBJECT entry for this because among other reasons there ! 647: 3rd field is already to store the type number. (The ! 648: forth needs to be free to contain flags such as DEFAULT ! 649: and OPTIONAL) So a new entry type is used, IMP_OBJ, to ! 650: hold the tag and class. It must be followed by an ! 651: OBJECT entry which is used to handle the type as nor- ! 652: mal, the IMP_OBJ entry gives the tag and class to be ! 653: used. Like the ETAG entry the IMP_OBJ affects the ! 654: entry that follows it. ! 655: ! 656: ! 657: ! 658: January 23, 1990 ! 659: ! 660: ! 661: ! 662: ! 663: ! 664: - 11 - ! 665: ! 666: ! 667: EXTOBJ and EXTMOD ! 668: These handle external type references. This is just ! 669: like a normal (internal?) type reference except we must ! 670: now specify which module as well as the type. Simi- ! 671: larly because there are no more free fields in the ! 672: OBJECT type we need two entries to hold all the infor- ! 673: mation we need. The EXTMOD occurs first and holds the ! 674: type number and the offset into the C data structure ! 675: and the flags, exactly as for an OBJECT entry. The ! 676: next entry, which must be an EXTMOD, contains a pointer ! 677: to the modtyp structure for its module. Like a normal ! 678: OBJECT entry to handle the case of an implicit tag an ! 679: IMP_OBJ entry would occur before these two entries ! 680: which gives the class and tag. Likewise it could have ! 681: an explicit tag in which the two entries would be pro- ! 682: ceeded by an ETAG entry. ! 683: ! 684: DFLT_F and DFLT_B ! 685: When a type has a default value, to handle decoding and ! 686: encoding properly you need to know its value. As there ! 687: is no space to store the value in most entries we allo- ! 688: cate a whole entry to specify the value. When encoding ! 689: it is convenient to have the default occur before the ! 690: entry it refers to. This allows a single check to han- ! 691: dle all the default encoding. All it has to do is ! 692: check whether it is the same as the default value and ! 693: if so not bother encoding the next type. On the other ! 694: hand when decoding it is more convenient to have the ! 695: entry after the one it refers to. In this case we need ! 696: to determine that it is missing before we use the ! 697: default value to determine the value to pass to the ! 698: user. To handle this we have entries of both types. ! 699: _D_F_L_T__F contains the default value for the following ! 700: entry (F = Front) and DFLT_B contains that for the ! 701: entry before it (B = Back). Consequently DFLT_F are ! 702: only used in the decoding tables and DFLT_B entries are ! 703: only used in the decoding (and printing tables). ! 704: ! 705: S-Types ! 706: These types are entries for the same ASN.1 type as the ! 707: entry type formed by removing the starting `S'. The ! 708: above forms would do to handle ASN.1 but we also have ! 709: to be compatible with the C data structures generated ! 710: by _p_o_s_y. The implementors decided to optimise the C ! 711: data structures generated a little means we have to ! 712: have all these S type entries. If a type was a single ! 713: field in most cases they produced a #define which elim- ! 714: inates the need to have a whole structure just for that ! 715: type. In all the places where this type is used the ! 716: field of the C structure is changed from a pointer to ! 717: field which holds the value directly in the structure. ! 718: See the ISODE reference given above for more details. ! 719: ! 720: We handle this by generating the same tables that would ! 721: ! 722: ! 723: ! 724: January 23, 1990 ! 725: ! 726: ! 727: ! 728: ! 729: ! 730: - 12 - ! 731: ! 732: ! 733: be generated with out the optimisation, except the optimised ! 734: types the S-type of entries instead of the normal ones. For ! 735: example an optimised OCTET STRING would have the type field ! 736: of its entry as SOCTETSTRING instead of OCTETSTRING. The ! 737: only difference in how S type and its corresponding normal ! 738: are handle is how they find the C data structure for that ! 739: entry. That difference is that there is no indirection ! 740: through pointers. ! 741: ! 742: Flags field ! 743: Besides the encoding the class the pe_flags field also ! 744: contains a few possible flags. Mainly FL_OPTIONAL ! 745: which means the ASN.1 type corresponding to this flag ! 746: is OPTIONAL. Consequently when encoding it has to ! 747: determine if the type is present in the user data pos- ! 748: sibly using the bit map as described under the OPTL ! 749: entry. Likewise when decoding it may have to set a bit ! 750: in the bit map appropriately. The other flag at the ! 751: moment is FL_DEFAULT which means the entry corresponds ! 752: to an ASN.1 DEFAULT type. This bit is still needed as ! 753: not all types have DFLT_* entries implmented for them ! 754: at the moment. In particular compound value things ! 755: like SEQUENCE and SET can't have thier default value ! 756: specified. This is consistent with ISODE, if fact ! 757: implementing that may even break existing ISODE code. ! 758: This last flag FL_IMPLICIT is obsolete and not not used ! 759: any where. ! 760: ! 761: ! 762: _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. ! 763: ! 764: Here we walk through all the pepsy library routines at ! 765: least briefly. If any new routines are added or a routine ! 766: changed this documentation is the most likely part that will ! 767: need changing. First we give some theory as to how the task ! 768: have have been brocken into routines then describe each ! 769: function in detail. We assume you are familiar with ISODE's ! 770: PE data structure manipulation routines. if not they are ! 771: documented in the ISODE manuals, Volume one, chapter 5, ! 772: "Encoding of Data-Structures" (It actually covers decoding ! 773: as well). ! 774: ! 775: _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 ! 776: ! 777: Each seperate task is put into a different file. So ! 778: all the encoding stuff is in _e_n_c._c, all the decoding stuff ! 779: is in _d_e_c._c, printing stuff in _p_r_n_t._c and freeing stuff in ! 780: _f_r_e._c. Actually it breaks down a little in practice, some ! 781: of the routines for moving around the tables are used in ! 782: both _e_n_c._c and _d_e_c._c for example. Probably they should ! 783: defined in _u_t_i_l._c so that linking one of the files from the ! 784: library doesn't force linking any other except _u_t_i_l._o. ! 785: ! 786: There is a common structure to each of the major files ! 787: ! 788: ! 789: ! 790: January 23, 1990 ! 791: ! 792: ! 793: ! 794: ! 795: ! 796: - 13 - ! 797: ! 798: ! 799: as well. There is a main routine which the user calls to ! 800: obtain the services provided by that file's routines. As ! 801: all the files revolve about processing the table entries ! 802: their structure is based on running through the table ! 803: entries. ! 804: ! 805: We shall call each array of entries a table or an ! 806: object. There is a routine, usually with a name ending in ! 807: _obj, which is designed to process an object. For example ! 808: en_obj is the routine called to generated an encoded object. ! 809: Then there are routines to call on each compound type such ! 810: as en_seq for encode a SEQUENCE. Finally all the primitives ! 811: are handled by a one function that ends in _type. This lets ! 812: each routine concentrate on handling the features particular ! 813: to its type and call the appropriate routine to handle each ! 814: type it finds with in its compound type. ! 815: ! 816: Most of these table processing routines have just three ! 817: arguements: which are called parm, p, mod. The parm is char ! 818: * or char ** in the encoding and decoding routines respec- ! 819: tively. This points to the user's C structure that data to ! 820: be encoded is taken from when encoding. When decoding it is ! 821: the address of a pointer which is made to point the C struc- ! 822: ture filled with the decode data. The freeing, which is ! 823: based on the decoding routines, has a char ** while the ! 824: printing routines don't look at the user's data and so don't ! 825: have such a pointer. The p points to the current table ! 826: entry we are up to processing and the mod arguement points ! 827: to the modtyp structure for the current module we are pro- ! 828: cessing. ! 829: ! 830: All these processing routines return a PE type, which ! 831: is defined in ISODE's file _h/_p_s_a_p._h, and to return zero if ! 832: they have an error, but not always. In fact the error han- ! 833: dling is needs some work and has not been tested very well. ! 834: Generally it tries to print out the table entry where some- ! 835: thing went wrong and the name of the function it was in. It ! 836: then sometimes does an exit which may not be very pleasent ! 837: for the user. ! 838: ! 839: _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._c ! 840: ! 841: enc_fThis is the the routine made available to the user for ! 842: the encoding routines. It is fairly simple as it ! 843: leaves all the hard things up to other routines. All ! 844: it does is use the type number and modtyp pointer to ! 845: get a pointer to the table for encoding that type. ! 846: Then it calls the table or object encoding routine, ! 847: en_obj, on that object. It first does a consistency ! 848: check of making sure the first entry in the table is a ! 849: PE_start. Note that it returns an integer (OK or ! 850: NOTOK) instead of a PE pointer. This is to be consi- ! 851: tent with ISODE functions. ! 852: ! 853: ! 854: ! 855: ! 856: January 23, 1990 ! 857: ! 858: ! 859: ! 860: ! 861: ! 862: - 14 - ! 863: ! 864: ! 865: en_objWe loop through the entries until we come to the end ! 866: of the table and then we return the PE we have built up ! 867: from the user's data which is pointed to by parm. In ! 868: looping through each entry we call the appropriate rou- ! 869: tine to encode its data. The default case is handled ! 870: by calling en_type which takes care of all the primi- ! 871: tive types. ! 872: ! 873: The macro NEXT_TPE sets its arguement to point to the ! 874: next type in the table, counting compound types as one type. ! 875: Thus if NEXT_TPE is called on a SET_START it will skip all ! 876: the entries up to and including the matching PE_END. As ! 877: many objects consist of one compound type and its components ! 878: the main loop will only be run through once. Even when the ! 879: object is not based on a compound type it will then consist ! 880: of one simple type which is processed by en_type, again ! 881: probably going through the loop only once. In fact the only ! 882: way it can go through the loop more than once is to process ! 883: entries that subsidary to the main type, e.g. ETAG entries ! 884: and things like that. To double check this is the case ! 885: there is some code that looks for the processing of more ! 886: than one data generating entry. ! 887: ! 888: Much of that testing could probably be eliminated with ! 889: no loss. Similarly prehaps the IMP_OBJ and ETAG could be ! 890: handled by the default action of calling en_type. As these ! 891: routines have evolved after many changes there are things ! 892: like that which really need to be looked at closely before ! 893: trying. The comment /*SUPRESS 288*/ means suppress warning ! 894: 288 to saber C debugging tool that we use. ! 895: ! 896: en_type ! 897: This is one of the longest functions as it has so many ! 898: cases to handle. It again is structure as a loop over ! 899: the types until PE_END but it actually returns as soon ! 900: as it has encoded the next type. We can now look at ! 901: the encoding of the primative ASN.1 types in detail. ! 902: ! 903: DFLT_FBecause we have arranged that for encoding tables, ! 904: that we precede the entry with a DFLT_F entry we can ! 905: neatly handle all the default cases. All we do is ! 906: check if the parameter passed in the user data, in ! 907: parm, is the same as the default value specified in the ! 908: DFLT_F entry. The function same performs this check. ! 909: If it is the same don't encode anything just return, ! 910: otherwise continue on and encode it. ! 911: ! 912: ETAG To handle explicit tags we merely allocate a PE with ! 913: the right tag and call en_etype to encode its contents, ! 914: which are in the following entries. The switch on the ! 915: pe_ucode field use to make a difference but now it is ! 916: meaningless and should be cleaned up. ! 917: ! 918: SEQ_START, SEQOF_START, SET_START, SETOF_START ! 919: ! 920: ! 921: ! 922: January 23, 1990 ! 923: ! 924: ! 925: ! 926: ! 927: ! 928: - 15 - ! 929: ! 930: ! 931: We merely call the appropriate function handle them. ! 932: Note one _i_m_p_o_r_t_a_n_t difference in the way they are ! 933: called here from that in enc_obj, the parm arguement is ! 934: used as a base to index off and fetch a new pointer to ! 935: pass the next function. This seemly bizarre action is ! 936: quite straight forward when seen written as it is nor- ! 937: mally in C, "parm->offset". Where the field offset is ! 938: a pointer which has an offset from the start of the ! 939: structure of p->pe_ucode bytes. ! 940: ! 941: This is the magic of how we access all the different ! 942: fields of the C data structures with the one piece of code. ! 943: It is also prehaps the most critical dependency of the whole ! 944: system on the implementation of the C language. As the BGNU ! 945: C compiler supports this feature then it is compilerable on ! 946: most machines. But any porters should pay attention to this ! 947: to ensure that thier compiler is happy generating these ! 948: offsets and compiling these casts properly. ! 949: ! 950: The reason why this is different from the calls in ! 951: en_obj is that this is not the first compound type in the ! 952: table. The first and only the first does not have an offset ! 953: and does not need to be indirected through any pointers. ! 954: All the compound types inside this type will have as their ! 955: field a pointer which points to a structure. From here on ! 956: we shall say _i_n_d_i_r_e_c_t_i_o_n to mean this adding the pe_ucode ! 957: field to the pointer to the structure and using it to refer- ! 958: ence a pointer. Whether to use _i_n_d_i_r_e_c_t_i_o_n or not is very ! 959: important matter that really needs to be understood to ! 960: understand how the routines are structured. ! 961: ! 962: IMP_OBJ ! 963: Here we have to handle the case where we can encode the ! 964: object then have to change its tag and class after ! 965: encoding. At the end of this entry this is done very ! 966: simply by assigning the right values to the appropriate ! 967: fields after the object has been built. This means ! 968: that if the intermeadiate form is altered this piece of ! 969: code may have to be altered as well. There seems to be ! 970: no better way of handling this. ! 971: ! 972: The complication in handling this field is the handling ! 973: of all the possible types of object. If it is an external ! 974: object we have to perform a call to enc_f with all the right ! 975: arguements where a normal OBJECT, the last else branch, ! 976: requires a normal call to en_obj. Note the case of SOBJECT ! 977: is 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. ! 978: ! 979: SOBJECT and OBJECT ! 980: Here is the code that handles the two cases sperately. ! 981: It is exactly as in the IMP_OBJ case except seperated ! 982: out. Note the only difference between the two cases is ! 983: lack of indirection in the SOBJECT case. ! 984: ! 985: ! 986: ! 987: ! 988: January 23, 1990 ! 989: ! 990: ! 991: ! 992: ! 993: ! 994: - 16 - ! 995: ! 996: ! 997: CHOICE_START ! 998: This is exactly as all other compound types, like ! 999: SEQ_START and OBJECT, we call the appropriate routine ! 1000: with indirection. From reading the ISODE manuals that ! 1001: the ASN.1 CHOICE type is handled by a structure of its ! 1002: own like the other compund types. ! 1003: ! 1004: EXTOBJ and SEXTOBJ ! 1005: ! 1006: ! 1007: ! 1008: ! 1009: ! 1010: ! 1011: ! 1012: ! 1013: ! 1014: ! 1015: ! 1016: ! 1017: ! 1018: ! 1019: ! 1020: ! 1021: ! 1022: ! 1023: ! 1024: ! 1025: ! 1026: ! 1027: ! 1028: ! 1029: ! 1030: ! 1031: ! 1032: ! 1033: ! 1034: ! 1035: ! 1036: ! 1037: ! 1038: ! 1039: ! 1040: ! 1041: ! 1042: ! 1043: ! 1044: ! 1045: ! 1046: ! 1047: ! 1048: ! 1049: ! 1050: ! 1051: ! 1052: ! 1053: ! 1054: January 23, 1990 ! 1055: ! 1056:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.