macro_rules! assign_decode_map {
($decode_map: ident, $encoder: ident) => {
$decode_map[$encoder[0] as usize] = 0;
$decode_map[$encoder[1] as usize] = 1;
$decode_map[$encoder[2] as usize] = 2;
$decode_map[$encoder[3] as usize] = 3;
$decode_map[$encoder[4] as usize] = 4;
$decode_map[$encoder[5] as usize] = 5;
$decode_map[$encoder[6] as usize] = 6;
$decode_map[$encoder[7] as usize] = 7;
$decode_map[$encoder[8] as usize] = 8;
$decode_map[$encoder[9] as usize] = 9;
$decode_map[$encoder[10] as usize] = 10;
$decode_map[$encoder[11] as usize] = 11;
$decode_map[$encoder[12] as usize] = 12;
$decode_map[$encoder[13] as usize] = 13;
$decode_map[$encoder[14] as usize] = 14;
$decode_map[$encoder[15] as usize] = 15;
$decode_map[$encoder[16] as usize] = 16;
$decode_map[$encoder[17] as usize] = 17;
$decode_map[$encoder[18] as usize] = 18;
$decode_map[$encoder[19] as usize] = 19;
$decode_map[$encoder[20] as usize] = 20;
$decode_map[$encoder[21] as usize] = 21;
$decode_map[$encoder[22] as usize] = 22;
$decode_map[$encoder[23] as usize] = 23;
$decode_map[$encoder[24] as usize] = 24;
$decode_map[$encoder[25] as usize] = 25;
$decode_map[$encoder[26] as usize] = 26;
$decode_map[$encoder[27] as usize] = 27;
$decode_map[$encoder[28] as usize] = 28;
$decode_map[$encoder[29] as usize] = 29;
$decode_map[$encoder[30] as usize] = 30;
$decode_map[$encoder[31] as usize] = 31;
};
}
macro_rules! check_32 {
($encoder: ident, $invalid: expr) => {{
if $encoder[0] == b'\n' || $encoder[0] == b'\r' {
$invalid;
}
if $encoder[1] == b'\n' || $encoder[1] == b'\r' {
$invalid;
}
if $encoder[2] == b'\n' || $encoder[2] == b'\r' {
$invalid;
}
if $encoder[3] == b'\n' || $encoder[3] == b'\r' {
$invalid;
}
if $encoder[4] == b'\n' || $encoder[4] == b'\r' {
$invalid;
}
if $encoder[5] == b'\n' || $encoder[5] == b'\r' {
$invalid;
}
if $encoder[6] == b'\n' || $encoder[6] == b'\r' {
$invalid;
}
if $encoder[7] == b'\n' || $encoder[7] == b'\r' {
$invalid;
}
if $encoder[8] == b'\n' || $encoder[8] == b'\r' {
$invalid;
}
if $encoder[9] == b'\n' || $encoder[9] == b'\r' {
$invalid;
}
if $encoder[10] == b'\n' || $encoder[10] == b'\r' {
$invalid;
}
if $encoder[11] == b'\n' || $encoder[11] == b'\r' {
$invalid;
}
if $encoder[12] == b'\n' || $encoder[12] == b'\r' {
$invalid;
}
if $encoder[13] == b'\n' || $encoder[13] == b'\r' {
$invalid;
}
if $encoder[14] == b'\n' || $encoder[14] == b'\r' {
$invalid;
}
if $encoder[15] == b'\n' || $encoder[15] == b'\r' {
$invalid;
}
if $encoder[16] == b'\n' || $encoder[16] == b'\r' {
$invalid;
}
if $encoder[17] == b'\n' || $encoder[17] == b'\r' {
$invalid;
}
if $encoder[18] == b'\n' || $encoder[18] == b'\r' {
$invalid;
}
if $encoder[19] == b'\n' || $encoder[19] == b'\r' {
$invalid;
}
if $encoder[20] == b'\n' || $encoder[20] == b'\r' {
$invalid;
}
if $encoder[21] == b'\n' || $encoder[21] == b'\r' {
$invalid;
}
if $encoder[22] == b'\n' || $encoder[22] == b'\r' {
$invalid;
}
if $encoder[23] == b'\n' || $encoder[23] == b'\r' {
$invalid;
}
if $encoder[24] == b'\n' || $encoder[24] == b'\r' {
$invalid;
}
if $encoder[25] == b'\n' || $encoder[25] == b'\r' {
$invalid;
}
if $encoder[26] == b'\n' || $encoder[26] == b'\r' {
$invalid;
}
if $encoder[27] == b'\n' || $encoder[27] == b'\r' {
$invalid;
}
if $encoder[28] == b'\n' || $encoder[28] == b'\r' {
$invalid;
}
if $encoder[29] == b'\n' || $encoder[29] == b'\r' {
$invalid;
}
if $encoder[30] == b'\n' || $encoder[30] == b'\r' {
$invalid;
}
if $encoder[31] == b'\n' || $encoder[31] == b'\r' {
$invalid;
}
}};
($encoder: ident, $ch: ident, $invalid: expr) => {{
if $encoder[0] == b'\n' || $encoder[0] == b'\r' || $encoder[0] == $ch as u8 {
$invalid;
}
if $encoder[1] == b'\n' || $encoder[1] == b'\r' || $encoder[1] == $ch as u8 {
$invalid;
}
if $encoder[2] == b'\n' || $encoder[2] == b'\r' || $encoder[2] == $ch as u8 {
$invalid;
}
if $encoder[3] == b'\n' || $encoder[3] == b'\r' || $encoder[3] == $ch as u8 {
$invalid;
}
if $encoder[4] == b'\n' || $encoder[4] == b'\r' || $encoder[4] == $ch as u8 {
$invalid;
}
if $encoder[5] == b'\n' || $encoder[5] == b'\r' || $encoder[5] == $ch as u8 {
$invalid;
}
if $encoder[6] == b'\n' || $encoder[6] == b'\r' || $encoder[6] == $ch as u8 {
$invalid;
}
if $encoder[7] == b'\n' || $encoder[7] == b'\r' || $encoder[7] == $ch as u8 {
$invalid;
}
if $encoder[8] == b'\n' || $encoder[8] == b'\r' || $encoder[8] == $ch as u8 {
$invalid;
}
if $encoder[9] == b'\n' || $encoder[9] == b'\r' || $encoder[9] == $ch as u8 {
$invalid;
}
if $encoder[10] == b'\n' || $encoder[10] == b'\r' || $encoder[10] == $ch as u8 {
$invalid;
}
if $encoder[11] == b'\n' || $encoder[11] == b'\r' || $encoder[11] == $ch as u8 {
$invalid;
}
if $encoder[12] == b'\n' || $encoder[12] == b'\r' || $encoder[12] == $ch as u8 {
$invalid;
}
if $encoder[13] == b'\n' || $encoder[13] == b'\r' || $encoder[13] == $ch as u8 {
$invalid;
}
if $encoder[14] == b'\n' || $encoder[14] == b'\r' || $encoder[14] == $ch as u8 {
$invalid;
}
if $encoder[15] == b'\n' || $encoder[15] == b'\r' || $encoder[15] == $ch as u8 {
$invalid;
}
if $encoder[16] == b'\n' || $encoder[16] == b'\r' || $encoder[16] == $ch as u8 {
$invalid;
}
if $encoder[17] == b'\n' || $encoder[17] == b'\r' || $encoder[17] == $ch as u8 {
$invalid;
}
if $encoder[18] == b'\n' || $encoder[18] == b'\r' || $encoder[18] == $ch as u8 {
$invalid;
}
if $encoder[19] == b'\n' || $encoder[19] == b'\r' || $encoder[19] == $ch as u8 {
$invalid;
}
if $encoder[20] == b'\n' || $encoder[20] == b'\r' || $encoder[20] == $ch as u8 {
$invalid;
}
if $encoder[21] == b'\n' || $encoder[21] == b'\r' || $encoder[21] == $ch as u8 {
$invalid;
}
if $encoder[22] == b'\n' || $encoder[22] == b'\r' || $encoder[22] == $ch as u8 {
$invalid;
}
if $encoder[23] == b'\n' || $encoder[23] == b'\r' || $encoder[23] == $ch as u8 {
$invalid;
}
if $encoder[24] == b'\n' || $encoder[24] == b'\r' || $encoder[24] == $ch as u8 {
$invalid;
}
if $encoder[25] == b'\n' || $encoder[25] == b'\r' || $encoder[25] == $ch as u8 {
$invalid;
}
if $encoder[26] == b'\n' || $encoder[26] == b'\r' || $encoder[26] == $ch as u8 {
$invalid;
}
if $encoder[27] == b'\n' || $encoder[27] == b'\r' || $encoder[27] == $ch as u8 {
$invalid;
}
if $encoder[28] == b'\n' || $encoder[28] == b'\r' || $encoder[28] == $ch as u8 {
$invalid;
}
if $encoder[29] == b'\n' || $encoder[29] == b'\r' || $encoder[29] == $ch as u8 {
$invalid;
}
if $encoder[30] == b'\n' || $encoder[30] == b'\r' || $encoder[30] == $ch as u8 {
$invalid;
}
if $encoder[31] == b'\n' || $encoder[31] == b'\r' || $encoder[31] == $ch as u8 {
$invalid;
}
}};
}
const BASE: usize = 32;
const ENCODE_STD: [u8; BASE] = *b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
const ENCODE_HEX: [u8; BASE] = *b"0123456789ABCDEFGHIJKLMNOPQRSTUV";
const DECODE_MAP_INITIALIZE: [u8; 256] = [255; 256];
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Error {
InvalidEncoder,
InvalidPadding,
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Error::InvalidEncoder => write!(f, "Base32 alphabet must be 32 bytes long"),
Error::InvalidPadding => write!(f, "Invalid padding character"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
pub const NO_PADDING: Option<char> = None;
pub const STD_PADDING: Option<char> = Some('=');
pub const STD_ENCODING: Base32 = Base32::new_unchecked(ENCODE_STD);
pub const RAW_STD_ENCODING: Base32 = Base32::new_unchecked(ENCODE_STD).with_padding_unchecked(None);
pub const HEX_ENCODING: Base32 = Base32::new_unchecked(ENCODE_HEX);
pub const RAW_HEX_ENCODING: Base32 = Base32::new_unchecked(ENCODE_HEX).with_padding_unchecked(None);
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct Base32 {
encode: [u8; BASE],
decode_map: [u8; 256],
pad_char: Option<char>,
}
impl Default for Base32 {
fn default() -> Self {
STD_ENCODING
}
}
impl Base32 {
#[inline]
pub const fn new(encoder: [u8; BASE]) -> Result<Self, Error> {
const CH: char = '=';
check_32!(encoder, CH, return Err(Error::InvalidEncoder));
let mut decode_map = DECODE_MAP_INITIALIZE;
assign_decode_map!(decode_map, encoder);
Ok(Self {
encode: encoder,
decode_map,
pad_char: Some('='),
})
}
#[inline]
pub const fn new_unchecked(encoder: [u8; BASE]) -> Self {
const CH: char = '=';
check_32!(
encoder,
CH,
panic!("encoding alphabet contains newline character or padding character")
);
let mut decode_map = DECODE_MAP_INITIALIZE;
assign_decode_map!(decode_map, encoder);
Self {
encode: encoder,
decode_map,
pad_char: Some('='),
}
}
#[inline]
pub const fn with_padding(self, padding: Option<char>) -> Result<Self, Error> {
let Self {
encode: encoder,
decode_map,
pad_char: _,
} = self;
match padding {
Some(ch) => {
check_32!(encoder, ch, return Err(Error::InvalidPadding));
}
None => {
check_32!(encoder, return Err(Error::InvalidPadding));
}
}
Ok(Self {
encode: encoder,
decode_map,
pad_char: padding,
})
}
#[inline]
pub const fn with_padding_unchecked(self, pad: Option<char>) -> Self {
let Self {
encode: encoder,
decode_map,
pad_char: _,
} = self;
match pad {
Some(ch) => {
check_32!(
encoder,
ch,
panic!("encoding alphabet contains newline character or padding character")
);
}
None => {
check_32!(
encoder,
panic!("encoding alphabet contains newline character or padding character")
);
}
}
Self {
encode: encoder,
decode_map,
pad_char: pad,
}
}
#[cfg(feature = "std")]
#[inline]
pub const fn encoder<W: std::io::Write>(&self, writer: W) -> Encoder<W> {
Encoder::new(*self, writer)
}
#[cfg(feature = "std")]
#[inline]
pub const fn decoder<R: std::io::Read>(&self, reader: R) -> Decoder<R> {
Decoder::new(*self, reader)
}
#[inline]
pub const fn encoded_len(&self, n: usize) -> usize {
if self.pad_char.is_none() {
return (n * 8 + 4) / 5;
}
(n + 4) / 5 * 8
}
#[inline]
pub fn encode(&self, mut src: &[u8], mut dst: &mut [u8]) {
while !src.is_empty() {
let mut b = [0; 8];
match src.len() {
4 => {
b[6] |= (src[3] << 3) & 0x1F;
b[5] = (src[3] >> 2) & 0x1F;
b[4] = src[3] >> 7;
b[4] |= (src[2] << 1) & 0x1F;
b[3] = (src[2] >> 4) & 0x1F;
b[3] |= (src[1] << 4) & 0x1F;
b[2] = (src[1] >> 1) & 0x1F;
b[1] = (src[1] >> 6) & 0x1F;
b[1] |= (src[0] << 2) & 0x1F;
b[0] = src[0] >> 3;
}
3 => {
b[4] |= (src[2] << 1) & 0x1F;
b[3] = (src[2] >> 4) & 0x1F;
b[3] |= (src[1] << 4) & 0x1F;
b[2] = (src[1] >> 1) & 0x1F;
b[1] = (src[1] >> 6) & 0x1F;
b[1] |= (src[0] << 2) & 0x1F;
b[0] = src[0] >> 3;
}
2 => {
b[3] |= (src[1] << 4) & 0x1F;
b[2] = (src[1] >> 1) & 0x1F;
b[1] = (src[1] >> 6) & 0x1F;
b[1] |= (src[0] << 2) & 0x1F;
b[0] = src[0] >> 3;
}
1 => {
b[1] |= (src[0] << 2) & 0x1F;
b[0] = src[0] >> 3;
}
_ => {
b[7] = src[4] & 0x1F;
b[6] = src[4] >> 5;
b[6] |= (src[3] << 3) & 0x1F;
b[5] = (src[3] >> 2) & 0x1F;
b[4] = src[3] >> 7;
b[4] |= (src[2] << 1) & 0x1F;
b[3] = (src[2] >> 4) & 0x1F;
b[3] |= (src[1] << 4) & 0x1F;
b[2] = (src[1] >> 1) & 0x1F;
b[1] = (src[1] >> 6) & 0x1F;
b[1] |= (src[0] << 2) & 0x1F;
b[0] = src[0] >> 3;
}
}
let size = dst.len();
if size >= 8 {
dst[0] = self.encode[b[0] as usize & 31];
dst[1] = self.encode[b[1] as usize & 31];
dst[2] = self.encode[b[2] as usize & 31];
dst[3] = self.encode[b[3] as usize & 31];
dst[4] = self.encode[b[4] as usize & 31];
dst[5] = self.encode[b[5] as usize & 31];
dst[6] = self.encode[b[6] as usize & 31];
dst[7] = self.encode[b[7] as usize & 31];
} else {
for i in 0..size {
dst[i] = self.encode[b[i] as usize & 31];
}
}
if src.len() < 5 {
if let Some(padding) = self.pad_char {
dst[7] = padding as u8;
if src.len() < 4 {
dst[6] = padding as u8;
dst[5] = padding as u8;
if src.len() < 3 {
dst[4] = padding as u8;
if src.len() < 2 {
dst[3] = padding as u8;
dst[2] = padding as u8;
}
}
}
} else {
break;
}
break;
}
src = &src[5..];
dst = &mut dst[8..];
}
}
#[cfg(feature = "alloc")]
pub fn encode_to_vec(&self, src: &[u8]) -> alloc::vec::Vec<u8> {
let mut dst = alloc::vec![0; self.encoded_len(src.len())];
self.encode(src, &mut dst);
dst
}
#[inline]
#[cfg(feature = "alloc")]
pub fn decode(&self, src: &[u8], dst: &mut [u8]) -> Result<usize, DecodeError> {
let mut buf = src.to_vec();
let l = strip_new_lines_inplace(&mut buf);
self.decode_in(&buf[..l], dst).map(|(n, _)| n)
}
#[inline]
#[cfg(feature = "alloc")]
pub fn decode_to_vec(&self, src: &[u8]) -> Result<alloc::vec::Vec<u8>, DecodeError> {
let mut buf = src.to_vec();
let l = strip_new_lines_inplace(&mut buf);
self.decode_inplace(&mut buf, l).map(|(n, _)| {
buf.truncate(n);
buf
})
}
#[inline]
fn decode_inplace(&self, dst: &mut [u8], src_len: usize) -> Result<(usize, bool), DecodeError> {
let mut n = 0;
let mut end = false;
let mut dsti = 0;
let src = dst;
let olen = src_len;
let mut src_start = 0;
let src_end = src_len;
while !src[src_start..src_end].is_empty() && !end {
let mut dbuf = [0; 8];
let mut dlen = 8;
let mut j = 0;
while j < 8 {
if src[src_start..src_end].is_empty() {
if self.pad_char.is_some() {
return Err(DecodeError(olen - (src_end - src_start) - j));
}
(dlen, end) = (j, true);
break;
}
let in_ = src[src_start];
src_start += 1;
match self.pad_char {
Some(padding)
if padding == (in_ as char) && j >= 2 && (src_end - src_start) < 8 =>
{
if (src_end - src_start) + j < 8 - 1 {
return Err(DecodeError(olen));
}
let mut k = 0;
while k < 8 - 1 - j {
if (src_end - src_start) > k && (src[src_start + k] as char) != padding
{
return Err(DecodeError(olen - (src_end - src_start)));
}
k += 1;
}
(dlen, end) = (j, true);
if dlen == 1 || dlen == 3 || dlen == 6 {
return Err(DecodeError(olen - (src_end - src_start) - 1));
}
break;
}
_ => {
dbuf[j] = self.decode_map[in_ as usize];
if dbuf[j] == 0xFF {
return Err(DecodeError(olen - (src_end - src_start) - 1));
}
j += 1;
}
}
}
match dlen {
8 => {
src[dsti + 4] = dbuf[6] << 5 | dbuf[7];
n += 1;
src[dsti + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3;
n += 1;
src[dsti + 2] = dbuf[3] << 4 | dbuf[4] >> 1;
n += 1;
src[dsti + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4;
n += 1;
src[dsti] = dbuf[0] << 3 | dbuf[1] >> 2;
n += 1;
}
7 => {
src[dsti + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3;
n += 1;
src[dsti + 2] = dbuf[3] << 4 | dbuf[4] >> 1;
n += 1;
src[dsti + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4;
n += 1;
src[dsti] = dbuf[0] << 3 | dbuf[1] >> 2;
n += 1;
}
5 => {
src[dsti + 2] = dbuf[3] << 4 | dbuf[4] >> 1;
n += 1;
src[dsti + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4;
n += 1;
src[dsti] = dbuf[0] << 3 | dbuf[1] >> 2;
n += 1;
}
4 => {
src[dsti + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4;
n += 1;
src[dsti] = dbuf[0] << 3 | dbuf[1] >> 2;
n += 1;
}
2 => {
src[dsti] = dbuf[0] << 3 | dbuf[1] >> 2;
n += 1;
}
_ => {}
}
dsti += 5;
}
Ok((n, end))
}
#[inline]
pub const fn decode_len(&self, n: usize) -> usize {
if self.pad_char.is_none() {
return n * 5 / 8;
}
n / 8 * 5
}
#[inline]
fn decode_in(&self, mut src: &[u8], dst: &mut [u8]) -> Result<(usize, bool), DecodeError> {
let mut n = 0;
let mut end = false;
let mut dsti = 0;
let olen = src.len();
while !src.is_empty() && !end {
let mut dbuf = [0; 8];
let mut dlen = 8;
let mut j = 0;
while j < 8 {
if src.is_empty() {
if self.pad_char.is_some() {
return Err(DecodeError(olen - src.len() - j));
}
(dlen, end) = (j, true);
break;
}
let in_ = src[0];
src = &src[1..];
match self.pad_char {
Some(padding) if padding == (in_ as char) && j >= 2 && src.len() < 8 => {
if src.len() + j < 8 - 1 {
return Err(DecodeError(olen));
}
let mut k = 0;
while k < 8 - 1 - j {
if src.len() > k && (src[k] as char) != padding {
return Err(DecodeError(olen - src.len()));
}
k += 1;
}
(dlen, end) = (j, true);
if dlen == 1 || dlen == 3 || dlen == 6 {
return Err(DecodeError(olen - src.len() - 1));
}
break;
}
_ => {
dbuf[j] = self.decode_map[in_ as usize];
if dbuf[j] == 0xFF {
return Err(DecodeError(olen - src.len() - 1));
}
j += 1;
}
}
}
match dlen {
8 => {
dst[dsti + 4] = dbuf[6] << 5 | dbuf[7];
n += 1;
dst[dsti + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3;
n += 1;
dst[dsti + 2] = dbuf[3] << 4 | dbuf[4] >> 1;
n += 1;
dst[dsti + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4;
n += 1;
dst[dsti] = dbuf[0] << 3 | dbuf[1] >> 2;
n += 1;
}
7 => {
dst[dsti + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3;
n += 1;
dst[dsti + 2] = dbuf[3] << 4 | dbuf[4] >> 1;
n += 1;
dst[dsti + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4;
n += 1;
dst[dsti] = dbuf[0] << 3 | dbuf[1] >> 2;
n += 1;
}
5 => {
dst[dsti + 2] = dbuf[3] << 4 | dbuf[4] >> 1;
n += 1;
dst[dsti + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4;
n += 1;
dst[dsti] = dbuf[0] << 3 | dbuf[1] >> 2;
n += 1;
}
4 => {
dst[dsti + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4;
n += 1;
dst[dsti] = dbuf[0] << 3 | dbuf[1] >> 2;
n += 1;
}
2 => {
dst[dsti] = dbuf[0] << 3 | dbuf[1] >> 2;
n += 1;
}
_ => {}
}
dsti += 5;
}
Ok((n, end))
}
}
#[inline]
fn strip_new_lines_inplace(dst: &mut [u8]) -> usize {
let mut offset = 0;
for i in 0..dst.len() {
let b = dst[i];
if b.eq(&b'\r') || b.eq(&b'\n') {
continue;
}
dst[offset] = b;
offset += 1;
}
offset
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DecodeError(usize);
impl core::fmt::Display for DecodeError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "illegal base32 data at input byte {}", self.0)
}
}
#[cfg(feature = "std")]
impl std::error::Error for DecodeError {}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Encoder<W> {
enc: Base32,
writer: W,
buf: [u8; 5],
nbuf: usize,
out: [u8; 1024],
}
impl<W> Encoder<W> {
#[inline]
pub const fn new(enc: Base32, writer: W) -> Self {
Self {
enc,
writer,
buf: [0; 5],
nbuf: 0,
out: [0; 1024],
}
}
}
#[cfg(feature = "std")]
impl<W: std::io::Write> std::io::Write for Encoder<W> {
fn write(&mut self, mut buf: &[u8]) -> std::io::Result<usize> {
let mut n = 0;
if self.nbuf > 0 {
let mut i = 0;
while i < buf.len() && self.nbuf < 5 {
self.buf[self.nbuf] = buf[i];
self.nbuf += 1;
i += 1;
}
n += i;
buf = &buf[i..];
if self.nbuf < 5 {
return Ok(n);
}
self.enc.encode(&self.buf, &mut self.out);
self.writer.write_all(&self.out[..8])?;
self.nbuf = 0;
}
while buf.len() >= 5 {
let mut nn = self.out.len() / 8 * 5;
if nn > buf.len() {
nn = buf.len();
nn -= nn % 5;
}
self.enc.encode(&buf[..nn], &mut self.out);
self.writer.write_all(&self.out[..nn / 5 * 8])?;
n += nn;
buf = &buf[nn..];
}
crate::copy(buf, &mut self.buf);
self.nbuf = buf.len();
n += buf.len();
Ok(n)
}
fn flush(&mut self) -> std::io::Result<()> {
if self.nbuf > 0 {
self.enc.encode(&self.buf[..self.nbuf], &mut self.out);
let encoded_len = self.enc.encoded_len(self.nbuf);
self.nbuf = 0;
self.writer.write_all(&self.out[..encoded_len])?;
}
self.writer.flush()
}
}
#[cfg(all(feature = "std", feature = "io"))]
impl<W: std::io::Write> crate::io::Closer for Encoder<W> {
fn close(&mut self) -> std::io::Result<()> {
use std::io::Write;
self.flush()
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
struct NewLineFilteringReader<R> {
wrapped: R,
}
impl<R> NewLineFilteringReader<R> {
#[inline]
const fn new(reader: R) -> NewLineFilteringReader<R> {
NewLineFilteringReader { wrapped: reader }
}
}
#[cfg(feature = "std")]
impl<R: std::io::Read> From<R> for NewLineFilteringReader<R> {
fn from(value: R) -> Self {
Self { wrapped: value }
}
}
impl<R: std::io::Read> std::io::Read for NewLineFilteringReader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self.wrapped.read(buf) {
Ok(mut n) => {
while n > 0 {
let s = &mut buf[..n];
let offset = strip_new_lines_inplace(s);
if offset > 0 {
return Ok(offset);
}
n = self.wrapped.read(buf)?;
}
Ok(n)
}
Err(e) => Err(e),
}
}
}
#[inline]
fn read_encoded_data(
r: &mut impl std::io::Read,
buf: &mut [u8],
min: usize,
expects_padding: bool,
) -> std::io::Result<usize> {
let mut n = 0;
while n < min {
n += r.read(&mut buf[n..])?;
if n == 0 {
break;
}
}
if n < min && n > 0 {
return Err(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
"base32 decoder: data was read, less than min bytes could be read",
));
}
if expects_padding && min < 8 && n == 0 {
return Err(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
"base32 decoder: no data was read, the buffer already contains some data",
));
}
Ok(n)
}
#[cfg(feature = "std")]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Decoder<R> {
enc: Base32,
reader: NewLineFilteringReader<R>,
end: bool,
buf: [u8; 1024],
nbuf: usize,
out: std::vec::Vec<u8>,
out_buf: [u8; 1024 / 8 * 5],
}
#[cfg(feature = "std")]
impl<R> Decoder<R> {
#[inline]
pub const fn new(enc: Base32, reader: R) -> Self {
Self {
enc,
reader: NewLineFilteringReader::new(reader),
end: false,
buf: [0; 1024],
nbuf: 0,
out: std::vec::Vec::new(),
out_buf: [0; 1024 / 8 * 5],
}
}
}
#[cfg(feature = "std")]
impl<R: std::io::Read> std::io::Read for Decoder<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let n;
if !self.out.is_empty() {
n = crate::copy(&self.out, buf);
self.out.drain(..self.out.len().min(n));
return Ok(n);
}
let mut nn = (buf.len() / 5 * 8).clamp(8, 1024);
let (min, expects_padding) = match self.enc.pad_char {
Some(_) => (8 - self.nbuf, true),
None => (1, false),
};
nn = read_encoded_data(
&mut self.reader,
&mut self.buf[self.nbuf..nn],
min,
expects_padding,
)?;
self.nbuf += nn;
if self.nbuf < min {
return Ok(0);
}
if nn > 0 && self.end {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
DecodeError(0),
));
}
let nr = match self.enc.pad_char {
Some(_) => self.nbuf / 8 * 8,
None => self.nbuf,
};
let mut nw = self.enc.decode_len(self.nbuf);
if nw > buf.len() {
(nw, self.end) = self
.enc
.decode_in(&self.buf[..nr], &mut self.out_buf)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
self.out = self.out_buf[..nw].to_vec();
n = crate::copy(&self.out, buf);
self.out.drain(..n);
} else {
(n, self.end) = self
.enc
.decode_in(&self.buf[..nr], buf)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
}
self.nbuf -= nr;
for i in 0..self.nbuf {
self.buf[i] = self.buf[i + nr];
}
Ok(n)
}
}
#[cfg(test)]
mod test {
use super::*;
use std::io::{Read, Write};
struct TestPair {
decoded: String,
encoded: String,
}
fn pairs() -> Vec<TestPair> {
vec![
TestPair {
decoded: Default::default(),
encoded: Default::default(),
},
TestPair {
decoded: "f".to_string(),
encoded: "MY======".to_string(),
},
TestPair {
decoded: "fo".to_string(),
encoded: "MZXQ====".to_string(),
},
TestPair {
decoded: "foo".to_string(),
encoded: "MZXW6===".to_string(),
},
TestPair {
decoded: "foob".to_string(),
encoded: "MZXW6YQ=".to_string(),
},
TestPair {
decoded: "fooba".to_string(),
encoded: "MZXW6YTB".to_string(),
},
TestPair {
decoded: "foobar".to_string(),
encoded: "MZXW6YTBOI======".to_string(),
},
TestPair {
decoded: "sure.".to_string(),
encoded: "ON2XEZJO".to_string(),
},
TestPair {
decoded: "sure".to_string(),
encoded: "ON2XEZI=".to_string(),
},
TestPair {
decoded: "sur".to_string(),
encoded: "ON2XE===".to_string(),
},
TestPair {
decoded: "su".to_string(),
encoded: "ON2Q====".to_string(),
},
TestPair {
decoded: "leasure.".to_string(),
encoded: "NRSWC43VOJSS4===".to_string(),
},
TestPair {
decoded: "easure.".to_string(),
encoded: "MVQXG5LSMUXA====".to_string(),
},
TestPair {
decoded: "asure.".to_string(),
encoded: "MFZXK4TFFY======".to_string(),
},
TestPair {
decoded: "sure.".to_string(),
encoded: "ON2XEZJO".to_string(),
},
]
}
fn big_test() -> TestPair {
TestPair {
decoded: "Twas brillig, and the slithy toves".to_string(),
encoded: "KR3WC4ZAMJZGS3DMNFTSYIDBNZSCA5DIMUQHG3DJORUHSIDUN53GK4Y=".to_string(),
}
}
#[test]
fn test_encode() {
for p in pairs() {
let got = STD_ENCODING.encode_to_vec(p.decoded.as_bytes());
assert_eq!(got, p.encoded.as_bytes());
}
}
#[test]
fn test_encoder() {
for p in pairs() {
let mut got = Vec::new();
let mut encoder = STD_ENCODING.encoder(&mut got);
let _ = encoder.write(p.decoded.as_bytes()).unwrap();
encoder.flush().unwrap();
assert_eq!(got, p.encoded.as_bytes());
}
}
#[test]
fn test_encoder_buffering() {
let input = big_test();
for bs in 1..=12 {
let mut bb = Vec::new();
let mut encoder = STD_ENCODING.encoder(&mut bb);
let mut pos = 0;
while pos < input.decoded.len() {
let mut end = pos + bs;
if end > input.decoded.len() {
end = input.decoded.len();
}
let n = encoder.write(&input.decoded.as_bytes()[pos..end]).unwrap();
assert_eq!(n, end - pos);
pos += bs;
}
encoder.flush().unwrap();
assert_eq!(bb, input.encoded.as_bytes());
}
}
#[test]
fn test_decode() {
for p in pairs() {
let mut dbuf = vec![0; STD_ENCODING.decode_len(p.encoded.len())];
let (n, end) = STD_ENCODING
.decode_in(p.encoded.as_bytes(), &mut dbuf)
.unwrap();
assert_eq!(n, p.decoded.len());
if !p.encoded.is_empty() {
assert_eq!(end, p.encoded.as_bytes()[p.encoded.len() - 1] == b'=');
}
assert_eq!(&dbuf[..n], p.decoded.as_bytes());
let dbuf = STD_ENCODING.decode_to_vec(p.encoded.as_bytes()).unwrap();
assert_eq!(dbuf, p.decoded.as_bytes());
}
}
#[test]
fn test_decoder() {
for p in pairs() {
let mut reader = p.encoded.as_bytes().to_vec();
let mut decoder =
Base32::new_unchecked(ENCODE_STD).decoder(std::io::Cursor::new(&mut reader));
let mut dbuf = vec![0; STD_ENCODING.decode_len(p.encoded.len())];
match decoder.read(&mut dbuf) {
Ok(n) => {
assert_eq!(n, p.decoded.len());
assert_eq!(&dbuf[..n], p.decoded.as_bytes());
}
Err(e) => {
assert_eq!(e.kind(), std::io::ErrorKind::UnexpectedEof);
}
}
}
}
#[test]
fn test_decoder_buffering() {
let big = big_test();
for bs in 1..=12 {
let mut decoder = STD_ENCODING.decoder(std::io::Cursor::new(big.encoded.as_bytes()));
let mut buf = vec![0; big.decoded.len() + 12];
let mut total = 0;
while total < big.decoded.len() {
match decoder.read(&mut buf[total..total + bs]) {
Ok(nn) => {
total += nn;
}
Err(e) => {
if e.kind() != std::io::ErrorKind::UnexpectedEof {
panic!("unexpected error: {}", e);
}
break;
}
}
}
assert_eq!(big.decoded.as_bytes(), &buf[..total]);
}
}
#[test]
fn test_decode_corrupt() {
struct Case {
input: &'static str,
offset: isize, }
let cases = vec![
Case {
input: "",
offset: -1,
},
Case {
input: "!!!!",
offset: 0,
},
Case {
input: "x===",
offset: 0,
},
Case {
input: "AA=A====",
offset: 2,
},
Case {
input: "AAA=AAAA",
offset: 3,
},
Case {
input: "MMMMMMMMM",
offset: 8,
},
Case {
input: "MMMMMM",
offset: 0,
},
Case {
input: "A=",
offset: 1,
},
Case {
input: "AA=",
offset: 3,
},
Case {
input: "AA==",
offset: 4,
},
Case {
input: "AA===",
offset: 5,
},
Case {
input: "AAAA=",
offset: 5,
},
Case {
input: "AAAA==",
offset: 6,
},
Case {
input: "AAAAA=",
offset: 6,
},
Case {
input: "AAAAA==",
offset: 7,
},
Case {
input: "A=======",
offset: 1,
},
Case {
input: "AA======",
offset: -1,
},
Case {
input: "AAA=====",
offset: 3,
},
Case {
input: "AAAA====",
offset: -1,
},
Case {
input: "AAAAA===",
offset: -1,
},
Case {
input: "AAAAAA==",
offset: 6,
},
Case {
input: "AAAAAAA=",
offset: -1,
},
Case {
input: "AAAAAAAA",
offset: -1,
},
];
for c in cases {
let mut dbuf = vec![0; STD_ENCODING.decode_len(c.input.len())];
let x = STD_ENCODING.decode(c.input.as_bytes(), &mut dbuf);
if c.offset == -1 {
assert!(x.is_ok());
continue;
}
assert!(x.is_err());
}
}
#[test]
fn test_big() {
let n = 3 * 1000 + 1;
let mut raw = vec![0; n];
const ALPHA: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for i in 0..n {
raw[i] = ALPHA[i % ALPHA.len()];
}
let mut encoded = vec![];
let mut w = STD_ENCODING.encoder(&mut encoded);
let _ = w.write(&raw).unwrap();
w.flush().unwrap();
eprintln!("encoded: {}", encoded.len());
let mut dst = String::new();
STD_ENCODING
.decoder(std::io::Cursor::new(&encoded))
.read_to_string(&mut dst)
.unwrap();
assert_eq!(raw, dst.as_bytes());
}
#[test]
fn test_new_line_characters() {
let test_string_encode = |expected: &str, examples: &[&str]| {
for e in examples {
match STD_ENCODING.decode_to_vec(e.as_bytes()) {
Ok(buf) => {
assert_eq!(expected.as_bytes(), &buf);
}
Err(err) => {
eprintln!("Decode {} failed: {}", e, err);
continue;
}
}
}
};
const EXAMPLES: &[&str] = &[
"ON2XEZI=",
"ON2XEZI=\r",
"ON2XEZI=\n",
"ON2XEZI=\r\n",
"ON2XEZ\r\nI=",
"ON2X\rEZ\nI=",
"ON2X\nEZ\rI=",
"ON2XEZ\nI=",
"ON2XEZI\n=",
];
test_string_encode("sure", EXAMPLES);
const EXAMPLES1: &[&str] = &["MZXW6YTBOI======", "MZXW6YTBOI=\r\n====="];
test_string_encode("foobar", EXAMPLES1);
}
#[test]
fn test_decoder_without_newlines() {
const ENCODED: &str = r"JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4
RAMFSGS4DJONUWG2LOM4QGK3DJOQWCA43FMQQGI3YKMVUXK43NN5SCA5DFNVYG64RANFXGG2LENFSH
K3TUEB2XIIDMMFRG64TFEBSXIIDEN5WG64TFEBWWCZ3OMEQGC3DJOF2WCLRAKV2CAZLONFWQUYLEEB
WWS3TJNUQHMZLONFQW2LBAOF2WS4ZANZXXG5DSOVSCAZLYMVZGG2LUMF2GS33OEB2WY3DBNVRW6IDM
MFRG64TJOMQG42LTNEQHK5AKMFWGS4LVNFYCAZLYEBSWCIDDN5WW233EN4QGG33OONSXC5LBOQXCAR
DVNFZSAYLVORSSA2LSOVZGKIDEN5WG64RANFXAU4TFOBZGK2DFNZSGK4TJOQQGS3RAOZXWY5LQORQX
IZJAOZSWY2LUEBSXG43FEBRWS3DMOVWSAZDPNRXXEZJAMV2SAZTVM5UWC5BANZ2WY3DBBJYGC4TJMF
2HK4ROEBCXQY3FOB2GK5LSEBZWS3TUEBXWGY3BMVRWC5BAMN2XA2LEMF2GC5BANZXW4IDQOJXWSZDF
NZ2CYIDTOVXHIIDJNYFGG5LMOBQSA4LVNEQG6ZTGNFRWSYJAMRSXGZLSOVXHIIDNN5WGY2LUEBQW42
LNEBUWIIDFON2CA3DBMJXXE5LNFY==
====";
let encoded_start = ENCODED.replace('\n', "");
let mut dec = STD_ENCODING.decoder(std::io::Cursor::new(&ENCODED));
let mut res1 = String::new();
dec.read_to_string(&mut res1).unwrap();
let mut dec = STD_ENCODING.decoder(std::io::Cursor::new(&encoded_start));
let mut res2 = String::new();
dec.read_to_string(&mut res2).unwrap();
assert_eq!(res1, res2);
}
#[test]
fn test_with_custom_padding() {
for case in pairs() {
let default_padding = STD_ENCODING.encode_to_vec(case.decoded.as_bytes());
let custom_padding = STD_ENCODING
.with_padding_unchecked(Some('@'))
.encode_to_vec(case.decoded.as_bytes());
let expected = String::from_utf8_lossy(&default_padding).replace('=', "@");
assert_eq!(expected, String::from_utf8_lossy(&custom_padding));
assert_eq!(case.encoded.as_bytes(), default_padding);
}
}
#[test]
fn test_without_padding() {
for case in pairs() {
let default_padding = STD_ENCODING.encode_to_vec(case.decoded.as_bytes());
let custom_padding = STD_ENCODING
.with_padding_unchecked(None)
.encode_to_vec(case.decoded.as_bytes());
let expected = String::from_utf8_lossy(&default_padding)
.trim_end_matches('=')
.to_owned();
assert_eq!(expected, String::from_utf8_lossy(&custom_padding));
assert_eq!(case.encoded.as_bytes(), default_padding);
}
}
#[test]
fn test_decode_with_padding() {
let encodings = [
STD_ENCODING,
STD_ENCODING.with_padding_unchecked(Some('-')),
STD_ENCODING.with_padding_unchecked(None),
];
for enc in encodings {
for case in pairs() {
let input = case.decoded.as_bytes();
let encoded = enc.encode_to_vec(input);
let decoded = enc.decode_to_vec(&encoded).unwrap();
assert_eq!(input, &decoded);
}
}
}
#[test]
fn test_decode_with_wrong_padding() {
let encoded = STD_ENCODING.encode_to_vec(b"foobar");
let _ = STD_ENCODING
.with_padding_unchecked(Some('-'))
.decode_to_vec(&encoded)
.unwrap_err();
let _ = STD_ENCODING
.with_padding_unchecked(None)
.decode_to_vec(&encoded)
.unwrap_err();
}
#[test]
fn test_buffered_decoding_padding() {}
#[test]
fn test_buffered_decoding_same_error() {}
#[test]
fn test_encoded_decoded_len() {
struct TestCase {
in_: usize,
want_enc: usize,
want_dec: usize,
}
struct Test {
enc: Base32,
cases: &'static [TestCase],
}
let tests = [
Test {
enc: STD_ENCODING,
cases: &[
TestCase {
in_: 0,
want_enc: 0,
want_dec: 0,
},
TestCase {
in_: 1,
want_enc: 8,
want_dec: 5,
},
TestCase {
in_: 5,
want_enc: 8,
want_dec: 5,
},
TestCase {
in_: 6,
want_enc: 16,
want_dec: 10,
},
TestCase {
in_: 10,
want_enc: 16,
want_dec: 10,
},
],
},
Test {
enc: STD_ENCODING.with_padding_unchecked(None),
cases: &[
TestCase {
in_: 0,
want_enc: 0,
want_dec: 0,
},
TestCase {
in_: 1,
want_enc: 2,
want_dec: 1,
},
TestCase {
in_: 2,
want_enc: 4,
want_dec: 2,
},
TestCase {
in_: 5,
want_enc: 8,
want_dec: 5,
},
TestCase {
in_: 6,
want_enc: 10,
want_dec: 6,
},
TestCase {
in_: 7,
want_enc: 12,
want_dec: 7,
},
TestCase {
in_: 10,
want_enc: 16,
want_dec: 10,
},
TestCase {
in_: 11,
want_enc: 18,
want_dec: 11,
},
],
},
];
let data = vec![b'x'; 100];
for test in tests {
for tc in test.cases {
let enc_len = test.enc.encoded_len(tc.in_);
let dec_len = test.enc.decode_len(enc_len);
let enc = test.enc.encode_to_vec(&data[..tc.in_]);
assert_eq!(enc_len, enc.len());
assert_eq!(enc_len, tc.want_enc);
assert_eq!(dec_len, tc.want_dec);
}
}
}
#[test]
fn test_without_padding_close() {
let encodings = [STD_ENCODING, STD_ENCODING.with_padding_unchecked(None)];
for enc in encodings {
for case in pairs() {
let mut buf = Vec::new();
let mut encoder = enc.encoder(&mut buf);
let _ = encoder.write(case.decoded.as_bytes()).unwrap();
encoder.flush().unwrap();
let mut expected = case.encoded;
if enc.pad_char.is_none() {
expected = expected.replace('=', "");
}
assert_eq!(expected.as_bytes(), &buf);
}
}
}
#[test]
fn test_decode_read_all() {
let encodings = [STD_ENCODING, STD_ENCODING.with_padding_unchecked(None)];
for pair in pairs() {
for enc in encodings {
let mut encoded = pair.encoded.clone();
if enc.pad_char.is_none() {
encoded = encoded.replace('=', "");
}
let mut dec = String::new();
enc.decoder(std::io::Cursor::new(encoded))
.read_to_string(&mut dec)
.unwrap();
assert_eq!(pair.decoded, dec);
}
}
}
#[test]
fn test_decode_small_buffer() {
let encodings = [STD_ENCODING, STD_ENCODING.with_padding_unchecked(None)];
for buffer_size in 1..200 {
for pair in pairs() {
for enc in encodings {
let mut encoded = pair.encoded.clone();
if enc.pad_char.is_none() {
encoded = encoded.replace('=', "");
}
let mut decoder = enc.decoder(std::io::Cursor::new(encoded));
let mut all_read = Vec::new();
loop {
let mut buf = vec![0; buffer_size];
let n = decoder.read(&mut buf).unwrap();
if n == 0 {
break;
}
all_read.extend_from_slice(&buf[..n]);
}
assert_eq!(pair.decoded.as_bytes(), all_read);
}
}
}
}
}