Skip to main content

read_fonts/ps/
string.rs

1//! String identifiers and the standard string table.
2
3/// PostScript string identifier (SID).
4#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
5pub struct Sid(u16);
6
7impl Sid {
8    /// Creates an identifier from a 16-bit unsigned integer.
9    pub const fn new(raw: u16) -> Self {
10        Self(raw)
11    }
12
13    /// Returns the underlying identifier as a 16-bit unsigned integer.
14    pub const fn to_u16(self) -> u16 {
15        self.0
16    }
17
18    /// Resolves the identifier as a standard string.
19    ///
20    /// If the identifier represents a standard string, returns `Ok(string)`,
21    /// otherwise returns `Err(index)` with the index that should be used to
22    /// retrieve the string from the CFF string INDEX.
23    ///
24    /// The standard string set is available in the section
25    /// "Appendix A - Standard Strings" at <https://adobe-type-tools.github.io/font-tech-notes/pdfs/5176.CFF.pdf>.
26    pub fn resolve_standard(self) -> Result<&'static [u8], usize> {
27        let ix = self.0 as usize;
28        if let Some(string) = STANDARD_STRINGS.get(ix) {
29            // The standard strings are all ASCII so it's safe to interpret them
30            // as Latin-1. This is verified in a unit test.
31            Ok(string.as_bytes())
32        } else {
33            Err(ix - STANDARD_STRINGS.len())
34        }
35    }
36}
37
38impl From<i32> for Sid {
39    fn from(value: i32) -> Self {
40        Self::new(value as u16)
41    }
42}
43
44/// The PostScript standard string set.
45///
46/// See "Appendix A - Standard Strings" in <https://adobe-type-tools.github.io/font-tech-notes/pdfs/5176.CFF.pdf>
47pub const STANDARD_STRINGS: &[&str] = &[
48    ".notdef",
49    "space",
50    "exclam",
51    "quotedbl",
52    "numbersign",
53    "dollar",
54    "percent",
55    "ampersand",
56    "quoteright",
57    "parenleft",
58    "parenright",
59    "asterisk",
60    "plus",
61    "comma",
62    "hyphen",
63    "period",
64    "slash",
65    "zero",
66    "one",
67    "two",
68    "three",
69    "four",
70    "five",
71    "six",
72    "seven",
73    "eight",
74    "nine",
75    "colon",
76    "semicolon",
77    "less",
78    "equal",
79    "greater",
80    "question",
81    "at",
82    "A",
83    "B",
84    "C",
85    "D",
86    "E",
87    "F",
88    "G",
89    "H",
90    "I",
91    "J",
92    "K",
93    "L",
94    "M",
95    "N",
96    "O",
97    "P",
98    "Q",
99    "R",
100    "S",
101    "T",
102    "U",
103    "V",
104    "W",
105    "X",
106    "Y",
107    "Z",
108    "bracketleft",
109    "backslash",
110    "bracketright",
111    "asciicircum",
112    "underscore",
113    "quoteleft",
114    "a",
115    "b",
116    "c",
117    "d",
118    "e",
119    "f",
120    "g",
121    "h",
122    "i",
123    "j",
124    "k",
125    "l",
126    "m",
127    "n",
128    "o",
129    "p",
130    "q",
131    "r",
132    "s",
133    "t",
134    "u",
135    "v",
136    "w",
137    "x",
138    "y",
139    "z",
140    "braceleft",
141    "bar",
142    "braceright",
143    "asciitilde",
144    "exclamdown",
145    "cent",
146    "sterling",
147    "fraction",
148    "yen",
149    "florin",
150    "section",
151    "currency",
152    "quotesingle",
153    "quotedblleft",
154    "guillemotleft",
155    "guilsinglleft",
156    "guilsinglright",
157    "fi",
158    "fl",
159    "endash",
160    "dagger",
161    "daggerdbl",
162    "periodcentered",
163    "paragraph",
164    "bullet",
165    "quotesinglbase",
166    "quotedblbase",
167    "quotedblright",
168    "guillemotright",
169    "ellipsis",
170    "perthousand",
171    "questiondown",
172    "grave",
173    "acute",
174    "circumflex",
175    "tilde",
176    "macron",
177    "breve",
178    "dotaccent",
179    "dieresis",
180    "ring",
181    "cedilla",
182    "hungarumlaut",
183    "ogonek",
184    "caron",
185    "emdash",
186    "AE",
187    "ordfeminine",
188    "Lslash",
189    "Oslash",
190    "OE",
191    "ordmasculine",
192    "ae",
193    "dotlessi",
194    "lslash",
195    "oslash",
196    "oe",
197    "germandbls",
198    "onesuperior",
199    "logicalnot",
200    "mu",
201    "trademark",
202    "Eth",
203    "onehalf",
204    "plusminus",
205    "Thorn",
206    "onequarter",
207    "divide",
208    "brokenbar",
209    "degree",
210    "thorn",
211    "threequarters",
212    "twosuperior",
213    "registered",
214    "minus",
215    "eth",
216    "multiply",
217    "threesuperior",
218    "copyright",
219    "Aacute",
220    "Acircumflex",
221    "Adieresis",
222    "Agrave",
223    "Aring",
224    "Atilde",
225    "Ccedilla",
226    "Eacute",
227    "Ecircumflex",
228    "Edieresis",
229    "Egrave",
230    "Iacute",
231    "Icircumflex",
232    "Idieresis",
233    "Igrave",
234    "Ntilde",
235    "Oacute",
236    "Ocircumflex",
237    "Odieresis",
238    "Ograve",
239    "Otilde",
240    "Scaron",
241    "Uacute",
242    "Ucircumflex",
243    "Udieresis",
244    "Ugrave",
245    "Yacute",
246    "Ydieresis",
247    "Zcaron",
248    "aacute",
249    "acircumflex",
250    "adieresis",
251    "agrave",
252    "aring",
253    "atilde",
254    "ccedilla",
255    "eacute",
256    "ecircumflex",
257    "edieresis",
258    "egrave",
259    "iacute",
260    "icircumflex",
261    "idieresis",
262    "igrave",
263    "ntilde",
264    "oacute",
265    "ocircumflex",
266    "odieresis",
267    "ograve",
268    "otilde",
269    "scaron",
270    "uacute",
271    "ucircumflex",
272    "udieresis",
273    "ugrave",
274    "yacute",
275    "ydieresis",
276    "zcaron",
277    "exclamsmall",
278    "Hungarumlautsmall",
279    "dollaroldstyle",
280    "dollarsuperior",
281    "ampersandsmall",
282    "Acutesmall",
283    "parenleftsuperior",
284    "parenrightsuperior",
285    "twodotenleader",
286    "onedotenleader",
287    "zerooldstyle",
288    "oneoldstyle",
289    "twooldstyle",
290    "threeoldstyle",
291    "fouroldstyle",
292    "fiveoldstyle",
293    "sixoldstyle",
294    "sevenoldstyle",
295    "eightoldstyle",
296    "nineoldstyle",
297    "commasuperior",
298    "threequartersemdash",
299    "periodsuperior",
300    "questionsmall",
301    "asuperior",
302    "bsuperior",
303    "centsuperior",
304    "dsuperior",
305    "esuperior",
306    "isuperior",
307    "lsuperior",
308    "msuperior",
309    "nsuperior",
310    "osuperior",
311    "rsuperior",
312    "ssuperior",
313    "tsuperior",
314    "ff",
315    "ffi",
316    "ffl",
317    "parenleftinferior",
318    "parenrightinferior",
319    "Circumflexsmall",
320    "hyphensuperior",
321    "Gravesmall",
322    "Asmall",
323    "Bsmall",
324    "Csmall",
325    "Dsmall",
326    "Esmall",
327    "Fsmall",
328    "Gsmall",
329    "Hsmall",
330    "Ismall",
331    "Jsmall",
332    "Ksmall",
333    "Lsmall",
334    "Msmall",
335    "Nsmall",
336    "Osmall",
337    "Psmall",
338    "Qsmall",
339    "Rsmall",
340    "Ssmall",
341    "Tsmall",
342    "Usmall",
343    "Vsmall",
344    "Wsmall",
345    "Xsmall",
346    "Ysmall",
347    "Zsmall",
348    "colonmonetary",
349    "onefitted",
350    "rupiah",
351    "Tildesmall",
352    "exclamdownsmall",
353    "centoldstyle",
354    "Lslashsmall",
355    "Scaronsmall",
356    "Zcaronsmall",
357    "Dieresissmall",
358    "Brevesmall",
359    "Caronsmall",
360    "Dotaccentsmall",
361    "Macronsmall",
362    "figuredash",
363    "hypheninferior",
364    "Ogoneksmall",
365    "Ringsmall",
366    "Cedillasmall",
367    "questiondownsmall",
368    "oneeighth",
369    "threeeighths",
370    "fiveeighths",
371    "seveneighths",
372    "onethird",
373    "twothirds",
374    "zerosuperior",
375    "foursuperior",
376    "fivesuperior",
377    "sixsuperior",
378    "sevensuperior",
379    "eightsuperior",
380    "ninesuperior",
381    "zeroinferior",
382    "oneinferior",
383    "twoinferior",
384    "threeinferior",
385    "fourinferior",
386    "fiveinferior",
387    "sixinferior",
388    "seveninferior",
389    "eightinferior",
390    "nineinferior",
391    "centinferior",
392    "dollarinferior",
393    "periodinferior",
394    "commainferior",
395    "Agravesmall",
396    "Aacutesmall",
397    "Acircumflexsmall",
398    "Atildesmall",
399    "Adieresissmall",
400    "Aringsmall",
401    "AEsmall",
402    "Ccedillasmall",
403    "Egravesmall",
404    "Eacutesmall",
405    "Ecircumflexsmall",
406    "Edieresissmall",
407    "Igravesmall",
408    "Iacutesmall",
409    "Icircumflexsmall",
410    "Idieresissmall",
411    "Ethsmall",
412    "Ntildesmall",
413    "Ogravesmall",
414    "Oacutesmall",
415    "Ocircumflexsmall",
416    "Otildesmall",
417    "Odieresissmall",
418    "OEsmall",
419    "Oslashsmall",
420    "Ugravesmall",
421    "Uacutesmall",
422    "Ucircumflexsmall",
423    "Udieresissmall",
424    "Yacutesmall",
425    "Thornsmall",
426    "Ydieresissmall",
427    "001.000",
428    "001.001",
429    "001.002",
430    "001.003",
431    "Black",
432    "Bold",
433    "Book",
434    "Light",
435    "Medium",
436    "Regular",
437    "Roman",
438    "Semibold",
439];
440
441#[cfg(test)]
442mod tests {
443    use super::{Sid, STANDARD_STRINGS};
444
445    #[test]
446    fn standard_strings() {
447        for (i, &std_string) in STANDARD_STRINGS.iter().enumerate() {
448            let sid = Sid::new(i as _);
449            let s = sid.resolve_standard().unwrap();
450            assert_eq!(s, std_string.as_bytes());
451        }
452    }
453
454    #[test]
455    fn not_a_standard_string() {
456        let sid = Sid::new(STANDARD_STRINGS.len() as _);
457        assert!(sid.resolve_standard().is_err());
458        assert_eq!(sid.resolve_standard().unwrap_err(), 0);
459    }
460}