[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