Skip to main content

read_fonts/tables/
postscript.rs

1//! PostScript (CFF and CFF2) common tables.
2
3use core::fmt;
4
5mod blend;
6mod charset;
7mod encoding;
8mod fd_select;
9mod index;
10mod stack;
11mod string;
12
13pub mod charstring;
14pub mod dict;
15pub mod font;
16
17include!("../../generated/generated_postscript.rs");
18
19pub use blend::BlendState;
20pub use charset::{Charset, CharsetIter};
21pub use encoding::PredefinedEncoding;
22pub use index::Index;
23pub use stack::{Number, Stack};
24pub use string::{Latin1String, StringId, STANDARD_STRINGS};
25
26/// Errors that are specific to PostScript processing.
27#[derive(Clone, Debug)]
28pub enum Error {
29    InvalidFontFormat,
30    InvalidIndexOffsetSize(u8),
31    ZeroOffsetInIndex,
32    InvalidVariationStoreIndex(u16),
33    StackOverflow,
34    StackUnderflow,
35    InvalidStackAccess(usize),
36    ExpectedI32StackEntry(usize),
37    InvalidNumber,
38    InvalidDictOperator(u8),
39    InvalidCharstringOperator(u8),
40    CharstringNestingDepthLimitExceeded,
41    MissingSubroutines,
42    MissingBlendState,
43    MissingFdArray,
44    MissingPrivateDict,
45    MissingCharstrings,
46    MissingCharset,
47    InvalidSeacCode(i32),
48    Read(ReadError),
49}
50
51impl From<ReadError> for Error {
52    fn from(value: ReadError) -> Self {
53        Self::Read(value)
54    }
55}
56
57impl fmt::Display for Error {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        match self {
60            Self::InvalidFontFormat => {
61                write!(f, "invalid font format")
62            }
63            Self::InvalidIndexOffsetSize(size) => {
64                write!(f, "invalid offset size of {size} for INDEX (expected 1-4)")
65            }
66            Self::ZeroOffsetInIndex => {
67                write!(f, "invalid offset of 0 in INDEX (must be >= 1)")
68            }
69            Self::InvalidVariationStoreIndex(index) => {
70                write!(
71                    f,
72                    "variation store index {index} referenced an invalid variation region"
73                )
74            }
75            Self::StackOverflow => {
76                write!(f, "attempted to push a value to a full stack")
77            }
78            Self::StackUnderflow => {
79                write!(f, "attempted to pop a value from an empty stack")
80            }
81            Self::InvalidStackAccess(index) => {
82                write!(f, "invalid stack access for index {index}")
83            }
84            Self::ExpectedI32StackEntry(index) => {
85                write!(f, "attempted to read an integer at stack index {index}, but found a fixed point value")
86            }
87            Self::InvalidNumber => {
88                write!(f, "number is in an invalid format")
89            }
90            Self::InvalidDictOperator(operator) => {
91                write!(f, "dictionary operator {operator} is invalid")
92            }
93            Self::InvalidCharstringOperator(operator) => {
94                write!(f, "charstring operator {operator} is invalid")
95            }
96            Self::CharstringNestingDepthLimitExceeded => {
97                write!(
98                    f,
99                    "exceeded subroutine nesting depth limit {} while evaluating a charstring",
100                    charstring::NESTING_DEPTH_LIMIT
101                )
102            }
103            Self::MissingSubroutines => {
104                write!(
105                    f,
106                    "encountered a callsubr operator but no subroutine index was provided"
107                )
108            }
109            Self::MissingBlendState => {
110                write!(
111                    f,
112                    "encountered a blend operator but no blend state was provided"
113                )
114            }
115            Self::MissingFdArray => {
116                write!(f, "CFF table does not contain a font dictionary index")
117            }
118            Self::MissingPrivateDict => {
119                write!(f, "CFF table does not contain a private dictionary")
120            }
121            Self::MissingCharstrings => {
122                write!(f, "CFF table does not contain a charstrings index")
123            }
124            Self::MissingCharset => {
125                write!(f, "CFF table does not contain a valid charset")
126            }
127            Self::InvalidSeacCode(code) => {
128                write!(f, "seac code {code} is not valid")
129            }
130            Self::Read(err) => write!(f, "{err}"),
131        }
132    }
133}
134
135impl core::error::Error for Error {
136    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
137        match self {
138            Self::Read(err) => Some(err),
139            _ => None,
140        }
141    }
142}