blob: 098e19a2526357776df47d5567ecde58308e46a3 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2000-2019 Ericsson Telecom AB AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
* Mate Kovacs - initial implementation and initial documentation
* Antal Wu-Hen Chang
* Naum Spaseski
* Bence Janos Szabo - negative testing branch
******************************************************************************/
//
// File: CoAP_EncDec.cc
// Rev: R1A
// Prodnr: CNL 113 829
#include "CoAP_Types.hh"
namespace CoAP__Types {
int getOptionCode(CoAP__Options option);
int getIntegerLength(const long long int value, int mode);
void encodeInteger(TTCN_Buffer &stream, const long long int option, const int length);
long long int decodeInteger(OCTETSTRING const &str, const int position, const int length);
int getBlockLengthForNum(const long long int num);
void encodeBlock(TTCN_Buffer &stream, const BlockOption option, const int length);
void decodeBlock(BlockOption& block, OCTETSTRING const &str, const int position, const int length);
INTEGER
f__CoAP__dec(OCTETSTRING const &str, CoAP__Message &msg)
{
if(TTCN_Logger::log_this_event(TTCN_DEBUG)){
TTCN_Logger::begin_event(TTCN_DEBUG);
TTCN_Logger::log_event("Decoding CoAP message: ");
str.log();
TTCN_Logger::end_event();
}
if(str.lengthof() >= 4){
const unsigned char* str_ptr = (const unsigned char*) str;
unsigned char chr;
int position = 0;
int token_length = 0;
int actual_option_code = 0;
int count_of_options = 0;
bool payload_marker = false;
//version, message type and token length
chr = str_ptr[0];
msg.msg().version() = chr >> 6;
msg.msg().msg__type() = (chr >> 4) & 3;
token_length = chr & 15;
msg.msg().tkl() = token_length;
//code
chr = str_ptr[1];
msg.msg().code().class_() = (chr >> 5) & 7;
msg.msg().code().detail() = chr & 31;
//message ID
msg.msg().message__id() = str_ptr[2] * 256 + str_ptr[3];
if(str.lengthof() > 4 && msg.msg().code().class_() == 0 && msg.msg().code().detail() == 0){
msg.raw__message() = str;
return 1;
}
position = 4;
//token
if(token_length > 0){
if(str.lengthof() >= position + token_length){
msg.msg().token() = OCTETSTRING(token_length, &str_ptr[position]);
position += token_length;
}else{
msg.raw__message() = str;
return 1;
}
}else{
msg.msg().token() = OCTETSTRING(0, 0);
}
//options
msg.msg().options() = OMIT_VALUE;
if(str.lengthof() > 4){
while(!payload_marker && str.lengthof() > position){
int delta = str_ptr[position] >> 4;
int length = str_ptr[position] & 15;
if(delta == 15 && length != 15){
msg.raw__message() = str;
return 1;
}
position++;
if(delta == 15 && length == 15){
payload_marker = true;
}else{
msg.msg().options()()[count_of_options].option__delta() = delta;
msg.msg().options()()[count_of_options].option__length() = length;
//optional delta
int opt_delta = 0;
if(delta == 13){
delta = str_ptr[position] + 13;
opt_delta = str_ptr[position];
position++;
}else if(delta == 14){
delta = (str_ptr[position] << 8) + str_ptr[position+1] + 269;
opt_delta = (str_ptr[position] << 8) + str_ptr[position+1];
position += 2;
}
//optional length
int opt_length = 0;
if(length == 13){
length = str_ptr[position] + 13;
opt_length = str_ptr[position];
position++;
}else if(length == 14){
length = (str_ptr[position] << 8) + str_ptr[position+1] + 269;
opt_length = (str_ptr[position] << 8) + str_ptr[position+1];
position += 2;
}else if(length == 15){
msg.raw__message() = str;
return 1;
}
if (opt_delta != 0) {
if (opt_delta >= 0 && opt_delta <= 255) {
msg.msg().options()()[count_of_options].option__delta__ext()().int__bit8() = opt_delta;
} else if (opt_delta > 255 && opt_delta <= 65335) {
msg.msg().options()()[count_of_options].option__delta__ext()().int__bit16() = opt_delta;
}
} else {
msg.msg().options()()[count_of_options].option__delta__ext() = OMIT_VALUE;
}
if (opt_length != 0) {
if (opt_length >= 0 && opt_length <= 255) {
msg.msg().options()()[count_of_options].option__length__ext()().int__bit8() = opt_length;
} else if (opt_length > 255 && opt_length <= 65335) {
msg.msg().options()()[count_of_options].option__length__ext()().int__bit16() = opt_length;
}
} else {
msg.msg().options()()[count_of_options].option__length__ext() = OMIT_VALUE;
}
//value
actual_option_code += delta;
switch(actual_option_code){
case 1:
msg.msg().options()()[count_of_options].option__value().if__match() = OCTETSTRING(length, &str_ptr[position]);
break;
case 3:
msg.msg().options()()[count_of_options].option__value().uri__host().decode_utf8(length, &str_ptr[position]);
break;
case 4:
msg.msg().options()()[count_of_options].option__value().etag() = OCTETSTRING(length, &str_ptr[position]);
break;
case 5:
msg.msg().options()()[count_of_options].option__value().if__none__match() = OCTETSTRING(0, 0);
break;
case 6:
if (length <= 1) {
msg.msg().options()()[count_of_options].option__value().observe().int__bit8().set_long_long_val(decodeInteger(str, position, length));
} else if (length <= 2) {
msg.msg().options()()[count_of_options].option__value().observe().int__bit16().set_long_long_val(decodeInteger(str, position, length));
} else if (length <= 3) {
msg.msg().options()()[count_of_options].option__value().observe().int__bit24().set_long_long_val(decodeInteger(str, position, length));
} else if (length <= 4) {
msg.msg().options()()[count_of_options].option__value().observe().int__bit32().set_long_long_val(decodeInteger(str, position, length));
}
break;
case 7:
if (length <= 1) {
msg.msg().options()()[count_of_options].option__value().uri__port().int__bit8().set_long_long_val(decodeInteger(str, position, length));
} else if (length >= 2) {
msg.msg().options()()[count_of_options].option__value().uri__port().int__bit16().set_long_long_val(decodeInteger(str, position, length));
}
break;
case 8:
msg.msg().options()()[count_of_options].option__value().location__path().decode_utf8(length, &str_ptr[position]);
break;
case 11:
msg.msg().options()()[count_of_options].option__value().uri__path().decode_utf8(length, &str_ptr[position]);
break;
case 12:
if (length <= 1) {
msg.msg().options()()[count_of_options].option__value().content__format().int__bit8().set_long_long_val(decodeInteger(str, position, length));
} else if (length >= 2) {
msg.msg().options()()[count_of_options].option__value().content__format().int__bit16().set_long_long_val(decodeInteger(str, position, length));
}
break;
case 14:
if (length <= 1) {
msg.msg().options()()[count_of_options].option__value().max__age().int__bit8().set_long_long_val(decodeInteger(str, position, length));
} else if (length <= 2) {
msg.msg().options()()[count_of_options].option__value().max__age().int__bit16().set_long_long_val(decodeInteger(str, position, length));
} else if (length <= 3) {
msg.msg().options()()[count_of_options].option__value().max__age().int__bit24().set_long_long_val(decodeInteger(str, position, length));
} else if (length <= 4) {
msg.msg().options()()[count_of_options].option__value().max__age().int__bit32().set_long_long_val(decodeInteger(str, position, length));
}
break;
case 15:
msg.msg().options()()[count_of_options].option__value().uri__query().decode_utf8(length, &str_ptr[position]);
break;
case 17:
if (length <= 1) {
msg.msg().options()()[count_of_options].option__value().accept().int__bit8().set_long_long_val(decodeInteger(str, position, length));
} else if (length >= 2) {
msg.msg().options()()[count_of_options].option__value().accept().int__bit16().set_long_long_val(decodeInteger(str, position, length));
}
break;
case 20:
msg.msg().options()()[count_of_options].option__value().location__query().decode_utf8(length, &str_ptr[position]);
break;
case 23: // Block2 RFC 7959
decodeBlock(msg.msg().options()()[count_of_options].option__value().block2(), str, position, length);
break;
case 27: // Block1 RFC 7959
decodeBlock(msg.msg().options()()[count_of_options].option__value().block1(), str, position, length);
break;
case 35:
msg.msg().options()()[count_of_options].option__value().proxy__uri().decode_utf8(length, &str_ptr[position]);
break;
case 39:
msg.msg().options()()[count_of_options].option__value().proxy__scheme().decode_utf8(length, &str_ptr[position]);
break;
case 60:
if (length <= 1) {
msg.msg().options()()[count_of_options].option__value().size1().int__bit8().set_long_long_val(decodeInteger(str, position, length));
} else if (length <= 2) {
msg.msg().options()()[count_of_options].option__value().size1().int__bit16().set_long_long_val(decodeInteger(str, position, length));
} else if (length <= 3) {
msg.msg().options()()[count_of_options].option__value().size1().int__bit24().set_long_long_val(decodeInteger(str, position, length));
} else if (length <= 4) {
msg.msg().options()()[count_of_options].option__value().size1().int__bit32().set_long_long_val(decodeInteger(str, position, length));
}
break;
default:
msg.msg().options()()[count_of_options].option__value().unknown__option().option__code() = actual_option_code;
msg.msg().options()()[count_of_options].option__value().unknown__option().option__value() = OCTETSTRING(length, &str_ptr[position]);
break;
}
position += length;
count_of_options++;
}
}
}
//payload
if(str.lengthof() > position){
msg.msg().payload()().payloadMarker() = OCTETSTRING(1, &str_ptr[position]-1);
msg.msg().payload()().payload() = OCTETSTRING(str.lengthof() - position, &str_ptr[position]);
if(msg.msg().payload()().payload().lengthof() == 0){
msg.raw__message() = str;
return 1;
}
}else{
if(payload_marker){
msg.raw__message() = str;
return 1;
}else{
msg.msg().payload() = OMIT_VALUE;
}
}
}else{
msg.raw__message() = str;
return 1;
}
if(TTCN_Logger::log_this_event(TTCN_DEBUG)){
TTCN_Logger::begin_event(TTCN_DEBUG);
TTCN_Logger::log_event("Decoded CoAP message: ");
msg.log();
TTCN_Logger::end_event();
}
return 0;
}
INTEGER
f__CoAP__enc(CoAP__Message const &msg, OCTETSTRING &str)
{
TTCN_Buffer stream;
unsigned char chr = 0;
if(TTCN_Logger::log_this_event(TTCN_DEBUG)){
TTCN_Logger::begin_event(TTCN_DEBUG);
TTCN_Logger::log_event("Encoding CoAP message: ");
msg.log();
TTCN_Logger::end_event();
}
switch(msg.get_selection()){
case CoAP__Message::ALT_raw__message:
stream.put_os(msg.raw__message());
stream.get_string(str);
return 0;
break;
case CoAP__Message::ALT_msg:
default:
break;
}
//HEADER
//version
if(0 <= msg.msg().version() && msg.msg().version() <= 3){
chr = msg.msg().version() << 6;
}else{
return 1;
}
//message type
chr += msg.msg().msg__type() << 4;
//tkl (token length)
chr += (int)(msg.msg().tkl());
stream.put_c(chr);
//code
if(msg.msg().code().class_() >= 0 && msg.msg().code().class_() <= 7){
chr = msg.msg().code().class_() << 5;
}else{
return 1;
}
if(msg.msg().code().detail() >= 0 && msg.msg().code().detail() <= 31){
chr += msg.msg().code().detail();
}else{
return 1;
}
stream.put_c(chr);
//message ID
if(msg.msg().message__id() >= 0 && msg.msg().message__id() <= 65535){
encodeInteger(stream, msg.msg().message__id(), 2);
}else{
return 1;
}
//TOKEN
stream.put_os(msg.msg().token());
//OPTIONS
if(msg.msg().options().ispresent() && msg.msg().options()().size_of() > 0){
int optionOrder[msg.msg().options()().size_of()];
int temp;
for(int i = 0; i < msg.msg().options()().size_of(); i++){
optionOrder[i] = i;
}
//determine the order of options
for(int j = 0; j < msg.msg().options()().size_of()-1; j++){
int minOptionCode = getOptionCode(msg.msg().options()()[optionOrder[j]].option__value());
int minOptionIndex = j;
for(int i = j+1; i < msg.msg().options()().size_of(); i++){
if(getOptionCode(msg.msg().options()()[optionOrder[i]].option__value()) < minOptionCode){
minOptionCode = getOptionCode(msg.msg().options()()[optionOrder[i]].option__value());
minOptionIndex = i;
}
}
temp = optionOrder[minOptionIndex];
optionOrder[minOptionIndex] = optionOrder[j];
optionOrder[j] = temp;
}
//encode options
int previousOptionCode = 0;
for(int i = 0; i < msg.msg().options()().size_of(); i++){
int delta = msg.msg().options()()[optionOrder[i]].option__delta();
int length = msg.msg().options()()[optionOrder[i]].option__length();
previousOptionCode += delta;
//first byte
if(delta >= 0 && delta <= 15){
chr = delta << 4;
} else {
return 1;
}
if(length >= 0 && length <= 15){
chr += length;
}else{
return 1;
}
stream.put_c(chr);
//optional delta
if (msg.msg().options()()[optionOrder[i]].option__delta__ext().ispresent()) {
switch(msg.msg().options()()[optionOrder[i]].option__delta__ext()().get_selection()) {
case INT__BIT8__OR__BIT16__MSB::ALT_int__bit8:
chr = (int)(msg.msg().options()()[optionOrder[i]].option__delta__ext()().int__bit8());
stream.put_c(chr);
break;
case INT__BIT8__OR__BIT16__MSB::ALT_int__bit16:
encodeInteger(stream, (int)(msg.msg().options()()[optionOrder[i]].option__delta__ext()().int__bit16()), 2);
break;
default:
return 1;
}
}
//optional length
if (msg.msg().options()()[optionOrder[i]].option__length__ext().ispresent()) {
switch(msg.msg().options()()[optionOrder[i]].option__length__ext()().get_selection()) {
case INT__BIT8__OR__BIT16__MSB::ALT_int__bit8:
chr = (int)(msg.msg().options()()[optionOrder[i]].option__length__ext()().int__bit8());
stream.put_c(chr);
break;
case INT__BIT8__OR__BIT16__MSB::ALT_int__bit16:
encodeInteger(stream, (int)(msg.msg().options()()[optionOrder[i]].option__length__ext()().int__bit16()), 2);
break;
default:
return 1;
}
}
//option value
if(length > 0){
switch(msg.msg().options()()[optionOrder[i]].option__value().get_selection()){
case CoAP__Options::ALT_if__match:
stream.put_os(msg.msg().options()()[optionOrder[i]].option__value().if__match());
break;
case CoAP__Options::ALT_uri__host:
msg.msg().options()()[optionOrder[i]].option__value().uri__host().encode_utf8(stream, false);
break;
case CoAP__Options::ALT_etag:
stream.put_os(msg.msg().options()()[optionOrder[i]].option__value().etag());
break;
case CoAP__Options::ALT_if__none__match:
stream.put_os(msg.msg().options()()[optionOrder[i]].option__value().if__none__match());
break;
case CoAP__Options::ALT_observe:
switch(msg.msg().options()()[optionOrder[i]].option__value().observe().get_selection()) {
case INT__BIT8__OR__16__OR__24__OR__32__MSB::ALT_int__bit8:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().observe().int__bit8(), length);
break;
case INT__BIT8__OR__16__OR__24__OR__32__MSB::ALT_int__bit16:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().observe().int__bit16(), length);
break;
case INT__BIT8__OR__16__OR__24__OR__32__MSB::ALT_int__bit24:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().observe().int__bit24(), length);
break;
case INT__BIT8__OR__16__OR__24__OR__32__MSB::ALT_int__bit32:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().observe().int__bit32(), length);
break;
default:
break;
}
break;
case CoAP__Options::ALT_uri__port:
switch(msg.msg().options()()[optionOrder[i]].option__value().uri__port().get_selection()) {
case INT__BIT8__OR__BIT16__MSB::ALT_int__bit8:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().uri__port().int__bit8(), length);
break;
case INT__BIT8__OR__BIT16__MSB::ALT_int__bit16:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().uri__port().int__bit16(), length);
break;
default:
break;
}
break;
case CoAP__Options::ALT_location__path:
msg.msg().options()()[optionOrder[i]].option__value().location__path().encode_utf8(stream, false);
break;
case CoAP__Options::ALT_uri__path:
msg.msg().options()()[optionOrder[i]].option__value().uri__path().encode_utf8(stream, false);
break;
case CoAP__Options::ALT_content__format:
switch(msg.msg().options()()[optionOrder[i]].option__value().content__format().get_selection()) {
case INT__BIT8__OR__BIT16__MSB::ALT_int__bit8:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().content__format().int__bit8(), length);
break;
case INT__BIT8__OR__BIT16__MSB::ALT_int__bit16:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().content__format().int__bit16(), length);
break;
default:
break;
}
break;
case CoAP__Options::ALT_max__age:
switch(msg.msg().options()()[optionOrder[i]].option__value().max__age().get_selection()) {
case INT__BIT8__OR__16__OR__24__OR__32__MSB::ALT_int__bit8:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().max__age().int__bit8(), length);
break;
case INT__BIT8__OR__16__OR__24__OR__32__MSB::ALT_int__bit16:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().max__age().int__bit16(), length);
break;
case INT__BIT8__OR__16__OR__24__OR__32__MSB::ALT_int__bit24:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().max__age().int__bit24(), length);
break;
case INT__BIT8__OR__16__OR__24__OR__32__MSB::ALT_int__bit32:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().max__age().int__bit32(), length);
break;
default:
break;
}
break;
case CoAP__Options::ALT_uri__query:
msg.msg().options()()[optionOrder[i]].option__value().uri__query().encode_utf8(stream, false);
break;
case CoAP__Options::ALT_accept:
switch(msg.msg().options()()[optionOrder[i]].option__value().accept().get_selection()) {
case INT__BIT8__OR__BIT16__MSB::ALT_int__bit8:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().accept().int__bit8(), length);
break;
case INT__BIT8__OR__BIT16__MSB::ALT_int__bit16:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().accept().int__bit16(), length);
break;
default:
break;
}
break;
case CoAP__Options::ALT_location__query:
msg.msg().options()()[optionOrder[i]].option__value().location__query().encode_utf8(stream, false);
break;
case CoAP__Options::ALT_block1:
encodeBlock(stream, msg.msg().options()()[optionOrder[i]].option__value().block1(), length);
break;
case CoAP__Options::ALT_block2:
encodeBlock(stream, msg.msg().options()()[optionOrder[i]].option__value().block2(), length);
break;
case CoAP__Options::ALT_proxy__uri:
msg.msg().options()()[optionOrder[i]].option__value().proxy__uri().encode_utf8(stream, false);
break;
case CoAP__Options::ALT_proxy__scheme:
msg.msg().options()()[optionOrder[i]].option__value().proxy__scheme().encode_utf8(stream, false);
break;
case CoAP__Options::ALT_size1:
switch(msg.msg().options()()[optionOrder[i]].option__value().size1().get_selection()) {
case INT__BIT8__OR__16__OR__24__OR__32__MSB::ALT_int__bit8:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().size1().int__bit8(), length);
break;
case INT__BIT8__OR__16__OR__24__OR__32__MSB::ALT_int__bit16:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().size1().int__bit16(), length);
break;
case INT__BIT8__OR__16__OR__24__OR__32__MSB::ALT_int__bit24:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().size1().int__bit24(), length);
break;
case INT__BIT8__OR__16__OR__24__OR__32__MSB::ALT_int__bit32:
encodeInteger(stream, msg.msg().options()()[optionOrder[i]].option__value().size1().int__bit32(), length);
break;
default:
break;
}
break;
case CoAP__Options::ALT_unknown__option:
stream.put_os(msg.msg().options()()[optionOrder[i]].option__value().unknown__option().option__value());
break;
case CoAP__Options::UNBOUND_VALUE:
default:
return 8;
break;
}
}
}
}
//PAYLOAD
if(msg.msg().payload().ispresent()){
stream.put_os(msg.msg().payload()().payloadMarker()); //payload marker
stream.put_os(msg.msg().payload()().payload());
}
TTCN_Logger::begin_event(TTCN_DEBUG);
TTCN_Logger::log_event("Encoded CoAP message: ");
stream.log();
TTCN_Logger::end_event();
stream.get_string(str);
return 0;
}
//helper functions
int getOptionCode(CoAP__Options option){
switch(option.get_selection()){
case CoAP__Options::ALT_if__match:
return 1;
break;
case CoAP__Options::ALT_uri__host:
return 3;
break;
case CoAP__Options::ALT_etag:
return 4;
break;
case CoAP__Options::ALT_if__none__match:
return 5;
break;
case CoAP__Options::ALT_observe:
return 6;
break;
case CoAP__Options::ALT_uri__port:
return 7;
break;
case CoAP__Options::ALT_location__path:
return 8;
break;
case CoAP__Options::ALT_uri__path:
return 11;
break;
case CoAP__Options::ALT_content__format:
return 12;
break;
case CoAP__Options::ALT_max__age:
return 14;
break;
case CoAP__Options::ALT_uri__query:
return 15;
break;
case CoAP__Options::ALT_accept:
return 17;
break;
case CoAP__Options::ALT_location__query:
return 20;
break;
case CoAP__Options::ALT_block1: // RFC 7959
return 27;
break;
case CoAP__Options::ALT_block2: // RFC 7959
return 23;
break;
case CoAP__Options::ALT_proxy__uri:
return 35;
break;
case CoAP__Options::ALT_proxy__scheme:
return 39;
break;
case CoAP__Options::ALT_size1:
return 60;
break;
case CoAP__Options::ALT_unknown__option:
return option.unknown__option().option__code();
break;
case CoAP__Options::UNBOUND_VALUE:
default:
TTCN_error("CoAP: Error at getOptionCode!");
break;
}
}
int getIntegerLength(const long long int value, int mode){
if(value == 0){
return 0;
}else if(value / 269 == 0){
return 1;
}else if(value / 65805 == 0){
return 2;
}else if(mode == 4 && value / 16777485 == 0){
return 3;
}else if(mode == 4 && value / 4294967296 == 0){
return 4;
}else{
TTCN_error("CoAP: Error at getIntegerLength!");
}
}
void encodeInteger(TTCN_Buffer &stream, const long long int option, const int length){
unsigned char chr;
for(int i = length-1; i > 0; i--){
chr = (option >> (8 * i)) & 255;
stream.put_c(chr);
}
chr = option & 255;
stream.put_c(chr);
}
long long int decodeInteger(OCTETSTRING const &str, const int position, const int length){
int value = 0;
for(int i = 0; i < length; i++){
value += (str[position+i].get_octet() << (8 * (length-i-1)));
}
return value;
}
// RFC 7959
int getBlockLengthForNum(const long long int num) {
if (num < 0 || num > 1048575)
TTCN_error("CoAP: Error at getBlockLengthForNum: num must larger than 0 and smaller than 1048576!");
if (num <= 15) { // 2^4-1
return 1;
}
else if (num <= 1023) { // 2^10-1
return 2;
}
else if (num <= 1048575) { // 2^20-1
return 3;
}
return 0;
}
// RFC 7959
void encodeBlock(TTCN_Buffer &stream, const BlockOption option, const int length) {
unsigned char chr;
long long int num_val = 0;
if (option.num().int__bit4().ispresent()) {
num_val = option.num().int__bit4()().get_long_long_val();
} else if (option.num().int__bit12().ispresent()) {
num_val = option.num().int__bit12()().get_long_long_val();
} else if (option.num().int__bit20().ispresent()) {
num_val = option.num().int__bit20()().get_long_long_val();
}
char szx;
szx = option.szx().get_long_long_val() & 0x07; // szx_val & 00000111b
char m;
if ((bool) option.m())
m = 0x08; // 00001000b
else
m = 0x00; // 00000000b
char num;
for(int i = length-1; i > 0; i--){
num = (num_val >> (8 * i - 4)) & 0xff;
stream.put_c(num);
}
num = (num_val << 4) & 0xf0; // num_val & 11110000b
chr = num | m | szx;
stream.put_c(chr);
}
void decodeBlock(BlockOption& block, OCTETSTRING const &str, const int position, const int length) {
int num = 0;
for(int i = 0; i < length-1; i++) {
num += (str[position+i].get_octet() << (8 * (length-i-1) - 4));
}
num += (str[position+length-1].get_octet() >> 4) & 0x0f;
int szx = 0;
szx = str[position+length-1].get_octet() & 0x07;
int m = 0;
m = str[position+length-1].get_octet() & 0x08;
if (num >= 0 && num <= 15) {
block.num().int__bit4() = INTEGER(num);
block.num().int__bit12() = OMIT_VALUE;
block.num().int__bit20() = OMIT_VALUE;
} else if (num >= 16 && num <= 4095) {
block.num().int__bit12() = INTEGER(num);
block.num().int__bit4() = OMIT_VALUE;
block.num().int__bit20() = OMIT_VALUE;
} else if (num >= 4096 && num <= 1048575) {
block.num().int__bit20() = INTEGER(num);
block.num().int__bit4() = OMIT_VALUE;
block.num().int__bit12() = OMIT_VALUE;
}
block.szx() = INTEGER(szx);
block.m() = BOOLEAN(m > 0);
}
}