From 344d0e03e7ce4cbd7c4579b6c13226a48b8eeaf9 Mon Sep 17 00:00:00 2001
From: Botond Baranyi <botond.baranyi@ericsson.com>
Date: Wed, 29 Aug 2018 16:08:27 +0200
Subject: [PATCH] Fixed OER encoding of empty records and record-ofs (github
 issues 133 and 134)

Change-Id: Ibde4c1345b1644427678a9e488ec53b34568ed8f
Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com>
---
 compiler2/record.c            | 24 ++++++++++++++++-----
 core/OER.cc                   |  3 ++-
 core2/Basetype2.cc            | 18 ++++++++++++++--
 regression_test/OER/OER.ttcn  | 40 +++++++++++++++++++++++++++++++++++
 regression_test/OER/Types.asn |  6 ++++++
 5 files changed, 83 insertions(+), 8 deletions(-)

diff --git a/compiler2/record.c b/compiler2/record.c
index 076f6b766..53fc76430 100644
--- a/compiler2/record.c
+++ b/compiler2/record.c
@@ -6792,25 +6792,39 @@ static void defEmptyRecordClass(const struct_def *sdef,
   if (oer_needed) {
     // OER encode, RT1
     src = mputprintf(src,
-      "int %s::OER_encode(const TTCN_Typedescriptor_t&, TTCN_Buffer&) const\n"
+      "int %s::OER_encode(const TTCN_Typedescriptor_t&, TTCN_Buffer&%s) const\n"
       "{\n"
       "  if (!is_bound()) {\n"
       "    TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,\n"
       "      \"Encoding an unbound value of type %s.\");\n"
       "    return -1;\n"
       "  }\n\n"
+      "%s"
       "  return 0;\n"
       "}\n\n"
-      , name, dispname);
+      , name, sdef->oerExtendable ? " p_buf" : "", dispname
+      , sdef->oerExtendable ? "  p_buf.put_c(0);\n" : "");
     
     // OER decode, RT1
     src = mputprintf(src,
-      "int %s::OER_decode(const TTCN_Typedescriptor_t&, TTCN_Buffer&, OER_struct&)\n"
+      "int %s::OER_decode(const TTCN_Typedescriptor_t&, TTCN_Buffer&%s, OER_struct&)\n"
       "{\n"
       "  bound_flag = TRUE;\n"
+      , name, sdef->oerExtendable ? " p_buf" : "");
+    if (sdef->oerExtendable) {
+      src = mputstr(src,
+        "  const unsigned char* uc = p_buf.get_read_data();\n"
+        "  boolean has_extension = (uc[0] & 0x80) != 0;\n"
+        "  p_buf.increase_pos(1);\n"
+        "  if (has_extension) {\n"
+        "    size_t bytes = decode_oer_length(p_buf, FALSE);\n"
+        "    p_buf.increase_pos(bytes);\n"
+        // TODO: handle extension fields
+        "  }\n");
+    }
+    src = mputstr(src,
       "  return 0;\n"
-      "}\n\n"
-      , name);
+      "}\n\n");      
   }
 
     /* closing class definition */
diff --git a/core/OER.cc b/core/OER.cc
index fd0e3b3fa..3a69e01a2 100644
--- a/core/OER.cc
+++ b/core/OER.cc
@@ -24,10 +24,11 @@ void encode_oer_length(size_t num_bytes, TTCN_Buffer& buf, boolean seof) {
     size_t bytes = num_bytes;
     // Encode length in maybe more than 1 byte
     size_t needed_bytes = 0;
-    while (bytes != 0) {
+    do {
       bytes >>= 8;
       needed_bytes++;
     }
+    while (bytes != 0);
     char c = 0;
     if (seof == FALSE) {
       c |= 1 << 7;
diff --git a/core2/Basetype2.cc b/core2/Basetype2.cc
index 630628be8..eabf226dd 100644
--- a/core2/Basetype2.cc
+++ b/core2/Basetype2.cc
@@ -7011,6 +7011,7 @@ int Record_Type::OER_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_bu
         act_pos = 0;
       }
     }
+    // TODO: handle extra extension fields
   }
   else if (p_td.oer->extendable) {
     // Set the optional fields after the extension to 'omit'
@@ -7442,17 +7443,30 @@ int Empty_Record_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Token
   return (int)dec_len;
 }
 
-int Empty_Record_Type::OER_encode(const TTCN_Typedescriptor_t&, TTCN_Buffer&) const {
+int Empty_Record_Type::OER_encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf) const {
   if (!is_bound()) {
     TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,
       "Encoding an unbound empty %s value.", is_set() ? "set" : "record");
     return -1;
   }
+  if (p_td.oer->extendable) {
+    p_buf.put_c(0);
+  }
   return 0;
 }
   
-int Empty_Record_Type::OER_decode(const TTCN_Typedescriptor_t&, TTCN_Buffer&, OER_struct&) {
+int Empty_Record_Type::OER_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, OER_struct&) {
   bound_flag = TRUE;
+  if (p_td.oer->extendable) {
+    const unsigned char* uc = p_buf.get_read_data();
+    boolean has_extension = (uc[0] & 0x80) != 0;
+    p_buf.increase_pos(1);
+    if (has_extension) {
+      size_t bytes = decode_oer_length(p_buf, FALSE);
+      p_buf.increase_pos(bytes);
+      // TODO: handle extension fields
+    }
+  }
   return 0;
 }
 
diff --git a/regression_test/OER/OER.ttcn b/regression_test/OER/OER.ttcn
index 8ce3e6eb6..a455baa2b 100644
--- a/regression_test/OER/OER.ttcn
+++ b/regression_test/OER/OER.ttcn
@@ -3252,6 +3252,44 @@
 
  		setverdict(pass);
  	}
+ 	
+ 	external function enc_EmptySeq(in EmptyExtendableSequence os) return octetstring
+    with { extension "prototype(convert) encode(OER)" }
+  
+  external function dec_EmptySeq(in octetstring os) return EmptyExtendableSequence
+    with { extension "prototype(convert) decode(OER)" }
+ 	
+ 	testcase tc_sequence_empty() runs on EmptyCT {
+ 	  var EmptyExtendableSequence x := {};
+ 	  var octetstring os := enc_EmptySeq(x);
+ 	  if (os != '00'O) {
+ 	    setverdict(fail, "tc_sequence_empty: ", match('00'O, os));
+ 	  }
+ 	  var EmptyExtendableSequence y := dec_EmptySeq(os);
+ 	  if (y != x) {
+ 	    setverdict(fail, "tc_sequence_empty: ", match(x, y));
+ 	  }
+ 	  setverdict(pass);
+ 	}
+ 	
+ 	external function enc_SeqOfInt(in SequenceOfInteger os) return octetstring
+    with { extension "prototype(convert) encode(OER)" }
+  
+  external function dec_SeqOfInt(in octetstring os) return SequenceOfInteger
+    with { extension "prototype(convert) decode(OER)" }
+  
+  testcase tc_sequence_of_empty() runs on EmptyCT {
+ 	  var SequenceOfInteger x := {};
+ 	  var octetstring os := enc_SeqOfInt(x);
+ 	  if (os != '0100'O) {
+ 	    setverdict(fail, "tc_sequence_of_empty: ", match('0100'O, os));
+ 	  }
+ 	  var SequenceOfInteger y := dec_SeqOfInt(os);
+ 	  if (y != x) {
+ 	    setverdict(fail, "tc_sequence_of_empty: ", match(x, y));
+ 	  }
+ 	  setverdict(pass);
+ 	}
 
  	external function enc_MySet(in MySet pdu) return octetstring
      with { extension "prototype (convert) encode(OER)" }
@@ -3685,6 +3723,8 @@
  		execute(tc_universal_charstring());
  		execute(tc_objid());
  		execute(tc_sequence());
+ 		execute(tc_sequence_empty());
+ 		execute(tc_sequence_of_empty());
  		execute(tc_pdv());
  		execute(tc_union());
  		execute(tc_set());
diff --git a/regression_test/OER/Types.asn b/regression_test/OER/Types.asn
index c06a6c79d..7e8582f5a 100644
--- a/regression_test/OER/Types.asn
+++ b/regression_test/OER/Types.asn
@@ -549,5 +549,11 @@ RecWithDefault ::= SEQUENCE
   field2 INTEGER
 }
 
+EmptyExtendableSequence ::= SEQUENCE {
+  ...
+}
+
+SequenceOfInteger ::= SEQUENCE OF INTEGER
+
 
 END
-- 
GitLab