source: trunk/poppler/mypoppler/poppler/Link.cc @ 461

Last change on this file since 461 was 461, checked in by Silvan Scherrer, 11 years ago

poppler update to 0.14.2

File size: 22.8 KB
Line 
1//========================================================================
2//
3// Link.cc
4//
5// Copyright 1996-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
9//========================================================================
10//
11// Modified under the Poppler project - http://poppler.freedesktop.org
12//
13// All changes made under the Poppler project to this file are licensed
14// under GPL version 2 or later
15//
16// Copyright (C) 2006, 2008 Pino Toscano <pino@kde.org>
17// Copyright (C) 2007,2010 Carlos Garcia Campos <carlosgc@gnome.org>
18// Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
19// Copyright (C) 2008, 2009 Albert Astals Cid <aacid@kde.org>
20// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
21// Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com>
22//
23// To see a description of the changes please see the Changelog file that
24// came with your tarball or type make ChangeLog if you are building from git
25//
26//========================================================================
27
28#include <config.h>
29
30#ifdef USE_GCC_PRAGMAS
31#pragma implementation
32#endif
33
34#include <stddef.h>
35#include <string.h>
36#include "goo/gmem.h"
37#include "goo/GooString.h"
38#include "goo/GooList.h"
39#include "Error.h"
40#include "Object.h"
41#include "Array.h"
42#include "Dict.h"
43#include "Link.h"
44#include "Sound.h"
45#include "FileSpec.h"
46#include "Rendition.h"
47
48//------------------------------------------------------------------------
49// LinkAction
50//------------------------------------------------------------------------
51
52LinkAction *LinkAction::parseDest(Object *obj) {
53  LinkAction *action;
54
55  action = new LinkGoTo(obj);
56  if (!action->isOk()) {
57    delete action;
58    return NULL;
59  }
60  return action;
61}
62
63LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
64  LinkAction *action;
65  Object obj2, obj3, obj4;
66
67  if (!obj->isDict()) {
68      error(-1, "parseAction: Bad annotation action for URI '%s'",
69            baseURI ? baseURI->getCString() : "NULL");
70      return NULL;
71  }
72
73  obj->dictLookup("S", &obj2);
74
75  // GoTo action
76  if (obj2.isName("GoTo")) {
77    obj->dictLookup("D", &obj3);
78    action = new LinkGoTo(&obj3);
79    obj3.free();
80
81  // GoToR action
82  } else if (obj2.isName("GoToR")) {
83    obj->dictLookup("F", &obj3);
84    obj->dictLookup("D", &obj4);
85    action = new LinkGoToR(&obj3, &obj4);
86    obj3.free();
87    obj4.free();
88
89  // Launch action
90  } else if (obj2.isName("Launch")) {
91    action = new LinkLaunch(obj);
92
93  // URI action
94  } else if (obj2.isName("URI")) {
95    obj->dictLookup("URI", &obj3);
96    action = new LinkURI(&obj3, baseURI);
97    obj3.free();
98
99  // Named action
100  } else if (obj2.isName("Named")) {
101    obj->dictLookup("N", &obj3);
102    action = new LinkNamed(&obj3);
103    obj3.free();
104
105  // Movie action
106  } else if (obj2.isName("Movie")) {
107    action = new LinkMovie(obj);
108
109  // Rendition action
110  } else if (obj2.isName("Rendition")) {
111    action = new LinkRendition(obj);
112
113  // Sound action
114  } else if (obj2.isName("Sound")) {
115    action = new LinkSound(obj);
116
117  // JavaScript action
118  } else if (obj2.isName("JavaScript")) {
119    obj->dictLookup("JS", &obj3);
120    action = new LinkJavaScript(&obj3);
121    obj3.free();
122
123  // Set-OCG-State action
124  } else if (obj2.isName("SetOCGState")) {
125    action = new LinkOCGState(obj);
126
127  // unknown action
128  } else if (obj2.isName()) {
129    action = new LinkUnknown(obj2.getName());
130
131  // action is missing or wrong type
132  } else {
133    error(-1, "parseAction: Unknown annotation action object: URI = '%s'",
134          baseURI ? baseURI->getCString() : "NULL");
135    action = NULL;
136  }
137
138  obj2.free();
139
140  if (action && !action->isOk()) {
141    delete action;
142    return NULL;
143  }
144  return action;
145}
146
147//------------------------------------------------------------------------
148// LinkDest
149//------------------------------------------------------------------------
150
151LinkDest::LinkDest(Array *a) {
152  Object obj1, obj2;
153
154  // initialize fields
155  left = bottom = right = top = zoom = 0;
156  changeLeft = changeTop = changeZoom = gFalse;
157  ok = gFalse;
158
159  // get page
160  if (a->getLength() < 2) {
161    error(-1, "Annotation destination array is too short");
162    return;
163  }
164  a->getNF(0, &obj1);
165  if (obj1.isInt()) {
166    pageNum = obj1.getInt() + 1;
167    pageIsRef = gFalse;
168  } else if (obj1.isRef()) {
169    pageRef.num = obj1.getRefNum();
170    pageRef.gen = obj1.getRefGen();
171    pageIsRef = gTrue;
172  } else {
173    error(-1, "Bad annotation destination");
174    goto err2;
175  }
176  obj1.free();
177
178  // get destination type
179  a->get(1, &obj1);
180
181  // XYZ link
182  if (obj1.isName("XYZ")) {
183    kind = destXYZ;
184    if (a->getLength() < 3) {
185      changeLeft = gFalse;
186    } else {
187      a->get(2, &obj2);
188      if (obj2.isNull()) {
189        changeLeft = gFalse;
190      } else if (obj2.isNum()) {
191        changeLeft = gTrue;
192        left = obj2.getNum();
193      } else {
194        error(-1, "Bad annotation destination position");
195        goto err1;
196      }
197      obj2.free();
198    }
199    if (a->getLength() < 4) {
200      changeTop = gFalse;
201    } else {
202      a->get(3, &obj2);
203      if (obj2.isNull()) {
204        changeTop = gFalse;
205      } else if (obj2.isNum()) {
206        changeTop = gTrue;
207        top = obj2.getNum();
208      } else {
209        error(-1, "Bad annotation destination position");
210        goto err1;
211      }
212      obj2.free();
213    }
214    if (a->getLength() < 5) {
215      changeZoom = gFalse;
216    } else {
217      a->get(4, &obj2);
218      if (obj2.isNull()) {
219        changeZoom = gFalse;
220      } else if (obj2.isNum()) {
221        changeZoom = gTrue;
222        zoom = obj2.getNum();
223      } else {
224        error(-1, "Bad annotation destination position");
225        goto err1;
226      }
227      obj2.free();
228    }
229
230  // Fit link
231  } else if (obj1.isName("Fit")) {
232    if (a->getLength() < 2) {
233      error(-1, "Annotation destination array is too short");
234      goto err2;
235    }
236    kind = destFit;
237
238  // FitH link
239  } else if (obj1.isName("FitH")) {
240    if (a->getLength() < 3) {
241      error(-1, "Annotation destination array is too short");
242      goto err2;
243    }
244    kind = destFitH;
245    a->get(2, &obj2);
246    if (obj2.isNull()) {
247      changeTop = gFalse;
248    } else if (obj2.isNum()) {
249      changeTop = gTrue;
250      top = obj2.getNum();
251    } else {
252      error(-1, "Bad annotation destination position");
253      kind = destFit;
254    }
255    obj2.free();
256
257  // FitV link
258  } else if (obj1.isName("FitV")) {
259    if (a->getLength() < 3) {
260      error(-1, "Annotation destination array is too short");
261      goto err2;
262    }
263    kind = destFitV;
264    a->get(2, &obj2);
265    if (obj2.isNull()) {
266      changeLeft = gFalse;
267    } else if (obj2.isNum()) {
268      changeLeft = gTrue;
269      left = obj2.getNum();
270    } else {
271      error(-1, "Bad annotation destination position");
272      kind = destFit;
273    }
274    obj2.free();
275
276  // FitR link
277  } else if (obj1.isName("FitR")) {
278    if (a->getLength() < 6) {
279      error(-1, "Annotation destination array is too short");
280      goto err2;
281    }
282    kind = destFitR;
283    if (!a->get(2, &obj2)->isNum()) {
284      error(-1, "Bad annotation destination position");
285      kind = destFit;
286    }
287    left = obj2.getNum();
288    obj2.free();
289    if (!a->get(3, &obj2)->isNum()) {
290      error(-1, "Bad annotation destination position");
291      kind = destFit;
292    }
293    bottom = obj2.getNum();
294    obj2.free();
295    if (!a->get(4, &obj2)->isNum()) {
296      error(-1, "Bad annotation destination position");
297      kind = destFit;
298    }
299    right = obj2.getNum();
300    obj2.free();
301    if (!a->get(5, &obj2)->isNum()) {
302      error(-1, "Bad annotation destination position");
303      kind = destFit;
304    }
305    top = obj2.getNum();
306    obj2.free();
307
308  // FitB link
309  } else if (obj1.isName("FitB")) {
310    if (a->getLength() < 2) {
311      error(-1, "Annotation destination array is too short");
312      goto err2;
313    }
314    kind = destFitB;
315
316  // FitBH link
317  } else if (obj1.isName("FitBH")) {
318    if (a->getLength() < 3) {
319      error(-1, "Annotation destination array is too short");
320      goto err2;
321    }
322    kind = destFitBH;
323    a->get(2, &obj2);
324    if (obj2.isNull()) {
325      changeTop = gFalse;
326    } else if (obj2.isNum()) {
327      changeTop = gTrue;
328      top = obj2.getNum();
329    } else {
330      error(-1, "Bad annotation destination position");
331      kind = destFit;
332    }
333    obj2.free();
334
335  // FitBV link
336  } else if (obj1.isName("FitBV")) {
337    if (a->getLength() < 3) {
338      error(-1, "Annotation destination array is too short");
339      goto err2;
340    }
341    kind = destFitBV;
342    a->get(2, &obj2);
343    if (obj2.isNull()) {
344      changeLeft = gFalse;
345    } else if (obj2.isNum()) {
346      changeLeft = gTrue;
347      left = obj2.getNum();
348    } else {
349      error(-1, "Bad annotation destination position");
350      kind = destFit;
351    }
352    obj2.free();
353
354  // unknown link kind
355  } else {
356    error(-1, "Unknown annotation destination type");
357    goto err2;
358  }
359
360  obj1.free();
361  ok = gTrue;
362  return;
363
364 err1:
365  obj2.free();
366 err2:
367  obj1.free();
368}
369
370LinkDest::LinkDest(LinkDest *dest) {
371  kind = dest->kind;
372  pageIsRef = dest->pageIsRef;
373  if (pageIsRef)
374    pageRef = dest->pageRef;
375  else
376    pageNum = dest->pageNum;
377  left = dest->left;
378  bottom = dest->bottom;
379  right = dest->right;
380  top = dest->top;
381  zoom = dest->zoom;
382  changeLeft = dest->changeLeft;
383  changeTop = dest->changeTop;
384  changeZoom = dest->changeZoom;
385  ok = gTrue;
386}
387
388//------------------------------------------------------------------------
389// LinkGoTo
390//------------------------------------------------------------------------
391
392LinkGoTo::LinkGoTo(Object *destObj) {
393  dest = NULL;
394  namedDest = NULL;
395
396  // named destination
397  if (destObj->isName()) {
398    namedDest = new GooString(destObj->getName());
399  } else if (destObj->isString()) {
400    namedDest = destObj->getString()->copy();
401
402  // destination dictionary
403  } else if (destObj->isArray()) {
404    dest = new LinkDest(destObj->getArray());
405    if (!dest->isOk()) {
406      delete dest;
407      dest = NULL;
408    }
409
410  // error
411  } else {
412    error(-1, "Illegal annotation destination");
413  }
414}
415
416LinkGoTo::~LinkGoTo() {
417  if (dest)
418    delete dest;
419  if (namedDest)
420    delete namedDest;
421}
422
423//------------------------------------------------------------------------
424// LinkGoToR
425//------------------------------------------------------------------------
426
427LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) {
428  fileName = NULL;
429  dest = NULL;
430  namedDest = NULL;
431
432  // get file name
433  Object obj1;
434  if (getFileSpecNameForPlatform (fileSpecObj, &obj1)) {
435    fileName = obj1.getString()->copy();
436    obj1.free();
437  }
438
439  // named destination
440  if (destObj->isName()) {
441    namedDest = new GooString(destObj->getName());
442  } else if (destObj->isString()) {
443    namedDest = destObj->getString()->copy();
444
445  // destination dictionary
446  } else if (destObj->isArray()) {
447    dest = new LinkDest(destObj->getArray());
448    if (!dest->isOk()) {
449      delete dest;
450      dest = NULL;
451    }
452
453  // error
454  } else {
455    error(-1, "Illegal annotation destination");
456  }
457}
458
459LinkGoToR::~LinkGoToR() {
460  if (fileName)
461    delete fileName;
462  if (dest)
463    delete dest;
464  if (namedDest)
465    delete namedDest;
466}
467
468
469//------------------------------------------------------------------------
470// LinkLaunch
471//------------------------------------------------------------------------
472
473LinkLaunch::LinkLaunch(Object *actionObj) {
474  Object obj1, obj2, obj3;
475
476  fileName = NULL;
477  params = NULL;
478
479  if (actionObj->isDict()) {
480    if (!actionObj->dictLookup("F", &obj1)->isNull()) {
481      if (getFileSpecNameForPlatform (&obj1, &obj3)) {
482        fileName = obj3.getString()->copy();
483        obj3.free();
484      }
485    } else {
486      obj1.free();
487#ifdef _WIN32
488      if (actionObj->dictLookup("Win", &obj1)->isDict()) {
489        obj1.dictLookup("F", &obj2);
490        if (getFileSpecNameForPlatform (&obj2, &obj3)) {
491          fileName = obj3.getString()->copy();
492          obj3.free();
493        }
494        obj2.free();
495        if (obj1.dictLookup("P", &obj2)->isString()) {
496          params = obj2.getString()->copy();
497        }
498        obj2.free();
499      } else {
500        error(-1, "Bad launch-type link action");
501      }
502#else
503      //~ This hasn't been defined by Adobe yet, so assume it looks
504      //~ just like the Win dictionary until they say otherwise.
505      if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
506        obj1.dictLookup("F", &obj2);
507        if (getFileSpecNameForPlatform (&obj2, &obj3)) {
508          fileName = obj3.getString()->copy();
509          obj3.free();
510        }
511        obj2.free();
512        if (obj1.dictLookup("P", &obj2)->isString()) {
513          params = obj2.getString()->copy();
514        }
515        obj2.free();
516      } else {
517        error(-1, "Bad launch-type link action");
518      }
519#endif
520    }
521    obj1.free();
522  }
523}
524
525LinkLaunch::~LinkLaunch() {
526  if (fileName)
527    delete fileName;
528  if (params)
529    delete params;
530}
531
532//------------------------------------------------------------------------
533// LinkURI
534//------------------------------------------------------------------------
535
536LinkURI::LinkURI(Object *uriObj, GooString *baseURI) {
537  GooString *uri2;
538  int n;
539  char c;
540
541  uri = NULL;
542  if (uriObj->isString()) {
543    uri2 = uriObj->getString()->copy();
544    if (baseURI && baseURI->getLength() > 0) {
545      n = strcspn(uri2->getCString(), "/:");
546      if (n == uri2->getLength() || uri2->getChar(n) == '/') {
547        uri = baseURI->copy();
548        c = uri->getChar(uri->getLength() - 1);
549        if (c == '/' || c == '?') {
550          if (uri2->getChar(0) == '/') {
551            uri2->del(0);
552          }
553        } else {
554          if (uri2->getChar(0) != '/') {
555            uri->append('/');
556          }
557        }
558        uri->append(uri2);
559        delete uri2;
560      } else {
561        uri = uri2;
562      }
563    } else {
564      uri = uri2;
565    }
566  } else {
567    error(-1, "Illegal URI-type link");
568  }
569}
570
571LinkURI::~LinkURI() {
572  if (uri)
573    delete uri;
574}
575
576//------------------------------------------------------------------------
577// LinkNamed
578//------------------------------------------------------------------------
579
580LinkNamed::LinkNamed(Object *nameObj) {
581  name = NULL;
582  if (nameObj->isName()) {
583    name = new GooString(nameObj->getName());
584  }
585}
586
587LinkNamed::~LinkNamed() {
588  if (name) {
589    delete name;
590  }
591}
592
593//------------------------------------------------------------------------
594// LinkMovie
595//------------------------------------------------------------------------
596
597LinkMovie::LinkMovie(Object *obj) {
598  annotRef.num = -1;
599  annotTitle = NULL;
600
601  Object tmp;
602  if (obj->dictLookupNF("Annotation", &tmp)->isRef()) {
603    annotRef = tmp.getRef();
604  }
605  tmp.free();
606
607  if (obj->dictLookup("T", &tmp)->isString()) {
608    annotTitle = tmp.getString()->copy();
609  }
610  tmp.free();
611
612  if ((annotTitle == NULL) && (annotRef.num == -1)) {
613    error(-1, "Movie action is missing both the Annot and T keys");
614  }
615
616  if (obj->dictLookup("Operation", &tmp)->isName()) {
617    char *name = tmp.getName();
618   
619    if (!strcmp(name, "Play")) {
620      operation = operationTypePlay;
621    }
622    else if (!strcmp(name, "Stop")) {
623      operation = operationTypeStop;
624    }
625    else if (!strcmp(name, "Pause")) {
626      operation = operationTypePause;
627    }
628    else if (!strcmp(name, "Resume")) {
629      operation = operationTypeResume;
630    }
631  }
632  tmp.free();
633}
634
635LinkMovie::~LinkMovie() {
636  if (annotTitle) {
637    delete annotTitle;
638  }
639}
640
641//------------------------------------------------------------------------
642// LinkSound
643//------------------------------------------------------------------------
644
645LinkSound::LinkSound(Object *soundObj) {
646  volume = 1.0;
647  sync = gFalse;
648  repeat = gFalse;
649  mix = gFalse;
650  sound = NULL;
651  if (soundObj->isDict())
652  {
653    Object tmp;
654    // volume
655    soundObj->dictLookup("Volume", &tmp);
656    if (tmp.isNum()) {
657      volume = tmp.getNum();
658    }
659    tmp.free();
660    // sync
661    soundObj->dictLookup("Synchronous", &tmp);
662    if (tmp.isBool()) {
663      sync = tmp.getBool();
664    }
665    tmp.free();
666    // repeat
667    soundObj->dictLookup("Repeat", &tmp);
668    if (tmp.isBool()) {
669      repeat = tmp.getBool();
670    }
671    tmp.free();
672    // mix
673    soundObj->dictLookup("Mix", &tmp);
674    if (tmp.isBool()) {
675      mix = tmp.getBool();
676    }
677    tmp.free();
678    // 'Sound' object
679    soundObj->dictLookup("Sound", &tmp);
680    sound = Sound::parseSound(&tmp);
681    tmp.free();
682  }
683}
684
685LinkSound::~LinkSound() {
686  delete sound;
687}
688
689//------------------------------------------------------------------------
690// LinkRendition
691//------------------------------------------------------------------------
692
693LinkRendition::LinkRendition(Object *obj) {
694  operation = -1;
695  media = NULL;
696  js = NULL;
697
698  if (obj->isDict()) {
699    Object tmp;
700
701    if (!obj->dictLookup("JS", &tmp)->isNull()) {
702      if (tmp.isString()) {
703        js = new GooString(tmp.getString());
704      } else if (tmp.isStream()) {
705        Stream *stream = tmp.getStream();
706        js = new GooString();
707        stream->reset();
708        int i;
709        while ((i = stream->getChar()) != EOF) {
710          js->append((char)i);
711        }
712      } else {
713        error(-1, "Invalid Rendition Action: JS not string or stream");
714      }
715    }
716    tmp.free();
717
718    if (obj->dictLookup("OP", &tmp)->isInt()) {
719      operation = tmp.getInt();
720      if (!js && (operation < 0 || operation > 4)) {
721        error (-1, "Invalid Rendition Action: unrecognized operation valued: %d", operation);
722      } else {
723        Object obj1;
724
725        // retrieve rendition object
726        if (obj->dictLookup("R", &renditionObj)->isDict()) {
727          media = new MediaRendition(&renditionObj);
728        } else if (operation == 0 || operation == 4) {
729          error (-1, "Invalid Rendition Action: no R field with op = %d", operation);
730          renditionObj.free();
731        }
732
733        if (!obj->dictLookupNF("AN", &screenRef)->isRef() && operation >= 0 && operation <= 4) {
734          error (-1, "Invalid Rendition Action: no AN field with op = %d", operation);
735          screenRef.free();
736        }
737      }
738    } else if (!js) {
739      error(-1, "Invalid Rendition action: no OP or JS field defined");
740    }
741    tmp.free();
742  }
743}
744
745LinkRendition::~LinkRendition() {
746  renditionObj.free();
747  screenRef.free();
748
749  if (js)
750    delete js;
751  if (media)
752    delete media;
753}
754
755
756//------------------------------------------------------------------------
757// LinkJavaScript
758//------------------------------------------------------------------------
759
760LinkJavaScript::LinkJavaScript(Object *jsObj) {
761  js = NULL;
762
763  if (jsObj->isString()) {
764    js = new GooString(jsObj->getString());
765  }
766  else if (jsObj->isStream()) {
767    Stream *stream = jsObj->getStream();
768    js = new GooString();
769    stream->reset();
770    int i;
771    while ((i = stream->getChar()) != EOF) {
772      js->append((char)i);
773    }
774  }
775}
776
777LinkJavaScript::~LinkJavaScript() {
778  if (js) {
779    delete js;
780  }
781}
782
783//------------------------------------------------------------------------
784// LinkOCGState
785//------------------------------------------------------------------------
786LinkOCGState::LinkOCGState(Object *obj) {
787  Object obj1;
788
789  stateList = new GooList();
790  preserveRB = gTrue;
791
792  if (obj->dictLookup("State", &obj1)->isArray()) {
793    StateList *stList = NULL;
794
795    for (int i = 0; i < obj1.arrayGetLength(); ++i) {
796      Object obj2;
797
798      obj1.arrayGetNF(i, &obj2);
799      if (obj2.isName()) {
800        if (stList)
801          stateList->append(stList);
802
803        char *name = obj2.getName();
804        stList = new StateList();
805        stList->list = new GooList();
806        if (!strcmp (name, "ON")) {
807          stList->st = On;
808        } else if (!strcmp (name, "OFF")) {
809          stList->st = Off;
810        } else if (!strcmp (name, "Toggle")) {
811          stList->st = Toggle;
812        } else {
813          error (-1, "Invalid name '%s' in OCG Action state array", name);
814          delete stList;
815          stList = NULL;
816        }
817      } else if (obj2.isRef()) {
818        if (stList) {
819          Ref ocgRef = obj2.getRef();
820          Ref *item = new Ref();
821          item->num = ocgRef.num;
822          item->gen = ocgRef.gen;
823          stList->list->append(item);
824        } else {
825          error (-1, "Invalid OCG Action State array, expected name instead of ref");
826        }
827      } else {
828        error (-1, "Invalid item in OCG Action State array");
829      }
830      obj2.free();
831    }
832    // Add the last group
833    if (stList)
834      stateList->append(stList);
835  } else {
836    error (-1, "Invalid OCGState action");
837    delete stateList;
838    stateList = NULL;
839  }
840  obj1.free();
841
842  if (obj->dictLookup("PreserveRB", &obj1)->isBool()) {
843    preserveRB = obj1.getBool();
844  }
845  obj1.free();
846}
847
848LinkOCGState::~LinkOCGState() {
849  if (stateList)
850    deleteGooList(stateList, StateList);
851}
852
853LinkOCGState::StateList::~StateList() {
854  if (list)
855    deleteGooList(list, Ref);
856}
857
858//------------------------------------------------------------------------
859// LinkUnknown
860//------------------------------------------------------------------------
861
862LinkUnknown::LinkUnknown(char *actionA) {
863  action = new GooString(actionA);
864}
865
866LinkUnknown::~LinkUnknown() {
867  delete action;
868}
869
870//------------------------------------------------------------------------
871// Link
872//------------------------------------------------------------------------
873
874Link::Link(Dict *dict, GooString *baseURI) {
875  Object obj1, obj2;
876  double t;
877
878  action = NULL;
879  ok = gFalse;
880
881  // get rectangle
882  if (!dict->lookup("Rect", &obj1)->isArray()) {
883    error(-1, "Annotation rectangle is wrong type");
884    goto err2;
885  }
886  if (!obj1.arrayGet(0, &obj2)->isNum()) {
887    error(-1, "Bad annotation rectangle");
888    goto err1;
889  }
890  x1 = obj2.getNum();
891  obj2.free();
892  if (!obj1.arrayGet(1, &obj2)->isNum()) {
893    error(-1, "Bad annotation rectangle");
894    goto err1;
895  }
896  y1 = obj2.getNum();
897  obj2.free();
898  if (!obj1.arrayGet(2, &obj2)->isNum()) {
899    error(-1, "Bad annotation rectangle");
900    goto err1;
901  }
902  x2 = obj2.getNum();
903  obj2.free();
904  if (!obj1.arrayGet(3, &obj2)->isNum()) {
905    error(-1, "Bad annotation rectangle");
906    goto err1;
907  }
908  y2 = obj2.getNum();
909  obj2.free();
910  obj1.free();
911  if (x1 > x2) {
912    t = x1;
913    x1 = x2;
914    x2 = t;
915  }
916  if (y1 > y2) {
917    t = y1;
918    y1 = y2;
919    y2 = t;
920  }
921
922  // look for destination
923  if (!dict->lookup("Dest", &obj1)->isNull()) {
924    action = LinkAction::parseDest(&obj1);
925
926  // look for action
927  } else {
928    obj1.free();
929    if (dict->lookup("A", &obj1)->isDict()) {
930      action = LinkAction::parseAction(&obj1, baseURI);
931    }
932  }
933  obj1.free();
934
935  // check for bad action
936  if (action) {
937    ok = gTrue;
938  }
939
940  return;
941
942 err1:
943  obj2.free();
944 err2:
945  obj1.free();
946}
947
948Link::~Link() {
949  if (action) {
950    delete action;
951  }
952}
953
954//------------------------------------------------------------------------
955// Links
956//------------------------------------------------------------------------
957
958Links::Links(Object *annots, GooString *baseURI) {
959  Link *link;
960  Object obj1, obj2;
961  int size;
962  int i;
963
964  links = NULL;
965  size = 0;
966  numLinks = 0;
967
968  if (annots->isArray()) {
969    for (i = 0; i < annots->arrayGetLength(); ++i) {
970      if (annots->arrayGet(i, &obj1)->isDict()) {
971        if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) {
972          link = new Link(obj1.getDict(), baseURI);
973          if (link->isOk()) {
974            if (numLinks >= size) {
975              size += 16;
976              links = (Link **)greallocn(links, size, sizeof(Link *));
977            }
978            links[numLinks++] = link;
979          } else {
980            delete link;
981          }
982        }
983        obj2.free();
984      }
985      obj1.free();
986    }
987  }
988}
989
990Links::~Links() {
991  int i;
992
993  for (i = 0; i < numLinks; ++i)
994    delete links[i];
995  gfree(links);
996}
997
998LinkAction *Links::find(double x, double y) const {
999  int i;
1000
1001  for (i = numLinks - 1; i >= 0; --i) {
1002    if (links[i]->inRect(x, y)) {
1003      return links[i]->getAction();
1004    }
1005  }
1006  return NULL;
1007}
1008
1009GBool Links::onLink(double x, double y) const {
1010  int i;
1011
1012  for (i = 0; i < numLinks; ++i) {
1013    if (links[i]->inRect(x, y))
1014      return gTrue;
1015  }
1016  return gFalse;
1017}
Note: See TracBrowser for help on using the repository browser.