1const STANDARD_TABLE: &[u8; 64] =
2 b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3const URL_TABLE: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
4
5fn encode_with_table(input: &[u8], table: &[u8; 64], pad: bool) -> String {
6 let mut output = String::with_capacity(input.len().div_ceil(3) * 4);
7 let mut i = 0;
8
9 while i + 3 <= input.len() {
10 let block =
11 ((input[i] as u32) << 16) | ((input[i + 1] as u32) << 8) | (input[i + 2] as u32);
12 output.push(table[((block >> 18) & 0x3f) as usize] as char);
13 output.push(table[((block >> 12) & 0x3f) as usize] as char);
14 output.push(table[((block >> 6) & 0x3f) as usize] as char);
15 output.push(table[(block & 0x3f) as usize] as char);
16 i += 3;
17 }
18
19 let remainder = input.len() - i;
20 if remainder == 1 {
21 let block = (input[i] as u32) << 16;
22 output.push(table[((block >> 18) & 0x3f) as usize] as char);
23 output.push(table[((block >> 12) & 0x3f) as usize] as char);
24 if pad {
25 output.push_str("==");
26 }
27 } else if remainder == 2 {
28 let block = ((input[i] as u32) << 16) | ((input[i + 1] as u32) << 8);
29 output.push(table[((block >> 18) & 0x3f) as usize] as char);
30 output.push(table[((block >> 12) & 0x3f) as usize] as char);
31 output.push(table[((block >> 6) & 0x3f) as usize] as char);
32 if pad {
33 output.push('=');
34 }
35 }
36
37 output
38}
39
40pub fn encode(input: &[u8]) -> String {
42 encode_with_table(input, STANDARD_TABLE, true)
43}
44
45pub fn encode_url(input: &[u8]) -> String {
47 encode_with_table(input, URL_TABLE, false)
48}
49
50pub fn encode_url_padded(input: &[u8]) -> String {
52 encode_with_table(input, URL_TABLE, true)
53}