TOP

ASN.1/C++ Runtime Advanced Topics

Applies to: ASN.1/C++ v8.0

C++ Compiler Macros to Optimize Size and Speed when Using the TOED

Code files generated for the Time-Optimized Encoder/Decoder contain a number of features that are either enabled or disabled by default. These features can be adjusted using C++ preprocessor macros during C++-compilation to optimize your application's performance and memory footprint. Most C++ compilers do this via the -D C++ compiler option (e.g., cc -DOSSDEBUG).

OSS_AVN_RESOLVE_OPEN_TYPE_BY_NAME
Enables the AVN TOED decoder code that tries to decode an open type using the PDU name provided in the type value notation when the decoder fails to resolve the type using component relation constraints. By default, this code is disabled by the C++ preprocessor.
OSS_AVN_DECODE_CONTAINED_IN_HEX
Enables support for the AVN_DECODE_CONTAINED_IN_HEX special runtime flag in the generated TOED AVN decoder. By default, this code is disabled by the C++ preprocessor to reduce the size of your program. If the runtime flag is set by the SetAVNFlags method the decoder automatically decodes the containing type from a value of a BIT STRING or OCTET STRING type constrained by content constraints when the value is provided in the hexadecimal form.
OSSDEBUG
Affects the verbosity of TOED diagnostic messages that can be retrieved with the getErrorMsg() method of the OssControl class. The OSSDEBUG macro has the following levels:
  • OSSDEBUG=0, no error message is constructed, and only an error code is returned.
  • OSSDEBUG=1, a simple error message is generated along with the error code.
  • OSSDEBUG=2 (or greater), an error message is generated that explains the specific error and in which component it occurred, along with the error code.
The default setting of the OSSDEBUG level is 2. Decrease this level to reduce the final application size and to slightly increase its performance.
OSSPRINT
Enables implementation of the ASN1Handle::print() method in TOED-based programs (as with SOED). By default, this function prints nothing and returns the NULL_FCN enumerator (error code 21). The -test compiler option enables OSSPRINT automatically.
OSS_COMPARE_VALUE
Enables implementation of the ASN1Handle::equal() method in TOED-based programs (as with SOED). By default, the ASN1Handle::equal() method does nothing and returns the UNIMPLEMENTED enumerator. The -test compiler option enables OSS_COMPARE_VALUE automatically.
OSS_COPY_VALUE
Enables implementation of the ASN1Handle::copy() method in TOED-based programs (as with SOED). By default, the ASN1Handle::copy() method does nothing and returns the UNIMPLEMENTED enumerator. The -test compiler option enables OSS_COPY_VALUE automatically.
OSS_DETECT_UNKNOWN_EXTENSION
Enables support by the generated code file for the OssControl::UnknownExtensionFound() method. This function allows the user to detect whether the last decoded PDU contained at least one unknown SEQUENCE/SET/CHOICE type extension. By default, this supporting code is disabled by the C++ preprocessor to reduce the size of your program and to achieve slightly better performance.
OSS_DO_NOT_CHECK_POINTERS
Disables the check for NULL pointers within the input C++ classes of the TOED encoder. By default, this check is performed to protect the encoder from a bad input value.
OSS_NO_BINARY_TEXT_API_CHECKS
Disables the checks required only for the Binary2XML(), XML2Binary(), Binary2JSON(), and JSON2Binary() OSS API methods. It is recommended that you set the macro when you do not use one of these functions.
OSS_NO_EXER_ENCODING_OF_DEFAULT_VALUES_AS_COMMENTS
Disables support for the EXER_ENCODING_OF_DEFAULT_VALUES_AS_COMMENTS runtime flag in TOED-based programs. This flag instructs the E-XER encoder to encode absent DEFAULT fields as XML comments that contain the corresponding default values. If set when compiling the C++ code file, the OSS_NO_EXER_ENCODING_OF_DEFAULT_VALUES_AS_COMMENTS macro eliminates the code generated to encode such fields.
OSS_NO_NESTING_CONTROL
Disables nesting control in TOED-based programs. Nesting control is a security mechanism used in decoders to prevent a possible stack overflow triggered by a specially crafted message. OSS runtime libraries provide protection from two types of nesting overflows: constructed string encodings and constructed types. They are enabled by default.
OSS_NO_STRICT_ENCODING_DECODING_CHECKING
Partially disables support for the STRICT_ENCODING_DECODING_RULES runtime flag in TOED-based programs. By default, this flag performs the checks for STRICT_ENCODING_DECODING_RULES. When the code file is C++-compiled with the OSS_NO_STRICT_ENCODING_DECODING_CHECKING macro, the following checks are disabled:
  • Incorrect fragmentation of constructed types in the PER encoding
  • Zero length extensions in the PER encoding
  • Zero length PER encodings
