eot-parse 1.0.1

Parser for the Embeddable OpenType font format.
Documentation
// Copyright (c) 2013-2026 Brennan T. Vincent <brennanv@email.arizona.edu>
// Copyright (c) 2026 Kiƫd Llaentenn <kiedtl@tilde.team>
//
// This file is part of eot-rs, which is based on libeot, which is licensed under the MPL license,
// version 2.0. For full details, read the LICENSE and PATENTS file.

#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum Error {
    OFF_BYTE_BOUNDARY = 7,
    VALUE_OUT_OF_BOUNDS = 6,
    OUT_OF_RESERVED_SPACE = 5,
    CANT_ALLOCATE_MEMORY_FOR_STREAM = 4,
    SEEK_PAST_EOS = 3,
    NEGATIVE_SEEK = 2,
    NOT_ENOUGH_DATA = 1,
}

#[derive(Clone)]
pub struct Stream {
    pub buf: Vec<u8>,
    pub pos: usize,
    pub bit_pos: usize,
}

impl Stream {
    fn check_byte_boundary(&self) -> Result<(), Error> {
        if self.bit_pos != 0 {
            return Err(Error::OFF_BYTE_BOUNDARY);
        }
        Ok(())
    }

    pub fn new(size: usize) -> Self {
        Self::new2(size, size)
    }

    pub fn new2(size: usize, reserved: usize) -> Self {
        let mut ret = Stream {
            buf: Vec::with_capacity(reserved),
            pos: 0,
            bit_pos: 0,
        };
        for _ in 0..size {
            ret.buf.push(0);
        }
        ret
    }

    pub fn be_read_rest_as_u32(&mut self) -> Result<u32, Error> {
        if self.pos >= self.buf.len() {
            return Err(Error::NOT_ENOUGH_DATA);
        }

        Ok(match self.buf.len() - self.pos {
            1 => (self.be_read_u8()? as u32) << 24,
            2 => (self.be_read_u16()? as u32) << 16,
            3 => self.be_read_u24()? << 8,
            4 | _ => self.be_read_u32()?,
        })
    }

    pub fn be_read_u8(&mut self) -> Result<u8, Error> {
        let v = self.be_peek_u8()?;
        self.pos += 1;
        Ok(v)
    }

    pub fn be_peek_u8(&mut self) -> Result<u8, Error> {
        self.check_byte_boundary()?;

        if self.pos >= self.buf.len() {
            return Err(Error::NOT_ENOUGH_DATA);
        }
        Ok(self.buf[self.pos])
    }

    pub fn be_read_u16(&mut self) -> Result<u16, Error> {
        self.check_byte_boundary()?;

        if self.pos + 2 > self.buf.len() {
            return Err(Error::NOT_ENOUGH_DATA);
        }

        let opos = self.pos;
        self.pos += 2;
        Ok((self.buf[opos] as u16) << 8 | self.buf[opos + 1] as u16)
    }

    pub fn be_read_u24(&mut self) -> Result<u32, Error> {
        self.check_byte_boundary()?;

        if self.pos + 3 > self.buf.len() {
            return Err(Error::NOT_ENOUGH_DATA);
        }

        let opos = self.pos;
        self.pos += 3;
        Ok((self.buf[opos] as u32) << 16 | (self.buf[opos + 1] as u32) << 8 | self.buf[opos + 2] as u32)
    }

    pub fn be_read_u32(&mut self) -> Result<u32, Error> {
        self.check_byte_boundary()?;

        if self.pos + 4 > self.buf.len() {
            return Err(Error::NOT_ENOUGH_DATA);
        }

        let opos = self.pos;
        self.pos += 4;
        Ok((self.buf[opos] as u32) << 24
            | (self.buf[opos + 1] as u32) << 16
            | (self.buf[opos + 2] as u32) << 8
            | self.buf[opos + 3] as u32)
    }

    pub fn be_read_i16(&mut self) -> Result<i16, Error> {
        Ok(self.be_read_u16()? as i16)
    }

    pub fn read_n_bits(&mut self, n: u32) -> Result<u32, Error> {
        let masks: [u8; 8] = [0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1];
        if n > 32 {
            return Err(Error::VALUE_OUT_OF_BOUNDS);
        }

        let mut out = 0u32;
        for i in 0..n {
            if self.pos >= self.buf.len() {
                return Err(Error::NOT_ENOUGH_DATA);
            }
            let is_bit_set = self.buf[self.pos] & masks[self.bit_pos] > 0;
            out |= if is_bit_set { 1 } else { 0 } << (n - i - 1);
            self.bit_pos += 1;
            if self.bit_pos == 8 {
                self.bit_pos = 0;
                self.pos += 1;
            }
        }

        Ok(out)
    }

