Since nicknames will be used as the basis for naming files, generated
IDL files will only be reusable in an environments where
identical nickname databases are used. Therefore, it is desirable to
make the nickname database as standard as possible (for example, have
standard
nicknames for all registered ASN.1 modules). In
order to facilitate this, the following nickname selection method is
recommended (but not mandatory):
As it is illegal to modify the existing contents of a standard in this context, it is assumed that the nickname always refers to the latest version of the standard. If, for any reason, parts of the original standard are modified in a revision, the last 2 digits of the revision year can be appended to the nickname.
In order to translate between ASN.1 and CORBA IDL, (hereinafter referred to simply as IDL), it is necessary to be able to map the basic definitions (that is, mapping between ASN.1 types and IDL type definitions).
There are two versions of ASN.1 defined, ASN.1:1990 (see reference ASN1) and ASN.1:1994 (see reference ASN1:1994). Since GDMO explicitly builds on ASN.1 and all new GDMO will provide ASN.1:1990 versions (at least in the short term), this document focuses on that version. However, translation is also provided for all the basic types (for example, BMPString and UniversalString) from ASN.1:1994 as a step towards migration to ASN.1:1994. Further steps on this path may be taken in the future.
In this document, unless otherwise noted, the unqualified name ASN.1 refers to ASN.1:1990.
ASN.1 has a much more complex type system than IDL. As a result, the translation necessarily loses some information; for instance in terms of tag values, sub-range types, compound type constants, etc. Capturing this information for subsequent use in the run-time system is a key issue. A number of schemes have been proposed including the use of string constants and #pragma directives, but the definitive statement is deferred to Interaction Translation.
In a number of cases, the complexity of some data types makes it desirable to define operations for manipulating their values. In CORBA, the standard technique is to define pseudo-IDL (PIDL) which allows a fairly tight definition of the operations but with the implication that these operations have library implementations and can only be invoked locally. For example, this is used to provide access methods to support manipulation of the BitString data type.
Lexical disambiguation is done when generating the mapping in this step, as described in the following sections in this document.
-
-
#ifndef _<capitalised_nickname>_IDL_
#define _<capitalised_nickname>_IDL_
module <nickname> {
<generated-IDL-code>
};
#endif /* _<capitalised_nickname>_IDL_ */
-
-
#include "<module_nickname>.idl"
to the corresponding IDL file, where <module_nickname> is the
nickname that has been assigned to the imported ASN.1 module.
This directive appears before the module being defined.
// Generated from X501.asn1
|
// X501Inf.idl file:
|
|
#ifndef _X501INF_IDL_
|
#define _X501INF_IDL_
|
|
module X501Inf {
|
|
|
};
|
|
#endif /* _X501INF_IDL_ */
|
In ASN.1, names for type-references, identifiers, value-references and module-references consist of an arbitrary sequence of one or more letters, digits, and hyphens. The letters and digits in ASN.1 names are mapped directly retaining case. The ASN.1 hyphen ("-") maps to IDL underscore ("_"). Subject to the possible suffixing as described below, names will be preserved, for example, CMISFilter type in ASN.1 will be mapped as CMISFilterType[n] in IDL.
ASN.1 names are case sensitive and IDL identifiers are not. In addition, ASN.1 has different name-spaces for types-references, identifiers and value-references, whereas IDL has a single namespace. Both have scoped naming spaces, but the naming scopes do not directly map. For example, enumerated types create a new naming scope in ASN.1 but not in IDL. It is therefore not possible to simply map ASN.1 names to IDL identifiers. To handle this, the translator must maintain a table of all identifiers in each resulting IDL scope and modify colliding identifiers within a given IDL scope to avoid such conflicts.
Not all conflicts arise from ASN.1 names. Additional conflicts could arise from clashes with IDL reserved words such as "interface" and identifiers and types defined in the base IDL file ASN1Types.idl and ASN1Limits.idl. The translator must take account of such existing definitions and use the same disambiguating mechanism to avoid clashes.
Clearly, all identifiers could be modified in order to
disambiguate, however the goal of the translation mechanism to
generate the simplest mapping where possible, leads to a
slightly more complex algorithm but preserves a direct mapping
where no ambiguity arises. The mapping used will therefore be
context dependent and hence the final mapping will be a necessary
input to the Interaction Translation since any gateway must be
able to replicate such mappings.
The rules for disambiguation are as follows:
When disambiguating CHOICE values, this rule is also applied where "Choice" is appended to the IDL enumerator; in this case, "Choice<_n>" should be appended instead.
This rule is also applied in the case where "Choice" and "Choice<n>" is appended in order to disambiguate CHOICE types.
With this scheme, type references cannot clash with identifiers or value references and these latter two are disambiguated numerically. Since the most commonly occurring clash is between data type names and identifiers differentiated only by the case of the first letter, this algorithm avoids the majority of clashes. For example, constructs such as eventRecord EventRecord translate to EventRecordType eventRecord;. In addition, it is easy to recover the original ASN.1 type identifier by finding the "Type" suffix and removing it and all subsequent text from the identifier. Giving preference to identifiers ensures minimum impact on the names of members of sequences and sets and such like so that application code is minimally impacted. The "Type<n>" suffix marks all types explicitly which, in many ways, helps code readability.
Further ambiguity can arise from directly translated names colliding with generated names. For example, a type may have name MyData, and a variable may have name myDataType. The translation of MyData would be MyDataType and this would collide with the direct translation of myDataType. This would be resolved by the normal disambiguation rule. In the same way, translations of ASN.1 constructs may append Opt, Default, etc, to type names, so this must also be considered during disambiguation.
The use of single underbar to separate numeric disambiguators does not guarantee that there will be no further clashes with other ASN.1 identifiers. This should be resolved using the same disambiguation rule.
In subsequent examples, it is assumed that there are no clashes with identifiers or types outside the given ASN.1 text. Thus identifiers largely map unchanged and type identifiers are mapped mapped with the "Type" suffix.
For lexical mapping collisions, a strict order of the ASN.1 input actually mapped to IDL is applied. That is, identifiers, names or literals that are not used for the translation process, are not considered for lexical collision purposes. This means that:
-
-
A ::= ENUMERATED { a(1), b(x) }
B ::= ENUMERATED { x(1), y(2) }
x ::= INTEGER x_1 = 3
The defined value "x" of the "b" literal in "A" type is not mapped, so it is not considered. Thus resulting mapping code would be:
-
-
enum AType = {a, b};
enum BType = {x, y};
const ASN1_Integer x_1 = 3;
<ModuleDefinition> ::=
|
<ModuleIdentifier> DEFINITIONS <TagDefault> ::= BEGIN
|
<ModuleBody>
|
END
|
|
<ModuleIdentifier> ::=
|
<modulereference>
|
<DefinitiveIdentifier>
|
|
<TagDefault> ::= EXPLICIT TAGS | IMPLICIT TAGS |
|
AUTOMATIC TAGS | empty
|
|
<ModuleBody> ::=
|
<Exports> <Imports> <AssignmentList> | empty
|
|
<Exports> ::=
|
EXPORTS <SymbolsList> ; | empty
|
|
<Imports> ::=
|
IMPORTS <SymbolsImported> ; | empty
|
|
<SymbolsImported> ::=
|
<SymbolsFromModuleList> | empty
|
|
<SymbolsFromModuleList> ::=
|
<SymbolsFromModule> | <SymbolsFromModuleList> <SymbolsFromModule>
|
|
<SymbolsFromModule> ::=
|
<SymbolList> FROM <GlobalModuleReference>
|
|
<GlobalModuleReference> ::=
|
<modulereference AssignedIdentifier>
|
|
<SymbolList> ::=
|
<Symbol> | <SymbolList> , <Symbol>
|
|
<AssignmentList> ::=
|
<Assignment> | <AssignmentList> <Assignment>
|
-
-
// ModuleIdentifier:<ModuleIdentifier>
In addition, an IDL #pragma is generated as follows:
-
-
#pragma ID <moduleNickname> "OSIOID:<DefinitiveIdentifier>"
If there is no definitive identifier then nothing is generated.
For each module imported from, an include directive is generated before the importing module definitions as follows:
-
-
#include <module_nickname>.idl
The production:
-
-
IMPORTS <symbol1>, ..., <symboln> FROM <GlobalModuleReference>
is mapped as follows for imported types:
-
-
typedef <moduleNickname>::<mapped symbol1> <mapped symbol1>
........
typedef <moduleNickname>::<mapped symboln> <mapped symboln>
The two mapped symbols may be different as they are disambiguated in different naming contexts - the imported from and the importing modules.
For imported ASN.1 values, code will be generated depending on
whether their types are simple or complex (see
-
-
const <type of imported const> <mapped symbol1> =
<moduleNickname>::<mapped symbol1>
...
const <type of imported const> <mapped symboln> =
<moduleNickname>::<mapped symboln>
Note that <GlobalModuleReference> is only used to identify the unique module nickname and does not appear in the IDL.
Otherwise, they are mapped as per normal.
An ASN.1 comment commences with a pair of adjacent hyphens ("--") and ends with the next pair of adjacent hyphens or at the end of the line, which ever comes first. In IDL, comments are delimited as per C++, using either /* and */ or // and end of line. The choice of which delimitation to use is left as an implementation concern.
ASN.1 Type | IDL Type
|
---|---|
BOOLEAN | typedef boolean ASN1_Boolean;
|
INTEGER | typedef long ASN1_Integer;
|
REAL | typedef double ASN1_Real;
|
NULL | typedef char ASN1_Null; const ASN1_Null ASN1_NullValue = '\x00'; |
ENUMERATED | enum <enumName> {<elem1>,......, <elemn>};
|
BIT STRING | typedef sequence<octet> ASN1_BitString;
|
// supported by PIDL
| |
OCTET STRING | typedef sequence<octet> ASN1_OctetString;
|
IA5 STRING | typedef string ASN1_IA5String;
|
ISO646 STRING | typedef string ASN1_ISO646String;
|
NUMERIC STRING | typedef string ASN1_NumericString;
|
PRINTABLE STRING | typedef string ASN1_PrintableString;
|
TELETEXT STRING | typedef string ASN1_TeletextString;
|
T61 STRING | typedef string ASN1_T61String;
|
VIDEO STRING | typedef string ASN1_VideoString;
|
VISIBLE STRING | typedef string ASN1_VisibleString;
|
GENERAL STRING | typedef sequence<octet> ASN1_GeneralString;
|
GRAPHIC STRING | typedef sequence<octet> ASN1_GraphicString;
|
BMP STRING | typedef sequence<unsigned short> ASN1_BMPString;
|
UNIVERSAL STRING | typedef sequence<unsigned long> ASN1_UniversalString;
|
OBJECT IDENTIFIER | typedef string ASN1_ObjectIdentifier;
|
ANY | typedef any ASN1_Any;
|
ANY DEFINED BY | typedef any ASN1_DefinedAny;
|
Tagged | as untagged type
|
EXTERNAL | struct ASN1_External { ASN1_ObjectIdentifier syntax; ASN1_DefinedAny data_value; // by 'syntax' }; |
Functions defined as translation of complex ASN.1 constants are included at the end of the IDL modules in the ConstValues interface. In general, a constant declaration of type <ConstType> with identifier <constName> would result in the generation of the operation:
-
-
interface ConstValues {
<ConstType> <constName>(); // returns "<text of constant value definition>"
........
};
For examples, see
-
-
typedef char ASN1_Null;
const ASN1_Null ASN1_NullValue = '\x00';
ASN.1 | IDL
|
---|---|
Married ::= BOOLEAN | typedef ASN1_Boolean MarriedType;
|
maritalStatus Married ::= TRUE | const MarriedType maritalStatus = TRUE;
|
For a named-number, the form <name>(<number>) within an integer type <type> generates the IDL const declaration:
-
-
const <type>Type[n] <name> = <number>;
The form <name>(<identifier>) within an integer type <type> generates the IDL const declaration:
-
-
const <type>Type[n] <name> = <translated identifier>;
Note that the identifier must also be translated in order to ensure that the right IDL identifier is referenced. Note also that these named values are subject to disambiguation in the normal way.
ASN.1 | IDL
|
---|---|
T0 ::= INTEGER | typedef ASN1_Integer T0;
|
a INTEGER ::= 1 | const ASN1_Integer a = 1;
|
T1::= INTEGER { a(2) } | typedef ASN1_Integer T1Type;
|
const T1Type a = 2;
| |
ax INTEGER ::= 1 | const ASN1_Integer ax = 1;
|
aX INTEGER ::= 2 | const ASN1_Integer aX_1 = 2;
|
T2 ::= INTEGER { a(3), b(aX) } | typedef ASN1_Integer T2Type;
|
c T2 ::= b | const T2Type a = 3;
|
d T2 ::= a | const T2Type b = aX_1;
|
const T2Type c = b;
| |
const T2Type d = a;
|
ASN.1 constants PLUS-INFINITY and MINUS-INFINITY are mapped to IDL double precision floating point constants plus_infinity and minus_infinity respectively. The values of these constants are defined int the file ASN1Limits.idl. In ASN.1, a floating point value may be defined as a triple of mantissa, base and exponent. In this case, the value of the constant is calculated and the corresponding double precision decimal floating point constant is used
ASN.1 | IDL
|
---|---|
AngleInRadians ::= REAL | typedef ASN1_Real AngleInRadiansType;
|
pi REAL ::= { 3141592653897, 10, -12} | const ASN1_Real pi =3.141592653897;
|
This does not preserve the actual values of the element values and the Interaction Translation process would need to support the dynamic mapping between values received on the wire and the corresponding enum values. As a consequence of this, any application requiring to access the actual values would be able to retrieve them via the management knowledge at run-time. The full details of the creation and maintenance of the management knowledge is addressed in the Interaction Translation Document.
It is important to note that the names of values in an enumerated type are identifiers in the enclosing scope since in IDL, enum does not define a new naming scope. This means that enum names are subject to disambiguation in the normal way but in a slightly wider scope than might otherwise be expected.
ASN.1 | IDL
|
---|---|
Message ::= ENUMERATED {basic(0), extended(1)} | enum MessageType { basic, extended }; |
DayOfTheWeek ::= ENUMERATED { sunday(0),monday(1), tuesday (2), wednesday (3), thursday(4), friday(5), saturday(7)} first DayOfTheWeek ::= sunday | enum DayOfTheWeekType { sunday, monday, tuesday, wednesday, thursday, friday, saturday }; interface ConstValues { .... DayOfTheWeekType first(); // returns "sunday"; .... }; |
MaritalStatus ::= ENUMERATED { single(0), married(2), widowed(1)} } | enum MaritalStatusType { single, married, widowed }; |
BIT STRING literal values encoded in this way, cannot be represented
as
IDL
constants and are handled via the mechanism defined in
Each named bit is mapped as an IDL constant of type unsigned long with value equal to the offset into the bit string. The name of the constant is the given name, disambiguated by the usual rules:
-
-
const unsigned long <bitname> = <offset>;
Note that offset may be defined by another constant.
-
-
interface ASN1_BitStringHandler { // PIDL
typedef short BitValue;
ASN1_BitString createBitString (in unsigned long number_of_bits);
BitValue getBit (in ASN1_BitString bit_string, in unsigned long
position);
void setBit (inout ASN1_BitString bit_string, in unsigned long position,
in BitValue new_bit_value);
long length (in ASN1_BitString bit_string);
string asString (in ASN1_BitString bit_string);
// produces a string with binary values ("1001011B")
void setFromString (inout ASN1_BitString bit_string, in string
string_value);
};
ASN.1 | IDL
|
---|---|
MessageFlag ::= BIT STRING { posResp (0), negResp (1), doNotForward (2) } | typedef ASN1_BitString MessageFlagType; const unsigned long posResp = 0; const unsigned long negResp = 1; const unsigned long doNotForward = 2; |
T0 ::= BIT STRING a INTEGER ::= 1 T1::= INTEGER { a(2) } T2 ::= BIT STRING { a(3), b(a) } | typedef ASN1_BitString T0Type; const ASN1_Integer a = 1; typedef ASN1_Integer T1Type; const T1Type a_1 = 2; typedef ASN1_BitString T2Type; const unsigned long a_2 = 3; const unsigned long b = a; |
G3FacsimilePage ::= BIT STRING -- a sequence of bits conforming to -- Recommendation T.4 image G3FacsimilePage ::= '100110100100001110110'B trailer BIT STRING ::= '0123456789ABCDEF'H | typedef ASN1_BitString G3FacsimilePageType; interface ConstValues { G3FacsimilePageType image(); // "'100110100100001110110'B"; BitString trailer(); // "'0123456789ABCDEF'H"; }; |
PersonalStatus ::= BIT STRING {married (0), employed (1), veteran(2), collegeGraduate (3)} johnDoe PersonalStatus ::= {married, employed, collegeGraduate} | typedef ASN1_BitString PersonalStatusType; const unsigned long married = 0; const unsigned long employed = 1; const unsigned long veteran = 2; const unsigned long collegeGraduate = 3; interface ConstValues { PersonalStatusType johnDoe(); // "married, employed, collegeGraduate"; }; |
OCTET STRING literals can be either binary of hexadecimal strings. In either case, the value is expanded from left to right as a sequence of bits with octets taken in order from the left. The final octet is padded with 0 bits if necessary.
Octet string literals cannot be represented as constants in IDL
and hence, are mapped in accordance with
ASN.1 | IDL
|
---|---|
G4FacsimilePage ::= OCTET STRING -- a sequence of octets conforming to -- Recommendation T.5 and T.6 image G4FacsimilePage ::= '3FE2EABAD471005'H | typedef ASN1_OctetString G4FacsimilePageType; interface ConstValues { G4FacsimilePageType image(); // "'3FE2EABAD471005'H"; }; |
The IDL file ASN1Types.idl contains the following typedefs which can then be used directly in the translated IDL:
-
-
// These can contain X'00'
typedef sequence<octet> ASN1_GeneralString;
typedef sequence<octet> ASN1_IA5String;
typedef sequence<octet> ASN1_VideotexString;
// These should support wide characters
typedef sequence<unsigned short> ASN1_BMPString;
typedef sequence<unsigned long> ASN1_UniversalString;
// These cannot
typedef string ASN1_NumericString;
typedef string ASN1_PrintableString;
typedef string ASN1_VisibleString;
typedef ASN1_VisibleString ASN1_ISO646String;
typedef string ASN1_GraphicString;
typedef ASN1_GraphicString ASN1_ObjectDescriptor;
typedef string ASN1_TeletexString;
typedef ASN1_TeletexString ASN1_T61String;
-
-
typedef ASN1_GraphicString ASN1_ObjectDescriptor;
GeneralizedTime and UTCTime are formatted string representations of time values (see reference ASN.1, clause 32). As strings, these values are not particularly easy to manipulate, for example, for comparison. For this reason PIDL functions are provided to manipulate these values converting to and from a more useful form corresponding to the POSIX timeval structure. Note that both GeneralizedTime and UTCTime optionally contain time zone information. Where this is not present, all operations assume that the time is local time and work accordingly.
-
-
#include "ASN1Types.idl"
interface ASN1_GeneralizedTimeHandler // PIDL
{
void set(inout ASN1_GeneralizedTime t, in unsigned long seconds,
in long useconds, in long tzp);
void get(in ASN1_GeneralizedTime t, out unsigned long seconds,
out long useconds, out long tzp);
short compare(in ASN1_GeneralizedTime t1, in ASN1_GeneralizedTime t2);
void setFromString( inout ASN1_GeneralizedTime t, in string s );
string asString(in ASN1_GeneralizedTime t );
}
interface ASN1_UTCTimeHandler // PIDL
{
void set(inout ASN1_UTCTime t, in unsigned long seconds,
in long useconds, in long tzp);
void get(in ASN1_UTCTime t, out unsigned long seconds,
out long useconds, out long tzp);
short compare(in ASN1_UTCTime t1, in ASN1_UTCTime t2);
void setFromString(inout ASN1_UTCTime t, in string s );
string asString(in ASN1_UTCTime t );
}
The format of the time strings is the ASN.1 value notation.
-
-
typedef string ASN1_ObjectIdentifier;
The contents of an ASN.1_ObjectIdentifier will be the value of the ASN.1 object identifier, in dot string notation (sequence of decimal representation of numbers in the object identifier, separated by dots, without any intervening spaces).
Constants of this ASN1_ObjectIdentifier type are represented as string literals which contain the value of the object identifier, in dot string notation.
ASN.1 | IDL
|
---|---|
AttributeId ::= OBJECT IDENTIFIER | typedef ASN1_ObjectIdentifier
|
AttributeIdType;
| |
arfProbableCause OBJECT IDENTIFIER ::= { joint-iso-ccitt ms(9) smi(3) part2(2) standardSpecificExtension(0) arf(0) } adapterError OBJECT IDENTIFIER ::= { arfProbableCause 1 } | const ASN1_ObjectIdentifier arfProbableCause = "2.9.3.2.0.0"; const ASN1_ObjectIdentifier adapterError = "2.9.3.2.0.0.1"; |
ASN.1 | IDL
|
---|---|
Attribute ::= SEQUENCE { attributeId OBJECT IDENTIFIER, attributeValue ANY DEFINED BY attributeId } | struct AttributeType { ASN1_ObjectIdentifier attributeId; ASN1_DefinedAny attributeValue; // defined by attributeId }; |
-
-
typedef X208Ext::ExternalType ASN1_External;
The module X208Ext is the direct application of the ASN.1 to IDL mapping to the ASN.1 definition of the EXTERNAL type, as follows:
ASN.1 |
---|
External ::= [UNIVERSAL 8] IMPLICIT SEQUENCE { |
direct-reference OBJECT IDENTIFIER OPTIONAL, |
indirect-reference INTEGER OPTIONAL, |
data-value-descriptor ObjectDescriptor OPTIONAL, |
encoding CHOICE { |
single-ASN1-type [0] ANY, |
octet-aligned [1] IMPLICIT OCTET STRING, |
arbitrary [2] IMPLICIT BIT STRING |
} |
} |
IDL |
module X208Ext { |
union ASN1_ObjectIdentifierOpt switch (boolean) { |
case TRUE: ASN1_ObjectIdentifier value; |
}; |
union ASN1_IntegerOpt switch (boolean) { |
case TRUE: ASN1_Integer value; |
}; |
union ASN1_ObjectDescriptorOpt switch (boolean) { |
case TRUE: ASN1_ObjectDescriptor value; |
}; |
enum ExternalEncodingTypeChoice { |
single_ASN1_typeChoice, |
octet_alignedChoice, |
arbitraryChoice |
}; |
union ExternalEncodingType switch(ExternalEncodingTypeChoice) { |
case single_ASN1_typeChoice: ASN1_Any single_ASN1_type; |
case octet_alignedChoice: ASN1_OctetString octet_aligned; |
case arbitraryChoice: ASN1_BitString arbitrary; |
}; |
struct ExternalType { |
ASN1_ObjectIdentifierOpt direct_reference; |
ASN1_IntegerOpt indirect_reference; |
ASN1_ObjectDescriptorOpt data_value_descriptor; |
ExternalEncodingType encoding; |
}; |
Note that this follows the rules described in
The approach to mapping constructed types is to map them according to
CHOICE, SET and SEQUENCE result from the aggregation of other types. From the ASN.1 grammar point of view, they are a list of elements. Each element is basically formed by an ASN.1 Named Type and some optional extra features.
In the case of SET and SEQUENCE type definitions, elements can be OPTIONAL or have default values. Also the COMPONENTS OF structure may be specified instead of the set of elements it represents.
In the case of the CHOICE type definition, none of these features are allowed , but instead the type of the Named Type can take the form of a selection type (which is not allowed for SET or SEQUENCE).
SET OF and SEQUENCE OF result from the aggregation of several instances of the same type which will be called an "item" in this document.
ASN.1 Construct | IDL Construct | Comments |
---|---|---|
CHOICE | union/switch | An enum is to be defined for switch case-constant. |
SET SEQUENCE | struct | struct members are declared in the same order as they are declared in the ASN.1 type. |
Selection Type | mapped as type of selected element | i.e. the selection type is first transformed to obtain its real element type |
OPTIONAL | union <mapped-type-name> Opt switch (boolean) { case TRUE: <type> value; } | an extra type is created to indicate whether the element is present. |
DEFAULT | typedef <mapped-type-name>Opt
<mapped=-type-name>Def; | same as OPTIONAL, with an extra typedef created to indicate whether the element is Default. |
SET-OF type
SEQUENCE-OF type | sequence<mapped-type-name> |
Rules to map each element or item in a constructed type are provided below:
When used in the elements or items of a constructed type, these are considered composite types. To avoid nested type declarations, they are extracted and a new IDL type is defined (unless recursion is detected). Thus a named IDL type definition is created.
The name of the new IDL type assignment is formed by concatenating the ASN.1 name of the container type (that is, the name of the constructed type that contains the current element/item without the "Type[<n>]" suffix) with the name of the element/item with an upper case first letter. Note that if it is an element, disambiguation with prior element names in the same constructed type must be done. Then the general rules for lexical mapping disambiguation of types are applied (that is, the corresponding Type[<n>] suffix is added).
Note that if recursion is detected, the rules described in
ASN.1 | IDL
|
---|---|
-- example with elements Bar ::= SEQUENCE { -- definition of an composite type paff SEQUENCE { a INTEGER, b VisibleString }, -- definition of a composite type dummy ENUMERATED { one(1), two(2) }, -- reference to primitive type, c INTEGER } | // mapping of the ASN.1 Bar type struct BarPaffType { ASN1_Integer a; ASN1_VisibleString b; }; enum BarDummyType {one, two); struct BarType { BarPaffType paff; BarDummyType dummy; ASN1_Integer c; }; |
-- example with items (no composite type) Array ::= SET OF INTEGER | //mapping of the ASN.1 Array type typedef sequence<ASN1_Integer> ArrayType; |
IDL does not fully support similar constructs, therefore the mapping needs to resolve these issues.
An element without an explicit name is converted to an element with a name taking the form elem<n>, where <n> specifies the position of such element within the definition of the constructed type..
When dealing with an item, if it represents a composite type, a new
type
is created as described above. A name has to be provided because
these
definition types have no name associated with them. To provide an
homogeneous
way to solve the mapping, the identifier item will be used as
if it
were the name of an element whose type is the one defined by the
item.
Thus the item identifier will be used as the name of the item when
Composite Type rules are to be applied (see
Note that when SET OF and SEQUENCE OF constructs have an
item
which is a Composite Type, it is always an anonymous item also.
This is because items do not have an identifier name in the ASN.1
grammar.
ASN.1 | IDL
|
---|---|
-- example with anonymous elements A::=SEQUENCE { INTEGER, b INTEGER, BOOLEAN, ENUMERATED { one(1), two(2) } } | //mapping of ASN.1 A type enum AElem4Type {one, two}; struct AType { ASN1_Integer elem1; ASN1_Integer b; ASN1_Boolean elem3; AElem4Type elem4; }; |
-- example of anonymous items CorrelNotif ::= SET OF SEQUENCE { correlNotif SET OF NotificationIdentifier } | // mapping of ASN.1 CorrelNotif type typedef sequence <NotificationIdentifierType> CorrelNotifItemCorrelNotifType; struct CorrelNotifItemType { CorrelNotifItemCorrelNotifType correlNotif; }; typedef sequence<CorrelNotifItemType> CorrelNotifType; |
The IDL identifier for the type of the discriminator is formed by adding a suffix "Choice" to the translated identifier of the CHOICE type. For each alternate, there will be one identifier in the discriminator type. This translated identifier is the identifier of the alternate suffixed by "Choice" and disambiguated within its IDL scope in the normal way.
Finally, the union type itself is constructed with one case for each alternate with label according to the enum type and the type and identifier according to the (intermediate) alternate. The resulting IDL looks like:
-
-
enum <choicetype>Choice {
<translated-identifier>Choice,
....... // one for each alternate
}
union <choicetype> switch (<choicetype>Choice) {
case <translated-identifier>Choice: <type> <translated-identifier>;
....... // one for each alternate
}
where <choicetype> is the name of the translated type (including "Type" suffix and numeric disambiguator if necessary).
ASN.1 | IDL
|
---|---|
Context ::= CHOICE { id INTEGER, data EXTERNAL } | enum ContextTypeChoice { idChoice, dataChoice }; union ContextType switch (ContextTypeChoice) { case idChoice: ASN1_Integer id; case dataChoice: ASN1_External data; }; |
Here is a fragment of the X.721 | ISO/IEC 10165-2 (1992) definition of ProbableCause showing the constants adapterError and applicationSubsystemFailure.
-
-
Attribute-ASN1Module {
joint-iso-ccitt ms(9) smi(3) part2(2) asn1Module(2) 1}
DEFINITIONS IMPLICIT TAGS ::= BEGIN
IMPORTS .......;
....
adapterError ProbableCause ::= globalValue : { arfProbableCause 1 }
applicationSubsystemFailure ProbableCause ::=
globalValue : { arfProbableCause 2 }
..........
ProbableCause ::= CHOICE {
globalValue OBJECT IDENTIFIER, localValue INTEGER
}
..........
END
-
-
module X721Att {
enum ProbableCauseTypeChoice {
globalValueChoice,
localValueChoice
};
union ProbableCauseType switch (ProbableCauseTypeChoice) {
case globalValueChoice: ASN1_ObjectIdentifier globalValue;
case localValueChoice: ASN1_Integer localValue;
};
...
interface ConstValues {
ProbableCauseType adapterError();
ProbableCauseType applicationSubsystemFailure();
...
};
};
Then an application program might access the values along the following lines:
-
-
// obtain access to the predefined ConstValue object for accessing the
// interface defined constants. This would probably be a pseudo object
X721Att::ConstValues constants (...);
// use constant in an assignment
ProbableCauseType pc; pc = constants.adapterError();
ASN.1 | IDL
|
---|---|
Attribute ::= CHOICE { number INTEGER, name VisibleString } Ident ::= CHOICE { id number < Attribute, name < Attribute } | // map the Attribute type enum AttributeTypeChoice { numberChoice, nameChoice }; union AttributeType switch (AttributeTypeChoice) { case numberChoice:ASN1_Integer number; case nameChoice: ASN1_VisibleString name; }; // map the Ident type enum IdentTypeChoice { idChoice, nameChoice_1 }; union IdentType switch (IdentTypeChoice) { case idChoice: ASN1_Integer id; case nameChoice_1: ASN1_VisibleString name; }; |
-
-
SEQUENCE { <identifier> <type> OPTIONAL}
the resultant IDL would be:
union <mapped type name>Opt switch (boolean) {case TRUE: <mapped type name> value;};
SEQUENCE { <identifier> <type> DEFAULT <value>; }
the resultant IDL would be:
-
-
typedef <mapped type name>Opt <mapped type name>Def;
If the "Opt" type had not been generated yet, then it should be generated
here, as described above in
To access the default value, either a constant or a PIDL function returning such value is provided. Where a programmer in the CORBA domain wants to use the default value, this constant or function call must be explicitly used. So if an ASN.1 DEFAULT value is present for a set or sequence element, an IDL constant will be generated, named by appending Default to the element's identifier and defined as the given default value. For example:
const <mapped type name> <mapped identifier>Default = <value>;
If the type of the element precludes the use of an IDL constant
then the mechanism described in
ASN.1 | IDL |
---|---|
T::= SEQUENCE {a Ta, b Tb, c Tc} E::= SEQUENCE {f1 E1, f2 T, f3 E3} | struct TType {TaType a; TbType b; TcType c;}; struct EType {E1Type f1; TType f2; E3Type f3;}; |
T::= SEQUENCE { a Ta, b SEQUENCE {b1 T1, b2 T2,b3 T3} c Tc } | struct TbType {T1Type b1; T2Type b2; T3Type b3;}; struct TType {TaType a; TbType b; TcType c;}; // The algorithm results in an additional // type TbType for the composite SEQUENCE // type in T. |
W ::= SEQUENCE {x Wx, COMPONENTS OF T, y Wy} | struct WbType { T1Type b1; T2Type b2; T3Type b3; }; struct WType { WxType x; TaType a; WbType b; TcType c; WyType y; }; // The algorithm expands the // COMPONENTS OF part of W before // translating to IDL. |
UserName ::= SET { -- SET treated as -- SEQUENCE personalName VisibleString, countryName VisibleString OPTIONAL } | union ASN1_VisibleStringOpt switch (boolean) { case TRUE: ASN1_VisibleString value; }; struct UserName { ASN1_VisibleString personalName, ASN1_VisibleStringOpt countryName, }; |
A ::= SET { a ENUMERATED {a, b}, b ENUMERATED {a, b} } | enum AaType {a, b}; enum AbType {a_1, b_1}; struct AType { AaType a; AbType b; }; |
Data :: = SEQUENCE { replaceWithDefault BOOLEAN DEFAULT FALSE, defaultValue ValueSpecifier, keyword SEQUENCE { type-reference DefinedType, field Identifier } OPTIONAL, createModifier BIT STRING { withRefObject (0), withAutoNaming (1) } } | union ASN1_BooleanOpt switch (boolean) { case TRUE: ASN1_Boolean value; }; typedef ASN1_BooleanOpt ASN1_BooleanDef; const ASN1_Boolean replaceWithDefaultDefault=FALSE; struct DataKeywordType { DefinedTypeType type_reference; IdentifierType field; }; union DataKeywordTypeOpt switch (boolean) { case TRUE: DataKeywordType value; }; typedef ASN1_BitString DataCreateModifierType; const unsigned long withRefObject = 0; const unsigned long withAutoNaming = 1; struct DataType { ASN1_BooleanDef replaceWithDefault; ValueSpecifierType defaultValue; DataKeywordTypeOpt keyword; DataCreateModifierType createModifier; } |
The last example is worth looking at in more detail. First, all composite types are handled by explicitly generating named types DataKeywordType and DataCreateModifierType.
Next, apply the rules for OPTIONAL and DEFAULT, generating a named value for the default and union types for both the OPTIONAL and DEFAULT components, that is, replaceWithDefaultDefault, ASN1_BooleanDef, and DataKeywordTypeOpt.
Now all the problem cases have been removed, the translation proceeds naturally resulting in the IDL as shown in the table above.
ASN.1 | IDL
|
---|---|
RDNSequence::= SEQUENCE OF RDN | typedef sequence<RDNType>
|
RDNSequenceType;
| |
Status ::= SEQUENCE OF INTEGER { | typedef ASN1_Integer StatusItemType;
|
initializationRequired (0), | const StatusItemType initializationRequired = 0;
|
notInitialized (1), | const StatusItemType notInitialized = 1;
|
initializing (2), | const StatusItemType initializing= 2;
|
reporting(3), | const StatusItemType reporting = 3;
|
terminating (4) | const StatusItemType terminating = 4;
|
} |
|
typedef sequence<StatusItemType> StatusType;
| |
A ::= SEQUENCE OF | typedef sequence<ASN1_Integer> AItemType;
|
SEQUENCE OF | typedef sequence<AItemType> AType;
|
INTEGER |
|
Unlike ASN.1, IDL does not support recursive type definitions, except direct recursions when they are used in sequences. Indirect mutual recursion is explicitly prohibited in IDL. The only solution to indirect mutual recursion, then, is to loose type safety by introducing an IDL "any", and semantically restricting its contents to those of the recursive type (applications are responsible for enforcing the semantics).
For the ASN.1 clause:
-
-
<type> ::= SEQUENCE { <identifier> <type> OPTIONAL }
the resultant IDL would be:
-
-
struct <mapped type name> {
union <mapped identifier name>Opt switch (boolean) {
case TRUE: sequence<<mapped type name>, 1> value;
} <mapped identifier name>;
};
and for the ASN.1 clause:
-
-
<type> ::= SEQUENCE { <identifier> [SET|SEQUENCE] OF <type> OPTIONAL }
the resultant IDL would be:
-
-
struct <mapped type name> {
union <mapped identifier name>Opt switch (boolean) {
case TRUE: sequence<<mapped type name>> value;
} <mapped identifier name>;
};
These same rules apply when a named type has the DEFAULT property, changing the "Opt" suffix of the IDL union to "Def".
ASN.1 | IDL
|
---|---|
Filter ::= CHOICE { item [8] FilterItem, and [9] IMPLICIT SET OF Filter, or [10] IMPLICIT SET OF Filter, not [11] Filter } | enum FilterTypeChoice { itemChoice, andChoice, orChoice, notChoice }; union FilterType switch (FilterTypeChoice) { case itemChoice: FilterItemType item; case andChoice: sequence<FilterType> and; case orChoice: sequence<FilterType> or; case notChoice: sequence<FilterType, 1> not; } |
NameTree ::= SEQUENCE { generation INTEGER, parents SET SIZE(0..2) OF NameTree, children SET OF NameTree } | struct NameTreeType { ASN1_Integer generation; sequence <NameTreeType, 2> parents; // SIZE constraint: [0..2] sequence <NameTreeType> children; } |
NumberTree ::= SEQUENCE { level INTEGER, root NumberTree OPTIONAL, children SET OF NumberTree OPTIONAL } | struct NumberTreeType { ASN1_Integer level; union rootDef switch (boolean) { case TRUE: sequence <NumberTreeType, 1> value; } root; union childrenOpt switch (boolean) { case TRUE: sequence <NumberTreeType> value; } children; } |
Note that types must be considered in their ASN.1 input order, and that only recursive references to the type being considered are substituted by this rule.
The references substituted by this rule should be mapped to the IDL type named ASN1_Recursive, defined in the ASN1Types.idl file as:
-
-
typedef any ASN1_Recursive;
A comment is added to identify the IDL type corresponding
to the substituted reference. Only values of this IDL
type are allowed in the
ASN1_Recursive.
If a value of a different type is inserted, the behavior is undefined.
ASN.1 | IDL
|
---|---|
NameTree ::= SEQUENCE { rdnInfo RDNInfo, family SET OF SEQUENCE { coparent NameTree, children SET OF NameTree } } | typedef sequence<ASN1_Recursive> NameTreeFamilyItemChildrenType; // must be NameTreeType struct NameTreeFamilyItemType { ASN1_Recursive coparent; // must be NameTreeType NameTreeFamilyItemChildrenType children; }; typedef sequence<NameTreeFamilyItemType> NameTreeFamilyType; struct NameTreeType { RDNInfoType rdnInfo; NameTreeFamilyType family; }; |
A ::= SET OF B B ::= SEQUENCE { a INTEGER, b A } | struct BType { ASN1_Integer a; ASN1_Recursive b; // must be AType }; typedef sequence<BType> AType; |
B ::= SEQUENCE { a INTEGER, b A } A ::= SET OF B | typedef sequence<ASN1_Recursive> AType; // must be BType struct BType { ASN1_Integer a; AType b; }; |
A ::= SEQUENCE { a INTEGER, b B } B ::= SEQUENCE { x INTEGER, y C } C ::= SET OF A | typedef sequence<ASN1_Recursive> CType; // must be AType struct BType { ASN1_Integer x; CType y; }; struct AType { ASN1_Integer a; BType b; }; |
-- NOTE: Unusable ASN.1 types -- due to circular references. A ::= SEQUENCE { b B, c C } B ::= SEQUENCE { a A, c C } C ::= SEQUENCE { a A, b B } | struct CType { ASN1_Recursive a; // must be AType ASN1_Recursive b; // must be BType }; struct BType { ASN1_Recursive a; // must be AType CType c; }; struct AType { CType c; BType b; } |
-
-
typedef sequence <<ItemType>, <upper-bound>> <type>;
where <ItemType> is the type of the SEQUENCE OF/SET OF item and <type> is the translated name of the compound type. For example:
-
-
T1 ::= SEQUENCE SIZE(0..10) OF ObjectInstance
T2 ::= SEQUENCE SIZE(1|3|5) OF INTEGER
maps to:
-
-
typedef sequence<ObjectInstanceType, 10> T1Type;
// T1Type SIZE(0..10)
typedef sequence<ASN1_Integer, 5> T2Type;
// T2Type SIZE(1|3|5)
Dynamic access to size information in order to ensure validity may be covered as part of Interaction Translation.
When a size constraint is applied to BIT STRING types, a constant integer literal is generated in the IDL. The identifier for the integer literal is generated by adding "_size" as a suffix to the translated parent type. This is because the mapping of BIT STRING to sequence of octet does not have the necessary granularity to usefully bound the sequence.
When a size constraint is applied to OCTET STRING or other STRING derived types, these are mapped as string or bounded sequences depending on the original type definition, where the upper-bound of the sequence in IDL is determined by the upper-end-value of the size constraint.
However, when the size constraint is applied to a non-composite named type marked as OPTIONAL or DEFAULT it is ignored, except for comment purposes.
More complex type constraints are ignored by Specification Translation and may be addressed in Interaction Translation.
Type | Min | Max | Condition | IDL Native Type
|
---|---|---|---|---|
ASN1_Unsigned16 | 0 | 2^16-1 | none | unsigned short
|
ASN1_Unsigned | 0 | 2^32-1 | 2^16 <= upper | unsigned long
|
ASN1_Unsigned64 | 0 | 2^64-1 | 2^32 <= upper | unsigned long long
|
ASN1_Integer16 | -2^15 | 2^15-1 | lower < 0 | short
|
ASN1_Integer | -2^31 | 2^31-1 | lower < 0 && | long
|
(lower < -2^15 || 2^15 <=upper) |
| |||
ASN1_Integer64 | -2^63 | 2^63-1 | lower < 0 && | long long
|
(lower < -2^31 || 2^31 <= upper) |
|
The lower and upper bounds for the ASN.1 INTEGER subtype must be within the minimum and maximum stated values for the corresponding IDL type (inclusive), and they should also fulfill the corresponding condition. In the table, the lower bound value of the ASN.1 value range INTEGER subtype is referred to as "lower", and the corresponding upper bound value as "upper"
If the ASN.1 type has a value range INTEGER subtype specification that is beyond the stated limits for ASN1_Unsigned64 and ASN1_Integer64, an ASN1_Unsigned64 will be generated if the lower bound has a positive or 0 value, otherwise an ASN1_Integer64 will be generated. The user will be informed of the translation limitation.
REAL is mapped as double in IDL. Value ranges are ignored.
-
-
A ::= INTEGER(1|3|5|7)
would be translated as
-
-
typedef ASN1_Unsigned16 AType; // AType (1|3|5|7)
Single Type Constraint (WITH COMPONENT) is ignored during Specification Translation. The specified type is generated without constraints.
Multiple Type Constraints (WITH COMPONENTS) are used for SET, SEQUENCE and CHOICE. This kind of constraint contains a list of constraints on the component of types of the parent type. The inner type to which the constraint applies is determined by the identifier.
When Full Specification is used there is an implied presence constraint of ABSENT on all inner types which can be constrained to be absent and which is not explicitly listed.
When Partial Specification is used and the parent type is a SET or SEQUENCE type, there are no implied constraints and any inner type can be omitted from the list. When an empty Presence Constraint is used, it is equivalent to a constraint PRESENT for a SET or SEQUENCE component marked OPTIONAL. In a Partial Specification no such constraint is imposed.
When Partial Specification is used and the parent type is a CHOICE type, there is implied presence constraint of PRESENT on all inner types which are not explicitly listed.
When Multiple Type Constraints are used to define a type from another type, the translation process generates a new type. Its components depend on the Multiple Type Constraints. The rules are as follows:
When the Inner Type Constraint is applied to a base type that is defined in a different module, it may occur that the types of some of the members of the new subtype are not known in the scope of the current module. In this case they must be explicitly imported from the module in which the base type is defined3.
-
-
PDU ::= SET {
alpha INTEGER,
beta IA5String OPTIONAL,
gamma SEQUENCE OF Parameter,
delta BOOLEAN
}
TestPDU ::= PDU (WITH COMPONENTS { ..., delta (FALSE),
alpha (MIN..<0) }) -- PartialSpecification
FurtherTestPdu ::= TestPDU (WITH COMPONENTS {... ,
beta (SIZE (5|12)) PRESENT})
is treated as if it were the following equivalent ASN.1 form which can be translated to IDL via the usual rules.
-
-
TestPDU ::= SET {
alpha INTEGER (MIN..<0),
beta IA5String OPTIONAL,
gamma SEQUENCE OF Parameter OPTIONAL,
delta BOOLEAN (FALSE)
}
FurtherTestPdu ::= SET {
alpha INTEGER (MIN..<0) OPTIONAL,
beta IA5String (SIZE (5|12) ,
gamma SEQUENCE OF Parameter OPTIONAL,
delta BOOLEAN (FALSE) OPTIONAL
}
Example 2
-
-
TestPDU ::= PDU (WITH COMPONENTS { delta (FALSE),
alpha (MIN..<0) }) -- FullSpecification
would change the equivalent ASN.1 form to:
-
-
TestPDU ::= SET {
alpha INTEGER (MIN..<0),
delta BOOLEAN (FALSE)
}
Now apply the SetType mapping scheme for ASN.1 to IDL on TestPDU and FurtherTestPDU.
-
-
Z ::= CHOICE { a A, b B, c C, d D, e E}
V::= Z (WITH COMPONENTS { ..., a ABSENT,
b ABSENT}) -- TaU & TbU must be absent
W::= Z (WITH COMPONENTS { ...,
a PRESENT }) -- TaU must be present
X::= Z (WITH COMPONENTS { a PRESENT })
-- TaU must be present
Y::= Z (WITH COMPONENTS { a ABSENT, b, c})
-- TaU, TdU and TeU must be absent
is treated as the following equivalent ASN.1 form:
-
-
V ::= CHOICE { c C, d D, e E}
W ::= CHOICE { a A, b B, c C, d D, e E}
X ::= CHOICE { a A}
W ::= CHOICE { b B, c C}
The two files are contained in
Contents | Next section | Index |