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.

pub mod core;
pub mod metadata;

mod lzcomp;
mod stream;
mod triplet_encodings;

mod ctf {
    pub(crate) mod sfnt_container;
    pub(crate) mod ctf_parse;
    pub(crate) mod ttf_parse;
}

use core::Error;

use ctf::ctf_parse::parse_ctf;
use metadata::Metadata;
use stream::Stream;

const TTEMBED_TTCOMPRESSED: ::core::ffi::c_int = 0x4 as ::core::ffi::c_int;
const TTEMBED_XORENCRYPTDATA: ::core::ffi::c_int = 0x10000000 as ::core::ffi::c_int;

pub fn eot_to_ttf(data: &[u8]) -> Result<(Metadata, Vec<u8>), Error> {
    let meta = metadata::read_metadata(data)?;
    let font_out = decode(
        &data[meta.font_data_offset as usize..(meta.font_data_offset + meta.font_data_size) as usize],
        meta.flags & TTEMBED_TTCOMPRESSED as u32 != 0,
        meta.flags & TTEMBED_XORENCRYPTDATA as u32 != 0,
    )?;
    Ok((meta, font_out))
}

pub fn decode(data: &[u8], is_compressed: bool, is_encrypted: bool) -> Result<Vec<u8>, Error> {
    const ENCRYPTION_KEY: u8 = 0x50;

    let final_out_buffer: Vec<u8>;

    let mut buf = Vec::from(data);
    if is_encrypted {
        for byte in &mut buf {
            *byte ^= ENCRYPTION_KEY;
        }
    }

    if is_compressed {
        let len = buf.len();
        let mut s_buf = Stream::new(0);
        s_buf.buf = buf;
        let ctfs = lzcomp::unpack_mtx(&mut s_buf, len as _)?;

        let mut streams: [Stream; 3] = [Stream::new2(0, 0), Stream::new2(0, 0), Stream::new2(0, 0)];
        for (stream, ctf) in streams.iter_mut().zip(ctfs.into_iter()) {
            stream.buf = ctf;
        }
        let mut ctr = parse_ctf(&mut streams)?;
        final_out_buffer = ctr.dump_to_vec()?;
    } else {
        final_out_buffer = buf;
    }

    Ok(final_out_buffer)
}