Skip to main content

json_syntax/parse/
string.rs

1use super::{JsonParse, JsonParseError, JsonParsingContext, Parser};
2use decoded_char::DecodedChar;
3use locspan::Span;
4use smallstr::SmallString;
5
6fn is_control(c: char) -> bool {
7	('\u{0000}'..='\u{001f}').contains(&c)
8}
9
10fn parse_hex4<C, E>(parser: &mut Parser<C, E>) -> Result<u32, JsonParseError<E>>
11where
12	C: Iterator<Item = Result<DecodedChar, E>>,
13{
14	match parser.next_char()? {
15		(p, Some(c)) => match c.to_digit(16) {
16			Some(h3) => match parser.next_char()? {
17				(p, Some(c)) => match c.to_digit(16) {
18					Some(h2) => match parser.next_char()? {
19						(p, Some(c)) => match c.to_digit(16) {
20							Some(h1) => match parser.next_char()? {
21								(p, Some(c)) => match c.to_digit(16) {
22									Some(h0) => Ok(h3 << 12 | h2 << 8 | h1 << 4 | h0),
23									None => Err(JsonParseError::unexpected(p, Some(c))),
24								},
25								(p, unexpected) => Err(JsonParseError::unexpected(p, unexpected)),
26							},
27							None => Err(JsonParseError::unexpected(p, Some(c))),
28						},
29						(p, unexpected) => Err(JsonParseError::unexpected(p, unexpected)),
30					},
31					None => Err(JsonParseError::unexpected(p, Some(c))),
32				},
33				(p, unexpected) => Err(JsonParseError::unexpected(p, unexpected)),
34			},
35			None => Err(JsonParseError::unexpected(p, Some(c))),
36		},
37		(p, unexpected) => Err(JsonParseError::unexpected(p, unexpected)),
38	}
39}
40
41impl<A: smallvec::Array<Item = u8>> JsonParse for SmallString<A> {
42	fn parse_in<C, E>(
43		parser: &mut Parser<C, E>,
44		_context: JsonParsingContext,
45	) -> Result<(Self, usize), JsonParseError<E>>
46	where
47		C: Iterator<Item = Result<DecodedChar, E>>,
48	{
49		let i = parser.begin_fragment();
50		match parser.next_char()? {
51			(_, Some('"')) => {
52				let mut result = Self::new();
53				let mut high_surrogate: Option<(usize, u32)> = None;
54				loop {
55					let c = match parser.next_char()? {
56						(p, Some('"')) => {
57							if let Some((p_high, high)) = high_surrogate {
58								if parser.options.accept_truncated_surrogate_pair {
59									result.push('\u{fffd}');
60								} else {
61									break Err(JsonParseError::MissingLowSurrogate(
62										Span::new(p_high, p),
63										high as u16,
64									));
65								}
66							}
67
68							parser.end_fragment(i);
69							break Ok((result, i));
70						}
71						(_, Some('\\')) => {
72							match parser.next_char()? {
73								(_, Some(c @ ('"' | '\\' | '/'))) => c,
74								(_, Some('b')) => '\u{0008}',
75								(_, Some('t')) => '\u{0009}',
76								(_, Some('n')) => '\u{000a}',
77								(_, Some('f')) => '\u{000c}',
78								(_, Some('r')) => '\u{000d}',
79								(p, Some('u')) => {
80									let codepoint = parse_hex4(parser)?;
81
82									match high_surrogate.take() {
83										Some((p_high, high)) => {
84											if (0xdc00..=0xdfff).contains(&codepoint) {
85												let low = codepoint;
86												let codepoint = ((high - 0xd800) << 10
87													| (low - 0xdc00)) + 0x010000;
88												match char::from_u32(codepoint) {
89													Some(c) => c,
90													None => {
91														if parser.options.accept_invalid_codepoints
92														{
93															'\u{fffd}'
94														} else {
95															break Err(JsonParseError::InvalidUnicodeCodePoint(
96															Span::new(p_high, parser.position),
97															codepoint,
98														));
99														}
100													}
101												}
102											} else if parser.options.accept_truncated_surrogate_pair
103											{
104												result.push('\u{fffd}');
105
106												match char::from_u32(codepoint) {
107													Some(c) => c,
108													None => {
109														if parser.options.accept_invalid_codepoints
110														{
111															'\u{fffd}'
112														} else {
113															break Err(JsonParseError::InvalidUnicodeCodePoint(
114															Span::new(p, parser.position),
115															codepoint,
116														));
117														}
118													}
119												}
120											} else {
121												break Err(JsonParseError::InvalidLowSurrogate(
122													Span::new(p, parser.position),
123													high as u16,
124													codepoint,
125												));
126											}
127										}
128										None => {
129											if (0xd800..=0xdbff).contains(&codepoint) {
130												high_surrogate = Some((p, codepoint));
131												continue;
132											} else {
133												match char::from_u32(codepoint) {
134													Some(c) => c,
135													None => {
136														if parser.options.accept_invalid_codepoints
137														{
138															'\u{fffd}'
139														} else {
140															break Err(JsonParseError::InvalidUnicodeCodePoint(
141															Span::new(p, parser.position),
142															codepoint,
143														));
144														}
145													}
146												}
147											}
148										}
149									}
150								}
151								(p, unexpected) => {
152									break Err(JsonParseError::unexpected(p, unexpected));
153								}
154							}
155						}
156						(_, Some(c)) if !is_control(c) => c,
157						(p, unexpected) => break Err(JsonParseError::unexpected(p, unexpected)),
158					};
159
160					if let Some((p_high, high)) = high_surrogate.take() {
161						if parser.options.accept_truncated_surrogate_pair {
162							result.push('\u{fffd}');
163						} else {
164							break Err(JsonParseError::MissingLowSurrogate(
165								Span::new(p_high, parser.position),
166								high as u16,
167							));
168						}
169					}
170
171					result.push(c);
172				}
173			}
174			(p, unexpected) => Err(JsonParseError::unexpected(p, unexpected)),
175		}
176	}
177}