postscript/compact1/font_set/
mod.rs

1//! The font sets.
2
3macro_rules! get(
4    (@single $operations:expr, $operator:ident) => (
5        match $operations.get_single(crate::compact1::Operator::$operator) {
6            Some(crate::compact1::Number::Integer(value)) => value,
7            Some(_) => raise!(concat!("found a malformed operation with operator ", stringify!($operator))),
8            _ => raise!(concat!("found no operation with operator ", stringify!($operator))),
9        }
10    );
11    (@try @single $operations:expr, $operator:ident) => (
12        match $operations.get_single(crate::compact1::Operator::$operator) {
13            Some(crate::compact1::Number::Integer(value)) => Some(value),
14            Some(_) => raise!(concat!("found a malformed operation with operator ", stringify!($operator))),
15            _ => None,
16        }
17    );
18    (@double $operations:expr, $operator:ident) => (
19        match $operations.get_double(crate::compact1::Operator::$operator) {
20            Some((crate::compact1::Number::Integer(value0), crate::compact1::Number::Integer(value1))) => (value0, value1),
21            Some(_) => raise!(concat!("found a malformed operation with operator ", stringify!($operator))),
22            _ => raise!(concat!("found no operation with operator ", stringify!($operator))),
23        }
24    );
25);
26
27pub mod character_id_keyed;
28pub mod character_name_keyed;
29
30use crate::compact1::index::{CharacterStrings, Dictionaries, Names, Strings, Subroutines};
31use crate::compact1::{CharacterSet, Encoding, Header, Operations, Operator};
32use crate::Result;
33
34/// A font set.
35#[derive(Clone, Debug)]
36pub struct FontSet {
37    pub header: Header,
38    pub names: Names,
39    pub operations: Vec<Operations>,
40    pub strings: Strings,
41    pub subroutines: Subroutines,
42    pub encodings: Vec<Encoding>,
43    pub character_strings: Vec<CharacterStrings>,
44    pub character_sets: Vec<CharacterSet>,
45    pub records: Vec<Record>,
46}
47
48/// A record in a font set.
49#[derive(Clone, Debug)]
50pub enum Record {
51    CharacterIDKeyed(character_id_keyed::Record),
52    CharacterNameKeyed(character_name_keyed::Record),
53}
54
55impl FontSet {
56    /// Count the number of records.
57    pub fn count<T: crate::tape::Read>(tape: &mut T) -> Result<usize> {
58        let position = tape.position()?;
59        let header = tape.take::<Header>()?;
60        let count: u16 = jump_take!(@unwrap tape, position, header.header_size);
61        Ok(count as usize)
62    }
63}
64
65impl crate::value::Read for FontSet {
66    fn read<T: crate::tape::Read>(tape: &mut T) -> Result<Self> {
67        let position = tape.position()?;
68        let header = tape.take::<Header>()?;
69        let names: Names = jump_take!(@unwrap tape, position, header.header_size);
70        let operations: Vec<_> = (&tape.take::<Dictionaries>()?).try_into()?;
71        let strings = tape.take::<Strings>()?;
72        let subroutines = tape.take::<Subroutines>()?;
73        let mut encodings = vec![];
74        let mut character_sets = vec![];
75        let mut character_strings: Vec<CharacterStrings> = vec![];
76        let mut records = vec![];
77        for (i, operations) in operations.iter().enumerate() {
78            character_strings.push(jump_take_given!(
79                @unwrap
80                tape,
81                position,
82                get!(@single operations, CharStrings),
83                get!(@single operations, CharStringType)
84            ));
85            character_sets.push(match get!(@single operations, CharSet) {
86                0 => CharacterSet::ISOAdobe,
87                1 => CharacterSet::Expert,
88                2 => CharacterSet::ExpertSubset,
89                offset => jump_take_given!(
90                    @unwrap
91                    tape,
92                    position,
93                    offset,
94                    character_strings[i].count as usize
95                ),
96            });
97            encodings.push(match get!(@single operations, Encoding) {
98                0 => Encoding::Standard,
99                1 => Encoding::Expert,
100                offset => jump_take!(@unwrap tape, position, offset),
101            });
102            records.push(tape.take_given((position, operations, &character_strings[i]))?);
103        }
104        Ok(Self {
105            header,
106            names,
107            operations,
108            strings,
109            subroutines,
110            encodings,
111            character_strings,
112            character_sets,
113            records,
114        })
115    }
116}
117
118impl<'l> crate::walue::Read<'l> for Record {
119    type Parameter = (u64, &'l Operations, &'l CharacterStrings);
120
121    fn read<T: crate::tape::Read>(
122        tape: &mut T,
123        (position, operations, character_strings): Self::Parameter,
124    ) -> Result<Self> {
125        if operations.contains_key(&Operator::ROS) {
126            Ok(Record::CharacterIDKeyed(tape.take_given((
127                position,
128                operations,
129                character_strings,
130            ))?))
131        } else {
132            Ok(Record::CharacterNameKeyed(
133                tape.take_given((position, operations))?,
134            ))
135        }
136    }
137}