Procedure for Calling C Decode Functions

This section describes the step-by-step procedure for calling a C PER 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.

Unlike BER, the user must know the ASN.1 type of a PER 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 a PER decode function can be called, the user must first initialize a context block structure. The context block is initialized by either calling the rtNewContext function (to allocate a dynamic context block), or by calling rtInitContext to initialize a static block. The pu_setBuffer function must then be called to specify a message buffer that contains the PER-encoded message to be decoded. This function also allows for the specification of aligned or unaligned decoding.

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 context is freed.

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 msgbuf[1024];
      ASN1TAG msgtag;
      int msglen, stat;
      OSCTXT ctxt;
      OSBOOL aligned = TRUE;
      PersonnelRecord employee;

      .. logic to read message into msgbuf ..

      /* This example uses a static context block */

      /* step 1: prepare the context block */

      stat = rtInitContext (&ctxt);

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

      pu_setBuffer (&ctxt, msgbuf, msglen, aligned);

      /* step 2: initialize the data variable */

      asn1Init_PersonnelRecord (&employee);

      /* step 3: call the decode function */

      stat = asn1PD_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 pu_setBuffer call above with one of the rtxStream*CreateReader functions to set up a file, memory, or socket stream as input.