From 7bec2f701381d27b1a0e71247b617f82d8aa9857 Mon Sep 17 00:00:00 2001
From: BenceJanosSzabo <bence.janos.szabo@ericsson.com>
Date: Tue, 18 Oct 2016 10:53:50 +0200
Subject: [PATCH] Fixed embed values are incorreclty encoded and decoded in
 record of records (Bug 505692)

Change-Id: I906e70839019de512f79b0dc4139a02ba95480df
Signed-off-by: BenceJanosSzabo <bence.janos.szabo@ericsson.com>
---
 compiler2/record.c                            |  42 +++++-
 compiler2/record_of.c                         |   3 +-
 core2/Basetype2.cc                            |  26 +++-
 .../XML/TTCNandXML/EmbedValues.ttcnpp         | 140 +++++++++++++++++-
 4 files changed, 201 insertions(+), 10 deletions(-)

diff --git a/compiler2/record.c b/compiler2/record.c
index 66e70ef82..fea74106c 100644
--- a/compiler2/record.c
+++ b/compiler2/record.c
@@ -1915,7 +1915,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc)
   /* * * * * * * * * * XER_encode * * * * * * * * * * * * * * */
   src = mputprintf(src,
     "int %s::XER_encode(const XERdescriptor_t& p_td, "
-    "TTCN_Buffer& p_buf, unsigned int p_flavor, int p_indent, embed_values_enc_struct_t*) const\n"
+    "TTCN_Buffer& p_buf, unsigned int p_flavor, int p_indent, embed_values_enc_struct_t* emb_val_parent) const\n"
     "{\n"
     "  if (!is_bound()) TTCN_EncDec_ErrorContext::error"
     "(TTCN_EncDec::ET_UNBOUND, \"Encoding an unbound value.\");\n"
@@ -2076,7 +2076,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc)
     /* If the first component is a record-of with ANY-ATTRIBUTES,
      * it has been taken care of because it looked like an EMBED-VALUES */
     if (i==0 && sdef->xerEmbedValuesPossible && (sdef->elements[i].xerAnyKind & ANY_ATTRIB_BIT)) continue ;
-    src = mputprintf(src,
+    src = mputprintf(src, 
       "  ec_1.set_msg(\"%s': \");\n"
       "  tmp_len = field_%s.XER_encode(%s_xer_, p_buf, p_flavor, p_indent+1, 0);\n"
       "  %ssub_len += tmp_len;\n" /* do not add if attribute and EXER */
@@ -2288,6 +2288,29 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc)
         "  ec_1.set_msg(\"%s': \");\n"
         , sdef->elements[i].dispname
       );
+      if (i > start_at + num_attributes) { // First field's embed value is already processed
+        src = mputprintf(src, 
+          "if (e_xer && (p_td.xer_bits & UNTAGGED && !(p_td.xer_bits & EMBED_VALUES) && 0 != emb_val_parent\n"
+          "  %s%s%s)) {\n"
+          "  if (0 != emb_val_parent->embval_array_reg) {\n"
+          "    if (emb_val_parent->embval_index < emb_val_parent->embval_array_reg->size_of()) {\n"
+          "      (*emb_val_parent->embval_array_reg)[emb_val_parent->embval_index].XER_encode(UNIVERSAL_CHARSTRING_xer_"
+          "      , p_buf, p_flavor | EMBED_VALUES, p_indent+1, 0);\n"
+          "      ++emb_val_parent->embval_index;\n"
+          "    }\n"
+          "  } else {\n"
+           "   if (emb_val_parent->embval_index < emb_val_parent->embval_array_opt->size_of()) {\n"
+          "      (*emb_val_parent->embval_array_opt)[emb_val_parent->embval_index].XER_encode(UNIVERSAL_CHARSTRING_xer_"
+          "      , p_buf, p_flavor | EMBED_VALUES, p_indent+1, 0);\n"
+          "      ++emb_val_parent->embval_index;\n"
+          "    }\n"
+          "  }\n"
+          "}\n"
+          , sdef->elements[0].isOptional ? "&& field_" : ""
+          , sdef->elements[0].isOptional ? sdef->elements[0].name : ""
+          , sdef->elements[0].isOptional ? ".ispresent()" : ""
+        );
+      }
       src = mputprintf(src,
         "  sub_len += field_%s.XER_encode(%s_xer_, p_buf, p_flavor%s, p_indent+!omit_tag, %s);\n"
         , sdef->elements[i].name, sdef->elements[i].typegen
@@ -2383,7 +2406,7 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc)
 
   src = mputprintf(src, /* XERSTUFF decodegen for record/SEQUENCE*/
     "int %s::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& p_reader,"
-    " unsigned int p_flavor, unsigned int p_flavor2, embed_values_dec_struct_t*)\n"
+    " unsigned int p_flavor, unsigned int p_flavor2, embed_values_dec_struct_t* emb_val_parent)\n"
     "{\n"
     /* Remove XER_LIST, XER_RECOF from p_flavor. This is not required
      * for is_exer (which tests another bit), but for subsequent code. */
@@ -2969,6 +2992,19 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc)
       "    ec_1.set_msg(\"%s': \");\n"
       , sdef->elements[i].dispname);
     
