///////////////////////////////////////////////////////////////////////////////
-// Copyright (c) 2000-2014 Ericsson Telecom AB
+// Copyright (c) 2000-2015 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
}
Record_Of_Type::Record_Of_Type(const Record_Of_Type& other_value)
-: Base_Type(other_value), val_ptr(NULL), err_descr(other_value.err_descr), refd_ind_ptr(NULL)
+: Base_Type(other_value), RefdIndexInterface(other_value)
+, val_ptr(NULL), err_descr(other_value.err_descr), refd_ind_ptr(NULL)
{
if (!other_value.is_bound())
TTCN_error("Copying an unbound record of/set of value.");
} /* next read */
} /* if not empty element */
} /* if not LIST */
+ if (!own_tag && exer && (p_td.xer_bits & XER_OPTIONAL) && get_nof_elements() == 0) {
+ // set it to unbound, so the OPTIONAL class sets it to omit
+ clean_up();
+ }
return 1; // decode successful
}
}
param.basic_check(Module_Param::BC_VALUE|Module_Param::BC_LIST, is_set()?"set of value":"record of value");
+
+ Module_Param_Ptr mp = ¶m;
+ if (param.get_type() == Module_Param::MP_Reference) {
+ mp = param.get_referenced_param();
+ }
+
switch (param.get_operation_type()) {
case Module_Param::OT_ASSIGN:
- if (param.get_type()==Module_Param::MP_Value_List && param.get_size()==0) {
+ if (mp->get_type()==Module_Param::MP_Value_List && mp->get_size()==0) {
set_val(NULL_VALUE);
return;
}
- switch (param.get_type()) {
+ switch (mp->get_type()) {
case Module_Param::MP_Value_List:
- set_size(param.get_size());
- for (size_t i=0; i<param.get_size(); ++i) {
- Module_Param* const curr = param.get_elem(i);
+ set_size(mp->get_size());
+ for (size_t i=0; i<mp->get_size(); ++i) {
+ Module_Param* const curr = mp->get_elem(i);
if (curr->get_type()!=Module_Param::MP_NotUsed) {
get_at(i)->set_param(*curr);
}
}
break;
case Module_Param::MP_Indexed_List:
- for (size_t i=0; i<param.get_size(); ++i) {
- Module_Param* const current = param.get_elem(i);
+ for (size_t i=0; i<mp->get_size(); ++i) {
+ Module_Param* const current = mp->get_elem(i);
get_at(current->get_id()->get_index())->set_param(*current);
}
break;
}
break;
case Module_Param::OT_CONCAT:
- switch (param.get_type()) {
+ switch (mp->get_type()) {
case Module_Param::MP_Value_List: {
if (!is_bound()) set_val(NULL_VALUE);
int start_idx = lengthof();
- for (size_t i=0; i<param.get_size(); ++i) {
- Module_Param* const curr = param.get_elem(i);
+ for (size_t i=0; i<mp->get_size(); ++i) {
+ Module_Param* const curr = mp->get_elem(i);
if ((curr->get_type()!=Module_Param::MP_NotUsed)) {
get_at(start_idx+(int)i)->set_param(*curr);
}
}
}
+Module_Param* Record_Of_Type::get_param(Module_Param_Name& param_name) const
+{
+ if (!is_bound()) {
+ return new Module_Param_Unbound();
+ }
+ if (param_name.next_name()) {
+ // Haven't reached the end of the module parameter name
+ // => the name refers to one of the elements, not to the whole record of
+ char* param_field = param_name.get_current_name();
+ if (param_field[0] < '0' || param_field[0] > '9') {
+ TTCN_error("Unexpected record field name in module parameter reference, "
+ "expected a valid index for %s type `%s'",
+ is_set() ? "set of" : "record of", get_descriptor()->name);
+ }
+ int param_index = -1;
+ sscanf(param_field, "%d", ¶m_index);
+ return get_at(param_index)->get_param(param_name);
+ }
+ Vector<Module_Param*> values;
+ for (int i = 0; i < val_ptr->n_elements; ++i) {
+ values.push_back(val_ptr->value_elements[i]->get_param(param_name));
+ }
+ Module_Param_Value_List* mp = new Module_Param_Value_List();
+ mp->add_list_with_implicit_ids(&values);
+ values.clear();
+ return mp;
+}
+
void Record_Of_Type::set_implicit_omit()
{
for (int i = 0; i < get_nof_elements(); ++i) {
}
param.basic_check(Module_Param::BC_VALUE, is_set()?"set value":"record value");
- switch (param.get_type()) {
+
+ Module_Param_Ptr mp = ¶m;
+ if (param.get_type() == Module_Param::MP_Reference) {
+ mp = param.get_referenced_param();
+ }
+
+ switch (mp->get_type()) {
case Module_Param::MP_Value_List:
- if (get_count()<(int)param.get_size()) {
- param.error("%s value of type %s has %d fields but list value has %d fields", is_set()?"Set":"Record", get_descriptor()->name, get_count(), (int)param.get_size());
+ if (get_count()<(int)mp->get_size()) {
+ param.error("%s value of type %s has %d fields but list value has %d fields", is_set()?"Set":"Record", get_descriptor()->name, get_count(), (int)mp->get_size());
}
- for (size_t i=0; i<param.get_size(); i++) {
- Module_Param* mp = param.get_elem(i);
- if (mp->get_type()!=Module_Param::MP_NotUsed) {
- get_at((int)i)->set_param(*mp);
+ for (size_t i=0; i<mp->get_size(); i++) {
+ Module_Param* mp_elem = mp->get_elem(i);
+ if (mp_elem->get_type()!=Module_Param::MP_NotUsed) {
+ get_at((int)i)->set_param(*mp_elem);
}
}
break;
case Module_Param::MP_Assignment_List:
- for (size_t i=0; i<param.get_size(); ++i) {
- Module_Param* const current = param.get_elem(i);
+ for (size_t i=0; i<mp->get_size(); ++i) {
+ Module_Param* const current = mp->get_elem(i);
bool found = false;
for (int j=0; j<get_count(); ++j) {
if (!strcmp(fld_name(j), current->get_id()->get_name())) {
}
}
+Module_Param* Record_Type::get_param(Module_Param_Name& param_name) const
+{
+ if (!is_bound()) {
+ return new Module_Param_Unbound();
+ }
+ if (param_name.next_name()) {
+ // Haven't reached the end of the module parameter name
+ // => the name refers to one of the fields, not to the whole record
+ char* param_field = param_name.get_current_name();
+ if (param_field[0] >= '0' && param_field[0] <= '9') {
+ TTCN_error("Unexpected array index in module parameter reference, "
+ "expected a valid field name for %s type `%s'",
+ is_set() ? "set" : "record", get_descriptor()->name);
+ }
+ int field_cnt = get_count();
+ for (int field_idx = 0; field_idx < field_cnt; field_idx++) {
+ if (strcmp(fld_name(field_idx), param_field) == 0) {
+ return get_at(field_idx)->get_param(param_name);
+ }
+ }
+ TTCN_error("Field `%s' not found in %s type `%s'",
+ param_field, is_set() ? "set" : "record", get_descriptor()->name);
+ }
+ Module_Param_Assignment_List* mp = new Module_Param_Assignment_List();
+ for (int i = 0; i < get_count(); ++i) {
+ Module_Param* mp_field = get_at(i)->get_param(param_name);
+ mp_field->set_id(new Module_Param_FieldName(mcopystr(fld_name(i))));
+ mp->add_elem(mp_field);
+ }
+ return mp;
+}
+
void Record_Type::set_implicit_omit()
{
int field_cnt = get_count();
get_at(oi)->set_to_omit();
++n_optionals;
}
+
Record_Of_Type *use_order = static_cast<Record_Of_Type*>(get_at(uo_index));
// Initialize the use_order field to empty. Let it grow on demand.
// (setting it to the minimum acceptable size may leave unbound elements
// if the XML was incomplete).
use_order->set_size(0);
- Record_Type *jumbled = this; // the record affected by USE_ORDER
- int begin = first_nonattr;
- int end = field_cnt; // "one past"
- if (p_td.xer_bits & USE_NIL) {
- Base_Type *last_optional = get_at(field_cnt-1);
- if (!usenil_attribute) { // exer known true
- last_optional->set_to_present();
- jumbled = static_cast<Record_Type*>(last_optional->get_opt_value());
- // We will operate on the members of last_optional,
- // effectively bypassing last_optional->XER_decode() itself.
- begin = 0;
- end = jumbled->get_count();
- ec_1.set_msg("%s': ", fld_name(field_cnt-1));
- }
- }
- if (num_attributes > 0
- && first_nonattr != field_cnt
- && i == first_nonattr - 1) { // exer known true
- // If there were attributes and their processing just finished,
- // the reader is positioned on the start tag of the record.
- // Move ahead, unless there are no non-attribute fields.
- reader.Read();
- }
- // Then, the non-attributes
-
- // The index runs over the members affected by USE-ORDER.
- // This is [first_nonattr,field_cnt) unless USE-NIL is involved,
- // in which case it's [0,optional_sequence::field_cnt)
- int *seen = new int[end-begin];
- int num_seen = 0;
- int last_any_elem = begin - 1;
- // The index of the latest embedded value can change outside of this function
- // (if the field is a untagged record of), in this case the next value should
- // be ignored, as it's already been handled by the record of
- int last_embval_index = 0;
- for (i = begin; i < end; i++) {
- for (success = reader.Ok(); success == 1; success = reader.Read()) {
- type = reader.NodeType();
- if (0 != emb_val && reader.NodeType()==XML_READER_TYPE_TEXT) {
- UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value());
- emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr);
+ // Nothing to order if there are no child elements
+ if (!tag_closed) {
+ Record_Type *jumbled = this; // the record affected by USE_ORDER
+ int begin = first_nonattr;
+ int end = field_cnt; // "one past"
+ if (p_td.xer_bits & USE_NIL) {
+ Base_Type *last_optional = get_at(field_cnt-1);
+ if (!usenil_attribute) { // exer known true
+ last_optional->set_to_present();
+ jumbled = static_cast<Record_Type*>(last_optional->get_opt_value());
+ // We will operate on the members of last_optional,
+ // effectively bypassing last_optional->XER_decode() itself.
+ begin = 0;
+ end = jumbled->get_count();
+ ec_1.set_msg("%s': ", fld_name(field_cnt-1));
}
- // The non-attribute components must not be UNTAGGED
- if (type == XML_READER_TYPE_ELEMENT) break;
- // else if (type==XML_READER_TYPE_END_ELEMENT) panic?
}
- if (0 != emb_val) {
- if (last_embval_index == emb_val->embval_index) {
- ++emb_val->embval_index;
- }
- last_embval_index = emb_val->embval_index;
+ if (num_attributes > 0
+ && first_nonattr != field_cnt
+ && i == first_nonattr - 1) { // exer known true
+ // If there were attributes and their processing just finished,
+ // the reader is positioned on the start tag of the record.
+ // Move ahead, unless there are no non-attribute fields.
+ reader.Read();
}
- if (success != 1) break;
- const char *name = (const char *)reader.LocalName();
- boolean field_name_found = false;
- // Find out which member it is.
- // FIXME some hashing should be implemented
- for (int k = begin; k < end; k++) {
- if (!(jumbled->xer_descr(k)->xer_bits & ANY_ELEMENT) &&
- check_name(name, *jumbled->xer_descr(k), 1)) {
- ec_1.set_msg("%s': ", jumbled->fld_name(k));
-
- // Check for the same field being decoded twice.
- // We can't use the field's is_bound()/is_present(),
- // because the field may be bound on input, e.g. for
- // prototype(fast) or prototype(backtrack).
- int in_dex = k - begin;
- for (int o = 0; o < num_seen ;++o) {
- if (in_dex == seen[o]) TTCN_EncDec_ErrorContext::error(
- TTCN_EncDec::ET_INVAL_MSG, "Duplicate element");
+ // Then, the non-attributes
+
+ // The index runs over the members affected by USE-ORDER.
+ // This is [first_nonattr,field_cnt) unless USE-NIL is involved,
+ // in which case it's [0,optional_sequence::field_cnt)
+ int *seen = new int[end-begin];
+ int num_seen = 0;
+ int last_any_elem = begin - 1;
+ // The index of the latest embedded value can change outside of this function
+ // (if the field is an untagged record of), in this case the next value should
+ // be ignored, as it's already been handled by the record of
+ int last_embval_index = 0;
+ bool early_exit = false;
+ for (i = begin; i < end; i++) {
+ for (success = reader.Ok(); success == 1; success = reader.Read()) {
+ type = reader.NodeType();
+ if (0 != emb_val && reader.NodeType()==XML_READER_TYPE_TEXT) {
+ UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value());
+ emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr);
+ }
+ // The non-attribute components must not be UNTAGGED
+ if (type == XML_READER_TYPE_ELEMENT) break;
+ if (type == XML_READER_TYPE_END_ELEMENT) {
+ early_exit = true;
+ break;
}
- seen[num_seen++] = in_dex;
- // Set the next use-order member.
- // Non-const get_at creates the object in the record-of.
- static_cast<Enum_Type*>(use_order->get_at(i - begin))
- ->from_int(in_dex);
- Base_Type *b = jumbled->get_at(k);
- b->XER_decode(*jumbled->xer_descr(k), reader, flavor, emb_val);
- field_name_found = true;
- break;
}
- }
- if (!field_name_found) {
- // Check the anyElement fields
- for (int k = last_any_elem + 1; k < end; k++) {
- if (jumbled->xer_descr(k)->xer_bits & ANY_ELEMENT) {
+ if (0 != emb_val) {
+ if (last_embval_index == emb_val->embval_index) {
+ ++emb_val->embval_index;
+ }
+ last_embval_index = emb_val->embval_index;
+ }
+ if (success != 1 || early_exit) break;
+ const char *name = (const char *)reader.LocalName();
+ bool field_name_found = false;
+ // Find out which member it is.
+ // FIXME some hashing should be implemented
+ for (int k = begin; k < end; k++) {
+ if (!(jumbled->xer_descr(k)->xer_bits & ANY_ELEMENT) &&
+ check_name(name, *jumbled->xer_descr(k), 1)) {
ec_1.set_msg("%s': ", jumbled->fld_name(k));
// Check for the same field being decoded twice.
->from_int(in_dex);
Base_Type *b = jumbled->get_at(k);
b->XER_decode(*jumbled->xer_descr(k), reader, flavor, emb_val);
- last_any_elem = k;
+ field_name_found = true;
break;
}
}
+ if (!field_name_found) {
+ // Check the anyElement fields
+ for (int k = last_any_elem + 1; k < end; k++) {
+ if (jumbled->xer_descr(k)->xer_bits & ANY_ELEMENT) {
+ ec_1.set_msg("%s': ", jumbled->fld_name(k));
+
+ // Check for the same field being decoded twice.
+ // We can't use the field's is_bound()/is_present(),
+ // because the field may be bound on input, e.g. for
+ // prototype(fast) or prototype(backtrack).
+ int in_dex = k - begin;
+ for (int o = 0; o < num_seen ;++o) {
+ if (in_dex == seen[o]) TTCN_EncDec_ErrorContext::error(
+ TTCN_EncDec::ET_INVAL_MSG, "Duplicate element");
+ }
+ seen[num_seen++] = in_dex;
+ // Set the next use-order member.
+ // Non-const get_at creates the object in the record-of.
+ static_cast<Enum_Type*>(use_order->get_at(i - begin))
+ ->from_int(in_dex);
+ Base_Type *b = jumbled->get_at(k);
+ b->XER_decode(*jumbled->xer_descr(k), reader, flavor, emb_val);
+ last_any_elem = k;
+ field_name_found = true;
+ break;
+ }
+ }
+ }
+ if (!field_name_found) {
+ TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG,
+ "Bad XML tag '%s' instead of a valid field", name);
+ break;
+ }
+ } // next field
+ if (0 != emb_val) {
+ if (reader.NodeType()==XML_READER_TYPE_TEXT) {
+ UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value());
+ emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr);
+ }
+ if (last_embval_index == emb_val->embval_index) {
+ ++emb_val->embval_index;
+ }
}
- } // next field
- if (0 != emb_val) {
- if (reader.NodeType()==XML_READER_TYPE_TEXT) {
- UNIVERSAL_CHARSTRING emb_ustr((const char*)reader.Value());
- emb_val->embval_array->get_at(emb_val->embval_index)->set_value(&emb_ustr);
- }
- if (last_embval_index == emb_val->embval_index) {
- ++emb_val->embval_index;
- }
- }
- delete [] seen;
- ec_1.set_msg(" "); // no active component
- ec_0.set_msg(" ");
-
- // Check that we collected the required number of children
- int num_collected = use_order->size_of();
- if (p_td.xer_bits & USE_NIL) {
- int expected = usenil_attribute ? 0 : jumbled->get_count();
- if (num_collected != expected) {
- TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG,
- "Incorrect number of fields %d, expected %d",
- num_collected, expected);
+ delete [] seen;
+ ec_1.set_msg(" "); // no active component
+ ec_0.set_msg(" ");
+
+ // Check that we collected the required number of children
+ int num_collected = use_order->size_of();
+ if (p_td.xer_bits & USE_NIL) {
+ int expected = usenil_attribute ? 0 : jumbled->get_count();
+ if (num_collected != expected) {
+ TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG,
+ "Incorrect number of fields %d, expected %d",
+ num_collected, expected);
+ }
}
- }
- else {
- if (num_collected < field_cnt - first_nonattr - n_optionals
- ||num_collected > field_cnt - first_nonattr) {
- TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG,
- "Wrong number of fields! size = %d, expected %d..%d",
- use_order->size_of(), field_cnt - first_nonattr - n_optionals,
- field_cnt - first_nonattr);
+ else {
+ if (num_collected < field_cnt - first_nonattr - n_optionals
+ ||num_collected > field_cnt - first_nonattr) {
+ TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG,
+ "Wrong number of fields! size = %d, expected %d..%d",
+ use_order->size_of(), field_cnt - first_nonattr - n_optionals,
+ field_cnt - first_nonattr);
+ }
}
- }
+ } // not empty element
}
else { // not USE-ORDER, simpler code
if (usenil_attribute) {
} // if embed-values
} // if use-qname
-
+
+ // 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()) {
+ TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INCOMPL_MSG,
+ "No data found for non-optional field '%s'", fld_name(i));
+ }
+ }
+
if (own_tag) {
// We had our start tag. Then our fields did their thing.
// Now we expect the end tag. And it better be our end tag!
int field_count = get_count();
for(int i = 0; i < field_count; ++i) {
+ boolean metainfo_unbound = NULL != fld_descr(i)->json && fld_descr(i)->json->metainfo_unbound;
if ((NULL != fld_descr(i)->json && fld_descr(i)->json->omit_as_null) ||
- !get_at(i)->is_optional() || get_at(i)->is_present()) {
- if (NULL != fld_descr(i)->json && NULL != fld_descr(i)->json->alias) {
- enc_len += p_tok.put_next_token(JSON_TOKEN_NAME, fld_descr(i)->json->alias);
- } else {
- enc_len += p_tok.put_next_token(JSON_TOKEN_NAME, fld_name(i));
+ get_at(i)->is_present() || metainfo_unbound) {
+ const char* field_name = (NULL != fld_descr(i)->json && NULL != fld_descr(i)->json->alias) ?
+ fld_descr(i)->json->alias : fld_name(i);
+ enc_len += p_tok.put_next_token(JSON_TOKEN_NAME, field_name);
+ if (metainfo_unbound && !get_at(i)->is_bound()) {
+ enc_len += p_tok.put_next_token(JSON_TOKEN_LITERAL_NULL);
+ char* metainfo_str = mprintf("metainfo %s", field_name);
+ enc_len += p_tok.put_next_token(JSON_TOKEN_NAME, metainfo_str);
+ Free(metainfo_str);
+ enc_len += p_tok.put_next_token(JSON_TOKEN_STRING, "\"unbound\"");
+ }
+ else {
+ enc_len += get_at(i)->JSON_encode(*fld_descr(i), p_tok);
}
- enc_len += get_at(i)->JSON_encode(*fld_descr(i), p_tok);
}
}
const int field_count = get_count();
+ // initialize meta info states
+ int* metainfo = new int[field_count];
+ for (int i = 0; i < field_count; ++i) {
+ metainfo[i] = (NULL != fld_descr(i)->json && fld_descr(i)->json->metainfo_unbound) ?
+ JSON_METAINFO_NONE : JSON_METAINFO_NOT_APPLICABLE;
+ }
+
while (true) {
// Read name - value token pairs until we reach some other token
char* name = 0;
break;
}
else {
+ // check for meta info
+ boolean is_metainfo = FALSE;
+ if (name_len > 9 && 0 == strncmp(name, "metainfo ", 9)) {
+ name += 9;
+ name_len -= 9;
+ is_metainfo = TRUE;
+ }
+
// check field name
int field_idx;
for (field_idx = 0; field_idx < field_count; ++field_idx) {
if (field_count == field_idx) {
// invalid field name
char* name2 = mcopystrn(name, name_len);
- JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_INVALID_NAME_ERROR, name2);
+ JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, is_metainfo ?
+ JSON_DEC_METAINFO_NAME_ERROR : JSON_DEC_INVALID_NAME_ERROR, name2);
// if this is set to a warning, skip the value of the field
dec_len += p_tok.get_next_token(&token, NULL, NULL);
if (JSON_TOKEN_NUMBER != token && JSON_TOKEN_STRING != token &&
continue;
}
- int ret_val = get_at(field_idx)->JSON_decode(*fld_descr(field_idx), p_tok, p_silent);
- if (0 > ret_val) {
- if (JSON_ERROR_INVALID_TOKEN) {
- JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FIELD_TOKEN_ERROR, fld_name(field_idx));
+ if (is_metainfo) {
+ if (JSON_METAINFO_NOT_APPLICABLE != metainfo[field_idx]) {
+ // check meta info
+ char* info_value = 0;
+ size_t info_len = 0;
+ dec_len += p_tok.get_next_token(&token, &info_value, &info_len);
+ if (JSON_TOKEN_STRING == token && 9 == info_len &&
+ 0 == strncmp(info_value, "\"unbound\"", 9)) {
+ metainfo[field_idx] = JSON_METAINFO_UNBOUND;
+ }
+ else {
+ JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_METAINFO_VALUE_ERROR,
+ fld_name(field_idx));
+ return JSON_ERROR_FATAL;
+ }
+ }
+ else {
+ JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_METAINFO_NOT_APPLICABLE,
+ fld_name(field_idx));
+ return JSON_ERROR_FATAL;
}
- return JSON_ERROR_FATAL;
}
- dec_len += ret_val;
+ else {
+ buf_pos = p_tok.get_buf_pos();
+ int ret_val = get_at(field_idx)->JSON_decode(*fld_descr(field_idx), p_tok, p_silent);
+ if (0 > ret_val) {
+ if (JSON_ERROR_INVALID_TOKEN == ret_val) {
+ // undo the last action on the buffer, check if the invalid token was a null token
+ p_tok.set_buf_pos(buf_pos);
+ p_tok.get_next_token(&token, NULL, NULL);
+ if (JSON_TOKEN_LITERAL_NULL == token) {
+ if (JSON_METAINFO_NONE == metainfo[field_idx]) {
+ // delay reporting an error for now, there might be meta info later
+ metainfo[field_idx] = JSON_METAINFO_NEEDED;
+ continue;
+ }
+ else if (JSON_METAINFO_UNBOUND == metainfo[field_idx]) {
+ // meta info already found
+ continue;
+ }
+ }
+ JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FIELD_TOKEN_ERROR, fld_name(field_idx));
+ }
+ return JSON_ERROR_FATAL;
+ }
+ dec_len += ret_val;
+ }
}
}
return JSON_ERROR_FATAL;
}
- // Check if every field has been set
+ // Check if every field has been set and handle meta info
for (int field_idx = 0; field_idx < field_count; ++field_idx) {
Base_Type* field = get_at(field_idx);
- if (!field->is_bound()) {
+ if (JSON_METAINFO_UNBOUND == metainfo[field_idx]) {
+ field->clean_up();
+ }
+ else if (JSON_METAINFO_NEEDED == metainfo[field_idx]) {
+ // no meta info was found for this field, report the delayed error
+ JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FIELD_TOKEN_ERROR, fld_name(field_idx));
+ }
+ else if (!field->is_bound()) {
if (NULL != fld_descr(field_idx)->json && NULL != fld_descr(field_idx)->json->default_value) {
get_at(field_idx)->JSON_decode(*fld_descr(field_idx), DUMMY_BUFFER, p_silent);
}
}
}
+ delete metainfo;
+
return dec_len;
}
void Empty_Record_Type::set_param(Module_Param& param) {
param.basic_check(Module_Param::BC_VALUE, "empty record/set value (i.e. { })");
- if (param.get_type()!=Module_Param::MP_Value_List || param.get_size()>0) {
+ Module_Param_Ptr mp = ¶m;
+ if (param.get_type() == Module_Param::MP_Reference) {
+ mp = param.get_referenced_param();
+ }
+ if (mp->get_type()!=Module_Param::MP_Value_List || mp->get_size()>0) {
param.type_error("empty record/set value (i.e. { })", get_descriptor()->name);
}
bound_flag = TRUE;
}
+Module_Param* Empty_Record_Type::get_param(Module_Param_Name& /* param_name */) const
+{
+ if (!is_bound()) {
+ return new Module_Param_Unbound();
+ }
+ return new Module_Param_Value_List();
+}
+
void Empty_Record_Type::encode_text(Text_Buf& /*text_buf*/) const
{
if (!bound_flag)