filters

Link.cc

00001 //========================================================================
00002 //
00003 // Link.cc
00004 //
00005 // Copyright 1996-2002 Glyph & Cog, LLC
00006 //
00007 //========================================================================
00008 
00009 #include <aconf.h>
00010 
00011 #ifdef USE_GCC_PRAGMAS
00012 #pragma implementation
00013 #endif
00014 
00015 #include <stddef.h>
00016 #include <string.h>
00017 #include "gmem.h"
00018 #include "GString.h"
00019 #include "Error.h"
00020 #include "Object.h"
00021 #include "Array.h"
00022 #include "Dict.h"
00023 #include "Link.h"
00024 
00025 //------------------------------------------------------------------------
00026 // LinkAction
00027 //------------------------------------------------------------------------
00028 
00029 LinkAction *LinkAction::parseDest(Object *obj) {
00030   LinkAction *action;
00031 
00032   action = new LinkGoTo(obj);
00033   if (!action->isOk()) {
00034     delete action;
00035     return NULL;
00036   }
00037   return action;
00038 }
00039 
00040 LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) {
00041   LinkAction *action;
00042   Object obj2, obj3, obj4;
00043 
00044   if (!obj->isDict()) {
00045     error(-1, "Bad annotation action");
00046     return NULL;
00047   }
00048 
00049   obj->dictLookup("S", &obj2);
00050 
00051   // GoTo action
00052   if (obj2.isName("GoTo")) {
00053     obj->dictLookup("D", &obj3);
00054     action = new LinkGoTo(&obj3);
00055     obj3.free();
00056 
00057   // GoToR action
00058   } else if (obj2.isName("GoToR")) {
00059     obj->dictLookup("F", &obj3);
00060     obj->dictLookup("D", &obj4);
00061     action = new LinkGoToR(&obj3, &obj4);
00062     obj3.free();
00063     obj4.free();
00064 
00065   // Launch action
00066   } else if (obj2.isName("Launch")) {
00067     action = new LinkLaunch(obj);
00068 
00069   // URI action
00070   } else if (obj2.isName("URI")) {
00071     obj->dictLookup("URI", &obj3);
00072     action = new LinkURI(&obj3, baseURI);
00073     obj3.free();
00074 
00075   // Named action
00076   } else if (obj2.isName("Named")) {
00077     obj->dictLookup("N", &obj3);
00078     action = new LinkNamed(&obj3);
00079     obj3.free();
00080 
00081   // Movie action
00082   } else if (obj2.isName("Movie")) {
00083     obj->dictLookupNF("Annot", &obj3);
00084     obj->dictLookup("T", &obj4);
00085     action = new LinkMovie(&obj3, &obj4);
00086     obj3.free();
00087     obj4.free();
00088 
00089   // unknown action
00090   } else if (obj2.isName()) {
00091     action = new LinkUnknown(obj2.getName());
00092 
00093   // action is missing or wrong type
00094   } else {
00095     error(-1, "Bad annotation action");
00096     action = NULL;
00097   }
00098 
00099   obj2.free();
00100 
00101   if (action && !action->isOk()) {
00102     delete action;
00103     return NULL;
00104   }
00105   return action;
00106 }
00107 
00108 GString *LinkAction::getFileSpecName(Object *fileSpecObj) {
00109   GString *name;
00110   Object obj1;
00111 
00112   name = NULL;
00113 
00114   // string
00115   if (fileSpecObj->isString()) {
00116     name = fileSpecObj->getString()->copy();
00117 
00118   // dictionary
00119   } else if (fileSpecObj->isDict()) {
00120     if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) {
00121       obj1.free();
00122       fileSpecObj->dictLookup("F", &obj1);
00123     }
00124     if (obj1.isString())
00125       name = obj1.getString()->copy();
00126     else
00127       error(-1, "Illegal file spec in link");
00128     obj1.free();
00129 
00130   // error
00131   } else {
00132     error(-1, "Illegal file spec in link");
00133   }
00134 
00135   return name;
00136 }
00137 
00138 //------------------------------------------------------------------------
00139 // LinkDest
00140 //------------------------------------------------------------------------
00141 
00142 LinkDest::LinkDest(Array *a) {
00143   Object obj1, obj2;
00144 
00145   // initialize fields
00146   left = bottom = right = top = zoom = 0;
00147   ok = gFalse;
00148 
00149   // get page
00150   if (a->getLength() < 2) {
00151     error(-1, "Annotation destination array has wrong length");
00152     return;
00153   }
00154   a->getNF(0, &obj1);
00155   if (obj1.isInt()) {
00156     pageNum = obj1.getInt() + 1;
00157     pageIsRef = gFalse;
00158   } else if (obj1.isRef()) {
00159     pageRef.num = obj1.getRefNum();
00160     pageRef.gen = obj1.getRefGen();
00161     pageIsRef = gTrue;
00162   } else {
00163     error(-1, "Bad annotation destination");
00164     goto err2;
00165   }
00166   obj1.free();
00167 
00168   // get destination type
00169   a->get(1, &obj1);
00170 
00171   // XYZ link
00172   if (obj1.isName("XYZ")) {
00173     if (a->getLength() != 5) {
00174       error(-1, "Annotation destination array has wrong length");
00175       goto err2;
00176     }
00177     kind = destXYZ;
00178     a->get(2, &obj2);
00179     if (obj2.isNull()) {
00180       changeLeft = gFalse;
00181     } else if (obj2.isNum()) {
00182       changeLeft = gTrue;
00183       left = obj2.getNum();
00184     } else {
00185       error(-1, "Bad annotation destination position");
00186       goto err1;
00187     }
00188     obj2.free();
00189     a->get(3, &obj2);
00190     if (obj2.isNull()) {
00191       changeTop = gFalse;
00192     } else if (obj2.isNum()) {
00193       changeTop = gTrue;
00194       top = obj2.getNum();
00195     } else {
00196       error(-1, "Bad annotation destination position");
00197       goto err1;
00198     }
00199     obj2.free();
00200     a->get(4, &obj2);
00201     if (obj2.isNull()) {
00202       changeZoom = gFalse;
00203     } else if (obj2.isNum()) {
00204       changeZoom = gTrue;
00205       zoom = obj2.getNum();
00206     } else {
00207       error(-1, "Bad annotation destination position");
00208       goto err1;
00209     }
00210     obj2.free();
00211 
00212   // Fit link
00213   } else if (obj1.isName("Fit")) {
00214     if (a->getLength() != 2) {
00215       error(-1, "Annotation destination array has wrong length");
00216       goto err2;
00217     }
00218     kind = destFit;
00219 
00220   // FitH link
00221   } else if (obj1.isName("FitH")) {
00222     if (a->getLength() != 3) {
00223       error(-1, "Annotation destination array has wrong length");
00224       goto err2;
00225     }
00226     kind = destFitH;
00227     if (!a->get(2, &obj2)->isNum()) {
00228       error(-1, "Bad annotation destination position");
00229       goto err1;
00230     }
00231     top = obj2.getNum();
00232     obj2.free();
00233 
00234   // FitV link
00235   } else if (obj1.isName("FitV")) {
00236     if (a->getLength() != 3) {
00237       error(-1, "Annotation destination array has wrong length");
00238       goto err2;
00239     }
00240     kind = destFitV;
00241     if (!a->get(2, &obj2)->isNum()) {
00242       error(-1, "Bad annotation destination position");
00243       goto err1;
00244     }
00245     left = obj2.getNum();
00246     obj2.free();
00247 
00248   // FitR link
00249   } else if (obj1.isName("FitR")) {
00250     if (a->getLength() != 6) {
00251       error(-1, "Annotation destination array has wrong length");
00252       goto err2;
00253     }
00254     kind = destFitR;
00255     if (!a->get(2, &obj2)->isNum()) {
00256       error(-1, "Bad annotation destination position");
00257       goto err1;
00258     }
00259     left = obj2.getNum();
00260     obj2.free();
00261     if (!a->get(3, &obj2)->isNum()) {
00262       error(-1, "Bad annotation destination position");
00263       goto err1;
00264     }
00265     bottom = obj2.getNum();
00266     obj2.free();
00267     if (!a->get(4, &obj2)->isNum()) {
00268       error(-1, "Bad annotation destination position");
00269       goto err1;
00270     }
00271     right = obj2.getNum();
00272     obj2.free();
00273     if (!a->get(5, &obj2)->isNum()) {
00274       error(-1, "Bad annotation destination position");
00275       goto err1;
00276     }
00277     top = obj2.getNum();
00278     obj2.free();
00279 
00280   // FitB link
00281   } else if (obj1.isName("FitB")) {
00282     if (a->getLength() != 2) {
00283       error(-1, "Annotation destination array has wrong length");
00284       goto err2;
00285     }
00286     kind = destFitB;
00287 
00288   // FitBH link
00289   } else if (obj1.isName("FitBH")) {
00290     if (a->getLength() != 3) {
00291       error(-1, "Annotation destination array has wrong length");
00292       goto err2;
00293     }
00294     kind = destFitBH;
00295     if (!a->get(2, &obj2)->isNum()) {
00296       error(-1, "Bad annotation destination position");
00297       goto err1;
00298     }
00299     top = obj2.getNum();
00300     obj2.free();
00301 
00302   // FitBV link
00303   } else if (obj1.isName("FitBV")) {
00304     if (a->getLength() != 3) {
00305       error(-1, "Annotation destination array has wrong length");
00306       goto err2;
00307     }
00308     kind = destFitBV;
00309     if (!a->get(2, &obj2)->isNum()) {
00310       error(-1, "Bad annotation destination position");
00311       goto err1;
00312     }
00313     left = obj2.getNum();
00314     obj2.free();
00315 
00316   // unknown link kind
00317   } else {
00318     error(-1, "Unknown annotation destination type");
00319     goto err2;
00320   }
00321 
00322   obj1.free();
00323   ok = gTrue;
00324   return;
00325 
00326  err1:
00327   obj2.free();
00328  err2:
00329   obj1.free();
00330 }
00331 
00332 LinkDest::LinkDest(LinkDest *dest) {
00333   kind = dest->kind;
00334   pageIsRef = dest->pageIsRef;
00335   if (pageIsRef)
00336     pageRef = dest->pageRef;
00337   else
00338     pageNum = dest->pageNum;
00339   left = dest->left;
00340   bottom = dest->bottom;
00341   right = dest->right;
00342   top = dest->top;
00343   zoom = dest->zoom;
00344   changeLeft = dest->changeLeft;
00345   changeTop = dest->changeTop;
00346   changeZoom = dest->changeZoom;
00347   ok = gTrue;
00348 }
00349 
00350 //------------------------------------------------------------------------
00351 // LinkGoTo
00352 //------------------------------------------------------------------------
00353 
00354 LinkGoTo::LinkGoTo(Object *destObj) {
00355   dest = NULL;
00356   namedDest = NULL;
00357 
00358   // named destination
00359   if (destObj->isName()) {
00360     namedDest = new GString(destObj->getName());
00361   } else if (destObj->isString()) {
00362     namedDest = destObj->getString()->copy();
00363 
00364   // destination dictionary
00365   } else if (destObj->isArray()) {
00366     dest = new LinkDest(destObj->getArray());
00367     if (!dest->isOk()) {
00368       delete dest;
00369       dest = NULL;
00370     }
00371 
00372   // error
00373   } else {
00374     error(-1, "Illegal annotation destination");
00375   }
00376 }
00377 
00378 LinkGoTo::~LinkGoTo() {
00379   if (dest)
00380     delete dest;
00381   if (namedDest)
00382     delete namedDest;
00383 }
00384 
00385 //------------------------------------------------------------------------
00386 // LinkGoToR
00387 //------------------------------------------------------------------------
00388 
00389 LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) {
00390   dest = NULL;
00391   namedDest = NULL;
00392 
00393   // get file name
00394   fileName = getFileSpecName(fileSpecObj);
00395 
00396   // named destination
00397   if (destObj->isName()) {
00398     namedDest = new GString(destObj->getName());
00399   } else if (destObj->isString()) {
00400     namedDest = destObj->getString()->copy();
00401 
00402   // destination dictionary
00403   } else if (destObj->isArray()) {
00404     dest = new LinkDest(destObj->getArray());
00405     if (!dest->isOk()) {
00406       delete dest;
00407       dest = NULL;
00408     }
00409 
00410   // error
00411   } else {
00412     error(-1, "Illegal annotation destination");
00413   }
00414 }
00415 
00416 LinkGoToR::~LinkGoToR() {
00417   if (fileName)
00418     delete fileName;
00419   if (dest)
00420     delete dest;
00421   if (namedDest)
00422     delete namedDest;
00423 }
00424 
00425 
00426 //------------------------------------------------------------------------
00427 // LinkLaunch
00428 //------------------------------------------------------------------------
00429 
00430 LinkLaunch::LinkLaunch(Object *actionObj) {
00431   Object obj1, obj2;
00432 
00433   fileName = NULL;
00434   params = NULL;
00435 
00436   if (actionObj->isDict()) {
00437     if (!actionObj->dictLookup("F", &obj1)->isNull()) {
00438       fileName = getFileSpecName(&obj1);
00439     } else {
00440       obj1.free();
00441 #ifdef WIN32
00442       if (actionObj->dictLookup("Win", &obj1)->isDict()) {
00443     obj1.dictLookup("F", &obj2);
00444     fileName = getFileSpecName(&obj2);
00445     obj2.free();
00446     if (obj1.dictLookup("P", &obj2)->isString()) {
00447       params = obj2.getString()->copy();
00448     }
00449     obj2.free();
00450       } else {
00451     error(-1, "Bad launch-type link action");
00452       }
00453 #else
00454       //~ This hasn't been defined by Adobe yet, so assume it looks
00455       //~ just like the Win dictionary until they say otherwise.
00456       if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
00457     obj1.dictLookup("F", &obj2);
00458     fileName = getFileSpecName(&obj2);
00459     obj2.free();
00460     if (obj1.dictLookup("P", &obj2)->isString()) {
00461       params = obj2.getString()->copy();
00462     }
00463     obj2.free();
00464       } else {
00465     error(-1, "Bad launch-type link action");
00466       }
00467 #endif
00468     }
00469     obj1.free();
00470   }
00471 }
00472 
00473 LinkLaunch::~LinkLaunch() {
00474   if (fileName)
00475     delete fileName;
00476   if (params)
00477     delete params;
00478 }
00479 
00480 //------------------------------------------------------------------------
00481 // LinkURI
00482 //------------------------------------------------------------------------
00483 
00484 LinkURI::LinkURI(Object *uriObj, GString *baseURI) {
00485   GString *uri2;
00486   int n;
00487   char c;
00488 
00489   uri = NULL;
00490   if (uriObj->isString()) {
00491     uri2 = uriObj->getString()->copy();
00492     if (baseURI) {
00493       n = strcspn(uri2->getCString(), "/:");
00494       if (n == uri2->getLength() || uri2->getChar(n) == '/') {
00495     uri = baseURI->copy();
00496     c = uri->getChar(uri->getLength() - 1);
00497     if (c == '/' || c == '?') {
00498       if (uri2->getChar(0) == '/') {
00499         uri2->del(0);
00500       }
00501     } else {
00502       if (uri2->getChar(0) != '/') {
00503         uri->append('/');
00504       }
00505     }
00506     uri->append(uri2);
00507     delete uri2;
00508       } else {
00509     uri = uri2;
00510       }
00511     } else {
00512       uri = uri2;
00513     }
00514   } else {
00515     error(-1, "Illegal URI-type link");
00516   }
00517 }
00518 
00519 LinkURI::~LinkURI() {
00520   if (uri)
00521     delete uri;
00522 }
00523 
00524 //------------------------------------------------------------------------
00525 // LinkNamed
00526 //------------------------------------------------------------------------
00527 
00528 LinkNamed::LinkNamed(Object *nameObj) {
00529   name = NULL;
00530   if (nameObj->isName()) {
00531     name = new GString(nameObj->getName());
00532   }
00533 }
00534 
00535 LinkNamed::~LinkNamed() {
00536   if (name) {
00537     delete name;
00538   }
00539 }
00540 
00541 //------------------------------------------------------------------------
00542 // LinkMovie
00543 //------------------------------------------------------------------------
00544 
00545 LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) {
00546   annotRef.num = -1;
00547   title = NULL;
00548   if (annotObj->isRef()) {
00549     annotRef = annotObj->getRef();
00550   } else if (titleObj->isString()) {
00551     title = titleObj->getString()->copy();
00552   } else {
00553     error(-1, "Movie action is missing both the Annot and T keys");
00554   }
00555 }
00556 
00557 LinkMovie::~LinkMovie() {
00558   if (title) {
00559     delete title;
00560   }
00561 }
00562 
00563 //------------------------------------------------------------------------
00564 // LinkUnknown
00565 //------------------------------------------------------------------------
00566 
00567 LinkUnknown::LinkUnknown(char *actionA) {
00568   action = new GString(actionA);
00569 }
00570 
00571 LinkUnknown::~LinkUnknown() {
00572   delete action;
00573 }
00574 
00575 //------------------------------------------------------------------------
00576 // Link
00577 //------------------------------------------------------------------------
00578 
00579 Link::Link(Dict *dict, GString *baseURI) {
00580   Object obj1, obj2;
00581   double t;
00582 
00583   action = NULL;
00584   ok = gFalse;
00585 
00586   // get rectangle
00587   if (!dict->lookup("Rect", &obj1)->isArray()) {
00588     error(-1, "Annotation rectangle is wrong type");
00589     goto err2;
00590   }
00591   if (!obj1.arrayGet(0, &obj2)->isNum()) {
00592     error(-1, "Bad annotation rectangle");
00593     goto err1;
00594   }
00595   x1 = obj2.getNum();
00596   obj2.free();
00597   if (!obj1.arrayGet(1, &obj2)->isNum()) {
00598     error(-1, "Bad annotation rectangle");
00599     goto err1;
00600   }
00601   y1 = obj2.getNum();
00602   obj2.free();
00603   if (!obj1.arrayGet(2, &obj2)->isNum()) {
00604     error(-1, "Bad annotation rectangle");
00605     goto err1;
00606   }
00607   x2 = obj2.getNum();
00608   obj2.free();
00609   if (!obj1.arrayGet(3, &obj2)->isNum()) {
00610     error(-1, "Bad annotation rectangle");
00611     goto err1;
00612   }
00613   y2 = obj2.getNum();
00614   obj2.free();
00615   obj1.free();
00616   if (x1 > x2) {
00617     t = x1;
00618     x1 = x2;
00619     x2 = t;
00620   }
00621   if (y1 > y2) {
00622     t = y1;
00623     y1 = y2;
00624     y2 = t;
00625   }
00626 
00627   // get border
00628   borderW = 1;
00629   if (!dict->lookup("Border", &obj1)->isNull()) {
00630     if (obj1.isArray() && obj1.arrayGetLength() >= 3) {
00631       if (obj1.arrayGet(2, &obj2)->isNum()) {
00632     borderW = obj2.getNum();
00633       } else {
00634     error(-1, "Bad annotation border");
00635       }
00636       obj2.free();
00637     }
00638   }
00639   obj1.free();
00640 
00641   // look for destination
00642   if (!dict->lookup("Dest", &obj1)->isNull()) {
00643     action = LinkAction::parseDest(&obj1);
00644 
00645   // look for action
00646   } else {
00647     obj1.free();
00648     if (dict->lookup("A", &obj1)->isDict()) {
00649       action = LinkAction::parseAction(&obj1, baseURI);
00650     }
00651   }
00652   obj1.free();
00653 
00654   // check for bad action
00655   if (action) {
00656     ok = gTrue;
00657   }
00658 
00659   return;
00660 
00661  err1:
00662   obj2.free();
00663  err2:
00664   obj1.free();
00665 }
00666 
00667 Link::~Link() {
00668   if (action)
00669     delete action;
00670 }
00671 
00672 //------------------------------------------------------------------------
00673 // Links
00674 //------------------------------------------------------------------------
00675 
00676 Links::Links(Object *annots, GString *baseURI) {
00677   Link *link;
00678   Object obj1, obj2;
00679   int size;
00680   int i;
00681 
00682   links = NULL;
00683   size = 0;
00684   numLinks = 0;
00685 
00686   if (annots->isArray()) {
00687     for (i = 0; i < annots->arrayGetLength(); ++i) {
00688       if (annots->arrayGet(i, &obj1)->isDict()) {
00689     if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) {
00690       link = new Link(obj1.getDict(), baseURI);
00691       if (link->isOk()) {
00692         if (numLinks >= size) {
00693           size += 16;
00694           links = (Link **)grealloc(links, size * sizeof(Link *));
00695         }
00696         links[numLinks++] = link;
00697       } else {
00698         delete link;
00699       }
00700     }
00701     obj2.free();
00702       }
00703       obj1.free();
00704     }
00705   }
00706 }
00707 
00708 Links::~Links() {
00709   int i;
00710 
00711   for (i = 0; i < numLinks; ++i)
00712     delete links[i];
00713   gfree(links);
00714 }
00715 
00716 LinkAction *Links::find(double x, double y) {
00717   int i;
00718 
00719   for (i = numLinks - 1; i >= 0; --i) {
00720     if (links[i]->inRect(x, y)) {
00721       return links[i]->getAction();
00722     }
00723   }
00724   return NULL;
00725 }
00726 
00727 GBool Links::onLink(double x, double y) {
00728   int i;
00729 
00730   for (i = 0; i < numLinks; ++i) {
00731     if (links[i]->inRect(x, y))
00732       return gTrue;
00733   }
00734   return gFalse;
00735 }
KDE Home | KDE Accessibility Home | Description of Access Keys