Back to index

tetex-bin  3.0
Public Member Functions | Private Member Functions | Private Attributes
Catalog Class Reference

#include <Catalog.h>

Collaboration diagram for Catalog:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 Catalog (XRef *xrefA)
 ~Catalog ()
GBool isOk ()
int getNumPages ()
PagegetPage (int i)
RefgetPageRef (int i)
GStringgetBaseURI ()
GStringreadMetadata ()
ObjectgetStructTreeRoot ()
int findPage (int num, int gen)
LinkDestfindDest (GString *name)
ObjectgetOutline ()

Private Member Functions

int readPageTree (Dict *pages, PageAttrs *attrs, int start)
ObjectfindDestInTree (Object *tree, GString *name, Object *obj)

Private Attributes

XRefxref
Page ** pages
RefpageRefs
int numPages
int pagesSize
Object dests
Object nameTree
GStringbaseURI
Object metadata
Object structTreeRoot
Object outline
GBool ok

Detailed Description

Definition at line 29 of file Catalog.h.


Constructor & Destructor Documentation

Catalog::Catalog ( XRef xrefA)

Definition at line 30 of file Catalog.cc.

                            {
  Object catDict, pagesDict;
  Object obj, obj2;
  int numPages0;
  int i;

  ok = gTrue;
  xref = xrefA;
  pages = NULL;
  pageRefs = NULL;
  numPages = pagesSize = 0;
  baseURI = NULL;

  xref->getCatalog(&catDict);
  if (!catDict.isDict()) {
    error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName());
    goto err1;
  }

  // read page tree
  catDict.dictLookup("Pages", &pagesDict);
  // This should really be isDict("Pages"), but I've seen at least one
  // PDF file where the /Type entry is missing.
  if (!pagesDict.isDict()) {
    error(-1, "Top-level pages object is wrong type (%s)",
         pagesDict.getTypeName());
    goto err2;
  }
  pagesDict.dictLookup("Count", &obj);
  // 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;
  }
  pagesSize = numPages0 = (int)obj.getNum();
  obj.free();
  pages = (Page **)gmalloc(pagesSize * sizeof(Page *));
  pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref));
  for (i = 0; i < pagesSize; ++i) {
    pages[i] = NULL;
    pageRefs[i].num = -1;
    pageRefs[i].gen = -1;
  }
  numPages = readPageTree(pagesDict.getDict(), NULL, 0);
  if (numPages != numPages0) {
    error(-1, "Page count in top-level pages object is incorrect");
  }
  pagesDict.free();

  // read named destination dictionary
  catDict.dictLookup("Dests", &dests);

  // read root of named destination tree
  if (catDict.dictLookup("Names", &obj)->isDict())
    obj.dictLookup("Dests", &nameTree);
  else
    nameTree.initNull();
  obj.free();

  // read base URI
  if (catDict.dictLookup("URI", &obj)->isDict()) {
    if (obj.dictLookup("Base", &obj2)->isString()) {
      baseURI = obj2.getString()->copy();
    }
    obj2.free();
  }
  obj.free();

  // get the metadata stream
  catDict.dictLookup("Metadata", &metadata);

  // get the structure tree root
  catDict.dictLookup("StructTreeRoot", &structTreeRoot);

  // get the outline dictionary
  catDict.dictLookup("Outlines", &outline);

  catDict.free();
  return;

 err3:
  obj.free();
 err2:
  pagesDict.free();
 err1:
  catDict.free();
  dests.initNull();
  nameTree.initNull();
  ok = gFalse;
}

Here is the call graph for this function:

Definition at line 122 of file Catalog.cc.

                  {
  int i;

  if (pages) {
    for (i = 0; i < pagesSize; ++i) {
      if (pages[i]) {
       delete pages[i];
      }
    }
    gfree(pages);
    gfree(pageRefs);
  }
  dests.free();
  nameTree.free();
  if (baseURI) {
    delete baseURI;
  }
  metadata.free();
  structTreeRoot.free();
  outline.free();
}

Here is the call graph for this function:


Member Function Documentation

