Add b64 enocoding and test

This commit is contained in:
Nathan Fisher 2024-05-02 12:15:22 -04:00
parent 683aa50d2a
commit e12cc66fba
3 changed files with 59 additions and 17 deletions

View File

@ -1,8 +1,6 @@
pub use { pub use {
super::B64Alphabet, super::B64Alphabet,
std::{ std::io::{self, ErrorKind, Read, Write},
io::{self, Read, Write, ErrorKind},
},
}; };
#[derive(Debug)] #[derive(Debug)]
@ -33,4 +31,3 @@ pub struct Decoder<R: Read, W: Write> {
mod tests { mod tests {
use super::*; use super::*;
} }

View File

@ -2,7 +2,7 @@ pub use {
super::B64Alphabet, super::B64Alphabet,
std::{ std::{
fmt::{self, Write}, fmt::{self, Write},
io::{self, Read, ErrorKind}, io::{self, ErrorKind, Read},
}, },
}; };
@ -50,11 +50,57 @@ pub struct Encoder<R: Read, W: Write> {
impl<R: Read, W: Write> Encoder<R, W> { impl<R: Read, W: Write> Encoder<R, W> {
pub fn new(reader: R, writer: W, alphabet: B64Alphabet) -> Self { pub fn new(reader: R, writer: W, alphabet: B64Alphabet) -> Self {
Self { reader, writer, alphabet } Self {
reader,
writer,
alphabet,
}
} }
pub fn encode(&mut self) -> Result<(), Error> { pub fn encode(&mut self) -> Result<(), Error> {
todo!() loop {
let mut ibuf = [0; 3];
let mut obuf = [self.alphabet.pad(); 4];
let mut n_bytes = 0;
let mut num: u64 = 0;
loop {
n_bytes += match self.reader.read(&mut ibuf) {
Ok(n) => n,
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e.into()),
};
break;
}
if n_bytes == 0 {
break;
}
for (idx, n) in ibuf.iter().enumerate() {
num <<= 8;
if idx < n_bytes {
num |= *n as u64;
}
}
let pad = n_bytes * 8 % 6;
for idx in (0..4).rev() {
if pad == 0 || idx < 4 - pad {
let b = num & 0b111111;
obuf[idx] = self.alphabet.items[b as usize];
}
num >>= 6;
}
write!(
self.writer,
"{}{}{}{}",
char::try_from(obuf[0]).unwrap(),
char::try_from(obuf[1]).unwrap(),
char::try_from(obuf[2]).unwrap(),
char::try_from(obuf[3]).unwrap()
)?;
if pad > 0 {
break;
}
}
Ok(())
} }
} }

View File

@ -1,9 +1,9 @@
mod encode;
mod decode; mod decode;
mod encode;
pub use { pub use {
encode::{Error as B64EncoderError, Encoder as B64Encoder}, decode::{Decoder as B64Decoder, Error as B64DecoderError},
decode::{Error as B64DecoderError, Decoder as B64Decoder}, encode::{Encoder as B64Encoder, Error as B64EncoderError},
}; };
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -14,11 +14,10 @@ pub struct B64Alphabet {
pub static B64_RFC4648_ALPHABET: B64Alphabet = B64Alphabet { pub static B64_RFC4648_ALPHABET: B64Alphabet = B64Alphabet {
items: [ items: [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1',
't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
'8', '9', '+', '/',
], ],
pad: '=', pad: '=',
}; };
@ -33,9 +32,9 @@ impl B64Alphabet {
pub fn idx(&self, c: char) -> Option<usize> { pub fn idx(&self, c: char) -> Option<usize> {
for (idx, x) in self.items.iter().enumerate() { for (idx, x) in self.items.iter().enumerate() {
if *x == c { if *x == c {
return Some(idx) return Some(idx);
}
} }
};
None None
} }