= Encoding and Decoding

:table-number: 2
:toc:

This tool is equipped with several standard encoding/decoding mechanisms. A part of these functions reside in the core library, but the type-dependent part must be generated by the compiler. In order to reduce the code size and compilation time, the code generation for encoding functions (separately for different encoders) can be switched off if they are not needed. For details, see section "Command line syntax" in the link:https://gitlab.eclipse.org/eclipse/titan/titan.core/tree/master/usrguide/referenceguide[Programmer's Technical Reference].

To make it easier to use the encoding features, a unified common API was developed. With help of this API the behaviour of the test executor in different error situations can be set during coding. There is also a common buffer class. The details of the above mentioned API as well as the specific features of the certain encoders are explained in the following sections.

[[the-common-API]]
== The Common API

The common API for encoders consists of three main parts:

* A dummy class named `TTCN_EncDec` which encapsulates functions regarding error handling.

* A buffer class named `TTCN_Buffer` which is used by the encoders to put data in, decoders to get data from.

* The functions needed to encode and decode values.

[[ttcn-encdec]]
=== TTCN_EncDec

`TTCN_EncDec` implements error handling functions.

==== Setting Error Behavior

There are lot of error situations during encoding and decoding. The coding functions can be told what to do if an error arises. To set the behaviour of test executor in a certain error situation the following function is to be invoked:
[source, subs="+quotes"]
void TTCN_EncDec::set_error_behavior(error_type_t, error_behavior_t);

WARNING: As error_type_t and error_behavior_t are enums defined in TTCN_EncDec class, they have to prefixed with the class name and the scope operator (that is `TTCN_EncDec::`).

The possible values of `error_type_t` are detailed in the sections describing the different codings. Some common error types are shown in the table below:

.Common error types
[width="100%",cols="30%,70%",options="header",]
|=========================================================================================
|ET_UNDEF |Undefined/unknown error.
|ET_UNBOUND |Encoding of an unbound value.
|ET_REPR |Representation error (for example, internal representation of integral numbers).
|ET_ENC_ENUM |Encoding of an unknown enumerated value.
|ET_DEC_ENUM |Decoding of an unknown enumerated value.
|ET_INCOMPL_MSG |Decode error: incomplete message.
|ET_INVAL MSG |Decode error: invalid message.
|ET_CONSTRAINT |The value breaks some constraint.
|ET_INTERNAL |Internal error. Error behaviour cannot be set for this.
|ET_ALL |All error type. Usable only when setting error behaviour.
|ET_NONE |No error.
|=========================================================================================

The possible values of `error_behavior_t` are shown in the table below:

.Possible values of `error_behavior_t`

[cols="30%,70%"]
|=========================================================================
|EB_DEFAULT |Sets the default error behaviour for the selected error type.
|EB_ERROR |Raises an error if the selected error type occurs.
|EB_WARNING |Gives a warning message but tries to continue the operation.
|EB_IGNORE |Like warning but without the message.
|=========================================================================

==== Getting Error Behavior

There are two functions: one for getting the current setting and one for getting the default setting for a particular error situation.
[source]
----
error_behavior_t TTCN_EncDec::get_error_behavior(error_type_t);
error_behavior_t TTCN_EncDec::get_default_error_behavior(error_type_t);
----
The using of these functions are straightforward: giving a particular `error_type_t` the function returns the current or default `error_behavior_t` for that error situation, respectively.

==== Checking if an Error Occurred

The last coding-related error and its textual description can be retrieved anytime. Before using a coding function, it is advisable to clear the "last error". This can be achieved by the following method:
[source, subs="+quotes"]
void TTCN_EncDec::clear_error();

After using some coding functions, it can be checked if an error occurred with this function:
[source, subs="+quotes"]
error_type_t TTCN_EncDec::get_last_error_type();

This returns the last error, or `ET_NONE` if there was no error. The string representation of the error can be requested with the help of this:
[source, subs="+quotes"]
const char* TTCN_EncDec::get_error_str();

WARNING: The above two functions do not clear the "last error" flag.

[[ttcn-buffer]]
=== TTCN_Buffer

