head 1.21; access; symbols XDS_0_9_3:1.21 XDS_0_9_2:1.21 XDS_0_9_1:1.20 XDS_0_9_0:1.17 callback-semantic-rewrite:1.5.0.2; locks; strict; comment @# @; 1.21 date 2005.06.02.18.51.44; author rse; state Exp; branches; next 1.20; 1.20 date 2004.09.12.17.34.05; author rse; state Exp; branches; next 1.19; 1.19 date 2004.09.12.17.32.14; author rse; state Exp; branches; next 1.18; 1.18 date 2003.02.17.12.51.58; author rse; state Exp; branches; next 1.17; 1.17 date 2003.02.17.12.36.02; author rse; state Exp; branches; next 1.16; 1.16 date 2002.03.17.10.25.53; author rse; state Exp; branches; next 1.15; 1.15 date 2002.01.03.14.22.33; author rse; state Exp; branches; next 1.14; 1.14 date 2002.01.02.18.35.51; author rse; state Exp; branches; next 1.13; 1.13 date 2002.01.02.17.13.44; author rse; state Exp; branches; next 1.12; 1.12 date 2001.08.30.15.02.52; author simons; state Exp; branches; next 1.11; 1.11 date 2001.08.30.11.29.38; author simons; state Exp; branches; next 1.10; 1.10 date 2001.08.13.18.31.53; author simons; state Exp; branches; next 1.9; 1.9 date 2001.08.12.11.31.45; author rse; state Exp; branches; next 1.8; 1.8 date 2001.08.09.19.58.35; author rse; state Exp; branches; next 1.7; 1.7 date 2001.08.08.19.15.23; author rse; state Exp; branches; next 1.6; 1.6 date 2001.08.07.11.14.08; author simons; state dead; branches; next 1.5; 1.5 date 2001.07.04.15.12.31; author simons; state Exp; branches; next 1.4; 1.4 date 2001.07.04.14.25.57; author simons; state Exp; branches; next 1.3; 1.3 date 2001.07.04.14.21.20; author simons; state Exp; branches; next 1.2; 1.2 date 2001.07.03.11.36.22; author simons; state Exp; branches; next 1.1; 1.1 date 2001.07.03.08.25.24; author simons; state Exp; branches; next ; desc @@ 1.21 log @Bumped year in copyright messages for year 2005. @ text @## ## OSSP xds - Extensible Data Serialization ## Copyright (c) 2001-2005 Ralf S. Engelschall ## Copyright (c) 2001-2005 The OSSP Project ## Copyright (c) 2001-2005 Cable & Wireless ## ## 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 - 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 library is generic and extensible encoding and decoding framework for the serialization of arbitrary ISO C data types. B 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, 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 interface defined in F. 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 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 #include #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 provides a generic framework for encoding and decoding. The corresponding API is described here. =over 4 =item xds_t *B(xds_mode_t I); This function creates and initializes a context. The I parameter may be either C or C, 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 and sets errno to C (failed to allocate internal memory buffers) or C (I 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_t *I); xds_destroy() will destroy the context I, 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_t *I, const char *I, xds_engine_t I, void *I); This function will register an engine in the provided context. An I is potentially any function that fullfils the following interface: int B(xds_t *I, void *I, void *I, size_t I, size_t *I, va_list *I); By calling xds_register(), the I will be registered under the name I in the context I. The last parameter I 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 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 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 (everything went fine; the engine is registered now), C (either I, I, or I are C or I contains illegal characters for an engine name), or C (failed to allocate internally required buffers). =item int B(xds_t *I, const char *I); xds_unregister() will remove the engine I from the context I. The function will return C in case everything went fine, C in case the engine I is not registered in I, or C if either I or I are C or I contains illegal characters for an engine name. =item int B(xds_t *I, xds_scope_t I, void *I, size_t I); This function allows the user to control the buffer handling: Calling it will replace the buffer currently used in I. The address and size of that buffer are passed to xds_setbuffer() via the I and I parameters. The I parameter determines for which context the new buffer will be set. Furthermore, you can set I to either C or C. C will tell B 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 is destroyed. If I is C and I is C, xds_setbuffer() will simply allocate a buffer of its own to be set in I. Please note that a buffer given to the library as a gift B have been allocated using malloc(3) -- it may not live on the stack because B will try to free or to resize the buffer as it sees fit. Passing C via I tells xds_setbuffer() that the buffer is owned by the application and that B should not free nor resize the buffer in any case. In this mode, passing a buffer of C will result in an invalid-argument error. =item int B(xds_t *I, xds_scope_t I, void **I, size_t *I); This function is the counterpart to xds_setbuffer(): It will get the buffer currently used in the context I. The address of that buffer is stored in the location I points to; the length of the buffer's content will be stored in the location I points to. The I argument may be set to either C or C. The first setting means that the buffer is now owned by the application and that B 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 to C tells B that the application just wishes to peek into the buffer and will not modify it. The buffer is still owned (and used) by B. Please note that the loaned address returned by xds_getbuffer() may change after any other xds_xxx() function call! The function will return C (everything went fine) or C (I, I or I are C or I is invalid) signifying success or failure respectively. Please note: It is perfectly legal for xds_getbuffer() to return a buffer of C 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_t *I, const char *I, va_list I); This function will encode one or several values using the appropriate encoding engines registered in the context I. The parameter I contains a sprintf(3)-alike descriptions of the values to be encoded; the actual values are provided in the varadic parameter I. The format for I is simple: Just provide the names of the engines to be used for encoding the appropriate value(s) in I. 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 earlier. Every time xds_vencode() is called, it will append the encoded data at the end of the internal buffer stored in I. 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 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 and B 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 (everything worked fine), C (failed to allocate or to resize the internal buffer), C (the internal buffer is too small but is not owned by us), C (I or I are C), C (an engine name specified in I is not registered in I), C (I is initialized in decode mode), or C (the engine returned an unspecified error). =item int B(xds_t *I, const char *I, ...); This function is basically identical to xds_vencode(), only that it uses a different prototype syntax. =item int B(xds_t *I, const char *I, va_list I); 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 entry. But please note that the exact behavior of the decoding engines is not specified! The B and B 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 (everything went fine), C (I or I are C), C (the format string says the next value is of a particular type, but that's not what we found in the buffer), C (an engine name specified in I is not registered in I), C (I has been initialized in encode mode), C (an engine tried to read more bytes from the buffer than what is data left), or C (an engine returned an unspecified error). =item int B(xds_t *I, const char *I, ...); This function is basically identical to xds_vdecode(), only that it uses a different prototype syntax. =back =head1 THE XDR ENGINES The B distribution ships with a set of engine functions which implement the encoding and decoding for the B 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 distribution ships with a set of engine functions which implement the encoding and decoding for an B based format specified by the included B 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 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, C, etc. The reason is that these data types have an undefined size. An C 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 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 structure from the stack and then uses xds_encode() to handle all elements of I separately -- which is fine, because these data types are supported by B already (both by the shipped B and B engines). It is worth noting, though, that we refer to the other engines by name, meaning that these engines must be registered in I 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 engines under the appropriate names, I will be encoded in B. If the user registers the B engines under the appropriate names, I will be encoded in B. 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 This is the B 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 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 This parameter points to the buffer the encoded data should be written to. In decoding mode, I 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 The number of bytes available in I. In encoding mode, this means "free space", in decoding mode, I determines how many bytes of encoded data are available in I for consumption. =item I 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. 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; in decoding mode the variable determines how many bytes the engines has read from I. =item I 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: =over 4 =item C No error. =item C Failed to allocate required memory. =item C The buffer is too small to hold all encoded data. The callback may set *I to the number of bytes it needs in I, thereby giving the framework a hint by how many bytes it should enlarge the buffer before trying the engine again, but just leaving *I 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 Unexpected or incorrect parameters. =item C 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, for example, does not. =item C 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/I provides less. =item C 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 can be found as F in the B 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 was initially written by Peter Simons Esimons@@crypt.toE in August 2001 under contract with the B sponsor B. =cut @ 1.20 log @Germany is no longer correct @ text @d3 3 a5 3 ## Copyright (c) 2001-2004 Ralf S. Engelschall ## Copyright (c) 2001-2004 The OSSP Project ## Copyright (c) 2001-2004 Cable & Wireless @ 1.19 log @Bumped year in copyright messages for year 2004. @ text @d617 1 a617 1 sponsor B. @ 1.18 log @provide a better abstract @ text @d3 3 a5 3 ## Copyright (c) 2001-2003 Ralf S. Engelschall ## Copyright (c) 2001-2003 The OSSP Project ## Copyright (c) 2001-2003 Cable & Wireless Germany @ 1.17 log @upgrade to standard OSSP copyright and bump year to 2003 @ text @d52 8 a59 7 The purpose of B is to encode data in a way that allows this data to be exchanged between different computer systems. Assume you would want to transfer the value 0x1234 from host A to host B. Then you would encode it using B, transfer the encoded data over the network, and decode the value again at the other end. Every program that follows this process will read the correct value no matter what native representation is uses internally. d61 1 a61 4 B consists of three components: The generic encoding and decoding framework, a set of engines to encode and decode values in a certain format, and a run-time context, which is used to manage buffers, registered engines, etc. @ 1.16 log @update texts @ text @d3 3 a5 2 ## Copyright (c) 2001-2002 The OSSP Project (http://www.ossp.org/) ## Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) @ 1.15 log @complete revamping of XDS manual page @ text @d2 1 a2 1 ## XDS - OSSP Extensible Data Serialization Library d6 2 a7 2 ## This file is part of OSSP XDS, an extensible data serialization ## library which can be found at http://www.ossp.org/pkg/xds/. d613 6 @ 1.14 log @first cut in cleaning up manual page @ text @d95 1 a95 1 will encode the unsigned integer 0x1234 into the XDR format (known from d177 44 a220 47 Please note that until the user calls xds_register() for an XDS context he obtained from xds_init(), no engines are registered for that context. Even the engines included in the library 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: XDS_OK (everything went fine; the engine is registered now), XDS_ERR_INVALID_ARG (either `xds', `name', or `engine' are NULL or `name' contains illegal characters for an engine name), or XDS_ERR_NO_MEM (failed to allocate internally required buffers). =item int xds_unregister(xds_t* I, const char* I); xds_unregister() will remove the engine `name' from XDS context `xds'. The function will return XDS_OK in case everything went fine, XDS_ERR_UNKNOWN_ENGINE in case the engine `name' is not registered in `xds', or XDS_ERR_INVALID_ARG if either `xds' or `name' are NULL or `name' contains illegal characters for an engine name. =item int xds_setbuffer(xds_t* I, xds_scope_t I, void* I, size_t I); This function allows the user to control XDS' buffer handling: Calling it will replace the buffer currently used in `xds'. The address and size of that buffer are passed to xds_setbuffer() via the `buffer' and `buffer_len' parameters. The `xds' parameter determines for which XDS context the new buffer will be set. Furthermore, you can set `flag' to either XDS_GIFT or XDS_LOAN. XDS_GIFT will tell 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 `xds' is destroyed. If `flag' is XDS_GIFT and `buffer' is NULL, xds_setbuffer() will simply allocate a buffer of its own to be set in `xds'. Please note that a buffer given to XDS as gift B have been allocated using malloc(3) -- it may not live on the stack because XDS will try to free or to resize the buffer as it sees fit. Passing XDS_LOAN via `flag' tells xds_setbuffer() that the buffer is owned by the application and that XDS should not free nor resize the buffer in any case. In this mode, passing a buffer of NULL will result in an invalid-argument error. d222 1 a222 1 =item int xds_getbuffer(xds_t* I, xds_scope_t I, void** I, size_t* I); d225 16 a240 16 the buffer currently used in the XDS context `xds'. The address of that buffer is stored in the location `buffer' points to; the length of the buffer's content will be stored in the location `buffer_len' points to. The `flag' argument may be set to either XDS_GIFT or XDS_LOAN. The first setting means that the buffer is now owned by the application and that XDS must not use it after this xds_getbuffer() call anymore; the library 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 `flag' to XDS_LOAN tells XDS that the application just wishes to peek into the buffer and will not modify it. The buffer is still owned (and used) by XDS. Please note that the loaned address returned by xds_getbuffer() may change after any other xds_xxx() d243 8 a250 9 The function will return XDS_OK (everything went fine) or XDS_ERR_INVALID_ARG (`xds', `buffer' or `buffer_len' are NULL or `flag' is invalid) signifying success or failure respectively. Please note: It is perfectly legal for xds_getbuffer() to return a buffer of NULL and a buffer length of 0! This happens when xds_getbuffer() is called for an XDS context before a buffer has been allocated. d252 1 a252 1 =item int xds_vencode(xds_t* I, const char* I, va_list I); d255 1 a255 1 encoding engines registered in XDS context `xds'. The parameter `fmt' d257 1 a257 1 encoded; the actual values are provided in the varadic parameter `args'. d259 2 a260 2 The format for `fmt' is simple: Just provide the names of the engines to be used for encoding the appropriate value(s) in `args'. Any non-legal d264 1 a264 1 int32 int32 int64 d268 1 a268 1 int32:int32:int64 d271 1 a271 1 register the engines in `xds' earlier. d273 26 a298 27 Every time xds_vencode() is called, it will append the encoded data at the end of the internal buffer stored in `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 `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 XML and 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: XDS_OK (everything worked fine), XDS_ERR_NO_MEM (failed to allocate or to resize the internal buffer), XDS_ERR_OVERFLOW (the internal buffer is too small but is not owned by us), XDS_ERR_INVALID_ARG (`xds' or `fmt' are NULL), XDS_ERR_UNKNOWN_ENGINE (an engine name specified in `fmt' is not registered in `xds'), XDS_ERR_INVALID_MODE (`xds' is initialized in decode mode), or XDS_ERR_UNKNOWN (the engine returned an unspecified error). d300 1 a300 1 =item int xds_encode(xds_t* I, const char* I, ...); d305 1 a305 1 =item int xds_vdecode(xds_t* I, const char* I, va_list I); d307 5 a311 5 This function is almost identical to xds_vencode(): It expects an XDS 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 d313 14 a326 15 corresponding `args' entry. But please note that the exact behavior of the decoding engines is not specified! The XML and 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: XDS_OK (everything went fine), XDS_ERR_INVALID_ARG (`xds' or `fmt' are NULL), XDS_ERR_TYPE_MISMATCH (the format string says the next value is of type $A$, but that's not what we found in the buffer), XDS_ERR_UNKNOWN_ENGINE (an engine name specified in `fmt' is not registered in `xds'), XDS_ERR_INVALID_MODE (`xds' has been initialized in encode mode), XDS_ERR_UNDERFLOW (an engine tried to read $n$ bytes from the buffer, but we don't have that much data left), or XDS_ERR_UNKNOWN (an engine returned an unspecified error). d328 1 a328 1 =item int xds_decode(xds_t* I, const char* I, ...); d337 22 a358 18 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 d361 7 a367 7 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. d371 22 a392 18 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 d397 4 a400 4 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 d403 1 a403 1 =head1 EXTENDING THE XDS LIBRARY d405 11 a415 12 This section demonstrates, how to write a `meta engine' and for the 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]; }; d418 5 a422 5 weird data types rather than the familiar ones like int, long, etc. The reason is that these data types have an undefined size. An 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 TRUE64 Unix, it will have a size of 64 bit. That is a problem d425 2 a426 1 even XDS cannot remedy. d431 22 a452 18 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 `mystruct' structure from the stack and then uses xds_encode() to handle all elements of `mystruct' separately -- which is fine, because these data types are supperted by XDS already. It is worth noting, though, that we refer to the other engines by name, meaning that these engines must be registered in `xds' by that name! d455 6 a460 6 not even need to know which engines are used to encode the actual values! If the user registeres the XDR engines under the appropriate names, `mystruct' will be encoded in XDR. If the user registeres the XML engines under the appropriate names, `mystruct' will be encoded in XML. Because of that property, we call such an engine a `meta engine'. d462 2 a463 2 Of coures you need not necessarily implement an engine as B engine: Rather than going through xds_encode(), it would be possible d465 3 a467 3 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. d476 40 a515 33 =item xds -- This is the 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 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 buffer -- This parameter points to the buffer the encoded data should be written to. In decoding mode, `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 buffer_size -- The number of bytes available in `buffer'. In encoding mode, this means `free space', in decoding mode, `buffer_size' determines how many bytes of encoded data are available in `buffer' for consumption. =item 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 `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 `buffer'; in decoding mode the variable determines how many bytes the engines has read from `buffer'. d517 3 a519 1 =item args -- This pointer points to an initialized varadic argument. d525 1 a525 1 xds.h: d529 23 a551 1 =item XDS_OK -- No error. d553 4 a556 1 =item XDS_ERR_NO_MEM -- Failed to allocate required memory. d558 1 a558 18 =item XDS_ERR_OVERFLOW -- The buffer is too small to hold all encoded data. The callback may set `*used_buffer_size' to the number of bytes it needs in `buffer', thereby giving the framework a hint by how many bytes it should enlarge the buffer before trying the engine again, but just leaving `*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 XDS_ERR_INVALID_ARG -- Unexpected or incorrect parameters. =item 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. XDR, for example, does not. =item 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 `buffer'/'buffer_size' provides less. d560 7 a566 2 =item XDS_ERR_UNKNOWN -- Any other reason to fail than those listed before. Catch all ... d570 1 a570 1 Let's take a look at the corresponding decoding engine now: d572 17 a588 15 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 = va_arg(*args, struct mystruct*); rc = xds_decode(xds, "int32 int64 uint32 octetstream", &(ms->small), &(ms->big), &(ms->positive), &tmp, &i); if (rc == XDS_OK) { d590 1 a590 1 memmove(ms->text, tmp, i); d592 1 a592 1 rc = XDS_ERR_TYPE_MISMATCH; d594 3 a596 9 } 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. d598 5 a602 2 A complete example program encoding and decoding `mystruct' can be found at docs/extended.c in the distribution. d604 2 a605 1 =head1 SO ALSO d607 1 a607 1 =over 4 d609 1 a609 1 =item RFC 1832: `XDR: External Data Representation Standard', d612 1 a612 1 =item XML-RPC Home Page: http://www.xmlrpc.org/ d614 1 a614 1 =back a615 1 =cut @ 1.13 log @bump copyright year @ text @d34 1 a34 1 xds - OSSP Extensible Data Serialization d38 11 d51 11 a61 11 The purpose of XDS is to encode data in a way that allows this data to be exchanged between different computer systems. Assume you'd want to transfer the value $1234 from host A to host B. Then you would encode it using XDS, transfer the encoded data over the network, and decode the value again at the other end. Every program that follows this process will read the correct value no matter what native representation is used internally. XDS consists of three components: The generic encoding and decoding framework, a set of engines to encode and decode values in a certain format, and a run-time context, which is used to manage buffers, d64 14 a77 13 In order to use the library, the first thing the developer has to do is to create a valid XDS context by calling xds_init(). The routine 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 XDS context has been obtained, the routine 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. These routines 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. d80 55 a134 55 routines 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 can be handled by the library. This means, that 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 xds_engine_t interface defined in xds.h. In particular, it is possible to register meta engines. That 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 will encode an unsigend integer into the XDR format, decode it back into the native host format, and compare the result to make sure it is the original value again: #include #include #include int main() { xds_t* xds; xds_uint32_t uint32 = 0x12345678; xds_uint32_t new_uint32; char* buffer; size_t buffer_size; if ((xds = xds_init(XDS_ENCODE)) == NULL || xds_register(xds, "uint32", &xdr_encode_uint32, NULL) != XDS_OK || xds_encode(xds, "uint32", uint32) != XDS_OK || xds_getbuffer(xds, XDS_GIFT, (void**)&buffer, &buffer_size) != XDS_OK) { printf("Encoding failed.\n"); exit(1); } xds_destroy(xds); if ((xds = xds_init(XDS_DECODE)) == NULL || xds_register(xds, "uint32", &xdr_decode_uint32, NULL) != XDS_OK || xds_setbuffer(xds, XDS_LOAN, buffer, buffer_size) != XDS_OK || xds_decode(xds, "uint32", &new_uint32) != XDS_OK) { printf("Decoding failed.\n"); exit(1); } xds_destroy(xds); if (uint32 == new_uint32) printf("OK\n"); else printf("Failure\n"); d136 1 a136 2 return 0; } d138 2 a139 1 =head1 THE XDS FRAMEWORK d143 8 a150 1 =item xds_t* xds_init(xds_mode_t I); d152 2 a153 18 This routine creates and initializes a context for use with the XDS library. The `mode' parameter may be either XDS_ENCODE or XDS_DECODE, depending on whether you want to encode or to decode data. If successful, xds_init() returns a pointer to the XDS context structure. In case of failure, xds_init() returns NULL and sets errno to ENOMEM (failed to allocate internal memory buffers) or EINVAL (`mode' parameter was invalid). A context obtained from xds_init() must be destroyed by xds_destroy() when it is not needed any more. =item void xds_destroy(xds_t* I); xds_destroy() will destroy an XDS context 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. d155 1 a155 1 =item int xds_register(xds_t* I, const char* I, xds_engine_t I, void* I); d157 9 a165 2 This routine will register an engine in the provided XDS context. An `engine' is potentially any function that fullfils the following d168 8 a175 11 int engine(xds_t* xds, void* engine_context, void* buffer, size_t buffer_size, size_t* used_buffer_size, va_list* args); By calling xds_register(), the engine `engine' will be registered under the name `name' in the XDS context `xds'. The last parameter `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 NULL should be specified here. d204 1 a204 1 This routine allows the user to control XDS' buffer handling: Calling it d227 1 a227 1 This routine is the counterpart to xds_setbuffer(): It will get d246 1 a246 1 The routine will return XDS_OK (everything went fine) or d258 1 a258 1 This routine will encode one or several values using the appropriate d307 1 a307 1 This routine is basically identical to xds_vencode(), only that d312 1 a312 1 This routine is almost identical to xds_vencode(): It expects an d336 1 a336 1 This routine is basically identical to xds_vdecode(), only that d362 1 a362 1 Please note that the routines xdr_decode_octetstream() and d392 1 a392 1 Please note that the routines xml_decode_octetstream() and d409 6 a414 6 { xds_int32_t small; xds_int64_t big; xds_uint32_t positive; char text[16]; }; d430 10 a439 10 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)); } d545 22 a566 22 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 = va_arg(*args, struct mystruct*); 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; } @ 1.12 log @Completed the documentation of (xml|xdr)_(en|de)code_(float|double)(). @ text @d3 2 a4 2 ## Copyright (c) 2001 The OSSP Project (http://www.ossp.org/) ## Copyright (c) 2001 Cable & Wireless Deutschland (http://www.cw.com/de/) @ 1.11 log @Updated the documentation to include the xdr_*_float() routines and to include the sizes for both native and encoded float and double values. @ text @d376 4 a379 4 xml_encode_float() xds_float_t 4 bytes ? bytes xml_decode_float() xds_float_t* ? bytes 4 bytes xml_encode_double() xds_double_t 8 bytes ? bytes xml_decode_double() xds_double_t* ? bytes 8 bytes @ 1.10 log @First attempt at a manual page. :-) @ text @d346 4 a349 2 xdr_encode_double() xds_double_t ? bytes ? bytes xdr_decode_double() xds_double_t* ? bytes ? bytes d376 4 a379 2 xml_encode_double() xds_double_t ? bytes ? bytes xml_decode_double() xds_double_t* ? bytes ? bytes @ 1.9 log @Hhmm... who has introduced ossp.com?! Our project's domain is ossp.org, of course. @ text @d5 1 a5 1 ## d8 1 a8 1 ## d13 2 a14 2 ## ## THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED d34 1 a34 1 xds - OSSP eXtensible Data Serialization d40 417 d459 33 a491 1 =item xds_t* B(xds_mode_t I); d493 2 a494 107 Valid settings for I are B and B. If successful, a valid handle is returned -- B otherwise. If the routine fails, the system variable B is set apropriately. =item void B(xds_t* I); Free all internally allocated resources associated with this context. I must be a handle obtained by calling B. =item int B(xds_t* I, const char* I, xds_engine_t I, void* I); Register the function I as formatting engine in context I under the name I. The function must have the following prototype: int my_engine(xds_t* xds, void* engine_context, void* buffer, size_t buffer_size, va_list args); It must gather its values from I and encode/decode them into I. The encoded/decoded representation must not take up more than I byte of memory, because that's the maximum I can hold. If the buffer is too small, I must return B. In case of no error, I must return the number of bytes it has written to the buffer. (Note that all xds error defines are smaller than >0.) The variable I is passed through to the function every time it is called; it is not touched in any way by the xds library. A valid name I for a callback function consists of an arbitrary number of characters from the class [a-zA-Z0-9_-]. =item int B(xds_t* I, const char* I); Remove encoding/decoding engine I from context I. The function will return B if successful and B if I is not a registered engine. =item int B(xds_t* I, xds_scope_t I, void* I, size_t I); Encoding mode: Set internal buffer used in context I to I. The buffer has a capacity of I byte. I may be set to B or B. A "loaned" buffer is one that is owned by the application; xds will use it, but it will not B the buffer nor will it try to B it if it's too small. A buffer given to xds as a "gift" is henceforth owned by xds and may be Bd or Bed as the library sees fit. If I is B, I must be a pointer obtained from calling the B API. Calling B with a I of B will cause the xds library to allocate a buffer of its own. I is ignored in this case. Decoding mode: I contains the encoded representation of the data to be used for following B calls. The encoded data is I byte long. Unlike in encoding mode, such a buffer is not modified, hence there is no need to extend the buffer. If I is set to B, the library will B I when the context is destroyed. B returns one of the following codes signifying success or failure: B (everything alright), B (failed to allocate new internal buffers), and B (arguments don't make sense). =item int B(xds_t* I, xds_scope_t flag, void** buffer, size_t* buffer_size); This routine will write the address and size of the internal buffer in context I to I and I. The I parameter determines who owns the buffer after that; setting I to B means that the buffer is owned by the xds library and that the user may not rely on its contents still being there after another xds library function call. Furthermore, calling B will flush the registered buffer, meaning that coming B calls will start at the beginning and potentially overwrite the buffer contents. Setting I to B means that the returned buffer is owned by the application programmer from now on, it is no longer modified or used in any way by the library. The application must B the buffer when it's not needed anymore. =item int B(xds_t* I, const char* I, ...); The B function call will encode an arbitrary number of values into the chosen representation. The syntax is very similar to B: As parameters, it requires the I handle obtained from B, a format string I describing the following value parameters, and an arbitrary number of actual values. The format string lists the names of the callback functions to be used in order to format the values; it has the format "name name ...". The names are delimited by any number of characters any of which is not part of the character set allowed for function names here. Hence, you can delimit the names by blanks, tabs, dollar signs or pretty much anyting your want. B will return either B (everything OK), B (failed allocating memory for intenal buffering), B (can't expand internal buffer because it's owned by the application), B (parameters don't make sense), B (specified callback can't handle this data type), and B (unknown call back name used in I). =item int B(xds_t* I, const char* I, ...); Like B, only the other way round. d496 1 a496 1 =item int B(xds_t* I, const char* I, va_list I); d498 71 a568 1 See B. d570 2 a571 1 =item int B(xds_t* I, const char* I, va_list I); d573 1 a573 1 See B. @ 1.8 log @Use the license consistently. @ text @d7 1 a7 1 ## library which can be found at http://www.ossp.com/pkg/xds/. @ 1.7 log @First cut of the ruthless style adjustments to OSSP XDS: o adjust source tree to follow OSSP source tree style by heavily combining sources into smaller sets (needs more work when still missing parts are added later) o automatic re-indentation of sources with GNU indent (still needs manual review and adjustments; will follow) These two heavy steps were mostly done automatically with the help of two helper scripts written in Perl. So expect more manual adjustments to follow... @ text @d1 29 d34 1 a34 1 xds - eXtensible Data Serialization a36 1 @ 1.6 log @Moved POD documentation into the docs directory. @ text @@ 1.5 log @The correct name is "extensible" rather than "extandable". @ text @@ 1.4 log @Documented the need to free() a buffer obtained via xds_getbuffer with the XDS_GIFT flag set. @ text @d5 1 a5 1 xds - eXtendable Data Serialization @ 1.3 log @Documented the return code of registered engines incorrectly: The enigne does not return XDS_OK but the number of bytes it wrote to the buffer. @ text @d94 2 a95 1 used in any way by the library. @ 1.2 log @xds_register: - Documented valid characters for callback names. xds_setbuffer: - Documented return codes. - Clearified requirement of library-owned buffers coming from malloc. xds_encode: - Added documentation. @ text @d39 5 a43 4 B. In case of no error, I must return B. The variable I is passed through to the function every time it is called; it is not touched in any way by the xds library. @ 1.1 log @Added preliminary documentation for xds_init(), xds_destroy(), xds_register(), xds_unregister(), xds_setbuffer(), and xds_getbuffer(). @ text @d44 3 d62 4 a65 4 B, I must be a pointer obtained from calling B or a comparable system routine. Calling B with a I of B will cause the xds library to allocate a buffer of its own. I is ignored in this case. d74 5 d95 1 d97 20 a116 1 =item int B(xds_t* I, const char* I, ...); d120 2 d124 2 d127 2 @