Work with more than 2 different structures in ASN.1 (C++) with asn1c compiler

163 Views Asked by At

I have 2 different structures in ASN.1: a rectangle and a circle:

Mystructs DEFINITIONS ::= BEGIN

Rectangle ::= SEQUENCE {
    height INTEGER (0..255),
    width INTEGER (0..255)
}
  
Circle ::= SEQUENCE {
    radius INTEGER (0..255)
}

END

After the compilation, I can encode these structures (uper_encode()) and send either the rectangle or the circle. My problem is that when I want to decode the structures (uper_decode()), I should know a priori what I am receiving but actually I don't know. I only know that it could be a circle or a rectangle.

So I thought that I could add somehow a tag after sending the encoded data (like a header) that I can process before I decode to know which template should I use to decode: rectangle or circle.

However, I do not know how to do this.

Thanks!!!

2

There are 2 best solutions below

0
Kevin On

I think you are looking for a CHOICE type.

CircleOrRectangle ::= CHOICE {
  circle Circle,
  rectangle Rectangle
}

The encoding will then carry information about which selection was made.

3
YaFred On

As @Botje and @Kevin answered you need a CHOICE

However, if you add it to your specification, you need to tag the alternatives (because they are both untagged SEQUENCE types)

Mystructs DEFINITIONS ::= BEGIN


CircleOrRectangle ::= CHOICE {
    circle [0] Circle,
    rectangle [1]  Rectangle
}

Rectangle ::= SEQUENCE {
    height INTEGER (0..255),
    width INTEGER (0..255)
}
  
Circle ::= SEQUENCE {
    radius INTEGER (0..255)
}

END

Another option, which is better if you can, is to add AUTOMATIC TAGS at the DEFINITIONS level

Mystructs DEFINITIONS AUTOMATIC TAGS ::= BEGIN


CircleOrRectangle ::= CHOICE {
  circle Circle,
  rectangle  Rectangle
}

Rectangle ::= SEQUENCE {
    height INTEGER (0..255),
    width INTEGER (0..255)
}
  
Circle ::= SEQUENCE {
    radius INTEGER (0..255)
}

END

EDIT ...

Using https://github.com/vlm/asn1c, this choice will be defined in CircleOrRectangle.h

/* Dependencies */
typedef enum CircleOrRectangle_PR {
    CircleOrRectangle_PR_NOTHING,   /* No components present */
    CircleOrRectangle_PR_circle,
    CircleOrRectangle_PR_rectangle
} CircleOrRectangle_PR;

/* CircleOrRectangle */
typedef struct CircleOrRectangle {
    CircleOrRectangle_PR present;
    union CircleOrRectangle_u {
        Circle_t     circle;
        Rectangle_t  rectangle;
    } choice;
    
    /* Context for parsing across buffer boundaries */
    asn_struct_ctx_t _asn_ctx;
} CircleOrRectangle_t;

As you see, it is mapped as as a struct containing an enum and a union. The enum will tell you which member to use in the union.