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 @@ -1,173 +1,180 @@ //======================================================================== // // XOutputDev.h // // Copyright 1996 Derek B. Noonburg // //======================================================================== #ifndef QOUTPUTDEV_H #define QOUTPUTDEV_H #ifdef __GNUC__ #pragma interface #endif #include "aconf.h" #include <stddef.h> #include <qscrollview.h> class Object; #include "config.h" #include "CharTypes.h" #include "GlobalParams.h" #include "OutputDev.h" class GString; class GList; struct GfxRGB; class GfxFont; class GfxSubpath; class TextPage; class XOutputFontCache; class Link; class Catalog; class DisplayFontParam; class UnicodeMap; class CharCodeToUnicode; class QPainter; class QPixmap; class QPointArray; typedef fouble fp_t; //------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------ //------------------------------------------------------------------------ // Misc types //------------------------------------------------------------------------ //------------------------------------------------------------------------ // 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); virtual void updateLineWidth(GfxState *state); virtual void updateFillColor(GfxState *state); virtual void updateStrokeColor(GfxState *state); //----- update text state virtual void updateFont(GfxState *state); //----- 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, fp_t x, fp_t y, fp_t dx, fp_t dy, fp_t originX, fp_t originY, CharCode code, Unicode *u, int uLen); //----- 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); // Find a string. If <top> is true, starts looking at <l>,<t>; // otherwise starts looking at top of page. If <bottom> is true, // stops looking at <l+w-1>,<t+h-1>; otherwise stops looking at bottom // of page. If found, sets the text bounding rectange and returns // true; otherwise returns false. GBool findText ( Unicode *s, int len, GBool top, GBool bottom, int *xMin, int *yMin, int *xMax, int *yMax ); //----- special QT access bool findText ( const QString &str, int &l, int &t, int &w, int &h, bool top = 0, bool bottom = 0 ); bool findText ( const QString &str, QRect &r, bool top = 0, bool bottom = 0 ); // Get the text which is inside the specified rectangle. QString getText ( int left, int top, int width, int height ); QString getText ( const QRect &r ); protected: virtual void drawContents ( QPainter *p, int, int, int, int ); private: QPixmap *m_pixmap; // pixmap to draw into QPainter *m_painter; TextPage *m_text; // text from the current page private: QFont matchFont ( GfxFont *, fp_t m11, fp_t m12, fp_t m21, fp_t m22 ); void updateLineAttrs ( GfxState *state, GBool updateDash ); void doFill ( GfxState *state, bool winding ); void doClip ( GfxState *state, bool winding ); int convertPath ( GfxState *state, QPointArray &points, QArray<int> &lengths ); int convertSubpath ( GfxState *state, GfxSubpath *subpath, QPointArray &points ); }; #endif 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,180 +1,191 @@ //======================================================================== // // 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 ))); m_tb_tool = new QToolBar ( this ); new QToolButton ( Resource::loadIconSet ( "fileopen" ), tr( "Open..." ), QString::null, this, SLOT( openFile ( )), m_tb_tool, "open" ); m_tb_tool-> addSeparator ( ); m_to_find = new QToolButton ( Resource::loadIconSet ( "find" ), tr( "Find..." ), QString::null, this, SLOT( toggleFindBar ( )), m_tb_tool, "find" ); m_to_find-> setToggleButton ( true ); m_tb_tool-> addSeparator ( ); m_to_full = new QToolButton ( Resource::loadIconSet ( "fullscreen" ), tr( "Fullscreen" ), QString::null, this, SLOT( toggleFullscreen ( )), m_tb_tool, "fullscreen" ); m_to_full-> setToggleButton ( true ); m_tb_tool-> addSeparator ( ); new QToolButton ( Resource::loadIconSet ( "fastback" ), tr( "First page" ), QString::null, this, SLOT( firstPage ( )), m_tb_tool, "first" ); new QToolButton ( Resource::loadIconSet ( "back" ), tr( "Previous page" ), QString::null, this, SLOT( prevPage ( )), m_tb_tool, "prev" ); new QToolButton ( Resource::loadIconSet ( "down" ), tr( "Goto page..." ), QString::null, this, SLOT( gotoPageDialog ( )), m_tb_tool, "goto" ); new QToolButton ( Resource::loadIconSet ( "forward" ), tr( "Next page" ), QString::null, this, SLOT( nextPage ( )), m_tb_tool, "next" ); new QToolButton ( Resource::loadIconSet ( "fastforward" ), tr( "Last page" ), QString::null, this, SLOT( lastPage ( )), m_tb_tool, "last" ); m_tb_find = new QToolBar ( this ); addToolBar ( m_tb_find, "Search", QMainWindow::Top, true ); m_tb_find-> setHorizontalStretchable ( true ); m_tb_find-> hide ( ); m_findedit = new QLineEdit ( m_tb_find, "findedit" ); m_tb_find-> setStretchableWidget ( m_findedit ); connect ( m_findedit, SIGNAL( textChanged ( const QString & )), this, SLOT( findText ( const QString & ))); new QToolButton ( Resource::loadIconSet ( "next" ), tr( "Next" ), QString::null, this, SLOT( findText ( )), m_tb_find, "findnext" ); openFile ( ); } QPdfDlg::~QPdfDlg ( ) { delete m_doc; } // vv Fullscreen handling (for broken QT-lib) [David Hedbor, www.eongames.com] void QPdfDlg::resizeEvent ( QResizeEvent * ) { if ( m_fullscreen && ( size ( ) != qApp-> desktop ( )-> size ( ))) setFullscreen ( true ); } void QPdfDlg::focusInEvent ( QFocusEvent * ) { if ( m_fullscreen ) setFullscreen ( true ); } void QPdfDlg::toggleFullscreen ( ) { if ( m_to_full-> isOn ( ) == m_fullscreen ) m_to_full-> setOn ( !m_fullscreen ); m_fullscreen = !m_fullscreen; setFullscreen ( m_fullscreen ); } void QPdfDlg::setFullscreen ( bool b ) { static QSize normalsize; if ( b ) { if ( !normalsize. isValid ( )) normalsize = size ( ); setFixedSize ( qApp-> desktop ( )-> size ( )); showNormal ( ); reparent ( 0, WStyle_Customize | WStyle_NoBorder, QPoint ( 0, 0 )); showFullScreen ( ); } 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,94 +1,101 @@ #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 ( ); void toggleFindBar ( ); void findText ( const QString & ); void findText ( ); void openFile ( ); void openFile ( const QString & ); void openFile ( const DocLnk & ); 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,139 +1,138 @@ //======================================================================== // -// 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(); } apObj.free(); if (dict->lookup("Rect", &obj1)->isArray() && obj1.arrayGetLength() == 4) { //~ should check object types here obj1.arrayGet(0, &obj2); xMin = obj2.getNum(); obj2.free(); obj1.arrayGet(1, &obj2); yMin = obj2.getNum(); obj2.free(); obj1.arrayGet(2, &obj2); xMax = obj2.getNum(); obj2.free(); obj1.arrayGet(3, &obj2); yMax = obj2.getNum(); obj2.free(); if (xMin > xMax) { t = xMin; xMin = xMax; xMax = t; } if (yMin > yMax) { t = yMin; yMin = yMax; yMax = t; } } else { //~ this should return an error xMin = yMin = 0; xMax = yMax = 1; } obj1.free(); } -FormWidget::~FormWidget() { +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,53 +1,53 @@ //======================================================================== // // 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; } Array::~Array() { int i; for (i = 0; i < length; ++i) elems[i].free(); gfree(elems); } void Array::add(Object *elem) { if (length + 1 > size) { size += 8; elems = (Object *)grealloc(elems, size * sizeof(Object)); } elems[length] = *elem; ++length; } Object *Array::get(int i, Object *obj) { return elems[i].fetch(xref, obj); } Object *Array::getNF(int i, Object *obj) { return elems[i].copy(obj); } 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,56 +1,56 @@ //======================================================================== // // 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); // Destructor. ~Array(); // Reference counting. int incRef() { return ++ref; } int decRef() { return --ref; } // Get number of elements. int getLength() { return length; } // Add an element. void add(Object *elem); // Accessors. Object *get(int i, Object *obj); Object *getNF(int i, Object *obj); private: XRef *xref; // the xref table for this PDF file Object *elems; // array of elements int size; // size of <elems> array int length; // number of elements in array int ref; // reference count }; #endif 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,55 +1,55 @@ //======================================================================== // // 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; }; //------------------------------------------------------------------------ struct BuiltinFontWidth { char *name; Gushort width; BuiltinFontWidth *next; }; class BuiltinFontWidths { public: BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA); ~BuiltinFontWidths(); GBool getWidth(char *name, Gushort *width); private: int hash(char *name); BuiltinFontWidth **tab; int size; }; #endif 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,101 +1,101 @@ //======================================================================== // // 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 }, { "yen", 600, NULL }, { "space", 600, NULL }, { "questiondown", 600, NULL }, { "emdash", 600, NULL }, { "Agrave", 600, NULL }, { "three", 600, NULL }, { "numbersign", 600, NULL }, { "A", 600, NULL }, { "B", 600, NULL }, { "C", 600, NULL }, { "D", 600, NULL }, { "E", 600, NULL }, { "onequarter", 600, NULL }, { "F", 600, NULL }, { "G", 600, NULL }, { "H", 600, NULL }, { "I", 600, NULL }, { "J", 600, NULL }, { "K", 600, NULL }, { "L", 600, NULL }, { "backslash", 600, NULL }, { "periodcentered", 600, NULL }, { "M", 600, NULL }, { "N", 600, NULL }, { "O", 600, NULL }, { "P", 600, NULL }, { "Q", 600, NULL }, { "R", 600, NULL }, { "Aacute", 600, NULL }, { "caron", 600, NULL }, { "S", 600, NULL }, { "T", 600, NULL }, { "U", 600, NULL }, { "agrave", 600, NULL }, { "V", 600, NULL }, { "tab", 600, NULL }, { "W", 600, NULL }, { "ll", 600, NULL }, { "equal", 600, NULL }, { "question", 600, NULL }, { "X", 600, NULL }, { "Y", 600, NULL }, { "Z", 600, NULL }, { "four", 600, NULL }, { "a", 600, NULL }, { "b", 600, NULL }, { "c", 600, NULL }, { "d", 600, NULL }, { "e", 600, NULL }, { "f", 600, NULL }, { "g", 600, NULL }, { "bullet", 600, NULL }, { "h", 600, NULL }, { "i", 600, NULL }, { "Oslash", 600, NULL }, { "dagger", 600, NULL }, { "j", 600, NULL }, { "k", 600, NULL }, { "l", 600, NULL }, { "m", 600, NULL }, { "n", 600, NULL }, { "o", 600, NULL }, { "ordfeminine", 600, NULL }, { "ring", 600, NULL }, { "p", 600, NULL }, { "q", 600, NULL }, { "r", 600, NULL }, { "twosuperior", 600, NULL }, { "largebullet", 600, NULL }, { "aacute", 600, NULL }, { "s", 600, NULL }, { "OE", 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,203 +1,223 @@ //======================================================================== // // 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; vector = NULL; refCnt = 1; } void CMap::useCMap(CMapCache *cache, char *useName) { GString *useNameStr; CMap *subCMap; useNameStr = new GString(useName); subCMap = cache->getCMap(collection, useNameStr); delete useNameStr; if (!subCMap) { return; } copyVector(vector, subCMap->vector); subCMap->decRefCnt(); } void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) { int i, j; for (i = 0; i < 256; ++i) { if (src[i].isVector) { if (!dest[i].isVector) { dest[i].isVector = gTrue; dest[i].vector = (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry)); for (j = 0; j < 256; ++j) { dest[i].vector[j].isVector = gFalse; dest[i].vector[j].cid = 0; } } copyVector(dest[i].vector, src[i].vector); } else { if (dest[i].isVector) { error(-1, "Collision in usecmap"); } else { dest[i].cid = src[i].cid; } } } } void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end, Guint nBytes) { Guint start2, end2; int startByte, endByte, i, j; if (nBytes > 1) { startByte = (start >> (8 * (nBytes - 1))) & 0xff; endByte = (end >> (8 * (nBytes - 1))) & 0xff; start2 = start & ((1 << (8 * (nBytes - 1))) - 1); end2 = end & ((1 << (8 * (nBytes - 1))) - 1); for (i = startByte; i <= endByte; ++i) { if (!vec[i].isVector) { vec[i].isVector = gTrue; vec[i].vector = (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry)); for (j = 0; j < 256; ++j) { vec[i].vector[j].isVector = gFalse; vec[i].vector[j].cid = 0; } } addCodeSpace(vec[i].vector, start2, end2, nBytes - 1); } } } void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) { CMapVectorEntry *vec; CID cid; int byte; 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,93 +1,93 @@ //======================================================================== // // 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. static CMap *parse(CMapCache *cache, GString *collectionA, GString *cMapNameA); ~CMap(); void incRefCnt(); void decRefCnt(); // Return collection name (<registry>-<ordering>). GString *getCollection() { return collection; } // Return true if this CMap matches the specified <collectionA>, and // <cMapNameA>. GBool match(GString *collectionA, GString *cMapNameA); // Return the CID corresponding to the character code starting at // <s>, which contains <len> bytes. Sets *<nUsed> to the number of // bytes used by the char code. CID getCID(char *s, int len, int *nUsed); // Return the writing mode (0=horizontal, 1=vertical). int getWMode() { return wMode; } private: CMap(GString *collectionA, GString *cMapNameA); CMap(GString *collectionA, GString *cMapNameA, int wModeA); void useCMap(CMapCache *cache, char *useName); void copyVector(CMapVectorEntry *dest, CMapVectorEntry *src); void addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end, Guint nBytes); void addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID); void freeCMapVector(CMapVectorEntry *vec); GString *collection; GString *cMapName; int wMode; // writing mode (0=horizontal, 1=vertical) CMapVectorEntry *vector; // vector for first byte (NULL for // identity CMap) int refCnt; }; //------------------------------------------------------------------------ #define cMapCacheSize 4 class CMapCache { public: CMapCache(); ~CMapCache(); // Get the <cMapName> CMap for the specified character collection. // Increments its reference count; there will be one reference for // the cache plus one for the caller of this function. Returns NULL // on failure. CMap *getCMap(GString *collection, GString *cMapName); private: CMap *cache[cMapCacheSize]; }; #endif 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,341 +1,341 @@ //======================================================================== // // 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) { Object catDict, pagesDict; Object obj, obj2; int numPages0; int i; ok = gTrue; xref = xrefA; pages = NULL; pageRefs = NULL; numPages = pagesSize = 0; baseURI = NULL; xref->getCatalog(&catDict); if (!catDict.isDict()) { error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName()); goto err1; } // read page tree catDict.dictLookup("Pages", &pagesDict); // This should really be isDict("Pages"), but I've seen at least one // PDF file where the /Type entry is missing. if (!pagesDict.isDict()) { error(-1, "Top-level pages object is wrong type (%s)", pagesDict.getTypeName()); goto err2; } pagesDict.dictLookup("Count", &obj); if (!obj.isInt()) { error(-1, "Page count in top-level pages object is wrong type (%s)", obj.getTypeName()); goto err3; } pagesSize = numPages0 = obj.getInt(); obj.free(); pages = (Page **)gmalloc(pagesSize * sizeof(Page *)); pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref)); for (i = 0; i < pagesSize; ++i) { pages[i] = NULL; pageRefs[i].num = -1; pageRefs[i].gen = -1; } numPages = readPageTree(pagesDict.getDict(), NULL, 0, printCommands); if (numPages != numPages0) { error(-1, "Page count in top-level pages object is incorrect"); } pagesDict.free(); // read named destination dictionary catDict.dictLookup("Dests", &dests); // read root of named destination tree if (catDict.dictLookup("Names", &obj)->isDict()) obj.dictLookup("Dests", &nameTree); else nameTree.initNull(); obj.free(); // read base URI if (catDict.dictLookup("URI", &obj)->isDict()) { if (obj.dictLookup("Base", &obj2)->isString()) { baseURI = obj2.getString()->copy(); } obj2.free(); } obj.free(); // get the metadata stream catDict.dictLookup("Metadata", &metadata); // get the structure tree root catDict.dictLookup("StructTreeRoot", &structTreeRoot); catDict.free(); return; err3: obj.free(); err2: pagesDict.free(); err1: catDict.free(); dests.initNull(); nameTree.initNull(); ok = gFalse; } Catalog::~Catalog() { int i; if (pages) { for (i = 0; i < pagesSize; ++i) { if (pages[i]) { delete pages[i]; } } 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()) { error(-1, "Kids object (page %d) is wrong type (%s)", start+1, kids.getTypeName()); goto err1; } for (i = 0; i < kids.arrayGetLength(); ++i) { kids.arrayGet(i, &kid); if (kid.isDict("Page")) { attrs2 = new PageAttrs(attrs1, kid.getDict()); page = new Page(xref, start+1, kid.getDict(), attrs2, printCommands); if (!page->isOk()) { ++start; goto err3; } if (start >= pagesSize) { pagesSize += 32; pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *)); pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref)); for (j = pagesSize - 32; j < pagesSize; ++j) { pages[j] = NULL; pageRefs[j].num = -1; pageRefs[j].gen = -1; } } pages[start] = page; kids.arrayGetNF(i, &kidRef); if (kidRef.isRef()) { pageRefs[start].num = kidRef.getRefNum(); pageRefs[start].gen = kidRef.getRefGen(); } kidRef.free(); ++start; // This should really be isDict("Pages"), but I've seen at least one // PDF file where the /Type entry is missing. } else if (kid.isDict()) { if ((start = readPageTree(kid.getDict(), attrs1, start, printCommands)) < 0) goto err2; } else { error(-1, "Kid object (page %d) is wrong type (%s)", start+1, kid.getTypeName()); goto err2; } kid.free(); } delete attrs1; kids.free(); return start; err3: delete page; err2: kid.free(); err1: kids.free(); delete attrs1; ok = gFalse; return -1; } int Catalog::findPage(int num, int gen) { int i; for (i = 0; i < numPages; ++i) { if (pageRefs[i].num == num && pageRefs[i].gen == gen) return i + 1; } return 0; } 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) { names.arrayGet(i+1, obj); found = gTrue; done = gTrue; } else if (cmp < 0) { done = gTrue; } name1.free(); } } names.free(); if (!found) obj->initNull(); return obj; } names.free(); // root or intermediate node done = gFalse; if (tree->dictLookup("Kids", &kids)->isArray()) { for (i = 0; !done && i < kids.arrayGetLength(); ++i) { if (kids.arrayGet(i, &kid)->isDict()) { if (kid.dictLookup("Limits", &limits)->isArray()) { if (limits.arrayGet(0, &low)->isString() && name->cmp(low.getString()) >= 0) { if (limits.arrayGet(1, &high)->isString() && name->cmp(high.getString()) <= 0) { findDestInTree(&kid, name, obj); done = gTrue; } high.free(); } low.free(); } limits.free(); } kid.free(); } } kids.free(); // name was outside of ranges of all kids if (!done) obj->initNull(); return obj; } 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,85 +1,85 @@ //======================================================================== // // 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: // Constructor. Catalog(XRef *xrefA, GBool printCommands = gFalse); // Destructor. ~Catalog(); // Is catalog valid? GBool isOk() { return ok; } // Get number of pages. int getNumPages() { return numPages; } // Get a page. Page *getPage(int i) { return pages[i-1]; } // Get the reference for a page object. Ref *getPageRef(int i) { return &pageRefs[i-1]; } // Return base URI, or NULL if none. GString *getBaseURI() { return baseURI; } // Return the contents of the metadata stream, or NULL if there is // no metadata. GString *readMetadata(); // Return the structure tree root object. Object *getStructTreeRoot() { return &structTreeRoot; } // Find a page, given its object ID. Returns page number, or 0 if // not found. int findPage(int num, int gen); // Find a named destination. Returns the link destination, or // NULL if <name> is not a destination. LinkDest *findDest(GString *name); private: XRef *xref; // the xref table for this PDF file Page **pages; // array of pages Ref *pageRefs; // object ID for each page int numPages; // number of pages int pagesSize; // size of pages array Object dests; // named destination dictionary Object nameTree; // name tree GString *baseURI; // base URI for URI-type links Object metadata; // metadata stream Object structTreeRoot; // structure tree root dictionary GBool ok; // true if catalog is valid int readPageTree(Dict *pages, PageAttrs *attrs, int start, GBool printCommands); Object *findDestInTree(Object *tree, GString *name, Object *obj); }; #endif 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,360 +1,356 @@ //======================================================================== // // 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)); memcpy(map, mapA, mapLen * sizeof(Unicode)); } else { map = mapA; } sMap = sMapA; sMapLen = sMapSize = sMapLenA; refCnt = 1; } CharCodeToUnicode::~CharCodeToUnicode() { if (collection) { delete collection; } gfree(map); if (sMap) { gfree(sMap); } } void CharCodeToUnicode::incRefCnt() { ++refCnt; } void CharCodeToUnicode::decRefCnt() { if (--refCnt == 0) { delete this; } } GBool CharCodeToUnicode::match(GString *collectionA) { return collection && !collection->cmp(collectionA); } int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) { int i, j; if (c >= mapLen) { return 0; } if (map[c]) { u[0] = map[c]; return 1; } for (i = 0; i < sMapLen; ++i) { if (sMap[i].c == c) { for (j = 0; j < sMap[i].len && j < size; ++j) { u[j] = sMap[i].u[j]; } return j; } } return 0; } //------------------------------------------------------------------------ CIDToUnicodeCache::CIDToUnicodeCache() { int i; for (i = 0; i < cidToUnicodeCacheSize; ++i) { cache[i] = NULL; } } CIDToUnicodeCache::~CIDToUnicodeCache() { int i; for (i = 0; i < cidToUnicodeCacheSize; ++i) { if (cache[i]) { cache[i]->decRefCnt(); } } 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,89 +1,88 @@ //======================================================================== // // 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 // its reference count; there will be one reference for the cache // plus one for the caller of this function. Returns NULL on // failure. CharCodeToUnicode *getCIDToUnicode(GString *collection); private: CharCodeToUnicode *cache[cidToUnicodeCacheSize]; }; #endif 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,101 +1,101 @@ //======================================================================== // // 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 //------------------------------------------------------------------------ Decrypt::Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen) { int i; // construct object key for (i = 0; i < keyLength; ++i) { objKey[i] = fileKey[i]; } objKey[keyLength] = objNum & 0xff; objKey[keyLength + 1] = (objNum >> 8) & 0xff; objKey[keyLength + 2] = (objNum >> 16) & 0xff; objKey[keyLength + 3] = objGen & 0xff; objKey[keyLength + 4] = (objGen >> 8) & 0xff; md5(objKey, keyLength + 5, objKey); // set up for decryption x = y = 0; if ((objKeyLength = keyLength + 5) > 16) { objKeyLength = 16; } rc4InitKey(objKey, objKeyLength, state); } void Decrypt::reset() { x = y = 0; rc4InitKey(objKey, objKeyLength, state); } Guchar Decrypt::decryptByte(Guchar c) { return rc4DecryptByte(state, &x, &y, c); } GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, int permissions, GString *fileID, GString *ownerPassword, GString *userPassword, Guchar *fileKey, GBool *ownerPasswordOk) { Guchar test[32]; GString *userPassword2; Guchar fState[256]; Guchar fx, fy; int len, i; // try using the supplied owner password to generate the user password if (ownerPassword) { len = ownerPassword->getLength(); if (len < 32) { memcpy(test, ownerPassword->getCString(), len); memcpy(test + len, passwordPad, 32 - len); } else { memcpy(test, ownerPassword->getCString(), 32); } } else { memcpy(test, passwordPad, 32); } md5(test, 32, test); if (encRevision == 3) { for (i = 0; i < 50; ++i) { md5(test, 16, test); } } rc4InitKey(test, keyLength, fState); fx = fy = 0; for (i = 0; i < 32; ++i) { test[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i)); } userPassword2 = new GString((char *)test, 32); if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, permissions, fileID, userPassword2, fileKey)) { *ownerPasswordOk = gTrue; delete userPassword2; 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,59 +1,59 @@ //======================================================================== // // 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. void reset(); // Decrypt one byte. Guchar decryptByte(Guchar c); // Generate a file key. The <fileKey> buffer must have space for at // least 16 bytes. Checks <ownerPassword> and then <userPassword> // and returns true if either is correct. Sets <ownerPasswordOk> if // the owner password was correct. Either or both of the passwords // may be NULL, which is treated as an empty string. static GBool makeFileKey(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, int permissions, GString *fileID, GString *ownerPassword, GString *userPassword, Guchar *fileKey, GBool *ownerPasswordOk); private: static GBool makeFileKey2(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, int permissions, GString *fileID, GString *userPassword, Guchar *fileKey); int objKeyLength; Guchar objKey[21]; Guchar state[256]; Guchar x, y; }; #endif 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,90 +1,90 @@ //======================================================================== // // 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; } Dict::~Dict() { int i; for (i = 0; i < length; ++i) { gfree(entries[i].key); entries[i].val.free(); } gfree(entries); } void Dict::add(char *key, Object *val) { if (length + 1 > size) { size += 8; entries = (DictEntry *)grealloc(entries, size * sizeof(DictEntry)); } entries[length].key = key; entries[length].val = *val; ++length; } inline DictEntry *Dict::find(char *key) { int i; for (i = 0; i < length; ++i) { if (!strcmp(key, entries[i].key)) return &entries[i]; } return NULL; } GBool Dict::is(char *type) { DictEntry *e; return (e = find("Type")) && e->val.isName(type); } Object *Dict::lookup(char *key, Object *obj) { DictEntry *e; return (e = find(key)) ? e->val.fetch(xref, obj) : obj->initNull(); } Object *Dict::lookupNF(char *key, Object *obj) { DictEntry *e; return (e = find(key)) ? e->val.copy(obj) : obj->initNull(); } char *Dict::getKey(int i) { return entries[i].key; } Object *Dict::getVal(int i, Object *obj) { return entries[i].val.fetch(xref, obj); } Object *Dict::getValNF(int i, Object *obj) { return entries[i].val.copy(obj); } 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,75 +1,75 @@ //======================================================================== // // 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: // Constructor. Dict(XRef *xrefA); // Destructor. ~Dict(); // Reference counting. int incRef() { return ++ref; } int decRef() { return --ref; } // Get number of entries. int getLength() { return length; } // Add an entry. NB: does not copy key. void add(char *key, Object *val); // Check if dictionary is of specified type. GBool is(char *type); // Look up an entry and return the value. Returns a null object // if <key> is not in the dictionary. Object *lookup(char *key, Object *obj); Object *lookupNF(char *key, Object *obj); // Iterative accessors. char *getKey(int i); Object *getVal(int i, Object *obj); Object *getValNF(int i, Object *obj); // Set the xref pointer. This is only used in one special case: the // trailer dictionary, which is read before the xref table is // parsed. void setXRef(XRef *xrefA) { xref = xrefA; } private: XRef *xref; // the xref table for this PDF file DictEntry *entries; // array of entries int size; // size of <entries> array int length; // number of entries in dictionary int ref; // reference count DictEntry *find(char *key); }; #endif 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,37 +1,37 @@ //======================================================================== // // 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 { fprintf(stderr, "Error: "); } va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, "\n"); fflush(stderr); } 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,101 +1,101 @@ //======================================================================== // // 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, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", 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,101 +1,101 @@ //======================================================================== // // 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() { } Function::~Function() { } Function *Function::parse(Object *funcObj) { Function *func; Dict *dict; int funcType; Object obj1; if (funcObj->isStream()) { dict = funcObj->streamGetDict(); } else if (funcObj->isDict()) { dict = funcObj->getDict(); } else if (funcObj->isName("Identity")) { return new IdentityFunction(); } else { error(-1, "Expected function dictionary or stream"); return NULL; } if (!dict->lookup("FunctionType", &obj1)->isInt()) { error(-1, "Function type is missing or wrong type"); obj1.free(); return NULL; } funcType = obj1.getInt(); obj1.free(); if (funcType == 0) { func = new SampledFunction(funcObj, dict); } else if (funcType == 2) { func = new ExponentialFunction(funcObj, dict); } else if (funcType == 3) { func = new StitchingFunction(funcObj, dict); } else if (funcType == 4) { func = new PostScriptFunction(funcObj, dict); } else { error(-1, "Unimplemented function type (%d)", funcType); return NULL; } if (!func->isOk()) { delete func; return NULL; } return func; } GBool Function::init(Dict *dict) { Object obj1, obj2; int i; //----- Domain if (!dict->lookup("Domain", &obj1)->isArray()) { error(-1, "Function is missing domain"); goto err2; } m = obj1.arrayGetLength() / 2; if (m > funcMaxInputs) { error(-1, "Functions with more than %d inputs are unsupported", funcMaxInputs); goto err2; } for (i = 0; i < m; ++i) { obj1.arrayGet(2*i, &obj2); if (!obj2.isNum()) { error(-1, "Illegal value in function domain array"); goto err1; } domain[i][0] = obj2.getNum(); @@ -322,257 +322,266 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { samples[i] = (fouble)s * sampleMul; } str->close(); ok = gTrue; return; err3: obj2.free(); err2: obj1.free(); err1: return; } SampledFunction::~SampledFunction() { if (samples) { gfree(samples); } } SampledFunction::SampledFunction(SampledFunction *func) { int nSamples, i; memcpy(this, func, sizeof(SampledFunction)); nSamples = n; for (i = 0; i < m; ++i) { nSamples *= sampleSize[i]; } samples = (fouble *)gmalloc(nSamples * sizeof(fouble)); memcpy(samples, func->samples, nSamples * sizeof(fouble)); } void SampledFunction::transform(fouble *in, fouble *out) { fouble x; int e[2][funcMaxInputs]; fouble efrac[funcMaxInputs]; fouble s0[1 << funcMaxInputs], s1[1 << funcMaxInputs]; int i, j, k, idx; // map input values into sample array for (i = 0; i < m; ++i) { x = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) * (encode[i][1] - encode[i][0]) + encode[i][0]; if (x < 0) { x = 0; } else if (x > sampleSize[i] - 1) { x = sampleSize[i] - 1; } e[0][i] = (int)floor(x); e[1][i] = (int)ceil(x); efrac[i] = x - e[0][i]; } // for each output, do m-linear interpolation for (i = 0; i < n; ++i) { // pull 2^m values out of the sample array for (j = 0; j < (1<<m); ++j) { idx = e[j & 1][m - 1]; for (k = m - 2; k >= 0; --k) { idx = idx * sampleSize[k] + e[(j >> k) & 1][k]; } idx = idx * n + i; s0[j] = samples[idx]; } // do m sets of interpolations for (j = 0; j < m; ++j) { for (k = 0; k < (1 << (m - j)); k += 2) { s1[k >> 1] = (1 - efrac[j]) * s0[k] + efrac[j] * s0[k+1]; } 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]; } else if (in[0] > domain[0][1]) { x = domain[0][1]; } else { x = in[0]; } for (i = 0; i < n; ++i) { out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]); if (hasRange) { if (out[i] < range[i][0]) { out[i] = range[i][0]; } else if (out[i] > range[i][1]) { out[i] = range[i][1]; } } } return; } //------------------------------------------------------------------------ // StitchingFunction //------------------------------------------------------------------------ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) { Object obj1, obj2; int i; ok = gFalse; funcs = NULL; bounds = NULL; encode = NULL; //----- initialize the generic stuff if (!init(dict)) { goto err1; } if (m != 1) { error(-1, "Stitching function with more than one input"); goto err1; } //----- Functions if (!dict->lookup("Functions", &obj1)->isArray()) { error(-1, "Missing 'Functions' entry in stitching function"); goto err1; } k = obj1.arrayGetLength(); funcs = (Function **)gmalloc(k * sizeof(Function *)); bounds = (fouble *)gmalloc((k + 1) * sizeof(fouble)); encode = (fouble *)gmalloc(2 * k * sizeof(fouble)); for (i = 0; i < k; ++i) { funcs[i] = NULL; } for (i = 0; i < k; ++i) { if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2)))) { goto err2; } if (i > 0 && (funcs[i]->getInputSize() != 1 || funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) { error(-1, "Incompatible subfunctions in stitching function"); goto err2; } obj2.free(); } obj1.free(); //----- Bounds if (!dict->lookup("Bounds", &obj1)->isArray() || obj1.arrayGetLength() != k - 1) { error(-1, "Missing or invalid 'Bounds' entry in stitching function"); goto err1; } bounds[0] = 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,101 +1,101 @@ //======================================================================== // // 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 class Function { public: Function(); virtual ~Function(); // Construct a function. Returns NULL if unsuccessful. static Function *parse(Object *funcObj); // Initialize the entries common to all function types. GBool init(Dict *dict); virtual Function *copy() = 0; // Return size of input and output tuples. int getInputSize() { return m; } int getOutputSize() { return n; } // Transform an input tuple into an output tuple. virtual void transform(fouble *in, fouble *out) = 0; virtual GBool isOk() = 0; protected: int m, n; // size of input and output tuples fouble // min and max values for function domain domain[funcMaxInputs][2]; fouble // min and max values for function range range[funcMaxOutputs][2]; GBool hasRange; // set if range is defined }; //------------------------------------------------------------------------ // IdentityFunction //------------------------------------------------------------------------ class IdentityFunction: public Function { public: IdentityFunction(); virtual ~IdentityFunction(); virtual Function *copy() { return new IdentityFunction(); } virtual void transform(fouble *in, fouble *out); virtual GBool isOk() { return gTrue; } private: }; //------------------------------------------------------------------------ // SampledFunction //------------------------------------------------------------------------ class SampledFunction: public Function { public: SampledFunction(Object *funcObj, Dict *dict); virtual ~SampledFunction(); virtual Function *copy() { return new SampledFunction(this); } virtual void transform(fouble *in, fouble *out); virtual GBool isOk() { return ok; } private: SampledFunction(SampledFunction *func); int // number of samples for each domain element sampleSize[funcMaxInputs]; fouble // min and max values for domain encoder encode[funcMaxInputs][2]; 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,138 +1,149 @@ //======================================================================== // // 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}, &Gfx::opSetStrokeColorSpace}, {"DP", 2, {tchkName, tchkProps}, &Gfx::opMarkPoint}, {"Do", 1, {tchkName}, &Gfx::opXObject}, {"EI", 0, {tchkNone}, &Gfx::opEndImage}, {"EMC", 0, {tchkNone}, &Gfx::opEndMarkedContent}, {"ET", 0, {tchkNone}, &Gfx::opEndText}, {"EX", 0, {tchkNone}, &Gfx::opEndIgnoreUndef}, {"F", 0, {tchkNone}, &Gfx::opFill}, {"G", 1, {tchkNum}, &Gfx::opSetStrokeGray}, {"ID", 0, {tchkNone}, &Gfx::opImageData}, {"J", 1, {tchkInt}, &Gfx::opSetLineCap}, {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opSetStrokeCMYKColor}, {"M", 1, {tchkNum}, &Gfx::opSetMiterLimit}, {"MP", 1, {tchkName}, &Gfx::opMarkPoint}, {"Q", 0, {tchkNone}, &Gfx::opRestore}, {"RG", 3, {tchkNum, tchkNum, tchkNum}, &Gfx::opSetStrokeRGBColor}, {"S", 0, {tchkNone}, &Gfx::opStroke}, {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opSetStrokeColor}, {"SCN", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN}, &Gfx::opSetStrokeColorN}, {"T*", 0, {tchkNone}, &Gfx::opTextNextLine}, {"TD", 2, {tchkNum, tchkNum}, &Gfx::opTextMoveSet}, {"TJ", 1, {tchkArray}, &Gfx::opShowSpaceText}, {"TL", 1, {tchkNum}, &Gfx::opSetTextLeading}, {"Tc", 1, {tchkNum}, &Gfx::opSetCharSpacing}, {"Td", 2, {tchkNum, tchkNum}, &Gfx::opTextMove}, {"Tf", 2, {tchkName, tchkNum}, &Gfx::opSetFont}, {"Tj", 1, {tchkString}, &Gfx::opShowText}, {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opSetTextMatrix}, {"Tr", 1, {tchkInt}, &Gfx::opSetTextRender}, {"Ts", 1, {tchkNum}, &Gfx::opSetTextRise}, {"Tw", 1, {tchkNum}, &Gfx::opSetWordSpacing}, {"Tz", 1, {tchkNum}, &Gfx::opSetHorizScaling}, {"W", 0, {tchkNone}, &Gfx::opClip}, {"W*", 0, {tchkNone}, &Gfx::opEOClip}, {"b", 0, {tchkNone}, &Gfx::opCloseFillStroke}, {"b*", 0, {tchkNone}, @@ -281,338 +292,372 @@ GBool GfxResources::lookupXObject(char *name, Object *obj) { } error(-1, "XObject '%s' is unknown", name); return gFalse; } GBool GfxResources::lookupXObjectNF(char *name, Object *obj) { GfxResources *resPtr; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->xObjDict.isDict()) { if (!resPtr->xObjDict.dictLookupNF(name, obj)->isNull()) return gTrue; obj->free(); } } error(-1, "XObject '%s' is unknown", name); return gFalse; } void GfxResources::lookupColorSpace(char *name, Object *obj) { GfxResources *resPtr; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->colorSpaceDict.isDict()) { if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) { return; } obj->free(); } } obj->initNull(); } GfxPattern *GfxResources::lookupPattern(char *name) { GfxResources *resPtr; GfxPattern *pattern; Object obj; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->patternDict.isDict()) { if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) { pattern = GfxPattern::parse(&obj); obj.free(); return pattern; } obj.free(); } } error(-1, "Unknown pattern '%s'", name); return NULL; } GfxShading *GfxResources::lookupShading(char *name) { GfxResources *resPtr; GfxShading *shading; Object obj; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->shadingDict.isDict()) { if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) { shading = GfxShading::parse(&obj); obj.free(); return shading; } obj.free(); } } error(-1, "Unknown shading '%s'", name); return NULL; } GBool GfxResources::lookupGState(char *name, Object *obj) { GfxResources *resPtr; 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; } } else { if (numArgs > -op->numArgs) { error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name); return; } } for (i = 0; i < numArgs; ++i) { if (!checkArg(&args[i], op->tchk[i])) { error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)", i, name, args[i].getTypeName()); return; } } // do it (this->*op->func)(args, numArgs); } Operator *Gfx::findOp(char *name) { int a, b, m, cmp; a = -1; b = numOps; // invariant: opTab[a] < name < opTab[b] while (b - a > 1) { m = (a + b) / 2; cmp = strcmp(opTab[m].name, name); if (cmp < 0) a = m; else if (cmp > 0) b = m; else a = b = m; } if (cmp != 0) return NULL; return &opTab[a]; } GBool Gfx::checkArg(Object *arg, TchkType type) { switch (type) { case tchkBool: return arg->isBool(); case tchkInt: return arg->isInt(); case tchkNum: return arg->isNum(); case tchkString: return arg->isString(); case tchkName: return arg->isName(); case tchkArray: return arg->isArray(); case tchkProps: return arg->isDict() || arg->isName(); case tchkSCN: return arg->isNum() || arg->isName(); case tchkNone: return gFalse; } return gFalse; } int Gfx::getPos() { return parser ? parser->getPos() : -1; } //------------------------------------------------------------------------ // graphics state operators //------------------------------------------------------------------------ void Gfx::opSave(Object args[], int numArgs) { out->saveState(state); state = state->save(); } void Gfx::opRestore(Object args[], int numArgs) { state = state->restore(); out->restoreState(state); } @@ -1045,459 +1090,404 @@ void Gfx::opFill(Object args[], int numArgs) { out->fill(state); } } doEndPath(); } void Gfx::opEOFill(Object args[], int numArgs) { if (!state->isCurPt()) { //error(getPos(), "No path in eofill"); return; } if (state->isPath()) { if (state->getFillColorSpace()->getMode() == csPattern) { doPatternFill(gTrue); } else { out->eoFill(state); } } doEndPath(); } void Gfx::opFillStroke(Object args[], int numArgs) { if (!state->isCurPt()) { //error(getPos(), "No path in fill/stroke"); return; } if (state->isPath()) { if (state->getFillColorSpace()->getMode() == csPattern) { doPatternFill(gFalse); } else { out->fill(state); } out->stroke(state); } doEndPath(); } void Gfx::opCloseFillStroke(Object args[], int numArgs) { if (!state->isCurPt()) { //error(getPos(), "No path in closepath/fill/stroke"); return; } if (state->isPath()) { state->closePath(); if (state->getFillColorSpace()->getMode() == csPattern) { doPatternFill(gFalse); } else { out->fill(state); } out->stroke(state); } doEndPath(); } void Gfx::opEOFillStroke(Object args[], int numArgs) { if (!state->isCurPt()) { //error(getPos(), "No path in eofill/stroke"); return; } if (state->isPath()) { if (state->getFillColorSpace()->getMode() == csPattern) { doPatternFill(gTrue); } else { out->eoFill(state); } out->stroke(state); } doEndPath(); } void Gfx::opCloseEOFillStroke(Object args[], int numArgs) { if (!state->isCurPt()) { //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 ctm = state->getCTM(); btm = baseMatrix; 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(); if (eoFill) { out->eoClip(state); } else { out->clip(state); } state->clearPath(); // transform clip region bbox to pattern space state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax); xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4]; yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5]; x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4]; y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5]; if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4]; y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5]; if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4]; y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5]; if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } // draw the pattern //~ this should treat negative steps differently -- start at right/top //~ edge instead of left/bottom (?) xstep = fabs(tPat->getXStep()); ystep = fabs(tPat->getYStep()); xi0 = (int)floor(xMin / xstep); xi1 = (int)ceil(xMax / xstep); yi0 = (int)floor(yMin / ystep); yi1 = (int)ceil(yMax / ystep); for (i = 0; i < 4; ++i) { m1[i] = m[i]; } for (yi = yi0; yi < yi1; ++yi) { for (xi = xi0; xi < xi1; ++xi) { x = xi * xstep; y = yi * ystep; m1[4] = x * m[0] + y * m[2] + m[4]; m1[5] = x * m[1] + y * m[3] + m[5]; doForm1(tPat->getContentStream(), tPat->getResDict(), m1, tPat->getBBox()); } } // restore graphics state state = state->restore(); out->restoreState(state); } void Gfx::opShFill(Object args[], int numArgs) { GfxShading *shading; fouble xMin, yMin, xMax, yMax; if (!(shading = res->lookupShading(args[0].getName()))) { return; } // save current graphics state out->saveState(state); state = state->save(); // clip to bbox if (shading->getHasBBox()) { shading->getBBox(&xMin, &yMin, &xMax, &yMax); state->moveTo(xMin, yMin); state->lineTo(xMax, yMin); state->lineTo(xMax, yMax); state->lineTo(xMin, yMax); state->closePath(); state->clip(); out->clip(state); state->clearPath(); } // set the color space state->setFillColorSpace(shading->getColorSpace()->copy()); // do shading type-specific operations switch (shading->getType()) { case 2: doAxialShFill((GfxAxialShading *)shading); break; + case 3: + doRadialShFill((GfxRadialShading *)shading); + break; } // restore graphics state state = state->restore(); out->restoreState(state); delete shading; } void Gfx::doAxialShFill(GfxAxialShading *shading) { 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) { tMax = t; } if (tMin < 0 && !shading->getExtend0()) { tMin = 0; } if (tMax > 1 && !shading->getExtend1()) { tMax = 1; } // get the function domain t0 = shading->getDomain0(); t1 = shading->getDomain1(); // Traverse the t axis and do the shading. // // For each point (tx, ty) on the t axis, consider a line through // that point perpendicular to the t axis: // // x(s) = tx + s * -dy --> s = (x - tx) / -dy // y(s) = ty + s * dx --> s = (y - ty) / dx // // Then look at the intersection of this line with the bounding box // (xMin, yMin, xMax, yMax). In the general case, there are four // intersection points: // // s0 = (xMin - tx) / -dy // s1 = (xMax - tx) / -dy // s2 = (yMin - ty) / dx // s3 = (yMax - ty) / dx // // and we want the middle two s values. // // In the case where dx = 0, take s0 and s1; in the case where dy = // 0, take s2 and s3. // // Each filled polygon is bounded by two of these line segments // perpdendicular to the t axis. // // The t axis is bisected into smaller regions until the color // difference across a region is small enough, and then the region // is painted with a single color. // set up nComps = shading->getColorSpace()->getNComps(); ta[0] = tMin; ta[axialMaxSplits] = tMax; next[0] = axialMaxSplits; // compute the color at t = tMin if (tMin < 0) { tt = t0; } else if (tMin > 1) { tt = t1; } else { tt = t0 + (t1 - t0) * tMin; } shading->getColor(tt, &color0); // compute the coordinates of the point on the t axis at t = tMin; // then compute the intersection of the perpendicular line with the // bounding box tx = x0 + tMin * dx; ty = y0 + tMin * dy; if (dx == 0 && dy == 0) { sMin = sMax = 0; } if (dx == 0) { sMin = (xMin - tx) / -dy; sMax = (xMax - tx) / -dy; if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } } else if (dy == 0) { sMin = (yMin - ty) / dx; sMax = (yMax - ty) / dx; @@ -1526,936 +1516,1245 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { i = 0; while (i < axialMaxSplits) { // bisect until color difference is small enough or we hit the // bisection limit j = next[i]; while (j > i + 1) { if (ta[j] < 0) { tt = t0; } else if (ta[j] > 1) { tt = t1; } else { tt = t0 + (t1 - t0) * ta[j]; } shading->getColor(tt, &color1); for (k = 0; k < nComps; ++k) { if (fabs(color1.c[k] - color0.c[k]) > axialColorDelta) { break; } } if (k == nComps) { break; } k = (i + j) / 2; ta[k] = 0.5 * (ta[i] + ta[j]); next[i] = k; next[k] = j; j = k; } // use the average of the colors of the two sides of the region for (k = 0; k < nComps; ++k) { color0.c[k] = 0.5 * (color0.c[k] + color1.c[k]); } // compute the coordinates of the point on the t axis; then // compute the intersection of the perpendicular line with the // bounding box tx = x0 + ta[j] * dx; ty = y0 + ta[j] * dy; if (dx == 0 && dy == 0) { sMin = sMax = 0; } if (dx == 0) { sMin = (xMin - tx) / -dy; sMax = (xMax - tx) / -dy; if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } } else if (dy == 0) { sMin = (yMin - ty) / dx; sMax = (yMax - ty) / dx; if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } } else { s[0] = (yMin - ty) / dx; s[1] = (yMax - ty) / dx; s[2] = (xMin - tx) / -dy; s[3] = (xMax - tx) / -dy; for (j = 0; j < 3; ++j) { kk = j; for (k = j + 1; k < 4; ++k) { if (s[k] < s[kk]) { kk = k; } } tmp = s[j]; s[j] = s[kk]; s[kk] = tmp; } sMin = s[1]; sMax = s[2]; } ux1 = tx - sMin * dy; uy1 = ty + sMin * dx; vx1 = tx - sMax * dy; vy1 = ty + sMax * dx; // set the color state->setFillColor(&color0); out->updateFillColor(state); // fill the region state->moveTo(ux0, uy0); state->lineTo(vx0, vy0); state->lineTo(vx1, vy1); state->lineTo(ux1, uy1); state->closePath(); out->fill(state); state->clearPath(); // set up for next region ux0 = ux1; uy0 = uy1; vx0 = vx1; vy0 = vy1; color0 = color1; i = next[i]; } } +void Gfx::doRadialShFill(GfxRadialShading *shading) { + 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; } //------------------------------------------------------------------------ // text object operators //------------------------------------------------------------------------ void Gfx::opBeginText(Object args[], int numArgs) { state->setTextMat(1, 0, 0, 1, 0, 0); state->textMoveTo(0, 0); out->updateTextMat(state); out->updateTextPos(state); fontChanged = gTrue; } void Gfx::opEndText(Object args[], int numArgs) { } //------------------------------------------------------------------------ // text state operators //------------------------------------------------------------------------ void Gfx::opSetCharSpacing(Object args[], int numArgs) { state->setCharSpace(args[0].getNum()); out->updateCharSpace(state); } void Gfx::opSetFont(Object args[], int numArgs) { GfxFont *font; if (!(font = res->lookupFont(args[0].getName()))) { return; } if (printCommands) { printf(" font: tag=%s name='%s' %g\n", font->getTag()->getCString(), font->getName() ? font->getName()->getCString() : "???", args[1].getNum()); fflush(stdout); } state->setFont(font, args[1].getNum()); fontChanged = gTrue; } void Gfx::opSetTextLeading(Object args[], int numArgs) { state->setLeading(args[0].getNum()); } void Gfx::opSetTextRender(Object args[], int numArgs) { state->setRender(args[0].getInt()); out->updateRender(state); } void Gfx::opSetTextRise(Object args[], int numArgs) { state->setRise(args[0].getNum()); out->updateRise(state); } void Gfx::opSetWordSpacing(Object args[], int numArgs) { state->setWordSpace(args[0].getNum()); out->updateWordSpace(state); } void Gfx::opSetHorizScaling(Object args[], int numArgs) { state->setHorizScaling(args[0].getNum()); out->updateHorizScaling(state); fontChanged = gTrue; } //------------------------------------------------------------------------ // text positioning operators //------------------------------------------------------------------------ void Gfx::opTextMove(Object args[], int numArgs) { fouble tx, ty; tx = state->getLineX() + args[0].getNum(); ty = state->getLineY() + args[1].getNum(); state->textMoveTo(tx, ty); out->updateTextPos(state); } void Gfx::opTextMoveSet(Object args[], int numArgs) { fouble tx, ty; tx = state->getLineX() + args[0].getNum(); ty = args[1].getNum(); state->setLeading(-ty); ty += state->getLineY(); state->textMoveTo(tx, ty); out->updateTextPos(state); } void Gfx::opSetTextMatrix(Object args[], int numArgs) { state->setTextMat(args[0].getNum(), args[1].getNum(), args[2].getNum(), args[3].getNum(), args[4].getNum(), args[5].getNum()); state->textMoveTo(0, 0); out->updateTextMat(state); out->updateTextPos(state); fontChanged = gTrue; } void Gfx::opTextNextLine(Object args[], int numArgs) { fouble tx, ty; tx = state->getLineX(); ty = state->getLineY() - state->getLeading(); state->textMoveTo(tx, ty); out->updateTextPos(state); } //------------------------------------------------------------------------ // text string operators //------------------------------------------------------------------------ void Gfx::opShowText(Object args[], int numArgs) { if (!state->getFont()) { error(getPos(), "No font in show"); return; } doShowText(args[0].getString()); } void Gfx::opMoveShowText(Object args[], int numArgs) { fouble tx, ty; if (!state->getFont()) { error(getPos(), "No font in move/show"); return; } tx = state->getLineX(); ty = state->getLineY() - state->getLeading(); state->textMoveTo(tx, ty); out->updateTextPos(state); 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; GBool haveMask; int maskColors[2*gfxColorMaxComps]; Object obj1, obj2; int i; // get stream dict dict = str->getDict(); // get size dict->lookup("Width", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("W", &obj1); } if (!obj1.isInt()) goto err2; width = obj1.getInt(); obj1.free(); dict->lookup("Height", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("H", &obj1); } if (!obj1.isInt()) goto err2; height = obj1.getInt(); obj1.free(); // image or mask? dict->lookup("ImageMask", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("IM", &obj1); } mask = gFalse; if (obj1.isBool()) mask = obj1.getBool(); else if (!obj1.isNull()) goto err2; obj1.free(); // bit depth dict->lookup("BitsPerComponent", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("BPC", &obj1); } if (!obj1.isInt()) goto err2; bits = obj1.getInt(); obj1.free(); // display a mask if (mask) { // check for inverted mask if (bits != 1) goto err1; invert = gFalse; dict->lookup("Decode", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("D", &obj1); } if (obj1.isArray()) { obj1.arrayGet(0, &obj2); if (obj2.isInt() && obj2.getInt() == 1) invert = gTrue; obj2.free(); } else if (!obj1.isNull()) { goto err2; } obj1.free(); // draw it out->drawImageMask(state, ref, str, width, height, invert, inlineImg); } else { // get color space and color map dict->lookup("ColorSpace", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("CS", &obj1); } if (obj1.isName()) { res->lookupColorSpace(obj1.getName(), &obj2); if (!obj2.isNull()) { obj1.free(); obj1 = obj2; } else { obj2.free(); } } colorSpace = GfxColorSpace::parse(&obj1); obj1.free(); if (!colorSpace) { goto err1; } dict->lookup("Decode", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("D", &obj1); } colorMap = new GfxImageColorMap(bits, &obj1, colorSpace); obj1.free(); if (!colorMap->isOk()) { 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"); } obj1.free(); // get bounding box dict->lookup("BBox", &bboxObj); if (!bboxObj.isArray()) { matrixObj.free(); 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 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); printf("\n"); fflush(stdout); } } void Gfx::opEndMarkedContent(Object args[], int numArgs) { } void Gfx::opMarkPoint(Object args[], int numArgs) { if (printCommands) { printf(" mark point: %s ", args[0].getName()); if (numArgs == 2) args[2].print(stdout); printf("\n"); fflush(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,240 +1,252 @@ //======================================================================== // // 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 }; #define maxArgs 8 struct Operator { char name[4]; int numArgs; TchkType tchk[maxArgs]; void (Gfx::*func)(Object args[], int numArgs); }; class GfxResources { public: GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA); ~GfxResources(); GfxFont *lookupFont(char *name); GBool lookupXObject(char *name, Object *obj); GBool lookupXObjectNF(char *name, Object *obj); void lookupColorSpace(char *name, Object *obj); GfxPattern *lookupPattern(char *name); GfxShading *lookupShading(char *name); GBool lookupGState(char *name, Object *obj); GfxResources *getNext() { return next; } 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); void opSetLineJoin(Object args[], int numArgs); void opSetLineCap(Object args[], int numArgs); void opSetMiterLimit(Object args[], int numArgs); void opSetLineWidth(Object args[], int numArgs); void opSetExtGState(Object args[], int numArgs); void opSetRenderingIntent(Object args[], int numArgs); // color operators void opSetFillGray(Object args[], int numArgs); void opSetStrokeGray(Object args[], int numArgs); void opSetFillCMYKColor(Object args[], int numArgs); void opSetStrokeCMYKColor(Object args[], int numArgs); void opSetFillRGBColor(Object args[], int numArgs); void opSetStrokeRGBColor(Object args[], int numArgs); void opSetFillColorSpace(Object args[], int numArgs); void opSetStrokeColorSpace(Object args[], int numArgs); void opSetFillColor(Object args[], int numArgs); void opSetStrokeColor(Object args[], int numArgs); void opSetFillColorN(Object args[], int numArgs); 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); // text string operators void opShowText(Object args[], int numArgs); void opMoveShowText(Object args[], int numArgs); void opMoveSetShowText(Object args[], int numArgs); void opShowSpaceText(Object args[], int numArgs); void doShowText(GString *s); // XObject operators void opXObject(Object args[], int numArgs); void doImage(Object *ref, Stream *str, GBool inlineImg); void doForm(Object *str); void doForm1(Object *str, Dict *resDict, fouble *matrix, fouble *bbox); // in-line image operators void opBeginImage(Object args[], int numArgs); Stream *buildImageStream(); void opImageData(Object args[], int numArgs); void opEndImage(Object args[], int numArgs); // type 3 font operators void opSetCharWidth(Object args[], int numArgs); void opSetCacheDevice(Object args[], int numArgs); // compatibility operators void opBeginIgnoreUndef(Object args[], int numArgs); void opEndIgnoreUndef(Object args[], int numArgs); // marked content operators void opBeginMarkedContent(Object args[], int numArgs); void opEndMarkedContent(Object args[], int numArgs); void opMarkPoint(Object args[], int numArgs); }; #endif 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,101 +1,101 @@ //======================================================================== // // 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" //------------------------------------------------------------------------ struct StdFontMapEntry { char *altName; char *properName; }; static StdFontMapEntry stdFontMap[] = { { "Arial", "Helvetica" }, { "Arial,Bold", "Helvetica-Bold" }, { "Arial,BoldItalic", "Helvetica-BoldOblique" }, { "Arial,Italic", "Helvetica-Oblique" }, { "Arial-Bold", "Helvetica-Bold" }, { "Arial-BoldItalic", "Helvetica-BoldOblique" }, { "Arial-BoldItalicMT", "Helvetica-BoldOblique" }, { "Arial-BoldMT", "Helvetica-Bold" }, { "Arial-Italic", "Helvetica-Oblique" }, { "Arial-ItalicMT", "Helvetica-Oblique" }, { "ArialMT", "Helvetica" }, { "Courier,Bold", "Courier-Bold" }, { "Courier,Italic", "Courier-Oblique" }, { "Courier,BoldItalic", "Courier-BoldOblique" }, { "CourierNew", "Courier" }, { "CourierNew,Bold", "Courier-Bold" }, { "CourierNew,BoldItalic", "Courier-BoldOblique" }, { "CourierNew,Italic", "Courier-Oblique" }, { "CourierNew-Bold", "Courier-Bold" }, { "CourierNew-BoldItalic", "Courier-BoldOblique" }, { "CourierNew-Italic", "Courier-Oblique" }, { "CourierNewPS-BoldItalicMT", "Courier-BoldOblique" }, { "CourierNewPS-BoldMT", "Courier-Bold" }, { "CourierNewPS-ItalicMT", "Courier-Oblique" }, { "CourierNewPSMT", "Courier" }, { "Helvetica,Bold", "Helvetica-Bold" }, { "Helvetica,BoldItalic", "Helvetica-BoldOblique" }, { "Helvetica,Italic", "Helvetica-Oblique" }, { "Helvetica-BoldItalic", "Helvetica-BoldOblique" }, { "Helvetica-Italic", "Helvetica-Oblique" }, { "TimesNewRoman", "Times-Roman" }, { "TimesNewRoman,Bold", "Times-Bold" }, { "TimesNewRoman,BoldItalic", "Times-BoldItalic" }, { "TimesNewRoman,Italic", "Times-Italic" }, { "TimesNewRoman-Bold", "Times-Bold" }, { "TimesNewRoman-BoldItalic", "Times-BoldItalic" }, { "TimesNewRoman-Italic", "Times-Italic" }, { "TimesNewRomanPS", "Times-Roman" }, { "TimesNewRomanPS-Bold", "Times-Bold" }, { "TimesNewRomanPS-BoldItalic", "Times-BoldItalic" }, { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" }, { "TimesNewRomanPS-BoldMT", "Times-Bold" }, { "TimesNewRomanPS-Italic", "Times-Italic" }, { "TimesNewRomanPS-ItalicMT", "Times-Italic" }, { "TimesNewRomanPSMT", "Times-Roman" } }; //------------------------------------------------------------------------ // GfxFont //------------------------------------------------------------------------ GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) { GString *nameA; GfxFont *font; Object obj1; // get base font name nameA = NULL; fontDict->lookup("BaseFont", &obj1); if (obj1.isName()) { nameA = new GString(obj1.getName()); } obj1.free(); @@ -361,518 +361,554 @@ char *GfxFont::readEmbFontFile(XRef *xref, int *len) { return buf; } //------------------------------------------------------------------------ // Gfx8BitFont //------------------------------------------------------------------------ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Dict *fontDict): GfxFont(tagA, idA, nameA) { BuiltinFont *builtinFont; char **baseEnc; GBool baseEncFromFontFile; char *buf; int len; FontFile *fontFile; int code, code2; char *charName; GBool missing, hex; Unicode toUnicode[256]; fouble mul; int firstChar, lastChar; Gushort w; Object obj1, obj2, obj3; int n, i, a, b, m; type = typeA; ctu = NULL; // Acrobat 4.0 and earlier substituted Base14-compatible fonts // without providing Widths and a FontDescriptor, so we munge the // names into the proper Base14 names. (This table is from // implementation note 44 in the PDF 1.4 spec.) if (name) { a = 0; b = sizeof(stdFontMap) / sizeof(StdFontMapEntry); // invariant: stdFontMap[a].altName <= name < stdFontMap[b].altName while (b - a > 1) { m = (a + b) / 2; if (name->cmp(stdFontMap[m].altName) >= 0) { a = m; } else { b = m; } } if (!name->cmp(stdFontMap[a].altName)) { delete name; name = new GString(stdFontMap[a].properName); } } // is it a built-in font? builtinFont = NULL; if (name) { for (i = 0; i < nBuiltinFonts; ++i) { if (!name->cmp(builtinFonts[i].name)) { builtinFont = &builtinFonts[i]; break; } } } // default ascent/descent values if (builtinFont) { ascent = 0.001 * builtinFont->ascent; descent = 0.001 * builtinFont->descent; fontBBox[0] = 0.001 * builtinFont->bbox[0]; fontBBox[1] = 0.001 * builtinFont->bbox[1]; fontBBox[2] = 0.001 * builtinFont->bbox[2]; fontBBox[3] = 0.001 * builtinFont->bbox[3]; } else { 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")) { hasEncoding = gTrue; baseEnc = macRomanEncoding; } else if (obj2.isName("MacExpertEncoding")) { hasEncoding = gTrue; baseEnc = macExpertEncoding; } else if (obj2.isName("WinAnsiEncoding")) { hasEncoding = gTrue; baseEnc = winAnsiEncoding; } else if (obj2.isName("StandardEncoding")) { hasEncoding = gTrue; baseEnc = standardEncoding; } obj2.free(); } else if (obj1.isName("MacRomanEncoding")) { hasEncoding = gTrue; baseEnc = macRomanEncoding; } else if (obj1.isName("MacExpertEncoding")) { hasEncoding = gTrue; baseEnc = macExpertEncoding; } else if (obj1.isName("WinAnsiEncoding")) { hasEncoding = gTrue; baseEnc = winAnsiEncoding; } else if (obj1.isName("StandardEncoding")) { hasEncoding = gTrue; baseEnc = standardEncoding; } // check embedded or external font file for base encoding + // (only for Type 1 fonts - trying to get an encoding out of a + // TrueType font is a losing proposition) fontFile = NULL; buf = NULL; - if ((type == fontType1 || type == fontType1C || 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(); if (fontFile) { delete fontFile; } //----- build the mapping to Unicode ----- // look for a ToUnicode CMap if (!(ctu = readToUnicodeCMap(fontDict, 8))) { // no ToUnicode CMap, so use the char names // pass 1: use the name-to-Unicode mapping table missing = hex = gFalse; for (code = 0; code < 256; ++code) { if ((charName = enc[code])) { if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) && strcmp(charName, ".notdef")) { // if it wasn't in the name-to-Unicode table, check for a // name that looks like 'Axx' or 'xx', where 'A' is any letter // and 'xx' is two hex digits if ((strlen(charName) == 3 && isalpha(charName[0]) && isxdigit(charName[1]) && isxdigit(charName[2]) && ((charName[1] >= 'a' && charName[1] <= 'f') || (charName[1] >= 'A' && charName[1] <= 'F') || (charName[2] >= 'a' && charName[2] <= 'f') || (charName[2] >= 'A' && charName[2] <= 'F'))) || (strlen(charName) == 2 && isxdigit(charName[0]) && isxdigit(charName[1]) && ((charName[0] >= 'a' && charName[0] <= 'f') || (charName[0] >= 'A' && charName[0] <= 'F') || (charName[1] >= 'a' && charName[1] <= 'f') || (charName[1] >= 'A' && charName[1] <= 'F')))) { hex = gTrue; } missing = gTrue; } } else { toUnicode[code] = 0; } } // pass 2: try to fill in the missing chars, looking for names of - // the form 'Axx', 'xx', 'Ann', 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; } else if (isSerif()) { i = 8; } else { i = 4; } if (isBold()) { i += 2; } if (isItalic()) { i += 1; } builtinFont = builtinFontSubst[i]; // this is a kludge for broken PDF files that encode char 32 // as .notdef if (builtinFont->widths->getWidth("space", &w)) { widths[32] = 0.001 * w; } for (code = 0; code < 256; ++code) { if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) { widths[code] = 0.001 * w; } } } obj1.free(); ok = gTrue; } Gfx8BitFont::~Gfx8BitFont() { int i; for (i = 0; i < 256; ++i) { if (encFree[i] && enc[i]) { gfree(enc[i]); } } ctu->decRefCnt(); if (charProcs.isDict()) { charProcs.free(); } + if (resources.isDict()) { + resources.free(); + } } 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; ascent = 0.95; descent = -0.35; fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0; cMap = NULL; ctu = NULL; widths.defWidth = 1.0; widths.defHeight = -1.0; widths.defVY = 0.880; widths.exceps = NULL; widths.nExceps = 0; widths.excepsV = NULL; widths.nExcepsV = 0; cidToGID = NULL; cidToGIDLen = 0; // get the descendant font if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) { error(-1, "Missing DescendantFonts entry in Type 0 font"); obj1.free(); goto err1; } if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) { error(-1, "Bad descendant font in Type 0 font"); goto err3; } obj1.free(); desFontDict = desFontDictObj.getDict(); // font type if (!desFontDict->lookup("Subtype", &obj1)) { error(-1, "Missing Subtype entry in Type 0 descendant font"); goto err3; } if (obj1.isName("CIDFontType0")) { type = fontCIDType0; } else if (obj1.isName("CIDFontType2")) { type = fontCIDType2; } else { error(-1, "Unknown Type 0 descendant font type '%s'", obj1.isName() ? obj1.getName() : "???"); goto err3; } obj1.free(); // get info from font descriptor readFontDescriptor(xref, desFontDict); // look for an external font file findExtFontFile(); //----- encoding info ----- // char collection if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) { error(-1, "Missing CIDSystemInfo dictionary in Type 0 descendant font"); goto err3; } obj1.dictLookup("Registry", &obj2); obj1.dictLookup("Ordering", &obj3); if (!obj2.isString() || !obj3.isString()) { error(-1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font"); goto err4; } collection = obj2.getString()->copy()->append('-')->append(obj3.getString()); obj3.free(); obj2.free(); obj1.free(); // look for a ToUnicode CMap if (!(ctu = readToUnicodeCMap(fontDict, 16))) { @@ -1093,155 +1129,159 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, obj1.free(); err2: desFontDictObj.free(); err1:; } GfxCIDFont::~GfxCIDFont() { if (cMap) { cMap->decRefCnt(); } if (ctu) { ctu->decRefCnt(); } gfree(widths.exceps); gfree(widths.excepsV); if (cidToGID) { gfree(cidToGID); } } int GfxCIDFont::getNextChar(char *s, int len, CharCode *code, Unicode *u, int uSize, int *uLen, fouble *dx, fouble *dy, fouble *ox, fouble *oy) { CID cid; fouble w, h, vx, vy; int n, a, b, m; if (!cMap) { *code = 0; *uLen = 0; *dx = *dy = 0; return 1; } *code = (CharCode)(cid = cMap->getCID(s, len, &n)); if (ctu) { *uLen = ctu->mapToUnicode(cid, u, uSize); } else { *uLen = 0; } // horizontal if (cMap->getWMode() == 0) { w = widths.defWidth; h = vx = vy = 0; if (widths.nExceps > 0 && cid >= widths.exceps[0].first) { a = 0; b = widths.nExceps; // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first while (b - a > 1) { m = (a + b) / 2; if (widths.exceps[m].first <= cid) { a = m; } else { b = m; } } if (cid <= widths.exceps[a].last) { w = widths.exceps[a].width; } } // vertical } else { w = 0; h = widths.defHeight; vx = widths.defWidth / 2; vy = widths.defVY; if (widths.nExcepsV > 0 && cid >= widths.excepsV[0].first) { a = 0; b = widths.nExcepsV; // invariant: widths.excepsV[a].first <= cid < widths.excepsV[b].first while (b - a > 1) { m = (a + b) / 2; if (widths.excepsV[m].last <= cid) { a = m; } else { b = m; } } if (cid <= widths.excepsV[a].last) { h = widths.excepsV[a].height; vx = widths.excepsV[a].vx; vy = widths.excepsV[a].vy; } } } *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]; } } return NULL; } 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,286 +1,298 @@ //======================================================================== // // 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 //------------------------------------------------------------------------ enum GfxFontType { //----- Gfx8BitFont fontUnknownType, fontType1, fontType1C, fontType3, fontTrueType, //----- GfxCIDFont fontCIDType0, fontCIDType0C, fontCIDType2 }; //------------------------------------------------------------------------ // GfxFontCIDWidths //------------------------------------------------------------------------ struct GfxFontCIDWidthExcep { CID first; // this record applies to CID last; // CIDs <first>..<last> fouble width; // char width }; struct GfxFontCIDWidthExcepV { CID first; // this record applies to CID last; // CIDs <first>..<last> fouble height; // char height fouble vx, vy; // origin position }; struct GfxFontCIDWidths { fouble defWidth; // default char width fouble defHeight; // default char height fouble defVY; // default origin position GfxFontCIDWidthExcep *exceps; // exceptions int nExceps; // number of valid entries in exceps GfxFontCIDWidthExcepV * // exceptions for vertical font excepsV; int nExcepsV; // number of valid entries in excepsV }; //------------------------------------------------------------------------ // GfxFont //------------------------------------------------------------------------ #define fontFixedWidth (1 << 0) #define fontSerif (1 << 1) #define fontSymbolic (1 << 2) #define fontItalic (1 << 6) #define fontBold (1 << 18) class GfxFont { public: // Build a GfxFont object. static GfxFont *makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict); GfxFont(char *tagA, Ref idA, GString *nameA); virtual ~GfxFont(); GBool isOk() { return ok; } // Get font tag. GString *getTag() { return tag; } // Get font dictionary ID. Ref *getID() { return &id; } // 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 //------------------------------------------------------------------------ class GfxFontDict { public: // Build the font dictionary, given the PDF font dictionary. GfxFontDict(XRef *xref, Dict *fontDict); // Destructor. ~GfxFontDict(); // Get the specified font. GfxFont *lookup(char *tag); // Iterative access. int getNumFonts() { return numFonts; } GfxFont *getFont(int i) { return fonts[i]; } private: GfxFont **fonts; // list of fonts int numFonts; // number of fonts }; #endif 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,101 +1,101 @@ //======================================================================== // // 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); } //------------------------------------------------------------------------ // GfxColorSpace //------------------------------------------------------------------------ GfxColorSpace::GfxColorSpace() { } GfxColorSpace::~GfxColorSpace() { } GfxColorSpace *GfxColorSpace::parse(Object *csObj) { GfxColorSpace *cs; Object obj1; cs = NULL; if (csObj->isName()) { if (csObj->isName("DeviceGray") || csObj->isName("G")) { cs = new GfxDeviceGrayColorSpace(); } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) { cs = new GfxDeviceRGBColorSpace(); } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) { cs = new GfxDeviceCMYKColorSpace(); } else if (csObj->isName("Pattern")) { cs = new GfxPatternColorSpace(NULL); } else { error(-1, "Bad color space '%s'", csObj->getName()); } } else if (csObj->isArray()) { csObj->arrayGet(0, &obj1); if (obj1.isName("DeviceGray") || obj1.isName("G")) { cs = new GfxDeviceGrayColorSpace(); } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) { cs = new GfxDeviceRGBColorSpace(); } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) { cs = new GfxDeviceCMYKColorSpace(); } else if (obj1.isName("CalGray")) { cs = GfxCalGrayColorSpace::parse(csObj->getArray()); } else if (obj1.isName("CalRGB")) { cs = GfxCalRGBColorSpace::parse(csObj->getArray()); } else if (obj1.isName("Lab")) { cs = GfxLabColorSpace::parse(csObj->getArray()); } else if (obj1.isName("ICCBased")) { cs = GfxICCBasedColorSpace::parse(csObj->getArray()); } else if (obj1.isName("Indexed") || obj1.isName("I")) { cs = GfxIndexedColorSpace::parse(csObj->getArray()); } else if (obj1.isName("Separation")) { cs = GfxSeparationColorSpace::parse(csObj->getArray()); } else if (obj1.isName("DeviceN")) { cs = GfxDeviceNColorSpace::parse(csObj->getArray()); } else if (obj1.isName("Pattern")) { cs = GfxPatternColorSpace::parse(csObj->getArray()); } else { error(-1, "Bad color space '%s'", csObj->getName()); } obj1.free(); } else { error(-1, "Bad color space - expected name or array"); } return cs; } void GfxColorSpace::getDefaultRanges(fouble *decodeLow, fouble *decodeRange, int maxImgPixel) { int i; for (i = 0; i < getNComps(); ++i) { decodeLow[i] = 0; decodeRange[i] = 1; } } //------------------------------------------------------------------------ @@ -315,195 +315,208 @@ GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) { cs->whiteZ = obj3.getNum(); obj3.free(); } obj2.free(); if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && obj2.arrayGetLength() == 3) { obj2.arrayGet(0, &obj3); cs->blackX = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->blackY = obj3.getNum(); obj3.free(); obj2.arrayGet(2, &obj3); cs->blackZ = obj3.getNum(); obj3.free(); } obj2.free(); if (obj1.dictLookup("Gamma", &obj2)->isArray() && obj2.arrayGetLength() == 3) { obj2.arrayGet(0, &obj3); cs->gammaR = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->gammaG = obj3.getNum(); obj3.free(); obj2.arrayGet(2, &obj3); cs->gammaB = obj3.getNum(); obj3.free(); } obj2.free(); if (obj1.dictLookup("Matrix", &obj2)->isArray() && obj2.arrayGetLength() == 9) { for (i = 0; i < 9; ++i) { obj2.arrayGet(i, &obj3); cs->mat[i] = obj3.getNum(); obj3.free(); } } obj2.free(); obj1.free(); return cs; } void GfxCalRGBColorSpace::getGray(GfxColor *color, fouble *gray) { *gray = clip01(0.299 * color->c[0] + 0.587 * color->c[1] + 0.114 * color->c[2]); } void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { rgb->r = clip01(color->c[0]); rgb->g = clip01(color->c[1]); rgb->b = clip01(color->c[2]); } void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { fouble c, m, y, k; c = clip01(1 - color->c[0]); m = clip01(1 - color->c[1]); y = clip01(1 - color->c[2]); k = c; if (m < k) { k = m; } if (y < k) { k = y; } cmyk->c = c - k; cmyk->m = m - k; cmyk->y = y - k; cmyk->k = k; } //------------------------------------------------------------------------ // 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; aMin = bMin = -100; aMax = bMax = 100; } GfxLabColorSpace::~GfxLabColorSpace() { } GfxColorSpace *GfxLabColorSpace::copy() { GfxLabColorSpace *cs; cs = new GfxLabColorSpace(); cs->whiteX = whiteX; cs->whiteY = whiteY; cs->whiteZ = whiteZ; cs->blackX = blackX; cs->blackY = blackY; cs->blackZ = blackZ; cs->aMin = aMin; cs->aMax = aMax; cs->bMin = bMin; cs->bMax = bMax; cs->kr = kr; cs->kg = kg; cs->kb = kb; return cs; } GfxColorSpace *GfxLabColorSpace::parse(Array *arr) { GfxLabColorSpace *cs; Object obj1, obj2, obj3; arr->get(1, &obj1); if (!obj1.isDict()) { error(-1, "Bad Lab color space"); obj1.free(); return NULL; } cs = new GfxLabColorSpace(); if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && obj2.arrayGetLength() == 3) { obj2.arrayGet(0, &obj3); cs->whiteX = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->whiteY = obj3.getNum(); obj3.free(); obj2.arrayGet(2, &obj3); cs->whiteZ = obj3.getNum(); obj3.free(); } obj2.free(); if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && obj2.arrayGetLength() == 3) { obj2.arrayGet(0, &obj3); cs->blackX = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->blackY = obj3.getNum(); obj3.free(); obj2.arrayGet(2, &obj3); cs->blackZ = obj3.getNum(); obj3.free(); } obj2.free(); if (obj1.dictLookup("Range", &obj2)->isArray() && obj2.arrayGetLength() == 4) { obj2.arrayGet(0, &obj3); cs->aMin = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->aMax = obj3.getNum(); obj3.free(); @@ -1175,381 +1188,509 @@ GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream): if (streamDict->lookup("BBox", &obj1)->isArray() && obj1.arrayGetLength() == 4) { for (i = 0; i < 4; ++i) { if (obj1.arrayGet(i, &obj2)->isNum()) { bbox[i] = obj2.getNum(); } obj2.free(); } } else { error(-1, "Invalid or missing BBox in pattern"); } obj1.free(); if (streamDict->lookup("XStep", &obj1)->isNum()) { xStep = obj1.getNum(); } else { xStep = 1; error(-1, "Invalid or missing XStep in pattern"); } obj1.free(); if (streamDict->lookup("YStep", &obj1)->isNum()) { yStep = obj1.getNum(); } else { yStep = 1; error(-1, "Invalid or missing YStep in pattern"); } obj1.free(); if (!streamDict->lookup("Resources", &resDict)->isDict()) { resDict.free(); resDict.initNull(); error(-1, "Invalid or missing Resources in pattern"); } matrix[0] = 1; matrix[1] = 0; matrix[2] = 0; matrix[3] = 1; matrix[4] = 0; matrix[5] = 0; if (streamDict->lookup("Matrix", &obj1)->isArray() && obj1.arrayGetLength() == 6) { for (i = 0; i < 6; ++i) { if (obj1.arrayGet(i, &obj2)->isNum()) { matrix[i] = obj2.getNum(); } obj2.free(); } } obj1.free(); stream->copy(&contentStream); } GfxTilingPattern::~GfxTilingPattern() { resDict.free(); contentStream.free(); } GfxPattern *GfxTilingPattern::copy() { return new GfxTilingPattern(this); } GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat): GfxPattern(1) { memcpy(this, pat, sizeof(GfxTilingPattern)); pat->resDict.copy(&resDict); pat->contentStream.copy(&contentStream); } //------------------------------------------------------------------------ // GfxShading //------------------------------------------------------------------------ GfxShading::GfxShading() { } 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 //------------------------------------------------------------------------ GfxAxialShading::GfxAxialShading(fouble x0A, fouble y0A, fouble x1A, fouble y1A, fouble t0A, fouble t1A, Function **funcsA, int nFuncsA, GBool extend0A, GBool extend1A) { int i; x0 = x0A; y0 = y0A; x1 = x1A; y1 = y1A; t0 = t0A; t1 = t1A; nFuncs = nFuncsA; for (i = 0; i < nFuncs; ++i) { funcs[i] = funcsA[i]; } extend0 = extend0A; extend1 = extend1A; } GfxAxialShading::~GfxAxialShading() { int i; for (i = 0; i < nFuncs; ++i) { delete funcs[i]; } } GfxAxialShading *GfxAxialShading::parse(Dict *dict) { fouble x0A, y0A, x1A, y1A; fouble t0A, t1A; Function *funcsA[gfxColorMaxComps]; int nFuncsA; GBool extend0A, extend1A; Object obj1, obj2; int i; x0A = y0A = x1A = y1A = 0; if (dict->lookup("Coords", &obj1)->isArray() && obj1.arrayGetLength() == 4) { x0A = obj1.arrayGet(0, &obj2)->getNum(); obj2.free(); y0A = obj1.arrayGet(1, &obj2)->getNum(); obj2.free(); x1A = obj1.arrayGet(2, &obj2)->getNum(); obj2.free(); y1A = obj1.arrayGet(3, &obj2)->getNum(); obj2.free(); } else { error(-1, "Missing or invalid Coords in shading dictionary"); goto err1; } obj1.free(); 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 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()) { nComps = colorSpace->getNComps(); colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel); } else if (decode->isArray()) { nComps = decode->arrayGetLength() / 2; if (nComps != colorSpace->getNComps()) { goto err1; } for (i = 0; i < nComps; ++i) { decode->arrayGet(2*i, &obj); if (!obj.isNum()) { goto err2; } decodeLow[i] = obj.getNum(); obj.free(); decode->arrayGet(2*i+1, &obj); if (!obj.isNum()) { goto err2; } decodeRange[i] = obj.getNum() - decodeLow[i]; obj.free(); } } else { goto err1; } // Construct a lookup table -- this stores pre-computed decoded // values for each component, i.e., the result of applying the // decode mapping to each possible image pixel component value. // // Optimization: for Indexed and Separation color spaces (which have // only one component), we store color values in the lookup table // rather than component values. colorSpace2 = NULL; nComps2 = 0; if (colorSpace->getMode() == csIndexed) { // Note that indexHigh may not be the same as maxPixel -- // Distiller will remove unused palette entries, resulting in // indexHigh < maxPixel. indexedCS = (GfxIndexedColorSpace *)colorSpace; colorSpace2 = indexedCS->getBase(); indexHigh = indexedCS->getIndexHigh(); nComps2 = colorSpace2->getNComps(); lookup = (fouble *)gmalloc((indexHigh + 1) * nComps2 * sizeof(fouble)); lookup2 = indexedCS->getLookup(); for (i = 0; i <= indexHigh; ++i) { j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5); for (k = 0; k < nComps2; ++k) { lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0; } } } else if (colorSpace->getMode() == csSeparation) { sepCS = (GfxSeparationColorSpace *)colorSpace; colorSpace2 = sepCS->getAlt(); nComps2 = colorSpace2->getNComps(); lookup = (fouble *)gmalloc((maxPixel + 1) * nComps2 * sizeof(fouble)); sepFunc = sepCS->getFunc(); for (i = 0; i <= maxPixel; ++i) { x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel; sepFunc->transform(x, y); for (k = 0; k < nComps2; ++k) { lookup[i*nComps2 + k] = y[k]; } } } else { lookup = (fouble *)gmalloc((maxPixel + 1) * nComps * sizeof(fouble)); for (i = 0; i <= maxPixel; ++i) { for (k = 0; k < nComps; ++k) { lookup[i*nComps + k] = decodeLow[k] + (i * decodeRange[k]) / maxPixel; } } } @@ -1825,273 +1966,356 @@ GfxState::GfxState(fouble dpi, PDFRectangle *pageBox, int rotate, ctm[1] = 0; ctm[2] = 0; ctm[3] = upsideDown ? -k : k; ctm[4] = -k * px1; ctm[5] = k * (upsideDown ? py2 : -py1); pageWidth = k * (px2 - px1); pageHeight = k * (py2 - py1); } fillColorSpace = new GfxDeviceGrayColorSpace(); strokeColorSpace = new GfxDeviceGrayColorSpace(); fillColor.c[0] = 0; strokeColor.c[0] = 0; fillPattern = NULL; strokePattern = NULL; fillOpacity = 1; strokeOpacity = 1; lineWidth = 1; lineDash = NULL; lineDashLength = 0; lineDashStart = 0; flatness = 0; lineJoin = 0; lineCap = 0; miterLimit = 10; font = NULL; fontSize = 0; textMat[0] = 1; textMat[1] = 0; textMat[2] = 0; textMat[3] = 1; textMat[4] = 0; textMat[5] = 0; charSpace = 0; wordSpace = 0; horizScaling = 1; leading = 0; rise = 0; render = 0; path = new GfxPath(); curX = curY = 0; lineX = lineY = 0; clipXMin = 0; clipYMin = 0; clipXMax = pageWidth; clipYMax = pageHeight; saved = NULL; } GfxState::~GfxState() { if (fillColorSpace) { delete fillColorSpace; } if (strokeColorSpace) { delete strokeColorSpace; } if (fillPattern) { delete fillPattern; } if (strokePattern) { delete strokePattern; } gfree(lineDash); if (path) { // this gets set to NULL by restore() delete path; } if (saved) { delete saved; } } // 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) { if (strokePattern) { delete strokePattern; } strokePattern = pattern; } void GfxState::setLineDash(fouble *dash, int length, fouble start) { if (lineDash) gfree(lineDash); lineDash = dash; lineDashLength = length; lineDashStart = start; } void GfxState::clearPath() { delete path; path = new GfxPath(); } void GfxState::clip() { fouble xMin, yMin, xMax, yMax, x, y; GfxSubpath *subpath; int i, j; xMin = xMax = yMin = yMax = 0; // make gcc happy for (i = 0; i < path->getNumSubpaths(); ++i) { subpath = path->getSubpath(i); for (j = 0; j < subpath->getNumPoints(); ++j) { transform(subpath->getX(j), subpath->getY(j), &x, &y); if (i == 0 && j == 0) { xMin = xMax = x; yMin = yMax = y; } else { if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } } } } if (xMin > clipXMin) { clipXMin = xMin; } if (yMin > clipYMin) { clipYMin = yMin; } if (xMax < clipXMax) { clipXMax = xMax; } if (yMax < clipYMax) { clipYMax = yMax; } } -void GfxState::textShift(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,101 +1,101 @@ //======================================================================== // // 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 struct GfxColor { fouble c[gfxColorMaxComps]; }; //------------------------------------------------------------------------ // GfxRGB //------------------------------------------------------------------------ struct GfxRGB { fouble r, g, b; }; //------------------------------------------------------------------------ // GfxCMYK //------------------------------------------------------------------------ struct GfxCMYK { fouble c, m, y, k; }; //------------------------------------------------------------------------ // GfxColorSpace //------------------------------------------------------------------------ enum GfxColorSpaceMode { csDeviceGray, csCalGray, csDeviceRGB, csCalRGB, csDeviceCMYK, csLab, csICCBased, csIndexed, csSeparation, csDeviceN, csPattern }; class GfxColorSpace { public: GfxColorSpace(); virtual ~GfxColorSpace(); virtual GfxColorSpace *copy() = 0; virtual GfxColorSpaceMode getMode() = 0; // Construct a color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Object *csObj); // Convert to gray, RGB, or CMYK. virtual void getGray(GfxColor *color, fouble *gray) = 0; virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0; virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0; // Return the number of color components. virtual int getNComps() = 0; // Return the default ranges for each component, assuming an image // with a max pixel value of <maxImgPixel>. virtual void getDefaultRanges(fouble *decodeLow, fouble *decodeRange, int maxImgPixel); private: }; //------------------------------------------------------------------------ // GfxDeviceGrayColorSpace //------------------------------------------------------------------------ class GfxDeviceGrayColorSpace: public GfxColorSpace { public: @@ -475,192 +475,226 @@ private: class GfxTilingPattern: public GfxPattern { public: GfxTilingPattern(Dict *streamDict, Object *stream); virtual ~GfxTilingPattern(); virtual GfxPattern *copy(); int getPaintType() { return paintType; } int getTilingType() { return tilingType; } fouble *getBBox() { return bbox; } fouble getXStep() { return xStep; } fouble getYStep() { return yStep; } Dict *getResDict() { return resDict.isDict() ? resDict.getDict() : (Dict *)NULL; } fouble *getMatrix() { return matrix; } Object *getContentStream() { return &contentStream; } private: GfxTilingPattern(GfxTilingPattern *pat); int paintType; int tilingType; fouble bbox[4]; fouble xStep, yStep; Object resDict; fouble matrix[6]; Object contentStream; }; //------------------------------------------------------------------------ // GfxShading //------------------------------------------------------------------------ class GfxShading { public: GfxShading(); virtual ~GfxShading(); static GfxShading *parse(Object *obj); int getType() { return type; } GfxColorSpace *getColorSpace() { return colorSpace; } GfxColor *getBackground() { return &background; } GBool getHasBackground() { return hasBackground; } void getBBox(fouble *xMinA, fouble *yMinA, fouble *xMaxA, fouble *yMaxA) { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } GBool getHasBBox() { return hasBBox; } private: int type; GfxColorSpace *colorSpace; GfxColor background; GBool hasBackground; fouble xMin, yMin, xMax, yMax; GBool hasBBox; }; //------------------------------------------------------------------------ // GfxAxialShading //------------------------------------------------------------------------ class GfxAxialShading: public GfxShading { public: GfxAxialShading(fouble x0A, fouble y0A, fouble x1A, fouble y1A, fouble t0A, fouble t1A, 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]; } fouble getDecodeHigh(int i) { return decodeLow[i] + decodeRange[i]; } // Convert an image pixel to a color. void getGray(Guchar *x, fouble *gray); void getRGB(Guchar *x, GfxRGB *rgb); void getCMYK(Guchar *x, GfxCMYK *cmyk); private: GfxColorSpace *colorSpace; // the image color space int bits; // bits per component int nComps; // number of components in a pixel GfxColorSpace *colorSpace2; // secondary color space int nComps2; // number of components in colorSpace2 fouble *lookup; // lookup table fouble // minimum values for each component decodeLow[gfxColorMaxComps]; fouble // max - min value for each component decodeRange[gfxColorMaxComps]; GBool ok; }; //------------------------------------------------------------------------ // GfxSubpath and GfxPath //------------------------------------------------------------------------ class GfxSubpath { public: // Constructor. GfxSubpath(fouble x1, fouble y1); // Destructor. ~GfxSubpath(); // Copy. GfxSubpath *copy() { return new GfxSubpath(this); } // Get points. int getNumPoints() { return n; } fouble getX(int i) { return x[i]; } fouble getY(int i) { return y[i]; } GBool getCurve(int i) { return curve[i]; } // Get last point. fouble getLastX() { return x[n-1]; } fouble getLastY() { return y[n-1]; } // Add a line segment. void lineTo(fouble x1, fouble y1); // Add a Bezier curve. void curveTo(fouble x1, fouble y1, fouble x2, fouble y2, fouble x3, fouble y3); // Close the subpath. void close(); GBool isClosed() { return closed; } private: fouble *x, *y; // points GBool *curve; // curve[i] => point i is a control point // for a Bezier curve int n; // number of points int size; // size of x/y arrays GBool closed; // set if path is closed GfxSubpath(GfxSubpath *subpath); }; class GfxPath { @@ -690,233 +724,234 @@ public: fouble getLastX() { return subpaths[n-1]->getLastX(); } fouble getLastY() { return subpaths[n-1]->getLastY(); } // Move the current point. void moveTo(fouble x, fouble y); // Add a segment to the last subpath. void lineTo(fouble x, fouble y); // Add a Bezier curve to the last subpath void curveTo(fouble x1, fouble y1, fouble x2, fouble y2, fouble x3, fouble y3); // Close the last subpath. void close(); private: GBool justMoved; // set if a new subpath was just started fouble firstX, firstY; // first point in new subpath GfxSubpath **subpaths; // subpaths int n; // number of subpaths int size; // size of subpaths array GfxPath(GBool justMoved1, fouble firstX1, fouble firstY1, GfxSubpath **subpaths1, int n1, int size1); }; //------------------------------------------------------------------------ // GfxState //------------------------------------------------------------------------ class GfxState { public: // Construct a default GfxState, for a device with resolution <dpi>, // page box <pageBox>, page rotation <rotate>, and coordinate system // specified by <upsideDown>. GfxState(fouble dpi, PDFRectangle *pageBox, int rotate, GBool upsideDown); // Destructor. ~GfxState(); // Copy. GfxState *copy() { return new GfxState(this); } // Accessors. fouble *getCTM() { return ctm; } fouble getX1() { return px1; } fouble getY1() { return py1; } fouble getX2() { return px2; } fouble getY2() { return py2; } fouble getPageWidth() { return pageWidth; } fouble getPageHeight() { return pageHeight; } GfxColor *getFillColor() { return &fillColor; } GfxColor *getStrokeColor() { return &strokeColor; } void getFillGray(fouble *gray) { fillColorSpace->getGray(&fillColor, gray); } void getStrokeGray(fouble *gray) { strokeColorSpace->getGray(&fillColor, gray); } void getFillRGB(GfxRGB *rgb) { fillColorSpace->getRGB(&fillColor, rgb); } void getStrokeRGB(GfxRGB *rgb) { strokeColorSpace->getRGB(&strokeColor, rgb); } void getFillCMYK(GfxCMYK *cmyk) { fillColorSpace->getCMYK(&fillColor, cmyk); } void getStrokeCMYK(GfxCMYK *cmyk) { strokeColorSpace->getCMYK(&strokeColor, cmyk); } GfxColorSpace *getFillColorSpace() { return fillColorSpace; } GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; } GfxPattern *getFillPattern() { return fillPattern; } 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(); void getFontTransMat(fouble *m11, fouble *m12, fouble *m21, fouble *m22); // Change state parameters. void setCTM(fouble a, fouble b, fouble c, fouble d, fouble e, fouble f); void concatCTM(fouble a, fouble b, fouble c, fouble d, fouble e, fouble f); void setFillColorSpace(GfxColorSpace *colorSpace); void setStrokeColorSpace(GfxColorSpace *colorSpace); void setFillColor(GfxColor *color) { fillColor = *color; } void setStrokeColor(GfxColor *color) { strokeColor = *color; } void setFillPattern(GfxPattern *pattern); void setStrokePattern(GfxPattern *pattern); void setFillOpacity(fouble opac) { fillOpacity = opac; } void setStrokeOpacity(fouble opac) { strokeOpacity = opac; } void setLineWidth(fouble width) { lineWidth = width; } void setLineDash(fouble *dash, int length, fouble start); void setFlatness(int flatness1) { flatness = flatness1; } void setLineJoin(int lineJoin1) { lineJoin = lineJoin1; } void setLineCap(int lineCap1) { lineCap = lineCap1; } void setMiterLimit(fouble limit) { miterLimit = limit; } void setFont(GfxFont *fontA, fouble fontSizeA) { font = fontA; fontSize = fontSizeA; } void setTextMat(fouble a, fouble b, fouble c, fouble d, fouble e, fouble f) { textMat[0] = a; textMat[1] = b; textMat[2] = c; textMat[3] = d; textMat[4] = e; textMat[5] = f; } void setCharSpace(fouble space) { charSpace = space; } void setWordSpace(fouble space) { wordSpace = space; } void setHorizScaling(fouble scale) { horizScaling = 0.01 * scale; } void setLeading(fouble leadingA) { 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 int lineDashLength; fouble lineDashStart; int flatness; // curve flatness int lineJoin; // line join style int lineCap; // line cap style fouble miterLimit; // line miter limit GfxFont *font; // font fouble fontSize; // font size fouble textMat[6]; // text matrix fouble charSpace; // character spacing fouble wordSpace; // word spacing fouble horizScaling; // horizontal scaling fouble leading; // text leading fouble rise; // text rise int render; // text rendering mode GfxPath *path; // array of path elements fouble curX, curY; // current point (user coords) fouble lineX, lineY; // start of current text line (text coords) fouble clipXMin, clipYMin, // bounding box for clip region clipXMax, clipYMax; GfxState *saved; // next GfxState on stack GfxState(GfxState *state); }; #endif 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,916 +1,1065 @@ //======================================================================== // // 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" #include "FontEncodingTables.h" #include "GlobalParams.h" #include "NameToUnicodeTable.h" #include "UnicodeMapTables.h" #include "DisplayFontTable.h" #include "UTF8.h" //------------------------------------------------------------------------ GlobalParams *globalParams = NULL; //------------------------------------------------------------------------ // DisplayFontParam //------------------------------------------------------------------------ DisplayFontParam::DisplayFontParam(GString *nameA, DisplayFontParamKind kindA) { name = nameA; kind = kindA; switch (kind) { case displayFontX: x.xlfd = NULL; x.encoding = NULL; break; case displayFontT1: t1.fileName = NULL; break; case displayFontTT: tt.fileName = NULL; break; } } DisplayFontParam::DisplayFontParam(char *nameA, char *xlfdA, char *encodingA) { name = new GString(nameA); kind = displayFontX; x.xlfd = new GString(xlfdA); x.encoding = new GString(encodingA); } DisplayFontParam::~DisplayFontParam() { delete name; switch (kind) { case displayFontX: 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; while (fgets(buf, sizeof(buf), f)) { tok1 = strtok(buf, " \t\r\n"); tok2 = strtok(NULL, " \t\r\n"); if (tok1 && tok2) { sscanf(tok1, "%x", &u); nameToUnicode->add(tok2, u); } else { error(-1, "Bad line in 'nameToUnicode' file (%s:%d)", name, line2); } ++line2; } fclose(f); } void GlobalParams::parseCIDToUnicode(GList *tokens, GString *fileName, int line) { GString *collection, *name, *old; if (tokens->getLength() != 3) { error(-1, "Bad 'cidToUnicode' config file command (%s:%d)", fileName->getCString(), line); return; } collection = (GString *)tokens->get(1); name = (GString *)tokens->get(2); if ((old = (GString *)cidToUnicodes->remove(collection))) { delete old; } cidToUnicodes->add(collection->copy(), name->copy()); } void GlobalParams::parseUnicodeMap(GList *tokens, GString *fileName, int line) { GString *encodingName, *name, *old; if (tokens->getLength() != 3) { error(-1, "Bad 'unicodeMap' config file command (%s:%d)", fileName->getCString(), line); return; } encodingName = (GString *)tokens->get(1); name = (GString *)tokens->get(2); if ((old = (GString *)unicodeMaps->remove(encodingName))) { delete old; } unicodeMaps->add(encodingName->copy(), name->copy()); } void GlobalParams::parseCMapDir(GList *tokens, GString *fileName, int line) { GString *collection, *dir; GList *list; 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) { return nameToUnicode->lookup(charName); } FILE *GlobalParams::getCIDToUnicodeFile(GString *collection) { GString *fileName; if (!(fileName = (GString *)cidToUnicodes->lookup(collection))) { return NULL; } return fopen(fileName->getCString(), "r"); } UnicodeMap *GlobalParams::getResidentUnicodeMap(GString *encodingName) { return (UnicodeMap *)residentUnicodeMaps->lookup(encodingName); } FILE *GlobalParams::getUnicodeMapFile(GString *encodingName) { GString *fileName; if (!(fileName = (GString *)unicodeMaps->lookup(encodingName))) { return NULL; } return fopen(fileName->getCString(), "r"); } FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) { GList *list; GString *dir; GString *fileName; FILE *f; int i; if (!(list = (GList *)cMapDirs->lookup(collection))) { return NULL; } for (i = 0; i < list->getLength(); ++i) { dir = (GString *)list->get(i); fileName = appendToPath(dir->copy(), cMapName->getCString()); f = fopen(fileName->getCString(), "r"); delete fileName; if (f) { return f; } } 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; } delete fileName; } } return NULL; } CharCodeToUnicode *GlobalParams::getCIDToUnicode(GString *collection) { return cidToUnicodeCache->getCIDToUnicode(collection); } UnicodeMap *GlobalParams::getUnicodeMap(GString *encodingName) { UnicodeMap *map; if ((map = getResidentUnicodeMap(encodingName))) { map->incRefCnt(); return map; } return unicodeMapCache->getUnicodeMap(encodingName); } CMap *GlobalParams::getCMap(GString *collection, GString *cMapName) { return cMapCache->getCMap(collection, cMapName); } UnicodeMap *GlobalParams::getTextEncoding() { return getUnicodeMap(textEncoding); } //------------------------------------------------------------------------ // functions to set parameters //------------------------------------------------------------------------ void GlobalParams::setPSFile(char *file) { if (psFile) { delete psFile; } psFile = new GString(file); } GBool GlobalParams::setPSPaperSize(char *size) { if (!strcmp(size, "letter")) { psPaperWidth = 612; psPaperHeight = 792; } else if (!strcmp(size, "legal")) { psPaperWidth = 612; psPaperHeight = 1008; } else if (!strcmp(size, "A4")) { psPaperWidth = 595; psPaperHeight = 842; } else if (!strcmp(size, "A3")) { psPaperWidth = 842; psPaperHeight = 1190; } else { return gFalse; } return gTrue; } 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) { errQuiet = 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,101 +1,101 @@ //======================================================================== // // 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 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 }; //------------------------------------------------------------------------ // Lexer //------------------------------------------------------------------------ Lexer::Lexer(XRef *xref, Stream *str) { Object obj; curStr.initStream(str); streams = new Array(xref); streams->add(curStr.copy(&obj)); strPtr = 0; freeArray = gTrue; curStr.streamReset(); } Lexer::Lexer(XRef *xref, Object *obj) { Object obj2; if (obj->isStream()) { streams = new Array(xref); freeArray = gTrue; streams->add(obj->copy(&obj2)); } else { streams = obj->getArray(); freeArray = gFalse; } strPtr = 0; if (streams->getLength() > 0) { streams->get(strPtr, &curStr); curStr.streamReset(); } } Lexer::~Lexer() { if (!curStr.isNone()) { curStr.streamClose(); curStr.free(); } if (freeArray) { delete streams; } } int Lexer::getChar() { int c; c = EOF; while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) { curStr.streamClose(); curStr.free(); ++strPtr; if (strPtr < streams->getLength()) { streams->get(strPtr, &curStr); curStr.streamReset(); } } return c; } 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,634 +1,630 @@ //======================================================================== // // 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(); } else { error(-1, "Bad annotation destination position"); goto err1; } obj2.free(); a->get(4, &obj2); if (obj2.isNull()) { changeZoom = gFalse; } else if (obj2.isNum()) { changeZoom = gTrue; zoom = obj2.getNum(); } else { error(-1, "Bad annotation destination position"); goto err1; } obj2.free(); // Fit link } else if (obj1.isName("Fit")) { kind = destFit; // FitH link } else if (obj1.isName("FitH")) { kind = destFitH; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); goto err1; } top = obj2.getNum(); obj2.free(); // FitV link } else if (obj1.isName("FitV")) { kind = destFitV; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); goto err1; } left = obj2.getNum(); obj2.free(); // FitR link } else if (obj1.isName("FitR")) { kind = destFitR; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); goto err1; } left = obj2.getNum(); obj2.free(); if (!a->get(3, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); goto err1; } bottom = obj2.getNum(); obj2.free(); if (!a->get(4, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); goto err1; } right = obj2.getNum(); obj2.free(); if (!a->get(5, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); goto err1; } top = obj2.getNum(); obj2.free(); // FitB link } else if (obj1.isName("FitB")) { kind = destFitB; // FitBH link } else if (obj1.isName("FitBH")) { kind = destFitBH; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); goto err1; } top = obj2.getNum(); obj2.free(); // FitBV link } else if (obj1.isName("FitBV")) { kind = destFitBV; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); goto err1; } left = obj2.getNum(); obj2.free(); // unknown link kind } else { error(-1, "Unknown annotation destination type"); goto err2; } obj1.free(); ok = gTrue; return; err1: obj2.free(); err2: obj1.free(); } LinkDest::LinkDest(LinkDest *dest) { kind = dest->kind; pageIsRef = dest->pageIsRef; if (pageIsRef) pageRef = dest->pageRef; else pageNum = dest->pageNum; left = dest->left; bottom = dest->bottom; right = dest->right; 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 //------------------------------------------------------------------------ LinkLaunch::LinkLaunch(Object *actionObj) { Object obj1, obj2; fileName = NULL; params = NULL; if (actionObj->isDict()) { if (!actionObj->dictLookup("F", &obj1)->isNull()) { fileName = getFileSpecName(&obj1); } else { obj1.free(); //~ This hasn't been defined by Adobe yet, so assume it looks //~ just like the Win dictionary until they say otherwise. if (actionObj->dictLookup("Unix", &obj1)->isDict()) { obj1.dictLookup("F", &obj2); fileName = getFileSpecName(&obj2); obj2.free(); if (obj1.dictLookup("P", &obj2)->isString()) params = obj2.getString()->copy(); obj2.free(); } else { error(-1, "Bad launch-type link action"); } } obj1.free(); } } LinkLaunch::~LinkLaunch() { if (fileName) delete fileName; if (params) delete params; } //------------------------------------------------------------------------ // LinkURI //------------------------------------------------------------------------ LinkURI::LinkURI(Object *uriObj, GString *baseURI) { GString *uri2; int n; char c; uri = NULL; if (uriObj->isString()) { uri2 = uriObj->getString()->copy(); if (baseURI) { n = strcspn(uri2->getCString(), "/:"); if (n == uri2->getLength() || uri2->getChar(n) == '/') { uri = baseURI->copy(); c = uri->getChar(uri->getLength() - 1); if (c == '/' || c == '?') { if (uri2->getChar(0) == '/') { uri2->del(0); } } else { if (uri2->getChar(0) != '/') { uri->append('/'); } } uri->append(uri2); delete uri2; } else { uri = uri2; } } else { uri = uri2; } } else { error(-1, "Illegal URI-type link"); } } LinkURI::~LinkURI() { if (uri) delete uri; } //------------------------------------------------------------------------ // LinkNamed //------------------------------------------------------------------------ LinkNamed::LinkNamed(Object *nameObj) { name = NULL; if (nameObj->isName()) { name = new GString(nameObj->getName()); } } LinkNamed::~LinkNamed() { if (name) { delete name; } } //------------------------------------------------------------------------ // LinkUnknown //------------------------------------------------------------------------ LinkUnknown::LinkUnknown(char *actionA) { action = new GString(actionA); } LinkUnknown::~LinkUnknown() { delete action; } //------------------------------------------------------------------------ // Link //------------------------------------------------------------------------ Link::Link(Dict *dict, GString *baseURI) { Object obj1, obj2, obj3, obj4; fouble t; action = NULL; ok = gFalse; // get rectangle if (!dict->lookup("Rect", &obj1)->isArray()) { error(-1, "Annotation rectangle is wrong type"); goto err2; } if (!obj1.arrayGet(0, &obj2)->isNum()) { error(-1, "Bad annotation rectangle"); goto err1; } x1 = obj2.getNum(); obj2.free(); if (!obj1.arrayGet(1, &obj2)->isNum()) { error(-1, "Bad annotation rectangle"); goto err1; } y1 = obj2.getNum(); obj2.free(); if (!obj1.arrayGet(2, &obj2)->isNum()) { 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")) { obj1.dictLookup("D", &obj3); action = new LinkGoTo(&obj3); obj3.free(); // GoToR action } else if (obj2.isName("GoToR")) { obj1.dictLookup("F", &obj3); obj1.dictLookup("D", &obj4); action = new LinkGoToR(&obj3, &obj4); obj3.free(); obj4.free(); // Launch action } else if (obj2.isName("Launch")) { action = new LinkLaunch(&obj1); // URI action } else if (obj2.isName("URI")) { obj1.dictLookup("URI", &obj3); action = new LinkURI(&obj3, baseURI); obj3.free(); // Named action } else if (obj2.isName("Named")) { obj1.dictLookup("N", &obj3); action = new LinkNamed(&obj3); obj3.free(); // unknown action } else if (obj2.isName()) { action = new LinkUnknown(obj2.getName()); // action is missing or wrong type } else { error(-1, "Bad annotation action"); action = NULL; } obj2.free(); } else { error(-1, "Missing annotation destination/action"); action = NULL; } } obj1.free(); // check for bad action if (action && action->isOk()) ok = gTrue; return; err1: obj2.free(); err2: obj1.free(); } Link::~Link() { if (action) delete action; } //------------------------------------------------------------------------ // Links //------------------------------------------------------------------------ Links::Links(Object *annots, GString *baseURI) { Link *link; Object obj1, obj2; int size; int i; links = NULL; size = 0; numLinks = 0; if (annots->isArray()) { for (i = 0; i < annots->arrayGetLength(); ++i) { if (annots->arrayGet(i, &obj1)->isDict()) { if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) { link = new Link(obj1.getDict(), baseURI); if (link->isOk()) { if (numLinks >= size) { size += 16; links = (Link **)grealloc(links, size * sizeof(Link *)); } 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; name = NULL; // string if (fileSpecObj->isString()) { name = fileSpecObj->getString()->copy(); // dictionary } else if (fileSpecObj->isDict()) { if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { obj1.free(); fileSpecObj->dictLookup("F", &obj1); } if (obj1.isString()) name = obj1.getString()->copy(); else error(-1, "Illegal file spec in link"); obj1.free(); // error } else { error(-1, "Illegal file spec in link"); } return name; } 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,165 +1,163 @@ //======================================================================== // // 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) actionURI, // URI actionNamed, // named action actionUnknown // anything else }; class LinkAction { public: // Destructor. virtual ~LinkAction() {} // Was the LinkAction created successfully? 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 GBool pageIsRef; // is the page a reference or number? union { Ref pageRef; // reference to page int pageNum; // one-relative page number }; fouble left, bottom; // position fouble right, top; fouble zoom; // zoom factor GBool changeLeft, changeTop; // for destXYZ links, which position GBool changeZoom; // components to change GBool ok; // set if created successfully LinkDest(LinkDest *dest); }; //------------------------------------------------------------------------ // LinkGoTo //------------------------------------------------------------------------ class LinkGoTo: public LinkAction { public: // Build a LinkGoTo from a destination (dictionary, name, or string). LinkGoTo(Object *destObj); // Destructor. virtual ~LinkGoTo(); // Was the LinkGoTo created successfully? virtual GBool isOk() { return dest || namedDest; } // Accessors. virtual LinkActionKind getKind() { return actionGoTo; } LinkDest *getDest() { return dest; } GString *getNamedDest() { return namedDest; } private: LinkDest *dest; // regular destination (NULL for remote // link with bad destination) GString *namedDest; // named destination (only one of dest and // and namedDest may be non-NULL) }; //------------------------------------------------------------------------ // LinkGoToR //------------------------------------------------------------------------ class LinkGoToR: public LinkAction { public: // Build a LinkGoToR from a file spec (dictionary) and destination // (dictionary, name, or string). LinkGoToR(Object *fileSpecObj, Object *destObj); // Destructor. virtual ~LinkGoToR(); // Was the LinkGoToR created successfully? virtual GBool isOk() { return fileName && (dest || namedDest); } // Accessors. virtual LinkActionKind getKind() { return actionGoToR; } GString *getFileName() { return fileName; } LinkDest *getDest() { return dest; } GString *getNamedDest() { return namedDest; } private: GString *fileName; // file name LinkDest *dest; // regular destination (NULL for remote // link with bad destination) 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,101 +1,101 @@ //======================================================================== // // 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; size = 31; len = 0; tab = (NameToCharCodeEntry *)gmalloc(size * sizeof(NameToCharCodeEntry)); for (i = 0; i < size; ++i) { tab[i].name = NULL; } } NameToCharCode::~NameToCharCode() { int i; for (i = 0; i < size; ++i) { if (tab[i].name) { gfree(tab[i].name); } } gfree(tab); } void NameToCharCode::add(char *name, CharCode c) { NameToCharCodeEntry *oldTab; int h, i, oldSize; // expand the table if necessary if (len >= size / 2) { oldSize = size; oldTab = tab; size = 2*size + 1; tab = (NameToCharCodeEntry *)gmalloc(size * sizeof(NameToCharCodeEntry)); for (h = 0; h < size; ++h) { tab[h].name = NULL; } for (i = 0; i < oldSize; ++i) { if (oldTab[i].name) { h = hash(oldTab[i].name); while (tab[h].name) { if (++h == size) { h = 0; } } tab[h] = oldTab[i]; } } gfree(oldTab); } // add the new name h = hash(name); while (tab[h].name && strcmp(tab[h].name, name)) { if (++h == size) { h = 0; } } if (!tab[h].name) { tab[h].name = copyString(name); } tab[h].c = c; ++len; } CharCode NameToCharCode::lookup(char *name) { int h; h = hash(name); while (tab[h].name) { if (!strcmp(tab[h].name, name)) { return tab[h].c; } if (++h == size) { h = 0; } 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,40 +1,40 @@ //======================================================================== // // 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); private: int hash(char *name); NameToCharCodeEntry *tab; int size; int len; }; #endif 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,101 +1,101 @@ //======================================================================== // // 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"}, {0x0100, "Amacron"}, {0x0104, "Aogonek"}, {0x00c5, "Aring"}, {0x01fa, "Aringacute"}, {0x00c5, "Aringsmall"}, {0x0041, "Asmall"}, {0x00c3, "Atilde"}, {0x00c3, "Atildesmall"}, {0x0042, "B"}, {0x0392, "Beta"}, {0xf6f4, "Brevesmall"}, {0x0042, "Bsmall"}, {0x0043, "C"}, {0x0106, "Cacute"}, {0xf6ca, "Caron"}, {0xf6ca, "Caronsmall"}, {0x010c, "Ccaron"}, {0x00c7, "Ccedilla"}, {0x00c7, "Ccedillasmall"}, {0x0108, "Ccircumflex"}, {0x010a, "Cdotaccent"}, {0xf7b8, "Cedillasmall"}, {0x03a7, "Chi"}, {0xf6f6, "Circumflexsmall"}, {0x0043, "Csmall"}, {0x0044, "D"}, {0x010e, "Dcaron"}, {0x0110, "Dcroat"}, {0x2206, "Delta"}, {0xf6cb, "Dieresis"}, {0xf6cc, "DieresisAcute"}, {0xf6cd, "DieresisGrave"}, {0xf6cb, "Dieresissmall"}, {0xf6f7, "Dotaccentsmall"}, {0x0044, "Dsmall"}, {0x0045, "E"}, {0x00c9, "Eacute"}, {0x00c9, "Eacutesmall"}, {0x0114, "Ebreve"}, {0x011a, "Ecaron"}, {0x00ca, "Ecircumflex"}, {0x00ca, "Ecircumflexsmall"}, {0x00cb, "Edieresis"}, {0x00cb, "Edieresissmall"}, {0x0116, "Edotaccent"}, {0x00c8, "Egrave"}, {0x00c8, "Egravesmall"}, {0x0112, "Emacron"}, {0x014a, "Eng"}, {0x0118, "Eogonek"}, {0x0395, "Epsilon"}, {0x0388, "Epsilontonos"}, {0x0045, "Esmall"}, {0x0397, "Eta"}, {0x0389, "Etatonos"}, {0x00d0, "Eth"}, {0x00d0, "Ethsmall"}, {0x20ac, "Euro"}, {0x0046, "F"}, {0x0046, "Fsmall"}, {0x0047, "G"}, {0x0393, "Gamma"}, {0x011e, "Gbreve"}, {0x01e6, "Gcaron"}, {0x011c, "Gcircumflex"}, {0x0122, "Gcommaaccent"}, {0x0120, "Gdotaccent"}, {0xf6ce, "Grave"}, {0xf6ce, "Gravesmall"}, {0x0047, "Gsmall"}, {0x0048, "H"}, {0x25cf, "H18533"}, 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,101 +1,101 @@ //======================================================================== // // 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", "string", "name", "null", "array", "dictionary", "stream", "ref", "cmd", "error", "eof", "none" }; #ifdef DEBUG_MEM int Object::numAlloc[numObjTypes] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; #endif Object *Object::initArray(XRef *xref) { initObj(objArray); array = new Array(xref); return this; } Object *Object::initDict(XRef *xref) { initObj(objDict); dict = new Dict(xref); return this; } Object *Object::initStream(Stream *streamA) { initObj(objStream); stream = streamA; return this; } Object *Object::copy(Object *obj) { *obj = *this; switch (type) { case objString: obj->string = string->copy(); break; case objName: obj->name = copyString(name); break; case objArray: array->incRef(); break; case objDict: dict->incRef(); break; case objStream: stream->incRef(); break; case objCmd: obj->cmd = copyString(cmd); break; default: break; } #ifdef DEBUG_MEM ++numAlloc[type]; #endif return obj; } Object *Object::fetch(XRef *xref, Object *obj) { return (type == objRef && xref) ? xref->fetch(ref.num, ref.gen, obj) : copy(obj); } void Object::free() { 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,299 +1,299 @@ //======================================================================== // // 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 //------------------------------------------------------------------------ struct Ref { int num; // object number int gen; // generation number }; //------------------------------------------------------------------------ // object types //------------------------------------------------------------------------ enum ObjType { // simple objects objBool, // boolean objInt, // integer objReal, // real objString, // string objName, // name objNull, // null // complex objects objArray, // array objDict, // dictionary objStream, // stream objRef, // indirect reference // special objects objCmd, // command name objError, // error return from Lexer objEOF, // end of file return from Lexer objNone // uninitialized object }; #define numObjTypes 14 // total number of object types //------------------------------------------------------------------------ // Object //------------------------------------------------------------------------ #ifdef DEBUG_MEM #define initObj(t) ++numAlloc[type = t] #else #define initObj(t) type = t #endif class Object { public: // Default constructor. Object(): type(objNone) {} // Initialize an object. Object *initBool(GBool boolnA) { initObj(objBool); booln = boolnA; return this; } Object *initInt(int intgA) { initObj(objInt); intg = intgA; return this; } Object *initReal(fouble realA) { initObj(objReal); real = realA; return this; } Object *initString(GString *stringA) { initObj(objString); string = stringA; return this; } Object *initName(char *nameA) { initObj(objName); name = copyString(nameA); return this; } Object *initNull() { initObj(objNull); return this; } Object *initArray(XRef *xref); Object *initDict(XRef *xref); Object *initStream(Stream *streamA); Object *initRef(int numA, int genA) { initObj(objRef); ref.num = numA; ref.gen = genA; return this; } Object *initCmd(char *cmdA) { initObj(objCmd); cmd = copyString(cmdA); return this; } Object *initError() { initObj(objError); return this; } Object *initEOF() { initObj(objEOF); return this; } // Copy an object. Object *copy(Object *obj); // If object is a Ref, fetch and return the referenced object. // Otherwise, return a copy of the object. Object *fetch(XRef *xref, Object *obj); // Free object contents. void free(); // Type checking. ObjType getType() { return type; } GBool isBool() { return type == objBool; } GBool isInt() { return type == objInt; } GBool isReal() { return type == objReal; } GBool isNum() { return type == objInt || type == objReal; } GBool isString() { return type == objString; } GBool isName() { return type == objName; } GBool isNull() { return type == objNull; } GBool isArray() { return type == objArray; } GBool isDict() { return type == objDict; } GBool isStream() { return type == objStream; } GBool isRef() { return type == objRef; } GBool isCmd() { return type == objCmd; } GBool isError() { return type == objError; } GBool isEOF() { return type == objEOF; } GBool isNone() { return type == objNone; } // Special type checking. GBool isName(char *nameA) { return type == objName && !strcmp(name, nameA); } GBool isDict(char *dictType); GBool isStream(char *dictType); GBool isCmd(char *cmdA) { return type == objCmd && !strcmp(cmd, cmdA); } // Accessors. NB: these assume object is of correct type. GBool getBool() { return booln; } int getInt() { return intg; } fouble getReal() { return real; } fouble getNum() { return type == objInt ? (fouble)intg : real; } GString *getString() { return string; } char *getName() { return name; } Array *getArray() { return array; } Dict *getDict() { return dict; } Stream *getStream() { return stream; } Ref getRef() { return ref; } int getRefNum() { return ref.num; } int getRefGen() { return ref.gen; } // 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 }; #ifdef DEBUG_MEM static int // number of each type of object numAlloc[numObjTypes]; // currently allocated #endif }; //------------------------------------------------------------------------ // Array accessors. //------------------------------------------------------------------------ #include "Array.h" inline int Object::arrayGetLength() { return array->getLength(); } inline void Object::arrayAdd(Object *elem) { array->add(elem); } inline Object *Object::arrayGet(int i, Object *obj) { return array->get(i, obj); } inline Object *Object::arrayGetNF(int i, Object *obj) { return array->getNF(i, obj); } //------------------------------------------------------------------------ // Dict accessors. //------------------------------------------------------------------------ #include "Dict.h" inline int Object::dictGetLength() { return dict->getLength(); } inline void Object::dictAdd(char *key, Object *val) { dict->add(key, val); } inline GBool Object::dictIs(char *dictType) { return dict->is(dictType); } inline GBool Object::isDict(char *dictType) { return type == objDict && dictIs(dictType); } inline Object *Object::dictLookup(char *key, Object *obj) { return dict->lookup(key, obj); } inline Object *Object::dictLookupNF(char *key, Object *obj) { return dict->lookupNF(key, obj); } inline char *Object::dictGetKey(int i) { return dict->getKey(i); } inline Object *Object::dictGetVal(int i, Object *obj) { return dict->getVal(i, obj); } inline Object *Object::dictGetValNF(int i, Object *obj) { return dict->getValNF(i, obj); } //------------------------------------------------------------------------ // Stream accessors. //------------------------------------------------------------------------ #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,97 +1,102 @@ //======================================================================== // // 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]; } det = 1 / (defCTM[0] * defCTM[3] - defCTM[1] * defCTM[2]); defICTM[0] = defCTM[3] * det; defICTM[1] = -defCTM[1] * det; defICTM[2] = -defCTM[2] * det; defICTM[3] = defCTM[0] * det; defICTM[4] = (defCTM[2] * defCTM[5] - defCTM[3] * defCTM[4]) * det; defICTM[5] = (defCTM[1] * defCTM[4] - defCTM[0] * defCTM[5]) * det; } void OutputDev::cvtDevToUser(int dx, int dy, 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) str->getChar(); str->close(); } } #if OPI_SUPPORT void OutputDev::opiBegin(GfxState *state, Dict *opiDict) { } void OutputDev::opiEnd(GfxState *state, Dict *opiDict) { } #endif 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,143 +1,158 @@ //======================================================================== // // 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 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, fouble m11, fouble m12, fouble m21, fouble m22, fouble m31, fouble 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) {} virtual void updateLineWidth(GfxState *state) {} virtual void updateFillColor(GfxState *state) {} virtual void updateStrokeColor(GfxState *state) {} virtual void updateFillOpacity(GfxState *state) {} virtual void updateStrokeOpacity(GfxState *state) {} //----- update text state virtual void updateFont(GfxState *state) {} virtual void updateTextMat(GfxState *state) {} virtual void updateCharSpace(GfxState *state) {} 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,251 +1,259 @@ //======================================================================== // // 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) { delete links; } } // Check for a PDF header on this stream. Skip past some garbage // if necessary. void PDFDoc::checkHeader() { char hdrBuf[headerSearchSize+1]; char *p; int i; pdfVersion = 0; for (i = 0; i < headerSearchSize; ++i) { hdrBuf[i] = str->getChar(); } hdrBuf[headerSearchSize] = '\0'; for (i = 0; i < headerSearchSize - 5; ++i) { if (!strncmp(&hdrBuf[i], "%PDF-", 5)) { break; } } if (i >= headerSearchSize - 5) { error(-1, "May not be a PDF file (continuing anyway)"); return; } str->moveStart(i); p = strtok(&hdrBuf[i+5], " \t\n\r"); pdfVersion = atof(p); if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') || pdfVersion > supportedPDFVersionNum + 0.0001) { error(-1, "PDF version %s -- xpdf supports version %s" " (continuing anyway)", p, supportedPDFVersionStr); } } void PDFDoc::displayPage(OutputDev *out, int page, fouble zoom, int rotate, GBool doLinks) { Page *p; if (printCommands) { printf("***** page %d *****\n", page); } p = catalog->getPage(page); if (doLinks) { if (links) { delete links; } 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; if (!(f = fopen(name->getCString(), "wb"))) { error(-1, "Couldn't open file '%s'", name->getCString()); return gFalse; } str->reset(); while ((c = str->getChar()) != EOF) { fputc(c, f); } str->close(); fclose(f); return gTrue; } void PDFDoc::getLinks(Page *page) { Object obj; links = new Links(page->getAnnots(&obj), catalog->getBaseURI()); obj.free(); } 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,142 +1,146 @@ //======================================================================== // // 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 // no metadata. GString *readMetadata() { return catalog->readMetadata(); } // Return the structure tree root object. Object *getStructTreeRoot() { return catalog->getStructTreeRoot(); } // Display a page. void displayPage(OutputDev *out, int page, fouble zoom, int rotate, GBool doLinks); // Display a range of pages. void displayPages(OutputDev *out, int firstPage, int lastPage, int zoom, int rotate, GBool doLinks); // Find a page, given its object ID. Returns page number, or 0 if // not found. int findPage(int num, int gen) { return catalog->findPage(num, gen); } // If point <x>,<y> is in a link, return the associated action; // else return NULL. LinkAction *findLink(fouble x, fouble y) { return links->find(x, y); } // Return true if <x>,<y> is in a link. GBool onLink(fouble x, fouble y) { return links->onLink(x, y); } // Find a named destination. Returns the link destination, or // NULL if <name> is not a destination. LinkDest *findDest(GString *name) { return catalog->findDest(name); } // Is the file encrypted? GBool isEncrypted() { return xref->isEncrypted(); } // Check various permissions. GBool okToPrint(GBool ignoreOwnerPW = gFalse) { return xref->okToPrint(ignoreOwnerPW); } GBool okToChange(GBool ignoreOwnerPW = gFalse) { return xref->okToChange(ignoreOwnerPW); } GBool okToCopy(GBool ignoreOwnerPW = gFalse) { return xref->okToCopy(ignoreOwnerPW); } GBool okToAddNotes(GBool ignoreOwnerPW = gFalse) { return xref->okToAddNotes(ignoreOwnerPW); } // Is this document linearized? GBool isLinearized(); // Return the document's Info dictionary (if any). 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,267 +1,281 @@ //======================================================================== // // 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; mediaBox.x2 = 612; mediaBox.y2 = 792; cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0; haveCropBox = gFalse; rotate = 0; resources.initNull(); } // media box readBox(dict, "MediaBox", &mediaBox); // crop box cropBox = mediaBox; haveCropBox = readBox(dict, "CropBox", &cropBox); // if the MediaBox is excessively larger than the CropBox, // just use the CropBox limitToCropBox = gFalse; if (haveCropBox) { w = 0.25 * (cropBox.x2 - cropBox.x1); h = 0.25 * (cropBox.y2 - cropBox.y1); if ((cropBox.x1 - mediaBox.x1) + (mediaBox.x2 - cropBox.x2) > w || (cropBox.y1 - mediaBox.y1) + (mediaBox.y2 - cropBox.y2) > h) { limitToCropBox = gTrue; } } // other boxes bleedBox = cropBox; readBox(dict, "BleedBox", &bleedBox); trimBox = cropBox; readBox(dict, "TrimBox", &trimBox); artBox = cropBox; readBox(dict, "ArtBox", &artBox); // rotate dict->lookup("Rotate", &obj1); if (obj1.isInt()) { 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; } obj2.free(); obj1.arrayGet(2, &obj2); if (obj2.isNum()) { tmp.x2 = obj2.getNum(); } else { ok = gFalse; } obj2.free(); obj1.arrayGet(3, &obj2); if (obj2.isNum()) { tmp.y2 = obj2.getNum(); } else { ok = gFalse; } obj2.free(); if (ok) { *box = tmp; } } else { ok = gFalse; } obj1.free(); return ok; } //------------------------------------------------------------------------ // Page //------------------------------------------------------------------------ Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, GBool printCommandsA) { ok = gTrue; xref = xrefA; num = numA; printCommands = printCommandsA; // get attributes attrs = attrsA; // annotations pageDict->lookupNF("Annots", &annots); if (!(annots.isRef() || annots.isArray() || annots.isNull())) { error(-1, "Page annotations object (page %d) is wrong type (%s)", num, annots.getTypeName()); annots.free(); goto err2; } // contents pageDict->lookupNF("Contents", &contents); if (!(contents.isRef() || contents.isArray() || contents.isNull())) { error(-1, "Page contents object (page %d) is wrong type (%s)", num, contents.getTypeName()); contents.free(); goto err1; } 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,125 +1,151 @@ //======================================================================== // // 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 }; #endif 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,213 +1,214 @@ //======================================================================== // // 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); lexer->getObj(&buf2); } Parser::~Parser() { buf1.free(); buf2.free(); delete lexer; } #ifndef NO_DECRYPTION Object *Parser::getObj(Object *obj, Guchar *fileKey, int keyLength, int objNum, int objGen) { #else Object *Parser::getObj(Object *obj) { #endif char *key; Stream *str; Object obj2; int num; #ifndef NO_DECRYPTION Decrypt *decrypt; GString *s; char *p; int i; #endif // refill buffer after inline image data if (inlineImg == 2) { buf1.free(); buf2.free(); lexer->getObj(&buf1); lexer->getObj(&buf2); inlineImg = 0; } // array if (buf1.isCmd("[")) { shift(); obj->initArray(xref); while (!buf1.isCmd("]") && !buf1.isEOF()) #ifndef NO_DECRYPTION obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen)); #else obj->arrayAdd(getObj(&obj2)); #endif if (buf1.isEOF()) error(getPos(), "End of file inside array"); shift(); // dictionary or stream } else if (buf1.isCmd("<<")) { shift(); obj->initDict(xref); while (!buf1.isCmd(">>") && !buf1.isEOF()) { if (!buf1.isName()) { error(getPos(), "Dictionary key must be a name object"); shift(); } else { key = copyString(buf1.getName()); shift(); if (buf1.isEOF() || buf1.isError()) break; #ifndef NO_DECRYPTION obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen)); #else obj->dictAdd(key, getObj(&obj2)); #endif } } if (buf1.isEOF()) error(getPos(), "End of file inside dictionary"); if (buf2.isCmd("stream")) { if ((str = makeStream(obj))) { obj->initStream(str); #ifndef NO_DECRYPTION if (fileKey) { str->getBaseStream()->doDecryption(fileKey, keyLength, objNum, objGen); } #endif } else { obj->free(); obj->initError(); } } else { shift(); } // indirect reference or integer } else if (buf1.isInt()) { num = buf1.getInt(); shift(); if (buf1.isInt() && buf2.isCmd("R")) { obj->initRef(num, buf1.getInt()); shift(); shift(); } else { obj->initInt(num); } #ifndef NO_DECRYPTION // string } else if (buf1.isString() && fileKey) { 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; } buf1.free(); buf1 = buf2; if (inlineImg > 0) // don't buffer inline image data buf2.initNull(); else lexer->getObj(&buf2); } 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,58 +1,58 @@ //======================================================================== // // 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(); // Get the next object from the input stream. #ifndef NO_DECRYPTION Object *getObj(Object *obj, Guchar *fileKey = NULL, int keyLength = 0, int objNum = 0, int objGen = 0); #else Object *getObj(Object *obj); #endif // Get stream. Stream *getStream() { return lexer->getStream(); } // Get current position in file. int getPos() { return lexer->getPos(); } private: XRef *xref; // the xref table for this PDF file Lexer *lexer; // input stream Object buf1, buf2; // next two tokens int inlineImg; // set when inline image data is encountered Stream *makeStream(Object *dict); void shift(); }; #endif 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,103 +1,103 @@ //======================================================================== // // 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 // 1-7 bit codes static CCITTCode twoDimTab1[128] = { {-1, -1}, {-1, -1}, // 000000x {7, twoDimVertL3}, // 0000010 {7, twoDimVertR3}, // 0000011 {6, twoDimVertL2}, {6, twoDimVertL2}, // 000010x {6, twoDimVertR2}, {6, twoDimVertR2}, // 000011x {4, twoDimPass}, {4, twoDimPass}, // 0001xxx {4, twoDimPass}, {4, twoDimPass}, {4, twoDimPass}, {4, twoDimPass}, {4, twoDimPass}, {4, twoDimPass}, {3, twoDimHoriz}, {3, twoDimHoriz}, // 001xxxx {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimVertL1}, {3, twoDimVertL1}, // 010xxxx {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertR1}, {3, twoDimVertR1}, // 011xxxx {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {1, twoDimVert0}, {1, twoDimVert0}, // 1xxxxxx {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0} }; //------------------------------------------------------------------------ // white run lengths //------------------------------------------------------------------------ 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,101 +1,101 @@ //======================================================================== // // 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 #include "Stream.h" #include "Stream-CCITT.h" #ifdef __DJGPP__ static GBool setDJSYSFLAGS = gFalse; #endif #ifdef VMS #if (__VMS_VER < 70000000) extern "C" int unlink(char *filename); #endif #ifdef __GNUC__ #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif #endif #ifdef MACOS #include "StuffItEngineLib.h" #endif //------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ Stream::Stream() { ref = 1; } Stream::~Stream() { } void Stream::close() { } int Stream::getRawChar() { error(-1, "Internal: called getRawChar() on non-predictor stream"); return EOF; } char *Stream::getLine(char *buf, int size) { int i; int c; if (lookChar() == EOF) return NULL; for (i = 0; i < size - 1; ++i) { c = getChar(); if (c == EOF || c == '\n') break; if (c == '\r') { if ((c = lookChar()) == '\n') getChar(); break; } buf[i] = c; } buf[i] = '\0'; return buf; } GString *Stream::getPSFilter(char *indent) { return new GString(); } Stream *Stream::addFilters(Object *dict) { Object obj, obj2; Object params, params2; Stream *str; int i; @@ -210,193 +210,193 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { if (obj.isInt()) { columns = obj.getInt(); } obj.free(); params->dictLookup("Rows", &obj); if (obj.isInt()) { rows = obj.getInt(); } obj.free(); params->dictLookup("EndOfBlock", &obj); if (obj.isBool()) { endOfBlock = obj.getBool(); } obj.free(); params->dictLookup("BlackIs1", &obj); if (obj.isBool()) { black = obj.getBool(); } obj.free(); } str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign, columns, rows, endOfBlock, black); } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) { str = new DCTStream(str); } else if (!strcmp(name, "FlateDecode") || !strcmp(name, "Fl")) { pred = 1; columns = 1; colors = 1; bits = 8; if (params->isDict()) { params->dictLookup("Predictor", &obj); if (obj.isInt()) pred = obj.getInt(); obj.free(); params->dictLookup("Columns", &obj); if (obj.isInt()) columns = obj.getInt(); obj.free(); params->dictLookup("Colors", &obj); if (obj.isInt()) colors = obj.getInt(); obj.free(); params->dictLookup("BitsPerComponent", &obj); if (obj.isInt()) bits = obj.getInt(); obj.free(); } str = new FlateStream(str, pred, columns, colors, bits); } else { error(getPos(), "Unknown filter '%s'", name); str = new EOFStream(str); } return str; } //------------------------------------------------------------------------ // BaseStream //------------------------------------------------------------------------ BaseStream::BaseStream(Object *dictA) { dict = *dictA; #ifndef NO_DECRYPTION decrypt = NULL; #endif } BaseStream::~BaseStream() { dict.free(); #ifndef NO_DECRYPTION if (decrypt) delete decrypt; #endif } #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; } ImageStream::~ImageStream() { gfree(imgLine); } void ImageStream::reset() { str->reset(); } GBool ImageStream::getPixel(Guchar *pix) { Gulong buf, bitMask; int bits; int c; int i; if (imgIdx >= nVals) { // read one line of image pixels if (nBits == 1) { for (i = 0; i < nVals; i += 8) { c = str->getChar(); imgLine[i+0] = (Guchar)((c >> 7) & 1); imgLine[i+1] = (Guchar)((c >> 6) & 1); imgLine[i+2] = (Guchar)((c >> 5) & 1); imgLine[i+3] = (Guchar)((c >> 4) & 1); imgLine[i+4] = (Guchar)((c >> 3) & 1); imgLine[i+5] = (Guchar)((c >> 2) & 1); imgLine[i+6] = (Guchar)((c >> 1) & 1); imgLine[i+7] = (Guchar)(c & 1); } } else if (nBits == 8) { for (i = 0; i < nVals; ++i) { imgLine[i] = str->getChar(); } } else { bitMask = (1 << nBits) - 1; buf = 0; bits = 0; for (i = 0; i < nVals; ++i) { if (bits < nBits) { buf = (buf << 8) | (str->getChar() & 0xff); bits += 8; } imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask); bits -= nBits; } } // reset to start of line imgIdx = 0; } for (i = 0; i < nComps; ++i) pix[i] = imgLine[imgIdx++]; return gTrue; } void ImageStream::skipLine() { int n, i; n = (nVals * nBits + 7) >> 3; for (i = 0; i < n; ++i) { str->getChar(); } } //------------------------------------------------------------------------ // StreamPredictor //------------------------------------------------------------------------ StreamPredictor::StreamPredictor(Stream *strA, int predictorA, int widthA, int nCompsA, int nBitsA) { @@ -461,313 +461,426 @@ GBool StreamPredictor::getNextLine() { upLeftBuf[3] = upLeftBuf[2]; upLeftBuf[2] = upLeftBuf[1]; upLeftBuf[1] = upLeftBuf[0]; upLeftBuf[0] = predLine[i]; if ((c = str->getRawChar()) == EOF) { break; } switch (curPred) { case 11: // PNG sub predLine[i] = predLine[i - pixBytes] + (Guchar)c; break; case 12: // PNG up predLine[i] = predLine[i] + (Guchar)c; break; case 13: // PNG average predLine[i] = ((predLine[i - pixBytes] + predLine[i]) >> 1) + (Guchar)c; break; case 14: // PNG Paeth left = predLine[i - pixBytes]; up = predLine[i]; upLeft = upLeftBuf[pixBytes]; p = left + up - upLeft; if ((pa = p - left) < 0) pa = -pa; if ((pb = p - up) < 0) pb = -pb; if ((pc = p - upLeft) < 0) pc = -pc; if (pa <= pb && pa <= pc) predLine[i] = left + (Guchar)c; else if (pb <= pc) predLine[i] = up + (Guchar)c; else predLine[i] = upLeft + (Guchar)c; break; case 10: // PNG none default: // no predictor or TIFF predictor predLine[i] = (Guchar)c; break; } } // apply TIFF (component) predictor //~ this is completely untested if (predictor == 2) { if (nBits == 1) { inBuf = predLine[pixBytes - 1]; for (i = pixBytes; i < rowBytes; i += 8) { // 1-bit add is just xor inBuf = (inBuf << 8) | predLine[i]; predLine[i] ^= inBuf >> nComps; } } else if (nBits == 8) { for (i = pixBytes; i < rowBytes; ++i) { predLine[i] += predLine[i - nComps]; } } else { upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0; bitMask = (1 << nBits) - 1; inBuf = outBuf = 0; inBits = outBits = 0; j = k = pixBytes; for (i = 0; i < nVals; ++i) { if (inBits < nBits) { inBuf = (inBuf << 8) | (predLine[j++] & 0xff); inBits += 8; } upLeftBuf[3] = upLeftBuf[2]; upLeftBuf[2] = upLeftBuf[1]; upLeftBuf[1] = upLeftBuf[0]; upLeftBuf[0] = (upLeftBuf[nComps] + (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() { int c1, c2, x; if (buf != EOF) return buf; if (eof) { buf = EOF; return EOF; } do { c1 = str->getChar(); } while (isspace(c1)); if (c1 == '>') { eof = gTrue; buf = EOF; return buf; } do { c2 = str->getChar(); } while (isspace(c2)); if (c2 == '>') { eof = gTrue; c2 = '0'; } if (c1 >= '0' && c1 <= '9') { x = (c1 - '0') << 4; } else if (c1 >= 'A' && c1 <= 'F') { x = (c1 - 'A' + 10) << 4; } else if (c1 >= 'a' && c1 <= 'f') { x = (c1 - 'a' + 10) << 4; } else if (c1 == EOF) { eof = gTrue; x = 0; } else { error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c1); x = 0; } if (c2 >= '0' && c2 <= '9') { x += c2 - '0'; } else if (c2 >= 'A' && c2 <= 'F') { x += c2 - 'A' + 10; } else if (c2 >= 'a' && c2 <= 'f') { x += c2 - 'a' + 10; } else if (c2 == EOF) { eof = gTrue; x = 0; } else { error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c2); } buf = x & 0xff; return buf; } GString *ASCIIHexStream::getPSFilter(char *indent) { GString *s; if (!(s = str->getPSFilter(indent))) { return NULL; } s->append(indent)->append("/ASCIIHexDecode filter\n"); return s; } GBool ASCIIHexStream::isBinary(GBool last) { return str->isBinary(gFalse); } //------------------------------------------------------------------------ // ASCII85Stream //------------------------------------------------------------------------ ASCII85Stream::ASCII85Stream(Stream *strA): FilterStream(strA) { @@ -866,197 +979,193 @@ LZWStream::~LZWStream() { pclose(zPipe); #else fclose(zPipe); #endif zPipe = NULL; unlink(zName->getCString()); delete zName; } if (pred) { delete pred; } delete str; } int LZWStream::getChar() { if (pred) { return pred->getChar(); } return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } int LZWStream::lookChar() { if (pred) { return pred->lookChar(); } return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } int LZWStream::getRawChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } void LZWStream::reset() { FILE *f; GString *zCmd; //----- close old LZW stream if (zPipe) { #ifdef HAVE_POPEN pclose(zPipe); #else fclose(zPipe); #endif zPipe = NULL; unlink(zName->getCString()); delete zName; } //----- tell Delorie runtime to spawn a new instance of COMMAND.COM // to run gzip #if __DJGPP__ if (!setDJSYSFLAGS) { setenv("DJSYSFLAGS", "0x0002", 0); setDJSYSFLAGS = gTrue; } #endif //----- create the .Z file if (!openTempFile(&zName, &f, "wb", ".Z")) { error(getPos(), "Couldn't create temporary file for LZW stream"); return; } dumpFile(f); fclose(f); //----- execute uncompress / gzip zCmd = new GString(uncompressCmd); zCmd->append(' '); zCmd->append(zName); #if defined(MACOS) long magicCookie; // first we open the engine up 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 int outBuf[8]; // output buffer int outData; // temporary output buffer int inCode, outCode; // input and output codes int nextCode; // next code index GBool eof; // set when EOF is reached GBool clear; // set if table needs to be cleared GBool first; // indicates first code word after clear int i, j; str->reset(); // magic number fputc(0x1f, f); fputc(0x9d, f); // max code length, block mode flag fputc(0x8c, f); // init input side inCodeBits = 9; inputBuf = 0; inputBits = 0; eof = gFalse; // init output side outCodeBits = 9; // clear table first = gTrue; nextCode = 258; clear = gFalse; do { for (i = 0; i < 8; ++i) { // check for table overflow if (nextCode + early > 0x1001) { inCode = 256; // read input code } else { do { inCode = getCode(); if (inCode == EOF) { eof = gTrue; inCode = 0; } } while (first && inCode == 256); } // compute output code if (inCode < 256) { outCode = inCode; } else if (inCode == 256) { outCode = 256; clear = gTrue; } else if (inCode == 257) { outCode = 0; eof = gTrue; } else { outCode = inCode - 1; } outBuf[i] = outCode; // next code index if (first) first = gFalse; else ++nextCode; // check input code size if (nextCode + early == 0x200) inCodeBits = 10; @@ -3194,192 +3303,242 @@ int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) { int code; int c; int i, j; code = 0; for (len = 1; len <= flateMaxHuffman; ++len) { // add a bit to the code if (codeSize == 0) { if ((c = str->getChar()) == EOF) return EOF; codeBuf = c & 0xff; codeSize = 8; } code = (code << 1) | (codeBuf & 1); codeBuf >>= 1; --codeSize; // look for code i = tab->start[len]; j = tab->start[len + 1]; if (i < j && code >= tab->codes[i].code && code <= tab->codes[j-1].code) { i += code - tab->codes[i].code; return tab->codes[i].val; } } // not found error(getPos(), "Bad code (%04x) in flate stream", code); return EOF; } int FlateStream::getCodeWord(int bits) { int c; while (codeSize < bits) { if ((c = str->getChar()) == EOF) return EOF; codeBuf |= (c & 0xff) << codeSize; codeSize += 8; } c = codeBuf & ((1 << bits) - 1); codeBuf >>= bits; codeSize -= bits; return c; } //------------------------------------------------------------------------ // EOFStream //------------------------------------------------------------------------ EOFStream::EOFStream(Stream *strA): FilterStream(strA) { } EOFStream::~EOFStream() { delete str; } //------------------------------------------------------------------------ // FixedLengthEncoder //------------------------------------------------------------------------ FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA): FilterStream(strA) { length = lengthA; count = 0; } FixedLengthEncoder::~FixedLengthEncoder() { if (str->isEncoder()) delete str; } 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() { } GBool ASCII85Encoder::fillBuf() { Gulong t; char buf1[5]; int c; int n, i; if (eof) return gFalse; t = 0; for (n = 0; n < 4; ++n) { if ((c = str->getChar()) == EOF) break; t = (t << 8) + c; } bufPtr = bufEnd = buf; if (n > 0) { if (n == 4 && t == 0) { *bufEnd++ = 'z'; if (++lineLen == 65) { *bufEnd++ = '\n'; lineLen = 0; } } else { if (n < 4) t <<= 8 * (4 - n); for (i = 4; i >= 0; --i) { buf1[i] = (char)(t % 85 + 0x21); t /= 85; } for (i = 0; i <= n; ++i) { *bufEnd++ = buf1[i]; if (++lineLen == 65) { *bufEnd++ = '\n'; lineLen = 0; } } } } if (n < 4) { *bufEnd++ = '~'; *bufEnd++ = '>'; eof = gTrue; } return bufPtr < bufEnd; } //------------------------------------------------------------------------ // RunLengthEncoder //------------------------------------------------------------------------ RunLengthEncoder::RunLengthEncoder(Stream *strA): FilterStream(strA) { bufPtr = bufEnd = nextEnd = buf; eof = gFalse; } RunLengthEncoder::~RunLengthEncoder() { if (str->isEncoder()) delete str; } void RunLengthEncoder::reset() { str->reset(); bufPtr = bufEnd = nextEnd = buf; eof = gFalse; } void RunLengthEncoder::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,394 +1,440 @@ //======================================================================== // // 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, strASCII85, strLZW, strRunLength, strCCITTFax, strDCT, strFlate, strWeird // internal-use stream types }; //------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ class Stream { public: // Constructor. Stream(); // Destructor. virtual ~Stream(); // Reference counting. int incRef() { return ++ref; } int decRef() { return --ref; } // Get kind of stream. 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(); // Gets the next pixel from the stream. <pix> should be able to hold // at least nComps elements. Returns false at end of file. GBool getPixel(Guchar *pix); // Skip an entire line from the image. void skipLine(); private: Stream *str; // base stream int width; // pixels per line int nComps; // components per pixel int nBits; // bits per component int nVals; // components per line Guchar *imgLine; // line buffer int imgIdx; // current index in imgLine }; //------------------------------------------------------------------------ // StreamPredictor //------------------------------------------------------------------------ class StreamPredictor { public: // Create a predictor object. Note that the parameters are for the // predictor, and may not match the actual image parameters. StreamPredictor(Stream *strA, int predictorA, int widthA, int nCompsA, int nBitsA); ~StreamPredictor(); int lookChar(); int getChar(); 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); private: int buf; GBool eof; }; //------------------------------------------------------------------------ // ASCII85Stream //------------------------------------------------------------------------ class ASCII85Stream: public FilterStream { public: ASCII85Stream(Stream *strA); virtual ~ASCII85Stream(); virtual StreamKind getKind() { return strASCII85; } virtual void reset(); virtual int getChar() { int ch = lookChar(); ++index; return ch; } virtual int lookChar(); virtual GString *getPSFilter(char *indent); virtual GBool isBinary(GBool last = gTrue); private: int c[5]; int b[4]; int index, n; GBool eof; }; //------------------------------------------------------------------------ // LZWStream //------------------------------------------------------------------------ class LZWStream: public FilterStream { public: LZWStream(Stream *strA, int predictor, int columns, int colors, int bits, int earlyA); virtual ~LZWStream(); virtual StreamKind getKind() { return strLZW; } virtual void reset(); virtual int getChar(); virtual int lookChar(); virtual int getRawChar(); virtual GString *getPSFilter(char *indent); virtual GBool isBinary(GBool last = gTrue); private: StreamPredictor *pred; // predictor int early; // early parameter FILE *zPipe; // uncompress pipe GString *zName; // .Z file name int inputBuf; // input buffer int inputBits; // number of bits in input buffer int inCodeBits; // size of input code char buf[256]; // buffer char *bufPtr; // next char to read char *bufEnd; // end of buffer void dumpFile(FILE *f); int getCode(); GBool fillBuf(); }; //------------------------------------------------------------------------ // RunLengthStream //------------------------------------------------------------------------ class RunLengthStream: public FilterStream { @@ -566,158 +612,189 @@ struct FlateHuffmanTab { // Decoding info for length and distance code words struct FlateDecode { int bits; // # extra bits int first; // first length/distance }; class FlateStream: public FilterStream { public: FlateStream(Stream *strA, int predictor, int columns, int colors, int bits); virtual ~FlateStream(); virtual StreamKind getKind() { return strFlate; } virtual void reset(); virtual int getChar(); virtual int lookChar(); virtual int getRawChar(); virtual GString *getPSFilter(char *indent); virtual GBool isBinary(GBool last = gTrue); private: StreamPredictor *pred; // predictor Guchar buf[flateWindow]; // output data buffer int index; // current index into output buffer int remain; // number valid bytes in output buffer int codeBuf; // input buffer int codeSize; // number of bits in input buffer FlateCode // literal and distance codes allCodes[flateMaxLitCodes + flateMaxDistCodes]; FlateHuffmanTab litCodeTab; // literal code table FlateHuffmanTab distCodeTab; // distance code table GBool compressedBlock; // set if reading a compressed block int blockLen; // remaining length of uncompressed block GBool endOfBlock; // set when end of block is reached GBool eof; // set when end of stream is reached static int // code length code reordering codeLenCodeMap[flateMaxCodeLenCodes]; static FlateDecode // length decoding info lengthDecode[flateMaxLitCodes-257]; static FlateDecode // distance decoding info distDecode[flateMaxDistCodes]; void readSome(); GBool startBlock(); void loadFixedCodes(); GBool readDynamicCodes(); void compHuffmanCodes(FlateHuffmanTab *tab, int n); int getHuffmanCodeWord(FlateHuffmanTab *tab); int getCodeWord(int bits); }; //------------------------------------------------------------------------ // EOFStream //------------------------------------------------------------------------ class EOFStream: public FilterStream { public: EOFStream(Stream *strA); virtual ~EOFStream(); virtual StreamKind getKind() { return strWeird; } virtual void reset() {} virtual int getChar() { return EOF; } virtual int lookChar() { return EOF; } virtual GString *getPSFilter(char *indent) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gFalse; } }; //------------------------------------------------------------------------ // 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; int lineLen; GBool eof; GBool fillBuf(); }; //------------------------------------------------------------------------ // RunLengthEncoder //------------------------------------------------------------------------ class RunLengthEncoder: public FilterStream { public: RunLengthEncoder(Stream *strA); virtual ~RunLengthEncoder(); 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[131]; char *bufPtr; char *bufEnd; char *nextEnd; GBool eof; GBool fillBuf(); }; #endif 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,254 +1,266 @@ //======================================================================== // // 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; } xMax = xRight[len] = x + dx; ++len; } //------------------------------------------------------------------------ // 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; } // insert string in y-major list h = curStr->yMax - curStr->yMin; y1 = curStr->yMin + 0.5 * h; y2 = curStr->yMin + 0.8 * h; if (rawOrder) { p1 = yxCur1; p2 = NULL; } else if ((!yxCur1 || (y1 >= yxCur1->yMin && (y2 >= yxCur1->yMax || curStr->xMax >= yxCur1->xMin))) && (!yxCur2 || (y1 < yxCur2->yMin || (y2 < yxCur2->yMax && curStr->xMax < yxCur2->xMin)))) { p1 = yxCur1; p2 = yxCur2; } else { for (p1 = NULL, p2 = yxStrings; p2; p1 = p2, p2 = p2->yxNext) { if (y1 < p2->yMin || (y2 < p2->yMax && curStr->xMax < p2->xMin)) { break; } } yxCur2 = p2; } yxCur1 = curStr; if (p1) { p1->yxNext = curStr; } else { yxStrings = curStr; } curStr->yxNext = p2; curStr = NULL; } void TextPage::coalesce() { TextString *str1, *str2; fouble space, d; GBool addSpace; int n, i; #if 0 //~ for debugging for (str1 = yxStrings; str1; str1 = str1->yxNext) { printf("x=%3d..%3d y=%3d..%3d size=%2d '", (int)str1->xMin, (int)str1->xMax, (int)str1->yMin, (int)str1->yMax, (int)(str1->yMax - str1->yMin)); for (i = 0; i < str1->len; ++i) { fputc(str1->text[i] & 0xff, stdout); } printf("'\n"); } printf("\n------------------------------------------------------------\n\n"); #endif str1 = yxStrings; while (str1 && (str2 = str1->yxNext)) { space = str1->yMax - str1->yMin; d = str2->xMin - str1->xMax; if (((rawOrder && ((str2->yMin >= str1->yMin && str2->yMin <= str1->yMax) || (str2->yMax >= str1->yMin && str2->yMax <= str1->yMax))) || (!rawOrder && str2->yMin < str1->yMax)) && d > -0.5 * space && d < space) { n = str1->len + str2->len; if ((addSpace = d > 0.1 * space)) { ++n; } str1->size = (n + 15) & ~15; str1->text = (Unicode *)grealloc(str1->text, str1->size * sizeof(Unicode)); str1->xRight = (fouble *)grealloc(str1->xRight, str1->size * sizeof(fouble)); if (addSpace) { str1->text[str1->len] = 0x20; str1->xRight[str1->len] = str2->xMin; @@ -336,351 +348,366 @@ GBool TextPage::findText(Unicode *s, int len, if (u1 != u2) { break; } } // found it if (j == len) { *xMin = (i == 0) ? str->xMin : str->xRight[i-1]; *xMax = str->xRight[i + len - 1]; *yMin = str->yMin; *yMax = str->yMax; return gTrue; } } } return gFalse; } GString *TextPage::getText(fouble xMin, fouble yMin, fouble xMax, fouble yMax) { GString *s; UnicodeMap *uMap; char space[8], eol[16], buf[8]; int spaceLen, eolLen, n; TextString *str1; fouble x0, x1, x2, y; fouble xPrev, yPrev; int i1, i2, i; GBool multiLine; s = new GString(); if (!(uMap = globalParams->getTextEncoding())) { return s; } 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; } xPrev = yPrev = 0; multiLine = gFalse; for (str1 = yxStrings; str1; str1 = str1->yxNext) { y = 0.5 * (str1->yMin + str1->yMax); if (y > yMax) { break; } if (y > yMin && str1->xMin < xMax && str1->xMax > xMin) { x0 = x1 = x2 = str1->xMin; for (i1 = 0; i1 < str1->len; ++i1) { x0 = (i1==0) ? str1->xMin : str1->xRight[i1-1]; x1 = str1->xRight[i1]; if (0.5 * (x0 + x1) >= xMin) { break; } } for (i2 = str1->len - 1; i2 > i1; --i2) { x1 = (i2==0) ? str1->xMin : str1->xRight[i2-1]; x2 = str1->xRight[i2]; if (0.5 * (x1 + x2) <= xMax) { break; } } if (s->getLength() > 0) { 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; } eopLen = uMap->mapUnicode(0x0c, eop, sizeof(eop)); // build x-major list xyStrings = NULL; for (str1 = yxStrings; str1; str1 = str1->yxNext) { for (str2 = NULL, str3 = xyStrings; str3; str2 = str3, str3 = str3->xyNext) { if (str1->xMin < str3->xMin || (str1->xMin == str3->xMin && str1->yMin < str3->yMin)) { break; } } if (str2) { str2->xyNext = str1; } else { xyStrings = str1; } str1->xyNext = str3; } // 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, fouble *xMin, fouble *yMin, fouble *xMax, fouble *yMax) { return text->findText(s, len, top, bottom, xMin, yMin, xMax, yMax); } 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,189 +1,203 @@ //======================================================================== // // 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 int size; // size of text and xRight arrays TextString *yxNext; // next string in y-major order TextString *xyNext; // next string in x-major order friend class TextPage; }; //------------------------------------------------------------------------ // TextPage //------------------------------------------------------------------------ class TextPage { public: // Constructor. TextPage(GBool rawOrderA); // Destructor. ~TextPage(); // Update the current font. void updateFont(GfxState *state); // Begin a new string. void beginString(GfxState *state); // Add a character to the current string. 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,101 +1,101 @@ //======================================================================== // // 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 char code[maxExtCode]; Guint nBytes; }; //------------------------------------------------------------------------ UnicodeMap *UnicodeMap::parse(GString *encodingNameA) { FILE *f; UnicodeMap *map; UnicodeMapRange *range; UnicodeMapExt *eMap; int size, eMapsSize; char buf[256]; int line, nBytes, i, x; char *tok1, *tok2, *tok3; if (!(f = globalParams->getUnicodeMapFile(encodingNameA))) { error(-1, "Couldn't find unicodeMap file for the '%s' encoding", encodingNameA->getCString()); return NULL; } map = new UnicodeMap(encodingNameA->copy()); size = 8; map->ranges = (UnicodeMapRange *)gmalloc(size * sizeof(UnicodeMapRange)); eMapsSize = 0; line = 1; while (getLine(buf, sizeof(buf), f)) { if ((tok1 = strtok(buf, " \t\r\n")) && (tok2 = strtok(NULL, " \t\r\n"))) { if (!(tok3 = strtok(NULL, " \t\r\n"))) { tok3 = tok2; tok2 = tok1; } nBytes = strlen(tok3) / 2; if (nBytes <= 4) { if (map->len == size) { size *= 2; map->ranges = (UnicodeMapRange *) grealloc(map->ranges, size * sizeof(UnicodeMapRange)); } range = &map->ranges[map->len]; sscanf(tok1, "%x", &range->start); sscanf(tok2, "%x", &range->end); sscanf(tok3, "%x", &range->code); range->nBytes = nBytes; ++map->len; } else if (tok2 == tok1) { if (map->eMapsLen == eMapsSize) { eMapsSize += 16; map->eMaps = (UnicodeMapExt *) grealloc(map->eMaps, eMapsSize * sizeof(UnicodeMapExt)); } eMap = &map->eMaps[map->eMapsLen]; sscanf(tok1, "%x", &eMap->u); for (i = 0; i < nBytes; ++i) { sscanf(tok3 + i*2, "%2x", &x); eMap->code[i] = (char)x; } eMap->nBytes = nBytes; ++map->eMapsLen; } else { error(-1, "Bad line (%d) in unicodeMap file for the '%s' encoding", line, encodingNameA->getCString()); } } else { error(-1, "Bad line (%d) in unicodeMap file for the '%s' encoding", line, encodingNameA->getCString()); } ++line; 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,103 +1,103 @@ //======================================================================== // // 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); struct UnicodeMapRange { Unicode start, end; // range of Unicode chars Guint code, nBytes; // first output code }; struct UnicodeMapExt; //------------------------------------------------------------------------ class UnicodeMap { public: // Create the UnicodeMap specified by <encodingName>. Sets the // initial reference count to 1. Returns NULL on failure. static UnicodeMap *parse(GString *encodingNameA); // Create a resident UnicodeMap. UnicodeMap(char *encodingNameA, UnicodeMapRange *rangesA, int lenA); // Create a resident UnicodeMap that uses a function instead of a // list of ranges. UnicodeMap(char *encodingNameA, UnicodeMapFunc funcA); ~UnicodeMap(); void incRefCnt(); void decRefCnt(); GString *getEncodingName() { return encodingName; } // Return true if this UnicodeMap matches the specified // <encodingNameA>. GBool match(GString *encodingNameA); // Map Unicode to the target encoding. Fills in <buf> with the // output and returns the number of bytes used. Output will be // truncated at <bufSize> bytes. No string terminator is written. // Returns 0 if no mapping is found. int mapUnicode(Unicode u, char *buf, int bufSize); private: UnicodeMap(GString *encodingNameA); GString *encodingName; UnicodeMapKind kind; union { UnicodeMapRange *ranges; // (user, resident) UnicodeMapFunc func; // (func) }; int len; // (user, resident) UnicodeMapExt *eMaps; // (user) int eMapsLen; // (user) int refCnt; }; //------------------------------------------------------------------------ #define unicodeMapCacheSize 4 class UnicodeMapCache { public: UnicodeMapCache(); ~UnicodeMapCache(); // Get the UnicodeMap for <encodingName>. Increments its reference // count; there will be one reference for the cache plus one for the // caller of this function. Returns NULL on failure. UnicodeMap *getUnicodeMap(GString *encodingName); 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,233 +1,291 @@ //======================================================================== // // 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 }, { 0x00c4, 0x00c4, 0x41, 1 }, { 0x00c5, 0x00c5, 0x41, 1 }, { 0x00c6, 0x00c6, 0x4145, 2 }, { 0x00c7, 0x00c7, 0x43, 1 }, { 0x00c8, 0x00c8, 0x45, 1 }, { 0x00c9, 0x00c9, 0x45, 1 }, { 0x00ca, 0x00ca, 0x45, 1 }, { 0x00cb, 0x00cb, 0x45, 1 }, { 0x00cc, 0x00cc, 0x49, 1 }, { 0x00cd, 0x00cd, 0x49, 1 }, { 0x00ce, 0x00ce, 0x49, 1 }, { 0x00cf, 0x00cf, 0x49, 1 }, { 0x00d1, 0x00d2, 0x4e, 1 }, { 0x00d3, 0x00d3, 0x4f, 1 }, { 0x00d4, 0x00d4, 0x4f, 1 }, { 0x00d5, 0x00d5, 0x4f, 1 }, { 0x00d6, 0x00d6, 0x4f, 1 }, { 0x00d7, 0x00d7, 0x78, 1 }, { 0x00d8, 0x00d8, 0x4f, 1 }, { 0x00d9, 0x00d9, 0x55, 1 }, { 0x00da, 0x00da, 0x55, 1 }, { 0x00db, 0x00db, 0x55, 1 }, { 0x00dc, 0x00dc, 0x55, 1 }, { 0x00dd, 0x00dd, 0x59, 1 }, { 0x00e0, 0x00e0, 0x61, 1 }, { 0x00e1, 0x00e1, 0x61, 1 }, { 0x00e2, 0x00e2, 0x61, 1 }, { 0x00e3, 0x00e3, 0x61, 1 }, { 0x00e4, 0x00e4, 0x61, 1 }, { 0x00e5, 0x00e5, 0x61, 1 }, { 0x00e6, 0x00e6, 0x6165, 2 }, { 0x00e7, 0x00e7, 0x63, 1 }, { 0x00e8, 0x00e8, 0x65, 1 }, { 0x00e9, 0x00e9, 0x65, 1 }, { 0x00ea, 0x00ea, 0x65, 1 }, { 0x00eb, 0x00eb, 0x65, 1 }, { 0x00ec, 0x00ec, 0x69, 1 }, { 0x00ed, 0x00ed, 0x69, 1 }, { 0x00ee, 0x00ee, 0x69, 1 }, { 0x00ef, 0x00ef, 0x69, 1 }, { 0x00f1, 0x00f2, 0x6e, 1 }, { 0x00f3, 0x00f3, 0x6f, 1 }, { 0x00f4, 0x00f4, 0x6f, 1 }, { 0x00f5, 0x00f5, 0x6f, 1 }, { 0x00f6, 0x00f6, 0x6f, 1 }, { 0x00f7, 0x00f7, 0x2f, 1 }, { 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 }, { 0x0192, 0x0192, 0xa6, 1 }, { 0x0391, 0x0392, 0x41, 1 }, { 0x0393, 0x0393, 0x47, 1 }, { 0x0395, 0x0395, 0x45, 1 }, { 0x0396, 0x0396, 0x5a, 1 }, { 0x0397, 0x0397, 0x48, 1 }, { 0x0398, 0x0398, 0x51, 1 }, { 0x0399, 0x0399, 0x49, 1 }, { 0x039a, 0x039d, 0x4b, 1 }, { 0x039e, 0x039e, 0x58, 1 }, { 0x039f, 0x03a0, 0x4f, 1 }, { 0x03a1, 0x03a1, 0x52, 1 }, { 0x03a3, 0x03a5, 0x53, 1 }, { 0x03a6, 0x03a6, 0x46, 1 }, { 0x03a7, 0x03a7, 0x43, 1 }, { 0x03a8, 0x03a8, 0x59, 1 }, { 0x03b1, 0x03b2, 0x61, 1 }, { 0x03b3, 0x03b3, 0x67, 1 }, { 0x03b4, 0x03b5, 0x64, 1 }, { 0x03b6, 0x03b6, 0x7a, 1 }, { 0x03b7, 0x03b7, 0x68, 1 }, { 0x03b8, 0x03b8, 0x71, 1 }, { 0x03b9, 0x03b9, 0x69, 1 }, { 0x03ba, 0x03bb, 0x6b, 1 }, { 0x03bd, 0x03bd, 0x6e, 1 }, { 0x03be, 0x03be, 0x78, 1 }, { 0x03bf, 0x03c0, 0x6f, 1 }, { 0x03c1, 0x03c1, 0x72, 1 }, { 0x03c2, 0x03c2, 0x56, 1 }, { 0x03c3, 0x03c5, 0x73, 1 }, { 0x03c6, 0x03c6, 0x66, 1 }, { 0x03c7, 0x03c7, 0x63, 1 }, { 0x03c8, 0x03c8, 0x79, 1 }, { 0x03c9, 0x03c9, 0x77, 1 }, { 0x03d1, 0x03d1, 0x4a, 1 }, { 0x03d2, 0x03d2, 0xa1, 1 }, { 0x03d5, 0x03d5, 0x6a, 1 }, { 0x03d6, 0x03d6, 0x76, 1 }, { 0x2022, 0x2022, 0xb7, 1 }, { 0x2026, 0x2026, 0xbc, 1 }, { 0x2032, 0x2032, 0xa2, 1 }, { 0x2033, 0x2033, 0xb2, 1 }, { 0x2044, 0x2044, 0xa4, 1 }, { 0x2111, 0x2111, 0xc1, 1 }, { 0x2118, 0x2118, 0xc3, 1 }, { 0x211c, 0x211c, 0xc2, 1 }, { 0x2126, 0x2126, 0x57, 1 }, { 0x2135, 0x2135, 0xc0, 1 }, { 0x2190, 0x2193, 0xac, 1 }, { 0x2194, 0x2194, 0xab, 1 }, { 0x21b5, 0x21b5, 0xbf, 1 }, { 0x21d0, 0x21d3, 0xdc, 1 }, { 0x21d4, 0x21d4, 0xdb, 1 }, { 0x2200, 0x2200, 0x22, 1 }, { 0x2202, 0x2202, 0xb6, 1 }, { 0x2203, 0x2203, 0x24, 1 }, { 0x2205, 0x2205, 0xc6, 1 }, { 0x2206, 0x2206, 0x44, 1 }, { 0x2207, 0x2207, 0xd1, 1 }, { 0x2208, 0x2209, 0xce, 1 }, { 0x220b, 0x220b, 0x27, 1 }, { 0x220f, 0x220f, 0xd5, 1 }, { 0x2211, 0x2211, 0xe5, 1 }, { 0x2212, 0x2212, 0x2d, 1 }, { 0x2217, 0x2217, 0x2a, 1 }, { 0x221a, 0x221a, 0xd6, 1 }, { 0x221d, 0x221d, 0xb5, 1 }, { 0x221e, 0x221e, 0xa5, 1 }, { 0x2220, 0x2220, 0xd0, 1 }, { 0x2227, 0x2228, 0xd9, 1 }, { 0x2229, 0x222a, 0xc7, 1 }, { 0x222b, 0x222b, 0xf2, 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,641 +1,665 @@ //======================================================================== // // 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(); } if (c == 't') { break; } for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) { s[i] = (char)c; } if (i == 0) { 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())) { ret = gTrue; encrypt.dictLookup("Filter", &filterObj); if (filterObj.isName("Standard")) { encrypt.dictLookup("V", &versionObj); encrypt.dictLookup("R", &revisionObj); encrypt.dictLookup("Length", &lengthObj); encrypt.dictLookup("O", &ownerKey); encrypt.dictLookup("U", &userKey); encrypt.dictLookup("P", &permissions); trailerDict.dictLookup("ID", &fileID); if (versionObj.isInt() && revisionObj.isInt() && ownerKey.isString() && ownerKey.getString()->getLength() == 32 && userKey.isString() && userKey.getString()->getLength() == 32 && permissions.isInt() && fileID.isArray()) { encVersion = versionObj.getInt(); encRevision = revisionObj.getInt(); if (lengthObj.isInt()) { keyLength = lengthObj.getInt() / 8; } else { keyLength = 5; } permFlags = permissions.getInt(); if (encVersion >= 1 && encVersion <= 2 && encRevision >= 2 && encRevision <= 3) { fileID.arrayGet(0, &fileID1); if (fileID1.isString()) { if (Decrypt::makeFileKey(encVersion, encRevision, keyLength, ownerKey.getString(), userKey.getString(), permFlags, fileID1.getString(), ownerPassword, userPassword, fileKey, &ownerPasswordOk)) { if (ownerPassword && !ownerPasswordOk) { error(-1, "Incorrect owner password"); } ret = gFalse; } else { error(-1, "Incorrect password"); } } else { error(-1, "Weird encryption info"); } fileID1.free(); } else { error(-1, "Unsupported version/revision (%d/%d) of Standard security handler", encVersion, encRevision); } } else { error(-1, "Weird encryption info"); } fileID.free(); permissions.free(); userKey.free(); ownerKey.free(); lengthObj.free(); revisionObj.free(); versionObj.free(); } else { error(-1, "Unknown security handler '%s'", filterObj.isName() ? filterObj.getName() : "???"); } filterObj.free(); } encrypt.free(); // this flag has to be set *after* we read the O/U/P strings encrypted = encrypted1; return ret; } #else GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) { Object obj; GBool encrypted; trailerDict.dictLookup("Encrypt", &obj); if ((encrypted = !obj.isNull())) { error(-1, "PDF file is encrypted and this version of the Xpdf tools"); error(-1, "was built without decryption support."); } obj.free(); return encrypted; } #endif GBool XRef::okToPrint(GBool ignoreOwnerPW) { #ifndef NO_DECRYPTION if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permPrint)) { return gFalse; } #endif return gTrue; } GBool XRef::okToChange(GBool ignoreOwnerPW) { #ifndef NO_DECRYPTION if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permChange)) { return gFalse; } #endif return gTrue; } GBool XRef::okToCopy(GBool ignoreOwnerPW) { #ifndef NO_DECRYPTION if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permCopy)) { return gFalse; } #endif 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 |