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 {
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])
.chain(std::iter::repeat('=').take(s.as_bytes().len() * 8 % self.w % 4 % 4))
.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));
}
c3RydWN0IEI2NCB7CiAgICB3OiB1c2l6ZSwKICAgIHRhYmxlOiBWZWM8Y2hhcj4sCn0KaW1wbCBCNjQgewogICAgZm4gbmV3KCkgLT4gQjY0IHtCNjQ6OndpdGhfdyg2KX0KICAgIGZuIHdpdGhfdyh3OiB1c2l6ZSkgLT4gQjY0IHsKICAgICAgICBCNjR7dzogdywgdGFibGU6ICJBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvIi5jaGFycygpLmNvbGxlY3QoKX0KICAgIH0KICAgIGZuIGVuY29kZSgmc2VsZiwgczogJnN0cikgLT4gU3RyaW5nIHsKICAgICAgICBzLmFzX2J5dGVzKCkuaXRlcigpCiAgICAgICAgICAgIC5mbGF0X21hcCh8YnwgKDAuLjgpLm1hcChtb3ZlIHxpfCBiID4+ICg3IC0gaSkgJiAxdTggIT0gMHU4KSkKICAgICAgICAgICAgLmNvbGxlY3Q6OjxWZWM8Xz4+KCkuY2h1bmtzKHNlbGYudykKICAgICAgICAgICAgLm1hcCh8Ynd8IGJ3Lml0ZXIoKS5lbnVtZXJhdGUoKS5mb2xkKDAsIHxhY2MsIChpLCBiKXwgYWNjICsgKCgqYiBhcyB1OCkgPDwgKHNlbGYudyAtIDEgLSBpKSkpKQogICAgICAgICAgICAubWFwKHx1fCBzZWxmLnRhYmxlW3UgYXMgdXNpemVdKQogICAgICAgICAgICAuY2hhaW4oc3RkOjppdGVyOjpyZXBlYXQoJz0nKS50YWtlKHMuYXNfYnl0ZXMoKS5sZW4oKSAqIDggJSBzZWxmLncgJSA0ICUgNCkpCiAgICAgICAgICAgIC5jb2xsZWN0KCkKICAgIH0KICAgIGZuIGRlY29kZSgmc2VsZiwgczogJnN0cikgLT4gU3RyaW5nIHsKICAgICAgICBsZXQgdXM6IFZlYzx1OD4gPSBzLmNoYXJzKCkudGFrZV93aGlsZSh8ZHwgKmQgIT0gJz0nKQogICAgICAgICAgICAuZmxhdF9tYXAofGN8IHNlbGYudGFibGUuaXRlcigpLnBvc2l0aW9uKHxlfCAqZSA9PSBjKSkKICAgICAgICAgICAgLmZsYXRfbWFwKHxifCAoMC4uc2VsZi53KS5tYXAobW92ZSB8aXwgYiBhcyB1OCA+PiAoc2VsZi53IC0gMSAtIGkpICYgMXU4ICE9IDB1OCkpCiAgICAgICAgICAgIC5jb2xsZWN0Ojo8VmVjPF8+PigpLmNodW5rcyg4KS5maWx0ZXIofGI4fCBiOC5sZW4oKSA9PSA4KQogICAgICAgICAgICAubWFwKHxiOHwgYjguaXRlcigpLmVudW1lcmF0ZSgpLmZvbGQoMCwgfGFjYywgKGksIGIpfCBhY2MgKyAoKCpiIGFzIHU4KSA8PCAoNyAtIGkpKSkpCiAgICAgICAgICAgIC5jb2xsZWN0KCk7CiAgICAgICAgU3RyaW5nOjpmcm9tX3V0ZjgodXMpLnVud3JhcF9vcihTdHJpbmc6Om5ldygpKQogICAgfQp9CmZuIG1haW4oKSB7CiAgICBsZXQgcCA9IHxiOiAmQjY0LCBzfCB7CiAgICAgICAgbGV0IGUgPSBiLmVuY29kZShzKTsKICAgICAgICBsZXQgZCA9IGIuZGVjb2RlKGUuYXNfc3RyKCkpOwogICAgICAgIHByaW50bG4hKCJ7fVxue31cbnt9XG4iLCBzLCBlLCBkKTsKICAgIH07CiAgICBsZXQgZiA9IHxifCBmb3IgcyBpbiAmWyJBQkNERUZHIiwgIkhlbGxvLCBXb3JsZCEiLCAiMDEyMzQ1Njc4OVwiIyQlJicoKWA9QCIsICLwn5KWIl0ge3AoJmIsIHMpfTsKICAgIGYoQjY0OjpuZXcoKSk7CiAgICBmKEI2NDo6d2l0aF93KDUpKTsKICAgIGYoQjY0Ojp3aXRoX3coMykpOwp9Cg==
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==
💖