home *** CD-ROM | disk | FTP | other *** search
/ PSION CD 2 / PsionCDVol2.iso / Programs / 720 / PDF090B4-SorceCode / pdf / Catalog.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-30  |  7.6 KB  |  325 lines

  1. //========================================================================
  2. //
  3. // Catalog.cc
  4. //
  5. // Copyright 1996 Derek B. Noonburg
  6. //
  7. //========================================================================
  8. //
  9. // Ported to EPOC by Sander van der Wal
  10. //
  11. // $Log: Catalog.cpp $
  12. // Revision 1.3  2000-09-20 20:41:55+02  svdwal
  13. // some bugfixes from xpdf 0.91
  14. //
  15. // Revision 1.2  2000-09-17 13:38:25+02  svdwal
  16. // Ported
  17. //
  18.  
  19. #ifdef __GNUC__
  20. #pragma implementation
  21. #endif
  22.  
  23. // --o GooLib
  24. #include "gmem.h"
  25.  
  26. // --o Pdf
  27. #include "Object.h"
  28. #include "Array.h"
  29. #include "Dict.h"
  30. #include "Page.h"
  31. #include "Error.h"
  32. #include "Link.h"
  33. #include "Catalog.h"
  34.  
  35. // --o Pdf
  36. #include "Pdf.rsg"
  37.  
  38.  
  39.  
  40. //------------------------------------------------------------------------
  41. // Catalog
  42. //------------------------------------------------------------------------
  43.  
  44. Catalog::Catalog() {
  45.   ok = gTrue;
  46. }
  47.  
  48. void Catalog::ConstructL(Object *catDict)
  49. {
  50.   RAutoObject pagesDict;
  51.   RAutoObject obj;
  52.   int i;
  53.  
  54.   ok = gFalse;
  55.   if (!catDict->isDict()) {
  56.     error(-1, R_CATALOG_OBJECT_IS_WRONG_TYPE___S_, catDict->getTypeName());
  57.     goto err1;
  58.   }
  59.  
  60.   // read page tree
  61.  
  62.   catDict->dictLookupL("Pages", &pagesDict);
  63.   // This should really be isDict("Pages"), but I've seen at least one
  64.   // PDF file where the /Type entry is missing.
  65.   if (!pagesDict.isDict()) {
  66.     error(-1, R_TOP_LEVEL_PAGES_OBJECT_IS_WRONG_TYPE___S_, pagesDict.getTypeName());
  67.     goto err2;
  68.   }
  69.  
  70.   pagesDict.dictLookupL("Count", &obj);
  71.   if (!obj.isInt()) {
  72.     error(-1, R_PAGE_COUNT_IN_TOP_LEVEL_PAGES_OBJECT_IS_WRONG_TYPE___S_, obj.getTypeName());
  73.     goto err3;
  74.   }
  75.   numPages = obj.getInt();
  76.   obj.free();
  77.   pageRefs = (Ref *)User::AllocL(numPages * sizeof(Ref));
  78.   pages = (Page **)User::AllocL(numPages * sizeof(Page *));
  79.   for (i = 0; i < numPages; ++i) {
  80.     pages[i] = 0;
  81.     pageRefs[i].num = -1;
  82.     pageRefs[i].gen = -1;
  83.   }
  84.   readPageTree(pagesDict.getDict(), 0, 0);
  85.   pagesDict.free();
  86.  
  87.   // read named destination dictionary
  88.   catDict->dictLookupL("Dests", &dests);
  89.  
  90.   // read root of named destination tree
  91.   if (catDict->dictLookupL("Names", &obj)->isDict())
  92.     obj.dictLookupL("Dests", &nameTree);
  93.   else
  94.     nameTree.initNull();
  95.   obj.free();
  96.  
  97.   // read base URI
  98.   
  99.   if (catDict->dictLookupL("URI", &obj)->isDict()) {
  100.     RAutoObject obj2;
  101.     if (obj.dictLookupL("Base", &obj2)->isString()) {
  102.       baseURI = obj2.getString()->copyL();
  103.     }
  104.     obj2.free();
  105.   }
  106.   obj.free();
  107.  
  108.   ok = gTrue;
  109.   return;
  110.  
  111.  err3:
  112.   obj.free();
  113.  err2:
  114.   pagesDict.free();
  115.  err1:
  116.   dests.initNull();
  117.   nameTree.initNull();
  118.   ok = gFalse;
  119. }
  120.  
  121. Catalog::~Catalog() {
  122.   int i;
  123.  
  124.   if (pages) {
  125.     for (i = 0; i < numPages; ++i) {
  126.       delete pages[i];
  127.     }
  128.     User::Free(pages);
  129.   }
  130.   User::Free(pageRefs);
  131.   dests.free();
  132.   nameTree.free();
  133.   delete baseURI;
  134. }
  135.  
  136. int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
  137.   RAutoObject kids;
  138.   RAutoObject kid;
  139.   RAutoObject kidRef;
  140.   PageAttrs *attrs1, *attrs2;
  141.   Page *page;
  142.   int i;
  143.  
  144.   attrs1 = new(ELeave) PageAttrs();
  145.   CleanupStack::PushL(attrs1);
  146.   attrs1->ConstructL(attrs, pagesDict);
  147.   pagesDict->lookupL("Kids", &kids);
  148.   if (!kids.isArray()) {
  149.     error(-1, R_KIDS_OBJECT__PAGE__D__IS_WRONG_TYPE___S_, start+1, kids.getTypeName());
  150.     goto err1;
  151.   }
  152.   for (i = 0; i < kids.arrayGetLength(); ++i) {
  153.     kids.arrayGetL(i, &kid);
  154.     if (kid.isDict("Page")) {
  155.       
  156.       attrs2 = new(ELeave) PageAttrs();
  157.       CleanupStack::PushL(attrs2);
  158.       attrs2->ConstructL(attrs1, kid.getDict());
  159.       
  160.       page = new(ELeave) Page(start+1, attrs2);
  161.       CleanupStack::Pop(); // attrs2
  162.       CleanupStack::PushL(page);
  163.       page->ConstructL(kid.getDict());
  164.       if (!page->isOk()) {
  165.         ++start;
  166.         goto err3;
  167.       }
  168.       CleanupStack::Pop(); // page
  169.       pages[start] = page;
  170.       kids.arrayGetNFL(i, &kidRef);
  171.       if (kidRef.isRef()) {
  172.         pageRefs[start].num = kidRef.getRefNum();
  173.         pageRefs[start].gen = kidRef.getRefGen();
  174.       }
  175.       kidRef.free();
  176.       ++start;
  177.     // This should really be isDict("Pages"), but I've seen at least one
  178.     // PDF file where the /Type entry is missing.
  179.     } else if (kid.isDict()) {
  180.       if ((start = readPageTree(kid.getDict(), attrs1, start)) < 0)
  181.         goto err2;
  182.     } else {
  183.       error(-1, R_KID_OBJECT__PAGE__D__IS_WRONG_TYPE___S_, start+1, kid.getTypeName());
  184.       goto err2;
  185.     }
  186.     kid.free();
  187.   }
  188.   CleanupStack::PopAndDestroy(); // delete attrs1;
  189.   kids.free();
  190.   return start;
  191.  
  192.  err3:
  193.   CleanupStack::PopAndDestroy(); // delete page;
  194.  err2:
  195.   kid.free();
  196.  err1:
  197.   kids.free();
  198.   CleanupStack::PopAndDestroy(); // delete attrs1;
  199.   ok = gFalse;
  200.   return -1;
  201. }
  202.  
  203.  
  204. int Catalog::findPage(int num, int gen) {
  205.   int i;
  206.  
  207.   for (i = 0; i < numPages; ++i) {
  208.     if (pageRefs[i].num == num && pageRefs[i].gen == gen)
  209.       return i + 1;
  210.   }
  211.   return 0;
  212. }
  213.  
  214.  
  215. LinkDest *Catalog::findDestL(GString *name) {
  216.   LinkDest *dest;
  217.   RAutoObject obj1;
  218.   GBool found;
  219.  
  220.   // try named destination dictionary then name tree
  221.   found = gFalse;
  222.   if (dests.isDict()) {
  223.     if (!dests.dictLookupL(name->getCString(), &obj1)->isNull())
  224.       found = gTrue;
  225.     else
  226.       obj1.free();
  227.   }
  228.   if (!found && nameTree.isDict()) {
  229.     if (!findDestInTreeL(&nameTree, name, &obj1)->isNull())
  230.       found = gTrue;
  231.     else
  232.       obj1.free();
  233.   }
  234.   if (!found)
  235.     return 0;
  236.  
  237.   // construct LinkDest
  238.   dest = 0;
  239.   if (obj1.isArray()) {
  240.     dest = new(ELeave) LinkDest();
  241.     CleanupStack::PushL(dest);
  242.     dest->ConstructL(obj1.getArray(), gTrue);
  243.     CleanupStack::Pop(); // dest
  244.   } 
  245.   else if (obj1.isDict()) {
  246.     RAutoObject obj2;
  247.     if (obj1.dictLookupL("D", &obj2)->isArray()) {
  248.       dest = new(ELeave) LinkDest();
  249.       CleanupStack::PushL(dest);
  250.       dest->ConstructL(obj2.getArray(), gTrue);
  251.       CleanupStack::Pop(); // dest
  252.     }
  253.     else
  254.       error(-1, R_BAD_NAMED_DESTINATION_VALUE);
  255.     obj2.free();
  256.   } 
  257.   else {
  258.     error(-1, R_BAD_NAMED_DESTINATION_VALUE);
  259.   }
  260.   obj1.free();
  261.  
  262.   return dest;
  263. }
  264.  
  265.  
  266. Object *Catalog::findDestInTreeL(Object *tree, GString *name, Object *obj) {
  267.   RAutoObject names, name1;
  268.   RAutoObject kids, kid, limits, low, high;
  269.   GBool done, found;
  270.   int cmp, i;
  271.  
  272.   // leaf node
  273.   if (tree->dictLookupL("Names", &names)->isArray()) {
  274.     done = found = gFalse;
  275.     for (i = 0; !done && i < names.arrayGetLength(); i += 2) {
  276.       if (names.arrayGetL(i, &name1)->isString()) {
  277.     cmp = name->cmp(name1.getString());
  278.     if (cmp == 0) {
  279.       names.arrayGetL(i+1, obj);
  280.       found = gTrue;
  281.       done = gTrue;
  282.     } else if (cmp < 0) {
  283.       done = gTrue;
  284.     }
  285.     name1.free();
  286.       }
  287.     }
  288.     names.free();
  289.     if (!found)
  290.       obj->initNull();
  291.     return obj;
  292.   }
  293.   names.free();
  294.  
  295.   // root or intermediate node
  296.   done = gFalse;
  297.   if (tree->dictLookupL("Kids", &kids)->isArray()) {
  298.     for (i = 0; !done && i < kids.arrayGetLength(); ++i) {
  299.       if (kids.arrayGetL(i, &kid)->isDict()) {
  300.         if (kid.dictLookupL("Limits", &limits)->isArray()) {
  301.           if (limits.arrayGetL(0, &low)->isString() &&
  302.               name->cmp(low.getString()) >= 0) {
  303.             if (limits.arrayGetL(1, &high)->isString() &&
  304.                 name->cmp(high.getString()) <= 0) {
  305.               findDestInTreeL(&kid, name, obj);
  306.               done = gTrue;
  307.             }
  308.             high.free();
  309.           }
  310.           low.free();
  311.         }
  312.         limits.free();
  313.       }
  314.       kid.free();
  315.     }
  316.   }
  317.   kids.free();
  318.  
  319.   // name was outside of ranges of all kids
  320.   if (!done)
  321.     obj->initNull();
  322.  
  323.   return obj;
  324. }
  325.