TTCN Buffer objects are used to store encoded values and to communicate with the coding functions. If encoding a value, the result will be put in a buffer, from which can be get. In the other hand, to decode a value, the encoded octet string must be put in a TTCN_Buffer object, and the decoding functions get their input from that.
[source, subs="+quotes"]
void TTCN_Buffer::clear();

Resets the buffer, cleaning up its content, setting the pointers to the beginning of buffer.
[source, subs="+quotes"]
void TTCN_Buffer::rewind();

Rewinds the buffer, that is, sets its reading pointer to the beginning of the buffer.
[source, subs="+quotes"]
size_t TTCN_Buffer::get_pos() const;

Returns the (reading) position of the buffer.
[source, subs="+quotes"]
void TTCN_Buffer::set_pos(size_t pos);

Sets the (reading) position to pos, or to the end of buffer, if `pos > get_len()`.
[source, subs="+quotes"]
size_t TTCN_Buffer::get_len() const;

Returns the amount of bytes in the buffer.
[source, subs="+quotes"]
const unsigned char* TTCN_Buffer::get_data() const;

Returns a pointer that points to the beginning of the buffer. You can read out `count` bytes beginning from this address, where `count` is the value returned by the `get_len()` member function.
[source, subs="+quotes"]
size_t TTCN_Buffer::get_read_len() const;

Returns how many bytes are in the buffer to read.
[source, subs="+quotes"]
const unsigned char* TTCN_Buffer::get_read_data() const;

Returns a pointer which points to the read position of data in the buffer. `count` bytes can be read out beginning from this address, where count is the value returned by the `get_read_len()` member function.
[source, subs="+quotes"]
void TTCN_Buffer::put_c(const unsigned char c);

Appends the byte `c` to the end of buffer.
[source, subs="+quotes"]
void TTCN_Buffer::put_s(const size_t len, const unsigned char *s);

Writes a string of bytes to the end of buffer, where len is the amount of bytes, `s` is a pointer to the data to be written.
[source, subs="+quotes"]
void TTCN_Buffer::put_os(const OCTETSTRING& os);

Appends the content of the octet string to the buffer.

Sometimes it is useful to copy data directly into a buffer. In this case, the buffer must be told the maximum number of bytes to be written. So the buffer can resize its data area. This can be done with the following function:
[source, subs="+quotes"]
void TTCN_Buffer::get_end(unsigned char*& end_ptr, size_t& end_len);

Parameter `end_len` is an in-out parameter: you tell how many bytes you want to write, and the returned value is equal to or greater than the requested. Parameter `end_ptr` is an out parameter. So up to `end_len` bytes can be written beginning from `end_ptr`. After writing also `increase_length()` must be called.
[source, subs="+quotes"]
void TTCN_Buffer::increase_length(size_t count);

After writing bytes directly to the end of buffer using the pointer returned by `get_end()` method, the buffer must be told how many bytes have been written. This can be done by this function.
[source, subs="+quotes"]
void TTCN_Buffer::cut();

Cuts (removes) the bytes between the beginning of the buffer and the read position. After calling this, the read position will be the beginning of buffer. As this function manipulates the internal data, pointers referencing to data inside the buffer will be invalid.
[source, subs="+quotes"]
void TTCN_Buffer::cut_end();

Cuts (removes) the bytes between the read position and the end of the buffer. After calling this, the read position remains unchanged (that is, it will point to the end of the truncated buffer). As this function manipulates the internal data, pointers referencing to data inside the buffer will be invalid.
[source, subs="+quotes"]
boolean TTCN_Buffer::contains_complete_TLV();

Returns `TRUE` if the buffer contains a complete TLV, otherwise it returns `FALSE`. Useful when decoding BER streams, and the data is coming in chunks. With the help of this, you can check before decoding whether the message is complete.

=== Invoking the Coding Functions

Every type class has members like these:

[source]
----
void encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
	TTCN_EncDec::coding_t p_cod, ...) const;
void decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
	TTCN_EncDec::coding_t p_cod, ...);
----

Parameter `p_td` is a special type descriptor. Each type has its own descriptor, which contains the name of the type, and a lot of information used by the different encoding mechanisms. The names of the descriptors come from the name of the types: the appropriate type descriptor for type `XXX is XXX_descr_`.

