home *** CD-ROM | disk | FTP | other *** search
- //========================================================================
- //
- // Catalog.cc
- //
- // Copyright 1996 Derek B. Noonburg
- //
- //========================================================================
- //
- // Ported to EPOC by Sander van der Wal
- //
- // $Log: Catalog.cpp $
- // Revision 1.3 2000-09-20 20:41:55+02 svdwal
- // some bugfixes from xpdf 0.91
- //
- // Revision 1.2 2000-09-17 13:38:25+02 svdwal
- // Ported
- //
-
- #ifdef __GNUC__
- #pragma implementation
- #endif
-
- // --o GooLib
- #include "gmem.h"
-
- // --o Pdf
- #include "Object.h"
- #include "Array.h"
- #include "Dict.h"
- #include "Page.h"
- #include "Error.h"
- #include "Link.h"
- #include "Catalog.h"
-
- // --o Pdf
- #include "Pdf.rsg"
-
-
-
- //------------------------------------------------------------------------
- // Catalog
- //------------------------------------------------------------------------
-
- Catalog::Catalog() {
- ok = gTrue;
- }
-
- void Catalog::ConstructL(Object *catDict)
- {
- RAutoObject pagesDict;
- RAutoObject obj;
- int i;
-
- ok = gFalse;
- if (!catDict->isDict()) {
- error(-1, R_CATALOG_OBJECT_IS_WRONG_TYPE___S_, catDict->getTypeName());
- goto err1;
- }
-
- // read page tree
-
- catDict->dictLookupL("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, R_TOP_LEVEL_PAGES_OBJECT_IS_WRONG_TYPE___S_, pagesDict.getTypeName());
- goto err2;
- }
-
- pagesDict.dictLookupL("Count", &obj);
- if (!obj.isInt()) {
- error(-1, R_PAGE_COUNT_IN_TOP_LEVEL_PAGES_OBJECT_IS_WRONG_TYPE___S_, obj.getTypeName());
- goto err3;
- }
- numPages = obj.getInt();
- obj.free();
- pageRefs = (Ref *)User::AllocL(numPages * sizeof(Ref));
- pages = (Page **)User::AllocL(numPages * sizeof(Page *));
- for (i = 0; i < numPages; ++i) {
- pages[i] = 0;
- pageRefs[i].num = -1;
- pageRefs[i].gen = -1;
- }
- readPageTree(pagesDict.getDict(), 0, 0);
- pagesDict.free();
-
- // read named destination dictionary
- catDict->dictLookupL("Dests", &dests);
-
- // read root of named destination tree
- if (catDict->dictLookupL("Names", &obj)->isDict())
- obj.dictLookupL("Dests", &nameTree);
- else
- nameTree.initNull();
- obj.free();
-
- // read base URI
-
- if (catDict->dictLookupL("URI", &obj)->isDict()) {
- RAutoObject obj2;
- if (obj.dictLookupL("Base", &obj2)->isString()) {
- baseURI = obj2.getString()->copyL();
- }
- obj2.free();
- }
- obj.free();
-
- ok = gTrue;
- return;
-
- err3:
- obj.free();
- err2:
- pagesDict.free();
- err1:
- dests.initNull();
- nameTree.initNull();
- ok = gFalse;
- }
-
- Catalog::~Catalog() {
- int i;
-
- if (pages) {
- for (i = 0; i < numPages; ++i) {
- delete pages[i];
- }
- User::Free(pages);
- }
- User::Free(pageRefs);
- dests.free();
- nameTree.free();
- delete baseURI;
- }
-
- int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
- RAutoObject kids;
- RAutoObject kid;
- RAutoObject kidRef;
- PageAttrs *attrs1, *attrs2;
- Page *page;
- int i;
-
- attrs1 = new(ELeave) PageAttrs();
- CleanupStack::PushL(attrs1);
- attrs1->ConstructL(attrs, pagesDict);
- pagesDict->lookupL("Kids", &kids);
- if (!kids.isArray()) {
- error(-1, R_KIDS_OBJECT__PAGE__D__IS_WRONG_TYPE___S_, start+1, kids.getTypeName());
- goto err1;
- }
- for (i = 0; i < kids.arrayGetLength(); ++i) {
- kids.arrayGetL(i, &kid);
- if (kid.isDict("Page")) {
-
- attrs2 = new(ELeave) PageAttrs();
- CleanupStack::PushL(attrs2);
- attrs2->ConstructL(attrs1, kid.getDict());
-
- page = new(ELeave) Page(start+1, attrs2);
- CleanupStack::Pop(); // attrs2
- CleanupStack::PushL(page);
- page->ConstructL(kid.getDict());
- if (!page->isOk()) {
- ++start;
- goto err3;
- }
- CleanupStack::Pop(); // page
- pages[start] = page;
- kids.arrayGetNFL(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, R_KID_OBJECT__PAGE__D__IS_WRONG_TYPE___S_, start+1, kid.getTypeName());
- goto err2;
- }
- kid.free();
- }
- CleanupStack::PopAndDestroy(); // delete attrs1;
- kids.free();
- return start;
-
- err3:
- CleanupStack::PopAndDestroy(); // delete page;
- err2:
- kid.free();
- err1:
- kids.free();
- CleanupStack::PopAndDestroy(); // delete attrs1;
- ok = gFalse;
- return -1;
- }
-
-
- int Catalog::findPage(int num, int gen) {
- int i;
-
- for (i = 0; i < numPages; ++i) {
- if (pageRefs[i].num == num && pageRefs[i].gen == gen)
- return i + 1;
- }
- return 0;
- }
-
-
- LinkDest *Catalog::findDestL(GString *name) {
- LinkDest *dest;
- RAutoObject obj1;
- GBool found;
-
- // try named destination dictionary then name tree
- found = gFalse;
- if (dests.isDict()) {
- if (!dests.dictLookupL(name->getCString(), &obj1)->isNull())
- found = gTrue;
- else
- obj1.free();
- }
- if (!found && nameTree.isDict()) {
- if (!findDestInTreeL(&nameTree, name, &obj1)->isNull())
- found = gTrue;
- else
- obj1.free();
- }
- if (!found)
- return 0;
-
- // construct LinkDest
- dest = 0;
- if (obj1.isArray()) {
- dest = new(ELeave) LinkDest();
- CleanupStack::PushL(dest);
- dest->ConstructL(obj1.getArray(), gTrue);
- CleanupStack::Pop(); // dest
- }
- else if (obj1.isDict()) {
- RAutoObject obj2;
- if (obj1.dictLookupL("D", &obj2)->isArray()) {
- dest = new(ELeave) LinkDest();
- CleanupStack::PushL(dest);
- dest->ConstructL(obj2.getArray(), gTrue);
- CleanupStack::Pop(); // dest
- }
- else
- error(-1, R_BAD_NAMED_DESTINATION_VALUE);
- obj2.free();
- }
- else {
- error(-1, R_BAD_NAMED_DESTINATION_VALUE);
- }
- obj1.free();
-
- return dest;
- }
-
-
- Object *Catalog::findDestInTreeL(Object *tree, GString *name, Object *obj) {
- RAutoObject names, name1;
- RAutoObject kids, kid, limits, low, high;
- GBool done, found;
- int cmp, i;
-
- // leaf node
- if (tree->dictLookupL("Names", &names)->isArray()) {
- done = found = gFalse;
- for (i = 0; !done && i < names.arrayGetLength(); i += 2) {
- if (names.arrayGetL(i, &name1)->isString()) {
- cmp = name->cmp(name1.getString());
- if (cmp == 0) {
- names.arrayGetL(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->dictLookupL("Kids", &kids)->isArray()) {
- for (i = 0; !done && i < kids.arrayGetLength(); ++i) {
- if (kids.arrayGetL(i, &kid)->isDict()) {
- if (kid.dictLookupL("Limits", &limits)->isArray()) {
- if (limits.arrayGetL(0, &low)->isString() &&
- name->cmp(low.getString()) >= 0) {
- if (limits.arrayGetL(1, &high)->isString() &&
- name->cmp(high.getString()) <= 0) {
- findDestInTreeL(&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;
- }
-