source: trunk/gsdl/packages/yaz/doc/yaz-5.html@ 1343

Last change on this file since 1343 was 1343, checked in by johnmcp, 24 years ago

Added the YAZ toolkit source to the packages directory (for z39.50 stuff)

  • Property svn:keywords set to Author Date Id Revision
File size: 35.1 KB
Line 
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
2<HTML>
3<HEAD>
4 <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
5 <TITLE>YAZ User's Guide and Reference: The ODR Module</TITLE>
6 <LINK HREF="yaz-6.html" REL=next>
7 <LINK HREF="yaz-4.html" REL=previous>
8 <LINK HREF="yaz.html#toc5" REL=contents>
9</HEAD>
10<BODY>
11<A HREF="yaz-6.html">Next</A>
12<A HREF="yaz-4.html">Previous</A>
13<A HREF="yaz.html#toc5">Contents</A>
14<HR>
15<H2><A NAME="odr"></A> <A NAME="s5">5. The ODR Module</A></H2>
16
17<H2><A NAME="ss5.1">5.1 Introduction</A>
18</H2>
19
20<P><B>ODR</B> is the BER-encoding/decoding subsystem of <B>YAZ</B>. Care as been taken
21to isolate <B>ODR</B> from the rest of the package - specifically from the
22transport interface. <B>ODR</B> may be used in any context where basic
23ASN.1/BER representations are used.
24<P>If you are only interested in writing a Z39.50 implementation based on
25the PDUs that are already provided with <B>YAZ</B>, you only need to concern
26yourself with the section on managing ODR streams (section
27<A HREF="#odr-use">Using ODR</A>). Only if you need to
28implement ASN.1 beyond that which has been provided, should you
29worry about the second half of the documentation
30(section
31<A HREF="#odr-prog">Programming with ODR</A>). If you use
32one of the higher-level interfaces, you can skip this section entirely.
33<P>This is important, so we'll repeat it for emphasis: <I>You do not
34need to read section
35<A HREF="#odr-prog">Programming with ODR</A> to
36implement Z39.50 with <B>YAZ</B>.</I>
37<P>If you need a part of the protocol that isn't already in <B>YAZ</B>, you
38should
39contact the authors before going to work on it yourself: We
40might already be working on it. Conversely, if you implement a useful
41part of the protocol before us, we'd be happy to include it in a
42future release.
43<P>
44<H2><A NAME="odr-use"></A> <A NAME="ss5.2">5.2 Using ODR</A>
45</H2>
46
47<P>
48<H3>ODR Streams</H3>
49
50<P>Conceptually, the ODR stream is the source of encoded data in the
51decoding mode; when encoding, it is the receptacle for the encoded
52data. Before you can use an ODR stream it must be allocated. This is
53done with the function
54<P>
55<BLOCKQUOTE><CODE>
56<PRE>
57ODR odr_createmem(int direction);
58</PRE>
59</CODE></BLOCKQUOTE>
60<P>The <CODE>odr_createmem()</CODE> function takes as argument one of three manifest
61constants: <CODE>ODR_ENCODE</CODE>, <CODE>ODR_DECODE</CODE>, or <CODE>ODR_PRINT</CODE>. An
62ODR stream can be
63in only one mode - it is not possible to change its mode once it's
64selected. Typically, your program will allocate at least two ODR
65streams - one for decoding, and one for encoding.
66<P>When you're done with the stream, you can use
67<P>
68<BLOCKQUOTE><CODE>
69<PRE>
70void odr_destroy(ODR o);
71</PRE>
72</CODE></BLOCKQUOTE>
73<P>to release the resources allocated for the stream.
74<P>
75<H3><A NAME="memory"></A> Memory Management</H3>
76
77<P>Two forms of memory management take place in the ODR system. The first
78one, which has to do with allocating little bits of memory (sometimes
79quite large bits of memory, actually) when a protocol package is
80decoded, and turned into a complex of interlinked structures. This
81section deals with this system, and how you can use it for your own
82purposes. The next section deals with the memory management which is
83required when encoding data - to make sure that a large enough buffer is
84available to hold the fully encoded PDU.
85<P>The <B>ODR</B> module has its own memory management system, which is
86used whenever memory is required. Specifically, it is used to allocate
87space for data when decoding incoming PDUs. You can use the memory
88system for your own purposes, by using the function
89<P>
90<BLOCKQUOTE><CODE>
91<PRE>
92void *odr_malloc(ODR o, int size);
93</PRE>
94</CODE></BLOCKQUOTE>
95<P>You can't use the normal <CODE>free</CODE>(2) routine to free memory allocated
96by this function, and <B>ODR</B> doesn't provide a parallel function. Instead,
97you can call
98<P>
99<BLOCKQUOTE><CODE>
100<PRE>
101void odr_reset(ODR o, int size);
102</PRE>
103</CODE></BLOCKQUOTE>
104<P>when you are done with the
105memory: Everything allocated since the last call to <CODE>odr_reset()</CODE> is
106released. The <CODE>odr_reset()</CODE> call is also required to clear up an
107error condition on a stream.
108<P>The function
109<P>
110<BLOCKQUOTE><CODE>
111<PRE>
112int odr_total(ODR o);
113</PRE>
114</CODE></BLOCKQUOTE>
115<P>returns the number of bytes allocated on the stream since the last call to
116<CODE>odr_reset()</CODE>.
117<P>The memory subsystem of <B>ODR</B> is fairly efficient at allocating and
118releasing little bits of memory. Rather than managing the individual,
119small bits of space, the system maintains a freelist of larger chunks
120of memory, which are handed out in small bits. This scheme is
121generally known as a <I>nibble memory</I> system. It is very useful for
122maintaing short-lived constructions such as protocol PDUs.
123<P>If you want to retain a bit of memory beyond the next call to
124<CODE>odr_reset()</CODE>, you can use the function
125<P>
126<BLOCKQUOTE><CODE>
127<PRE>
128ODR_MEM odr_extract_mem(ODR o);
129</PRE>
130</CODE></BLOCKQUOTE>
131<P>This function will give you control of the memory recently allocated
132on the ODR stream. The memory will live (past calls to <CODE>odr_reset()</CODE>),
133until you call the function
134<P>
135<BLOCKQUOTE><CODE>
136<PRE>
137void odr_release_mem(ODR_MEM p);
138</PRE>
139</CODE></BLOCKQUOTE>
140<P>The opaque <CODE>ODR_MEM</CODE> handle has no other purpose than referencing
141the memory block for you until you want to release it.
142<P>You can use <CODE>odr_extract_mem()</CODE> repeatedly between allocating data,
143to retain individual control of separate chunks of data.
144<P>
145<H3>Encoding and Decoding Data</H3>
146
147<P>When encoding data, the ODR stream will write the encoded octet string
148in an internal buffer. To retrieve the data, use the function
149<P>
150<BLOCKQUOTE><CODE>
151<PRE>
152char *odr_getbuf(ODR o, int *len, int *size);
153</PRE>
154</CODE></BLOCKQUOTE>
155<P>The integer pointed to by len is set to the length of the encoded
156data, and a pointer to that data is returned. *<CODE>size</CODE> is set to the size
157of the buffer (unless <CODE>size</CODE> is null, signalling that you are
158not interested in the size). The next call to a primitive function
159using the same ODR stream will overwrite the data, unless a different
160buffer has been supplied using the call
161<P>
162<BLOCKQUOTE><CODE>
163<PRE>
164void odr_setbuf(ODR o, char *buf, int len, int can_grow);
165</PRE>
166</CODE></BLOCKQUOTE>
167<P>which sets the encoding (or decoding) buffer used by <CODE>o</CODE> to
168<CODE>buf</CODE>,
169using the length <CODE>len</CODE>. Before a call to an encoding function,
170you can use <CODE>odr_setbuf()</CODE> to provide the stream with an encoding buffer
171of sufficient size (length). The <CODE>can_grow</CODE> parameter tells the encoding
172ODR stream whether it is allowed to use <CODE>realloc</CODE>(2) to increase the size
173of the buffer when necessary. The default condition of a new encoding
174stream is equivalent to the results of calling
175<P>
176<BLOCKQUOTE><CODE>
177<PRE>
178odr_setbuf(stream, 0, 0, 1);
179</PRE>
180</CODE></BLOCKQUOTE>
181<P>In this case, the stream will allocate and reallocate memory as
182necessary. The stream reallocates memory by repeatedly doubling the
183size of the buffer - the result is that the buffer will typically
184reach its maximum, working size with only a small number of reallocation
185operations. The memory is freed by the stream when the latter is destroyed,
186unless it was assigned by the user with the <CODE>can_grow</CODE>
187parameter set to zero (in this case, you are expected to retain
188control of the memory yourself).
189<P>To assume full control of an encoded buffer, you must first call
190<CODE>odr_getbuf()</CODE> to fetch the buffer and its length. Next, you should
191call <CODE>odr_setbuf()</CODE> to provide a different buffer (or a null
192pointer) to the stream. In the simplest case, you will reuse the same
193buffer over and over again, and you will just need to call
194<CODE>odr_getbuf()</CODE> after each encoding operation to get the length and
195address of the buffer. Note that the stream may reallocate the buffer
196during an encoding operation, so it is necessary to retrieve the
197correct address after each encoding operation.
198<P>It is important to realise that the ODR stream will not release this
199memory when you call <CODE>odr_reset()</CODE>: It will merely update its
200internal pointers to prepare for the encoding of a new data value.
201When the stream is released by the <CODE>odr_destroy()</CODE> function, the
202memory given to it by odr_setbuf will be released <I>only</I> if the
203<CODE>can_grow</CODE> parameter to <CODE>odr_setbuf()</CODE> was nonzero. The
204<CODE>can_grow</CODE> parameter, in other words, is a way of signalling who
205is to own the buffer, you or the ODR stream. If you never call
206<CODE>odr_setbuf()</CODE> on your encoding stream, which is typically the
207case, the buffer allocated by the stream will belong to the stream by
208default.
209<P>When you wish to decode data, you should first call <CODE>odr_setbuf()</CODE>, to
210tell the decoding stream where to find the encoded data, and how long
211the buffer is (the <CODE>can_grow</CODE> parameter is ignored by a decoding
212stream). After this, you can call the function corresponding to the
213data you wish to decode (eg, <CODE>odr_integer()</CODE> odr <CODE>z_APDU()</CODE>).
214<P>Examples of encoding/decoding functions:
215<P>
216<BLOCKQUOTE><CODE>
217<PRE>
218int odr_integer(ODR o, int **p, int optional, const char *name);
219
220int z_APDU(ODR o, Z_APDU **p, int optional, const char *name);
221</PRE>
222</CODE></BLOCKQUOTE>
223<P>If the data is absent (or
224doesn't match the tag corresponding to the type), the return value
225will be either 0 or 1 depending on the <CODE>optional</CODE> flag. If
226<CODE>optional</CODE>
227is 0 and the data is absent, an error flag will be raised in the
228stream, and you'll need to call <CODE>odr_reset()</CODE> before you can use the
229stream again. If <CODE>optional</CODE> is nonzero, the pointer <I>pointed to</I> by
230<CODE>p</CODE> will be set to the null value, and the function will return 1.
231The <CODE>name</CODE> argument is used to pretty-print the tag in question.
232It may be set to <CODE>NULL</CODE> if pretty-printing is not desired.
233<P>If the data value is found where it's expected, the pointer
234<I>pointed to</I> by the <CODE>p</CODE> argument will be set to point to the
235decoded type. The
236space for the type will be allocated and owned by the ODR stream, and
237it will live until you call <CODE>odr_reset()</CODE> on the stream. You cannot use
238<CODE>free</CODE>(2) to release the memory. You can decode several data elements
239(by repeated calls to <CODE>odr_setbuf()</CODE> and your decoding function), and
240new memory will be allocated each time. When you do call
241<CODE>odr_reset()</CODE>,
242everything decoded since the last call to <CODE>odr_reset()</CODE> will be
243released.
244<P>The use of the double indirection can be a little confusing at first
245(its purpose will become clear later on, hopefully),
246so an example is in order. We'll encode an integer value, and
247immediately decode it again using a different stream. A useless, but
248informative operation.
249<P>
250<BLOCKQUOTE><CODE>
251<PRE>
252void do_nothing_useful(int value)
253{
254 ODR encode, decode;
255 int *valp, *resvalp;
256 char *bufferp;
257 int len;
258
259 /* allocate streams */
260 if (!(encode = odr_createmem(ODR_ENCODE)))
261 return;
262 if (!(decode = odr_createmem(ODR_DECODE)))
263 return;
264
265 valp = &amp;value;
266 if (odr_integer(encode, &amp;valp, 0, 0) == 0)
267 {
268 printf("encoding went bad\n");
269 return;
270 }
271 bufferp = odr_getbuf(encode, &amp;len);
272 printf("length of encoded data is %d\n", len);
273
274 /* now let's decode the thing again */
275 odr_setbuf(decode, bufferp, len);
276 if (odr_integer(decode, &amp;resvalp, 0, 0) == 0)
277 {
278 printf("decoding went bad\n");
279 return;
280 }
281 printf("the value is %d\n", *resvalp);
282
283 /* clean up */
284 odr_destroy(encode);
285 odr_destroy(decode);
286}
287</PRE>
288</CODE></BLOCKQUOTE>
289<P>This looks like a lot of work, offhand. In practice, the ODR streams
290will typically be allocated once, in the beginning of your program (or at the
291beginning of a new network session), and the encoding and decoding
292will only take place in a few, isolated places in your program, so the
293overhead is quite manageable.
294<P>
295<H3>Diagnostics</H3>
296
297<P>The encoding/decoding functions all return 0 when an error occurs.
298Until you call <CODE>odr_reset()</CODE>, you cannot use the stream again, and
299any function called will immediately return 0.
300<P>To provide information to the programmer or administrator, the
301function
302<P>
303<BLOCKQUOTE><CODE>
304<PRE>
305void odr_perror(ODR o, char *message);
306</PRE>
307</CODE></BLOCKQUOTE>
308<P>is provided, which prints the <CODE>message</CODE> argument to <CODE>stderr</CODE>
309along with an error message from the stream.
310<P>You can also use the function
311<P>
312<BLOCKQUOTE><CODE>
313<PRE>
314int odr_geterror(ODR o);
315</PRE>
316</CODE></BLOCKQUOTE>
317<P>to get the current error number from the screen. The number will be
318one of these constants:
319<P>
320<DL>
321<DT><B>OMEMORY</B><DD><P>Memory allocation failed.
322<DT><B>OSYSERR</B><DD><P>A system- or library call has failed. The standard
323diagnostic variable <CODE>errno</CODE>
324should be examined to determine the actual error.
325<DT><B>OSPACE</B><DD><P>No more space for encoding. This will only occur when the user has
326explicitly provided a buffer for an encoding stream without allowing
327the system to allocate more space.
328<DT><B>OREQUIRED</B><DD><P>This is a common protocol error; A required data element was
329missing during
330encoding or decoding.
331<DT><B>OUNEXPECTED</B><DD><P>An unexpected data element was found during decoding.
332<DT><B>OOTHER</B><DD><P>Other error. This is typically an indication of misuse of
333the <B>ODR</B> system by the programmer, and also that the diagnostic
334system isn't as good as it should be, yet.
335</DL>
336<P>The character string array
337<P>
338<BLOCKQUOTE><CODE>
339<PRE>
340char *odr_errlist[]
341</PRE>
342</CODE></BLOCKQUOTE>
343<P>can be indexed by the error code to obtain a human-readable
344representation of the problem.
345<P>
346<H3>Summary and Synopsis</H3>
347
348<P>
349<BLOCKQUOTE><CODE>
350<PRE>
351#include &lt;odr.h>
352
353ODR odr_createmem(int direction);
354
355void odr_destroy(ODR o);
356
357void odr_reset(ODR o);
358
359char *odr_getbuf(ODR o, int *len);
360
361void odr_setbuf(ODR o, char *buf, int len);
362
363void *odr_malloc(ODR o, int size);
364
365ODR_MEM odr_extract_mem(ODR o);
366
367void odr_release_mem(ODR_MEM r);
368
369int odr_geterror(ODR o);
370
371void odr_perror(char *message);
372
373extern char *odr_errlist[];
374</PRE>
375</CODE></BLOCKQUOTE>
376<P>
377<H2><A NAME="odr-prog"></A> <A NAME="ss5.3">5.3 Programming with ODR</A>
378</H2>
379
380<P>The API of <B>ODR</B> is designed to reflect the structure of ASN.1, rather
381than BER itself. Future releases may be able to represent data in
382other external forms.
383<P>The interface is based loosely on that of the Sun Microsystems XDR routines.
384Specifically, each function which corresponds to an ASN.1 primitive
385type has a dual function. Depending on the settings of the ODR
386stream which is supplied as a parameter, the function may be used
387either to encode or decode data. The functions that can be built
388using these primitive functions, to represent more complex datatypes, share
389this quality. The result is that you only have to enter the definition
390for a type once - and you have the functionality of encoding, decoding
391(and pretty-printing) all in one unit. The resulting C source code is
392quite compact, and is a pretty straightforward representation of the
393source ASN.1 specification. Although no ASN.1 compiler is supplied
394with <B>ODR</B> at this time, it shouldn't be too difficult to write one, or
395perhaps even to adapt an existing compiler to output <B>ODR</B> routines
396(not surprisingly, writing encoders/decoders using <B>ODR</B> turns out
397to be boring work).
398<P>In many cases, the model of the XDR functions works quite well in this
399role. In
400others, it is less elegant. Most of the hassle comes from the optional
401SEQUENCE memebers which don't exist in XDR.
402<P>
403<H3>The Primitive ASN.1 Types</H3>
404
405<P>ASN.1 defines a number of primitive types (many of which correspond
406roughly to
407primitive types in structured programming languages, such as C).
408<P>
409<H3>INTEGER</H3>
410
411<P>The <B>ODR</B> function for encoding or decoding (or printing) the ASN.1
412INTEGER type looks like this:
413<P>
414<BLOCKQUOTE><CODE>
415<PRE>
416int odr_integer(ODR o, int **p, int optional, const char *name);
417</PRE>
418</CODE></BLOCKQUOTE>
419<P>(we don't allow values that can't be contained in a C integer.)
420<P>This form is typical of the primitive <B>ODR</B> functions. They are named
421after the type of data that they encode or decode. They take an
422ODR
423stream, an indirect reference to the type in question, and an
424<CODE>optional</CODE> flag (corresponding to the OPTIONAL keyword of ASN.1) as
425parameters. They all return an integer value of either one or zero.
426When you use the primitive functions to construct encoders for complex
427types of your own, you should follow this model as well. This
428ensures that your new types can be reused as elements in yet more
429complex types.
430<P>The <CODE>o</CODE> parameter should obviously refer to a properly
431initialized ODR
432stream of the right type (encoding/decoding/printing) for the
433operation that you wish to perform.
434<P>When encoding or printing, the function first looks at *<CODE>p</CODE>. If
435*<CODE>p</CODE> (the
436pointer pointed to by <CODE>p</CODE>) is a null pointer, this is taken to mean that
437the data element is absent. If the <CODE>optional</CODE> parameter is nonzero,
438the function will return one (signifying success) without any further
439processing. If the <CODE>optional</CODE> is zero, an internal error flag is
440set in the ODR stream, and the function will return 0. No further
441operations can be carried out on the stream without a call to
442the function <CODE>odr_reset()</CODE>.
443<P>If *<CODE>p</CODE> is not a null pointer, it is expected to point to an instance of
444the data type. The data will be subjected to the encoding rules, and
445the result will be placed in the buffer held by the ODR stream.
446<P>The other ASN.1 primitives have similar functions that operate in
447similar manners:
448<P>
449<H3>BOOLEAN</H3>
450
451<P>
452<BLOCKQUOTE><CODE>
453<PRE>
454int odr_bool(ODR o, bool_t **p, int optional, const char *name);
455</PRE>
456</CODE></BLOCKQUOTE>
457<P>
458<H3>REAL</H3>
459
460<P>Not defined.
461<P>
462<H3>NULL</H3>
463
464<P>
465<BLOCKQUOTE><CODE>
466<PRE>
467int odr_null(ODR o, bool_t **p, int optional, const char *name);
468</PRE>
469</CODE></BLOCKQUOTE>
470<P>In this case, the value of **p is not important. If *p is different
471from the null pointer, the null value is present, otherwise it's
472absent.
473<P>
474<H3>OCTET STRING</H3>
475
476<P>
477<BLOCKQUOTE><CODE>
478<PRE>
479typedef struct odr_oct
480{
481 unsigned char *buf;
482 int len;
483 int size;
484} Odr_oct;
485
486int odr_octetstring(ODR o, Odr_oct **p, int optional, const char *name);
487</PRE>
488</CODE></BLOCKQUOTE>
489<P>The <CODE>buf</CODE> field should point to the character array that holds the
490octetstring. The <CODE>len</CODE> field holds the actual length, while the
491<CODE>size</CODE>
492field gives the size of the allocated array (not of interest to you,
493in most cases). The character array need not be null terminated.
494<P>To make things a little easier, an alternative is given for string
495types that are not expected to contain embedded NULL characters (eg.
496VisibleString):
497<P>
498<BLOCKQUOTE><CODE>
499<PRE>
500int odr_cstring(ODR o, char **p, int optional, const char *name);
501</PRE>
502</CODE></BLOCKQUOTE>
503<P>Which encoded or decodes between OCTETSTRING representations and
504null-terminates C strings.
505<P>Functions are provided for the derived string types, eg:
506<P>
507<BLOCKQUOTE><CODE>
508<PRE>
509int odr_visiblestring(ODR o, char **p, int optional, const char *name);
510</PRE>
511</CODE></BLOCKQUOTE>
512<P>
513<H3>BIT STRING</H3>
514
515<P>
516<BLOCKQUOTE><CODE>
517<PRE>
518int odr_bitstring(ODR o, Odr_bitmask **p, int optional, const char *name);
519</PRE>
520</CODE></BLOCKQUOTE>
521<P>The opaque type <CODE>Odr_bitmask</CODE> is only suitable for holding relatively brief bit
522strings, eg. for options fields, etc. The constant
523<CODE>ODR_BITMASK_SIZE</CODE>
524multiplied by 8 gives the maximum possible number of bits.
525<P>A set of macros are provided for manipulating the
526<CODE>Odr_bitmask</CODE>
527type:
528<P>
529<BLOCKQUOTE><CODE>
530<PRE>
531void ODR_MASK_ZERO(Odr_bitmask *b);
532
533void ODR_MASK_SET(Odr_bitmask *b, int bitno);
534
535void ODR_MASK_CLEAR(Odr_bitmask *b, int bitno);
536
537int ODR_MASK_GET(Odr_bitmask *b, int bitno);
538</PRE>
539</CODE></BLOCKQUOTE>
540<P>The functions are modelled after the manipulation functions that
541accompany the <CODE>fd_set</CODE> type used by the <CODE>select</CODE>(2) call.
542<CODE>ODR_MASK_ZERO</CODE> should always be called first on a new bitmask, to
543initialize the bits to zero.
544<P>
545<H3>OBJECT IDENTIFIER</H3>
546
547<P>
548<BLOCKQUOTE><CODE>
549<PRE>
550int odr_oid(ODR o, Odr_oid **p, int optional, const char *name);
551</PRE>
552</CODE></BLOCKQUOTE>
553<P>The C OID represenation is simply an array of integers, terminated by
554the value -1 (the <CODE>Odr_oid</CODE> type is synonymous with the <CODE>int</CODE>
555type). We suggest that you use the OID database module (see section
556<A HREF="yaz-3.html#oid">Object Identifiers</A>) to handle object identifiers
557in your application.
558<P>
559<H3><A NAME="tag-prim"></A> Tagging Primitive Types</H3>
560
561<P>The simplest way of tagging a type is to use the <CODE>odr_implicit_tag()</CODE> or
562<CODE>odr_explicit_tag()</CODE> macros:
563<P>
564<BLOCKQUOTE><CODE>
565<PRE>
566int odr_implicit_tag(ODR o, Odr_fun fun, int class, int tag, int
567 optional, const char *name);
568
569int odr_explicit_tag(ODR o, Odr_fun fun, int class, int tag,
570 int optional, const char *name);
571</PRE>
572</CODE></BLOCKQUOTE>
573<P>To create a type derived from the integer type by implicit tagging, you
574might write:
575<P>
576<BLOCKQUOTE><CODE>
577<PRE>
578MyInt ::= [210] IMPLICIT INTEGER
579</PRE>
580</CODE></BLOCKQUOTE>
581<P>In the <B>ODR</B> system, this would be written like:
582<P>
583<BLOCKQUOTE><CODE>
584<PRE>
585int myInt(ODR o, int **p, int optional, const char *name)
586{
587 return odr_implicit_tag(o, odr_integer, p,
588 ODR_CONTEXT, 210, optional, name);
589}
590</PRE>
591</CODE></BLOCKQUOTE>
592<P>The function <CODE>myInt()</CODE> can then be used like any of the primitive
593functions provided by ODR. Note that the behavior of
594<CODE>odr_explicit()</CODE>
595and <CODE>odr_implicit()</CODE> macros act exactly the same as the functions they
596are applied to - they respond to error conditions, etc, in the same
597manner - they simply have three extra parameters. The class parameter may
598take one of the values: <CODE>ODR_CONTEXT</CODE>, <CODE>ODR_PRIVATE</CODE>,
599<CODE>ODR_UNIVERSAL</CODE>, or
600<CODE>ODR_APPLICATION</CODE>.
601<P>
602<H3>Constructed Types</H3>
603
604<P>Constructed types are created by combining primitive types. The
605<B>ODR</B>
606system only implements the SEQUENCE and SEQUENCE OF constructions
607(although adding the rest of the container types should be simple
608enough, if the need arises).
609<P>For implementing SEQUENCEs, the functions
610<P>
611<BLOCKQUOTE><CODE>
612<PRE>
613int odr_sequence_begin(ODR o, void *p, int size, const char *name);
614int odr_sequence_end(ODR o);
615</PRE>
616</CODE></BLOCKQUOTE>
617<P>are provided.
618<P>The <CODE>odr_sequence_begin()</CODE> function should be called in the beginning of a
619function that implements a SEQUENCE type. Its parameters are the
620<B>ODR</B>
621stream, a pointer (to a pointer to the type you're implementing), and
622the <CODE>size</CODE> of the type (typically a C structure). On encoding, it
623returns 1 if *<CODE>p</CODE> is a null pointer. The <CODE>size</CODE> parameter is ignored. On
624decoding, it returns 1 if the type is found in the data stream.
625<CODE>size</CODE>
626bytes of memory are allocated, and *<CODE>p</CODE> is set to point to this space.
627<CODE>odr_sequence_end()</CODE> is called at the end of the complex function. Assume
628that a type is defined like this:
629<P>
630<BLOCKQUOTE><CODE>
631<PRE>
632MySequence ::= SEQUENCE {
633 intval INTEGER,
634 boolval BOOLEAN OPTIONAL }
635</PRE>
636</CODE></BLOCKQUOTE>
637<P>The corresponding ODR encoder/decoder function and the associated data
638structures could be written like this:
639<P>
640<BLOCKQUOTE><CODE>
641<PRE>
642typedef struct MySequence
643{
644 int *intval;
645 bool_t *boolval;
646} MySequence;
647
648int mySequence(ODR o, MySequence **p, int optional, const char *name)
649{
650 if (odr_sequence_begin(o, p, sizeof(**p), name) == 0)
651 return optional &amp;&amp; odr_ok(o);
652 return
653 odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
654 odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
655 odr_sequence_end(o);
656}
657</PRE>
658</CODE></BLOCKQUOTE>
659<P>Note the 1 in the call to <CODE>odr_bool()</CODE>, to mark that the sequence
660member is optional. If either of the member types had been tagged, the
661macros <CODE>odr_implicit()</CODE> or <CODE>odr_explicit()</CODE> could have been used.
662The new
663function can be used exactly like the standard functions provided with
664<B>ODR</B>. It will encode, decode or pretty-print a data value of the
665<CODE>MySequence</CODE> type. We like to name types with an initial capital, as
666done in ASN.1 definitions, and to name the corresponding function with
667the first character of the name in lower case. You could, of course,
668name your structures, types, and functions any way you please - as
669long as you're consistent, and your code is easily readable.
670<CODE>odr_ok</CODE> is
671just that - a predicate that returns the state of the stream. It is
672used to ensure that the behaviour of the new type is compatible with
673the interface of the primitive types.
674<P>
675<H3>Tagging Constructed Types</H3>
676
677<P><I>NOTE: See section
678<A HREF="#tag-prim">Tagging Primitive types</A>
679for information on how to tag the primitive types, as well as types
680that are already defined.</I>
681<P>
682<H3>Implicit Tagging</H3>
683
684<P>Assume the type above had been defined as
685<P>
686<BLOCKQUOTE><CODE>
687<PRE>
688MySequence ::= [10] IMPLICIT SEQUENCE {
689 intval INTEGER,
690 boolval BOOLEAN OPTIONAL }
691</PRE>
692</CODE></BLOCKQUOTE>
693<P>You would implement this in <B>ODR</B> by calling the function
694<P>
695<BLOCKQUOTE><CODE>
696<PRE>
697int odr_implicit_settag(ODR o, int class, int tag);
698</PRE>
699</CODE></BLOCKQUOTE>
700<P>which overrides the tag of the type immediately following it. The
701macro <CODE>odr_implicit()</CODE> works by calling <CODE>odr_implicit_settag()</CODE>
702immediately
703before calling the function pointer argument. Your type function could
704look like this:
705<P>
706<BLOCKQUOTE><CODE>
707<PRE>
708int mySequence(ODR o, MySequence **p, int optional, const char *name)
709{
710 if (odr_implicit_settag(o, ODR_CONTEXT, 10) == 0 ||
711 odr_sequence_begin(o, p, sizeof(**p), name) == 0)
712 return optional &amp;&amp; odr_ok(o);
713 return
714 odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
715 odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
716 odr_sequence_end(o);
717}
718</PRE>
719</CODE></BLOCKQUOTE>
720<P>The definition of the structure <CODE>MySequence</CODE> would be the same.
721<P>
722<H3>Explicit Tagging</H3>
723
724<P>Explicit tagging of constructed types is a little more complicated,
725since you are in effect adding a level of construction to the data.
726<P>Assume the definition:
727<P>
728<BLOCKQUOTE><CODE>
729<PRE>
730MySequence ::= [10] IMPLICIT SEQUENCE {
731 intval INTEGER,
732 boolval BOOLEAN OPTIONAL }
733</PRE>
734</CODE></BLOCKQUOTE>
735<P>Since the new type has an extra level of construction, two new functions
736are needed to encapsulate the base type:
737<P>
738<BLOCKQUOTE><CODE>
739<PRE>
740int odr_constructed_begin(ODR o, void *p, int class, int tag,
741 const char *name);
742
743int odr_constructed_end(ODR o);
744</PRE>
745</CODE></BLOCKQUOTE>
746<P>Assume that the IMPLICIT in the type definition above were replaced
747with EXPLICIT (or that the IMPLICIT keyword were simply deleted, which
748would be equivalent). The structure definition would look the same,
749but the function would look like this:
750<P>
751<BLOCKQUOTE><CODE>
752<PRE>
753int mySequence(ODR o, MySequence **p, int optional, const char *name)
754{
755 if (odr_constructed_begin(o, p, ODR_CONTEXT, 10, name) == 0)
756 return optional &amp;&amp; odr_ok(o);
757 if (o->direction == ODR_DECODE)
758 *p = odr_malloc(o, sizeof(**p));
759 if (odr_sequence_begin(o, p, sizeof(**p), 0) == 0)
760 {
761 *p = 0; /* this is almost certainly a protocol error */
762 return 0;
763 }
764 return
765 odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
766 odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
767 odr_sequence_end(o) &amp;&amp;
768 odr_constructed_end(o);
769}
770</PRE>
771</CODE></BLOCKQUOTE>
772<P>Notice that the interface here gets kind of nasty. The reason is
773simple: Explicitly tagged, constructed types are fairly rare in
774the protocols that we care about, so the
775aesthetic annoyance (not to mention the dangers of a cluttered
776interface) is less than the time that would be required to develop a
777better interface. Nevertheless, it is far from satisfying, and it's a
778point that will be worked on in the future. One option for you would
779be to simply apply the <CODE>odr_explicit()</CODE> macro to the first function,
780and not
781have to worry about <CODE>odr_constructed_*</CODE> yourself. Incidentally, as you
782might have guessed, the <CODE>odr_sequence_</CODE> functions are themselves
783implemented using the <CODE>odr_constructed_</CODE> functions.
784<P>
785<H3>SEQUENCE OF</H3>
786
787<P>To handle sequences (arrays) of a apecific type, the function
788<P>
789<BLOCKQUOTE><CODE>
790<PRE>
791int odr_sequence_of(ODR o, int (*fun)(ODR o, void *p, int optional),
792 void *p, int *num, const char *name);
793</PRE>
794</CODE></BLOCKQUOTE>
795<P>The <CODE>fun</CODE> parameter is a pointer to the decoder/encoder
796function of the type. <CODE>p</CODE> is a pointer to an array of pointers to your
797type. <CODE>num</CODE> is the number of elements in the array.
798<P>Assume a type
799<P>
800<BLOCKQUOTE><CODE>
801<PRE>
802MyArray ::= SEQUENCE OF INTEGER
803</PRE>
804</CODE></BLOCKQUOTE>
805<P>The C representation might be
806<P>
807<BLOCKQUOTE><CODE>
808<PRE>
809typedef struct MyArray
810{
811 int num_elements;
812 int **elements;
813} MyArray;
814</PRE>
815</CODE></BLOCKQUOTE>
816<P>And the function might look like
817<P>
818<BLOCKQUOTE><CODE>
819<PRE>
820int myArray(ODR o, MyArray **p, int optional, const char *name)
821{
822 if (o->direction == ODR_DECODE)
823 *p = odr_malloc(o, sizeof(**p));
824 if (odr_sequence_of(o, odr_integer, &amp;(*p)->elements,
825 &amp;(*p)->num_elements, name))
826 return 1;
827 *p = 0;
828 return optional &amp;&amp; odr_ok(o);
829}
830</PRE>
831</CODE></BLOCKQUOTE>
832<P>
833<H3>CHOICE Types</H3>
834
835<P>The choice type is used fairly often in some ASN.1 definitions, so
836some work has gone into streamlining its interface.
837<P>CHOICE types are handled by the function:
838<P>
839<BLOCKQUOTE><CODE>
840<PRE>
841int odr_choice(ODR o, Odr_arm arm[], void *p, void *whichp,
842 const char *name);
843</PRE>
844</CODE></BLOCKQUOTE>
845<P>The <CODE>arm</CODE> array is used to describe each of the possible types that the
846CHOICE type may assume. Internally in your application, the CHOICE
847type is represented as a discriminated union. That is, a C union
848accompanied by an integer (or enum) identifying the active 'arm' of
849the union. <CODE>whichp</CODE> is a pointer to the union discriminator. When
850encoding, it is examined to determine the current type. When decoding,
851it is set to reference the type that was found in the input stream.
852<P>The Odr_arm type is defined thus:
853<P>
854<BLOCKQUOTE><CODE>
855<PRE>
856typedef struct odr_arm
857{
858 int tagmode;
859 int class;
860 int tag;
861 int which;
862 Odr_fun fun;
863 char *name;
864} Odr_arm;
865</PRE>
866</CODE></BLOCKQUOTE>
867<P>The interpretation of the fields are:
868<P>
869<DL>
870<DT><B>tagmode</B><DD><P>Either <CODE>ODR_IMPLICIT</CODE>, <CODE>ODR_EXPLICIT</CODE>, or <CODE>ODR_NONE</CODE>
871(-1) to mark
872no tagging.
873<DT><B>class, tag</B><DD><P>The class and tag of the type (-1 if no tagging is
874used).
875<DT><B>which</B><DD><P>The value of the discriminator that corresponds to
876this CHOICE element. Typically, it will be a #defined constant, or
877an enum member.
878<DT><B>fun</B><DD><P>A pointer to a function that implements the type of
879the CHOICE member. It may be either a standard <B>ODR</B> type or a type
880defined by yourself.
881<DT><B>name</B><DD><P>Name of tag.
882</DL>
883<P>A handy way to prepare the array for use by the <CODE>odr_choice()</CODE> function
884is to
885define it as a static, initialized array in the beginning of your
886decoding/encoding function. Assume the type definition:
887<P>
888<BLOCKQUOTE><CODE>
889<PRE>
890MyChoice ::= CHOICE {
891 untagged INTEGER,
892 tagged [99] IMPLICIT INTEGER,
893 other BOOLEAN
894}
895</PRE>
896</CODE></BLOCKQUOTE>
897<P>Your C type might look like
898<P>
899<BLOCKQUOTE><CODE>
900<PRE>
901typedef struct MyChoice
902{
903 enum
904 {
905 MyChoice_untagged,
906 MyChoice_tagged,
907 MyChoice_other
908 } which;
909 union
910 {
911 int *untagged;
912 int *tagged;
913 bool_t *other;
914 } u;
915};
916</PRE>
917</CODE></BLOCKQUOTE>
918<P>And your function could look like this:
919<P>
920<BLOCKQUOTE><CODE>
921<PRE>
922int myChoice(ODR o, MyChoice **p, int optional, const char *name)
923{
924 static Odr_arm arm[] =
925 {
926 {-1, -1, -1, MyChoice_untagged, odr_integer, "untagged"},
927 {ODR_IMPLICIT, ODR_CONTEXT, 99, MyChoice_tagged, odr_integer,
928 "tagged"},
929 {-1, -1, -1, MyChoice_other, odr_boolean, "other"},
930 {-1, -1, -1, -1, 0}
931 };
932
933 if (o->direction == ODR_DECODE)
934 *p = odr_malloc(o, sizeof(**p);
935 else if (!*p)
936 return optional &amp;&amp; odr_ok(o);
937
938 if (odr_choice(o, arm, &amp;(*p)->u, &amp;(*p)->which), name)
939 return 1;
940 *p = 0;
941 return optional &amp;&amp; odr_ok(o);
942}
943</PRE>
944</CODE></BLOCKQUOTE>
945<P>In some cases (say, a non-optional choice which is a member of a sequence),
946you can &quot;embed&quot; the union and its discriminator in the structure
947belonging to the enclosing type, and you won't need to fiddle with
948memory allocation to create a separate structure to wrap the
949discriminator and union.
950<P>The corresponding function is somewhat nicer in the Sun XDR interface.
951Most of the complexity of this interface comes from the possibility of
952declaring sequence elements (including CHOICEs) optional.
953<P>The ASN.1 specifictions naturally requires that each member of a
954CHOICE have a distinct tag, so they can be told apart on decoding.
955Sometimes it can be useful to define a CHOICE that has multiple types
956that share the same tag. You'll need some other mechanism, perhaps
957keyed to the context of the CHOICE type. In effect, we would like to
958introduce a level of context-sensitiveness to our ASN.1 specification.
959When encoding an internal representation, we have no problem, as long
960as each CHOICE member has a distinct discriminator value. For
961decoding, we need a way to tell the choice function to look for a
962specific arm of the table. The function
963<P>
964<BLOCKQUOTE><CODE>
965<PRE>
966void odr_choice_bias(ODR o, int what);
967</PRE>
968</CODE></BLOCKQUOTE>
969<P>provides this functionality. When called, it leaves a notice for the
970next call to <CODE>odr_choice()</CODE> to be called on the decoding
971stream <CODE>o</CODE> that only the <CODE>arm</CODE> entry with a <CODE>which</CODE> field
972equal to <CODE>what</CODE> should be tried.
973<P>The most important application (perhaps the only one, really) is in
974the definition of application-specific EXTERNAL encoders/decoders
975which will automatically decode an ANY member given the direct or
976indirect reference.
977<P>
978<H2><A NAME="ss5.4">5.4 Debugging</A>
979</H2>
980
981<P>The protocol modules are suffering somewhat from a lack of diagnostic
982tools at the moment. Specifically ways to pretty-print PDUs that
983aren't recognized by the system. We'll include something to this end
984in a not-too-distant release. In the meantime, what we do when we get
985packages we don't understand is to compile the ODR module with
986<CODE>ODR_DEBUG</CODE> defined. This causes the module to dump tracing
987information as it processes data units. With this output and the
988protocol specification (Z39.50), it is generally fairly easy to see
989what goes wrong.
990<P>
991<HR>
992<A HREF="yaz-6.html">Next</A>
993<A HREF="yaz-4.html">Previous</A>
994<A HREF="yaz.html#toc5">Contents</A>
995</BODY>
996</HTML>
Note: See TracBrowser for help on using the repository browser.