Definition at line 248 of file Catalog.cc.

                                         {
  LinkDest *dest;
  Object obj1, obj2;
  GBool found;

  // try named destination dictionary then name tree
  found = gFalse;
  if (dests.isDict()) {
    if (!dests.dictLookup(name->getCString(), &obj1)->isNull())
      found = gTrue;
    else
      obj1.free();
  }
  if (!found && nameTree.isDict()) {
    if (!findDestInTree(&nameTree, name, &obj1)->isNull())
      found = gTrue;
    else
      obj1.free();
  }
  if (!found)
    return NULL;

  // construct LinkDest
  dest = NULL;
  if (obj1.isArray()) {
    dest = new LinkDest(obj1.getArray());
  } else if (obj1.isDict()) {
    if (obj1.dictLookup("D", &obj2)->isArray())
      dest = new LinkDest(obj2.getArray());
    else
      error(-1, "Bad named destination value");
    obj2.free();
  } else {
    error(-1, "Bad named destination value");
  }
  obj1.free();
  if (dest && !dest->isOk()) {
    delete dest;
    dest = NULL;
  }

  return dest;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Object * Catalog::findDestInTree ( Object tree,
GString name,
Object obj 
) [private]

Definition at line 292 of file Catalog.cc.

                                                                        {
  Object names, name1;
  Object kids, kid, limits, low, high;
  GBool done, found;
  int cmp, i;

  // leaf node
  if (tree->dictLookup("Names", &names)->isArray()) {
    done = found = gFalse;
    for (i = 0; !done && i < names.arrayGetLength(); i += 2) {
      if (names.arrayGet(i, &name1)->isString()) {
       cmp = name->cmp(name1.getString());
       if (cmp == 0) {
         names.arrayGet(i+1, obj);
         found = gTrue;
         done = gTrue;
       } else if (cmp < 0) {
         done = gTrue;
       }
      }
      name1.free();
    }
    names.free();
    if (!found)
      obj->initNull();
    return obj;
  }
  names.free();

  // root or intermediate node
  done = gFalse;
  if (tree->dictLookup("Kids", &kids)->isArray()) {
    for (i = 0; !done && i < kids.arrayGetLength(); ++i) {
      if (kids.arrayGet(i, &kid)->isDict()) {
       if (kid.dictLookup("Limits", &limits)->isArray()) {
         if (limits.arrayGet(0, &low)->isString() &&
             name->cmp(low.getString()) >= 0) {
           if (limits.arrayGet(1, &high)->isString() &&
              name->cmp(high.getString()) <= 0) {
             findDestInTree(&kid, name, obj);
             done = gTrue;
           }
           high.free();
         }
         low.free();
       }
       limits.free();
      }
      kid.free();
    }
  }
  kids.free();

  // name was outside of ranges of all kids
  if (!done)
    obj->initNull();

  return obj;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int Catalog::findPage ( int  num,
int  gen 
)

Definition at line 238 of file Catalog.cc.

                                      {
  int i;

  for (i = 0; i < numPages; ++i) {
    if (pageRefs[i].num == num && pageRefs[i].gen == gen)
      return i + 1;
  }
  return 0;
}

Here is the caller graph for this function:

Definition at line 51 of file Catalog.h.

{ return baseURI; }

Here is the caller graph for this function:

int Catalog::getNumPages ( ) [inline]

Definition at line 42 of file Catalog.h.

{ return numPages; }

Here is the caller graph for this function:

Object* Catalog::getOutline ( ) [inline]

Definition at line 68 of file Catalog.h.

{ return &outline; }

Here is the caller graph for this function:

Page* Catalog::getPage ( int  i) [inline]

Definition at line 45 of file Catalog.h.

{ return pages[i-1]; }

Here is the caller graph for this function:

Ref* Catalog::getPageRef ( int  i) [inline]

Definition at line 48 of file Catalog.h.

{ return &pageRefs[i-1]; }

Definition at line 58 of file Catalog.h.

{ return &structTreeRoot; }

Here is the caller graph for this function:

GBool Catalog::isOk ( ) [inline]

Definition at line 39 of file Catalog.h.

{ return ok; }

Here is the caller graph for this function:

Definition at line 144 of file Catalog.cc.

                               {
  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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int Catalog::readPageTree ( Dict pages,
PageAttrs attrs,
int  start 
) [private]

Definition at line 168 of file Catalog.cc.

                                                                      {
  Object kids;
  Object kid;
  Object kidRef;
  PageAttrs *attrs1, *attrs2;
  Page *page;
  int i, j;

  attrs1 = new PageAttrs(attrs, pagesDict);
  pagesDict->lookup("Kids", &kids);
  if (!kids.isArray()) {
    error(-1, "Kids object (page %d) is wrong type (%s)",
         start+1, kids.getTypeName());
    goto err1;
  }
  for (i = 0; i < kids.arrayGetLength(); ++i) {
    kids.arrayGet(i, &kid);
    if (kid.isDict("Page")) {
      attrs2 = new PageAttrs(attrs1, kid.getDict());
      page = new Page(xref, start+1, kid.getDict(), attrs2);
      if (!page->isOk()) {
       ++start;
       goto err3;
      }
      if (start >= pagesSize) {
       pagesSize += 32;
       pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *));
       pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref));
       for (j = pagesSize - 32; j < pagesSize; ++j) {
         pages[j] = NULL;
         pageRefs[j].num = -1;
         pageRefs[j].gen = -1;
       }
      }
      pages[start] = page;
      kids.arrayGetNF(i, &kidRef);
      if (kidRef.isRef()) {
       pageRefs[start].num = kidRef.getRefNum();
       pageRefs[start].gen = kidRef.getRefGen();
      }
      kidRef.free();
      ++start;
    // This should really be isDict("Pages"), but I've seen at least one
    // PDF file where the /Type entry is missing.
    } else if (kid.isDict()) {
      if ((start = readPageTree(kid.getDict(), attrs1, start))
         < 0)
       goto err2;
    } else {
      error(-1, "Kid object (page %d) is wrong type (%s)",
           start+1, kid.getTypeName());
      goto err2;
    }
    kid.free();
  }
  delete attrs1;
  kids.free();
  return start;

 err3:
  delete page;
 err2:
  kid.free();
 err1:
  kids.free();
  delete attrs1;
  ok = gFalse;
  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Definition at line 79 of file Catalog.h.

Definition at line 77 of file Catalog.h.

Definition at line 80 of file Catalog.h.

Definition at line 78 of file Catalog.h.

Definition at line 75 of file Catalog.h.

GBool Catalog::ok [private]

Definition at line 83 of file Catalog.h.

Definition at line 82 of file Catalog.h.

Ref* Catalog::pageRefs [private]

Definition at line 74 of file Catalog.h.

Page** Catalog::pages [private]

Definition at line 73 of file Catalog.h.

Definition at line 76 of file Catalog.h.

Definition at line 81 of file Catalog.h.

XRef* Catalog::xref [private]

Definition at line 72 of file Catalog.h.


The documentation for this class was generated from the following files: