struct B64 {
w: usize,
table: Vec<char>,
}
impl B64 {
fn new() -> B64 {B64::with_w(6)}
fn with_w(w: usize) -> B64 {
B64{w: w, table: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".chars().collect()}
}
fn encode(&self, s: &str) -> String {
let mut cs: Vec<char> = s.as_bytes().iter()
.flat_map(|b| (0..8).map(move |i| b >> (7 - i) & 1u8 != 0u8)).collect::<Vec<_>>().chunks(self.w)
.map(|bw| bw.iter().enumerate().fold(0, |acc, (i, b)| acc + ((*b as u8) << (self.w - 1 - i))))
.map(|u| self.table[u as usize]).collect();
while 0 < cs.len() % 4 {cs.push('=')}
cs.into_iter().collect()
}
fn decode(&self, s: &str) -> String {
let us: Vec<u8> = s.chars().take_while(|d| *d != '=')
.flat_map(|c| self.table.iter().position(|e| *e == c))
.flat_map(|b| (0..self.w).map(move |i| b as u8 >> (self.w - 1 - i) & 1u8 != 0u8))
.collect::<Vec<_>>().chunks(8).filter(|b8| b8.len() == 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 p = |b: &B64, s| {
let e = b.encode(s);
let d = b.decode(e.as_str());
println!("{}\n{}\n{}\n", s, e, d);
};
let f = |b| for s in &["ABCDEFG", "Hello, World!", "0123456789\"#$%&'()`=@", "💖"] {p(&b, s)};
f(B64::new());
f(B64::with_w(5));
f(B64::with_w(3));
}
c3RydWN0IEI2NCB7CiAgICB3OiB1c2l6ZSwKICAgIHRhYmxlOiBWZWM8Y2hhcj4sCn0KaW1wbCBCNjQgewogICAgZm4gbmV3KCkgLT4gQjY0IHtCNjQ6OndpdGhfdyg2KX0KICAgIGZuIHdpdGhfdyh3OiB1c2l6ZSkgLT4gQjY0IHsKICAgICAgICBCNjR7dzogdywgdGFibGU6ICJBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvIi5jaGFycygpLmNvbGxlY3QoKX0KICAgIH0KICAgIGZuIGVuY29kZSgmc2VsZiwgczogJnN0cikgLT4gU3RyaW5nIHsKICAgICAgICBsZXQgbXV0IGNzOiBWZWM8Y2hhcj4gPSBzLmFzX2J5dGVzKCkuaXRlcigpCiAgICAgICAgICAgIC5mbGF0X21hcCh8YnwgKDAuLjgpLm1hcChtb3ZlIHxpfCBiID4+ICg3IC0gaSkgJiAxdTggIT0gMHU4KSkuY29sbGVjdDo6PFZlYzxfPj4oKS5jaHVua3Moc2VsZi53KQogICAgICAgICAgICAubWFwKHxid3wgYncuaXRlcigpLmVudW1lcmF0ZSgpLmZvbGQoMCwgfGFjYywgKGksIGIpfCBhY2MgKyAoKCpiIGFzIHU4KSA8PCAoc2VsZi53IC0gMSAtIGkpKSkpCiAgICAgICAgICAgIC5tYXAofHV8IHNlbGYudGFibGVbdSBhcyB1c2l6ZV0pLmNvbGxlY3QoKTsKICAgICAgICB3aGlsZSAwIDwgY3MubGVuKCkgJSA0IHtjcy5wdXNoKCc9Jyl9CiAgICAgICAgY3MuaW50b19pdGVyKCkuY29sbGVjdCgpCiAgICB9CiAgICBmbiBkZWNvZGUoJnNlbGYsIHM6ICZzdHIpIC0+IFN0cmluZyB7CiAgICAgICAgbGV0IHVzOiBWZWM8dTg+ID0gcy5jaGFycygpLnRha2Vfd2hpbGUofGR8ICpkICE9ICc9JykKICAgICAgICAgICAgLmZsYXRfbWFwKHxjfCBzZWxmLnRhYmxlLml0ZXIoKS5wb3NpdGlvbih8ZXwgKmUgPT0gYykpCiAgICAgICAgICAgIC5mbGF0X21hcCh8YnwgKDAuLnNlbGYudykubWFwKG1vdmUgfGl8IGIgYXMgdTggPj4gKHNlbGYudyAtIDEgLSBpKSAmIDF1OCAhPSAwdTgpKQogICAgICAgICAgICAuY29sbGVjdDo6PFZlYzxfPj4oKS5jaHVua3MoOCkuZmlsdGVyKHxiOHwgYjgubGVuKCkgPT0gOCkKICAgICAgICAgICAgLm1hcCh8Yjh8IGI4Lml0ZXIoKS5lbnVtZXJhdGUoKS5mb2xkKDAsIHxhY2MsIChpLCBiKXwgYWNjICsgKCgqYiBhcyB1OCkgPDwgKDcgLSBpKSkpKQogICAgICAgICAgICAuY29sbGVjdCgpOwogICAgICAgIFN0cmluZzo6ZnJvbV91dGY4KHVzKS51bndyYXBfb3IoU3RyaW5nOjpuZXcoKSkKICAgIH0KfQpmbiBtYWluKCkgewogICAgbGV0IHAgPSB8YjogJkI2NCwgc3wgewogICAgICAgIGxldCBlID0gYi5lbmNvZGUocyk7CiAgICAgICAgbGV0IGQgPSBiLmRlY29kZShlLmFzX3N0cigpKTsKICAgICAgICBwcmludGxuISgie31cbnt9XG57fVxuIiwgcywgZSwgZCk7CiAgICB9OwogICAgbGV0IGYgPSB8YnwgZm9yIHMgaW4gJlsiQUJDREVGRyIsICJIZWxsbywgV29ybGQhIiwgIjAxMjM0NTY3ODlcIiMkJSYnKClgPUAiLCAi8J+SliJdIHtwKCZiLCBzKX07CiAgICBmKEI2NDo6bmV3KCkpOwogICAgZihCNjQ6OndpdGhfdyg1KSk7CiAgICBmKEI2NDo6d2l0aF93KDMpKTsKfQo=
ABCDEFG
QUJDREVGRw==
ABCDEFG
Hello, World!
SGVsbG8sIFdvcmxkIQ==
Hello, World!
0123456789"#$%&'()`=@
MDEyMzQ1Njc4OSIjJCUmJygpYD1A
0123456789"#$%&'()`=@
💖
8J+Slg==
💖
ABCDEFG
IFBEGRCFIZDQ
ABCDEFG
Hello, World!
JBSWYbDPFQQFObbSNRSCC===
Hello, World!
0123456789"#$%&'()`=@
GAYTEMZUGUbDOOBZEIRSIJJGEcUCSYBdIA==
0123456789"#$%&'()`=@
💖
eCPZFFQ=
💖
ABCDEFG
CACEBBADCBAECFAGCBG=
ABCDEFG
Hello, World!
CCAGCFFEDDAGHEFEBAAFDFFHDEEGGBEEBAC=
Hello, World!
0123456789"#$%&'()`=@
BEADAEGCBEGDCAGFBFEDDEHABGCCBAEDBBACCEEGBBGCEAFBDAADGFAA
0123456789"#$%&'()`=@
💖
HEBBHGCCEFE=
💖