X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=doc%2Fodr.xml;h=6438e6f6c3d2d722b2a626f8a5d317150591c68f;hp=8b1cc4f8faf5ddf8663a3b0665dc8accfc878fb4;hb=053367cbe356fb3ce0def34b065dae589d700daf;hpb=ec1f815d5348cd21e393f76bc212c910c34bbc45 diff --git a/doc/odr.xml b/doc/odr.xml index 8b1cc4f..6438e6f 100644 --- a/doc/odr.xml +++ b/doc/odr.xml @@ -1,6 +1,5 @@ - The ODR Module - + Introduction @@ -13,19 +12,19 @@ If you are only interested in writing a Z39.50 implementation based on the PDUs that are already provided with &yaz;, you only need to concern - yourself with the section on managing ODR streams (section - Using ODR). Only if you need to + yourself with the section on managing ODR streams + (). Only if you need to implement ASN.1 beyond that which has been provided, should you worry about the second half of the documentation - (section Programming with ODR). + (). If you use one of the higher-level interfaces, you can skip this section entirely. This is important, so we'll repeat it for emphasis: You do - not need to read section Programming with - ODR to implement Z39.50 with &yaz;. + not need to read + to implement Z39.50 with &yaz;. @@ -37,9 +36,9 @@ - Using ODR + Using ODR - ODR Streams + ODR Streams Conceptually, the ODR stream is the source of encoded data in the @@ -74,7 +73,7 @@ - Memory Management + Memory Management Two forms of memory management take place in the &odr; system. The first @@ -95,7 +94,7 @@ - void *odr_malloc(ODR o, int size); + void *odr_malloc(ODR o, size_t size); @@ -105,7 +104,7 @@ - void odr_reset(ODR o, int size); + void odr_reset(ODR o); @@ -121,7 +120,7 @@ - int odr_total(ODR o); + size_t odr_total(ODR o); @@ -169,7 +168,7 @@ - Encoding and Decoding Data + Encoding and Decoding Data When encoding data, the ODR stream will write the encoded octet string @@ -260,15 +259,14 @@ z_APDU()). - - Examples of encoding/decoding functions: - - - - int odr_integer(ODR o, int **p, int optional, const char *name); + + Encoding and decoding functions + + int odr_integer(ODR o, Odr_int **p, int optional, const char *name); - int z_APDU(ODR o, Z_APDU **p, int optional, const char *name); - + int z_APDU(ODR o, Z_APDU **p, int optional, const char *name); + + If the data is absent (or doesn't match the tag corresponding to @@ -295,69 +293,122 @@ free(2) to release the memory. You can decode several data elements (by repeated calls to odr_setbuf() and your decoding function), and - new memory will be allocated each time. When you do call + new memory will be allocated each time. When you do call odr_reset(), everything decoded since the last call to odr_reset() will be released. - - The use of the double indirection can be a little confusing at first - (its purpose will become clear later on, hopefully), - so an example is in order. We'll encode an integer value, and - immediately decode it again using a different stream. A useless, but - informative operation. - - - - -void do_nothing_useful(int value) + + Encoding and decoding of an integer + + The use of the double indirection can be a little confusing at first + (its purpose will become clear later on, hopefully), + so an example is in order. We'll encode an integer value, and + immediately decode it again using a different stream. A useless, but + informative operation. + + +]]> + + + This looks like a lot of work, offhand. In practice, the &odr; streams + will typically be allocated once, in the beginning of your program + (or at the beginning of a new network session), and the encoding + and decoding will only take place in a few, isolated places in your + program, so the overhead is quite manageable. + + + + + Printing - This looks like a lot of work, offhand. In practice, the &odr; streams - will typically be allocated once, in the beginning of your program - (or at the beginning of a new network session), and the encoding - and decoding will only take place in a few, isolated places in your - program, so the overhead is quite manageable. + When an ODR stream is created of type ODR_PRINT + the ODR module will print the contents of a PDU in a readable format. + By default output is written to the stderr stream. + This behavior can be changed, however, by calling the function + + odr_setprint(ODR o, FILE *file); + + before encoders or decoders are being invoked. + It is also possible to direct the output to a buffer (of indeed + another file), by using the more generic mechanism: + + void odr_set_stream(ODR o, void *handle, + void (*stream_write)(ODR o, void *handle, int type, + const char *buf, int len), + void (*stream_close)(void *handle)); + + Here the user provides an opaque handle and two handlers, + stream_write for writing, + and stream_close which is supposed + to close/free resources associated with handle. + The stream_close handler is optional and + if NULL for the function is provided, it will not be invoked. + The stream_write takes the ODR handle + as parameter, the user defined handle, a type + ODR_OCTETSTRING, ODR_VISIBLESTRING + which indicates the type of contents is being written. - + + Another utility useful for diagnostics (error handling) or as + part of the printing facilities is: + + const char **odr_get_element_path(ODR o); + + which returns a list of current elements that ODR deals with at the + moment. For the returned array, say ar, + ar[0] is the top level element, + ar[n] is the last. The last element has the + property that ar[n+1] == NULL. + + + Element Path for record + + For a database record part of a PresentResponse the + array returned by odr_get_element + is presentResponse, databaseOrSurDiagnostics, ?, record, ?, databaseRecord . The question mark appears due to + unnamed constructions. + + - - Diagnostics + Diagnostics The encoding/decoding functions all return 0 when an error occurs. @@ -391,7 +442,8 @@ void do_nothing_useful(int value) one of these constants: - ODR Error codes +
+ ODR Error codes @@ -440,7 +492,7 @@ void do_nothing_useful(int value) - char *odr_errlist[] + char *odr_errlist[] @@ -449,10 +501,11 @@ void do_nothing_useful(int value) - Summary and Synopsis + + Summary and Synopsis - #include <odr.h> + #include <yaz/odr.h> ODR odr_createmem(int direction); @@ -460,19 +513,17 @@ void do_nothing_useful(int value) void odr_reset(ODR o); - char *odr_getbuf(ODR o, int *len); + char *odr_getbuf(ODR o, int *len, int *size); - void odr_setbuf(ODR o, char *buf, int len); + void odr_setbuf(ODR o, char *buf, int len, int can_grow); void *odr_malloc(ODR o, int size); - ODR_MEM odr_extract_mem(ODR o); - - void odr_release_mem(ODR_MEM r); + NMEM odr_extract_mem(ODR o); int odr_geterror(ODR o); - void odr_perror(char *message); + void odr_perror(ODR o, const char *message); extern char *odr_errlist[]; @@ -480,7 +531,7 @@ void do_nothing_useful(int value) - Programming with ODR + Programming with ODR The API of &odr; is designed to reflect the structure of ASN.1, rather @@ -488,9 +539,18 @@ void do_nothing_useful(int value) other external forms. + + + There is an ASN.1 tutorial available at + this site. + This site also has standards for ASN.1 (X.680) and BER (X.690) + online. + + + - The interface is based loosely on that of the Sun Microsystems XDR - routines. + The ODR interface is based loosely on that of the Sun Microsystems + XDR routines. Specifically, each function which corresponds to an ASN.1 primitive type has a dual function. Depending on the settings of the ODR stream which is supplied as a parameter, the function may be used @@ -500,7 +560,7 @@ void do_nothing_useful(int value) definition for a type once - and you have the functionality of encoding, decoding (and pretty-printing) all in one unit. The resulting C source code is quite compact, and is a pretty - straightforward representation of the source ASN.1 specification. + straightforward representation of the source ASN.1 specification. @@ -510,14 +570,15 @@ void do_nothing_useful(int value) SEQUENCE members which don't exist in XDR. - The Primitive ASN.1 Types + + The Primitive ASN.1 Types ASN.1 defines a number of primitive types (many of which correspond roughly to primitive types in structured programming languages, such as C). - INTEGER + INTEGER The &odr; function for encoding or decoding (or printing) the ASN.1 @@ -525,11 +586,11 @@ void do_nothing_useful(int value) -int odr_integer(ODR o, int **p, int optional, const char *name); + int odr_integer(ODR o, Odr_int **p, int optional, const char *name); - (we don't allow values that can't be contained in a C integer.) + The Odr_int is just a simple integer. @@ -575,24 +636,24 @@ int odr_integer(ODR o, int **p, int optional, const char *name); similar manners: - BOOLEAN + BOOLEAN -int odr_bool(ODR o, bool_t **p, int optional, const char *name); +int odr_bool(ODR o, Odr_bool **p, int optional, const char *name); - REAL + REAL Not defined. - NULL + NULL -int odr_null(ODR o, bool_t **p, int optional, const char *name); +int odr_null(ODR o, Odr_null **p, int optional, const char *name); @@ -602,14 +663,13 @@ int odr_null(ODR o, bool_t **p, int optional, const char *name); - OCTET STRING + OCTET STRING typedef struct odr_oct { unsigned char *buf; int len; - int size; } Odr_oct; int odr_octetstring(ODR o, Odr_oct **p, int optional, @@ -619,8 +679,7 @@ int odr_octetstring(ODR o, Odr_oct **p, int optional, The buf field should point to the character array that holds the octetstring. The len field holds the - actual length, while the size field gives the size - of the allocated array (not of interest to you, in most cases). + actual length. The character array need not be null terminated. @@ -649,7 +708,7 @@ int odr_visiblestring(ODR o, char **p, int optional, - BIT STRING + BIT STRING int odr_bitstring(ODR o, Odr_bitmask **p, int optional, @@ -687,7 +746,7 @@ int ODR_MASK_GET(Odr_bitmask *b, int bitno); - OBJECT IDENTIFIER + OBJECT IDENTIFIER int odr_oid(ODR o, Odr_oid **p, int optional, const char *name); @@ -696,19 +755,19 @@ int odr_oid(ODR o, Odr_oid **p, int optional, const char *name); The C OID representation is simply an array of integers, terminated by the value -1 (the Odr_oid type is synonymous with - the int type). - We suggest that you use the OID database module (see section - Object Identifiers) to handle object identifiers + the short type). + We suggest that you use the OID database module (see + ) to handle object identifiers in your application. - Tagging Primitive Types + Tagging Primitive Types The simplest way of tagging a type is to use the - odr_implicit_tag() or + odr_implicit_tag() or odr_explicit_tag() macros: @@ -726,7 +785,7 @@ int odr_explicit_tag(ODR o, Odr_fun fun, int class, int tag, - MyInt ::= [210] IMPLICIT INTEGER + MyInt ::= [210] IMPLICIT INTEGER @@ -734,7 +793,7 @@ int odr_explicit_tag(ODR o, Odr_fun fun, int class, int tag, -int myInt(ODR o, int **p, int optional, const char *name) +int myInt(ODR o, Odr_int **p, int optional, const char *name) { return odr_implicit_tag(o, odr_integer, p, ODR_CONTEXT, 210, optional, name); @@ -755,7 +814,7 @@ int myInt(ODR o, int **p, int optional, const char *name) - Constructed Types + Constructed Types Constructed types are created by combining primitive types. The @@ -806,10 +865,10 @@ MySequence ::= SEQUENCE { typedef struct MySequence { - int *intval; - bool_t *boolval; + Odr_int *intval; + Odr_bool *boolval; } MySequence; - + int mySequence(ODR o, MySequence **p, int optional, const char *name) { if (odr_sequence_begin(o, p, sizeof(**p), name) == 0) @@ -842,24 +901,25 @@ int mySequence(ODR o, MySequence **p, int optional, const char *name) - Tagging Constructed Types + + Tagging Constructed Types - See section Tagging Primitive types - for information on how to tag the primitive types, as well as types - that are already defined. + See for information on how to tag + the primitive types, as well as types that are already defined. - Implicit Tagging + + Implicit Tagging Assume the type above had been defined as -MySequence ::= [10] IMPLICIT SEQUENCE { +MySequence ::= [10] IMPLICIT SEQUENCE { intval INTEGER, boolval BOOLEAN OPTIONAL } @@ -900,7 +960,7 @@ int mySequence(ODR o, MySequence **p, int optional, const char *name) - Explicit Tagging + Explicit Tagging Explicit tagging of constructed types is a little more complicated, @@ -912,7 +972,7 @@ int mySequence(ODR o, MySequence **p, int optional, const char *name) -MySequence ::= [10] IMPLICIT SEQUENCE { +MySequence ::= [10] IMPLICIT SEQUENCE { intval INTEGER, boolval BOOLEAN OPTIONAL } @@ -975,7 +1035,7 @@ int mySequence(ODR o, MySequence **p, int optional, const char *name) - SEQUENCE OF + SEQUENCE OF To handle sequences (arrays) of a specific type, the function @@ -1009,7 +1069,7 @@ MyArray ::= SEQUENCE OF INTEGER typedef struct MyArray { int num_elements; - int **elements; + Odr_int **elements; } MyArray; @@ -1031,7 +1091,7 @@ int myArray(ODR o, MyArray **p, int optional, const char *name) - CHOICE Types + CHOICE Types The choice type is used fairly often in some ASN.1 definitions, so @@ -1043,7 +1103,7 @@ int myArray(ODR o, MyArray **p, int optional, const char *name) -int odr_choice(ODR o, Odr_arm arm[], void *p, void *whichp, +int odr_choice(ODR o, Odr_arm arm[], void *p, void *whichp, const char *name); @@ -1088,7 +1148,7 @@ typedef struct odr_arm which The value of the discriminator that corresponds to - this CHOICE element. Typically, it will be a #defined constant, or + this CHOICE element. Typically, it will be a #defined constant, or an enum member. @@ -1113,7 +1173,7 @@ typedef struct odr_arm MyChoice ::= CHOICE { untagged INTEGER, - tagged [99] IMPLICIT INTEGER, + tagged [99] IMPLICIT INTEGER, other BOOLEAN } @@ -1133,9 +1193,9 @@ typedef struct MyChoice } which; union { - int *untagged; - int *tagged; - bool_t *other; + Odr_int *untagged; + Odr_int *tagged; + Odr_bool *other; } u; }; @@ -1147,7 +1207,7 @@ typedef struct MyChoice int myChoice(ODR o, MyChoice **p, int optional, const char *name) { - static Odr_arm arm[] = + static Odr_arm arm[] = { {-1, -1, -1, MyChoice_untagged, odr_integer, "untagged"}, {ODR_IMPLICIT, ODR_CONTEXT, 99, MyChoice_tagged, odr_integer,