mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-10-06 11:09:37 +00:00
Merge remote branch 'qmp/for-anthony' into staging
This commit is contained in:
commit
a2da0395c1
112
check-qjson.c
112
check-qjson.c
|
@ -28,6 +28,13 @@ START_TEST(escaped_string)
|
||||||
const char *decoded;
|
const char *decoded;
|
||||||
int skip;
|
int skip;
|
||||||
} test_cases[] = {
|
} test_cases[] = {
|
||||||
|
{ "\"\\b\"", "\b" },
|
||||||
|
{ "\"\\f\"", "\f" },
|
||||||
|
{ "\"\\n\"", "\n" },
|
||||||
|
{ "\"\\r\"", "\r" },
|
||||||
|
{ "\"\\t\"", "\t" },
|
||||||
|
{ "\"\\/\"", "\\/" },
|
||||||
|
{ "\"\\\\\"", "\\" },
|
||||||
{ "\"\\\"\"", "\"" },
|
{ "\"\\\"\"", "\"" },
|
||||||
{ "\"hello world \\\"embedded string\\\"\"",
|
{ "\"hello world \\\"embedded string\\\"\"",
|
||||||
"hello world \"embedded string\"" },
|
"hello world \"embedded string\"" },
|
||||||
|
@ -48,11 +55,14 @@ START_TEST(escaped_string)
|
||||||
fail_unless(qobject_type(obj) == QTYPE_QSTRING);
|
fail_unless(qobject_type(obj) == QTYPE_QSTRING);
|
||||||
|
|
||||||
str = qobject_to_qstring(obj);
|
str = qobject_to_qstring(obj);
|
||||||
fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
|
fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0,
|
||||||
|
"%s != %s\n", qstring_get_str(str), test_cases[i].decoded);
|
||||||
|
|
||||||
if (test_cases[i].skip == 0) {
|
if (test_cases[i].skip == 0) {
|
||||||
str = qobject_to_json(obj);
|
str = qobject_to_json(obj);
|
||||||
fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
|
fail_unless(strcmp(qstring_get_str(str),test_cases[i].encoded) == 0,
|
||||||
|
"%s != %s\n", qstring_get_str(str),
|
||||||
|
test_cases[i].encoded);
|
||||||
|
|
||||||
qobject_decref(obj);
|
qobject_decref(obj);
|
||||||
}
|
}
|
||||||
|
@ -627,11 +637,90 @@ START_TEST(simple_varargs)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(empty_input)
|
||||||
|
{
|
||||||
|
QObject *obj = qobject_from_json("");
|
||||||
|
fail_unless(obj == NULL);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(unterminated_string)
|
||||||
|
{
|
||||||
|
QObject *obj = qobject_from_json("\"abc");
|
||||||
|
fail_unless(obj == NULL);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(unterminated_sq_string)
|
||||||
|
{
|
||||||
|
QObject *obj = qobject_from_json("'abc");
|
||||||
|
fail_unless(obj == NULL);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(unterminated_escape)
|
||||||
|
{
|
||||||
|
QObject *obj = qobject_from_json("\"abc\\\"");
|
||||||
|
fail_unless(obj == NULL);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(unterminated_array)
|
||||||
|
{
|
||||||
|
QObject *obj = qobject_from_json("[32");
|
||||||
|
fail_unless(obj == NULL);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(unterminated_array_comma)
|
||||||
|
{
|
||||||
|
QObject *obj = qobject_from_json("[32,");
|
||||||
|
fail_unless(obj == NULL);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(invalid_array_comma)
|
||||||
|
{
|
||||||
|
QObject *obj = qobject_from_json("[32,}");
|
||||||
|
fail_unless(obj == NULL);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(unterminated_dict)
|
||||||
|
{
|
||||||
|
QObject *obj = qobject_from_json("{'abc':32");
|
||||||
|
fail_unless(obj == NULL);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(unterminated_dict_comma)
|
||||||
|
{
|
||||||
|
QObject *obj = qobject_from_json("{'abc':32,");
|
||||||
|
fail_unless(obj == NULL);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
START_TEST(invalid_dict_comma)
|
||||||
|
{
|
||||||
|
QObject *obj = qobject_from_json("{'abc':32,}");
|
||||||
|
fail_unless(obj == NULL);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(unterminated_literal)
|
||||||
|
{
|
||||||
|
QObject *obj = qobject_from_json("nul");
|
||||||
|
fail_unless(obj == NULL);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
#endif
|
||||||
|
|
||||||
static Suite *qjson_suite(void)
|
static Suite *qjson_suite(void)
|
||||||
{
|
{
|
||||||
Suite *suite;
|
Suite *suite;
|
||||||
TCase *string_literals, *number_literals, *keyword_literals;
|
TCase *string_literals, *number_literals, *keyword_literals;
|
||||||
TCase *dicts, *lists, *whitespace, *varargs;
|
TCase *dicts, *lists, *whitespace, *varargs, *errors;
|
||||||
|
|
||||||
string_literals = tcase_create("String Literals");
|
string_literals = tcase_create("String Literals");
|
||||||
tcase_add_test(string_literals, simple_string);
|
tcase_add_test(string_literals, simple_string);
|
||||||
|
@ -657,6 +746,22 @@ static Suite *qjson_suite(void)
|
||||||
varargs = tcase_create("Varargs");
|
varargs = tcase_create("Varargs");
|
||||||
tcase_add_test(varargs, simple_varargs);
|
tcase_add_test(varargs, simple_varargs);
|
||||||
|
|
||||||
|
errors = tcase_create("Invalid JSON");
|
||||||
|
tcase_add_test(errors, empty_input);
|
||||||
|
tcase_add_test(errors, unterminated_string);
|
||||||
|
tcase_add_test(errors, unterminated_escape);
|
||||||
|
tcase_add_test(errors, unterminated_sq_string);
|
||||||
|
tcase_add_test(errors, unterminated_array);
|
||||||
|
tcase_add_test(errors, unterminated_array_comma);
|
||||||
|
tcase_add_test(errors, invalid_array_comma);
|
||||||
|
tcase_add_test(errors, unterminated_dict);
|
||||||
|
tcase_add_test(errors, unterminated_dict_comma);
|
||||||
|
#if 0
|
||||||
|
/* FIXME: this print parse error messages on stderr. */
|
||||||
|
tcase_add_test(errors, invalid_dict_comma);
|
||||||
|
tcase_add_test(errors, unterminated_literal);
|
||||||
|
#endif
|
||||||
|
|
||||||
suite = suite_create("QJSON test-suite");
|
suite = suite_create("QJSON test-suite");
|
||||||
suite_add_tcase(suite, string_literals);
|
suite_add_tcase(suite, string_literals);
|
||||||
suite_add_tcase(suite, number_literals);
|
suite_add_tcase(suite, number_literals);
|
||||||
|
@ -665,6 +770,7 @@ static Suite *qjson_suite(void)
|
||||||
suite_add_tcase(suite, lists);
|
suite_add_tcase(suite, lists);
|
||||||
suite_add_tcase(suite, whitespace);
|
suite_add_tcase(suite, whitespace);
|
||||||
suite_add_tcase(suite, varargs);
|
suite_add_tcase(suite, varargs);
|
||||||
|
suite_add_tcase(suite, errors);
|
||||||
|
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
2
hxtool
2
hxtool
|
@ -59,6 +59,7 @@ hxtoqmp()
|
||||||
{
|
{
|
||||||
IFS=
|
IFS=
|
||||||
flag=0
|
flag=0
|
||||||
|
line=1
|
||||||
while read -r str; do
|
while read -r str; do
|
||||||
case "$str" in
|
case "$str" in
|
||||||
HXCOMM*)
|
HXCOMM*)
|
||||||
|
@ -87,6 +88,7 @@ hxtoqmp()
|
||||||
test $flag -eq 1 && echo "$str"
|
test $flag -eq 1 && echo "$str"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
line=$((line+1))
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
114
json-lexer.c
114
json-lexer.c
|
@ -29,7 +29,6 @@
|
||||||
|
|
||||||
enum json_lexer_state {
|
enum json_lexer_state {
|
||||||
ERROR = 0,
|
ERROR = 0,
|
||||||
IN_DONE_STRING,
|
|
||||||
IN_DQ_UCODE3,
|
IN_DQ_UCODE3,
|
||||||
IN_DQ_UCODE2,
|
IN_DQ_UCODE2,
|
||||||
IN_DQ_UCODE1,
|
IN_DQ_UCODE1,
|
||||||
|
@ -57,19 +56,19 @@ enum json_lexer_state {
|
||||||
IN_ESCAPE_I,
|
IN_ESCAPE_I,
|
||||||
IN_ESCAPE_I6,
|
IN_ESCAPE_I6,
|
||||||
IN_ESCAPE_I64,
|
IN_ESCAPE_I64,
|
||||||
IN_ESCAPE_DONE,
|
|
||||||
IN_WHITESPACE,
|
IN_WHITESPACE,
|
||||||
IN_OPERATOR_DONE,
|
|
||||||
IN_START,
|
IN_START,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TERMINAL(state) [0 ... 0x7F] = (state)
|
#define TERMINAL(state) [0 ... 0x7F] = (state)
|
||||||
|
|
||||||
static const uint8_t json_lexer[][256] = {
|
/* Return whether TERMINAL is a terminal state and the transition to it
|
||||||
[IN_DONE_STRING] = {
|
from OLD_STATE required lookahead. This happens whenever the table
|
||||||
TERMINAL(JSON_STRING),
|
below uses the TERMINAL macro. */
|
||||||
},
|
#define TERMINAL_NEEDED_LOOKAHEAD(old_state, terminal) \
|
||||||
|
(json_lexer[(old_state)][0] == (terminal))
|
||||||
|
|
||||||
|
static const uint8_t json_lexer[][256] = {
|
||||||
/* double quote string */
|
/* double quote string */
|
||||||
[IN_DQ_UCODE3] = {
|
[IN_DQ_UCODE3] = {
|
||||||
['0' ... '9'] = IN_DQ_STRING,
|
['0' ... '9'] = IN_DQ_STRING,
|
||||||
|
@ -97,6 +96,8 @@ static const uint8_t json_lexer[][256] = {
|
||||||
['n'] = IN_DQ_STRING,
|
['n'] = IN_DQ_STRING,
|
||||||
['r'] = IN_DQ_STRING,
|
['r'] = IN_DQ_STRING,
|
||||||
['t'] = IN_DQ_STRING,
|
['t'] = IN_DQ_STRING,
|
||||||
|
['/'] = IN_DQ_STRING,
|
||||||
|
['\\'] = IN_DQ_STRING,
|
||||||
['\''] = IN_DQ_STRING,
|
['\''] = IN_DQ_STRING,
|
||||||
['\"'] = IN_DQ_STRING,
|
['\"'] = IN_DQ_STRING,
|
||||||
['u'] = IN_DQ_UCODE0,
|
['u'] = IN_DQ_UCODE0,
|
||||||
|
@ -104,7 +105,7 @@ static const uint8_t json_lexer[][256] = {
|
||||||
[IN_DQ_STRING] = {
|
[IN_DQ_STRING] = {
|
||||||
[1 ... 0xFF] = IN_DQ_STRING,
|
[1 ... 0xFF] = IN_DQ_STRING,
|
||||||
['\\'] = IN_DQ_STRING_ESCAPE,
|
['\\'] = IN_DQ_STRING_ESCAPE,
|
||||||
['"'] = IN_DONE_STRING,
|
['"'] = JSON_STRING,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* single quote string */
|
/* single quote string */
|
||||||
|
@ -134,6 +135,8 @@ static const uint8_t json_lexer[][256] = {
|
||||||
['n'] = IN_SQ_STRING,
|
['n'] = IN_SQ_STRING,
|
||||||
['r'] = IN_SQ_STRING,
|
['r'] = IN_SQ_STRING,
|
||||||
['t'] = IN_SQ_STRING,
|
['t'] = IN_SQ_STRING,
|
||||||
|
['/'] = IN_DQ_STRING,
|
||||||
|
['\\'] = IN_DQ_STRING,
|
||||||
['\''] = IN_SQ_STRING,
|
['\''] = IN_SQ_STRING,
|
||||||
['\"'] = IN_SQ_STRING,
|
['\"'] = IN_SQ_STRING,
|
||||||
['u'] = IN_SQ_UCODE0,
|
['u'] = IN_SQ_UCODE0,
|
||||||
|
@ -141,7 +144,7 @@ static const uint8_t json_lexer[][256] = {
|
||||||
[IN_SQ_STRING] = {
|
[IN_SQ_STRING] = {
|
||||||
[1 ... 0xFF] = IN_SQ_STRING,
|
[1 ... 0xFF] = IN_SQ_STRING,
|
||||||
['\\'] = IN_SQ_STRING_ESCAPE,
|
['\\'] = IN_SQ_STRING_ESCAPE,
|
||||||
['\''] = IN_DONE_STRING,
|
['\''] = JSON_STRING,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Zero */
|
/* Zero */
|
||||||
|
@ -207,27 +210,18 @@ static const uint8_t json_lexer[][256] = {
|
||||||
['\n'] = IN_WHITESPACE,
|
['\n'] = IN_WHITESPACE,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* operator */
|
|
||||||
[IN_OPERATOR_DONE] = {
|
|
||||||
TERMINAL(JSON_OPERATOR),
|
|
||||||
},
|
|
||||||
|
|
||||||
/* escape */
|
/* escape */
|
||||||
[IN_ESCAPE_DONE] = {
|
|
||||||
TERMINAL(JSON_ESCAPE),
|
|
||||||
},
|
|
||||||
|
|
||||||
[IN_ESCAPE_LL] = {
|
[IN_ESCAPE_LL] = {
|
||||||
['d'] = IN_ESCAPE_DONE,
|
['d'] = JSON_ESCAPE,
|
||||||
},
|
},
|
||||||
|
|
||||||
[IN_ESCAPE_L] = {
|
[IN_ESCAPE_L] = {
|
||||||
['d'] = IN_ESCAPE_DONE,
|
['d'] = JSON_ESCAPE,
|
||||||
['l'] = IN_ESCAPE_LL,
|
['l'] = IN_ESCAPE_LL,
|
||||||
},
|
},
|
||||||
|
|
||||||
[IN_ESCAPE_I64] = {
|
[IN_ESCAPE_I64] = {
|
||||||
['d'] = IN_ESCAPE_DONE,
|
['d'] = JSON_ESCAPE,
|
||||||
},
|
},
|
||||||
|
|
||||||
[IN_ESCAPE_I6] = {
|
[IN_ESCAPE_I6] = {
|
||||||
|
@ -239,11 +233,11 @@ static const uint8_t json_lexer[][256] = {
|
||||||
},
|
},
|
||||||
|
|
||||||
[IN_ESCAPE] = {
|
[IN_ESCAPE] = {
|
||||||
['d'] = IN_ESCAPE_DONE,
|
['d'] = JSON_ESCAPE,
|
||||||
['i'] = IN_ESCAPE_DONE,
|
['i'] = JSON_ESCAPE,
|
||||||
['p'] = IN_ESCAPE_DONE,
|
['p'] = JSON_ESCAPE,
|
||||||
['s'] = IN_ESCAPE_DONE,
|
['s'] = JSON_ESCAPE,
|
||||||
['f'] = IN_ESCAPE_DONE,
|
['f'] = JSON_ESCAPE,
|
||||||
['l'] = IN_ESCAPE_L,
|
['l'] = IN_ESCAPE_L,
|
||||||
['I'] = IN_ESCAPE_I,
|
['I'] = IN_ESCAPE_I,
|
||||||
},
|
},
|
||||||
|
@ -255,12 +249,12 @@ static const uint8_t json_lexer[][256] = {
|
||||||
['0'] = IN_ZERO,
|
['0'] = IN_ZERO,
|
||||||
['1' ... '9'] = IN_NONZERO_NUMBER,
|
['1' ... '9'] = IN_NONZERO_NUMBER,
|
||||||
['-'] = IN_NEG_NONZERO_NUMBER,
|
['-'] = IN_NEG_NONZERO_NUMBER,
|
||||||
['{'] = IN_OPERATOR_DONE,
|
['{'] = JSON_OPERATOR,
|
||||||
['}'] = IN_OPERATOR_DONE,
|
['}'] = JSON_OPERATOR,
|
||||||
['['] = IN_OPERATOR_DONE,
|
['['] = JSON_OPERATOR,
|
||||||
[']'] = IN_OPERATOR_DONE,
|
[']'] = JSON_OPERATOR,
|
||||||
[','] = IN_OPERATOR_DONE,
|
[','] = JSON_OPERATOR,
|
||||||
[':'] = IN_OPERATOR_DONE,
|
[':'] = JSON_OPERATOR,
|
||||||
['a' ... 'z'] = IN_KEYWORD,
|
['a' ... 'z'] = IN_KEYWORD,
|
||||||
['%'] = IN_ESCAPE,
|
['%'] = IN_ESCAPE,
|
||||||
[' '] = IN_WHITESPACE,
|
[' '] = IN_WHITESPACE,
|
||||||
|
@ -275,11 +269,12 @@ void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func)
|
||||||
lexer->emit = func;
|
lexer->emit = func;
|
||||||
lexer->state = IN_START;
|
lexer->state = IN_START;
|
||||||
lexer->token = qstring_new();
|
lexer->token = qstring_new();
|
||||||
|
lexer->x = lexer->y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int json_lexer_feed_char(JSONLexer *lexer, char ch)
|
static int json_lexer_feed_char(JSONLexer *lexer, char ch)
|
||||||
{
|
{
|
||||||
char buf[2];
|
int char_consumed, new_state;
|
||||||
|
|
||||||
lexer->x++;
|
lexer->x++;
|
||||||
if (ch == '\n') {
|
if (ch == '\n') {
|
||||||
|
@ -287,32 +282,33 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch)
|
||||||
lexer->y++;
|
lexer->y++;
|
||||||
}
|
}
|
||||||
|
|
||||||
lexer->state = json_lexer[lexer->state][(uint8_t)ch];
|
do {
|
||||||
|
new_state = json_lexer[lexer->state][(uint8_t)ch];
|
||||||
switch (lexer->state) {
|
char_consumed = !TERMINAL_NEEDED_LOOKAHEAD(lexer->state, new_state);
|
||||||
case JSON_OPERATOR:
|
if (char_consumed) {
|
||||||
case JSON_ESCAPE:
|
qstring_append_chr(lexer->token, ch);
|
||||||
case JSON_INTEGER:
|
}
|
||||||
case JSON_FLOAT:
|
|
||||||
case JSON_KEYWORD:
|
|
||||||
case JSON_STRING:
|
|
||||||
lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y);
|
|
||||||
case JSON_SKIP:
|
|
||||||
lexer->state = json_lexer[IN_START][(uint8_t)ch];
|
|
||||||
QDECREF(lexer->token);
|
|
||||||
lexer->token = qstring_new();
|
|
||||||
break;
|
|
||||||
case ERROR:
|
|
||||||
return -EINVAL;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[0] = ch;
|
|
||||||
buf[1] = 0;
|
|
||||||
|
|
||||||
qstring_append(lexer->token, buf);
|
|
||||||
|
|
||||||
|
switch (new_state) {
|
||||||
|
case JSON_OPERATOR:
|
||||||
|
case JSON_ESCAPE:
|
||||||
|
case JSON_INTEGER:
|
||||||
|
case JSON_FLOAT:
|
||||||
|
case JSON_KEYWORD:
|
||||||
|
case JSON_STRING:
|
||||||
|
lexer->emit(lexer, lexer->token, new_state, lexer->x, lexer->y);
|
||||||
|
case JSON_SKIP:
|
||||||
|
QDECREF(lexer->token);
|
||||||
|
lexer->token = qstring_new();
|
||||||
|
new_state = IN_START;
|
||||||
|
break;
|
||||||
|
case ERROR:
|
||||||
|
return -EINVAL;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lexer->state = new_state;
|
||||||
|
} while (!char_consumed);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +330,7 @@ int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
|
||||||
|
|
||||||
int json_lexer_flush(JSONLexer *lexer)
|
int json_lexer_flush(JSONLexer *lexer)
|
||||||
{
|
{
|
||||||
return json_lexer_feed_char(lexer, 0);
|
return lexer->state == IN_START ? 0 : json_lexer_feed_char(lexer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void json_lexer_destroy(JSONLexer *lexer)
|
void json_lexer_destroy(JSONLexer *lexer)
|
||||||
|
|
|
@ -205,6 +205,10 @@ static QString *qstring_from_escaped_str(JSONParserContext *ctxt, QObject *token
|
||||||
qstring_append(str, "\b");
|
qstring_append(str, "\b");
|
||||||
ptr++;
|
ptr++;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
qstring_append(str, "\f");
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
qstring_append(str, "\n");
|
qstring_append(str, "\n");
|
||||||
ptr++;
|
ptr++;
|
||||||
|
|
|
@ -43,11 +43,11 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok
|
||||||
}
|
}
|
||||||
|
|
||||||
dict = qdict_new();
|
dict = qdict_new();
|
||||||
qdict_put_obj(dict, "type", QOBJECT(qint_from_int(type)));
|
qdict_put(dict, "type", qint_from_int(type));
|
||||||
QINCREF(token);
|
QINCREF(token);
|
||||||
qdict_put_obj(dict, "token", QOBJECT(token));
|
qdict_put(dict, "token", token);
|
||||||
qdict_put_obj(dict, "x", QOBJECT(qint_from_int(x)));
|
qdict_put(dict, "x", qint_from_int(x));
|
||||||
qdict_put_obj(dict, "y", QOBJECT(qint_from_int(y)));
|
qdict_put(dict, "y", qint_from_int(y));
|
||||||
|
|
||||||
qlist_append(parser->tokens, dict);
|
qlist_append(parser->tokens, dict);
|
||||||
|
|
||||||
|
|
3
qjson.c
3
qjson.c
|
@ -158,6 +158,9 @@ static void to_json(const QObject *obj, QString *str)
|
||||||
case '\b':
|
case '\b':
|
||||||
qstring_append(str, "\\b");
|
qstring_append(str, "\\b");
|
||||||
break;
|
break;
|
||||||
|
case '\f':
|
||||||
|
qstring_append(str, "\\f");
|
||||||
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
qstring_append(str, "\\n");
|
qstring_append(str, "\\n");
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue