home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 110 / EnigmaAmiga110CD.iso / indispensabili / utility / apdf / xpdf-0.80 / xpdf / link.cc < prev    next >
C/C++ Source or Header  |  1998-11-27  |  13KB  |  582 lines

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