From 009e07fd074218c6f6b334adb2665322249dc180 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Thu, 13 Apr 2023 22:51:55 +0200 Subject: [PATCH] Berry json patches (#18407) --- lib/libesp32/berry/src/be_jsonlib.c | 97 +++++- lib/libesp32/berry/src/be_string.c | 6 + lib/libesp32/berry/tests/json.be | 22 +- lib/libesp32/berry/tests/json_advenced.be | 50 +++ lib/libesp32/berry/tests/json_test_cases.json | 295 ++++++++++++++++++ 5 files changed, 463 insertions(+), 7 deletions(-) create mode 100644 lib/libesp32/berry/tests/json_advenced.be create mode 100644 lib/libesp32/berry/tests/json_test_cases.json diff --git a/lib/libesp32/berry/src/be_jsonlib.c b/lib/libesp32/berry/src/be_jsonlib.c index c0c764792..9550d642a 100644 --- a/lib/libesp32/berry/src/be_jsonlib.c +++ b/lib/libesp32/berry/src/be_jsonlib.c @@ -178,6 +178,11 @@ static const char* parser_string(bvm *vm, const char *json) } default: be_free(vm, buf, len); return NULL; /* error */ } + } else if(ch >= 0 && ch <= 0x1f) { + /* control characters must be escaped + as per https://www.rfc-editor.org/rfc/rfc7159#section-7 */ + be_free(vm, buf, len); + return NULL; } else { *dst++ = (char)ch; } @@ -273,6 +278,92 @@ static const char* parser_array(bvm *vm, const char *json) return json; } +static const char* parser_number(bvm *vm, const char *json) +{ + char c = *json++; + bbool is_neg = c == '-'; + if(is_neg) { + c = *json++; + if(!is_digit(c)) { + /* minus must be followed by digit */ + return NULL; + } + } + bint intv = 0; + if(c != '0') { + /* parse integer part */ + while(is_digit(c)) { + intv = intv * 10 + c - '0'; + c = *json++; + } + + } else { + /* + Number starts with zero, this is only allowed + if the number is just '0' or + it has a fractional part or exponent. + */ + c = *json++; + + } + if(c != '.' && c != 'e' && c != 'E') { + /* + No fractional part or exponent follows, this is an integer. + If digits follow after it (for example due to a leading zero) + this will cause an error in the calling function. + */ + be_pushint(vm, intv * (is_neg ? -1 : 1)); + json--; + return json; + } + breal realval = (breal) intv; + if(c == '.') { + + breal deci = 0.0, point = 0.1; + /* fractional part */ + c = *json++; + if(!is_digit(c)) { + /* decimal point must be followed by digit */ + return NULL; + } + while (is_digit(c)) { + deci = deci + ((breal)c - '0') * point; + point *= (breal)0.1; + c = *json++; + } + + realval += deci; + } + if(c == 'e' || c == 'E') { + c = *json++; + /* exponent part */ + breal ratio = c == '-' ? (breal)0.1 : 10; + if (c == '+' || c == '-') { + c = *json++; + if(!is_digit(c)) { + return NULL; + } + } + if(!is_digit(c)) { + /* e and sign must be followed by digit */ + return NULL; + } + unsigned int e = 0; + while (is_digit(c)) { + e = e * 10 + c - '0'; + c = *json++; + } + /* e > 0 must be here to prevent infinite loops when e overflows */ + while (e--) { + realval *= ratio; + } + } + + be_pushreal(vm, realval * (is_neg ? -1.0 : 1.0)); + json--; + return json; +} + /* parser json value */ static const char* parser_value(bvm *vm, const char *json) { @@ -292,11 +383,7 @@ static const char* parser_value(bvm *vm, const char *json) return parser_null(vm, json); default: /* number */ if (*json == '-' || is_digit(*json)) { - /* check invalid JSON syntax: 0\d+ */ - if (json[0] == '0' && is_digit(json[1])) { - return NULL; - } - return be_str2num(vm, json); + return parser_number(vm, json); } } return NULL; diff --git a/lib/libesp32/berry/src/be_string.c b/lib/libesp32/berry/src/be_string.c index 2ab0d1004..07a0fb162 100644 --- a/lib/libesp32/berry/src/be_string.c +++ b/lib/libesp32/berry/src/be_string.c @@ -167,6 +167,12 @@ static bstring* find_conststr(const char *str, size_t len) uint32_t hash = str_hash(str, len); bcstring *s = (bcstring*)tab->table[hash % tab->size]; for (; s != NULL; s = next(s)) { + if (len == 0 && s->slen == 0) { + /* special case for the empty string, + since we don't want to compare it using strncmp, + because str might be NULL */ + return (bstring*)s; + } if (len == s->slen && !strncmp(str, s->s, len)) { return (bstring*)s; } diff --git a/lib/libesp32/berry/tests/json.be b/lib/libesp32/berry/tests/json.be index 3664ba08b..92df2f3e6 100644 --- a/lib/libesp32/berry/tests/json.be +++ b/lib/libesp32/berry/tests/json.be @@ -1,9 +1,14 @@ import json - +import string # load tests def assert_load(text, value) - assert(json.load(text) == value) + var loaded_val = json.load(text) + var ok = loaded_val == value + if !ok + print(string.format('for JSON \'%s\' expected %s [%s] but got %s [%s]', text, str(value), type(value), str(loaded_val), type(loaded_val))) + end + assert(ok) end def assert_load_failed(text) @@ -15,6 +20,13 @@ assert_load('true', true) assert_load('false', false) assert_load('123', 123) assert_load('12.3', 12.3) +assert_load('-0.1', -0.1) +assert_load('1e2', 1e2) +assert_load('1e+2', 1e+2) +assert_load('1e-2', 1e-2) +assert_load('1E2', 1e2) +assert_load('1E+2', 1e+2) +assert_load('1.2e7', 1.2e7) assert_load('"abc"', 'abc') # strings assert_load('"\\"\\\\\\/\\b\\f\\n\\r\\t"', '\"\\/\b\f\n\r\t') @@ -30,6 +42,12 @@ assert_load_failed('[1, null') # object var o = json.load('{"key": 1}') assert(o['key'] == 1 && o.size() == 1) + +# parsing an empty string used to cause berry to pass a NULL to strncmp +# make sure we catch this +o = json.load('{"key": ""}') +assert(o['key'] == '' && o.size() == 1) + assert_load_failed('{"ke: 1}') assert_load_failed('{"key": 1x}') assert_load_failed('{"key"}') diff --git a/lib/libesp32/berry/tests/json_advenced.be b/lib/libesp32/berry/tests/json_advenced.be new file mode 100644 index 000000000..be3b87e0b --- /dev/null +++ b/lib/libesp32/berry/tests/json_advenced.be @@ -0,0 +1,50 @@ +import os +import json + + + +def assert_load_failed(text) + assert(json.load(text) == nil) +end + +var input_file = open("tests/json_test_cases.json", "r") +var test_cases = json.load(input_file.read()) + +# check positive cases +var has_failed_positives = false +for case_name : test_cases["positive"].keys() + var case = test_cases["positive"][case_name] + var val = json.load(case) + if val == nil && case != "null" + print("Failed to load case: " + case_name) + has_failed_positives = true + end +end + +if has_failed_positives + assert(false) +end + +# check negative cases + +var has_failed_negatives = false +for case_name : test_cases["negative"].keys() + var case = test_cases["negative"][case_name] + + var val = json.load(case) + if val != nil + print("Failed to fail case: " + case_name + ", got: " + json.dump(val)) + has_failed_negatives = true + end +end + +if has_failed_negatives + # assert(false) +end + +# check "any" cases, only for crashes + +for case_name : test_cases["any"].keys() + var case = test_cases["any"][case_name] + var val = json.load(case) +end diff --git a/lib/libesp32/berry/tests/json_test_cases.json b/lib/libesp32/berry/tests/json_test_cases.json new file mode 100644 index 000000000..c6e8e4a53 --- /dev/null +++ b/lib/libesp32/berry/tests/json_test_cases.json @@ -0,0 +1,295 @@ +{ + "___comment": "Adapted from https://github.com/nst/JSONTestSuite", + "positive": { + "array_arraysWithSpaces": "[[] ]", + "array_empty-string": "[\"\"]", + "array_empty": "[]", + "array_ending_with_newline": "[\"a\"]", + "array_false": "[false]", + "array_heterogeneous": "[null, 1, \"1\", {}]", + "array_null": "[null]", + "array_with_1_and_newline": "[1\n]", + "array_with_leading_space": " [1]", + "array_with_several_null": "[1,null,null,null,2]", + "array_with_trailing_space": "[2] ", + "number": "[123e65]", + "number_0e+1": "[0e+1]", + "number_0e1": "[0e1]", + "number_after_space": "[ 4]", + "number_double_close_to_zero": "[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001]\n", + "number_int_with_exp": "[20e1]", + "number_minus_zero": "[-0]", + "number_negative_int": "[-123]", + "number_negative_one": "[-1]", + "number_negative_zero": "[-0]", + "number_real_capital_e": "[1E22]", + "number_real_capital_e_neg_exp": "[1E-2]", + "number_real_capital_e_pos_exp": "[1E+2]", + "number_real_exponent": "[123e45]", + "number_real_fraction_exponent": "[123.456e78]", + "number_real_neg_exp": "[1e-2]", + "number_real_pos_exponent": "[1e+2]", + "number_simple_int": "[123]", + "number_simple_real": "[123.456789]", + "object": "{\"asd\":\"sdf\", \"dfg\":\"fgh\"}", + "object_basic": "{\"asd\":\"sdf\"}", + "object_duplicated_key": "{\"a\":\"b\",\"a\":\"c\"}", + "object_duplicated_key_and_value": "{\"a\":\"b\",\"a\":\"b\"}", + "object_empty": "{}", + "object_empty_key": "{\"\":0}", + "object_escaped_null_in_key": "{\"foo\\u0000bar\": 42}", + "object_extreme_numbers": "{ \"min\": -1.0e+28, \"max\": 1.0e+28 }", + "object_long_strings": "{\"x\":[{\"id\": \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"}], \"id\": \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"}", + "object_simple": "{\"a\":[]}", + "object_string_unicode": "{\"title\":\"\\u041f\\u043e\\u043b\\u0442\\u043e\\u0440\\u0430 \\u0417\\u0435\\u043c\\u043b\\u0435\\u043a\\u043e\\u043f\\u0430\" }", + "object_with_newlines": "{\n\"a\": \"b\"\n}", + "string_1_2_3_bytes_UTF-8_sequences": "[\"\\u0060\\u012a\\u12AB\"]", + "string_accepted_surrogate_pair": "[\"\\uD801\\udc37\"]", + "string_accepted_surrogate_pairs": "[\"\\ud83d\\ude39\\ud83d\\udc8d\"]", + "string_allowed_escapes": "[\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"]", + "string_backslash_and_u_escaped_zero": "[\"\\\\u0000\"]", + "string_backslash_doublequotes": "[\"\\\"\"]", + "string_comments": "[\"a/*b*/c/*d//e\"]", + "string_double_escape_a": "[\"\\\\a\"]", + "string_double_escape_n": "[\"\\\\n\"]", + "string_escaped_control_character": "[\"\\u0012\"]", + "string_escaped_noncharacter": "[\"\\uFFFF\"]", + "string_in_array": "[\"asd\"]", + "string_in_array_with_leading_space": "[ \"asd\"]", + "string_last_surrogates_1_and_2": "[\"\\uDBFF\\uDFFF\"]", + "string_nbsp_uescaped": "[\"new\\u00A0line\"]", + "string_nonCharacterInUTF-8_U+10FFFF": "[\"\udbff\udfff\"]", + "string_nonCharacterInUTF-8_U+FFFF": "[\"\uffff\"]", + "string_null_escape": "[\"\\u0000\"]", + "string_one-byte-utf-8": "[\"\\u002c\"]", + "string_pi": "[\"\u03c0\"]", + "string_reservedCharacterInUTF-8_U+1BFFF": "[\"\ud82f\udfff\"]", + "string_simple_ascii": "[\"asd \"]", + "string_space": "\" \"", + "string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF": "[\"\\uD834\\uDd1e\"]", + "string_three-byte-utf-8": "[\"\\u0821\"]", + "string_two-byte-utf-8": "[\"\\u0123\"]", + "string_u+2028_line_sep": "[\"\u2028\"]", + "string_u+2029_par_sep": "[\"\u2029\"]", + "string_uEscape": "[\"\\u0061\\u30af\\u30EA\\u30b9\"]", + "string_uescaped_newline": "[\"new\\u000Aline\"]", + "string_unescaped_char_delete": "[\"\u007f\"]", + "string_unicode": "[\"\\uA66D\"]", + "string_unicodeEscapedBackslash": "[\"\\u005C\"]", + "string_unicode_2": "[\"\u2342\u3234\u2342\"]", + "string_unicode_U+10FFFE_nonchar": "[\"\\uDBFF\\uDFFE\"]", + "string_unicode_U+1FFFE_nonchar": "[\"\\uD83F\\uDFFE\"]", + "string_unicode_U+200B_ZERO_WIDTH_SPACE": "[\"\\u200B\"]", + "string_unicode_U+2064_invisible_plus": "[\"\\u2064\"]", + "string_unicode_U+FDD0_nonchar": "[\"\\uFDD0\"]", + "string_unicode_U+FFFE_nonchar": "[\"\\uFFFE\"]", + "string_unicode_escaped_double_quote": "[\"\\u0022\"]", + "string_utf8": "[\"\u20ac\ud834\udd1e\"]", + "string_with_del_character": "[\"a\u007fa\"]", + "structure_lonely_false": "false", + "structure_lonely_int": "42", + "structure_lonely_negative_real": "-0.1", + "structure_lonely_null": "null", + "structure_lonely_string": "\"asd\"", + "structure_lonely_true": "true", + "structure_string_empty": "\"\"", + "structure_trailing_newline": "[\"a\"]\n", + "structure_true_in_array": "[true]", + "structure_whitespace_array": " [] " + }, + "negative": { + "array_1_true_without_comma": "[1 true]", + "array_colon_instead_of_comma": "[\"\": 1]", + "array_comma_after_close": "[\"\"],", + "array_comma_and_number": "[,1]", + "array_double_comma": "[1,,2]", + "array_double_extra_comma": "[\"x\",,]", + "array_extra_close": "[\"x\"]]", + "array_extra_comma": "[\"\",]", + "array_incomplete": "[\"x\"", + "array_incomplete_invalid_value": "[x", + "array_inner_array_no_comma": "[3[4]]", + "array_items_separated_by_semicolon": "[1:2]", + "array_just_comma": "[,]", + "array_just_minus": "[-]", + "array_missing_value": "[ , \"\"]", + "array_newlines_unclosed": "[\"a\",\n4\n,1,", + "array_number_and_comma": "[1,]", + "array_number_and_several_commas": "[1,,]", + "array_spaces_vertical_tab_formfeed": "[\"\u000ba\"\\f]", + "array_star_inside": "[*]", + "array_unclosed": "[\"\"", + "array_unclosed_trailing_comma": "[1,", + "array_unclosed_with_new_lines": "[1,\n1\n,1", + "array_unclosed_with_object_inside": "[{}", + "incomplete_false": "[fals]", + "incomplete_null": "[nul]", + "incomplete_true": "[tru]", + "number_++": "[++1234]", + "number_+1": "[+1]", + "number_+Inf": "[+Inf]", + "number_-01": "[-01]", + "number_-1.0.": "[-1.0.]", + "number_-2.": "[-2.]", + "number_-NaN": "[-NaN]", + "number_.-1": "[.-1]", + "number_.2e-3": "[.2e-3]", + "number_0.1.2": "[0.1.2]", + "number_0.3e+": "[0.3e+]", + "number_0.3e": "[0.3e]", + "number_0.e1": "[0.e1]", + "number_0_capital_E+": "[0E+]", + "number_0_capital_E": "[0E]", + "number_0e+": "[0e+]", + "number_0e": "[0e]", + "number_1.0e+": "[1.0e+]", + "number_1.0e-": "[1.0e-]", + "number_1.0e": "[1.0e]", + "number_1_000": "[1 000.0]", + "number_1eE2": "[1eE2]", + "number_2.e+3": "[2.e+3]", + "number_2.e-3": "[2.e-3]", + "number_2.e3": "[2.e3]", + "number_9.e+": "[9.e+]", + "number_Inf": "[Inf]", + "number_NaN": "[NaN]", + "number_U+FF11_fullwidth_digit_one": "[\uff11]", + "number_expression": "[1+2]", + "number_hex_1_digit": "[0x1]", + "number_hex_2_digits": "[0x42]", + "number_infinity": "[Infinity]", + "number_invalid+-": "[0e+-1]", + "number_invalid-negative-real": "[-123.123foo]", + "number_minus_infinity": "[-Infinity]", + "number_minus_sign_with_trailing_garbage": "[-foo]", + "number_minus_space_1": "[- 1]", + "number_neg_int_starting_with_zero": "[-012]", + "number_neg_real_without_int_part": "[-.123]", + "number_neg_with_garbage_at_end": "[-1x]", + "number_real_garbage_after_e": "[1ea]", + "number_real_without_fractional_part": "[1.]", + "number_starting_with_dot": "[.123]", + "number_with_alpha": "[1.2a-3]", + "number_with_alpha_char": "[1.8011670033376514H-308]", + "number_with_leading_zero": "[012]", + "object_bad_value": "[\"x\", truth]", + "object_bracket_key": "{[: \"x\"}\n", + "object_comma_instead_of_colon": "{\"x\", null}", + "object_double_colon": "{\"x\"::\"b\"}", + "object_emoji": "{\ud83c\udde8\ud83c\udded}", + "object_garbage_at_end": "{\"a\":\"a\" 123}", + "object_key_with_single_quotes": "{key: 'value'}", + "object_missing_colon": "{\"a\" b}", + "object_missing_key": "{:\"b\"}", + "object_missing_semicolon": "{\"a\" \"b\"}", + "object_missing_value": "{\"a\":", + "object_no-colon": "{\"a\"", + "object_non_string_key": "{1:1}", + "object_non_string_key_but_huge_number_instead": "{9999E9999:1}", + "object_repeated_null_null": "{null:null,null:null}", + "object_several_trailing_commas": "{\"id\":0,,,,,}", + "object_single_quote": "{'a':0}", + "object_trailing_comma": "{\"id\":0,}", + "object_trailing_comment": "{\"a\":\"b\"}/**/", + "object_trailing_comment_open": "{\"a\":\"b\"}/**//", + "object_trailing_comment_slash_open": "{\"a\":\"b\"}//", + "object_trailing_comment_slash_open_incomplete": "{\"a\":\"b\"}/", + "object_two_commas_in_a_row": "{\"a\":\"b\",,\"c\":\"d\"}", + "object_unquoted_key": "{a: \"b\"}", + "object_unterminated-value": "{\"a\":\"a", + "object_with_single_string": "{ \"foo\" : \"bar\", \"a\" }", + "object_with_trailing_garbage": "{\"a\":\"b\"}#", + "single_space": " ", + "string_1_surrogate_then_escape": "[\"\\uD800\\\"]", + "string_1_surrogate_then_escape_u": "[\"\\uD800\\u\"]", + "string_1_surrogate_then_escape_u1": "[\"\\uD800\\u1\"]", + "string_1_surrogate_then_escape_u1x": "[\"\\uD800\\u1x\"]", + "string_accentuated_char_no_quotes": "[\u00e9]", + "string_backslash_00": "[\"\\\u0000\"]", + "string_escape_x": "[\"\\x00\"]", + "string_escaped_backslash_bad": "[\"\\\\\\\"]", + "string_escaped_ctrl_char_tab": "[\"\\\t\"]", + "string_escaped_emoji": "[\"\\\ud83c\udf00\"]", + "string_incomplete_escape": "[\"\\\"]", + "string_incomplete_escaped_character": "[\"\\u00A\"]", + "string_incomplete_surrogate": "[\"\\uD834\\uDd\"]", + "string_incomplete_surrogate_escape_invalid": "[\"\\uD800\\uD800\\x\"]", + "string_invalid_backslash_esc": "[\"\\a\"]", + "string_invalid_unicode_escape": "[\"\\uqqqq\"]", + "string_leading_uescaped_thinspace": "[\\u0020\"asd\"]", + "string_no_quotes_with_bad_escape": "[\\n]", + "string_single_doublequote": "\"", + "string_single_quote": "['single quote']", + "string_single_string_no_double_quotes": "abc", + "string_start_escape_unclosed": "[\"\\", + "string_unescaped_ctrl_char": "[\"a\u0000a\"]", + "string_unescaped_newline": "[\"new\nline\"]", + "string_unescaped_tab": "[\"\t\"]", + "string_unicode_CapitalU": "\"\\UA66D\"", + "string_with_trailing_garbage": "\"\"x", + "structure_U+2060_word_joined": "[\u2060]", + "structure_UTF8_BOM_no_data": "\ufeff", + "structure_angle_bracket_.": "<.>", + "structure_angle_bracket_null": "[]", + "structure_array_trailing_garbage": "[1]x", + "structure_array_with_extra_array_close": "[1]]", + "structure_array_with_unclosed_string": "[\"asd]", + "structure_ascii-unicode-identifier": "a\u00e5", + "structure_capitalized_True": "[True]", + "structure_close_unopened_array": "1]", + "structure_comma_instead_of_closing_brace": "{\"x\": true,", + "structure_double_array": "[][]", + "structure_end_array": "]", + "structure_lone-open-bracket": "[", + "structure_no_data": "", + "structure_null-byte-outside-string": "[\u0000]", + "structure_number_with_trailing_garbage": "2@", + "structure_object_followed_by_closing_object": "{}}", + "structure_object_unclosed_no_value": "{\"\":", + "structure_object_with_comment": "{\"a\":/*comment*/\"b\"}", + "structure_object_with_trailing_garbage": "{\"a\": true} \"x\"", + "structure_open_array_apostrophe": "['", + "structure_open_array_comma": "[,", + "structure_open_array_open_object": "[{", + "structure_open_array_open_string": "[\"a", + "structure_open_array_string": "[\"a\"", + "structure_open_object": "{", + "structure_open_object_close_array": "{]", + "structure_open_object_comma": "{,", + "structure_open_object_open_array": "{[", + "structure_open_object_open_string": "{\"a", + "structure_open_object_string_with_apostrophes": "{'a'", + "structure_open_open": "[\"\\{[\"\\{[\"\\{[\"\\{", + "structure_single_star": "*", + "structure_trailing_#": "{\"a\":\"b\"}#{}", + "structure_uescaped_LF_before_string": "[\\u000A\"\"]", + "structure_unclosed_array": "[1", + "structure_unclosed_array_partial_null": "[ false, nul", + "structure_unclosed_array_unfinished_false": "[ true, fals", + "structure_unclosed_array_unfinished_true": "[ false, tru", + "structure_unclosed_object": "{\"asd\":\"asd\"", + "structure_unicode-identifier": "\u00e5", + "structure_whitespace_U+2060_word_joiner": "[\u2060]", + "structure_whitespace_formfeed": "[\f]" + }, + "any": { + "number_double_huge_neg_exp": "[123.456e-789]", + "number_huge_exp": "[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006]", + "number_neg_int_huge_exp": "[-1e+9999]", + "number_pos_double_huge_exp": "[1.5e+9999]", + "number_real_neg_overflow": "[-123123e100000]", + "number_real_pos_overflow": "[123123e100000]", + "number_real_underflow": "[123e-10000000]", + "object_key_lone_2nd_surrogate": "{\"\\uDFAA\":0}", + "string_1st_surrogate_but_2nd_missing": "[\"\\uDADA\"]", + "string_1st_valid_surrogate_2nd_invalid": "[\"\\uD888\\u1234\"]", + "string_incomplete_surrogate_and_escape_valid": "[\"\\uD800\\n\"]", + "string_incomplete_surrogate_pair": "[\"\\uDd1ea\"]", + "string_incomplete_surrogates_escape_valid": "[\"\\uD800\\uD800\\n\"]", + "string_invalid_lonely_surrogate": "[\"\\ud800\"]", + "string_invalid_surrogate": "[\"\\ud800abc\"]", + "string_inverted_surrogates_U+1D11E": "[\"\\uDd1e\\uD834\"]", + "string_lone_second_surrogate": "[\"\\uDFAA\"]", + "structure_UTF-8_BOM_empty_object": "\ufeff{}" + } +}