1use std::io::{self, Write};
13
14const CHARPAD: u8 = b'=';
15
16#[inline(always)]
17pub fn base64_encode(input: &[u8]) -> io::Result<Vec<u8>> {
18 let mut buf = Vec::with_capacity(4 * (input.len() / 3));
19 base64_encode_mime(input, &mut buf, true)?;
20 Ok(buf)
21}
22
23pub fn base64_encode_mime(input: &[u8], mut output: impl Write, is_inline: bool) -> io::Result<usize> {
24 let mut i = 0;
25 let mut t1;
26 let mut t2;
27 let mut t3;
28 let mut bytes_written = 0;
29
30 if input.len() > 2 {
31 while i < input.len() - 2 {
32 #[cfg(not(feature = "ludicrous_mode"))]
33 {
34 t1 = input[i];
35 t2 = input[i + 1];
36 t3 = input[i + 2];
37
38 output.write_all(&[
39 E0[t1 as usize],
40 E1[(((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)) as usize],
41 E1[(((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)) as usize],
42 E2[t3 as usize],
43 ])?;
44 }
45
46 #[cfg(feature = "ludicrous_mode")]
47 unsafe {
48 t1 = *input.get_unchecked(i);
49 t2 = *input.get_unchecked(i + 1);
50 t3 = *input.get_unchecked(i + 2);
51
52 output.write_all(&[
53 *E0.get_unchecked(t1 as usize),
54 *E1.get_unchecked((((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)) as usize),
55 *E1.get_unchecked((((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)) as usize),
56 *E2.get_unchecked(t3 as usize),
57 ])?;
58 }
59
60 bytes_written += 4;
61
62 if !is_inline && bytes_written % 19 == 0 {
63 output.write_all(b"\r\n")?;
64 }
65
66 i += 3;
67 }
68 }
69
70 let remaining = input.len() - i;
71 if remaining > 0 {
72 #[cfg(not(feature = "ludicrous_mode"))]
73 {
74 t1 = input[i];
75 if remaining == 1 {
76 output.write_all(&[E0[t1 as usize], E1[((t1 & 0x03) << 4) as usize], CHARPAD, CHARPAD])?;
77 } else {
78 t2 = input[i + 1];
79 output.write_all(&[
80 E0[t1 as usize],
81 E1[(((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)) as usize],
82 E2[((t2 & 0x0F) << 2) as usize],
83 CHARPAD,
84 ])?;
85 }
86 }
87
88 #[cfg(feature = "ludicrous_mode")]
89 unsafe {
90 t1 = *input.get_unchecked(i);
91 if remaining == 1 {
92 output.write_all(&[
93 *E0.get_unchecked(t1 as usize),
94 *E1.get_unchecked(((t1 & 0x03) << 4) as usize),
95 CHARPAD,
96 CHARPAD,
97 ])?;
98 } else {
99 t2 = *input.get_unchecked(i + 1);
100 output.write_all(&[
101 *E0.get_unchecked(t1 as usize),
102 *E1.get_unchecked((((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)) as usize),
103 *E2.get_unchecked(((t2 & 0x0F) << 2) as usize),
104 CHARPAD,
105 ])?;
106 }
107 }
108
109 bytes_written += 4;
110
111 if !is_inline && bytes_written % 19 == 0 {
112 output.write_all(b"\r\n")?;
113 }
114 }
115
116 if !is_inline && bytes_written % 19 != 0 {
117 output.write_all(b"\r\n")?;
118 }
119
120 Ok(bytes_written)
121}
122
123#[cfg(test)]
124mod tests {
125
126 #[test]
127 fn encode_base64() {
128 for (input, expected_result, is_inline) in [
129 ("Test".to_string(), "VGVzdA==\r\n", false),
130 ("Ye".to_string(), "WWU=\r\n", false),
131 ("A".to_string(), "QQ==\r\n", false),
132 ("ro".to_string(), "cm8=\r\n", false),
133 (
134 "Are you a Shimano or Campagnolo person?".to_string(),
135 "QXJlIHlvdSBhIFNoaW1hbm8gb3IgQ2FtcGFnbm9sbyBwZXJzb24/\r\n",
136 false,
137 ),
138 (
139 "<!DOCTYPE html>\n<html>\n<body>\n</body>\n</html>\n".to_string(),
140 "PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8Ym9keT4KPC9ib2R5Pgo8L2h0bWw+Cg==\r\n",
141 false,
142 ),
143 ("áéíóú".to_string(), "w6HDqcOtw7PDug==\r\n", false),
144 (
145 " ".repeat(100),
146 concat!(
147 "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg",
148 "ICAgICAgICAgICAgICAgICAgICAgICAgICAg\r\n",
149 "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg",
150 "ICAgICAgICAgICAgIA==\r\n",
151 ),
152 false,
153 ),
154 ] {
155 let mut output = Vec::new();
156 super::base64_encode_mime(input.as_bytes(), &mut output, is_inline).unwrap();
157 assert_eq!(std::str::from_utf8(&output).unwrap(), expected_result);
158 }
159 }
160}
161
162pub static E0: &[u8] = &[
175 b'A', b'A', b'A', b'A', b'B', b'B', b'B', b'B', b'C', b'C', b'C', b'C', b'D', b'D', b'D', b'D', b'E', b'E', b'E',
176 b'E', b'F', b'F', b'F', b'F', b'G', b'G', b'G', b'G', b'H', b'H', b'H', b'H', b'I', b'I', b'I', b'I', b'J', b'J',
177 b'J', b'J', b'K', b'K', b'K', b'K', b'L', b'L', b'L', b'L', b'M', b'M', b'M', b'M', b'N', b'N', b'N', b'N', b'O',
178 b'O', b'O', b'O', b'P', b'P', b'P', b'P', b'Q', b'Q', b'Q', b'Q', b'R', b'R', b'R', b'R', b'S', b'S', b'S', b'S',
179 b'T', b'T', b'T', b'T', b'U', b'U', b'U', b'U', b'V', b'V', b'V', b'V', b'W', b'W', b'W', b'W', b'X', b'X', b'X',
180 b'X', b'Y', b'Y', b'Y', b'Y', b'Z', b'Z', b'Z', b'Z', b'a', b'a', b'a', b'a', b'b', b'b', b'b', b'b', b'c', b'c',
181 b'c', b'c', b'd', b'd', b'd', b'd', b'e', b'e', b'e', b'e', b'f', b'f', b'f', b'f', b'g', b'g', b'g', b'g', b'h',
182 b'h', b'h', b'h', b'i', b'i', b'i', b'i', b'j', b'j', b'j', b'j', b'k', b'k', b'k', b'k', b'l', b'l', b'l', b'l',
183 b'm', b'm', b'm', b'm', b'n', b'n', b'n', b'n', b'o', b'o', b'o', b'o', b'p', b'p', b'p', b'p', b'q', b'q', b'q',
184 b'q', b'r', b'r', b'r', b'r', b's', b's', b's', b's', b't', b't', b't', b't', b'u', b'u', b'u', b'u', b'v', b'v',
185 b'v', b'v', b'w', b'w', b'w', b'w', b'x', b'x', b'x', b'x', b'y', b'y', b'y', b'y', b'z', b'z', b'z', b'z', b'0',
186 b'0', b'0', b'0', b'1', b'1', b'1', b'1', b'2', b'2', b'2', b'2', b'3', b'3', b'3', b'3', b'4', b'4', b'4', b'4',
187 b'5', b'5', b'5', b'5', b'6', b'6', b'6', b'6', b'7', b'7', b'7', b'7', b'8', b'8', b'8', b'8', b'9', b'9', b'9',
188 b'9', b'+', b'+', b'+', b'+', b'/', b'/', b'/', b'/',
189];
190
191pub static E1: &[u8] = &[
192 b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S',
193 b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l',
194 b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', b'0', b'1', b'2', b'3', b'4',
195 b'5', b'6', b'7', b'8', b'9', b'+', b'/', b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L',
196 b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e',
197 b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x',
198 b'y', b'z', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'+', b'/', b'A', b'B', b'C', b'D', b'E',
199 b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X',
200 b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q',
201 b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9',
202 b'+', b'/', b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q',
203 b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j',
204 b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', b'0', b'1', b'2',
205 b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'+', b'/',
206];
207
208pub static E2: &[u8] = &[
209 b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S',
210 b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l',
211 b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', b'0', b'1', b'2', b'3', b'4',
212 b'5', b'6', b'7', b'8', b'9', b'+', b'/', b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L',
213 b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e',
214 b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x',
215 b'y', b'z', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'+', b'/', b'A', b'B', b'C', b'D', b'E',
216 b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X',
217 b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q',
218 b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9',
219 b'+', b'/', b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q',
220 b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j',
221 b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', b'0', b'1', b'2',
222 b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'+', b'/',
223];