OSSP CVS Repository

ossp - Check-in [4294]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 4294
Date: 2001-Aug-08 15:12:28 (local)
2001-Aug-08 13:12:28 (UTC)
User:simons
Branch:
Comment: Added the missing chapter about extending the library.
Tickets:
Inspections:
Files:
ossp-pkg/xds/docs/libxds.tex      1.3 -> 1.4     197 inserted, 10 deleted

ossp-pkg/xds/docs/libxds.tex 1.3 -> 1.4

--- libxds.tex   2001/08/07 14:41:06     1.3
+++ libxds.tex   2001/08/08 13:12:28     1.4
@@ -1,6 +1,6 @@
 % -*- mode: LaTeX; fill-column: 75; -*-
 %
-% $Id: libxds.tex,v 1.3 2001/08/07 14:41:06 simons Exp $
+% $Id: libxds.tex,v 1.4 2001/08/08 13:12:28 simons Exp $
 %
 \documentclass[a4paper,10pt,pointlessnumbers,bibtotoc]{scrartcl}
 \usepackage[dvips,xdvi]{graphicx}
@@ -548,6 +548,176 @@
 \section{Extending the XDS library}
 \label{meta engines}
 
+Now that we know how primitive data types can be encoded and decoded, let's
+write a ``meta engine'' that will handle complex data structures. For the
+example, we'll use the structure ``mystruct'', which is defined as follows:
+
+\begin{quote}
+\begin{verbatim}
+struct mystruct
+    {
+    xds_int32_t   small;
+    xds_int64_t   big;
+    xds_uint32_t  positive;
+    char          text[16];
+    };
+\end{verbatim}
+\end{quote}
+
+In order to encode an instance of this structure, we first write an
+encoding engine:
+
+\begin{quote}
+\begin{verbatim}
+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));
+    }
+\end{verbatim}
+\end{quote}
+
+This engine does nothing but take the address of the ``mystruct'' instance
+from the stack and then use xds\_encode() to handle all elements of
+``mystruct'' separately --- which is fine, because these data types are
+supperted by libxds 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!
+
+What is very nice, though, is the fact that this encoding engine does not
+even need to know which formatting engines are used to encode the actual
+values! If the user registeres the XDR engines under the apropriate names,
+``mystruct'' will be encoded in XDR. If the user registeres the XML engines
+under the apropriate names, ``mystruct'' will be encoded in XML. Because of
+that property we call such an engine a ``meta engine''.
+
+Of coures you need not necessarily implement an engine like that: Rather
+than going through xds\_encode(), it would be possible to execute the
+apropriate encoding engines directly. This had the advantage of not
+depending on those engines being registered at all, but it would make the
+meta engine depend on the elementary engines unnecessarily.
+
+One more word about the engine syntax and semantics: As has been mentioned
+earlier, any function that adheres to the shown above is potentially a
+formatting engine. These parameters have the following meaning:
+
+\begin{itemize}
+
+\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\_en\-code() again like we did in the example
+engine shown before.
+
+\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 may obviously neglect this parameter if they don't need a context
+of their own --- all engines included in this distribution do so.
+
+\item buffer --- This parameter points to the buffer in which the encoded
+data should be written. 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 that are 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 consumation.
+
+\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 actually used in ``buffer''. A callback encoding, say, an
+int32 number into a 8 byte text representation would set the
+used\_buffer\_size to 8, for instance:
+\begin{quote}
+\begin{verbatim}
+*used_buffer_size = 8;
+\end{verbatim}
+\end{quote}
+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''.
+
+\item args --- This pointer points to an initialized varadic argument. Use
+the standard C macro va\_arg() to fetch the actual data.
+
+\end{itemize}
+
+A callback may return any of the following return codes as defined in
+\textsf{xds.h}:
+
+\begin{itemize}
+\item XDS\_OK --- No error.
+
+\item XDS\_ERR\_NO\_MEM --- Failed to allocate required memory.
+
+\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 parameters.
+
+\item XDS\_ERR\_TYPE\_MISMATCH --- This return code should be returned in
+decoding mode in case the decoding engine realizes that the data it is
+decoding does not fit what it's 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 should be returned
+when an engine needs, say, 4 byte of data in order to decode a value but
+``buffer''/''buffer\_size'' provides less.
+
+\item XDS\_ERR\_UNKNOWN --- Any other reason to fail than those listed
+before.
+
+\end{itemize}
+
+Let's take a look at the corresponding decoding engine now:
+
+\begin{quote}
+\begin{verbatim}
+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)
+        {
+        assert(i == sizeof(ms->text));
+        memmove(ms->text, tmp, i);
+        free(tmp);
+        }
+    return rc;
+    }
+\end{verbatim}
+\end{quote}
+
+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 \textsf{malloc()}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 ``mystruct'' can be found
+at \textsf{docs/\-extended.c} in the distribution.
+
 \section{The XDS Framework}
 \label{xds}
 
