1
/*************************************************************************
4
** This file is part of dvisvgm -- the DVI to SVG converter **
5
** Copyright (C) 2005-2014 Martin Gieseking <martin.gieseking@uos.de> **
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. **
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. **
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
*************************************************************************/
26
#include "SignalHandler.h"
32
void (GFReader::*method)(int);
37
static inline double fix2double (Int32 fix) {
38
return double(fix)/(1 << 20)*72/72.27;
42
static inline double scaled2double (Int32 scaled) {
43
return double(scaled)/(1 << 16);
47
GFReader::GFReader (istream &is) : _in(is), _penDown(false)
49
_minX = _maxX = _minY = _maxY = _x = _y = 0;
57
UInt32 GFReader::readUnsigned (int bytes) {
59
for (int i=bytes-1; i >= 0 && !_in.eof(); i--) {
67
Int32 GFReader::readSigned (int bytes) {
68
Int32 ret = _in.get();
69
if (ret & 128) // negative value?
71
for (int i=bytes-2; i >= 0 && !_in.eof(); i--)
72
ret = (ret << 8) | _in.get();
77
string GFReader::readString (int bytes) {
78
vector<char> buf(bytes+1);
80
_in.get(&buf[0], bytes+1); // reads 'bytes' bytes (pos. bytes+1 is set to 0)
87
/** Reads a single GF command from the current position of the input stream and calls the
88
* corresponding cmdFOO method.
89
* @return opcode of the executed command */
90
int GFReader::executeCommand () {
91
SignalHandler::instance().check();
92
/* Each cmdFOO command reads the necessary number of bytes from the stream so executeCommand
93
doesn't need to know the exact GF command format. Some cmdFOO methods are used for multiple
94
GF commands because they only differ in the size of their parameters. */
95
static const GFCommand commands[] = {
96
{&GFReader::cmdPaint, 1}, {&GFReader::cmdPaint, 2}, {&GFReader::cmdPaint, 3}, // 64-66
97
{&GFReader::cmdBoc, 0}, {&GFReader::cmdBoc1, 0}, // 67-68
98
{&GFReader::cmdEoc, 0}, // 69
99
{&GFReader::cmdSkip, 0}, {&GFReader::cmdSkip, 1}, {&GFReader::cmdSkip, 2},{&GFReader::cmdSkip, 3}, // 70-73
100
{&GFReader::cmdXXX, 1}, {&GFReader::cmdXXX, 2}, {&GFReader::cmdXXX, 3}, {&GFReader::cmdXXX, 4}, // 239-242
101
{&GFReader::cmdYYY, 0}, // 243
102
{&GFReader::cmdNop, 0}, // 244
103
{&GFReader::cmdCharLoc, 0}, {&GFReader::cmdCharLoc0, 0}, // 245-246
104
{&GFReader::cmdPre, 0}, {&GFReader::cmdPost, 0}, {&GFReader::cmdPostPost, 0} // 247-249
107
int opcode = _in.get();
108
if (opcode < 0) // at end of file?
109
throw GFException("unexpected end of file");
111
if (opcode >= 0 && opcode <= 63)
113
else if (opcode >= 74 && opcode <= 238)
114
cmdNewRow(opcode-74);
115
else if (opcode >= 250) {
117
oss << "undefined GF command (opcode " << opcode << ")";
118
throw GFException(oss.str());
121
int offset = opcode <= 73 ? 64 : 239-(73-64+1);
122
const GFCommand &cmd = commands[opcode-offset];
124
(this->*cmd.method)(cmd.numBytes);
130
bool GFReader::executeChar (UInt8 c) {
132
if (_charInfoMap.empty())
133
executePostamble(); // read character info
135
Iterator it = _charInfoMap.find(c);
136
if (_in && it != _charInfoMap.end()) {
137
_in.seekg(it->second.location);
138
while (executeCommand() != 69); // execute all commands until eoc is reached
145
bool GFReader::executeAllChars () {
147
if (_charInfoMap.empty())
148
executePostamble(); // read character info
152
while (executeCommand() != 248); // execute all commands until postamble is reached
159
bool GFReader::executePostamble () {
163
_in.seekg(-1, ios_base::end);
164
while (_in.peek() == 223) // skip fill bytes
165
_in.seekg(-1, ios_base::cur);
166
_in.seekg(-4, ios_base::cur);
167
UInt32 q = readUnsigned(4); // pointer to begin of postamble
168
_in.seekg(q); // now on begin of postamble
169
while (executeCommand() != 249); // execute all commands until postpost is reached
174
/** Returns the design size of this font int PS point units. */
175
double GFReader::getDesignSize () const {
176
return fix2double(_designSize);
179
/** Returns the number of horizontal pixels per point. */
180
double GFReader::getHPixelsPerPoint () const {
181
return scaled2double(_hppp)*72/72.27;
184
/** Returns the number of vertical pixels per point. */
185
double GFReader::getVPixelsPerPoint () const {
186
return scaled2double(_vppp)*72/72.27;
189
/** Returns the width of character c in PS point units */
190
double GFReader::getCharWidth (UInt32 c) const {
191
ConstIterator it = _charInfoMap.find(c%256);
192
return it == _charInfoMap.end() ? 0 : it->second.width*getDesignSize()/(1<<24);
195
///////////////////////
198
/** Reads the preamble. */
199
void GFReader::cmdPre (int) {
200
UInt32 i = readUnsigned(1);
202
UInt32 k = readUnsigned(1);
203
string s = readString(k);
207
throw GFException("invalid identification number in GF preamble");
211
/** Reads the postamble. */
212
void GFReader::cmdPost (int) {
213
readUnsigned(4); // pointer to byte after final eoc
214
_designSize = readUnsigned(4); // design size of font in points
215
_checksum = readUnsigned(4); // checksum
216
_hppp = readUnsigned(4); // horizontal pixels per point (scaled int)
217
_vppp = readUnsigned(4); // vertical pixels per point (scaled int)
218
_in.seekg(16, ios_base::cur); // skip x and y bounds
223
/** Reads trailing bytes at end of stream. */
224
void GFReader::cmdPostPost (int) {
225
readUnsigned(4); // pointer to begin of postamble
226
UInt32 i = readUnsigned(1);
228
while (readUnsigned(1) == 223); // skip fill bytes
230
throw GFException("invalid identification number in GF preamble");
234
/** Inverts "paint color" (black to white or vice versa) of n pixels
235
* and advances the cursor by n.
236
* @param[in] n number of pixels to be inverted */
237
void GFReader::cmdPaint0 (int n) {
238
if (_penDown) // set pixels?
239
_bitmap.setBits(_y, _x, n);
241
_penDown = !_penDown; // inverse pen state
245
/** Inverts "paint color" (black to white or vice versa) of n pixels
246
* and advances the cursor by n. The number n of pixels is read from
248
* @param[in] len size of n in bytes */
249
void GFReader::cmdPaint (int len) {
250
UInt32 pixels = readUnsigned(len);
255
/** Beginning of character (generic format). */
256
void GFReader::cmdBoc (int) {
257
_currentChar = readSigned(4);
258
readSigned(4); // pointer to previous boc with same c mod 256
259
_minX = readSigned(4);
260
_maxX = readSigned(4);
261
_minY = readSigned(4);
262
_maxY = readSigned(4);
266
_bitmap.resize(_minX, _maxX, _minY, _maxY);
267
beginChar(_currentChar);
271
/** Beginning of character (compact format). */
272
void GFReader::cmdBoc1 (int) {
273
_currentChar = readUnsigned(1);
274
UInt32 dx = readUnsigned(1);
275
_maxX = readUnsigned(1);
277
UInt32 dy = readUnsigned(1);
278
_maxY = readUnsigned(1);
283
_bitmap.resize(_minX, _maxX, _minY, _maxY);
284
beginChar(_currentChar);
288
/** End of character. */
289
void GFReader::cmdEoc (int) {
290
endChar(_currentChar);
294
/** Moves cursor to the beginning of a following row and sets
295
* paint color to white.
296
* @param[in] len if 0: move to next row, otherwise: number of bytes to read.
297
* The read value denotes the number of rows to be skipped. */
298
void GFReader::cmdSkip (int len) {
302
_y -= readUnsigned(len)+1;
308
/** Moves cursor to pixel number 'col' in the next row and sets
309
* the paint color to black.
310
* @param[in] col pixel/column number */
311
void GFReader::cmdNewRow (int col) {
318
void GFReader::cmdXXX (int len) {
319
UInt32 n = readUnsigned(len);
320
string str = readString(n);
325
void GFReader::cmdYYY (int) {
326
Int32 y = readSigned(4);
332
void GFReader::cmdNop (int) {
336
/** Reads character locator (part of postamble) */
337
void GFReader::cmdCharLoc0 (int) {
338
UInt8 c = readUnsigned(1); // character code mod 256
339
UInt8 dm = readUnsigned(1); //
340
Int32 w = readSigned(4); // (1<<24)*characterWidth/designSize
341
Int32 p = readSigned(4); // pointer to begin of (last) character data
344
_charInfoMap[c] = CharInfo(dx, dy, w, p);
348
/** Reads character locator (part of postamble) */
349
void GFReader::cmdCharLoc (int) {
350
UInt32 c = readUnsigned(1); // character code mod 256
351
Int32 dx = readSigned(4); // horizontal escapement (scaled pixel units)
352
Int32 dy = readSigned(4); // vertical escapement (scaled pixel units)
353
Int32 w = readSigned(4); // (1<<24)*characterWidth/designSize
354
Int32 p = readSigned(4); // pointer to begin of (last) character data
355
_charInfoMap[c] = CharInfo(dx, dy, w, p);