General Procedure for Table Constraint Decoding

The general procedure to decode an ASN.1 message with table constraints is the same as without table constraints. The only difference will exist in the decoded data for open type fields within the message. In this case, the Asn1Object / Asn1TObject’s decoded member variable will contain the original decoded type and the encoded member variable will contain the original data in encoded form.

Refer to the BER/DER/PER decoding procedure for further information.

The procedure to retrieve the value for open type fields is as follow:

  1. Check the possible Type in the Information Object Set from index element value.

  2. Assign or cast the Asn1Object.decoded member variable ( void* ) to the result type.

  3. The Asn1Object.encoded field will hold the data in encoded form.

For the above complete example, the Invoke type’s argument element will be decoded as one of the types in the SupportedAttributes information object set (i.e. either as a VisibleString or INTEGER type). If the SupportedAttributes information object set is extensible, then the argument element may be of a type not defined in the set. In this case, the decoder will set the Asn1Object.encoded field as before but the Asn1Object.decoded field will be NULL indicating the value is of an unknown type.

A C++ program fragment that could be used to decode the Invoke example is as follows:

   #include Test.h //           include file generated by ASN1C

   main ()
   {
      OSOCTET msgbuf[1024];
      ASN1TAG msgtag;
      int msglen, status;

      /* step 1: logic to read message into msgbuf */
      ...

      /* step 2: create decode buffer and msg data type */

      ASN1BERDecodeBuffer decodeBuffer (msgbuf, len);

      ASN1T_Invoke msgData;
      ASN1C_Invoke invoke (decodeBuffer, msgData);

      /* step 3: call decode function */

      if ((status = invoke.Decode ()) == 0)
      {
         // decoding successful, data in msgData
         // use key field value to set type of message data
         ASN1OBJID oid1[] = { 3, { 0, 1, 1 }};
         ASN1OBJID oid2[] = { 3, { 0, 1, 2 }};
         if (msgData.opcode == oid1) {
            // argument is a VisibleString
            ASN1VisibleString* pArg =
               (ASN1VisibleString*) msgData.argument.decoded;
            ...
         }
         else if (msgData.opcode == oid2) {
            // argument is an INTEGER
            OSINT32 arg = (OSINT32) *msgData.argument.decoded;
            ...
         }
       }
      else {
           // error processing
      }

In this case, the type of the decoded argument can be determined by testing the key field value. In the example as shown, the SupportedAttributes information object set is not extensible, therefore, the type of the argument must be one of the two shown. If the set were extensible (indicated by a “,...” in the definition), then it is possible that an unknown opcode could be received which would mean the type can not be determined. In this case, the original encoded message data would be present in msgData.argument.encoded field and it would be up to the user to determine how to process it.

The decoding procedure for C requires one additional step. This is a call to the module initialization functions after context initialization is complete. All module initialization functions for all modules in the project must be invoked. The module initialization function definitions can be found in the <ModuleName>Table.h file.

A C program fragment that could be used to decode the Invoke example is as follows:

   #include TestTable.h             // include file generated by ASN1C

   main ()
   {
      OSOCTET msgbuf[1024];
      ASN1TAG   msgtag;
      int       msglen;
      OSCTXT    ctxt;
      Invoke    invoke;
      ASN1OBJID oid1[] = { 3, { 0, 1, 1 }};
      ASN1OBJID oid2[] = { 3, { 0, 1, 2 }};

      .. 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;
      }

      xd_setp (&ctxt, msgbuf, 0, &msgtag, &msglen);

      /* step 2: call module initialization functions */

      Test_init (&ctxt);

      /* Step 3: Call decode function */

      status = asn1D_Invoke (&ctxt, &invoke, ASN1EXPL, 0);

      /* Step 4: Check return status */

      if (status == 0)
      {
         /* process received data in ‘invoke’ variable */
         if (rtCmpTCOID (&invoke.opcode, &oid1) == 0) {
            /* argument is a VisibleString */
            ASN1VisibleString* pArg =
               (ASN1VisibleString*) msgData.argument.decoded;
            ...
         }
         else if (rtCmpTCOID (&invoke.opcode, &oid2) == 0) {
            /* argument is an INTEGER */
            OSINT32 arg = (OSINT32) *msgData.argument.decoded;
            ...
         }

         /* Remember to release dynamic memory when done! */
         ASN1MEMFREE (&ctxt);
      }
      else
         error processing...
      }
      }