*** /dev/null Sat Nov 23 00:54:19 2024
--- - Sat Nov 23 00:54:33 2024
***************
*** 0 ****
--- 1,620 ----
+ ##
+ ## OSSP xds - Extensible Data Serialization
+ ## Copyright (c) 2001-2005 Ralf S. Engelschall <rse@engelschall.com>
+ ## Copyright (c) 2001-2005 The OSSP Project <http://www.ossp.org/>
+ ## Copyright (c) 2001-2005 Cable & Wireless <http://www.cw.com/>
+ ##
+ ## This file is part of OSSP xds, an extensible data serialization
+ ## library which can be found at http://www.ossp.org/pkg/lib/xds/.
+ ##
+ ## Permission to use, copy, modify, and distribute this software for
+ ## any purpose with or without fee is hereby granted, provided that
+ ## the above copyright notice and this permission notice appear in all
+ ## copies.
+ ##
+ ## THIS SOFTWARE IS PROVIDED `AS IS' AND ANY EXPRESSED OR IMPLIED
+ ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+ ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ ## SUCH DAMAGE.
+ ##
+ ## xds.pod: Unix manual page source
+ ##
+
+ =pod
+
+ =head1 NAME
+
+ B<OSSP xds> - eXtensible Data Serialization
+
+ =head1 SYNOPSIS
+
+ xds_init,
+ xds_destroy,
+ xds_register,
+ xds_unregister,
+ xds_setbuffer,
+ xds_getbuffer,
+ xds_encode,
+ xds_decode,
+ xds_vencode,
+ xds_vdecode.
+
+ =head1 DESCRIPTION
+
+ The B<OSSP xds> library is generic and extensible encoding and decoding
+ framework for the serialization of arbitrary ISO C data types. B<OSSP
+ xds> consists of three components: the generic encoding and decoding
+ framework, a set of shipped engines to encode and decode values in
+ certain existing formats (Sun RPC/XDR and XDS/XML are currently
+ provided), and a run-time context, which is used to manage buffers,
+ registered engines, etc. The library is designed to allow fully
+ recursive and efficient encoding/decoding of arbitrary nested data.
+
+ =head2 INTRODUCTION
+
+ In order to use B<OSSP xds>, the first thing the developer has to
+ do is to create a valid context by calling xds_init(). The function
+ requires one parameter that determines whether to operate in encoding-
+ or decoding mode. A context can be used for encoding or decoding only;
+ it is not possible to use the same context for both operations. Once a
+ valid context has been obtained, the function xds_register() can be used
+ to register an arbitrary number of encoding (or decoding) engines within
+ the context.
+
+ Two sets of engines are included in the library, additional ones can be
+ easily programmed. These functions will handle any elementary datatype
+ defined by the ISO-C language, such as 32-bit integers, 64-bit integers,
+ unsigned integers (of both 32 and 64-bit), floating point numbers,
+ strings and octet streams.
+
+ Once all required encoding/decoding engines are registered, the
+ functions xds_encode() or xds_decode() may be used to actually perform
+ the encoding or decoding process. Any data type for which an engine has
+ been registered before can be handled by the library.
+
+ This means, it is possible for the developer to write custom engines for
+ any data type he desires to use and to register them in the context --
+ as long as these engines adhere to the C<xds_engine_t> interface defined
+ in F<xds.h>.
+
+ In particular, it is possible to register meta engines. This is an
+ engine designed to encode or decode data types which consist of several
+ elementary data types. Such an engine will simply re-use the existing
+ engines to encode or decode the elements of the structure.
+
+ The following example program (without error checking for simplicity)
+ will encode the unsigned integer 0x1234 into the B<XDR> format (known from
+ Sun RPC), decode it back into the native host format, and compare the
+ result to make sure it is the original value again:
+
+ #include <stdio.h>
+ #include <errno.h>
+
+ #include "xds.h"
+
+ int main(int argc, char *argv[])
+ {
+ xds_t *xds;
+ xds_uint32_t uint32 = 0x1234;
+ xds_uint32_t uint32_new;
+ char *buffer;
+ size_t buffer_size;
+
+ /* encoding */
+ xds = xds_init(XDS_ENCODE);
+ xds_register(xds, "uint32", &xdr_encode_uint32, NULL);
+ xds_encode(xds, "uint32", uint32);
+ xds_getbuffer(xds, XDS_GIFT, (void**)&buffer, &buffer_size);
+ xds_destroy(xds);
+
+ /* ...usually buffer is now transferred to a remote system... */
+
+ /* decoding */
+ xds = xds_init(XDS_DECODE);
+ xds_register(xds, "uint32", &xdr_decode_uint32, NULL);
+ xds_setbuffer(xds, XDS_LOAN, buffer, buffer_size);
+ xds_decode(xds, "uint32", &uint32_new);
+ xds_destroy(xds);
+
+ /* comparison */
+ if (uint32 == uint32_new)
+ printf("OK\n");
+ else
+ printf("Failure\n");
+ return 0;
+ }
+
+ =head1 THE XDS FRAMEWORK
+
+ B<OSSP xds> provides a generic framework for encoding and decoding.
+ The corresponding API is described here.
+
+ =over 4
+
+ =item xds_t *B<xds_init>(xds_mode_t I<mode>);
+
+ This function creates and initializes a context. The I<mode> parameter
+ may be either C<XDS_ENCODE> or C<XDS_DECODE>, depending on whether you
+ want to encode or decode data. If successful, xds_init() returns a
+ pointer to the context. In case of failure, xds_init() returns C<NULL>
+ and sets errno to C<ENOMEM> (failed to allocate internal memory buffers)
+ or C<EINVAL> (I<mode> parameter was invalid).
+
+ A context obtained from xds_init() must be destroyed by xds_destroy() if
+ it is no longer needed.
+
+ =item void B<xds_destroy>(xds_t *I<xds>);
+
+ xds_destroy() will destroy the context I<xds>, created by xds_init().
+ Doing so will return all resources associated with this context -- most
+ notably the memory used to buffer the results of encoding or decoding
+ any values. A context may not be used after it has been destroyed.
+
+ =item int B<xds_register>(xds_t *I<xds>, const char *I<name>, xds_engine_t I<engine>, void *I<engine_context>);
+
+ This function will register an engine in the provided context. An
+ I<engine> is potentially any function that fullfils the following
+ interface:
+
+ int B<engine>(xds_t *I<xds>, void *I<engine_context>, void *I<buffer>, size_t I<buffer_size>, size_t *I<used_buffer_size>, va_list *I<args>);
+
+ By calling xds_register(), the I<engine> will be registered under the
+ name I<name> in the context I<xds>. The last parameter I<engine_context>
+ may be used as the user sees fit: It will be passed when the engine is
+ actually called and may be used to implement an engine-specific context.
+ Most engines will not need a context of their own, in which case C<NULL>
+ should be specified here.
+
+ Please note that until the user calls xds_register() for a context he
+ obtained from xds_init(), no engines are registered for that context.
+ Even the engines included in the B<OSSP xds> source distribution are not
+ registered automatically.
+
+ For engine names, any combination of the characters a-z, A-Z, 0-9, "-",
+ and "_" may be used; anything else is not a legal engine name component.
+
+ xds_register() may return the following return codes: C<XDS_OK>
+ (everything went fine; the engine is registered now),
+ C<XDS_ERR_INVALID_ARG> (either I<xds>, I<name>, or I<engine> are
+ C<NULL> or I<name> contains illegal characters for an engine name), or
+ C<XDS_ERR_NO_MEM> (failed to allocate internally required buffers).
+
+ =item int B<xds_unregister>(xds_t *I<xds>, const char *I<name>);
+
+ xds_unregister() will remove the engine I<name> from the context I<xds>.
+ The function will return C<XDS_OK> in case everything went fine,
+ C<XDS_ERR_UNKNOWN_ENGINE> in case the engine I<name> is not registered
+ in I<xds>, or C<XDS_ERR_INVALID_ARG> if either I<xds> or I<name> are
+ C<NULL> or I<name> contains illegal characters for an engine name.
+
+ =item int B<xds_setbuffer>(xds_t *I<xds>, xds_scope_t I<flag>, void *I<buffer>, size_t I<buffer_len>);
+
+ This function allows the user to control the buffer handling: Calling
+ it will replace the buffer currently used in I<xds>. The address and
+ size of that buffer are passed to xds_setbuffer() via the I<buffer> and
+ I<buffer_len> parameters. The I<xds> parameter determines for which
+ context the new buffer will be set. Furthermore, you can set I<flag> to
+ either C<XDS_GIFT> or C<XDS_LOAN>.
+
+ C<XDS_GIFT> will tell B<OSSP xds> that the provided buffer is now
+ owned by the library and that it may be resized by calling realloc(3).
+ Furthermore, the buffer is free(3)'ed when I<xds> is destroyed. If
+ I<flag> is C<XDS_GIFT> and I<buffer> is C<NULL>, xds_setbuffer() will
+ simply allocate a buffer of its own to be set in I<xds>. Please note
+ that a buffer given to the library as a gift B<must> have been allocated
+ using malloc(3) -- it may not live on the stack because B<OSSP xds> will
+ try to free or to resize the buffer as it sees fit.
+
+ Passing C<XDS_LOAN> via I<flag> tells xds_setbuffer() that the buffer is
+ owned by the application and that B<OSSP xds> should not free nor resize
+ the buffer in any case. In this mode, passing a buffer of C<NULL> will
+ result in an invalid-argument error.
+
+ =item int B<xds_getbuffer>(xds_t *I<xds>, xds_scope_t I<flag>, void **I<buffer>, size_t *I<buffer_len>);
+
+ This function is the counterpart to xds_setbuffer(): It will get
+ the buffer currently used in the context I<xds>. The address of that
+ buffer is stored in the location I<buffer> points to; the length of the
+ buffer's content will be stored in the location I<buffer_len> points to.
+
+ The I<flag> argument may be set to either C<XDS_GIFT> or C<XDS_LOAN>.
+ The first setting means that the buffer is now owned by the application
+ and that B<OSSP xds> must not use it after this xds_getbuffer() call
+ anymore; it will allocate a new internal buffer instead. Of course,
+ this also means that the buffer will not be freed by xds_destroy();
+ the application has to free(3) the buffer itself when it is not needed
+ anymore.
+
+ Setting I<flag> to C<XDS_LOAN> tells B<OSSP xds> that the application
+ just wishes to peek into the buffer and will not modify it. The buffer
+ is still owned (and used) by B<OSSP xds>. Please note that the loaned
+ address returned by xds_getbuffer() may change after any other xds_xxx()
+ function call!
+
+ The function will return C<XDS_OK> (everything went fine) or
+ C<XDS_ERR_INVALID_ARG> (I<xds>, I<buffer> or I<buffer_len> are C<NULL>
+ or I<flag> is invalid) signifying success or failure respectively.
+
+ Please note: It is perfectly legal for xds_getbuffer() to return a
+ buffer of C<NULL> and a buffer length of C<0>! This happens when
+ xds_getbuffer() is called for a fresh context before a buffer has been
+ allocated at all.
+
+ =item int B<xds_vencode>(xds_t *I<xds>, const char *I<fmt>, va_list I<args>);
+
+ This function will encode one or several values using the appropriate
+ encoding engines registered in the context I<xds>. The parameter I<fmt>
+ contains a sprintf(3)-alike descriptions of the values to be
+ encoded; the actual values are provided in the varadic parameter I<args>.
+
+ The format for I<fmt> is simple: Just provide the names of the engines to
+ be used for encoding the appropriate value(s) in I<args>. Any non-legal
+ engine-name character may be used as a delimiter. In order to encode two
+ 32-bit integers followed by a 64-bit integer, the format string
+
+ int32 int32 int64
+
+ could be used. In case you don't like the blank, use the colon instead:
+
+ int32:int32:int64
+
+ Of course the names to be used here have to match to the names used to
+ register the engines in I<xds> earlier.
+
+ Every time xds_vencode() is called, it will append the encoded data
+ at the end of the internal buffer stored in I<xds>. Thus, you can
+ call xds_vencode() several times in order to encode several values,
+ but you'll still get all encoded values stored in one buffer. Calling
+ xds_setbuffer() or xds_getbuffer() with gift semantics at any point
+ during encoding will re-set the buffer to the beginning. All values
+ that have been encoded into that buffer already will eventually be
+ overwritten when xds_encode() is called again. Hence: Don't call
+ xds_setbuffer() or xds_getbuffer() unless you actually want to access
+ the data stored in the buffer.
+
+ Also, it should be noted that the data you have to provide for I<args>
+ depends entirely on what the deployed engines expect to find on the
+ stack -- there is no "standard" on what should be put on the stack here.
+ The B<XML> and B<XDR> engines included in the distribution will simply expect
+ the value to be encoded to be found on the stack, but other engines may
+ act differently.
+
+ xds_vencode() will return any of the following return codes: C<XDS_OK>
+ (everything worked fine), C<XDS_ERR_NO_MEM> (failed to allocate or to
+ resize the internal buffer), C<XDS_ERR_OVERFLOW> (the internal buffer
+ is too small but is not owned by us), C<XDS_ERR_INVALID_ARG> (I<xds> or
+ I<fmt> are C<NULL>), C<XDS_ERR_UNKNOWN_ENGINE> (an engine name specified
+ in I<fmt> is not registered in I<xds>), C<XDS_ERR_INVALID_MODE> (I<xds>
+ is initialized in decode mode), or C<XDS_ERR_UNKNOWN> (the engine
+ returned an unspecified error).
+
+ =item int B<xds_encode>(xds_t *I<xds>, const char *I<fmt>, ...);
+
+ This function is basically identical to xds_vencode(), only that
+ it uses a different prototype syntax.
+
+ =item int B<xds_vdecode>(xds_t *I<xds>, const char *I<fmt>, va_list I<args>);
+
+ This function is almost identical to xds_vencode(): It expects a
+ context, a format string and a set of parameters for the engines, but
+ xds_vdecode() does not encode any data, it decodes the data back into
+ the native format. The format string determines which engines are to be
+ called by the framework in order to decode the values contained in the
+ buffer. The values will then be stored at the locations found in the
+ corresponding I<args> entry. But please note that the exact behavior of
+ the decoding engines is not specified! The B<XML> and B<XDR> engines included
+ in this distribution expect a pointer to a location where to store the
+ decoded value, but other engines may vary.
+
+ xds_vdecode() may return any of the following return codes: C<XDS_OK>
+ (everything went fine), C<XDS_ERR_INVALID_ARG> (I<xds> or I<fmt> are
+ C<NULL>), C<XDS_ERR_TYPE_MISMATCH> (the format string says the next
+ value is of a particular type, but that's not what we found in the
+ buffer), C<XDS_ERR_UNKNOWN_ENGINE> (an engine name specified in I<fmt>
+ is not registered in I<xds>), C<XDS_ERR_INVALID_MODE> (I<xds> has
+ been initialized in encode mode), C<XDS_ERR_UNDERFLOW> (an engine
+ tried to read more bytes from the buffer than what is data left), or
+ C<XDS_ERR_UNKNOWN> (an engine returned an unspecified error).
+
+ =item int B<xds_decode>(xds_t *I<xds>, const char *I<fmt>, ...);
+
+ This function is basically identical to xds_vdecode(), only that
+ it uses a different prototype syntax.
+
+ =back
+
+ =head1 THE XDR ENGINES
+
+ The B<OSSP xds> distribution ships with a set of engine functions which
+ implement the encoding and decoding for the B<XDR> encoding known from
+ Sun RPC.
+
+ Function Name Expected `args' Input Output
+ ----------------------------------------------------------
+ xdr_encode_uint32() xds_uint32_t 4 bytes 4 bytes
+ xdr_decode_uint32() xds_uint32_t* 4 bytes 4 bytes
+ xdr_encode_int32() xds_int32_t 4 bytes 4 bytes
+ xdr_decode_int32() xds_int32_t* 4 bytes 4 bytes
+ xdr_encode_uint64() xds_uint64_t 4 bytes 4 bytes
+ xdr_decode_uint64() xds_uint64_t* 4 bytes 4 bytes
+ xdr_encode_int64() xds_int64_t 4 bytes 4 bytes
+ xdr_decode_int64() xds_int64_t* 4 bytes 4 bytes
+ xdr_encode_float() xds_float_t 4 bytes 4 bytes
+ xdr_decode_float() xds_float_t* 4 bytes 4 bytes
+ xdr_encode_double() xds_double_t 8 bytes 8 bytes
+ xdr_decode_double() xds_double_t* 8 bytes 8 bytes
+ xdr_encode_octetstream() void*, size_t variable variable
+ xdr_decode_octetstream() void**, size_t* variable variable
+ xdr_encode_string() char* variable variable
+ xdr_decode_string() char** variable variable
+
+ Please note that the functions xdr_decode_octetstream() and
+ xdr_decode_string() return a pointer to a buffer holding the decoded
+ data. This buffer has been allocated with malloc(3) and must be
+ free(3)'ed by the application when it is not required anymore. All other
+ callbacks write the decoded value into the location found on the stack,
+ but these behave differently because the length of the decoded data is
+ not known in advance and the application cannot provide a buffer that's
+ guaranteed to suffice.
+
+ =head1 THE XML ENGINES
+
+ The B<OSSP xds> distribution ships with a set of engine functions which
+ implement the encoding and decoding for an B<XML> based format specified by
+ the included B<XML> DTD.
+
+ Function Name Expected `args' Input Output
+ ----------------------------------------------------------------
+ xml_encode_uint32() xds_uint32_t 4 bytes 8-27 bytes
+ xml_decode_uint32() xds_uint32_t* 18-27 bytes 4 bytes
+ xml_encode_int32() xds_int32_t 4 bytes 16-26 bytes
+ xml_decode_int32() xds_int32_t* 16-26 bytes 4 bytes
+ xml_encode_uint64() xds_uint64_t 8 bytes 18-37 bytes
+ xml_decode_uint64() xds_uint64_t* 18-37 bytes 8 bytes
+ xml_encode_int64() xds_int64_t 8 bytes 16-36 bytes
+ xml_decode_int64() xds_int64_t* 16-36 bytes 8 bytes
+ xml_encode_float() xds_float_t 4 bytes variable
+ xml_decode_float() xds_float_t* variable 4 bytes
+ xml_encode_double() xds_double_t 8 bytes variable
+ xml_decode_double() xds_double_t* variable 8 bytes
+ xml_encode_octetstream() void*, size_t variable variable
+ xml_decode_octetstream() void**, size_t* variable variable
+ xml_encode_string() char* variable variable
+ xml_decode_string() char** variable variable
+
+ Please note that the functions xml_decode_octetstream() and
+ xml_decode_string() return a pointer to a buffer holding the decoded
+ data. This buffer has been allocated with malloc(3) and must be
+ free(3)ed by the application when it is not required anymore. All other
+ callbacks write the decoded value into the location found on the stack,
+ but these behave differently because the length of the decoded data is
+ not known in advance and the application cannot provide a buffer that's
+ guaranteed to suffice.
+
+ =head1 EXTENDING THE LIBRARY
+
+ This section demonstrates how to write a "meta engine" for the B<OSSP
+ xds> framework. The example engine will encode a complex data structure,
+ consisting of three elementary data types. The structure is defined as
+ follows:
+
+ struct mystruct {
+ xds_int32_t small;
+ xds_int64_t big;
+ xds_uint32_t positive;
+ char text[16];
+ };
+
+ Some readers might wonder why the structure is defined using these
+ weird data types rather than the familiar ones like C<int>, C<long>,
+ etc. The reason is that these data types have an undefined size. An
+ C<int> variable will have, say, 32 bits when compiled on the average
+ Unix machine, but when the same program is compiled on a 64-bit machine
+ like Tru64 Unix, it will have a size of 64 bit. This is a problem
+ when those structures have to be exchanged between entirely different
+ systems, because the structures are binary incompatible -- something
+ even B<OSSP xds> cannot remedy, because it is impossible to construct a
+ bidirectional and lossless mapping in this case.
+
+ In order to encode an instance of this structure, we write an encoding
+ engine:
+
+ static int
+ encode_mystruct(
+ xds_t *xds, void *engine_context,
+ void *buffer, size_t buffer_size,
+ size_t *used_buffer_size,
+ va_list *args)
+ {
+ struct mystruct *ms;
+
+ ms = va_arg(*args, struct mystruct*);
+ return xds_encode(xds, "int32 int64 uint32 octetstream",
+ ms->small, ms->big, ms->positive,
+ ms->text, sizeof(ms->text));
+ }
+
+ This engine takes the address of the I<mystruct> structure from the
+ stack and then uses xds_encode() to handle all elements of I<mystruct>
+ separately -- which is fine, because these data types are supported
+ by B<OSSP xds> already (both by the shipped B<XDR> and B<XML> engines). It
+ is worth noting, though, that we refer to the other engines by name,
+ meaning that these engines must be registered in I<xds> by that name
+ before!
+
+ What is very nice, though, is the fact that this encoding engine does
+ not even need to know which particular engines are used to encode the
+ actual values! If the user registere the B<XDR> engines under the
+ appropriate names, I<mystruct> will be encoded in B<XDR>. If the user
+ registers the B<XML> engines under the appropriate names, I<mystruct>
+ will be encoded in B<XML>. Because of that property, we call such an
+ engine a "meta engine".
+
+ Of coures you need not necessarily implement an engine as a "meta
+ engine": Rather than going through xds_encode(), it would be possible
+ to execute the appropriate encoding engines directly. This had the
+ advantage of not depending on those engines being registered at all, but
+ it would make the custom engine depend on the elementary engines -- what
+ is an unnecessary limitation.
+
+ One more word about the engine syntax and semantics: As has been
+ mentioned earlier, any function that adheres to the interface shown
+ above is potentially an engine. These parameters have the following
+ meaning:
+
+ =over 4
+
+ =item I<xds>
+
+ This is the B<OSSP xds> context that was originally provided to the
+ xds_encode() call, which in turn executed the engine. It may be used,
+ for example, for executing xds_encode() again like we did in our example
+ engines.
+
+ =item I<engine_context>
+
+ The engine context can be used by the engine to store any type of
+ internal information. The value the engine will receive must have been
+ provided when the engine was registered by xds_register(). Engines
+ obviously may neglect this parameter if they don't need a context of
+ their own -- all engines included in the distribution do so.
+
+ =item I<buffer>
+
+ This parameter points to the buffer the encoded data should be written
+ to. In decoding mode, I<buffer> points to the encoded data, which should
+ be decoded; the location where the results should be stored at can be
+ found on the stack then.
+
+ =item I<buffer_size>
+
+ The number of bytes available in I<buffer>. In encoding mode, this means
+ "free space", in decoding mode, I<buffer_size> determines how many bytes
+ of encoded data are available in I<buffer> for consumption.
+
+ =item I<used_buffer_size>
+
+ This parameter points to a variable, which the callback must set before
+ returning in order to let the framework know how many bytes it consumed
+ from I<buffer>. A callback encoding, say, an int32 number into a 8 bytes
+ text representation would set the used_buffer_size to 8:
+
+ *used_buffer_size = 8;
+
+ In encoding mode, this variable determines how many bytes the engine has
+ written into I<buffer>; in decoding mode the variable determines how
+ many bytes the engines has read from I<buffer>.
+
+ =item I<args>
+
+ This pointer points to an initialized varadic argument.
+ Use the standard C macro va_arg(3) to fetch the actual data.
+
+ =back
+
+ A callback may return any of the following return codes, as defined in
+ F<xds.h>:
+
+ =over 4
+
+ =item C<XDS_OK>
+
+ No error.
+
+ =item C<XDS_ERR_NO_MEM>
+
+ Failed to allocate required memory.
+
+ =item C<XDS_ERR_OVERFLOW>
+
+ The buffer is too small to hold all encoded data. The callback may set
+ *I<used_buffer_size> to the number of bytes it needs in I<buffer>,
+ thereby giving the framework a hint by how many bytes it should
+ enlarge the buffer before trying the engine again, but just leaving
+ *I<used_buffer_size> alone will work fine too, it may just be a bit less
+ efficient in some cases. Obviously this return code does not make much
+ sense in decoding mode.
+
+ =item C<XDS_ERR_INVALID_ARG>
+
+ Unexpected or incorrect parameters.
+
+ =item C<XDS_ERR_TYPE_MISMATCH>
+
+ This return code will be returned in decoding mode in case the decoding
+ engine realizes that the data it is decoding does not fit what it is
+ expecting. Not all encoding formats will allow to detect this at all.
+ B<XDR>, for example, does not.
+
+ =item C<XDS_ERR_UNDERFLOW>
+
+ In decode mode, this error is be returned when an engine needs, say, 4
+ bytes of data in order to decode a value but I<buffer>/I<buffer_size>
+ provides less.
+
+ =item C<XDS_ERR_UNKNOWN>
+
+ Any other reason to fail than those listed before. Catch all...
+
+ =back
+
+ Let's take a look at the corresponding decoding "meta engine" now:
+
+ static int
+ decode_mystruct(
+ xds_t *xds, void *engine_context,
+ void *buffer, size_t buffer_size,
+ size_t *used_buffer_size,
+ va_list *args)
+ {
+ struct mystruct *ms;
+ size_t i;
+ char *tmp;
+ int rc;
+
+ ms = (struct mystruct *)va_arg(*args, void *);
+ rc = xds_decode(xds, "int32 int64 uint32 octetstream",
+ &(ms->small), &(ms->big), &(ms->positive),
+ &tmp, &i);
+ if (rc == XDS_OK) {
+ if (i == sizeof(ms->text))
+ memmove(ms->text, tmp, i);
+ else
+ rc = XDS_ERR_TYPE_MISMATCH;
+ free(tmp);
+ }
+ return rc;
+ }
+
+ The engine simply calls xds_decode() to handle the separate data types.
+ The only complication is that the octet stream decoding engines return a
+ pointer to malloc(3)ed buffer -- what is not what we need. Thus we have
+ to manually copy the contents of that buffer into the right place in the
+ structure and free the (now unused) buffer again.
+
+ A complete example program encoding and decoding C<mystruct> can be
+ found as F<docs/extended.c> in the B<OSSP xds> source distribution.
+
+ =head1 SEE ALSO
+
+ RFC 1832: `XDR: External Data Representation Standard',
+ R. Srinivasan, August 1995
+
+ XML-RPC Home Page: http://www.xmlrpc.org/
+
+ =head1 HISTORY
+
+ B<OSSP var> was initially written by Peter Simons
+ E<lt>simons@crypt.toE<gt> in August 2001 under contract with the B<OSSP>
+ sponsor B<Cable & Wireless>.
+
+ =cut
+
|