TOP

C Representation of ASN.1 Notation

Applies to: ASN.1/C v11.3-11.3.1

The following topics describe the representation of the ASN.1 type notation in C:

Translation Rules

For each type reference, a typedef is generated.

Example

ASN.1 C
Age ::= INTEGER
typedef int Age;

For SET and SEQUENCE types, a struct is generated.

Example

ASN.1 C
Personal ::=  SEQUENCE {
	age     INTEGER,
	weight  INTEGER
}
typedef struct Personal {
	int age;
	int weight;
} Personal;

For OPTIONAL elements in a SET or SEQUENCE, a bit_mask field and a #define constant are generated to indicate which element is present.

Example

ASN.1 C
Personal ::= SEQUENCE {
	married  BOOLEAN,
	age      INTEGER,
	weight   INTEGER OPTIONAL,
	name     IA5String OPTIONAL
}
typedef struct Personal {
		    unsigned char   bit_mask;
		#       define      weight_present 0x80
		    ossBoolean      married;
		    int             age;
		    int             weight;  /* optional; set in bit_mask 
											weight_present if * present */
		    char            *name;  /* NULL for not present */
		} Personal;

NOTE: Bit mask values are generally not needed for optional elements that have pointers since their absence is indicated by a NULL pointer.

For CHOICE types, a struct consisting of a selector field and a union containing alternatives (represented as fundamental C data types) are generated. For each element in the CHOICE, a #define is generated to indicate which element is present.

Example

ASN.1 C
Personal ::= CHOICE {
    married  BOOLEAN,
    age      INTEGER
}
typedef struct Personal {
   unsigned short  choice;
   #       define      married_chosen 1
   #       define      age_chosen 2
		  union {
        ossBoolean      married;  /* to choose, set choice to married_chosen */
                                 int  age;  /* to choose, set choice to  age_chosen */
                                 } u;
                                 } Personal;

For each element of a named number list or named bit list, a #define is generated.

Example

ASN.1 C
Name ::= BIT STRING {red(0), white(1), blue(2)}
typedef unsigned char   Name;
#define                   red 0x80
#define                   white 0x40
#define                   blue 0x20

Compiler directives

Compiler directives provide control over the C representation of ASN.1 types.

Local directives take precedence over type constraints. This rule does not apply to global or module directives.

When certain directives (--<SHORT>--, for example) conflict with schema constraints, the compiler issues a warning. At run time, the encoder/decoder ensures that values do not override the bounds of the C data type.

Subtype constraints and compiler directives do not affect how data is encoded when BER, CER, or DER encoding rules are used.

You can apply more than one compiler directive to an ASN.1 type. However, when mutually exclusive directives are applied to the same type, the last one specified is used.

Recursive ASN.1 types

Recursive types are types that reference themselves and may not be available in the generated code. To convert them to PDUs, use the ASN1.PDU or the ASN1.WorkingSet directive.

ASN.1 C
Age  ::= INTEGER
Info ::= SEQUENCE {
   Age,
   married BOOLEAN,
   names   SEQUENCE OF NameInfo
}

NameInfo ::= SEQUENCE {
   firstName VisibleString (SIZE(20)),
   lastName  VisibleString (SIZE(20))
}
typedef int             Age;

typedef struct NameInfo {
    char            firstName[21];
    char            lastName[21];
} NameInfo;

typedef struct Info {
    Age             age;
    ossBoolean      married;
    struct _seqof1 {
        struct _seqof1  *next;
        NameInfo        value;
    } *names;
} Info;
PrimaryColors ::= INTEGER {blue(0), yellow(1), red(2)}

FlagColors ::= INTEGER {blue(0),  white(1), red(2)}
typedef int             PrimaryColors;
#define                     PrimaryColors_blue 0
#define                     yellow 1
#define                     PrimaryColors_red 2

typedef int             FlagColors;
#define                     FlagColors_blue 0
#define                     white 1
#define                     FlagColors_red 2
Personal ::= SEQUENCE {
   married  BOOLEAN,
   age      INTEGER OPTIONAL,
   weight   INTEGER,
   name     IA5String OPTIONAL
}
typedef struct Personal {
    unsigned char   bit_mask;
#       define      age_present 0x80
    ossBoolean      married;
    int             age;  /* optional; set in bit_mask age_present if present */
    int             weight;
    char            *name;  /* NULL for not present */
} Personal;

Names

