1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! The compact font format.

use std::io::{Cursor, Read, Seek};

use Result;
use tape::{Tape, Value, ValueExt};

/// A font set.
pub struct FontSet {
    pub header: Header,
    pub names: Vec<String>,
    pub top_dictionaries: Vec<Operations>,
    pub strings: Strings,
    pub global_subroutines: Subroutines,
    pub encodings: Vec<Encoding>,
    pub charsets: Vec<Charset>,
    pub charstrings: Vec<Charstrings>,
    pub private_dictionaries: Vec<Operations>,
    pub local_subroutines: Vec<Subroutines>,
}

impl FontSet {
    /// Parse a font set.
    #[inline]
    pub fn read<T: Read + Seek>(reader: &mut T) -> Result<Self> {
        Value::read(reader)
    }
}

impl Value for FontSet {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        let header = try!(Header::read(tape));
        try!(tape.jump(header.header_size as u64));
        let names = try!(try!(Names::read(tape)).into_vec());
        let top_dictionaries = try!(try!(TopDictionaries::read(tape)).into_vec());
        let strings = try!(Strings::read(tape));
        let global_subroutines = try!(Subroutines::read(tape));

        let mut encodings = vec![];
        let mut charsets = vec![];
        let mut charstrings = vec![];
        let mut private_dictionaries = vec![];
        let mut local_subroutines = vec![];
        for (i, top) in top_dictionaries.iter().enumerate() {
            encodings.push(try!(read_encoding(tape, top)));
            charstrings.push(try!(read_charstrings(tape, top)));

            let glyphs = charstrings[i].len();
            charsets.push(try!(read_charset(tape, top, glyphs)));

            private_dictionaries.push(try!(read_private_dictionary(tape, top)));

            let private = &private_dictionaries[i];
            local_subroutines.push(try!(read_local_subroutines(tape, top, private)));
        }

        Ok(FontSet {
            header: header,
            names: names,
            top_dictionaries: top_dictionaries,
            strings: strings,
            global_subroutines: global_subroutines,
            encodings: encodings,
            charsets: charsets,
            charstrings: charstrings,
            private_dictionaries: private_dictionaries,
            local_subroutines: local_subroutines,
        })
    }
}

macro_rules! get_single(
    ($operations:expr, $operator:ident) => ({
        match $operations.get_single(Operator::$operator) {
            Some(Number::Integer(value)) => value,
            _ => raise!("failed to process an operation ({})", stringify!($operator)),
        }
    });
);

macro_rules! get_double(
    ($operations:expr, $operator:ident) => (
        match $operations.get_double(Operator::$operator) {
            Some((Number::Integer(value0), Number::Integer(value1))) => (value0, value1),
            _ => raise!("failed to process an operation ({})", stringify!($operator)),
        }
    );
);

fn read_encoding<T: Tape>(_: &mut T, top: &Operations) -> Result<Encoding> {
    Ok(match get_single!(top, Encoding) {
        0 => Encoding::Standard,
        1 => Encoding::Expert,
        _ => unimplemented!(),
    })
}

fn read_charset<T: Tape>(tape: &mut T, top: &Operations, glyphs: usize) -> Result<Charset> {
    match get_single!(top, Charset) {
        0 => Ok(Charset::ISOAdobe),
        1 => Ok(Charset::Expert),
        2 => Ok(Charset::ExpertSubset),
        offset => {
            try!(tape.jump(offset as u64));
            ValueExt::read(tape, glyphs)
        },
    }
}

fn read_charstrings<T: Tape>(tape: &mut T, top: &Operations) -> Result<Charstrings> {
    try!(tape.jump(get_single!(top, Charstrings) as u64));
    ValueExt::read(tape, get_single!(top, CharstringType))
}

fn read_private_dictionary<T: Tape>(tape: &mut T, top: &Operations) -> Result<Operations> {
    let (size, offset) = get_double!(top, Private);
    try!(tape.jump(offset as u64));
    let chunk: Vec<u8> = try!(ValueExt::read(tape, size as usize));
    Value::read(&mut Cursor::new(chunk))
}

fn read_local_subroutines<T: Tape>(tape: &mut T, top: &Operations, private: &Operations)
                                   -> Result<Subroutines> {

    let (_, mut offset) = get_double!(top, Private);
    offset += get_single!(private, Subrs);
    try!(tape.jump(offset as u64));
    Value::read(tape)
}

pub mod compound;
pub mod primitive;

use self::compound::{Charset, Encoding, Header};
use self::compound::{Charstrings, Names, Strings, Subroutines, TopDictionaries};
use self::compound::{Operator, Operations};
use self::primitive::Number;