1use std::collections::HashMap;
10
11use super::encodings;
12use super::GlyphPath;
13
14pub struct Type1Font {
15 charstrings: HashMap<String, Vec<u8>>,
17 subrs: Vec<Vec<u8>>,
18 pub encoding: HashMap<u8, String>,
20 pub font_matrix: [f64; 6],
21}
22
23const EEXEC_R: u16 = 55665;
24const CHARSTRING_R: u16 = 4330;
25
26fn decrypt(data: &[u8], mut r: u16, skip: usize) -> Vec<u8> {
27 const C1: u16 = 52845;
28 const C2: u16 = 22719;
29 let mut out = Vec::with_capacity(data.len());
30 for &c in data {
31 let p = c ^ (r >> 8) as u8;
32 r = (u16::from(c))
33 .wrapping_add(r)
34 .wrapping_mul(C1)
35 .wrapping_add(C2);
36 out.push(p);
37 }
38 if out.len() > skip {
39 out.drain(..skip);
40 } else {
41 out.clear();
42 }
43 out
44}
45
46fn is_hex(b: u8) -> bool {
47 b.is_ascii_hexdigit()
48}
49
50fn unwrap_pfb(data: &[u8]) -> Vec<u8> {
52 if data.len() < 6 || data[0] != 0x80 {
53 return data.to_vec();
54 }
55 let mut out = Vec::with_capacity(data.len());
56 let mut pos = 0;
57 while pos + 6 <= data.len() && data[pos] == 0x80 {
58 let kind = data[pos + 1];
59 if kind == 3 {
60 break;
61 }
62 let len = u32::from_le_bytes([data[pos + 2], data[pos + 3], data[pos + 4], data[pos + 5]])
63 as usize;
64 pos += 6;
65 let end = (pos + len).min(data.len());
66 out.extend_from_slice(&data[pos..end]);
67 pos = end;
68 }
69 out
70}
71
72impl Type1Font {
73 pub fn parse(raw: &[u8]) -> Option<Type1Font> {
74 let data = unwrap_pfb(raw);
75 let eexec = find(&data, b"eexec")?;
76 let clear = &data[..eexec];
77 let mut pos = eexec + 5;
78 while pos < data.len() && matches!(data[pos], b'\r' | b'\n' | b' ' | b'\t') {
79 pos += 1;
80 }
81 let enc_part = &data[pos..];
82 let bin: Vec<u8> = if enc_part.len() >= 4 && enc_part[..4].iter().all(|&b| is_hex(b)) {
84 let mut out = Vec::with_capacity(enc_part.len() / 2);
85 let mut hi: Option<u8> = None;
86 for &b in enc_part {
87 let v = match b {
88 b'0'..=b'9' => b - b'0',
89 b'a'..=b'f' => b - b'a' + 10,
90 b'A'..=b'F' => b - b'A' + 10,
91 _ => continue,
92 };
93 match hi.take() {
94 None => hi = Some(v),
95 Some(h) => out.push((h << 4) | v),
96 }
97 }
98 out
99 } else {
100 enc_part.to_vec()
101 };
102 let private = decrypt(&bin, EEXEC_R, 4);
103 let len_iv = find(&private, b"/lenIV")
104 .and_then(|p| parse_int_after(&private, p + 6))
105 .unwrap_or(4)
106 .max(0) as usize;
107
108 let font_matrix = find(clear, b"/FontMatrix")
109 .and_then(|p| parse_array6(clear, p + 11))
110 .unwrap_or([0.001, 0.0, 0.0, 0.001, 0.0, 0.0]);
111
112 let mut encoding = HashMap::new();
113 if let Some(p) = find(clear, b"/Encoding") {
114 let rest = &clear[p + 9..];
115 let head = &rest[..rest.len().min(40)];
116 if find(head, b"StandardEncoding").is_some() {
117 for &(c, n) in encodings::STANDARD {
118 encoding.insert(c, n.to_string());
119 }
120 } else {
121 let end = find(rest, b" def").map(|e| e + 4).unwrap_or(rest.len());
123 let section = &rest[..end];
124 let mut i = 0;
125 while let Some(d) = find(§ion[i..], b"dup ") {
126 let at = i + d + 4;
127 let toks: Vec<&[u8]> = section[at..]
128 .split(|b| b.is_ascii_whitespace())
129 .filter(|t| !t.is_empty())
130 .take(3)
131 .collect();
132 if toks.len() >= 2 {
133 if let (Ok(code), Some(nm)) = (
134 std::str::from_utf8(toks[0])
135 .ok()
136 .and_then(|s| s.parse::<u32>().ok())
137 .ok_or(()),
138 toks[1].strip_prefix(b"/"),
139 ) {
140 if code <= 255 {
141 encoding
142 .insert(code as u8, String::from_utf8_lossy(nm).into_owned());
143 }
144 }
145 }
146 i = at;
147 }
148 }
149 }
150
151 let subrs = parse_subrs(&private, len_iv);
152 let charstrings = parse_charstrings(&private, len_iv)?;
153 Some(Type1Font {
154 charstrings,
155 subrs,
156 encoding,
157 font_matrix,
158 })
159 }
160
161 pub fn has_glyph(&self, name: &str) -> bool {
162 self.charstrings.contains_key(name)
163 }
164
165 pub fn glyph_names(&self) -> impl Iterator<Item = &String> {
166 self.charstrings.keys()
167 }
168
169 pub fn glyph(&self, name: &str) -> Option<GlyphPath> {
172 let cs = self.charstrings.get(name)?;
173 let mut st = Interp {
174 font: self,
175 path: tiny_skia::PathBuilder::new(),
176 stack: Vec::new(),
177 ps_stack: Vec::new(),
178 x: 0.0,
179 y: 0.0,
180 width: 0.0,
181 sbx: 0.0,
182 sby: 0.0,
183 flex: None,
184 open: false,
185 depth: 0,
186 };
187 st.run(cs);
188 st.close();
189 let width = st.width;
190 Some(GlyphPath {
191 path: st.path.finish(),
192 advance: width,
193 })
194 }
195}
196
197fn find(hay: &[u8], needle: &[u8]) -> Option<usize> {
198 hay.windows(needle.len()).position(|w| w == needle)
199}
200
201fn parse_int_after(data: &[u8], pos: usize) -> Option<i64> {
202 let s = &data[pos..data.len().min(pos + 32)];
203 let tok = s
204 .split(|b| b.is_ascii_whitespace())
205 .find(|t| !t.is_empty())?;
206 std::str::from_utf8(tok).ok()?.parse().ok()
207}
208
209fn parse_array6(data: &[u8], pos: usize) -> Option<[f64; 6]> {
210 let open = pos + find(&data[pos..], b"[")?;
211 let close = open + find(&data[open..], b"]")?;
212 let vals: Vec<f64> = std::str::from_utf8(&data[open + 1..close])
213 .ok()?
214 .split_whitespace()
215 .filter_map(|t| t.parse().ok())
216 .collect();
217 if vals.len() != 6 {
218 return None;
219 }
220 Some([vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]])
221}
222
223fn parse_subrs(private: &[u8], len_iv: usize) -> Vec<Vec<u8>> {
225 let mut out = Vec::new();
226 let Some(p) = find(private, b"/Subrs") else {
227 return out;
228 };
229 let count = parse_int_after(private, p + 6).unwrap_or(0).clamp(0, 65536) as usize;
230 out.resize(count, Vec::new());
231 let mut pos = p + 6;
232 for _ in 0..count {
233 let Some(d) = find(&private[pos..], b"dup ") else {
234 break;
235 };
236 let at = pos + d + 4;
237 let Some((idx, rest)) = read_int(private, at) else {
238 break;
239 };
240 let Some((n, rest)) = read_int(private, rest) else {
241 break;
242 };
243 let Some(tok_end) = skip_token(private, rest) else {
245 break;
246 };
247 let start = tok_end + 1;
248 let end = start + n.max(0) as usize;
249 if end > private.len() {
250 break;
251 }
252 if idx >= 0 && (idx as usize) < count {
253 out[idx as usize] = decrypt(&private[start..end], CHARSTRING_R, len_iv);
254 }
255 pos = end;
256 }
257 out
258}
259
260fn parse_charstrings(private: &[u8], len_iv: usize) -> Option<HashMap<String, Vec<u8>>> {
262 let p = find(private, b"/CharStrings")?;
263 let mut map = HashMap::new();
264 let mut pos = p
265 + 12
266 + find(&private[p + 12..], b"begin")
267 .map(|b| b + 5)
268 .unwrap_or(0);
269 while let Some(slash) = private[pos..].iter().position(|&b| b == b'/') {
271 let name_start = pos + slash + 1;
272 let name_end = name_start
273 + private[name_start..]
274 .iter()
275 .position(|b| b.is_ascii_whitespace() || *b == b'{' || *b == b'(')
276 .unwrap_or(0);
277 if name_end == name_start {
278 pos = name_start;
279 continue;
280 }
281 let name = String::from_utf8_lossy(&private[name_start..name_end]).into_owned();
282 let Some((n, rest)) = read_int(private, name_end) else {
283 if find(&private[pos..pos + slash], b"end").is_some() {
285 break;
286 }
287 pos = name_end;
288 if !map.is_empty()
289 && find(
290 &private[name_end..(name_end + 8).min(private.len())],
291 b"end",
292 )
293 .is_some()
294 {
295 break;
296 }
297 continue;
298 };
299 let Some(tok_end) = skip_token(private, rest) else {
300 break;
301 };
302 let start = tok_end + 1;
303 let end = start + n.max(0) as usize;
304 if end > private.len() {
305 break;
306 }
307 map.insert(name, decrypt(&private[start..end], CHARSTRING_R, len_iv));
308 pos = end;
309 if map.len() > 70_000 {
310 break;
311 }
312 }
313 if map.is_empty() {
314 None
315 } else {
316 Some(map)
317 }
318}
319
320fn read_int(data: &[u8], mut pos: usize) -> Option<(i64, usize)> {
322 while pos < data.len() && data[pos].is_ascii_whitespace() {
323 pos += 1;
324 }
325 let start = pos;
326 while pos < data.len() && (data[pos].is_ascii_digit() || (pos == start && data[pos] == b'-')) {
327 pos += 1;
328 }
329 if pos == start {
330 return None;
331 }
332 let v = std::str::from_utf8(&data[start..pos]).ok()?.parse().ok()?;
333 Some((v, pos))
334}
335
336fn skip_token(data: &[u8], mut pos: usize) -> Option<usize> {
338 while pos < data.len() && data[pos].is_ascii_whitespace() {
339 pos += 1;
340 }
341 let start = pos;
342 while pos < data.len() && !data[pos].is_ascii_whitespace() {
343 pos += 1;
344 }
345 if pos == start {
346 return None;
347 }
348 Some(pos)
349}
350
351struct Interp<'a> {
352 font: &'a Type1Font,
353 path: tiny_skia::PathBuilder,
354 stack: Vec<f64>,
355 ps_stack: Vec<f64>,
356 x: f64,
357 y: f64,
358 width: f64,
359 sbx: f64,
360 sby: f64,
361 flex: Option<Vec<(f64, f64)>>,
363 open: bool,
364 depth: usize,
365}
366
367impl Interp<'_> {
368 fn close(&mut self) {
369 if self.open {
370 self.path.close();
371 self.open = false;
372 }
373 }
374
375 fn move_to(&mut self, x: f64, y: f64) {
376 self.close();
377 self.path.move_to(x as f32, y as f32);
378 self.open = true;
379 }
380
381 fn line_to(&mut self, x: f64, y: f64) {
382 if !self.open {
383 self.path.move_to(self.x as f32, self.y as f32);
384 self.open = true;
385 }
386 self.path.line_to(x as f32, y as f32);
387 }
388
389 fn curve_to(&mut self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) {
390 if !self.open {
391 self.path.move_to(self.x as f32, self.y as f32);
392 self.open = true;
393 }
394 self.path.cubic_to(
395 x1 as f32, y1 as f32, x2 as f32, y2 as f32, x3 as f32, y3 as f32,
396 );
397 }
398
399 fn run(&mut self, cs: &[u8]) -> bool {
401 if self.depth > 30 {
402 return true;
403 }
404 let mut i = 0;
405 while i < cs.len() {
406 let v = cs[i];
407 i += 1;
408 match v {
409 32..=246 => self.stack.push(f64::from(v) - 139.0),
410 247..=250 => {
411 let w = f64::from(*cs.get(i).unwrap_or(&0));
412 i += 1;
413 self.stack.push((f64::from(v) - 247.0) * 256.0 + w + 108.0);
414 }
415 251..=254 => {
416 let w = f64::from(*cs.get(i).unwrap_or(&0));
417 i += 1;
418 self.stack.push(-(f64::from(v) - 251.0) * 256.0 - w - 108.0);
419 }
420 255 => {
421 if i + 4 > cs.len() {
422 return true;
423 }
424 let n = i32::from_be_bytes([cs[i], cs[i + 1], cs[i + 2], cs[i + 3]]);
425 i += 4;
426 self.stack.push(f64::from(n));
427 }
428 13 => {
429 if self.stack.len() >= 2 {
431 self.sbx = self.stack[0];
432 self.width = self.stack[1];
433 self.x = self.sbx;
434 self.y = 0.0;
435 }
436 self.stack.clear();
437 }
438 9 => {
439 self.close();
440 self.stack.clear();
441 }
442 1 | 3 => self.stack.clear(),
443 21 => {
444 let (dx, dy) = self.take2();
445 self.x += dx;
446 self.y += dy;
447 self.after_move();
448 }
449 22 => {
450 let dx = self.take1();
451 self.x += dx;
452 self.after_move();
453 }
454 4 => {
455 let dy = self.take1();
456 self.y += dy;
457 self.after_move();
458 }
459 5 => {
460 let (dx, dy) = self.take2();
461 self.x += dx;
462 self.y += dy;
463 let (x, y) = (self.x, self.y);
464 self.line_to(x, y);
465 }
466 6 => {
467 let dx = self.take1();
468 self.x += dx;
469 let (x, y) = (self.x, self.y);
470 self.line_to(x, y);
471 }
472 7 => {
473 let dy = self.take1();
474 self.y += dy;
475 let (x, y) = (self.x, self.y);
476 self.line_to(x, y);
477 }
478 8 => {
479 if self.stack.len() >= 6 {
480 let s = self.stack.clone();
481 self.rrcurveto(s[0], s[1], s[2], s[3], s[4], s[5]);
482 }
483 self.stack.clear();
484 }
485 30 => {
486 if self.stack.len() >= 4 {
488 let s = self.stack.clone();
489 self.rrcurveto(0.0, s[0], s[1], s[2], s[3], 0.0);
490 }
491 self.stack.clear();
492 }
493 31 => {
494 if self.stack.len() >= 4 {
496 let s = self.stack.clone();
497 self.rrcurveto(s[0], 0.0, s[1], s[2], 0.0, s[3]);
498 }
499 self.stack.clear();
500 }
501 10 => {
502 let Some(n) = self.stack.pop() else { continue };
503 let n = n as i64;
504 if n >= 0 {
505 if let Some(sub) = self.font.subrs.get(n as usize) {
506 self.depth += 1;
510 let sub = sub.clone();
511 let done = self.run(&sub);
512 self.depth -= 1;
513 if done {
514 return true;
515 }
516 }
517 }
518 }
519 11 => return false,
520 14 => {
521 self.close();
522 return true;
523 }
524 12 => {
525 let v2 = *cs.get(i).unwrap_or(&0);
526 i += 1;
527 match v2 {
528 0 => self.stack.clear(), 1 | 2 => self.stack.clear(), 6 => {
531 if self.stack.len() >= 5 {
533 let s = self.stack.clone();
534 self.stack.clear();
535 self.seac(s[0], s[1], s[2], s[3] as i64, s[4] as i64);
536 }
537 return true;
538 }
539 7 => {
540 if self.stack.len() >= 4 {
542 self.sbx = self.stack[0];
543 self.sby = self.stack[1];
544 self.width = self.stack[2];
545 self.x = self.sbx;
546 self.y = self.sby;
547 }
548 self.stack.clear();
549 }
550 12 => {
551 let b = self.stack.pop().unwrap_or(1.0);
552 let a = self.stack.pop().unwrap_or(0.0);
553 self.stack.push(if b != 0.0 { a / b } else { 0.0 });
554 }
555 16 => self.callothersubr(),
556 17 => {
557 let v = self.ps_stack.pop().unwrap_or(0.0);
558 self.stack.push(v);
559 }
560 33 => {
561 if self.stack.len() >= 2 {
563 self.x = self.stack[0];
564 self.y = self.stack[1];
565 }
566 self.stack.clear();
567 }
568 _ => self.stack.clear(),
569 }
570 }
571 _ => self.stack.clear(),
572 }
573 }
574 false
575 }
576
577 fn take1(&mut self) -> f64 {
578 let v = self.stack.first().copied().unwrap_or(0.0);
579 self.stack.clear();
580 v
581 }
582
583 fn take2(&mut self) -> (f64, f64) {
584 let a = self.stack.first().copied().unwrap_or(0.0);
585 let b = self.stack.get(1).copied().unwrap_or(0.0);
586 self.stack.clear();
587 (a, b)
588 }
589
590 fn after_move(&mut self) {
591 if let Some(pts) = &mut self.flex {
592 pts.push((self.x, self.y));
593 } else {
594 let (x, y) = (self.x, self.y);
595 self.move_to(x, y);
596 }
597 }
598
599 fn rrcurveto(&mut self, dx1: f64, dy1: f64, dx2: f64, dy2: f64, dx3: f64, dy3: f64) {
600 let x1 = self.x + dx1;
601 let y1 = self.y + dy1;
602 let x2 = x1 + dx2;
603 let y2 = y1 + dy2;
604 self.x = x2 + dx3;
605 self.y = y2 + dy3;
606 let (x, y) = (self.x, self.y);
607 self.curve_to(x1, y1, x2, y2, x, y);
608 }
609
610 fn callothersubr(&mut self) {
611 let Some(othersubr) = self.stack.pop() else {
612 return;
613 };
614 let Some(n) = self.stack.pop() else { return };
615 let n = (n.max(0.0) as usize).min(self.stack.len());
616 let args: Vec<f64> = self.stack.split_off(self.stack.len() - n);
617 match othersubr as i64 {
618 1 => {
619 self.flex = Some(Vec::new());
621 }
622 0 => {
623 if let Some(pts) = self.flex.take() {
627 if pts.len() >= 7 {
629 let p = &pts[1..7];
630 let (sx, sy) = (self.x, self.y);
631 let _ = (sx, sy);
634 self.curve_to(p[0].0, p[0].1, p[1].0, p[1].1, p[2].0, p[2].1);
635 self.curve_to(p[3].0, p[3].1, p[4].0, p[4].1, p[5].0, p[5].1);
636 self.x = p[5].0;
637 self.y = p[5].1;
638 } else if let Some(last) = pts.last() {
639 self.line_to(last.0, last.1);
640 }
641 }
642 let end_y = self.y;
643 let end_x = self.x;
644 self.ps_stack = vec![end_y, end_x];
646 }
647 2 => {}
648 3 => {
649 self.ps_stack = vec![3.0];
651 let _ = args;
652 }
653 _ => {
654 let mut a = args;
656 a.reverse();
657 self.ps_stack = a;
658 }
659 }
660 }
661
662 fn seac(&mut self, asb: f64, adx: f64, ady: f64, bchar: i64, achar: i64) {
663 let name_of = |c: i64| -> Option<&'static str> {
664 if !(0..=255).contains(&c) {
665 return None;
666 }
667 encodings::lookup(encodings::STANDARD, c as u8)
668 };
669 let (Some(bname), Some(aname)) = (name_of(bchar), name_of(achar)) else {
670 return;
671 };
672 let sbx = self.sbx;
673 let width = self.width;
674 if let Some(base) = self.font.glyph(bname).and_then(|g| g.path) {
675 self.path.push_path(&base);
676 }
677 if let Some(acc) = self.font.glyph_raw(aname) {
678 let dx = sbx - acc.sbx + adx - asb;
679 let dy = ady;
680 if let Some(p) = acc
681 .path
682 .transform(tiny_skia::Transform::from_translate(dx as f32, dy as f32))
683 {
684 self.path.push_path(&p);
685 }
686 }
687 self.width = width;
688 self.open = false;
689 }
690}
691
692struct RawGlyph {
693 path: tiny_skia::Path,
694 sbx: f64,
695}
696
697impl Type1Font {
698 fn glyph_raw(&self, name: &str) -> Option<RawGlyph> {
700 let cs = self.charstrings.get(name)?;
701 let mut st = Interp {
702 font: self,
703 path: tiny_skia::PathBuilder::new(),
704 stack: Vec::new(),
705 ps_stack: Vec::new(),
706 x: 0.0,
707 y: 0.0,
708 width: 0.0,
709 sbx: 0.0,
710 sby: 0.0,
711 flex: None,
712 open: false,
713 depth: 1,
714 };
715 st.run(cs);
716 st.close();
717 let sbx = st.sbx;
718 Some(RawGlyph {
719 path: st.path.finish()?,
720 sbx,
721 })
722 }
723}
724
725#[cfg(test)]
726mod tests {
727 use super::*;
728
729 fn encrypt(data: &[u8], mut r: u16, lead: usize) -> Vec<u8> {
731 const C1: u16 = 52845;
732 const C2: u16 = 22719;
733 let mut out = Vec::new();
734 let plain: Vec<u8> = std::iter::repeat_n(0u8, lead)
735 .chain(data.iter().copied())
736 .collect();
737 for &p in &plain {
738 let c = p ^ (r >> 8) as u8;
739 r = (u16::from(c))
740 .wrapping_add(r)
741 .wrapping_mul(C1)
742 .wrapping_add(C2);
743 out.push(c);
744 }
745 out
746 }
747
748 fn num(v: i32) -> Vec<u8> {
749 if (-107..=107).contains(&v) {
750 vec![(v + 139) as u8]
751 } else {
752 let mut out = vec![255];
753 out.extend_from_slice(&v.to_be_bytes());
754 out
755 }
756 }
757
758 #[test]
760 fn parses_a_synthetic_program() {
761 let mut cs = Vec::new();
762 cs.extend(num(50));
763 cs.extend(num(600));
764 cs.push(13);
765 cs.extend(num(0));
766 cs.extend(num(0));
767 cs.push(21);
768 cs.extend(num(500));
769 cs.push(6);
770 cs.extend(num(500));
771 cs.push(7);
772 cs.extend(num(-500));
773 cs.push(6);
774 cs.push(9);
775 cs.push(14);
776 let enc_cs = encrypt(&cs, CHARSTRING_R, 4);
777 let mut private = Vec::new();
778 private.extend_from_slice(
779 b"dup /Private 8 dict dup begin /lenIV 4 def /Subrs 1 array\ndup 0 1 RD ",
780 );
781 private.extend(encrypt(&[11], CHARSTRING_R, 4));
782 private.extend_from_slice(b" NP\n/CharStrings 2 dict dup begin\n/square ");
783 private.extend_from_slice(format!("{} RD ", enc_cs.len()).as_bytes());
784 private.extend(&enc_cs);
785 private.extend_from_slice(b" ND\n/.notdef 1 RD ");
786 private.extend(encrypt(&[14], CHARSTRING_R, 4));
787 private.extend_from_slice(b" ND\nend\n");
788 let mut data = Vec::new();
789 data.extend_from_slice(
790 b"%!PS-AdobeFont-1.0: Test\n/FontMatrix [0.001 0 0 0.001 0 0] readonly def\n/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\ndup 65 /square put\nreadonly def\ncurrentdict end\ncurrentfile eexec\n",
791 );
792 data.extend(encrypt(&private, EEXEC_R, 4));
793 let font = Type1Font::parse(&data).expect("parses");
794 assert_eq!(font.encoding.get(&65).map(String::as_str), Some("square"));
795 assert_eq!(font.font_matrix[0], 0.001);
796 let g = font.glyph("square").expect("glyph");
797 assert_eq!(g.advance, 600.0);
798 let b = g.path.as_ref().expect("path").bounds();
799 assert_eq!(
800 (b.left(), b.top(), b.right(), b.bottom()),
801 (50.0, 0.0, 550.0, 500.0)
802 );
803 }
804}