use super::SerialError;
pub(crate) const BL4_BASE85_ALPHABET: &[u8; 85] =
b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{/}~";
#[inline]
pub fn mirror_byte(byte: u8) -> u8 {
byte.reverse_bits()
}
pub fn decode_base85(input: &str) -> Result<Vec<u8>, SerialError> {
let cleaned: String;
let input = if input.contains('\\') {
cleaned = input.replace('\\', "");
&cleaned
} else {
input
};
let mut lookup = [0u8; 256];
for (i, &ch) in BL4_BASE85_ALPHABET.iter().enumerate() {
lookup[ch as usize] = i as u8;
}
let mut result = Vec::new();
let chars: Vec<char> = input.chars().collect();
for chunk in chars.chunks(5) {
let mut value: u64 = 0;
for &ch in chunk.iter() {
let byte_val = lookup[ch as usize] as u64;
value = value * 85 + byte_val;
}
for _ in chunk.len()..5 {
value = value * 85 + 84;
}
let num_bytes = if chunk.len() == 5 { 4 } else { chunk.len() - 1 };
for i in (0..num_bytes).rev() {
let shift = if chunk.len() == 5 {
i * 8
} else {
(3 - (num_bytes - 1 - i)) * 8
};
result.push(((value >> shift) & 0xFF) as u8);
}
}
Ok(result)
}
pub fn encode_base85(bytes: &[u8]) -> String {
let mut result = String::new();
for chunk in bytes.chunks(4) {
let mut value: u64 = 0;
for &byte in chunk {
value = (value << 8) | (byte as u64);
}
if chunk.len() < 4 {
value <<= (4 - chunk.len()) * 8;
}
let mut chars = [0u8; 5];
for i in (0..5).rev() {
chars[i] = BL4_BASE85_ALPHABET[(value % 85) as usize];
value /= 85;
}
let num_chars = if chunk.len() == 4 { 5 } else { chunk.len() + 1 };
for &ch in &chars[0..num_chars] {
result.push(ch as char);
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mirror_byte() {
assert_eq!(mirror_byte(0b10000000), 0b00000001);
assert_eq!(mirror_byte(0b11000000), 0b00000011);
assert_eq!(mirror_byte(0b10101010), 0b01010101);
assert_eq!(mirror_byte(0b00000000), 0b00000000);
assert_eq!(mirror_byte(0b11111111), 0b11111111);
}
#[test]
fn test_base85_decode() {
let result = decode_base85("g").unwrap();
assert_eq!(result.len(), 0); }
}