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″]
This post is also available in: Greek