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 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 return dest
234 }
235 1 => {
236 let x: u32 = D0[self_[k] as usize]; dest[j + 0] = x as u8;
239 }
240 2 => {
241 let x: u32 = D0[self_[k] as usize] | D1[self_[1 + k] as usize]; 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]; dest[j + 0] = x as u8;
249 dest[j + 1] = (x >> 8) as u8;
250 }
251 }
252
253 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}