The procedure to encode a message using the C++ class interface is as follows:
Instantiate an ASN.1 PER encode buffer object (ASN1PEREncodeBuffer) to describe the buffer into which the message will be encoded. Two overloaded constructors are available. The first form takes as arguments a static encode buffer and size and a Boolean value indicating whether aligned encoding is to be done. The second form only takes the Boolean aligned argument. This form is used to specify dynamic encoding.
Instantiate an ASN1T_<ProdName> object and populate it with data to be encoded.
Instantiate an ASN1C_<ProdName> object to associate the message buffer with the data to be encoded.
Invoke the ASN1C_<ProdName> object Encode method.
Check the return status. The return value is a status value indicating whether encoding was successful or not. Zero indicates success. If encoding failed, the status value will be a negative number. The encode buffer method printErrorInfo can be invoked to get a textual explanation and stack trace of where the error occurred.
If encoding was successful, get the start-of-message pointer and message length. The start-of-message pointer is obtained by calling the getMsgPtr method of the encode buffer object. If static encoding was specified (i.e., a message buffer address and size were specified to the PER Encode Buffer class constructor), the start-of-message pointer is the buffer start address. The message length is obtained by calling the getMsgLen method of the encode buffer object.
A program fragment that could be used to encode an employee record is as follows:
#include employee.h // include file generated by ASN1C main () { const OSOCTET* msgptr; OSOCTET msgbuf[1024]; int msglen, stat; OSBOOL aligned = TRUE; // step 1: instantiate an instance of the PER encode // buffer class. This example specifies a static // message buffer.. ASN1PEREncodeBuffer encodeBuffer (msgbuf, sizeof(msgbuf), aligned); // step 2: populate msgData with data to be encoded ASN1T_PersonnelRecord msgData; msgData.name.givenName = "SMITH"; ... // step 3: instantiate an instance of the ASN1C_<ProdName> // class to associate the encode buffer and message data.. ASN1C_PersonnelRecord employee (encodeBuffer, msgData); // steps 4 and 5: encode and check return status if ((stat = employee.Encode ()) == 0) { printf ("Encoding was successful\n"); printf ("Hex dump of encoded record:\n"); encodeBuffer.hexDump (); printf ("Binary dump:\n"); encodeBuffer.binDump ("employee"); // step 6: get start-of-message pointer and message length. // start-of-message pointer is start of msgbuf // call getMsgLen to get message length.. msgptr = encodeBuffer.getMsgPtr (); // will return &msgbuf len = encodeBuffer.getMsgLen (); } else { printf ("Encoding failed\n"); encodeBuffer.printErrorInfo (); exit (0); } // msgptr and len now describe fully encoded message ...
In general, static buffers should be used for encoding messages where possible as they offer a substantial performance benefit over dynamic buffer allocation. The problem with static buffers, however, is that you are required to estimate in advance the approximate size of the messages you will be encoding. There is no built-in formula to do this, the size of an ASN.1 message can vary widely based on data types and other factors.
If performance is not a significant issue, then dynamic buffer allocation is a good alternative. Using the form of the ASN1PEREncodeBuffer constructor that does not include buffer address and size arguments specifies dynamic buffer allocation. This constructor only requires a Boolean value to specify whether aligned or unaligned encoding should be performed (aligned is true).
The following code fragment illustrates PER encoding using a dynamic buffer:
#include employee.h // include file generated by ASN1C main () { OSOCTET* msgptr; int msglen, stat; OSBOOL aligned = TRUE; // Create an instance of the compiler generated class. // This example does dynamic encoding (no message buffer // is specified).. ASN1PEREncodeBuffer encodeBuffer (aligned); ASN1T_PersonnelRecord msgData; ASN1C_PersonnelRecord employee (encodeBuffer, msgData); // Populate msgData within the class variable msgData.name.givenName = "SMITH"; ... // Encode if ((stat = employee.Encode ()) == 0) { printf ("Encoding was successful\n"); printf ("Hex dump of encoded record:\n"); encodeBuffer.hexDump (); printf ("Binary dump:\n"); encodeBuffer.binDump ("employee"); // Get start-of-message pointer and length msgptr = encodeBuffer.getMsgPtr (); len = encodeBuffer.getMsgLen (); } else { printf ("Encoding failed\n"); encodeBuffer.printErrorInfo (); exit (0); } return 0; }
It is also possible to encode a PER message to a stream rather than a memory buffer. To do this, you would first declare a variable of one of the OSRT output stream classes. This would then be associated with the encode buffer through the ASN1PERencode buffer declaration. Everything after that would be similar to the memory buffer based program. The preceding program fragment rewritten to do streaming output to a file would look like this:
#include employee.h // include file generated by ASN1C main () { int stat; OSBOOL aligned = TRUE; const char* filename = "message_out.per"; // Create an instance of the compiler generated class. // This example write output to a file stream.. OSRTFileOutputStream fostrm (filename); ASN1PEREncodeBuffer encodeBuffer (fostrm, aligned); ASN1T_PersonnelRecord msgData; ASN1C_PersonnelRecord employee (encodeBuffer, msgData); // Populate msgData within the class variable msgData.name.givenName = "SMITH"; ... // Encode if ((stat = employee.Encode ()) == 0) { printf ("Encoding was successful\n"); printf ("Hex dump of encoded record:\n"); encodeBuffer.hexDump (); printf ("Binary dump:\n"); encodeBuffer.binDump ("employee"); } else { printf ("Encoding failed\n"); encodeBuffer.printErrorInfo (); exit (0); } return 0; }
Note that the encodeBuffer.hexDump and encodeBuffer.binDump commands work despite the fact that the output has been written to a stream. This is because a capture buffer is used when tracing is enabled to record all of the encoded information. If memory is tight, a user should ensure that trace output is turned off when using the stream.