struct B64 {
table: Vec<char>,
}
impl B64 {
fn new() -> B64 {
B64{table: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".chars().collect()}
}
fn encode(&self, s: &str) -> String {
let mut bs: Vec<bool> = s.as_bytes().iter()
.flat_map(|b| (0..8).map(move |i| b >> (7 - i) & 1u8 != 0u8)).collect();
for _ in 0..6 - bs.len() % 6 {bs.push(false)}
let mut cs: Vec<char> = bs.chunks(6)
.map(|b6| b6.iter().enumerate().fold(0, |acc, (i, b)| acc + ((*b as u8) << (5 - i))))
.map(|u| self.table[u as usize]).collect();
for _ in 0..4 - cs.len() % 4 {cs.push('=')}
cs.into_iter().collect()
}
fn decode(&self, s: &str) -> String {
let mut bs: Vec<bool> = s.chars().take_while(|d| *d != '=')
.flat_map(|c| self.table.iter().position(|e| *e == c))
.flat_map(|b| (0..6).map(move |i| b as u8 >> (5 - i) & 1u8 != 0u8)).collect();
let newlen = bs.len() - bs.len() % 8;
bs.truncate(newlen);
let us: Vec<u8> = bs.chunks(8)
.map(|b8| b8.iter().enumerate().fold(0, |acc, (i, b)| acc + ((*b as u8) << (7 - i))))
.collect();
String::from_utf8(us).unwrap_or(String::new())
}
}
fn main() {
let b64 = B64::new();
let p = |s| {
let e = b64.encode(s);
let d = b64.decode(e.as_str());
println!("{}\n{}\n{}\n", s, e, d);
};
p("ABCDEFG");
p("Hello, World!");
p("0123456789\"#$%&'()`=@");
p("💖");
}
c3RydWN0IEI2NCB7CiAgICB0YWJsZTogVmVjPGNoYXI+LAp9CmltcGwgQjY0IHsKICAgIGZuIG5ldygpIC0+IEI2NCB7CiAgICAgICAgQjY0e3RhYmxlOiAiQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLyIuY2hhcnMoKS5jb2xsZWN0KCl9CiAgICB9CiAgICBmbiBlbmNvZGUoJnNlbGYsIHM6ICZzdHIpIC0+IFN0cmluZyB7CiAgICAgICAgbGV0IG11dCBiczogVmVjPGJvb2w+ID0gcy5hc19ieXRlcygpLml0ZXIoKQogICAgICAgICAgICAuZmxhdF9tYXAofGJ8ICgwLi44KS5tYXAobW92ZSB8aXwgYiA+PiAoNyAtIGkpICYgMXU4ICE9IDB1OCkpLmNvbGxlY3QoKTsKICAgICAgICBmb3IgXyBpbiAwLi42IC0gYnMubGVuKCkgJSA2IHticy5wdXNoKGZhbHNlKX0KICAgICAgICBsZXQgbXV0IGNzOiBWZWM8Y2hhcj4gPSBicy5jaHVua3MoNikKICAgICAgICAgICAgLm1hcCh8YjZ8IGI2Lml0ZXIoKS5lbnVtZXJhdGUoKS5mb2xkKDAsIHxhY2MsIChpLCBiKXwgYWNjICsgKCgqYiBhcyB1OCkgPDwgKDUgLSBpKSkpKQogICAgICAgICAgICAubWFwKHx1fCBzZWxmLnRhYmxlW3UgYXMgdXNpemVdKS5jb2xsZWN0KCk7CiAgICAgICAgZm9yIF8gaW4gMC4uNCAtIGNzLmxlbigpICUgNCB7Y3MucHVzaCgnPScpfQogICAgICAgIGNzLmludG9faXRlcigpLmNvbGxlY3QoKQogICAgfQogICAgZm4gZGVjb2RlKCZzZWxmLCBzOiAmc3RyKSAtPiBTdHJpbmcgewogICAgICAgIGxldCBtdXQgYnM6IFZlYzxib29sPiA9IHMuY2hhcnMoKS50YWtlX3doaWxlKHxkfCAqZCAhPSAnPScpCiAgICAgICAgICAgIC5mbGF0X21hcCh8Y3wgc2VsZi50YWJsZS5pdGVyKCkucG9zaXRpb24ofGV8ICplID09IGMpKQogICAgICAgICAgICAuZmxhdF9tYXAofGJ8ICgwLi42KS5tYXAobW92ZSB8aXwgYiBhcyB1OCA+PiAoNSAtIGkpICYgMXU4ICE9IDB1OCkpLmNvbGxlY3QoKTsKICAgICAgICBsZXQgbmV3bGVuID0gYnMubGVuKCkgLSBicy5sZW4oKSAlIDg7CiAgICAgICAgYnMudHJ1bmNhdGUobmV3bGVuKTsKICAgICAgICBsZXQgdXM6IFZlYzx1OD4gPSBicy5jaHVua3MoOCkKICAgICAgICAgICAgLm1hcCh8Yjh8IGI4Lml0ZXIoKS5lbnVtZXJhdGUoKS5mb2xkKDAsIHxhY2MsIChpLCBiKXwgYWNjICsgKCgqYiBhcyB1OCkgPDwgKDcgLSBpKSkpKQogICAgICAgICAgICAuY29sbGVjdCgpOwogICAgICAgIFN0cmluZzo6ZnJvbV91dGY4KHVzKS51bndyYXBfb3IoU3RyaW5nOjpuZXcoKSkKICAgIH0KfQpmbiBtYWluKCkgewogICAgbGV0IGI2NCA9IEI2NDo6bmV3KCk7CiAgICBsZXQgcCA9IHxzfCB7CiAgICAgICAgbGV0IGUgPSBiNjQuZW5jb2RlKHMpOwogICAgICAgIGxldCBkID0gYjY0LmRlY29kZShlLmFzX3N0cigpKTsKICAgICAgICBwcmludGxuISgie31cbnt9XG57fVxuIiwgcywgZSwgZCk7CiAgICB9OwogICAgcCgiQUJDREVGRyIpOwogICAgcCgiSGVsbG8sIFdvcmxkISIpOwogICAgcCgiMDEyMzQ1Njc4OVwiIyQlJicoKWA9QCIpOwogICAgcCgi8J+SliIpOwp9Cg==