pub struct Base85;
use super::utils::*;
use super::*;
impl Base for Base85 {
fn get_name(&self) -> &'static str {
"base85"
}
fn get_short_name(&self) -> &'static str {
"b85"
}
fn get_base(&self) -> &'static str {
"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu"
}
fn get_padding(&self) -> Option<&'static str> {
None
}
fn encode(&self, decoded: &str) -> Result<String, String> {
let mut encoded = String::new();
let padding = if decoded.len() % 4 != 0 {
4 - decoded.len() % 4
} else {
0
};
let decoded = decoded.to_string() + &"\0".repeat(padding);
for chunk in decoded.as_str().packed_by(4) {
let mut value = 0;
for c in chunk.chars() {
value *= 256;
value += c as usize;
}
encoded.push(self.get_base().chars().nth(value / 52200625).unwrap());
let remainder = value % 52200625;
encoded.push(self.get_base().chars().nth(remainder / 614125).unwrap());
let remainder = remainder % 614125;
encoded.push(self.get_base().chars().nth(remainder / 7225).unwrap());
let remainder = remainder % 7225;
encoded.push(self.get_base().chars().nth(remainder / 85).unwrap());
encoded.push(self.get_base().chars().nth(remainder % 85).unwrap());
}
for _ in 0..padding {
encoded.pop();
}
Ok(encoded)
}
fn decode(&self, encoded: &str) -> Result<String, String> {
let mut decoded = String::new();
let padding = if encoded.len() % 5 != 0 {
5 - encoded.len() % 5
} else {
0
};
let encoded = encoded.to_string() + &"u".repeat(padding);
for chunk in encoded.as_str().packed_by(5) {
let mut value = 0;
for c in chunk.chars() {
value *= 85;
value += match self.get_base().chars().position(|x| x == c) {
Some(i) => i,
None => return Err(format!("Invalid character {}", c)),
};
}
decoded.push((value >> 24) as u8 as char);
decoded.push(((value >> 16) & 255) as u8 as char);
decoded.push(((value >> 8) & 255) as u8 as char);
decoded.push((value & 255) as u8 as char);
}
for _ in 0..padding {
decoded.pop();
}
Ok(decoded)
}
}
#[cfg(test)]
#[test]
fn test_encode_decode() {
let base = Base85;
const TESTLIST: [(&str, &str); 10] = [
("Hello World!", "87cURD]i,\"Ebo80"),
("BaseCracker", "6=FqH6ZQUFCLqM"),
("\x7fELF", "Imm%#"),
("", ""),
("a", "@/"),
("aa", "@:9"),
("aaa", "@:<R"),
("aaaa", "@:<SQ"),
("aaaaa", "@:<SQ@/"),
("aaaaaa", "@:<SQ@:9"),
];
for test in TESTLIST.iter() {
let encoded = match base.encode(&test.0) {
Ok(encoded) => encoded,
Err(e) => panic!("Error while encoding \"{}\": {}", test.0, e),
};
assert_eq!(encoded, test.1, "Encoding \"{}\" failed", test.0);
let decoded = match base.decode(&encoded) {
Ok(decoded) => decoded,
Err(e) => panic!("Error while decoding \"{}\": {}", encoded, e),
};
assert_eq!(decoded, test.0, "Decoding \"{}\" failed", encoded);
}
}