1 /*************************************************************************
2 ** VFReader.cpp **
3 ** **
4 ** This file is part of dvisvgm -- the DVI to SVG converter **
5 ** Copyright (C) 2005-2015 Martin Gieseking <martin.gieseking@uos.de> **
6 ** **
7 ** This program is free software; you can redistribute it and/or **
8 ** modify it under the terms of the GNU General Public License as **
9 ** published by the Free Software Foundation; either version 3 of **
10 ** the License, or (at your option) any later version. **
11 ** **
12 ** This program is distributed in the hope that it will be useful, but **
13 ** WITHOUT ANY WARRANTY; without even the implied warranty of **
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **
15 ** GNU General Public License for more details. **
16 ** **
17 ** You should have received a copy of the GNU General Public License **
18 ** along with this program; if not, see <http://www.gnu.org/licenses/>. **
19 *************************************************************************/
20
21 #include <config.h>
22 #include <sstream>
23 #include "Font.h"
24 #include "VFActions.h"
25 #include "VFReader.h"
26 #include "macros.h"
27
28 using namespace std;
29
30
31 /** Converts a TFM fix point value to double (PS point units). */
fix2double(FixWord fix)32 static inline double fix2double (FixWord fix) {
33 const double pt2bp = 72/72.27;
34 return double(fix)/(1 << 20)*pt2bp;
35 }
36
37
VFReader(istream & is)38 VFReader::VFReader (istream &is)
39 : StreamReader(is), _actions(0), _designSize(0) {
40 }
41
42
~VFReader()43 VFReader::~VFReader () {
44 }
45
46
replaceActions(VFActions * a)47 VFActions* VFReader::replaceActions (VFActions *a) {
48 VFActions *ret = _actions;
49 _actions = a;
50 return ret;
51 }
52
53
54 /** Reads a single VF command from the current position of the input stream and calls the
55 * corresponding cmdFOO method. The execution can be influenced by a function of type ApproveOpcode.
56 * It takes an opcode and returns true if the command is supposed to be executed.
57 * @param[in] approve function to approve invocation of the action assigned to command
58 * @return opcode of the executed command */
executeCommand(ApproveAction approve)59 int VFReader::executeCommand (ApproveAction approve) {
60 int opcode = readByte();
61 if (!isStreamValid() || opcode < 0) // at end of file?
62 throw VFException("invalid VF file");
63
64 bool approved = !approve || approve(opcode);
65 VFActions *actions = _actions;
66 if (!approved)
67 replaceActions(0); // disable actions
68
69 if (opcode <= 241) // short character definition?
70 cmdShortChar(opcode);
71 else if (opcode >= 243 && opcode <= 246) // font definition?
72 cmdFontDef(opcode-243+1);
73 else {
74 switch (opcode) {
75 case 242: cmdLongChar(); break; // long character definition
76 case 247: cmdPre(); break; // preamble
77 case 248: cmdPost(); break; // postamble
78 default : { // invalid opcode
79 replaceActions(actions); // reenable actions
80 ostringstream oss;
81 oss << "undefined VF command (opcode " << opcode << ')';
82 throw VFException(oss.str());
83 }
84 }
85 }
86 replaceActions(actions); // reenable actions
87 return opcode;
88 }
89
90
executeAll()91 bool VFReader::executeAll () {
92 clearStream(); // reset all status bits
93 if (!isStreamValid())
94 return false;
95 seek(0); // move file pointer to first byte of the input stream
96 while (!eof() && executeCommand() != 248); // stop reading after post (248)
97 return true;
98 }
99
100
101 /// Returns true if op indicates the preamble or a font definition
is_pre_or_fontdef(int op)102 static bool is_pre_or_fontdef (int op) {return op > 242;}
is_chardef(int op)103 static bool is_chardef (int op) {return op < 243;}
104
105
executePreambleAndFontDefs()106 bool VFReader::executePreambleAndFontDefs () {
107 clearStream();
108 if (!isStreamValid())
109 return false;
110 seek(0); // move file pointer to first byte of the input stream
111 while (!eof() && executeCommand(is_pre_or_fontdef) > 242); // stop reading after last font definition
112 return true;
113 }
114
115
executeCharDefs()116 bool VFReader::executeCharDefs () {
117 clearStream();
118 if (!isStreamValid())
119 return false;
120 seek(0);
121 while (!eof() && executeCommand(is_chardef) < 243); // stop reading after last char definition
122 return true;
123 }
124
125 //////////////////////////////////////////////////////////////////////////////
126
127 /** Reads and executes DVI preamble command. */
cmdPre()128 void VFReader::cmdPre () {
129 UInt32 i = readUnsigned(1); // identification number (should be 2)
130 UInt32 k = readUnsigned(1); // length of following comment
131 string cmt = readString(k); // comment
132 UInt32 cs = readUnsigned(4); // check sum to be compared with TFM cecksum
133 UInt32 ds = readUnsigned(4); // design size (same as TFM design size) (fix_word)
134 _designSize = fix2double(ds);
135 if (i != 202)
136 throw VFException("invalid identification value in preamble");
137 if (_actions)
138 _actions->preamble(cmt, cs, ds);
139 }
140
141
cmdPost()142 void VFReader::cmdPost () {
143 while ((readUnsigned(1)) == 248); // skip fill bytes
144 if (_actions)
145 _actions->postamble();
146 }
147
148
cmdLongChar()149 void VFReader::cmdLongChar () {
150 UInt32 pl = readUnsigned(4); // packet length (length of DVI subroutine)
151 if (!_actions)
152 seek(8+pl, ios::cur); // skip remaining char definition bytes
153 else {
154 UInt32 cc = readUnsigned(4); // character code
155 readUnsigned(4); // character width from corresponding TFM file
156 vector<UInt8> *dvi = new vector<UInt8>(pl); // DVI subroutine
157 readBytes(pl, *dvi);
158 _actions->defineVFChar(cc, dvi); // call template method for user actions
159 }
160 }
161
162
163 /** Reads and executes short_char_x command.
164 * @param[in] pl packet length (length of DVI subroutine) */
cmdShortChar(int pl)165 void VFReader::cmdShortChar (int pl) {
166 if (!_actions)
167 seek(4+pl, ios::cur); // skip char definition bytes
168 else {
169 UInt32 cc = readUnsigned(1); // character code
170 readUnsigned(3); // character width from corresponding TFM file
171 vector<UInt8> *dvi = new vector<UInt8>(pl); // DVI subroutine
172 readBytes(pl, *dvi);
173 _actions->defineVFChar(cc, dvi); // call template method for user actions
174 }
175 }
176
177
cmdFontDef(int len)178 void VFReader::cmdFontDef (int len) {
179 UInt32 fontnum = readUnsigned(len); // font number
180 UInt32 checksum = readUnsigned(4); // font checksum (to be compared with corresponding TFM checksum)
181 UInt32 ssize = readUnsigned(4); // scaled size of font relative to design size (fix_word)
182 UInt32 dsize = readUnsigned(4); // design size of font (same as TFM design size) (fix_word)
183 UInt32 pathlen = readUnsigned(1); // length of font path
184 UInt32 namelen = readUnsigned(1); // length of font name
185 string fontpath = readString(pathlen);
186 string fontname = readString(namelen);
187 if (_actions) {
188 double ss = fix2double(ssize);
189 double ds = fix2double(dsize);
190 _actions->defineVFFont(fontnum, fontpath, fontname, checksum, ds, ss*_designSize);
191 }
192 }
193