Solstice Enterprise Manager 4.1 Developing C++ Applications | ![]() ![]() ![]() ![]() ![]() |
Encoding and Decoding Complex ASN.1 Values
In the Solstice EM environment, attribute values in management requests, responses and event notifications are represented in a machine-independent format for transmission over a network. The format used is defined in ITU-T X.208/ISO-8824 Specification of Abstract Syntax Notation One (ASN.1). This standard defines several complex data types and enables you to define your own custom data types. When an application sends a request to set an attribute value represented by a complex data type, the application must encode this value for transmission over a network. When an application receives an attribute value represented by a complex data type (for example in a response or an event notification) the application must decode this value to extract the information the value contains.
This chapter explains how to encode and decode complex ASN.1 values.
- Section 9.1 Introduction to the Morf Class
- Section 9.2 Creating Complex ASN.1 Values
- Section 9.3 Parsing Complex ASN.1 Values
- Section 9.4 Decoding Complex ASN.1 Values
- Section 9.5 Using the MorfBuilder Class
9.1 Introduction to the Morf Class
The high-level Portable Management Interface (PMI) API provides the Morf (mysterious object related to framework) class for representing complex ASN.1 values. To simplify the encoding and decoding of complex ASN.1 values, use the Morf class for:
- Creating complex ASN.1 values
- Parsing complex ASN.1 values to get information on their structure and content
- Decoding the values stored in complex ASN.1 values
Every instance of the Morf class is associated with an instance of the Syntax class. The Syntax class represents an ASN.1 type loaded into the metadata repository (MDR). The Morf class provides a simple way to transform string data into Asn1Value data in the underlying Syntax instance or to decode Asn1Value data into string data. Constructing and decoding complex data values by using strings is often much simpler than using the Asn1Value class directly.
Morf instances that represent complex data values can be used to pass data as a single instance to other functions and applications. This can be particularly useful is the data type of the value is unknown until run time, such as with a CHOICE type. In many cases where an application requires an Asn1Value instance, it is easier to construct a Morf instance and then use its get_value function to create the Asn1Value instance.
The MorfBuilder class provides additional facilities for building Morf instances that represent CHOICE, SET, SET OF, SEQUENCE, and SEQUENCE OF data types. The MorfBuilder class relies on constructing or decoding a value as a collection of Morf instances, so you need to understand how to work with the Morf class. Working with the MorfBuilder class is explained in Section 9.5 Using the MorfBuilder Class.
9.2 Creating Complex ASN.1 Values
To enable an application to send a request to set a complex ASN.1 value, you must create the value. To create a complex ASN.1 value, create and initialize an instance of the Morf class from any of the following:
- Data represented as strings
- Values that are instances of primitive types
- Other Morf instances
9.2.1 Creating a Morf Instance From String Data
You can represent the values in a complex value as a string. You can use this string directly in the Morf constructor or by calling the set function of the Morf class. The Morf class takes care of converting the string into the underlying Asn1Value instances contained in the complex value.
Most complex values contain lists of other values. Any value defined as a SET, SET OF, SEQUENCE, or SEQUENCE OF is considered a list. Lists can contain scalar values as well as other lists. Scalar values are represented literally as strings such as "32", "4.104", or "Satellite A". Lists require additional syntax to mark the start and end of the list and to separate the list members.
9.2.1.1 Representing Complex Values as Strings
To represent a list as a string, enclose all of the list data in braces, { and }, and separate members with a comma.
Use the name of an ENUMERATED type in the string.
Consider the syntax of the DestructSet type in the satellite example, as shown in CODE EXAMPLE 9-1 .
CODE EXAMPLE 9-1 ASN.1 Syntax of DestructSet
CheckSum ::= SET OF OBJECT IDENTIFIER DestructSet ::= SET OF SEQUENCE { name GraphicString, value Integer32, checkSum CheckSum }An instance of the DestructSet type is a set the members of which are sequences, and each sequence contains a set (checkSum). An instance of the DestructSet type that contains two members is represented as a string as follows:
"{{name \"Code 1\", value 6753, checkSum { 1 34 12 }}, {name \"Code B\", value 9345, checkSum { 3 12 5 }}}"9.2.1.2 Constructing a Morf Instance From a String
When you construct a Morf instance, you probably get the data for the Morf instance's attributes from various sources. Convert the data to DataUnit strings, then add the braces and commas required to order the data in sets and sequences. You can only build a Morf instance from a string that has values for all of the attributes in the underlying Syntax instance. You cannot update only a subset of the Morf instance's attributes.
If you need to build the subcomponents of a Morf instance at different times, consider building a Morf instance for each subcomponent. You can create an array of Morf instances from the subcomponents, and build a complex Morf instance that contains those subcomponents from the array. See Section 9.2.5 Creating Complex Morf Instances From Other Morf Instances.
CODE EXAMPLE 9-2 shows how to construct a destructSet from string data. This code creates a Syntax instance that represents the destructSet type, builds a string representation of a data set, then shows two ways of creating a Morf instance.
9.2.2 Creating Simple Morf Instances
The set_str function converts a string to an arbitrary ASN.1 scalar value, such as graphicString, topoBoolean, or INTEGER. The set_str function does not work on values that are instances of list types such as SET or SEQUENCE. Use set for values that are instances of list types.
It may be easier to use assign numeric data directly to a scalar, rather than first converting it to a character string. There are several functions for using numeric data to set the value of scalars based on numeric types.
The numeric data functions work on Morf instances that represent a scalar value the base type of which is one of the following:
- BOOLEAN
- ENUMERATED
- INTEGER
- OCTET STRING
- REAL
The functions for setting scalar values all return a new Morf instance. The functions in TABLE 9-1 set the ASN.1 value of scalar-valued Morf instances.
TABLE 9-1 Functions for Assigning Scalar Values to a Morf Instance set_dbl Use a variable of type double to assign a value to a scalar-valued numeric Morf instance. set_gint Use a reference to a variable of type GenInt to assign a value to a scalar-valued numeric Morf instance. Most types derived from int (long, I32, U32) can be cast as GenInt. set_long Use a variable of type long to assign a value to a scalar-valued numeric Morf instance. set_str Use a string to assign a value to a scalar-valued Morf instance of any ASN.1 type (for example: GraphicString, Integer32, or BOOLEAN). In the call to set_str, you also have to specify format bits to control the format of the string. For more information, see Section 9.4.1.2 Controlling the String Representation of a Morf Instance.
9.2.3 Selecting the Type for a CHOICE Value
Before you assign a value to a CHOICE type, call the set_memname function to select which real syntax this instance of the type should use.
A Morf instance that corresponds to a CHOICE value has no definite syntax until one of the types in the CHOICE is selected. If you attempt to assign a value to an uninitialized Morf instance of type CHOICE, the Morf instance will not understand which syntax to use.
CODE EXAMPLE 9-3 shows how to use set_memname.
CODE EXAMPLE 9-3 Selecting the Type for a CHOICE Value
... #include <pmi/hi.hh> ... // Assume Syntax syn is associated with a GeoLocation: // // GeoLocation ::= CHOICE { // null NULL, // value SEQUENCE { // longitude REAL, // latitude REAL // } // } ... Morf geoLocation(syn); geoLocation.set_memname("value"); // use value syntax, not null geoLocation.set("{longitude 122.35, latitude 38.35}"); ...9.2.4 Creating a Morf Instance for ASN.1 ANY Values
Call the set_any function to assign another Morf instance associated with the real syntax of the value to a Morf instance associated with an ANY or ANY DEFINED BY syntax. In the call to set_any, specify the Morf instance associated with the real syntax of the value.
ANY and ANY DEFINED BY values are harder to build programmatically because the actual ASN.1 type, syntax, and valid values for the data are context sensitive. For example, the AttributeValueAssertion type has the following syntax:
CODE EXAMPLE 9-4 ASN.1 Syntax of AttributeValueAssertion
AttributeType ::= OBJECT IDENTIFIER AttributeValue ::= ANY AttributeValueAssertion ::= SEQUENCE { type AttributeType, value AttributeValue }In this type, the kind of data referenced by the type field determines the syntax of the value field.
Assigning a value to a Morf instance of type ANY involves:
- Creating a Morf instance (m1) based on the Syntax instance of type ANY
- Creating a second Morf instance (m2) by using the real Syntax instance of the value to be assigned
- Assigning a value to the second Morf instance by calling, for example, set or set_str
- Calling set_any on m1, specifying m2 as follows:
m1.set_any(Morf m2(realSyntax, DU(realData));CODE EXAMPLE 9-5 shows the construction of an AttributeValueAssertion ASN.1 value. The value represents the attribute value assertion: topoBoolean = TRUE.
CODE EXAMPLE 9-5 Assigning a Value to an Instance of the ASN.1 ANY Type
... #include <pmi/hi.hh> ... // Create Syntax for AttributeValueAssertion, AttributeType // AttributeValue and TopoBoolean (real type of AttributeValue // Assume em_mis is an existing Platform instance // previously connected to the MIS Syntax avaSyn("attributeValueAsserion", em_mis); Syntax attSyn("attributeType", em_mis); Syntax atvSyn("attributeValue", em_mis); Syntax tbSyn("topoBoolean", em_mis); // get the OID of TopoBoolean to create a Morf Oid tbOid; Result r; if ((r = OidNameRegistry::find_oid_by_name("topoBoolean", tbOID)) != OK ) { // Handle error } Morf attMf(attSyn, tbOid.data()); // create an AttributeValue Morf (type ANY) and assign a // Morf of type TopoBoolean to it Morf atvMf(atvSyn); Morf tbMf(tbSyn, "TRUE"); atvMf = atvMf.set_any(tbMf); // Assemble the type and the value into one Morf Array(Morf) ava(2); ava[0] = attMf; ava[1] = atvMf; Morf avaMf(avaSyn, ava); ...9.2.5 Creating Complex Morf Instances From Other Morf Instances
CODE EXAMPLE 9-5 shows how to build a Morf instance by first building Morf instances that represent its component values. For SEQUENCE, SEQUENCE OF, SET, and SET OF type Morf instances, you can create an array that has the list members as elements, then use that array to construct a new Morf instance.
You can also use the Queue class to construct a Morf instance from a queue (that is, an ordered list) of Morf instances.
The syntax of the constructor for creating a Morf instance from an array of Morf instances is as follows:
Morf(Syntax& syn, Array(Morf)& ma)The syntax of the constructor for creating a Morf instance from a queue of Morf instances is as follows:
Morf(Syntax& syn, class Queue(MorfElem)& mq)These constructors are useful for simple SET and SEQUENCE values. More complex values may involve CHOICE values, SET values within SET values, or SEQUENCE OF SET values, for example. For constructing any moderately complex Morf instance, it is usually easier to use the MorfBuilder class. See Section 9.5 Using the MorfBuilder Class for information on using the MorfBuilder class.
Note A Morf instance does not change after you have constructed it. Changes made to an array or a queue after the Morf instance is constructed are not reflected in the Morf instance.
9.3 Parsing Complex ASN.1 Values
You usually derive a complex ASN.1 value from the Solstice EM platform as an instance of the Morf class without knowing its explicit type and structure. Parsing the Morf instance that represents a complex ASN.1 value enables you to understand the structure of the instance and its ASN.1 syntax. When you know the type and structure, you can extract the data you need from the Morf instance or run different code based on the type of data received.
Reading or modifying values in a Morf instance involves:
- Finding the member of the instance that you want (for example, a particular member of a SET or an attribute in a SEQUENCE)
- Verifying the ASN.1 type of the selected member
- Understanding any constraints on values for the selected type (valid ranges or size constraints)
You need to parse a Morf instance when the data type of a value is unknown, but also sometimes when the type is known. For CHOICE types, you must parse the Morf instance to determine which of the possible types the data represents.
The Morf class provides functions to discover the structure of a Morf instance and all of the data types of all the values it contains.
9.3.1 Structure of Morf Instances
Every Morf instance is associated with a Syntax instance that represents an ASN.1 type. Every ASN.1 type is either a scalar type or a constructed type. A constructed type is either a list type (namely: SET, SET OF, SEQUENCE, or SEQUENCE OF) or a CHOICE type.
The ANY or ANY DEFINED BY is an open type. The actual syntax of the data contained in an instance of the type could be any valid ASN.1 type. For ANY DEFINED BY, the possible syntax choices are restricted to types allowed by the type named in the declaration.
Lists and scalars may be combined with other lists or scalars to create more complex types. For example, a SEQUENCE can contain scalars and a SET of instances of the type SEQUENCE.
Functions for parsing a Morf instance enable you decompose a Morf instance into the values it contains, decompose those values, and so on, until you have identified all of the fundamental scalar values and how they are contained in other values.
Any type or a corresponding Morf instance can be only one of the following types:
- ANY
- CHOICE
- List type
- Scalar
Parsing a Morf instance involves:
- Determining the type associated with the Morf instance
- Doing one of the following, depending on the type:
9.3.2 Overview of Functions for Parsing Morf Instances
The functions of the Morf class for obtaining information about the structure of a Morf instance are listed in TABLE 9-2.
TABLE 9-2 Functions for Parsing Morf Instances extract Extracts the specified element as a Morf instance. Use a navigation string to specify an attribute name or element number in the current Morf instance or one of its contained values. Separate contained values with a dot (.). For example, the navigation string GeoLocation.value.latitude extracts the value of latitude from the value element in the attribute GeoLocation. The definition of the GeoLocation type is shown in CODE EXAMPLE 9-3 . get_member_names Returns an array of the Morf instance's attribute names. If the Morf instance represents an instance of a CHOICE type, returns the attribute names of the type chosen for the instance. get_memname Returns the attribute name of the ASN.1 type associated with the Morf instance. If the Morf instance represents an instance of a CHOICE type, returns the attribute names of the type chosen for the instance. get_platform Returns the Platform instance associated with the Morf instances's Syntax instance. get_syntax Returns a Syntax instance that represents the syntax associated with the Morf instance. get_type Returns an Asn1Type instance that corresponds to the Morf instance's ASN.1 type. has_value Use only to check if the Morf instance has a value assigned to it. If there is no value assigned or if the value is NULL, this function returns a null pointer. is_any Returns TRUE if the Morf instance represents an instance of type ANY or ANY DEFINED BY. is_choice Returns TRUE if the Morf instance represents an instance of type CHOICE. is_list Returns TRUE if the Morf instance represents an instance of type SEQUENCE, SEQUENCE OF, SET, or SET OF. is_sequence Returns TRUE if the Morf instance represents an instance of type SEQUENCE or SEQUENCE OF. is_set Returns TRUE if the Morf instance represents an instance of type SET or SET OF. num_elements Returns the number of elements in a set or sequence. Valid only on list type Morf instances. split_array Returns the elements in a value that is an instance of a list type as an array of Morf instances. Valid only on list type Morf instances. split_queue Returns the elements in a value that is an instance of a list type as a queue of MorfElem types. Valid only on list type Morf instances.
TABLE 9-3 lists functions provided by the Asn1Type class that are also useful for parsing Morf instances. Call the get_type function of the Morf class to extract an Asn1Type instance from a Morf instance.
TABLE 9-3 Functions of the Asn1Type Class For Parsing Morf Instances get_bit_string_identifiers< /td> Valid for BIT STRING types. Returns an array that contains the name and position of possible values defined for the string. get_enum_identifiers Valid for ENUMERATED types. Returns an array that contains the string identifier and numeric value for all values defined in the enumeration. get_range Valid for types derived from INTEGER or REAL. Returns the lowest and highest possible value for this type. If a range cannot be determined for this type, get_range returns NOT_OK. get_size_constraint Valid for types derived from BIT STRING, OCTET STRING, SEQUENCE OF, and SET OF. Returns the smallest and largest possible size for this type. If there are no size constraints for this type, get_size_constraint returns NOT_OK.
9.3.3 Parsing CHOICE Values
Use is_choice to determine if a Morf instance represents a CHOICE type.
If you only want to know what type is chosen, use get_memname. For CHOICE types, get_memname returns the attribute name of the chosen type.
If you want to parse the instance further, call extract to extract a Morf instance associated with the chosen syntax. In the call to extract, specify a navigation string by calling get_memname to identify the name of the chosen instance.
CODE EXAMPLE 9-6 shows how to get information about a CHOICE value by using get_memname and extract.
CODE EXAMPLE 9-6 Extracting Data From a CHOICE Value
... #include <pmi/hi.hh> ... // Assume we have a CHOICE Morf in morf if (morf.is_choice()) { cout << "CHOICE attribute selected is : "; cout << morf.get_memname(); // Now replace morf with the chosen Syntax for further // parsing. Morf tmp = morf; morf = tmp.extract(tmp.get_memname()); if (!morf) { // handle the error } } // Continue parsing with morf ...9.3.4 Parsing List Values
Parsing a list value involves:
- Determining if the Morf instance represents a list
- Determining how many members are in the list
- Splitting the list into an array or queue of new Morf instances
- Getting the type of members of the list
The sample code in Section 9.3.7 Example of Parsing a Morf Instance shows how to parse list values.
9.3.4.1 Determining That a Morf Instance Represents a List
The following functions enable you to determine if a Morf instance represents a list and, if so, whether the list is a sequence or a set:
- is_list returns TRUE for any list.
- is_sequence returns TRUE for any instance of type SEQUENCE or SEQUENCE OF.
- is_set returns TRUE for any instance of type SET or SET OF.
9.3.4.2 Getting the Number of Members in a List
If a Morf instance represents a list, call num_elements to determine how many members are in the list.
9.3.4.3 Splitting a List Into an Array or Queue of New Morf Instances
If you need to parse the members of a list, you first need to extract the members into new Morf instances. The following functions return each element in a list as a new Morf instance:
- split_array returns an array of Morf instances.
- split_queue returns a queue of Morf instances.
You then need to parse each element in the array or queue.
CODE EXAMPLE 9-7 shows how to use a queue to determine whether a list contains a particular value.
CODE EXAMPLE 9-7 Using a Queue to Parse a List
... #include <pmi/hi.hh> ... // SatelliteSeq ::= SEQUENCE { // name GraphicString, // value Integer32, // checkSum CheckSum // } SatelliteData ::= SET OF SatelliteSeq // Assume Morf morf is of type Satellite Data // Create the value we are looking for // Assume em_mis is an existing Platform instance // previously connected to the MIS Syntax syn("Integer32", em_mis); Morf testMf(syn, "7777"); // Iterate over the SatelliteData looking for a SatelliteSeq // that matches our test value if (morf.is_set() && (morf.num_elements() > 0) ) { Queue(MorfElem) setQ = morf.split_queue(); MorfElem mfe; for (mfe = setQ.fiq(); mfe; mfe = setQ.niq(mfe)) { // Each queue item is a SatelliteSeq; check its 'value' Morf testVal = mfe.mf->extract("value"); if (!testVal) continue; if ( testVal == testMf ) { // Found, return this SatelliteSeq return Morf(mfe.mf); } } } return Morf(); // Not found or empty set ...9.3.4.4 Getting the Types of Members of a List
You may need only the types of the members of a list. For example, if the type of a member is CHOICE or ANY, you can only know at runtime the actual type of the member. To get the actual type of a member that is an instance of the CHOICE or ANY type, call the get_member_names function.
The get_member_names function returns an array the ASN.1 of types in of the members of list.
To examine the array, call functions of the DataUnit class to get information about the data types.
9.3.5 Getting Objects Associated With a Morf Instance
An instance of each of the following classes is associated with a Morf instance:
- Platform
- Syntax
- Asn1Type
To retrieve an instance, call one of the functions of the Morf class listed in TABLE 9-4.
TABLE 9-4 Functions for Retrieving Information About the Type Instance Platform get_platform A reference to the associated Platform instance Syntax get_syntax The instance of the Syntax class associated with the Morf instance's syntax Asn1Type get_type The Asn1Type instance that represents the Morf instance's underlying ASN.1 type
9.3.6 Getting Metainformation About the ASN.1 Type of a Morf Instance
To test if a value is assigned to a Morf instance, call the has_value function on the Morf instance. Use the has_value function only to test if a value is assigned to a Morf instance. Do not attempt to use pointer that the has_value function returns.
The Asn1Type class provides functions for getting:
- Identifiers for a BIT STRING value
- Identifiers for an ENUMERATED value
- The range of a value of a type or subtype of REAL or INTEGER
- The size constraints of a value of a type or subtype of BIT STRING, OCTET STRING, SEQUENCE OF, or SET OF
Use the get_type function of the Morf class to get an Asn1Type instance that corresponds to the Morf instance. Use the returned Asn1Type instance to call functions for getting metainformation about values. For example:
Result r = morf.get_type().get_enum_identifiers(idArray);9.3.6.1 Getting Identifiers for a BIT STRING Value
To get identifiers for a BIT STRING value, call the get_bit_string_identifiers function of the Asn1Type class.
The syntax of get_bit_string_identifiers is as follows:
Result get_bit_string_identifiers(Array(Asn1NamedNumber) &idents)If this function returns OK, the idents array holds the identifiers and associated positions for the members in an ASN.1 BIT STRING value.
CODE EXAMPLE 9-8 shows how to use get_bit_string_identifiers.
9.3.6.2 Getting Identifiers for an ENUMERATED Value
To get identifiers for an ENUMERATED value, call the get_enum_identifiers function of the Asn1Type class.
The syntax of get_enum_identifiers is as follows:
Result get_enum_identifiers(Array(Asn1NamedNumber) &idents)If this function returns OK, the idents array holds the identifiers and associated values for the values defined in an ASN.1 ENUMERATED value.
CODE EXAMPLE 9-8 shows how to use get_bit_string_identifiers and get_enum_identifiers to print the possible values for BIT STRING and ENUMERATED types:
CODE EXAMPLE 9-8 Obtaining BIT STRING and ENUMERATED Identifiers
... #define BIT_STRING 1 #define ENUM 2 #include <pmi/hi.hh> ... void show_idents(Array(Asn1NamedNumber) &idents, int type) { Asn1TypeInt int_type(AK_INTEGER); DU ident; GenInt numbvalue; U32 i; Asn1Value asn1number; Asn1ParsedValue number; cout << "Number of identifiers: " << idents.size << endl; for (i=0; i<idents.size; i++) { number = idents[i].num; ident = idents[i].name; if (number) { asn1number = number.get_real_val(int_type); asn1number.decode_int(numbvalue); } cout << "Identifier # => " << i << " Name is => "; cout << ident.chp() << ";"; cout << " Identifier "; cout << ((type == ENUM ) ? "value" : "position") ; cout << " is => "; if (number) { cout << I32(numbvalue); } else { cout << "NULL" ; } cout << endl ; } // end for() } // end show_idents() ... // bitStrMf is a Morf of type BIT STRING // enumMf is a Morf of type ENUMERATED ... Result r; Array(Asn1NamedNumber) newidents; // BIT STRING r = bitStrMf.get_type().get_bit_string_identifiers(newidents); if (r == NOT_OK) { cout << "Failed to get BIT STRING identifiers!" << endl; } else { show_idents(newidents, BIT_STRING); } // ENUMERATED r = enumMf.get_type().get_enum_identifiers(newidents); if (r == NOT_OK) { cout << "Failed to get ENUMERATED identifiers!" << endl; } else { show_idents(newidents, ENUM); } ...9.3.6.3 Getting the Range of a Value of a Type or Subtype of REAL or INTEGER
To get the range of a value of a type or subtype of REAL or INTEGER, call the get_range function of the Asn1Type class.
The syntax of get_range is as follows:
Result get_range(Asn1ParsedValue &lower,Boolean &lower_open,Asn1ParsedValue &upper,Boolean &upper_open)The get_range function returns NOT_OK if it is called on an instance that does not represent an ASN.1 type or subtype of INTEGER or REAL.
If the function returns OK, lower is set to the lowest possible value for the type and upper is set to the highest possible value.
ITU-T X.208/ISO-8824 Specification of Abstract Syntax Notation One (ASN.1) uses MIN and MAX to define the lower and upper ranges of subtypes of INTEGER and REAL. The PMI library encodes MIN and MAX as NULL Asn1ParsedValue values. Therefore, you must make sure lower and upper are not NULL before attempting to decode them.
If the function returns OK, the lower_open and upper_open boolean variables indicate whether the lower and upper range limits are open (TRUE). If a range limit is not open, the corresponding variable (lower_open or upper_open) is set to FALSE.
The code in CODE EXAMPLE 9-9 shows how to use get_range to parse and decode the range limits for REAL and INTEGER types.
CODE EXAMPLE 9-9 Obtaining the Range Limits for a Value
... #include <pmi/hi.hh> ... void show_range(Asn1Type rtype) { Asn1TypeInt int_type(AK_INTEGER); Asn1Type real_type(AK_REAL); Result r; int is_real = 0; Asn1Value asn1lower, asn1upper; Asn1ParsedValue lower, upper; GenInt low, up; Boolean lower_open, upper_open; double dbl; if (rtype.base_kind() == AK_REAL) { is_real = 1; } else if (rtype.base_kind() != AK_INTEGER) {// Not valid type for get_range()! cout << "Cannot determine range for type." << endl; return; } r = rtype.get_range(lower, lower_open, upper, upper_open); if (r == NOT_OK) { cout << "get_range() failed!" << endl; return; } cout << '\t'; if (lower) { if (is_real) { //REAL asn1lower = lower.get_real_val(real_type); asn1lower.decode_real(dbl); cout << "Lower range is " << dbl << "."; } else { // INTEGER asn1lower = lower.get_real_val(int_type); asn1lower.decode_int(low); cout << "Lower range is " << I32(low) << "."; } if (lower_open == TRUE) { cout << "Lower range is open." << endl; } else { cout << "Lower range is closed." << endl; } } else { // lower is NULL, range is MIN cout << "Lower range is MIN." << endl; } cout << '\t'; if (upper) { if (is_real) { //REAL asn1upper = upper.get_real_val(real_type); asn1upper.decode_real(dbl); cout << "Upper range is " << dbl << "."; } else { // INTEGER asn1upper = upper.get_real_val(int_type); asn1upper.decode_int(up); cout << "Lower range is " << I32(up) << "."; } if (upper_open == TRUE) { cout << "Upper range is open." << endl; } else { cout << "Upper range is closed." << endl; } } else { // upper is NULL, range is MAX cout << "Upper range is MAX." << endl; } } // end show_range() ... // Morf morf represents a type we think is // derived from INTEGER or REAL if (morf.get_type()) { if ((morf.get_type().base_kind() == AK_INTEGER) || (morf.get_type().base_kind() == AK_REAL)) show_range(morf.get_type()); } else { cout << "morf not initialized!" << endl; } ...9.3.6.4 Getting the Size Constraints of a Value
To get the size constraints of a value of a type or subtype of BIT STRING, OCTET STRING, SEQUENCE OF, or SET OF, call the get_size_constraint function of the Asn1Type class.
The syntax of get_size_constraint is as follows:
Result get_size_constraint(Asn1ParsedValue &lower,Boolean &lower_open,Asn1ParsedValue &upper,Boolean &upper_open)If the function returns OK, lower is set to the smallest possible size for the type and upper is set to the largest possible size.
ITU-T X.208/ISO-8824 Specification of Abstract Syntax Notation One (ASN.1) uses MIN and MAX to define the lower and upper size limits of subtypes of BIT STRING, OCTET STRING, SEQUENCE OF, and SET OF. The PMI library encodes MIN and MAX as NULL Asn1ParsedValue values. Therefore, you must make sure lower and upper are not NULL before attempting to decode them.
If the function returns OK, the lower_open and upper_open boolean variables indicate whether the lower and upper size limits are open (TRUE). If a size limit is not open, the corresponding variable (lower_open or upper_open) will be set to FALSE.
The get_size_constraint function returns NOT_OK if it is called on an instance that does not represent an ASN.1 type or subtype of BIT STRING, OCTET STRING, SEQUENCE OF, or SET OF.
The code in CODE EXAMPLE 9-10 shows how to use get_size_constraint to parse and decode the size limits for BIT STRING, OCTET STRING, SEQUENCE OF, and SET OF types.
CODE EXAMPLE 9-10 Obtaining the Size Constraints of a Value
... #include <pmi/hi.hh> ... void show_size_constraint(Asn1Type stype) { char buf[4096], *bufp; U32 i, buflen = 4096; Asn1TypeInt int_type(AK_INTEGER); Result r; Asn1Value asn1lower, asn1upper; Asn1ParsedValue lower, upper; GenInt low, up; Boolean lower_open, upper_open; r = stype.get_size_constraint(lower, lower_open, upper, upper_open); if (r == NOT_OK) { cout << "Could not get size constraints." << endl; return; } if (lower) { asn1lower = lower.get_real_val(int_type); asn1lower.decode_int(low); buflen = 4096; bufp = buf; int_type.format_value(asn1lower, bufp, buflen, 0, TAG_EXPLICIT, DataUnit(), 0); cout << "Lower limit is " << buf << "." << endl; cout << "Lower limit is "; cout << ((lower_open == TRUE) ? "open" : "closed") ; cout << "." << endl; } else { // lower is NULL, constraint is MIN cout << "Lower limit is MIN." << endl; } if (upper) { asn1upper = upper.get_real_val(int_type); asn1upper.decode_int(up); buflen = 4096; bufp = buf; int_type.format_value(asn1upper, bufp, buflen, 0, TAG_EXPLICIT, DataUnit(), 0); cout << "Upper limit is " << buf << "." << endl; cout << "Upper limit is "; cout << ((upper_open == TRUE) ? "open" : "closed") ; cout << "." << endl; } else { // upper is NULL, constraint is MAX cout << "Upper limit is MAX." << endl; } } // end show_size_constraint() ...// Morf morf has been derived from the platform somehow... if (morf.get_type()) { show_size_constraint(morf.get_type()); } else { cout << "morf not initialized!" << endl; } ...9.3.7 Example of Parsing a Morf Instance
The function morf_split in CODE EXAMPLE 9-11 shows a typical recursive algorithm for parsing any type of Morf instance. The example prints out type names and values for scalars, but you can use the same algorithm to do other things with the data.
CODE EXAMPLE 9-11 Sample Function for Parsing a Morf Instance
... #include <pmi/hi.hh> ... void morf_split( Morf& m) { // Check if the morf contains CHOICE, // // If the morf contains CHOICE, // extract the morf, then call the function recursively. // If the morf does not contains CHOICE, // Check if the morf contains a compound data value. // // If the morf contains a compound data value, // split the morf, then call the function recursively. // // If the morf contains scalar data value, // print the scalar data value. if (m.is_choice()){ morf_split(m.extract(DU())); } else if (m.is_list()) { Array(Morf) mm = m.split_array(); for (int i=0; i<mm.size; i++) { cout << "morf["; cout << i ; cout << "] = "; cout << mm[i].get_str().chp(); cout << endl; morf_split(mm[i]); } } else { cout << endl; cout << "---scalar value--->"; cout << m.get_str().chp(); cout << endl << endl << endl; } }9.4 Decoding Complex ASN.1 Values
After you understand the structure of any Morf instance, you may want to extract values assigned to attributes in the instance. The Morf class provides functions for extracting or decoding data in a Morf instance. You can decode any Morf instance that has been initialized with data by:
- Getting a string representation of the Morf instance
- Extracting a value in the Morf instance as a new Morf instance
- Getting the value assigned to the Morf instance as an Asn1Value instance
- Getting scalar values assigned to a Morf instance
9.4.1 Getting a String Representation of a Morf Instance
To retrieve a string representation of a Morf instance's values, call the get function on the Morf instance. The get function works on any Morf instance. The get function returns a string that represents the Morf instance's structure and the values assigned to attributes.
9.4.1.1 Getting the Default String Representation of a Morf Instance
To get the default string representation of a Morf instance, call the get function on the Morf instance specifying 0 for the format bits parameter. The default representation of each value depends on the type of the value as shown inTABLE 9-5.
TABLE 9-5 Default String Representation of Values by Type in a Morf Instance SET SEQUENCE The members of the SET or SEQUENCE value are enclosed in braces and separated by commas. CHOICE ANY The actual type represented by a CHOICE or ANY value is indicated by a label of the form "type :" in the string before the values. By default, the string contains identifiers of named numbers, such as ENUMERATED values. BIT STRING When they appear as numbers, BIT STRING values are enclosed in single quotes followed by B. For example, '01101101'B. OCTET STRING When they appear as hexadecimal values, OCTET STRING values are enclosed in single quotes followed by H. For example, '323A1F0A'H. BOOLEAN Boolean values are translated into the strings TRUE and FALSE.
CODE EXAMPLE 9-12 shows the ASN.1 type definition of the GeoLocation type.
CODE EXAMPLE 9-12 ASN.1 Type Definition of the GeoLocation Type
GeoLocation ::= CHOICE { null NULL, value SEQUENCE { latitude REAL, longitude REAL } }CODE EXAMPLE 9-13 shows the default string representation of a GeoLocation value returned by a call to get.
CODE EXAMPLE 9-13 Default String Representation of a GeoLocation Value
"value : { 122.35, 38.37 }"9.4.1.2 Controlling the String Representation of a Morf Instance
You often extract a string representation of a Morf instance or one of its members by using the get function. Strings can represent any arbitrary data in a way that makes it easy to parse or to reuse the data to build new Morf instances. If you require a string representation that uses a different format than the default, specify the format bits parameter in calls to functions that use strings.
The format bits argument is a set of bit flags that specify how to format data in the output string. The default value is 0, and that is usually what you use.
Because the Morf class handles complex data as familiar string types, you sometimes want control over how to format the string. The format bits argument is used in get and get_str. The set and set_str functions also accept format bits, but only the USE_EXPLICIT_CHOICE flag is meaningful when a value is set.
To use the format bits, combine all of the flags you want to use using a bitwise OR:
cout << "mrf = " << mrf.get(USE_NUMERIC_NAMES|USE_C_ESCAPES);TABLE 9-6 lists the identifiers for specifying format bits.
TABLE 9-6 Identifiers for Format Bits Arguments USE_NUMERIC_NAMES Returns only the numbers of an object identifier. Do not attempt to translate OID components into names. OMIT_NEWLINES Removes newline characters from a string before it is returned. USE_C_ESCAPES Returns OCTET STRING values with special characters escaped by using C shell escape characters. Nonprinting characters are represented by \0, \a, \b, \f, \n, \t, \r, \v, or \nnn where nnn is the hexadecimal value of the character. USE_EXPLICIT_TYPES Prefixes values of type ANY or ANY DEFINED BY with a label that indicates the actual type of the value returned. OMIT_SPACES Strips spaces from a string before it is returned. USE_HEX Shows the hexadecimal value of each octet in OCTET STRING data. USE_EXPLICIT_CHOICE Prefixes values of type CHOICE with a label that indicates the actual type of the value returned.
9.4.2 Extracting a Value in a Morf Instance as a New Morf Instance
To extract a value in a Morf instance as a new Morf Instance, call the extract function on the existing Morf instance. The extract function retrieves a member of a Morf instance that represents a list.
Use the extract function when you want to work with a subcomponent of a complex Morf instance, especially when you want to extract one element from a SET or SEQUENCE. Unlike split_array and split_queue, extract enables you to name and extract a single item from a list.
The extract function is also useful for working with CHOICE types. The CHOICE syntax tells you nothing about the structure of the data. To get information on the structure of the data, use extract to extract a Morf instance that represents the syntax of the actual values assigned to the Morf instance.
In the call to extract, specify a navigation string. The navigation string indicates which member of a list Morf instance to extract. The navigation string is composed of one or more identifiers separated by periods (.). Each identifier can be one of the following:
- The name of an attribute in a SEQUENCE
- The name of an attribute option in a CHOICE
- A number that represents the position of an element in a SEQUENCE or SET
CODE EXAMPLE 9-14 shows how to use navigation strings to extract Morf instances from a list.
CODE EXAMPLE 9-14 Using Navigation Strings With the extract Function
... #include <pmi/hi.hh> ... // SatelliteSeq ::= SEQUENCE { // name GraphicString, // value Integer32, // checkSum CheckSum // } // // SatelliteData ::= SET OF SatelliteSeq // // If Syntax syn is associated with SatelliteData and // Morf satSetMf is associated with syn... ... // satSetMf is a SET OF; try to get the third element in SET Morf seqMf = satSetMf.extract("3"); if (!seqMf) return(NOT_OK); // Three ways to get the name from the third element in // the satSetMf set Morf nameMf1 = seqMf.extract("name"); Morf nameMf2 = satSetMf.extract("3.name"); Morf nameMf3 = satSetMf.extract("3.1"); ...9.4.3 Getting the Value Assigned to a Morf Instance
To obtain the Asn1Value instance that represents the value assigned to a Morf instance, call the get_value function on the Morf instance.
For list type Morf instances, you can only get either the string representation or the Asn1Value representation of a Morf instance's value. For some scalar Morf instances, you can retrieve the value directly into an integer or real variable as explained in Section 9.4.4 Getting Scalar Values Assigned to a Morf Instance.
You may need to get the value of a Morf instance for another function or application that expects an Asn1Value instance.
The get_value function is also useful for obtaining the real value associated with scalar values such as ENUMERATED and OBJECT IDENTIFIER values. From the resulting Asn1Value instance, you can decode the value (not the identifier) and assign it to an instance of a class such as GenInt or Oid.
9.4.4 Getting Scalar Values Assigned to a Morf Instance
The Morf and ASN1Value classes provide functions for assigning a scalar Morf instance's value directly to a variable of another type as follows:
- The Morf class provides functions for retrieving values as DataUnit, long, GenInt, or double.
- The Asn1Value class provides functions for converting the Asn1Value instance associated with a Morf instance into another type.
To retrieve the string representation of any scalar value, call the get_str function of the Morf class. Calling the get_str function on a list type Morf instance is equivalent to calling the get function on that instance.
The other functions of the Morf class for scalar values return values that can be assigned to variables of numeric types. These functions are very useful for extracting numeric data because you do not have to convert from a string or Asn1Value instance to a number.
TABLE 9-7 lists the functions for obtaining numeric scalar values from a Morf instance.
TABLE 9-7 Functions for Extracting Numeric Scalars Into Numeric Types get_dbl Returns the numeric value assigned to the Morf instance as a double. If the Morf instance is not a scalar nor based on a numeric type, get_dbl returns 0.0. get_gint Returns the integer part of the numeric value assigned to a Morf instance as an instance of the GenInt class. The GenInt class eases the handling of arbitrary integers. If the Morf instance is not a scalar nor based on a numeric type, get_gint returns 0. get_long Returns the integer part of the numeric value assigned to a Morf instance as a long. If the Morf instance is not a scalar nor based on a numeric type, get_long returns 0.
These functions are valid only for values the base type of which is BOOLEAN, ENUMERATED, INTEGER, OCTET STRING, or REAL. The following rules govern the conversion of these values to numeric values:
- Nonnumeric values or non-scalar values return 0 (or 0.0).
- REAL values retrieved by using the integer functions return only the integer part of the Morf instance's value. For example, get_gint and get_long return 6 for 6.022e23.
- BOOLEAN values return 0 (or 0.0) for FALSE, and nonzero for TRUE.
- ENUMERATED values return the integer value associated with the named value.
- OCTET STRING values are returned as a single number. For example, get_long converts a string of four octets to an integer with four significant bytes, that is, an integer in the range 0 to 231 (0..2^31).
In addition to numeric values or strings, you may want to extract a Morf instance's data directly into other types. To get other types of data, you can use get_type to get an Asn1Value instance of the value, then call one of the decoding functions on the Asn1Value instance. It is often easier to work with data in a closely matching type, and sometimes it may be required. For example, if a function takes an Oid instance as a parameter, you may want to extract an Oid instance directly from a Morf instance of type OBJECT IDENTIFIER.
Using the decoding functions of the Asn1Value class makes it easy to extract data into the following types:
- Boolean
- Octet
- OID
TABLE 9-8 lists the functions of the Asn1Value class for decoding data and the conversions they perform.
TABLE 9-8 Functions of the Asn1Value Class For Decoding Data decode_bits BIT STRING decode_bits returns: A string of octets that represents the BIT STRING value The number of octets in the string If necessary, the beginning of the string is padded with zeroes to make an octet. decode_boolean BOOLEAN decode_boolean returns a boolean value. decode_octets OCTET STRING decode_octets returns: The octets of the OCTET STRING value The number of octets returned decode_oid OBJECT IDENTIFIER decode_oid returns an instance of the Oid class that represents the OBJECT IDENTIFIER value.
To use these functions on data stored in a Morf instance, you must first call get_value to get the Asn1Value instance of the Morf instance.
CODE EXAMPLE 9-15 shows how to use decode_oid to retrieve an instance of the OBJECT IDENTIFIER type from a Morf instance.
CODE EXAMPLE 9-15 Decoding a Morf Instance Directly Into an Oid Instance
... #include <pmi/hi.hh> ... // TopoNodeAttrList ::= SEQUENCE { // view TopoNodeId, // attrs SET OF OBJECT IDENTIFIER // } // // Assume morf is a Morf associated with the Syntax of // TopoNodeAttrList... extract each OBJECT IDENTIFIER // in attrs as an instance of the Oid class. ... Morf attrMf = morf.extract("attrs"); // Get the attrs SET if (attrMf.num_elements() > 0) { Array(Oid) oids(attrMf.num_elements()); Array(Morf) oidsMf = attrMf.split_array(); Result r; for (int i=0; i<oidsMf.size;i++) { // Need Asn1Value to get Oid from Morf r = oidsMf.get_value().decode_oid(oids[i]) if (r == NOT_OK) oids[i] = Oid(DU("")); // NULL } ... // Do something useful with all those OIDs ... } ...9.5 Using the MorfBuilder Class
The MorfBuilder class makes it easier to work with very complex Morf instances, especially if the ASN.1 syntax includes combinations of CHOICE, SET, or SEQUENCE.
The MorfBuilder class does not ease the decoding of Morf data, but it is possible to extract any part of a MorfBuilder instance as a new Morf instance. You can then use techniques described in the following sections to parse and decode the Morf instance:
To build complex Morf instances by using only the Morf class, you must either build very complex string representations of the data or carefully assemble subcomponents into larger arrays and build a new Morf instance from the array.
Use the MorfBuilder class for:
- Constructing a MorfBuilder instance
- Adding data to a MorfBuilder instance
- Selecting a syntax for CHOICE values
- Setting a navigation type for SEQUENCE values
- Validating the data in a MorfBuilder instance
- Assembling the MorfBuilder data into a single Morf instance
The MorfBuilder class enhances the features of the Morf class. Therefore you need to understand how to use the Morf class to be able to work with MorfBuilder instances. You will need to navigate the structure of the MorfBuilder instance's underlying syntax by using navigation strings. Refer to Section 9.4.1 Getting a String Representation of a Morf Instance for more information about how syntactic structure is represented in a string.
9.5.1 Constructing a MorfBuilder Instance
To construct a MorfBuilder instance that corresponds to any Syntax instance, use the one of the constructors of the MorfBuilder class listed in TABLE 9-9.
TABLE 9-9 Constructors of the MorfBuilder Class MorfBuilder(Morf& morf) Constructs a MorfBuilder instance by using the syntax and values stored in an existing Morf instance MorfBuilder(Syntax& syntax) Creates a MorfBuilder instance based on the syntax of a Syntax instance with no assigned value MorfBuilder(CDU attr_name, Platform& plat = Platform::def_platform) Looks up the syntax of attr_name on the named Platform instance or the default Platform instance and uses it to create a new MorfBuilder instance MorfBuilder(const MorfBuilder& old_mbd) Creates a new MorfBuilder instance that has the same syntax and values as an existing MorfBuilder instance
9.5.2 Adding Data to a MorfBuilder Instance
Adding data to a MorfBuilder instance assigns values to members contained in the MorfBuilder instance. You can assign a value to any member of a MorfBuilder instance in any order. To assign a value, call one of the following functions of the MorfBuilder class:
- set, specifying a string representation of the value you want to assign
- set_raw, specifying a Morf instance corresponding to the syntax and the values you want to assign to the member
These functions replace the value of the MorfBuilder instance (or the selected member) and any contained instances with new values. Any updates you have made to the selected member or the members it contains will be lost unless they have been cached.
To update the currently cached image of a MorfBuilder instance or any of its members, call validate or get_raw before calling set or set_raw. These functions update the cached copy of the MorfBuilder instance. After you call set or set_raw, call validate or get_raw again to update the cached copy with the latest changes.
Section 9.5.5 Validating the Data in a MorfBuilder Instance and Section 9.5.6 Assembling MorfBuilder Data Into a Single Morf Instance contain more information about the internally cached MorfBuilder instance.
The set function of the MorfBuilder class is similar to the set function of the Morf class, but it also takes an optional navigation string. Use the navigation string to specify the attribute or member of the MorfBuilder instance to which to assign the value. Refer to Section 9.2.1 Creating a Morf Instance From String Data for details on forming the value string.
The set_raw function uses a Morf instance instead of a string to assign a value to a MorfBuilder instance or one of its members.
CODE EXAMPLE 9-16 shows how to update members of a MorfBuilder instance.
CODE EXAMPLE 9-16 Using set to Update a MorfBuilder Instance
... #include <pmi/hi.hh> // High-level PMI #include <extpmi/exthi.hh> // Extended PMI (MorfBuilder, for // example) ... // SatelliteSeq ::= SEQUENCE { // name GraphicString, // value Integer32, // checkSum CheckSum // } // // If Syntax syn is associated with SatelliteSeq... ... Result r; DU name, value, platform; MorfBuilder mfb(syn); ... // ...code to retrieve name, value, and checkSum // from some data source... ... mfb.set("name", name); // validate() updates the cached mfb with the new name so // subsequent set() calls do not clobber this change if (mfb.validate() == NOT_OK) { cout << mfb.get_error_string() << endl; } mfb.set("value", value); if (mfb.validate() == NOT_OK) { cout << mfb.get_error_string() << endl; } mfb.set("checkSum", checkSum); if (mfb.validate() == NOT_OK) { cout << mfb.get_error_string() << endl; } ...9.5.3 Selecting a Syntax for CHOICE Values
You can select the ASN.1 syntax to use for any CHOICE value contained in the MorfBuilder syntax in one of the following ways:
- select_choice uses a string to name the value selected.
- set_syntax uses a Syntax instance that corresponds to the value selected.
The function you use depends on what data is available to your program when the CHOICE syntax needs to be selected.
- If you know the attributes listed in the CHOICE syntax ahead of time, use select_choice.
- If you are working with data derived from the platform, you may not know what choices area available to a given instance at run time. At run time, for example, you may be parsing another Morf instance to determine which syntax to select. In that case, use set_syntax with an instance derived from the Morf instance's get_syntax function.
You cannot assign values to a member of type CHOICE. First, you must use one of these functions to choose the actual syntax. Both functions for selecting a syntax for a CHOICE accept navigation strings, so both can be used to set a choice for any member of a constructed type.
Note Both select_choice and set_syntax change the Syntax instance associated with a member of a MorfBuilder instance. After calling one of these functions, the syntax will no longer represent a CHOICE value. Calling one of these functions after a syntax has already been chosen by a previous call will return NOT_OK.
CODE EXAMPLE 9-17 shows how to use both functions for selecting a CHOICE value.
CODE EXAMPLE 9-17 Selecting a Syntax For a CHOICE Value
... #include <pmi/hi.hh> #include <extpmi/exthi.hh> ... // Syntax hostSyn is associated with this ASN.1: // // myHostEntry ::= SEQUENCE { // myHostname GraphicString, // myIpAddr CHOICE { // ipString GraphicString, -- "111.222.111.222" // ipInt INTEGER, -- 32-bit int // ipOctet OCTET STRING(SIZE(4)) // } // } // // Syntax ipOctetSyn is associated with the syntax of ipOctet ... Result r; MorfBuilder host1Mfb(hostSyn); MorfBuilder host2Mfb(hostSyn); r = host1Mfb.set("myHostname", DU("mailhost")); // handle if r != OK r = host2Mfb.set("myHostname", DU("newshost")); r = host1Mfb.validate(); r = host2Mfb.validate(); // SELECT_CHOICE() // Set host1Mfb's myIpAddr to use ipString, then assign value r = host1Mfb.select_choice("myIpAddr", "ipString"); // myIpAddr is now a GraphicString type r = host1Mfb.set("myIpAddr", DU("111.222.111.12")); r = host1Mfb.validate(); ... // SET_SYNTAX // Set host2Mfb's myIpAddr to use ipOctet; r = host2Mfb.set_syntax("myIpAddr", ipOctetSyn); Morf ipOct(ipOctetSyn); if (!ipOct) { // handle error } ipOct = ipOct.set(DU("6FDE6F0D")); // 111.222.11.13 r= host2Mfb.set_raw("myIpAddr", ipOct); ...9.5.4 Setting a Navigation Type for SEQUENCE Values
You can control whether navigation strings address members of a sequence by names or by position number. By default, you must use the name of a member of a sequence in a navigation string.
Instances of the MorfBuilder class have a property called access_type that indicates how members of a SEQUENCE must be addressed. The access_type property can be set for any component of a MorfBuilder syntax that represents a SEQUENCE type.
The access_type property can be set to one of the following:
- by_name (default) means that you must use the attribute name to refer to members of a SEQUENCE
- by_index means that you must use a position number to refer to members of a SEQUENCE
To get the value of the access_type property for a SEQUENCE component of a MorfBuilder instance, call the get_prop function on the MorfBuilder instance.
In the call to get_prop, specify:
- A key. The only valid key is access_type. If the selected component is a SEQUENCE value, get_prop returns either by_name or by_value. Otherwise, get_prop returns a NULL DataUnit instance.
- Optionally, a navigation string. Use a navigation string to select a component of a constructed value.
To set the access_type for a SEQUENCE component, use set_prop. Use a navigation string to select a component of a constructed value.
CODE EXAMPLE 9-18 shows how to use get_prop and set_prop.
CODE EXAMPLE 9-18 Using get_prop and set_prop
... #include <pmi/hi.hh> #include <extpmi/exthi.hh> ... // MorfBuilder mbd is associated with the simple syntax: // // SEQUENCE { // int INTEGER, // char OCTET STRING // } ... Morf morf; Result r; ... // using get_prop() if (mbd.get_prop("access_type") == DU("by_name")) { morf = mbd.get_raw("char"); } else if (mbd.get_prop("access_type") == DU("by_index")) { morf = mbd.get_raw("2"); } else { cout << "No access_type available!" << endl; } ... // using set_prop() r = mbd.set_prop("access_type", "by_name"); if (r == OK) morf = mbd.get_raw("char"); r = mbd.set_prop("access_type", "by_index"); if (r == OK) morf = mbd.get_raw("2"); ...9.5.5 Validating the Data in a MorfBuilder Instance
At any point during the construction of a MorfBuilder instance, you can validate the values assigned to any component of the underlying syntax. To validate the values assigned to a component, call the validate function of the MorfBuilder class.
The validate function verifies that the internal values of the MorfBuilder instance or component are valid. If all of the assigned values are valid, the validate function returns OK.
The validate function accepts a boolean parameter. If you set this parameter to TRUE, validate only ensures that the values are valid for the type defined in the ASN.1 syntax without making sure that they are tagged with the proper attribute type. For example, an integer value might be valid for an ENUMERATED type even though the value is not explicitly tagged as ENUMERATED.
The validate function updates the internally cached image of the MorfBuilder instance with any new changes made since the last update. Call validate as you assemble a MorfBuilder instance to update the cached image of the instance so that later calls to set and set_raw do not overwrite previous changes.
9.5.6 Assembling MorfBuilder Data Into a Single Morf Instance
After you have assigned all the values to a MorfBuilder instance, extract the data as an instance of the Morf class so that you can do something useful with it. To extract the entire MorfBuilder instance or any component as a new Morf instance, call the get_raw function.
Use get_raw and a navigation string to extract any part of a constructed value.
If get_raw fails to construct a Morf instance from the underlying MorfBuilder instance, it returns a null Morf instance.
The get_raw function accepts a boolean parameter.
- If this parameter is set to TRUE, get_raw attempts to update the cached internal Syntax and Asn1Value relationships and build a new Morf instance. If the Syntax instance associated with a MorfBuilder instance is a constructed type, changes you make to any member values are not updated in the internally cached copy until you call get_raw(TRUE) or validate.
- If this parameter is set to FALSE, get_raw returns the internal cached representation of the Syntax and Asn1Value assignments. This copy represents whatever data was assembled from the previous call to validate or get_raw(TRUE). Any changes made since the last update to the internal cache are not reflected in the Morf instance that get_raw(FALSE) returns.
Sun Microsystems, Inc. Copyright information. All rights reserved. |
Doc Set | Contents | Previous | Next | Index |