diff --git a/compiler2/record.c b/compiler2/record.c index 5ca149813fdfb648990aa9e337f730bb8824c232..1b3006ea383ac7b66e55c3d5665ef35b3df3e107 100644 --- a/compiler2/record.c +++ b/compiler2/record.c @@ -4799,8 +4799,14 @@ void defRecordClass1(const struct_def *sdef, output_struct *output) " boolean has_extension = FALSE;\n"); for (i = sdef->oerNrOrRootcomps; i < sdef->nElements; i++) { src = mputprintf(src, - " has_extension = has_extension || (field_%s.is_bound() && field_%s.is_present());\n", - sdef->elements[i].name, sdef->elements[sdef->oerP[i]].name); + " has_extension = has_extension || (field_%s.is_bound() && field_%s.is_present()", + sdef->elements[sdef->oerP[i]].name, sdef->elements[sdef->oerP[i]].name); + if (sdef->elements[sdef->oerP[i]].isDefault) { + src = mputprintf(src, " && field_%s != %s", + sdef->elements[sdef->oerP[i]].name, + sdef->elements[sdef->oerP[i]].defvalname); + } + src = mputstr(src, ");\n"); } } size_t opt_elements = 0; @@ -4833,10 +4839,16 @@ void defRecordClass1(const struct_def *sdef, output_struct *output) if (sdef->elements[sdef->oerP[i]].isOptional || sdef->elements[sdef->oerP[i]].isDefault) { pos--; src = mputprintf(src, - " if (field_%s.is_present()) {\n" + " if (field_%s.is_present()", sdef->elements[sdef->oerP[i]].name); + if (sdef->elements[sdef->oerP[i]].isDefault) { + src = mputprintf(src, " && field_%s != %s", + sdef->elements[sdef->oerP[i]].name, + sdef->elements[sdef->oerP[i]].defvalname); + } + src = mputprintf(src, + ") {\n" " c += %i;\n" " }\n" - , sdef->elements[sdef->oerP[i]].name , 1 << pos); if (pos == 0) { pos = 8; @@ -4856,8 +4868,13 @@ void defRecordClass1(const struct_def *sdef, output_struct *output) for (i = 0; i < limit; i++) { if (sdef->elements[sdef->oerP[i]].isOptional || sdef->elements[sdef->oerP[i]].isDefault) { src = mputprintf(src, - " if (field_%s.is_present())\n " - , sdef->elements[sdef->oerP[i]].name); + " if (field_%s.is_present()", sdef->elements[sdef->oerP[i]].name); + if (sdef->elements[sdef->oerP[i]].isDefault) { + src = mputprintf(src, " && field_%s != %s", + sdef->elements[sdef->oerP[i]].name, + sdef->elements[sdef->oerP[i]].defvalname); + } + src = mputstr(src, ")\n "); } src = mputprintf(src, " field_%s.OER_encode(%s_descr_, p_buf);\n" @@ -4899,7 +4916,13 @@ void defRecordClass1(const struct_def *sdef, output_struct *output) opt_elems++; } src = mputprintf(src, - " has_present = has_present || field_%s.is_present();\n", sdef->elements[sdef->oerP[j]].name); + " has_present = has_present || (field_%s.is_present()", sdef->elements[sdef->oerP[j]].name); + if (sdef->elements[sdef->oerP[j]].isDefault) { + src = mputprintf(src, " && field_%s != %s", + sdef->elements[sdef->oerP[j]].name, + sdef->elements[sdef->oerP[j]].defvalname); + } + src = mputstr(src, ");\n"); } src = mputprintf(src, " if (has_present) {\n" @@ -4914,10 +4937,18 @@ void defRecordClass1(const struct_def *sdef, output_struct *output) if (sdef->elements[sdef->oerP[j]].isOptional || sdef->elements[sdef->oerP[j]].isDefault) { pos2--; src = mputprintf(src, - " if (field_%s.is_present()) {\n" + " if (field_%s.is_present()", + sdef->elements[sdef->oerP[j]].name); + if (sdef->elements[sdef->oerP[j]].isDefault) { + src = mputprintf(src, " && field_%s != %s", + sdef->elements[sdef->oerP[j]].name, + sdef->elements[sdef->oerP[j]].defvalname); + } + src = mputprintf(src, + ") {\n" " c2 += %i;\n" " }\n" - , sdef->elements[sdef->oerP[j]].name, 1 << pos2); + , 1 << pos2); if (pos2 == 0) { pos2 = 8; ind2++; @@ -4946,14 +4977,21 @@ void defRecordClass1(const struct_def *sdef, output_struct *output) eag_pos++; } else { src = mputprintf(src, - " if (field_%s.is_present()) {\n" + " if (field_%s.is_present()", sdef->elements[sdef->oerP[i]].name); + if (sdef->elements[sdef->oerP[i]].isDefault) { + src = mputprintf(src, " && field_%s != %s", + sdef->elements[sdef->oerP[i]].name, + sdef->elements[sdef->oerP[i]].defvalname); + } + src = mputprintf(src, + ") {\n" " c += %i;\n" " field_%s.OER_encode(%s_descr_, tmp_buf2);\n" " encode_oer_length(tmp_buf2.get_len(), tmp_buf, FALSE);\n" " tmp_buf.put_buf(tmp_buf2);\n" " tmp_buf2.clear();\n" " }\n" - , sdef->elements[sdef->oerP[i]].name, 1 << pos + , 1 << pos , sdef->elements[sdef->oerP[i]].name, sdef->elements[sdef->oerP[i]].typedescrname); } if (pos == 0) { diff --git a/core2/Basetype2.cc b/core2/Basetype2.cc index 66fd141f5679a2063b7e942449848b40cb3b7902..630628be8aad40159396703b78711ccd99708097 100644 --- a/core2/Basetype2.cc +++ b/core2/Basetype2.cc @@ -6274,9 +6274,16 @@ int Record_Type::OER_encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_bu // If extendable record and has real extensions the first bit of the // preamble is 1 if (p_td.oer->extendable) { - for (int i = p_td.oer->nr_of_root_comps; i < field_count; i++) { + for (int i = 0; i < field_count; i++) { + boolean is_default_field = default_indexes && (default_indexes[next_default_idx].index==p_td.oer->p[i]); + const Base_Type* default_value = is_default_field ? default_indexes[next_default_idx].value : NULL; + if (is_default_field) { + next_default_idx++; + } // If there are extension fields the first bit is 1 - if (get_at(p_td.oer->p[i])->is_bound() && get_at(p_td.oer->p[i])->is_present()) { + if (i >= p_td.oer->nr_of_root_comps && + get_at(p_td.oer->p[i])->is_bound() && get_at(p_td.oer->p[i])->is_present() && + (!is_default_field || !get_at(p_td.oer->p[i])->is_equal(default_value))) { c = 1 << 7; has_extension = true; break; @@ -6285,14 +6292,19 @@ int Record_Type::OER_encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_bu pos--; limit = p_td.oer->nr_of_root_comps; } + next_default_idx = 0; for (int i = 0; i < limit; i++) { boolean is_default_field = default_indexes && (default_indexes[next_default_idx].index==p_td.oer->p[i]); + const Base_Type* default_value = is_default_field ? default_indexes[next_default_idx].value : NULL; if (is_default_field) { next_default_idx++; } if (get_at(p_td.oer->p[i])->is_optional() || is_default_field) { pos--; - c += get_at(p_td.oer->p[i])->is_present() << pos; + if (get_at(p_td.oer->p[i])->is_present() && + (!is_default_field || !get_at(p_td.oer->p[i])->is_equal(default_value))) { + c += 1 << pos; + } if (pos == 0) { p_buf.put_c(c); pos = 8; @@ -6303,9 +6315,19 @@ int Record_Type::OER_encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_bu if (pos != 8) { p_buf.put_c(c); } + next_default_idx = 0; for (int i = 0; i < limit; ++i) { - get_at(p_td.oer->p[i])->OER_encode(*fld_descr(p_td.oer->p[i]), p_buf); + boolean is_default_field = default_indexes && (default_indexes[next_default_idx].index==p_td.oer->p[i]); + const Base_Type* default_value = is_default_field ? default_indexes[next_default_idx].value : NULL; + if (is_default_field) { + next_default_idx++; + } + if (!is_default_field || !get_at(p_td.oer->p[i])->is_equal(default_value)) { + get_at(p_td.oer->p[i])->OER_encode(*fld_descr(p_td.oer->p[i]), p_buf); + } } + + int ext_default_idx_start = next_default_idx; // If the record is extendable and has real extensions if (has_extension) { @@ -6315,21 +6337,38 @@ int Record_Type::OER_encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_bu pos = 8; int eag_pos = p_td.oer->eag_len == 0 ? -1 : 0; for (int i = limit; i < field_count; i++) { + boolean is_default_field = default_indexes && (default_indexes[next_default_idx].index==p_td.oer->p[i]); + const Base_Type* default_value = is_default_field ? default_indexes[next_default_idx].value : NULL; + if (is_default_field) { + next_default_idx++; + } pos--; if (eag_pos != -1 && p_td.oer->eag[eag_pos] == i - limit) { eag_pos++; + bool found = false; for (int j = i; j < limit + p_td.oer->eag[eag_pos]; j++) { - if (get_at(p_td.oer->p[j])->is_bound() && get_at(p_td.oer->p[j])->is_present()) { - // Add bit if there are at least one present field - c += 1 << pos; - break; + if (j != i) { + is_default_field = default_indexes && (default_indexes[next_default_idx].index==p_td.oer->p[j]); + default_value = is_default_field ? default_indexes[next_default_idx].value : NULL; + if (is_default_field) { + next_default_idx++; + } + } + if (get_at(p_td.oer->p[j])->is_bound() && get_at(p_td.oer->p[j])->is_present() && + (!is_default_field || !get_at(p_td.oer->p[j])->is_equal(default_value))) { + found = true; } } + if (found) { + // Add bit if there is at least one present field + c += 1 << pos; + } i += p_td.oer->eag[eag_pos] - p_td.oer->eag[eag_pos-1] - 1; eag_pos++; } else { // extension attribute groups counted as one in the presence bitmap - if (get_at(p_td.oer->p[i])->is_present()) { + if (get_at(p_td.oer->p[i])->is_present() && + (!is_default_field || !get_at(p_td.oer->p[i])->is_equal(default_value))) { c += 1 << pos; } } @@ -6351,9 +6390,11 @@ int Record_Type::OER_encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_bu p_buf.put_buf(tmp_buf); tmp_buf.clear(); + next_default_idx = ext_default_idx_start; eag_pos = p_td.oer->eag_len == 0 ? -1 : 0; for (int i = limit; i < field_count; ++i) { boolean is_default_field = default_indexes && (default_indexes[next_default_idx].index==p_td.oer->p[i]); + const Base_Type* default_value = is_default_field ? default_indexes[next_default_idx].value : NULL; if (is_default_field) { next_default_idx++; } @@ -6366,18 +6407,24 @@ int Record_Type::OER_encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_bu if (is_default_field) { next_default_idx--; } + int current_default_idx = next_default_idx; bool has_present = false; for (int j = i; j < limit + p_td.oer->eag[eag_pos]; j++) { - if (get_at(p_td.oer->p[j])->is_present()) { - has_present = true; - } is_default_field = default_indexes && (default_indexes[next_default_idx].index==p_td.oer->p[j]); + default_value = is_default_field ? default_indexes[next_default_idx].value : NULL; if (is_default_field) { next_default_idx++; } + if (get_at(p_td.oer->p[j])->is_present() && + (!is_default_field || !get_at(p_td.oer->p[j])->is_equal(default_value))) { + has_present = true; + } if (get_at(p_td.oer->p[j])->is_optional() || is_default_field) { pos--; - c += get_at(p_td.oer->p[j])->is_present() << pos; + if (get_at(p_td.oer->p[j])->is_present() && + (!is_default_field || !get_at(p_td.oer->p[j])->is_equal(default_value))) { + c += 1 << pos; + } if (pos == 0) { tmp_buf.put_c(c); pos = 8; @@ -6389,8 +6436,16 @@ int Record_Type::OER_encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_bu tmp_buf.put_c(c); } if (has_present) { + next_default_idx = current_default_idx; for (int j = i; j < limit + p_td.oer->eag[eag_pos]; j++) { - get_at(p_td.oer->p[j])->OER_encode(*fld_descr(p_td.oer->p[j]), tmp_buf); + is_default_field = default_indexes && (default_indexes[next_default_idx].index==p_td.oer->p[j]); + default_value = is_default_field ? default_indexes[next_default_idx].value : NULL; + if (is_default_field) { + next_default_idx++; + } + if (!is_default_field || !get_at(p_td.oer->p[j])->is_equal(default_value)) { + get_at(p_td.oer->p[j])->OER_encode(*fld_descr(p_td.oer->p[j]), tmp_buf); + } } encode_oer_length(tmp_buf.get_len(), p_buf, FALSE); p_buf.put_buf(tmp_buf); @@ -6398,7 +6453,8 @@ int Record_Type::OER_encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_bu tmp_buf.clear(); i += p_td.oer->eag[eag_pos] - p_td.oer->eag[eag_pos-1] - 1; eag_pos++; - } else if (get_at(p_td.oer->p[i])->is_bound() && get_at(p_td.oer->p[i])->is_present()) { + } else if (get_at(p_td.oer->p[i])->is_bound() && get_at(p_td.oer->p[i])->is_present() && + (!is_default_field || !get_at(p_td.oer->p[i])->is_equal(default_value))) { get_at(p_td.oer->p[i])->OER_encode(*fld_descr(p_td.oer->p[i]), tmp_buf); encode_oer_length(tmp_buf.get_len(), p_buf, FALSE); p_buf.put_buf(tmp_buf); @@ -6862,8 +6918,13 @@ int Record_Type::OER_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_bu if (eag_pos != -1 && p_td.oer->eag[eag_pos] == i - limit) { eag_pos++; for (int j = i; j < limit + p_td.oer->eag[eag_pos]; j++) { - is_default_field = default_indexes && (default_indexes[next_default_idx].index==p_td.oer->p[j]); - default_value = is_default_field ? default_indexes[next_default_idx].value : NULL; + if (j != i) { + is_default_field = default_indexes && (default_indexes[next_default_idx].index==p_td.oer->p[j]); + default_value = is_default_field ? default_indexes[next_default_idx].value : NULL; + if (is_default_field) { + next_default_idx++; + } + } if (get_at(p_td.oer->p[j])->is_optional()) { get_at(p_td.oer->p[j])->set_to_omit(); } diff --git a/regression_test/OER/OER.ttcn b/regression_test/OER/OER.ttcn index 26f5eecfc37f453619599d6e4f464ef554ec6216..8ce3e6eb678dd08d7e1a4de4ee26188108007334 100644 --- a/regression_test/OER/OER.ttcn +++ b/regression_test/OER/OER.ttcn @@ -2700,6 +2700,17 @@ if (not(match(log2str(erres7), log2str(erres71)))) { setverdict(fail, "tc_sequence: ", match(log2str(erres7), log2str(erres71))); } + + er7 := { + me := 1, + f1 := 5, // default value + f2 := omit, + f3 := 5 // default value + } + os := enc_ExtensionRecord5(er7); + if (os != '400101'O) { // there's no extension in the encoding, since it only contains default values and 'omit' + setverdict(fail, "tc_sequence: ", match('400101'O, os)); + } er7 := { me := 1, @@ -2747,7 +2758,7 @@ setverdict(fail, "tc_sequence: ", match(log2str(er7), log2str(erres7))); } - var ExtensionRecord6 er8, erres8; + var ExtensionRecord6 er8, erres8, erres81; er8 := { me := 1, f0 := 0, @@ -2766,9 +2777,24 @@ if (os != 'C001010302FFE0038001000380010103800102038001030380010403800105038001060380010703800108038001090180'O) { setverdict(fail, "tc_sequence: ", match('C001010302FFE0038001000380010103800102038001030380010403800105038001060380010703800108038001090180'O, os)); } + erres81 := { + me := 1, + f0 := 0, + f1 := 1, + f2 := 2, + f3 := 3, + f4 := 4, + f5 := 5, + f6 := 6, + f7 := 7, + f8 := 8, + f9 := 9, + f_nul := NULL, + f10 := 4 // default value + } erres8 := dec_ExtensionRecord6(os); - if (not(match(log2str(er8), log2str(erres8)))) { - setverdict(fail, "tc_sequence: ", match(log2str(er8), log2str(erres8))); + if (not(match(log2str(erres81), log2str(erres8)))) { + setverdict(fail, "tc_sequence: ", match(log2str(erres81), log2str(erres8))); } er8 := { @@ -2789,9 +2815,24 @@ if (os != 'C001010302D8A003800100038001010380010303800104038001080180'O) { setverdict(fail, "tc_sequence: ", match('C001010302D8A003800100038001010380010303800104038001080180'O, os)); } + erres81 := { + me := 1, + f0 := 0, + f1 := 1, + f2 := omit, + f3 := 3, + f4 := 4, + f5 := omit, + f6 := omit, + f7 := omit, + f8 := 8, + f9 := omit, + f_nul := NULL, + f10 := 4 // default value + } erres8 := dec_ExtensionRecord6(os); - if (not(match(log2str(er8), log2str(erres8)))) { - setverdict(fail, "tc_sequence: ", match(log2str(er8), log2str(erres8))); + if (not(match(log2str(erres81), log2str(erres8)))) { + setverdict(fail, "tc_sequence: ", match(log2str(erres81), log2str(erres8))); } er8 := { @@ -2867,6 +2908,33 @@ setverdict(fail, "tc_sequence: ", match('C001010302D8BC0380010003800101038001030380010403800108018002010A04010B010C02010D'O, os)); } erres8 := dec_ExtensionRecord6(os); + if (not(match(log2str(er8), log2str(erres8)))) { + setverdict(fail, "tc_sequence: ", match(log2str(er8), log2str(erres8))); + } + + er8 := { + me := 1, + f0 := 5, // default value + f1 := 3, + f2 := omit, + f3 := 5, // default value + f4 := omit, + f5 := omit, + f6 := omit, + f7 := 2, + f8 := 1, + f9 := omit, + f_nul := omit, + f10 := 4, // default value + f11 := 11, + f12 := 12, + f13 := 13 + } + os := enc_ExtensionRecord6(er8); + if (os != 'C001010302418C03800103038001020380010104010B010C02010D'O) { + setverdict(fail, "tc_sequence: ", match('C001010302418C03800103038001020380010104010B010C02010D'O, os)); + } + erres8 := dec_ExtensionRecord6(os); if (not(match(log2str(er8), log2str(erres8)))) { setverdict(fail, "tc_sequence: ", match(log2str(er8), log2str(erres8))); } @@ -3581,7 +3649,7 @@ with { extension "prototype (convert) decode(OER)" } // Testing the decoding of a field with a default value (bug 534769, bug 534943) - testcase tc_default() runs on EmptyCT { + testcase tc_default_dec() runs on EmptyCT { var octetstring enc := '000104'O; var RecWithDefault dec := dec_RecWithDefault(enc); var RecWithDefault dec_exp := { field1 := 1, field2 := 4 }; @@ -3590,6 +3658,20 @@ } setverdict(pass); } + + external function enc_RecWithDefault(in RecWithDefault pdu) return octetstring + with { extension "prototype (convert) encode(OER)" } + + // Testing that the encoder omits the default field if its value is equal to the default value (bug 537502) + testcase tc_default_enc() runs on EmptyCT { + var RecWithDefault x := { field1 := 1, field2 := 4 }; + var octetstring enc := enc_RecWithDefault(x); + var octetstring enc_exp := '000104'O; + if (enc != enc_exp) { + setverdict(fail, "Encoding failed. Got: ", enc, ", expected: ", enc_exp); + } + setverdict(pass); + } control { execute(tc_boolean()); @@ -3612,7 +3694,8 @@ execute(tc_example()); execute(tc_529017()); execute(tc_533061()); - execute(tc_default()); + execute(tc_default_dec()); + execute(tc_default_enc()); } } diff --git a/regression_test/OER/Types.asn b/regression_test/OER/Types.asn index 37b09e7429c6e3335d94ef7426a907510c90257e..c06a6c79dd530d44798d19398fed2bd3191ac478 100644 --- a/regression_test/OER/Types.asn +++ b/regression_test/OER/Types.asn @@ -328,7 +328,7 @@ ExtensionRecord6 ::= SEQUENCE { [[f8 INTEGER DEFAULT 4]], [[f9 INTEGER OPTIONAL]], [[f-nul NULL OPTIONAL]], - f10 INTEGER, + f10 INTEGER DEFAULT 4, [[f11 INTEGER, f12 INTEGER]], f13 INTEGER