@@ -602,12 +772,12 @@
 engine name component.
 
 xds\_register() may return the following return codes: \textsf{XDS\_OK}
-        (everything went fine; the engine is registered now),
+        (everything went fine; the engine is registered now),
 \textsf{XDS\_ERR\_INVALID\_ARG} (either ``xds'', ``name'', or ``engine''
-        are \textsf{NULL} or ``name'' contains illegal characters for an engine
-        name), or
+        are \textsf{NULL} or ``name'' contains illegal characters for an engine
+        name), or
 \textsf{XDS\_ERR\_NO\_MEM} (failed to allocate internally required
-        buffers).
+        buffers).
 
 \subsection{int xds\_unregister(xds\_t*~\underline{xds}, const~char*~\underline{name});}
 
@@ -775,7 +945,7 @@
 \label{xdr}
 
 \begin{tabular}{|c|c|c|c|} \hline
-\bf Function Name     & \bf Expected ``args'' Data Type & \bf Input Size & \bf Output Size \\ \hline
+\bf Function Name     & \bf Expected ``args'' Datatype & \bf Input & \bf Output \\ \hline
 xdr\_encode\_uint32()      & xds\_uint32\_t   & 4 byte   & 4 byte \\
 xdr\_decode\_uint32()      & xds\_uint32\_t*  & 4 byte   & 4 byte \\[1ex]
 xdr\_encode\_int32()       & xds\_int32\_t    & 4 byte   & 4 byte \\
@@ -791,14 +961,22 @@
 xdr\_encode\_string()      & char*            & variable & variable \\
 xdr\_decode\_string()      & char**           & variable & variable \\ \hline
 \end{tabular}
+\medskip
+
+Please note that the routines xdr\_decode\_octetstream() and
+xdr\_decode\_string() return a pointer to a buffer holding the decoded
+data. This buffer has been allocated with \textsf{malloc()} and must be
+\textsf{free()}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.
 
 \section{The XML Engines}
 \label{xml}
 
-\subsection{Encoding engines}
-
 \begin{tabular}{|c|c|c|c|} \hline
-\bf Function Name     & \bf Expected ``args'' Data Type & \bf Input Size & \bf Output Size \\ \hline
+\bf Function Name     & \bf Expected ``args'' Datatype & \bf Input & \bf Output \\ \hline
 xml\_encode\_uint32()      & xds\_uint32\_t   & ?? byte  & ?? byte \\
 xml\_decode\_uint32()      & xds\_uint32\_t*  & ?? byte  & ?? byte \\[1ex]
 xml\_encode\_int32()       & xds\_int32\_t    & ?? byte  & ?? byte \\
@@ -814,8 +992,17 @@
 xml\_encode\_string()      & char*            & variable & variable \\
 xml\_decode\_string()      & char**           & variable & variable \\ \hline
 \end{tabular}
+\medskip
+
+Please note that the routines xml\_decode\_octetstream() and
+xml\_decode\_string() return a pointer to a buffer holding the decoded
+data. This buffer has been allocated with \textsf{malloc()} and must be
+\textsf{free()}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.
 
-\newpage
 \begin{thebibliography}{xxx}
 
 \bibitem{xdr} RFC 1832: ``XDR: External Data Representation Standard'',

CVSTrac 2.0.1