69 files changed, 2201 insertions, 715 deletions
diff --git a/noncore/unsupported/qpdf/QOutputDev.h b/noncore/unsupported/qpdf/QOutputDev.h index 2958062..f3c5a01 100644 --- a/noncore/unsupported/qpdf/QOutputDev.h +++ b/noncore/unsupported/qpdf/QOutputDev.h @@ -78,8 +78,15 @@ public: // Does this device use drawChar() or drawString()? virtual GBool useDrawChar() { return gTrue; } + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() { return gFalse; } + + // Does this device need non-text content? + virtual GBool needNonText() { return gFalse; } + //----- initialization and control // Start a page. virtual void startPage(int pageNum, GfxState *state); diff --git a/noncore/unsupported/qpdf/README b/noncore/unsupported/qpdf/README index 36ce6bc..65e7aaf 100644 --- a/noncore/unsupported/qpdf/README +++ b/noncore/unsupported/qpdf/README @@ -1,8 +1,8 @@ QPDF - a PDF viewer for the Qtopia environment -This tool is based on xpdf (currently 1.00). It uses the (mostly unmodified - +This tool is based on xpdf (currently 1.01). It uses the (mostly unmodified - see below) xpdf PDF rendering engine. The Qtopia adaption was done with a new OutputDev which renders directly to a QPixmap via QPainter calls. Changes in 20020406: @@ -19,14 +19,21 @@ Changes in 20020408: - Progress indicator added - Problems with type 3 fonts (not fully supported by XPDF) solved - Heavy optimizations in the image rendering code -Changed in 20020413: +Changes in 20020413: - Fixed crash in find routine - Stylus selection reworked - Cursor-key navigation added - Various crashes related to recursive calling of XPDF fixed +Changes in 20020417: + - Fixed crash in XPDF regarding 0-length strings. + - Fast sqrt, rint and fabs functions added. + +Changes in 20020524: + - Ported to xpdf 1.01 + Changes to xpdf: - xpdf calculates nearly everything with doubles. Since ARMs are not equipped with a FPU, all doubles have been replaced with a C++ class "fouble" (fixed @@ -51,38 +58,22 @@ ToDo: - Links are currently simply ignored. Install: - - xpdf-1.00 - Get the tarball for xpdf, version 1.0, untar it and ./configure it. - (No special flags are needed for ./configure - it simply has to run) - - - qpdf - Make sure your QPEDIR / TMAKEPATH variables are correctly ! - - cd into the xpdf directory (xpdf-1.00) and untar the qpdf tarball. This - should create a subdirectory qpdf. - cd into this directory and start the script "./setup-qpdf". This - incorporates the above mentioned patches into xpdf. - - Now do a make. - - Copy the files qpdf, qpdf_icon.png and qpdf.desktop to the appropriate - directories on your iPaq or: - If you want a ipk, just run ./mkipkg + - Qpdf is now fully integrated into Opie. For compilation and installation + instructions see http://opie.handhelds.org. - compress / uncompress - If you run a normal familiar installation, it the standard gzip (I tested - 1.2.4-33 ipkg) can handle the compression format used in PDF files, when + If you run a normal familiar installation, the standard gzip (I tested + 1.2.4-33 ipkg) can handle the compression format used in PDF files, when called as uncompress. The BusyBox version of gzip can _not_ handle this old format. - If you do not have a working uncompress installed on your iPaq, you can - simply use the one in the contrib directory of the tarball (make uncompress - a link to compress). - [I could not find an official tarball for compress -- this is the SuSE - version cross-compiled for ARM] - + If you do not have a working uncompress installed on your iPaq, you could + simply use the old compress package. + (I could not find an official tarball for compress -- I used the SuSE + version cross-compiled for ARM for myself, but I will make an ipk soon) + Have fun ;) Robert (griebl@gmx.de) diff --git a/noncore/unsupported/qpdf/UTF8.h b/noncore/unsupported/qpdf/UTF8.h index aacf663..95adecf 100644 --- a/noncore/unsupported/qpdf/UTF8.h +++ b/noncore/unsupported/qpdf/UTF8.h @@ -21,4 +21,18 @@ static int mapUTF8 ( Unicode u, char *buf, int bufSize ) } else return 0; } + +static int mapUCS2 ( Unicode u, char *buf, int bufSize) +{ + if (u <= 0xffff) { + if (bufSize < 2) + return 0; + + buf[0] = (char)((u >> 8) & 0xff); + buf[1] = (char)(u & 0xff); + return 2; + } + else + return 0; +} diff --git a/noncore/unsupported/qpdf/qpdf.cpp b/noncore/unsupported/qpdf/qpdf.cpp index 6c268ec..f338509 100644 --- a/noncore/unsupported/qpdf/qpdf.cpp +++ b/noncore/unsupported/qpdf/qpdf.cpp @@ -15,14 +15,14 @@ #include <qpe/qpeapplication.h> #include <qpe/resource.h> #include <qpe/applnk.h> -#include <qpe/fileselector.h> #include <qpe/qcopenvelope_qws.h> #include <qclipboard.h> #include <qtoolbar.h> +#include <qtoolbutton.h> #include <qmenubar.h> #include <qpopupmenu.h> #include <qwidgetstack.h> #include <qtimer.h> @@ -36,8 +36,14 @@ #include <qmessagebox.h> #include "qpdf.h" +#ifdef QPDF_QPE_ONLY +#include <qpe/fileselector.h> +#else +#include <opie/ofileselector.h> +#endif + int main ( int argc, char **argv ) { QPEApplication app ( argc, argv ); @@ -80,9 +86,14 @@ QPdfDlg::QPdfDlg ( ) : QMainWindow ( ) m_outdev = new QPEOutputDev ( m_stack ); connect ( m_outdev, SIGNAL( selectionChanged ( const QRect & )), this, SLOT( copyToClipboard ( const QRect & ))); +#ifdef QPDF_QPE_ONLY m_filesel = new FileSelector ( "application/pdf", m_stack, "fs", false, true ); +#else + m_filesel = new OFileSelector ( "application/pdf", m_stack, "fs", false, true ); +#endif + connect ( m_filesel, SIGNAL( closeMe ( )), this, SLOT( closeFileSelector ( ))); connect ( m_filesel, SIGNAL( fileSelected ( const DocLnk & )), this, SLOT( openFile ( const DocLnk & ))); m_tb_menu = new QToolBar ( this ); diff --git a/noncore/unsupported/qpdf/qpdf.h b/noncore/unsupported/qpdf/qpdf.h index b4ce554..8b3cff9 100644 --- a/noncore/unsupported/qpdf/qpdf.h +++ b/noncore/unsupported/qpdf/qpdf.h @@ -4,14 +4,16 @@ #include "aconf.h" #include <qmainwindow.h> +#define QPDF_QPE_ONLY 1 // ofileselector does not work right currently class QPEOutputDev; class PDFDoc; class DocLnk; class FileSelector; +class OFileSelector; class QWidgetStack; class QLineEdit; @@ -67,9 +69,14 @@ protected: private: QWidgetStack *m_stack; QPEOutputDev *m_outdev; + +#ifdef QPDF_QPE_ONLY FileSelector *m_filesel; +#else + OFileSelector *m_filesel; +#endif QToolBar *m_tb_menu, *m_tb_tool, *m_tb_find; QLineEdit *m_findedit; QPopupMenu *m_pm_zoom; diff --git a/noncore/unsupported/qpdf/qpdf.pro b/noncore/unsupported/qpdf/qpdf.pro index 0c2e38b..fe5abfb 100644 --- a/noncore/unsupported/qpdf/qpdf.pro +++ b/noncore/unsupported/qpdf/qpdf.pro @@ -12,9 +12,9 @@ SOURCES = xpdf/Array.cc \ xpdf/Decrypt.cc \ xpdf/Dict.cc \ xpdf/Error.cc \ xpdf/FontEncodingTables.cc \ - xpdf/FormWidget.cc \ + xpdf/Annot.cc \ xpdf/Function.cc \ xpdf/Gfx.cc \ xpdf/GfxFont.cc \ xpdf/GfxState.cc \ @@ -26,8 +26,9 @@ SOURCES = xpdf/Array.cc \ xpdf/OutputDev.cc \ xpdf/PDFDoc.cc \ xpdf/Page.cc \ xpdf/Parser.cc \ + xpdf/PSTokenizer.cc \ xpdf/Stream.cc \ xpdf/TextOutputDev.cc \ xpdf/UnicodeMap.cc \ xpdf/XRef.cc \ @@ -51,9 +52,9 @@ INCLUDEPATH += . \ $(OPIEDIR)/include \ ../goo \ goo -LIBS += -L $(OPIEDIR)/lib -lqpe +LIBS += -L $(OPIEDIR)/lib -lqpe -lopie DESTDIR = $(OPIEDIR)/bin TARGET = qpdf diff --git a/noncore/unsupported/qpdf/xpdf/FormWidget.cc b/noncore/unsupported/qpdf/xpdf/Annot.cc index 05c67a4..49ae50a 100644 --- a/noncore/unsupported/qpdf/xpdf/FormWidget.cc +++ b/noncore/unsupported/qpdf/xpdf/Annot.cc @@ -1,9 +1,9 @@ //======================================================================== // -// FormWidget.cc +// Annot.cc // -// Copyright 2000 Derek B. Noonburg +// Copyright 2000-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -13,15 +13,15 @@ #include <aconf.h> #include "gmem.h" #include "Object.h" #include "Gfx.h" -#include "FormWidget.h" +#include "Annot.h" //------------------------------------------------------------------------ -// FormWidget +// Annot //------------------------------------------------------------------------ -FormWidget::FormWidget(XRef *xrefA, Dict *dict) { +Annot::Annot(XRef *xrefA, Dict *dict) { Object apObj, asObj, obj1, obj2; fouble t; ok = gFalse; @@ -76,51 +76,50 @@ FormWidget::FormWidget(XRef *xrefA, Dict *dict) { } obj1.free(); } -FormWidget::~FormWidget() { +Annot::~Annot() { appearance.free(); } -void FormWidget::draw(Gfx *gfx) { +void Annot::draw(Gfx *gfx) { Object obj; if (appearance.fetch(xref, &obj)->isStream()) { - gfx->doWidgetForm(&obj, xMin, yMin, xMax, yMax); + gfx->doAnnot(&obj, xMin, yMin, xMax, yMax); } obj.free(); } //------------------------------------------------------------------------ -// FormWidgets +// Annots //------------------------------------------------------------------------ -FormWidgets::FormWidgets(XRef *xref, Object *annots) { - FormWidget *widget; +Annots::Annots(XRef *xref, Object *annotsObj) { + Annot *annot; Object obj1, obj2; int size; int i; - widgets = NULL; + annots = NULL; size = 0; - nWidgets = 0; + nAnnots = 0; - if (annots->isArray()) { - for (i = 0; i < annots->arrayGetLength(); ++i) { - if (annots->arrayGet(i, &obj1)->isDict()) { + if (annotsObj->isArray()) { + for (i = 0; i < annotsObj->arrayGetLength(); ++i) { + if (annotsObj->arrayGet(i, &obj1)->isDict()) { obj1.dictLookup("Subtype", &obj2); if (obj2.isName("Widget") || obj2.isName("Stamp")) { - widget = new FormWidget(xref, obj1.getDict()); - if (widget->isOk()) { - if (nWidgets >= size) { + annot = new Annot(xref, obj1.getDict()); + if (annot->isOk()) { + if (nAnnots >= size) { size += 16; - widgets = (FormWidget **)grealloc(widgets, - size * sizeof(FormWidget *)); + annots = (Annot **)grealloc(annots, size * sizeof(Annot *)); } - widgets[nWidgets++] = widget; + annots[nAnnots++] = annot; } else { - delete widget; + delete annot; } } obj2.free(); } @@ -128,12 +127,12 @@ FormWidgets::FormWidgets(XRef *xref, Object *annots) { } } } -FormWidgets::~FormWidgets() { +Annots::~Annots() { int i; - for (i = 0; i < nWidgets; ++i) { - delete widgets[i]; + for (i = 0; i < nAnnots; ++i) { + delete annots[i]; } - gfree(widgets); + gfree(annots); } diff --git a/noncore/unsupported/qpdf/xpdf/FormWidget.h b/noncore/unsupported/qpdf/xpdf/Annot.h index 7f07889..0cc33dd 100644 --- a/noncore/unsupported/qpdf/xpdf/FormWidget.h +++ b/noncore/unsupported/qpdf/xpdf/Annot.h @@ -1,31 +1,33 @@ //======================================================================== // -// FormWidget.h +// Annot.h // -// Copyright 2000 Derek B. Noonburg +// Copyright 2000-2002 Glyph & Cog, LLC // //======================================================================== -#ifndef FORMWIDGET_H -#define FORMWIDGET_H +#ifndef ANNOT_H +#define ANNOT_H #ifdef __GNUC__ #pragma interface #endif +#include <aconf.h> + class XRef; class Gfx; //------------------------------------------------------------------------ -// FormWidget +// Annot //------------------------------------------------------------------------ -class FormWidget { +class Annot { public: - FormWidget(XRef *xrefA, Dict *dict); - ~FormWidget(); + Annot(XRef *xrefA, Dict *dict); + ~Annot(); GBool isOk() { return ok; } void draw(Gfx *gfx); @@ -36,32 +38,32 @@ private: XRef *xref; // the xref table for this PDF file Object appearance; // a reference to the Form XObject stream // for the normal appearance - fouble xMin, yMin, // widget rectangle + fouble xMin, yMin, // annotation rectangle xMax, yMax; GBool ok; }; //------------------------------------------------------------------------ -// FormWidgets +// Annots //------------------------------------------------------------------------ -class FormWidgets { +class Annots { public: - // Extract widgets from array of annotations. - FormWidgets(XRef *xref, Object *annots); + // Extract non-link annotations from array of annotations. + Annots(XRef *xref, Object *annotsObj); - ~FormWidgets(); + ~Annots(); - // Iterate through list of widgets. - int getNumWidgets() { return nWidgets; } - FormWidget *getWidget(int i) { return widgets[i]; } + // Iterate through list of annotations. + int getNumAnnots() { return nAnnots; } + Annot *getAnnot(int i) { return annots[i]; } private: - FormWidget **widgets; - int nWidgets; + Annot **annots; + int nAnnots; }; #endif diff --git a/noncore/unsupported/qpdf/xpdf/Array.cc b/noncore/unsupported/qpdf/xpdf/Array.cc index 5743fe6..fbdde49 100644 --- a/noncore/unsupported/qpdf/xpdf/Array.cc +++ b/noncore/unsupported/qpdf/xpdf/Array.cc @@ -1,9 +1,9 @@ //======================================================================== // // Array.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ diff --git a/noncore/unsupported/qpdf/xpdf/Array.h b/noncore/unsupported/qpdf/xpdf/Array.h index 1616fc3..a118f68 100644 --- a/noncore/unsupported/qpdf/xpdf/Array.h +++ b/noncore/unsupported/qpdf/xpdf/Array.h @@ -1,9 +1,9 @@ //======================================================================== // // Array.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef ARRAY_H diff --git a/noncore/unsupported/qpdf/xpdf/BuiltinFont.h b/noncore/unsupported/qpdf/xpdf/BuiltinFont.h index b4fa24c..a795311 100644 --- a/noncore/unsupported/qpdf/xpdf/BuiltinFont.h +++ b/noncore/unsupported/qpdf/xpdf/BuiltinFont.h @@ -1,9 +1,9 @@ //======================================================================== // // BuiltinFont.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef BUILTINFONT_H diff --git a/noncore/unsupported/qpdf/xpdf/BuiltinFontTables.cc b/noncore/unsupported/qpdf/xpdf/BuiltinFontTables.cc index 6833972..845abcd 100644 --- a/noncore/unsupported/qpdf/xpdf/BuiltinFontTables.cc +++ b/noncore/unsupported/qpdf/xpdf/BuiltinFontTables.cc @@ -1,9 +1,9 @@ //======================================================================== // // BuiltinFontTables.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #include <aconf.h> diff --git a/noncore/unsupported/qpdf/xpdf/BuiltinFontTables.h b/noncore/unsupported/qpdf/xpdf/BuiltinFontTables.h index 9a17ce9..3a8892e 100644 --- a/noncore/unsupported/qpdf/xpdf/BuiltinFontTables.h +++ b/noncore/unsupported/qpdf/xpdf/BuiltinFontTables.h @@ -1,9 +1,9 @@ //======================================================================== // // BuiltinFontTables.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef BUILTINFONTTABLES_H diff --git a/noncore/unsupported/qpdf/xpdf/CMap.cc b/noncore/unsupported/qpdf/xpdf/CMap.cc index 57809f0..b49cffd 100644 --- a/noncore/unsupported/qpdf/xpdf/CMap.cc +++ b/noncore/unsupported/qpdf/xpdf/CMap.cc @@ -1,9 +1,9 @@ //======================================================================== // // CMap.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -19,8 +19,9 @@ #include "gfile.h" #include "GString.h" #include "Error.h" #include "GlobalParams.h" +#include "PSTokenizer.h" #include "CMap.h" //------------------------------------------------------------------------ @@ -33,17 +34,22 @@ struct CMapVectorEntry { }; //------------------------------------------------------------------------ +static int getCharFromFile(void *data) { + return fgetc((FILE *)data); +} + +//------------------------------------------------------------------------ + CMap *CMap::parse(CMapCache *cache, GString *collectionA, GString *cMapNameA) { FILE *f; CMap *cmap; - char buf[256]; - GBool inCodeSpace, inCIDRange; - char *tok1, *tok2, *tok3; + PSTokenizer *pst; + char tok1[256], tok2[256], tok3[256]; + int n1, n2, n3; Guint start, end; - Guint n; if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) { // Check for an identity CMap. @@ -60,52 +66,66 @@ CMap *CMap::parse(CMapCache *cache, GString *collectionA, } cmap = new CMap(collectionA->copy(), cMapNameA->copy()); - inCodeSpace = inCIDRange = gFalse; - while (getLine(buf, sizeof(buf), f)) { - tok1 = strtok(buf, " \t\r\n"); - if (!tok1 || tok1[0] == '%') { - continue; - } - tok2 = strtok(NULL, " \t\r\n"); - tok3 = strtok(NULL, " \t\r\n"); - if (inCodeSpace) { - if (!strcmp(tok1, "endcodespacerange")) { - inCodeSpace = gFalse; - } else if (tok2 && tok1[0] == '<' && tok2[0] == '<' && - (n = strlen(tok1)) == strlen(tok2) && - n >= 4 && (n & 1) == 0) { - tok1[n - 1] = tok2[n - 1] = '\0'; - sscanf(tok1 + 1, "%x", &start); - sscanf(tok2 + 1, "%x", &end); - n = (n - 2) / 2; - cmap->addCodeSpace(cmap->vector, start, end, n); - } - } else if (inCIDRange) { - if (!strcmp(tok1, "endcidrange")) { - inCIDRange = gFalse; - } else if (tok2 && tok3 && tok1[0] == '<' && tok2[0] == '<' && - (n = strlen(tok1)) == strlen(tok2) && - n >= 4 && (n & 1) == 0) { - tok1[n - 1] = tok2[n - 1] = '\0'; - sscanf(tok1 + 1, "%x", &start); - sscanf(tok2 + 1, "%x", &end); - n = (n - 2) / 2; - cmap->addCIDs(start, end, n, (CID)atoi(tok3)); - } - } else if (tok2 && !strcmp(tok2, "usecmap")) { + pst = new PSTokenizer(&getCharFromFile, f); + pst->getToken(tok1, sizeof(tok1), &n1); + while (pst->getToken(tok2, sizeof(tok2), &n2)) { + if (!strcmp(tok2, "usecmap")) { if (tok1[0] == '/') { cmap->useCMap(cache, tok1 + 1); } + pst->getToken(tok1, sizeof(tok1), &n1); } else if (!strcmp(tok1, "/WMode")) { cmap->wMode = atoi(tok2); - } else if (tok2 && !strcmp(tok2, "begincodespacerange")) { - inCodeSpace = gTrue; - } else if (tok2 && !strcmp(tok2, "begincidrange")) { - inCIDRange = gTrue; + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "begincodespacerange")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endcodespacerange")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endcodespacerange")) { + error(-1, "Illegal entry in codespacerange block in CMap"); + break; + } + if (tok1[0] == '<' && tok2[0] == '<' && + n1 == n2 && n1 >= 4 && (n1 & 1) == 0) { + tok1[n1 - 1] = tok2[n1 - 1] = '\0'; + sscanf(tok1 + 1, "%x", &start); + sscanf(tok2 + 1, "%x", &end); + n1 = (n1 - 2) / 2; + cmap->addCodeSpace(cmap->vector, start, end, n1); + } + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "begincidrange")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endcidrange")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endcidrange") || + !pst->getToken(tok3, sizeof(tok3), &n3) || + !strcmp(tok3, "endcidrange")) { + error(-1, "Illegal entry in cidrange block in CMap"); + break; + } + if (tok1[0] == '<' && tok2[0] == '<' && + n1 == n2 && n1 >= 4 && (n1 & 1) == 0) { + tok1[n1 - 1] = tok2[n1 - 1] = '\0'; + sscanf(tok1 + 1, "%x", &start); + sscanf(tok2 + 1, "%x", &end); + n1 = (n1 - 2) / 2; + cmap->addCIDs(start, end, n1, (CID)atoi(tok3)); + } + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else { + strcpy(tok1, tok2); } } + delete pst; fclose(f); return cmap; diff --git a/noncore/unsupported/qpdf/xpdf/CMap.h b/noncore/unsupported/qpdf/xpdf/CMap.h index 8b29ef7..fe49acf 100644 --- a/noncore/unsupported/qpdf/xpdf/CMap.h +++ b/noncore/unsupported/qpdf/xpdf/CMap.h @@ -1,9 +1,9 @@ //======================================================================== // // CMap.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef CMAP_H diff --git a/noncore/unsupported/qpdf/xpdf/Catalog.cc b/noncore/unsupported/qpdf/xpdf/Catalog.cc index 6a0c2d5..1212e2e 100644 --- a/noncore/unsupported/qpdf/xpdf/Catalog.cc +++ b/noncore/unsupported/qpdf/xpdf/Catalog.cc @@ -1,9 +1,9 @@ //======================================================================== // // Catalog.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -145,9 +145,9 @@ GString *Catalog::readMetadata() { return NULL; } dict = metadata.streamGetDict(); if (!dict->lookup("Subtype", &obj)->isName("XML")) { - error(-1, "Unknown Metadata type: '%s'\n", + error(-1, "Unknown Metadata type: '%s'", obj.isName() ? obj.getName() : "???"); } obj.free(); s = new GString(); @@ -264,12 +264,12 @@ 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(); } else { diff --git a/noncore/unsupported/qpdf/xpdf/Catalog.h b/noncore/unsupported/qpdf/xpdf/Catalog.h index 197f5b8..afad803 100644 --- a/noncore/unsupported/qpdf/xpdf/Catalog.h +++ b/noncore/unsupported/qpdf/xpdf/Catalog.h @@ -1,9 +1,9 @@ //======================================================================== // // Catalog.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef CATALOG_H diff --git a/noncore/unsupported/qpdf/xpdf/CharCodeToUnicode.cc b/noncore/unsupported/qpdf/xpdf/CharCodeToUnicode.cc index 6793398..912981e 100644 --- a/noncore/unsupported/qpdf/xpdf/CharCodeToUnicode.cc +++ b/noncore/unsupported/qpdf/xpdf/CharCodeToUnicode.cc @@ -1,9 +1,9 @@ //======================================================================== // // CharCodeToUnicode.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -17,8 +17,9 @@ #include "gfile.h" #include "GString.h" #include "Error.h" #include "GlobalParams.h" +#include "PSTokenizer.h" #include "CharCodeToUnicode.h" //------------------------------------------------------------------------ @@ -31,8 +32,28 @@ struct CharCodeToUnicodeString { }; //------------------------------------------------------------------------ +static int getCharFromString(void *data) { + char *p; + int c; + + p = *(char **)data; + if (*p) { + c = *p++; + *(char **)data = p; + } else { + c = EOF; + } + return c; +} + +static int getCharFromFile(void *data) { + return fgetc((FILE *)data); +} + +//------------------------------------------------------------------------ + CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *collectionA) { FILE *f; Unicode *mapA; CharCode size, mapLenA; @@ -74,49 +95,22 @@ CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *collectionA) { CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) { return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0); } -static char *getLineFromString(char *buf, int size, char **s) { - char c; - int i; - - i = 0; - while (i < size - 1 && **s) { - buf[i++] = c = *(*s)++; - if (c == '\x0a') { - break; - } - if (c == '\x0d') { - if (**s == '\x0a' && i < size - 1) { - buf[i++] = '\x0a'; - ++*s; - } - break; - } - } - buf[i] = '\0'; - if (i == 0) { - return NULL; - } - return buf; -} - CharCodeToUnicode *CharCodeToUnicode::parseCMap(GString *buf, int nBits) { CharCodeToUnicode *ctu; char *p; ctu = new CharCodeToUnicode(NULL); p = buf->getCString(); - ctu->parseCMap1((char *(*)(char *, int, void *))&getLineFromString, - &p, nBits); + ctu->parseCMap1(&getCharFromString, &p, nBits); return ctu; } -void CharCodeToUnicode::parseCMap1(char *(*getLineFunc)(char *, int, void *), - void *data, int nBits) { - char buf[256]; - GBool inBFChar, inBFRange; - char *tok1, *tok2, *tok3; +void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, + int nBits) { + PSTokenizer *pst; + char tok1[256], tok2[256], tok3[256]; int nDigits, n1, n2, n3; CharCode oldLen, i; CharCode code1, code2; Unicode u; @@ -125,30 +119,42 @@ void CharCodeToUnicode::parseCMap1(char *(*getLineFunc)(char *, int, void *), GString *name; FILE *f; nDigits = nBits / 4; - inBFChar = inBFRange = gFalse; - while ((*getLineFunc)(buf, sizeof(buf), data)) { - tok1 = strtok(buf, " \t\r\n"); - if (!tok1 || tok1[0] == '%') { - continue; - } - tok2 = strtok(NULL, " \t\r\n"); - tok3 = strtok(NULL, " \t\r\n"); - if (inBFChar) { - if (!strcmp(tok1, "endbfchar")) { - inBFChar = gFalse; - } else if (tok2) { - n1 = strlen(tok1); - n2 = strlen(tok2); + pst = new PSTokenizer(getCharFunc, data); + pst->getToken(tok1, sizeof(tok1), &n1); + while (pst->getToken(tok2, sizeof(tok2), &n2)) { + if (!strcmp(tok2, "usecmap")) { + if (tok1[0] == '/') { + name = new GString(tok1 + 1); + if ((f = globalParams->findToUnicodeFile(name))) { + parseCMap1(&getCharFromFile, f, nBits); + fclose(f); + } else { + error(-1, "Couldn't find ToUnicode CMap file for '%s'", + name->getCString()); + } + delete name; + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "beginbfchar")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endbfchar")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endbfchar")) { + error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); + break; + } if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' && tok2[0] == '<' && tok2[n2 - 1] == '>')) { - error(-1, "Illegal line in bfchar block in ToUnicode CMap"); + error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); continue; } tok1[n1 - 1] = tok2[n2 - 1] = '\0'; if (sscanf(tok1 + 1, "%x", &code1) != 1) { - error(-1, "Illegal line in bfchar block in ToUnicode CMap"); + error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); continue; } if (code1 >= mapLen) { oldLen = mapLen; @@ -159,9 +165,9 @@ void CharCodeToUnicode::parseCMap1(char *(*getLineFunc)(char *, int, void *), } } if (n2 == 6) { if (sscanf(tok2 + 1, "%x", &u) != 1) { - error(-1, "Illegal line in bfchar block in ToUnicode CMap"); + error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); continue; } map[code1] = u; } else { @@ -176,33 +182,37 @@ void CharCodeToUnicode::parseCMap1(char *(*getLineFunc)(char *, int, void *), for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) { strncpy(uHex, tok2 + 1 + j*4, 4); uHex[4] = '\0'; if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) { - error(-1, "Illegal line in bfchar block in ToUnicode CMap"); + error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); } } ++sMapLen; } - } else { - error(-1, "Illegal bfchar block in ToUnicode CMap"); } - } else if (inBFRange) { - if (!strcmp(tok1, "endbfrange")) { - inBFRange = gFalse; - } else if (tok2 && tok3) { - n1 = strlen(tok1); - n2 = strlen(tok2); - n3 = strlen(tok3); + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "beginbfrange")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endbfrange")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endbfrange") || + !pst->getToken(tok3, sizeof(tok3), &n3) || + !strcmp(tok3, "endbfrange")) { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); + break; + } if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' && n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>' && tok3[0] == '<' && tok3[n3 - 1] == '>')) { - error(-1, "Illegal line in bfrange block in ToUnicode CMap"); + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); continue; } tok1[n1 - 1] = tok2[n2 - 1] = tok3[n3 - 1] = '\0'; if (sscanf(tok1 + 1, "%x", &code1) != 1 || sscanf(tok2 + 1, "%x", &code2) != 1) { - error(-1, "Illegal line in bfrange block in ToUnicode CMap"); + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); continue; } if (code2 >= mapLen) { oldLen = mapLen; @@ -213,9 +223,9 @@ void CharCodeToUnicode::parseCMap1(char *(*getLineFunc)(char *, int, void *), } } if (n3 == 6) { if (sscanf(tok3 + 1, "%x", &u) != 1) { - error(-1, "Illegal line in bfrange block in ToUnicode CMap"); + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); continue; } for (; code1 <= code2; ++code1) { map[code1] = u++; @@ -233,36 +243,22 @@ void CharCodeToUnicode::parseCMap1(char *(*getLineFunc)(char *, int, void *), for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) { strncpy(uHex, tok3 + 1 + j*4, 4); uHex[4] = '\0'; if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) { - error(-1, "Illegal line in bfrange block in ToUnicode CMap"); + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); } } sMap[sMapLen].u[sMap[sMapLen].len - 1] += i; ++sMapLen; } } - } else { - error(-1, "Illegal bfrange block in ToUnicode CMap"); } - } else if (tok2 && !strcmp(tok2, "usecmap")) { - if (tok1[0] == '/') { - name = new GString(tok1 + 1); - if ((f = globalParams->findToUnicodeFile(name))) { - parseCMap1((char *(*)(char *, int, void *))&getLine, f, nBits); - fclose(f); - } else { - error(-1, "Couldn't find ToUnicode CMap file for '%s'", - name->getCString()); - } - delete name; - } - } else if (tok2 && !strcmp(tok2, "beginbfchar")) { - inBFChar = gTrue; - } else if (tok2 && !strcmp(tok2, "beginbfrange")) { - inBFRange = gTrue; + pst->getToken(tok1, sizeof(tok1), &n1); + } else { + strcpy(tok1, tok2); } } + delete pst; } CharCodeToUnicode::CharCodeToUnicode(GString *collectionA) { CharCode i; diff --git a/noncore/unsupported/qpdf/xpdf/CharCodeToUnicode.h b/noncore/unsupported/qpdf/xpdf/CharCodeToUnicode.h index c811d72..06916c8 100644 --- a/noncore/unsupported/qpdf/xpdf/CharCodeToUnicode.h +++ b/noncore/unsupported/qpdf/xpdf/CharCodeToUnicode.h @@ -3,9 +3,9 @@ // CharCodeToUnicode.h // // Mapping from character codes to Unicode. // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef CHARCODETOUNICODE_H @@ -49,10 +49,9 @@ public: int mapToUnicode(CharCode c, Unicode *u, int size); private: - void parseCMap1(char *(*getLineFunc)(char *, int, void *), - void *data, int nBits); + void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits); CharCodeToUnicode(GString *collectionA); CharCodeToUnicode(GString *collectionA, Unicode *mapA, CharCode mapLenA, GBool copyMap, CharCodeToUnicodeString *sMapA, int sMapLenA); diff --git a/noncore/unsupported/qpdf/xpdf/CharTypes.h b/noncore/unsupported/qpdf/xpdf/CharTypes.h index 8938be5..bae2f26 100644 --- a/noncore/unsupported/qpdf/xpdf/CharTypes.h +++ b/noncore/unsupported/qpdf/xpdf/CharTypes.h @@ -1,9 +1,9 @@ //======================================================================== // // CharTypes.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef CHARTYPES_H diff --git a/noncore/unsupported/qpdf/xpdf/Decrypt.cc b/noncore/unsupported/qpdf/xpdf/Decrypt.cc index 2def802..8de4091 100644 --- a/noncore/unsupported/qpdf/xpdf/Decrypt.cc +++ b/noncore/unsupported/qpdf/xpdf/Decrypt.cc @@ -1,9 +1,9 @@ //======================================================================== // // Decrypt.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ diff --git a/noncore/unsupported/qpdf/xpdf/Decrypt.h b/noncore/unsupported/qpdf/xpdf/Decrypt.h index 1bdb2b7..52afb2f 100644 --- a/noncore/unsupported/qpdf/xpdf/Decrypt.h +++ b/noncore/unsupported/qpdf/xpdf/Decrypt.h @@ -1,9 +1,9 @@ //======================================================================== // // Decrypt.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef DECRYPT_H diff --git a/noncore/unsupported/qpdf/xpdf/Dict.cc b/noncore/unsupported/qpdf/xpdf/Dict.cc index 1a49ca5..5eb077e 100644 --- a/noncore/unsupported/qpdf/xpdf/Dict.cc +++ b/noncore/unsupported/qpdf/xpdf/Dict.cc @@ -1,9 +1,9 @@ //======================================================================== // // Dict.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ diff --git a/noncore/unsupported/qpdf/xpdf/Dict.h b/noncore/unsupported/qpdf/xpdf/Dict.h index c4f1ea5..b994514 100644 --- a/noncore/unsupported/qpdf/xpdf/Dict.h +++ b/noncore/unsupported/qpdf/xpdf/Dict.h @@ -1,9 +1,9 @@ //======================================================================== // // Dict.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef DICT_H diff --git a/noncore/unsupported/qpdf/xpdf/DisplayFontTable.h b/noncore/unsupported/qpdf/xpdf/DisplayFontTable.h index 048e25d..8e73486 100644 --- a/noncore/unsupported/qpdf/xpdf/DisplayFontTable.h +++ b/noncore/unsupported/qpdf/xpdf/DisplayFontTable.h @@ -1,18 +1,18 @@ //======================================================================== // // DisplayFontTable.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== static struct { char *name; char *xlfd; char *encoding; } displayFontTab[] = { -#if _NO_USE_FOR_QPE +#if 0 {"Courier", "-*-courier-medium-r-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, {"Courier-Bold", "-*-courier-bold-r-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, {"Courier-BoldOblique", "-*-courier-bold-o-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, {"Courier-Oblique", "-*-courier-medium-o-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, @@ -26,6 +26,6 @@ static struct { {"Times-Italic", "-*-times-medium-i-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, {"Times-Roman", "-*-times-medium-r-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, {"ZapfDingbats", "-*-zapfdingbats-medium-r-normal-*-%s-*-*-*-*-*-*-*", "ZapfDingbats"}, #endif - {NULL} + {NULL,0,0} }; diff --git a/noncore/unsupported/qpdf/xpdf/Error.cc b/noncore/unsupported/qpdf/xpdf/Error.cc index 8763846..3eae5c9 100644 --- a/noncore/unsupported/qpdf/xpdf/Error.cc +++ b/noncore/unsupported/qpdf/xpdf/Error.cc @@ -1,9 +1,9 @@ //======================================================================== // // Error.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ diff --git a/noncore/unsupported/qpdf/xpdf/Error.h b/noncore/unsupported/qpdf/xpdf/Error.h index 151e961..77801c5 100644 --- a/noncore/unsupported/qpdf/xpdf/Error.h +++ b/noncore/unsupported/qpdf/xpdf/Error.h @@ -1,9 +1,9 @@ //======================================================================== // // Error.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef ERROR_H diff --git a/noncore/unsupported/qpdf/xpdf/ErrorCodes.h b/noncore/unsupported/qpdf/xpdf/ErrorCodes.h new file mode 100644 index 0000000..4e0d38a --- a/dev/null +++ b/noncore/unsupported/qpdf/xpdf/ErrorCodes.h @@ -0,0 +1,24 @@ +//======================================================================== +// +// ErrorCodes.h +// +// Copyright 2002 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef ERRORCODES_H +#define ERRORCODES_H + +#define errNone 0 // no error + +#define errOpenFile 1 // couldn't open the PDF file + +#define errBadCatalog 2 // couldn't read the page catalog + +#define errDamaged 3 // PDF file was damaged and couldn't be + // repaired + +#define errEncrypted 4 // file was encrypted and password was + // incorrect or not supplied + +#endif diff --git a/noncore/unsupported/qpdf/xpdf/FontEncodingTables.cc b/noncore/unsupported/qpdf/xpdf/FontEncodingTables.cc index 12a1a27..bd5f9cf 100644 --- a/noncore/unsupported/qpdf/xpdf/FontEncodingTables.cc +++ b/noncore/unsupported/qpdf/xpdf/FontEncodingTables.cc @@ -1,9 +1,9 @@ //======================================================================== // // FontEncodingTables.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #include <aconf.h> diff --git a/noncore/unsupported/qpdf/xpdf/FontEncodingTables.h b/noncore/unsupported/qpdf/xpdf/FontEncodingTables.h index 4646a43..deee0a8 100644 --- a/noncore/unsupported/qpdf/xpdf/FontEncodingTables.h +++ b/noncore/unsupported/qpdf/xpdf/FontEncodingTables.h @@ -1,9 +1,9 @@ //======================================================================== // // FontEncodingTables.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef FONTENCODINGTABLES_H diff --git a/noncore/unsupported/qpdf/xpdf/Function.cc b/noncore/unsupported/qpdf/xpdf/Function.cc index 815cc89..ebf3718 100644 --- a/noncore/unsupported/qpdf/xpdf/Function.cc +++ b/noncore/unsupported/qpdf/xpdf/Function.cc @@ -1,9 +1,9 @@ //======================================================================== // // Function.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -414,9 +414,8 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { GBool hasN; int i; ok = gFalse; - hasN = gFalse; //----- initialize the generic stuff if (!init(dict)) { goto err1; @@ -424,8 +423,9 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { if (m != 1) { error(-1, "Exponential function with more than one input"); goto err1; } + hasN = hasRange; //----- default values for (i = 0; i < funcMaxOutputs; ++i) { c0[i] = 0; @@ -435,8 +435,9 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { //----- C0 if (dict->lookup("C0", &obj1)->isArray()) { if (!hasN) { n = obj1.arrayGetLength(); + hasN = gTrue; } else if (obj1.arrayGetLength() != n) { error(-1, "Function's C0 array is wrong length"); goto err2; } @@ -455,8 +456,9 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { //----- C1 if (dict->lookup("C1", &obj1)->isArray()) { if (!hasN) { n = obj1.arrayGetLength(); + hasN = gTrue; } else if (obj1.arrayGetLength() != n) { error(-1, "Function's C1 array is wrong length"); goto err2; } @@ -479,8 +481,15 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { } e = obj1.getNum(); obj1.free(); + // this isn't supposed to happen, but I've run into (broken) PDF + // files where it does + if (!hasN) { + error(-1, "Exponential function does not define number of output values"); + n = 1; + } + ok = gTrue; return; err3: diff --git a/noncore/unsupported/qpdf/xpdf/Function.h b/noncore/unsupported/qpdf/xpdf/Function.h index a223359..deb4630 100644 --- a/noncore/unsupported/qpdf/xpdf/Function.h +++ b/noncore/unsupported/qpdf/xpdf/Function.h @@ -1,9 +1,9 @@ //======================================================================== // // Function.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef FUNCTION_H diff --git a/noncore/unsupported/qpdf/xpdf/Gfx.cc b/noncore/unsupported/qpdf/xpdf/Gfx.cc index c19971c..17d613e 100644 --- a/noncore/unsupported/qpdf/xpdf/Gfx.cc +++ b/noncore/unsupported/qpdf/xpdf/Gfx.cc @@ -1,9 +1,9 @@ //======================================================================== // // Gfx.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -29,8 +29,13 @@ #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 //------------------------------------------------------------------------ @@ -39,8 +44,14 @@ // 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 //------------------------------------------------------------------------ @@ -373,8 +384,9 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, fouble dpi, GBool printCommandsA) { int i; xref = xrefA; + subPage = gFalse; printCommands = printCommandsA; // start the resource stack res = new GfxResources(xref, resDict, NULL); @@ -404,23 +416,56 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, fouble dpi, 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) { Object obj2; @@ -448,13 +493,13 @@ 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()) { @@ -475,11 +520,11 @@ void Gfx::go(GBool topLevel) { args[i].free(); numArgs = 0; // periodically update display - if (++numCmds == 200) { + if (++updateLevel >= 20000) { out->dump(); - numCmds = 0; + updateLevel = 0; } // got an argument - save it } else if (numArgs < maxArgs) { @@ -518,9 +563,9 @@ void Gfx::go(GBool topLevel) { args[i].free(); } // update display - if (topLevel && numCmds > 0) { + if (topLevel && updateLevel > 0) { out->dump(); } } @@ -1137,9 +1182,9 @@ void Gfx::doPatternFill(GBool eoFill) { fouble xMin, yMin, xMax, yMax, x, y, x1, y1; fouble cxMin, cyMin, cxMax, cyMax; int xi0, yi0, xi1, yi1, xi, yi; fouble *ctm, *btm, *ptm; - fouble m[6], ictm[6], m1[6], im[6], imb[6]; + fouble m[6], ictm[6], m1[6], imb[6]; fouble det; fouble xstep, ystep; int i; @@ -1188,17 +1233,8 @@ void Gfx::doPatternFill(GBool eoFill) { m[3] = m1[2] * ictm[1] + m1[3] * ictm[3]; 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; - // 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; @@ -1330,8 +1366,11 @@ void Gfx::opShFill(Object args[], int numArgs) { switch (shading->getType()) { case 2: doAxialShFill((GfxAxialShading *)shading); break; + case 3: + doRadialShFill((GfxRadialShading *)shading); + break; } // restore graphics state state = state->restore(); @@ -1342,11 +1381,8 @@ void Gfx::opShFill(Object args[], int numArgs) { void Gfx::doAxialShFill(GfxAxialShading *shading) { fouble xMin, yMin, xMax, yMax; fouble x0, y0, x1, y1; - fouble det; - fouble *ctm; - fouble ictm[6]; fouble dx, dy, mul; fouble tMin, tMax, t, tx, ty; fouble s[4], sMin, sMax, tmp; fouble ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1; @@ -1356,56 +1392,10 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { GfxColor color0, color1; int nComps; int i, j, k, kk; - // get clip region bbox and transform to current user space - state->getClipBBox(&x0, &y0, &x1, &y1); - 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; - xMin = xMax = x0 * ictm[0] + y0 * ictm[2] + ictm[4]; - yMin = yMax = x0 * ictm[1] + y0 * ictm[3] + ictm[5]; - tx = x0 * ictm[0] + y1 * ictm[2] + ictm[4]; - ty = x0 * ictm[1] + y1 * ictm[3] + ictm[5]; - if (tx < xMin) { - xMin = tx; - } else if (tx > xMax) { - xMax = tx; - } - if (ty < yMin) { - yMin = ty; - } else if (ty > yMax) { - yMax = ty; - } - tx = x1 * ictm[0] + y0 * ictm[2] + ictm[4]; - ty = x1 * ictm[1] + y0 * ictm[3] + ictm[5]; - if (tx < xMin) { - xMin = tx; - } else if (tx > xMax) { - xMax = tx; - } - if (ty < yMin) { - yMin = ty; - } else if (ty > yMax) { - yMax = ty; - } - tx = x1 * ictm[0] + y1 * ictm[2] + ictm[4]; - ty = x1 * ictm[1] + y1 * ictm[3] + ictm[5]; - if (tx < xMin) { - xMin = tx; - } else if (tx > xMax) { - xMax = tx; - } - if (ty < yMin) { - yMin = ty; - } else if (ty > yMax) { - yMax = ty; - } + // 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); @@ -1618,8 +1608,204 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { i = next[i]; } } +void Gfx::doRadialShFill(GfxRadialShading *shading) { + fouble sMin, sMax, xMin, yMin, xMax, yMax; + fouble x0, y0, r0, x1, y1, r1, t0, t1; + int nComps; + GfxColor colorA, colorB; + fouble xa, ya, xb, yb, ra, rb; + fouble ta, tb, sa, sb; + int ia, ib, k, n; + fouble *ctm; + fouble 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 + ((fouble)ib / (fouble)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 + ((fouble)ib / (fouble)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 = ((fouble)k / (fouble)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 = ((fouble)k / (fouble)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() && clip != clipNone) { state->clip(); if (clip == clipNormal) { @@ -1799,19 +1985,25 @@ 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()); } else { @@ -1822,33 +2014,35 @@ void Gfx::opShowSpaceText(Object args[], int numArgs) { } void Gfx::doShowText(GString *s) { GfxFont *font; + int wMode; fouble riseX, riseY; CharCode code; Unicode u[8]; - fouble dx, dy, dx2, dy2, tdx, tdy; + fouble x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy; fouble originX, originY, tOriginX, tOriginY; + fouble oldCTM[6], newCTM[6]; + fouble *mat; + Object charProc; + Dict *resDict; + Parser *oldParser; char *p; - int len, n, uLen, nChars, nSpaces; + int len, n, uLen, nChars, nSpaces, i; if (fontChanged) { out->updateFont(state); fontChanged = gFalse; } font = state->getFont(); + wMode = font->getWMode(); -#if 0 //~type3 - fouble x, y; - fouble oldCTM[6], newCTM[6]; - fouble *mat; - Object charProc; - Parser *oldParser; - int i; - - //~ also check out->renderType3() - if (font->getType() == fontType3) { + if (out->useDrawChar()) { out->beginString(state, s); + } + + // handle a Type 3 char + if (font->getType() == fontType3 && out->interpretType3Chars()) { mat = state->getCTM(); for (i = 0; i < 6; ++i) { oldCTM[i] = mat[i]; } @@ -1866,62 +2060,79 @@ void Gfx::doShowText(GString *s) { 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); - state->transform(state->getCurX() + riseX, state->getCurY() + riseY, - &x, &y); - out->saveState(state); - state = state->save(); - state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y); - //~ out->updateCTM(???) - ((Gfx8BitFont *)font)->getCharProc(code, &charProc); - if (charProc.isStream()) { - display(&charProc, gFalse); - } else { - error(getPos(), "Missing or bad Type3 CharProc entry"); - } - state = state->restore(); - out->restoreState(state); - charProc.free(); dx = dx * state->getFontSize() + state->getCharSpace(); if (n == 1 && *p == ' ') { dx += state->getWordSpace(); } dx *= state->getHorizScaling(); dy *= state->getFontSize(); state->textTransformDelta(dx, dy, &tdx, &tdy); - state->shift(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"); + } + out->endType3Char(state); + if (resDict) { + popResources(); + } + charProc.free(); + } + 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; - out->endString(state); - return; - } -#endif - if (out->useDrawChar()) { + } else if (out->useDrawChar()) { state->textTransformDelta(0, state->getRise(), &riseX, &riseY); - out->beginString(state, s); 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(); + 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(); + } + dx *= state->getHorizScaling(); + dy *= state->getFontSize(); } - dx *= state->getHorizScaling(); - dy *= state->getFontSize(); state->textTransformDelta(dx, dy, &tdx, &tdy); originX *= state->getFontSize(); originY *= state->getFontSize(); state->textTransformDelta(originX, originY, &tOriginX, &tOriginY); @@ -1930,9 +2141,8 @@ void Gfx::doShowText(GString *s) { state->shift(tdx, tdy); p += n; len -= n; } - out->endString(state); } else { dx = dy = 0; p = s->getCString(); @@ -1950,25 +2160,38 @@ void Gfx::doShowText(GString *s) { ++nChars; p += n; len -= n; } - dx = dx * state->getFontSize() - + nChars * state->getCharSpace() - + nSpaces * state->getWordSpace(); - dx *= state->getHorizScaling(); - dy *= state->getFontSize(); + if (wMode) { + dx *= state->getFontSize(); + dy = dy * state->getFontSize() + + nChars * state->getCharSpace() + + nSpaces * state->getWordSpace(); + } else { + 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); } + + if (out->useDrawChar()) { + out->endString(state); + } + + updateLevel += 10 * s->getLength(); } //------------------------------------------------------------------------ // XObject operators //------------------------------------------------------------------------ void Gfx::opXObject(Object args[], int numArgs) { - Object obj1, obj2, refObj; + Object obj1, obj2, obj3, refObj; #if OPI_SUPPORT Object opiDict; #endif @@ -1992,8 +2215,12 @@ void Gfx::opXObject(Object args[], int numArgs) { doImage(&refObj, obj1.getStream(), gFalse); 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 { error(getPos(), "XObject subtype is missing or wrong type"); @@ -2147,8 +2374,13 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { maskObj.free(); } + if ((i = width * height) > 1000) { + i = 1000; + } + updateLevel += i; + return; err2: obj1.free(); @@ -2214,21 +2446,24 @@ void Gfx::doForm(Object *str) { resObj.free(); } -void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin, - fouble xMax, fouble yMax) { +void Gfx::doAnnot(Object *str, fouble xMin, fouble yMin, + fouble xMax, fouble yMax) { Dict *dict, *resDict; Object matrixObj, bboxObj, resObj; Object obj1; - fouble m[6], bbox[6]; - fouble sx, sy; + fouble m[6], bbox[6], ictm[6]; + fouble *ctm; + fouble formX0, formY0, formX1, formY1; + fouble annotX0, annotY0, annotX1, annotY1; + fouble 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(); error(getPos(), "Bad form bounding box"); @@ -2240,9 +2475,9 @@ void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin, obj1.free(); } bboxObj.free(); - // get matrix + // get the form matrix dict->lookup("Matrix", &matrixObj); if (matrixObj.isArray()) { for (i = 0; i < 6; ++i) { matrixObj.arrayGet(i, &obj1); @@ -2255,18 +2490,66 @@ void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin, m[4] = 0; m[5] = 0; } 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() : (Dict *)NULL; @@ -2280,13 +2563,12 @@ void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin, void Gfx::doForm1(Object *str, Dict *resDict, fouble *matrix, fouble *bbox) { Parser *oldParser; fouble oldBaseMatrix[6]; - GfxResources *resPtr; int i; // push new resources on stack - res = new GfxResources(xref, resDict, res); + pushResources(resDict); // save current graphics state out->saveState(state); state = state->save(); @@ -2331,13 +2613,23 @@ void Gfx::doForm1(Object *str, Dict *resDict, fouble *matrix, fouble *bbox) { state = state->restore(); 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; } //------------------------------------------------------------------------ // in-line image operators @@ -2377,21 +2669,26 @@ Stream *Gfx::buildImageStream() { 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 str = new EmbedStream(parser->getStream(), &dict); @@ -2412,13 +2709,15 @@ void Gfx::opEndImage(Object args[], int numArgs) { // type 3 font operators //------------------------------------------------------------------------ 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()); } //------------------------------------------------------------------------ // compatibility operators diff --git a/noncore/unsupported/qpdf/xpdf/Gfx.h b/noncore/unsupported/qpdf/xpdf/Gfx.h index be5f2c2..2ecfb24 100644 --- a/noncore/unsupported/qpdf/xpdf/Gfx.h +++ b/noncore/unsupported/qpdf/xpdf/Gfx.h @@ -1,9 +1,9 @@ //======================================================================== // // Gfx.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef GFX_H @@ -26,8 +26,9 @@ class GfxFontDict; class GfxFont; class GfxPattern; class GfxShading; class GfxAxialShading; +class GfxRadialShading; class GfxState; class Gfx; struct PDFRectangle; @@ -96,23 +97,33 @@ public: Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, fouble dpi, PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate, GBool printCommandsA); - // Destructor. + // Constructor for a sub-page object. + Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, + PDFRectangle *box, GBool crop, PDFRectangle *cropBox); + ~Gfx(); // Interpret a stream or array of streams. void display(Object *obj, GBool topLevel = gTrue); - void doWidgetForm(Object *str, fouble xMin, fouble yMin, - fouble xMax, fouble yMax); + // Display an annotation, given its appearance (a Form XObject) and + // bounding box (in default user space). + void doAnnot(Object *str, fouble xMin, fouble yMin, + fouble xMax, fouble 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 GfxClipType clip; // do a clip? @@ -178,8 +189,9 @@ private: void opCloseEOFillStroke(Object args[], int numArgs); void doPatternFill(GBool eoFill); void opShFill(Object args[], int numArgs); void doAxialShFill(GfxAxialShading *shading); + void doRadialShFill(GfxRadialShading *shading); void doEndPath(); // path clipping operators void opClip(Object args[], int numArgs); diff --git a/noncore/unsupported/qpdf/xpdf/GfxFont.cc b/noncore/unsupported/qpdf/xpdf/GfxFont.cc index 518f97b..8d722d6 100644 --- a/noncore/unsupported/qpdf/xpdf/GfxFont.cc +++ b/noncore/unsupported/qpdf/xpdf/GfxFont.cc @@ -1,9 +1,9 @@ //======================================================================== // // GfxFont.cc // -// Copyright 1996-2001 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -453,15 +453,26 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, } } obj1.free(); - // get Type3 font definition + // get Type 3 bounding box, font definition, and resources if (type == fontType3) { - fontDict->lookup("CharProcs", &charProcs); - if (!charProcs.isDict()) { + 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 ----- @@ -512,25 +523,30 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, 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 || type == fontTrueType) && + if ((type == fontType1 || type == fontType1C) && (extFontFile || embFontID.num >= 0)) { if (extFontFile) { buf = readExtFontFile(&len); } else { buf = readEmbFontFile(xref, &len); } if (buf) { #if 0 + 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 if (type == fontType1C) { - fontFile = new Type1CFontFile(buf, len); } else { - fontFile = new TrueTypeFontFile(buf, len); + fontFile = new Type1CFontFile(buf, len); } if (fontFile->getName()) { if (embFontName) { delete embFontName; @@ -568,8 +584,9 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // 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()) { @@ -635,10 +652,11 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, } } // pass 2: try to fill in the missing chars, looking for names of - // the form 'Axx', 'xx', 'Ann', or 'nn', where 'A' is any letter, - // 'xx' is two hex digits, and 'nn' is 2-4 decimal digits + // 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 = enc[code]) && !toUnicode[code] && strcmp(charName, ".notdef")) { @@ -655,8 +673,11 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, 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; } @@ -683,12 +704,16 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, obj1.free(); mul = (type == fontType3) ? fontMat[0] : fouble(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(); } @@ -751,8 +776,11 @@ Gfx8BitFont::~Gfx8BitFont() { ctu->decRefCnt(); if (charProcs.isDict()) { charProcs.free(); } + if (resources.isDict()) { + resources.free(); + } } int Gfx8BitFont::getNextChar(char *s, int len, CharCode *code, Unicode *u, int uSize, int *uLen, @@ -770,8 +798,12 @@ 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 { @@ -779,8 +811,12 @@ Object *Gfx8BitFont::getCharProc(int code, Object *proc) { } return proc; } +Dict *Gfx8BitFont::getResources() { + return resources.isDict() ? resources.getDict() : (Dict *)NULL; +} + //------------------------------------------------------------------------ // GfxCIDFont //------------------------------------------------------------------------ @@ -1185,8 +1221,12 @@ int GfxCIDFont::getNextChar(char *s, int len, CharCode *code, return n; } +int GfxCIDFont::getWMode() { + return cMap ? cMap->getWMode() : 0; +} + CharCodeToUnicode *GfxCIDFont::getToUnicode() { ctu->incRefCnt(); return ctu; } @@ -1215,9 +1255,9 @@ GfxFontDict::GfxFontDict(XRef *xref, Dict *fontDict) { 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(); obj2.free(); diff --git a/noncore/unsupported/qpdf/xpdf/GfxFont.h b/noncore/unsupported/qpdf/xpdf/GfxFont.h index b1aa952..8e9fe38 100644 --- a/noncore/unsupported/qpdf/xpdf/GfxFont.h +++ b/noncore/unsupported/qpdf/xpdf/GfxFont.h @@ -1,9 +1,9 @@ //======================================================================== // // GfxFont.h // -// Copyright 1996-2001 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef GFXFONT_H @@ -112,10 +112,9 @@ public: { *embID = embFontID; return embFontID.num >= 0; } // 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. GString *getExtFontFile() { return extFontFile; } @@ -136,8 +135,11 @@ public: // Return the ascent and descent values. fouble getAscent() { return ascent; } fouble 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); @@ -154,9 +156,9 @@ public: protected: void readFontDescriptor(XRef *xref, Dict *fontDict); CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits); - void GfxFont::findExtFontFile(); + void findExtFontFile(); GString *tag; // PDF font tag Ref id; // reference (used as unique ID) GString *name; // font name @@ -165,9 +167,9 @@ protected: GString *embFontName; // name of embedded font Ref embFontID; // ref to embedded font file stream GString *extFontFile; // external font file name fouble fontMat[6]; // font matrix (Type 3 only) - fouble fontBBox[4]; // font bounding box + fouble fontBBox[4]; // font bounding box (Type 3 only) fouble missingWidth; // "default" width fouble ascent; // max height above baseline fouble descent; // max depth below baseline GBool ok; @@ -203,20 +205,27 @@ public: // Get width of a character or string. fouble getWidth(Guchar c) { return widths[c]; } + // Return the Type 3 CharProc dictionary, or NULL if none. + Dict *getCharProcs(); + // Return the Type 3 CharProc for the character associated with <code>. Object *getCharProc(int code, Object *proc); + // Return the Type 3 Resources dictionary, or NULL if none. + Dict *getResources(); + private: 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; fouble widths[256]; // character widths - Object charProcs; // Type3 CharProcs dictionary + Object charProcs; // Type 3 CharProcs dictionary + Object resources; // Type 3 Resources dictionary }; //------------------------------------------------------------------------ // GfxCIDFont @@ -235,8 +244,11 @@ public: virtual int getNextChar(char *s, int len, CharCode *code, Unicode *u, int uSize, int *uLen, fouble *dx, fouble *dy, fouble *ox, fouble *oy); + // Return the writing mode (0=horizontal, 1=vertical). + virtual int getWMode(); + // Return the Unicode map. CharCodeToUnicode *getToUnicode(); // Get the collection name (<registry>-<ordering>). diff --git a/noncore/unsupported/qpdf/xpdf/GfxState.cc b/noncore/unsupported/qpdf/xpdf/GfxState.cc index af4e0d4..befd45a 100644 --- a/noncore/unsupported/qpdf/xpdf/GfxState.cc +++ b/noncore/unsupported/qpdf/xpdf/GfxState.cc @@ -1,9 +1,9 @@ //======================================================================== // // GfxState.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -407,11 +407,24 @@ void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, fouble *gray) { - 0.114 * color->c[2]); } 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])); + fouble 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) { cmyk->c = clip01(color->c[0]); @@ -1267,12 +1280,8 @@ GfxShading *GfxShading::parse(Object *obj) { goto err1; } typeA = obj1.getInt(); obj1.free(); - if (typeA != 2) { - error(-1, "Unimplemented shading type %d", typeA); - goto err1; - } obj->dictLookup("ColorSpace", &obj1); if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) { error(-1, "Bad color space in shading dictionary"); @@ -1316,9 +1325,19 @@ GfxShading *GfxShading::parse(Object *obj) { } } obj1.free(); - shading = GfxAxialShading::parse(obj->getDict()); + 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; @@ -1456,8 +1475,130 @@ void GfxAxialShading::getColor(fouble t, GfxColor *color) { } } //------------------------------------------------------------------------ +// GfxRadialShading +//------------------------------------------------------------------------ + +GfxRadialShading::GfxRadialShading(fouble x0A, fouble y0A, fouble r0A, + fouble x1A, fouble y1A, fouble r1A, + fouble t0A, fouble t1A, + Function **funcsA, int nFuncsA, + GBool extend0A, GBool extend1A) { + int 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]; + } + extend0 = extend0A; + extend1 = extend1A; +} + +GfxRadialShading::~GfxRadialShading() { + int i; + + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxRadialShading *GfxRadialShading::parse(Dict *dict) { + fouble x0A, y0A, r0A, x1A, y1A, r1A; + fouble t0A, t1A; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + GBool extend0A, extend1A; + Object obj1, obj2; + int i; + + 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(); + + 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(); + + 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; + } + obj2.free(); + } + } else { + nFuncsA = 1; + if (!(funcsA[0] = Function::parse(&obj1))) { + obj1.free(); + goto err1; + } + } + obj1.free(); + + 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(); + + return new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A, + funcsA, nFuncsA, extend0A, extend1A); + + err1: + return NULL; +} + +void GfxRadialShading::getColor(fouble t, GfxColor *color) { + int i; + + for (i = 0; i < nFuncs; ++i) { + funcs[i]->transform(&t, &color->c[i]); + } +} + +//------------------------------------------------------------------------ // GfxImageColorMap //------------------------------------------------------------------------ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, @@ -1917,8 +2058,69 @@ GfxState::GfxState(GfxState *state) { } saved = NULL; } +void GfxState::getUserClipBBox(fouble *xMin, fouble *yMin, + fouble *xMax, fouble *yMax) { + fouble ictm[6]; + fouble 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; +} + fouble GfxState::transformWidth(fouble w) { fouble x, y; x = ctm[0] + ctm[2]; @@ -1945,29 +2147,50 @@ void GfxState::getFontTransMat(fouble *m11, fouble *m12, } void GfxState::setCTM(fouble a, fouble b, fouble c, fouble d, fouble e, fouble 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] > fouble(1e3)) { + ctm[i] = fouble(1e3); + } else if (ctm[i] < -fouble(1e3)) { + ctm[i] = -fouble(1e3); + } + } } void GfxState::concatCTM(fouble a, fouble b, fouble c, fouble d, fouble e, fouble f) { fouble a1 = ctm[0]; fouble b1 = ctm[1]; fouble c1 = ctm[2]; fouble d1 = ctm[3]; + int i; ctm[0] = a * a1 + b * c1; ctm[1] = a * b1 + b * d1; ctm[2] = c * a1 + d * c1; 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] > fouble(1e3)) { + ctm[i] = fouble(1e3); + } else if (ctm[i] < -fouble(1e3)) { + ctm[i] = -fouble(1e3); + } + } } void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) { if (fillColorSpace) { @@ -2050,12 +2273,12 @@ void GfxState::clip() { clipYMax = yMax; } } -void GfxState::textShift(fouble tx) { +void GfxState::textShift(fouble tx, fouble ty) { fouble dx, dy; - textTransformDelta(tx, 0, &dx, &dy); + textTransformDelta(tx, ty, &dx, &dy); curX += dx; curY += dy; } @@ -2094,4 +2317,5 @@ GfxState *GfxState::restore() { } return oldState; } + diff --git a/noncore/unsupported/qpdf/xpdf/GfxState.h b/noncore/unsupported/qpdf/xpdf/GfxState.h index 7fe16ea..328f9a8 100644 --- a/noncore/unsupported/qpdf/xpdf/GfxState.h +++ b/noncore/unsupported/qpdf/xpdf/GfxState.h @@ -1,9 +1,9 @@ //======================================================================== // // GfxState.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef GFXSTATE_H @@ -567,8 +567,42 @@ private: GBool extend0, extend1; }; //------------------------------------------------------------------------ +// GfxRadialShading +//------------------------------------------------------------------------ + +class GfxRadialShading: public GfxShading { +public: + + GfxRadialShading(fouble x0A, fouble y0A, fouble r0A, + fouble x1A, fouble y1A, fouble r1A, + fouble t0A, fouble t1A, + Function **funcsA, int nFuncsA, + GBool extend0A, GBool extend1A); + virtual ~GfxRadialShading(); + + static GfxRadialShading *parse(Dict *dict); + + void getCoords(fouble *x0A, fouble *y0A, fouble *r0A, + fouble *x1A, fouble *y1A, fouble *r1A) + { *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; } + fouble getDomain0() { return t0; } + fouble getDomain1() { return t1; } + void getColor(fouble t, GfxColor *color); + GBool getExtend0() { return extend0; } + GBool getExtend1() { return extend1; } + +private: + + fouble x0, y0, r0, x1, y1, r1; + fouble t0, t1; + Function *funcs[gfxColorMaxComps]; + int nFuncs; + GBool extend0, extend1; +}; + +//------------------------------------------------------------------------ // GfxImageColorMap //------------------------------------------------------------------------ class GfxImageColorMap { @@ -782,8 +816,9 @@ public: fouble getCurX() { return curX; } fouble getCurY() { return curY; } void getClipBBox(fouble *xMin, fouble *yMin, fouble *xMax, fouble *yMax) { *xMin = clipXMin; *yMin = clipYMin; *xMax = clipXMax; *yMax = clipYMax; } + void getUserClipBBox(fouble *xMin, fouble *yMin, fouble *xMax, fouble *yMax); fouble getLineX() { return lineX; } fouble getLineY() { return lineY; } // Is there a current point/path? @@ -864,9 +899,9 @@ public: // Text position. void textMoveTo(fouble tx, fouble ty) { lineX = tx; lineY = ty; textTransform(tx, ty, &curX, &curY); } - void textShift(fouble tx); + void textShift(fouble tx, fouble ty); void shift(fouble dx, fouble dy); // Push/pop GfxState on/off stack. GfxState *save(); diff --git a/noncore/unsupported/qpdf/xpdf/GlobalParams.cc b/noncore/unsupported/qpdf/xpdf/GlobalParams.cc index 8be58a3..0bc908e 100644 --- a/noncore/unsupported/qpdf/xpdf/GlobalParams.cc +++ b/noncore/unsupported/qpdf/xpdf/GlobalParams.cc @@ -1,9 +1,9 @@ //======================================================================== // // GlobalParams.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -95,16 +95,22 @@ DisplayFontParam::~DisplayFontParam() { //------------------------------------------------------------------------ // PSFontParam //------------------------------------------------------------------------ -PSFontParam::PSFontParam(GString *pdfFontNameA, GString *psFontNameA) { +PSFontParam::PSFontParam(GString *pdfFontNameA, int wModeA, + GString *psFontNameA, GString *encodingA) { pdfFontName = pdfFontNameA; + wMode = wModeA; psFontName = psFontNameA; + encoding = encodingA; } PSFontParam::~PSFontParam() { delete pdfFontName; delete psFontName; + if (encoding) { + delete encoding; + } } //------------------------------------------------------------------------ // parsing @@ -114,19 +120,16 @@ GlobalParams::GlobalParams(char *cfgFileName) { UnicodeMap *map; DisplayFontParam *dfp; GString *fileName; FILE *f; - char buf[512]; - int line; - GList *tokens; - GString *cmd; - char *p1, *p2; int i; initBuiltinFontTables(); + // scan the encoding in reverse because we want the lowest-numbered + // index for each char name ('space' is encoded twice) macRomanReverseMap = new NameToCharCode(); - for (i = 0; i < 256; ++i) { + for (i = 255; i >= 0; --i) { if (macRomanEncoding[i]) { macRomanReverseMap->add(macRomanEncoding[i], (CharCode)i); } } @@ -138,8 +141,9 @@ GlobalParams::GlobalParams(char *cfgFileName) { cMapDirs = new GHash(gTrue); toUnicodeDirs = new GList(); displayFonts = new GHash(); displayCIDFonts = new GHash(); + displayNamedCIDFonts = new GHash(); #if HAVE_PAPER_H const struct paper *paperType; paperinit(); paperType = paperinfo(systempapername()); @@ -153,11 +157,16 @@ GlobalParams::GlobalParams(char *cfgFileName) { psDuplex = gFalse; psLevel = psLevel2; psFile = NULL; psFonts = new GHash(); + psNamedFonts16 = new GList(); + psFonts16 = new GList(); psEmbedType1 = gTrue; psEmbedTrueType = gTrue; + psEmbedCIDPostScript = gTrue; + psEmbedCIDTrueType = gTrue; psOPI = gFalse; + psASCIIHex = gFalse; textEncoding = new GString("Latin1"); #if defined(WIN32) textEOL = eolDOS; #elif defined(MACOS) @@ -165,8 +174,9 @@ GlobalParams::GlobalParams(char *cfgFileName) { #else textEOL = eolUnix; #endif fontDirs = new GList(); + initialZoom = new GString("1"); t1libControl = fontRastAALow; freetypeControl = fontRastAALow; urlCommand = NULL; mapNumericCharNames = gTrue; @@ -192,8 +202,10 @@ GlobalParams::GlobalParams(char *cfgFileName) { zapfDingbatsUnicodeMapLen); residentUnicodeMaps->add(map->getEncodingName(), map); map = new UnicodeMap("UTF-8", &mapUTF8); residentUnicodeMaps->add(map->getEncodingName(), map); + map = new UnicodeMap("UCS-2", &mapUCS2); + residentUnicodeMaps->add(map->getEncodingName(), map); // default displayFonts table for (i = 0; displayFontTab[i].name; ++i) { dfp = new DisplayFontParam(displayFontTab[i].name, @@ -218,8 +230,9 @@ GlobalParams::GlobalParams(char *cfgFileName) { } } if (!f) { #if defined(WIN32) && !defined(__CYGWIN32__) + char buf[512]; i = GetModuleFileName(NULL, buf, sizeof(buf)); if (i <= 0 || i >= sizeof(buf)) { // error or path too long for buffer - just use the current dir buf[i] = '\0'; @@ -233,100 +246,143 @@ GlobalParams::GlobalParams(char *cfgFileName) { delete fileName; } } if (f) { - line = 1; - while (fgets(buf, sizeof(buf) - 1, f)) { - - // break the line into tokens - tokens = new GList(); - p1 = buf; - while (*p1) { - for (; *p1 && isspace(*p1); ++p1) ; - if (!*p1) { - break; - } - if (*p1 == '"' || *p1 == '\'') { - for (p2 = p1 + 1; *p2 && *p2 != *p1; ++p2) ; - ++p1; - } else { - for (p2 = p1 + 1; *p2 && !isspace(*p2); ++p2) ; - } - tokens->append(new GString(p1, p2 - p1)); - p1 = p2 + 1; + parseFile(fileName, f); + delete fileName; + } +} + +void GlobalParams::parseFile(GString *fileName, FILE *f) { + int line; + GList *tokens; + GString *cmd, *incFile; + char *p1, *p2; + char buf[512]; + FILE *f2; + + line = 1; + while (fgets(buf, sizeof(buf) - 1, f)) { + + // break the line into tokens + tokens = new GList(); + p1 = buf; + while (*p1) { + for (; *p1 && isspace(*p1); ++p1) ; + if (!*p1) { + break; + } + if (*p1 == '"' || *p1 == '\'') { + for (p2 = p1 + 1; *p2 && *p2 != *p1; ++p2) ; + ++p1; + } else { + for (p2 = p1 + 1; *p2 && !isspace(*p2); ++p2) ; } + tokens->append(new GString(p1, p2 - p1)); + p1 = p2 + 1; + } - if (tokens->getLength() > 0 && - ((GString *)tokens->get(0))->getChar(0) != '#') { - cmd = (GString *)tokens->get(0); - if (!cmd->cmp("nameToUnicode")) { - parseNameToUnicode(tokens, fileName, line); - } else if (!cmd->cmp("cidToUnicode")) { - parseCIDToUnicode(tokens, fileName, line); - } else if (!cmd->cmp("unicodeMap")) { - parseUnicodeMap(tokens, fileName, line); - } else if (!cmd->cmp("cMapDir")) { - parseCMapDir(tokens, fileName, line); - } else if (!cmd->cmp("toUnicodeDir")) { - parseToUnicodeDir(tokens, fileName, line); - } else if (!cmd->cmp("displayFontX")) { - parseDisplayFont(tokens, gFalse, displayFontX, fileName, line); - } else if (!cmd->cmp("displayFontT1")) { - parseDisplayFont(tokens, gFalse, displayFontT1, fileName, line); - } else if (!cmd->cmp("displayFontTT")) { - parseDisplayFont(tokens, gFalse, displayFontTT, fileName, line); - } else if (!cmd->cmp("displayCIDFontX")) { - parseDisplayFont(tokens, gTrue, displayFontX, fileName, line); - } else if (!cmd->cmp("psFile")) { - parsePSFile(tokens, fileName, line); - } else if (!cmd->cmp("psFont")) { - parsePSFont(tokens, fileName, line); - } else if (!cmd->cmp("psPaperSize")) { - parsePSPaperSize(tokens, fileName, line); - } else if (!cmd->cmp("psDuplex")) { - parseYesNo("psDuplex", &psDuplex, tokens, fileName, line); - } else if (!cmd->cmp("psLevel")) { - parsePSLevel(tokens, fileName, line); - } else if (!cmd->cmp("psEmbedType1")) { - parseYesNo("psEmbedType1", &psEmbedType1, tokens, fileName, line); - } else if (!cmd->cmp("psEmbedTrueType")) { - parseYesNo("psEmbedTrueType", &psEmbedTrueType, - tokens, fileName, line); - } else if (!cmd->cmp("psOPI")) { - parseYesNo("psOPI", &psOPI, tokens, fileName, line); - } else if (!cmd->cmp("textEncoding")) { - parseTextEncoding(tokens, fileName, line); - } else if (!cmd->cmp("textEOL")) { - parseTextEOL(tokens, fileName, line); - } else if (!cmd->cmp("fontDir")) { - parseFontDir(tokens, fileName, line); - } else if (!cmd->cmp("t1libControl")) { - parseFontRastControl("t1libControl", &t1libControl, - tokens, fileName, line); - } else if (!cmd->cmp("freetypeControl")) { - parseFontRastControl("freetypeControl", &freetypeControl, - tokens, fileName, line); - } else if (!cmd->cmp("urlCommand")) { - parseURLCommand(tokens, fileName, line); - } else if (!cmd->cmp("mapNumericCharNames")) { - parseYesNo("mapNumericCharNames", &mapNumericCharNames, - tokens, fileName, line); - } else if (!cmd->cmp("errQuiet")) { - parseYesNo("errQuiet", &errQuiet, tokens, fileName, line); - } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) { - error(-1, "Unknown config file command"); - error(-1, "-- the config file format has changed since Xpdf 0.9x"); + if (tokens->getLength() > 0 && + ((GString *)tokens->get(0))->getChar(0) != '#') { + cmd = (GString *)tokens->get(0); + if (!cmd->cmp("include")) { + if (tokens->getLength() == 2) { + incFile = (GString *)tokens->get(1); + if ((f2 = fopen(incFile->getCString(), "r"))) { + parseFile(incFile, f2); + fclose(f2); + } else { + error(-1, "Couldn't find included config file: '%s' (%s:%d)", + incFile->getCString(), fileName->getCString(), line); + } } else { - error(-1, "Unknown config file command '%s' (%s:%d)", - cmd->getCString(), fileName->getCString(), line); + error(-1, "Bad 'include' config file command (%s:%d)", + fileName->getCString(), line); } + } else if (!cmd->cmp("nameToUnicode")) { + parseNameToUnicode(tokens, fileName, line); + } else if (!cmd->cmp("cidToUnicode")) { + parseCIDToUnicode(tokens, fileName, line); + } else if (!cmd->cmp("unicodeMap")) { + parseUnicodeMap(tokens, fileName, line); + } else if (!cmd->cmp("cMapDir")) { + parseCMapDir(tokens, fileName, line); + } else if (!cmd->cmp("toUnicodeDir")) { + parseToUnicodeDir(tokens, fileName, line); + } else if (!cmd->cmp("displayFontX")) { + parseDisplayFont(tokens, displayFonts, displayFontX, fileName, line); + } else if (!cmd->cmp("displayFontT1")) { + parseDisplayFont(tokens, displayFonts, displayFontT1, fileName, line); + } else if (!cmd->cmp("displayFontTT")) { + parseDisplayFont(tokens, displayFonts, displayFontTT, fileName, line); + } else if (!cmd->cmp("displayCIDFontX")) { + parseDisplayFont(tokens, displayCIDFonts, + displayFontX, fileName, line); + } else if (!cmd->cmp("displayNamedCIDFontX")) { + parseDisplayFont(tokens, displayNamedCIDFonts, + displayFontX, fileName, line); + } else if (!cmd->cmp("psFile")) { + parsePSFile(tokens, fileName, line); + } else if (!cmd->cmp("psFont")) { + parsePSFont(tokens, fileName, line); + } else if (!cmd->cmp("psNamedFont16")) { + parsePSFont16("psNamedFont16", psNamedFonts16, + tokens, fileName, line); + } else if (!cmd->cmp("psFont16")) { + parsePSFont16("psFont16", psFonts16, tokens, fileName, line); + } else if (!cmd->cmp("psPaperSize")) { + parsePSPaperSize(tokens, fileName, line); + } else if (!cmd->cmp("psDuplex")) { + parseYesNo("psDuplex", &psDuplex, tokens, fileName, line); + } else if (!cmd->cmp("psLevel")) { + parsePSLevel(tokens, fileName, line); + } else if (!cmd->cmp("psEmbedType1Fonts")) { + parseYesNo("psEmbedType1", &psEmbedType1, tokens, fileName, line); + } else if (!cmd->cmp("psEmbedTrueTypeFonts")) { + parseYesNo("psEmbedTrueType", &psEmbedTrueType, + tokens, fileName, line); + } else if (!cmd->cmp("psEmbedCIDPostScriptFonts")) { + parseYesNo("psEmbedCIDPostScript", &psEmbedCIDPostScript, + tokens, fileName, line); + } else if (!cmd->cmp("psEmbedCIDTrueTypeFonts")) { + parseYesNo("psEmbedCIDTrueType", &psEmbedCIDTrueType, + tokens, fileName, line); + } else if (!cmd->cmp("psOPI")) { + parseYesNo("psOPI", &psOPI, tokens, fileName, line); + } else if (!cmd->cmp("psASCIIHex")) { + parseYesNo("psASCIIHex", &psASCIIHex, tokens, fileName, line); + } else if (!cmd->cmp("textEncoding")) { + parseTextEncoding(tokens, fileName, line); + } else if (!cmd->cmp("textEOL")) { + parseTextEOL(tokens, fileName, line); + } else if (!cmd->cmp("fontDir")) { + parseFontDir(tokens, fileName, line); + } else if (!cmd->cmp("initialZoom")) { + parseInitialZoom(tokens, fileName, line); + } else if (!cmd->cmp("t1libControl")) { + parseFontRastControl("t1libControl", &t1libControl, + tokens, fileName, line); + } else if (!cmd->cmp("freetypeControl")) { + parseFontRastControl("freetypeControl", &freetypeControl, + tokens, fileName, line); + } else if (!cmd->cmp("urlCommand")) { + parseURLCommand(tokens, fileName, line); + } else if (!cmd->cmp("mapNumericCharNames")) { + parseYesNo("mapNumericCharNames", &mapNumericCharNames, + tokens, fileName, line); + } else if (!cmd->cmp("errQuiet")) { + parseYesNo("errQuiet", &errQuiet, tokens, fileName, line); + } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) { + error(-1, "Unknown config file command"); + error(-1, "-- the config file format has changed since Xpdf 0.9x"); + } else { + error(-1, "Unknown config file command '%s' (%s:%d)", + cmd->getCString(), fileName->getCString(), line); } - - deleteGList(tokens, GString); - ++line; } - delete fileName; + deleteGList(tokens, GString); + ++line; } } void GlobalParams::parseNameToUnicode(GList *tokens, GString *fileName, @@ -425,9 +481,9 @@ void GlobalParams::parseToUnicodeDir(GList *tokens, GString *fileName, } toUnicodeDirs->append(((GString *)tokens->get(1))->copy()); } -void GlobalParams::parseDisplayFont(GList *tokens, GBool isCID, +void GlobalParams::parseDisplayFont(GList *tokens, GHash *fontHash, DisplayFontParamKind kind, GString *fileName, int line) { DisplayFontParam *param, *old; @@ -457,25 +513,18 @@ void GlobalParams::parseDisplayFont(GList *tokens, GBool isCID, param->tt.fileName = ((GString *)tokens->get(2))->copy(); break; } - if (isCID) { - if ((old = (DisplayFontParam *)displayCIDFonts->remove(param->name))) { - delete old; - } - displayCIDFonts->add(param->name, param); - } else { - if ((old = (DisplayFontParam *)displayFonts->remove(param->name))) { - delete old; - } - displayFonts->add(param->name, param); + if ((old = (DisplayFontParam *)fontHash->remove(param->name))) { + delete old; } + fontHash->add(param->name, param); return; err2: delete param; err1: - error(-1, "Bad 'displayFont...' config file command (%s:%d)", + error(-1, "Bad 'display*Font*' config file command (%s:%d)", fileName->getCString(), line); } void GlobalParams::parsePSPaperSize(GList *tokens, GString *fileName, @@ -515,8 +564,12 @@ void GlobalParams::parsePSLevel(GList *tokens, GString *fileName, int line) { } else if (!tok->cmp("level2")) { psLevel = psLevel2; } else if (!tok->cmp("level2sep")) { psLevel = psLevel2Sep; + } else if (!tok->cmp("level3")) { + psLevel = psLevel3; + } else if (!tok->cmp("level3Sep")) { + psLevel = psLevel3Sep; } else { error(-1, "Bad 'psLevel' config file command (%s:%d)", fileName->getCString(), line); } @@ -541,13 +594,41 @@ void GlobalParams::parsePSFont(GList *tokens, GString *fileName, int line) { error(-1, "Bad 'psFont' config file command (%s:%d)", fileName->getCString(), line); return; } - param = new PSFontParam(((GString *)tokens->get(1))->copy(), - ((GString *)tokens->get(2))->copy()); + param = new PSFontParam(((GString *)tokens->get(1))->copy(), 0, + ((GString *)tokens->get(2))->copy(), NULL); psFonts->add(param->pdfFontName, param); } +void GlobalParams::parsePSFont16(char *cmdName, GList *fontList, + GList *tokens, GString *fileName, int line) { + PSFontParam *param; + int wMode; + GString *tok; + + if (tokens->getLength() != 5) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(2); + if (!tok->cmp("H")) { + wMode = 0; + } else if (!tok->cmp("V")) { + wMode = 1; + } else { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + param = new PSFontParam(((GString *)tokens->get(1))->copy(), + wMode, + ((GString *)tokens->get(3))->copy(), + ((GString *)tokens->get(4))->copy()); + fontList->append(param); +} + void GlobalParams::parseTextEncoding(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { error(-1, "Bad 'textEncoding' config file command (%s:%d)", @@ -587,19 +668,17 @@ void GlobalParams::parseFontDir(GList *tokens, GString *fileName, int line) { } fontDirs->append(((GString *)tokens->get(1))->copy()); } -void GlobalParams::parseURLCommand(GList *tokens, GString *fileName, - int line) { +void GlobalParams::parseInitialZoom(GList *tokens, + GString *fileName, int line) { if (tokens->getLength() != 2) { - error(-1, "Bad 'urlCommand' config file command (%s:%d)", + error(-1, "Bad 'initialZoom' config file command (%s:%d)", fileName->getCString(), line); return; } - if (urlCommand) { - delete urlCommand; - } - urlCommand = ((GString *)tokens->get(1))->copy(); + delete initialZoom; + initialZoom = ((GString *)tokens->get(1))->copy(); } void GlobalParams::parseFontRastControl(char *cmdName, FontRastControl *val, GList *tokens, GString *fileName, @@ -617,8 +696,21 @@ void GlobalParams::parseFontRastControl(char *cmdName, FontRastControl *val, cmdName, fileName->getCString(), line); } } +void GlobalParams::parseURLCommand(GList *tokens, GString *fileName, + int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad 'urlCommand' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + if (urlCommand) { + delete urlCommand; + } + urlCommand = ((GString *)tokens->get(1))->copy(); +} + void GlobalParams::parseYesNo(char *cmdName, GBool *flag, GList *tokens, GString *fileName, int line) { GString *tok; @@ -653,14 +745,18 @@ GlobalParams::~GlobalParams() { deleteGHash(unicodeMaps, GString); deleteGList(toUnicodeDirs, GString); deleteGHash(displayFonts, DisplayFontParam); deleteGHash(displayCIDFonts, DisplayFontParam); + deleteGHash(displayNamedCIDFonts, DisplayFontParam); if (psFile) { delete psFile; } deleteGHash(psFonts, PSFontParam); + deleteGList(psNamedFonts16, PSFontParam); + deleteGList(psFonts16, PSFontParam); delete textEncoding; deleteGList(fontDirs, GString); + delete initialZoom; if (urlCommand) { delete urlCommand; } @@ -751,16 +847,52 @@ FILE *GlobalParams::findToUnicodeFile(GString *name) { DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) { return (DisplayFontParam *)displayFonts->lookup(fontName); } -DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *collection) { - return (DisplayFontParam *)displayCIDFonts->lookup(collection); +DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *fontName, + GString *collection) { + DisplayFontParam *dfp; + + if (!fontName || + !(dfp = (DisplayFontParam *)displayNamedCIDFonts->lookup(fontName))) { + dfp = (DisplayFontParam *)displayCIDFonts->lookup(collection); + } + return dfp; } PSFontParam *GlobalParams::getPSFont(GString *fontName) { return (PSFontParam *)psFonts->lookup(fontName); } +PSFontParam *GlobalParams::getPSFont16(GString *fontName, + GString *collection, int wMode) { + PSFontParam *p; + int i; + + p = NULL; + if (fontName) { + for (i = 0; i < psNamedFonts16->getLength(); ++i) { + p = (PSFontParam *)psNamedFonts16->get(i); + if (!p->pdfFontName->cmp(fontName) && + p->wMode == wMode) { + break; + } + p = NULL; + } + } + if (!p && collection) { + for (i = 0; i < psFonts16->getLength(); ++i) { + p = (PSFontParam *)psFonts16->get(i); + if (!p->pdfFontName->cmp(collection) && + p->wMode == wMode) { + break; + } + p = NULL; + } + } + return p; +} + GString *GlobalParams::findFontFile(GString *fontName, char *ext1, char *ext2) { GString *dir, *fileName; FILE *f; @@ -865,12 +997,24 @@ void GlobalParams::setPSEmbedType1(GBool embed) { void GlobalParams::setPSEmbedTrueType(GBool embed) { psEmbedTrueType = embed; } +void GlobalParams::setPSEmbedCIDPostScript(GBool embed) { + psEmbedCIDPostScript = embed; +} + +void GlobalParams::setPSEmbedCIDTrueType(GBool embed) { + psEmbedCIDTrueType = embed; +} + void GlobalParams::setPSOPI(GBool opi) { psOPI = opi; } +void GlobalParams::setPSASCIIHex(GBool hex) { + psASCIIHex = hex; +} + void GlobalParams::setTextEncoding(char *encodingName) { delete textEncoding; textEncoding = new GString(encodingName); } @@ -887,8 +1031,13 @@ GBool GlobalParams::setTextEOL(char *s) { } return gTrue; } +void GlobalParams::setInitialZoom(char *s) { + delete initialZoom; + initialZoom = new GString(s); +} + GBool GlobalParams::setT1libControl(char *s) { return setFontRastControl(&t1libControl, s); } diff --git a/noncore/unsupported/qpdf/xpdf/GlobalParams.h b/noncore/unsupported/qpdf/xpdf/GlobalParams.h index ecbb5fc..b651110 100644 --- a/noncore/unsupported/qpdf/xpdf/GlobalParams.h +++ b/noncore/unsupported/qpdf/xpdf/GlobalParams.h @@ -1,9 +1,9 @@ //======================================================================== // // GlobalParams.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef GLOBALPARAMS_H @@ -44,10 +44,11 @@ enum DisplayFontParamKind { class DisplayFontParam { public: - GString *name; // font name for 8-bit fonts; - // collection name for CID fonts + GString *name; // font name for 8-bit fonts and named + // CID fonts; collection name for + // generic CID fonts DisplayFontParamKind kind; union { struct { GString *xlfd; @@ -78,12 +79,18 @@ enum FontRastControl { class PSFontParam { public: - GString *pdfFontName; - GString *psFontName; + GString *pdfFontName; // PDF font name for 8-bit fonts and + // named 16-bit fonts; char collection + // name for generic 16-bit fonts + int wMode; // writing mode (0=horiz, 1=vert) for + // 16-bit fonts + GString *psFontName; // PostScript font name + GString *encoding; // encoding, for 16-bit fonts only - PSFontParam(GString *pdfFontNameA, GString *psFontNameA); + PSFontParam(GString *pdfFontNameA, int wModeA, + GString *psFontNameA, GString *encodingA); ~PSFontParam(); }; //------------------------------------------------------------------------ @@ -91,9 +98,11 @@ public: enum PSLevel { psLevel1, psLevel1Sep, psLevel2, - psLevel2Sep + psLevel2Sep, + psLevel3, + psLevel3Sep }; //------------------------------------------------------------------------ @@ -124,21 +133,26 @@ public: FILE *getUnicodeMapFile(GString *encodingName); FILE *findCMapFile(GString *collection, GString *cMapName); FILE *findToUnicodeFile(GString *name); DisplayFontParam *getDisplayFont(GString *fontName); - DisplayFontParam *getDisplayCIDFont(GString *collection); + DisplayFontParam *getDisplayCIDFont(GString *fontName, GString *collection); GString *getPSFile() { return psFile; } int getPSPaperWidth() { return psPaperWidth; } int getPSPaperHeight() { return psPaperHeight; } GBool getPSDuplex() { return psDuplex; } PSLevel getPSLevel() { return psLevel; } PSFontParam *getPSFont(GString *fontName); + PSFontParam *getPSFont16(GString *fontName, GString *collection, int wMode); GBool getPSEmbedType1() { return psEmbedType1; } GBool getPSEmbedTrueType() { return psEmbedTrueType; } + GBool getPSEmbedCIDPostScript() { return psEmbedCIDPostScript; } + GBool getPSEmbedCIDTrueType() { return psEmbedCIDTrueType; } GBool getPSOPI() { return psOPI; } + GBool getPSASCIIHex() { return psASCIIHex; } GString *getTextEncodingName() { return textEncoding; } EndOfLineKind getTextEOL() { return textEOL; } GString *findFontFile(GString *fontName, char *ext1, char *ext2); + GString *getInitialZoom() { return initialZoom; } FontRastControl getT1libControl() { return t1libControl; } FontRastControl getFreeTypeControl() { return freetypeControl; } GString *getURLCommand() { return urlCommand; } GBool getMapNumericCharNames() { return mapNumericCharNames; } @@ -158,31 +172,40 @@ public: void setPSDuplex(GBool duplex); void setPSLevel(PSLevel level); void setPSEmbedType1(GBool embed); void setPSEmbedTrueType(GBool embed); + void setPSEmbedCIDPostScript(GBool embed); + void setPSEmbedCIDTrueType(GBool embed); void setPSOPI(GBool opi); + void setPSASCIIHex(GBool hex); void setTextEncoding(char *encodingName); GBool setTextEOL(char *s); + void setInitialZoom(char *s); GBool setT1libControl(char *s); GBool setFreeTypeControl(char *s); void setErrQuiet(GBool errQuietA); private: + void parseFile(GString *fileName, FILE *f); void parseNameToUnicode(GList *tokens, GString *fileName, int line); void parseCIDToUnicode(GList *tokens, GString *fileName, int line); void parseUnicodeMap(GList *tokens, GString *fileName, int line); void parseCMapDir(GList *tokens, GString *fileName, int line); void parseToUnicodeDir(GList *tokens, GString *fileName, int line); - void parseDisplayFont(GList *tokens, GBool isCID, DisplayFontParamKind kind, + void parseDisplayFont(GList *tokens, GHash *fontHash, + DisplayFontParamKind kind, GString *fileName, int line); void parsePSFile(GList *tokens, GString *fileName, int line); void parsePSPaperSize(GList *tokens, GString *fileName, int line); void parsePSLevel(GList *tokens, GString *fileName, int line); void parsePSFont(GList *tokens, GString *fileName, int line); + void parsePSFont16(char *cmdName, GList *fontList, + GList *tokens, GString *fileName, int line); void parseTextEncoding(GList *tokens, GString *fileName, int line); void parseTextEOL(GList *tokens, GString *fileName, int line); void parseFontDir(GList *tokens, GString *fileName, int line); + void parseInitialZoom(GList *tokens, GString *fileName, int line); void parseFontRastControl(char *cmdName, FontRastControl *val, GList *tokens, GString *fileName, int line); void parseURLCommand(GList *tokens, GString *fileName, int line); void parseYesNo(char *cmdName, GBool *flag, @@ -211,23 +234,31 @@ private: GHash *displayFonts; // display font info, indexed by font name // [DisplayFontParam] GHash *displayCIDFonts; // display CID font info, indexed by // collection [DisplayFontParam] + GHash *displayNamedCIDFonts; // display CID font info, indexed by + // font name [DisplayFontParam] GString *psFile; // PostScript file or command (for xpdf) int psPaperWidth; // paper size, in PostScript points, for int psPaperHeight; // PostScript output GBool psDuplex; // enable duplexing in PostScript? PSLevel psLevel; // PostScript level to generate GHash *psFonts; // PostScript font info, indexed by PDF // font name [PSFontParam] + GList *psNamedFonts16; // named 16-bit fonts [PSFontParam] + GList *psFonts16; // generic 16-bit fonts [PSFontParam] GBool psEmbedType1; // embed Type 1 fonts? GBool psEmbedTrueType; // embed TrueType fonts? + GBool psEmbedCIDPostScript; // embed CID PostScript fonts? + GBool psEmbedCIDTrueType; // embed CID TrueType fonts? GBool psOPI; // generate PostScript OPI comments? + GBool psASCIIHex; // use ASCIIHex instead of ASCII85? GString *textEncoding; // encoding (unicodeMap) to use for text // output EndOfLineKind textEOL; // type of EOL marker to use for text // output GList *fontDirs; // list of font dirs [GString] + GString *initialZoom; // initial zoom level FontRastControl t1libControl; // t1lib rasterization mode FontRastControl // FreeType rasterization mode freetypeControl; GString *urlCommand; // command executed for URL links diff --git a/noncore/unsupported/qpdf/xpdf/Lexer.cc b/noncore/unsupported/qpdf/xpdf/Lexer.cc index fff4bcb..a258950 100644 --- a/noncore/unsupported/qpdf/xpdf/Lexer.cc +++ b/noncore/unsupported/qpdf/xpdf/Lexer.cc @@ -1,9 +1,9 @@ //======================================================================== // // Lexer.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ diff --git a/noncore/unsupported/qpdf/xpdf/Lexer.h b/noncore/unsupported/qpdf/xpdf/Lexer.h index 5edbeda..8a01ab2 100644 --- a/noncore/unsupported/qpdf/xpdf/Lexer.h +++ b/noncore/unsupported/qpdf/xpdf/Lexer.h @@ -1,9 +1,9 @@ //======================================================================== // // Lexer.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef LEXER_H @@ -50,15 +50,16 @@ public: // Get stream. 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: int getChar(); diff --git a/noncore/unsupported/qpdf/xpdf/Link.cc b/noncore/unsupported/qpdf/xpdf/Link.cc index 79a5f6e..c25ec43 100644 --- a/noncore/unsupported/qpdf/xpdf/Link.cc +++ b/noncore/unsupported/qpdf/xpdf/Link.cc @@ -1,9 +1,9 @@ //======================================================================== // // Link.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -28,33 +28,29 @@ static GString *getFileSpecName(Object *fileSpecObj); //------------------------------------------------------------------------ // LinkDest //------------------------------------------------------------------------ -LinkDest::LinkDest(Array *a, GBool pageIsRefA) { +LinkDest::LinkDest(Array *a) { Object obj1, obj2; // initialize fields - pageIsRef = pageIsRefA; left = bottom = right = top = zoom = 0; ok = gFalse; // get page - if (pageIsRef) { - if (!a->getNF(0, &obj1)->isRef()) { - error(-1, "Bad annotation destination"); - 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"); - goto err2; - } - pageNum = obj1.getInt() + 1; - obj1.free(); + error(-1, "Bad annotation destination"); + goto err2; } + obj1.free(); // get destination type a->get(1, &obj1); @@ -220,9 +216,9 @@ LinkGoTo::LinkGoTo(Object *destObj) { namedDest = destObj->getString()->copy(); // destination dictionary } else if (destObj->isArray()) { - dest = new LinkDest(destObj->getArray(), gTrue); + dest = new LinkDest(destObj->getArray()); if (!dest->isOk()) { delete dest; dest = NULL; } @@ -258,9 +254,9 @@ LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) { namedDest = destObj->getString()->copy(); // destination dictionary } else if (destObj->isArray()) { - dest = new LinkDest(destObj->getArray(), gFalse); + dest = new LinkDest(destObj->getArray()); if (!dest->isOk()) { delete dest; dest = NULL; } @@ -445,9 +441,9 @@ Link::Link(Dict *dict, GString *baseURI) { y2 = t; } // get border - borderW = 0; + borderW = 1; if (!dict->lookup("Border", &obj1)->isNull()) { if (obj1.isArray() && obj1.arrayGetLength() >= 3) { if (obj1.arrayGet(2, &obj2)->isNum()) { borderW = obj2.getNum(); @@ -581,9 +577,9 @@ Links::~Links() { LinkAction *Links::find(fouble x, fouble 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/noncore/unsupported/qpdf/xpdf/Link.h b/noncore/unsupported/qpdf/xpdf/Link.h index 0ad4581..7b5ba86 100644 --- a/noncore/unsupported/qpdf/xpdf/Link.h +++ b/noncore/unsupported/qpdf/xpdf/Link.h @@ -1,9 +1,9 @@ //======================================================================== // // Link.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef LINK_H @@ -62,12 +62,10 @@ enum LinkDestKind { class LinkDest { public: - // Build a LinkDest from the array. If <pageIsRef> is true, the - // page is specified by an object reference; otherwise the page is - // specified by a (zero-relative) page number. - LinkDest(Array *a, GBool pageIsRef1); + // Build a LinkDest from the array. + LinkDest(Array *a); // Copy a LinkDest. LinkDest *copy() { return new LinkDest(this); } diff --git a/noncore/unsupported/qpdf/xpdf/NameToCharCode.cc b/noncore/unsupported/qpdf/xpdf/NameToCharCode.cc index 06be2f4..b9cde77 100644 --- a/noncore/unsupported/qpdf/xpdf/NameToCharCode.cc +++ b/noncore/unsupported/qpdf/xpdf/NameToCharCode.cc @@ -1,9 +1,9 @@ //======================================================================== // // NameToCharCode.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ diff --git a/noncore/unsupported/qpdf/xpdf/NameToCharCode.h b/noncore/unsupported/qpdf/xpdf/NameToCharCode.h index 9f9b1c3..22e41b6 100644 --- a/noncore/unsupported/qpdf/xpdf/NameToCharCode.h +++ b/noncore/unsupported/qpdf/xpdf/NameToCharCode.h @@ -1,9 +1,9 @@ //======================================================================== // // NameToCharCode.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef NAMETOCHARCODE_H diff --git a/noncore/unsupported/qpdf/xpdf/NameToUnicodeTable.h b/noncore/unsupported/qpdf/xpdf/NameToUnicodeTable.h index 7ca635e..432fafb 100644 --- a/noncore/unsupported/qpdf/xpdf/NameToUnicodeTable.h +++ b/noncore/unsupported/qpdf/xpdf/NameToUnicodeTable.h @@ -1,9 +1,9 @@ //======================================================================== // // NameToUnicodeTable.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== static struct { diff --git a/noncore/unsupported/qpdf/xpdf/Object.cc b/noncore/unsupported/qpdf/xpdf/Object.cc index 5ecade3..6d92c6a 100644 --- a/noncore/unsupported/qpdf/xpdf/Object.cc +++ b/noncore/unsupported/qpdf/xpdf/Object.cc @@ -1,9 +1,9 @@ //======================================================================== // // Object.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ diff --git a/noncore/unsupported/qpdf/xpdf/Object.h b/noncore/unsupported/qpdf/xpdf/Object.h index 000ffa0..7a67a7d 100644 --- a/noncore/unsupported/qpdf/xpdf/Object.h +++ b/noncore/unsupported/qpdf/xpdf/Object.h @@ -1,9 +1,9 @@ //======================================================================== // // Object.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef OBJECT_H @@ -175,10 +175,10 @@ public: void streamClose(); 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. char *getTypeName(); @@ -286,13 +286,13 @@ 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/noncore/unsupported/qpdf/xpdf/OutputDev.cc b/noncore/unsupported/qpdf/xpdf/OutputDev.cc index 3c02835..1004f0f 100644 --- a/noncore/unsupported/qpdf/xpdf/OutputDev.cc +++ b/noncore/unsupported/qpdf/xpdf/OutputDev.cc @@ -1,9 +1,9 @@ //======================================================================== // // OutputDev.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -58,8 +58,13 @@ void OutputDev::updateAll(GfxState *state) { updateStrokeColor(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) { int i, j; diff --git a/noncore/unsupported/qpdf/xpdf/OutputDev.h b/noncore/unsupported/qpdf/xpdf/OutputDev.h index 04cbace..398c035 100644 --- a/noncore/unsupported/qpdf/xpdf/OutputDev.h +++ b/noncore/unsupported/qpdf/xpdf/OutputDev.h @@ -1,9 +1,9 @@ //======================================================================== // // OutputDev.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef OUTPUTDEV_H @@ -45,8 +45,12 @@ 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 @@ -118,8 +122,11 @@ public: fouble dx, fouble dy, fouble originX, fouble originY, CharCode code, Unicode *u, int uLen) {} virtual void drawString(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, int width, int height, GBool invert, @@ -133,8 +140,16 @@ public: virtual void opiBegin(GfxState *state, Dict *opiDict); virtual void opiEnd(GfxState *state, Dict *opiDict); #endif + //----- Type 3 font operators + virtual void type3D0(GfxState *state, fouble wx, fouble wy) {} + virtual void type3D1(GfxState *state, fouble wx, fouble wy, + fouble llx, fouble lly, fouble urx, fouble ury) {} + + //----- PostScript XObjects + virtual void psXObject(Stream *psStream, Stream *level1Stream) {} + private: fouble defCTM[6]; // default coordinate transform matrix fouble defICTM[6]; // inverse of default CTM diff --git a/noncore/unsupported/qpdf/xpdf/PDFDoc.cc b/noncore/unsupported/qpdf/xpdf/PDFDoc.cc index 4bbe9b7..97dfa55 100644 --- a/noncore/unsupported/qpdf/xpdf/PDFDoc.cc +++ b/noncore/unsupported/qpdf/xpdf/PDFDoc.cc @@ -1,9 +1,9 @@ //======================================================================== // // PDFDoc.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -23,8 +23,9 @@ #include "XRef.h" #include "Link.h" #include "OutputDev.h" #include "Error.h" +#include "ErrorCodes.h" #include "Lexer.h" #include "Parser.h" #include "PDFDoc.h" @@ -42,8 +43,9 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, Object obj; GString *fileName2; ok = gFalse; + errCode = errNone; file = NULL; str = NULL; xref = NULL; @@ -56,8 +58,9 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, fileName2 = NULL; #ifdef VMS if (!(file = fopen(fileName->getCString(), "rb", "ctx=stm"))) { error(-1, "Couldn't open file '%s'", fileName->getCString()); + errCode = errOpenFile; return; } #else if (!(file = fopen(fileName->getCString(), "rb"))) { @@ -67,8 +70,9 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, fileName2->upperCase(); if (!(file = fopen(fileName2->getCString(), "rb"))) { error(-1, "Couldn't open file '%s'", fileName->getCString()); delete fileName2; + errCode = errOpenFile; return; } } delete fileName2; @@ -76,16 +80,17 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, #endif // create stream obj.initNull(); - str = new FileStream(file, 0, -1, &obj); + str = new FileStream(file, 0, gFalse, 0, &obj); ok = setup(ownerPassword, userPassword); } PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, GString *userPassword, GBool printCommandsA) { ok = gFalse; + errCode = errNone; fileName = NULL; file = NULL; str = strA; xref = NULL; @@ -102,15 +107,17 @@ GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { // read xref table 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, printCommands); if (!catalog->isOk()) { error(-1, "Couldn't read page catalog"); + errCode = errBadCatalog; return gFalse; } // done @@ -203,10 +210,11 @@ GBool PDFDoc::isLinearized() { GBool lin; lin = gFalse; obj1.initNull(); - parser = new Parser(xref, new Lexer(xref, 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); parser->getObj(&obj4); diff --git a/noncore/unsupported/qpdf/xpdf/PDFDoc.h b/noncore/unsupported/qpdf/xpdf/PDFDoc.h index 592095e..3157683 100644 --- a/noncore/unsupported/qpdf/xpdf/PDFDoc.h +++ b/noncore/unsupported/qpdf/xpdf/PDFDoc.h @@ -1,9 +1,9 @@ //======================================================================== // // PDFDoc.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef PDFDOC_H @@ -41,8 +41,11 @@ public: // 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. @@ -136,7 +139,8 @@ private: Links *links; GBool printCommands; GBool ok; + int errCode; }; #endif diff --git a/noncore/unsupported/qpdf/xpdf/PSTokenizer.cc b/noncore/unsupported/qpdf/xpdf/PSTokenizer.cc new file mode 100644 index 0000000..8d654bd --- a/dev/null +++ b/noncore/unsupported/qpdf/xpdf/PSTokenizer.cc @@ -0,0 +1,133 @@ +//======================================================================== +// +// PSTokenizer.cc +// +// Copyright 2002 Glyph & Cog, LLC +// +//======================================================================== + +#ifdef __GNUC__ +#pragma implementation +#endif + +#include <stdio.h> +#include <stdlib.h> +#include "PSTokenizer.h" + +//------------------------------------------------------------------------ + +// A '1' in this array means the character is white space. A '1' or +// '2' means the character ends a name or command. +static char specialChars[256] = { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x + 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx +}; + +//------------------------------------------------------------------------ + +PSTokenizer::PSTokenizer(int (*getCharFuncA)(void *), void *dataA) { + getCharFunc = getCharFuncA; + data = dataA; + charBuf = -1; +} + +PSTokenizer::~PSTokenizer() { +} + +GBool PSTokenizer::getToken(char *buf, int size, int *length) { + GBool comment, backslash; + int c; + int i; + + // skip whitespace and comments + comment = gFalse; + while (1) { + if ((c = getChar()) == EOF) { + buf[0] = '\0'; + *length = 0; + return gFalse; + } + if (comment) { + if (c == '\x0a' || c == '\x0d') { + comment = gFalse; + } + } else if (c == '%') { + comment = gTrue; + } else if (specialChars[c] != 1) { + break; + } + } + + // read a token + i = 0; + buf[i++] = c; + if (c == '(') { + backslash = gFalse; + while ((c = lookChar()) != EOF) { + if (i < size - 1) { + buf[i++] = c; + } + getChar(); + if (c == '\\') { + backslash = gTrue; + } else if (!backslash && c == ')') { + break; + } else { + backslash = gFalse; + } + } + } else if (c == '<') { + while ((c = lookChar()) != EOF) { + getChar(); + if (i < size - 1) { + buf[i++] = c; + } + if (c == '>') { + break; + } + } + } else if (c != '[' && c != ']') { + while ((c = lookChar()) != EOF && !specialChars[c]) { + getChar(); + if (i < size - 1) { + buf[i++] = c; + } + } + } + buf[i] = '\0'; + *length = i; + + return gTrue; +} + +int PSTokenizer::lookChar() { + if (charBuf < 0) { + charBuf = (*getCharFunc)(data); + } + return charBuf; +} + +int PSTokenizer::getChar() { + int c; + + if (charBuf < 0) { + charBuf = (*getCharFunc)(data); + } + c = charBuf; + charBuf = -1; + return c; +} diff --git a/noncore/unsupported/qpdf/xpdf/PSTokenizer.h b/noncore/unsupported/qpdf/xpdf/PSTokenizer.h new file mode 100644 index 0000000..1053c67 --- a/dev/null +++ b/noncore/unsupported/qpdf/xpdf/PSTokenizer.h @@ -0,0 +1,39 @@ +//======================================================================== +// +// PSTokenizer.h +// +// Copyright 2002 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PSTOKENIZER_H +#define PSTOKENIZER_H + +#ifdef __GNUC__ +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ + +class PSTokenizer { +public: + + PSTokenizer(int (*getCharFuncA)(void *), void *dataA); + ~PSTokenizer(); + + // Get the next PostScript token. Returns false at end-of-stream. + GBool getToken(char *buf, int size, int *length); + +private: + + int lookChar(); + int getChar(); + + int (*getCharFunc)(void *); + void *data; + int charBuf; +}; + +#endif diff --git a/noncore/unsupported/qpdf/xpdf/Page.cc b/noncore/unsupported/qpdf/xpdf/Page.cc index 17c4481..9cc08c4 100644 --- a/noncore/unsupported/qpdf/xpdf/Page.cc +++ b/noncore/unsupported/qpdf/xpdf/Page.cc @@ -1,9 +1,9 @@ //======================================================================== // // Page.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -19,9 +19,9 @@ #include "Link.h" #include "OutputDev.h" #ifndef PDF_PARSER_ONLY #include "Gfx.h" -#include "FormWidget.h" +#include "Annot.h" #endif #include "Error.h" #include "Page.h" @@ -92,8 +92,16 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { 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); if (obj1.isDict()) { resources.free(); @@ -102,8 +110,14 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { obj1.free(); } 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) { @@ -208,9 +222,9 @@ void Page::display(OutputDev *out, fouble dpi, int rotate, Gfx *gfx; Object obj; Link *link; int i; - FormWidgets *formWidgets; + Annots *annotList; box = getBox(); cropBox = getCropBox(); @@ -246,22 +260,22 @@ void Page::display(OutputDev *out, fouble dpi, int rotate, } out->dump(); } - // draw AcroForm widgets + // draw non-link annotations //~ need to reset CTM ??? - formWidgets = new FormWidgets(xref, annots.fetch(xref, &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/noncore/unsupported/qpdf/xpdf/Page.h b/noncore/unsupported/qpdf/xpdf/Page.h index 203878f..57e802a 100644 --- a/noncore/unsupported/qpdf/xpdf/Page.h +++ b/noncore/unsupported/qpdf/xpdf/Page.h @@ -1,9 +1,9 @@ //======================================================================== // // Page.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef PAGE_H @@ -50,8 +50,22 @@ public: 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: @@ -65,8 +79,14 @@ private: PDFRectangle bleedBox; PDFRectangle trimBox; PDFRectangle artBox; int rotate; + Object lastModified; + Object boxColorInfo; + Object group; + Object metadata; + Object pieceInfo; + Object separationInfo; Object resources; }; //------------------------------------------------------------------------ @@ -96,8 +116,14 @@ public: 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(); } diff --git a/noncore/unsupported/qpdf/xpdf/Parser.cc b/noncore/unsupported/qpdf/xpdf/Parser.cc index a98753d..4df53c9 100644 --- a/noncore/unsupported/qpdf/xpdf/Parser.cc +++ b/noncore/unsupported/qpdf/xpdf/Parser.cc @@ -1,9 +1,9 @@ //======================================================================== // // Parser.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -154,32 +154,33 @@ 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(); pos = lexer->getPos(); // 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"); obj.free(); return NULL; } // 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/noncore/unsupported/qpdf/xpdf/Parser.h b/noncore/unsupported/qpdf/xpdf/Parser.h index 463d998..c11475b 100644 --- a/noncore/unsupported/qpdf/xpdf/Parser.h +++ b/noncore/unsupported/qpdf/xpdf/Parser.h @@ -1,9 +1,9 @@ //======================================================================== // // Parser.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef PARSER_H diff --git a/noncore/unsupported/qpdf/xpdf/Stream-CCITT.h b/noncore/unsupported/qpdf/xpdf/Stream-CCITT.h index 1af8742..f5a77b0 100644 --- a/noncore/unsupported/qpdf/xpdf/Stream-CCITT.h +++ b/noncore/unsupported/qpdf/xpdf/Stream-CCITT.h @@ -3,9 +3,9 @@ // Stream-CCITT.h // // Tables for CCITT Fax decoding. // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== struct CCITTCode { diff --git a/noncore/unsupported/qpdf/xpdf/Stream.cc b/noncore/unsupported/qpdf/xpdf/Stream.cc index 18490d4..c558478 100644 --- a/noncore/unsupported/qpdf/xpdf/Stream.cc +++ b/noncore/unsupported/qpdf/xpdf/Stream.cc @@ -1,9 +1,9 @@ //======================================================================== // // Stream.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -302,9 +302,9 @@ FilterStream::~FilterStream() { void FilterStream::close() { str->close(); } -void FilterStream::setPos(int pos) { +void FilterStream::setPos(Guint pos, int dir) { error(-1, "Internal: called setPos() on FilterStream"); } //------------------------------------------------------------------------ @@ -553,29 +553,39 @@ GBool StreamPredictor::getNextLine() { //------------------------------------------------------------------------ // FileStream //------------------------------------------------------------------------ -FileStream::FileStream(FILE *fA, int startA, int lengthA, Object *dictA): +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 startA, int lengthA, Object *dictA) { - return new FileStream(f, startA, lengthA, dictA); +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 if (decrypt) @@ -583,11 +593,15 @@ void FileStream::reset() { #endif } 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; } } GBool FileStream::fillBuf() { @@ -597,12 +611,12 @@ GBool FileStream::fillBuf() { #endif 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; } @@ -620,25 +634,39 @@ GBool FileStream::fillBuf() { #endif return gTrue; } -void FileStream::setPos(int pos) { - long size; +void FileStream::setPos(Guint pos, int dir) { + Guint size; - if (pos >= 0) { + 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 (pos < -size) - pos = (int)(-size); + 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 - fseek(f, pos, SEEK_END); - bufPos = (int)ftell(f); +#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; } @@ -648,8 +676,92 @@ void FileStream::moveStart(int delta) { 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 *strA, Object *dictA): @@ -659,23 +771,24 @@ EmbedStream::EmbedStream(Stream *strA, Object *dictA): EmbedStream::~EmbedStream() { } -Stream *EmbedStream::makeSubStream(int start, int length, Object *dictA) { +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"); } //------------------------------------------------------------------------ @@ -958,13 +1071,9 @@ void LZWStream::reset() { delete zName; 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; return; @@ -3286,8 +3395,58 @@ int FixedLengthEncoder::lookChar() { return str->getChar(); } //------------------------------------------------------------------------ +// 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 *strA): diff --git a/noncore/unsupported/qpdf/xpdf/Stream.h b/noncore/unsupported/qpdf/xpdf/Stream.h index 1f9c561..3319dcc 100644 --- a/noncore/unsupported/qpdf/xpdf/Stream.h +++ b/noncore/unsupported/qpdf/xpdf/Stream.h @@ -1,9 +1,9 @@ //======================================================================== // // Stream.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef STREAM_H @@ -77,10 +77,12 @@ public: // Get current position in file. virtual int getPos() = 0; - // Go to a position in the stream. - virtual void setPos(int pos) = 0; + // Go to a position in the stream. If <dir> is negative, the + // position is from the end of the file; otherwise the position is + // from the start of the file. + virtual void setPos(Guint pos, int dir = 0) = 0; // Get PostScript command for the filter(s). virtual GString *getPSFilter(char *indent); @@ -117,20 +119,22 @@ class BaseStream: public Stream { public: BaseStream(Object *dictA); virtual ~BaseStream(); - virtual Stream *makeSubStream(int start, int length, Object *dict) = 0; - virtual void setPos(int pos) = 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 keyLength, int objNum, int objGen); + virtual void doDecryption(Guchar *fileKey, int keyLength, + int objNum, int objGen); #endif #ifndef NO_DECRYPTION protected: @@ -155,9 +159,9 @@ public: 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(); } protected: @@ -241,36 +245,77 @@ private: class FileStream: public BaseStream { public: - FileStream(FILE *fA, int startA, int lengthA, Object *dictA); + FileStream(FILE *fA, Guint startA, GBool limitedA, + Guint lengthA, Object *dictA); virtual ~FileStream(); - virtual Stream *makeSubStream(int startA, int lengthA, Object *dictA); + virtual Stream *makeSubStream(Guint startA, GBool limitedA, + Guint lengthA, Object *dictA); virtual StreamKind getKind() { return strFile; } 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 int getPos() { return bufPos + (bufPtr - buf); } - virtual void setPos(int pos); + virtual void setPos(Guint pos, int dir = 0); virtual GBool isBinary(GBool last = gTrue) { return last; } - virtual int getStart() { return start; } + virtual Guint getStart() { return start; } virtual void moveStart(int delta); private: GBool fillBuf(); FILE *f; - int start; - int length; + Guint start; + GBool limited; + Guint length; char buf[fileStreamBufSize]; char *bufPtr; char *bufEnd; - int bufPos; + Guint bufPos; int savePos; + GBool saved; +}; + +//------------------------------------------------------------------------ +// MemStream +//------------------------------------------------------------------------ + +class MemStream: public BaseStream { +public: + + MemStream(char *bufA, Guint lengthA, Object *dictA); + virtual ~MemStream(); + virtual Stream *makeSubStream(Guint start, GBool limited, + Guint lengthA, Object *dictA); + virtual StreamKind getKind() { return strWeird; } + virtual void reset(); + virtual void close(); + virtual int getChar() + { return (bufPtr < bufEnd) ? (*bufPtr++ & 0xff) : EOF; } + virtual int lookChar() + { return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; } + virtual int getPos() { return bufPtr - buf; } + virtual void setPos(Guint pos, int dir = 0); + virtual GBool isBinary(GBool last = gTrue) { return last; } + virtual Guint getStart() { return 0; } + virtual void moveStart(int delta); +#ifndef NO_DECRYPTION + virtual void doDecryption(Guchar *fileKey, int keyLength, + int objNum, int objGen); +#endif + +private: + + char *buf; + Guint length; + GBool needFree; + char *bufEnd; + char *bufPtr; }; //------------------------------------------------------------------------ // EmbedStream @@ -286,17 +331,18 @@ class EmbedStream: public BaseStream { public: EmbedStream(Stream *strA, Object *dictA); virtual ~EmbedStream(); - virtual Stream *makeSubStream(int start, int length, Object *dictA); + 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: @@ -658,8 +704,39 @@ private: int count; }; //------------------------------------------------------------------------ +// 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 { diff --git a/noncore/unsupported/qpdf/xpdf/TextOutputDev.cc b/noncore/unsupported/qpdf/xpdf/TextOutputDev.cc index aa9366a..d3b0137 100644 --- a/noncore/unsupported/qpdf/xpdf/TextOutputDev.cc +++ b/noncore/unsupported/qpdf/xpdf/TextOutputDev.cc @@ -1,9 +1,9 @@ //======================================================================== // // TextOutputDev.cc // -// Copyright 1997 Derek B. Noonburg +// Copyright 1997-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -47,8 +47,14 @@ TextString::TextString(GfxState *state, fouble fontSize) { // which should never happen yMin = y - 0.95 * fontSize; yMax = y + 0.35 * fontSize; } + if (yMin == yMax) { + // this is a sanity check for a case that shouldn't happen -- but + // if it does happen, we want to avoid dividing by zero later + yMin = y; + yMax = y + 1; + } col = 0; text = NULL; xRight = NULL; len = size = 0; @@ -98,8 +104,9 @@ void TextPage::updateFont(GfxState *state) { GfxFont *font; fouble *fm; char *name; int code; + fouble w; // adjust the font size fontSize = state->getTransformedFontSize(); if ((font = state->getFont()) && font->getType() == fontType3) { @@ -115,10 +122,13 @@ void TextPage::updateFont(GfxState *state) { break; } } if (code < 256) { - // 600 is a generic average 'm' width -- yes, this is a hack - fontSize *= ((Gfx8BitFont *)font)->getWidth(code) / 0.6; + w = ((Gfx8BitFont *)font)->getWidth(code); + if (w != 0) { + // 600 is a generic average 'm' width -- yes, this is a hack + fontSize *= w / 0.6; + } } fm = font->getFontMatrix(); if (fm[0] != 0) { fontSize *= fabs(fm[3] / fm[0]); @@ -153,10 +163,12 @@ void TextPage::addChar(GfxState *state, fouble x, fouble y, 0, &dx2, &dy2); dx -= dx2; dy -= dy2; state->transformDelta(dx, dy, &w1, &h1); - w1 /= uLen; - h1 /= uLen; + if (uLen != 0) { + w1 /= uLen; + h1 /= uLen; + } for (i = 0; i < uLen; ++i) { curStr->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]); } } @@ -428,9 +440,9 @@ GString *TextPage::getText(fouble xMin, fouble yMin, uMap->decRefCnt(); return s; } -void TextPage::dump(FILE *f) { +void TextPage::dump(void *outputStream, TextOutputFunc outputFunc) { UnicodeMap *uMap; char space[8], eol[16], eop[8], buf[8]; int spaceLen, eolLen, eopLen, n; TextString *str1, *str2, *str3; @@ -497,19 +509,19 @@ void TextPage::dump(FILE *f) { str1->col = col1; } #if 0 //~ for debugging - fprintf(f, "~~~~~~~~~~\n"); + fprintf((FILE *)outputStream, "~~~~~~~~~~\n"); for (str1 = yxStrings; str1; str1 = str1->yxNext) { - fprintf(f, "(%4d,%4d) - (%4d,%4d) [%3d] '", + fprintf((FILE *)outputStream, "(%4d,%4d) - (%4d,%4d) [%3d] '", (int)str1->xMin, (int)str1->yMin, (int)str1->xMax, (int)str1->yMax, str1->col); for (i = 0; i < str1->len; ++i) { fputc(str1->text[i] & 0xff, stdout); } printf("'\n"); } - fprintf(f, "~~~~~~~~~~\n"); + fprintf((FILE *)outputStream, "~~~~~~~~~~\n"); #endif // output col1 = 0; @@ -520,16 +532,16 @@ void TextPage::dump(FILE *f) { if (rawOrder && col1 == 0) { col1 = str1->col; } else { for (; col1 < str1->col; ++col1) { - fwrite(space, 1, spaceLen, f); + (*outputFunc)(outputStream, space, spaceLen); } } // print the string for (i = 0; i < str1->len; ++i) { if ((n = uMap->mapUnicode(str1->text[i], buf, sizeof(buf))) > 0) { - fwrite(buf, 1, n, f); + (*outputFunc)(outputStream, buf, n); } } // increment column @@ -546,9 +558,9 @@ void TextPage::dump(FILE *f) { str1->yxNext->yMin < 0.2*str1->yMin + 0.8*str1->yMax && str1->yxNext->xMin >= str1->xMax)) { // print a return - fwrite(eol, 1, eolLen, f); + (*outputFunc)(outputStream, eol, eolLen); // print extra vertical space if necessary if (str1->yxNext) { @@ -572,9 +584,9 @@ void TextPage::dump(FILE *f) { } else if (!rawOrder && d > 5) { d = 5; } for (; d > 0; --d) { - fwrite(eol, 1, eolLen, f); + (*outputFunc)(outputStream, eol, eolLen); } } // set up for next line @@ -583,11 +595,11 @@ void TextPage::dump(FILE *f) { } } // end of page - fwrite(eol, 1, eolLen, f); - fwrite(eop, 1, eopLen, f); - fwrite(eol, 1, eolLen, f); + (*outputFunc)(outputStream, eol, eolLen); + (*outputFunc)(outputStream, eop, eopLen); + (*outputFunc)(outputStream, eol, eolLen); uMap->decRefCnt(); } @@ -610,8 +622,12 @@ void TextPage::clear() { //------------------------------------------------------------------------ // TextOutputDev //------------------------------------------------------------------------ +static void outputToFile(void *stream, char *text, int len) { + fwrite(text, 1, len, (FILE *)stream); +} + TextOutputDev::TextOutputDev(char *fileName, GBool rawOrderA, GBool append) { text = NULL; rawOrder = rawOrderA; ok = gTrue; @@ -619,30 +635,41 @@ TextOutputDev::TextOutputDev(char *fileName, GBool rawOrderA, GBool append) { // open file needClose = gFalse; if (fileName) { if (!strcmp(fileName, "-")) { - f = stdout; - } else if ((f = fopen(fileName, append ? "a" : "w"))) { + outputStream = stdout; + } else if ((outputStream = fopen(fileName, append ? "ab" : "wb"))) { needClose = gTrue; } else { error(-1, "Couldn't open text file '%s'", fileName); ok = gFalse; return; } + outputFunc = &outputToFile; } else { - f = NULL; + outputStream = NULL; } // set up text object text = new TextPage(rawOrder); } +TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream, + GBool rawOrderA) { + outputFunc = func; + outputStream = stream; + needClose = gFalse; + rawOrder = rawOrderA; + text = new TextPage(rawOrder); + ok = gTrue; +} + TextOutputDev::~TextOutputDev() { if (needClose) { #ifdef MACOS - ICS_MapRefNumAndAssign((short)f->handle); + ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle); #endif - fclose(f); + fclose((FILE *)outputStream); } if (text) { delete text; } @@ -653,10 +680,10 @@ void TextOutputDev::startPage(int pageNum, GfxState *state) { } void TextOutputDev::endPage() { text->coalesce(); - if (f) { - text->dump(f); + if (outputStream) { + text->dump(outputStream, outputFunc); } } void TextOutputDev::updateFont(GfxState *state) { diff --git a/noncore/unsupported/qpdf/xpdf/TextOutputDev.h b/noncore/unsupported/qpdf/xpdf/TextOutputDev.h index 4c71e5e..f0f238e 100644 --- a/noncore/unsupported/qpdf/xpdf/TextOutputDev.h +++ b/noncore/unsupported/qpdf/xpdf/TextOutputDev.h @@ -1,9 +1,9 @@ //======================================================================== // // TextOutputDev.h // -// Copyright 1997 Derek B. Noonburg +// Copyright 1997-2002 Glyph & Cog, LLC // //======================================================================== #ifndef TEXTOUTPUTDEV_H @@ -21,8 +21,12 @@ class GfxState; class GString; //------------------------------------------------------------------------ + +typedef void (*TextOutputFunc)(void *stream, char *text, int len); + +//------------------------------------------------------------------------ // TextString //------------------------------------------------------------------------ class TextString { @@ -96,9 +100,9 @@ public: GString *getText(fouble xMin, fouble yMin, fouble xMax, fouble yMax); // Dump contents of page to a file. - void dump(FILE *f); + void dump(void *outputStream, TextOutputFunc outputFunc); // Clear the page. void clear(); @@ -127,8 +131,12 @@ public: // written (this is useful, e.g., for searching text). If // <rawOrder> is true, the text is kept in content stream order. TextOutputDev(char *fileName, GBool rawOrderA, GBool append); + // Create a TextOutputDev which will write to a generic stream. If + // <rawOrder> is true, the text is kept in content stream order. + TextOutputDev(TextOutputFunc func, void *stream, GBool rawOrderA); + // Destructor. virtual ~TextOutputDev(); // Check if file was successfully created. @@ -142,8 +150,12 @@ public: // Does this device use drawChar() or drawString()? virtual GBool useDrawChar() { return gTrue; } + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() { return gFalse; } + // Does this device need non-text content? virtual GBool needNonText() { return gFalse; } //----- initialization and control @@ -178,10 +190,12 @@ public: fouble *xMax, fouble *yMax); private: - FILE *f; // text file - GBool needClose; // need to close the file? + TextOutputFunc outputFunc; // output function + void *outputStream; // output stream + GBool needClose; // need to close the output file? + // (only if outputStream is a FILE*) TextPage *text; // text for the current page GBool rawOrder; // keep text in content stream order GBool ok; // set up ok? }; diff --git a/noncore/unsupported/qpdf/xpdf/UnicodeMap.cc b/noncore/unsupported/qpdf/xpdf/UnicodeMap.cc index ab823b1..75f23d2 100644 --- a/noncore/unsupported/qpdf/xpdf/UnicodeMap.cc +++ b/noncore/unsupported/qpdf/xpdf/UnicodeMap.cc @@ -1,9 +1,9 @@ //======================================================================== // // UnicodeMap.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ diff --git a/noncore/unsupported/qpdf/xpdf/UnicodeMap.h b/noncore/unsupported/qpdf/xpdf/UnicodeMap.h index 4d982c8..274c447 100644 --- a/noncore/unsupported/qpdf/xpdf/UnicodeMap.h +++ b/noncore/unsupported/qpdf/xpdf/UnicodeMap.h @@ -3,9 +3,9 @@ // UnicodeMap.h // // Mapping from Unicode to an encoding. // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef UNICODEMAP_H diff --git a/noncore/unsupported/qpdf/xpdf/UnicodeMapTables.h b/noncore/unsupported/qpdf/xpdf/UnicodeMapTables.h index 6fcd44e..51dee98 100644 --- a/noncore/unsupported/qpdf/xpdf/UnicodeMapTables.h +++ b/noncore/unsupported/qpdf/xpdf/UnicodeMapTables.h @@ -1,9 +1,9 @@ //======================================================================== // // UnicodeMapTables.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== static UnicodeMapRange latin1UnicodeMapRanges[] = { @@ -12,8 +12,10 @@ static UnicodeMapRange latin1UnicodeMapRanges[] = { { 0x0020, 0x007e, 0x20, 1 }, { 0x00a0, 0x00a0, 0x20, 1 }, { 0x00a1, 0x00ac, 0xa1, 1 }, { 0x00ae, 0x00ff, 0xae, 1 }, + { 0x010c, 0x010c, 0x43, 1 }, + { 0x010d, 0x010d, 0x63, 1 }, { 0x0131, 0x0131, 0x69, 1 }, { 0x0141, 0x0141, 0x4c, 1 }, { 0x0142, 0x0142, 0x6c, 1 }, { 0x0152, 0x0152, 0x4f45, 2 }, @@ -40,8 +42,25 @@ static UnicodeMapRange latin1UnicodeMapRanges[] = { { 0x203a, 0x203a, 0x3e, 1 }, { 0x2044, 0x2044, 0x2f, 1 }, { 0x2122, 0x2122, 0x544d, 2 }, { 0x2212, 0x2212, 0x2d, 1 }, + { 0xf6f9, 0xf6f9, 0x4c, 1 }, + { 0xf6fa, 0xf6fa, 0x4f45, 2 }, + { 0xf6fc, 0xf6fc, 0xb0, 1 }, + { 0xf6fd, 0xf6fd, 0x53, 1 }, + { 0xf6fe, 0xf6fe, 0x7e, 1 }, + { 0xf6ff, 0xf6ff, 0x5a, 1 }, + { 0xf721, 0xf721, 0x21, 1 }, + { 0xf724, 0xf724, 0x24, 1 }, + { 0xf726, 0xf726, 0x26, 1 }, + { 0xf730, 0xf739, 0x30, 1 }, + { 0xf73f, 0xf73f, 0x3f, 1 }, + { 0xf761, 0xf77a, 0x41, 1 }, + { 0xf7a1, 0xf7a2, 0xa1, 1 }, + { 0xf7bf, 0xf7bf, 0xbf, 1 }, + { 0xf7e0, 0xf7f6, 0xc0, 1 }, + { 0xf7f8, 0xf7fe, 0xd8, 1 }, + { 0xf7ff, 0xf7ff, 0x59, 1 }, { 0xfb00, 0xfb00, 0x6666, 2 }, { 0xfb01, 0xfb01, 0x6669, 2 }, { 0xfb02, 0xfb02, 0x666c, 2 }, { 0xfb03, 0xfb03, 0x666669, 3 }, @@ -134,8 +153,47 @@ static UnicodeMapRange ascii7UnicodeMapRanges[] = { { 0x2022, 0x2022, 0x2a, 1 }, { 0x2026, 0x2026, 0x2e2e2e, 3 }, { 0x2122, 0x2122, 0x544d, 2 }, { 0x2212, 0x2212, 0x2d, 1 }, + { 0xf6f9, 0xf6f9, 0x4c, 1 }, + { 0xf6fa, 0xf6fa, 0x4f45, 2 }, + { 0xf6fd, 0xf6fd, 0x53, 1 }, + { 0xf6fe, 0xf6fe, 0x7e, 1 }, + { 0xf6ff, 0xf6ff, 0x5a, 1 }, + { 0xf721, 0xf721, 0x21, 1 }, + { 0xf724, 0xf724, 0x24, 1 }, + { 0xf726, 0xf726, 0x26, 1 }, + { 0xf730, 0xf739, 0x30, 1 }, + { 0xf73f, 0xf73f, 0x3f, 1 }, + { 0xf761, 0xf77a, 0x41, 1 }, + { 0xf7e0, 0xf7e0, 0x41, 1 }, + { 0xf7e1, 0xf7e1, 0x41, 1 }, + { 0xf7e2, 0xf7e2, 0x41, 1 }, + { 0xf7e3, 0xf7e3, 0x41, 1 }, + { 0xf7e4, 0xf7e4, 0x41, 1 }, + { 0xf7e5, 0xf7e5, 0x41, 1 }, + { 0xf7e6, 0xf7e6, 0x4145, 2 }, + { 0xf7e7, 0xf7e7, 0x43, 1 }, + { 0xf7e8, 0xf7e8, 0x45, 1 }, + { 0xf7e9, 0xf7e9, 0x45, 1 }, + { 0xf7ea, 0xf7ea, 0x45, 1 }, + { 0xf7eb, 0xf7eb, 0x45, 1 }, + { 0xf7ec, 0xf7ec, 0x49, 1 }, + { 0xf7ed, 0xf7ed, 0x49, 1 }, + { 0xf7ee, 0xf7ee, 0x49, 1 }, + { 0xf7ef, 0xf7ef, 0x49, 1 }, + { 0xf7f1, 0xf7f2, 0x4e, 1 }, + { 0xf7f3, 0xf7f3, 0x4f, 1 }, + { 0xf7f4, 0xf7f4, 0x4f, 1 }, + { 0xf7f5, 0xf7f5, 0x4f, 1 }, + { 0xf7f6, 0xf7f6, 0x4f, 1 }, + { 0xf7f8, 0xf7f8, 0x4f, 1 }, + { 0xf7f9, 0xf7f9, 0x55, 1 }, + { 0xf7fa, 0xf7fa, 0x55, 1 }, + { 0xf7fb, 0xf7fb, 0x55, 1 }, + { 0xf7fc, 0xf7fc, 0x55, 1 }, + { 0xf7fd, 0xf7fd, 0x59, 1 }, + { 0xf7ff, 0xf7ff, 0x59, 1 }, { 0xfb00, 0xfb00, 0x6666, 2 }, { 0xfb01, 0xfb01, 0x6669, 2 }, { 0xfb02, 0xfb02, 0x666c, 2 }, { 0xfb03, 0xfb03, 0x666669, 3 }, diff --git a/noncore/unsupported/qpdf/xpdf/XRef.cc b/noncore/unsupported/qpdf/xpdf/XRef.cc index 5d526e9..0e1bbc9 100644 --- a/noncore/unsupported/qpdf/xpdf/XRef.cc +++ b/noncore/unsupported/qpdf/xpdf/XRef.cc @@ -1,9 +1,9 @@ //======================================================================== // // XRef.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ @@ -24,8 +24,9 @@ #ifndef NO_DECRYPTION #include "Decrypt.h" #endif #include "Error.h" +#include "ErrorCodes.h" #include "XRef.h" //------------------------------------------------------------------------ @@ -48,12 +49,13 @@ // XRef //------------------------------------------------------------------------ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { - int pos; + Guint pos; int i; ok = gTrue; + errCode = errNone; size = 0; entries = NULL; streamEnds = NULL; streamEndsLen = 0; @@ -66,16 +68,17 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { // if there was a problem with the trailer, // try to reconstruct the xref table if (pos == 0) { if (!(ok = constructXRef())) { + errCode = errDamaged; return; } // trailer is ok - read the xref table } 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)) ; @@ -85,8 +88,9 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { gfree(entries); size = 0; entries = NULL; if (!(ok = constructXRef())) { + errCode = errDamaged; return; } } } @@ -100,8 +104,9 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { encrypted = gFalse; #endif if (checkEncrypted(ownerPassword, userPassword)) { ok = gFalse; + errCode = errEncrypted; return; } } @@ -114,19 +119,20 @@ 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; buf[n] = c; @@ -140,9 +146,9 @@ 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 -- // this won't work for linearized files.) @@ -175,10 +181,11 @@ int XRef::readTrailer() { pos1 += 7; // read trailer dict obj.initNull(); - parser = new Parser(NULL, new Lexer(NULL, 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); if (obj.isInt()) @@ -203,9 +210,9 @@ int XRef::readTrailer() { return pos; } // 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; @@ -260,9 +267,9 @@ GBool XRef::readXRef(int *pos) { if (first + n > size) { newSize = size + 256; 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; } @@ -272,11 +279,11 @@ GBool XRef::readXRef(int *pos) { 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') { entries[i].used = gTrue; @@ -292,18 +299,19 @@ GBool XRef::readXRef(int *pos) { 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; } } } } // read prev pointer from trailer dictionary obj.initNull(); - parser = new Parser(NULL, new Lexer(NULL, 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")) { goto err1; } @@ -313,9 +321,9 @@ GBool XRef::readXRef(int *pos) { goto err1; } obj.getDict()->lookupNF("Prev", &obj2); if (obj2.isInt()) { - *pos = obj2.getInt(); + *pos = (Guint)obj2.getInt(); more = gTrue; } else { more = gFalse; } @@ -336,9 +344,9 @@ GBool XRef::readXRef(int *pos) { GBool XRef::constructXRef() { Parser *parser; Object obj; char buf[256]; - int pos; + Guint pos; int num, gen; int newSize; int streamEndsSize; char *p; @@ -359,10 +367,11 @@ GBool XRef::constructXRef() { // got trailer dictionary if (!strncmp(p, "trailer", 7)) { obj.initNull(); - parser = new Parser(NULL, new Lexer(NULL, - 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); if (trailerDict.isDict()) { @@ -402,9 +411,9 @@ GBool XRef::constructXRef() { newSize = (num + 1 + 255) & ~255; 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; } @@ -420,9 +429,10 @@ 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; } } @@ -579,12 +589,13 @@ Object *XRef::fetch(int num, int gen, Object *obj) { return obj; } e = &entries[num]; - if (e->gen == gen && e->offset >= 0) { + if (e->gen == gen && e->offset != 0xffffffff) { obj1.initNull(); - parser = new Parser(this, new Lexer(this, - 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); if (obj1.isInt() && obj1.getInt() == num && @@ -617,14 +628,14 @@ Object *XRef::getDocInfo(Object *obj) { Object *XRef::getDocInfoNF(Object *obj) { return trailerDict.dictLookupNF("Info", obj); } -int XRef::getStreamEnd(int streamStart) { +GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) { int a, b, m; if (streamEndsLen == 0 || streamStart > streamEnds[streamEndsLen - 1]) { - return -1; + return gFalse; } a = -1; b = streamEndsLen - 1; @@ -636,6 +647,19 @@ int XRef::getStreamEnd(int streamStart) { } 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/noncore/unsupported/qpdf/xpdf/XRef.h b/noncore/unsupported/qpdf/xpdf/XRef.h index a44c495..7876fa6 100644 --- a/noncore/unsupported/qpdf/xpdf/XRef.h +++ b/noncore/unsupported/qpdf/xpdf/XRef.h @@ -1,9 +1,9 @@ //======================================================================== // // XRef.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef XREF_H @@ -23,9 +23,9 @@ class Stream; // XRef //------------------------------------------------------------------------ struct XRefEntry { - int offset; + Guint offset; int gen; GBool used; }; @@ -40,8 +40,11 @@ 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; } #else @@ -67,30 +70,31 @@ public: // 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 streamStart); + // Returns false if unknown or file is not damaged. + GBool getStreamEnd(Guint streamStart, Guint *streamEnd); private: BaseStream *str; // input stream - int start; // offset in file (to allow for garbage + Guint start; // offset in file (to allow for garbage // at beginning of file) XRefEntry *entries; // xref entries int size; // size of <entries> array int rootNum, rootGen; // catalog dict GBool ok; // true if xref table is valid + int errCode; // error code (if <ok> is false) Object trailerDict; // trailer dictionary - int lastXRefPos; // offset of last xref table - int *streamEnds; // 'endstream' positions - only used in + Guint lastXRefPos; // offset of last xref table + Guint *streamEnds; // 'endstream' positions - only used in // damaged files int streamEndsLen; // number of valid entries in streamEnds #ifndef NO_DECRYPTION GBool encrypted; // true if file is encrypted @@ -101,11 +105,12 @@ private: 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 *ownerPassword, GString *userPassword); + Guint strToUnsigned(char *s); }; #endif |