Skip to main content

base64_stream/
from_base64_reader.rs

1use std::{
2    fmt,
3    io::{self, ErrorKind, Read},
4};
5
6use base64::{
7    DecodeSliceError, Engine,
8    engine::{GeneralPurpose, general_purpose::STANDARD},
9};
10
11#[inline]
12fn decode_error_to_io_error(error: DecodeSliceError) -> io::Error {
13    io::Error::new(ErrorKind::InvalidData, error)
14}
15
16/// Read base64 data and decode them to plain data.
17pub struct FromBase64Reader<R: Read, const N: usize = 4096> {
18    inner:       R,
19    buf:         [u8; N],
20    buf_length:  usize,
21    buf_offset:  usize,
22    temp:        [u8; 2],
23    temp_length: usize,
24    engine:      &'static GeneralPurpose,
25}
26
27impl<R: Read, const N: usize> fmt::Debug for FromBase64Reader<R, N> {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        f.debug_struct("FromBase64Reader")
30            .field("buf_length", &self.buf_length)
31            .field("buf_offset", &self.buf_offset)
32            .field("temp", &&self.temp[..self.temp_length])
33            .field("temp_length", &self.temp_length)
34            .finish_non_exhaustive()
35    }
36}
37
38impl<R: Read> FromBase64Reader<R> {
39    #[inline]
40    pub fn new(reader: R) -> FromBase64Reader<R> {
41        Self::new2(reader)
42    }
43}
44
45impl<R: Read, const N: usize> FromBase64Reader<R, N> {
46    #[inline]
47    pub fn new2(reader: R) -> FromBase64Reader<R, N> {
48        const { assert!(N >= 4, "buffer size N must be at least 4") };
49        FromBase64Reader {
50            inner:       reader,
51            buf:         [0u8; N],
52            buf_length:  0,
53            buf_offset:  0,
54            temp:        [0; 2],
55            temp_length: 0,
56            engine:      &STANDARD,
57        }
58    }
59}
60
61impl<R: Read, const N: usize> FromBase64Reader<R, N> {
62    fn buf_left_shift(&mut self, distance: usize) {
63        debug_assert!(self.buf_length >= distance);
64
65        self.buf_offset += distance;
66        self.buf_length -= distance;
67
68        if self.buf_offset >= N - 4 {
69            self.buf.copy_within(self.buf_offset..self.buf_offset + self.buf_length, 0);
70
71            self.buf_offset = 0;
72        }
73    }
74
75    #[inline]
76    fn drain_temp<'a>(&mut self, buf: &'a mut [u8]) -> &'a mut [u8] {
77        debug_assert!(self.temp_length > 0);
78        debug_assert!(!buf.is_empty());
79
80        let drain_length = buf.len().min(self.temp_length);
81
82        buf[..drain_length].copy_from_slice(&self.temp[..drain_length]);
83
84        self.temp_length -= drain_length;
85        self.temp.copy_within(drain_length..drain_length + self.temp_length, 0);
86
87        &mut buf[drain_length..]
88    }
89
90    #[inline]
91    fn drain_block<'a>(&mut self, mut buf: &'a mut [u8]) -> Result<&'a mut [u8], DecodeSliceError> {
92        debug_assert!(self.buf_length > 0);
93        debug_assert!(self.temp_length == 0);
94        debug_assert!(!buf.is_empty());
95
96        let drain_length = self.buf_length.min(4);
97
98        let mut b = [0; 3];
99
100        let decode_length = self
101            .engine
102            .decode_slice(&self.buf[self.buf_offset..(self.buf_offset + drain_length)], &mut b)?;
103
104        self.buf_left_shift(drain_length);
105
106        let buf_length = buf.len();
107
108        if buf_length >= decode_length {
109            buf[..decode_length].copy_from_slice(&b[..decode_length]);
110
111            buf = &mut buf[decode_length..];
112        } else {
113            buf[..buf_length].copy_from_slice(&b[..buf_length]);
114
115            buf = &mut buf[buf_length..];
116
117            self.temp_length = decode_length - buf_length;
118            self.temp[..self.temp_length].copy_from_slice(&b[buf_length..decode_length]);
119        }
120
121        Ok(buf)
122    }
123
124    fn drain<'a>(&mut self, mut buf: &'a mut [u8]) -> Result<&'a mut [u8], DecodeSliceError> {
125        if buf.is_empty() {
126            return Ok(buf);
127        }
128
129        if self.temp_length > 0 {
130            buf = self.drain_temp(buf);
131        }
132
133        debug_assert!(self.buf_length >= 4);
134
135        let buf_length = buf.len();
136
137        if buf_length >= 3 {
138            debug_assert!(self.temp_length == 0);
139
140            let actual_max_read_size = (buf_length / 3) << 2; // (buf_length / 3) * 4
141            let max_available_self_buf_length = self.buf_length & !0b11;
142
143            let drain_length = max_available_self_buf_length.min(actual_max_read_size);
144
145            let decode_length = self
146                .engine
147                .decode_slice(&self.buf[self.buf_offset..(self.buf_offset + drain_length)], buf)?;
148
149            buf = &mut buf[decode_length..];
150
151            self.buf_left_shift(drain_length);
152        }
153
154        if !buf.is_empty() && self.buf_length >= 4 { self.drain_block(buf) } else { Ok(buf) }
155    }
156
157    #[inline]
158    fn drain_end<'a>(&mut self, mut buf: &'a mut [u8]) -> Result<&'a mut [u8], DecodeSliceError> {
159        if buf.is_empty() {
160            return Ok(buf);
161        }
162
163        if self.temp_length > 0 {
164            buf = self.drain_temp(buf);
165        }
166
167        if !buf.is_empty() && self.buf_length > 0 { self.drain_block(buf) } else { Ok(buf) }
168    }
169
170    /// Returns the inner reader, consuming this wrapper.
171    #[inline]
172    pub fn into_inner(self) -> R {
173        self.inner
174    }
175}
176
177impl<R: Read, const N: usize> Read for FromBase64Reader<R, N> {
178    fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, io::Error> {
179        let original_buf_length = buf.len();
180
181        if buf.is_empty() {
182            return Ok(0);
183        }
184
185        if self.temp_length > 0 {
186            buf = self.drain_temp(buf);
187
188            return Ok(original_buf_length - buf.len());
189        }
190
191        if self.buf_length >= 4 {
192            buf = self.drain(buf).map_err(decode_error_to_io_error)?;
193
194            return Ok(original_buf_length - buf.len());
195        }
196
197        while self.buf_length < 4 {
198            debug_assert!(self.buf_offset + self.buf_length <= N);
199
200            match self.inner.read(&mut self.buf[(self.buf_offset + self.buf_length)..]) {
201                Ok(0) => {
202                    buf = self.drain_end(buf).map_err(decode_error_to_io_error)?;
203
204                    return Ok(original_buf_length - buf.len());
205                },
206                Ok(c) => self.buf_length += c,
207                Err(ref e) if e.kind() == ErrorKind::Interrupted => {},
208                Err(e) => return Err(e),
209            }
210        }
211
212        buf = self.drain(buf).map_err(decode_error_to_io_error)?;
213
214        Ok(original_buf_length - buf.len())
215    }
216}
217
218impl<R: Read> From<R> for FromBase64Reader<R> {
219    #[inline]
220    fn from(reader: R) -> Self {
221        FromBase64Reader::new(reader)
222    }
223}