00001
00002
00003
00004
00005
00006
00007
00008
00009 #ifdef __GNUC__
00010 #pragma implementation
00011 #endif
00012
00013 #include <aconf.h>
00014 #include <stddef.h>
00015 #include "gmem.h"
00016 #include "Object.h"
00017 #include "XRef.h"
00018 #include "Array.h"
00019 #include "Dict.h"
00020 #include "Page.h"
00021 #include "Error.h"
00022 #include "Link.h"
00023 #include "Catalog.h"
00024
00025
00026
00027
00028
00029 Catalog::Catalog(XRef *xrefA, GBool printCommands) {
00030 Object catDict, pagesDict;
00031 Object obj, obj2;
00032 int numPages0;
00033 int i;
00034
00035 ok = gTrue;
00036 xref = xrefA;
00037 pages = NULL;
00038 pageRefs = NULL;
00039 numPages = pagesSize = 0;
00040 baseURI = NULL;
00041
00042 xref->getCatalog(&catDict);
00043 if (!catDict.isDict()) {
00044 error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName());
00045 goto err1;
00046 }
00047
00048
00049 catDict.dictLookup("Pages", &pagesDict);
00050
00051
00052 if (!pagesDict.isDict()) {
00053 error(-1, "Top-level pages object is wrong type (%s)",
00054 pagesDict.getTypeName());
00055 goto err2;
00056 }
00057 pagesDict.dictLookup("Count", &obj);
00058 if (!obj.isInt()) {
00059 error(-1, "Page count in top-level pages object is wrong type (%s)",
00060 obj.getTypeName());
00061 goto err3;
00062 }
00063 pagesSize = numPages0 = obj.getInt();
00064 obj.free();
00065 pages = (Page **)gmalloc(pagesSize * sizeof(Page *));
00066 pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref));
00067 for (i = 0; i < pagesSize; ++i) {
00068 pages[i] = NULL;
00069 pageRefs[i].num = -1;
00070 pageRefs[i].gen = -1;
00071 }
00072 numPages = readPageTree(pagesDict.getDict(), NULL, 0, printCommands);
00073 if (numPages != numPages0) {
00074 error(-1, "Page count in top-level pages object is incorrect");
00075 }
00076 pagesDict.free();
00077
00078
00079 catDict.dictLookup("Dests", &dests);
00080
00081
00082 if (catDict.dictLookup("Names", &obj)->isDict())
00083 obj.dictLookup("Dests", &nameTree);
00084 else
00085 nameTree.initNull();
00086 obj.free();
00087
00088
00089 if (catDict.dictLookup("URI", &obj)->isDict()) {
00090 if (obj.dictLookup("Base", &obj2)->isString()) {
00091 baseURI = obj2.getString()->copy();
00092 }
00093 obj2.free();
00094 }
00095 obj.free();
00096
00097
00098 catDict.dictLookup("Metadata", &metadata);
00099
00100
00101 catDict.dictLookup("StructTreeRoot", &structTreeRoot);
00102
00103 catDict.free();
00104 return;
00105
00106 err3:
00107 obj.free();
00108 err2:
00109 pagesDict.free();
00110 err1:
00111 catDict.free();
00112 dests.initNull();
00113 nameTree.initNull();
00114 ok = gFalse;
00115 }
00116
00117 Catalog::~Catalog() {
00118 int i;
00119
00120 if (pages) {
00121 for (i = 0; i < pagesSize; ++i) {
00122 if (pages[i]) {
00123 delete pages[i];
00124 }
00125 }
00126 gfree(pages);
00127 gfree(pageRefs);
00128 }
00129 dests.free();
00130 nameTree.free();
00131 if (baseURI) {
00132 delete baseURI;
00133 }
00134 metadata.free();
00135 structTreeRoot.free();
00136 }
00137
00138 GString *Catalog::readMetadata() {
00139 GString *s;
00140 Dict *dict;
00141 Object obj;
00142 int c;
00143
00144 if (!metadata.isStream()) {
00145 return NULL;
00146 }
00147 dict = metadata.streamGetDict();
00148 if (!dict->lookup("Subtype", &obj)->isName("XML")) {
00149 error(-1, "Unknown Metadata type: '%s'",
00150 obj.isName() ? obj.getName() : "???");
00151 }
00152 obj.free();
00153 s = new GString();
00154 metadata.streamReset();
00155 while ((c = metadata.streamGetChar()) != EOF) {
00156 s->append(c);
00157 }
00158 metadata.streamClose();
00159 return s;
00160 }
00161
00162 int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start,
00163 GBool printCommands) {
00164 Object kids;
00165 Object kid;
00166 Object kidRef;
00167 PageAttrs *attrs1, *attrs2;
00168 Page *page;
00169 int i, j;
00170
00171 attrs1 = new PageAttrs(attrs, pagesDict);
00172 pagesDict->lookup("Kids", &kids);
00173 if (!kids.isArray()) {
00174 error(-1, "Kids object (page %d) is wrong type (%s)",
00175 start+1, kids.getTypeName());
00176 goto err1;
00177 }
00178 for (i = 0; i < kids.arrayGetLength(); ++i) {
00179 kids.arrayGet(i, &kid);
00180 if (kid.isDict("Page")) {
00181 attrs2 = new PageAttrs(attrs1, kid.getDict());
00182 page = new Page(xref, start+1, kid.getDict(), attrs2, printCommands);
00183 if (!page->isOk()) {
00184 ++start;
00185 goto err3;
00186 }
00187 if (start >= pagesSize) {
00188 pagesSize += 32;
00189 pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *));
00190 pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref));
00191 for (j = pagesSize - 32; j < pagesSize; ++j) {
00192 pages[j] = NULL;
00193 pageRefs[j].num = -1;
00194 pageRefs[j].gen = -1;
00195 }
00196 }
00197 pages[start] = page;
00198 kids.arrayGetNF(i, &kidRef);
00199 if (kidRef.isRef()) {
00200 pageRefs[start].num = kidRef.getRefNum();
00201 pageRefs[start].gen = kidRef.getRefGen();
00202 }
00203 kidRef.free();
00204 ++start;
00205
00206
00207 } else if (kid.isDict()) {
00208 if ((start = readPageTree(kid.getDict(), attrs1, start, printCommands))
00209 < 0)
00210 goto err2;
00211 } else {
00212 error(-1, "Kid object (page %d) is wrong type (%s)",
00213 start+1, kid.getTypeName());
00214 goto err2;
00215 }
00216 kid.free();
00217 }
00218 delete attrs1;
00219 kids.free();
00220 return start;
00221
00222 err3:
00223 delete page;
00224 err2:
00225 kid.free();
00226 err1:
00227 kids.free();
00228 delete attrs1;
00229 ok = gFalse;
00230 return -1;
00231 }
00232
00233 int Catalog::findPage(int num, int gen) {
00234 int i;
00235
00236 for (i = 0; i < numPages; ++i) {
00237 if (pageRefs[i].num == num && pageRefs[i].gen == gen)
00238 return i + 1;
00239 }
00240 return 0;
00241 }
00242
00243 LinkDest *Catalog::findDest(GString *name) {
00244 LinkDest *dest;
00245 Object obj1, obj2;
00246 GBool found;
00247
00248
00249 found = gFalse;
00250 if (dests.isDict()) {
00251 if (!dests.dictLookup(name->getCString(), &obj1)->isNull())
00252 found = gTrue;
00253 else
00254 obj1.free();
00255 }
00256 if (!found && nameTree.isDict()) {
00257 if (!findDestInTree(&nameTree, name, &obj1)->isNull())
00258 found = gTrue;
00259 else
00260 obj1.free();
00261 }
00262 if (!found)
00263 return NULL;
00264
00265
00266 dest = NULL;
00267 if (obj1.isArray()) {
00268 dest = new LinkDest(obj1.getArray());
00269 } else if (obj1.isDict()) {
00270 if (obj1.dictLookup("D", &obj2)->isArray())
00271 dest = new LinkDest(obj2.getArray());
00272 else
00273 error(-1, "Bad named destination value");
00274 obj2.free();
00275 } else {
00276 error(-1, "Bad named destination value");
00277 }
00278 obj1.free();
00279
00280 return dest;
00281 }
00282
00283 Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) {
00284 Object names, name1;
00285 Object kids, kid, limits, low, high;
00286 GBool done, found;
00287 int cmp, i;
00288
00289
00290 if (tree->dictLookup("Names", &names)->isArray()) {
00291 done = found = gFalse;
00292 for (i = 0; !done && i < names.arrayGetLength(); i += 2) {
00293 if (names.arrayGet(i, &name1)->isString()) {
00294 cmp = name->cmp(name1.getString());
00295 if (cmp == 0) {
00296 names.arrayGet(i+1, obj);
00297 found = gTrue;
00298 done = gTrue;
00299 } else if (cmp < 0) {
00300 done = gTrue;
00301 }
00302 name1.free();
00303 }
00304 }
00305 names.free();
00306 if (!found)
00307 obj->initNull();
00308 return obj;
00309 }
00310 names.free();
00311
00312
00313 done = gFalse;
00314 if (tree->dictLookup("Kids", &kids)->isArray()) {
00315 for (i = 0; !done && i < kids.arrayGetLength(); ++i) {
00316 if (kids.arrayGet(i, &kid)->isDict()) {
00317 if (kid.dictLookup("Limits", &limits)->isArray()) {
00318 if (limits.arrayGet(0, &low)->isString() &&
00319 name->cmp(low.getString()) >= 0) {
00320 if (limits.arrayGet(1, &high)->isString() &&
00321 name->cmp(high.getString()) <= 0) {
00322 findDestInTree(&kid, name, obj);
00323 done = gTrue;
00324 }
00325 high.free();
00326 }
00327 low.free();
00328 }
00329 limits.free();
00330 }
00331 kid.free();
00332 }
00333 }
00334 kids.free();
00335
00336
00337 if (!done)
00338 obj->initNull();
00339
00340 return obj;
00341 }