struct B64 {
table: Vec<char>,
}
impl B64 {
fn new() -> B64 {
B64{table: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".chars().collect()}
}
fn _push(bs: &mut Vec<bool>, byte: u8, width: i32) {
for i in 0..width {bs.push(byte >> (width - 1 - i) & 1 != 0);}
}
fn encode(&self, s: &str) -> String {
let mut bs: Vec<bool> = Vec::new();
for b in s.as_bytes() {B64::_push(&mut bs, *b, 8)}
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> = Vec::new();
for c in s.chars().take_while(|d| *d != '=') {
if let Some(i) = self.table.iter().position(|e| *e == c) {B64::_push(&mut bs, i as u8, 6)}
}
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+IEI2NCB7CiAgICAgICAgQjY0e3RhYmxlOiAiQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLyIuY2hhcnMoKS5jb2xsZWN0KCl9CiAgICB9CiAgICBmbiBfcHVzaChiczogJm11dCBWZWM8Ym9vbD4sIGJ5dGU6IHU4LCB3aWR0aDogaTMyKSB7CiAgICAgICAgZm9yIGkgaW4gMC4ud2lkdGgge2JzLnB1c2goYnl0ZSA+PiAod2lkdGggLSAxIC0gaSkgJiAxICE9IDApO30KICAgIH0KICAgIGZuIGVuY29kZSgmc2VsZiwgczogJnN0cikgLT4gU3RyaW5nIHsKICAgICAgICBsZXQgbXV0IGJzOiBWZWM8Ym9vbD4gPSBWZWM6Om5ldygpOwogICAgICAgIGZvciBiIGluIHMuYXNfYnl0ZXMoKSB7QjY0OjpfcHVzaCgmbXV0IGJzLCAqYiwgOCl9CiAgICAgICAgZm9yIF8gaW4gMC4uNiAtIGJzLmxlbigpICUgNiB7YnMucHVzaChmYWxzZSl9CiAgICAgICAgbGV0IG11dCBjczogVmVjPGNoYXI+ID0gYnMuY2h1bmtzKDYpCiAgICAgICAgICAgIC5tYXAofGI2fCBiNi5pdGVyKCkuZW51bWVyYXRlKCkuZm9sZCgwLCB8YWNjLCAoaSwgYil8IGFjYyArICgoKmIgYXMgdTgpIDw8ICg1IC0gaSkpKSkKICAgICAgICAgICAgLm1hcCh8dXwgc2VsZi50YWJsZVt1IGFzIHVzaXplXSkuY29sbGVjdCgpOwogICAgICAgIGZvciBfIGluIDAuLjQgLSBjcy5sZW4oKSAlIDQge2NzLnB1c2goJz0nKX0KICAgICAgICBjcy5pbnRvX2l0ZXIoKS5jb2xsZWN0KCkKICAgIH0KICAgIGZuIGRlY29kZSgmc2VsZiwgczogJnN0cikgLT4gU3RyaW5nIHsKICAgICAgICBsZXQgbXV0IGJzOiBWZWM8Ym9vbD4gPSBWZWM6Om5ldygpOwogICAgICAgIGZvciBjIGluIHMuY2hhcnMoKS50YWtlX3doaWxlKHxkfCAqZCAhPSAnPScpIHsKICAgICAgICAgICAgaWYgbGV0IFNvbWUoaSkgPSBzZWxmLnRhYmxlLml0ZXIoKS5wb3NpdGlvbih8ZXwgKmUgPT0gYykge0I2NDo6X3B1c2goJm11dCBicywgaSBhcyB1OCwgNil9CiAgICAgICAgfQogICAgICAgIGxldCBuZXdsZW4gPSBicy5sZW4oKSAtIGJzLmxlbigpICUgODsKICAgICAgICBicy50cnVuY2F0ZShuZXdsZW4pOwogICAgICAgIGxldCB1czogVmVjPHU4PiA9IGJzLmNodW5rcyg4KQogICAgICAgICAgICAubWFwKHxiOHwgYjguaXRlcigpLmVudW1lcmF0ZSgpLmZvbGQoMCwgfGFjYywgKGksIGIpfCBhY2MgKyAoKCpiIGFzIHU4KSA8PCAoNyAtIGkpKSkpCiAgICAgICAgICAgIC5jb2xsZWN0KCk7CiAgICAgICAgU3RyaW5nOjpmcm9tX3V0ZjgodXMpLnVud3JhcF9vcihTdHJpbmc6Om5ldygpKQogICAgfQp9CmZuIG1haW4oKSB7CiAgICBsZXQgYjY0ID0gQjY0OjpuZXcoKTsKICAgIGxldCBwID0gfHN8IHsKICAgICAgICBsZXQgZSA9IGI2NC5lbmNvZGUocyk7CiAgICAgICAgbGV0IGQgPSBiNjQuZGVjb2RlKGUuYXNfc3RyKCkpOwogICAgICAgIHByaW50bG4hKCJ7fVxue31cbnt9XG4iLCBzLCBlLCBkKTsKICAgIH07CiAgICBwKCJBQkNERUZHIik7CiAgICBwKCJIZWxsbywgV29ybGQhIik7CiAgICBwKCIwMTIzNDU2Nzg5XCIjJCUmJygpYD1AIik7CiAgICBwKCLwn5KWIik7Cn0K