From fe3d2a9abacf47618f4e19bee4a64d6bfd831a2c Mon Sep 17 00:00:00 2001 From: Anton Zavodchikov Date: Sun, 15 Nov 2020 17:58:17 +0500 Subject: [PATCH] json2: unescape characters (#6836) --- vlib/x/json2/decoder.v | 55 +++++++++++++++++++++++++++++++-------- vlib/x/json2/encoder.v | 6 ++++- vlib/x/json2/json2_test.v | 22 ++++++++++++++++ 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/vlib/x/json2/decoder.v b/vlib/x/json2/decoder.v index eb1f1097f7..39ab3627b8 100644 --- a/vlib/x/json2/decoder.v +++ b/vlib/x/json2/decoder.v @@ -223,8 +223,6 @@ fn (mut p Parser) decode_value() ?Any { fn (mut p Parser) decode_string() ?Any { mut strwr := strings.new_builder(200) for i := 0; i < p.tok.lit.len; i++ { - // s := p.tok.lit[i].str() - // println('$i $s') if ((i-1 >= 0 && p.tok.lit[i-1] != `/`) || i == 0) && int(p.tok.lit[i]) in [9, 10, 0] { return error('character must be escaped with a backslash.') } @@ -235,8 +233,33 @@ fn (mut p Parser) decode_string() ?Any { if i+1 < p.tok.lit.len && p.tok.lit[i] == 92 { peek := p.tok.lit[i+1] - if peek in [`b`, `f`, `n`, `r`, `t`, `u`, `\\`, `"`, `/`] { - if peek == `u` { + match peek{ + `b` { + i++ + strwr.write_b(`\b`) + continue + } + `f` { + i++ + strwr.write_b(`\f`) + continue + } + `n` { + i++ + strwr.write_b(`\n`) + continue + } + `r` { + i++ + strwr.write_b(`\r`) + continue + } + `t` { + i++ + strwr.write_b(`\t`) + continue + } + `u` { if i+5 < p.tok.lit.len { codepoint := p.tok.lit[i+2..i+6] check_valid_hex(codepoint)? @@ -248,13 +271,23 @@ fn (mut p Parser) decode_string() ?Any { return error('incomplete unicode escape.') } } - - i++ - strwr.write_b(p.tok.lit[i]) - continue - } else { - return error('invalid backslash escape.') - } + `\\` { + i++ + strwr.write_b(`\\`) + continue + } + `"` { + i++ + strwr.write_b(`\"`) + continue + } + `/` { + i++ + strwr.write_b(`/`) + continue + } + else { return error('invalid backslash escape.') } + } if int(peek) == 85 { return error('unicode endpoints must be in lowercase `u`.') diff --git a/vlib/x/json2/encoder.v b/vlib/x/json2/encoder.v index 2a0d5bcfd4..a2e11b1f3e 100644 --- a/vlib/x/json2/encoder.v +++ b/vlib/x/json2/encoder.v @@ -7,7 +7,11 @@ import strings fn write_value(v Any, i int, len int, mut wr strings.Builder) { str := v.str() - wr.write(if v is string { '"$str"' } else { str }) + if v is string { + wr.write('"$str"') + } else { + wr.write(str) + } if i >= len-1 { return } wr.write_b(`,`) } diff --git a/vlib/x/json2/json2_test.v b/vlib/x/json2/json2_test.v index f67c7dbfc0..defd544cad 100644 --- a/vlib/x/json2/json2_test.v +++ b/vlib/x/json2/json2_test.v @@ -69,6 +69,28 @@ fn test_fast_raw_decode() { assert str == '{"name":"Peter","age":"28","salary":"95000.5","title":"2"}' } +fn test_character_unescape() { + // Need to test `\r`, `\b`, `\f` ?? + message := '{ + "newline":"new\\nline", + "tab":"\\ttab", + "backslash": "back\\\\slash", + "quotes": "\\"quotes\\"", + "slash":"\/dev\/null" + }' + mut obj := json2.raw_decode(message) or { + assert false + json2.Any{} + } + lines := obj.as_map() + eprintln("$lines") + assert lines['newline'].str() == 'new\nline' + assert lines['tab'].str() == '\ttab' + assert lines['backslash'].str() == 'back\\slash' + assert lines['quotes'].str() == '\"quotes\"' + assert lines['slash'].str() == '/dev/null' +} + /* struct User2 { age int