osc7501-parser 0.1.0

Bounded, allocation-free OSC 7501 program-status parsing
Documentation
use crate::Error;

const INVALID: u8 = 255;
const fn table() -> [u8; 256] {
    let mut values = [INVALID; 256];
    let alphabet = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    let mut i: u8 = 0;
    while i < 64 {
        values[alphabet[i as usize] as usize] = i;
        i += 1;
    }
    values
}
const DECODE: [u8; 256] = table();

pub(crate) fn decode(input: &[u8], output: &mut [u8]) -> Result<usize, Error> {
    let padding = input.iter().rev().take_while(|&&byte| byte == b'=').count();
    let length = input.len() - padding;
    let remainder = length % 4;
    if padding > 2
        || remainder == 1
        || (padding != 0 && (!input.len().is_multiple_of(4) || padding != 4 - remainder))
    {
        return Err(Error::InvalidBase64);
    }
    let needed = length / 4 * 3
        + match remainder {
            2 => 1,
            3 => 2,
            _ => 0,
        };
    if needed > output.len() {
        return Err(Error::BufferTooSmall);
    }
    let mut written = 0;
    let (chunks, tail) = input[..length].as_chunks::<4>();
    for chunk in chunks {
        let [a, b, c, d] = [
            DECODE[chunk[0] as usize],
            DECODE[chunk[1] as usize],
            DECODE[chunk[2] as usize],
            DECODE[chunk[3] as usize],
        ];
        if (a | b | c | d) == INVALID {
            return Err(Error::InvalidBase64);
        }
        output[written] = a << 2 | b >> 4;
        output[written + 1] = b << 4 | c >> 2;
        output[written + 2] = c << 6 | d;
        written += 3;
    }
    if tail.len() >= 2 {
        let a = DECODE[tail[0] as usize];
        let b = DECODE[tail[1] as usize];
        if (a | b) == INVALID {
            return Err(Error::InvalidBase64);
        }
        output[written] = a << 2 | b >> 4;
        if tail.len() == 2 {
            if b & 15 != 0 {
                return Err(Error::InvalidBase64);
            }
        } else {
            let c = DECODE[tail[2] as usize];
            if c == INVALID || c & 3 != 0 {
                return Err(Error::InvalidBase64);
            }
            output[written + 1] = b << 4 | c >> 2;
        }
    }
    Ok(needed)
}