+    src = mputprintf(src, 
+      "  if (p_td.xer_bits & UNTAGGED && 0 != emb_val_parent) {\n"
+      "    if (p_reader.NodeType() == XML_READER_TYPE_TEXT) {\n"
+      "      UNIVERSAL_CHARSTRING emb_ustr((const char*)p_reader.Value());\n"
+      "      if (0 != emb_val_parent->embval_array_reg) {\n"
+      "        (*emb_val_parent->embval_array_reg)[emb_val_parent->embval_index] = emb_ustr;\n"
+      "      } else {\n"
+      "        (*emb_val_parent->embval_array_opt)[emb_val_parent->embval_index] = emb_ustr;\n"
+      "      }\n"
+      "      ++emb_val_parent->embval_index;\n"
+      "    }\n"
+      "  }\n");
+    
     if ( (sdef->elements[i].xerAnyKind & ANY_ELEM_BIT)
          && !strcmp(sdef->elements[i].type,"UNIVERSAL_CHARSTRING") ) {
       // In case the field is an optional anyElement -> check if it should be omitted
diff --git a/compiler2/record_of.c b/compiler2/record_of.c
index 0e8fc1ab3..eef45b375 100644
--- a/compiler2/record_of.c
+++ b/compiler2/record_of.c
@@ -1506,7 +1506,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
       /* The call to the non-const operator[] creates the element */
       "            (*this)[val_ptr->n_elements].XER_decode(*p_td.oftype_descr, p_reader, p_flavor, p_flavor2, emb_val);\n"    
       "          }\n"
-      "          if (0 != emb_val && !own_tag && val_ptr->n_elements > 1) {\n"
+      "          if (0 != emb_val && !own_tag && val_ptr->n_elements > 1 && !(p_td.oftype_descr->xer_bits & UNTAGGED)) {\n"
       "            ++emb_val->embval_index;\n"
       "          }\n"
       "        }\n"
@@ -1527,6 +1527,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
       "            (*emb_val->embval_array_opt)[emb_val->embval_index] = emb_ustr;\n"
       "          }\n"
       "          rd_ok = p_reader.Read();\n"
+      "          if (p_td.oftype_descr->xer_bits & UNTAGGED) ++emb_val->embval_index;\n"
       "        }\n"
       "        else {\n"
       "          rd_ok = p_reader.Read();\n"
diff --git a/core2/Basetype2.cc b/core2/Basetype2.cc
index 9248c4b83..50e3acaba 100644
--- a/core2/Basetype2.cc
+++ b/core2/Basetype2.cc
@@ -2400,7 +2400,7 @@ int Record_Of_Type::XER_decode(const XERdescriptor_t& p_td,
             /* The call to the non-const get_at() creates the element */
             get_at(get_nof_elements())->XER_decode(*p_td.oftype_descr, reader, flavor, flavor2, emb_val);
           }
-          if (0 != emb_val && !own_tag && get_nof_elements() > 1) {
+          if (0 != emb_val && !own_tag && get_nof_elements() > 1 && !(p_td.oftype_descr->xer_bits & UNTAGGED)) {
             ++emb_val->embval_index;
           }
         }
@@ -2413,11 +2413,12 @@ int Record_Of_Type::XER_decode(const XERdescriptor_t& p_td,
             reader.Read(); // move forward one last time
           }
           break;
-        }
+        } 
         else if (XML_READER_TYPE_TEXT == type && 0 != emb_val && !own_tag && get_nof_elements() > 0) {
           UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value());
           emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr);
           success = reader.Read();