Parameter `p_buf` contains the encoded value. For details about using it, please consult the previous subsection.

Parameter `p_cod` is the desired coding mechanism. As `coding_t` is defined in `TTCN_EncDec`, its value must be prefixed with `TTCN_EncDec::`. For the time being, this parameter may have one of the following values:

* CT_BER - BER coding;
* CT_RAW - RAW coding;
* CT_TEXT - TEXT coding;
* CT_XER  - XML coding;
* CT_JSON - JSON coding;
* CT_OER - OER coding;
* CT_PER - PER coding;

The optional … parameter(s) are depending on the chosen coding.

== BER

The encoding rules defined in link:https://www.itu.int/rec/T-REC-X.690-200811-S[Information TechnologyASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished] can be used to encode and/or decode the values of ASN.1 types. There are three methods defined in the referenced document: BER, CER and DER (Basic, Canonical and Distinguished Encoding Rules). While the BER gives a lot of options to the sender (that is, to the encoder), the CER and DER select just one encoding from those allowed by the BER, eliminating all of the sender options. In other words, CER (and also DER) is a subset of BER. Any value encoded by CER or DER can be decoded using BER, but it is not true in the other direction.

In this section it is assumed that the reader has basic knowledge about BER, TLVs, tags, length forms and other items defined in link:https://www.itu.int/rec/T-REC-X.690-200811-S[Information TechnologyASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished].

This tool is capable of encoding values in CER or DER, and uses the BER while decodingfootnote:[Though the decoder can be forced to accept only certain length forms (short, long, indefinite or any combination of these.]. The tags are handled quite separated from the types, giving extra freedom to the user when encoding only one component of a compound type. Let us suppose we have a large SEQUENCE with automatic tags (that is, context-specific implicit tags 1, 2, …), the third component is `"‎[3] Other-sequence"`. Then we have the possibility to encode only this field using SEQUENCE-tag. (Implementation details and examples follow in next sections.)

=== Error Situations

In addition to error situations mentioned in <<the-common-API, The Common API>>, these can occur during BER-coding:

.BER-coding errors

[width="100%",cols="30%,70%",options=" ",]
|===================================================================================================================================================
|ET_INCOMPL_ANY |Encoding of an ASN ANY value which does not contain a valid BER TLV.
|ET_LEN_FORM |During decoding: the received message has a non-acceptable length form.
|ET_TAG |During decoding: unexpected tag.
|ET_SUPERFL |During decoding: superfluous part detected. This can be superfluous TLV at the end of a constructed TLV.
|ET_EXTENSION |During decoding: there was something in the extension (for example: in ASN.1 ellipsis). This is not supported in the current version.
|ET_DEC_DUPFLD |While decoding a SET: duplicated field (value for the given field already received).
|ET_DEC_MISSFLD |While decoding a SET: missing field (value for the given field not received).
|ET_DEC_OPENTYPE |Cannot decode an opentype (broken component relation constraint).
|ET_DEC_UCSTR |While decoding a universal charstring: Malformed sequence.
|===================================================================================================================================================

=== API

The Application Programming Interface for ASN.1 type encoding and decoding is described in the following.

==== Encoding

[source, subs="+quotes"]
void encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
	TTCN_EncDec::coding_t p_cod, ...) const;

The parameter `p_cod` must be set to `TTCN_EncDec::CT_BER`. The variable argument list (...) must be set to one `int` argument, which is used to choose between CER and DER.

`BER_ENCODE_CER` = CER coding.

`BER_ENCODE_DER` = DER coding.

==== Decoding

[source, subs="+quotes"]
void decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
	TTCN_EncDec::coding_t p_cod, ...);

The parameter `p_cod` must be set to `TTCN_EncDec::CT_BER`. The variable argument list (...) must be set to one `int` argument, which determines which length forms are accepted.

* `BER_ACCEPT_SHORT`
+
Short form.

* `BER_ACCEPT_LONG`
+
Long form.

* `BER_ACCEPT_INDEFINITE`
+
Indefinite form.

