basekit 0.4.0

Universal library for encoding in various bases
Documentation
use super::super::config::Base32DecodeConfig;
use super::super::error::Base32Error;

#[inline(always)]
pub(crate) unsafe fn decode_tail_into(
    config: &Base32DecodeConfig,
    dst: &mut [u8],
    dst_offset: usize,
    tail: &[u8],
    src_offset: usize,
    padding_count: usize,
) -> Result<usize, Base32Error> {
    let tail_len = tail.len();

    if tail_len == 0 {
        return Ok(0);
    }

    let bytes_written = match padding_count {
        6 => Ok(1),
        4 => Ok(2),
        3 => Ok(3),
        1 => Ok(4),
        0 => match tail_len {
            1 => Ok(0),
            2 => Ok(1),
            3 => Ok(1),
            4 => Ok(2),
            5 => Ok(3),
            6 => Ok(3),
            7 => Ok(4),
            _ => panic!("invalid unpadded base32 tail length: {}", tail_len),
        },
        _ => Err(Base32Error::InvalidPadding),
    };

    let decode_table = config.decode_table;
    let mut indices: [i8; 8] = [0; 8];

    for (j, &byte) in tail.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 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;

    let bytes_written = bytes_written?;

    unsafe {
        let ptr = dst.as_mut_ptr().add(dst_offset);

        match bytes_written {
            0 => {}
            1 => {
                ptr.write(b0 as u8);
            }
            2 => {
                ptr.write(b0 as u8);
                ptr.offset(1).write(b1 as u8);
            }
            3 => {
                ptr.write(b0 as u8);
                ptr.offset(1).write(b1 as u8);
                ptr.offset(2).write(b2 as u8);
            }
            4 => {
                ptr.write(b0 as u8);
                ptr.offset(1).write(b1 as u8);
                ptr.offset(2).write(b2 as u8);
                ptr.offset(3).write(b3 as u8);
            }
            5 => {
                ptr.write(b0 as u8);
                ptr.offset(1).write(b1 as u8);
                ptr.offset(2).write(b2 as u8);
                ptr.offset(3).write(b3 as u8);
                ptr.offset(4).write(b4 as u8);
            }
            _ => panic!("invalid bytes_written value: {}", bytes_written),
        }
    }

    Ok(bytes_written)
}