Procedure for Calling a Generated C Encode Function

The encode function generated for an XSD global element definition is the normal entry point for encoding an EXI message. The general procedure for calling a global element encode function is as follows:

  1. Prepare a context variable for encoding

  2. Initialize an encode message buffer or stream to receive the encoded data

  3. Populate the data variable with data to be encoded

  4. Call the appropriate compiler-generated encode function to encode the message

  5. If a message buffer was used, get the start pointer and length of the encoded message

Before a C EXI encode function can be called, the user must initialize a context variable. This is a variable of type OSCTXT. This variable holds all of the working data used during the encoding of a message. The context variable is declared as a normal automatic variable within the top-level calling function. It must be initialized before use. This can be accomplished by using the rtEXIInitContext function:

       OSCTXT ctxt;/* context variable */
       stat = rtEXIInitContext (&ctxt);
       if (0 != stat) {
          printf ("Context initialization failed.\n");
          rtxErrPrint (&ctxt);
          return stat;
       }

It is also possible to call the base context initialization function rtxInitContext followed by the rtEXIInitCtxtAppInfo to initialize the EXI subcontext. This can be useful if multiple encoding rules are used (for example, XML and EXI).

The next step is to specify an encode buffer or stream into which the message will be encoded. This is accomplished by calling the rtxCtxtSetBufPtr run-time function (for a message buffer) or one of the rtxStream functions to create an output stream. If a message buffer is to be used, the user has the option to either pass the address of a buffer and size allocated in his or her program (referred to as a static buffer), or set these parameters to zero and let the encode function manage the buffer memory allocation (referred to as a dynamic buffer). Better performance can normally be attained by using a static buffer because this eliminates the high-overhead operation of allocating and reallocating memory.

After initializing the context and populating a variable of the structure to be encoded, an encode function can be called to encode the message. If the return status indicates success, the run-time library function rtxCtxtGetMsgPtr can be called to obtain the start address of the encoded message. In the static case, this is simply the start address of the static buffer. In the dynamic case, this function will return the pointer to the allocated memory buffer. The memory allocated for a dynamic buffer will be freed when either the context is freed (rtxFreeContext) or all memory associated with the context is released (rtxMemFree) or the buffer memory is explicity released (rtxMemFreePtr).

In the stream case, the pointer to the encoded message generally cannot be obtained since the message has already been written to the stream. The stream should be closed after encoding is complete by calling the rtxStreamClose function. This should be called before calling the rtxFreeContext function.

A program fragment that could be used to encode a notebook record is as follows:

   #include "notebook.h"

   int main (int argc, char** argv)
   {
      notebook_ELEM* pdata;
      OSCTXT       ctxt;
      int          stat;
      ...

      /* Init context */

      stat = rtEXIInitContext (&ctxt);
      if (0 != stat) {
         printf ("Context initialization failed.\n");
         rtxErrPrint (&ctxt);
         return stat;
      }

      /* Populate structure of generated type (note: this uses a generated
         random test data function) */

      pdata = Test_notebook (&ctxt);

      /* Encode (this uses a dynamic buffer) */

      stat = rtxCtxtSetBufPtr (&ctxt, 0, 0);

      if (0 == stat)
         stat = EXIEnc_notebook (&ctxt, pdata);

      if (0 != stat) {
         printf ("Encoding failed\n");
         rtxErrPrint (&ctxt);
         return stat;
      }

      pMsgBuf = rtxCtxtGetMsgPtr (&ctxt);
      msglen  = rtxCtxtGetMsgLen (&ctxt);

      ... logic to process encoded message (write to file, etc.) ...
   
      rtxFreeContext (&ctxt);

This example uses a dynamic message buffer. The encoded binary data is accessed using the rtxCtxtGetMsgPtr and rtxCtxtGetMsgLen functions.