Commit 5495dce1 authored by Botond Baranyi's avatar Botond Baranyi
Browse files

Implemented multiple encoding strings for variant attributes (bug 529892)



Change-Id: Ia4c3129dfed902dd36969707c0313ce588ca8727
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent 07f0e3e9
......@@ -2849,8 +2849,12 @@ namespace Common {
if (NULL != jsonattrib->alias) {
Type* parent = get_parent_type();
if (NULL == parent || (T_SEQ_T != parent->typetype &&
T_SET_T != parent->typetype && T_CHOICE_T != parent->typetype)) {
if (!legacy_codec_handling &&
(NULL == parent || (T_SEQ_T != parent->typetype &&
T_SET_T != parent->typetype && T_CHOICE_T != parent->typetype))) {
// only report this error when using the new codec handling, otherwise
// ignore the attribute (since it can also be set by the XML 'name as ...'
// attribute)
error("Invalid attribute, 'name as ...' requires field of a "
"record, set or union.");
}
......
......@@ -965,10 +965,11 @@ void Type::chk_this_variant(const Ttcn::SingleWithAttrib* swa, bool global)
}
}
else {
const string& enc_str = swa->get_attribSpec().get_encoding();
MessageEncodingType_t coding = get_enc_type(enc_str);
const vector<string>* coding_strings = swa->get_attribSpec().get_encodings();
// gather the built-in codecs referred to by the variant's encoding strings
vector<MessageEncodingType_t> codings;
bool erroneous = false;
if (enc_str.empty()) {
if (coding_strings == NULL) {
if (t->coding_table.size() > 1) {
if (!global) {
swa->error("The encoding reference is mandatory for variant attributes "
......@@ -977,129 +978,148 @@ void Type::chk_this_variant(const Ttcn::SingleWithAttrib* swa, bool global)
erroneous = true;
}
else if (t->coding_table[0]->built_in) {
coding = t->coding_table[0]->built_in_coding;
codings.add(new MessageEncodingType_t(t->coding_table[0]->built_in_coding));
}
else if (strcmp(t->coding_table[0]->custom_coding.name, "PER") == 0) {
coding = CT_PER;
else { // PER or custom encoding
MessageEncodingType_t coding =
strcmp(t->coding_table[0]->custom_coding.name, "PER") == 0 ?
CT_PER : CT_CUSTOM;
swa->warning("Variant attributes related to %s encoding are ignored",
get_encoding_name(coding));
}
// else leave it as CT_CUSTOM
}
else {
if (!has_encoding(coding, &enc_str)) {
erroneous = true;
if (!global) {
if (coding != CT_CUSTOM) {
swa->error("Type `%s' does not support %s encoding",
get_typename().c_str(), get_encoding_name(coding));
}
else {
swa->error("Type `%s' does not support custom encoding `%s'",
get_typename().c_str(), enc_str.c_str());
for (size_t i = 0; i < coding_strings->size(); ++i) {
const string& enc_str = *(*coding_strings)[i];
MessageEncodingType_t coding = get_enc_type(enc_str);
if (!has_encoding(coding, &enc_str)) {
erroneous = true;
if (!global) {
if (coding != CT_CUSTOM) {
swa->error("Type `%s' does not support %s encoding",
get_typename().c_str(), get_encoding_name(coding));
}
else {
swa->error("Type `%s' does not support custom encoding `%s'",
get_typename().c_str(), enc_str.c_str());
}
}
}
else if (coding != CT_PER && coding != CT_CUSTOM) {
codings.add(new MessageEncodingType_t(coding));
}
else { // PER or custom encoding
swa->warning("Variant attributes related to %s encoding are ignored",
get_encoding_name(coding));
}
}
}
if (!erroneous && coding != CT_PER && coding != CT_CUSTOM) {
bool new_ber = false; // a BerAST object was allocated here
bool new_raw = false; // a RawAST object was allocated here
bool new_text = false; // a TextAST object was allocated here
bool new_xer = false; // a XerAttribute object was allocated here
bool new_json = false; // a JsonAST object was allocated here
bool ber_found = false; // a BER attribute was found by the parser
bool raw_found = false; // a RAW attribute was found by the parser
bool text_found = false; // a TEXT attribute was found by the parser
bool xer_found = false; // a XER attribute was found by the parser
bool json_found = false; // a JSON attribute was found by the parser
if (berattrib == NULL) {
berattrib = new BerAST;
new_ber = true;
}
if (rawattrib == NULL) {
Type* t_refd = this;
while (t_refd->rawattrib == NULL && t_refd->is_ref()) {
t_refd = t_refd->get_type_refd();
if (!erroneous && codings.size() != 0) {
for (size_t i = 0; i < codings.size(); ++i) {
MessageEncodingType_t coding = *codings[i];
bool new_ber = false; // a BerAST object was allocated here
bool new_raw = false; // a RawAST object was allocated here
bool new_text = false; // a TextAST object was allocated here
bool new_xer = false; // a XerAttribute object was allocated here
bool new_json = false; // a JsonAST object was allocated here
bool ber_found = false; // a BER attribute was found by the parser
bool raw_found = false; // a RAW attribute was found by the parser
bool text_found = false; // a TEXT attribute was found by the parser
bool xer_found = false; // a XER attribute was found by the parser
bool json_found = false; // a JSON attribute was found by the parser
if (berattrib == NULL) {
berattrib = new BerAST;
new_ber = true;
}
rawattrib = new RawAST(t_refd->rawattrib, get_default_raw_fieldlength());
new_raw = true;
}
if (textattrib == NULL) {
Type* t_refd = this;
while (t_refd->textattrib == NULL && t_refd->is_ref()) {
t_refd = t_refd->get_type_refd();
if (rawattrib == NULL) {
Type* t_refd = this;
while (t_refd->rawattrib == NULL && t_refd->is_ref()) {
t_refd = t_refd->get_type_refd();
}
rawattrib = new RawAST(t_refd->rawattrib, get_default_raw_fieldlength());
new_raw = true;
}
textattrib = new TextAST(t_refd->textattrib);
new_text = true;
}
if (xerattrib == NULL) {
xerattrib = new XerAttributes;
new_xer = true;
}
if (jsonattrib == NULL) {
Type* t_refd = this;
while (t_refd->jsonattrib == NULL && t_refd->is_ref()) {
t_refd = t_refd->get_type_refd();
if (textattrib == NULL) {
Type* t_refd = this;
while (t_refd->textattrib == NULL && t_refd->is_ref()) {
t_refd = t_refd->get_type_refd();
}
textattrib = new TextAST(t_refd->textattrib);
new_text = true;
}
jsonattrib = new JsonAST(t_refd->jsonattrib);
new_json = true;
}
int ret = parse_rawAST(rawattrib, textattrib, xerattrib, berattrib, jsonattrib,
swa->get_attribSpec(), get_length_multiplier(), my_scope->get_scope_mod(),
raw_found, text_found, xer_found, ber_found, json_found, coding);
bool mismatch = false;
if (ber_found || raw_found || text_found || xer_found || json_found) {
switch (coding) {
case CT_BER:
mismatch = !ber_found;
break;
case CT_RAW:
mismatch = !raw_found;
break;
case CT_TEXT:
mismatch = !text_found;
break;
case CT_XER:
mismatch = !xer_found;
break;
case CT_JSON:
mismatch = !json_found;
break;
default:
FATAL_ERROR("Type::chk_this_variant");
break;
if (xerattrib == NULL) {
xerattrib = new XerAttributes;
new_xer = true;
}
}
if (mismatch && ret == 0) {
if (!global || !enc_str.empty()) {
// don't display this if there were parsing errors in the variant
// attribute, or if it was empty
swa->error("Variant attribute is not related to %s encoding",
get_encoding_name(coding));
if (jsonattrib == NULL) {
Type* t_refd = this;
while (t_refd->jsonattrib == NULL && t_refd->is_ref()) {
t_refd = t_refd->get_type_refd();
}
jsonattrib = new JsonAST(t_refd->jsonattrib);
new_json = true;
}
int ret = parse_rawAST(rawattrib, textattrib, xerattrib, berattrib, jsonattrib,
swa->get_attribSpec(), get_length_multiplier(), my_scope->get_scope_mod(),
raw_found, text_found, xer_found, ber_found, json_found, coding);
bool mismatch = false;
if (ber_found || raw_found || text_found || xer_found || json_found) {
switch (coding) {
case CT_BER:
mismatch = !ber_found;
break;
case CT_RAW:
mismatch = !raw_found;
break;
case CT_TEXT:
mismatch = !text_found;
break;
case CT_XER:
mismatch = !xer_found;
break;
case CT_JSON:
mismatch = !json_found;
break;
default:
FATAL_ERROR("Type::chk_this_variant");
break;
}
}
if (mismatch && ret == 0) {
if (!global || coding_strings != NULL) {
// don't display this if there were parsing errors in the variant
// attribute, or if it didn't have encoding strings
swa->error("Variant attribute is not related to %s encoding",
get_encoding_name(coding));
}
}
if (new_ber && !ber_found) {
delete berattrib;
berattrib = NULL;
}
if (new_raw && !raw_found) {
delete rawattrib;
rawattrib = NULL;
}
if (new_text && !text_found) {
delete textattrib;
textattrib = NULL;
}
if (new_xer && !xer_found) {
delete xerattrib;
xerattrib = NULL;
}
if (new_json && !json_found) {
delete jsonattrib;
jsonattrib = NULL;
}
}
if (new_ber && !ber_found) {
delete berattrib;
berattrib = NULL;
}
if (new_raw && !raw_found) {
delete rawattrib;
rawattrib = NULL;
}
if (new_text && !text_found) {
delete textattrib;
textattrib = NULL;
}
if (new_xer && !xer_found) {
delete xerattrib;
xerattrib = NULL;
}
if (new_json && !json_found) {
delete jsonattrib;
jsonattrib = NULL;
}
}
else if (!erroneous && !global) { // PER or custom encoding
swa->warning("Variant attributes related to %s encoding are ignored",
get_encoding_name(coding));
if (codings.size() != 0) {
for (size_t i = 0; i < codings.size(); ++i) {
delete codings[i];
}
codings.clear();
}
} // if t != NULL
if (global) {
......
......@@ -883,6 +883,17 @@ namespace Ttcn {
}
// ==== AttributeSpec ====
AttributeSpec::~AttributeSpec()
{
if (encodings != NULL) {
for (size_t i = 0; i < encodings->size(); ++i) {
delete (*encodings)[i];
}
encodings->clear();
delete encodings;
}
}
AttributeSpec* AttributeSpec::clone() const
{
......@@ -897,8 +908,15 @@ namespace Ttcn {
void AttributeSpec::dump(unsigned level) const
{
DEBUG(level,"spec: %s", spec.c_str());
if (!encoding.empty()) {
DEBUG(level, "encoding: %s", encoding.c_str());
if (encodings != NULL) {
string res;
for (size_t i = 0; i < encodings->size(); ++i) {
if (i != 0) {
res += ", ";
}
res += *(*encodings)[i];
}
DEBUG(level, "encoding(s): %s", res.c_str());
}
}
......@@ -1203,7 +1221,7 @@ namespace Ttcn {
"attributes. Modifier ignored.");
}
}
if (!temp_attrib->get_attribSpec().get_encoding().empty() &&
if (temp_attrib->get_attribSpec().get_encodings() != NULL &&
(legacy_codec_handling ||
temp_attrib->get_attribKeyword() != SingleWithAttrib::AT_VARIANT)) {
temp_attrib->error("Invalid attribute format. Dot notation is only "
......
......@@ -221,7 +221,7 @@ namespace Ttcn {
void chk();
ErroneousDescriptor* get_err_descr() const { return err_descr_tree; }
};
/**
* Stores the attribute specification and its location
*/
......@@ -230,20 +230,20 @@ namespace Ttcn {
AttributeSpec& operator=(const AttributeSpec& p);
private:
string spec; ///< The attribute specification (free text)
string encoding; ///< Encoding specification for variant attributes (free text)
// TODO: check that the variant indeed belongs to the specified encoding
vector<string>* encodings; ///< Encoding specifications for variant attributes (free text)
/// Copy constructor, for clone() only
AttributeSpec(const AttributeSpec& p)
: Node(p), Location(p), spec(p.spec), encoding(p.encoding) { }
: Node(p), Location(p), spec(p.spec), encodings(p.encodings) { }
public:
AttributeSpec(const string& p_spec)
: Node(), Location(), spec(p_spec), encoding() { }
AttributeSpec(const string& p_spec, const string& p_encoding)
: Node(), Location(), spec(p_spec), encoding(p_encoding) { }
: Node(), Location(), spec(p_spec), encodings(NULL) { }
AttributeSpec(const string& p_spec, vector<string>* p_encodings)
: Node(), Location(), spec(p_spec), encodings(p_encodings) { }
~AttributeSpec();
virtual AttributeSpec* clone() const;
virtual void set_fullname(const string& p_fullname);
const string& get_spec() const { return spec; }
const string& get_encoding() const { return encoding; }
const vector<string>* get_encodings() const { return encodings; }
virtual void dump(unsigned level) const;
};
......
......@@ -217,6 +217,7 @@ static const string anyname("anytype");
param_eval_t eval;
TypeMappingTargets *typemappingtargets;
attribute_modifier_t attrib_mod;
vector<string>* string_vector;
struct {
bool is_raw;
......@@ -1130,6 +1131,7 @@ AllOrTypeListWithTo TypeListWithFrom TypeListWithTo
%type <single_value_redirect_list> SingleValueSpecList
%type <typemappingtargets> WithList
%type <reference_list> PortTypeList
%type <string_vector> AttribSpecEncodings
/*********************************************************************
* Destructors
......@@ -1490,6 +1492,7 @@ Quadruple
AllowedValues
optSubTypeSpec
seqValueOrRange
AttribSpecEncodings
%destructor {
for(size_t i=0; i<$$.nElements; i++) delete $$.elements[i];
......@@ -8331,11 +8334,34 @@ AttribSpec: // 542
}
| FreeText '.' FreeText
{
$$ = new AttributeSpec(string($3), string($1));
vector<string>* v = new vector<string>;
v->add(new string($1));
$$ = new AttributeSpec(string($3), v);
$$->set_location(infile, @$);
Free($1);
Free($3);
}
| '{' AttribSpecEncodings '}' '.' FreeText
{
$$ = new AttributeSpec(string($5), $2);
$$->set_location(infile, @$);
Free($5);
}
;
AttribSpecEncodings:
FreeText
{
$$ = new vector<string>;
$$->add(new string($1));
Free($1);
}
| AttribSpecEncodings ',' FreeText
{
$$ = $1;
$$->add(new string($3));
Free($3);
}
;
/* A.1.6.7 Behaviour statements */
......
......@@ -1364,7 +1364,7 @@ XERattribute:
// this handles the "name as '...' " attributes for both the XER and
// JSON codecs
// (overwrites any previously set name)
if (selected_codec == Common::Type::CT_XER) {
if (selected_codec == Common::Type::CT_XER || legacy_codec_handling) {
switch (xerstruct->name_.kw_) {
case NamespaceSpecification::NO_MANGLING:
case NamespaceSpecification::CAPITALIZED:
......@@ -1377,7 +1377,7 @@ XERattribute:
}
xerstruct->name_.nn_ = $1;
}
else {
if (selected_codec != Common::Type::CT_XER) {
// treat XML special values and real strings separately
XerAttributes::NameChange special;
special.nn_ = $1;
......@@ -1397,9 +1397,17 @@ XERattribute:
}
break;
default: // it's a real string
if (selected_codec == Common::Type::CT_JSON) {
if (selected_codec == Common::Type::CT_JSON ||
legacy_codec_handling) {
Free(jsonstruct->alias);
jsonstruct->alias = $1;
if (legacy_codec_handling) {
// in this case the string is saved in both the XML and JSON
// structs, so we can't use the same string
jsonstruct->alias = mcopystr($1);
}
else {
jsonstruct->alias = $1;
}
json_f = true;
}
else {
......
......@@ -476,6 +476,38 @@ testcase tc_ttcn_codec_switch() runs on CT {
setverdict(pass);
}
// Testing the 'name as ...' attribute applied to multiple codecs using only one variant attribute
testcase tc_ttcn_multi_attrib() runs on CT {
var S x := { num := 12, str := "abc" };
// JSON encoding & decoding
var universal charstring exp := "{\"int\":12,\"str\":\"abc\"}";
var universal charstring enc1 := encvalue_unichar(x, "UTF-8", "", "JSON");
if (exp != enc1) {
setverdict(fail, "JSON encoding failed. Expected: ", exp, ", got: ", enc1);
}
var S dec1;
var integer res := decvalue_unichar(enc1, dec1, "UTF-8", "", "JSON");
if (x != dec1) {
setverdict(fail, "JSON decoding failed. Expected: ", x, ", got: ", dec1);
}
// XML encoding & decoding
exp := "<S>\n\t<int>12</int>\n\t<str>abc</str>\n</S>\n\n";
var universal charstring enc2 := encvalue_unichar(x, "UTF-8", "", "XML");
if (exp != enc2) {
setverdict(fail, "XML encoding test failed. Expected: ", exp, ", got: ", enc2);
}
var S dec2;
res := decvalue_unichar(enc2, dec2, "UTF-8", "", "XML");
if (x != dec2) {
setverdict(fail, "XML decoding test failed. Expected: ", x, ", got: ", dec2);
}
setverdict(pass);
}
control {
execute(tc_ttcn_encvalue());
execute(tc_ttcn_encvalue_negtest());
......@@ -495,6 +527,7 @@ control {
execute(tc_asn_setencode_per());
execute(tc_asn_setencode_negtest());
execute(tc_ttcn_codec_switch());
execute(tc_ttcn_multi_attrib());
}
}
......@@ -56,6 +56,16 @@ with {
encode "JSON";
}
type set S {
integer num,
charstring str
}
with {
encode "JSON";
encode "XML";
variant (num) {"JSON", "XML"}."name as 'int'";
}
type record Msg {
bitstring data
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment