TOP

ASN.1/C++ Runtime Advanced Topics

Applies to: ASN.1/C++ v7.3

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.


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

Copyright © 2024 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.