Some polish and adjustment to make the interface and code closer to the
corresponding b64 crate
This commit is contained in:
parent
0d1f59bf6c
commit
0ce411a7fd
2 changed files with 46 additions and 27 deletions
|
@ -1,17 +1,7 @@
|
|||
use super::*;
|
||||
use std::io::{self, ErrorKind, Read, Write};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DecoderError {
|
||||
IO(io::Error),
|
||||
IllegalChar,
|
||||
}
|
||||
|
||||
impl From<io::Error> for DecoderError {
|
||||
fn from(value: io::Error) -> Self {
|
||||
Self::IO(value)
|
||||
}
|
||||
}
|
||||
use {
|
||||
crate::{error::Error, B32Alphabet},
|
||||
std::io::{ErrorKind, Read, Write},
|
||||
};
|
||||
|
||||
pub struct Decoder<R: Read, W: Write> {
|
||||
reader: R,
|
||||
|
@ -30,7 +20,22 @@ impl<R: Read, W: Write> Decoder<R, W> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn decode(mut self) -> Result<W, DecoderError> {
|
||||
|
||||
/// Decodes the bytes provided by `self.reader` and writes the resulting
|
||||
/// bytes into `self.writer`.
|
||||
/// # Important
|
||||
/// Both reader and writer should be buffered for good performance, as the
|
||||
/// process of decoding will perform a series of very short read and write
|
||||
/// operations.
|
||||
/// # 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<W, Error> {
|
||||
let mut byte_reader = self.reader.bytes();
|
||||
'outer: loop {
|
||||
let mut in_buf = [0_u8; 8];
|
||||
|
@ -58,7 +63,7 @@ impl<R: Read, W: Write> Decoder<R, W> {
|
|||
for c in &in_buf {
|
||||
num <<= 5;
|
||||
if !matches!(self.alphabet.pad(), Some(ch) if ch == *c) {
|
||||
let idx = self.alphabet.idx(*c).ok_or(DecoderError::IllegalChar)?;
|
||||
let idx = self.alphabet.idx(*c).ok_or(Error::IllegalChar((*c).into()))?;
|
||||
num |= idx as u64;
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +88,11 @@ impl<R: Read, W: Write> Decoder<R, W> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::B32_RFC4648_ALPHABET;
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufReader, Read},
|
||||
};
|
||||
|
||||
static HELLO: &'static str = "Hello, World!";
|
||||
static ENCODED: &'static str = "JBSWY3DPFQQFO33SNRSCC===";
|
||||
|
@ -98,7 +108,25 @@ mod tests {
|
|||
let reader = ENCODED.as_bytes();
|
||||
let writer = Vec::<u8>::new();
|
||||
let decoder = Decoder::new(reader, writer, None, false);
|
||||
let output = decoder.decode().unwrap();
|
||||
assert_eq!(HELLO.as_bytes(), output);
|
||||
assert_eq!(decoder.decode().unwrap(), HELLO.as_bytes());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignore_whitespace() {
|
||||
let decoder = Decoder::new(" JBSWY3DP\tFQQFO33SNRSCC===".as_bytes(), vec![], None, true);
|
||||
assert_eq!(decoder.decode().unwrap(), HELLO.as_bytes());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_wrapped() {
|
||||
let infile = File::open("src/testdata/lorem_b32.txt").unwrap();
|
||||
let reader = BufReader::new(infile);
|
||||
let mut outfile = vec![];
|
||||
File::open("src/testdata/lorem.txt")
|
||||
.unwrap()
|
||||
.read_to_end(&mut outfile)
|
||||
.unwrap();
|
||||
let decoder = Decoder::new(reader, vec![], None, false);
|
||||
assert_eq!(decoder.decode().unwrap(), outfile);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ use std::{error, fmt, io, num::TryFromIntError};
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Fmt(fmt::Error),
|
||||
Io(io::Error),
|
||||
IllegalChar(char),
|
||||
IntError(TryFromIntError),
|
||||
|
@ -12,7 +11,6 @@ pub enum Error {
|
|||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Fmt(e) => write!(f, "{e}"),
|
||||
Self::Io(e) => write!(f, "{e}"),
|
||||
Self::IllegalChar(c) => write!(f, "Illegal Character ({c})"),
|
||||
Self::MissingPadding => write!(f, "Missing Padding"),
|
||||
|
@ -21,12 +19,6 @@ impl fmt::Display for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<fmt::Error> for Error {
|
||||
fn from(value: fmt::Error) -> Self {
|
||||
Self::Fmt(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(value: io::Error) -> Self {
|
||||
Self::Io(value)
|
||||
|
@ -48,7 +40,6 @@ impl From<TryFromIntError> for Error {
|
|||
impl error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::Fmt(e) => Some(e),
|
||||
Self::Io(e) => Some(e),
|
||||
Self::IntError(e) => Some(e),
|
||||
_ => None,
|
||||
|
|
Loading…
Add table
Reference in a new issue