[poppler] 5 commits - goo/GooVector.h poppler/Gfx.cc poppler/GfxFont.cc poppler/Gfx.h
Albert Astals Cid
aacid at kemper.freedesktop.org
Wed Jan 27 14:42:58 PST 2010
goo/GooVector.h | 237 +++++++++++++++++++++++++++++++----------------------
poppler/Gfx.cc | 45 +++++++++-
poppler/Gfx.h | 13 ++
poppler/GfxFont.cc | 8 +
4 files changed, 203 insertions(+), 100 deletions(-)
New commits:
commit 309228404710debee4337cc53c641dfef64ad86c
Author: David Benjamin <davidben at mit.edu>
Date: Wed Jan 27 22:41:16 2010 +0000
Allow commands to abort the current stream
In many instances, the sensible response (and what acroread does) in
case of an error is abort the PDF stream. To avoid changing the return
value of every function and using C++ exceptions, we communicate via a
commandAborted variable.
This patch, matching acroread's behavior aborts the current stream when
there are too few arguments or we pop too many times. Implementation
note 39 in Appendix H of the PDF reference contradicts the former, but
hand-crafted test PDFs as well as the file in #24575 suggest otherwise.
Unlike all the other attempts, this patch actually fixes the PDF in
bug #24575.
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index a3ed723..9b6e96b 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -680,6 +680,7 @@ void Gfx::go(GBool topLevel) {
numArgs = 0;
parser->getObj(&obj);
while (!obj.isEOF()) {
+ commandAborted = gFalse;
// got a command - execute it
if (obj.isCmd()) {
@@ -727,6 +728,14 @@ void Gfx::go(GBool topLevel) {
updateLevel = 0;
}
+ // did the command throw an exception
+ if (commandAborted) {
+ // don't propogate; recursive drawing comes from Form XObjects which
+ // should probably be drawn in a separate context anyway for caching
+ commandAborted = gFalse;
+ break;
+ }
+
// check for an abort
if (abortCheckCbk) {
if (updateLevel - lastAbortCheck > 10) {
@@ -801,6 +810,7 @@ void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
if (op->numArgs >= 0) {
if (numArgs < op->numArgs) {
error(getPos(), "Too few (%d) args to '%s' operator", numArgs, name);
+ commandAborted = gTrue;
return;
}
if (numArgs > op->numArgs) {
@@ -4779,6 +4789,7 @@ void Gfx::saveState() {
void Gfx::restoreState() {
if (stackHeight <= bottomGuard() || !state->hasSaves()) {
error(-1, "Restoring state when no valid states to pop");
+ commandAborted = gTrue;
return;
}
state = state->restore();
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index fb4e364..3e12509 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -195,6 +195,7 @@ private:
GBool textHaveCSPattern; // in text drawing and text has pattern colorspace
GBool drawText; // in text drawing
GBool maskHaveCSPattern; // in mask drawing and mask has pattern colorspace
+ GBool commandAborted; // did the previous command abort the drawing?
GfxColorSpace *colorSpaceText;// colorspace after text has filled with pattern
GfxColor colorText; // fill color after after text has filled with pattern
GfxResources *res; // resource stack
commit 8284008aa8230a92ba08d547864353d3290e9bf9
Author: David Benjamin <davidben at mit.edu>
Date: Wed Jan 27 22:40:33 2010 +0000
Add a stack of stateGuards to Gfx
While a stack of states is a good way to maintain graphics contexts, if
the command stream you are interpreting is untrusted, we must place
appropriate guards to be sure that, not only do we not pop past the end
of the stack, but we do not pop past the stack as it was when we began
rendering.
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index a9429b8..a3ed723 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -30,7 +30,7 @@
// Copyright (C) 2009 M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
// Copyright (C) 2009 William Bader <williambader at hotmail.com>
-// Copyright (C) 2009 David Benjamin <davidben at mit.edu>
+// Copyright (C) 2009, 2010 David Benjamin <davidben at mit.edu>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -543,6 +543,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, Catalog *cata
out = outA;
state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown());
stackHeight = 1;
+ pushStateGuard();
fontChanged = gFalse;
clip = clipNone;
ignoreUndef = 0;
@@ -596,6 +597,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, Catalog *catalogA,
out = outA;
state = new GfxState(72, 72, box, 0, gFalse);
stackHeight = 1;
+ pushStateGuard();
fontChanged = gFalse;
clip = clipNone;
ignoreUndef = 0;
@@ -620,7 +622,12 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, Catalog *catalogA,
}
Gfx::~Gfx() {
+ while (stateGuards.size()) {
+ popStateGuard();
+ }
+ // There shouldn't be more saves, but pop them if there were any
while (state->hasSaves()) {
+ error(-1, "Found state under last state guard. Popping.");
restoreState();
}
if (!subPage) {
@@ -668,6 +675,7 @@ void Gfx::go(GBool topLevel) {
int lastAbortCheck;
// scan a sequence of objects
+ pushStateGuard();
updateLevel = lastAbortCheck = 0;
numArgs = 0;
parser->getObj(&obj);
@@ -766,6 +774,8 @@ void Gfx::go(GBool topLevel) {
args[i].free();
}
+ popStateGuard();
+
// update display
if (topLevel && updateLevel > 0) {
out->dump();
@@ -4746,6 +4756,20 @@ void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor, double
}
}
+int Gfx::bottomGuard() {
+ return stateGuards[stateGuards.size()-1];
+}
+
+void Gfx::pushStateGuard() {
+ stateGuards.push_back(stackHeight);
+}
+
+void Gfx::popStateGuard() {
+ while (stackHeight > bottomGuard() && state->hasSaves())
+ restoreState();
+ stateGuards.pop_back();
+}
+
void Gfx::saveState() {
out->saveState(state);
state = state->save();
@@ -4753,6 +4777,10 @@ void Gfx::saveState() {
}
void Gfx::restoreState() {
+ if (stackHeight <= bottomGuard() || !state->hasSaves()) {
+ error(-1, "Restoring state when no valid states to pop");
+ return;
+ }
state = state->restore();
out->restoreState(state);
stackHeight--;
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index 2a808ce..fb4e364 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -19,6 +19,7 @@
// Copyright (C) 2008, 2010 Carlos Garcia Campos <carlosgc at gnome.org>
// Copyright (C) 2009 Albert Astals Cid <aacid at kde.org>
// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2010 David Benjamin <davidben at mit.edu>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -34,6 +35,7 @@
#include "goo/gtypes.h"
#include "goo/GooList.h"
+#include "goo/GooVector.h"
#include "GfxState.h"
#include "Object.h"
#include "PopplerCache.h"
@@ -163,9 +165,15 @@ public:
// Save graphics state.
void saveState();
+ // Push a new state guard
+ void pushStateGuard();
+
// Restore graphics state.
void restoreState();
+ // Pop to state guard and pop guard
+ void popStateGuard();
+
// Get the current graphics state object.
GfxState *getState() { return state; }
@@ -194,6 +202,7 @@ private:
GfxState *state; // current graphics state
int stackHeight; // the height of the current graphics stack
+ GooVector<int> stateGuards; // a stack of state limits; to guard against unmatched pops
GBool fontChanged; // set if font or text matrix has changed
GfxClipType clip; // do a clip?
int ignoreUndef; // current BX/EX nesting level
@@ -221,6 +230,8 @@ private:
GBool checkArg(Object *arg, TchkType type);
int getPos();
+ int bottomGuard();
+
// graphics state operators
void opSave(Object args[], int numArgs);
void opRestore(Object args[], int numArgs);
commit 4ae84c830f842d100cbb702b32970951a5a5769f
Author: David Benjamin <davidben at mit.edu>
Date: Wed Jan 27 22:39:20 2010 +0000
Maintain the height of the stack in Gfx
Introduces a new variable Gfx::stackHeight that maintains up-to-date
information about the current height of the stack.
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index a8713a4..a9429b8 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -542,6 +542,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, Catalog *cata
// initialize
out = outA;
state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown());
+ stackHeight = 1;
fontChanged = gFalse;
clip = clipNone;
ignoreUndef = 0;
@@ -594,6 +595,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, Catalog *catalogA,
// initialize
out = outA;
state = new GfxState(72, 72, box, 0, gFalse);
+ stackHeight = 1;
fontChanged = gFalse;
clip = clipNone;
ignoreUndef = 0;
@@ -4747,11 +4749,13 @@ void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor, double
void Gfx::saveState() {
out->saveState(state);
state = state->save();
+ stackHeight++;
}
void Gfx::restoreState() {
state = state->restore();
out->restoreState(state);
+ stackHeight--;
}
void Gfx::pushResources(Dict *resDict) {
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index 3025b6c..2a808ce 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -193,6 +193,7 @@ private:
int updateLevel;
GfxState *state; // current graphics state
+ int stackHeight; // the height of the current graphics stack
GBool fontChanged; // set if font or text matrix has changed
GfxClipType clip; // do a clip?
int ignoreUndef; // current BX/EX nesting level
commit 120fe6ef673c648ae7b19ad2a7e9aef22ee25810
Author: David Benjamin <davidben at mit.edu>
Date: Wed Jan 27 22:38:43 2010 +0000
Do not use objects just after deleting them
The error condition in GfxCIDFont::GfxCIDFont references cMapName and
collection, so they should not be deleted yet.
diff --git a/poppler/GfxFont.cc b/poppler/GfxFont.cc
index e7d564a..f823faf 100644
--- a/poppler/GfxFont.cc
+++ b/poppler/GfxFont.cc
@@ -21,7 +21,7 @@
// Copyright (C) 2008 Ed Avis <eda at waniasset.com>
// Copyright (C) 2008 Hib Eris <hib at hiberis.nl>
// Copyright (C) 2009 Peter Kerzum <kerzum at yandex-team.ru>
-// Copyright (C) 2009 David Benjamin <davidben at mit.edu>
+// Copyright (C) 2009, 2010 David Benjamin <davidben at mit.edu>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -1489,13 +1489,15 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GooString *nameA,
cMapName = new GooString(obj1.getName());
cMap = globalParams->getCMap(collection, cMapName);
}
- delete collection;
- delete cMapName;
if (!cMap) {
error(-1, "Unknown CMap '%s' for character collection '%s'",
cMapName->getCString(), collection->getCString());
+ delete collection;
+ delete cMapName;
goto err2;
}
+ delete collection;
+ delete cMapName;
obj1.free();
// CIDToGIDMap (for embedded TrueType fonts)
commit 3375fa96c7a7dbbb98f5a7b3df9e840a5f30bc80
Author: Albert Astals Cid <aacid at kde.org>
Date: Wed Jan 27 22:32:29 2010 +0000
GooVector rewrite, old version had "unknown" origins/license
diff --git a/goo/GooVector.h b/goo/GooVector.h
index 31a72e9..d396c6f 100644
--- a/goo/GooVector.h
+++ b/goo/GooVector.h
@@ -1,113 +1,158 @@
//========================================================================
//
-// This file comes from pdftohtml project
-// http://pdftohtml.sourceforge.net
+// GooVector.h
//
-// Copyright from:
-// Gueorgui Ovtcharov
-// Rainer Dorsch <http://www.ra.informatik.uni-stuttgart.de/~rainer/>
-// Mikhail Kruk <meshko at cs.brandeis.edu>
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 David Benjamin <davidben at mit.edu>
//
//========================================================================
-#ifndef GOO_VECTOR_H
-#define GOO_VECTOR_H
-#include "goo/gtypes.h"
-
-
-template<class T>
-class GooVector{
-private:
-
- int _size;
- T* last;
- T* storage;
-
- void resize(){
- if (_size==0) _size=2;else _size=2*_size;
- T *tmp=new T[_size];
- if (storage){
- last=copy(storage,last,tmp);
- delete [] storage;
- }
- else last=tmp;
- storage=tmp;
- }
-
- T* copy(T* src1,T* src2,T* dest){
- T* tmp=src1;
- T* d=dest;
- while(tmp!=src2){
- *d=*tmp;
- d++;tmp++;
- }
- return d;
- }
-
-public:
- typedef T* iterator;
- GooVector(){
- _size=0;
- last=0;
- storage=0;
-}
+#ifndef GOO_GOOVECTOR_H
+#define GOO_GOOVECTOR_H
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
-virtual ~GooVector(){
- delete[] storage ;
-}
-
-void reset(){
- last=storage;
-}
-
-int size(){
- return (last-storage);
-}
-void push_back(const T& elem){
- if (!storage||(size() >=_size)) resize();
- *last=elem;
- last++;
-
-
-}
-
-
-T pop_back() {
- if (last!=storage) last--;
+#include <new> // vector implementations need placement-new
- return *last;
-}
+#include <assert.h>
+#include <stdlib.h>
+/* Mostly STL-compatible vector class. Should correctly call constructors and
+ * destructors, but does not carefully handle alignment requirements. */
-T operator[](unsigned int i){
- return *(storage+i);
-}
+template<class T> class GooVector {
+public:
+ /* various STL-compatible typedefs */
+ typedef T value_type;
+ typedef T* pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef size_t size_type;
+ typedef int difference_type;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+ // TODO: reverse_iterator, if we feel like it
+ GooVector() : m_data(NULL), m_capacity(0), m_size(0) {}
+ explicit GooVector(size_type n) : m_data(NULL), m_capacity(0), m_size(0) {
+ resize(n);
+ }
+ explicit GooVector(size_type n, const T& t) : m_data(NULL), m_capacity(0), m_size(0) {
+ resize(n, t);
+ }
+ explicit GooVector(const GooVector& gv) : m_data(NULL), m_capacity(0), m_size(0) {
+ reserve(gv.size());
+ for (size_type i = 0; i < m_size; i++) {
+ push_back(gv[i]);
+ }
+ }
+
+ ~GooVector() {
+ clear();
+ }
+
+ iterator begin() { return m_data; }
+ const_iterator begin() const { return m_data; }
+ iterator end() { return m_data + m_capacity; }
+ const_iterator end() const { return m_data + m_capacity; }
+
+ size_type size() const { return m_size; }
+ size_type capacity() const { return m_capacity; }
+
+ bool empty() const { return m_size == 0; }
+
+ reference operator[] (size_type n) { return m_data[n]; }
+ const_reference operator[] (size_type n) const { return m_data[n]; }
+
+ reference at(size_type n) {
+ assert(n < m_size);
+ return m_data[n];
+ }
+ const_reference at(size_type n) const {
+ assert(n < m_size);
+ return m_data[n];
+ }
+
+ reference front() { assert(!empty()); return m_data[0]; }
+ const_reference front() const { assert(!empty()); return m_data[0]; }
+
+ reference back() { assert(!empty()); return m_data[m_size-1]; }
+ const_reference back() const { assert(!empty()); return m_data[m_size-1]; }
+
+ void push_back(const T& v) {
+ reserve(m_size + 1);
+ place_new(m_data + m_size, v);
+ m_size++;
+ }
+ void pop_back() {
+ assert(!empty());
+ m_size--;
+ destruct(m_data + m_size);
+ }
+
+ void clear() {
+ for (size_t i = 0; i < m_size; i++) {
+ destruct(m_data + i);
+ }
+ m_size = 0;
+ free(m_data);
+ m_data = NULL;
+ m_capacity = 0;
+ }
+
+ void reserve(size_type cap) {
+ if (m_capacity >= cap) return;
+ // make sure we always at least double
+ if (m_capacity*2 > cap)
+ cap = m_capacity*2;
+ resize_internal(cap);
+ }
+
+ void resize(size_type n) { resize(n, T()); }
+ void resize(size_type n, const T& t) {
+ reserve(n);
+ while (m_size < n)
+ push_back(t);
+ while (m_size > n)
+ pop_back();
+ }
-GBool isEmpty() const{
- return !_size || (last==storage) ;
-}
-
-
-
-iterator begin() const{
- return storage;
-}
-
-iterator end() const {
- return last;
-}
+private:
+ T *m_data;
+ size_type m_capacity;
+ size_type m_size;
+
+ inline void destruct(T *obj) {
+ obj->~T();
+ }
+ inline void place_new(T *loc, const T& v) {
+ new (loc) T(v);
+ }
+
+ inline void resize_internal(size_type new_cap) {
+ assert(new_cap >= m_capacity);
+ // To be correct with ctors and dtors, we do not use realloc and friends.
+ // A more efficient implementation would specialize for POD types and just
+ // realloc() or something. Meh, if we care, we ought to use just STL's
+ T *new_data = (T*) malloc(sizeof(T) * new_cap);
+ assert(new_data);
+ // Move over old data
+ if (m_data) {
+ for (size_type i = 0; i < m_size; i++) {
+ place_new(new_data + i, m_data[i]);
+ destruct(m_data + i);
+ }
+ free(m_data);
+ }
+ // And set the new values
+ m_data = new_data;
+ m_capacity = new_cap;
+ }
};
-#endif
-
-
-
-
-
-
-
-
+#endif
More information about the poppler
mailing list