use super::super::config::Base32DecodeConfig;
use super::super::error::Base32Error;
#[inline(always)]
pub fn decode_tail_into(
config: &Base32DecodeConfig,
dst: &mut [u8],
src: &[u8],
src_offset: usize,
padding_count: usize,
) -> Result<usize, Base32Error> {
let decode_table = config.decode_table;
let mut indices: [i8; 8] = [0; 8];
for (j, &byte) in src.iter().enumerate() {
let pos = src_offset + j;
if let Some(padding) = config.padding {
if byte == padding {
let expected_min_pos = 8 - padding_count;
if j < expected_min_pos {
return Err(Base32Error::InvalidPadding);
}
indices[j] = 0;
} else {
if byte >= 128 {
return Err(Base32Error::InvalidCharacter(byte, pos));
}
let val = decode_table[byte as usize];
if val < 0 {
return Err(Base32Error::InvalidCharacter(byte, pos));
}
indices[j] = val;
}
} else {
if byte >= 128 {
return Err(Base32Error::InvalidCharacter(byte, pos));
}
let val = decode_table[byte as usize];
if val < 0 {
return Err(Base32Error::InvalidCharacter(byte, pos));
}
indices[j] = val;
}
}
let bytes_written = match padding_count {
6 => 1,
4 => 2,
3 => 3,
1 => 4,
0 => 5,
_ => return Err(Base32Error::InvalidPadding),
};
let i0 = indices[0] as u32;
let i1 = indices[1] as u32;
let i2 = indices[2] as u32;
let i3 = indices[3] as u32;
let i4 = indices[4] as u32;
let i5 = indices[5] as u32;
let i6 = indices[6] as u32;
let i7 = indices[7] as u32;
let b0 = (i0 << 3) | (i1 >> 2);
let b1 = (i1 << 6) | (i2 << 1) | (i3 >> 4);
let b2 = (i3 << 4) | (i4 >> 1);
let b3 = (i4 << 7) | (i5 << 2) | (i6 >> 3);
let b4 = (i6 << 5) | i7;
match padding_count {
6 => {
dst[0] = b0 as u8;
}
4 => {
dst[0] = b0 as u8;
dst[1] = b1 as u8;
}
3 => {
dst[0] = b0 as u8;
dst[1] = b1 as u8;
dst[2] = b2 as u8;
}
1 => {
dst[0] = b0 as u8;
dst[1] = b1 as u8;
dst[2] = b2 as u8;
dst[3] = b3 as u8;
}
0 => {
dst[0] = b0 as u8;
dst[1] = b1 as u8;
dst[2] = b2 as u8;
dst[3] = b3 as u8;
dst[4] = b4 as u8;
}
_ => unreachable!(),
}
Ok(bytes_written)
}