The generated C or C++ include file contains a section for each ASN.1 production defined in the ASN.1 source file. Different items will be generated depending on whether the selected output code is C or C++. In general, C++ will add some additional items (such as a control class definition) onto what is generated for C.
The following items are generated for each ASN.1 production:
Tag value constant
Choice tag constants (CHOICE type only)
Named bit number constants (BIT STRING type only)
Enumerated type option values (ENUMERATED or INTEGER type only)
C type definition
Encode function prototype
Decode function prototype
Other function prototypes depending on selected options (for example, print)
C++ control class definition (C++ only)
A sample section from a C header file is as follows:
/**************************************************************/ /* */ /* EmployeeNumber */ /* */ /**************************************************************/ #define TV_EmployeeNumber(TM_APPL|TM_PRIM|2) typedef OSINT32 EmployeeNumber; EXTERN int asn1E_EmployeeNumber (OSCTXT* pctxt, EmployeeNumber *pvalue, ASN1TagType tagging); EXTERN int asn1D_EmployeeNumber (OSCTXT* pctxt, EmployeeNumber *pvalue, ASN1TagType tagging, int length);
This corresponds to the following ASN.1 production specification:
EmployeeNumber ::= [APPLICATION 2] IMPLICIT INTEGER
In this definition, TV_EmployeeNumber is the tag constant. Doing a logical OR on the class, form, and identifier fields forms this constant. This constant can be used in a comparison operation with a tag parsed from a message.
The following line:
typedef OSINT32 EmployeeNumber;
declares EmployeeNumber to be of an integer type (note: OSINT32 and other primitive type definitions can be found in the osSysTypes.h header file).
asn1E_EmployeeNumber and asn1D_EmployeeNumber are function prototypes for the encode and decode functions respectively. These are BER function prototypes. If the -per switch is used, PER function prototypes are generated. The PER prototypes begin with the prefix asn1PE_ and asn1PD_ for encoder and decoder respectively. XER function prototypes begin with asn1XE_ and asn1XD_.
A sample section from a C++ header file for the same production is as follows:
/**************************************************************/ /* */ /* EmployeeNumber */ /* */ /**************************************************************/ #define TV_EmployeeNumber(TM_APPL|TM_PRIM|2) typedef OSINT32 ASN1T_EmployeeNumber; class EXTERN ASN1C_EmployeeNumber : public ASN1CType { protected: ASN1T_EmployeeNumber& msgData; public: ASN1C_EmployeeNumber (ASN1T_EmployeeNumber& data); ASN1C_EmployeeNumber ( ASN1MessageBufferIF& msgBuf, ASN1T_EmployeeNumber& data); // standard encode/decode methods (defined in ASN1CType base class): // int Encode (); // int Decode (); // stream encode/decode methods: int EncodeTo (ASN1MessageBufferIF& msgBuf); int DecodeFrom (ASN1MessageBufferIF& msgBuf); } ; EXTERN int asn1E_EmployeeNumber (OSCTXT* pctxt, ASN1T_EmployeeNumber *pvalue, ASN1TagType tagging); EXTERN int asn1D_EmployeeNumber (OSCTXT* pctxt, ASN1T_EmployeeNumber *pvalue, ASN1TagType tagging, int length);
Note the two main differences between this and the C version:
The use of the ASN1T_ prefix on the type definition. The C++ version uses the ASN1T_ prefix for the typedef and the ASN1C_ prefix for the control class definition.
The inclusion of the ASN1C_EmployeeNumber control class.
As of ASN1C version 5.6, control classes are not automatically generated for all ASN.1 types. The only types they are generated for are those determined to be Protocol Data Units (or PDU’s for short). A PDU is a top-level message type in a specification. These are the only types control classes are required for because the only purpose of a control class is to provide the user with a simplified calling interface for encoding and decoding a message. They are not used in any of the ASN1C internally generated logic (the exception to this rule is the XER / XML encoding rules where they are used internally and still must be generated for all types).
A type is determined to be a PDU in two different ways:
If it is explicitly declared to be PDU via the <isPDU/> configuration setting or -pdu command-line option.
If no explicit declarations exist, a type is determined to be a PDU if it is not referenced by any other types.
In the employee sample program, EmployeeNumber would not be considered to be a PDU because it is referenced as an element within the Employee production. For the purpose of this discussion, we will assume EmployeeNumber was explicitly declared to be a PDU via a configuration setting or command-line specification.
ASN1C_EmployeeNumber is the control class declaration. The purpose of the control class is to provide a linkage between the message buffer object and the ASN.1 typed object containing the message data. The class provides methods such as EncodeTo and DecodeFrom for encoding and decoding the contents to the linked objects. It also provides other utility methods to make populating the typed variable object easier.
ASN1C always adds an ASN1C_prefix to the production name to form the class name. Most generated classes are derived from the standard ASN1CType base class defined in asn1Message.h. The following ASN.1 types cause code to be generated from different base classes:
BIT STRING – The generated control class is derived from the ASN1CBitStr class
SEQUENCE OF or SET OF with linked list storage – The generated control class is derived from the ASN1CSeqOfList base class.
Defined Type – The generated control class for defined types is derived from the generated base class for the reference type. For example, if we have A ::= INTEGER and B ::= A, then B is a defined type and would inherit from the base class generated for A (class ASN1C_B : public ASN1C_A { … ).
These intermediate classes are also derived from the ASN1CType base class. Their purpose is the addition of functionality specific to the given ASN.1 type. For example, the ASN1CBitStr control class provides methods for setting, clearing and testing bits in the referenced bit string variable.
In the generated control class, the msgData member variable is a reference to a variable of the generated type. The constructor takes two arguments – an Asn1MessageBufferIF (message buffer interface) object reference and a reference to a variable of the data type to be encoded or decoded. The message buffer object is a work buffer object for encoding or decoding. The interface reference can also be used to specify a stream. Stream classes are derived from this same base class. The data type reference is a reference to the ASN1T_ variable that was generated for the data type.
EncodeFrom and DecodeTo methods are declared that wrap the respective compiler generated C encode and decode stream functions. Standard Encode and Decode methods exist in the ASN1CType base class for direct encoding and decoding to a memory buffer. Command-line options may cause additional methods to be generated. For example, if the –print command line argument was specified; a Print method is generated to wrap the corresponding C print function.
The equivalent C and C++ type definitions for each of the various ASN.1 types follow.