Encoding the Message

The general procedure of encoding a message is as this:

  1. Create the message data struct variable
  2. Allocate the memory for the buffer
  3. Do the encoding by calling the encode routine
  4. Process the result of the encoding
  5. Deallocate the memory for the buffer
  6. Free the data struct variable's memory (optional)

Create the message data struct variable

This step varies from case to case. In most case, this step is done in another function before jump into this encoding procedure. The following is an example of creating the message data struct variable myRequest:

char bytes[1] = { 0xC0 };
Bits standards = { 4, bytes };
struct GetRequest myRequest = { 
	true /* header_only */, 
	false /* lock */, 
	{ 
		&standards /* standards */, 
		NULL /* others */
	} /* accept_types */,
	"www.asnlab.org" /* url */,
	{ 2010, 02, 02, 02, 02, 02, 0, 0, 0 } /* timestamp */
};

The variable myRequest and all its members here are allocated in the stack, so there is no need to deallocate the memory for them; such step 6 is not required. But if there are dynamic memory allocated in this step, the programmer is responsible for deallocating these memory when this variable is no longer need. The rule to follow here is: Who created it who destroy it.

Allocate the memory for the buffer

The buffer can be allocated by calling this function:

/**
 * Allocates a new byte buffer.
 *
 * For Basic Encoding Rules, the new buffer's capacity and limit will be numBytes,
 * and for Pack Encoding Rules, the new buffer's capacity and limit will be numBytes*8.
 */
Buffer* allocBuffer(unsigned long numBytes, boolean autoExpand, char encodingRules);

This function will allocate the memory for the byte array and the memory for the buffer itself, if it fails to do so, a NULL pointer is return. The user of this function should check if the return buffer is NULL or not and handle it appropreately.

Another way to create a buffer is through this function:

/**
 * Wraps a byte array into a buffer.
 * 
 * The new buffer will be backed by the given byte array;
 * that is, modifications to the buffer will cause the array to be modified and vice versa. 
 * For Basic Encoding Rules, the new buffer's capacity and limit will be numBytes, 
 * and for Pack Encoding Rules, the new buffer's capacity and limit will be numBytes*8.
 */
Buffer* wrapBuffer(char* array, unsigned long numBytes, char encodingRules);

But the length of the buffer created by this function is fixed to numBytes, this is not suitable for encoding while the buffer length is unknown beforehand.

Do the encoding by calling the encode routine

This is done by calling the struct specific encode routine, or generic routine from the ASN.1 C Runtime Library. The example here uses the generated struct specific encoding routine:

/*
 * Do the encoding
 */
result = encode_GetRequest(buffer, &myRequest);

The return result of the encoding is zero if the encoding is successful, non-zero error code otherwise. Error codes are defined in asnrt.h:

/* error codes */
#define		INVALID_TAG                     1
#define		INVALID_LENGTH                  2
#define		INVALID_INTEGER                 3
#define		INVALID_ENUM                    4
#define		INVALID_REAL                    5
#define		OUT_OF_MEMORY                   6
#define		INVALID_TIME                    7
#define		MISSING_COMPONENT               8
#define		EXTRA_COMPONENT                 9
#define		INVALID_INDEX                   10
#define		BUFFER_OVERFLOW                 11
#define		BUFFER_UNDERFLOW                12
#define		INVALID_ENCODE_RULE             13
#define		NULL_POINTER_EXCEPTION          14
#define		NOT_PERMITTED_ALPHABET          15
#define		NO_MATCH_INFO_OBJ               16
#define		INVALID_LICENSE                 17
#define		INVALID_SIZE                    18

Process the result of the encoding

To retrieve the encoding result, you can:

  1. Flush the buffer's content to output stream through a writer callback function, like the example in the MyHTTP example:
    /*
     * Flush the buffer with writer callback
     */
    flush_buffer(buffer, write_byte);
    	
    The write_byte is a callback functiondeclared as:
    /** 
     * Callback routine: write a byte to output stream
     **/
    typedef void (*WriteByte)(char byte);
    	
  2. Retrieve the buffer's content manually, buffer content is in the buffer's array field, length is determined by buffer's position field. Note that the unit of positron is bit for PER encoding, but byte. The following code snippet shows how to get the encoding bytes and it's length (in bytes):
    char* bytes  =  buffer->array;
    unsigned long length = buffer->encoding_rules<=DISTINGUISHED_ENCODING_RULES?  buffer->limit:((buffer->limit-1)/8+1); 
    	

Deallocate the memory for the buffer

The buffer is deallocated by:

/*
 * Deallocate the memory for the buffer
 */
freeBuffer(buffer);
if this buffer is created by calling allocBuffer(). This function will free the buffer's content (byte array) and itself. If this buffer is created by calling wrapBuffer(), call asn_free() to free the buffer itself without freeing its content.

Free the data struct variable's memory (optional)

As mentioned in step 1, if the variable myRequest is not allocated dynamically, this step is skipped. This step is required only there are dynamical memory allocated in creating the message data struct variable.