binarytext 0.1.2

Binary-to-text encoders / decoders
Documentation
//! Implemention of the Base16 encoder.

use crate::binarytext::BinaryText;
use crate::error::BinTxtError;

/// Simply encodes and decodes Hex as described in RFC 4648
#[derive(Clone, Debug)]
pub struct Base16 {}

impl Default for Base16 {
    fn default() -> Self {
        Self::new()
    }
}

impl Base16 {
    pub fn new() -> Self {
        Self {}
    }
}

impl BinaryText for Base16 {
    fn base(&self) -> usize {
        16
    }

    fn name(&self) -> &str {
        "Base16"
    }

    fn n_bytes_encode(&self) -> usize {
        1
    }

    fn n_bytes_decode(&self) -> usize {
        2
    }

    fn encode_byte(&self, byte: u8) -> Result<u8, BinTxtError> {
        const LUT: [char; 16] = [
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
        ];
        if byte >= 16 {
            let msg = format!("Byte {byte} exceeds maximum {}", 16);
            return Err(BinTxtError::EncodingErr(msg));
        }
        Ok(LUT[byte as usize] as u8)
    }

    fn encode_into_vec(&self, input: &[u8], res: &mut Vec<u8>) -> Result<(), BinTxtError> {
        res.clear();
        for byte in input {
            let pos = byte >> 4;
            let b = self.encode_byte(pos)?;
            res.push(b);
            let pos = byte & 0xF;
            let b = self.encode_byte(pos)?;
            res.push(b);
        }
        Ok(())
    }

    fn decode_byte(&self, byte: u8) -> Result<u8, BinTxtError> {
        const LUT: [u8; 128] = [
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5,
            6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
            20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255,
            255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
            29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255,
        ];
        let b = if byte < 128 { LUT[byte as usize] } else { 255 };
        if b < 255 {
            Ok(b)
        } else {
            let errmsg = format!("Invalid byte \"{}\" in Base16 string", byte);
            Err(BinTxtError::DecodingErr(errmsg))
        }
    }

    fn decode_into_vec(&self, input: &[u8], res: &mut Vec<u8>) -> Result<(), BinTxtError> {
        if !input.len().is_multiple_of(2) {
            let errmsg = "Length of input must be a multiple of 2".to_string();
            return Err(BinTxtError::DecodingErr(errmsg));
        }
        res.clear();
        if !input.is_empty() {
            // Leave out preceding 0x / 0X for hex values
            let start = if &input[0..2] == b"0x" || &input[0..2] == b"0X" {
                2
            } else {
                0
            };
            for bytes in input[start..].chunks_exact(2) {
                let dec = self.decode_byte(bytes[0])?;
                let mut val = dec << 4;
                let dec = self.decode_byte(bytes[1])?;
                val |= dec;
                res.push(val);
            }
        }
        Ok(())
    }

    fn is_decodable(&self, input: &str) -> bool {
        if !input.len().is_multiple_of(2) {
            return false;
        }
        for &byte in input.as_bytes() {
            match self.decode_byte(byte) {
                Ok(_) => {}
                Err(_) => {
                    return false;
                }
            }
        }
        true
    }
}