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

  1. //========================================================================
  2. //
  3. // Link.cc
  4. //
  5. // Copyright 1996 Derek B. Noonburg
  6. //
  7. //========================================================================
  8. //
  9. // Ported to EPOC by Sander van der Wal
  10. //
  11. // $Log: Link.cpp $
  12. // Revision 1.3  2000-09-20 20:06:26+02  svdwal
  13. // xpdf 0.91 changes added
  14. //
  15. // Revision 1.2  2000-09-17 13:38:22+02  svdwal
  16. // Ported
  17. //
  18.  
  19. #ifdef __GNUC__
  20. #pragma implementation
  21. #endif
  22.  
  23. #ifndef __E32DEF_H__
  24. #include <e32def.h> // remove warning about NULL redefinition
  25. #endif
  26.  
  27.  
  28. #include "gmem.h"
  29. #include "GString.h"
  30.  
  31. #include "Error.h"
  32. #include "Object.h"
  33. #include "Array.h"
  34. #include "Dict.h"
  35. #include "Link.h"
  36.  
  37. #include "Pdf.rsg"
  38.  
  39. //------------------------------------------------------------------------
  40.  
  41. static TFileName* getFileSpecName(Object *fileSpecObj);
  42.  
  43.  
  44. //------------------------------------------------------------------------
  45. // LinkAction
  46. //------------------------------------------------------------------------
  47. LinkAction* LinkAction::NewL(Object* aActionObj, GString *aBaseURI)
  48. {
  49.   RAutoObject obj1, obj2;
  50.  
  51.   aActionObj->dictLookupL("S", &obj1);
  52.  
  53.   if (obj1.isName("GoTo")) {
  54.     aActionObj->dictLookupL("D", &obj2);
  55.     return LinkGoTo::NewL(&obj2);
  56.   } 
  57.   else if (obj1.isName("GoToR")) {
  58.     RAutoObject obj3;
  59.     aActionObj->dictLookupL("F", &obj2);
  60.     aActionObj->dictLookupL("D", &obj3);
  61.     return LinkGoToR::NewL(&obj2, &obj3);
  62.   }
  63.   else if (obj1.isName("Launch")) {
  64.     return LinkLaunch::NewL(aActionObj);
  65.   } 
  66.   else if (obj1.isName("URI")) {
  67.     aActionObj->dictLookupL("URI", &obj2);
  68.     return LinkURI::NewL(&obj2, aBaseURI);
  69.   } 
  70.   else if (obj1.isName("Thread")    ||
  71.            obj1.isName("Sound")     ||
  72.            obj1.isName("Movie")     ||
  73.            obj1.isName("SetState")  ||
  74.            obj1.isName("Hide")      ||
  75.            obj1.isName("Named")     ||
  76.            obj1.isName("SubmitForm")|| 
  77.            obj1.isName("ResetForm") ||
  78.            obj1.isName("ImportData")||
  79.            obj1.isName("JavaScript")) {
  80.     return LinkUnknown::NewL(obj1.getName());
  81.   }
  82.   else 
  83.     // action is missing or wrong type
  84.     return 0;
  85. }
  86.  
  87. //------------------------------------------------------------------------
  88. // LinkDest
  89. //------------------------------------------------------------------------
  90. LinkDest::LinkDest() {}
  91.  
  92.  
  93. void LinkDest::ConstructL(Array *a, GBool pageIsRef1) {
  94.   RAutoObject obj1, obj2;
  95.  
  96.   // initialize fields
  97.   pageIsRef = pageIsRef1;
  98.   left = bottom = right = top = zoom = 0;
  99.   ok = gFalse;
  100.  
  101.   // get page
  102.   if (pageIsRef) {
  103.     if (!a->getNFL(0, &obj1)->isRef()) {
  104.       error(-1, R_BAD_ANNOTATION_DESTINATION);
  105.       goto err2;
  106.     }
  107.     pageRef.num = obj1.getRefNum();
  108.     pageRef.gen = obj1.getRefGen();
  109.     obj1.free();
  110.   } else {
  111.     if (!a->getL(0, &obj1)->isInt()) {
  112.       error(-1, R_BAD_ANNOTATION_DESTINATION);
  113.       goto err2;
  114.     }
  115.     pageNum = obj1.getInt() + 1;
  116.     obj1.free();
  117.   }
  118.  
  119.   // get destination type
  120.   a->getL(1, &obj1);
  121.  
  122.   // XYZ link
  123.   if (obj1.isName("XYZ")) {
  124.     kind = destXYZ;
  125.     a->getL(2, &obj2);
  126.     if (obj2.isNull()) {
  127.       changeLeft = gFalse;
  128.     } else if (obj2.isNum()) {
  129.       changeLeft = gTrue;
  130.       left = obj2.getNum();
  131.     } else {
  132.       error(-1, R_BAD_ANNOTATION_DESTINATION_POSITION);
  133.       goto err1;
  134.     }
  135.     obj2.free();
  136.     a->getL(3, &obj2);
  137.     if (obj2.isNull()) {
  138.       changeTop = gFalse;
  139.     } else if (obj2.isNum()) {
  140.       changeTop = gTrue;
  141.       top = obj2.getNum();
  142.     } else {
  143.       error(-1, R_BAD_ANNOTATION_DESTINATION_POSITION);
  144.       goto err1;
  145.     }
  146.     obj2.free();
  147.     a->getL(4, &obj2);
  148.     if (obj2.isNull()) {
  149.       changeZoom = gFalse;
  150.     } else if (obj2.isNum()) {
  151.       changeZoom = gTrue;
  152.       zoom = obj2.getNum();
  153.     } else {
  154.       error(-1, R_BAD_ANNOTATION_DESTINATION_POSITION);
  155.       goto err1;
  156.     }
  157.     obj2.free();
  158.  
  159.   // Fit link
  160.   } else if (obj1.isName("Fit")) {
  161.     kind = destFit;
  162.  
  163.   // FitH link
  164.   } else if (obj1.isName("FitH")) {
  165.     kind = destFitH;
  166.     if (!a->getL(2, &obj2)->isNum()) {
  167.       error(-1, R_BAD_ANNOTATION_DESTINATION_POSITION);
  168.       goto err1;
  169.     }
  170.     top = obj2.getNum();
  171.     obj2.free();
  172.  
  173.   // FitV link
  174.   } else if (obj1.isName("FitV")) {
  175.     kind = destFitV;
  176.     if (!a->getL(2, &obj2)->isNum()) {
  177.       error(-1, R_BAD_ANNOTATION_DESTINATION_POSITION);
  178.       goto err1;
  179.     }
  180.     left = obj2.getNum();
  181.     obj2.free();
  182.  
  183.   // FitR link
  184.   } else if (obj1.isName("FitR")) {
  185.     kind = destFitR;
  186.     if (!a->getL(2, &obj2)->isNum()) {
  187.       error(-1, R_BAD_ANNOTATION_DESTINATION_POSITION);
  188.       goto err1;
  189.     }
  190.     left = obj2.getNum();
  191.     obj2.free();
  192.     if (!a->getL(3, &obj2)->isNum()) {
  193.       error(-1, R_BAD_ANNOTATION_DESTINATION_POSITION);
  194.       goto err1;
  195.     }
  196.     bottom = obj2.getNum();
  197.     obj2.free();
  198.     if (!a->getL(4, &obj2)->isNum()) {
  199.       error(-1, R_BAD_ANNOTATION_DESTINATION_POSITION);
  200.       goto err1;
  201.     }
  202.     right = obj2.getNum();
  203.     obj2.free();
  204.     if (!a->getL(5, &obj2)->isNum()) {
  205.       error(-1, R_BAD_ANNOTATION_DESTINATION_POSITION);
  206.       goto err1;
  207.     }
  208.     top = obj2.getNum();
  209.     obj2.free();
  210.  
  211.   // FitB link
  212.   } else if (obj1.isName("FitB")) {
  213.     kind = destFitB;
  214.  
  215.   // FitBH link
  216.   } else if (obj1.isName("FitBH")) {
  217.     kind = destFitBH;
  218.     if (!a->getL(2, &obj2)->isNum()) {
  219.       error(-1, R_BAD_ANNOTATION_DESTINATION_POSITION);
  220.       goto err1;
  221.     }
  222.     top = obj2.getNum();
  223.     obj2.free();
  224.  
  225.   // FitBV link
  226.   } else if (obj1.isName("FitBV")) {
  227.     kind = destFitBV;
  228.     if (!a->getL(2, &obj2)->isNum()) {
  229.       error(-1, R_BAD_ANNOTATION_DESTINATION_POSITION);
  230.       goto err1;
  231.     }
  232.     left = obj2.getNum();
  233.     obj2.free();
  234.  
  235.   // unknown link kind
  236.   } else {
  237.     error(-1, R_UNKNOWN_ANNOTATION_DESTINATION_TYPE);
  238.     goto err2;
  239.   }
  240.  
  241.   obj1.free();
  242.   ok = gTrue;
  243.   return;
  244.  
  245.  err1:
  246.   obj2.free();
  247.  err2:
  248.   obj1.free();
  249. }
  250.  
  251.  
  252. LinkDest::LinkDest(LinkDest *dest) {
  253.   kind = dest->kind;
  254.   pageIsRef = dest->pageIsRef;
  255.   if (pageIsRef)
  256.     pageRef = dest->pageRef;
  257.   else
  258.     pageNum = dest->pageNum;
  259.   left = dest->left;
  260.   bottom = dest->bottom;
  261.   right = dest->right;
  262.   top = dest->top;
  263.   zoom = dest->zoom;
  264.   changeLeft = dest->changeLeft;
  265.   changeTop = dest->changeTop;
  266.   changeZoom = dest->changeZoom;
  267.   ok = gTrue;
  268. }
  269.  
  270. //------------------------------------------------------------------------
  271. // LinkGoTo
  272. //------------------------------------------------------------------------
  273.  
  274. void LinkGoTo::ConstructL(Object *destObj) {
  275.  
  276.   // named destination
  277.   if (destObj->isName()) {
  278.     namedDest = GString::NewL(destObj->getName());
  279.   } else if (destObj->isString()) {
  280.     namedDest = destObj->getString()->copyL();
  281.  
  282.   // destination dictionary
  283.   } else if (destObj->isArray()) {
  284.     dest = new(ELeave) LinkDest();
  285.     dest->ConstructL(destObj->getArray(), gTrue);
  286.     if (!dest->isOk()) {
  287.       delete dest;
  288.       dest = NULL;
  289.     }
  290.  
  291.   // error
  292.   } else {
  293.     error(-1, R_ILLEGAL_ANNOTATION_DESTINATION);
  294.   }
  295. }
  296.  
  297. LinkGoTo* LinkGoTo::NewL(Object *destObj)
  298. {
  299.   LinkGoTo* self = new(ELeave) LinkGoTo();
  300.   CleanupStack::PushL(self);
  301.   self->ConstructL(destObj);
  302.   CleanupStack::Pop(); // self
  303.   return self;
  304. }
  305.  
  306. LinkGoTo::~LinkGoTo() {
  307.   delete dest;
  308.   delete namedDest;
  309. }
  310.  
  311. //------------------------------------------------------------------------
  312. // LinkGoToR
  313. //------------------------------------------------------------------------
  314.  
  315. void LinkGoToR::ConstructL(Object *fileSpecObj, Object *destObj) {
  316.  
  317.   // get file name
  318.   fileName = getFileSpecName(fileSpecObj);
  319.  
  320.   // named destination
  321.   if (destObj->isName()) {
  322.     namedDest = GString::NewL(destObj->getName());
  323.   } else if (destObj->isString()) {
  324.     namedDest = destObj->getString()->copyL();
  325.  
  326.   // destination dictionary
  327.   } else if (destObj->isArray()) {
  328.     dest = new(ELeave) LinkDest();
  329.     dest->ConstructL(destObj->getArray(), gFalse);
  330.     if (!dest->isOk()) {
  331.       delete dest;
  332.       dest = NULL;
  333.     }
  334.  
  335.   // error
  336.   } else {
  337.     error(-1, R_ILLEGAL_ANNOTATION_DESTINATION);
  338.   }
  339. }
  340.  
  341. LinkGoToR* LinkGoToR::NewL(Object *fileSpecObj,Object *destObj)
  342. {
  343.   LinkGoToR* self = new(ELeave) LinkGoToR();
  344.   CleanupStack::PushL(self);
  345.   self->ConstructL(fileSpecObj, destObj);
  346.   CleanupStack::Pop(); // self
  347.   return self;
  348. }
  349.  
  350. LinkGoToR::~LinkGoToR() {
  351.   delete fileName;
  352.   delete dest;
  353.   delete namedDest;
  354. }
  355.  
  356.  
  357. //------------------------------------------------------------------------
  358. // LinkLaunch
  359. //------------------------------------------------------------------------
  360.  
  361. void LinkLaunch::ConstructL(Object *actionObj) {
  362.   RAutoObject obj1, obj2;
  363.  
  364.   if (actionObj->isDict()) {
  365.     if (!actionObj->dictLookupL("F", &obj1)->isNull()) {
  366.       fileName = getFileSpecName(&obj1);
  367.     } else {
  368.       obj1.free();
  369.       //~ This hasn't been defined by Adobe yet, so assume it looks
  370.       //~ just like the Win dictionary until they say otherwise.
  371.       if (actionObj->dictLookupL("Unix", &obj1)->isDict()) {
  372.     obj1.dictLookupL("F", &obj2);
  373.     fileName = getFileSpecName(&obj2);
  374.     obj2.free();
  375.     if (obj1.dictLookupL("P", &obj2)->isString())
  376.       params = obj2.getString()->copyL();
  377.     obj2.free();
  378.       } else {
  379.     error(-1, R_BAD_LAUNCH_TYPE_LINK_ACTION);
  380.       }
  381.     }
  382.     obj1.free();
  383.   }
  384. }
  385.  
  386. LinkLaunch* LinkLaunch::NewL(Object *actionObj)
  387. {
  388.   LinkLaunch* self = new(ELeave) LinkLaunch();
  389.   CleanupStack::PushL(self);
  390.   self->ConstructL(actionObj);
  391.   CleanupStack::Pop(); // self
  392.   return self;
  393. }
  394.  
  395. LinkLaunch::~LinkLaunch() {
  396.   delete fileName;
  397.   delete params;
  398. }
  399.  
  400. //------------------------------------------------------------------------
  401. // LinkURI
  402. //------------------------------------------------------------------------
  403.  
  404. void LinkURI::ConstructL(Object *uriObj, GString *baseURI) {
  405.   GString *uri2;
  406.   int n;
  407.   char c;
  408.  
  409.   if (uriObj->isString()) {
  410.     uri2 = uriObj->getString()->copyL();
  411.     if (baseURI) {
  412.       n = strcspn(uri2->getCString(), "/:");
  413.       if (n == uri2->getLength() || uri2->getChar(n) == '/') {
  414.         CleanupStack::PushL(uri2);
  415.         uri = baseURI->copyL();
  416.         c = uri->getChar(uri->getLength() - 1);
  417.         if (c == '/' || c == '?') {
  418.           if (uri2->getChar(0) == '/') {
  419.             uri2->delL(0);
  420.           }
  421.         } 
  422.         else {
  423.           if (uri2->getChar(0) != '/') {
  424.            uri->appendL('/');
  425.           }
  426.         }
  427.         uri->appendL(uri2);
  428.         CleanupStack::PopAndDestroy(); // delete uri2;
  429.       } 
  430.       else {
  431.         uri = uri2;
  432.       }
  433.     } 
  434.     else {
  435.       uri = uri2;
  436.     }
  437.   } 
  438.   else {
  439.     error(-1, R_ILLEGAL_URI_TYPE_LINK);
  440.   }
  441. }
  442.  
  443. LinkURI* LinkURI::NewL(Object *uriObj, GString *baseURI)
  444. {
  445.   LinkURI* self = new(ELeave) LinkURI();
  446.   CleanupStack::PushL(self);
  447.   self->ConstructL(uriObj, baseURI);
  448.   CleanupStack::Pop(); // self
  449.   return self;
  450. }
  451.  
  452. LinkURI::~LinkURI() {
  453.   delete uri;
  454. }
  455.  
  456. //------------------------------------------------------------------------
  457. // LinkUnknown
  458. //------------------------------------------------------------------------
  459.  
  460. void LinkUnknown::ConstructL(char *action1) {
  461.   action = GString::NewL(action1);
  462. }
  463.  
  464. LinkUnknown* LinkUnknown::NewL(char *action1)
  465. {
  466.   LinkUnknown* self = new(ELeave) LinkUnknown();
  467.   CleanupStack::PushL(self);
  468.   self->ConstructL(action1);
  469.   CleanupStack::Pop(); // self
  470.   return self;
  471. }
  472.  
  473. LinkUnknown::~LinkUnknown() {
  474.   delete action;
  475. }
  476.  
  477. //------------------------------------------------------------------------
  478. // Link
  479. //------------------------------------------------------------------------
  480.  
  481. void Link::ConstructL(Dict *dict, GString *baseURI) {
  482.   RAutoObject obj1, obj2;
  483.   double t;
  484.  
  485.   action = NULL;
  486.   ok = gFalse;
  487.  
  488.   // get rectangle
  489.   if (!dict->lookupL("Rect", &obj1)->isArray()) {
  490.     error(-1, R_ANNOTATION_RECTANGLE_IS_WRONG_TYPE);
  491.     goto err2;
  492.   }
  493.   if (!obj1.arrayGetL(0, &obj2)->isNum()) {
  494.     error(-1, R_BAD_ANNOTATION_RECTANGLE);
  495.     goto err1;
  496.   }
  497.   x1 = obj2.getNum();
  498.   obj2.free();
  499.   if (!obj1.arrayGetL(1, &obj2)->isNum()) {
  500.     error(-1, R_BAD_ANNOTATION_RECTANGLE);
  501.     goto err1;
  502.   }
  503.   y1 = obj2.getNum();
  504.   obj2.free();
  505.   if (!obj1.arrayGetL(2, &obj2)->isNum()) {
  506.     error(-1, R_BAD_ANNOTATION_RECTANGLE);
  507.     goto err1;
  508.   }
  509.   x2 = obj2.getNum();
  510.   obj2.free();
  511.   if (!obj1.arrayGetL(3, &obj2)->isNum()) {
  512.     error(-1, R_BAD_ANNOTATION_RECTANGLE);
  513.     goto err1;
  514.   }
  515.   y2 = obj2.getNum();
  516.   obj2.free();
  517.   obj1.free();
  518.   if (x1 > x2) {
  519.     t = x1;
  520.     x1 = x2;
  521.     x2 = t;
  522.   }
  523.   if (y1 > y2) {
  524.     t = y1;
  525.     y1 = y2;
  526.     y2 = t;
  527.   }
  528.  
  529.   // get border
  530.   borderW = 0;
  531.   if (!dict->lookupL("Border", &obj1)->isNull()) {
  532.     if (obj1.isArray() && obj1.arrayGetL(2, &obj2)->isNum())
  533.       borderW = obj2.getNum();
  534.     else
  535.       error(-1, R_BAD_ANNOTATION_BORDER);
  536.     obj2.free();
  537.   }
  538.   obj1.free();
  539.  
  540.   // look for destination
  541.   if (!dict->lookupL("Dest", &obj1)->isNull()) {
  542.     action = LinkGoTo::NewL(&obj1);
  543.   } 
  544.   else { // look for action
  545.     obj1.free();
  546.     if (dict->lookupL("A", &obj1)->isDict()) {
  547.       action = LinkAction::NewL(&obj1, baseURI);
  548.     } else {
  549.       error(-1, R_MISSING_ANNOTATION_DESTINATION_ACTION);
  550.       action = NULL;
  551.     }
  552.   }
  553.   obj1.free();
  554.  
  555.   // check for bad action
  556.   if (action && action->isOk())
  557.     ok = gTrue;
  558.  
  559.   return;
  560.  
  561.  err1:
  562.   obj2.free();
  563.  err2:
  564.   obj1.free();
  565. }
  566.  
  567. Link::~Link() {
  568.   delete action;
  569. }
  570.  
  571. //------------------------------------------------------------------------
  572. // Links
  573. //------------------------------------------------------------------------
  574.  
  575. void Links::ConstructL(Object *annots, GString *baseURI) {
  576.   Link *link;
  577.   RAutoObject obj1, obj2;
  578.   int size=0;
  579.   int i;
  580.  
  581.   if (annots->isArray()) {
  582.     for (i = 0; i < annots->arrayGetLength(); ++i) {
  583.       if (annots->arrayGetL(i, &obj1)->isDict()) {
  584.     if (obj1.dictLookupL("Subtype", &obj2)->isName("Link")) {
  585.       link = new(ELeave) Link();
  586.           CleanupStack::PushL(link);
  587.           link->ConstructL(obj1.getDict(), baseURI);
  588.       if (link->isOk()) {
  589.         if (numLinks >= size) {
  590.           size += 16;
  591.               links = (Link **)User::ReAllocL(links, size * sizeof(Link *));
  592.         }
  593.             CleanupStack::Pop(); // link
  594.         links[numLinks++] = link;
  595.       } else {
  596.             CleanupStack::PopAndDestroy(); // delete link;
  597.       }
  598.     }
  599.     obj2.free();
  600.       }
  601.       obj1.free();
  602.     }
  603.   }
  604. }
  605.  
  606. Links::~Links() {
  607.   int i;
  608.   if (links) {
  609.     for (i = 0; i < numLinks; ++i)
  610.       delete links[i];
  611.   }
  612.   User::Free(links);
  613. }
  614.  
  615. LinkAction *Links::find(double x, double y) {
  616.   int i;
  617.  
  618.   for (i = 0; i < numLinks; ++i) {
  619.     if (links[i]->inRect(x, y)) {
  620.       return links[i]->getAction();
  621.     }
  622.   }
  623.   return NULL;
  624. }
  625.  
  626. GBool Links::onLink(double x, double y) {
  627.   int i;
  628.  
  629.   for (i = 0; i < numLinks; ++i) {
  630.     if (links[i]->inRect(x, y))
  631.       return gTrue;
  632.   }
  633.   return gFalse;
  634. }
  635.  
  636. //------------------------------------------------------------------------
  637.  
  638. // Extract a file name from a file specification (string or dictionary).
  639. static TFileName* getFileSpecName(Object *fileSpecObj) {
  640.   TFileName *name;
  641.   RAutoObject obj1;
  642.  
  643.   name = NULL;
  644.  
  645.   // string
  646.   if (fileSpecObj->isString()) {
  647.     name = new(ELeave) TFileName((const TText8*) fileSpecObj->getString()->getCString());
  648.  
  649.   // dictionary
  650.   } else if (fileSpecObj->isDict()) {
  651.     if (!fileSpecObj->dictLookupL("Unix", &obj1)->isString()) {
  652.       obj1.free();
  653.       fileSpecObj->dictLookupL("F", &obj1);
  654.     }
  655.     if (obj1.isString())
  656.       name = new(ELeave) TFileName((const TText8*)obj1.getString()->getCString());
  657.     else
  658.       error(-1, R_ILLEGAL_FILE_SPEC_IN_LINK);
  659.     obj1.free();
  660.  
  661.   // error
  662.   } else {
  663.     error(-1, R_ILLEGAL_FILE_SPEC_IN_LINK);
  664.   }
  665.  
  666.   return name;
  667. }
  668.