1use std::io::{self, Read};
8
9use encoding_rs::{Decoder, Encoding};
10
11pub struct DecodingReader<R> {
29 inner: R,
30 decoder: Decoder,
31 raw_buf: Vec<u8>,
33 raw_len: usize,
35 decoded_buf: Vec<u8>,
37 decoded_pos: usize,
39 decoded_len: usize,
41 eof: bool,
43}
44
45const CHUNK_SIZE: usize = 8192;
47
48impl<R: Read> DecodingReader<R> {
49 pub fn new(inner: R, encoding: &'static Encoding) -> Self {
51 Self {
52 inner,
53 decoder: encoding.new_decoder(),
54 raw_buf: vec![0u8; CHUNK_SIZE],
55 raw_len: 0,
56 decoded_buf: vec![0u8; CHUNK_SIZE * 4], decoded_pos: 0,
58 decoded_len: 0,
59 eof: false,
60 }
61 }
62
63 fn fill_decoded(&mut self) -> io::Result<()> {
65 if self.decoded_pos < self.decoded_len {
67 return Ok(());
68 }
69
70 self.decoded_pos = 0;
72 self.decoded_len = 0;
73
74 loop {
81 let (_result, read, written, _had_errors) = self.decoder.decode_to_utf8(
82 &self.raw_buf[..self.raw_len],
83 &mut self.decoded_buf,
84 self.eof,
85 );
86
87 if read < self.raw_len {
90 self.raw_buf.copy_within(read..self.raw_len, 0);
91 self.raw_len -= read;
92 } else {
93 self.raw_len = 0;
94 }
95
96 if written > 0 {
97 self.decoded_len = written;
98 return Ok(());
99 }
100
101 if self.eof {
103 return Ok(());
104 }
105
106 if self.raw_len == self.raw_buf.len() {
109 self.raw_buf.resize(self.raw_buf.len() * 2, 0);
112 }
113 let n = self.inner.read(&mut self.raw_buf[self.raw_len..])?;
114 if n == 0 {
115 self.eof = true;
116 } else {
117 self.raw_len += n;
118 }
119 }
120 }
121}
122
123impl<R: Read> Read for DecodingReader<R> {
124 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
125 if self.decoded_pos >= self.decoded_len {
126 self.fill_decoded()?;
127 }
128
129 if self.decoded_pos >= self.decoded_len {
130 return Ok(0); }
132
133 let available = self.decoded_len - self.decoded_pos;
134 let to_copy = available.min(buf.len());
135 buf[..to_copy]
136 .copy_from_slice(&self.decoded_buf[self.decoded_pos..self.decoded_pos + to_copy]);
137 self.decoded_pos += to_copy;
138 Ok(to_copy)
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn stream_utf8() {
148 let data = b"Hello, world!";
149 let mut reader = DecodingReader::new(&data[..], encoding_rs::UTF_8);
150 let mut output = String::new();
151 reader.read_to_string(&mut output).unwrap();
152 assert_eq!(output, "Hello, world!");
153 }
154
155 #[test]
156 fn stream_windows_1254_turkish() {
157 let data: &[u8] = &[0xFE, 0xF0, 0xFD];
159 let mut reader = DecodingReader::new(data, encoding_rs::WINDOWS_1254);
160 let mut output = String::new();
161 reader.read_to_string(&mut output).unwrap();
162 assert_eq!(output, "\u{015F}\u{011F}\u{0131}"); }
164
165 #[test]
166 fn stream_empty() {
167 let data: &[u8] = b"";
168 let mut reader = DecodingReader::new(data, encoding_rs::UTF_8);
169 let mut output = String::new();
170 reader.read_to_string(&mut output).unwrap();
171 assert_eq!(output, "");
172 }
173
174 #[test]
175 fn stream_large_input() {
176 let data = "abcdefgh".repeat(2000); let mut reader = DecodingReader::new(data.as_bytes(), encoding_rs::UTF_8);
179 let mut output = String::new();
180 reader.read_to_string(&mut output).unwrap();
181 assert_eq!(output, data);
182 }
183
184 #[test]
185 fn stream_small_read_buf() {
186 let data = b"Hello, world!";
187 let mut reader = DecodingReader::new(&data[..], encoding_rs::UTF_8);
188 let mut output = Vec::new();
189 let mut buf = [0u8; 3]; loop {
191 let n = reader.read(&mut buf).unwrap();
192 if n == 0 {
193 break;
194 }
195 output.extend_from_slice(&buf[..n]);
196 }
197 assert_eq!(String::from_utf8(output).unwrap(), "Hello, world!");
198 }
199
200 struct OneByteReader<'a> {
203 data: &'a [u8],
204 pos: usize,
205 }
206
207 impl Read for OneByteReader<'_> {
208 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
209 if self.pos >= self.data.len() || buf.is_empty() {
210 return Ok(0);
211 }
212 buf[0] = self.data[self.pos];
213 self.pos += 1;
214 Ok(1)
215 }
216 }
217
218 #[test]
219 fn stream_multibyte_split_across_reads() {
220 let text = "cafe\u{301} gu\u{308}naydin nai\u{308}ve \u{1F600}";
224 let reader = OneByteReader {
225 data: text.as_bytes(),
226 pos: 0,
227 };
228 let mut out = String::new();
229 DecodingReader::new(reader, encoding_rs::UTF_8)
230 .read_to_string(&mut out)
231 .unwrap();
232 assert_eq!(out, text);
233 }
234
235 #[test]
236 fn stream_multibyte_across_chunk_boundary() {
237 let mut text = "a".repeat(CHUNK_SIZE - 1);
240 text.push('\u{20AC}'); text.push_str(&"b".repeat(100));
242 let mut out = String::new();
243 DecodingReader::new(text.as_bytes(), encoding_rs::UTF_8)
244 .read_to_string(&mut out)
245 .unwrap();
246 assert_eq!(out, text);
247 }
248}