]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/Catalog.cc
Fix mouse wheel scrolling
[evince.git] / pdf / xpdf / Catalog.cc
index fded0bef9a1286a238b5055486f892f105e9aa8a..8762cd4cb4d1a908436382fbadfc4d26b5805620 100644 (file)
@@ -2,17 +2,20 @@
 //
 // Catalog.cc
 //
 //
 // Catalog.cc
 //
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
 //
 //========================================================================
 
-#ifdef __GNUC__
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
 #pragma implementation
 #endif
 
 #include <stddef.h>
 #include "gmem.h"
 #include "Object.h"
 #pragma implementation
 #endif
 
 #include <stddef.h>
 #include "gmem.h"
 #include "Object.h"
+#include "XRef.h"
 #include "Array.h"
 #include "Dict.h"
 #include "Page.h"
 #include "Array.h"
 #include "Dict.h"
 #include "Page.h"
 // Catalog
 //------------------------------------------------------------------------
 
 // Catalog
 //------------------------------------------------------------------------
 
-Catalog::Catalog(Object *catDict) {
-  Object pagesDict;
-  Object obj;
+Catalog::Catalog(XRef *xrefA) {
+  Object catDict, pagesDict;
+  Object obj, obj2;
+  int numPages0;
   int i;
 
   ok = gTrue;
   int i;
 
   ok = gTrue;
+  xref = xrefA;
   pages = NULL;
   pageRefs = NULL;
   pages = NULL;
   pageRefs = NULL;
-  numPages = 0;
+  numPages = pagesSize = 0;
+  baseURI = NULL;
 
 
-  if (!catDict->isDict("Catalog")) {
-    error(-1, "Catalog object is wrong type (%s)", catDict->getTypeName());
+  xref->getCatalog(&catDict);
+  if (!catDict.isDict()) {
+    error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName());
     goto err1;
   }
 
   // read page tree
     goto err1;
   }
 
   // read page tree
-  catDict->dictLookup("Pages", &pagesDict);
-  if (!pagesDict.isDict("Pages")) {
+  catDict.dictLookup("Pages", &pagesDict);
+  // This should really be isDict("Pages"), but I've seen at least one
+  // PDF file where the /Type entry is missing.
+  if (!pagesDict.isDict()) {
     error(-1, "Top-level pages object is wrong type (%s)",
          pagesDict.getTypeName());
     goto err2;
   }
   pagesDict.dictLookup("Count", &obj);
     error(-1, "Top-level pages object is wrong type (%s)",
          pagesDict.getTypeName());
     goto err2;
   }
   pagesDict.dictLookup("Count", &obj);
-  if (!obj.isInt()) {
+  // some PDF files actually use real numbers here ("/Count 9.0")
+  if (!obj.isNum()) {
     error(-1, "Page count in top-level pages object is wrong type (%s)",
          obj.getTypeName());
     goto err3;
   }
     error(-1, "Page count in top-level pages object is wrong type (%s)",
          obj.getTypeName());
     goto err3;
   }
-  numPages = obj.getInt();
+  pagesSize = numPages0 = (int)obj.getNum();
   obj.free();
   obj.free();
-  pages = (Page **)gmalloc(numPages * sizeof(Page *));
-  pageRefs = (Ref *)gmalloc(numPages * sizeof(Ref));
-  for (i = 0; i < numPages; ++i) {
+  // The gcc doesnt optimize this away, so this check is ok,
+  // even if it looks like a pagesSize != pagesSize check
+  if (pagesSize*sizeof(Page *)/sizeof(Page *) != pagesSize ||
+      pagesSize*sizeof(Ref)/sizeof(Ref) != pagesSize) {
+    error(-1, "Invalid 'pagesSize'");
+    ok = gFalse;
+    return;
+  }
+
+  pages = (Page **)gmalloc(pagesSize * sizeof(Page *));
+  pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref));
+  for (i = 0; i < pagesSize; ++i) {
     pages[i] = NULL;
     pageRefs[i].num = -1;
     pageRefs[i].gen = -1;
   }
     pages[i] = NULL;
     pageRefs[i].num = -1;
     pageRefs[i].gen = -1;
   }
