Skip to content

Commit a05dc81

Browse files
authored
Keep strings before incomplete escape sequences in partial mode (#208)
1 parent e6b28c2 commit a05dc81

File tree

2 files changed

+37
-7
lines changed

2 files changed

+37
-7
lines changed

crates/jiter/src/string_decoder.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::ops::Range;
22
use std::str::{from_utf8, from_utf8_unchecked};
33

4-
use crate::errors::{json_err, json_error, JsonResult};
4+
use crate::errors::{json_err, json_error, JsonErrorType, JsonResult};
55

66
pub type Tape = Vec<u8>;
77

@@ -154,16 +154,28 @@ fn decode_to_tape<'t, 'j>(
154154
b'n' => tape.push(b'\n'),
155155
b'r' => tape.push(b'\r'),
156156
b't' => tape.push(b'\t'),
157-
b'u' => {
158-
let (c, new_index) = parse_escape(data, index)?;
159-
ascii_only = false;
160-
index = new_index;
161-
tape.extend_from_slice(c.encode_utf8(&mut [0_u8; 4]).as_bytes());
162-
}
157+
b'u' => match parse_escape(data, index) {
158+
Ok((c, new_index)) => {
159+
ascii_only = false;
160+
index = new_index;
161+
tape.extend_from_slice(c.encode_utf8(&mut [0_u8; 4]).as_bytes());
162+
}
163+
Err(e) => {
164+
if allow_partial && e.error_type == JsonErrorType::EofWhileParsingString {
165+
let s = to_str(tape, ascii_only, start)?;
166+
return Ok((unsafe { StringOutput::tape(s, ascii_only) }, e.index));
167+
}
168+
return Err(e);
169+
}
170+
},
163171
_ => return json_err!(InvalidEscape, index),
164172
}
165173
index += 1;
166174
} else {
175+
if allow_partial {
176+
let s = to_str(tape, ascii_only, start)?;
177+
return Ok((unsafe { StringOutput::tape(s, ascii_only) }, index));
178+
}
167179
return json_err!(EofWhileParsingString, index);
168180
}
169181

crates/jiter/tests/main.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,6 +1564,24 @@ fn jiter_partial_string() {
15641564
);
15651565
}
15661566

1567+
#[test]
1568+
fn jiter_partial_string_escape() {
1569+
let mut jiter = Jiter::new(br#""foo\"#).with_allow_partial_strings();
1570+
assert_eq!(jiter.next_str().unwrap(), "foo");
1571+
1572+
let mut jiter = Jiter::new(br#""foo\u"#).with_allow_partial_strings();
1573+
assert_eq!(jiter.next_str().unwrap(), "foo");
1574+
1575+
let mut jiter = Jiter::new(br#""foo\u1"#).with_allow_partial_strings();
1576+
assert_eq!(jiter.next_str().unwrap(), "foo");
1577+
1578+
let mut jiter = Jiter::new(br#""foo\u12"#).with_allow_partial_strings();
1579+
assert_eq!(jiter.next_str().unwrap(), "foo");
1580+
1581+
let mut jiter = Jiter::new(br#""foo\u123"#).with_allow_partial_strings();
1582+
assert_eq!(jiter.next_str().unwrap(), "foo");
1583+
}
1584+
15671585
#[test]
15681586
fn test_unicode_roundtrip() {
15691587
// '"中文"'

0 commit comments

Comments
 (0)