From: kramm Date: Mon, 27 May 2002 15:50:04 +0000 (+0000) Subject: upgrade to xpdf 1.01. X-Git-Tag: xpdf-1-01~1 X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=commitdiff_plain;h=50dd339d3d6262763616efe8d7ee415ab19befb9 upgrade to xpdf 1.01. --- diff --git a/pdf2swf/xpdf/Array.cc b/pdf2swf/xpdf/Array.cc index 9681b68..fbdde49 100644 --- a/pdf2swf/xpdf/Array.cc +++ b/pdf2swf/xpdf/Array.cc @@ -2,7 +2,7 @@ // // Array.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include "gmem.h" #include "Object.h" @@ -19,7 +20,8 @@ // Array //------------------------------------------------------------------------ -Array::Array() { +Array::Array(XRef *xrefA) { + xref = xrefA; elems = NULL; size = length = 0; ref = 1; @@ -43,7 +45,7 @@ void Array::add(Object *elem) { } 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) { diff --git a/pdf2swf/xpdf/Array.h b/pdf2swf/xpdf/Array.h index ecf2eea..a118f68 100644 --- a/pdf2swf/xpdf/Array.h +++ b/pdf2swf/xpdf/Array.h @@ -2,7 +2,7 @@ // // Array.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -15,6 +15,8 @@ #include "Object.h" +class XRef; + //------------------------------------------------------------------------ // Array //------------------------------------------------------------------------ @@ -23,7 +25,7 @@ class Array { public: // Constructor. - Array(); + Array(XRef *xrefA); // Destructor. ~Array(); @@ -44,6 +46,7 @@ public: private: + XRef *xref; // the xref table for this PDF file Object *elems; // array of elements int size; // size of array int length; // number of elements in array diff --git a/pdf2swf/xpdf/Catalog.cc b/pdf2swf/xpdf/Catalog.cc index 815cca3..1212e2e 100644 --- a/pdf2swf/xpdf/Catalog.cc +++ b/pdf2swf/xpdf/Catalog.cc @@ -2,7 +2,7 @@ // // Catalog.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,9 +10,11 @@ #pragma implementation #endif +#include #include #include "gmem.h" #include "Object.h" +#include "XRef.h" #include "Array.h" #include "Dict.h" #include "Page.h" @@ -24,24 +26,27 @@ // 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()) { @@ -64,25 +69,24 @@ Catalog::Catalog(Object *catDict) { 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(); } @@ -90,6 +94,13 @@ Catalog::Catalog(Object *catDict) { } obj.free(); + // get the metadata stream + catDict.dictLookup("Metadata", &metadata); + + // get the structure tree root + catDict.dictLookup("StructTreeRoot", &structTreeRoot); + + catDict.free(); return; err3: @@ -97,6 +108,7 @@ Catalog::Catalog(Object *catDict) { err2: pagesDict.free(); err1: + catDict.free(); dests.initNull(); nameTree.initNull(); ok = gFalse; @@ -119,9 +131,36 @@ Catalog::~Catalog() { 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; @@ -140,7 +179,7 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { 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; @@ -166,7 +205,8 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { // 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)", @@ -225,10 +265,10 @@ LinkDest *Catalog::findDest(GString *name) { // 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(); diff --git a/pdf2swf/xpdf/Catalog.h b/pdf2swf/xpdf/Catalog.h index b0f3143..afad803 100644 --- a/pdf2swf/xpdf/Catalog.h +++ b/pdf2swf/xpdf/Catalog.h @@ -2,7 +2,7 @@ // // Catalog.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -13,6 +13,7 @@ #pragma interface #endif +class XRef; class Object; class Page; class PageAttrs; @@ -27,7 +28,7 @@ class Catalog { public: // Constructor. - Catalog(Object *catDict); + Catalog(XRef *xrefA, GBool printCommands = gFalse); // Destructor. ~Catalog(); @@ -47,6 +48,13 @@ public: // 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); @@ -57,6 +65,7 @@ public: 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 @@ -64,9 +73,12 @@ private: 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); }; diff --git a/pdf2swf/xpdf/CompactFontInfo.h b/pdf2swf/xpdf/CompactFontInfo.h deleted file mode 100644 index c642660..0000000 --- a/pdf2swf/xpdf/CompactFontInfo.h +++ /dev/null @@ -1,464 +0,0 @@ -//======================================================================== -// -// 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 diff --git a/pdf2swf/xpdf/Decrypt.cc b/pdf2swf/xpdf/Decrypt.cc index ae9b732..8de4091 100644 --- a/pdf2swf/xpdf/Decrypt.cc +++ b/pdf2swf/xpdf/Decrypt.cc @@ -2,7 +2,7 @@ // // Decrypt.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include "gmem.h" #include "Decrypt.h" @@ -28,42 +29,96 @@ static Guchar passwordPad[32] = { // 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 @@ -86,16 +141,41 @@ GBool Decrypt::makeFileKey(GString *ownerKey, GString *userKey, 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; } @@ -136,6 +216,7 @@ static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) { // 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; diff --git a/pdf2swf/xpdf/Decrypt.h b/pdf2swf/xpdf/Decrypt.h index 3ea4374..52afb2f 100644 --- a/pdf2swf/xpdf/Decrypt.h +++ b/pdf2swf/xpdf/Decrypt.h @@ -2,7 +2,7 @@ // // Decrypt.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -24,7 +24,7 @@ class Decrypt { 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(); @@ -32,16 +32,26 @@ public: // Decrypt one byte. Guchar decryptByte(Guchar c); - // Generate a file key. The buffer must have space for - // at least 16 bytes. Checks user key and returns gTrue if okay. - // may be NULL. - static GBool makeFileKey(GString *ownerKey, GString *userKey, + // Generate a file key. The buffer must have space for at + // least 16 bytes. Checks and then + // and returns true if either is correct. Sets 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; }; diff --git a/pdf2swf/xpdf/Dict.cc b/pdf2swf/xpdf/Dict.cc index 94ca386..5eb077e 100644 --- a/pdf2swf/xpdf/Dict.cc +++ b/pdf2swf/xpdf/Dict.cc @@ -2,7 +2,7 @@ // // Dict.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include #include "gmem.h" @@ -21,7 +22,8 @@ // Dict //------------------------------------------------------------------------ -Dict::Dict() { +Dict::Dict(XRef *xrefA) { + xref = xrefA; entries = NULL; size = length = 0; ref = 1; @@ -66,7 +68,7 @@ GBool Dict::is(char *type) { 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) { @@ -80,26 +82,9 @@ char *Dict::getKey(int i) { } 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 array int length; // number of entries in dictionary int ref; // reference count DictEntry *find(char *key); - -public: - void dumpEntries(); - }; #endif diff --git a/pdf2swf/xpdf/Error.cc b/pdf2swf/xpdf/Error.cc index 485a7cb..3eae5c9 100644 --- a/pdf2swf/xpdf/Error.cc +++ b/pdf2swf/xpdf/Error.cc @@ -2,7 +2,7 @@ // // Error.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,41 +10,28 @@ #pragma implementation #endif +#include #include #include #include -#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); } diff --git a/pdf2swf/xpdf/Error.h b/pdf2swf/xpdf/Error.h index f651678..77801c5 100644 --- a/pdf2swf/xpdf/Error.h +++ b/pdf2swf/xpdf/Error.h @@ -2,7 +2,7 @@ // // Error.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -16,11 +16,6 @@ #include #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 diff --git a/pdf2swf/xpdf/FontEncoding.cc b/pdf2swf/xpdf/FontEncoding.cc deleted file mode 100644 index bf12577..0000000 --- a/pdf2swf/xpdf/FontEncoding.cc +++ /dev/null @@ -1,143 +0,0 @@ -//======================================================================== -// -// FontEncoding.cc -// -// Copyright 1999 Derek B. Noonburg -// -//======================================================================== - -#ifdef __GNUC__ -#pragma implementation -#endif - -#include -#include -#include -#include -#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; -} diff --git a/pdf2swf/xpdf/FontEncoding.h b/pdf2swf/xpdf/FontEncoding.h deleted file mode 100644 index 10e6fce..0000000 --- a/pdf2swf/xpdf/FontEncoding.h +++ /dev/null @@ -1,64 +0,0 @@ -//======================================================================== -// -// 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 . - char *getCharName(int code) { return code>=size?0:encoding[code]; } - - // Return the code associated with . - 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 diff --git a/pdf2swf/xpdf/FontFile.cc b/pdf2swf/xpdf/FontFile.cc index 777b56a..ae58547 100644 --- a/pdf2swf/xpdf/FontFile.cc +++ b/pdf2swf/xpdf/FontFile.cc @@ -2,7 +2,7 @@ // // FontFile.cc // -// Copyright 1999 Derek B. Noonburg +// Copyright 1999-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include #include @@ -17,18 +18,12 @@ #include #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" //------------------------------------------------------------------------ @@ -58,34 +53,46 @@ FontFile::~FontFile() { 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) ; @@ -102,7 +109,7 @@ Type1FontFile::Type1FontFile(char *file, int len) { ++p; for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ; *p2 = '\0'; - encoding->addChar(code, copyString(p)); + encoding[code] = copyString(p); } } } @@ -115,6 +122,7 @@ Type1FontFile::Type1FontFile(char *file, int len) { line = line1; } //~ check for getinterval/putinterval junk + haveEncoding = gTrue; } else { line = nextLine(line, file + len); @@ -123,77 +131,143 @@ Type1FontFile::Type1FontFile(char *file, int 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 @@ -203,445 +277,130 @@ Type1CFontFile::Type1CFontFile(char *file, int len) { } 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", @@ -650,52 +409,16 @@ void Type1CFontConverter::convert() { 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 "); @@ -706,54 +429,55 @@ void Type1CFontConverter::convert() { 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"); @@ -762,128 +486,31 @@ void Type1CFontConverter::convert() { 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 } @@ -891,21 +518,16 @@ void Type1CFontConverter::convert() { } // 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"); @@ -915,719 +537,3145 @@ void Type1CFontConverter::convert() { 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); } diff --git a/pdf2swf/xpdf/FontFile.h b/pdf2swf/xpdf/FontFile.h index ec625ef..d5de25c 100644 --- a/pdf2swf/xpdf/FontFile.h +++ b/pdf2swf/xpdf/FontFile.h @@ -2,7 +2,7 @@ // // FontFile.h // -// Copyright 1999 Derek B. Noonburg +// Copyright 1999-2002 Glyph & Cog, LLC // //======================================================================== @@ -16,7 +16,9 @@ #include #include "gtypes.h" #include "GString.h" -#include "FontEncoding.h" +#include "CharTypes.h" + +class CharCodeToUnicode; //------------------------------------------------------------------------ // FontFile @@ -32,10 +34,9 @@ public: // 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 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; }; //------------------------------------------------------------------------ @@ -48,59 +49,79 @@ public: 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 @@ -114,4 +135,81 @@ private: 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 diff --git a/pdf2swf/xpdf/FontInfo.h b/pdf2swf/xpdf/FontInfo.h deleted file mode 100644 index ed768d6..0000000 --- a/pdf2swf/xpdf/FontInfo.h +++ /dev/null @@ -1,2068 +0,0 @@ -//======================================================================== -// -// 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 diff --git a/pdf2swf/xpdf/FormWidget.cc b/pdf2swf/xpdf/FormWidget.cc deleted file mode 100644 index 76428d0..0000000 --- a/pdf2swf/xpdf/FormWidget.cc +++ /dev/null @@ -1,129 +0,0 @@ -//======================================================================== -// -// 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); -} diff --git a/pdf2swf/xpdf/FormWidget.h b/pdf2swf/xpdf/FormWidget.h deleted file mode 100644 index d746083..0000000 --- a/pdf2swf/xpdf/FormWidget.h +++ /dev/null @@ -1,65 +0,0 @@ -//======================================================================== -// -// 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 diff --git a/pdf2swf/xpdf/GString.cc b/pdf2swf/xpdf/GString.cc index 7b8f271..3bf626a 100644 --- a/pdf2swf/xpdf/GString.cc +++ b/pdf2swf/xpdf/GString.cc @@ -4,7 +4,7 @@ // // Simple variable-length string type. // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -12,6 +12,7 @@ #pragma implementation #endif +#include #include #include #include @@ -45,18 +46,25 @@ GString::GString() { 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'; } @@ -137,10 +145,10 @@ GString *GString::append(const char *str) { 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; } @@ -180,14 +188,14 @@ GString *GString::insert(int i, const char *str) { 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; } diff --git a/pdf2swf/xpdf/GString.h b/pdf2swf/xpdf/GString.h index 4c3b95f..93796cb 100644 --- a/pdf2swf/xpdf/GString.h +++ b/pdf2swf/xpdf/GString.h @@ -4,7 +4,7 @@ // // Simple variable-length string type. // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -24,11 +24,14 @@ public: GString(); // Create a string from a C string. - GString(const char *s1); + GString(const char *sA); - // Create a string from chars at . This string + // Create a string from chars at . This string // can contain null characters. - GString (const char *s1, int length1); + GString(const char *sA, int lengthA); + + // Create a string from chars at in . + GString(GString *str, int idx, int lengthA); // Copy a string. GString(GString *str); @@ -62,13 +65,13 @@ public: 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); @@ -81,8 +84,8 @@ public: // 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: diff --git a/pdf2swf/xpdf/Gfx.cc b/pdf2swf/xpdf/Gfx.cc index 0096d4b..0b00f91 100644 --- a/pdf2swf/xpdf/Gfx.cc +++ b/pdf2swf/xpdf/Gfx.cc @@ -2,7 +2,7 @@ // // Gfx.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,11 +10,13 @@ #pragma implementation #endif +#include #include #include #include #include #include "gmem.h" +#include "CharTypes.h" #include "Object.h" #include "Array.h" #include "Dict.h" @@ -24,10 +26,31 @@ #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 //------------------------------------------------------------------------ @@ -190,14 +213,10 @@ Operator Gfx::opTab[] = { #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) { @@ -206,7 +225,7 @@ GfxResources::GfxResources(Dict *resDict, GfxResources *next) { fonts = NULL; resDict->lookup("Font", &obj1); if (obj1.isDict()) { - fonts = new GfxFontDict(obj1.getDict()); + fonts = new GfxFontDict(xref, obj1.getDict()); } obj1.free(); @@ -219,6 +238,9 @@ GfxResources::GfxResources(Dict *resDict, GfxResources *next) { // get pattern dictionary resDict->lookup("Pattern", &patternDict); + // get shading dictionary + resDict->lookup("Shading", &shadingDict); + // get graphics state parameter dictionary resDict->lookup("ExtGState", &gStateDict); @@ -230,7 +252,7 @@ GfxResources::GfxResources(Dict *resDict, GfxResources *next) { gStateDict.initNull(); } - this->next = next; + next = nextA; } GfxResources::~GfxResources() { @@ -240,6 +262,7 @@ GfxResources::~GfxResources() { xObjDict.free(); colorSpaceDict.free(); patternDict.free(); + shadingDict.free(); gStateDict.free(); } @@ -318,6 +341,25 @@ GfxPattern *GfxResources::lookupPattern(char *name) { 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; @@ -337,18 +379,21 @@ GBool GfxResources::lookupGState(char *name, Object *obj) { // 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; @@ -361,31 +406,65 @@ Gfx::Gfx(OutputDev *out1, int pageNum, Dict *resDict, // 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) { @@ -406,7 +485,7 @@ 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; @@ -415,11 +494,11 @@ void Gfx::display(Object *obj, GBool topLevel) { 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()) { @@ -433,6 +512,7 @@ void Gfx::go(GBool topLevel) { args[i].print(stdout); } printf("\n"); + fflush(stdout); } execOp(&obj, args, numArgs); obj.free(); @@ -441,9 +521,9 @@ void Gfx::go(GBool topLevel) { numArgs = 0; // periodically update display - if (++numCmds == 200) { + if (++updateLevel >= 20000) { out->dump(); - numCmds = 0; + updateLevel = 0; } // got an argument - save it @@ -457,6 +537,7 @@ void Gfx::go(GBool topLevel) { printf("throwing away arg: "); obj.print(stdout); printf("\n"); + fflush(stdout); } obj.free(); } @@ -476,20 +557,16 @@ void Gfx::go(GBool topLevel) { 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) { @@ -583,12 +660,6 @@ void Gfx::opSave(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) { @@ -768,7 +839,7 @@ void Gfx::opSetFillColorSpace(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; @@ -794,7 +865,7 @@ void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) { 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; @@ -970,7 +1041,7 @@ void Gfx::opRectangle(Object args[], int numArgs) { } void Gfx::opClosePath(Object args[], int numArgs) { - if (!state->isPath()) { + if (!state->isCurPt()) { error(getPos(), "No current point in closepath"); return; } @@ -1103,23 +1174,26 @@ void Gfx::opCloseEOFillStroke(Object args[], int numArgs) { 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(); @@ -1160,42 +1234,14 @@ void Gfx::doPatternFill(GBool eoFill) { 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); @@ -1211,6 +1257,7 @@ void Gfx::doPatternFill(GBool eoFill) { out->updateFillColor(state); // clip to current path + state->clip(); if (eoFill) { out->eoClip(state); } else { @@ -1218,6 +1265,47 @@ void Gfx::doPatternFill(GBool eoFill) { } 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 (?) @@ -1246,12 +1334,485 @@ void Gfx::doPatternFill(GBool eoFill) { 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(); @@ -1300,9 +1861,11 @@ void Gfx::opSetFont(Object args[], int numArgs) { 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; @@ -1330,6 +1893,7 @@ void Gfx::opSetWordSpacing(Object args[], int numArgs) { void Gfx::opSetHorizScaling(Object args[], int numArgs) { state->setHorizScaling(args[0].getNum()); out->updateHorizScaling(state); + fontChanged = gTrue; } //------------------------------------------------------------------------ @@ -1422,17 +1986,23 @@ void Gfx::opMoveSetShowText(Object args[], int numArgs) { 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()); @@ -1445,188 +2015,174 @@ void Gfx::opShowSpaceText(Object args[], int numArgs) { 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(); } //------------------------------------------------------------------------ @@ -1634,7 +2190,7 @@ int Gfx::getNextChar16(GfxFontEncoding16 *enc, Guchar *p, int *c16) { //------------------------------------------------------------------------ void Gfx::opXObject(Object args[], int numArgs) { - Object obj1, obj2, refObj; + Object obj1, obj2, obj3, refObj; #if OPI_SUPPORT Object opiDict; #endif @@ -1660,6 +2216,10 @@ void Gfx::opXObject(Object args[], int numArgs) { 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 { @@ -1677,13 +2237,17 @@ void Gfx::opXObject(Object args[], int numArgs) { 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(); @@ -1791,11 +2355,30 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { 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; @@ -1856,7 +2439,7 @@ void Gfx::doForm(Object *str) { // 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); @@ -1864,19 +2447,22 @@ void Gfx::doForm(Object *str) { 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(); @@ -1890,7 +2476,7 @@ void Gfx::doWidgetForm(Object *str, double xMin, double yMin, } bboxObj.free(); - // get matrix + // get the form matrix dict->lookup("Matrix", &matrixObj); if (matrixObj.isArray()) { for (i = 0; i < 6; ++i) { @@ -1905,20 +2491,68 @@ void Gfx::doWidgetForm(Object *str, double xMin, double yMin, } 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); @@ -1930,11 +2564,10 @@ void Gfx::doWidgetForm(Object *str, double xMin, double yMin, 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); @@ -1961,6 +2594,7 @@ void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) { state->lineTo(bbox[2], bbox[3]); state->lineTo(bbox[0], bbox[3]); state->closePath(); + state->clip(); out->clip(state); state->clearPath(); @@ -1980,11 +2614,21 @@ void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) { 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; } //------------------------------------------------------------------------ @@ -2020,25 +2664,30 @@ Stream *Gfx::buildImageStream() { 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 @@ -2061,11 +2710,13 @@ void Gfx::opEndImage(Object args[], int numArgs) { //------------------------------------------------------------------------ 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()); } //------------------------------------------------------------------------ @@ -2091,6 +2742,7 @@ void Gfx::opBeginMarkedContent(Object args[], int numArgs) { if (numArgs == 2) args[2].print(stdout); printf("\n"); + fflush(stdout); } } @@ -2103,5 +2755,6 @@ void Gfx::opMarkPoint(Object args[], int numArgs) { if (numArgs == 2) args[2].print(stdout); printf("\n"); + fflush(stdout); } } diff --git a/pdf2swf/xpdf/Gfx.h b/pdf2swf/xpdf/Gfx.h index 34d8f99..b4da531 100644 --- a/pdf2swf/xpdf/Gfx.h +++ b/pdf2swf/xpdf/Gfx.h @@ -2,7 +2,7 @@ // // Gfx.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -16,6 +16,7 @@ #include "gtypes.h" class GString; +class XRef; class Array; class Stream; class Parser; @@ -23,10 +24,13 @@ class Dict; class OutputDev; class GfxFontDict; class GfxFont; -struct GfxFontEncoding16; class GfxPattern; +class GfxShading; +class GfxAxialShading; +class GfxRadialShading; class GfxState; class Gfx; +struct PDFRectangle; //------------------------------------------------------------------------ // Gfx @@ -62,7 +66,7 @@ struct Operator { class GfxResources { public: - GfxResources(Dict *resDict, GfxResources *next); + GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA); ~GfxResources(); GfxFont *lookupFont(char *name); @@ -70,6 +74,7 @@ public: 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; } @@ -80,6 +85,7 @@ private: Object xObjDict; Object colorSpaceDict; Object patternDict; + Object shadingDict; Object gStateDict; GfxResources *next; }; @@ -88,24 +94,35 @@ class Gfx { 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 @@ -170,8 +187,10 @@ private: 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 @@ -203,7 +222,6 @@ private: 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); diff --git a/pdf2swf/xpdf/GfxFont.cc b/pdf2swf/xpdf/GfxFont.cc index 16b311b..8dcd8e7 100644 --- a/pdf2swf/xpdf/GfxFont.cc +++ b/pdf2swf/xpdf/GfxFont.cc @@ -2,7 +2,7 @@ // // GfxFont.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,513 +10,298 @@ #pragma implementation #endif -#include -#include +#include #include +#include #include #include -#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; } } @@ -525,20 +310,21 @@ char *GfxFont::readExtFontFile(int *len) { 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; @@ -546,7 +332,7 @@ char *GfxFont::readEmbFontFile(int *len) { 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(); @@ -575,410 +361,883 @@ char *GfxFont::readEmbFontFile(int *len) { 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; @@ -986,12 +1245,16 @@ GfxFontDict::GfxFontDict(Dict *fontDict) { 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(); @@ -1002,8 +1265,11 @@ GfxFontDict::GfxFontDict(Dict *fontDict) { 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); } @@ -1011,8 +1277,9 @@ GfxFont *GfxFontDict::lookup(char *tag) { 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; } diff --git a/pdf2swf/xpdf/GfxFont.h b/pdf2swf/xpdf/GfxFont.h index 0435d90..c67ac29 100644 --- a/pdf2swf/xpdf/GfxFont.h +++ b/pdf2swf/xpdf/GfxFont.h @@ -2,7 +2,7 @@ // // GfxFont.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -16,63 +16,56 @@ #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 .. +struct GfxFontCIDWidthExcep { + CID first; // this record applies to + CID last; // CIDs .. double width; // char width }; -struct GfxFontWidthExcepV { - int first; // this record applies to - int last; // chars .. +struct GfxFontCIDWidthExcepV { + CID first; // this record applies to + CID last; // CIDs .. 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 }; //------------------------------------------------------------------------ @@ -85,41 +78,33 @@ struct GfxFontWidths16 { #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. @@ -128,8 +113,7 @@ public: // 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. @@ -142,73 +126,147 @@ public: 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 of bytes, returning the + // char , its Unicode mapping , its displacement vector + // (, ), and its origin offset vector (, ). + // is the number of entries available in , and 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 . - char *getCharName(int code) { return encoding->getCharName(code); } + char *getCharName(int code) { return enc[code]; } - // Return the code associated with . - 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 . 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 (-). + 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; }; //------------------------------------------------------------------------ @@ -219,7 +277,7 @@ class GfxFontDict { public: // Build the font dictionary, given the PDF font dictionary. - GfxFontDict(Dict *fontDict); + GfxFontDict(XRef *xref, Dict *fontDict); // Destructor. ~GfxFontDict(); diff --git a/pdf2swf/xpdf/GfxState.cc b/pdf2swf/xpdf/GfxState.cc index b7afdae..1668c24 100644 --- a/pdf2swf/xpdf/GfxState.cc +++ b/pdf2swf/xpdf/GfxState.cc @@ -2,7 +2,7 @@ // // GfxState.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include #include // for memcpy() @@ -17,6 +18,7 @@ #include "Error.h" #include "Object.h" #include "Array.h" +#include "Page.h" #include "GfxState.h" //------------------------------------------------------------------------ @@ -261,9 +263,9 @@ GfxCalRGBColorSpace::GfxCalRGBColorSpace() { 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() { @@ -284,7 +286,7 @@ GfxColorSpace *GfxCalRGBColorSpace::copy() { cs->gammaG = gammaG; cs->gammaB = gammaB; for (i = 0; i < 9; ++i) { - cs->m[i] = m[i]; + cs->mat[i] = mat[i]; } return cs; } @@ -344,7 +346,7 @@ GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) { 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(); } } @@ -406,9 +408,22 @@ void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) { } 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) { @@ -609,11 +624,11 @@ void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, // 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; } @@ -636,19 +651,19 @@ GfxColorSpace *GfxICCBasedColorSpace::copy() { 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); @@ -664,19 +679,19 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) { 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"); @@ -686,10 +701,10 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) { } } 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(); @@ -730,12 +745,12 @@ void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow, // 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() { @@ -754,8 +769,8 @@ GfxColorSpace *GfxIndexedColorSpace::copy() { GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) { GfxIndexedColorSpace *cs; - GfxColorSpace *base; - int indexHigh; + GfxColorSpace *baseA; + int indexHighA; Object obj1; int x; char *s; @@ -766,7 +781,7 @@ GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) { 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; } @@ -775,14 +790,14 @@ GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) { 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)"); @@ -793,12 +808,12 @@ GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) { } 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++; } @@ -868,12 +883,12 @@ void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow, // 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() { @@ -889,9 +904,9 @@ GfxColorSpace *GfxSeparationColorSpace::copy() { //~ 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) { @@ -902,28 +917,26 @@ GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) { 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: @@ -955,12 +968,12 @@ void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { // 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() { @@ -987,10 +1000,10 @@ GfxColorSpace *GfxDeviceNColorSpace::copy() { //~ 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; @@ -1002,40 +1015,39 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) { 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(); @@ -1068,8 +1080,8 @@ void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { // GfxPatternColorSpace //------------------------------------------------------------------------ -GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *under) { - this->under = under; +GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) { + under = underA; } GfxPatternColorSpace::~GfxPatternColorSpace() { @@ -1085,24 +1097,24 @@ GfxColorSpace *GfxPatternColorSpace::copy() { 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; } @@ -1123,8 +1135,8 @@ void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { // Pattern //------------------------------------------------------------------------ -GfxPattern::GfxPattern(int type) { - this->type = type; +GfxPattern::GfxPattern(int typeA) { + type = typeA; } GfxPattern::~GfxPattern() { @@ -1238,480 +1250,375 @@ GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat): } //------------------------------------------------------------------------ -// 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()) { @@ -1740,18 +1647,6 @@ GfxImageColorMap::GfxImageColorMap(int bits, Object *decode, 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. @@ -1784,8 +1679,8 @@ GfxImageColorMap::GfxImageColorMap(int bits, Object *decode, 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]; } @@ -2010,19 +1905,34 @@ void GfxPath::curveTo(double x1, double y1, double x2, double y2, 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; @@ -2096,6 +2006,11 @@ GfxState::GfxState(double dpi, double px1a, double py1a, curX = curY = 0; lineX = lineY = 0; + clipXMin = 0; + clipYMin = 0; + clipXMax = pageWidth; + clipYMax = pageHeight; + saved = NULL; } @@ -2113,7 +2028,10 @@ GfxState::~GfxState() { delete strokePattern; } gfree(lineDash); - delete path; + if (path) { + // this gets set to NULL by restore() + delete path; + } if (saved) { delete saved; } @@ -2138,10 +2056,70 @@ GfxState::GfxState(GfxState *state) { 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; @@ -2170,12 +2148,23 @@ void GfxState::getFontTransMat(double *m11, double *m12, 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, @@ -2184,6 +2173,7 @@ 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; @@ -2191,6 +2181,15 @@ void GfxState::concatCTM(double a, double b, double c, 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) { @@ -2234,12 +2233,45 @@ void GfxState::clearPath() { 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) { @@ -2250,6 +2282,11 @@ 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; @@ -2263,10 +2300,21 @@ GfxState *GfxState::restore() { 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; } diff --git a/pdf2swf/xpdf/GfxState.h b/pdf2swf/xpdf/GfxState.h index 2056c4d..b1f6f28 100644 --- a/pdf2swf/xpdf/GfxState.h +++ b/pdf2swf/xpdf/GfxState.h @@ -2,7 +2,7 @@ // // GfxState.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -15,16 +15,17 @@ #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]; @@ -201,14 +202,14 @@ public: 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 }; //------------------------------------------------------------------------ @@ -283,8 +284,8 @@ private: 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; } @@ -320,7 +321,7 @@ private: 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; } @@ -356,8 +357,8 @@ private: 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; } @@ -424,7 +425,7 @@ private: class GfxPatternColorSpace: public GfxColorSpace { public: - GfxPatternColorSpace(GfxColorSpace *under); + GfxPatternColorSpace(GfxColorSpace *underA); virtual ~GfxPatternColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csPattern; } @@ -454,7 +455,7 @@ private: class GfxPattern { public: - GfxPattern(int type); + GfxPattern(int typeA); virtual ~GfxPattern(); static GfxPattern *parse(Object *obj); @@ -504,94 +505,100 @@ private: }; //------------------------------------------------------------------------ -// 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; }; //------------------------------------------------------------------------ @@ -602,7 +609,7 @@ class GfxImageColorMap { public: // Constructor. - GfxImageColorMap(int bits, Object *decode, GfxColorSpace *colorSpace); + GfxImageColorMap(int bitsA, Object *decode, GfxColorSpace *colorSpaceA); // Destructor. ~GfxImageColorMap(); @@ -728,7 +735,7 @@ public: double x3, double y3); // Close the last subpath. - void close() { subpaths[n-1]->close(); } + void close(); private: @@ -750,10 +757,10 @@ class GfxState { public: // Construct a default GfxState, for a device with resolution , - // page box (,)-(,), page rotation , and - // coordinate system specified by . - GfxState(double dpi, double px1a, double py1a, - double px2a, double py2a, int rotate, GBool upsideDown); + // page box , page rotation , and coordinate system + // specified by . + GfxState(double dpi, PDFRectangle *pageBox, int rotate, + GBool upsideDown); // Destructor. ~GfxState(); @@ -771,6 +778,10 @@ public: 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) @@ -804,6 +815,9 @@ public: 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; } @@ -848,9 +862,9 @@ public: 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; @@ -861,12 +875,12 @@ public: { 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) @@ -880,11 +894,14 @@ public: { 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(); @@ -929,6 +946,9 @@ private: 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); diff --git a/pdf2swf/xpdf/Lexer.cc b/pdf2swf/xpdf/Lexer.cc index 4ca8cfe..d037469 100644 --- a/pdf2swf/xpdf/Lexer.cc +++ b/pdf2swf/xpdf/Lexer.cc @@ -2,7 +2,7 @@ // // Lexer.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include #include @@ -44,22 +45,22 @@ static char specialChars[256] = { // 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 { @@ -204,11 +205,15 @@ Object *Lexer::getObj(Object *obj) { case '(': ++numParen; + c2 = c; break; case ')': - if (--numParen == 0) + if (--numParen == 0) { done = gTrue; + } else { + c2 = c; + } break; case '\\': diff --git a/pdf2swf/xpdf/Lexer.h b/pdf2swf/xpdf/Lexer.h index 70144b8..8a01ab2 100644 --- a/pdf2swf/xpdf/Lexer.h +++ b/pdf2swf/xpdf/Lexer.h @@ -2,7 +2,7 @@ // // Lexer.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -16,6 +16,8 @@ #include "Object.h" #include "Stream.h" +class XRef; + #define tokBufSize 128 // size of token buffer //------------------------------------------------------------------------ @@ -27,11 +29,11 @@ public: // 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(); @@ -49,13 +51,14 @@ public: 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: diff --git a/pdf2swf/xpdf/Link.cc b/pdf2swf/xpdf/Link.cc index 154a577..af64c8b 100644 --- a/pdf2swf/xpdf/Link.cc +++ b/pdf2swf/xpdf/Link.cc @@ -2,7 +2,7 @@ // // Link.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include #include "gmem.h" @@ -28,32 +29,27 @@ static GString *getFileSpecName(Object *fileSpecObj); // 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); @@ -221,7 +217,7 @@ LinkGoTo::LinkGoTo(Object *destObj) { // destination dictionary } else if (destObj->isArray()) { - dest = new LinkDest(destObj->getArray(), gTrue); + dest = new LinkDest(destObj->getArray()); if (!dest->isOk()) { delete dest; dest = NULL; @@ -259,7 +255,7 @@ LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) { // destination dictionary } else if (destObj->isArray()) { - dest = new LinkDest(destObj->getArray(), gFalse); + dest = new LinkDest(destObj->getArray()); if (!dest->isOk()) { delete dest; dest = NULL; @@ -385,8 +381,8 @@ LinkNamed::~LinkNamed() { // LinkUnknown //------------------------------------------------------------------------ -LinkUnknown::LinkUnknown(char *action1) { - action = new GString(action1); +LinkUnknown::LinkUnknown(char *actionA) { + action = new GString(actionA); } LinkUnknown::~LinkUnknown() { @@ -446,13 +442,16 @@ Link::Link(Dict *dict, GString *baseURI) { } // 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(); @@ -579,7 +578,7 @@ Links::~Links() { 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(); } diff --git a/pdf2swf/xpdf/Link.h b/pdf2swf/xpdf/Link.h index 7e00510..4c644b8 100644 --- a/pdf2swf/xpdf/Link.h +++ b/pdf2swf/xpdf/Link.h @@ -2,7 +2,7 @@ // // Link.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -63,10 +63,8 @@ enum LinkDestKind { class LinkDest { public: - // Build a LinkDest from the array. If 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); } @@ -249,7 +247,7 @@ class LinkUnknown: public LinkAction { public: // Build a LinkUnknown with the specified action type. - LinkUnknown(char *action1); + LinkUnknown(char *actionA); // Destructor. virtual ~LinkUnknown(); diff --git a/pdf2swf/xpdf/Object.cc b/pdf2swf/xpdf/Object.cc index f9c1067..6d92c6a 100644 --- a/pdf2swf/xpdf/Object.cc +++ b/pdf2swf/xpdf/Object.cc @@ -2,7 +2,7 @@ // // Object.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include "Object.h" #include "Array.h" @@ -44,21 +45,21 @@ int Object::numAlloc[numObjTypes] = {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; } @@ -92,7 +93,7 @@ Object *Object::copy(Object *obj) { 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); } @@ -151,7 +152,9 @@ void Object::print(FILE *f) { 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); diff --git a/pdf2swf/xpdf/Object.h b/pdf2swf/xpdf/Object.h index fa4f740..65d0be0 100644 --- a/pdf2swf/xpdf/Object.h +++ b/pdf2swf/xpdf/Object.h @@ -2,7 +2,7 @@ // // Object.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -19,6 +19,7 @@ #include "gmem.h" #include "GString.h" +class XRef; class Array; class Dict; class Stream; @@ -78,27 +79,25 @@ public: 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() @@ -109,7 +108,7 @@ public: // 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(); @@ -133,12 +132,12 @@ public: 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; } @@ -177,8 +176,8 @@ public: 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. @@ -288,11 +287,11 @@ inline int Object::streamLookChar() 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(); } diff --git a/pdf2swf/xpdf/OutputDev.cc b/pdf2swf/xpdf/OutputDev.cc index eebf460..6d46542 100644 --- a/pdf2swf/xpdf/OutputDev.cc +++ b/pdf2swf/xpdf/OutputDev.cc @@ -2,7 +2,7 @@ // // OutputDev.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include "Object.h" #include "Stream.h" @@ -20,29 +21,30 @@ // 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) { @@ -57,6 +59,11 @@ 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) { @@ -67,12 +74,13 @@ void OutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, 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) { @@ -81,6 +89,7 @@ void OutputDev::drawImage(GfxState *state, Object *ref, Stream *str, colorMap->getBits() + 7) / 8); for (i = 0; i < j; ++i) str->getChar(); + str->close(); } } diff --git a/pdf2swf/xpdf/OutputDev.h b/pdf2swf/xpdf/OutputDev.h index d7de97a..cb825e0 100644 --- a/pdf2swf/xpdf/OutputDev.h +++ b/pdf2swf/xpdf/OutputDev.h @@ -2,7 +2,7 @@ // // OutputDev.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -14,6 +14,7 @@ #endif #include "gtypes.h" +#include "CharTypes.h" class GString; class GfxState; @@ -45,10 +46,17 @@ public: // 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) {} @@ -111,11 +119,13 @@ public: 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, @@ -123,7 +133,7 @@ public: 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 @@ -131,10 +141,18 @@ public: 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 diff --git a/pdf2swf/xpdf/PDFDoc.cc b/pdf2swf/xpdf/PDFDoc.cc index ae55d23..29abba0 100644 --- a/pdf2swf/xpdf/PDFDoc.cc +++ b/pdf2swf/xpdf/PDFDoc.cc @@ -2,7 +2,7 @@ // // PDFDoc.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include #include @@ -22,8 +23,8 @@ #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" @@ -37,24 +38,28 @@ // 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 @@ -66,6 +71,7 @@ PDFDoc::PDFDoc(GString *fileName1, GString *userPassword) { if (!(file = fopen(fileName2->getCString(), "rb"))) { error(-1, "Couldn't open file '%s'", fileName->getCString()); delete fileName2; + errCode = errOpenFile; return; } } @@ -75,40 +81,42 @@ PDFDoc::PDFDoc(GString *fileName1, GString *userPassword) { // 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; } @@ -203,8 +211,9 @@ GBool PDFDoc::isLinearized() { 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); @@ -248,4 +257,3 @@ void PDFDoc::getLinks(Page *page) { links = new Links(page->getAnnots(&obj), catalog->getBaseURI()); obj.free(); } - diff --git a/pdf2swf/xpdf/PDFDoc.h b/pdf2swf/xpdf/PDFDoc.h index e679db9..c12531e 100644 --- a/pdf2swf/xpdf/PDFDoc.h +++ b/pdf2swf/xpdf/PDFDoc.h @@ -2,7 +2,7 @@ // // PDFDoc.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -14,13 +14,13 @@ #endif #include +#include "XRef.h" #include "Link.h" #include "Catalog.h" #include "Page.h" class GString; class BaseStream; -class XRef; class OutputDev; class Links; class LinkAction; @@ -33,16 +33,24 @@ class LinkDest; 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; } @@ -60,6 +68,13 @@ public: // 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); @@ -88,10 +103,14 @@ public: 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(); @@ -107,7 +126,7 @@ public: private: - GBool setup(GString *userPassword); + GBool setup(GString *ownerPassword, GString *userPassword); void checkHeader(); void getLinks(Page *page); @@ -118,8 +137,10 @@ private: XRef *xref; Catalog *catalog; Links *links; + GBool printCommands; GBool ok; + int errCode; }; #endif diff --git a/pdf2swf/xpdf/Page.cc b/pdf2swf/xpdf/Page.cc index c2ac6b1..c601857 100644 --- a/pdf2swf/xpdf/Page.cc +++ b/pdf2swf/xpdf/Page.cc @@ -2,7 +2,7 @@ // // Page.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include "Object.h" #include "Array.h" @@ -19,11 +20,9 @@ #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" //------------------------------------------------------------------------ @@ -31,97 +30,76 @@ //------------------------------------------------------------------------ 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); @@ -133,20 +111,75 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { } 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); @@ -185,18 +218,22 @@ Page::~Page() { 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()); } @@ -207,10 +244,9 @@ void Page::display(OutputDev *out, double dpi, int rotate, } 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); } @@ -225,20 +261,20 @@ void Page::display(OutputDev *out, double dpi, int rotate, 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 diff --git a/pdf2swf/xpdf/Page.h b/pdf2swf/xpdf/Page.h index a144d2c..7207b20 100644 --- a/pdf2swf/xpdf/Page.h +++ b/pdf2swf/xpdf/Page.h @@ -2,7 +2,7 @@ // // Page.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -22,6 +22,12 @@ class Links; class Catalog; //------------------------------------------------------------------------ + +struct PDFRectangle { + double x1, y1, x2, y2; +}; + +//------------------------------------------------------------------------ // PageAttrs //------------------------------------------------------------------------ @@ -37,25 +43,49 @@ public: ~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; }; @@ -67,7 +97,8 @@ class Page { public: // Constructor. - Page(int num1, Dict *pageDict, PageAttrs *attrs1); + Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, + GBool printCommandsA); // Destructor. ~Page(); @@ -76,27 +107,31 @@ public: 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, @@ -104,10 +139,12 @@ public: 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 }; diff --git a/pdf2swf/xpdf/Params.cc b/pdf2swf/xpdf/Params.cc deleted file mode 100644 index 35adfdf..0000000 --- a/pdf2swf/xpdf/Params.cc +++ /dev/null @@ -1,87 +0,0 @@ -//======================================================================== -// -// Params.cc -// -// Copyright 1996 Derek B. Noonburg -// -//======================================================================== - -#include -#include -#include -#include -#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); - } -} diff --git a/pdf2swf/xpdf/Params.h b/pdf2swf/xpdf/Params.h deleted file mode 100644 index ea8536f..0000000 --- a/pdf2swf/xpdf/Params.h +++ /dev/null @@ -1,37 +0,0 @@ -//======================================================================== -// -// 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 diff --git a/pdf2swf/xpdf/Parser.cc b/pdf2swf/xpdf/Parser.cc index 6ad0c5a..4df53c9 100644 --- a/pdf2swf/xpdf/Parser.cc +++ b/pdf2swf/xpdf/Parser.cc @@ -2,7 +2,7 @@ // // Parser.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include "Object.h" #include "Array.h" @@ -21,8 +22,9 @@ #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); @@ -36,7 +38,8 @@ Parser::~Parser() { #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 @@ -63,10 +66,10 @@ Object *Parser::getObj(Object *obj) { // 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 @@ -77,7 +80,7 @@ Object *Parser::getObj(Object *obj) { // 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"); @@ -88,7 +91,7 @@ Object *Parser::getObj(Object *obj) { 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 @@ -101,7 +104,8 @@ Object *Parser::getObj(Object *obj) { obj->initStream(str); #ifndef NO_DECRYPTION if (fileKey) { - str->getBaseStream()->doDecryption(fileKey, objNum, objGen); + str->getBaseStream()->doDecryption(fileKey, keyLength, + objNum, objGen); } #endif } else { @@ -129,7 +133,7 @@ Object *Parser::getObj(Object *obj) { } 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) { @@ -151,7 +155,7 @@ Object *Parser::getObj(Object *obj) { Stream *Parser::makeStream(Object *dict) { Object obj; Stream *str; - int pos, endPos, length; + Guint pos, endPos, length; // get stream start position lexer->skipToNextLine(); @@ -160,7 +164,7 @@ Stream *Parser::makeStream(Object *dict) { // 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"); @@ -169,12 +173,13 @@ Stream *Parser::makeStream(Object *dict) { } // 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); diff --git a/pdf2swf/xpdf/Parser.h b/pdf2swf/xpdf/Parser.h index 6e61844..c11475b 100644 --- a/pdf2swf/xpdf/Parser.h +++ b/pdf2swf/xpdf/Parser.h @@ -2,7 +2,7 @@ // // Parser.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -23,7 +23,7 @@ class Parser { public: // Constructor. - Parser(Lexer *lexer1); + Parser(XRef *xrefA, Lexer *lexerA); // Destructor. ~Parser(); @@ -31,7 +31,8 @@ public: // 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 @@ -44,6 +45,7 @@ public: 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 diff --git a/pdf2swf/xpdf/StdFontInfo.h b/pdf2swf/xpdf/StdFontInfo.h deleted file mode 100644 index 0db033f..0000000 --- a/pdf2swf/xpdf/StdFontInfo.h +++ /dev/null @@ -1,546 +0,0 @@ -//======================================================================== -// -// 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 diff --git a/pdf2swf/xpdf/Stream-CCITT.h b/pdf2swf/xpdf/Stream-CCITT.h index 1af8742..f5a77b0 100644 --- a/pdf2swf/xpdf/Stream-CCITT.h +++ b/pdf2swf/xpdf/Stream-CCITT.h @@ -4,7 +4,7 @@ // // Tables for CCITT Fax decoding. // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf2swf/xpdf/Stream.cc b/pdf2swf/xpdf/Stream.cc index 0afcc94..9777940 100644 --- a/pdf2swf/xpdf/Stream.cc +++ b/pdf2swf/xpdf/Stream.cc @@ -2,7 +2,7 @@ // // Stream.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include #include @@ -265,8 +266,8 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { // BaseStream //------------------------------------------------------------------------ -BaseStream::BaseStream(Object *dict) { - this->dict = *dict; +BaseStream::BaseStream(Object *dictA) { + dict = *dictA; #ifndef NO_DECRYPTION decrypt = NULL; #endif @@ -281,8 +282,9 @@ BaseStream::~BaseStream() { } #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 @@ -290,8 +292,8 @@ void BaseStream::doDecryption(Guchar *fileKey, int objNum, int objGen) { // FilterStream //------------------------------------------------------------------------ -FilterStream::FilterStream(Stream *str) { - this->str = str; +FilterStream::FilterStream(Stream *strA) { + str = strA; } FilterStream::~FilterStream() { @@ -301,7 +303,7 @@ void FilterStream::close() { str->close(); } -void FilterStream::setPos(int pos) { +void FilterStream::setPos(Guint pos, int dir) { error(-1, "Internal: called setPos() on FilterStream"); } @@ -309,13 +311,13 @@ void FilterStream::setPos(int pos) { // 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) { @@ -396,13 +398,13 @@ void ImageStream::skipLine() { // 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; @@ -486,11 +488,11 @@ GBool StreamPredictor::getNextLine() { 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 @@ -552,27 +554,37 @@ GBool StreamPredictor::getNextLine() { // 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 @@ -582,9 +594,13 @@ void FileStream::reset() { } 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; } } @@ -596,10 +612,10 @@ GBool FileStream::fillBuf() { 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; @@ -619,56 +635,159 @@ GBool FileStream::fillBuf() { 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"); } @@ -676,8 +795,8 @@ void EmbedStream::moveStart(int start) { // ASCIIHexStream //------------------------------------------------------------------------ -ASCIIHexStream::ASCIIHexStream(Stream *str): - FilterStream(str) { +ASCIIHexStream::ASCIIHexStream(Stream *strA): + FilterStream(strA) { buf = EOF; eof = gFalse; } @@ -748,7 +867,9 @@ int ASCIIHexStream::lookChar() { 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; } @@ -761,8 +882,8 @@ GBool ASCIIHexStream::isBinary(GBool last) { // ASCII85Stream //------------------------------------------------------------------------ -ASCII85Stream::ASCII85Stream(Stream *str): - FilterStream(str) { +ASCII85Stream::ASCII85Stream(Stream *strA): + FilterStream(strA) { index = n = 0; eof = gFalse; } @@ -824,7 +945,9 @@ int ASCII85Stream::lookChar() { 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; } @@ -837,15 +960,15 @@ GBool ASCII85Stream::isBinary(GBool last) { // 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; } @@ -949,11 +1072,7 @@ void LZWStream::reset() { 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; @@ -1139,7 +1258,9 @@ GString *LZWStream::getPSFilter(char *indent) { if (pred) { return NULL; } - s = str->getPSFilter(indent); + if (!(s = str->getPSFilter(indent))) { + return NULL; + } s->append(indent)->append("/LZWDecode filter\n"); return s; } @@ -1152,8 +1273,8 @@ GBool LZWStream::isBinary(GBool last) { // RunLengthStream //------------------------------------------------------------------------ -RunLengthStream::RunLengthStream(Stream *str): - FilterStream(str) { +RunLengthStream::RunLengthStream(Stream *strA): + FilterStream(strA) { bufPtr = bufEnd = buf; eof = gFalse; } @@ -1171,7 +1292,9 @@ void RunLengthStream::reset() { 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; } @@ -1210,17 +1333,17 @@ GBool RunLengthStream::fillBuf() { // 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)); @@ -1274,7 +1397,7 @@ void CCITTFaxStream::reset() { int CCITTFaxStream::lookChar() { short code1, code2, code3; int a0New; -#if 0 //~ +#if 0 GBool err; #endif GBool gotEOL; @@ -1287,7 +1410,7 @@ int CCITTFaxStream::lookChar() { } // read the next row -#if 0 //~ +#if 0 err = gFalse; #endif if (codingLine[a0] >= columns) { @@ -1389,7 +1512,7 @@ int CCITTFaxStream::lookChar() { return EOF; default: error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1); -#if 0 //~ +#if 0 err = gTrue; break; #else @@ -1424,7 +1547,7 @@ int CCITTFaxStream::lookChar() { if (codingLine[a0] != columns) { error(getPos(), "CCITTFax row is wrong length (%d)", codingLine[a0]); -#if 0 //~ +#if 0 err = gTrue; #endif } @@ -1484,7 +1607,7 @@ int CCITTFaxStream::lookChar() { } } -#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 @@ -1720,7 +1843,9 @@ GString *CCITTFaxStream::getPSFilter(char *indent) { 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); @@ -1810,8 +1935,8 @@ static int dctZigZag[64] = { 63 }; -DCTStream::DCTStream(Stream *str): - FilterStream(str) { +DCTStream::DCTStream(Stream *strA): + FilterStream(strA) { int i, j; width = height = 0; @@ -2001,7 +2126,7 @@ GBool DCTStream::readMCURow() { 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]; @@ -2710,7 +2835,9 @@ int DCTStream::read16() { 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; } @@ -2792,11 +2919,11 @@ FlateDecode FlateStream::distDecode[flateMaxDistCodes] = { {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; } @@ -3224,8 +3351,8 @@ int FlateStream::getCodeWord(int bits) { // EOFStream //------------------------------------------------------------------------ -EOFStream::EOFStream(Stream *str): - FilterStream(str) { +EOFStream::EOFStream(Stream *strA): + FilterStream(strA) { } EOFStream::~EOFStream() { @@ -3236,9 +3363,9 @@ 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; } @@ -3269,11 +3396,61 @@ int FixedLengthEncoder::lookChar() { } //------------------------------------------------------------------------ +// 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; @@ -3344,8 +3521,8 @@ GBool ASCII85Encoder::fillBuf() { // RunLengthEncoder //------------------------------------------------------------------------ -RunLengthEncoder::RunLengthEncoder(Stream *str): - FilterStream(str) { +RunLengthEncoder::RunLengthEncoder(Stream *strA): + FilterStream(strA) { bufPtr = bufEnd = nextEnd = buf; eof = gFalse; } diff --git a/pdf2swf/xpdf/Stream.h b/pdf2swf/xpdf/Stream.h index 50345bb..3319dcc 100644 --- a/pdf2swf/xpdf/Stream.h +++ b/pdf2swf/xpdf/Stream.h @@ -2,7 +2,7 @@ // // Stream.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -78,8 +78,10 @@ public: // 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 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); @@ -116,20 +118,22 @@ private: 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 @@ -152,11 +156,11 @@ private: 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(); } @@ -175,7 +179,7 @@ public: // 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(); @@ -209,8 +213,8 @@ public: // 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(); @@ -242,9 +246,11 @@ private: 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(); @@ -253,9 +259,9 @@ public: 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: @@ -263,13 +269,52 @@ 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; }; //------------------------------------------------------------------------ @@ -285,17 +330,18 @@ private: 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: @@ -310,7 +356,7 @@ private: class ASCIIHexStream: public FilterStream { public: - ASCIIHexStream(Stream *str); + ASCIIHexStream(Stream *strA); virtual ~ASCIIHexStream(); virtual StreamKind getKind() { return strASCIIHex; } virtual void reset(); @@ -333,7 +379,7 @@ private: class ASCII85Stream: public FilterStream { public: - ASCII85Stream(Stream *str); + ASCII85Stream(Stream *strA); virtual ~ASCII85Stream(); virtual StreamKind getKind() { return strASCII85; } virtual void reset(); @@ -358,8 +404,8 @@ private: 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(); @@ -394,7 +440,7 @@ private: class RunLengthStream: public FilterStream { public: - RunLengthStream(Stream *str); + RunLengthStream(Stream *strA); virtual ~RunLengthStream(); virtual StreamKind getKind() { return strRunLength; } virtual void reset(); @@ -424,9 +470,9 @@ struct CCITTCodeTable; 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(); @@ -489,7 +535,7 @@ struct DCTHuffTable { class DCTStream: public FilterStream { public: - DCTStream(Stream *str); + DCTStream(Stream *strA); virtual ~DCTStream(); virtual StreamKind getKind() { return strDCT; } virtual void reset(); @@ -573,8 +619,8 @@ struct FlateDecode { 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(); @@ -624,7 +670,7 @@ private: class EOFStream: public FilterStream { public: - EOFStream(Stream *str); + EOFStream(Stream *strA); virtual ~EOFStream(); virtual StreamKind getKind() { return strWeird; } virtual void reset() {} @@ -641,7 +687,7 @@ public: class FixedLengthEncoder: public FilterStream { public: - FixedLengthEncoder(Stream *str, int length1); + FixedLengthEncoder(Stream *strA, int lengthA); ~FixedLengthEncoder(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); @@ -659,13 +705,44 @@ private: }; //------------------------------------------------------------------------ +// 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(); @@ -696,7 +773,7 @@ private: class RunLengthEncoder: public FilterStream { public: - RunLengthEncoder(Stream *str); + RunLengthEncoder(Stream *strA); virtual ~RunLengthEncoder(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); diff --git a/pdf2swf/xpdf/XRef.cc b/pdf2swf/xpdf/XRef.cc index d70b9f2..0e1bbc9 100644 --- a/pdf2swf/xpdf/XRef.cc +++ b/pdf2swf/xpdf/XRef.cc @@ -2,7 +2,7 @@ // // XRef.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,7 @@ #pragma implementation #endif +#include #include #include #include @@ -24,6 +25,7 @@ #include "Decrypt.h" #endif #include "Error.h" +#include "ErrorCodes.h" #include "XRef.h" //------------------------------------------------------------------------ @@ -44,33 +46,22 @@ #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(); @@ -78,7 +69,7 @@ XRef::XRef(BaseStream *str, GString *userPassword) { // try to reconstruct the xref table if (pos == 0) { if (!(ok = constructXRef())) { - xref = oldXref; + errCode = errDamaged; return; } @@ -86,7 +77,7 @@ XRef::XRef(BaseStream *str, GString *userPassword) { } 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)) ; @@ -98,22 +89,23 @@ XRef::XRef(BaseStream *str, GString *userPassword) { 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; } } @@ -128,17 +120,18 @@ XRef::~XRef() { // 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; @@ -154,7 +147,7 @@ int XRef::readTrailer() { 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 -- @@ -189,7 +182,9 @@ int XRef::readTrailer() { // 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); @@ -216,12 +211,12 @@ int XRef::readTrailer() { } // 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 @@ -233,77 +228,101 @@ GBool XRef::readXRef(int *pos) { 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; @@ -326,7 +345,7 @@ GBool XRef::constructXRef() { Parser *parser; Object obj; char buf[256]; - int pos; + Guint pos; int num, gen; int newSize; int streamEndsSize; @@ -349,8 +368,9 @@ GBool XRef::constructXRef() { // 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); @@ -392,7 +412,7 @@ GBool XRef::constructXRef() { 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; @@ -410,7 +430,8 @@ GBool XRef::constructXRef() { } 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; } @@ -424,8 +445,9 @@ GBool XRef::constructXRef() { } #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; @@ -435,35 +457,68 @@ GBool XRef::checkEncrypted(GString *userPassword) { 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(); @@ -473,52 +528,50 @@ GBool XRef::checkEncrypted(GString *userPassword) { 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 @@ -537,10 +590,11 @@ Object *XRef::fetch(int num, int gen, Object *obj) { } 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); @@ -548,7 +602,8 @@ Object *XRef::fetch(int num, int gen, Object *obj) { 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 @@ -569,24 +624,42 @@ Object *XRef::getDocInfo(Object *obj) { 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; } diff --git a/pdf2swf/xpdf/XRef.h b/pdf2swf/xpdf/XRef.h index e2260d0..7876fa6 100644 --- a/pdf2swf/xpdf/XRef.h +++ b/pdf2swf/xpdf/XRef.h @@ -2,7 +2,7 @@ // // XRef.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -24,7 +24,7 @@ class Stream; //------------------------------------------------------------------------ struct XRefEntry { - int offset; + Guint offset; int gen; GBool used; }; @@ -33,7 +33,7 @@ class XRef { public: // Constructor. Read xref table from stream. - XRef(BaseStream *str, GString *userPassword); + XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword); // Destructor. ~XRef(); @@ -41,6 +41,9 @@ public: // 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; } @@ -49,10 +52,10 @@ public: #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); } @@ -62,51 +65,52 @@ public: // 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 array int rootNum, rootGen; // catalog dict GBool ok; // true if xref table is valid + int errCode; // error code (if 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 diff --git a/pdf2swf/xpdf/config.h b/pdf2swf/xpdf/config.h index c09d8f5..39cb291 100644 --- a/pdf2swf/xpdf/config.h +++ b/pdf2swf/xpdf/config.h @@ -2,7 +2,7 @@ // // config.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -10,18 +10,23 @@ #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 @@ -32,11 +37,24 @@ #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 //------------------------------------------------------------------------ @@ -46,14 +64,11 @@ // 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 @@ -64,7 +79,7 @@ #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" diff --git a/pdf2swf/xpdf/gfile.cc b/pdf2swf/xpdf/gfile.cc index 2350a90..d6d2363 100644 --- a/pdf2swf/xpdf/gfile.cc +++ b/pdf2swf/xpdf/gfile.cc @@ -4,11 +4,12 @@ // // Miscellaneous file and directory name manipulation. // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== -#include "../../config.h" +#include + #ifdef WIN32 extern "C" { # ifndef _MSC_VER @@ -441,23 +442,28 @@ time_t getModTime(char *fileName) { 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; @@ -465,7 +471,7 @@ GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) { // 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); @@ -479,20 +485,26 @@ GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) { 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"))) { @@ -503,7 +515,7 @@ GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) { (*name)->append("/XXXXXX"); fd = mkstemp((*name)->getCString()); #else // HAVE_MKSTEMP - if (!(s = mktmpname(NULL))) { + if (!(s = tmpnam(NULL))) { return gFalse; } *name = new GString(s); @@ -518,11 +530,48 @@ GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) { #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) @@ -534,17 +583,17 @@ GDirEntry::GDirEntry(char *dirPath, char *name1, GBool doStat) { 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)); @@ -561,9 +610,9 @@ GDirEntry::~GDirEntry() { 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; diff --git a/pdf2swf/xpdf/gfile.h b/pdf2swf/xpdf/gfile.h index f3041b9..bb6131d 100644 --- a/pdf2swf/xpdf/gfile.h +++ b/pdf2swf/xpdf/gfile.h @@ -4,7 +4,7 @@ // // Miscellaneous file and directory name manipulation. // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== @@ -14,7 +14,6 @@ #include #include #include -#include "../../config.h" #if defined(WIN32) # include # ifdef FPTEX @@ -72,11 +71,11 @@ extern GBool isAbsolutePath(char *path); // 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 . 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 is not // NULL, it will be used as the file name extension. Returns both the @@ -84,10 +83,14 @@ time_t getModTime(char *fileName); // should be done to the returned file pointer; the file may be // reopened later for reading, but not for writing. The 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 . 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 @@ -96,7 +99,7 @@ char* mktmpname(char*ptr); 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; } @@ -110,7 +113,7 @@ private: class GDir { public: - GDir(char *name, GBool doStat1 = gTrue); + GDir(char *name, GBool doStatA = gTrue); ~GDir(); GDirEntry *getNextEntry(); void rewind(); diff --git a/pdf2swf/xpdf/gmem.c b/pdf2swf/xpdf/gmem.c index cac386b..27ebb2b 100644 --- a/pdf2swf/xpdf/gmem.c +++ b/pdf2swf/xpdf/gmem.c @@ -3,9 +3,10 @@ * * Memory routines with out-of-memory checking. * - * Copyright 1996 Derek B. Noonburg + * Copyright 1996-2002 Glyph & Cog, LLC */ +#include #include #include #include @@ -24,9 +25,9 @@ typedef struct _GMemHdr { #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 */ @@ -59,7 +60,7 @@ void *gmalloc(int size) { GMemHdr *hdr; void *data; int lst; - long *trl, *p; + unsigned long *trl, *p; if (size == 0) return NULL; @@ -70,14 +71,14 @@ void *gmalloc(int size) { } 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 @@ -140,7 +141,7 @@ void gfree(void *p) { GMemHdr *hdr; GMemHdr *prevHdr, *q; int lst; - long *trl, *clr; + unsigned long *trl, *clr; if (p) { hdr = (GMemHdr *)((char *)p - gMemHdrSize); @@ -156,12 +157,12 @@ void gfree(void *p) { 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 { diff --git a/pdf2swf/xpdf/gmem.h b/pdf2swf/xpdf/gmem.h index 732726d..93ccb94 100644 --- a/pdf2swf/xpdf/gmem.h +++ b/pdf2swf/xpdf/gmem.h @@ -3,14 +3,13 @@ * * 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 -#include "../../config.h" #ifdef __cplusplus extern "C" { diff --git a/pdf2swf/xpdf/gtypes.h b/pdf2swf/xpdf/gtypes.h index 6593267..1879b88 100644 --- a/pdf2swf/xpdf/gtypes.h +++ b/pdf2swf/xpdf/gtypes.h @@ -3,7 +3,7 @@ * * Some useful simple types. * - * Copyright 1996 Derek B. Noonburg + * Copyright 1996-2002 Glyph & Cog, LLC */ #ifndef GTYPES_H