You cannot cancel the entire effect of the STRICT_ENCODING_DECODING_RULES runtime flag with the OSS_NO_STRICT_ENCODING_DECODING_CHECKING macro, because not all the checks are performed by the generated code file. The rest are performed by the TOED runtime; to disable these checks completely omit the STRICT_ENCODING_DECODING_RULES runtime flag from your application code.
OSS_NO_STRICT_EXTENSION_CONTROL
Disables the check for missing mandatory (non-optional) fields after the extension marker in the input PDU in TOED-based programs. By default, the check is performed.
OSS_OPENTYPE_PRECEDES_REFERENCED_FIELD_IN_JSON
Disables the automatic decoding of an open type feature of the TOED JSON decoder when the encoding of an open type precedes the encoding of its referenced field in a JSON encoding. This feature incurs some performance and decoder size overhead. When JSON encodings have open type fields that always follow their referenced fields (as is the case for JSON encodings produced by the OSS JSON encoders), this feature can be disabled to reduce the size and to increase the speed of the resulting application. Note that automatic decoding of an open type field when the field follows its referenced field in a JSON encoding is still possible. This feature is disabled by default.
OSS_REDUCED_ERROR_MSGS
Causes the message text returned by getErrorMsg() for the TOED to contain only the 5 character message prefix instead of the full text of the error message. This can reduce the size of the executable on platforms with limited resources. Note that if OSSDEBUG=0 is defined, the error message strings will be removed completely from the executable, leaving only the return codes to determine which error occurred.
OSS_STRICT_PER_ENCODING_OF_DEFAULT_VALUES
Provides support for the STRICT_PER_ENCODING_OF_DEFAULT_VALUES runtime flag in TOED-based programs (as with SOED). By default, this flag has no effect on the program. That is, the Basic-PER encoder produces a non-empty encoding for components defined with a DEFAULT value, even when the value to be encoded is the default value. The Canonical-PER encoder always skips components marked DEFAULT when the value to be encoded is the default value.
OSS_SKIP_UNKNOWN_CONTENT_SUPPORTED
Enables support for the OSS_SKIP_UNKNOWN_CONTENT runtime flag in the E-XER TOED-based programs. By default, this code is disabled by the C++ preprocessor to reduce the size of your program and to achieve slightly better performance (the difference is in the range of 5 to 10% for size and speed). By default, the decoder issues errors if unknown elements or attributes are present in the input XML message.

Guidelines for Improving Runtime Performance

  • Be sure to use the default TOED (Time-Optimized Encoder/Decoder) runtime rather than the SOED.
  • Do not set the DEBUGPDU flag before calling the encoder/decoder. This will disable time-consuming trace activity during encoding/decoding operations.
  • Specify the -minimize ASN.1 compiler command line option when compiling your ASN.1 syntax. This will usually lead to a smaller .cpp file and will result in only crucial constraint checking being done on values which are being encoded/decoded. Alternatively, specify the NOCONSTRAIN flag before calling the encoder/decoder, thereby disabling run-time constraint checking while retaining the ability to later enable it, if the need arises.
  • Do not specify the OSS_TRAPPING flag before calling the encoder/decoder. The flag enables the trapping of memory violations and the construction of an error message that details which field of the PDU was being processed when the memory violation occurred. If your application is fully tested, you have every reason to not specify OSS_TRAPPING. For versions prior to 4.1 specify the NOTRAPPING flag before calling the encoder/decoder.
  • Use the OSS ASN.1/C++ Memory Pools API that offers optimized dynamic memory management. A sample that demonstrates the Memory Pools API is in the samples/advanced/memory_pool subdirectory of the software installation.
  • When using the default OSS TOED library, review C++ Compiler Macros to Optimize Size and Speed when Using the TOED above and tune your application to achieve better performance by setting some of the listed macros.
  • Use ownership-transferring functions to avoid excessive copying of large memory blocks. Use the OSS.POINTER directive to additionally generate ownership-transferring functions for components of constructed types.
  • C++ compile the generated code with optimization flags.

