Procedure for Calling C Decode Functions

This section describes the step-by-step procedure for calling a C OER decode function.

Unlike BER, the user must know the ASN.1 type of an OER message before it can be decoded. This is because the type cannot be determined at run-time. There are no embedded tag values to reference to determine the type of message received.

The following are the basic steps in calling a compiler-generated decode function:

  1. Prepare a context variable for decoding

  2. Initialize the data structure to receive the decoded data

  3. Call the appropriate compiler-generated decode function to decode the message

  4. Free the context after use of the decoded data is complete to free allocated memory structures

Before an OER decode function can be called, the user must first initialize a context block structure. The context block is initialized by calling the rtInitContext function.

The user then has the option to do stream-based or memory-based decoding. If stream-based is to be done, the user must call a rtxStreamCreateReader function for the type of stream from which data will be read. For example, if the user wishes to read data from a file, the rtxStreamFileCreateReader function would be called.

To do memory-based decoding, the rtxInitContextBuffer function would be called. The message to be decoded must reside in memory. The arguments to this function would then specify the message buffer in which the data to be decoded exists.

The variable that is to receive the decoded data must then be initialized. This can be done by either initializing the variable to zero using memset, or by calling the ASN1C generated initialization function.

A decode function can then be called to decode the message. If the return status indicates success (0), then the message will have been decoded into the given ASN.1 type variable. The decode function may automatically allocate dynamic memory to hold variable length variables during the course of decoding. This memory will be tracked in the context structure, so the programmer does not need to worry about freeing it. It will be released when the either the context is freed or explicitly when the rtxMemFree or rtxMemReset function is called.

The final step of the procedure is to free the context block. This must be done regardless of whether the block is static (declared on the stack and initialized using rtInitContext), or dynamic (created using rtNewContext). The function to free the context is rtFreeContext.

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

   #include employee.h           /* include file generated by ASN1C */

   main ()
   {
      OSOCTET* pMsgBuf;
      int len, stat;
      OSCTXT ctxt;
      PersonnelRecord employee;
      const char* filename = "message.dat";

      /* step 1: initialize context */

      stat = rtInitContext (&ctxt);

      if (stat != 0) {
         printf (“rtInitContext failed (check license)\n“);
         rtErrPrint (&ctxt);
         return stat;
      }

      /* step 2: read input file into a memory buffer */

      stat = rtxFileReadBinary (&ctxt, filename, &pMsgBuf, &len);
      if (0 == stat) {
         stat = rtxInitContextBuffer (&ctxt, pMsgBuf, len);
      }
      if (0 != stat) {
         rtxErrPrint (&ctxt);
         rtFreeContext (&ctxt);
         return stat;
      }

      /* step 3: initialize the data variable */

      asn1Init_PersonnelRecord (&employee);

      /* step 4: call the decode function */

      stat = OERDec_PersonnelRecord (&ctxt, &employee);

      if (stat == 0)
      {
         process received data..
      }
      else {
         /* error processing... */
         rtxErrPrint (&ctxt);
      }

      /* step 4: free the context */

      rtFreeContext (&ctxt);
   }

An input stream can be used instead of a memory buffer as the data source by replacing the rtxFileReadBinary code block above with one of the rtxStreamCreateReader functions to set up a file, memory, or socket stream as input.