]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/Link.cc
(eog_hig_dialog_new): add terminating NULL in g_object_set.
[evince.git] / pdf / xpdf / Link.cc
index af64c8bef5d713977649ad9e2e0909ee4fbee81f..39b7cebe22d52122d893901a28295af1a395d093 100644 (file)
@@ -2,15 +2,16 @@
 //
 // Link.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
-#ifdef __GNUC__
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
 #pragma implementation
 #endif
 
-#include <aconf.h>
 #include <stddef.h>
 #include <string.h>
 #include "gmem.h"
 #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();
 
-static GString *getFileSpecName(Object *fileSpecObj);
+  // error
+  } else {
+    error(-1, "Illegal file spec in link");
+  }
+
+  return name;
+}
 
 //------------------------------------------------------------------------
 // LinkDest
@@ -37,6 +147,10 @@ LinkDest::LinkDest(Array *a) {
   ok = gFalse;
 
   // get page
+  if (a->getLength() < 2) {
+    error(-1, "Annotation destination array is too short");
+    return;
+  }
   a->getNF(0, &obj1);
   if (obj1.isInt()) {
     pageNum = obj1.getInt() + 1;
@@ -57,46 +171,66 @@ LinkDest::LinkDest(Array *a) {
   // XYZ link
   if (obj1.isName("XYZ")) {
     kind = destXYZ;
-    a->get(2, &obj2);
-    if (obj2.isNull()) {
+    if (a->getLength() < 3) {
       changeLeft = gFalse;
-    } else if (obj2.isNum()) {
-      changeLeft = gTrue;
-      left = obj2.getNum();
     } else {
-      error(-1, "Bad annotation destination position");
-      goto err1;
+      a->get(2, &obj2);
+      if (obj2.isNull()) {
+       changeLeft = gFalse;
+      } else if (obj2.isNum()) {
+       changeLeft = gTrue;
+       left = obj2.getNum();
+      } else {
+       error(-1, "Bad annotation destination position");
+       goto err1;
+      }
+      obj2.free();
     }
-    obj2.free();
-    a->get(3, &obj2);
-    if (obj2.isNull()) {
+    if (a->getLength() < 4) {
       changeTop = gFalse;
-    } else if (obj2.isNum()) {
-      changeTop = gTrue;
-      top = obj2.getNum();
     } else {
-      error(-1, "Bad annotation destination position");
-      goto err1;
+      a->get(3, &obj2);
+      if (obj2.isNull()) {
+       changeTop = gFalse;
+      } else if (obj2.isNum()) {
+       changeTop = gTrue;
+       top = obj2.getNum();
+      } else {
+       error(-1, "Bad annotation destination position");
+       goto err1;
+      }
+      obj2.free();
     }
-    obj2.free();
-    a->get(4, &obj2);
-    if (obj2.isNull()) {
+    if (a->getLength() < 5) {
       changeZoom = gFalse;
-    } else if (obj2.isNum()) {
-      changeZoom = gTrue;
-      zoom = obj2.getNum();
     } else {
-      error(-1, "Bad annotation destination position");
-      goto err1;
+      a->get(4, &obj2);
+      if (obj2.isNull()) {
+       changeZoom = gFalse;
+      } else if (obj2.isNum()) {
+       changeZoom = gTrue;
+       zoom = obj2.getNum();
+      } else {
+       error(-1, "Bad annotation destination position");
+       goto err1;
+      }
+      obj2.free();
     }
-    obj2.free();
 
   // Fit link
   } else if (obj1.isName("Fit")) {
+    if (a->getLength() < 2) {
+      error(-1, "Annotation destination array is too short");
+      goto err2;
+    }
     kind = destFit;
 
   // FitH link
   } else if (obj1.isName("FitH")) {
+    if (a->getLength() < 3) {
+      error(-1, "Annotation destination array is too short");
+      goto err2;
+    }
     kind = destFitH;
     if (!a->get(2, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
@@ -107,6 +241,10 @@ LinkDest::LinkDest(Array *a) {
 
   // FitV link
   } else if (obj1.isName("FitV")) {
+    if (a->getLength() < 3) {
+      error(-1, "Annotation destination array is too short");
+      goto err2;
+    }
     kind = destFitV;
     if (!a->get(2, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
@@ -117,6 +255,10 @@ LinkDest::LinkDest(Array *a) {
 
   // FitR link
   } else if (obj1.isName("FitR")) {
+    if (a->getLength() < 6) {
+      error(-1, "Annotation destination array is too short");
+      goto err2;
+    }
     kind = destFitR;
     if (!a->get(2, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
@@ -145,10 +287,18 @@ LinkDest::LinkDest(Array *a) {
 
   // FitB link
   } else if (obj1.isName("FitB")) {
+    if (a->getLength() < 2) {
+      error(-1, "Annotation destination array is too short");
+      goto err2;
+    }
     kind = destFitB;
 
   // FitBH link
   } else if (obj1.isName("FitBH")) {
+    if (a->getLength() < 3) {
+      error(-1, "Annotation destination array is too short");
+      goto err2;
+    }
     kind = destFitBH;
     if (!a->get(2, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
@@ -159,6 +309,10 @@ LinkDest::LinkDest(Array *a) {
 
   // FitBV link
   } else if (obj1.isName("FitBV")) {
+    if (a->getLength() < 3) {
+      error(-1, "Annotation destination array is too short");
+      goto err2;
+    }
     kind = destFitBV;
     if (!a->get(2, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
@@ -292,18 +446,33 @@ LinkLaunch::LinkLaunch(Object *actionObj) {
       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();
   }
@@ -377,6 +546,28 @@ LinkNamed::~LinkNamed() {
   }
 }
 
+//------------------------------------------------------------------------
+// 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
 //------------------------------------------------------------------------
@@ -394,7 +585,7 @@ LinkUnknown::~LinkUnknown() {
 //------------------------------------------------------------------------
 
 Link::Link(Dict *dict, GString *baseURI) {
-  Object obj1, obj2, obj3, obj4;
+  Object obj1, obj2;
   double t;
 
   action = NULL;
@@ -457,66 +648,21 @@ Link::Link(Dict *dict, GString *baseURI) {
 
   // 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();
-
-      // Named action
-      } else if (obj2.isName("Named")) {
-       obj1.dictLookup("N", &obj3);
-       action = new LinkNamed(&obj3);
-       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;
 
@@ -575,7 +721,7 @@ Links::~Links() {
   gfree(links);
 }
 
-LinkAction *Links::find(double x, double y) {
+LinkAction *Links::find(double x, double y) const {
   int i;
 
   for (i = numLinks - 1; i >= 0; --i) {
@@ -586,7 +732,7 @@ LinkAction *Links::find(double x, double y) {
   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) {
@@ -595,36 +741,3 @@ GBool Links::onLink(double x, double y) {
   }
   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;
-}