1use super::*;
2
3pub fn serialize(file: &File) -> Vec<u8> {
4 let mut b = vec![0_u8; 24];
7 let mut sub_file_sizes = SubFileSizes {
8 lf: 0,
9 lh: serialize_header(&file.header, &mut b),
10 bc: match file.char_info_bounds() {
11 None => 1,
12 Some((Char(bc), _)) => bc as i16,
13 },
14 ec: match file.char_info_bounds() {
15 None => 0,
16 Some((bc, ec)) => {
17 serialize_char_infos(file, bc, ec, &mut b);
18 ec.0 as i16
19 }
20 },
21 nw: serialize_section(&file.widths, &mut b, None),
22 nh: serialize_section(&file.heights, &mut b, None),
23 nd: serialize_section(&file.depths, &mut b, None),
24 ni: serialize_section(&file.italic_corrections, &mut b, None),
25 nl: serialize_section(
28 &file.lig_kern_program.instructions,
29 &mut b,
30 file.lig_kern_program.right_boundary_char,
31 ),
32 nk: serialize_section(&file.kerns, &mut b, None),
33 ne: serialize_section(&file.extensible_chars, &mut b, None),
34 np: serialize_section(&file.params, &mut b, None),
35 };
36 sub_file_sizes.lf = sub_file_sizes.valid_lf();
37 let sfs_b: [u8; 24] = sub_file_sizes.into();
38 for (i, byte) in sfs_b.into_iter().enumerate() {
39 b[i] = byte;
40 }
41 b
42}
43
44#[derive(Clone)]
45enum SerializableCharTag {
46 None,
47 Valid(CharTag),
48 Unset(u8),
49}
50
51fn serialize_char_infos(file: &File, bc: Char, ec: Char, b: &mut Vec<u8>) {
52 let mut v: Vec<(Option<CharDimensions>, SerializableCharTag)> =
53 vec![(None, SerializableCharTag::None); (ec.0 as usize) + 1 - (bc.0 as usize)];
54 for (c, dimens) in &file.char_dimens {
55 v[(c.0 - bc.0) as usize].0 = Some(dimens.clone());
56 }
57 for (c, tag) in &file.char_tags {
58 if let Some(slot) = v.get_mut((c.0 - bc.0) as usize) {
59 slot.1 = SerializableCharTag::Valid(tag.clone());
60 }
61 }
62 for (c, tag) in &file.unset_char_tags {
63 if let Some(slot) = v.get_mut((c.0 - bc.0) as usize) {
64 slot.1 = SerializableCharTag::Unset(*tag);
65 }
66 }
67 serialize_section(&v, b, None);
68}
69
70fn serialize_section<T: Serializable>(t: &[T], b: &mut Vec<u8>, c: Option<Char>) -> i16 {
71 let start = b.len();
72 for element in t {
73 element.serialize(b, c);
74 }
75 ((b.len() - start) / 4).try_into().unwrap()
76}
77
78trait Serializable: Sized {
79 fn serialize(&self, b: &mut Vec<u8>, _: Option<Char>);
80}
81
82impl Serializable for u32 {
83 fn serialize(&self, b: &mut Vec<u8>, _: Option<Char>) {
84 b.extend(self.to_be_bytes())
85 }
86}
87
88impl Serializable for (Option<CharDimensions>, SerializableCharTag) {
89 fn serialize(&self, b: &mut Vec<u8>, _: Option<Char>) {
90 let italic = match &self.0 {
91 None => {
92 b.extend([0; 2]);
93 0
94 }
95 Some(char_dimens) => {
96 b.push(char_dimens.width_index.get());
97 b.push(
98 char_dimens
99 .height_index
100 .wrapping_mul(16)
101 .wrapping_add(char_dimens.depth_index),
102 );
103 char_dimens.italic_index
104 }
105 };
106 let (discriminant, payload) = match &self.1 {
107 SerializableCharTag::None => (0_u8, 0_u8),
108 SerializableCharTag::Valid(char_tag) => match char_tag {
109 CharTag::Ligature(p) => (1, *p),
110 CharTag::List(p) => (2, p.0),
111 CharTag::Extension(p) => (3, *p),
112 },
113 SerializableCharTag::Unset(u) => (0, *u),
114 };
115 b.push(italic.wrapping_mul(4).wrapping_add(discriminant));
116 b.push(payload);
117 }
118}
119
120impl Serializable for FixWord {
121 fn serialize(&self, b: &mut Vec<u8>, _: Option<Char>) {
122 (self.0 as u32).serialize(b, None)
123 }
124}
125
126impl Serializable for ligkern::lang::Instruction {
127 fn serialize(&self, b: &mut Vec<u8>, boundary_char: Option<Char>) {
128 let first = [self.next_instruction.unwrap_or(128), self.right_char.0];
130 match self.operation {
131 ligkern::lang::Operation::Kern(_) => {
132 panic!("tfm::format::File lig/kern programs cannot contain `Kern` operations. Use `KernAtIndex` operations instead and provide an appropriate kerns array.");
133 }
134 ligkern::lang::Operation::KernAtIndex(index) => {
135 let [hi, lo] = index.to_be_bytes();
136 b.extend(first);
137 b.push(hi + 128);
138 b.push(lo);
139 }
140 ligkern::lang::Operation::Ligature {
141 char_to_insert,
142 post_lig_operation,
143 post_lig_tag_invalid: _,
144 } => {
145 use ligkern::lang::PostLigOperation::*;
146 b.extend(first);
147 b.push(match post_lig_operation {
148 RetainBothMoveNowhere => 3,
149 RetainBothMoveToInserted => 3 + 4,
150 RetainBothMoveToRight => 3 + 8,
151 RetainRightMoveToInserted => 1,
152 RetainRightMoveToRight => 1 + 4,
153 RetainLeftMoveNowhere => 2,
154 RetainLeftMoveToInserted => 2 + 4,
155 RetainNeitherMoveToInserted => 0,
156 });
157 b.push(char_to_insert.0);
158 }
159 ligkern::lang::Operation::EntrypointRedirect(index, char) => {
160 b.extend(match char {
161 false => [255, 0],
162 true => match boundary_char {
163 None => [254, 0],
164 Some(c) => [255, c.0],
165 },
166 });
167 b.extend(index.to_be_bytes());
168 }
169 }
170 }
171}
172
173impl Serializable for ExtensibleRecipe {
174 fn serialize(&self, b: &mut Vec<u8>, _: Option<Char>) {
175 b.push(self.top.unwrap_or(Char(0)).0);
176 b.push(self.middle.unwrap_or(Char(0)).0);
177 b.push(self.bottom.unwrap_or(Char(0)).0);
178 b.push(self.rep.0);
179 }
180}
181
182fn serialize_string(s: &Option<String>, size: u8, b: &mut Vec<u8>) {
183 let s = match s {
185 None => "",
186 Some(s) => s,
187 };
188 let len_padding_or = match s.len().try_into() {
189 Ok(len) => size.checked_sub(len).map(|padding| (len, padding)),
190 Err(_) => None,
191 };
192 match len_padding_or {
193 None => {
194 b.push(size);
195 b.extend(&s.as_bytes()[0..size as usize])
196 }
197 Some((len, padding)) => {
198 b.push(len);
199 b.extend(s.as_bytes());
200 b.extend(vec![0; padding as usize]);
201 }
202 }
203}
204
205fn serialize_header(header: &Header, b: &mut Vec<u8>) -> i16 {
206 header.checksum.unwrap_or_default().serialize(b, None);
207 header.design_size.serialize(b, None);
208 serialize_string(&header.character_coding_scheme, 39, b);
209 serialize_string(&header.font_family, 19, b);
210 if header.seven_bit_safe == Some(true) {
211 b.push(128);
213 } else {
214 b.push(0);
216 }
217 b.push(0);
218 b.push(0);
219 b.push(header.face.unwrap_or(0_u8.into()).into());
220 serialize_section(&header.additional_data, b, None);
221 (18 + header.additional_data.len())
222 .try_into()
223 .expect("header.len()=18+header.additional_data.len()<= i16::MAX")
224}