1use crate::{
4 Name, Result,
5 machine::{
6 Key, Machine, MachineError, MachinePlugin, MachineResult, RuntimeDictionary, RuntimeValue,
7 TypeCheckSnafu, UndefinedSnafu, ok,
8 },
9 sname,
10};
11use educe::Educe;
12use either::Either;
13use log::{debug, error};
14use once_cell::unsync::OnceCell;
15use phf::phf_map;
16use snafu::{OptionExt as _, ResultExt as _, ensure_whatever};
17use std::{collections::HashMap, rc::Rc, str::from_utf8};
18use tinyvec::ArrayVec;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub struct CID(pub u16);
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27enum CharCode {
28 One([u8; 1]),
29 Two([u8; 2]),
30 Three([u8; 3]),
31 Four([u8; 4]),
32}
33
34impl CharCode {
35 fn from_str_buf(s: &[u8]) -> Self {
36 match s.len() {
37 1 => Self::One([s[0]]),
38 2 => Self::Two([s[0], s[1]]),
39 3 => Self::Three([s[0], s[1], s[2]]),
40 4 => Self::Four([s[0], s[1], s[2], s[3]]),
41 _ => unreachable!("invalid bytes length"),
42 }
43 }
44
45 pub fn n_bytes(self) -> usize {
46 match self {
47 Self::One(_) => 1,
48 Self::Two(_) => 2,
49 Self::Three(_) => 3,
50 Self::Four(_) => 4,
51 }
52 }
53}
54
55fn parse_cid_from_str_buf(s: &[u8]) -> CID {
56 let bytes = match s.len() {
57 1 => [0, s[0]],
58 2 => [s[0], s[1]],
59 _ => unreachable!(),
60 };
61 CID(u16::from_be_bytes(bytes))
62}
63
64impl AsRef<[u8]> for CharCode {
65 fn as_ref(&self) -> &[u8] {
66 match self {
67 Self::One(b) => b,
68 Self::Two(b) => b,
69 Self::Three(b) => b,
70 Self::Four(b) => b,
71 }
72 }
73}
74
75impl From<&[u8]> for CharCode {
76 fn from(bytes: &[u8]) -> Self {
77 match bytes.len() {
78 1 => Self::One([bytes[0]]),
79 2 => Self::Two([bytes[0], bytes[1]]),
80 3 => Self::Three([bytes[0], bytes[1], bytes[2]]),
81 4 => Self::Four([bytes[0], bytes[1], bytes[2], bytes[3]]),
82 _ => unreachable!("invalid bytes length"),
83 }
84 }
85}
86
87trait CodeMap {
89 fn map(&self, code: CharCode) -> Option<CID>;
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
93struct ByteRange {
94 lower: u8,
95 upper: u8,
96}
97
98impl ByteRange {
99 pub fn new(lower: u8, upper: u8) -> Self {
100 assert!(lower <= upper);
101 Self { lower, upper }
102 }
103
104 fn in_range(self, c: u8) -> bool {
105 self.lower <= c && c <= self.upper
106 }
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110enum CodeSpaceResult {
111 Matched(CharCode),
113 Partial(CharCode),
115 NotMatched,
117}
118
119#[derive(Debug, Clone, PartialEq, Eq)]
124struct CodeRange(ArrayVec<[ByteRange; 4]>);
125
126impl CodeRange {
127 fn from_str_buf(lower: &[u8], upper: &[u8]) -> Option<Self> {
128 if lower.len() != upper.len() {
129 return None;
130 }
131 let mut r = ArrayVec::new();
132 for (l, u) in lower.iter().copied().zip(upper.iter().copied()) {
133 r.push(ByteRange::new(l, u));
134 }
135 Some(Self(r))
136 }
137
138 fn offset(&self, ch: CharCode) -> Option<u16> {
141 if ch.n_bytes() != self.n_bytes() {
142 return None;
143 }
144
145 let mut offset = 0u16;
146 for (r, c) in self.0.iter().zip(ch.as_ref().iter().copied()) {
147 if !r.in_range(c) {
148 return None;
149 }
150 offset = offset * (r.upper as u16 - r.lower as u16 + 1) + (c as u16 - r.lower as u16);
151 }
152 Some(offset)
153 }
154
155 fn in_range(&self, ch: CharCode) -> bool {
157 self.offset(ch).is_some()
158 }
159
160 fn next_code(&self, codes: &[u8]) -> CodeSpaceResult {
162 match self
163 .0
164 .iter()
165 .zip(codes.iter().copied())
166 .take_while(|(r, c)| r.in_range(*c))
167 .count()
168 {
169 0 => CodeSpaceResult::NotMatched,
170 n if n == self.n_bytes() => CodeSpaceResult::Matched(CharCode::from(&codes[..n])),
171 _ => {
172 CodeSpaceResult::Partial(CharCode::from(&codes[..self.n_bytes().min(codes.len())]))
173 }
174 }
175 }
176
177 fn n_bytes(&self) -> usize {
178 self.0.len()
179 }
180}
181
182struct CodeRangeParser;
183
184impl EntryParser<CodeRange> for CodeRangeParser {
185 fn parse_entry<P>(&self, m: &mut Machine<'_, P>) -> Result<CodeRange, MachineError> {
186 let s_upper = m.pop()?.string()?;
187 let s_upper = s_upper.borrow();
188 let s_lower = m.pop()?.string()?;
189 let s_lower = s_lower.borrow();
190 CodeRange::from_str_buf(&s_lower, &s_upper).context(TypeCheckSnafu)
191 }
192}
193
194#[derive(Debug, Clone, PartialEq, Eq, Default)]
196struct CodeSpace(Box<[CodeRange]>);
197
198impl CodeSpace {
199 fn new(ranges: Vec<CodeRange>) -> Self {
200 Self(ranges.into_boxed_slice())
201 }
202
203 fn next_code<'a>(&self, codes: &'a [u8]) -> Result<(&'a [u8], Either<CharCode, CharCode>)> {
208 let next = self
209 .0
210 .iter()
211 .find_map(|r| {
212 let r = r.next_code(codes);
213 match r {
214 CodeSpaceResult::Matched(code) => Some(Either::Right(Ok(code))),
215 CodeSpaceResult::Partial(code) => Some(Either::Left(code)),
216 CodeSpaceResult::NotMatched => None,
217 }
218 })
219 .unwrap_or_else(|| Either::Left(CharCode::One([codes[0]])))
220 .map_left(|code| {
221 let min_bytes = self.min_bytes()?;
222 if code.n_bytes() >= min_bytes {
223 return Ok(code);
224 }
225
226 let mut bytes = Vec::with_capacity(min_bytes);
227 bytes.extend_from_slice(&codes[..min_bytes.min(codes.len())]);
228 bytes.resize(min_bytes, 0);
229 Ok(CharCode::from(bytes.as_slice()))
230 })
231 .factor_err()?;
232 Ok((&codes[next.into_inner().n_bytes().min(codes.len())..], next))
233 }
234
235 fn min_bytes(&self) -> Result<usize> {
236 self.0
237 .iter()
238 .map(CodeRange::n_bytes)
239 .min()
240 .whatever_context("Should not happen")
241 }
242}
243
244#[derive(Debug, Clone, PartialEq, Eq)]
247struct IncRangeMap {
248 range: CodeRange,
249 start_cid: CID,
250}
251
252impl CodeMap for IncRangeMap {
253 fn map(&self, code: CharCode) -> Option<CID> {
254 self.range
255 .offset(code)
256 .map(|offset| CID(self.start_cid.0 + offset))
257 }
258}
259
260struct IncRangeMapParser;
261
262impl EntryParser<IncRangeMap> for IncRangeMapParser {
263 fn parse_entry<P>(&self, m: &mut Machine<'_, P>) -> Result<IncRangeMap, MachineError> {
264 let cid = m.pop()?.int()?.try_into().whatever_context("Cast to cid")?;
265 let s_upper = m.pop()?.string()?;
266 let s_lower = m.pop()?.string()?;
267 let range = CodeRange::from_str_buf(&s_lower.borrow(), &s_upper.borrow())
268 .context(TypeCheckSnafu)?;
269 Ok(IncRangeMap {
270 range,
271 start_cid: CID(cid),
272 })
273 }
274}
275
276struct BFIncRangeMapParser;
277
278impl EntryParser<IncRangeMap> for BFIncRangeMapParser {
279 fn parse_entry<P>(&self, m: &mut Machine<'_, P>) -> Result<IncRangeMap, MachineError> {
280 let cid = parse_cid_from_str_buf(&m.pop()?.string()?.borrow());
281 let s_upper = m.pop()?.string()?;
282 let s_lower = m.pop()?.string()?;
283 let range = CodeRange::from_str_buf(&s_lower.borrow(), &s_upper.borrow())
284 .context(TypeCheckSnafu)?;
285 Ok(IncRangeMap {
286 range,
287 start_cid: cid,
288 })
289 }
290}
291
292#[derive(Debug, Clone, PartialEq, Eq)]
294struct RangeMapToOne {
295 range: CodeRange,
296 cid: CID,
297}
298
299impl CodeMap for RangeMapToOne {
300 fn map(&self, code: CharCode) -> Option<CID> {
301 (self.range.in_range(code)).then_some(self.cid)
302 }
303}
304
305struct RangeMapToOneParser;
306
307impl EntryParser<RangeMapToOne> for RangeMapToOneParser {
308 fn parse_entry<P>(&self, m: &mut Machine<'_, P>) -> Result<RangeMapToOne, MachineError> {
309 let cid = m.pop()?.int()?.try_into().whatever_context("cast to cid")?;
310 let s_upper = m.pop()?.string()?;
311 let s_lower = m.pop()?.string()?;
312 let range = CodeRange::from_str_buf(&s_lower.borrow(), &s_upper.borrow())
313 .context(TypeCheckSnafu)?;
314 Ok(RangeMapToOne {
315 range,
316 cid: CID(cid),
317 })
318 }
319}
320
321#[derive(Debug, Clone, PartialEq, Eq)]
323struct SingleCodeMap {
324 code: CharCode,
325 cid: CID,
326}
327
328impl SingleCodeMap {
329 fn new(code: CharCode, cid: CID) -> Self {
330 Self { code, cid }
331 }
332}
333
334impl CodeMap for SingleCodeMap {
335 fn map(&self, code: CharCode) -> Option<CID> {
336 (code == self.code).then_some(self.cid)
337 }
338}
339
340struct SingleCodeMapParser;
341
342impl EntryParser<SingleCodeMap> for SingleCodeMapParser {
343 fn parse_entry<P>(&self, m: &mut Machine<'_, P>) -> Result<SingleCodeMap, MachineError> {
344 let cid = m.pop()?.int()?.try_into().whatever_context("cast to cid")?;
345 let s_code = m.pop()?.string()?;
346 let code = CharCode::from_str_buf(&s_code.borrow());
347 Ok(SingleCodeMap::new(code, CID(cid)))
348 }
349}
350
351struct BFSingleCodeMapParser;
352
353impl EntryParser<SingleCodeMap> for BFSingleCodeMapParser {
354 fn parse_entry<P>(&self, m: &mut Machine<'_, P>) -> Result<SingleCodeMap, MachineError> {
355 let cid = parse_cid_from_str_buf(&m.pop()?.string()?.borrow());
356 let s_code = m.pop()?.string()?;
357 let code = CharCode::from_str_buf(&s_code.borrow());
358 Ok(SingleCodeMap::new(code, cid))
359 }
360}
361
362#[derive(Debug, Clone, PartialEq, Eq, Educe)]
365#[educe(Default)]
366struct Mapper<R> {
367 ranges: Box<[R]>,
368 chars: Box<[SingleCodeMap]>,
369}
370
371impl<R: CodeMap> CodeMap for Mapper<R> {
372 fn map(&self, code: CharCode) -> Option<CID> {
373 let find_in_chars = self.chars.iter().filter_map(|m| m.map(code));
374 let find_in_ranges = self.ranges.iter().filter_map(|m| m.map(code));
375 find_in_chars.chain(find_in_ranges).next()
376 }
377}
378
379#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
380pub struct CIDSystemInfo {
381 registry: String,
382 ordering: String,
383 supplement: u16,
384}
385
386impl CIDSystemInfo {
387 fn from_dict<P>(d: &RuntimeDictionary<'_, P>) -> MachineResult<Self> {
388 let registry = from_utf8(&d[&sname("Registry")].string()?.borrow())
389 .whatever_context("Read Registry name from utf8")?
390 .to_owned();
391 let ordering = from_utf8(&d[&sname("Ordering")].string()?.borrow())
392 .whatever_context("Read Ordering name from utf8")?
393 .to_owned();
394 let supplement = d[&sname("Supplement")]
395 .int()?
396 .try_into()
397 .whatever_context("Read Supplement name from utf8")?;
398 Ok(Self {
399 registry,
400 ordering,
401 supplement,
402 })
403 }
404}
405
406#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
407pub enum WriteMode {
408 #[default]
409 Horizontal = 0,
410 Vertical = 1,
411}
412
413impl WriteMode {
414 fn parse(v: i32) -> MachineResult<Self> {
415 match v {
416 0 => Ok(Self::Horizontal),
417 1 => Ok(Self::Vertical),
418 _ => {
419 error!("Invalid WriteMode: {}", v);
420 Err(TypeCheckSnafu.build())
421 }
422 }
423 }
424}
425
426const GB_EUC_H: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/GB-EUC-H");
427const GB_EUC_V: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/GB-EUC-V");
428const GBPC_EUC_H: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/GBpc-EUC-H");
429const GBPC_EUC_V: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/GBpc-EUC-V");
430const GBK_EUC_V: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/GBK-EUC-H");
431const GBK_EUC_H: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/GBK-EUC-V");
432const GBKP_EUC_V: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/GBKp-EUC-H");
433const GBKP_EUC_H: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/GBKp-EUC-V");
434const GBK2K_H: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/GBK2K-H");
435const GBK2K_V: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/GBK2K-V");
436const UNI_GB_GCSS_H: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/UniGB-UCS2-H");
437const UNI_GB_GCSS_V: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/UniGB-UCS2-V");
438const UNI_GB_UTF16_H: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/UniGB-UTF16-H");
439const UNI_GB_UTF16_V: &[u8] = include_bytes!("../cmap-resources/Adobe-GB1-6/CMap/UniGB-UTF16-V");
440
441const B5PC_H: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/B5pc-H");
442const B5PC_V: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/B5pc-V");
443const HKSCS_B5_H: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/HKscs-B5-H");
444const HKSCS_B5_V: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/HKscs-B5-V");
445const ETEN_B5_H: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/ETen-B5-H");
446const ETEN_B5_V: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/ETen-B5-V");
447const ETENMS_B5_H: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/ETenms-B5-H");
448const ETENMS_B5_V: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/ETenms-B5-V");
449const CNS_EUC_H: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/CNS-EUC-H");
450const CNS_EUC_V: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/CNS-EUC-V");
451const UNI_CNS_UCS2_H: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/UniCNS-UCS2-H");
452const UNI_CNS_UCS2_V: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/UniCNS-UCS2-V");
453const UNI_CNS_UTF16_H: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/UniCNS-UTF16-H");
454const UNI_CNS_UTF16_V: &[u8] = include_bytes!("../cmap-resources/Adobe-CNS1-7/CMap/UniCNS-UTF16-V");
455
456const _83PV_RKSJ_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/83pv-RKSJ-H");
457const _90MS_RKSJ_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/90ms-RKSJ-H");
458const _90MS_RKSJ_V: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/90ms-RKSJ-V");
459const _90MSP_RKSJ_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/90msp-RKSJ-H");
460const _90MSP_RKSJ_V: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/90msp-RKSJ-V");
461const _90PV_RKSJ_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/90pv-RKSJ-H");
462const ADD_RKSJ_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/Add-RKSJ-H");
463const ADD_RKSJ_V: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/Add-RKSJ-V");
464const EUC_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/EUC-H");
465const EUC_V: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/EUC-V");
466const EXT_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/Ext-RKSJ-H");
467const EXT_V: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/Ext-RKSJ-V");
468const H: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/H");
469const V: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/V");
470const UNI_JIS_UCS2_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/UniJIS-UCS2-H");
471const UNI_JIS_UCS2_V: &[u8] = include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/UniJIS-UCS2-V");
472const UNI_JIS_UCS2_HW_H: &[u8] =
473 include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/UniJIS-UCS2-HW-H");
474const UNI_JIS_UCS2_HW_V: &[u8] =
475 include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/UniJIS-UCS2-HW-V");
476const UNI_JIS_UTF16_H: &[u8] =
477 include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/UniJIS-UTF16-H");
478const UNI_JIS_UTF16_V: &[u8] =
479 include_bytes!("../cmap-resources/Adobe-Japan1-7/CMap/UniJIS-UTF16-V");
480
481const KSC_EUC_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Korea1-2/CMap/KSC-EUC-H");
482const KSC_EUC_V: &[u8] = include_bytes!("../cmap-resources/Adobe-Korea1-2/CMap/KSC-EUC-V");
483const KSCMS_UHC_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Korea1-2/CMap/KSCms-UHC-H");
484const KSCMS_UHC_V: &[u8] = include_bytes!("../cmap-resources/Adobe-Korea1-2/CMap/KSCms-UHC-V");
485const KSCMS_UHC_HW_H: &[u8] =
486 include_bytes!("../cmap-resources/Adobe-Korea1-2/CMap/KSCms-UHC-HW-H");
487const KSCMS_UHC_HW_V: &[u8] =
488 include_bytes!("../cmap-resources/Adobe-Korea1-2/CMap/KSCms-UHC-HW-V");
489const KSCPC_EUC_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Korea1-2/CMap/KSCpc-EUC-H");
490const UNI_KS_UCS2_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Korea1-2/CMap/UniKS-UCS2-H");
491const UNI_KS_UCS2_V: &[u8] = include_bytes!("../cmap-resources/Adobe-Korea1-2/CMap/UniKS-UCS2-V");
492const UNI_KS_UTF16_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Korea1-2/CMap/UniKS-UTF16-H");
493const UNI_KS_UTF16_V: &[u8] = include_bytes!("../cmap-resources/Adobe-Korea1-2/CMap/UniKS-UTF16-V");
494
495const IDENTITY_H: &[u8] = include_bytes!("../cmap-resources/Adobe-Identity-0/CMap/Identity-H");
496const IDENTITY_V: &[u8] = include_bytes!("../cmap-resources/Adobe-Identity-0/CMap/Identity-V");
497static PREDEFINED_CMAPS: phf::Map<&'static str, &'static [u8]> = phf_map! {
498 "GB-EUC-H" => GB_EUC_H,
499 "GB-EUC-V" => GB_EUC_V,
500 "GBpc-EUC-H" => GBPC_EUC_H,
501 "GBpc-EUC-V" => GBPC_EUC_V,
502 "GBK-EUC-H" => GBK_EUC_V,
503 "GBK-EUC-V" => GBK_EUC_H,
504 "GBKp-EUC-H" => GBKP_EUC_V,
505 "GBKp-EUC-V" => GBKP_EUC_H,
506 "GBK2K-H" => GBK2K_H,
507 "GBK2K-V" => GBK2K_V,
508 "UniGB-UCS2-H" => UNI_GB_GCSS_H,
509 "UniGB-UCS2-V" => UNI_GB_GCSS_V,
510 "UniGB-UTF16-H" => UNI_GB_UTF16_H,
511 "UniGB-UTF16-V" => UNI_GB_UTF16_V,
512
513 "B5pc-H" => B5PC_H,
514 "B5pc-V" => B5PC_V,
515 "HKscs-B5-H" => HKSCS_B5_H,
516 "HKscs-B5-V" => HKSCS_B5_V,
517 "ETen-B5-H" => ETEN_B5_H,
518 "ETen-B5-V" => ETEN_B5_V,
519 "ETenms-B5-H" => ETENMS_B5_H,
520 "ETenms-B5-V" => ETENMS_B5_V,
521 "CNS-EUC-H" => CNS_EUC_H,
522 "CNS-EUC-V" => CNS_EUC_V,
523 "UniCNS-UCS2-H" => UNI_CNS_UCS2_H,
524 "UniCNS-UCS2-V" => UNI_CNS_UCS2_V,
525 "UniCNS-UTF16-H" => UNI_CNS_UTF16_H,
526 "UniCNS-UTF16-V" => UNI_CNS_UTF16_V,
527
528 "83pv-RKSJ-H" => _83PV_RKSJ_H,
529 "90ms-RKSJ-H" => _90MS_RKSJ_H,
530 "90ms-RKSJ-V" => _90MS_RKSJ_V,
531 "90msp-RKSJ-H" => _90MSP_RKSJ_H,
532 "90msp-RKSJ-V" => _90MSP_RKSJ_V,
533 "90pv-RKSJ-H" => _90PV_RKSJ_H,
534 "Add-RKSJ-H" => ADD_RKSJ_H,
535 "Add-RKSJ-V" => ADD_RKSJ_V,
536 "EUC-H" => EUC_H,
537 "EUC-V" => EUC_V,
538 "Ext-RKSJ-H" => EXT_H,
539 "Ext-RKSJ-V" => EXT_V,
540 "H" => H,
541 "V" => V,
542 "UniJIS-UCS2-H" => UNI_JIS_UCS2_H,
543 "UniJIS-UCS2-V" => UNI_JIS_UCS2_V,
544 "UniJIS-UCS2-HW-H" => UNI_JIS_UCS2_HW_H,
545 "UniJIS-UCS2-HW-V" => UNI_JIS_UCS2_HW_V,
546 "UniJIS-UTF16-H" => UNI_JIS_UTF16_H,
547 "UniJIS-UTF16-V" => UNI_JIS_UTF16_V,
548
549 "KSC-EUC-H" => KSC_EUC_H,
550 "KSC-EUC-V" => KSC_EUC_V,
551 "KSCms-UHC-H" => KSCMS_UHC_H,
552 "KSCms-UHC-V" => KSCMS_UHC_V,
553 "KSCms-UHC-HW-H" => KSCMS_UHC_HW_H,
554 "KSCms-UHC-HW-V" => KSCMS_UHC_HW_V,
555 "KSCpc-EUC-H" => KSCPC_EUC_H,
556 "UniKS-UCS2-H" => UNI_KS_UCS2_H,
557 "UniKS-UCS2-V" => UNI_KS_UCS2_V,
558 "UniKS-UTF16-H" => UNI_KS_UTF16_H,
559 "UniKS-UTF16-V" => UNI_KS_UTF16_V,
560
561 "Identity-H" => IDENTITY_H,
562 "Identity-V" => IDENTITY_V,
563};
564
565#[derive(Debug)]
567pub struct CMapRegistry {
568 predefined: HashMap<&'static str, OnceCell<Rc<CMap>>>,
569 files: HashMap<Name, Rc<CMap>>,
570}
571
572impl Default for CMapRegistry {
573 fn default() -> Self {
574 Self::new()
575 }
576}
577
578impl CMapRegistry {
579 pub fn new() -> Self {
580 Self {
581 predefined: (PREDEFINED_CMAPS
582 .keys()
583 .copied()
584 .map(|k| (k, OnceCell::new())))
585 .collect(),
586 files: HashMap::new(),
587 }
588 }
589
590 pub fn add(&mut self, cmap: CMap) {
591 self.files.insert(cmap.name.clone(), Rc::new(cmap));
592 }
593
594 pub fn get(&self, name: &Name) -> Result<Option<Rc<CMap>>, MachineError> {
595 self.predefined
596 .get(name.as_str())
597 .map(|c| {
598 Ok(Rc::clone(c.get_or_try_init(|| {
599 let file = PREDEFINED_CMAPS[name.as_str()];
600 Ok(Rc::new(self.parse_cmap_file(file)?))
601 })?))
602 })
603 .or_else(|| Ok::<_, MachineError>(self.files.get(name).cloned()).transpose())
604 .transpose()
605 }
606
607 fn parse_cmap_file(&self, file: &[u8]) -> Result<CMap, MachineError> {
608 let p = CMapMachinePlugin {
609 registry: self,
610 parsed: None,
611 entries_parsing: None,
612 code_space_entries: Default::default(),
613 cid_range_entries: Default::default(),
614 cid_char_entries: Default::default(),
615 notdef_range_entries: Default::default(),
616 notdef_char_entries: Default::default(),
617 use_cmap: None,
618 };
619 let mut m = Machine::<'_, CMapMachinePlugin<'_>>::with_plugin(file, p);
620 m.execute()?;
621 let mut p = m.take_plugin();
622 p.parsed
623 .take()
624 .whatever_context("CMap not defined in cmap file")
625 }
626
627 pub fn add_cmap_file(&mut self, file: &[u8]) -> Result<Rc<CMap>> {
629 let parsed = self
630 .parse_cmap_file(file)
631 .whatever_context("parse cmap file")?;
632 let name = parsed.name.clone();
633 debug!("CMap added: {}", name);
634 self.add(parsed);
635 self.get(&name)
636 .with_whatever_context(|_| format!("get cmap: {}", name))?
637 .with_whatever_context(|| format!("CMap not found: {}", name))
638 }
639}
640
641#[derive(Debug, PartialEq, Eq)]
643pub struct CMap {
644 pub cid_system_info: CIDSystemInfo,
645 pub w_mode: WriteMode,
646 pub name: Name,
647
648 code_space: CodeSpace,
649 cid_map: Mapper<IncRangeMap>,
650 notdef_map: Mapper<RangeMapToOne>,
651 use_map: Option<Rc<CMap>>,
652}
653
654const DEFAULT_NOTDEF: CID = CID(0);
655
656impl CMap {
657 pub fn map(&self, mut codes: &[u8]) -> Result<Vec<CID>> {
661 let mut r = Vec::with_capacity(codes.len());
662 while !codes.is_empty() {
663 let code;
664 (codes, code) = self.next_cid(codes)?;
665 let cid = code.map_left(|c| self.map_undef(c)).into_inner();
666
667 r.push(cid);
668 }
669 Ok(r)
670 }
671
672 fn next_cid<'a>(&self, codes: &'a [u8]) -> Result<(&'a [u8], Either<CharCode, CID>)> {
675 let (new_codes, code) = self.code_space.next_code(codes)?;
676 let cid_or_code = code.right_and_then(|c| self.cid_map.map(c).ok_or(c).into());
677
678 let Some(use_map) = self.use_map.as_ref() else {
679 return Ok((new_codes, cid_or_code));
680 };
681
682 cid_or_code
683 .map_either(
684 |_| use_map.next_cid(codes),
685 |cid| Ok((new_codes, Either::Right(cid))),
686 )
687 .into_inner()
688 }
689
690 fn map_undef(&self, ch: CharCode) -> CID {
692 self.notdef_map.map(ch).unwrap_or_else(|| {
693 self.use_map
694 .as_ref()
695 .map_or(DEFAULT_NOTDEF, |m| m.map_undef(ch))
696 })
697 }
698}
699
700trait EntryParser<T> {
701 fn parse_entry<P>(&self, m: &mut Machine<'_, P>) -> Result<T, MachineError>;
702}
703
704struct EntriesParsing {
705 n: usize,
706}
707
708impl EntriesParsing {
709 fn new<P>(m: &mut Machine<'_, P>) -> Result<Self, MachineError> {
710 Ok(Self {
711 n: m.pop()?.int()? as usize,
712 })
713 }
714
715 fn on_end<P, EP: EntryParser<T>, T>(
716 self,
717 parser: &EP,
718 m: &mut Machine<'_, P>,
719 ) -> Result<Vec<T>, MachineError> {
720 let mut entries = Vec::with_capacity(self.n);
721 for _ in 0..self.n {
722 entries.push(parser.parse_entry(m)?);
723 }
724 entries.reverse();
725 Ok(entries)
726 }
727}
728
729#[derive(Educe)]
730#[educe(Default)]
731struct EntriesParser<T> {
732 entries: Vec<T>,
733}
734
735impl<T> EntriesParser<T> {
736 fn extend(&mut self, entries: Vec<T>) {
737 self.entries.extend(entries);
738 }
739
740 fn take(&mut self) -> Vec<T> {
741 std::mem::take(&mut self.entries)
742 }
743}
744
745struct CMapMachinePlugin<'a> {
747 registry: &'a CMapRegistry,
748 parsed: Option<CMap>,
749 use_cmap: Option<Rc<CMap>>,
750 entries_parsing: Option<EntriesParsing>,
751 code_space_entries: EntriesParser<CodeRange>,
752 cid_range_entries: EntriesParser<IncRangeMap>,
753 cid_char_entries: EntriesParser<SingleCodeMap>,
754 notdef_range_entries: EntriesParser<RangeMapToOne>,
755 notdef_char_entries: EntriesParser<SingleCodeMap>,
756}
757
758macro_rules! built_in_ops {
759 ($($k:literal => $v:expr),* $(,)?) => {
760 std::iter::Iterator::collect(std::iter::IntoIterator::into_iter([$((Key::Name(Name::from_static($k)), RuntimeValue::<'_, CMapMachinePlugin<'_>>::BuiltInOp($v)),)*]))
761 };
762}
763
764impl MachinePlugin for CMapMachinePlugin<'_> {
765 fn find_proc_set_resource<'b>(&self, name: &Name) -> Option<RuntimeDictionary<'b, Self>> {
766 (name == "CIDInit").then(|| -> HashMap<Key, RuntimeValue<'_, Self>> {
767 built_in_ops!(
768 "begincmap" => |_| {
769 ok()
770 },
771 "endcmap" => |_| {
772 ok()
773 },
774 "CMapName" => |m| {
775 let d = m.current_dict()?;
776 m.push(d.borrow().get(&sname("CMapName")).whatever_context("get CMapName")?.clone());
777 ok()
778 },
779 "begincodespacerange" => |m| {
780 m.p.entries_parsing = Some(EntriesParsing::new(m)?);
781 ok()
782 },
783 "endcodespacerange" => |m| {
784 let entries = m.p.entries_parsing.take().whatever_context("take entries_parsing")?.on_end(&CodeRangeParser, m)?;
785 m.p.code_space_entries.extend(entries);
786 ok()
787 },
788 "begincidrange" => |m| {
789 m.p.entries_parsing = Some(EntriesParsing::new(m)?);
790 ok()
791 },
792 "endcidrange" => |m| {
793 let entries = m.p.entries_parsing.take().whatever_context("take entries_parsing")?.on_end(&IncRangeMapParser, m)?;
794 m.p.cid_range_entries.extend(entries);
795 ok()
796 },
797 "beginbfrange" => |m| {
798 m.p.entries_parsing = Some(EntriesParsing::new(m)?);
799 ok()
800 },
801 "endbfrange" => |m| {
802 let entries = m.p.entries_parsing.take().whatever_context("take entries_parsing")?.on_end(&BFIncRangeMapParser, m)?;
803 m.p.cid_range_entries.extend(entries);
804 ok()
805 },
806 "begincidchar" => |m| {
807 m.p.entries_parsing = Some(EntriesParsing::new(m)?);
808 ok()
809 },
810 "endcidchar" => |m| {
811 let entries = m.p.entries_parsing.take().whatever_context("take entries_parsing")?.on_end(&SingleCodeMapParser, m)?;
812 m.p.cid_char_entries.extend(entries);
813 ok()
814 },
815 "beginbfchar" => |m| {
816 m.p.entries_parsing = Some(EntriesParsing::new(m)?);
817 ok()
818 },
819 "endbfchar" => |m| {
820 let entries = m.p.entries_parsing.take().whatever_context("take entries_parsing")?.on_end(&BFSingleCodeMapParser, m)?;
821 m.p.cid_char_entries.extend(entries);
822 ok()
823 },
824 "beginnotdefrange" => |m| {
825 m.p.entries_parsing = Some(EntriesParsing::new(m)?);
826 ok()
827 },
828 "endnotdefrange" => |m| {
829 let entries = m.p.entries_parsing.take().whatever_context("take entries_parsing")?.on_end(&RangeMapToOneParser, m)?;
830 m.p.notdef_range_entries.extend(entries);
831 ok()
832 },
833 "beginnotdefchar" => |m| {
834 m.p.entries_parsing = Some(EntriesParsing::new(m)?);
835 ok()
836 },
837 "endnotdefchar" => |m| {
838 let entries = m.p.entries_parsing.take().whatever_context("take entries_parsing")?.on_end(&SingleCodeMapParser, m)?;
839 m.p.notdef_char_entries.extend(entries);
840 ok()
841 },
842 "defineresource" => |m| {
843 let res_category = m.pop()?.name()?;
844 ensure_whatever!(res_category == sname("CMap"), "Not CMap resource");
845 let d = m.pop()?.dict()?;
846 let d_ref = d.borrow();
847 let cmap_name = m.pop()?.name()?;
848 let cmap = CMap {
849 cid_system_info: CIDSystemInfo::from_dict(&d_ref[&sname("CIDSystemInfo")].dict()?.borrow())?,
850 w_mode: WriteMode::parse(
851 d_ref.get(&sname("WMode")).map_or_else(|| Ok(0), |v| v.int()).whatever_context("get WMode")?
852 ).whatever_context("parse WMode")?,
853 name: cmap_name,
854 code_space: CodeSpace::new(m.p.code_space_entries.take()),
855 cid_map: Mapper {
856 ranges: m.p.cid_range_entries.take().into(),
857 chars: m.p.cid_char_entries.take().into(),
858 },
859 notdef_map: Mapper{
860 ranges: m.p.notdef_range_entries.take().into(),
861 chars: m.p.notdef_char_entries.take().into(),
862 },
863 use_map: m.p.use_cmap.take(),
864 };
865 m.p.parsed = Some(cmap);
866 m.push(sname("cmap stub"));
869 ok()
870 },
871 "usecmap" => |m| {
872 let name = m.pop()?.name()?;
873 let cmap = m.p.registry.get(&name).with_whatever_context(|_|format!("get cmap: {}", name))?.context(UndefinedSnafu)?;
874 m.p.use_cmap = Some(cmap);
875 ok()
876 },
877 )
878 })
879 }
880}
881
882#[cfg(test)]
883mod tests;