1 //========================================================================
5 // Copyright 1996-2002 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
25 //------------------------------------------------------------------------
27 //------------------------------------------------------------------------
29 LinkAction *LinkAction::parseDest(Object *obj) {
32 action = new LinkGoTo(obj);
33 if (!action->isOk()) {
40 LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) {
42 Object obj2, obj3, obj4;
45 error(-1, "Bad annotation action");
49 obj->dictLookup("S", &obj2);
52 if (obj2.isName("GoTo")) {
53 obj->dictLookup("D", &obj3);
54 action = new LinkGoTo(&obj3);
58 } else if (obj2.isName("GoToR")) {
59 obj->dictLookup("F", &obj3);
60 obj->dictLookup("D", &obj4);
61 action = new LinkGoToR(&obj3, &obj4);
66 } else if (obj2.isName("Launch")) {
67 action = new LinkLaunch(obj);
70 } else if (obj2.isName("URI")) {
71 obj->dictLookup("URI", &obj3);
72 action = new LinkURI(&obj3, baseURI);
76 } else if (obj2.isName("Named")) {
77 obj->dictLookup("N", &obj3);
78 action = new LinkNamed(&obj3);
82 } else if (obj2.isName("Movie")) {
83 obj->dictLookupNF("Annot", &obj3);
84 obj->dictLookup("T", &obj4);
85 action = new LinkMovie(&obj3, &obj4);
90 } else if (obj2.isName()) {
91 action = new LinkUnknown(obj2.getName());
93 // action is missing or wrong type
95 error(-1, "Bad annotation action");
101 if (action && !action->isOk()) {
108 GString *LinkAction::getFileSpecName(Object *fileSpecObj) {
115 if (fileSpecObj->isString()) {
116 name = fileSpecObj->getString()->copy();
119 } else if (fileSpecObj->isDict()) {
120 if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) {
122 fileSpecObj->dictLookup("F", &obj1);
125 name = obj1.getString()->copy();
127 error(-1, "Illegal file spec in link");
132 error(-1, "Illegal file spec in link");
138 //------------------------------------------------------------------------
140 //------------------------------------------------------------------------
142 LinkDest::LinkDest(Array *a) {
146 left = bottom = right = top = zoom = 0;
150 if (a->getLength() < 2) {
151 error(-1, "Annotation destination array has wrong length");
156 pageNum = obj1.getInt() + 1;
158 } else if (obj1.isRef()) {
159 pageRef.num = obj1.getRefNum();
160 pageRef.gen = obj1.getRefGen();
163 error(-1, "Bad annotation destination");
168 // get destination type
172 if (obj1.isName("XYZ")) {
174 if (a->getLength() < 3) {
180 } else if (obj2.isNum()) {
182 left = obj2.getNum();
184 error(-1, "Bad annotation destination position");
189 if (a->getLength() < 4) {
195 } else if (obj2.isNum()) {
199 error(-1, "Bad annotation destination position");
204 if (a->getLength() < 5) {
210 } else if (obj2.isNum()) {
212 zoom = obj2.getNum();
214 error(-1, "Bad annotation destination position");
221 } else if (obj1.isName("Fit")) {
222 if (a->getLength() != 2) {
223 error(-1, "Annotation destination array has wrong length");
229 } else if (obj1.isName("FitH")) {
230 if (a->getLength() != 3) {
231 error(-1, "Annotation destination array has wrong length");
235 if (!a->get(2, &obj2)->isNum()) {
236 error(-1, "Bad annotation destination position");
243 } else if (obj1.isName("FitV")) {
244 if (a->getLength() != 3) {
245 error(-1, "Annotation destination array has wrong length");
249 if (!a->get(2, &obj2)->isNum()) {
250 error(-1, "Bad annotation destination position");
253 left = obj2.getNum();
257 } else if (obj1.isName("FitR")) {
258 if (a->getLength() != 6) {
259 error(-1, "Annotation destination array has wrong length");
263 if (!a->get(2, &obj2)->isNum()) {
264 error(-1, "Bad annotation destination position");
267 left = obj2.getNum();
269 if (!a->get(3, &obj2)->isNum()) {
270 error(-1, "Bad annotation destination position");
273 bottom = obj2.getNum();
275 if (!a->get(4, &obj2)->isNum()) {
276 error(-1, "Bad annotation destination position");
279 right = obj2.getNum();
281 if (!a->get(5, &obj2)->isNum()) {
282 error(-1, "Bad annotation destination position");
289 } else if (obj1.isName("FitB")) {
290 if (a->getLength() != 2) {
291 error(-1, "Annotation destination array has wrong length");
297 } else if (obj1.isName("FitBH")) {
298 if (a->getLength() != 3) {
299 error(-1, "Annotation destination array has wrong length");
303 if (!a->get(2, &obj2)->isNum()) {
304 error(-1, "Bad annotation destination position");
311 } else if (obj1.isName("FitBV")) {
312 if (a->getLength() != 3) {
313 error(-1, "Annotation destination array has wrong length");
317 if (!a->get(2, &obj2)->isNum()) {
318 error(-1, "Bad annotation destination position");
321 left = obj2.getNum();
326 error(-1, "Unknown annotation destination type");
340 LinkDest::LinkDest(LinkDest *dest) {
342 pageIsRef = dest->pageIsRef;
344 pageRef = dest->pageRef;
346 pageNum = dest->pageNum;
348 bottom = dest->bottom;
352 changeLeft = dest->changeLeft;
353 changeTop = dest->changeTop;
354 changeZoom = dest->changeZoom;
358 //------------------------------------------------------------------------
360 //------------------------------------------------------------------------
362 LinkGoTo::LinkGoTo(Object *destObj) {
367 if (destObj->isName()) {
368 namedDest = new GString(destObj->getName());
369 } else if (destObj->isString()) {
370 namedDest = destObj->getString()->copy();
372 // destination dictionary
373 } else if (destObj->isArray()) {
374 dest = new LinkDest(destObj->getArray());
382 error(-1, "Illegal annotation destination");
386 LinkGoTo::~LinkGoTo() {
393 //------------------------------------------------------------------------
395 //------------------------------------------------------------------------
397 LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) {
402 fileName = getFileSpecName(fileSpecObj);
405 if (destObj->isName()) {
406 namedDest = new GString(destObj->getName());
407 } else if (destObj->isString()) {
408 namedDest = destObj->getString()->copy();
410 // destination dictionary
411 } else if (destObj->isArray()) {
412 dest = new LinkDest(destObj->getArray());
420 error(-1, "Illegal annotation destination");
424 LinkGoToR::~LinkGoToR() {
434 //------------------------------------------------------------------------
436 //------------------------------------------------------------------------
438 LinkLaunch::LinkLaunch(Object *actionObj) {
444 if (actionObj->isDict()) {
445 if (!actionObj->dictLookup("F", &obj1)->isNull()) {
446 fileName = getFileSpecName(&obj1);
450 if (actionObj->dictLookup("Win", &obj1)->isDict()) {
451 obj1.dictLookup("F", &obj2);
452 fileName = getFileSpecName(&obj2);
454 if (obj1.dictLookup("P", &obj2)->isString()) {
455 params = obj2.getString()->copy();
459 error(-1, "Bad launch-type link action");
462 //~ This hasn't been defined by Adobe yet, so assume it looks
463 //~ just like the Win dictionary until they say otherwise.
464 if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
465 obj1.dictLookup("F", &obj2);
466 fileName = getFileSpecName(&obj2);
468 if (obj1.dictLookup("P", &obj2)->isString()) {
469 params = obj2.getString()->copy();
473 error(-1, "Bad launch-type link action");
481 LinkLaunch::~LinkLaunch() {
488 //------------------------------------------------------------------------
490 //------------------------------------------------------------------------
492 LinkURI::LinkURI(Object *uriObj, GString *baseURI) {
498 if (uriObj->isString()) {
499 uri2 = uriObj->getString()->copy();
501 n = strcspn(uri2->getCString(), "/:");
502 if (n == uri2->getLength() || uri2->getChar(n) == '/') {
503 uri = baseURI->copy();
504 c = uri->getChar(uri->getLength() - 1);
505 if (c == '/' || c == '?') {
506 if (uri2->getChar(0) == '/') {
510 if (uri2->getChar(0) != '/') {
523 error(-1, "Illegal URI-type link");
527 LinkURI::~LinkURI() {
532 //------------------------------------------------------------------------
534 //------------------------------------------------------------------------
536 LinkNamed::LinkNamed(Object *nameObj) {
538 if (nameObj->isName()) {
539 name = new GString(nameObj->getName());
543 LinkNamed::~LinkNamed() {
549 //------------------------------------------------------------------------
551 //------------------------------------------------------------------------
553 LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) {
556 if (annotObj->isRef()) {
557 annotRef = annotObj->getRef();
558 } else if (titleObj->isString()) {
559 title = titleObj->getString()->copy();
561 error(-1, "Movie action is missing both the Annot and T keys");
565 LinkMovie::~LinkMovie() {
571 //------------------------------------------------------------------------
573 //------------------------------------------------------------------------
575 LinkUnknown::LinkUnknown(char *actionA) {
576 action = new GString(actionA);
579 LinkUnknown::~LinkUnknown() {
583 //------------------------------------------------------------------------
585 //------------------------------------------------------------------------
587 Link::Link(Dict *dict, GString *baseURI) {
595 if (!dict->lookup("Rect", &obj1)->isArray()) {
596 error(-1, "Annotation rectangle is wrong type");
599 if (!obj1.arrayGet(0, &obj2)->isNum()) {
600 error(-1, "Bad annotation rectangle");
605 if (!obj1.arrayGet(1, &obj2)->isNum()) {
606 error(-1, "Bad annotation rectangle");
611 if (!obj1.arrayGet(2, &obj2)->isNum()) {
612 error(-1, "Bad annotation rectangle");
617 if (!obj1.arrayGet(3, &obj2)->isNum()) {
618 error(-1, "Bad annotation rectangle");
637 if (!dict->lookup("Border", &obj1)->isNull()) {
638 if (obj1.isArray() && obj1.arrayGetLength() >= 3) {
639 if (obj1.arrayGet(2, &obj2)->isNum()) {
640 borderW = obj2.getNum();
642 error(-1, "Bad annotation border");
649 // look for destination
650 if (!dict->lookup("Dest", &obj1)->isNull()) {
651 action = LinkAction::parseDest(&obj1);
656 if (dict->lookup("A", &obj1)->isDict()) {
657 action = LinkAction::parseAction(&obj1, baseURI);
662 // check for bad action
680 //------------------------------------------------------------------------
682 //------------------------------------------------------------------------
684 Links::Links(Object *annots, GString *baseURI) {
694 if (annots->isArray()) {
695 for (i = 0; i < annots->arrayGetLength(); ++i) {
696 if (annots->arrayGet(i, &obj1)->isDict()) {
697 if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) {
698 link = new Link(obj1.getDict(), baseURI);
700 if (numLinks >= size) {
702 links = (Link **)grealloc(links, size * sizeof(Link *));
704 links[numLinks++] = link;
719 for (i = 0; i < numLinks; ++i)
724 LinkAction *Links::find(double x, double y) const {
727 for (i = numLinks - 1; i >= 0; --i) {
728 if (links[i]->inRect(x, y)) {
729 return links[i]->getAction();
735 GBool Links::onLink(double x, double y) const {
738 for (i = 0; i < numLinks; ++i) {
739 if (links[i]->inRect(x, y))