From: kramm <kramm>
Date: Sat, 3 Dec 2005 14:28:56 +0000 (+0000)
Subject: upgraded to xpdf-3.01pl1
X-Git-Tag: xpdf-3-01~4
X-Git-Url: http://git.asbjorn.it/?a=commitdiff_plain;h=85c46a8011c7fd5e4bda282266006c972ea7606b;p=swftools.git

upgraded to xpdf-3.01pl1
---

diff --git a/pdf2swf/xpdf/Annot.cc b/pdf2swf/xpdf/Annot.cc
index 245780d..68bfb6d 100644
--- a/pdf2swf/xpdf/Annot.cc
+++ b/pdf2swf/xpdf/Annot.cc
@@ -12,42 +12,26 @@
 #pragma implementation
 #endif
 
+#include <stdlib.h>
 #include "gmem.h"
 #include "Object.h"
+#include "Catalog.h"
 #include "Gfx.h"
+#include "Lexer.h"
 #include "Annot.h"
 
 //------------------------------------------------------------------------
 // Annot
 //------------------------------------------------------------------------
 
-Annot::Annot(XRef *xrefA, Dict *dict) {
+Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict) {
   Object apObj, asObj, obj1, obj2;
+  GBool regen, isTextField;
   double 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();
+  appearBuf = NULL;
 
   if (dict->lookup("Rect", &obj1)->isArray() &&
       obj1.arrayGetLength() == 4) {
@@ -76,10 +60,204 @@ Annot::Annot(XRef *xrefA, Dict *dict) {
     xMax = yMax = 1;
   }
   obj1.free();
+
+  // check if field apperances need to be regenerated
+  regen = gFalse;
+  if (acroForm) {
+    acroForm->lookup("NeedAppearances", &obj1);
+    if (obj1.isBool() && obj1.getBool()) {
+      regen = gTrue;
+    }
+    obj1.free();
+  }
+
+  // check for a text-type field
+  isTextField = dict->lookup("FT", &obj1)->isName("Tx");
+  obj1.free();
+
+#if 0 //~ appearance stream generation is not finished yet
+  if (regen && isTextField) {
+    generateAppearance(acroForm, dict);
+  } else {
+#endif
+    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;
+	  } else {
+	    obj2.free();
+	    if (obj1.dictLookupNF("Off", &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 0 //~ appearance stream generation is not finished yet
+  }
+#endif
 }
 
 Annot::~Annot() {
   appearance.free();
+  if (appearBuf) {
+    delete appearBuf;
+  }
+}
+
+void Annot::generateAppearance(Dict *acroForm, Dict *dict) {
+  MemStream *appearStream;
+  Object daObj, vObj, drObj, appearDict, obj1, obj2;
+  GString *daStr, *daStr1, *vStr, *s;
+  char buf[256];
+  double fontSize;
+  int c;
+  int i0, i1;
+
+  //~ DA can be inherited
+  if (dict->lookup("DA", &daObj)->isString()) {
+    daStr = daObj.getString();
+
+    // look for a font size
+    //~ may want to parse the DS entry in place of this (if it exists)
+    daStr1 = NULL;
+    fontSize = 10;
+    for (i1 = daStr->getLength() - 2; i1 >= 0; --i1) {
+      if (daStr->getChar(i1) == 'T' && daStr->getChar(i1+1) == 'f') {
+	for (--i1; i1 >= 0 && Lexer::isSpace(daStr->getChar(i1)); --i1) ;
+	for (i0 = i1; i0 >= 0 && !Lexer::isSpace(daStr->getChar(i0)); --i0) ;
+	if (i0 >= 0) {
+	  ++i0;
+	  ++i1;
+	  s = new GString(daStr, i0, i1 - i0);
+	  fontSize = atof(s->getCString());
+	  delete s;
+
+	  // autosize the font
+	  if (fontSize == 0) {
+	    fontSize = 0.67 * (yMax - yMin);
+	    daStr1 = new GString(daStr, 0, i0);
+	    sprintf(buf, "%.2f", fontSize);
+	    daStr1->append(buf);
+	    daStr1->append(daStr->getCString() + i1,
+			   daStr->getLength() - i1);
+	  }
+	}
+	break;
+      }
+    }
+
+    // build the appearance stream contents
+    appearBuf = new GString();
+    appearBuf->append("/Tx BMC\n");
+    appearBuf->append("q BT\n");
+    appearBuf->append(daStr1 ? daStr1 : daStr)->append("\n");
+    if (dict->lookup("V", &vObj)->isString()) {
+      //~ handle quadding -- this requires finding the font and using
+      //~   the encoding and char widths
+      sprintf(buf, "1 0 0 1 %.2f %.2f Tm\n", 2.0, yMax - yMin - fontSize);
+      appearBuf->append(buf);
+      sprintf(buf, "%g TL\n", fontSize);
+      appearBuf->append(buf);
+      vStr = vObj.getString();
+      i0 = 0;
+      while (i0 < vStr->getLength()) {
+	for (i1 = i0;
+	     i1 < vStr->getLength() &&
+	       vStr->getChar(i1) != '\n' && vStr->getChar(i1) != '\r';
+	     ++i1) ;
+	if (i0 > 0) {
+	  appearBuf->append("T*\n");
+	}
+	appearBuf->append('(');
+	for (; i0 < i1; ++i0) {
+	  c = vStr->getChar(i0);
+	  if (c == '(' || c == ')' || c == '\\') {
+	    appearBuf->append('\\');
+	    appearBuf->append(c);
+	  } else if (c < 0x20 || c >= 0x80) {
+	    sprintf(buf, "\\%03o", c);
+	    appearBuf->append(buf);
+	  } else {
+	    appearBuf->append(c);
+	  }
+	}
+	appearBuf->append(") Tj\n");
+	if (i1 + 1 < vStr->getLength() &&
+	    vStr->getChar(i1) == '\r' && vStr->getChar(i1 + 1) == '\n') {
+	  i0 = i1 + 2;
+	} else {
+	  i0 = i1 + 1;
+	}
+      }
+    }
+    vObj.free();
+    appearBuf->append("ET Q\n");
+    appearBuf->append("EMC\n");
+
+    // build the appearance stream dictionary
+    appearDict.initDict(xref);
+    appearDict.dictAdd(copyString("Length"),
+		       obj1.initInt(appearBuf->getLength()));
+    appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
+    obj1.initArray(xref);
+    obj1.arrayAdd(obj2.initReal(0));
+    obj1.arrayAdd(obj2.initReal(0));
+    obj1.arrayAdd(obj2.initReal(xMax - xMin));
+    obj1.arrayAdd(obj2.initReal(yMax - yMin));
+    appearDict.dictAdd(copyString("BBox"), &obj1);
+
+    // find the resource dictionary
+    dict->lookup("DR", &drObj);
+    if (!drObj.isDict()) {
+      dict->lookup("Parent", &obj1);
+      while (obj1.isDict()) {
+	drObj.free();
+	obj1.dictLookup("DR", &drObj);
+	if (drObj.isDict()) {
+	  break;
+	}
+	obj1.dictLookup("Parent", &obj2);
+	obj1.free();
+	obj1 = obj2;
+      }
+      obj1.free();
+      if (!drObj.isDict()) {
+	if (acroForm) {
+	  drObj.free();
+	  acroForm->lookup("DR", &drObj);
+	}
+      }
+    }
+    if (drObj.isDict()) {
+      appearDict.dictAdd(copyString("Resources"), drObj.copy(&obj1));
+    }
+    drObj.free();
+
+    // build the appearance stream
+    appearStream = new MemStream(appearBuf->getCString(), 0,
+				 appearBuf->getLength(), &appearDict);
+    appearance.initStream(appearStream);
+    ok = gTrue;
+
+    if (daStr1) {
+      delete daStr1;
+    }
+  }
+  daObj.free();
 }
 
 void Annot::draw(Gfx *gfx) {
@@ -95,7 +273,8 @@ void Annot::draw(Gfx *gfx) {
 // Annots
 //------------------------------------------------------------------------
 
-Annots::Annots(XRef *xref, Object *annotsObj) {
+Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) {
+  Dict *acroForm;
   Annot *annot;
   Object obj1;
   int size;
@@ -105,14 +284,16 @@ Annots::Annots(XRef *xref, Object *annotsObj) {
   size = 0;
   nAnnots = 0;
 
+  acroForm = catalog->getAcroForm()->isDict() ?
+               catalog->getAcroForm()->getDict() : NULL;
   if (annotsObj->isArray()) {
     for (i = 0; i < annotsObj->arrayGetLength(); ++i) {
       if (annotsObj->arrayGet(i, &obj1)->isDict()) {
-	annot = new Annot(xref, obj1.getDict());
+	annot = new Annot(xref, acroForm, obj1.getDict());
 	if (annot->isOk()) {
 	  if (nAnnots >= size) {
 	    size += 16;
-	    annots = (Annot **)grealloc(annots, size * sizeof(Annot *));
+	    annots = (Annot **)greallocn(annots, size, sizeof(Annot *));
 	  }
 	  annots[nAnnots++] = annot;
 	} else {
diff --git a/pdf2swf/xpdf/Annot.h b/pdf2swf/xpdf/Annot.h
index 89dde0f..e5fd841 100644
--- a/pdf2swf/xpdf/Annot.h
+++ b/pdf2swf/xpdf/Annot.h
@@ -16,6 +16,7 @@
 #endif
 
 class XRef;
+class Catalog;
 class Gfx;
 
 //------------------------------------------------------------------------
@@ -25,7 +26,7 @@ class Gfx;
 class Annot {
 public:
 
-  Annot(XRef *xrefA, Dict *dict);
+  Annot(XRef *xrefA, Dict *acroForm, Dict *dict);
   ~Annot();
   GBool isOk() { return ok; }
 
@@ -35,10 +36,13 @@ public:
   Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); }
 
 private:
+ 
+  void generateAppearance(Dict *acroForm, Dict *dict);
 
   XRef *xref;			// the xref table for this PDF file
   Object appearance;		// a reference to the Form XObject stream
 				//   for the normal appearance
+  GString *appearBuf;
   double xMin, yMin,		// annotation rectangle
          xMax, yMax;
   GBool ok;
@@ -52,7 +56,7 @@ class Annots {
 public:
 
   // Extract non-link annotations from array of annotations.
-  Annots(XRef *xref, Object *annotsObj);
+  Annots(XRef *xref, Catalog *catalog, Object *annotsObj);
 
   ~Annots();
 
diff --git a/pdf2swf/xpdf/Array.cc b/pdf2swf/xpdf/Array.cc
index a6c6db1..10ded14 100644
--- a/pdf2swf/xpdf/Array.cc
+++ b/pdf2swf/xpdf/Array.cc
@@ -44,7 +44,7 @@ void Array::add(Object *elem) {
     } else {
       size *= 2;
     }
-    elems = (Object *)grealloc(elems, size * sizeof(Object));
+    elems = (Object *)greallocn(elems, size, sizeof(Object));
   }
   elems[length] = *elem;
   ++length;
diff --git a/pdf2swf/xpdf/BuiltinFont.cc b/pdf2swf/xpdf/BuiltinFont.cc
index a687e73..ce98957 100644
--- a/pdf2swf/xpdf/BuiltinFont.cc
+++ b/pdf2swf/xpdf/BuiltinFont.cc
@@ -24,7 +24,7 @@ BuiltinFontWidths::BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA) {
   int i, h;
 
   size = sizeA;
-  tab = (BuiltinFontWidth **)gmalloc(size * sizeof(BuiltinFontWidth *));
+  tab = (BuiltinFontWidth **)gmallocn(size, sizeof(BuiltinFontWidth *));
   for (i = 0; i < size; ++i) {
     tab[i] = NULL;
   }
diff --git a/pdf2swf/xpdf/CMap.cc b/pdf2swf/xpdf/CMap.cc
index 25f3af7..303cf09 100644
--- a/pdf2swf/xpdf/CMap.cc
+++ b/pdf2swf/xpdf/CMap.cc
@@ -49,7 +49,7 @@ CMap *CMap::parse(CMapCache *cache, GString *collectionA,
   PSTokenizer *pst;
   char tok1[256], tok2[256], tok3[256];
   int n1, n2, n3;
-  Guint start, end;
+  Guint start, end, code;
 
   if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
 
@@ -99,6 +99,30 @@ CMap *CMap::parse(CMapCache *cache, GString *collectionA,
 	}
       }
       pst->getToken(tok1, sizeof(tok1), &n1);
+    } else if (!strcmp(tok2, "begincidchar")) {
+      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+	if (!strcmp(tok1, "endcidchar")) {
+	  break;
+	}
+	if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+	    !strcmp(tok2, "endcidchar")) {
+	  error(-1, "Illegal entry in cidchar block in CMap");
+	  break;
+	}
+	if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+	      n1 >= 4 && (n1 & 1) == 0)) {
+	  error(-1, "Illegal entry in cidchar block in CMap");
+	  continue;
+	}
+	tok1[n1 - 1] = '\0';
+	if (sscanf(tok1 + 1, "%x", &code) != 1) {
+	  error(-1, "Illegal entry in cidchar block in CMap");
+	  continue;
+	}
+	n1 = (n1 - 2) / 2;
+	cmap->addCIDs(code, code, n1, (CID)atoi(tok2));
+      }
+      pst->getToken(tok1, sizeof(tok1), &n1);
     } else if (!strcmp(tok2, "begincidrange")) {
       while (pst->getToken(tok1, sizeof(tok1), &n1)) {
 	if (!strcmp(tok1, "endcidrange")) {
@@ -138,7 +162,7 @@ CMap::CMap(GString *collectionA, GString *cMapNameA) {
   collection = collectionA;
   cMapName = cMapNameA;
   wMode = 0;
-  vector = (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
+  vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
   for (i = 0; i < 256; ++i) {
     vector[i].isVector = gFalse;
     vector[i].cid = 0;
@@ -182,7 +206,7 @@ void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) {
       if (!dest[i].isVector) {
 	dest[i].isVector = gTrue;
 	dest[i].vector =
-	  (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
+	  (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
 	for (j = 0; j < 256; ++j) {
 	  dest[i].vector[j].isVector = gFalse;
 	  dest[i].vector[j].cid = 0;
@@ -213,7 +237,7 @@ void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end,
       if (!vec[i].isVector) {
 	vec[i].isVector = gTrue;
 	vec[i].vector =
-	  (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
+	  (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
 	for (j = 0; j < 256; ++j) {
 	  vec[i].vector[j].isVector = gFalse;
 	  vec[i].vector[j].cid = 0;
@@ -234,7 +258,7 @@ void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) {
   for (i = nBytes - 1; i >= 1; --i) {
     byte = (start >> (8 * i)) & 0xff;
     if (!vec[byte].isVector) {
-      error(-1, "Invalid CID (%*x - %*x) in CMap",
+      error(-1, "Invalid CID (%0*x - %0*x) in CMap",
 	    2*nBytes, start, 2*nBytes, end);
       return;
     }
@@ -243,7 +267,7 @@ void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) {
   cid = firstCID;
   for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) {
     if (vec[byte].isVector) {
-      error(-1, "Invalid CID (%*x - %*x) in CMap",
+      error(-1, "Invalid CID (%0*x - %0*x) in CMap",
 	    2*nBytes, start, 2*nBytes, end);
     } else {
       vec[byte].cid = cid;
diff --git a/pdf2swf/xpdf/CMap.h b/pdf2swf/xpdf/CMap.h
index eff2a81..c321a57 100644
--- a/pdf2swf/xpdf/CMap.h
+++ b/pdf2swf/xpdf/CMap.h
@@ -73,7 +73,7 @@ private:
   CMapVectorEntry *vector;	// vector for first byte (NULL for
 				//   identity CMap)
   int refCnt;
-#ifdef MULTITHREADED
+#if MULTITHREADED
   GMutex mutex;
 #endif
 };
diff --git a/pdf2swf/xpdf/Catalog.cc b/pdf2swf/xpdf/Catalog.cc
index c645fd0..fd235d6 100644
--- a/pdf2swf/xpdf/Catalog.cc
+++ b/pdf2swf/xpdf/Catalog.cc
@@ -64,8 +64,8 @@ Catalog::Catalog(XRef *xrefA) {
   }
   pagesSize = numPages0 = (int)obj.getNum();
   obj.free();
-  pages = (Page **)gmalloc(pagesSize * sizeof(Page *));
-  pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref));
+  pages = (Page **)gmallocn(pagesSize, sizeof(Page *));
+  pageRefs = (Ref *)gmallocn(pagesSize, sizeof(Ref));
   for (i = 0; i < pagesSize; ++i) {
     pages[i] = NULL;
     pageRefs[i].num = -1;
@@ -105,6 +105,9 @@ Catalog::Catalog(XRef *xrefA) {
   // get the outline dictionary
   catDict.dictLookup("Outlines", &outline);
 
+  // get the AcroForm dictionary
+  catDict.dictLookup("AcroForm", &acroForm);
+
   catDict.free();
   return;
 
@@ -139,6 +142,7 @@ Catalog::~Catalog() {
   metadata.free();
   structTreeRoot.free();
   outline.free();
+  acroForm.free();
 }
 
 GString *Catalog::readMetadata() {
@@ -191,8 +195,8 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
       }
       if (start >= pagesSize) {
 	pagesSize += 32;
-	pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *));
-	pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref));
+	pages = (Page **)greallocn(pages, pagesSize, sizeof(Page *));
+	pageRefs = (Ref *)greallocn(pageRefs, pagesSize, sizeof(Ref));
 	for (j = pagesSize - 32; j < pagesSize; ++j) {
 	  pages[j] = NULL;
 	  pageRefs[j].num = -1;
@@ -216,7 +220,6 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
     } else {
       error(-1, "Kid object (page %d) is wrong type (%s)",
 	    start+1, kid.getTypeName());
-      goto err2;
     }
     kid.free();
   }
diff --git a/pdf2swf/xpdf/Catalog.h b/pdf2swf/xpdf/Catalog.h
index 8ab7c61..c38f109 100644
--- a/pdf2swf/xpdf/Catalog.h
+++ b/pdf2swf/xpdf/Catalog.h
@@ -67,6 +67,8 @@ public:
 
   Object *getOutline() { return &outline; }
 
+  Object *getAcroForm() { return &acroForm; }
+
 private:
 
   XRef *xref;			// the xref table for this PDF file
@@ -80,6 +82,7 @@ private:
   Object metadata;		// metadata stream
   Object structTreeRoot;	// structure tree root dictionary
   Object outline;		// outline dictionary
+  Object acroForm;		// AcroForm dictionary
   GBool ok;			// true if catalog is valid
 
   int readPageTree(Dict *pages, PageAttrs *attrs, int start);
diff --git a/pdf2swf/xpdf/CharCodeToUnicode.cc b/pdf2swf/xpdf/CharCodeToUnicode.cc
index 2e2ad47..3702a16 100644
--- a/pdf2swf/xpdf/CharCodeToUnicode.cc
+++ b/pdf2swf/xpdf/CharCodeToUnicode.cc
@@ -70,13 +70,13 @@ CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *fileName,
   }
 
   size = 32768;
-  mapA = (Unicode *)gmalloc(size * sizeof(Unicode));
+  mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
   mapLenA = 0;
 
   while (getLine(buf, sizeof(buf), f)) {
     if (mapLenA == size) {
       size *= 2;
-      mapA = (Unicode *)grealloc(mapA, size * sizeof(Unicode));
+      mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
     }
     if (sscanf(buf, "%x", &u) == 1) {
       mapA[mapLenA] = u;
@@ -115,7 +115,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(
   }
 
   size = 4096;
-  mapA = (Unicode *)gmalloc(size * sizeof(Unicode));
+  mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
   memset(mapA, 0, size * sizeof(Unicode));
   len = 0;
   sMapA = NULL;
@@ -152,7 +152,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(
       while (u0 >= size) {
 	size *= 2;
       }
-      mapA = (Unicode *)grealloc(mapA, size * sizeof(Unicode));
+      mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
       memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode));
     }
     if (n == 1) {
@@ -162,7 +162,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(
       if (sMapLenA == sMapSizeA) {
 	sMapSizeA += 16;
 	sMapA = (CharCodeToUnicodeString *)
-	          grealloc(sMapA, sMapSizeA * sizeof(CharCodeToUnicodeString));
+	          greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString));
       }
       sMapA[sMapLenA].c = u0;
       for (i = 0; i < n; ++i) {
@@ -251,7 +251,7 @@ void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data,
 	  error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
 	  continue;
 	}
-	addMapping(code1, tok2 + 1, n2 - 1, 0);
+	addMapping(code1, tok2 + 1, n2 - 2, 0);
       }
       pst->getToken(tok1, sizeof(tok1), &n1);
     } else if (!strcmp(tok2, "beginbfrange")) {
@@ -320,7 +320,7 @@ void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n,
   if (code >= mapLen) {
     oldLen = mapLen;
     mapLen = (code + 256) & ~255;
-    map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode));
+    map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode));
     for (i = oldLen; i < mapLen; ++i) {
       map[i] = 0;
     }
@@ -335,7 +335,7 @@ void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n,
     if (sMapLen >= sMapSize) {
       sMapSize = sMapSize + 16;
       sMap = (CharCodeToUnicodeString *)
-	       grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString));
+	       greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
     }
     map[code] = 0;
     sMap[sMapLen].c = code;
@@ -357,7 +357,7 @@ CharCodeToUnicode::CharCodeToUnicode(GString *tagA) {
 
   tag = tagA;
   mapLen = 256;
-  map = (Unicode *)gmalloc(mapLen * sizeof(Unicode));
+  map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
   for (i = 0; i < mapLen; ++i) {
     map[i] = 0;
   }
@@ -376,7 +376,7 @@ CharCodeToUnicode::CharCodeToUnicode(GString *tagA, Unicode *mapA,
   tag = tagA;
   mapLen = mapLenA;
   if (copyMap) {
-    map = (Unicode *)gmalloc(mapLen * sizeof(Unicode));
+    map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
     memcpy(map, mapA, mapLen * sizeof(Unicode));
   } else {
     map = mapA;
@@ -433,23 +433,30 @@ GBool CharCodeToUnicode::match(GString *tagA) {
 }
 
 void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) {
-  int i;
+  int i, j;
 
   if (len == 1) {
     map[c] = u[0];
   } else {
-    map[c] = 0;
-    if (sMapLen == sMapSize) {
-      sMapSize += 8;
-      sMap = (CharCodeToUnicodeString *)
-	       grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString));
+    for (i = 0; i < sMapLen; ++i) {
+      if (sMap[i].c == c) {
+	break;
+      }
     }
-    sMap[sMapLen].c = c;
-    sMap[sMapLen].len = len;
-    for (i = 0; i < len && i < maxUnicodeString; ++i) {
-      sMap[sMapLen].u[i] = u[i];
+    if (i == sMapLen) {
+      if (sMapLen == sMapSize) {
+	sMapSize += 8;
+	sMap = (CharCodeToUnicodeString *)
+	         greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
+      }
+      ++sMapLen;
+    }
+    map[c] = 0;
+    sMap[i].c = c;
+    sMap[i].len = len;
+    for (j = 0; j < len && j < maxUnicodeString; ++j) {
+      sMap[i].u[j] = u[j];
     }
-    ++sMapLen;
   }
 }
 
@@ -480,7 +487,7 @@ CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) {
   int i;
 
   size = sizeA;
-  cache = (CharCodeToUnicode **)gmalloc(size * sizeof(CharCodeToUnicode *));
+  cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *));
   for (i = 0; i < size; ++i) {
     cache[i] = NULL;
   }
diff --git a/pdf2swf/xpdf/CharCodeToUnicode.h b/pdf2swf/xpdf/CharCodeToUnicode.h
index 605e2bd..04852ae 100644
--- a/pdf2swf/xpdf/CharCodeToUnicode.h
+++ b/pdf2swf/xpdf/CharCodeToUnicode.h
@@ -67,6 +67,10 @@ public:
   // Map a CharCode to Unicode.
   int mapToUnicode(CharCode c, Unicode *u, int size);
 
+  // Return the mapping's length, i.e., one more than the max char
+  // code supported by the mapping.
+  CharCode getLength() { return mapLen; }
+
 private:
 
   void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits);
@@ -83,7 +87,7 @@ private:
   CharCodeToUnicodeString *sMap;
   int sMapLen, sMapSize;
   int refCnt;
-#ifdef MULTITHREADED
+#if MULTITHREADED
   GMutex mutex;
 #endif
 };
diff --git a/pdf2swf/xpdf/Decrypt.cc b/pdf2swf/xpdf/Decrypt.cc
index dab0750..91eb452 100644
--- a/pdf2swf/xpdf/Decrypt.cc
+++ b/pdf2swf/xpdf/Decrypt.cc
@@ -12,6 +12,7 @@
 #pragma implementation
 #endif
 
+#include <string.h>
 #include "gmem.h"
 #include "Decrypt.h"
 
@@ -65,7 +66,8 @@ 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 *fileKey, GBool encryptMetadata,
+			   GBool *ownerPasswordOk) {
   Guchar test[32], test2[32];
   GString *userPassword2;
   Guchar fState[256];
@@ -110,7 +112,8 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
     }
     userPassword2 = new GString((char *)test2, 32);
     if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
-		     permissions, fileID, userPassword2, fileKey)) {
+		     permissions, fileID, userPassword2, fileKey,
+		     encryptMetadata)) {
       *ownerPasswordOk = gTrue;
       delete userPassword2;
       return gTrue;
@@ -120,13 +123,15 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
 
   // try using the supplied user password
   return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
-		      permissions, fileID, userPassword, fileKey);
+		      permissions, fileID, userPassword, fileKey,
+		      encryptMetadata);
 }
 
 GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength,
 			    GString *ownerKey, GString *userKey,
 			    int permissions, GString *fileID,
-			    GString *userPassword, Guchar *fileKey) {
+			    GString *userPassword, Guchar *fileKey,
+			    GBool encryptMetadata) {
   Guchar *buf;
   Guchar test[32];
   Guchar fState[256];
@@ -136,7 +141,7 @@ GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength,
   GBool ok;
 
   // generate file key
-  buf = (Guchar *)gmalloc(68 + fileID->getLength());
+  buf = (Guchar *)gmalloc(72 + fileID->getLength());
   if (userPassword) {
     len = userPassword->getLength();
     if (len < 32) {
@@ -154,7 +159,14 @@ GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength,
   buf[66] = (permissions >> 16) & 0xff;
   buf[67] = (permissions >> 24) & 0xff;
   memcpy(buf + 68, fileID->getCString(), fileID->getLength());
-  md5(buf, 68 + fileID->getLength(), fileKey);
+  len = 68 + fileID->getLength();
+  if (!encryptMetadata) {
+    buf[len++] = 0xff;
+    buf[len++] = 0xff;
+    buf[len++] = 0xff;
+    buf[len++] = 0xff;
+  }
+  md5(buf, len, fileKey);
   if (encRevision == 3) {
     for (i = 0; i < 50; ++i) {
       md5(fileKey, keyLength, fileKey);
diff --git a/pdf2swf/xpdf/Decrypt.h b/pdf2swf/xpdf/Decrypt.h
index 71f9457..2beba58 100644
--- a/pdf2swf/xpdf/Decrypt.h
+++ b/pdf2swf/xpdf/Decrypt.h
@@ -43,14 +43,16 @@ public:
 			   GString *ownerKey, GString *userKey,
 			   int permissions, GString *fileID,
 			   GString *ownerPassword, GString *userPassword,
-			   Guchar *fileKey, GBool *ownerPasswordOk);
+			   Guchar *fileKey, GBool encryptMetadata,
+			   GBool *ownerPasswordOk);
 
 private:
 
   static GBool makeFileKey2(int encVersion, int encRevision, int keyLength,
 			    GString *ownerKey, GString *userKey,
 			    int permissions, GString *fileID,
-			    GString *userPassword, Guchar *fileKey);
+			    GString *userPassword, Guchar *fileKey,
+			    GBool encryptMetadata);
 
   int objKeyLength;
   Guchar objKey[21];
diff --git a/pdf2swf/xpdf/Dict.cc b/pdf2swf/xpdf/Dict.cc
index 6274590..dd1517f 100644
--- a/pdf2swf/xpdf/Dict.cc
+++ b/pdf2swf/xpdf/Dict.cc
@@ -47,7 +47,7 @@ void Dict::add(char *key, Object *val) {
     } else {
       size *= 2;
     }
-    entries = (DictEntry *)grealloc(entries, size * sizeof(DictEntry));
+    entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry));
   }
   entries[length].key = key;
   entries[length].val = *val;
diff --git a/pdf2swf/xpdf/FoFiTrueType.cc b/pdf2swf/xpdf/FoFiTrueType.cc
index a4cf43c..46b61ec 100644
--- a/pdf2swf/xpdf/FoFiTrueType.cc
+++ b/pdf2swf/xpdf/FoFiTrueType.cc
@@ -13,6 +13,7 @@
 #endif
 
 #include <stdlib.h>
+#include <string.h>
 #include "gtypes.h"
 #include "gmem.h"
 #include "GString.h"
@@ -77,6 +78,10 @@
 
 //------------------------------------------------------------------------
 
+#define ttcfTag 0x74746366
+
+//------------------------------------------------------------------------
+
 struct TrueTypeTable {
   Guint tag;
   Guint checksum;
@@ -102,6 +107,7 @@ struct TrueTypeLoca {
 
 #define cmapTag 0x636d6170
 #define glyfTag 0x676c7966
+#define headTag 0x68656164
 #define locaTag 0x6c6f6361
 #define nameTag 0x6e616d65
 #define postTag 0x706f7374
@@ -153,9 +159,11 @@ static T42Table t42Tables[nT42Tables] = {
   { "vhea", gFalse },
   { "vmtx", gFalse }
 };
-#define t42HeadTable 3
-#define t42LocaTable 6
-#define t42GlyfTable 2
+#define t42HeadTable  3
+#define t42LocaTable  6
+#define t42GlyfTable  2
+#define t42VheaTable  9
+#define t42VmtxTable 10
 
 //------------------------------------------------------------------------
 
@@ -276,7 +284,9 @@ FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA):
 FoFiTrueType::~FoFiTrueType() {
   gfree(tables);
   gfree(cmaps);
-  delete nameToGID;
+  if (nameToGID) {
+    delete nameToGID;
+  }
 }
 
 int FoFiTrueType::getNumCmaps() {
@@ -432,7 +442,7 @@ void FoFiTrueType::convertToType42(char *psName, char **encoding,
   // write the guts of the dictionary
   cvtEncoding(encoding, outputFunc, outputStream);
   cvtCharStrings(encoding, codeToGID, outputFunc, outputStream);
-  cvtSfnts(outputFunc, outputStream, NULL);
+  cvtSfnts(outputFunc, outputStream, NULL, gFalse);
 
   // end the dictionary and define the font
   (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
@@ -440,6 +450,7 @@ void FoFiTrueType::convertToType42(char *psName, char **encoding,
 
 void FoFiTrueType::convertToCIDType2(char *psName,
 				     Gushort *cidMap, int nCIDs,
+				     GBool needVerticalMetrics,
 				     FoFiOutputFunc outputFunc,
 				     void *outputStream) {
   char buf[512];
@@ -540,7 +551,7 @@ void FoFiTrueType::convertToCIDType2(char *psName,
   (*outputFunc)(outputStream, "  end readonly def\n", 19);
 
   // write the guts of the dictionary
-  cvtSfnts(outputFunc, outputStream, NULL);
+  cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics);
 
   // end the dictionary and define the font
   (*outputFunc)(outputStream,
@@ -549,6 +560,7 @@ void FoFiTrueType::convertToCIDType2(char *psName,
 }
 
 void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
+				  GBool needVerticalMetrics,
 				  FoFiOutputFunc outputFunc,
 				  void *outputStream) {
   char buf[512];
@@ -557,7 +569,7 @@ void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
 
   // write the Type 42 sfnts array
   sfntsName = (new GString(psName))->append("_sfnts");
-  cvtSfnts(outputFunc, outputStream, sfntsName);
+  cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics);
   delete sfntsName;
 
   // write the descendant Type 42 fonts
@@ -620,18 +632,28 @@ void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
 }
 
 void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
-			    void *outputStream) {
-  static char cmapTab[20] = {
+			    void *outputStream, char *name,
+			    Gushort *codeToGID) {
+  // this substitute cmap table maps char codes 0000-ffff directly to
+  // glyphs 0000-ffff
+  static char cmapTab[36] = {
     0, 0,			// table version number
     0, 1,			// number of encoding tables
     0, 1,			// platform ID
     0, 0,			// encoding ID
     0, 0, 0, 12,		// offset of subtable
-    0, 0,			// subtable format
-    0, 1,			// subtable length
-    0, 1,			// subtable version
-    0,				// map char 0 -> glyph 0
-    0				// pad to multiple of four bytes
+    0, 4,			// subtable format
+    0, 24,			// subtable length
+    0, 0,			// subtable version
+    0, 2,			// segment count * 2
+    0, 2,			// 2 * 2 ^ floor(log2(segCount))
+    0, 0,			// floor(log2(segCount))
+    0, 0,			// 2*segCount - 2*2^floor(log2(segCount))
+    (char)0xff, (char)0xff,	// endCount[0]
+    0, 0,			// reserved
+    0, 0,			// startCount[0]
+    0, 0,			// idDelta[0]
+    0, 0			// pad to a mulitple of four bytes
   };
   static char nameTab[8] = {
     0, 0,			// format
@@ -654,9 +676,11 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
   int nZeroLengthTables;
   TrueTypeLoca *locaTable;
   TrueTypeTable *newTables;
-  int nNewTables, cmapIdx, cmapLen, glyfLen;
+  char *newNameTab, *newCmapTab;
+  int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next;
+  Guint locaChecksum, glyfChecksum, fileChecksum;
   char *tableDir;
-  char locaBuf[4];
+  char locaBuf[4], checksumBuf[4];
   GBool ok;
   Guint t;
   int pos, i, j, k, n;
@@ -667,7 +691,7 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
   missingPost = seekTable("post") < 0;
 
   // read the loca table, check to see if it's sorted
-  locaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * sizeof(TrueTypeLoca));
+  locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
   unsortedLoca = gFalse;
   i = seekTable("loca");
   pos = tables[i].offset;
@@ -710,7 +734,7 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
 
   // if nothing is broken, just write the TTF file as is
   if (!missingCmap && !missingName && !missingPost && !unsortedLoca &&
-      !badCmapLen && nZeroLengthTables == 0) {
+      !badCmapLen && nZeroLengthTables == 0 && !name && !codeToGID) {
     (*outputFunc)(outputStream, (char *)file, len);
     goto done1;
   }
@@ -742,46 +766,206 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
     glyfLen = pos;
   }
 
+  // compute checksums for the loca and glyf tables
+  locaChecksum = glyfChecksum = 0;
+  if (unsortedLoca) {
+    if (locaFmt) {
+      for (j = 0; j <= nGlyphs; ++j) {
+	locaChecksum += locaTable[j].newOffset;
+      }
+    } else {
+      for (j = 0; j <= nGlyphs; j += 2) {
+	locaChecksum += locaTable[j].newOffset << 16;
+	if (j + 1 <= nGlyphs) {
+	  locaChecksum += locaTable[j+1].newOffset;
+	}
+      }
+    }
+    pos = tables[seekTable("glyf")].offset;
+    for (j = 0; j < nGlyphs; ++j) {
+      n = locaTable[j].len;
+      if (n > 0) {
+	k = locaTable[j].origOffset;
+	if (checkRegion(pos + k, n)) {
+	  glyfChecksum += computeTableChecksum(file + pos + k, n);
+	}
+      }
+    }
+  }
+
+  // construct the new name table
+  if (name) {
+    n = strlen(name);
+    newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3;
+    newNameTab = (char *)gmalloc(newNameLen);
+    memset(newNameTab, 0, newNameLen);
+    newNameTab[0] = 0;		// format selector
+    newNameTab[1] = 0;
+    newNameTab[2] = 0;		// number of name records
+    newNameTab[3] = 4;
+    newNameTab[4] = 0;		// offset to start of string storage
+    newNameTab[5] = 6 + 4*12;
+    next = 0;
+    for (i = 0; i < 4; ++i) {
+      newNameTab[6 + i*12 + 0] = 0;	// platform ID = Microsoft
+      newNameTab[6 + i*12 + 1] = 3;
+      newNameTab[6 + i*12 + 2] = 0;	// encoding ID = Unicode
+      newNameTab[6 + i*12 + 3] = 1;
+      newNameTab[6 + i*12 + 4] = 0x04;	// language ID = American English
+      newNameTab[6 + i*12 + 5] = 0x09;
+      newNameTab[6 + i*12 + 6] = 0;	// name ID
+      newNameTab[6 + i*12 + 7] = i + 1;
+      newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length
+      newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff);
+      newNameTab[6 + i*12 + 10] = next >> 8;		    // string offset
+      newNameTab[6 + i*12 + 11] = next & 0xff;
+      if (i+1 == 2) {
+	memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14);
+	next += 14;
+      } else {
+	for (j = 0; j < n; ++j) {
+	  newNameTab[6 + 4*12 + next + 2*j] = 0;
+	  newNameTab[6 + 4*12 + next + 2*j + 1] = name[j];
+	}
+	next += 2*n;
+      }
+    }
+  } else {
+    newNameLen = 0;
+    newNameTab = NULL;
+  }
+
+  // construct the new cmap table
+  if (codeToGID) {
+    newCmapLen = 44 + 256 * 2;
+    newCmapTab = (char *)gmalloc(newCmapLen);
+    newCmapTab[0] = 0;		// table version number = 0
+    newCmapTab[1] = 0;
+    newCmapTab[2] = 0;		// number of encoding tables = 1
+    newCmapTab[3] = 1;
+    newCmapTab[4] = 0;		// platform ID = Microsoft
+    newCmapTab[5] = 3;
+    newCmapTab[6] = 0;		// encoding ID = Unicode
+    newCmapTab[7] = 1;
+    newCmapTab[8] = 0;		// offset of subtable
+    newCmapTab[9] = 0;
+    newCmapTab[10] = 0;
+    newCmapTab[11] = 12;
+    newCmapTab[12] = 0;		// subtable format = 4
+    newCmapTab[13] = 4;
+    newCmapTab[14] = 0x02;	// subtable length
+    newCmapTab[15] = 0x20;
+    newCmapTab[16] = 0;		// subtable version = 0
+    newCmapTab[17] = 0;
+    newCmapTab[18] = 0;		// segment count * 2
+    newCmapTab[19] = 4;
+    newCmapTab[20] = 0;		// 2 * 2 ^ floor(log2(segCount))
+    newCmapTab[21] = 4;
+    newCmapTab[22] = 0;		// floor(log2(segCount))
+    newCmapTab[23] = 1;
+    newCmapTab[24] = 0;		// 2*segCount - 2*2^floor(log2(segCount))
+    newCmapTab[25] = 0;
+    newCmapTab[26] = 0x00;	// endCount[0]
+    newCmapTab[27] = (char)0xff;
+    newCmapTab[28] = (char)0xff; // endCount[1]
+    newCmapTab[29] = (char)0xff;
+    newCmapTab[30] = 0;		// reserved
+    newCmapTab[31] = 0;
+    newCmapTab[32] = 0x00;	// startCount[0]
+    newCmapTab[33] = 0x00;
+    newCmapTab[34] = (char)0xff; // startCount[1]
+    newCmapTab[35] = (char)0xff;
+    newCmapTab[36] = 0;		// idDelta[0]
+    newCmapTab[37] = 0;
+    newCmapTab[38] = 0;		// idDelta[1]
+    newCmapTab[39] = 1;
+    newCmapTab[40] = 0;		// idRangeOffset[0]
+    newCmapTab[41] = 4;
+    newCmapTab[42] = 0;		// idRangeOffset[1]
+    newCmapTab[43] = 0;
+    for (i = 0; i < 256; ++i) {
+      newCmapTab[44 + 2*i] = codeToGID[i] >> 8;
+      newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff;
+    }
+  } else {
+    newCmapLen = 0;
+    newCmapTab = NULL;
+  }
+
   // construct the new table directory:
   // - keep all original tables with non-zero length
   // - fix the cmap table's length, if necessary
   // - add missing tables
   // - sort the table by tag
   // - compute new table positions, including 4-byte alignment
+  // - (re)compute table checksums
   nNewTables = nTables - nZeroLengthTables +
                (missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
                (missingPost ? 1 : 0);
-  newTables = (TrueTypeTable *)gmalloc(nNewTables * sizeof(TrueTypeTable));
+  newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable));
   j = 0;
   for (i = 0; i < nTables; ++i) {
     if (tables[i].len > 0) {
       newTables[j] = tables[i];
       newTables[j].origOffset = tables[i].offset;
-      if (newTables[j].tag == cmapTag && badCmapLen) {
+      if (checkRegion(tables[i].offset, newTables[i].len)) {
+	newTables[j].checksum =
+	    computeTableChecksum(file + tables[i].offset, tables[i].len);
+	if (tables[i].tag == headTag) {
+	  // don't include the file checksum
+	  newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok);
+	}
+      }
+      if (newTables[j].tag == cmapTag && codeToGID) {
+	newTables[j].len = newCmapLen;
+	newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
+						     newCmapLen);
+      } else if (newTables[j].tag == cmapTag && badCmapLen) {
 	newTables[j].len = cmapLen;
       } else if (newTables[j].tag == locaTag && unsortedLoca) {
 	newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+	newTables[j].checksum = locaChecksum;
       } else if (newTables[j].tag == glyfTag && unsortedLoca) {
 	newTables[j].len = glyfLen;
+	newTables[j].checksum = glyfChecksum;
+      } else if (newTables[j].tag == nameTag && name) {
+	newTables[j].len = newNameLen;
+	newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
+						     newNameLen);
       }
       ++j;
     }
   }
   if (missingCmap) {
     newTables[j].tag = cmapTag;
-    newTables[j].checksum = 0; //~ should compute the checksum
-    newTables[j].len = sizeof(cmapTab);
+    if (codeToGID) {
+      newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
+						   newCmapLen);
+      newTables[j].len = newCmapLen;
+    } else {
+      newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab,
+						   sizeof(cmapTab));
+      newTables[j].len = sizeof(cmapTab);
+    }
     ++j;
   }
   if (missingName) {
     newTables[j].tag = nameTag;
-    newTables[j].checksum = 0; //~ should compute the checksum
-    newTables[j].len = sizeof(nameTab);
+    if (name) {
+      newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
+						   newNameLen);
+      newTables[j].len = newNameLen;
+    } else {
+      newTables[j].checksum = computeTableChecksum((Guchar *)nameTab,
+						   sizeof(nameTab));
+      newTables[j].len = sizeof(nameTab);
+    }
     ++j;
   }
   if (missingPost) {
     newTables[j].tag = postTag;
-    newTables[j].checksum = 0; //~ should compute the checksum
+    newTables[j].checksum = computeTableChecksum((Guchar *)postTab,
+						 sizeof(postTab));
     newTables[j].len = sizeof(postTab);
     ++j;
   }
