honzo_chunks/data/
font.rs1use honzo_core::{FontEmbedding, HonzoError};
2
3pub const FONT_TAG: [u8; 4] = *b"FONT";
4
5pub fn is_font_tag(tag: &[u8; 4]) -> bool {
6 *tag == FONT_TAG
7}
8
9pub fn validate_font(bytes: &[u8]) -> Result<&[u8], HonzoError> {
11 if guess_font_format(bytes).is_none() {
12 return Err(HonzoError::Truncated);
13 }
14 Ok(bytes)
15}
16
17pub fn validate_font_bytes(bytes: &[u8]) -> Result<(), u8> {
19 match validate_font(bytes) {
20 Ok(..) => Ok(()),
21 Err(HonzoError::Truncated) => Err(7),
22 Err(..) => Err(255),
23 }
24}
25
26pub fn guess_font_format(bytes: &[u8]) -> Option<&'static str> {
28 if bytes.len() < 4 {
29 return None;
30 }
31 if &bytes[..4] == b"wOFF" {
32 return Some("font/woff");
33 }
34 if &bytes[..4] == b"wOF2" {
35 return Some("font/woff2");
36 }
37 if &bytes[..4] == b"OTTO" {
38 return Some("font/otf");
39 }
40 if bytes.starts_with(&[0x00, 0x01, 0x00, 0x00])
41 || bytes.starts_with(&[0x00, 0x01, 0x00, 0x01])
42 || bytes.starts_with(b"true")
43 || bytes.starts_with(b"typ1")
44 {
45 return Some("font/ttf");
46 }
47 None
48}
49
50pub fn read_font_toc_fields<'a>(
53 buf: &'a [u8],
54 cursor: &mut usize,
55) -> Result<(FontEmbedding, Option<&'a str>), HonzoError> {
56 if *cursor + 3 > buf.len() {
57 return Err(HonzoError::Truncated);
58 }
59 let embedding = FontEmbedding::from_u8(buf[*cursor])?;
60 *cursor += 1;
61 let url_len = u16::from_le_bytes([buf[*cursor], buf[*cursor + 1]]) as usize;
62 *cursor += 2;
63 let license_url = if url_len > 0 {
64 let end = *cursor + url_len;
65 if end > buf.len() {
66 return Err(HonzoError::Truncated);
67 }
68 let s = core::str::from_utf8(&buf[*cursor..end]).map_err(|_| HonzoError::Truncated)?;
69 *cursor = end;
70 Some(s)
71 } else {
72 None
73 };
74 Ok((embedding, license_url))
75}
76
77pub fn write_font_toc_fields(
79 out: &mut Vec<u8>,
80 embedding: FontEmbedding,
81 license_url: Option<&str>,
82) {
83 out.push(embedding as u8);
84 if let Some(url) = license_url {
85 out.extend_from_slice(&(url.len() as u16).to_le_bytes());
86 out.extend_from_slice(url.as_bytes());
87 } else {
88 out.extend_from_slice(&0u16.to_le_bytes());
89 }
90}
91
92pub fn chunk_name() -> &'static str {
93 "font"
94}