Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

Link.cc

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

Generated on Sat Nov 5 16:18:15 2005 for OPIE by  doxygen 1.4.2