CMap
CMap parser for PDF /ToUnicode streams (ISO 32000-1 §9.10.3, Adobe Tech Note 5014).
A ToUnicode CMap is a small PostScript-ish program that tells the reader "given the source character codes I show in this content stream, here are the unicode codepoints to use when extracting/copying text." It uses these section types:
begincodespacerange … endcodespacerange : declares the valid byte patterns beginbfchar … endbfchar : <src> <utf16BE-bytes> pairs beginbfrange … endbfrange : <srcLo> <srcHi> <utf16BE-start> : <srcLo> <srcHi> [ <utf> <utf> … ] begincidchar … endcidchar : <src> cid (embedded /Encoding CMaps) begincidrange … endcidrange : <srcLo> <srcHi> cid
Source codes are 1-byte (most simple fonts), 2-byte (CIDFonts, Identity-H), or a mix (many CJK CMaps: ASCII stays 1-byte, kanji goes 2-byte). The mix is disambiguated by the codespace ranges, which give the exact byte-prefix pattern for each width (see Codespace). Destination codes in ToUnicode are UTF-16BE byte strings, possibly multi-character (ligatures) or non-BMP (surrogate pairs).
We mirror MuPDF's pdf-cmap-parse.c approach: tokenize with our regular PDF Lexer, then walk section keywords. Anything outside known sections (CIDSystemInfo, /Registry strings, etc.) is silently skipped: robustness over strictness, per the spec recommendation.
Besides ToUnicode, this class doubles as a decoder for an EMBEDDED /Encoding CMap stream on a Type 0 font: codeUnits performs codespace-correct byte segmentation and maps each code to a CID via the cidchar/cidrange sections.
Types
Properties
Maximum byte length of one source code (1–4). Inferred from codespacerange; used only as a hint / legacy accessor. Segmentation itself is driven by codespaces, not this width.
True iff this CMap carries CID mappings (embedded /Encoding), not just ToUnicode.
Functions
Segment bytes into (CID, byteOffset, byteCount) code units for use as a Type 0 /Encoding CMap. Codespace-correct: mixed 1-/2-byte streams are split by matching codespace ranges. When no cidchar/cidrange maps a code we fall back to CID == code (last resort; see PredefinedCMaps).