base64cr/
lib.rs

1#![forbid(unsafe_code)]
2extern crate alloc;
3use alloc::vec::Vec;
4
5use constants::{D0, D1, D2, D3, E0, E1, E2};
6
7mod constants {
8    pub(crate) static E0: [char; 256] = [
9        'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 'D', 'E', 'E',
10        'E', 'E', 'F', 'F', 'F', 'F', 'G', 'G', 'G', 'G', 'H', 'H', 'H', 'H', 'I', 'I', 'I', 'I',
11        'J', 'J', 'J', 'J', 'K', 'K', 'K', 'K', 'L', 'L', 'L', 'L', 'M', 'M', 'M', 'M', 'N', 'N',
12        'N', 'N', 'O', 'O', 'O', 'O', 'P', 'P', 'P', 'P', 'Q', 'Q', 'Q', 'Q', 'R', 'R', 'R', 'R',
13        'S', 'S', 'S', 'S', 'T', 'T', 'T', 'T', 'U', 'U', 'U', 'U', 'V', 'V', 'V', 'V', 'W', 'W',
14        'W', 'W', 'X', 'X', 'X', 'X', 'Y', 'Y', 'Y', 'Y', 'Z', 'Z', 'Z', 'Z', 'a', 'a', 'a', 'a',
15        'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd', 'd', 'd', 'e', 'e', 'e', 'e', 'f', 'f',
16        'f', 'f', 'g', 'g', 'g', 'g', 'h', 'h', 'h', 'h', 'i', 'i', 'i', 'i', 'j', 'j', 'j', 'j',
17        'k', 'k', 'k', 'k', 'l', 'l', 'l', 'l', 'm', 'm', 'm', 'm', 'n', 'n', 'n', 'n', 'o', 'o',
18        'o', 'o', 'p', 'p', 'p', 'p', 'q', 'q', 'q', 'q', 'r', 'r', 'r', 'r', 's', 's', 's', 's',
19        't', 't', 't', 't', 'u', 'u', 'u', 'u', 'v', 'v', 'v', 'v', 'w', 'w', 'w', 'w', 'x', 'x',
20        'x', 'x', 'y', 'y', 'y', 'y', 'z', 'z', 'z', 'z', '0', '0', '0', '0', '1', '1', '1', '1',
21        '2', '2', '2', '2', '3', '3', '3', '3', '4', '4', '4', '4', '5', '5', '5', '5', '6', '6',
22        '6', '6', '7', '7', '7', '7', '8', '8', '8', '8', '9', '9', '9', '9', '+', '+', '+', '+',
23        '/', '/', '/', '/',
24    ];
25
26    pub(crate) static E1: [char; 256] = [
27        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
28        'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
29        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1',
30        '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
31        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
32        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
33        's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
34        '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
35        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
36        'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
37        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F',
38        'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
39        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
40        'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
41        '8', '9', '+', '/',
42    ];
43
44    pub(crate) static E2: [char; 256] = [
45        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
46        'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
47        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1',
48        '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
49        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
50        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
51        's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
52        '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
53        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
54        'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
55        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F',
56        'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
57        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
58        'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
59        '8', '9', '+', '/',
60    ];
61
62    const FF: u32 = 33554431;
63
64    pub(crate) static D0: [u32; 256] = [
65        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
66        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, 248, FF,
67        FF, FF, 252, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, FF, FF, FF, FF, FF, FF, FF,
68        0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88,
69        92, 96, 100, FF, FF, FF, FF, FF, FF, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
70        148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, FF, FF, FF, FF,
71        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
72        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
73        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
74        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
75        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
76        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
77    ];
78
79    pub(crate) static D1: [u32; 256] = [
80        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
81        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, 57347, FF,
82        FF, FF, 61443, 16387, 20483, 24579, 28675, 32771, 36867, 40963, 45059, 49155, 53251, FF,
83        FF, FF, FF, FF, FF, FF, 0, 4096, 8192, 12288, 16384, 20480, 24576, 28672, 32768, 36864,
84        40960, 45056, 49152, 53248, 57344, 61440, 1, 4097, 8193, 12289, 16385, 20481, 24577, 28673,
85        32769, 36865, FF, FF, FF, FF, FF, FF, 40961, 45057, 49153, 53249, 57345, 61441, 2, 4098,
86        8194, 12290, 16386, 20482, 24578, 28674, 32770, 36866, 40962, 45058, 49154, 53250, 57346,
87        61442, 3, 4099, 8195, 12291, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
88        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
89        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
90        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
91        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
92        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
93        FF, FF, FF,
94    ];
95
96    pub(crate) static D2: [u32; 256] = [
97        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
98        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, 8392448,
99        FF, FF, FF, 12586752, 3328, 4197632, 8391936, 12586240, 3584, 4197888, 8392192, 12586496,
100        3840, 4198144, FF, FF, FF, FF, FF, FF, FF, 0, 4194304, 8388608, 12582912, 256, 4194560,
101        8388864, 12583168, 512, 4194816, 8389120, 12583424, 768, 4195072, 8389376, 12583680, 1024,
102        4195328, 8389632, 12583936, 1280, 4195584, 8389888, 12584192, 1536, 4195840, FF, FF, FF,
103        FF, FF, FF, 8390144, 12584448, 1792, 4196096, 8390400, 12584704, 2048, 4196352, 8390656,
104        12584960, 2304, 4196608, 8390912, 12585216, 2560, 4196864, 8391168, 12585472, 2816,
105        4197120, 8391424, 12585728, 3072, 4197376, 8391680, 12585984, FF, FF, FF, FF, FF, FF, FF,
106        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
107        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
108        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
109        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
110        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
111        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
112    ];
113
114    pub(crate) static D3: [u32; 256] = [
115        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
116        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, 4063232,
117        FF, FF, FF, 4128768, 3407872, 3473408, 3538944, 3604480, 3670016, 3735552, 3801088,
118        3866624, 3932160, 3997696, FF, FF, FF, FF, FF, FF, FF, 0, 65536, 131072, 196608, 262144,
119        327680, 393216, 458752, 524288, 589824, 655360, 720896, 786432, 851968, 917504, 983040,
120        1048576, 1114112, 1179648, 1245184, 1310720, 1376256, 1441792, 1507328, 1572864, 1638400,
121        FF, FF, FF, FF, FF, FF, 1703936, 1769472, 1835008, 1900544, 1966080, 2031616, 2097152,
122        2162688, 2228224, 2293760, 2359296, 2424832, 2490368, 2555904, 2621440, 2686976, 2752512,
123        2818048, 2883584, 2949120, 3014656, 3080192, 3145728, 3211264, 3276800, 3342336, FF, FF,
124        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
125        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
126        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
127        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
128        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
129        FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF,
130    ];
131}
132
133pub trait Base64 {
134    fn encode(&self) -> Vec<u8>;
135    fn decode(&self) -> Vec<u8>;
136}
137
138impl Base64 for [u8] {
139    fn encode(&self) -> Vec<u8> {
140        let self_ = self.as_ref();
141        let len = self_.len();
142
143        let mut dest = vec![0u8; ((4 * len / 3) + 3) & !3];
144
145        let mut i = 0;
146        let mut j = 0;
147
148        if len > 2 {
149            while i < len - 2 {
150                let t1 = self_[i];
151                let t2 = self_[i + 1];
152                let t3 = self_[i + 2];
153
154                dest[j] = E0[t1 as usize] as u8;
155                dest[j + 1] = E1[(((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)) as usize] as u8;
156                dest[j + 2] = E1[(((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)) as usize] as u8;
157                dest[j + 3] = E2[t3 as usize] as u8;
158
159                i += 3;
160                j += 4;
161            }
162        }
163        match len - i {
164            0 => {}
165            1 => {
166                let t1 = self_[i];
167
168                dest[j] = E0[t1 as usize] as u8;
169                dest[j + 1] = E1[((t1 & 0x03) << 4) as usize] as u8;
170                dest[j + 2] = b'=';
171                dest[j + 3] = b'=';
172            }
173            _ => {
174                /* case 2 */
175                let t1 = self_[i] as usize;
176                let t2 = self_[i + 1] as usize;
177
178                dest[j] = E0[t1] as u8;
179                dest[j + 1] = E1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)] as u8;
180                dest[j + 2] = E2[(t2 & 0x0F) << 2] as u8;
181                dest[j + 3] = b'=';
182            }
183        }
184
185        dest
186    }
187
188    fn decode(&self) -> Vec<u8> {
189        let self_ = self.as_ref();
190        let mut len = self_.len();
191
192        if self_[len - 1] == b'=' {
193            len -= 1;
194            if self_[len - 1] == b'=' {
195                len -= 1;
196            }
197        }
198
199        let mut dest = vec![0u8; (3 * (self_.len() / 4)) - (self_.len() - len)];
200
201
202        let leftover = len % 4;
203        let chunks = if leftover == 0 { len / 4 - 1 } else { len / 4 };
204
205        let mut j = 0;
206        let mut k = 0;
207        for _ in 0..chunks {
208            let x: u32 = D0[self_[k] as usize]
209                | D1[self_[1 + k] as usize]
210                | D2[self_[2 + k] as usize]
211                | D3[self_[3 + k] as usize];
212
213            dest[j + 0] = x as u8;
214            dest[j + 1] = (x >> 8) as u8;
215            dest[j + 2] = (x >> 16) as u8;
216
217            j += 3;
218            k += 4;
219        }
220
221        match leftover {
222            0 => {
223                let x: u32 = D0[self_[k] as usize]
224                    | D1[self_[1 + k] as usize]
225                    | D2[self_[2 + k] as usize]
226                    | D3[self_[3 + k] as usize];
227
228                dest[j + 0] = x as u8;
229                dest[j + 1] = (x >> 8) as u8;
230                dest[j + 2] = (x >> 16) as u8;
231
232                // (chunks + 1) * 3)
233                return dest
234            }
235            1 => {
236                /* with padding this is an impossible case */
237                let x: u32 = D0[self_[k] as usize]; // i.e. first char/byte in int
238                dest[j + 0] = x as u8;
239            }
240            2 => {
241                // * case 2, 1  output byte */
242                let x: u32 = D0[self_[k] as usize] | D1[self_[1 + k] as usize]; // i.e. first char
243                dest[j + 0] = x as u8;
244            }
245            _ => {
246                let x: u32 =
247                    D0[self_[k] as usize] | D1[self_[1 + k] as usize] | D2[self_[2 + k] as usize]; /* 0x3c */
248                dest[j + 0] = x as u8;
249                dest[j + 1] = (x >> 8) as u8;
250            }
251        }
252
253        // 3 * chunks + (6 * leftover) / 8
254        dest
255    }
256}
257
258#[cfg(test)]
259#[test]
260pub fn test_examples() {
261    const EXAMPLES: [(&[u8], &[u8]); 3] = [
262        (b"abc123!?$*&()'-=@~", b"YWJjMTIzIT8kKiYoKSctPUB+"),
263        (b"TutorialsPoint?java8", b"VHV0b3JpYWxzUG9pbnQ/amF2YTg="),
264        (
265            b"Man is distinguished, not only by his reason, but by this singular passion from \
266            other animals, which is a lust of the mind, that by a perseverance of delight \
267            in the continued and indefatigable generation of knowledge, exceeds the short \
268            vehemence of any carnal pleasure.",
269            b"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz\
270            IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg\
271            dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu\
272            dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo\
273            ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=",
274        ),
275    ];
276
277    for &(input, answer) in EXAMPLES.iter() {
278        let res = input.encode();
279        assert_eq!(answer, res);
280
281        let res = answer.decode();
282        assert_eq!(input, res);
283    }
284}