1mod single_byte;
4mod utf16;
5mod utf8;
6
7use crate::cjk::{big5, euc_kr, gb18030};
8use crate::jis::{euc_jp, iso2022jp, shift_jis};
9use crate::label::Encoding;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct DecodeError {
25 pub offset: usize,
27 pub length: usize,
32 pub kind: DecodeErrorKind,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum DecodeErrorKind {
39 MalformedSequence,
42 TruncatedSequence,
45 UnpairedSurrogate,
47 DisallowedByte,
50}
51
52impl std::fmt::Display for DecodeError {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 let what = match self.kind {
55 DecodeErrorKind::MalformedSequence => "malformed byte sequence",
56 DecodeErrorKind::TruncatedSequence => "truncated byte sequence at end of input",
57 DecodeErrorKind::UnpairedSurrogate => "unpaired UTF-16 surrogate",
58 DecodeErrorKind::DisallowedByte => "byte outside the encoding's repertoire",
59 };
60 write!(
61 f,
62 "{what} at offset {} (length {})",
63 self.offset, self.length
64 )
65 }
66}
67
68impl std::error::Error for DecodeError {}
69
70#[derive(Debug, Clone)]
100pub struct Decoder {
101 kind: DecoderKind,
102}
103
104#[derive(Debug, Clone)]
105enum DecoderKind {
106 Utf8(utf8::Utf8State),
107 Utf16Le(utf16::Utf16State),
108 Utf16Be(utf16::Utf16State),
109 Latin1,
110 Windows1252,
111 Ascii,
112 LegacySingleByte(Encoding),
117 ShiftJis(shift_jis::ShiftJisState),
118 EucJp(euc_jp::EucJpState),
119 Iso2022Jp(iso2022jp::Iso2022JpState),
120 Gbk(gb18030::Gb18030State),
123 Gb18030(gb18030::Gb18030State),
124 Big5(big5::Big5State),
125 EucKr(euc_kr::EucKrState),
126}
127
128impl Decoder {
129 #[must_use]
132 pub(crate) const fn new(encoding: Encoding) -> Decoder {
133 let kind = match encoding {
134 Encoding::Utf8 => DecoderKind::Utf8(utf8::Utf8State::new()),
135 Encoding::Utf16Le => DecoderKind::Utf16Le(utf16::Utf16State::new()),
136 Encoding::Utf16Be => DecoderKind::Utf16Be(utf16::Utf16State::new()),
137 Encoding::Latin1 => DecoderKind::Latin1,
138 Encoding::Windows1252 => DecoderKind::Windows1252,
139 Encoding::Ascii => DecoderKind::Ascii,
140 Encoding::ShiftJis => DecoderKind::ShiftJis(shift_jis::ShiftJisState::new()),
141 Encoding::EucJp => DecoderKind::EucJp(euc_jp::EucJpState::new()),
142 Encoding::Iso2022Jp => DecoderKind::Iso2022Jp(iso2022jp::Iso2022JpState::new()),
143 Encoding::Gbk => DecoderKind::Gbk(gb18030::Gb18030State::new()),
144 Encoding::Gb18030 => DecoderKind::Gb18030(gb18030::Gb18030State::new()),
145 Encoding::Big5 => DecoderKind::Big5(big5::Big5State::new()),
146 Encoding::EucKr => DecoderKind::EucKr(euc_kr::EucKrState::new()),
147 other => {
155 debug_assert!(
156 other.is_legacy_single_byte_table(),
157 "Decoder::new: unhandled Encoding variant"
158 );
159 DecoderKind::LegacySingleByte(other)
160 }
161 };
162 Decoder { kind }
163 }
164
165 #[must_use]
167 pub const fn encoding(&self) -> Encoding {
168 match &self.kind {
169 DecoderKind::Utf8(_) => Encoding::Utf8,
170 DecoderKind::Utf16Le(_) => Encoding::Utf16Le,
171 DecoderKind::Utf16Be(_) => Encoding::Utf16Be,
172 DecoderKind::Latin1 => Encoding::Latin1,
173 DecoderKind::Windows1252 => Encoding::Windows1252,
174 DecoderKind::Ascii => Encoding::Ascii,
175 DecoderKind::LegacySingleByte(encoding) => *encoding,
176 DecoderKind::ShiftJis(_) => Encoding::ShiftJis,
177 DecoderKind::EucJp(_) => Encoding::EucJp,
178 DecoderKind::Iso2022Jp(_) => Encoding::Iso2022Jp,
179 DecoderKind::Gbk(_) => Encoding::Gbk,
180 DecoderKind::Gb18030(_) => Encoding::Gb18030,
181 DecoderKind::Big5(_) => Encoding::Big5,
182 DecoderKind::EucKr(_) => Encoding::EucKr,
183 }
184 }
185
186 #[must_use]
193 pub const fn has_pending_state(&self) -> bool {
194 match &self.kind {
195 DecoderKind::Utf8(state) => state.has_pending(),
196 DecoderKind::Utf16Le(state) | DecoderKind::Utf16Be(state) => state.has_pending(),
197 DecoderKind::Latin1
198 | DecoderKind::Windows1252
199 | DecoderKind::Ascii
200 | DecoderKind::LegacySingleByte(_) => false,
201 DecoderKind::ShiftJis(state) => state.has_pending(),
202 DecoderKind::EucJp(state) => state.has_pending(),
203 DecoderKind::Iso2022Jp(state) => state.has_pending(),
204 DecoderKind::Gbk(state) | DecoderKind::Gb18030(state) => state.has_pending(),
205 DecoderKind::Big5(state) => state.has_pending(),
206 DecoderKind::EucKr(state) => state.has_pending(),
207 }
208 }
209
210 pub fn decode_to_string(
231 &mut self,
232 input: &[u8],
233 dst: &mut String,
234 last: bool,
235 ) -> Result<usize, DecodeError> {
236 match &mut self.kind {
237 DecoderKind::Utf8(state) => utf8::decode(state, input, dst, last),
238 DecoderKind::Utf16Le(state) => utf16::decode(state, input, dst, last, false),
239 DecoderKind::Utf16Be(state) => utf16::decode(state, input, dst, last, true),
240 DecoderKind::Latin1 => single_byte::decode_latin1(input, dst),
241 DecoderKind::Windows1252 => single_byte::decode_windows1252(input, dst),
242 DecoderKind::Ascii => single_byte::decode_ascii(input, dst),
243 DecoderKind::LegacySingleByte(encoding) => {
244 single_byte::decode_legacy_single_byte(*encoding, input, dst)
245 }
246 DecoderKind::ShiftJis(state) => shift_jis::decode(state, input, dst, last),
247 DecoderKind::EucJp(state) => euc_jp::decode(state, input, dst, last),
248 DecoderKind::Iso2022Jp(state) => iso2022jp::decode(state, input, dst, last),
249 DecoderKind::Gbk(state) | DecoderKind::Gb18030(state) => {
250 gb18030::decode(state, input, dst, last)
251 }
252 DecoderKind::Big5(state) => big5::decode(state, input, dst, last),
253 DecoderKind::EucKr(state) => euc_kr::decode(state, input, dst, last),
254 }
255 }
256
257 pub fn decode_to_string_lossy(&mut self, input: &[u8], dst: &mut String, last: bool) -> usize {
266 match &mut self.kind {
267 DecoderKind::Utf8(state) => utf8::decode_lossy(state, input, dst, last),
268 DecoderKind::Utf16Le(state) => utf16::decode_lossy(state, input, dst, last, false),
269 DecoderKind::Utf16Be(state) => utf16::decode_lossy(state, input, dst, last, true),
270 DecoderKind::Latin1 => single_byte::decode_latin1_lossy(input, dst),
271 DecoderKind::Windows1252 => single_byte::decode_windows1252_lossy(input, dst),
272 DecoderKind::Ascii => single_byte::decode_ascii_lossy(input, dst),
273 DecoderKind::LegacySingleByte(encoding) => {
274 single_byte::decode_legacy_single_byte_lossy(*encoding, input, dst)
275 }
276 DecoderKind::ShiftJis(state) => shift_jis::decode_lossy(state, input, dst, last),
277 DecoderKind::EucJp(state) => euc_jp::decode_lossy(state, input, dst, last),
278 DecoderKind::Iso2022Jp(state) => iso2022jp::decode_lossy(state, input, dst, last),
279 DecoderKind::Gbk(state) | DecoderKind::Gb18030(state) => {
280 gb18030::decode_lossy(state, input, dst, last)
281 }
282 DecoderKind::Big5(state) => big5::decode_lossy(state, input, dst, last),
283 DecoderKind::EucKr(state) => euc_kr::decode_lossy(state, input, dst, last),
284 }
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use super::*;
291
292 #[test]
293 fn encoding_round_trips_for_every_variant() {
294 for &enc in Encoding::ALL {
295 assert_eq!(enc.new_decoder().encoding(), enc);
296 }
297 }
298
299 #[test]
300 fn fresh_decoder_has_no_pending_state() {
301 for &enc in Encoding::ALL {
302 assert!(!enc.new_decoder().has_pending_state(), "{enc}");
303 }
304 }
305
306 #[test]
307 fn shift_jis_euc_jp_iso2022jp_decoders_report_pending_state_mid_sequence()
308 -> Result<(), DecodeError> {
309 let mut decoder = Encoding::ShiftJis.new_decoder();
310 let mut out = String::new();
311 decoder.decode_to_string(&[0x82], &mut out, false)?;
312 assert!(decoder.has_pending_state());
313 decoder.decode_to_string(&[0xA0], &mut out, true)?;
314 assert!(!decoder.has_pending_state());
315
316 let mut decoder = Encoding::EucJp.new_decoder();
317 let mut out = String::new();
318 decoder.decode_to_string(&[0xA4], &mut out, false)?;
319 assert!(decoder.has_pending_state());
320 decoder.decode_to_string(&[0xA2], &mut out, true)?;
321 assert!(!decoder.has_pending_state());
322
323 let mut decoder = Encoding::Iso2022Jp.new_decoder();
324 let mut out = String::new();
325 decoder.decode_to_string(&[0x1B], &mut out, false)?;
326 assert!(decoder.has_pending_state());
327 decoder.decode_to_string(&[0x28, 0x42], &mut out, true)?;
328 assert!(!decoder.has_pending_state());
329 Ok(())
330 }
331
332 #[test]
333 fn cjk_decoders_report_pending_state_mid_sequence() -> Result<(), DecodeError> {
334 for (encoding, lead, trail) in [
335 (Encoding::Gbk, 0xD6u8, 0xD0u8),
336 (Encoding::Gb18030, 0xD6, 0xD0),
337 (Encoding::Big5, 0xA4, 0xA4),
338 (Encoding::EucKr, 0xC7, 0xD1),
339 ] {
340 let mut decoder = encoding.new_decoder();
341 let mut out = String::new();
342 decoder.decode_to_string(&[lead], &mut out, false)?;
343 assert!(decoder.has_pending_state(), "{encoding}");
344 decoder.decode_to_string(&[trail], &mut out, true)?;
345 assert!(!decoder.has_pending_state(), "{encoding}");
346 }
347 Ok(())
348 }
349
350 #[test]
351 fn legacy_single_byte_decoders_never_report_pending_state() {
352 for &enc in Encoding::ALL {
353 if !enc.is_legacy_single_byte_table() {
354 continue;
355 }
356 let mut decoder = enc.new_decoder();
357 let mut out = String::new();
358 let _ = decoder.decode_to_string(&[0x80], &mut out, false);
359 assert!(!decoder.has_pending_state(), "{enc}");
360 }
361 }
362
363 #[test]
364 fn utf8_decoder_reports_pending_state_mid_sequence() -> Result<(), DecodeError> {
365 let mut decoder = Encoding::Utf8.new_decoder();
366 let mut out = String::new();
367 decoder.decode_to_string(&[0xE2], &mut out, false)?;
369 assert!(decoder.has_pending_state());
370 decoder.decode_to_string(&[0x86, 0x92], &mut out, true)?;
371 assert!(!decoder.has_pending_state());
372 assert_eq!(out, "→");
373 Ok(())
374 }
375
376 #[test]
377 fn decode_error_display_is_human_readable() {
378 let err = DecodeError {
379 offset: 3,
380 length: 1,
381 kind: DecodeErrorKind::DisallowedByte,
382 };
383 assert_eq!(
384 err.to_string(),
385 "byte outside the encoding's repertoire at offset 3 (length 1)"
386 );
387 }
388}