mail_parser/decoders/
base64.rs

1/*
2 * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
3 *
4 * SPDX-License-Identifier: Apache-2.0 OR MIT
5 */
6
7use std::borrow::Cow;
8
9use crate::parsers::MessageStream;
10
11#[inline(always)]
12pub fn base64_decode(bytes: &[u8]) -> Option<Vec<u8>> {
13    base64_decode_stream(bytes.iter(), bytes.len(), u8::MAX)
14}
15
16pub fn base64_decode_stream<'x>(
17    stream: impl Iterator<Item = &'x u8>,
18    stream_len: usize,
19    stop_char: u8,
20) -> Option<Vec<u8>> {
21    let mut chunk: u32 = 0;
22    let mut byte_count: u8 = 0;
23
24    let mut buf = Vec::with_capacity(stream_len / 4 * 3);
25
26    for &ch in stream {
27        let val = BASE64_MAP[byte_count as usize][ch as usize];
28
29        if val < 0x01ffffff {
30            byte_count = (byte_count + 1) & 3;
31
32            if byte_count == 1 {
33                chunk = val;
34            } else {
35                chunk |= val;
36
37                if byte_count == 0 {
38                    buf.extend_from_slice(&chunk.to_le_bytes()[0..3]);
39                }
40            }
41        } else {
42            match ch {
43                b'=' => match byte_count {
44                    1 | 2 => {
45                        buf.push(chunk.to_le_bytes()[0]);
46                        byte_count = 0;
47                    }
48                    3 => {
49                        buf.extend_from_slice(&chunk.to_le_bytes()[0..2]);
50                        byte_count = 0;
51                    }
52                    0 => (),
53                    _ => {
54                        return None;
55                    }
56                },
57                b' ' | b'\t' | b'\r' | b'\n' => (),
58                _ => return if ch == stop_char { buf.into() } else { None },
59            }
60        }
61    }
62
63    buf.into()
64}
65
66impl<'x> MessageStream<'x> {
67    pub fn decode_base64_mime(&mut self, boundary: &[u8]) -> (usize, Cow<'x, [u8]>) {
68        let mut chunk: u32 = 0;
69        let mut byte_count: u8 = 0;
70
71        let mut buf = Vec::with_capacity(self.remaining() / 4 * 3);
72        let mut last_ch = b'\n';
73        let mut before_last_ch = 0;
74        let mut end_pos = self.offset();
75
76        self.checkpoint();
77
78        while let Some(&ch) = self.next() {
79            let val = BASE64_MAP[byte_count as usize][ch as usize];
80
81            if val < 0x01ffffff {
82                byte_count = (byte_count + 1) & 3;
83
84                if byte_count == 1 {
85                    chunk = val;
86                } else {
87                    chunk |= val;
88
89                    if byte_count == 0 {
90                        buf.extend_from_slice(&chunk.to_le_bytes()[0..3]);
91                    }
92                }
93            } else {
94                match ch {
95                    b'=' => match byte_count {
96                        1 | 2 => {
97                            buf.push(chunk.to_le_bytes()[0]);
98                            byte_count = 0;
99                        }
100                        3 => {
101                            buf.extend_from_slice(&chunk.to_le_bytes()[0..2]);
102                            byte_count = 0;
103                        }
104                        0 => (),
105                        _ => {
106                            self.restore();
107                            return (usize::MAX, b""[..].into());
108                        }
109                    },
110                    b'\n' => {
111                        end_pos = if last_ch == b'\r' {
112                            self.offset() - 2
113                        } else {
114                            self.offset() - 1
115                        }
116                    }
117                    b' ' | b'\t' | b'\r' => (),
118                    b'-' => {
119                        if last_ch == b'-' {
120                            return if !boundary.is_empty() && self.try_skip(boundary) {
121                                buf.shrink_to_fit();
122                                (
123                                    if before_last_ch == b'\n' {
124                                        end_pos
125                                    } else {
126                                        self.offset() - boundary.len() - 2
127                                    },
128                                    buf.into(),
129                                )
130                            } else {
131                                self.restore();
132                                (usize::MAX, b""[..].into())
133                            };
134                        }
135                    }
136                    _ => {
137                        self.restore();
138                        return (usize::MAX, b""[..].into());
139                    }
140                }
141            }
142
143            before_last_ch = last_ch;
144            last_ch = ch;
145        }
146
147        buf.shrink_to_fit();
148        (
149            if boundary.is_empty() {
150                self.offset()
151            } else {
152                self.restore();
153                usize::MAX
154            },
155            buf.into(),
156        )
157    }
158
159    pub fn decode_base64_word(&mut self) -> Option<Vec<u8>> {
160        let mut chunk: u32 = 0;
161        let mut byte_count: u8 = 0;
162        let mut buf = Vec::with_capacity(64);
163
164        while let Some(&ch) = self.next() {
165            match ch {
166                b'=' => {
167                    match byte_count {
168                        1 | 2 => {
169                            buf.push(chunk.to_le_bytes()[0]);
170                            byte_count = 0;
171                        }
172                        3 => {
173                            buf.extend_from_slice(&chunk.to_le_bytes()[0..2]);
174                            byte_count = 0;
175                        }
176                        0 => (),
177                        _ => {
178                            // Invalid
179                            break;
180                        }
181                    }
182                }
183                b'?' => {
184                    if let Some(b'=') = self.next() {
185                        return Some(buf);
186                    } else {
187                        break;
188                    }
189                }
190                b'\n' => {
191                    if !self.next_is_space() {
192                        break;
193                    }
194                }
195                b' ' | b'\t' | b'\r' => (),
196                _ => {
197                    let val = BASE64_MAP[byte_count as usize][ch as usize];
198
199                    if val < 0x01ffffff {
200                        byte_count = (byte_count + 1) & 3;
201
202                        if byte_count == 1 {
203                            chunk = val;
204                        } else {
205                            chunk |= val;
206
207                            if byte_count == 0 {
208                                buf.extend_from_slice(&chunk.to_le_bytes()[0..3]);
209                            }
210                        }
211                    } else {
212                        break;
213                    }
214                }
215            }
216        }
217
218        None
219    }
220}
221
222/*
223 * Table adapted from Nick Galbreath's "High performance base64 encoder / decoder"
224 *
225 * Copyright 2005, 2006, 2007 Nick Galbreath -- nickg [at] modp [dot] com
226 * All rights reserved.
227 *
228 * http://code.google.com/p/stringencoders/
229 *
230 * Released under bsd license.
231 *
232 */
233
234pub static BASE64_MAP: &[&[u32]] = &[
235    &[
236        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
237        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
238        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
239        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
240        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
241        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
242        0x01ffffff, 0x000000f8, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000fc, 0x000000d0,
243        0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4, 0x000000e8, 0x000000ec,
244        0x000000f0, 0x000000f4, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
245        0x01ffffff, 0x01ffffff, 0x00000000, 0x00000004, 0x00000008, 0x0000000c, 0x00000010,
246        0x00000014, 0x00000018, 0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c,
247        0x00000030, 0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048,
248        0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060, 0x00000064,
249        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000068,
250        0x0000006c, 0x00000070, 0x00000074, 0x00000078, 0x0000007c, 0x00000080, 0x00000084,
251        0x00000088, 0x0000008c, 0x00000090, 0x00000094, 0x00000098, 0x0000009c, 0x000000a0,
252        0x000000a4, 0x000000a8, 0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc,
253        0x000000c0, 0x000000c4, 0x000000c8, 0x000000cc, 0x01ffffff, 0x01ffffff, 0x01ffffff,
254        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
255        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
256        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
257        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
258        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
259        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
260        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
261        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
262        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
263        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
264        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
265        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
266        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
267        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
268        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
269        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
270        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
271        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
272        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
273    ],
274    &[
275        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
276        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
277        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
278        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
279        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
280        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
281        0x01ffffff, 0x0000e003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000f003, 0x00004003,
282        0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003, 0x0000a003, 0x0000b003,
283        0x0000c003, 0x0000d003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
284        0x01ffffff, 0x01ffffff, 0x00000000, 0x00001000, 0x00002000, 0x00003000, 0x00004000,
285        0x00005000, 0x00006000, 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000,
286        0x0000c000, 0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001,
287        0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001, 0x00009001,
288        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000a001,
289        0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001, 0x0000f001, 0x00000002, 0x00001002,
290        0x00002002, 0x00003002, 0x00004002, 0x00005002, 0x00006002, 0x00007002, 0x00008002,
291        0x00009002, 0x0000a002, 0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002,
292        0x00000003, 0x00001003, 0x00002003, 0x00003003, 0x01ffffff, 0x01ffffff, 0x01ffffff,
293        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
294        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
295        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
296        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
297        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
298        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
299        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
300        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
301        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
302        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
303        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
304        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
305        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
306        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
307        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
308        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
309        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
310        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
311        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
312    ],
313    &[
314        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
315        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
316        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
317        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
318        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
319        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
320        0x01ffffff, 0x00800f00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00c00f00, 0x00000d00,
321        0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00, 0x00800e00, 0x00c00e00,
322        0x00000f00, 0x00400f00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
323        0x01ffffff, 0x01ffffff, 0x00000000, 0x00400000, 0x00800000, 0x00c00000, 0x00000100,
324        0x00400100, 0x00800100, 0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200,
325        0x00000300, 0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400,
326        0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600, 0x00400600,
327        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00800600,
328        0x00c00600, 0x00000700, 0x00400700, 0x00800700, 0x00c00700, 0x00000800, 0x00400800,
329        0x00800800, 0x00c00800, 0x00000900, 0x00400900, 0x00800900, 0x00c00900, 0x00000a00,
330        0x00400a00, 0x00800a00, 0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00,
331        0x00000c00, 0x00400c00, 0x00800c00, 0x00c00c00, 0x01ffffff, 0x01ffffff, 0x01ffffff,
332        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
333        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
334        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
335        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
336        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
337        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
338        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
339        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
340        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
341        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
342        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
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, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
350        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
351    ],
352    &[
353        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
354        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
355        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
356        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
357        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
358        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
359        0x01ffffff, 0x003e0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003f0000, 0x00340000,
360        0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000, 0x003a0000, 0x003b0000,
361        0x003c0000, 0x003d0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
362        0x01ffffff, 0x01ffffff, 0x00000000, 0x00010000, 0x00020000, 0x00030000, 0x00040000,
363        0x00050000, 0x00060000, 0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000,
364        0x000c0000, 0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000,
365        0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000, 0x00190000,
366        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x001a0000,
367        0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000, 0x001f0000, 0x00200000, 0x00210000,
368        0x00220000, 0x00230000, 0x00240000, 0x00250000, 0x00260000, 0x00270000, 0x00280000,
369        0x00290000, 0x002a0000, 0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000,
370        0x00300000, 0x00310000, 0x00320000, 0x00330000, 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, 0x01ffffff, 0x01ffffff, 0x01ffffff,
380        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
381        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
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, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
389        0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
390    ],
391];
392
393#[cfg(test)]
394mod tests {
395    use crate::parsers::MessageStream;
396
397    #[test]
398    fn decode_base64() {
399        for (encoded_str, expected_result) in [
400            ("VGVzdA==", "Test"),
401            ("WWU=", "Ye"),
402            ("QQ==", "A"),
403            ("cm8=", "ro"),
404            (
405                "QXJlIHlvdSBhIFNoaW1hbm8gb3IgQ2FtcGFnbm9sbyBwZXJzb24/",
406                "Are you a Shimano or Campagnolo person?",
407            ),
408            (
409                "PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8Ym9keT4KPC9ib2R5Pgo8L2h0bWw+Cg==",
410                "<!DOCTYPE html>\n<html>\n<body>\n</body>\n</html>\n",
411            ),
412            (
413                "PCFET0NUWVBFIGh0bWw+CjxodG1sPg\no8Ym9ke\nT4KPC 9ib2R5Pg\n o8L2h0bWw+Cg==",
414                "<!DOCTYPE html>\n<html>\n<body>\n</body>\n</html>\n",
415            ),
416            ("w6HDqcOtw7PDug==", "áéíóú"),
417            ("====", ""),
418            ("w6HDq!cOtw7PDug=", ""),
419            ("w6 HD qcOt", "áéí"),
420            ("cmáé", ""),
421            ("áé", ""),
422            ("w\n6\nH\nD\nq\nc\nO\nt\nw\n7\n P\tD u g\n==", "áéíóú"),
423            ("w6HDqcOtw7PDug==", "áéíóú"),
424        ] {
425            assert_eq!(
426                super::base64_decode(encoded_str.as_bytes()).unwrap_or_default(),
427                expected_result.as_bytes(),
428                "Failed for {encoded_str:?}",
429            );
430        }
431    }
432
433    #[test]
434    fn decode_base64_mime() {
435        for (encoded_str, expected_result) in [
436            ("VGVzdA==\r\n--boundary\n", "Test"),
437            (
438                "PCFET0NUWVBFIGh0bWw+CjxodG1sPg\no8Ym9ke\nT4KPC 9ib2R5Pg\n o8L2h0bWw+Cg==\r\n--boundary--\r\n",
439                "<!DOCTYPE html>\n<html>\n<body>\n</body>\n</html>\n",
440            ),
441            ("w6HDqcOtw7PDug==\r\n--boundary \n", "áéíóú"),
442            ("w\n6\nH\nD\nq\nc\nO\nt\nw\n7\n P\tD u g\n==\r\n--boundary\n", "áéíóú"),
443            ("w6HDqcOtw7PDug==--boundary", "áéíóú"),
444            (
445                "w6HDqcOtw7PDug==\n--boundary--",
446                "áéíóú",
447            ),
448            (
449                "w\n6\nH\nD\nq\nc\nO\nt\nw\n7\n P\tD u g\n==\n--boundary",
450                "áéíóú",
451            ),
452        ] {
453            let mut s = MessageStream::new(encoded_str.as_bytes());
454            let (_, result) = s.decode_base64_mime(b"boundary");
455
456            assert_eq!(
457                result,
458                expected_result.as_bytes(),
459                "Failed for {encoded_str:?}",
460            );
461        }
462    }
463
464    #[test]
465    fn decode_base64_word() {
466        for (encoded_str, expected_result) in [
467            ("w 6 H D q c O t w 7 P D u g==  ?=", "áéíóú"),
468            ("w6HDqcOtw7PDug==?=", "áéíóú"),
469            ("w6HDqc\n  Otw7PDug==?=", "áéíóú"),
470            ("w6HDqcOtw7PDug================?=", "áéíóú"),
471            ("?=", ""),
472        ] {
473            let mut s = MessageStream::new(encoded_str.as_bytes());
474            assert_eq!(
475                s.decode_base64_word().unwrap(),
476                expected_result.as_bytes(),
477                "Failed for {encoded_str:?}",
478            );
479        }
480    }
481}