When C++ code generation is specified, the ASN1C compiler generates an Encode method in the generated control class that wraps the C function call. This method provides a more simplified calling interface because it hides things such as the context structure and the tag type parameters.
The calling sequence for the generated C++ class method is as follows:
len = <object>.Encode ();
In this definition, <object> is an instance of the control class (i.e., ASN1C_<prodName>) generated for the given production. The function result variable len returns the length of the data actually encoded or an error status code if encoding fails. Error status codes are negative to tell them apart from length values. Return status values are defined in the asn1type.h include file.
The procedure to encode a message using the C++ class interface is as follows:
Create a variable of the ASN1T_<name> type and populate it with the data to be encoded.
Create an ASN1BEREncodeBuffer object.
Create a variable of the generated ASN1C_<name> class specifying the items created in 1 and 2 as arguments to the constructor.
Invoke the Encode method.
The constructor of the ASN1C_<type> class takes a message buffer object argument. This makes it possible to specify a static encode message buffer when the class variable is declared. A static buffer can improve encoding performance greatly as it relieves the internal software from having to repeatedly resize the buffer to hold the encoded message. If you know the general size of the messages you will be sending, or have a fixed size maximum message length, then a static buffer should be used. The message buffer argument can also be used to specify the start address and length of a received message to be decoded.
After the data to be encoded is set, the Encode method is called. This method returns the length of the encoded message or a negative value indicating that an error occurred. The error codes can be found in the asn1type.h run-time header file or in Appendix A of the C/C++ Common Functions Reference Manual.
If encoding is successful, a pointer to the encoded message can be obtained by using the getMsgPtr or getMsgCopy methods available in the ASN1BEREncodeBuffer class. The getMsgPtr method is faster as it simply returns a pointer to the actual start-of-message that is maintained within the message buffer object. The getMsgCopy method will return a copy of the message. Memory for this copy will be allocated using the standard new operator, so it is up to the user to free this memory using delete when finished with the copy.
A program fragment that could be used to encode an employee record is as follows. This example uses a static encode buffer:
#include employee.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)); ASN1T_PersonnelRecord msgData; ASN1C_PersonnelRecord employee (encodeBuffer, msgData); // step 2: populate msgData structure with data to be encoded msgData.name = “SMITH”; ... // step 3: invoke Encode method if ((msglen = employee.Encode ()) > 0) { // encoding successful, get pointer to start of message msgptr = encodeBuffer.getMsgPtr(); } else error processing... }
The following code fragment illustrates encoding using a dynamic buffer. This also illustrates using the getMsgCopy method to fetch a copy of the encoded message:
#include employee.h // include file generated by ASN1C main () { OSOCTET* msgptr; int msglen; // construct encodeBuffer class with no arguments ASN1BEREncodeBuffer encodeBuffer; ASN1T_PersonnelRecord msgData; ASN1C_PersonnelRecord employee (encodeBuffer, msgData); // populate msgData structure msgData.name = "SMITH"; ... // call Encode method if ((msglen = employee.Encode ()) > 0) { // encoding successful, get copy of message msgptr = encodeBuffer.getMsgCopy(); ... delete [] msgptr; // free the dynamic memory! } else error processing... }
A common application of BER encoding is the repetitive encoding of a series of the same type of message over and over again. For example, a TAP3 batch application might read billing data out of a database table and encode each of the records for a batch transmission.
If a user was to repeatedly instantiate and destroy the C++ objects involved in the encoding of a message, performance would suffer. This is not necessary however, because the C++ objects can be reused to allow multiple messages to be encoded. As example showing how to do this is as follows:
#include employee.h // include file generated by ASN1C main () { const OSOCTET* msgptr; OSOCTET msgbuf[1024]; int msglen; ASN1BEREncodeBuffer encodeBuffer (msgbuf, sizeof(msgbuf)); ASN1T_PersonnelRecord msgData; ASN1C_PersonnelRecord employee (encodeBuffer, msgData); // Encode loop starts here, this will repeatedly use the // objects declared above to encode the messages for (;;) { // logic here to read record from some source (database, // flat file, socket, etc.).. // populate structure with data to sbe encoded msgData.name = “SMITH”; ... // invoke Encode method if ((msglen = employee.Encode ()) > 0) { // encoding successful, get pointer to start of message smsgptr = encodeBuffer.getMsgPtr(); // do something with the encoded message ... } else error processing... // Call the init method on the encodeBuffer object to // prepare the buffer for encoding another message.. encodeBuffer.init(); } }