@@ -835,10 +1019,38 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
   }
   (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16);
 
+  // compute the file checksum
+  fileChecksum = computeTableChecksum((Guchar *)tableDir,
+				      12 + nNewTables * 16);
+  for (i = 0; i < nNewTables; ++i) {
+    fileChecksum += newTables[i].checksum;
+  }
+  fileChecksum = 0xb1b0afba - fileChecksum;
+
   // write the tables
   for (i = 0; i < nNewTables; ++i) {
-    if (newTables[i].tag == cmapTag && missingCmap) {
+    if (newTables[i].tag == headTag) {
+      if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
+	(*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8);
+	checksumBuf[0] = fileChecksum >> 24;
+	checksumBuf[1] = fileChecksum >> 16;
+	checksumBuf[2] = fileChecksum >> 8;
+	checksumBuf[3] = fileChecksum;
+	(*outputFunc)(outputStream, checksumBuf, 4);
+	(*outputFunc)(outputStream,
+		      (char *)file + newTables[i].origOffset + 12,
+		      newTables[i].len - 12);
+      } else {
+	for (j = 0; j < newTables[i].len; ++j) {
+	  (*outputFunc)(outputStream, "\0", 1);
+	}
+      }
+    } else if (newTables[i].tag == cmapTag && codeToGID) {
+      (*outputFunc)(outputStream, newCmapTab, newTables[i].len);
+    } else if (newTables[i].tag == cmapTag && missingCmap) {
       (*outputFunc)(outputStream, cmapTab, newTables[i].len);
+    } else if (newTables[i].tag == nameTag && name) {
+      (*outputFunc)(outputStream, newNameTab, newTables[i].len);
     } else if (newTables[i].tag == nameTag && missingName) {
       (*outputFunc)(outputStream, nameTab, newTables[i].len);
     } else if (newTables[i].tag == postTag && missingPost) {
@@ -890,6 +1102,8 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
     }
   }
 
+  gfree(newCmapTab);
+  gfree(newNameTab);
   gfree(tableDir);
   gfree(newTables);
  done1:
@@ -974,7 +1188,8 @@ void FoFiTrueType::cvtCharStrings(char **encoding,
 }
 
 void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
-			    void *outputStream, GString *name) {
+			    void *outputStream, GString *name,
+			    GBool needVerticalMetrics) {
   Guchar headData[54];
   TrueTypeLoca *locaTable;
   Guchar *locaData;
@@ -984,6 +1199,28 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
   Guint checksum;
   int nNewTables;
   int length, pos, glyfPos, i, j, k;
+  Guchar vheaTab[36] = {
+    0, 1, 0, 0,			// table version number
+    0, 0,			// ascent
+    0, 0,			// descent
+    0, 0,			// reserved
+    0, 0,			// max advance height
+    0, 0,			// min top side bearing
+    0, 0,			// min bottom side bearing
+    0, 0,			// y max extent
+    0, 0,			// caret slope rise
+    0, 1,			// caret slope run
+    0, 0,			// caret offset
+    0, 0,			// reserved
+    0, 0,			// reserved
+    0, 0,			// reserved
+    0, 0,			// reserved
+    0, 0,			// metric data format
+    0, 1			// number of advance heights in vmtx table
+  };
+  Guchar *vmtxTab;
+  GBool needVhea, needVmtx;
+  int advance;
 
   // construct the 'head' table, zero out the font checksum
   i = seekTable("head");
@@ -1001,7 +1238,7 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
   // table, cmpTrueTypeLocaPos uses offset as its primary sort key,
   // and idx as its secondary key (ensuring that adjacent entries with
   // the same pos value remain in the same order)
-  locaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * sizeof(TrueTypeLoca));
+  locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
   i = seekTable("loca");
   pos = tables[i].offset;
   ok = gTrue;
@@ -1031,7 +1268,7 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
   }
 
   // construct the new 'loca' table
-  locaData = (Guchar *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
+  locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2));
   for (i = 0; i <= nGlyphs; ++i) {
     pos = locaTable[i].newOffset;
     if (locaFmt) {
@@ -1053,6 +1290,22 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
       ++nNewTables;
     }
   }
+  vmtxTab = NULL; // make gcc happy
+  advance = 0; // make gcc happy
+  if (needVerticalMetrics) {
+    needVhea = seekTable("vhea") < 0;
+    needVmtx = seekTable("vmtx") < 0;
+    if (needVhea || needVmtx) {
+      i = seekTable("head");
+      advance = getU16BE(tables[i].offset + 18, &ok); // units per em
+      if (needVhea) {
+	++nNewTables;
+      }
+      if (needVmtx) {
+	++nNewTables;
+      }
+    }
+  }
 
   // construct the new table headers, including table checksums
   // (pad each table out to a multiple of 4 bytes)
@@ -1088,6 +1341,21 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
 	if (checkRegion(tables[j].offset, length)) {
 	  checksum = computeTableChecksum(file + tables[j].offset, length);
 	}
+      } else if (needVerticalMetrics && i == t42VheaTable) {
+	vheaTab[10] = advance / 256;    // max advance height
+	vheaTab[11] = advance % 256;
+	length = sizeof(vheaTab);
+	checksum = computeTableChecksum(vheaTab, length);
+      } else if (needVerticalMetrics && i == t42VmtxTable) {
+	length = 4 + (nGlyphs - 1) * 4;
+	vmtxTab = (Guchar *)gmalloc(length);
+	vmtxTab[0] = advance / 256;
+	vmtxTab[1] = advance % 256;
+	for (j = 2; j < length; j += 2) {
+	  vmtxTab[j] = 0;
+	  vmtxTab[j+1] = 0;
+	}
+	checksum = computeTableChecksum(vmtxTab, length);
       } else if (t42Tables[i].required) {
 	//~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
 	//~       t42Tables[i].tag);
@@ -1193,6 +1461,11 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
 	    checkRegion(tables[j].offset, tables[j].len)) {
 	  dumpString(file + tables[j].offset, tables[j].len,
 		     outputFunc, outputStream);
+	} else if (needVerticalMetrics && i == t42VheaTable) {
+	  dumpString(vheaTab, length, outputFunc, outputStream);
+	} else if (needVerticalMetrics && i == t42VmtxTable) {
+	  dumpString(vmtxTab, length, outputFunc, outputStream);
+	  gfree(vmtxTab);
 	}
       }
     }
@@ -1263,17 +1536,32 @@ Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) {
 }
 
 void FoFiTrueType::parse() {
+  Guint topTag;
   int pos, i, j;
 
   parsedOk = gTrue;
 
+  // look for a collection (TTC)
+  topTag = getU32BE(0, &parsedOk);
+  if (!parsedOk) {
+    return;
+  }
+  if (topTag == ttcfTag) {
+    pos = getU32BE(12, &parsedOk);
+    if (!parsedOk) {
+      return;
+    }
+  } else {
+    pos = 0;
+  }
+
   // read the table directory
-  nTables = getU16BE(4, &parsedOk);
+  nTables = getU16BE(pos + 4, &parsedOk);
   if (!parsedOk) {
     return;
   }
-  tables = (TrueTypeTable *)gmalloc(nTables * sizeof(TrueTypeTable));
-  pos = 12;
+  tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable));
+  pos += 12;
   for (i = 0; i < nTables; ++i) {
     tables[i].tag = getU32BE(pos, &parsedOk);
     tables[i].checksum = getU32BE(pos + 4, &parsedOk);
@@ -1309,7 +1597,7 @@ void FoFiTrueType::parse() {
     if (!parsedOk) {
       return;
     }
-    cmaps = (TrueTypeCmap *)gmalloc(nCmaps * sizeof(TrueTypeCmap));
+    cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap));
     for (j = 0; j < nCmaps; ++j) {
       cmaps[j].platform = getU16BE(pos, &parsedOk);
       cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
@@ -1343,25 +1631,45 @@ void FoFiTrueType::parse() {
     return;
   }
 
-  // read the post table
-  readPostTable();
+  // make sure the loca table is sane (correct length and entries are
+  // in bounds)
+  i = seekTable("loca");
+  if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
+    parsedOk = gFalse;
+    return;
+  }
+  for (j = 0; j <= nGlyphs; ++j) {
+    if (locaFmt) {
+      pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
+    } else {
+      pos = getU16BE(tables[i].offset + j*2, &parsedOk);
+    }
+    if (pos < 0 || pos > len) {
+      parsedOk = gFalse;
+    }
+  }
   if (!parsedOk) {
     return;
   }
