Solstice Enterprise Manager 4.1 Developing C++ Applications Doc Set ContentsPreviousNextIndex


Chapter 9

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.

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:

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:

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.

CODE EXAMPLE 9-2   Constructing a Morf From a String  
...
#include <pmi/hi.hh>
#include <rw/cstring.h>
...
//  CheckSum ::= SET OF OBJECT IDENTIFIER
//    DestructSet ::= SET OF SEQUENCE {
//            name      GraphicString,
//            value     Integer3
2,
//            checkSum  CheckSum
//    }                                         
// Assume em_mis is an existing Platform instance
//   previously connected to the MIS            
Syntax syn(DU("destructSet"), em_mis);
RWCString destrSet, destrSequence1, destrSequence2;
//Build the string representation of the set
destrSequence1 = 
    "{ name \"Code A\", value 6753, checkSum { 1 34 12 }}";
destrSequence2 = 
    "{ name \"Code B\", value 9345, checkSum { 3 12 5 }}";
destrSet = "{" + destrSequence1 + "," 
               + destrSequence2 + "}";
//Construct a Morf using the string and Syntax syn
Morf m1(syn, destrSet.data());
//Construct an empty Morf, then add the data
Morf m2(syn);
m2 = m2.set(destrSet);
if (m2.get_error_type != PMI_SUCCESS) {
         //handle the error
}
...

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:

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 
Function Description
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:

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:

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:

Parsing a Morf instance involves:

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  
Morf Class Function Description
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 
Asn1Type Class Function Description
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:

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:

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:

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:

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 
Class Function Returns
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:

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:

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 
Type Representation
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 
Format Bit Identifier Description
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:

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:

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 
Function Description
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:

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:

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 
Asn1Value Class Function Source ASN.1 Type Return Values
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:

    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 
    Constructor Description
    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:

    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:

    The function you use depends on what data is available to your program when the CHOICE syntax needs to be selected.

    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:

    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:

    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.


    Sun Microsystems, Inc.
    Copyright information. All rights reserved.
    Doc Set  |   Contents   |   Previous   |   Next   |   Index