diff options
Diffstat (limited to 'Build/source/libs/poppler/poppler-0.18.4/poppler/Link.cc')
-rw-r--r-- | Build/source/libs/poppler/poppler-0.18.4/poppler/Link.cc | 921 |
1 files changed, 921 insertions, 0 deletions
diff --git a/Build/source/libs/poppler/poppler-0.18.4/poppler/Link.cc b/Build/source/libs/poppler/poppler-0.18.4/poppler/Link.cc new file mode 100644 index 00000000000..971accf2810 --- /dev/null +++ b/Build/source/libs/poppler/poppler-0.18.4/poppler/Link.cc @@ -0,0 +1,921 @@ +//======================================================================== +// +// Link.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006, 2008 Pino Toscano <pino@kde.org> +// Copyright (C) 2007, 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org> +// Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com> +// Copyright (C) 2008-2010 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net> +// Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stddef.h> +#include <string.h> +#include "goo/gmem.h" +#include "goo/GooString.h" +#include "goo/GooList.h" +#include "Error.h" +#include "Object.h" +#include "Array.h" +#include "Dict.h" +#include "Link.h" +#include "Sound.h" +#include "FileSpec.h" +#include "Rendition.h" +#include "Annot.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, GooString *baseURI) { + LinkAction *action; + Object obj2, obj3, obj4; + + if (!obj->isDict()) { + error(-1, "parseAction: Bad annotation action for URI '%s'", + baseURI ? baseURI->getCString() : "NULL"); + 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")) { + action = new LinkMovie(obj); + + // Rendition action + } else if (obj2.isName("Rendition")) { + action = new LinkRendition(obj); + + // Sound action + } else if (obj2.isName("Sound")) { + action = new LinkSound(obj); + + // JavaScript action + } else if (obj2.isName("JavaScript")) { + obj->dictLookup("JS", &obj3); + action = new LinkJavaScript(&obj3); + obj3.free(); + + // Set-OCG-State action + } else if (obj2.isName("SetOCGState")) { + action = new LinkOCGState(obj); + + // unknown action + } else if (obj2.isName()) { + action = new LinkUnknown(obj2.getName()); + + // action is missing or wrong type + } else { + error(-1, "parseAction: Unknown annotation action object: URI = '%s'", + baseURI ? baseURI->getCString() : "NULL"); + action = NULL; + } + + obj2.free(); + + if (action && !action->isOk()) { + delete action; + return NULL; + } + return action; +} + +//------------------------------------------------------------------------ +// LinkDest +//------------------------------------------------------------------------ + +LinkDest::LinkDest(Array *a) { + Object obj1, obj2; + + // initialize fields + left = bottom = right = top = zoom = 0; + changeLeft = changeTop = changeZoom = gFalse; + 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; + pageIsRef = gFalse; + } else if (obj1.isRef()) { + pageRef.num = obj1.getRefNum(); + pageRef.gen = obj1.getRefGen(); + pageIsRef = gTrue; + } else { + error(-1, "Bad annotation destination"); + goto err2; + } + obj1.free(); + + // get destination type + a->get(1, &obj1); + + // XYZ link + if (obj1.isName("XYZ")) { + kind = destXYZ; + if (a->getLength() < 3) { + changeLeft = gFalse; + } else { + 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(); + } + if (a->getLength() < 4) { + changeTop = gFalse; + } else { + 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(); + } + if (a->getLength() < 5) { + changeZoom = gFalse; + } else { + 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(); + } + + // 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; + a->get(2, &obj2); + if (obj2.isNull()) { + changeTop = gFalse; + } else if (obj2.isNum()) { + changeTop = gTrue; + top = obj2.getNum(); + } else { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + obj2.free(); + + // FitV link + } else if (obj1.isName("FitV")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + kind = destFitV; + 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"); + kind = destFit; + } + obj2.free(); + + // 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"); + kind = destFit; + } + left = obj2.getNum(); + obj2.free(); + if (!a->get(3, &obj2)->isNum()) { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + bottom = obj2.getNum(); + obj2.free(); + if (!a->get(4, &obj2)->isNum()) { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + right = obj2.getNum(); + obj2.free(); + if (!a->get(5, &obj2)->isNum()) { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + top = obj2.getNum(); + obj2.free(); + + // 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; + a->get(2, &obj2); + if (obj2.isNull()) { + changeTop = gFalse; + } else if (obj2.isNum()) { + changeTop = gTrue; + top = obj2.getNum(); + } else { + error(-1, "Bad annotation destination position"); + kind = destFit; + } + obj2.free(); + + // FitBV link + } else if (obj1.isName("FitBV")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + kind = destFitBV; + 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"); + kind = destFit; + } + obj2.free(); + + // unknown link kind + } else { + error(-1, "Unknown annotation destination type"); + goto err2; + } + + obj1.free(); + ok = gTrue; + return; + + err1: + obj2.free(); + err2: + obj1.free(); +} + +LinkDest::LinkDest(LinkDest *dest) { + kind = dest->kind; + pageIsRef = dest->pageIsRef; + if (pageIsRef) + pageRef = dest->pageRef; + else + pageNum = dest->pageNum; + left = dest->left; + bottom = dest->bottom; + right = dest->right; + top = dest->top; + zoom = dest->zoom; + changeLeft = dest->changeLeft; + changeTop = dest->changeTop; + changeZoom = dest->changeZoom; + ok = gTrue; +} + +//------------------------------------------------------------------------ +// LinkGoTo +//------------------------------------------------------------------------ + +LinkGoTo::LinkGoTo(Object *destObj) { + dest = NULL; + namedDest = NULL; + + // named destination + if (destObj->isName()) { + namedDest = new GooString(destObj->getName()); + } else if (destObj->isString()) { + namedDest = destObj->getString()->copy(); + + // destination dictionary + } else if (destObj->isArray()) { + dest = new LinkDest(destObj->getArray()); + if (!dest->isOk()) { + delete dest; + dest = NULL; + } + + // error + } else { + error(-1, "Illegal annotation destination"); + } +} + +LinkGoTo::~LinkGoTo() { + if (dest) + delete dest; + if (namedDest) + delete namedDest; +} + +//------------------------------------------------------------------------ +// LinkGoToR +//------------------------------------------------------------------------ + +LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) { + fileName = NULL; + dest = NULL; + namedDest = NULL; + + // get file name + Object obj1; + if (getFileSpecNameForPlatform (fileSpecObj, &obj1)) { + fileName = obj1.getString()->copy(); + obj1.free(); + } + + // named destination + if (destObj->isName()) { + namedDest = new GooString(destObj->getName()); + } else if (destObj->isString()) { + namedDest = destObj->getString()->copy(); + + // destination dictionary + } else if (destObj->isArray()) { + dest = new LinkDest(destObj->getArray()); + if (!dest->isOk()) { + delete dest; + dest = NULL; + } + + // error + } else { + error(-1, "Illegal annotation destination"); + } +} + +LinkGoToR::~LinkGoToR() { + if (fileName) + delete fileName; + if (dest) + delete dest; + if (namedDest) + delete namedDest; +} + + +//------------------------------------------------------------------------ +// LinkLaunch +//------------------------------------------------------------------------ + +LinkLaunch::LinkLaunch(Object *actionObj) { + Object obj1, obj2, obj3; + + fileName = NULL; + params = NULL; + + if (actionObj->isDict()) { + if (!actionObj->dictLookup("F", &obj1)->isNull()) { + if (getFileSpecNameForPlatform (&obj1, &obj3)) { + fileName = obj3.getString()->copy(); + obj3.free(); + } + } else { + obj1.free(); +#ifdef _WIN32 + if (actionObj->dictLookup("Win", &obj1)->isDict()) { + obj1.dictLookup("F", &obj2); + if (getFileSpecNameForPlatform (&obj2, &obj3)) { + fileName = obj3.getString()->copy(); + obj3.free(); + } + 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); + if (getFileSpecNameForPlatform (&obj2, &obj3)) { + fileName = obj3.getString()->copy(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("P", &obj2)->isString()) { + params = obj2.getString()->copy(); + } + obj2.free(); + } else { + error(-1, "Bad launch-type link action"); + } +#endif + } + obj1.free(); + } +} + +LinkLaunch::~LinkLaunch() { + if (fileName) + delete fileName; + if (params) + delete params; +} + +//------------------------------------------------------------------------ +// LinkURI +//------------------------------------------------------------------------ + +LinkURI::LinkURI(Object *uriObj, GooString *baseURI) { + GooString *uri2; + int n; + char c; + + uri = NULL; + if (uriObj->isString()) { + uri2 = uriObj->getString()->copy(); + if (baseURI && baseURI->getLength() > 0) { + n = strcspn(uri2->getCString(), "/:"); + if (n == uri2->getLength() || uri2->getChar(n) == '/') { + uri = baseURI->copy(); + c = uri->getChar(uri->getLength() - 1); + if (c == '/' || c == '?') { + if (uri2->getChar(0) == '/') { + uri2->del(0); + } + } else { + if (uri2->getChar(0) != '/') { + uri->append('/'); + } + } + uri->append(uri2); + delete uri2; + } else { + uri = uri2; + } + } else { + uri = uri2; + } + } else { + error(-1, "Illegal URI-type link"); + } +} + +LinkURI::~LinkURI() { + if (uri) + delete uri; +} + +//------------------------------------------------------------------------ +// LinkNamed +//------------------------------------------------------------------------ + +LinkNamed::LinkNamed(Object *nameObj) { + name = NULL; + if (nameObj->isName()) { + name = new GooString(nameObj->getName()); + } +} + +LinkNamed::~LinkNamed() { + if (name) { + delete name; + } +} + +//------------------------------------------------------------------------ +// LinkMovie +//------------------------------------------------------------------------ + +LinkMovie::LinkMovie(Object *obj) { + annotRef.num = -1; + annotTitle = NULL; + + Object tmp; + if (obj->dictLookupNF("Annotation", &tmp)->isRef()) { + annotRef = tmp.getRef(); + } + tmp.free(); + + if (obj->dictLookup("T", &tmp)->isString()) { + annotTitle = tmp.getString()->copy(); + } + tmp.free(); + + if ((annotTitle == NULL) && (annotRef.num == -1)) { + error(-1, "Movie action is missing both the Annot and T keys"); + } + + if (obj->dictLookup("Operation", &tmp)->isName()) { + char *name = tmp.getName(); + + if (!strcmp(name, "Play")) { + operation = operationTypePlay; + } + else if (!strcmp(name, "Stop")) { + operation = operationTypeStop; + } + else if (!strcmp(name, "Pause")) { + operation = operationTypePause; + } + else if (!strcmp(name, "Resume")) { + operation = operationTypeResume; + } + } + tmp.free(); +} + +LinkMovie::~LinkMovie() { + if (annotTitle) { + delete annotTitle; + } +} + +//------------------------------------------------------------------------ +// LinkSound +//------------------------------------------------------------------------ + +LinkSound::LinkSound(Object *soundObj) { + volume = 1.0; + sync = gFalse; + repeat = gFalse; + mix = gFalse; + sound = NULL; + if (soundObj->isDict()) + { + Object tmp; + // volume + soundObj->dictLookup("Volume", &tmp); + if (tmp.isNum()) { + volume = tmp.getNum(); + } + tmp.free(); + // sync + soundObj->dictLookup("Synchronous", &tmp); + if (tmp.isBool()) { + sync = tmp.getBool(); + } + tmp.free(); + // repeat + soundObj->dictLookup("Repeat", &tmp); + if (tmp.isBool()) { + repeat = tmp.getBool(); + } + tmp.free(); + // mix + soundObj->dictLookup("Mix", &tmp); + if (tmp.isBool()) { + mix = tmp.getBool(); + } + tmp.free(); + // 'Sound' object + soundObj->dictLookup("Sound", &tmp); + sound = Sound::parseSound(&tmp); + tmp.free(); + } +} + +LinkSound::~LinkSound() { + delete sound; +} + +//------------------------------------------------------------------------ +// LinkRendition +//------------------------------------------------------------------------ + +LinkRendition::LinkRendition(Object *obj) { + operation = -1; + media = NULL; + js = NULL; + + if (obj->isDict()) { + Object tmp; + + if (!obj->dictLookup("JS", &tmp)->isNull()) { + if (tmp.isString()) { + js = new GooString(tmp.getString()); + } else if (tmp.isStream()) { + Stream *stream = tmp.getStream(); + js = new GooString(); + stream->fillGooString(js); + } else { + error(-1, "Invalid Rendition Action: JS not string or stream"); + } + } + tmp.free(); + + if (obj->dictLookup("OP", &tmp)->isInt()) { + operation = tmp.getInt(); + if (!js && (operation < 0 || operation > 4)) { + error (-1, "Invalid Rendition Action: unrecognized operation valued: %d", operation); + } else { + Object obj1; + + // retrieve rendition object + if (obj->dictLookup("R", &renditionObj)->isDict()) { + media = new MediaRendition(&renditionObj); + } else if (operation == 0 || operation == 4) { + error (-1, "Invalid Rendition Action: no R field with op = %d", operation); + renditionObj.free(); + } + + if (!obj->dictLookupNF("AN", &screenRef)->isRef() && operation >= 0 && operation <= 4) { + error (-1, "Invalid Rendition Action: no AN field with op = %d", operation); + screenRef.free(); + } + } + } else if (!js) { + error(-1, "Invalid Rendition action: no OP or JS field defined"); + } + tmp.free(); + } +} + +LinkRendition::~LinkRendition() { + renditionObj.free(); + screenRef.free(); + + if (js) + delete js; + if (media) + delete media; +} + + +//------------------------------------------------------------------------ +// LinkJavaScript +//------------------------------------------------------------------------ + +LinkJavaScript::LinkJavaScript(Object *jsObj) { + js = NULL; + + if (jsObj->isString()) { + js = new GooString(jsObj->getString()); + } + else if (jsObj->isStream()) { + Stream *stream = jsObj->getStream(); + js = new GooString(); + stream->fillGooString(js); + } +} + +LinkJavaScript::~LinkJavaScript() { + if (js) { + delete js; + } +} + +//------------------------------------------------------------------------ +// LinkOCGState +//------------------------------------------------------------------------ +LinkOCGState::LinkOCGState(Object *obj) { + Object obj1; + + stateList = new GooList(); + preserveRB = gTrue; + + if (obj->dictLookup("State", &obj1)->isArray()) { + StateList *stList = NULL; + + for (int i = 0; i < obj1.arrayGetLength(); ++i) { + Object obj2; + + obj1.arrayGetNF(i, &obj2); + if (obj2.isName()) { + if (stList) + stateList->append(stList); + + char *name = obj2.getName(); + stList = new StateList(); + stList->list = new GooList(); + if (!strcmp (name, "ON")) { + stList->st = On; + } else if (!strcmp (name, "OFF")) { + stList->st = Off; + } else if (!strcmp (name, "Toggle")) { + stList->st = Toggle; + } else { + error (-1, "Invalid name '%s' in OCG Action state array", name); + delete stList; + stList = NULL; + } + } else if (obj2.isRef()) { + if (stList) { + Ref ocgRef = obj2.getRef(); + Ref *item = new Ref(); + item->num = ocgRef.num; + item->gen = ocgRef.gen; + stList->list->append(item); + } else { + error (-1, "Invalid OCG Action State array, expected name instead of ref"); + } + } else { + error (-1, "Invalid item in OCG Action State array"); + } + obj2.free(); + } + // Add the last group + if (stList) + stateList->append(stList); + } else { + error (-1, "Invalid OCGState action"); + delete stateList; + stateList = NULL; + } + obj1.free(); + + if (obj->dictLookup("PreserveRB", &obj1)->isBool()) { + preserveRB = obj1.getBool(); + } + obj1.free(); +} + +LinkOCGState::~LinkOCGState() { + if (stateList) + deleteGooList(stateList, StateList); +} + +LinkOCGState::StateList::~StateList() { + if (list) + deleteGooList(list, Ref); +} + +//------------------------------------------------------------------------ +// LinkUnknown +//------------------------------------------------------------------------ + +LinkUnknown::LinkUnknown(char *actionA) { + action = new GooString(actionA); +} + +LinkUnknown::~LinkUnknown() { + delete action; +} + +//------------------------------------------------------------------------ +// Links +//------------------------------------------------------------------------ + +Links::Links(Annots *annots) { + int size; + int i; + + links = NULL; + size = 0; + numLinks = 0; + + if (!annots) + return; + + for (i = 0; i < annots->getNumAnnots(); ++i) { + Annot *annot = annots->getAnnot(i); + + if (annot->getType() != Annot::typeLink) + continue; + + if (numLinks >= size) { + size += 16; + links = (AnnotLink **)greallocn(links, size, sizeof(AnnotLink *)); + } + annot->incRefCnt(); + links[numLinks++] = static_cast<AnnotLink *>(annot); + } +} + +Links::~Links() { + int i; + + for (i = 0; i < numLinks; ++i) + links[i]->decRefCnt(); + + gfree(links); +} + +LinkAction *Links::find(double x, double y) const { + int i; + + for (i = numLinks - 1; i >= 0; --i) { + if (links[i]->inRect(x, y)) { + return links[i]->getAction(); + } + } + return NULL; +} + +GBool Links::onLink(double x, double y) const { + int i; + + for (i = 0; i < numLinks; ++i) { + if (links[i]->inRect(x, y)) + return gTrue; + } + return gFalse; +} |