author | sandman <sandman> | 2002-05-23 23:51:52 (UTC) |
---|---|---|
committer | sandman <sandman> | 2002-05-23 23:51:52 (UTC) |
commit | 2f3bb7b07f833273d966d41813e68bfe8b9d8d76 (patch) (side-by-side diff) | |
tree | 00beb1bd9e7f4ba79e22334a0d258269b28f4564 | |
parent | 6e82b45dd416ceeba78765717b700e853c96a137 (diff) | |
download | opie-2f3bb7b07f833273d966d41813e68bfe8b9d8d76.zip opie-2f3bb7b07f833273d966d41813e68bfe8b9d8d76.tar.gz opie-2f3bb7b07f833273d966d41813e68bfe8b9d8d76.tar.bz2 |
Port to xpdf 1.01
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 @@ -58,48 +58,55 @@ typedef fouble fp_t; //------------------------------------------------------------------------ // XOutputDev //------------------------------------------------------------------------ class QOutputDev : public QScrollView, public OutputDev { public: // Constructor. QOutputDev( QWidget *parent = 0, const char *name = 0, int flags = 0 ); // Destructor. virtual ~QOutputDev(); //---- get info about output device // Does this device use upside-down coordinates? // (Upside-down means (0,0) is the top left corner of the page.) virtual GBool upsideDown() { return gTrue; } // 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); // End a page. virtual void endPage(); //----- link borders virtual void drawLink(Link *link, Catalog *catalog); //----- save/restore graphics state virtual void saveState(GfxState *state); virtual void restoreState(GfxState *state); //----- update graphics state virtual void updateAll(GfxState *state); virtual void updateCTM(GfxState *state, fp_t m11, fp_t m12, fp_t m21, fp_t m22, fp_t m31, fp_t m32); virtual void updateLineDash(GfxState *state); virtual void updateFlatness(GfxState *state); virtual void updateLineJoin(GfxState *state); virtual void updateLineCap(GfxState *state); virtual void updateMiterLimit(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,89 +1,80 @@ 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: - Font substitution handling improved. - Unknown characters are simply ignored now. - Fullscreen view added. Changes in 20020407: - Crash with FontName == 0 fixed - Cleanup - Prepare for CVS import 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 double), which operates on 32bit integers with fixed point arithmetic. This gave a speedup of up to 800% for image rendering. - No Font handling anymore - This means no embedded, no true-type, no type1- fonts. The task to choose the right font is up to the Qt QFont class. This works pretty well -- only Symbol fonts give problems. - Everything that should be rotated (fonts, images) is simply ignored, because a) the Qtopia Qt/E config has QPainter transformations disabled b) the transformation is awful slow c) do you really need rotated images on your iPaq ? ;) ToDo: - Clipping has been deactivated, because Qt/E had problems with QPainter save/restore's with active clipping regions. I need to investigate this in detail. - 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)
\ No newline at end of file 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 @@ -1,24 +1,38 @@ //======================================================================== // // UTF8.h // // Copyright 2001 Derek B. Noonburg // Modified for QPE by Robert Griebl // //======================================================================== #include <qstring.h> #include <string.h> static int mapUTF8 ( Unicode u, char *buf, int bufSize ) { QCString utf = QString ( QChar ( u )). utf8 ( ); int len = utf. length ( ); if ( len <= bufSize ) { ::memcpy ( buf, utf. data ( ), len ); return len; } 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 @@ -1,108 +1,119 @@ //======================================================================== // // qpdf.cc // // Copyright 2001 Robert Griebl // //======================================================================== #include "aconf.h" #include "GString.h" #include "PDFDoc.h" #include "TextOutputDev.h" #include "QPEOutputDev.h" #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> #include <qfileinfo.h> #include <qstring.h> #include <qlineedit.h> #include <qspinbox.h> #include <qlayout.h> #include <qdialog.h> #include <qlabel.h> #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 ); // read config file globalParams = new GlobalParams ( "" ); globalParams-> setErrQuiet ( true ); QPdfDlg *dlg = new QPdfDlg ( ); app. showMainDocumentWidget ( dlg ); if (( app. argc ( ) == 3 ) && ( app. argv ( ) [1] == QCString ( "-f" ))) dlg-> openFile ( app. argv ( ) [2] ); return app. exec ( ); } QPdfDlg::QPdfDlg ( ) : QMainWindow ( ) { setCaption ( tr( "QPdf" )); setIcon ( Resource::loadPixmap ( "qpdf_icon" )); m_busy = false; m_doc = 0; m_pages = 0; m_zoom = 72; m_currentpage = 0; m_fullscreen = false; m_renderok = false; setToolBarsMovable ( false ); m_stack = new QWidgetStack ( this ); m_stack-> setSizePolicy ( QSizePolicy ( QSizePolicy::Expanding, QSizePolicy::Expanding )); setCentralWidget ( m_stack ); 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 ); m_tb_menu-> setHorizontalStretchable ( true ); QMenuBar *mb = new QMenuBar ( m_tb_menu ); m_pm_zoom = new QPopupMenu ( mb ); m_pm_zoom-> setCheckable ( true ); mb-> insertItem ( tr( "Zoom" ), m_pm_zoom ); m_pm_zoom-> insertItem ( tr( "Fit to width" ), 1 ); m_pm_zoom-> insertItem ( tr( "Fit to page" ), 2 ); m_pm_zoom-> insertSeparator ( ); m_pm_zoom-> insertItem ( tr( "50%" ), 50 ); m_pm_zoom-> insertItem ( tr( "75%" ), 75 ); m_pm_zoom-> insertItem ( tr( "100%" ), 100 ); m_pm_zoom-> insertItem ( tr( "125%" ), 125 ); m_pm_zoom-> insertItem ( tr( "150%" ), 150 ); m_pm_zoom-> insertItem ( tr( "200%" ), 200 ); connect ( m_pm_zoom, SIGNAL( activated ( int )), this, SLOT( setZoom ( int ))); 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 @@ -1,37 +1,39 @@ #ifndef __QPDF_H__ #define __QPDF_H__ #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; class QPdfDlg : public QMainWindow { Q_OBJECT public: QPdfDlg ( ); virtual ~QPdfDlg ( ); public slots: void firstPage ( ); void prevPage ( ); void nextPage ( ); void lastPage ( ); void gotoPage ( int n ); void setZoom ( int z ); void gotoPageDialog ( ); void toggleFullscreen ( ); @@ -47,48 +49,53 @@ public slots: void setDocument ( const QString & ); private slots: void delayedInit ( ); void closeFileSelector ( ); void updateCaption ( ); void copyToClipboard ( const QRect & ); protected: void setFullscreen ( bool b = true ); void setBusy ( bool b = true ); bool busy ( ) const; void renderPage ( ); virtual void resizeEvent ( QResizeEvent *e ); virtual void focusInEvent ( QFocusEvent *e ); 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; QToolButton *m_to_find, *m_to_full; bool m_fullscreen; bool m_busy; bool m_renderok; int m_currentpage; int m_pages; int m_zoom; PDFDoc *m_doc; QString m_currentdoc; }; #endif 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 @@ -1,60 +1,61 @@ TEMPLATE = app CONFIG *= qt embedded release warn_off CONFIG -= warn_on SOURCES = xpdf/Array.cc \ xpdf/BuiltinFont.cc \ xpdf/BuiltinFontTables.cc \ xpdf/CMap.cc \ xpdf/Catalog.cc \ xpdf/CharCodeToUnicode.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 \ xpdf/GlobalParams.cc \ xpdf/Lexer.cc \ xpdf/Link.cc \ xpdf/NameToCharCode.cc \ xpdf/Object.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 \ goo/GHash.cc \ goo/GString.cc \ goo/GList.cc \ QOutputDev.cpp \ QPEOutputDev.cpp \ qpdf.cpp \ qbusybar.cpp \ gooStub.cpp HEADERS = QOutputDev.h \ QPEOutputDev.h \ qbusybar.h \ qpdf.h INCLUDEPATH += . \ .. \ xpdf \ $(OPIEDIR)/include \ ../goo \ goo -LIBS += -L $(OPIEDIR)/lib -lqpe +LIBS += -L $(OPIEDIR)/lib -lqpe -lopie DESTDIR = $(OPIEDIR)/bin TARGET = qpdf TRANSLATIONS = ../../i18n/de/qpdf.ts 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,47 +1,47 @@ //======================================================================== // -// FormWidget.cc +// Annot.cc // -// Copyright 2000 Derek B. Noonburg +// Copyright 2000-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #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; xref = xrefA; if (dict->lookup("AP", &apObj)->isDict()) { if (dict->lookup("AS", &asObj)->isName()) { if (apObj.dictLookup("N", &obj1)->isDict()) { if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) { obj2.copy(&appearance); ok = gTrue; } obj2.free(); } obj1.free(); } else { if (apObj.dictLookupNF("N", &obj1)->isRef()) { obj1.copy(&appearance); ok = gTrue; } obj1.free(); } asObj.free(); @@ -56,84 +56,83 @@ FormWidget::FormWidget(XRef *xrefA, Dict *dict) { obj2.free(); obj1.arrayGet(1, &obj2); yMin = obj2.getNum(); obj2.free(); obj1.arrayGet(2, &obj2); xMax = obj2.getNum(); obj2.free(); obj1.arrayGet(3, &obj2); yMax = obj2.getNum(); obj2.free(); if (xMin > xMax) { t = xMin; xMin = xMax; xMax = t; } if (yMin > yMax) { t = yMin; yMin = yMax; yMax = t; } } else { //~ this should return an error xMin = yMin = 0; xMax = yMax = 1; } obj1.free(); } -FormWidget::~FormWidget() { +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(); } obj1.free(); } } } -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,67 +1,69 @@ //======================================================================== // -// 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); // Get appearance object. Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); } 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,29 +1,29 @@ //======================================================================== // // Array.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stddef.h> #include "gmem.h" #include "Object.h" #include "Array.h" //------------------------------------------------------------------------ // Array //------------------------------------------------------------------------ Array::Array(XRef *xrefA) { xref = xrefA; elems = NULL; size = length = 0; ref = 1; } 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,29 +1,29 @@ //======================================================================== // // Array.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef ARRAY_H #define ARRAY_H #ifdef __GNUC__ #pragma interface #endif #include "Object.h" class XRef; //------------------------------------------------------------------------ // Array //------------------------------------------------------------------------ class Array { public: // Constructor. Array(XRef *xrefA); 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,29 +1,29 @@ //======================================================================== // // BuiltinFont.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef BUILTINFONT_H #define BUILTINFONT_H #ifdef __GNUC__ #pragma interface #endif #include "gtypes.h" struct BuiltinFont; class BuiltinFontWidths; //------------------------------------------------------------------------ struct BuiltinFont { char *name; char **defaultBaseEnc; short ascent; short descent; short bbox[4]; BuiltinFontWidths *widths; 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,29 +1,29 @@ //======================================================================== // // BuiltinFontTables.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #include <aconf.h> #include <stdlib.h> #include "FontEncodingTables.h" #include "BuiltinFontTables.h" static BuiltinFontWidth courierWidthsTab[] = { { "Ntilde", 600, NULL }, { "comma", 600, NULL }, { "cedilla", 600, NULL }, { "plusminus", 600, NULL }, { "arrowup", 600, NULL }, { "circumflex", 600, NULL }, { "dotaccent", 600, NULL }, { "LL", 600, NULL }, { "asciitilde", 600, NULL }, { "colon", 600, NULL }, { "onehalf", 600, NULL }, { "dollar", 600, NULL }, { "ntilde", 600, NULL }, { "left", 600, NULL }, { "minus", 600, NULL }, 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,23 +1,23 @@ //======================================================================== // // BuiltinFontTables.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef BUILTINFONTTABLES_H #define BUILTINFONTTABLES_H #include "BuiltinFont.h" #define nBuiltinFonts 14 #define nBuiltinFontSubsts 12 extern BuiltinFont builtinFonts[nBuiltinFonts]; extern BuiltinFont *builtinFontSubst[nBuiltinFontSubsts]; extern void initBuiltinFontTables(); extern void freeBuiltinFontTables(); #endif 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,131 +1,151 @@ //======================================================================== // // CMap.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include "gmem.h" #include "gfile.h" #include "GString.h" #include "Error.h" #include "GlobalParams.h" +#include "PSTokenizer.h" #include "CMap.h" //------------------------------------------------------------------------ struct CMapVectorEntry { GBool isVector; union { CMapVectorEntry *vector; CID cid; }; }; //------------------------------------------------------------------------ +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. if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) { return new CMap(collectionA->copy(), cMapNameA->copy(), 0); } if (!cMapNameA->cmp("Identity-V")) { return new CMap(collectionA->copy(), cMapNameA->copy(), 1); } error(-1, "Couldn't find '%s' CMap file for '%s' collection", cMapNameA->getCString(), collectionA->getCString()); return NULL; } 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; } CMap::CMap(GString *collectionA, GString *cMapNameA) { int i; collection = collectionA; cMapName = cMapNameA; wMode = 0; vector = (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry)); for (i = 0; i < 256; ++i) { vector[i].isVector = gFalse; vector[i].cid = 0; } refCnt = 1; } CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) { collection = collectionA; cMapName = cMapNameA; wMode = wModeA; 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,29 +1,29 @@ //======================================================================== // // CMap.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef CMAP_H #define CMAP_H #ifdef __GNUC__ #pragma interface #endif #include "gtypes.h" #include "CharTypes.h" class GString; struct CMapVectorEntry; class CMapCache; //------------------------------------------------------------------------ class CMap { public: // Create the CMap specified by <collection> and <cMapName>. Sets // the initial reference count to 1. Returns NULL on failure. 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,29 +1,29 @@ //======================================================================== // // Catalog.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stddef.h> #include "gmem.h" #include "Object.h" #include "XRef.h" #include "Array.h" #include "Dict.h" #include "Page.h" #include "Error.h" #include "Link.h" #include "Catalog.h" //------------------------------------------------------------------------ // Catalog //------------------------------------------------------------------------ Catalog::Catalog(XRef *xrefA, GBool printCommands) { @@ -125,49 +125,49 @@ Catalog::~Catalog() { } gfree(pages); gfree(pageRefs); } dests.free(); nameTree.free(); if (baseURI) { delete baseURI; } metadata.free(); structTreeRoot.free(); } GString *Catalog::readMetadata() { GString *s; Dict *dict; Object obj; int c; if (!metadata.isStream()) { return NULL; } dict = metadata.streamGetDict(); if (!dict->lookup("Subtype", &obj)->isName("XML")) { - error(-1, "Unknown Metadata type: '%s'\n", + error(-1, "Unknown Metadata type: '%s'", obj.isName() ? obj.getName() : "???"); } obj.free(); s = new GString(); metadata.streamReset(); while ((c = metadata.streamGetChar()) != EOF) { s->append(c); } metadata.streamClose(); return s; } int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start, GBool printCommands) { Object kids; Object kid; Object kidRef; PageAttrs *attrs1, *attrs2; Page *page; int i, j; attrs1 = new PageAttrs(attrs, pagesDict); pagesDict->lookup("Kids", &kids); if (!kids.isArray()) { @@ -244,52 +244,52 @@ LinkDest *Catalog::findDest(GString *name) { LinkDest *dest; Object obj1, obj2; GBool found; // try named destination dictionary then name tree found = gFalse; if (dests.isDict()) { if (!dests.dictLookup(name->getCString(), &obj1)->isNull()) found = gTrue; else obj1.free(); } if (!found && nameTree.isDict()) { if (!findDestInTree(&nameTree, name, &obj1)->isNull()) found = gTrue; else obj1.free(); } if (!found) return NULL; // 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 { error(-1, "Bad named destination value"); } obj1.free(); return dest; } Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) { Object names, name1; Object kids, kid, limits, low, high; GBool done, found; int cmp, i; // leaf node if (tree->dictLookup("Names", &names)->isArray()) { done = found = gFalse; for (i = 0; !done && i < names.arrayGetLength(); i += 2) { if (names.arrayGet(i, &name1)->isString()) { cmp = name->cmp(name1.getString()); if (cmp == 0) { 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,29 +1,29 @@ //======================================================================== // // Catalog.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef CATALOG_H #define CATALOG_H #ifdef __GNUC__ #pragma interface #endif class XRef; class Object; class Page; class PageAttrs; struct Ref; class LinkDest; //------------------------------------------------------------------------ // Catalog //------------------------------------------------------------------------ class Catalog { public: 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,288 +1,284 @@ //======================================================================== // // CharCodeToUnicode.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdio.h> #include <string.h> #include "gmem.h" #include "gfile.h" #include "GString.h" #include "Error.h" #include "GlobalParams.h" +#include "PSTokenizer.h" #include "CharCodeToUnicode.h" //------------------------------------------------------------------------ #define maxUnicodeString 8 struct CharCodeToUnicodeString { CharCode c; Unicode u[maxUnicodeString]; int len; }; //------------------------------------------------------------------------ +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; char buf[64]; Unicode u; CharCodeToUnicode *ctu; if (!(f = globalParams->getCIDToUnicodeFile(collectionA))) { error(-1, "Couldn't find cidToUnicode file for the '%s' collection", collectionA->getCString()); return NULL; } size = 32768; mapA = (Unicode *)gmalloc(size * sizeof(Unicode)); mapLenA = 0; while (getLine(buf, sizeof(buf), f)) { if (mapLenA == size) { size *= 2; mapA = (Unicode *)grealloc(mapA, size * sizeof(Unicode)); } if (sscanf(buf, "%x", &u) == 1) { mapA[mapLenA] = u; } else { error(-1, "Bad line (%d) in cidToUnicode file for the '%s' collection", (int)(mapLenA + 1), collectionA->getCString()); mapA[mapLenA] = 0; } ++mapLenA; } ctu = new CharCodeToUnicode(collectionA->copy(), mapA, mapLenA, gTrue, NULL, 0); gfree(mapA); return ctu; } 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; char uHex[5]; int j; 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; mapLen = (code1 + 256) & ~255; map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode)); for (i = oldLen; i < mapLen; ++i) { map[i] = 0; } } 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 { map[code1] = 0; if (sMapLen == sMapSize) { sMapSize += 8; sMap = (CharCodeToUnicodeString *) grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString)); } sMap[sMapLen].c = code1; sMap[sMapLen].len = (n2 - 2) / 4; 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; mapLen = (code2 + 256) & ~255; map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode)); for (i = oldLen; i < mapLen; ++i) { map[i] = 0; } } 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++; } } else { if (sMapLen + (int)(code2 - code1 + 1) > sMapSize) { sMapSize = (sMapSize + (code2 - code1 + 1) + 7) & ~7; sMap = (CharCodeToUnicodeString *) grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString)); } for (i = 0; code1 <= code2; ++code1, ++i) { map[code1] = 0; sMap[sMapLen].c = code1; sMap[sMapLen].len = (n3 - 2) / 4; 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; collection = collectionA; mapLen = 256; map = (Unicode *)gmalloc(mapLen * sizeof(Unicode)); for (i = 0; i < mapLen; ++i) { map[i] = 0; } sMap = NULL; sMapLen = sMapSize = 0; refCnt = 1; } CharCodeToUnicode::CharCodeToUnicode(GString *collectionA, Unicode *mapA, CharCode mapLenA, GBool copyMap, CharCodeToUnicodeString *sMapA, int sMapLenA) { collection = collectionA; mapLen = mapLenA; if (copyMap) { map = (Unicode *)gmalloc(mapLen * sizeof(Unicode)); 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 @@ -1,78 +1,77 @@ //======================================================================== // // CharCodeToUnicode.h // // Mapping from character codes to Unicode. // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef CHARCODETOUNICODE_H #define CHARCODETOUNICODE_H #ifdef __GNUC__ #pragma interface #endif #include "CharTypes.h" struct CharCodeToUnicodeString; //------------------------------------------------------------------------ class CharCodeToUnicode { public: // Create the CID-to-Unicode mapping specified by <collection>. // This reads a .cidToUnicode file from disk. Sets the initial // reference count to 1. Returns NULL on failure. static CharCodeToUnicode *parseCIDToUnicode(GString *collectionA); // Create the CharCode-to-Unicode mapping for an 8-bit font. // <toUnicode> is an array of 256 Unicode indexes. Sets the initial // reference count to 1. static CharCodeToUnicode *make8BitToUnicode(Unicode *toUnicode); // Parse a ToUnicode CMap for an 8- or 16-bit font. static CharCodeToUnicode *parseCMap(GString *buf, int nBits); ~CharCodeToUnicode(); void incRefCnt(); void decRefCnt(); // Return true if this mapping matches the specified <collectionA>. GBool match(GString *collectionA); // Map a CharCode to Unicode. 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); GString *collection; Unicode *map; CharCode mapLen; CharCodeToUnicodeString *sMap; int sMapLen, sMapSize; int refCnt; }; //------------------------------------------------------------------------ #define cidToUnicodeCacheSize 4 class CIDToUnicodeCache { public: CIDToUnicodeCache(); ~CIDToUnicodeCache(); // Get the CharCodeToUnicode object for <collection>. Increments 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,24 +1,24 @@ //======================================================================== // // CharTypes.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef CHARTYPES_H #define CHARTYPES_H // Unicode character. typedef unsigned int Unicode; // Character ID for CID character collections. typedef unsigned int CID; // This is large enough to hold any of the following: // - 8-bit char code // - 16-bit CID // - Unicode typedef unsigned int CharCode; #endif 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,29 +1,29 @@ //======================================================================== // // Decrypt.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include "gmem.h" #include "Decrypt.h" static void rc4InitKey(Guchar *key, int keyLen, Guchar *state); static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c); static void md5(Guchar *msg, int msgLen, Guchar *digest); static Guchar passwordPad[32] = { 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a }; //------------------------------------------------------------------------ // Decrypt 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,29 +1,29 @@ //======================================================================== // // Decrypt.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef DECRYPT_H #define DECRYPT_H #ifdef __GNUC__ #pragma interface #endif #include "gtypes.h" #include "GString.h" //------------------------------------------------------------------------ // Decrypt //------------------------------------------------------------------------ class Decrypt { public: // Initialize the decryptor object. Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen); // Reset decryption. 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,29 +1,29 @@ //======================================================================== // // Dict.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stddef.h> #include <string.h> #include "gmem.h" #include "Object.h" #include "XRef.h" #include "Dict.h" //------------------------------------------------------------------------ // Dict //------------------------------------------------------------------------ Dict::Dict(XRef *xrefA) { xref = xrefA; entries = NULL; size = length = 0; ref = 1; 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,29 +1,29 @@ //======================================================================== // // Dict.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef DICT_H #define DICT_H #ifdef __GNUC__ #pragma interface #endif #include "Object.h" //------------------------------------------------------------------------ // Dict //------------------------------------------------------------------------ struct DictEntry { char *key; Object val; }; class Dict { public: 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,31 +1,31 @@ //======================================================================== // // 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"}, {"Helvetica", "-*-helvetica-medium-r-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, {"Helvetica-Bold", "-*-helvetica-bold-r-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, {"Helvetica-BoldOblique", "-*-helvetica-bold-o-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, {"Helvetica-Oblique", "-*-helvetica-medium-o-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, {"Symbol", "-*-symbol-medium-r-normal-*-%s-*-*-*-*-*-adobe-fontspecific", "Symbol"}, {"Times-Bold", "-*-times-bold-r-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, {"Times-BoldItalic", "-*-times-bold-i-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, {"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,29 +1,29 @@ //======================================================================== // // Error.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdio.h> #include <stddef.h> #include <stdarg.h> #include "GlobalParams.h" #include "Error.h" void CDECL error(int pos, char *msg, ...) { va_list args; // NB: this can be called before the globalParams object is created if (globalParams && globalParams->getErrQuiet()) { return; } if (pos >= 0) { fprintf(stderr, "Error (%d): ", pos); } else { 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,21 +1,21 @@ //======================================================================== // // Error.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef ERROR_H #define ERROR_H #ifdef __GNUC__ #pragma interface #endif #include <stdio.h> #include "config.h" extern void CDECL error(int pos, char *msg, ...); #endif 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,29 +1,29 @@ //======================================================================== // // FontEncodingTables.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #include <aconf.h> #include <stdlib.h> #include "FontEncodingTables.h" char *macRomanEncoding[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 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,20 +1,20 @@ //======================================================================== // // FontEncodingTables.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef FONTENCODINGTABLES_H #define FONTENCODINGTABLES_H extern char *macRomanEncoding[]; extern char *macExpertEncoding[]; extern char *winAnsiEncoding[]; extern char *standardEncoding[]; extern char *expertEncoding[]; extern char *symbolEncoding[]; extern char *zapfDingbatsEncoding[]; #endif 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,29 +1,29 @@ //======================================================================== // // Function.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <math.h> #include "gmem.h" #include "Object.h" #include "Dict.h" #include "Stream.h" #include "Error.h" #include "Function.h" //------------------------------------------------------------------------ // Function //------------------------------------------------------------------------ Function::Function() { @@ -394,113 +394,122 @@ void SampledFunction::transform(fouble *in, fouble *out) { } memcpy(s0, s1, (1 << (m - j - 1)) * sizeof(fouble)); } // map output value to range out[i] = s0[0] * (decode[i][1] - decode[i][0]) + decode[i][0]; if (out[i] < range[i][0]) { out[i] = range[i][0]; } else if (out[i] > range[i][1]) { out[i] = range[i][1]; } } } //------------------------------------------------------------------------ // ExponentialFunction //------------------------------------------------------------------------ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { Object obj1, obj2; GBool hasN; int i; ok = gFalse; - hasN = gFalse; //----- initialize the generic stuff if (!init(dict)) { goto err1; } if (m != 1) { error(-1, "Exponential function with more than one input"); goto err1; } + hasN = hasRange; //----- default values for (i = 0; i < funcMaxOutputs; ++i) { c0[i] = 0; c1[i] = 1; } //----- 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; } for (i = 0; i < n; ++i) { obj1.arrayGet(i, &obj2); if (!obj2.isNum()) { error(-1, "Illegal value in function C0 array"); goto err3; } c0[i] = obj2.getNum(); obj2.free(); } } obj1.free(); //----- 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; } for (i = 0; i < n; ++i) { obj1.arrayGet(i, &obj2); if (!obj2.isNum()) { error(-1, "Illegal value in function C1 array"); goto err3; } c1[i] = obj2.getNum(); obj2.free(); } } obj1.free(); //----- N (exponent) if (!dict->lookup("N", &obj1)->isNum()) { error(-1, "Function has missing or invalid N"); goto err2; } 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: obj2.free(); err2: obj1.free(); err1: return; } ExponentialFunction::~ExponentialFunction() { } ExponentialFunction::ExponentialFunction(ExponentialFunction *func) { memcpy(this, func, sizeof(ExponentialFunction)); } void ExponentialFunction::transform(fouble *in, fouble *out) { fouble x; int i; if (in[0] < domain[0][0]) { x = domain[0][0]; 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,29 +1,29 @@ //======================================================================== // // Function.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef FUNCTION_H #define FUNCTION_H #ifdef __GNUC__ #pragma interface #endif #include "gtypes.h" #include "Object.h" class Dict; class Stream; struct PSObject; class PSStack; //------------------------------------------------------------------------ // Function //------------------------------------------------------------------------ #define funcMaxInputs 8 #define funcMaxOutputs 8 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,66 +1,77 @@ //======================================================================== // // Gfx.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdio.h> #include <stddef.h> #include <string.h> #include <math.h> #include "gmem.h" #include "CharTypes.h" #include "Object.h" #include "Array.h" #include "Dict.h" #include "Stream.h" #include "Lexer.h" #include "Parser.h" #include "GfxFont.h" #include "GfxState.h" #include "OutputDev.h" #include "Page.h" #include "Error.h" #include "Gfx.h" +// the MSVC math.h doesn't define this +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + //------------------------------------------------------------------------ // constants //------------------------------------------------------------------------ // Max number of splits along the t axis for an axial shading fill. #define axialMaxSplits 256 // Max delta allowed in any color component for an axial shading fill. #define axialColorDelta (1 / 256.0) +// Max number of splits along the t axis for a radial shading fill. +#define radialMaxSplits 256 + +// Max delta allowed in any color component for a radial shading fill. +#define radialColorDelta (1 / 256.0) + //------------------------------------------------------------------------ // Operator table //------------------------------------------------------------------------ Operator Gfx::opTab[] = { {"\"", 3, {tchkNum, tchkNum, tchkString}, &Gfx::opMoveSetShowText}, {"'", 1, {tchkString}, &Gfx::opMoveShowText}, {"B", 0, {tchkNone}, &Gfx::opFillStroke}, {"B*", 0, {tchkNone}, &Gfx::opEOFillStroke}, {"BDC", 2, {tchkName, tchkProps}, &Gfx::opBeginMarkedContent}, {"BI", 0, {tchkNone}, &Gfx::opBeginImage}, {"BMC", 1, {tchkName}, &Gfx::opBeginMarkedContent}, {"BT", 0, {tchkNone}, &Gfx::opBeginText}, {"BX", 0, {tchkNone}, &Gfx::opBeginIgnoreUndef}, {"CS", 1, {tchkName}, @@ -353,194 +364,228 @@ GBool GfxResources::lookupGState(char *name, Object *obj) { GfxResources *resPtr; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->gStateDict.isDict()) { if (!resPtr->gStateDict.dictLookup(name, obj)->isNull()) { return gTrue; } obj->free(); } } error(-1, "ExtGState '%s' is unknown", name); return gFalse; } //------------------------------------------------------------------------ // Gfx //------------------------------------------------------------------------ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, fouble dpi, PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate, GBool printCommandsA) { int i; xref = xrefA; + subPage = gFalse; printCommands = printCommandsA; // start the resource stack res = new GfxResources(xref, resDict, NULL); // initialize out = outA; state = new GfxState(dpi, box, rotate, out->upsideDown()); fontChanged = gFalse; clip = clipNone; ignoreUndef = 0; out->startPage(pageNum, state); out->setDefaultCTM(state->getCTM()); out->updateAll(state); 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() { - 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; int i; if (obj->isArray()) { for (i = 0; i < obj->arrayGetLength(); ++i) { obj->arrayGet(i, &obj2); if (!obj2.isStream()) { error(-1, "Weird page contents"); obj2.free(); return; } obj2.free(); } } else if (!obj->isStream()) { error(-1, "Weird page contents"); return; } parser = new Parser(xref, new Lexer(xref, obj)); go(topLevel); delete parser; parser = NULL; } void Gfx::go(GBool topLevel) { Object obj; Object args[maxArgs]; - int numCmds, numArgs; + int numArgs; int i; // scan a sequence of objects - numCmds = 0; + updateLevel = 0; numArgs = 0; parser->getObj(&obj); while (!obj.isEOF()) { // got a command - execute it if (obj.isCmd()) { if (printCommands) { obj.print(stdout); for (i = 0; i < numArgs; ++i) { printf(" "); args[i].print(stdout); } printf("\n"); fflush(stdout); } execOp(&obj, args, numArgs); obj.free(); for (i = 0; i < numArgs; ++i) 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) { args[numArgs++] = obj; // too many arguments - something is wrong } else { error(getPos(), "Too many args in content stream"); if (printCommands) { printf("throwing away arg: "); obj.print(stdout); printf("\n"); fflush(stdout); } obj.free(); } // grab the next object parser->getObj(&obj); } obj.free(); // args at end with no command if (numArgs > 0) { error(getPos(), "Leftover args in content stream"); if (printCommands) { printf("%d leftovers:", numArgs); for (i = 0; i < numArgs; ++i) { printf(" "); args[i].print(stdout); } printf("\n"); fflush(stdout); } for (i = 0; i < numArgs; ++i) args[i].free(); } // update display - if (topLevel && numCmds > 0) { + if (topLevel && updateLevel > 0) { out->dump(); } } void Gfx::execOp(Object *cmd, Object args[], int numArgs) { Operator *op; char *name; int i; // find operator name = cmd->getName(); if (!(op = findOp(name))) { if (ignoreUndef == 0) error(getPos(), "Unknown operator '%s'", name); return; } // type check args if (op->numArgs >= 0) { if (numArgs != op->numArgs) { error(getPos(), "Wrong number (%d) of args to '%s' operator", numArgs, name); return; } @@ -1117,49 +1162,49 @@ void Gfx::opCloseEOFillStroke(Object args[], int numArgs) { //error(getPos(), "No path in closepath/eofill/stroke"); return; } if (state->isPath()) { state->closePath(); if (state->getFillColorSpace()->getMode() == csPattern) { doPatternFill(gTrue); } else { out->eoFill(state); } out->stroke(state); } doEndPath(); } void Gfx::doPatternFill(GBool eoFill) { GfxPatternColorSpace *patCS; GfxPattern *pattern; GfxTilingPattern *tPat; GfxColorSpace *cs; 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; // this is a bit of a kludge -- patterns can be really slow, so we // skip them if we're only doing text extraction, since they almost // certainly don't contain any text if (!out->needNonText()) { return; } // get color space patCS = (GfxPatternColorSpace *)state->getFillColorSpace(); // get pattern if (!(pattern = state->getFillPattern())) { return; } if (pattern->getType() != 1) { return; } tPat = (GfxTilingPattern *)pattern; // construct a (pattern space) -> (current space) transform matrix @@ -1168,57 +1213,48 @@ void Gfx::doPatternFill(GBool eoFill) { ptm = tPat->getMatrix(); // iCTM = invert 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; // m1 = PTM * BTM = PTM * base transform matrix m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2]; m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3]; m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2]; m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3]; m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4]; m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5]; // m = m1 * iCTM = (PTM * BTM) * (iCTM) m[0] = m1[0] * ictm[0] + m1[1] * ictm[2]; m[1] = m1[0] * ictm[1] + m1[1] * ictm[3]; m[2] = m1[2] * ictm[0] + m1[3] * ictm[2]; 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; imb[2] = -m1[2] * det; imb[3] = m1[0] * det; imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det; imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det; // save current graphics state out->saveState(state); state = state->save(); // set underlying color space (for uncolored tiling patterns) if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) { state->setFillColorSpace(cs->copy()); } else { state->setFillColorSpace(new GfxDeviceGrayColorSpace()); } state->setFillPattern(NULL); out->updateFillColor(state); // clip to current path state->clip(); @@ -1310,122 +1346,76 @@ void Gfx::opShFill(Object args[], int numArgs) { out->saveState(state); state = state->save(); // clip to bbox if (shading->getHasBBox()) { shading->getBBox(&xMin, &yMin, &xMax, &yMax); state->moveTo(xMin, yMin); state->lineTo(xMax, yMin); state->lineTo(xMax, yMax); state->lineTo(xMin, yMax); state->closePath(); state->clip(); out->clip(state); state->clearPath(); } // set the color space state->setFillColorSpace(shading->getColorSpace()->copy()); // do shading type-specific operations switch (shading->getType()) { case 2: doAxialShFill((GfxAxialShading *)shading); break; + case 3: + doRadialShFill((GfxRadialShading *)shading); + break; } // restore graphics state state = state->restore(); out->restoreState(state); delete shading; } void Gfx::doAxialShFill(GfxAxialShading *shading) { 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; fouble t0, t1, tt; fouble ta[axialMaxSplits + 1]; int next[axialMaxSplits + 1]; 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); dx = x1 - x0; dy = y1 - y0; mul = 1 / (dx * dx + dy * dy); tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul; t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul; if (t < tMin) { tMin = t; } else if (t > tMax) { tMax = t; } t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul; if (t < tMin) { tMin = t; } else if (t > tMax) { tMax = t; } t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul; if (t < tMin) { tMin = t; } else if (t > tMax) { @@ -1598,48 +1588,244 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { // set the color state->setFillColor(&color0); out->updateFillColor(state); // fill the region state->moveTo(ux0, uy0); state->lineTo(vx0, vy0); state->lineTo(vx1, vy1); state->lineTo(ux1, uy1); state->closePath(); out->fill(state); state->clearPath(); // set up for next region ux0 = ux1; uy0 = uy1; vx0 = vx1; vy0 = vy1; color0 = color1; i = next[i]; } } +void Gfx::doRadialShFill(GfxRadialShading *shading) { + 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) { out->clip(state); } else { out->eoClip(state); } } clip = clipNone; state->clearPath(); } //------------------------------------------------------------------------ // path clipping operators //------------------------------------------------------------------------ void Gfx::opClip(Object args[], int numArgs) { clip = clipNormal; } void Gfx::opEOClip(Object args[], int numArgs) { clip = clipEO; } @@ -1779,241 +1965,282 @@ void Gfx::opMoveShowText(Object args[], int numArgs) { doShowText(args[0].getString()); } void Gfx::opMoveSetShowText(Object args[], int numArgs) { fouble tx, ty; if (!state->getFont()) { error(getPos(), "No font in move/set/show"); return; } state->setWordSpace(args[0].getNum()); state->setCharSpace(args[1].getNum()); tx = state->getLineX(); ty = state->getLineY() - state->getLeading(); state->textMoveTo(tx, ty); out->updateWordSpace(state); out->updateCharSpace(state); out->updateTextPos(state); doShowText(args[2].getString()); } 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 { error(getPos(), "Element of show/space array must be number or string"); } obj.free(); } } 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]; } mat = state->getTextMat(); newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2]; newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3]; newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2]; newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3]; mat = font->getFontMatrix(); newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2]; newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3]; newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2]; newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3]; newCTM[0] *= state->getFontSize(); newCTM[3] *= state->getFontSize(); newCTM[0] *= state->getHorizScaling(); newCTM[2] *= state->getHorizScaling(); state->textTransformDelta(0, state->getRise(), &riseX, &riseY); + curX = state->getCurX(); + curY = state->getCurY(); oldParser = parser; p = s->getCString(); len = s->getLength(); while (len > 0) { n = font->getNextChar(p, len, &code, u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, &dx, &dy, &originX, &originY); - 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); out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY, tdx, tdy, tOriginX, tOriginY, code, u, uLen); state->shift(tdx, tdy); p += n; len -= n; } - out->endString(state); } else { dx = dy = 0; p = s->getCString(); len = s->getLength(); nChars = nSpaces = 0; while (len > 0) { n = font->getNextChar(p, len, &code, u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, &dx2, &dy2, &originX, &originY); dx += dx2; dy += dy2; if (n == 1 && *p == ' ') { ++nSpaces; } ++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 if (!res->lookupXObject(args[0].getName(), &obj1)) { return; } if (!obj1.isStream()) { error(getPos(), "XObject '%s' is wrong type", args[0].getName()); obj1.free(); return; } #if OPI_SUPPORT obj1.streamGetDict()->lookup("OPI", &opiDict); if (opiDict.isDict()) { out->opiBegin(state, opiDict.getDict()); } #endif obj1.streamGetDict()->lookup("Subtype", &obj2); if (obj2.isName("Image")) { res->lookupXObjectNF(args[0].getName(), &refObj); 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"); } obj2.free(); #if OPI_SUPPORT if (opiDict.isDict()) { out->opiEnd(state, opiDict.getDict()); } opiDict.free(); #endif obj1.free(); } void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { Dict *dict; int width, height; int bits; GBool mask; GBool invert; GfxColorSpace *colorSpace; GfxImageColorMap *colorMap; Object maskObj; @@ -2127,48 +2354,53 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { delete colorMap; goto err1; } // get the mask haveMask = gFalse; dict->lookup("Mask", &maskObj); if (maskObj.isArray()) { for (i = 0; i < maskObj.arrayGetLength(); ++i) { maskObj.arrayGet(i, &obj1); maskColors[i] = obj1.getInt(); obj1.free(); } haveMask = gTrue; } // draw it out->drawImage(state, ref, str, width, height, colorMap, haveMask ? maskColors : (int *)NULL, inlineImg); delete colorMap; maskObj.free(); } + if ((i = width * height) > 1000) { + i = 1000; + } + updateLevel += i; + return; err2: obj1.free(); err1: error(getPos(), "Bad image parameters"); } void Gfx::doForm(Object *str) { Dict *dict; Object matrixObj, bboxObj; fouble m[6], bbox[6]; Object resObj; Dict *resDict; Object obj1; int i; // get stream dict dict = str->streamGetDict(); // check form type dict->lookup("FormType", &obj1); if (!(obj1.isInt() && obj1.getInt() == 1)) { error(getPos(), "Unknown form type"); @@ -2194,251 +2426,318 @@ void Gfx::doForm(Object *str) { dict->lookup("Matrix", &matrixObj); if (matrixObj.isArray()) { for (i = 0; i < 6; ++i) { matrixObj.arrayGet(i, &obj1); m[i] = obj1.getNum(); obj1.free(); } } else { m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 1; m[4] = 0; m[5] = 0; } matrixObj.free(); // get resources dict->lookup("Resources", &resObj); resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; // draw it doForm1(str, resDict, m, bbox); 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"); return; } for (i = 0; i < 4; ++i) { bboxObj.arrayGet(i, &obj1); bbox[i] = obj1.getNum(); 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); m[i] = obj1.getNum(); obj1.free(); } } else { m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 1; 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; // draw it doForm1(str, resDict, m, bbox); resObj.free(); bboxObj.free(); } 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(); // save current parser oldParser = parser; // set form transformation matrix state->concatCTM(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); out->updateCTM(state, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); // set new base matrix for (i = 0; i < 6; ++i) { oldBaseMatrix[i] = baseMatrix[i]; baseMatrix[i] = state->getCTM()[i]; } // set form bounding box state->moveTo(bbox[0], bbox[1]); state->lineTo(bbox[2], bbox[1]); state->lineTo(bbox[2], bbox[3]); state->lineTo(bbox[0], bbox[3]); state->closePath(); state->clip(); out->clip(state); state->clearPath(); // draw the form display(str, gFalse); // restore base matrix for (i = 0; i < 6; ++i) { baseMatrix[i] = oldBaseMatrix[i]; } // restore parser parser = oldParser; // restore graphics state 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 //------------------------------------------------------------------------ void Gfx::opBeginImage(Object args[], int numArgs) { Stream *str; int c1, c2; // build dict/stream str = buildImageStream(); // display the image if (str) { doImage(NULL, str, gTrue); // skip 'EI' tag c1 = str->getBaseStream()->getChar(); c2 = str->getBaseStream()->getChar(); while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) { c1 = c2; c2 = str->getBaseStream()->getChar(); } delete str; } } Stream *Gfx::buildImageStream() { Object dict; Object obj; char *key; Stream *str; // build dictionary dict.initDict(xref); parser->getObj(&obj); while (!obj.isCmd("ID") && !obj.isEOF()) { if (!obj.isName()) { error(getPos(), "Inline image dictionary key must be a name object"); obj.free(); - parser->getObj(&obj); } else { key = copyString(obj.getName()); obj.free(); parser->getObj(&obj); - if (obj.isEOF() || obj.isError()) + if (obj.isEOF() || obj.isError()) { + gfree(key); break; + } dict.dictAdd(key, &obj); } parser->getObj(&obj); } - if (obj.isEOF()) + if (obj.isEOF()) { error(getPos(), "End of file in inline image"); + obj.free(); + dict.free(); + return NULL; + } obj.free(); // make stream str = new EmbedStream(parser->getStream(), &dict); str = str->addFilters(&dict); return str; } void Gfx::opImageData(Object args[], int numArgs) { error(getPos(), "Internal: got 'ID' operator"); } void Gfx::opEndImage(Object args[], int numArgs) { error(getPos(), "Internal: got 'EI' operator"); } //------------------------------------------------------------------------ // 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 //------------------------------------------------------------------------ void Gfx::opBeginIgnoreUndef(Object args[], int numArgs) { ++ignoreUndef; } void Gfx::opEndIgnoreUndef(Object args[], int numArgs) { if (ignoreUndef > 0) --ignoreUndef; } //------------------------------------------------------------------------ // marked content operators //------------------------------------------------------------------------ void Gfx::opBeginMarkedContent(Object args[], int numArgs) { if (printCommands) { printf(" marked content: %s ", args[0].getName()); if (numArgs == 2) args[2].print(stdout); 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,53 +1,54 @@ //======================================================================== // // Gfx.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef GFX_H #define GFX_H #ifdef __GNUC__ #pragma interface #endif #include "gtypes.h" class GString; class XRef; class Array; class Stream; class Parser; class Dict; class OutputDev; class GfxFontDict; class GfxFont; class GfxPattern; class GfxShading; class GfxAxialShading; +class GfxRadialShading; class GfxState; class Gfx; struct PDFRectangle; //------------------------------------------------------------------------ // Gfx //------------------------------------------------------------------------ enum GfxClipType { clipNone, clipNormal, clipEO }; enum TchkType { tchkBool, // boolean tchkInt, // integer tchkNum, // number (integer or real) tchkString, // string tchkName, // name tchkArray, // array tchkProps, // properties (dictionary or name) tchkSCN, // scn/SCN args (number of name) tchkNone // used to avoid empty initializer lists @@ -76,63 +77,73 @@ public: GfxShading *lookupShading(char *name); GBool lookupGState(char *name, Object *obj); GfxResources *getNext() { return next; } private: GfxFontDict *fonts; Object xObjDict; Object colorSpaceDict; Object patternDict; Object shadingDict; Object gStateDict; GfxResources *next; }; class Gfx { public: // Constructor for regular output. 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? int ignoreUndef; // current BX/EX nesting level fouble baseMatrix[6]; // default matrix for most recent // page/form/pattern Parser *parser; // parser for page content stream(s) static Operator opTab[]; // table of operators void go(GBool topLevel); void execOp(Object *cmd, Object args[], int numArgs); Operator *findOp(char *name); GBool checkArg(Object *arg, TchkType type); int getPos(); // graphics state operators void opSave(Object args[], int numArgs); void opRestore(Object args[], int numArgs); void opConcat(Object args[], int numArgs); void opSetDash(Object args[], int numArgs); void opSetFlat(Object args[], int numArgs); @@ -158,48 +169,49 @@ private: void opSetStrokeColorN(Object args[], int numArgs); // path segment operators void opMoveTo(Object args[], int numArgs); void opLineTo(Object args[], int numArgs); void opCurveTo(Object args[], int numArgs); void opCurveTo1(Object args[], int numArgs); void opCurveTo2(Object args[], int numArgs); void opRectangle(Object args[], int numArgs); void opClosePath(Object args[], int numArgs); // path painting operators void opEndPath(Object args[], int numArgs); void opStroke(Object args[], int numArgs); void opCloseStroke(Object args[], int numArgs); void opFill(Object args[], int numArgs); void opEOFill(Object args[], int numArgs); void opFillStroke(Object args[], int numArgs); void opCloseFillStroke(Object args[], int numArgs); void opEOFillStroke(Object args[], int numArgs); 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); void opEOClip(Object args[], int numArgs); // text object operators void opBeginText(Object args[], int numArgs); void opEndText(Object args[], int numArgs); // text state operators void opSetCharSpacing(Object args[], int numArgs); void opSetFont(Object args[], int numArgs); void opSetTextLeading(Object args[], int numArgs); void opSetTextRender(Object args[], int numArgs); void opSetTextRise(Object args[], int numArgs); void opSetWordSpacing(Object args[], int numArgs); void opSetHorizScaling(Object args[], int numArgs); // text positioning operators void opTextMove(Object args[], int numArgs); void opTextMoveSet(Object args[], int numArgs); void opSetTextMatrix(Object args[], int numArgs); void opTextNextLine(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,29 +1,29 @@ //======================================================================== // // GfxFont.cc // -// Copyright 1996-2001 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include "gmem.h" #include "Error.h" #include "Object.h" #include "Dict.h" #include "GlobalParams.h" #include "CMap.h" #include "CharCodeToUnicode.h" #include "FontEncodingTables.h" #include "BuiltinFontTables.h" #include "FontFile.h" #include "GfxFont.h" @@ -433,55 +433,66 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, ascent = 0.95; descent = -0.35; fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0; } // get info from font descriptor readFontDescriptor(xref, fontDict); // look for an external font file findExtFontFile(); // get font matrix fontMat[0] = fontMat[3] = 1; fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0; if (fontDict->lookup("FontMatrix", &obj1)->isArray()) { for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) { if (obj1.arrayGet(i, &obj2)->isNum()) { fontMat[i] = obj2.getNum(); } obj2.free(); } } obj1.free(); - // get 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 ----- // Encodings start with a base encoding, which can come from // (in order of priority): // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding // - MacRoman / MacExpert / WinAnsi / Standard // 2. embedded or external font file // 3. default: // - builtin --> builtin encoding // - TrueType --> MacRomanEncoding // - others --> StandardEncoding // and then add a list of differences (if any) from // FontDict.Encoding.Differences. // check FontDict for base encoding hasEncoding = gFalse; baseEnc = NULL; baseEncFromFontFile = gFalse; fontDict->lookup("Encoding", &obj1); if (obj1.isDict()) { obj1.dictLookup("BaseEncoding", &obj2); if (obj2.isName("MacRomanEncoding")) { @@ -492,104 +503,110 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, baseEnc = macExpertEncoding; } else if (obj2.isName("WinAnsiEncoding")) { hasEncoding = gTrue; baseEnc = winAnsiEncoding; } else if (obj2.isName("StandardEncoding")) { hasEncoding = gTrue; baseEnc = standardEncoding; } obj2.free(); } else if (obj1.isName("MacRomanEncoding")) { hasEncoding = gTrue; baseEnc = macRomanEncoding; } else if (obj1.isName("MacExpertEncoding")) { hasEncoding = gTrue; baseEnc = macExpertEncoding; } else if (obj1.isName("WinAnsiEncoding")) { hasEncoding = gTrue; baseEnc = winAnsiEncoding; } else if (obj1.isName("StandardEncoding")) { hasEncoding = gTrue; baseEnc = standardEncoding; } // check embedded or external font file for base encoding + // (only for Type 1 fonts - trying to get an encoding out of a + // TrueType font is a losing proposition) fontFile = NULL; buf = NULL; - if ((type == fontType1 || type == fontType1C || 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; } embFontName = new GString(fontFile->getName()); } if (!baseEnc) { baseEnc = fontFile->getEncoding(); baseEncFromFontFile = gTrue; } #endif gfree(buf); } } // get default base encoding if (!baseEnc) { if (builtinFont) { baseEnc = builtinFont->defaultBaseEnc; } else if (type == fontTrueType) { baseEnc = macRomanEncoding; } else { baseEnc = standardEncoding; } } // copy the base encoding for (i = 0; i < 256; ++i) { enc[i] = baseEnc[i]; if ((encFree[i] = baseEncFromFontFile) && enc[i]) { enc[i] = copyString(baseEnc[i]); } } // merge differences into encoding if (obj1.isDict()) { obj1.dictLookup("Differences", &obj2); if (obj2.isArray()) { + hasEncoding = gTrue; code = 0; for (i = 0; i < obj2.arrayGetLength(); ++i) { obj2.arrayGet(i, &obj3); if (obj3.isInt()) { code = obj3.getInt(); } else if (obj3.isName()) { if (code < 256) { if (encFree[code]) { gfree(enc[code]); } enc[code] = copyString(obj3.getName()); encFree[code] = gTrue; } ++code; } else { error(-1, "Wrong type in font encoding resource differences (%s)", obj3.getTypeName()); } obj3.free(); } } obj2.free(); } obj1.free(); @@ -615,100 +632,108 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // and 'xx' is two hex digits if ((strlen(charName) == 3 && isalpha(charName[0]) && isxdigit(charName[1]) && isxdigit(charName[2]) && ((charName[1] >= 'a' && charName[1] <= 'f') || (charName[1] >= 'A' && charName[1] <= 'F') || (charName[2] >= 'a' && charName[2] <= 'f') || (charName[2] >= 'A' && charName[2] <= 'F'))) || (strlen(charName) == 2 && isxdigit(charName[0]) && isxdigit(charName[1]) && ((charName[0] >= 'a' && charName[0] <= 'f') || (charName[0] >= 'A' && charName[0] <= 'F') || (charName[1] >= 'a' && charName[1] <= 'f') || (charName[1] >= 'A' && charName[1] <= 'F')))) { hex = gTrue; } missing = gTrue; } } else { toUnicode[code] = 0; } } // pass 2: try to fill in the missing chars, looking for names of - // the form 'Axx', 'xx', 'Ann', 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")) { n = strlen(charName); code2 = -1; if (hex && n == 3 && isalpha(charName[0]) && isxdigit(charName[1]) && isxdigit(charName[2])) { sscanf(charName+1, "%x", &code2); } else if (hex && n == 2 && isxdigit(charName[0]) && isxdigit(charName[1])) { sscanf(charName, "%x", &code2); } else if (!hex && n >= 2 && n <= 4 && isdigit(charName[0]) && isdigit(charName[1])) { code2 = atoi(charName); } else if (n >= 3 && n <= 5 && isdigit(charName[1]) && isdigit(charName[2])) { code2 = atoi(charName+1); + } else if (n >= 4 && n <= 6 && + isdigit(charName[2]) && isdigit(charName[3])) { + code2 = atoi(charName+2); } if (code2 >= 0 && code2 <= 0xff) { toUnicode[code] = (Unicode)code2; } } } } ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode); } //----- get the character widths ----- // initialize all widths for (code = 0; code < 256; ++code) { widths[code] = missingWidth * 0.001; } // use widths from font dict, if present fontDict->lookup("FirstChar", &obj1); firstChar = obj1.isInt() ? obj1.getInt() : 0; obj1.free(); fontDict->lookup("LastChar", &obj1); lastChar = obj1.isInt() ? obj1.getInt() : 255; obj1.free(); mul = (type == fontType3) ? fontMat[0] : 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(); } // use widths from built-in font } else if (builtinFont) { // this is a kludge for broken PDF files that encode char 32 // as .notdef if (builtinFont->widths->getWidth("space", &w)) { widths[32] = 0.001 * w; } for (code = 0; code < 256; ++code) { if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) { widths[code] = 0.001 * w; } } // couldn't find widths -- use defaults } else { // this is technically an error -- the Widths entry is required // for all but the Base-14 fonts -- but certain PDF generators // apparently don't include widths for Arial and TimesNewRoman if (isFixedWidth()) { i = 0; @@ -731,76 +756,87 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, } for (code = 0; code < 256; ++code) { if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) { widths[code] = 0.001 * w; } } } obj1.free(); ok = gTrue; } Gfx8BitFont::~Gfx8BitFont() { int i; for (i = 0; i < 256; ++i) { if (encFree[i] && enc[i]) { gfree(enc[i]); } } ctu->decRefCnt(); if (charProcs.isDict()) { charProcs.free(); } + if (resources.isDict()) { + resources.free(); + } } int Gfx8BitFont::getNextChar(char *s, int len, CharCode *code, Unicode *u, int uSize, int *uLen, fouble *dx, fouble *dy, fouble *ox, fouble *oy) { CharCode c; *code = c = (CharCode)(*s & 0xff); *uLen = ctu->mapToUnicode(c, u, uSize); *dx = widths[c]; *dy = *ox = *oy = 0; return 1; } CharCodeToUnicode *Gfx8BitFont::getToUnicode() { ctu->incRefCnt(); return ctu; } +Dict *Gfx8BitFont::getCharProcs() { + return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL; +} + Object *Gfx8BitFont::getCharProc(int code, Object *proc) { if (charProcs.isDict()) { charProcs.dictLookup(enc[code], proc); } else { proc->initNull(); } return proc; } +Dict *Gfx8BitFont::getResources() { + return resources.isDict() ? resources.getDict() : (Dict *)NULL; +} + //------------------------------------------------------------------------ // GfxCIDFont //------------------------------------------------------------------------ static int cmpWidthExcep(const void *w1, const void *w2) { return ((GfxFontCIDWidthExcep *)w1)->first - ((GfxFontCIDWidthExcep *)w2)->first; } static int cmpWidthExcepV(const void *w1, const void *w2) { return ((GfxFontCIDWidthExcepV *)w1)->first - ((GfxFontCIDWidthExcepV *)w2)->first; } GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, Dict *fontDict): GfxFont(tagA, idA, nameA) { Dict *desFontDict; GString *collection, *cMapName; Object desFontDictObj; Object obj1, obj2, obj3, obj4, obj5, obj6; int c1, c2; int excepsSize, i, j, k; @@ -1165,79 +1201,83 @@ int GfxCIDFont::getNextChar(char *s, int len, CharCode *code, while (b - a > 1) { m = (a + b) / 2; if (widths.excepsV[m].last <= cid) { a = m; } else { b = m; } } if (cid <= widths.excepsV[a].last) { h = widths.excepsV[a].height; vx = widths.excepsV[a].vx; vy = widths.excepsV[a].vy; } } } *dx = w; *dy = h; *ox = vx; *oy = vy; return n; } +int GfxCIDFont::getWMode() { + return cMap ? cMap->getWMode() : 0; +} + CharCodeToUnicode *GfxCIDFont::getToUnicode() { ctu->incRefCnt(); return ctu; } GString *GfxCIDFont::getCollection() { return cMap ? cMap->getCollection() : (GString *)NULL; } //------------------------------------------------------------------------ // GfxFontDict //------------------------------------------------------------------------ GfxFontDict::GfxFontDict(XRef *xref, Dict *fontDict) { int i; Object obj1, obj2; numFonts = fontDict->getLength(); fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *)); for (i = 0; i < numFonts; ++i) { fontDict->getValNF(i, &obj1); obj1.fetch(xref, &obj2); if (obj1.isRef() && obj2.isDict()) { fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i), obj1.getRef(), obj2.getDict()); if (fonts[i] && !fonts[i]->isOk()) { delete fonts[i]; fonts[i] = NULL; } } else { - error(-1, "font resource is not a dictionary"); + error(-1, "font resource is not a dictionary reference"); fonts[i] = NULL; } obj1.free(); obj2.free(); } } GfxFontDict::~GfxFontDict() { int i; for (i = 0; i < numFonts; ++i) { if (fonts[i]) { delete fonts[i]; } } gfree(fonts); } GfxFont *GfxFontDict::lookup(char *tag) { int i; for (i = 0; i < numFonts; ++i) { if (fonts[i] && fonts[i]->matches(tag)) { return fonts[i]; 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,29 +1,29 @@ //======================================================================== // // GfxFont.h // -// Copyright 1996-2001 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef GFXFONT_H #define GFXFONT_H #ifdef __GNUC__ #pragma interface #endif #include "gtypes.h" #include "GString.h" #include "Object.h" #include "CharTypes.h" class Dict; class CMap; class CharCodeToUnicode; struct GfxFontCIDWidths; //------------------------------------------------------------------------ // GfxFontType //------------------------------------------------------------------------ @@ -92,171 +92,183 @@ public: // Get font tag. GString *getTag() { return tag; } // Get font dictionary ID. Ref *getID() { return &id; } // Does this font match the tag? GBool matches(char *tagA) { return !tag->cmp(tagA); } // Get base font name. GString *getName() { return name; } // Get font type. GfxFontType getType() { return type; } virtual GBool isCIDFont() { return gFalse; } // Get embedded font ID, i.e., a ref for the font file stream. // Returns false if there is no embedded font. GBool getEmbeddedFontID(Ref *embID) { *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; } // Get font descriptor flags. GBool isFixedWidth() { return flags & fontFixedWidth; } GBool isSerif() { return flags & fontSerif; } GBool isSymbolic() { return flags & fontSymbolic; } GBool isItalic() { return flags & fontItalic; } GBool isBold() { return flags & fontBold; } // Return the font matrix. fouble *getFontMatrix() { return fontMat; } // Return the font bounding box. fouble *getFontBBox() { return fontBBox; } // 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); // Get the next char from a string <s> of <len> bytes, returning the // char <code>, its Unicode mapping <u>, its displacement vector // (<dx>, <dy>), and its origin offset vector (<ox>, <oy>). <uSize> // is the number of entries available in <u>, and <uLen> is set to // the number actually used. Returns the number of bytes used by // the char code. virtual int getNextChar(char *s, int len, CharCode *code, Unicode *u, int uSize, int *uLen, fouble *dx, fouble *dy, fouble *ox, fouble *oy) = 0; 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 GfxFontType type; // type of font int flags; // font descriptor flags GString *embFontName; // name of embedded font Ref embFontID; // ref to embedded font file stream GString *extFontFile; // external font file name 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; }; //------------------------------------------------------------------------ // Gfx8BitFont //------------------------------------------------------------------------ class Gfx8BitFont: public GfxFont { public: Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Dict *fontDict); virtual ~Gfx8BitFont(); virtual int getNextChar(char *s, int len, CharCode *code, Unicode *u, int uSize, int *uLen, fouble *dx, fouble *dy, fouble *ox, fouble *oy); // Return the encoding. char **getEncoding() { return enc; } // Return the Unicode map. CharCodeToUnicode *getToUnicode(); // Return the character name associated with <code>. char *getCharName(int code) { return enc[code]; } // Returns true if the PDF font specified an encoding. GBool getHasEncoding() { return hasEncoding; } // 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 //------------------------------------------------------------------------ class GfxCIDFont: public GfxFont { public: GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, Dict *fontDict); virtual ~GfxCIDFont(); virtual GBool isCIDFont() { return gTrue; } 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>). GString *getCollection(); // Return the CID-to-GID mapping table. These should only be called // if type is fontCIDType2. Gushort *getCIDToGID() { return cidToGID; } int getCIDToGIDLen() { return cidToGIDLen; } private: CMap *cMap; // char code --> CID CharCodeToUnicode *ctu; // CID --> Unicode GfxFontCIDWidths widths; // character widths Gushort *cidToGID; // CID --> GID mapping (for embedded // TrueType fonts) int cidToGIDLen; }; //------------------------------------------------------------------------ // GfxFontDict //------------------------------------------------------------------------ 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,29 +1,29 @@ //======================================================================== // // GfxState.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stddef.h> #include <math.h> #include <string.h> // for memcpy() #include "gmem.h" #include "Error.h" #include "Object.h" #include "Array.h" #include "Page.h" #include "GfxState.h" //------------------------------------------------------------------------ static inline fouble clip01(fouble x) { return (x < 0) ? fouble(0) : ((x > 1) ? fouble(1) : x); } @@ -387,51 +387,64 @@ void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { } //------------------------------------------------------------------------ // GfxDeviceCMYKColorSpace //------------------------------------------------------------------------ GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() { } GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() { } GfxColorSpace *GfxDeviceCMYKColorSpace::copy() { return new GfxDeviceCMYKColorSpace(); } void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, fouble *gray) { *gray = clip01(1 - color->c[3] - 0.299 * color->c[0] - 0.587 * color->c[1] - 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]); cmyk->m = clip01(color->c[1]); cmyk->y = clip01(color->c[2]); cmyk->k = clip01(color->c[3]); } //------------------------------------------------------------------------ // GfxLabColorSpace //------------------------------------------------------------------------ // This is the inverse of MatrixLMN in Example 4.10 from the PostScript // Language Reference, Third Edition. static fouble xyzrgb[3][3] = { { 3.240449, -1.537136, -0.498531 }, { -0.969265, 1.876011, 0.041556 }, { 0.055643, -0.204026, 1.057229 } }; GfxLabColorSpace::GfxLabColorSpace() { whiteX = whiteY = whiteZ = 1; blackX = blackY = blackZ = 0; @@ -1247,98 +1260,104 @@ GfxShading::~GfxShading() { delete colorSpace; } GfxShading *GfxShading::parse(Object *obj) { GfxShading *shading; int typeA; GfxColorSpace *colorSpaceA; GfxColor backgroundA; GBool hasBackgroundA; fouble xMinA, yMinA, xMaxA, yMaxA; GBool hasBBoxA; Object obj1, obj2; int i; shading = NULL; if (obj->isDict()) { if (!obj->dictLookup("ShadingType", &obj1)->isInt()) { error(-1, "Invalid ShadingType in shading dictionary"); obj1.free(); 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"); obj1.free(); goto err1; } obj1.free(); for (i = 0; i < gfxColorMaxComps; ++i) { backgroundA.c[i] = 0; } hasBackgroundA = gFalse; if (obj->dictLookup("Background", &obj1)->isArray()) { if (obj1.arrayGetLength() == colorSpaceA->getNComps()) { hasBackgroundA = gTrue; for (i = 0; i < colorSpaceA->getNComps(); ++i) { backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum(); obj2.free(); } } else { error(-1, "Bad Background in shading dictionary"); } } obj1.free(); xMinA = yMinA = xMaxA = yMaxA = 0; hasBBoxA = gFalse; if (obj->dictLookup("BBox", &obj1)->isArray()) { if (obj1.arrayGetLength() == 4) { hasBBoxA = gTrue; xMinA = obj1.arrayGet(0, &obj2)->getNum(); obj2.free(); yMinA = obj1.arrayGet(1, &obj2)->getNum(); obj2.free(); xMaxA = obj1.arrayGet(2, &obj2)->getNum(); obj2.free(); yMaxA = obj1.arrayGet(3, &obj2)->getNum(); obj2.free(); } else { error(-1, "Bad BBox in shading dictionary"); } } 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; shading->background = backgroundA; shading->hasBackground = hasBackgroundA; shading->xMin = xMinA; shading->yMin = yMinA; shading->xMax = xMaxA; shading->yMax = yMaxA; shading->hasBBox = hasBBoxA; } else { delete colorSpaceA; } } return shading; err1: return NULL; } //------------------------------------------------------------------------ // GfxAxialShading @@ -1436,48 +1455,170 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict) { obj1.arrayGetLength() == 2) { extend0A = obj1.arrayGet(0, &obj2)->getBool(); obj2.free(); extend1A = obj1.arrayGet(1, &obj2)->getBool(); obj2.free(); } obj1.free(); return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A, funcsA, nFuncsA, extend0A, extend1A); err1: return NULL; } void GfxAxialShading::getColor(fouble t, GfxColor *color) { int i; for (i = 0; i < nFuncs; ++i) { funcs[i]->transform(&t, &color->c[i]); } } //------------------------------------------------------------------------ +// 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, GfxColorSpace *colorSpaceA) { GfxIndexedColorSpace *indexedCS; GfxSeparationColorSpace *sepCS; int maxPixel, indexHigh; Guchar *lookup2; Function *sepFunc; Object obj; fouble x[gfxColorMaxComps]; fouble y[gfxColorMaxComps]; int i, j, k; ok = gTrue; // bits per component and color space bits = bitsA; maxPixel = (1 << bits) - 1; colorSpace = colorSpaceA; // get decode map if (decode->isNull()) { @@ -1897,97 +2038,179 @@ GfxState::~GfxState() { } // Used for copy(); GfxState::GfxState(GfxState *state) { memcpy(this, state, sizeof(GfxState)); if (fillColorSpace) { fillColorSpace = state->fillColorSpace->copy(); } if (strokeColorSpace) { strokeColorSpace = state->strokeColorSpace->copy(); } if (fillPattern) { fillPattern = state->fillPattern->copy(); } if (strokePattern) { strokePattern = state->strokePattern->copy(); } if (lineDashLength > 0) { lineDash = (fouble *)gmalloc(lineDashLength * sizeof(fouble)); memcpy(lineDash, state->lineDash, lineDashLength * sizeof(fouble)); } 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]; y = ctm[1] + ctm[3]; return w * sqrt(0.5 * (x * x + y * y)); } fouble GfxState::getTransformedFontSize() { fouble x1, y1, x2, y2; x1 = textMat[2] * fontSize; y1 = textMat[3] * fontSize; x2 = ctm[0] * x1 + ctm[2] * y1; y2 = ctm[1] * x1 + ctm[3] * y1; return sqrt(x2 * x2 + y2 * y2); } void GfxState::getFontTransMat(fouble *m11, fouble *m12, fouble *m21, fouble *m22) { *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize; *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize; *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize; *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize; } 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) { delete fillColorSpace; } fillColorSpace = colorSpace; } void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) { if (strokeColorSpace) { delete strokeColorSpace; } strokeColorSpace = colorSpace; } void GfxState::setFillPattern(GfxPattern *pattern) { if (fillPattern) { delete fillPattern; } fillPattern = pattern; } void GfxState::setStrokePattern(GfxPattern *pattern) { @@ -2030,68 +2253,69 @@ void GfxState::clip() { xMax = x; } if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } } } } if (xMin > clipXMin) { clipXMin = xMin; } if (yMin > clipYMin) { clipYMin = yMin; } if (xMax < clipXMax) { clipXMax = xMax; } if (yMax < clipYMax) { clipYMax = yMax; } } -void GfxState::textShift(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; } void GfxState::shift(fouble dx, fouble dy) { curX += dx; curY += dy; } GfxState *GfxState::save() { GfxState *newState; newState = copy(); newState->saved = this; return newState; } GfxState *GfxState::restore() { GfxState *oldState; if (saved) { oldState = saved; // these attributes aren't saved/restored by the q/Q operators oldState->path = path; oldState->curX = curX; oldState->curY = curY; oldState->lineX = lineX; oldState->lineY = lineY; path = NULL; saved = NULL; delete this; } else { oldState = this; } return oldState; } + diff --git a/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,29 +1,29 @@ //======================================================================== // // GfxState.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef GFXSTATE_H #define GFXSTATE_H #ifdef __GNUC__ #pragma interface #endif #include "gtypes.h" #include "Object.h" #include "Function.h" class Array; class GfxFont; struct PDFRectangle; //------------------------------------------------------------------------ // GfxColor //------------------------------------------------------------------------ #define gfxColorMaxComps funcMaxOutputs @@ -547,48 +547,82 @@ public: Function **funcsA, int nFuncsA, GBool extend0A, GBool extend1A); virtual ~GfxAxialShading(); static GfxAxialShading *parse(Dict *dict); void getCoords(fouble *x0A, fouble *y0A, fouble *x1A, fouble *y1A) { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } 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, x1, y1; fouble t0, t1; Function *funcs[gfxColorMaxComps]; int nFuncs; 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 { public: // Constructor. GfxImageColorMap(int bitsA, Object *decode, GfxColorSpace *colorSpaceA); // Destructor. ~GfxImageColorMap(); // Is color map valid? GBool isOk() { return ok; } // Get the color space. GfxColorSpace *getColorSpace() { return colorSpace; } // Get stream decoding info. int getNumPixelComps() { return nComps; } int getBits() { return bits; } // Get decode table. fouble getDecodeLow(int i) { return decodeLow[i]; } @@ -762,48 +796,49 @@ public: GfxPattern *getStrokePattern() { return strokePattern; } fouble getFillOpacity() { return fillOpacity; } fouble getStrokeOpacity() { return strokeOpacity; } fouble getLineWidth() { return lineWidth; } void getLineDash(fouble **dash, int *length, fouble *start) { *dash = lineDash; *length = lineDashLength; *start = lineDashStart; } int getFlatness() { return flatness; } int getLineJoin() { return lineJoin; } int getLineCap() { return lineCap; } fouble getMiterLimit() { return miterLimit; } GfxFont *getFont() { return font; } fouble getFontSize() { return fontSize; } fouble *getTextMat() { return textMat; } fouble getCharSpace() { return charSpace; } fouble getWordSpace() { return wordSpace; } fouble getHorizScaling() { return horizScaling; } fouble getLeading() { return leading; } fouble getRise() { return rise; } int getRender() { return render; } GfxPath *getPath() { return path; } 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? GBool isCurPt() { return path->isCurPt(); } GBool isPath() { return path->isPath(); } // Transforms. void transform(fouble x1, fouble y1, fouble *x2, fouble *y2) { *x2 = ctm[0] * x1 + ctm[2] * y1 + ctm[4]; *y2 = ctm[1] * x1 + ctm[3] * y1 + ctm[5]; } void transformDelta(fouble x1, fouble y1, fouble *x2, fouble *y2) { *x2 = ctm[0] * x1 + ctm[2] * y1; *y2 = ctm[1] * x1 + ctm[3] * y1; } void textTransform(fouble x1, fouble y1, fouble *x2, fouble *y2) { *x2 = textMat[0] * x1 + textMat[2] * y1 + textMat[4]; *y2 = textMat[1] * x1 + textMat[3] * y1 + textMat[5]; } void textTransformDelta(fouble x1, fouble y1, fouble *x2, fouble *y2) { *x2 = textMat[0] * x1 + textMat[2] * y1; *y2 = textMat[1] * x1 + textMat[3] * y1; } fouble transformWidth(fouble w); fouble getTransformedLineWidth() { return transformWidth(lineWidth); } fouble getTransformedFontSize(); @@ -844,49 +879,49 @@ public: { leading = leadingA; } void setRise(fouble riseA) { rise = riseA; } void setRender(int renderA) { render = renderA; } // Add to path. void moveTo(fouble x, fouble y) { path->moveTo(curX = x, curY = y); } void lineTo(fouble x, fouble y) { path->lineTo(curX = x, curY = y); } void curveTo(fouble x1, fouble y1, fouble x2, fouble y2, fouble x3, fouble y3) { path->curveTo(x1, y1, x2, y2, curX = x3, curY = y3); } void closePath() { path->close(); curX = path->getLastX(); curY = path->getLastY(); } void clearPath(); // Update clip region. void clip(); // 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(); GfxState *restore(); GBool hasSaves() { return saved != NULL; } private: fouble ctm[6]; // coord transform matrix fouble px1, py1, px2, py2; // page corners (user coords) fouble pageWidth, pageHeight; // page size (pixels) GfxColorSpace *fillColorSpace; // fill color space GfxColorSpace *strokeColorSpace; // stroke color space GfxColor fillColor; // fill color GfxColor strokeColor; // stroke color GfxPattern *fillPattern; // fill pattern GfxPattern *strokePattern; // stroke pattern fouble fillOpacity; // fill opacity fouble strokeOpacity; // stroke opacity fouble lineWidth; // line width fouble *lineDash; // line dash 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,29 +1,29 @@ //======================================================================== // // GlobalParams.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <string.h> #include <ctype.h> #if HAVE_PAPER_H #include <paper.h> #endif #include "gmem.h" #include "GString.h" #include "GList.h" #include "GHash.h" #include "gfile.h" #include "Error.h" #include "NameToCharCode.h" #include "CharCodeToUnicode.h" #include "UnicodeMap.h" #include "CMap.h" #include "BuiltinFontTables.h" @@ -75,278 +75,334 @@ DisplayFontParam::~DisplayFontParam() { if (x.xlfd) { delete x.xlfd; } if (x.encoding) { delete x.encoding; } break; case displayFontT1: if (t1.fileName) { delete t1.fileName; } break; case displayFontTT: if (tt.fileName) { delete tt.fileName; } break; } } //------------------------------------------------------------------------ // 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 //------------------------------------------------------------------------ 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); } } nameToUnicode = new NameToCharCode(); cidToUnicodes = new GHash(gTrue); residentUnicodeMaps = new GHash(); unicodeMaps = new GHash(gTrue); 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()); psPaperWidth = (int)paperpswidth(paperType); psPaperHeight = (int)paperpsheight(paperType); paperdone(); #else psPaperWidth = defPaperWidth; psPaperHeight = defPaperHeight; #endif 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) textEOL = eolMac; #else textEOL = eolUnix; #endif fontDirs = new GList(); + initialZoom = new GString("1"); t1libControl = fontRastAALow; freetypeControl = fontRastAALow; urlCommand = NULL; mapNumericCharNames = gTrue; errQuiet = gFalse; cidToUnicodeCache = new CIDToUnicodeCache(); unicodeMapCache = new UnicodeMapCache(); cMapCache = new CMapCache(); // set up the initial nameToUnicode table for (i = 0; nameToUnicodeTab[i].name; ++i) { nameToUnicode->add(nameToUnicodeTab[i].name, nameToUnicodeTab[i].u); } // set up the residentUnicodeMaps table map = new UnicodeMap("Latin1", latin1UnicodeMapRanges, latin1UnicodeMapLen); residentUnicodeMaps->add(map->getEncodingName(), map); map = new UnicodeMap("ASCII7", ascii7UnicodeMapRanges, ascii7UnicodeMapLen); residentUnicodeMaps->add(map->getEncodingName(), map); map = new UnicodeMap("Symbol", symbolUnicodeMapRanges, symbolUnicodeMapLen); residentUnicodeMaps->add(map->getEncodingName(), map); map = new UnicodeMap("ZapfDingbats", zapfDingbatsUnicodeMapRanges, 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, displayFontTab[i].xlfd, displayFontTab[i].encoding); displayFonts->add(dfp->name, dfp); } // look for a user config file, then a system-wide config file f = NULL; fileName = NULL; if (cfgFileName && cfgFileName[0]) { fileName = new GString(cfgFileName); if (!(f = fopen(fileName->getCString(), "r"))) { delete fileName; } } if (!f) { fileName = appendToPath(getHomeDir(), xpdfUserConfigFile); if (!(f = fopen(fileName->getCString(), "r"))) { delete fileName; } } 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'; } fileName = grabPath(buf); appendToPath(fileName, xpdfSysConfigFile); #else fileName = new GString(xpdfSysConfigFile); #endif if (!(f = fopen(fileName->getCString(), "r"))) { 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, int line) { GString *name; char *tok1, *tok2; FILE *f; char buf[256]; int line2; Unicode u; if (tokens->getLength() != 2) { error(-1, "Bad 'nameToUnicode' config file command (%s:%d)", fileName->getCString(), line); return; } name = (GString *)tokens->get(1); if (!(f = fopen(name->getCString(), "r"))) { error(-1, "Couldn't open 'nameToUnicode' file '%s'", name->getCString()); return; } line2 = 1; @@ -405,282 +461,322 @@ void GlobalParams::parseCMapDir(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 3) { error(-1, "Bad 'cMapDir' config file command (%s:%d)", fileName->getCString(), line); return; } collection = (GString *)tokens->get(1); dir = (GString *)tokens->get(2); if (!(list = (GList *)cMapDirs->lookup(collection))) { list = new GList(); cMapDirs->add(collection->copy(), list); } list->append(dir->copy()); } void GlobalParams::parseToUnicodeDir(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { error(-1, "Bad 'toUnicodeDir' config file command (%s:%d)", fileName->getCString(), line); return; } 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; if (tokens->getLength() < 2) { goto err1; } param = new DisplayFontParam(((GString *)tokens->get(1))->copy(), kind); switch (kind) { case displayFontX: if (tokens->getLength() != 4) { goto err2; } param->x.xlfd = ((GString *)tokens->get(2))->copy(); param->x.encoding = ((GString *)tokens->get(3))->copy(); break; case displayFontT1: if (tokens->getLength() != 3) { goto err2; } param->t1.fileName = ((GString *)tokens->get(2))->copy(); break; case displayFontTT: if (tokens->getLength() != 3) { goto err2; } 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, int line) { GString *tok; if (tokens->getLength() == 2) { tok = (GString *)tokens->get(1); if (!setPSPaperSize(tok->getCString())) { error(-1, "Bad 'psPaperSize' config file command (%s:%d)", fileName->getCString(), line); } } else if (tokens->getLength() == 3) { tok = (GString *)tokens->get(1); psPaperWidth = atoi(tok->getCString()); tok = (GString *)tokens->get(2); psPaperHeight = atoi(tok->getCString()); } else { error(-1, "Bad 'psPaperSize' config file command (%s:%d)", fileName->getCString(), line); } } void GlobalParams::parsePSLevel(GList *tokens, GString *fileName, int line) { GString *tok; if (tokens->getLength() != 2) { error(-1, "Bad 'psLevel' config file command (%s:%d)", fileName->getCString(), line); return; } tok = (GString *)tokens->get(1); if (!tok->cmp("level1")) { psLevel = psLevel1; } else if (!tok->cmp("level1sep")) { psLevel = psLevel1Sep; } 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); } } void GlobalParams::parsePSFile(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { error(-1, "Bad 'psFile' config file command (%s:%d)", fileName->getCString(), line); return; } if (psFile) { delete psFile; } psFile = ((GString *)tokens->get(1))->copy(); } void GlobalParams::parsePSFont(GList *tokens, GString *fileName, int line) { PSFontParam *param; if (tokens->getLength() != 3) { 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)", fileName->getCString(), line); return; } delete textEncoding; textEncoding = ((GString *)tokens->get(1))->copy(); } void GlobalParams::parseTextEOL(GList *tokens, GString *fileName, int line) { GString *tok; if (tokens->getLength() != 2) { error(-1, "Bad 'textEOL' config file command (%s:%d)", fileName->getCString(), line); return; } tok = (GString *)tokens->get(1); if (!tok->cmp("unix")) { textEOL = eolUnix; } else if (!tok->cmp("dos")) { textEOL = eolDOS; } else if (!tok->cmp("mac")) { textEOL = eolMac; } else { error(-1, "Bad 'textEOL' config file command (%s:%d)", fileName->getCString(), line); } } void GlobalParams::parseFontDir(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { error(-1, "Bad 'fontDir' config file command (%s:%d)", fileName->getCString(), line); return; } 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, int line) { GString *tok; if (tokens->getLength() != 2) { error(-1, "Bad '%s' config file command (%s:%d)", cmdName, fileName->getCString(), line); return; } tok = (GString *)tokens->get(1); if (!setFontRastControl(val, tok->getCString())) { error(-1, "Bad '%s' config file command (%s:%d)", 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; if (tokens->getLength() != 2) { error(-1, "Bad '%s' config file command (%s:%d)", cmdName, fileName->getCString(), line); return; } tok = (GString *)tokens->get(1); if (!tok->cmp("yes")) { *flag = gTrue; } else if (!tok->cmp("no")) { *flag = gFalse; } else { error(-1, "Bad '%s' config file command (%s:%d)", cmdName, fileName->getCString(), line); } } GlobalParams::~GlobalParams() { GHashIter *iter; GString *key; GList *list; freeBuiltinFontTables(); delete macRomanReverseMap; delete nameToUnicode; deleteGHash(cidToUnicodes, GString); deleteGHash(residentUnicodeMaps, UnicodeMap); 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; } cMapDirs->startIter(&iter); while (cMapDirs->getNext(&iter, &key, (void **)&list)) { deleteGList(list, GString); } delete cMapDirs; delete cidToUnicodeCache; delete unicodeMapCache; delete cMapCache; } //------------------------------------------------------------------------ // accessors //------------------------------------------------------------------------ CharCode GlobalParams::getMacRomanCharCode(char *charName) { return macRomanReverseMap->lookup(charName); } Unicode GlobalParams::mapNameToUnicode(char *charName) { @@ -731,56 +827,92 @@ FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) { return NULL; } FILE *GlobalParams::findToUnicodeFile(GString *name) { GString *dir, *fileName; FILE *f; int i; for (i = 0; i < toUnicodeDirs->getLength(); ++i) { dir = (GString *)toUnicodeDirs->get(i); fileName = appendToPath(dir->copy(), name->getCString()); f = fopen(fileName->getCString(), "r"); delete fileName; if (f) { return f; } } return NULL; } 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; int i; for (i = 0; i < fontDirs->getLength(); ++i) { dir = (GString *)fontDirs->get(i); if (ext1) { fileName = appendToPath(dir->copy(), fontName->getCString()); fileName->append(ext1); if ((f = fopen(fileName->getCString(), "r"))) { fclose(f); return fileName; } delete fileName; } if (ext2) { fileName = appendToPath(dir->copy(), fontName->getCString()); fileName->append(ext2); if ((f = fopen(fileName->getCString(), "r"))) { fclose(f); return fileName; } @@ -845,70 +977,87 @@ GBool GlobalParams::setPSPaperSize(char *size) { void GlobalParams::setPSPaperWidth(int width) { psPaperWidth = width; } void GlobalParams::setPSPaperHeight(int height) { psPaperHeight = height; } void GlobalParams::setPSDuplex(GBool duplex) { psDuplex = duplex; } void GlobalParams::setPSLevel(PSLevel level) { psLevel = level; } void GlobalParams::setPSEmbedType1(GBool embed) { psEmbedType1 = 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); } GBool GlobalParams::setTextEOL(char *s) { if (!strcmp(s, "unix")) { textEOL = eolUnix; } else if (!strcmp(s, "dos")) { textEOL = eolDOS; } else if (!strcmp(s, "mac")) { textEOL = eolMac; } else { return gFalse; } return gTrue; } +void GlobalParams::setInitialZoom(char *s) { + delete initialZoom; + initialZoom = new GString(s); +} + GBool GlobalParams::setT1libControl(char *s) { return setFontRastControl(&t1libControl, s); } GBool GlobalParams::setFreeTypeControl(char *s) { return setFontRastControl(&freetypeControl, s); } GBool GlobalParams::setFontRastControl(FontRastControl *val, char *s) { if (!strcmp(s, "none")) { *val = fontRastNone; } else if (!strcmp(s, "plain")) { *val = fontRastPlain; } else if (!strcmp(s, "low")) { *val = fontRastAALow; } else if (!strcmp(s, "high")) { *val = fontRastAAHigh; } else { return gFalse; } return gTrue; } void GlobalParams::setErrQuiet(GBool errQuietA) { 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,242 +1,273 @@ //======================================================================== // // GlobalParams.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef GLOBALPARAMS_H #define GLOBALPARAMS_H #ifdef __GNUC__ #pragma interface #endif #include <stdio.h> #include "gtypes.h" #include "CharTypes.h" class GString; class GList; class GHash; class NameToCharCode; class CharCodeToUnicode; class CIDToUnicodeCache; class UnicodeMap; class UnicodeMapCache; class CMap; class CMapCache; class GlobalParams; //------------------------------------------------------------------------ // The global parameters object. extern GlobalParams *globalParams; //------------------------------------------------------------------------ enum DisplayFontParamKind { displayFontX, displayFontT1, displayFontTT }; 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; GString *encoding; } x; struct { GString *fileName; } t1; struct { GString *fileName; } tt; }; DisplayFontParam(GString *nameA, DisplayFontParamKind kindA); DisplayFontParam(char *nameA, char *xlfdA, char *encodingA); ~DisplayFontParam(); }; // Font rasterizer control. enum FontRastControl { fontRastNone, // don't use this rasterizer fontRastPlain, // use it, without anti-aliasing fontRastAALow, // use it, with low-level anti-aliasing fontRastAAHigh // use it, with high-level anti-aliasing }; //------------------------------------------------------------------------ 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(); }; //------------------------------------------------------------------------ enum PSLevel { psLevel1, psLevel1Sep, psLevel2, - psLevel2Sep + psLevel2Sep, + psLevel3, + psLevel3Sep }; //------------------------------------------------------------------------ enum EndOfLineKind { eolUnix, // LF eolDOS, // CR+LF eolMac // CR }; //------------------------------------------------------------------------ class GlobalParams { public: // Initialize the global parameters by attempting to read a config // file. GlobalParams(char *cfgFileName); ~GlobalParams(); //----- accessors CharCode getMacRomanCharCode(char *charName); Unicode mapNameToUnicode(char *charName); FILE *getCIDToUnicodeFile(GString *collection); UnicodeMap *getResidentUnicodeMap(GString *encodingName); 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; } GBool getErrQuiet() { return errQuiet; } CharCodeToUnicode *getCIDToUnicode(GString *collection); UnicodeMap *getUnicodeMap(GString *encodingName); CMap *getCMap(GString *collection, GString *cMapName); UnicodeMap *getTextEncoding(); //----- functions to set parameters void setPSFile(char *file); GBool setPSPaperSize(char *size); void setPSPaperWidth(int width); void setPSPaperHeight(int height); 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, GList *tokens, GString *fileName, int line); GBool setFontRastControl(FontRastControl *val, char *s); //----- static tables NameToCharCode * // mapping from char name to macRomanReverseMap; // MacRomanEncoding index //----- user-modifiable settings NameToCharCode * // mapping from char name to Unicode nameToUnicode; GHash *cidToUnicodes; // files for mappings from char collections // to Unicode, indexed by collection name // [GString] GHash *residentUnicodeMaps; // mappings from Unicode to char codes, // indexed by encoding name [UnicodeMap] GHash *unicodeMaps; // files for mappings from Unicode to char // codes, indexed by encoding name [GString] GHash *cMapDirs; // list of CMap dirs, indexed by collection // name [GList[GString]] GList *toUnicodeDirs; // list of ToUnicode CMap dirs [GString] 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 GBool mapNumericCharNames; // map numeric char names (from font subsets)? GBool errQuiet; // suppress error messages? CIDToUnicodeCache *cidToUnicodeCache; UnicodeMapCache *unicodeMapCache; CMapCache *cMapCache; }; #endif 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,29 +1,29 @@ //======================================================================== // // Lexer.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdlib.h> #include <stddef.h> #include <string.h> #include <ctype.h> #include "Lexer.h" #include "Error.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 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,74 +1,75 @@ //======================================================================== // // Lexer.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef LEXER_H #define LEXER_H #ifdef __GNUC__ #pragma interface #endif #include "Object.h" #include "Stream.h" class XRef; #define tokBufSize 128 // size of token buffer //------------------------------------------------------------------------ // Lexer //------------------------------------------------------------------------ class Lexer { public: // Construct a lexer for a single stream. Deletes the stream when // lexer is deleted. Lexer(XRef *xref, Stream *str); // Construct a lexer for a stream or array of streams (assumes obj // is either a stream or array of streams). Lexer(XRef *xref, Object *obj); // Destructor. ~Lexer(); // Get the next object from the input stream. Object *getObj(Object *obj); // Skip to the beginning of the next line in the input stream. void skipToNextLine(); // Skip over one character. void skipChar() { getChar(); } // 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(); int lookChar(); Array *streams; // array of input streams int strPtr; // index of current stream Object curStr; // current stream GBool freeArray; // should lexer free the streams array? char tokBuf[tokBufSize]; // temporary token buffer }; #endif 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,80 +1,76 @@ //======================================================================== // // Link.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stddef.h> #include <string.h> #include "gmem.h" #include "GString.h" #include "Error.h" #include "Object.h" #include "Array.h" #include "Dict.h" #include "Link.h" //------------------------------------------------------------------------ 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); // XYZ link if (obj1.isName("XYZ")) { kind = destXYZ; a->get(2, &obj2); if (obj2.isNull()) { changeLeft = gFalse; } else if (obj2.isNum()) { changeLeft = gTrue; left = obj2.getNum(); } else { error(-1, "Bad annotation destination position"); goto err1; } obj2.free(); a->get(3, &obj2); if (obj2.isNull()) { changeTop = gFalse; } else if (obj2.isNum()) { changeTop = gTrue; top = obj2.getNum(); @@ -200,87 +196,87 @@ LinkDest::LinkDest(LinkDest *dest) { top = dest->top; zoom = dest->zoom; changeLeft = dest->changeLeft; changeTop = dest->changeTop; changeZoom = dest->changeZoom; ok = gTrue; } //------------------------------------------------------------------------ // LinkGoTo //------------------------------------------------------------------------ LinkGoTo::LinkGoTo(Object *destObj) { dest = NULL; namedDest = NULL; // named destination if (destObj->isName()) { namedDest = new GString(destObj->getName()); } else if (destObj->isString()) { 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; } // error } else { error(-1, "Illegal annotation destination"); } } LinkGoTo::~LinkGoTo() { if (dest) delete dest; if (namedDest) delete namedDest; } //------------------------------------------------------------------------ // LinkGoToR //------------------------------------------------------------------------ LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) { dest = NULL; namedDest = NULL; // get file name fileName = getFileSpecName(fileSpecObj); // named destination if (destObj->isName()) { namedDest = new GString(destObj->getName()); } else if (destObj->isString()) { 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; } // error } else { error(-1, "Illegal annotation destination"); } } LinkGoToR::~LinkGoToR() { if (fileName) delete fileName; if (dest) delete dest; if (namedDest) delete namedDest; } //------------------------------------------------------------------------ // LinkLaunch //------------------------------------------------------------------------ @@ -425,49 +421,49 @@ Link::Link(Dict *dict, GString *baseURI) { error(-1, "Bad annotation rectangle"); goto err1; } x2 = obj2.getNum(); obj2.free(); if (!obj1.arrayGet(3, &obj2)->isNum()) { error(-1, "Bad annotation rectangle"); goto err1; } y2 = obj2.getNum(); obj2.free(); obj1.free(); if (x1 > x2) { t = x1; x1 = x2; x2 = t; } if (y1 > y2) { t = y1; y1 = y2; 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(); } else { error(-1, "Bad annotation border"); } obj2.free(); } } obj1.free(); // look for destination if (!dict->lookup("Dest", &obj1)->isNull()) { action = new LinkGoTo(&obj1); // look for action } else { obj1.free(); if (dict->lookup("A", &obj1)->isDict()) { obj1.dictLookup("S", &obj2); // GoTo action if (obj2.isName("GoTo")) { @@ -561,49 +557,49 @@ Links::Links(Object *annots, GString *baseURI) { } links[numLinks++] = link; } else { delete link; } } obj2.free(); } obj1.free(); } } } Links::~Links() { int i; for (i = 0; i < numLinks; ++i) delete links[i]; gfree(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(); } } return NULL; } GBool Links::onLink(fouble x, fouble y) { int i; for (i = 0; i < numLinks; ++i) { if (links[i]->inRect(x, y)) return gTrue; } return gFalse; } //------------------------------------------------------------------------ // Extract a file name from a file specification (string or dictionary). static GString *getFileSpecName(Object *fileSpecObj) { GString *name; Object obj1; 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,29 +1,29 @@ //======================================================================== // // Link.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef LINK_H #define LINK_H #ifdef __GNUC__ #pragma interface #endif #include "Object.h" class GString; class Array; class Dict; //------------------------------------------------------------------------ // LinkAction //------------------------------------------------------------------------ enum LinkActionKind { actionGoTo, // go to destination actionGoToR, // go to destination in new file actionLaunch, // launch app (or open document) @@ -42,52 +42,50 @@ public: virtual GBool isOk() = 0; // Check link action type. virtual LinkActionKind getKind() = 0; }; //------------------------------------------------------------------------ // LinkDest //------------------------------------------------------------------------ enum LinkDestKind { destXYZ, destFit, destFitH, destFitV, destFitR, destFitB, destFitBH, destFitBV }; 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); } // Was the LinkDest created successfully? GBool isOk() { return ok; } // Accessors. LinkDestKind getKind() { return kind; } GBool isPageRef() { return pageIsRef; } int getPageNum() { return pageNum; } Ref getPageRef() { return pageRef; } fouble getLeft() { return left; } fouble getBottom() { return bottom; } fouble getRight() { return right; } fouble getTop() { return top; } fouble getZoom() { return zoom; } GBool getChangeLeft() { return changeLeft; } GBool getChangeTop() { return changeTop; } GBool getChangeZoom() { return changeZoom; } private: LinkDestKind kind; // destination type 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,29 +1,29 @@ //======================================================================== // // NameToCharCode.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <string.h> #include "gmem.h" #include "NameToCharCode.h" //------------------------------------------------------------------------ struct NameToCharCodeEntry { char *name; CharCode c; }; //------------------------------------------------------------------------ NameToCharCode::NameToCharCode() { int i; 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,29 +1,29 @@ //======================================================================== // // NameToCharCode.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef NAMETOCHARCODE_H #define NAMETOCHARCODE_H #ifdef __GNUC__ #pragma interface #endif #include "CharTypes.h" struct NameToCharCodeEntry; //------------------------------------------------------------------------ class NameToCharCode { public: NameToCharCode(); ~NameToCharCode(); void add(char *name, CharCode c); CharCode lookup(char *name); 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,29 +1,29 @@ //======================================================================== // // NameToUnicodeTable.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== static struct { Unicode u; char *name; } nameToUnicodeTab[] = { {0x0041, "A"}, {0x00c6, "AE"}, {0x01fc, "AEacute"}, {0x00c6, "AEsmall"}, {0x00c1, "Aacute"}, {0x00c1, "Aacutesmall"}, {0x0102, "Abreve"}, {0x00c2, "Acircumflex"}, {0x00c2, "Acircumflexsmall"}, {0xf6c9, "Acute"}, {0xf6c9, "Acutesmall"}, {0x00c4, "Adieresis"}, {0x00c4, "Adieresissmall"}, {0x00c0, "Agrave"}, {0x00c0, "Agravesmall"}, {0x0391, "Alpha"}, {0x0386, "Alphatonos"}, 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,29 +1,29 @@ //======================================================================== // // Object.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stddef.h> #include "Object.h" #include "Array.h" #include "Dict.h" #include "Error.h" #include "Stream.h" #include "XRef.h" //------------------------------------------------------------------------ // Object //------------------------------------------------------------------------ char *objTypeNames[numObjTypes] = { "boolean", "integer", "real", 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,29 +1,29 @@ //======================================================================== // // Object.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef OBJECT_H #define OBJECT_H #ifdef __GNUC__ #pragma interface #endif #include <stdio.h> #include <string.h> #include "gtypes.h" #include "gmem.h" #include "GString.h" class XRef; class Array; class Dict; class Stream; //------------------------------------------------------------------------ // Ref //------------------------------------------------------------------------ @@ -155,50 +155,50 @@ public: // Array accessors. int arrayGetLength(); void arrayAdd(Object *elem); Object *arrayGet(int i, Object *obj); Object *arrayGetNF(int i, Object *obj); // Dict accessors. int dictGetLength(); void dictAdd(char *key, Object *val); GBool dictIs(char *dictType); Object *dictLookup(char *key, Object *obj); Object *dictLookupNF(char *key, Object *obj); char *dictGetKey(int i); Object *dictGetVal(int i, Object *obj); Object *dictGetValNF(int i, Object *obj); // Stream accessors. GBool streamIs(char *dictType); void streamReset(); 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(); void print(FILE *f = stdout); // Memory testing. static void memCheck(FILE *f); private: ObjType type; // object type fouble real; // real union { // value for each type: GBool booln; // boolean int intg; // integer GString *string; // string char *name; // name Array *array; // array Dict *dict; // dictionary Stream *stream; // stream Ref ref; // indirect reference char *cmd; // command }; @@ -266,34 +266,34 @@ inline Object *Object::dictGetValNF(int i, Object *obj) #include "Stream.h" inline GBool Object::streamIs(char *dictType) { return stream->getDict()->is(dictType); } inline GBool Object::isStream(char *dictType) { return type == objStream && streamIs(dictType); } inline void Object::streamReset() { stream->reset(); } inline void Object::streamClose() { stream->close(); } inline int Object::streamGetChar() { return stream->getChar(); } inline int Object::streamLookChar() { return stream->lookChar(); } 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(); } #endif 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,29 +1,29 @@ //======================================================================== // // OutputDev.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stddef.h> #include "Object.h" #include "Stream.h" #include "GfxState.h" #include "OutputDev.h" //------------------------------------------------------------------------ // OutputDev //------------------------------------------------------------------------ void OutputDev::setDefaultCTM(fouble *ctm) { int i; fouble det; for (i = 0; i < 6; ++i) { defCTM[i] = ctm[i]; @@ -38,48 +38,53 @@ void OutputDev::setDefaultCTM(fouble *ctm) { } void OutputDev::cvtDevToUser(int dx, int dy, fouble *ux, fouble *uy) { *ux = defICTM[0] * dx + defICTM[2] * dy + defICTM[4]; *uy = defICTM[1] * dx + defICTM[3] * dy + defICTM[5]; } void OutputDev::cvtUserToDev(fouble ux, fouble uy, int *dx, int *dy) { *dx = (int)(defCTM[0] * ux + defCTM[2] * uy + defCTM[4] + 0.5); *dy = (int)(defCTM[1] * ux + defCTM[3] * uy + defCTM[5] + 0.5); } void OutputDev::updateAll(GfxState *state) { updateLineDash(state); updateFlatness(state); updateLineJoin(state); updateLineCap(state); updateMiterLimit(state); updateLineWidth(state); updateFillColor(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; if (inlineImg) { str->reset(); j = height * ((width + 7) / 8); for (i = 0; i < j; ++i) str->getChar(); str->close(); } } void OutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg) { int i, j; if (inlineImg) { str->reset(); j = height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8); for (i = 0; i < j; ++i) 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,72 +1,76 @@ //======================================================================== // // OutputDev.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef OUTPUTDEV_H #define OUTPUTDEV_H #ifdef __GNUC__ #pragma interface #endif #include "gtypes.h" #include "CharTypes.h" class GString; class GfxState; class GfxColorSpace; class GfxImageColorMap; class Stream; class Link; class Catalog; //------------------------------------------------------------------------ // OutputDev //------------------------------------------------------------------------ class OutputDev { public: // Constructor. OutputDev() {} // Destructor. virtual ~OutputDev() {} //----- get info about output device // Does this device use upside-down coordinates? // (Upside-down means (0,0) is the top left corner of the page.) virtual GBool upsideDown() = 0; // Does this device use drawChar() or drawString()? virtual GBool useDrawChar() = 0; + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() = 0; + // Does this device need non-text content? virtual GBool needNonText() { return gTrue; } //----- initialization and control // Set default transform matrix. virtual void setDefaultCTM(fouble *ctm); // Start a page. virtual void startPage(int pageNum, GfxState *state) {} // End a page. virtual void endPage() {} // Dump page contents to display. virtual void dump() {} //----- coordinate conversion // Convert between device and user coordinates. virtual void cvtDevToUser(int dx, int dy, fouble *ux, fouble *uy); virtual void cvtUserToDev(fouble ux, fouble uy, int *dx, int *dy); //----- link borders @@ -98,46 +102,57 @@ public: virtual void updateRender(GfxState *state) {} virtual void updateRise(GfxState *state) {} virtual void updateWordSpace(GfxState *state) {} virtual void updateHorizScaling(GfxState *state) {} virtual void updateTextPos(GfxState *state) {} virtual void updateTextShift(GfxState *state, fouble shift) {} //----- path painting virtual void stroke(GfxState *state) {} virtual void fill(GfxState *state) {} virtual void eoFill(GfxState *state) {} //----- path clipping virtual void clip(GfxState *state) {} virtual void eoClip(GfxState *state) {} //----- text drawing virtual void beginString(GfxState *state, GString *s) {} virtual void endString(GfxState *state) {} virtual void drawChar(GfxState *state, fouble x, fouble y, 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, GBool inlineImg); virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); #if OPI_SUPPORT //----- OPI functions 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 }; #endif 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,136 +1,143 @@ //======================================================================== // // PDFDoc.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdio.h> #include <stdlib.h> #include <stddef.h> #include <string.h> #include "GString.h" #include "config.h" #include "Page.h" #include "Catalog.h" #include "Stream.h" #include "XRef.h" #include "Link.h" #include "OutputDev.h" #include "Error.h" +#include "ErrorCodes.h" #include "Lexer.h" #include "Parser.h" #include "PDFDoc.h" //------------------------------------------------------------------------ #define headerSearchSize 1024 // read this many bytes at beginning of // file to look for '%PDF' //------------------------------------------------------------------------ // PDFDoc //------------------------------------------------------------------------ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, GString *userPassword, GBool printCommandsA) { Object obj; GString *fileName2; ok = gFalse; + errCode = errNone; file = NULL; str = NULL; xref = NULL; catalog = NULL; links = NULL; printCommands = printCommandsA; // try to open file fileName = fileNameA; fileName2 = NULL; #ifdef VMS if (!(file = fopen(fileName->getCString(), "rb", "ctx=stm"))) { error(-1, "Couldn't open file '%s'", fileName->getCString()); + errCode = errOpenFile; return; } #else if (!(file = fopen(fileName->getCString(), "rb"))) { fileName2 = fileName->copy(); fileName2->lowerCase(); if (!(file = fopen(fileName2->getCString(), "rb"))) { fileName2->upperCase(); if (!(file = fopen(fileName2->getCString(), "rb"))) { error(-1, "Couldn't open file '%s'", fileName->getCString()); delete fileName2; + errCode = errOpenFile; return; } } delete fileName2; } #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; catalog = NULL; links = NULL; printCommands = printCommandsA; ok = setup(ownerPassword, userPassword); } GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { // check header checkHeader(); // 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 return gTrue; } PDFDoc::~PDFDoc() { if (catalog) { delete catalog; } if (xref) { delete xref; } if (str) { delete str; } if (file) { fclose(file); } if (fileName) { delete fileName; } if (links) { @@ -183,50 +190,51 @@ void PDFDoc::displayPage(OutputDev *out, int page, fouble zoom, } getLinks(p); p->display(out, zoom, rotate, links, catalog); } else { p->display(out, zoom, rotate, NULL, catalog); } } void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, int zoom, int rotate, GBool doLinks) { int page; for (page = firstPage; page <= lastPage; ++page) { displayPage(out, page, zoom, rotate, doLinks); } } GBool PDFDoc::isLinearized() { Parser *parser; Object obj1, obj2, obj3, obj4, obj5; 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); if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && obj4.isDict()) { obj4.dictLookup("Linearized", &obj5); if (obj5.isNum() && obj5.getNum() > 0) { lin = gTrue; } obj5.free(); } obj4.free(); obj3.free(); obj2.free(); obj1.free(); delete parser; return lin; } GBool PDFDoc::saveAs(GString *name) { FILE *f; int c; 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,68 +1,71 @@ //======================================================================== // // PDFDoc.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef PDFDOC_H #define PDFDOC_H #ifdef __GNUC__ #pragma interface #endif #include <stdio.h> #include "XRef.h" #include "Link.h" #include "Catalog.h" #include "Page.h" class GString; class BaseStream; class OutputDev; class Links; class LinkAction; class LinkDest; //------------------------------------------------------------------------ // PDFDoc //------------------------------------------------------------------------ class PDFDoc { public: PDFDoc(GString *fileNameA, GString *ownerPassword = NULL, GString *userPassword = NULL, GBool printCommandsA = gFalse); PDFDoc(BaseStream *strA, GString *ownerPassword = NULL, GString *userPassword = NULL, GBool printCommandsA = gFalse); ~PDFDoc(); // Was PDF document successfully opened? GBool isOk() { return ok; } + // Get the error code (if isOk() returns false). + int getErrorCode() { return errCode; } + // Get file name. GString *getFileName() { return fileName; } // Get the xref table. XRef *getXRef() { return xref; } // Get catalog. Catalog *getCatalog() { return catalog; } // Get base stream. BaseStream *getBaseStream() { return str; } // Get page parameters. fouble getPageWidth(int page) { return catalog->getPage(page)->getWidth(); } fouble getPageHeight(int page) { return catalog->getPage(page)->getHeight(); } int getPageRotate(int page) { return catalog->getPage(page)->getRotate(); } // Get number of pages. int getNumPages() { return catalog->getNumPages(); } // Return the contents of the metadata stream, or NULL if there is @@ -116,27 +119,28 @@ public: Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); } // Return the PDF version specified by the file. fouble getPDFVersion() { return pdfVersion; } // Save this file with another name. GBool saveAs(GString *name); private: GBool setup(GString *ownerPassword, GString *userPassword); void checkHeader(); void getLinks(Page *page); GString *fileName; FILE *file; BaseStream *str; fouble pdfVersion; XRef *xref; Catalog *catalog; 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,47 +1,47 @@ //======================================================================== // // Page.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stddef.h> #include "Object.h" #include "Array.h" #include "Dict.h" #include "XRef.h" #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" //------------------------------------------------------------------------ // PageAttrs //------------------------------------------------------------------------ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { Object obj1; fouble w, h; // get old/default values if (attrs) { mediaBox = attrs->mediaBox; cropBox = attrs->cropBox; haveCropBox = attrs->haveCropBox; rotate = attrs->rotate; attrs->resources.copy(&resources); } else { // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary // but some (non-compliant) PDF files don't specify a MediaBox mediaBox.x1 = 0; mediaBox.y1 = 0; @@ -72,58 +72,72 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { } } // other boxes bleedBox = cropBox; readBox(dict, "BleedBox", &bleedBox); trimBox = cropBox; readBox(dict, "TrimBox", &trimBox); artBox = cropBox; readBox(dict, "ArtBox", &artBox); // rotate dict->lookup("Rotate", &obj1); if (obj1.isInt()) { rotate = obj1.getInt(); } obj1.free(); while (rotate < 0) { rotate += 360; } while (rotate >= 360) { rotate -= 360; } + // misc attributes + dict->lookup("LastModified", &lastModified); + dict->lookup("BoxColorInfo", &boxColorInfo); + dict->lookup("Group", &group); + dict->lookup("Metadata", &metadata); + dict->lookup("PieceInfo", &pieceInfo); + dict->lookup("SeparationInfo", &separationInfo); + // resource dictionary dict->lookup("Resources", &obj1); if (obj1.isDict()) { resources.free(); obj1.copy(&resources); } 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) { PDFRectangle tmp; Object obj1, obj2; GBool ok; dict->lookup(key, &obj1); if (obj1.isArray() && obj1.arrayGetLength() == 4) { ok = gTrue; obj1.arrayGet(0, &obj2); if (obj2.isNum()) { tmp.x1 = obj2.getNum(); } else { ok = gFalse; } obj2.free(); obj1.arrayGet(1, &obj2); if (obj2.isNum()) { tmp.y1 = obj2.getNum(); } else { ok = gFalse; } @@ -188,80 +202,80 @@ Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, return; err2: annots.initNull(); err1: contents.initNull(); ok = gFalse; } Page::~Page() { delete attrs; annots.free(); contents.free(); } void Page::display(OutputDev *out, fouble dpi, int rotate, Links *links, Catalog *catalog) { #ifndef PDF_PARSER_ONLY PDFRectangle *box, *cropBox; Gfx *gfx; Object obj; Link *link; int i; - FormWidgets *formWidgets; + Annots *annotList; box = getBox(); cropBox = getCropBox(); if (printCommands) { printf("***** MediaBox = ll:%g,%g ur:%g,%g\n", box->x1, box->y1, box->x2, box->y2); if (isCropped()) { printf("***** CropBox = ll:%g,%g ur:%g,%g\n", cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); } printf("***** Rotate = %d\n", attrs->getRotate()); } rotate += getRotate(); if (rotate >= 360) { rotate -= 360; } else if (rotate < 0) { rotate += 360; } gfx = new Gfx(xref, out, num, attrs->getResourceDict(), dpi, box, isCropped(), cropBox, rotate, printCommands); contents.fetch(xref, &obj); if (!obj.isNull()) { gfx->display(&obj); } obj.free(); // draw links if (links) { for (i = 0; i < links->getNumLinks(); ++i) { link = links->getLink(i); out->drawLink(link, catalog); } 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,123 +1,149 @@ //======================================================================== // // Page.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef PAGE_H #define PAGE_H #ifdef __GNUC__ #pragma interface #endif #include "Object.h" class Dict; class XRef; class OutputDev; class Links; class Catalog; //------------------------------------------------------------------------ struct PDFRectangle { fouble x1, y1, x2, y2; }; //------------------------------------------------------------------------ // PageAttrs //------------------------------------------------------------------------ class PageAttrs { public: // Construct a new PageAttrs object by merging a dictionary // (of type Pages or Page) into another PageAttrs object. If // <attrs> is NULL, uses defaults. PageAttrs(PageAttrs *attrs, Dict *dict); // Destructor. ~PageAttrs(); // Accessors. PDFRectangle *getBox() { return limitToCropBox ? &cropBox : &mediaBox; } PDFRectangle *getMediaBox() { return &mediaBox; } PDFRectangle *getCropBox() { return &cropBox; } GBool isCropped() { return haveCropBox; } PDFRectangle *getBleedBox() { return &bleedBox; } PDFRectangle *getTrimBox() { return &trimBox; } PDFRectangle *getArtBox() { return &artBox; } int getRotate() { return rotate; } + GString *getLastModified() + { return lastModified.isString() + ? lastModified.getString() : (GString *)NULL; } + Dict *getBoxColorInfo() + { return boxColorInfo.isDict() ? boxColorInfo.getDict() : (Dict *)NULL; } + Dict *getGroup() + { return group.isDict() ? group.getDict() : (Dict *)NULL; } + Stream *getMetadata() + { return metadata.isStream() ? metadata.getStream() : (Stream *)NULL; } + Dict *getPieceInfo() + { return pieceInfo.isDict() ? pieceInfo.getDict() : (Dict *)NULL; } + Dict *getSeparationInfo() + { return separationInfo.isDict() + ? separationInfo.getDict() : (Dict *)NULL; } Dict *getResourceDict() { return resources.isDict() ? resources.getDict() : (Dict *)NULL; } private: GBool readBox(Dict *dict, char *key, PDFRectangle *box); PDFRectangle mediaBox; PDFRectangle cropBox; GBool haveCropBox; GBool limitToCropBox; PDFRectangle bleedBox; PDFRectangle trimBox; PDFRectangle artBox; int rotate; + Object lastModified; + Object boxColorInfo; + Object group; + Object metadata; + Object pieceInfo; + Object separationInfo; Object resources; }; //------------------------------------------------------------------------ // Page //------------------------------------------------------------------------ class Page { public: // Constructor. Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, GBool printCommandsA); // Destructor. ~Page(); // Is page valid? GBool isOk() { return ok; } // Get page parameters. PDFRectangle *getBox() { return attrs->getBox(); } PDFRectangle *getMediaBox() { return attrs->getMediaBox(); } PDFRectangle *getCropBox() { return attrs->getCropBox(); } GBool isCropped() { return attrs->isCropped(); } fouble getWidth() { return attrs->getBox()->x2 - attrs->getBox()->x1; } fouble getHeight() { return attrs->getBox()->y2 - attrs->getBox()->y1; } PDFRectangle *getBleedBox() { return attrs->getBleedBox(); } PDFRectangle *getTrimBox() { return attrs->getTrimBox(); } PDFRectangle *getArtBox() { return attrs->getArtBox(); } int getRotate() { return attrs->getRotate(); } + GString *getLastModified() { return attrs->getLastModified(); } + Dict *getBoxColorInfo() { return attrs->getBoxColorInfo(); } + Dict *getGroup() { return attrs->getGroup(); } + Stream *getMetadata() { return attrs->getMetadata(); } + Dict *getPieceInfo() { return attrs->getPieceInfo(); } + Dict *getSeparationInfo() { return attrs->getSeparationInfo(); } // Get resource dictionary. Dict *getResourceDict() { return attrs->getResourceDict(); } // Get annotations array. Object *getAnnots(Object *obj) { return annots.fetch(xref, obj); } // Get contents. Object *getContents(Object *obj) { return contents.fetch(xref, obj); } // Display a page. void display(OutputDev *out, fouble dpi, int rotate, Links *links, Catalog *catalog); private: XRef *xref; // the xref table for this PDF file int num; // page number PageAttrs *attrs; // page attributes Object annots; // annotations array Object contents; // page contents GBool printCommands; // print the drawing commands (for debugging) GBool ok; // true if page is valid }; diff --git a/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,29 +1,29 @@ //======================================================================== // // Parser.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stddef.h> #include "Object.h" #include "Array.h" #include "Dict.h" #include "Parser.h" #include "XRef.h" #include "Error.h" #ifndef NO_DECRYPTION #include "Decrypt.h" #endif Parser::Parser(XRef *xrefA, Lexer *lexerA) { xref = xrefA; lexer = lexerA; inlineImg = 0; lexer->getObj(&buf1); @@ -134,72 +134,73 @@ Object *Parser::getObj(Object *obj) { buf1.copy(obj); s = obj->getString(); decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); for (i = 0, p = obj->getString()->getCString(); i < s->getLength(); ++i, ++p) { *p = decrypt->decryptByte(*p); } delete decrypt; shift(); #endif // simple object } else { buf1.copy(obj); shift(); } return 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); // skip over stream data lexer->setPos(pos + length); // refill token buffers and check for 'endstream' shift(); // kill '>>' shift(); // kill 'stream' if (buf1.isCmd("endstream")) shift(); else error(getPos(), "Missing 'endstream'"); return str; } void Parser::shift() { if (inlineImg > 0) { ++inlineImg; } else if (buf2.isCmd("ID")) { lexer->skipChar(); // skip char after 'ID' command inlineImg = 1; 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,29 +1,29 @@ //======================================================================== // // Parser.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef PARSER_H #define PARSER_H #ifdef __GNUC__ #pragma interface #endif #include "Lexer.h" //------------------------------------------------------------------------ // Parser //------------------------------------------------------------------------ class Parser { public: // Constructor. Parser(XRef *xrefA, Lexer *lexerA); // Destructor. ~Parser(); 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 @@ -1,31 +1,31 @@ //======================================================================== // // Stream-CCITT.h // // Tables for CCITT Fax decoding. // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== struct CCITTCode { short bits; short n; }; #define ccittEOL -2 //------------------------------------------------------------------------ // 2D codes //------------------------------------------------------------------------ #define twoDimPass 0 #define twoDimHoriz 1 #define twoDimVert0 2 #define twoDimVertR1 3 #define twoDimVertL1 4 #define twoDimVertR2 5 #define twoDimVertL2 6 #define twoDimVertR3 7 #define twoDimVertL3 8 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,29 +1,29 @@ //======================================================================== // // Stream.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdio.h> #include <stdlib.h> #include <stddef.h> #ifndef WIN32 #include <unistd.h> #endif #include <string.h> #include <ctype.h> #include "gmem.h" #include "gfile.h" #include "config.h" #include "Error.h" #include "Object.h" #ifndef NO_DECRYPTION #include "Decrypt.h" #endif @@ -282,49 +282,49 @@ BaseStream::~BaseStream() { } #ifndef NO_DECRYPTION void BaseStream::doDecryption(Guchar *fileKey, int keyLength, int objNum, int objGen) { decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); } #endif //------------------------------------------------------------------------ // FilterStream //------------------------------------------------------------------------ FilterStream::FilterStream(Stream *strA) { str = strA; } 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"); } //------------------------------------------------------------------------ // ImageStream //------------------------------------------------------------------------ ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) { int imgLineSize; str = strA; width = widthA; nComps = nCompsA; nBits = nBitsA; nVals = width * nComps; if (nBits == 1) { imgLineSize = (nVals + 7) & ~7; } else { imgLineSize = nVals; } imgLine = (Guchar *)gmalloc(imgLineSize * sizeof(Guchar)); imgIdx = nVals; } @@ -533,169 +533,282 @@ GBool StreamPredictor::getNextLine() { (inBuf >> (inBits - nBits))) & bitMask; outBuf = (outBuf << nBits) | upLeftBuf[0]; inBits -= nBits; outBits += nBits; if (outBits > 8) { predLine[k++] = (Guchar)(outBuf >> (outBits - 8)); } } if (outBits > 0) { predLine[k++] = (Guchar)(outBuf << (8 - outBits)); } } } // reset to start of line predIdx = pixBytes; return gTrue; } //------------------------------------------------------------------------ // 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) decrypt->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() { int n; #ifndef NO_DECRYPTION char *p; #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; } n = fread(buf, 1, n, f); bufEnd = buf + n; if (bufPtr >= bufEnd) { return gFalse; } #ifndef NO_DECRYPTION if (decrypt) { for (p = buf; p < bufEnd; ++p) { *p = (char)decrypt->decryptByte((Guchar)*p); } } #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; } void FileStream::moveStart(int delta) { start += delta; bufPtr = bufEnd = buf; bufPos = start; } //------------------------------------------------------------------------ +// MemStream +//------------------------------------------------------------------------ + +MemStream::MemStream(char *bufA, Guint lengthA, Object *dictA): + BaseStream(dictA) { + buf = bufA; + needFree = gFalse; + length = lengthA; + bufEnd = buf + length; + bufPtr = buf; +} + +MemStream::~MemStream() { + if (needFree) { + gfree(buf); + } +} + +Stream *MemStream::makeSubStream(Guint start, GBool limited, + Guint lengthA, Object *dictA) { + Guint newLength; + + if (!limited || start + lengthA > length) { + newLength = length - start; + } else { + newLength = lengthA; + } + return new MemStream(buf + start, newLength, dictA); +} + +void MemStream::reset() { + bufPtr = buf; +#ifndef NO_DECRYPTION + if (decrypt) { + decrypt->reset(); + } +#endif +} + +void MemStream::close() { +} + +void MemStream::setPos(Guint pos, int dir) { + if (dir >= 0) { + if (pos > length) { + bufPtr = bufEnd; + } else { + bufPtr = buf + pos; + } + } else { + if (pos > length) { + bufPtr = buf; + } else { + bufPtr = bufEnd - pos; + } + } +} + +void MemStream::moveStart(int delta) { + buf += delta; + bufPtr = buf; +} + +#ifndef NO_DECRYPTION +void MemStream::doDecryption(Guchar *fileKey, int keyLength, + int objNum, int objGen) { + char *newBuf; + char *p, *q; + + this->BaseStream::doDecryption(fileKey, keyLength, objNum, objGen); + if (decrypt) { + newBuf = (char *)gmalloc(bufEnd - buf); + for (p = buf, q = newBuf; p < bufEnd; ++p, ++q) { + *q = (char)decrypt->decryptByte((Guchar)*p); + } + bufEnd = newBuf + (bufEnd - buf); + bufPtr = newBuf + (bufPtr - buf); + buf = newBuf; + needFree = gTrue; + } +} +#endif + +//------------------------------------------------------------------------ // EmbedStream //------------------------------------------------------------------------ EmbedStream::EmbedStream(Stream *strA, Object *dictA): BaseStream(dictA) { str = strA; } 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"); } //------------------------------------------------------------------------ // ASCIIHexStream //------------------------------------------------------------------------ ASCIIHexStream::ASCIIHexStream(Stream *strA): FilterStream(strA) { buf = EOF; eof = gFalse; } ASCIIHexStream::~ASCIIHexStream() { delete str; } void ASCIIHexStream::reset() { str->reset(); buf = EOF; eof = gFalse; } int ASCIIHexStream::lookChar() { @@ -938,53 +1051,49 @@ void LZWStream::reset() { OSErr err = OpenSITEngine(kUseExternalEngine, &magicCookie); // if we found it - let's use it! if (!err && magicCookie) { // make sure we have the correct version of the Engine if (GetSITEngineVersion(magicCookie) >= kFirstSupportedEngine) { FSSpec myFSS; Str255 pName; strcpy((char *)pName, zName->getCString()); c2pstr((char *)pName); FSMakeFSSpec(0, 0, pName, &myFSS); short ftype = DetermineFileType(magicCookie, &myFSS); OSErr expandErr = ExpandFSSpec(magicCookie, ftype, &myFSS, NULL, NULL, kCreateFolderNever, kDeleteOriginal, kTextConvertSmart); } } #elif defined(HAVE_POPEN) if (!(zPipe = popen(zCmd->getCString(), POPEN_READ_MODE))) { error(getPos(), "Couldn't popen '%s'", zCmd->getCString()); unlink(zName->getCString()); 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; } zName->del(zName->getLength() - 2, 2); if (!(zPipe = fopen(zName->getCString(), "rb"))) { error(getPos(), "Couldn't open uncompress file '%s'", zName->getCString()); unlink(zName->getCString()); delete zName; return; } #endif // HAVE_POPEN //----- clean up delete zCmd; //----- initialize buffer bufPtr = bufEnd = buf; } void LZWStream::dumpFile(FILE *f) { int outCodeBits; // size of output code int outBits; // max output code @@ -3266,48 +3375,98 @@ FixedLengthEncoder::~FixedLengthEncoder() { } void FixedLengthEncoder::reset() { str->reset(); count = 0; } void FixedLengthEncoder::close() { } int FixedLengthEncoder::getChar() { if (length >= 0 && count >= length) return EOF; ++count; return str->getChar(); } int FixedLengthEncoder::lookChar() { if (length >= 0 && count >= length) return EOF; 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): FilterStream(strA) { bufPtr = bufEnd = buf; lineLen = 0; eof = gFalse; } ASCII85Encoder::~ASCII85Encoder() { if (str->isEncoder()) delete str; } void ASCII85Encoder::reset() { str->reset(); bufPtr = bufEnd = buf; lineLen = 0; eof = gFalse; } void ASCII85Encoder::close() { } 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,29 +1,29 @@ //======================================================================== // // Stream.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef STREAM_H #define STREAM_H #ifdef __GNUC__ #pragma interface #endif #include <stdio.h> #include "gtypes.h" #include "Object.h" #ifndef NO_DECRYPTION class Decrypt; #endif class BaseStream; //------------------------------------------------------------------------ enum StreamKind { strFile, strASCIIHex, @@ -57,127 +57,131 @@ public: virtual StreamKind getKind() = 0; // Reset stream to beginning. virtual void reset() = 0; // Close down the stream. virtual void close(); // Get next char from stream. virtual int getChar() = 0; // Peek at next char in stream. virtual int lookChar() = 0; // Get next char from stream without using the predictor. // This is only used by StreamPredictor. virtual int getRawChar(); // Get next line from stream. virtual char *getLine(char *buf, int size); // 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); // Does this stream type potentially contain non-printable chars? virtual GBool isBinary(GBool last = gTrue) = 0; // Get the BaseStream or EmbedStream of this stream. virtual BaseStream *getBaseStream() = 0; // Get the dictionary associated with this stream. virtual Dict *getDict() = 0; // Is this an encoding filter? virtual GBool isEncoder() { return gFalse; } // Add filters to this stream according to the parameters in <dict>. // Returns the new stream. Stream *addFilters(Object *dict); private: Stream *makeFilter(char *name, Stream *str, Object *params); int ref; // reference count }; //------------------------------------------------------------------------ // BaseStream // // This is the base class for all streams that read directly from a file. //------------------------------------------------------------------------ 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: Decrypt *decrypt; #endif private: Object dict; }; //------------------------------------------------------------------------ // FilterStream // // This is the base class for all streams that filter another stream. //------------------------------------------------------------------------ class FilterStream: public Stream { 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: Stream *str; }; //------------------------------------------------------------------------ // ImageStream //------------------------------------------------------------------------ class ImageStream { public: // Create an image stream object for an image with the specified // parameters. Note that these are the actual image parameters, // which may be different from the predictor parameters. ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA); ~ImageStream(); // Reset the stream. void reset(); @@ -221,102 +225,144 @@ private: GBool getNextLine(); Stream *str; // base stream int predictor; // predictor int width; // pixels per line int nComps; // components per pixel int nBits; // bits per component int nVals; // components per line int pixBytes; // bytes per pixel int rowBytes; // bytes per line Guchar *predLine; // line buffer int predIdx; // current index in predLine }; //------------------------------------------------------------------------ // FileStream //------------------------------------------------------------------------ #define fileStreamBufSize 256 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 // // This is a special stream type used for embedded streams (inline // images). It reads directly from the base stream -- after the // EmbedStream is deleted, reads from the base stream will proceed where // the BaseStream left off. Note that this is very different behavior // that creating a new FileStream (using makeSubStream). //------------------------------------------------------------------------ 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: Stream *str; }; //------------------------------------------------------------------------ // ASCIIHexStream //------------------------------------------------------------------------ class ASCIIHexStream: public FilterStream { public: ASCIIHexStream(Stream *strA); virtual ~ASCIIHexStream(); virtual StreamKind getKind() { return strASCIIHex; } virtual void reset(); virtual int getChar() { int c = lookChar(); buf = EOF; return c; } virtual int lookChar(); virtual GString *getPSFilter(char *indent); virtual GBool isBinary(GBool last = gTrue); @@ -638,48 +684,79 @@ public: // FixedLengthEncoder //------------------------------------------------------------------------ class FixedLengthEncoder: public FilterStream { public: FixedLengthEncoder(Stream *strA, int lengthA); ~FixedLengthEncoder(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); virtual void close(); virtual int getChar(); virtual int lookChar(); virtual GString *getPSFilter(char *indent) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gFalse; } virtual GBool isEncoder() { return gTrue; } private: int length; 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 { public: ASCII85Encoder(Stream *strA); virtual ~ASCII85Encoder(); 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[8]; char *bufPtr; char *bufEnd; 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,74 +1,80 @@ //======================================================================== // // TextOutputDev.cc // -// Copyright 1997 Derek B. Noonburg +// Copyright 1997-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdio.h> #include <stdlib.h> #include <stddef.h> #include <math.h> #include <ctype.h> #include "GString.h" #include "gmem.h" #include "config.h" #include "Error.h" #include "GlobalParams.h" #include "UnicodeMap.h" #include "GfxState.h" #include "TextOutputDev.h" #ifdef MACOS // needed for setting type/creator of MacOS files #include "ICSupport.h" #endif //------------------------------------------------------------------------ // TextString //------------------------------------------------------------------------ TextString::TextString(GfxState *state, fouble fontSize) { GfxFont *font; fouble x, y; state->transform(state->getCurX(), state->getCurY(), &x, &y); if ((font = state->getFont())) { yMin = y - font->getAscent() * fontSize; yMax = y - font->getDescent() * fontSize; } else { // this means that the PDF file draws text without a current font, // 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; yxNext = NULL; xyNext = NULL; } TextString::~TextString() { gfree(text); gfree(xRight); } void TextString::addChar(GfxState *state, fouble x, fouble y, fouble dx, fouble dy, Unicode u) { if (len == size) { size += 16; text = (Unicode *)grealloc(text, size * sizeof(Unicode)); xRight = (fouble *)grealloc(xRight, size * sizeof(fouble)); } text[len] = u; if (len == 0) { xMin = x; } @@ -78,105 +84,111 @@ void TextString::addChar(GfxState *state, fouble x, fouble y, //------------------------------------------------------------------------ // TextPage //------------------------------------------------------------------------ TextPage::TextPage(GBool rawOrderA) { rawOrder = rawOrderA; curStr = NULL; fontSize = 0; yxStrings = NULL; xyStrings = NULL; yxCur1 = yxCur2 = NULL; nest = 0; } TextPage::~TextPage() { clear(); } 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) { // This is a hack which makes it possible to deal with some Type 3 // fonts. The problem is that it's impossible to know what the // base coordinate system used in the font is without actually // rendering the font. This code tries to guess by looking at the // width of the character 'm' (which breaks if the font is a // subset that doesn't contain 'm'). for (code = 0; code < 256; ++code) { if ((name = ((Gfx8BitFont *)font)->getCharName(code)) && name[0] == 'm' && name[1] == '\0') { 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]); } } } void TextPage::beginString(GfxState *state) { // This check is needed because Type 3 characters can contain // text-drawing operations. if (curStr) { ++nest; return; } curStr = new TextString(state, fontSize); } void TextPage::addChar(GfxState *state, fouble x, fouble y, fouble dx, fouble dy, Unicode *u, int uLen) { fouble x1, y1, w1, h1, dx2, dy2; int n, i; state->transform(x, y, &x1, &y1); n = curStr->len; if (n > 0 && x1 - curStr->xRight[n-1] > 0.1 * (curStr->yMax - curStr->yMin)) { endString(); beginString(state); } state->textTransformDelta(state->getCharSpace() * state->getHorizScaling(), 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]); } } void TextPage::endString() { TextString *p1, *p2; fouble h, y1, y2; // This check is needed because Type 3 characters can contain // text-drawing operations. if (nest > 0) { --nest; return; } // throw away zero-length strings -- they don't have valid xMin/xMax // values, and they're useless anyway if (curStr->len == 0) { delete curStr; curStr = NULL; return; } @@ -408,49 +420,49 @@ GString *TextPage::getText(fouble xMin, fouble yMin, if (x0 < xPrev || str1->yMin > yPrev) { s->append(eol, eolLen); multiLine = gTrue; } else { for (i = 0; i < 4; ++i) { s->append(space, spaceLen); } } } for (i = i1; i <= i2; ++i) { n = uMap->mapUnicode(str1->text[i], buf, sizeof(buf)); s->append(buf, n); } xPrev = x2; yPrev = str1->yMax; } } if (multiLine) { s->append(eol, eolLen); } 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; fouble yMin, yMax; int col1, col2, d, i; // get the output encoding if (!(uMap = globalParams->getTextEncoding())) { return; } spaceLen = uMap->mapUnicode(0x20, space, sizeof(space)); eolLen = 0; // make gcc happy switch (globalParams->getTextEOL()) { case eolUnix: eolLen = uMap->mapUnicode(0x0a, eol, sizeof(eol)); break; case eolDOS: eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); eolLen += uMap->mapUnicode(0x0a, eol + eolLen, sizeof(eol) - eolLen); break; case eolMac: eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); break; @@ -477,206 +489,221 @@ void TextPage::dump(FILE *f) { } // do column assignment for (str1 = xyStrings; str1; str1 = str1->xyNext) { col1 = 0; for (str2 = xyStrings; str2 != str1; str2 = str2->xyNext) { if (str1->xMin >= str2->xMax) { col2 = str2->col + str2->len + 4; if (col2 > col1) { col1 = col2; } } else if (str1->xMin > str2->xMin) { col2 = str2->col + (int)(((str1->xMin - str2->xMin) / (str2->xMax - str2->xMin)) * str2->len); if (col2 > col1) { col1 = col2; } } } 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; yMax = yxStrings ? yxStrings->yMax : fouble(0); for (str1 = yxStrings; str1; str1 = str1->yxNext) { // line this string up with the correct column 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 col1 += str1->len; // update yMax for this line if (str1->yMax > yMax) { yMax = str1->yMax; } // if we've hit the end of the line... if (!(str1->yxNext && !(rawOrder && str1->yxNext->yMax < str1->yMin) && 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) { // find yMin for next line yMin = str1->yxNext->yMin; for (str2 = str1->yxNext; str2; str2 = str2->yxNext) { if (str2->yMin < yMin) { yMin = str2->yMin; } if (!(str2->yxNext && str2->yxNext->yMin < str2->yMax && str2->yxNext->xMin >= str2->xMax)) break; } // print the space d = (int)((yMin - yMax) / (str1->yMax - str1->yMin) + 0.5); // various things (weird font matrices) can result in bogus // values here, so do a sanity check if (rawOrder && d > 2) { d = 2; } 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 col1 = 0; yMax = str1->yxNext ? str1->yxNext->yMax : fouble(0); } } // 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(); } void TextPage::clear() { TextString *p1, *p2; if (curStr) { delete curStr; curStr = NULL; } for (p1 = yxStrings; p1; p1 = p2) { p2 = p1->yxNext; delete p1; } yxStrings = NULL; xyStrings = NULL; yxCur1 = yxCur2 = NULL; } //------------------------------------------------------------------------ // 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; // 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; } } void TextOutputDev::startPage(int pageNum, GfxState *state) { text->clear(); } void TextOutputDev::endPage() { text->coalesce(); - if (f) { - text->dump(f); + if (outputStream) { + text->dump(outputStream, outputFunc); } } void TextOutputDev::updateFont(GfxState *state) { text->updateFont(state); } void TextOutputDev::beginString(GfxState *state, GString *s) { text->beginString(state); } void TextOutputDev::endString(GfxState *state) { text->endString(); } void TextOutputDev::drawChar(GfxState *state, fouble x, fouble y, fouble dx, fouble dy, fouble originX, fouble originY, CharCode c, Unicode *u, int uLen) { text->addChar(state, x, y, dx, dy, u, uLen); } GBool TextOutputDev::findText(Unicode *s, int len, GBool top, GBool bottom, 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,48 +1,52 @@ //======================================================================== // // TextOutputDev.h // -// Copyright 1997 Derek B. Noonburg +// Copyright 1997-2002 Glyph & Cog, LLC // //======================================================================== #ifndef TEXTOUTPUTDEV_H #define TEXTOUTPUTDEV_H #ifdef __GNUC__ #pragma interface #endif #include <stdio.h> #include "gtypes.h" #include "GfxFont.h" #include "OutputDev.h" class GfxState; class GString; //------------------------------------------------------------------------ + +typedef void (*TextOutputFunc)(void *stream, char *text, int len); + +//------------------------------------------------------------------------ // TextString //------------------------------------------------------------------------ class TextString { public: // Constructor. TextString(GfxState *state, fouble fontSize); // Destructor. ~TextString(); // Add a character to the string. void addChar(GfxState *state, fouble x, fouble y, fouble dx, fouble dy, Unicode u); private: fouble xMin, xMax; // bounding box x coordinates fouble yMin, yMax; // bounding box y coordinates int col; // starting column Unicode *text; // the text fouble *xRight; // right-hand x coord of each char int len; // length of text and xRight @@ -76,114 +80,124 @@ public: void addChar(GfxState *state, fouble x, fouble y, fouble dx, fouble dy, Unicode *u, int uLen); // End the current string, sorting it into the list of strings. void endString(); // Coalesce strings that look like parts of the same line. void coalesce(); // Find a string. If <top> is true, starts looking at top of page; // otherwise starts looking at <xMin>,<yMin>. If <bottom> is true, // stops looking at bottom of page; otherwise stops looking at // <xMax>,<yMax>. If found, sets the text bounding rectange and // returns true; otherwise returns false. GBool findText(Unicode *s, int len, GBool top, GBool bottom, fouble *xMin, fouble *yMin, fouble *xMax, fouble *yMax); // Get the text which is inside the specified rectangle. 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(); private: GBool rawOrder; // keep strings in content stream order TextString *curStr; // currently active string fouble fontSize; // current font size TextString *yxStrings; // strings in y-major order TextString *xyStrings; // strings in x-major order TextString *yxCur1, *yxCur2; // cursors for yxStrings list int nest; // current nesting level (for Type 3 fonts) }; //------------------------------------------------------------------------ // TextOutputDev //------------------------------------------------------------------------ class TextOutputDev: public OutputDev { public: // Open a text output file. If <fileName> is NULL, no file is // 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. virtual GBool isOk() { return ok; } //---- get info about output device // Does this device use upside-down coordinates? // (Upside-down means (0,0) is the top left corner of the page.) virtual GBool upsideDown() { return gTrue; } // 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); // End a page. virtual void endPage(); //----- update text state virtual void updateFont(GfxState *state); //----- text drawing virtual void beginString(GfxState *state, GString *s); virtual void endString(GfxState *state); virtual void drawChar(GfxState *state, fouble x, fouble y, fouble dx, fouble dy, fouble originX, fouble originY, CharCode c, Unicode *u, int uLen); //----- special access // Find a string. If <top> is true, starts looking at top of page; // otherwise starts looking at <xMin>,<yMin>. If <bottom> is true, // stops looking at bottom of page; otherwise stops looking at // <xMax>,<yMax>. If found, sets the text bounding rectange and // returns true; otherwise returns false. GBool findText(Unicode *s, int len, GBool top, GBool bottom, fouble *xMin, fouble *yMin, 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? }; #endif 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,29 +1,29 @@ //======================================================================== // // UnicodeMap.cc // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdio.h> #include <string.h> #include "gmem.h" #include "gfile.h" #include "GString.h" #include "GList.h" #include "Error.h" #include "GlobalParams.h" #include "UnicodeMap.h" //------------------------------------------------------------------------ #define maxExtCode 16 struct UnicodeMapExt { Unicode u; // Unicode char 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 @@ -1,31 +1,31 @@ //======================================================================== // // UnicodeMap.h // // Mapping from Unicode to an encoding. // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== #ifndef UNICODEMAP_H #define UNICODEMAP_H #ifdef __GNUC__ #pragma interface #endif #include "gtypes.h" #include "CharTypes.h" class GString; //------------------------------------------------------------------------ enum UnicodeMapKind { unicodeMapUser, // read from a file unicodeMapResident, // static list of ranges unicodeMapFunc // function pointer }; typedef int (*UnicodeMapFunc)(Unicode u, char *buf, int bufSize); 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,67 +1,86 @@ //======================================================================== // // UnicodeMapTables.h // -// Copyright 2001 Derek B. Noonburg +// Copyright 2001-2002 Glyph & Cog, LLC // //======================================================================== static UnicodeMapRange latin1UnicodeMapRanges[] = { { 0x000a, 0x000a, 0x0a, 1 }, { 0x000c, 0x000d, 0x0c, 1 }, { 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 }, { 0x0153, 0x0153, 0x6f65, 2 }, { 0x0160, 0x0160, 0x53, 1 }, { 0x0161, 0x0161, 0x73, 1 }, { 0x0178, 0x0178, 0x59, 1 }, { 0x017d, 0x017d, 0x5a, 1 }, { 0x017e, 0x017e, 0x7a, 1 }, { 0x02c6, 0x02c6, 0x5e, 1 }, { 0x02da, 0x02da, 0xb0, 1 }, { 0x02dc, 0x02dc, 0x7e, 1 }, { 0x2013, 0x2013, 0xad, 1 }, { 0x2014, 0x2014, 0x2d2d, 2 }, { 0x2018, 0x2018, 0x60, 1 }, { 0x2019, 0x2019, 0x27, 1 }, { 0x201a, 0x201a, 0x2c, 1 }, { 0x201c, 0x201c, 0x22, 1 }, { 0x201d, 0x201d, 0x22, 1 }, { 0x201e, 0x201e, 0x2c2c, 2 }, { 0x2022, 0x2022, 0xb7, 1 }, { 0x2026, 0x2026, 0x2e2e2e, 3 }, { 0x2039, 0x2039, 0x3c, 1 }, { 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 }, { 0xfb04, 0xfb04, 0x66666c, 3 } }; #define latin1UnicodeMapLen (sizeof(latin1UnicodeMapRanges) / sizeof(UnicodeMapRange)) static UnicodeMapRange ascii7UnicodeMapRanges[] = { { 0x000a, 0x000a, 0x0a, 1 }, { 0x000c, 0x000d, 0x0c, 1 }, { 0x0020, 0x005f, 0x20, 1 }, { 0x0061, 0x007e, 0x61, 1 }, { 0x00a6, 0x00a6, 0x7c, 1 }, { 0x00a9, 0x00a9, 0x286329, 3 }, { 0x00ae, 0x00ae, 0x285229, 3 }, { 0x00b7, 0x00b7, 0x2a, 1 }, { 0x00bc, 0x00bc, 0x312f34, 3 }, { 0x00bd, 0x00bd, 0x312f32, 3 }, { 0x00be, 0x00be, 0x332f34, 3 }, { 0x00c0, 0x00c0, 0x41, 1 }, { 0x00c1, 0x00c1, 0x41, 1 }, { 0x00c2, 0x00c2, 0x41, 1 }, { 0x00c3, 0x00c3, 0x41, 1 }, @@ -114,48 +133,87 @@ static UnicodeMapRange ascii7UnicodeMapRanges[] = { { 0x00f8, 0x00f8, 0x6f, 1 }, { 0x00f9, 0x00f9, 0x75, 1 }, { 0x00fa, 0x00fa, 0x75, 1 }, { 0x00fb, 0x00fb, 0x75, 1 }, { 0x00fc, 0x00fc, 0x75, 1 }, { 0x00fd, 0x00fd, 0x79, 1 }, { 0x00ff, 0x00ff, 0x79, 1 }, { 0x0131, 0x0131, 0x69, 1 }, { 0x0141, 0x0141, 0x4c, 1 }, { 0x0152, 0x0152, 0x4f45, 2 }, { 0x0153, 0x0153, 0x6f65, 2 }, { 0x0160, 0x0160, 0x53, 1 }, { 0x0178, 0x0178, 0x59, 1 }, { 0x017d, 0x017d, 0x5a, 1 }, { 0x2013, 0x2013, 0x2d, 1 }, { 0x2014, 0x2014, 0x2d2d, 2 }, { 0x2018, 0x2018, 0x60, 1 }, { 0x2019, 0x2019, 0x27, 1 }, { 0x201c, 0x201c, 0x22, 1 }, { 0x201d, 0x201d, 0x22, 1 }, { 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 }, { 0xfb04, 0xfb04, 0x66666c, 3 } }; #define ascii7UnicodeMapLen (sizeof(ascii7UnicodeMapRanges) / sizeof(UnicodeMapRange)) static UnicodeMapRange symbolUnicodeMapRanges[] = { { 0x0020, 0x0021, 0x20, 1 }, { 0x0023, 0x0023, 0x23, 1 }, { 0x0025, 0x0026, 0x25, 1 }, { 0x0028, 0x0029, 0x28, 1 }, { 0x002b, 0x002c, 0x2b, 1 }, { 0x002e, 0x003f, 0x2e, 1 }, { 0x005b, 0x005b, 0x5b, 1 }, { 0x005d, 0x005d, 0x5d, 1 }, { 0x005f, 0x005f, 0x5f, 1 }, { 0x007b, 0x007d, 0x7b, 1 }, { 0x00ac, 0x00ac, 0xd8, 1 }, { 0x00b0, 0x00b1, 0xb0, 1 }, { 0x00b5, 0x00b5, 0x6d, 1 }, { 0x00d7, 0x00d7, 0xb4, 1 }, { 0x00f7, 0x00f7, 0xb8, 1 }, 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,231 +1,238 @@ //======================================================================== // // XRef.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdlib.h> #include <stddef.h> #include <string.h> #include <ctype.h> #include "gmem.h" #include "Object.h" #include "Stream.h" #include "Lexer.h" #include "Parser.h" #include "Dict.h" #ifndef NO_DECRYPTION #include "Decrypt.h" #endif #include "Error.h" +#include "ErrorCodes.h" #include "XRef.h" //------------------------------------------------------------------------ #define xrefSearchSize 1024 // read this many bytes at end of file // to look for 'startxref' #ifndef NO_DECRYPTION //------------------------------------------------------------------------ // Permission bits //------------------------------------------------------------------------ #define permPrint (1<<2) #define permChange (1<<3) #define permCopy (1<<4) #define permNotes (1<<5) #define defPermFlags 0xfffc #endif //------------------------------------------------------------------------ // 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; // read the trailer str = strA; start = str->getStart(); pos = readTrailer(); // 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)) ; // if there was a problem with the xref table, // try to reconstruct it if (!ok) { gfree(entries); size = 0; entries = NULL; if (!(ok = constructXRef())) { + errCode = errDamaged; return; } } } // now set the trailer dictionary's xref pointer so we can fetch // indirect objects from it trailerDict.getDict()->setXRef(this); // check for encryption #ifndef NO_DECRYPTION encrypted = gFalse; #endif if (checkEncrypted(ownerPassword, userPassword)) { ok = gFalse; + errCode = errEncrypted; return; } } XRef::~XRef() { gfree(entries); trailerDict.free(); if (streamEnds) { gfree(streamEnds); } } // 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; } buf[n] = '\0'; // find startxref for (i = n - 9; i >= 0; --i) { if (!strncmp(&buf[i], "startxref", 9)) break; } if (i < 0) return 0; for (p = &buf[i+9]; isspace(*p); ++p) ; - pos = lastXRefPos = atoi(p); + pos = lastXRefPos = strToUnsigned(p); // find trailer dict by looking after first xref table // (NB: we can't just use the trailer dict at the end of the file -- // this won't work for linearized files.) str->setPos(start + pos); for (i = 0; i < 4; ++i) buf[i] = str->getChar(); if (strncmp(buf, "xref", 4)) return 0; pos1 = pos + 4; while (1) { str->setPos(start + pos1); for (i = 0; i < 35; ++i) { if ((c = str->getChar()) == EOF) return 0; buf[i] = c; } if (!strncmp(buf, "trailer", 7)) break; p = buf; while (isspace(*p)) ++p; while ('0' <= *p && *p <= '9') ++p; while (isspace(*p)) ++p; n = atoi(p); while ('0' <= *p && *p <= '9') ++p; while (isspace(*p)) ++p; if (p == buf) return 0; pos1 += (p - buf) + n * 20; } 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()) size = obj.getInt(); else pos = 0; obj.free(); trailerDict.dictLookupNF("Root", &obj); if (obj.isRef()) { rootNum = obj.getRefNum(); rootGen = obj.getRefGen(); } else { pos = 0; } obj.free(); } else { pos = 0; } delete parser; // return first xref position 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; int first, newSize, n, i, j; int c; // seek to xref in stream str->setPos(start + *pos); // make sure it's an xref table while ((c = str->getChar()) != EOF && isspace(c)) ; s[0] = (char)c; s[1] = (char)str->getChar(); s[2] = (char)str->getChar(); s[3] = (char)str->getChar(); if (!(s[0] == 'x' && s[1] == 'r' && s[2] == 'e' && s[3] == 'f')) { goto err2; } // read xref while (1) { while ((c = str->lookChar()) != EOF && isspace(c)) { str->getChar(); @@ -240,209 +247,212 @@ GBool XRef::readXRef(int *pos) { goto err2; } s[i] = '\0'; first = atoi(s); while ((c = str->lookChar()) != EOF && isspace(c)) { str->getChar(); } for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) { s[i] = (char)c; } if (i == 0) { goto err2; } s[i] = '\0'; n = atoi(s); while ((c = str->lookChar()) != EOF && isspace(c)) { str->getChar(); } // check for buggy PDF files with an incorrect (too small) xref // table size if (first + n > size) { newSize = size + 256; entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { - entries[i].offset = -1; + entries[i].offset = 0xffffffff; entries[i].used = gFalse; } size = newSize; } for (i = first; i < first + n; ++i) { for (j = 0; j < 20; ++j) { if ((c = str->getChar()) == EOF) { 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; } else if (s[17] == 'f') { entries[i].used = gFalse; } else { goto err2; } // PDF files of patents from the IBM Intellectual Property // Network have a bug: the xref table claims to start at 1 // instead of 0. if (i == 1 && first == 1 && entries[1].offset == 0 && entries[1].gen == 65535 && !entries[1].used) { i = first = 0; entries[0] = entries[1]; - entries[1].offset = -1; + entries[1].offset = 0xffffffff; } } } } // 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; } obj.free(); parser->getObj(&obj); if (!obj.isDict()) { goto err1; } obj.getDict()->lookupNF("Prev", &obj2); if (obj2.isInt()) { - *pos = obj2.getInt(); + *pos = (Guint)obj2.getInt(); more = gTrue; } else { more = gFalse; } obj.free(); obj2.free(); delete parser; return more; err1: obj.free(); err2: ok = gFalse; return gFalse; } // Attempt to construct an xref table for a damaged file. GBool XRef::constructXRef() { Parser *parser; Object obj; char buf[256]; - int pos; + Guint pos; int num, gen; int newSize; int streamEndsSize; char *p; int i; GBool gotRoot; error(0, "PDF file is damaged - attempting to reconstruct xref table..."); gotRoot = gFalse; streamEndsLen = streamEndsSize = 0; str->reset(); while (1) { pos = str->getPos(); if (!str->getLine(buf, 256)) { break; } p = buf; // 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()) { trailerDict.dictLookupNF("Root", &obj); if (obj.isRef()) { rootNum = obj.getRefNum(); rootGen = obj.getRefGen(); gotRoot = gTrue; } obj.free(); } else { pos = 0; } delete parser; // look for object } else if (isdigit(*p)) { num = atoi(p); do { ++p; } while (*p && isdigit(*p)); if (isspace(*p)) { do { ++p; } while (*p && isspace(*p)); if (isdigit(*p)) { gen = atoi(p); do { ++p; } while (*p && isdigit(*p)); if (isspace(*p)) { do { ++p; } while (*p && isspace(*p)); if (!strncmp(p, "obj", 3)) { if (num >= size) { 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; } if (!entries[num].used || gen >= entries[num].gen) { entries[num].offset = pos - start; entries[num].gen = gen; entries[num].used = gTrue; } } } } } } 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; } } if (gotRoot) return gTrue; error(-1, "Couldn't find trailer dictionary"); return gFalse; } #ifndef NO_DECRYPTION GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) { Object encrypt, filterObj, versionObj, revisionObj, lengthObj; Object ownerKey, userKey, permissions, fileID, fileID1; GBool encrypted1; GBool ret; ret = gFalse; permFlags = defPermFlags; trailerDict.dictLookup("Encrypt", &encrypt); if ((encrypted1 = encrypt.isDict())) { @@ -559,83 +569,97 @@ GBool XRef::okToCopy(GBool ignoreOwnerPW) { return gTrue; } GBool XRef::okToAddNotes(GBool ignoreOwnerPW) { #ifndef NO_DECRYPTION if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permNotes)) { return gFalse; } #endif return gTrue; } Object *XRef::fetch(int num, int gen, Object *obj) { XRefEntry *e; Parser *parser; Object obj1, obj2, obj3; // check for bogus ref - this can happen in corrupted PDF files if (num < 0 || num >= size) { obj->initNull(); 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 && obj2.isInt() && obj2.getInt() == gen && obj3.isCmd("obj")) { #ifndef NO_DECRYPTION parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength, num, gen); #else parser->getObj(obj); #endif } else { obj->initNull(); } obj1.free(); obj2.free(); obj3.free(); delete parser; } else { obj->initNull(); } return obj; } Object *XRef::getDocInfo(Object *obj) { return trailerDict.dictLookup("Info", obj); } // Added for the pdftex project. 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; // invariant: streamEnds[a] < streamStart <= streamEnds[b] while (b - a > 1) { m = (a + b) / 2; if (streamStart <= streamEnds[m]) { b = m; } else { a = m; } } - return streamEnds[b]; + *streamEnd = streamEnds[b]; + return gTrue; +} + +Guint XRef::strToUnsigned(char *s) { + Guint x; + char *p; + int i; + + x = 0; + for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) { + x = 10 * x + (*p - '0'); + } + return x; } diff --git a/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,111 +1,116 @@ //======================================================================== // // XRef.h // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2002 Glyph & Cog, LLC // //======================================================================== #ifndef XREF_H #define XREF_H #ifdef __GNUC__ #pragma interface #endif #include "gtypes.h" #include "Object.h" class Dict; class Stream; //------------------------------------------------------------------------ // XRef //------------------------------------------------------------------------ struct XRefEntry { - int offset; + Guint offset; int gen; GBool used; }; class XRef { public: // Constructor. Read xref table from stream. XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword); // Destructor. ~XRef(); // Is xref table valid? GBool isOk() { return ok; } + // Get the error code (if isOk() returns false). + int getErrorCode() { return errCode; } + // Is the file encrypted? #ifndef NO_DECRYPTION GBool isEncrypted() { return encrypted; } #else GBool isEncrypted() { return gFalse; } #endif // Check various permissions. GBool okToPrint(GBool ignoreOwnerPW = gFalse); GBool okToChange(GBool ignoreOwnerPW = gFalse); GBool okToCopy(GBool ignoreOwnerPW = gFalse); GBool okToAddNotes(GBool ignoreOwnerPW = gFalse); // Get catalog object. Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); } // Fetch an indirect reference. Object *fetch(int num, int gen, Object *obj); // Return the document's Info dictionary (if any). Object *getDocInfo(Object *obj); Object *getDocInfoNF(Object *obj); // Return the number of objects in the xref table. int getNumObjects() { return size; } // Return the offset of the last xref table. - int getLastXRefPos() { return lastXRefPos; } + Guint getLastXRefPos() { return lastXRefPos; } // Return the catalog object reference. int getRootNum() { return rootNum; } int getRootGen() { return rootGen; } // Get end position for a stream in a damaged file. - // Returns -1 if unknown or file is not damaged. - int getStreamEnd(int 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 int encVersion; // encryption algorithm int encRevision; // security handler revision int keyLength; // length of key, in bytes int permFlags; // permission bits Guchar fileKey[16]; // file decryption key GBool ownerPasswordOk; // true if owner password is correct #endif - int readTrailer(); - GBool readXRef(int *pos); + Guint readTrailer(); + GBool readXRef(Guint *pos); GBool constructXRef(); GBool checkEncrypted(GString *ownerPassword, GString *userPassword); + Guint strToUnsigned(char *s); }; #endif |