The advanced topics covered in this section include the following:
Contents
PDU encoding or decoding requires extensive use of memory to store the source and destination data buffers. An encoded PDU is always stored as a single stream of bytes, while an unencoded (decoded) PDU is allocated in memory as C-representation of its individual fields (a combination of structures, arrays, and linked lists).
Depending on the PDU and memory size, your performance needs, and your choice of encoder or decoder runtime (SOED or TOED), the following options are available:
Additionally, you can combine the options mentioned above. For example, you can encode from memory to a file or decode from a socket to memory, while storing a large OCTET STRING field (of the un-decoded PDU) in a temporary file. Also, you can decode PDUs that start in a memory buffer and continue in a file or a socket. Note that only the SOED library supports files and sockets.
As illustrated in the following diagram, the encoder or decoder allocates and deallocates memory through low level functions contained in the OssGlobal structure (by default: malloc(), realloc(), free()).
To optimize memory use, consider the following options:
SOED Runtime Memory
In general, unencoded PDUs reside in memory, where each field is mapped to a certain C representation. However, to save memory, you can redirect fields (large streams of bytes) to a file. To ensure correct C-representation and handling, mark the fields with OSS.OBJHANDLE | OSS.NOCOPY at ASN.1 compile time, then use ossMarkObj() to bound to a file. Note that to add support for the files, you must link with the File Memory Manager library.
Encoded PDUs are represented as streams of bytes, thus they can be streamed directly to or from files or sockets during encoding or decoding to save memory.
The ossEncode() and ossDecode() functions inherit the behavior of the send() and recv() socket functions. For example, when a socket is closed by the remote side and a subsequent send() on the local side does not report an error, ossEncode() cannot detect the closed socket; instead, it accepts the undeliverable packet. To tune the socket, to send or receive additional messages using socket functions, use the socket handler.
NOTE: The ossDetermineMessageLength(), ossCompress(), and ossUnCompress() functions do not support encoded PDUs streamed to or from files.
Binding data to a file/socket
To use the selected PDU handling method, link with the corresponding management library. There are four libraries available:
Additionally, you can develop your own management library.
On Windows, you can link either statically or dynamically (DLL). The latter implements the explicit linking (late binding), thus the desired library is loaded at runtime, as follows: during the initialization, the encoder/decoder always loads the ossdmem.dll (conventional memory manager). Then, if the application needs a different PDU handling. To replace the default library, call ossLoadMemoryManager() and specify a different DLL (ossfmem.dll or osssmem.dll for files and sockets, accordingly, provided by OSS).
When linking statically, link ossdmgmt.obj/ossfmgmt.obj/osssmgmt.obj (default/file/socket library) with soeddefa.lib, or ossdmgmd.obj/ossfmgmd.obj/osssmgmd.obj (default/file/socket library) with soeddemd.lib.
The OSS ASN.1 runtime supports two modes of memory allocation during encoding and decoding.
In user allocation mode you provide to the OSS runtime a buffer sufficient to hold the data. For encoding it must be large enough to accommodate the encoded message; for decoding it must be large enough to accommodate the decoded PDU struct. This mode is faster than OSS-allocated mode, but you need to know how large a buffer is needed. If your buffer is too small, your call to ossEncode() or ossDecode() fails and returns an error code.
In OSS allocation mode the OSS runtime allocates the buffer, and if the size is insufficient, automatically allocates more. It will continue allocating memory, as needed, so ossEncode() and ossDecode() cannot fail because the buffer is too small.
The default for OSS allocation mode is to allocate little pieces, which has the advantage of not wasting space, but the disadvantage of having to call the system's memory allocation function (malloc) many times. You can instead use the Memory Handle API to request that the OSS runtime allocate memory in larger chunks, and to fill its need for buffer space from within those larger chunks.
A memory handle is a linked list of typically large memory blocks, where you choose the size. Rather than call malloc, the OSS runtime allocates pieces of memory from these blocks. You can also use this technique when working with helper macros, the helper list API, or when manually allocating values using the ossGetMemory() function.
The Memory Handle API is a set of functions to activate, control and terminate the memory handle mode. It employs ossSetUserMallocFreeRealloc() to override the default allocation (malloc), reallocation (realloc), and deallocation (free) functions with its own functions to maintain a chain of memory blocks.
As a result, you cannot use the ossSetUserMallocFreeRealloc() function when working with memory handles (you cannot override memory handle-specific allocation functions with your own).
Memory needed by ossEncode(), ossDecode(), or any other OSS API function is allocated from the same memory handle. You can allocate several memory handles for different parts of the program, for example, one handle to store the encoded data and another to store the decoded value.
NOTE: Due to specifics of the RTOED library to make the Memory Handle API available to an application linked with this library, the RTOED codefile generated by the ASN.1/C compiler must be C-compiled using the -DOSS_RTOED_MEMORY_HANDLES_SUPPORTED option.
With the Memory Handle API, you can optimize dynamic memory freeing and reuse. Since the memory is hosted by a single 'handle' structure as a list of blocks, it's possible to free it quickly.
The OSS decoder creates a tree-like C structure in memory. This tree can become quite intricate, and were it not for the Memory Handle feature, quite scattered. To deallocate a PDU, you would call the ossFreePDU() function to traverse the PDU tree and calls a system freer for each block of memory; this is time consuming. On the other hand, with memory handles, a single ossDeleteMemoryHandle() call deallocates the memory handle and the entire chain of memory blocks hosted by this handle.
In an even more efficient manner, you can release the memory without deallocating it by calling ossCleanMemoryHandle(), which instead of deallocating the memory blocks simply marks them as unused. The memory from these blocks can now be reused, for instance, by subsequent ossDecode() function calls. You can thus reuse the same memory for all your decodes, allocating it only once, that is, before the initial ossDecode() call.
Bearing in mind that user allocation mode is always fastest, we present some simple performance statistics for encoding and decoding the PersonnelRecord sample PDU in OSS allocation mode. For encoding without the benefit of memory handles, the TOED BER is 35% slower than user allocation mode; with memory handles, only 10% slower. The performance improvement in decoding is much more pronounced. Without memory handles, the TOED BER decoder is 300% slower, while with memory handles, only 22% slower.
To use the memory handle API, start by calling the ossCreateMemoryHandle() API function. It returns a pointer to the allocated handle or NULL in case of failure.
If several memory handles are in use, one of them should be set as "active" for a given instance of the global OSS environment variable by calling the ossSetActiveMemoryHandle() function. To retrieve the active memory handle pointer, call the ossGetActiveMemoryHandle() API function. The function returns NULL if memory handle mode is not in use.
To release memory, you can use ossCleanMemoryHandle() or ossDeleteMemoryHandle().
ossCleanMemoryHandle() - does not delete the handle itself nor does it deallocate the memory blocks attached to the handle (the memory releasing system function is not called). Instead, it marks all memory in these blocks as unused. As a result, subsequent attempts to allocate memory from the same handle will reuse the same memory blocks without having to allocate new ones with the system memory allocator (a decreased number of dynamic memory allocations per API function call makes the application work faster).
ossDeleteMemoryHandle() - permanently deallocates the memory handle and all its memory blocks. The handle pointer becomes unusable. This function should be called only once immediately before the ossterm() function. In all other cases, call the ossCleanMemoryHandle().
Memory usage statistics are available to help you tune the size of the buffer blocks and the number of handles. You can access the information by calling ossGetMemoryHandleStat().
For details on individual memory handle functions, see:
NOTE: You can find a complete working sample test program in the OSS ASN.1 installation directory, samples/advanced/memory_handles.
In this example, a memory handle is allocated only once. It is reset by ossCleanMemoryHandle() at the end of each iteration and is permanently deleted before ossterm().
struct ossMemoryHandle *hdl; if ((hdl = ossCreateMemoryHandle(world, CHUNK_LENGTH))) { while (loop) { rc = ossDecode(world, &pdunum, &buf, &value); /* any actions with 'value' */ .......................... /* ossCleanMemoryHandle resets the memory */ ossCleanMemoryHandle(world, hdl); } } else /* handle the error case - could not allocate a handle */ .......................... ossDeleteMemoryHandle(world, hdl); /* delete 'hdl' to prevent a memory leak */ ossterm(world);
Suppose you need to work with two decoded messages separately at the same time - this means that the messages should reside in different memory handles. The scenario illustrated below is as follows:
Struct ossMemoryHandle *hdl1, *hdl2; if (hdl1 = ossCreateMemoryHandle(world, CHUNK_LENGTH)) { rc = ossDecode(world, &pdunum1, &buf1, &value1); /* any actions with 'value1' */ .......................... } else /* handle the error case - could not allocate a handle #1 */ .......................... if (hdl2 = ossCreateMemoryHandle(world, CHUNK_LENGTH)) { rc = ossDecode(world, &pdunum2, &buf2, &value2); /* any actions with 'value2' */ .......................... } else /* handle the error case - could not allocate a handle #2 */ .......................... ossDeleteMemoryHandle(hdl1); /* any actions with 'value2', 'value1' being already freed */ ossDeleteMemoryHandle(hdl2);
Here is how you use the same memory handle for decoding as well as for manually allocating memory after decoding. Suppose you decode a message for the following PDU:
S ::= SEQUENCE { s1 INTEGER, s2 SEQUENCE OF OCTET STRING OPTIONAL }
If the decoder creates a value that in ASN.1 value notation is:
value S ::= { s1 200 }
and the task is to add a value for s2 so that the value of S looks like:
value S ::= { s1 200, s2 {'112233'H} }
The application code illustrates how this can be done.
S *s = NULL; if (ossCreateMemoryHandle(world, CHUNK_LENGTH)) { rc = ossDecode(world, &pdunum, &buf, &s); ...................... if (s && !s->s2) /* The function oss_S_s3 will allocate memory by calling ossGetMemory(); memory is allocated from the same active memory handle that was used by the decoder; same does the macro oss__OctStr_copy() */ s->s2 = oss_S_s2(world); oss_S_s2_append(world, s->s2, oss__OctStr_copy(world, (unsigned char *)"\x11\x22\x33", 3)); /* any further actions with 's' */ .......................... /* ossFreePDU will call ossCleanMemoryHandle */ ossDeleteMemoryHandle(world, ossGetActiveMemoryHandle(world)); }
This section illustrates how to free memory used by the handle when the amount of memory allocated by all its nodes (total) exceeds 1 MB. When the size of the messages being decoded is too large, the current active handle may allocate huge chunks; to avoid using system resources, the application may return the memory to the system immediately after decoding these messages by using the reset_handle() function:
#define SUCCESS 0 #define ERR_STATS 1 #define ERR_DELETE 2 #define ERR_CREATE 3 #define ERR_CLEAN 4 #define ERR_ACTIVE 5 static int reset_handle(OssGlobal *world) { struct ossMemoryHandle *curr = ossGetActiveMemoryHandle(world); OssMemoryHandleStat stat; size_t nBytes, nBlocks; if (curr) { if (ossGetMemoryHandleStat(world, curr, &stat, OSS_MH_BRIEF)) /* could not get the statistics */ return ERR_STATS; if (stat.system_allocated > 1024*1024 || stat.nodes > 32) { /* It's time to free the memory at the system level */ if (ossDeleteMemoryHandle(world, curr)) /* could not delete the handle */ return ERR_DELETE; if (!ossCreateMemoryHandle(world, CHUNK_LENGTH)) /* could not create a handle */ return ERR_CREATE; } else /* Release the memory at the OSS Memory Manager level */ if (ossCleanMemoryHandle(world, curr)) /* could not reuse the handle */ return ERR_CLEAN; } else /* active memory handle is NULL */ return ERR_ACTIVE; return SUCCESS; } .......................... int main (void) { .......................... if (ossCreateMemoryHandle(world, CHUNK_LENGTH)) { while (loop) { rc = ossDecode(world, &pdunum, &buf, &value); /* any actions with 'value' */ .......................... if (reset_handle(world)) { /* handle the error - could not reset the handle */ .......................... break; } } } else /* handle the error case - could not allocate a handle */ .......................... }
OSS provides global #defined macros that you can include in your function prototypes, function definitions, and function pointers. These macros are defined in ossasn1.h and their meaning depends on the platform. Use these macros to:
Consider these six global macros:
The eopenIn() function takes three arguments. Here is the function prototype:
unsigned char* DLL_ENTRY eopenIn(OssGlobal *world, void *lock, size_t length);
Here is the function definition:
unsigned char* DLL_ENTRY_FDEF eopenIn(OssGlobal *world, void *lock, size_t length); { /* Function body */ }
Here is the function pointer for eopenIn():
unsigned char *(DLL_ENTRY_FPTR eopenInp)(void *, void *, size_t);
The following example shows how macros are used to declare three callback functions and function pointers passed to the ossSetUserMallocFreeRealloc() and ossGetUserMallocFreeRealloc() OSS API functions to set up a custom memory allocator:
/* The user functions prototypes should look like: */ void * CDECL_ENTRY myMalloc(OssGlobal *world, size_t size); void * CDECL_ENTRY myRealloc(OssGlobal *world, void *buf, size_t size); void CDECL_ENTRY myFree(OssGlobal *world, void *buf); int main() { struct ossGlobal w, *world = &w; /* The function pointers should look like: */ void *(CDECL_ENTRY_FPTR *oldMalloc)(OssGlobal *world, size_t size); void *(CDECL_ENTRY_FPTR *oldRealloc)(OssGlobal *world, void *buf, size_t size); void (CDECL_ENTRY_FPTR *oldFree)(OssGlobal *world, void *buf); ossinit(world, oss_data); /* Save original allocation functions */ ossGetUserMallocFreeRealloc(world, &oldMalloc, &oldFree, &oldRealloc); /* Set new ones */ ossSetUserMallocFreeRealloc(world, myMalloc, myFree, myRealloc); /* Restore original allocation functions */ ossSetUserMallocFreeRealloc(world, oldMalloc, oldFree, oldRealloc); ossterm(world); } /* The user functions definitions should look like: */ void * CDECL_ENTRY_FDEF myMalloc(OssGlobal *world, size_t size) { /* Function body */ } void * CDECL_ENTRY_FDEF myRealloc(OssGlobal *world, void *buf, size_t size) { /* Function body */ } void CDECL_ENTRY_FDEF myFree(OssGlobal *world, void *buf) { /* Function body */ }
The global environment variable is passed to almost every API function. Aside from the variables documented in this section, you should not explicitly modify any other field in OssGlobal, because it might generate unpredictable results.
typedef struct OssGlobal {...};
You can access (set/get) the following fields in this structure:
typedef struct OpenType { int pduNum; long length; /* length of encoded */ void *encoded; void *decoded; # ifdef OSS_OPENTYPE_HAS_USERFIELD void *userField; # endif } OpenType;
typedef struct OpenTypeExtended { int pduNum; long length; /* length of encoded */ void *encoded; void *decoded; unsigned long byteOffset; unsigned short bitOffset; /* Used only for PER */ unsigned short residualBits; /* Used only for PER */ #ifdef OSS_OPENTYPE_HAS_USERFIELD void *userField; #endif } OpenTypeExtended;
The ASN.1 compiler generates OpenType structures when Information Objects are defined in a way that renders ambiguous the exact type intended for a certain field. OpenType is generated for elements of CHOICE, SEQUENCE, and SET types that have either the ASN1.DeferDecoding or OSS.ENCODABLE directive applied to them. OpenTypeExtended is generated for ASN.1 types marked with ASN1.DeferDecoding and OSS.OBJHANDLE/OSS.NOCOPY to represent data which can reside in "external" memory, such as a file, whose decoding is to be deferred.
pduNum and decoded fields are used only if the AUTOMATIC_ENCDEC flag is set (see the ossSetFlags()).
When the AUTOMATIC_ENCDEC flag is set, the length and encoded fields should be set to NULL before calling the encoder; while the decoder sets these fields to NULL upon completing a successful automatic decode.
When the AUTOMATIC_ENCDEC flag is not set, the pduNum and decoded fields must be set to NULL, while the encoded and length fields must reference the encoded data and its length, respectively.
To automatically encode or decode OpenType values, the open type declaration must contain a component relation constraint applied to it, such as the "({SupportedAttributes}{@type})" in the following:
AttributeTypeAndValue ::= SEQUENCE { type ATTRIBUTE.&id ({SupportedAttributes}), value ATTRIBUTE.&Type ({SupportedAttributes}{@type}) }
Currently, for the TOED implementation of automatic encoding/decoding of open types, a SET OF or SEQUENCE OF type may not be referenced by a component relation constraint that is used to determine the base type of the open type.
Code files generated for TOED contain a number of features that are either enabled or disabled by default and can be adjusted for performance and/or the memory footprint by a set of C compiler macros. This is done via -D compiler option (-DOSSDEBUG).
ossPrintPER() | ossPrintXPER() |
---|---|
int ossPrintPER(OssGlobal *world, int *pdunum, OssBuf *input, void **output, long flags, UserPrintPer userPrintPer); |
int ossPrintXPER(struct ossGlobal *world, int *pdunum, OssBuf *input, void **output, long flags, UserPrintPer userPrintPer) |
The ossPrintPER() and ossPrintXPER() functions take a PER encoded PDU from "input" and print to "world->asn1out" a well-commented description of the encoded data. The generated output identifies the name and value of each component of the PER-encoded message, the exact location within the input buffer of the value, its length, the number of pad bits, how extension addition values are constructed, and so on. The functions support all PER variants: BASIC-PER ALIGNED, BASIC-PER UNALIGNED, CANONICAL-PER ALIGNED, and CANONICAL-PER UNALIGNED.
The "flags" argument allows you to customize the generated output.
The "userPrintPer" argument allows you to customize the printout and analyze the PER encodings by accepting as input your own print function.
NOTE: The OSS PER Encoding Analyzer (PrintPER) is available for common platforms like Windows, Linux, and Solaris, and might not be available for your embedded system port. If you are interested in PrintPER for your platform, contact Sales ‹info@oss.com›.
The ossPrintPER() function prints a description of the PER encoded data in valid ASN.1 value notation along with additional comments.
The ossPrintXPER() function prints a description of the PER encoded data as a valid XML document (see http://www.w3.org/XML/), according to a predefined schema in DTD form (to learn how a valid DTD file appears, see the ossprintxper.dtd file).
The following example shows the output of the ossPrintPER() and ossPrintXPER() functions. The output may vary depending on the "flags" setting.
ASN.1 type and value definition:
Foo ::= SEQUENCE { a INTEGER (250..253) OPTIONAL, ..., [[ b NumericString (SIZE(3)), c INTEGER ]], ..., d BOOLEAN OPTIONAL } value Foo ::= { a 253, b "123", c 20000, d TRUE }
value is encoded in PER ALIGNED (shown in hexadecimal) as: FC040523 40024E20.
ossPrintPER() output:
value Foo ::= { --extension flag: <.1> --preamble: <11> a 253, --contents: <11> d TRUE, --contents: <1> --extension count: <00.00000> --extension preamble: <1> --[[ --padding: <00> --extension length: <.00000101> b "123", --contents: <.0010 0011 .0100> c 20000 --padding: <0000> --length: <.00000010> --contents: <.01001110 .00100000> --]] } --TOTAL LENGTH: 8,0
ossPrintXPER() output:
<PDU name="Foo"> <Value type="seqset"> <Details> <metadata type="TYPE INFORMATION">SEQUENCE</metadata> <metadata type="LEVEL NUMBER">1</metadata> <position offset="0,0"/> <encoding type="extension flag">[.1]</encoding> <encoding type="preamble"> [11] <description>bit #0 = 1: 'a' is present</description> <description>bit #1 = 1: 'd' is present</description> </encoding> </Details> <Field name="a"> <Value> 253 <Details> <metadata type="TYPE INFORMATION">INTEGER (250..253) OPTIONAL</metadata> <metadata type="FULL NAME">a</metadata> <metadata type="LEVEL NUMBER">1.1</metadata> <position offset="0,3" length="0,2"/> <encoding type="contents">[11]</encoding> </Details> </Value> </Field> <Field name="d"> <Value> TRUE <Details> <metadata type="TYPE INFORMATION">BOOLEAN OPTIONAL</metadata> <metadata type="FULL NAME">d</metadata> <metadata type="LEVEL NUMBER">1.2</metadata> <position offset="0,5" length="0,1"/> <encoding type="contents">[1]</encoding> </Details> </Value> </Field> <Extensions> <ExtensionsPreamble> <encoding type="extension preamble size flag"> [0] <description>(preamble size is EQUAL or LESS than 64)</description> </encoding> <encoding type="extension preamble length"> [0.00000] <description>(decoded as 1)</description> </encoding> <encoding type="extension preamble"> [1] <description>bit #0 = 1: version brackets that contain: 'b' and 'c' are present</description> </encoding> </ExtensionsPreamble> <Extension brackets="yes"> <ExtensionHeader> <encoding type="padding">[00]</encoding> <encoding type="extension length"> [.00000101] <description>(decoded as 5)</description> </encoding> </ExtensionHeader> <Field name="b"> <Value> "123" <Details> <metadata type="TYPE INFORMATION">NumericString (SIZE(3))</metadata> <metadata type="FULL NAME">b</metadata> <metadata type="LEVEL NUMBER">1.3</metadata> <position offset="3,0" length="1,4"/> <encoding type="contents">[.0010 0011 .0100]</encoding> </Details> </Value> </Field> <Field name="c"> <Value> 20000 <Details> <metadata type="TYPE INFORMATION">INTEGER</metadata> <metadata type="FULL NAME">c</metadata> <metadata type="LEVEL NUMBER">1.4</metadata> <position offset="4,4" length="3,4"/> <encoding type="padding">[0000]</encoding> <encoding type="length"> [.00000010] <description>(decoded as 2)</description> </encoding> <encoding type="contents">[.01001110 .00100000]</encoding> </Details> </Value> </Field> </Extension> </Extensions> </Value> <TotalLength bytecount="8"/> </PDU>
The ossPrintPER() function generates ASN.1 comments.
The ossPrintXPER() function generates comments that are represented as XML tags and attributes.
The comments act as a bridge between the decoded PDU (the "top" level) and its PER encoding (the "low" level). Although some of the comments may seem superfluous (for example, offsets or absolute references), they make the output more complete. There are two main groups of comments:
The first group of comments is best explained by understanding how the encoder works. The encoded data is divided into logical groups of bits. Each group has its own particular significance. The encoding of ASN.1 values may contain any number of groups, depending on the type of the value. The ossPrintPER() | ossPrintXPER() function recognizes the groups during decoding and prints its description and contents as comments.
The ossPrintPER() function prints the comments in the following format:
--<name_of_group>: <bits_in_encoding>
name_of_group is the name of a classification of groups of bits listed below.
bits_in_encoding shows the content of the current group. The content is taken from a real encoding and can be presented in two possible formats described below.
The first format is a pure binary format. The content of the group of bits is shown as a sequence of bits enclosed in less-than ("<") and greater-than (">") signs.
The second format is a combination of hex and binary, where full bytes are written in hex format and leading and trailing bits are written between "<" and ">" signs.
a) <1010.1 11111 11.000> - "binary" format; b) <1010>.ff<.000> - "hex/binary" format;
The period (".") indicates the boundary between whole bytes. The space (" "), in "binary" format, indicates the boundary between logical parts of data in the encoding.
The ossPrintXPER() function prints groups of bits in the following format:
<encoding type="name_of_group">[bits_in_encoding]</encoding>
In the hex/binary format, ossPrintXPER() prints full bytes in hex format, and leading and trailing bits between brackets ("[" and "]"), and not angle brackets, because the latter are reserved symbols in XML.
The following section describes the bit groups:
For more information, see the X.6911 standards.
The second group of comments, namely "additional information" comments, are printed when the corresponding flags are specified and appear in capital letters. The additional information helps you understand the structure of the encoded output, and is especially useful when decoding a complicated PDU. Also, the comments are useful when parsing an output or searching for any particular fields. The following types are considered "additional information" comments:
The following example shows the generated output of the ossPrintPER() that contains "additional information" comments. Note that the ASN.1 declarations and the encoding rules are the same as in the first example:
value Foo ::= { --TYPE INFORMATION: SEQUENCE --LEVEL NUMBER: 1 --OFFSET: 0,0 --extension flag: <.1> --preamble: <11> --bit #0 = 1: 'a' is present --bit #1 = 1: 'd' is present a 253, --TYPE INFORMATION: INTEGER (250..253) OPTIONAL --FULL NAME: a --LEVEL NUMBER: 1.1 --OFFSET: 0,3; LENGTH: 0,2 --contents: <11> d TRUE, --TYPE INFORMATION: BOOLEAN OPTIONAL --FULL NAME: d --LEVEL NUMBER: 1.2 --OFFSET: 0,5; LENGTH: 0,1 --contents: <1> --extension count: <00.00000> (decoded as 1) --extension preamble: <1> --bit #0 = 1: version brackets that contain: --'b' --'c' --is present --[[ --padding: <00> --extension length: <.00000101> (decoded as 5) b "123", --TYPE INFORMATION: NumericString (SIZE(3)) --FULL NAME: b --LEVEL NUMBER: 1.3 --OFFSET: 3,0; LENGTH: 1,4 --contents: <.0010 0011 .0100> c 20000 --TYPE INFORMATION: INTEGER --FULL NAME: c --LEVEL NUMBER: 1.4 --OFFSET: 4,4; LENGTH: 3,4 --padding: <0000> --length: <.00000010> (decoded as 2) --contents: <.01001110 .00100000> --]] } --TOTAL LENGTH: 8,0
The output does not change when using the ossPrintXPER() function (see the first example), because this function always produces additional details within its output.
The type of "additional information" is determined based on the following:
The following example shows how the absolute reference and level number are counted.
SamplePDU ::= SET { a SEQUENCE OF BOOLEAN, b SEQUENCE { c BOOLEAN } } value SamplePDU ::= { a { TRUE }, b { c TRUE }}
value is encoded in PER ALIGNED into two bytes: 01C0.
ossPrintPER() | ossPrintXPER() |
---|---|
value SamplePDU ::= { --TYPE INFORMATION: SET --OFFSET: 0,0 --LEVEL NUMBER: 1 a { --TYPE INFORMATION: SEQUENCE OF --OFFSET: 0.0 --FULL NAME: a --LEVEL NUMBER: 1.1 --length: <.00000001> (decoded as 1) TRUE --TYPE INFORMATION: BOOLEAN --OFFSET: 1,0; LENGTH: 0,1 --FULL NAME: a.[0] --LEVEL NUMBER: 1.1.1 --contents: <.1> }, b { --TYPE INFORMATION: SEQUENCE --OFFSET: 1,1 --FULL NAME: b --LEVEL NUMBER: 1.2 c TRUE --TYPE INFORMATION: BOOLEAN --OFFSET: 1,1; LENGTH: 0,1 --FULL NAME: b.c --LEVEL NUMBER: 1.2.1 --contents: <1> } } --PDU padding: <000000> --TOTAL LENGTH: 2,0 |
<PDU name="SamplePDU"> <Value type="seqset"> <Details> <metadata type="TYPE INFORMATION">SET</metadata> <metadata type="LEVEL NUMBER">1</metadata> <position offset="0,0"/> </Details> <Field name="a"> <Value type="seqsetof"> <Details> <metadata type="TYPE INFORMATION">SEQUENCE OF</metadata> <metadata type="FULL NAME">a</metadata> <metadata type="LEVEL NUMBER">1.1</metadata> <position offset="0,0"/> <encoding type="length"> [.00000001] <description>(decoded as 1)</description> </encoding> </Details> <Value> TRUE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">a.[0]</metadata> <metadata type="LEVEL NUMBER">1.1.1</metadata> <position offset="1,0" length="0,1"/> <encoding type="contents">[.1]</encoding> </Details> </Value> </Value> </Field> <Field name="b"> <Value type="seqset"> <Details> <metadata type="TYPE INFORMATION">SEQUENCE</metadata> <metadata type="FULL NAME">b</metadata> <metadata type="LEVEL NUMBER">1.2</metadata> <position offset="1,1"/> </Details> <Field name="c"> <Value> TRUE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">b.c</metadata> <metadata type="LEVEL NUMBER">1.2.1</metadata> <position offset="1,1" length="0,1"/> <encoding type="contents">[1]</encoding> </Details> </Value> </Field> </Value> </Field> </Value> <encoding type="PDU padding">[000000]</encoding> <TotalLength bytecount="2"/> </PDU> |
Note that "FULL NAME" and "LEVEL NUMBER" are increased when a constructed type is decoded.
The information about the ASN.1 type notation that is printed as "TYPE INFORMATION" is not equivalent to the primary ASN.1 declaration. Only general information is printed about base constraints and default values. This information helps you understand how a value of an actual ASN.1 type is decoded.
The "useful" comments can be divided into two groups:
The following example is taken from the above ossPrintPER() and ossPrintXPER() output:
ossPrintPER() | ossPrintXPER() |
---|---|
--extension preamble: <1> --bit #0 = 1: version brackets that contain: --'b' --'c' --are present |
<encoding type="extension preamble"> [1] <description>bit #0 = 1: version brackets that contain: 'b'and 'c' are present</description> </encoding> |
Note that these comments are printed only for the "preamble" and the "extension preamble" bits.
The second group of "useful" comments, namely a presentation of certain groups of bits that define any values that can be shown as an integer number, contains the following: "length", "extension length", "choice index", "exponent length", "extension count". Here is an output fragment generated by ossPrintPER() and ossPrintXPER():
ossPrintPER() | ossPrintXPER() |
---|---|
c 20000 --TYPE INFORMATION: INTEGER --FULL NAME: c --LEVEL NUMBER: 1.4 --OFFSET: 4,4; LENGTH: 3,4 --padding: <0000> --length: <.00000010> (decoded as 2) <-- --contents: <.01001110 .00100000> |
<Field name="c"> <Value> 20000 <Details> <metadata type="TYPE INFORMATION">INTEGER</metadata> <metadata type="FULL NAME">c</metadata> <metadata type="LEVEL NUMBER">1.4</metadata> <position offset="4,4" length="3,4"/> <encoding type="padding">[0000]</encoding> <encoding type="length"> [.00000010] <description>(decoded as 2)</description> </encoding> <encoding type="contents">[.01001110.00100000]</encoding> </Details> </Value> </Field> |
OSS_ASN_ONLY OSS_HEXBYTES OSS_SEPARATE_ASN OSS_NOBRACES OSS_PRINT_ABSREF OSS_PRINT_OFFSET OSS_PRINT_NUMBERS OSS_PRINT_TYPE_INFO OSS_PRINT_COMMENTS OSS_NOPRINT OSS_PRINT_XML_HEADER (added in version 2.0) OSS_PRE_2_0_COMPAT (added in version 2.0) OSS_NO_TIME_DETAILS (added in version 8.4) OSS_NO_CONTAINED_TYPE (added in version 8.4) OSS_NO_CONTAINED_TYPE_TRACE (added in version 8.4) OSS_NO_TRACE_FOR_TRUNCATED_ELEMENTS (added in version 10.1) OSS_PRE_10_1_COMPAT (added in version 10.1)
The flags argument does not have default settings. The following ASN.1 notation shows the impact of each flag:
Foo2 ::= SET { a SEQUENCE { b [1] BOOLEAN OPTIONAL, c [2] BOOLEAN } } value Foo2 ::= { a { c TRUE}}
value is encoded in PER Aligned (shown in hexadecimal) as: 40 (into one byte).
The default output generated by ossPrintPER() and ossPrintXPER() for this encoding is:
ossPrintPER() | ossPrintXPER() |
---|---|
value Foo2 ::= { a { --preamble: <.0> c TRUE --contents: <1> } } --PDU padding: <000000> |
<PDU name="Foo2"> <Value type="seqset"> <Details> <metadata type="TYPE INFORMATION">SET</metadata> <metadata type="LEVEL NUMBER">1</metadata> <position offset="0,0"/> </Details> <Field name="a"> <Value type="seqset"> <Details> <metadata type="TYPE INFORMATION">SEQUENCE</metadata> <metadata type="FULL NAME">a</metadata> <metadata type="LEVEL NUMBER">1.1</metadata> <position offset="0,0"/> <encoding type="preamble"> [.0] <description>bit #0 = 0: 'b' is absent</description> </encoding> </Details> <Field name="c"> <Value> TRUE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">a.c</metadata> <metadata type="LEVEL NUMBER">1.1.1</metadata> <position offset="0,1" length="0,1"/> <encoding type="contents">[1]</encoding> </Details> </Value> </Field> </Value> </Field> </Value> <encoding type="PDU padding">[000000]</encoding> <TotalLength bytecount="1"/> </PDU> |
Note that the OSS_ASN_ONLY and OSS_SEPARATE_ASN flags are always removed, and the OSS_NOBRACES, OSS_PRINT_ABSREF, OSS_PRINT_OFFSET, OSS_PRINT_NUMBERS, OSS_PRINT_TYPE_INFO, and OSS_PRINT_COMMENTS flags are always added by default. Only the OSS_HEXBYTES, OSS_NOPRINT, OSS_PRE_2_0_COMPAT, OSS_NO_TIME_DETAILS, OSS_PRE_10_1_COMPAT, and OSS_NO_TRACE_FOR_TRUNCATED_ELEMENTS flags affect the ossPrintXPER() output.
The following table describes the available flags.
Flag | Description |
---|---|
OSS_ASN_ONLY |
Prints only decoded values, without a hex/binary representation of the encoded data and without truncated elements of SEQUENCE OF or SET OF. For example:
value Foo2 ::= { a { c TRUE } }Note that all details about the encoding are skipped. This flag does not affect the ossPrintXPER() output. |
OSS_HEXBYTES |
Prints encoded data in hex/binary format rather than pure binary format. Considering the above notation, note that this flag has no impact on the output:
value Foo2 ::= { a { --preamble: <.0> c TRUE --contents: <1> } } --PDU padding: <000000>The following example shows the impact of the flag: Foo3 ::= INTEGER value Foo3 = 100Output generated by ossPrintXPER(), when OSS_HEXBYTES is set: value Foo3 ::= 100 --length: .01 --contents: .64 and without OSS_HEXBYTES: value Foo3 ::= 100 --length: <.00000001> --contents: <.01100100>Output generated by ossPrintXPER() when the OSS_HEXBYTES flag is set: <PDU name="Foo3"> <Value> 100 <Details> <metadata type="TYPE INFORMATION">INTEGER</metadata> <metadata type="LEVEL NUMBER">1</metadata> <position offset="0,0" length="2,0"/> <encoding type="length"> .01 <description>(decoded as 1)</description> </encoding> <encoding type="contents">.64</encoding> </Details> </Value> <TotalLength bytecount="2"/> </PDU>Note that when the OSS_HEXBYTES flag is specified, full bytes are written in hex format, and leading and trailing bits are written between "<" and ">" (between "[" and "]" for ossPrintXPER). The period (".") marks the boundary between whole bytes, and the space (" ") marks the boundary between the logical parts of the data in the encoding. |
OSS_SEPARATE_ASN |
Prints an additional line after each block related to each ASN.1 value. |
OSS_NOBRACES |
Will not print braces in the description (in general, braces are printed for constructed types). If this flag is specified, the printed information will not be in valid ASN.1 value notation. This flag does not affect the ossPrintXPER() output.
For example:
value Foo2 ::= a --preamble: <.0> c TRUE --contents: <1> |
OSS_PRINT_ABSREF |
Prints the names of the fields of decoded values with the fully qualified reference (name1.name2.name3...). This flag does not affect the ossPrintXPER() output.
value Foo2 ::= { a { --FULL NAME: a --preamble: <.0> c TRUE --FULL NAME: a.c --contents: <1> } } --PDU padding: <000000> |
OSS_PRINT_OFFSET |
Prints the length and offset of the encoded data corresponding to the ASN.1 value that is decoded. Note that length is considered as unknown for constructive types (SET, SEQUENCE, CHOICE, SET OF, and SEQUENCE OF). This flag does not affect the ossPrintXPER() output. For example:
value Foo2 ::= { --OFFSET: 0,0 a { --OFFSET: 0.0 --preamble: <.0> c TRUE --OFFSET: 0,1; LENGTH: 0,1 --contents: <1> } } --PDU padding: <000000> --TOTAL LENGTH: 1,0 |
OSS_PRINT_NUMBERS |
Prints an additional structurized level number to identify each logical component part of the output. This flag does not affect the ossPrintXPER() output. For example:
value Foo2 ::= { --LEVEL NUMBER: 1 a { --LEVEL NUMBER: 1.1 --preamble: <.0> c TRUE --LEVEL NUMBER: 1.1.1 --contents: <1> } } --PDU padding: <000000> |
OSS_PRINT_TYPE_INFO |
Prints information about the ASN.1 type notation. For example:
value Foo2 ::= { --TYPE INFORMATION: SET a { --TYPE INFORMATION: SEQUENCE --preamble: <.0> c TRUE --TYPE INFORMATION: BOOLEAN --contents: <1> } } --PDU padding: <000000>The second example is based on the following ASN.1 declaration: Foo ::= SEQUENCE { a INTEGER (250..253) OPTIONAL, ..., [[ b NumericString (SIZE(3)) DEFAULT "000", c INTEGER DEFAULT 0 ]], ..., d BOOLEAN OPTIONAL } value Foo ::= { a 253, b "123", c 20000, d TRUE }value is decoded with PER ALIGNED into 8 bytes: F80805C8 D0024E20. The output generated by the ossPrintPER() is: value Foo ::= { --TYPE INFORMATION: SEQUENCE --extension flag: <.1> --preamble: <1> a 253, --TYPE INFORMATION: INTEGER (250..253) --contents: <11> d TRUE, --TYPE INFORMATION: BOOLEAN OPTIONAL --contents: <1> --extension count: <000.0000> --extension preamble: <1> --[[ --padding: <000> --extension length: <.00000101> --preamble: <.11> b "123", --TYPE INFORMATION: NumericString (SIZE(3)) DEFAULT "000" --contents: <0010 00.11 0100> c 20000 --TYPE INFORMATION: INTEGER DEFAULT 0 --padding: <00> --length: <.00000010> --contents: <.01001110 .00100000> --]] }This flag does not affect the ossPrintXPER() output. |
OSS_PRINT_COMMENTS |
Prints "useful" comments. For example:
value Foo2 ::= { a { --preamble: <.0> -bit #0 = 0: 'b' is absent c TRUE --contents: <1> } } --PDU padding: <000000>The second example is based on the following ASN.1 declaration: Foo ::= SEQUENCE { a INTEGER (250..253) OPTIONAL, ..., [[ b NumericString (SIZE(3)) DEFAULT "000", c INTEGER DEFAULT 0 ]], ..., d BOOLEAN OPTIONAL } value Foo ::= { a 253, b "123", c 20000, d TRUE }This value is decoded with PER UNALIGNED into 8 bytes: F80805C8 D0024E20. The output generated by the ossPrintPER() is: value Foo ::= { --extension flag: <.1> --preamble: <1> --bit #0 = 1: 'd' is present a 253, --contents: <11> d TRUE, --contents: <1> --extension count: <000.0000> (decoded as 1) --extension preamble: <1> --bit #0 = 1: version brackets that contain: --'b' --'c' --is present --[[ --extension length: <000.00101> (decoded as 5) --preamble: <11> --bit #0 = 1: 'b' is present --bit #1 = 1: 'c' is present b "123", --contents: <0.010 0011 0.100> c 20000 --length: <00000.010> (decoded as 2) --contents: <01001.110 00100.000> --trailing bits: <00> --]] } --PDU padding: <000>This flag does not affect the ossPrintXPER() output. |
OSS_NOPRINT |
When specified, ossPrintPER() | ossPrintXPER() will not print anything. Instead, the data will be prepared in a special format. This flag is useful when you define your own API function to print or/and analyze the encoded data. |
OSS_PRINT_XML_HEADER |
Generates the following header into the produced XML document:
<?xml version="1.0"?> <!DOCTYPE PDU SYSTEM "ossprintxper.dtd">This flag does not affect the ossPrintPER() output. |
OSS_PRE_2_0_COMPAT |
Disables the passing of post-v1.x records to the userPrintPer() callback function. If this flag is set, the behavior of ossPrintPER() is the same as that of version 1.0. In other words, this flag provides backward compatibility for applications written using the v1.0 userPrintPer() records with a version 2.0 ossPrintPER() library. NOTE: Starting with version 8.4, the flag affects TIME types as follows: the only record passed is for a TIME value with "typeId" OSS_ASN1_TYPE_PPR. The record has "timeEncId" and "decodedContent" fields. It contains the simplest record with encodedContent. For example: MIX ::= TIME ((SETTINGS "Year=Basic") | (SETTINGS "Year=Proleptic")) value MIX ::= "23:59,99999+12:59" 000.typeId: OSS_ASN1_TYPE_PPR timeEncId: OSS_TEK_NOTIME typeName: "MIX" addition->typeInformation: "TIME" addition->optional: No 001.typeId: OSS_ASN1_TYPE_PPR timeEncId: OSS_TEK_MIXED typeName: "MIX" addition->typeInformation: "TIME" addition->optional: No decodedContent: "23:59.99999+12:59" encodedContent: 78 bits numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_CONTENTS_TYPE_PPR encodedContent: 78 bits } } 002.typeId: OSS_ADDITIONS_TYPE_PPR timeEncId: OSS_TEK_NOTIME encodedContent: 2 bits numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_PDU_PADDING_TYPE_PPR encodedContent: 2 bits } } NOTE: Starting with version 8.4, the flag is effective for types with a contents constraint applied (the CONTAINING keyword is present) as follows: the only record passed is for a CONTAINING type value with "typeId" OSS_ASN1_TYPE_PPR and with "decodedContent" corresponding to the value of an OCTET/BIT STRING with CONTAINING. No records with information about the contained type value encoding are passed. T ::= BIT STRING (CONTAINING INTEGER) v T ::= CONTAINING 33 000.typeId : OSS_ASN1_TYPE_PPR decodedContent : '00000001 00100001'B typeName : "T" encodedContent : .10 ... length : 24 numberOfSimplestRecord : 2 simplestRecords : { { typeId : OSS_LENGTH_TYPE_PPR length : 8 encodedContent : .10 ... addition->comments : "(decoded as 16)" }, { typeId : OSS_CONTENTS_TYPE_PPR length : 16 encodedContent : .01 ... } } bitsPerContentUnit : 8 offset : 0 addition->typeInformation : "BIT STRING (CONTAINING ...)" |
OSS_NO_TIME_DETAILS |
Disables the passing of the inner records that corresponds to the internal structure of the TIME type defined by Amendment 2 to ITU-T Rec. X.691:2002. Only the records of OSS_TIME8601_BEGIN_PPR and OSS_TIME8601_FINISHED_PPR types are passed to the user. The decoded value ("decodedContent") and the whole TIME value encoding ("encodedContent") are passed in the OSS_TIME8601_FINISHED_PPR record. This flag is useful to reduce the number of passed records. For example: MIX ::= TIME ((SETTINGS "Year=Basic") | (SETTINGS "Year=Proleptic")) value MIX ::= "23:59,99999+12:59" 000.typeId: OSS_PDU_BEGIN_PPR timeEncId: OSS_TEK_NOTIME typeName: "MIX" 001.typeId: OSS_TIME8601_BEGIN_PPR timeEncId: OSS_TEK_NOTIME typeName: "MIX" addition->typeInformation: "TIME" addition->optional: No 002.typeId: OSS_TIME8601_FINISHED_PPR timeEncId: OSS_TEK_MIXED typeName: "MIX" addition->typeInformation: "TIME" addition->optional: No decodedContent: "23:59.99999+12:59" encodedContent: 78 bits numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_CONTENTS_TYPE_PPR encodedContent: 78 bits } } 003.typeId: OSS_ADDITIONS_TYPE_PPR timeEncId: OSS_TEK_NOTIME encodedContent: 2 bits numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_PDU_PADDING_TYPE_PPR encodedContent: 2 bits } } 004.typeId: OSS_TOTAL_LENGTH_PPR timeEncId: OSS_TEK_NOTIME 005.typeId: OSS_PDU_END_PPR timeEncId: OSS_TEK_NOTIME typeName: "MIX" |
OSS_NO_CONTAINED_TYPE |
Is used for types with a contents constraint applied. It disables the printing of contained type information. Only records of OSS_CONTAINING_TYPE_BEGIN_PPR, OSS_ASN1_TYPE_PPR, and OSS_CONTAINING_TYPE_END_PPR types are passed to the user. The decoded value ("decodedContent") and the encoding for the value of OCTET/BIT STRING with CONTAINING are passed in the OSS_ASN1_TYPE_PPR record. For example: T ::= BIT STRING (CONTAINING INTEGER) v T ::= CONTAINING 33 000.typeId : OSS_PDU_BEGIN_PPR typeName : "T" 001.typeId : OSS_CONTAINING_TYPE_BEGIN_PPR typeName : "T" 002.typeId : OSS_ASN1_TYPE_PPR possibleLast : TRUE decodedContent : '00000001 00100001'B typeName : "T" encodedContent : .10 ... length : 24 numberOfSimplestRecord : 2 simplestRecords : { { typeId : OSS_LENGTH_TYPE_PPR length : 8 encodedContent : .10 ... addition->comments : "(decoded as 16)" }, { typeId : OSS_CONTENTS_TYPE_PPR length : 16 encodedContent : .01 ... } } bitsPerContentUnit : 8 offset : 0 addition->typeInformation : "BIT STRING (CONTAINING ...)" 003.typeId : OSS_CONTAINING_TYPE_END_PPR typeName : "T" 004.typeId : OSS_TOTAL_LENGTH_PPR length : 3 005.typeId : OSS_PDU_END_PPR typeName : "T" |
OSS_NO_CONTAINED_TYPE_TRACE |
Is used for types with a contents constraint applied. It disables the printing of comments with trace data for a contained type encoded by any non-PER rule. This flag affects only the output of the ossPrintPER() and ossPrintXPER() functions and does not affect records passed to the user.cer OBJECT IDENTIFIER ::= {joint-iso-itu-t(2) asn1(1) ber-derived(2) canonical-encoding(0)} T ::= BIT STRING (CONTAINING INTEGER ENCODED BY cer) v T ::= CONTAINING 33The ossPrintPER() output without the OSS_NO_CONTAINED_TYPE_TRACE flag: value T ::= '00000010 00000001 00100001'B --TYPE INFORMATION: BIT STRING (CONTAINING ... ENCODED BY CER) --LEVEL NUMBER: 1 --OFFSET: 0,0; LENGTH: 4,0 --length: .18 (decoded as 24) --contents: .02.01.21 /* INTEGER: tag = [UNIVERSAL 2] primitive; length = 1 33 */ --TOTAL LENGTH: 4,0Output with the OSS_NO_CONTAINED_TYPE_TRACE flag set: value T ::= '00000010 00000001 00100001'B --TYPE INFORMATION: BIT STRING (CONTAINING ... ENCODED BY CER) --LEVEL NUMBER: 1 --OFFSET: 0,0; LENGTH: 4,0 --length: .18 (decoded as 24) --contents: .02.01.21 --TOTAL LENGTH: 4,0 |
OSS_NO_TRACE_FOR_TRUNCATED_ELEMENTS |
Is used for SEQUENCE OF and SET OF types with the OSS.Truncate directive applied. If the flag is set, the records for each of the truncated elements are not passed to the user, and only records of OSS_START_TRUNCATED_ELEMENTS_TRACE_PPR and OSS_END_TRUNCATED_ELEMENTS_TRACE_PPR types are passed. Additionally, the information about the truncated elements is not printed by ossPrintPER() and ossPrintXPER(). |
OSS_PRE_10_1_COMPAT |
Disables the passing of post-v10.x records to the "userPrintPer()" callback function. If this flag is set, the behavior of ossPrintPER() is the same as in previous versions: the truncated elements are processed and not skipped. In other words, this flag provides backward compatibility for applications written using the v8.4 "userPrintPer()" records with a version 10.1 ossPrintPER() library. |
The ossPrintPER() | ossPrintXPER() function allows you to access the formatted data that is received after decoding, so you can format and print the data by providing your own API. This is especially useful when analyzing the PER encoding for any purposes.
The "userPrintPer" argument pertaining to the ossPrintPER() | ossPrintXPER() function is a pointer to your function of the following type:
typedef ossBoolean (DLL_ENTRY_FPTR *_System UserPrintPer) (struct ossGlobal *world, PrintPerRecord *data);
world is an argument that is common to all API functions.
data is a pointer to the PrintPerRecord structure that contains the data provided by ossPrintPER() | ossPrintXPER(). The structure corresponds to a logical part of encoded data.
Your function is called for every PrintPerRecord filled by ossPrintPER() | ossPrintXPER(). If you want to print the record by ossPrintPER() | ossPrintXPER(), it returns FALSE; otherwise, it returns TRUE.
To better understand the format of the "data" that the ossPrintPER() | ossPrintXPER() function generates, think of it as a tree. Each leaf corresponds to a few bits in the encoding. It defines a place where the bits are stored, as well as the significance of the bits. Other elements of the tree correspond to the decoded ASN.1 values.
In C, the PrintPerRecord structure is defined by the following:
struct PrintPerRecord { unsigned char typeId; /* identifies a significance of the present record */ ossBoolean possibleLast; /* used only when typeId = OSS_ASN1_TYPE TRUE, if there are any chances that this one is last element of the set/sequence */ void *decodedContent; /* points to the decoded content in "displayed" format */ char *typeName; /* points to the name of corresponding ASN.1 type */ char *fieldName; /* ... ASN.1 name */ char *qualifiedName; /* name1.name2...nameN.fieldName */ char *qualifiedNameOfTopRecord; /* name1.name2...nameN */ char *qualifiedNumber; /* for example, 1.2.1.3 */ char *qualifiedNumberOfTopRecord; /* for example, 1.2.1 */ unsigned int depth; unsigned char *encodedContent; /* this pointer defines a first byte of encoding; */ unsigned char encodedBitOffset; /* defines a first bit of encoding*/ unsigned long length; /* length (in bits) */ unsigned int numberOfSimplestRecord; /* number of simplestRecords */ struct PrintPerSimplestRecord *simplestRecords; /* array of pointers to logical parts */ unsigned char bitsPerContentUnit; /* usually - 8, but could be differ for strings with constraints specified*/ unsigned int offset; /* offset from a start of encoded data */ ossBoolean allocMem; /* TRUE if decodedContent points to * allocated memory*/ struct PrintPerRecordAddition *addition; unsigned char timeEncId; /* TIME type kind, added in version 8.4 */ }; struct PrintPerSimplestRecord { /* a significance of fields is same as */ /* in the PrintPerRecord-structure */ unsigned char typeId; unsigned long length; unsigned char *encodedContent; unsigned char encodedBitOffset; struct PrintPerSimplestRecordAddition *addition; }; struct PrintPerSimplestRecordAddition { char *comments; ossBoolean commentsAllocMem; unsigned char *reserved; }; struct PrintPerRecordAddition { char *typeInformation; struct PrintPerRecord *top_level_record; ossBoolean optional; void *internal_ptr; unsigned char *reserved; };
Each record corresponds either to a decoded ASN.1 value, or to any logical part of encoded data, which is a set of bits with certain significance in PER encoding. Generally, PrintPerRecord contains a reference to decoded data. The references to encoded data are contained in the array of SimplestPerRecord.
Type | Description |
---|---|
OSS_ASN1_TYPE |
The record corresponds to the ASN.1 value. |
OSS_CHOICE_BEGIN |
The record corresponds to CHOICE values. |
OSS_SEQ_SET_BEGIN |
The record corresponds to SET or SEQUENCE values. |
OSS_CHOICE_FINISHED |
|
OSS_SEQ_SET_FINISHED |
Indicates that the decoding of CHOICE, SEQUENCE, or SET is finished. |
OSS_VERSION_BRACKETS_BEGIN |
|
OSS_VERSION_BRACKETS_FINISHED |
Indicates that the version brackets started and ended. It is useful when using PDUs that contain version brackets. |
OSS_VERSION_BRACKETS_FINISHED |
Indicates that the version brackets started and ended. It is useful when using PDUs that contain version brackets. |
OSS_ADDITIONS_TYPE |
This record does not contain useful information; however it contains "simplest" records that correspond to certain bits in encoding. |
All the other types identify a PER-specific part of the encoding. This group contains "low"-level references to the PER-encoding. The typeId of a SimplestPerRecord has one of the following types:
OSS_CONTENTS_TYPE OSS_LENGTH_TYPE OSS_PADDING_TYPE OSS_EXTENSION_LENGTH_TYPE OSS_EXTENSION_RANGE_TYPE OSS_CHOICE_INDEX OSS_EXTENSION_CHOICE OSS_PDU_PADDING_TYPE OSS_REALINF_TYPE OSS_EXPLENGTH_TYPE OSS_EXP_TYPE OSS_MANTISSA_TYPE OSS_UNKNOWN_EXTENSION OSS_LENGTH_LEADING_BIT OSS_EXTENSION_FLAG_TYPE OSS_EXTENSION_COUNT_TYPE OSS_EXTENSION_PREAMBLE_TYPE OSS_PREAMBLE_TYPE
The following new types of records are added in version 2.0:
OSS_PDU_BEGIN OSS_PDU_END OSS_EXTENSION_BEGIN OSS_EXTENSION_FINISHED OSS_EXTENSIONS_BEGIN OSS_EXTENSIONS_FINISHED OSS_TOTAL_LENGTH
Note that if the OSS_PRE_2_0_COMPAT flag is set, the new types of records are not passed to the user. This flag does not affect the format of generated output.
The following new types of records have been added in version 8.4:
Type | Description |
---|---|
OSS_TIME8601_BEGIN_PPR |
The record corresponds to TIME values, does not contain "simplest" records and useful information about its type. It indicates that the decoding of TIME value has started. |
OSS_TIME8601_FINISHED_PPR |
It indicates that decoding of TIME values has finished. The record contains timeEncId and decodedContent fields. It may contain "simplest" records with encodedContent, if OSS_NO_TIME_DETAILS flag is set. |
OSS_CONTAINING_TYPE_BEGIN_PPR, |
The records correspond to the value of a type with a contents constraint applied. They do not contain "simplestRecords" or other useful information about theirtype. They indicate that the decoding of a CONTAINING type value has started (OSS_CONTAINING_TYPE_BEGIN_PPR) or has finished (OSS_CONTAINING_TYPE_END_PPR). |
The following new types of records have been added in version 10.1:
Type | Description |
---|---|
OSS_START_TRUNCATED_ELEMENTS_TRACE_PPR |
The records correspond to the value of a SEQUENCE OF or SET OF type with the OSS.Truncate directive applied; they do not contain "simplestRecords" or other useful information about their type. They indicate that the truncation of elements has started. Note that all records generated for truncated elements are passed to the user if the new OSS_NO_TRACE_FOR_TRUNCATED_ELEMENTS flag is not set. Records of the truncated elements do not change; however, the corresponding values are printed as ASN.1 comments. |
OSS_END_TRUNCATED_ELEMENTS_TRACE_PPR |
The records correspond to the value of a SEQUENCE OF or SET OF type with the OSS.Truncate directive applied; they do not contain "simplestRecords". They indicate that truncation of elements has finished; the value of the length field contains the number of skipped elements. Note that if the OSS_PRE_10_1_COMPAT flag is set, the new types of records are not passed to the user. |
OSS_ASN1_TYPE, OSS_CHOICE_BEGIN or OSS_SEQ_SET_BEGIN.If the ASN.1 value that corresponds to this record is contained in any constructed type (SEQUENCE, SET, CHOICE, SET OF, SEQUENCE OF), possibleLast is TRUE if the ASN.1 value is the "last" field; otherwise, it is FALSE.
struct PrintPerRecordAddition { char *typeInformation; struct PrintPerRecord *top_level_record; ossBoolean optional; void *internal_ptr; unsigned char *reserved; };This pointer is NULL except when the OSS_PRINT_TYPE_INFO flag is specified. Note that the structure is used only for records where typeId is equal to OSS_ASN1_TYPE. The fields of this structure are:
The TIME types corresponding to named ASN.1 types of ITU-T Rec. X.691:2002 | ISO/IEC 8825-2:2002 are:
OSS_TEK_CENTURY OSS_TEK_ANY_CENTURY OSS_TEK_YEAR OSS_TEK_ANY_YEAR OSS_TEK_YEAR_MONT0048 OSS_TEK_ANY_YEAR_MONTH OSS_TEK_DATE OSS_TEK_ANY_DATE OSS_TEK_YEAR_DAY OSS_TEK_ANY_YEAR_DAY OSS_TEK_YEAR_WEEK OSS_TEK_ANY_YEAR_WEEK OSS_TEK_YEAR_WEEK_DAY OSS_TEK_ANY_YEAR_WEEK_DAY OSS_TEK_HOURS OSS_TEK_HOURS_UTC OSS_TEK_HOURS_AND_DIFF OSS_TEK_MINUTES OSS_TEK_MINUTES_UTC OSS_TEK_MINUTES_AND_DIFF OSS_TEK_TIME_OF_DAY OSS_TEK_TIME_OF_DAY_UTC OSS_TEK_TIME_OF_DAY_AND_DIFF OSS_TEK_HOURS_AND_FRACTION OSS_TEK_HOURS_UTC_AND_FRACTION OSS_TEK_HOURS_AND_DIFF_AND_FRACTION OSS_TEK_MINUTES_AND_FRACTION OSS_TEK_MINUTES_UTC_AND_FRACTION OSS_TEK_MINUTES_AND_DIFF_AND_FRACTION OSS_TEK_TIME_OF_DAY_AND_FRACTION OSS_TEK_TIME_OF_DAY_UTC_AND_FRACTION OSS_TEK_TIME_OF_DAY_AND_DIFF_AND_FRACTION OSS_TEK_DATE_TIME OSS_TEK_START_END_DATE_INTERVAL OSS_TEK_START_END_TIME_INTERVAL OSS_TEK_START_END_DATE_TIME_INTERVAL OSS_TEK_DURATION_INTERVAL OSS_TEK_START_DATE_DURATION_INTERVAL OSS_TEK_START_TIME_DURATION_INTERVAL OSS_TEK_START_DATE_TIME_DURATION_INTERVAL OSS_TEK_DURATION_END_DATE_INTERVAL OSS_TEK_DURATION_END_TIME_INTERVAL OSS_TEK_DURATION_END_DATE_TIME_INTERVAL OSS_TEK_REC_START_END_DATE_INTERVAL OSS_TEK_REC_START_END_TIME_INTERVAL OSS_TEK_REC_START_END_DATE_TIME_INTERVAL OSS_TEK_REC_DURATION_INTERVAL OSS_TEK_REC_START_DATE_DURATION_INTERVAL OSS_TEK_REC_START_TIME_DURATION_INTERVAL OSS_TEK_REC_START_DATE_TIME_DURATION_INTERVAL OSS_TEK_REC_DURATION_END_DATE_INTERVAL OSS_TEK_REC_DURATION_END_TIME_INTERVAL OSS_TEK_REC_DURATION_END_DATE_TIME_INTERVAL
The TIME types for unnamed ASN.1 types of ITU-T Rec. X.691:2002 | ISO/IEC 8825-2:2002 are:
OSS_TEK_MIXED OSS_TEK_INTEGER OSS_TEK_ENUMERATED OSS_TEK_FRACTIONAL_TIME OSS_TEK_FRACTIONAL_PART OSS_TEK_DATE_TYPE OSS_TEK_TIME_TYPE OSS_TEK_TIME_TYPE_TIME OSS_TEK_TIME_DIFFERENCE
Given the following ASN.1 type and value definition:
Foo ::= SEQUENCE { a INTEGER (250..253) OPTIONAL, ..., b NumericString (SIZE(3)), ..., c BOOLEAN OPTIONAL } value Foo ::= { a 253, b "123" }
"value" is encoded in PER Aligned (shown in hexadecimal): D8080223 40.
If you provide your own function, it is called by turns, with the following records as arguments:
0. typeId: OSS_PDU_BEGIN possibleLast: - decodedContent: - typeName: "Foo" fieldName: - qualifiedName: - qualifiedNameOfTopRecord: - qualifiedNumber: - qualifiedNumberOfTopRecord: - depth: 0 encodedContent: - encodedBitOffset: - length: - numberOfSimplestRecord: - simplestRecords: - bitsPerContentUnit: - offset: - 1. typeId: OSS_SEQ_SET_BEGIN possibleLast: TRUE decodedContent: NULL typeName: "Foo" fieldName: "value" qualifiedName: "value" qualifiedNameOfTopRecord: NULL qualifiedNumber: "1" qualifiedNumberOfTopRecord: NULL depth: 0 (1, for XPER) encodedContent: [0] encodedBitOffset: 0 length: -1 (unknown) numberOfSimplestRecord: 2 simplestRecords: { { typeId: OSS_EXTENSION_FLAG_TYPE length: 1 encodedContent: [0] encodedBitOffset: 0 }, { typeId: OSS_PREAMBLE_TYPE, length: 2 encodedContent: [0] encodedBitOffset: 1 } } bitsPerContentUnit: 8 offset: 0 2. typeId: OSS_ASN1_TYPE possibleLast: TRUE decodedContent: "253" typeName: "INTEGER" fieldName: "a" qualifiedName: "value.a" qualifiedNameOfTopRecord: "value" qualifiedNumber: "1.1" qualifiedNumberOfTopRecord: "1" depth: 1 (2, for XPER) encodedContent: [0] encodedBitOffset: 3 length: 2 numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_CONTENTS_TYPE, length: 2 encodedContent: [0] encodedBitOffset: 3 } } bitsPerContentUnit: 8 offset: 3 2a. typeId: OSS_EXTENSIONS_BEGIN possibleLast: - decodedContent: - typeName: - fieldName: - qualifiedName: - qualifiedNameOfTopRecord: - qualifiedNumber: - qualifiedNumberOfTopRecord: - depth: 1 (2, for XPER) encodedContent: - encodedBitOffset: - length: - numberOfSimplestRecord: - simplestRecords: - bitsPerContentUnit: - offset: - 3. typeId: OSS_ADDITIONS_TYPE possibleLast: - decodedContent: - typeName: - fieldName: - qualifiedName: - qualifiedNameOfTopRecord: "value" qualifiedNumber: "1.2" qualifiedNumberOfTopRecord: "1" depth: 1 (3, for XPER) encodedContent: [0] encodedBitOffset: 5 length: 8 numberOfSimplestRecord: 2 simplestRecords: { { typeId: OSS_EXTENSION_COUNT_TYPE length: 7 encodedContent: [0] encodedBitOffset: 5 }, { typeId: OSS_EXTENSION_PREAMBLE_TYPE length: 1 encodedContent: [1] encodedBitOffset: 4 } } bitsPerContentUnit: 8 offset: 5 3a. typeId: OSS_EXTENSION_BEGIN possibleLast: - decodedContent: - typeName: - fieldName: - qualifiedName: - qualifiedNameOfTopRecord: - qualifiedNumber: - qualifiedNumberOfTopRecord: - depth: 1 (3, for XPER) encodedContent: - encodedBitOffset: - length: - numberOfSimplestRecord: - simplestRecords: - bitsPerContentUnit: - offset: - 4. typeId: OSS_ADDITIONS_TYPE decodedContent: - typeName: - fieldName: - qualifiedName: - qualifiedNameOfTopRecord: "value" qualifiedNumber: "1.3" qualifiedNumberOfTopRecord: "1" depth: 1 (4, for XPER) encodedContent: [1] encodedBitOffset: 5 length: 13 numberOfSimplestRecord: 2 simplestRecords: { { typeId: OSS_PADDING_TYPE length: 3 encodedContent: [1] encodedBitOffset: 5 }, { typeId: OSS_EXTENSION_LENGTH length: 8 encodedContent: [2] encodedBitOffset: 0 } } bitsPerContentUnit: 8 offset: 13 5. typeId: OSS_ASN1_TYPE possibleLast: TRUE decodedContent: "123" typeName: "NumericString" fieldName: "b" qualifiedName: "value.b" qualifiedNameOfTopRecord: "value" qualifiedNumber: "1.4" qualifiedNumberOfTopRecord: "1" depth: 1 (4, for XPER) encodedContent: [3] encodedBitOffset: 0 length: 12 numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_CONTENT_TYPE length: 12 encodedContent: [3] encodedBitOffset: 0 } } bitsPerContentUnit: 4 offset: 24 5a. typeId: OSS_EXTENSION_FINISHED possibleLast: - decodedContent: - typeName: - fieldName: - qualifiedName: - qualifiedNameOfTopRecord: - qualifiedNumber: - qualifiedNumberOfTopRecord: - depth: 1 (3, for XPER) encodedContent: - encodedBitOffset: - length: - numberOfSimplestRecord: - simplestRecords: - bitsPerContentUnit: - offset: - 5b. typeId: OSS_EXTENSIONS_FINISHED possibleLast: - decodedContent: - typeName: - fieldName: - qualifiedName: - qualifiedNameOfTopRecord: - qualifiedNumber: - qualifiedNumberOfTopRecord: - depth: 1 (2, for XPER) encodedContent: - encodedBitOffset: - length: - numberOfSimplestRecord: - simplestRecords: - bitsPerContentUnit: - offset: - 6. typeId: OSS_SEQ_SET_FINISHED decodedContent: - typeName: - fieldName: - qualifiedName: - qualifiedNameOfTopRecord: - qualifiedNumber: - qualifiedNumberOfTopRecord: - depth: 0 (1, for XPER) encodedContent: - encodedBitOffset: - length: - numberOfSimplestRecord: - simplestRecords: - bitsPerContentUnit: - offset: - 7. typeId: OSS_ADDITIONS_TYPE decodedContent: - typeName: - fieldName: - qualifiedName: - qualifiedNameOfTopRecord: "value" qualifiedNumber: "1.5" qualifiedNumberOfTopRecord: "1" depth: 0 (1, for XPER) encodedContent: [4] encodedBitOffset: 4 length: 4 numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_PADDING_TYPE length: 4 encodedContent: [4] encodedBitOffset: 4 } } bitsPerContentUnit: 8 offset: 36 7a. typeId: OSS_TOTAL_LENGTH possibleLast: - decodedContent: - typeName: - fieldName: - qualifiedName: - qualifiedNameOfTopRecord: - qualifiedNumber: - qualifiedNumberOfTopRecord: - depth: 0 (1, for XPER) encodedContent: - encodedBitOffset: - length: 5 numberOfSimplestRecord: - simplestRecords: - bitsPerContentUnit: - offset: - 7b. typeId: OSS_PDU_END_TYPE possibleLast: - decodedContent: - typeName: - fieldName: - qualifiedName: - qualifiedNameOfTopRecord: - qualifiedNumber: - qualifiedNumberOfTopRecord: - depth: 0 encodedContent: - encodedBitOffset: - length: - numberOfSimplestRecord: - simplestRecords: - bitsPerContentUnit: - offset: -
Given the following ASN.1 type and value definition:
MIX ::= TIME ((SETTINGS "Year=Basic") | (SETTINGS "Year=Proleptic")) value MIX ::= "23:59,99999+12:59"
"value" is encoded in PER Aligned as (shown in hexadecimal): 700104BF 70030186 9FB3A0.
If you provide your own function, it is called by turns with the following records as arguments:
000.typeId: OSS_PDU_BEGIN_PPR timeEncId: OSS_TEK_NOTIME typeName: "MIX" 001.typeId: OSS_TIME8601_BEGIN_PPR timeEncId: OSS_TEK_NOTIME typeName: "MIX" addition->typeInformation: "TIME" addition->optional: No 002.typeId: OSS_CHOICE_BEGIN_PPR timeEncId: OSS_TEK_MIXED typeName: "MIX" addition->typeInformation: ""MIXED-ENCODING" CHOICE" addition->optional: No encodedContent: 6 bits numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_CHOICE_INDEX_PPR comments: "(index = 28)" encodedContent: 6 bits } } 003.typeId: OSS_SEQ_SET_BEGIN_PPR timeEncId: OSS_TEK_FRACTIONAL_TIME fieldName: "row-29" addition->typeInformation: ""FRACTIONAL-TIME" SEQUENCE" addition->optional: No 004.typeId: OSS_ASN1_TYPE_PPR timeEncId: OSS_TEK_INTEGER fieldName: "number-of-digits" addition->typeInformation: "INTEGER (1..MAX)" addition->optional: No decodedContent: 5 encodedContent: 16 bits numberOfSimplestRecord: 2 simplestRecords: { { typeId: OSS_LENGTH_TYPE_PPR comments: "(decoded as 1)" encodedContent: 8 bits }, { typeId: OSS_CONTENTS_TYPE_PPR encodedContent: 8 bits } } 005.typeId: OSS_SEQ_SET_BEGIN_PPR timeEncId: OSS_TEK_MINUTES_AND_DIFF_AND_FRACTION fieldName: "time-value" addition->typeInformation: ""MINUTES-AND-DIFF-AND-FRACTION-ENCODING" SEQUENCE addition->optional: No 006.typeId: OSS_SEQ_SET_BEGIN_PPR timeEncId: OSS_TEK_MINUTES_AND_FRACTION fieldName: "local-time" addition->typeInformation: "SEQUENCE" addition->optional: No 007.typeId: OSS_ASN1_TYPE_PPR timeEncId: OSS_TEK_INTEGER fieldName: "hours" addition->typeInformation: "INTEGER (0..24)" addition->optional: No decodedContent: 23 encodedContent: 5 bits numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_CONTENTS_TYPE_PPR encodedContent: 5 bits } } 008.typeId: OSS_ASN1_TYPE_PPR timeEncId: OSS_TEK_INTEGER fieldName: "minutes" addition->typeInformation: "INTEGER (0..59)" addition->optional: No decodedContent: 59 encodedContent: 6 bits numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_CONTENTS_TYPE_PPR encodedContent: 6 bits } } 009.typeId: OSS_ASN1_TYPE_PPR timeEncId: OSS_TEK_INTEGER fieldName: "fraction" addition->typeInformation: "INTEGER (0..999, ..., 1000..MAX)" addition->optional: No decodedContent: 99999 encodedContent: 33 bits numberOfSimplestRecord: 3 simplestRecords: { { typeId: OSS_EXTENSION_RANGE_TYPE_PPR encodedContent: 1 bits }, { typeId: OSS_LENGTH_TYPE_PPR comments: "(decoded as 3)" encodedContent: 8 bits }, { typeId: OSS_CONTENTS_TYPE_PPR encodedContent: 24 bits } } 010.typeId: OSS_SEQ_SET_FINISHED_PPR timeEncId: OSS_TEK_MINUTES_AND_FRACTION fieldName: "fraction" 011.typeId: OSS_SEQ_SET_BEGIN_PPR timeEncId: OSS_TEK_TIME_DIFFERENCE fieldName: "time-difference" addition->typeInformation: ""TIME-DIFFERENCE" SEQUENCE" addition->optional: No encodedContent: 1 bits numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_PREAMBLE_TYPE_PPR comments: "--bit #0 = 1: 'minutes' is present" encodedContent: 1 bits } } 012.typeId: OSS_ASN1_TYPE_PPR timeEncId: OSS_TEK_ENUMERATED fieldName: "sign" addition->typeInformation: "ENUMERATED" addition->optional: No decodedContent: positive encodedContent: 1 bits numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_CONTENTS_TYPE_PPR encodedContent: 1 bits } } 013.typeId: OSS_ASN1_TYPE_PPR timeEncId: OSS_TEK_INTEGER fieldName: "hours" addition->typeInformation: "INTEGER (0..15)" addition->optional: No decodedContent: 12 encodedContent: 4 bits numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_CONTENTS_TYPE_PPR encodedContent: 4 bits } } 014.typeId: OSS_ASN1_TYPE_PPR timeEncId: OSS_TEK_INTEGER fieldName: "minutes" addition->typeInformation: "INTEGER (1..59) OPTIONAL" addition->optional: Yes decodedContent: 59 encodedContent: 6 bits numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_CONTENTS_TYPE_PPR encodedContent: 6 bits } } 015.typeId: OSS_SEQ_SET_FINISHED_PPR timeEncId: OSS_TEK_TIME_DIFFERENCE fieldName: "time-difference" 016.typeId: OSS_SEQ_SET_FINISHED_PPR timeEncId: OSS_TEK_MINUTES_AND_DIFF_AND_FRACTION fieldName: "time-value" 017.typeId: OSS_SEQ_SET_FINISHED_PPR timeEncId: OSS_TEK_FRACTIONAL_TIME fieldName: "row-29" 018.typeId: OSS_CHOICE_FINISHED_PPR timeEncId: OSS_TEK_MIXED typeName: "MIX" 019.typeId: OSS_TIME8601_FINISHED_PPR timeEncId: OSS_TEK_MIXED typeName: "MIX" decodedContent: "23:59.99999+12:59" 020.typeId: OSS_ADDITIONS_TYPE_PPR timeEncId: OSS_TEK_NOTIME encodedContent: 2 bits numberOfSimplestRecord: 1 simplestRecords: { { typeId: OSS_PDU_PADDING_TYPE_PPR encodedContent: 2 bits } } 021.typeId: OSS_TOTAL_LENGTH_PPR timeEncId: OSS_TEK_NOTIME 022.typeId: OSS_PDU_END_PPR timeEncId: OSS_TEK_NOTIME typeName: "MIX" ossPrintPER output: value MIX ::= --TYPE INFORMATION: TIME --LEVEL NUMBER: 1 --value MIX ::= --TYPE INFORMATION: "MIXED-ENCODING" CHOICE --LEVEL NUMBER: 1 --OFFSET: 0,0 --choice index: <.011100> (index = 28) --row-29 : --{ --TYPE INFORMATION: "FRACTIONAL-TIME" SEQUENCE --LEVEL NUMBER: 1.1 --OFFSET: 0,6 --number-of-digits 5, --TYPE INFORMATION: INTEGER (1..MAX) --LEVEL NUMBER: 1.1.1 --OFFSET: 0,6; LENGTH: 2,2 --padding: <00> --length: .01 (decoded as 1) --contents: .04 --time-value --{ --TYPE INFORMATION: "MINUTES-AND-DIFF-AND-FRACTION-ENCODING" SEQUENCE --LEVEL NUMBER: 1.1.2 --OFFSET: 3,0 --local-time --{ --TYPE INFORMATION: SEQUENCE --LEVEL NUMBER: 1.1.2.1 --OFFSET: 3,0 --hours 23, --TYPE INFORMATION: INTEGER (0..24) --LEVEL NUMBER: 1.1.2.1.1 --OFFSET: 3,0; LENGTH: 0,5 --contents: <.10111> --minutes 59, --TYPE INFORMATION: INTEGER (0..59) --LEVEL NUMBER: 1.1.2.1.2 --OFFSET: 3,5; LENGTH: 0,6 --contents: <111.011> --fraction 99999 --TYPE INFORMATION: INTEGER (0..999, ..., 1000..MAX) --LEVEL NUMBER: 1.1.2.1.3 --OFFSET: 4,3; LENGTH: 4,5 --extension range: <1> --padding: <0000> --length: .03 (decoded as 3) --contents: .01.86.9F --}, --time-difference --{ --TYPE INFORMATION: "TIME-DIFFERENCE" SEQUENCE --LEVEL NUMBER: 1.1.2.2 --OFFSET: 9,0 --preamble: <.1> --bit #0 = 1: 'minutes' is present --sign positive, --TYPE INFORMATION: ENUMERATED --LEVEL NUMBER: 1.1.2.2.1 --OFFSET: 9,1; LENGTH: 0,1 --contents: <0> --hours 12, --TYPE INFORMATION: INTEGER (0..15) --LEVEL NUMBER: 1.1.2.2.2 --OFFSET: 9,2; LENGTH: 0,4 --contents: <1100> --minutes 59 --TYPE INFORMATION: INTEGER (1..59) OPTIONAL --LEVEL NUMBER: 1.1.2.2.3 --OFFSET: 9,6; LENGTH: 0,6 --contents: <11.1010> --} --} --} "23:59.99999+12:59" --PDU padding: <0000> --TOTAL LENGTH: 11,0
ossPrintXPER output:
<PDU name="MIX"> <Value type="time"> <Details> <metadata type="TYPE INFORMATION">TIME</metadata> <metadata type="LEVEL NUMBER">1</metadata> </Details> <Value type="choice"> <Details> <metadata type="TYPE INFORMATION">"MIXED-ENCODING" CHOICE</metadata> <metadata type="LEVEL NUMBER">1</metadata> <position offset="0,0"/> <encoding type="choice index"> [.011100] <description>(index = 28)</description> </encoding> </Details> <Field name="row-29"> <Value type="seqset"> <Details> <metadata type="TYPE INFORMATION">"FRACTIONAL-TIME" SEQUENCE</metadata> <metadata type="FULL NAME">row-29</metadata> <metadata type="LEVEL NUMBER">1.1</metadata> <position offset="0,6"/> </Details> <Field name="number-of-digits"> <Value> 5 <Details> <metadata type="TYPE INFORMATION">INTEGER (1..MAX)</metadata> <metadata type="FULL NAME">row-29.number-of-digits</metadata> <metadata type="LEVEL NUMBER">1.1.1</metadata> <position offset="0,6" length="2,2"/> <encoding type="padding">[00]</encoding> <encoding type="length"> .01 <description>(decoded as 1)</description> </encoding> <encoding type="contents">.04</encoding> </Details> </Value> </Field> <Field name="time-value"> <Value type="seqset"> <Details> <metadata type="TYPE INFORMATION">"MINUTES-AND-DIFF-AND- FRACTION-ENCODING" SEQUENCE</metadata> <metadata type="FULL NAME">row-29.time-value</metadata> <metadata type="LEVEL NUMBER">1.1.2</metadata> <position offset="3,0"/> </Details> <Field name="local-time"> <Value type="seqset"> <Details> <metadata type="TYPE INFORMATION">SEQUENCE</metadata> <metadata type="FULL NAME">row-29.time-value.local- time</metadata> <metadata type="LEVEL NUMBER">1.1.2.1</metadata> <position offset="3,0"/> </Details> <Field name="hours"> <Value> 23 <Details> <metadata type="TYPE INFORMATION">INTEGER (0..24)</metadata> <metadata type="FULL NAME">row-29.time-value.local- time.hours</metadata> <metadata type="LEVEL NUMBER">1.1.2.1.1</metadata> <position offset="3,0" length="0,5"/> <encoding type="contents">[.10111]</encoding> </Details> </Value> </Field> <Field name="minutes"> <Value> 59 <Details> <metadata type="TYPE INFORMATION">INTEGER (0..59)</metadata> <metadata type="FULL NAME">row-29.time-value.local- time.minutes</metadata> <metadata type="LEVEL NUMBER">1.1.2.1.2</metadata> <position offset="3,5" length="0,6"/> <encoding type="contents">[111.011]</encoding> </Details> </Value> </Field> <Field name="fraction"> <Value> 99999 <Details> <metadata type="TYPE INFORMATION">INTEGER (0..999, ...,1000..MAX)</metadata> <metadata type="FULL NAME">row-29.time-value.local- time.fraction</metadata> <metadata type="LEVEL NUMBER">1.1.2.1.3</metadata> <position offset="4,3" length="4,5"/> <encoding type="extension range">[1]</encoding> <encoding type="padding">[0000]</encoding> <encoding type="length"> .03 <description>(decoded as 3)</description> </encoding> <encoding type="contents">.01.86.9F</encoding> </Details> </Value> </Field> </Value> </Field> <Field name="time-difference"> <Value type="seqset"> <Details> <metadata type="TYPE INFORMATION">"TIME-DIFFERENCE" SEQUENCE</metadata> <metadata type="FULL NAME">row-29.time-value.time- difference</metadata> <metadata type="LEVEL NUMBER">1.1.2.2</metadata> <position offset="9,0"/> <encoding type="preamble"> [.1] <description>bit #0 = 1: 'minutes' is present</description> </encoding> </Details> <Field name="sign"> <Value> positive <Details> <metadata type="TYPE INFORMATION">ENUMERATED</metadata> <metadata type="FULL NAME">row-29.time-value.time- difference.sign</metadata> <metadata type="LEVEL NUMBER">1.1.2.2.1</metadata> <position offset="9,1" length="0,1"/> <encoding type="contents">[0]</encoding> </Details> </Value> </Field> <Field name="hours"> <Value> 12 <Details> <metadata type="TYPE INFORMATION">INTEGER (0..15)</metadata> <metadata type="FULL NAME">row-29.time-value.time- difference.hours</metadata> <metadata type="LEVEL NUMBER">1.1.2.2.2</metadata> <position offset="9,2" length="0,4"/> <encoding type="contents">[1100]</encoding> </Details> </Value> </Field> <Field name="minutes"> <Value> 59 <Details> <metadata type="TYPE INFORMATION">INTEGER (1..59) OPTIONAL</metadata> <metadata type="FULL NAME">row-29.time-value.time- difference.minutes</metadata> <metadata type="LEVEL NUMBER">1.1.2.2.3</metadata> <position offset="9,6" length="0,6"/> <encoding type="contents">[11.1010]</encoding> </Details> </Value> </Field> </Value> </Field> </Value> </Field> </Value> </Field> </Value> "23:59.99999+12:59" </Value> <encoding type="PDU padding">[0000]</encoding> <TotalLength bytecount="11"/> </PDU>
The following example uses a type with a contents constraint applied. Note that if a record with information about a contained type value is present, the "decodedContent" for the value of a containing type is NULL, if no information about the contained type value is passed to the user, then "decodedContent" contains the decoded value of an OCTET or BIT STRING with CONTAINING.
enc-CER OBJECT IDENTIFIER ::= {joint-iso-itu-t(2) asn1(1) ber-derived(2) canonical-encoding(0)} enc-PER-Aligned OBJECT IDENTIFIER ::= {joint-iso-itu-t(2) asn1(1) packed-encoding(3) basic(0) aligned(0)} enc-PER-Unaligned OBJECT IDENTIFIER ::= {joint-iso-itu-t(2) asn1(1) packed-encoding(3) basic(0) unaligned(1)} T ::= [1] BIT STRING ( CONTAINING BIT STRING ( CONTAINING BIT STRING ( CONTAINING BIT STRING ( CONTAINING BIT STRING ( CONTAINING PrintableString --<UNBOUNDED>-- ENCODED BY enc-PER-Unaligned ) ENCODED BY enc-PER-Aligned ) ENCODED BY enc-CER ) ENCODED BY enc-PER-Unaligned ) ENCODED BY enc-PER-Aligned ) v T ::= CONTAINING CONTAINING CONTAINING CONTAINING CONTAINING "AaBbC"
The value "value" is encoded in PER Aligned as (shown in hexadecimal): 60585003 08052B05 83861628 60.
If you provide your own function, it will be called by turns with the following records as an argument:
000.typeId : OSS_PDU_BEGIN_PPR typeName : "T" 001.typeId : OSS_CONTAINING_TYPE_BEGIN_PPR typeName : "T" 002.typeId : OSS_ASN1_TYPE_PPR decodedContent : - typeName : "T" qualifiedNumber : "1" depth : 0 encodedContent : .60 ... length : 104 numberOfSimplestRecord : 2 simplestRecords : { { typeId : OSS_LENGTH_TYPE_PPR length : 8 encodedContent : .60 ... addition->comments : "(decoded as 96)" }, { typeId : OSS_CONTENTS_TYPE_PPR length : 96 encodedContent : .58 ... } } bitsPerContentUnit : 8 offset : 0 addition->typeInformation : "BIT STRING (CONTAINING ... ENCODED BY PER_ALIGNED)" 003.typeId : OSS_CONTAINING_TYPE_BEGIN_PPR typeName : "Contents Constraint" 004.typeId : OSS_ASN1_TYPE_PPR decodedContent : - typeName : "Contents Constraint" qualifiedName : "*" qualifiedNumber : "1.1" qualifiedNumberOfTopRecord : "1" depth : 1 encodedContent : .58 ... length : 96 numberOfSimplestRecord : 2 simplestRecords : { { typeId : OSS_LENGTH_TYPE_PPR length : 8 encodedContent : .58 ... encodedBitOffset : 0 addition->comments : "(decoded as 88)" }, { typeId : OSS_CONTENTS_TYPE_PPR length : 88 encodedContent : .50 ... encodedBitOffset : 0 } } offset : 8 addition->typeInformation : "BIT STRING (CONTAINING ... ENCODED BY PER_UNALIGNED)" 005.typeId : OSS_CONTAINING_TYPE_BEGIN_PPR typeName : "Contents Constraint" 006.typeId : OSS_ASN1_TYPE_PPR possibleLast : TRUE decodedContent : '00000011 00001000 00000101 00101011 000 ...'B typeName : "Contents Constraint" qualifiedName : "*.*" qualifiedNameOfTopRecord : "*" qualifiedNumber : "1.1.1" qualifiedNumberOfTopRecord : "1.1" depth : 2 encodedContent : .50 ... length : 88 numberOfSimplestRecord : 2 simplestRecords : { { typeId : OSS_LENGTH_TYPE_PPR length : 8 encodedContent : .50 ... addition->comments : "(decoded as 80)" }, { typeId : OSS_CONTENTS_TYPE_PPR length : 80 encodedContent : .03 ... } } offset : 16 addition->typeInformation : "BIT STRING (CONTAINING ... ENCODED BY CER)" addition->optional : FALSE 007.typeId : OSS_CONTAINING_TYPE_END_PPR typeName : "Contents Constraint" 008.typeId : OSS_CONTAINING_TYPE_END_PPR typeName : "Contents Constraint" 009.typeId : OSS_CONTAINING_TYPE_END_PPR typeName : "T" 010.typeId : OSS_TOTAL_LENGTH_PPR length : 13 011.typeId : OSS_PDU_END_PPR typeName : "T"
ossPrintPER output:
value T ::= CONTAINING --TYPE INFORMATION: BIT STRING (CONTAINING ... ENCODED BY PER_ALIGNED) --LEVEL NUMBER: 1 --OFFSET: 0,0; LENGTH: 13,0 --length: .60 (decoded as 96) --contents: .58.50.03.08.05.2B.05.83.86.16.28.60 CONTAINING --TYPE INFORMATION: BIT STRING (CONTAINING ... ENCODED BY PER_UNALIGNED) --LEVEL NUMBER: 1.1 --OFFSET: 1,0; LENGTH: 12,0 --length: .58 (decoded as 88) --contents: .50.03.08.05.2B.05.83.86.16.28.60 '00000011 00001000 00000101 00101011 000 ...'B --TYPE INFORMATION: BIT STRING (CONTAINING ... ENCODED BY CER) --LEVEL NUMBER: 1.1.1 --OFFSET: 2,0; LENGTH: 11,0 --length: .50 (decoded as 80) --contents: .03.08.05.2B.05.83.86.16.28.60 /* Contents Constraint: tag = [UNIVERSAL 3] primitive; length = 8 0x052b058386162860 BIT STRING [length = 5.3] 0x058386162860 PrintableString [length = 5.0] "AaBbC" */ --TOTAL LENGTH: 13,0
ossPrintXPER output:
<PDU name="T"> <Value type="containing"> <Details> <metadata type="TYPE INFORMATION">BIT STRING (CONTAINING ... ENCODED BY PER_ALIGNED)</metadata> <metadata type="LEVEL NUMBER">1</metadata> <position offset="0,0" length="13,0"/> <encoding type="length"> .60 <description>(decoded as 96)</description> </encoding> <encoding type="contents">.58.50.03.08.05.2B.05.83.86.16.28.60</encoding> </Details> <Value type="containing"> <Details> <metadata type="TYPE INFORMATION">BIT STRING (CONTAINING ... ENCODED BY PER_UNALIGNED)</metadata> <metadata type="FULL NAME">*</metadata> <metadata type="LEVEL NUMBER">1.1</metadata> <position offset="1,0" length="12,0"/> <encoding type="length"> .58 <description>(decoded as 88)</description> </encoding> <encoding type="contents">.50.03.08.05.2B.05.83.86.16.28.60</encoding> </Details> <Value type="containing"> '00000011 00001000 00000101 00101011 000 ...'B <Details> <metadata type="TYPE INFORMATION">BIT STRING (CONTAINING ... ENCODED BY CER)</metadata> <metadata type="FULL NAME">*.*</metadata> <metadata type="LEVEL NUMBER">1.1.1</metadata> <position offset="2,0" length="11,0"/> <encoding type="length"> .50 <description>(decoded as 80)</description> </encoding> <encoding type="contents">.03.08.05.2B.05.83.86.16.28.60</encoding> <!-- Contents Constraint: tag = [UNIVERSAL 3] primitive; length = 8 0x052b058386162860 BIT STRING [length = 5.3] 0x058386162860 PrintableString [length = 5.0] "AaBbC" --> </Details> </Value> </Value> </Value> <TotalLength bytecount="13"/> </PDU>
The following example contains a SEQUENCE OF type with the OSS.Truncate directive applied:
--<OSS.Truncate M.S 2>-- --<OSS.Truncate M.S.* 1>-- M DEFINITIONS AUTOMATIC TAGS ::= BEGIN S::= SEQUENCE OF SEQUENCE OF BOOLEAN s S ::= { { FALSE, TRUE, TRUE }, { TRUE, FALSE, TRUE }, { TRUE, TRUE, FALSE } } END
If you provide your own function, it is called by turns with the following records as an argument:
000.typeId: OSS_PDU_BEGIN_PPR 001.typeId: OSS_SEQ_SET_BEGIN_PPR 002.typeId: OSS_SEQ_SET_BEGIN_PPR 003.typeId: OSS_ASN1_TYPE_PPR 004.typeId: OSS_START_TRUNCATED_ELEMENTS_TRACE_PPR 005.typeId: OSS_ASN1_TYPE_PPR 006.typeId: OSS_ASN1_TYPE_PPR 007.typeId: OSS_END_TRUNCATED_ELEMENTS_TRACE_PPR(length = 2) 008.typeId: OSS_SEQ_SET_FINISHED_PPR 009.typeId: OSS_SEQ_SET_BEGIN_PPR 010.typeId: OSS_ASN1_TYPE_PPR 011.typeId: OSS_START_TRUNCATED_ELEMENTS_TRACE_PPR 012.typeId: OSS_ASN1_TYPE_PPR 013.typeId: OSS_ASN1_TYPE_PPR 014.typeId: OSS_END_TRUNCATED_ELEMENTS_TRACE_PPR(length = 2) 015.typeId: OSS_SEQ_SET_FINISHED_PPR 016.typeId: OSS_START_TRUNCATED_ELEMENTS_TRACE_PPR 017.typeId: OSS_SEQ_SET_BEGIN_PPR 018.typeId: OSS_ASN1_TYPE_PPR 019.typeId: OSS_ASN1_TYPE_PPR 020.typeId: OSS_ASN1_TYPE_PPR 021.typeId: OSS_SEQ_SET_FINISHED_PPR 022.typeId: OSS_END_TRUNCATED_ELEMENTS_TRACE_PPR(length = 1) 023.typeId: OSS_SEQ_SET_FINISHED_PPR 024.typeId: OSS_ADDITIONS_TYPE_PPR 025.typeId: OSS_PDU_END_PPR
The sequence of records with OSS_NO_TRACE_FOR_TRUNCATED_ELEMENTS flag:
000.typeId: OSS_PDU_BEGIN_PPR 001.typeId: OSS_SEQ_SET_BEGIN_PPR 002.typeId: OSS_SEQ_SET_BEGIN_PPR 003.typeId: OSS_ASN1_TYPE_PPR 004.typeId: OSS_START_TRUNCATED_ELEMENTS_TRACE_PPR 005.typeId: OSS_END_TRUNCATED_ELEMENTS_TRACE_PPR(length = 2) 006.typeId: OSS_SEQ_SET_FINISHED_PPR 007.typeId: OSS_SEQ_SET_BEGIN_PPR 008.typeId: OSS_ASN1_TYPE_PPR 009.typeId: OSS_START_TRUNCATED_ELEMENTS_TRACE_PPR 010.typeId: OSS_END_TRUNCATED_ELEMENTS_TRACE_PPR(length = 2) 011.typeId: OSS_SEQ_SET_FINISHED_PPR 012.typeId: OSS_START_TRUNCATED_ELEMENTS_TRACE_PPR 013.typeId: OSS_END_TRUNCATED_ELEMENTS_TRACE_PPR(length = 1) 014.typeId: OSS_SEQ_SET_FINISHED_PPR 015.typeId: OSS_ADDITIONS_TYPE_PPR 016.typeId: OSS_PDU_END_PPR
ossPrintPER output:
value S ::=. { --length: <.00000011> { --length: <.00000011> FALSE --contents: <.0> --, the rest of elements are not decoded due to OSS.Truncate --TRUE, --contents: <1> --TRUE --contents: <1> --skipped 2 elements }, { --padding: <00000> --length: <.00000011> TRUE --contents: <.1> --, the rest of elements are not decoded due to OSS.Truncate --FALSE, --contents: <0> --TRUE --contents: <1> --skipped 2 elements } --, the rest of elements are not decoded due to OSS.Truncate --{ --padding: <00000> --length: <.00000011> --TRUE --contents: <.1> --, --TRUE, --contents: <1> --FALSE --contents: <0> --} --skipped 1 elements } --PDU padding: <00000>
ossPrintPER output with OSS_NO_TRACE_FOR_TRUNCATED_ELEMENTS flag:
value S ::=. { --length: <.00000011> { --length: <.00000011> FALSE --contents: <.0> --the rest of elements are not decoded due to OSS.Truncate --skipped 2 elements }, { --padding: <00000> --length: <.00000011> TRUE --contents: <.1> --the rest of elements are not decoded due to OSS.Truncate --skipped 2 elements } --the rest of elements are not decoded due to OSS.Truncate --skipped 1 elements } --PDU padding: <00000>
ossPrintXPER output:
<PDU name="S"> <Value type="seqsetof"> <Details> <metadata type="TYPE INFORMATION">SEQUENCE OF</metadata> <metadata type="LEVEL NUMBER">1</metadata> <position offset="0,0"/> <encoding type="length"> [.00000011] <description>(decoded as 3)</description> </encoding> </Details> <Value type="seqsetof"> <Details> <metadata type="TYPE INFORMATION">SEQUENCE OF</metadata> <metadata type="FULL NAME">[0]</metadata> <metadata type="LEVEL NUMBER">1.1</metadata> <position offset="1,0"/> <encoding type="length"> [.00000011] <description>(decoded as 3)</description> </encoding> </Details> <Value> FALSE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">[0].[0]</metadata> <metadata type="LEVEL NUMBER">1.1.1</metadata> <position offset="2,0" length="0,1"/> <encoding type="contents">[.0]</encoding> </Details> </Value> <Truncated> <Value> TRUE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">[0].[1]</metadata> <metadata type="LEVEL NUMBER">1.1.2</metadata> <position offset="2,1" length="0,1"/> <encoding type="contents">[1]</encoding> </Details> </Value> <Value> TRUE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">[0].[2]</metadata> <metadata type="LEVEL NUMBER">1.1.3</metadata> <position offset="2,2" length="0,1"/> <encoding type="contents">[1]</encoding> </Details> </Value> <Skipped elements="2"/> </Truncated> </Value> <Value type="seqsetof"> <Details> <metadata type="TYPE INFORMATION">SEQUENCE OF</metadata> <metadata type="FULL NAME">[1]</metadata> <metadata type="LEVEL NUMBER">1.2</metadata> <position offset="2,3"/> <encoding type="padding">[00000]</encoding> <encoding type="length"> [.00000011] <description>(decoded as 3)</description> </encoding> </Details> <Value> TRUE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">[1].[0]</metadata> <metadata type="LEVEL NUMBER">1.2.1</metadata> <position offset="4,0" length="0,1"/> <encoding type="contents">[.1]</encoding> </Details> </Value> <Truncated> <Value> FALSE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">[1].[1]</metadata> <metadata type="LEVEL NUMBER">1.2.2</metadata> <position offset="4,1" length="0,1"/> <encoding type="contents">[0]</encoding> </Details> </Value> <Value> TRUE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">[1].[2]</metadata> <metadata type="LEVEL NUMBER">1.2.3</metadata> <position offset="4,2" length="0,1"/> <encoding type="contents">[1]</encoding> </Details> </Value> <Skipped elements="2"/> </Truncated> </Value> <Truncated> <Value type="seqsetof"> <Details> <metadata type="TYPE INFORMATION">SEQUENCE OF</metadata> <metadata type="FULL NAME">[2]</metadata> <metadata type="LEVEL NUMBER">1.3</metadata> <position offset="4,3"/> <encoding type="padding">[00000]</encoding> <encoding type="length"> [.00000011] <description>(decoded as 3)</description> </encoding> </Details> <Value> TRUE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">[2].[0]</metadata> <metadata type="LEVEL NUMBER">1.3.1</metadata> <position offset="6,0" length="0,1"/> <encoding type="contents">[.1]</encoding> </Details> </Value> <Value> TRUE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">[2].[1]</metadata> <metadata type="LEVEL NUMBER">1.3.2</metadata> <position offset="6,1" length="0,1"/> <encoding type="contents">[1]</encoding> </Details> </Value> <Value> FALSE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">[2].[2]</metadata> <metadata type="LEVEL NUMBER">1.3.3</metadata> <position offset="6,2" length="0,1"/> <encoding type="contents">[0]</encoding> </Details> </Value> </Value> <Skipped elements="1"/> </Truncated> </Value> <encoding type="PDU padding">[00000]</encoding> <TotalLength bytecount="7"/> </PDU>
ossPrintXPER output with OSS_NO_TRACE_FOR_TRUNCATED_ELEMENTS flag:
<PDU name="S"> <Value type="seqsetof"> <Details> <metadata type="TYPE INFORMATION">SEQUENCE OF</metadata> <metadata type="LEVEL NUMBER">1</metadata> <position offset="0,0"/> <encoding type="length"> [.00000011] <description>(decoded as 3)</description> </encoding> </Details> <Value type="seqsetof"> <Details> <metadata type="TYPE INFORMATION">SEQUENCE OF</metadata> <metadata type="FULL NAME">[0]</metadata> <metadata type="LEVEL NUMBER">1.1</metadata> <position offset="1,0"/> <encoding type="length"> [.00000011] <description>(decoded as 3)</description> </encoding> </Details> <Value> FALSE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">[0].[0]</metadata> <metadata type="LEVEL NUMBER">1.1.1</metadata> <position offset="2,0" length="0,1"/> <encoding type="contents">[.0]</encoding> </Details> </Value> <Truncated> <Skipped elements="2"/> </Truncated> </Value> <Value type="seqsetof"> <Details> <metadata type="TYPE INFORMATION">SEQUENCE OF</metadata> <metadata type="FULL NAME">[1]</metadata> <metadata type="LEVEL NUMBER">1.2</metadata> <position offset="2,3"/> <encoding type="padding">[00000]</encoding> <encoding type="length"> [.00000011] <description>(decoded as 3)</description> </encoding> </Details> <Value> TRUE <Details> <metadata type="TYPE INFORMATION">BOOLEAN</metadata> <metadata type="FULL NAME">[1].[0]</metadata> <metadata type="LEVEL NUMBER">1.2.1</metadata> <position offset="4,0" length="0,1"/> <encoding type="contents">[.1]</encoding> </Details> </Value> <Truncated> <Skipped elements="2"/> </Truncated> </Value> <Truncated> <Skipped elements="1"/> </Truncated> </Value> <encoding type="PDU padding">[00000]</encoding> <TotalLength bytecount="7"/> </PDU>
When printing the PER encoding of a BIT STRING or OCTET STRING with a contents constraint applied (when a CONTAINING keyword is present), the function never displays encoding information for a contained type if it cannot be automatically decoded. The function will only explain the BIT STRING or OCTET STRING encoding. If automatic decoding is only possible with any non-PER encoding rule specified in ENCODED BY for the type with CONTAINING, then the function writes out trace data for the contained type value as the decoder does when the DEBUGPDU runtime flag is set for decoding.
The ossPrintPER() function prints such trace data inside /* */ comments and ossPrintXPER() prints it inside <!-- --> comments. No records for such a contained type encoding are passed to the user.
The partial decoding feature can be used instead of, or in addition to standard (full) decoding. The advantages of using partial decoding include the following:
For each decoded field, the offset, length, and value are provided by the decoder to the user application via callback functions. This means that you don't need to know the details of the PDU C representation or to write code to access a deeply nested field.
Your callback function can analyze the decoded value, and by setting the return code, instructs the decoder whether to terminate or continue decoding.
The ossPartialDecode() does not return the decoded PDU value. Instead, it calls a user-defined callback function upon decoding each field marked by the OSS.DataCallback or OSS.InfoCallback compiler directive and, optionally, passes the decoded field value to it.
The partial decoding feature requires TOED runtime version 10.2+.
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.
The following example illustrates how data and info callback functions may be combined to allow one of them to handle zipcode values from homeAddress and ignore zipcode from companyAddress. The sample code is provided for illustrative purposes. In a real-life situation, the flag in the sample code would need only one bit so that, instead of using the world->userVar field as a pointer to the user data, the field could directly store the flag.
--<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
/* 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; /* Info callback function. It sets the flag indicating * that homeAddress field is being decoded */ int DLL_ENTRY_FDEF homeAddressField(OssGlobal *world, char *fieldname, unsigned int flags) { UserData *udP = (UserData *)world->userVar; if ((flags & OSS_DECODING_OF_COMPONENT_IN_PROGRESS) /* decoding of homeAddress is to be started */ udP->flag = 1; else /* decoding of homeAddress is completed */ udP->flag = 0; return OSS_CONTINUE_DECODING; } /* Data callback function. * It prints binary encoding and value of zipcode field * if it belongs to home address but not to company address */ int DLL_ENTRY_FDEF myZipcode(OssGlobal *world, long offset, long length, unsigned int flags, unsigned int *zipcode). { UserData *udP = (UserData *)world->userVar; if (udP->flag != 1) /* we are not in homeAddress */ return OSS_CONTINUE_DECODING; /* Print homeAddress zipcode */ ossPrint(world, "zipcode = %05d\n", *zipcode); return OSS_SKIP_TO_PDU_END; }
Note: Partial decoding is a chargeable feature in non-evaluation licenses. Contact Sales to obtain pricing information.
This documentation applies to the OSS® ASN.1 Tools for C release 11.3 and later.
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.