1use crate::parsers::MessageStream;
8use std::borrow::Cow;
9
10const B64_INVALID: u8 = 0xff;
11#[cfg(feature = "base64_slice")]
12const B64_STOP_SCAN: usize = 512;
13
14static BASE64_DECODE: [u8; 256] = base64_decode_table();
15
16const fn base64_decode_table() -> [u8; 256] {
17 let mut table = [B64_INVALID; 256];
18 let mut value = 0u8;
19 while value < 64 {
20 let ch = match value {
21 0..=25 => b'A' + value,
22 26..=51 => b'a' + (value - 26),
23 52..=61 => b'0' + (value - 52),
24 62 => b'+',
25 _ => b'/',
26 };
27 table[ch as usize] = value;
28 value += 1;
29 }
30 table
31}
32
33enum Base64Byte {
34 Consumed,
35 Stop,
36 Invalid,
37}
38
39struct Base64Decoder {
40 chunk: u32,
41 byte_count: u8,
42 buf: Vec<u8>,
43}
44
45impl Base64Decoder {
46 fn with_capacity(capacity: usize) -> Self {
47 Base64Decoder {
48 chunk: 0,
49 byte_count: 0,
50 buf: Vec::with_capacity(capacity),
51 }
52 }
53
54 #[inline(always)]
55 fn push(&mut self, ch: u8, stop_char: u8) -> Base64Byte {
56 let val = BASE64_DECODE[ch as usize];
57 if val < 0x40 {
58 self.chunk = (self.chunk << 6) | val as u32;
59 self.byte_count = (self.byte_count + 1) & 3;
60 if self.byte_count == 0 {
61 self.buf.extend_from_slice(&self.chunk.to_be_bytes()[1..]);
62 }
63 Base64Byte::Consumed
64 } else if ch == b'=' {
65 self.flush();
66 Base64Byte::Consumed
67 } else if matches!(ch, b' ' | b'\t' | b'\r' | b'\n') {
68 Base64Byte::Consumed
69 } else if ch == stop_char {
70 Base64Byte::Stop
71 } else {
72 Base64Byte::Invalid
73 }
74 }
75
76 #[inline(always)]
77 fn decode_groups<'a>(&mut self, mut rest: &'a [u8]) -> &'a [u8] {
78 if self.byte_count != 0 {
79 return rest;
80 }
81 while let [a, b, c, d, tail @ ..] = rest {
82 let a = BASE64_DECODE[*a as usize];
83 let b = BASE64_DECODE[*b as usize];
84 let c = BASE64_DECODE[*c as usize];
85 let d = BASE64_DECODE[*d as usize];
86 if a | b | c | d >= 0x40 {
87 break;
88 }
89 let word = ((a as u32) << 18) | ((b as u32) << 12) | ((c as u32) << 6) | d as u32;
90 self.buf.extend_from_slice(&word.to_be_bytes()[1..]);
91 rest = tail;
92 }
93 rest
94 }
95
96 #[inline(always)]
97 fn flush(&mut self) {
98 match self.byte_count {
99 2 => self.buf.push((self.chunk >> 4) as u8),
100 3 => self
101 .buf
102 .extend_from_slice(&[(self.chunk >> 10) as u8, (self.chunk >> 2) as u8]),
103 _ => (),
104 }
105 self.byte_count = 0;
106 }
107
108 fn finish(mut self) -> Vec<u8> {
109 self.flush();
110 self.buf
111 }
112}
113
114#[cfg(feature = "base64_slice")]
115#[inline(always)]
116fn base64_capacity(bytes: &[u8], stop_char: u8) -> usize {
117 let len = if BASE64_DECODE[stop_char as usize] == B64_INVALID
118 && stop_char != b'='
119 && !matches!(stop_char, b' ' | b'\t' | b'\r' | b'\n')
120 {
121 let window = bytes.len().min(B64_STOP_SCAN);
122 memchr::memchr(stop_char, bytes.get(..window).unwrap_or(bytes)).unwrap_or(bytes.len())
123 } else {
124 bytes.len()
125 };
126 len.div_ceil(4) * 3
127}
128
129#[inline(always)]
130pub fn base64_decode(bytes: &[u8]) -> Option<Vec<u8>> {
131 decode_slice(bytes, u8::MAX, bytes.len().div_ceil(4) * 3).map(|(decoded, _)| decoded)
132}
133
134#[cfg(feature = "base64_slice")]
135pub fn base64_decode_slice(bytes: &[u8], stop_char: u8) -> Option<(Vec<u8>, usize)> {
136 decode_slice(bytes, stop_char, base64_capacity(bytes, stop_char))
137}
138
139fn decode_slice(bytes: &[u8], stop_char: u8, capacity: usize) -> Option<(Vec<u8>, usize)> {
140 let mut decoder = Base64Decoder::with_capacity(capacity);
141 let mut rest = bytes;
142 loop {
143 rest = decoder.decode_groups(rest);
144 let Some((&ch, tail)) = rest.split_first() else {
145 break;
146 };
147 rest = tail;
148 match decoder.push(ch, stop_char) {
149 Base64Byte::Consumed => (),
150 Base64Byte::Stop => return Some((decoder.finish(), bytes.len() - rest.len())),
151 Base64Byte::Invalid => return None,
152 }
153 }
154 Some((decoder.finish(), bytes.len()))
155}
156
157pub fn base64_decode_stream<'x>(
158 stream: impl Iterator<Item = &'x u8>,
159 stream_len: usize,
160 stop_char: u8,
161) -> Option<Vec<u8>> {
162 let mut decoder = Base64Decoder::with_capacity(stream_len / 4 * 3);
163 for &ch in stream {
164 match decoder.push(ch, stop_char) {
165 Base64Byte::Consumed => (),
166 Base64Byte::Stop => return Some(decoder.finish()),
167 Base64Byte::Invalid => return None,
168 }
169 }
170 Some(decoder.finish())
171}
172
173impl<'x> MessageStream<'x> {
174 pub fn decode_base64_mime(&mut self, boundary: &[u8]) -> (usize, Cow<'x, [u8]>) {
175 let mut chunk: u32 = 0;
176 let mut byte_count: u8 = 0;
177
178 let mut buf = Vec::with_capacity(self.remaining() / 4 * 3);
179 let mut last_ch = b'\n';
180 let mut before_last_ch = 0;
181 let mut end_pos = self.offset();
182
183 self.checkpoint();
184
185 while let Some(&ch) = self.next() {
186 let val = BASE64_MAP[byte_count as usize][ch as usize];
187
188 if val < 0x01ffffff {
189 byte_count = (byte_count + 1) & 3;
190
191 if byte_count == 1 {
192 chunk = val;
193 } else {
194 chunk |= val;
195
196 if byte_count == 0 {
197 buf.extend_from_slice(&chunk.to_le_bytes()[0..3]);
198 }
199 }
200 } else {
201 match ch {
202 b'=' => match byte_count {
203 1 | 2 => {
204 buf.push(chunk.to_le_bytes()[0]);
205 byte_count = 0;
206 }
207 3 => {
208 buf.extend_from_slice(&chunk.to_le_bytes()[0..2]);
209 byte_count = 0;
210 }
211 0 => (),
212 _ => {
213 self.restore();
214 return (usize::MAX, b""[..].into());
215 }
216 },
217 b'\n' => {
218 end_pos = if last_ch == b'\r' {
219 self.offset() - 2
220 } else {
221 self.offset() - 1
222 }
223 }
224 b' ' | b'\t' | b'\r' => (),
225 b'-' => {
226 if last_ch == b'-' {
227 return if !boundary.is_empty() && self.try_skip(boundary) {
228 buf.shrink_to_fit();
229 (
230 if before_last_ch == b'\n' {
231 end_pos
232 } else {
233 self.offset() - boundary.len() - 2
234 },
235 buf.into(),
236 )
237 } else {
238 self.restore();
239 (usize::MAX, b""[..].into())
240 };
241 }
242 }
243 _ => {
244 self.restore();
245 return (usize::MAX, b""[..].into());
246 }
247 }
248 }
249
250 before_last_ch = last_ch;
251 last_ch = ch;
252 }
253
254 buf.shrink_to_fit();
255 (
256 if boundary.is_empty() {
257 self.offset()
258 } else {
259 self.restore();
260 usize::MAX
261 },
262 buf.into(),
263 )
264 }
265
266 pub fn decode_base64_word(&mut self) -> Option<Vec<u8>> {
267 let mut chunk: u32 = 0;
268 let mut byte_count: u8 = 0;
269 let mut buf = Vec::with_capacity(64);
270
271 while let Some(&ch) = self.next() {
272 match ch {
273 b'=' => {
274 match byte_count {
275 1 | 2 => {
276 buf.push(chunk.to_le_bytes()[0]);
277 byte_count = 0;
278 }
279 3 => {
280 buf.extend_from_slice(&chunk.to_le_bytes()[0..2]);
281 byte_count = 0;
282 }
283 0 => (),
284 _ => {
285 break;
287 }
288 }
289 }
290 b'?' => {
291 if let Some(b'=') = self.next() {
292 return Some(buf);
293 } else {
294 break;
295 }
296 }
297 b'\n' => {
298 if !self.next_is_space() {
299 break;
300 }
301 }
302 b' ' | b'\t' | b'\r' => (),
303 _ => {
304 let val = BASE64_MAP[byte_count as usize][ch as usize];
305
306 if val < 0x01ffffff {
307 byte_count = (byte_count + 1) & 3;
308
309 if byte_count == 1 {
310 chunk = val;
311 } else {
312 chunk |= val;
313
314 if byte_count == 0 {
315 buf.extend_from_slice(&chunk.to_le_bytes()[0..3]);
316 }
317 }
318 } else {
319 break;
320 }
321 }
322 }
323 }
324
325 None
326 }
327}
328
329pub static BASE64_MAP: &[&[u32]] = &[
342 &[
343 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
344 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
345 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
346 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
347 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
348 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
349 0x01ffffff, 0x000000f8, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000fc, 0x000000d0,
350 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4, 0x000000e8, 0x000000ec,
351 0x000000f0, 0x000000f4, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
352 0x01ffffff, 0x01ffffff, 0x00000000, 0x00000004, 0x00000008, 0x0000000c, 0x00000010,
353 0x00000014, 0x00000018, 0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c,
354 0x00000030, 0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048,
355 0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060, 0x00000064,
356 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000068,
357 0x0000006c, 0x00000070, 0x00000074, 0x00000078, 0x0000007c, 0x00000080, 0x00000084,
358 0x00000088, 0x0000008c, 0x00000090, 0x00000094, 0x00000098, 0x0000009c, 0x000000a0,
359 0x000000a4, 0x000000a8, 0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc,
360 0x000000c0, 0x000000c4, 0x000000c8, 0x000000cc, 0x01ffffff, 0x01ffffff, 0x01ffffff,
361 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
362 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
363 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
364 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
365 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
366 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
367 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
368 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
369 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
370 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
371 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
372 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
373 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
374 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
375 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
376 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
377 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
378 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
379 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
380 ],
381 &[
382 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
383 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
384 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
385 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
386 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
387 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
388 0x01ffffff, 0x0000e003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000f003, 0x00004003,
389 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003, 0x0000a003, 0x0000b003,
390 0x0000c003, 0x0000d003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
391 0x01ffffff, 0x01ffffff, 0x00000000, 0x00001000, 0x00002000, 0x00003000, 0x00004000,
392 0x00005000, 0x00006000, 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000,
393 0x0000c000, 0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001,
394 0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001, 0x00009001,
395 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000a001,
396 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001, 0x0000f001, 0x00000002, 0x00001002,
397 0x00002002, 0x00003002, 0x00004002, 0x00005002, 0x00006002, 0x00007002, 0x00008002,
398 0x00009002, 0x0000a002, 0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002,
399 0x00000003, 0x00001003, 0x00002003, 0x00003003, 0x01ffffff, 0x01ffffff, 0x01ffffff,
400 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
401 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
402 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
403 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
404 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
405 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
406 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
407 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
408 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
409 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
410 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
411 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
412 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
413 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
414 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
415 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
416 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
417 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
418 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
419 ],
420 &[
421 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
422 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
423 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
424 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
425 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
426 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
427 0x01ffffff, 0x00800f00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00c00f00, 0x00000d00,
428 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00, 0x00800e00, 0x00c00e00,
429 0x00000f00, 0x00400f00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
430 0x01ffffff, 0x01ffffff, 0x00000000, 0x00400000, 0x00800000, 0x00c00000, 0x00000100,
431 0x00400100, 0x00800100, 0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200,
432 0x00000300, 0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400,
433 0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600, 0x00400600,
434 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00800600,
435 0x00c00600, 0x00000700, 0x00400700, 0x00800700, 0x00c00700, 0x00000800, 0x00400800,
436 0x00800800, 0x00c00800, 0x00000900, 0x00400900, 0x00800900, 0x00c00900, 0x00000a00,
437 0x00400a00, 0x00800a00, 0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00,
438 0x00000c00, 0x00400c00, 0x00800c00, 0x00c00c00, 0x01ffffff, 0x01ffffff, 0x01ffffff,
439 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
440 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
441 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
442 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
443 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
444 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
445 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
446 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
447 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
448 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
449 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
450 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
451 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
452 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
453 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
454 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
455 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
456 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
457 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
458 ],
459 &[
460 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
461 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
462 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
463 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
464 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
465 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
466 0x01ffffff, 0x003e0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003f0000, 0x00340000,
467 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000, 0x003a0000, 0x003b0000,
468 0x003c0000, 0x003d0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
469 0x01ffffff, 0x01ffffff, 0x00000000, 0x00010000, 0x00020000, 0x00030000, 0x00040000,
470 0x00050000, 0x00060000, 0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000,
471 0x000c0000, 0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000,
472 0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000, 0x00190000,
473 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x001a0000,
474 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000, 0x001f0000, 0x00200000, 0x00210000,
475 0x00220000, 0x00230000, 0x00240000, 0x00250000, 0x00260000, 0x00270000, 0x00280000,
476 0x00290000, 0x002a0000, 0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000,
477 0x00300000, 0x00310000, 0x00320000, 0x00330000, 0x01ffffff, 0x01ffffff, 0x01ffffff,
478 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
479 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
480 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
481 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
482 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
483 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
484 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
485 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
486 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
487 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
488 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
489 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
490 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
491 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
492 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
493 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
494 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
495 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
496 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
497 ],
498];
499
500#[cfg(test)]
501mod tests {
502 use crate::parsers::MessageStream;
503
504 #[test]
505 fn decode_base64() {
506 for (encoded_str, expected_result) in [
507 ("VGVzdA==", "Test"),
508 ("WWU=", "Ye"),
509 ("QQ==", "A"),
510 ("cm8=", "ro"),
511 (
512 "QXJlIHlvdSBhIFNoaW1hbm8gb3IgQ2FtcGFnbm9sbyBwZXJzb24/",
513 "Are you a Shimano or Campagnolo person?",
514 ),
515 (
516 "PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8Ym9keT4KPC9ib2R5Pgo8L2h0bWw+Cg==",
517 "<!DOCTYPE html>\n<html>\n<body>\n</body>\n</html>\n",
518 ),
519 (
520 "PCFET0NUWVBFIGh0bWw+CjxodG1sPg\no8Ym9ke\nT4KPC 9ib2R5Pg\n o8L2h0bWw+Cg==",
521 "<!DOCTYPE html>\n<html>\n<body>\n</body>\n</html>\n",
522 ),
523 ("w6HDqcOtw7PDug==", "áéíóú"),
524 ("====", ""),
525 ("w6HDq!cOtw7PDug=", ""),
526 ("w6 HD qcOt", "áéí"),
527 ("cmáé", ""),
528 ("áé", ""),
529 ("w\n6\nH\nD\nq\nc\nO\nt\nw\n7\n P\tD u g\n==", "áéíóú"),
530 ("w6HDqcOtw7PDug==", "áéíóú"),
531 ] {
532 assert_eq!(
533 super::base64_decode(encoded_str.as_bytes()).unwrap_or_default(),
534 expected_result.as_bytes(),
535 "Failed for {encoded_str:?}",
536 );
537 }
538 }
539
540 #[test]
541 fn decode_base64_mime() {
542 for (encoded_str, expected_result) in [
543 ("VGVzdA==\r\n--boundary\n", "Test"),
544 (
545 "PCFET0NUWVBFIGh0bWw+CjxodG1sPg\no8Ym9ke\nT4KPC 9ib2R5Pg\n o8L2h0bWw+Cg==\r\n--boundary--\r\n",
546 "<!DOCTYPE html>\n<html>\n<body>\n</body>\n</html>\n",
547 ),
548 ("w6HDqcOtw7PDug==\r\n--boundary \n", "áéíóú"),
549 (
550 "w\n6\nH\nD\nq\nc\nO\nt\nw\n7\n P\tD u g\n==\r\n--boundary\n",
551 "áéíóú",
552 ),
553 ("w6HDqcOtw7PDug==--boundary", "áéíóú"),
554 ("w6HDqcOtw7PDug==\n--boundary--", "áéíóú"),
555 (
556 "w\n6\nH\nD\nq\nc\nO\nt\nw\n7\n P\tD u g\n==\n--boundary",
557 "áéíóú",
558 ),
559 ] {
560 let mut s = MessageStream::new(encoded_str.as_bytes());
561 let (_, result) = s.decode_base64_mime(b"boundary");
562
563 assert_eq!(
564 result,
565 expected_result.as_bytes(),
566 "Failed for {encoded_str:?}",
567 );
568 }
569 }
570
571 #[test]
572 fn decode_base64_word() {
573 for (encoded_str, expected_result) in [
574 ("w 6 H D q c O t w 7 P D u g== ?=", "áéíóú"),
575 ("w6HDqcOtw7PDug==?=", "áéíóú"),
576 ("w6HDqc\n Otw7PDug==?=", "áéíóú"),
577 ("w6HDqcOtw7PDug================?=", "áéíóú"),
578 ("?=", ""),
579 ] {
580 let mut s = MessageStream::new(encoded_str.as_bytes());
581 assert_eq!(
582 s.decode_base64_word().unwrap(),
583 expected_result.as_bytes(),
584 "Failed for {encoded_str:?}",
585 );
586 }
587 }
588}