ENUMERATED

The ASN.1 ENUMERATED type is converted into different types depending on whether C or C++ code is being generated. The C mapping is either a C enum or integer type depending on whether or not the ASN.1 type is extensible or not. The C++ mapping adds a struct wrapper around this type to provide a namespace to aid in making the enumerated values unique across all modules.

C Mapping

ASN.1 production:

   <name> ::= ENUMERATED (<id1>(<val1>), <id2>(<val2>), ...)

Generated code :

   typedef enum {
      id1 = val1,
      id2 = val2,
      ...
   } <name>_Root
   
   typedef OSUINT32 <name>;
                

The compiler will automatically generate a new identifier value if it detects a duplicate within the source specification. The format of this generated identifier is 'id_n' where id is the original identifier and n is a sequential number. The compiler will output an informational message when this is done. This message is only displayed if the -warnings qualifier is specified on the command line.

A configuration setting is also available to further disambiguate duplicate enumerated item names. This is the "enum prefix" setting that is available at both the module and production levels. For example, the following would cause the prefix "h225" to be added to all enumerated identifiers within the H225 module:

       <module>
          <name>H225</name>
          <enumPrefix>h225</enumPrefix>
       </module>

The -fqenum (fully-qualified enum) option may also be used to make C names unique. When specified, enumerated identifiers will be automatically prefixed with the enclosing type name. In the specification above, each of the identifiers would have the form "<name>_<id>". This can be useful in situations where common identifiers are often repeated in different types. This is not a problem in C++ because the identifiers are wrapped in a struct declaration which provides a namespace for the values (see the C++ section below for more details).

The -use-enum-types (use enumerated types) option causes the direct use of the generated enum type as the C type. The general pattern in this case is:

   typedef enum {
      id1 = val1,
      id2 = val2,
      ...
      <name>_UNKNOWN_
   } <name>;
                

The advantages of the type generated in the former case are a) the integer type is of a known size, and b) it can hold unknown values. However, some users don't care about this and would prefer the second case which provide a more debug friendly format for modern IDE's which can normally shown the symbolic value rather than the numeric.

For PER, unknown extension values are encoded by encoding an index into the sorted list of extension values. This means that the value associated with an unknown extension value is itself unknown. Therefore, when the ENUMERATED is represented as OSUINT32 (i.e. -use-enum-types is not used), an unknown extension value is represented for PER by the value ASN_K_EXTENUM.

In addition to the generated type definition, helper functions are also generated to make it easier to convert to/from enumerated and string format. The signatures of these functions are as follows:

const OSUTF8CHAR* <name>_ToString (OSINT32 value);
int <name>_ToEnum (OSCTXT* pctxt, const OSUTF8CHAR* value, <name>* pvalue);

The first function would be used to convert an enumerated value into string form. The second would do the opposite - convert from string to enumerated.

C++ Mapping

ASN.1 production:

   <name> ::= ENUMERATED (<id1>(<val1>), <id2>(<val2>), ...)

Generated code :

   struct <name> {
      enum Root {
         id1 = val1,
         id2 = val2,
         ...
      }
      [ enum Ext {
         extid1 = extval1,
         ...
      } ]
   } ;

   typedef OSUINT32 ASN1T_<name>

The struct type provides a namespace for the enumerated elements. This allows the same enumerated constant names to be used in different productions within the ASN.1 specification. An enumerated item is specified in the code using the <name>::<id> form.

Every generated definition contains a Root enumerated specification and, optionally, an Ext specification. The Root specification contains the root elements of the type (or all of the elements if it is not an extended type), and the Ext specification contains the extension enumerated items.

The form of the typedef following the struct specification depends on whether or not the enumerated type contains an extension marker or not. If a marker is present, it means the type can contain values outside the root enumeration. An OSUINT32 is always used in the final typedef to ensure a consistent size of an enumerated variable and to handle the case of unknown extension values.

If the -use-enum-types (use enumerated types) command-line option is selected, the type generated for C++ is identical to what is generated for the C case documented above when this option is selected.