Partial Decoding

The partial decoding feature can be used instead of, or in addition to standard (full) decoding. Partial decoding allows you to

  • Decode preselected fields from incoming messages at a very high speed. The remaining fields are bypassed.
  • Modify the value of a preselected field; you can directly replace a field value in a binary message (not recommended for messages encoded by the Packed Encoding Rules).

For each decoded field, the offset, length, and value are provided by the decoder to the user application via callback methods. This means that you don't need to write code or know the PDU's C++ representation details to access a deeply nested field.

Your callback method can analyze a decoded value and, by setting the return code, instruct the decoder to terminate or continue decoding.

The ASN.1/C++ Compiler generates the <module_name>_Callback class that contains your callback methods (virtual member functions); you can easily derive the class and implement the callback methods. The <module_name>_Callback class is a subclass of the OssCallback base interface.

The partial decoding feature requires the ASN.1/C++ TOED Runtime version 6.2 or later.

The BER, DER, PER, UPER, CPER, CUPER, OER, and COER binary encoding rules support partial decoding. XER, CXER, E-XER, and JSON encoding rules do not support partial decoding.

Example

This example shows how data and info callback methods can be combined so that only zipcode values from homeAddress are processed and zipcode values from companyAddress are ignored. The result of the OSS.DataCallback directive is that myZipcode() is called for zipcode in both uses of Address. Next, the OSS.InfoCallback directive applies a filter so only the zipcode values from homeAddress are used.

ASN.1 syntax (infotest.asn):

--<OSS.DataCallback M.Address.zipcode "myZipcode">--
--<OSS.InfoCallback M.Subscriber.homeAddress" homeAddressField">--

M DEFINITIONS AUTOMATIC TAGS ::= BEGIN
Subscriber ::= SEQUENCE {
   name         VisibleString,
   company      Company,
   homeAddress  Address
}
Company ::= SEQUENCE {
   name     VisibleString,
   address  Address
}
Address ::= SEQUENCE {
   zipcode      INTEGER( 0..99999 ),
   addressline  VisibleString( SIZE (1..64) )
}
END

Subscriber PDU encoding:

/* the BER encoding of a Subscriber PDU */
char   ber_enc[] = {

    0x30, 0x5D, 0x80, 0x08, 0x4A, 0x6F, 0x68, 0x6E, 0x20, 0x44,
    0x6F, 0x65, 0xA1, 0x2D, 0x80, 0x10, 0x41, 0x62, 0x73, 0x75,
    0x72, 0x64, 0x20, 0x4C, 0x6F, 0x67, 0x69, 0x73, 0x74, 0x69,
    0x63, 0x73, 0xA1, 0x19, 0x80, 0x02, 0x30, 0x39, 0x81, 0x13,
    0x38, 0x30, 0x30, 0x2C, 0x20, 0x37, 0x74, 0x68, 0x20, 0x53,
    0x74, 0x72, 0x65, 0x65, 0x74, 0x2C, 0x20, 0x4E, 0x59, 0xA2,
    0x22, 0x80, 0x03, 0x01, 0x09, 0x32, 0x81, 0x1B, 0x33, 0x33,
    0x33, 0x2C, 0x20, 0x46, 0x6F, 0x6F, 0x62, 0x61, 0x72, 0x20,
    0x44, 0x72, 0x2E, 0x2C, 0x20, 0x42, 0x61, 0x79, 0x6F, 0x6E,
    0x6E, 0x65, 0x20, 0x4E, 0x4A
};

Generated .cpp:

/*
    A structure for data exchange between callback function calls.
    In case of multithreading it should be allocated per thread.
*/
typedef struct {
    int    flag;
} UserData;

UserData data;

/* derive the compiler generated infotest_Callback class */
class myCallbackClass : public infotest_Callback {
public:
    int myZipcode(OssGlobal *_g, long offset, long length, unsigned int flags, OSS_UINT32  *value);
    int homeAddressField(OssGlobal *_g, const char *fname, unsigned int flags);
};