+          if (p_td.oftype_descr->xer_bits & UNTAGGED) ++emb_val->embval_index;
         }
         else {
           success = reader.Read();
@@ -4114,7 +4115,7 @@ int Record_Type::get_index_byname(const char *name, const char *uri) const {
 }
 
 int Record_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf,
-  unsigned int flavor, int indent, embed_values_enc_struct_t*) const
+  unsigned int flavor, int indent, embed_values_enc_struct_t* emb_val_parent) const
 {
   if (err_descr) {
     return XER_encode_negtest(err_descr, p_td, p_buf, flavor, indent, 0);
@@ -4414,7 +4415,13 @@ int Record_Type::XER_encode(const XERdescriptor_t& p_td, TTCN_Buffer& p_buf,
           uoe = use_order->get_at(i - begin);
           enm = static_cast<const Enum_Type *>(uoe);
         }
-
+        if (p_td.xer_bits & UNTAGGED && i > 0 && exer && embed_values == NULL && 0 != emb_val_parent &&
+          emb_val_parent->embval_index < emb_val_parent->embval_array->size_of()) {
+          emb_val_parent->embval_array->get_at(emb_val_parent->embval_index)->XER_encode(UNIVERSAL_CHARSTRING_xer_
+            , p_buf, flavor | EMBED_VALUES, indent+1, 0);
+          ++emb_val_parent->embval_index;
+        }
+        
         // "actual" index, may be perturbed by USE-ORDER
         int ai = !(exer && (p_td.xer_bits & USE_ORDER)) ? i :
         enm->as_int() + useorder_base;
@@ -5127,7 +5134,7 @@ int Record_Type::XER_encode_negtest(const Erroneous_descriptor_t* p_err_descr,
 }
 
 int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader,
-                            unsigned int flavor, unsigned int flavor2, embed_values_dec_struct_t*)
+                            unsigned int flavor, unsigned int flavor2, embed_values_dec_struct_t* emb_val_parent)
 {
   int exer = is_exer(flavor);
   int success, type;
@@ -5601,6 +5608,15 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader,
               ++emb_val->embval_index;
             }
             last_embval_index = emb_val->embval_index;
+          } else if (p_td.xer_bits & UNTAGGED && 0 != emb_val_parent) {
+            if (reader.NodeType()==XML_READER_TYPE_TEXT) {
+              UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value());
+              emb_val_parent->embval_array->get_at(emb_val_parent->embval_index)->set_value(&emb_ustr);
+            }
+            if (last_embval_index == emb_val_parent->embval_index) {
+              ++emb_val_parent->embval_index;
+            }
+            last_embval_index = emb_val_parent->embval_index;
           }
           ec_1.set_msg("%s': ", fld_name(i));
           if (exer && i==field_cnt-1 && p_td.dfeValue && reader.IsEmptyElement()) {
diff --git a/regression_test/XML/TTCNandXML/EmbedValues.ttcnpp b/regression_test/XML/TTCNandXML/EmbedValues.ttcnpp
index 39e1fbaa8..134006836 100644
--- a/regression_test/XML/TTCNandXML/EmbedValues.ttcnpp
+++ b/regression_test/XML/TTCNandXML/EmbedValues.ttcnpp
@@ -389,6 +389,142 @@ testcase dec_emb_opt() runs on Embedder
   CHECK_DECODE(exer_dec_eo, estr_test2, EmOpt, expected);
 }
 
