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