1use log::error;
12use prescript::Encoding;
13use std::borrow::Cow;
14
15mod inner;
16
17pub use inner::{Error, Result};
18
19pub struct Font<'a> {
20 font_data: &'a [u8],
21 name: Cow<'a, str>,
22 top_dict_data: inner::TopDictData<'a>,
23}
24
25impl<'a> Font<'a> {
26 pub fn new(
27 font_data: &'a [u8],
28 name: Cow<'a, str>,
29 top_dict_data: inner::TopDictData<'a>,
30 ) -> Self {
31 Self {
32 font_data,
33 name,
34 top_dict_data,
35 }
36 }
37
38 pub fn name(&self) -> &str {
39 &self.name
40 }
41
42 pub fn encodings(&self) -> Result<Encoding> {
43 let charsets = self.top_dict_data.charsets(self.font_data)?;
44 let (encodings, supplements) = self.top_dict_data.encodings(self.font_data)?;
45 let mut r = encodings.build(&charsets, self.top_dict_data.string_index())?;
46 if let Some(supplements) = supplements {
47 for supp in supplements {
48 supp.apply(self.top_dict_data.string_index(), &mut r)?;
49 }
50 }
51
52 Ok(r)
53 }
54}
55
56pub struct Fonts<'a> {
58 data: &'a [u8],
59 names_index: inner::NameIndex<'a>,
60 top_dict_index: inner::TopDictIndex<'a>,
61 string_index: inner::StringIndex<'a>,
62 idx: usize,
63}
64
65impl<'a> Fonts<'a> {
66 pub fn new(f: &File<'a>) -> Result<Self> {
67 let names_offset = f.header.hdr_size as usize;
68 let buf = &f.data[names_offset..];
69 let (names_index, top_dict_index, string_index) = inner::parse_fonts(buf)?;
70 Ok(Self {
71 data: f.data,
72 names_index,
73 top_dict_index,
74 string_index,
75 idx: 0,
76 })
77 }
78}
79
80impl<'a> Iterator for Fonts<'a> {
81 type Item = Font<'a>;
82
83 fn next(&mut self) -> Option<Self::Item> {
84 if self.idx < self.names_index.len() {
85 let name = self.names_index.get(self.idx).unwrap_or_else(|e| {
86 error!("Error getting name: {}", e);
87 None
88 });
89 let top_dict_data = self.top_dict_index.get(self.idx, self.string_index).ok()?;
90 self.idx += 1;
91 match name {
92 Some(name) => Some(Font::new(self.data, name, top_dict_data)),
93 None => self.next(),
94 }
95 } else {
96 None
97 }
98 }
99}
100
101pub struct File<'a> {
102 header: inner::Header,
103 data: &'a [u8],
104}
105
106impl<'a> File<'a> {
107 pub fn open(data: &'a [u8]) -> Result<Self> {
108 let header = inner::parse_header(data)?;
109 Ok(File { data, header })
110 }
111
112 pub fn iter(&self) -> Result<Fonts<'a>> {
113 Fonts::new(self)
114 }
115
116 pub fn major_version(&self) -> u8 {
117 self.header.major
118 }
119
120 pub fn minor_version(&self) -> u8 {
121 self.header.minor
122 }
123}
124
125#[cfg(test)]
126mod tests;