-  readPageTree(pagesDict.getDict(), NULL, 0);
+  numPages = readPageTree(pagesDict.getDict(), NULL, 0);
+  if (numPages != numPages0) {
+    error(-1, "Page count in top-level pages object is incorrect");
+  }
   pagesDict.free();
 
   // read named destination dictionary
   pagesDict.free();
 
   // read named destination dictionary
-  catDict->dictLookup("Dests", &dests);
+  catDict.dictLookup("Dests", &dests);
 
   // read root of named destination tree
 
   // read root of named destination tree
-  if (catDict->dictLookup("Names", &obj)->isDict())
+  if (catDict.dictLookup("Names", &obj)->isDict())
     obj.dictLookup("Dests", &nameTree);
   else
     nameTree.initNull();
   obj.free();
 
     obj.dictLookup("Dests", &nameTree);
   else
     nameTree.initNull();
   obj.free();
 
+  // read base URI
+  if (catDict.dictLookup("URI", &obj)->isDict()) {
+    if (obj.dictLookup("Base", &obj2)->isString()) {
+      baseURI = obj2.getString()->copy();
+    }
+    obj2.free();
+  }
+  obj.free();
+
+  // get the metadata stream
+  catDict.dictLookup("Metadata", &metadata);
+
+  // get the structure tree root
+  catDict.dictLookup("StructTreeRoot", &structTreeRoot);
+
+  // get the outline dictionary
+  catDict.dictLookup("Outlines", &outline);
+
+  catDict.free();
   return;
 
  err3:
   return;
 
  err3:
@@ -81,6 +122,7 @@ Catalog::Catalog(Object *catDict) {
  err2:
   pagesDict.free();
  err1:
  err2:
   pagesDict.free();
  err1:
+  catDict.free();
   dests.initNull();
   nameTree.initNull();
   ok = gFalse;
   dests.initNull();
   nameTree.initNull();
   ok = gFalse;
@@ -90,15 +132,46 @@ Catalog::~Catalog() {
   int i;
 
   if (pages) {
   int i;
 
   if (pages) {
-    for (i = 0; i < numPages; ++i) {
-      if (pages[i])
+    for (i = 0; i < pagesSize; ++i) {
+      if (pages[i]) {
        delete pages[i];
        delete pages[i];
+      }
     }
     gfree(pages);
     gfree(pageRefs);
   }
   dests.free();
   nameTree.free();
     }
     gfree(pages);
     gfree(pageRefs);
   }
   dests.free();
   nameTree.free();
+  if (baseURI) {
+    delete baseURI;
+  }
+  metadata.free();
+  structTreeRoot.free();
+  outline.free();
+}
+
+GString *Catalog::readMetadata() {
+  GString *s;
+  Dict *dict;
+  Object obj;
+  int c;
+
+  if (!metadata.isStream()) {
+    return NULL;
+  }
+  dict = metadata.streamGetDict();
+  if (!dict->lookup("Subtype", &obj)->isName("XML")) {
+    error(-1, "Unknown Metadata type: '%s'",
+         obj.isName() ? obj.getName() : "???");
+  }
+  obj.free();
+  s = new GString();
+  metadata.streamReset();
+  while ((c = metadata.streamGetChar()) != EOF) {
+    s->append(c);
+  }
+  metadata.streamClose();
+  return s;
 }
 
 int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
 }
 
 int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
@@ -107,7 +180,7 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
   Object kidRef;
   PageAttrs *attrs1, *attrs2;
   Page *page;
   Object kidRef;
   PageAttrs *attrs1, *attrs2;
   Page *page;
-  int i;
+  int i, j;
 
   attrs1 = new PageAttrs(attrs, pagesDict);
   pagesDict->lookup("Kids", &kids);
 
   attrs1 = new PageAttrs(attrs, pagesDict);
   pagesDict->lookup("Kids", &kids);