* `BER_ACCEPT_DEFINITE`
+
Short and long form.

* `BER_ACCEPT_ALL`
+
All form.

=== Example

Let us assume that we have an ASN.1 module named `MyASN` which contains a type named `ErrorReturn`, and we have a TTCN–3 module which imports this type. This module contains also two ports:

type port MyPort1 message

[source]
----
type port MyPort1 message
{
  out ErrorReturn;
  in octetstring;
}

type port MyPort2 message
{
  out octetstring;
  in ErrorReturn;
}
----

Then we can complete the port skeleton generated by the compiler:

[source]
----
void MyPort1::outgoing_send(const MyASN::ErrorReturn& send_par)
{
  TTCN_Buffer buf;
  send_par.encode(MyASN::ErrorReturn_descr_, buf,
                  TTCN_EncDec::CT_BER, BER_ENCODE_DER);
  OCTETSTRING encodeddata(buf.get_len(), buf.get_data());
  incoming_message(encodeddata);
}

void MyPort2::outgoing_send(const OCTETSTRING& send_par)
{
  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL,
                                  TTCN_EncDec::EB_WARNING);
  TTCN_Buffer buf;
  buf.put_os(send_par);
  MyASN::ErrorReturn pdu;
  pdu.decode(MyASN::ErrorReturn_descr_, buf, TTCN_EncDec::CT_BER,
             BER_ACCEPT_ALL);
  incoming_message(pdu);
}
----

== RAW

You can use the encoding rules defined in the section "RAW encoder and decoder" in the link:https://gitlab.eclipse.org/eclipse/titan/titan.core/tree/master/usrguide/referenceguide[Programmer's Technical Reference] to encode and decode the following TTCN–3 types:

* boolean

* integer

* float

* bitstring

* octetstring

* charstring

* hexstring

* enumerated

* record

* set

* union

* record of

* set of

The compiler will produce code capable of RAW encoding/decoding for compound types if they have at least one `variant` attribute. +
When a compound type is only used internally or it is never RAW encoded/decoded then the attribute `variant` has to be omitted. +
 When a type can be RAW encoded/decoded but with default specification then the empty variant specification can be used: `variant ""`.

[[error-situations-0]]
=== Error Situations

.RAW-coding errors

[width="100%",cols="30%,70%",options="",]
|============================================================================================================================================================
|ET_LEN_ERR |During encoding: Not enough length specified in FIELDLENGTH to encode the value. During decoding: the received message is shorter than expected.
|ET_SIGN_ERR |Unsigned encoding of a negative number.
|ET_FLOAT_NAN |Not a Number float value has been received.
|ET_FLOAT_TR |The float value will be truncated during double to single precision conversion.
|============================================================================================================================================================

[[api-0]]
=== API

The {cpp} Application Programming Interface for RAW encoding and decoding is described in the following. It can be used for example in test port implementation, in external function implementation.

[[encoding-0]]
==== Encoding

[source]
----
void encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
            TTCN_EncDec::coding_t p_cod, ...) const;
----

The parameter `p_cod` must be set to `TTCN_EncDec::CT_RAW`. The variable argument list (...) is ignored.

[[decoding-0]]
==== Decoding

[source]
----
void decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
            TTCN_EncDec::coding_t p_cod, ...);
----

The parameter `p_cod` must be set to `TTCN_EncDec::CT_RAW`. The variable argument list (...) is ignored.

[[example-0]]
=== Example

Let us assume that we have a TTCN–3 module which contains a type named `ProtocolPdu`, and this module contains also two ports:
[source]
----
type port MyPort1 message
{
  out ProtocolPdu;
  in octetstring;
}

type port MyPort2 message
{
  out octetstring;
  in ProtocolPdu;
}
----

Then we can complete the port skeleton generated by the compiler as follows:
[source]
----
void MyPort1::outgoing_send(const ProtocolPdu& send_par)
{
  TTCN_Buffer buf;
  send_par.encode(ProtocolPdu_descr_, buf,
                  TTCN_EncDec::CT_RAW);
  OCTETSTRING encodeddata(buf.get_len(), buf.get_data());

  incoming_message(encodeddata);
}