/* 
    Info callback method. It sets the flag indicating that homeAddress
    field is being decoded 
*/
int myCallbackClass::homeAddressField(OssGlobal *_g, const char *fname, unsigned int flags) {
    UserData *udP = (UserData *)this->userVar;
    if (flags & OSS_DECODING_OF_COMPONENT_IN_PROGRESS) {
        ossPrint(_g, "\n\nDecoding of homeAddressField started...");
        udP->flag = 1;
    }
    else {
        ossPrint(_g, "\nDecoding of homeAddressField completed.\n\n");
        udP->flag = 0;
    }
    return OSS_CONTINUE_DECODING;
}

/* 
    myZipcode callback method implementation.
    it prints the value of zipcode field 
*/
int myCallbackClass::myZipcode(OssGlobal *_g, long offset, long length,
                                                             unsigned int flags, OSS_UINT32  *value) {
    UserData *udP = (UserData *)this->userVar;

    ossPrint(_g, "\n!myZipcode() callback...\n");

    if (udP->flag != 1) {  /* we are not in homeAddress */
        ossPrint(_g, "    we are not in homeAaddress! Continue decoding...\n");
        return OSS_CONTINUE_DECODING;
    }
    /* Print homeAddress zipcode */
    ossPrint(_g, "   zipcode value is %05d\n", *value);

    return OSS_SKIP_TO_PDU_END;
};
void testInfoCallback()
{
    Subscriber_PDU      pdu;
    infotest_Control    ctl;
    EncodedBuffer       eb;
    myCallbackClass     cback;

    cback.userVar = &data;

    ctl.setEncodingRules(OSS_BER);
    eb.set_buffer(sizeof(ber_enc), ber_enc);

    pdu.partialDecode(ctl, eb, cback);
}

Here is the output of the code sample:

!myZipcode() callback...
    we are not in homeAddress! Continue decoding...


Decoding of homeAddressField started...
!myZipcode() callback...
   zipcode value is 67890

For more details about this example, see Effect of OSS.InfoCallback.

See Also

Note: Partial decoding is a chargeable feature in non-evaluation licenses. Contact Sales to obtain pricing information.


Comma-Separated Value Encoding Rules (CSV)

The Time-Optimized Encoder (TOED) supports the Comma-Separated Value encoding rules (CSV). The -csv compiler option instructs the compiler to generate encoding code for CSV. When the OSS_CSV rules are set by the OssControl::setEncodingRules() API call, the PDU::encode() function encodes an in-memory PDU value to this format.

The Comma-Separated Value encoding rules (CSV) are currently supported only by the TOED runtime (excluding RTOED). The -csv compiler option is not compatible with the -soed or -rtoed option.

The CSV encoder flattens a structured ASN.1 message into a fixed number of columns by recursively expanding complex SET, SEQUENCE, and CHOICE types up to the innermost fields with simple ASN.1 types. The resulting record includes a place for each simple type value, which can be empty for optional fields with absent values or CHOICE alternatives that were not selected.

Two CSV formats are supported:

  • A row format, where each row is a record that contains values separated by a comma (',') or by a user-specified column separator: semicolon (';'), colon (':'), or equal sign ('=').
  • A column format, where each value is placed on a separate line, possibly following an optional CSV header name and a column separator. Call OssControl::setCsvFlags() with the CSV_ENCODE_FORMAT_COLUMN flag to specify this format.

