1pub(crate) fn byte_to_alphabet(byte: u8) -> char {
9 match byte {
10 0..=25 => (b'A' + byte) as char, 26..=51 => (b'a' + (byte - 26)) as char, 52..=61 => (b'0' + (byte - 52)) as char, 62 => '-',
14 63 => '_',
15 _ => '\0',
16 }
17}
18
19pub(crate) fn alphabet_to_byte(byte: u8) -> u8 {
20 match byte {
21 b'A'..=b'Z' => byte - b'A',
22 b'a'..=b'z' => byte - b'a' + 26,
23 b'0'..=b'9' => byte - b'0' + 52,
24 b'-' => 62,
25 b'_' => 63,
26 b'=' => 64,
27 _ => 0,
28 }
29}
30
31pub fn encode(bytes: &[u8]) -> Vec<u8> {
32 let mut result: Vec<u8> = vec![];
33
34 let mut bytes_iter = bytes.iter();
35 while bytes_iter.len() > 0 {
36 let mut block: Vec<u8> = vec![];
38
39 while block.len() < 3 {
40 if let Some(next) = bytes_iter.next() {
41 block.push(*next);
42 } else {
43 break;
44 }
45 }
46
47 let missing_bytes = 3 - block.len();
48
49 let mut carry = 0;
52 let mut carry_bits: i32 = 0;
53 for byte in block {
54 let mut chunk = 0;
55 let bits_left = 6 - carry_bits;
56 if bits_left > 0 {
57 chunk = byte >> (8 - bits_left);
58 }
59 chunk |= carry << bits_left;
61 carry_bits = 8 - bits_left;
62 carry = byte & ((1 << carry_bits) - 1);
63 result.push(byte_to_alphabet(chunk) as u8);
64 }
65 let chunk = carry << (6 - carry_bits);
66 result.push(byte_to_alphabet(chunk) as u8);
67
68 if missing_bytes == 1 {
69 result.push(b'=');
70 }
71 if missing_bytes == 2 {
72 result.push(b'=');
73 result.push(b'=');
74 }
75 }
76
77 result
78}
79
80pub fn decode(bytes: &[u8]) -> Vec<u8> {
81 let mut result = vec![];
82 let mut carry_bits: u8 = 0;
83
84 for (i, byte) in bytes.iter().enumerate() {
85 let val = alphabet_to_byte(*byte);
86 if val == 64 {
87 break;
88 }
89
90 if carry_bits == 6 {
92 carry_bits = 0;
93 continue;
94 }
95
96 let bit_1 = alphabet_to_byte(*byte) & ((1 << (6 - carry_bits)) - 1);
97 carry_bits = 8 - (6 - carry_bits);
98
99 if i + 1 >= bytes.len() {
101 break;
102 }
103 let next_val = alphabet_to_byte(bytes[i + 1]);
104 if next_val == 64 {
105 break;
106 }
107 let bit_2 = next_val >> (6 - carry_bits);
108
109 let bits = (bit_1 << (carry_bits)) | bit_2;
110 result.push(bits);
111 }
112
113 result
114}