void MyPort2::outgoing_send(const OCTETSTRING& send_par)
{
  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL,
                                  TTCN_EncDec::EB_WARNING);
  TTCN_Buffer buf;
  buf.put_os(send_par);
  ProtocolPdu pdu;
  pdu.decode(ProtocolPdu_descr_, buf, TTCN_EncDec::CT_RAW);

  incoming_message(pdu);
}
----

== TEXT

You can use the encoding rules defined in the section "TEXT encoder, decoder" in the link:https://gitlab.eclipse.org/eclipse/titan/titan.core/tree/master/usrguide/referenceguide[Programmer's Technical Reference] to encode and decode the following TTCN–3 types:

* boolean

* integer

* charstring

* enumerated

* record

* set

* union

* record of

* set of

The compiler will produce code capable of TEXT encoding/decoding for compound types if they have at least one variant attribute or it is used within a compound type which has a TEXT attribute. If you need a compound type that is only used internally or it is never RAW encoded/decoded then you have to omit the variant attribute. If you need a type which can be TEXT encoded/decoded but with default specification then the empty variant specification can be used: `variant "TEXT_CODING()"`.

[[error-situations-1]]
=== Error Situations

`ET_TOKEN_ERR` - The specified token is not found during decoding

[[api-1]]
=== API

The Application Programming Interface for TEXT encoding and decoding is described in the following.

[[encoding-1]]
==== Encoding

[source]
----
void encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
            TTCN_EncDec::coding_t p_cod, ...) const;
----
The parameter `p_cod` must be set to `TTCN_EncDec::CT_TEXT`. The variable argument list (...) is ignored.

[[decoding-1]]
==== Decoding

[source]
----
void decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
            TTCN_EncDec::coding_t p_cod, ...);
----

The parameter `p_cod` must be set to `TTCN_EncDec::CT_TEXT`. The variable argument list (...) is ignored.

[[example-1]]
=== Example

Let us assume that we have a TTCN–3 module which contains a type named `ProtocolPdu`, and this module contains also two ports:
[source]
----
type port MyPort1 message
{
  out ProtocolPdu;
  in charstring;
}

type port MyPort2 message
{
  out charstring;
  in ProtocolPdu;
}
----

Then we can complete the port skeleton generated by the compiler:

[source]
----
void MyPort1::outgoing_send(const ProtocolPdu& send_par)
{
  TTCN_Buffer buf;
  send_par.encode(ProtocolPdu_descr_, buf,
                  TTCN_EncDec::CT_TEXT);
  CHARSTRING encodeddata(buf.get_len(), buf.get_data());

  incoming_message(encodeddata);
}

void MyPort2::outgoing_send(const CHARSTRING& send_par)
{
  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL,
                                  TTCN_EncDec::EB_WARNING);
  TTCN_Buffer buf;
  buf.put_cs(send_par);
  ProtocolPdu pdu;
  pdu.decode(ProtocolPdu_descr_, buf, TTCN_EncDec::CT_TEXT);

  incoming_message(pdu);
}
----

[[xml-encoding-xer]]
== XML Encoding (XER)

The encoding rules defined by link:https://www.etsi.org/deliver/etsi_ES/201800_201899/20187309/04.05.01_60/es_20187309v040501p.pdf[Methods for Testing and Specification (MTS); The Testing and Test Control Notation version 3. Part 9: Using XML Schema with TTCN–3 European] can be used to encode and/or decode values of ASN.1 and TTCN-3 types. This tool is capable of encoding and decoding Basic XER (BXER), Canonical XER (CXER) and Extended XER (EXER). Values of all ASN.1 types can be encoded, but only BXER and CXER are available for them because parsing XML Encoding Instructions in ASN.1 files is not implemented.

The following built-in TTCN-3 types can be encoded in XML:

* boolean

* integer

* float

* bitstring

* octetstring

* hexstring

* objid

* charstring

* universal charstring

* verdicttype

The following user-defined types can be encoded in XML:

* enumerated types

* record, set and union types, if all components can be encoded.

* record of and set of types, if the type of the element can be encoded.