+
+
+/****************** EMBED-VALUES and record of record fields untagged ******************/
+
+type record EmbRecordOrRecordUntagged {
+  record of universal charstring embed,
+  record of record {
+    universal charstring a,
+    boolean b
+  } sequence_list
+}
+with {
+  variant "embedValues"
+  variant "element";
+  variant (sequence_list) "untagged";
+  variant (sequence_list[-]) "untagged";
+}
+
+DECLARE_XER_ENCODERS(EmbRecordOrRecordUntagged, erecofrecuntagged);
+DECLARE_EXER_ENCODERS(EmbRecordOrRecordUntagged, erecofrecuntagged);
+
+const EmbRecordOrRecordUntagged c_testingrecofrecuntagged := {
+  embed := { "a1", "b1", "a2", "b2", "end" },
+  sequence_list := {
+    {
+      a := "firsta",
+      b := false
+    },
+    {
+      a := "seconda",
+      b := false
+    }
+  }
+}
+
+const universal charstring bstr_test7 :=
+"<EmbRecordOrRecordUntagged>\n" &
+"\t<embed>\n" &
+"\t\t<UNIVERSAL_CHARSTRING>a1</UNIVERSAL_CHARSTRING>\n" &
+"\t\t<UNIVERSAL_CHARSTRING>b1</UNIVERSAL_CHARSTRING>\n" &
+"\t\t<UNIVERSAL_CHARSTRING>a2</UNIVERSAL_CHARSTRING>\n" &
+"\t\t<UNIVERSAL_CHARSTRING>b2</UNIVERSAL_CHARSTRING>\n" &
+"\t\t<UNIVERSAL_CHARSTRING>end</UNIVERSAL_CHARSTRING>\n" &
+"\t</embed>\n" &
+"\t<sequence_list>\n" &
+"\t\t<SEQUENCE>\n" &
+"\t\t\t<a>firsta</a>\n" &
+"\t\t\t<b><false/></b>\n" &
+"\t\t</SEQUENCE>\n" &
+"\t\t<SEQUENCE>\n" &
+"\t\t\t<a>seconda</a>\n" &
+"\t\t\t<b><false/></b>\n" &
+"\t\t</SEQUENCE>\n" &
+"\t</sequence_list>\n" &
+"</EmbRecordOrRecordUntagged>\n\n";
+
+const universal charstring estr_test7 :=
+"<EmbRecordOrRecordUntagged>a1" &
+"<a>firsta</a>b1"&
+"<b>false</b>a2"&
+"<a>seconda</a>b2"&
+"<b>false</b>end"&
+"</EmbRecordOrRecordUntagged>\n"
+
+
+const universal charstring bstr_test8 :=
+"<EmbRecordOrRecordUntagged>\n"&
+"\t<embed>\n"&
+"\t\t<UNIVERSAL_CHARSTRING>first</UNIVERSAL_CHARSTRING>\n"&
+"\t\t<UNIVERSAL_CHARSTRING>second</UNIVERSAL_CHARSTRING>\n"&
+"\t\t<UNIVERSAL_CHARSTRING>third</UNIVERSAL_CHARSTRING>\n"&
+"\t</embed>\n"&
+"\t<sequence_list>\n"&
+"\t\t<SEQUENCE>\n"&
+"\t\t\t<a>firsta</a>\n"&
+"\t\t\t<b><false/></b>\n"&
+"\t\t</SEQUENCE>\n"&
+"\t</sequence_list>\n"&
+"</EmbRecordOrRecordUntagged>\n"&
+"\n"
+
+const universal charstring estr_test8 :=
+"<EmbRecordOrRecordUntagged>first"&
+"<a>firsta</a>second"&
+"<b>false</b>third"&
+"</EmbRecordOrRecordUntagged>\n"
+
+const universal charstring bstr_test9 :=
+"<EmbRecordOrRecordUntagged>\n"&
+"\t<embed>\n"&
+"\t\t<UNIVERSAL_CHARSTRING>first</UNIVERSAL_CHARSTRING>\n"&
+"\t\t<UNIVERSAL_CHARSTRING/>\n"&
+"\t</embed>\n"&
+"\t<sequence_list/>\n"&
+"</EmbRecordOrRecordUntagged>\n"&
+"\n"
+
+const universal charstring estr_test9 :=
+"<EmbRecordOrRecordUntagged>first"&
+"</EmbRecordOrRecordUntagged>\n"
+
+testcase enc_emb_record_of_record_untagged() runs on Embedder
+{
+  var EmbRecordOrRecordUntagged testing := c_testingrecofrecuntagged;
+  CHECK_METHOD(bxer_enc_erecofrecuntagged, testing, bstr_test7);
+  CHECK_METHOD(exer_enc_erecofrecuntagged, testing, estr_test7);
+  
+  testing.sequence_list := { { a := "firsta", b := false } }
+  testing.embed := {"first", "second", "third"}
+  CHECK_METHOD(bxer_enc_erecofrecuntagged, testing, bstr_test8);
+  CHECK_METHOD(exer_enc_erecofrecuntagged, testing, estr_test8);
+  
+  testing.sequence_list := { }
+  testing.embed := {"first", ""}
+  CHECK_METHOD(bxer_enc_erecofrecuntagged, testing, bstr_test9);
+  CHECK_METHOD(exer_enc_erecofrecuntagged, testing, estr_test9);
+}
+
+testcase dec_emb_record_of_record_untagged() runs on Embedder
+{
+  var EmbRecordOrRecordUntagged expected := c_testingrecofrecuntagged;
+  CHECK_DECODE(bxer_dec_erecofrecuntagged, bstr_test7, EmbRecordOrRecordUntagged, expected);
+  CHECK_DECODE(exer_dec_erecofrecuntagged, estr_test7, EmbRecordOrRecordUntagged, expected);
+
+  expected.sequence_list := { { a := "firsta", b := false } }
+  expected.embed := {"first", "second", "third"}
+  CHECK_DECODE(bxer_dec_erecofrecuntagged, bstr_test8, EmbRecordOrRecordUntagged, expected);
+  CHECK_DECODE(exer_dec_erecofrecuntagged, estr_test8, EmbRecordOrRecordUntagged, expected);
+
+  expected.sequence_list := { }
+  expected.embed := {"first", ""}
+  CHECK_DECODE(bxer_dec_erecofrecuntagged, bstr_test9, EmbRecordOrRecordUntagged, expected);
+  CHECK_DECODE(exer_dec_erecofrecuntagged, estr_test9, EmbRecordOrRecordUntagged, expected);
+}
+
+
 /********************** Control part **********************/
 
 control {
@@ -403,8 +539,10 @@ control {
 
     execute(enc_emb_opt());
     execute(dec_emb_opt());
-}
 
+    execute(enc_emb_record_of_record_untagged());
+    execute(dec_emb_record_of_record_untagged());
+  }
 }
 with {
   encode "XML"
-- 
GitLab