+
+  // read the post table
+  readPostTable();
 }
 
 void FoFiTrueType::readPostTable() {
   GString *name;
   int tablePos, postFmt, stringIdx, stringPos;
+  GBool ok;
   int i, j, n, m;
 
+  ok = gTrue;
   if ((i = seekTable("post")) < 0) {
     return;
   }
   tablePos = tables[i].offset;
-  postFmt = getU32BE(tablePos, &parsedOk);
-  if (!parsedOk) {
-    return;
+  postFmt = getU32BE(tablePos, &ok);
+  if (!ok) {
+    goto err;
   }
   if (postFmt == 0x00010000) {
     nameToGID = new GHash(gTrue);
@@ -1370,9 +1678,9 @@ void FoFiTrueType::readPostTable() {
     }
   } else if (postFmt == 0x00020000) {
     nameToGID = new GHash(gTrue);
-    n = getU16BE(tablePos + 32, &parsedOk);
-    if (!parsedOk) {
-      return;
+    n = getU16BE(tablePos + 32, &ok);
+    if (!ok) {
+      goto err;
     }
     if (n > nGlyphs) {
       n = nGlyphs;
@@ -1380,7 +1688,7 @@ void FoFiTrueType::readPostTable() {
     stringIdx = 0;
     stringPos = tablePos + 34 + 2*n;
     for (i = 0; i < n; ++i) {
-      j = getU16BE(tablePos + 34 + 2*i, &parsedOk);
+      j = getU16BE(tablePos + 34 + 2*i, &ok);
       if (j < 258) {
 	nameToGID->removeInt(macGlyphNames[j]);
 	nameToGID->add(new GString(macGlyphNames[j]), i);
@@ -1389,15 +1697,14 @@ void FoFiTrueType::readPostTable() {
 	if (j != stringIdx) {
 	  for (stringIdx = 0, stringPos = tablePos + 34 + 2*n;
 	       stringIdx < j;
-	       ++stringIdx, stringPos += 1 + getU8(stringPos, &parsedOk)) ;
-	  if (!parsedOk) {
-	    return;
+	       ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ;
+	  if (!ok) {
+	    goto err;
 	  }
 	}
-	m = getU8(stringPos, &parsedOk);
-	if (!parsedOk || !checkRegion(stringPos + 1, m)) {
-	  parsedOk = gFalse;
-	  return;
+	m = getU8(stringPos, &ok);
+	if (!ok || !checkRegion(stringPos + 1, m)) {
+	  goto err;
 	}
 	name = new GString((char *)&file[stringPos + 1], m);
 	nameToGID->removeInt(name);
@@ -1409,9 +1716,9 @@ void FoFiTrueType::readPostTable() {
   } else if (postFmt == 0x00028000) {
     nameToGID = new GHash(gTrue);
     for (i = 0; i < nGlyphs; ++i) {
-      j = getU8(tablePos + 32 + i, &parsedOk);
-      if (!parsedOk) {
-	return;
+      j = getU8(tablePos + 32 + i, &ok);
+      if (!ok) {
+	goto err;
       }
       if (j < 258) {
 	nameToGID->removeInt(macGlyphNames[j]);
@@ -1419,6 +1726,14 @@ void FoFiTrueType::readPostTable() {
       }
     }
   }
+
+  return;
+
+ err:
+  if (nameToGID) {
+    delete nameToGID;
+    nameToGID = NULL;
+  }
 }
 
 int FoFiTrueType::seekTable(char *tag) {
diff --git a/pdf2swf/xpdf/FoFiTrueType.h b/pdf2swf/xpdf/FoFiTrueType.h
index ea05eec..f7b09d6 100644
--- a/pdf2swf/xpdf/FoFiTrueType.h
+++ b/pdf2swf/xpdf/FoFiTrueType.h
@@ -18,6 +18,7 @@
 #include "gtypes.h"
 #include "FoFiBase.h"
 
+class GString;
 class GHash;
 struct TrueTypeTable;
 struct TrueTypeCmap;
@@ -83,6 +84,7 @@ public:
   // font).  The <cidMap> array maps CIDs to GIDs; it has <nCIDs>
   // entries.
   void convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs,
+			 GBool needVerticalMetrics,
 			 FoFiOutputFunc outputFunc, void *outputStream);
 
   // Convert to a Type 0 (but non-CID) composite font, suitable for
@@ -91,12 +93,16 @@ public:
   // table in the font).  The <cidMap> array maps CIDs to GIDs; it has
   // <nCIDs> entries.
   void convertToType0(char *psName, Gushort *cidMap, int nCIDs,
+		      GBool needVerticalMetrics,
 		      FoFiOutputFunc outputFunc, void *outputStream);
 
   // Write a clean TTF file, filling in missing tables and correcting
-  // various other errors.  If the font is complete and correct, it
-  // will be written unmodified.
-  void writeTTF(FoFiOutputFunc outputFunc, void *outputStream);
+  // various other errors.  If <name> is non-NULL, the font is renamed
+  // to <name>.  If <codeToGID> is non-NULL, the font is re-encoded,
+  // using a Windows Unicode cmap.  If <name> is NULL and the font is
+  // complete and correct, it will be written unmodified.
+  void writeTTF(FoFiOutputFunc outputFunc, void *outputStream,
+		char *name = NULL, Gushort *codeToGID = NULL);
 
 private:
 
@@ -109,7 +115,8 @@ private:
 		      FoFiOutputFunc outputFunc,
 		      void *outputStream);
   void cvtSfnts(FoFiOutputFunc outputFunc,
-		void *outputStream, GString *name);
+		void *outputStream, GString *name,
+		GBool needVerticalMetrics);
   void dumpString(Guchar *s, int length,
 		  FoFiOutputFunc outputFunc,
 		  void *outputStream);
diff --git a/pdf2swf/xpdf/FoFiType1.cc b/pdf2swf/xpdf/FoFiType1.cc
index fe54a63..a8a69fd 100644
--- a/pdf2swf/xpdf/FoFiType1.cc
+++ b/pdf2swf/xpdf/FoFiType1.cc
@@ -108,6 +108,9 @@ void FoFiType1::writeEncoded(char **newEncoding,
     for (line = getNextLine(line);
 	 line && strncmp(line, "readonly def", 12);
 	 line = getNextLine(line)) ;
+    if (line) {
+      line = getNextLine(line);
+    }
   }
   if (line) {
     (*outputFunc)(outputStream, line, ((char *)file + len) - line);
@@ -156,13 +159,13 @@ void FoFiType1::parse() {
       encoding = fofiType1StandardEncoding;
     } else if (!encoding &&
 	       !strncmp(line, "/Encoding 256 array", 19)) {
-      encoding = (char **)gmalloc(256 * sizeof(char *));
+      encoding = (char **)gmallocn(256, sizeof(char *));
       for (j = 0; j < 256; ++j) {
 	encoding[j] = NULL;
       }
-      line = getNextLine(line);
-      for (j = 0; j < 300 && line; ++j) {
-	line1 = getNextLine(line);
+      for (j = 0, line = getNextLine(line);
+	   j < 300 && line && (line1 = getNextLine(line));
+	   ++j, line = line1) {
 	if ((n = line1 - line) > 255) {
 	  n = 255;
 	}
@@ -187,20 +190,22 @@ void FoFiType1::parse() {
 	    }
 	  }
 	} else {
-	  if (strtok(buf, " \t") &&
-	      (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) {
-	    break;
+	  p = strtok(buf, " \t\n\r");
+	  if (p)
+	  {
+	    if (!strcmp(p, "def")) break;
+	    if (!strcmp(p, "readonly")) break;
+	    // the spec does not says this but i'm mantaining old xpdf behaviour that accepts "foo def" as end of the encoding array
+	    p = strtok(buf, " \t\n\r");
+	    if (p && !strcmp(p, "def")) break;
 	  }
 	}
-	line = line1;
       }
       //~ check for getinterval/putinterval junk
 
     } else {
       line = getNextLine(line);
     }
-
-    ++i;
   }
 
   parsed = gTrue;
diff --git a/pdf2swf/xpdf/FoFiType1C.h b/pdf2swf/xpdf/FoFiType1C.h
index e6f2b64..62649ed 100644
--- a/pdf2swf/xpdf/FoFiType1C.h
+++ b/pdf2swf/xpdf/FoFiType1C.h
@@ -51,6 +51,9 @@ struct Type1CTopDict {
   int paintType;
   int charstringType;
   double fontMatrix[6];
+  GBool hasFontMatrix;		// CID fonts are allowed to put their
+				//   FontMatrix in the FD instead of the
+				//   top dict
   int uniqueID;
   double fontBBox[4];
   double strokeWidth;
@@ -73,6 +76,8 @@ struct Type1CTopDict {
 #define type1CMaxStemSnap   12
 
 struct Type1CPrivateDict {
+  double fontMatrix[6];
+  GBool hasFontMatrix;
   int blueValues[type1CMaxBlueValues];
   int nBlueValues;
   int otherBlues[type1CMaxOtherBlues];
@@ -221,6 +226,7 @@ private:
   int nOps;			// number of operands
   int nHints;			// number of hints for the current glyph
   GBool firstOp;		// true if we haven't hit the first op yet
+  GBool openPath;		// true if there is an unclosed path
 };
 
 #endif
diff --git a/pdf2swf/xpdf/Function.cc b/pdf2swf/xpdf/Function.cc
index 46b1912..f699641 100644
--- a/pdf2swf/xpdf/Function.cc
+++ b/pdf2swf/xpdf/Function.cc
@@ -185,7 +185,7 @@ void IdentityFunction::transform(double *in, double *out) {
 
 SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
   Stream *str;
-  int nSamples, sampleBits;
+  int sampleBits;
   double sampleMul;
   Object obj1, obj2;
   Guint buf, bitMask;
@@ -228,6 +228,10 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
     obj2.free();
   }
   obj1.free();
+  idxMul[0] = n;
+  for (i = 1; i < m; ++i) {
+    idxMul[i] = idxMul[i-1] * sampleSize[i-1];
+  }
 
   //----- BitsPerSample
   if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
@@ -264,6 +268,10 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
     }
   }
   obj1.free();
+  for (i = 0; i < m; ++i) {
+    inputMul[i] = (encode[i][1] - encode[i][0]) /
+                  (domain[i][1] - domain[i][0]);
+  }
 
   //----- Decode
   if (dict->lookup("Decode", &obj1)->isArray() &&
@@ -296,7 +304,7 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
   nSamples = n;
   for (i = 0; i < m; ++i)
     nSamples *= sampleSize[i];
-  samples = (double *)gmalloc(nSamples * sizeof(double));
+  samples = (double *)gmallocn(nSamples, sizeof(double));
   buf = 0;
   bits = 0;
   bitMask = (1 << sampleBits) - 1;
@@ -342,37 +350,34 @@ SampledFunction::~SampledFunction() {
 }
 
 SampledFunction::SampledFunction(SampledFunction *func) {
-  int nSamples, i;
-
   memcpy(this, func, sizeof(SampledFunction));
-
-  nSamples = n;
-  for (i = 0; i < m; ++i) {
-    nSamples *= sampleSize[i];
-  }
-  samples = (double *)gmalloc(nSamples * sizeof(double));
+  samples = (double *)gmallocn(nSamples, sizeof(double));
   memcpy(samples, func->samples, nSamples * sizeof(double));
 }
 
 void SampledFunction::transform(double *in, double *out) {
   double x;
-  int e[2][funcMaxInputs];
-  double efrac[funcMaxInputs];
-  double s0[1 << funcMaxInputs], s1[1 << funcMaxInputs];
-  int i, j, k, idx;
+  int e[funcMaxInputs][2];
+  double efrac0[funcMaxInputs];
+  double efrac1[funcMaxInputs];
+  double s[1 << funcMaxInputs];
+  int i, j, k, idx, t;
 
   // 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];
+    x = (in[i] - domain[i][0]) * inputMul[i] + 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];
+    e[i][0] = (int)x;
+    if ((e[i][1] = e[i][0] + 1) >= sampleSize[i]) {
+      // this happens if in[i] = domain[i][1]
+      e[i][1] = e[i][0];
+    }
+    efrac1[i] = x - e[i][0];
+    efrac0[i] = 1 - efrac1[i];
   }
 
   // for each output, do m-linear interpolation
@@ -380,24 +385,22 @@ void SampledFunction::transform(double *in, double *out) {
 
     // pull 2^m values out of the sample array
     for (j = 0; j < (1<<m); ++j) {
-      idx = 0;
-      for (k = m - 1; k >= 0; --k) {
-	idx = idx * sampleSize[k] + e[(j >> k) & 1][k];
+      idx = i;
+      for (k = 0, t = j; k < m; ++k, t >>= 1) {
+	idx += idxMul[k] * (e[k][t & 1]);
       }
-      idx = idx * n + i;
-      s0[j] = samples[idx];
+      s[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];
+    for (j = 0, t = (1<<m); j < m; ++j, t >>= 1) {
+      for (k = 0; k < t; k += 2) {
+	s[k >> 1] = efrac0[j] * s[k] + efrac1[j] * s[k+1];
       }
-      memcpy(s0, s1, (1 << (m - j - 1)) * sizeof(double));
     }
 
     // map output value to range
-    out[i] = s0[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
+    out[i] = s[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]) {
@@ -553,9 +556,9 @@ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) {
     goto err1;
   }
   k = obj1.arrayGetLength();
-  funcs = (Function **)gmalloc(k * sizeof(Function *));
-  bounds = (double *)gmalloc((k + 1) * sizeof(double));
-  encode = (double *)gmalloc(2 * k * sizeof(double));
+  funcs = (Function **)gmallocn(k, sizeof(Function *));
+  bounds = (double *)gmallocn(k + 1, sizeof(double));
+  encode = (double *)gmallocn(2 * k, sizeof(double));
   for (i = 0; i < k; ++i) {
     funcs[i] = NULL;
   }
@@ -619,13 +622,13 @@ StitchingFunction::StitchingFunction(StitchingFunction *func) {
   int i;
 
   k = func->k;
-  funcs = (Function **)gmalloc(k * sizeof(Function *));
+  funcs = (Function **)gmallocn(k, sizeof(Function *));
   for (i = 0; i < k; ++i) {
     funcs[i] = func->funcs[i]->copy();
   }
-  bounds = (double *)gmalloc((k + 1) * sizeof(double));
+  bounds = (double *)gmallocn(k + 1, sizeof(double));
   memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
-  encode = (double *)gmalloc(2 * k * sizeof(double));
+  encode = (double *)gmallocn(2 * k, sizeof(double));
   memcpy(encode, func->encode, 2 * k * sizeof(double));
   ok = gTrue;
 }
@@ -916,10 +919,14 @@ double PSStack::popNum() {
 void PSStack::copy(int n) {
   int i;
 
+  if (sp + n > psStackSize) {
+    error(-1, "Stack underflow in PostScript function");
+    return;
+  }
   if (!checkOverflow(n)) {
     return;
   }
-  for (i = sp + n - 1; i <= sp; ++i) {
+  for (i = sp + n - 1; i >= sp; --i) {
     stack[i - n] = stack[i];
   }
   sp -= n;
@@ -990,6 +997,7 @@ PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
   str = funcObj->getStream();
 
   //----- parse the function
+  codeString = new GString();
   str->reset();
   if (!(tok = getToken(str)) || tok->cmp("{")) {
     error(-1, "Expected '{' at start of PostScript function");
@@ -1015,12 +1023,14 @@ PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
 
 PostScriptFunction::PostScriptFunction(PostScriptFunction *func) {
   memcpy(this, func, sizeof(PostScriptFunction));
-  code = (PSObject *)gmalloc(codeSize * sizeof(PSObject));
+  code = (PSObject *)gmallocn(codeSize, sizeof(PSObject));
   memcpy(code, func->code, codeSize * sizeof(PSObject));
+  codeString = func->codeString->copy();
 }
 
 PostScriptFunction::~PostScriptFunction() {
   gfree(code);
+  delete codeString;
 }
 
 void PostScriptFunction::transform(double *in, double *out) {
@@ -1174,6 +1184,9 @@ GString *PostScriptFunction::getToken(Stream *str) {
   s = new GString();
   do {
     c = str->getChar();
+    if (c != EOF) {
+      codeString->append(c);
+    }
   } while (c != EOF && isspace(c));
   if (c == '{' || c == '}') {
     s->append((char)c);
@@ -1185,6 +1198,7 @@ GString *PostScriptFunction::getToken(Stream *str) {
 	break;
       }
       str->getChar();
+      codeString->append(c);
     }
   } else {
     while (1) {
@@ -1194,6 +1208,7 @@ GString *PostScriptFunction::getToken(Stream *str) {
 	break;
       }
       str->getChar();
+      codeString->append(c);
     }
   }
   return s;
@@ -1202,7 +1217,7 @@ GString *PostScriptFunction::getToken(Stream *str) {
 void PostScriptFunction::resizeCode(int newSize) {
   if (newSize >= codeSize) {
     codeSize += 64;
-    code = (PSObject *)grealloc(code, codeSize * sizeof(PSObject));
+    code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject));
   }
 }
 
diff --git a/pdf2swf/xpdf/Function.h b/pdf2swf/xpdf/Function.h
index 0ceb035..bfaf83e 100644
--- a/pdf2swf/xpdf/Function.h
+++ b/pdf2swf/xpdf/Function.h
@@ -45,10 +45,24 @@ public:
 
   virtual Function *copy() = 0;
 
+  // Return the function type:
+  //   -1 : identity
+  //    0 : sampled
+  //    2 : exponential
+  //    3 : stitching
+  //    4 : PostScript
+  virtual int getType() = 0;
+
   // Return size of input and output tuples.
   int getInputSize() { return m; }
   int getOutputSize() { return n; }
 
+  double getDomainMin(int i) { return domain[i][0]; }
+  double getDomainMax(int i) { return domain[i][1]; }
+  double getRangeMin(int i) { return range[i][0]; }
+  double getRangeMax(int i) { return range[i][1]; }
+  GBool getHasRange() { return hasRange; }
+
   // Transform an input tuple into an output tuple.
   virtual void transform(double *in, double *out) = 0;
 
@@ -74,6 +88,7 @@ public:
   IdentityFunction();
   virtual ~IdentityFunction();
   virtual Function *copy() { return new IdentityFunction(); }
+  virtual int getType() { return -1; }
   virtual void transform(double *in, double *out);
   virtual GBool isOk() { return gTrue; }
 
@@ -90,9 +105,17 @@ public:
   SampledFunction(Object *funcObj, Dict *dict);
   virtual ~SampledFunction();
   virtual Function *copy() { return new SampledFunction(this); }
+  virtual int getType() { return 0; }
   virtual void transform(double *in, double *out);
   virtual GBool isOk() { return ok; }
 
+  int getSampleSize(int i) { return sampleSize[i]; }
+  double getEncodeMin(int i) { return encode[i][0]; }
+  double getEncodeMax(int i) { return encode[i][1]; }
+  double getDecodeMin(int i) { return decode[i][0]; }
+  double getDecodeMax(int i) { return decode[i][1]; }
+  double *getSamples() { return samples; }
+
 private:
 
   SampledFunction(SampledFunction *func);
@@ -103,7 +126,11 @@ private:
     encode[funcMaxInputs][2];
   double			// min and max values for range decoder
     decode[funcMaxOutputs][2];
+  double			// input multipliers
+    inputMul[funcMaxInputs];
+  int idxMul[funcMaxInputs];	// sample array index multipliers
   double *samples;		// the samples
+  int nSamples;			// size of the samples array
   GBool ok;
 };
 
@@ -117,9 +144,14 @@ public:
   ExponentialFunction(Object *funcObj, Dict *dict);
   virtual ~ExponentialFunction();
   virtual Function *copy() { return new ExponentialFunction(this); }
+  virtual int getType() { return 2; }
   virtual void transform(double *in, double *out);
   virtual GBool isOk() { return ok; }
 
+  double *getC0() { return c0; }
+  double *getC1() { return c1; }
+  double getE() { return e; }
+
 private:
 
   ExponentialFunction(ExponentialFunction *func);
@@ -140,9 +172,15 @@ public:
   StitchingFunction(Object *funcObj, Dict *dict);
   virtual ~StitchingFunction();
   virtual Function *copy() { return new StitchingFunction(this); }
+  virtual int getType() { return 3; }
   virtual void transform(double *in, double *out);
   virtual GBool isOk() { return ok; }
 
+  int getNumFuncs() { return k; }
+  Function *getFunc(int i) { return funcs[i]; }
+  double *getBounds() { return bounds; }
+  double *getEncode() { return encode; }
+
 private:
 
   StitchingFunction(StitchingFunction *func);
@@ -164,9 +202,12 @@ public:
   PostScriptFunction(Object *funcObj, Dict *dict);
   virtual ~PostScriptFunction();
   virtual Function *copy() { return new PostScriptFunction(this); }
+  virtual int getType() { return 4; }
   virtual void transform(double *in, double *out);
   virtual GBool isOk() { return ok; }
 
+  GString *getCodeString() { return codeString; }
+
 private:
 
   PostScriptFunction(PostScriptFunction *func);
@@ -175,6 +216,7 @@ private:
   void resizeCode(int newSize);
   void exec(PSStack *stack, int codePtr);
 
+  GString *codeString;
   PSObject *code;
   int codeSize;
   GBool ok;
diff --git a/pdf2swf/xpdf/GHash.cc b/pdf2swf/xpdf/GHash.cc
index 1dd0e26..b51a764 100644
--- a/pdf2swf/xpdf/GHash.cc
+++ b/pdf2swf/xpdf/GHash.cc
@@ -39,7 +39,7 @@ GHash::GHash(GBool deleteKeysA) {
 
   deleteKeys = deleteKeysA;
   size = 7;
-  tab = (GHashBucket **)gmalloc(size * sizeof(GHashBucket *));
+  tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *));
   for (h = 0; h < size; ++h) {
     tab[h] = NULL;
   }
@@ -101,6 +101,30 @@ void GHash::add(GString *key, int val) {
   ++len;
 }
 
+void GHash::replace(GString *key, void *val) {
+  GHashBucket *p;
+  int h;
+
+  if ((p = find(key, &h))) {
+    p->val.p = val;
+    delete key;
+  } else {
+    add(key, val);
+  }
+}
+
+void GHash::replace(GString *key, int val) {
+  GHashBucket *p;
+  int h;
+
+  if ((p = find(key, &h))) {
+    p->val.i = val;
+    delete key;
+  } else {
+    add(key, val);
+  }
+}
+
 void *GHash::lookup(GString *key) {
   GHashBucket *p;
   int h;
@@ -292,7 +316,7 @@ void GHash::expand() {
   oldSize = size;
   oldTab = tab;
   size = 2*size + 1;
-  tab = (GHashBucket **)gmalloc(size * sizeof(GHashBucket *));
+  tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *));
   for (h = 0; h < size; ++h) {
     tab[h] = NULL;
   }
diff --git a/pdf2swf/xpdf/GHash.h b/pdf2swf/xpdf/GHash.h
index 4a6e08d..31aba93 100644
--- a/pdf2swf/xpdf/GHash.h
+++ b/pdf2swf/xpdf/GHash.h
@@ -30,6 +30,8 @@ public:
   ~GHash();
   void add(GString *key, void *val);
   void add(GString *key, int val);
+  void replace(GString *key, void *val);
+  void replace(GString *key, int val);
   void *lookup(GString *key);
   int lookupInt(GString *key);
   void *lookup(char *key);
diff --git a/pdf2swf/xpdf/GList.cc b/pdf2swf/xpdf/GList.cc
index 9534232..fb5fd62 100644
--- a/pdf2swf/xpdf/GList.cc
+++ b/pdf2swf/xpdf/GList.cc
@@ -12,6 +12,7 @@
 #pragma implementation
 #endif
 
+#include <stdlib.h>
 #include <string.h>
 #include "gmem.h"
 #include "GList.h"
@@ -22,14 +23,14 @@
 
 GList::GList() {
   size = 8;
-  data = (void **)gmalloc(size * sizeof(void*));
+  data = (void **)gmallocn(size, sizeof(void*));
   length = 0;
   inc = 0;
 }
 
 GList::GList(int sizeA) {
   size = sizeA;
-  data = (void **)gmalloc(size * sizeof(void*));
+  data = (void **)gmallocn(size, sizeof(void*));
   length = 0;
   inc = 0;
 }
@@ -81,12 +82,16 @@ void *GList::del(int i) {
   return p;
 }
 
+void GList::sort(int (*cmp)(const void *obj1, const void *obj2)) {
+  qsort(data, length, sizeof(void *), cmp);
+}
+
 void GList::expand() {
   size += (inc > 0) ? inc : size;
-  data = (void **)grealloc(data, size * sizeof(void*));
+  data = (void **)greallocn(data, size, sizeof(void*));
 }
 
 void GList::shrink() {
   size -= (inc > 0) ? inc : size/2;
-  data = (void **)grealloc(data, size * sizeof(void*));
+  data = (void **)greallocn(data, size, sizeof(void*));
 }
diff --git a/pdf2swf/xpdf/GList.h b/pdf2swf/xpdf/GList.h
index 4c52489..e4d8ff8 100644
--- a/pdf2swf/xpdf/GList.h
+++ b/pdf2swf/xpdf/GList.h
@@ -58,6 +58,11 @@ public:
   // Assumes 0 <= i < length.
   void *del(int i);
 
+  // Sort the list accoring to the given comparison function.
+  // NB: this sorts an array of pointers, so the pointer args need to
+  // be double-dereferenced.
+  void sort(int (*cmp)(const void *ptr1, const void *ptr2));
+
   //----- control
 
   // Set allocation increment to <inc>.  If inc > 0, that many
diff --git a/pdf2swf/xpdf/GString.cc b/pdf2swf/xpdf/GString.cc
index 7653fd0..049dcf3 100644
--- a/pdf2swf/xpdf/GString.cc
+++ b/pdf2swf/xpdf/GString.cc
@@ -35,7 +35,12 @@ inline void GString::resize(int length1) {
     s = new char[size(length1)];
   } else if (size(length1) != size(length)) {
     s1 = new char[size(length1)];
-    memcpy(s1, s, length + 1);
+    if (length1 < length) {
+      memcpy(s1, s, length1);
+      s1[length1] = '\0';
+    } else {
+      memcpy(s1, s, length + 1);
+    }
     delete[] s;
     s = s1;
   }
@@ -234,3 +239,81 @@ GString *GString::lowerCase() {
   }
   return this;
 }
+
+int GString::cmp(GString *str) {
+  int n1, n2, i, x;
+  char *p1, *p2;
+
+  n1 = length;
+  n2 = str->length;
+  for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) {
+    x = *p1 - *p2;
+    if (x != 0) {
+      return x;
+    }
+  }
+  return n1 - n2;
+}
+
+int GString::cmpN(GString *str, int n) {
+  int n1, n2, i, x;
+  char *p1, *p2;
+
+  n1 = length;
+  n2 = str->length;
+  for (i = 0, p1 = s, p2 = str->s;
+       i < n1 && i < n2 && i < n;
+       ++i, ++p1, ++p2) {
+    x = *p1 - *p2;
+    if (x != 0) {
+      return x;
+    }
+  }
+  if (i == n) {
+    return 0;
+  }
+  return n1 - n2;
+}
+
+int GString::cmp(const char *sA) {
+  int n1, i, x;
+  const char *p1, *p2;
+
+  n1 = length;
+  for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) {
+    x = *p1 - *p2;
+    if (x != 0) {
+      return x;
+    }
+  }
+  if (i < n1) {
+    return 1;
+  }
+  if (*p2) {
+    return -1;
+  }
+  return 0;
+}
+
+int GString::cmpN(const char *sA, int n) {
+  int n1, i, x;
+  const char *p1, *p2;
+
+  n1 = length;
+  for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) {
+    x = *p1 - *p2;
+    if (x != 0) {
+      return x;
+    }
+  }
+  if (i == n) {
+    return 0;
+  }
+  if (i < n1) {
+    return 1;
+  }
+  if (*p2) {
+    return -1;
+  }
+  return 0;
+}
diff --git a/pdf2swf/xpdf/GString.h b/pdf2swf/xpdf/GString.h
index 2083802..f4ff7c6 100644
--- a/pdf2swf/xpdf/GString.h
+++ b/pdf2swf/xpdf/GString.h
@@ -17,8 +17,6 @@
 #pragma interface
 #endif
 
-#include <string.h>
-
 class GString {
 public:
 
@@ -83,11 +81,10 @@ public:
   GString *lowerCase();
 
   // Compare two strings:  -1:<  0:=  +1:>
-  // These functions assume the strings do not contain null characters.
-  int cmp(GString *str) { return strcmp(s, str->getCString()); }
-  int cmpN(GString *str, int n) { return strncmp(s, str->getCString(), n); }
-  int cmp(const char *sA) { return strcmp(s, sA); }
-  int cmpN(const char *sA, int n) { return strncmp(s, sA, n); }
+  int cmp(GString *str);
+  int cmpN(GString *str, int n);
+  int cmp(const char *sA);
+  int cmpN(const char *sA, int n);
 
 private:
 
diff --git a/pdf2swf/xpdf/Gfx.h b/pdf2swf/xpdf/Gfx.h
index 2e40a57..168206d 100644
--- a/pdf2swf/xpdf/Gfx.h
+++ b/pdf2swf/xpdf/Gfx.h
@@ -33,6 +33,9 @@ class GfxShading;
 class GfxFunctionShading;
 class GfxAxialShading;
 class GfxRadialShading;
+class GfxGouraudTriangleShading;
+class GfxPatchMeshShading;
+struct GfxPatch;
 class GfxState;
 struct GfxColor;
 class Gfx;
@@ -101,14 +104,14 @@ public:
 
   // Constructor for regular output.
   Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict,
-      double hDPI, double vDPI, PDFRectangle *box, GBool crop,
+      double hDPI, double vDPI, PDFRectangle *box,
       PDFRectangle *cropBox, int rotate,
       GBool (*abortCheckCbkA)(void *data) = NULL,
       void *abortCheckCbkDataA = NULL);
 
   // Constructor for a sub-page object.
   Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
-      PDFRectangle *box, GBool crop, PDFRectangle *cropBox,
+      PDFRectangle *box, PDFRectangle *cropBox,
       GBool (*abortCheckCbkA)(void *data) = NULL,
       void *abortCheckCbkDataA = NULL);
 
@@ -128,6 +131,9 @@ public:
   // Restore graphics state.
   void restoreState();
 
+  // Get the current graphics state object.
+  GfxState *getState() { return state; }
+
 private:
 
   XRef *xref;			// the xref table for this PDF file
@@ -216,6 +222,13 @@ private:
 			 GfxColor *colors, int depth);
   void doAxialShFill(GfxAxialShading *shading);
   void doRadialShFill(GfxRadialShading *shading);
+  void doGouraudTriangleShFill(GfxGouraudTriangleShading *shading);
+  void gouraudFillTriangle(double x0, double y0, GfxColor *color0,
+			   double x1, double y1, GfxColor *color1,
+			   double x2, double y2, GfxColor *color2,
+			   int nComps, int depth);
+  void doPatchMeshShFill(GfxPatchMeshShading *shading);
+  void fillPatch(GfxPatch *patch, int nComps, int depth);
   void doEndPath();
 
   // path clipping operators
diff --git a/pdf2swf/xpdf/GfxFont.cc b/pdf2swf/xpdf/GfxFont.cc
index ed9f076..a4581c0 100644
--- a/pdf2swf/xpdf/GfxFont.cc
+++ b/pdf2swf/xpdf/GfxFont.cc
@@ -55,8 +55,8 @@ static StdFontMapEntry stdFontMap[] = {
   { "Arial-ItalicMT",               "Helvetica-Oblique" },
   { "ArialMT",                      "Helvetica" },
   { "Courier,Bold",                 "Courier-Bold" },
-  { "Courier,Italic",               "Courier-Oblique" },
   { "Courier,BoldItalic",           "Courier-BoldOblique" },
+  { "Courier,Italic",               "Courier-Oblique" },
   { "CourierNew",                   "Courier" },
   { "CourierNew,Bold",              "Courier-Bold" },
   { "CourierNew,BoldItalic",        "Courier-BoldOblique" },
@@ -191,19 +191,19 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
 
     // look for embedded font file
     if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) {
-      if (type == fontType1) {
-	embFontID = obj2.getRef();
-      } else {
+      embFontID = obj2.getRef();
+      if (type != fontType1) {
 	error(-1, "Mismatch between font type and embedded font file");
+	type = fontType1;
       }
     }
     obj2.free();
     if (embFontID.num == -1 &&
 	obj1.dictLookupNF("FontFile2", &obj2)->isRef()) {
-      if (type == fontTrueType || type == fontCIDType2) {
-	embFontID = obj2.getRef();
-      } else {
+      embFontID = obj2.getRef();
+      if (type != fontTrueType && type != fontCIDType2) {
 	error(-1, "Mismatch between font type and embedded font file");
+	type = type == fontCIDType0 ? fontCIDType2 : fontTrueType;
       }
     }
     obj2.free();
@@ -212,33 +212,29 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
       if (obj2.fetch(xref, &obj3)->isStream()) {
 	obj3.streamGetDict()->lookup("Subtype", &obj4);
 	if (obj4.isName("Type1")) {
-	  if (type == fontType1) {
-	    embFontID = obj2.getRef();
-	  } else {
+	  embFontID = obj2.getRef();
+	  if (type != fontType1) {
 	    error(-1, "Mismatch between font type and embedded font file");
+	    type = fontType1;
 	  }
 	} else if (obj4.isName("Type1C")) {
-	  if (type == fontType1) {
-	    type = fontType1C;
-	    embFontID = obj2.getRef();
-	  } else if (type == fontType1C) {
-	    embFontID = obj2.getRef();
-	  } else {
+	  embFontID = obj2.getRef();
+	  if (type != fontType1 && type != fontType1C) {
 	    error(-1, "Mismatch between font type and embedded font file");
 	  }
+	  type = fontType1C;
 	} else if (obj4.isName("TrueType")) {
-	  if (type == fontTrueType) {
-	    embFontID = obj2.getRef();
-	  } else {
+	  embFontID = obj2.getRef();
+	  if (type != fontTrueType) {
 	    error(-1, "Mismatch between font type and embedded font file");
+	    type = fontTrueType;
 	  }
 	} else if (obj4.isName("CIDFontType0C")) {
-	  if (type == fontCIDType0) {
-	    type = fontCIDType0C;
-	    embFontID = obj2.getRef();
-	  } else {
+	  embFontID = obj2.getRef();
+	  if (type != fontCIDType0) {
 	    error(-1, "Mismatch between font type and embedded font file");
 	  }
+	  type = fontCIDType0C;
 	} else {
 	  error(-1, "Unknown embedded font type '%s'",
 		obj4.isName() ? obj4.getName() : "???");
@@ -399,6 +395,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
 			 GfxFontType typeA, Dict *fontDict):
   GfxFont(tagA, idA, nameA)
 {
+  GString *name2;
   BuiltinFont *builtinFont;
   char **baseEnc;
   GBool baseEncFromFontFile;
@@ -424,20 +421,30 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
   // do font name substitution for various aliases of the Base 14 font
   // names
   if (name) {
+    name2 = name->copy();
+    i = 0;
+    while (i < name2->getLength()) {
+      if (name2->getChar(i) == ' ') {
+	name2->del(i);
+      } else {
+	++i;
+      }
+    }
     a = 0;
     b = sizeof(stdFontMap) / sizeof(StdFontMapEntry);
-    // invariant: stdFontMap[a].altName <= name < stdFontMap[b].altName
+    // invariant: stdFontMap[a].altName <= name2 < stdFontMap[b].altName
     while (b - a > 1) {
       m = (a + b) / 2;
-      if (name->cmp(stdFontMap[m].altName) >= 0) {
+      if (name2->cmp(stdFontMap[m].altName) >= 0) {
 	a = m;
       } else {
 	b = m;
       }
     }
-    if (!name->cmp(stdFontMap[a].altName)) {
+    if (!name2->cmp(stdFontMap[a].altName)) {
       name = new GString(stdFontMap[a].properName);
     }
+    delete name2;
   }
 
   // is it a built-in font?
@@ -468,6 +475,17 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
   // get info from font descriptor
   readFontDescriptor(xref, fontDict);
 
+  // for non-embedded fonts, don't trust the ascent/descent/bbox
+  // values from the font descriptor
+  if (builtinFont && embFontID.num < 0) {
+    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];
+  }
+
   // look for an external font file
   findExtFontFile();
 
@@ -513,7 +531,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
   //   2. embedded or external font file
   //   3. default:
   //        - builtin --> builtin encoding
-  //        - TrueType --> MacRomanEncoding
+  //        - TrueType --> WinAnsiEncoding
   //        - others --> StandardEncoding
   // and then add a list of differences (if any) from
   // FontDict.Encoding.Differences.
@@ -536,9 +554,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
     } 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")) {
@@ -551,9 +566,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
   } 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
@@ -607,7 +619,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
 
   // get default base encoding
   if (!baseEnc) {
-    if (builtinFont) {
+    if (builtinFont && embFontID.num < 0) {
       baseEnc = builtinFont->defaultBaseEnc;
       hasEncoding = gTrue;
     } else if (type == fontTrueType) {
@@ -899,7 +911,7 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
   Unicode u;
   int code, i, n;
 
-  map = (Gushort *)gmalloc(256 * sizeof(Gushort));
+  map = (Gushort *)gmallocn(256, sizeof(Gushort));
   for (i = 0; i < 256; ++i) {
     map[i] = 0;
   }
@@ -919,7 +931,8 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
   //        directly (possibly with an offset of 0xf000).
   //    1d. If the TrueType font has a Macintosh Roman cmap, use it,
   //        as in case 1a.
-  // 2. If the PDF font does not have an encoding:
+  // 2. If the PDF font does not have an encoding or the PDF font is
+  //    symbolic:
   //    2a. If the TrueType font has a Macintosh Roman cmap, use it,
   //        and use char codes directly (possibly with an offset of
   //        0xf000).
@@ -953,6 +966,8 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
       useUnicode = gTrue;
     } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) {
       cmap = msSymbolCmap;
+    } else if ((flags & fontSymbolic) && macRomanCmap >= 0) {
+      cmap = macRomanCmap;
     } else if (macRomanCmap >= 0) {
       cmap = macRomanCmap;
       useMacRoman = gTrue;
@@ -979,7 +994,9 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
   // map Unicode through the cmap
   } else if (useUnicode) {
     for (i = 0; i < 256; ++i) {
-      if ((n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
+      if (((charName = enc[i]) &&
+	   (u = globalParams->mapNameToUnicode(charName))) ||
+	  (n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
 	map[i] = ff->mapCodeToGID(cmap, u);
       }
     }
@@ -1043,8 +1060,11 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
   GString *collection, *cMapName;
   Object desFontDictObj;
   Object obj1, obj2, obj3, obj4, obj5, obj6;
+  CharCodeToUnicode *utu;
+  CharCode c;
+  Unicode uBuf[8];
   int c1, c2;
-  int excepsSize, i, j, k;
+  int excepsSize, i, j, k, n;
 
   ascent = 0.95;
   descent = -0.35;
@@ -1126,9 +1146,27 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
       if (!(ctu = globalParams->getCIDToUnicode(collection))) {
 	error(-1, "Unknown character collection '%s'",
 	      collection->getCString());
-	delete collection;
-	goto err2;
+	// fall-through, assuming the Identity mapping -- this appears
+	// to match Adobe's behavior
+      }
+    }
+  }
+
+  // look for a Unicode-to-Unicode mapping
+  if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
+    if (ctu) {
+      for (c = 0; c < ctu->getLength(); ++c) {
+	n = ctu->mapToUnicode(c, uBuf, 8);
+	if (n >= 1) {
+	  n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8);
+	  if (n >= 1) {
+	    ctu->setMapping(c, uBuf, n);
+	  }
+	}
       }
+      utu->decRefCnt();
+    } else {
+      ctu = utu;
     }
   }
 
@@ -1158,13 +1196,13 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
     if (obj1.isStream()) {
       cidToGIDLen = 0;
       i = 64;
-      cidToGID = (Gushort *)gmalloc(i * sizeof(Gushort));
+      cidToGID = (Gushort *)gmallocn(i, sizeof(Gushort));
       obj1.streamReset();
       while ((c1 = obj1.streamGetChar()) != EOF &&
 	     (c2 = obj1.streamGetChar()) != EOF) {
 	if (cidToGIDLen == i) {
 	  i *= 2;
-	  cidToGID = (Gushort *)grealloc(cidToGID, i * sizeof(Gushort));
+	  cidToGID = (Gushort *)greallocn(cidToGID, i, sizeof(Gushort));
 	}
 	cidToGID[cidToGIDLen++] = (Gushort)((c1 << 8) + c2);
       }
@@ -1194,8 +1232,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
 	  if (widths.nExceps == excepsSize) {
 	    excepsSize += 16;
 	    widths.exceps = (GfxFontCIDWidthExcep *)
-	      grealloc(widths.exceps,
-		       excepsSize * sizeof(GfxFontCIDWidthExcep));
+	      greallocn(widths.exceps,
+			excepsSize, sizeof(GfxFontCIDWidthExcep));
 	  }
 	  widths.exceps[widths.nExceps].first = obj2.getInt();
 	  widths.exceps[widths.nExceps].last = obj3.getInt();
@@ -1210,8 +1248,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
 	if (widths.nExceps + obj3.arrayGetLength() > excepsSize) {
 	  excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15;
 	  widths.exceps = (GfxFontCIDWidthExcep *)
-	    grealloc(widths.exceps,
-		     excepsSize * sizeof(GfxFontCIDWidthExcep));
+	    greallocn(widths.exceps,
+		      excepsSize, sizeof(GfxFontCIDWidthExcep));
 	}
 	j = obj2.getInt();
 	for (k = 0; k < obj3.arrayGetLength(); ++k) {
@@ -1267,8 +1305,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
 	  if (widths.nExcepsV == excepsSize) {
 	    excepsSize += 16;
 	    widths.excepsV = (GfxFontCIDWidthExcepV *)
-	      grealloc(widths.excepsV,
-		       excepsSize * sizeof(GfxFontCIDWidthExcepV));
+	      greallocn(widths.excepsV,
+			excepsSize, sizeof(GfxFontCIDWidthExcepV));
 	  }
 	  widths.excepsV[widths.nExcepsV].first = obj2.getInt();
 	  widths.excepsV[widths.nExcepsV].last = obj3.getInt();
@@ -1288,8 +1326,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
 	  excepsSize =
 	    (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15;
 	  widths.excepsV = (GfxFontCIDWidthExcepV *)
-	    grealloc(widths.excepsV,
-		     excepsSize * sizeof(GfxFontCIDWidthExcepV));
+	    greallocn(widths.excepsV,
+		      excepsSize, sizeof(GfxFontCIDWidthExcepV));
 	}
 	j = obj2.getInt();
 	for (k = 0; k < obj3.arrayGetLength(); k += 3) {
@@ -1452,7 +1490,7 @@ GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) {
   Ref r;
 
   numFonts = fontDict->getLength();
-  fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *));
+  fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *));
   for (i = 0; i < numFonts; ++i) {
     fontDict->getValNF(i, &obj1);
     obj1.fetch(xref, &obj2);
diff --git a/pdf2swf/xpdf/GfxState.h b/pdf2swf/xpdf/GfxState.h
index f747a83..e1d6801 100644
--- a/pdf2swf/xpdf/GfxState.h
+++ b/pdf2swf/xpdf/GfxState.h
@@ -25,21 +25,80 @@ class PDFRectangle;
 class GfxShading;
 
 //------------------------------------------------------------------------
+// GfxBlendMode
+//------------------------------------------------------------------------
+
+enum GfxBlendMode {
+  gfxBlendNormal,
+  gfxBlendMultiply,
+  gfxBlendScreen,
+  gfxBlendOverlay,
+  gfxBlendDarken,
+  gfxBlendLighten,
+  gfxBlendColorDodge,
+  gfxBlendColorBurn,
+  gfxBlendHardLight,
+  gfxBlendSoftLight,
+  gfxBlendDifference,
+  gfxBlendExclusion,
+  gfxBlendHue,
+  gfxBlendSaturation,
+  gfxBlendColor,
+  gfxBlendLuminosity
+};
+
+//------------------------------------------------------------------------
+// GfxColorComp
+//------------------------------------------------------------------------
+
+// 16.16 fixed point color component
+typedef int GfxColorComp;
+
+#define gfxColorComp1 0x10000
+
+static inline GfxColorComp dblToCol(double x) {
+  return (GfxColorComp)(x * gfxColorComp1);
+}
+
+static inline double colToDbl(GfxColorComp x) {
+  return (double)x / (double)gfxColorComp1;
+}
+
+static inline GfxColorComp byteToCol(Guchar x) {
+  // (x / 255) << 16  =  (0.0000000100000001... * x) << 16
+  //                  =  ((x << 8) + (x) + (x >> 8) + ...) << 16
+  //                  =  (x << 8) + (x) + (x >> 7)
+  //                                      [for rounding]
+  return (GfxColorComp)((x << 8) + x + (x >> 7));
+}
+
+static inline Guchar colToByte(GfxColorComp x) {
+  // 255 * x + 0.5  =  256 * x - x + 0x8000
+  return (Guchar)(((x << 8) - x + 0x8000) >> 16);
+}
+
+//------------------------------------------------------------------------
 // GfxColor
 //------------------------------------------------------------------------
 
 #define gfxColorMaxComps funcMaxOutputs
 
 struct GfxColor {
-  double c[gfxColorMaxComps];
+  GfxColorComp c[gfxColorMaxComps];
 };
 
 //------------------------------------------------------------------------
+// GfxGray
+//------------------------------------------------------------------------
+
+typedef GfxColorComp GfxGray;
+
+//------------------------------------------------------------------------
 // GfxRGB
 //------------------------------------------------------------------------
 
 struct GfxRGB {
-  double r, g, b;
+  GfxColorComp r, g, b;
 };
 
 //------------------------------------------------------------------------
@@ -47,7 +106,7 @@ struct GfxRGB {
 //------------------------------------------------------------------------
 
 struct GfxCMYK {
-  double c, m, y, k;
+  GfxColorComp c, m, y, k;
 };
 
 //------------------------------------------------------------------------
@@ -82,7 +141,7 @@ public:
   static GfxColorSpace *parse(Object *csObj);
 
   // Convert to gray, RGB, or CMYK.
-  virtual void getGray(GfxColor *color, double *gray) = 0;
+  virtual void getGray(GfxColor *color, GfxGray *gray) = 0;
   virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0;
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0;
 
@@ -115,7 +174,7 @@ public:
   virtual GfxColorSpace *copy();
   virtual GfxColorSpaceMode getMode() { return csDeviceGray; }
 
-  virtual void getGray(GfxColor *color, double *gray);
+  virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
@@ -139,7 +198,7 @@ public:
   // Construct a CalGray color space.  Returns NULL if unsuccessful.
   static GfxColorSpace *parse(Array *arr);
 
-  virtual void getGray(GfxColor *color, double *gray);
+  virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
@@ -173,7 +232,7 @@ public:
   virtual GfxColorSpace *copy();
   virtual GfxColorSpaceMode getMode() { return csDeviceRGB; }
 
-  virtual void getGray(GfxColor *color, double *gray);
+  virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
@@ -197,7 +256,7 @@ public:
   // Construct a CalRGB color space.  Returns NULL if unsuccessful.
   static GfxColorSpace *parse(Array *arr);
 
-  virtual void getGray(GfxColor *color, double *gray);
+  virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
@@ -220,7 +279,7 @@ private:
   double whiteX, whiteY, whiteZ;    // white point
   double blackX, blackY, blackZ;    // black point
   double gammaR, gammaG, gammaB;    // gamma values
-  double mat[9];		// ABC -> XYZ transform matrix
+  double mat[9];		    // ABC -> XYZ transform matrix
 };
 
 //------------------------------------------------------------------------
@@ -235,7 +294,7 @@ public:
   virtual GfxColorSpace *copy();
   virtual GfxColorSpaceMode getMode() { return csDeviceCMYK; }
 
-  virtual void getGray(GfxColor *color, double *gray);
+  virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
@@ -259,7 +318,7 @@ public:
   // Construct a Lab color space.  Returns NULL if unsuccessful.
   static GfxColorSpace *parse(Array *arr);
 
-  virtual void getGray(GfxColor *color, double *gray);
+  virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
@@ -304,7 +363,7 @@ public:
   // Construct an ICCBased color space.  Returns NULL if unsuccessful.
   static GfxColorSpace *parse(Array *arr);
 
-  virtual void getGray(GfxColor *color, double *gray);
+  virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
@@ -340,7 +399,7 @@ public:
   // Construct a Lab color space.  Returns NULL if unsuccessful.
   static GfxColorSpace *parse(Array *arr);
 
-  virtual void getGray(GfxColor *color, double *gray);
+  virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
@@ -378,7 +437,7 @@ public:
   // Construct a Separation color space.  Returns NULL if unsuccessful.
   static GfxColorSpace *parse(Array *arr);
 
-  virtual void getGray(GfxColor *color, double *gray);
+  virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
@@ -411,7 +470,7 @@ public:
   // Construct a DeviceN color space.  Returns NULL if unsuccessful.
   static GfxColorSpace *parse(Array *arr);
 
-  virtual void getGray(GfxColor *color, double *gray);
+  virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
@@ -446,7 +505,7 @@ public:
   // Construct a Pattern color space.  Returns NULL if unsuccessful.
   static GfxColorSpace *parse(Array *arr);
 
-  virtual void getGray(GfxColor *color, double *gray);
+  virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
@@ -599,6 +658,8 @@ public:
   void getDomain(double *x0A, double *y0A, double *x1A, double *y1A)
     { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
   double *getMatrix() { return matrix; }
+  int getNFuncs() { return nFuncs; }
+  Function *getFunc(int i) { return funcs[i]; }
   void getColor(double x, double y, GfxColor *color);
 
 private:
@@ -632,9 +693,11 @@ public:
     { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
   double getDomain0() { return t0; }
   double getDomain1() { return t1; }
-  void getColor(double t, GfxColor *color);
   GBool getExtend0() { return extend0; }
   GBool getExtend1() { return extend1; }
+  int getNFuncs() { return nFuncs; }
+  Function *getFunc(int i) { return funcs[i]; }
+  void getColor(double t, GfxColor *color);
 
 private:
 
@@ -669,9 +732,11 @@ public:
     { *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; }
   double getDomain0() { return t0; }
   double getDomain1() { return t1; }
-  void getColor(double t, GfxColor *color);
   GBool getExtend0() { return extend0; }
   GBool getExtend1() { return extend1; }
+  int getNFuncs() { return nFuncs; }
+  Function *getFunc(int i) { return funcs[i]; }
+  void getColor(double t, GfxColor *color);
 
 private:
 
@@ -683,6 +748,77 @@ private:
 };
 
 //------------------------------------------------------------------------
+// GfxGouraudTriangleShading
+//------------------------------------------------------------------------
+
+struct GfxGouraudVertex {
+  double x, y;
+  GfxColor color;
+};
+
+class GfxGouraudTriangleShading: public GfxShading {
+public:
+
+  GfxGouraudTriangleShading(int typeA,
+			    GfxGouraudVertex *verticesA, int nVerticesA,
+			    int (*trianglesA)[3], int nTrianglesA,
+			    Function **funcsA, int nFuncsA);
+  GfxGouraudTriangleShading(GfxGouraudTriangleShading *shading);
+  virtual ~GfxGouraudTriangleShading();
+
+  static GfxGouraudTriangleShading *parse(int typeA, Dict *dict, Stream *str);
+
+  virtual GfxShading *copy();
+
+  int getNTriangles() { return nTriangles; }
+  void getTriangle(int i, double *x0, double *y0, GfxColor *color0,
+		   double *x1, double *y1, GfxColor *color1,
+		   double *x2, double *y2, GfxColor *color2);
+
+private:
+
+  GfxGouraudVertex *vertices;
+  int nVertices;
+  int (*triangles)[3];
+  int nTriangles;
+  Function *funcs[gfxColorMaxComps];
+  int nFuncs;
+};
+
+//------------------------------------------------------------------------
+// GfxPatchMeshShading
+//------------------------------------------------------------------------
+
+struct GfxPatch {
+  double x[4][4];
+  double y[4][4];
+  GfxColor color[2][2];
+};
+
+class GfxPatchMeshShading: public GfxShading {
+public:
+
+  GfxPatchMeshShading(int typeA, GfxPatch *patchesA, int nPatchesA,
+		      Function **funcsA, int nFuncsA);
+  GfxPatchMeshShading(GfxPatchMeshShading *shading);
+  virtual ~GfxPatchMeshShading();
+
+  static GfxPatchMeshShading *parse(int typeA, Dict *dict, Stream *str);
+
+  virtual GfxShading *copy();
+
+  int getNPatches() { return nPatches; }
+  GfxPatch *getPatch(int i) { return &patches[i]; }
+
+private:
+
+  GfxPatch *patches;
+  int nPatches;
+  Function *funcs[gfxColorMaxComps];
+  int nFuncs;
+};
+
+//------------------------------------------------------------------------
 // GfxImageColorMap
 //------------------------------------------------------------------------
 
@@ -713,7 +849,7 @@ public:
   double getDecodeHigh(int i) { return decodeLow[i] + decodeRange[i]; }
 
   // Convert an image pixel to a color.
-  void getGray(Guchar *x, double *gray);
+  void getGray(Guchar *x, GfxGray *gray);
   void getRGB(Guchar *x, GfxRGB *rgb);
   void getCMYK(Guchar *x, GfxCMYK *cmyk);
   void getColor(Guchar *x, GfxColor *color);
@@ -727,7 +863,8 @@ private:
   int nComps;			// number of components in a pixel
   GfxColorSpace *colorSpace2;	// secondary color space
   int nComps2;			// number of components in colorSpace2
-  double *lookup;		// lookup table
+  GfxColorComp *		// lookup table
+    lookup[gfxColorMaxComps];
   double			// minimum values for each component
     decodeLow[gfxColorMaxComps];
   double			// max - min value for each component
@@ -853,10 +990,10 @@ class GfxState {
 public:
 
   // Construct a default GfxState, for a device with resolution <hDPI>
-  // x <vDPI>, page box <pageBox>, page rotation <rotate>, and
+  // x <vDPI>, page box <pageBox>, page rotation <rotateA>, and
   // coordinate system specified by <upsideDown>.
   GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
-	   int rotate, GBool upsideDown);
+	   int rotateA, GBool upsideDown);
 
   // Destructor.
   ~GfxState();
@@ -872,11 +1009,12 @@ public:
   double getY2() { return py2; }
   double getPageWidth() { return pageWidth; }
   double getPageHeight() { return pageHeight; }
+  int getRotate() { return rotate; }
   GfxColor *getFillColor() { return &fillColor; }
   GfxColor *getStrokeColor() { return &strokeColor; }
-  void getFillGray(double *gray)
+  void getFillGray(GfxGray *gray)
     { fillColorSpace->getGray(&fillColor, gray); }
-  void getStrokeGray(double *gray)
+  void getStrokeGray(GfxGray *gray)
     { strokeColorSpace->getGray(&strokeColor, gray); }
   void getFillRGB(GfxRGB *rgb)
     { fillColorSpace->getRGB(&fillColor, rgb); }
@@ -890,8 +1028,11 @@ public:
   GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; }
   GfxPattern *getFillPattern() { return fillPattern; }
   GfxPattern *getStrokePattern() { return strokePattern; }
+  GfxBlendMode getBlendMode() { return blendMode; }
   double getFillOpacity() { return fillOpacity; }
   double getStrokeOpacity() { return strokeOpacity; }
+  GBool getFillOverprint() { return fillOverprint; }
+  GBool getStrokeOverprint() { return strokeOverprint; }
   double getLineWidth() { return lineWidth; }
   void getLineDash(double **dash, int *length, double *start)
     { *dash = lineDash; *length = lineDashLength; *start = lineDashStart; }
@@ -952,8 +1093,11 @@ public:
   void setStrokeColor(GfxColor *color) { strokeColor = *color; }
   void setFillPattern(GfxPattern *pattern);
   void setStrokePattern(GfxPattern *pattern);
+  void setBlendMode(GfxBlendMode mode) { blendMode = mode; }
   void setFillOpacity(double opac) { fillOpacity = opac; }
   void setStrokeOpacity(double opac) { strokeOpacity = opac; }
+  void setFillOverprint(GBool op) { fillOverprint = op; }
+  void setStrokeOverprint(GBool op) { strokeOverprint = op; }
   void setLineWidth(double width) { lineWidth = width; }
   void setLineDash(double *dash, int length, double start);
   void setFlatness(int flatness1) { flatness = flatness1; }
@@ -1006,11 +1150,15 @@ public:
   GfxState *restore();
   GBool hasSaves() { return saved != NULL; }
 
+  // Misc
+  GBool parseBlendMode(Object *obj, GfxBlendMode *mode);
+
 private:
 
   double ctm[6];		// coord transform matrix
   double px1, py1, px2, py2;	// page corners (user coords)
   double pageWidth, pageHeight;	// page size (pixels)
+  int rotate;			// page rotation angle
 
   GfxColorSpace *fillColorSpace;   // fill color space
   GfxColorSpace *strokeColorSpace; // stroke color space
@@ -1018,8 +1166,11 @@ private:
   GfxColor strokeColor;		// stroke color
   GfxPattern *fillPattern;	// fill pattern
   GfxPattern *strokePattern;	// stroke pattern
+  GfxBlendMode blendMode;	// transparency blend mode
   double fillOpacity;		// fill opacity
   double strokeOpacity;		// stroke opacity
+  GBool fillOverprint;		// fill overprint
+  GBool strokeOverprint;	// stroke overprint
 
   double lineWidth;		// line width
   double *lineDash;		// line dash
diff --git a/pdf2swf/xpdf/JArithmeticDecoder.cc b/pdf2swf/xpdf/JArithmeticDecoder.cc
index fd29744..195b73e 100644
--- a/pdf2swf/xpdf/JArithmeticDecoder.cc
+++ b/pdf2swf/xpdf/JArithmeticDecoder.cc
@@ -22,7 +22,7 @@
 
 JArithmeticDecoderStats::JArithmeticDecoderStats(int contextSizeA) {
   contextSize = contextSizeA;
-  cxTab = (Guchar *)gmalloc(contextSize * sizeof(Guchar));
+  cxTab = (Guchar *)gmallocn(contextSize, sizeof(Guchar));
   reset();
 }
 
@@ -89,24 +89,24 @@ int JArithmeticDecoder::switchTab[47] = {
 
 JArithmeticDecoder::JArithmeticDecoder() {
   str = NULL;
-}
-
-JArithmeticDecoder::~JArithmeticDecoder() {
-  while (dataLen > 0) {
-    readByte();
-  }
+  dataLen = 0;
+  limitStream = gFalse;
 }
 
 inline Guint JArithmeticDecoder::readByte() {
-  if (dataLen == 0) {
-    return 0xff;
-  }
-  if (dataLen > 0) {
+  if (limitStream) {
     --dataLen;
+    if (dataLen < 0) {
+      return 0xff;
+    }
   }
   return (Guint)str->getChar() & 0xff;
 }
 
+JArithmeticDecoder::~JArithmeticDecoder() {
+  cleanup();
+}
+
 void JArithmeticDecoder::start() {
   buf0 = readByte();
   buf1 = readByte();
@@ -119,6 +119,28 @@ void JArithmeticDecoder::start() {
   a = 0x80000000;
 }
 
+void JArithmeticDecoder::restart(int dataLenA) {
+  int oldDataLen;
+
+  oldDataLen = dataLen;
+  dataLen = dataLenA;
+  if (oldDataLen == -1) {
+    buf1 = readByte();
+  } else if (oldDataLen <= -2) {
+    buf0 = readByte();
+    buf1 = readByte();
+  }
+}
+
+void JArithmeticDecoder::cleanup() {
+  if (limitStream) {
+    while (dataLen > 0) {
+      buf0 = buf1;
+      buf1 = readByte();
+    }
+  }
+}
+
 int JArithmeticDecoder::decodeBit(Guint context,
 				  JArithmeticDecoderStats *stats) {
   int bit;
diff --git a/pdf2swf/xpdf/JArithmeticDecoder.h b/pdf2swf/xpdf/JArithmeticDecoder.h
index a348017..a40823d 100644
--- a/pdf2swf/xpdf/JArithmeticDecoder.h
+++ b/pdf2swf/xpdf/JArithmeticDecoder.h
@@ -53,12 +53,29 @@ public:
 
   JArithmeticDecoder();
   ~JArithmeticDecoder();
+
   void setStream(Stream *strA)
-    { str = strA; dataLen = -1; }
+    { str = strA; dataLen = 0; limitStream = gFalse; }
   void setStream(Stream *strA, int dataLenA)
-    { str = strA; dataLen = dataLenA; }
+    { str = strA; dataLen = dataLenA; limitStream = gTrue; }
+
+  // Start decoding on a new stream.  This fills the byte buffers and
+  // runs INITDEC.
   void start();
+
+  // Restart decoding on an interrupted stream.  This refills the
+  // buffers if needed, but does not run INITDEC.  (This is used in
+  // JPEG 2000 streams when codeblock data is split across multiple
+  // packets/layers.)
+  void restart(int dataLenA);
+
+  // Read any leftover data in the stream.
+  void cleanup();
+
+  // Decode one bit.
   int decodeBit(Guint context, JArithmeticDecoderStats *stats);
+
+  // Decode eight bits.
   int decodeByte(Guint context, JArithmeticDecoderStats *stats);
 
   // Returns false for OOB, otherwise sets *<x> and returns true.
@@ -86,6 +103,7 @@ private:
 
   Stream *str;
   int dataLen;
+  GBool limitStream;
 };
 
 #endif
diff --git a/pdf2swf/xpdf/JBIG2Stream.cc b/pdf2swf/xpdf/JBIG2Stream.cc
index c1bf4f7..a90db80 100644
--- a/pdf2swf/xpdf/JBIG2Stream.cc
+++ b/pdf2swf/xpdf/JBIG2Stream.cc
@@ -681,7 +681,9 @@ JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA):
   w = wA;
   h = hA;
   line = (wA + 7) >> 3;
-  data = (Guchar *)gmalloc(h * line);
+  // need to allocate one extra guard byte for use in combine()
+  data = (Guchar *)gmalloc(h * line + 1);
+  data[h * line] = 0;
 }
 
 JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap):
@@ -690,8 +692,10 @@ JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap):
   w = bitmap->w;
   h = bitmap->h;
   line = bitmap->line;
-  data = (Guchar *)gmalloc(h * line);
+  // need to allocate one extra guard byte for use in combine()
+  data = (Guchar *)gmalloc(h * line + 1);
   memcpy(data, bitmap->data, h * line);
+  data[h * line] = 0;
 }
 
 JBIG2Bitmap::~JBIG2Bitmap() {
@@ -719,13 +723,15 @@ void JBIG2Bitmap::expand(int newH, Guint pixel) {
   if (newH <= h) {
     return;
   }
-  data = (Guchar *)grealloc(data, newH * line);
+  // need to allocate one extra guard byte for use in combine()
+  data = (Guchar *)grealloc(data, newH * line + 1);
   if (pixel) {
     memset(data + h * line, 0xff, (newH - h) * line);
   } else {
     memset(data + h * line, 0x00, (newH - h) * line);
   }
   h = newH;
+  data[h * line] = 0;
 }
 
 void JBIG2Bitmap::clearToZero() {
@@ -933,6 +939,10 @@ void JBIG2Bitmap::combine(JBIG2Bitmap *bitmap, int x, int y,
       }
 
       // right-most byte
+      // note: this last byte (src1) may not actually be used, depending
+      // on the values of s1, m1, and m2 - and in fact, it may be off
+      // the edge of the source bitmap, which means we need to allocate
+      // one extra guard byte at the end of each bitmap
       dest = *destPtr;
       src0 = src1;
       src1 = *srcPtr++;
@@ -993,7 +1003,7 @@ JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA):
   JBIG2Segment(segNumA)
 {
   size = sizeA;
-  bitmaps = (JBIG2Bitmap **)gmalloc(size * sizeof(JBIG2Bitmap *));
+  bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *));
   genericRegionStats = NULL;
   refinementRegionStats = NULL;
 }
@@ -1037,7 +1047,7 @@ JBIG2PatternDict::JBIG2PatternDict(Guint segNumA, Guint sizeA):
   JBIG2Segment(segNumA)
 {
   size = sizeA;
-  bitmaps = (JBIG2Bitmap **)gmalloc(size * sizeof(JBIG2Bitmap *));
+  bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *));
 }
 
 JBIG2PatternDict::~JBIG2PatternDict() {
@@ -1233,7 +1243,7 @@ void JBIG2Stream::readSegments() {
     }
 
     // referred-to segment numbers
-    refSegs = (Guint *)gmalloc(nRefSegs * sizeof(Guint));
+    refSegs = (Guint *)gmallocn(nRefSegs, sizeof(Guint));
     if (segNum <= 256) {
       for (i = 0; i < nRefSegs; ++i) {
 	if (!readUByte(&refSegs[i])) {
@@ -1273,7 +1283,9 @@ void JBIG2Stream::readSegments() {
     // read the segment data
     switch (segType) {
     case 0:
-      readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs);
+      if (!readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs)) {
+	goto syntaxError;
+      }
       break;
     case 4:
       readTextRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs);
@@ -1350,14 +1362,18 @@ void JBIG2Stream::readSegments() {
 
   return;
 
+ syntaxError:
+  gfree(refSegs);
+  return;
+
  eofError2:
   gfree(refSegs);
  eofError1:
   error(getPos(), "Unexpected EOF in JBIG2 stream");
 }
 
-void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
-				    Guint *refSegs, Guint nRefSegs) {
+GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
+				     Guint *refSegs, Guint nRefSegs) {
   JBIG2SymbolDict *symbolDict;
   JBIG2HuffmanTable *huffDHTable, *huffDWTable;
   JBIG2HuffmanTable *huffBMSizeTable, *huffAggInstTable;
@@ -1451,8 +1467,11 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
   }
 
   // get the input symbol bitmaps
-  bitmaps = (JBIG2Bitmap **)gmalloc((numInputSyms + numNewSyms) *
-				    sizeof(JBIG2Bitmap *));
+  bitmaps = (JBIG2Bitmap **)gmallocn(numInputSyms + numNewSyms,
+				     sizeof(JBIG2Bitmap *));
+  for (i = 0; i < numInputSyms + numNewSyms; ++i) {
+    bitmaps[i] = NULL;
+  }
   k = 0;
   inputSymbolDict = NULL;
   for (i = 0; i < nRefSegs; ++i) {
@@ -1527,7 +1546,7 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
   // allocate symbol widths storage
   symWidths = NULL;
   if (huff && !refAgg) {
-    symWidths = (Guint *)gmalloc(numNewSyms * sizeof(Guint));
+    symWidths = (Guint *)gmallocn(numNewSyms, sizeof(Guint));
   }
 
   symHeight = 0;
@@ -1540,6 +1559,10 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
     } else {
       arithDecoder->decodeInt(&dh, iadhStats);
     }
+    if (dh < 0 && (Guint)-dh >= symHeight) {
+      error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary");
+      goto syntaxError;
+    }
     symHeight += dh;
     symWidth = 0;
     totalWidth = 0;
@@ -1558,6 +1581,10 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
 	  break;
 	}
       }
+      if (dw < 0 && (Guint)-dw >= symWidth) {
+	error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary");
+	goto syntaxError;
+      }
       symWidth += dw;
 
       // using a collective bitmap, so don't read a bitmap here
@@ -1690,10 +1717,23 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
   // store the new symbol dict
   segments->append(symbolDict);
 
-  return;
+  return gTrue;
+
+ syntaxError:
+  for (i = 0; i < numNewSyms; ++i) {
+    if (bitmaps[numInputSyms + i]) {
+      delete bitmaps[numInputSyms + i];
+    }
+  }
+  gfree(bitmaps);
+  if (symWidths) {
+    gfree(symWidths);
+  }
+  return gFalse;
 
  eofError:
   error(getPos(), "Unexpected EOF in JBIG2 stream");
+  return gFalse;
 }
 
 void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
@@ -1773,11 +1813,14 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
   codeTables = new GList();
   numSyms = 0;
   for (i = 0; i < nRefSegs; ++i) {
-    seg = findSegment(refSegs[i]);
-    if (seg->getType() == jbig2SegSymbolDict) {
-      numSyms += ((JBIG2SymbolDict *)seg)->getSize();
-    } else if (seg->getType() == jbig2SegCodeTable) {
-      codeTables->append(seg);
+    if ((seg = findSegment(refSegs[i]))) {
+      if (seg->getType() == jbig2SegSymbolDict) {
+	numSyms += ((JBIG2SymbolDict *)seg)->getSize();
+      } else if (seg->getType() == jbig2SegCodeTable) {
+	codeTables->append(seg);
+      }
+    } else {
+      error(getPos(), "Invalid segment reference in JBIG2 text region");
     }
   }
   symCodeLen = 0;
@@ -1788,14 +1831,15 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
   }
 
   // get the symbol bitmaps
-  syms = (JBIG2Bitmap **)gmalloc(numSyms * sizeof(JBIG2Bitmap *));
+  syms = (JBIG2Bitmap **)gmallocn(numSyms, sizeof(JBIG2Bitmap *));
   kk = 0;
   for (i = 0; i < nRefSegs; ++i) {
-    seg = findSegment(refSegs[i]);
-    if (seg->getType() == jbig2SegSymbolDict) {
-      symbolDict = (JBIG2SymbolDict *)seg;
-      for (k = 0; k < symbolDict->getSize(); ++k) {
-	syms[kk++] = symbolDict->getBitmap(k);
+    if ((seg = findSegment(refSegs[i]))) {
+      if (seg->getType() == jbig2SegSymbolDict) {
+	symbolDict = (JBIG2SymbolDict *)seg;
+	for (k = 0; k < symbolDict->getSize(); ++k) {
+	  syms[kk++] = symbolDict->getBitmap(k);
+	}
       }
     }
   }
@@ -1888,8 +1932,8 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
     runLengthTab[35].prefixLen = 0;
     runLengthTab[35].rangeLen = jbig2HuffmanEOT;
     huffDecoder->buildTable(runLengthTab, 35);
-    symCodeTab = (JBIG2HuffmanTable *)gmalloc((numSyms + 1) *
-					      sizeof(JBIG2HuffmanTable));
+    symCodeTab = (JBIG2HuffmanTable *)gmallocn(numSyms + 1,
+					       sizeof(JBIG2HuffmanTable));
     for (i = 0; i < numSyms; ++i) {
       symCodeTab[i].val = i;
       symCodeTab[i].rangeLen = 0;
@@ -2052,85 +2096,90 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine,
 	symID = arithDecoder->decodeIAID(symCodeLen, iaidStats);
       }
 
-      // get the symbol bitmap
-      symbolBitmap = NULL;
-      if (refine) {
-	if (huff) {
-	  ri = (int)huffDecoder->readBit();
+      if (symID >= (Guint)numSyms) {
+	error(getPos(), "Invalid symbol number in JBIG2 text region");
+      } else {
+
+	// get the symbol bitmap
+	symbolBitmap = NULL;
+	if (refine) {
+	  if (huff) {
+	    ri = (int)huffDecoder->readBit();
+	  } else {
+	    arithDecoder->decodeInt(&ri, iariStats);
+	  }
 	} else {
-	  arithDecoder->decodeInt(&ri, iariStats);
+	  ri = 0;
 	}
-      } else {
-	ri = 0;
-      }
-      if (ri) {
-	if (huff) {
-	  huffDecoder->decodeInt(&rdw, huffRDWTable);
-	  huffDecoder->decodeInt(&rdh, huffRDHTable);
-	  huffDecoder->decodeInt(&rdx, huffRDXTable);
-	  huffDecoder->decodeInt(&rdy, huffRDYTable);
-	  huffDecoder->decodeInt(&bmSize, huffRSizeTable);
-	  huffDecoder->reset();
-	  arithDecoder->start();
+	if (ri) {
+	  if (huff) {
+	    huffDecoder->decodeInt(&rdw, huffRDWTable);
+	    huffDecoder->decodeInt(&rdh, huffRDHTable);
+	    huffDecoder->decodeInt(&rdx, huffRDXTable);
+	    huffDecoder->decodeInt(&rdy, huffRDYTable);
+	    huffDecoder->decodeInt(&bmSize, huffRSizeTable);
+	    huffDecoder->reset();
+	    arithDecoder->start();
+	  } else {
+	    arithDecoder->decodeInt(&rdw, iardwStats);
+	    arithDecoder->decodeInt(&rdh, iardhStats);
+	    arithDecoder->decodeInt(&rdx, iardxStats);
+	    arithDecoder->decodeInt(&rdy, iardyStats);
+	  }
+	  refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx;
+	  refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy;
+
+	  symbolBitmap =
+	    readGenericRefinementRegion(rdw + syms[symID]->getWidth(),
+					rdh + syms[symID]->getHeight(),
+					templ, gFalse, syms[symID],
+					refDX, refDY, atx, aty);
+	  //~ do we need to use the bmSize value here (in Huffman mode)?
 	} else {
-	  arithDecoder->decodeInt(&rdw, iardwStats);
-	  arithDecoder->decodeInt(&rdh, iardhStats);
-	  arithDecoder->decodeInt(&rdx, iardxStats);
-	  arithDecoder->decodeInt(&rdy, iardyStats);
+	  symbolBitmap = syms[symID];
 	}
-	refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx;
-	refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy;
-
-	symbolBitmap =
-	  readGenericRefinementRegion(rdw + syms[symID]->getWidth(),
-				      rdh + syms[symID]->getHeight(),
-				      templ, gFalse, syms[symID],
-				      refDX, refDY, atx, aty);
-	//~ do we need to use the bmSize value here (in Huffman mode)?
-      } else {
-	symbolBitmap = syms[symID];
-      }
 
-      // combine the symbol bitmap into the region bitmap
-      //~ something is wrong here - refCorner shouldn't degenerate into
-      //~   two cases
-      bw = symbolBitmap->getWidth() - 1;
-      bh = symbolBitmap->getHeight() - 1;
-      if (transposed) {
-	switch (refCorner) {
-	case 0: // bottom left
-	  bitmap->combine(symbolBitmap, tt, s, combOp);
-	  break;
-	case 1: // top left
-	  bitmap->combine(symbolBitmap, tt, s, combOp);
-	  break;
-	case 2: // bottom right
-	  bitmap->combine(symbolBitmap, tt - bw, s, combOp);
-	  break;
-	case 3: // top right
-	  bitmap->combine(symbolBitmap, tt - bw, s, combOp);
-	  break;
+	// combine the symbol bitmap into the region bitmap
+	//~ something is wrong here - refCorner shouldn't degenerate into
+	//~   two cases
+	bw = symbolBitmap->getWidth() - 1;
+	bh = symbolBitmap->getHeight() - 1;
+	if (transposed) {
+	  switch (refCorner) {
+	  case 0: // bottom left
+	    bitmap->combine(symbolBitmap, tt, s, combOp);
+	    break;
+	  case 1: // top left
+	    bitmap->combine(symbolBitmap, tt, s, combOp);
+	    break;
+	  case 2: // bottom right
+	    bitmap->combine(symbolBitmap, tt - bw, s, combOp);
+	    break;
+	  case 3: // top right
+	    bitmap->combine(symbolBitmap, tt - bw, s, combOp);
+	    break;
+	  }
+	  s += bh;
+	} else {
+	  switch (refCorner) {
+	  case 0: // bottom left
+	    bitmap->combine(symbolBitmap, s, tt - bh, combOp);
+	    break;
+	  case 1: // top left
+	    bitmap->combine(symbolBitmap, s, tt, combOp);
+	    break;
+	  case 2: // bottom right
+	    bitmap->combine(symbolBitmap, s, tt - bh, combOp);
+	    break;
+	  case 3: // top right
+	    bitmap->combine(symbolBitmap, s, tt, combOp);
+	    break;
+	  }
+	  s += bw;
 	}
-	s += bh;
-      } else {
-	switch (refCorner) {
-	case 0: // bottom left
-	  bitmap->combine(symbolBitmap, s, tt - bh, combOp);
-	  break;
-	case 1: // top left
-	  bitmap->combine(symbolBitmap, s, tt, combOp);
-	  break;
-	case 2: // bottom right
-	  bitmap->combine(symbolBitmap, s, tt - bh, combOp);
-	  break;
-	case 3: // top right
-	  bitmap->combine(symbolBitmap, s, tt, combOp);
-	  break;
+	if (ri) {
+	  delete symbolBitmap;
 	}
-	s += bw;
-      }
-      if (ri) {
-	delete symbolBitmap;
       }
 
       // next instance
@@ -2298,7 +2347,7 @@ void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm,
   }
 
   // read the gray-scale image
-  grayImg = (Guint *)gmalloc(gridW * gridH * sizeof(Guint));
+  grayImg = (Guint *)gmallocn(gridW * gridH, sizeof(Guint));
   memset(grayImg, 0, gridW * gridH * sizeof(Guint));
   atx[0] = templ <= 1 ? 3 : 2;  aty[0] = -1;
   atx[1] = -3;                  aty[1] = -1;
@@ -2451,8 +2500,8 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
   if (mmr) {
 
     mmrDecoder->reset();
-    refLine = (int *)gmalloc((w + 2) * sizeof(int));
-    codingLine = (int *)gmalloc((w + 2) * sizeof(int));
+    refLine = (int *)gmallocn(w + 2, sizeof(int));
+    codingLine = (int *)gmallocn(w + 2, sizeof(int));
     codingLine[0] = codingLine[1] = w;
 
     for (y = 0; y < h; ++y) {
@@ -3111,14 +3160,14 @@ void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint length) {
   huffDecoder->reset();
   huffTabSize = 8;
   huffTab = (JBIG2HuffmanTable *)
-                gmalloc(huffTabSize * sizeof(JBIG2HuffmanTable));
+                gmallocn(huffTabSize, sizeof(JBIG2HuffmanTable));
   i = 0;
   val = lowVal;
   while (val < highVal) {
     if (i == huffTabSize) {
       huffTabSize *= 2;
       huffTab = (JBIG2HuffmanTable *)
-	            grealloc(huffTab, huffTabSize * sizeof(JBIG2HuffmanTable));
+	            greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable));
     }
     huffTab[i].val = val;
     huffTab[i].prefixLen = huffDecoder->readBits(prefixBits);
@@ -3129,7 +3178,7 @@ void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint length) {
   if (i + oob + 3 > huffTabSize) {
     huffTabSize = i + oob + 3;
     huffTab = (JBIG2HuffmanTable *)
-                  grealloc(huffTab, huffTabSize * sizeof(JBIG2HuffmanTable));
+                  greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable));
   }
   huffTab[i].val = lowVal - 1;
   huffTab[i].prefixLen = huffDecoder->readBits(prefixBits);
diff --git a/pdf2swf/xpdf/JBIG2Stream.h b/pdf2swf/xpdf/JBIG2Stream.h
index ed26d4e..44e09db 100644
--- a/pdf2swf/xpdf/JBIG2Stream.h
+++ b/pdf2swf/xpdf/JBIG2Stream.h
@@ -45,8 +45,8 @@ public:
 private:
 
   void readSegments();
-  void readSymbolDictSeg(Guint segNum, Guint length,
-			 Guint *refSegs, Guint nRefSegs);
+  GBool readSymbolDictSeg(Guint segNum, Guint length,
+			  Guint *refSegs, Guint nRefSegs);
   void readTextRegionSeg(Guint segNum, GBool imm,
 			 GBool lossless, Guint length,
 			 Guint *refSegs, Guint nRefSegs);
diff --git a/pdf2swf/xpdf/JPXStream.cc b/pdf2swf/xpdf/JPXStream.cc
index defa7d2..336b7ba 100644
--- a/pdf2swf/xpdf/JPXStream.cc
+++ b/pdf2swf/xpdf/JPXStream.cc
@@ -243,6 +243,9 @@ JPXStream::~JPXStream() {
 			for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) {
 			  cb = &subband->cbs[k];
 			  gfree(cb->coeffs);
+			  if (cb->arithDecoder) {
+			    delete cb->arithDecoder;
+			  }
 			  if (cb->stats) {
 			    delete cb->stats;
 			  }
@@ -374,6 +377,122 @@ GBool JPXStream::isBinary(GBool last) {
   return str->isBinary(gTrue);
 }
 
+void JPXStream::getImageParams(int *bitsPerComponent,
+			       StreamColorSpaceMode *csMode) {
+  Guint boxType, boxLen, dataLen, csEnum;
+  Guint bpc1, dummy, i;
+  int csMeth, csPrec, csPrec1, dummy2;
+  StreamColorSpaceMode csMode1;
+  GBool haveBPC, haveCSMode;
+
+  csPrec = 0; // make gcc happy
+  haveBPC = haveCSMode = gFalse;
+  str->reset();
+  if (str->lookChar() == 0xff) {
+    getImageParams2(bitsPerComponent, csMode);
+  } else {
+    while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
+      if (boxType == 0x6a703268) { // JP2 header
+	// skip the superbox
+      } else if (boxType == 0x69686472) { // image header
+	if (readULong(&dummy) &&
+	    readULong(&dummy) &&
+	    readUWord(&dummy) &&
+	    readUByte(&bpc1) &&
+	    readUByte(&dummy) &&
+	    readUByte(&dummy) &&
+	    readUByte(&dummy)) {
+	  *bitsPerComponent = bpc1 + 1;
+	  haveBPC = gTrue;
+	}
+      } else if (boxType == 0x636F6C72) { // color specification
+	if (readByte(&csMeth) &&
+	    readByte(&csPrec1) &&
+	    readByte(&dummy2)) {
+	  if (csMeth == 1) {
+	    if (readULong(&csEnum)) {
+	      csMode1 = streamCSNone;
+	      if (csEnum == jpxCSBiLevel ||
+		  csEnum == jpxCSGrayscale) {
+		csMode1 = streamCSDeviceGray;
+	      } else if (csEnum == jpxCSCMYK) {
+		csMode1 = streamCSDeviceCMYK;
+	      } else if (csEnum == jpxCSsRGB ||
+			 csEnum == jpxCSCISesRGB ||
+			 csEnum == jpxCSROMMRGB) {
+		csMode1 = streamCSDeviceRGB;
+	      }
+	      if (csMode1 != streamCSNone &&
+		  (!haveCSMode || csPrec1 > csPrec)) {
+		*csMode = csMode1;
+		csPrec = csPrec1;
+		haveCSMode = gTrue;
+	      }
+	      for (i = 0; i < dataLen - 7; ++i) {
+		str->getChar();
+	      }
+	    }
+	  } else {
+	    for (i = 0; i < dataLen - 3; ++i) {
+	      str->getChar();
+	    }
+	  }
+	}
+      } else if (boxType == 0x6A703263) { // codestream
+	if (!(haveBPC && haveCSMode)) {
+	  getImageParams2(bitsPerComponent, csMode);
+	}
+	break;
+      } else {
+	for (i = 0; i < dataLen; ++i) {
+	  str->getChar();
+	}
+      }
+    }
+  }
+  str->close();
+}
+
+// Get image parameters from the codestream.
+void JPXStream::getImageParams2(int *bitsPerComponent,
+				StreamColorSpaceMode *csMode) {
+  int segType;
+  Guint segLen, nComps1, bpc1, dummy, i;
+
+  while (readMarkerHdr(&segType, &segLen)) {
+    if (segType == 0x51) { // SIZ - image and tile size
+      if (readUWord(&dummy) &&
+	  readULong(&dummy) &&
+	  readULong(&dummy) &&
+	  readULong(&dummy) &&
+	  readULong(&dummy) &&
+	  readULong(&dummy) &&
+	  readULong(&dummy) &&
+	  readULong(&dummy) &&
+	  readULong(&dummy) &&
+	  readUWord(&nComps1) &&
+	  readUByte(&bpc1)) {
+	*bitsPerComponent = (bpc1 & 0x7f) + 1;
+	// if there's no color space info, take a guess
+	if (nComps1 == 1) {
+	  *csMode = streamCSDeviceGray;
+	} else if (nComps1 == 3) {
+	  *csMode = streamCSDeviceRGB;
+	} else if (nComps1 == 4) {
+	  *csMode = streamCSDeviceCMYK;
+	}
+      }
+      break;
+    } else {
+      if (segLen > 2) {
+	for (i = 0; i < segLen - 2; ++i) {
+	  str->getChar();
+	}
+      }
+    }
+  }
+}
+
 GBool JPXStream::readBoxes() {
   Guint boxType, boxLen, dataLen;
   Guint bpc1, compression, unknownColorspace, ipr;
@@ -388,7 +507,7 @@ GBool JPXStream::readBoxes() {
     error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper");
     readCodestream(0);
     nComps = img.nComps;
-    bpc = (Guint *)gmalloc(nComps * sizeof(Guint));
+    bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
     for (i = 0; i < nComps; ++i) {
       bpc[i] = img.tiles[0].tileComps[i].prec;
     }
@@ -421,7 +540,7 @@ GBool JPXStream::readBoxes() {
 	error(getPos(), "Unknown compression type in JPX stream");
 	return gFalse;
       }
-      bpc = (Guint *)gmalloc(nComps * sizeof(Guint));
+      bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
       for (i = 0; i < nComps; ++i) {
 	bpc[i] = bpc1;
       }
@@ -454,9 +573,9 @@ GBool JPXStream::readBoxes() {
 	error(getPos(), "Unexpected EOF in JPX stream");
 	return gFalse;
       }
-      palette.bpc = (Guint *)gmalloc(palette.nComps * sizeof(Guint));
+      palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint));
       palette.c =
-          (int *)gmalloc(palette.nEntries * palette.nComps * sizeof(int));
+          (int *)gmallocn(palette.nEntries * palette.nComps, sizeof(int));
       for (i = 0; i < palette.nComps; ++i) {
 	if (!readUByte(&palette.bpc[i])) {
 	  error(getPos(), "Unexpected EOF in JPX stream");
@@ -478,9 +597,9 @@ GBool JPXStream::readBoxes() {
       break;
     case 0x636d6170:		// component mapping
       compMap.nChannels = dataLen / 4;
-      compMap.comp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
-      compMap.type = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
-      compMap.pComp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
+      compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
+      compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
+      compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
       for (i = 0; i < compMap.nChannels; ++i) {
 	if (!readUWord(&compMap.comp[i]) ||
 	    !readUByte(&compMap.type[i]) ||
@@ -497,11 +616,11 @@ GBool JPXStream::readBoxes() {
 	return gFalse;
       }
       channelDefn.idx =
-	  (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
+	  (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
       channelDefn.type =
-	  (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
+	  (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
       channelDefn.assoc =
-	  (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
+	  (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
       for (i = 0; i < channelDefn.nChannels; ++i) {
 	if (!readUWord(&channelDefn.idx[i]) ||
 	    !readUWord(&channelDefn.type[i]) ||
@@ -515,11 +634,9 @@ GBool JPXStream::readBoxes() {
     case 0x6A703263:		// contiguous codestream
       if (!bpc) {
 	error(getPos(), "JPX stream is missing the image header box");
-	return gFalse;
       }
       if (!haveCS) {
 	error(getPos(), "JPX stream has no supported color spec");
-	return gFalse;
       }
       if (!readCodestream(dataLen)) {
 	return gFalse;
@@ -582,7 +699,7 @@ GBool JPXStream::readColorSpecBox(Guint dataLen) {
       ok = gTrue;
       break;
     case jpxCSCIELab:
-      if (dataLen == 3 + 7*4) {
+      if (dataLen == 7 + 7*4) {
 	if (!readULong(&newCS.enumerated.cieLab.rl) ||
 	    !readULong(&newCS.enumerated.cieLab.ol) ||
 	    !readULong(&newCS.enumerated.cieLab.ra) ||
@@ -592,7 +709,7 @@ GBool JPXStream::readColorSpecBox(Guint dataLen) {
 	    !readULong(&newCS.enumerated.cieLab.il)) {
 	  goto err;
 	}
-      } else if (dataLen == 3) {
+      } else if (dataLen == 7) {
 	//~ this assumes the 8-bit case
 	newCS.enumerated.cieLab.rl = 100;
 	newCS.enumerated.cieLab.ol = 0;
@@ -666,7 +783,7 @@ GBool JPXStream::readCodestream(Guint len) {
   int segType;
   GBool haveSIZ, haveCOD, haveQCD, haveSOT;
   Guint precinctSize, style;
-  Guint segLen, capabilities, comp, i, j, r;
+  Guint segLen, capabilities, nTiles, comp, i, j, r;
 
   //----- main header
   haveSIZ = haveCOD = haveQCD = haveSOT = gFalse;
@@ -701,11 +818,16 @@ GBool JPXStream::readCodestream(Guint len) {
 	            / img.xTileSize;
       img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1)
 	            / img.yTileSize;
-      img.tiles = (JPXTile *)gmalloc(img.nXTiles * img.nYTiles *
-				     sizeof(JPXTile));
+      nTiles = img.nXTiles * img.nYTiles;
+      // check for overflow before allocating memory
+      if (nTiles == 0 || nTiles / img.nXTiles != img.nYTiles) {
+	error(getPos(), "Bad tile count in JPX SIZ marker segment");
+	return gFalse;
+      }
+      img.tiles = (JPXTile *)gmallocn(nTiles, sizeof(JPXTile));
       for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
-	img.tiles[i].tileComps = (JPXTileComp *)gmalloc(img.nComps *
-							sizeof(JPXTileComp));
+	img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps,
+							 sizeof(JPXTileComp));
 	for (comp = 0; comp < img.nComps; ++comp) {
 	  img.tiles[i].tileComps[comp].quantSteps = NULL;
 	  img.tiles[i].tileComps[comp].data = NULL;
@@ -767,8 +889,8 @@ GBool JPXStream::readCodestream(Guint len) {
 	        img.tiles[0].tileComps[0].transform;
 	  }
 	  img.tiles[i].tileComps[comp].resLevels =
-	      (JPXResLevel *)gmalloc(
-		     (img.tiles[i].tileComps[comp].nDecompLevels + 1) *
+	      (JPXResLevel *)gmallocn(
+		     (img.tiles[i].tileComps[comp].nDecompLevels + 1),
 		     sizeof(JPXResLevel));
 	  for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
 	    img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
@@ -841,10 +963,10 @@ GBool JPXStream::readCodestream(Guint len) {
 	      img.tiles[0].tileComps[comp].transform;
 	}
 	img.tiles[i].tileComps[comp].resLevels =
-	    (JPXResLevel *)grealloc(
+	    (JPXResLevel *)greallocn(
 		     img.tiles[i].tileComps[comp].resLevels,
-		     (img.tiles[i].tileComps[comp].nDecompLevels + 1) *
-		       sizeof(JPXResLevel));
+		     (img.tiles[i].tileComps[comp].nDecompLevels + 1),
+		     sizeof(JPXResLevel));
 	for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
 	  img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
 	}
@@ -881,9 +1003,9 @@ GBool JPXStream::readCodestream(Guint len) {
       if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) {
 	img.tiles[0].tileComps[0].nQuantSteps = segLen - 3;
 	img.tiles[0].tileComps[0].quantSteps =
-	    (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
-			      img.tiles[0].tileComps[0].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+			       img.tiles[0].tileComps[0].nQuantSteps,
+			       sizeof(Guint));
 	for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
 	  if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) {
 	    error(getPos(), "Error in JPX QCD marker segment");
@@ -893,9 +1015,9 @@ GBool JPXStream::readCodestream(Guint len) {
       } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) {
 	img.tiles[0].tileComps[0].nQuantSteps = 1;
 	img.tiles[0].tileComps[0].quantSteps =
-	    (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
-			      img.tiles[0].tileComps[0].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+			       img.tiles[0].tileComps[0].nQuantSteps,
+			       sizeof(Guint));
 	if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) {
 	  error(getPos(), "Error in JPX QCD marker segment");
 	  return gFalse;
@@ -903,9 +1025,9 @@ GBool JPXStream::readCodestream(Guint len) {
       } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) {
 	img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2;
 	img.tiles[0].tileComps[0].quantSteps =
-	    (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
-			      img.tiles[0].tileComps[0].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+			       img.tiles[0].tileComps[0].nQuantSteps,
+			       sizeof(Guint));
 	for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
 	  if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) {
 	    error(getPos(), "Error in JPX QCD marker segment");
@@ -924,9 +1046,9 @@ GBool JPXStream::readCodestream(Guint len) {
 	    img.tiles[i].tileComps[comp].nQuantSteps =
 	        img.tiles[0].tileComps[0].nQuantSteps;
 	    img.tiles[i].tileComps[comp].quantSteps = 
-	        (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps,
-				  img.tiles[0].tileComps[0].nQuantSteps *
-				    sizeof(Guint));
+	        (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
+				   img.tiles[0].tileComps[0].nQuantSteps,
+				   sizeof(Guint));
 	    for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) {
 	      img.tiles[i].tileComps[comp].quantSteps[j] =
 		  img.tiles[0].tileComps[0].quantSteps[j];
@@ -952,9 +1074,9 @@ GBool JPXStream::readCodestream(Guint len) {
 	img.tiles[0].tileComps[comp].nQuantSteps =
 	    segLen - (img.nComps > 256 ? 5 : 4);
 	img.tiles[0].tileComps[comp].quantSteps =
-	    (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
-			      img.tiles[0].tileComps[comp].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+			       img.tiles[0].tileComps[comp].nQuantSteps,
+			       sizeof(Guint));
 	for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
 	  if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) {
 	    error(getPos(), "Error in JPX QCC marker segment");
@@ -964,9 +1086,9 @@ GBool JPXStream::readCodestream(Guint len) {
       } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) {
 	img.tiles[0].tileComps[comp].nQuantSteps = 1;
 	img.tiles[0].tileComps[comp].quantSteps =
-	    (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
-			      img.tiles[0].tileComps[comp].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+			       img.tiles[0].tileComps[comp].nQuantSteps,
+			       sizeof(Guint));
 	if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) {
 	  error(getPos(), "Error in JPX QCC marker segment");
 	  return gFalse;
@@ -975,9 +1097,9 @@ GBool JPXStream::readCodestream(Guint len) {
 	img.tiles[0].tileComps[comp].nQuantSteps =
 	    (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
 	img.tiles[0].tileComps[comp].quantSteps =
-	    (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
-			      img.tiles[0].tileComps[comp].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+			       img.tiles[0].tileComps[comp].nQuantSteps,
+			       sizeof(Guint));
 	for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
 	  if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) {
 	    error(getPos(), "Error in JPX QCD marker segment");
@@ -994,9 +1116,9 @@ GBool JPXStream::readCodestream(Guint len) {
 	img.tiles[i].tileComps[comp].nQuantSteps =
 	    img.tiles[0].tileComps[comp].nQuantSteps;
 	img.tiles[i].tileComps[comp].quantSteps = 
-	    (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps,
-			      img.tiles[0].tileComps[comp].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
+			       img.tiles[0].tileComps[comp].nQuantSteps,
+			       sizeof(Guint));
 	for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) {
 	  img.tiles[i].tileComps[comp].quantSteps[j] =
 	      img.tiles[0].tileComps[comp].quantSteps[j];
@@ -1034,7 +1156,7 @@ GBool JPXStream::readCodestream(Guint len) {
       }
 #else
       nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
-      progs = (JPXProgOrder *)gmalloc(nProgs * sizeof(JPXProgOrder));
+      progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder));
       for (i = 0; i < nProgs; ++i) {
 	if (!readUByte(&progs[i].startRes) ||
 	    !(img.nComps > 256 && readUWord(&progs[i].startComp)) ||
@@ -1231,10 +1353,10 @@ GBool JPXStream::readTilePart() {
 	      img.tiles[tileIdx].tileComps[0].transform;
 	}
 	img.tiles[tileIdx].tileComps[comp].resLevels =
-	    (JPXResLevel *)grealloc(
+	    (JPXResLevel *)greallocn(
 		     img.tiles[tileIdx].tileComps[comp].resLevels,
-		     (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) *
-		       sizeof(JPXResLevel));
+		     (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
+		     sizeof(JPXResLevel));
 	for (r = 0;
 	     r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
 	     ++r) {
@@ -1285,10 +1407,10 @@ GBool JPXStream::readTilePart() {
       img.tiles[tileIdx].tileComps[comp].codeBlockW += 2;
       img.tiles[tileIdx].tileComps[comp].codeBlockH += 2;
       img.tiles[tileIdx].tileComps[comp].resLevels =
-	  (JPXResLevel *)grealloc(
+	  (JPXResLevel *)greallocn(
 		     img.tiles[tileIdx].tileComps[comp].resLevels,
-		     (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) *
-		       sizeof(JPXResLevel));
+		     (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
+		     sizeof(JPXResLevel));
       for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
 	img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
       }
@@ -1317,9 +1439,9 @@ GBool JPXStream::readTilePart() {
 	img.tiles[tileIdx].tileComps[0].nQuantSteps =
 	    segLen - 3;
 	img.tiles[tileIdx].tileComps[0].quantSteps =
-	    (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
-			      img.tiles[tileIdx].tileComps[0].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+			       img.tiles[tileIdx].tileComps[0].nQuantSteps,
+			       sizeof(Guint));
 	for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
 	  if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
 	    error(getPos(), "Error in JPX QCD marker segment");
@@ -1329,9 +1451,9 @@ GBool JPXStream::readTilePart() {
       } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) {
 	img.tiles[tileIdx].tileComps[0].nQuantSteps = 1;
 	img.tiles[tileIdx].tileComps[0].quantSteps =
-	    (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
-			      img.tiles[tileIdx].tileComps[0].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+			       img.tiles[tileIdx].tileComps[0].nQuantSteps,
+			       sizeof(Guint));
 	if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) {
 	  error(getPos(), "Error in JPX QCD marker segment");
 	  return gFalse;
@@ -1339,9 +1461,9 @@ GBool JPXStream::readTilePart() {
       } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) {
 	img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2;
 	img.tiles[tileIdx].tileComps[0].quantSteps =
-	    (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
-			      img.tiles[tileIdx].tileComps[0].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+			       img.tiles[tileIdx].tileComps[0].nQuantSteps,
+			       sizeof(Guint));
 	for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
 	  if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
 	    error(getPos(), "Error in JPX QCD marker segment");
@@ -1358,9 +1480,9 @@ GBool JPXStream::readTilePart() {
 	img.tiles[tileIdx].tileComps[comp].nQuantSteps =
 	    img.tiles[tileIdx].tileComps[0].nQuantSteps;
 	img.tiles[tileIdx].tileComps[comp].quantSteps = 
-	    (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
-			      img.tiles[tileIdx].tileComps[0].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+			       img.tiles[tileIdx].tileComps[0].nQuantSteps,
+			       sizeof(Guint));
 	for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) {
 	  img.tiles[tileIdx].tileComps[comp].quantSteps[j] =
 	      img.tiles[tileIdx].tileComps[0].quantSteps[j];
@@ -1379,9 +1501,9 @@ GBool JPXStream::readTilePart() {
 	img.tiles[tileIdx].tileComps[comp].nQuantSteps =
 	    segLen - (img.nComps > 256 ? 5 : 4);
 	img.tiles[tileIdx].tileComps[comp].quantSteps =
-	    (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
-			      img.tiles[tileIdx].tileComps[comp].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+			       img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+			       sizeof(Guint));
 	for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
 	  if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
 	    error(getPos(), "Error in JPX QCC marker segment");
@@ -1392,9 +1514,9 @@ GBool JPXStream::readTilePart() {
 		 == 0x01) {
 	img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1;
 	img.tiles[tileIdx].tileComps[comp].quantSteps =
-	    (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
-			      img.tiles[tileIdx].tileComps[comp].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+			       img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+			       sizeof(Guint));
 	if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) {
 	  error(getPos(), "Error in JPX QCC marker segment");
 	  return gFalse;
@@ -1404,9 +1526,9 @@ GBool JPXStream::readTilePart() {
 	img.tiles[tileIdx].tileComps[comp].nQuantSteps =
 	    (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
 	img.tiles[tileIdx].tileComps[comp].quantSteps =
-	    (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
-			      img.tiles[tileIdx].tileComps[comp].nQuantSteps *
-			        sizeof(Guint));
+	    (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+			       img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+			       sizeof(Guint));
 	for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
 	  if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
 	    error(getPos(), "Error in JPX QCD marker segment");
@@ -1449,7 +1571,7 @@ GBool JPXStream::readTilePart() {
       }
 #else
       nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
-      tileProgs = (JPXProgOrder *)gmalloc(nTileProgs * sizeof(JPXProgOrder));
+      tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder));
       for (i = 0; i < nTileProgs; ++i) {
 	if (!readUByte(&tileProgs[i].startRes) ||
 	    !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) ||
@@ -1541,15 +1663,15 @@ GBool JPXStream::readTilePart() {
       tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->hSep);
       tileComp->cbW = 1 << tileComp->codeBlockW;
       tileComp->cbH = 1 << tileComp->codeBlockH;
-      tileComp->data = (int *)gmalloc((tileComp->x1 - tileComp->x0) *
-				      (tileComp->y1 - tileComp->y0) *
-				      sizeof(int));
+      tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) *
+				       (tileComp->y1 - tileComp->y0),
+				       sizeof(int));
       if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
 	n = tileComp->x1 - tileComp->x0;
       } else {
 	n = tileComp->y1 - tileComp->y0;
       }
-      tileComp->buf = (int *)gmalloc((n + 8) * sizeof(int));
+      tileComp->buf = (int *)gmallocn(n + 8, sizeof(int));
       for (r = 0; r <= tileComp->nDecompLevels; ++r) {
 	resLevel = &tileComp->resLevels[r];
 	k = r == 0 ? tileComp->nDecompLevels
@@ -1577,7 +1699,7 @@ GBool JPXStream::readTilePart() {
 	  resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
 	  resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
 	}
-	resLevel->precincts = (JPXPrecinct *)gmalloc(1 * sizeof(JPXPrecinct));
+	resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct));
 	for (pre = 0; pre < 1; ++pre) {
 	  precinct = &resLevel->precincts[pre];
 	  precinct->x0 = resLevel->x0;
@@ -1586,7 +1708,7 @@ GBool JPXStream::readTilePart() {
 	  precinct->y1 = resLevel->y1;
 	  nSBs = r == 0 ? 1 : 3;
 	  precinct->subbands =
-	      (JPXSubband *)gmalloc(nSBs * sizeof(JPXSubband));
+	      (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband));
 	  for (sb = 0; sb < nSBs; ++sb) {
 	    subband = &precinct->subbands[sb];
 	    subband->x0 = resLevel->bx0[sb];
@@ -1613,18 +1735,18 @@ GBool JPXStream::readTilePart() {
 	      n += nx * ny;
 	    }
 	    subband->inclusion =
-	        (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode));
+	        (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
 	    subband->zeroBitPlane =
-	        (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode));
+	        (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
 	    for (k = 0; k < n; ++k) {
 	      subband->inclusion[k].finished = gFalse;
 	      subband->inclusion[k].val = 0;
 	      subband->zeroBitPlane[k].finished = gFalse;
 	      subband->zeroBitPlane[k].val = 0;
 	    }
-	    subband->cbs = (JPXCodeBlock *)gmalloc(subband->nXCBs *
-						   subband->nYCBs *
-						   sizeof(JPXCodeBlock));
+	    subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs *
+						      subband->nYCBs,
+						    sizeof(JPXCodeBlock));
 	    sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW);
 	    sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH);
 	    cb = subband->cbs;
@@ -1651,9 +1773,9 @@ GBool JPXStream::readTilePart() {
 		cb->nextPass = jpxPassCleanup;
 		cb->nZeroBitPlanes = 0;
 		cb->coeffs =
-		    (JPXCoeff *)gmalloc((1 << (tileComp->codeBlockW
-					       + tileComp->codeBlockH))
-					* sizeof(JPXCoeff));
+		    (JPXCoeff *)gmallocn((1 << (tileComp->codeBlockW
+						+ tileComp->codeBlockH)),
+					 sizeof(JPXCoeff));
 		for (cbi = 0;
 		     cbi < (Guint)(1 << (tileComp->codeBlockW
 					 + tileComp->codeBlockH));
@@ -1662,10 +1784,8 @@ GBool JPXStream::readTilePart() {
 		  cb->coeffs[cbi].len = 0;
 		  cb->coeffs[cbi].mag = 0;
 		}
-		cb->stats = new JArithmeticDecoderStats(jpxNContexts);
-		cb->stats->setEntry(jpxContextSigProp, 4, 0);
-		cb->stats->setEntry(jpxContextRunLength, 3, 0);
-		cb->stats->setEntry(jpxContextUniform, 46, 0);
+		cb->arithDecoder = NULL;
+		cb->stats = NULL;
 		++cb;
 	      }
 	    }
@@ -1963,14 +2083,21 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 				   Guint res, Guint sb,
 				   JPXCodeBlock *cb) {
   JPXCoeff *coeff0, *coeff1, *coeff;
-  JArithmeticDecoder *arithDecoder;
   Guint horiz, vert, diag, all, cx, xorBit;
   int horizSign, vertSign;
   Guint i, x, y0, y1, y2;
 
-  arithDecoder = new JArithmeticDecoder();
-  arithDecoder->setStream(str, cb->dataLen);
-  arithDecoder->start();
+  if (cb->arithDecoder) {
+    cb->arithDecoder->restart(cb->dataLen);
+  } else {
+    cb->arithDecoder = new JArithmeticDecoder();
+    cb->arithDecoder->setStream(str, cb->dataLen);
+    cb->arithDecoder->start();
+    cb->stats = new JArithmeticDecoderStats(jpxNContexts);
+    cb->stats->setEntry(jpxContextSigProp, 4, 0);
+    cb->stats->setEntry(jpxContextRunLength, 3, 0);
+    cb->stats->setEntry(jpxContextUniform, 46, 0);
+  }
 
   for (i = 0; i < cb->nCodingPasses; ++i) {
     switch (cb->nextPass) {
@@ -1995,7 +2122,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 		  horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
 		}
 		if (y0+y1 > cb->y0) {
-		  diag += (coeff[-tileComp->cbW - 1].flags
+		  diag += (coeff[-(int)tileComp->cbW - 1].flags
 			   >> jpxCoeffSignificantB) & 1;
 		}
 		if (y0+y1 < cb->y1 - 1) {
@@ -2009,7 +2136,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 		  horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
 		}
 		if (y0+y1 > cb->y0) {
-		  diag += (coeff[-tileComp->cbW + 1].flags
+		  diag += (coeff[-(int)tileComp->cbW + 1].flags
 			   >> jpxCoeffSignificantB) & 1;
 		}
 		if (y0+y1 < cb->y1 - 1) {
@@ -2018,9 +2145,9 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 		}
 	      }
 	      if (y0+y1 > cb->y0) {
-		if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) {
+		if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) {
 		  ++vert;
-		  vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign)
+		  vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign)
 		              ? -1 : 1;
 		}
 	      }
@@ -2033,12 +2160,12 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 	      }
 	      cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
 	      if (cx != 0) {
-		if (arithDecoder->decodeBit(cx, cb->stats)) {
+		if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
 		  coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
 		  coeff->mag = (coeff->mag << 1) | 1;
 		  cx = signContext[horizSign][vertSign][0];
 		  xorBit = signContext[horizSign][vertSign][1];
-		  if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+		  if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
 		    coeff->flags |= jpxCoeffSign;
 		  }
 		}
@@ -2070,7 +2197,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 		if (x > cb->x0) {
 		  all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1;
 		  if (y0+y1 > cb->y0) {
-		    all += (coeff[-tileComp->cbW - 1].flags
+		    all += (coeff[-(int)tileComp->cbW - 1].flags
 			    >> jpxCoeffSignificantB) & 1;
 		  }
 		  if (y0+y1 < cb->y1 - 1) {
@@ -2081,7 +2208,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 		if (x < cb->x1 - 1) {
 		  all += (coeff[1].flags >> jpxCoeffSignificantB) & 1;
 		  if (y0+y1 > cb->y0) {
-		    all += (coeff[-tileComp->cbW + 1].flags
+		    all += (coeff[-(int)tileComp->cbW + 1].flags
 			    >> jpxCoeffSignificantB) & 1;
 		  }
 		  if (y0+y1 < cb->y1 - 1) {
@@ -2090,7 +2217,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 		  }
 		}
 		if (y0+y1 > cb->y0) {
-		  all += (coeff[-tileComp->cbW].flags
+		  all += (coeff[-(int)tileComp->cbW].flags
 			  >> jpxCoeffSignificantB) & 1;
 		}
 		if (y0+y1 < cb->y1 - 1) {
@@ -2102,7 +2229,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 		cx = 16;
 	      }
 	      coeff->mag = (coeff->mag << 1) |
-		           arithDecoder->decodeBit(cx, cb->stats);
+		           cb->arithDecoder->decodeBit(cx, cb->stats);
 	      ++coeff->len;
 	      coeff->flags |= jpxCoeffTouched;
 	      coeff->flags &= ~jpxCoeffFirstMagRef;
@@ -2128,12 +2255,14 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 	      !(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) &&
 	      !(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) &&
 	      (x == cb->x0 || y0 == cb->y0 ||
-	       !(coeff1[-tileComp->cbW - 1].flags
+	       !(coeff1[-(int)tileComp->cbW - 1].flags
 		 & jpxCoeffSignificant)) &&
 	      (y0 == cb->y0 ||
-	       !(coeff1[-tileComp->cbW].flags & jpxCoeffSignificant)) &&
+	       !(coeff1[-(int)tileComp->cbW].flags
+		 & jpxCoeffSignificant)) &&
 	      (x == cb->x1 - 1 || y0 == cb->y0 ||
-	       !(coeff1[-tileComp->cbW + 1].flags & jpxCoeffSignificant)) &&
+	       !(coeff1[-(int)tileComp->cbW + 1].flags
+		 & jpxCoeffSignificant)) &&
 	      (x == cb->x0 ||
 	       (!(coeff1[-1].flags & jpxCoeffSignificant) &&
 		!(coeff1[tileComp->cbW - 1].flags
@@ -2157,10 +2286,10 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 	      (x == cb->x1 - 1 || y0+4 == cb->y1 ||
 	       !(coeff1[4 * tileComp->cbW + 1].flags
 		 & jpxCoeffSignificant))) {
-	    if (arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) {
-	      y1 = arithDecoder->decodeBit(jpxContextUniform, cb->stats);
+	    if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) {
+	      y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
 	      y1 = (y1 << 1) |
-		   arithDecoder->decodeBit(jpxContextUniform, cb->stats);
+		   cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
 	      for (y2 = 0, coeff = coeff1;
 		   y2 < y1;
 		   ++y2, coeff += tileComp->cbW) {
@@ -2171,7 +2300,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 	      ++coeff->len;
 	      cx = signContext[2][2][0];
 	      xorBit = signContext[2][2][1];
-	      if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+	      if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
 		coeff->flags |= jpxCoeffSign;
 	      }
 	      ++y1;
@@ -2196,7 +2325,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 		  horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
 		}
 		if (y0+y1 > cb->y0) {
-		  diag += (coeff[-tileComp->cbW - 1].flags
+		  diag += (coeff[-(int)tileComp->cbW - 1].flags
 			   >> jpxCoeffSignificantB) & 1;
 		}
 		if (y0+y1 < cb->y1 - 1) {
@@ -2210,7 +2339,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 		  horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
 		}
 		if (y0+y1 > cb->y0) {
-		  diag += (coeff[-tileComp->cbW + 1].flags
+		  diag += (coeff[-(int)tileComp->cbW + 1].flags
 			   >> jpxCoeffSignificantB) & 1;
 		}
 		if (y0+y1 < cb->y1 - 1) {
@@ -2219,9 +2348,9 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 		}
 	      }
 	      if (y0+y1 > cb->y0) {
-		if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) {
+		if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) {
 		  ++vert;
-		  vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign)
+		  vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign)
 		              ? -1 : 1;
 		}
 	      }
@@ -2233,12 +2362,12 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
 		}
 	      }
 	      cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
-	      if (arithDecoder->decodeBit(cx, cb->stats)) {
+	      if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
 		coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
 		coeff->mag = (coeff->mag << 1) | 1;
 		cx = signContext[horizSign][vertSign][0];
 		xorBit = signContext[horizSign][vertSign][1];
-		if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+		if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
 		  coeff->flags |= jpxCoeffSign;
 		}
 	      }
@@ -2254,7 +2383,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
     }
   }
 
-  delete arithDecoder;
+  cb->arithDecoder->cleanup();
   return gTrue;
 }
 
@@ -2266,7 +2395,8 @@ void JPXStream::inverseTransform(JPXTileComp *tileComp) {
   JPXSubband *subband;
   JPXCodeBlock *cb;
   JPXCoeff *coeff0, *coeff;
-  Guint qStyle, guard, eps, shift, shift2;
+  Guint qStyle, guard, eps, shift;
+  int shift2;
   double mu;
   int val;
   int *dataPtr;
@@ -2368,7 +2498,8 @@ void JPXStream::inverseTransformLevel(JPXTileComp *tileComp,
   JPXSubband *subband;
   JPXCodeBlock *cb;
   JPXCoeff *coeff0, *coeff;
-  Guint qStyle, guard, eps, shift, shift2, t;
+  Guint qStyle, guard, eps, shift, t;
+  int shift2;
   double mu;
   int val;
   int *dataPtr;
@@ -2578,7 +2709,7 @@ void JPXStream::inverseTransform1D(JPXTileComp *tileComp,
 // converts fixed point samples back to integers.
 GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) {
   JPXTileComp *tileComp;
-  int coeff, d0, d1, d2, minVal, maxVal, zeroVal;
+  int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal;
   int *dataPtr;
   Guint j, comp, x, y;
 
@@ -2617,9 +2748,9 @@ GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) {
 	  d0 = tile->tileComps[0].data[j];
 	  d1 = tile->tileComps[1].data[j];
 	  d2 = tile->tileComps[2].data[j];
-	  tile->tileComps[0].data[j] = d0 - ((d2 + d1) >> 2);
-	  tile->tileComps[1].data[j] = d2 - d1;
-	  tile->tileComps[2].data[j] = d0 - d1;
+	  tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2);
+	  tile->tileComps[0].data[j] = d2 + t;
+	  tile->tileComps[2].data[j] = d1 + t;
 	  ++j;
 	}
       }
diff --git a/pdf2swf/xpdf/JPXStream.h b/pdf2swf/xpdf/JPXStream.h
index eb84fe6..e64731d 100644
--- a/pdf2swf/xpdf/JPXStream.h
+++ b/pdf2swf/xpdf/JPXStream.h
@@ -44,18 +44,22 @@ enum JPXColorSpaceType {
   jpxCSYPbPr1250 = 24
 };
 
+struct JPXColorSpecCIELab {
+  Guint rl, ol, ra, oa, rb, ob, il;
+};
+
+struct JPXColorSpecEnumerated {
+  JPXColorSpaceType type;	// color space type
+  union {
+    JPXColorSpecCIELab cieLab;
+  };
+};
+
 struct JPXColorSpec {
   Guint meth;			// method
   int prec;			// precedence
   union {
-    struct {
-      JPXColorSpaceType type;	// color space type
-      union {
-	struct {
-	  Guint rl, ol, ra, oa, rb, ob, il;
-	} cieLab;
-      };
-    } enumerated;
+    JPXColorSpecEnumerated enumerated;
   };
 };
 
@@ -135,6 +139,8 @@ struct JPXCodeBlock {
 
   //----- coefficient data
   JPXCoeff *coeffs;		// the coefficients
+  JArithmeticDecoder		// arithmetic decoder
+    *arithDecoder;
   JArithmeticDecoderStats	// arithmetic decoder stats
     *stats;
 };
@@ -275,10 +281,13 @@ public:
   virtual int lookChar();
   virtual GString *getPSFilter(int psLevel, char *indent);
   virtual GBool isBinary(GBool last = gTrue);
+  virtual void getImageParams(int *bitsPerComponent,
+			      StreamColorSpaceMode *csMode);
 
 private:
 
   void fillReadBuf();
+  void getImageParams2(int *bitsPerComponent, StreamColorSpaceMode *csMode);
   GBool readBoxes();
   GBool readColorSpecBox(Guint dataLen);
   GBool readCodestream(Guint len);
diff --git a/pdf2swf/xpdf/Lexer.cc b/pdf2swf/xpdf/Lexer.cc
index 1fa166f..9f0c3ca 100644
--- a/pdf2swf/xpdf/Lexer.cc
+++ b/pdf2swf/xpdf/Lexer.cc
@@ -171,6 +171,13 @@ Object *Lexer::getObj(Object *obj) {
     scale = 0.1;
     while (1) {
       c = lookChar();
+      if (c == '-') {
+	// ignore minus signs in the middle of numbers to match
+	// Adobe's behavior
+	error(getPos(), "Badly formatted number");
+	getChar();
+	continue;
+      }
       if (!isdigit(c)) {
 	break;
       }
@@ -472,3 +479,7 @@ void Lexer::skipToNextLine() {
     }
   }
 }
+
+GBool Lexer::isSpace(int c) {
+  return c >= 0 && c <= 0xff && specialChars[c] == 1;
+}
diff --git a/pdf2swf/xpdf/Lexer.h b/pdf2swf/xpdf/Lexer.h
index 398d27c..f6ad9ce 100644
--- a/pdf2swf/xpdf/Lexer.h
+++ b/pdf2swf/xpdf/Lexer.h
@@ -62,6 +62,9 @@ public:
   void setPos(Guint pos, int dir = 0)
     { if (!curStr.isNone()) curStr.streamSetPos(pos, dir); }
 
+  // Returns true if <c> is a whitespace character.
+  static GBool isSpace(int c);
+
 private:
 
   int getChar();
diff --git a/pdf2swf/xpdf/Link.cc b/pdf2swf/xpdf/Link.cc
index 2d146b5..898ca20 100644
--- a/pdf2swf/xpdf/Link.cc
+++ b/pdf2swf/xpdf/Link.cc
@@ -117,14 +117,19 @@ GString *LinkAction::getFileSpecName(Object *fileSpecObj) {
 
   // dictionary
   } else if (fileSpecObj->isDict()) {
+#ifdef WIN32
+    if (!fileSpecObj->dictLookup("DOS", &obj1)->isString()) {
+#else
     if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) {
+#endif
       obj1.free();
       fileSpecObj->dictLookup("F", &obj1);
     }
-    if (obj1.isString())
+    if (obj1.isString()) {
       name = obj1.getString()->copy();
-    else
+    } else {
       error(-1, "Illegal file spec in link");
+    }
     obj1.free();
 
   // error
@@ -132,6 +137,55 @@ GString *LinkAction::getFileSpecName(Object *fileSpecObj) {
     error(-1, "Illegal file spec in link");
   }
 
+  // system-dependent path manipulation
+  if (name) {
+#ifdef WIN32
+    int i, j;
+
+    // "//...."             --> "\...."
+    // "/x/...."            --> "x:\...."
+    // "/server/share/...." --> "\\server\share\...."
+    // convert escaped slashes to slashes and unescaped slashes to backslashes
+    i = 0;
+    if (name->getChar(0) == '/') {
+      if (name->getLength() >= 2 && name->getChar(1) == '/') {
+	name->del(0);
+	i = 0;
+      } else if (name->getLength() >= 2 &&
+		 ((name->getChar(1) >= 'a' && name->getChar(1) <= 'z') ||
+		  (name->getChar(1) >= 'A' && name->getChar(1) <= 'Z')) &&
+		 (name->getLength() == 2 || name->getChar(2) == '/')) {
+	name->setChar(0, name->getChar(1));
+	name->setChar(1, ':');
+	i = 2;
+      } else {
+	for (j = 2; j < name->getLength(); ++j) {
+	  if (name->getChar(j-1) != '\\' &&
+	      name->getChar(j) == '/') {
+	    break;
+	  }
+	}
+	if (j < name->getLength()) {
+	  name->setChar(0, '\\');
+	  name->insert(0, '\\');
+	  i = 2;
+	}
+      }
+    }
+    for (; i < name->getLength(); ++i) {
+      if (name->getChar(i) == '/') {
+	name->setChar(i, '\\');
+      } else if (name->getChar(i) == '\\' &&
+		 i+1 < name->getLength() &&
+		 name->getChar(i+1) == '/') {
+	name->del(i);
+      }
+    }
+#else
+    // no manipulation needed for Unix
+#endif
+  }
+
   return name;
 }
 
@@ -497,7 +551,7 @@ LinkURI::LinkURI(Object *uriObj, GString *baseURI) {
   uri = NULL;
   if (uriObj->isString()) {
     uri2 = uriObj->getString()->copy();
-    if (baseURI) {
+    if (baseURI && baseURI->getLength() > 0) {
       n = strcspn(uri2->getCString(), "/:");
       if (n == uri2->getLength() || uri2->getChar(n) == '/') {
 	uri = baseURI->copy();
@@ -690,7 +744,7 @@ Link::Link(Dict *dict, GString *baseURI) {
     obj2.free();
     if (obj1.dictLookup("D", &obj2)->isArray()) {
       borderDashLength = obj2.arrayGetLength();
-      borderDash = (double *)gmalloc(borderDashLength * sizeof(double));
+      borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
       for (i = 0; i < borderDashLength; ++i) {
 	if (obj2.arrayGet(i, &obj3)->isNum()) {
 	  borderDash[i] = obj3.getNum();
@@ -713,7 +767,7 @@ Link::Link(Dict *dict, GString *baseURI) {
 	  if (obj1.arrayGet(3, &obj2)->isArray()) {
 	    borderType = linkBorderDashed;
 	    borderDashLength = obj2.arrayGetLength();
-	    borderDash = (double *)gmalloc(borderDashLength * sizeof(double));
+	    borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
 	    for (i = 0; i < borderDashLength; ++i) {
 	      if (obj2.arrayGet(i, &obj3)->isNum()) {
 		borderDash[i] = obj3.getNum();
@@ -722,6 +776,10 @@ Link::Link(Dict *dict, GString *baseURI) {
 	      }
 	      obj3.free();
 	    }
+	  } else {
+	    // Adobe draws no border at all if the last element is of
+	    // the wrong type.
+	    borderWidth = 0;
 	  }
 	  obj2.free();
 	}
@@ -805,7 +863,7 @@ Links::Links(Object *annots, GString *baseURI) {
 	  if (link->isOk()) {
 	    if (numLinks >= size) {
 	      size += 16;
-	      links = (Link **)grealloc(links, size * sizeof(Link *));
+	      links = (Link **)greallocn(links, size, sizeof(Link *));
 	    }
 	    links[numLinks++] = link;
 	  } else {
diff --git a/pdf2swf/xpdf/NameToCharCode.cc b/pdf2swf/xpdf/NameToCharCode.cc
index 8f22a90..7ebf4e1 100644
--- a/pdf2swf/xpdf/NameToCharCode.cc
+++ b/pdf2swf/xpdf/NameToCharCode.cc
@@ -30,7 +30,7 @@ NameToCharCode::NameToCharCode() {
 
   size = 31;
   len = 0;
-  tab = (NameToCharCodeEntry *)gmalloc(size * sizeof(NameToCharCodeEntry));
+  tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry));
   for (i = 0; i < size; ++i) {
     tab[i].name = NULL;
   }
@@ -56,7 +56,7 @@ void NameToCharCode::add(char *name, CharCode c) {
     oldSize = size;
     oldTab = tab;
     size = 2*size + 1;
-    tab = (NameToCharCodeEntry *)gmalloc(size * sizeof(NameToCharCodeEntry));
+    tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry));
     for (h = 0; h < size; ++h) {
       tab[h].name = NULL;
     }
diff --git a/pdf2swf/xpdf/NameToUnicodeTable.h b/pdf2swf/xpdf/NameToUnicodeTable.h
index 4f28fff..c5ecba4 100644
--- a/pdf2swf/xpdf/NameToUnicodeTable.h
+++ b/pdf2swf/xpdf/NameToUnicodeTable.h
@@ -2,7 +2,7 @@
 //
 // NameToUnicodeTable.h
 //
-// Copyright 2001-2003 Glyph & Cog, LLC
+// Copyright 2001-2004 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -44,45 +44,45 @@ static struct {
   {0x0041, "A"},
   {0x00c6, "AE"},
   {0x01fc, "AEacute"},
-  {0x00c6, "AEsmall"},
+  {0xf7e6, "AEsmall"},
   {0x00c1, "Aacute"},
-  {0x00c1, "Aacutesmall"},
+  {0xf7e1, "Aacutesmall"},
   {0x0102, "Abreve"},
   {0x00c2, "Acircumflex"},
-  {0x00c2, "Acircumflexsmall"},
+  {0xf7e2, "Acircumflexsmall"},
   {0xf6c9, "Acute"},
-  {0xf6c9, "Acutesmall"},
+  {0xf7b4, "Acutesmall"},
   {0x00c4, "Adieresis"},
-  {0x00c4, "Adieresissmall"},
+  {0xf7e4, "Adieresissmall"},
   {0x00c0, "Agrave"},
-  {0x00c0, "Agravesmall"},
+  {0xf7e0, "Agravesmall"},
   {0x0391, "Alpha"},
   {0x0386, "Alphatonos"},
   {0x0100, "Amacron"},
   {0x0104, "Aogonek"},
   {0x00c5, "Aring"},
   {0x01fa, "Aringacute"},
-  {0x00c5, "Aringsmall"},
-  {0x0041, "Asmall"},
+  {0xf7e5, "Aringsmall"},
+  {0xf761, "Asmall"},
   {0x00c3, "Atilde"},
-  {0x00c3, "Atildesmall"},
+  {0xf7e3, "Atildesmall"},
   {0x0042, "B"},
   {0x0392, "Beta"},
   {0xf6f4, "Brevesmall"},
-  {0x0042, "Bsmall"},
+  {0xf762, "Bsmall"},
   {0x0043, "C"},
   {0x0106, "Cacute"},
   {0xf6ca, "Caron"},
-  {0xf6ca, "Caronsmall"},
+  {0xf6f5, "Caronsmall"},
   {0x010c, "Ccaron"},
   {0x00c7, "Ccedilla"},
-  {0x00c7, "Ccedillasmall"},
+  {0xf7e7, "Ccedillasmall"},
   {0x0108, "Ccircumflex"},
   {0x010a, "Cdotaccent"},
   {0xf7b8, "Cedillasmall"},
   {0x03a7, "Chi"},
   {0xf6f6, "Circumflexsmall"},
-  {0x0043, "Csmall"},
+  {0xf763, "Csmall"},
   {0x0044, "D"},
   {0x010e, "Dcaron"},
   {0x0110, "Dcroat"},
@@ -90,34 +90,34 @@ static struct {
   {0xf6cb, "Dieresis"},
   {0xf6cc, "DieresisAcute"},
   {0xf6cd, "DieresisGrave"},
-  {0xf6cb, "Dieresissmall"},
+  {0xf7a8, "Dieresissmall"},
   {0xf6f7, "Dotaccentsmall"},
-  {0x0044, "Dsmall"},
+  {0xf764, "Dsmall"},
   {0x0045, "E"},
   {0x00c9, "Eacute"},
-  {0x00c9, "Eacutesmall"},
+  {0xf7e9, "Eacutesmall"},
   {0x0114, "Ebreve"},
   {0x011a, "Ecaron"},
   {0x00ca, "Ecircumflex"},
-  {0x00ca, "Ecircumflexsmall"},
+  {0xf7ea, "Ecircumflexsmall"},
   {0x00cb, "Edieresis"},
-  {0x00cb, "Edieresissmall"},
+  {0xf7eb, "Edieresissmall"},
   {0x0116, "Edotaccent"},
   {0x00c8, "Egrave"},
-  {0x00c8, "Egravesmall"},
+  {0xf7e8, "Egravesmall"},
   {0x0112, "Emacron"},
   {0x014a, "Eng"},
   {0x0118, "Eogonek"},
   {0x0395, "Epsilon"},
   {0x0388, "Epsilontonos"},
-  {0x0045, "Esmall"},
+  {0xf765, "Esmall"},
   {0x0397, "Eta"},
   {0x0389, "Etatonos"},
   {0x00d0, "Eth"},
-  {0x00d0, "Ethsmall"},
+  {0xf7f0, "Ethsmall"},
   {0x20ac, "Euro"},
   {0x0046, "F"},
-  {0x0046, "Fsmall"},
+  {0xf766, "Fsmall"},
   {0x0047, "G"},
   {0x0393, "Gamma"},
   {0x011e, "Gbreve"},
@@ -126,8 +126,8 @@ static struct {
   {0x0122, "Gcommaaccent"},
   {0x0120, "Gdotaccent"},
   {0xf6ce, "Grave"},
-  {0xf6ce, "Gravesmall"},
-  {0x0047, "Gsmall"},
+  {0xf760, "Gravesmall"},
+  {0xf767, "Gsmall"},
   {0x0048, "H"},
   {0x25cf, "H18533"},
   {0x25aa, "H18543"},
@@ -135,36 +135,36 @@ static struct {
   {0x25a1, "H22073"},
   {0x0126, "Hbar"},
   {0x0124, "Hcircumflex"},
-  {0x0048, "Hsmall"},
+  {0xf768, "Hsmall"},
   {0xf6cf, "Hungarumlaut"},
-  {0xf6cf, "Hungarumlautsmall"},
+  {0xf6f8, "Hungarumlautsmall"},
   {0x0049, "I"},
   {0x0132, "IJ"},
   {0x00cd, "Iacute"},
-  {0x00cd, "Iacutesmall"},
+  {0xf7ed, "Iacutesmall"},
   {0x012c, "Ibreve"},
   {0x00ce, "Icircumflex"},
-  {0x00ce, "Icircumflexsmall"},
+  {0xf7ee, "Icircumflexsmall"},
   {0x00cf, "Idieresis"},
-  {0x00cf, "Idieresissmall"},
+  {0xf7ef, "Idieresissmall"},
   {0x0130, "Idotaccent"},
   {0x2111, "Ifraktur"},
   {0x00cc, "Igrave"},
-  {0x00cc, "Igravesmall"},
+  {0xf7ec, "Igravesmall"},
   {0x012a, "Imacron"},
   {0x012e, "Iogonek"},
   {0x0399, "Iota"},
   {0x03aa, "Iotadieresis"},
   {0x038a, "Iotatonos"},
-  {0x0049, "Ismall"},
+  {0xf769, "Ismall"},
   {0x0128, "Itilde"},
   {0x004a, "J"},
   {0x0134, "Jcircumflex"},
-  {0x004a, "Jsmall"},
+  {0xf76a, "Jsmall"},
   {0x004b, "K"},
   {0x039a, "Kappa"},
   {0x0136, "Kcommaaccent"},
-  {0x004b, "Ksmall"},
+  {0xf76b, "Ksmall"},
   {0x004c, "L"},
   {0xf6bf, "LL"},
   {0x0139, "Lacute"},
@@ -173,34 +173,34 @@ static struct {
   {0x013b, "Lcommaaccent"},
   {0x013f, "Ldot"},
   {0x0141, "Lslash"},
-  {0x0141, "Lslashsmall"},
-  {0x004c, "Lsmall"},
+  {0xf6f9, "Lslashsmall"},
+  {0xf76c, "Lsmall"},
   {0x004d, "M"},
   {0xf6d0, "Macron"},
-  {0xf6d0, "Macronsmall"},
-  {0x004d, "Msmall"},
+  {0xf7af, "Macronsmall"},
+  {0xf76d, "Msmall"},
   {0x039c, "Mu"},
   {0x004e, "N"},
   {0x0143, "Nacute"},
   {0x0147, "Ncaron"},
   {0x0145, "Ncommaaccent"},
-  {0x004e, "Nsmall"},
+  {0xf76e, "Nsmall"},
   {0x00d1, "Ntilde"},
-  {0x00d1, "Ntildesmall"},
+  {0xf7f1, "Ntildesmall"},
   {0x039d, "Nu"},
   {0x004f, "O"},
   {0x0152, "OE"},
-  {0x0152, "OEsmall"},
+  {0xf6fa, "OEsmall"},
   {0x00d3, "Oacute"},
-  {0x00d3, "Oacutesmall"},
+  {0xf7f3, "Oacutesmall"},
   {0x014e, "Obreve"},
   {0x00d4, "Ocircumflex"},
-  {0x00d4, "Ocircumflexsmall"},
+  {0xf7f4, "Ocircumflexsmall"},
   {0x00d6, "Odieresis"},
-  {0x00d6, "Odieresissmall"},
+  {0xf7f6, "Odieresissmall"},
   {0xf6fb, "Ogoneksmall"},
   {0x00d2, "Ograve"},
-  {0x00d2, "Ogravesmall"},
+  {0xf7f2, "Ogravesmall"},
   {0x01a0, "Ohorn"},
   {0x0150, "Ohungarumlaut"},
   {0x014c, "Omacron"},
@@ -210,17 +210,17 @@ static struct {
   {0x038c, "Omicrontonos"},
   {0x00d8, "Oslash"},
   {0x01fe, "Oslashacute"},
-  {0x00d8, "Oslashsmall"},
-  {0x004f, "Osmall"},
+  {0xf7f8, "Oslashsmall"},
+  {0xf76f, "Osmall"},
   {0x00d5, "Otilde"},
-  {0x00d5, "Otildesmall"},
+  {0xf7f5, "Otildesmall"},
   {0x0050, "P"},
   {0x03a6, "Phi"},
   {0x03a0, "Pi"},
   {0x03a8, "Psi"},
-  {0x0050, "Psmall"},
+  {0xf770, "Psmall"},
   {0x0051, "Q"},
-  {0x0051, "Qsmall"},
+  {0xf771, "Qsmall"},
   {0x0052, "R"},
   {0x0154, "Racute"},
   {0x0158, "Rcaron"},
@@ -228,7 +228,7 @@ static struct {
   {0x211c, "Rfraktur"},
   {0x03a1, "Rho"},
   {0xf6fc, "Ringsmall"},
-  {0x0052, "Rsmall"},
+  {0xf772, "Rsmall"},
   {0x0053, "S"},
   {0x250c, "SF010000"},
   {0x2514, "SF020000"},
@@ -272,12 +272,12 @@ static struct {
   {0x256a, "SF540000"},
   {0x015a, "Sacute"},
   {0x0160, "Scaron"},
-  {0x0160, "Scaronsmall"},
+  {0xf6fd, "Scaronsmall"},
   {0x015e, "Scedilla"},
   {0x015c, "Scircumflex"},
   {0x0218, "Scommaaccent"},
   {0x03a3, "Sigma"},
-  {0x0053, "Ssmall"},
+  {0xf773, "Ssmall"},
   {0x0054, "T"},
   {0x03a4, "Tau"},
   {0x0166, "Tbar"},
@@ -285,19 +285,19 @@ static struct {
   {0x0162, "Tcommaaccent"},
   {0x0398, "Theta"},
   {0x00de, "Thorn"},
-  {0x00de, "Thornsmall"},
+  {0xf7fe, "Thornsmall"},
   {0xf6fe, "Tildesmall"},
-  {0x0054, "Tsmall"},
+  {0xf774, "Tsmall"},
   {0x0055, "U"},
   {0x00da, "Uacute"},
-  {0x00da, "Uacutesmall"},
+  {0xf7fa, "Uacutesmall"},
   {0x016c, "Ubreve"},
   {0x00db, "Ucircumflex"},
-  {0x00db, "Ucircumflexsmall"},
+  {0xf7fb, "Ucircumflexsmall"},
   {0x00dc, "Udieresis"},
-  {0x00dc, "Udieresissmall"},
+  {0xf7fc, "Udieresissmall"},
   {0x00d9, "Ugrave"},
-  {0x00d9, "Ugravesmall"},
+  {0xf7f9, "Ugravesmall"},
   {0x01af, "Uhorn"},
   {0x0170, "Uhungarumlaut"},
   {0x016a, "Umacron"},
@@ -307,34 +307,34 @@ static struct {
   {0x03ab, "Upsilondieresis"},
   {0x038e, "Upsilontonos"},
   {0x016e, "Uring"},
-  {0x0055, "Usmall"},
+  {0xf775, "Usmall"},
   {0x0168, "Utilde"},
   {0x0056, "V"},
-  {0x0056, "Vsmall"},
+  {0xf776, "Vsmall"},
   {0x0057, "W"},
   {0x1e82, "Wacute"},
   {0x0174, "Wcircumflex"},
   {0x1e84, "Wdieresis"},
   {0x1e80, "Wgrave"},
-  {0x0057, "Wsmall"},
+  {0xf777, "Wsmall"},
   {0x0058, "X"},
   {0x039e, "Xi"},
-  {0x0058, "Xsmall"},
+  {0xf778, "Xsmall"},
   {0x0059, "Y"},
   {0x00dd, "Yacute"},
-  {0x00dd, "Yacutesmall"},
+  {0xf7fd, "Yacutesmall"},
   {0x0176, "Ycircumflex"},
   {0x0178, "Ydieresis"},
-  {0x0178, "Ydieresissmall"},
+  {0xf7ff, "Ydieresissmall"},
   {0x1ef2, "Ygrave"},
-  {0x0059, "Ysmall"},
+  {0xf779, "Ysmall"},
   {0x005a, "Z"},
   {0x0179, "Zacute"},
   {0x017d, "Zcaron"},
-  {0x017d, "Zcaronsmall"},
+  {0xf6ff, "Zcaronsmall"},
   {0x017b, "Zdotaccent"},
   {0x0396, "Zeta"},
-  {0x005a, "Zsmall"},
+  {0xf77a, "Zsmall"},
   {0x0022, "\""},
   {0x005c, "\\"},
   {0x005d, "]"},
@@ -601,7 +601,7 @@ static struct {
   {0x03ac, "alphatonos"},
   {0x0101, "amacron"},
   {0x0026, "ampersand"},
-  {0x0026, "ampersandsmall"},
+  {0xf726, "ampersandsmall"},
   {0x2220, "angle"},
   {0x2329, "angleleft"},
   {0x232a, "angleright"},
@@ -668,7 +668,7 @@ static struct {
   {0x00b8, "cedilla"},
   {0x00a2, "cent"},
   {0xf6df, "centinferior"},
-  {0x00a2, "centoldstyle"},
+  {0xf7a2, "centoldstyle"},
   {0xf6e0, "centsuperior"},
   {0x03c7, "chi"},
   {0x25cb, "circle"},
@@ -710,7 +710,7 @@ static struct {
   {0x2584, "dnblock"},
   {0x0024, "dollar"},
   {0xf6e3, "dollarinferior"},
-  {0x0024, "dollaroldstyle"},
+  {0xf724, "dollaroldstyle"},
   {0xf6e4, "dollarsuperior"},
   {0x20ab, "dong"},
   {0x02d9, "dotaccent"},
@@ -729,7 +729,7 @@ static struct {
   {0x00e8, "egrave"},
   {0x0038, "eight"},
   {0x2088, "eightinferior"},
-  {0x0038, "eightoldstyle"},
+  {0xf738, "eightoldstyle"},
   {0x2078, "eightsuperior"},
   {0x2208, "element"},
   {0x2026, "ellipsis"},
@@ -751,9 +751,9 @@ static struct {
   {0x0021, "exclam"},
   {0x203c, "exclamdbl"},
   {0x00a1, "exclamdown"},
-  {0x00a1, "exclamdownsmall"},
+  {0xf7a1, "exclamdownsmall"},
   {0x0021, "exclamleft"},
-  {0x0021, "exclamsmall"},
+  {0xf721, "exclamsmall"},
   {0x2203, "existential"},
   {0x0066, "f"},
   {0x2640, "female"},
@@ -767,13 +767,13 @@ static struct {
   {0x0035, "five"},
   {0x215d, "fiveeighths"},
   {0x2085, "fiveinferior"},
-  {0x0035, "fiveoldstyle"},
+  {0xf735, "fiveoldstyle"},
   {0x2075, "fivesuperior"},
   {0xfb02, "fl"},
   {0x0192, "florin"},
   {0x0034, "four"},
   {0x2084, "fourinferior"},
-  {0x0034, "fouroldstyle"},
+  {0xf734, "fouroldstyle"},
   {0x2074, "foursuperior"},
   {0x2044, "fraction"},
   {0x20a3, "franc"},
@@ -871,7 +871,7 @@ static struct {
   {0x0146, "ncommaaccent"},
   {0x0039, "nine"},
   {0x2089, "nineinferior"},
-  {0x0039, "nineoldstyle"},
+  {0xf739, "nineoldstyle"},
   {0x2079, "ninesuperior"},
   {0x00a0, "nonbreakingspace"},
   {0x2209, "notelement"},
@@ -903,7 +903,7 @@ static struct {
   {0xf6dc, "onefitted"},
   {0x00bd, "onehalf"},
   {0x2081, "oneinferior"},
-  {0x0031, "oneoldstyle"},
+  {0xf731, "oneoldstyle"},
   {0x00bc, "onequarter"},
   {0x00b9, "onesuperior"},
   {0x2153, "onethird"},
@@ -952,8 +952,8 @@ static struct {
   {0x0071, "q"},
   {0x003f, "question"},
   {0x00bf, "questiondown"},
-  {0x00bf, "questiondownsmall"},
-  {0x003f, "questionsmall"},
+  {0xf7bf, "questiondownsmall"},
+  {0xf73f, "questionsmall"},
   {0x0022, "quotedbl"},
   {0x201e, "quotedblbase"},
   {0x201c, "quotedblleft"},
@@ -992,7 +992,7 @@ static struct {
   {0x0037, "seven"},
   {0x215e, "seveneighths"},
   {0x2087, "seveninferior"},
-  {0x0037, "sevenoldstyle"},
+  {0xf737, "sevenoldstyle"},
   {0x2077, "sevensuperior"},
   {0x2592, "shade"},
   {0x03c3, "sigma"},
@@ -1000,7 +1000,7 @@ static struct {
   {0x223c, "similar"},
   {0x0036, "six"},
   {0x2086, "sixinferior"},
-  {0x0036, "sixoldstyle"},
+  {0xf736, "sixoldstyle"},
   {0x2076, "sixsuperior"},
   {0x002f, "slash"},
   {0x263a, "smileface"},
@@ -1023,7 +1023,7 @@ static struct {
   {0x0033, "three"},
   {0x215c, "threeeighths"},
   {0x2083, "threeinferior"},
-  {0x0033, "threeoldstyle"},
+  {0xf733, "threeoldstyle"},
   {0x00be, "threequarters"},
   {0xf6de, "threequartersemdash"},
   {0x00b3, "threesuperior"},
@@ -1041,7 +1041,7 @@ static struct {
   {0x0032, "two"},
   {0x2025, "twodotenleader"},
   {0x2082, "twoinferior"},
-  {0x0032, "twooldstyle"},
+  {0xf732, "twooldstyle"},
   {0x00b2, "twosuperior"},
   {0x2154, "twothirds"},
   {0x0075, "u"},
@@ -1086,7 +1086,7 @@ static struct {
   {0x017c, "zdotaccent"},
   {0x0030, "zero"},
   {0x2080, "zeroinferior"},
-  {0x0030, "zerooldstyle"},
+  {0xf730, "zerooldstyle"},
   {0x2070, "zerosuperior"},
   {0x03b6, "zeta"},
   {0x007b, "{"},
diff --git a/pdf2swf/xpdf/Object.cc b/pdf2swf/xpdf/Object.cc
index ddd6da6..71c632a 100644
--- a/pdf2swf/xpdf/Object.cc
+++ b/pdf2swf/xpdf/Object.cc
@@ -161,7 +161,7 @@ void Object::print(FILE *f) {
     break;
   case objString:
     fprintf(f, "(");
-    fwrite(string->getCString(), 1, string->getLength(), stdout);
+    fwrite(string->getCString(), 1, string->getLength(), f);
     fprintf(f, ")");
     break;
   case objName:
diff --git a/pdf2swf/xpdf/Outline.cc b/pdf2swf/xpdf/Outline.cc
index 04891f3..39e89a3 100644
--- a/pdf2swf/xpdf/Outline.cc
+++ b/pdf2swf/xpdf/Outline.cc
@@ -58,14 +58,14 @@ OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) {
     if ((s->getChar(0) & 0xff) == 0xfe &&
 	(s->getChar(1) & 0xff) == 0xff) {
       titleLen = (s->getLength() - 2) / 2;
-      title = (Unicode *)gmalloc(titleLen * sizeof(Unicode));
+      title = (Unicode *)gmallocn(titleLen, sizeof(Unicode));
       for (i = 0; i < titleLen; ++i) {
 	title[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) |
 	           (s->getChar(3 + 2*i) & 0xff);
       }
     } else {
       titleLen = s->getLength();
-      title = (Unicode *)gmalloc(titleLen * sizeof(Unicode));
+      title = (Unicode *)gmallocn(titleLen, sizeof(Unicode));
       for (i = 0; i < titleLen; ++i) {
 	title[i] = pdfDocEncoding[s->getChar(i) & 0xff];
       }
@@ -79,7 +79,7 @@ OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) {
     action = LinkAction::parseDest(&obj1);
   } else {
     obj1.free();
-    if (dict->lookup("A", &obj1)) {
+    if (!dict->lookup("A", &obj1)->isNull()) {
       action = LinkAction::parseAction(&obj1);
     }
   }
diff --git a/pdf2swf/xpdf/OutputDev.cc b/pdf2swf/xpdf/OutputDev.cc
index e83882d..cfa4161 100644
--- a/pdf2swf/xpdf/OutputDev.cc
+++ b/pdf2swf/xpdf/OutputDev.cc
@@ -55,8 +55,15 @@ void OutputDev::updateAll(GfxState *state) {
   updateLineCap(state);
   updateMiterLimit(state);
   updateLineWidth(state);
+  updateFillColorSpace(state);
   updateFillColor(state);
+  updateStrokeColorSpace(state);
   updateStrokeColor(state);
+  updateBlendMode(state);
+  updateFillOpacity(state);
+  updateStrokeOpacity(state);
+  updateFillOverprint(state);
+  updateStrokeOverprint(state);
   updateFont(state);
 }
 
@@ -95,6 +102,24 @@ void OutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   }
 }
 
+void OutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+				int width, int height,
+				GfxImageColorMap *colorMap,
+				Stream *maskStr,
+				int maskWidth, int maskHeight,
+				GBool maskInvert) {
+  drawImage(state, ref, str, width, height, colorMap, NULL, gFalse);
+}
+
+void OutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+				    int width, int height,
+				    GfxImageColorMap *colorMap,
+				    Stream *maskStr,
+				    int maskWidth, int maskHeight,
+				    GfxImageColorMap *maskColorMap) {
+  drawImage(state, ref, str, width, height, colorMap, NULL, gFalse);
+}
+
 #if OPI_SUPPORT
 void OutputDev::opiBegin(GfxState *state, Dict *opiDict) {
 }
diff --git a/pdf2swf/xpdf/PDFDoc.cc b/pdf2swf/xpdf/PDFDoc.cc
index b5981d9..92863e4 100644
--- a/pdf2swf/xpdf/PDFDoc.cc
+++ b/pdf2swf/xpdf/PDFDoc.cc
@@ -16,6 +16,9 @@
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
+#ifdef WIN32
+#  include <windows.h>
+#endif
 #include "GString.h"
 #include "config.h"
 #include "GlobalParams.h"
@@ -29,6 +32,7 @@
 #include "ErrorCodes.h"
 #include "Lexer.h"
 #include "Parser.h"
+#include "SecurityHandler.h"
 #ifndef DISABLE_OUTLINE
 #include "Outline.h"
 #endif
@@ -44,13 +48,15 @@
 //------------------------------------------------------------------------
 
 PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword,
-	       GString *userPassword) {
+	       GString *userPassword, void *guiDataA) {
   Object obj;
   GString *fileName1, *fileName2;
 
   ok = gFalse;
   errCode = errNone;
 
+  guiData = guiDataA;
+
   file = NULL;
   str = NULL;
   xref = NULL;
@@ -96,10 +102,68 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword,
   ok = setup(ownerPassword, userPassword);
 }
 
+#ifdef WIN32
+PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword,
+	       GString *userPassword, void *guiDataA) {
+  OSVERSIONINFO version;
+  wchar_t fileName2[_MAX_PATH + 1];
+  Object obj;
+  int i;
+
+  ok = gFalse;
+  errCode = errNone;
+
+  guiData = guiDataA;
+
+  file = NULL;
+  str = NULL;
+  xref = NULL;
+  catalog = NULL;
+  links = NULL;
+#ifndef DISABLE_OUTLINE
+  outline = NULL;
+#endif
+
+  //~ file name should be stored in Unicode (?)
+  fileName = new GString();
+  for (i = 0; i < fileNameLen; ++i) {
+    fileName->append((char)fileNameA[i]);
+  }
+
+  // zero-terminate the file name string
+  for (i = 0; i < fileNameLen && i < _MAX_PATH; ++i) {
+    fileName2[i] = fileNameA[i];
+  }
+  fileName2[i] = 0;
+
+  // try to open file
+  // NB: _wfopen is only available in NT
+  version.dwOSVersionInfoSize = sizeof(version);
+  GetVersionEx(&version);
+  if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+    file = _wfopen(fileName2, L"rb");
+  } else {
+    file = fopen(fileName->getCString(), "rb");
+  }
+  if (!file) {
+    error(-1, "Couldn't open file '%s'", fileName->getCString());
+    errCode = errOpenFile;
+    return;
+  }
+
+  // create stream
+  obj.initNull();
+  str = new FileStream(file, 0, gFalse, 0, &obj);
+
+  ok = setup(ownerPassword, userPassword);
+}
+#endif
+
 PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword,
-	       GString *userPassword) {
+	       GString *userPassword, void *guiDataA) {
   ok = gFalse;
   errCode = errNone;
+  guiData = guiDataA;
   fileName = NULL;
   file = NULL;
   str = strA;
@@ -119,13 +183,19 @@ GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) {
   checkHeader();
 
   // read xref table
-  xref = new XRef(str, ownerPassword, userPassword);
+  xref = new XRef(str);
   if (!xref->isOk()) {
     error(-1, "Couldn't read xref table");
     errCode = xref->getErrorCode();
     return gFalse;
   }
 
+  // check for encryption
+  if (!checkEncryption(ownerPassword, userPassword)) {
+    errCode = errEncrypted;
+    return gFalse;
+  }
+
   // read catalog
   catalog = new Catalog(xref);
   if (!catalog->isOk()) {
@@ -191,7 +261,10 @@ void PDFDoc::checkHeader() {
     return;
   }
   str->moveStart(i);
-  p = strtok(&hdrBuf[i+5], " \t\n\r");
+  if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) {
+    error(-1, "May not be a PDF file (continuing anyway)");
+    return;
+  }
   pdfVersion = atof(p);
   if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') ||
       pdfVersion > supportedPDFVersionNum + 0.0001) {
@@ -200,8 +273,43 @@ void PDFDoc::checkHeader() {
   }
 }
 
+GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) {
+  Object encrypt;
+  GBool encrypted;
+  SecurityHandler *secHdlr;
+  GBool ret;
+
+  xref->getTrailerDict()->dictLookup("Encrypt", &encrypt);
+  if ((encrypted = encrypt.isDict())) {
+    if ((secHdlr = SecurityHandler::make(this, &encrypt))) {
+      if (secHdlr->checkEncryption(ownerPassword, userPassword)) {
+	// authorization succeeded
+       	xref->setEncryption(secHdlr->getPermissionFlags(),
+			    secHdlr->getOwnerPasswordOk(),
+			    secHdlr->getFileKey(),
+			    secHdlr->getFileKeyLength(),
+			    secHdlr->getEncVersion());
+	ret = gTrue;
+      } else {
+	// authorization failed
+	ret = gFalse;
+      }
+      delete secHdlr;
+    } else {
+      // couldn't find the matching security handler
+      ret = gFalse;
+    }
+  } else {
+    // document is not encrypted
+    ret = gTrue;
+  }
+  encrypt.free();
+  return ret;
+}
+
 void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI,
-			 int rotate, GBool crop, GBool doLinks,
+			 int rotate, GBool useMediaBox, GBool crop,
+			 GBool doLinks,
 			 GBool (*abortCheckCbk)(void *data),
 			 void *abortCheckCbkData) {
   Page *p;
@@ -215,39 +323,57 @@ void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI,
       delete links;
     }
     getLinks(p);
-    p->display(out, hDPI, vDPI, rotate, crop, links, catalog,
+    p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, links, catalog,
 	       abortCheckCbk, abortCheckCbkData);
   } else {
-    p->display(out, hDPI, vDPI, rotate, crop, NULL, catalog,
+    p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, NULL, catalog,
 	       abortCheckCbk, abortCheckCbkData);
   }
 }
 
 void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
 			  double hDPI, double vDPI, int rotate,
-			  GBool crop, GBool doLinks,
+			  GBool useMediaBox, GBool crop, GBool doLinks,
 			  GBool (*abortCheckCbk)(void *data),
 			  void *abortCheckCbkData) {
   int page;
 
   for (page = firstPage; page <= lastPage; ++page) {
-    displayPage(out, page, hDPI, vDPI, rotate, crop, doLinks,
+    displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, doLinks,
 		abortCheckCbk, abortCheckCbkData);
   }
 }
 
 void PDFDoc::displayPageSlice(OutputDev *out, int page,
-			      double hDPI, double vDPI,
-			      int rotate, GBool crop,
+			      double hDPI, double vDPI, int rotate,
+			      GBool useMediaBox, GBool crop, GBool doLinks,
 			      int sliceX, int sliceY, int sliceW, int sliceH,
 			      GBool (*abortCheckCbk)(void *data),
 			      void *abortCheckCbkData) {
   Page *p;
 
   p = catalog->getPage(page);
-  p->displaySlice(out, hDPI, vDPI, rotate, crop,
-		  sliceX, sliceY, sliceW, sliceH,
-		  NULL, catalog, abortCheckCbk, abortCheckCbkData);
+  if (doLinks) {
+    if (links) {
+      delete links;
+    }
+    getLinks(p);
+    p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
+		    sliceX, sliceY, sliceW, sliceH,
+		    links, catalog, abortCheckCbk, abortCheckCbkData);
+  } else {
+    p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
+		    sliceX, sliceY, sliceW, sliceH,
+		    NULL, catalog, abortCheckCbk, abortCheckCbkData);
+  }
+}
+
+Links *PDFDoc::takeLinks() {
+  Links *ret;
+
+  ret = links;
+  links = NULL;
+  return ret;
 }
 
 GBool PDFDoc::isLinearized() {
diff --git a/pdf2swf/xpdf/PDFDoc.h b/pdf2swf/xpdf/PDFDoc.h
index bdcbd65..a1f42c0 100644
--- a/pdf2swf/xpdf/PDFDoc.h
+++ b/pdf2swf/xpdf/PDFDoc.h
@@ -17,7 +17,6 @@
 
 #include <stdio.h>
 #include "XRef.h"
-#include "Link.h"
 #include "Catalog.h"
 #include "Page.h"
 
@@ -37,9 +36,13 @@ class PDFDoc {
 public:
 
   PDFDoc(GString *fileNameA, GString *ownerPassword = NULL,
-	 GString *userPassword = NULL);
+	 GString *userPassword = NULL, void *guiDataA = NULL);
+#ifdef WIN32
+  PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword = NULL,
+	 GString *userPassword = NULL, void *guiDataA = NULL);
+#endif
   PDFDoc(BaseStream *strA, GString *ownerPassword = NULL,
-	 GString *userPassword = NULL);
+	 GString *userPassword = NULL, void *guiDataA = NULL);
   ~PDFDoc();
 
   // Was PDF document successfully opened?
@@ -61,10 +64,14 @@ public:
   BaseStream *getBaseStream() { return str; }
 
   // Get page parameters.
-  double getPageWidth(int page)
-    { return catalog->getPage(page)->getWidth(); }
-  double getPageHeight(int page)
-    { return catalog->getPage(page)->getHeight(); }
+  double getPageMediaWidth(int page)
+    { return catalog->getPage(page)->getMediaWidth(); }
+  double getPageMediaHeight(int page)
+    { return catalog->getPage(page)->getMediaHeight(); }
+  double getPageCropWidth(int page)
+    { return catalog->getPage(page)->getCropWidth(); }
+  double getPageCropHeight(int page)
+    { return catalog->getPage(page)->getCropHeight(); }
   int getPageRotate(int page)
     { return catalog->getPage(page)->getRotate(); }
 
@@ -80,21 +87,22 @@ public:
 
   // Display a page.
   void displayPage(OutputDev *out, int page, double hDPI, double vDPI,
-		   int rotate, GBool crop, GBool doLinks,
+		   int rotate, GBool useMediaBox, GBool crop,
+		   GBool doLinks,
 		   GBool (*abortCheckCbk)(void *data) = NULL,
 		   void *abortCheckCbkData = NULL);
 
   // Display a range of pages.
   void displayPages(OutputDev *out, int firstPage, int lastPage,
 		    double hDPI, double vDPI, int rotate,
-		    GBool crop, GBool doLinks,
+		    GBool useMediaBox, GBool crop, GBool doLinks,
 		    GBool (*abortCheckCbk)(void *data) = NULL,
 		    void *abortCheckCbkData = NULL);
 
   // Display part of a page.
   void displayPageSlice(OutputDev *out, int page,
-			double hDPI, double vDPI,
-			int rotate, GBool crop,
+			double hDPI, double vDPI, int rotate,
+			GBool useMediaBox, GBool crop, GBool doLinks,
 			int sliceX, int sliceY, int sliceW, int sliceH,
 			GBool (*abortCheckCbk)(void *data) = NULL,
 			void *abortCheckCbkData = NULL);
@@ -103,13 +111,9 @@ public:
   // 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(double x, double y)
-    { return links ? links->find(x, y) : (LinkAction *)NULL; }
-
-  // Return true if <x>,<y> is in a link.
-  GBool onLink(double x, double y) { return links->onLink(x, y); }
+  // Returns the links for the current page, transferring ownership to
+  // the caller.
+  Links *takeLinks();
 
   // Find a named destination.  Returns the link destination, or
   // NULL if <name> is not a destination.
@@ -147,16 +151,21 @@ public:
   // Save this file with another name.
   GBool saveAs(GString *name);
 
+  // Return a pointer to the GUI (XPDFCore or WinPDFCore object).
+  void *getGUIData() { return guiData; }
+
 
 private:
 
   GBool setup(GString *ownerPassword, GString *userPassword);
   void checkHeader();
+  GBool checkEncryption(GString *ownerPassword, GString *userPassword);
   void getLinks(Page *page);
 
   GString *fileName;
   FILE *file;
   BaseStream *str;
+  void *guiData;
   double pdfVersion;
   XRef *xref;
   Catalog *catalog;
diff --git a/pdf2swf/xpdf/Page.h b/pdf2swf/xpdf/Page.h
index 2376cb4..36f96e1 100644
--- a/pdf2swf/xpdf/Page.h
+++ b/pdf2swf/xpdf/Page.h
@@ -51,7 +51,6 @@ public:
   ~PageAttrs();
 
   // Accessors.
-  PDFRectangle *getBox() { return limitToCropBox ? &cropBox : &mediaBox; }
   PDFRectangle *getMediaBox() { return &mediaBox; }
   PDFRectangle *getCropBox() { return &cropBox; }
   GBool isCropped() { return haveCropBox; }
@@ -83,7 +82,6 @@ private:
   PDFRectangle mediaBox;
   PDFRectangle cropBox;
   GBool haveCropBox;
-  GBool limitToCropBox;
   PDFRectangle bleedBox;
   PDFRectangle trimBox;
   PDFRectangle artBox;
@@ -114,12 +112,17 @@ public:
   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(); }
-  double getWidth() { return attrs->getBox()->x2 - attrs->getBox()->x1; }
-  double getHeight() { return attrs->getBox()->y2 - attrs->getBox()->y1; }
+  double getMediaWidth() 
+    { return attrs->getMediaBox()->x2 - attrs->getMediaBox()->x1; }
+  double getMediaHeight()
+    { return attrs->getMediaBox()->y2 - attrs->getMediaBox()->y1; }
+  double getCropWidth() 
+    { return attrs->getCropBox()->x2 - attrs->getCropBox()->x1; }
+  double getCropHeight()
+    { return attrs->getCropBox()->y2 - attrs->getCropBox()->y1; }
   PDFRectangle *getBleedBox() { return attrs->getBleedBox(); }
   PDFRectangle *getTrimBox() { return attrs->getTrimBox(); }
   PDFRectangle *getArtBox() { return attrs->getArtBox(); }
@@ -142,19 +145,23 @@ public:
 
   // Display a page.
   void display(OutputDev *out, double hDPI, double vDPI,
-	       int rotate, GBool crop,
+	       int rotate, GBool useMediaBox, GBool crop,
 	       Links *links, Catalog *catalog,
 	       GBool (*abortCheckCbk)(void *data) = NULL,
 	       void *abortCheckCbkData = NULL);
 
   // Display part of a page.
   void displaySlice(OutputDev *out, double hDPI, double vDPI,
-		    int rotate, GBool crop,
+		    int rotate, GBool useMediaBox, GBool crop,
 		    int sliceX, int sliceY, int sliceW, int sliceH,
 		    Links *links, Catalog *catalog,
 		    GBool (*abortCheckCbk)(void *data) = NULL,
 		    void *abortCheckCbkData = NULL);
 
+  // Get the page's default CTM.
+  void getDefaultCTM(double *ctm, double hDPI, double vDPI,
+		     int rotate, GBool upsideDown);
+
 private:
 
   XRef *xref;			// the xref table for this PDF file
diff --git a/pdf2swf/xpdf/Parser.cc b/pdf2swf/xpdf/Parser.cc
index 0aa66d3..af7c933 100644
--- a/pdf2swf/xpdf/Parser.cc
+++ b/pdf2swf/xpdf/Parser.cc
@@ -19,9 +19,7 @@
 #include "Parser.h"
 #include "XRef.h"
 #include "Error.h"
-#ifndef NO_DECRYPTION
 #include "Decrypt.h"
-#endif
 
 Parser::Parser(XRef *xrefA, Lexer *lexerA) {
   xref = xrefA;
@@ -37,23 +35,17 @@ Parser::~Parser() {
   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) {
@@ -69,11 +61,7 @@ Object *Parser::getObj(Object *obj) {
     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();
@@ -93,11 +81,7 @@ Object *Parser::getObj(Object *obj) {
 	  gfree(key);
 	  break;
 	}
-#ifndef NO_DECRYPTION
 	obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen));
-#else
-	obj->dictAdd(key, getObj(&obj2));
-#endif
       }
     }
     if (buf1.isEOF())
@@ -105,12 +89,10 @@ Object *Parser::getObj(Object *obj) {
     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();
@@ -131,7 +113,6 @@ Object *Parser::getObj(Object *obj) {
       obj->initInt(num);
     }
 
-#ifndef NO_DECRYPTION
   // string
   } else if (buf1.isString() && fileKey) {
     buf1.copy(obj);
@@ -144,7 +125,6 @@ Object *Parser::getObj(Object *obj) {
     }
     delete decrypt;
     shift();
-#endif
 
   // simple object
   } else {
@@ -157,6 +137,7 @@ Object *Parser::getObj(Object *obj) {
 
 Stream *Parser::makeStream(Object *dict) {
   Object obj;
+  BaseStream *baseStr;
   Stream *str;
   Guint pos, endPos, length;
 
@@ -185,13 +166,7 @@ Stream *Parser::makeStream(Object *dict) {
   if (!lexer->getStream()) {
     return NULL;
   }
-
-  // make base stream
-  str = lexer->getStream()->getBaseStream()->makeSubStream(pos, gTrue,
-							   length, dict);
-
-  // get filters
-  str = str->addFilters(dict);
+  baseStr = lexer->getStream()->getBaseStream();
 
   // skip over stream data
   lexer->setPos(pos + length);
@@ -203,9 +178,17 @@ Stream *Parser::makeStream(Object *dict) {
     shift();
   } else {
     error(getPos(), "Missing 'endstream'");
-    str->ignoreLength();
+    // kludge for broken PDF files: just add 5k to the length, and
+    // hope its enough
+    length += 5000;
   }
 
+  // make base stream
+  str = baseStr->makeSubStream(pos, gTrue, length, dict);
+
+  // get filters
+  str = str->addFilters(dict);
+
   return str;
 }
 
diff --git a/pdf2swf/xpdf/Parser.h b/pdf2swf/xpdf/Parser.h
index 3bc3ab2..b583baf 100644
--- a/pdf2swf/xpdf/Parser.h
+++ b/pdf2swf/xpdf/Parser.h
@@ -31,13 +31,9 @@ public:
   ~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(); }
diff --git a/pdf2swf/xpdf/SecurityHandler.cc b/pdf2swf/xpdf/SecurityHandler.cc
new file mode 100644
index 0000000..8825ce8
--- /dev/null
+++ b/pdf2swf/xpdf/SecurityHandler.cc
@@ -0,0 +1,376 @@
+//========================================================================
+//
+// SecurityHandler.cc
+//
+// Copyright 2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "GString.h"
+#include "PDFDoc.h"
+#include "Decrypt.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#if HAVE_XPDFCORE
+#  include "XPDFCore.h"
+#elif HAVE_WINPDFCORE
+#  include "WinPDFCore.h"
+#endif
+#ifdef ENABLE_PLUGINS
+#  include "XpdfPluginAPI.h"
+#endif
+#include "SecurityHandler.h"
+
+//------------------------------------------------------------------------
+// SecurityHandler
+//------------------------------------------------------------------------
+
+SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) {
+  Object filterObj;
+  SecurityHandler *secHdlr;
+  XpdfSecurityHandler *xsh;
+
+  encryptDictA->dictLookup("Filter", &filterObj);
+  if (filterObj.isName("Standard")) {
+    secHdlr = new StandardSecurityHandler(docA, encryptDictA);
+  } else if (filterObj.isName()) {
+#ifdef ENABLE_PLUGINS
+    if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) {
+      secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh);
+    } else {
+#endif
+      error(-1, "Couldn't find the '%s' security handler",
+	    filterObj.getName());
+      secHdlr = NULL;
+#ifdef ENABLE_PLUGINS
+    }
+#endif
+  } else {
+    error(-1, "Missing or invalid 'Filter' entry in encryption dictionary");
+    secHdlr = NULL;
+  }
+  filterObj.free();
+  return secHdlr;
+}
+
+SecurityHandler::SecurityHandler(PDFDoc *docA) {
+  doc = docA;
+}
+
+SecurityHandler::~SecurityHandler() {
+}
+
+GBool SecurityHandler::checkEncryption(GString *ownerPassword,
+				       GString *userPassword) {
+  void *authData;
+  GBool ok;
+  int i;
+
+  if (ownerPassword || userPassword) {
+    authData = makeAuthData(ownerPassword, userPassword);
+  } else {
+    authData = NULL;
+  }
+  ok = authorize(authData);
+  if (authData) {
+    freeAuthData(authData);
+  }
+  for (i = 0; !ok && i < 3; ++i) {
+    if (!(authData = getAuthData())) {
+      break;
+    }
+    ok = authorize(authData);
+    if (authData) {
+      freeAuthData(authData);
+    }
+  }
+  if (!ok) {
+    error(-1, "Incorrect password");
+  }
+  return ok;
+}
+
+//------------------------------------------------------------------------
+// StandardSecurityHandler
+//------------------------------------------------------------------------
+
+class StandardAuthData {
+public:
+
+  StandardAuthData(GString *ownerPasswordA, GString *userPasswordA) {
+    ownerPassword = ownerPasswordA;
+    userPassword = userPasswordA;
+  }
+
+  ~StandardAuthData() {
+    if (ownerPassword) {
+      delete ownerPassword;
+    }
+    if (userPassword) {
+      delete userPassword;
+    }
+  }
+
+  GString *ownerPassword;
+  GString *userPassword;
+};
+
+StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
+						 Object *encryptDictA):
+  SecurityHandler(docA)
+{
+  Object versionObj, revisionObj, lengthObj;
+  Object ownerKeyObj, userKeyObj, permObj, fileIDObj;
+  Object fileIDObj1;
+  Object cryptFiltersObj, streamFilterObj, stringFilterObj;
+  Object cryptFilterObj, cfmObj, cfLengthObj;
+  Object encryptMetadataObj;
+
+  ok = gFalse;
+  fileID = NULL;
+  ownerKey = NULL;
+  userKey = NULL;
+
+  encryptDictA->dictLookup("V", &versionObj);
+  encryptDictA->dictLookup("R", &revisionObj);
+  encryptDictA->dictLookup("Length", &lengthObj);
+  encryptDictA->dictLookup("O", &ownerKeyObj);
+  encryptDictA->dictLookup("U", &userKeyObj);
+  encryptDictA->dictLookup("P", &permObj);
+  doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj);
+  if (versionObj.isInt() &&
+      revisionObj.isInt() &&
+      ownerKeyObj.isString() && ownerKeyObj.getString()->getLength() == 32 &&
+      userKeyObj.isString() && userKeyObj.getString()->getLength() == 32 &&
+      permObj.isInt()) {
+    encVersion = versionObj.getInt();
+    encRevision = revisionObj.getInt();
+    // revision 2 forces a 40-bit key - some buggy PDF generators
+    // set the Length value incorrectly
+    if (encRevision == 2 || !lengthObj.isInt()) {
+      fileKeyLength = 5;
+    } else {
+      fileKeyLength = lengthObj.getInt() / 8;
+    }
+    encryptMetadata = gTrue;
+    //~ this currently only handles a subset of crypt filter functionality
+    if (encVersion == 4 && encRevision == 4) {
+      encryptDictA->dictLookup("CF", &cryptFiltersObj);
+      encryptDictA->dictLookup("StmF", &streamFilterObj);
+      encryptDictA->dictLookup("StrF", &stringFilterObj);
+      if (cryptFiltersObj.isDict() &&
+	  streamFilterObj.isName() &&
+	  stringFilterObj.isName() &&
+	  !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) {
+	if (cryptFiltersObj.dictLookup(streamFilterObj.getName(),
+				       &cryptFilterObj)->isDict()) {
+	  if (cryptFilterObj.dictLookup("CFM", &cfmObj)->isName("V2")) {
+	    encVersion = 2;
+	    encRevision = 3;
+	    if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) {
+	      //~ according to the spec, this should be cfLengthObj / 8
+	      fileKeyLength = cfLengthObj.getInt();
+	    }
+	    cfLengthObj.free();
+	  }
+	  cfmObj.free();
+	}
+	cryptFilterObj.free();
+      }
+      stringFilterObj.free();
+      streamFilterObj.free();
+      cryptFiltersObj.free();
+      if (encryptDictA->dictLookup("EncryptMetadata",
+				   &encryptMetadataObj)->isBool()) {
+	encryptMetadata = encryptMetadataObj.getBool();
+      }
+      encryptMetadataObj.free();
+    }
+    permFlags = permObj.getInt();
+    ownerKey = ownerKeyObj.getString()->copy();
+    userKey = userKeyObj.getString()->copy();
+    if (encVersion >= 1 && encVersion <= 2 &&
+	encRevision >= 2 && encRevision <= 3) {
+      if (fileIDObj.isArray()) {
+	if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) {
+	  fileID = fileIDObj1.getString()->copy();
+	} else {
+	  fileID = new GString();
+	}
+	fileIDObj1.free();
+      } else {
+	fileID = new GString();
+      }
+      ok = gTrue;
+    } else {
+      error(-1, "Unsupported version/revision (%d/%d) of Standard security handler",
+	    encVersion, encRevision);
+    }
+  } else {
+    error(-1, "Weird encryption info");
+  }
+  if (fileKeyLength > 16) {
+    fileKeyLength = 16;
+  }
+  fileIDObj.free();
+  permObj.free();
+  userKeyObj.free();
+  ownerKeyObj.free();
+  lengthObj.free();
+  revisionObj.free();
+  versionObj.free();
+}
+
+StandardSecurityHandler::~StandardSecurityHandler() {
+  if (fileID) {
+    delete fileID;
+  }
+  if (ownerKey) {
+    delete ownerKey;
+  }
+  if (userKey) {
+    delete userKey;
+  }
+}
+
+void *StandardSecurityHandler::makeAuthData(GString *ownerPassword,
+					    GString *userPassword) {
+  return new StandardAuthData(ownerPassword ? ownerPassword->copy()
+			                    : (GString *)NULL,
+			      userPassword ? userPassword->copy()
+			                   : (GString *)NULL);
+}
+
+void *StandardSecurityHandler::getAuthData() {
+#if HAVE_XPDFCORE
+  XPDFCore *core;
+  GString *password;
+
+  if (!(core = (XPDFCore *)doc->getGUIData()) ||
+      !(password = core->getPassword())) {
+    return NULL;
+  }
+  return new StandardAuthData(password, password->copy());
+#elif HAVE_WINPDFCORE
+  WinPDFCore *core;
+  GString *password;
+
+  if (!(core = (WinPDFCore *)doc->getGUIData()) ||
+      !(password = core->getPassword())) {
+    return NULL;
+  }
+  return new StandardAuthData(password, password->copy());
+#else
+  return NULL;
+#endif
+}
+
+void StandardSecurityHandler::freeAuthData(void *authData) {
+  delete (StandardAuthData *)authData;
+}
+
+GBool StandardSecurityHandler::authorize(void *authData) {
+  GString *ownerPassword, *userPassword;
+
+  if (!ok) {
+    return gFalse;
+  }
+  if (authData) {
+    ownerPassword = ((StandardAuthData *)authData)->ownerPassword;
+    userPassword = ((StandardAuthData *)authData)->userPassword;
+  } else {
+    ownerPassword = NULL;
+    userPassword = NULL;
+  }
+  if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength,
+			    ownerKey, userKey, permFlags, fileID,
+			    ownerPassword, userPassword, fileKey,
+			    encryptMetadata, &ownerPasswordOk)) {
+    return gFalse;
+  }
+  return gTrue;
+}
+
+#ifdef ENABLE_PLUGINS
+
+//------------------------------------------------------------------------
+// ExternalSecurityHandler
+//------------------------------------------------------------------------
+
+ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA,
+						 Object *encryptDictA,
+						 XpdfSecurityHandler *xshA):
+  SecurityHandler(docA)
+{
+  encryptDictA->copy(&encryptDict);
+  xsh = xshA;
+  ok = gFalse;
+
+  if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA,
+		      (XpdfObject)encryptDictA, &docData)) {
+    return;
+  }
+
+  ok = gTrue;
+}
+
+ExternalSecurityHandler::~ExternalSecurityHandler() {
+  (*xsh->freeDoc)(xsh->handlerData, docData);
+  encryptDict.free();
+}
+
+void *ExternalSecurityHandler::makeAuthData(GString *ownerPassword,
+					    GString *userPassword) {
+  char *opw, *upw;
+  void *authData;
+
+  opw = ownerPassword ? ownerPassword->getCString() : (char *)NULL;
+  upw = userPassword ? userPassword->getCString() : (char *)NULL;
+  if (!(*xsh->makeAuthData)(xsh->handlerData, docData, opw, upw, &authData)) {
+    return NULL;
+  }
+  return authData;
+}
+
+void *ExternalSecurityHandler::getAuthData() {
+  void *authData;
+
+  if (!(*xsh->getAuthData)(xsh->handlerData, docData, &authData)) {
+    return NULL;
+  }
+  return authData;
+}
+
+void ExternalSecurityHandler::freeAuthData(void *authData) {
+  (*xsh->freeAuthData)(xsh->handlerData, docData, authData);
+}
+
+GBool ExternalSecurityHandler::authorize(void *authData) {
+  char *key;
+  int length;
+
+  if (!ok) {
+    return gFalse;
+  }
+  permFlags = (*xsh->authorize)(xsh->handlerData, docData, authData);
+  if (!(permFlags & xpdfPermissionOpen)) {
+    return gFalse;
+  }
+  if (!(*xsh->getKey)(xsh->handlerData, docData, &key, &length, &encVersion)) {
+    return gFalse;
+  }
+  if ((fileKeyLength = length) > 16) {
+    fileKeyLength = 16;
+  }
+  memcpy(fileKey, key, fileKeyLength);
+  (*xsh->freeKey)(xsh->handlerData, docData, key, length);
+  return gTrue;
+}
+
+#endif // ENABLE_PLUGINS
diff --git a/pdf2swf/xpdf/SecurityHandler.h b/pdf2swf/xpdf/SecurityHandler.h
new file mode 100644
index 0000000..127acb7
--- /dev/null
+++ b/pdf2swf/xpdf/SecurityHandler.h
@@ -0,0 +1,155 @@
+//========================================================================
+//
+// SecurityHandler.h
+//
+// Copyright 2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef SECURITYHANDLER_H
+#define SECURITYHANDLER_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "Object.h"
+
+class GString;
+class PDFDoc;
+struct XpdfSecurityHandler;
+
+//------------------------------------------------------------------------
+// SecurityHandler
+//------------------------------------------------------------------------
+
+class SecurityHandler {
+public:
+
+  static SecurityHandler *make(PDFDoc *docA, Object *encryptDictA);
+
+  SecurityHandler(PDFDoc *docA);
+  virtual ~SecurityHandler();
+
+  // Check the document's encryption.  If the document is encrypted,
+  // this will first try <ownerPassword> and <userPassword> (in
+  // "batch" mode), and if those fail, it will attempt to request a
+  // password from the user.  This is the high-level function that
+  // calls the lower level functions for the specific security handler
+  // (requesting a password three times, etc.).  Returns true if the
+  // document can be opened (if it's unencrypted, or if a correct
+  // password is obtained); false otherwise (encrypted and no correct
+  // password).
+  GBool checkEncryption(GString *ownerPassword,
+			GString *userPassword);
+
+  // Create authorization data for the specified owner and user
+  // passwords.  If the security handler doesn't support "batch" mode,
+  // this function should return NULL.
+  virtual void *makeAuthData(GString *ownerPassword,
+			     GString *userPassword) = 0;
+
+  // Construct authorization data, typically by prompting the user for
+  // a password.  Returns an authorization data object, or NULL to
+  // cancel.
+  virtual void *getAuthData() = 0;
+
+  // Free the authorization data returned by makeAuthData or
+  // getAuthData.
+  virtual void freeAuthData(void *authData) = 0;
+
+  // Attempt to authorize the document, using the supplied
+  // authorization data (which may be NULL).  Returns true if
+  // successful (i.e., if at least the right to open the document was
+  // granted).
+  virtual GBool authorize(void *authData) = 0;
+
+  // Return the various authorization parameters.  These are only
+  // valid after authorize has returned true.
+  virtual int getPermissionFlags() = 0;
+  virtual GBool getOwnerPasswordOk() = 0;
+  virtual Guchar *getFileKey() = 0;
+  virtual int getFileKeyLength() = 0;
+  virtual int getEncVersion() = 0;
+
+protected:
+
+  PDFDoc *doc;
+};
+
+//------------------------------------------------------------------------
+// StandardSecurityHandler
+//------------------------------------------------------------------------
+
+class StandardSecurityHandler: public SecurityHandler {
+public:
+
+  StandardSecurityHandler(PDFDoc *docA, Object *encryptDictA);
+  virtual ~StandardSecurityHandler();
+
+  virtual void *makeAuthData(GString *ownerPassword,
+			     GString *userPassword);
+  virtual void *getAuthData();
+  virtual void freeAuthData(void *authData);
+  virtual GBool authorize(void *authData);
+  virtual int getPermissionFlags() { return permFlags; }
+  virtual GBool getOwnerPasswordOk() { return ownerPasswordOk; }
+  virtual Guchar *getFileKey() { return fileKey; }
+  virtual int getFileKeyLength() { return fileKeyLength; }
+  virtual int getEncVersion() { return encVersion; }
+
+private:
+
+  int permFlags;
+  GBool ownerPasswordOk;
+  Guchar fileKey[16];
+  int fileKeyLength;
+  int encVersion;
+  int encRevision;
+  GBool encryptMetadata;
+
+  GString *ownerKey, *userKey;
+  GString *fileID;
+  GBool ok;
+};
+
+#ifdef ENABLE_PLUGINS
+//------------------------------------------------------------------------
+// ExternalSecurityHandler
+//------------------------------------------------------------------------
+
+class ExternalSecurityHandler: public SecurityHandler {
+public:
+
+  ExternalSecurityHandler(PDFDoc *docA, Object *encryptDictA,
+			  XpdfSecurityHandler *xshA);
+  virtual ~ExternalSecurityHandler();
+
+  virtual void *makeAuthData(GString *ownerPassword,
+			     GString *userPassword);
+  virtual void *getAuthData();
+  virtual void freeAuthData(void *authData);
+  virtual GBool authorize(void *authData);
+  virtual int getPermissionFlags() { return permFlags; }
+  virtual GBool getOwnerPasswordOk() { return gFalse; }
+  virtual Guchar *getFileKey() { return fileKey; }
+  virtual int getFileKeyLength() { return fileKeyLength; }
+  virtual int getEncVersion() { return encVersion; }
+
+private:
+
+  Object encryptDict;
+  XpdfSecurityHandler *xsh;
+  void *docData;
+  int permFlags;
+  Guchar fileKey[16];
+  int fileKeyLength;
+  int encVersion;
+  GBool ok;
+};
+#endif // ENABLE_PLUGINS
+
+#endif
diff --git a/pdf2swf/xpdf/Stream.h b/pdf2swf/xpdf/Stream.h
index 0b70afa..e1e7bae 100644
--- a/pdf2swf/xpdf/Stream.h
+++ b/pdf2swf/xpdf/Stream.h
@@ -19,9 +19,7 @@
 #include "gtypes.h"
 #include "Object.h"
 
-#ifndef NO_DECRYPTION
 class Decrypt;
-#endif
 class BaseStream;
 
 //------------------------------------------------------------------------
@@ -40,6 +38,13 @@ enum StreamKind {
   strWeird			// internal-use stream types
 };
 
+enum StreamColorSpaceMode {
+  streamCSNone,
+  streamCSDeviceGray,
+  streamCSDeviceRGB,
+  streamCSDeviceCMYK
+};
+
 //------------------------------------------------------------------------
 // Stream (base class)
 //------------------------------------------------------------------------
@@ -102,15 +107,14 @@ public:
   // Is this an encoding filter?
   virtual GBool isEncoder() { return gFalse; }
 
+  // Get image parameters which are defined by the stream contents.
+  virtual void getImageParams(int *bitsPerComponent,
+			      StreamColorSpaceMode *csMode) {}
+
   // Add filters to this stream according to the parameters in <dict>.
   // Returns the new stream.
   Stream *addFilters(Object *dict);
 
-  // Tell this stream to ignore any length limitation -- this only
-  // applies to BaseStream subclasses, and is used as a hack to work
-  // around broken PDF files with incorrect stream lengths.
-  virtual void ignoreLength() {}
-
 private:
 
   Stream *makeFilter(char *name, Stream *str, Object *params);
@@ -140,17 +144,13 @@ public:
   virtual Guint getStart() = 0;
   virtual void moveStart(int delta) = 0;
 
-#ifndef NO_DECRYPTION
   // Set decryption for this stream.
   virtual void doDecryption(Guchar *fileKey, int keyLength,
 			    int objNum, int objGen);
-#endif
 
-#ifndef NO_DECRYPTION
 protected:
 
   Decrypt *decrypt;
-#endif
 
 private:
 
@@ -173,7 +173,6 @@ public:
   virtual void setPos(Guint pos, int dir = 0);
   virtual BaseStream *getBaseStream() { return str->getBaseStream(); }
   virtual Dict *getDict() { return str->getDict(); }
-  virtual void ignoreLength() { str->ignoreLength(); }
 
 protected:
 
@@ -233,6 +232,8 @@ public:
 
   ~StreamPredictor();
 
+  GBool isOk() { return ok; }
+
   int lookChar();
   int getChar();
 
@@ -250,6 +251,7 @@ private:
   int rowBytes;			// bytes per line
   Guchar *predLine;		// line buffer
   int predIdx;			// current index in predLine
+  GBool ok;
 };
 
 //------------------------------------------------------------------------
@@ -275,7 +277,6 @@ public:
     { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
   virtual int getPos() { return bufPos + (bufPtr - buf); }
   virtual void setPos(Guint pos, int dir = 0);
-  virtual void ignoreLength() { limited = gFalse; }
   virtual Guint getStart() { return start; }
   virtual void moveStart(int delta);
 
@@ -317,10 +318,8 @@ public:
   virtual void setPos(Guint pos, int dir = 0);
   virtual Guint getStart() { return start; }
   virtual void moveStart(int delta);
-#ifndef NO_DECRYPTION
   virtual void doDecryption(Guchar *fileKey, int keyLength,
 			    int objNum, int objGen);
-#endif
 
 private:
 
@@ -591,7 +590,7 @@ private:
   GBool gotJFIFMarker;		// set if APP0 JFIF marker was present
   GBool gotAdobeMarker;		// set if APP14 Adobe marker was present
   int restartInterval;		// restart interval, in MCUs
-  Guchar quantTables[4][64];	// quantization tables
+  Gushort quantTables[4][64];	// quantization tables
   int numQuantTables;		// number of quantization tables
   DCTHuffTable dcHuffTables[4];	// DC Huffman tables
   DCTHuffTable acHuffTables[4];	// AC Huffman tables
@@ -616,7 +615,7 @@ private:
 				DCTHuffTable *acHuffTable,
 				int *prevDC, int data[64]);
   void decodeImage();
-  void transformDataUnit(Guchar *quantTable,
+  void transformDataUnit(Gushort *quantTable,
 			 int dataIn[64], Guchar dataOut[64]);
   int readHuffSym(DCTHuffTable *table);
   int readAmp(int size);
@@ -700,6 +699,10 @@ private:
     lengthDecode[flateMaxLitCodes-257];
   static FlateDecode		// distance decoding info
     distDecode[flateMaxDistCodes];
+  static FlateHuffmanTab	// fixed literal code table
+    fixedLitCodeTab;
+  static FlateHuffmanTab	// fixed distance code table
+    fixedDistCodeTab;
 
   void readSome();
   GBool startBlock();
diff --git a/pdf2swf/xpdf/UnicodeMap.cc b/pdf2swf/xpdf/UnicodeMap.cc
index 300d802..2b8cb1f 100644
--- a/pdf2swf/xpdf/UnicodeMap.cc
+++ b/pdf2swf/xpdf/UnicodeMap.cc
@@ -53,7 +53,7 @@ UnicodeMap *UnicodeMap::parse(GString *encodingNameA) {
   map = new UnicodeMap(encodingNameA->copy());
 
   size = 8;
-  map->ranges = (UnicodeMapRange *)gmalloc(size * sizeof(UnicodeMapRange));
+  map->ranges = (UnicodeMapRange *)gmallocn(size, sizeof(UnicodeMapRange));
   eMapsSize = 0;
 
   line = 1;
@@ -69,7 +69,7 @@ UnicodeMap *UnicodeMap::parse(GString *encodingNameA) {
 	if (map->len == size) {
 	  size *= 2;
 	  map->ranges = (UnicodeMapRange *)
-	    grealloc(map->ranges, size * sizeof(UnicodeMapRange));
+	    greallocn(map->ranges, size, sizeof(UnicodeMapRange));
 	}
 	range = &map->ranges[map->len];
 	sscanf(tok1, "%x", &range->start);
@@ -81,7 +81,7 @@ UnicodeMap *UnicodeMap::parse(GString *encodingNameA) {
 	if (map->eMapsLen == eMapsSize) {
 	  eMapsSize += 16;
 	  map->eMaps = (UnicodeMapExt *)
-	    grealloc(map->eMaps, eMapsSize * sizeof(UnicodeMapExt));
+	    greallocn(map->eMaps, eMapsSize, sizeof(UnicodeMapExt));
 	}
 	eMap = &map->eMaps[map->eMapsLen];
 	sscanf(tok1, "%x", &eMap->u);
diff --git a/pdf2swf/xpdf/UnicodeMap.h b/pdf2swf/xpdf/UnicodeMap.h
index 6fd4ed2..0f86101 100644
--- a/pdf2swf/xpdf/UnicodeMap.h
+++ b/pdf2swf/xpdf/UnicodeMap.h
@@ -95,7 +95,7 @@ private:
   UnicodeMapExt *eMaps;		// (user)
   int eMapsLen;			// (user)
   int refCnt;
-#ifdef MULTITHREADED
+#if MULTITHREADED
   GMutex mutex;
 #endif
 };
diff --git a/pdf2swf/xpdf/XRef.cc b/pdf2swf/xpdf/XRef.cc
index e0d82d2..b371541 100644
--- a/pdf2swf/xpdf/XRef.cc
+++ b/pdf2swf/xpdf/XRef.cc
@@ -22,9 +22,6 @@
 #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"
@@ -34,7 +31,6 @@
 #define xrefSearchSize 1024	// read this many bytes at end of file
 				//   to look for 'startxref'
 
-#ifndef NO_DECRYPTION
 //------------------------------------------------------------------------
 // Permission bits
 //------------------------------------------------------------------------
@@ -44,7 +40,6 @@
 #define permCopy     (1<<4)
 #define permNotes    (1<<5)
 #define defPermFlags 0xfffc
-#endif
 
 //------------------------------------------------------------------------
 // ObjectStream
@@ -96,7 +91,7 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) {
   }
   nObjects = obj1.getInt();
   obj1.free();
-  if (nObjects == 0) {
+  if (nObjects <= 0) {
     goto err1;
   }
 
@@ -106,10 +101,13 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) {
   }
   first = obj1.getInt();
   obj1.free();
+  if (first < 0) {
+    goto err1;
+  }
 
   objs = new Object[nObjects];
-  objNums = (int *)gmalloc(nObjects * sizeof(int));
-  offsets = (int *)gmalloc(nObjects * sizeof(int));
+  objNums = (int *)gmallocn(nObjects, sizeof(int));
+  offsets = (int *)gmallocn(nObjects, sizeof(int));
 
   // parse the header: object numbers and offsets
   objStr.streamReset();
@@ -130,6 +128,12 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) {
     offsets[i] = obj2.getInt();
     obj1.free();
     obj2.free();
+    if (objNums[i] < 0 || offsets[i] < 0 ||
+	(i > 0 && offsets[i] < offsets[i-1])) {
+      delete parser;
+      gfree(offsets);
+      goto err1;
+    }
   }
   while (str->getChar() != EOF) ;
   delete parser;
@@ -186,7 +190,7 @@ Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) {
 // XRef
 //------------------------------------------------------------------------
 
-XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) {
+XRef::XRef(BaseStream *strA) {
   Guint pos;
   Object obj;
 
@@ -198,6 +202,10 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) {
   streamEndsLen = 0;
   objStr = NULL;
 
+  encrypted = gFalse;
+  permFlags = defPermFlags;
+  ownerPasswordOk = gFalse;
+
   // read the trailer
   str = strA;
   start = str->getStart();
@@ -242,16 +250,6 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) {
   // 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() {
@@ -369,11 +367,17 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos) {
     }
     n = obj.getInt();
     obj.free();
+    if (first < 0 || n < 0 || first + n < 0) {
+      goto err1;
+    }
     if (first + n > size) {
       for (newSize = size ? 2 * size : 1024;
-	   first + n > newSize;
+	   first + n > newSize && newSize > 0;
 	   newSize <<= 1) ;
-      entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry));
+      if (newSize < 0) {
+	goto err1;
+      }
+      entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
       for (i = size; i < newSize; ++i) {
 	entries[i].offset = 0xffffffff;
 	entries[i].type = xrefEntryFree;
@@ -443,9 +447,10 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos) {
 
   // check for an 'XRefStm' key
   if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) {
-    pos2 = obj2.getInt();
+    pos2 = (Guint)obj2.getInt();
     readXRef(&pos2);
     if (!ok) {
+      obj2.free();
       goto err1;
     }
   }
@@ -474,8 +479,11 @@ GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) {
   }
   newSize = obj.getInt();
   obj.free();
+  if (newSize < 0) {
+    goto err1;
+  }
   if (newSize > size) {
-    entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry));
+    entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
     for (i = size; i < newSize; ++i) {
       entries[i].offset = 0xffffffff;
       entries[i].type = xrefEntryFree;
@@ -494,6 +502,9 @@ GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) {
     }
     w[i] = obj2.getInt();
     obj2.free();
+    if (w[i] < 0 || w[i] > 4) {
+      goto err1;
+    }
   }
   obj.free();
 
@@ -513,13 +524,14 @@ GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) {
       }
       n = obj.getInt();
       obj.free();
-      if (!readXRefStreamSection(xrefStr, w, first, n)) {
+      if (first < 0 || n < 0 ||
+	  !readXRefStreamSection(xrefStr, w, first, n)) {
 	idx.free();
 	goto err0;
       }
     }
   } else {
-    if (!readXRefStreamSection(xrefStr, w, 0, size)) {
+    if (!readXRefStreamSection(xrefStr, w, 0, newSize)) {
       idx.free();
       goto err0;
     }
@@ -551,11 +563,17 @@ GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) {
   Guint offset;
   int type, gen, c, newSize, i, j;
 
+  if (first + n < 0) {
+    return gFalse;
+  }
   if (first + n > size) {
     for (newSize = size ? 2 * size : 1024;
-	 first + n > newSize;
+	 first + n > newSize && newSize > 0;
 	 newSize <<= 1) ;
-    entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry));
+    if (newSize < 0) {
+      return gFalse;
+    }
+    entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
     for (i = size; i < newSize; ++i) {
       entries[i].offset = 0xffffffff;
       entries[i].type = xrefEntryFree;
@@ -585,24 +603,26 @@ GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) {
       }
       gen = (gen << 8) + c;
     }
-    switch (type) {
-    case 0:
-      entries[i].offset = offset;
-      entries[i].gen = gen;
-      entries[i].type = xrefEntryFree;
-      break;
-    case 1:
-      entries[i].offset = offset;
-      entries[i].gen = gen;
-      entries[i].type = xrefEntryUncompressed;
-      break;
-    case 2:
-      entries[i].offset = offset;
-      entries[i].gen = gen;
-      entries[i].type = xrefEntryCompressed;
-      break;
-    default:
-      return gFalse;
+    if (entries[i].offset == 0xffffffff) {
+      switch (type) {
+      case 0:
+	entries[i].offset = offset;
+	entries[i].gen = gen;
+	entries[i].type = xrefEntryFree;
+	break;
+      case 1:
+	entries[i].offset = offset;
+	entries[i].gen = gen;
+	entries[i].type = xrefEntryUncompressed;
+	break;
+      case 2:
+	entries[i].offset = offset;
+	entries[i].gen = gen;
+	entries[i].type = xrefEntryCompressed;
+	break;
+      default:
+	return gFalse;
+      }
     }
   }
 
@@ -643,7 +663,7 @@ GBool XRef::constructXRef() {
       obj.initNull();
       parser = new Parser(NULL,
 		 new Lexer(NULL,
-		   str->makeSubStream(start + pos + 7, gFalse, 0, &obj)));
+		   str->makeSubStream(pos + 7, gFalse, 0, &obj)));
       parser->getObj(&newTrailerDict);
       if (newTrailerDict.isDict()) {
 	newTrailerDict.dictLookupNF("Root", &obj);
@@ -664,38 +684,44 @@ GBool XRef::constructXRef() {
     // look for object
     } else if (isdigit(*p)) {
       num = atoi(p);
-      do {
-	++p;
-      } while (*p && isdigit(*p));
-      if (isspace(*p)) {
+      if (num > 0) {
 	do {
 	  ++p;
-	} while (*p && isspace(*p));
-	if (isdigit(*p)) {
-	  gen = atoi(p);
+	} while (*p && isdigit(*p));
+	if (isspace(*p)) {
 	  do {
 	    ++p;
-	  } while (*p && isdigit(*p));
-	  if (isspace(*p)) {
+	  } while (*p && isspace(*p));
+	  if (isdigit(*p)) {
+	    gen = atoi(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 = 0xffffffff;
-		  entries[i].type = xrefEntryFree;
+	    } 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;
+		  if (newSize < 0) {
+		    error(-1, "Bad object number");
+		    return gFalse;
+		  }
+		  entries = (XRefEntry *)
+		      greallocn(entries, newSize, sizeof(XRefEntry));
+		  for (i = size; i < newSize; ++i) {
+		    entries[i].offset = 0xffffffff;
+		    entries[i].type = xrefEntryFree;
+		  }
+		  size = newSize;
+		}
+		if (entries[num].type == xrefEntryFree ||
+		    gen >= entries[num].gen) {
+		  entries[num].offset = pos - start;
+		  entries[num].gen = gen;
+		  entries[num].type = xrefEntryUncompressed;
 		}
-		size = newSize;
-	      }
-	      if (entries[num].type == xrefEntryFree ||
-		  gen >= entries[num].gen) {
-		entries[num].offset = pos - start;
-		entries[num].gen = gen;
-		entries[num].type = xrefEntryUncompressed;
 	      }
 	    }
 	  }
@@ -705,8 +731,8 @@ GBool XRef::constructXRef() {
     } else if (!strncmp(p, "endstream", 9)) {
       if (streamEndsLen == streamEndsSize) {
 	streamEndsSize += 64;
-	streamEnds = (Guint *)grealloc(streamEnds,
-				       streamEndsSize * sizeof(int));
+	streamEnds = (Guint *)greallocn(streamEnds,
+					streamEndsSize, sizeof(int));
       }
       streamEnds[streamEndsLen++] = pos;
     }
@@ -719,137 +745,38 @@ GBool XRef::constructXRef() {
   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;
-
-  keyLength = 0;
-  encVersion = encRevision = 0;
-  ret = gFalse;
+void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA,
+			 Guchar *fileKeyA, int keyLengthA, int encVersionA) {
+  int i;
 
-  permFlags = defPermFlags;
-  ownerPasswordOk = gFalse;
-  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();
+  encrypted = gTrue;
+  permFlags = permFlagsA;
+  ownerPasswordOk = ownerPasswordOkA;
+  if (keyLengthA <= 16) {
+    keyLength = keyLengthA;
+  } else {
+    keyLength = 16;
   }
-  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.");
+  for (i = 0; i < keyLength; ++i) {
+    fileKey[i] = fileKeyA[i];
   }
-  obj.free();
-  return encrypted;
+  encVersion = encVersionA;
 }
-#endif
 
 GBool XRef::okToPrint(GBool ignoreOwnerPW) {
-#ifndef NO_DECRYPTION
   return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint);
-#else
-  return gTrue;
-#endif
 }
 
 GBool XRef::okToChange(GBool ignoreOwnerPW) {
-#ifndef NO_DECRYPTION
   return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange);
-#else
-  return gTrue;
-#endif
 }
 
 GBool XRef::okToCopy(GBool ignoreOwnerPW) {
-#ifndef NO_DECRYPTION
   return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy);
-#else
-  return gTrue;
-#endif
 }
 
 GBool XRef::okToAddNotes(GBool ignoreOwnerPW) {
-#ifndef NO_DECRYPTION
   return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes);
-#else
-  return gTrue;
-#endif
 }
 
 Object *XRef::fetch(int num, int gen, Object *obj) {
@@ -879,14 +806,14 @@ Object *XRef::fetch(int num, int gen, Object *obj) {
     if (!obj1.isInt() || obj1.getInt() != num ||
 	!obj2.isInt() || obj2.getInt() != gen ||
 	!obj3.isCmd("obj")) {
+      obj1.free();
+      obj2.free();
+      obj3.free();
+      delete parser;
       goto err;
     }
-#ifndef NO_DECRYPTION
     parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength,
 		   num, gen);
-#else
-    parser->getObj(obj);
-#endif
     obj1.free();
     obj2.free();
     obj3.free();
diff --git a/pdf2swf/xpdf/XRef.h b/pdf2swf/xpdf/XRef.h
index bec487a..f9dede3 100644
--- a/pdf2swf/xpdf/XRef.h
+++ b/pdf2swf/xpdf/XRef.h
@@ -43,7 +43,7 @@ class XRef {
 public:
 
   // Constructor.  Read xref table from stream.
-  XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword);
+  XRef(BaseStream *strA);
 
   // Destructor.
   ~XRef();
@@ -54,12 +54,12 @@ public:
   // Get the error code (if isOk() returns false).
   int getErrorCode() { return errCode; }
 
+  // Set the encryption parameters.
+  void setEncryption(int permFlagsA, GBool ownerPasswordOkA,
+		     Guchar *fileKeyA, int keyLengthA, int encVersionA);
+
   // 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);
@@ -112,15 +112,12 @@ private:
 				//   damaged files
   int streamEndsLen;		// number of valid entries in streamEnds
   ObjectStream *objStr;		// cached object stream
-#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
+  Guchar fileKey[16];		// file decryption key
+  int keyLength;		// length of key, in bytes
+  int encVersion;		// encryption algorithm
 
   Guint getStartXref();
   GBool readXRef(Guint *pos);
@@ -128,7 +125,6 @@ private:
   GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n);
   GBool readXRefStream(Stream *xrefStr, Guint *pos);
   GBool constructXRef();
-  GBool checkEncrypted(GString *ownerPassword, GString *userPassword);
   Guint strToUnsigned(char *s);
 };
 
diff --git a/pdf2swf/xpdf/gmem.c b/pdf2swf/xpdf/gmem.c
index 07bbf81..a0f2cf5 100644
--- a/pdf2swf/xpdf/gmem.c
+++ b/pdf2swf/xpdf/gmem.c
@@ -50,6 +50,7 @@ static GMemHdr *gMemList[gMemNLists] = {
 
 static int gMemIndex = 0;
 static int gMemAlloc = 0;
+static int gMemInUse = 0;
 
 #endif /* DEBUG_MEM */
 
@@ -78,6 +79,7 @@ void *gmalloc(int size) {
   hdr->next = gMemList[lst];
   gMemList[lst] = hdr;
   ++gMemAlloc;
+  gMemInUse += size;
   for (p = (unsigned long *)data; p <= trl; ++p)
     *p = gMemDeadVal;
   return data;
@@ -135,6 +137,28 @@ void *grealloc(void *p, int size) {
 #endif
 }
 
+void *gmallocn(int nObjs, int objSize) {
+  int n;
+
+  n = nObjs * objSize;
+  if (objSize == 0 || n / objSize != nObjs) {
+    fprintf(stderr, "Bogus memory allocation size\n");
+    exit(1);
+  }
+  return gmalloc(n);
+}
+
+void *greallocn(void *p, int nObjs, int objSize) {
+  int n;
+
+  n = nObjs * objSize;
+  if (objSize == 0 || n / objSize != nObjs) {
+    fprintf(stderr, "Bogus memory allocation size\n");
+    exit(1);
+  }
+  return grealloc(p, n);
+}
+
 void gfree(void *p) {
 #ifdef DEBUG_MEM
   int size;
@@ -156,6 +180,7 @@ void gfree(void *p) {
       else
 	gMemList[lst] = hdr->next;
       --gMemAlloc;
+      gMemInUse -= hdr->size;
       size = gMemDataSize(hdr->size);
       trl = (unsigned long *)((char *)hdr + gMemHdrSize + size);
       if (*trl != gMemDeadVal) {
diff --git a/pdf2swf/xpdf/gmem.h b/pdf2swf/xpdf/gmem.h
index 587e7fa..e74d182 100644
--- a/pdf2swf/xpdf/gmem.h
+++ b/pdf2swf/xpdf/gmem.h
@@ -28,6 +28,15 @@ extern void *gmalloc(int size);
 extern void *grealloc(void *p, int size);
 
 /*
+ * These are similar to gmalloc and grealloc, but take an object count
+ * and size.  The result is similar to allocating nObjs * objSize
+ * bytes, but there is an additional error check that the total size
+ * doesn't overflow an int.
+ */
+extern void *gmallocn(int nObjs, int objSize);
+extern void *greallocn(void *p, int nObjs, int objSize);
+
+/*
  * Same as free, but checks for and ignores NULL pointers.
  */
 extern void gfree(void *p);