Names from the input ASN.1 definitions are preserved in the generated header files. When element identifiers are missing, the ASN.1 compiler generates names derived from the type name. When the element of a SET OF or SEQUENCE OF is not a simple defined type (but is a SEQUENCE OF or SET OF), the compiler generates names in the header output (_setof# or _seqof# where '#' is an integer value).

Example

ASN.1 C
Age  ::= INTEGER

	Info ::= SEQUENCE {
			           Age,
		married    BOOLEAN,
		names      SEQUENCE OF NameInfo
	}

	NameInfo ::= SEQUENCE {
		 firstName VisibleString (SIZE(20)),
		 lastName  VisibleString (SIZE(20))
}
typedef int             Age;

typedef struct NameInfo {
    char            firstName[21];
    char            lastName[21];
} NameInfo;

typedef struct Info {
    Age             age;
    ossBoolean      married;
    struct _seqof1 {
        struct _seqof1  *next;
        NameInfo        value;
    } *names;
} Info;

Remarks

The compiler switches the order of the Info and NameInfo structures so that NameInfo can be referenced from within Info. SEQUENCE OF is named struct _seqof1 in the C header file. The other names in the ASN.1 input are passed by default to the header file without change.

When the -helperNames option is specified, the ASN.1 compiler generates names for nested C structures derived from built-in ASN.1 types.

Built-in simple types that are represented by a C structure have intuitive names derived from ASN.1 type names. All names are prefixed with an underscore except for OpenType, UTCTime, GeneralizedTime, which are defined in the asn1hdr.h file.

ASN.1 type C structure name
BIT STRING
_BitStr
BMPString
_BMPStr
All character string types with -- <UNBOUNDED>-- directive applied
_UnbCharStr
GeneralizedTime --<TIMESTRUCT>--
GeneralizedTime
INTEGER --<HUGE>--
_HugeInt
OBJECT IDENTIFIER
_OID
OCTET STRING
_OctStr
Open type
OpenType
or generated 'typedef' name
RELATIVE-OID
_RelOID
UniversalString
_UnivStr
Open type
OpenType
or generated 'typedef' name
UTCTime --<TIMESTRUCT>--
UTCTime
UTF8String --<UNBOUNDED>--
_UTF8Str

Example

ASN.1 C
B ::= BIT STRING {bit(1)}
S ::= SET OF BIT STRING
typedef struct _BitStr {
    unsigned int    length;  /* number of significant bits */
    unsigned char   *value;
} _BitStr;

typedef _BitStr B;
#define                     bit 0x40
#define                     bit_byte 0

typedef struct S {
    struct S_node   *head;
    struct S_node   *tail;
    unsigned int    count;
} S;

typedef struct S_node {
    struct S_node   *next;
    struct S_node   *prev;
    struct _BitStr *value;
} S_node;

Compiler-generated context-based names for structures that are not derived from built-in simple types are created based on the position of the built-in type within a complex type with a user-defined name. These names have the following format:

TypedefName_componentId1[componentId2[...]][number]
TypedefName
The name generated in a typedef, usually derived from an ASN.1 typereference name.
componentId1
The identifier within the topmost structure whose type is built-in and whose C representation is a structure.
componentId2
A field within componentId1. It is added to name a structure that appears at the second level of nesting if its ASN.1 type is a built-in type and its C representation is a structure.
number
Can be appended to the compiler-generated name in rare cases if it conflicts with a user-defined name (for example, a user-defined name is S-id1 and there is a typereference S that has the id1 field whose type is structured) or with another compiler-generated name.

For SET OF and SEQUENCE OF types whose elements do not have identifiers and instead have built-in types represented by a C structure, the structures for these elements have names that include one of the following component names instead of identifiers:

  • set for SEQUENCE OF SET
  • seq for SEQUENCE OF SEQUENCE
  • setof for SEQUENCE OF SET OF
  • seqof for SEQUENCE OF SEQUENCE OF
  • enum for SEQUENCE OF ENUMERATED

Example

ASN.1 C
S ::= SEQUENCE {
   s1 SEQUENCE OF SET {
        a1 INTEGER,
        a2 BOOLEAN
   }
}
typedef struct S {
    struct S_s1     *s1;
} S;

typedef struct S_s1_set {
    int             a1;
    ossBoolean      a2;
} S_s1_set;

typedef struct S_s1 {
    struct S_s1_node *head;
    struct S_s1_node *tail;
    unsigned int    count;
} S_s1;

typedef struct S_s1_node {
    struct S_s1_node *next;
    struct S_s1_node *prev;
    struct S_s1_set *value;
} S_s1_node;

One of the following keywords can be added to the name of the structure that appears within CONTAINING or CONSTRAINED BY constraints: seq, set, choice, setof, seqof, enum, any, boolean, null, integer, real.

ASN.1 C
SeqBit ::= SEQUENCE {
		    a BIT STRING (CONTAINING INTEGER)
}
typedef struct _BitStr {
    unsigned int    length;  /* number of significant bits */
    unsigned char   *value;
} _BitStr;

typedef struct SeqBit {
    struct SeqBit_a *a;
} SeqBit;

typedef int             SeqBit_integer;

typedef struct SeqBit_a {
    /* ContentsConstraint is applied to SeqBit_a */
    _BitStr         encoded;
    SeqBit_integer  *decoded;
} SeqBit_a;
I ::= INTEGER (CONSTRAINED BY {SEQUENCE {a INTEGER}})
typedef int             I;

typedef struct I_seq {
    int             a;
} I_seq;

Handling long names

The -shortenNames compiler command-line option and the SHORTENNAMES compiler directive allow you to limit all variable names generated by the OSS Language Translator to a maximum of 31 characters. The compiler shortens user-supplied and compiler-generated names that are too long.

Disambiguation of names

The compiler applies a disambiguation algorithm to ensure that all generated variable names are unique within the current scope of reference. Additionally, it ensures that no generated name conflicts with any C reserved name.

If a compiler-generated name is ambiguous and the named type is a member of a structure (CHOICE, SET, SET OF, SEQUENCE or SEQUENCE OF), the name is prefixed with the containing-structure's name. If the name is still ambiguous, it is further prefixed with the next higher-level containing-structure's name (if present), and so on.

If an ENUMERATED type, or an INTEGER or BIT STRING with named values generates an ambiguous name, the compiler adds a name prefix of the defined type.

Example

ASN.1 C
PrimaryColors ::= INTEGER {blue(0), yellow(1), red(2)}
FlagColors ::= INTEGER {red(0), white(1), blue(2)}
typedef int	PrimaryColors;
    #define         PrimaryColors_blue 0
    #define         yellow 1
    #define         PrimaryColors_red 2
	
typedef int	FlagColors;
    #define         FlagColors_red 0
    #define         white 1
    #define         FlagColors_blue 2

The shared colors, red and blue, are prefixed with their parent-type's name and an underscore.

Subtypes

Subtypes used on ASN.1 user-defined types have the same effect as on ASN.1 built-in types.

Example

ASN.1 C
Name ::= VisibleString (SIZE (1..32))
typedef char		Name[33];
Name ::= VisibleString
First-name ::= Name (SIZE (1..32))
typedef char		First_name[33];
ASN.1 C (with -helperNames)
Name ::= VisibleString
First-name ::= Name (SIZE (1..32))
typedef char      *First_name;

SingleValue

When the SingleValue subtype is used with the INTEGER type and the OSS.SHORT | OSS.INT | OSS.LONG | LONGLONG local directive and the -helperNames option are not specified, the ASN.1 compiler checks if the C variable is large enough to hold the value specified in the SingleValue subtype.

See Also

ValueRange

When the OSS.SHORT | OSS.INT | OSS.LONG | LONGLONG local directive and the -helperNames option are not specified, the OSS ASN.1 compiler uses the ValueRange subtype to determine the size of the integer C data types. When a ValueRange subtype is specified, the compiler generates a C integer data type that is large enough to hold the minimum and maximum values indicated in ValueRange.

At run time, the decoder checks if the decoded value is not too large to fit into the C data type associated with ValueRange.

NOTE: The ValueRange subtype has no effect on the representation of the REAL type.

See Also

SizeConstraint

The SizeConstraint subtype is used to determine the size of the C data types associated with BIT STRING, OCTET STRING, Character String types, SET OF and SEQUENCE OF, if -helperNames is not specified or implied.

At run-time the decoder checks if the decoded value is not too large to fit into the C data type associated with the SizeConstraint. The encoder ensures that the size or number of occurrences of the data it is encoding is within the uppermost and lowermost bounds of the SizeConstraint.

See Also

PermittedAlphabet

PermittedAlphabet subtypes have no effect on C representations.

Contained

The representation of a type with a Contained subtype is the same as that of the type it "INCLUDES".

Example

ASN.1 C
NormalBit ::= BIT STRING --<VARYING>--
Flags     ::= BIT STRING (SIZE(1..61)) --<VARYING>--
MoreFlags ::= BIT STRING (INCLUDES Flags) --<VARYING>--
typedef struct NormalBit {
    unsigned short  length;  /* number of significant bits */
    unsigned char   value[1];  /* first element of the array */
} *NormalBit;
		
typedef struct Flags {
    unsigned short  length;  /* number of significant bits */
    unsigned char   value[8];
} Flags;

typedef struct MoreFlags {
    unsigned short  length;  /* number of significant bits */
    unsigned char   value[8];
} MoreFlags;

In this case, the SizeConstraint subtype, (SIZE(1..61)), affects the C data type generated for the Flags structure (64 bits (8 bytes) are allocated for the value field). The Contained subtype (INCLUDES Flags) above instructs the compiler to treat MoreFlags in the same way as Flags.

If the subtype has no effect on the data type to be "INCLUDED", the type that "INCLUDES" is not affected. For example:

ASN.1 C
Flags ::= BIT STRING (SIZE(1..61)) --<UNBOUNDED>--
MoreFlags ::= BIT STRING (INCLUDES Flags) --<UNBOUNDED>--
typedef struct Flags {
    short     length;  /* number of significant bits */
    unsigned char   *value;
    } Flags;

typedef struct MoreFlags {
    short     length;  /* number of significant bits */
    unsigned char   *value;
    } MoreFlags;

The OSS.UNBOUNDED representation is not affected by SizeConstraint, so Contained has no effect on the MoreFlags structure. However, at run time, the encoder/decoder enforces SizeConstraint for both Flags and MoreFlags.

Inner

The Inner subtypes has the same effect on the compiler-generated data as if the subtype information that follows WITH COMPONENTS was specified in the parent type element definition.

Example

ASN.1 C
Flags ::= BIT STRING (SIZE(1..61)) --<VARYING>--
ManyFlags ::= SET OF Flags
LessFlags ::= ManyFlags (WITH COMPONENT (SIZE(1..51)))
typedef struct Flags {
   unsigned short	length;  /* number of significant bits */
   unsigned char	value[8];
   } Flags;

typedef struct ManyFlags {
   struct ManyFlags *next;  /* number of significant bits */
      Flags            value;
   } *ManyFlags;

typedef struct LessFlags {
   struct LessFlags *next;
      struct {
            short          length;  /* number of significant bits */
            unsigned char  value[7];
       } value;
   } *LessFlags;

In this case, the Inner subtype of LessFlags, WITH COMPONENT(SIZE(1..51)), affects the generated C data type (value is of size 7 instead of 8). The Inner subtype affects the generated C data type also because the compiler rules for VARYING bit strings allow SizeConstraint to affect the C representation.

If a different directive (OSS.UNBOUNDED) is used for Flags, a SizeConstraint subtype applied to LessFlags has no effect on the C representation.

Example

ASN.1 C
Flags ::= BIT STRING (SIZE(1..61)) --<UNBOUNDED>--
ManyFlags ::= SET OF Flags
LessFlags ::= ManyFlags (WITH COMPONENT (SIZE(1..51)))
typedef struct Flags {
   short		length;  /* number of significant bits */
   unsigned char	*value;
} Flags;

typedef struct ManyFlags {
   struct ManyFlags *next;
   Flags            value;
} *ManyFlags;

typedef struct LessFlags {
   struct LessFlags *next;
   struct {
      short         length;  /* number of significant bits */
      unsigned char *value;
   } value;
} *LessFlags;

The value field for Flags and LessFlags is represented by unsigned char*.

PATTERN constraint

This notation allows you to restrict a character string type to be of a preset sequence of acceptable character patterns. This constraint notation has the general format:

<TypeName> ::= <RestrictedCharType> (PATTERN <RegularExpression>)

Example

NoZeros ::= NumericString (PATTERN noZero)
noZero  UniversalString ::= "[^0]"

The type of RegularExpression must be UniversalString. Refer to Annex A "ASN.1 regular expressions" of the ASN.1 standard to learn the language for specifying character patterns using a regular expression.

PATTERN constraints are only enforced by the Space-optimized and Lean encoders/decoders at runtime.

The header file output of the ASN.1 compiler usually does not change if a PATTERN constraint is applied.

Examples: ASN.1 Types

Here is a list of the ASN.1 types described in this section:

ANY/ANY DEFINED BY

ASN.1 C
Any ::= ANY
typedef struct _Any {
		unsigned long   length;
		unsigned char   *value;
	} _Any;

typedef _Any            Any;
AnyD ::= ANY --<DLINKED>--
typedef struct AnyD {
		struct AnyD     *next;
			struct AnyD     *prev;
		unsigned long   length;
		unsigned char   *value;
	} *AnyD;
AnyL ::= ANY --<LINKED>--
typedef struct AnyL {
    	struct AnyL     *next;
    	unsigned long   length;
    	unsigned char   *value;
	} *AnyL;
AnyP ::= ANY --<POINTER>--
typedef _Any            *AnyP;

Remarks

The OSS.DLINKED and the OSS.LINKED directives allow you to represent the ANY type as a doubly linked list of values and as a linked list of values respectively, which when concatenated form the entire value of the Any type. The OSS.UNBOUNDED directive is always implied.

The OSS.POINTER directive introduces a level of indirection by declaring a C pointer to the type.

The conversion of the ASN.1 value notation to C is not supported for the ANY type. If you need this feature, contact Sales <info@oss.com>.

When the OSS.HelperMacro directive is applied to ANY, the following helper macros are generated:

  • _new or _new_pdu macro (if ANY is a PDU type) to allocate an empty structure for ANY.
  • _copy or _copy_pdu macro to create a structure and copy input data.
  • _setv macro to fill in an existing structure with input data.

Example

Note that "main" helper macros are produced for generated _Any types and then referenced by macros for each user-defined ANY type.

ASN.1 Helper macro
AnyHM ::= ANY
typedef struct _Any {
    unsigned long   length;
    unsigned char   *value;
} _Any;

typedef _Any            AnyHM;

/* allocates memory for AnyHM_PDU */
#define oss_AnyHM_new_pdu(world) \
    (AnyHM *)ossGetInitializedMemory(world, sizeof(AnyHM))

/* allocates memory for AnyHM_PDU and initializes it by copy of an input
 * string */
#define oss_AnyHM_copy_pdu(world, value_, length_) \
    (AnyHM *)oss__UnbCharString_copy(world, (char *)value_, length_)

/* initializes 'value' and 'length' fields of a structure by given values */
#define oss_AnyHM_setv(outp, value_, length_) \
    { \
		(outp)->value = (value_); \
		(outp)->length = (length_); \
	} 

/* initializes 'value' and 'length' fields of a structure by given values */
#define oss_AnyHM_setv(outp, value_, length_) \
    oss__Any_setv(outp, value_, length_)

See Also

BIT STRING

ASN.1 C
Name ::= BIT STRING (SIZE (5))
typedef struct Name {
    unsigned short  length;  /* number of significant bits */
    unsigned char   *value;
} Name;
--<OSS.VARYING MyModule.Flags >--
Flags     ::= BIT STRING (SIZE(1..61))
typedef struct Flags {
    unsigned short  length;  /* number of significant bits */
    unsigned char   *value;
} Flags;

Remarks

Size constraints for BIT STRING types are specified in bits.

When a NamedBitList is present, constants with a _byte suffix are generated to indicate the location of NamedBit.

Example

ASN.1 C C (with -helperNames)
BitStrNbB ::= BIT STRING {red(0), white(1), blue(50)}
typedef struct BitStrNbB {
    unsigned int    length;  /* number of significant bits */
    unsigned char   *value;
} BitStrNbB;
#define                     red 0x80
#define                     red_byte 0
#define                     white 0x40
#define                     white_byte 0
#define                     blue 0x20
#define                     blue_byte 6
typedef struct _BitStr {
	   unsigned int    length;  /* number of significant bits */
	    unsigned char   *value;
} _BitStr;

typedef _BitStr BitStrNbA;
#define                     a 0x80
#define                     a_byte 0
#define                     b 0x40
#define                     b_byte 0
#define                     c 0x08
#define                     c_byte 0

When a NamedBitList generates an array of characters, constants with a _byte suffix are generated to indicate the location of NamedBit.

Example

ASN.1 C C (with -helperNames)
BitStrNbB ::= BIT STRING {red(0), white(1), blue(50)}
typedef unsigned char   BitStrNbB[7];
#define                     red 0x80
#define                     red_byte 0
#define                     white 0x40
#define                     white_byte 0
#define                     blue 0x20
#define                     blue_byte 6
typedef struct _BitStr {
    unsigned int    length;  /* number of significant bits */
    unsigned char   *value;
} _BitStr;

typedef _BitStr BitStrNbB;
#define                     red 0x80
#define                     red_byte 0
#define                     white 0x40
#define                     white_byte 0
#define                     blue 0x20
#define                     blue_byte 6

The compiler uses the SizeConstraint subtype to determine the maximum number of bytes that BIT STRING contains. Each byte contains as many bits as it can fit. When directives and the -helperNames option are not specified, an unsigned char, short, int, long or an array of unsigned chars is generated (the PADDED representation), depending on the number of bytes needed to hold the bit string. If -helperNames is specified, an unsigned int is always generated.

ASN.1 C C (with -helperNames)
BitStrSz ::= BIT STRING (SIZE(50))
typedef struct BitStrSz {
   unsigned short  length;  /* number of significant bits */
   unsigned char   *value;
} BitStrSz;
typedef struct _BitStr {
   unsigned int    length;  /* number of significant bits */
   unsigned char   *value;
} _BitStr;

typedef _BitStr BitStrSz;

The OSS.PADDED directive requires the presence of a NamedBitList or the SizeConstraint subtype, because the compiler must be able to determine the maximum length of the bit string. An unsigned char, short, int, long or array of unsigned chars is generated depending on the number of bytes needed to satisfy the SizeConstraint or accommodate the largest named bit. If the OSS.PADDED directive is specified without the required length indicators, the compiler issues an error message.

ASN.1 C
BitStrPa  ::= BIT STRING --<PADDED>-- (SIZE(10))	
typedef unsigned short  BitStrPa;

If the OSS.VARYING directive is specified, the result is a pointer to a structure containing a length field of type unsigned short and a character field of unspecified length. The effect is the same as when the OSS.VARYING and OSS.POINTER directives are specified together (OSS.POINTER is assumed because the array length is indeterminable by the compiler).

ASN.1 C
BitStrVa ::= BIT STRING --<VARYING>--
typedef struct BitStrVa {
    unsigned short  length;  /* number of significant bits */
    unsigned char   value[1];  /* first element of the array */
} *BitStrVa;

The OSS.HelperMacro directive applied to a BIT STRING generates the following helper macros:

  • _new or _new_pdu macro (if BIT STRING is a PDU type) to allocate an empty structure.
  • _copy or _copy_pdu macro to create a structure and copy input data to it.
  • _setv macro to fill in an existing structure with input data.

Note that "main" helper macros are produced for generated _BitStr types and then referenced by macros for each user-defined BIT STRING type. Here is an example:

ASN.1 Helper macros
BitStrHM  ::= BIT STRING
typedef struct _BitStr {
    unsigned int    length;  /* number of significant bits */
    unsigned char   *value;
} _BitStr;

/* allocates memory for an empty string */
#define oss__BitStr_new(world) \
    (_BitStr *)ossGetInitializedMemory(world, sizeof(_BitStr))

/* allocates memory for the string and initializes it by copying the input
 * value, length_ is number of bits */
#define oss__BitStr_copy(world, value_, length_) \
    (_BitStr *)oss__UnbBitStr_copy(world, value_, length_)

/* initializes 'value' and 'length' fields of a string by given values, length_
 * is number of bits */
#define oss__BitStr_setv(outp, value_, length_) \
    { \
	(outp)->value = (value_); \
	(outp)->length = (length_); \
    }

typedef _BitStr BitStrHM;

/* allocates memory for BitStrHM_PDU */
#define oss_BitStrHM_new_pdu(world) \
    oss__BitStr_new(world)

/* allocates memory for BitStrHM_PDU and initializes it by copy of an input
 * string */
#define oss_BitStrHM_copy_pdu(world, value_, length_) \
    oss__BitStr_copy(world, value_, length_)

/* initializes 'value' and 'length' fields of a string by given values, length_
 * is number of bits */
#define oss_BitStrHM_setv(outp, value_, length_) \
    oss__BitStr_setv(outp, value_, length_)

See Also

BOOLEAN

ASN.1 C
Married ::= BOOLEAN
typedef char            ossBoolean;
typedef ossBoolean      Married;

The OSS.HelperMacro directive applied to a BOOLEAN generates the following helper macros:

  • _new or _new_pdu macro to allocate memory for the value and set it to FALSE.
  • _copy or _copy_pdu macro to allocate memory and copy input data to it.

Macros for a BOOLEAN type are produced only if this type is a PDU or it is referenced by a pointer. If a BOOLEAN type is a non-typereference field of a SET or SEQUENCE, then its parent type must have its own macros to produce macros for BOOLEAN (the same rule is true for any non-typereference ASN.1 type in place of BOOLEAN).

Example

ASN.1 C
--<OSS.HelperMacro Mod.BoolHM>--
--<OSS.HelperMacro Mod.SetBoolHM>--
--<OSS.HelperMacro Mod.SetBoolHM.bool>--
Mod DEFINITIONS ::= BEGIN
BoolHM  ::= BOOLEAN --<PDU>--
SetBoolHM  ::= SET {bool BOOLEAN --<POINTER>--}
END
/* allocates memory for BoolHM_PDU */
#define oss_BoolHM_new_pdu(world) \
    (BoolHM *)ossGetMemory(world, sizeof(BoolHM))

/* allocates memory for BoolHM_PDU and initializes it by given value */
#define oss_BoolHM_copy_pdu(world, value_) \
    oss__Bool_copy(world, value_)

typedef struct SetBoolHM {
    ossBoolean      *bool;
} SetBoolHM;

...

/* allocates memory for an instance of the boolean type */
#define oss_SetBoolHM_bool_new(world) \
    (ossBoolean *)ossGetMemory(world, sizeof(ossBoolean))

/* allocates memory for an instance of the boolean type and initializes it by
 * given value */
#define oss_SetBoolHM_bool_copy(world, value_) \
    oss__Bool_copy(world, value_)

See Also

OSS.POINTER

CHOICE

typedef struct Name1 {
	  unsigned short choice;     /* selector for the union */
#       define      alternative1_chosen;
#       define      alternative2_chosen;
	             .
	             .
	             .
#       define      alternativen_chosen;
	  union {
	     type1   alternative1;
	     type2   alternative2;
	          .
	          .
	          .
	     typen   alternativen;
        } u;
	 } Name1;

Note that the alternatives ( alternative1, for example) are the identifiers associated with the alternatives of the CHOICE type. If an identifier is missing, the compiler generates a name based on the name of the alternative.

The compiler generates manifest constants to identify which alternative is contained within the union. The names generated for these manifest constants are the identifier and a suffix of _chosen.

ASN.1 C
ProductDesignator ::= CHOICE {
   departmentNo        INTEGER,
   description     [0] IMPLICIT VisibleString,
   inventoryNo     [1] IMPLICIT INTEGER
}
typedef struct ProductDesignator {
unsigned short  _choice;
#       define      departmentNo_chosen 1
#       define      description_chosen 2
#       define      inventoryNo_chosen 3
    union {
        int             departmentNo;  /* to choose, set _choice to
                                        * departmentNo_chosen */
        char            *description;  /* to choose, set _choice to
                                        * description_chosen */
        int             inventoryNo;  /* to choose, set _choice to
                                       * inventoryNo_chosen */
    } u;
} ProductDesignator;

When the OSS.HelperMacro directive is applied to a CHOICE, the following helper macros are generated:

  • _new or _new_pdu macro to allocate memory for the structure.
  • _which macro to identify a CHOICE alternative currently selected.
  • _<identifier>_get macro to determine a value of that alternative.
  • _<identifier>_set macro to set a particular CHOICE alternative value.

Example

ASN.1 Helper macros
C ::= CHOICE {
    a1 INTEGER,
    a2 C
} --<PDU>--
typedef struct C {
    unsigned short  choice;
#       define      a1_chosen 1
#       define      a2_chosen 2
    union {
        int    a1;  /* to choose, set choice to a1_chosen */
        struct C   *a2;  /* to choose, set choice to a2_chosen */
    } u;
} C;

/* allocates memory for an empty instance of the choice type */
#define oss_C_new(world) \
    (C *)ossGetInitializedMemory(world, sizeof(C))

/* allocates memory for C_PDU */
#define oss_C_new_pdu(world) \
    oss_C_new(world)

/* gets index of currently selected alternative */
#define oss_C_which(inp) \
    (inp)->choice

/* gets "a1" alternative value */
#define oss_C_a1_get(inp) \
    (inp)->u.a1

/* selects "a1" alternative and set its value */
#define oss_C_a1_set(outp, a1_) \
    { \
	(outp)->choice = a1_chosen; \
	(outp)->u.a1 = (a1_); \
    }

/* gets "a2" alternative value */
#define oss_C_a2_get(inp) \
    (inp)->u.a2

/* selects "a2" alternative and set its value */
#define oss_C_a2_set(outp, a2_) \
    { \
	(outp)->choice = a2_chosen; \
	(outp)->u.a2 = (a2_); \
    }

See Also

Contents Constraints

The CONTAINING and ENCODED BY subtype constraint notation (defined in X.682) allows you to define the contents of BIT STRING and OCTET STRING types. You can specify a simple or structured ASN.1 value contained in a bit stream or octet stream and you can also indicate which encoding rules are used to generate the value.

Example

Ex1 ::= OCTET STRING (
   CONTAINING INTEGER
   ENCODED BY {joint-iso-itu-t(2) asn1(1) packed-encoding(3) basic(0)
               aligned(0)}
)

Ex2 ::= BIT STRING (
   CONTAINING IA5String (SIZE(0..8))
   ENCODED BY {joint-iso-itu-t(2) asn1(1) packed-encoding(3) basic(0)
               aligned(0)}
)

Ex1 illustrates how to constrain an octet stream to contain INTEGER values encoded with PER (Packed Encoding Rules).

Ex2 illustrates how to constrain a bit stream to contain IA5String values which are between 0 and 8 bytes long and are encoded with PER.

The encoding rules are specified using an OBJECT IDENTIFIER value. The OBJECT IDENTIFIER value must refer to a valid node in the object identifier tree for a set of encoding rules for ASN.1 data structures. Note that the encoding rules may be different from the ones defined by the ASN.1 standard.

If the OBJECT IDENTIFIER value used for ENCODED BY does not match any of the permitted encoding rules supported by the OSS ASN.1 Tools, the ASN.1 compiler issues a warning and the ENCODED BY clause is ignored.

For example, for the following notation:

OS ::= OCTET STRING (
   CONTAINING INTEGER
   ENCODED BY {1 2 3}
)

The following warning is issued:

"sample.asn", line 3 (Sample): C0673W: The object identifier value
specified in the ENCODED BY clause of ContentsConstraint for 'OS' does
not match any of the permitted encoding rules.  Refer to OSS
documentation for a list of permitted values.

Note that the compiler ignores the ENCODED BY clause while encoding/decoding the type OS.

To improve readability, you can predefine values for the encoding rules you wish to use:

enc-BER OBJECT IDENTIFIER ::=
        {joint-iso-itu-t(2) asn1(1) basic-encoding(1)}
enc-DER OBJECT IDENTIFIER ::=
        { joint-iso-itu-t(2) asn1(1) ber-derived(2) 
distinguished-encoding(1)}
enc-CER OBJECT IDENTIFIER(2) ::=
        { joint-iso-itu-t(2) asn1(1) ber-derived(2) canonical-encoding(0)}
enc-PER-Aligned OBJECT IDENTIFIER ::= 
        {joint-iso-itu-t(2) asn1(1) packed-encoding(3) basic(0) 
aligned(0)}
enc-PER-Unaligned OBJECT IDENTIFIER ::= 
        {joint-iso-itu-t(2) asn1(1) packed-encoding(3) basic(0) 
unaligned(1)}
 enc-CPER-aligned OBJECT IDENTIFIER ::= {joint-iso-itu-t asn1 (1) packed-encoding (3) canonical (1) aligned (0)}
 enc-CPER-unaligned OBJECT IDENTIFIER ::= {joint-iso-itu-t asn1 (1) packed-encoding (3) canonical (1) unaligned (1)}
enc-XER-Basic OBJECT IDENTIFIER ::=
        {joint-iso-itu-t(2) asn1(1) xml-encoding(5) basic(0)}
enc-XER-Canonical OBJECT IDENTIFIER ::=
        {joint-iso-itu-t(2) asn1(1) xml-encoding(5) canonical(1)}

Contents constraint:

-- Pre-defined values for OBJECT IDENTIFIER
    --
    enc-PER-Aligned OBJECT IDENTIFIER ::= 
        {joint-iso-itu-t(2) asn1(1) packed-encoding(3) basic(0) 
aligned(0)}

    -- Contents constraint definition
    --
    Ex1 ::= OCTET STRING (
      CONTAINING INTEGER
      ENCODED BY enc-PER-Aligned
    )

The following data structures are generated using the above notation:

C C (with -helperNames)
#define          Ex1_PDU 1
#define          Ex1_integer_PDU 2

typedef struct ObjectID {
    unsigned short  length;
    unsigned char   *value;
} ObjectID;

typedef int             Ex1_integer;

/* Contents constraint definition*/
/**/
typedef struct Ex1 {
    /* ContentsConstraint is applied to Ex1 */
    struct {
        unsigned int    length;
        unsigned char   *value;
    } encoded;
    Ex1_integer     *decoded;
} Ex1;
#define          Ex1_PDU 1
#define          Ex1_integer_PDU 2

typedef struct _OID {
    unsigned int    length;
    unsigned char   *value;
} _OID;

typedef struct _OctStr {
    unsigned int    length;
    unsigned char   *value;
} _OctStr;

typedef int             Ex1_integer;

    /* Contents constraint definition */
    /**/
typedef struct Ex1 {
    /* ContentsConstraint is applied to Ex1 */
    _OctStr         encoded;
    Ex1_integer     *decoded;
} Ex1;

Remarks

When the -helperNames option is not specified, compiler generates PDU constants for both the containing OCTET STRING and the contained integer.

Note that when the containing type is not specified, decoded is declared as void*.

Also note that when the global or local OSS.NOPDU directive is applied to a contained type or when the -noPdusForContainingTypes compiler option is specified, PDU constants are not generated for these types.

When the -helperNames option is specified, the encoded field gets the extracted but still non-pointered type.

When the OSS.HelperMacro directive is applied to a type with contents constraints, the following helper macros are generated:

  • _new or _new_pdu macro to allocate memory for the structure and set all bytes of the allocated memory block to zero.
  • _set_encoded macro to fill the encoded representation of a type by reference to encoded data.
  • _copy_encoded or _copy_encoded_pdu macro to allocate memory for the structure and fill its encoded representation by a copy of encoded data.
  • _set_decoded macro to fill the decoded representation of a type by reference to a C value.
  • _copy_decoded or _copy_decoded_pdu macro to allocate memory for the structure and fill its decoded representation by a copy of a C value (implies a call to the ossCpyValue() API function).
ASN.1 C
--<OSS.HelperMacro M.CC.*>--
M DEFINITIONS ::= BEGIN
CC ::= SEQUENCE OF OCTET STRING (CONTAINING NULL)
END
...

typedef struct CC_seq {
    /* ContentsConstraint is applied to CC_seq */
    _OctStr         encoded;
    CC_null         *decoded;
} CC_seq;

/* allocates memory for the octet string with a ContentsConstraint applied */
#define oss_CC_seq_new(world) \
    (CC_seq *)ossGetInitializedMemory(world, sizeof(CC_seq))

/* allocates memory for the octet string with a ContentsConstraint applied and
 * initializes it by copying the encoded value */
#define oss_CC_seq_copy_encoded(world, value_, length_) \
    (CC_seq *)oss__OctStrCC_copy_encoded(world, value_, length_)

/* allocates memory for the octet string with a ContentsConstraint applied and
 * initializes it by copying the decoded value */
#define oss_CC_seq_copy_decoded(world, decoded_) \
    (CC_seq *)oss__CC_copy_decoded(world, decoded_, CC_null_PDU)

/* sets encoded value of the unbounded octet string */
#define oss_CC_seq_set_encoded(outp, value_, length_) \
    { \
	(outp)->encoded.value = (value_); \
	(outp)->encoded.length = (length_); \
	(outp)->decoded = NULL; \
    }

/* sets decoded value of the type within CONTAINING clause */
#define oss_CC_seq_set_decoded(outp, decoded_) \
    (outp)->decoded = (decoded_)

Encoding types with contents constraints applied

To enable the encoder to automatically encode the contained type, set the encoded field of the generated structure to { 0, NULL } and the decoded field to point to a decoded value of the contained type. The encoder encodes this value using the encoding rules specified with the ENCODED BY notation (or the current encoding rules in use if the ENCODED BY notation was omitted) and places it in the encoded field.

If the encoding of the decoded field is successful, the encoder will again encode the contained value but this time treating it as the containing OCTET STRING or BIT STRING. The encoded field is encoded as a normal OCTET STRING value or BIT STRING value.

If the encoding rules which correspond to the OBJECT IDENTIFIER value used for ENCODED BY are not specified (either implicitly or explicitly) during ASN.1-compiling, the automatic encoding of contained types is not possible and the encoder issues the following error message:

"E0103S: The requested encoding rules were not linked".

When the encoded field is not empty, the decoded field is ignored. The encoder skips the automatic encoding of the contained type and encodes the value of the encoded field. For example, you can manually encode the contained type and place it in the encoded field and when you call the encoder, it will simply encode your preset octet stream or bit stream as a value of the BIT STRING or OCTET STRING type.

Note that the encoder takes the value "as is", it does not check if it is a valid encoding of an abstract value of the containing type.

Note that automatic encoding/decoding is not performed at runtime in the following cases:

  • If the global or local OSS.NOPDU directive is applied to the contained type.
  • If the global OSS.NoConstrain directive is applied to the BIT STRING or OCTET STRING with a contents constraint.
  • When the -noPdusForContainingTypes compiler option is specified.

Decoding types with contents constraints applied

After receiving an encoded PDU corresponding to a type with contents constraint, the decoder decodes the PDU as a normal OCTET STRING or BIT STRING value and places the result in the encoded field of the generated structure. Then a second decode is automatically performed on the contents of the encoded field using the encoding rules specified with the ENCODED BY clause and the result is placed in the decoded field. At the same time the encoder discards the contents of the encoded field and sets it to an empty value.

If the encoding rule that corresponds to the OBJECT IDENTIFIER value used for the ENCODED BY clause is not linked during ASN.1-compiling, automatic decoding is not possible and the decoder issues the following error message:

D0103S: The requested encoding rules were not linked.

The above paragraph assumes that contents constraint with the CONTAINING and ENCODED BY keywords is used. If the CONTAINING keyword is omitted, the second decode is not automatically performed. If the ENCODED BY clause is omitted, the current encoded rules are employed.

Contents constraint value notation

The value notation associated with a BIT STRING or OCTET STRING type defined with a contents constraint can either correspond to a value for the contained type or (if the ENCODED BY clause is present) to a bit or octet stream. In the first case, the keyword CONTAINING must be inserted before the assigned value to indicate that the value corresponds to the contained type. For example, the following type definition:

A ::= OCTET STRING (
    CONTAINING INTEGER
    ENCODED BY
        {joint-iso-itu-t(2) asn1(1) packed-encoding(3) basic(0) 
aligned(0)}
)

allows for the following two value notation alternatives:

a1 A ::= '1A25'H -- specifies a value for containing OCTET STRING
a2 A ::= CONTAINING 22 -- specifies a value for the contained type

Limitations

The OCTET STRING or BIT STRING type must have the UNBOUNDED representation (the default). You cannot use the PADDED or VARYING directive with the OCTET STRING and the BIT STRING types.

See Also

EMBEDDED PDV

ASN.1 C C (with -helperNames)
DefaultEPDV ::= EMBEDDED PDV
typedef struct ObjectID {
    unsigned short  length;
    unsigned char   *value;
} ObjectID;

typedef struct EmbeddedPDV {
    struct {
        unsigned short  choice;
#    define      syntaxes_chosen 1
#    define      syntax_chosen 2
#    define      presentation_context_id_chosen 3
#    define      context_negotiation_chosen 4
#    define      transfer_syntax_chosen 5
#    define      fixed_chosen 6
   union {
      struct EmbeddedPDV_syntaxes {
          ObjectID        abstract;
          ObjectID        transfer;
          } syntaxes;  /* to choose, set choice to syntaxes_chosen */
          ObjectID        syntax;  /* to choose, set choice to syntax_chosen */
      int      presentation_context_id;  /* to choose, set choice to presentation_context_id_chosen */
      struct EmbeddedPDV_negotiation {
          int        presentation_context_id;
          ObjectID   transfer_syntax;
         } context_negotiation;  /* to choose, set choice to 							 context_negotiation_chosen */
         ObjectID    transfer_syntax;  /* to choose, set choice to transfer_syntax_chosen */
      Nulltype    fixed;  /* to choose, set choice to fixed_chosen */
    } u;
    } identification;
  struct {
      unsigned int    length;
      unsigned char   *value;
  } data_value;
} EmbeddedPDV;

typedef EmbeddedPDV     DefaultEPDV;
typedef struct _OID {
    unsigned int    length;
    unsigned char   *value;
} _OID;

typedef struct _OctStr {
    unsigned int    length;
    unsigned char   *value;
} _OctStr;

typedef struct EmbeddedPDV {
    struct EmbeddedPDV_identification *identification;
     _OctStr  *data_value;
} EmbeddedPDV;

typedef EmbeddedPDV     DefaultEPDV;

typedef struct EmbeddedPDV_syntaxes {
    struct _OID     *abstract;
    struct _OID     *transfer;
} EmbeddedPDV_syntaxes;

typedef struct EmbeddedPDV_negotiation {
    int             presentation_context_id;
    struct _OID     *transfer_syntax;
} EmbeddedPDV_negotiation;

typedef struct EmbeddedPDV_identification {
    unsigned short  choice;
#   define      syntaxes_chosen 1
#   define      syntax_chosen 2
#   define      presentation_context_id_chosen 3
#   define      context_negotiation_chosen 4
#   define      transfer_syntax_chosen 5
#   define      fixed_chosen 6
    union {
 struct EmbeddedPDV_syntaxes *syntaxes;  /* to choose, set choice 
 * to syntaxes chosen */    struct _OID  *syntax;/*to choose, set choice to syntax_chosen */
        int  presentation_context_id;  /* to choose, set choice to presentation_context_id_chosen */
        struct EmbeddedPDV_negotiation *context_negotiation;  /* to  choose, set choice to context_negotiation_chosen */ struct _OID     *transfer_syntax;  /* to choose, set choice to
        * transfer_syntax_chosen */
        Nulltype        fixed; /* to choose, set choice to fixed_chosen */ } u;
} EmbeddedPDV_identification;

See Also

ENUMERATED

ASN.1 C
Colors ::= ENUMERATED { red(1), white(2), blue(purple) } 
purple INTEGER ::= 3
typedef enum Colors {
    red = 1,
    white = 2,
    blue = 3
} Colors;

extern int purple;
int purple = 3;

Remarks

When you assign values, you must always use the defined enumerator and not the INTEGER equivalent. For example, use:

Color myColor = blue

and not:

Color myColor = 3

When you store unknown ENUMERATED types in relay-safe mode, the value is preserved in enciphered form which is represented locally as (MAXINT-enumValue). See the following limitations:

  • Unknown ENUMERATED values cannot be encoded.
  • Unknown ENUMERATED values can be decoded and re-encoded for relay purposes.
  • Unknown ENUMERATED values which are decoded have the enciphered form of the value which appears in the C structure. You cannot interpret the value (MAXINT-n), but you can re-encode it for relay.

See Also

EXTERNAL

ASN.1 C C (with -helperNames)
MyExternal  ::= EXTERNAL
typedef struct ObjectID {
    unsigned short  length;
    unsigned char   *value;
} ObjectID;

typedef struct External {
    unsigned char   bit_mask;
#define      direct_reference_present 0x80
#define      indirect_reference_present 0x40
    ObjectID        direct_reference;  /* optional; set in bit_mask  
direct_reference_present if present */
    int             indirect_reference;  /* optional; set in bit_mask
											        indirect_reference_present if  present */
    char            *data_value_descriptor;  /* NULL for not present */
    struct {
        unsigned short  choice;
#define      single_ASN1_type_chosen 1
#define      octet_aligned_chosen 2
#define      arbitrary_chosen 3
        union {
            OpenType        single_ASN1_type;  /* to choose, set choice to single_ASN1_type_chosen */
            struct External_octet_aligned {
                unsigned int    length;
                unsigned char   *value;
            } octet_aligned;  /* to choose, set choice to octet_aligned_chosen */
            struct External_arbitrary {
                unsigned int    length;  /* number of significant bits */
                unsigned char   *value;
            } arbitrary;  /* to choose, set choice to arbitrary_chosen */
        } u;
    } encoding;
} External;
typedef struct _OID {
    unsigned int    length;
    unsigned char   *value;
} _OID;

typedef struct _BitStr {
    unsigned int    length;  /* number of significant bits */
    unsigned char   *value;
} _BitStr;

typedef struct _OctStr {
    unsigned int    length;
    unsigned char   *value;
} _OctStr;

typedef struct External {
    unsigned char   bit_mask;
#       define      indirect_reference_present 0x80
    struct _OID     *direct_reference;  /* NULL for not present */
    int             indirect_reference;  /* optional; set in bit_mask
                                          * indirect_reference_present if
                                          * present */
    char            *data_value_descriptor;  /* NULL for not present */
    struct External_encoding *encoding;
} External;

typedef External        MyExternal;

typedef _OctStr         External_octet_aligned;

typedef _BitStr         External_arbitrary;

typedef struct External_encoding {
    unsigned short  choice;
#define      single_ASN1_type_chosen 1
#define      octet_aligned_chosen 2
#define      arbitrary_chosen 3
    union {
        OpenType        *single_ASN1_type;  /* to choose, set choice to
                                             * single_ASN1_type_chosen */
        External_octet_aligned *octet_aligned;  /* to choose, set choice to
                                                 * octet_aligned_chosen */
        External_arbitrary *arbitrary; /* to choose, set choice to   
                                        * arbitrary_chosen */
    } u;
} External_encoding;

Remarks

The C representation of the EXTERNAL type components is affected by global directives. For example, the representation for ObjectID can be altered by the global OSS.UNBOUNDED directive.

EXTERNAL is used when you need to carry a value that uses a different encoding scheme. For example, if you are using BER and the value is encoded using PER, you need to encode the value in PER and then put the encoded value in the External.encoding field. Also, you must set direct_reference or indirect_reference to indicate the type/encoding of the value in External.encoding.

EXTERNAL is also used when the application that you are implementing has a "container" type. For example, suppose you have a message that can carry a value of any ASN.1 specification. You encode it using other application that knows the ASN.1 definition of the type. The value is already encoded for you to put into the External.encoding field. You would also receive a direct_reference or an indirect_reference which indicates to the communications peer the type of the value that is contained in External.encoding.

You can customize the representation of EXTERNAL by creating a type reference, External, whose tag is UNIVERSAL 8 and whose elements mirror those of the UNIVERSAL type as defined in ISO 8824 | X.208. You can also add local directives to the individual elements.

Example

External ::= [UNIVERSAL 8] IMPLICIT SEQUENCE {
	direct reference          OBJECT IDENTIFIER --<OBJECTID 10>-- OPTIONAL,
	indirect reference        INTEGER OPTIONAL,
	data value descriptor     ObjectDescriptor OPTIONAL,
	encoding CHOICE {
		single ASN1 type   [0] ANY --<LINKED>--,
		octet aligned      [1] IMPLICIT OCTET STRING,
		arbitrary          [2] IMPLICIT BIT STRING}}

The following warning is generated:

A0307W: OSS has relaxed its implementation of the standards to allow the definition of a type with tag [UNIVERSAL 8].  This is normally invalid ASN.1.

See Also

GeneralizedTime

ASN.1 C
Generaltime  ::= GeneralizedTime
typedef GeneralizedTime Generaltime;
where GeneralizedTime is defined in the asn1hdr.h file as follows:
typedef struct {
  short          year;      /* YYYY format when used for GeneralizedTime */
                            /* YY format when used for UTCTime */
  short          month;
  short          day;
  short          hour;
  short          minute;
  short          second;
  short          millisec;
  short          mindiff;      /* UTC +/- minute differential     */
  ossBoolean     utc;          /* TRUE means UTC time             */
} GeneralizedTime;

Remarks

The GeneralizedTime type can be represented either as GeneralizedTime structs (for example { short year; short month; etc. } ) or as strings. Strings are used when the -lean option, the -helperNames option or the NULLTERM directive is used.

When the NULLTERM directive is used or the -lean option or the -helperNames option is specified, the GeneralizedTime type is represented as GeneralizedTime strings.

ASN.1 C
Generaltime     ::= GeneralizedTime --<NULLTERM>--
   t Generaltime ::= "19851106210627.3-0500"
   -- local time 6 minutes, 27.3 seconds after 9 pm on 6 November 1985 with
   -- local time 5 hours retarded in relation to coordinated universal time
typedef char            *Generaltime;

Generaltime t = "19851106210627.3-0500";

The OSS.HelperMacro directive applied to a GeneralizedTime with the NULLTERM representation generates the following helper macros:

  • _new or _new_pdu macro to allocate memory for the string of given length and set all bytes of the allocated memory block to zero.
  • _copy or _copy_pdu macro to allocate memory and copy given input null terminated time value to it.

The OSS.HelperMacro directive applied to a GeneralizedTime with the TIMESTRUCT directive generates the following helper macros:

  • _new or _new_pdu macro to allocate memory for the time structure and set all bytes of the allocated memory block to zero.
  • _copy_nullterm or _copy_nullterm_pdu macro to allocate memory for the time structure and initialize it by parsing a string containing a time value.
  • _setv_nullterm macro to initialize existing time structure by parsing a string containing a time value.
ASN.1 Helper macros
--<OSS.HelperMacro Mod.SeqTime>--
--<OSS.HelperMacro Mod.SeqTime.n-time>--
--<OSS.TIMESTRUCT  Mod.SeqTime.s-time>--
--<OSS.HelperMacro Mod.SeqTime.s-time>--
Mod DEFINITIONS ::= BEGIN
SeqTime ::= SEQUENCE {
    n-time GeneralizedTime,
    s-time GeneralizedTime 
}
END
typedef struct SeqTime {
    char            *n_time;
    GeneralizedTime *s_time;
} SeqTime;

...

/* allocates memory for a string of given length */
#define oss_SeqTime_n_time_new(world, length_) \
    oss__CharStr_new(world, length_)

/* allocates memory and returns a copy of an input string */
#define oss_SeqTime_n_time_copy(world, value_) \
    oss__CharStr_copy(world, value_)

...

/* allocates memory for the time structure */
#define oss_SeqTime_s_time_new(world) \
    (GeneralizedTime *)ossGetInitializedMemory(world, sizeof(GeneralizedTime))

/* allocates memory for the time structure and initializes it by parsing a
 * string containing a GeneralizedTime value */
#define oss_SeqTime_s_time_copy_nullterm(world, value_) \
    oss__GeneralizedTime_copy_nullterm(world, value_)

/* initializes the structure by parsing a string containing a GeneralizedTime
 * value */
#define oss_SeqTime_s_time_setv_nullterm(world, outp, value_) \
    oss__GeneralizedTime_setv_nullterm(world, outp, value_)

NOTE: As specified in ITU-T Rec. X.680 | ISO/IEC 8824-1, year is specified in YYYY format for GeneralizedTime and in YY format for UTCTime. The time differential, mindiff, indicates the minute differential from Coordinated Universal Time (UTC time or Greenwich Mean Time); mindiff may have either a positive or negative value. The minute differential can have an absolute value greater than 59, so to express a time differential of one hour and thirty minutes, you would set mindiff to 90. A utc value of TRUE indicates that the time contained in the GeneralizedTime structure is the UTC time. If utc is TRUE, mindiff is ignored. If utc is FALSE, and mindiff contains zero, the time in the GeneralizedTime structure is the local time. If utc is FALSE, and mindiff is non zero, the hour, minute, and second minus the minute differential yields the UTC time.

See Also

INSTANCE OF

The INSTANCE OF type is equivalent to an EXTERNAL type that is used to specify an attribute-id / attribute-value pair.

Only the OSS.OBJHANDLE directive is allowed with the INSTANCE OF type and it does not affect the C representation.

Example

ASN.1:

Module DEFINITIONS ::= BEGIN
   MHS-BODY     ::= TYPE-IDENTIFIER
   InstanceOfMHS        ::= INSTANCE OF MHS-BODY
END

where TYPE-IDENTIFIER is internally defined as:

TYPE-IDENTIFIER ::= CLASS
{
   &id OBJECT IDENTIFIER UNIQUE,
   &Type
}

and IntanceOfMHS has the following implied associated SEQUENCE:

InstanceOfMHS ::= SEQUENCE
{
   type-id        MHS-BODY.&id,
   value      [0] MHS-BODY.&Type
}
C C (with -helperNames)
#define          InstanceOfMHS_PDU 1

typedef struct ObjectID {
    unsigned short  length;
    unsigned char   *value;
} ObjectID;

typedef struct InstanceOfMHS {
    ObjectID        type_id;
    OpenType        value;
} InstanceOfMHS;
#define          InstanceOfMHS_PDU 1

typedef struct _OID {
    unsigned int  length;
    unsigned char   *value;
} _OID;

typedef struct InstanceOfMHS {
    struct _OID     *type_id;
    OpenType        *value;
} InstanceOfMHS;

See Also

OpenType

INTEGER

ASN.1 C
RegInt    ::= INTEGER

NumLstInt ::= INTEGER { one(1), two(2), three(3) }
   
SizeInt   ::= INTEGER (1..123456789)
typedef int             RegInt;

typedef int             NumLstInt;
#define                     one 1
#define                     two 2
#define                     three 3

typedef unsigned int    SizeInt;

Remarks

When a ValueRange or SingleValue constraint conflicts with a local directive (the value is too large or too small for the type indicated by the directive), the directive takes precedence and the compiler issues a warning.

See Also

NULL

ASN.1 C
Name1 ::= NULL
typedef char            Nulltype;
typedef Nulltype        Name1;

See Also

OSS.POINTER

OBJECT IDENTIFIER

ASN.1 C
DefaultOID ::= OBJECT IDENTIFIER
typedef struct ObjectID {
    unsigned short  length;
    unsigned char   *value;
} ObjectID;

typedef ObjectID        DefaultOID;
ArrayOID ::= OBJECT IDENTIFIER --<ARRAY>--
typedef struct ArrayOID {
    unsigned short  count;
    unsigned short  value[1];
} *ArrayOID;
ObjIdOID ::= OBJECT IDENTIFIER --<OBJECTID 8>--
typedef struct ObjIdOID {
    unsigned short  length;
    unsigned char   value[8];
} ObjIdOID;
LongOID ::= OBJECT IDENTIFIER --<LONG>--
typedef struct LongOID {
    unsigned short  length;
    unsigned char   *value;
} LongOID;
UnboundedLongOID ::= OBJECT IDENTIFIER --<UNBOUNDED|LONG>--
typedef struct UnboundedLongOID {
    unsigned short  count;
    unsigned long   *value;
} UnboundedLongOID;
OIDUnbndOID ::= OBJECT IDENTIFIER --<OBJECTID 10 | UNBOUNDED>--
typedef struct OIDUnbndOID {
    unsigned short  count;
    unsigned short  *value;
} OIDUnbndOID;
OIDLnkPtrOID ::= OBJECT IDENTIFIER --<OBJECTID 8 | LINKED | POINTER>--
typedef struct OIDLnkPtrOID {
    struct OIDLnkPtrOID *next;
    unsigned short  value;
} **OIDLnkPtrOID;

Remarks

char *value contains the BER-encoded OBJECT IDENTIFIER ({1 2 3 4 5} stored as: {0x2A, 0x03, 0x04, 0x05}). This allows the representation with node values to exceed the maximum INTEGER representation on a particular machine. The encoded value is derived according to the ITU-T Rec.X.690 (2021) document.

short value[] contains an array of short INTEGERs which include the individual node values of the OBJECT IDENTIFIER.

See Also

OCTET STRING

ASN.1 C
DefaultOctStr ::= OCTET STRING
// UNBOUNDED representation by default.
typedef struct DefaultOctStr {
    unsigned int    length;
    unsigned char   *value;
} DefaultOctStr;
SizeOctStr ::= OCTET STRING (SIZE(10))
// VARYING representation by default. 
typedef struct SizeOctStr {
    unsigned short  length;
    unsigned char   value[10];
} SizeOctStr;

See Also

Open Type

Open types are the equivalent of ANY and ANY DEFINED BY in ASN.1:1990. Unlike other types in this section, the open type does not have a reserved identifier in the ASN.1 notation which causes it to be generated. Rather, it results when information object notation is written in a way that renders ambiguous the exact type intended for a certain field. Note that the open type is particularly useful for embedding a separately encoded ASN.1 type within other ASN.1 type. The representation for open type contains information about an ASN.1 type and its decoded value or stores encoded data of the type.

An open type is represented with the decoded value as a union of PDU type alternatives if the following conditions are met:

  • Table constraints are applied to the type.
  • The OSS.NonUnionOpenType directive is not applied to the type.
  • The -compat noUnionRepresentationForOpenTypes command-line option is not specified.

Otherwise, the predefined OpenType structure is used to represent an ASN.1 open type.

Example

ASN.1 C
DEFINITIONS ::= BEGIN
    C ::= CLASS {
        &code INTEGER,
        &Type
    }

    Object C ::= {
        { &code 1, &Type INTEGER } |
        { &code 2, &Type UTF8String }
    }

    S ::= SEQUENCE {
        key C.&code ({Object}),
        value C.&Type ({Object}{@key})
    }
END
#define          S_PDU 1
#define          Object_integer_PDU 2
#define          Object_UTF8String_PDU 3

typedef int             Object_integer;

typedef unsigned char   *Object_UTF8String;

enum Object_Type_PDUs {
    PDU_Object_Type_UNKNOWN        = 0,
    PDU_Object_Type_integer        = Object_integer_PDU,
    PDU_Object_Type_UTF8String     = Object_UTF8String_PDU
};

union Object_Type_union {
    Object_integer  *pdu_Object_integer;  /* PDU_Object_Type_integer */
    Object_UTF8String *pdu_Object_UTF8String;  /* PDU_Object_Type_UTF8String */
};

typedef struct Object_Type {
    enum Object_Type_PDUs pduNum;
    OssBuf          encoded;
    union Object_Type_union decoded;
} Object_Type;

typedef struct S {
    int             key;
    Object_Type     value;
} S;

The generated Object_Type type consists of the following fields:

pduNum
Contains the PDU identification constant of the decoded value. All constants possible for the field are defined in the enum Object_Type_PDUs. When an extensible ObjectSet is present, the PDU_Object_Type_MAX constant is also generated in enum Object_Type_PDUs and serves as a placeholder to ensure that pduNum has a broad enough numeric range to store the PDU numbers beside the enum constant set. The PDU_Object_Type_UNKNOWN constant means that nothing is stored in the decoded field and other PDU identification constants are equal to the PDU numbers.
encoded
Optionally contains data in encoded form. The C-type of the encoded field is OssBuf, defined as follows:
typedef struct {
    long           length;
    unsigned char *value;
} OssBuf;
A non-zero value of both the length and value fields indicates that encoded data is present for OpenType. The address of the encoded field can be passed directly to the ossDecode() and ossEncode() runtime API functions as the input and output parameters respectively.
decoded
Contains the decoded value of the PDU type identified by the pduNum field. The address of the PDU type value can be taken from the field of union Object_Type_union that is composed of all the PDU types allowed by the ObjectSet. Each field of union Object_Type_union is a pointer type, so all fields are compatible with the untyped pointer. When there is an extensible ObjectSet, the other field is also generated in union Object_Type_union and serves as storage for a PDU type value for a PDU type that is not in the ObjectSet.

In the above structure, the pduNum and decoded fields are only used if the AUTOMATIC_ENCDEC flag is set using the ossSetEncodingFlags() and ossSetDecodingFlags() functions. Specifically, the pduNum field should reference the PDU identification constant of the data structure to be contained in the open type and the decoded field should reference the value-filled compiler-generated data structure to be encoded. Finally, when AUTOMATIC_ENCDEC is specified, the length and value fields in the encoded field should be set to zero and NULL respectively, before calling the encoder.

When the AUTOMATIC_ENCDEC flag is not set, the pduNum and decoded fields should be set to UNKNOWN and NULL, respectively, while the value and length fields in the encoded field should be set to the pre-encoded data and its length, respectively.

Legacy representation with the untyped pointer to the decoded value

This C representation uses a predefined OpenType structure. This was the only possible representation prior to version 9.0 of the ASN.1 compiler. Starting with version 9.0, the following representation is used:

  • For non-constrained ASN.1 open types.
  • When the ASN1.DeferDecoding, the OSS.ENCODABLE, or the OSS.NonUnionOpenType directive is applied to the type
  • When the -compat noUnionRepresentationForOpenTypes command-line option is specified.
ASN.1 C
Module DEFINITIONS ::= BEGIN
     A ::= TYPE-IDENTIFIER.&Type
END
where TYPE-IDENTIFIER is defined as follows:
TYPE-IDENTIFIER ::= CLASS
{
   &id      OBJECT IDENTIFIER UNIQUE,
   &Type
}
#define          A_PDU 1

typedef OpenType        A;

Note that the OpenType type has a declaration of the following form:

typedef struct {
       int            pduNum;
       long           length;           /* length of "encoded" */
       void          *encoded;
       void          *decoded;
} OpenType;

The pduNum field can contain the PDU identification number of the decoded structure/value. The length field can contain the length of the encoded value returned by the encoder. The encoded field can contain the address of the encoded value returned by the encoder. The decoded field can contain the address of the decoded structure/value.

In the above structure, the pduNum and decoded fields are only used if the AUTOMATIC_ENCDEC flag is set using the ossSetEncodingFlags() and ossSetDecodingFlags() functions. The pduNum field should reference the compiler-generated PDU identification number of the data structure to be contained in the open type and the decoded field should reference the value-filled compiler-generated data structure to be encoded. When AUTOMATIC_ENCDEC is specified, the length and encoded fields should be set to zero and NULL respectively, before calling the encoder.

When the AUTOMATIC_ENCDEC flag is not set, the pduNum and decoded fields should be set to zero and NULL, respectively, while the encoded and length fields should be set to the pre-encoded data and its length, respectively.

The OSS.HelperMacro directive applied to an open type generates the following helper macros:

  • _new or _new_pdu macro to allocate memory for the OpenType structure and set all bytes of the allocated memory block to zero.
  • _set_encoded macro to fill the encoded representation of a type by reference to encoded data.
  • _copy_encoded or _copy_encoded_pdu macro to allocate memory for the OpenType structure and fill its encoded representation by a copy of encoded data.
  • _set_decoded macro to fill the decoded representation of a type by reference to a C value.
  • _copy_decoded or _copy_decoded_pdu macro to allocate memory for the OpenType structure and fill its decoded representation by a copy of a C value (implies a call to the ossCpyValue() API function).
ASN.1 Helper macros
ArbitraryType ::= [0] TYPE-IDENTIFIER.&Type
typedef OpenType        ArbitraryType;

/* allocates memory for ArbitraryType_PDU */
#define oss_ArbitraryType_new_pdu(world) \
    (ArbitraryType *)ossGetInitializedMemory(world, sizeof(ArbitraryType))

/* allocates memory for ArbitraryType_PDU and initializes it by copying the
 * encoded value */
#define oss_ArbitraryType_copy_encoded_pdu(world, value_, length_) \
    (ArbitraryType *)oss__OpenType_copy_encoded(world, value_, length_, sizeof(ArbitraryType))

/* allocates memory for ArbitraryType_PDU and initializes it by copying the
 * decoded value */
#define oss_ArbitraryType_copy_decoded_pdu(world, decoded_, pdunum_) \
    (ArbitraryType *)oss__OpenType_copy_decoded(world, decoded_, pdunum_, sizeof(ArbitraryType))

/* sets encoded value of the OpenType */
#define oss_ArbitraryType_set_encoded(outp, value_, length_) \
    { \
	(outp)->encoded = (value_); \
	(outp)->length = (length_); \
	(outp)->decoded = NULL; \
    }

/* sets decoded value of the OpenType */
#define oss_ArbitraryType_set_decoded(outp, decoded_, pdunum_) \
    { \
	(outp)->decoded = (decoded_); \
	(outp)->pduNum = (pdunum_); \
    }

Remarks

An OpenType is also generated for elements of CHOICE, SEQUENCE, and SET types that have the ASN1.DeferDecoding or OSS.ENCODABLE directive applied to them.

If the -extendOpenType compiler option is specified, a user-specific field (userField) is generated within the OpenType structure that is not encoded by the encoder. This field has the following format:

void           userField;

See Also

REAL

ASN.1 C
DefaultReal ::= REAL
FloatReal   ::= REAL --<FLOAT>--
DecimalReal ::= REAL --<DECIMAL>--
MyMixReal   ::= REAL --<MIXED>--
typedef double          DefaultReal;
typedef float           FloatReal;
typedef char            *DecimalReal;
typedef MixedReal       MyMixReal;

Remarks

SingleValue and ValueRange constraints have no effect on the representation of REAL types.

See Also

RELATIVE-OID

A relative object identifier can be used to identify an object in the object identifier tree relative to other known object identifier. Thus, the relative object identifier type can be used to transmit the trailing component or components of an object identifier value. This leads to bandwidth savings over transmitting the entire object identifier value.

Example

ASN.1 C
DefaultROID ::= RELATIVE-OID

myUniversity  OBJECT IDENTIFIER ::=
    {iso member-body country(29) universities(56) universityOfNokalva(32)}

relativeDept DefaultROID ::=  {engineering(4) digitalSignalProcessing(3)}

dspDept OBJECT IDENTIFIER ::= { myUniversity relativeDept }
static unsigned char _v0[] = { 0x2A, 0x1D, 0x38, 0x20 };
ObjectID myUniversity = {
    4,    /* length in octets */
    _v0   /* BER-encoded value */
};

static unsigned char _v1[] = { 0x04, 0x03 };
DefaultROID relativeDept = {
    2,    /* length in octets */
    _v1   /* BER-encoded value */
};

static unsigned char _v2[] = { 0x2A, 0x1D, 0x38, 0x20, 0x04, 0x03 };
ObjectID dspDept = {
    6,    /* length in octets */
    _v2   /* BER-encoded value */
};

In the above example, relativeDept can be transmitted alone if both the sender and the receiver are aware that engineering(4) is an offshoot (branch) of {iso member-body country(29) universities(56) universityOfNokalva(32)}.

Note how the value field contents are simply the BER-encoded octets of the object identifier value.

Example

ASN.1 C C (with -helperNames)
DefaultROID ::= RELATIVE-OID
typedef struct OssRelativeOID {
    unsigned short  length;
    unsigned char   *value;
} OssRelativeOID;

typedef OssRelativeOID  DefaultROID;
typedef struct _RelOID {
    unsigned int    length;
    unsigned char   *value;
} _RelOID;

typedef _RelOID         DefaultROID;

Remarks

If the OSS.OBJECTID directive is specified with a length operand, a fixed-size character string is generated preceded by a length field giving the size in octets of the character string.

ASN.1 C
BigROID ::= RELATIVE-OID --<OBJECTID 80>--
typedef struct BigROID {
    unsigned short  length;
    unsigned char   value[80];
} BigROID;

The value field contains the BER-encoded contents of the OBJECT IDENTIFIER (for example, {1 2 3 4 5} would be stored as: {0x2A, 0x03, 0x04, 0x05}).

The following helper macros are generated when the OSS.HelperMacro directive is applied:

  • _new or _new_pdu macro to allocate an empty structure.
  • _copy or _copy_pdu macro to create a structure and copy input data to it.
  • _setv macro to fill in an existing structure with input data.

Note that "main" helper macros are produced for generated _RelOID types and then referenced by macros for each user-defined RELATIVE-OID type.

ASN.1 Helper macros
OID-Tail ::= RELATIVE-OID
typedef struct _RelOID {
    unsigned int    length;
    unsigned char   *value;
} _RelOID;

/* allocates memory for an empty structure */
#define oss__RelOID_new(world) \
    (_RelOID *)ossGetInitializedMemory(world, sizeof(_RelOID))

/* allocates memory for the structure and initializes it by copying the input
 * value */
#define oss__RelOID_copy(world, value_, length_) \
    (_RelOID *)oss__UnbCharString_copy(world, (char *)value_, length_)

/* initializes 'value' and 'length' fields of a structure by given values */
#define oss__RelOID_setv(outp, value_, length_) \
    { \
	(outp)->value = (value_); \
	(outp)->length = (length_); \
    }

typedef _RelOID         OID_Tail;

/* allocates memory for OID_Tail_PDU */
#define oss_OID_Tail_new_pdu(world) \
    oss__RelOID_new(world)

/* allocates memory for OID_Tail_PDU and initializes it by copy of an input
 * string */
#define oss_OID_Tail_copy_pdu(world, value_, length_) \
    oss__RelOID_copy(world, value_, length_)

/* initializes 'value' and 'length' fields of a structure by given values */
#define oss_OID_Tail_setv(outp, value_, length_) \
    oss__RelOID_setv(outp, value_, length_)

See Also

BMPString | GeneralString | IA5String | ISO646String | NumericString |

PrintableString | UniversalString | UTF8String | VisibleString

ASN.1 C
Str ::= VisibleString
typedef char            *Str;
SmallStr ::= VisibleString (SIZE(10))
typedef char            SmallStr[11];
BigStr ::= PrintableString (SIZE(257))
typedef struct BigStr {
    unsigned short  length;
    char            *value;
} BigStr;

Remarks

For Strings larger than 256 bytes, the compiler automatically uses the UNBOUNDED representation.

See Also

Selection

ASN.1 C
Info1 ::= CHOICE
	     {name   VisibleString,
	      age    INTEGER} --<PDU>--

Info2 ::= SEQUENCE
	     {birthdate INTEGER,
	      name < Info1}
typedef struct Info1 {
   unsigned short  choice;
#       define      name_chosen 1
#       define      age_chosen 2
    union {
	      char            *name;
	      int             age;
	  } u;
} Info1;
	
typedef struct Info2 {
    int             birthdate;
    char            *name;
} Info2;

The Selection type < Info1 has the same representation as VisibleString.

SEQUENCE

ASN.1 C
Names ::= SEQUENCE {
   ceo       VisibleString (SIZE(1..32)),
   secretary VisibleString (SIZE(1..32)),
             VisibleString (SIZE(1..32))
   }
typedef struct Names {
    char            ceo[33];
    char            secretary[33];
    char            visibleString[33];
} Names;

Names2 ::= SEQUENCE {
    ceo       UTF8String (SIZE(1..32)) OPTIONAL,
    secretary UTF8String OPTIONAL,
    other     UTF8String (SIZE(1..32))
}
typedef struct Names2 {
    unsigned char   bit_mask;
#       define      ceo_present 0x80
    unsigned char   ceo[193];  /* optional; set in bit_mask ceo_present if
                                * present */
    unsigned char   *secretary;  /* NULL for not present */
    unsigned char   other[193];
} Names2;
Names3 ::= SEQUENCE {
   ceo       VisibleString (SIZE(1..32)),
   secretary VisibleString (SIZE(1..32)),
   COMPONENTS OF More
}

More ::= SEQUENCE {
   vp VisibleString (SIZE(1..32)),
      VisibleString (SIZE(1..32)) 
}
typedef struct Names3 {
    char            ceo[33];
    char            secretary[33];
    char            vp[33];
    char            visibleString[33];
} Names3;

typedef struct More {
    char            vp[33];
    char            visibleString[33];
} More;

Remarks

bit_mask indicates absent or present components that are not referenced via a pointer. These components can be OPTIONAL or DEFAULT.

When components are referenced via a pointer, the non-NULL or NULL pointer value indicates whether the component is present or absent.

See Also

SEQUENCE OF

ASN.1 C
 X ::= SEQUENCE OF INTEGER
typedef struct X {
    struct X        *next;
    int             value;
} *X;   
SeqDlnkOfInt ::= SEQUENCE --<DLINKED>-- OF INTEGER
typedef struct SeqDlnkOfInt {
    struct SeqDlnkOfInt *next;
    struct SeqDlnkOfInt *prev;
    int             value;
} *SeqDlnkOfInt;
SeqUnbdOfInt ::= SEQUENCE --<UNBOUNDED>-- OF INTEGER
typedef struct SeqUnbdOfInt {
    unsigned int    count;
    int             *value;
} SeqUnbdOfInt;
SeqSzArOfInt ::= SEQUENCE SIZE(33000) --<ARRAY>-- OF INTEGER
typedef struct SeqSzArOfInt {
    unsigned short  count;
    int             value[33000];
} SeqSzArOfInt;
Street-addresses ::= SEQUENCE SIZE (1..20) --<ARRAY>-- OF VisibleString (SIZE (1..64))
typedef struct Street_addresses {
    unsigned short  count;
    char            value[20][65];
} Street_addresses;
SeqDlinkPlOfInt ::= SEQUENCE --<DLINKED-PLUS>-- OF INTEGER
typedef struct SeqDlinkPlOfInt {
    struct SeqDlinkPlOfInt_node *head;
    struct SeqDlinkPlOfInt_node *tail;
    unsigned int    count;
} SeqDlinkPlOfInt;

typedef struct SeqDlinkPlOfInt_node {
    struct SeqDlinkPlOfInt_node *next;
    struct SeqDlinkPlOfInt_node *prev;
    int             value;
} SeqDlinkPlOfInt_node;

Remarks

The first link in the link-list that represents the SEQUENCE OF does not store any values. It is used to indicate whether the SEQUENCE is empty (next = NULL) or not.

Example

 empty X ::= {}
 struct X empty;
 
 one X  ::= {1}
 struct X one0, one1;
 
 empty.next = NULL;
 one0.next  = &one1;
 one1.value = 1;
 one1.next  = NULL;
 

See Also

SET

typedef struct Name1 {
	      type1   element1;
	              .
	              .
	              .
	      typen   elementn;
} Name1;

The elements (element1, for example) are the identifiers associated with each component of the SET type. If an identifier is missing, the compiler generates a C identifier based on the ASN.1 type.

Example

ASN.1 C C (with -helperNames)
NamesOfOfficers1 ::= SET {
    president         [0]   VisibleString (SIZE(1..32)),
    vicePresident     [1]   VisibleString (SIZE(1..32)),
    secretary         [2]   VisibleString (SIZE(1..32)),
                      [3]   VisibleString (SIZE(1..32)) }
typedef struct NamesOfOfficers1 {
    char     president[33];
    char     vicePresident[33];
    char     secretary[33];
    char     treasurer[33];
} NamesOfOfficers1;
typedef struct NamesOfOfficers1 {
    char     *president;
    char     *vicePresident;
    char     *secretary;
    char     *visibleString;
} NamesOfOfficers1;

When the COMPONENTS OF notation is used in a SET, the elements of the referenced SET are copied inline.

ASN.1 C
NamesOfOfficers3 ::= SET {
    president           [0] VisibleString (SIZE(1..32)),
    vicePresident       [1] VisibleString (SIZE(1..32)),
        COMPONENTS OF MoreOfficers }

MoreOfficers ::= [1] SET {
    secretary     [2] VisibleString (SIZE(1..32)),
    treasurer     [3] VisibleString (SIZE(1..32))}
typedef struct NamesOfOfficers3 {
    char    president[33];
    char    vicePresident[33];
    char    secretary[33];
    char    treasurer[33];
} NamesOfOfficers3;

If a component of SET is OPTIONAL or has a DEFAULT value, the C representation is of the form:

typedef struct Name1{
	  unsigned char   bit_mask;
#       define      elementj_present  0x80
	  type1           element1;
	                  .
	                  .
	                  .
	  typen           elementn;
} Name1;

The bit_mask variable is used to indicate the presence or absence of SET components that are OPTIONAL or have a DEFAULT value, but are not referenced via a pointer. For components that are referenced via a pointer, a non-NULL or NULL pointer value indicates the component's presence or absence.

The type of the bit_mask variable (char, short, int, long, or unsigned char* array) depends on the smallest type that can accommodate all optional components that are not referenced via a pointer.

For each SET component represented in the bitmask, the compiler generates a bitmask manifest constant whose name is the component's name with a suffix of _present. The application programmer should perform a logical AND with this manifest constant and the bit_mask variable to determine if a specific component is present.

Example

ASN.1 C C (with -helperNames)
NamesOfOfficers2::= SET {
    president      [0] VisibleString (SIZE(1..32)) OPTIONAL,
    vicePresident  [1] VisibleString (SIZE(1..32)),
    treasurer      [2] VisibleString OPTIONAL,
    secretary      [3] VisibleString (SIZE(1..32)) OPTIONAL }
typedef struct NamesOfOfficers2 {
    unsigned char   bit_mask;
#define      president_present 0x80
#define      secretary_present 0x40
    char   president[33];  /* optional; set in bit_mask
                                     * president_present if present */
    char   vicePresident[33];
    char   *treasurer;  /* NULL for not present */
    char   secretary[33];  /* optional; set in bit_mask
           * secretary_present if present */
} NamesOfOfficers2;
typedef struct NamesOfOfficers2 {
    char   *president;  /* NULL for not present */
    char   *vicePresident;
    char   *treasurer;  /* NULL for not present */
    char   *secretary;  /* NULL for not present */
} NamesOfOfficers2;

Note that, when -helperNames is not specified, although the field treasurer is OPTIONAL, it is not represented in the bitmask since its pointer can simply be set to the address of a character string or to NULL to indicate its presence or absence, respectively.

Macros generated for SET are identical to the ones generated for the SEQUENCE type.

See Also

SET OF

Example

C C (with -helperNames)
typedef struct Name1 {
    struct Name1  *next;
	       Type1   value;
} *Name1;
typedef struct Name1 {
    struct Name1   *next;
	       Type1    value;
} *Name1;
typedef struct Name1 {
    struct Name1_node *head;
    struct Name1_node *tail;
    unsigned int    count;
} Name1;

typedef struct Name1_node {
    struct Name1_node *next;
    struct Name1_node *prev;
    Type1             *value;
} Name1_node;

By default, when -helperNames is specified, the DLINKED-PLUS representation is generated for SET OF types with structured or pointered non-structured elements.

The UNBOUNDED representation is generated for SET OF types with simple non-pointered elements:

typedef struct Name1 {
	  unsigned int   count;
	  ossBoolean     *value;
} Name1;

In the absence of directives SizeConstraint does not affect the representation.

Example

ASN.1 C
SetSzOfInt ::= SET SIZE(5) OF INTEGER
typedef struct SetSzOfInt {
    struct SetSzOfInt *next;
    int             value;
} *SetSzOfInt;

If the OSS.ARRAY directive is specified, an array of types is generated, preceded by a count of the number of occurrences that follow. The OSS.POINTER directive is implied when the OSS.ARRAY directive is used. If SizeConstraint is also specified, depending on the array size, a short or int is generated to indicate the size of the array.

ASN.1 C
SetArOfInt ::= SET --<ARRAY>-- OF INTEGER
typedef struct SetArOfInt {
    unsigned int    count;
    int             value[1];  /* first element of the array */
} *SetArOfInt;

If only the OSS.DLINKED directive is specified alone, a pointer to a doubly linked list of values is generated.

ASN.1 C
SetDlOfInt ::= SET --<DLINKED>-- OF INTEGER
typedef struct SetDlOfInt {
    struct SetDlOfInt *next;
    struct SetDlOfInt *prev;
    int             value;
} *SetDlOfInt;

If the OSS.LINKED directive is specified, a pointer to a linked list of values is generated.

ASN.1 C
SetLnOfInt ::= SET --<LINKED>-- OF INTEGER
typedef struct SetLnOfInt {
    struct SetLnOfInt *next;
    int             value;
} *SetLnOfInt;

If the OSS.UNBOUNDED directive is specified, a pointer to a string of types is generated, preceded by a count of the number of occurrences pointed to.

ASN.1 C
SetUnOfInt ::= SET --<UNBOUNDED>-- OF INTEGER
typedef struct SetUnOfInt {
    unsigned int    count;
    int             *value;
} SetUnOfInt;

If the OSS.DLINKED-PLUS directive is specified, two structures are generated. One structure whose name has the _node suffix is a doubly linked list of values similar to the DLINKED representation. The second structure keeps pointers to the head and to the tail nodes in the doubly-linked list as well as the count field where the number of nodes in the list is stored. This structure is used to facilitate linked-list manipulation in the helper list API.

ASN.1 C
SetDPlusOfInt ::= SET --<DLINKED-PLUS>-- OF INTEGER
typedef struct SetDPlusOfInt {
    struct SetDPlusOfInt_node *head;
    struct SetDPlusOfInt_node *tail;
    unsigned int    count;
} SetDPlusOfInt;

typedef struct SetDPlusOfInt_node {
    struct SetDPlusOfInt_node *next;
    struct SetDPlusOfInt_node *prev;
    int             value;
} SetDPlusOfInt_node;

When the OSS.UNBOUNDED directive is used with SizeConstraint, the UNBOUNDED representation is used. However, if -helperNames is not specified or implied, the type of the count field varies depending on the size needed to accommodate the maximum number of occurrences in the SET OF. Without SizeConstraint, an int is always generated for the count field for the UNBOUNDED representation.

ASN.1 C C (with -helperNames)
SetSzUnOfInt ::= SET SIZE(33) --<UNBOUNDED>-- OF INTEGER
typedef struct SetSzUnOfInt {
    unsigned short  count;
    int             *value;
} SetSzUnOfInt;
typedef struct SetSzUnOfInt {
    unsigned int  count;
    int           *value;
} SetSzUnOfInt;

When the OSS.ARRAY directive is used with SizeConstraint, the ARRAY representation is used, but the type of the count field varies depending on the size needed to accommodate the maximum number of occurrences in the SET OF. Without the SizeConstraint, an int is always generated for the count field under the ARRAY representation.

ASN.1 C
SetSzArOfInt ::= SET SIZE(33000) --<ARRAY>-- OF INTEGER
typedef struct SetSzArOfInt {
    unsigned short  count;
    int             value[33000];
} SetSzArOfInt;

SizeConstraint has no effect on the LINKED representation. OSS.POINTER simply introduces an additional level of indirection.

ASN.1 C
SetSzLnPtOfInt ::= SET SIZE(5) --<LINKED|POINTER>-- OF INTEGER
typedef struct SetSzLnPtOfInt {
    struct SetSzLnPtOfInt *next;
    int             value;
} **SetSzLnPtOfInt;

The following examples illustrate the effect of a SizeConstraint on TypeX (where the SET OF type is of the form Street-addresses ::= SET OF TypeX):

ASN.1 C
Street-addresses1 ::= SET SIZE (1..20) --<ARRAY>-- OF
	                        VisibleString (SIZE (1..64))
typedef struct Street_addresses1 {
    unsigned short  count;
    char            value[20][65];
} Street_addresses1;
Street-addresses2 ::= SET SIZE (1..20) --<LINKED>-- OF
	                        VisibleString (SIZE (1..64))
typedef struct Street_addresses2 {
    struct Street_addresses2 *next;
    char            value[65];
} *Street_addresses2;
Street-addresses3 ::= SET SIZE (1..20) --<UNBOUNDED>-- OF
	                        VisibleString (SIZE (1..64))

typedef struct Street_addresses3 {
    unsigned short  count;
    char            (*value)[65];
} Street_addresses3;

Here is an example of a nested SET OF with no directives:

ASN.1 C C (with -helperNames)
Street-addresses4 ::= SET OF SET OF
	    VisibleString (SIZE (1..64))
typedef struct Street_addresses4 {
    struct Street_addresses4 *next;
    struct _setof1 {
        struct _setof1  *next;
        char            value[65];
    } *value;
} *Street_addresses4;
typedef struct Street_addresses4 {
    struct Street_addresses4_node *head;
    struct Street_addresses4_node *tail;
    unsigned int    count;
} Street_addresses4;

typedef struct Street_addresses4_node {
    struct Street_addresses4_node *next;
    struct Street_addresses4_node *prev;
    struct Street_addresses4_setof *value;
} Street_addresses4_node;

typedef struct Street_addresses4_setof {
    struct Street_addresses4_setof_node *head;
    struct Street_addresses4_setof_node *tail;
    unsigned int    count;
} Street_addresses4_setof;

typedef struct Street_addresses4_setof_node {
    struct Street_addresses4_setof_node *next;
    struct Street_addresses4_setof_node *prev;
    char            *value;
} Street_addresses4_setof_node;

Here is an example of a nested SET OF, the OSS.LINKED directive, and the OSS.UNBOUNDED directive:

ASN.1 C
Street-addresses5 ::= SET --<LINKED>-- OF
                      SET --<UNBOUNDED>-- OF
                      VisibleString (SIZE (1..64))
typedef struct Street_addresses5 {
    struct Street_addresses5 *next;
    struct {
        unsigned int    count;
        char            (*value)[65];
    } value;
} *Street_addresses5;

Macros generated for SET OF are identical to the ones for the SEQUENCE OF type.

See Also

Tagged

ASN.1 C
TaggedIntegerType      ::= INTEGER
MySeq ::= SEQUENCE {
     builtInInt        INTEGER,
     tagggedInt        TaggedIntegerType
}
typedef int             TaggedIntegerType;

typedef struct MySeq {
    int             builtInInt;
    TaggedIntegerType tagggedInt;
} MySeq;

Remarks

Note that int and TaggedIntegerType are equated above using a typedef statement.

TIME | DATE | DATE-TIME | DURATION | TIME-OF-DAY

ASN.1 C
Time ::= TIME
t Time ::= "R/P12Y"
 
Date ::= DATE
d Date ::= "1999-10-12"

Time t = "R/P12Y";;;
Date d = "1999-10-12";
typedef char            *Time;
typedef char            *Date;

Remarks

These time types are always represented as null-terminated strings.

See Also

UTCTime

ASN.1 C C (with -helperNames)
Name1 ::= UTCTime
typedef UTCTime Name1;
where UTCTime is defined in file asn1hdr.h as
typedef GeneralizedTime UTCTime;
typedef char            *Name1;

Remarks

Although UTCTime uses the same C structure as GeneralizedTime, the semantics of the two structures differ. When used to represent UTCTime, the year field is in YY format, and the millisec field is ignored by the encoder and set to zero by the decoder.

The UTCTime type can be represented either as UTCTime structs ( { short year; short month; } ) or as strings. Strings are used when the -lean option or the NULLTERM directive is specified.

When the NULLTERM directive is used, UTCTime types are represented as strings. The -lean or -helperNames option has the same effect as NULLTERM.

Example

ASN.1 C
Name1  ::= UTCTime --<NULLTERM>--

 -- If local time is 7am on 2 January 1982 and coordinated universal
 -- time is 12 noon on 2 January 1982, the value of UTCTime is either of:
   t1 Name1 ::= "8201021200Z"
   t2 Name1 ::= "8201020700-0500"
typedef char            *Name1;

    Name1 t1 = "8201021200Z";
    Name1 t2 = "8201020700-0500";

Remarks

The OSS.HelperMacro directive applied to a UTCTime with NULLTERM representation generates the following helper macros:

  • _new or _new_pdu macro to allocate memory for the string of given length and set all bytes of the allocated memory block to zero.
  • _copy or _copy_pdu macro to allocate memory and copy given input null terminated time value to it.

The OSS.HelperMacro directive applied to a UTCTime with TIMESTRUCT directive generates the following helper macros:

  • _new or _new_pdu macro to allocate memory for the time structure and set all bytes of the allocated memory block to zero.
  • _copy_nullterm or _copy_nullterm_pdu macro to allocate memory for the time structure and initialize it by parsing a string containing a time value.
  • _setv_nullterm macro to initialize existing time structure by parsing a string containing a time value.

Example

ASN.1 Helper macros
--<OSS.HelperMacro Mod.SeqUTime>--
--<OSS.HelperMacro Mod.SeqUTime.n-time>--
--<OSS.TIMESTRUCT  Mod.SeqUTime.s-time>--
--<OSS.HelperMacro Mod.SeqUTime.s-time>--
Mod DEFINITIONS ::= BEGIN
SeqUTime ::= SEQUENCE {
    n-time UTCTime,
    s-time UTCTime 
}
END
typedef struct SeqUTime {
    char            *n_time;
    UTCTime         *s_time;
} SeqUTime;

...

/* allocates memory for a string of given length */
#define oss_SeqUTime_n_time_new(world, length_) \
    oss__CharStr_new(world, length_)

/* allocates memory and returns a copy of an input string */
#define oss_SeqUTime_n_time_copy(world, value_) \
    oss__CharStr_copy(world, value_)

...

/* allocates memory for the time structure */
#define oss_SeqUTime_s_time_new(world) \
    (UTCTime *)ossGetInitializedMemory(world, sizeof(UTCTime))

/* allocates memory for the time structure and initializes it by parsing a
 * string containing an UTCTime value */
#define oss_SeqUTime_s_time_copy_nullterm(world, value_) \
    oss__UTCTime_copy_nullterm(world, value_)

/* initializes the structure by parsing a string containing an UTCTime value */
#define oss_SeqUTime_s_time_setv_nullterm(world, outp, value_) \
    oss__UTCTime_setv_nullterm(world, outp, value_)

See Also

OID-IRI | RELATIVE-OID-IRI

By default, the C representation is NULLTERM-POINTER.

Example

ASN.1 C C (with -helperNames)
ID ::= OID-IRI --<NULLTERM>--
typedef char            *ID;
ID ::= OID-IRI --<UNBOUNDED>--
typedef struct ID {
		unsigned int    length;
		char            *value;
		} ID;
typedef struct _UnbCharStr {
		unsigned int    length;
		char            *value;
		} _UnbCharStr;

		typedef _UnbCharStr ID;

The OSS.HelperMacro applied on the OID-IRI and RELATIVE-OID-IRI types has the same effect as on the restricted character string types.

See Also

ASN.1 Macros

The representation of ASN.1 macro instances in C is determined by the type returned by the macro instance, irrespective of the C representation of the returned type.

For example, when an ASN.1 macro (ERROR), is defined as follows:

ERROR MACRO ::= BEGIN
   TYPE NOTATION ::= "PARAMETER" NamedType | empty 
   VALUE NOTATION ::= value (VALUE INTEGER)
   NamedType ::= identifier type | type
END

and is used as follows:

ErrorRecord ::= SEQUENCE {
    rectype ERROR PARAMETER VisibleString,
    sector                  INTEGER
}

The C representation is:

typedef struct ErrorRecord {
int rectype;
int sector;
} ErrorRecord;

PDUs

Each PDU defined in your ASN.1 input files can be represented in C when you compile your syntax. Representations of PDUs can be affected by the following:

  • ASN.1 type definition options (DEFAULT, SIZE())
  • Compiler options and directives (--<POINTER>--)
  • Platform defaults (typically optimized for size)

Values

Values are declared and initialized in the generated C code. To declare values, you can use either the ASN.1 syntax or the XML syntax. For example, the following lines of code are equivalent:

studentAge INTEGER ::= 23
studentAge ::= <INTEGER>23</INTEGER>

Comments

ASN.1 comments are transferred into C code.

Tags

ASN.1 tags do not affect the C representation of ASN.1 types.

ASN.1 C
Int   ::= INTEGER
Big   ::= INTEGER (12345678900)
Small ::= INTEGER (255)
Var   ::= INTEGER --<POINTER>--
typedef int             Int;
typedef ULONG_LONG      Big;
typedef unsigned short  Small;
typedef int             *Var;

Type Extensibility

The ASN.1 extensibility marker ("...") ensures compatibility between current and future versions of the schema. Types defined as extensible receive a bitmask that indicates whether elements defined after the extensibility marker are present or absent.

ASN.1 C
/* Version 1 */
Names ::= SEQUENCE {
   president     VisibleString (SIZE(1..32)),
   vicePresident VisibleString (SIZE(1..32)),
   secretary     VisibleString (SIZE(1..32)),
   ...
}
/* Version 1 */
typedef struct Names {
    char            president[33];
    char            vicePresident[33];
    char            secretary[33];
} Names;
/* Version 2 */
Names ::= SEQUENCE {
   president     VisibleString (SIZE(1..32)),
   vicePresident VisibleString (SIZE(1..32)),
   secretary     VisibleString (SIZE(1..32)),
   ...,
   treasurer     VisibleString (SIZE(1..32))
}
/* Version 2 */
typedef struct Names {
    unsigned char   bit_mask;
#       define      treasurer_present 0x80
    char            president[33];
    char            vicePresident[33];
    char            secretary[33];
    char            treasurer[33];  /* extension #1; set in bit_mask
                                     * treasurer_present if present */
} Names;

Remarks

The compiler generates a special code to inform the encoder/decoder about the presence of extensible elements. For each PDU, the decoder is instructed to:

  • Ignore all elements of a CHOICE, SEQUENCE, or SET, whose tags are not defined in the schema.
  • Ignore bits, if no names are assigned to them in the schema.
  • Ignore unrecognized elements in named number lists of ENUMERATED and INTEGER types.
  • Allow values that are not defined in the original constrained INTEGER type.
  • Allow array sizes that are not specified in the original definitions of SEQUENCE OF and SET OF types.
  • Allow unrecognized sizes and values for constrained character string types (IA5String, NumericString, PrintableString, BMPString, UniversalString).

Parameterized Types

Parameterized types are represented in the same way as types resulted from parameter substitution.

Example

ASN.1 C
Module DEFINITIONS ::= BEGIN
   DesiredType ::= INTEGER
   Record {TypeForSubstitution} ::= SET{ 
      myTypeVar    TypeForSubstitution,
      filled       BOOLEAN
   } 

   MyRec ::= Record {DesiredType}
END
typedef int             DesiredType;

typedef struct Record {
    DesiredType     myTypeVar;
    ossBoolean      filled;
} Record;

typedef Record          MyRec;

Information Object Classes

Information object classes contain three common types of fields:

Type fields
Identify specific types associated with the information object. By default, the compiler assigns ascending INTEGERs (starting from 1) to types declared for information objects. For each type field, the ASN.1 compiler generates an unsigned short.
Object set fields
For each object set field, the ASN.1 compiler generates an ObjectSetEntry.
Value fields
For each value field, the ASN.1 compiler generates a specific C type representation.

In the following example, &ArgumentType and &ResultType are type fields, &Errors and &Linked are object set fields, and &resultReturned and &operationCode are value fields:

ASN.1 C
OPERATION ::= CLASS {
   &ArgumentType  OPTIONAL,
   &ResultType    OPTIONAL,
   &Errors ERROR  OPTIONAL,
   &Linked OPERATION OPTIONAL,
   &resultReturned BOOLEAN DEFAULT TRUE,
   &operationCode INTEGER UNIQUE
   }
                 
ERROR ::= CLASS {
   &ParameterType OPTIONAL,
   &errorCode INTEGER UNIQUE
   }
                
intIsValid OPERATION ::= {
   &ArgumentType INTEGER,
   &ResultType   BOOLEAN,
   &Errors {intIsNegative},
   &operationCode 7
   }
   
intIsNegative ERROR ::= {
   &errorCode 1
   }
   
intIsZero ERROR ::= {
   &errorCode 2
   } 

NegZeroInfoObjSet ERROR ::= {
intIsNegative | intIsZero,
 ...
}
typedef struct ObjectSetEntry {
struct ObjectSetEntry *next;
void *object;
struct ObjectSetEntry *prev;
char *object_name;
 } ObjectSetEntry;

#define IntIsValid_integer_PDU 1
#define IntIsValid_boolean_PDU 2
#define NegZeroInfoObjSet_OSET 1

typedef struct OPERATION {
unsigned char bit_mask;
# define ArgumentType_present 0x80
# define ResultType_present 0x40
# define resultReturned_present 0x20
unsigned short ArgumentType; 
unsigned short ResultType;
ObjectSetEntry *Errors; /* NULL for not present */
ObjectSetEntry *Linked; /* NULL for not present */
ossBoolean resultReturned; 
int operationCode;
} OPERATION;

typedef struct ERROR {
unsigned char bit_mask;
# define ParameterType_present 0x80
unsigned short ParameterType; 
int errorCode;
} ERROR;

typedef int IntIsValid_integer;
typedef ossBoolean IntIsValid_boolean;
extern OPERATION intIsValid;
extern ERROR intIsNegative;
extern ERROR intIsZero;

Remarks

The ObjectSetEntry structure is used to traverse a series of information objects which together form an information object set. Each object field points to an information object.

The first item in the ObjectSetEntry double-linked list has its prev pointer set to NULL and the last element has its next pointer set to NULL.

The compiler generates bitmasks and #defined constants for OPTIONAL and DEFAULT fields in the information object classes.

The above example is based on clause 11 and 12 of ITU-T Rec. X681 (2021) | ISO/IEC 8824-2 : 2021.


This documentation applies to the OSS® ASN.1 Tools for C release 11.3 and later.

Copyright © 2024 OSS Nokalva, Inc. All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted in any form or by any means electronic, mechanical, photocopying, recording or otherwise, without the prior permission of OSS Nokalva, Inc.
Every distributed copy of the OSS® ASN.1 Tools for C is associated with a specific license and related unique license number. That license determines, among other things, what functions of the OSS ASN.1 Tools for C are available to you.