The CSV format can include an optional CSV header that is created by parsing the input PDU type definition. The header record consists of absolute references or single names that match the values in the columns (in case of a row format) or rows (in case of a column format) where each node is separated by an underscore ('_') by default or by one of the following header separators: dash ('-'), period ('.'), slash ('/'), backslash ('\').

Example

ASN.1:

PersonnelRecord ::= SEQUENCE {
          name     PrintableString,
          number   INTEGER OPTIONAL,
          children SEQUENCE OF ChildInformation
}
ChildInformation ::= SET {
         name    PrintableString,
         date    GeneralizedTime OPTIONAL
}
value PersonnelRecord ::= {
         name "Nancy",
         number 20,
         children {
              {name "James", date "20020312000000"},
              {name "Martha", date "20100820000000"}
         }
}

CSV row format:

name,number,children_name,children_date
"Nancy",20,"James",20020312000000
"Nancy",20,"Martha",20100820000000

CSV Conversion Restrictions

  • CSV encoding rules are not supported by the RTOED runtime.
  • Values of SET OF and SEQUENCE OF types with multiple components are mapped into several CSV records, where only one component differs and the rest are repeated. SET OF and SEQUENCE OF types can be nested within these types. By default, to avoid significant performance degradation, additional CSVs for up to 50 components within each SET OF and SEQUENCE OF type are created. To limit this number of components, call OssControl::setCsvSetOfSeqOfLimit(). The total number of additional CSVs for all SET OF and SEQUENCE OF types within a PDU type is limited to the maximum between the user-specified number set by the OssControl::setCsvSetOfSeqOfLimit() function and 50, multiplied by 50. To limit this number, call OssControl::setAllCsvLimit().
  • When open types are included, at any nesting level, within SET OF or SEQUENCE OF types, their containing PDU types must be the same for all components to ensure that each component has the same CSV structure. If values of different PDU types are included in these open type values, the CSV header is created based on the PDU type whose value is included in the first component. In this case, CSVs created for different components may have a different number of columns and different types of values (if simple types are different) within the same columns.

Type Mapping and Data Conversion

CSVs are in human-readable format similar to ASN.1 value notation. The table below shows the differences sorted by ASN.1 type. Additional CSV representations are available by passing special flags to the OssControl::setCsvFlags() function.

ASN.1 Type ASN.1 Value CSV Value
BIT STRING bstring
'0101011'B
xmlbstring
010101
BOOLEAN TRUE or FALSE Default: true or false
With CSV_ENCODE_BOOLEAN_NUM flag: 1 or 0
Restricted Character String types Quoted cstring or list notation Quoted strings.
With CSV_USE_UNICODE_ESCAPE_SEQUENCE flag:
"\\u0000" format is used for Unicode characters
CHOICE The selected alternative name is included as 'chosen : <value>' All alternatives are present, the ones that are not chosen have empty values with extra separators for all their nested components.
ENUMERATED identifier Default: enumerator's identifier
With CSV_ENCODE_ENUMERATED_NUM flag: enumerator's numeric value
GeneralizedTime "20120808131347+0500" The same non-quoted value
NULL NULL null
OBJECT IDENTIFIER,
RELATIVE-OID
{arc1(num1) arc2 ... } or encoded format Dot notation:
1.3.6.1.4.1.1900
OCTET STRINGS hstring
'6B646F726C793031'H
xmlhstring
6B646F726C793031
Types with ContentsConstraint bstring Automatically decoded if the containing PDU is known.
REAL Different representations, including {mantissa, base, exponent} notation Decimal format
SET, SEQUENCE Values for fields with OPTIONAL/DEFAULT can be absent Columns for all fields with all their nested components are present. Missing values for optional fields are marked with extra separators. Missing values for fields with DEFAULT have values from the DEFAULT syntax.
SET OF, SEQUENCE OF Component values are included in {val1, val2, ...} One column is present for only one component. The row for the complete PDU is repeated for each extra component.
TIME, DATE, and other time types "2010-04-15T17:18:18-07:00" The same quoted value
UTCTime "200808131347Z" The same non-quoted value
Circularly defined types Values for nested types are printed. The same value
Fields marked with the ASN1.Remove, OSS.NOENCODE, OSS.USERFIELD directive Ignored Ignored without extra columns

See Also

Note: Support of Comma-Separated Value encoding rules is a chargeable feature in non-evaluation licenses. Contact Sales to obtain pricing information.


This documentation applies to release 8.0 and later of the OSS® ASN.1 Tools for C++.

Copyright © 2025 OSS Nokalva, Inc. All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted in any form or by any means electronic, mechanical, photocopying, recording or otherwise, without the prior permission of OSS Nokalva, Inc.
Every distributed copy of the OSS® ASN.1 Tools for C++ is associated with a specific license and related unique license number. That license determines, among other things, what functions of the OSS ASN.1 Tools for C++ are available to you.