Commit 2a1e4f6f authored by Kristian Høgsberg's avatar Kristian Høgsberg

2005-03-22 Kristian Høgsberg <krh@redhat.com>

        * poppler/Array.cc:
        * poppler/Array.h: Add getString() convenience method.

        * poppler/Catalog.cc:
        * poppler/Catalog.h: Optimize lookup of named destinations.
parent 4dfe0ce4
2005-03-22 Kristian Høgsberg <krh@redhat.com>
* poppler/Array.cc:
* poppler/Array.h: Add getString() convenience method.
* poppler/Catalog.cc:
* poppler/Catalog.h: Optimize lookup of named destinations.
2005-03-21 Kristian Høgsberg <krh@redhat.com>
* NEWS, TODO: Update these.
......
......@@ -71,3 +71,18 @@ Object *Array::getNF(int i, Object *obj) {
}
return elems[i].copy(obj);
}
GBool Array::getString(int i, GooString *string)
{
Object obj;
if (getNF(i, &obj)->isString()) {
string->clear();
string->append(obj.getString());
obj.free();
return gTrue;
} else {
obj.free();
return gFalse;
}
}
......@@ -43,6 +43,7 @@ public:
// Accessors.
Object *get(int i, Object *obj);
Object *getNF(int i, Object *obj);
GBool getString(int i, GooString *string);
private:
......
......@@ -13,6 +13,7 @@
#endif
#include <stddef.h>
#include <stdlib.h>
#include "goo/gmem.h"
#include "Object.h"
#include "XRef.h"
......@@ -91,10 +92,11 @@ Catalog::Catalog(XRef *xrefA) {
catDict.dictLookup("Dests", &dests);
// read root of named destination tree
if (catDict.dictLookup("Names", &obj)->isDict())
obj.dictLookup("Dests", &nameTree);
else
nameTree.initNull();
if (catDict.dictLookup("Names", &obj)->isDict()) {
obj.dictLookup("Dests", &obj2);
destNameTree.init(xref, &obj2);
obj2.free();
}
obj.free();
if (catDict.dictLookup("PageLabels", &obj)->isDict())
......@@ -145,7 +147,6 @@ Catalog::Catalog(XRef *xrefA) {
err1:
catDict.free();
dests.initNull();
nameTree.initNull();
ok = gFalse;
}
......@@ -162,7 +163,7 @@ Catalog::~Catalog() {
gfree(pageRefs);
}
dests.free();
nameTree.free();
destNameTree.free();
if (baseURI) {
delete baseURI;
}
......@@ -293,8 +294,8 @@ LinkDest *Catalog::findDest(GooString *name) {
else
obj1.free();
}
if (!found && nameTree.isDict()) {
if (!findDestInTree(&nameTree, name, &obj1)->isNull())
if (!found) {
if (destNameTree.lookup(name, &obj1))
found = gTrue;
else
obj1.free();
......@@ -324,64 +325,103 @@ LinkDest *Catalog::findDest(GooString *name) {
return dest;
}
Object *Catalog::findDestInTree(Object *tree, GooString *name, Object *obj) {
Object names, name1;
Object kids, kid, limits, low, high;
GBool done, found;
int cmp, i;
NameTree::NameTree(void)
{
size = 0;
length = 0;
entries = NULL;
}
NameTree::Entry::Entry(Array *array, int index) {
if (!array->getString(index, &name) || !array->getNF(index + 1, &value))
error(-1, "Invalid page tree");
}
NameTree::Entry::~Entry() {
value.free();
}
void NameTree::addEntry(Entry *entry)
{
if (length == size) {
if (length == 0) {
size = 8;
} else {
size *= 2;
}
entries = (Entry **) grealloc (entries, sizeof (Entry *) * size);
}
entries[length] = entry;
++length;
}
void NameTree::init(XRef *xrefA, Object *tree) {
xref = xrefA;
parse(tree);
}
void NameTree::parse(Object *tree) {
Object names;
Object kids, kid;
int i;
if (!tree->isDict())
return;
// 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();
for (i = 0; i < names.arrayGetLength(); i += 2) {
NameTree::Entry *entry;
entry = new Entry(names.getArray(), i);
addEntry(entry);
}
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();
}
for (i = 0; i < kids.arrayGetLength(); ++i) {
if (kids.arrayGet(i, &kid)->isDict())
parse(&kid);
kid.free();
}
}
kids.free();
}
int NameTree::Entry::cmp(const void *voidKey, const void *voidEntry)
{
GooString *key = (GooString *) voidKey;
Entry *entry = *(NameTree::Entry **) voidEntry;
return key->cmp(&entry->name);
}
GBool NameTree::lookup(GooString *name, Object *obj)
{
Entry *entry;
// name was outside of ranges of all kids
if (!done)
entry = *(Entry **) bsearch(name, entries,
length, sizeof(Entry *), Entry::cmp);
if (entry != NULL) {
entry->value.fetch(xref, obj);
return gTrue;
} else {
printf("failed to look up %s\n", name->getCString());
obj->initNull();
return gFalse;
}
}
void NameTree::free()
{
int i;
for (i = 0; i < length; i++)
delete entries[i];
return obj;
gfree(entries);
}
GBool Catalog::labelToIndex(GooString *label, int *index)
......
......@@ -21,6 +21,36 @@ struct Ref;
class LinkDest;
class PageLabelInfo;
//------------------------------------------------------------------------
// NameTree
//------------------------------------------------------------------------
class NameTree {
public:
NameTree();
void init(XRef *xref, Object *tree);
void parse(Object *tree);
GBool lookup(GooString *name, Object *obj);
void free();
private:
struct Entry {
Entry(Array *array, int index);
~Entry();
GooString name;
Object value;
void free();
static int cmp(const void *key, const void *entry);
};
void addEntry(Entry *entry);
XRef *xref;
Object *root;
Entry **entries;
int size, length;
};
//------------------------------------------------------------------------
// Catalog
//------------------------------------------------------------------------
......@@ -89,7 +119,7 @@ private:
int numPages; // number of pages
int pagesSize; // size of pages array
Object dests; // named destination dictionary
Object nameTree; // name tree
NameTree destNameTree; // name tree
GooString *baseURI; // base URI for URI-type links
Object metadata; // metadata stream
Object structTreeRoot; // structure tree root dictionary
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment