diff --git a/compiler2/record.c b/compiler2/record.c index b1d3cdf7d4ae7c1e08ce6a1ca984ab915bc4242e..4cf831439dc711528e87a7f775e8e8bb61e5f068 100644 --- a/compiler2/record.c +++ b/compiler2/record.c @@ -3041,6 +3041,13 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) " }\n" , sdef->elements[i].name); } + if (!sdef->elements[i].isOptional) { + src = mputprintf(src, + " if (field_%s.is_bound()) {\n" + " p_flavor &= ~XER_OPTIONAL;\n" + " }\n" + , sdef->elements[i].name); + } } /* next field */ if (i == start_at + num_attributes) { @@ -3117,6 +3124,10 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc) if (!sdef->elements[i].isOptional) { src = mputprintf(src, " if (!field_%s.is_bound()) {\n" + " if (p_flavor & XER_OPTIONAL) {\n" + " clean_up();\n" + " return -1;\n" + " }\n" " TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG,\n" " \"No data found for non-optional field '%s'\");\n" " }\n" diff --git a/compiler2/record_of.c b/compiler2/record_of.c index 1cd8f7be523ed1d24540b49f971e6e9a5bddd81d..828cd66de89fb62683f737322434ca40eeaed3a4 100644 --- a/compiler2/record_of.c +++ b/compiler2/record_of.c @@ -1428,6 +1428,9 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) /* The call to the non-const operator[] creates a new element object, * then we call its XER_decode with the temporary XML reader. */ " (*this)[val_ptr->n_elements].XER_decode(*p_td.oftype_descr, reader_2, p_flavor, p_flavor2, 0);\n" + " if ((*this)[val_ptr->n_elements - 1].is_bound()) {\n" + " p_flavor &= ~XER_OPTIONAL;\n" + " }\n" " if (p_flavor & EXIT_ON_ERROR && !(*this)[val_ptr->n_elements - 1].is_bound()) {\n" " if (1 == val_ptr->n_elements) {\n" // Failed to decode even the first element diff --git a/core/ASN_CharacterString.cc b/core/ASN_CharacterString.cc index fb49217c5055826fc1a7075f605ac71085b6ab4c..4b91fc63a4579a25bda9c1aac37b2b533c260545 100644 --- a/core/ASN_CharacterString.cc +++ b/core/ASN_CharacterString.cc @@ -3394,6 +3394,11 @@ int CHARACTER_STRING::XER_decode(const XERdescriptor_t& p_td, for (; success == 1; success = reader.Read()) { type = reader.NodeType(); if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); depth = reader.Depth(); reader.Read(); diff --git a/core/ASN_EmbeddedPDV.cc b/core/ASN_EmbeddedPDV.cc index 8f4b7f22ca0890b724ce4f9db722acfab9992603..c5d4e55aee75b1d8c6ba5676207538cdae68b232 100644 --- a/core/ASN_EmbeddedPDV.cc +++ b/core/ASN_EmbeddedPDV.cc @@ -3413,6 +3413,11 @@ int EMBEDDED_PDV::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, for (success = reader.Ok(); success == 1; success = reader.Read()) { type = reader.NodeType(); if (type==XML_READER_TYPE_ELEMENT) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); depth = reader.Depth(); reader.Read(); diff --git a/core/ASN_External.cc b/core/ASN_External.cc index c1690ce25b4aec0069196763720192a8ff6cd188..2ba329dc83ef6d7933984a38831a97f792e991a8 100644 --- a/core/ASN_External.cc +++ b/core/ASN_External.cc @@ -603,6 +603,11 @@ namespace { /* anonymous namespace */ for (; success == 1; success = reader.Read()) { int type = reader.NodeType(); if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); depth = reader.Depth(); reader.Read(); diff --git a/core/ASN_Null.cc b/core/ASN_Null.cc index 107d47585469f7247a49a6ad3249d05d3b3c6734..b857580844b5bebf73149119dc4d9ab328081ce6 100644 --- a/core/ASN_Null.cc +++ b/core/ASN_Null.cc @@ -266,6 +266,11 @@ int ASN_NULL::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, for (; success == 1; success = reader.Read()) { int type = reader.NodeType(); if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); depth = reader.Depth(); break; diff --git a/core/Bitstring.cc b/core/Bitstring.cc index 571b342424b382148e2e5bda19934e59019fc395..f0e6ce518c008958ec6529e3c3a60881b5f5cf9d 100644 --- a/core/Bitstring.cc +++ b/core/Bitstring.cc @@ -1104,6 +1104,11 @@ int BITSTRING::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, for (; success == 1; success = reader.Read()) { type = reader.NodeType(); if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); depth = reader.Depth(); if (reader.IsEmptyElement()) { diff --git a/core/Boolean.cc b/core/Boolean.cc index 4faa62f051fada2d53d4a73234cd0131feec5b68..ab68746175717c5d3b9ceba0d10493ef3f315f8f 100644 --- a/core/Boolean.cc +++ b/core/Boolean.cc @@ -663,6 +663,11 @@ int BOOLEAN::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, type = reader.NodeType(); if (!notag && depth == -1) { if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); depth = reader.Depth(); diff --git a/core/Charstring.cc b/core/Charstring.cc index f2994c9c770c31d39202beecdc589fab346fcbc7..5d3240fb9f1d256bfd024a98cc6a5f899792ccab 100644 --- a/core/Charstring.cc +++ b/core/Charstring.cc @@ -1372,6 +1372,11 @@ int CHARSTRING::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, for (; success == 1; success = reader.Read()) { int type = reader.NodeType(); if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); if (reader.IsEmptyElement()) { // has no text, needs special processing if (exer && p_td.dfeValue != 0) { diff --git a/core/Float.cc b/core/Float.cc index 721420353ed6498e369a1363a30e03ddf8cdc83a..e01479804506c5fc2cb6d5bce07fc881b07afcff 100644 --- a/core/Float.cc +++ b/core/Float.cc @@ -989,6 +989,11 @@ tagless: for (; success == 1; success = reader.Read()) { int type = reader.NodeType(); if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); if (reader.IsEmptyElement()) { if (exer && p_td.dfeValue != 0) { diff --git a/core/Hexstring.cc b/core/Hexstring.cc index 639c5e30816846bb40e4dfde082dee98159b3ec4..eb0595d66f28ce0e6440fda62bffba35327a8bc0 100644 --- a/core/Hexstring.cc +++ b/core/Hexstring.cc @@ -937,6 +937,11 @@ int HEXSTRING::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, if (own_tag) for (; success == 1; success = reader.Read()) { type = reader.NodeType(); if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); depth = reader.Depth(); if (reader.IsEmptyElement()) { diff --git a/core/Integer.cc b/core/Integer.cc index f84fe0f59996d617011f3ff4fd8026e364044238..4a0e88edc2dabea3eac1ad7f3e1bbfe1f346f3ef 100644 --- a/core/Integer.cc +++ b/core/Integer.cc @@ -1647,6 +1647,11 @@ tagless: for (; success == 1; success = reader.Read()) { type = reader.NodeType(); if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); if (reader.IsEmptyElement()) { if (exer && p_td.dfeValue != 0) { diff --git a/core/Objid.cc b/core/Objid.cc index dd09fd65778b8220476f3cd799356603f0e85864..fb9f997ef8e4d123fc8b2e0fc483bd1d8309c77a 100644 --- a/core/Objid.cc +++ b/core/Objid.cc @@ -566,6 +566,11 @@ int OBJID::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, for (; success == 1; success = reader.Read()) { int type = reader.NodeType(); if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); depth = reader.Depth(); break; diff --git a/core/Octetstring.cc b/core/Octetstring.cc index b652ed43e8db6197de8b5b03f709917a3fd41ec0..1aa836e988bba5b9ec027b67ddf227e1bc924ad0 100644 --- a/core/Octetstring.cc +++ b/core/Octetstring.cc @@ -975,6 +975,11 @@ int OCTETSTRING::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, if (own_tag) for (; success == 1; success = reader.Read()) { type = reader.NodeType(); if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); depth = reader.Depth(); if (reader.IsEmptyElement()) { diff --git a/core/Optional.hh b/core/Optional.hh index 8182f7ef0e835af033662e60dadd2001c756dcf1..df8a1ac446ab5b2a1fe7332b2184600d95676248 100644 --- a/core/Optional.hh +++ b/core/Optional.hh @@ -1102,7 +1102,8 @@ OPTIONAL<T_type>::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, found_it: set_to_present(); //success = reader.Read(); // move to next thing TODO should it loop till an element ? - optional_value->XER_decode(p_td, reader, flavor, flavor2, emb_val); + // Pass XER_OPTIONAL to flavor, to sign that we are optional + optional_value->XER_decode(p_td, reader, flavor | XER_OPTIONAL, flavor2, emb_val); if (!optional_value->is_bound()) { set_to_omit(); } diff --git a/core/Universal_charstring.cc b/core/Universal_charstring.cc index a826ff1d4c97f190721e2dd3003ade5c1205c48d..4d9957f067b38f89a1de1d2865f6b0363fc9faf0 100644 --- a/core/Universal_charstring.cc +++ b/core/Universal_charstring.cc @@ -2148,6 +2148,11 @@ int UNIVERSAL_CHARSTRING::XER_decode(const XERdescriptor_t& p_td, if (!omit_tag) for (; success == 1; success = reader.Read()) { int type = reader.NodeType(); if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) { + return -1; + } verify_name(reader, p_td, exer); if (reader.IsEmptyElement()) { if (exer && p_td.dfeValue != 0) { diff --git a/core/Verdicttype.cc b/core/Verdicttype.cc index 82a47649865a32e3cddde01c71e440f900b58a4f..fdbb3e3d7a8c6ef5cb31ef5fe4c373e3cef5f7fc 100644 --- a/core/Verdicttype.cc +++ b/core/Verdicttype.cc @@ -332,6 +332,12 @@ int VERDICTTYPE::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& p_reader if (name_tag) for (; rd_ok == 1; rd_ok = p_reader.Read()) { type = p_reader.NodeType(); if (XML_READER_TYPE_ELEMENT == type) { + // If our parent is optional and there is an unexpected tag then return and + // we stay unbound. + if ((p_flavor & XER_OPTIONAL) && !check_name((const char*)p_reader.LocalName(), p_td, e_xer)) { + return -1; + } + verify_name(p_reader, p_td, e_xer); rd_ok = p_reader.Read(); break; } diff --git a/core/XER.hh b/core/XER.hh index efc41a4afeff486793f48cb2f1a0a817d207a67f..c2bea32e094f664c2e9e84c1194e3537052d4d5b 100644 --- a/core/XER.hh +++ b/core/XER.hh @@ -57,7 +57,6 @@ enum XER_flavor { XER_EXTENDED = 1U << 2, /**< Extended XER */ DEF_NS_PRESENT = 1U << 3, // 0x08 DEF_NS_SQUASHED = 1U << 4, // 0x10 - XER_MASK = 0x1FU, /**< All the "real" XER flavors plus DEF_NS */ /* Additional flags, for the parent to pass information to its children * (when the parent affects the child, e.g. LIST) */ @@ -100,7 +99,10 @@ enum XER_flavor { EXIT_ON_ERROR = 1U << 29, /* 0x20000000 clean up and exit instead of throwing a decoding error, used on alternatives of a union with USE-UNION */ XER_OPTIONAL = 1U << 30, // 0x40000000 is an optional field of a record or set - BLOCKED = 1U << 31 // 0x80000000 either ABSTRACT or BLOCK + BLOCKED = 1U << 31, // 0x80000000 either ABSTRACT or BLOCK + + /**< All the "real" XER flavors plus DEF_NS + XER_OPTIONAL*/ + XER_MASK = 0x1FU | XER_OPTIONAL }; enum XER_flavor2 { diff --git a/core2/Basetype2.cc b/core2/Basetype2.cc index c62c657d5962b6a570ba7e8a57bf8e9817c13e24..695fdff6de0a1aae65ec6cc459dc8e7e6e2eff44 100644 --- a/core2/Basetype2.cc +++ b/core2/Basetype2.cc @@ -2399,6 +2399,9 @@ int Record_Of_Type::XER_decode(const XERdescriptor_t& p_td, ec_1.set_msg("%d: ", get_nof_elements()); /* 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 (get_at(get_nof_elements()-1)->is_bound()) { + flavor &= ~XER_OPTIONAL; + } } if (0 != emb_val && !own_tag && get_nof_elements() > 1 && !(p_td.oftype_descr->xer_bits & UNTAGGED)) { ++emb_val->embval_index; @@ -5589,7 +5592,7 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, } } // not empty element } - else { // not USE-ORDER, simpler code + else { // not USE-ORDER, simpler code if (usenil_attribute) { reader.MoveToElement(); // value absent, nothing more to do } else { @@ -5642,6 +5645,10 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, if (tag_closed) new_flavor |= PARENT_CLOSED; get_at(i)->XER_decode(*xer_descr(i), reader, new_flavor, flavor2, emb_val); + if (!get_at(i)->is_optional() && get_at(i)->is_bound()) { + // Remove XER_OPTIONAL when we found a non optional field which is bound + flavor &= ~XER_OPTIONAL; + } } } if (!get_at(i)->is_present()) { @@ -5683,6 +5690,12 @@ int Record_Type::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, // Check if every non-optional field has been set for (i = 0; i < field_cnt; ++i) { if (!get_at(i)->is_optional() && !get_at(i)->is_bound()) { + if (flavor & XER_OPTIONAL) { + // If there is a non optional field which is unbound and we are optional + // then set to omit. Test: RecordOmit + clean_up(); + return -1; + } TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG, "No data found for non-optional field '%s'", fld_name(i)); } diff --git a/regression_test/XML/Makefile b/regression_test/XML/Makefile index f8187f37b9079c8f27a41f033a420b7ea7e42344..d0433baeadea48fefd5a7eba09034e372aebaf78 100644 --- a/regression_test/XML/Makefile +++ b/regression_test/XML/Makefile @@ -29,7 +29,8 @@ endif XDIRS := $(wildcard $(SHADOWED)) xsdConverter \ HM60295 HN15589 HQ30408 HR49727 HU13380 $(RT2_ONLY) \ -XmlWorkflow tpdValidTest AbstractBlock UseNilLong AttributeFormDefault +XmlWorkflow tpdValidTest AbstractBlock UseNilLong AttributeFormDefault \ +RecordOmit # List of fake targets: .PHONY: all dep clean run $(XDIRS) $(addsuffix /, $(XDIRS)) profile diff --git a/regression_test/XML/RecordOmit/Makefile b/regression_test/XML/RecordOmit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..232dcf8723e08c951563cae74dca17513d2957df --- /dev/null +++ b/regression_test/XML/RecordOmit/Makefile @@ -0,0 +1,208 @@ +############################################################################## +# 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: +# Szabo, Bence Janos +# +############################################################################## +TOPDIR := ../.. +include ../../Makefile.regression + +ORIG ?= . + +ifdef SRCDIR +ORIGSRC := $(ABS_SRC) +#$(warning yes SRC, $(ORIGSRC)) +else +ORIGSRC := $(ORIG) +#$(warning no SRC, $(ORIGSRC)) +endif + +# WARNING! This Makefile can be used with GNU make only. +# Other versions of make may report syntax errors in it. + +# +# Do NOT touch this line... +# +.PHONY: all check clean dep objects preprocess +.SUFFIXES: .d + +# +# Set these variables... +# + +# C preprocessor used for TTCN-3 files: +CPP = cpp + +# Flags for the C++ preprocessor (and makedepend as well): +CPPFLAGS += -D$(PLATFORM) + +# Flags for the C++ compiler: (-Wall already in) +CXXFLAGS += -g -W -Wformat=2 + +# Flags for the linker: +#LDFLAGS += -g -rdynamic +WIN32_LIBS += -liconv +FREEBSD_LIBS += -liconv + +# Local flags for Titan (can be overridden from the environment or commandline) +TTCNFLAGS += -b -r -x + +# Flags for the TTCN-3 and ASN.1 compiler +# (common flags already set in Makefile.regression) +COMPILER_FLAGS += $(TTCNFLAGS) + +# $(sort ) also eliminates duplicates +COMPILER_FLAGS := $(sort $(COMPILER_FLAGS)) + +# Execution mode: (either ttcn3 or ttcn3-parallel) +TTCN3_LIB := ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) + +# +# You may change these variables. Add your files if necessary... +# + +# TTCN-3 modules to preprocess: +TTCN3_PP_MODULES := $(wildcard $(ORIGSRC)/../RecordOmit/*.ttcnpp) + +# Files to include in TTCN-3 preprocessed modules: +TTCN3_INCLUDES := $(TOP_SRC)/XML/macros.ttcnin + +# ASN.1 modules of this project: +ASN1_MODULES := + +# TTCN-3 source files generated by the C preprocessor: +PREPROCESSED_TTCN3_MODULES := $(TTCN3_PP_MODULES:.ttcnpp=.ttcn) + + +# TTCN-3 modules of this project: +ALL_TTCN3_MODULES := $(wildcard $(ORIGSRC)/../RecordOmit/*.ttcn) +# Eliminate preprocessed modules +TTCN3_MODULES := $(filter-out $(PREPROCESSED_TTCN3_MODULES), $(ALL_TTCN3_MODULES)) +TTCN3_MODULES += $(TOP_SRC)/iconv/converter.ttcn + +# C++ source & header files generated from the TTCN-3 & ASN.1 modules of +# this project: +GENERATED_SOURCES := $(notdir $(TTCN3_MODULES:.ttcn=.cc) $(PREPROCESSED_TTCN3_MODULES:.ttcn=.cc) $(ASN1_MODULES:.asn=.cc)) +GENERATED_HEADERS := $(GENERATED_SOURCES:.cc=.hh) +ifdef CODE_SPLIT +GENERATED_SOURCES := $(foreach file, $(GENERATED_SOURCES:.cc=), $(addprefix $(file), .cc _seq.cc _set.cc _seqof.cc _setof.cc _union.cc)) +else ifdef SPLIT_TO_SLICES +POSTFIXES := $(foreach file, $(SPLIT_TO_SLICES), $(addsuffix $(file), _part_)) +POSTFIXES := $(foreach file, $(POSTFIXES), $(addprefix $(file), .cc)) +GENERATED_SOURCES2 := $(foreach file, $(GENERATED_SOURCES:.cc=), $(addprefix $(file), $(POSTFIXES))) +GENERATED_SOURCES += $(GENERATED_SOURCES2) +endif + + +# C/C++ Source & header files of Test Ports, external functions and +# other modules: +USER_SOURCES := iconver.cc +USER_HEADERS := $(USER_SOURCES:.cc=.hh) + +# Object files of this project that are needed for the executable test suite: +OBJECTS = $(GENERATED_SOURCES:.cc=.o) $(USER_SOURCES:.cc=.o) + +# The name of the executable test suite: +TARGET = RecordOmit$(RT2_SUFFIX)$(EXESUFFIX) + + +# +# Rules for building the executable... +# + +all: $(TARGET) ; + +target: $(TARGET) ; + +objects: $(OBJECTS) ; + +ifeq ($(findstring dynamic,$(TTCN3_LIB)),) +# not dynamic +CORELIB_BINARY := $(TTCN3_DIR)/lib/lib$(TTCN3_LIB).a +else +CORELIB_BINARY := $(TTCN3_DIR)/lib/lib$(TTCN3_LIB).so +endif + +$(TARGET): $(OBJECTS) $(CORELIB_BINARY) + $(CXX) $(LDFLAGS) -o $@ $(OBJECTS) \ + -L$(TTCN3_DIR)/lib -l$(TTCN3_LIB) \ + -L$(OPENSSL_DIR)/lib -lcrypto \ + $($(PLATFORM)_LIBS) \ + || $(TTCN3_DIR)/bin/titanver $(OBJECTS) + +.cc.o .c.o: + @echo '(C++)' $<; $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $@ $< + +.cc.d .c.d: + @echo Creating dependency file for '$<'; set -e; \ + $(CXX) -MM $(CPPFLAGS) $(CXXFLAGS) $< \ + | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ + [ -s $@ ] || rm -f $@ + +%.ttcn: %.ttcnpp $(TTCN3_INCLUDES) + $(CPP) -x c -nostdinc $(CPPFLAGS_TTCN3) $< $@ + +preprocess: $(PREPROCESSED_TTCN3_MODULES) ; + +$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile + @if [ ! -f $@ ]; then $(RM) compile; $(MAKE) compile; fi + +# +############################################################################ +# + +compile: $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES) $(firstword $(TTCN3_COMPILER)) + $(TTCN3_COMPILER) $(COMPILER_FLAGS) $(filter-out $(TTCN3_COMPILER), $^) + touch $@ + +clean: + -$(RM) $(TARGET) $(OBJECTS) $(GENERATED_HEADERS) \ + $(GENERATED_SOURCES) $(PREPROCESSED_TTCN3_MODULES) compile \ + tags *.log *.stackdump + +distclean: clean + -$(RM) $(DEPFILES) + +# +# Add your rules here if necessary... +# + +install: + @echo You cannot be serious! + +re: + rm -f compile + +RUN := $(shell which colortitan 2>/dev/null) +ifeq ($(firstword $(RUN)),no) +# stupid /bin/which on Solaris writes errors to stdout instead of stderr +RUN := +endif + +run: $(TARGET) + $(RUN) ./$^ + +debug: + $(MAKE) run RUN='gdb --args' + +vpath %.cc $(TOP_SRC)/iconv + + +dep: ; + +DEPFILES := $(OBJECTS:.o=.d) + +ifeq (,$(findstring n,$(MAKEFLAGS))) +ifeq (,$(filter clean distclean,$(MAKECMDGOALS))) +-include $(DEPFILES) +endif +endif + +ifdef SRCDIR +$(foreach src, $(USER_SOURCES), $(eval vpath $(src) $(ABS_SRC))) +endif diff --git a/regression_test/XML/RecordOmit/RecordOmit.ttcnpp b/regression_test/XML/RecordOmit/RecordOmit.ttcnpp new file mode 100644 index 0000000000000000000000000000000000000000..5151bacf1984632a01a9e3850ab678aa13093b54 --- /dev/null +++ b/regression_test/XML/RecordOmit/RecordOmit.ttcnpp @@ -0,0 +1,219 @@ +/****************************************************************************** + * 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: + * Bence Janos Szabo – initial implementation + * + ******************************************************************************/ +module RecordOmit { +modulepar boolean RecordOmit_verbose := false; +#define verbose RecordOmit_verbose +#include "../macros.ttcnin" + +type component CT {}; + +type record FirstRecordOpt +{ + record { + charstring foo optional, + charstring bar + } sequence optional, + boolean b +} +with { + variant "element"; + variant (sequence) "untagged"; +}; + +DECLARE_EXER_ENCODERS(FirstRecordOpt, firstrec); + +const FirstRecordOpt c_omit := { sequence := omit, b := true }; + +const universal charstring c_result_omit_e := "<FirstRecordOpt>\n\t<b>true</b>\n</FirstRecordOpt>\n\n" + +const FirstRecordOpt c_not_omit := { sequence := { foo := "foo", bar := "bar"}, b := true}; + +const universal charstring c_result_not_omit_e := "<FirstRecordOpt>\n\t<foo>foo</foo>\n\t<bar>bar</bar>\n\t<b>true</b>\n</FirstRecordOpt>\n\n"; + +testcase tc_enc_first_record() runs on CT { + CHECK_METHOD(exer_enc_firstrec, c_omit, c_result_omit_e); + CHECK_METHOD(exer_enc_firstrec, c_not_omit, c_result_not_omit_e); +} + +testcase tc_dec_first_record() runs on CT { + CHECK_DECODE(exer_dec_firstrec, c_result_omit_e, FirstRecordOpt, c_omit); + CHECK_DECODE(exer_dec_firstrec, c_result_not_omit_e, FirstRecordOpt, c_not_omit); +} + +//----------------------------------------------------------------------------- + +type record MiddleRecordOpt +{ + boolean first optional, + record { + charstring foo optional, + charstring bar + } sequence optional, + boolean b +} +with { + variant "element"; + variant (sequence) "untagged"; +}; + +DECLARE_EXER_ENCODERS(MiddleRecordOpt, middlerec); + +const MiddleRecordOpt c_omit_middle := { first := omit, sequence := omit, b := true }; + +const universal charstring c_result_omit_middle_e := "<MiddleRecordOpt>\n\t<b>true</b>\n</MiddleRecordOpt>\n\n" + +const MiddleRecordOpt c_not_omit_middle := { first := omit, sequence := { foo := "foo", bar := "bar"}, b := true}; + +const universal charstring c_result_not_omit_middle_e := "<MiddleRecordOpt>\n\t<foo>foo</foo>\n\t<bar>bar</bar>\n\t<b>true</b>\n</MiddleRecordOpt>\n\n"; + +const MiddleRecordOpt c_omit_middle2 := { first := true, sequence := omit, b := true }; + +const universal charstring c_result_omit_middle2_e := "<MiddleRecordOpt>\n\t<first>true</first>\n\t<b>true</b>\n</MiddleRecordOpt>\n\n" + +testcase tc_enc_middle_record() runs on CT { + CHECK_METHOD(exer_enc_middlerec, c_omit_middle, c_result_omit_middle_e); + CHECK_METHOD(exer_enc_middlerec, c_not_omit_middle, c_result_not_omit_middle_e); + CHECK_METHOD(exer_enc_middlerec, c_omit_middle2, c_result_omit_middle2_e); +} + +testcase tc_dec_middle_record() runs on CT { + CHECK_DECODE(exer_dec_middlerec, c_result_omit_middle_e, MiddleRecordOpt, c_omit_middle); + CHECK_DECODE(exer_dec_middlerec, c_result_not_omit_middle_e, MiddleRecordOpt, c_not_omit_middle); + CHECK_DECODE(exer_dec_middlerec, c_result_omit_middle2_e, MiddleRecordOpt, c_omit_middle2); +} + +//----------------------------------------------------------------------------- + +type record AllTypesInRecord +{ + record { + boolean bool optional, + bitstring bs optional, + octetstring os optional, + hexstring hs optional, + integer i optional, + float f optional, + charstring cs optional, + universal charstring us optional, + boolean end + } sequence optional, + boolean b +} +with { + variant "element"; + variant (sequence) "untagged"; +}; + +DECLARE_EXER_ENCODERS(AllTypesInRecord, allrec); + +const AllTypesInRecord c_omit_allrec := { sequence := omit, b := true }; + +const universal charstring c_result_omit_allrec_e := "<AllTypesInRecord>\n\t<b>true</b>\n</AllTypesInRecord>\n\n" + +testcase tc_enc_alltype_record() runs on CT { + CHECK_METHOD(exer_enc_allrec, c_omit_allrec, c_result_omit_allrec_e); +} + +testcase tc_dec_alltype_record() runs on CT { + CHECK_DECODE(exer_dec_allrec, c_result_omit_allrec_e, AllTypesInRecord, c_omit_allrec); +} + +//----------------------------------------------------------------------------- + +type record UnionUntagged +{ + union { + boolean bool, + bitstring bs, + octetstring os, + hexstring hs, + integer i, + float f, + charstring cs, + universal charstring us, + boolean end + } choice optional, + boolean b +} +with { + variant "element"; + variant (choice) "untagged"; +}; + +DECLARE_EXER_ENCODERS(UnionUntagged, union); + +const UnionUntagged c_omit_union := { choice := omit, b := true }; + +const universal charstring c_result_omit_union_e := "<UnionUntagged>\n\t<b>true</b>\n</UnionUntagged>\n\n" + +testcase tc_enc_union() runs on CT { + CHECK_METHOD(exer_enc_union, c_omit_union, c_result_omit_union_e); +} + +testcase tc_dec_union() runs on CT { + CHECK_DECODE(exer_dec_union, c_result_omit_union_e, UnionUntagged, c_omit_union); +} + + + +type record Inner { + charstring a +} +with { + variant "untagged"; +} + +type record RecordOfRecordUntagged +{ + record of Inner sequence optional, + boolean b +} +with { + variant "element"; +}; + +DECLARE_EXER_ENCODERS(RecordOfRecordUntagged, recordof); + +const RecordOfRecordUntagged c_omit_recordof := { sequence := omit, b := true }; + +const universal charstring c_result_omit_recordof_e := "<RecordOfRecordUntagged>\n\t<b>true</b>\n</RecordOfRecordUntagged>\n\n" + +testcase tc_enc_recordof() runs on CT { + CHECK_METHOD(exer_enc_recordof, c_omit_recordof, c_result_omit_recordof_e); +} + +testcase tc_dec_recordof() runs on CT { + CHECK_DECODE(exer_dec_recordof, c_result_omit_recordof_e, RecordOfRecordUntagged, c_omit_recordof); +} + + + +control { + execute(tc_enc_first_record()); + execute(tc_dec_first_record()); + + execute(tc_enc_middle_record()); + execute(tc_dec_middle_record()); + + execute(tc_enc_alltype_record()); + execute(tc_dec_alltype_record()); + + execute(tc_enc_union()); + execute(tc_dec_union()); + + execute(tc_enc_recordof()); + execute(tc_dec_recordof()); +} + +} with { +encode "XML"; +}