The encoder and the decoder are working with XML data encoded in UTF-8 (described in link:https://tools.ietf.org/html/rfc3629[UTF-8, a transformation format of ISO 10646]), stored in an object of type `TTCN_buffer`. Although the contents of this object can be retrieved (using the overloads of the get_string function) as an instance of `OCTETSTRING`, `CHARSTRING` or `UNIVERSAL_CHARSTRING`, it is recommended to use only the `OCTETSTRING` representation. `CHARSTRING` is not recommended, because UTF-8 is an 8-bit encoding so the buffer may contain bytes with values over 127, which are not valid characters for a TTCN-3 `charstring` (which is implemented by `CHARSTRING`, see <<6-mapping_ttcn3_data_types_to_c++_constructs.adoc#Charstring, Charstring>>). `UNIVERSAL_CHARSTRING` must not be used because its internal representation is not UTF-8.

[[error-situations-2]]
=== Error Situations

In addition to error situations mentioned in <<the-common-API, The Common API>>, the following can occur during XMLcoding:

.XER coding errors

[cols=",",options=" ",]
|============================================================
|ET_TAG |Incorrect (unexpected) XML tag found during decoding
|============================================================

[[api-2]]
=== API

The Application Programming Interface for XML encoding and decoding is described in the following.

[[encoding-2]]
==== Encoding

[source]
----
void encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
	TTCN_EncDec::coding_t p_cod, ...) const;
----

The parameter `p_cod` must be set to `TTCN_EncDec::CT_XER`. The variable argument list (...) must be set to one `int` argument, which is used to choose between BXER, CXER and EXER:

`XER_BASIC` = Basic XER (BXER)

`XER_CANONICAL` = Canonical XER (CXER)

`XER_EXTENDED` = Extended XER (EXER)

[[decoding-2]]
==== Decoding

[source]
----
void decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
	TTCN_EncDec::coding_t p_cod, ...);
----

The parameter `p_cod` must be set to `TTCN_EncDec::CT_XER`. The variable argument list (...) must be set to one `int` argument, which is used to choose between BXER, CXER and EXER:

`XER_BASIC` = Basic XER (BXER)

`XER_CANONICAL` = Canonical XER (CXER)

`XER_EXTENDED` = Extended XER (EXER)

[[example-2]]
=== Example

Let us assume that we have a TTCN–3 module which contains a type named `ProtocolPdu`, and this module contains also two ports:

[source]
----
void MyPort1::outgoing_send(const ProtocolPdu& send_par)
{
  TTCN_Buffer buf;
  send_par.encode(ProtocolPdu_descr_, buf,
                  TTCN_EncDec::CT_XER, XER_EXTENDED);
  OCTETSTRING encodeddata(buf.get_len(), buf.get_data());

  incoming_message(encodeddata);
}

void MyPort2::outgoing_send(const OCTETSTRING& send_par)
{
  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL,
                                  TTCN_EncDec::EB_WARNING);
  TTCN_Buffer buf;
  buf.put_os(send_par);
  ProtocolPdu pdu;
  pdu.decode(ProtocolPdu_descr_, buf, TTCN_EncDec::CT_XER, XER_EXTENDED);

  incoming_message(pdu);
}
----
== JSON

The encoding rules defined in the section "JSON Encoder and Decoder" of the link:https://gitlab.eclipse.org/eclipse/titan/titan.core/tree/master/usrguide/referenceguide[Programmer's Technical Reference] can be used to encode and decode the following TTCN–3 types:

* anytype

* array

* bitstring

* boolean

* charstring

* enumerated

* float

* hexstring

* integer

* objid

* octetstring

* record`, set

* record of`, set of

* union

* universal charstring

* verdicttype

The rules also apply to the following ASN.1 types (if imported to a TTCN-3 module):

* ANY

* BIT STRING

* BOOLEAN

* BMPString

* CHOICE, open type (in instances of parameterized types)

* ENUMERATED

* GeneralString

* GraphicString

* IA5String

* INTEGER

* NULL

* NumericString

* OBJECT IDENTIFIER

* OCTET STRING

* PrintableString

