Code Generation for Partial Decoding

Using partial decoding can change how types are generated in addition to changing what functions are generated.

Type Generation

When -noencode is not used, types are generated normally, to support the complete generation of encoders. If, however, the -noencode option is used, then the partial decode configuration determines how types are generated: they may be fully generated, partially generated, or discarded; which case applies depends on what values the partial decode functions will need to return.

Fully Generated Types

If you target an element, that element's type will be fully generated (i.e. generated normally), allowing the partial decode function to return the complete value for that element. All types referenced by that type will also be fully generated, since those types conceptually form a part of the targeted element's value.

You can force a type to be fully generated by adding it to the types list of an <include> configuration element (refer to the section on configuration files). If you do this, it isn't necessary to also add types that your partial decoding configuration would require to be fully generated; those types will be automatically included.

Partially Generated Types

If you target a group of elements, the enclosing SEQUENCE or SET type will be partially generated (unless it must be fully generated, according to the above rules). In this case, the generated type will include just the fields corresponding to the targeted elements. If you target different groups of elements in the same enclosing SEQUENCE or SET, the generated type will include fields for all of the elements that were targeted in one or more of the groups.

To illustrate this, consider the group target example referenced above. The Name type is defined as

Name ::= SEQUENCE {
   givenName	VisibleString,
   initial	VisibleString,
   familyName	VisibleString
}

and we targeted just two of the three elements (givenName and familyName). As a result, the type was partially generated:

typedef struct Name {
   const char* givenName;
   const char* familyName;
} Name;

Discarded Types

Any type that is neither fully generated nor partially generated will not be generated at all. Such a type might still have corresponding functions generated.

To illustrate, in both of our examples, PersonnelRecord is not a part of the values we targeted, nor did we target any group of elements in that type. Therefore, PersonnelRecord is discarded. If you look at the generated header file for the aforementioned samples, you will find we don't generate that type.

Function Generation

Three kinds of PER decode functions may be generated:

  1. normal decode functions

  2. partial decode functions

  3. skip functions

All fully generated types will have a normal decode function generated.

For some types, no function will need to be generated. Types that are discarded and which require neither a partial decode function nor a skip function will have no generated functions.

The next two sections cover partial decode and skip functions.

Partial Decode Functions

A partial decode function will be generated for each partial decode target you configure. Partial decode function names have the following format:

asn1PPD_<outermost_type>_<suffix>

The suffix is a unique suffix, indicating the element or elements being targeted. The suffix may be longer or shorter, as needed, to uniquely identify which of the outermost type's configured targets it relates to. For groups, the suffix will be based on the type name of the enclosing SEQUENCE or SET. You can control the suffix by providing a name when configuring the target in the configuration file. The behavior of this partial decode function is to decode a value of the given outermost type, and return just the targeted value(s).

Other partial decode functions will also be generated to support the top-level partial decode functions just described. Each of these functions is responsible for returning the same value(s), but will decode a type nested inside the outermost type. The name for such a function will be based on the type it actually decodes, rather than the outermost type for which partial decoding was configured. For these supplemental partial decode functions, the suffix part of the function name is not configurable, but you will not use these supplemental functions directly anyway.

The value returned by a partial decode function is dynamically allocated (or is a list of dynamically allocated values). You are responsible for freeing the memory associated with those values. If you are generating code using the C++ standard libary option (-cpp11), it's important to follow the memory management guidelines discussed for that option. Otherwise, make use of the generated free functions or rtxMemFree to free the memory. If the partial decode function returns a list, here are some additional rules to keep in mind:

  • If you are using -cpp11, the objects in the list may contain standard library objects (e.g. std::string). If so, you will need to interate through the list and follow the memory management rules related to using that option. The remaining points in this list do not apply to you.

  • rtxDListFreeAll can be used to free all of the memory associated with the list and its contents. However, this cannot be used if the objects in the list contain pointers to dynamically allocated memory. If the objects in the list have an associated asn1Free_* function, you should iterate through the list and use it (or else, see the next option).

  • You can use rtxMemFree to free all memory allocated with the current OSCTXT context object in one shot.

Skip Functions

A skip function may be generated when a type will need to be skipped over (sometimes, a separate function is not required). This happens during partial decoding, when the decoder needs to parse through an encoded value that it isn't interested in, in order to reach the encoded values that it is interested in. The job of the skip function is simply to get past the value of the corresponding type. Skip function names are of the form asn1PDSkip_<typename>. You will not directly invoke the skip functions.

In our examples, the target path passes through PersonnelRecord.children, which means our partial decode function must skip over the sibling elements, such as PersonnelRecord.name of type Name. Therefore, we generate function asn1PDSkip_Name.

C++ Control Classes

The partial decode feature affects C++ Control Class generation. The C++ Control Class will include partial decode helper methods for any partial decode functions that are generated for the associated type. If the outermost type, the one the control class is being generated for, is fully generated, the partial decode methods will simply be added to what is normally generated. However, if the type is not fully generated, then the C++ control class will be generated without a msgData field (it won't contain a value of the type) and without most of the other methods it would normally have (those which would operate on msgData); it will, however, have the partial decode helper methods.