//
// Array.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stddef.h>
#include "gmem.h"
#include "Object.h"
// Array
//------------------------------------------------------------------------
-Array::Array() {
+Array::Array(XRef *xrefA) {
+ xref = xrefA;
elems = NULL;
size = length = 0;
ref = 1;
}
Object *Array::get(int i, Object *obj) {
- return elems[i].fetch(obj);
+ return elems[i].fetch(xref, obj);
}
Object *Array::getNF(int i, Object *obj) {
//
// Array.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#include "Object.h"
+class XRef;
+
//------------------------------------------------------------------------
// Array
//------------------------------------------------------------------------
public:
// Constructor.
- Array();
+ Array(XRef *xrefA);
// Destructor.
~Array();
private:
+ XRef *xref; // the xref table for this PDF file
Object *elems; // array of elements
int size; // size of <elems> array
int length; // number of elements in array
//
// Catalog.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stddef.h>
#include "gmem.h"
#include "Object.h"
+#include "XRef.h"
#include "Array.h"
#include "Dict.h"
#include "Page.h"
// Catalog
//------------------------------------------------------------------------
-Catalog::Catalog(Object *catDict) {
- Object pagesDict;
+Catalog::Catalog(XRef *xrefA, GBool printCommands) {
+ Object catDict, pagesDict;
Object obj, obj2;
int numPages0;
int i;
ok = gTrue;
+ xref = xrefA;
pages = NULL;
pageRefs = NULL;
numPages = pagesSize = 0;
+ baseURI = NULL;
- if (!catDict->isDict()) {
- error(-1, "Catalog object is wrong type (%s)", catDict->getTypeName());
+ xref->getCatalog(&catDict);
+ if (!catDict.isDict()) {
+ error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName());
goto err1;
}
// read page tree
- catDict->dictLookup("Pages", &pagesDict);
+ catDict.dictLookup("Pages", &pagesDict);
// This should really be isDict("Pages"), but I've seen at least one
// PDF file where the /Type entry is missing.
if (!pagesDict.isDict()) {
pageRefs[i].num = -1;
pageRefs[i].gen = -1;
}
- numPages = readPageTree(pagesDict.getDict(), NULL, 0);
+ numPages = readPageTree(pagesDict.getDict(), NULL, 0, printCommands);
if (numPages != numPages0) {
error(-1, "Page count in top-level pages object is incorrect");
}
pagesDict.free();
// read named destination dictionary
- catDict->dictLookup("Dests", &dests);
+ catDict.dictLookup("Dests", &dests);
// read root of named destination tree
- if (catDict->dictLookup("Names", &obj)->isDict())
+ if (catDict.dictLookup("Names", &obj)->isDict())
obj.dictLookup("Dests", &nameTree);
else
nameTree.initNull();
obj.free();
// read base URI
- baseURI = NULL;
- if (catDict->dictLookup("URI", &obj)->isDict()) {
+ if (catDict.dictLookup("URI", &obj)->isDict()) {
if (obj.dictLookup("Base", &obj2)->isString()) {
baseURI = obj2.getString()->copy();
}
}
obj.free();
+ // get the metadata stream
+ catDict.dictLookup("Metadata", &metadata);
+
+ // get the structure tree root
+ catDict.dictLookup("StructTreeRoot", &structTreeRoot);
+
+ catDict.free();
return;
err3:
err2:
pagesDict.free();
err1:
+ catDict.free();
dests.initNull();
nameTree.initNull();
ok = gFalse;
if (baseURI) {
delete baseURI;
}
+ metadata.free();
+ structTreeRoot.free();
+}
+
+GString *Catalog::readMetadata() {
+ GString *s;
+ Dict *dict;
+ Object obj;
+ int c;
+
+ if (!metadata.isStream()) {
+ return NULL;
+ }
+ dict = metadata.streamGetDict();
+ if (!dict->lookup("Subtype", &obj)->isName("XML")) {
+ error(-1, "Unknown Metadata type: '%s'",
+ obj.isName() ? obj.getName() : "???");
+ }
+ obj.free();
+ s = new GString();
+ metadata.streamReset();
+ while ((c = metadata.streamGetChar()) != EOF) {
+ s->append(c);
+ }
+ metadata.streamClose();
+ return s;
}
-int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
+int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start,
+ GBool printCommands) {
Object kids;
Object kid;
Object kidRef;
kids.arrayGet(i, &kid);
if (kid.isDict("Page")) {
attrs2 = new PageAttrs(attrs1, kid.getDict());
- page = new Page(start+1, kid.getDict(), attrs2);
+ page = new Page(xref, start+1, kid.getDict(), attrs2, printCommands);
if (!page->isOk()) {
++start;
goto err3;
// This should really be isDict("Pages"), but I've seen at least one
// PDF file where the /Type entry is missing.
} else if (kid.isDict()) {
- if ((start = readPageTree(kid.getDict(), attrs1, start)) < 0)
+ if ((start = readPageTree(kid.getDict(), attrs1, start, printCommands))
+ < 0)
goto err2;
} else {
error(-1, "Kid object (page %d) is wrong type (%s)",
// construct LinkDest
dest = NULL;
if (obj1.isArray()) {
- dest = new LinkDest(obj1.getArray(), gTrue);
+ dest = new LinkDest(obj1.getArray());
} else if (obj1.isDict()) {
if (obj1.dictLookup("D", &obj2)->isArray())
- dest = new LinkDest(obj2.getArray(), gTrue);
+ dest = new LinkDest(obj2.getArray());
else
error(-1, "Bad named destination value");
obj2.free();
//
// Catalog.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma interface
#endif
+class XRef;
class Object;
class Page;
class PageAttrs;
public:
// Constructor.
- Catalog(Object *catDict);
+ Catalog(XRef *xrefA, GBool printCommands = gFalse);
// Destructor.
~Catalog();
// Return base URI, or NULL if none.
GString *getBaseURI() { return baseURI; }
+ // Return the contents of the metadata stream, or NULL if there is
+ // no metadata.
+ GString *readMetadata();
+
+ // Return the structure tree root object.
+ Object *getStructTreeRoot() { return &structTreeRoot; }
+
// Find a page, given its object ID. Returns page number, or 0 if
// not found.
int findPage(int num, int gen);
private:
+ XRef *xref; // the xref table for this PDF file
Page **pages; // array of pages
Ref *pageRefs; // object ID for each page
int numPages; // number of pages
Object dests; // named destination dictionary
Object nameTree; // name tree
GString *baseURI; // base URI for URI-type links
+ Object metadata; // metadata stream
+ Object structTreeRoot; // structure tree root dictionary
GBool ok; // true if catalog is valid
- int readPageTree(Dict *pages, PageAttrs *attrs, int start);
+ int readPageTree(Dict *pages, PageAttrs *attrs, int start,
+ GBool printCommands);
Object *findDestInTree(Object *tree, GString *name, Object *obj);
};
+++ /dev/null
-//========================================================================
-//
-// CompactFontInfo.h
-//
-// Copyright 1999 Derek B. Noonburg
-//
-//========================================================================
-
-#ifndef COMPACTFONTINFO_H
-#define COMPACTFONTINFO_H
-
-static char *type1CStdStrings[391] = {
- ".notdef",
- "space",
- "exclam",
- "quotedbl",
- "numbersign",
- "dollar",
- "percent",
- "ampersand",
- "quoteright",
- "parenleft",
- "parenright",
- "asterisk",
- "plus",
- "comma",
- "hyphen",
- "period",
- "slash",
- "zero",
- "one",
- "two",
- "three",
- "four",
- "five",
- "six",
- "seven",
- "eight",
- "nine",
- "colon",
- "semicolon",
- "less",
- "equal",
- "greater",
- "question",
- "at",
- "A",
- "B",
- "C",
- "D",
- "E",
- "F",
- "G",
- "H",
- "I",
- "J",
- "K",
- "L",
- "M",
- "N",
- "O",
- "P",
- "Q",
- "R",
- "S",
- "T",
- "U",
- "V",
- "W",
- "X",
- "Y",
- "Z",
- "bracketleft",
- "backslash",
- "bracketright",
- "asciicircum",
- "underscore",
- "quoteleft",
- "a",
- "b",
- "c",
- "d",
- "e",
- "f",
- "g",
- "h",
- "i",
- "j",
- "k",
- "l",
- "m",
- "n",
- "o",
- "p",
- "q",
- "r",
- "s",
- "t",
- "u",
- "v",
- "w",
- "x",
- "y",
- "z",
- "braceleft",
- "bar",
- "braceright",
- "asciitilde",
- "exclamdown",
- "cent",
- "sterling",
- "fraction",
- "yen",
- "florin",
- "section",
- "currency",
- "quotesingle",
- "quotedblleft",
- "guillemotleft",
- "guilsinglleft",
- "guilsinglright",
- "fi",
- "fl",
- "endash",
- "dagger",
- "daggerdbl",
- "periodcentered",
- "paragraph",
- "bullet",
- "quotesinglbase",
- "quotedblbase",
- "quotedblright",
- "guillemotright",
- "ellipsis",
- "perthousand",
- "questiondown",
- "grave",
- "acute",
- "circumflex",
- "tilde",
- "macron",
- "breve",
- "dotaccent",
- "dieresis",
- "ring",
- "cedilla",
- "hungarumlaut",
- "ogonek",
- "caron",
- "emdash",
- "AE",
- "ordfeminine",
- "Lslash",
- "Oslash",
- "OE",
- "ordmasculine",
- "ae",
- "dotlessi",
- "lslash",
- "oslash",
- "oe",
- "germandbls",
- "onesuperior",
- "logicalnot",
- "mu",
- "trademark",
- "Eth",
- "onehalf",
- "plusminus",
- "Thorn",
- "onequarter",
- "divide",
- "brokenbar",
- "degree",
- "thorn",
- "threequarters",
- "twosuperior",
- "registered",
- "minus",
- "eth",
- "multiply",
- "threesuperior",
- "copyright",
- "Aacute",
- "Acircumflex",
- "Adieresis",
- "Agrave",
- "Aring",
- "Atilde",
- "Ccedilla",
- "Eacute",
- "Ecircumflex",
- "Edieresis",
- "Egrave",
- "Iacute",
- "Icircumflex",
- "Idieresis",
- "Igrave",
- "Ntilde",
- "Oacute",
- "Ocircumflex",
- "Odieresis",
- "Ograve",
- "Otilde",
- "Scaron",
- "Uacute",
- "Ucircumflex",
- "Udieresis",
- "Ugrave",
- "Yacute",
- "Ydieresis",
- "Zcaron",
- "aacute",
- "acircumflex",
- "adieresis",
- "agrave",
- "aring",
- "atilde",
- "ccedilla",
- "eacute",
- "ecircumflex",
- "edieresis",
- "egrave",
- "iacute",
- "icircumflex",
- "idieresis",
- "igrave",
- "ntilde",
- "oacute",
- "ocircumflex",
- "odieresis",
- "ograve",
- "otilde",
- "scaron",
- "uacute",
- "ucircumflex",
- "udieresis",
- "ugrave",
- "yacute",
- "ydieresis",
- "zcaron",
- "exclamsmall",
- "Hungarumlautsmall",
- "dollaroldstyle",
- "dollarsuperior",
- "ampersandsmall",
- "Acutesmall",
- "parenleftsuperior",
- "parenrightsuperior",
- "twodotenleader",
- "onedotenleader",
- "zerooldstyle",
- "oneoldstyle",
- "twooldstyle",
- "threeoldstyle",
- "fouroldstyle",
- "fiveoldstyle",
- "sixoldstyle",
- "sevenoldstyle",
- "eightoldstyle",
- "nineoldstyle",
- "commasuperior",
- "threequartersemdash",
- "periodsuperior",
- "questionsmall",
- "asuperior",
- "bsuperior",
- "centsuperior",
- "dsuperior",
- "esuperior",
- "isuperior",
- "lsuperior",
- "msuperior",
- "nsuperior",
- "osuperior",
- "rsuperior",
- "ssuperior",
- "tsuperior",
- "ff",
- "ffi",
- "ffl",
- "parenleftinferior",
- "parenrightinferior",
- "Circumflexsmall",
- "hyphensuperior",
- "Gravesmall",
- "Asmall",
- "Bsmall",
- "Csmall",
- "Dsmall",
- "Esmall",
- "Fsmall",
- "Gsmall",
- "Hsmall",
- "Ismall",
- "Jsmall",
- "Ksmall",
- "Lsmall",
- "Msmall",
- "Nsmall",
- "Osmall",
- "Psmall",
- "Qsmall",
- "Rsmall",
- "Ssmall",
- "Tsmall",
- "Usmall",
- "Vsmall",
- "Wsmall",
- "Xsmall",
- "Ysmall",
- "Zsmall",
- "colonmonetary",
- "onefitted",
- "rupiah",
- "Tildesmall",
- "exclamdownsmall",
- "centoldstyle",
- "Lslashsmall",
- "Scaronsmall",
- "Zcaronsmall",
- "Dieresissmall",
- "Brevesmall",
- "Caronsmall",
- "Dotaccentsmall",
- "Macronsmall",
- "figuredash",
- "hypheninferior",
- "Ogoneksmall",
- "Ringsmall",
- "Cedillasmall",
- "questiondownsmall",
- "oneeighth",
- "threeeighths",
- "fiveeighths",
- "seveneighths",
- "onethird",
- "twothirds",
- "zerosuperior",
- "foursuperior",
- "fivesuperior",
- "sixsuperior",
- "sevensuperior",
- "eightsuperior",
- "ninesuperior",
- "zeroinferior",
- "oneinferior",
- "twoinferior",
- "threeinferior",
- "fourinferior",
- "fiveinferior",
- "sixinferior",
- "seveninferior",
- "eightinferior",
- "nineinferior",
- "centinferior",
- "dollarinferior",
- "periodinferior",
- "commainferior",
- "Agravesmall",
- "Aacutesmall",
- "Acircumflexsmall",
- "Atildesmall",
- "Adieresissmall",
- "Aringsmall",
- "AEsmall",
- "Ccedillasmall",
- "Egravesmall",
- "Eacutesmall",
- "Ecircumflexsmall",
- "Edieresissmall",
- "Igravesmall",
- "Iacutesmall",
- "Icircumflexsmall",
- "Idieresissmall",
- "Ethsmall",
- "Ntildesmall",
- "Ogravesmall",
- "Oacutesmall",
- "Ocircumflexsmall",
- "Otildesmall",
- "Odieresissmall",
- "OEsmall",
- "Oslashsmall",
- "Ugravesmall",
- "Uacutesmall",
- "Ucircumflexsmall",
- "Udieresissmall",
- "Yacutesmall",
- "Thornsmall",
- "Ydieresissmall",
- "001.000",
- "001.001",
- "001.002",
- "001.003",
- "Black",
- "Bold",
- "Book",
- "Light",
- "Medium",
- "Regular",
- "Roman",
- "Semibold"
-};
-
-static Gushort type1CISOAdobeCharset[229] = {
- 0, 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, 138, 139,
- 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
- 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
- 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
- 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
- 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
- 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
- 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
- 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
- 220, 221, 222, 223, 224, 225, 226, 227, 228
-};
-
-static Gushort type1CExpertCharset[166] = {
- 0, 1, 229, 230, 231, 232, 233, 234, 235, 236,
- 237, 238, 13, 14, 15, 99, 239, 240, 241, 242,
- 243, 244, 245, 246, 247, 248, 27, 28, 249, 250,
- 251, 252, 253, 254, 255, 256, 257, 258, 259, 260,
- 261, 262, 263, 264, 265, 266, 109, 110, 267, 268,
- 269, 270, 271, 272, 273, 274, 275, 276, 277, 278,
- 279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
- 289, 290, 291, 292, 293, 294, 295, 296, 297, 298,
- 299, 300, 301, 302, 303, 304, 305, 306, 307, 308,
- 309, 310, 311, 312, 313, 314, 315, 316, 317, 318,
- 158, 155, 163, 319, 320, 321, 322, 323, 324, 325,
- 326, 150, 164, 169, 327, 328, 329, 330, 331, 332,
- 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
- 343, 344, 345, 346, 347, 348, 349, 350, 351, 352,
- 353, 354, 355, 356, 357, 358, 359, 360, 361, 362,
- 363, 364, 365, 366, 367, 368, 369, 370, 371, 372,
- 373, 374, 375, 376, 377, 378
-};
-
-static Gushort type1CExpertSubsetCharset[87] = {
- 0, 1, 231, 232, 235, 236, 237, 238, 13, 14,
- 15, 99, 239, 240, 241, 242, 243, 244, 245, 246,
- 247, 248, 27, 28, 249, 250, 251, 253, 254, 255,
- 256, 257, 258, 259, 260, 261, 262, 263, 264, 265,
- 266, 109, 110, 267, 268, 269, 270, 272, 300, 301,
- 302, 305, 314, 315, 158, 155, 163, 320, 321, 322,
- 323, 324, 325, 326, 150, 164, 169, 327, 328, 329,
- 330, 331, 332, 333, 334, 335, 336, 337, 338, 339,
- 340, 341, 342, 343, 344, 345, 346
-};
-
-#endif
//
// Decrypt.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include "gmem.h"
#include "Decrypt.h"
// Decrypt
//------------------------------------------------------------------------
-Decrypt::Decrypt(Guchar *fileKey, int objNum, int objGen) {
+Decrypt::Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen) {
+ int i;
+
// construct object key
- objKey[0] = fileKey[0];
- objKey[1] = fileKey[1];
- objKey[2] = fileKey[2];
- objKey[3] = fileKey[3];
- objKey[4] = fileKey[4];
- objKey[5] = objNum & 0xff;
- objKey[6] = (objNum >> 8) & 0xff;
- objKey[7] = (objNum >> 16) & 0xff;
- objKey[8] = objGen & 0xff;
- objKey[9] = (objGen >> 8) & 0xff;
- md5(objKey, 10, objKey);
+ for (i = 0; i < keyLength; ++i) {
+ objKey[i] = fileKey[i];
+ }
+ objKey[keyLength] = objNum & 0xff;
+ objKey[keyLength + 1] = (objNum >> 8) & 0xff;
+ objKey[keyLength + 2] = (objNum >> 16) & 0xff;
+ objKey[keyLength + 3] = objGen & 0xff;
+ objKey[keyLength + 4] = (objGen >> 8) & 0xff;
+ md5(objKey, keyLength + 5, objKey);
// set up for decryption
x = y = 0;
- rc4InitKey(objKey, 10, state);
+ if ((objKeyLength = keyLength + 5) > 16) {
+ objKeyLength = 16;
+ }
+ rc4InitKey(objKey, objKeyLength, state);
}
void Decrypt::reset() {
x = y = 0;
- rc4InitKey(objKey, 10, state);
+ rc4InitKey(objKey, objKeyLength, state);
}
Guchar Decrypt::decryptByte(Guchar c) {
return rc4DecryptByte(state, &x, &y, c);
}
-GBool Decrypt::makeFileKey(GString *ownerKey, GString *userKey,
+GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
int permissions, GString *fileID,
- GString *userPassword, Guchar *fileKey) {
- Guchar *buf;
- Guchar userTest[32];
+ GString *ownerPassword, GString *userPassword,
+ Guchar *fileKey, GBool *ownerPasswordOk) {
+ Guchar test[32];
+ GString *userPassword2;
Guchar fState[256];
Guchar fx, fy;
int len, i;
+
+ // try using the supplied owner password to generate the user password
+ if (ownerPassword) {
+ len = ownerPassword->getLength();
+ if (len < 32) {
+ memcpy(test, ownerPassword->getCString(), len);
+ memcpy(test + len, passwordPad, 32 - len);
+ } else {
+ memcpy(test, ownerPassword->getCString(), 32);
+ }
+ } else {
+ memcpy(test, passwordPad, 32);
+ }
+ md5(test, 32, test);
+ if (encRevision == 3) {
+ for (i = 0; i < 50; ++i) {
+ md5(test, 16, test);
+ }
+ }
+ rc4InitKey(test, keyLength, fState);
+ fx = fy = 0;
+ for (i = 0; i < 32; ++i) {
+ test[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i));
+ }
+ userPassword2 = new GString((char *)test, 32);
+ if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
+ permissions, fileID, userPassword2, fileKey)) {
+ *ownerPasswordOk = gTrue;
+ delete userPassword2;
+ return gTrue;
+ }
+ *ownerPasswordOk = gFalse;
+ delete userPassword2;
+
+ // try using the supplied user password
+ return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
+ permissions, fileID, userPassword, fileKey);
+}
+
+GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
+ int permissions, GString *fileID,
+ GString *userPassword, Guchar *fileKey) {
+ Guchar *buf;
+ Guchar test[32];
+ Guchar fState[256];
+ Guchar tmpKey[16];
+ Guchar fx, fy;
+ int len, i, j;
GBool ok;
// generate file key
buf[67] = (permissions >> 24) & 0xff;
memcpy(buf + 68, fileID->getCString(), fileID->getLength());
md5(buf, 68 + fileID->getLength(), fileKey);
+ if (encRevision == 3) {
+ for (i = 0; i < 50; ++i) {
+ md5(fileKey, 16, fileKey);
+ }
+ }
- // test user key
- fx = fy = 0;
- rc4InitKey(fileKey, 5, fState);
- for (i = 0; i < 32; ++i) {
- userTest[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i));
+ // test user password
+ if (encRevision == 2) {
+ rc4InitKey(fileKey, keyLength, fState);
+ fx = fy = 0;
+ for (i = 0; i < 32; ++i) {
+ test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i));
+ }
+ ok = memcmp(test, passwordPad, 32) == 0;
+ } else if (encRevision == 3) {
+ memcpy(test, userKey->getCString(), 32);
+ for (i = 19; i >= 0; --i) {
+ for (j = 0; j < keyLength; ++j) {
+ tmpKey[j] = fileKey[j] ^ i;
+ }
+ rc4InitKey(tmpKey, keyLength, fState);
+ fx = fy = 0;
+ for (j = 0; j < 32; ++j) {
+ test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]);
+ }
+ }
+ memcpy(buf, passwordPad, 32);
+ memcpy(buf + 32, fileID->getCString(), fileID->getLength());
+ md5(buf, 32 + fileID->getLength(), buf);
+ ok = memcmp(test, buf, 16) == 0;
+ } else {
+ ok = gFalse;
}
- ok = memcmp(userTest, passwordPad, 32) == 0;
- gfree(buf);
+ gfree(buf);
return ok;
}
// MD5 message digest
//------------------------------------------------------------------------
+// this works around a bug in older Sun compilers
static inline Gulong rotateLeft(Gulong x, int r) {
x &= 0xffffffff;
return ((x << r) | (x >> (32 - r))) & 0xffffffff;
//
// Decrypt.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
public:
// Initialize the decryptor object.
- Decrypt(Guchar *fileKey, int objNum, int objGen);
+ Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen);
// Reset decryption.
void reset();
// Decrypt one byte.
Guchar decryptByte(Guchar c);
- // Generate a file key. The <fileKey> buffer must have space for
- // at least 16 bytes. Checks user key and returns gTrue if okay.
- // <userPassword> may be NULL.
- static GBool makeFileKey(GString *ownerKey, GString *userKey,
+ // Generate a file key. The <fileKey> buffer must have space for at
+ // least 16 bytes. Checks <ownerPassword> and then <userPassword>
+ // and returns true if either is correct. Sets <ownerPasswordOk> if
+ // the owner password was correct. Either or both of the passwords
+ // may be NULL, which is treated as an empty string.
+ static GBool makeFileKey(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
int permissions, GString *fileID,
- GString *userPassword, Guchar *fileKey);
+ GString *ownerPassword, GString *userPassword,
+ Guchar *fileKey, GBool *ownerPasswordOk);
private:
- Guchar objKey[16];
+ static GBool makeFileKey2(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
+ int permissions, GString *fileID,
+ GString *userPassword, Guchar *fileKey);
+
+ int objKeyLength;
+ Guchar objKey[21];
Guchar state[256];
Guchar x, y;
};
//
// Dict.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stddef.h>
#include <string.h>
#include "gmem.h"
// Dict
//------------------------------------------------------------------------
-Dict::Dict() {
+Dict::Dict(XRef *xrefA) {
+ xref = xrefA;
entries = NULL;
size = length = 0;
ref = 1;
Object *Dict::lookup(char *key, Object *obj) {
DictEntry *e;
- return (e = find(key)) ? e->val.fetch(obj) : obj->initNull();
+ return (e = find(key)) ? e->val.fetch(xref, obj) : obj->initNull();
}
Object *Dict::lookupNF(char *key, Object *obj) {
}
Object *Dict::getVal(int i, Object *obj) {
- return entries[i].val.fetch(obj);
+ return entries[i].val.fetch(xref, obj);
}
Object *Dict::getValNF(int i, Object *obj) {
return entries[i].val.copy(obj);
}
-
-void Dict::dumpEntries()
-{
- int t;
- for(t=0;t<size;t++)
- {
- printf("key: %s\n", entries[t].key);
- fflush(stdout);
- {
- printf(" value:\n");
- entries[t].val.print();
- }
- fflush(stdout);
- printf("---\n");
- fflush(stdout);
- }
-}
//
// Dict.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
public:
// Constructor.
- Dict();
+ Dict(XRef *xrefA);
// Destructor.
~Dict();
Object *getVal(int i, Object *obj);
Object *getValNF(int i, Object *obj);
+ // Set the xref pointer. This is only used in one special case: the
+ // trailer dictionary, which is read before the xref table is
+ // parsed.
+ void setXRef(XRef *xrefA) { xref = xrefA; }
+
private:
+ XRef *xref; // the xref table for this PDF file
DictEntry *entries; // array of entries
int size; // size of <entries> array
int length; // number of entries in dictionary
int ref; // reference count
DictEntry *find(char *key);
-
-public:
- void dumpEntries();
-
};
#endif
//
// Error.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
-#include "gtypes.h"
-#include "Params.h"
+#include "GlobalParams.h"
#include "Error.h"
-FILE *errFile;
-GBool errQuiet;
-
-void errorInit() {
- if (errQuiet) {
- errFile = NULL;
- } else {
- errFile = stderr;
- }
-}
-
void CDECL error(int pos, char *msg, ...) {
va_list args;
- if (errQuiet) {
+ // NB: this can be called before the globalParams object is created
+ if (globalParams && globalParams->getErrQuiet()) {
return;
}
- if (printCommands) {
- fflush(stdout);
- }
if (pos >= 0) {
- fprintf(errFile, "Error (%d): ", pos);
+ fprintf(stderr, "Error (%d): ", pos);
} else {
- fprintf(errFile, "Error: ");
+ fprintf(stderr, "Error: ");
}
va_start(args, msg);
- vfprintf(errFile, msg, args);
+ vfprintf(stderr, msg, args);
va_end(args);
- fprintf(errFile, "\n");
- fflush(errFile);
+ fprintf(stderr, "\n");
+ fflush(stderr);
}
//
// Error.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#include <stdio.h>
#include "config.h"
-// File to send error (and other) messages to.
-extern FILE *errFile;
-
-extern void errorInit();
-
extern void CDECL error(int pos, char *msg, ...);
#endif
+++ /dev/null
-//========================================================================
-//
-// FontEncoding.cc
-//
-// Copyright 1999 Derek B. Noonburg
-//
-//========================================================================
-
-#ifdef __GNUC__
-#pragma implementation
-#endif
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include "gmem.h"
-#include "FontEncoding.h"
-
-//------------------------------------------------------------------------
-// FontEncoding
-//------------------------------------------------------------------------
-
-inline int FontEncoding::hash(char *name) {
- Guint h;
-
- h = (Guint)name[0] & 0xff;
- if (h && name[1])
- h = h * 61 + ((Guint)name[1] & 0xff);
- return (int)(h % (Guint)fontEncHashSize);
-}
-
-FontEncoding::FontEncoding() {
- int i;
-
- encoding = (char **)gmalloc(256 * sizeof(char *));
- size = 256;
- freeEnc = gTrue;
- for (i = 0; i < 256; ++i)
- encoding[i] = NULL;
- for (i = 0; i < fontEncHashSize; ++i)
- hashTab[i] = -1;
-}
-
-FontEncoding::FontEncoding(char **encoding, int size) {
- int i;
-
- this->encoding = encoding;
- this->size = size;
- freeEnc = gFalse;
- for (i = 0; i < fontEncHashSize; ++i)
- hashTab[i] = -1;
- for (i = 0; i < size; ++i) {
- if (encoding[i])
- addChar1(i, encoding[i]);
- }
-}
-
-FontEncoding::FontEncoding(FontEncoding *fontEnc) {
- int i;
-
- encoding = (char **)gmalloc(fontEnc->size * sizeof(char *));
- size = fontEnc->size;
- freeEnc = gTrue;
- for (i = 0; i < size; ++i) {
- encoding[i] =
- fontEnc->encoding[i] ? copyString(fontEnc->encoding[i]) : (char *)NULL;
- }
- memcpy(hashTab, fontEnc->hashTab, fontEncHashSize * sizeof(short));
-}
-
-void FontEncoding::addChar(int code, char *name) {
- int h, i;
-
- // replace character associated with code
- if (encoding[code]) {
- h = hash(encoding[code]);
- for (i = 0; i < fontEncHashSize; ++i) {
- if (hashTab[h] == code) {
- hashTab[h] = -2;
- break;
- }
- if (++h == fontEncHashSize)
- h = 0;
- }
- gfree(encoding[code]);
- }
-
- // associate name with code
- encoding[code] = name;
-
- // insert name in hash table
- addChar1(code, name);
-}
-
-void FontEncoding::addChar1(int code, char *name) {
- int h, i, code2;
-
- // insert name in hash table
- h = hash(name);
- for (i = 0; i < fontEncHashSize; ++i) {
- code2 = hashTab[h];
- if (code2 < 0) {
- hashTab[h] = code;
- break;
- } else if (encoding[code2] && !strcmp(encoding[code2], name)) {
- // keep the highest code for each char -- this is needed because
- // X won't display chars with codes < 32
- if (code > code2)
- hashTab[h] = code;
- break;
- }
- if (++h == fontEncHashSize)
- h = 0;
- }
-}
-
-FontEncoding::~FontEncoding() {
- int i;
-
- if (freeEnc) {
- for (i = 0; i < size; ++i) {
- if (encoding[i])
- gfree(encoding[i]);
- }
- gfree(encoding);
- }
-}
-
-int FontEncoding::getCharCode(char *name) {
- int h, i, code;
-
- h = hash(name);
- for (i = 0; i < fontEncHashSize; ++i) {
- code = hashTab[h];
- if (code == -1 ||
- (code >= 0 && encoding[code] && !strcmp(encoding[code], name)))
- return code;
- if (++h >= fontEncHashSize)
- h = 0;
- }
- return -1;
-}
+++ /dev/null
-//========================================================================
-//
-// FontEncoding.h
-//
-// Copyright 1999 Derek B. Noonburg
-//
-//========================================================================
-
-#ifndef FONTENCODING_H
-#define FONTENCODING_H
-
-#ifdef __GNUC__
-#pragma interface
-#endif
-
-#include "gtypes.h"
-
-//------------------------------------------------------------------------
-// FontEncoding
-//------------------------------------------------------------------------
-
-#define fontEncHashSize 419
-
-class FontEncoding {
-public:
-
- // Construct an empty encoding.
- FontEncoding();
-
- // Construct an encoding from an array of char names.
- FontEncoding(char **encoding, int size);
-
- // Destructor.
- ~FontEncoding();
-
- // Create a copy of the encoding.
- FontEncoding *copy() { return new FontEncoding(this); }
-
- // Return number of codes in encoding, i.e., max code + 1.
- int getSize() { return size; }
-
- // Add a char to the encoding.
- void addChar(int code, char *name);
-
- // Return the character name associated with <code>.
- char *getCharName(int code) { return code>=size?0:encoding[code]; }
-
- // Return the code associated with <name>.
- int getCharCode(char *name);
-
-private:
-
- FontEncoding(FontEncoding *fontEnc);
- int hash(char *name);
- void addChar1(int code, char *name);
-
- char **encoding; // code --> name mapping
- int size; // number of codes
- GBool freeEnc; // should we free the encoding array?
- short // name --> code hash table
- hashTab[fontEncHashSize];
-};
-
-#endif
//
// FontFile.cc
//
-// Copyright 1999 Derek B. Noonburg
+// Copyright 1999-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <math.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include "gmem.h"
#include "Error.h"
+#include "GlobalParams.h"
+#include "CharCodeToUnicode.h"
+#include "FontEncodingTables.h"
#include "FontFile.h"
-#include "StdFontInfo.h"
-#include "CompactFontInfo.h"
-
-//------------------------------------------------------------------------
-
-static Guint getWord(Guchar *ptr, int size);
-static double getNum(Guchar **ptr, GBool *fp);
-static char *getString(int sid, Guchar *stringIdxPtr,
- Guchar *stringStartPtr, int stringOffSize,
- char *buf);
+#include "CompactFontTables.h"
//------------------------------------------------------------------------
Type1FontFile::Type1FontFile(char *file, int len) {
char *line, *line1, *p, *p2;
+ GBool haveEncoding;
char buf[256];
char c;
- int n, code, i;
+ int n, code, i, j;
name = NULL;
- encoding = NULL;
- freeEnc = gTrue;
+ encoding = (char **)gmalloc(256 * sizeof(char *));
+ for (i = 0; i < 256; ++i) {
+ encoding[i] = NULL;
+ }
+ haveEncoding = gFalse;
- for (i = 1, line = file; i <= 100 && line < file + len && !encoding; ++i) {
+ for (i = 1, line = file;
+ i <= 100 && line < file + len && !haveEncoding;
+ ++i) {
// get font name
if (!strncmp(line, "/FontName", 9)) {
strncpy(buf, line, 255);
buf[255] = '\0';
if ((p = strchr(buf+9, '/')) &&
- (p = strtok(p+1, " \t\n\r")))
+ (p = strtok(p+1, " \t\n\r"))) {
name = copyString(p);
+ }
line = nextLine(line, file + len);
// get encoding
} else if (!strncmp(line, "/Encoding StandardEncoding def", 30)) {
- encoding = type1StdEncoding.copy();
+ for (j = 0; j < 256; ++j) {
+ if (standardEncoding[j]) {
+ encoding[j] = copyString(standardEncoding[j]);
+ }
+ }
+ haveEncoding = gTrue;
} else if (!strncmp(line, "/Encoding 256 array", 19)) {
- encoding = new FontEncoding();
- for (i = 0; i < 300; ++i) {
+ for (j = 0; j < 300; ++j) {
line1 = nextLine(line, file + len);
- if ((n = line1 - line) > 255)
+ if ((n = line1 - line) > 255) {
n = 255;
+ }
strncpy(buf, line, n);
buf[n] = '\0';
for (p = buf; *p == ' ' || *p == '\t'; ++p) ;
++p;
for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ;
*p2 = '\0';
- encoding->addChar(code, copyString(p));
+ encoding[code] = copyString(p);
}
}
}
line = line1;
}
//~ check for getinterval/putinterval junk
+ haveEncoding = gTrue;
} else {
line = nextLine(line, file + len);
}
Type1FontFile::~Type1FontFile() {
- if (name)
- gfree(name);
- if (encoding && freeEnc)
- delete encoding;
-}
+ int i;
-FontEncoding *Type1FontFile::getEncoding(GBool taken) {
- if (taken)
- freeEnc = gFalse;
- return encoding;
+ if (name) {
+ gfree(name);
+ }
+ for (i = 0; i < 256; ++i) {
+ gfree(encoding[i]);
+ }
+ gfree(encoding);
}
//------------------------------------------------------------------------
// Type1CFontFile
//------------------------------------------------------------------------
-Type1CFontFile::Type1CFontFile(char *file, int len) {
+struct Type1CTopDict {
+ int version;
+ int notice;
+ int copyright;
+ int fullName;
+ int familyName;
+ int weight;
+ int isFixedPitch;
+ double italicAngle;
+ double underlinePosition;
+ double underlineThickness;
+ int paintType;
+ int charstringType;
+ double fontMatrix[6];
+ int uniqueID;
+ double fontBBox[4];
+ double strokeWidth;
+ int charset;
+ int encoding;
+ int charStrings;
+ int privateSize;
+ int privateOffset;
+
+ //----- CIDFont entries
+ int registry;
+ int ordering;
+ int supplement;
+ int fdArrayOffset;
+ int fdSelectOffset;
+};
+
+struct Type1CPrivateDict {
+ GString *dictData;
+ int subrsOffset;
+ double defaultWidthX;
+ GBool defaultWidthXFP;
+ double nominalWidthX;
+ GBool nominalWidthXFP;
+};
+
+Type1CFontFile::Type1CFontFile(char *fileA, int lenA) {
+ Guchar *nameIdxPtr, *idxPtr0, *idxPtr1;
+
+ file = fileA;
+ len = lenA;
+ name = NULL;
+ encoding = NULL;
+
+ // some tools embed Type 1C fonts with an extra whitespace char at
+ // the beginning
+ if (file[0] != '\x01') {
+ ++file;
+ }
+
+ // read header
+ topOffSize = file[3] & 0xff;
+
+ // read name index (first font only)
+ nameIdxPtr = (Guchar *)file + (file[2] & 0xff);
+ idxPtr0 = getIndexValPtr(nameIdxPtr, 0);
+ idxPtr1 = getIndexValPtr(nameIdxPtr, 1);
+ name = new GString((char *)idxPtr0, idxPtr1 - idxPtr0);
+
+ topDictIdxPtr = getIndexEnd(nameIdxPtr);
+ stringIdxPtr = getIndexEnd(topDictIdxPtr);
+ gsubrIdxPtr = getIndexEnd(stringIdxPtr);
+}
+
+Type1CFontFile::~Type1CFontFile() {
+ int i;
+
+ delete name;
+ if (encoding) {
+ for (i = 0; i < 256; ++i) {
+ gfree(encoding[i]);
+ }
+ gfree(encoding);
+ }
+}
+
+char *Type1CFontFile::getName() {
+ return name->getCString();
+}
+
+char **Type1CFontFile::getEncoding() {
+ if (!encoding) {
+ readNameAndEncoding();
+ }
+ return encoding;
+}
+
+void Type1CFontFile::readNameAndEncoding() {
char buf[256];
- Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1;
- Guchar *stringIdxPtr, *stringStartPtr;
- int topOffSize, idxOffSize, stringOffSize;
- int nFonts, nStrings, nGlyphs;
+ Guchar *idxPtr0, *idxPtr1, *ptr;
+ int nGlyphs;
int nCodes, nRanges, nLeft, nSups;
Gushort *glyphNames;
int charset, enc, charstrings;
- int charsetFormat, encFormat;
+ int encFormat;
int c, sid;
- double op[48];
double x;
GBool isFP;
int key;
- int i, j, n;
-
- name = NULL;
- encoding = NULL;
- freeEnc = gTrue;
+ int i, j;
- // read header
- topPtr = (Guchar *)file + (file[2] & 0xff);
- topOffSize = file[3] & 0xff;
+ encoding = (char **)gmalloc(256 * sizeof(char *));
+ for (i = 0; i < 256; ++i) {
+ encoding[i] = NULL;
+ }
- // read name index (first font only)
- nFonts = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
- idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
- idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
- idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
- if ((n = idxPtr1 - idxPtr0) > 255)
- n = 255;
- strncpy(buf, (char *)idxPtr0, n);
- buf[n] = '\0';
- name = copyString(buf);
- topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
-
- // read top dict index (first font only)
- nFonts = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
- idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
- idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
- idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
- charset = 0;
- enc = 0;
- charstrings = 0;
+ // read top dict (first font only)
+ idxPtr0 = getIndexValPtr(topDictIdxPtr, 0);
+ idxPtr1 = getIndexValPtr(topDictIdxPtr, 1);
+ charset = enc = charstrings = 0;
i = 0;
- while (idxPtr0 < idxPtr1) {
- if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
- key = *idxPtr0++;
- if (key == 0x0c)
- key = (key << 8) | *idxPtr0++;
+ ptr = idxPtr0;
+ while (ptr < idxPtr1) {
+ if (*ptr <= 27 || *ptr == 31) {
+ key = *ptr++;
+ if (key == 0x0c) {
+ key = (key << 8) | *ptr++;
+ }
if (key == 0x0f) { // charset
charset = (int)op[0];
} else if (key == 0x10) { // encoding
}
i = 0;
} else {
- x = getNum(&idxPtr0, &isFP);
- if (i < 48)
+ x = getNum(&ptr, &isFP);
+ if (i < 48) {
op[i++] = x;
+ }
}
}
- topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
-
- // read string index
- nStrings = getWord(topPtr, 2);
- stringOffSize = topPtr[2];
- topPtr += 3;
- stringIdxPtr = topPtr;
- stringStartPtr = topPtr + (nStrings + 1) * stringOffSize - 1;
- topPtr = stringStartPtr + getWord(topPtr + nStrings * stringOffSize,
- stringOffSize);
// get number of glyphs from charstrings index
- topPtr = (Guchar *)file + charstrings;
- nGlyphs = getWord(topPtr, 2);
+ nGlyphs = getIndexLen((Guchar *)file + charstrings);
- // read charset
- if (charset == 0) {
- glyphNames = type1CISOAdobeCharset;
- } else if (charset == 1) {
- glyphNames = type1CExpertCharset;
- } else if (charset == 2) {
- glyphNames = type1CExpertSubsetCharset;
- } else {
- glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
- glyphNames[0] = 0;
- topPtr = (Guchar *)file + charset;
- charsetFormat = *topPtr++;
- if (charsetFormat == 0) {
- for (i = 1; i < nGlyphs; ++i) {
- glyphNames[i] = getWord(topPtr, 2);
- topPtr += 2;
- }
- } else if (charsetFormat == 1) {
- i = 1;
- while (i < nGlyphs) {
- c = getWord(topPtr, 2);
- topPtr += 2;
- nLeft = *topPtr++;
- for (j = 0; j <= nLeft; ++j)
- glyphNames[i++] = c++;
- }
- } else if (charsetFormat == 2) {
- i = 1;
- while (i < nGlyphs) {
- c = getWord(topPtr, 2);
- topPtr += 2;
- nLeft = getWord(topPtr, 2);
- topPtr += 2;
- for (j = 0; j <= nLeft; ++j)
- glyphNames[i++] = c++;
- }
- }
- }
+ // read charset (GID -> name mapping)
+ glyphNames = readCharset(charset, nGlyphs);
- // read encoding (glyph -> code mapping)
+ // read encoding (GID -> code mapping)
if (enc == 0) {
- encoding = type1StdEncoding.copy();
+ for (i = 0; i < 256; ++i) {
+ if (standardEncoding[i]) {
+ encoding[i] = copyString(standardEncoding[i]);
+ }
+ }
} else if (enc == 1) {
- encoding = type1ExpertEncoding.copy();
+ for (i = 0; i < 256; ++i) {
+ if (expertEncoding[i]) {
+ encoding[i] = copyString(expertEncoding[i]);
+ }
+ }
} else {
- encoding = new FontEncoding();
- topPtr = (Guchar *)file + enc;
- encFormat = *topPtr++;
+ ptr = (Guchar *)file + enc;
+ encFormat = *ptr++;
if ((encFormat & 0x7f) == 0) {
- nCodes = 1 + *topPtr++;
+ nCodes = 1 + *ptr++;
if (nCodes > nGlyphs) {
nCodes = nGlyphs;
}
for (i = 1; i < nCodes; ++i) {
- c = *topPtr++;
- getString(glyphNames[i], stringIdxPtr, stringStartPtr,
- stringOffSize, buf);
- encoding->addChar(c, copyString(buf));
+ c = *ptr++;
+ encoding[c] = copyString(getString(glyphNames[i], buf));
}
} else if ((encFormat & 0x7f) == 1) {
- nRanges = *topPtr++;
+ nRanges = *ptr++;
nCodes = 1;
for (i = 0; i < nRanges; ++i) {
- c = *topPtr++;
- nLeft = *topPtr++;
+ c = *ptr++;
+ nLeft = *ptr++;
for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
- getString(glyphNames[nCodes], stringIdxPtr, stringStartPtr,
- stringOffSize, buf);
- encoding->addChar(c, copyString(buf));
+ encoding[c] = copyString(getString(glyphNames[nCodes], buf));
++nCodes;
++c;
}
}
}
if (encFormat & 0x80) {
- nSups = *topPtr++;
+ nSups = *ptr++;
for (i = 0; i < nSups; ++i) {
- c = *topPtr++;
- sid = getWord(topPtr, 2);
- topPtr += 2;
- getString(sid, stringIdxPtr, stringStartPtr,
- stringOffSize, buf);
- encoding->addChar(c, copyString(buf));
+ c = *ptr++;
+ sid = getWord(ptr, 2);
+ ptr += 2;
+ encoding[c] = copyString(getString(sid, buf));
}
}
}
- if (charset > 2)
+ if (charset > 2) {
gfree(glyphNames);
-}
-
-Type1CFontFile::~Type1CFontFile() {
- if (name)
- gfree(name);
- if (encoding && freeEnc)
- delete encoding;
-}
-
-FontEncoding *Type1CFontFile::getEncoding(GBool taken) {
- if (taken)
- freeEnc = gFalse;
- return encoding;
-}
-
-static Guint getWord(Guchar *ptr, int size) {
- Guint x;
- int i;
-
- x = 0;
- for (i = 0; i < size; ++i)
- x = (x << 8) + *ptr++;
- return x;
-}
-
-static double getNum(Guchar **ptr, GBool *fp) {
- static char nybChars[16] = "0123456789.ee -";
- int b0, b, nyb0, nyb1;
- double x;
- char buf[65];
- int i;
-
- x = 0;
- *fp = gFalse;
- b0 = (*ptr)[0];
- if (b0 < 28) {
- x = 0;
- } else if (b0 == 28) {
- x = ((*ptr)[1] << 8) + (*ptr)[2];
- *ptr += 3;
- } else if (b0 == 29) {
- x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4];
- *ptr += 5;
- } else if (b0 == 30) {
- *ptr += 1;
- i = 0;
- do {
- b = *(*ptr)++;
- nyb0 = b >> 4;
- nyb1 = b & 0x0f;
- if (nyb0 == 0xf)
- break;
- buf[i++] = nybChars[nyb0];
- if (i == 64)
- break;
- if (nyb0 == 0xc)
- buf[i++] = '-';
- if (i == 64)
- break;
- if (nyb1 == 0xf)
- break;
- buf[i++] = nybChars[nyb1];
- if (i == 64)
- break;
- if (nyb1 == 0xc)
- buf[i++] = '-';
- } while (i < 64);
- buf[i] = '\0';
- x = atof(buf);
- *fp = gTrue;
- } else if (b0 == 31) {
- x = 0;
- } else if (b0 < 247) {
- x = b0 - 139;
- *ptr += 1;
- } else if (b0 < 251) {
- x = ((b0 - 247) << 8) + (*ptr)[1] + 108;
- *ptr += 2;
- } else {
- x = -((b0 - 251) << 8) - (*ptr)[1] - 108;
- *ptr += 2;
- }
- return x;
-}
-
-static char *getString(int sid, Guchar *stringIdxPtr,
- Guchar *stringStartPtr, int stringOffSize,
- char *buf) {
- Guchar *idxPtr0, *idxPtr1;
- int len;
-
- if (sid < 391) {
- strcpy(buf, type1CStdStrings[sid]);
- } else {
- sid -= 391;
- idxPtr0 = stringStartPtr + getWord(stringIdxPtr + sid * stringOffSize,
- stringOffSize);
- idxPtr1 = stringStartPtr + getWord(stringIdxPtr + (sid+1) * stringOffSize,
- stringOffSize);
- if ((len = idxPtr1 - idxPtr0) > 255)
- len = 255;
- strncpy(buf, (char *)idxPtr0, len);
- buf[len] = '\0';
}
- return buf;
-}
-
-//------------------------------------------------------------------------
-// Type1CFontConverter
-//------------------------------------------------------------------------
-
-Type1CFontConverter::Type1CFontConverter(char *file, int len, FILE *out) {
- this->file = file;
- this->len = len;
- this->out = out;
- r1 = 55665;
- line = 0;
-}
-
-Type1CFontConverter::~Type1CFontConverter() {
}
-void Type1CFontConverter::convert() {
- char *fontName;
- struct {
- int version;
- int notice;
- int copyright;
- int fullName;
- int familyName;
- int weight;
- int isFixedPitch;
- double italicAngle;
- double underlinePosition;
- double underlineThickness;
- int paintType;
- int charstringType; //~ ???
- double fontMatrix[6];
- int uniqueID;
- double fontBBox[4];
- double strokeWidth; //~ ???
- int charset;
- int encoding;
- int charStrings;
- int privateSize;
- int privateOffset;
- } dict;
+void Type1CFontFile::convertToType1(FILE *outA) {
+ Type1CTopDict dict;
+ Type1CPrivateDict privateDict;
char buf[256], eBuf[256];
- Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1;
- Guchar *stringIdxPtr, *stringStartPtr;
- int topOffSize, idxOffSize, stringOffSize;
- int nFonts, nStrings, nGlyphs;
- int nCodes, nRanges, nLeft, nSups;
+ Guchar *idxPtr0, *idxPtr1, *subrsIdxPtr, *charStringsIdxPtr, *ptr;
+ int nGlyphs, nCodes, nRanges, nLeft, nSups;
Gushort *glyphNames;
- int charsetFormat, encFormat;
- int subrsOffset, nSubrs;
- int nCharStrings;
+ int encFormat, nSubrs, nCharStrings;
int c, sid;
- double x;
- GBool isFP;
- int key;
int i, j, n;
- // read header
- topPtr = (Guchar *)file + (file[2] & 0xff);
- topOffSize = file[3] & 0xff;
-
- // read name (first font only)
- nFonts = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
- idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
- idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
- idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
- if ((n = idxPtr1 - idxPtr0) > 255)
- n = 255;
- strncpy(buf, (char *)idxPtr0, n);
- buf[n] = '\0';
- fontName = copyString(buf);
- topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
+ out = outA;
// read top dict (first font only)
- nFonts = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
- idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
- idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
- idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
- dict.version = 0;
- dict.notice = 0;
- dict.copyright = 0;
- dict.fullName = 0;
- dict.familyName = 0;
- dict.weight = 0;
- dict.isFixedPitch = 0;
- dict.italicAngle = 0;
- dict.underlinePosition = -100;
- dict.underlineThickness = 50;
- dict.paintType = 0;
- dict.charstringType = 2;
- dict.fontMatrix[0] = 0.001;
- dict.fontMatrix[1] = 0;
- dict.fontMatrix[2] = 0;
- dict.fontMatrix[3] = 0.001;
- dict.fontMatrix[4] = 0;
- dict.fontMatrix[5] = 0;
- dict.uniqueID = 0;
- dict.fontBBox[0] = 0;
- dict.fontBBox[1] = 0;
- dict.fontBBox[2] = 0;
- dict.fontBBox[3] = 0;
- dict.strokeWidth = 0;
- dict.charset = 0;
- dict.encoding = 0;
- dict.charStrings = 0;
- dict.privateSize = 0;
- dict.privateOffset = 0;
- i = 0;
- while (idxPtr0 < idxPtr1) {
- if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
- key = *idxPtr0++;
- if (key == 0x0c)
- key = (key << 8) | *idxPtr0++;
- switch (key) {
- case 0x0000: dict.version = (int)op[0]; break;
- case 0x0001: dict.notice = (int)op[0]; break;
- case 0x0c00: dict.copyright = (int)op[0]; break;
- case 0x0002: dict.fullName = (int)op[0]; break;
- case 0x0003: dict.familyName = (int)op[0]; break;
- case 0x0004: dict.weight = (int)op[0]; break;
- case 0x0c01: dict.isFixedPitch = (int)op[0]; break;
- case 0x0c02: dict.italicAngle = op[0]; break;
- case 0x0c03: dict.underlinePosition = op[0]; break;
- case 0x0c04: dict.underlineThickness = op[0]; break;
- case 0x0c05: dict.paintType = (int)op[0]; break;
- case 0x0c06: dict.charstringType = (int)op[0]; break;
- case 0x0c07: dict.fontMatrix[0] = op[0];
- dict.fontMatrix[1] = op[1];
- dict.fontMatrix[2] = op[2];
- dict.fontMatrix[3] = op[3];
- dict.fontMatrix[4] = op[4];
- dict.fontMatrix[5] = op[5]; break;
- case 0x000d: dict.uniqueID = (int)op[0]; break;
- case 0x0005: dict.fontBBox[0] = op[0];
- dict.fontBBox[1] = op[1];
- dict.fontBBox[2] = op[2];
- dict.fontBBox[3] = op[3]; break;
- case 0x0c08: dict.strokeWidth = op[0]; break;
- case 0x000f: dict.charset = (int)op[0]; break;
- case 0x0010: dict.encoding = (int)op[0]; break;
- case 0x0011: dict.charStrings = (int)op[0]; break;
- case 0x0012: dict.privateSize = (int)op[0];
- dict.privateOffset = (int)op[1]; break;
- }
- i = 0;
- } else {
- x = getNum(&idxPtr0, &isFP);
- if (i < 48) {
- op[i] = x;
- fp[i++] = isFP;
- }
- }
- }
- topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
-
- // read string index
- nStrings = getWord(topPtr, 2);
- stringOffSize = topPtr[2];
- topPtr += 3;
- stringIdxPtr = topPtr;
- stringStartPtr = topPtr + (nStrings + 1) * stringOffSize - 1;
- topPtr = stringStartPtr + getWord(topPtr + nStrings * stringOffSize,
- stringOffSize);
+ readTopDict(&dict);
-#if 1 //~
// get global subrs
- int nGSubrs;
- int gSubrOffSize;
-
- nGSubrs = getWord(topPtr, 2);
- gSubrOffSize = topPtr[2];
- topPtr += 3;
-#endif
+ //~ ... global subrs are unimplemented
// write header and font dictionary, up to encoding
- fprintf(out, "%%!FontType1-1.0: %s", fontName);
+ fprintf(out, "%%!FontType1-1.0: %s", name->getCString());
if (dict.version != 0) {
- fprintf(out, "%s",
- getString(dict.version, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ fprintf(out, "%s", getString(dict.version, buf));
}
fprintf(out, "\n");
fprintf(out, "11 dict begin\n");
fprintf(out, "/FontInfo 10 dict dup begin\n");
if (dict.version != 0) {
fprintf(out, "/version (%s) readonly def\n",
- getString(dict.version, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.version, buf));
}
if (dict.notice != 0) {
fprintf(out, "/Notice (%s) readonly def\n",
- getString(dict.notice, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.notice, buf));
}
if (dict.copyright != 0) {
fprintf(out, "/Copyright (%s) readonly def\n",
- getString(dict.copyright, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.copyright, buf));
}
if (dict.fullName != 0) {
fprintf(out, "/FullName (%s) readonly def\n",
- getString(dict.fullName, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.fullName, buf));
}
if (dict.familyName != 0) {
fprintf(out, "/FamilyName (%s) readonly def\n",
- getString(dict.familyName, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.familyName, buf));
}
if (dict.weight != 0) {
fprintf(out, "/Weight (%s) readonly def\n",
- getString(dict.weight, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ getString(dict.weight, buf));
}
fprintf(out, "/isFixedPitch %s def\n", dict.isFixedPitch ? "true" : "false");
fprintf(out, "/ItalicAngle %g def\n", dict.italicAngle);
fprintf(out, "/UnderlinePosition %g def\n", dict.underlinePosition);
fprintf(out, "/UnderlineThickness %g def\n", dict.underlineThickness);
fprintf(out, "end readonly def\n");
- fprintf(out, "/FontName /%s def\n", fontName);
+ fprintf(out, "/FontName /%s def\n", name->getCString());
fprintf(out, "/PaintType %d def\n", dict.paintType);
fprintf(out, "/FontType 1 def\n");
fprintf(out, "/FontMatrix [%g %g %g %g %g %g] readonly def\n",
fprintf(out, "/FontBBox [%g %g %g %g] readonly def\n",
dict.fontBBox[0], dict.fontBBox[1],
dict.fontBBox[2], dict.fontBBox[3]);
+ fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
if (dict.uniqueID != 0) {
fprintf(out, "/UniqueID %d def\n", dict.uniqueID);
}
// get number of glyphs from charstrings index
- topPtr = (Guchar *)file + dict.charStrings;
- nGlyphs = getWord(topPtr, 2);
+ nGlyphs = getIndexLen((Guchar *)file + dict.charStrings);
// read charset
- if (dict.charset == 0) {
- glyphNames = type1CISOAdobeCharset;
- } else if (dict.charset == 1) {
- glyphNames = type1CExpertCharset;
- } else if (dict.charset == 2) {
- glyphNames = type1CExpertSubsetCharset;
- } else {
- glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
- glyphNames[0] = 0;
- topPtr = (Guchar *)file + dict.charset;
- charsetFormat = *topPtr++;
- if (charsetFormat == 0) {
- for (i = 1; i < nGlyphs; ++i) {
- glyphNames[i] = getWord(topPtr, 2);
- topPtr += 2;
- }
- } else if (charsetFormat == 1) {
- i = 1;
- while (i < nGlyphs) {
- c = getWord(topPtr, 2);
- topPtr += 2;
- nLeft = *topPtr++;
- for (j = 0; j <= nLeft; ++j)
- glyphNames[i++] = c++;
- }
- } else if (charsetFormat == 2) {
- i = 1;
- while (i < nGlyphs) {
- c = getWord(topPtr, 2);
- topPtr += 2;
- nLeft = getWord(topPtr, 2);
- topPtr += 2;
- for (j = 0; j <= nLeft; ++j)
- glyphNames[i++] = c++;
- }
- }
- }
+ glyphNames = readCharset(dict.charset, nGlyphs);
// read encoding (glyph -> code mapping), write Type 1 encoding
fprintf(out, "/Encoding ");
fprintf(out, "0 1 255 {1 index exch /.notdef put} for\n");
if (dict.encoding == 1) {
for (i = 0; i < 256; ++i) {
- if (type1ExpertEncodingNames[i])
- fprintf(out, "dup %d /%s put\n", i, type1ExpertEncodingNames[i]);
+ if (expertEncoding[i]) {
+ fprintf(out, "dup %d /%s put\n", i, expertEncoding[i]);
+ }
}
} else {
- topPtr = (Guchar *)file + dict.encoding;
- encFormat = *topPtr++;
+ ptr = (Guchar *)file + dict.encoding;
+ encFormat = *ptr++;
if ((encFormat & 0x7f) == 0) {
- nCodes = 1 + *topPtr++;
+ nCodes = 1 + *ptr++;
if (nCodes > nGlyphs) {
nCodes = nGlyphs;
}
for (i = 1; i < nCodes; ++i) {
- c = *topPtr++;
- fprintf(out, "dup %d /%s put\n", c,
- getString(glyphNames[i], stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ c = *ptr++;
+ fprintf(out, "dup %d /%s put\n",
+ c, getString(glyphNames[i], buf));
}
} else if ((encFormat & 0x7f) == 1) {
- nRanges = *topPtr++;
+ nRanges = *ptr++;
nCodes = 1;
for (i = 0; i < nRanges; ++i) {
- c = *topPtr++;
- nLeft = *topPtr++;
+ c = *ptr++;
+ nLeft = *ptr++;
for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
- fprintf(out, "dup %d /%s put\n", c,
- getString(glyphNames[nCodes], stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ fprintf(out, "dup %d /%s put\n",
+ c, getString(glyphNames[nCodes], buf));
++nCodes;
++c;
}
}
}
if (encFormat & 0x80) {
- nSups = *topPtr++;
+ nSups = *ptr++;
for (i = 0; i < nSups; ++i) {
- c = *topPtr++;
- sid = getWord(topPtr, 2);
- topPtr += 2;
- fprintf(out, "dup %d /%s put\n", c,
- getString(sid, stringIdxPtr, stringStartPtr,
- stringOffSize, buf));
+ c = *ptr++;
+ sid = getWord(ptr, 2);
+ ptr += 2;
+ fprintf(out, "dup %d /%s put\n", c, getString(sid, buf));
}
}
}
fprintf(out, "readonly def\n");
}
fprintf(out, "currentdict end\n");
+
+ // start the binary section
fprintf(out, "currentfile eexec\n");
+ r1 = 55665;
+ line = 0;
// get private dictionary
eexecWrite("\x83\xca\x73\xd5");
eexecWrite("/ND {noaccess def} executeonly def\n");
eexecWrite("/NP {noaccess put} executeonly def\n");
eexecWrite("/MinFeature {16 16} ND\n");
- eexecWrite("/password 5839 def\n");
- subrsOffset = 0;
- defaultWidthX = 0;
- nominalWidthX = 0;
- topPtr = (Guchar *)file + dict.privateOffset;
- idxPtr0 = topPtr;
- idxPtr1 = idxPtr0 + dict.privateSize;
- i = 0;
- while (idxPtr0 < idxPtr1) {
- if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
- key = *idxPtr0++;
- if (key == 0x0c)
- key = (key << 8) | *idxPtr0++;
- switch (key) {
- case 0x0006:
- getDeltaInt(eBuf, "BlueValues", op, i);
- eexecWrite(eBuf);
- break;
- case 0x0007:
- getDeltaInt(eBuf, "OtherBlues", op, i);
- eexecWrite(eBuf);
- break;
- case 0x0008:
- getDeltaInt(eBuf, "FamilyBlues", op, i);
- eexecWrite(eBuf);
- break;
- case 0x0009:
- getDeltaInt(eBuf, "FamilyOtherBlues", op, i);
- eexecWrite(eBuf);
- break;
- case 0x0c09:
- sprintf(eBuf, "/BlueScale %g def\n", op[0]);
- eexecWrite(eBuf);
- break;
- case 0x0c0a:
- sprintf(eBuf, "/BlueShift %d def\n", (int)op[0]);
- eexecWrite(eBuf);
- break;
- case 0x0c0b:
- sprintf(eBuf, "/BlueFuzz %d def\n", (int)op[0]);
- eexecWrite(eBuf);
- break;
- case 0x000a:
- sprintf(eBuf, "/StdHW [%g] def\n", op[0]);
- eexecWrite(eBuf);
- break;
- case 0x000b:
- sprintf(eBuf, "/StdVW [%g] def\n", op[0]);
- eexecWrite(eBuf);
- break;
- case 0x0c0c:
- getDeltaReal(eBuf, "StemSnapH", op, i);
- eexecWrite(eBuf);
- break;
- case 0x0c0d:
- getDeltaReal(eBuf, "StemSnapV", op, i);
- eexecWrite(eBuf);
- break;
- case 0x0c0e:
- sprintf(eBuf, "/ForceBold %s def\n", op[0] ? "true" : "false");
- eexecWrite(eBuf);
- break;
- case 0x0c0f:
- sprintf(eBuf, "/ForceBoldThreshold %g def\n", op[0]);
- eexecWrite(eBuf);
- break;
- case 0x0c11:
- sprintf(eBuf, "/LanguageGroup %d def\n", (int)op[0]);
- eexecWrite(eBuf);
- break;
- case 0x0c12:
- sprintf(eBuf, "/ExpansionFactor %g def\n", op[0]);
- eexecWrite(eBuf);
- break;
- case 0x0c13:
- error(-1, "Got Type 1C InitialRandomSeed");
- break;
- case 0x0013:
- subrsOffset = (int)op[0];
- break;
- case 0x0014:
- defaultWidthX = op[0];
- defaultWidthXFP = fp[0];
- break;
- case 0x0015:
- nominalWidthX = op[0];
- nominalWidthXFP = fp[0];
- break;
- default:
- error(-1, "Uknown Type 1C private dict entry %04x", key);
- break;
- }
- i = 0;
- } else {
- x = getNum(&idxPtr0, &isFP);
- if (i < 48) {
- op[i] = x;
- fp[i++] = isFP;
- }
- }
- }
+ readPrivateDict(&privateDict, dict.privateOffset, dict.privateSize);
+ eexecWrite(privateDict.dictData->getCString());
+ defaultWidthX = privateDict.defaultWidthX;
+ defaultWidthXFP = privateDict.defaultWidthXFP;
+ nominalWidthX = privateDict.nominalWidthX;
+ nominalWidthXFP = privateDict.nominalWidthXFP;
// get subrs
- if (subrsOffset != 0) {
- topPtr += subrsOffset;
- nSubrs = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
+ if (privateDict.subrsOffset != 0) {
+ subrsIdxPtr = (Guchar *)file + dict.privateOffset +
+ privateDict.subrsOffset;
+ nSubrs = getIndexLen(subrsIdxPtr);
sprintf(eBuf, "/Subrs %d array\n", nSubrs);
eexecWrite(eBuf);
- idxStartPtr = topPtr + (nSubrs + 1) * idxOffSize - 1;
- idxPtr1 = idxStartPtr + getWord(topPtr, idxOffSize);
+ idxPtr1 = getIndexValPtr(subrsIdxPtr, 0);
for (i = 0; i < nSubrs; ++i) {
idxPtr0 = idxPtr1;
- idxPtr1 = idxStartPtr + getWord(topPtr + (i+1)*idxOffSize, idxOffSize);
+ idxPtr1 = getIndexValPtr(subrsIdxPtr, i+1);
n = idxPtr1 - idxPtr0;
-#if 1 //~
+#if 1 //~ Type 2 subrs are unimplemented
error(-1, "Unimplemented Type 2 subrs");
#else
sprintf(eBuf, "dup %d %d RD ", i, n);
eexecWrite(eBuf);
- cvtGlyph(idxPtr0, n);
+ eexecCvtGlyph(idxPtr0, n);
eexecWrite(" NP\n");
#endif
}
}
// get CharStrings
- topPtr = (Guchar *)file + dict.charStrings;
- nCharStrings = getWord(topPtr, 2);
- idxOffSize = topPtr[2];
- topPtr += 3;
+ charStringsIdxPtr = (Guchar *)file + dict.charStrings;
+ nCharStrings = getIndexLen(charStringsIdxPtr);
sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings);
eexecWrite(eBuf);
- idxStartPtr = topPtr + (nCharStrings + 1) * idxOffSize - 1;
- idxPtr1 = idxStartPtr + getWord(topPtr, idxOffSize);
+ idxPtr1 = getIndexValPtr(charStringsIdxPtr, 0);
for (i = 0; i < nCharStrings; ++i) {
idxPtr0 = idxPtr1;
- idxPtr1 = idxStartPtr + getWord(topPtr + (i+1)*idxOffSize, idxOffSize);
+ idxPtr1 = getIndexValPtr(charStringsIdxPtr, i+1);
n = idxPtr1 - idxPtr0;
- cvtGlyph(getString(glyphNames[i], stringIdxPtr, stringStartPtr,
- stringOffSize, buf),
- idxPtr0, n);
+ eexecCvtGlyph(getString(glyphNames[i], buf), idxPtr0, n);
}
eexecWrite("end\n");
eexecWrite("end\n");
eexecWrite("mark currentfile closefile\n");
// trailer
- if (line > 0)
+ if (line > 0) {
fputc('\n', out);
+ }
for (i = 0; i < 8; ++i) {
fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
}
fprintf(out, "cleartomark\n");
// clean up
- if (dict.charset > 2)
+ delete privateDict.dictData;
+ if (dict.charset > 2) {
gfree(glyphNames);
- gfree(fontName);
+ }
}
-void Type1CFontConverter::eexecWrite(char *s) {
- Guchar *p;
- Guchar x;
+void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
+ Type1CTopDict dict;
+ Type1CPrivateDict *privateDicts;
+ GString *charStrings;
+ int *charStringOffsets;
+ Gushort *charset;
+ int *cidMap;
+ Guchar *fdSelect;
+ Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr;
+ char buf[256];
+ int nGlyphs, nCIDs, gdBytes, nFDs;
+ int fdSelectFmt, nRanges, gid0, gid1, fd, offset;
+ int key;
+ double x;
+ GBool isFP;
+ int i, j, k, n;
- for (p = (Guchar *)s; *p; ++p) {
- x = *p ^ (r1 >> 8);
- r1 = (x + r1) * 52845 + 22719;
- fputc(hexChars[x >> 4], out);
- fputc(hexChars[x & 0x0f], out);
- line += 2;
- if (line == 64) {
- fputc('\n', out);
- line = 0;
+ out = outA;
+
+ fprintf(out, "/CIDInit /ProcSet findresource begin\n");
+
+ // read top dict (first font only)
+ readTopDict(&dict);
+
+ // read the FDArray dictionaries and Private dictionaries
+ if (dict.fdArrayOffset == 0) {
+ nFDs = 1;
+ privateDicts = (Type1CPrivateDict *)
+ gmalloc(nFDs * sizeof(Type1CPrivateDict));
+ privateDicts[0].dictData = new GString();
+ privateDicts[0].subrsOffset = 0;
+ privateDicts[0].defaultWidthX = 0;
+ privateDicts[0].defaultWidthXFP = gFalse;
+ privateDicts[0].nominalWidthX = 0;
+ privateDicts[0].nominalWidthXFP = gFalse;
+ } else {
+ fdArrayIdx = (Guchar *)file + dict.fdArrayOffset;
+ nFDs = getIndexLen(fdArrayIdx);
+ privateDicts = (Type1CPrivateDict *)
+ gmalloc(nFDs * sizeof(Type1CPrivateDict));
+ idxPtr1 = getIndexValPtr(fdArrayIdx, 0);
+ for (i = 0; i < nFDs; ++i) {
+ privateDicts[i].dictData = NULL;
+ idxPtr0 = idxPtr1;
+ idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1);
+ ptr = idxPtr0;
+ j = 0;
+ while (ptr < idxPtr1) {
+ if (*ptr <= 27 || *ptr == 31) {
+ key = *ptr++;
+ if (key == 0x0c) {
+ key = (key << 8) | *ptr++;
+ }
+ if (key == 0x0012) {
+ readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]);
+ }
+ j = 0;
+ } else {
+ x = getNum(&ptr, &isFP);
+ if (j < 48) {
+ op[j] = x;
+ fp[j++] = isFP;
+ }
+ }
+ }
+ if (!privateDicts[i].dictData) {
+ privateDicts[i].dictData = new GString();
+ privateDicts[i].subrsOffset = 0;
+ privateDicts[i].defaultWidthX = 0;
+ privateDicts[i].defaultWidthXFP = gFalse;
+ privateDicts[i].nominalWidthX = 0;
+ privateDicts[i].nominalWidthXFP = gFalse;
+ }
+ }
+ }
+
+ // get the glyph count
+ charStringsIdxPtr = (Guchar *)file + dict.charStrings;
+ nGlyphs = getIndexLen(charStringsIdxPtr);
+
+ // read the FDSelect table
+ fdSelect = (Guchar *)gmalloc(nGlyphs);
+ if (dict.fdSelectOffset == 0) {
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
+ }
+ } else {
+ ptr = (Guchar *)file + dict.fdSelectOffset;
+ fdSelectFmt = *ptr++;
+ if (fdSelectFmt == 0) {
+ memcpy(fdSelect, ptr, nGlyphs);
+ } else if (fdSelectFmt == 3) {
+ nRanges = getWord(ptr, 2);
+ ptr += 2;
+ gid0 = getWord(ptr, 2);
+ ptr += 2;
+ for (i = 1; i <= nRanges; ++i) {
+ fd = *ptr++;
+ gid1 = getWord(ptr, 2);
+ ptr += 2;
+ for (j = gid0; j < gid1; ++j) {
+ fdSelect[j] = fd;
+ }
+ gid0 = gid1;
+ }
+ } else {
+ error(-1, "Unknown FDSelect table format in CID font");
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
+ }
+ }
+ }
+
+ // read the charset, compute the CID-to-GID mapping
+ charset = readCharset(dict.charset, nGlyphs);
+ nCIDs = 0;
+ for (i = 0; i < nGlyphs; ++i) {
+ if (charset[i] >= nCIDs) {
+ nCIDs = charset[i] + 1;
+ }
+ }
+ cidMap = (int *)gmalloc(nCIDs * sizeof(int));
+ for (i = 0; i < nCIDs; ++i) {
+ cidMap[i] = -1;
+ }
+ for (i = 0; i < nGlyphs; ++i) {
+ cidMap[charset[i]] = i;
+ }
+
+ // build the charstrings
+ charStrings = new GString();
+ charStringOffsets = (int *)gmalloc((nCIDs + 1) * sizeof(int));
+ for (i = 0; i < nCIDs; ++i) {
+ charStringOffsets[i] = charStrings->getLength();
+ if (cidMap[i] >= 0) {
+ idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i]);
+ idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i]+1);
+ n = idxPtr1 - idxPtr0;
+ j = fdSelect[cidMap[i]];
+ defaultWidthX = privateDicts[j].defaultWidthX;
+ defaultWidthXFP = privateDicts[j].defaultWidthXFP;
+ nominalWidthX = privateDicts[j].nominalWidthX;
+ nominalWidthXFP = privateDicts[j].nominalWidthXFP;
+ cvtGlyph(idxPtr0, n);
+ charStrings->append(charBuf);
+ delete charBuf;
+ }
+ }
+ charStringOffsets[nCIDs] = charStrings->getLength();
+
+ // compute gdBytes = number of bytes needed for charstring offsets
+ // (offset size needs to account for the charstring offset table,
+ // with a worst case of five bytes per entry, plus the charstrings
+ // themselves)
+ i = (nCIDs + 1) * 5 + charStrings->getLength();
+ if (i < 0x100) {
+ gdBytes = 1;
+ } else if (i < 0x10000) {
+ gdBytes = 2;
+ } else if (i < 0x1000000) {
+ gdBytes = 3;
+ } else {
+ gdBytes = 4;
+ }
+
+ // begin the font dictionary
+ fprintf(out, "20 dict begin\n");
+ fprintf(out, "/CIDFontName /%s def\n", psName);
+ fprintf(out, "/CIDFontType 0 def\n");
+ fprintf(out, "/CIDSystemInfo 3 dict dup begin\n");
+ if (dict.registry > 0 && dict.ordering > 0) {
+ fprintf(out, " /Registry (%s) def\n", getString(dict.registry, buf));
+ fprintf(out, " /Ordering (%s) def\n", getString(dict.ordering, buf));
+ } else {
+ fprintf(out, " /Registry (Adobe) def\n");
+ fprintf(out, " /Ordering (Identity) def\n");
+ }
+ fprintf(out, " /Supplement %d def\n", dict.supplement);
+ fprintf(out, "end def\n");
+ fprintf(out, "/FontMatrix [%g %g %g %g %g %g] def\n",
+ dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2],
+ dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]);
+ fprintf(out, "/FontBBox [%g %g %g %g] def\n",
+ dict.fontBBox[0], dict.fontBBox[1],
+ dict.fontBBox[2], dict.fontBBox[3]);
+ fprintf(out, "/FontInfo 1 dict dup begin\n");
+ fprintf(out, " /FSType 8 def\n");
+ fprintf(out, "end def\n");
+
+ // CIDFont-specific entries
+ fprintf(out, "/CIDCount %d def\n", nCIDs);
+ fprintf(out, "/FDBytes 1 def\n");
+ fprintf(out, "/GDBytes %d def\n", gdBytes);
+ fprintf(out, "/CIDMapOffset 0 def\n");
+ if (dict.paintType != 0) {
+ fprintf(out, "/PaintType %d def\n", dict.paintType);
+ fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
+ }
+
+ // FDArray entry
+ fprintf(out, "/FDArray %d array\n", nFDs);
+ for (i = 0; i < nFDs; ++i) {
+ fprintf(out, "dup %d 10 dict begin\n", i);
+ fprintf(out, "/FontType 1 def\n");
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/PaintType %d def\n", dict.paintType);
+ fprintf(out, "/Private 32 dict begin\n");
+ fwrite(privateDicts[i].dictData->getCString(), 1,
+ privateDicts[i].dictData->getLength(), out);
+ fprintf(out, "currentdict end def\n");
+ fprintf(out, "currentdict end put\n");
+ }
+ fprintf(out, "def\n");
+
+ //~ need to deal with subrs
+
+ // start the binary section
+ offset = (nCIDs + 1) * (1 + gdBytes);
+ fprintf(out, "(Hex) %d StartData\n",
+ offset + charStrings->getLength());
+
+ // write the charstring offset (CIDMap) table
+ for (i = 0; i <= nCIDs; i += 6) {
+ for (j = 0; j < 6 && i+j <= nCIDs; ++j) {
+ if (cidMap[i+j] >= 0) {
+ buf[0] = (char)fdSelect[cidMap[i+j]];
+ } else {
+ buf[0] = (char)0;
+ }
+ n = offset + charStringOffsets[i+j];
+ for (k = gdBytes; k >= 1; --k) {
+ buf[k] = (char)(n & 0xff);
+ n >>= 8;
+ }
+ for (k = 0; k <= gdBytes; ++k) {
+ fprintf(out, "%02x", buf[k] & 0xff);
+ }
+ }
+ fputc('\n', out);
+ }
+
+ // write the charstring data
+ n = charStrings->getLength();
+ for (i = 0; i < n; i += 32) {
+ for (j = 0; j < 32 && i+j < n; ++j) {
+ fprintf(out, "%02x", charStrings->getChar(i+j) & 0xff);
+ }
+ if (i + 32 >= n) {
+ fputc('>', out);
}
+ fputc('\n', out);
+ }
+
+ for (i = 0; i < nFDs; ++i) {
+ delete privateDicts[i].dictData;
}
+ gfree(privateDicts);
+ gfree(cidMap);
+ gfree(charset);
+ gfree(charStringOffsets);
+ delete charStrings;
+ gfree(fdSelect);
}
-void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
- int nHints;
- int x;
- GBool first = gTrue;
+void Type1CFontFile::convertToType0(char *psName, FILE *outA) {
+ Type1CTopDict dict;
+ Type1CPrivateDict *privateDicts;
+ Gushort *charset;
+ int *cidMap;
+ Guchar *fdSelect;
+ Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr;
+ char buf[256];
char eBuf[256];
- double d, dx, dy;
- GBool dFP;
- int i, k;
+ int nGlyphs, nCIDs, nFDs;
+ int fdSelectFmt, nRanges, gid0, gid1, fd;
+ int key;
+ double x;
+ GBool isFP;
+ int i, j, n;
- charBuf = new GString();
- charBuf->append((char)73);
- charBuf->append((char)58);
- charBuf->append((char)147);
- charBuf->append((char)134);
+ out = outA;
- i = 0;
- nOps = 0;
- nHints = 0;
- while (i < n) {
- if (s[i] == 12) {
- switch (s[i+1]) {
- case 0: // dotsection (should be Type 1 only?)
- //~ ignored
- break;
- case 34: // hflex
- if (nOps != 7) {
- error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps);
- }
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[1], fp[1]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpNum(0, gFalse);
- eexecDumpOp1(8);
- eexecDumpNum(op[4], fp[4]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[5], fp[5]);
- eexecDumpNum(-op[2], fp[2]);
- eexecDumpNum(op[6], fp[6]);
- eexecDumpNum(0, gFalse);
- eexecDumpOp1(8);
- break;
- case 35: // flex
- if (nOps != 13) {
- error(-1, "Wrong number of args (%d) to Type 2 flex", nOps);
- }
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(op[1], fp[1]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpNum(op[4], fp[4]);
- eexecDumpNum(op[5], fp[5]);
- eexecDumpOp1(8);
- eexecDumpNum(op[6], fp[6]);
- eexecDumpNum(op[7], fp[7]);
- eexecDumpNum(op[8], fp[8]);
- eexecDumpNum(op[9], fp[9]);
- eexecDumpNum(op[10], fp[10]);
- eexecDumpNum(op[11], fp[11]);
- eexecDumpOp1(8);
- break;
- case 36: // hflex1
- if (nOps != 9) {
- error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps);
- }
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(op[1], fp[1]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpNum(op[4], fp[4]);
- eexecDumpNum(0, gFalse);
- eexecDumpOp1(8);
- eexecDumpNum(op[5], fp[5]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[6], fp[6]);
- eexecDumpNum(op[7], fp[7]);
- eexecDumpNum(op[8], fp[8]);
- eexecDumpNum(-(op[1] + op[3] + op[7]), fp[1] | fp[3] | fp[7]);
- eexecDumpOp1(8);
- break;
- case 37: // flex1
- if (nOps != 11) {
- error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps);
- }
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(op[1], fp[1]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpNum(op[4], fp[4]);
- eexecDumpNum(op[5], fp[5]);
- eexecDumpOp1(8);
- eexecDumpNum(op[6], fp[6]);
- eexecDumpNum(op[7], fp[7]);
- eexecDumpNum(op[8], fp[8]);
- eexecDumpNum(op[9], fp[9]);
- dx = op[0] + op[2] + op[4] + op[6] + op[8];
- dy = op[1] + op[3] + op[5] + op[7] + op[9];
- if (fabs(dx) > fabs(dy)) {
- eexecDumpNum(op[10], fp[10]);
- eexecDumpNum(-dy, fp[1] | fp[3] | fp[5] | fp[7] | fp[9]);
+ // read top dict (first font only)
+ readTopDict(&dict);
+
+ // read the FDArray dictionaries and Private dictionaries
+ if (dict.fdArrayOffset == 0) {
+ nFDs = 1;
+ privateDicts = (Type1CPrivateDict *)
+ gmalloc(nFDs * sizeof(Type1CPrivateDict));
+ privateDicts[0].dictData = new GString();
+ privateDicts[0].subrsOffset = 0;
+ privateDicts[0].defaultWidthX = 0;
+ privateDicts[0].defaultWidthXFP = gFalse;
+ privateDicts[0].nominalWidthX = 0;
+ privateDicts[0].nominalWidthXFP = gFalse;
+ } else {
+ fdArrayIdx = (Guchar *)file + dict.fdArrayOffset;
+ nFDs = getIndexLen(fdArrayIdx);
+ privateDicts = (Type1CPrivateDict *)
+ gmalloc(nFDs * sizeof(Type1CPrivateDict));
+ idxPtr1 = getIndexValPtr(fdArrayIdx, 0);
+ for (i = 0; i < nFDs; ++i) {
+ privateDicts[i].dictData = NULL;
+ idxPtr0 = idxPtr1;
+ idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1);
+ ptr = idxPtr0;
+ j = 0;
+ while (ptr < idxPtr1) {
+ if (*ptr <= 27 || *ptr == 31) {
+ key = *ptr++;
+ if (key == 0x0c) {
+ key = (key << 8) | *ptr++;
+ }
+ if (key == 0x0012) {
+ readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]);
+ }
+ j = 0;
} else {
- eexecDumpNum(-dx, fp[0] | fp[2] | fp[4] | fp[6] | fp[8]);
- eexecDumpNum(op[10], fp[10]);
+ x = getNum(&ptr, &isFP);
+ if (j < 48) {
+ op[j] = x;
+ fp[j++] = isFP;
+ }
}
- eexecDumpOp1(8);
- break;
- case 3: // and
- case 4: // or
- case 5: // not
- case 8: // store
- case 9: // abs
- case 10: // add
- case 11: // sub
- case 12: // div
- case 13: // load
- case 14: // neg
- case 15: // eq
- case 18: // drop
- case 20: // put
- case 21: // get
- case 22: // ifelse
- case 23: // random
- case 24: // mul
- case 26: // sqrt
- case 27: // dup
- case 28: // exch
- case 29: // index
- case 30: // roll
- error(-1, "Unimplemented Type 2 charstring op: 12.%d", s[i+1]);
- break;
- default:
- error(-1, "Illegal Type 2 charstring op: 12.%d", s[i+1]);
- break;
}
- i += 2;
- nOps = 0;
- } else if (s[i] == 19) { // hintmask
- //~ ignored
- if (first) {
- cvtGlyphWidth(nOps == 1);
- first = gFalse;
+ if (!privateDicts[i].dictData) {
+ privateDicts[i].dictData = new GString();
+ privateDicts[i].subrsOffset = 0;
+ privateDicts[i].defaultWidthX = 0;
+ privateDicts[i].defaultWidthXFP = gFalse;
+ privateDicts[i].nominalWidthX = 0;
+ privateDicts[i].nominalWidthXFP = gFalse;
}
- if (nOps > 0) {
- if (nOps & 1) {
- error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm",
- nOps);
+ }
+ }
+
+ // get the glyph count
+ charStringsIdxPtr = (Guchar *)file + dict.charStrings;
+ nGlyphs = getIndexLen(charStringsIdxPtr);
+
+ // read the FDSelect table
+ fdSelect = (Guchar *)gmalloc(nGlyphs);
+ if (dict.fdSelectOffset == 0) {
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
+ }
+ } else {
+ ptr = (Guchar *)file + dict.fdSelectOffset;
+ fdSelectFmt = *ptr++;
+ if (fdSelectFmt == 0) {
+ memcpy(fdSelect, ptr, nGlyphs);
+ } else if (fdSelectFmt == 3) {
+ nRanges = getWord(ptr, 2);
+ ptr += 2;
+ gid0 = getWord(ptr, 2);
+ ptr += 2;
+ for (i = 1; i <= nRanges; ++i) {
+ fd = *ptr++;
+ gid1 = getWord(ptr, 2);
+ ptr += 2;
+ for (j = gid0; j < gid1; ++j) {
+ fdSelect[j] = fd;
}
- nHints += nOps / 2;
+ gid0 = gid1;
}
- i += 1 + ((nHints + 7) >> 3);
- nOps = 0;
- } else if (s[i] == 20) { // cntrmask
- //~ ignored
- if (first) {
- cvtGlyphWidth(nOps == 1);
- first = gFalse;
+ } else {
+ error(-1, "Unknown FDSelect table format in CID font");
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
}
- if (nOps > 0) {
- if (nOps & 1) {
- error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm",
- nOps);
- }
- nHints += nOps / 2;
+ }
+ }
+
+ // read the charset, compute the CID-to-GID mapping
+ charset = readCharset(dict.charset, nGlyphs);
+ nCIDs = 0;
+ for (i = 0; i < nGlyphs; ++i) {
+ if (charset[i] >= nCIDs) {
+ nCIDs = charset[i] + 1;
+ }
+ }
+ cidMap = (int *)gmalloc(nCIDs * sizeof(int));
+ for (i = 0; i < nCIDs; ++i) {
+ cidMap[i] = -1;
+ }
+ for (i = 0; i < nGlyphs; ++i) {
+ cidMap[charset[i]] = i;
+ }
+
+ // write the descendant Type 1 fonts
+ for (i = 0; i < nCIDs; i += 256) {
+
+ //~ this assumes that all CIDs in this block have the same FD --
+ //~ to handle multiple FDs correctly, need to somehow divide the
+ //~ font up by FD
+ fd = 0;
+ for (j = 0; j < 256 && i+j < nCIDs; ++j) {
+ if (cidMap[i+j] >= 0) {
+ fd = fdSelect[cidMap[i+j]];
+ break;
}
- i += 1 + ((nHints + 7) >> 3);
- nOps = 0;
- } else if (s[i] == 28) {
- x = (s[i+1] << 8) + s[i+2];
- if (x & 0x8000)
- x |= -1 << 15;
- if (nOps < 48) {
- fp[nOps] = gFalse;
- op[nOps++] = x;
+ }
+
+ // font dictionary (unencrypted section)
+ fprintf(out, "16 dict begin\n");
+ fprintf(out, "/FontName /%s_%02x def\n", psName, i >> 8);
+ fprintf(out, "/FontType 1 def\n");
+ fprintf(out, "/FontMatrix [%g %g %g %g %g %g] def\n",
+ dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2],
+ dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]);
+ fprintf(out, "/FontBBox [%g %g %g %g] def\n",
+ dict.fontBBox[0], dict.fontBBox[1],
+ dict.fontBBox[2], dict.fontBBox[3]);
+ fprintf(out, "/PaintType %d def\n", dict.paintType);
+ if (dict.paintType != 0) {
+ fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
+ }
+ fprintf(out, "/Encoding 256 array\n");
+ for (j = 0; j < 256 && i+j < nCIDs; ++j) {
+ fprintf(out, "dup %d /c%02x put\n", j, j);
+ }
+ fprintf(out, "readonly def\n");
+ fprintf(out, "currentdict end\n");
+
+ // start the binary section
+ fprintf(out, "currentfile eexec\n");
+ r1 = 55665;
+ line = 0;
+
+ // start the private dictionary
+ eexecWrite("\x83\xca\x73\xd5");
+ eexecWrite("dup /Private 32 dict dup begin\n");
+ eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n");
+ eexecWrite("/ND {noaccess def} executeonly def\n");
+ eexecWrite("/NP {noaccess put} executeonly def\n");
+ eexecWrite("/MinFeature {16 16} ND\n");
+ eexecWrite(privateDicts[fd].dictData->getCString());
+ defaultWidthX = privateDicts[fd].defaultWidthX;
+ defaultWidthXFP = privateDicts[fd].defaultWidthXFP;
+ nominalWidthX = privateDicts[fd].nominalWidthX;
+ nominalWidthXFP = privateDicts[fd].nominalWidthXFP;
+
+ // start the CharStrings
+ sprintf(eBuf, "2 index /CharStrings 256 dict dup begin\n");
+ eexecWrite(eBuf);
+
+ // write the .notdef CharString
+ idxPtr0 = getIndexValPtr(charStringsIdxPtr, 0);
+ idxPtr1 = getIndexValPtr(charStringsIdxPtr, 1);
+ n = idxPtr1 - idxPtr0;
+ eexecCvtGlyph(".notdef", idxPtr0, n);
+
+ // write the CharStrings
+ for (j = 0; j < 256 && i+j < nCIDs; ++j) {
+ if (cidMap[i+j] >= 0) {
+ idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]);
+ idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]+1);
+ n = idxPtr1 - idxPtr0;
+ sprintf(buf, "c%02x", j);
+ eexecCvtGlyph(buf, idxPtr0, n);
}
- i += 3;
- } else if (s[i] <= 31) {
- switch (s[i]) {
- case 4: // vmoveto
- if (first) {
- cvtGlyphWidth(nOps == 2);
- first = gFalse;
- }
- if (nOps != 1)
- error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps);
- eexecDumpNum(op[0], fp[0]);
- eexecDumpOp1(4);
+ }
+ eexecWrite("end\n");
+ eexecWrite("end\n");
+ eexecWrite("readonly put\n");
+ eexecWrite("noaccess put\n");
+ eexecWrite("dup /FontName get exch definefont pop\n");
+ eexecWrite("mark currentfile closefile\n");
+
+ // trailer
+ if (line > 0) {
+ fputc('\n', out);
+ }
+ for (j = 0; j < 8; ++j) {
+ fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
+ }
+ fprintf(out, "cleartomark\n");
+ }
+
+ // write the Type 0 parent font
+ fprintf(out, "16 dict begin\n");
+ fprintf(out, "/FontName /%s def\n", psName);
+ fprintf(out, "/FontType 0 def\n");
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/FMapType 2 def\n");
+ fprintf(out, "/Encoding [\n");
+ for (i = 0; i < nCIDs; i += 256) {
+ fprintf(out, "%d\n", i >> 8);
+ }
+ fprintf(out, "] def\n");
+ fprintf(out, "/FDepVector [\n");
+ for (i = 0; i < nCIDs; i += 256) {
+ fprintf(out, "/%s_%02x findfont\n", psName, i >> 8);
+ }
+ fprintf(out, "] def\n");
+ fprintf(out, "FontName currentdict end definefont pop\n");
+
+ // clean up
+ for (i = 0; i < nFDs; ++i) {
+ delete privateDicts[i].dictData;
+ }
+ gfree(privateDicts);
+ gfree(cidMap);
+ gfree(charset);
+ gfree(fdSelect);
+}
+
+void Type1CFontFile::readTopDict(Type1CTopDict *dict) {
+ Guchar *idxPtr0, *idxPtr1, *ptr;
+ double x;
+ GBool isFP;
+ int key;
+ int i;
+
+ idxPtr0 = getIndexValPtr(topDictIdxPtr, 0);
+ idxPtr1 = getIndexValPtr(topDictIdxPtr, 1);
+ dict->version = 0;
+ dict->notice = 0;
+ dict->copyright = 0;
+ dict->fullName = 0;
+ dict->familyName = 0;
+ dict->weight = 0;
+ dict->isFixedPitch = 0;
+ dict->italicAngle = 0;
+ dict->underlinePosition = -100;
+ dict->underlineThickness = 50;
+ dict->paintType = 0;
+ dict->charstringType = 2;
+ dict->fontMatrix[0] = 0.001;
+ dict->fontMatrix[1] = 0;
+ dict->fontMatrix[2] = 0;
+ dict->fontMatrix[3] = 0.001;
+ dict->fontMatrix[4] = 0;
+ dict->fontMatrix[5] = 0;
+ dict->uniqueID = 0;
+ dict->fontBBox[0] = 0;
+ dict->fontBBox[1] = 0;
+ dict->fontBBox[2] = 0;
+ dict->fontBBox[3] = 0;
+ dict->strokeWidth = 0;
+ dict->charset = 0;
+ dict->encoding = 0;
+ dict->charStrings = 0;
+ dict->privateSize = 0;
+ dict->privateOffset = 0;
+ dict->registry = 0;
+ dict->ordering = 0;
+ dict->supplement = 0;
+ dict->fdArrayOffset = 0;
+ dict->fdSelectOffset = 0;
+ i = 0;
+ ptr = idxPtr0;
+ while (ptr < idxPtr1) {
+ if (*ptr <= 27 || *ptr == 31) {
+ key = *ptr++;
+ if (key == 0x0c) {
+ key = (key << 8) | *ptr++;
+ }
+ switch (key) {
+ case 0x0000: dict->version = (int)op[0]; break;
+ case 0x0001: dict->notice = (int)op[0]; break;
+ case 0x0c00: dict->copyright = (int)op[0]; break;
+ case 0x0002: dict->fullName = (int)op[0]; break;
+ case 0x0003: dict->familyName = (int)op[0]; break;
+ case 0x0004: dict->weight = (int)op[0]; break;
+ case 0x0c01: dict->isFixedPitch = (int)op[0]; break;
+ case 0x0c02: dict->italicAngle = op[0]; break;
+ case 0x0c03: dict->underlinePosition = op[0]; break;
+ case 0x0c04: dict->underlineThickness = op[0]; break;
+ case 0x0c05: dict->paintType = (int)op[0]; break;
+ case 0x0c06: dict->charstringType = (int)op[0]; break;
+ case 0x0c07: dict->fontMatrix[0] = op[0];
+ dict->fontMatrix[1] = op[1];
+ dict->fontMatrix[2] = op[2];
+ dict->fontMatrix[3] = op[3];
+ dict->fontMatrix[4] = op[4];
+ dict->fontMatrix[5] = op[5]; break;
+ case 0x000d: dict->uniqueID = (int)op[0]; break;
+ case 0x0005: dict->fontBBox[0] = op[0];
+ dict->fontBBox[1] = op[1];
+ dict->fontBBox[2] = op[2];
+ dict->fontBBox[3] = op[3]; break;
+ case 0x0c08: dict->strokeWidth = op[0]; break;
+ case 0x000f: dict->charset = (int)op[0]; break;
+ case 0x0010: dict->encoding = (int)op[0]; break;
+ case 0x0011: dict->charStrings = (int)op[0]; break;
+ case 0x0012: dict->privateSize = (int)op[0];
+ dict->privateOffset = (int)op[1]; break;
+ case 0x0c1e: dict->registry = (int)op[0];
+ dict->ordering = (int)op[1];
+ dict->supplement = (int)op[2]; break;
+ case 0x0c24: dict->fdArrayOffset = (int)op[0]; break;
+ case 0x0c25: dict->fdSelectOffset = (int)op[0]; break;
+ }
+ i = 0;
+ } else {
+ x = getNum(&ptr, &isFP);
+ if (i < 48) {
+ op[i] = x;
+ fp[i++] = isFP;
+ }
+ }
+ }
+}
+
+void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
+ int offset, int size) {
+ Guchar *idxPtr0, *idxPtr1, *ptr;
+ char eBuf[256];
+ int key;
+ double x;
+ GBool isFP;
+ int i;
+
+ privateDict->dictData = new GString();
+ privateDict->subrsOffset = 0;
+ privateDict->defaultWidthX = 0;
+ privateDict->defaultWidthXFP = gFalse;
+ privateDict->nominalWidthX = 0;
+ privateDict->nominalWidthXFP = gFalse;
+ idxPtr0 = (Guchar *)file + offset;
+ idxPtr1 = idxPtr0 + size;
+ ptr = idxPtr0;
+ i = 0;
+ while (ptr < idxPtr1) {
+ if (*ptr <= 27 || *ptr == 31) {
+ key = *ptr++;
+ if (key == 0x0c) {
+ key = (key << 8) | *ptr++;
+ }
+ switch (key) {
+ case 0x0006:
+ getDeltaInt(eBuf, "BlueValues", op, i);
+ privateDict->dictData->append(eBuf);
break;
- case 5: // rlineto
- if (nOps < 2 || nOps % 2 != 0)
- error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps);
- for (k = 0; k < nOps; k += 2) {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpOp1(5);
- }
+ case 0x0007:
+ getDeltaInt(eBuf, "OtherBlues", op, i);
+ privateDict->dictData->append(eBuf);
break;
- case 6: // hlineto
- if (nOps < 1)
- error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps);
- for (k = 0; k < nOps; ++k) {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpOp1((k & 1) ? 7 : 6);
- }
+ case 0x0008:
+ getDeltaInt(eBuf, "FamilyBlues", op, i);
+ privateDict->dictData->append(eBuf);
break;
- case 7: // vlineto
- if (nOps < 1)
- error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps);
- for (k = 0; k < nOps; ++k) {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpOp1((k & 1) ? 6 : 7);
- }
+ case 0x0009:
+ getDeltaInt(eBuf, "FamilyOtherBlues", op, i);
+ privateDict->dictData->append(eBuf);
break;
- case 8: // rrcurveto
- if (nOps < 6 || nOps % 6 != 0)
- error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps);
- for (k = 0; k < nOps; k += 6) {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpNum(op[k+4], fp[k+4]);
- eexecDumpNum(op[k+5], fp[k+5]);
- eexecDumpOp1(8);
- }
+ case 0x0c09:
+ sprintf(eBuf, "/BlueScale %g def\n", op[0]);
+ privateDict->dictData->append(eBuf);
break;
- case 14: // endchar / seac
- if (first) {
- cvtGlyphWidth(nOps == 1 || nOps == 5);
- first = gFalse;
- }
- if (nOps == 4) {
- eexecDumpNum(0, 0);
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(op[1], fp[1]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpOp2(6);
- } else if (nOps == 0) {
- eexecDumpOp1(14);
- } else {
- error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps);
- }
+ case 0x0c0a:
+ sprintf(eBuf, "/BlueShift %d def\n", (int)op[0]);
+ privateDict->dictData->append(eBuf);
break;
- case 21: // rmoveto
- if (first) {
- cvtGlyphWidth(nOps == 3);
- first = gFalse;
- }
- if (nOps != 2)
- error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps);
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(op[1], fp[1]);
- eexecDumpOp1(21);
+ case 0x0c0b:
+ sprintf(eBuf, "/BlueFuzz %d def\n", (int)op[0]);
+ privateDict->dictData->append(eBuf);
break;
- case 22: // hmoveto
- if (first) {
- cvtGlyphWidth(nOps == 2);
- first = gFalse;
- }
- if (nOps != 1)
- error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps);
- eexecDumpNum(op[0], fp[0]);
- eexecDumpOp1(22);
+ case 0x000a:
+ sprintf(eBuf, "/StdHW [%g] def\n", op[0]);
+ privateDict->dictData->append(eBuf);
break;
- case 24: // rcurveline
- if (nOps < 8 || (nOps - 2) % 6 != 0)
- error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps);
- for (k = 0; k < nOps - 2; k += 6) {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpNum(op[k+4], fp[k+4]);
- eexecDumpNum(op[k+5], fp[k+5]);
- eexecDumpOp1(8);
- }
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k]);
- eexecDumpOp1(5);
+ case 0x000b:
+ sprintf(eBuf, "/StdVW [%g] def\n", op[0]);
+ privateDict->dictData->append(eBuf);
break;
- case 25: // rlinecurve
- if (nOps < 8 || (nOps - 6) % 2 != 0)
- error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps);
- for (k = 0; k < nOps - 6; k += 2) {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k]);
- eexecDumpOp1(5);
- }
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpNum(op[k+4], fp[k+4]);
- eexecDumpNum(op[k+5], fp[k+5]);
- eexecDumpOp1(8);
+ case 0x0c0c:
+ getDeltaReal(eBuf, "StemSnapH", op, i);
+ privateDict->dictData->append(eBuf);
break;
- case 26: // vvcurveto
- if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
- error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps);
- if (nOps % 2 == 1) {
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(op[1], fp[1]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[4], fp[4]);
- eexecDumpOp1(8);
- k = 5;
- } else {
- k = 0;
- }
- for (; k < nOps; k += 4) {
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpOp1(8);
- }
+ case 0x0c0d:
+ getDeltaReal(eBuf, "StemSnapV", op, i);
+ privateDict->dictData->append(eBuf);
break;
- case 27: // hhcurveto
- if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
- error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps);
- if (nOps % 2 == 1) {
- eexecDumpNum(op[1], fp[1]);
- eexecDumpNum(op[0], fp[0]);
- eexecDumpNum(op[2], fp[2]);
- eexecDumpNum(op[3], fp[3]);
- eexecDumpNum(op[4], fp[4]);
- eexecDumpNum(0, gFalse);
- eexecDumpOp1(8);
- k = 5;
- } else {
- k = 0;
- }
- for (; k < nOps; k += 4) {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpNum(0, gFalse);
- eexecDumpOp1(8);
- }
+ case 0x0c0e:
+ sprintf(eBuf, "/ForceBold %s def\n", op[0] ? "true" : "false");
+ privateDict->dictData->append(eBuf);
break;
- case 30: // vhcurveto
- if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
- error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps);
- for (k = 0; k < nOps && k != nOps-5; k += 4) {
- if (k % 8 == 0) {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
+ case 0x0c0f:
+ sprintf(eBuf, "/ForceBoldThreshold %g def\n", op[0]);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c11:
+ sprintf(eBuf, "/LanguageGroup %d def\n", (int)op[0]);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c12:
+ sprintf(eBuf, "/ExpansionFactor %g def\n", op[0]);
+ privateDict->dictData->append(eBuf);
+ break;
+ case 0x0c13:
+ error(-1, "Got Type 1C InitialRandomSeed");
+ break;
+ case 0x0013:
+ privateDict->subrsOffset = (int)op[0];
+ break;
+ case 0x0014:
+ privateDict->defaultWidthX = op[0];
+ privateDict->defaultWidthXFP = fp[0];
+ break;
+ case 0x0015:
+ privateDict->nominalWidthX = op[0];
+ privateDict->nominalWidthXFP = fp[0];
+ break;
+ default:
+ error(-1, "Unknown Type 1C private dict entry %04x", key);
+ break;
+ }
+ i = 0;
+ } else {
+ x = getNum(&ptr, &isFP);
+ if (i < 48) {
+ op[i] = x;
+ fp[i++] = isFP;
+ }
+ }
+ }
+}
+
+Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) {
+ Gushort *glyphNames;
+ Guchar *ptr;
+ int charsetFormat, c;
+ int nLeft, i, j;
+
+ if (charset == 0) {
+ glyphNames = type1CISOAdobeCharset;
+ } else if (charset == 1) {
+ glyphNames = type1CExpertCharset;
+ } else if (charset == 2) {
+ glyphNames = type1CExpertSubsetCharset;
+ } else {
+ glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
+ glyphNames[0] = 0;
+ ptr = (Guchar *)file + charset;
+ charsetFormat = *ptr++;
+ if (charsetFormat == 0) {
+ for (i = 1; i < nGlyphs; ++i) {
+ glyphNames[i] = getWord(ptr, 2);
+ ptr += 2;
+ }
+ } else if (charsetFormat == 1) {
+ i = 1;
+ while (i < nGlyphs) {
+ c = getWord(ptr, 2);
+ ptr += 2;
+ nLeft = *ptr++;
+ for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
+ glyphNames[i++] = c++;
+ }
+ }
+ } else if (charsetFormat == 2) {
+ i = 1;
+ while (i < nGlyphs) {
+ c = getWord(ptr, 2);
+ ptr += 2;
+ nLeft = getWord(ptr, 2);
+ ptr += 2;
+ for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
+ glyphNames[i++] = c++;
+ }
+ }
+ }
+ }
+ return glyphNames;
+}
+
+void Type1CFontFile::eexecWrite(char *s) {
+ Guchar *p;
+ Guchar x;
+
+ for (p = (Guchar *)s; *p; ++p) {
+ x = *p ^ (r1 >> 8);
+ r1 = (x + r1) * 52845 + 22719;
+ fputc(hexChars[x >> 4], out);
+ fputc(hexChars[x & 0x0f], out);
+ line += 2;
+ if (line == 64) {
+ fputc('\n', out);
+ line = 0;
+ }
+ }
+}
+
+void Type1CFontFile::eexecCvtGlyph(char *glyphName, Guchar *s, int n) {
+ char eBuf[256];
+
+ cvtGlyph(s, n);
+ sprintf(eBuf, "/%s %d RD ", glyphName, charBuf->getLength());
+ eexecWrite(eBuf);
+ eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength());
+ eexecWrite(" ND\n");
+ delete charBuf;
+}
+
+void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
+ int nHints;
+ int x;
+ GBool first = gTrue;
+ double d, dx, dy;
+ GBool dFP;
+ Gushort r2;
+ Guchar byte;
+ int i, k;
+
+ charBuf = new GString();
+ charBuf->append((char)73);
+ charBuf->append((char)58);
+ charBuf->append((char)147);
+ charBuf->append((char)134);
+
+ i = 0;
+ nOps = 0;
+ nHints = 0;
+ while (i < n) {
+ if (s[i] == 12) {
+ switch (s[i+1]) {
+ case 0: // dotsection (should be Type 1 only?)
+ // ignored
+ break;
+ case 34: // hflex
+ if (nOps != 7) {
+ error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps);
+ }
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[5], fp[5]);
+ eexecDumpNum(-op[2], fp[2]);
+ eexecDumpNum(op[6], fp[6]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ break;
+ case 35: // flex
+ if (nOps != 13) {
+ error(-1, "Wrong number of args (%d) to Type 2 flex", nOps);
+ }
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(op[5], fp[5]);
+ eexecDumpOp1(8);
+ eexecDumpNum(op[6], fp[6]);
+ eexecDumpNum(op[7], fp[7]);
+ eexecDumpNum(op[8], fp[8]);
+ eexecDumpNum(op[9], fp[9]);
+ eexecDumpNum(op[10], fp[10]);
+ eexecDumpNum(op[11], fp[11]);
+ eexecDumpOp1(8);
+ break;
+ case 36: // hflex1
+ if (nOps != 9) {
+ error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps);
+ }
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ eexecDumpNum(op[5], fp[5]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[6], fp[6]);
+ eexecDumpNum(op[7], fp[7]);
+ eexecDumpNum(op[8], fp[8]);
+ eexecDumpNum(-(op[1] + op[3] + op[7]), fp[1] | fp[3] | fp[7]);
+ eexecDumpOp1(8);
+ break;
+ case 37: // flex1
+ if (nOps != 11) {
+ error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps);
+ }
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(op[5], fp[5]);
+ eexecDumpOp1(8);
+ eexecDumpNum(op[6], fp[6]);
+ eexecDumpNum(op[7], fp[7]);
+ eexecDumpNum(op[8], fp[8]);
+ eexecDumpNum(op[9], fp[9]);
+ dx = op[0] + op[2] + op[4] + op[6] + op[8];
+ dy = op[1] + op[3] + op[5] + op[7] + op[9];
+ if (fabs(dx) > fabs(dy)) {
+ eexecDumpNum(op[10], fp[10]);
+ eexecDumpNum(-dy, fp[1] | fp[3] | fp[5] | fp[7] | fp[9]);
+ } else {
+ eexecDumpNum(-dx, fp[0] | fp[2] | fp[4] | fp[6] | fp[8]);
+ eexecDumpNum(op[10], fp[10]);
+ }
+ eexecDumpOp1(8);
+ break;
+ case 3: // and
+ case 4: // or
+ case 5: // not
+ case 8: // store
+ case 9: // abs
+ case 10: // add
+ case 11: // sub
+ case 12: // div
+ case 13: // load
+ case 14: // neg
+ case 15: // eq
+ case 18: // drop
+ case 20: // put
+ case 21: // get
+ case 22: // ifelse
+ case 23: // random
+ case 24: // mul
+ case 26: // sqrt
+ case 27: // dup
+ case 28: // exch
+ case 29: // index
+ case 30: // roll
+ error(-1, "Unimplemented Type 2 charstring op: 12.%d", s[i+1]);
+ break;
+ default:
+ error(-1, "Illegal Type 2 charstring op: 12.%d", s[i+1]);
+ break;
+ }
+ i += 2;
+ nOps = 0;
+ } else if (s[i] == 19) { // hintmask
+ // ignored
+ if (first) {
+ cvtGlyphWidth(nOps == 1);
+ first = gFalse;
+ }
+ if (nOps > 0) {
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm",
+ nOps);
+ }
+ nHints += nOps / 2;
+ }
+ i += 1 + ((nHints + 7) >> 3);
+ nOps = 0;
+ } else if (s[i] == 20) { // cntrmask
+ // ignored
+ if (first) {
+ cvtGlyphWidth(nOps == 1);
+ first = gFalse;
+ }
+ if (nOps > 0) {
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm",
+ nOps);
+ }
+ nHints += nOps / 2;
+ }
+ i += 1 + ((nHints + 7) >> 3);
+ nOps = 0;
+ } else if (s[i] == 28) {
+ x = (s[i+1] << 8) + s[i+2];
+ if (x & 0x8000) {
+ x |= -1 << 15;
+ }
+ if (nOps < 48) {
+ fp[nOps] = gFalse;
+ op[nOps++] = x;
+ }
+ i += 3;
+ } else if (s[i] <= 31) {
+ switch (s[i]) {
+ case 4: // vmoveto
+ if (first) {
+ cvtGlyphWidth(nOps == 2);
+ first = gFalse;
+ }
+ if (nOps != 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps);
+ }
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpOp1(4);
+ break;
+ case 5: // rlineto
+ if (nOps < 2 || nOps % 2 != 0) {
+ error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps);
+ }
+ for (k = 0; k < nOps; k += 2) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpOp1(5);
+ }
+ break;
+ case 6: // hlineto
+ if (nOps < 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps);
+ }
+ for (k = 0; k < nOps; ++k) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpOp1((k & 1) ? 7 : 6);
+ }
+ break;
+ case 7: // vlineto
+ if (nOps < 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps);
+ }
+ for (k = 0; k < nOps; ++k) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpOp1((k & 1) ? 6 : 7);
+ }
+ break;
+ case 8: // rrcurveto
+ if (nOps < 6 || nOps % 6 != 0) {
+ error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps);
+ }
+ for (k = 0; k < nOps; k += 6) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+5], fp[k+5]);
+ eexecDumpOp1(8);
+ }
+ break;
+ case 14: // endchar / seac
+ if (first) {
+ cvtGlyphWidth(nOps == 1 || nOps == 5);
+ first = gFalse;
+ }
+ if (nOps == 4) {
+ eexecDumpNum(0, 0);
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpOp2(6);
+ } else if (nOps == 0) {
+ eexecDumpOp1(14);
+ } else {
+ error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps);
+ }
+ break;
+ case 21: // rmoveto
+ if (first) {
+ cvtGlyphWidth(nOps == 3);
+ first = gFalse;
+ }
+ if (nOps != 2) {
+ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps);
+ }
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpOp1(21);
+ break;
+ case 22: // hmoveto
+ if (first) {
+ cvtGlyphWidth(nOps == 2);
+ first = gFalse;
+ }
+ if (nOps != 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps);
+ }
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpOp1(22);
+ break;
+ case 24: // rcurveline
+ if (nOps < 8 || (nOps - 2) % 6 != 0) {
+ error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps);
+ }
+ for (k = 0; k < nOps - 2; k += 6) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+5], fp[k+5]);
+ eexecDumpOp1(8);
+ }
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k]);
+ eexecDumpOp1(5);
+ break;
+ case 25: // rlinecurve
+ if (nOps < 8 || (nOps - 6) % 2 != 0) {
+ error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps);
+ }
+ for (k = 0; k < nOps - 6; k += 2) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k]);
+ eexecDumpOp1(5);
+ }
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+5], fp[k+5]);
+ eexecDumpOp1(8);
+ break;
+ case 26: // vvcurveto
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
+ error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps);
+ }
+ if (nOps % 2 == 1) {
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpOp1(8);
+ k = 5;
+ } else {
+ k = 0;
+ }
+ for (; k < nOps; k += 4) {
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(8);
+ }
+ break;
+ case 27: // hhcurveto
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
+ error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps);
+ }
+ if (nOps % 2 == 1) {
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ k = 5;
+ } else {
+ k = 0;
+ }
+ for (; k < nOps; k += 4) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ }
+ break;
+ case 30: // vhcurveto
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
+ error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps);
+ }
+ for (k = 0; k < nOps && k != nOps-5; k += 4) {
+ if (k % 8 == 0) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(30);
+ } else {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(31);
+ }
+ }
+ if (k == nOps-5) {
+ if (k % 8 == 0) {
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ } else {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ }
+ eexecDumpOp1(8);
+ }
+ break;
+ case 31: // hvcurveto
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
+ error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps);
+ }
+ for (k = 0; k < nOps && k != nOps-5; k += 4) {
+ if (k % 8 == 0) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(31);
+ } else {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
eexecDumpNum(op[k+3], fp[k+3]);
eexecDumpOp1(30);
+ }
+ }
+ if (k == nOps-5) {
+ if (k % 8 == 0) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ } else {
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ }
+ eexecDumpOp1(8);
+ }
+ break;
+ case 1: // hstem
+ if (first) {
+ cvtGlyphWidth(nOps & 1);
+ first = gFalse;
+ }
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps);
+ }
+ d = 0;
+ dFP = gFalse;
+ for (k = 0; k < nOps; k += 2) {
+ if (op[k+1] < 0) {
+ d += op[k] + op[k+1];
+ dFP |= fp[k] | fp[k+1];
+ eexecDumpNum(d, dFP);
+ eexecDumpNum(-op[k+1], fp[k+1]);
} else {
- eexecDumpNum(op[k], fp[k]);
+ d += op[k];
+ dFP |= fp[k];
+ eexecDumpNum(d, dFP);
eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpOp1(31);
+ d += op[k+1];
+ dFP |= fp[k+1];
}
+ eexecDumpOp1(1);
}
- if (k == nOps-5) {
- if (k % 8 == 0) {
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpNum(op[k+4], fp[k+4]);
+ nHints += nOps / 2;
+ break;
+ case 3: // vstem
+ if (first) {
+ cvtGlyphWidth(nOps & 1);
+ first = gFalse;
+ }
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps);
+ }
+ d = 0;
+ dFP = gFalse;
+ for (k = 0; k < nOps; k += 2) {
+ if (op[k+1] < 0) {
+ d += op[k] + op[k+1];
+ dFP |= fp[k] | fp[k+1];
+ eexecDumpNum(d, dFP);
+ eexecDumpNum(-op[k+1], fp[k+1]);
} else {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(0, gFalse);
+ d += op[k];
+ dFP |= fp[k];
+ eexecDumpNum(d, dFP);
eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+4], fp[k+4]);
- eexecDumpNum(op[k+3], fp[k+3]);
+ d += op[k+1];
+ dFP |= fp[k+1];
}
- eexecDumpOp1(8);
+ eexecDumpOp1(3);
+ }
+ nHints += nOps / 2;
+ break;
+ case 18: // hstemhm
+ // ignored
+ if (first) {
+ cvtGlyphWidth(nOps & 1);
+ first = gFalse;
+ }
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps);
+ }
+ nHints += nOps / 2;
+ break;
+ case 23: // vstemhm
+ // ignored
+ if (first) {
+ cvtGlyphWidth(nOps & 1);
+ first = gFalse;
+ }
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps);
}
+ nHints += nOps / 2;
+ break;
+ case 10: // callsubr
+ case 11: // return
+ case 16: // blend
+ case 29: // callgsubr
+ error(-1, "Unimplemented Type 2 charstring op: %d", s[i]);
+ break;
+ default:
+ error(-1, "Illegal Type 2 charstring op: %d", s[i]);
+ break;
+ }
+ ++i;
+ nOps = 0;
+ } else if (s[i] <= 246) {
+ if (nOps < 48) {
+ fp[nOps] = gFalse;
+ op[nOps++] = (int)s[i] - 139;
+ }
+ ++i;
+ } else if (s[i] <= 250) {
+ if (nOps < 48) {
+ fp[nOps] = gFalse;
+ op[nOps++] = (((int)s[i] - 247) << 8) + (int)s[i+1] + 108;
+ }
+ i += 2;
+ } else if (s[i] <= 254) {
+ if (nOps < 48) {
+ fp[nOps] = gFalse;
+ op[nOps++] = -(((int)s[i] - 251) << 8) - (int)s[i+1] - 108;
+ }
+ i += 2;
+ } else {
+ x = (s[i+1] << 24) | (s[i+2] << 16) | (s[i+3] << 8) | s[i+4];
+ if (x & 0x80000000)
+ x |= -1 << 31;
+ if (nOps < 48) {
+ fp[nOps] = gTrue;
+ op[nOps++] = (double)x / 65536.0;
+ }
+ i += 5;
+ }
+ }
+
+ // charstring encryption
+ r2 = 4330;
+ for (i = 0; i < charBuf->getLength(); ++i) {
+ byte = charBuf->getChar(i) ^ (r2 >> 8);
+ charBuf->setChar(i, byte);
+ r2 = (byte + r2) * 52845 + 22719;
+ }
+}
+
+void Type1CFontFile::cvtGlyphWidth(GBool useOp) {
+ double w;
+ GBool wFP;
+ int i;
+
+ if (useOp) {
+ w = nominalWidthX + op[0];
+ wFP = nominalWidthXFP | fp[0];
+ for (i = 1; i < nOps; ++i) {
+ op[i-1] = op[i];
+ fp[i-1] = fp[i];
+ }
+ --nOps;
+ } else {
+ w = defaultWidthX;
+ wFP = defaultWidthXFP;
+ }
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(w, wFP);
+ eexecDumpOp1(13);
+}
+
+void Type1CFontFile::eexecDumpNum(double x, GBool fpA) {
+ Guchar buf[12];
+ int y, n;
+
+ n = 0;
+ if (fpA) {
+ if (x >= -32768 && x < 32768) {
+ y = (int)(x * 256.0);
+ buf[0] = 255;
+ buf[1] = (Guchar)(y >> 24);
+ buf[2] = (Guchar)(y >> 16);
+ buf[3] = (Guchar)(y >> 8);
+ buf[4] = (Guchar)y;
+ buf[5] = 255;
+ buf[6] = 0;
+ buf[7] = 0;
+ buf[8] = 1;
+ buf[9] = 0;
+ buf[10] = 12;
+ buf[11] = 12;
+ n = 12;
+ } else {
+ error(-1, "Type 2 fixed point constant out of range");
+ }
+ } else {
+ y = (int)x;
+ if (y >= -107 && y <= 107) {
+ buf[0] = (Guchar)(y + 139);
+ n = 1;
+ } else if (y > 107 && y <= 1131) {
+ y -= 108;
+ buf[0] = (Guchar)((y >> 8) + 247);
+ buf[1] = (Guchar)(y & 0xff);
+ n = 2;
+ } else if (y < -107 && y >= -1131) {
+ y = -y - 108;
+ buf[0] = (Guchar)((y >> 8) + 251);
+ buf[1] = (Guchar)(y & 0xff);
+ n = 2;
+ } else {
+ buf[0] = 255;
+ buf[1] = (Guchar)(y >> 24);
+ buf[2] = (Guchar)(y >> 16);
+ buf[3] = (Guchar)(y >> 8);
+ buf[4] = (Guchar)y;
+ n = 5;
+ }
+ }
+ charBuf->append((char *)buf, n);
+}
+
+void Type1CFontFile::eexecDumpOp1(int opA) {
+ charBuf->append((char)opA);
+}
+
+void Type1CFontFile::eexecDumpOp2(int opA) {
+ charBuf->append((char)12);
+ charBuf->append((char)opA);
+}
+
+void Type1CFontFile::eexecWriteCharstring(Guchar *s, int n) {
+ Guchar x;
+ int i;
+
+ // eexec encryption
+ for (i = 0; i < n; ++i) {
+ x = s[i] ^ (r1 >> 8);
+ r1 = (x + r1) * 52845 + 22719;
+ fputc(hexChars[x >> 4], out);
+ fputc(hexChars[x & 0x0f], out);
+ line += 2;
+ if (line == 64) {
+ fputc('\n', out);
+ line = 0;
+ }
+ }
+}
+
+void Type1CFontFile::getDeltaInt(char *buf, char *key, double *opA,
+ int n) {
+ int x, i;
+
+ sprintf(buf, "/%s [", key);
+ buf += strlen(buf);
+ x = 0;
+ for (i = 0; i < n; ++i) {
+ x += (int)opA[i];
+ sprintf(buf, "%s%d", i > 0 ? " " : "", x);
+ buf += strlen(buf);
+ }
+ sprintf(buf, "] def\n");
+}
+
+void Type1CFontFile::getDeltaReal(char *buf, char *key, double *opA,
+ int n) {
+ double x;
+ int i;
+
+ sprintf(buf, "/%s [", key);
+ buf += strlen(buf);
+ x = 0;
+ for (i = 0; i < n; ++i) {
+ x += opA[i];
+ sprintf(buf, "%s%g", i > 0 ? " " : "", x);
+ buf += strlen(buf);
+ }
+ sprintf(buf, "] def\n");
+}
+
+int Type1CFontFile::getIndexLen(Guchar *indexPtr) {
+ return (int)getWord(indexPtr, 2);
+}
+
+Guchar *Type1CFontFile::getIndexValPtr(Guchar *indexPtr, int i) {
+ int n, offSize;
+ Guchar *idxStartPtr;
+
+ n = (int)getWord(indexPtr, 2);
+ offSize = indexPtr[2];
+ idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1;
+ return idxStartPtr + getWord(indexPtr + 3 + i * offSize, offSize);
+}
+
+Guchar *Type1CFontFile::getIndexEnd(Guchar *indexPtr) {
+ int n, offSize;
+ Guchar *idxStartPtr;
+
+ n = (int)getWord(indexPtr, 2);
+ offSize = indexPtr[2];
+ idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1;
+ return idxStartPtr + getWord(indexPtr + 3 + n * offSize, offSize);
+}
+
+Guint Type1CFontFile::getWord(Guchar *ptr, int size) {
+ Guint x;
+ int i;
+
+ x = 0;
+ for (i = 0; i < size; ++i) {
+ x = (x << 8) + *ptr++;
+ }
+ return x;
+}
+
+double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) {
+ static char nybChars[16] = "0123456789.ee -";
+ int b0, b, nyb0, nyb1;
+ double x;
+ char buf[65];
+ int i;
+
+ x = 0;
+ *isFP = gFalse;
+ b0 = (*ptr)[0];
+ if (b0 < 28) {
+ x = 0;
+ } else if (b0 == 28) {
+ x = ((*ptr)[1] << 8) + (*ptr)[2];
+ *ptr += 3;
+ } else if (b0 == 29) {
+ x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4];
+ *ptr += 5;
+ } else if (b0 == 30) {
+ *ptr += 1;
+ i = 0;
+ do {
+ b = *(*ptr)++;
+ nyb0 = b >> 4;
+ nyb1 = b & 0x0f;
+ if (nyb0 == 0xf) {
break;
- case 31: // hvcurveto
- if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
- error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps);
- for (k = 0; k < nOps && k != nOps-5; k += 4) {
- if (k % 8 == 0) {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpOp1(31);
- } else {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpOp1(30);
- }
- }
- if (k == nOps-5) {
- if (k % 8 == 0) {
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+4], fp[k+4]);
- eexecDumpNum(op[k+3], fp[k+3]);
- } else {
- eexecDumpNum(0, gFalse);
- eexecDumpNum(op[k], fp[k]);
- eexecDumpNum(op[k+1], fp[k+1]);
- eexecDumpNum(op[k+2], fp[k+2]);
- eexecDumpNum(op[k+3], fp[k+3]);
- eexecDumpNum(op[k+4], fp[k+4]);
- }
- eexecDumpOp1(8);
- }
+ }
+ buf[i++] = nybChars[nyb0];
+ if (i == 64) {
break;
- case 1: // hstem
- if (first) {
- cvtGlyphWidth(nOps & 1);
- first = gFalse;
- }
- if (nOps & 1) {
- error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps);
+ }
+ if (nyb0 == 0xc) {
+ buf[i++] = '-';
+ }
+ if (i == 64) {
+ break;
+ }
+ if (nyb1 == 0xf) {
+ break;
+ }
+ buf[i++] = nybChars[nyb1];
+ if (i == 64) {
+ break;
+ }
+ if (nyb1 == 0xc) {
+ buf[i++] = '-';
+ }
+ } while (i < 64);
+ buf[i] = '\0';
+ x = atof(buf);
+ *isFP = gTrue;
+ } else if (b0 == 31) {
+ x = 0;
+ } else if (b0 < 247) {
+ x = b0 - 139;
+ *ptr += 1;
+ } else if (b0 < 251) {
+ x = ((b0 - 247) << 8) + (*ptr)[1] + 108;
+ *ptr += 2;
+ } else {
+ x = -((b0 - 251) << 8) - (*ptr)[1] - 108;
+ *ptr += 2;
+ }
+ return x;
+}
+
+char *Type1CFontFile::getString(int sid, char *buf) {
+ Guchar *idxPtr0, *idxPtr1;
+ int n;
+
+ if (sid < 391) {
+ strcpy(buf, type1CStdStrings[sid]);
+ } else {
+ sid -= 391;
+ idxPtr0 = getIndexValPtr(stringIdxPtr, sid);
+ idxPtr1 = getIndexValPtr(stringIdxPtr, sid + 1);
+ if ((n = idxPtr1 - idxPtr0) > 255) {
+ n = 255;
+ }
+ strncpy(buf, (char *)idxPtr0, n);
+ buf[n] = '\0';
+ }
+ return buf;
+}
+
+//------------------------------------------------------------------------
+// TrueTypeFontFile
+//------------------------------------------------------------------------
+
+//
+// Terminology
+// -----------
+//
+// character code = number used as an element of a text string
+//
+// character name = glyph name = name for a particular glyph within a
+// font
+//
+// glyph index = position (within some internal table in the font)
+// where the instructions to draw a particular glyph are
+// stored
+//
+// Type 1 fonts
+// ------------
+//
+// Type 1 fonts contain:
+//
+// Encoding: array of glyph names, maps char codes to glyph names
+//
+// Encoding[charCode] = charName
+//
+// CharStrings: dictionary of instructions, keyed by character names,
+// maps character name to glyph data
+//
+// CharStrings[charName] = glyphData
+//
+// TrueType fonts
+// --------------
+//
+// TrueType fonts contain:
+//
+// 'cmap' table: mapping from character code to glyph index; there may
+// be multiple cmaps in a TrueType font
+//
+// cmap[charCode] = glyphIdx
+//
+// 'post' table: mapping from glyph index to glyph name
+//
+// post[glyphIdx] = glyphName
+//
+// Type 42 fonts
+// -------------
+//
+// Type 42 fonts contain:
+//
+// Encoding: array of glyph names, maps char codes to glyph names
+//
+// Encoding[charCode] = charName
+//
+// CharStrings: dictionary of glyph indexes, keyed by character names,
+// maps character name to glyph index
+//
+// CharStrings[charName] = glyphIdx
+//
+
+struct TTFontTableHdr {
+ char tag[4];
+ Guint checksum;
+ Guint offset;
+ Guint length;
+};
+
+struct T42Table {
+ char *tag; // 4-byte tag
+ GBool required; // required by the TrueType spec?
+};
+
+// TrueType tables to be embedded in Type 42 fonts.
+// NB: the table names must be in alphabetical order here.
+#define nT42Tables 11
+static T42Table t42Tables[nT42Tables] = {
+ { "cvt ", gTrue },
+ { "fpgm", gTrue },
+ { "glyf", gTrue },
+ { "head", gTrue },
+ { "hhea", gTrue },
+ { "hmtx", gTrue },
+ { "loca", gTrue },
+ { "maxp", gTrue },
+ { "prep", gTrue },
+ { "vhea", gFalse },
+ { "vmtx", gFalse }
+};
+#define t42HeadTable 3
+#define t42LocaTable 6
+#define t42GlyfTable 2
+
+// Glyph names in some arbitrary standard that Apple uses for their
+// TrueType fonts.
+static char *macGlyphNames[258] = {
+ ".notdef",
+ "null",
+ "CR",
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quotesingle",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "grave",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "Adieresis",
+ "Aring",
+ "Ccedilla",
+ "Eacute",
+ "Ntilde",
+ "Odieresis",
+ "Udieresis",
+ "aacute",
+ "agrave",
+ "acircumflex",
+ "adieresis",
+ "atilde",
+ "aring",
+ "ccedilla",
+ "eacute",
+ "egrave",
+ "ecircumflex",
+ "edieresis",
+ "iacute",
+ "igrave",
+ "icircumflex",
+ "idieresis",
+ "ntilde",
+ "oacute",
+ "ograve",
+ "ocircumflex",
+ "odieresis",
+ "otilde",
+ "uacute",
+ "ugrave",
+ "ucircumflex",
+ "udieresis",
+ "dagger",
+ "degree",
+ "cent",
+ "sterling",
+ "section",
+ "bullet",
+ "paragraph",
+ "germandbls",
+ "registered",
+ "copyright",
+ "trademark",
+ "acute",
+ "dieresis",
+ "notequal",
+ "AE",
+ "Oslash",
+ "infinity",
+ "plusminus",
+ "lessequal",
+ "greaterequal",
+ "yen",
+ "mu1",
+ "partialdiff",
+ "summation",
+ "product",
+ "pi",
+ "integral",
+ "ordfeminine",
+ "ordmasculine",
+ "Ohm",
+ "ae",
+ "oslash",
+ "questiondown",
+ "exclamdown",
+ "logicalnot",
+ "radical",
+ "florin",
+ "approxequal",
+ "increment",
+ "guillemotleft",
+ "guillemotright",
+ "ellipsis",
+ "nbspace",
+ "Agrave",
+ "Atilde",
+ "Otilde",
+ "OE",
+ "oe",
+ "endash",
+ "emdash",
+ "quotedblleft",
+ "quotedblright",
+ "quoteleft",
+ "quoteright",
+ "divide",
+ "lozenge",
+ "ydieresis",
+ "Ydieresis",
+ "fraction",
+ "currency",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "daggerdbl",
+ "periodcentered",
+ "quotesinglbase",
+ "quotedblbase",
+ "perthousand",
+ "Acircumflex",
+ "Ecircumflex",
+ "Aacute",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Oacute",
+ "Ocircumflex",
+ "applelogo",
+ "Ograve",
+ "Uacute",
+ "Ucircumflex",
+ "Ugrave",
+ "dotlessi",
+ "circumflex",
+ "tilde",
+ "overscore",
+ "breve",
+ "dotaccent",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "Lslash",
+ "lslash",
+ "Scaron",
+ "scaron",
+ "Zcaron",
+ "zcaron",
+ "brokenbar",
+ "Eth",
+ "eth",
+ "Yacute",
+ "yacute",
+ "Thorn",
+ "thorn",
+ "minus",
+ "multiply",
+ "onesuperior",
+ "twosuperior",
+ "threesuperior",
+ "onehalf",
+ "onequarter",
+ "threequarters",
+ "franc",
+ "Gbreve",
+ "gbreve",
+ "Idot",
+ "Scedilla",
+ "scedilla",
+ "Cacute",
+ "cacute",
+ "Ccaron",
+ "ccaron",
+ "dmacron"
+};
+
+enum T42FontIndexMode {
+ t42FontModeUnicode,
+ t42FontModeCharCode,
+ t42FontModeCharCodeOffset,
+ t42FontModeMacRoman
+};
+
+TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
+ int pos, i;
+
+ file = fileA;
+ len = lenA;
+
+ encoding = NULL;
+
+ // read table directory
+ nTables = getUShort(4);
+ tableHdrs = (TTFontTableHdr *)gmalloc(nTables * sizeof(TTFontTableHdr));
+ pos = 12;
+ for (i = 0; i < nTables; ++i) {
+ tableHdrs[i].tag[0] = getByte(pos+0);
+ tableHdrs[i].tag[1] = getByte(pos+1);
+ tableHdrs[i].tag[2] = getByte(pos+2);
+ tableHdrs[i].tag[3] = getByte(pos+3);
+ tableHdrs[i].checksum = getULong(pos+4);
+ tableHdrs[i].offset = getULong(pos+8);
+ tableHdrs[i].length = getULong(pos+12);
+ pos += 16;
+ }
+
+ // check for tables that are required by both the TrueType spec
+ // and the Type 42 spec
+ if (seekTable("head") < 0 ||
+ seekTable("hhea") < 0 ||
+ seekTable("loca") < 0 ||
+ seekTable("maxp") < 0 ||
+ seekTable("glyf") < 0 ||
+ seekTable("hmtx") < 0) {
+ error(-1, "TrueType font file is missing a required table");
+ return;
+ }
+
+ // read the 'head' table
+ pos = seekTable("head");
+ bbox[0] = getShort(pos + 36);
+ bbox[1] = getShort(pos + 38);
+ bbox[2] = getShort(pos + 40);
+ bbox[3] = getShort(pos + 42);
+ locaFmt = getShort(pos + 50);
+
+ // read the 'maxp' table
+ pos = seekTable("maxp");
+ nGlyphs = getUShort(pos + 4);
+}
+
+TrueTypeFontFile::~TrueTypeFontFile() {
+ int i;
+
+ if (encoding) {
+ for (i = 0; i < 256; ++i) {
+ gfree(encoding[i]);
+ }
+ gfree(encoding);
+ }
+ gfree(tableHdrs);
+}
+
+char *TrueTypeFontFile::getName() {
+ return NULL;
+}
+
+char **TrueTypeFontFile::getEncoding() {
+ int cmap[256];
+ int nCmaps, cmapPlatform, cmapEncoding, cmapFmt;
+ int cmapLen, cmapOffset, cmapFirst;
+ int segCnt, segStart, segEnd, segDelta, segOffset;
+ int pos, i, j, k;
+ Guint fmt;
+ GString *s;
+ int stringIdx, stringPos, n;
+
+ if (encoding) {
+ return encoding;
+ }
+
+ //----- construct the (char code) -> (glyph idx) mapping
+
+ // map everything to the missing glyph
+ for (i = 0; i < 256; ++i) {
+ cmap[i] = 0;
+ }
+
+ // look for the 'cmap' table
+ if ((pos = seekTable("cmap")) >= 0) {
+ nCmaps = getUShort(pos+2);
+
+ // if the font has a Windows-symbol cmap, use it;
+ // otherwise, use the first cmap in the table
+ for (i = 0; i < nCmaps; ++i) {
+ cmapPlatform = getUShort(pos + 4 + 8*i);
+ cmapEncoding = getUShort(pos + 4 + 8*i + 2);
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ break;
+ }
+ }
+ if (i >= nCmaps) {
+ i = 0;
+ cmapPlatform = getUShort(pos + 4);
+ cmapEncoding = getUShort(pos + 4 + 2);
+ }
+ pos += getULong(pos + 4 + 8*i + 4);
+
+ // read the cmap
+ cmapFmt = getUShort(pos);
+ switch (cmapFmt) {
+ case 0: // byte encoding table (Apple standard)
+ cmapLen = getUShort(pos + 2);
+ for (i = 0; i < cmapLen && i < 256; ++i) {
+ cmap[i] = getByte(pos + 6 + i);
+ }
+ break;
+ case 4: // segment mapping to delta values (Microsoft standard)
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ // Windows-symbol uses char codes 0xf000 - 0xf0ff
+ cmapOffset = 0xf000;
+ } else {
+ cmapOffset = 0;
+ }
+ segCnt = getUShort(pos + 6) / 2;
+ for (i = 0; i < segCnt; ++i) {
+ segEnd = getUShort(pos + 14 + 2*i);
+ segStart = getUShort(pos + 16 + 2*segCnt + 2*i);
+ segDelta = getUShort(pos + 16 + 4*segCnt + 2*i);
+ segOffset = getUShort(pos + 16 + 6*segCnt + 2*i);
+ if (segStart - cmapOffset <= 0xff &&
+ segEnd - cmapOffset >= 0) {
+ for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset;
+ j <= segEnd && j - cmapOffset <= 0xff;
+ ++j) {
+ if (segOffset == 0) {
+ k = (j + segDelta) & 0xffff;
+ } else {
+ k = getUShort(pos + 16 + 6*segCnt + 2*i +
+ segOffset + 2 * (j - segStart));
+ if (k != 0) {
+ k = (k + segDelta) & 0xffff;
+ }
+ }
+ cmap[j - cmapOffset] = k;
+ }
}
- d = 0;
- dFP = gFalse;
- for (k = 0; k < nOps; k += 2) {
- if (op[k+1] < 0) {
- d += op[k] + op[k+1];
- dFP |= fp[k] | fp[k+1];
- eexecDumpNum(d, dFP);
- eexecDumpNum(-op[k+1], fp[k+1]);
+ }
+ break;
+ case 6: // trimmed table mapping
+ cmapFirst = getUShort(pos + 6);
+ cmapLen = getUShort(pos + 8);
+ for (i = cmapFirst; i < 256 && i < cmapFirst + cmapLen; ++i) {
+ cmap[i] = getUShort(pos + 10 + 2*i);
+ }
+ break;
+ default:
+ error(-1, "Unimplemented cmap format (%d) in TrueType font file",
+ cmapFmt);
+ break;
+ }
+ }
+
+ //----- construct the (glyph idx) -> (glyph name) mapping
+ //----- and compute the (char code) -> (glyph name) mapping
+
+ encoding = (char **)gmalloc(256 * sizeof(char *));
+ for (i = 0; i < 256; ++i) {
+ encoding[i] = NULL;
+ }
+
+ if ((pos = seekTable("post")) >= 0) {
+ fmt = getULong(pos);
+
+ // Apple font
+ if (fmt == 0x00010000) {
+ for (i = 0; i < 256; ++i) {
+ j = (cmap[i] < 258) ? cmap[i] : 0;
+ encoding[i] = copyString(macGlyphNames[j]);
+ }
+
+ // Microsoft font
+ } else if (fmt == 0x00020000) {
+ stringIdx = 0;
+ stringPos = pos + 34 + 2*nGlyphs;
+ for (i = 0; i < 256; ++i) {
+ if (cmap[i] < nGlyphs) {
+ j = getUShort(pos + 34 + 2 * cmap[i]);
+ if (j < 258) {
+ encoding[i] = copyString(macGlyphNames[j]);
} else {
- d += op[k];
- dFP |= fp[k];
- eexecDumpNum(d, dFP);
- eexecDumpNum(op[k+1], fp[k+1]);
- d += op[k+1];
- dFP |= fp[k+1];
+ j -= 258;
+ if (j != stringIdx) {
+ for (stringIdx = 0, stringPos = pos + 34 + 2*nGlyphs;
+ stringIdx < j;
+ ++stringIdx, stringPos += 1 + getByte(stringPos)) ;
+ }
+ n = getByte(stringPos);
+ s = new GString(file + stringPos + 1, n);
+ encoding[i] = copyString(s->getCString());
+ delete s;
+ ++stringIdx;
+ stringPos += 1 + n;
}
- eexecDumpOp1(1);
- }
- nHints += nOps / 2;
- break;
- case 3: // vstem
- if (first) {
- cvtGlyphWidth(nOps & 1);
- first = gFalse;
+ } else {
+ encoding[i] = copyString(macGlyphNames[0]);
}
- if (nOps & 1) {
- error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps);
+ }
+
+ // Apple subset
+ } else if (fmt == 0x000280000) {
+ for (i = 0; i < 256; ++i) {
+ if (cmap[i] < nGlyphs) {
+ j = i + getChar(pos + 32 + cmap[i]);
+ } else {
+ j = 0;
}
- d = 0;
- dFP = gFalse;
- for (k = 0; k < nOps; k += 2) {
- if (op[k+1] < 0) {
- d += op[k] + op[k+1];
- dFP |= fp[k] | fp[k+1];
- eexecDumpNum(d, dFP);
- eexecDumpNum(-op[k+1], fp[k+1]);
- } else {
- d += op[k];
- dFP |= fp[k];
- eexecDumpNum(d, dFP);
- eexecDumpNum(op[k+1], fp[k+1]);
- d += op[k+1];
- dFP |= fp[k+1];
+ encoding[i] = copyString(macGlyphNames[j]);
+ }
+
+ // Ugh, just assume the Apple glyph set
+ } else {
+ for (i = 0; i < 256; ++i) {
+ j = (cmap[i] < 258) ? cmap[i] : 0;
+ encoding[i] = copyString(macGlyphNames[j]);
+ }
+ }
+
+ // no "post" table: assume the Apple glyph set
+ } else {
+ for (i = 0; i < 256; ++i) {
+ j = (cmap[i] < 258) ? cmap[i] : 0;
+ encoding[i] = copyString(macGlyphNames[j]);
+ }
+ }
+
+ return encoding;
+}
+
+void TrueTypeFontFile::convertToType42(char *name, char **encodingA,
+ CharCodeToUnicode *toUnicode,
+ GBool pdfFontHasEncoding, FILE *out) {
+ // write the header
+ fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+
+ // begin the font dictionary
+ fprintf(out, "10 dict begin\n");
+ fprintf(out, "/FontName /%s def\n", name);
+ fprintf(out, "/FontType 42 def\n");
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ fprintf(out, "/PaintType 0 def\n");
+
+ // write the guts of the dictionary
+ cvtEncoding(encodingA, out);
+ cvtCharStrings(encodingA, toUnicode, pdfFontHasEncoding, out);
+ cvtSfnts(out, NULL);
+
+ // end the dictionary and define the font
+ fprintf(out, "FontName currentdict end definefont pop\n");
+}
+
+void TrueTypeFontFile::convertToCIDType2(char *name, Gushort *cidMap,
+ int nCIDs, FILE *out) {
+ Gushort cid;
+ int i, j, k;
+
+ // write the header
+ fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+
+ // begin the font dictionary
+ fprintf(out, "20 dict begin\n");
+ fprintf(out, "/CIDFontName /%s def\n", name);
+ fprintf(out, "/CIDFontType 2 def\n");
+ fprintf(out, "/FontType 42 def\n");
+ fprintf(out, "/CIDSystemInfo 3 dict dup begin\n");
+ fprintf(out, " /Registry (Adobe) def\n");
+ fprintf(out, " /Ordering (Identity) def\n");
+ fprintf(out, " /Supplement 0 def\n");
+ fprintf(out, " end def\n");
+ fprintf(out, "/GDBytes 2 def\n");
+ if (cidMap) {
+ fprintf(out, "/CIDCount %d def\n", nCIDs);
+ if (nCIDs > 32767) {
+ fprintf(out, "/CIDMap [");
+ for (i = 0; i < nCIDs; i += 32768 - 16) {
+ fprintf(out, "<\n");
+ for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
+ fprintf(out, " ");
+ for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
+ cid = cidMap[i+j+k];
+ fprintf(out, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
}
- eexecDumpOp1(3);
- }
- nHints += nOps / 2;
- break;
- case 18: // hstemhm
- //~ ignored
- if (first) {
- cvtGlyphWidth(nOps & 1);
- first = gFalse;
+ fprintf(out, "\n");
}
- if (nOps & 1) {
- error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps);
+ fprintf(out, " >");
+ }
+ fprintf(out, "\n");
+ fprintf(out, "] def\n");
+ } else {
+ fprintf(out, "/CIDMap <\n");
+ for (i = 0; i < nCIDs; i += 16) {
+ fprintf(out, " ");
+ for (j = 0; j < 16 && i+j < nCIDs; ++j) {
+ cid = cidMap[i+j];
+ fprintf(out, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
}
- nHints += nOps / 2;
+ fprintf(out, "\n");
+ }
+ fprintf(out, "> def\n");
+ }
+ } else {
+ // direct mapping - just fill the string(s) with s[i]=i
+ fprintf(out, "/CIDCount %d def\n", nGlyphs);
+ if (nGlyphs > 32767) {
+ fprintf(out, "/CIDMap [\n");
+ for (i = 0; i < nGlyphs; i += 32767) {
+ j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
+ fprintf(out, " %d string 0 1 %d {\n", 2 * j, j - 1);
+ fprintf(out, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
+ fprintf(out, " 1 index exch dup 2 mul 1 add exch %d add"
+ " 255 and put\n", i);
+ fprintf(out, " } for\n");
+ }
+ fprintf(out, "] def\n");
+ } else {
+ fprintf(out, "/CIDMap %d string\n", 2 * nGlyphs);
+ fprintf(out, " 0 1 %d {\n", nGlyphs - 1);
+ fprintf(out, " 2 copy dup 2 mul exch -8 bitshift put\n");
+ fprintf(out, " 1 index exch dup 2 mul 1 add exch 255 and put\n");
+ fprintf(out, " } for\n");
+ fprintf(out, "def\n");
+ }
+ }
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ fprintf(out, "/PaintType 0 def\n");
+ fprintf(out, "/Encoding [] readonly def\n");
+ fprintf(out, "/CharStrings 1 dict dup begin\n");
+ fprintf(out, " /.notdef 0 def\n");
+ fprintf(out, " end readonly def\n");
+
+ // write the guts of the dictionary
+ cvtSfnts(out, NULL);
+
+ // end the dictionary and define the font
+ fprintf(out, "CIDFontName currentdict end /CIDFont defineresource pop\n");
+}
+
+void TrueTypeFontFile::convertToType0(char *name, Gushort *cidMap,
+ int nCIDs, FILE *out) {
+ GString *sfntsName;
+ int n, i, j;
+
+ // write the Type 42 sfnts array
+ sfntsName = (new GString(name))->append("_sfnts");
+ cvtSfnts(out, sfntsName);
+ delete sfntsName;
+
+ // write the descendant Type 42 fonts
+ n = cidMap ? nCIDs : nGlyphs;
+ for (i = 0; i < n; i += 256) {
+ fprintf(out, "10 dict begin\n");
+ fprintf(out, "/FontName /%s_%02x def\n", name, i >> 8);
+ fprintf(out, "/FontType 42 def\n");
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ fprintf(out, "/PaintType 0 def\n");
+ fprintf(out, "/sfnts %s_sfnts def\n", name);
+ fprintf(out, "/Encoding 256 array\n");
+ for (j = 0; j < 256 && i+j < n; ++j) {
+ fprintf(out, "dup %d /c%02x put\n", j, j);
+ }
+ fprintf(out, "readonly def\n");
+ fprintf(out, "/CharStrings 257 dict dup begin\n");
+ fprintf(out, "/.notdef 0 def\n");
+ for (j = 0; j < 256 && i+j < n; ++j) {
+ fprintf(out, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
+ }
+ fprintf(out, "end readonly def\n");
+ fprintf(out, "FontName currentdict end definefont pop\n");
+ }
+
+ // write the Type 0 parent font
+ fprintf(out, "16 dict begin\n");
+ fprintf(out, "/FontName /%s def\n", name);
+ fprintf(out, "/FontType 0 def\n");
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/FMapType 2 def\n");
+ fprintf(out, "/Encoding [\n");
+ for (i = 0; i < n; i += 256) {
+ fprintf(out, "%d\n", i >> 8);
+ }
+ fprintf(out, "] def\n");
+ fprintf(out, "/FDepVector [\n");
+ for (i = 0; i < n; i += 256) {
+ fprintf(out, "/%s_%02x findfont\n", name, i >> 8);
+ }
+ fprintf(out, "] def\n");
+ fprintf(out, "FontName currentdict end definefont pop\n");
+}
+
+int TrueTypeFontFile::getByte(int pos) {
+ if (pos < 0 || pos >= len) {
+ return 0;
+ }
+ return file[pos] & 0xff;
+}
+
+int TrueTypeFontFile::getChar(int pos) {
+ int x;
+
+ if (pos < 0 || pos >= len) {
+ return 0;
+ }
+ x = file[pos] & 0xff;
+ if (x & 0x80)
+ x |= 0xffffff00;
+ return x;
+}
+
+int TrueTypeFontFile::getUShort(int pos) {
+ int x;
+
+ if (pos < 0 || pos+1 >= len) {
+ return 0;
+ }
+ x = file[pos] & 0xff;
+ x = (x << 8) + (file[pos+1] & 0xff);
+ return x;
+}
+
+int TrueTypeFontFile::getShort(int pos) {
+ int x;
+
+ if (pos < 0 || pos+1 >= len) {
+ return 0;
+ }
+ x = file[pos] & 0xff;
+ x = (x << 8) + (file[pos+1] & 0xff);
+ if (x & 0x8000)
+ x |= 0xffff0000;
+ return x;
+}
+
+Guint TrueTypeFontFile::getULong(int pos) {
+ int x;
+
+ if (pos < 0 || pos+3 >= len) {
+ return 0;
+ }
+ x = file[pos] & 0xff;
+ x = (x << 8) + (file[pos+1] & 0xff);
+ x = (x << 8) + (file[pos+2] & 0xff);
+ x = (x << 8) + (file[pos+3] & 0xff);
+ return x;
+}
+
+double TrueTypeFontFile::getFixed(int pos) {
+ int x, y;
+
+ x = getShort(pos);
+ y = getUShort(pos+2);
+ return (double)x + (double)y / 65536;
+}
+
+int TrueTypeFontFile::seekTable(char *tag) {
+ int i;
+
+ for (i = 0; i < nTables; ++i) {
+ if (!strncmp(tableHdrs[i].tag, tag, 4)) {
+ return tableHdrs[i].offset;
+ }
+ }
+ return -1;
+}
+
+int TrueTypeFontFile::seekTableIdx(char *tag) {
+ int i;
+
+ for (i = 0; i < nTables; ++i) {
+ if (!strncmp(tableHdrs[i].tag, tag, 4)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void TrueTypeFontFile::cvtEncoding(char **encodingA, FILE *out) {
+ char *name;
+ int i;
+
+ fprintf(out, "/Encoding 256 array\n");
+ for (i = 0; i < 256; ++i) {
+ if (!(name = encodingA[i])) {
+ name = ".notdef";
+ }
+ fprintf(out, "dup %d /%s put\n", i, name);
+ }
+ fprintf(out, "readonly def\n");
+}
+
+void TrueTypeFontFile::cvtCharStrings(char **encodingA,
+ CharCodeToUnicode *toUnicode,
+ GBool pdfFontHasEncoding, FILE *out) {
+ int unicodeCmap, macRomanCmap, msSymbolCmap;
+ int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapOffset;
+ T42FontIndexMode mode;
+ char *name;
+ Unicode u;
+ int pos, i, j, k;
+
+ // always define '.notdef'
+ fprintf(out, "/CharStrings 256 dict dup begin\n");
+ fprintf(out, "/.notdef 0 def\n");
+
+ // if there's no 'cmap' table, punt
+ if ((pos = seekTable("cmap")) < 0) {
+ goto err;
+ }
+
+ // To match up with the Adobe-defined behaviour, we choose a cmap
+ // like this:
+ // 1. If the PDF font has an encoding:
+ // 1a. If the TrueType font has a Microsoft Unicode cmap, use it,
+ // and use the Unicode indexes, not the char codes.
+ // 1b. If the TrueType font has a Macintosh Roman cmap, use it,
+ // and reverse map the char names through MacRomanEncoding to
+ // get char codes.
+ // 2. If the PDF font does not have an encoding:
+ // 2a. If the TrueType font has a Macintosh Roman cmap, use it,
+ // and use char codes directly.
+ // 2b. If the TrueType font has a Microsoft Symbol cmap, use it,
+ // and use (0xf000 + char code).
+ // 3. If none of these rules apply, use the first cmap and hope for
+ // the best (this shouldn't happen).
+ nCmaps = getUShort(pos+2);
+ unicodeCmap = macRomanCmap = msSymbolCmap = -1;
+ cmapOffset = 0;
+ for (i = 0; i < nCmaps; ++i) {
+ cmapPlatform = getUShort(pos + 4 + 8*i);
+ cmapEncoding = getUShort(pos + 4 + 8*i + 2);
+ if (cmapPlatform == 3 && cmapEncoding == 1) {
+ unicodeCmap = i;
+ } else if (cmapPlatform == 1 && cmapEncoding == 0) {
+ macRomanCmap = i;
+ } else if (cmapPlatform == 3 && cmapEncoding == 0) {
+ msSymbolCmap = i;
+ }
+ }
+ i = 0;
+ mode = t42FontModeCharCode;
+ if (pdfFontHasEncoding) {
+ if (unicodeCmap >= 0) {
+ i = unicodeCmap;
+ mode = t42FontModeUnicode;
+ } else if (macRomanCmap >= 0) {
+ i = macRomanCmap;
+ mode = t42FontModeMacRoman;
+ }
+ } else {
+ if (macRomanCmap >= 0) {
+ i = macRomanCmap;
+ mode = t42FontModeCharCode;
+ } else if (msSymbolCmap >= 0) {
+ i = msSymbolCmap;
+ mode = t42FontModeCharCodeOffset;
+ cmapOffset = 0xf000;
+ }
+ }
+ cmapPlatform = getUShort(pos + 4 + 8*i);
+ cmapEncoding = getUShort(pos + 4 + 8*i + 2);
+ pos += getULong(pos + 4 + 8*i + 4);
+ cmapFmt = getUShort(pos);
+ if (cmapFmt != 0 && cmapFmt != 4 && cmapFmt != 6) {
+ error(-1, "Unimplemented cmap format (%d) in TrueType font file",
+ cmapFmt);
+ goto err;
+ }
+
+ // map char name to glyph index:
+ // 1. use encoding to map name to char code
+ // 2. use cmap to map char code to glyph index
+ j = 0; // make gcc happy
+ for (i = 0; i < 256; ++i) {
+ name = encodingA[i];
+ if (name && strcmp(name, ".notdef")) {
+ switch (mode) {
+ case t42FontModeUnicode:
+ toUnicode->mapToUnicode((CharCode)i, &u, 1);
+ j = (int)u;
break;
- case 23: // vstemhm
- //~ ignored
- if (first) {
- cvtGlyphWidth(nOps & 1);
- first = gFalse;
- }
- if (nOps & 1) {
- error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps);
- }
- nHints += nOps / 2;
+ case t42FontModeCharCode:
+ j = i;
break;
- case 10: // callsubr
- case 11: // return
- case 16: // blend
- case 29: // callgsubr
- error(-1, "Unimplemented Type 2 charstring op: %d", s[i]);
+ case t42FontModeCharCodeOffset:
+ j = cmapOffset + i;
break;
- default:
- error(-1, "Illegal Type 2 charstring op: %d", s[i]);
+ case t42FontModeMacRoman:
+ j = globalParams->getMacRomanCharCode(name);
break;
}
- ++i;
- nOps = 0;
- } else if (s[i] <= 246) {
- if (nOps < 48) {
- fp[nOps] = gFalse;
- op[nOps++] = (int)s[i] - 139;
- }
- ++i;
- } else if (s[i] <= 250) {
- if (nOps < 48) {
- fp[nOps] = gFalse;
- op[nOps++] = (((int)s[i] - 247) << 8) + (int)s[i+1] + 108;
+ // note: Distiller (maybe Adobe's PS interpreter in general)
+ // doesn't like TrueType fonts that have CharStrings entries
+ // which point to nonexistent glyphs, hence the (k < nGlyphs)
+ // test
+ if ((k = getCmapEntry(cmapFmt, pos, j)) > 0 &&
+ k < nGlyphs) {
+ fprintf(out, "/%s %d def\n", name, k);
}
- i += 2;
- } else if (s[i] <= 254) {
- if (nOps < 48) {
- fp[nOps] = gFalse;
- op[nOps++] = -(((int)s[i] - 251) << 8) - (int)s[i+1] - 108;
+ }
+ }
+
+ err:
+ fprintf(out, "end readonly def\n");
+}
+
+int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) {
+ int cmapLen, cmapFirst;
+ int segCnt, segEnd, segStart, segDelta, segOffset;
+ int a, b, m, i;
+
+ switch (cmapFmt) {
+ case 0: // byte encoding table (Apple standard)
+ cmapLen = getUShort(pos + 2);
+ if (code >= cmapLen) {
+ return 0;
+ }
+ return getByte(pos + 6 + code);
+
+ case 4: // segment mapping to delta values (Microsoft standard)
+ segCnt = getUShort(pos + 6) / 2;
+ a = -1;
+ b = segCnt - 1;
+ segEnd = getUShort(pos + 14 + 2*b);
+ if (code > segEnd) {
+ // malformed font -- the TrueType spec requires the last segEnd
+ // to be 0xffff
+ return 0;
+ }
+ // invariant: seg[a].end < code <= seg[b].end
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ segEnd = getUShort(pos + 14 + 2*m);
+ if (segEnd < code) {
+ a = m;
+ } else {
+ b = m;
}
- i += 2;
+ }
+ segStart = getUShort(pos + 16 + 2*segCnt + 2*b);
+ segDelta = getUShort(pos + 16 + 4*segCnt + 2*b);
+ segOffset = getUShort(pos + 16 + 6*segCnt + 2*b);
+ if (segOffset == 0) {
+ i = (code + segDelta) & 0xffff;
} else {
- x = (s[i+1] << 24) | (s[i+2] << 16) | (s[i+3] << 8) | s[i+4];
- if (x & 0x80000000)
- x |= -1 << 31;
- if (nOps < 48) {
- fp[nOps] = gTrue;
- op[nOps++] = (double)x / 65536.0;
+ i = getUShort(pos + 16 + 6*segCnt + 2*b +
+ segOffset + 2 * (code - segStart));
+ if (i != 0) {
+ i = (i + segDelta) & 0xffff;
}
- i += 5;
}
- }
+ return i;
- sprintf(eBuf, "/%s %d RD ", name, charBuf->getLength());
- eexecWrite(eBuf);
- eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength());
- eexecWrite(" ND\n");
- delete charBuf;
-}
+ case 6: // trimmed table mapping
+ cmapFirst = getUShort(pos + 6);
+ cmapLen = getUShort(pos + 8);
+ if (code < cmapFirst || code >= cmapFirst + cmapLen) {
+ return 0;
+ }
+ return getUShort(pos + 10 + 2*(code - cmapFirst));
-void Type1CFontConverter::cvtGlyphWidth(GBool useOp) {
- double w;
- GBool wFP;
- int i;
+ default:
+ // shouldn't happen - this is checked earlier
+ break;
+ }
+ return 0;
+}
- if (useOp) {
- w = nominalWidthX + op[0];
- wFP = nominalWidthXFP | fp[0];
- for (i = 1; i < nOps; ++i) {
- op[i-1] = op[i];
- fp[i-1] = fp[i];
+void TrueTypeFontFile::cvtSfnts(FILE *out, GString *name) {
+ TTFontTableHdr newTableHdrs[nT42Tables];
+ char tableDir[12 + nT42Tables*16];
+ char headTable[54];
+ int *origLocaTable;
+ char *locaTable;
+ int nNewTables;
+ Guint checksum;
+ int pos, glyfPos, length, glyphLength, pad;
+ int i, j, k;
+
+ // construct the 'head' table, zero out the font checksum
+ memcpy(headTable, file + seekTable("head"), 54);
+ headTable[8] = headTable[9] = headTable[10] = headTable[11] = (char)0;
+
+ // read the original 'loca' table and construct the new one
+ // (pad each glyph out to a multiple of 4 bytes)
+ origLocaTable = (int *)gmalloc((nGlyphs + 1) * sizeof(int));
+ pos = seekTable("loca");
+ for (i = 0; i <= nGlyphs; ++i) {
+ if (locaFmt) {
+ origLocaTable[i] = getULong(pos + 4*i);
+ } else {
+ origLocaTable[i] = 2 * getUShort(pos + 2*i);
}
- --nOps;
+ }
+ locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
+ if (locaFmt) {
+ locaTable[0] = locaTable[1] = locaTable[2] = locaTable[3] = 0;
} else {
- w = defaultWidthX;
- wFP = defaultWidthXFP;
+ locaTable[0] = locaTable[1] = 0;
+ }
+ pos = 0;
+ for (i = 1; i <= nGlyphs; ++i) {
+ length = origLocaTable[i] - origLocaTable[i-1];
+ if (length & 3) {
+ length += 4 - (length & 3);
+ }
+ pos += length;
+ if (locaFmt) {
+ locaTable[4*i ] = (char)(pos >> 24);
+ locaTable[4*i+1] = (char)(pos >> 16);
+ locaTable[4*i+2] = (char)(pos >> 8);
+ locaTable[4*i+3] = (char) pos;
+ } else {
+ locaTable[2*i ] = (char)(pos >> 9);
+ locaTable[2*i+1] = (char)(pos >> 1);
+ }
}
- eexecDumpNum(0, gFalse);
- eexecDumpNum(w, wFP);
- eexecDumpOp1(13);
-}
-void Type1CFontConverter::eexecDumpNum(double x, GBool fp) {
- Guchar buf[12];
- int y, n;
+ // count the number of tables
+ nNewTables = 0;
+ for (i = 0; i < nT42Tables; ++i) {
+ if (t42Tables[i].required ||
+ seekTable(t42Tables[i].tag) >= 0) {
+ ++nNewTables;
+ }
+ }
- n = 0;
- if (fp) {
- if (x >= -32768 && x < 32768) {
- y = (int)(x * 256.0);
- buf[0] = 255;
- buf[1] = (Guchar)(y >> 24);
- buf[2] = (Guchar)(y >> 16);
- buf[3] = (Guchar)(y >> 8);
- buf[4] = (Guchar)y;
- buf[5] = 255;
- buf[6] = 0;
- buf[7] = 0;
- buf[8] = 1;
- buf[9] = 0;
- buf[10] = 12;
- buf[11] = 12;
- n = 12;
+ // construct the new table headers, including table checksums
+ // (pad each table out to a multiple of 4 bytes)
+ pos = 12 + nNewTables*16;
+ k = 0;
+ for (i = 0; i < nT42Tables; ++i) {
+ length = -1;
+ checksum = 0; // make gcc happy
+ if (i == t42HeadTable) {
+ length = 54;
+ checksum = computeTableChecksum(headTable, 54);
+ } else if (i == t42LocaTable) {
+ length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+ checksum = computeTableChecksum(locaTable, length);
+ } else if (i == t42GlyfTable) {
+ length = 0;
+ checksum = 0;
+ glyfPos = seekTable("glyf");
+ for (j = 0; j < nGlyphs; ++j) {
+ glyphLength = origLocaTable[j+1] - origLocaTable[j];
+ pad = (glyphLength & 3) ? 4 - (glyphLength & 3) : 0;
+ length += glyphLength + pad;
+ checksum += computeTableChecksum(file + glyfPos + origLocaTable[j],
+ glyphLength);
+ }
} else {
- error(-1, "Type 2 fixed point constant out of range");
+ if ((j = seekTableIdx(t42Tables[i].tag)) >= 0) {
+ length = tableHdrs[j].length;
+ checksum = computeTableChecksum(file + tableHdrs[j].offset, length);
+ } else if (t42Tables[i].required) {
+ error(-1, "Embedded TrueType font is missing a required table ('%s')",
+ t42Tables[i].tag);
+ length = 0;
+ checksum = 0;
+ }
+ }
+ if (length >= 0) {
+ strncpy(newTableHdrs[k].tag, t42Tables[i].tag, 4);
+ newTableHdrs[k].checksum = checksum;
+ newTableHdrs[k].offset = pos;
+ newTableHdrs[k].length = length;
+ pad = (length & 3) ? 4 - (length & 3) : 0;
+ pos += length + pad;
+ ++k;
}
+ }
+
+ // construct the table directory
+ tableDir[0] = 0x00; // sfnt version
+ tableDir[1] = 0x01;
+ tableDir[2] = 0x00;
+ tableDir[3] = 0x00;
+ tableDir[4] = 0; // numTables
+ tableDir[5] = nNewTables;
+ tableDir[6] = 0; // searchRange
+ tableDir[7] = (char)128;
+ tableDir[8] = 0; // entrySelector
+ tableDir[9] = 3;
+ tableDir[10] = 0; // rangeShift
+ tableDir[11] = (char)(16 * nNewTables - 128);
+ pos = 12;
+ for (i = 0; i < nNewTables; ++i) {
+ tableDir[pos ] = newTableHdrs[i].tag[0];
+ tableDir[pos+ 1] = newTableHdrs[i].tag[1];
+ tableDir[pos+ 2] = newTableHdrs[i].tag[2];
+ tableDir[pos+ 3] = newTableHdrs[i].tag[3];
+ tableDir[pos+ 4] = (char)(newTableHdrs[i].checksum >> 24);
+ tableDir[pos+ 5] = (char)(newTableHdrs[i].checksum >> 16);
+ tableDir[pos+ 6] = (char)(newTableHdrs[i].checksum >> 8);
+ tableDir[pos+ 7] = (char) newTableHdrs[i].checksum;
+ tableDir[pos+ 8] = (char)(newTableHdrs[i].offset >> 24);
+ tableDir[pos+ 9] = (char)(newTableHdrs[i].offset >> 16);
+ tableDir[pos+10] = (char)(newTableHdrs[i].offset >> 8);
+ tableDir[pos+11] = (char) newTableHdrs[i].offset;
+ tableDir[pos+12] = (char)(newTableHdrs[i].length >> 24);
+ tableDir[pos+13] = (char)(newTableHdrs[i].length >> 16);
+ tableDir[pos+14] = (char)(newTableHdrs[i].length >> 8);
+ tableDir[pos+15] = (char) newTableHdrs[i].length;
+ pos += 16;
+ }
+
+ // compute the font checksum and store it in the head table
+ checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
+ for (i = 0; i < nNewTables; ++i) {
+ checksum += newTableHdrs[i].checksum;
+ }
+ checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
+ headTable[ 8] = (char)(checksum >> 24);
+ headTable[ 9] = (char)(checksum >> 16);
+ headTable[10] = (char)(checksum >> 8);
+ headTable[11] = (char) checksum;
+
+ // start the sfnts array
+ if (name) {
+ fprintf(out, "/%s [\n", name->getCString());
} else {
- y = (int)x;
- if (y >= -107 && y <= 107) {
- buf[0] = (Guchar)(y + 139);
- n = 1;
- } else if (y > 107 && y <= 1131) {
- y -= 108;
- buf[0] = (Guchar)((y >> 8) + 247);
- buf[1] = (Guchar)(y & 0xff);
- n = 2;
- } else if (y < -107 && y >= -1131) {
- y = -y - 108;
- buf[0] = (Guchar)((y >> 8) + 251);
- buf[1] = (Guchar)(y & 0xff);
- n = 2;
+ fprintf(out, "/sfnts [\n");
+ }
+
+ // write the table directory
+ dumpString(tableDir, 12 + nNewTables*16, out);
+
+ // write the tables
+ for (i = 0; i < nNewTables; ++i) {
+ if (i == t42HeadTable) {
+ dumpString(headTable, 54, out);
+ } else if (i == t42LocaTable) {
+ length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+ dumpString(locaTable, length, out);
+ } else if (i == t42GlyfTable) {
+ glyfPos = seekTable("glyf");
+ for (j = 0; j < nGlyphs; ++j) {
+ length = origLocaTable[j+1] - origLocaTable[j];
+ if (length > 0) {
+ dumpString(file + glyfPos + origLocaTable[j], length, out);
+ }
+ }
} else {
- buf[0] = 255;
- buf[1] = (Guchar)(y >> 24);
- buf[2] = (Guchar)(y >> 16);
- buf[3] = (Guchar)(y >> 8);
- buf[4] = (Guchar)y;
- n = 5;
+ // length == 0 means the table is missing and the error was
+ // already reported during the construction of the table
+ // headers
+ if ((length = newTableHdrs[i].length) > 0) {
+ dumpString(file + seekTable(t42Tables[i].tag), length, out);
+ }
}
}
- charBuf->append((char *)buf, n);
-}
-void Type1CFontConverter::eexecDumpOp1(int op) {
- charBuf->append((char)op);
-}
+ // end the sfnts array
+ fprintf(out, "] def\n");
-void Type1CFontConverter::eexecDumpOp2(int op) {
- charBuf->append((char)12);
- charBuf->append((char)op);
+ gfree(origLocaTable);
+ gfree(locaTable);
}
-void Type1CFontConverter::eexecWriteCharstring(Guchar *s, int n) {
- Gushort r2;
- Guchar x;
- int i;
+void TrueTypeFontFile::dumpString(char *s, int length, FILE *out) {
+ int pad, i, j;
- r2 = 4330;
+ fprintf(out, "<");
+ for (i = 0; i < length; i += 32) {
+ for (j = 0; j < 32 && i+j < length; ++j) {
+ fprintf(out, "%02X", s[i+j] & 0xff);
+ }
+ if (i % (65536 - 32) == 65536 - 64) {
+ fprintf(out, ">\n<");
+ } else if (i+32 < length) {
+ fprintf(out, "\n");
+ }
+ }
+ if (length & 3) {
+ pad = 4 - (length & 3);
+ for (i = 0; i < pad; ++i) {
+ fprintf(out, "00");
+ }
+ }
+ // add an extra zero byte because the Adobe Type 42 spec says so
+ fprintf(out, "00>\n");
+}
- for (i = 0; i < n; ++i) {
- // charstring encryption
- x = s[i];
- x ^= (r2 >> 8);
- r2 = (x + r2) * 52845 + 22719;
+Guint TrueTypeFontFile::computeTableChecksum(char *data, int length) {
+ Guint checksum, word;
+ int i;
- // eexec encryption
- x ^= (r1 >> 8);
- r1 = (x + r1) * 52845 + 22719;
- fputc(hexChars[x >> 4], out);
- fputc(hexChars[x & 0x0f], out);
- line += 2;
- if (line == 64) {
- fputc('\n', out);
- line = 0;
+ checksum = 0;
+ for (i = 0; i+3 < length; i += 4) {
+ word = ((data[i ] & 0xff) << 24) +
+ ((data[i+1] & 0xff) << 16) +
+ ((data[i+2] & 0xff) << 8) +
+ (data[i+3] & 0xff);
+ checksum += word;
+ }
+ if (length & 3) {
+ word = 0;
+ i = length & ~3;
+ switch (length & 3) {
+ case 3:
+ word |= (data[i+2] & 0xff) << 8;
+ case 2:
+ word |= (data[i+1] & 0xff) << 16;
+ case 1:
+ word |= (data[i ] & 0xff) << 24;
+ break;
}
+ checksum += word;
}
+ return checksum;
}
-void Type1CFontConverter::getDeltaInt(char *buf, char *name, double *op,
- int n) {
- int x, i;
+void TrueTypeFontFile::writeTTF(FILE *out) {
+ static char cmapTab[20] = {
+ 0, 0, // table version number
+ 0, 1, // number of encoding tables
+ 0, 1, // platform ID
+ 0, 0, // encoding ID
+ 0, 0, 0, 12, // offset of subtable
+ 0, 0, // subtable format
+ 0, 1, // subtable length
+ 0, 1, // subtable version
+ 0, // map char 0 -> glyph 0
+ 0 // pad to multiple of four bytes
+ };
+ static char nameTab[8] = {
+ 0, 0, // format
+ 0, 0, // number of name records
+ 0, 6, // offset to start of string storage
+ 0, 0 // pad to multiple of four bytes
+ };
+ static char postTab[32] = {
+ 0, 1, 0, 0, // format
+ 0, 0, 0, 0, // italic angle
+ 0, 0, // underline position
+ 0, 0, // underline thickness
+ 0, 0, 0, 0, // fixed pitch
+ 0, 0, 0, 0, // min Type 42 memory
+ 0, 0, 0, 0, // max Type 42 memory
+ 0, 0, 0, 0, // min Type 1 memory
+ 0, 0, 0, 0 // max Type 1 memory
+ };
+ GBool haveCmap, haveName, havePost;
+ GBool dirCmap, dirName, dirPost;
+ int nNewTables, nAllTables, pad;
+ char *tableDir;
+ Guint t, pos;
+ int i, j;
+
+ // check for missing tables
+ haveCmap = seekTable("cmap") >= 0;
+ haveName = seekTable("name") >= 0;
+ havePost = seekTable("post") >= 0;
+ nNewTables = (haveCmap ? 0 : 1) + (haveName ? 0 : 1) + (havePost ? 0 : 1);
+ if (!nNewTables) {
+ // none are missing - write the TTF file as is
+ fwrite(file, 1, len, out);
+ return;
+ }
- sprintf(buf, "/%s [", name);
- buf += strlen(buf);
- x = 0;
- for (i = 0; i < n; ++i) {
- x += (int)op[i];
- sprintf(buf, "%s%d", i > 0 ? " " : "", x);
- buf += strlen(buf);
+ // construct the new table directory
+ nAllTables = nTables + nNewTables;
+ tableDir = (char *)gmalloc(12 + nAllTables * 16);
+ memcpy(tableDir, file, 12 + nTables * 16);
+ tableDir[4] = (char)((nAllTables >> 8) & 0xff);
+ tableDir[5] = (char)(nAllTables & 0xff);
+ for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ;
+ t = 1 << (4 + i);
+ tableDir[6] = (char)((t >> 8) & 0xff);
+ tableDir[7] = (char)(t & 0xff);
+ tableDir[8] = (char)((i >> 8) & 0xff);
+ tableDir[9] = (char)(i & 0xff);
+ t = nAllTables * 16 - t;
+ tableDir[10] = (char)((t >> 8) & 0xff);
+ tableDir[11] = (char)(t & 0xff);
+ dirCmap = haveCmap;
+ dirName = haveName;
+ dirPost = havePost;
+ j = 0;
+ pad = (len & 3) ? 4 - (len & 3) : 0;
+ pos = len + pad + 16 * nNewTables;
+ for (i = 0; i < nTables; ++i) {
+ if (!dirCmap && strncmp(tableHdrs[i].tag, "cmap", 4) > 0) {
+ tableDir[12 + 16*j ] = 'c';
+ tableDir[12 + 16*j + 1] = 'm';
+ tableDir[12 + 16*j + 2] = 'a';
+ tableDir[12 + 16*j + 3] = 'p';
+ tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
+ tableDir[12 + 16*j + 5] = (char)0;
+ tableDir[12 + 16*j + 6] = (char)0;
+ tableDir[12 + 16*j + 7] = (char)0;
+ tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
+ tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff);
+ tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff);
+ tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >> 8) & 0xff);
+ tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab) & 0xff);
+ pos += sizeof(cmapTab);
+ ++j;
+ dirCmap = gTrue;
+ }
+ if (!dirName && strncmp(tableHdrs[i].tag, "name", 4) > 0) {
+ tableDir[12 + 16*j ] = 'n';
+ tableDir[12 + 16*j + 1] = 'a';
+ tableDir[12 + 16*j + 2] = 'm';
+ tableDir[12 + 16*j + 3] = 'e';
+ tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
+ tableDir[12 + 16*j + 5] = (char)0;
+ tableDir[12 + 16*j + 6] = (char)0;
+ tableDir[12 + 16*j + 7] = (char)0;
+ tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
+ tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff);
+ tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff);
+ tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >> 8) & 0xff);
+ tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab) & 0xff);
+ pos += sizeof(nameTab);
+ ++j;
+ dirName = gTrue;
+ }
+ if (!dirName && strncmp(tableHdrs[i].tag, "post", 4) > 0) {
+ tableDir[12 + 16*j ] = 'p';
+ tableDir[12 + 16*j + 1] = 'o';
+ tableDir[12 + 16*j + 2] = 's';
+ tableDir[12 + 16*j + 3] = 't';
+ tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
+ tableDir[12 + 16*j + 5] = (char)0;
+ tableDir[12 + 16*j + 6] = (char)0;
+ tableDir[12 + 16*j + 7] = (char)0;
+ tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
+ tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff);
+ tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff);
+ tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >> 8) & 0xff);
+ tableDir[12 + 16*j + 15] = (char)( sizeof(postTab) & 0xff);
+ pos += sizeof(postTab);
+ ++j;
+ dirPost = gTrue;
+ }
+ memcpy(&tableDir[12 + 16*j], file + 12 + 16*i, 16);
+ t = tableHdrs[i].offset + nNewTables * 16;
+ tableDir[12 + 16*j + 8] = (char)((t >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((t >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((t >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( t & 0xff);
+ ++j;
+ }
+ if (!dirCmap) {
+ tableDir[12 + 16*j ] = 'c';
+ tableDir[12 + 16*j + 1] = 'm';
+ tableDir[12 + 16*j + 2] = 'a';
+ tableDir[12 + 16*j + 3] = 'p';
+ tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
+ tableDir[12 + 16*j + 5] = (char)0;
+ tableDir[12 + 16*j + 6] = (char)0;
+ tableDir[12 + 16*j + 7] = (char)0;
+ tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
+ tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff);
+ tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff);
+ tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >> 8) & 0xff);
+ tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab) & 0xff);
+ pos += sizeof(cmapTab);
+ ++j;
+ dirCmap = gTrue;
+ }
+ if (!dirName) {
+ tableDir[12 + 16*j ] = 'n';
+ tableDir[12 + 16*j + 1] = 'a';
+ tableDir[12 + 16*j + 2] = 'm';
+ tableDir[12 + 16*j + 3] = 'e';
+ tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
+ tableDir[12 + 16*j + 5] = (char)0;
+ tableDir[12 + 16*j + 6] = (char)0;
+ tableDir[12 + 16*j + 7] = (char)0;
+ tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
+ tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff);
+ tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff);
+ tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >> 8) & 0xff);
+ tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab) & 0xff);
+ pos += sizeof(nameTab);
+ ++j;
+ dirName = gTrue;
+ }
+ if (!dirPost) {
+ tableDir[12 + 16*j ] = 'p';
+ tableDir[12 + 16*j + 1] = 'o';
+ tableDir[12 + 16*j + 2] = 's';
+ tableDir[12 + 16*j + 3] = 't';
+ tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum
+ tableDir[12 + 16*j + 5] = (char)0;
+ tableDir[12 + 16*j + 6] = (char)0;
+ tableDir[12 + 16*j + 7] = (char)0;
+ tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff);
+ tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff);
+ tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff);
+ tableDir[12 + 16*j + 11] = (char)( pos & 0xff);
+ tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff);
+ tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff);
+ tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >> 8) & 0xff);
+ tableDir[12 + 16*j + 15] = (char)( sizeof(postTab) & 0xff);
+ pos += sizeof(postTab);
+ ++j;
+ dirPost = gTrue;
}
- sprintf(buf, "] def\n");
-}
-void Type1CFontConverter::getDeltaReal(char *buf, char *name, double *op,
- int n) {
- double x;
- int i;
+ // write the table directory
+ fwrite(tableDir, 1, 12 + 16 * nAllTables, out);
- sprintf(buf, "/%s [", name);
- buf += strlen(buf);
- x = 0;
- for (i = 0; i < n; ++i) {
- x += op[i];
- sprintf(buf, "%s%g", i > 0 ? " " : "", x);
- buf += strlen(buf);
+ // write the original tables
+ fwrite(file + 12 + 16*nTables, 1, len - (12 + 16*nTables), out);
+
+ // write the new tables
+ for (i = 0; i < pad; ++i) {
+ fputc((char)0, out);
}
- sprintf(buf, "] def\n");
+ if (!haveCmap) {
+ fwrite(cmapTab, 1, sizeof(cmapTab), out);
+ }
+ if (!haveName) {
+ fwrite(nameTab, 1, sizeof(nameTab), out);
+ }
+ if (!havePost) {
+ fwrite(postTab, 1, sizeof(postTab), out);
+ }
+
+ gfree(tableDir);
}
//
// FontFile.h
//
-// Copyright 1999 Derek B. Noonburg
+// Copyright 1999-2002 Glyph & Cog, LLC
//
//========================================================================
#include <stdio.h>
#include "gtypes.h"
#include "GString.h"
-#include "FontEncoding.h"
+#include "CharTypes.h"
+
+class CharCodeToUnicode;
//------------------------------------------------------------------------
// FontFile
// Returns NULL if no name is available.
virtual char *getName() = 0;
- // Returns the custom font encoding, or NULL if the encoding is
- // not available. If <taken> is set, the caller of this function
- // will be responsible for freeing the encoding object.
- virtual FontEncoding *getEncoding(GBool taken) = 0;
+ // Returns the custom font encoding, or NULL if the encoding is not
+ // available.
+ virtual char **getEncoding() = 0;
};
//------------------------------------------------------------------------
Type1FontFile(char *file, int len);
virtual ~Type1FontFile();
virtual char *getName() { return name; }
- virtual FontEncoding *getEncoding(GBool taken);
+ virtual char **getEncoding() { return encoding; }
private:
char *name;
- FontEncoding *encoding;
- GBool freeEnc;
+ char **encoding;
};
//------------------------------------------------------------------------
// Type1CFontFile
//------------------------------------------------------------------------
+struct Type1CTopDict;
+struct Type1CPrivateDict;
+
class Type1CFontFile: public FontFile {
public:
- Type1CFontFile(char *file, int len);
+ Type1CFontFile(char *fileA, int lenA);
virtual ~Type1CFontFile();
- virtual char *getName() { return name; }
- virtual FontEncoding *getEncoding(GBool taken);
-private:
-
- char *name;
- FontEncoding *encoding;
- GBool freeEnc;
-};
+ virtual char *getName();
+ virtual char **getEncoding();
-//------------------------------------------------------------------------
-// Type1CFontConverter
-//------------------------------------------------------------------------
+ // Convert to a Type 1 font, suitable for embedding in a PostScript
+ // file. The name will be used as the PostScript font name.
+ void convertToType1(FILE *outA);
-class Type1CFontConverter {
-public:
+ // Convert to a Type 0 CIDFont, suitable for embedding in a
+ // PostScript file. The name will be used as the PostScript font
+ // name.
+ void convertToCIDType0(char *psName, FILE *outA);
- Type1CFontConverter(char *file, int len, FILE *out);
- ~Type1CFontConverter();
- void convert();
+ // Convert to a Type 0 (but non-CID) composite font, suitable for
+ // embedding in a PostScript file. The name will be used as the
+ // PostScript font name.
+ void convertToType0(char *psName, FILE *outA);
private:
+ void readNameAndEncoding();
+ void readTopDict(Type1CTopDict *dict);
+ void readPrivateDict(Type1CPrivateDict *privateDict,
+ int offset, int size);
+ Gushort *readCharset(int charset, int nGlyphs);
void eexecWrite(char *s);
- void cvtGlyph(char *name, Guchar *s, int n);
+ void eexecCvtGlyph(char *glyphName, Guchar *s, int n);
+ void cvtGlyph(Guchar *s, int n);
void cvtGlyphWidth(GBool useOp);
- void eexecDumpNum(double x, GBool fp);
- void eexecDumpOp1(int op);
- void eexecDumpOp2(int op);
+ void eexecDumpNum(double x, GBool fpA);
+ void eexecDumpOp1(int opA);
+ void eexecDumpOp2(int opA);
void eexecWriteCharstring(Guchar *s, int n);
- void getDeltaInt(char *buf, char *name, double *op, int n);
- void getDeltaReal(char *buf, char *name, double *op, int n);
+ void getDeltaInt(char *buf, char *key, double *opA, int n);
+ void getDeltaReal(char *buf, char *key, double *opA, int n);
+ int getIndexLen(Guchar *indexPtr);
+ Guchar *getIndexValPtr(Guchar *indexPtr, int i);
+ Guchar *getIndexEnd(Guchar *indexPtr);
+ Guint getWord(Guchar *ptr, int size);
+ double getNum(Guchar **ptr, GBool *fp);
+ char *getString(int sid, char *buf);
char *file;
int len;
+
+ GString *name;
+ char **encoding;
+
+ int topOffSize;
+ Guchar *topDictIdxPtr;
+ Guchar *stringIdxPtr;
+ Guchar *gsubrIdxPtr;
+
FILE *out;
double op[48]; // operands
GBool fp[48]; // true if operand is fixed point
int line; // number of eexec chars on current line
};
+//------------------------------------------------------------------------
+// TrueTypeFontFile
+//------------------------------------------------------------------------
+
+struct TTFontTableHdr;
+
+class TrueTypeFontFile: public FontFile {
+public:
+
+ TrueTypeFontFile(char *fileA, int lenA);
+ ~TrueTypeFontFile();
+
+ // This always returns NULL, since it's probably better to trust the
+ // font name in the PDF file rather than the one in the TrueType
+ // font file.
+ virtual char *getName();
+
+ virtual char **getEncoding();
+
+ // Convert to a Type 42 font, suitable for embedding in a PostScript
+ // file. The name will be used as the PostScript font name (so we
+ // don't need to depend on the 'name' table in the font). The
+ // encoding is needed because the PDF Font object can modify the
+ // encoding.
+ void convertToType42(char *name, char **encodingA,
+ CharCodeToUnicode *toUnicode,
+ GBool pdfFontHasEncoding, FILE *out);
+
+ // Convert to a Type 2 CIDFont, suitable for embedding in a
+ // PostScript file. The name will be used as the PostScript font
+ // name (so we don't need to depend on the 'name' table in the
+ // font).
+ void convertToCIDType2(char *name, Gushort *cidMap,
+ int nCIDs, FILE *out);
+
+ // Convert to a Type 0 (but non-CID) composite font, suitable for
+ // embedding in a PostScript file. The name will be used as the
+ // PostScript font name (so we don't need to depend on the 'name'
+ // table in the font).
+ void convertToType0(char *name, Gushort *cidMap,
+ int nCIDs, FILE *out);
+
+ // Write a TTF file, filling in any missing tables that are required
+ // by the TrueType spec. If the font already has all the required
+ // tables, it will be written unmodified.
+ void writeTTF(FILE *out);
+
+private:
+
+ char *file;
+ int len;
+
+ char **encoding;
+
+ TTFontTableHdr *tableHdrs;
+ int nTables;
+ int bbox[4];
+ int locaFmt;
+ int nGlyphs;
+
+ int getByte(int pos);
+ int getChar(int pos);
+ int getUShort(int pos);
+ int getShort(int pos);
+ Guint getULong(int pos);
+ double getFixed(int pos);
+ int seekTable(char *tag);
+ int seekTableIdx(char *tag);
+ void cvtEncoding(char **encodingA, FILE *out);
+ void cvtCharStrings(char **encodingA, CharCodeToUnicode *toUnicode,
+ GBool pdfFontHasEncoding, FILE *out);
+ int getCmapEntry(int cmapFmt, int pos, int code);
+ void cvtSfnts(FILE *out, GString *name);
+ void dumpString(char *s, int length, FILE *out);
+ Guint computeTableChecksum(char *data, int length);
+};
+
#endif
+++ /dev/null
-//========================================================================
-//
-// FontInfo.h
-//
-// This file was automatically generated by makeFontInfo.
-//
-// Copyright 1996 Derek B. Noonburg
-//
-//========================================================================
-
-#ifndef FONTINFO_H
-#define FONTINFO_H
-
-//------------------------------------------------------------------------
-// Character encodings.
-//------------------------------------------------------------------------
-
-#define standardEncodingSize 335
-char *standardEncodingNames[standardEncodingSize] = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "space",
- "exclam",
- "quotedbl",
- "numbersign",
- "dollar",
- "percent",
- "ampersand",
- "quoteright",
- "parenleft",
- "parenright",
- "asterisk",
- "plus",
- "comma",
- "hyphen",
- "period",
- "slash",
- "zero",
- "one",
- "two",
- "three",
- "four",
- "five",
- "six",
- "seven",
- "eight",
- "nine",
- "colon",
- "semicolon",
- "less",
- "equal",
- "greater",
- "question",
- "at",
- "A",
- "B",
- "C",
- "D",
- "E",
- "F",
- "G",
- "H",
- "I",
- "J",
- "K",
- "L",
- "M",
- "N",
- "O",
- "P",
- "Q",
- "R",
- "S",
- "T",
- "U",
- "V",
- "W",
- "X",
- "Y",
- "Z",
- "bracketleft",
- "backslash",
- "bracketright",
- "asciicircum",
- "underscore",
- "quoteleft",
- "a",
- "b",
- "c",
- "d",
- "e",
- "f",
- "g",
- "h",
- "i",
- "j",
- "k",
- "l",
- "m",
- "n",
- "o",
- "p",
- "q",
- "r",
- "s",
- "t",
- "u",
- "v",
- "w",
- "x",
- "y",
- "z",
- "braceleft",
- "bar",
- "braceright",
- "asciitilde",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "exclamdown",
- "cent",
- "sterling",
- "fraction",
- "yen",
- "florin",
- "section",
- "currency",
- "quotesingle",
- "quotedblleft",
- "guillemotleft",
- "guilsinglleft",
- "guilsinglright",
- "fi",
- "fl",
- NULL,
- "endash",
- "dagger",
- "daggerdbl",
- "periodcentered",
- NULL,
- "paragraph",
- "bullet",
- "quotesinglbase",
- "quotedblbase",
- "quotedblright",
- "guillemotright",
- "ellipsis",
- "perthousand",
- NULL,
- "questiondown",
- NULL,
- "grave",
- "acute",
- "circumflex",
- "tilde",
- "macron",
- "breve",
- "dotaccent",
- "dieresis",
- NULL,
- "ring",
- "cedilla",
- NULL,
- "hungarumlaut",
- "ogonek",
- "caron",
- "emdash",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "AE",
- NULL,
- "ordfeminine",
- NULL,
- NULL,
- NULL,
- NULL,
- "Lslash",
- "Oslash",
- "OE",
- "ordmasculine",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "ae",
- NULL,
- NULL,
- NULL,
- "dotlessi",
- NULL,
- NULL,
- "lslash",
- "oslash",
- "oe",
- "germandbls",
- NULL,
- NULL,
- NULL,
- NULL,
- "Aacute",
- "Acircumflex",
- "Adieresis",
- "Agrave",
- "Aring",
- "Atilde",
- "Ccedilla",
- "Eacute",
- "Ecircumflex",
- "Edieresis",
- "Egrave",
- "Eth",
- "Iacute",
- "Icircumflex",
- "Idieresis",
- "Igrave",
- "Ntilde",
- "Oacute",
- "Ocircumflex",
- "Odieresis",
- "Ograve",
- "Otilde",
- "Scaron",
- "Thorn",
- "Uacute",
- "Ucircumflex",
- "Udieresis",
- "Ugrave",
- "Yacute",
- "Ydieresis",
- "Zcaron",
- "aacute",
- "acircumflex",
- "adieresis",
- "agrave",
- "aring",
- "atilde",
- "brokenbar",
- "ccedilla",
- "copyright",
- "degree",
- "divide",
- "eacute",
- "ecircumflex",
- "edieresis",
- "egrave",
- "eth",
- "iacute",
- "icircumflex",
- "idieresis",
- "igrave",
- "logicalnot",
- "minus",
- "mu",
- "multiply",
- "ntilde",
- "oacute",
- "ocircumflex",
- "odieresis",
- "ograve",
- "onehalf",
- "onequarter",
- "onesuperior",
- "otilde",
- "plusminus",
- "registered",
- "scaron",
- "thorn",
- "threequarters",
- "threesuperior",
- "trademark",
- "twosuperior",
- "uacute",
- "ucircumflex",
- "udieresis",
- "ugrave",
- "yacute",
- "ydieresis",
- "zcaron"
-};
-static FontEncoding standardEncoding(standardEncodingNames,
- standardEncodingSize);
-
-#define symbolEncodingSize 257
-char *symbolEncodingNames[symbolEncodingSize] = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "space",
- "exclam",
- "universal",
- "numbersign",
- "existential",
- "percent",
- "ampersand",
- "suchthat",
- "parenleft",
- "parenright",
- "asteriskmath",
- "plus",
- "comma",
- "minus",
- "period",
- "slash",
- "zero",
- "one",
- "two",
- "three",
- "four",
- "five",
- "six",
- "seven",
- "eight",
- "nine",
- "colon",
- "semicolon",
- "less",
- "equal",
- "greater",
- "question",
- "congruent",
- "Alpha",
- "Beta",
- "Chi",
- "Delta",
- "Epsilon",
- "Phi",
- "Gamma",
- "Eta",
- "Iota",
- "theta1",
- "Kappa",
- "Lambda",
- "Mu",
- "Nu",
- "Omicron",
- "Pi",
- "Theta",
- "Rho",
- "Sigma",
- "Tau",
- "Upsilon",
- "sigma1",
- "Omega",
- "Xi",
- "Psi",
- "Zeta",
- "bracketleft",
- "therefore",
- "bracketright",
- "perpendicular",
- "underscore",
- "radicalex",
- "alpha",
- "beta",
- "chi",
- "delta",
- "epsilon",
- "phi",
- "gamma",
- "eta",
- "iota",
- "phi1",
- "kappa",
- "lambda",
- "mu",
- "nu",
- "omicron",
- "pi",
- "theta",
- "rho",
- "sigma",
- "tau",
- "upsilon",
- "omega1",
- "omega",
- "xi",
- "psi",
- "zeta",
- "braceleft",
- "bar",
- "braceright",
- "similar",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "Upsilon1",
- "minute",
- "lessequal",
- "fraction",
- "infinity",
- "florin",
- "club",
- "diamond",
- "heart",
- "spade",
- "arrowboth",
- "arrowleft",
- "arrowup",
- "arrowright",
- "arrowdown",
- "degree",
- "plusminus",
- "second",
- "greaterequal",
- "multiply",
- "proportional",
- "partialdiff",
- "bullet",
- "divide",
- "notequal",
- "equivalence",
- "approxequal",
- "ellipsis",
- "arrowvertex",
- "arrowhorizex",
- "carriagereturn",
- "aleph",
- "Ifraktur",
- "Rfraktur",
- "weierstrass",
- "circlemultiply",
- "circleplus",
- "emptyset",
- "intersection",
- "union",
- "propersuperset",
- "reflexsuperset",
- "notsubset",
- "propersubset",
- "reflexsubset",
- "element",
- "notelement",
- "angle",
- "gradient",
- "registerserif",
- "copyrightserif",
- "trademarkserif",
- "product",
- "radical",
- "dotmath",
- "logicalnot",
- "logicaland",
- "logicalor",
- "arrowdblboth",
- "arrowdblleft",
- "arrowdblup",
- "arrowdblright",
- "arrowdbldown",
- "lozenge",
- "angleleft",
- "registersans",
- "copyrightsans",
- "trademarksans",
- "summation",
- "parenlefttp",
- "parenleftex",
- "parenleftbt",
- "bracketlefttp",
- "bracketleftex",
- "bracketleftbt",
- "bracelefttp",
- "braceleftmid",
- "braceleftbt",
- "braceex",
- NULL,
- "angleright",
- "integral",
- "integraltp",
- "integralex",
- "integralbt",
- "parenrighttp",
- "parenrightex",
- "parenrightbt",
- "bracketrighttp",
- "bracketrightex",
- "bracketrightbt",
- "bracerighttp",
- "bracerightmid",
- "bracerightbt",
- NULL,
- "apple"
-};
-static FontEncoding symbolEncoding(symbolEncodingNames,
- symbolEncodingSize);
-
-#define zapfDingbatsEncodingSize 270
-char *zapfDingbatsEncodingNames[zapfDingbatsEncodingSize] = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "space",
- "a1",
- "a2",
- "a202",
- "a3",
- "a4",
- "a5",
- "a119",
- "a118",
- "a117",
- "a11",
- "a12",
- "a13",
- "a14",
- "a15",
- "a16",
- "a105",
- "a17",
- "a18",
- "a19",
- "a20",
- "a21",
- "a22",
- "a23",
- "a24",
- "a25",
- "a26",
- "a27",
- "a28",
- "a6",
- "a7",
- "a8",
- "a9",
- "a10",
- "a29",
- "a30",
- "a31",
- "a32",
- "a33",
- "a34",
- "a35",
- "a36",
- "a37",
- "a38",
- "a39",
- "a40",
- "a41",
- "a42",
- "a43",
- "a44",
- "a45",
- "a46",
- "a47",
- "a48",
- "a49",
- "a50",
- "a51",
- "a52",
- "a53",
- "a54",
- "a55",
- "a56",
- "a57",
- "a58",
- "a59",
- "a60",
- "a61",
- "a62",
- "a63",
- "a64",
- "a65",
- "a66",
- "a67",
- "a68",
- "a69",
- "a70",
- "a71",
- "a72",
- "a73",
- "a74",
- "a203",
- "a75",
- "a204",
- "a76",
- "a77",
- "a78",
- "a79",
- "a81",
- "a82",
- "a83",
- "a84",
- "a97",
- "a98",
- "a99",
- "a100",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "a101",
- "a102",
- "a103",
- "a104",
- "a106",
- "a107",
- "a108",
- "a112",
- "a111",
- "a110",
- "a109",
- "a120",
- "a121",
- "a122",
- "a123",
- "a124",
- "a125",
- "a126",
- "a127",
- "a128",
- "a129",
- "a130",
- "a131",
- "a132",
- "a133",
- "a134",
- "a135",
- "a136",
- "a137",
- "a138",
- "a139",
- "a140",
- "a141",
- "a142",
- "a143",
- "a144",
- "a145",
- "a146",
- "a147",
- "a148",
- "a149",
- "a150",
- "a151",
- "a152",
- "a153",
- "a154",
- "a155",
- "a156",
- "a157",
- "a158",
- "a159",
- "a160",
- "a161",
- "a163",
- "a164",
- "a196",
- "a165",
- "a192",
- "a166",
- "a167",
- "a168",
- "a169",
- "a170",
- "a171",
- "a172",
- "a173",
- "a162",
- "a174",
- "a175",
- "a176",
- "a177",
- "a178",
- "a179",
- "a193",
- "a180",
- "a199",
- "a181",
- "a200",
- "a182",
- NULL,
- "a201",
- "a183",
- "a184",
- "a197",
- "a185",
- "a194",
- "a198",
- "a186",
- "a195",
- "a187",
- "a188",
- "a189",
- "a190",
- "a191",
- NULL,
- "a205",
- "a206",
- "a85",
- "a86",
- "a87",
- "a88",
- "a89",
- "a90",
- "a91",
- "a92",
- "a93",
- "a94",
- "a95",
- "a96"
-};
-static FontEncoding zapfDingbatsEncoding(zapfDingbatsEncodingNames,
- zapfDingbatsEncodingSize);
-
-#define macRomanEncodingSize 256
-char *macRomanEncodingNames[macRomanEncodingSize] = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "space",
- "exclam",
- "quotedbl",
- "numbersign",
- "dollar",
- "percent",
- "ampersand",
- "quotesingle",
- "parenleft",
- "parenright",
- "asterisk",
- "plus",
- "comma",
- "hyphen",
- "period",
- "slash",
- "zero",
- "one",
- "two",
- "three",
- "four",
- "five",
- "six",
- "seven",
- "eight",
- "nine",
- "colon",
- "semicolon",
- "less",
- "equal",
- "greater",
- "question",
- "at",
- "A",
- "B",
- "C",
- "D",
- "E",
- "F",
- "G",
- "H",
- "I",
- "J",
- "K",
- "L",
- "M",
- "N",
- "O",
- "P",
- "Q",
- "R",
- "S",
- "T",
- "U",
- "V",
- "W",
- "X",
- "Y",
- "Z",
- "bracketleft",
- "backslash",
- "bracketright",
- "asciicircum",
- "underscore",
- "grave",
- "a",
- "b",
- "c",
- "d",
- "e",
- "f",
- "g",
- "h",
- "i",
- "j",
- "k",
- "l",
- "m",
- "n",
- "o",
- "p",
- "q",
- "r",
- "s",
- "t",
- "u",
- "v",
- "w",
- "x",
- "y",
- "z",
- "braceleft",
- "bar",
- "braceright",
- "asciitilde",
- NULL,
- "Adieresis",
- "Aring",
- "Ccedilla",
- "Eacute",
- "Ntilde",
- "Odieresis",
- "Udieresis",
- "aacute",
- "agrave",
- "acircumflex",
- "adieresis",
- "atilde",
- "aring",
- "ccedilla",
- "eacute",
- "egrave",
- "ecircumflex",
- "edieresis",
- "iacute",
- "igrave",
- "icircumflex",
- "idieresis",
- "ntilde",
- "oacute",
- "ograve",
- "ocircumflex",
- "odieresis",
- "otilde",
- "uacute",
- "ugrave",
- "ucircumflex",
- "udieresis",
- "dagger",
- "degree",
- "cent",
- "sterling",
- "section",
- "bullet",
- "paragraph",
- "germandbls",
- "registered",
- "copyright",
- "trademark",
- "acute",
- "dieresis",
- NULL,
- "AE",
- "Oslash",
- NULL,
- "plusminus",
- NULL,
- NULL,
- "yen",
- "mu",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "ordfeminine",
- "ordmasculine",
- NULL,
- "ae",
- "oslash",
- "questiondown",
- "exclamdown",
- "logicalnot",
- NULL,
- "florin",
- NULL,
- NULL,
- "guillemotleft",
- "guillemotright",
- "ellipsis",
- "space",
- "Agrave",
- "Atilde",
- "Otilde",
- "OE",
- "oe",
- "endash",
- "emdash",
- "quotedblleft",
- "quotedblright",
- "quoteleft",
- "quoteright",
- "divide",
- NULL,
- "ydieresis",
- "Ydieresis",
- "fraction",
- "currency",
- "guilsinglleft",
- "guilsinglright",
- "fi",
- "fl",
- "daggerdbl",
- "periodcentered",
- "quotesinglbase",
- "quotedblbase",
- "perthousand",
- "Acircumflex",
- "Ecircumflex",
- "Aacute",
- "Edieresis",
- "Egrave",
- "Iacute",
- "Icircumflex",
- "Idieresis",
- "Igrave",
- "Oacute",
- "Ocircumflex",
- NULL,
- "Ograve",
- "Uacute",
- "Ucircumflex",
- "Ugrave",
- "dotlessi",
- "circumflex",
- "tilde",
- "macron",
- "breve",
- "dotaccent",
- "ring",
- "cedilla",
- "hungarumlaut",
- "ogonek",
- "caron"
-};
-static FontEncoding macRomanEncoding(macRomanEncodingNames,
- macRomanEncodingSize);
-
-#define winAnsiEncodingSize 256
-static char *winAnsiEncodingNames[winAnsiEncodingSize] = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "space",
- "exclam",
- "quotedbl",
- "numbersign",
- "dollar",
- "percent",
- "ampersand",
- "quotesingle",
- "parenleft",
- "parenright",
- "asterisk",
- "plus",
- "comma",
- "hyphen",
- "period",
- "slash",
- "zero",
- "one",
- "two",
- "three",
- "four",
- "five",
- "six",
- "seven",
- "eight",
- "nine",
- "colon",
- "semicolon",
- "less",
- "equal",
- "greater",
- "question",
- "at",
- "A",
- "B",
- "C",
- "D",
- "E",
- "F",
- "G",
- "H",
- "I",
- "J",
- "K",
- "L",
- "M",
- "N",
- "O",
- "P",
- "Q",
- "R",
- "S",
- "T",
- "U",
- "V",
- "W",
- "X",
- "Y",
- "Z",
- "bracketleft",
- "backslash",
- "bracketright",
- "asciicircum",
- "underscore",
- "grave",
- "a",
- "b",
- "c",
- "d",
- "e",
- "f",
- "g",
- "h",
- "i",
- "j",
- "k",
- "l",
- "m",
- "n",
- "o",
- "p",
- "q",
- "r",
- "s",
- "t",
- "u",
- "v",
- "w",
- "x",
- "y",
- "z",
- "braceleft",
- "bar",
- "braceright",
- "asciitilde",
- "bullet",
- "bullet",
- "bullet",
- "quotesinglbase",
- "florin",
- "quotedblbase",
- "ellipsis",
- "dagger",
- "daggerdbl",
- "circumflex",
- "perthousand",
- "Scaron",
- "guilsinglleft",
- "OE",
- "bullet",
- "bullet",
- "bullet",
- "bullet",
- "quoteleft",
- "quoteright",
- "quotedblleft",
- "quotedblright",
- "bullet",
- "endash",
- "emdash",
- "tilde",
- "trademark",
- "scaron",
- "guilsinglright",
- "oe",
- "bullet",
- "bullet",
- "Ydieresis",
- "space",
- "exclamdown",
- "cent",
- "sterling",
- "currency",
- "yen",
- "brokenbar",
- "section",
- "dieresis",
- "copyright",
- "ordfeminine",
- "guillemotleft",
- "logicalnot",
- "hyphen",
- "registered",
- "macron",
- "degree",
- "plusminus",
- "twosuperior",
- "threesuperior",
- "acute",
- "mu",
- "paragraph",
- "periodcentered",
- "cedilla",
- "onesuperior",
- "ordmasculine",
- "guillemotright",
- "onequarter",
- "onehalf",
- "threequarters",
- "questiondown",
- "Agrave",
- "Aacute",
- "Acircumflex",
- "Atilde",
- "Adieresis",
- "Aring",
- "AE",
- "Ccedilla",
- "Egrave",
- "Eacute",
- "Ecircumflex",
- "Edieresis",
- "Igrave",
- "Iacute",
- "Icircumflex",
- "Idieresis",
- "Eth",
- "Ntilde",
- "Ograve",
- "Oacute",
- "Ocircumflex",
- "Otilde",
- "Odieresis",
- "multiply",
- "Oslash",
- "Ugrave",
- "Uacute",
- "Ucircumflex",
- "Udieresis",
- "Yacute",
- "Thorn",
- "germandbls",
- "agrave",
- "aacute",
- "acircumflex",
- "atilde",
- "adieresis",
- "aring",
- "ae",
- "ccedilla",
- "egrave",
- "eacute",
- "ecircumflex",
- "edieresis",
- "igrave",
- "iacute",
- "icircumflex",
- "idieresis",
- "eth",
- "ntilde",
- "ograve",
- "oacute",
- "ocircumflex",
- "otilde",
- "odieresis",
- "divide",
- "oslash",
- "ugrave",
- "uacute",
- "ucircumflex",
- "udieresis",
- "yacute",
- "thorn",
- "ydieresis"
-};
-static FontEncoding winAnsiEncoding(winAnsiEncodingNames,
- winAnsiEncodingSize);
-
-//------------------------------------------------------------------------
-// Character widths for built-in fonts.
-//------------------------------------------------------------------------
-
-static Gushort courierWidths[335] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 0, 600, 600, 600, 600, 0, 600, 600,
- 600, 600, 600, 600, 600, 600, 0, 600,
- 0, 600, 600, 600, 600, 600, 600, 600,
- 600, 0, 600, 600, 0, 600, 600, 600,
- 600, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 600, 0, 600, 0, 0, 0, 0,
- 600, 600, 600, 600, 0, 0, 0, 0,
- 0, 600, 0, 0, 0, 600, 0, 0,
- 600, 600, 600, 600, 0, 0, 0, 0,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600
-};
-
-static Gushort courierBoldWidths[335] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 0, 600, 600, 600, 600, 0, 600, 600,
- 600, 600, 600, 600, 600, 600, 0, 600,
- 0, 600, 600, 600, 600, 600, 600, 600,
- 600, 0, 600, 600, 0, 600, 600, 600,
- 600, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 600, 0, 600, 0, 0, 0, 0,
- 600, 600, 600, 600, 0, 0, 0, 0,
- 0, 600, 0, 0, 0, 600, 0, 0,
- 600, 600, 600, 600, 0, 0, 0, 0,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600
-};
-
-static Gushort courierBoldObliqueWidths[335] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 0, 600, 600, 600, 600, 0, 600, 600,
- 600, 600, 600, 600, 600, 600, 0, 600,
- 0, 600, 600, 600, 600, 600, 600, 600,
- 600, 0, 600, 600, 0, 600, 600, 600,
- 600, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 600, 0, 600, 0, 0, 0, 0,
- 600, 600, 600, 600, 0, 0, 0, 0,
- 0, 600, 0, 0, 0, 600, 0, 0,
- 600, 600, 600, 600, 0, 0, 0, 0,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600
-};
-
-static Gushort courierObliqueWidths[335] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 0, 600, 600, 600, 600, 0, 600, 600,
- 600, 600, 600, 600, 600, 600, 0, 600,
- 0, 600, 600, 600, 600, 600, 600, 600,
- 600, 0, 600, 600, 0, 600, 600, 600,
- 600, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 600, 0, 600, 0, 0, 0, 0,
- 600, 600, 600, 600, 0, 0, 0, 0,
- 0, 600, 0, 0, 0, 600, 0, 0,
- 600, 600, 600, 600, 0, 0, 0, 0,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600, 600,
- 600, 600, 600, 600, 600, 600, 600
-};
-
-static Gushort helveticaWidths[335] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 278, 278, 355, 556, 556, 889, 667, 222,
- 333, 333, 389, 584, 278, 333, 278, 278,
- 556, 556, 556, 556, 556, 556, 556, 556,
- 556, 556, 278, 278, 584, 584, 584, 556,
- 1015, 667, 667, 722, 722, 667, 611, 778,
- 722, 278, 500, 667, 556, 833, 722, 778,
- 667, 778, 722, 667, 611, 722, 667, 944,
- 667, 667, 611, 278, 278, 278, 469, 556,
- 222, 556, 556, 500, 556, 556, 278, 556,
- 556, 222, 222, 500, 222, 833, 556, 556,
- 556, 556, 333, 500, 278, 556, 500, 722,
- 500, 500, 500, 334, 260, 334, 584, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 333, 556, 556, 167, 556, 556, 556,
- 556, 191, 333, 556, 333, 333, 500, 500,
- 0, 556, 556, 556, 278, 0, 537, 350,
- 222, 333, 333, 556, 1000, 1000, 0, 611,
- 0, 333, 333, 333, 333, 333, 333, 333,
- 333, 0, 333, 333, 0, 333, 333, 333,
- 1000, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1000, 0, 370, 0, 0, 0, 0,
- 556, 778, 1000, 365, 0, 0, 0, 0,
- 0, 889, 0, 0, 0, 278, 0, 0,
- 222, 611, 944, 611, 0, 0, 0, 0,
- 667, 667, 667, 667, 667, 667, 722, 667,
- 667, 667, 667, 722, 278, 278, 278, 278,
- 722, 778, 778, 778, 778, 778, 667, 667,
- 722, 722, 722, 722, 667, 667, 611, 556,
- 556, 556, 556, 556, 556, 260, 500, 737,
- 400, 584, 556, 556, 556, 556, 556, 278,
- 278, 278, 278, 584, 584, 556, 584, 556,
- 556, 556, 556, 556, 834, 834, 333, 556,
- 584, 737, 500, 556, 834, 333, 1000, 333,
- 556, 556, 556, 556, 500, 500, 500
-};
-
-static Gushort helveticaBoldWidths[335] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 278, 333, 474, 556, 556, 889, 722, 278,
- 333, 333, 389, 584, 278, 333, 278, 278,
- 556, 556, 556, 556, 556, 556, 556, 556,
- 556, 556, 333, 333, 584, 584, 584, 611,
- 975, 722, 722, 722, 722, 667, 611, 778,
- 722, 278, 556, 722, 611, 833, 722, 778,
- 667, 778, 722, 667, 611, 722, 667, 944,
- 667, 667, 611, 333, 278, 333, 584, 556,
- 278, 556, 611, 556, 611, 556, 333, 611,
- 611, 278, 278, 556, 278, 889, 611, 611,
- 611, 611, 389, 556, 333, 611, 556, 778,
- 556, 556, 500, 389, 280, 389, 584, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 333, 556, 556, 167, 556, 556, 556,
- 556, 238, 500, 556, 333, 333, 611, 611,
- 0, 556, 556, 556, 278, 0, 556, 350,
- 278, 500, 500, 556, 1000, 1000, 0, 611,
- 0, 333, 333, 333, 333, 333, 333, 333,
- 333, 0, 333, 333, 0, 333, 333, 333,
- 1000, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1000, 0, 370, 0, 0, 0, 0,
- 611, 778, 1000, 365, 0, 0, 0, 0,
- 0, 889, 0, 0, 0, 278, 0, 0,
- 278, 611, 944, 611, 0, 0, 0, 0,
- 722, 722, 722, 722, 722, 722, 722, 667,
- 667, 667, 667, 722, 278, 278, 278, 278,
- 722, 778, 778, 778, 778, 778, 667, 667,
- 722, 722, 722, 722, 667, 667, 611, 556,
- 556, 556, 556, 556, 556, 280, 556, 737,
- 400, 584, 556, 556, 556, 556, 611, 278,
- 278, 278, 278, 584, 584, 611, 584, 611,
- 611, 611, 611, 611, 834, 834, 333, 611,
- 584, 737, 556, 611, 834, 333, 1000, 333,
- 611, 611, 611, 611, 556, 556, 500
-};
-
-static Gushort helveticaBoldObliqueWidths[335] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 278, 333, 474, 556, 556, 889, 722, 278,
- 333, 333, 389, 584, 278, 333, 278, 278,
- 556, 556, 556, 556, 556, 556, 556, 556,
- 556, 556, 333, 333, 584, 584, 584, 611,
- 975, 722, 722, 722, 722, 667, 611, 778,
- 722, 278, 556, 722, 611, 833, 722, 778,
- 667, 778, 722, 667, 611, 722, 667, 944,
- 667, 667, 611, 333, 278, 333, 584, 556,
- 278, 556, 611, 556, 611, 556, 333, 611,
- 611, 278, 278, 556, 278, 889, 611, 611,
- 611, 611, 389, 556, 333, 611, 556, 778,
- 556, 556, 500, 389, 280, 389, 584, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 333, 556, 556, 167, 556, 556, 556,
- 556, 238, 500, 556, 333, 333, 611, 611,
- 0, 556, 556, 556, 278, 0, 556, 350,
- 278, 500, 500, 556, 1000, 1000, 0, 611,
- 0, 333, 333, 333, 333, 333, 333, 333,
- 333, 0, 333, 333, 0, 333, 333, 333,
- 1000, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1000, 0, 370, 0, 0, 0, 0,
- 611, 778, 1000, 365, 0, 0, 0, 0,
- 0, 889, 0, 0, 0, 278, 0, 0,
- 278, 611, 944, 611, 0, 0, 0, 0,
- 722, 722, 722, 722, 722, 722, 722, 667,
- 667, 667, 667, 722, 278, 278, 278, 278,
- 722, 778, 778, 778, 778, 778, 667, 667,
- 722, 722, 722, 722, 667, 667, 611, 556,
- 556, 556, 556, 556, 556, 280, 556, 737,
- 400, 584, 556, 556, 556, 556, 611, 278,
- 278, 278, 278, 584, 584, 611, 584, 611,
- 611, 611, 611, 611, 834, 834, 333, 611,
- 584, 737, 556, 611, 834, 333, 1000, 333,
- 611, 611, 611, 611, 556, 556, 500
-};
-
-static Gushort helveticaObliqueWidths[335] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 278, 278, 355, 556, 556, 889, 667, 222,
- 333, 333, 389, 584, 278, 333, 278, 278,
- 556, 556, 556, 556, 556, 556, 556, 556,
- 556, 556, 278, 278, 584, 584, 584, 556,
- 1015, 667, 667, 722, 722, 667, 611, 778,
- 722, 278, 500, 667, 556, 833, 722, 778,
- 667, 778, 722, 667, 611, 722, 667, 944,
- 667, 667, 611, 278, 278, 278, 469, 556,
- 222, 556, 556, 500, 556, 556, 278, 556,
- 556, 222, 222, 500, 222, 833, 556, 556,
- 556, 556, 333, 500, 278, 556, 500, 722,
- 500, 500, 500, 334, 260, 334, 584, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 333, 556, 556, 167, 556, 556, 556,
- 556, 191, 333, 556, 333, 333, 500, 500,
- 0, 556, 556, 556, 278, 0, 537, 350,
- 222, 333, 333, 556, 1000, 1000, 0, 611,
- 0, 333, 333, 333, 333, 333, 333, 333,
- 333, 0, 333, 333, 0, 333, 333, 333,
- 1000, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1000, 0, 370, 0, 0, 0, 0,
- 556, 778, 1000, 365, 0, 0, 0, 0,
- 0, 889, 0, 0, 0, 278, 0, 0,
- 222, 611, 944, 611, 0, 0, 0, 0,
- 667, 667, 667, 667, 667, 667, 722, 667,
- 667, 667, 667, 722, 278, 278, 278, 278,
- 722, 778, 778, 778, 778, 778, 667, 667,
- 722, 722, 722, 722, 667, 667, 611, 556,
- 556, 556, 556, 556, 556, 260, 500, 737,
- 400, 584, 556, 556, 556, 556, 556, 278,
- 278, 278, 278, 584, 584, 556, 584, 556,
- 556, 556, 556, 556, 834, 834, 333, 556,
- 584, 737, 500, 556, 834, 333, 1000, 333,
- 556, 556, 556, 556, 500, 500, 500
-};
-
-static Gushort symbolWidths[257] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 250, 333, 713, 500, 549, 833, 778, 439,
- 333, 333, 500, 549, 250, 549, 250, 278,
- 500, 500, 500, 500, 500, 500, 500, 500,
- 500, 500, 278, 278, 549, 549, 549, 444,
- 549, 722, 667, 722, 612, 611, 763, 603,
- 722, 333, 631, 722, 686, 889, 722, 722,
- 768, 741, 556, 592, 611, 690, 439, 768,
- 645, 795, 611, 333, 863, 333, 658, 500,
- 500, 631, 549, 549, 494, 439, 521, 411,
- 603, 329, 603, 549, 549, 576, 521, 549,
- 549, 521, 549, 603, 439, 576, 713, 686,
- 493, 686, 494, 480, 200, 480, 549, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 620, 247, 549, 167, 713, 500, 753,
- 753, 753, 753, 1042, 987, 603, 987, 603,
- 400, 549, 411, 549, 549, 713, 494, 460,
- 549, 549, 549, 549, 1000, 603, 1000, 658,
- 823, 686, 795, 987, 768, 768, 823, 768,
- 768, 713, 713, 713, 713, 713, 713, 713,
- 768, 713, 790, 790, 890, 823, 549, 250,
- 713, 603, 603, 1042, 987, 603, 987, 603,
- 494, 329, 790, 790, 786, 713, 384, 384,
- 384, 384, 384, 384, 494, 494, 494, 494,
- 0, 329, 274, 686, 686, 686, 384, 384,
- 384, 384, 384, 384, 494, 494, 494, 0,
- 790
-};
-
-static Gushort timesBoldWidths[335] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 250, 333, 555, 500, 500, 1000, 833, 333,
- 333, 333, 500, 570, 250, 333, 250, 278,
- 500, 500, 500, 500, 500, 500, 500, 500,
- 500, 500, 333, 333, 570, 570, 570, 500,
- 930, 722, 667, 722, 722, 667, 611, 778,
- 778, 389, 500, 778, 667, 944, 722, 778,
- 611, 778, 722, 556, 667, 722, 722, 1000,
- 722, 722, 667, 333, 278, 333, 581, 500,
- 333, 500, 556, 444, 556, 444, 333, 500,
- 556, 278, 333, 556, 278, 833, 556, 500,
- 556, 556, 444, 389, 333, 556, 500, 722,
- 500, 500, 444, 394, 220, 394, 520, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 333, 500, 500, 167, 500, 500, 500,
- 500, 278, 500, 500, 333, 333, 556, 556,
- 0, 500, 500, 500, 250, 0, 540, 350,
- 333, 500, 500, 500, 1000, 1000, 0, 500,
- 0, 333, 333, 333, 333, 333, 333, 333,
- 333, 0, 333, 333, 0, 333, 333, 333,
- 1000, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1000, 0, 300, 0, 0, 0, 0,
- 667, 778, 1000, 330, 0, 0, 0, 0,
- 0, 722, 0, 0, 0, 278, 0, 0,
- 278, 500, 722, 556, 0, 0, 0, 0,
- 722, 722, 722, 722, 722, 722, 722, 667,
- 667, 667, 667, 722, 389, 389, 389, 389,
- 722, 778, 778, 778, 778, 778, 556, 611,
- 722, 722, 722, 722, 722, 722, 667, 500,
- 500, 500, 500, 500, 500, 220, 444, 747,
- 400, 570, 444, 444, 444, 444, 500, 278,
- 278, 278, 278, 570, 570, 556, 570, 556,
- 500, 500, 500, 500, 750, 750, 300, 500,
- 570, 747, 389, 556, 750, 300, 1000, 300,
- 556, 556, 556, 556, 500, 500, 444
-};
-
-static Gushort timesBoldItalicWidths[335] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 250, 389, 555, 500, 500, 833, 778, 333,
- 333, 333, 500, 570, 250, 333, 250, 278,
- 500, 500, 500, 500, 500, 500, 500, 500,
- 500, 500, 333, 333, 570, 570, 570, 500,
- 832, 667, 667, 667, 722, 667, 667, 722,
- 778, 389, 500, 667, 611, 889, 722, 722,
- 611, 722, 667, 556, 611, 722, 667, 889,
- 667, 611, 611, 333, 278, 333, 570, 500,
- 333, 500, 500, 444, 500, 444, 333, 500,
- 556, 278, 278, 500, 278, 778, 556, 500,
- 500, 500, 389, 389, 278, 556, 444, 667,
- 500, 444, 389, 348, 220, 348, 570, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 389, 500, 500, 167, 500, 500, 500,
- 500, 278, 500, 500, 333, 333, 556, 556,
- 0, 500, 500, 500, 250, 0, 500, 350,
- 333, 500, 500, 500, 1000, 1000, 0, 500,
- 0, 333, 333, 333, 333, 333, 333, 333,
- 333, 0, 333, 333, 0, 333, 333, 333,
- 1000, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 944, 0, 266, 0, 0, 0, 0,
- 611, 722, 944, 300, 0, 0, 0, 0,
- 0, 722, 0, 0, 0, 278, 0, 0,
- 278, 500, 722, 500, 0, 0, 0, 0,
- 667, 667, 667, 667, 667, 667, 667, 667,
- 667, 667, 667, 722, 389, 389, 389, 389,
- 722, 722, 722, 722, 722, 722, 556, 611,
- 722, 722, 722, 722, 611, 611, 611, 500,
- 500, 500, 500, 500, 500, 220, 444, 747,
- 400, 570, 444, 444, 444, 444, 500, 278,
- 278, 278, 278, 606, 606, 576, 570, 556,
- 500, 500, 500, 500, 750, 750, 300, 500,
- 570, 747, 389, 500, 750, 300, 1000, 300,
- 556, 556, 556, 556, 444, 444, 389
-};
-
-static Gushort timesItalicWidths[335] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 250, 333, 420, 500, 500, 833, 778, 333,
- 333, 333, 500, 675, 250, 333, 250, 278,
- 500, 500, 500, 500, 500, 500, 500, 500,
- 500, 500, 333, 333, 675, 675, 675, 500,
- 920, 611, 611, 667, 722, 611, 611, 722,
- 722, 333, 444, 667, 556, 833, 667, 722,
- 611, 722, 611, 500, 556, 722, 611, 833,
- 611, 556, 556, 389, 278, 389, 422, 500,
- 333, 500, 500, 444, 500, 444, 278, 500,
- 500, 278, 278, 444, 278, 722, 500, 500,
- 500, 500, 389, 389, 278, 500, 444, 667,
- 444, 444, 389, 400, 275, 400, 541, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 389, 500, 500, 167, 500, 500, 500,
- 500, 214, 556, 500, 333, 333, 500, 500,
- 0, 500, 500, 500, 250, 0, 523, 350,
- 333, 556, 556, 500, 889, 1000, 0, 500,
- 0, 333, 333, 333, 333, 333, 333, 333,
- 333, 0, 333, 333, 0, 333, 333, 333,
- 889, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 889, 0, 276, 0, 0, 0, 0,
- 556, 722, 944, 310, 0, 0, 0, 0,
- 0, 667, 0, 0, 0, 278, 0, 0,
- 278, 500, 667, 500, 0, 0, 0, 0,
- 611, 611, 611, 611, 611, 611, 667, 611,
- 611, 611, 611, 722, 333, 333, 333, 333,
- 667, 722, 722, 722, 722, 722, 500, 611,
- 722, 722, 722, 722, 556, 556, 556, 500,
- 500, 500, 500, 500, 500, 275, 444, 760,
- 400, 675, 444, 444, 444, 444, 500, 278,
- 278, 278, 278, 675, 675, 500, 675, 500,
- 500, 500, 500, 500, 750, 750, 300, 500,
- 675, 760, 389, 500, 750, 300, 980, 300,
- 500, 500, 500, 500, 444, 444, 389
-};
-
-static Gushort timesRomanWidths[335] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 250, 333, 408, 500, 500, 833, 778, 333,
- 333, 333, 500, 564, 250, 333, 250, 278,
- 500, 500, 500, 500, 500, 500, 500, 500,
- 500, 500, 278, 278, 564, 564, 564, 444,
- 921, 722, 667, 667, 722, 611, 556, 722,
- 722, 333, 389, 722, 611, 889, 722, 722,
- 556, 722, 667, 556, 611, 722, 722, 944,
- 722, 722, 611, 333, 278, 333, 469, 500,
- 333, 444, 500, 444, 500, 444, 333, 500,
- 500, 278, 278, 500, 278, 778, 500, 500,
- 500, 500, 333, 389, 278, 500, 500, 722,
- 500, 500, 444, 480, 200, 480, 541, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 333, 500, 500, 167, 500, 500, 500,
- 500, 180, 444, 500, 333, 333, 556, 556,
- 0, 500, 500, 500, 250, 0, 453, 350,
- 333, 444, 444, 500, 1000, 1000, 0, 444,
- 0, 333, 333, 333, 333, 333, 333, 333,
- 333, 0, 333, 333, 0, 333, 333, 333,
- 1000, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 889, 0, 276, 0, 0, 0, 0,
- 611, 722, 889, 310, 0, 0, 0, 0,
- 0, 667, 0, 0, 0, 278, 0, 0,
- 278, 500, 722, 500, 0, 0, 0, 0,
- 722, 722, 722, 722, 722, 722, 667, 611,
- 611, 611, 611, 722, 333, 333, 333, 333,
- 722, 722, 722, 722, 722, 722, 556, 556,
- 722, 722, 722, 722, 722, 722, 611, 444,
- 444, 444, 444, 444, 444, 200, 444, 760,
- 400, 564, 444, 444, 444, 444, 500, 278,
- 278, 278, 278, 564, 564, 500, 564, 500,
- 500, 500, 500, 500, 750, 750, 300, 500,
- 564, 760, 389, 500, 750, 300, 980, 300,
- 500, 500, 500, 500, 500, 500, 444
-};
-
-static Gushort zapfDingbatsWidths[270] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 278, 974, 961, 974, 980, 719, 789, 790,
- 791, 690, 960, 939, 549, 855, 911, 933,
- 911, 945, 974, 755, 846, 762, 761, 571,
- 677, 763, 760, 759, 754, 494, 552, 537,
- 577, 692, 786, 788, 788, 790, 793, 794,
- 816, 823, 789, 841, 823, 833, 816, 831,
- 923, 744, 723, 749, 790, 792, 695, 776,
- 768, 792, 759, 707, 708, 682, 701, 826,
- 815, 789, 789, 707, 687, 696, 689, 786,
- 787, 713, 791, 785, 791, 873, 761, 762,
- 762, 759, 759, 892, 892, 788, 784, 438,
- 138, 277, 415, 392, 392, 668, 668, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 732, 544, 544, 910, 667, 760, 760,
- 776, 595, 694, 626, 788, 788, 788, 788,
- 788, 788, 788, 788, 788, 788, 788, 788,
- 788, 788, 788, 788, 788, 788, 788, 788,
- 788, 788, 788, 788, 788, 788, 788, 788,
- 788, 788, 788, 788, 788, 788, 788, 788,
- 788, 788, 788, 788, 894, 838, 1016, 458,
- 748, 924, 748, 918, 927, 928, 928, 834,
- 873, 828, 924, 924, 917, 930, 931, 463,
- 883, 836, 836, 867, 867, 696, 696, 874,
- 0, 874, 760, 946, 771, 865, 771, 888,
- 967, 888, 831, 873, 927, 970, 918, 0,
- 509, 410, 509, 410, 234, 234, 390, 390,
- 276, 276, 317, 317, 334, 334
-};
-
-//------------------------------------------------------------------------
-// Built-in font table.
-//------------------------------------------------------------------------
-
-struct BuiltinFont {
- char *name;
- Gushort *widths;
- FontEncoding *encoding;
-};
-
-#define numBuiltinFonts ((int)(sizeof(builtinFonts)/sizeof(BuiltinFont)))
-
-static BuiltinFont builtinFonts[] = {
- {"Courier", courierWidths, &standardEncoding},
- {"Courier-Bold", courierBoldWidths, &standardEncoding},
- {"Courier-BoldOblique", courierBoldObliqueWidths, &standardEncoding},
- {"Courier-Oblique", courierObliqueWidths, &standardEncoding},
- {"Helvetica", helveticaWidths, &standardEncoding},
- {"Helvetica-Bold", helveticaBoldWidths, &standardEncoding},
- {"Helvetica-BoldOblique", helveticaBoldObliqueWidths, &standardEncoding},
- {"Helvetica-Oblique", helveticaObliqueWidths, &standardEncoding},
- {"Symbol", symbolWidths, &symbolEncoding},
- {"Times-Bold", timesBoldWidths, &standardEncoding},
- {"Times-BoldItalic", timesBoldItalicWidths, &standardEncoding},
- {"Times-Italic", timesItalicWidths, &standardEncoding},
- {"Times-Roman", timesRomanWidths, &standardEncoding},
- {"ZapfDingbats", zapfDingbatsWidths, &zapfDingbatsEncoding}
-};
-
-#endif
+++ /dev/null
-//========================================================================
-//
-// FormWidget.cc
-//
-// Copyright 2000 Derek B. Noonburg
-//
-//========================================================================
-
-#ifdef __GNUC__
-#pragma implementation
-#endif
-
-#include "gmem.h"
-#include "Object.h"
-#include "Gfx.h"
-#include "FormWidget.h"
-
-//------------------------------------------------------------------------
-// FormWidget
-//------------------------------------------------------------------------
-
-FormWidget::FormWidget(Dict *dict) {
- Object obj1, obj2;
- double t;
-
- ok = gFalse;
-
- if (dict->lookup("AP", &obj1)->isDict()) {
- obj1.dictLookupNF("N", &obj2);
- //~ this doesn't handle appearances with multiple states --
- //~ need to look at AS key to get state and then get the
- //~ corresponding entry from the N dict
- if (obj2.isRef()) {
- obj2.copy(&appearance);
- ok = gTrue;
- }
- obj2.free();
- }
- obj1.free();
-
- if (dict->lookup("Rect", &obj1)->isArray() &&
- obj1.arrayGetLength() == 4) {
- //~ should check object types here
- obj1.arrayGet(0, &obj2);
- xMin = obj2.getNum();
- obj2.free();
- obj1.arrayGet(1, &obj2);
- yMin = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2, &obj2);
- xMax = obj2.getNum();
- obj2.free();
- obj1.arrayGet(3, &obj2);
- yMax = obj2.getNum();
- obj2.free();
- if (xMin > xMax) {
- t = xMin; xMin = xMax; xMax = t;
- }
- if (yMin > yMax) {
- t = yMin; yMin = yMax; yMax = t;
- }
- } else {
- //~ this should return an error
- xMin = yMin = 0;
- xMax = yMax = 1;
- }
- obj1.free();
-}
-
-FormWidget::~FormWidget() {
- appearance.free();
-}
-
-void FormWidget::draw(Gfx *gfx) {
- Object obj;
-
- if (appearance.fetch(&obj)->isStream()) {
- gfx->doWidgetForm(&obj, xMin, yMin, xMax, yMax);
- }
- obj.free();
-}
-
-//------------------------------------------------------------------------
-// FormWidgets
-//------------------------------------------------------------------------
-
-FormWidgets::FormWidgets(Object *annots) {
- FormWidget *widget;
- Object obj1, obj2;
- int size;
- int i;
-
- widgets = NULL;
- size = 0;
- nWidgets = 0;
-
- if (annots->isArray()) {
- for (i = 0; i < annots->arrayGetLength(); ++i) {
- if (annots->arrayGet(i, &obj1)->isDict()) {
- obj1.dictLookup("Subtype", &obj2);
- if (obj2.isName("Widget") ||
- obj2.isName("Stamp")) {
- widget = new FormWidget(obj1.getDict());
- if (widget->isOk()) {
- if (nWidgets >= size) {
- size += 16;
- widgets = (FormWidget **)grealloc(widgets,
- size * sizeof(FormWidget *));
- }
- widgets[nWidgets++] = widget;
- } else {
- delete widget;
- }
- }
- obj2.free();
- }
- obj1.free();
- }
- }
-}
-
-FormWidgets::~FormWidgets() {
- int i;
-
- for (i = 0; i < nWidgets; ++i) {
- delete widgets[i];
- }
- gfree(widgets);
-}
+++ /dev/null
-//========================================================================
-//
-// FormWidget.h
-//
-// Copyright 2000 Derek B. Noonburg
-//
-//========================================================================
-
-#ifndef FORMWIDGET_H
-#define FORMWIDGET_H
-
-#ifdef __GNUC__
-#pragma interface
-#endif
-
-class Gfx;
-
-//------------------------------------------------------------------------
-// FormWidget
-//------------------------------------------------------------------------
-
-class FormWidget {
-public:
-
- FormWidget(Dict *dict);
- ~FormWidget();
- GBool isOk() { return ok; }
-
- void draw(Gfx *gfx);
-
- // Get appearance object.
- Object *getAppearance(Object *obj) { return appearance.fetch(obj); }
-
-private:
-
- Object appearance; // a reference to the Form XObject stream
- // for the normal appearance
- double xMin, yMin, // widget rectangle
- xMax, yMax;
- GBool ok;
-};
-
-//------------------------------------------------------------------------
-// FormWidgets
-//------------------------------------------------------------------------
-
-class FormWidgets {
-public:
-
- // Extract widgets from array of annotations.
- FormWidgets(Object *annots);
-
- ~FormWidgets();
-
- // Iterate through list of widgets.
- int getNumWidgets() { return nWidgets; }
- FormWidget *getWidget(int i) { return widgets[i]; }
-
-private:
-
- FormWidget **widgets;
- int nWidgets;
-};
-
-#endif
//
// Simple variable-length string type.
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
s[0] = '\0';
}
-GString::GString(const char *s1) {
- int n = strlen(s1);
+GString::GString(const char *sA) {
+ int n = strlen(sA);
s = NULL;
resize(length = n);
- memcpy(s, s1, n + 1);
+ memcpy(s, sA, n + 1);
}
-GString::GString(const char *s1, int length1) {
+GString::GString(const char *sA, int lengthA) {
s = NULL;
- resize(length = length1);
- memcpy(s, s1, length * sizeof(char));
+ resize(length = lengthA);
+ memcpy(s, sA, length * sizeof(char));
+ s[length] = '\0';
+}
+
+GString::GString(GString *str, int idx, int lengthA) {
+ s = NULL;
+ resize(length = lengthA);
+ memcpy(s, str->getCString() + idx, length);
s[length] = '\0';
}
return this;
}
-GString *GString::append(const char *str, int length1) {
- resize(length + length1);
- memcpy(s + length, str, length1);
- length += length1;
+GString *GString::append(const char *str, int lengthA) {
+ resize(length + lengthA);
+ memcpy(s + length, str, lengthA);
+ length += lengthA;
s[length] = '\0';
return this;
}
return this;
}
-GString *GString::insert(int i, const char *str, int length1) {
+GString *GString::insert(int i, const char *str, int lengthA) {
int j;
- resize(length + length1);
+ resize(length + lengthA);
for (j = length; j >= i; --j)
- s[j+length1] = s[j];
- memcpy(s+i, str, length1);
- length += length1;
+ s[j+lengthA] = s[j];
+ memcpy(s+i, str, lengthA);
+ length += lengthA;
return this;
}
//
// Simple variable-length string type.
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
GString();
// Create a string from a C string.
- GString(const char *s1);
+ GString(const char *sA);
- // Create a string from <length1> chars at <s1>. This string
+ // Create a string from <lengthA> chars at <sA>. This string
// can contain null characters.
- GString (const char *s1, int length1);
+ GString(const char *sA, int lengthA);
+
+ // Create a string from <lengthA> chars at <idx> in <str>.
+ GString(GString *str, int idx, int lengthA);
// Copy a string.
GString(GString *str);
GString *append(char c);
GString *append(GString *str);
GString *append(const char *str);
- GString *append(const char *str, int length1);
+ GString *append(const char *str, int lengthA);
// Insert a character or string.
GString *insert(int i, char c);
GString *insert(int i, GString *str);
GString *insert(int i, const char *str);
- GString *insert(int i, const char *str, int length1);
+ GString *insert(int i, const char *str, int lengthA);
// Delete a character or range of characters.
GString *del(int i, int n = 1);
// These functions assume the strings do not contain null characters.
int cmp(GString *str) { return strcmp(s, str->getCString()); }
int cmpN(GString *str, int n) { return strncmp(s, str->getCString(), n); }
- int cmp(const char *s1) { return strcmp(s, s1); }
- int cmpN(const char *s1, int n) { return strncmp(s, s1, n); }
+ int cmp(const char *sA) { return strcmp(s, sA); }
+ int cmpN(const char *sA, int n) { return strncmp(s, sA, n); }
private:
//
// Gfx.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <math.h>
#include "gmem.h"
+#include "CharTypes.h"
#include "Object.h"
#include "Array.h"
#include "Dict.h"
#include "GfxFont.h"
#include "GfxState.h"
#include "OutputDev.h"
-#include "Params.h"
+#include "Page.h"
#include "Error.h"
#include "Gfx.h"
+// the MSVC math.h doesn't define this
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+//------------------------------------------------------------------------
+// constants
+//------------------------------------------------------------------------
+
+// Max number of splits along the t axis for an axial shading fill.
+#define axialMaxSplits 256
+
+// Max delta allowed in any color component for an axial shading fill.
+#define axialColorDelta (1 / 256.0)
+
+// Max number of splits along the t axis for a radial shading fill.
+#define radialMaxSplits 256
+
+// Max delta allowed in any color component for a radial shading fill.
+#define radialColorDelta (1 / 256.0)
+
//------------------------------------------------------------------------
// Operator table
//------------------------------------------------------------------------
#define numOps (sizeof(opTab) / sizeof(Operator))
//------------------------------------------------------------------------
-
-GBool printCommands = gFalse;
-
-//------------------------------------------------------------------------
// GfxResources
//------------------------------------------------------------------------
-GfxResources::GfxResources(Dict *resDict, GfxResources *next) {
+GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) {
Object obj1;
if (resDict) {
fonts = NULL;
resDict->lookup("Font", &obj1);
if (obj1.isDict()) {
- fonts = new GfxFontDict(obj1.getDict());
+ fonts = new GfxFontDict(xref, obj1.getDict());
}
obj1.free();
// get pattern dictionary
resDict->lookup("Pattern", &patternDict);
+ // get shading dictionary
+ resDict->lookup("Shading", &shadingDict);
+
// get graphics state parameter dictionary
resDict->lookup("ExtGState", &gStateDict);
gStateDict.initNull();
}
- this->next = next;
+ next = nextA;
}
GfxResources::~GfxResources() {
xObjDict.free();
colorSpaceDict.free();
patternDict.free();
+ shadingDict.free();
gStateDict.free();
}
return NULL;
}
+GfxShading *GfxResources::lookupShading(char *name) {
+ GfxResources *resPtr;
+ GfxShading *shading;
+ Object obj;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->shadingDict.isDict()) {
+ if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) {
+ shading = GfxShading::parse(&obj);
+ obj.free();
+ return shading;
+ }
+ obj.free();
+ }
+ }
+ error(-1, "Unknown shading '%s'", name);
+ return NULL;
+}
+
GBool GfxResources::lookupGState(char *name, Object *obj) {
GfxResources *resPtr;
// Gfx
//------------------------------------------------------------------------
-Gfx::Gfx(OutputDev *out1, int pageNum, Dict *resDict,
- double dpi, double x1, double y1, double x2, double y2, GBool crop,
- double cropX1, double cropY1, double cropX2, double cropY2,
- int rotate) {
+Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi,
+ PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate,
+ GBool printCommandsA) {
int i;
+ xref = xrefA;
+ subPage = gFalse;
+ printCommands = printCommandsA;
+
// start the resource stack
- res = new GfxResources(resDict, NULL);
+ res = new GfxResources(xref, resDict, NULL);
// initialize
- out = out1;
- state = new GfxState(dpi, x1, y1, x2, y2, rotate, out->upsideDown());
+ out = outA;
+ state = new GfxState(dpi, box, rotate, out->upsideDown());
fontChanged = gFalse;
clip = clipNone;
ignoreUndef = 0;
// set crop box
if (crop) {
- state->moveTo(cropX1, cropY1);
- state->lineTo(cropX2, cropY1);
- state->lineTo(cropX2, cropY2);
- state->lineTo(cropX1, cropY2);
+ state->moveTo(cropBox->x1, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y2);
+ state->lineTo(cropBox->x1, cropBox->y2);
state->closePath();
+ state->clip();
out->clip(state);
state->clearPath();
}
}
-Gfx::~Gfx() {
- GfxResources *resPtr;
+Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
+ PDFRectangle *box, GBool crop, PDFRectangle *cropBox) {
+ int i;
+
+ xref = xrefA;
+ subPage = gTrue;
+ printCommands = gFalse;
+
+ // start the resource stack
+ res = new GfxResources(xref, resDict, NULL);
+ // initialize
+ out = outA;
+ state = new GfxState(72, box, 0, gFalse);
+ fontChanged = gFalse;
+ clip = clipNone;
+ ignoreUndef = 0;
+ for (i = 0; i < 6; ++i) {
+ baseMatrix[i] = state->getCTM()[i];
+ }
+
+ // set crop box
+ if (crop) {
+ state->moveTo(cropBox->x1, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y2);
+ state->lineTo(cropBox->x1, cropBox->y2);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+}
+
+Gfx::~Gfx() {
while (state->hasSaves()) {
state = state->restore();
out->restoreState(state);
}
- out->endPage();
+ if (!subPage) {
+ out->endPage();
+ }
while (res) {
- resPtr = res->getNext();
- delete res;
- res = resPtr;
+ popResources();
}
- if (state)
+ if (state) {
delete state;
+ }
}
void Gfx::display(Object *obj, GBool topLevel) {
error(-1, "Weird page contents");
return;
}
- parser = new Parser(new Lexer(obj));
+ parser = new Parser(xref, new Lexer(xref, obj));
go(topLevel);
delete parser;
parser = NULL;
void Gfx::go(GBool topLevel) {
Object obj;
Object args[maxArgs];
- int numCmds, numArgs;
+ int numArgs;
int i;
// scan a sequence of objects
- numCmds = 0;
+ updateLevel = 0;
numArgs = 0;
parser->getObj(&obj);
while (!obj.isEOF()) {
args[i].print(stdout);
}
printf("\n");
+ fflush(stdout);
}
execOp(&obj, args, numArgs);
obj.free();
numArgs = 0;
// periodically update display
- if (++numCmds == 200) {
+ if (++updateLevel >= 20000) {
out->dump();
- numCmds = 0;
+ updateLevel = 0;
}
// got an argument - save it
printf("throwing away arg: ");
obj.print(stdout);
printf("\n");
+ fflush(stdout);
}
obj.free();
}
args[i].print(stdout);
}
printf("\n");
+ fflush(stdout);
}
for (i = 0; i < numArgs; ++i)
args[i].free();
}
// update display
- if (topLevel && numCmds > 0) {
+ if (topLevel && updateLevel > 0) {
out->dump();
}
-
- // clean up
- if (printCommands) {
- fflush(stdout);
- }
}
void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
void Gfx::opRestore(Object args[], int numArgs) {
state = state->restore();
out->restoreState(state);
-
- // Some PDF producers (Macromedia FreeHand) generate a save (q) and
- // restore (Q) inside a path sequence. The PDF spec seems to imply
- // that this is illegal. Calling clearPath() here implements the
- // behavior apparently expected by this software.
- state->clearPath();
}
void Gfx::opConcat(Object args[], int numArgs) {
if (colorSpace) {
state->setFillColorSpace(colorSpace);
} else {
- error(getPos(), "Bad color space");
+ error(getPos(), "Bad color space (fill)");
}
for (i = 0; i < gfxColorMaxComps; ++i) {
color.c[i] = 0;
if (colorSpace) {
state->setStrokeColorSpace(colorSpace);
} else {
- error(getPos(), "Bad color space");
+ error(getPos(), "Bad color space (stroke)");
}
for (i = 0; i < gfxColorMaxComps; ++i) {
color.c[i] = 0;
}
void Gfx::opClosePath(Object args[], int numArgs) {
- if (!state->isPath()) {
+ if (!state->isCurPt()) {
error(getPos(), "No current point in closepath");
return;
}
doEndPath();
}
-void Gfx::opShFill(Object args[], int numArgs) {
-}
-
void Gfx::doPatternFill(GBool eoFill) {
GfxPatternColorSpace *patCS;
GfxPattern *pattern;
GfxTilingPattern *tPat;
GfxColorSpace *cs;
- GfxPath *path;
- GfxSubpath *subpath;
double xMin, yMin, xMax, yMax, x, y, x1, y1;
+ double cxMin, cyMin, cxMax, cyMax;
int xi0, yi0, xi1, yi1, xi, yi;
double *ctm, *btm, *ptm;
- double m[6], ictm[6], m1[6], im[6];
+ double m[6], ictm[6], m1[6], imb[6];
double det;
double xstep, ystep;
- int i, j;
+ int i;
+
+ // this is a bit of a kludge -- patterns can be really slow, so we
+ // skip them if we're only doing text extraction, since they almost
+ // certainly don't contain any text
+ if (!out->needNonText()) {
+ return;
+ }
// get color space
patCS = (GfxPatternColorSpace *)state->getFillColorSpace();
m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
- // construct a (current space) -> (pattern space) transform matrix
- det = 1 / (m[0] * m[3] - m[1] * m[2]);
- im[0] = m[3] * det;
- im[1] = -m[1] * det;
- im[2] = -m[2] * det;
- im[3] = m[0] * det;
- im[4] = (m[2] * m[5] - m[3] * m[4]) * det;
- im[5] = (m[1] * m[4] - m[0] * m[5]) * det;
-
- // compute bounding box of current path, in pattern space
- xMin = xMax = yMin = yMax = 0; // make gcc happy
- path = state->getPath();
- for (i = 0; i < path->getNumSubpaths(); ++i) {
- subpath = path->getSubpath(i);
- for (j = 0; j < subpath->getNumPoints(); ++j) {
- x = subpath->getX(j);
- y = subpath->getY(j);
- x1 = x * im[0] + y * im[2] + im[4];
- y1 = x * im[1] + y * im[3] + im[5];
- if (i == 0 && j == 0) {
- xMin = xMax = x1;
- yMin = yMax = y1;
- } else {
- if (x1 < xMin) {
- xMin = x1;
- } else if (x1 > xMax) {
- xMax = x1;
- }
- if (y1 < yMin) {
- yMin = y1;
- } else if (y1 > yMax) {
- yMax = y1;
- }
- }
- }
- }
+ // construct a (base space) -> (pattern space) transform matrix
+ det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]);
+ imb[0] = m1[3] * det;
+ imb[1] = -m1[1] * det;
+ imb[2] = -m1[2] * det;
+ imb[3] = m1[0] * det;
+ imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det;
+ imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det;
// save current graphics state
out->saveState(state);
out->updateFillColor(state);
// clip to current path
+ state->clip();
if (eoFill) {
out->eoClip(state);
} else {
}
state->clearPath();
+ // transform clip region bbox to pattern space
+ state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
+ xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4];
+ yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5];
+ x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4];
+ y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4];
+ y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4];
+ y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+
// draw the pattern
//~ this should treat negative steps differently -- start at right/top
//~ edge instead of left/bottom (?)
out->restoreState(state);
}
+void Gfx::opShFill(Object args[], int numArgs) {
+ GfxShading *shading;
+ double xMin, yMin, xMax, yMax;
+
+ if (!(shading = res->lookupShading(args[0].getName()))) {
+ return;
+ }
+
+ // save current graphics state
+ out->saveState(state);
+ state = state->save();
+
+ // clip to bbox
+ if (shading->getHasBBox()) {
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+
+ // set the color space
+ state->setFillColorSpace(shading->getColorSpace()->copy());
+
+ // do shading type-specific operations
+ switch (shading->getType()) {
+ case 2:
+ doAxialShFill((GfxAxialShading *)shading);
+ break;
+ case 3:
+ doRadialShFill((GfxRadialShading *)shading);
+ break;
+ }
+
+ // restore graphics state
+ state = state->restore();
+ out->restoreState(state);
+
+ delete shading;
+}
+
+void Gfx::doAxialShFill(GfxAxialShading *shading) {
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, x1, y1;
+ double dx, dy, mul;
+ double tMin, tMax, t, tx, ty;
+ double s[4], sMin, sMax, tmp;
+ double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1;
+ double t0, t1, tt;
+ double ta[axialMaxSplits + 1];
+ int next[axialMaxSplits + 1];
+ GfxColor color0, color1;
+ int nComps;
+ int i, j, k, kk;
+
+ // get the clip region bbox
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+
+ // compute min and max t values, based on the four corners of the
+ // clip region bbox
+ shading->getCoords(&x0, &y0, &x1, &y1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+ mul = 1 / (dx * dx + dy * dy);
+ tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
+ t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ if (tMin < 0 && !shading->getExtend0()) {
+ tMin = 0;
+ }
+ if (tMax > 1 && !shading->getExtend1()) {
+ tMax = 1;
+ }
+
+ // get the function domain
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+
+ // Traverse the t axis and do the shading.
+ //
+ // For each point (tx, ty) on the t axis, consider a line through
+ // that point perpendicular to the t axis:
+ //
+ // x(s) = tx + s * -dy --> s = (x - tx) / -dy
+ // y(s) = ty + s * dx --> s = (y - ty) / dx
+ //
+ // Then look at the intersection of this line with the bounding box
+ // (xMin, yMin, xMax, yMax). In the general case, there are four
+ // intersection points:
+ //
+ // s0 = (xMin - tx) / -dy
+ // s1 = (xMax - tx) / -dy
+ // s2 = (yMin - ty) / dx
+ // s3 = (yMax - ty) / dx
+ //
+ // and we want the middle two s values.
+ //
+ // In the case where dx = 0, take s0 and s1; in the case where dy =
+ // 0, take s2 and s3.
+ //
+ // Each filled polygon is bounded by two of these line segments
+ // perpdendicular to the t axis.
+ //
+ // The t axis is bisected into smaller regions until the color
+ // difference across a region is small enough, and then the region
+ // is painted with a single color.
+
+ // set up
+ nComps = shading->getColorSpace()->getNComps();
+ ta[0] = tMin;
+ ta[axialMaxSplits] = tMax;
+ next[0] = axialMaxSplits;
+
+ // compute the color at t = tMin
+ if (tMin < 0) {
+ tt = t0;
+ } else if (tMin > 1) {
+ tt = t1;
+ } else {
+ tt = t0 + (t1 - t0) * tMin;
+ }
+ shading->getColor(tt, &color0);
+
+ // compute the coordinates of the point on the t axis at t = tMin;
+ // then compute the intersection of the perpendicular line with the
+ // bounding box
+ tx = x0 + tMin * dx;
+ ty = y0 + tMin * dy;
+ if (dx == 0 && dy == 0) {
+ sMin = sMax = 0;
+ } if (dx == 0) {
+ sMin = (xMin - tx) / -dy;
+ sMax = (xMax - tx) / -dy;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else if (dy == 0) {
+ sMin = (yMin - ty) / dx;
+ sMax = (yMax - ty) / dx;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+ s[0] = (yMin - ty) / dx;
+ s[1] = (yMax - ty) / dx;
+ s[2] = (xMin - tx) / -dy;
+ s[3] = (xMax - tx) / -dy;
+ for (j = 0; j < 3; ++j) {
+ kk = j;
+ for (k = j + 1; k < 4; ++k) {
+ if (s[k] < s[kk]) {
+ kk = k;
+ }
+ }
+ tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
+ }
+ sMin = s[1];
+ sMax = s[2];
+ }
+ ux0 = tx - sMin * dy;
+ uy0 = ty + sMin * dx;
+ vx0 = tx - sMax * dy;
+ vy0 = ty + sMax * dx;
+
+ i = 0;
+ while (i < axialMaxSplits) {
+
+ // bisect until color difference is small enough or we hit the
+ // bisection limit
+ j = next[i];
+ while (j > i + 1) {
+ if (ta[j] < 0) {
+ tt = t0;
+ } else if (ta[j] > 1) {
+ tt = t1;
+ } else {
+ tt = t0 + (t1 - t0) * ta[j];
+ }
+ shading->getColor(tt, &color1);
+ for (k = 0; k < nComps; ++k) {
+ if (fabs(color1.c[k] - color0.c[k]) > axialColorDelta) {
+ break;
+ }
+ }
+ if (k == nComps) {
+ break;
+ }
+ k = (i + j) / 2;
+ ta[k] = 0.5 * (ta[i] + ta[j]);
+ next[i] = k;
+ next[k] = j;
+ j = k;
+ }
+
+ // use the average of the colors of the two sides of the region
+ for (k = 0; k < nComps; ++k) {
+ color0.c[k] = 0.5 * (color0.c[k] + color1.c[k]);
+ }
+
+ // compute the coordinates of the point on the t axis; then
+ // compute the intersection of the perpendicular line with the
+ // bounding box
+ tx = x0 + ta[j] * dx;
+ ty = y0 + ta[j] * dy;
+ if (dx == 0 && dy == 0) {
+ sMin = sMax = 0;
+ } if (dx == 0) {
+ sMin = (xMin - tx) / -dy;
+ sMax = (xMax - tx) / -dy;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else if (dy == 0) {
+ sMin = (yMin - ty) / dx;
+ sMax = (yMax - ty) / dx;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+ s[0] = (yMin - ty) / dx;
+ s[1] = (yMax - ty) / dx;
+ s[2] = (xMin - tx) / -dy;
+ s[3] = (xMax - tx) / -dy;
+ for (j = 0; j < 3; ++j) {
+ kk = j;
+ for (k = j + 1; k < 4; ++k) {
+ if (s[k] < s[kk]) {
+ kk = k;
+ }
+ }
+ tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
+ }
+ sMin = s[1];
+ sMax = s[2];
+ }
+ ux1 = tx - sMin * dy;
+ uy1 = ty + sMin * dx;
+ vx1 = tx - sMax * dy;
+ vy1 = ty + sMax * dx;
+
+ // set the color
+ state->setFillColor(&color0);
+ out->updateFillColor(state);
+
+ // fill the region
+ state->moveTo(ux0, uy0);
+ state->lineTo(vx0, vy0);
+ state->lineTo(vx1, vy1);
+ state->lineTo(ux1, uy1);
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+
+ // set up for next region
+ ux0 = ux1;
+ uy0 = uy1;
+ vx0 = vx1;
+ vy0 = vy1;
+ color0 = color1;
+ i = next[i];
+ }
+}
+
+void Gfx::doRadialShFill(GfxRadialShading *shading) {
+ double sMin, sMax, xMin, yMin, xMax, yMax;
+ double x0, y0, r0, x1, y1, r1, t0, t1;
+ int nComps;
+ GfxColor colorA, colorB;
+ double xa, ya, xb, yb, ra, rb;
+ double ta, tb, sa, sb;
+ int ia, ib, k, n;
+ double *ctm;
+ double angle, t;
+
+ // get the shading info
+ shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+ nComps = shading->getColorSpace()->getNComps();
+
+ // compute the (possibly extended) s range
+ sMin = 0;
+ sMax = 1;
+ if (shading->getExtend0()) {
+ if (r0 < r1) {
+ // extend the smaller end
+ sMin = -r0 / (r1 - r0);
+ } else {
+ // extend the larger end
+ //~ this computes the diagonal of the bounding box -- we should
+ //~ really compute the intersection of the moving/expanding
+ //~ circles with each of the four corners and look for the max
+ //~ radius
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ sMin = (sqrt((xMax - xMin) * (xMax - xMin) +
+ (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
+ if (sMin > 0) {
+ sMin = 0;
+ } else if (sMin < -20) {
+ // sanity check
+ sMin = -20;
+ }
+ }
+ }
+ if (shading->getExtend1()) {
+ if (r1 < r0) {
+ // extend the smaller end
+ sMax = -r0 / (r1 - r0);
+ } else if (r1 > r0) {
+ // extend the larger end
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ sMax = (sqrt((xMax - xMin) * (xMax - xMin) +
+ (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
+ if (sMax < 1) {
+ sMin = 1;
+ } else if (sMax > 20) {
+ // sanity check
+ sMax = 20;
+ }
+ }
+ }
+
+ // compute the number of steps into which circles must be divided to
+ // achieve a curve flatness of 0.1 pixel in device space for the
+ // largest circle (note that "device space" is 72 dpi when generating
+ // PostScript, hence the relatively small 0.1 pixel accuracy)
+ ctm = state->getCTM();
+ t = fabs(ctm[0]);
+ if (fabs(ctm[1]) > t) {
+ t = fabs(ctm[1]);
+ }
+ if (fabs(ctm[2]) > t) {
+ t = fabs(ctm[2]);
+ }
+ if (fabs(ctm[3]) > t) {
+ t = fabs(ctm[3]);
+ }
+ if (r0 > r1) {
+ t *= r0;
+ } else {
+ t *= r1;
+ }
+ if (t < 1) {
+ n = 3;
+ } else {
+ n = (int)(M_PI / acos(1 - 0.1 / t));
+ if (n < 3) {
+ n = 3;
+ } else if (n > 200) {
+ n = 200;
+ }
+ }
+
+ // Traverse the t axis and do the shading.
+ //
+ // This generates and fills a series of rings. Each ring is defined
+ // by two circles:
+ // sa, ta, xa, ya, ra, colorA
+ // sb, tb, xb, yb, rb, colorB
+ //
+ // The s/t axis is divided into radialMaxSplits parts; these parts
+ // are combined as much as possible while respecting the
+ // radialColorDelta parameter.
+
+ // setup for the start circle
+ ia = 0;
+ sa = sMin;
+ ta = t0 + sa * (t1 - t0);
+ xa = x0 + sa * (x1 - x0);
+ ya = y0 + sa * (y1 - y0);
+ ra = r0 + sa * (r1 - r0);
+ if (ta < t0) {
+ shading->getColor(t0, &colorA);
+ } else if (ta > t1) {
+ shading->getColor(t1, &colorA);
+ } else {
+ shading->getColor(ta, &colorA);
+ }
+
+ while (ia < radialMaxSplits) {
+
+ // go as far along the t axis (toward t1) as we can, such that the
+ // color difference is within the tolerance (radialColorDelta) --
+ // this uses bisection (between the current value, t, and t1),
+ // limited to radialMaxSplits points along the t axis
+ ib = radialMaxSplits;
+ sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
+ tb = t0 + sb * (t1 - t0);
+ if (tb < t0) {
+ shading->getColor(t0, &colorB);
+ } else if (tb > t1) {
+ shading->getColor(t1, &colorB);
+ } else {
+ shading->getColor(tb, &colorB);
+ }
+ while (ib - ia > 1) {
+ for (k = 0; k < nComps; ++k) {
+ if (fabs(colorB.c[k] - colorA.c[k]) > radialColorDelta) {
+ break;
+ }
+ }
+ if (k == nComps) {
+ break;
+ }
+ ib = (ia + ib) / 2;
+ sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
+ tb = t0 + sb * (t1 - t0);
+ if (tb < t0) {
+ shading->getColor(t0, &colorB);
+ } else if (tb > t1) {
+ shading->getColor(t1, &colorB);
+ } else {
+ shading->getColor(tb, &colorB);
+ }
+ }
+
+ // compute center and radius of the circle
+ xb = x0 + sb * (x1 - x0);
+ yb = y0 + sb * (y1 - y0);
+ rb = r0 + sb * (r1 - r0);
+
+ // use the average of the colors at the two circles
+ for (k = 0; k < nComps; ++k) {
+ colorA.c[k] = 0.5 * (colorA.c[k] + colorB.c[k]);
+ }
+ state->setFillColor(&colorA);
+ out->updateFillColor(state);
+
+ // construct path for first circle
+ state->moveTo(xa + ra, ya);
+ for (k = 1; k < n; ++k) {
+ angle = ((double)k / (double)n) * 2 * M_PI;
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
+
+ // construct and append path for second circle
+ state->moveTo(xb + rb, yb);
+ for (k = 1; k < n; ++k) {
+ angle = ((double)k / (double)n) * 2 * M_PI;
+ state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
+ }
+ state->closePath();
+
+ // fill the ring
+ out->eoFill(state);
+ state->clearPath();
+
+ // step to the next value of t
+ ia = ib;
+ sa = sb;
+ ta = tb;
+ xa = xb;
+ ya = yb;
+ ra = rb;
+ colorA = colorB;
+ }
+}
+
void Gfx::doEndPath() {
- if (state->isPath()) {
- if (clip == clipNormal)
+ if (state->isPath() && clip != clipNone) {
+ state->clip();
+ if (clip == clipNormal) {
out->clip(state);
- else if (clip == clipEO)
+ } else {
out->eoClip(state);
+ }
}
clip = clipNone;
state->clearPath();
return;
}
if (printCommands) {
- printf(" font: '%s' %g\n",
+ printf(" font: tag=%s name='%s' %g\n",
+ font->getTag()->getCString(),
font->getName() ? font->getName()->getCString() : "???",
args[1].getNum());
+ fflush(stdout);
}
state->setFont(font, args[1].getNum());
fontChanged = gTrue;
void Gfx::opSetHorizScaling(Object args[], int numArgs) {
state->setHorizScaling(args[0].getNum());
out->updateHorizScaling(state);
+ fontChanged = gTrue;
}
//------------------------------------------------------------------------
void Gfx::opShowSpaceText(Object args[], int numArgs) {
Array *a;
Object obj;
+ int wMode;
int i;
if (!state->getFont()) {
error(getPos(), "No font in show/space");
return;
}
+ wMode = state->getFont()->getWMode();
a = args[0].getArray();
for (i = 0; i < a->getLength(); ++i) {
a->get(i, &obj);
if (obj.isNum()) {
- state->textShift(-obj.getNum() * 0.001 * state->getFontSize());
+ if (wMode) {
+ state->textShift(0, -obj.getNum() * 0.001 * state->getFontSize());
+ } else {
+ state->textShift(-obj.getNum() * 0.001 * state->getFontSize(), 0);
+ }
out->updateTextShift(state, obj.getNum());
} else if (obj.isString()) {
doShowText(obj.getString());
void Gfx::doShowText(GString *s) {
GfxFont *font;
- GfxFontEncoding16 *enc;
- Guchar *p;
- Guchar c8;
- int c16;
- GString *s16;
- char s16a[2];
- int m, n;
-#if 0 //~type3
- double dx, dy, width, height, w, h, x, y;
+ int wMode;
+ double riseX, riseY;
+ CharCode code;
+ Unicode u[8];
+ double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy;
+ double originX, originY, tOriginX, tOriginY;
double oldCTM[6], newCTM[6];
double *mat;
Object charProc;
+ Dict *resDict;
Parser *oldParser;
- int i;
-#else
- double dx, dy, width, height, w, h, sWidth, sHeight;
-#endif
+ char *p;
+ int len, n, uLen, nChars, nSpaces, i;
if (fontChanged) {
out->updateFont(state);
fontChanged = gFalse;
}
font = state->getFont();
+ wMode = font->getWMode();
- //----- 16-bit font
- if (font->is16Bit()) {
- enc = font->getEncoding16();
- if (out->useDrawChar()) {
- out->beginString(state, s);
- s16 = NULL;
- } else {
- s16 = new GString();
- }
- sWidth = sHeight = 0;
- state->textTransformDelta(0, state->getRise(), &dx, &dy);
- p = (Guchar *)s->getCString();
- n = s->getLength();
- while (n > 0) {
- m = getNextChar16(enc, p, &c16);
- if (enc->wMode == 0) {
- width = state->getFontSize() * state->getHorizScaling() *
- font->getWidth16(c16) +
- state->getCharSpace();
- if (c16 == ' ') {
- width += state->getWordSpace();
- }
- height = 0;
- } else {
- width = 0;
- height = state->getFontSize() * font->getHeight16(c16);
- }
- state->textTransformDelta(width, height, &w, &h);
- if (out->useDrawChar()) {
- out->drawChar16(state, state->getCurX() + dx, state->getCurY() + dy,
- w, h, c16);
- state->textShift(width, height);
- } else {
- s16a[0] = (char)(c16 >> 8);
- s16a[1] = (char)c16;
- s16->append(s16a, 2);
- sWidth += w;
- sHeight += h;
- }
- n -= m;
- p += m;
- }
- if (out->useDrawChar()) {
- out->endString(state);
- } else {
- out->drawString16(state, s16);
- delete s16;
- state->textShift(sWidth, sHeight);
- }
+ if (out->useDrawChar()) {
+ out->beginString(state, s);
+ }
- //----- 8-bit font
- } else {
-#if 0 //~type3
- //~ also check out->renderType3()
- if (font->getType() == fontType3) {
- out->beginString(state, s);
- mat = state->getCTM();
- for (i = 0; i < 6; ++i) {
- oldCTM[i] = mat[i];
+ // handle a Type 3 char
+ if (font->getType() == fontType3 && out->interpretType3Chars()) {
+ mat = state->getCTM();
+ for (i = 0; i < 6; ++i) {
+ oldCTM[i] = mat[i];
+ }
+ mat = state->getTextMat();
+ newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2];
+ newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3];
+ newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2];
+ newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3];
+ mat = font->getFontMatrix();
+ newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2];
+ newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3];
+ newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2];
+ newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3];
+ newCTM[0] *= state->getFontSize();
+ newCTM[3] *= state->getFontSize();
+ newCTM[0] *= state->getHorizScaling();
+ newCTM[2] *= state->getHorizScaling();
+ state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
+ curX = state->getCurX();
+ curY = state->getCurY();
+ oldParser = parser;
+ p = s->getCString();
+ len = s->getLength();
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
+ &dx, &dy, &originX, &originY);
+ dx = dx * state->getFontSize() + state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dx += state->getWordSpace();
}
- mat = state->getTextMat();
- newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2];
- newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3];
- newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2];
- newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3];
- mat = font->getFontMatrix();
- newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2];
- newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3];
- newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2];
- newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3];
- newCTM[0] *= state->getFontSize();
- newCTM[3] *= state->getFontSize();
- newCTM[0] *= state->getHorizScaling();
- newCTM[2] *= state->getHorizScaling();
- state->textTransformDelta(0, state->getRise(), &dx, &dy);
- oldParser = parser;
- for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
- c8 = *p;
- font->getCharProc(c8, &charProc);
- state->transform(state->getCurX() + dx, state->getCurY() + dy, &x, &y);
- state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
- //~ out->updateCTM(???)
+ dx *= state->getHorizScaling();
+ dy *= state->getFontSize();
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
+ state->transform(curX + riseX, curY + riseY, &x, &y);
+ out->saveState(state);
+ state = state->save();
+ state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
+ //~ out->updateCTM(???)
+ if (!out->beginType3Char(state, code, u, uLen)) {
+ ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
+ if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
+ pushResources(resDict);
+ }
if (charProc.isStream()) {
display(&charProc, gFalse);
} else {
error(getPos(), "Missing or bad Type3 CharProc entry");
}
- state->setCTM(oldCTM[0], oldCTM[1], oldCTM[2],
- oldCTM[3], oldCTM[4], oldCTM[5]);
- //~ out->updateCTM(???) - use gsave/grestore instead?
+ out->endType3Char(state);
+ if (resDict) {
+ popResources();
+ }
charProc.free();
- width = state->getFontSize() * state->getHorizScaling() *
- font->getWidth(c8) +
- state->getCharSpace();
- if (c8 == ' ') {
- width += state->getWordSpace();
+ }
+ state = state->restore();
+ out->restoreState(state);
+ // GfxState::restore() does *not* restore the current position,
+ // so we track it here with (curX, curY)
+ curX += tdx;
+ curY += tdy;
+ state->moveTo(curX, curY);
+ p += n;
+ len -= n;
+ }
+ parser = oldParser;
+
+ } else if (out->useDrawChar()) {
+ state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
+ p = s->getCString();
+ len = s->getLength();
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
+ &dx, &dy, &originX, &originY);
+ if (wMode) {
+ dx *= state->getFontSize();
+ dy = dy * state->getFontSize() + state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dy += state->getWordSpace();
+ }
+ } else {
+ dx = dx * state->getFontSize() + state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dx += state->getWordSpace();
}
- state->textShift(width);
+ dx *= state->getHorizScaling();
+ dy *= state->getFontSize();
}
- parser = oldParser;
- out->endString(state);
- } else
-#endif
- if (out->useDrawChar()) {
- out->beginString(state, s);
- state->textTransformDelta(0, state->getRise(), &dx, &dy);
- for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
- c8 = *p;
- width = state->getFontSize() * state->getHorizScaling() *
- font->getWidth(c8) +
- state->getCharSpace();
- if (c8 == ' ')
- width += state->getWordSpace();
- state->textTransformDelta(width, 0, &w, &h);
- out->drawChar(state, state->getCurX() + dx, state->getCurY() + dy,
- w, h, c8);
- state->textShift(width);
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
+ originX *= state->getFontSize();
+ originY *= state->getFontSize();
+ state->textTransformDelta(originX, originY, &tOriginX, &tOriginY);
+ out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
+ tdx, tdy, tOriginX, tOriginY, code, u, uLen);
+ state->shift(tdx, tdy);
+ p += n;
+ len -= n;
+ }
+
+ } else {
+ dx = dy = 0;
+ p = s->getCString();
+ len = s->getLength();
+ nChars = nSpaces = 0;
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
+ &dx2, &dy2, &originX, &originY);
+ dx += dx2;
+ dy += dy2;
+ if (n == 1 && *p == ' ') {
+ ++nSpaces;
}
- out->endString(state);
+ ++nChars;
+ p += n;
+ len -= n;
+ }
+ if (wMode) {
+ dx *= state->getFontSize();
+ dy = dy * state->getFontSize()
+ + nChars * state->getCharSpace()
+ + nSpaces * state->getWordSpace();
} else {
- out->drawString(state, s);
- width = state->getFontSize() * state->getHorizScaling() *
- font->getWidth(s) +
- s->getLength() * state->getCharSpace();
- for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
- if (*p == ' ')
- width += state->getWordSpace();
- }
- state->textShift(width);
+ dx = dx * state->getFontSize()
+ + nChars * state->getCharSpace()
+ + nSpaces * state->getWordSpace();
+ dx *= state->getHorizScaling();
+ dy *= state->getFontSize();
}
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
+ out->drawString(state, s);
+ state->shift(tdx, tdy);
}
-}
-int Gfx::getNextChar16(GfxFontEncoding16 *enc, Guchar *p, int *c16) {
- int n;
- int code;
- int a, b, m;
-
- n = enc->codeLen[*p];
- if (n == 1) {
- *c16 = enc->map1[*p];
- } else {
- code = (p[0] << 8) + p[1];
- a = 0;
- b = enc->map2Len;
- // invariant: map2[2*a] <= code < map2[2*b]
- while (b - a > 1) {
- m = (a + b) / 2;
- if (enc->map2[2*m] <= code)
- a = m;
- else if (enc->map2[2*m] > code)
- b = m;
- else
- break;
- }
- *c16 = enc->map2[2*a+1] + (code - enc->map2[2*a]);
+ if (out->useDrawChar()) {
+ out->endString(state);
}
- return n;
+
+ updateLevel += 10 * s->getLength();
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void Gfx::opXObject(Object args[], int numArgs) {
- Object obj1, obj2, refObj;
+ Object obj1, obj2, obj3, refObj;
#if OPI_SUPPORT
Object opiDict;
#endif
refObj.free();
} else if (obj2.isName("Form")) {
doForm(&obj1);
+ } else if (obj2.isName("PS")) {
+ obj1.streamGetDict()->lookup("Level1", &obj3);
+ out->psXObject(obj1.getStream(),
+ obj3.isStream() ? obj3.getStream() : (Stream *)NULL);
} else if (obj2.isName()) {
error(getPos(), "Unknown XObject subtype '%s'", obj2.getName());
} else {
void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
Dict *dict;
- Object obj1, obj2;
int width, height;
int bits;
GBool mask;
+ GBool invert;
GfxColorSpace *colorSpace;
GfxImageColorMap *colorMap;
- GBool invert;
+ Object maskObj;
+ GBool haveMask;
+ int maskColors[2*gfxColorMaxComps];
+ Object obj1, obj2;
+ int i;
// get stream dict
dict = str->getDict();
goto err1;
}
+ // get the mask
+ haveMask = gFalse;
+ dict->lookup("Mask", &maskObj);
+ if (maskObj.isArray()) {
+ for (i = 0; i < maskObj.arrayGetLength(); ++i) {
+ maskObj.arrayGet(i, &obj1);
+ maskColors[i] = obj1.getInt();
+ obj1.free();
+ }
+ haveMask = gTrue;
+ }
+
// draw it
- out->drawImage(state, ref, str, width, height, colorMap, inlineImg);
+ out->drawImage(state, ref, str, width, height, colorMap,
+ haveMask ? maskColors : (int *)NULL, inlineImg);
delete colorMap;
- str->close();
+
+ maskObj.free();
+ }
+
+ if ((i = width * height) > 1000) {
+ i = 1000;
}
+ updateLevel += i;
return;
// get resources
dict->lookup("Resources", &resObj);
- resDict = resObj.isDict() ? resObj.getDict() : NULL;
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
// draw it
doForm1(str, resDict, m, bbox);
resObj.free();
}
-void Gfx::doWidgetForm(Object *str, double xMin, double yMin,
- double xMax, double yMax) {
+void Gfx::doAnnot(Object *str, double xMin, double yMin,
+ double xMax, double yMax) {
Dict *dict, *resDict;
Object matrixObj, bboxObj, resObj;
Object obj1;
- double m[6], bbox[6];
- double sx, sy;
+ double m[6], bbox[6], ictm[6];
+ double *ctm;
+ double formX0, formY0, formX1, formY1;
+ double annotX0, annotY0, annotX1, annotY1;
+ double det, x, y, sx, sy;
int i;
// get stream dict
dict = str->streamGetDict();
- // get bounding box
+ // get the form bounding box
dict->lookup("BBox", &bboxObj);
if (!bboxObj.isArray()) {
bboxObj.free();
}
bboxObj.free();
- // get matrix
+ // get the form matrix
dict->lookup("Matrix", &matrixObj);
if (matrixObj.isArray()) {
for (i = 0; i < 6; ++i) {
}
matrixObj.free();
- // scale form bbox to widget rectangle
- sx = fabs((xMax - xMin) / (bbox[2] - bbox[0]));
- sy = fabs((yMax - yMin) / (bbox[3] - bbox[1]));
- m[0] *= sx; m[1] *= sy;
- m[2] *= sx; m[3] *= sy;
- m[4] *= sx; m[5] *= sy;
+ // transform the form bbox from form space to user space
+ formX0 = bbox[0] * m[0] + bbox[1] * m[2] + m[4];
+ formY0 = bbox[0] * m[1] + bbox[1] * m[3] + m[5];
+ formX1 = bbox[2] * m[0] + bbox[3] * m[2] + m[4];
+ formY1 = bbox[2] * m[1] + bbox[3] * m[3] + m[5];
+
+ // transform the annotation bbox from default user space to user
+ // space: (bbox * baseMatrix) * iCTM
+ ctm = state->getCTM();
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ x = baseMatrix[0] * xMin + baseMatrix[2] * yMin + baseMatrix[4];
+ y = baseMatrix[1] * xMin + baseMatrix[3] * yMin + baseMatrix[5];
+ annotX0 = ictm[0] * x + ictm[2] * y + ictm[4];
+ annotY0 = ictm[1] * x + ictm[3] * y + ictm[5];
+ x = baseMatrix[0] * xMax + baseMatrix[2] * yMax + baseMatrix[4];
+ y = baseMatrix[1] * xMax + baseMatrix[3] * yMax + baseMatrix[5];
+ annotX1 = ictm[0] * x + ictm[2] * y + ictm[4];
+ annotY1 = ictm[1] * x + ictm[3] * y + ictm[5];
+
+ // swap min/max coords
+ if (formX0 > formX1) {
+ x = formX0; formX0 = formX1; formX1 = x;
+ }
+ if (formY0 > formY1) {
+ y = formY0; formY0 = formY1; formY1 = y;
+ }
+ if (annotX0 > annotX1) {
+ x = annotX0; annotX0 = annotX1; annotX1 = x;
+ }
+ if (annotY0 > annotY1) {
+ y = annotY0; annotY0 = annotY1; annotY1 = y;
+ }
- // translate to widget rectangle
- m[4] += xMin;
- m[5] += yMin;
+ // scale the form to fit the annotation bbox
+ if (formX1 == formX0) {
+ // this shouldn't happen
+ sx = 1;
+ } else {
+ sx = (annotX1 - annotX0) / (formX1 - formX0);
+ }
+ if (formY1 == formY0) {
+ // this shouldn't happen
+ sy = 1;
+ } else {
+ sy = (annotY1 - annotY0) / (formY1 - formY0);
+ }
+ m[0] *= sx;
+ m[2] *= sx;
+ m[4] = (m[4] - formX0) * sx + annotX0;
+ m[1] *= sy;
+ m[3] *= sy;
+ m[5] = (m[5] - formY0) * sy + annotY0;
// get resources
dict->lookup("Resources", &resObj);
- resDict = resObj.isDict() ? resObj.getDict() : NULL;
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
// draw it
doForm1(str, resDict, m, bbox);
void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) {
Parser *oldParser;
double oldBaseMatrix[6];
- GfxResources *resPtr;
int i;
// push new resources on stack
- res = new GfxResources(resDict, res);
+ pushResources(resDict);
// save current graphics state
out->saveState(state);
state->lineTo(bbox[2], bbox[3]);
state->lineTo(bbox[0], bbox[3]);
state->closePath();
+ state->clip();
out->clip(state);
state->clearPath();
out->restoreState(state);
// pop resource stack
+ popResources();
+
+ return;
+}
+
+void Gfx::pushResources(Dict *resDict) {
+ res = new GfxResources(xref, resDict, res);
+}
+
+void Gfx::popResources() {
+ GfxResources *resPtr;
+
resPtr = res->getNext();
delete res;
res = resPtr;
-
- return;
}
//------------------------------------------------------------------------
Stream *str;
// build dictionary
- dict.initDict();
+ dict.initDict(xref);
parser->getObj(&obj);
while (!obj.isCmd("ID") && !obj.isEOF()) {
if (!obj.isName()) {
error(getPos(), "Inline image dictionary key must be a name object");
obj.free();
- parser->getObj(&obj);
} else {
key = copyString(obj.getName());
obj.free();
parser->getObj(&obj);
- if (obj.isEOF() || obj.isError())
+ if (obj.isEOF() || obj.isError()) {
+ gfree(key);
break;
+ }
dict.dictAdd(key, &obj);
}
parser->getObj(&obj);
}
- if (obj.isEOF())
+ if (obj.isEOF()) {
error(getPos(), "End of file in inline image");
+ obj.free();
+ dict.free();
+ return NULL;
+ }
obj.free();
// make stream
//------------------------------------------------------------------------
void Gfx::opSetCharWidth(Object args[], int numArgs) {
- error(getPos(), "Encountered 'd0' operator in content stream");
+ out->type3D0(state, args[0].getNum(), args[1].getNum());
}
void Gfx::opSetCacheDevice(Object args[], int numArgs) {
- error(getPos(), "Encountered 'd1' operator in content stream");
+ out->type3D1(state, args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
}
//------------------------------------------------------------------------
if (numArgs == 2)
args[2].print(stdout);
printf("\n");
+ fflush(stdout);
}
}
if (numArgs == 2)
args[2].print(stdout);
printf("\n");
+ fflush(stdout);
}
}
//
// Gfx.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#include "gtypes.h"
class GString;
+class XRef;
class Array;
class Stream;
class Parser;
class OutputDev;
class GfxFontDict;
class GfxFont;
-struct GfxFontEncoding16;
class GfxPattern;
+class GfxShading;
+class GfxAxialShading;
+class GfxRadialShading;
class GfxState;
class Gfx;
+struct PDFRectangle;
//------------------------------------------------------------------------
// Gfx
class GfxResources {
public:
- GfxResources(Dict *resDict, GfxResources *next);
+ GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA);
~GfxResources();
GfxFont *lookupFont(char *name);
GBool lookupXObjectNF(char *name, Object *obj);
void lookupColorSpace(char *name, Object *obj);
GfxPattern *lookupPattern(char *name);
+ GfxShading *lookupShading(char *name);
GBool lookupGState(char *name, Object *obj);
GfxResources *getNext() { return next; }
Object xObjDict;
Object colorSpaceDict;
Object patternDict;
+ Object shadingDict;
Object gStateDict;
GfxResources *next;
};
public:
// Constructor for regular output.
- Gfx(OutputDev *out1, int pageNum, Dict *resDict,
- double dpi, double x1, double y1, double x2, double y2, GBool crop,
- double cropX1, double cropY1, double cropX2, double cropY2,
- int rotate);
+ Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi,
+ PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate,
+ GBool printCommandsA);
+
+ // Constructor for a sub-page object.
+ Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
+ PDFRectangle *box, GBool crop, PDFRectangle *cropBox);
- // Destructor.
~Gfx();
// Interpret a stream or array of streams.
void display(Object *obj, GBool topLevel = gTrue);
- void doWidgetForm(Object *str, double xMin, double yMin,
- double xMax, double yMax);
+ // Display an annotation, given its appearance (a Form XObject) and
+ // bounding box (in default user space).
+ void doAnnot(Object *str, double xMin, double yMin,
+ double xMax, double yMax);
+
+ void pushResources(Dict *resDict);
+ void popResources();
private:
+ XRef *xref; // the xref table for this PDF file
OutputDev *out; // output device
+ GBool subPage; // is this a sub-page object?
+ GBool printCommands; // print the drawing commands (for debugging)
GfxResources *res; // resource stack
+ int updateLevel;
GfxState *state; // current graphics state
GBool fontChanged; // set if font or text matrix has changed
void opCloseFillStroke(Object args[], int numArgs);
void opEOFillStroke(Object args[], int numArgs);
void opCloseEOFillStroke(Object args[], int numArgs);
- void opShFill(Object args[], int numArgs);
void doPatternFill(GBool eoFill);
+ void opShFill(Object args[], int numArgs);
+ void doAxialShFill(GfxAxialShading *shading);
+ void doRadialShFill(GfxRadialShading *shading);
void doEndPath();
// path clipping operators
void opMoveSetShowText(Object args[], int numArgs);
void opShowSpaceText(Object args[], int numArgs);
void doShowText(GString *s);
- int getNextChar16(GfxFontEncoding16 *enc, Guchar *p, int *c16);
// XObject operators
void opXObject(Object args[], int numArgs);
//
// GfxFont.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
-#include <stdlib.h>
-#include <stddef.h>
+#include <aconf.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <ctype.h>
-#include "GString.h"
#include "gmem.h"
-#include "gfile.h"
-#include "config.h"
+#include "Error.h"
#include "Object.h"
-#include "Array.h"
#include "Dict.h"
-#include "Error.h"
-#include "Params.h"
+#include "GlobalParams.h"
+#include "CMap.h"
+#include "CharCodeToUnicode.h"
+#include "FontEncodingTables.h"
+#include "BuiltinFontTables.h"
#include "FontFile.h"
#include "GfxFont.h"
-#include "FontInfo.h"
-#if JAPANESE_SUPPORT
-#include "Japan12CMapInfo.h"
-#endif
-#if CHINESE_GB_SUPPORT
-#include "GB12CMapInfo.h"
-#endif
-#if CHINESE_CNS_SUPPORT
-#include "CNS13CMapInfo.h"
-#endif
-
//------------------------------------------------------------------------
-static int CDECL cmpWidthExcep(const void *w1, const void *w2);
-static int CDECL cmpWidthExcepV(const void *w1, const void *w2);
-
-//------------------------------------------------------------------------
+struct StdFontMapEntry {
+ char *altName;
+ char *properName;
+};
-static Gushort *defCharWidths[12] = {
- courierWidths,
- courierObliqueWidths,
- courierBoldWidths,
- courierBoldObliqueWidths,
- helveticaWidths,
- helveticaObliqueWidths,
- helveticaBoldWidths,
- helveticaBoldObliqueWidths,
- timesRomanWidths,
- timesItalicWidths,
- timesBoldWidths,
- timesBoldItalicWidths
+static StdFontMapEntry stdFontMap[] = {
+ { "Arial", "Helvetica" },
+ { "Arial,Bold", "Helvetica-Bold" },
+ { "Arial,BoldItalic", "Helvetica-BoldOblique" },
+ { "Arial,Italic", "Helvetica-Oblique" },
+ { "Arial-Bold", "Helvetica-Bold" },
+ { "Arial-BoldItalic", "Helvetica-BoldOblique" },
+ { "Arial-BoldItalicMT", "Helvetica-BoldOblique" },
+ { "Arial-BoldMT", "Helvetica-Bold" },
+ { "Arial-Italic", "Helvetica-Oblique" },
+ { "Arial-ItalicMT", "Helvetica-Oblique" },
+ { "ArialMT", "Helvetica" },
+ { "Courier,Bold", "Courier-Bold" },
+ { "Courier,Italic", "Courier-Oblique" },
+ { "Courier,BoldItalic", "Courier-BoldOblique" },
+ { "CourierNew", "Courier" },
+ { "CourierNew,Bold", "Courier-Bold" },
+ { "CourierNew,BoldItalic", "Courier-BoldOblique" },
+ { "CourierNew,Italic", "Courier-Oblique" },
+ { "CourierNew-Bold", "Courier-Bold" },
+ { "CourierNew-BoldItalic", "Courier-BoldOblique" },
+ { "CourierNew-Italic", "Courier-Oblique" },
+ { "CourierNewPS-BoldItalicMT", "Courier-BoldOblique" },
+ { "CourierNewPS-BoldMT", "Courier-Bold" },
+ { "CourierNewPS-ItalicMT", "Courier-Oblique" },
+ { "CourierNewPSMT", "Courier" },
+ { "Helvetica,Bold", "Helvetica-Bold" },
+ { "Helvetica,BoldItalic", "Helvetica-BoldOblique" },
+ { "Helvetica,Italic", "Helvetica-Oblique" },
+ { "Helvetica-BoldItalic", "Helvetica-BoldOblique" },
+ { "Helvetica-Italic", "Helvetica-Oblique" },
+ { "TimesNewRoman", "Times-Roman" },
+ { "TimesNewRoman,Bold", "Times-Bold" },
+ { "TimesNewRoman,BoldItalic", "Times-BoldItalic" },
+ { "TimesNewRoman,Italic", "Times-Italic" },
+ { "TimesNewRoman-Bold", "Times-Bold" },
+ { "TimesNewRoman-BoldItalic", "Times-BoldItalic" },
+ { "TimesNewRoman-Italic", "Times-Italic" },
+ { "TimesNewRomanPS", "Times-Roman" },
+ { "TimesNewRomanPS-Bold", "Times-Bold" },
+ { "TimesNewRomanPS-BoldItalic", "Times-BoldItalic" },
+ { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" },
+ { "TimesNewRomanPS-BoldMT", "Times-Bold" },
+ { "TimesNewRomanPS-Italic", "Times-Italic" },
+ { "TimesNewRomanPS-ItalicMT", "Times-Italic" },
+ { "TimesNewRomanPSMT", "Times-Roman" }
};
//------------------------------------------------------------------------
// GfxFont
//------------------------------------------------------------------------
-GfxFont::GfxFont(char *tag1, Ref id1, Dict *fontDict) {
- BuiltinFont *builtinFont;
- Object obj1, obj2, obj3, obj4;
- int missingWidth;
- char *name2, *p;
- int i;
+GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) {
+ GString *nameA;
+ GfxFont *font;
+ Object obj1;
- // get font tag and ID
- tag = new GString(tag1);
- id = id1;
+ // get base font name
+ nameA = NULL;
+ fontDict->lookup("BaseFont", &obj1);
+ if (obj1.isName()) {
+ nameA = new GString(obj1.getName());
+ }
+ obj1.free();
// get font type
- type = fontUnknownType;
+ font = NULL;
fontDict->lookup("Subtype", &obj1);
- if (obj1.isName("Type1"))
- type = fontType1;
- else if (obj1.isName("Type1C"))
- type = fontType1C;
- else if (obj1.isName("Type3"))
- type = fontType3;
- else if (obj1.isName("TrueType"))
- type = fontTrueType;
- else if (obj1.isName("Type0"))
- type = fontType0;
+ if (obj1.isName("Type1") || obj1.isName("MMType1")) {
+ font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1, fontDict);
+ } else if (obj1.isName("Type1C")) {
+ font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1C, fontDict);
+ } else if (obj1.isName("Type3")) {
+ font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType3, fontDict);
+ } else if (obj1.isName("TrueType")) {
+ font = new Gfx8BitFont(xref, tagA, idA, nameA, fontTrueType, fontDict);
+ } else if (obj1.isName("Type0")) {
+ font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict);
+ } else {
+ error(-1, "Unknown font type: '%s'",
+ obj1.isName() ? obj1.getName() : "???");
+ font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict);
+ }
obj1.free();
- is16 = gFalse;
- // get base font name
- name = NULL;
- fontDict->lookup("BaseFont", &obj1);
- if (obj1.isName())
- name = new GString(obj1.getName());
- obj1.free();
+ return font;
+}
- // Newer Adobe tools are using Base14-compatible TrueType fonts
- // without embedding them, so munge the names into the equivalent
- // PostScript names. This is a kludge -- it would be nice if Adobe
- // followed their own spec.
- if (type == fontTrueType) {
- p = name->getCString();
- name2 = NULL;
- if (!strncmp(p, "Arial", 5)) {
- if (!strcmp(p+5, ",Bold")) {
- name2 = "Helvetica-Bold";
- } else if (!strcmp(p+5, ",Italic")) {
- name2 = "Helvetica-Oblique";
- } else if (!strcmp(p+5, ",BoldItalic")) {
- name2 = "Helvetica-BoldOblique";
- } else {
- name2 = "Helvetica";
- }
- } else if (!strncmp(p, "TimesNewRoman", 13)) {
- if (!strcmp(p+13, ",Bold")) {
- name2 = "Times-Bold";
- } else if (!strcmp(p+13, ",Italic")) {
- name2 = "Times-Italic";
- } else if (!strcmp(p+13, ",BoldItalic")) {
- name2 = "Times-BoldItalic";
- } else {
- name2 = "Times-Roman";
- }
- } else if (!strncmp(p, "CourierNew", 10)) {
- if (!strcmp(p+10, ",Bold")) {
- name2 = "Courier-Bold";
- } else if (!strcmp(p+10, ",Italic")) {
- name2 = "Courier-Oblique";
- } else if (!strcmp(p+10, ",BoldItalic")) {
- name2 = "Courier-BoldOblique";
- } else {
- name2 = "Courier";
- }
- }
- if (name2) {
- delete name;
- name = new GString(name2);
- }
- }
+GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA) {
+ ok = gFalse;
+ tag = new GString(tagA);
+ id = idA;
+ name = nameA;
+ embFontName = NULL;
+ extFontFile = NULL;
+}
- // is it a built-in font?
- builtinFont = NULL;
+GfxFont::~GfxFont() {
+ delete tag;
if (name) {
- for (i = 0; i < numBuiltinFonts; ++i) {
- if (!strcmp(builtinFonts[i].name, name->getCString())) {
- builtinFont = &builtinFonts[i];
- break;
- }
- }
+ delete name;
+ }
+ if (embFontName) {
+ delete embFontName;
+ }
+ if (extFontFile) {
+ delete extFontFile;
}
+}
+
+void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
+ Object obj1, obj2, obj3, obj4;
+ double t;
+ int i;
// assume Times-Roman by default (for substitution purposes)
flags = fontSerif;
- // get info from font descriptor
- embFontName = NULL;
embFontID.num = -1;
embFontID.gen = -1;
missingWidth = 0;
- fontDict->lookup("FontDescriptor", &obj1);
- if (obj1.isDict()) {
+
+ if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) {
// get flags
- obj1.dictLookup("Flags", &obj2);
- if (obj2.isInt())
+ if (obj1.dictLookup("Flags", &obj2)->isInt()) {
flags = obj2.getInt();
+ }
obj2.free();
// get name
obj1.dictLookup("FontName", &obj2);
- if (obj2.isName())
+ if (obj2.isName()) {
embFontName = new GString(obj2.getName());
+ }
obj2.free();
// look for embedded font file
- if (type == fontType1) {
- obj1.dictLookupNF("FontFile", &obj2);
- if (obj2.isRef())
+ if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) {
+ if (type == fontType1) {
embFontID = obj2.getRef();
- obj2.free();
+ } else {
+ error(-1, "Mismatch between font type and embedded font file");
+ }
}
- if (embFontID.num == -1 && type == fontTrueType) {
- obj1.dictLookupNF("FontFile2", &obj2);
- if (obj2.isRef())
+ obj2.free();
+ if (embFontID.num == -1 &&
+ obj1.dictLookupNF("FontFile2", &obj2)->isRef()) {
+ if (type == fontTrueType || type == fontCIDType2) {
embFontID = obj2.getRef();
- obj2.free();
+ } else {
+ error(-1, "Mismatch between font type and embedded font file");
+ }
}
- if (embFontID.num == -1) {
- obj1.dictLookupNF("FontFile3", &obj2);
- if (obj2.isRef()) {
- embFontID = obj2.getRef();
- obj2.fetch(&obj3);
- if (obj3.isStream()) {
- obj3.streamGetDict()->lookup("Subtype", &obj4);
- if (obj4.isName("Type1"))
- type = fontType1;
- else if (obj4.isName("Type1C"))
+ obj2.free();
+ if (embFontID.num == -1 &&
+ obj1.dictLookupNF("FontFile3", &obj2)->isRef()) {
+ if (obj2.fetch(xref, &obj3)->isStream()) {
+ obj3.streamGetDict()->lookup("Subtype", &obj4);
+ if (obj4.isName("Type1")) {
+ if (type == fontType1) {
+ embFontID = obj2.getRef();
+ } else {
+ error(-1, "Mismatch between font type and embedded font file");
+ }
+ } else if (obj4.isName("Type1C")) {
+ if (type == fontType1) {
type = fontType1C;
- else if (obj4.isName("Type3"))
- type = fontType3;
- else if (obj4.isName("TrueType"))
- type = fontTrueType;
- else if (obj4.isName("Type0"))
- type = fontType0;
- obj4.free();
+ embFontID = obj2.getRef();
+ } else if (type == fontType1C) {
+ embFontID = obj2.getRef();
+ } else {
+ error(-1, "Mismatch between font type and embedded font file");
+ }
+ } else if (obj4.isName("TrueType")) {
+ if (type == fontTrueType) {
+ embFontID = obj2.getRef();
+ } else {
+ error(-1, "Mismatch between font type and embedded font file");
+ }
+ } else if (obj4.isName("CIDFontType0C")) {
+ if (type == fontCIDType0) {
+ type = fontCIDType0C;
+ embFontID = obj2.getRef();
+ } else {
+ error(-1, "Mismatch between font type and embedded font file");
+ }
+ } else {
+ error(-1, "Unknown embedded font type '%s'",
+ obj4.isName() ? obj4.getName() : "???");
}
- obj3.free();
+ obj4.free();
}
- obj2.free();
+ obj3.free();
}
+ obj2.free();
// look for MissingWidth
obj1.dictLookup("MissingWidth", &obj2);
- if (obj2.isInt()) {
- missingWidth = obj2.getInt();
+ if (obj2.isNum()) {
+ missingWidth = obj2.getNum();
}
obj2.free();
- }
- obj1.free();
-
- // get Type3 font definition
- if (type == fontType3) {
- fontDict->lookup("CharProcs", &charProcs);
- if (!charProcs.isDict()) {
- error(-1, "Missing or invalid CharProcs dictionary in Type 3 font");
- charProcs.free();
- }
- }
-
- // look for an external font file
- extFontFile = NULL;
- if (type == fontType1 && name)
- findExtFontFile();
-
- // get font matrix
- fontMat[0] = fontMat[3] = 1;
- fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
- if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
- for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
- if (obj1.arrayGet(i, &obj2)->isNum())
- fontMat[i] = obj2.getNum();
- obj2.free();
- }
- }
- obj1.free();
-
- // get encoding and character widths
- if (type == fontType0) {
- getType0EncAndWidths(fontDict);
- } else {
- getEncAndWidths(fontDict, builtinFont, missingWidth);
- }
-}
-
-GfxFont::~GfxFont() {
- delete tag;
- if (name) {
- delete name;
- }
- if (!is16 && encoding) {
- delete encoding;
- }
- if (embFontName) {
- delete embFontName;
- }
- if (extFontFile) {
- delete extFontFile;
- }
- if (charProcs.isDict()) {
- charProcs.free();
- }
- if (is16) {
- gfree(widths16.exceps);
- gfree(widths16.excepsV);
- }
-}
-
-double GfxFont::getWidth(GString *s) {
- double w;
- int i;
- w = 0;
- for (i = 0; i < s->getLength(); ++i)
- w += widths[s->getChar(i) & 0xff];
- return w;
-}
-
-double GfxFont::getWidth16(int c) {
- double w;
- int a, b, m;
-
- w = widths16.defWidth;
- a = -1;
- b = widths16.numExceps;
- // invariant: widths16.exceps[a].last < c < widths16.exceps[b].first
- while (b - a > 1) {
- m = (a + b) / 2;
- if (widths16.exceps[m].last < c) {
- a = m;
- } else if (c < widths16.exceps[m].first) {
- b = m;
- } else {
- w = widths16.exceps[m].width;
- break;
- }
- }
- return w;
-}
-
-double GfxFont::getHeight16(int c) {
- double h;
- int a, b, m;
-
- h = widths16.defHeight;
- a = -1;
- b = widths16.numExcepsV;
- // invariant: widths16.excepsV[a].last < c < widths16.excepsV[b].first
- while (b - a > 1) {
- m = (a + b) / 2;
- if (widths16.excepsV[m].last < c) {
- a = m;
- } else if (c < widths16.excepsV[m].first) {
- b = m;
- } else {
- h = widths16.excepsV[m].height;
- break;
- }
- }
- return h;
-}
-
-double GfxFont::getOriginX16(int c) {
- double vx;
- int a, b, m;
-
- vx = widths16.defWidth / 2;
- a = -1;
- b = widths16.numExcepsV;
- // invariant: widths16.excepsV[a].last < c < widths16.excepsV[b].first
- while (b - a > 1) {
- m = (a + b) / 2;
- if (widths16.excepsV[m].last < c) {
- a = m;
- } else if (c < widths16.excepsV[m].first) {
- b = m;
- } else {
- vx = widths16.excepsV[m].vx;
- break;
- }
- }
- return vx;
-}
-
-double GfxFont::getOriginY16(int c) {
- double vy;
- int a, b, m;
-
- vy = widths16.defVY;
- a = -1;
- b = widths16.numExcepsV;
- // invariant: widths16.excepsV[a].last < c < widths16.excepsV[b].first
- while (b - a > 1) {
- m = (a + b) / 2;
- if (widths16.excepsV[m].last < c) {
- a = m;
- } else if (c < widths16.excepsV[m].first) {
- b = m;
- } else {
- vy = widths16.excepsV[m].vy;
- break;
- }
- }
- return vy;
-}
-
-Object *GfxFont::getCharProc(int code, Object *proc) {
- if (charProcs.isDict()) {
- charProcs.dictLookup(encoding->getCharName(code), proc);
- } else {
- proc->initNull();
- }
- return proc;
-}
-
-void GfxFont::getEncAndWidths(Dict *fontDict, BuiltinFont *builtinFont,
- int missingWidth) {
- Object obj1, obj2, obj3;
- char *buf;
- int len;
- FontFile *fontFile;
- int code, i;
-
- // Encodings start with a base encoding, which can come from
- // (in order of priority):
- // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding
- // - MacRoman / WinAnsi / Standard
- // 2. embedded font file
- // 3. default:
- // - builtin --> builtin encoding
- // - TrueType --> MacRomanEncoding
- // - others --> StandardEncoding
- // and then add a list of differences from
- // FontDict.Encoding.Differences.
-
- // check FontDict for base encoding
- encoding = NULL;
- fontDict->lookup("Encoding", &obj1);
- if (obj1.isDict()) {
- obj1.dictLookup("BaseEncoding", &obj2);
- if (obj2.isName("MacRomanEncoding")) {
- encoding = macRomanEncoding.copy();
- } else if (obj2.isName("WinAnsiEncoding")) {
- encoding = winAnsiEncoding.copy();
- } else if (obj2.isName("StandardEncoding")) {
- encoding = standardEncoding.copy();
+ // get Ascent and Descent
+ obj1.dictLookup("Ascent", &obj2);
+ if (obj2.isNum()) {
+ t = 0.001 * obj2.getNum();
+ // some broken font descriptors set ascent and descent to 0
+ if (t != 0) {
+ ascent = t;
+ }
}
obj2.free();
- } else if (obj1.isName("MacRomanEncoding")) {
- encoding = macRomanEncoding.copy();
- } else if (obj1.isName("WinAnsiEncoding")) {
- encoding = winAnsiEncoding.copy();
- } else if (obj1.isName("StandardEncoding")) {
- encoding = standardEncoding.copy();
- }
- obj1.free();
-
- // check embedded or external font file for base encoding
- if ((type == fontType1 || type == fontType1C) &&
- (extFontFile || embFontID.num >= 0)) {
- if (extFontFile)
- buf = readExtFontFile(&len);
- else
- buf = readEmbFontFile(&len);
- if (buf) {
- if (type == fontType1)
- fontFile = new Type1FontFile(buf, len);
- else
- fontFile = new Type1CFontFile(buf, len);
- if (fontFile->getName()) {
- if (embFontName)
- delete embFontName;
- embFontName = new GString(fontFile->getName());
+ obj1.dictLookup("Descent", &obj2);
+ if (obj2.isNum()) {
+ t = 0.001 * obj2.getNum();
+ // some broken font descriptors set ascent and descent to 0
+ if (t != 0) {
+ descent = t;
}
- if (!encoding)
- encoding = fontFile->getEncoding(gTrue);
- delete fontFile;
- gfree(buf);
}
- }
-
- // get default base encoding
- if (!encoding) {
- if (builtinFont)
- encoding = builtinFont->encoding->copy();
- else if (type == fontTrueType)
- encoding = macRomanEncoding.copy();
- else
- encoding = standardEncoding.copy();
- }
+ obj2.free();
- // merge differences into encoding
- fontDict->lookup("Encoding", &obj1);
- if (obj1.isDict()) {
- obj1.dictLookup("Differences", &obj2);
- if (obj2.isArray()) {
- code = 0;
- for (i = 0; i < obj2.arrayGetLength(); ++i) {
- obj2.arrayGet(i, &obj3);
- if (obj3.isInt()) {
- code = obj3.getInt();
- } else if (obj3.isName()) {
- if (code < 256)
- encoding->addChar(code, copyString(obj3.getName()));
- ++code;
- } else {
- error(-1, "Wrong type in font encoding resource differences (%s)",
- obj3.getTypeName());
+ // font FontBBox
+ if (obj1.dictLookup("FontBBox", &obj2)->isArray()) {
+ for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
+ if (obj2.arrayGet(i, &obj3)->isNum()) {
+ fontBBox[i] = 0.001 * obj3.getNum();
}
obj3.free();
}
}
obj2.free();
+
}
obj1.free();
+}
+
+CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits) {
+ CharCodeToUnicode *ctu;
+ GString *buf;
+ Object obj1;
+ int c;
- // get character widths
- if (builtinFont)
- makeWidths(fontDict, builtinFont->encoding, builtinFont->widths,
- missingWidth);
- else
- makeWidths(fontDict, NULL, NULL, missingWidth);
+ if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) {
+ obj1.free();
+ return NULL;
+ }
+ buf = new GString();
+ obj1.streamReset();
+ while ((c = obj1.streamGetChar()) != EOF) {
+ buf->append(c);
+ }
+ obj1.streamClose();
+ obj1.free();
+ ctu = CharCodeToUnicode::parseCMap(buf, nBits);
+ delete buf;
+ return ctu;
}
void GfxFont::findExtFontFile() {
- char **path;
- FILE *f;
-
- for (path = fontPath; *path; ++path) {
- extFontFile = appendToPath(new GString(*path), name->getCString());
- f = fopen(extFontFile->getCString(), "rb");
- if (!f) {
- extFontFile->append(".pfb");
- f = fopen(extFontFile->getCString(), "rb");
- }
- if (!f) {
- extFontFile->del(extFontFile->getLength() - 4, 4);
- extFontFile->append(".pfa");
- f = fopen(extFontFile->getCString(), "rb");
- }
- if (f) {
- fclose(f);
- break;
+ if (name) {
+ if (type == fontType1) {
+ extFontFile = globalParams->findFontFile(name, ".pfa", ".pfb");
+ } else if (type == fontTrueType) {
+ extFontFile = globalParams->findFontFile(name, ".ttf", NULL);
}
- delete extFontFile;
- extFontFile = NULL;
}
}
char *buf;
if (!(f = fopen(extFontFile->getCString(), "rb"))) {
- error(-1, "Internal: external font file '%s' vanished", extFontFile);
+ error(-1, "External font file '%s' vanished", extFontFile->getCString());
return NULL;
}
fseek(f, 0, SEEK_END);
*len = (int)ftell(f);
fseek(f, 0, SEEK_SET);
buf = (char *)gmalloc(*len);
- if ((int)fread(buf, 1, *len, f) != *len)
+ if ((int)fread(buf, 1, *len, f) != *len) {
error(-1, "Error reading external font file '%s'", extFontFile);
+ }
fclose(f);
return buf;
}
-char *GfxFont::readEmbFontFile(int *len) {
+char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
char *buf;
Object obj1, obj2;
Stream *str;
int size, i;
obj1.initRef(embFontID.num, embFontID.gen);
- obj1.fetch(&obj2);
+ obj1.fetch(xref, &obj2);
if (!obj2.isStream()) {
error(-1, "Embedded font file is not a stream");
obj2.free();
return buf;
}
-void GfxFont::makeWidths(Dict *fontDict, FontEncoding *builtinEncoding,
- Gushort *builtinWidths, int missingWidth) {
- Object obj1, obj2;
- int firstChar, lastChar;
+//------------------------------------------------------------------------
+// Gfx8BitFont
+//------------------------------------------------------------------------
+
+Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
+ GfxFontType typeA, Dict *fontDict):
+ GfxFont(tagA, idA, nameA)
+{
+ BuiltinFont *builtinFont;
+ char **baseEnc;
+ GBool baseEncFromFontFile;
+ char *buf;
+ int len;
+ FontFile *fontFile;
int code, code2;
char *charName;
- Gushort *defWidths;
- int index;
- double mult;
+ GBool missing, hex;
+ Unicode toUnicode[256];
+ double mul;
+ int firstChar, lastChar;
+ Gushort w;
+ Object obj1, obj2, obj3;
+ int n, i, a, b, m;
- // initialize all widths
- for (code = 0; code < 256; ++code) {
- widths[code] = missingWidth * 0.001;
- }
+ type = typeA;
+ ctu = NULL;
- // use widths from built-in font
- if (builtinEncoding) {
- code2 = 0; // to make gcc happy
- for (code = 0; code < 256; ++code) {
- if ((charName = encoding->getCharName(code)) &&
- (code2 = builtinEncoding->getCharCode(charName)) >= 0)
- widths[code] = builtinWidths[code2] * 0.001;
+ // Acrobat 4.0 and earlier substituted Base14-compatible fonts
+ // without providing Widths and a FontDescriptor, so we munge the
+ // names into the proper Base14 names. (This table is from
+ // implementation note 44 in the PDF 1.4 spec.)
+ if (name) {
+ a = 0;
+ b = sizeof(stdFontMap) / sizeof(StdFontMapEntry);
+ // invariant: stdFontMap[a].altName <= name < stdFontMap[b].altName
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (name->cmp(stdFontMap[m].altName) >= 0) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ if (!name->cmp(stdFontMap[a].altName)) {
+ delete name;
+ name = new GString(stdFontMap[a].properName);
}
+ }
- // get widths from font dict
+ // is it a built-in font?
+ builtinFont = NULL;
+ if (name) {
+ for (i = 0; i < nBuiltinFonts; ++i) {
+ if (!name->cmp(builtinFonts[i].name)) {
+ builtinFont = &builtinFonts[i];
+ break;
+ }
+ }
+ }
+
+ // default ascent/descent values
+ if (builtinFont) {
+ ascent = 0.001 * builtinFont->ascent;
+ descent = 0.001 * builtinFont->descent;
+ fontBBox[0] = 0.001 * builtinFont->bbox[0];
+ fontBBox[1] = 0.001 * builtinFont->bbox[1];
+ fontBBox[2] = 0.001 * builtinFont->bbox[2];
+ fontBBox[3] = 0.001 * builtinFont->bbox[3];
} else {
- fontDict->lookup("FirstChar", &obj1);
- firstChar = obj1.isInt() ? obj1.getInt() : 0;
- obj1.free();
- fontDict->lookup("LastChar", &obj1);
- lastChar = obj1.isInt() ? obj1.getInt() : 255;
- obj1.free();
- if (type == fontType3)
- mult = fontMat[0];
- else
- mult = 0.001;
- fontDict->lookup("Widths", &obj1);
- if (obj1.isArray()) {
- for (code = firstChar; code <= lastChar; ++code) {
- obj1.arrayGet(code - firstChar, &obj2);
- if (obj2.isNum())
- widths[code] = obj2.getNum() * mult;
+ ascent = 0.95;
+ descent = -0.35;
+ fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
+ }
+
+ // get info from font descriptor
+ readFontDescriptor(xref, fontDict);
+
+ // look for an external font file
+ findExtFontFile();
+
+ // get font matrix
+ fontMat[0] = fontMat[3] = 1;
+ fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
+ if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
+ for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ fontMat[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ // get Type 3 bounding box, font definition, and resources
+ if (type == fontType3) {
+ if (fontDict->lookup("FontBBox", &obj1)->isArray()) {
+ for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ fontBBox[i] = obj2.getNum();
+ }
obj2.free();
}
+ }
+ obj1.free();
+ if (!fontDict->lookup("CharProcs", &charProcs)->isDict()) {
+ error(-1, "Missing or invalid CharProcs dictionary in Type 3 font");
+ charProcs.free();
+ }
+ if (!fontDict->lookup("Resources", &resources)->isDict()) {
+ resources.free();
+ }
+ }
+
+ //----- build the font encoding -----
+
+ // Encodings start with a base encoding, which can come from
+ // (in order of priority):
+ // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding
+ // - MacRoman / MacExpert / WinAnsi / Standard
+ // 2. embedded or external font file
+ // 3. default:
+ // - builtin --> builtin encoding
+ // - TrueType --> MacRomanEncoding
+ // - others --> StandardEncoding
+ // and then add a list of differences (if any) from
+ // FontDict.Encoding.Differences.
+
+ // check FontDict for base encoding
+ hasEncoding = gFalse;
+ baseEnc = NULL;
+ baseEncFromFontFile = gFalse;
+ fontDict->lookup("Encoding", &obj1);
+ if (obj1.isDict()) {
+ obj1.dictLookup("BaseEncoding", &obj2);
+ if (obj2.isName("MacRomanEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = macRomanEncoding;
+ } else if (obj2.isName("MacExpertEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = macExpertEncoding;
+ } else if (obj2.isName("WinAnsiEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = winAnsiEncoding;
+ } else if (obj2.isName("StandardEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = standardEncoding;
+ }
+ obj2.free();
+ } else if (obj1.isName("MacRomanEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = macRomanEncoding;
+ } else if (obj1.isName("MacExpertEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = macExpertEncoding;
+ } else if (obj1.isName("WinAnsiEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = winAnsiEncoding;
+ } else if (obj1.isName("StandardEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = standardEncoding;
+ }
+
+ // check embedded or external font file for base encoding
+ // (only for Type 1 fonts - trying to get an encoding out of a
+ // TrueType font is a losing proposition)
+ fontFile = NULL;
+ buf = NULL;
+ if ((type == fontType1 || type == fontType1C) &&
+ (extFontFile || embFontID.num >= 0)) {
+ if (extFontFile) {
+ buf = readExtFontFile(&len);
+ } else {
+ buf = readEmbFontFile(xref, &len);
+ }
+ if (buf) {
+ if (type == fontType1C && !strncmp(buf, "%!", 2)) {
+ // various tools (including Adobe's) occasionally embed Type 1
+ // fonts but label them Type 1C
+ type = fontType1;
+ }
+ if (type == fontType1) {
+ fontFile = new Type1FontFile(buf, len);
+ } else {
+ fontFile = new Type1CFontFile(buf, len);
+ }
+ if (fontFile->getName()) {
+ if (embFontName) {
+ delete embFontName;
+ }
+ embFontName = new GString(fontFile->getName());
+ }
+ if (!baseEnc) {
+ baseEnc = fontFile->getEncoding();
+ baseEncFromFontFile = gTrue;
+ }
+ gfree(buf);
+ }
+ }
+
+ // get default base encoding
+ if (!baseEnc) {
+ if (builtinFont) {
+ baseEnc = builtinFont->defaultBaseEnc;
+ } else if (type == fontTrueType) {
+ baseEnc = macRomanEncoding;
} else {
+ baseEnc = standardEncoding;
+ }
+ }
- // couldn't find widths -- use defaults
-#if 0 //~
- //~ certain PDF generators apparently don't include widths
- //~ for Arial and TimesNewRoman -- and this error message
- //~ is a nuisance
- error(-1, "No character widths resource for non-builtin font");
-#endif
- if (isFixedWidth())
- index = 0;
- else if (isSerif())
- index = 8;
- else
- index = 4;
- if (isBold())
- index += 2;
- if (isItalic())
- index += 1;
- defWidths = defCharWidths[index];
- code2 = 0; // to make gcc happy
+ // copy the base encoding
+ for (i = 0; i < 256; ++i) {
+ enc[i] = baseEnc[i];
+ if ((encFree[i] = baseEncFromFontFile) && enc[i]) {
+ enc[i] = copyString(baseEnc[i]);
+ }
+ }
+
+ // merge differences into encoding
+ if (obj1.isDict()) {
+ obj1.dictLookup("Differences", &obj2);
+ if (obj2.isArray()) {
+ hasEncoding = gTrue;
+ code = 0;
+ for (i = 0; i < obj2.arrayGetLength(); ++i) {
+ obj2.arrayGet(i, &obj3);
+ if (obj3.isInt()) {
+ code = obj3.getInt();
+ } else if (obj3.isName()) {
+ if (code < 256) {
+ if (encFree[code]) {
+ gfree(enc[code]);
+ }
+ enc[code] = copyString(obj3.getName());
+ encFree[code] = gTrue;
+ }
+ ++code;
+ } else {
+ error(-1, "Wrong type in font encoding resource differences (%s)",
+ obj3.getTypeName());
+ }
+ obj3.free();
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+ if (fontFile) {
+ delete fontFile;
+ }
+
+ //----- build the mapping to Unicode -----
+
+ // look for a ToUnicode CMap
+ if (!(ctu = readToUnicodeCMap(fontDict, 8))) {
+
+ // no ToUnicode CMap, so use the char names
+
+ // pass 1: use the name-to-Unicode mapping table
+ missing = hex = gFalse;
+ for (code = 0; code < 256; ++code) {
+ if ((charName = enc[code])) {
+ if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) &&
+ strcmp(charName, ".notdef")) {
+ // if it wasn't in the name-to-Unicode table, check for a
+ // name that looks like 'Axx' or 'xx', where 'A' is any letter
+ // and 'xx' is two hex digits
+ if ((strlen(charName) == 3 &&
+ isalpha(charName[0]) &&
+ isxdigit(charName[1]) && isxdigit(charName[2]) &&
+ ((charName[1] >= 'a' && charName[1] <= 'f') ||
+ (charName[1] >= 'A' && charName[1] <= 'F') ||
+ (charName[2] >= 'a' && charName[2] <= 'f') ||
+ (charName[2] >= 'A' && charName[2] <= 'F'))) ||
+ (strlen(charName) == 2 &&
+ isxdigit(charName[0]) && isxdigit(charName[1]) &&
+ ((charName[0] >= 'a' && charName[0] <= 'f') ||
+ (charName[0] >= 'A' && charName[0] <= 'F') ||
+ (charName[1] >= 'a' && charName[1] <= 'f') ||
+ (charName[1] >= 'A' && charName[1] <= 'F')))) {
+ hex = gTrue;
+ }
+ missing = gTrue;
+ }
+ } else {
+ toUnicode[code] = 0;
+ }
+ }
+
+ // pass 2: try to fill in the missing chars, looking for names of
+ // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B'
+ // are any letters, 'xx' is two hex digits, and 'nn' is 2-4
+ // decimal digits
+ if (missing && globalParams->getMapNumericCharNames()) {
for (code = 0; code < 256; ++code) {
- if ((charName = encoding->getCharName(code)) &&
- (code2 = standardEncoding.getCharCode(charName)) >= 0)
- widths[code] = defWidths[code2] * 0.001;
+ if ((charName = enc[code]) && !toUnicode[code] &&
+ strcmp(charName, ".notdef")) {
+ n = strlen(charName);
+ code2 = -1;
+ if (hex && n == 3 && isalpha(charName[0]) &&
+ isxdigit(charName[1]) && isxdigit(charName[2])) {
+ sscanf(charName+1, "%x", &code2);
+ } else if (hex && n == 2 &&
+ isxdigit(charName[0]) && isxdigit(charName[1])) {
+ sscanf(charName, "%x", &code2);
+ } else if (!hex && n >= 2 && n <= 4 &&
+ isdigit(charName[0]) && isdigit(charName[1])) {
+ code2 = atoi(charName);
+ } else if (n >= 3 && n <= 5 &&
+ isdigit(charName[1]) && isdigit(charName[2])) {
+ code2 = atoi(charName+1);
+ } else if (n >= 4 && n <= 6 &&
+ isdigit(charName[2]) && isdigit(charName[3])) {
+ code2 = atoi(charName+2);
+ }
+ if (code2 >= 0 && code2 <= 0xff) {
+ toUnicode[code] = (Unicode)code2;
+ }
+ }
}
}
- obj1.free();
+
+ ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode);
+ }
+
+ //----- get the character widths -----
+
+ // initialize all widths
+ for (code = 0; code < 256; ++code) {
+ widths[code] = missingWidth * 0.001;
+ }
+
+ // use widths from font dict, if present
+ fontDict->lookup("FirstChar", &obj1);
+ firstChar = obj1.isInt() ? obj1.getInt() : 0;
+ obj1.free();
+ fontDict->lookup("LastChar", &obj1);
+ lastChar = obj1.isInt() ? obj1.getInt() : 255;
+ obj1.free();
+ mul = (type == fontType3) ? fontMat[0] : 0.001;
+ fontDict->lookup("Widths", &obj1);
+ if (obj1.isArray()) {
+ flags |= fontFixedWidth;
+ for (code = firstChar; code <= lastChar; ++code) {
+ obj1.arrayGet(code - firstChar, &obj2);
+ if (obj2.isNum()) {
+ widths[code] = obj2.getNum() * mul;
+ if (widths[code] != widths[firstChar]) {
+ flags &= ~fontFixedWidth;
+ }
+ }
+ obj2.free();
+ }
+
+ // use widths from built-in font
+ } else if (builtinFont) {
+ // this is a kludge for broken PDF files that encode char 32
+ // as .notdef
+ if (builtinFont->widths->getWidth("space", &w)) {
+ widths[32] = 0.001 * w;
+ }
+ for (code = 0; code < 256; ++code) {
+ if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
+ widths[code] = 0.001 * w;
+ }
+ }
+
+ // couldn't find widths -- use defaults
+ } else {
+ // this is technically an error -- the Widths entry is required
+ // for all but the Base-14 fonts -- but certain PDF generators
+ // apparently don't include widths for Arial and TimesNewRoman
+ if (isFixedWidth()) {
+ i = 0;
+ } else if (isSerif()) {
+ i = 8;
+ } else {
+ i = 4;
+ }
+ if (isBold()) {
+ i += 2;
+ }
+ if (isItalic()) {
+ i += 1;
+ }
+ builtinFont = builtinFontSubst[i];
+ // this is a kludge for broken PDF files that encode char 32
+ // as .notdef
+ if (builtinFont->widths->getWidth("space", &w)) {
+ widths[32] = 0.001 * w;
+ }
+ for (code = 0; code < 256; ++code) {
+ if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
+ widths[code] = 0.001 * w;
+ }
+ }
+ }
+ obj1.free();
+
+ ok = gTrue;
+}
+
+Gfx8BitFont::~Gfx8BitFont() {
+ int i;
+
+ for (i = 0; i < 256; ++i) {
+ if (encFree[i] && enc[i]) {
+ gfree(enc[i]);
+ }
+ }
+ ctu->decRefCnt();
+ if (charProcs.isDict()) {
+ charProcs.free();
+ }
+ if (resources.isDict()) {
+ resources.free();
}
}
-void GfxFont::getType0EncAndWidths(Dict *fontDict) {
- Object obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8;
- int excepsSize;
- int i, j, k, n;
+int Gfx8BitFont::getNextChar(char *s, int len, CharCode *code,
+ Unicode *u, int uSize, int *uLen,
+ double *dx, double *dy, double *ox, double *oy) {
+ CharCode c;
- widths16.exceps = NULL;
- widths16.excepsV = NULL;
+ *code = c = (CharCode)(*s & 0xff);
+ *uLen = ctu->mapToUnicode(c, u, uSize);
+ *dx = widths[c];
+ *dy = *ox = *oy = 0;
+ return 1;
+}
- // get the CIDFont
- fontDict->lookup("DescendantFonts", &obj1);
- if (!obj1.isArray() || obj1.arrayGetLength() != 1) {
- error(-1, "Bad DescendantFonts entry for Type 0 font");
+CharCodeToUnicode *Gfx8BitFont::getToUnicode() {
+ ctu->incRefCnt();
+ return ctu;
+}
+
+Dict *Gfx8BitFont::getCharProcs() {
+ return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL;
+}
+
+Object *Gfx8BitFont::getCharProc(int code, Object *proc) {
+ if (charProcs.isDict()) {
+ charProcs.dictLookup(enc[code], proc);
+ } else {
+ proc->initNull();
+ }
+ return proc;
+}
+
+Dict *Gfx8BitFont::getResources() {
+ return resources.isDict() ? resources.getDict() : (Dict *)NULL;
+}
+
+//------------------------------------------------------------------------
+// GfxCIDFont
+//------------------------------------------------------------------------
+
+static int cmpWidthExcep(const void *w1, const void *w2) {
+ return ((GfxFontCIDWidthExcep *)w1)->first -
+ ((GfxFontCIDWidthExcep *)w2)->first;
+}
+
+static int cmpWidthExcepV(const void *w1, const void *w2) {
+ return ((GfxFontCIDWidthExcepV *)w1)->first -
+ ((GfxFontCIDWidthExcepV *)w2)->first;
+}
+
+GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
+ Dict *fontDict):
+ GfxFont(tagA, idA, nameA)
+{
+ Dict *desFontDict;
+ GString *collection, *cMapName;
+ Object desFontDictObj;
+ Object obj1, obj2, obj3, obj4, obj5, obj6;
+ int c1, c2;
+ int excepsSize, i, j, k;
+
+ ascent = 0.95;
+ descent = -0.35;
+ fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
+ cMap = NULL;
+ ctu = NULL;
+ widths.defWidth = 1.0;
+ widths.defHeight = -1.0;
+ widths.defVY = 0.880;
+ widths.exceps = NULL;
+ widths.nExceps = 0;
+ widths.excepsV = NULL;
+ widths.nExcepsV = 0;
+ cidToGID = NULL;
+ cidToGIDLen = 0;
+
+ // get the descendant font
+ if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
+ error(-1, "Missing DescendantFonts entry in Type 0 font");
+ obj1.free();
goto err1;
}
- obj1.arrayGet(0, &obj2);
- if (!obj2.isDict()) {
- error(-1, "Bad descendant font of Type 0 font");
- goto err2;
+ if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) {
+ error(-1, "Bad descendant font in Type 0 font");
+ goto err3;
}
+ obj1.free();
+ desFontDict = desFontDictObj.getDict();
- // get font info
- obj2.dictLookup("CIDSystemInfo", &obj3);
- if (!obj3.isDict()) {
- error(-1, "Bad CIDSystemInfo in Type 0 font descendant");
+ // font type
+ if (!desFontDict->lookup("Subtype", &obj1)) {
+ error(-1, "Missing Subtype entry in Type 0 descendant font");
goto err3;
}
- obj3.dictLookup("Registry", &obj4);
- obj3.dictLookup("Ordering", &obj5);
- if (obj4.isString() && obj5.isString()) {
- if (obj4.getString()->cmp("Adobe") == 0 &&
- obj5.getString()->cmp("Japan1") == 0) {
-#if JAPANESE_SUPPORT
- is16 = gTrue;
- enc16.charSet = font16AdobeJapan12;
-#else
- error(-1, "Xpdf was compiled without Japanese font support");
- goto err4;
-#endif
- } else if (obj4.getString()->cmp("Adobe") == 0 &&
- obj5.getString()->cmp("GB1") == 0) {
-#if CHINESE_GB_SUPPORT
- is16 = gTrue;
- enc16.charSet = font16AdobeGB12;
-#else
- error(-1, "Xpdf was compiled without Chinese GB font support");
- goto err4;
-#endif
- } else if (obj4.getString()->cmp("Adobe") == 0 &&
- obj5.getString()->cmp("CNS1") == 0) {
-#if CHINESE_CNS_SUPPORT
- is16 = gTrue;
- enc16.charSet = font16AdobeCNS13;
-#else
- error(-1, "Xpdf was compiled without Chinese CNS font support");
- goto err4;
-#endif
- } else {
- error(-1, "Uknown Type 0 character set: %s-%s",
- obj4.getString()->getCString(), obj5.getString()->getCString());
- goto err4;
- }
+ if (obj1.isName("CIDFontType0")) {
+ type = fontCIDType0;
+ } else if (obj1.isName("CIDFontType2")) {
+ type = fontCIDType2;
} else {
- error(-1, "Unknown Type 0 character set");
+ error(-1, "Unknown Type 0 descendant font type '%s'",
+ obj1.isName() ? obj1.getName() : "???");
+ goto err3;
+ }
+ obj1.free();
+
+ // get info from font descriptor
+ readFontDescriptor(xref, desFontDict);
+
+ // look for an external font file
+ findExtFontFile();
+
+ //----- encoding info -----
+
+ // char collection
+ if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) {
+ error(-1, "Missing CIDSystemInfo dictionary in Type 0 descendant font");
+ goto err3;
+ }
+ obj1.dictLookup("Registry", &obj2);
+ obj1.dictLookup("Ordering", &obj3);
+ if (!obj2.isString() || !obj3.isString()) {
+ error(-1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
goto err4;
}
- obj5.free();
- obj4.free();
+ collection = obj2.getString()->copy()->append('-')->append(obj3.getString());
obj3.free();
+ obj2.free();
+ obj1.free();
- // get default char width
- obj2.dictLookup("DW", &obj3);
- if (obj3.isInt())
- widths16.defWidth = obj3.getInt() * 0.001;
- else
- widths16.defWidth = 1.0;
- obj3.free();
+ // look for a ToUnicode CMap
+ if (!(ctu = readToUnicodeCMap(fontDict, 16))) {
+
+ // the "Adobe-Identity" and "Adobe-UCS" collections don't have
+ // cidToUnicode files
+ if (collection->cmp("Adobe-Identity") &&
+ collection->cmp("Adobe-UCS")) {
- // get default char metrics for vertical font
- obj2.dictLookup("DW2", &obj3);
- widths16.defVY = 0.880;
- widths16.defHeight = -1;
- if (obj3.isArray() && obj3.arrayGetLength() == 2) {
- obj3.arrayGet(0, &obj4);
- if (obj4.isInt()) {
- widths16.defVY = obj4.getInt() * 0.001;
+ // look for a user-supplied .cidToUnicode file
+ if (!(ctu = globalParams->getCIDToUnicode(collection))) {
+ error(-1, "Unknown character collection '%s'",
+ collection->getCString());
+ delete collection;
+ goto err2;
+ }
}
- obj4.free();
- obj3.arrayGet(1, &obj4);
- if (obj4.isInt()) {
- widths16.defHeight = obj4.getInt() * 0.001;
+ }
+
+ // encoding (i.e., CMap)
+ //~ need to handle a CMap stream here
+ //~ also need to deal with the UseCMap entry in the stream dict
+ if (!fontDict->lookup("Encoding", &obj1)->isName()) {
+ error(-1, "Missing or invalid Encoding entry in Type 0 font");
+ delete collection;
+ goto err3;
+ }
+ cMapName = new GString(obj1.getName());
+ obj1.free();
+ if (!(cMap = globalParams->getCMap(collection, cMapName))) {
+ error(-1, "Unknown CMap '%s' for character collection '%s'",
+ cMapName->getCString(), collection->getCString());
+ delete collection;
+ delete cMapName;
+ goto err2;
+ }
+ delete collection;
+ delete cMapName;
+
+ // CIDToGIDMap (for embedded TrueType fonts)
+ if (type == fontCIDType2) {
+ fontDict->lookup("CIDToGIDMap", &obj1);
+ if (obj1.isStream()) {
+ cidToGIDLen = 0;
+ i = 64;
+ cidToGID = (Gushort *)gmalloc(i * sizeof(Gushort));
+ obj1.streamReset();
+ while ((c1 = obj1.streamGetChar()) != EOF &&
+ (c2 = obj1.streamGetChar()) != EOF) {
+ if (cidToGIDLen == i) {
+ i *= 2;
+ cidToGID = (Gushort *)grealloc(cidToGID, i * sizeof(Gushort));
+ }
+ cidToGID[cidToGIDLen++] = (Gushort)((c1 << 8) + c2);
+ }
+ } else if (!obj1.isName("Identity") && !obj1.isNull()) {
+ error(-1, "Invalid CIDToGIDMap entry in CID font");
}
- obj4.free();
+ obj1.free();
}
- obj3.free();
- // get char width exceptions
- widths16.exceps = NULL;
- widths16.numExceps = 0;
- obj2.dictLookup("W", &obj3);
- if (obj3.isArray()) {
+ //----- character metrics -----
+
+ // default char width
+ if (desFontDict->lookup("DW", &obj1)->isInt()) {
+ widths.defWidth = obj1.getInt() * 0.001;
+ }
+ obj1.free();
+
+ // char width exceptions
+ if (desFontDict->lookup("W", &obj1)->isArray()) {
excepsSize = 0;
- k = 0;
i = 0;
- while (i+1 < obj3.arrayGetLength()) {
- obj3.arrayGet(i, &obj4);
- obj3.arrayGet(i+1, &obj5);
- if (obj4.isInt() && obj5.isInt()) {
- obj3.arrayGet(i+2, &obj6);
- if (!obj6.isNum()) {
+ while (i + 1 < obj1.arrayGetLength()) {
+ obj1.arrayGet(i, &obj2);
+ obj1.arrayGet(i + 1, &obj3);
+ if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) {
+ if (obj1.arrayGet(i + 2, &obj4)->isNum()) {
+ if (widths.nExceps == excepsSize) {
+ excepsSize += 16;
+ widths.exceps = (GfxFontCIDWidthExcep *)
+ grealloc(widths.exceps,
+ excepsSize * sizeof(GfxFontCIDWidthExcep));
+ }
+ widths.exceps[widths.nExceps].first = obj2.getInt();
+ widths.exceps[widths.nExceps].last = obj3.getInt();
+ widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
+ ++widths.nExceps;
+ } else {
error(-1, "Bad widths array in Type 0 font");
- obj6.free();
- obj5.free();
- obj4.free();
- break;
- }
- if (k == excepsSize) {
- excepsSize += 16;
- widths16.exceps = (GfxFontWidthExcep *)
- grealloc(widths16.exceps,
- excepsSize * sizeof(GfxFontWidthExcep));
}
- widths16.exceps[k].first = obj4.getInt();
- widths16.exceps[k].last = obj5.getInt();
- widths16.exceps[k].width = obj6.getNum() * 0.001;
- obj6.free();
- ++k;
+ obj4.free();
i += 3;
- } else if (obj4.isInt() && obj5.isArray()) {
- if (k + obj5.arrayGetLength() >= excepsSize) {
- excepsSize = (k + obj5.arrayGetLength() + 15) & ~15;
- widths16.exceps = (GfxFontWidthExcep *)
- grealloc(widths16.exceps,
- excepsSize * sizeof(GfxFontWidthExcep));
+ } else if (obj2.isInt() && obj3.isArray()) {
+ if (widths.nExceps + obj3.arrayGetLength() > excepsSize) {
+ excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15;
+ widths.exceps = (GfxFontCIDWidthExcep *)
+ grealloc(widths.exceps,
+ excepsSize * sizeof(GfxFontCIDWidthExcep));
}
- n = obj4.getInt();
- for (j = 0; j < obj5.arrayGetLength(); ++j) {
- obj5.arrayGet(j, &obj6);
- if (!obj6.isNum()) {
+ j = obj2.getInt();
+ for (k = 0; k < obj3.arrayGetLength(); ++k) {
+ if (obj3.arrayGet(k, &obj4)->isNum()) {
+ widths.exceps[widths.nExceps].first = j;
+ widths.exceps[widths.nExceps].last = j;
+ widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
+ ++j;
+ ++widths.nExceps;
+ } else {
error(-1, "Bad widths array in Type 0 font");
- obj6.free();
- break;
}
- widths16.exceps[k].first = widths16.exceps[k].last = n++;
- widths16.exceps[k].width = obj6.getNum() * 0.001;
- obj6.free();
- ++k;
+ obj4.free();
}
i += 2;
} else {
error(-1, "Bad widths array in Type 0 font");
- obj6.free();
- obj5.free();
- obj4.free();
- break;
+ ++i;
}
- obj5.free();
- obj4.free();
+ obj3.free();
+ obj2.free();
}
- widths16.numExceps = k;
- if (k > 0)
- qsort(widths16.exceps, k, sizeof(GfxFontWidthExcep), &cmpWidthExcep);
+ qsort(widths.exceps, widths.nExceps, sizeof(GfxFontCIDWidthExcep),
+ &cmpWidthExcep);
}
- obj3.free();
+ obj1.free();
- // get char metric exceptions for vertical font
- widths16.excepsV = NULL;
- widths16.numExcepsV = 0;
- obj2.dictLookup("W2", &obj3);
- if (obj3.isArray()) {
+ // default metrics for vertical font
+ if (desFontDict->lookup("DW2", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ if (obj1.arrayGet(0, &obj2)->isNum()) {
+ widths.defVY = obj1.getNum() * 0.001;
+ }
+ obj2.free();
+ if (obj1.arrayGet(1, &obj2)->isNum()) {
+ widths.defHeight = obj1.getNum() * 0.001;
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ // char metric exceptions for vertical font
+ if (desFontDict->lookup("W2", &obj1)->isArray()) {
excepsSize = 0;
- k = 0;
i = 0;
- while (i+1 < obj3.arrayGetLength()) {
- obj3.arrayGet(i, &obj4);
- obj3.arrayGet(i+1, &obj5);
- if (obj4.isInt() && obj5.isInt()) {
- obj3.arrayGet(i+2, &obj6);
- obj3.arrayGet(i+3, &obj7);
- obj3.arrayGet(i+4, &obj8);
- if (!obj6.isNum() || !obj7.isNum() || !obj8.isNum()) {
+ while (i + 1 < obj1.arrayGetLength()) {
+ obj1.arrayGet(0, &obj2);
+ obj2.arrayGet(0, &obj3);
+ if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) {
+ if (obj1.arrayGet(i + 2, &obj4)->isNum() &&
+ obj1.arrayGet(i + 3, &obj5)->isNum() &&
+ obj1.arrayGet(i + 4, &obj6)->isNum()) {
+ if (widths.nExcepsV == excepsSize) {
+ excepsSize += 16;
+ widths.excepsV = (GfxFontCIDWidthExcepV *)
+ grealloc(widths.excepsV,
+ excepsSize * sizeof(GfxFontCIDWidthExcepV));
+ }
+ widths.excepsV[widths.nExcepsV].first = obj2.getInt();
+ widths.excepsV[widths.nExcepsV].last = obj3.getInt();
+ widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001;
+ widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001;
+ widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001;
+ ++widths.nExcepsV;
+ } else {
error(-1, "Bad widths (W2) array in Type 0 font");
- obj8.free();
- obj7.free();
- obj6.free();
- obj5.free();
- obj4.free();
- break;
- }
- if (k == excepsSize) {
- excepsSize += 16;
- widths16.excepsV = (GfxFontWidthExcepV *)
- grealloc(widths16.excepsV,
- excepsSize * sizeof(GfxFontWidthExcepV));
}
- widths16.excepsV[k].first = obj4.getInt();
- widths16.excepsV[k].last = obj5.getInt();
- widths16.excepsV[k].height = obj6.getNum() * 0.001;
- widths16.excepsV[k].vx = obj7.getNum() * 0.001;
- widths16.excepsV[k].vy = obj8.getNum() * 0.001;
- obj8.free();
- obj7.free();
obj6.free();
- ++k;
+ obj5.free();
+ obj4.free();
i += 5;
- } else if (obj4.isInt() && obj5.isArray()) {
- if (k + obj5.arrayGetLength() / 3 >= excepsSize) {
- excepsSize = (k + obj5.arrayGetLength() / 3 + 15) & ~15;
- widths16.excepsV = (GfxFontWidthExcepV *)
- grealloc(widths16.excepsV,
- excepsSize * sizeof(GfxFontWidthExcepV));
+ } else if (obj2.isInt() && obj3.isArray()) {
+ if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) {
+ excepsSize =
+ (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15;
+ widths.excepsV = (GfxFontCIDWidthExcepV *)
+ grealloc(widths.excepsV,
+ excepsSize * sizeof(GfxFontCIDWidthExcepV));
}
- n = obj4.getInt();
- for (j = 0; j < obj5.arrayGetLength(); j += 3) {
- obj5.arrayGet(j, &obj6);
- obj5.arrayGet(j+1, &obj7);
- obj5.arrayGet(j+1, &obj8);
- if (!obj6.isNum() || !obj7.isNum() || !obj8.isNum()) {
+ j = obj2.getInt();
+ for (k = 0; k < obj3.arrayGetLength(); ++k) {
+ if (obj3.arrayGet(k, &obj4)->isNum() &&
+ obj3.arrayGet(k, &obj5)->isNum() &&
+ obj3.arrayGet(k, &obj6)->isNum()) {
+ widths.excepsV[widths.nExceps].first = j;
+ widths.excepsV[widths.nExceps].last = j;
+ widths.excepsV[widths.nExceps].height = obj4.getNum() * 0.001;
+ widths.excepsV[widths.nExceps].vx = obj5.getNum() * 0.001;
+ widths.excepsV[widths.nExceps].vy = obj6.getNum() * 0.001;
+ ++j;
+ ++widths.nExcepsV;
+ } else {
error(-1, "Bad widths (W2) array in Type 0 font");
- obj6.free();
- break;
}
- widths16.excepsV[k].first = widths16.exceps[k].last = n++;
- widths16.excepsV[k].height = obj6.getNum() * 0.001;
- widths16.excepsV[k].vx = obj7.getNum() * 0.001;
- widths16.excepsV[k].vy = obj8.getNum() * 0.001;
- obj8.free();
- obj7.free();
obj6.free();
- ++k;
+ obj5.free();
+ obj4.free();
}
i += 2;
} else {
- error(-1, "Bad widths array in Type 0 font");
- obj5.free();
- obj4.free();
- break;
+ error(-1, "Bad widths (W2) array in Type 0 font");
+ ++i;
}
- obj5.free();
- obj4.free();
- }
- widths16.numExcepsV = k;
- if (k > 0) {
- qsort(widths16.excepsV, k, sizeof(GfxFontWidthExcepV), &cmpWidthExcepV);
+ obj3.free();
+ obj2.free();
}
+ qsort(widths.excepsV, widths.nExcepsV, sizeof(GfxFontCIDWidthExcepV),
+ &cmpWidthExcepV);
}
- obj3.free();
+ obj1.free();
+ desFontDictObj.free();
+ ok = gTrue;
+ return;
+
+ err4:
+ obj3.free();
obj2.free();
+ err3:
obj1.free();
+ err2:
+ desFontDictObj.free();
+ err1:;
+}
- // get encoding (CMap)
- fontDict->lookup("Encoding", &obj1);
- if (!obj1.isName()) {
- error(-1, "Bad encoding for Type 0 font");
- goto err1;
+GfxCIDFont::~GfxCIDFont() {
+ if (cMap) {
+ cMap->decRefCnt();
}
-#if JAPANESE_SUPPORT
- if (enc16.charSet == font16AdobeJapan12) {
- for (i = 0; gfxJapan12Tab[i].name; ++i) {
- if (!strcmp(obj1.getName(), gfxJapan12Tab[i].name))
- break;
- }
- if (!gfxJapan12Tab[i].name) {
- error(-1, "Unknown encoding '%s' for Adobe-Japan1-2 font",
- obj1.getName());
- goto err1;
- }
- enc16.enc = gfxJapan12Tab[i].enc;
+ if (ctu) {
+ ctu->decRefCnt();
}
-#endif
-#if CHINESE_GB_SUPPORT
- if (enc16.charSet == font16AdobeGB12) {
- for (i = 0; gfxGB12Tab[i].name; ++i) {
- if (!strcmp(obj1.getName(), gfxGB12Tab[i].name))
- break;
- }
- if (!gfxGB12Tab[i].name) {
- error(-1, "Unknown encoding '%s' for Adobe-GB1-2 font",
- obj1.getName());
- goto err1;
- }
- enc16.enc = gfxGB12Tab[i].enc;
+ gfree(widths.exceps);
+ gfree(widths.excepsV);
+ if (cidToGID) {
+ gfree(cidToGID);
}
-#endif
-#if CHINESE_CNS_SUPPORT
- if (enc16.charSet == font16AdobeCNS13) {
- for (i = 0; gfxCNS13Tab[i].name; ++i) {
- if (!strcmp(obj1.getName(), gfxCNS13Tab[i].name))
- break;
+}
+
+int GfxCIDFont::getNextChar(char *s, int len, CharCode *code,
+ Unicode *u, int uSize, int *uLen,
+ double *dx, double *dy, double *ox, double *oy) {
+ CID cid;
+ double w, h, vx, vy;
+ int n, a, b, m;
+
+ if (!cMap) {
+ *code = 0;
+ *uLen = 0;
+ *dx = *dy = 0;
+ return 1;
+ }
+
+ *code = (CharCode)(cid = cMap->getCID(s, len, &n));
+ if (ctu) {
+ *uLen = ctu->mapToUnicode(cid, u, uSize);
+ } else {
+ *uLen = 0;
+ }
+
+ // horizontal
+ if (cMap->getWMode() == 0) {
+ w = widths.defWidth;
+ h = vx = vy = 0;
+ if (widths.nExceps > 0 && cid >= widths.exceps[0].first) {
+ a = 0;
+ b = widths.nExceps;
+ // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (widths.exceps[m].first <= cid) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ if (cid <= widths.exceps[a].last) {
+ w = widths.exceps[a].width;
+ }
}
- if (!gfxCNS13Tab[i].name) {
- error(-1, "Unknown encoding '%s' for Adobe-CNS1-3 font",
- obj1.getName());
- goto err1;
+
+ // vertical
+ } else {
+ w = 0;
+ h = widths.defHeight;
+ vx = widths.defWidth / 2;
+ vy = widths.defVY;
+ if (widths.nExcepsV > 0 && cid >= widths.excepsV[0].first) {
+ a = 0;
+ b = widths.nExcepsV;
+ // invariant: widths.excepsV[a].first <= cid < widths.excepsV[b].first
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (widths.excepsV[m].last <= cid) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ if (cid <= widths.excepsV[a].last) {
+ h = widths.excepsV[a].height;
+ vx = widths.excepsV[a].vx;
+ vy = widths.excepsV[a].vy;
+ }
}
- enc16.enc = gfxCNS13Tab[i].enc;
}
-#endif
- obj1.free();
- return;
+ *dx = w;
+ *dy = h;
+ *ox = vx;
+ *oy = vy;
- err4:
- obj5.free();
- obj4.free();
- err3:
- obj3.free();
- err2:
- obj2.free();
- err1:
- obj1.free();
- //~ fix this --> add 16-bit font support to FontFile
- encoding = new FontEncoding();
- makeWidths(fontDict, NULL, NULL, 0);
+ return n;
+}
+
+int GfxCIDFont::getWMode() {
+ return cMap ? cMap->getWMode() : 0;
}
-static int CDECL cmpWidthExcep(const void *w1, const void *w2) {
- return ((GfxFontWidthExcep *)w1)->first - ((GfxFontWidthExcep *)w2)->first;
+CharCodeToUnicode *GfxCIDFont::getToUnicode() {
+ ctu->incRefCnt();
+ return ctu;
}
-static int CDECL cmpWidthExcepV(const void *w1, const void *w2) {
- return ((GfxFontWidthExcepV *)w1)->first - ((GfxFontWidthExcepV *)w2)->first;
+GString *GfxCIDFont::getCollection() {
+ return cMap ? cMap->getCollection() : (GString *)NULL;
}
//------------------------------------------------------------------------
// GfxFontDict
//------------------------------------------------------------------------
-GfxFontDict::GfxFontDict(Dict *fontDict) {
+GfxFontDict::GfxFontDict(XRef *xref, Dict *fontDict) {
int i;
Object obj1, obj2;
fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *));
for (i = 0; i < numFonts; ++i) {
fontDict->getValNF(i, &obj1);
- obj1.fetch(&obj2);
+ obj1.fetch(xref, &obj2);
if (obj1.isRef() && obj2.isDict()) {
- fonts[i] = new GfxFont(fontDict->getKey(i), obj1.getRef(),
- obj2.getDict());
+ fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i),
+ obj1.getRef(), obj2.getDict());
+ if (fonts[i] && !fonts[i]->isOk()) {
+ delete fonts[i];
+ fonts[i] = NULL;
+ }
} else {
- error(-1, "font resource is not a dictionary");
+ error(-1, "font resource is not a dictionary reference");
fonts[i] = NULL;
}
obj1.free();
GfxFontDict::~GfxFontDict() {
int i;
- for (i = 0; i < numFonts; ++i)
- delete fonts[i];
+ for (i = 0; i < numFonts; ++i) {
+ if (fonts[i]) {
+ delete fonts[i];
+ }
+ }
gfree(fonts);
}
int i;
for (i = 0; i < numFonts; ++i) {
- if (fonts[i]->matches(tag))
+ if (fonts[i] && fonts[i]->matches(tag)) {
return fonts[i];
+ }
}
return NULL;
}
//
// GfxFont.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#include "gtypes.h"
#include "GString.h"
#include "Object.h"
-#include "FontEncoding.h"
+#include "CharTypes.h"
class Dict;
-struct BuiltinFont;
+class CMap;
+class CharCodeToUnicode;
+struct GfxFontCIDWidths;
//------------------------------------------------------------------------
-// GfxFontCharSet16
+// GfxFontType
//------------------------------------------------------------------------
-enum GfxFontCharSet16 {
- font16AdobeJapan12, // Adobe-Japan1-2
- font16AdobeGB12, // Adobe-GB1-2 (Chinese)
- font16AdobeCNS13 // Adobe-CNS1-3 (Chinese)
-};
-
-//------------------------------------------------------------------------
-// GfxFontEncoding16
-//------------------------------------------------------------------------
-
-struct GfxFontEncoding16 {
- int wMode; // writing mode (0=horizontal, 1=vertical)
- Guchar codeLen[256]; // length of codes, in bytes, indexed by
- // first byte of code
- Gushort map1[256]; // one-byte code mapping:
- // map1[code] --> 16-bit char selector
- Gushort *map2; // two-byte code mapping
- // map2[2*i] --> first code in range
- // map2[2*i+1] --> 16-bit char selector
- // for map2[2*i]
- int map2Len; // length of map2 array (divided by 2)
+enum GfxFontType {
+ //----- Gfx8BitFont
+ fontUnknownType,
+ fontType1,
+ fontType1C,
+ fontType3,
+ fontTrueType,
+ //----- GfxCIDFont
+ fontCIDType0,
+ fontCIDType0C,
+ fontCIDType2
};
//------------------------------------------------------------------------
-// GfxFontWidths16
+// GfxFontCIDWidths
//------------------------------------------------------------------------
-struct GfxFontWidthExcep {
- int first; // this record applies to
- int last; // chars <first>..<last>
+struct GfxFontCIDWidthExcep {
+ CID first; // this record applies to
+ CID last; // CIDs <first>..<last>
double width; // char width
};
-struct GfxFontWidthExcepV {
- int first; // this record applies to
- int last; // chars <first>..<last>
+struct GfxFontCIDWidthExcepV {
+ CID first; // this record applies to
+ CID last; // CIDs <first>..<last>
double height; // char height
double vx, vy; // origin position
};
-struct GfxFontWidths16 {
+struct GfxFontCIDWidths {
double defWidth; // default char width
double defHeight; // default char height
double defVY; // default origin position
- GfxFontWidthExcep *exceps; // exceptions
- int numExceps; // number of valid entries in exceps
- GfxFontWidthExcepV *excepsV; // exceptions for vertical font
- int numExcepsV; // number of valid entries in excepsV
+ GfxFontCIDWidthExcep *exceps; // exceptions
+ int nExceps; // number of valid entries in exceps
+ GfxFontCIDWidthExcepV * // exceptions for vertical font
+ excepsV;
+ int nExcepsV; // number of valid entries in excepsV
};
//------------------------------------------------------------------------
#define fontItalic (1 << 6)
#define fontBold (1 << 18)
-enum GfxFontType {
- fontUnknownType,
- fontType1,
- fontType1C,
- fontType3,
- fontTrueType,
- fontType0
-};
-
class GfxFont {
public:
- // Constructor.
- GfxFont(char *tag1, Ref id1, Dict *fontDict);
+ // Build a GfxFont object.
+ static GfxFont *makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict);
- // Destructor.
- ~GfxFont();
+ GfxFont(char *tagA, Ref idA, GString *nameA);
+
+ virtual ~GfxFont();
+
+ GBool isOk() { return ok; }
// Get font tag.
GString *getTag() { return tag; }
// Get font dictionary ID.
- Ref getID() { return id; }
+ Ref *getID() { return &id; }
// Does this font match the tag?
- GBool matches(char *tag1) { return !tag->cmp(tag1); }
+ GBool matches(char *tagA) { return !tag->cmp(tagA); }
// Get base font name.
GString *getName() { return name; }
// Get font type.
GfxFontType getType() { return type; }
-
- // Does this font use 16-bit characters?
- GBool is16Bit() { return is16; }
+ virtual GBool isCIDFont() { return gFalse; }
// Get embedded font ID, i.e., a ref for the font file stream.
// Returns false if there is no embedded font.
// Get the PostScript font name for the embedded font. Returns
// NULL if there is no embedded font.
- char *getEmbeddedFontName()
- { return embFontName ? embFontName->getCString() : (char *)NULL; }
+ GString *getEmbeddedFontName() { return embFontName; }
// Get the name of the external font file. Returns NULL if there
// is no external font file.
GBool isItalic() { return flags & fontItalic; }
GBool isBold() { return flags & fontBold; }
- // Get width of a character or string.
- double getWidth(Guchar c) { return widths[c]; }
- double getWidth(GString *s);
+ // Return the font matrix.
+ double *getFontMatrix() { return fontMat; }
+
+ // Return the font bounding box.
+ double *getFontBBox() { return fontBBox; }
+
+ // Return the ascent and descent values.
+ double getAscent() { return ascent; }
+ double getDescent() { return descent; }
+
+ // Return the writing mode (0=horizontal, 1=vertical).
+ virtual int getWMode() { return 0; }
+
+ // Read an external or embedded font file into a buffer.
+ char *readExtFontFile(int *len);
+ char *readEmbFontFile(XRef *xref, int *len);
+
+ // Get the next char from a string <s> of <len> bytes, returning the
+ // char <code>, its Unicode mapping <u>, its displacement vector
+ // (<dx>, <dy>), and its origin offset vector (<ox>, <oy>). <uSize>
+ // is the number of entries available in <u>, and <uLen> is set to
+ // the number actually used. Returns the number of bytes used by
+ // the char code.
+ virtual int getNextChar(char *s, int len, CharCode *code,
+ Unicode *u, int uSize, int *uLen,
+ double *dx, double *dy, double *ox, double *oy) = 0;
+
+protected:
+
+ void readFontDescriptor(XRef *xref, Dict *fontDict);
+ CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits);
+ void findExtFontFile();
+
+ GString *tag; // PDF font tag
+ Ref id; // reference (used as unique ID)
+ GString *name; // font name
+ GfxFontType type; // type of font
+ int flags; // font descriptor flags
+ GString *embFontName; // name of embedded font
+ Ref embFontID; // ref to embedded font file stream
+ GString *extFontFile; // external font file name
+ double fontMat[6]; // font matrix (Type 3 only)
+ double fontBBox[4]; // font bounding box (Type 3 only)
+ double missingWidth; // "default" width
+ double ascent; // max height above baseline
+ double descent; // max depth below baseline
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// Gfx8BitFont
+//------------------------------------------------------------------------
- // Get character metrics for 16-bit font.
- double getWidth16(int c);
- double getHeight16(int c);
- double getOriginX16(int c);
- double getOriginY16(int c);
+class Gfx8BitFont: public GfxFont {
+public:
+
+ Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
+ GfxFontType typeA, Dict *fontDict);
+
+ virtual ~Gfx8BitFont();
+
+ virtual int getNextChar(char *s, int len, CharCode *code,
+ Unicode *u, int uSize, int *uLen,
+ double *dx, double *dy, double *ox, double *oy);
// Return the encoding.
- FontEncoding *getEncoding() { return encoding; }
+ char **getEncoding() { return enc; }
+
+ // Return the Unicode map.
+ CharCodeToUnicode *getToUnicode();
// Return the character name associated with <code>.
- char *getCharName(int code) { return encoding->getCharName(code); }
+ char *getCharName(int code) { return enc[code]; }
- // Return the code associated with <name>.
- int getCharCode(char *charName) { return encoding->getCharCode(charName); }
+ // Returns true if the PDF font specified an encoding.
+ GBool getHasEncoding() { return hasEncoding; }
+
+ // Get width of a character or string.
+ double getWidth(Guchar c) { return widths[c]; }
+
+ // Return the Type 3 CharProc dictionary, or NULL if none.
+ Dict *getCharProcs();
// Return the Type 3 CharProc for the character associated with <code>.
Object *getCharProc(int code, Object *proc);
- // Return the 16-bit character set and encoding.
- GfxFontCharSet16 getCharSet16() { return enc16.charSet; }
- GfxFontEncoding16 *getEncoding16() { return enc16.enc; }
+ // Return the Type 3 Resources dictionary, or NULL if none.
+ Dict *getResources();
- // Get the writing mode (0=horizontal, 1=vertical).
- int getWMode16() { return enc16.enc->wMode; }
+private:
- // Return the font matrix.
- double *getFontMatrix() { return fontMat; }
+ char *enc[256]; // char code --> char name
+ char encFree[256]; // boolean for each char name: if set,
+ // the string is malloc'ed
+ CharCodeToUnicode *ctu; // char code --> Unicode
+ GBool hasEncoding;
+ double widths[256]; // character widths
+ Object charProcs; // Type 3 CharProcs dictionary
+ Object resources; // Type 3 Resources dictionary
+};
- // Read an external or embedded font file into a buffer.
- char *readExtFontFile(int *len);
- char *readEmbFontFile(int *len);
+//------------------------------------------------------------------------
+// GfxCIDFont
+//------------------------------------------------------------------------
-private:
+class GfxCIDFont: public GfxFont {
+public:
- void getEncAndWidths(Dict *fontDict, BuiltinFont *builtinFont,
- int missingWidth);
- void findExtFontFile();
- void makeWidths(Dict *fontDict, FontEncoding *builtinEncoding,
- Gushort *builtinWidths, int missingWidth);
- void getType0EncAndWidths(Dict *fontDict);
+ GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
+ Dict *fontDict);
- GString *tag; // PDF font tag
- Ref id; // reference (used as unique ID)
- GString *name; // font name
- int flags; // font descriptor flags
- GfxFontType type; // type of font
- GBool is16; // set if font uses 16-bit chars
- GString *embFontName; // name of embedded font
- Ref embFontID; // ref to embedded font file stream
- GString *extFontFile; // external font file name
- Object charProcs; // Type3 CharProcs dictionary
- double fontMat[6]; // font matrix
- union {
- FontEncoding *encoding; // 8-bit font encoding
- struct {
- GfxFontCharSet16 charSet; // 16-bit character set
- GfxFontEncoding16 *enc; // 16-bit encoding (CMap)
- } enc16;
- };
- union {
- double widths[256]; // width of each char for 8-bit font
- GfxFontWidths16 widths16; // char widths for 16-bit font
- };
+ virtual ~GfxCIDFont();
+
+ virtual GBool isCIDFont() { return gTrue; }
+
+ virtual int getNextChar(char *s, int len, CharCode *code,
+ Unicode *u, int uSize, int *uLen,
+ double *dx, double *dy, double *ox, double *oy);
+
+ // Return the writing mode (0=horizontal, 1=vertical).
+ virtual int getWMode();
+
+ // Return the Unicode map.
+ CharCodeToUnicode *getToUnicode();
+
+ // Get the collection name (<registry>-<ordering>).
+ GString *getCollection();
+
+ // Return the CID-to-GID mapping table. These should only be called
+ // if type is fontCIDType2.
+ Gushort *getCIDToGID() { return cidToGID; }
+ int getCIDToGIDLen() { return cidToGIDLen; }
+
+private:
+
+ CMap *cMap; // char code --> CID
+ CharCodeToUnicode *ctu; // CID --> Unicode
+ GfxFontCIDWidths widths; // character widths
+ Gushort *cidToGID; // CID --> GID mapping (for embedded
+ // TrueType fonts)
+ int cidToGIDLen;
};
//------------------------------------------------------------------------
public:
// Build the font dictionary, given the PDF font dictionary.
- GfxFontDict(Dict *fontDict);
+ GfxFontDict(XRef *xref, Dict *fontDict);
// Destructor.
~GfxFontDict();
//
// GfxState.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stddef.h>
#include <math.h>
#include <string.h> // for memcpy()
#include "Error.h"
#include "Object.h"
#include "Array.h"
+#include "Page.h"
#include "GfxState.h"
//------------------------------------------------------------------------
whiteX = whiteY = whiteZ = 1;
blackX = blackY = blackZ = 0;
gammaR = gammaG = gammaB = 1;
- m[0] = 1; m[1] = 0; m[2] = 0;
- m[3] = 0; m[4] = 1; m[5] = 0;
- m[6] = 0; m[7] = 0; m[8] = 1;
+ mat[0] = 1; mat[1] = 0; mat[2] = 0;
+ mat[3] = 0; mat[4] = 1; mat[5] = 0;
+ mat[6] = 0; mat[7] = 0; mat[8] = 1;
}
GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
cs->gammaG = gammaG;
cs->gammaB = gammaB;
for (i = 0; i < 9; ++i) {
- cs->m[i] = m[i];
+ cs->mat[i] = mat[i];
}
return cs;
}
obj2.arrayGetLength() == 9) {
for (i = 0; i < 9; ++i) {
obj2.arrayGet(i, &obj3);
- cs->m[i] = obj3.getNum();
+ cs->mat[i] = obj3.getNum();
obj3.free();
}
}
}
void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
- rgb->r = clip01(1 - (color->c[0] + color->c[3]));
- rgb->g = clip01(1 - (color->c[1] + color->c[3]));
- rgb->b = clip01(1 - (color->c[2] + color->c[3]));
+ double c, m, y, aw, ac, am, ay, ar, ag, ab;
+
+ c = clip01(color->c[0] + color->c[3]);
+ m = clip01(color->c[1] + color->c[3]);
+ y = clip01(color->c[2] + color->c[3]);
+ aw = (1-c) * (1-m) * (1-y);
+ ac = c * (1-m) * (1-y);
+ am = (1-c) * m * (1-y);
+ ay = (1-c) * (1-m) * y;
+ ar = (1-c) * m * y;
+ ag = c * (1-m) * y;
+ ab = c * m * (1-y);
+ rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
+ rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
+ rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag +
+ 0.4863*ab);
}
void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
// GfxICCBasedColorSpace
//------------------------------------------------------------------------
-GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nComps, GfxColorSpace *alt,
- Ref *iccProfileStream) {
- this->nComps = nComps;
- this->alt = alt;
- this->iccProfileStream = *iccProfileStream;
+GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+ Ref *iccProfileStreamA) {
+ nComps = nCompsA;
+ alt = altA;
+ iccProfileStream = *iccProfileStreamA;
rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
}
GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
GfxICCBasedColorSpace *cs;
- Ref iccProfileStream;
- int nComps;
- GfxColorSpace *alt;
+ Ref iccProfileStreamA;
+ int nCompsA;
+ GfxColorSpace *altA;
Dict *dict;
Object obj1, obj2, obj3;
int i;
arr->getNF(1, &obj1);
if (obj1.isRef()) {
- iccProfileStream = obj1.getRef();
+ iccProfileStreamA = obj1.getRef();
} else {
- iccProfileStream.num = 0;
- iccProfileStream.gen = 0;
+ iccProfileStreamA.num = 0;
+ iccProfileStreamA.gen = 0;
}
obj1.free();
arr->get(1, &obj1);
obj1.free();
return NULL;
}
- nComps = obj2.getInt();
+ nCompsA = obj2.getInt();
obj2.free();
if (dict->lookup("Alternate", &obj2)->isNull() ||
- !(alt = GfxColorSpace::parse(&obj2))) {
- switch (nComps) {
+ !(altA = GfxColorSpace::parse(&obj2))) {
+ switch (nCompsA) {
case 1:
- alt = new GfxDeviceGrayColorSpace();
+ altA = new GfxDeviceGrayColorSpace();
break;
case 3:
- alt = new GfxDeviceRGBColorSpace();
+ altA = new GfxDeviceRGBColorSpace();
break;
case 4:
- alt = new GfxDeviceCMYKColorSpace();
+ altA = new GfxDeviceCMYKColorSpace();
break;
default:
error(-1, "Bad ICCBased color space - invalid N");
}
}
obj2.free();
- cs = new GfxICCBasedColorSpace(nComps, alt, &iccProfileStream);
+ cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
if (dict->lookup("Range", &obj2)->isArray() &&
- obj2.arrayGetLength() == 2 * nComps) {
- for (i = 0; i < nComps; ++i) {
+ obj2.arrayGetLength() == 2 * nCompsA) {
+ for (i = 0; i < nCompsA; ++i) {
obj2.arrayGet(2*i, &obj3);
cs->rangeMin[i] = obj3.getNum();
obj3.free();
// GfxIndexedColorSpace
//------------------------------------------------------------------------
-GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *base,
- int indexHigh) {
- this->base = base;
- this->indexHigh = indexHigh;
- this->lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
- sizeof(Guchar));
+GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
+ int indexHighA) {
+ base = baseA;
+ indexHigh = indexHighA;
+ lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
+ sizeof(Guchar));
}
GfxIndexedColorSpace::~GfxIndexedColorSpace() {
GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
GfxIndexedColorSpace *cs;
- GfxColorSpace *base;
- int indexHigh;
+ GfxColorSpace *baseA;
+ int indexHighA;
Object obj1;
int x;
char *s;
goto err1;
}
arr->get(1, &obj1);
- if (!(base = GfxColorSpace::parse(&obj1))) {
+ if (!(baseA = GfxColorSpace::parse(&obj1))) {
error(-1, "Bad Indexed color space (base color space)");
goto err2;
}
error(-1, "Bad Indexed color space (hival)");
goto err2;
}
- indexHigh = obj1.getInt();
+ indexHighA = obj1.getInt();
obj1.free();
- cs = new GfxIndexedColorSpace(base, indexHigh);
+ cs = new GfxIndexedColorSpace(baseA, indexHighA);
arr->get(3, &obj1);
- n = base->getNComps();
+ n = baseA->getNComps();
if (obj1.isStream()) {
obj1.streamReset();
- for (i = 0; i <= indexHigh; ++i) {
+ for (i = 0; i <= indexHighA; ++i) {
for (j = 0; j < n; ++j) {
if ((x = obj1.streamGetChar()) == EOF) {
error(-1, "Bad Indexed color space (lookup table stream too short)");
}
obj1.streamClose();
} else if (obj1.isString()) {
- if (obj1.getString()->getLength() < (indexHigh + 1) * n) {
+ if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
error(-1, "Bad Indexed color space (lookup table string too short)");
goto err3;
}
s = obj1.getString()->getCString();
- for (i = 0; i <= indexHigh; ++i) {
+ for (i = 0; i <= indexHighA; ++i) {
for (j = 0; j < n; ++j) {
cs->lookup[i*n + j] = (Guchar)*s++;
}
// GfxSeparationColorSpace
//------------------------------------------------------------------------
-GfxSeparationColorSpace::GfxSeparationColorSpace(GString *name,
- GfxColorSpace *alt,
- Function *func) {
- this->name = name;
- this->alt = alt;
- this->func = func;
+GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
+ GfxColorSpace *altA,
+ Function *funcA) {
+ name = nameA;
+ alt = altA;
+ func = funcA;
}
GfxSeparationColorSpace::~GfxSeparationColorSpace() {
//~ handle the 'All' and 'None' colorants
GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
GfxSeparationColorSpace *cs;
- GString *name;
- GfxColorSpace *alt;
- Function *func;
+ GString *nameA;
+ GfxColorSpace *altA;
+ Function *funcA;
Object obj1;
if (arr->getLength() != 4) {
error(-1, "Bad Separation color space (name)");
goto err2;
}
- name = new GString(obj1.getName());
+ nameA = new GString(obj1.getName());
obj1.free();
arr->get(2, &obj1);
- if (!(alt = GfxColorSpace::parse(&obj1))) {
+ if (!(altA = GfxColorSpace::parse(&obj1))) {
error(-1, "Bad Separation color space (alternate color space)");
goto err3;
}
obj1.free();
- func = Function::parse(arr->get(3, &obj1));
- obj1.free();
- if (!func || !func->isOk()) {
+ arr->get(3, &obj1);
+ if (!(funcA = Function::parse(&obj1))) {
goto err4;
}
- cs = new GfxSeparationColorSpace(name, alt, func);
+ obj1.free();
+ cs = new GfxSeparationColorSpace(nameA, altA, funcA);
return cs;
err4:
- if(func)
- delete func;
- delete alt;
+ delete altA;
err3:
- delete name;
+ delete nameA;
err2:
obj1.free();
err1:
// GfxDeviceNColorSpace
//------------------------------------------------------------------------
-GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nComps,
- GfxColorSpace *alt,
- Function *func) {
- this->nComps = nComps;
- this->alt = alt;
- this->func = func;
+GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
+ GfxColorSpace *altA,
+ Function *funcA) {
+ nComps = nCompsA;
+ alt = altA;
+ func = funcA;
}
GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
//~ handle the 'None' colorant
GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
GfxDeviceNColorSpace *cs;
- int nComps;
- GString *names[gfxColorMaxComps];
- GfxColorSpace *alt;
- Function *func;
+ int nCompsA;
+ GString *namesA[gfxColorMaxComps];
+ GfxColorSpace *altA;
+ Function *funcA;
Object obj1, obj2;
int i;
error(-1, "Bad DeviceN color space (names)");
goto err2;
}
- nComps = obj1.arrayGetLength();
- for (i = 0; i < nComps; ++i) {
+ nCompsA = obj1.arrayGetLength();
+ for (i = 0; i < nCompsA; ++i) {
if (!obj1.arrayGet(i, &obj2)->isName()) {
error(-1, "Bad DeviceN color space (names)");
obj2.free();
goto err2;
}
- names[i] = new GString(obj2.getName());
+ namesA[i] = new GString(obj2.getName());
obj2.free();
}
obj1.free();
arr->get(2, &obj1);
- if (!(alt = GfxColorSpace::parse(&obj1))) {
+ if (!(altA = GfxColorSpace::parse(&obj1))) {
error(-1, "Bad DeviceN color space (alternate color space)");
goto err3;
}
obj1.free();
- func = Function::parse(arr->get(3, &obj1));
- obj1.free();
- if (!func->isOk()) {
+ arr->get(3, &obj1);
+ if (!(funcA = Function::parse(&obj1))) {
goto err4;
}
- cs = new GfxDeviceNColorSpace(nComps, alt, func);
- for (i = 0; i < nComps; ++i) {
- cs->names[i] = names[i];
+ obj1.free();
+ cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
+ for (i = 0; i < nCompsA; ++i) {
+ cs->names[i] = namesA[i];
}
return cs;
err4:
- delete func;
- delete alt;
+ delete altA;
err3:
- for (i = 0; i < nComps; ++i) {
- delete names[i];
+ for (i = 0; i < nCompsA; ++i) {
+ delete namesA[i];
}
err2:
obj1.free();
// GfxPatternColorSpace
//------------------------------------------------------------------------
-GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *under) {
- this->under = under;
+GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
+ under = underA;
}
GfxPatternColorSpace::~GfxPatternColorSpace() {
GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
GfxPatternColorSpace *cs;
- GfxColorSpace *under;
+ GfxColorSpace *underA;
Object obj1;
if (arr->getLength() != 1 && arr->getLength() != 2) {
error(-1, "Bad Pattern color space");
return NULL;
}
- under = NULL;
+ underA = NULL;
if (arr->getLength() == 2) {
arr->get(1, &obj1);
- if (!(under = GfxColorSpace::parse(&obj1))) {
+ if (!(underA = GfxColorSpace::parse(&obj1))) {
error(-1, "Bad Pattern color space (underlying color space)");
obj1.free();
return NULL;
}
obj1.free();
}
- cs = new GfxPatternColorSpace(under);
+ cs = new GfxPatternColorSpace(underA);
return cs;
}
// Pattern
//------------------------------------------------------------------------
-GfxPattern::GfxPattern(int type) {
- this->type = type;
+GfxPattern::GfxPattern(int typeA) {
+ type = typeA;
}
GfxPattern::~GfxPattern() {
}
//------------------------------------------------------------------------
-// Function
+// GfxShading
//------------------------------------------------------------------------
-Function::Function() {
-}
-
-Function::~Function() {
+GfxShading::GfxShading() {
}
-Function *Function::parse(Object *funcObj) {
- Function *func;
- Dict *dict;
- int funcType;
- Object obj1;
-
- if (funcObj->isStream()) {
- dict = funcObj->streamGetDict();
- } else if (funcObj->isDict()) {
- dict = funcObj->getDict();
- } else {
- error(-1, "Expected function dictionary or stream");
- return NULL;
- }
-
- if (!dict->lookup("FunctionType", &obj1)->isInt()) {
- error(-1, "Function type is missing or wrong type");
- obj1.free();
- return NULL;
- }
- funcType = obj1.getInt();
- obj1.free();
-
- if (funcType == 0) {
- func = new SampledFunction(funcObj, dict);
- } else if (funcType == 2) {
- func = new ExponentialFunction(funcObj, dict);
- } else {
- error(-1, "Unimplemented function type");
- return NULL;
- }
- if (!func->isOk()) {
- delete func;
- return NULL;
- }
-
- return func;
+GfxShading::~GfxShading() {
+ delete colorSpace;
}
-GBool Function::init(Dict *dict) {
+GfxShading *GfxShading::parse(Object *obj) {
+ GfxShading *shading;
+ int typeA;
+ GfxColorSpace *colorSpaceA;
+ GfxColor backgroundA;
+ GBool hasBackgroundA;
+ double xMinA, yMinA, xMaxA, yMaxA;
+ GBool hasBBoxA;
Object obj1, obj2;
int i;
- //----- Domain
- if (!dict->lookup("Domain", &obj1)->isArray()) {
- error(-1, "Function is missing domain");
- goto err2;
- }
- m = obj1.arrayGetLength() / 2;
- if (m > funcMaxInputs) {
- error(-1, "Functions with more than %d inputs are unsupported",
- funcMaxInputs);
- goto err2;
- }
- for (i = 0; i < m; ++i) {
- obj1.arrayGet(2*i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function domain array");
+ shading = NULL;
+ if (obj->isDict()) {
+
+ if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
+ error(-1, "Invalid ShadingType in shading dictionary");
+ obj1.free();
goto err1;
}
- domain[i][0] = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2*i+1, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function domain array");
+ typeA = obj1.getInt();
+ obj1.free();
+
+ obj->dictLookup("ColorSpace", &obj1);
+ if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad color space in shading dictionary");
+ obj1.free();
goto err1;
}
- domain[i][1] = obj2.getNum();
- obj2.free();
- }
- obj1.free();
+ obj1.free();
- //----- Range
- hasRange = gFalse;
- n = 0;
- if (dict->lookup("Range", &obj1)->isArray()) {
- hasRange = gTrue;
- n = obj1.arrayGetLength() / 2;
- if (n > funcMaxOutputs) {
- error(-1, "Functions with more than %d outputs are unsupported",
- funcMaxOutputs);
- goto err2;
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ backgroundA.c[i] = 0;
}
- for (i = 0; i < n; ++i) {
- obj1.arrayGet(2*i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function range array");
- goto err1;
+ hasBackgroundA = gFalse;
+ if (obj->dictLookup("Background", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
+ hasBackgroundA = gTrue;
+ for (i = 0; i < colorSpaceA->getNComps(); ++i) {
+ backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
+ obj2.free();
+ }
+ } else {
+ error(-1, "Bad Background in shading dictionary");
}
- range[i][0] = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2*i+1, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function range array");
- goto err1;
+ }
+ obj1.free();
+
+ xMinA = yMinA = xMaxA = yMaxA = 0;
+ hasBBoxA = gFalse;
+ if (obj->dictLookup("BBox", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == 4) {
+ hasBBoxA = gTrue;
+ xMinA = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ yMinA = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ xMaxA = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ yMaxA = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Bad BBox in shading dictionary");
}
- range[i][1] = obj2.getNum();
- obj2.free();
}
obj1.free();
+
+ switch (typeA) {
+ case 2:
+ shading = GfxAxialShading::parse(obj->getDict());
+ break;
+ case 3:
+ shading = GfxRadialShading::parse(obj->getDict());
+ break;
+ default:
+ error(-1, "Unimplemented shading type %d", typeA);
+ goto err1;
+ }
+
+ if (shading) {
+ shading->type = typeA;
+ shading->colorSpace = colorSpaceA;
+ shading->background = backgroundA;
+ shading->hasBackground = hasBackgroundA;
+ shading->xMin = xMinA;
+ shading->yMin = yMinA;
+ shading->xMax = xMaxA;
+ shading->yMax = yMaxA;
+ shading->hasBBox = hasBBoxA;
+ } else {
+ delete colorSpaceA;
+ }
}
- return gTrue;
+ return shading;
err1:
- obj2.free();
- err2:
- obj1.free();
- return gFalse;
+ return NULL;
}
//------------------------------------------------------------------------
-// SampledFunction
+// GfxAxialShading
//------------------------------------------------------------------------
-SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
- Stream *str;
- int nSamples, sampleBits;
- double sampleMul;
- Object obj1, obj2;
- Guint buf, bitMask;
- int bits;
- int s;
+GfxAxialShading::GfxAxialShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A) {
int i;
- samples = NULL;
- ok = gFalse;
-
- //----- initialize the generic stuff
- if (!init(dict)) {
- goto err1;
- }
- if (!hasRange) {
- error(-1, "Type 0 function is missing range");
- goto err1;
+ x0 = x0A;
+ y0 = y0A;
+ x1 = x1A;
+ y1 = y1A;
+ t0 = t0A;
+ t1 = t1A;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
}
+ extend0 = extend0A;
+ extend1 = extend1A;
+}
- //----- get the stream
- if (!funcObj->isStream()) {
- error(-1, "Type 0 function isn't a stream");
- goto err1;
- }
- str = funcObj->getStream();
+GfxAxialShading::~GfxAxialShading() {
+ int i;
- //----- Size
- if (!dict->lookup("Size", &obj1)->isArray() ||
- obj1.arrayGetLength() != m) {
- error(-1, "Function has missing or invalid size array");
- goto err2;
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
}
- for (i = 0; i < m; ++i) {
- obj1.arrayGet(i, &obj2);
- if (!obj2.isInt()) {
- error(-1, "Illegal value in function size array");
- goto err3;
- }
- sampleSize[i] = obj2.getInt();
+}
+
+GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
+ double x0A, y0A, x1A, y1A;
+ double t0A, t1A;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ GBool extend0A, extend1A;
+ Object obj1, obj2;
+ int i;
+
+ x0A = y0A = x1A = y1A = 0;
+ if (dict->lookup("Coords", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(2, &obj2)->getNum();
obj2.free();
+ y1A = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Missing or invalid Coords in shading dictionary");
+ goto err1;
}
obj1.free();
- //----- BitsPerSample
- if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
- error(-1, "Function has missing or invalid BitsPerSample");
- goto err2;
+ t0A = 0;
+ t1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ t0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ t1A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
}
- sampleBits = obj1.getInt();
- sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
obj1.free();
- //----- Encode
- if (dict->lookup("Encode", &obj1)->isArray() &&
- obj1.arrayGetLength() == 2*m) {
- for (i = 0; i < m; ++i) {
- obj1.arrayGet(2*i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function encode array");
- goto err3;
- }
- encode[i][0] = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2*i+1, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function encode array");
- goto err3;
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
}
- encode[i][1] = obj2.getNum();
obj2.free();
}
} else {
- for (i = 0; i < m; ++i) {
- encode[i][0] = 0;
- encode[i][1] = sampleSize[i] - 1;
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
}
}
obj1.free();
- //----- Decode
- if (dict->lookup("Decode", &obj1)->isArray() &&
- obj1.arrayGetLength() == 2*n) {
- for (i = 0; i < n; ++i) {
- obj1.arrayGet(2*i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function decode array");
- goto err3;
- }
- decode[i][0] = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2*i+1, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function decode array");
- goto err3;
- }
- decode[i][1] = obj2.getNum();
- obj2.free();
- }
- } else {
- for (i = 0; i < n; ++i) {
- decode[i][0] = range[i][0];
- decode[i][1] = range[i][1];
- }
+ extend0A = extend1A = gFalse;
+ if (dict->lookup("Extend", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ extend0A = obj1.arrayGet(0, &obj2)->getBool();
+ obj2.free();
+ extend1A = obj1.arrayGet(1, &obj2)->getBool();
+ obj2.free();
}
obj1.free();
- //----- samples
- nSamples = n;
- for (i = 0; i < m; ++i)
- nSamples *= sampleSize[i];
- samples = (double *)gmalloc(nSamples * sizeof(double));
- buf = 0;
- bits = 0;
- bitMask = (1 << sampleBits) - 1;
- str->reset();
- for (i = 0; i < nSamples; ++i) {
- if (sampleBits == 8) {
- s = str->getChar();
- } else if (sampleBits == 16) {
- s = str->getChar();
- s = (s << 8) + str->getChar();
- } else if (sampleBits == 32) {
- s = str->getChar();
- s = (s << 8) + str->getChar();
- s = (s << 8) + str->getChar();
- s = (s << 8) + str->getChar();
- } else {
- while (bits < sampleBits) {
- buf = (buf << 8) | (str->getChar() & 0xff);
- bits += 8;
- }
- s = (buf >> (bits - sampleBits)) & bitMask;
- bits -= sampleBits;
- }
- samples[i] = (double)s * sampleMul;
- }
- str->close();
-
- ok = gTrue;
- return;
+ return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
+ funcsA, nFuncsA, extend0A, extend1A);
- err3:
- obj2.free();
- err2:
- obj1.free();
err1:
- return;
+ return NULL;
}
-SampledFunction::~SampledFunction() {
- if (samples) {
- gfree(samples);
+void GfxAxialShading::getColor(double t, GfxColor *color) {
+ int i;
+
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(&t, &color->c[i]);
}
}
-SampledFunction::SampledFunction(SampledFunction *func) {
- int nSamples, i;
+//------------------------------------------------------------------------
+// GfxRadialShading
+//------------------------------------------------------------------------
- memcpy(this, func, sizeof(SampledFunction));
+GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
+ double x1A, double y1A, double r1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A) {
+ int i;
- nSamples = n;
- for (i = 0; i < m; ++i) {
- nSamples *= sampleSize[i];
+ x0 = x0A;
+ y0 = y0A;
+ r0 = r0A;
+ x1 = x1A;
+ y1 = y1A;
+ r1 = r1A;
+ t0 = t0A;
+ t1 = t1A;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
}
- samples = (double *)gmalloc(nSamples * sizeof(double));
- memcpy(samples, func->samples, nSamples * sizeof(double));
+ extend0 = extend0A;
+ extend1 = extend1A;
}
-void SampledFunction::transform(double *in, double *out) {
- double e[4];
- double s;
- double x0, x1;
- int e0, e1;
- double efrac;
+GfxRadialShading::~GfxRadialShading() {
int i;
- // map input values into sample array
- for (i = 0; i < m; ++i) {
- e[i] = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
- (encode[i][1] - encode[i][0]) + encode[i][0];
- if (e[i] < 0) {
- e[i] = 0;
- } else if (e[i] > sampleSize[i] - 1) {
- e[i] = sampleSize[i] - 1;
- }
- }
-
- for (i = 0; i < n; ++i) {
-
- // m-linear interpolation
- // (only m=1 is currently supported)
- e0 = (int)floor(e[0]);
- e1 = (int)ceil(e[0]);
- efrac = e[0] - e0;
- x0 = samples[e0 * n + i];
- x1 = samples[e1 * n + i];
- s = (1 - efrac) * x0 + efrac * x1;
-
- // map output values to range
- out[i] = s * (decode[i][1] - decode[i][0]) + decode[i][0];
- if (out[i] < range[i][0]) {
- out[i] = range[i][0];
- } else if (out[i] > range[i][1]) {
- out[i] = range[i][1];
- }
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
}
}
-//------------------------------------------------------------------------
-// ExponentialFunction
-//------------------------------------------------------------------------
-
-ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
+GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
+ double x0A, y0A, r0A, x1A, y1A, r1A;
+ double t0A, t1A;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ GBool extend0A, extend1A;
Object obj1, obj2;
- GBool hasN;
int i;
- ok = gFalse;
- hasN = gFalse;
-
- //----- initialize the generic stuff
- if (!init(dict)) {
- goto err1;
- }
- if (m != 1) {
- error(-1, "Exponential function with more than one input");
+ x0A = y0A = r0A = x1A = y1A = r1A = 0;
+ if (dict->lookup("Coords", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ r0A = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ y1A = obj1.arrayGet(4, &obj2)->getNum();
+ obj2.free();
+ r1A = obj1.arrayGet(5, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Missing or invalid Coords in shading dictionary");
goto err1;
}
+ obj1.free();
- //----- default values
- for (i = 0; i < funcMaxOutputs; ++i) {
- c0[i] = 0;
- c1[i] = 1;
+ t0A = 0;
+ t1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ t0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ t1A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
}
+ obj1.free();
- //----- C0
- if (dict->lookup("C0", &obj1)->isArray()) {
- if (!hasN) {
- n = obj1.arrayGetLength();
- } else if (obj1.arrayGetLength() != n) {
- error(-1, "Function's C0 array is wrong length");
- goto err2;
- }
- for (i = 0; i < n; ++i) {
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ for (i = 0; i < nFuncsA; ++i) {
obj1.arrayGet(i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function C0 array");
- goto err3;
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
}
- c0[i] = obj2.getNum();
obj2.free();
}
- obj1.free();
- }
-
- //----- C1
- if (dict->lookup("C1", &obj1)->isArray()) {
- if (!hasN) {
- n = obj1.arrayGetLength();
- } else if (obj1.arrayGetLength() != n) {
- error(-1, "Function's C1 array is wrong length");
- goto err2;
- }
- for (i = 0; i < n; ++i) {
- obj1.arrayGet(i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function C1 array");
- goto err3;
- }
- c1[i] = obj2.getNum();
- obj2.free();
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
}
- obj1.free();
}
+ obj1.free();
- //----- N (exponent)
- if (!dict->lookup("N", &obj1)->isNum()) {
- error(-1, "Function has missing or invalid N");
- goto err2;
+ extend0A = extend1A = gFalse;
+ if (dict->lookup("Extend", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ extend0A = obj1.arrayGet(0, &obj2)->getBool();
+ obj2.free();
+ extend1A = obj1.arrayGet(1, &obj2)->getBool();
+ obj2.free();
}
- e = obj1.getNum();
obj1.free();
- ok = gTrue;
- return;
+ return new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
+ funcsA, nFuncsA, extend0A, extend1A);
- err3:
- obj2.free();
- err2:
- obj1.free();
err1:
- return;
-}
-
-ExponentialFunction::~ExponentialFunction() {
-}
-
-ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
- memcpy(this, func, sizeof(ExponentialFunction));
+ return NULL;
}
-void ExponentialFunction::transform(double *in, double *out) {
- double x;
+void GfxRadialShading::getColor(double t, GfxColor *color) {
int i;
- if (in[0] < domain[0][0]) {
- x = domain[0][0];
- } else if (in[0] > domain[0][1]) {
- x = domain[0][1];
- } else {
- x = in[0];
- }
- for (i = 0; i < n; ++i) {
- out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
- if (hasRange) {
- if (out[i] < range[i][0]) {
- out[i] = range[i][0];
- } else if (out[i] > range[i][1]) {
- out[i] = range[i][1];
- }
- }
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(&t, &color->c[i]);
}
- return;
}
//------------------------------------------------------------------------
// GfxImageColorMap
//------------------------------------------------------------------------
-GfxImageColorMap::GfxImageColorMap(int bits, Object *decode,
- GfxColorSpace *colorSpace) {
+GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
+ GfxColorSpace *colorSpaceA) {
GfxIndexedColorSpace *indexedCS;
GfxSeparationColorSpace *sepCS;
int maxPixel, indexHigh;
Guchar *lookup2;
Function *sepFunc;
Object obj;
- double x;
+ double x[gfxColorMaxComps];
double y[gfxColorMaxComps];
int i, j, k;
ok = gTrue;
// bits per component and color space
- this->bits = bits;
+ bits = bitsA;
maxPixel = (1 << bits) - 1;
- this->colorSpace = colorSpace;
+ colorSpace = colorSpaceA;
// get decode map
if (decode->isNull()) {
goto err1;
}
-#if 0 //~
- // handle the case where fewer than 2^n palette entries of an n-bit
- // indexed color space are populated (this happens, e.g., in files
- // optimized by Distiller)
- if (colorSpace->getMode() == csIndexed) {
- i = ((GfxIndexedColorSpace *)colorSpace)->getIndexHigh();
- if (i < maxPixel) {
- maxPixel = i;
- }
- }
-#endif
-
// Construct a lookup table -- this stores pre-computed decoded
// values for each component, i.e., the result of applying the
// decode mapping to each possible image pixel component value.
lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
sepFunc = sepCS->getFunc();
for (i = 0; i <= maxPixel; ++i) {
- x = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
- sepFunc->transform(&x, y);
+ x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
+ sepFunc->transform(x, y);
for (k = 0; k < nComps2; ++k) {
lookup[i*nComps2 + k] = y[k];
}
subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
}
+void GfxPath::close() {
+ // this is necessary to handle the pathological case of
+ // moveto/closepath/clip, which defines an empty clipping region
+ if (justMoved) {
+ if (n >= size) {
+ size += 16;
+ subpaths = (GfxSubpath **)
+ grealloc(subpaths, size * sizeof(GfxSubpath *));
+ }
+ subpaths[n] = new GfxSubpath(firstX, firstY);
+ ++n;
+ justMoved = gFalse;
+ }
+ subpaths[n-1]->close();
+}
//------------------------------------------------------------------------
// GfxState
//------------------------------------------------------------------------
-GfxState::GfxState(double dpi, double px1a, double py1a,
- double px2a, double py2a, int rotate, GBool upsideDown) {
+GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
+ GBool upsideDown) {
double k;
- px1 = px1a;
- py1 = py1a;
- px2 = px2a;
- py2 = py2a;
+ px1 = pageBox->x1;
+ py1 = pageBox->y1;
+ px2 = pageBox->x2;
+ py2 = pageBox->y2;
k = dpi / 72.0;
if (rotate == 90) {
ctm[0] = 0;
curX = curY = 0;
lineX = lineY = 0;
+ clipXMin = 0;
+ clipYMin = 0;
+ clipXMax = pageWidth;
+ clipYMax = pageHeight;
+
saved = NULL;
}
delete strokePattern;
}
gfree(lineDash);
- delete path;
+ if (path) {
+ // this gets set to NULL by restore()
+ delete path;
+ }
if (saved) {
delete saved;
}
lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
}
- path = state->path->copy();
saved = NULL;
}
+void GfxState::getUserClipBBox(double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ double ictm[6];
+ double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
+
+ // invert the CTM
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+
+ // transform all four corners of the clip bbox; find the min and max
+ // x and y values
+ xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
+ yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
+ tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
+ ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
+ if (tx < xMin1) {
+ xMin1 = tx;
+ } else if (tx > xMax1) {
+ xMax1 = tx;
+ }
+ if (ty < yMin1) {
+ yMin1 = ty;
+ } else if (ty > yMax1) {
+ yMax1 = ty;
+ }
+ tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
+ ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
+ if (tx < xMin1) {
+ xMin1 = tx;
+ } else if (tx > xMax1) {
+ xMax1 = tx;
+ }
+ if (ty < yMin1) {
+ yMin1 = ty;
+ } else if (ty > yMax1) {
+ yMax1 = ty;
+ }
+ tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
+ ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
+ if (tx < xMin1) {
+ xMin1 = tx;
+ } else if (tx > xMax1) {
+ xMax1 = tx;
+ }
+ if (ty < yMin1) {
+ yMin1 = ty;
+ } else if (ty > yMax1) {
+ yMax1 = ty;
+ }
+
+ *xMin = xMin1;
+ *yMin = yMin1;
+ *xMax = xMax1;
+ *yMax = yMax1;
+}
+
double GfxState::transformWidth(double w) {
double x, y;
void GfxState::setCTM(double a, double b, double c,
double d, double e, double f) {
+ int i;
+
ctm[0] = a;
ctm[1] = b;
ctm[2] = c;
ctm[3] = d;
ctm[4] = e;
ctm[5] = f;
+
+ // avoid FP exceptions on badly messed up PDF files
+ for (i = 0; i < 6; ++i) {
+ if (ctm[i] > 1e10) {
+ ctm[i] = 1e10;
+ } else if (ctm[i] < -1e10) {
+ ctm[i] = -1e10;
+ }
+ }
}
void GfxState::concatCTM(double a, double b, double c,
double b1 = ctm[1];
double c1 = ctm[2];
double d1 = ctm[3];
+ int i;
ctm[0] = a * a1 + b * c1;
ctm[1] = a * b1 + b * d1;
ctm[3] = c * b1 + d * d1;
ctm[4] = e * a1 + f * c1 + ctm[4];
ctm[5] = e * b1 + f * d1 + ctm[5];
+
+ // avoid FP exceptions on badly messed up PDF files
+ for (i = 0; i < 6; ++i) {
+ if (ctm[i] > 1e10) {
+ ctm[i] = 1e10;
+ } else if (ctm[i] < -1e10) {
+ ctm[i] = -1e10;
+ }
+ }
}
void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
path = new GfxPath();
}
-void GfxState::textShift(double tx) {
- double dx, dy;
-
- textTransformDelta(tx, 0, &dx, &dy);
- curX += dx;
- curY += dy;
+void GfxState::clip() {
+ double xMin, yMin, xMax, yMax, x, y;
+ GfxSubpath *subpath;
+ int i, j;
+
+ xMin = xMax = yMin = yMax = 0; // make gcc happy
+ for (i = 0; i < path->getNumSubpaths(); ++i) {
+ subpath = path->getSubpath(i);
+ for (j = 0; j < subpath->getNumPoints(); ++j) {
+ transform(subpath->getX(j), subpath->getY(j), &x, &y);
+ if (i == 0 && j == 0) {
+ xMin = xMax = x;
+ yMin = yMax = y;
+ } else {
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ }
+ }
+ }
+ if (xMin > clipXMin) {
+ clipXMin = xMin;
+ }
+ if (yMin > clipYMin) {
+ clipYMin = yMin;
+ }
+ if (xMax < clipXMax) {
+ clipXMax = xMax;
+ }
+ if (yMax < clipYMax) {
+ clipYMax = yMax;
+ }
}
void GfxState::textShift(double tx, double ty) {
curY += dy;
}
+void GfxState::shift(double dx, double dy) {
+ curX += dx;
+ curY += dy;
+}
+
GfxState *GfxState::save() {
GfxState *newState;
if (saved) {
oldState = saved;
+
+ // these attributes aren't saved/restored by the q/Q operators
+ oldState->path = path;
+ oldState->curX = curX;
+ oldState->curY = curY;
+ oldState->lineX = lineX;
+ oldState->lineY = lineY;
+
+ path = NULL;
saved = NULL;
delete this;
+
} else {
oldState = this;
}
+
return oldState;
}
//
// GfxState.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#include "gtypes.h"
#include "Object.h"
+#include "Function.h"
class Array;
-class Function;
class GfxFont;
+struct PDFRectangle;
//------------------------------------------------------------------------
// GfxColor
//------------------------------------------------------------------------
-#define gfxColorMaxComps 8
+#define gfxColorMaxComps funcMaxOutputs
struct GfxColor {
double c[gfxColorMaxComps];
double getGammaR() { return gammaR; }
double getGammaG() { return gammaG; }
double getGammaB() { return gammaB; }
- double *getMatrix() { return m; }
+ double *getMatrix() { return mat; }
private:
double whiteX, whiteY, whiteZ; // white point
double blackX, blackY, blackZ; // black point
double gammaR, gammaG, gammaB; // gamma values
- double m[9]; // ABC -> XYZ transform matrix
+ double mat[9]; // ABC -> XYZ transform matrix
};
//------------------------------------------------------------------------
class GfxICCBasedColorSpace: public GfxColorSpace {
public:
- GfxICCBasedColorSpace(int nComps, GfxColorSpace *alt,
- Ref *iccProfileStream);
+ GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+ Ref *iccProfileStreamA);
virtual ~GfxICCBasedColorSpace();
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csICCBased; }
class GfxIndexedColorSpace: public GfxColorSpace {
public:
- GfxIndexedColorSpace(GfxColorSpace *base, int indexHigh);
+ GfxIndexedColorSpace(GfxColorSpace *baseA, int indexHighA);
virtual ~GfxIndexedColorSpace();
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csIndexed; }
class GfxSeparationColorSpace: public GfxColorSpace {
public:
- GfxSeparationColorSpace(GString *name, GfxColorSpace *alt,
- Function *func);
+ GfxSeparationColorSpace(GString *nameA, GfxColorSpace *altA,
+ Function *funcA);
virtual ~GfxSeparationColorSpace();
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csSeparation; }
class GfxPatternColorSpace: public GfxColorSpace {
public:
- GfxPatternColorSpace(GfxColorSpace *under);
+ GfxPatternColorSpace(GfxColorSpace *underA);
virtual ~GfxPatternColorSpace();
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csPattern; }
class GfxPattern {
public:
- GfxPattern(int type);
+ GfxPattern(int typeA);
virtual ~GfxPattern();
static GfxPattern *parse(Object *obj);
};
//------------------------------------------------------------------------
-// Function
+// GfxShading
//------------------------------------------------------------------------
-#define funcMaxInputs 1
-#define funcMaxOutputs 8
-
-class Function {
+class GfxShading {
public:
- Function();
-
- virtual ~Function();
-
- // Construct a function. Returns NULL if unsuccessful.
- static Function *parse(Object *funcObj);
-
- // Initialize the entries common to all function types.
- GBool init(Dict *dict);
-
- virtual Function *copy() = 0;
-
- // Return size of input and output tuples.
- int getInputSize() { return m; }
- int getOutputSize() { return n; }
+ GfxShading();
+ virtual ~GfxShading();
- // Transform an input tuple into an output tuple.
- virtual void transform(double *in, double *out) = 0;
+ static GfxShading *parse(Object *obj);
- virtual GBool isOk() = 0;
+ int getType() { return type; }
+ GfxColorSpace *getColorSpace() { return colorSpace; }
+ GfxColor *getBackground() { return &background; }
+ GBool getHasBackground() { return hasBackground; }
+ void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
+ { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+ GBool getHasBBox() { return hasBBox; }
-protected:
+private:
- int m, n; // size of input and output tuples
- double // min and max values for function domain
- domain[funcMaxInputs][2];
- double // min and max values for function range
- range[funcMaxOutputs][2];
- GBool hasRange; // set if range is defined
+ int type;
+ GfxColorSpace *colorSpace;
+ GfxColor background;
+ GBool hasBackground;
+ double xMin, yMin, xMax, yMax;
+ GBool hasBBox;
};
//------------------------------------------------------------------------
-// SampledFunction
+// GfxAxialShading
//------------------------------------------------------------------------
-class SampledFunction: public Function {
+class GfxAxialShading: public GfxShading {
public:
- SampledFunction(Object *funcObj, Dict *dict);
- virtual ~SampledFunction();
- virtual Function *copy() { return new SampledFunction(this); }
- virtual void transform(double *in, double *out);
- virtual GBool isOk() { return ok; }
+ GfxAxialShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A);
+ virtual ~GfxAxialShading();
-private:
+ static GfxAxialShading *parse(Dict *dict);
- SampledFunction(SampledFunction *func);
+ void getCoords(double *x0A, double *y0A, double *x1A, double *y1A)
+ { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
+ double getDomain0() { return t0; }
+ double getDomain1() { return t1; }
+ void getColor(double t, GfxColor *color);
+ GBool getExtend0() { return extend0; }
+ GBool getExtend1() { return extend1; }
- int // number of samples for each domain element
- sampleSize[funcMaxInputs];
- double // min and max values for domain encoder
- encode[funcMaxInputs][2];
- double // min and max values for range decoder
- decode[funcMaxOutputs][2];
- double *samples; // the samples
- GBool ok;
+private:
+
+ double x0, y0, x1, y1;
+ double t0, t1;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+ GBool extend0, extend1;
};
//------------------------------------------------------------------------
-// ExponentialFunction
+// GfxRadialShading
//------------------------------------------------------------------------
-class ExponentialFunction: public Function {
+class GfxRadialShading: public GfxShading {
public:
- ExponentialFunction(Object *funcObj, Dict *dict);
- virtual ~ExponentialFunction();
- virtual Function *copy() { return new ExponentialFunction(this); }
- virtual void transform(double *in, double *out);
- virtual GBool isOk() { return ok; }
+ GfxRadialShading(double x0A, double y0A, double r0A,
+ double x1A, double y1A, double r1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A);
+ virtual ~GfxRadialShading();
-private:
+ static GfxRadialShading *parse(Dict *dict);
- ExponentialFunction(ExponentialFunction *func);
+ void getCoords(double *x0A, double *y0A, double *r0A,
+ double *x1A, double *y1A, double *r1A)
+ { *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; }
+ double getDomain0() { return t0; }
+ double getDomain1() { return t1; }
+ void getColor(double t, GfxColor *color);
+ GBool getExtend0() { return extend0; }
+ GBool getExtend1() { return extend1; }
- double c0[funcMaxOutputs];
- double c1[funcMaxOutputs];
- double e;
- GBool ok;
+private:
+
+ double x0, y0, r0, x1, y1, r1;
+ double t0, t1;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+ GBool extend0, extend1;
};
//------------------------------------------------------------------------
public:
// Constructor.
- GfxImageColorMap(int bits, Object *decode, GfxColorSpace *colorSpace);
+ GfxImageColorMap(int bitsA, Object *decode, GfxColorSpace *colorSpaceA);
// Destructor.
~GfxImageColorMap();
double x3, double y3);
// Close the last subpath.
- void close() { subpaths[n-1]->close(); }
+ void close();
private:
public:
// Construct a default GfxState, for a device with resolution <dpi>,
- // page box (<x1>,<y1>)-(<x2>,<y2>), page rotation <rotate>, and
- // coordinate system specified by <upsideDown>.
- GfxState(double dpi, double px1a, double py1a,
- double px2a, double py2a, int rotate, GBool upsideDown);
+ // page box <pageBox>, page rotation <rotate>, and coordinate system
+ // specified by <upsideDown>.
+ GfxState(double dpi, PDFRectangle *pageBox, int rotate,
+ GBool upsideDown);
// Destructor.
~GfxState();
double getPageHeight() { return pageHeight; }
GfxColor *getFillColor() { return &fillColor; }
GfxColor *getStrokeColor() { return &strokeColor; }
+ void getFillGray(double *gray)
+ { fillColorSpace->getGray(&fillColor, gray); }
+ void getStrokeGray(double *gray)
+ { strokeColorSpace->getGray(&fillColor, gray); }
void getFillRGB(GfxRGB *rgb)
{ fillColorSpace->getRGB(&fillColor, rgb); }
void getStrokeRGB(GfxRGB *rgb)
GfxPath *getPath() { return path; }
double getCurX() { return curX; }
double getCurY() { return curY; }
+ void getClipBBox(double *xMin, double *yMin, double *xMax, double *yMax)
+ { *xMin = clipXMin; *yMin = clipYMin; *xMax = clipXMax; *yMax = clipYMax; }
+ void getUserClipBBox(double *xMin, double *yMin, double *xMax, double *yMax);
double getLineX() { return lineX; }
double getLineY() { return lineY; }
void setFlatness(int flatness1) { flatness = flatness1; }
void setLineJoin(int lineJoin1) { lineJoin = lineJoin1; }
void setLineCap(int lineCap1) { lineCap = lineCap1; }
- void setMiterLimit(double miterLimit1) { miterLimit = miterLimit1; }
- void setFont(GfxFont *font1, double fontSize1)
- { font = font1; fontSize = fontSize1; }
+ void setMiterLimit(double limit) { miterLimit = limit; }
+ void setFont(GfxFont *fontA, double fontSizeA)
+ { font = fontA; fontSize = fontSizeA; }
void setTextMat(double a, double b, double c,
double d, double e, double f)
{ textMat[0] = a; textMat[1] = b; textMat[2] = c;
{ wordSpace = space; }
void setHorizScaling(double scale)
{ horizScaling = 0.01 * scale; }
- void setLeading(double leading1)
- { leading = leading1; }
- void setRise(double rise1)
- { rise = rise1; }
- void setRender(int render1)
- { render = render1; }
+ void setLeading(double leadingA)
+ { leading = leadingA; }
+ void setRise(double riseA)
+ { rise = riseA; }
+ void setRender(int renderA)
+ { render = renderA; }
// Add to path.
void moveTo(double x, double y)
{ path->close(); curX = path->getLastX(); curY = path->getLastY(); }
void clearPath();
+ // Update clip region.
+ void clip();
+
// Text position.
void textMoveTo(double tx, double ty)
{ lineX = tx; lineY = ty; textTransform(tx, ty, &curX, &curY); }
- void textShift(double tx);
void textShift(double tx, double ty);
+ void shift(double dx, double dy);
// Push/pop GfxState on/off stack.
GfxState *save();
double curX, curY; // current point (user coords)
double lineX, lineY; // start of current text line (text coords)
+ double clipXMin, clipYMin, // bounding box for clip region
+ clipXMax, clipYMax;
+
GfxState *saved; // next GfxState on stack
GfxState(GfxState *state);
//
// Lexer.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
// Lexer
//------------------------------------------------------------------------
-Lexer::Lexer(Stream *str) {
+Lexer::Lexer(XRef *xref, Stream *str) {
Object obj;
curStr.initStream(str);
- streams = new Array();
+ streams = new Array(xref);
streams->add(curStr.copy(&obj));
strPtr = 0;
freeArray = gTrue;
curStr.streamReset();
}
-Lexer::Lexer(Object *obj) {
+Lexer::Lexer(XRef *xref, Object *obj) {
Object obj2;
if (obj->isStream()) {
- streams = new Array();
+ streams = new Array(xref);
freeArray = gTrue;
streams->add(obj->copy(&obj2));
} else {
case '(':
++numParen;
+ c2 = c;
break;
case ')':
- if (--numParen == 0)
+ if (--numParen == 0) {
done = gTrue;
+ } else {
+ c2 = c;
+ }
break;
case '\\':
//
// Lexer.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#include "Object.h"
#include "Stream.h"
+class XRef;
+
#define tokBufSize 128 // size of token buffer
//------------------------------------------------------------------------
// Construct a lexer for a single stream. Deletes the stream when
// lexer is deleted.
- Lexer(Stream *str);
+ Lexer(XRef *xref, Stream *str);
// Construct a lexer for a stream or array of streams (assumes obj
// is either a stream or array of streams).
- Lexer(Object *obj);
+ Lexer(XRef *xref, Object *obj);
// Destructor.
~Lexer();
Stream *getStream()
{ return curStr.isNone() ? (Stream *)NULL : curStr.getStream(); }
- // Get current position in file.
+ // Get current position in file. This is only used for error
+ // messages, so it returns an int instead of a Guint.
int getPos()
- { return curStr.isNone() ? -1 : curStr.streamGetPos(); }
+ { return curStr.isNone() ? -1 : (int)curStr.streamGetPos(); }
// Set position in file.
- void setPos(int pos)
- { if (!curStr.isNone()) curStr.streamSetPos(pos); }
+ void setPos(Guint pos, int dir = 0)
+ { if (!curStr.isNone()) curStr.streamSetPos(pos, dir); }
private:
//
// Link.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stddef.h>
#include <string.h>
#include "gmem.h"
// LinkDest
//------------------------------------------------------------------------
-LinkDest::LinkDest(Array *a, GBool pageIsRef1) {
+LinkDest::LinkDest(Array *a) {
Object obj1, obj2;
// initialize fields
- pageIsRef = pageIsRef1;
left = bottom = right = top = zoom = 0;
ok = gFalse;
// get page
- if (pageIsRef) {
- if (!a->getNF(0, &obj1)->isRef()) {
- if(obj1.getType()!=objInt)
- error(-1, "Bad annotation destination (1) type=%d", obj1.getType());
- goto err2;
- }
+ a->getNF(0, &obj1);
+ if (obj1.isInt()) {
+ pageNum = obj1.getInt() + 1;
+ pageIsRef = gFalse;
+ } else if (obj1.isRef()) {
pageRef.num = obj1.getRefNum();
pageRef.gen = obj1.getRefGen();
- obj1.free();
+ pageIsRef = gTrue;
} else {
- if (!a->get(0, &obj1)->isInt()) {
- error(-1, "Bad annotation destination (2)");
- goto err2;
- }
- pageNum = obj1.getInt() + 1;
- obj1.free();
+ error(-1, "Bad annotation destination");
+ goto err2;
}
+ obj1.free();
// get destination type
a->get(1, &obj1);
// destination dictionary
} else if (destObj->isArray()) {
- dest = new LinkDest(destObj->getArray(), gTrue);
+ dest = new LinkDest(destObj->getArray());
if (!dest->isOk()) {
delete dest;
dest = NULL;
// destination dictionary
} else if (destObj->isArray()) {
- dest = new LinkDest(destObj->getArray(), gFalse);
+ dest = new LinkDest(destObj->getArray());
if (!dest->isOk()) {
delete dest;
dest = NULL;
// LinkUnknown
//------------------------------------------------------------------------
-LinkUnknown::LinkUnknown(char *action1) {
- action = new GString(action1);
+LinkUnknown::LinkUnknown(char *actionA) {
+ action = new GString(actionA);
}
LinkUnknown::~LinkUnknown() {
}
// get border
- borderW = 0;
+ borderW = 1;
if (!dict->lookup("Border", &obj1)->isNull()) {
- if (obj1.isArray() && obj1.arrayGet(2, &obj2)->isNum())
- borderW = obj2.getNum();
- else
- error(-1, "Bad annotation border");
- obj2.free();
+ if (obj1.isArray() && obj1.arrayGetLength() >= 3) {
+ if (obj1.arrayGet(2, &obj2)->isNum()) {
+ borderW = obj2.getNum();
+ } else {
+ error(-1, "Bad annotation border");
+ }
+ obj2.free();
+ }
}
obj1.free();
LinkAction *Links::find(double x, double y) {
int i;
- for (i = 0; i < numLinks; ++i) {
+ for (i = numLinks - 1; i >= 0; --i) {
if (links[i]->inRect(x, y)) {
return links[i]->getAction();
}
//
// Link.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
class LinkDest {
public:
- // Build a LinkDest from the array. If <pageIsRef> is true, the
- // page is specified by an object reference; otherwise the page is
- // specified by a (zero-relative) page number.
- LinkDest(Array *a, GBool pageIsRef1);
+ // Build a LinkDest from the array.
+ LinkDest(Array *a);
// Copy a LinkDest.
LinkDest *copy() { return new LinkDest(this); }
public:
// Build a LinkUnknown with the specified action type.
- LinkUnknown(char *action1);
+ LinkUnknown(char *actionA);
// Destructor.
virtual ~LinkUnknown();
//
// Object.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stddef.h>
#include "Object.h"
#include "Array.h"
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
#endif
-Object *Object::initArray() {
+Object *Object::initArray(XRef *xref) {
initObj(objArray);
- array = new Array();
+ array = new Array(xref);
return this;
}
-Object *Object::initDict() {
+Object *Object::initDict(XRef *xref) {
initObj(objDict);
- dict = new Dict();
+ dict = new Dict(xref);
return this;
}
-Object *Object::initStream(Stream *stream1) {
+Object *Object::initStream(Stream *streamA) {
initObj(objStream);
- stream = stream1;
+ stream = streamA;
return this;
}
return obj;
}
-Object *Object::fetch(Object *obj) {
+Object *Object::fetch(XRef *xref, Object *obj) {
return (type == objRef && xref) ?
xref->fetch(ref.num, ref.gen, obj) : copy(obj);
}
fprintf(f, "%g", real);
break;
case objString:
- fprintf(f, "(%s)", string->getCString());
+ fprintf(f, "(");
+ fwrite(string->getCString(), 1, string->getLength(), stdout);
+ fprintf(f, ")");
break;
case objName:
fprintf(f, "/%s", name);
//
// Object.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#include "gmem.h"
#include "GString.h"
+class XRef;
class Array;
class Dict;
class Stream;
type(objNone) {}
// Initialize an object.
- Object *initBool(GBool booln1)
- { initObj(objBool); booln = booln1; return this; }
- Object *initInt(int intg1)
- { initObj(objInt); intg = intg1; return this; }
- Object *initReal(double real1)
- { initObj(objReal); real = real1; return this; }
- Object *initString(GString *string1)
- { initObj(objString); string = string1; return this; }
- Object *initName(char *name1)
- { initObj(objName); name = copyString(name1); return this; }
+ Object *initBool(GBool boolnA)
+ { initObj(objBool); booln = boolnA; return this; }
+ Object *initInt(int intgA)
+ { initObj(objInt); intg = intgA; return this; }
+ Object *initReal(double realA)
+ { initObj(objReal); real = realA; return this; }
+ Object *initString(GString *stringA)
+ { initObj(objString); string = stringA; return this; }
+ Object *initName(char *nameA)
+ { initObj(objName); name = copyString(nameA); return this; }
Object *initNull()
{ initObj(objNull); return this; }
- Object *initArray();
- Object *initDict();
- Object *initDict(Dict *dict1)
- { initObj(objDict); dict = dict1; return this; }
- Object *initStream(Stream *stream1);
- Object *initRef(int num1, int gen1)
- { initObj(objRef); ref.num = num1; ref.gen = gen1; return this; }
- Object *initCmd(char *cmd1)
- { initObj(objCmd); cmd = copyString(cmd1); return this; }
+ Object *initArray(XRef *xref);
+ Object *initDict(XRef *xref);
+ Object *initStream(Stream *streamA);
+ Object *initRef(int numA, int genA)
+ { initObj(objRef); ref.num = numA; ref.gen = genA; return this; }
+ Object *initCmd(char *cmdA)
+ { initObj(objCmd); cmd = copyString(cmdA); return this; }
Object *initError()
{ initObj(objError); return this; }
Object *initEOF()
// If object is a Ref, fetch and return the referenced object.
// Otherwise, return a copy of the object.
- Object *fetch(Object *obj);
+ Object *fetch(XRef *xref, Object *obj);
// Free object contents.
void free();
GBool isNone() { return type == objNone; }
// Special type checking.
- GBool isName(char *name1)
- { return type == objName && !strcmp(name, name1); }
+ GBool isName(char *nameA)
+ { return type == objName && !strcmp(name, nameA); }
GBool isDict(char *dictType);
GBool isStream(char *dictType);
- GBool isCmd(char *cmd1)
- { return type == objCmd && !strcmp(cmd, cmd1); }
+ GBool isCmd(char *cmdA)
+ { return type == objCmd && !strcmp(cmd, cmdA); }
// Accessors. NB: these assume object is of correct type.
GBool getBool() { return booln; }
int streamGetChar();
int streamLookChar();
char *streamGetLine(char *buf, int size);
- int streamGetPos();
- void streamSetPos(int pos);
+ Guint streamGetPos();
+ void streamSetPos(Guint pos, int dir = 0);
Dict *streamGetDict();
// Output.
inline char *Object::streamGetLine(char *buf, int size)
{ return stream->getLine(buf, size); }
-inline int Object::streamGetPos()
+inline Guint Object::streamGetPos()
{ return stream->getPos(); }
-inline void Object::streamSetPos(int pos)
- { stream->setPos(pos); }
+inline void Object::streamSetPos(Guint pos, int dir)
+ { stream->setPos(pos, dir); }
inline Dict *Object::streamGetDict()
{ return stream->getDict(); }
//
// OutputDev.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stddef.h>
#include "Object.h"
#include "Stream.h"
// OutputDev
//------------------------------------------------------------------------
-void OutputDev::setDefaultCTM(double *ctm1) {
+void OutputDev::setDefaultCTM(double *ctm) {
int i;
double det;
- for (i = 0; i < 6; ++i)
- ctm[i] = ctm1[i];
- det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
- ictm[0] = ctm[3] * det;
- ictm[1] = -ctm[1] * det;
- ictm[2] = -ctm[2] * det;
- ictm[3] = ctm[0] * det;
- ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
- ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ for (i = 0; i < 6; ++i) {
+ defCTM[i] = ctm[i];
+ }
+ det = 1 / (defCTM[0] * defCTM[3] - defCTM[1] * defCTM[2]);
+ defICTM[0] = defCTM[3] * det;
+ defICTM[1] = -defCTM[1] * det;
+ defICTM[2] = -defCTM[2] * det;
+ defICTM[3] = defCTM[0] * det;
+ defICTM[4] = (defCTM[2] * defCTM[5] - defCTM[3] * defCTM[4]) * det;
+ defICTM[5] = (defCTM[1] * defCTM[4] - defCTM[0] * defCTM[5]) * det;
}
void OutputDev::cvtDevToUser(int dx, int dy, double *ux, double *uy) {
- *ux = ictm[0] * dx + ictm[2] * dy + ictm[4];
- *uy = ictm[1] * dx + ictm[3] * dy + ictm[5];
+ *ux = defICTM[0] * dx + defICTM[2] * dy + defICTM[4];
+ *uy = defICTM[1] * dx + defICTM[3] * dy + defICTM[5];
}
void OutputDev::cvtUserToDev(double ux, double uy, int *dx, int *dy) {
- *dx = (int)(ctm[0] * ux + ctm[2] * uy + ctm[4] + 0.5);
- *dy = (int)(ctm[1] * ux + ctm[3] * uy + ctm[5] + 0.5);
+ *dx = (int)(defCTM[0] * ux + defCTM[2] * uy + defCTM[4] + 0.5);
+ *dy = (int)(defCTM[1] * ux + defCTM[3] * uy + defCTM[5] + 0.5);
}
void OutputDev::updateAll(GfxState *state) {
updateFont(state);
}
+GBool OutputDev::beginType3Char(GfxState *state,
+ CharCode code, Unicode *u, int uLen) {
+ return gFalse;
+}
+
void OutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
int width, int height, GBool invert,
GBool inlineImg) {
j = height * ((width + 7) / 8);
for (i = 0; i < j; ++i)
str->getChar();
+ str->close();
}
}
void OutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
int width, int height, GfxImageColorMap *colorMap,
- GBool inlineImg) {
+ int *maskColors, GBool inlineImg) {
int i, j;
if (inlineImg) {
colorMap->getBits() + 7) / 8);
for (i = 0; i < j; ++i)
str->getChar();
+ str->close();
}
}
//
// OutputDev.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#endif
#include "gtypes.h"
+#include "CharTypes.h"
class GString;
class GfxState;
// Does this device use drawChar() or drawString()?
virtual GBool useDrawChar() = 0;
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() = 0;
+
+ // Does this device need non-text content?
+ virtual GBool needNonText() { return gTrue; }
+
//----- initialization and control
// Set default transform matrix.
- virtual void setDefaultCTM(double *ctm1);
+ virtual void setDefaultCTM(double *ctm);
// Start a page.
virtual void startPage(int pageNum, GfxState *state) {}
virtual void beginString(GfxState *state, GString *s) {}
virtual void endString(GfxState *state) {}
virtual void drawChar(GfxState *state, double x, double y,
- double dx, double dy, Guchar c) {}
- virtual void drawChar16(GfxState *state, double x, double y,
- double dx, double dy, int c) {}
+ double dx, double dy,
+ double originX, double originY,
+ CharCode code, Unicode *u, int uLen) {}
virtual void drawString(GfxState *state, GString *s) {}
- virtual void drawString16(GfxState *state, GString *s) {}
+ virtual GBool beginType3Char(GfxState *state,
+ CharCode code, Unicode *u, int uLen);
+ virtual void endType3Char(GfxState *state) {}
//----- image drawing
virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
GBool inlineImg);
virtual void drawImage(GfxState *state, Object *ref, Stream *str,
int width, int height, GfxImageColorMap *colorMap,
- GBool inlineImg);
+ int *maskColors, GBool inlineImg);
#if OPI_SUPPORT
//----- OPI functions
virtual void opiEnd(GfxState *state, Dict *opiDict);
#endif
+ //----- Type 3 font operators
+ virtual void type3D0(GfxState *state, double wx, double wy) {}
+ virtual void type3D1(GfxState *state, double wx, double wy,
+ double llx, double lly, double urx, double ury) {}
+
+ //----- PostScript XObjects
+ virtual void psXObject(Stream *psStream, Stream *level1Stream) {}
+
private:
- double ctm[6]; // coordinate transform matrix
- double ictm[6]; // inverse CTM
+ double defCTM[6]; // default coordinate transform matrix
+ double defICTM[6]; // inverse of default CTM
};
#endif
//
// PDFDoc.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include "XRef.h"
#include "Link.h"
#include "OutputDev.h"
-#include "Params.h"
#include "Error.h"
+#include "ErrorCodes.h"
#include "Lexer.h"
#include "Parser.h"
#include "PDFDoc.h"
// PDFDoc
//------------------------------------------------------------------------
-PDFDoc::PDFDoc(GString *fileName1, GString *userPassword) {
+PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword,
+ GString *userPassword, GBool printCommandsA) {
Object obj;
GString *fileName2;
ok = gFalse;
+ errCode = errNone;
file = NULL;
str = NULL;
xref = NULL;
catalog = NULL;
links = NULL;
+ printCommands = printCommandsA;
// try to open file
- fileName = fileName1;
+ fileName = fileNameA;
fileName2 = NULL;
#ifdef VMS
if (!(file = fopen(fileName->getCString(), "rb", "ctx=stm"))) {
error(-1, "Couldn't open file '%s'", fileName->getCString());
+ errCode = errOpenFile;
return;
}
#else
if (!(file = fopen(fileName2->getCString(), "rb"))) {
error(-1, "Couldn't open file '%s'", fileName->getCString());
delete fileName2;
+ errCode = errOpenFile;
return;
}
}
// create stream
obj.initNull();
- str = new FileStream(file, 0, -1, &obj);
+ str = new FileStream(file, 0, gFalse, 0, &obj);
- ok = setup(userPassword);
+ ok = setup(ownerPassword, userPassword);
}
-PDFDoc::PDFDoc(BaseStream *str, GString *userPassword) {
+PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword,
+ GString *userPassword, GBool printCommandsA) {
ok = gFalse;
+ errCode = errNone;
fileName = NULL;
file = NULL;
- this->str = str;
+ str = strA;
xref = NULL;
catalog = NULL;
links = NULL;
- ok = setup(userPassword);
+ printCommands = printCommandsA;
+ ok = setup(ownerPassword, userPassword);
}
-GBool PDFDoc::setup(GString *userPassword) {
- Object catObj;
-
+GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) {
// check header
checkHeader();
// read xref table
- xref = new XRef(str, userPassword);
+ xref = new XRef(str, ownerPassword, userPassword);
if (!xref->isOk()) {
error(-1, "Couldn't read xref table");
+ errCode = xref->getErrorCode();
return gFalse;
}
// read catalog
- catalog = new Catalog(xref->getCatalog(&catObj));
- catObj.free();
+ catalog = new Catalog(xref, printCommands);
if (!catalog->isOk()) {
error(-1, "Couldn't read page catalog");
+ errCode = errBadCatalog;
return gFalse;
}
lin = gFalse;
obj1.initNull();
- parser = new Parser(new Lexer(str->makeSubStream(str->getStart(),
- -1, &obj1)));
+ parser = new Parser(xref,
+ new Lexer(xref,
+ str->makeSubStream(str->getStart(), gFalse, 0, &obj1)));
parser->getObj(&obj1);
parser->getObj(&obj2);
parser->getObj(&obj3);
links = new Links(page->getAnnots(&obj), catalog->getBaseURI());
obj.free();
}
-
//
// PDFDoc.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#endif
#include <stdio.h>
+#include "XRef.h"
#include "Link.h"
#include "Catalog.h"
#include "Page.h"
class GString;
class BaseStream;
-class XRef;
class OutputDev;
class Links;
class LinkAction;
class PDFDoc {
public:
- PDFDoc(GString *fileName1, GString *userPassword = NULL);
- PDFDoc(BaseStream *str, GString *userPassword = NULL);
+ PDFDoc(GString *fileNameA, GString *ownerPassword = NULL,
+ GString *userPassword = NULL, GBool printCommandsA = gFalse);
+ PDFDoc(BaseStream *strA, GString *ownerPassword = NULL,
+ GString *userPassword = NULL, GBool printCommandsA = gFalse);
~PDFDoc();
// Was PDF document successfully opened?
GBool isOk() { return ok; }
+ // Get the error code (if isOk() returns false).
+ int getErrorCode() { return errCode; }
+
// Get file name.
GString *getFileName() { return fileName; }
+ // Get the xref table.
+ XRef *getXRef() { return xref; }
+
// Get catalog.
Catalog *getCatalog() { return catalog; }
// Get number of pages.
int getNumPages() { return catalog->getNumPages(); }
+ // Return the contents of the metadata stream, or NULL if there is
+ // no metadata.
+ GString *readMetadata() { return catalog->readMetadata(); }
+
+ // Return the structure tree root object.
+ Object *getStructTreeRoot() { return catalog->getStructTreeRoot(); }
+
// Display a page.
void displayPage(OutputDev *out, int page, double zoom,
int rotate, GBool doLinks);
GBool isEncrypted() { return xref->isEncrypted(); }
// Check various permissions.
- GBool okToPrint() { return xref->okToPrint(); }
- GBool okToChange() { return xref->okToChange(); }
- GBool okToCopy() { return xref->okToCopy(); }
- GBool okToAddNotes() { return xref->okToAddNotes(); }
+ GBool okToPrint(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToPrint(ignoreOwnerPW); }
+ GBool okToChange(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToChange(ignoreOwnerPW); }
+ GBool okToCopy(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToCopy(ignoreOwnerPW); }
+ GBool okToAddNotes(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToAddNotes(ignoreOwnerPW); }
// Is this document linearized?
GBool isLinearized();
private:
- GBool setup(GString *userPassword);
+ GBool setup(GString *ownerPassword, GString *userPassword);
void checkHeader();
void getLinks(Page *page);
XRef *xref;
Catalog *catalog;
Links *links;
+ GBool printCommands;
GBool ok;
+ int errCode;
};
#endif
//
// Page.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stddef.h>
#include "Object.h"
#include "Array.h"
#include "OutputDev.h"
#ifndef PDF_PARSER_ONLY
#include "Gfx.h"
-#include "FormWidget.h"
+#include "Annot.h"
#endif
#include "Error.h"
-
-#include "Params.h"
#include "Page.h"
//------------------------------------------------------------------------
//------------------------------------------------------------------------
PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
- Object obj1, obj2;
+ Object obj1;
double w, h;
// get old/default values
if (attrs) {
- x1 = attrs->x1;
- y1 = attrs->y1;
- x2 = attrs->x2;
- y2 = attrs->y2;
- cropX1 = attrs->cropX1;
- cropY1 = attrs->cropY1;
- cropX2 = attrs->cropX2;
- cropY2 = attrs->cropY2;
+ mediaBox = attrs->mediaBox;
+ cropBox = attrs->cropBox;
+ haveCropBox = attrs->haveCropBox;
rotate = attrs->rotate;
attrs->resources.copy(&resources);
} else {
// set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
// but some (non-compliant) PDF files don't specify a MediaBox
- x1 = 0;
- y1 = 0;
- x2 = 612;
- y2 = 792;
- cropX1 = cropY1 = cropX2 = cropY2 = 0;
+ mediaBox.x1 = 0;
+ mediaBox.y1 = 0;
+ mediaBox.x2 = 612;
+ mediaBox.y2 = 792;
+ cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
+ haveCropBox = gFalse;
rotate = 0;
resources.initNull();
}
// media box
- dict->lookup("MediaBox", &obj1);
- if (obj1.isArray() && obj1.arrayGetLength() == 4) {
- obj1.arrayGet(0, &obj2);
- if (obj2.isNum())
- x1 = obj2.getNum();
- obj2.free();
- obj1.arrayGet(1, &obj2);
- if (obj2.isNum())
- y1 = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2, &obj2);
- if (obj2.isNum())
- x2 = obj2.getNum();
- obj2.free();
- obj1.arrayGet(3, &obj2);
- if (obj2.isNum())
- y2 = obj2.getNum();
- obj2.free();
- }
- obj1.free();
+ readBox(dict, "MediaBox", &mediaBox);
// crop box
- dict->lookup("CropBox", &obj1);
- if (obj1.isArray() && obj1.arrayGetLength() == 4) {
- obj1.arrayGet(0, &obj2);
- if (obj2.isNum())
- cropX1 = obj2.getNum();
- obj2.free();
- obj1.arrayGet(1, &obj2);
- if (obj2.isNum())
- cropY1 = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2, &obj2);
- if (obj2.isNum())
- cropX2 = obj2.getNum();
- obj2.free();
- obj1.arrayGet(3, &obj2);
- if (obj2.isNum())
- cropY2 = obj2.getNum();
- obj2.free();
- }
- obj1.free();
+ cropBox = mediaBox;
+ haveCropBox = readBox(dict, "CropBox", &cropBox);
// if the MediaBox is excessively larger than the CropBox,
// just use the CropBox
limitToCropBox = gFalse;
- w = 0.25 * (cropX2 - cropX1);
- h = 0.25 * (cropY2 - cropY1);
- if (cropX2 > cropX1 &&
- ((cropX1 - x1) + (x2 - cropX2) > w ||
- (cropY1 - y1) + (y2 - cropY2) > h)) {
- limitToCropBox = gTrue;
+ if (haveCropBox) {
+ w = 0.25 * (cropBox.x2 - cropBox.x1);
+ h = 0.25 * (cropBox.y2 - cropBox.y1);
+ if ((cropBox.x1 - mediaBox.x1) + (mediaBox.x2 - cropBox.x2) > w ||
+ (cropBox.y1 - mediaBox.y1) + (mediaBox.y2 - cropBox.y2) > h) {
+ limitToCropBox = gTrue;
+ }
}
+ // other boxes
+ bleedBox = cropBox;
+ readBox(dict, "BleedBox", &bleedBox);
+ trimBox = cropBox;
+ readBox(dict, "TrimBox", &trimBox);
+ artBox = cropBox;
+ readBox(dict, "ArtBox", &artBox);
+
// rotate
dict->lookup("Rotate", &obj1);
- if (obj1.isInt())
+ if (obj1.isInt()) {
rotate = obj1.getInt();
+ }
obj1.free();
- while (rotate < 0)
+ while (rotate < 0) {
rotate += 360;
- while (rotate >= 360)
+ }
+ while (rotate >= 360) {
rotate -= 360;
+ }
+
+ // misc attributes
+ dict->lookup("LastModified", &lastModified);
+ dict->lookup("BoxColorInfo", &boxColorInfo);
+ dict->lookup("Group", &group);
+ dict->lookup("Metadata", &metadata);
+ dict->lookup("PieceInfo", &pieceInfo);
+ dict->lookup("SeparationInfo", &separationInfo);
// resource dictionary
dict->lookup("Resources", &obj1);
}
PageAttrs::~PageAttrs() {
+ lastModified.free();
+ boxColorInfo.free();
+ group.free();
+ metadata.free();
+ pieceInfo.free();
+ separationInfo.free();
resources.free();
}
+GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) {
+ PDFRectangle tmp;
+ Object obj1, obj2;
+ GBool ok;
+
+ dict->lookup(key, &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+ ok = gTrue;
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isNum()) {
+ tmp.x1 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ if (obj2.isNum()) {
+ tmp.y1 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ if (obj2.isNum()) {
+ tmp.x2 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ if (obj2.isNum()) {
+ tmp.y2 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ if (ok) {
+ *box = tmp;
+ }
+ } else {
+ ok = gFalse;
+ }
+ obj1.free();
+ return ok;
+}
+
//------------------------------------------------------------------------
// Page
//------------------------------------------------------------------------
-Page::Page(int num1, Dict *pageDict, PageAttrs *attrs1) {
+Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA,
+ GBool printCommandsA) {
ok = gTrue;
- num = num1;
+ xref = xrefA;
+ num = numA;
+ printCommands = printCommandsA;
// get attributes
- attrs = attrs1;
+ attrs = attrsA;
// annotations
pageDict->lookupNF("Annots", &annots);
void Page::display(OutputDev *out, double dpi, int rotate,
Links *links, Catalog *catalog) {
#ifndef PDF_PARSER_ONLY
+ PDFRectangle *box, *cropBox;
Gfx *gfx;
Object obj;
Link *link;
int i;
- FormWidgets *formWidgets;
+ Annots *annotList;
+
+ box = getBox();
+ cropBox = getCropBox();
if (printCommands) {
printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
- getX1(), getY1(), getX2(), getY2());
+ box->x1, box->y1, box->x2, box->y2);
if (isCropped()) {
printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
- getCropX1(), getCropY1(), getCropX2(), getCropY2());
+ cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
}
printf("***** Rotate = %d\n", attrs->getRotate());
}
} else if (rotate < 0) {
rotate += 360;
}
- gfx = new Gfx(out, num, attrs->getResourceDict(),
- dpi, getX1(), getY1(), getX2(), getY2(), isCropped(),
- getCropX1(), getCropY1(), getCropX2(), getCropY2(), rotate);
- contents.fetch(&obj);
+ gfx = new Gfx(xref, out, num, attrs->getResourceDict(),
+ dpi, box, isCropped(), cropBox, rotate, printCommands);
+ contents.fetch(xref, &obj);
if (!obj.isNull()) {
gfx->display(&obj);
}
out->dump();
}
- // draw AcroForm widgets
+ // draw non-link annotations
//~ need to reset CTM ???
- formWidgets = new FormWidgets(annots.fetch(&obj));
+ annotList = new Annots(xref, annots.fetch(xref, &obj));
obj.free();
- if (printCommands && formWidgets->getNumWidgets() > 0) {
- printf("***** AcroForm widgets\n");
- }
- for (i = 0; i < formWidgets->getNumWidgets(); ++i) {
- formWidgets->getWidget(i)->draw(gfx);
- }
- if (formWidgets->getNumWidgets() > 0) {
+ if (annotList->getNumAnnots() > 0) {
+ if (printCommands) {
+ printf("***** Annotations\n");
+ }
+ for (i = 0; i < annotList->getNumAnnots(); ++i) {
+ annotList->getAnnot(i)->draw(gfx);
+ }
out->dump();
}
- delete formWidgets;
+ delete annotList;
delete gfx;
#endif
//
// Page.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
class Catalog;
//------------------------------------------------------------------------
+
+struct PDFRectangle {
+ double x1, y1, x2, y2;
+};
+
+//------------------------------------------------------------------------
// PageAttrs
//------------------------------------------------------------------------
~PageAttrs();
// Accessors.
- double getX1() { return limitToCropBox ? cropX1 : x1; }
- double getY1() { return limitToCropBox ? cropY1 : y1; }
- double getX2() { return limitToCropBox ? cropX2 : x2; }
- double getY2() { return limitToCropBox ? cropY2 : y2; }
- GBool isCropped() { return cropX2 > cropX1; }
- double getCropX1() { return cropX1; }
- double getCropY1() { return cropY1; }
- double getCropX2() { return cropX2; }
- double getCropY2() { return cropY2; }
+ PDFRectangle *getBox() { return limitToCropBox ? &cropBox : &mediaBox; }
+ PDFRectangle *getMediaBox() { return &mediaBox; }
+ PDFRectangle *getCropBox() { return &cropBox; }
+ GBool isCropped() { return haveCropBox; }
+ PDFRectangle *getBleedBox() { return &bleedBox; }
+ PDFRectangle *getTrimBox() { return &trimBox; }
+ PDFRectangle *getArtBox() { return &artBox; }
int getRotate() { return rotate; }
+ GString *getLastModified()
+ { return lastModified.isString()
+ ? lastModified.getString() : (GString *)NULL; }
+ Dict *getBoxColorInfo()
+ { return boxColorInfo.isDict() ? boxColorInfo.getDict() : (Dict *)NULL; }
+ Dict *getGroup()
+ { return group.isDict() ? group.getDict() : (Dict *)NULL; }
+ Stream *getMetadata()
+ { return metadata.isStream() ? metadata.getStream() : (Stream *)NULL; }
+ Dict *getPieceInfo()
+ { return pieceInfo.isDict() ? pieceInfo.getDict() : (Dict *)NULL; }
+ Dict *getSeparationInfo()
+ { return separationInfo.isDict()
+ ? separationInfo.getDict() : (Dict *)NULL; }
Dict *getResourceDict()
{ return resources.isDict() ? resources.getDict() : (Dict *)NULL; }
private:
- double x1, y1, x2, y2;
- double cropX1, cropY1, cropX2, cropY2;
+ GBool readBox(Dict *dict, char *key, PDFRectangle *box);
+
+ PDFRectangle mediaBox;
+ PDFRectangle cropBox;
+ GBool haveCropBox;
GBool limitToCropBox;
+ PDFRectangle bleedBox;
+ PDFRectangle trimBox;
+ PDFRectangle artBox;
int rotate;
+ Object lastModified;
+ Object boxColorInfo;
+ Object group;
+ Object metadata;
+ Object pieceInfo;
+ Object separationInfo;
Object resources;
};
public:
// Constructor.
- Page(int num1, Dict *pageDict, PageAttrs *attrs1);
+ Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA,
+ GBool printCommandsA);
// Destructor.
~Page();
GBool isOk() { return ok; }
// Get page parameters.
- double getX1() { return attrs->getX1(); }
- double getY1() { return attrs->getY1(); }
- double getX2() { return attrs->getX2(); }
- double getY2() { return attrs->getY2(); }
+ PDFRectangle *getBox() { return attrs->getBox(); }
+ PDFRectangle *getMediaBox() { return attrs->getMediaBox(); }
+ PDFRectangle *getCropBox() { return attrs->getCropBox(); }
GBool isCropped() { return attrs->isCropped(); }
- double getCropX1() { return attrs->getCropX1(); }
- double getCropY1() { return attrs->getCropY1(); }
- double getCropX2() { return attrs->getCropX2(); }
- double getCropY2() { return attrs->getCropY2(); }
- double getWidth() { return attrs->getX2() - attrs->getX1(); }
- double getHeight() { return attrs->getY2() - attrs->getY1(); }
+ double getWidth() { return attrs->getBox()->x2 - attrs->getBox()->x1; }
+ double getHeight() { return attrs->getBox()->y2 - attrs->getBox()->y1; }
+ PDFRectangle *getBleedBox() { return attrs->getBleedBox(); }
+ PDFRectangle *getTrimBox() { return attrs->getTrimBox(); }
+ PDFRectangle *getArtBox() { return attrs->getArtBox(); }
int getRotate() { return attrs->getRotate(); }
+ GString *getLastModified() { return attrs->getLastModified(); }
+ Dict *getBoxColorInfo() { return attrs->getBoxColorInfo(); }
+ Dict *getGroup() { return attrs->getGroup(); }
+ Stream *getMetadata() { return attrs->getMetadata(); }
+ Dict *getPieceInfo() { return attrs->getPieceInfo(); }
+ Dict *getSeparationInfo() { return attrs->getSeparationInfo(); }
// Get resource dictionary.
Dict *getResourceDict() { return attrs->getResourceDict(); }
// Get annotations array.
- Object *getAnnots(Object *obj) { return annots.fetch(obj); }
+ Object *getAnnots(Object *obj) { return annots.fetch(xref, obj); }
// Get contents.
- Object *getContents(Object *obj) { return contents.fetch(obj); }
+ Object *getContents(Object *obj) { return contents.fetch(xref, obj); }
// Display a page.
void display(OutputDev *out, double dpi, int rotate,
private:
+ XRef *xref; // the xref table for this PDF file
int num; // page number
PageAttrs *attrs; // page attributes
Object annots; // annotations array
Object contents; // page contents
+ GBool printCommands; // print the drawing commands (for debugging)
GBool ok; // true if page is valid
};
+++ /dev/null
-//========================================================================
-//
-// Params.cc
-//
-// Copyright 1996 Derek B. Noonburg
-//
-//========================================================================
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include "gtypes.h"
-#include "gmem.h"
-#include "GString.h"
-#include "gfile.h"
-#include "Params.h"
-
-char **fontPath = NULL;
-static int fontPathLen, fontPathSize;
-
-DevFontMapEntry *devFontMap = NULL;
-static int devFontMapLen, devFontMapSize;
-
-void initParams(char *configFile) {
- GString *fileName;
- FILE *f;
- char buf[256];
- char *p, *q;
-
- // initialize font path and font map
- fontPath = (char **)gmalloc((fontPathSize = 8) * sizeof(char *));
- fontPath[fontPathLen = 0] = NULL;
- devFontMap = (DevFontMapEntry *)gmalloc((devFontMapSize = 8) *
- sizeof(DevFontMapEntry));
- devFontMap[devFontMapLen = 0].pdfFont = NULL;
-
- // read config file
- fileName = appendToPath(getHomeDir(), configFile);
- if ((f = fopen(fileName->getCString(), "r"))) {
- while (fgets(buf, sizeof(buf)-1, f)) {
- buf[sizeof(buf)-1] = '\0';
- p = strtok(buf, " \t\n\r");
- if (p && !strcmp(p, "fontpath")) {
- if (fontPathLen+1 >= fontPathSize)
- fontPath = (char **)
- grealloc(fontPath, (fontPathSize += 8) * sizeof(char *));
- p = strtok(NULL, " \t\n\r");
- fontPath[fontPathLen++] = copyString(p);
- } else if (p && !strcmp(p, "fontmap")) {
- if (devFontMapLen+1 >= devFontMapSize)
- devFontMap = (DevFontMapEntry *)
- grealloc(devFontMap,
- (devFontMapSize += 8) * sizeof(DevFontMapEntry));
- p = strtok(NULL, " \t\n\r");
- devFontMap[devFontMapLen].pdfFont = copyString(p);
- p = strtok(NULL, "\t\n\r");
- while (*p == ' ')
- ++p;
- for (q = p + strlen(p) - 1; q >= p && *q == ' '; --q) ;
- q[1] = '\0';
- devFontMap[devFontMapLen++].devFont = copyString(p);
- }
- }
- fclose(f);
- fontPath[fontPathLen] = NULL;
- devFontMap[devFontMapLen].pdfFont = NULL;
- }
- delete fileName;
-}
-
-void freeParams() {
- int i;
-
- if (fontPath) {
- for (i = 0; i < fontPathLen; ++i)
- gfree(fontPath[i]);
- gfree(fontPath);
- }
- if (devFontMap) {
- for (i = 0; i < devFontMapLen; ++i) {
- gfree(devFontMap[i].pdfFont);
- gfree(devFontMap[i].devFont);
- }
- gfree(devFontMap);
- }
-}
+++ /dev/null
-//========================================================================
-//
-// Params.h
-//
-// Copyright 1996 Derek B. Noonburg
-//
-//========================================================================
-
-#ifndef PARAMS_H
-#define PARAMS_H
-
-// Print commands as they're executed.
-extern GBool printCommands;
-
-// If this is set, error messages will be silently discarded.
-extern GBool errQuiet;
-
-// Font search path.
-extern char **fontPath;
-
-// Mapping from PDF font name to device font name.
-struct DevFontMapEntry {
- char *pdfFont;
- char *devFont;
-};
-extern DevFontMapEntry *devFontMap;
-
-//------------------------------------------------------------------------
-
-// Initialize font path and font map, and read configuration file,
-// if present.
-extern void initParams(char *configFile);
-
-// Free memory used for font path and font map.
-extern void freeParams();
-
-#endif
//
// Parser.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stddef.h>
#include "Object.h"
#include "Array.h"
#include "Decrypt.h"
#endif
-Parser::Parser(Lexer *lexer1) {
- lexer = lexer1;
+Parser::Parser(XRef *xrefA, Lexer *lexerA) {
+ xref = xrefA;
+ lexer = lexerA;
inlineImg = 0;
lexer->getObj(&buf1);
lexer->getObj(&buf2);
#ifndef NO_DECRYPTION
Object *Parser::getObj(Object *obj,
- Guchar *fileKey, int objNum, int objGen) {
+ Guchar *fileKey, int keyLength,
+ int objNum, int objGen) {
#else
Object *Parser::getObj(Object *obj) {
#endif
// array
if (buf1.isCmd("[")) {
shift();
- obj->initArray();
+ obj->initArray(xref);
while (!buf1.isCmd("]") && !buf1.isEOF())
#ifndef NO_DECRYPTION
- obj->arrayAdd(getObj(&obj2, fileKey, objNum, objGen));
+ obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen));
#else
obj->arrayAdd(getObj(&obj2));
#endif
// dictionary or stream
} else if (buf1.isCmd("<<")) {
shift();
- obj->initDict();
+ obj->initDict(xref);
while (!buf1.isCmd(">>") && !buf1.isEOF()) {
if (!buf1.isName()) {
error(getPos(), "Dictionary key must be a name object");
if (buf1.isEOF() || buf1.isError())
break;
#ifndef NO_DECRYPTION
- obj->dictAdd(key, getObj(&obj2, fileKey, objNum, objGen));
+ obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen));
#else
obj->dictAdd(key, getObj(&obj2));
#endif
obj->initStream(str);
#ifndef NO_DECRYPTION
if (fileKey) {
- str->getBaseStream()->doDecryption(fileKey, objNum, objGen);
+ str->getBaseStream()->doDecryption(fileKey, keyLength,
+ objNum, objGen);
}
#endif
} else {
} else if (buf1.isString() && fileKey) {
buf1.copy(obj);
s = obj->getString();
- decrypt = new Decrypt(fileKey, objNum, objGen);
+ decrypt = new Decrypt(fileKey, keyLength, objNum, objGen);
for (i = 0, p = obj->getString()->getCString();
i < s->getLength();
++i, ++p) {
Stream *Parser::makeStream(Object *dict) {
Object obj;
Stream *str;
- int pos, endPos, length;
+ Guint pos, endPos, length;
// get stream start position
lexer->skipToNextLine();
// get length
dict->dictLookup("Length", &obj);
if (obj.isInt()) {
- length = obj.getInt();
+ length = (Guint)obj.getInt();
obj.free();
} else {
error(getPos(), "Bad 'Length' attribute in stream");
}
// check for length in damaged file
- if ((endPos = xref->getStreamEnd(pos)) >= 0) {
+ if (xref->getStreamEnd(pos, &endPos)) {
length = endPos - pos;
}
// make base stream
- str = lexer->getStream()->getBaseStream()->makeSubStream(pos, length, dict);
+ str = lexer->getStream()->getBaseStream()->makeSubStream(pos, gTrue,
+ length, dict);
// get filters
str = str->addFilters(dict);
//
// Parser.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
public:
// Constructor.
- Parser(Lexer *lexer1);
+ Parser(XRef *xrefA, Lexer *lexerA);
// Destructor.
~Parser();
// Get the next object from the input stream.
#ifndef NO_DECRYPTION
Object *getObj(Object *obj,
- Guchar *fileKey = NULL, int objNum = 0, int objGen = 0);
+ Guchar *fileKey = NULL, int keyLength = 0,
+ int objNum = 0, int objGen = 0);
#else
Object *getObj(Object *obj);
#endif
private:
+ XRef *xref; // the xref table for this PDF file
Lexer *lexer; // input stream
Object buf1, buf2; // next two tokens
int inlineImg; // set when inline image data is encountered
+++ /dev/null
-//========================================================================
-//
-// StdFontInfo.h
-//
-// This file was automatically generated by makeFontInfo.
-//
-// Copyright 1999 Derek B. Noonburg
-//
-//========================================================================
-
-#ifndef STDFONTINFO_H
-#define STDFONTINFO_H
-
-//------------------------------------------------------------------------
-// type1StdEncoding -- Adobe Type 1 StandardEncoding
-//------------------------------------------------------------------------
-
-#define type1StdEncodingSize 256
-static char *type1StdEncodingNames[type1StdEncodingSize] = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "space",
- "exclam",
- "quotedbl",
- "numbersign",
- "dollar",
- "percent",
- "ampersand",
- "quoteright",
- "parenleft",
- "parenright",
- "asterisk",
- "plus",
- "comma",
- "hyphen",
- "period",
- "slash",
- "zero",
- "one",
- "two",
- "three",
- "four",
- "five",
- "six",
- "seven",
- "eight",
- "nine",
- "colon",
- "semicolon",
- "less",
- "equal",
- "greater",
- "question",
- "at",
- "A",
- "B",
- "C",
- "D",
- "E",
- "F",
- "G",
- "H",
- "I",
- "J",
- "K",
- "L",
- "M",
- "N",
- "O",
- "P",
- "Q",
- "R",
- "S",
- "T",
- "U",
- "V",
- "W",
- "X",
- "Y",
- "Z",
- "bracketleft",
- "backslash",
- "bracketright",
- "asciicircum",
- "underscore",
- "quoteleft",
- "a",
- "b",
- "c",
- "d",
- "e",
- "f",
- "g",
- "h",
- "i",
- "j",
- "k",
- "l",
- "m",
- "n",
- "o",
- "p",
- "q",
- "r",
- "s",
- "t",
- "u",
- "v",
- "w",
- "x",
- "y",
- "z",
- "braceleft",
- "bar",
- "braceright",
- "asciitilde",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "exclamdown",
- "cent",
- "sterling",
- "fraction",
- "yen",
- "florin",
- "section",
- "currency",
- "quotesingle",
- "quotedblleft",
- "guillemotleft",
- "guilsinglleft",
- "guilsinglright",
- "fi",
- "fl",
- NULL,
- "endash",
- "dagger",
- "daggerdbl",
- "periodcentered",
- NULL,
- "paragraph",
- "bullet",
- "quotesinglbase",
- "quotedblbase",
- "quotedblright",
- "guillemotright",
- "ellipsis",
- "perthousand",
- NULL,
- "questiondown",
- NULL,
- "grave",
- "acute",
- "circumflex",
- "tilde",
- "macron",
- "breve",
- "dotaccent",
- "dieresis",
- NULL,
- "ring",
- "cedilla",
- NULL,
- "hungarumlaut",
- "ogonek",
- "caron",
- "emdash",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "AE",
- NULL,
- "ordfeminine",
- NULL,
- NULL,
- NULL,
- NULL,
- "Lslash",
- "Oslash",
- "OE",
- "ordmasculine",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "ae",
- NULL,
- NULL,
- NULL,
- "dotlessi",
- NULL,
- NULL,
- "lslash",
- "oslash",
- "oe",
- "germandbls",
- NULL,
- NULL,
- NULL,
- NULL
-};
-static FontEncoding type1StdEncoding(type1StdEncodingNames,
- type1StdEncodingSize);
-
-//------------------------------------------------------------------------
-// type1ExpertEncoding -- Adobe Type 1 ExpertEncoding
-//------------------------------------------------------------------------
-
-#define type1ExpertEncodingSize 256
-static char *type1ExpertEncodingNames[type1ExpertEncodingSize] = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "space",
- "exclamsmall",
- "Hungarumlautsmall",
- NULL,
- "dollaroldstyle",
- "dollarsuperior",
- "ampersandsmall",
- "Acutesmall",
- "parenleftsuperior",
- "parenrightsuperior",
- "twodotenleader",
- "onedotenleader",
- "comma",
- "hyphen",
- "period",
- "fraction",
- "zerooldstyle",
- "oneoldstyle",
- "twooldstyle",
- "threeoldstyle",
- "fouroldstyle",
- "fiveoldstyle",
- "sixoldstyle",
- "sevenoldstyle",
- "eightoldstyle",
- "nineoldstyle",
- "colon",
- "semicolon",
- "commasuperior",
- "threequartersemdash",
- "periodsuperior",
- "questionsmall",
- NULL,
- "asuperior",
- "bsuperior",
- "centsuperior",
- "dsuperior",
- "esuperior",
- NULL,
- NULL,
- NULL,
- "isuperior",
- NULL,
- NULL,
- "lsuperior",
- "msuperior",
- "nsuperior",
- "osuperior",
- NULL,
- NULL,
- "rsuperior",
- "ssuperior",
- "tsuperior",
- NULL,
- "ff",
- "fi",
- "fl",
- "ffi",
- "ffl",
- "parenleftinferior",
- NULL,
- "parenrightinferior",
- "Circumflexsmall",
- "hyphensuperior",
- "Gravesmall",
- "Asmall",
- "Bsmall",
- "Csmall",
- "Dsmall",
- "Esmall",
- "Fsmall",
- "Gsmall",
- "Hsmall",
- "Ismall",
- "Jsmall",
- "Ksmall",
- "Lsmall",
- "Msmall",
- "Nsmall",
- "Osmall",
- "Psmall",
- "Qsmall",
- "Rsmall",
- "Ssmall",
- "Tsmall",
- "Usmall",
- "Vsmall",
- "Wsmall",
- "Xsmall",
- "Ysmall",
- "Zsmall",
- "colonmonetary",
- "onefitted",
- "rupiah",
- "Tildesmall",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "exclamdownsmall",
- "centoldstyle",
- "Lslashsmall",
- NULL,
- NULL,
- "Scaronsmall",
- "Zcaronsmall",
- "Dieresissmall",
- "Brevesmall",
- "Caronsmall",
- NULL,
- "Dotaccentsmall",
- NULL,
- NULL,
- "Macronsmall",
- NULL,
- NULL,
- "figuredash",
- "hypheninferior",
- NULL,
- NULL,
- "Ogoneksmall",
- "Ringsmall",
- "Cedillasmall",
- NULL,
- NULL,
- NULL,
- "onequarter",
- "onehalf",
- "threequarters",
- "questiondownsmall",
- "oneeighth",
- "threeeighths",
- "fiveeighths",
- "seveneighths",
- "onethird",
- "twothirds",
- NULL,
- NULL,
- "zerosuperior",
- "onesuperior",
- "twosuperior",
- "threesuperior",
- "foursuperior",
- "fivesuperior",
- "sixsuperior",
- "sevensuperior",
- "eightsuperior",
- "ninesuperior",
- "zeroinferior",
- "oneinferior",
- "twoinferior",
- "threeinferior",
- "fourinferior",
- "fiveinferior",
- "sixinferior",
- "seveninferior",
- "eightinferior",
- "nineinferior",
- "centinferior",
- "dollarinferior",
- "periodinferior",
- "commainferior",
- "Agravesmall",
- "Aacutesmall",
- "Acircumflexsmall",
- "Atildesmall",
- "Adieresissmall",
- "Aringsmall",
- "AEsmall",
- "Ccedillasmall",
- "Egravesmall",
- "Eacutesmall",
- "Ecircumflexsmall",
- "Edieresissmall",
- "Igravesmall",
- "Iacutesmall",
- "Icircumflexsmall",
- "Idieresissmall",
- "Ethsmall",
- "Ntildesmall",
- "Ogravesmall",
- "Oacutesmall",
- "Ocircumflexsmall",
- "Otildesmall",
- "Odieresissmall",
- "OEsmall",
- "Oslashsmall",
- "Ugravesmall",
- "Uacutesmall",
- "Ucircumflexsmall",
- "Udieresissmall",
- "Yacutesmall",
- "Thornsmall",
- "Ydieresissmall"
-};
-static FontEncoding type1ExpertEncoding(type1ExpertEncodingNames,
- type1ExpertEncodingSize);
-
-#endif
//
// Tables for CCITT Fax decoding.
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
//
// Stream.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
// BaseStream
//------------------------------------------------------------------------
-BaseStream::BaseStream(Object *dict) {
- this->dict = *dict;
+BaseStream::BaseStream(Object *dictA) {
+ dict = *dictA;
#ifndef NO_DECRYPTION
decrypt = NULL;
#endif
}
#ifndef NO_DECRYPTION
-void BaseStream::doDecryption(Guchar *fileKey, int objNum, int objGen) {
- decrypt = new Decrypt(fileKey, objNum, objGen);
+void BaseStream::doDecryption(Guchar *fileKey, int keyLength,
+ int objNum, int objGen) {
+ decrypt = new Decrypt(fileKey, keyLength, objNum, objGen);
}
#endif
// FilterStream
//------------------------------------------------------------------------
-FilterStream::FilterStream(Stream *str) {
- this->str = str;
+FilterStream::FilterStream(Stream *strA) {
+ str = strA;
}
FilterStream::~FilterStream() {
str->close();
}
-void FilterStream::setPos(int pos) {
+void FilterStream::setPos(Guint pos, int dir) {
error(-1, "Internal: called setPos() on FilterStream");
}
// ImageStream
//------------------------------------------------------------------------
-ImageStream::ImageStream(Stream *str, int width, int nComps, int nBits) {
+ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) {
int imgLineSize;
- this->str = str;
- this->width = width;
- this->nComps = nComps;
- this->nBits = nBits;
+ str = strA;
+ width = widthA;
+ nComps = nCompsA;
+ nBits = nBitsA;
nVals = width * nComps;
if (nBits == 1) {
// StreamPredictor
//------------------------------------------------------------------------
-StreamPredictor::StreamPredictor(Stream *str, int predictor,
- int width, int nComps, int nBits) {
- this->str = str;
- this->predictor = predictor;
- this->width = width;
- this->nComps = nComps;
- this->nBits = nBits;
+StreamPredictor::StreamPredictor(Stream *strA, int predictorA,
+ int widthA, int nCompsA, int nBitsA) {
+ str = strA;
+ predictor = predictorA;
+ width = widthA;
+ nComps = nCompsA;
+ nBits = nBitsA;
nVals = width * nComps;
pixBytes = (nComps * nBits + 7) >> 3;
if ((pc = p - upLeft) < 0)
pc = -pc;
if (pa <= pb && pa <= pc)
- predLine[i] = pa + (Guchar)c;
+ predLine[i] = left + (Guchar)c;
else if (pb <= pc)
- predLine[i] = pb + (Guchar)c;
+ predLine[i] = up + (Guchar)c;
else
- predLine[i] = pc + (Guchar)c;
+ predLine[i] = upLeft + (Guchar)c;
break;
case 10: // PNG none
default: // no predictor or TIFF predictor
// FileStream
//------------------------------------------------------------------------
-FileStream::FileStream(FILE *f, int start, int length, Object *dict):
- BaseStream(dict) {
- this->f = f;
- this->start = start;
- this->length = length;
+FileStream::FileStream(FILE *fA, Guint startA, GBool limitedA,
+ Guint lengthA, Object *dictA):
+ BaseStream(dictA) {
+ f = fA;
+ start = startA;
+ limited = limitedA;
+ length = lengthA;
bufPtr = bufEnd = buf;
bufPos = start;
- savePos = -1;
+ savePos = 0;
+ saved = gFalse;
}
FileStream::~FileStream() {
close();
}
-Stream *FileStream::makeSubStream(int start, int length, Object *dict) {
- return new FileStream(f, start, length, dict);
+Stream *FileStream::makeSubStream(Guint startA, GBool limitedA,
+ Guint lengthA, Object *dictA) {
+ return new FileStream(f, startA, limitedA, lengthA, dictA);
}
void FileStream::reset() {
- savePos = (int)ftell(f);
+#if HAVE_FSEEK64
+ savePos = (Guint)ftell64(f);
+ fseek64(f, start, SEEK_SET);
+#else
+ savePos = (Guint)ftell(f);
fseek(f, start, SEEK_SET);
+#endif
+ saved = gTrue;
bufPtr = bufEnd = buf;
bufPos = start;
#ifndef NO_DECRYPTION
}
void FileStream::close() {
- if (savePos >= 0) {
+ if (saved) {
+#if HAVE_FSEEK64
+ fseek64(f, savePos, SEEK_SET);
+#else
fseek(f, savePos, SEEK_SET);
- savePos = -1;
+#endif
+ saved = gFalse;
}
}
bufPos += bufEnd - buf;
bufPtr = bufEnd = buf;
- if (length >= 0 && bufPos >= start + length) {
+ if (limited && bufPos >= start + length) {
return gFalse;
}
- if (length >= 0 && bufPos + fileStreamBufSize > start + length) {
+ if (limited && bufPos + fileStreamBufSize > start + length) {
n = start + length - bufPos;
} else {
n = fileStreamBufSize;
return gTrue;
}
-void FileStream::setPos(int pos1) {
- long size;
+void FileStream::setPos(Guint pos, int dir) {
+ Guint size;
- if (pos1 >= 0) {
- fseek(f, pos1, SEEK_SET);
- bufPos = pos1;
+ if (dir >= 0) {
+#if HAVE_FSEEK64
+ fseek64(f, pos, SEEK_SET);
+#else
+ fseek(f, pos, SEEK_SET);
+#endif
+ bufPos = pos;
} else {
+#if HAVE_FSEEK64
+ fseek64(f, 0, SEEK_END);
+ size = (Guint)ftell64(f);
+#else
fseek(f, 0, SEEK_END);
- size = ftell(f);
- if (pos1 < -size)
- pos1 = (int)(-size);
- fseek(f, pos1, SEEK_END);
- bufPos = (int)ftell(f);
+ size = (Guint)ftell(f);
+#endif
+ if (pos > size)
+ pos = (Guint)size;
+#ifdef __CYGWIN32__
+ //~ work around a bug in cygwin's implementation of fseek
+ rewind(f);
+#endif
+#if HAVE_FSEEK64
+ fseek64(f, -(int)pos, SEEK_END);
+ bufPos = (Guint)ftell64(f);
+#else
+ fseek(f, -(int)pos, SEEK_END);
+ bufPos = (Guint)ftell(f);
+#endif
}
bufPtr = bufEnd = buf;
}
void FileStream::moveStart(int delta) {
- this->start += delta;
+ start += delta;
bufPtr = bufEnd = buf;
bufPos = start;
}
//------------------------------------------------------------------------
+// MemStream
+//------------------------------------------------------------------------
+
+MemStream::MemStream(char *bufA, Guint lengthA, Object *dictA):
+ BaseStream(dictA) {
+ buf = bufA;
+ needFree = gFalse;
+ length = lengthA;
+ bufEnd = buf + length;
+ bufPtr = buf;
+}
+
+MemStream::~MemStream() {
+ if (needFree) {
+ gfree(buf);
+ }
+}
+
+Stream *MemStream::makeSubStream(Guint start, GBool limited,
+ Guint lengthA, Object *dictA) {
+ Guint newLength;
+
+ if (!limited || start + lengthA > length) {
+ newLength = length - start;
+ } else {
+ newLength = lengthA;
+ }
+ return new MemStream(buf + start, newLength, dictA);
+}
+
+void MemStream::reset() {
+ bufPtr = buf;
+#ifndef NO_DECRYPTION
+ if (decrypt) {
+ decrypt->reset();
+ }
+#endif
+}
+
+void MemStream::close() {
+}
+
+void MemStream::setPos(Guint pos, int dir) {
+ if (dir >= 0) {
+ if (pos > length) {
+ bufPtr = bufEnd;
+ } else {
+ bufPtr = buf + pos;
+ }
+ } else {
+ if (pos > length) {
+ bufPtr = buf;
+ } else {
+ bufPtr = bufEnd - pos;
+ }
+ }
+}
+
+void MemStream::moveStart(int delta) {
+ buf += delta;
+ bufPtr = buf;
+}
+
+#ifndef NO_DECRYPTION
+void MemStream::doDecryption(Guchar *fileKey, int keyLength,
+ int objNum, int objGen) {
+ char *newBuf;
+ char *p, *q;
+
+ this->BaseStream::doDecryption(fileKey, keyLength, objNum, objGen);
+ if (decrypt) {
+ newBuf = (char *)gmalloc(bufEnd - buf);
+ for (p = buf, q = newBuf; p < bufEnd; ++p, ++q) {
+ *q = (char)decrypt->decryptByte((Guchar)*p);
+ }
+ bufEnd = newBuf + (bufEnd - buf);
+ bufPtr = newBuf + (bufPtr - buf);
+ buf = newBuf;
+ needFree = gTrue;
+ }
+}
+#endif
+
+//------------------------------------------------------------------------
// EmbedStream
//------------------------------------------------------------------------
-EmbedStream::EmbedStream(Stream *str, Object *dict):
- BaseStream(dict) {
- this->str = str;
+EmbedStream::EmbedStream(Stream *strA, Object *dictA):
+ BaseStream(dictA) {
+ str = strA;
}
EmbedStream::~EmbedStream() {
}
-Stream *EmbedStream::makeSubStream(int start, int length, Object *dict) {
+Stream *EmbedStream::makeSubStream(Guint start, GBool limited,
+ Guint length, Object *dictA) {
error(-1, "Internal: called makeSubStream() on EmbedStream");
return NULL;
}
-void EmbedStream::setPos(int pos) {
+void EmbedStream::setPos(Guint pos, int dir) {
error(-1, "Internal: called setPos() on EmbedStream");
}
-int EmbedStream::getStart() {
+Guint EmbedStream::getStart() {
error(-1, "Internal: called getStart() on EmbedStream");
return 0;
}
-void EmbedStream::moveStart(int start) {
+void EmbedStream::moveStart(int delta) {
error(-1, "Internal: called moveStart() on EmbedStream");
}
// ASCIIHexStream
//------------------------------------------------------------------------
-ASCIIHexStream::ASCIIHexStream(Stream *str):
- FilterStream(str) {
+ASCIIHexStream::ASCIIHexStream(Stream *strA):
+ FilterStream(strA) {
buf = EOF;
eof = gFalse;
}
GString *ASCIIHexStream::getPSFilter(char *indent) {
GString *s;
- s = str->getPSFilter(indent);
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
s->append(indent)->append("/ASCIIHexDecode filter\n");
return s;
}
// ASCII85Stream
//------------------------------------------------------------------------
-ASCII85Stream::ASCII85Stream(Stream *str):
- FilterStream(str) {
+ASCII85Stream::ASCII85Stream(Stream *strA):
+ FilterStream(strA) {
index = n = 0;
eof = gFalse;
}
GString *ASCII85Stream::getPSFilter(char *indent) {
GString *s;
- s = str->getPSFilter(indent);
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
s->append(indent)->append("/ASCII85Decode filter\n");
return s;
}
// LZWStream
//------------------------------------------------------------------------
-LZWStream::LZWStream(Stream *str, int predictor1, int columns1, int colors1,
- int bits1, int early1):
- FilterStream(str) {
- if (predictor1 != 1) {
- pred = new StreamPredictor(this, predictor1, columns1, colors1, bits1);
+LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors,
+ int bits, int earlyA):
+ FilterStream(strA) {
+ if (predictor != 1) {
+ pred = new StreamPredictor(this, predictor, columns, colors, bits);
} else {
pred = NULL;
}
- early = early1;
+ early = earlyA;
zPipe = NULL;
bufPtr = bufEnd = buf;
}
return;
}
#else // HAVE_POPEN
-#ifdef VMS
- if (!system(zCmd->getCString())) {
-#else
- if (system(zCmd->getCString())) {
-#endif
+ if (!executeCommand(zCmd->getCString())) {
error(getPos(), "Couldn't execute '%s'", zCmd->getCString());
unlink(zName->getCString());
delete zName;
if (pred) {
return NULL;
}
- s = str->getPSFilter(indent);
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
s->append(indent)->append("/LZWDecode filter\n");
return s;
}
// RunLengthStream
//------------------------------------------------------------------------
-RunLengthStream::RunLengthStream(Stream *str):
- FilterStream(str) {
+RunLengthStream::RunLengthStream(Stream *strA):
+ FilterStream(strA) {
bufPtr = bufEnd = buf;
eof = gFalse;
}
GString *RunLengthStream::getPSFilter(char *indent) {
GString *s;
- s = str->getPSFilter(indent);
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
s->append(indent)->append("/RunLengthDecode filter\n");
return s;
}
// CCITTFaxStream
//------------------------------------------------------------------------
-CCITTFaxStream::CCITTFaxStream(Stream *str, int encoding, GBool endOfLine,
- GBool byteAlign, int columns, int rows,
- GBool endOfBlock, GBool black):
- FilterStream(str) {
- this->encoding = encoding;
- this->endOfLine = endOfLine;
- this->byteAlign = byteAlign;
- this->columns = columns;
- this->rows = rows;
- this->endOfBlock = endOfBlock;
- this->black = black;
+CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
+ GBool byteAlignA, int columnsA, int rowsA,
+ GBool endOfBlockA, GBool blackA):
+ FilterStream(strA) {
+ encoding = encodingA;
+ endOfLine = endOfLineA;
+ byteAlign = byteAlignA;
+ columns = columnsA;
+ rows = rowsA;
+ endOfBlock = endOfBlockA;
+ black = blackA;
refLine = (short *)gmalloc((columns + 3) * sizeof(short));
codingLine = (short *)gmalloc((columns + 2) * sizeof(short));
int CCITTFaxStream::lookChar() {
short code1, code2, code3;
int a0New;
-#if 0 //~
+#if 0
GBool err;
#endif
GBool gotEOL;
}
// read the next row
-#if 0 //~
+#if 0
err = gFalse;
#endif
if (codingLine[a0] >= columns) {
return EOF;
default:
error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1);
-#if 0 //~
+#if 0
err = gTrue;
break;
#else
if (codingLine[a0] != columns) {
error(getPos(), "CCITTFax row is wrong length (%d)", codingLine[a0]);
-#if 0 //~
+#if 0
err = gTrue;
#endif
}
}
}
-#if 0 //~
+#if 0
// This looks for an end-of-line marker after an error, however
// some (most?) CCITT streams in PDF files don't use end-of-line
// markers, and the just-plow-on technique works better in those
GString *s;
char s1[50];
- s = str->getPSFilter(indent);
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
s->append(indent)->append("<< ");
if (encoding != 0) {
sprintf(s1, "/K %d ", encoding);
63
};
-DCTStream::DCTStream(Stream *str):
- FilterStream(str) {
+DCTStream::DCTStream(Stream *strA):
+ FilterStream(strA) {
int i, j;
width = height = 0;
pCr = rowBuf[2][y2][x1+x2] - 128;
pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16;
rowBuf[0][y2][x1+x2] = 255 - dctClip[dctClipOffset + pR];
- pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32678) >> 16;
+ pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16;
rowBuf[1][y2][x1+x2] = 255 - dctClip[dctClipOffset + pG];
pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16;
rowBuf[2][y2][x1+x2] = 255 - dctClip[dctClipOffset + pB];
GString *DCTStream::getPSFilter(char *indent) {
GString *s;
- s = str->getPSFilter(indent);
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
s->append(indent)->append("<< >> /DCTDecode filter\n");
return s;
}
{13, 24577}
};
-FlateStream::FlateStream(Stream *str, int predictor1, int columns1,
- int colors1, int bits1):
- FilterStream(str) {
- if (predictor1 != 1) {
- pred = new StreamPredictor(this, predictor1, columns1, colors1, bits1);
+FlateStream::FlateStream(Stream *strA, int predictor, int columns,
+ int colors, int bits):
+ FilterStream(strA) {
+ if (predictor != 1) {
+ pred = new StreamPredictor(this, predictor, columns, colors, bits);
} else {
pred = NULL;
}
// EOFStream
//------------------------------------------------------------------------
-EOFStream::EOFStream(Stream *str):
- FilterStream(str) {
+EOFStream::EOFStream(Stream *strA):
+ FilterStream(strA) {
}
EOFStream::~EOFStream() {
// FixedLengthEncoder
//------------------------------------------------------------------------
-FixedLengthEncoder::FixedLengthEncoder(Stream *str, int length1):
- FilterStream(str) {
- length = length1;
+FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA):
+ FilterStream(strA) {
+ length = lengthA;
count = 0;
}
}
//------------------------------------------------------------------------
+// ASCIIHexEncoder
+//------------------------------------------------------------------------
+
+ASCIIHexEncoder::ASCIIHexEncoder(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = buf;
+ lineLen = 0;
+ eof = gFalse;
+}
+
+ASCIIHexEncoder::~ASCIIHexEncoder() {
+ if (str->isEncoder()) {
+ delete str;
+ }
+}
+
+void ASCIIHexEncoder::reset() {
+ str->reset();
+ bufPtr = bufEnd = buf;
+ lineLen = 0;
+ eof = gFalse;
+}
+
+void ASCIIHexEncoder::close() {
+}
+
+GBool ASCIIHexEncoder::fillBuf() {
+ static char *hex = "0123456789abcdef";
+ int c;
+
+ if (eof) {
+ return gFalse;
+ }
+ bufPtr = bufEnd = buf;
+ if ((c = str->getChar()) == EOF) {
+ *bufEnd++ = '>';
+ eof = gTrue;
+ } else {
+ if (lineLen >= 64) {
+ *bufEnd++ = '\n';
+ lineLen = 0;
+ }
+ *bufEnd++ = hex[(c >> 4) & 0x0f];
+ *bufEnd++ = hex[c & 0x0f];
+ lineLen += 2;
+ }
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
// ASCII85Encoder
//------------------------------------------------------------------------
-ASCII85Encoder::ASCII85Encoder(Stream *str):
- FilterStream(str) {
+ASCII85Encoder::ASCII85Encoder(Stream *strA):
+ FilterStream(strA) {
bufPtr = bufEnd = buf;
lineLen = 0;
eof = gFalse;
// RunLengthEncoder
//------------------------------------------------------------------------
-RunLengthEncoder::RunLengthEncoder(Stream *str):
- FilterStream(str) {
+RunLengthEncoder::RunLengthEncoder(Stream *strA):
+ FilterStream(strA) {
bufPtr = bufEnd = nextEnd = buf;
eof = gFalse;
}
//
// Stream.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
// Get current position in file.
virtual int getPos() = 0;
- // Go to a position in the stream.
- virtual void setPos(int pos1) = 0;
+ // Go to a position in the stream. If <dir> is negative, the
+ // position is from the end of the file; otherwise the position is
+ // from the start of the file.
+ virtual void setPos(Guint pos, int dir = 0) = 0;
// Get PostScript command for the filter(s).
virtual GString *getPSFilter(char *indent);
class BaseStream: public Stream {
public:
- BaseStream(Object *dict);
+ BaseStream(Object *dictA);
virtual ~BaseStream();
- virtual Stream *makeSubStream(int start, int length, Object *dict) = 0;
- virtual void setPos(int pos1) = 0;
+ virtual Stream *makeSubStream(Guint start, GBool limited,
+ Guint length, Object *dict) = 0;
+ virtual void setPos(Guint pos, int dir = 0) = 0;
virtual BaseStream *getBaseStream() { return this; }
virtual Dict *getDict() { return dict.getDict(); }
// Get/set position of first byte of stream within the file.
- virtual int getStart() = 0;
+ virtual Guint getStart() = 0;
virtual void moveStart(int delta) = 0;
#ifndef NO_DECRYPTION
// Set decryption for this stream.
- void doDecryption(Guchar *fileKey, int objNum, int objGen);
+ virtual void doDecryption(Guchar *fileKey, int keyLength,
+ int objNum, int objGen);
#endif
#ifndef NO_DECRYPTION
class FilterStream: public Stream {
public:
- FilterStream(Stream *str);
+ FilterStream(Stream *strA);
virtual ~FilterStream();
virtual void close();
virtual int getPos() { return str->getPos(); }
- virtual void setPos(int pos);
+ virtual void setPos(Guint pos, int dir = 0);
virtual BaseStream *getBaseStream() { return str->getBaseStream(); }
virtual Dict *getDict() { return str->getDict(); }
// Create an image stream object for an image with the specified
// parameters. Note that these are the actual image parameters,
// which may be different from the predictor parameters.
- ImageStream(Stream *str, int width, int nComps, int nBits);
+ ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA);
~ImageStream();
// Create a predictor object. Note that the parameters are for the
// predictor, and may not match the actual image parameters.
- StreamPredictor(Stream *str, int predictor,
- int width, int nComps, int nBits);
+ StreamPredictor(Stream *strA, int predictorA,
+ int widthA, int nCompsA, int nBitsA);
~StreamPredictor();
class FileStream: public BaseStream {
public:
- FileStream(FILE *f, int start, int length, Object *dict);
+ FileStream(FILE *fA, Guint startA, GBool limitedA,
+ Guint lengthA, Object *dictA);
virtual ~FileStream();
- virtual Stream *makeSubStream(int start, int length, Object *dict);
+ virtual Stream *makeSubStream(Guint startA, GBool limitedA,
+ Guint lengthA, Object *dictA);
virtual StreamKind getKind() { return strFile; }
virtual void reset();
virtual void close();
virtual int lookChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
virtual int getPos() { return bufPos + (bufPtr - buf); }
- virtual void setPos(int pos1);
+ virtual void setPos(Guint pos, int dir = 0);
virtual GBool isBinary(GBool last = gTrue) { return last; }
- virtual int getStart() { return start; }
+ virtual Guint getStart() { return start; }
virtual void moveStart(int delta);
private:
GBool fillBuf();
FILE *f;
- int start;
- int length;
+ Guint start;
+ GBool limited;
+ Guint length;
char buf[fileStreamBufSize];
char *bufPtr;
char *bufEnd;
- int bufPos;
+ Guint bufPos;
int savePos;
+ GBool saved;
+};
+
+//------------------------------------------------------------------------
+// MemStream
+//------------------------------------------------------------------------
+
+class MemStream: public BaseStream {
+public:
+
+ MemStream(char *bufA, Guint lengthA, Object *dictA);
+ virtual ~MemStream();
+ virtual Stream *makeSubStream(Guint start, GBool limited,
+ Guint lengthA, Object *dictA);
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufPtr < bufEnd) ? (*bufPtr++ & 0xff) : EOF; }
+ virtual int lookChar()
+ { return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; }
+ virtual int getPos() { return bufPtr - buf; }
+ virtual void setPos(Guint pos, int dir = 0);
+ virtual GBool isBinary(GBool last = gTrue) { return last; }
+ virtual Guint getStart() { return 0; }
+ virtual void moveStart(int delta);
+#ifndef NO_DECRYPTION
+ virtual void doDecryption(Guchar *fileKey, int keyLength,
+ int objNum, int objGen);
+#endif
+
+private:
+
+ char *buf;
+ Guint length;
+ GBool needFree;
+ char *bufEnd;
+ char *bufPtr;
};
//------------------------------------------------------------------------
class EmbedStream: public BaseStream {
public:
- EmbedStream(Stream *str, Object *dict);
+ EmbedStream(Stream *strA, Object *dictA);
virtual ~EmbedStream();
- virtual Stream *makeSubStream(int start, int length, Object *dict);
+ virtual Stream *makeSubStream(Guint start, GBool limited,
+ Guint length, Object *dictA);
virtual StreamKind getKind() { return str->getKind(); }
virtual void reset() {}
virtual int getChar() { return str->getChar(); }
virtual int lookChar() { return str->lookChar(); }
virtual int getPos() { return str->getPos(); }
- virtual void setPos(int pos);
+ virtual void setPos(Guint pos, int dir = 0);
virtual GBool isBinary(GBool last = gTrue) { return last; }
- virtual int getStart();
+ virtual Guint getStart();
virtual void moveStart(int delta);
private:
class ASCIIHexStream: public FilterStream {
public:
- ASCIIHexStream(Stream *str);
+ ASCIIHexStream(Stream *strA);
virtual ~ASCIIHexStream();
virtual StreamKind getKind() { return strASCIIHex; }
virtual void reset();
class ASCII85Stream: public FilterStream {
public:
- ASCII85Stream(Stream *str);
+ ASCII85Stream(Stream *strA);
virtual ~ASCII85Stream();
virtual StreamKind getKind() { return strASCII85; }
virtual void reset();
class LZWStream: public FilterStream {
public:
- LZWStream(Stream *str, int predictor1, int columns1, int colors1,
- int bits1, int early1);
+ LZWStream(Stream *strA, int predictor, int columns, int colors,
+ int bits, int earlyA);
virtual ~LZWStream();
virtual StreamKind getKind() { return strLZW; }
virtual void reset();
class RunLengthStream: public FilterStream {
public:
- RunLengthStream(Stream *str);
+ RunLengthStream(Stream *strA);
virtual ~RunLengthStream();
virtual StreamKind getKind() { return strRunLength; }
virtual void reset();
class CCITTFaxStream: public FilterStream {
public:
- CCITTFaxStream(Stream *str, int encoding, GBool endOfLine,
- GBool byteAlign, int columns, int rows,
- GBool endOfBlock, GBool black);
+ CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
+ GBool byteAlignA, int columnsA, int rowsA,
+ GBool endOfBlockA, GBool blackA);
virtual ~CCITTFaxStream();
virtual StreamKind getKind() { return strCCITTFax; }
virtual void reset();
class DCTStream: public FilterStream {
public:
- DCTStream(Stream *str);
+ DCTStream(Stream *strA);
virtual ~DCTStream();
virtual StreamKind getKind() { return strDCT; }
virtual void reset();
class FlateStream: public FilterStream {
public:
- FlateStream(Stream *str, int predictor1, int columns1,
- int colors1, int bits1);
+ FlateStream(Stream *strA, int predictor, int columns,
+ int colors, int bits);
virtual ~FlateStream();
virtual StreamKind getKind() { return strFlate; }
virtual void reset();
class EOFStream: public FilterStream {
public:
- EOFStream(Stream *str);
+ EOFStream(Stream *strA);
virtual ~EOFStream();
virtual StreamKind getKind() { return strWeird; }
virtual void reset() {}
class FixedLengthEncoder: public FilterStream {
public:
- FixedLengthEncoder(Stream *str, int length1);
+ FixedLengthEncoder(Stream *strA, int lengthA);
~FixedLengthEncoder();
virtual StreamKind getKind() { return strWeird; }
virtual void reset();
};
//------------------------------------------------------------------------
+// ASCIIHexEncoder
+//------------------------------------------------------------------------
+
+class ASCIIHexEncoder: public FilterStream {
+public:
+
+ ASCIIHexEncoder(Stream *strA);
+ virtual ~ASCIIHexEncoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ char buf[4];
+ char *bufPtr;
+ char *bufEnd;
+ int lineLen;
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+//------------------------------------------------------------------------
// ASCII85Encoder
//------------------------------------------------------------------------
class ASCII85Encoder: public FilterStream {
public:
- ASCII85Encoder(Stream *str);
+ ASCII85Encoder(Stream *strA);
virtual ~ASCII85Encoder();
virtual StreamKind getKind() { return strWeird; }
virtual void reset();
class RunLengthEncoder: public FilterStream {
public:
- RunLengthEncoder(Stream *str);
+ RunLengthEncoder(Stream *strA);
virtual ~RunLengthEncoder();
virtual StreamKind getKind() { return strWeird; }
virtual void reset();
//
// XRef.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <aconf.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "Decrypt.h"
#endif
#include "Error.h"
+#include "ErrorCodes.h"
#include "XRef.h"
//------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------
-// The global xref table
-//------------------------------------------------------------------------
-
-XRef *xref = NULL;
-
-//------------------------------------------------------------------------
// XRef
//------------------------------------------------------------------------
-XRef::XRef(BaseStream *str, GString *userPassword) {
- XRef *oldXref;
- int pos;
+XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) {
+ Guint pos;
int i;
ok = gTrue;
+ errCode = errNone;
size = 0;
entries = NULL;
streamEnds = NULL;
streamEndsLen = 0;
- // get rid of old xref (otherwise it will try to fetch the Root object
- // in the new document, using the old xref)
- oldXref = xref;
- xref = NULL;
-
// read the trailer
- this->str = str;
+ str = strA;
start = str->getStart();
pos = readTrailer();
// try to reconstruct the xref table
if (pos == 0) {
if (!(ok = constructXRef())) {
- xref = oldXref;
+ errCode = errDamaged;
return;
}
} else {
entries = (XRefEntry *)gmalloc(size * sizeof(XRefEntry));
for (i = 0; i < size; ++i) {
- entries[i].offset = -1;
+ entries[i].offset = 0xffffffff;
entries[i].used = gFalse;
}
while (readXRef(&pos)) ;
size = 0;
entries = NULL;
if (!(ok = constructXRef())) {
- xref = oldXref;
+ errCode = errDamaged;
return;
}
}
}
- // set up new xref table
- xref = this;
+ // now set the trailer dictionary's xref pointer so we can fetch
+ // indirect objects from it
+ trailerDict.getDict()->setXRef(this);
// check for encryption
#ifndef NO_DECRYPTION
encrypted = gFalse;
#endif
- if (checkEncrypted(userPassword)) {
+ if (checkEncrypted(ownerPassword, userPassword)) {
ok = gFalse;
- xref = oldXref;
+ errCode = errEncrypted;
return;
}
}
// Read startxref position, xref table size, and root. Returns
// first xref position.
-int XRef::readTrailer() {
+Guint XRef::readTrailer() {
Parser *parser;
Object obj;
char buf[xrefSearchSize+1];
- int n, pos, pos1;
+ int n;
+ Guint pos, pos1;
char *p;
int c;
int i;
// read last xrefSearchSize bytes
- str->setPos(-xrefSearchSize);
+ str->setPos(xrefSearchSize, -1);
for (n = 0; n < xrefSearchSize; ++n) {
if ((c = str->getChar()) == EOF)
break;
if (i < 0)
return 0;
for (p = &buf[i+9]; isspace(*p); ++p) ;
- pos = lastXRefPos = atoi(p);
+ pos = lastXRefPos = strToUnsigned(p);
// find trailer dict by looking after first xref table
// (NB: we can't just use the trailer dict at the end of the file --
// read trailer dict
obj.initNull();
- parser = new Parser(new Lexer(str->makeSubStream(start + pos1, -1, &obj)));
+ parser = new Parser(NULL,
+ new Lexer(NULL,
+ str->makeSubStream(start + pos1, gFalse, 0, &obj)));
parser->getObj(&trailerDict);
if (trailerDict.isDict()) {
trailerDict.dictLookupNF("Size", &obj);
}
// Read an xref table and the prev pointer from the trailer.
-GBool XRef::readXRef(int *pos) {
+GBool XRef::readXRef(Guint *pos) {
Parser *parser;
Object obj, obj2;
char s[20];
GBool more;
- int first, n, i, j;
+ int first, newSize, n, i, j;
int c;
// seek to xref in stream
s[1] = (char)str->getChar();
s[2] = (char)str->getChar();
s[3] = (char)str->getChar();
- if (!(s[0] == 'x' && s[1] == 'r' && s[2] == 'e' && s[3] == 'f'))
+ if (!(s[0] == 'x' && s[1] == 'r' && s[2] == 'e' && s[3] == 'f')) {
goto err2;
+ }
// read xref
while (1) {
- while ((c = str->lookChar()) != EOF && isspace(c))
+ while ((c = str->lookChar()) != EOF && isspace(c)) {
str->getChar();
- if (c == 't')
+ }
+ if (c == 't') {
break;
- for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i)
+ }
+ for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) {
s[i] = (char)c;
- if (i == 0)
+ }
+ if (i == 0) {
goto err2;
+ }
s[i] = '\0';
first = atoi(s);
- while ((c = str->lookChar()) != EOF && isspace(c))
+ while ((c = str->lookChar()) != EOF && isspace(c)) {
str->getChar();
- for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i)
+ }
+ for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) {
s[i] = (char)c;
- if (i == 0)
+ }
+ if (i == 0) {
goto err2;
+ }
s[i] = '\0';
n = atoi(s);
- while ((c = str->lookChar()) != EOF && isspace(c))
+ while ((c = str->lookChar()) != EOF && isspace(c)) {
str->getChar();
+ }
+ // check for buggy PDF files with an incorrect (too small) xref
+ // table size
+ if (first + n > size) {
+ newSize = size + 256;
+ entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry));
+ for (i = size; i < newSize; ++i) {
+ entries[i].offset = 0xffffffff;
+ entries[i].used = gFalse;
+ }
+ size = newSize;
+ }
for (i = first; i < first + n; ++i) {
for (j = 0; j < 20; ++j) {
- if ((c = str->getChar()) == EOF)
+ if ((c = str->getChar()) == EOF) {
goto err2;
+ }
s[j] = (char)c;
}
- if (entries[i].offset < 0) {
+ if (entries[i].offset == 0xffffffff) {
s[10] = '\0';
- entries[i].offset = atoi(s);
+ entries[i].offset = strToUnsigned(s);
s[16] = '\0';
entries[i].gen = atoi(&s[11]);
- if (s[17] == 'n')
+ if (s[17] == 'n') {
entries[i].used = gTrue;
- else if (s[17] == 'f')
+ } else if (s[17] == 'f') {
entries[i].used = gFalse;
- else
+ } else {
goto err2;
-#if 1 //~
- //~ PDF files of patents from the IBM Intellectual Property
- //~ Network have a bug: the xref table claims to start at 1
- //~ instead of 0.
+ }
+ // PDF files of patents from the IBM Intellectual Property
+ // Network have a bug: the xref table claims to start at 1
+ // instead of 0.
if (i == 1 && first == 1 &&
entries[1].offset == 0 && entries[1].gen == 65535 &&
!entries[1].used) {
i = first = 0;
entries[0] = entries[1];
- entries[1].offset = -1;
+ entries[1].offset = 0xffffffff;
}
-#endif
}
}
}
// read prev pointer from trailer dictionary
obj.initNull();
- parser = new Parser(new Lexer(str->makeSubStream(str->getPos(), -1, &obj)));
+ parser = new Parser(NULL,
+ new Lexer(NULL,
+ str->makeSubStream(str->getPos(), gFalse, 0, &obj)));
parser->getObj(&obj);
- if (!obj.isCmd("trailer"))
+ if (!obj.isCmd("trailer")) {
goto err1;
+ }
obj.free();
parser->getObj(&obj);
- if (!obj.isDict())
+ if (!obj.isDict()) {
goto err1;
+ }
obj.getDict()->lookupNF("Prev", &obj2);
if (obj2.isInt()) {
- *pos = obj2.getInt();
+ *pos = (Guint)obj2.getInt();
more = gTrue;
} else {
more = gFalse;
Parser *parser;
Object obj;
char buf[256];
- int pos;
+ Guint pos;
int num, gen;
int newSize;
int streamEndsSize;
// got trailer dictionary
if (!strncmp(p, "trailer", 7)) {
obj.initNull();
- parser = new Parser(new Lexer(
- str->makeSubStream(start + pos + 7, -1, &obj)));
+ parser = new Parser(NULL,
+ new Lexer(NULL,
+ str->makeSubStream(start + pos + 7, gFalse, 0, &obj)));
if (!trailerDict.isNone())
trailerDict.free();
parser->getObj(&trailerDict);
entries = (XRefEntry *)
grealloc(entries, newSize * sizeof(XRefEntry));
for (i = size; i < newSize; ++i) {
- entries[i].offset = -1;
+ entries[i].offset = 0xffffffff;
entries[i].used = gFalse;
}
size = newSize;
} else if (!strncmp(p, "endstream", 9)) {
if (streamEndsLen == streamEndsSize) {
streamEndsSize += 64;
- streamEnds = (int *)grealloc(streamEnds, streamEndsSize * sizeof(int));
+ streamEnds = (Guint *)grealloc(streamEnds,
+ streamEndsSize * sizeof(int));
}
streamEnds[streamEndsLen++] = pos;
}
}
#ifndef NO_DECRYPTION
-GBool XRef::checkEncrypted(GString *userPassword) {
- Object encrypt, ownerKey, userKey, permissions, fileID, fileID1;
+GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) {
+ Object encrypt, filterObj, versionObj, revisionObj, lengthObj;
+ Object ownerKey, userKey, permissions, fileID, fileID1;
GBool encrypted1;
GBool ret;
trailerDict.dictLookup("Encrypt", &encrypt);
if ((encrypted1 = encrypt.isDict())) {
ret = gTrue;
- encrypt.dictLookup("O", &ownerKey);
- encrypt.dictLookup("U", &userKey);
- encrypt.dictLookup("P", &permissions);
- trailerDict.dictLookup("ID", &fileID);
- if (ownerKey.isString() && ownerKey.getString()->getLength() == 32 &&
- userKey.isString() && userKey.getString()->getLength() == 32 &&
- permissions.isInt() &&
- fileID.isArray()) {
- permFlags = permissions.getInt();
- fileID.arrayGet(0, &fileID1);
- if (fileID1.isString()) {
- if (Decrypt::makeFileKey(ownerKey.getString(), userKey.getString(),
- permFlags, fileID1.getString(),
- userPassword, fileKey)) {
- ret = gFalse;
+ encrypt.dictLookup("Filter", &filterObj);
+ if (filterObj.isName("Standard")) {
+ encrypt.dictLookup("V", &versionObj);
+ encrypt.dictLookup("R", &revisionObj);
+ encrypt.dictLookup("Length", &lengthObj);
+ encrypt.dictLookup("O", &ownerKey);
+ encrypt.dictLookup("U", &userKey);
+ encrypt.dictLookup("P", &permissions);
+ trailerDict.dictLookup("ID", &fileID);
+ if (versionObj.isInt() &&
+ revisionObj.isInt() &&
+ ownerKey.isString() && ownerKey.getString()->getLength() == 32 &&
+ userKey.isString() && userKey.getString()->getLength() == 32 &&
+ permissions.isInt() &&
+ fileID.isArray()) {
+ encVersion = versionObj.getInt();
+ encRevision = revisionObj.getInt();
+ if (lengthObj.isInt()) {
+ keyLength = lengthObj.getInt() / 8;
} else {
- error(-1, "Incorrect user password");
+ keyLength = 5;
+ }
+ permFlags = permissions.getInt();
+ if (encVersion >= 1 && encVersion <= 2 &&
+ encRevision >= 2 && encRevision <= 3) {
+ fileID.arrayGet(0, &fileID1);
+ if (fileID1.isString()) {
+ if (Decrypt::makeFileKey(encVersion, encRevision, keyLength,
+ ownerKey.getString(), userKey.getString(),
+ permFlags, fileID1.getString(),
+ ownerPassword, userPassword, fileKey,
+ &ownerPasswordOk)) {
+ if (ownerPassword && !ownerPasswordOk) {
+ error(-1, "Incorrect owner password");
+ }
+ ret = gFalse;
+ } else {
+ error(-1, "Incorrect password");
+ }
+ } else {
+ error(-1, "Weird encryption info");
+ }
+ fileID1.free();
+ } else {
+ error(-1, "Unsupported version/revision (%d/%d) of Standard security handler",
+ encVersion, encRevision);
}
} else {
error(-1, "Weird encryption info");
}
- fileID1.free();
+ fileID.free();
+ permissions.free();
+ userKey.free();
+ ownerKey.free();
+ lengthObj.free();
+ revisionObj.free();
+ versionObj.free();
} else {
- error(-1, "Weird encryption info");
+ error(-1, "Unknown security handler '%s'",
+ filterObj.isName() ? filterObj.getName() : "???");
}
- ownerKey.free();
- userKey.free();
- permissions.free();
- fileID.free();
+ filterObj.free();
}
encrypt.free();
return ret;
}
#else
-GBool XRef::checkEncrypted(GString *userPassword) {
+GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) {
Object obj;
GBool encrypted;
trailerDict.dictLookup("Encrypt", &obj);
if ((encrypted = !obj.isNull())) {
- error(-1, "PDF file is encrypted and cannot be displayed");
- error(-1, "* Decryption support is currently not included in xpdf");
- error(-1, "* due to legal restrictions: the U.S.A. still has bogus");
- error(-1, "* export controls on cryptography software.");
+ error(-1, "PDF file is encrypted and this version of the Xpdf tools");
+ error(-1, "was built without decryption support.");
}
obj.free();
return encrypted;
}
#endif
-GBool XRef::okToPrint() {
+GBool XRef::okToPrint(GBool ignoreOwnerPW) {
#ifndef NO_DECRYPTION
- if (!(permFlags & permPrint)) {
+ if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permPrint)) {
return gFalse;
}
#endif
return gTrue;
}
-GBool XRef::okToChange() {
+GBool XRef::okToChange(GBool ignoreOwnerPW) {
#ifndef NO_DECRYPTION
- if (!(permFlags & permChange)) {
+ if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permChange)) {
return gFalse;
}
#endif
return gTrue;
}
-GBool XRef::okToCopy() {
+GBool XRef::okToCopy(GBool ignoreOwnerPW) {
#ifndef NO_DECRYPTION
- if (!(permFlags & permCopy)) {
+ if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permCopy)) {
return gFalse;
}
#endif
return gTrue;
}
-GBool XRef::okToAddNotes() {
+GBool XRef::okToAddNotes(GBool ignoreOwnerPW) {
#ifndef NO_DECRYPTION
- if (!(permFlags & permNotes)) {
+ if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permNotes)) {
return gFalse;
}
#endif
}
e = &entries[num];
- if (e->gen == gen && e->offset >= 0) {
+ if (e->gen == gen && e->offset != 0xffffffff) {
obj1.initNull();
- parser = new Parser(new Lexer(
- str->makeSubStream(start + e->offset, -1, &obj1)));
+ parser = new Parser(this,
+ new Lexer(this,
+ str->makeSubStream(start + e->offset, gFalse, 0, &obj1)));
parser->getObj(&obj1);
parser->getObj(&obj2);
parser->getObj(&obj3);
obj2.isInt() && obj2.getInt() == gen &&
obj3.isCmd("obj")) {
#ifndef NO_DECRYPTION
- parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, num, gen);
+ parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength,
+ num, gen);
#else
parser->getObj(obj);
#endif
return trailerDict.dictLookup("Info", obj);
}
-int XRef::getStreamEnd(int start) {
+// Added for the pdftex project.
+Object *XRef::getDocInfoNF(Object *obj) {
+ return trailerDict.dictLookupNF("Info", obj);
+}
+
+GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) {
int a, b, m;
if (streamEndsLen == 0 ||
- start > streamEnds[streamEndsLen - 1]) {
- return -1;
+ streamStart > streamEnds[streamEndsLen - 1]) {
+ return gFalse;
}
a = -1;
b = streamEndsLen - 1;
- // invariant: streamEnds[a] < start <= streamEnds[b]
+ // invariant: streamEnds[a] < streamStart <= streamEnds[b]
while (b - a > 1) {
m = (a + b) / 2;
- if (start <= streamEnds[m]) {
+ if (streamStart <= streamEnds[m]) {
b = m;
} else {
a = m;
}
}
- return streamEnds[b];
+ *streamEnd = streamEnds[b];
+ return gTrue;
+}
+
+Guint XRef::strToUnsigned(char *s) {
+ Guint x;
+ char *p;
+ int i;
+
+ x = 0;
+ for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) {
+ x = 10 * x + (*p - '0');
+ }
+ return x;
}
//
// XRef.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
//------------------------------------------------------------------------
struct XRefEntry {
- int offset;
+ Guint offset;
int gen;
GBool used;
};
public:
// Constructor. Read xref table from stream.
- XRef(BaseStream *str, GString *userPassword);
+ XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword);
// Destructor.
~XRef();
// Is xref table valid?
GBool isOk() { return ok; }
+ // Get the error code (if isOk() returns false).
+ int getErrorCode() { return errCode; }
+
// Is the file encrypted?
#ifndef NO_DECRYPTION
GBool isEncrypted() { return encrypted; }
#endif
// Check various permissions.
- GBool okToPrint();
- GBool okToChange();
- GBool okToCopy();
- GBool okToAddNotes();
+ GBool okToPrint(GBool ignoreOwnerPW = gFalse);
+ GBool okToChange(GBool ignoreOwnerPW = gFalse);
+ GBool okToCopy(GBool ignoreOwnerPW = gFalse);
+ GBool okToAddNotes(GBool ignoreOwnerPW = gFalse);
// Get catalog object.
Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); }
// Return the document's Info dictionary (if any).
Object *getDocInfo(Object *obj);
+ Object *getDocInfoNF(Object *obj);
// Return the number of objects in the xref table.
int getNumObjects() { return size; }
// Return the offset of the last xref table.
- int getLastXRefPos() { return lastXRefPos; }
+ Guint getLastXRefPos() { return lastXRefPos; }
// Return the catalog object reference.
int getRootNum() { return rootNum; }
int getRootGen() { return rootGen; }
// Get end position for a stream in a damaged file.
- // Returns -1 if unknown or file is not damaged.
- int getStreamEnd(int start);
+ // Returns false if unknown or file is not damaged.
+ GBool getStreamEnd(Guint streamStart, Guint *streamEnd);
private:
BaseStream *str; // input stream
- int start; // offset in file (to allow for garbage
+ Guint start; // offset in file (to allow for garbage
// at beginning of file)
XRefEntry *entries; // xref entries
int size; // size of <entries> array
int rootNum, rootGen; // catalog dict
GBool ok; // true if xref table is valid
+ int errCode; // error code (if <ok> is false)
Object trailerDict; // trailer dictionary
- int lastXRefPos; // offset of last xref table
- int *streamEnds; // 'endstream' positions - only used in
+ Guint lastXRefPos; // offset of last xref table
+ Guint *streamEnds; // 'endstream' positions - only used in
// damaged files
int streamEndsLen; // number of valid entries in streamEnds
#ifndef NO_DECRYPTION
GBool encrypted; // true if file is encrypted
+ int encVersion; // encryption algorithm
+ int encRevision; // security handler revision
+ int keyLength; // length of key, in bytes
int permFlags; // permission bits
Guchar fileKey[16]; // file decryption key
+ GBool ownerPasswordOk; // true if owner password is correct
#endif
- int readTrailer();
- GBool readXRef(int *pos);
+ Guint readTrailer();
+ GBool readXRef(Guint *pos);
GBool constructXRef();
- GBool checkEncrypted(GString *userPassword);
+ GBool checkEncrypted(GString *ownerPassword, GString *userPassword);
+ Guint strToUnsigned(char *s);
};
-//------------------------------------------------------------------------
-// The global xref table
-//------------------------------------------------------------------------
-
-extern XRef *xref;
-
#endif
//
// config.h
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#define CONFIG_H
//------------------------------------------------------------------------
-// general constants
+// version
//------------------------------------------------------------------------
// xpdf version
-#define xpdfVersion "0.92"
+
+#define xpdfVersion "1.01"
// supported PDF version
-#define supportedPDFVersionStr "1.3"
-#define supportedPDFVersionNum 1.3
+#define supportedPDFVersionStr "1.4"
+#define supportedPDFVersionNum 1.4
// copyright notice
-#define xpdfCopyright "Copyright 1996-2000 Derek B. Noonburg"
+#define xpdfCopyright "Copyright 1996-2002 Glyph & Cog, LLC"
+
+//------------------------------------------------------------------------
+// paper size
+//------------------------------------------------------------------------
// default paper size (in points) for PostScript output
#ifdef A4_PAPER
#define defPaperHeight 792
#endif
-// config file name
-#if defined(VMS)
-#define xpdfConfigFile "xpdfrc"
+//------------------------------------------------------------------------
+// config file (xpdfrc) path
+//------------------------------------------------------------------------
+
+// user config file name, relative to the user's home directory
+#if defined(VMS) || (defined(WIN32) && !defined(__CYGWIN32__))
+#define xpdfUserConfigFile "xpdfrc"
#else
-#define xpdfConfigFile ".xpdfrc"
+#define xpdfUserConfigFile ".xpdfrc"
+#endif
+
+// system config file name (set via the configure script)
+#ifdef SYSTEM_XPDFRC
+#define xpdfSysConfigFile SYSTEM_XPDFRC
+#else
+// under Windows, we get the directory with the executable and then
+// append this file name
+#define xpdfSysConfigFile "xpdfrc"
#endif
//------------------------------------------------------------------------
// default maximum size of color cube to allocate
#define defaultRGBCube 5
-// number of X server fonts to cache
-#define serverFontCacheSize 16
-
-// number of Type 1 (t1lib) fonts to cache
-#define t1FontCacheSize 32
+// number of fonts (combined t1lib, FreeType, X server) to cache
+#define xOutFontCacheSize 64
-// number of TrueType (FreeType) fonts to cache
-#define ttFontCacheSize 32
+// number of Type 3 fonts to cache
+#define xOutT3FontCacheSize 8
//------------------------------------------------------------------------
// popen
#define pclose _pclose
#endif
-#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(WIN32) || defined(__DJGPP__) || defined(__CYGWIN32) || defined(MACOS)
+#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(WIN32) || defined(__DJGPP__) || defined(__CYGWIN32__) || defined(MACOS)
#define POPEN_READ_MODE "rb"
#else
#define POPEN_READ_MODE "r"
//
// Miscellaneous file and directory name manipulation.
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
-#include "../../config.h"
+#include <aconf.h>
+
#ifdef WIN32
extern "C" {
# ifndef _MSC_VER
return statBuf.st_mtime;
#endif
}
-static char tmpbuf[128];
-char* mktmpname(char*ptr) {
-// used to be mktemp. This does remove the warnings, but
-// It's not exactly an improvement.
-#ifdef HAVE_LRAND48
- sprintf(tmpbuf, "/tmp/%08x%08x",lrand48(),lrand48());
-#else
-# ifdef HAVE_RAND
- sprintf(tmpbuf, "/tmp/%08x%08x",rand(),rand());
-# else
- sprintf(tmpbuf, "/tmp/%08x%08x",time(0),(unsigned int)tmpbuf);
-# endif
-#endif
- return tmpbuf;
-}
+
GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
-#if defined(VMS) || defined(__EMX__) || defined(WIN32) || defined(ACORN) || defined(MACOS)
+#if defined(WIN32)
+ //---------- Win32 ----------
+ char *s;
+ char buf[_MAX_PATH];
+ char *fp;
+
+ if (!(s = _tempnam(getenv("TEMP"), NULL))) {
+ return gFalse;
+ }
+ *name = new GString(s);
+ free(s);
+ if (ext) {
+ (*name)->append(ext);
+ }
+ if (!(*f = fopen((*name)->getCString(), mode))) {
+ delete (*name);
+ return gFalse;
+ }
+ return gTrue;
+#elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS)
//---------- non-Unix ----------
char *s;
// with this file name after the tmpnam call and before the fopen
// call. I will happily accept fixes to this function for non-Unix
// OSs.
- if (!(s = mktmpname(NULL))) {
+ if (!(s = tmpnam(NULL))) {
return gFalse;
}
*name = new GString(s);
return gTrue;
#else
//---------- Unix ----------
- char *s, *p;
+ char *s;
int fd;
if (ext) {
- if (!(s = mktmpname(NULL))) {
+#if HAVE_MKSTEMPS
+ if ((s = getenv("TMPDIR"))) {
+ *name = new GString(s);
+ } else {
+ *name = new GString("/tmp");
+ }
+ (*name)->append("/XXXXXX")->append(ext);
+ fd = mkstemps((*name)->getCString(), strlen(ext));
+#else
+ if (!(s = tmpnam(NULL))) {
return gFalse;
}
*name = new GString(s);
- s = (*name)->getCString();
- if ((p = strrchr(s, '.'))) {
- (*name)->del(p - s, (*name)->getLength() - (p - s));
- }
(*name)->append(ext);
fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
+#endif
} else {
#if HAVE_MKSTEMP
if ((s = getenv("TMPDIR"))) {
(*name)->append("/XXXXXX");
fd = mkstemp((*name)->getCString());
#else // HAVE_MKSTEMP
- if (!(s = mktmpname(NULL))) {
+ if (!(s = tmpnam(NULL))) {
return gFalse;
}
*name = new GString(s);
#endif
}
+GBool executeCommand(char *cmd) {
+#ifdef VMS
+ return system(cmd) ? gTrue : gFalse;
+#else
+ return system(cmd) ? gFalse : gTrue;
+#endif
+}
+
+char *getLine(char *buf, int size, FILE *f) {
+ int c, i;
+
+ i = 0;
+ while (i < size - 1) {
+ if ((c = fgetc(f)) == EOF) {
+ break;
+ }
+ buf[i++] = (char)c;
+ if (c == '\x0a') {
+ break;
+ }
+ if (c == '\x0d') {
+ c = fgetc(f);
+ if (c == '\x0a' && i < size - 1) {
+ buf[i++] = (char)c;
+ } else if (c != EOF) {
+ ungetc(c, f);
+ }
+ break;
+ }
+ }
+ buf[i] = '\0';
+ if (i == 0) {
+ return NULL;
+ }
+ return buf;
+}
+
//------------------------------------------------------------------------
// GDir and GDirEntry
//------------------------------------------------------------------------
-GDirEntry::GDirEntry(char *dirPath, char *name1, GBool doStat) {
+GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) {
#ifdef VMS
char *p;
#elif defined(WIN32)
GString *s;
#endif
- name = new GString(name1);
+ name = new GString(nameA);
dir = gFalse;
if (doStat) {
#ifdef VMS
- if (!strcmp(name1, "-") ||
- ((p = strrchr(name1, '.')) && !strncmp(p, ".DIR;", 5)))
+ if (!strcmp(nameA, "-") ||
+ ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5)))
dir = gTrue;
#elif defined(ACORN)
#else
s = new GString(dirPath);
- appendToPath(s, name1);
+ appendToPath(s, nameA);
#ifdef WIN32
fa = GetFileAttributes(s->getCString());
dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
delete name;
}
-GDir::GDir(char *name, GBool doStat1) {
+GDir::GDir(char *name, GBool doStatA) {
path = new GString(name);
- doStat = doStat1;
+ doStat = doStatA;
#if defined(WIN32)
GString *tmp;
//
// Miscellaneous file and directory name manipulation.
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
-#include "../../config.h"
#if defined(WIN32)
# include <sys/stat.h>
# ifdef FPTEX
// Make this path absolute by prepending current directory (if path is
// relative) or prepending user's directory (if path starts with '~').
-GString *makePathAbsolute(GString *path);
+extern GString *makePathAbsolute(GString *path);
// Get the modification time for <fileName>. Returns 0 if there is an
// error.
-time_t getModTime(char *fileName);
+extern time_t getModTime(char *fileName);
// Create a temporary file and open it for writing. If <ext> is not
// NULL, it will be used as the file name extension. Returns both the
// should be done to the returned file pointer; the file may be
// reopened later for reading, but not for writing. The <mode> string
// should be "w" or "wb". Returns true on success.
-GBool openTempFile(GString **name, FILE **f, char *mode, char *ext);
+extern GBool openTempFile(GString **name, FILE **f, char *mode, char *ext);
-/* create a temporary filename */
-char* mktmpname(char*ptr);
+// Execute <command>. Returns true on success.
+extern GBool executeCommand(char *cmd);
+
+// Just like fgets, but handles Unix, Mac, and/or DOS end-of-line
+// conventions.
+extern char *getLine(char *buf, int size, FILE *f);
//------------------------------------------------------------------------
// GDir and GDirEntry
class GDirEntry {
public:
- GDirEntry(char *dirPath, char *name1, GBool doStat);
+ GDirEntry(char *dirPath, char *nameA, GBool doStat);
~GDirEntry();
GString *getName() { return name; }
GBool isDir() { return dir; }
class GDir {
public:
- GDir(char *name, GBool doStat1 = gTrue);
+ GDir(char *name, GBool doStatA = gTrue);
~GDir();
GDirEntry *getNextEntry();
void rewind();
*
* Memory routines with out-of-memory checking.
*
- * Copyright 1996 Derek B. Noonburg
+ * Copyright 1996-2002 Glyph & Cog, LLC
*/
+#include <aconf.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#define gMemTrlSize (sizeof(long))
#if gmemTrlSize==8
-#define gMemDeadVal 0xdeadbeefdeadbeef
+#define gMemDeadVal 0xdeadbeefdeadbeefUL
#else
-#define gMemDeadVal 0xdeadbeef
+#define gMemDeadVal 0xdeadbeefUL
#endif
/* round data size so trailer will be aligned */
GMemHdr *hdr;
void *data;
int lst;
- long *trl, *p;
+ unsigned long *trl, *p;
if (size == 0)
return NULL;
}
hdr = (GMemHdr *)mem;
data = (void *)(mem + gMemHdrSize);
- trl = (long *)(mem + gMemHdrSize + size1);
+ trl = (unsigned long *)(mem + gMemHdrSize + size1);
hdr->size = size;
hdr->index = gMemIndex++;
lst = ((int)hdr >> gMemListShift) & gMemListMask;
hdr->next = gMemList[lst];
gMemList[lst] = hdr;
++gMemAlloc;
- for (p = (long *)data; p <= trl; ++p)
+ for (p = (unsigned long *)data; p <= trl; ++p)
*p = gMemDeadVal;
return data;
#else
GMemHdr *hdr;
GMemHdr *prevHdr, *q;
int lst;
- long *trl, *clr;
+ unsigned long *trl, *clr;
if (p) {
hdr = (GMemHdr *)((char *)p - gMemHdrSize);
gMemList[lst] = hdr->next;
--gMemAlloc;
size = gMemDataSize(hdr->size);
- trl = (long *)((char *)hdr + gMemHdrSize + size);
+ trl = (unsigned long *)((char *)hdr + gMemHdrSize + size);
if (*trl != gMemDeadVal) {
fprintf(stderr, "Overwrite past end of block %d at address %p\n",
hdr->index, p);
}
- for (clr = (long *)hdr; clr <= trl; ++clr)
+ for (clr = (unsigned long *)hdr; clr <= trl; ++clr)
*clr = gMemDeadVal;
free(hdr);
} else {
*
* Memory routines with out-of-memory checking.
*
- * Copyright 1996 Derek B. Noonburg
+ * Copyright 1996-2002 Glyph & Cog, LLC
*/
#ifndef GMEM_H
#define GMEM_H
#include <stdio.h>
-#include "../../config.h"
#ifdef __cplusplus
extern "C" {
*
* Some useful simple types.
*
- * Copyright 1996 Derek B. Noonburg
+ * Copyright 1996-2002 Glyph & Cog, LLC
*/
#ifndef GTYPES_H