* RELATIVE`-OID

* SEQUENCE, SET

* SEQUENCE OF, SET OF

* TeletexString

* UniversalString

* UTF8String

* VideotexString

* VisibleString

The compiler will produce code capable of JSON encoding/decoding for compound types if they have at least one JSON variant attribute or the `encode "JSON"` attribute (and, for compound types, all fields and elements of compound types also have a JSON variant attribute or the `encode "JSON"` attribute).

The encoder and the decoder work with JSON data encoded in UTF-8 (described in link:https://tools.ietf.org/html/rfc3629[UTF-8, a transformation format of ISO 10646]), stored in an object of type `TTCN_buffer`. Although the contents of this object can be retrieved (using the overloads of the `get_string` function) as an instance of `OCTETSTRING`, `CHARSTRING` or `UNIVERSAL_CHARSTRING`, it is recommended to use only the `OCTETSTRING` representation. `CHARSTRING` is not recommended, because UTF-8 is an 8-bit encoding so the buffer may contain bytes with values over 127, which are not valid characters for a TTCN-3 `charstring` (which is implemented by `CHARSTRING`, see <<6-mapping_ttcn3_data_types_to_c+\+_constructs.adoc#Charstring, Charstring>>). `UNIVERSAL_CHARSTRING` must not be used because its internal representation is not UTF-8.

[[error-situations-3]]
=== Error Situations

There are no extra error situations apart from the ones in <<the-common-API, The Common API>>.

[[api-3]]
=== API

The Application Programming Interface for JSON encoding and decoding is described in the following.

[[encoding-3]]
==== Encoding

[source]
----
void encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
            TTCN_EncDec::coding_t p_cod, ...) const;
----

The parameter `p_cod` must be set to `TTCN_EncDec::CT_JSON`. The variable argument list (...) must be set to one `int` argument, which indicates how the JSON language elements are printed:

`0` = compact printing (i.e. no extra whitespaces are added between JSON language elements),

`1` = pretty printing (i.e. extra whitespaces are added between JSON language elements).

[[decoding-3]]
==== Decoding

[source]
----
void decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
            TTCN_EncDec::coding_t p_cod, ...);
----

The parameter `p_cod` must be set to `TTCN_EncDec::CT_JSON`. The variable argument list (...) is ignored.

[[example-3]]
=== Example

Let us assume that we have a TTCN–3 module which contains a type named `ProtocolPdu`, and this module also contains two ports:
[source]
----
type port MyPort1 message
{
  out ProtocolPdu;
  in octetstring;
}

type port MyPort2 message
{
  out octetstring;
  in ProtocolPdu;
}
----

Then we can complete the port skeleton generated by the compiler:
[source]
----
void MyPort1::outgoing_send(const ProtocolPdu& send_par)
{
  TTCN_Buffer buf;
  send_par.encode(ProtocolPdu_descr_, buf,
                  TTCN_EncDec::CT_JSON);
  OCTETSTRING encodeddata(buf.get_len(), buf.get_data());

  incoming_message(encodeddata);
}

void MyPort2::outgoing_send(const OCTETSTRING& send_par)
{
  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL,
                                  TTCN_EncDec::EB_WARNING);
  TTCN_Buffer buf;
  buf.put_os(send_par);
  ProtocolPdu pdu;
  pdu.decode(ProtocolPdu_descr_, buf, TTCN_EncDec::CT_JSON);

  incoming_message(pdu);
}
----

== OER

The encoding rules defined in the section "OER Encoder and Decoder" of the link:https://gitlab.eclipse.org/eclipse/titan/titan.core/tree/master/usrguide/referenceguide[Programmer's Technical Reference] can be used to encode and/or decode the values of ASN.1 types.

=== Error Situations

There are no extra error situations apart from the ones in <<the-common-API, The Common API>>.

=== API

The Application Programming Interface for ASN.1 type encoding and decoding is described in the following.

==== Encoding

[source, subs="+quotes"]
void encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
	TTCN_EncDec::coding_t p_cod, ...) const;

The parameter `p_cod` must be set to `TTCN_EncDec::CT_OER`. The variable argument list (...) is ignored.

==== Decoding

[source, subs="+quotes"]
void decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
	TTCN_EncDec::coding_t p_cod, ...);

The parameter `p_cod` must be set to `TTCN_EncDec::CT_OER`. The variable argument list (...) is ignored.

=== Example

Let us assume that we have an ASN.1 module named `MyASN` which contains a type named `ErrorReturn`, and we have a TTCN–3 module which imports this type. This module also contains two ports:

[source]
----
type port MyPort1 message
{
  out ErrorReturn;
  in octetstring;
}

type port MyPort2 message
{
  out octetstring;
  in ErrorReturn;
}
----

Then we can complete the port skeleton generated by the compiler:

[source]
----
void MyPort1::outgoing_send(const MyASN::ErrorReturn& send_par)
{
  TTCN_Buffer buf;
  send_par.encode(MyASN::ErrorReturn_descr_, buf,
                  TTCN_EncDec::CT_OER);
  OCTETSTRING encodeddata(buf.get_len(), buf.get_data());
  incoming_message(encodeddata);
}

void MyPort2::outgoing_send(const OCTETSTRING& send_par)
{
  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL,
                                  TTCN_EncDec::EB_WARNING);
  TTCN_Buffer buf;
  buf.put_os(send_par);
  MyASN::ErrorReturn pdu;
  pdu.decode(MyASN::ErrorReturn_descr_, buf, TTCN_EncDec::CT_OER);
  incoming_message(pdu);
}
----

== PER

The encoding rules defined in the section "PER Encoder and Decoder" of the link:https://gitlab.eclipse.org/eclipse/titan/titan.core/tree/master/usrguide/referenceguide[Programmer's Technical Reference] can be used to encode and/or decode the values of ASN.1 types.

=== Error Situations

There are no extra error situations apart from the ones in <<the-common-API, The Common API>>.

=== API

The Application Programming Interface for PER encoding and decoding is described in the following.

==== Encoding

[source, subs="+quotes"]
void encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
	TTCN_EncDec::coding_t p_coding, ...) const;

The parameter `p_coding` must be set to `TTCN_EncDec::CT_PER`.

The variable argument list (...) must be set to one `int` argument. The following flags are available for convenience:

* basic, unaligned PER: `PER_UNALIGNED`, `PER_BASIC`;
* aligned PER: `PER_ALIGNED`;
* canonical PER: `PER_CANONICAL`.

==== Decoding

[source, subs="+quotes"]
void decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
	TTCN_EncDec::coding_t p_coding, ...);

The parameter `p_coding` must be set to `TTCN_EncDec::CT_PER`.

The variable argument list (...) must be set to one `int` argument. The following flags are available for convenience:

* basic, unaligned PER: `PER_UNALIGNED`, `PER_BASIC`;
* aligned PER: `PER_ALIGNED`;
* canonical PER: `PER_CANONICAL`.

=== Example

Let us assume that we have an ASN.1 module named `MyASN` which contains a type named `ErrorReturn`, and we have a TTCN–3 module which imports this type. This module also contains two ports:

[source]
----
type port MyPort1 message
{
  out ErrorReturn;
  in octetstring;
}

type port MyPort2 message
{
  out octetstring;
  in ErrorReturn;
}
----

Then we can complete the port skeleton generated by the compiler:

[source]
----
void MyPort1::outgoing_send(const MyASN::ErrorReturn& send_par)
{
  TTCN_Buffer buf;
  send_par.encode(MyASN::ErrorReturn_descr_, buf,
                  TTCN_EncDec::CT_PER, PER_ALIGNED);
  OCTETSTRING encodeddata(buf.get_len(), buf.get_data());
  incoming_message(encodeddata);
}

void MyPort2::outgoing_send(const OCTETSTRING& send_par)
{
  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL,
                                  TTCN_EncDec::EB_WARNING);
  TTCN_Buffer buf;
  buf.put_os(send_par);
  MyASN::ErrorReturn pdu;
  pdu.decode(MyASN::ErrorReturn_descr_, buf,
             TTCN_EncDec::CT_PER, PER_ALIGNED);
  incoming_message(pdu);
}
----

