The general procedure to encode an ASN.1 message with table constraints is the same as without table constraints. The only difference is in the open type data population procedure.
The -table-unions option will cause union structure to be generated for open type field containing relationsal table constraints. These are populated for encoding in much the same way CHOICE onstructs are handled.
The -tables option will cause ASN1TObject fields to be inserted in the generated code instead of Asn1OpenType declarations.
The procedure to populate the value for an ASN1TObject item is as follows:
Check the ASN.1 specification or generated C code for the type of the type field value in the information object set that corresponds to the selected key field value.
Create a variable of that type and assign a pointer to it to the Asn1Object.decoded member variable as void*.
Follow the common BER/PER/DER encode procedure.
A complete example showing how to assign an open type value in the legacy tables case is as follows:
Test DEFINITIONS ::= BEGIN ATTRIBUTE ::= CLASS { &Type, &id OBJECT IDENTIFIER UNIQUE } WITH SYNTAX { WITH SYNTAX &Type ID &id } name ATTRIBUTE ::= { WITH SYNTAX VisibleString ID { 0 1 1 } } name ATTRIBUTE ::= { WITH SYNTAX INTEGER ID { 0 1 2 } } SupportedAttributes ATTRIBUTE ::= { name | commonName } Invoke ::= SEQUENCE { opcode ATTRIBUTE.&id ({SupportedAttributes}), argument ATTRIBUTE.&Type ({SupportedAttributes}{@opcode}) } END
In the above example, the Invoke type contains a table constraint. Its element opcode refers to the ATTRIBUTE id field and argument element refers to the ATTRIBUTE Type field. The opcode element is an index element for the Invoke type’s table constraint. The argument element is an open type whose type is determined by the opcode value. In this example, opcode is the key field.
The opcode element can have only two possible values: { 0 1 1 } or { 0 1 2 }. If the opcode value is { 0 1 1} then argument will have a VisibleString value and if the opcode value is { 0 1 2 } then argument will have an INTEGER value. Any other value of the opcode element will be violation of the Table Constraint.
If the SupportedAttributes information object set was extensible (indicated by a “,...” at the end of the definition), then the argument element may have a value of a type that is not in the defined set. In this case, if the index element value is outside the information object set, then the argument element will be assumed to be an Asn1OpenType. The Invoke type encode function call will use the value from argument.encoded.data field (i.e. it will have to be pre-encoded because the encode function will not be able to determine from the table constraint how to encode it).
A C++ program fragment that could be used to encode an instance of the Invoke type is as follows:
#include TestTable.h // include file generated by ASN1C main () { const OSOCTET* msgptr; OSOCTET msgbuf[1024]; int msglen; // step 1: construct ASN1C C++ generated class. // this specifies a static encode message buffer ASN1BEREncodeBuffer encodeBuffer (msgbuf, sizeof(msgbuf)); // step 2: populate msgData structure with data to be encoded ASN1T_Invoke msgData; ASN1C_Invoke invoke (encodeBuffer, msgData); msgData.opcode.numids = 3; msgData.opcode.subid[0] = 0; msgData.opcode.subid[1] = 1; msgData.opcode.subid[2] = 1; ASN1VisibleString argument = “objsys”; msgData.argument.decoded = (void*) &argument; // note: opcode value is {0 1 1 }, so argument must be // ASN1VisibleString type // step 3: invoke Encode method if ((msglen = invoke.Encode ()) > 0) { // encoding successful, get pointer to start of message msgptr = encodeBuffer.getMsgPtr(); } else error processing... }
The encoding procedure for C requires one extra 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.
The format of each module initialization function name is as follows:
void <ModuleName>_init (OSCTXT* pctxt)
Here ModuleName would be replaced with name of the module.
A C program fragment that could be used to encode the Invoke record defined above is as follows:
#include TestTable.h /* include file generated by ASN1C */ int main () { OSOCTET msgbuf[1024], *msgptr; int msglen; OSCTXT ctxt; Invoke invoke; /* typedef generated by ASN1C */ /* Step 1: Initialize the context and set the buffer pointer */ if (rtInitContext (&ctxt) != 0) { /* initialization failed, could be a license problem */ printf (“context initialization failed (check license)\n”); return –1; } xe_setp (&ctxt, msgbuf, sizeof(msgbuf)); /* step 2: call module initialization functions */ Test_init (&ctxt); /* Step 3: Populate the structure to be encoded */ msgData.opcode.numids = 3; msgData.opcode.subid[0] = 0; msgData.opcode.subid[1] = 1; msgData.opcode.subid[2] = 1; //note: opcode value is {0 1 1 }, so argument must be //ASN1VisibleString type ASN1VisibleString argument = “objsys”; msgData.argument.decoded = (void*) &argument; ... /* Step 4: Call the generated encode function */ msglen = asn1E_Invoke (&ctxt, &invoke, ASN1EXPL); /* Step 5: Check the return status (note: the test is */ /* > 0 because the returned value is the length of the */ /* encoded message component)..*/ if (msglen > 0) { /* Step 6: If encoding is successful, call xe_getp to */ /* fetch a pointer to the start of the encoded message.*/ msgptr = xe_getp (&ctxt); ... } else error processing... }