@@ -120,11 +193,26 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
     kids.arrayGet(i, &kid);
     if (kid.isDict("Page")) {
       attrs2 = new PageAttrs(attrs1, kid.getDict());
     kids.arrayGet(i, &kid);
     if (kid.isDict("Page")) {
       attrs2 = new PageAttrs(attrs1, kid.getDict());
-      page = new Page(start+1, kid.getDict(), attrs2);
+      page = new Page(xref, start+1, kid.getDict(), attrs2);
       if (!page->isOk()) {
        ++start;
        goto err3;
       }
       if (!page->isOk()) {
        ++start;
        goto err3;
       }
+      if (start >= pagesSize) {
+       pagesSize += 32;
+        if (pagesSize*sizeof(Page *)/sizeof(Page *) != pagesSize ||
+            pagesSize*sizeof(Ref)/sizeof(Ref) != pagesSize) {
+          error(-1, "Invalid 'pagesSize' parameter.");
+          goto err3;
+        }
+       pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *));
+       pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref));
+       for (j = pagesSize - 32; j < pagesSize; ++j) {
+         pages[j] = NULL;
+         pageRefs[j].num = -1;
+         pageRefs[j].gen = -1;
+       }
+      }
       pages[start] = page;
       kids.arrayGetNF(i, &kidRef);
       if (kidRef.isRef()) {
       pages[start] = page;
       kids.arrayGetNF(i, &kidRef);
       if (kidRef.isRef()) {
@@ -133,10 +221,11 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
       }
       kidRef.free();
       ++start;
       }
       kidRef.free();
       ++start;
-    //~ found one PDF file where a Pages object is missing the /Type entry
-    // } else if (kid.isDict("Pages")) {
+    // This should really be isDict("Pages"), but I've seen at least one
+    // PDF file where the /Type entry is missing.
     } else if (kid.isDict()) {
     } else if (kid.isDict()) {
-      if ((start = readPageTree(kid.getDict(), attrs1, start)) < 0)
+      if ((start = readPageTree(kid.getDict(), attrs1, start))
+         < 0)
        goto err2;
     } else {
       error(-1, "Kid object (page %d) is wrong type (%s)",
        goto err2;
     } else {
       error(-1, "Kid object (page %d) is wrong type (%s)",
@@ -195,10 +284,10 @@ LinkDest *Catalog::findDest(GString *name) {
   // construct LinkDest
   dest = NULL;
   if (obj1.isArray()) {
   // construct LinkDest
   dest = NULL;
   if (obj1.isArray()) {
-    dest = new LinkDest(obj1.getArray(), gTrue);
+    dest = new LinkDest(obj1.getArray());
   } else if (obj1.isDict()) {
     if (obj1.dictLookup("D", &obj2)->isArray())
   } else if (obj1.isDict()) {
     if (obj1.dictLookup("D", &obj2)->isArray())
-      dest = new LinkDest(obj2.getArray(), gTrue);
+      dest = new LinkDest(obj2.getArray());
     else
       error(-1, "Bad named destination value");
     obj2.free();
     else
       error(-1, "Bad named destination value");
     obj2.free();
@@ -206,6 +295,10 @@ LinkDest *Catalog::findDest(GString *name) {
     error(-1, "Bad named destination value");
   }
   obj1.free();
     error(-1, "Bad named destination value");
   }
   obj1.free();
+  if (dest && !dest->isOk()) {
+    delete dest;
+    dest = NULL;
+  }
 
   return dest;
 }
 
   return dest;
 }
@@ -229,8 +322,8 @@ Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) {
        } else if (cmp < 0) {
          done = gTrue;
        }
        } else if (cmp < 0) {
          done = gTrue;
        }
-       name1.free();
       }
       }
+      name1.free();
     }
     names.free();
     if (!found)
     }
     names.free();
     if (!found)