|
|
Index Data > YAZ > YAZ User's Guide and Reference > Using ODR Conceptually, the ODR stream is the source of encoded data in the decoding mode; when encoding, it is the receptacle for the encoded data. Before you can use an ODR stream it must be allocated. This is done with the function
ODR odr_createmem(int direction);
The When you're done with the stream, you can use
void odr_destroy(ODR o);
to release the resources allocated for the stream. Two forms of memory management take place in the ODR system. The first one, which has to do with allocating little bits of memory (sometimes quite large bits of memory, actually) when a protocol package is decoded, and turned into a complex of interlinked structures. This section deals with this system, and how you can use it for your own purposes. The next section deals with the memory management which is required when encoding data - to make sure that a large enough buffer is available to hold the fully encoded PDU. The ODR module has its own memory management system, which is used whenever memory is required. Specifically, it is used to allocate space for data when decoding incoming PDUs. You can use the memory system for your own purposes, by using the function
void *odr_malloc(ODR o, int size);
You can't use the normal
void odr_reset(ODR o, int size);
when you are done with the
memory: Everything allocated since the last call to
The function
int odr_total(ODR o);
returns the number of bytes allocated on the stream since the last call to
The memory subsystem of ODR is fairly efficient at allocating and releasing little bits of memory. Rather than managing the individual, small bits of space, the system maintains a free-list of larger chunks of memory, which are handed out in small bits. This scheme is generally known as a nibble memory system. It is very useful for maintaining short-lived constructions such as protocol PDUs.
If you want to retain a bit of memory beyond the next call to
ODR_MEM odr_extract_mem(ODR o);
This function will give you control of the memory recently allocated
on the ODR stream. The memory will live (past calls to
void odr_release_mem(ODR_MEM p);
The opaque
You can use When encoding data, the ODR stream will write the encoded octet string in an internal buffer. To retrieve the data, use the function
char *odr_getbuf(ODR o, int *len, int *size);
The integer pointed to by len is set to the length of the encoded
data, and a pointer to that data is returned.
void odr_setbuf(ODR o, char *buf, int len, int can_grow);
which sets the encoding (or decoding) buffer used by
odr_setbuf(stream, 0, 0, 1);
In this case, the stream will allocate and reallocate memory as
necessary. The stream reallocates memory by repeatedly doubling the
size of the buffer - the result is that the buffer will typically
reach its maximum, working size with only a small number of reallocation
operations. The memory is freed by the stream when the latter is destroyed,
unless it was assigned by the user with the
To assume full control of an encoded buffer, you must first call
It is important to realize that the ODR stream will not release this
memory when you call
When you wish to decode data, you should first call
Example 8.1. Encoding and decoding functions
int odr_integer(ODR o, int **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
the type), the return value will be either 0 or 1 depending on the
If the data value is found where it's expected, the pointer
pointed to
by the Example 8.2. 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.
void do_nothing_useful(int value)
{
ODR encode, decode;
int *valp, *resvalp;
char *bufferp;
int len;
/* allocate streams */
if (!(encode = odr_createmem(ODR_ENCODE)))
return;
if (!(decode = odr_createmem(ODR_DECODE)))
return;
valp = &value;
if (odr_integer(encode, &valp, 0, 0) == 0)
{
printf("encoding went bad\n");
return;
}
bufferp = odr_getbuf(encode, &len);
printf("length of encoded data is %d\n", len);
/* now let's decode the thing again */
odr_setbuf(decode, bufferp, len);
if (odr_integer(decode, &resvalp, 0, 0) == 0)
{
printf("decoding went bad\n");
return;
}
printf("the value is %d\n", *resvalp);
/* clean up */
odr_destroy(encode);
odr_destroy(decode);
}
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_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,
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 Example 8.3. Element Path for record
For a database record part of a PresentResponse the
array returned by
The encoding/decoding functions all return 0 when an error occurs.
Until you call To provide information to the programmer or administrator, the function
void odr_perror(ODR o, char *message);
is provided, which prints the You can also use the function
int odr_geterror(ODR o);
to get the current error number from the screen. The number will be one of these constants: Table 8.1. ODR Error codes
The character string array
char *odr_errlist[]
can be indexed by the error code to obtain a human-readable representation of the problem.
#include <odr.h>
ODR odr_createmem(int direction);
void odr_destroy(ODR o);
void odr_reset(ODR o);
char *odr_getbuf(ODR o, int *len);
void odr_setbuf(ODR o, char *buf, int len);
void *odr_malloc(ODR o, int size);
ODR_MEM odr_extract_mem(ODR o);
void odr_release_mem(ODR_MEM r);
int odr_geterror(ODR o);
void odr_perror(char *message);
extern char *odr_errlist[];
|
|||||||||||||||||
|
|
||||||||||||||||||
| Copyright Index Data ApS 2008 | ||||||||||||||||||