diff --git a/compiler2/Value.cc b/compiler2/Value.cc index 17831849f84c68dd0adc9744aa9c130cd6325602..404bcdbc032061ba9c0ef8f340ab030eccea6fdf 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -12939,6 +12939,11 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) is_templ = true; break; } + + const char * v2_code = NULL; + if(u.expr.v2) { + v2_code = generate_code_char_coding_check(expr, u.expr.v2, "encvalue_unichar"); + } if (!gov_last->is_coding_by_function()) { const string& tmp_id = get_temporary_id(); @@ -12974,10 +12979,6 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) tmp_buf_id.c_str(), tmp_id.c_str() ); - const char * v2_code = NULL; - if(u.expr.v2) { - v2_code = generate_code_char_coding_check(expr, u.expr.v2, "encvalue_unichar"); - } expr->expr = mputprintf(expr->expr, "oct2unichar(%s", tmp_id.c_str()); if(u.expr.v2) { expr->expr = mputprintf(expr->expr, ", %s", v2_code); @@ -12987,10 +12988,17 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) expr->expr = mputprintf(expr->expr, ")"); if (expr2.postamble) expr->postamble = mputstr(expr->postamble, expr2.postamble); - } else - expr->expr = mputprintf(expr->expr, "%s(%s%s)", + } else { + expr->expr = mputprintf(expr->expr, "oct2unichar(bit2oct(%s(%s%s))", gov_last->get_coding(true).c_str(), expr2.expr, is_templ ? ".valueof()" : ""); + if(u.expr.v2) { + expr->expr = mputprintf(expr->expr, ", %s", v2_code); + } else { + expr->expr = mputprintf(expr->expr, ", \"UTF-8\""); //default + } + expr->expr = mputprintf(expr->expr, ")"); + } Code::free_expr(&expr2); } @@ -13010,6 +13018,10 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) expr->preamble = mputprintf(expr->preamble, "%s", expr1.preamble); if (expr2.preamble) expr->preamble = mputprintf(expr->preamble, "%s", expr2.preamble); + const char* v3_code = NULL; + if(u.expr.v3) { + v3_code = generate_code_char_coding_check(expr, u.expr.v3, "decvalue_unichar"); + } if (!_type->is_coding_by_function()) { const string& tmp_id = get_temporary_id(); @@ -13018,10 +13030,6 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) const bool optional = u.expr.r2->get_refd_assignment()->get_Type()-> field_is_optional(u.expr.r2->get_subrefs()); - const char* v3_code = NULL; - if(u.expr.v3) { - v3_code = generate_code_char_coding_check(expr, u.expr.v3, "decvalue_unichar"); - } expr->preamble = mputprintf(expr->preamble, "TTCN_Buffer %s(unichar2oct(%s, %s));\n" "INTEGER %s;\n" @@ -13074,9 +13082,21 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) retval_id.c_str() ); expr->expr = mputprintf(expr->expr, "%s", retval_id.c_str()); - } else - expr->expr = mputprintf(expr->expr, "%s(%s, %s)", - _type->get_coding(false).c_str(), expr1.expr, expr2.expr); + } else { + const string& ustr_ref_id = get_temporary_id(); + const string& bstr_id = get_temporary_id(); + const string& ret_val_id = get_temporary_id(); + expr->preamble = mputprintf(expr->preamble, + "UNIVERSAL_CHARSTRING& %s = %s;\n" + "BITSTRING %s(oct2bit(unichar2oct(%s, %s)));\n" + "INTEGER %s(%s(%s, %s));\n" + "%s = oct2unichar(bit2oct(%s), %s);\n", + ustr_ref_id.c_str(), expr1.expr, + bstr_id.c_str(), ustr_ref_id.c_str(), u.expr.v3 ? v3_code : "\"UTF-8\"", + ret_val_id.c_str(), _type->get_coding(false).c_str(), bstr_id.c_str(), expr2.expr, + ustr_ref_id.c_str(), bstr_id.c_str(), u.expr.v3 ? v3_code : "\"UTF-8\""); + expr->expr = mputprintf(expr->expr, "%s", ret_val_id.c_str()); + } if (expr1.postamble) expr->postamble = mputprintf(expr->postamble, "%s", expr1.postamble); if (expr2.postamble) diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index f696c989a4da69b8941e2b3b7abe87321ef149cf..ed5f97873a9809e68efb790d28b434a2fc707859 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -8852,94 +8852,154 @@ error: if (use_decmatch_result) { set_params_str = mputstr(set_params_str, "}\nelse {\n"); } - switch (par->get_type()->get_type_refd_last()->get_typetype_ttcn3()) { - case Type::T_OSTR: - case Type::T_CSTR: - set_params_str = mputprintf(set_params_str, - "TTCN_Buffer buff(par.%s());\n", par_name); - break; - case Type::T_BSTR: - set_params_str = mputprintf(set_params_str, - "OCTETSTRING os(bit2oct(par.%s()));\n" - "TTCN_Buffer buff(os);\n", par_name); - break; - case Type::T_HSTR: - set_params_str = mputprintf(set_params_str, - "OCTETSTRING os(hex2oct(par.%s()));\n" - "TTCN_Buffer buff(os);\n", par_name); - break; - case Type::T_USTR: - set_params_str = mputstr(set_params_str, "TTCN_Buffer buff;\n"); - if (ve->get_str_enc() == NULL || !ve->get_str_enc()->is_unfoldable()) { - // if the encoding format is missing or is known at compile-time, then - // use the appropriate string encoding function - string str_enc = (ve->get_str_enc() != NULL) ? - ve->get_str_enc()->get_val_str() : string("UTF-8"); - if (str_enc == "UTF-8") { - set_params_str = mputprintf(set_params_str, - "par.%s().encode_utf8(buff, false);\n", par_name); - } - else if (str_enc == "UTF-16" || str_enc == "UTF-16LE" || - str_enc == "UTF-16BE") { - set_params_str = mputprintf(set_params_str, - "par.%s().encode_utf16(buff, CharCoding::UTF16%s);\n", par_name, - (str_enc == "UTF-16LE") ? "LE" : "BE"); + Type::typetype_t tt = par->get_type()->get_type_refd_last()->get_typetype_ttcn3(); + if (ve->get_dec_type()->is_coding_by_function()) { + set_params_str = mputstr(set_params_str, "BITSTRING buff("); + switch (tt) { + case Type::T_BSTR: + set_params_str = mputprintf(set_params_str, "par.%s()", par_name); + break; + case Type::T_HSTR: + set_params_str = mputprintf(set_params_str, "hex2bit(par.%s())", + par_name); + break; + case Type::T_OSTR: + set_params_str = mputprintf(set_params_str, "oct2bit(par.%s())", + par_name); + break; + case Type::T_CSTR: + set_params_str = mputprintf(set_params_str, + "oct2bit(char2oct(par.%s()))", par_name); + break; + case Type::T_USTR: + set_params_str = mputprintf(set_params_str, + "oct2bit(unichar2oct(par.%s(), ", par_name); + if (ve->get_str_enc() == NULL || !ve->get_str_enc()->is_unfoldable()) { + // encoding format is missing or is known at compile-time + set_params_str = mputprintf(set_params_str, "\"%s\"", + ve->get_str_enc() != NULL ? + ve->get_str_enc()->get_val_str().c_str() : "UTF-8"); } - else if (str_enc == "UTF-32" || str_enc == "UTF-32LE" || - str_enc == "UTF-32BE") { - set_params_str = mputprintf(set_params_str, - "par.%s().encode_utf32(buff, CharCoding::UTF32%s);\n", par_name, - (str_enc == "UTF-32LE") ? "LE" : "BE"); + else { + // the encoding format is not known at compile-time, so an extra + // member and constructor parameter is needed to store it + members_str = mputprintf(members_str, "CHARSTRING enc_fmt_%s;\n", + par_name); + constr_params_str = mputprintf(constr_params_str, + ", CHARSTRING par_fmt_%s = CHARSTRING()", par_name); + constr_init_list_str = mputprintf(constr_init_list_str, + ", enc_fmt_%s(par_fmt_%s)", par_name, par_name); + set_params_str = mputprintf(set_params_str, "enc_fmt_%s", par_name); } + set_params_str = mputstr(set_params_str, "))"); + break; + default: + FATAL_ERROR("ParamRedirect::generate_code_decoded"); } - else { - // the encoding format is not known at compile-time, so an extra - // member and constructor parameter is needed to store it - members_str = mputprintf(members_str, "CHARSTRING enc_fmt_%s;\n", - par_name); - constr_params_str = mputprintf(constr_params_str, - ", CHARSTRING par_fmt_%s = CHARSTRING()", par_name); - constr_init_list_str = mputprintf(constr_init_list_str, - ", enc_fmt_%s(par_fmt_%s)", par_name, par_name); - if (!use_decmatch_result) { - // if the decmatch result code is generated too, then this variable - // was already generated before the main 'if' - set_params_str = mputprintf(set_params_str, - "CharCoding::CharCodingType coding = UNIVERSAL_CHARSTRING::" - "get_character_coding(enc_fmt_%s, \"decoded parameter redirect\");\n", + set_params_str = mputprintf(set_params_str, + ");\n" + "if (%s(buff, *ptr_%s_dec) != 0) {\n" + "TTCN_error(\"Decoding failed in parameter redirect " + "(for parameter '%s').\");\n" + "}\n" + "if (buff.lengthof() != 0) {\n" + "TTCN_error(\"Parameter redirect (for parameter '%s') failed, " + "because the buffer was not empty after decoding. " + "Remaining bits: %%d.\", buff.lengthof());\n" + "}\n", ve->get_dec_type()->get_coding(false).c_str(), + par_name, par_name, par_name); + } + else { // built-in decoding + switch (tt) { + case Type::T_OSTR: + case Type::T_CSTR: + set_params_str = mputprintf(set_params_str, + "TTCN_Buffer buff(par.%s());\n", par_name); + break; + case Type::T_BSTR: + set_params_str = mputprintf(set_params_str, + "OCTETSTRING os(bit2oct(par.%s()));\n" + "TTCN_Buffer buff(os);\n", par_name); + break; + case Type::T_HSTR: + set_params_str = mputprintf(set_params_str, + "OCTETSTRING os(hex2oct(par.%s()));\n" + "TTCN_Buffer buff(os);\n", par_name); + break; + case Type::T_USTR: + set_params_str = mputstr(set_params_str, "TTCN_Buffer buff;\n"); + if (ve->get_str_enc() == NULL || !ve->get_str_enc()->is_unfoldable()) { + // if the encoding format is missing or is known at compile-time, then + // use the appropriate string encoding function + string str_enc = (ve->get_str_enc() != NULL) ? + ve->get_str_enc()->get_val_str() : string("UTF-8"); + if (str_enc == "UTF-8") { + set_params_str = mputprintf(set_params_str, + "par.%s().encode_utf8(buff, false);\n", par_name); + } + else if (str_enc == "UTF-16" || str_enc == "UTF-16LE" || + str_enc == "UTF-16BE") { + set_params_str = mputprintf(set_params_str, + "par.%s().encode_utf16(buff, CharCoding::UTF16%s);\n", par_name, + (str_enc == "UTF-16LE") ? "LE" : "BE"); + } + else if (str_enc == "UTF-32" || str_enc == "UTF-32LE" || + str_enc == "UTF-32BE") { + set_params_str = mputprintf(set_params_str, + "par.%s().encode_utf32(buff, CharCoding::UTF32%s);\n", par_name, + (str_enc == "UTF-32LE") ? "LE" : "BE"); + } + } + else { + // the encoding format is not known at compile-time, so an extra + // member and constructor parameter is needed to store it + members_str = mputprintf(members_str, "CHARSTRING enc_fmt_%s;\n", par_name); + constr_params_str = mputprintf(constr_params_str, + ", CHARSTRING par_fmt_%s = CHARSTRING()", par_name); + constr_init_list_str = mputprintf(constr_init_list_str, + ", enc_fmt_%s(par_fmt_%s)", par_name, par_name); + if (!use_decmatch_result) { + // if the decmatch result code is generated too, then this variable + // was already generated before the main 'if' + set_params_str = mputprintf(set_params_str, + "CharCoding::CharCodingType coding = UNIVERSAL_CHARSTRING::" + "get_character_coding(enc_fmt_%s, \"decoded parameter redirect\");\n", + par_name); + } + set_params_str = mputprintf(set_params_str, + "switch (coding) {\n" + "case CharCoding::UTF_8:\n" + "par.%s().encode_utf8(buff, false);\n" + "break;\n" + "case CharCoding::UTF16:\n" + "case CharCoding::UTF16LE:\n" + "case CharCoding::UTF16BE:\n" + "par.%s().encode_utf16(buff, coding);\n" + "break;\n" + "case CharCoding::UTF32:\n" + "case CharCoding::UTF32LE:\n" + "case CharCoding::UTF32BE:\n" + "par.%s().encode_utf32(buff, coding);\n" + "break;\n" + "default:\n" + "break;\n" + "}\n", par_name, par_name, par_name); } - set_params_str = mputprintf(set_params_str, - "switch (coding) {\n" - "case CharCoding::UTF_8:\n" - "par.%s().encode_utf8(buff, false);\n" - "break;\n" - "case CharCoding::UTF16:\n" - "case CharCoding::UTF16LE:\n" - "case CharCoding::UTF16BE:\n" - "par.%s().encode_utf16(buff, coding);\n" - "break;\n" - "case CharCoding::UTF32:\n" - "case CharCoding::UTF32LE:\n" - "case CharCoding::UTF32BE:\n" - "par.%s().encode_utf32(buff, coding);\n" - "break;\n" - "default:\n" - "break;\n" - "}\n", par_name, par_name, par_name); + break; + default: + FATAL_ERROR("ParamRedirect::generate_code_decoded"); } - break; - default: - FATAL_ERROR("ParamRedirect::generate_code_decoded"); + set_params_str = mputprintf(set_params_str, + "ptr_%s_dec->decode(%s_descr_, buff, TTCN_EncDec::CT_%s);\n" + "if (buff.get_read_len() != 0) {\n" + "TTCN_error(\"Parameter redirect (for parameter '%s') failed, " + "because the buffer was not empty after decoding. " + "Remaining octets: %%d.\", (int)buff.get_read_len());\n" + "}\n", par_name, + ve->get_dec_type()->get_genname_typedescriptor(scope).c_str(), + ve->get_dec_type()->get_coding(false).c_str(), par_name); } - set_params_str = mputprintf(set_params_str, - "ptr_%s_dec->decode(%s_descr_, buff, TTCN_EncDec::CT_%s);\n" - "if (buff.get_read_len() != 0) {\n" - "TTCN_error(\"Parameter redirect failed, because the buffer was not " - "empty after decoding. Remaining octets: %%d.\", (int)buff.get_read_len());\n" - "}\n", par_name, - ve->get_dec_type()->get_genname_typedescriptor(scope).c_str(), - ve->get_dec_type()->get_coding(false).c_str()); if (use_decmatch_result) { set_params_str = mputstr(set_params_str, "}\n"); } @@ -9541,99 +9601,161 @@ error: if (use_decmatch_result) { set_values_str = mputstr(set_values_str, "}\nelse {\n"); } - switch (redir_type->get_type_refd_last()->get_typetype_ttcn3()) { - case Type::T_OSTR: - case Type::T_CSTR: - set_values_str = mputprintf(set_values_str, - "TTCN_Buffer buff_%d(par%s%s);\n", (int)i, subrefs_str, opt_suffix); - break; - case Type::T_BSTR: - set_values_str = mputprintf(set_values_str, - "OCTETSTRING os(bit2oct(par%s%s));\n" - "TTCN_Buffer buff_%d(os);\n", subrefs_str, opt_suffix, (int)i); - break; - case Type::T_HSTR: - set_values_str = mputprintf(set_values_str, - "OCTETSTRING os(hex2oct(par%s%s));\n" - "TTCN_Buffer buff_%d(os);\n", subrefs_str, opt_suffix, (int)i); - break; - case Type::T_USTR: - set_values_str = mputprintf(set_values_str, "TTCN_Buffer buff_%d;\n", + Type::typetype_t tt = redir_type->get_type_refd_last()->get_typetype_ttcn3(); + if (member_type->is_coding_by_function()) { + set_values_str = mputprintf(set_values_str, "BITSTRING buff_%d(", (int)i); - if (v[i]->get_str_enc() == NULL || !v[i]->get_str_enc()->is_unfoldable()) { - // if the encoding format is missing or is known at compile-time, then - // use the appropriate string encoding function - string str_enc = (v[i]->get_str_enc() != NULL) ? - v[i]->get_str_enc()->get_val_str() : string("UTF-8"); - if (str_enc == "UTF-8") { - set_values_str = mputprintf(set_values_str, - "par%s%s.encode_utf8(buff_%d, false);\n", subrefs_str, opt_suffix, (int)i); - } - else if (str_enc == "UTF-16" || str_enc == "UTF-16LE" || - str_enc == "UTF-16BE") { - set_values_str = mputprintf(set_values_str, - "par%s%s.encode_utf16(buff_%d, CharCoding::UTF16%s);\n", subrefs_str, - opt_suffix, (int)i, (str_enc == "UTF-16LE") ? "LE" : "BE"); + switch (tt) { + case Type::T_BSTR: + set_values_str = mputprintf(set_values_str, "par%s%s", + subrefs_str, opt_suffix); + break; + case Type::T_HSTR: + set_values_str = mputprintf(set_values_str, "hex2bit(par%s%s)", + subrefs_str, opt_suffix); + break; + case Type::T_OSTR: + set_values_str = mputprintf(set_values_str, "oct2bit(par%s%s)", + subrefs_str, opt_suffix); + break; + case Type::T_CSTR: + set_values_str = mputprintf(set_values_str, + "oct2bit(char2oct(par%s%s))", subrefs_str, opt_suffix); + break; + case Type::T_USTR: + set_values_str = mputprintf(set_values_str, + "oct2bit(unichar2oct(par%s%s, ", subrefs_str, opt_suffix); + if (v[i]->get_str_enc() == NULL || !v[i]->get_str_enc()->is_unfoldable()) { + // encoding format is missing or is known at compile-time + set_values_str = mputprintf(set_values_str, "\"%s\"", + v[i]->get_str_enc() != NULL ? + v[i]->get_str_enc()->get_val_str().c_str() : "UTF-8"); } - else if (str_enc == "UTF-32" || str_enc == "UTF-32LE" || - str_enc == "UTF-32BE") { - set_values_str = mputprintf(set_values_str, - "par%s%s.encode_utf32(buff_%d, CharCoding::UTF32%s);\n", subrefs_str, - opt_suffix, (int)i, (str_enc == "UTF-32LE") ? "LE" : "BE"); + else { + // the encoding format is not known at compile-time, so an extra + // member and constructor parameter is needed to store it + expr->expr = mputstr(expr->expr, ", "); + v[i]->get_str_enc()->generate_code_expr(expr); + members_str = mputprintf(members_str, "CHARSTRING enc_fmt_%d;\n", + (int)i); + constr_params_str = mputprintf(constr_params_str, + ", CHARSTRING par_fmt_%d", (int)i); + constr_init_list_str = mputprintf(constr_init_list_str, + ", enc_fmt_%d(par_fmt_%d)", (int)i, (int)i); + set_values_str = mputprintf(set_values_str, "enc_fmt_%d", (int)i); } + set_values_str = mputstr(set_values_str, "))"); + break; + default: + FATAL_ERROR("ValueRedirect::generate_code"); } - else { - // the encoding format is not known at compile-time, so an extra - // member and constructor parameter is needed to store it - expr->expr = mputstr(expr->expr, ", "); - v[i]->get_str_enc()->generate_code_expr(expr); - members_str = mputprintf(members_str, "CHARSTRING enc_fmt_%d;\n", + set_values_str = mputprintf(set_values_str, + ");\n" + "if (%s(buff_%d, *ptr_%d) != 0) {\n" + "TTCN_error(\"Decoding failed in value redirect #%d.\");\n" + "}\n" + "if (buff_%d.lengthof() != 0) {\n" + "TTCN_error(\"Value redirect #%d failed, because the buffer was " + "not empty after decoding. Remaining bits: %%d.\", " + "buff_%d.lengthof());\n" + "}\n", member_type->get_coding(false).c_str(), + (int)i, (int)i, (int)(i + 1), (int)i, (int)(i + 1), (int)i); + } + else { // built-in decoding + switch (tt) { + case Type::T_OSTR: + case Type::T_CSTR: + set_values_str = mputprintf(set_values_str, + "TTCN_Buffer buff_%d(par%s%s);\n", (int)i, subrefs_str, opt_suffix); + break; + case Type::T_BSTR: + set_values_str = mputprintf(set_values_str, + "OCTETSTRING os(bit2oct(par%s%s));\n" + "TTCN_Buffer buff_%d(os);\n", subrefs_str, opt_suffix, (int)i); + break; + case Type::T_HSTR: + set_values_str = mputprintf(set_values_str, + "OCTETSTRING os(hex2oct(par%s%s));\n" + "TTCN_Buffer buff_%d(os);\n", subrefs_str, opt_suffix, (int)i); + break; + case Type::T_USTR: + set_values_str = mputprintf(set_values_str, "TTCN_Buffer buff_%d;\n", (int)i); - constr_params_str = mputprintf(constr_params_str, - ", CHARSTRING par_fmt_%d", (int)i); - constr_init_list_str = mputprintf(constr_init_list_str, - ", enc_fmt_%d(par_fmt_%d)", (int)i, (int)i); - if (!use_decmatch_result) { - // if the decmatch result code is generated too, then this variable - // was already generated before the main 'if' - set_values_str = mputprintf(set_values_str, - "CharCoding::CharCodingType coding = UNIVERSAL_CHARSTRING::" - "get_character_coding(enc_fmt_%d, \"decoded value redirect\");\n", + if (v[i]->get_str_enc() == NULL || !v[i]->get_str_enc()->is_unfoldable()) { + // if the encoding format is missing or is known at compile-time, then + // use the appropriate string encoding function + string str_enc = (v[i]->get_str_enc() != NULL) ? + v[i]->get_str_enc()->get_val_str() : string("UTF-8"); + if (str_enc == "UTF-8") { + set_values_str = mputprintf(set_values_str, + "par%s%s.encode_utf8(buff_%d, false);\n", subrefs_str, opt_suffix, (int)i); + } + else if (str_enc == "UTF-16" || str_enc == "UTF-16LE" || + str_enc == "UTF-16BE") { + set_values_str = mputprintf(set_values_str, + "par%s%s.encode_utf16(buff_%d, CharCoding::UTF16%s);\n", subrefs_str, + opt_suffix, (int)i, (str_enc == "UTF-16LE") ? "LE" : "BE"); + } + else if (str_enc == "UTF-32" || str_enc == "UTF-32LE" || + str_enc == "UTF-32BE") { + set_values_str = mputprintf(set_values_str, + "par%s%s.encode_utf32(buff_%d, CharCoding::UTF32%s);\n", subrefs_str, + opt_suffix, (int)i, (str_enc == "UTF-32LE") ? "LE" : "BE"); + } + } + else { + // the encoding format is not known at compile-time, so an extra + // member and constructor parameter is needed to store it + expr->expr = mputstr(expr->expr, ", "); + v[i]->get_str_enc()->generate_code_expr(expr); + members_str = mputprintf(members_str, "CHARSTRING enc_fmt_%d;\n", (int)i); + constr_params_str = mputprintf(constr_params_str, + ", CHARSTRING par_fmt_%d", (int)i); + constr_init_list_str = mputprintf(constr_init_list_str, + ", enc_fmt_%d(par_fmt_%d)", (int)i, (int)i); + if (!use_decmatch_result) { + // if the decmatch result code is generated too, then this variable + // was already generated before the main 'if' + set_values_str = mputprintf(set_values_str, + "CharCoding::CharCodingType coding = UNIVERSAL_CHARSTRING::" + "get_character_coding(enc_fmt_%d, \"decoded value redirect\");\n", + (int)i); + } + set_values_str = mputprintf(set_values_str, + "switch (coding) {\n" + "case CharCoding::UTF_8:\n" + "par%s%s.encode_utf8(buff_%d, false);\n" + "break;\n" + "case CharCoding::UTF16:\n" + "case CharCoding::UTF16LE:\n" + "case CharCoding::UTF16BE:\n" + "par%s%s.encode_utf16(buff_%d, coding);\n" + "break;\n" + "case CharCoding::UTF32:\n" + "case CharCoding::UTF32LE:\n" + "case CharCoding::UTF32BE:\n" + "par%s%s.encode_utf32(buff_%d, coding);\n" + "break;\n" + "default:\n" + "break;\n" + "}\n", subrefs_str, opt_suffix, (int)i, subrefs_str, opt_suffix, + (int)i, subrefs_str, opt_suffix, (int)i); } - set_values_str = mputprintf(set_values_str, - "switch (coding) {\n" - "case CharCoding::UTF_8:\n" - "par%s%s.encode_utf8(buff_%d, false);\n" - "break;\n" - "case CharCoding::UTF16:\n" - "case CharCoding::UTF16LE:\n" - "case CharCoding::UTF16BE:\n" - "par%s%s.encode_utf16(buff_%d, coding);\n" - "break;\n" - "case CharCoding::UTF32:\n" - "case CharCoding::UTF32LE:\n" - "case CharCoding::UTF32BE:\n" - "par%s%s.encode_utf32(buff_%d, coding);\n" - "break;\n" - "default:\n" - "break;\n" - "}\n", subrefs_str, opt_suffix, (int)i, subrefs_str, opt_suffix, - (int)i, subrefs_str, opt_suffix, (int)i); + break; + default: + FATAL_ERROR("ValueRedirect::generate_code"); } - break; - default: - FATAL_ERROR("ValueRedirect::generate_code"); + set_values_str = mputprintf(set_values_str, + "ptr_%d->decode(%s_descr_, buff_%d, TTCN_EncDec::CT_%s);\n" + "if (buff_%d.get_read_len() != 0) {\n" + "TTCN_error(\"Value redirect #%d failed, because the buffer was " + "not empty after decoding. Remaining octets: %%d.\", " + "(int)buff_%d.get_read_len());\n" + "}\n", + (int)i, member_type->get_genname_typedescriptor(scope).c_str(), (int)i, + member_type->get_coding(false).c_str(), (int)i, (int)(i + 1), (int)i); } - set_values_str = mputprintf(set_values_str, - "ptr_%d->decode(%s_descr_, buff_%d, TTCN_EncDec::CT_%s);\n" - "if (buff_%d.get_read_len() != 0) {\n" - "TTCN_error(\"Value redirect #%d failed, because the buffer was " - "not empty after decoding. Remaining octets: %%d.\", " - "(int)buff_%d.get_read_len());\n" - "}\n", - (int)i, member_type->get_genname_typedescriptor(scope).c_str(), (int)i, - member_type->get_coding(false).c_str(), (int)i, (int)(i + 1), (int)i); if (use_decmatch_result) { set_values_str = mputstr(set_values_str, "}\n"); } diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc index 300e4515b2160ee39a68d2bf7c23731e5983c48f..2ebecec4eaee2f964c1540b5a328020ddb3b643c 100644 --- a/compiler2/ttcn3/TtcnTemplate.cc +++ b/compiler2/ttcn3/TtcnTemplate.cc @@ -4574,17 +4574,44 @@ compile_time: "{\n" "if (dec_val != NULL) delete dec_val;\n" "dec_val = new %s;\n" - // decode the value - "dec_val->decode(%s_descr_, buff, TTCN_EncDec::CT_%s);\n" - "boolean ret_val;\n" - // make sure no errors occurred (these already displayed warnings during - // decoding) - "if (TTCN_EncDec::get_last_error_type() != TTCN_EncDec::ET_NONE) " - "ret_val = FALSE;\n" - // make sure the buffer is empty after decoding, display a warning otherwise - "else if (buff.get_read_len() != 0) {\n" + "boolean ret_val;\n", class_tmp_id.c_str(), + target_type->get_genname_template(my_scope).c_str(), + target_type->get_genname_value(my_scope).c_str(), class_tmp_id.c_str(), + target_type->get_genname_template(my_scope).c_str(), class_tmp_id.c_str(), + target_type->get_genname_value(my_scope).c_str()); + bool dec_by_func = target_type->is_coding_by_function(); + if (dec_by_func) { + str = mputprintf(str, + // convert the TTCN_Buffer into a bitstring + "OCTETSTRING os;\n" + "buff.get_string(os);\n" + "BITSTRING bs(oct2bit(os));\n" + // decode the value (with the user function) + "if (%s(bs, *dec_val) != 0) {\n" + "TTCN_warning(\"Decoded content matching failed, because the data could " + "not be decoded by the provided function.\");\n" + "ret_val = FALSE;\n" + "}\n" + // make sure the bitstring is empty after decoding, display a warning otherwise + "else if (bs.lengthof() != 0) {\n", + target_type->get_coding(false).c_str()); + } + else { + str = mputprintf(str, + // decode the value (with a built-in decoder) + "dec_val->decode(%s_descr_, buff, TTCN_EncDec::CT_%s);\n" + // make sure no errors occurred (these already displayed warnings during + // decoding) + "if (TTCN_EncDec::get_last_error_type() != TTCN_EncDec::ET_NONE) " + "ret_val = FALSE;\n" + // make sure the buffer is empty after decoding, display a warning otherwise + "else if (buff.get_read_len() != 0) {\n", + target_type->get_genname_typedescriptor(my_scope).c_str(), + target_type->get_coding(false).c_str()); + } + str = mputprintf(str, "TTCN_warning(\"Decoded content matching failed, because the buffer was not " - "empty after decoding. Remaining octets: %%d.\", (int)buff.get_read_len());\n" + "empty after decoding. Remaining %s: %%d.\", %s);\n" "ret_val = FALSE;\n" "}\n" // finally, match the decoded value against the target template @@ -4610,13 +4637,8 @@ compile_time: "const TTCN_Typedescriptor_t* get_type_descr() const { return &%s_descr_; }\n" "};\n" "%s.set_type(DECODE_MATCH);\n" - "{\n", class_tmp_id.c_str(), - target_type->get_genname_template(my_scope).c_str(), - target_type->get_genname_value(my_scope).c_str(), class_tmp_id.c_str(), - target_type->get_genname_template(my_scope).c_str(), class_tmp_id.c_str(), - target_type->get_genname_value(my_scope).c_str(), - target_type->get_genname_typedescriptor(my_scope).c_str(), - target_type->get_coding(false).c_str(), + "{\n", dec_by_func ? "bits" : "octets", + dec_by_func ? "bs.lengthof()" : "(int)buff.get_read_len()", omit_in_value_list ? ", TRUE" : "", type_name.c_str(), target_type->get_genname_typedescriptor(my_scope).c_str(), name); diff --git a/regression_test/customEncoding/Coders.cc b/regression_test/customEncoding/Coders.cc index a06e4334a35bf8e135400b229fff037048976a0f..139db624d873e52bb9e9d2e92beb1265a4457b39 100644 --- a/regression_test/customEncoding/Coders.cc +++ b/regression_test/customEncoding/Coders.cc @@ -26,6 +26,7 @@ INTEGER f__dec__rec(BITSTRING& b, Custom3::Rec& x) { x.num() = bit2int(b); x.str() = "c++"; + b = BITSTRING(0, NULL); return 0; } @@ -49,6 +50,7 @@ INTEGER f__dec__uni(BITSTRING& b, Custom1::Uni& x) if (b_len > 2 * sep_len) { x.i() = bit2int(substr(b, sep_len, b_len - 2 * sep_len)); } + b = BITSTRING(0, NULL); return 0; } else { @@ -92,6 +94,7 @@ INTEGER f__dec__recof(BITSTRING& b, RecOf& x) end = find_bitstring(b, start, c__separator); } x[index] = substr(b, start, b.lengthof() - start); + b = BITSTRING(0, NULL); return 0; } diff --git a/regression_test/customEncoding/Custom1.ttcn b/regression_test/customEncoding/Custom1.ttcn index be9ef7edc90ad689508df809444ae11db43e414d..29b7c8ce7dee303552174dfddfa78bbdebfda602 100644 --- a/regression_test/customEncoding/Custom1.ttcn +++ b/regression_test/customEncoding/Custom1.ttcn @@ -20,7 +20,31 @@ module Custom1 { import from Custom2 all; import from Custom3 all; -type component CT {} +type record Msg { + octetstring data optional, + RecOf list +} + +signature Sig(inout universal charstring p); + +type port PT_Msg message { + inout Msg +} +with { + extension "internal"; +} + +type port PT_Proc procedure { + inout Sig +} +with { + extension "internal"; +} + +type component CT { + port PT_Msg pt_msg; + port PT_Proc pt_proc; +} // Test 1. // The encoded type is a record defined in another module @@ -133,11 +157,94 @@ testcase tc_custom_temp() runs on CT setverdict(pass); } +// Test 5. +// Same as test 2, but with encvalue_unichar and decvalue_unichar. +// The input RecOf has also been adjusted, so it doesn't cause problems for the UTF-8 decoder. +testcase tc_custom_unichar() runs on CT +{ + var RecOf x := { '0110'B, '0100'B, '01110101'B }; + var universal charstring enc_exp := oct2unichar(bit2oct(x[0] & c_separator & x[1] & c_separator & x[2]), "UTF-8"); + var RecOf dec_exp := x; + + var universal charstring enc := encvalue_unichar(x, "UTF-8"); + if (enc != enc_exp) { + setverdict(fail, "Expected: ", enc_exp, ", got: ", enc); + } + var RecOf dec; + var integer res := decvalue_unichar(enc_exp, dec, "UTF-8"); + if (res != 0) { + setverdict(fail, "Failed to decode ", enc_exp); + } + if (dec != dec_exp) { + setverdict(fail, "Expected: ", dec_exp, ", got: ", dec); + } + setverdict(pass); +} + +// Test 6. +// Using custom encoding on a decoded parameter redirect. +// Same input value as in test 5. +testcase tc_custom_param_redirect() runs on CT +{ + connect(self:pt_proc, self:pt_proc); + var RecOf val := { '0110'B, '0100'B, '01110101'B }; + var charstring str_fmt := "UTF-8"; + var universal charstring val_enc := encvalue_unichar(val, str_fmt); + var RecOf res; + pt_proc.reply(Sig: { p := val_enc }); + timer tmr := 1.0; + tmr.start; + alt { + [] pt_proc.getreply(Sig: { p := val_enc }) -> param (res := @decoded(str_fmt) p) { + if (res != val) { + setverdict(fail, "Invalid decoded parameter. Expected: ", val, ", got: ", res); + } + else { + setverdict(pass); + } + } + [] pt_proc.getreply(Sig: { p := ?}) { + setverdict(fail, "Invalid reply received."); + } + [] tmr.timeout { + setverdict(fail, "Timed out."); + } + } +} + +// Test 7. +// Using custom encoding in a template with decoded content matching. +// Same input as test 3. +testcase tc_custom_decmatch() runs on CT +{ + connect(self:pt_msg, self:pt_msg); + var Uni val := { i := 16 }; + var Msg msg := { data := omit, list := { encvalue(val) } }; + var Uni res; + pt_msg.send(msg); + timer tmr := 1.0; + tmr.start; + alt { + [] pt_msg.receive(Msg: { data := omit, list := { decmatch val } }) { + setverdict(pass); + } + [] pt_msg.receive(?) { + setverdict(fail, "Invalid message received or decoded content matching failed."); + } + [] tmr.timeout { + setverdict(fail, "Timed out."); + } + } +} + control { execute(tc_custom1()); execute(tc_custom2()); execute(tc_custom3()); execute(tc_custom_temp()); + execute(tc_custom_unichar()); + execute(tc_custom_param_redirect()); + execute(tc_custom_decmatch()); } } diff --git a/regression_test/customEncoding/Custom4.ttcn b/regression_test/customEncoding/Custom4.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..c3e68713a56ac1f96597e60bb4628030d29c36eb --- /dev/null +++ b/regression_test/customEncoding/Custom4.ttcn @@ -0,0 +1,56 @@ +/****************************************************************************** + * Copyright (c) 2000-2016 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Baranyi, Botond + * + ******************************************************************************/ + +// This module contains further tests for custom encodings +// (in features only available in the Function Test Runtime). +module Custom4 { + +import from Custom1 all; +import from Custom2 all; +import from Custom3 all; + +// Test 8 (RT2 only). +// Using custom encoding on a decoded value redirect. +// Same input value as in test 1. +testcase tc_custom_value_redirect() runs on CT +{ + connect(self:pt_msg, self:pt_msg); + var Rec val := { num := 3, str := "ttcn" }; + var Msg msg := { data := bit2oct(encvalue(val)), list := { } }; + var Rec res; + var Rec exp := { num := 3, str := "c++" }; + pt_msg.send(msg); + timer tmr := 1.0; + tmr.start; + alt { + [] pt_msg.receive(msg) -> value (res := @decoded data) { + if (res != exp) { + setverdict(fail, "Invalid decoded value. Expected: ", exp, ", got: ", res); + } + else { + setverdict(pass); + } + } + [] pt_msg.receive(?) { + setverdict(fail, "Invalid message received."); + } + [] tmr.timeout { + setverdict(fail, "Timed out."); + } + } +} + +control { + execute(tc_custom_value_redirect()); +} + +} diff --git a/regression_test/customEncoding/Makefile b/regression_test/customEncoding/Makefile index 2ad9ee502ba931b5aeae391aed1537562d03d54f..21f701f43ac93fea3b7c4b0f103403fff6105a41 100644 --- a/regression_test/customEncoding/Makefile +++ b/regression_test/customEncoding/Makefile @@ -21,6 +21,10 @@ TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) TTCN3_MODULES = Custom1.ttcn Custom2.ttcn Custom3.ttcn +ifdef RT2 +TTCN3_MODULES += Custom4.ttcn +endif + USER_SOURCES = Coders.cc GENERATED_SOURCES = $(TTCN3_MODULES:.ttcn=.cc) @@ -57,7 +61,7 @@ clean distclean: dep: $(GENERATED_SOURCES) makedepend $(CPPFLAGS) $(GENERATED_SOURCES) -run: $(TARGET) config.cfg +run: $(TARGET) config$(RT2_SUFFIX).cfg ./$^ .NOTPARALLEL: diff --git a/regression_test/customEncoding/config-rt2.cfg b/regression_test/customEncoding/config-rt2.cfg new file mode 100644 index 0000000000000000000000000000000000000000..af5db504896dc0d4009c5d99e70046e489e1132e --- /dev/null +++ b/regression_test/customEncoding/config-rt2.cfg @@ -0,0 +1,19 @@ +############################################################################### +# Copyright (c) 2000-2016 Ericsson Telecom AB +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Baranyi, Botond +# +############################################################################### +[MODULE_PARAMETERS] +[LOGGING] +Logfile := "customEncoding.log" +FileMask := LOG_ALL +ConsoleMask := TTCN_WARNING | TTCN_ERROR | TTCN_TESTCASE | TTCN_STATISTICS +[EXECUTE] +Custom1 +Custom4