Skip to main content

eot_parse/
lib.rs

1// Copyright (c) 2013-2026 Brennan T. Vincent <brennanv@email.arizona.edu>
2// Copyright (c) 2026 Kiƫd Llaentenn <kiedtl@tilde.team>
3//
4// This file is part of eot-rs, which is based on libeot, which is licensed under the MPL license,
5// version 2.0. For full details, read the LICENSE and PATENTS file.
6
7pub mod core;
8pub mod metadata;
9
10mod lzcomp;
11mod stream;
12mod triplet_encodings;
13
14mod ctf {
15    pub(crate) mod sfnt_container;
16    pub(crate) mod ctf_parse;
17    pub(crate) mod ttf_parse;
18}
19
20use core::Error;
21
22use ctf::ctf_parse::parse_ctf;
23use metadata::Metadata;
24use stream::Stream;
25
26const TTEMBED_TTCOMPRESSED: ::core::ffi::c_int = 0x4 as ::core::ffi::c_int;
27const TTEMBED_XORENCRYPTDATA: ::core::ffi::c_int = 0x10000000 as ::core::ffi::c_int;
28
29pub fn eot_to_ttf(data: &[u8]) -> Result<(Metadata, Vec<u8>), Error> {
30    let meta = metadata::read_metadata(data)?;
31    let font_out = decode(
32        &data[meta.font_data_offset as usize..(meta.font_data_offset + meta.font_data_size) as usize],
33        meta.flags & TTEMBED_TTCOMPRESSED as u32 != 0,
34        meta.flags & TTEMBED_XORENCRYPTDATA as u32 != 0,
35    )?;
36    Ok((meta, font_out))
37}
38
39pub fn decode(data: &[u8], is_compressed: bool, is_encrypted: bool) -> Result<Vec<u8>, Error> {
40    const ENCRYPTION_KEY: u8 = 0x50;
41
42    let final_out_buffer: Vec<u8>;
43
44    let mut buf = Vec::from(data);
45    if is_encrypted {
46        for byte in &mut buf {
47            *byte ^= ENCRYPTION_KEY;
48        }
49    }
50
51    if is_compressed {
52        let len = buf.len();
53        let mut s_buf = Stream::new(0);
54        s_buf.buf = buf;
55        let ctfs = lzcomp::unpack_mtx(&mut s_buf, len as _)?;
56
57        let mut streams: [Stream; 3] = [Stream::new2(0, 0), Stream::new2(0, 0), Stream::new2(0, 0)];
58        for (stream, ctf) in streams.iter_mut().zip(ctfs.into_iter()) {
59            stream.buf = ctf;
60        }
61        let mut ctr = parse_ctf(&mut streams)?;
62        final_out_buffer = ctr.dump_to_vec()?;
63    } else {
64        final_out_buffer = buf;
65    }
66
67    Ok(final_out_buffer)
68}