//
// Link.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
//========================================================================
-#ifdef __GNUC__
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
#include "Link.h"
//------------------------------------------------------------------------
+// LinkAction
+//------------------------------------------------------------------------
+
+LinkAction *LinkAction::parseDest(Object *obj) {
+ LinkAction *action;
+
+ action = new LinkGoTo(obj);
+ if (!action->isOk()) {
+ delete action;
+ return NULL;
+ }
+ return action;
+}
+
+LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) {
+ LinkAction *action;
+ Object obj2, obj3, obj4;
+
+ if (!obj->isDict()) {
+ error(-1, "Bad annotation action");
+ return NULL;
+ }
+
+ obj->dictLookup("S", &obj2);
+
+ // GoTo action
+ if (obj2.isName("GoTo")) {
+ obj->dictLookup("D", &obj3);
+ action = new LinkGoTo(&obj3);
+ obj3.free();
+
+ // GoToR action
+ } else if (obj2.isName("GoToR")) {
+ obj->dictLookup("F", &obj3);
+ obj->dictLookup("D", &obj4);
+ action = new LinkGoToR(&obj3, &obj4);
+ obj3.free();
+ obj4.free();
+
+ // Launch action
+ } else if (obj2.isName("Launch")) {
+ action = new LinkLaunch(obj);
+
+ // URI action
+ } else if (obj2.isName("URI")) {
+ obj->dictLookup("URI", &obj3);
+ action = new LinkURI(&obj3, baseURI);
+ obj3.free();
+
+ // Named action
+ } else if (obj2.isName("Named")) {
+ obj->dictLookup("N", &obj3);
+ action = new LinkNamed(&obj3);
+ obj3.free();
+
+ // Movie action
+ } else if (obj2.isName("Movie")) {
+ obj->dictLookupNF("Annot", &obj3);
+ obj->dictLookup("T", &obj4);
+ action = new LinkMovie(&obj3, &obj4);
+ obj3.free();
+ obj4.free();
+
+ // unknown action
+ } else if (obj2.isName()) {
+ action = new LinkUnknown(obj2.getName());
+
+ // action is missing or wrong type
+ } else {
+ error(-1, "Bad annotation action");
+ action = NULL;
+ }
+
+ obj2.free();
+
+ if (action && !action->isOk()) {
+ delete action;
+ return NULL;
+ }
+ return action;
+}
+
+GString *LinkAction::getFileSpecName(Object *fileSpecObj) {
+ GString *name;
+ Object obj1;
+
+ name = NULL;
+
+ // string
+ if (fileSpecObj->isString()) {
+ name = fileSpecObj->getString()->copy();
+
+ // dictionary
+ } else if (fileSpecObj->isDict()) {
+ if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) {
+ obj1.free();
+ fileSpecObj->dictLookup("F", &obj1);
+ }
+ if (obj1.isString())
+ name = obj1.getString()->copy();
+ else
+ error(-1, "Illegal file spec in link");
+ obj1.free();
+
+ // error
+ } else {
+ error(-1, "Illegal file spec in link");
+ }
-static GString *getFileSpecName(Object *fileSpecObj);
+ return name;
+}
//------------------------------------------------------------------------
// LinkDest
//------------------------------------------------------------------------
-LinkDest::LinkDest(Array *a, GBool pageIsRef1) {
+LinkDest::LinkDest(Array *a) {
Object obj1, obj2;
// initialize fields
- pageIsRef = pageIsRef1;
left = bottom = right = top = zoom = 0;
ok = gFalse;
// get page
- if (pageIsRef) {
- if (!a->getNF(0, &obj1)->isRef()) {
- error(-1, "Bad annotation destination");
- goto err2;
- }
+ if (a->getLength() < 2) {
+ error(-1, "Annotation destination array has wrong length");
+ return;
+ }
+ a->getNF(0, &obj1);
+ if (obj1.isInt()) {
+ pageNum = obj1.getInt() + 1;
+ pageIsRef = gFalse;
+ } else if (obj1.isRef()) {
pageRef.num = obj1.getRefNum();
pageRef.gen = obj1.getRefGen();
- obj1.free();
+ pageIsRef = gTrue;
} else {
- if (!a->get(0, &obj1)->isInt()) {
- error(-1, "Bad annotation destination");
- goto err2;
- }
- pageNum = obj1.getInt() + 1;
- obj1.free();
+ error(-1, "Bad annotation destination");
+ goto err2;
}
+ obj1.free();
// get destination type
a->get(1, &obj1);
// XYZ link
if (obj1.isName("XYZ")) {
+ if (a->getLength() != 5) {
+ error(-1, "Annotation destination array has wrong length");
+ goto err2;
+ }
kind = destXYZ;
a->get(2, &obj2);
if (obj2.isNull()) {
// Fit link
} else if (obj1.isName("Fit")) {
+ if (a->getLength() != 2) {
+ error(-1, "Annotation destination array has wrong length");
+ goto err2;
+ }
kind = destFit;
// FitH link
} else if (obj1.isName("FitH")) {
+ if (a->getLength() != 3) {
+ error(-1, "Annotation destination array has wrong length");
+ goto err2;
+ }
kind = destFitH;
if (!a->get(2, &obj2)->isNum()) {
error(-1, "Bad annotation destination position");
// FitV link
} else if (obj1.isName("FitV")) {
+ if (a->getLength() != 3) {
+ error(-1, "Annotation destination array has wrong length");
+ goto err2;
+ }
kind = destFitV;
if (!a->get(2, &obj2)->isNum()) {
error(-1, "Bad annotation destination position");
// FitR link
} else if (obj1.isName("FitR")) {
+ if (a->getLength() != 6) {
+ error(-1, "Annotation destination array has wrong length");
+ goto err2;
+ }
kind = destFitR;
if (!a->get(2, &obj2)->isNum()) {
error(-1, "Bad annotation destination position");
// FitB link
} else if (obj1.isName("FitB")) {
+ if (a->getLength() != 2) {
+ error(-1, "Annotation destination array has wrong length");
+ goto err2;
+ }
kind = destFitB;
// FitBH link
} else if (obj1.isName("FitBH")) {
+ if (a->getLength() != 3) {
+ error(-1, "Annotation destination array has wrong length");
+ goto err2;
+ }
kind = destFitBH;
if (!a->get(2, &obj2)->isNum()) {
error(-1, "Bad annotation destination position");
// FitBV link
} else if (obj1.isName("FitBV")) {
+ if (a->getLength() != 3) {
+ error(-1, "Annotation destination array has wrong length");
+ goto err2;
+ }
kind = destFitBV;
if (!a->get(2, &obj2)->isNum()) {
error(-1, "Bad annotation destination position");
// destination dictionary
} else if (destObj->isArray()) {
- dest = new LinkDest(destObj->getArray(), gTrue);
+ dest = new LinkDest(destObj->getArray());
if (!dest->isOk()) {
delete dest;
dest = NULL;
// destination dictionary
} else if (destObj->isArray()) {
- dest = new LinkDest(destObj->getArray(), gFalse);
+ dest = new LinkDest(destObj->getArray());
if (!dest->isOk()) {
delete dest;
dest = NULL;
fileName = getFileSpecName(&obj1);
} else {
obj1.free();
+#ifdef WIN32
+ if (actionObj->dictLookup("Win", &obj1)->isDict()) {
+ obj1.dictLookup("F", &obj2);
+ fileName = getFileSpecName(&obj2);
+ obj2.free();
+ if (obj1.dictLookup("P", &obj2)->isString()) {
+ params = obj2.getString()->copy();
+ }
+ obj2.free();
+ } else {
+ error(-1, "Bad launch-type link action");
+ }
+#else
//~ This hasn't been defined by Adobe yet, so assume it looks
//~ just like the Win dictionary until they say otherwise.
if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
obj1.dictLookup("F", &obj2);
fileName = getFileSpecName(&obj2);
obj2.free();
- if (obj1.dictLookup("P", &obj2)->isString())
+ if (obj1.dictLookup("P", &obj2)->isString()) {
params = obj2.getString()->copy();
+ }
obj2.free();
} else {
error(-1, "Bad launch-type link action");
}
+#endif
}
obj1.free();
}
delete uri;
}
+//------------------------------------------------------------------------
+// LinkNamed
+//------------------------------------------------------------------------
+
+LinkNamed::LinkNamed(Object *nameObj) {
+ name = NULL;
+ if (nameObj->isName()) {
+ name = new GString(nameObj->getName());
+ }
+}
+
+LinkNamed::~LinkNamed() {
+ if (name) {
+ delete name;
+ }
+}
+
+//------------------------------------------------------------------------
+// LinkMovie
+//------------------------------------------------------------------------
+
+LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) {
+ annotRef.num = -1;
+ title = NULL;
+ if (annotObj->isRef()) {
+ annotRef = annotObj->getRef();
+ } else if (titleObj->isString()) {
+ title = titleObj->getString()->copy();
+ } else {
+ error(-1, "Movie action is missing both the Annot and T keys");
+ }
+}
+
+LinkMovie::~LinkMovie() {
+ if (title) {
+ delete title;
+ }
+}
+
//------------------------------------------------------------------------
// LinkUnknown
//------------------------------------------------------------------------
-LinkUnknown::LinkUnknown(char *action1) {
- action = new GString(action1);
+LinkUnknown::LinkUnknown(char *actionA) {
+ action = new GString(actionA);
}
LinkUnknown::~LinkUnknown() {
//------------------------------------------------------------------------
Link::Link(Dict *dict, GString *baseURI) {
- Object obj1, obj2, obj3, obj4;
+ Object obj1, obj2;
double t;
action = NULL;
}
// get border
- borderW = 0;
+ borderW = 1;
if (!dict->lookup("Border", &obj1)->isNull()) {
- if (obj1.isArray() && obj1.arrayGet(2, &obj2)->isNum())
- borderW = obj2.getNum();
- else
- error(-1, "Bad annotation border");
- obj2.free();
+ if (obj1.isArray() && obj1.arrayGetLength() >= 3) {
+ if (obj1.arrayGet(2, &obj2)->isNum()) {
+ borderW = obj2.getNum();
+ } else {
+ error(-1, "Bad annotation border");
+ }
+ obj2.free();
+ }
}
obj1.free();
// look for destination
if (!dict->lookup("Dest", &obj1)->isNull()) {
- action = new LinkGoTo(&obj1);
+ action = LinkAction::parseDest(&obj1);
// look for action
} else {
obj1.free();
if (dict->lookup("A", &obj1)->isDict()) {
- obj1.dictLookup("S", &obj2);
-
- // GoTo action
- if (obj2.isName("GoTo")) {
- obj1.dictLookup("D", &obj3);
- action = new LinkGoTo(&obj3);
- obj3.free();
-
- // GoToR action
- } else if (obj2.isName("GoToR")) {
- obj1.dictLookup("F", &obj3);
- obj1.dictLookup("D", &obj4);
- action = new LinkGoToR(&obj3, &obj4);
- obj3.free();
- obj4.free();
-
- // Launch action
- } else if (obj2.isName("Launch")) {
- action = new LinkLaunch(&obj1);
-
- // URI action
- } else if (obj2.isName("URI")) {
- obj1.dictLookup("URI", &obj3);
- action = new LinkURI(&obj3, baseURI);
- obj3.free();
-
- // unknown action
- } else if (obj2.isName()) {
- action = new LinkUnknown(obj2.getName());
-
- // action is missing or wrong type
- } else {
- error(-1, "Bad annotation action");
- action = NULL;
- }
-
- obj2.free();
-
- } else {
- error(-1, "Missing annotation destination/action");
- action = NULL;
+ action = LinkAction::parseAction(&obj1, baseURI);
}
}
obj1.free();
// check for bad action
- if (action && action->isOk())
+ if (action) {
ok = gTrue;
+ }
return;
gfree(links);
}
-LinkAction *Links::find(double x, double y) {
+LinkAction *Links::find(double x, double y) const {
int i;
- for (i = 0; i < numLinks; ++i) {
+ for (i = numLinks - 1; i >= 0; --i) {
if (links[i]->inRect(x, y)) {
- if (links[i]->getAction())
- return links[i]->getAction();
- return NULL;
+ return links[i]->getAction();
}
}
return NULL;
}
-GBool Links::onLink(double x, double y) {
+GBool Links::onLink(double x, double y) const {
int i;
for (i = 0; i < numLinks; ++i) {
}
return gFalse;
}
-
-//------------------------------------------------------------------------
-
-// Extract a file name from a file specification (string or dictionary).
-static GString *getFileSpecName(Object *fileSpecObj) {
- GString *name;
- Object obj1;
-
- name = NULL;
-
- // string
- if (fileSpecObj->isString()) {
- name = fileSpecObj->getString()->copy();
-
- // dictionary
- } else if (fileSpecObj->isDict()) {
- if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) {
- obj1.free();
- fileSpecObj->dictLookup("F", &obj1);
- }
- if (obj1.isString())
- name = obj1.getString()->copy();
- else
- error(-1, "Illegal file spec in link");
- obj1.free();
-
- // error
- } else {
- error(-1, "Illegal file spec in link");
- }
-
- return name;
-}