Commit 6c6bc1d0 authored by Botond Baranyi's avatar Botond Baranyi
Browse files

Implemented support for the attributes in the standard's JSON module (bug 553584)



Change-Id: I042bae37f20d4dcb9a23d96a5c30cafda9d978f0
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent dad2eee2
......@@ -2983,7 +2983,7 @@ namespace Common {
if (json_checked) return;
json_checked = true;
if ((NULL == jsonattrib && !hasEncodeAttr(get_encoding_name(CT_JSON))) || !enable_json()) return;
switch (typetype) {
case T_ANYTYPE:
case T_CHOICE_T:
......@@ -3020,13 +3020,14 @@ namespace Common {
break; // OK
case T_SEQ_T:
case T_SET_T:
if (last->get_nof_comps() == 1) {
if (last->get_nof_comps() == 1 &&
!last->get_comp_byIndex(0)->get_is_optional()) {
break; // OK
}
// else fall through
default:
error("Invalid attribute, 'as value' is only allowed for unions, "
"the anytype, or records or sets with one field");
"the anytype, or records or sets with one mandatory field");
}
}
......@@ -3164,7 +3165,10 @@ namespace Common {
chk_json_tag_list();
}
if (jsonattrib->as_map) {
if (jsonattrib->as_map || (ownertype == OT_COMP_FIELD &&
parent_type->jsonattrib != NULL &&
parent_type->jsonattrib->type_indicator == JsonAST::JSON_OBJECT)) {
jsonattrib->as_map = true;
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");
......@@ -3220,6 +3224,74 @@ namespace Common {
}
}
}
if (jsonattrib->type_indicator != JsonAST::JSON_NO_TYPE) {
Type* last = get_type_refd_last();
switch (jsonattrib->type_indicator) {
case JsonAST::JSON_NUMBER:
if (last->typetype != T_REAL) {
error("Invalid attribute, 'JSON:number' requires a float type");
}
break;
case JsonAST::JSON_INTEGER:
if (last->typetype != T_INT) {
error("Invalid attribute, 'JSON:integer' requires an integer type");
}
break;
case JsonAST::JSON_STRING:
if (last->typetype != T_USTR) {
error("Invalid attribute, 'JSON:string' requires a universal charstring type");
}
break;
case JsonAST::JSON_ARRAY:
if (last->typetype != T_SEQOF) {
error("Invalid attribute, 'JSON:array' requires a record of type");
}
break;
case JsonAST::JSON_OBJECT_MEMBER:
if (last->typetype != T_SEQ_T) {
error("Invalid attribute, 'JSON:objectMember' requires a record type");
}
break;
case JsonAST::JSON_OBJECT:
if ((last->typetype == T_SEQ_T || last->typetype == T_SET_T) &&
last->get_nof_comps() == 1 && last->get_comp_byIndex(0)->get_is_optional()) {
jsonattrib->as_value = true;
// the field type's chk_json will set the 'as map' flag for itself
// note: normally the 'as value' attribute doesn't allow the one field
// in the record to be optional; this is used at runtime to differentiate
// between a regular 'as value' attribute and 'JSON:object'
}
else {
error("Invalid attribute, 'JSON:object' requires a record or set type "
"with one optional field");
}
break;
case JsonAST::JSON_LITERAL:
if (last->typetype == T_ENUM_T) {
if (last->u.enums.eis->get_nof_eis() == 1) {
jsonattrib->use_null = true;
}
else {
error("Invalid attribute, 'JSON:object' requires the type to have "
"only one enumerated item");
}
}
else if (last->typetype != T_BOOL) {
error("Invalid attribute, 'JSON:literal' requires a boolean or "
"enumerated type");
}
break;
default:
FATAL_ERROR("Type::chk_json");
}
}
if (jsonattrib->string_escaping != JsonAST::ESCAPING_UNSET) {
Type* last = get_type_refd_last();
if (last->typetype != T_USTR && last->typetype != T_CSTR) {
error("Invalid attribute, 'escape as ...' requires a charstring or "
"universal charstring type");
}
}
}
}
......
......@@ -1113,7 +1113,7 @@ void Type::generate_code_jsondescriptor(output_struct *target)
if (NULL == jsonattrib) {
target->source.global_vars = mputprintf(target->source.global_vars,
"const TTCN_JSONdescriptor_t %s_json_ = { FALSE, NULL, FALSE, NULL, "
"FALSE, FALSE, %s, 0, NULL };\n"
"FALSE, FALSE, %s, 0, NULL, FALSE, ESCAPE_AS_SHORT };\n"
, get_genname_own().c_str(), as_map ? "TRUE" : "FALSE");
} else {
char* alias = jsonattrib->alias ? mputprintf(NULL, "\"%s\"", jsonattrib->alias) : NULL;
......@@ -1139,7 +1139,7 @@ void Type::generate_code_jsondescriptor(output_struct *target)
target->source.global_vars = mputprintf(target->source.global_vars,
"const TTCN_JSONdescriptor_t %s_json_ = { %s, %s, %s, %s, %s, %s, %s, "
"%d, %s };\n"
"%d, %s, %s, %s };\n"
, get_genname_own().c_str()
, jsonattrib->omit_as_null ? "TRUE" : "FALSE"
, alias ? alias : "NULL"
......@@ -1149,7 +1149,9 @@ void Type::generate_code_jsondescriptor(output_struct *target)
, jsonattrib->as_number ? "TRUE" : "FALSE"
, as_map ? "TRUE" : "FALSE"
, static_cast<int>(jsonattrib->enum_texts.size())
, enum_texts_name);
, enum_texts_name
, jsonattrib->use_null ? "TRUE" : "FALSE"
, jsonattrib->get_escaping_gen_str());
Free(alias);
Free(def_val);
Free(enum_texts_name);
......@@ -1411,6 +1413,9 @@ void Type::generate_code_Choice(output_struct *target)
case T_NULL:
sdef.elements[i].jsonValueType = JSON_NULL;
break;
case T_ENUM_T:
sdef.elements[i].jsonValueType = JSON_STRING | JSON_NULL;
break;
case T_BSTR:
case T_BSTR_A:
case T_HSTR:
......@@ -1429,7 +1434,6 @@ void Type::generate_code_Choice(output_struct *target)
case T_UNIVERSALSTRING:
case T_BMPSTRING:
case T_VERDICT:
case T_ENUM_T:
case T_ENUM_A:
case T_OID:
case T_ROID:
......
......@@ -81,9 +81,9 @@ void def_encdec(const char *p_classname,
);
if(json) {
def = mputprintf(def,
"int JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&) const;\n"
"int JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean) const;\n"
"int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean, "
"int p_chosen_field = CHOSEN_FIELD_UNSET);\n");
"boolean, int p_chosen_field = CHOSEN_FIELD_UNSET);\n");
}
if(oer) {
def = mputprintf(def,
......@@ -147,7 +147,7 @@ void def_encdec(const char *p_classname,
" TTCN_EncDec_ErrorContext::error_internal\n"
" (\"No JSON descriptor available for type '%%s'.\", p_td.name);\n"
" JSON_Tokenizer tok(va_arg(pvar, int) != 0);\n"
" JSON_encode(p_td, tok);\n"
" JSON_encode(p_td, tok, FALSE);\n"
" p_buf.put_s(tok.get_buffer_length(), (const unsigned char*)tok.get_buffer());\n"
" break;}\n"
" case TTCN_EncDec::CT_OER: {\n"
......@@ -265,7 +265,7 @@ void def_encdec(const char *p_classname,
" TTCN_EncDec_ErrorContext::error_internal\n"
" (\"No JSON descriptor available for type '%%s'.\", p_td.name);\n"
" JSON_Tokenizer tok((const char*)p_buf.get_data(), p_buf.get_len());\n"
" if(JSON_decode(p_td, tok, FALSE)<0)\n"
" if(JSON_decode(p_td, tok, FALSE, FALSE)<0)\n"
" ec.error(TTCN_EncDec::ET_INCOMPL_MSG,"
"\"Can not decode type '%%s', because invalid or incomplete"
" message was received\", p_td.name);\n"
......
......@@ -795,15 +795,18 @@ void defEnumClass(const enum_def *edef, output_struct *output)
if (json_needed) {
// JSON encode
src = mputprintf(src,
"int %s::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok) const\n"
"int %s::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean) const\n"
"{\n"
" if (enum_value == %s) {\n"
" TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,\n"
" \"Encoding an unbound value of enumerated type %s.\");\n"
" return -1;\n"
" }\n\n"
" if (p_td.json->use_null) {\n"
" return p_tok.put_next_token(JSON_TOKEN_LITERAL_NULL);\n"
" }\n"
" char* tmp_str;\n"
" if (p_td.json->as_number) {"
" if (p_td.json->as_number) {\n"
" tmp_str = mprintf(\"%%d\", enum_value);\n"
" }\n"
" else {\n"
......@@ -828,7 +831,7 @@ void defEnumClass(const enum_def *edef, output_struct *output)
// JSON decode
src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, int)\n"
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n"
"{\n"
" json_token_t token = JSON_TOKEN_NONE;\n"
" char* value = 0;\n"
......@@ -847,7 +850,10 @@ void defEnumClass(const enum_def *edef, output_struct *output)
" JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, \"\");\n"
" return JSON_ERROR_FATAL;\n"
" }\n"
" else if ((JSON_TOKEN_STRING == token && !p_td.json->as_number) || use_default) {\n"
" else if (JSON_TOKEN_LITERAL_NULL == token && p_td.json->use_null) {\n"
" enum_value = %s;\n"
" }\n"
" else if (!p_td.json->use_null && ((JSON_TOKEN_STRING == token && !p_td.json->as_number) || use_default)) {\n"
" if (use_default || (value_len > 2 && value[0] == '\\\"' && value[value_len - 1] == '\\\"')) {\n"
" if (!use_default) value[value_len - 1] = 0;\n"
" boolean text_found = false;\n"
......@@ -869,7 +875,7 @@ void defEnumClass(const enum_def *edef, output_struct *output)
" error = TRUE;\n"
" }\n"
" }\n"
" else if (JSON_TOKEN_NUMBER == token && p_td.json->as_number) {\n"
" else if (!p_td.json->use_null && JSON_TOKEN_NUMBER == token && p_td.json->as_number) {\n"
" char* value_str = mcopystrn(value, value_len);\n"
" int number = atoi(value_str);\n"
" if (strchr(value_str, '.') != NULL || strchr(value_str, 'e') != NULL "
......@@ -896,7 +902,8 @@ void defEnumClass(const enum_def *edef, output_struct *output)
" }\n"
" return (int)dec_len;\n"
"}\n\n"
, name, enum_type, unknown_value, enum_type, unbound_value, unbound_value);
, name, edef->elements[0].name, enum_type, unknown_value, enum_type
, unbound_value, unbound_value);
}
if (oer_needed) {
......
......@@ -3236,7 +3236,7 @@ char* generate_json_decoder(char* src, const struct_def* sdef)
{
src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t&%s, JSON_Tokenizer& p_tok, "
"boolean p_silent, int)\n"
"boolean p_silent, boolean p_parent_is_map, int)\n"
"{\n", sdef->name,
((sdef->nElements == 1 && !sdef->jsonAsValue) || sdef->jsonAsMapPossible) ? " p_td" : "");
......@@ -3244,8 +3244,31 @@ char* generate_json_decoder(char* src, const struct_def* sdef)
if (!sdef->jsonAsValue) {
src = mputstr(src, " if (NULL != p_td.json && p_td.json->as_value) {\n");
}
src = mputprintf(src, " %sreturn field_%s.JSON_decode(%s_descr_, p_tok, p_silent);\n",
sdef->jsonAsValue ? "" : " ", sdef->elements[0].name, sdef->elements[0].typedescrname);
if (sdef->elements[0].isOptional) {
// can only happen if the record has the 'JSON:object' attribute;
// in this case the optional class must not be allowed to decode the
// JSON literal 'null', since it's not a JSON object;
// furthermore, the empty JSON object should be decoded as 'omit'
src = mputprintf(src,
" json_token_t j_token = JSON_TOKEN_NONE;\n"
" size_t buf_pos = p_tok.get_buf_pos();\n"
" size_t dec_len = p_tok.get_next_token(&j_token, NULL, NULL);\n"
" if (j_token == JSON_TOKEN_LITERAL_NULL) {\n"
" return JSON_ERROR_FATAL;\n"
" }\n"
" else if (j_token == JSON_TOKEN_OBJECT_START) {\n"
" dec_len += p_tok.get_next_token(&j_token, NULL, NULL);\n"
" if (j_token == JSON_TOKEN_OBJECT_END) {\n"
" field_%s = OMIT_VALUE;\n"
" return dec_len;\n"
" }\n"
" }\n"
// otherwise rewind the buffer and decode normally
" p_tok.set_buf_pos(buf_pos);\n",
sdef->elements[0].name);
}
src = mputprintf(src, " return field_%s.JSON_decode(%s_descr_, p_tok, p_silent, FALSE);\n",
sdef->elements[0].name, sdef->elements[0].typedescrname);
if (!sdef->jsonAsValue) {
src = mputstr(src, " }\n");
}
......@@ -3255,7 +3278,7 @@ char* generate_json_decoder(char* src, const struct_def* sdef)
}
if (sdef->jsonAsMapPossible) {
src = mputprintf(src,
" if (p_td.json->as_map) {\n"
" if (p_parent_is_map) {\n"
" char* fld_name = NULL;\n"
" size_t name_len = 0;\n"
" size_t buf_pos = p_tok.get_buf_pos();\n"
......@@ -3269,7 +3292,7 @@ char* generate_json_decoder(char* src, const struct_def* sdef)
" 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"
" return field_%s.JSON_decode(%s_descr_, p_tok, p_silent, FALSE) + dec_len;\n"
" }\n", sdef->elements[0].name,
sdef->elements[1].name, sdef->elements[1].typedescrname);
}
......@@ -3290,7 +3313,7 @@ char* generate_json_decoder(char* src, const struct_def* sdef)
// initialize fields with their default values (they will be overwritten
// later, if the JSON document contains data for these fields)
src = mputprintf(src,
" field_%s.JSON_decode(%s_descr_, DUMMY_BUFFER, p_silent);\n"
" field_%s.JSON_decode(%s_descr_, DUMMY_BUFFER, p_silent, FALSE);\n"
, sdef->elements[i].name, sdef->elements[i].typedescrname);
}
else {
......@@ -3419,7 +3442,7 @@ char* generate_json_decoder(char* src, const struct_def* sdef)
}
}
src = mputprintf(src,
" int ret_val = field_%s.JSON_decode(%s_descr_, p_tok, p_silent%s);\n"
" int ret_val = field_%s.JSON_decode(%s_descr_, p_tok, p_silent, FALSE%s);\n"
" if (0 > ret_val) {\n"
" if (JSON_ERROR_INVALID_TOKEN == ret_val) {\n"
, sdef->elements[i].name, sdef->elements[i].typedescrname
......@@ -4775,7 +4798,7 @@ void defRecordClass1(const struct_def *sdef, output_struct *output)
if (json_needed) {
// JSON encode, RT1
src = mputprintf(src,
"int %s::JSON_encode(const TTCN_Typedescriptor_t&%s, JSON_Tokenizer& p_tok) const\n"
"int %s::JSON_encode(const TTCN_Typedescriptor_t&%s, JSON_Tokenizer& p_tok, boolean p_parent_is_map) const\n"
"{\n"
" if (!is_bound()) {\n"
" TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,\n"
......@@ -4787,21 +4810,30 @@ void defRecordClass1(const struct_def *sdef, output_struct *output)
if (!sdef->jsonAsValue) {
src = mputstr(src, " if (NULL != p_td.json && p_td.json->as_value) {\n");
}
src = mputprintf(src, " %sreturn field_%s.JSON_encode(%s_descr_, p_tok);\n",
sdef->jsonAsValue ? "" : " ", sdef->elements[0].name, sdef->elements[0].typedescrname);
if (sdef->elements[0].isOptional) {
// can only happen if the record has the 'JSON:object' attribute;
// in this case 'omit' is the same as if the field was an empty record of
src = mputprintf(src,
" if (field_%s == OMIT_VALUE) {\n"
" return p_tok.put_next_token(JSON_TOKEN_OBJECT_START, NULL) + \n"
" p_tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL);\n"
" }\n", sdef->elements[0].name);
}
src = mputprintf(src, " return field_%s.JSON_encode(%s_descr_, p_tok, FALSE);\n",
sdef->elements[0].name, sdef->elements[0].typedescrname);
if (!sdef->jsonAsValue) {
src = mputstr(src, " }\n");
}
}
if (sdef->jsonAsMapPossible) {
src = mputprintf(src,
" if (p_td.json->as_map) {\n"
" if (p_parent_is_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"
" field_%s.JSON_encode(%s_descr_, p_tok, FALSE);\n"
" }\n", sdef->elements[0].name,
sdef->elements[1].name, sdef->elements[1].typedescrname);
}
......@@ -4830,7 +4862,7 @@ void defRecordClass1(const struct_def *sdef, output_struct *output)
, sdef->elements[i].jsonAlias ? sdef->elements[i].jsonAlias : sdef->elements[i].dispname);
}
src = mputprintf(src,
"enc_len += field_%s.JSON_encode(%s_descr_, p_tok);\n"
"enc_len += field_%s.JSON_encode(%s_descr_, p_tok, FALSE);\n"
" }\n\n"
, sdef->elements[i].name, sdef->elements[i].typedescrname);
}
......@@ -6818,7 +6850,7 @@ static void defEmptyRecordClass(const struct_def *sdef,
if (json_needed) {
// JSON encode, RT1
src = mputprintf(src,
"int %s::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const\n"
"int %s::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok, boolean) const\n"
"{\n"
" if (!is_bound()) {\n"
" TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,\n"
......@@ -6832,7 +6864,7 @@ static void defEmptyRecordClass(const struct_def *sdef,
// JSON decode, RT1
src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, int)\n"
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n"
"{\n"
" if (NULL != p_td.json->default_value && 0 == p_tok.get_buffer_length()) {\n"
// use the default value
......@@ -7814,7 +7846,7 @@ check_generate_end:
otherwise Record_Type::JSON_decode is enough */
def = mputprintf(def,
"int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, "
"boolean, int p_chosen_field = CHOSEN_FIELD_UNSET);\n");
"boolean, boolean, int p_chosen_field = CHOSEN_FIELD_UNSET);\n");
src = generate_json_decoder(src, sdef);
break;
}
......
......@@ -1538,7 +1538,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
if (json_needed) {
// JSON encode, RT1
src = mputprintf(src,
"int %s::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok) const\n"
"int %s::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean) const\n"
"{\n"
" if (!is_bound()) {\n"
" TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,\n"
......@@ -1556,7 +1556,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
" enc_len += p_tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL);\n"
" }\n"
" else {\n"
" int ret_val = (*this)[i].JSON_encode(*p_td.oftype_descr, p_tok);\n"
" int ret_val = (*this)[i].JSON_encode(*p_td.oftype_descr, p_tok, p_td.json->as_map);\n"
" if (0 > ret_val) break;\n"
" enc_len += ret_val;\n"
" }\n"
......@@ -1569,7 +1569,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
// JSON decode, RT1
src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, int)\n"
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n"
"{\n"
" if (NULL != p_td.json->default_value && 0 == p_tok.get_buffer_length()) {\n"
// use the default value (currently only the empty array can be set as
......@@ -1615,7 +1615,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
" p_tok.set_buf_pos(buf_pos);\n"
" }\n"
" %s* val = new %s;\n"
" int ret_val2 = val->JSON_decode(*p_td.oftype_descr, p_tok, p_silent);\n"
" int ret_val2 = val->JSON_decode(*p_td.oftype_descr, p_tok, p_silent, p_td.json->as_map);\n"
" if (JSON_ERROR_INVALID_TOKEN == ret_val2) {\n"
" p_tok.set_buf_pos(buf_pos);\n"
" delete val;\n"
......@@ -3058,7 +3058,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct
if (json_needed) {
// JSON encode, RT1, mem. alloc. optimised
src = mputprintf(src,
"int %s::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok) const\n"
"int %s::JSON_encode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean) const\n"
"{\n"
" if (!is_bound()) {\n"
" TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,\n"
......@@ -3075,7 +3075,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct
" enc_len += p_tok.put_next_token(JSON_TOKEN_OBJECT_END, NULL);\n"
" }\n"
" else {\n"
" int ret_val = value_elements[i].JSON_encode(*p_td.oftype_descr, p_tok);\n"
" int ret_val = value_elements[i].JSON_encode(*p_td.oftype_descr, p_tok, p_td.json->as_map);\n"
" if (0 > ret_val) break;\n"
" enc_len += ret_val;\n"
" }\n"
......@@ -3087,7 +3087,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct
// JSON decode, RT1, mem. alloc. optimised
src = mputprintf(src,
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, int)\n"
"int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n"
"{\n"
" json_token_t token = JSON_TOKEN_NONE;\n"
" size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);\n"
......@@ -3126,7 +3126,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct
" p_tok.set_buf_pos(buf_pos);\n"
" }\n"
" %s val;\n"
" int ret_val2 = val.JSON_decode(*p_td.oftype_descr, p_tok, p_silent);\n"
" int ret_val2 = val.JSON_decode(*p_td.oftype_descr, p_tok, p_silent, p_td.json->as_map);\n"
" if (JSON_ERROR_INVALID_TOKEN == ret_val2) {\n"
" p_tok.set_buf_pos(buf_pos);\n"
" break;\n"
......
......@@ -43,6 +43,9 @@ void JsonAST::init_JsonAST()
as_number = false;
tag_list = NULL;
as_map = false;
use_null = false;
type_indicator = JSON_NO_TYPE;
string_escaping = ESCAPING_UNSET;
}
JsonAST::JsonAST(const JsonAST *other_val)
......@@ -63,6 +66,9 @@ JsonAST::JsonAST(const JsonAST *other_val)
enum_texts.add(new JsonEnumText(mcopystr(other_val->enum_texts[i]->from),
mcopystr(other_val->enum_texts[i]->to)));
}
use_null = other_val->use_null;
type_indicator = other_val->type_indicator;
string_escaping = other_val->string_escaping;
}
}
......@@ -88,7 +94,63 @@ boolean JsonAST::empty() const
{
return omit_as_null == false && alias == NULL && as_value == false &&
default_value == NULL && metainfo_unbound == false && as_number == false &&
tag_list == NULL && as_map == false && enum_texts.size() == 0;
tag_list == NULL && as_map == false && enum_texts.size() == 0 &&
use_null == false && type_indicator != JSON_OBJECT &&
type_indicator != JSON_OBJECT_MEMBER && type_indicator != JSON_LITERAL &&
(string_escaping == ESCAPING_UNSET || string_escaping == ESCAPE_AS_SHORT);
}
const char* JsonAST::get_type_str() const
{
switch (type_indicator) {
case JSON_NO_TYPE:
return "<none>";
case JSON_NUMBER:
return "JSON:number";
case JSON_INTEGER:
return "JSON:integer";
case JSON_STRING:
return "JSON:string";
case JSON_ARRAY:
return "JSON:array";
case JSON_OBJECT:
return "JSON:object";
case JSON_OBJECT_MEMBER:
return "JSON:objectMember";
case JSON_LITERAL:
return "JSON:literal";
default:
FATAL_ERROR("JsonAST::get_type_str");
}
}
const char* JsonAST::get_escaping_str() const
{
switch (string_escaping) {
case ESCAPE_AS_SHORT:
return "escape as short";
case ESCAPE_AS_USI:
return "escape as usi";
case ESCAPE_AS_TRANSPARENT:
return "escape as transparent";
default:
FATAL_ERROR("JsonAST::get_escaping_str");
}
}
const char* JsonAST::get_escaping_gen_str() const
{
switch (string_escaping) {
case ESCAPING_UNSET:
case ESCAPE_AS_SHORT:
return "ESCAPE_AS_SHORT";
case ESCAPE_AS_USI:
return "ESCAPE_AS_USI";
case ESCAPE_AS_TRANSPARENT:
return "ESCAPE_AS_TRANSPARENT";
default:
FATAL_ERROR("JsonAST::get_escaping_gen_str");
}
}
void JsonAST::print_JsonAST() const
......@@ -141,6 +203,10 @@ void JsonAST::print_JsonAST() const
printf("\n\r");
}
}
printf("Type: %s\n\r", get_type_str());
if (string_escaping != ESCAPING_UNSET) {
printf("%s\n\r", get_escaping_str());
}
}
if (as_map) {
printf("Encoding elements into a map of key-value pairs.\n\r");
......
......@@ -38,29 +38,53 @@ struct JsonEnumText {
};
class JsonAST {
private:
void init_JsonAST();
JsonAST(const JsonAST&);
JsonAST& operator=(const JsonAST&);
public:
boolean omit_as_null;
char* alias;
boolean as_value;
char* default_value;
vector<JsonSchemaExtension> schema_extensions;
boolean metainfo_unbound;
boolean as_number;
rawAST_tag_list* tag_list;
boolean as_map;
vector<JsonEnumText> enum_texts;
JsonAST() { init_JsonAST(); }
JsonAST(const JsonAST *other_val);
~JsonAST();
boolean empty() const;
void print_JsonAST() const;
public:
enum json_type_indicator {
JSON_NO_TYPE,
JSON_NUMBER,
JSON_INTEGER,
JSON_STRING,
JSON_ARRAY,
JSON_OBJECT,
JSON_OBJECT_MEMBER,
JSON_LITERAL
};
enum json_string_escaping {
ESCAPING_UNSET, // no escaping attribute was set (equivalent with ESCAPE_AS_SHORT at runtime)
ESCAPE_AS_SHORT, // attribute "escape as short" was set explicitly
ESCAPE_AS_USI,
ESCAPE_AS_TRANSPARENT
};
private:
void init_JsonAST();
JsonAST(const JsonAST&);
JsonAST& operator=(const JsonAST&);
public:
boolean omit_as_null;
char* alias;
boolean as_value;
char* default_value;
vector<JsonSchemaExtension> schema_extensions;
boolean metainfo_unbound;