This section describes the step-by-step procedure for calling a C PER 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 a PER encode function can be called, the user must first initialize an encoding context block structure. The context block is initialized by calling the rtInitContext to initialize the block. The user then must call pu_setBuffer to specify a message buffer to receive the encoded message. Specification of a dynamic message buffer is possible by setting the buffer address argument to null and the buffer size argument to zero. The pu_setBuffer function also allows for the specification of aligned or unaligned encoding.
An encode function can then be called to encode the message. If the return status indicates success (0), then the message will have been encoded in the given buffer. PER encoding starts from the beginning of the buffer and proceeds from low memory to high memory until the message is complete. This differs from BER where encoding was done from back-to-front. Therefore, the buffer start address is where the encoded PER message begins. The length of the encoded message can be obtained by calling the pe_GetMsgLen run-time function. If dynamic encoding was specified (i.e., a buffer start address and length were not given), the run-time routine pe_GetMsgPtr can be used to obtain the start address of the message. This routine will also return the length of the encoded message.
A program fragment that could be used to encode an employee record is as follows:
#include employee.h /* include file generated by ASN1C */ main () { OSOCTET msgbuf[1024]; int msglen, stat; OSCTXT ctxt; OSBOOL aligned = TRUE; Employee employee; /* typedef generated by ASN1C */ /* Populate employee C structure */ employee.name.givenName = "SMITH"; ... /* Allocate and initialize a new context pointer */ stat = rtInitContext (&ctxt); if (stat != 0) { printf (“rtInitContext failed (check license)\n“); rtxErrPrint (&ctxt); return stat; } pu_setBuffer (&ctxt, msgbuf, msglen, aligned); if ((stat = asn1PE_Employee (&ctxt, &employee)) == 0) { msglen = pe_GetMsgLen (&ctxt); ... } else error processing... }
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. Setting the buffer pointer argument to NULL in the call to pu_setBuffer specifies dynamic allocation. This tells the encoding functions to allocate a buffer dynamically. The address of the start of the message is obtained after encoding by calling the run-time function pe_GetMsgPtr .
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; OSCTXT ctxt; OSBOOL aligned = TRUE; Employee employee;/* typedef generated by ASN1C */ employee.name.givenName = "SMITH"; ... stat = rtInitContext (&ctxt); if (stat != 0) { printf (“rtInitContext failed (check license)\n“); rtxErrPrint (&ctxt); return stat; } pu_setBuffer (&ctxt, 0, 0, aligned); if ((stat = asn1PE_Employee (&ctxt, &employee)) == 0) { msgptr = pe_GetMsgPtr (&ctxt, &msglen); ... } else error processing... }
It is also possible to encode directly to a stream interface. To do this, the call to pu_setBuffer above would be replaced with a call to create a stream writer within the context such as rtxStreamFileCreateWriter. The call to the generated PER encode function would not change - it will automatically know to use the stream interface instead of a memory buffer.