Generated C Function Format and Calling Parameters

The format of each generated decode function name is as follows:

   asn1AvnDec_[<prefix>]<prodName>

where <prodName> is the name of the ASN.1 production for which the function is being generated and <prefix> is an optional prefix that can be set via a configuration file setting. The configuration setting used to set the prefix is the <typePrefix> element. This element specifies a prefix that will be applied to all generated typedef names and function names for the production.

The decode function declaration is as follows:

   status = asn1AvnDec_<name> (OSCTXT* pctxt, <name> *pvalue);

In this declaration, <name> denotes the prefixed production name defined above.

The pctxt argument is used to hold a context pointer to keep track of decode parameters. This is a basic "handle" variable that is used to make the function reentrant so it can be used in an asynchronous or threaded application. The user is required to supply a pointer to a variable of this type declared somewhere in his or her program. The variable must be initialized using the rtInitContext run-time function before use.

The pvalue argument is a pointer to a variable of the generated type that will receive the decoded data.

The function result variable status returns the status of the decode operation. The return status will be zero if decoding is successful or negative if an error occurs. Error status codes are defined in rtsrc/asn1ErrCodes.h and rtxsrc/rtxErrCodes.h and are listed in Appendix A of the C/C++ Common Functions Reference Manual.

When table constraints are involved, the decode function for some types will have extra parameters. This will happen when the table-oonstrained type is contained within an ASN.1 type that is nested within another type, and will affect the signatures of the decode functions of the nested types. It would be highly unusual for these functions to be called directly by users, however.

Procedure for Calling C Decode Functions

This section describes the step-by-step procedure for calling a C AVN decode function. This method must be used if C code generation was done. This method can also be used as an alternative to using the control class interface if C++ code generation was done.

Before any decode function can be called; the user must first initialize a context variable. This is a variable of type OSCTXT. This variable holds all of the working data used during the decoding 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 as follows:

   OSCTXT ctxt;

   if (rtInitContext (&ctxt) != 0) {
      /* initialization failed, could be a license problem */
      printf (“context initialization failed (check license)\n”);
      return –1;
   }

The next step is the provide the data to be decoded. If your data is in a buffer, you can call rtxInitContextBuffer. Alternatively, you can create a stream, e.g. by calling rtxStreamFileCreateReader.

A decode function can then be called to decode the message. If the return status indicates success, the C variable that was passed as an argument will contain the decoded message contents. Note that the decoder may have allocated dynamic memory and stored pointers to objects in the C structure. After processing on the C structure is complete, the run-time library function rtxMemFree should be called to free the allocated memory.

A program fragment that could be used to decode an employee record is as follows:

   #include employee.h          /* include file generated by ASN1C */
   #include "rtxsrc/rtxStreamFile.h"
   
   main ()
   {
      OSCTXT    ctxt;
      PersonnelRecord employee;
      int stat;

      .. logic to read message into msgbuf ..

      /* Step 1: Initialize a context variable for decoding */

      if (rtInitContext (&ctxt) != 0) {
         /* initialization failed, could be a license problem */
         printf (“context initialization failed (check license)\n”);
         return –1;
      }

      stat = rtxStreamFileCreateReader (&ctxt, filename);
      if (0 != stat) {
         rtxErrPrint (&ctxt);
         rtFreeContext (&ctxt);
         return stat;
      }


      /* Step 2: Call decode function. */
      stat = asn1AvnDec_PersonnelRecord (&ctxt,
                                      &employee);

      /* Step 3: Check return status */
      if (status == 0)
      {
         process received data in ‘employee’ variable..

         /* Remember to release dynamic memory when done! */

         rtxMemFree (&ctxt);
      }
      else
         error processing...
      }
      }

To decode from a buffer, use rtxInitContextBuffer(pctxt, msgbuf, msgbuflen) to specify the buffer to decode from.

To decode from a stream, you need to create a stream object within the context (OSCTXT). This object is an abstraction of the output device to which the data is to be encoded and is initialized by calling one of the following functions:

  • rtxStreamFileOpen

  • rtxStreamFileAttach

  • rtxStreamSocketAttach

  • rtxStreamMemoryCreate

  • rtxStreamMemoryAttach

The flags parameter of these functions should be set to OSRTSTRMF_INPUT to indicate an input stream is being created (see the C/C++ Common Run-Time Library Reference Manual for a full description of these functions).

A simpler method for opening a stream is to use one of the following *CreateReader funtions, as in the previous example:

  • rtxStreamFileCreateReader

  • rtxStreamMemoryCreateReader

  • rtxStreamSocketCreateReader

When you are finished with decoding from a stream, close it by invoking the rtxStreamClose function.

Decoding Multiple Records using C Decoder

If the input contains multiple records, you will need a loop that determines whether to decode another record or not. An example is provided in c/sample_avn/employee_loop.

In the sample, observe the following points:

  • rtxTxtSkipWhitespace is used to skip whitespace that might appear between records.

  • rtxCheckInputBuffer is used to check whether more input is present beyond that whitespace.

  • rtxMemReset is used to allow memory allocated by the current decode operation to be reused for the next decode operation (doing this is optional).