1use std::char;
5use std::collections::HashMap;
6
7const BASE64ALPHABET: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
8
9pub fn encode(string: &str) -> String {
20 let chars: Vec<char> = string.chars().collect();
21 let alphabet: Vec<char> = BASE64ALPHABET.chars().collect();
22 let mut result = String::new();
23
24 let mut i = 0;
25
26 while i < chars.len() {
27 let chr1 = chars[i] as u32;
28 i += 1;
29
30 let chr2 = if i == chars.len() { 0 } else { chars[i] as u32 };
31 i += 1;
32
33 let chr3 = if i >= chars.len() { 0 } else { chars[i] as u32 };
34 i += 1;
35
36 let res1 = chr1 >> 2;
37 let res2 = ((chr1 & 3) << 4) | (chr2 >> 4);
38
39 let mut res3 = ((chr2 & 15) << 2) | (chr3 >> 6);
40 let mut res4 = chr3 & 63;
41
42 if chr2 == 0 {
43 res3 = 64;
44 res4 = 64;
45 } else if chr3 == 0 {
46 res4 = 64;
47 }
48
49 result.push(alphabet[res1 as usize]);
50 result.push(alphabet[res2 as usize]);
51 result.push(alphabet[res3 as usize]);
52 result.push(alphabet[res4 as usize]);
53 }
54
55 result
56}
57
58pub fn decode(string: &str) -> String {
69 let chars: Vec<char> = string.chars().collect();
70 let alphabet: Vec<char> = BASE64ALPHABET.chars().collect();
71 let mut alphabet_num = HashMap::new();
72 let mut result = String::new();
73
74 for (i, chr) in alphabet.iter().enumerate() {
75 alphabet_num.insert(chr, i as u32);
76 }
77
78 let mut i = 0;
79
80 while i < chars.len() {
81 let mut bits: u32 = 0;
82 let bytes;
83
84 bits |= alphabet_num[&chars[i]] << 18;
85 bits |= alphabet_num[&chars[i + 1]] << 12;
86
87 if alphabet_num[&chars[i + 2]] == 64 {
88 bytes = bits.to_be_bytes()[1..2].to_vec();
89 } else if alphabet_num[&chars[i + 3]] == 64 {
90 bits |= alphabet_num[&chars[i + 2]] << 6;
91 bytes = bits.to_be_bytes()[1..3].to_vec();
92 } else {
93 bits |= alphabet_num[&chars[i + 2]] << 6;
94 bits |= alphabet_num[&chars[i + 3]];
95 bytes = bits.to_be_bytes()[1..4].to_vec();
96 }
97
98 let characters = std::str::from_utf8(&bytes);
99 match characters {
100 Ok(characters) => result.push_str(characters),
101 Err(_) => result.push_str(&String::new()),
102 }
103
104 i += 4;
105 }
106
107 result
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn it_works() {
116 assert_eq!(encode("Hi!"), String::from("SGkh"));
117 assert_eq!(encode("Test"), String::from("VGVzdA=="));
118 assert_eq!(encode("Rust"), String::from("UnVzdA=="));
119 assert_eq!(
120 encode("Lorem ipsum dolor sit amet, consectetur adipiscing elit"),
121 String::from(
122 "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA=="
123 )
124 );
125
126 assert_eq!(decode("SGkh"), String::from("Hi!"));
127 assert_eq!(decode("VGVzdA=="), String::from("Test"));
128 assert_eq!(decode("UnVzdA=="), String::from("Rust"));
129 assert_eq!(
130 decode("TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA=="),
131 String::from("Lorem ipsum dolor sit amet, consectetur adipiscing elit")
132 );
133 }
134}