Each encoding and decoding method needs a “context” as a parameter. A context is an instance of the C++ class asnContext. In a multi-threaded environment, each thread must use a different context. Furthermore, a context contains settings, which control the way encoding and decoding are performed. In the above example, the context controls the way traces are generated while encoding and decoding.
The context is created by the instruction:
asnContext context;
It’s highly recommended to create the context before the first memory allocation and destroy it after the last memory release to be able to use all the memory management functionalities offered by the ASNSDK runtime.
The trace of the encoding result is activated by the instruction:
context.setEncodingTraceWhileEncoding( asnTRUE );
The trace of the decoded value is activated by the instruction:
context.setValueTraceWhileDecoding( asnTRUE );
The trace output is a “write text stream”. A stream is an instance of one of the following C++ classes: asnMemoryStream or asnFileStream. A stream is a data encapsulation giving a unidirectional access (read or write) to a contiguous memory buffer, or to a file.
A file text stream is build by the instruction:
asnFileStream traceStream( "traces.txt", // file name
asnFSTREAM_TXT_WRITE );// write text stream
This file stream is used as trace output by the instruction:
context.setTraceStream( &traceStream );
Encoding process
“Write streams” are also used as encoding output. The user application example uses an automatic memory stream, which encapsulates the access to a memory area allocated during the encoding. The following instruction builds the memory stream:
asnMemoryStream encoding(asnFSTREAM_WRITE ); // write binary stream
The ASN.1 compiler has generated the MyType C++ class.
To encode a value of the ASN.1 type: MyType, the user application must first create an instance of the MyType C++ class and instantiate the attributes:
MyType myValue;
myValue.firstComponent = 10;
myValue.secondComponent = asnTRUE;
To encode this value, the user application must just call the PERencode method of the MyType C++ class. The thread context and the output stream are used as parameters:
asnMAXUINT len = myValue.PERencode( &context, &encoding );
This method puts the encoding result in a newly created memory area and returns the result length (in bytes). As required by the context settings, the PERencode method also generates the trace of the encoding in the traces.txt file. The user can get the encoded data by detaching the created memory area from the encoding stream. This memory area will not anymore be managed by the encoding stream.
asnbytep buffer = encoding.detach();
Decoding process
“Read streams” are used as decoding input. The user application example uses a memory stream which encapsulates the memory area created during the encoding.
The following instruction builds the memory stream:
asnMemoryStream decoding(buffer, // memory area
len, // area length
asnFSTREAM_READ ); // read binary stream
To decode the message, the user application must create a new instance of the MyType C++ class:
MyType myDecodedValue;
The thread context and the input stream are used as PERdecode method parameters:
myDecodedValue.PERdecode( &context, &decoding );
This method puts the decoding result in the instance of the MyType C++ class. As required by the context settings, it also generates the XML trace of the decoded value in the traces.txt file.
Note that it is not possible to use the same instance to decode several times without destroying the instance between each decoding (the decoder assumes that the instance is not initialized ; thus, it could create memory leaks if the instance is initialized).
If the decoding is successful, the instance of the MyType C++ class (myDecodedValue) contains the PER message. The user application can access the fields of this object in a way depending on the type of each field. Here, the user application simply displays the value of the two fields on the standard output:
printf(“value of firstComponent is %ld\n”,
(long)myDecodedValue.firstComponent);
printf(“value of secondComponent is %s\n”,
(myDecodedValue.secondComponent==asnFALSE ? “false” : “true”));
Memory cleanup
To avoid memory leak, the previously allocated C++ instances must be deleted. Here they will be automatically deleted at the closing bracket. The memory buffer detached by the user now belongs to him, he also has to delete it :
asnfree(buffer);
Running the user application
Running the application example generates the traces.txt file, which contains in sequence the XML trace of the encoding, then the XML trace of the decoded value:
<encoding>
010A80
</encoding>
<MyType>
<firstComponent>10</firstComponent>
<secondComponent>
<true/>
</secondComponent>
</MyType>