Generated C Function Format and Calling Parameters

The format of the name of each generated encode function is as follows:

   asn1AvnEnc_[<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 calling sequence for each encode function is as follows:

   ret = asn1AvnEnc_<name> (OSCTXT* pctxt,
                       <name>* pvalue);

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

The pctxt argument is used to hold a context pointer to keep track of encode 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 should be initialized using the rtInitContext run-time library function (see the C/C++ Common Run-Time Library Reference Manual for a complete description of this function).

The pvalue argument holds a pointer to the data to be encoded and is of the type generated from the ASN.1 production.

The function result variable ret returns 0 for success or an error status code if encoding fails. Error status codes are defined in rtsrc/asn1ErrCodes.h and rtxsrc/rtxErrCodes.h.

Procedure for Calling C Encode Functions

This section describes the step-by-step procedure for calling a C AVN encode 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 encode function can be called the user must first initialize an encoding context. 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 rtInitContext function 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 set up the destination for the encoded message. You specify a dynamic or static buffer by using rtxInitContextBuffer, or a stream by calling, e.g., rtxStreamFileCreateWriter.

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 encoding is successful and was done into a dynamic buffer, you can use rtxCtxtGetMsgPtr to get a pointer to the message. Note that the buffer is not a null-terminated string. If you want to treat the buffer as a null-terminated string, you can write a null-terminator using rtxWriteBytes.

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

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

   int main ()
   {
       int       stat;
       OSCTXT    ctxt;
       PersonnelRecord  employee; /* typedef generated by ASN1C */
       const char* filename = "message.txt";
       
       /* Step 1: Initialize the context and create a file stream */

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

       stat = rtxStreamFileCreateWriter (&ctxt, filename);
       if (stat < 0) {
          printf ("Create file output stream failed\n");
          rtxErrPrint (&ctxt);
          rtFreeContext (&ctxt);
          return stat;
       }

       /* Step 2: Populate the structure to be encoded */

       employee.name.givenName = "SMITH";
       ...

       /* Step 3: Call the generated encode function */

       stat = asn1AvnEnc_PersonnelRecord (&ctxt, &employee);

       /* Step 4: Check the return status */

       if (stat == 0) {
          printf ("Output file written successfully.\n");
       }
       else {
          rtxErrPrint (&ctxt);
          return stat;
       }
    }

To encode to a static buffer, you simply pass the buffer and its length to rtxInitContextBuffer like so:

   stat = rtxInitContextBuffer(pctxt, mybuf, mybuflen);
   if (stat != 0) /* Error! */                  
               

To encode to a dynamic buffer, pass a null buffer and 0 length to rtxInitContextBuffer:

   stat = rtxInitContextBuffer(pctxt, 0, 0);
   if (stat != 0) /* Error! */                  
               

To encode to a stream, you must 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 the OSRTSTRMF_OUTPUT constant value to indicate an output stream is being created (see the C/C++ Common Run-Time Library Reference Manual for a full description of these functions).

It is also possible to use a simplified form of these function calls to create a writer interface to a file, memory, or socket stream (as in the previous example):

  • rtxStreamFileCreateWriter

  • rtxStreamMemoryCreateWriter

  • rtxStreamSocketCreateWriter

When you are finished encoding to a stream, close it by calling rtxStreamClose