1use crate::error::PdfError;
27use crate::objects::Object;
28use std::borrow::Cow;
29
30#[derive(Clone, Debug, PartialEq, Eq)]
33pub struct EncodingOverride {
34 pub code: u8,
35 pub glyph_name: String,
36}
37
38#[derive(Clone, Debug, Default, PartialEq, Eq)]
45pub struct EncodingDifferences {
46 pub overrides: Vec<EncodingOverride>,
47}
48
49impl EncodingDifferences {
50 pub fn is_empty(&self) -> bool {
51 self.overrides.is_empty()
52 }
53
54 pub fn len(&self) -> usize {
55 self.overrides.len()
56 }
57}
58
59#[derive(Clone, Copy, Debug, PartialEq, Eq)]
62pub enum BaseEncoding {
63 WinAnsi,
64 MacRoman,
65 MacExpert,
66 Standard,
69 Symbol,
72 ZapfDingbats,
74}
75
76impl BaseEncoding {
77 pub fn from_name(name: &str) -> Option<BaseEncoding> {
78 Some(match name {
79 "WinAnsiEncoding" => BaseEncoding::WinAnsi,
80 "MacRomanEncoding" => BaseEncoding::MacRoman,
81 "MacExpertEncoding" => BaseEncoding::MacExpert,
82 "StandardEncoding" => BaseEncoding::Standard,
83 "SymbolEncoding" => BaseEncoding::Symbol,
84 "ZapfDingbatsEncoding" => BaseEncoding::ZapfDingbats,
85 _ => return None,
86 })
87 }
88}
89
90#[derive(Clone, Debug)]
96pub struct EncodingMap {
97 table: [String; 256],
98}
99
100impl Default for EncodingMap {
101 fn default() -> Self {
102 Self::new()
103 }
104}
105
106impl EncodingMap {
107 pub fn new() -> Self {
108 Self {
109 table: std::array::from_fn(|_| String::new()),
110 }
111 }
112
113 pub fn set_char(&mut self, code: u8, c: char) {
114 self.table[code as usize] = String::from(c);
115 }
116
117 pub fn set_string(&mut self, code: u8, s: &str) {
118 self.table[code as usize] = s.to_owned();
119 }
120
121 pub fn lookup(&self, code: u8) -> &str {
124 &self.table[code as usize]
125 }
126
127 pub fn decode(&self, bytes: &[u8]) -> String {
130 let mut out = String::with_capacity(bytes.len());
131 for &b in bytes {
132 let slot = self.lookup(b);
133 if slot.is_empty() {
134 out.push('\u{FFFD}');
135 } else {
136 out.push_str(slot);
137 }
138 }
139 out
140 }
141
142 pub fn from_base(base: BaseEncoding) -> EncodingMap {
144 let mut m = EncodingMap::new();
145 match base {
146 BaseEncoding::WinAnsi => fill_winansi(&mut m),
147 BaseEncoding::MacRoman => fill_macroman(&mut m),
148 BaseEncoding::MacExpert => fill_macexpert(&mut m),
149 BaseEncoding::Standard => fill_standard(&mut m),
150 BaseEncoding::Symbol => fill_symbol(&mut m),
151 BaseEncoding::ZapfDingbats => fill_zapfdingbats(&mut m),
152 }
153 m
154 }
155}
156
157pub fn parse_encoding_differences(arr: &Object) -> Result<EncodingDifferences, PdfError> {
172 let items = match arr {
173 Object::Array(v) => v,
174 _ => {
175 return Err(PdfError::other(format!(
176 "PDF encoding: /Differences must be an array (got {arr:?})"
177 )));
178 }
179 };
180 let mut out = EncodingDifferences::default();
181 let mut running: Option<u32> = None;
182 for item in items {
183 match item {
184 Object::Integer(n) if (0..=255).contains(n) => {
185 running = Some(*n as u32);
186 }
187 Object::Real(r) => {
188 let v = *r as i64;
189 if (0..=255).contains(&v) {
190 running = Some(v as u32);
191 }
192 }
193 Object::Name(name) => {
194 if let Some(code) = running {
195 if code <= 255 {
196 out.overrides.push(EncodingOverride {
197 code: code as u8,
198 glyph_name: name.clone(),
199 });
200 }
201 running = Some(code + 1);
202 }
203 }
204 _ => {
205 }
209 }
210 }
211 Ok(out)
212}
213
214pub fn apply_encoding_differences(
218 base: &EncodingMap,
219 differences: &EncodingDifferences,
220) -> EncodingMap {
221 let mut out = base.clone();
222 for ov in &differences.overrides {
223 if let Some(s) = glyph_name_to_unicode(&ov.glyph_name) {
224 out.set_string(ov.code, s.as_ref());
225 } else {
226 out.set_string(ov.code, "");
231 }
232 }
233 out
234}
235
236pub fn glyph_name_to_unicode(name: &str) -> Option<Cow<'static, str>> {
256 if name == ".notdef" || name.is_empty() {
260 return Some(Cow::Borrowed(""));
261 }
262 for (n, s) in AGL_SUBSET {
269 if *n == name {
270 return Some(Cow::Borrowed(*s));
271 }
272 }
273 uni_prefix_decode(name).map(Cow::Owned)
275}
276
277fn uni_prefix_decode(name: &str) -> Option<String> {
299 if let Some(rest) = name.strip_prefix("uni") {
300 if rest.is_empty() || rest.len() % 4 != 0 {
303 return None;
304 }
305 let mut out = String::with_capacity(rest.len() / 4);
306 for chunk in rest.as_bytes().chunks(4) {
307 let hex = std::str::from_utf8(chunk).ok()?;
309 if !is_uppercase_hex(hex) {
313 return None;
314 }
315 let cp = u32::from_str_radix(hex, 16).ok()?;
316 if (0xD800..=0xDFFF).contains(&cp) || cp == 0xFFFF {
318 return None;
319 }
320 let c = char::from_u32(cp)?;
321 out.push(c);
322 }
323 Some(out)
324 } else if let Some(rest) = name.strip_prefix('u') {
325 if !(4..=6).contains(&rest.len()) {
328 return None;
329 }
330 if !is_uppercase_hex(rest) {
331 return None;
332 }
333 let cp = u32::from_str_radix(rest, 16).ok()?;
334 if (0xD800..=0xDFFF).contains(&cp) || cp == 0xFFFF {
335 return None;
336 }
337 let c = char::from_u32(cp)?;
338 Some(c.to_string())
339 } else {
340 None
341 }
342}
343
344fn is_uppercase_hex(s: &str) -> bool {
348 !s.is_empty()
349 && s.bytes()
350 .all(|b| b.is_ascii_digit() || (b'A'..=b'F').contains(&b))
351}
352
353const AGL_SUBSET: &[(&str, &str)] = &[
357 ("space", " "),
359 ("exclam", "!"),
360 ("quotedbl", "\""),
361 ("numbersign", "#"),
362 ("dollar", "$"),
363 ("percent", "%"),
364 ("ampersand", "&"),
365 ("quoteright", "\u{2019}"),
366 ("quotesingle", "'"),
367 ("parenleft", "("),
368 ("parenright", ")"),
369 ("asterisk", "*"),
370 ("plus", "+"),
371 ("comma", ","),
372 ("hyphen", "-"),
373 ("period", "."),
374 ("slash", "/"),
375 ("zero", "0"),
376 ("one", "1"),
377 ("two", "2"),
378 ("three", "3"),
379 ("four", "4"),
380 ("five", "5"),
381 ("six", "6"),
382 ("seven", "7"),
383 ("eight", "8"),
384 ("nine", "9"),
385 ("colon", ":"),
386 ("semicolon", ";"),
387 ("less", "<"),
388 ("equal", "="),
389 ("greater", ">"),
390 ("question", "?"),
391 ("at", "@"),
392 ("A", "A"),
393 ("B", "B"),
394 ("C", "C"),
395 ("D", "D"),
396 ("E", "E"),
397 ("F", "F"),
398 ("G", "G"),
399 ("H", "H"),
400 ("I", "I"),
401 ("J", "J"),
402 ("K", "K"),
403 ("L", "L"),
404 ("M", "M"),
405 ("N", "N"),
406 ("O", "O"),
407 ("P", "P"),
408 ("Q", "Q"),
409 ("R", "R"),
410 ("S", "S"),
411 ("T", "T"),
412 ("U", "U"),
413 ("V", "V"),
414 ("W", "W"),
415 ("X", "X"),
416 ("Y", "Y"),
417 ("Z", "Z"),
418 ("bracketleft", "["),
419 ("backslash", "\\"),
420 ("bracketright", "]"),
421 ("asciicircum", "^"),
422 ("underscore", "_"),
423 ("quoteleft", "\u{2018}"),
424 ("grave", "`"),
425 ("a", "a"),
426 ("b", "b"),
427 ("c", "c"),
428 ("d", "d"),
429 ("e", "e"),
430 ("f", "f"),
431 ("g", "g"),
432 ("h", "h"),
433 ("i", "i"),
434 ("j", "j"),
435 ("k", "k"),
436 ("l", "l"),
437 ("m", "m"),
438 ("n", "n"),
439 ("o", "o"),
440 ("p", "p"),
441 ("q", "q"),
442 ("r", "r"),
443 ("s", "s"),
444 ("t", "t"),
445 ("u", "u"),
446 ("v", "v"),
447 ("w", "w"),
448 ("x", "x"),
449 ("y", "y"),
450 ("z", "z"),
451 ("braceleft", "{"),
452 ("bar", "|"),
453 ("braceright", "}"),
454 ("asciitilde", "~"),
455 ("exclamdown", "\u{00A1}"),
457 ("cent", "\u{00A2}"),
458 ("sterling", "\u{00A3}"),
459 ("currency", "\u{00A4}"),
460 ("yen", "\u{00A5}"),
461 ("brokenbar", "\u{00A6}"),
462 ("section", "\u{00A7}"),
463 ("dieresis", "\u{00A8}"),
464 ("copyright", "\u{00A9}"),
465 ("ordfeminine", "\u{00AA}"),
466 ("guillemotleft", "\u{00AB}"),
467 ("logicalnot", "\u{00AC}"),
468 ("hyphensoft", "\u{00AD}"),
469 ("registered", "\u{00AE}"),
470 ("macron", "\u{00AF}"),
471 ("degree", "\u{00B0}"),
472 ("plusminus", "\u{00B1}"),
473 ("twosuperior", "\u{00B2}"),
474 ("threesuperior", "\u{00B3}"),
475 ("acute", "\u{00B4}"),
476 ("mu", "\u{00B5}"),
477 ("paragraph", "\u{00B6}"),
478 ("periodcentered", "\u{00B7}"),
479 ("cedilla", "\u{00B8}"),
480 ("onesuperior", "\u{00B9}"),
481 ("ordmasculine", "\u{00BA}"),
482 ("guillemotright", "\u{00BB}"),
483 ("onequarter", "\u{00BC}"),
484 ("onehalf", "\u{00BD}"),
485 ("threequarters", "\u{00BE}"),
486 ("questiondown", "\u{00BF}"),
487 ("Agrave", "\u{00C0}"),
488 ("Aacute", "\u{00C1}"),
489 ("Acircumflex", "\u{00C2}"),
490 ("Atilde", "\u{00C3}"),
491 ("Adieresis", "\u{00C4}"),
492 ("Aring", "\u{00C5}"),
493 ("AE", "\u{00C6}"),
494 ("Ccedilla", "\u{00C7}"),
495 ("Egrave", "\u{00C8}"),
496 ("Eacute", "\u{00C9}"),
497 ("Ecircumflex", "\u{00CA}"),
498 ("Edieresis", "\u{00CB}"),
499 ("Igrave", "\u{00CC}"),
500 ("Iacute", "\u{00CD}"),
501 ("Icircumflex", "\u{00CE}"),
502 ("Idieresis", "\u{00CF}"),
503 ("Eth", "\u{00D0}"),
504 ("Ntilde", "\u{00D1}"),
505 ("Ograve", "\u{00D2}"),
506 ("Oacute", "\u{00D3}"),
507 ("Ocircumflex", "\u{00D4}"),
508 ("Otilde", "\u{00D5}"),
509 ("Odieresis", "\u{00D6}"),
510 ("multiply", "\u{00D7}"),
511 ("Oslash", "\u{00D8}"),
512 ("Ugrave", "\u{00D9}"),
513 ("Uacute", "\u{00DA}"),
514 ("Ucircumflex", "\u{00DB}"),
515 ("Udieresis", "\u{00DC}"),
516 ("Yacute", "\u{00DD}"),
517 ("Thorn", "\u{00DE}"),
518 ("germandbls", "\u{00DF}"),
519 ("agrave", "\u{00E0}"),
520 ("aacute", "\u{00E1}"),
521 ("acircumflex", "\u{00E2}"),
522 ("atilde", "\u{00E3}"),
523 ("adieresis", "\u{00E4}"),
524 ("aring", "\u{00E5}"),
525 ("ae", "\u{00E6}"),
526 ("ccedilla", "\u{00E7}"),
527 ("egrave", "\u{00E8}"),
528 ("eacute", "\u{00E9}"),
529 ("ecircumflex", "\u{00EA}"),
530 ("edieresis", "\u{00EB}"),
531 ("igrave", "\u{00EC}"),
532 ("iacute", "\u{00ED}"),
533 ("icircumflex", "\u{00EE}"),
534 ("idieresis", "\u{00EF}"),
535 ("eth", "\u{00F0}"),
536 ("ntilde", "\u{00F1}"),
537 ("ograve", "\u{00F2}"),
538 ("oacute", "\u{00F3}"),
539 ("ocircumflex", "\u{00F4}"),
540 ("otilde", "\u{00F5}"),
541 ("odieresis", "\u{00F6}"),
542 ("divide", "\u{00F7}"),
543 ("oslash", "\u{00F8}"),
544 ("ugrave", "\u{00F9}"),
545 ("uacute", "\u{00FA}"),
546 ("ucircumflex", "\u{00FB}"),
547 ("udieresis", "\u{00FC}"),
548 ("yacute", "\u{00FD}"),
549 ("thorn", "\u{00FE}"),
550 ("ydieresis", "\u{00FF}"),
551 ("Lslash", "\u{0141}"),
553 ("lslash", "\u{0142}"),
554 ("Scaron", "\u{0160}"),
555 ("scaron", "\u{0161}"),
556 ("OE", "\u{0152}"),
557 ("oe", "\u{0153}"),
558 ("Ydieresis", "\u{0178}"),
559 ("Zcaron", "\u{017D}"),
560 ("zcaron", "\u{017E}"),
561 ("florin", "\u{0192}"),
562 ("circumflex", "\u{02C6}"),
563 ("tilde", "\u{02DC}"),
564 ("caron", "\u{02C7}"),
565 ("breve", "\u{02D8}"),
566 ("dotaccent", "\u{02D9}"),
567 ("ring", "\u{02DA}"),
568 ("ogonek", "\u{02DB}"),
569 ("hungarumlaut", "\u{02DD}"),
570 ("Alpha", "\u{0391}"),
572 ("Beta", "\u{0392}"),
573 ("Gamma", "\u{0393}"),
574 ("Delta", "\u{0394}"),
575 ("Epsilon", "\u{0395}"),
576 ("Zeta", "\u{0396}"),
577 ("Eta", "\u{0397}"),
578 ("Theta", "\u{0398}"),
579 ("Iota", "\u{0399}"),
580 ("Kappa", "\u{039A}"),
581 ("Lambda", "\u{039B}"),
582 ("Mu", "\u{039C}"),
583 ("Nu", "\u{039D}"),
584 ("Xi", "\u{039E}"),
585 ("Omicron", "\u{039F}"),
586 ("Pi", "\u{03A0}"),
587 ("Rho", "\u{03A1}"),
588 ("Sigma", "\u{03A3}"),
589 ("Tau", "\u{03A4}"),
590 ("Upsilon", "\u{03A5}"),
591 ("Phi", "\u{03A6}"),
592 ("Chi", "\u{03A7}"),
593 ("Psi", "\u{03A8}"),
594 ("Omega", "\u{03A9}"),
595 ("alpha", "\u{03B1}"),
596 ("beta", "\u{03B2}"),
597 ("gamma", "\u{03B3}"),
598 ("delta", "\u{03B4}"),
599 ("epsilon", "\u{03B5}"),
600 ("zeta", "\u{03B6}"),
601 ("eta", "\u{03B7}"),
602 ("theta", "\u{03B8}"),
603 ("iota", "\u{03B9}"),
604 ("kappa", "\u{03BA}"),
605 ("lambda", "\u{03BB}"),
606 ("nu", "\u{03BD}"),
607 ("xi", "\u{03BE}"),
608 ("omicron", "\u{03BF}"),
609 ("pi", "\u{03C0}"),
610 ("rho", "\u{03C1}"),
611 ("sigma", "\u{03C3}"),
612 ("tau", "\u{03C4}"),
613 ("upsilon", "\u{03C5}"),
614 ("phi", "\u{03C6}"),
615 ("chi", "\u{03C7}"),
616 ("psi", "\u{03C8}"),
617 ("omega", "\u{03C9}"),
618 ("endash", "\u{2013}"),
620 ("emdash", "\u{2014}"),
621 ("quotesinglbase", "\u{201A}"),
622 ("quotedblbase", "\u{201E}"),
623 ("quotedblleft", "\u{201C}"),
624 ("quotedblright", "\u{201D}"),
625 ("dagger", "\u{2020}"),
626 ("daggerdbl", "\u{2021}"),
627 ("bullet", "\u{2022}"),
628 ("ellipsis", "\u{2026}"),
629 ("perthousand", "\u{2030}"),
630 ("guilsinglleft", "\u{2039}"),
631 ("guilsinglright", "\u{203A}"),
632 ("Euro", "\u{20AC}"),
633 ("trademark", "\u{2122}"),
634 ("onethird", "\u{2153}"),
636 ("twothirds", "\u{2154}"),
637 ("oneeighth", "\u{215B}"),
638 ("threeeighths", "\u{215C}"),
639 ("fiveeighths", "\u{215D}"),
640 ("seveneighths", "\u{215E}"),
641 ("minus", "\u{2212}"),
643 ("fraction", "\u{2044}"),
644 ("infinity", "\u{221E}"),
645 ("notequal", "\u{2260}"),
646 ("lessequal", "\u{2264}"),
647 ("greaterequal", "\u{2265}"),
648 ("arrowleft", "\u{2190}"),
649 ("arrowup", "\u{2191}"),
650 ("arrowright", "\u{2192}"),
651 ("arrowdown", "\u{2193}"),
652 ("arrowboth", "\u{2194}"),
653 ("arrowdblleft", "\u{21D0}"),
654 ("arrowdblup", "\u{21D1}"),
655 ("arrowdblright", "\u{21D2}"),
656 ("arrowdbldown", "\u{21D3}"),
657 ("arrowdblboth", "\u{21D4}"),
658 ("partialdiff", "\u{2202}"),
659 ("gradient", "\u{2207}"),
660 ("product", "\u{220F}"),
661 ("summation", "\u{2211}"),
662 ("radical", "\u{221A}"),
663 ("proportional", "\u{221D}"),
664 ("integral", "\u{222B}"),
665 ("approxequal", "\u{2248}"),
666 ("equivalence", "\u{2261}"),
667 ("lozenge", "\u{25CA}"),
668 ("notelement", "\u{2209}"),
669 ("element", "\u{2208}"),
670 ("emptyset", "\u{2205}"),
671 ("intersection", "\u{2229}"),
672 ("union", "\u{222A}"),
673 ("logicalor", "\u{2228}"),
674 ("logicaland", "\u{2227}"),
675 ("universal", "\u{2200}"),
676 ("existential", "\u{2203}"),
677 ("fi", "fi"),
679 ("fl", "fl"),
680 ("filledbox", "\u{25A0}"),
682 ("emptybox", "\u{25A1}"),
683 ("filledrect", "\u{25AC}"),
684 ("triagup", "\u{25B2}"),
685 ("triagrt", "\u{25BA}"),
686 ("triagdn", "\u{25BC}"),
687 ("triaglf", "\u{25C4}"),
688 ("circle", "\u{25CB}"),
689 ("filledcircle", "\u{25CF}"),
690 ("heart", "\u{2665}"),
691 ("musicalnote", "\u{266A}"),
692 ("musicalnotedbl", "\u{266B}"),
693];
694
695fn fill_winansi(m: &mut EncodingMap) {
704 for b in 0x20u8..=0x7E {
706 m.set_char(b, b as char);
707 }
708 let overlay: &[(u8, char)] = &[
710 (0x80, '\u{20AC}'),
711 (0x82, '\u{201A}'),
712 (0x83, '\u{0192}'),
713 (0x84, '\u{201E}'),
714 (0x85, '\u{2026}'),
715 (0x86, '\u{2020}'),
716 (0x87, '\u{2021}'),
717 (0x88, '\u{02C6}'),
718 (0x89, '\u{2030}'),
719 (0x8A, '\u{0160}'),
720 (0x8B, '\u{2039}'),
721 (0x8C, '\u{0152}'),
722 (0x8E, '\u{017D}'),
723 (0x91, '\u{2018}'),
724 (0x92, '\u{2019}'),
725 (0x93, '\u{201C}'),
726 (0x94, '\u{201D}'),
727 (0x95, '\u{2022}'),
728 (0x96, '\u{2013}'),
729 (0x97, '\u{2014}'),
730 (0x98, '\u{02DC}'),
731 (0x99, '\u{2122}'),
732 (0x9A, '\u{0161}'),
733 (0x9B, '\u{203A}'),
734 (0x9C, '\u{0153}'),
735 (0x9E, '\u{017E}'),
736 (0x9F, '\u{0178}'),
737 ];
738 for (b, c) in overlay {
739 m.set_char(*b, *c);
740 }
741 for b in 0xA0u8..=0xFF {
743 m.set_char(b, b as char);
744 }
745}
746
747fn fill_macroman(m: &mut EncodingMap) {
749 for b in 0x20u8..=0x7E {
751 m.set_char(b, b as char);
752 }
753 let table: &[(u8, char)] = &[
755 (0x80, '\u{00C4}'),
756 (0x81, '\u{00C5}'),
757 (0x82, '\u{00C7}'),
758 (0x83, '\u{00C9}'),
759 (0x84, '\u{00D1}'),
760 (0x85, '\u{00D6}'),
761 (0x86, '\u{00DC}'),
762 (0x87, '\u{00E1}'),
763 (0x88, '\u{00E0}'),
764 (0x89, '\u{00E2}'),
765 (0x8A, '\u{00E4}'),
766 (0x8B, '\u{00E3}'),
767 (0x8C, '\u{00E5}'),
768 (0x8D, '\u{00E7}'),
769 (0x8E, '\u{00E9}'),
770 (0x8F, '\u{00E8}'),
771 (0x90, '\u{00EA}'),
772 (0x91, '\u{00EB}'),
773 (0x92, '\u{00ED}'),
774 (0x93, '\u{00EC}'),
775 (0x94, '\u{00EE}'),
776 (0x95, '\u{00EF}'),
777 (0x96, '\u{00F1}'),
778 (0x97, '\u{00F3}'),
779 (0x98, '\u{00F2}'),
780 (0x99, '\u{00F4}'),
781 (0x9A, '\u{00F6}'),
782 (0x9B, '\u{00F5}'),
783 (0x9C, '\u{00FA}'),
784 (0x9D, '\u{00F9}'),
785 (0x9E, '\u{00FB}'),
786 (0x9F, '\u{00FC}'),
787 (0xA0, '\u{2020}'),
788 (0xA1, '\u{00B0}'),
789 (0xA2, '\u{00A2}'),
790 (0xA3, '\u{00A3}'),
791 (0xA4, '\u{00A7}'),
792 (0xA5, '\u{2022}'),
793 (0xA6, '\u{00B6}'),
794 (0xA7, '\u{00DF}'),
795 (0xA8, '\u{00AE}'),
796 (0xA9, '\u{00A9}'),
797 (0xAA, '\u{2122}'),
798 (0xAB, '\u{00B4}'),
799 (0xAC, '\u{00A8}'),
800 (0xAD, '\u{2260}'),
801 (0xAE, '\u{00C6}'),
802 (0xAF, '\u{00D8}'),
803 (0xB0, '\u{221E}'),
804 (0xB1, '\u{00B1}'),
805 (0xB2, '\u{2264}'),
806 (0xB3, '\u{2265}'),
807 (0xB4, '\u{00A5}'),
808 (0xB5, '\u{00B5}'),
809 (0xB6, '\u{2202}'),
810 (0xB7, '\u{2211}'),
811 (0xB8, '\u{220F}'),
812 (0xB9, '\u{03C0}'),
813 (0xBA, '\u{222B}'),
814 (0xBB, '\u{00AA}'),
815 (0xBC, '\u{00BA}'),
816 (0xBD, '\u{03A9}'),
817 (0xBE, '\u{00E6}'),
818 (0xBF, '\u{00F8}'),
819 (0xC0, '\u{00BF}'),
820 (0xC1, '\u{00A1}'),
821 (0xC2, '\u{00AC}'),
822 (0xC3, '\u{221A}'),
823 (0xC4, '\u{0192}'),
824 (0xC5, '\u{2248}'),
825 (0xC6, '\u{2206}'),
826 (0xC7, '\u{00AB}'),
827 (0xC8, '\u{00BB}'),
828 (0xC9, '\u{2026}'),
829 (0xCA, '\u{00A0}'),
830 (0xCB, '\u{00C0}'),
831 (0xCC, '\u{00C3}'),
832 (0xCD, '\u{00D5}'),
833 (0xCE, '\u{0152}'),
834 (0xCF, '\u{0153}'),
835 (0xD0, '\u{2013}'),
836 (0xD1, '\u{2014}'),
837 (0xD2, '\u{201C}'),
838 (0xD3, '\u{201D}'),
839 (0xD4, '\u{2018}'),
840 (0xD5, '\u{2019}'),
841 (0xD6, '\u{00F7}'),
842 (0xD7, '\u{25CA}'),
843 (0xD8, '\u{00FF}'),
844 (0xD9, '\u{0178}'),
845 (0xDA, '\u{2044}'),
846 (0xDB, '\u{20AC}'),
847 (0xDC, '\u{2039}'),
848 (0xDD, '\u{203A}'),
849 (0xDE, '\u{FB01}'),
850 (0xDF, '\u{FB02}'),
851 (0xE0, '\u{2021}'),
852 (0xE1, '\u{00B7}'),
853 (0xE2, '\u{201A}'),
854 (0xE3, '\u{201E}'),
855 (0xE4, '\u{2030}'),
856 (0xE5, '\u{00C2}'),
857 (0xE6, '\u{00CA}'),
858 (0xE7, '\u{00C1}'),
859 (0xE8, '\u{00CB}'),
860 (0xE9, '\u{00C8}'),
861 (0xEA, '\u{00CD}'),
862 (0xEB, '\u{00CE}'),
863 (0xEC, '\u{00CF}'),
864 (0xED, '\u{00CC}'),
865 (0xEE, '\u{00D3}'),
866 (0xEF, '\u{00D4}'),
867 (0xF1, '\u{00D2}'),
868 (0xF2, '\u{00DA}'),
869 (0xF3, '\u{00DB}'),
870 (0xF4, '\u{00D9}'),
871 (0xF5, '\u{0131}'),
872 (0xF6, '\u{02C6}'),
873 (0xF7, '\u{02DC}'),
874 (0xF8, '\u{00AF}'),
875 (0xF9, '\u{02D8}'),
876 (0xFA, '\u{02D9}'),
877 (0xFB, '\u{02DA}'),
878 (0xFC, '\u{00B8}'),
879 (0xFD, '\u{02DD}'),
880 (0xFE, '\u{02DB}'),
881 (0xFF, '\u{02C7}'),
882 ];
883 for (b, c) in table {
884 m.set_char(*b, *c);
885 }
886}
887
888fn fill_macexpert(m: &mut EncodingMap) {
893 let table: &[(u8, char)] = &[
896 (0x20, ' '),
897 (0x21, '\u{F721}'),
898 (0x22, '\u{F6F8}'),
899 (0x23, '\u{F7A2}'),
900 (0x24, '\u{F724}'),
901 (0x25, '\u{F6E4}'),
902 (0x26, '\u{F726}'),
903 (0x27, '\u{F7B4}'),
904 (0x28, '\u{207D}'),
905 (0x29, '\u{207E}'),
906 (0x2A, '\u{2022}'),
907 (0x2B, '\u{2024}'),
908 (0x2C, ','),
909 (0x2D, '-'),
910 (0x2E, '.'),
911 (0x2F, '\u{2044}'),
912 (0x30, '\u{F730}'),
913 (0x31, '\u{F731}'),
914 (0x32, '\u{F732}'),
915 (0x33, '\u{F733}'),
916 (0x34, '\u{F734}'),
917 (0x35, '\u{F735}'),
918 (0x36, '\u{F736}'),
919 (0x37, '\u{F737}'),
920 (0x38, '\u{F738}'),
921 (0x39, '\u{F739}'),
922 (0x3A, ':'),
923 (0x3B, ';'),
924 (0x3D, '\u{F6DE}'),
925 (0x3F, '\u{F73F}'),
926 ];
927 for (b, c) in table {
928 m.set_char(*b, *c);
929 }
930}
931
932fn fill_standard(m: &mut EncodingMap) {
936 for b in 0x20u8..=0x7E {
938 m.set_char(b, b as char);
939 }
940 m.set_char(0x27, '\u{2019}'); m.set_char(0x60, '\u{2018}'); m.set_char(0x22, '"'); let upper: &[(u8, char)] = &[
948 (0xA1, '\u{00A1}'),
949 (0xA2, '\u{00A2}'),
950 (0xA3, '\u{00A3}'),
951 (0xA4, '\u{2044}'),
952 (0xA5, '\u{00A5}'),
953 (0xA6, '\u{0192}'),
954 (0xA7, '\u{00A7}'),
955 (0xA8, '\u{00A4}'),
956 (0xA9, '\''),
957 (0xAA, '\u{201C}'),
958 (0xAB, '\u{00AB}'),
959 (0xAC, '\u{2039}'),
960 (0xAD, '\u{203A}'),
961 (0xAE, '\u{FB01}'),
962 (0xAF, '\u{FB02}'),
963 (0xB1, '\u{2013}'),
964 (0xB2, '\u{2020}'),
965 (0xB3, '\u{2021}'),
966 (0xB4, '\u{00B7}'),
967 (0xB6, '\u{00B6}'),
968 (0xB7, '\u{2022}'),
969 (0xB8, '\u{201A}'),
970 (0xB9, '\u{201E}'),
971 (0xBA, '\u{201D}'),
972 (0xBB, '\u{00BB}'),
973 (0xBC, '\u{2026}'),
974 (0xBD, '\u{2030}'),
975 (0xBF, '\u{00BF}'),
976 (0xC1, '\u{0060}'),
977 (0xC2, '\u{00B4}'),
978 (0xC3, '\u{02C6}'),
979 (0xC4, '\u{02DC}'),
980 (0xC5, '\u{00AF}'),
981 (0xC6, '\u{02D8}'),
982 (0xC7, '\u{02D9}'),
983 (0xC8, '\u{00A8}'),
984 (0xCA, '\u{02DA}'),
985 (0xCB, '\u{00B8}'),
986 (0xCD, '\u{02DD}'),
987 (0xCE, '\u{02DB}'),
988 (0xCF, '\u{02C7}'),
989 (0xD0, '\u{2014}'),
990 (0xE1, '\u{00C6}'),
991 (0xE3, '\u{00AA}'),
992 (0xE8, '\u{0141}'),
993 (0xE9, '\u{00D8}'),
994 (0xEA, '\u{0152}'),
995 (0xEB, '\u{00BA}'),
996 (0xF1, '\u{00E6}'),
997 (0xF5, '\u{0131}'),
998 (0xF8, '\u{0142}'),
999 (0xF9, '\u{00F8}'),
1000 (0xFA, '\u{0153}'),
1001 (0xFB, '\u{00DF}'),
1002 ];
1003 for (b, c) in upper {
1004 m.set_char(*b, *c);
1005 }
1006}
1007
1008fn fill_symbol(m: &mut EncodingMap) {
1011 let table: &[(u8, char)] = &[
1012 (0x20, ' '),
1013 (0x21, '!'),
1014 (0x22, '\u{2200}'), (0x23, '#'),
1016 (0x24, '\u{2203}'), (0x25, '%'),
1018 (0x26, '&'),
1019 (0x27, '\u{220B}'),
1020 (0x28, '('),
1021 (0x29, ')'),
1022 (0x2A, '\u{2217}'),
1023 (0x2B, '+'),
1024 (0x2C, ','),
1025 (0x2D, '\u{2212}'),
1026 (0x2E, '.'),
1027 (0x2F, '/'),
1028 (0x30, '0'),
1029 (0x31, '1'),
1030 (0x32, '2'),
1031 (0x33, '3'),
1032 (0x34, '4'),
1033 (0x35, '5'),
1034 (0x36, '6'),
1035 (0x37, '7'),
1036 (0x38, '8'),
1037 (0x39, '9'),
1038 (0x3A, ':'),
1039 (0x3B, ';'),
1040 (0x3C, '<'),
1041 (0x3D, '='),
1042 (0x3E, '>'),
1043 (0x3F, '?'),
1044 (0x40, '\u{2245}'),
1045 (0x41, '\u{0391}'),
1046 (0x42, '\u{0392}'),
1047 (0x43, '\u{03A7}'),
1048 (0x44, '\u{0394}'),
1049 (0x45, '\u{0395}'),
1050 (0x46, '\u{03A6}'),
1051 (0x47, '\u{0393}'),
1052 (0x48, '\u{0397}'),
1053 (0x49, '\u{0399}'),
1054 (0x4A, '\u{03D1}'),
1055 (0x4B, '\u{039A}'),
1056 (0x4C, '\u{039B}'),
1057 (0x4D, '\u{039C}'),
1058 (0x4E, '\u{039D}'),
1059 (0x4F, '\u{039F}'),
1060 (0x50, '\u{03A0}'),
1061 (0x51, '\u{0398}'),
1062 (0x52, '\u{03A1}'),
1063 (0x53, '\u{03A3}'),
1064 (0x54, '\u{03A4}'),
1065 (0x55, '\u{03A5}'),
1066 (0x56, '\u{03C2}'),
1067 (0x57, '\u{03A9}'),
1068 (0x58, '\u{039E}'),
1069 (0x59, '\u{03A8}'),
1070 (0x5A, '\u{0396}'),
1071 (0x61, '\u{03B1}'),
1072 (0x62, '\u{03B2}'),
1073 (0x63, '\u{03C7}'),
1074 (0x64, '\u{03B4}'),
1075 (0x65, '\u{03B5}'),
1076 (0x66, '\u{03C6}'),
1077 (0x67, '\u{03B3}'),
1078 (0x68, '\u{03B7}'),
1079 (0x69, '\u{03B9}'),
1080 (0x6A, '\u{03D5}'),
1081 (0x6B, '\u{03BA}'),
1082 (0x6C, '\u{03BB}'),
1083 (0x6D, '\u{03BC}'),
1084 (0x6E, '\u{03BD}'),
1085 (0x6F, '\u{03BF}'),
1086 (0x70, '\u{03C0}'),
1087 (0x71, '\u{03B8}'),
1088 (0x72, '\u{03C1}'),
1089 (0x73, '\u{03C3}'),
1090 (0x74, '\u{03C4}'),
1091 (0x75, '\u{03C5}'),
1092 (0x76, '\u{03D6}'),
1093 (0x77, '\u{03C9}'),
1094 (0x78, '\u{03BE}'),
1095 (0x79, '\u{03C8}'),
1096 (0x7A, '\u{03B6}'),
1097 ];
1098 for (b, c) in table {
1099 m.set_char(*b, *c);
1100 }
1101}
1102
1103fn fill_zapfdingbats(m: &mut EncodingMap) {
1106 let table: &[(u8, char)] = &[
1107 (0x20, ' '),
1108 (0x21, '\u{2701}'),
1109 (0x22, '\u{2702}'),
1110 (0x23, '\u{2703}'),
1111 (0x24, '\u{2704}'),
1112 (0x25, '\u{260E}'),
1113 (0x26, '\u{2706}'),
1114 (0x27, '\u{2707}'),
1115 (0x28, '\u{2708}'),
1116 (0x29, '\u{2709}'),
1117 (0x2A, '\u{261B}'),
1118 (0x2B, '\u{261E}'),
1119 (0x2C, '\u{270C}'),
1120 (0x2D, '\u{270D}'),
1121 (0x2E, '\u{270E}'),
1122 (0x2F, '\u{270F}'),
1123 (0x30, '\u{2710}'),
1124 (0x31, '\u{2711}'),
1125 (0x32, '\u{2712}'),
1126 (0x33, '\u{2713}'),
1127 (0x34, '\u{2714}'),
1128 (0x35, '\u{2715}'),
1129 (0x36, '\u{2716}'),
1130 (0x37, '\u{2717}'),
1131 (0x38, '\u{2718}'),
1132 (0x39, '\u{2719}'),
1133 (0x3A, '\u{271A}'),
1134 (0x3B, '\u{271B}'),
1135 (0x3C, '\u{271C}'),
1136 (0x3D, '\u{271D}'),
1137 (0x3E, '\u{271E}'),
1138 (0x3F, '\u{271F}'),
1139 (0x40, '\u{2720}'),
1140 (0x41, '\u{2721}'),
1141 (0x42, '\u{2722}'),
1142 (0x43, '\u{2723}'),
1143 ];
1144 for (b, c) in table {
1145 m.set_char(*b, *c);
1146 }
1147}
1148
1149#[cfg(test)]
1152mod tests {
1153 use super::*;
1154
1155 fn name(s: &str) -> Object {
1156 Object::Name(s.to_string())
1157 }
1158 fn int(n: i64) -> Object {
1159 Object::Integer(n)
1160 }
1161
1162 #[test]
1163 fn parse_simple_differences_array() {
1164 let arr = Object::Array(vec![
1166 int(24),
1167 name("breve"),
1168 name("caron"),
1169 name("circumflex"),
1170 int(32),
1171 name("space"),
1172 ]);
1173 let d = parse_encoding_differences(&arr).unwrap();
1174 assert_eq!(d.overrides.len(), 4);
1175 assert_eq!(d.overrides[0].code, 24);
1176 assert_eq!(d.overrides[0].glyph_name, "breve");
1177 assert_eq!(d.overrides[1].code, 25);
1178 assert_eq!(d.overrides[1].glyph_name, "caron");
1179 assert_eq!(d.overrides[2].code, 26);
1180 assert_eq!(d.overrides[2].glyph_name, "circumflex");
1181 assert_eq!(d.overrides[3].code, 32);
1182 assert_eq!(d.overrides[3].glyph_name, "space");
1183 }
1184
1185 #[test]
1186 fn parse_differences_skips_unknown_tokens() {
1187 let arr = Object::Array(vec![int(24), name("breve"), Object::Null, name("caron")]);
1189 let d = parse_encoding_differences(&arr).unwrap();
1190 assert_eq!(d.overrides.len(), 2);
1191 assert_eq!(d.overrides[0].code, 24);
1192 assert_eq!(d.overrides[1].code, 25);
1193 assert_eq!(d.overrides[1].glyph_name, "caron");
1194 }
1195
1196 #[test]
1197 fn parse_differences_real_coerced() {
1198 let arr = Object::Array(vec![Object::Real(24.0), name("breve")]);
1200 let d = parse_encoding_differences(&arr).unwrap();
1201 assert_eq!(d.overrides.len(), 1);
1202 assert_eq!(d.overrides[0].code, 24);
1203 }
1204
1205 #[test]
1206 fn parse_differences_rejects_non_array() {
1207 let r = parse_encoding_differences(&Object::Null);
1208 assert!(r.is_err());
1209 }
1210
1211 #[test]
1212 fn agl_lookup_basic_latin() {
1213 assert_eq!(glyph_name_to_unicode("A").as_deref(), Some("A"));
1214 assert_eq!(glyph_name_to_unicode("space").as_deref(), Some(" "));
1215 assert_eq!(glyph_name_to_unicode("zero").as_deref(), Some("0"));
1216 }
1217
1218 #[test]
1219 fn agl_lookup_smart_quotes() {
1220 assert_eq!(
1221 glyph_name_to_unicode("quoteright").as_deref(),
1222 Some("\u{2019}")
1223 );
1224 assert_eq!(
1225 glyph_name_to_unicode("quotedblleft").as_deref(),
1226 Some("\u{201C}")
1227 );
1228 }
1229
1230 #[test]
1231 fn agl_lookup_ligature() {
1232 assert_eq!(glyph_name_to_unicode("fi").as_deref(), Some("fi"));
1233 assert_eq!(glyph_name_to_unicode("fl").as_deref(), Some("fl"));
1234 }
1235
1236 #[test]
1237 fn agl_lookup_notdef_is_empty() {
1238 assert_eq!(glyph_name_to_unicode(".notdef").as_deref(), Some(""));
1239 }
1240
1241 #[test]
1242 fn agl_lookup_unknown() {
1243 assert!(glyph_name_to_unicode("notaglyphname").is_none());
1244 }
1245
1246 #[test]
1247 fn agl_uni_bmp_single_group() {
1248 assert_eq!(
1250 glyph_name_to_unicode("uni201C").as_deref(),
1251 Some("\u{201C}")
1252 );
1253 assert_eq!(
1254 glyph_name_to_unicode("uni2019").as_deref(),
1255 Some("\u{2019}")
1256 );
1257 assert_eq!(glyph_name_to_unicode("uni0041").as_deref(), Some("A"));
1260 }
1261
1262 #[test]
1263 fn agl_uni_bmp_multi_group() {
1264 assert_eq!(
1267 glyph_name_to_unicode("uni20142019").as_deref(),
1268 Some("\u{2014}\u{2019}")
1269 );
1270 }
1271
1272 #[test]
1273 fn agl_uni_supplementary_plane() {
1274 assert_eq!(
1277 glyph_name_to_unicode("u1F600").as_deref(),
1278 Some("\u{1F600}")
1279 );
1280 assert_eq!(
1282 glyph_name_to_unicode("u10FFFF").as_deref(),
1283 Some("\u{10FFFF}")
1284 );
1285 assert_eq!(glyph_name_to_unicode("u00A9").as_deref(), Some("\u{00A9}"));
1287 }
1288
1289 #[test]
1290 fn agl_uni_rejects_surrogate_halves() {
1291 assert!(glyph_name_to_unicode("uniD800").is_none());
1293 assert!(glyph_name_to_unicode("uniDFFF").is_none());
1294 assert!(glyph_name_to_unicode("uD800").is_none());
1295 }
1296
1297 #[test]
1298 fn agl_uni_rejects_ffff_noncharacter() {
1299 assert!(glyph_name_to_unicode("uniFFFF").is_none());
1301 assert!(glyph_name_to_unicode("uFFFF").is_none());
1302 }
1303
1304 #[test]
1305 fn agl_uni_rejects_misshapen_input() {
1306 assert!(glyph_name_to_unicode("uni20").is_none());
1308 assert!(glyph_name_to_unicode("uni20142").is_none());
1309 assert!(glyph_name_to_unicode("uni").is_none());
1311 assert!(glyph_name_to_unicode("u041").is_none());
1313 assert!(glyph_name_to_unicode("u1234567").is_none());
1314 assert!(glyph_name_to_unicode("u110000").is_none());
1316 assert!(glyph_name_to_unicode("uni201c").is_none());
1319 assert!(glyph_name_to_unicode("u1f600").is_none());
1320 assert!(glyph_name_to_unicode("uniZZZZ").is_none());
1322 assert!(glyph_name_to_unicode("university").is_none());
1326 }
1327
1328 #[test]
1329 fn agl_uni_escape_in_differences() {
1330 let base = EncodingMap::from_base(BaseEncoding::WinAnsi);
1333 let diffs = EncodingDifferences {
1334 overrides: vec![
1335 EncodingOverride {
1336 code: 0x80,
1337 glyph_name: "uni201C".to_string(),
1338 },
1339 EncodingOverride {
1340 code: 0x81,
1341 glyph_name: "u1F600".to_string(),
1342 },
1343 ],
1344 };
1345 let out = apply_encoding_differences(&base, &diffs);
1346 assert_eq!(out.decode(&[0x80]), "\u{201C}");
1347 assert_eq!(out.decode(&[0x81]), "\u{1F600}");
1348 }
1349
1350 #[test]
1351 fn winansi_base_map_decodes_ascii_and_smart_quote() {
1352 let m = EncodingMap::from_base(BaseEncoding::WinAnsi);
1353 assert_eq!(m.decode(b"Hello"), "Hello");
1354 assert_eq!(m.decode(&[0x93]), "\u{201C}");
1356 }
1357
1358 #[test]
1359 fn apply_differences_overrides_base_map() {
1360 let base = EncodingMap::from_base(BaseEncoding::WinAnsi);
1362 let diffs = EncodingDifferences {
1363 overrides: vec![EncodingOverride {
1364 code: 0x41,
1365 glyph_name: "Omega".to_string(),
1366 }],
1367 };
1368 let out = apply_encoding_differences(&base, &diffs);
1369 assert_eq!(out.decode(&[0x41]), "\u{03A9}"); assert_eq!(out.decode(&[0x42]), "B");
1372 }
1373
1374 #[test]
1375 fn apply_differences_unknown_glyph_becomes_replacement() {
1376 let base = EncodingMap::from_base(BaseEncoding::WinAnsi);
1377 let diffs = EncodingDifferences {
1378 overrides: vec![EncodingOverride {
1379 code: 0x41,
1380 glyph_name: "not-a-real-glyph-name".to_string(),
1381 }],
1382 };
1383 let out = apply_encoding_differences(&base, &diffs);
1384 assert_eq!(out.decode(&[0x41]), "\u{FFFD}");
1386 }
1387
1388 #[test]
1389 fn apply_differences_ligature_expands() {
1390 let base = EncodingMap::from_base(BaseEncoding::WinAnsi);
1391 let diffs = EncodingDifferences {
1392 overrides: vec![EncodingOverride {
1393 code: 0xFD,
1394 glyph_name: "fi".to_string(),
1395 }],
1396 };
1397 let out = apply_encoding_differences(&base, &diffs);
1398 assert_eq!(out.decode(&[0xFD]), "fi");
1399 }
1400
1401 #[test]
1402 fn macroman_base_map_smart_quotes() {
1403 let m = EncodingMap::from_base(BaseEncoding::MacRoman);
1404 assert_eq!(m.decode(&[0xD2]), "\u{201C}");
1406 }
1407
1408 #[test]
1409 fn standard_base_map_quotes() {
1410 let m = EncodingMap::from_base(BaseEncoding::Standard);
1411 assert_eq!(m.decode(&[0x27]), "\u{2019}");
1413 }
1414
1415 #[test]
1416 fn symbol_base_map_alpha() {
1417 let m = EncodingMap::from_base(BaseEncoding::Symbol);
1418 assert_eq!(m.decode(&[0x41]), "\u{0391}");
1420 assert_eq!(m.decode(&[0x70]), "\u{03C0}");
1422 }
1423
1424 #[test]
1425 fn base_encoding_name_recognition() {
1426 assert_eq!(
1427 BaseEncoding::from_name("WinAnsiEncoding"),
1428 Some(BaseEncoding::WinAnsi)
1429 );
1430 assert_eq!(
1431 BaseEncoding::from_name("MacRomanEncoding"),
1432 Some(BaseEncoding::MacRoman)
1433 );
1434 assert_eq!(BaseEncoding::from_name("not-a-real-name"), None);
1435 }
1436
1437 #[test]
1438 fn unassigned_code_decodes_to_replacement() {
1439 let m = EncodingMap::from_base(BaseEncoding::Standard);
1440 assert_eq!(m.decode(&[0x00]), "\u{FFFD}");
1442 }
1443}