diff --git a/compiler2/Value.cc b/compiler2/Value.cc index bc61a5b4f2ead17b6439713d8a3ab7406d06f5f2..fa470b3e209ecf234178f872f54beb81ed7c92b6 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -183,6 +183,7 @@ namespace Common { case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: + case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: @@ -196,6 +197,7 @@ namespace Common { case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: + case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: @@ -534,6 +536,7 @@ namespace Common { case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: + case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: @@ -547,6 +550,7 @@ namespace Common { case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: + case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: @@ -939,6 +943,7 @@ namespace Common { case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: + case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: @@ -952,6 +957,7 @@ namespace Common { case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: + case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: @@ -1726,6 +1732,7 @@ namespace Common { case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: + case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: @@ -1739,6 +1746,7 @@ namespace Common { case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: + case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: @@ -1973,6 +1981,7 @@ namespace Common { case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: + case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: @@ -1986,6 +1995,7 @@ namespace Common { case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: + case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: @@ -2342,6 +2352,7 @@ namespace Common { case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: + case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: @@ -2355,6 +2366,7 @@ namespace Common { case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: + case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: @@ -3536,6 +3548,7 @@ namespace Common { case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCVALUE_UNICHAR: case OPTYPE_ANY2UNISTR: + case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: return Type::T_USTR; case OPTYPE_INT2BIT: @@ -3550,6 +3563,7 @@ namespace Common { case OPTYPE_STR2HEX: return Type::T_HSTR; case OPTYPE_INT2OCT: + case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_CHAR2OCT: case OPTYPE_HEX2OCT: @@ -3826,6 +3840,8 @@ namespace Common { return "bit2oct()"; case OPTYPE_BIT2STR: return "bit2str()"; + case OPTYPE_BSON2JSON: + return "bson2json()"; case OPTYPE_CBOR2JSON: return "cbor2json()"; case OPTYPE_CHAR2INT: @@ -3852,6 +3868,8 @@ namespace Common { return "int2str()"; case OPTYPE_INT2UNICHAR: return "int2unichar()"; + case OPTYPE_JSON2BSON: + return "json2bson()"; case OPTYPE_JSON2CBOR: return "json2cbor()"; case OPTYPE_OCT2BIT: @@ -6994,6 +7012,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } break; case OPTYPE_OCT2BIT: + case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_OCT2HEX: case OPTYPE_OCT2STR: @@ -7111,6 +7130,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; + case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: // v1 v1=u.expr.v1; { @@ -7859,6 +7879,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_ISTEMPLATEKIND: // ti1 v2 case OPTYPE_CBOR2JSON: // v1 case OPTYPE_JSON2CBOR: // v1 + case OPTYPE_BSON2JSON: // v1 + case OPTYPE_JSON2BSON: // v1 break; case OPTYPE_TESTCASENAME: { // - if (!my_scope) FATAL_ERROR("Value::evaluate_value()"); @@ -9163,6 +9185,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_ISTEMPLATEKIND: // ti1 v2 case OPTYPE_CBOR2JSON: case OPTYPE_JSON2CBOR: + case OPTYPE_BSON2JSON: + case OPTYPE_JSON2BSON: return true; case OPTYPE_COMP_NULL: // - return false; @@ -10396,6 +10420,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: + case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: @@ -10409,6 +10434,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: + case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: @@ -10808,6 +10834,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_BIT2INT: // v1 case OPTYPE_BIT2OCT: // v1 case OPTYPE_BIT2STR: // v1 + case OPTYPE_BSON2JSON: // v1 case OPTYPE_CBOR2JSON: // v1 case OPTYPE_CHAR2INT: // v1 case OPTYPE_CHAR2OCT: // v1 @@ -10821,6 +10848,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_INT2FLOAT: // v1 case OPTYPE_INT2STR: // v1 case OPTYPE_INT2UNICHAR: // v1 + case OPTYPE_JSON2BSON: // v1 case OPTYPE_JSON2CBOR: // v1 case OPTYPE_OCT2BIT: // v1 case OPTYPE_OCT2CHAR: // v1 @@ -11212,6 +11240,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1, return create_stringRepr_predef1("bit2oct"); case OPTYPE_BIT2STR: return create_stringRepr_predef1("bit2str"); + case OPTYPE_BSON2JSON: + return create_stringRepr_predef1("bson2json"); case OPTYPE_CBOR2JSON: return create_stringRepr_predef1("cbor2json"); case OPTYPE_CHAR2INT: @@ -11236,6 +11266,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1, return create_stringRepr_predef1("int2float"); case OPTYPE_INT2STR: return create_stringRepr_predef1("int2str"); + case OPTYPE_JSON2BSON: + return create_stringRepr_predef1("json2bson"); case OPTYPE_JSON2CBOR: return create_stringRepr_predef1("json2cbor"); case OPTYPE_INT2UNICHAR: @@ -12211,6 +12243,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: + case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: @@ -12224,6 +12257,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: + case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: @@ -12518,6 +12552,9 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_BIT2STR: generate_code_expr_predef1(expr, "bit2str", u.expr.v1); break; + case OPTYPE_BSON2JSON: + generate_code_expr_predef1(expr, "bson2json", u.expr.v1); + break; case OPTYPE_CBOR2JSON: generate_code_expr_predef1(expr, "cbor2json", u.expr.v1); break; @@ -12557,6 +12594,9 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_INT2UNICHAR: generate_code_expr_predef1(expr, "int2unichar", u.expr.v1); break; + case OPTYPE_JSON2BSON: + generate_code_expr_predef1(expr, "json2bson", u.expr.v1); + break; case OPTYPE_JSON2CBOR: generate_code_expr_predef1(expr, "json2cbor", u.expr.v1); break; @@ -14665,6 +14705,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: + case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: @@ -14678,6 +14719,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: + case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: diff --git a/compiler2/Value.hh b/compiler2/Value.hh index 33282982a28095e1ce69b5a3c03d203db1a39177..66e94f7ec05d3376ddd1079baea45083a12e4a02 100644 --- a/compiler2/Value.hh +++ b/compiler2/Value.hh @@ -275,6 +275,8 @@ namespace Common { OPTYPE_CBOR2JSON, // v1 OPTYPE_JSON2CBOR, // v1 + OPTYPE_BSON2JSON, // v1 + OPTYPE_JSON2BSON, // v1 NUMBER_OF_OPTYPES // must be last }; diff --git a/compiler2/ttcn3/compiler.l b/compiler2/ttcn3/compiler.l index f97f5893b236bdc3f10d82b9b9b4e9be43be73f9..852036dddfb5b3adcd71353b96b01bde42278c61 100644 --- a/compiler2/ttcn3/compiler.l +++ b/compiler2/ttcn3/compiler.l @@ -540,6 +540,7 @@ bit2hex RETURN(bit2hexKeyword); bit2int RETURN(bit2intKeyword); bit2oct RETURN(bit2octKeyword); bit2str RETURN(bit2strKeyword); +bson2json RETURN(bson2JsonKeyword); cbor2json RETURN(cbor2JsonKeyword); char2int RETURN(char2intKeyword); char2oct RETURN(char2octKeyword); @@ -563,6 +564,7 @@ isbound RETURN(isboundKeyword); ischosen RETURN(ischosenKeyword); ispresent RETURN(ispresentKeyword); istemplatekind RETURN(istemplatekindKeyword); +json2bson RETURN(json2bsonKeyword); json2cbor RETURN(json2CborKeyword); lengthof RETURN(lengthofKeyword); oct2bit RETURN(oct2bitKeyword); diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y index 862c80520429499350c611d64dc2de37ba106866..675618d476df46927d5b474ae9911bdea39acefd 100644 --- a/compiler2/ttcn3/compiler.y +++ b/compiler2/ttcn3/compiler.y @@ -837,6 +837,7 @@ static const string anyname("anytype"); %token bit2intKeyword %token bit2octKeyword %token bit2strKeyword +%token bson2JsonKeyword %token cbor2JsonKeyword %token char2intKeyword %token char2octKeyword @@ -859,6 +860,7 @@ static const string anyname("anytype"); %token ischosenKeyword %token ispresentKeyword %token istemplatekindKeyword +%token json2bsonKeyword %token json2CborKeyword %token lengthofKeyword %token oct2bitKeyword @@ -9874,6 +9876,7 @@ PredefinedOpKeyword1: | bit2octKeyword { $$ = Value::OPTYPE_BIT2OCT; } | bit2strKeyword { $$ = Value::OPTYPE_BIT2STR; } | cbor2JsonKeyword { $$ = Value::OPTYPE_CBOR2JSON; } +| bson2JsonKeyword { $$ = Value::OPTYPE_BSON2JSON; } | char2intKeyword { $$ = Value::OPTYPE_CHAR2INT; } | char2octKeyword { $$ = Value::OPTYPE_CHAR2OCT; } | float2intKeyword { $$ = Value::OPTYPE_FLOAT2INT; } @@ -9887,6 +9890,7 @@ PredefinedOpKeyword1: | int2strKeyword { $$ = Value::OPTYPE_INT2STR; } | int2unicharKeyword { $$ = Value::OPTYPE_INT2UNICHAR; } | json2CborKeyword { $$ = Value::OPTYPE_JSON2CBOR; } +| json2bsonKeyword { $$ = Value::OPTYPE_JSON2BSON; } | oct2bitKeyword { $$ = Value::OPTYPE_OCT2BIT; } | oct2charKeyword { $$ = Value::OPTYPE_OCT2CHAR; } | oct2hexKeyword { $$ = Value::OPTYPE_OCT2HEX; } diff --git a/core/Addfunc.cc b/core/Addfunc.cc index 4d72b8b1936b1ed7876a891cf3cb45f0553091f9..5b541276e428d597f85ddf0b83b124a3094010bc 100644 --- a/core/Addfunc.cc +++ b/core/Addfunc.cc @@ -3170,3 +3170,31 @@ UNIVERSAL_CHARSTRING cbor2json(const OCTETSTRING& value) { result.decode_utf8(tok.get_buffer_length(), (const unsigned char*)tok.get_buffer()); return result; } + +UNIVERSAL_CHARSTRING bson2json(const OCTETSTRING& value) { + UNIVERSAL_CHARSTRING result; + TTCN_Buffer buff; + buff.put_os(value); + JSON_Tokenizer tok; + bson2json_coding(buff, tok, false, false); + result.decode_utf8(tok.get_buffer_length(), (const unsigned char*)tok.get_buffer()); + return result; +} + +OCTETSTRING json2bson(const UNIVERSAL_CHARSTRING& value) { + OCTETSTRING result; + TTCN_Buffer buff; + value.encode_utf8(buff); + const unsigned char* ustr = buff.get_data(); + const size_t ustr_len = buff.get_len(); + char* json_str = mcopystr((const char*)ustr); + JSON_Tokenizer tok(json_str, ustr_len); + Free(json_str); + buff.clear(); + INTEGER length = 0; + CHARSTRING cs; + bool is_special; + json2bson_coding(buff, tok, false, false, length, cs, is_special); + buff.get_string(result); + return result; +} diff --git a/core/Addfunc.hh b/core/Addfunc.hh index 11dc1a5805672e4b24cc7e8edb6c778385c5a759..04feabb154f307eff2f916b5c8e6adbeb4cf6c1b 100644 --- a/core/Addfunc.hh +++ b/core/Addfunc.hh @@ -488,4 +488,7 @@ extern OCTETSTRING decode_base64(const CHARSTRING& b64); extern OCTETSTRING json2cbor(const UNIVERSAL_CHARSTRING& value); extern UNIVERSAL_CHARSTRING cbor2json(const OCTETSTRING& value); +extern OCTETSTRING json2bson(const UNIVERSAL_CHARSTRING& value); +extern UNIVERSAL_CHARSTRING bson2json(const OCTETSTRING& value); + #endif diff --git a/core/JSON.cc b/core/JSON.cc index 354da842f1674fd5a0c38d25b52a2998326bf46a..12e85c0cd0ae72965421b65b718d647032e83f26 100644 --- a/core/JSON.cc +++ b/core/JSON.cc @@ -84,6 +84,10 @@ const TTCN_JSONdescriptor_t ENUMERATED_json_ = { FALSE, NULL, FALSE, NULL, FALSE +//////////////////////////////////////////////////////////////////////////////// +//// CBOR conversion +//////////////////////////////////////////////////////////////////////////////// + // Never use buff.get_read_data() without checking if it has enough bytes in the // buffer. const unsigned char* check_and_get_buffer(const TTCN_Buffer& buff, int bytes) { @@ -563,3 +567,944 @@ void cbor2json_coding(TTCN_Buffer& buff, JSON_Tokenizer& tok, bool in_object) { TTCN_error("Unexpected major type %i while decoding using cbor2json().", major_type); } } + + +//////////////////////////////////////////////////////////////////////////////// +//// BSON conversion +//////////////////////////////////////////////////////////////////////////////// + +const TTCN_RAWdescriptor_t bson_float_raw_ = {64,SG_NO,ORDER_MSB,ORDER_LSB,ORDER_LSB,ORDER_LSB,EXT_BIT_NO,ORDER_LSB,ORDER_LSB,TOP_BIT_INHERITED,0,0,0,8,0,NULL,-1,CharCoding::UNKNOWN}; +const TTCN_Typedescriptor_t bson_float_descr_ = { NULL, NULL, &bson_float_raw_, NULL, NULL, NULL, NULL, TTCN_Typedescriptor_t::DONTCARE }; + +// Never use buff.get_read_data() without checking if it has enough bytes in the +// buffer. +const unsigned char* check_and_get_buffer_bson(const TTCN_Buffer& buff, int bytes) { + if (bytes < 0) { + TTCN_error("Incorrect length byte received: %d, while decoding using bson2json()", bytes); + } + if (buff.get_pos() + bytes > buff.get_len()) { + TTCN_error("Not enough bytes in bytestream while decoding using bson2json()."); + } + return buff.get_read_data(); +} + +void encode_int_bson(TTCN_Buffer& buff, const INTEGER& int_num, INTEGER& length) { + if (int_num.is_native()) { // 32 bit + length = length + 4; + RInt value = (int)int_num; + for (size_t i = 0; i < 4; i++) { + buff.put_c(static_cast<unsigned char>(value >> i*8)); + } + } else { + BIGNUM* bn = BN_dup(int_num.get_val().get_val_openssl()); + INTEGER bn_length = BN_num_bytes(bn); + BN_free(bn); + long long int long_int = 0; + int bytes = 0; + if (bn_length <= 4) { // 32 bit + bytes = 4; + long_int = int_num.get_long_long_val(); + } else if (bn_length <= 8) { //64 bit + bytes = 8; + long_int = int_num.get_long_long_val(); + } else { + // The standard encodes max 64 bits + TTCN_error("An integer value which cannot be represented " + "on 64bits cannot be encoded using json2bson()"); + } + for (int i = 0; i < bytes; i++) { + buff.put_c(static_cast<unsigned char>(long_int >> i*8)); + } + length = length + bytes; + } +} + +INTEGER decode_int_bson(TTCN_Buffer& buff, int bytes) { + const unsigned char* uc = check_and_get_buffer_bson(buff, bytes); + buff.increase_pos(bytes); + if (bytes <= 4) { //32 bit + RInt value = 0; + for (size_t i = 0; i < 4; i++) { + value += uc[i] << i*8; + } + return INTEGER(value); + } else if (bytes <= 8) { + TTCN_Buffer tmp_buf; + for (int i = 0; i < bytes; i++) { + tmp_buf.put_c(uc[bytes-i-1]); + } + OCTETSTRING os; + tmp_buf.get_string(os); + INTEGER value = oct2int(os); + return value; + } else { + TTCN_error("An integer value larger than " + "64 bytes cannot be decoded using bson2json()"); + } +} + +void put_name(TTCN_Buffer& buff, INTEGER& length, CHARSTRING& name, bool in_array) { + if (in_array) { + buff.put_cs(name); + buff.put_c(0); // Closing 0 + length = length + name.lengthof() + 1; + // TODO: is it very slow? + // Increment index + INTEGER num = str2int(name); + num = num + 1; + name = int2str(num); + } else { + buff.put_cs(name); + buff.put_c(0); // Closing 0 + length = length + name.lengthof() + 1; + } +} + +void get_name(TTCN_Buffer& buff, JSON_Tokenizer& tok, bool in_array) { + const unsigned char* uc = buff.get_read_data(); + // Copy until closing 0 + char* tmp_str = mcopystr(reinterpret_cast<const char*>(uc)); + if (in_array == false) { // We dont need name when in array + tok.put_next_token(JSON_TOKEN_NAME, tmp_str); + } + buff.increase_pos(strlen(tmp_str)+1); + Free(tmp_str); +} + +bool encode_bson_binary(TTCN_Buffer& buff, JSON_Tokenizer& tok, INTEGER& length) { + char *content; + size_t len; + json_token_t token; + // Check if this is really binary + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_STRING) { + return false; + } + CHARSTRING cs2(len-2, content+1); + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_NAME) { + return false; + } + CHARSTRING cs3(len, content); + if (cs3 != "$type") { + return false; + } + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_STRING) { + return false; + } + CHARSTRING cs4(len-2, content+1); + if (cs4.lengthof() != 2) { + return false; + } + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + + buff.put_c(5); + length = length + 1; + // We do not know the name here. It will be inserted later. + OCTETSTRING os = decode_base64(cs2); + INTEGER os_len = os.lengthof(); + encode_int_bson(buff, os_len, length); + unsigned int type = 0; + if (sscanf((const char*)cs4, "%02x", &type) != 1) { + TTCN_error("Incorrect binary format while encoding with json2bson()"); + } + buff.put_c(type); + length = length + 1; + buff.put_os(os); + length = length + os_len; + return true; +} + +bool encode_bson_date(TTCN_Buffer& buff, JSON_Tokenizer& tok, INTEGER& length) { + char *content; + size_t len; + json_token_t token; + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_START) { + return false; + } + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_NAME) { + return false; + } + CHARSTRING cs(len, content); + if (cs != "$numberLong") { + return false; + } + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_NUMBER) { + return false; + } + CHARSTRING cs2(len, content); + + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + INTEGER int_num = str2int(cs2); + buff.put_c(9); // datetime + length = length + 1; + // We do not know the name here. It will be inserted later. + // Encode on 64 bit + long long int long_int = int_num.get_long_long_val(); + for (int i = 0; i < 8; i++) { + buff.put_c(static_cast<unsigned char>(long_int >> i*8)); + } + length = length + 8; + return true; +} + + +bool encode_bson_timestamp(TTCN_Buffer& buff, JSON_Tokenizer& tok, INTEGER& length) { + char *content; + size_t len; + json_token_t token; + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_START) { + return false; + } + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_NAME) { + return false; + } + CHARSTRING cs(len, content); + if (cs != "t") { + return false; + } + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_NUMBER) { + return false; + } + CHARSTRING cs2(len, content); + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_NAME) { + return false; + } + CHARSTRING cs3(len, content); + if (cs3 != "i") { + return false; + } + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_NUMBER) { + return false; + } + CHARSTRING cs4(len, content); + + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + INTEGER timestamp = str2int(cs2); + INTEGER increment = str2int(cs4); + buff.put_c(17); + length = length + 1; + // We do not know the name here. It will be inserted later. + encode_int_bson(buff, increment, length); + encode_int_bson(buff, timestamp, length); + return true; +} + +bool encode_bson_regex(TTCN_Buffer& buff, JSON_Tokenizer& tok, INTEGER& length) { + char *content; + size_t len; + json_token_t token; + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_STRING) { + return false; + } + CHARSTRING regex(len-2, content+1); + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_NAME) { + return false; + } + CHARSTRING cs2(len, content); + if (cs2 != "$options") { + return false; + } + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_STRING) { + return false; + } + CHARSTRING options(len-2, content+1); + + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + + buff.put_c(11); + length = length + 1; + // We do not know the name here. It will be inserted later. + buff.put_cs(regex); + length = length + regex.lengthof(); + buff.put_c(0); // Closing 0 + length = length + 1; + buff.put_cs(options); + length = length + options.lengthof(); + buff.put_c(0); // Closing 0 + length = length + 1; + return true; +} + +bool encode_bson_oid(TTCN_Buffer& buff, JSON_Tokenizer& tok, INTEGER& length) { + char *content; + size_t len; + json_token_t token; + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_STRING) { + return false; + } + CHARSTRING id(len-2, content+1); + if (id.lengthof() != 24) { + return false; + } + + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + + buff.put_c(7); + length = length + 1; + // We do not know the name here. It will be inserted later. + unsigned char hex[12]; + for (size_t i = 0; i < 24; i = i + 2) { + if (sscanf(((const char*)id)+i, "%02x", (unsigned int*)&(hex[i/2])) != 1) { + TTCN_error("Incorrect binary format while encoding with json2bson()"); + } + } + buff.put_s(12, hex); + length = length + 12; + return true; +} + +bool encode_bson_ref(TTCN_Buffer& buff, JSON_Tokenizer& tok, INTEGER& length) { + char *content; + size_t len; + json_token_t token; + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_STRING) { + return false; + } + CHARSTRING name(len-2, content+1); + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_NAME) { + return false; + } + CHARSTRING cs(len, content); + if (cs != "$id") { + return false; + } + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_STRING) { + return false; + } + CHARSTRING id(len-2, content+1); + if (id.lengthof() != 24) { + return false; + } + + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + + buff.put_c(12); + length = length + 1; + // We do not know the name here. It will be inserted later. + INTEGER name_length = name.lengthof()+1; + encode_int_bson(buff, name_length, length); + buff.put_cs(name); + buff.put_c(0); // Closing 0 + length = length + name_length; + unsigned char hex[12]; + for (size_t i = 0; i < 24; i = i + 2) { + if (sscanf(((const char*)id)+i, "%02x", (unsigned int*)&(hex[i/2])) != 1) { + TTCN_error("Incorrect binary format while encoding with json2bson()"); + } + } + buff.put_s(12, hex); + length = length + 12; + return true; +} + +bool encode_bson_undefined(TTCN_Buffer& buff, JSON_Tokenizer& tok, INTEGER& length) { + char *content; + size_t len; + json_token_t token; + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_LITERAL_TRUE) { + return false; + } + + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + + buff.put_c(6); + length = length + 1; + // We do not know the name here. It will be inserted later. + return true; +} + +bool encode_bson_minkey(TTCN_Buffer& buff, JSON_Tokenizer& tok, INTEGER& length) { + char *content; + size_t len; + json_token_t token; + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_NUMBER) { + return false; + } + CHARSTRING cs(len, content); + if (cs != "1") { + return false; + } + + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + + buff.put_c(255); + length = length + 1; + // We do not know the name here. It will be inserted later. + return true; +} + +bool encode_bson_maxkey(TTCN_Buffer& buff, JSON_Tokenizer& tok, INTEGER& length) { + char *content; + size_t len; + json_token_t token; + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_NUMBER) { + return false; + } + CHARSTRING cs(len, content); + if (cs != "1") { + return false; + } + + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + + buff.put_c(127); + length = length + 1; + // We do not know the name here. It will be inserted later. + return true; +} + +bool encode_bson_numberlong(TTCN_Buffer& buff, JSON_Tokenizer& tok, INTEGER& length) { + char *content; + size_t len; + json_token_t token; + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_STRING) { + return false; + } + CHARSTRING cs(len-2, content+1); + + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + + buff.put_c(18); + length = length + 1; + // We do not know the name here. It will be inserted later. + INTEGER number = str2int(cs); + long long int value = number.get_long_long_val(); + for (int i = 0; i < 8; i++) { + buff.put_c(static_cast<unsigned char>(value >> i*8)); + } + length = length + 8; + return true; +} + +bool encode_bson_code_with_scope(TTCN_Buffer& buff, JSON_Tokenizer& tok, INTEGER& length) { + char *content; + size_t len; + json_token_t token; + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_STRING) { + return false; + } + CHARSTRING cs(len-2, content+1); + + tok.get_next_token(&token, &content, &len); + if (token != JSON_TOKEN_NAME) { + return false; + } + CHARSTRING cs2(len, content); + if (cs2 != "$scope") { + return false; + } + + INTEGER code_w_scope_length = 0; + bool is_special = false; + CHARSTRING f_name; + TTCN_Buffer sub_buff; + json2bson_coding(sub_buff, tok, false, false, code_w_scope_length, f_name, is_special); + + tok.get_next_token(&token, NULL, NULL); + if (token != JSON_TOKEN_OBJECT_END) { + return false; + } + + buff.put_c(15); + length = length + 1; + // We do not know the name here. It will be inserted later. + code_w_scope_length = code_w_scope_length + cs.lengthof() + 4 + 1; + encode_int_bson(buff, code_w_scope_length, code_w_scope_length); + encode_int_bson(buff, cs.lengthof()+1, length); + buff.put_string(cs); + buff.put_c(0); // Closing 0 + buff.put_buf(sub_buff); + length = length + code_w_scope_length - 4; // We added the length of cs twice + return true; +} + + +void json2bson_coding(TTCN_Buffer& buff, JSON_Tokenizer& tok, bool in_object, + bool in_array, INTEGER& length, CHARSTRING& obj_name, bool& is_special) { + json_token_t token; + char* content = NULL; + size_t len; + size_t prev_pos = tok.get_buf_pos(); + tok.get_next_token(&token, &content, &len); + if (in_object == false && token != JSON_TOKEN_OBJECT_START) { + TTCN_error("Json document must be an object when encoding with json2bson()"); + } + switch(token) { + case JSON_TOKEN_OBJECT_START: { + TTCN_Buffer sub_buff; + INTEGER sub_len = 0; + CHARSTRING subobj_name; + if (obj_name.is_bound()) { + subobj_name = obj_name; + } + while ((prev_pos = tok.get_buf_pos(), tok.get_next_token(&token, NULL, NULL))) { + if (token != JSON_TOKEN_OBJECT_END) { + tok.set_buf_pos(prev_pos); + json2bson_coding(sub_buff, tok, true, false, sub_len, subobj_name, is_special); + // We found a specially translated json + if (is_special) { + // The sub_buff contains the encoded bson except the obj_name. + // We put it in here after the first byte + TTCN_Buffer tmp_buff; + tmp_buff.put_c(*(sub_buff.get_data())); + put_name(tmp_buff, sub_len, subobj_name, in_array); + tmp_buff.put_s(sub_buff.get_len()-1, sub_buff.get_data()+1); + sub_buff = tmp_buff; + in_object = false; + break; + } + } else { + sub_buff.put_c(0);// Closing zero + sub_len = sub_len + 1; + break; + } + } + + if (in_object == true) { + TTCN_Buffer tmp_buff; + tmp_buff.put_c(3); // embedded document + length = length + 1; + put_name(tmp_buff, length, obj_name, in_array); + encode_int_bson(tmp_buff, sub_len, sub_len); + length = length + sub_len; + tmp_buff.put_buf(sub_buff); + sub_buff = tmp_buff; + } else if (is_special == false) { + length = length + sub_len; + encode_int_bson(buff, length, length); + } else { + length = length + sub_len; + is_special = false; + } + buff.put_buf(sub_buff); + break; + } + case JSON_TOKEN_OBJECT_END: + TTCN_error("Unexpected object end character while encoding using json2bson()."); + break; + case JSON_TOKEN_NAME: { + CHARSTRING cs(len, content); + prev_pos = tok.get_buf_pos(); + if (cs == "$binary") { + is_special = encode_bson_binary(buff, tok, length); + } else if (cs == "$date") { + is_special = encode_bson_date(buff, tok, length); + } else if (cs == "$timestamp") { + is_special = encode_bson_timestamp(buff, tok, length); + } else if (cs == "$regex") { + is_special = encode_bson_regex(buff, tok, length); + } else if (cs == "$oid") { + is_special = encode_bson_oid(buff, tok, length); + } else if (cs == "$ref") { + is_special = encode_bson_ref(buff, tok, length); + } else if (cs == "$undefined") { + is_special = encode_bson_undefined(buff, tok, length); + } else if (cs == "$minKey") { + is_special = encode_bson_minkey(buff, tok, length); + } else if (cs == "$maxKey") { + is_special = encode_bson_maxkey(buff, tok, length); + } else if (cs == "$numberLong") { + is_special = encode_bson_numberlong(buff, tok, length); + } else if (cs == "$code") { + is_special = encode_bson_code_with_scope(buff, tok, length); + } else { + obj_name = cs; + } + if (!is_special) { + tok.set_buf_pos(prev_pos); + obj_name = cs; + } + break; } + case JSON_TOKEN_STRING: { + buff.put_c(2); // string + length = length + 1; + put_name(buff, length, obj_name, in_array); + encode_int_bson(buff, len-1, length); // Remove "-s but add terminating null + char * tmp_str = mcopystrn(content+1, len-2); // Remove "-s + buff.put_string(tmp_str); + buff.put_c(0); // Closing 0 + length = length + (int)len-1; // Remove "-s but add terminating null + Free(tmp_str); + break; } + case JSON_TOKEN_NUMBER: { + char *str = mcopystrn(content, len); + size_t curr_pos = tok.get_buf_pos(); + tok.set_buf_pos(prev_pos); + bool is_float = false; + tok.check_for_number(&is_float); + tok.set_buf_pos(curr_pos); + if (is_float) { + buff.put_c(1); // 64bit float + put_name(buff, length, obj_name, in_array); + double d; + sscanf(str, "%lf", &d); + FLOAT f = d; + f.encode(bson_float_descr_, buff, TTCN_EncDec::CT_RAW); + } else { + INTEGER int_num = str2int(str); + if (int_num.is_native()) { + buff.put_c(16); //32bit integer + length = length + 1; + } else { + buff.put_c(18); // 64bit integer + length = length + 1; + } + put_name(buff, length, obj_name, in_array); + encode_int_bson(buff, int_num, length); + } + Free(str); + break; } + case JSON_TOKEN_LITERAL_FALSE: { + buff.put_c(8); // true or false + put_name(buff, length, obj_name, in_array); + buff.put_c(0); // false + break; } + case JSON_TOKEN_LITERAL_TRUE: { + buff.put_c(8); // true or false + put_name(buff, length, obj_name, in_array); + buff.put_c(1); // true + break; } + case JSON_TOKEN_LITERAL_NULL: { + buff.put_c(10); // null + put_name(buff, length, obj_name, in_array); + break; } + case JSON_TOKEN_ARRAY_START: { + buff.put_c(4); // array + length = length + 1; + put_name(buff, length, obj_name, in_array); + obj_name = "0"; // arrays are objects but the key is a number which increases + TTCN_Buffer sub_buff; + INTEGER sub_length = 0; + while ((prev_pos = tok.get_buf_pos(), tok.get_next_token(&token, NULL, NULL))) { + if (token != JSON_TOKEN_ARRAY_END) { + tok.set_buf_pos(prev_pos); + in_array = true; + json2bson_coding(sub_buff, tok, in_object, in_array, sub_length, obj_name, is_special); + } else { + sub_buff.put_c(0);// Closing zero + sub_length = sub_length + 1; + break; + } + } + encode_int_bson(buff, sub_length, sub_length); + length = length + sub_length; + buff.put_buf(sub_buff); + break; } + default: + TTCN_error("Unexpected json token %i, while encoding using json2bson().", token); + } +} + +void bson2json_coding(TTCN_Buffer& buff, JSON_Tokenizer& tok, bool in_object, bool in_array) { + INTEGER length = 0; + // Beginning of the document + if (in_object == false) { + length = decode_int_bson(buff, 4); + // Check if the input is long enough + check_and_get_buffer_bson(buff, length-4); + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + while (*(check_and_get_buffer_bson(buff, 1)) != 0) { + bson2json_coding(buff, tok, true, in_array); + } + buff.increase_pos(1); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + } else { + const unsigned char* type = check_and_get_buffer_bson(buff, 1); + buff.increase_pos(1); + // There is always a name + get_name(buff, tok, in_array); + switch(*type) { + case 0: // document end + TTCN_error("Unexpected document end character while decoding with bson2json()"); + break; + case 1: { // 64bit float + FLOAT f; + check_and_get_buffer_bson(buff, 8); + f.decode(bson_float_descr_, buff, TTCN_EncDec::CT_RAW); + f.JSON_encode(bson_float_descr_, tok); + break; + } + case 13: // Javascript code. Decoded as string + case 14: // Symbol. Decoded as string + case 2: { // UTF8 string + INTEGER len = decode_int_bson(buff, 4); + // Get the value of the pair + const unsigned char* uc = check_and_get_buffer_bson(buff, (int)len); + char *tmp_str = mcopystrn(reinterpret_cast<const char*>(uc), (int)len); + buff.increase_pos((int)len); + char* tmp_str2 = mprintf("\"%s\"", tmp_str); + tok.put_next_token(JSON_TOKEN_STRING, tmp_str2); + Free(tmp_str2); + Free(tmp_str); + break; } + case 3: { // Embedded document + length = decode_int_bson(buff, 4); + // Check if the input is long enough + check_and_get_buffer_bson(buff, length-4); + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + while (*(check_and_get_buffer_bson(buff, 1)) != 0) { // error message while converting + bson2json_coding(buff, tok, in_object, false); + } + buff.increase_pos(1); // Skip the closing 0 + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + break; } + case 4: { // array + length = decode_int_bson(buff, 4); + // Check if the input is long enough + check_and_get_buffer_bson(buff, length-4); + tok.put_next_token(JSON_TOKEN_ARRAY_START, NULL); + in_array = true; + while (*(check_and_get_buffer_bson(buff, 1)) != 0) { // erorr message while converting + bson2json_coding(buff, tok, in_object, in_array); + } + buff.increase_pos(1); // Skip the closing 0 + tok.put_next_token(JSON_TOKEN_ARRAY_END, NULL); + break; } + case 5: { // bytestring + // decode bytestring length + INTEGER bytestr_length = decode_int_bson(buff, 4); + OCTETSTRING os(1, check_and_get_buffer_bson(buff, 1)); + buff.increase_pos(1); + INTEGER typestr_type = oct2int(os); + char* str_type = mprintf("\"%02x\"", (int)typestr_type); + OCTETSTRING data(bytestr_length, check_and_get_buffer_bson(buff, bytestr_length)); + buff.increase_pos(bytestr_length); + CHARSTRING cs = encode_base64(data); + char* data_str = mprintf("\"%s\"", (const char*)cs); + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + tok.put_next_token(JSON_TOKEN_NAME, "$binary"); + tok.put_next_token(JSON_TOKEN_STRING, data_str); + tok.put_next_token(JSON_TOKEN_NAME, "$type"); + tok.put_next_token(JSON_TOKEN_STRING, str_type); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + Free(data_str); + Free(str_type); + break; } + case 6: { // undefined + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + tok.put_next_token(JSON_TOKEN_NAME, "$undefined"); + tok.put_next_token(JSON_TOKEN_LITERAL_TRUE); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + break; } + case 7: { // oid + OCTETSTRING os(12, check_and_get_buffer_bson(buff, 12)); + char* tmp_oct = NULL; + for (size_t i = 0; i < 12; i++) { + tmp_oct = mputprintf(tmp_oct, "%02X", os[i].get_octet()); + } + char *str_hex = mprintf("\"%s\"", tmp_oct); + buff.increase_pos(12); + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + tok.put_next_token(JSON_TOKEN_NAME, "$oid"); + tok.put_next_token(JSON_TOKEN_STRING, str_hex); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + Free(str_hex); + Free(tmp_oct); + break; } + case 8: { // true or false + const unsigned char* uc = check_and_get_buffer_bson(buff, 1); + if (*uc == 0) { + tok.put_next_token(JSON_TOKEN_LITERAL_FALSE, NULL); + } else { + tok.put_next_token(JSON_TOKEN_LITERAL_TRUE, NULL); + } + buff.increase_pos(1); + break; + } + case 9: { // datetime + INTEGER date = decode_int_bson(buff, 8); + char *tmp_str = mprintf("%lld", date.get_long_long_val()); + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + tok.put_next_token(JSON_TOKEN_NAME, "$date"); + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + tok.put_next_token(JSON_TOKEN_NAME, "$numberLong"); + tok.put_next_token(JSON_TOKEN_NUMBER, tmp_str); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + Free(tmp_str); + break; } + case 10: { // null + tok.put_next_token(JSON_TOKEN_LITERAL_NULL, NULL); + break; + } + case 11: { // regex + // copy until closing 0 + const unsigned char* uc = check_and_get_buffer_bson(buff, 1); + char *tmp_str = mcopystr(reinterpret_cast<const char*>(uc)); + buff.increase_pos(strlen(tmp_str)+1); + char *regex = mprintf("\"%s\"", tmp_str); + Free(tmp_str); + uc = check_and_get_buffer_bson(buff, 1); + tmp_str = mcopystr(reinterpret_cast<const char*>(uc)); + buff.increase_pos(strlen(tmp_str)+1); + char *options = mprintf("\"%s\"", tmp_str); + Free(tmp_str); + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + tok.put_next_token(JSON_TOKEN_NAME, "$regex"); + tok.put_next_token(JSON_TOKEN_STRING, regex); + tok.put_next_token(JSON_TOKEN_NAME, "$options"); + tok.put_next_token(JSON_TOKEN_STRING, options); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + Free(options); + Free(regex); + break; } + case 12: { // dbref + INTEGER name_len = decode_int_bson(buff, 4); + const unsigned char* uc = check_and_get_buffer_bson(buff, (int)name_len); + char *tmp_name = mcopystrn(reinterpret_cast<const char*>(uc), (int)name_len); + buff.increase_pos((int)name_len); + char* tmp_str = mprintf("\"%s\"", tmp_name); + OCTETSTRING os(12, check_and_get_buffer_bson(buff, 12)); + buff.increase_pos(12); + char* tmp_oct = NULL; + for (size_t i = 0; i < 12; i++) { + tmp_oct = mputprintf(tmp_oct, "%02X", os[i].get_octet()); + } + char *str_hex = mprintf("\"%s\"", tmp_oct); + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + tok.put_next_token(JSON_TOKEN_NAME, "$ref"); + tok.put_next_token(JSON_TOKEN_STRING, tmp_str); + tok.put_next_token(JSON_TOKEN_NAME, "$id"); + tok.put_next_token(JSON_TOKEN_STRING, str_hex); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + Free(tmp_oct); + Free(str_hex); + Free(tmp_str); + Free(tmp_name); + break; } + case 15: { // code_with_scope + INTEGER len = decode_int_bson(buff, 4); + check_and_get_buffer_bson(buff, (int)len-4); // len contains the length of itself + len = decode_int_bson(buff, 4); + const unsigned char* uc = check_and_get_buffer_bson(buff, (int)len); + char *tmp_str = mcopystrn(reinterpret_cast<const char*>(uc), (int)len); + char *tmp_str2 = mprintf("\"%s\"", tmp_str); + buff.increase_pos((int)len); + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + tok.put_next_token(JSON_TOKEN_NAME, "$code"); + tok.put_next_token(JSON_TOKEN_STRING, tmp_str2); + tok.put_next_token(JSON_TOKEN_NAME, "$scope"); + bson2json_coding(buff, tok, false, false); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + Free(tmp_str2); + Free(tmp_str); + break; } + case 16: { // 32bit integer + INTEGER value = decode_int_bson(buff, 4); + char *tmp_str = mprintf("%d", (int)value); + tok.put_next_token(JSON_TOKEN_NUMBER, tmp_str); + Free(tmp_str); + break; } + case 17: { // timestamp + INTEGER increment = decode_int_bson(buff, 4); + INTEGER timestamp = decode_int_bson(buff, 4); + char *increment_str = mprintf("%i", (int)increment); + char *timestamp_str = mprintf("%i", (int)timestamp); + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + tok.put_next_token(JSON_TOKEN_NAME, "$timestamp"); + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + tok.put_next_token(JSON_TOKEN_NAME, "t"); + tok.put_next_token(JSON_TOKEN_STRING, timestamp_str); + tok.put_next_token(JSON_TOKEN_NAME, "i"); + tok.put_next_token(JSON_TOKEN_STRING, increment_str); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + Free(timestamp_str); + Free(increment_str); + break; } + case 18: { //64 bit integer + INTEGER value = decode_int_bson(buff, 8); + char *tmp_str = mprintf("%lld", value.get_long_long_val()); + tok.put_next_token(JSON_TOKEN_NUMBER, tmp_str); + Free(tmp_str); + break; } + case 127: { // maxkey + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + tok.put_next_token(JSON_TOKEN_NAME, "$maxKey"); + tok.put_next_token(JSON_TOKEN_NUMBER, "1"); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + break; } + case 255: { // minkey + tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL); + tok.put_next_token(JSON_TOKEN_NAME, "$minKey"); + tok.put_next_token(JSON_TOKEN_NUMBER, "1"); + tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL); + break; } + default: + TTCN_error("Unexpected type %i while decoding using bson2json().", *type); + } + } +} \ No newline at end of file diff --git a/core/JSON.hh b/core/JSON.hh index 767ae6ed636e201ae0bee630908f548674b26ce4..050df32201b2f08230b811674f156f2192cfa3b4 100644 --- a/core/JSON.hh +++ b/core/JSON.hh @@ -18,6 +18,8 @@ class TTCN_Buffer; class JSON_Tokenizer; +class CHARSTRING; +class INTEGER; /** Descriptor for JSON encoding/decoding during runtime */ struct TTCN_JSONdescriptor_t @@ -145,5 +147,9 @@ enum json_metainfo_t { void json2cbor_coding(TTCN_Buffer& buff, JSON_Tokenizer& tok, size_t& num_of_items); void cbor2json_coding(TTCN_Buffer& buff, JSON_Tokenizer& tok, bool in_object); +// Functions for conversion between json and bson and vice versa +void json2bson_coding(TTCN_Buffer& buff, JSON_Tokenizer& tok, bool in_object, bool in_array, INTEGER& length, CHARSTRING& f_name, bool& is_special); +void bson2json_coding(TTCN_Buffer& buff, JSON_Tokenizer& tok, bool in_object, bool in_array); + #endif /* JSON_HH_ */ diff --git a/regression_test/json/.gitignore b/regression_test/json/.gitignore index 47c5b42d6270c35a865a96183f953782ad234260..c04239387d25a26efaaea4ed1d30e94c0b34f127 100644 --- a/regression_test/json/.gitignore +++ b/regression_test/json/.gitignore @@ -16,5 +16,7 @@ Types*.cc Types*.hh Cbor*.cc Cbor*.hh +Bson*.cc +Bson*.hh logs compile diff --git a/regression_test/json/Bson.ttcn b/regression_test/json/Bson.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..028d1c93ed95821fb25847d025f69adca4ee059e --- /dev/null +++ b/regression_test/json/Bson.ttcn @@ -0,0 +1,580 @@ +module Bson { + + type component EmptyCT { + + } + + testcase tc_bson_encdec() runs on EmptyCT { + var octetstring os, expected_os; + var universal charstring json, decoded, decoded_json; + + json := "{}" + expected_os := '0500000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":\"b\"}" + expected_os := '0E00000002610002000000620000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"aaaab\":\"bbbbbbc\"}" + expected_os := '180000000261616161620008000000626262626262630000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"ááá\":\"óóó\"}" + expected_os := '1800000002C3A1C3A1C3A10007000000C3B3C3B3C3B30000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":\"b\",\"c\":\"d\"}" + expected_os := '1700000002610002000000620002630002000000640000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":1}" + expected_os := '0C0000001061000100000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":15614615}" + expected_os := '0E00000010616263009742EE0000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":-15614615}" + expected_os := '0E000000106162630069BD11FF00'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + + json := "{\"abc\":4586797657}" + expected_os := '12000000126162630059FA64110100000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":-4586797657}" + expected_os := '120000001261626300A7059BEEFEFFFFFF00'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":1.120000}" + expected_os := '090000000161626300EC51B81E85EBF13F00'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":-11321.120465}" + expected_os := '090000000161626300A8A9656B8F1CC6C000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":true}" + expected_os := '0900000008616263000100'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":false}" + expected_os := '0900000008616263000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":null}" + expected_os := '090000000A6162630000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":[1]}" + expected_os := '1600000004616263000C000000103000010000000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":[1,2,\"abc\"]}" + expected_os := '2800000004616263001E000000103000010000001031000200000002320004000000616263000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":[1,2,[3,4],\"abc\"]}" + expected_os := '3E00000004616263003400000010300001000000103100020000000432001300000010300003000000103100040000000002320004000000616263000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":{\"def\":4}}" + expected_os := '1800000003616263000E0000001064656600040000000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":{\"a\":[2]}}" + expected_os := '1E0000000361626300140000000461000C00000010300002000000000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":[2,{\"a\":4}]}" + expected_os := '2500000004616263001B000000103000020000000331000C00000010610004000000000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"abc\":{\"def\":4,\"dd\":[1,2,3,{\"q\":3},3]},\"w\":[{\"a\":3}]}" + expected_os := '6300000003616263004200000010646566000400000004646400300000001030000100000010310002000000103200030000000333000C0000001071000300000000103400030000000000047700140000000330000C00000010610003000000000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + + // Special cases + + json := "{\"a\":{\"$binary\":\"VEVTVCBUM1NU\",\"$type\":\"01\"}}" + expected_os := '16000000056100090000000154455354205433535400'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":{\"$binary\":\"VEVTVCBUM1NU\",\"$type\":\"01\"},\"b\":3}" + expected_os := '1D00000005610009000000015445535420543353541062000300000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":[{\"$binary\":\"VEVTVCBUM1NU\",\"$type\":\"01\"}],\"b\":3}" + expected_os := '25000000046100160000000530000900000001544553542054335354001062000300000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"b\":[{\"a\":[{\"$binary\":\"VEVTVCBUM1NU\",\"$type\":\"01\"}],\"b\":3}],\"c\":4532}" + expected_os := '3C0000000462002D0000000330002500000004610016000000053000090000000154455354205433535400106200030000000000106300B411000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":{\"$date\":{\"$numberLong\":345}}}" + expected_os := '10000000096100590100000000000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":[{\"$date\":{\"$numberLong\":345}}],\"b\":3}" + expected_os := '1F000000046100100000000930005901000000000000001062000300000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"b\":[{\"a\":[{\"$binary\":\"VEVTVCBUM1NU\",\"$type\":\"01\"},{\"$date\":{\"$numberLong\":34654776445}}],\"b\":3}],\"c\":4532}" + expected_os := '4700000004620038000000033000300000000461002100000005300009000000015445535420543353540930007DEC95110800000000106200030000000000106300B411000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":{\"$timestamp\":{\"t\":123,\"i\":456}}}" + expected_os := '10000000116100C80100007B00000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":[{\"$timestamp\":{\"t\":123,\"i\":456}}],\"b\":3}" + expected_os := '1F00000004610010000000113000C80100007B000000001062000300000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":{\"$regex\":\"myregex\",\"$options\":\"gim\"}}" + expected_os := '140000000b61006d7972656765780067696d0000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":[{\"$regex\":\"myregex\",\"$options\":\"gim\"}],\"b\":3}" + expected_os := '23000000046100140000000B30006D7972656765780067696D00001062000300000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":{\"$oid\":\"123456789ABCDEF123456789\"}}" + expected_os := '14000000076100123456789ABCDEF12345678900'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":[{\"$oid\":\"123456789ABCDEF123456789\"}],\"b\":3}" + expected_os := '2300000004610014000000073000123456789ABCDEF123456789001062000300000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":{\"$ref\":\"myname\",\"$id\":\"123456789ABCDEF123456789\"}}" + expected_os := '1F0000000C6100070000006D796E616D6500123456789ABCDEF12345678900'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":[{\"$ref\":\"myname\",\"$id\":\"123456789ABCDEF123456789\"}],\"b\":3}" + expected_os := '2E0000000461001F0000000C3000070000006D796E616D6500123456789ABCDEF123456789001062000300000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":{\"$undefined\":true}}" + expected_os := '0800000006610000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":[{\"$undefined\":true}],\"b\":3}" + expected_os := '1700000004610008000000063000001062000300000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":{\"$minKey\":1}}" + expected_os := '08000000FF610000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":[{\"$minKey\":1}],\"b\":3}" + expected_os := '1700000004610008000000FF3000001062000300000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":{\"$maxKey\":1}}" + expected_os := '080000007F610000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":[{\"$maxKey\":1}],\"b\":3}" + expected_os := '17000000046100080000007F3000001062000300000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + // Bad maxkey, encode as embedded document + json := "{\"a\":{\"$maxKey\":2}}" + expected_os := '1A0000000361001200000010246D61784B657900020000000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":{\"$numberLong\":\"123\"}}" + expected_os := '100000001261007B0000000000000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded_json := "{\"a\":123}" + decoded := bson2json(os); + if (not match(decoded, decoded_json)) { + setverdict(fail, match(decoded, decoded_json)); + } + + json := "{\"a\":{\"$numberLong\":\"12332232323232\"}}" + expected_os := '10000000126100A0B05352370B000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded_json := "{\"a\":12332232323232}" + decoded := bson2json(os); + if (not match(decoded, decoded_json)) { + setverdict(fail, match(decoded, decoded_json)); + } + + json := "{\"a\":[{\"$numberLong\":\"12332232323232\"}],\"b\":3}" + expected_os := '1F00000004610010000000123000A0B05352370B0000001062000300000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded_json := "{\"a\":[12332232323232],\"b\":3}" + decoded := bson2json(os); + if (not match(decoded, decoded_json)) { + setverdict(fail, match(decoded, decoded_json)); + } + + json := "{\"a\":{\"$code\":\"aaa\",\"$scope\":{\"a\":\"b\"}}}" + expected_os := '220000000F61001A00000004000000616161000E0000000261000200000062000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":[{\"$code\":\"aaa\",\"$scope\":{\"a\":\"b\"}}],\"b\":3}" + expected_os := '31000000046100220000000F30001A00000004000000616161000E00000002610002000000620000001062000300000000'O; + os := json2bson(json);log(os); + if (not match(os, expected_os)) { + setverdict(fail, match(os, expected_os)); + } + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":\"aaa\"}" + // Javascript code. Cannot be produced from json + os := '100000000D6100040000006161610000'O; + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + json := "{\"a\":\"aaa\"}" + // Symbol. Cannot be produced from json + os := '100000000E6100040000006161610000'O; + decoded := bson2json(os); + if (not match(decoded, json)) { + setverdict(fail, match(decoded, json)); + } + + setverdict(pass); + } + + control { + execute(tc_bson_encdec()); + } +} \ No newline at end of file diff --git a/regression_test/json/JSON.cfg b/regression_test/json/JSON.cfg index 684b527d59c3b4bae4b384f9c18634d5be603f18..178cbdf935d528f32ffa50c0c4a49583eda34399 100644 --- a/regression_test/json/JSON.cfg +++ b/regression_test/json/JSON.cfg @@ -85,6 +85,7 @@ AttributeTestcases.control #AttributeTestcases.tc_attribute_prettyprint2 #AttributeTestcases.tc_attribute_union Cbor.control +Bson.control [GROUPS] # In this section you can specify groups of hosts. These groups can be used inside the # [COMPONENTS] section to restrict the creation of certain PTCs to a given set of hosts. diff --git a/regression_test/json/Makefile b/regression_test/json/Makefile index 6bce0e452385fe8073c1a2e57a2caa9588209114..3687365513db84a350944860e18a07f94772db3f 100644 --- a/regression_test/json/Makefile +++ b/regression_test/json/Makefile @@ -19,7 +19,7 @@ include $(TOPDIR)/Makefile.regression TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) -TTCN3_MODULES = Types.ttcn Functions.ttcn AttributeTestcases.ttcn Testcases.ttcn OtherTypes.ttcn SemanticCheck.ttcn Cbor.ttcn +TTCN3_MODULES = Types.ttcn Functions.ttcn AttributeTestcases.ttcn Testcases.ttcn OtherTypes.ttcn SemanticCheck.ttcn Cbor.ttcn Bson.ttcn ifdef LEGACY_CODEC_HANDLING TTCN3_MODULES += SemanticCheck2.ttcn diff --git a/usrguide/referenceguide.doc b/usrguide/referenceguide.doc index 06da4541084bb168cf5bd0764aaba5df8871270e..2d0a4de28daee726c4c5ca3f1af1abb983fac98f 100644 Binary files a/usrguide/referenceguide.doc and b/usrguide/referenceguide.doc differ