b16_rs/src/decode.rs

82 lines
2.7 KiB
Rust

use {
crate::Error,
std::io::{ErrorKind, Read, Write},
};
pub struct Decoder<R: Read, W: Write> {
reader: R,
writer: W,
}
impl<R: Read, W: Write> Decoder<R, W> {
pub fn new(reader: R, writer: W) -> Self {
Self { reader, writer }
}
/// Decodes the bytes provided by `self.reader` and writes the resulting
/// bytes into `self.writer`.
/// # Errors
/// - io failure will return `Error::Io`
/// - a character not in the alphabet, or encountering any character after
/// the first occurance of the padding character, will return `Error::IllegalChar`
/// - if the reader comes up short of the final four byte block will return
/// `Error::MissingPadding`
/// - `intError` should never be returned. If this error is recieved the code
/// is somehow broken. Please file a bug.
pub fn decode(&mut self) -> Result<(), Error> {
loop {
let mut in_buf = [0_u8; 2];
let mut out_buf = [0_u8; 1];
let mut n_bytes = 0;
loop {
n_bytes += match self.reader.read(&mut in_buf) {
Ok(n) => n,
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e.into()),
};
break;
}
match n_bytes {
0 => break,
1 => return Err(Error::MissingChar),
2 => {}
_ => unreachable!(),
}
let mut c = char::from(in_buf[0]);
if let Some(idx) = super::get_idx(c.to_ascii_uppercase()) {
out_buf[0] |= (idx << 4) as u8;
} else {
return Err(Error::IllegalChar(c));
}
c = char::from(in_buf[1]);
if let Some(idx) = super::get_idx(c.to_ascii_uppercase()) {
out_buf[0] |= idx as u8;
} else {
return Err(Error::IllegalChar(c));
}
self.writer.write_all(&out_buf)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decode() {
let mut decoder = Decoder::new("48656C6C6F2C20576F726C64".as_bytes(), vec![]);
decoder.decode().unwrap();
assert_eq!(String::from_utf8(decoder.writer).unwrap(), "Hello, World");
decoder = Decoder::new("48656C6C6F2C20576F726C6421".as_bytes(), vec![]);
decoder.decode().unwrap();
assert_eq!(String::from_utf8(decoder.writer).unwrap(), "Hello, World!");
decoder = Decoder::new("48656C6C6F2C20576F726C64210A".as_bytes(), vec![]);
decoder.decode().unwrap();
assert_eq!(
String::from_utf8(decoder.writer).unwrap(),
"Hello, World!\n"
);
}
}