    pub fn seek_relative(&mut self, offset: isize) -> Result<(), Error> {
        self.check_byte_boundary()?;

        let newpos = self.pos as isize + offset;
        if newpos < 0 {
            return Err(Error::NEGATIVE_SEEK);
        } else if newpos as usize > self.buf.len() {
            return Err(Error::SEEK_PAST_EOS);
        }

        self.pos = newpos as usize;
        Ok(())
    }

    pub fn seek_relative_through_reserve(&mut self, offset: isize) -> Result<(), Error> {
        self.check_byte_boundary()?;

        let newpos = self.pos as isize + offset;
        if newpos < 0 {
            return Err(Error::NEGATIVE_SEEK);
        } else if newpos as usize > self.buf.capacity() {
            return Err(Error::SEEK_PAST_EOS);
        }

        while self.buf.len() < newpos as usize {
            self.buf.push(0);
        }

        self.pos = newpos as usize;
        Ok(())
    }

    pub fn seek_absolute(&mut self, pos: usize) -> Result<(), Error> {
        self.check_byte_boundary()?;

        if pos > self.buf.len() {
            return Err(Error::SEEK_PAST_EOS);
        }

        self.pos = pos;
        Ok(())
    }

    pub fn seek_absolute_through_reserve(&mut self, pos: usize) -> Result<(), Error> {
        self.check_byte_boundary()?;
        if pos > self.buf.capacity() {
            return Err(Error::SEEK_PAST_EOS);
        }
        self.pos = pos;
        while self.buf.len() < self.pos {
            self.buf.push(0);
        }
        Ok(())
    }

    pub fn be_write_u8(&mut self, val: u8) -> Result<(), Error> {
        self.check_byte_boundary()?;

        if self.pos + 1 > self.buf.capacity() {
            return Err(Error::OUT_OF_RESERVED_SPACE);
        }

        if self.pos == self.buf.len() {
            self.buf.push(val);
        } else {
            self.buf[self.pos] = val;
        }

        self.pos += 1;
        Ok(())
    }

    pub fn be_write_i16(&mut self, val: i16) -> Result<(), Error> {
        self.be_write_u16(val as u16)
    }

    pub fn be_write_u16(&mut self, val: u16) -> Result<(), Error> {
        self.check_byte_boundary()?;

        if self.pos + 2 > self.buf.capacity() {
            return Err(Error::OUT_OF_RESERVED_SPACE);
        }

        let bytes = [((val >> 8) & 0xFF) as u8, (val & 0xFF) as u8];
        for byte in bytes {
            if self.pos == self.buf.len() {
                self.buf.push(byte);
            } else {
                self.buf[self.pos] = byte;
            }
            self.pos += 1;
        }

        Ok(())
    }

    pub fn be_write_u32(&mut self, val: u32) -> Result<(), Error> {
        self.check_byte_boundary()?;

        if self.pos + 4 > self.buf.capacity() {
            return Err(Error::OUT_OF_RESERVED_SPACE);
        }

        let bytes =
            [(val >> 24) as u8, ((val >> 16) & 0xFF) as u8, ((val >> 8) & 0xFF) as u8, (val & 0xFF) as u8];

        for byte in bytes {
            if self.pos == self.buf.len() {
                self.buf.push(byte);
            } else {
                self.buf[self.pos] = byte;
            }
            self.pos += 1;
        }

        Ok(())
    }

    pub fn be_checksum32(&mut self, begin_pos: usize, end_pos: usize) -> Result<u32, Error> {
        if begin_pos > end_pos {
            return Err(Error::VALUE_OUT_OF_BOUNDS);
        }

        if end_pos > self.buf.len() {
            return Err(Error::NOT_ENOUGH_DATA);
        }

        let mut slice = Stream::new(end_pos - begin_pos);
        slice.buf[..].copy_from_slice(&self.buf[begin_pos..end_pos]);
        let mut out: u32 = 0;

        loop {
            match slice.be_read_rest_as_u32() {
                Ok(c) => out = out.wrapping_add(c),
                Err(Error::NOT_ENOUGH_DATA) => break,
                Err(e) => return Err(e),
            }
        }

        Ok(out)
    }
}