1mod predefined;
9
10pub use predefined::{cid_to_unicode, predefined, CidToUnicode};
11
12use crate::document::decoded_stream_data_with;
13use crate::hash::FastMap;
14use crate::lexer::{decode_hex, decode_hex_fixed, Lexer, RawToken, Token};
15use crate::object::{Dict, Object, Stream};
16use crate::source::AsyncObjectSource;
17use std::sync::Arc;
18
19#[derive(Clone, Copy)]
24struct Codespace {
25 len: u8,
26 lo: [u8; 4],
27 hi: [u8; 4],
28}
29
30impl Codespace {
31 fn contains(&self, code: &[u8]) -> bool {
32 code.iter()
33 .zip(self.lo.iter().zip(&self.hi))
34 .all(|(&b, (&lo, &hi))| lo <= b && b <= hi)
35 }
36}
37
38#[derive(Clone, Copy)]
41struct CidRange {
42 len: u8,
43 lo: u32,
44 hi: u32,
45 cid: u32,
46}
47
48pub struct CidCmap {
52 wmode: u8,
53 codespaces: Vec<Codespace>,
56 singles: FastMap<(u8, u32), u32>,
58 ranges: Vec<CidRange>,
60 notdefs: Vec<CidRange>,
63 parent: Option<Arc<CidCmap>>,
66}
67
68fn code_value(bytes: &[u8]) -> u32 {
70 bytes.iter().fold(0u32, |acc, &b| (acc << 8) | u32::from(b))
71}
72
73fn covering_range(ranges: &[CidRange], code: u32, len: u8) -> Option<&CidRange> {
75 let idx = ranges.partition_point(|r| (r.len, r.lo) <= (len, code));
76 let r = ranges.get(idx.checked_sub(1)?)?;
77 (r.len == len && code <= r.hi).then_some(r)
78}
79
80impl CidCmap {
81 pub fn identity(vertical: bool) -> CidCmap {
84 CidCmap {
85 wmode: u8::from(vertical),
86 codespaces: vec![Codespace {
87 len: 2,
88 lo: [0; 4],
89 hi: [0xFF; 4],
90 }],
91 singles: FastMap::default(),
92 ranges: vec![CidRange {
93 len: 2,
94 lo: 0,
95 hi: 0xFFFF,
96 cid: 0,
97 }],
98 notdefs: Vec::new(),
99 parent: None,
100 }
101 }
102
103 pub fn parse(data: &[u8]) -> CidCmap {
105 CidCmap::parse_with(data, None, &mut |_| None)
106 }
107
108 pub fn parse_with(
113 data: &[u8],
114 parent: Option<Arc<CidCmap>>,
115 resolve: &mut dyn FnMut(&str) -> Option<Arc<CidCmap>>,
116 ) -> CidCmap {
117 let mut out = CidCmap {
118 wmode: 0,
119 codespaces: Vec::new(),
120 singles: FastMap::default(),
121 ranges: Vec::new(),
122 notdefs: Vec::new(),
123 parent,
124 };
125 let mut lx = Lexer::new(data);
126 let mut pending_name: Option<String> = None;
127 let mut wmode_pending = false;
128 loop {
129 match next_or_skip(&mut lx, data.len()) {
130 None => break,
131 Some(RawToken::Keyword(kw)) => {
132 match kw {
133 b"begincodespacerange" => out.parse_codespaces(&mut lx, data.len()),
134 b"begincidchar" => out.parse_cidchars(&mut lx, data.len(), false),
135 b"begincidrange" => out.parse_cidranges(&mut lx, data.len(), false),
136 b"beginnotdefchar" => out.parse_cidchars(&mut lx, data.len(), true),
137 b"beginnotdefrange" => out.parse_cidranges(&mut lx, data.len(), true),
138 b"usecmap" => {
139 if let (None, Some(name)) = (&out.parent, pending_name.take()) {
140 out.parent = resolve(&name);
141 }
142 }
143 _ => {}
144 }
145 pending_name = None;
146 wmode_pending = false;
147 }
148 Some(RawToken::Owned(Token::Name(n))) => {
149 wmode_pending = n.0 == "WMode";
150 pending_name = (!wmode_pending).then_some(n.0);
151 }
152 Some(RawToken::Owned(Token::Int(i))) => {
153 if wmode_pending {
154 out.wmode = u8::from(i == 1);
155 }
156 wmode_pending = false;
157 }
158 Some(_) => {
159 pending_name = None;
160 wmode_pending = false;
161 }
162 }
163 }
164 out.finish();
165 out
166 }
167
168 fn finish(&mut self) {
171 if let Some(parent) = &self.parent {
172 self.codespaces.extend_from_slice(&parent.codespaces);
173 }
174 self.codespaces.sort_by_key(|c| c.len);
175 self.ranges.sort_by_key(|r| (r.len, r.lo));
176 self.notdefs.sort_by_key(|r| (r.len, r.lo));
177 }
178
179 pub fn is_empty(&self) -> bool {
183 self.singles.is_empty() && self.ranges.is_empty() && self.parent.is_none()
184 }
185
186 pub fn vertical(&self) -> bool {
188 self.wmode == 1
189 }
190
191 pub fn parent(&self) -> Option<&Arc<CidCmap>> {
195 self.parent.as_ref()
196 }
197
198 pub fn single_byte(&self, b: u8) -> bool {
202 self.codespaces
203 .iter()
204 .any(|c| c.len == 1 && c.contains(&[b]))
205 }
206
207 pub fn code_at(&self, bytes: &[u8], pos: usize) -> (u32, u8) {
216 let rest = &bytes[pos..];
217 if self.codespaces.is_empty() {
218 let n = rest.len().min(2);
219 return (code_value(&rest[..n]), n as u8);
220 }
221 for cs in &self.codespaces {
222 let n = usize::from(cs.len);
223 if rest.len() >= n && cs.contains(&rest[..n]) {
224 return (code_value(&rest[..n]), cs.len);
225 }
226 }
227 for cs in &self.codespaces {
228 if cs.lo[0] <= rest[0] && rest[0] <= cs.hi[0] {
229 let n = usize::from(cs.len).min(rest.len());
230 return (code_value(&rest[..n]), n as u8);
231 }
232 }
233 (u32::from(rest[0]), 1)
234 }
235
236 pub fn cid(&self, code: u32, len: u8) -> Option<u32> {
240 self.mapped(code, len).or_else(|| self.notdef(code, len))
241 }
242
243 fn mapped(&self, code: u32, len: u8) -> Option<u32> {
244 if let Some(&cid) = self.singles.get(&(len, code)) {
245 return Some(cid);
246 }
247 if let Some(r) = covering_range(&self.ranges, code, len) {
249 return Some(r.cid.saturating_add(code - r.lo));
250 }
251 self.parent.as_ref()?.mapped(code, len)
252 }
253
254 fn notdef(&self, code: u32, len: u8) -> Option<u32> {
256 covering_range(&self.notdefs, code, len)
257 .map(|r| r.cid)
258 .or_else(|| self.parent.as_ref()?.notdef(code, len))
259 }
260
261 fn mappings(&self, push: &mut impl FnMut(u8, u32, u32, u32)) {
266 let mut singles: Vec<(u8, u32, u32)> = self
267 .singles
268 .iter()
269 .map(|(&(len, code), &cid)| (len, code, cid))
270 .collect();
271 singles.sort_unstable();
272 let mut singles = singles.into_iter().peekable();
273 let mut ranges = self.ranges.iter().peekable();
274 loop {
275 let single_first = match (singles.peek(), ranges.peek()) {
276 (None, None) => break,
277 (Some(_), None) => true,
278 (None, Some(_)) => false,
279 (Some(&(len, code, _)), Some(r)) => (len, code) <= (r.len, r.lo),
280 };
281 if single_first {
282 let (len, code, cid) = singles.next().unwrap();
283 push(len, code, code, cid);
284 } else {
285 let r = ranges.next().unwrap();
286 push(r.len, r.lo, r.hi, r.cid);
287 }
288 }
289 if let Some(parent) = &self.parent {
290 parent.mappings(push);
291 }
292 }
293
294 fn parse_codespaces(&mut self, lx: &mut Lexer<'_>, len: usize) {
296 loop {
297 let lo = match next_or_skip(lx, len) {
298 Some(RawToken::Hex(span)) => span,
299 Some(_) | None => return, };
301 let Some(RawToken::Hex(hi)) = next_or_skip(lx, len) else {
302 return;
303 };
304 let (Some((lo, lo_len)), Some((hi, hi_len))) =
307 (decode_hex_fixed::<4>(lo), decode_hex_fixed::<4>(hi))
308 else {
309 continue;
310 };
311 if lo_len == 0 || hi_len != lo_len {
312 continue;
313 }
314 self.codespaces.push(Codespace {
315 len: lo_len as u8,
316 lo,
317 hi,
318 });
319 }
320 }
321
322 fn parse_cidchars(&mut self, lx: &mut Lexer<'_>, len: usize, notdef: bool) {
324 loop {
325 let code = match next_or_skip(lx, len) {
326 Some(RawToken::Hex(span)) => span,
327 Some(_) | None => return,
328 };
329 let Some(RawToken::Owned(Token::Int(cid))) = next_or_skip(lx, len) else {
330 return;
331 };
332 let Some((code, code_len)) = decode_hex_fixed::<4>(code) else {
333 continue;
334 };
335 if code_len == 0 {
336 continue;
337 }
338 let (value, width) = (code_value(&code[..code_len]), code_len as u8);
339 let cid = cid.max(0) as u32;
340 if notdef {
341 self.notdefs.push(CidRange {
342 len: width,
343 lo: value,
344 hi: value,
345 cid,
346 });
347 } else {
348 self.singles.insert((width, value), cid);
349 }
350 }
351 }
352
353 fn parse_cidranges(&mut self, lx: &mut Lexer<'_>, len: usize, notdef: bool) {
355 loop {
356 let lo = match next_or_skip(lx, len) {
357 Some(RawToken::Hex(span)) => span,
358 Some(_) | None => return,
359 };
360 let Some(RawToken::Hex(hi)) = next_or_skip(lx, len) else {
361 return;
362 };
363 let Some(RawToken::Owned(Token::Int(cid))) = next_or_skip(lx, len) else {
364 return;
365 };
366 let Some((lo, lo_len)) = decode_hex_fixed::<4>(lo) else {
367 continue;
368 };
369 if lo_len == 0 {
370 continue;
371 }
372 let hi_v = match decode_hex_fixed::<4>(hi) {
375 Some((hi, hi_len)) => code_value(&hi[..hi_len]),
376 None => code_value(&decode_hex(hi)),
377 };
378 let lo_v = code_value(&lo[..lo_len]);
379 if hi_v < lo_v {
380 continue;
381 }
382 let range = CidRange {
383 len: lo_len as u8,
384 lo: lo_v,
385 hi: hi_v,
386 cid: cid.max(0) as u32,
387 };
388 if notdef {
389 self.notdefs.push(range);
390 } else {
391 self.ranges.push(range);
392 }
393 }
394 }
395}
396
397pub struct Type0Encoding {
399 pub cmap: Option<Arc<CidCmap>>,
403 pub vertical: bool,
405 pub known: bool,
409}
410
411async fn rv<S: AsyncObjectSource>(src: &S, dict: &Dict, key: &str) -> Option<Object> {
413 let obj = dict.get(key)?;
414 let resolved = src.resolve(obj).await.ok()?;
415 (!resolved.is_null()).then_some(resolved)
416}
417
418pub async fn type0_encoding<S: AsyncObjectSource>(src: &S, font: &Dict) -> Type0Encoding {
425 let identity = |vertical: bool, known: bool| Type0Encoding {
426 cmap: None,
427 vertical,
428 known,
429 };
430 let Some(enc) = rv(src, font, "Encoding").await else {
431 return identity(false, false);
432 };
433 match enc {
434 Object::Name(n) if n.0 == "Identity-H" => identity(false, true),
435 Object::Name(n) if n.0 == "Identity-V" => identity(true, true),
436 Object::Name(n) => match predefined(&n.0) {
437 Some(cmap) => Type0Encoding {
438 vertical: cmap.vertical(),
439 cmap: Some(cmap),
440 known: true,
441 },
442 None => identity(n.0.ends_with("-V"), false),
443 },
444 Object::Stream(stream) => match embedded_cmap(src, &stream).await {
445 Some(cmap) => Type0Encoding {
446 vertical: cmap.vertical(),
447 cmap: Some(cmap),
448 known: true,
449 },
450 None => identity(false, false),
451 },
452 _ => identity(false, false),
453 }
454}
455
456async fn embedded_cmap<S: AsyncObjectSource>(src: &S, stream: &Stream) -> Option<Arc<CidCmap>> {
459 let mut layers: Vec<(Vec<u8>, Option<i64>)> = Vec::new();
462 let mut parent: Option<Arc<CidCmap>> = None;
463 let mut current = stream.clone();
464 for _ in 0..4 {
465 let data = decoded_stream_data_with(src, ¤t).await.ok()?;
468 let wmode = rv(src, ¤t.dict, "WMode")
469 .await
470 .and_then(|o| o.as_int());
471 layers.push((data, wmode));
472 match rv(src, ¤t.dict, "UseCMap").await {
473 Some(Object::Name(n)) => {
474 parent = predefined(&n.0);
475 break;
476 }
477 Some(Object::Stream(s)) => current = s,
478 _ => break,
479 }
480 }
481 for (data, wmode) in layers.into_iter().rev() {
482 let mut resolve = |n: &str| predefined(n);
483 let mut cmap = CidCmap::parse_with(&data, parent.take(), &mut resolve);
484 if let Some(w) = wmode {
485 cmap.wmode = u8::from(w == 1);
486 }
487 parent = Some(Arc::new(cmap));
488 }
489 parent.filter(|c| !c.is_empty())
490}
491
492fn next_or_skip<'a>(lx: &mut Lexer<'a>, len: usize) -> Option<RawToken<'a>> {
495 loop {
496 let before = lx.pos();
497 match lx.next_raw_token() {
498 Ok(RawToken::Owned(Token::Eof)) => return None,
499 Ok(t) => return Some(t),
500 Err(_) => {
501 if lx.pos() <= before {
502 if before + 1 >= len {
503 return None;
504 }
505 lx.seek(before + 1);
506 }
507 }
508 }
509 }
510}
511
512#[cfg(test)]
513mod tests {
514 use super::*;
515
516 const RKSJ_CODESPACES: &str = "4 begincodespacerange\n\
519 <00> <80>\n\
520 <8140> <9FFC>\n\
521 <A0> <DF>\n\
522 <E040> <FCFC>\n\
523 endcodespacerange\n";
524
525 fn rksj() -> CidCmap {
526 let data = format!(
527 "{RKSJ_CODESPACES}\
528 1 beginnotdefrange\n<00> <1f> 231\nendnotdefrange\n\
529 3 begincidrange\n\
530 <20> <7d> 231\n\
531 <8140> <817e> 633\n\
532 <e040> <e07e> 100\n\
533 endcidrange\n\
534 1 begincidchar\n<a1> 9000\nendcidchar\n"
535 );
536 CidCmap::parse(data.as_bytes())
537 }
538
539 #[test]
540 fn rksj_codespaces_split_mixed_widths() {
541 let c = rksj();
542 let bytes = [0x41, 0x81, 0x40, 0xA1];
544 assert_eq!(c.code_at(&bytes, 0), (0x41, 1));
545 assert_eq!(c.code_at(&bytes, 1), (0x8140, 2));
546 assert_eq!(c.code_at(&bytes, 3), (0xA1, 1));
547 }
548
549 #[test]
550 fn cidrange_arithmetic_offsets_within_the_range() {
551 let c = rksj();
552 assert_eq!(c.cid(0x20, 1), Some(231));
553 assert_eq!(c.cid(0x7d, 1), Some(324));
554 assert_eq!(c.cid(0x8140, 2), Some(633));
555 assert_eq!(c.cid(0x8163, 2), Some(633 + 0x23));
556 assert_eq!(c.cid(0xe041, 2), Some(101));
557 assert_eq!(c.cid(0x82FF, 2), None);
558 }
559
560 #[test]
561 fn cidchar_singletons_map() {
562 let c = rksj();
563 assert_eq!(c.cid(0xA1, 1), Some(9000));
564 }
565
566 #[test]
567 fn notdef_ranges_lose_to_real_mappings() {
568 let data = format!(
569 "{RKSJ_CODESPACES}\
570 1 beginnotdefrange\n<00> <1f> 231\nendnotdefrange\n\
571 1 begincidrange\n<10> <11> 5\nendcidrange\n"
572 );
573 let c = CidCmap::parse(data.as_bytes());
574 assert_eq!(c.cid(0x10, 1), Some(5)); assert_eq!(c.cid(0x12, 1), Some(231)); assert_eq!(c.cid(0x20, 1), None);
577 }
578
579 #[test]
580 fn a_one_byte_code_and_a_two_byte_code_with_equal_values_stay_apart() {
581 let data = "2 begincodespacerange <00> <20> <4000> <41FF> endcodespacerange\n\
582 2 begincidrange <20> <20> 7 <0020> <0020> 9 endcidrange";
583 let c = CidCmap::parse(data.as_bytes());
584 assert_eq!(c.cid(0x20, 1), Some(7));
585 assert_eq!(c.cid(0x20, 2), Some(9));
586 }
587
588 #[test]
589 fn usecmap_layers_child_over_parent() {
590 let parent = Arc::new(CidCmap::parse(
591 format!(
592 "{RKSJ_CODESPACES}\
593 2 begincidrange <8140> <817e> 633 <20> <7d> 231 endcidrange"
594 )
595 .as_bytes(),
596 ));
597 let mut resolve = |name: &str| (name == "90ms-RKSJ-H").then(|| Arc::clone(&parent));
598 let child = CidCmap::parse_with(
599 b"/90ms-RKSJ-H usecmap\n\
600 /WMode 1 def\n\
601 1 begincidrange <8141> <8142> 7887 endcidrange",
602 None,
603 &mut resolve,
604 );
605 assert!(child.vertical());
606 assert_eq!(child.cid(0x8141, 2), Some(7887)); assert_eq!(child.cid(0x8140, 2), Some(633)); assert_eq!(child.cid(0x21, 1), Some(232)); assert_eq!(child.code_at(&[0x81, 0x40], 0), (0x8140, 2)); assert_eq!(child.parent().map(|p| p.cid(0x8141, 2)), Some(Some(634)));
611 }
612
613 #[test]
614 fn wmode_reads_and_defaults_horizontal() {
615 assert!(!CidCmap::parse(b"/WMode 0 def").vertical());
616 assert!(CidCmap::parse(b"/WMode 1 def").vertical());
617 assert!(!CidCmap::parse(b"").vertical());
618 assert!(CidCmap::identity(true).vertical());
619 }
620
621 #[test]
622 fn identity_maps_code_to_cid() {
623 let c = CidCmap::identity(false);
624 assert_eq!(c.code_at(&[0x12, 0x34], 0), (0x1234, 2));
625 assert_eq!(c.cid(0x1234, 2), Some(0x1234));
626 assert!(!c.single_byte(0x20));
627 }
628
629 #[test]
630 fn word_spacing_evidence_is_a_one_byte_codespace() {
631 assert!(rksj().single_byte(0x20));
632 assert!(!rksj().single_byte(0x81));
633 }
634
635 #[test]
638 fn splitting_always_consumes_at_least_one_byte() {
639 let cmaps = [rksj(), CidCmap::identity(false), CidCmap::parse(b"")];
640 for c in &cmaps {
641 for bytes in [&[0x81][..], &[0xFF][..], &[0x00, 0x81][..]] {
642 let mut pos = 0;
643 let mut codes = 0;
644 while pos < bytes.len() {
645 let (_, n) = c.code_at(bytes, pos);
646 assert!(n >= 1);
647 pos += usize::from(n).min(bytes.len() - pos);
648 codes += 1;
649 }
650 assert!(codes >= 1);
651 }
652 }
653 assert_eq!(rksj().code_at(&[0x81], 0), (0x81, 1));
655 }
656
657 #[test]
658 fn a_truncated_section_keeps_what_parsed_so_far() {
659 let c = CidCmap::parse(b"2 begincidrange <20> <7d> 231 <8140> <81");
660 assert_eq!(c.cid(0x20, 1), Some(231));
661 assert_eq!(c.cid(0x8140, 2), None);
662 let garbage = CidCmap::parse(b"\xFF\xFE ) ] >> begincidchar <41> 12 endcidchar");
663 assert_eq!(garbage.cid(0x41, 1), Some(12));
664 assert!(CidCmap::parse(b"").is_empty());
665 }
666}