The following project demonstrates a full working example of encoding and decoding ASN.1
structures using the asn1c
compiler of http://lionet.info/asn1c/
In this project we assumed that we have to encode a set of geometric elements, including:
- A rectangle that is composed by its height and its width
- A rectangular cuboid that it is composed by a rectangle and a depth parameter
- A list of rectangular cuboids that has no limit on how many elements to add to it
- A list of rectangular cuboids that must have at least one element and at most three
- We assume that all parameters should be positive integer values
[download id=”2470″]
Following is our ASN.1
syntax to describe the above elements:
Geometry.asn1
GeometryModule DEFINITIONS ::= BEGIN
Rectangle ::= SEQUENCE {
height INTEGER (0..MAX),
width INTEGER (0..MAX)
}
RectangularCuboid ::= SEQUENCE {
depth INTEGER (0..MAX),
rectangle Rectangle
}
UnlimitedRectangularCuboids ::= SEQUENCE OF RectangularCuboid
LimitedRectangularCuboids ::= SEQUENCE SIZE(1..3) OF RectangularCuboid
END
Inside the directory where our source is located, we created folder called geometryASN
.
From that folder we executed the following command to generate the c code that is needed for our C/C++
source code to operate:
asn1c -fcompound-names -gen-PER ../Geometry.asn1
Following is our C
source code that creates new ANS.1
elements, encodes them, decodes them and verifies that all limitations and constraints were met.
[download id=”2470″]
main.cpp
//From the folder geometryASN, to convert the ASN1 to c execute the following
// asn1c -fcompound-names -gen-PER ../Geometry.asn1
#include <iostream>
#include "geometryASN/Rectangle.h"
#include "geometryASN/RectangularCuboid.h"
#include "geometryASN/LimitedRectangularCuboids.h"
#include "geometryASN/UnlimitedRectangularCuboids.h"
bool validate_constraints(asn_TYPE_descriptor_t *type_descriptor, const void *struct_ptr) {
char error_buffer[128];
size_t error_length = sizeof(error_buffer);
const int return_value = asn_check_constraints(type_descriptor, struct_ptr, error_buffer, &error_length);
if (return_value) {
perror("asn_check_constraints() failed");
}
return (return_value == 0);
}
void *encode_and_decode_object(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr) {
//First we validate that our object meets the expected constraints
if (validate_constraints(type_descriptor, struct_ptr)) {
void *buffer;
asn_per_constraints_s *constraints = NULL;
//Then, we encode the object to ASN.1 and assign the data to a buffer in memory
const ssize_t ec = uper_encode_to_new_buffer(type_descriptor, constraints, struct_ptr, &buffer);
if (ec == -1) {
perror("uper_encode_to_new_buffer() failed");
} else {
//ASN.1 encoded object is not in the buffer variable and it is available for you to use.
//Finally, since the encoding process went fine, we decode the data to verify with our own eyes that the process went smoothly
void *decoded_object = 0;
const asn_dec_rval_t rval = uper_decode(0, type_descriptor, &decoded_object, buffer, (size_t) ec, 0, 0);
free(buffer);
if (rval.code != RC_OK) {
perror("uper_decode() failed");
fprintf(stderr, "Broken encoding at byte %ld\n", rval.consumed);
} else {
return decoded_object;
}
}
}
return NULL;
}
int main(int argc, char *argv[]) {
//Scenario A: We test basic encoding and decoding on a Rectangle.
{
//First we create a rectangle and then we encode it
Rectangle_t *rectangle = (Rectangle_t *) calloc(1, sizeof(Rectangle_t));
if (rectangle == NULL) {
perror("calloc() failed");
exit(EXIT_FAILURE);
}
rectangle->height = 10;
rectangle->width = 150;
Rectangle_t *decoded_rectangle = (Rectangle_t *) encode_and_decode_object(&asn_DEF_Rectangle, rectangle);
if (decoded_rectangle != NULL) {
if (rectangle->height != decoded_rectangle->height || rectangle->width != decoded_rectangle->width) {
perror("uper_decode() failed. Wrong values found after decoding");
ASN_STRUCT_FREE(asn_DEF_Rectangle, rectangle);
ASN_STRUCT_FREE(asn_DEF_Rectangle, decoded_rectangle);
exit(EXIT_FAILURE);
}
}
ASN_STRUCT_FREE(asn_DEF_Rectangle, rectangle);
ASN_STRUCT_FREE(asn_DEF_Rectangle, decoded_rectangle);
}
//Scenario B: We test basic encoding and decoding on a Rectangle.
//We will provide a value that is out of the constraints area to force the test to fail.
{
//First we create a rectangle and then we encode it
Rectangle_t *rectangle = (Rectangle_t *) calloc(1, sizeof(Rectangle_t));
if (rectangle == NULL) {
perror("calloc() failed");
exit(EXIT_FAILURE);
}
rectangle->height = -10;
rectangle->width = 150;
Rectangle_t *decoded_rectangle = (Rectangle_t *) encode_and_decode_object(&asn_DEF_Rectangle, rectangle);
if (decoded_rectangle != NULL) {
perror("This test should have failed due to the constaint on the range of the valid values.");
ASN_STRUCT_FREE(asn_DEF_Rectangle, rectangle);
ASN_STRUCT_FREE(asn_DEF_Rectangle, decoded_rectangle);
exit(EXIT_FAILURE);
}
ASN_STRUCT_FREE(asn_DEF_Rectangle, rectangle);
}
//Scenario C: We test basic encoding and decoding on a Rectangular Cuboid.
{
//First we create a rectangular cuboid and then we encode it
RectangularCuboid_t *rectangular_cuboid = (RectangularCuboid_t *) calloc(1, sizeof(RectangularCuboid_t));
if (rectangular_cuboid == NULL) {
perror("calloc() failed");
exit(EXIT_FAILURE);
}
rectangular_cuboid->depth = 27;
rectangular_cuboid->rectangle.height = 10;
rectangular_cuboid->rectangle.width = 150;
RectangularCuboid_t *decoded_rectangular_cuboid = (RectangularCuboid_t *) encode_and_decode_object(
&asn_DEF_RectangularCuboid, rectangular_cuboid);
if (decoded_rectangular_cuboid != NULL) {
if (rectangular_cuboid->rectangle.height != decoded_rectangular_cuboid->rectangle.height
|| rectangular_cuboid->rectangle.width != decoded_rectangular_cuboid->rectangle.width
|| rectangular_cuboid->depth != decoded_rectangular_cuboid->depth) {
perror("uper_decode() failed. Wrong values found after decoding");
ASN_STRUCT_FREE(asn_DEF_RectangularCuboid, rectangular_cuboid);
ASN_STRUCT_FREE(asn_DEF_RectangularCuboid, decoded_rectangular_cuboid);
exit(EXIT_FAILURE);
}
}
ASN_STRUCT_FREE(asn_DEF_RectangularCuboid, rectangular_cuboid);
ASN_STRUCT_FREE(asn_DEF_RectangularCuboid, decoded_rectangular_cuboid);
}
//Scenario D: We will create an array of elements that has no limitation on its size.
{
UnlimitedRectangularCuboids_t *unlimited_rectangular_cuboids = (UnlimitedRectangularCuboids_t *) calloc(1,
sizeof(UnlimitedRectangularCuboids_t));
if (unlimited_rectangular_cuboids == NULL) {
perror("calloc() failed");
exit(EXIT_FAILURE);
}
int i;
for (i = 0; i < 10; i++) { RectangularCuboid_t *tmp_rectangular_cuboid = (RectangularCuboid_t *) calloc(1, sizeof(RectangularCuboid_t)); if (tmp_rectangular_cuboid == NULL) { perror("calloc() failed"); exit(EXIT_FAILURE); } tmp_rectangular_cuboid->depth = i;
tmp_rectangular_cuboid->rectangle.height = i * 11;
tmp_rectangular_cuboid->rectangle.width = i * 101;
const int result = asn_set_add(unlimited_rectangular_cuboids, tmp_rectangular_cuboid);
if (result != 0) {
perror("asn_set_add() failed");
ASN_STRUCT_FREE(asn_DEF_UnlimitedRectangularCuboids, unlimited_rectangular_cuboids);
exit(EXIT_FAILURE);
}
}
UnlimitedRectangularCuboids_t *decoded_unlimited_rectangular_cuboids = (UnlimitedRectangularCuboids_t *) encode_and_decode_object(
&asn_DEF_UnlimitedRectangularCuboids, unlimited_rectangular_cuboids);
if (decoded_unlimited_rectangular_cuboids != NULL) {
for (i = 0; i < decoded_unlimited_rectangular_cuboids->list.count; i++) {
RectangularCuboid_t *tmp_rectangular_cuboid = decoded_unlimited_rectangular_cuboids->list.array[i];
if (tmp_rectangular_cuboid->rectangle.height != i * 11
|| tmp_rectangular_cuboid->rectangle.width != i * 101
|| tmp_rectangular_cuboid->depth != i) {
perror("uper_decode() failed. Wrong values found after decoding");
ASN_STRUCT_FREE(asn_DEF_UnlimitedRectangularCuboids, unlimited_rectangular_cuboids);
ASN_STRUCT_FREE(asn_DEF_UnlimitedRectangularCuboids, decoded_unlimited_rectangular_cuboids);
exit(EXIT_FAILURE);
}
}
}
ASN_STRUCT_FREE(asn_DEF_UnlimitedRectangularCuboids, unlimited_rectangular_cuboids);
ASN_STRUCT_FREE(asn_DEF_UnlimitedRectangularCuboids, decoded_unlimited_rectangular_cuboids);
}
//Scenario E: We will create an array of elements that has a limitation on how many elements it can accept.
//We will add more elements than expected and we expect the encoding to fail.
{
LimitedRectangularCuboids_t *limited_rectangular_cuboids = (LimitedRectangularCuboids_t *) calloc(1,
sizeof(LimitedRectangularCuboids_t));
if (limited_rectangular_cuboids == NULL) {
perror("calloc() failed");
exit(EXIT_FAILURE);
}
int i;
for (i = 0; i < 10; i++) { RectangularCuboid_t *tmp_rectangular_cuboid = (RectangularCuboid_t *) calloc(1, sizeof(RectangularCuboid_t)); if (tmp_rectangular_cuboid == NULL) { perror("calloc() failed"); exit(EXIT_FAILURE); } tmp_rectangular_cuboid->depth = i;
tmp_rectangular_cuboid->rectangle.height = i * 11;
tmp_rectangular_cuboid->rectangle.width = i * 101;
const int result = asn_set_add(limited_rectangular_cuboids, tmp_rectangular_cuboid);
if (result != 0) {
perror("asn_set_add() failed");
ASN_STRUCT_FREE(asn_DEF_LimitedRectangularCuboids, limited_rectangular_cuboids);
exit(EXIT_FAILURE);
}
}
LimitedRectangularCuboids_t *decoded_limited_rectangular_cuboids = (LimitedRectangularCuboids_t *) encode_and_decode_object(
&asn_DEF_LimitedRectangularCuboids, limited_rectangular_cuboids);
if (decoded_limited_rectangular_cuboids != NULL) {
perror("This test should have failed due to limitation on the size of the list.");
ASN_STRUCT_FREE(asn_DEF_LimitedRectangularCuboids, limited_rectangular_cuboids);
ASN_STRUCT_FREE(asn_DEF_LimitedRectangularCuboids, decoded_limited_rectangular_cuboids);
exit(EXIT_FAILURE);
}
ASN_STRUCT_FREE(asn_DEF_LimitedRectangularCuboids, limited_rectangular_cuboids);
}
printf ("All tests were successful\n");
return EXIT_SUCCESS;
}
[download id=”2470″]