Commit 468b295f authored by Botond Baranyi's avatar Botond Baranyi
Browse files

Implemented JSON attribute 'as map' (bug 540051)



Change-Id: I5d228318532b9e6774e77c7604e63e2fba4afab5
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent 284c5813
...@@ -3013,6 +3013,34 @@ namespace Common { ...@@ -3013,6 +3013,34 @@ namespace Common {
if (NULL != jsonattrib->tag_list) { if (NULL != jsonattrib->tag_list) {
chk_json_tag_list(); chk_json_tag_list();
} }
if (jsonattrib->as_map) {
Type* last = get_type_refd_last();
if (T_SEQOF != last->typetype && T_SETOF != last->typetype) {
error("Invalid attribute, 'as map' requires record of or set of");
}
else {
Type* of_type = last->get_ofType();
Type* of_type_last = of_type->get_type_refd_last();
if ((T_SEQ_T != of_type_last->typetype &&
T_SET_T != of_type_last->typetype) ||
of_type_last->get_nof_comps() != 2) {
error("Invalid attribute, 'as map' requires the element type to be "
"a record or set with 2 fields");
}
else {
Type* key_type = of_type_last->get_comp_byIndex(0)->get_type();
if (key_type->get_type_refd_last()->get_typetype() != T_USTR) {
error("Invalid attribute, 'as map' requires the element type's "
"first field to be a universal charstring");
}
if (key_type->is_optional_field()) {
error("Invalid attribute, 'as map' requires the element type's "
"first field to be mandatory");
}
}
}
}
} }
} }
......
...@@ -1091,23 +1091,30 @@ void Type::generate_code_jsondescriptor(output_struct *target) ...@@ -1091,23 +1091,30 @@ void Type::generate_code_jsondescriptor(output_struct *target)
target->header.global_vars = mputprintf(target->header.global_vars, target->header.global_vars = mputprintf(target->header.global_vars,
"extern const TTCN_JSONdescriptor_t %s_json_;\n", get_genname_own().c_str()); "extern const TTCN_JSONdescriptor_t %s_json_;\n", get_genname_own().c_str());
boolean as_map = (jsonattrib != NULL && jsonattrib->as_map) ||
(ownertype == OT_RECORD_OF && parent_type->jsonattrib != NULL &&
parent_type->jsonattrib->as_map);
if (NULL == jsonattrib) { if (NULL == jsonattrib) {
target->source.global_vars = mputprintf(target->source.global_vars, target->source.global_vars = mputprintf(target->source.global_vars,
"const TTCN_JSONdescriptor_t %s_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE };\n" "const TTCN_JSONdescriptor_t %s_json_ = { FALSE, NULL, FALSE, NULL, "
, get_genname_own().c_str()); "FALSE, FALSE, %s };\n"
, get_genname_own().c_str(), as_map ? "TRUE" : "FALSE");
} else { } else {
char* alias = jsonattrib->alias ? mputprintf(NULL, "\"%s\"", jsonattrib->alias) : NULL; char* alias = jsonattrib->alias ? mputprintf(NULL, "\"%s\"", jsonattrib->alias) : NULL;
char* def_val = jsonattrib->default_value ? char* def_val = jsonattrib->default_value ?
mputprintf(NULL, "\"%s\"", jsonattrib->default_value) : NULL; mputprintf(NULL, "\"%s\"", jsonattrib->default_value) : NULL;
target->source.global_vars = mputprintf(target->source.global_vars, target->source.global_vars = mputprintf(target->source.global_vars,
"const TTCN_JSONdescriptor_t %s_json_ = { %s, %s, %s, %s, %s, %s };\n" "const TTCN_JSONdescriptor_t %s_json_ = { %s, %s, %s, %s, %s, %s, %s };\n"
, get_genname_own().c_str() , get_genname_own().c_str()
, jsonattrib->omit_as_null ? "TRUE" : "FALSE" , jsonattrib->omit_as_null ? "TRUE" : "FALSE"
, alias ? alias : "NULL" , alias ? alias : "NULL"
, (jsonattrib->as_value || jsonattrib->tag_list != NULL) ? "TRUE" : "FALSE" , (jsonattrib->as_value || jsonattrib->tag_list != NULL) ? "TRUE" : "FALSE"
, def_val ? def_val : "NULL" , def_val ? def_val : "NULL"
, jsonattrib->metainfo_unbound ? "TRUE" : "FALSE" , jsonattrib->metainfo_unbound ? "TRUE" : "FALSE"
, jsonattrib->as_number ? "TRUE" : "FALSE"); , jsonattrib->as_number ? "TRUE" : "FALSE"
, as_map ? "TRUE" : "FALSE");
Free(alias); Free(alias);
Free(def_val); Free(def_val);
} }
...@@ -1737,6 +1744,18 @@ void Type::generate_code_Se(output_struct *target) ...@@ -1737,6 +1744,18 @@ void Type::generate_code_Se(output_struct *target)
FATAL_ERROR("Type::generate_code_Se()"); // union only, not for record FATAL_ERROR("Type::generate_code_Se()"); // union only, not for record
} }
} }
if (jsonattrib != NULL) {
sdef.jsonAsValue = jsonattrib->as_value;
}
if (sdef.nElements == 2) {
Type* first_field_type = get_comp_byIndex(0)->get_type();
sdef.jsonAsMapPossible = !first_field_type->is_optional_field() &&
first_field_type->get_type_refd_last()->typetype == T_USTR;
}
else {
sdef.jsonAsMapPossible = FALSE;
}
sdef.elements = (struct_field*) sdef.elements = (struct_field*)
Malloc(sdef.totalElements*sizeof(*sdef.elements)); Malloc(sdef.totalElements*sizeof(*sdef.elements));
memset(sdef.elements, 0, sdef.totalElements * sizeof(*sdef.elements)); memset(sdef.elements, 0, sdef.totalElements * sizeof(*sdef.elements));
......
...@@ -121,6 +121,7 @@ typedef struct { ...@@ -121,6 +121,7 @@ typedef struct {
boolean xerHasNamespaces; /* from the module */ boolean xerHasNamespaces; /* from the module */
boolean xerEmbedValuesPossible; /* for sequence */ boolean xerEmbedValuesPossible; /* for sequence */
boolean jsonAsValue; /* for both */ boolean jsonAsValue; /* for both */
boolean jsonAsMapPossible; /* for sequence */
/** The index of the last field which can generate empty XML, or -1 */ /** The index of the last field which can generate empty XML, or -1 */
int exerMaybeEmptyIndex; /* for union */ int exerMaybeEmptyIndex; /* for union */
const char * control_ns_prefix; const char * control_ns_prefix;
......
...@@ -3226,7 +3226,8 @@ char* generate_json_decoder(char* src, const struct_def* sdef) ...@@ -3226,7 +3226,8 @@ char* generate_json_decoder(char* src, const struct_def* sdef)
src = mputprintf(src, src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t&%s, JSON_Tokenizer& p_tok, " "int %s::JSON_decode(const TTCN_Typedescriptor_t&%s, JSON_Tokenizer& p_tok, "
"boolean p_silent, int)\n" "boolean p_silent, int)\n"
"{\n", sdef->name, (sdef->nElements == 1 && !sdef->jsonAsValue) ? " p_td" : ""); "{\n", sdef->name,
((sdef->nElements == 1 && !sdef->jsonAsValue) || sdef->jsonAsMapPossible) ? " p_td" : "");
if (sdef->nElements == 1) { if (sdef->nElements == 1) {
if (!sdef->jsonAsValue) { if (!sdef->jsonAsValue) {
...@@ -3238,9 +3239,31 @@ char* generate_json_decoder(char* src, const struct_def* sdef) ...@@ -3238,9 +3239,31 @@ char* generate_json_decoder(char* src, const struct_def* sdef)
src = mputstr(src, " }\n"); src = mputstr(src, " }\n");
} }
} }
if (!sdef->jsonAsValue) {
src = mputstr(src, " json_token_t j_token = JSON_TOKEN_NONE;\n");
}
if (sdef->jsonAsMapPossible) {
src = mputprintf(src,
" if (p_td.json->as_map) {\n"
" char* fld_name = NULL;\n"
" size_t name_len = 0;\n"
" size_t buf_pos = p_tok.get_buf_pos();\n"
" size_t dec_len = p_tok.get_next_token(&j_token, &fld_name, &name_len);\n"
" if (JSON_TOKEN_ERROR == j_token) {\n"
" JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, \"\");\n"
" return JSON_ERROR_FATAL;\n"
" }\n"
" else if (JSON_TOKEN_NAME != j_token) {\n"
" p_tok.set_buf_pos(buf_pos);\n"
" return JSON_ERROR_INVALID_TOKEN;\n"
" }\n"
" field_%s.decode_utf8(name_len, (unsigned char*) fld_name);\n"
" return field_%s.JSON_decode(%s_descr_, p_tok, p_silent) + dec_len;\n"
" }\n", sdef->elements[0].name,
sdef->elements[1].name, sdef->elements[1].typedescrname);
}
if (!sdef->jsonAsValue) { if (!sdef->jsonAsValue) {
src = mputstr(src, src = mputstr(src,
" json_token_t j_token = JSON_TOKEN_NONE;\n"
" size_t dec_len = p_tok.get_next_token(&j_token, NULL, NULL);\n" " size_t dec_len = p_tok.get_next_token(&j_token, NULL, NULL);\n"
" if (JSON_TOKEN_ERROR == j_token) {\n" " if (JSON_TOKEN_ERROR == j_token) {\n"
" JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, \"\");\n" " JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, \"\");\n"
...@@ -4738,7 +4761,8 @@ void defRecordClass1(const struct_def *sdef, output_struct *output) ...@@ -4738,7 +4761,8 @@ void defRecordClass1(const struct_def *sdef, output_struct *output)
" TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,\n" " TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,\n"
" \"Encoding an unbound value of type %s.\");\n" " \"Encoding an unbound value of type %s.\");\n"
" return -1;\n" " return -1;\n"
" }\n\n", name, (sdef->nElements == 1 && !sdef->jsonAsValue) ? " p_td" : "", dispname); " }\n\n", name,
((sdef->nElements == 1 && !sdef->jsonAsValue) || sdef->jsonAsMapPossible) ? " p_td" : "", dispname);
if (sdef->nElements == 1) { if (sdef->nElements == 1) {
if (!sdef->jsonAsValue) { if (!sdef->jsonAsValue) {
src = mputstr(src, " if (NULL != p_td.json && p_td.json->as_value) {\n"); src = mputstr(src, " if (NULL != p_td.json && p_td.json->as_value) {\n");
...@@ -4749,6 +4773,18 @@ void defRecordClass1(const struct_def *sdef, output_struct *output) ...@@ -4749,6 +4773,18 @@ void defRecordClass1(const struct_def *sdef, output_struct *output)
src = mputstr(src, " }\n"); src = mputstr(src, " }\n");
} }
} }
if (sdef->jsonAsMapPossible) {
src = mputprintf(src,
" if (p_td.json->as_map) {\n"
" TTCN_Buffer key_buf;\n"
" field_%s.encode_utf8(key_buf);\n"
" CHARSTRING key_str;\n"
" key_buf.get_string(key_str);\n"
" return p_tok.put_next_token(JSON_TOKEN_NAME, (const char*) key_str) + \n"
" field_%s.JSON_encode(%s_descr_, p_tok);\n"
" }\n", sdef->elements[0].name,
sdef->elements[1].name, sdef->elements[1].typedescrname);
}
if (!sdef->jsonAsValue) { if (!sdef->jsonAsValue) {
src = mputstr(src, " int enc_len = p_tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL);\n\n"); src = mputstr(src, " int enc_len = p_tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL);\n\n");
for (i = 0; i < sdef->nElements; ++i) { for (i = 0; i < sdef->nElements; ++i) {
......
...@@ -1545,7 +1545,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) ...@@ -1545,7 +1545,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
" \"Encoding an unbound value of type %s.\");\n" " \"Encoding an unbound value of type %s.\");\n"
" return -1;\n" " return -1;\n"
" }\n\n" " }\n\n"
" int enc_len = p_tok.put_next_token(JSON_TOKEN_ARRAY_START, NULL);\n" " int enc_len = p_tok.put_next_token(p_td.json->as_map ? "
"JSON_TOKEN_OBJECT_START : JSON_TOKEN_ARRAY_START, NULL);\n"
" for (int i = 0; i < val_ptr->n_elements; ++i) {\n" " for (int i = 0; i < val_ptr->n_elements; ++i) {\n"
" if (NULL != p_td.json && p_td.json->metainfo_unbound && !(*this)[i].is_bound()) {\n" " if (NULL != p_td.json && p_td.json->metainfo_unbound && !(*this)[i].is_bound()) {\n"
// unbound elements are encoded as { "metainfo []" : "unbound" } // unbound elements are encoded as { "metainfo []" : "unbound" }
...@@ -1560,7 +1561,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) ...@@ -1560,7 +1561,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
" enc_len += ret_val;\n" " enc_len += ret_val;\n"
" }\n" " }\n"
" }\n" " }\n"
" enc_len += p_tok.put_next_token(JSON_TOKEN_ARRAY_END, NULL);\n" " enc_len += p_tok.put_next_token(p_td.json->as_map ? "
"JSON_TOKEN_OBJECT_END : JSON_TOKEN_ARRAY_END, NULL);\n"
" return enc_len;\n" " return enc_len;\n"
"}\n\n" "}\n\n"
, name, dispname); , name, dispname);
...@@ -1581,7 +1583,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) ...@@ -1581,7 +1583,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
" JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, \"\");\n" " JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, \"\");\n"
" return JSON_ERROR_FATAL;\n" " return JSON_ERROR_FATAL;\n"
" }\n" " }\n"
" else if (JSON_TOKEN_ARRAY_START != token) {\n" " else if ((!p_td.json->as_map && JSON_TOKEN_ARRAY_START != token) ||\n"
" (p_td.json->as_map && JSON_TOKEN_OBJECT_START != token)) {\n"
" return JSON_ERROR_INVALID_TOKEN;\n" " return JSON_ERROR_INVALID_TOKEN;\n"
" }\n\n" " }\n\n"
" set_size(0);\n" " set_size(0);\n"
...@@ -1632,7 +1635,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output) ...@@ -1632,7 +1635,8 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
" dec_len += (size_t)ret_val2;\n" " dec_len += (size_t)ret_val2;\n"
" }\n\n" " }\n\n"
" dec_len += p_tok.get_next_token(&token, NULL, NULL);\n" " dec_len += p_tok.get_next_token(&token, NULL, NULL);\n"
" if (JSON_TOKEN_ARRAY_END != token) {\n" " if ((!p_td.json->as_map && JSON_TOKEN_ARRAY_END != token) ||\n"
" (p_td.json->as_map && JSON_TOKEN_OBJECT_END != token)) {\n"
" JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_REC_OF_END_TOKEN_ERROR, \"\");\n" " JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_REC_OF_END_TOKEN_ERROR, \"\");\n"
" if (p_silent) {\n" " if (p_silent) {\n"
" clean_up();\n" " clean_up();\n"
......
...@@ -36,6 +36,7 @@ void JsonAST::init_JsonAST() ...@@ -36,6 +36,7 @@ void JsonAST::init_JsonAST()
metainfo_unbound = false; metainfo_unbound = false;
as_number = false; as_number = false;
tag_list = NULL; tag_list = NULL;
as_map = false;
} }
JsonAST::JsonAST(const JsonAST *other_val) JsonAST::JsonAST(const JsonAST *other_val)
...@@ -51,6 +52,7 @@ JsonAST::JsonAST(const JsonAST *other_val) ...@@ -51,6 +52,7 @@ JsonAST::JsonAST(const JsonAST *other_val)
schema_extensions.add(new JsonSchemaExtension(*other_val->schema_extensions[i])); schema_extensions.add(new JsonSchemaExtension(*other_val->schema_extensions[i]));
} }
metainfo_unbound = other_val->metainfo_unbound; metainfo_unbound = other_val->metainfo_unbound;
as_map = other_val->as_map;
} }
} }
...@@ -119,4 +121,7 @@ void JsonAST::print_JsonAST() const ...@@ -119,4 +121,7 @@ void JsonAST::print_JsonAST() const
} }
} }
} }
if (as_map) {
printf("Encoding elements into a map of key-value pairs.\n\r");
}
} }
...@@ -43,6 +43,7 @@ class JsonAST { ...@@ -43,6 +43,7 @@ class JsonAST {
boolean metainfo_unbound; boolean metainfo_unbound;
boolean as_number; boolean as_number;
rawAST_tag_list* tag_list; rawAST_tag_list* tag_list;
boolean as_map;
JsonAST() { init_JsonAST(); } JsonAST() { init_JsonAST(); }
JsonAST(const JsonAST *other_val); JsonAST(const JsonAST *other_val);
......
...@@ -500,6 +500,7 @@ for RETURN(XKWfor); ...@@ -500,6 +500,7 @@ for RETURN(XKWfor);
unbound RETURN(XKWunbound); unbound RETURN(XKWunbound);
chosen RETURN(XChosenKeyword); chosen RETURN(XChosenKeyword);
otherwise RETURN(XJsonOtherwise); otherwise RETURN(XJsonOtherwise);
map RETURN(XJsonMap);
} }
<INITIAL>{ <INITIAL>{
......
...@@ -298,6 +298,7 @@ static void yyprint(FILE *file, int type, const YYSTYPE& value); ...@@ -298,6 +298,7 @@ static void yyprint(FILE *file, int type, const YYSTYPE& value);
%token XAsValueKeyword "asValue" %token XAsValueKeyword "asValue"
%token XChosenKeyword "chosen" %token XChosenKeyword "chosen"
%token XJsonOtherwise "otherwise" %token XJsonOtherwise "otherwise"
%token XJsonMap "map"
%type <enumval> %type <enumval>
...@@ -1840,6 +1841,7 @@ JSONattribute: ...@@ -1840,6 +1841,7 @@ JSONattribute:
| JMetainfoForUnbound | JMetainfoForUnbound
| JAsNumber | JAsNumber
| JChosen | JChosen
| JAsMap
; ;
JOmitAsNull: JOmitAsNull:
...@@ -1880,6 +1882,10 @@ JChosen: ...@@ -1880,6 +1882,10 @@ JChosen:
} }
; ;
JAsMap:
XKWas XJsonMap { jsonstruct->as_map = true; }
;
%% %%
/* parse_rawAST(), which calls our rawAST_parse, is over in rawASST.l */ /* parse_rawAST(), which calls our rawAST_parse, is over in rawASST.l */
......
...@@ -32,55 +32,55 @@ ...@@ -32,55 +32,55 @@
#include <sys/types.h> #include <sys/types.h>
// JSON descriptors for base types // JSON descriptors for base types
const TTCN_JSONdescriptor_t INTEGER_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t INTEGER_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t FLOAT_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t FLOAT_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t BOOLEAN_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t BOOLEAN_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t BITSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t BITSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t HEXSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t HEXSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t OCTETSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t OCTETSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t CHARSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t CHARSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t UNIVERSAL_CHARSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t UNIVERSAL_CHARSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t VERDICTTYPE_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t VERDICTTYPE_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t GeneralString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t GeneralString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t NumericString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t NumericString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t UTF8String_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t UTF8String_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t PrintableString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t PrintableString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t UniversalString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t UniversalString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t BMPString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t BMPString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t GraphicString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t GraphicString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t IA5String_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t IA5String_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t TeletexString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t TeletexString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t VideotexString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t VideotexString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t VisibleString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t VisibleString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t ASN_NULL_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t ASN_NULL_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t OBJID_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t OBJID_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t ASN_ROID_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t ASN_ROID_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t ASN_ANY_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t ASN_ANY_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
const TTCN_JSONdescriptor_t ENUMERATED_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE }; const TTCN_JSONdescriptor_t ENUMERATED_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE };
......
...@@ -66,6 +66,13 @@ struct TTCN_JSONdescriptor_t ...@@ -66,6 +66,13 @@ struct TTCN_JSONdescriptor_t
* number, instead of its name form as a JSON string (affects both encoding * number, instead of its name form as a JSON string (affects both encoding
* and decoding). */ * and decoding). */
boolean as_number; boolean as_number;
/** If set, encodes the value into a map of key-value pairs (i.e. a fully
* customizable JSON object). The encoded type has to be a record of/set of
* with a record/set element type, which has 2 fields, the first of which is
* a non-optional universal charstring.
* Example: { "key1" : value1, "key2" : value2 } */
boolean as_map;
}; };
/** This macro makes sure that coding errors will only be displayed if the silent /** This macro makes sure that coding errors will only be displayed if the silent
......
...@@ -1476,7 +1476,8 @@ int Record_Of_Type::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenize ...@@ -1476,7 +1476,8 @@ int Record_Of_Type::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenize
return -1; return -1;
} }
int enc_len = p_tok.put_next_token(JSON_TOKEN_ARRAY_START, NULL); int enc_len = p_tok.put_next_token(p_td.json->as_map ? JSON_TOKEN_OBJECT_START :
JSON_TOKEN_ARRAY_START, NULL);
for (int i = 0; i < get_nof_elements(); ++i) { for (int i = 0; i < get_nof_elements(); ++i) {
if (NULL != p_td.json && p_td.json->metainfo_unbound && !get_at(i)->is_bound()) { if (NULL != p_td.json && p_td.json->metainfo_unbound && !get_at(i)->is_bound()) {
...@@ -1493,7 +1494,8 @@ int Record_Of_Type::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenize ...@@ -1493,7 +1494,8 @@ int Record_Of_Type::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenize
} }
} }
enc_len += p_tok.put_next_token(JSON_TOKEN_ARRAY_END, NULL); enc_len += p_tok.put_next_token(p_td.json->as_map ? JSON_TOKEN_OBJECT_END :
JSON_TOKEN_ARRAY_END, NULL);
return enc_len; return enc_len;
} }
...@@ -1507,7 +1509,8 @@ int Record_Of_Type::JSON_encode_negtest(const Erroneous_descriptor_t* p_err_desc ...@@ -1507,7 +1509,8 @@ int Record_Of_Type::JSON_encode_negtest(const Erroneous_descriptor_t* p_err_desc
return -1; return -1;
} }
int enc_len = p_tok.put_next_token(JSON_TOKEN_ARRAY_START, NULL); int enc_len = p_tok.put_next_token(p_td.json->as_map ? JSON_TOKEN_OBJECT_START :
JSON_TOKEN_ARRAY_START, NULL);
int values_idx = 0; int values_idx = 0;
int edescr_idx = 0; int edescr_idx = 0;
...@@ -1583,7 +1586,8 @@ int Record_Of_Type::JSON_encode_negtest(const Erroneous_descriptor_t* p_err_desc ...@@ -1583,7 +1586,8 @@ int Record_Of_Type::JSON_encode_negtest(const Erroneous_descriptor_t* p_err_desc
} }
} }
enc_len += p_tok.put_next_token(JSON_TOKEN_ARRAY_END, NULL); enc_len += p_tok.put_next_token(p_td.json->as_map ? JSON_TOKEN_OBJECT_END :
JSON_TOKEN_ARRAY_END, NULL);
return enc_len; return enc_len;
} }
...@@ -1601,7 +1605,8 @@ int Record_Of_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenize ...@@ -1601,7 +1605,8 @@ int Record_Of_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenize
JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, ""); JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, "");
return JSON_ERROR_FATAL; return JSON_ERROR_FATAL;
} }
else if (JSON_TOKEN_ARRAY_START != token) { else if ((!p_td.json->as_map && JSON_TOKEN_ARRAY_START != token) ||
(p_td.json->as_map && JSON_TOKEN_OBJECT_START != token)) {
return JSON_ERROR_INVALID_TOKEN; return JSON_ERROR_INVALID_TOKEN;
} }
...@@ -1661,7 +1666,8 @@ int Record_Of_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenize ...@@ -1661,7 +1666,8 @@ int Record_Of_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenize
} }
dec_len += p_tok.get_next_token(&token, NULL, NULL); dec_len += p_tok.get_next_token(&token, NULL, NULL);
if (JSON_TOKEN_ARRAY_END != token) { if ((!p_td.json->as_map && JSON_TOKEN_ARRAY_END != token) ||
(p_td.json->as_map && JSON_TOKEN_OBJECT_END != token)) {
JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_REC_OF_END_TOKEN_ERROR, ""); JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_REC_OF_END_TOKEN_ERROR, "");
if (p_silent) { if (p_silent) {
clean_up(); clean_up();
...@@ -5951,6 +5957,21 @@ int Record_Type::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& ...@@ -5951,6 +5957,21 @@ int Record_Type::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer&
return get_at(0)->JSON_encode(*fld_descr(0), p_tok); return get_at(0)->JSON_encode(*fld_descr(0), p_tok);
} }
if (p_td.json->as_map) { // TODO: implement negtest
const UNIVERSAL_CHARSTRING* key_ustr = dynamic_cast<
const UNIVERSAL_CHARSTRING*>(get_at(0));
if (NULL == key_ustr) {
TTCN_error("Internal error: attribute 'as map' is set, but the first "
"field is not a universal charstring");
}
TTCN_Buffer key_buf;