fixed windows access violation which occurs if one tries to retrieve
[swftools.git] / pdf2swf / xpdf / Link.cc
blobaf64c8bef5d713977649ad9e2e0909ee4fbee81f
1 //========================================================================
2 //
3 // Link.cc
4 //
5 // Copyright 1996-2002 Glyph & Cog, LLC
6 //
7 //========================================================================
9 #ifdef __GNUC__
10 #pragma implementation
11 #endif
13 #include <aconf.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include "gmem.h"
17 #include "GString.h"
18 #include "Error.h"
19 #include "Object.h"
20 #include "Array.h"
21 #include "Dict.h"
22 #include "Link.h"
24 //------------------------------------------------------------------------
26 static GString *getFileSpecName(Object *fileSpecObj);
28 //------------------------------------------------------------------------
29 // LinkDest
30 //------------------------------------------------------------------------
32 LinkDest::LinkDest(Array *a) {
33 Object obj1, obj2;
35 // initialize fields
36 left = bottom = right = top = zoom = 0;
37 ok = gFalse;
39 // get page
40 a->getNF(0, &obj1);
41 if (obj1.isInt()) {
42 pageNum = obj1.getInt() + 1;
43 pageIsRef = gFalse;
44 } else if (obj1.isRef()) {
45 pageRef.num = obj1.getRefNum();
46 pageRef.gen = obj1.getRefGen();
47 pageIsRef = gTrue;
48 } else {
49 error(-1, "Bad annotation destination");
50 goto err2;
52 obj1.free();
54 // get destination type
55 a->get(1, &obj1);
57 // XYZ link
58 if (obj1.isName("XYZ")) {
59 kind = destXYZ;
60 a->get(2, &obj2);
61 if (obj2.isNull()) {
62 changeLeft = gFalse;
63 } else if (obj2.isNum()) {
64 changeLeft = gTrue;
65 left = obj2.getNum();
66 } else {
67 error(-1, "Bad annotation destination position");
68 goto err1;
70 obj2.free();
71 a->get(3, &obj2);
72 if (obj2.isNull()) {
73 changeTop = gFalse;
74 } else if (obj2.isNum()) {
75 changeTop = gTrue;
76 top = obj2.getNum();
77 } else {
78 error(-1, "Bad annotation destination position");
79 goto err1;
81 obj2.free();
82 a->get(4, &obj2);
83 if (obj2.isNull()) {
84 changeZoom = gFalse;
85 } else if (obj2.isNum()) {
86 changeZoom = gTrue;
87 zoom = obj2.getNum();
88 } else {
89 error(-1, "Bad annotation destination position");
90 goto err1;
92 obj2.free();
94 // Fit link
95 } else if (obj1.isName("Fit")) {
96 kind = destFit;
98 // FitH link
99 } else if (obj1.isName("FitH")) {
100 kind = destFitH;
101 if (!a->get(2, &obj2)->isNum()) {
102 error(-1, "Bad annotation destination position");
103 goto err1;
105 top = obj2.getNum();
106 obj2.free();
108 // FitV link
109 } else if (obj1.isName("FitV")) {
110 kind = destFitV;
111 if (!a->get(2, &obj2)->isNum()) {
112 error(-1, "Bad annotation destination position");
113 goto err1;
115 left = obj2.getNum();
116 obj2.free();
118 // FitR link
119 } else if (obj1.isName("FitR")) {
120 kind = destFitR;
121 if (!a->get(2, &obj2)->isNum()) {
122 error(-1, "Bad annotation destination position");
123 goto err1;
125 left = obj2.getNum();
126 obj2.free();
127 if (!a->get(3, &obj2)->isNum()) {
128 error(-1, "Bad annotation destination position");
129 goto err1;
131 bottom = obj2.getNum();
132 obj2.free();
133 if (!a->get(4, &obj2)->isNum()) {
134 error(-1, "Bad annotation destination position");
135 goto err1;
137 right = obj2.getNum();
138 obj2.free();
139 if (!a->get(5, &obj2)->isNum()) {
140 error(-1, "Bad annotation destination position");
141 goto err1;
143 top = obj2.getNum();
144 obj2.free();
146 // FitB link
147 } else if (obj1.isName("FitB")) {
148 kind = destFitB;
150 // FitBH link
151 } else if (obj1.isName("FitBH")) {
152 kind = destFitBH;
153 if (!a->get(2, &obj2)->isNum()) {
154 error(-1, "Bad annotation destination position");
155 goto err1;
157 top = obj2.getNum();
158 obj2.free();
160 // FitBV link
161 } else if (obj1.isName("FitBV")) {
162 kind = destFitBV;
163 if (!a->get(2, &obj2)->isNum()) {
164 error(-1, "Bad annotation destination position");
165 goto err1;
167 left = obj2.getNum();
168 obj2.free();
170 // unknown link kind
171 } else {
172 error(-1, "Unknown annotation destination type");
173 goto err2;
176 obj1.free();
177 ok = gTrue;
178 return;
180 err1:
181 obj2.free();
182 err2:
183 obj1.free();
186 LinkDest::LinkDest(LinkDest *dest) {
187 kind = dest->kind;
188 pageIsRef = dest->pageIsRef;
189 if (pageIsRef)
190 pageRef = dest->pageRef;
191 else
192 pageNum = dest->pageNum;
193 left = dest->left;
194 bottom = dest->bottom;
195 right = dest->right;
196 top = dest->top;
197 zoom = dest->zoom;
198 changeLeft = dest->changeLeft;
199 changeTop = dest->changeTop;
200 changeZoom = dest->changeZoom;
201 ok = gTrue;
204 //------------------------------------------------------------------------
205 // LinkGoTo
206 //------------------------------------------------------------------------
208 LinkGoTo::LinkGoTo(Object *destObj) {
209 dest = NULL;
210 namedDest = NULL;
212 // named destination
213 if (destObj->isName()) {
214 namedDest = new GString(destObj->getName());
215 } else if (destObj->isString()) {
216 namedDest = destObj->getString()->copy();
218 // destination dictionary
219 } else if (destObj->isArray()) {
220 dest = new LinkDest(destObj->getArray());
221 if (!dest->isOk()) {
222 delete dest;
223 dest = NULL;
226 // error
227 } else {
228 error(-1, "Illegal annotation destination");
232 LinkGoTo::~LinkGoTo() {
233 if (dest)
234 delete dest;
235 if (namedDest)
236 delete namedDest;
239 //------------------------------------------------------------------------
240 // LinkGoToR
241 //------------------------------------------------------------------------
243 LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) {
244 dest = NULL;
245 namedDest = NULL;
247 // get file name
248 fileName = getFileSpecName(fileSpecObj);
250 // named destination
251 if (destObj->isName()) {
252 namedDest = new GString(destObj->getName());
253 } else if (destObj->isString()) {
254 namedDest = destObj->getString()->copy();
256 // destination dictionary
257 } else if (destObj->isArray()) {
258 dest = new LinkDest(destObj->getArray());
259 if (!dest->isOk()) {
260 delete dest;
261 dest = NULL;
264 // error
265 } else {
266 error(-1, "Illegal annotation destination");
270 LinkGoToR::~LinkGoToR() {
271 if (fileName)
272 delete fileName;
273 if (dest)
274 delete dest;
275 if (namedDest)
276 delete namedDest;
280 //------------------------------------------------------------------------
281 // LinkLaunch
282 //------------------------------------------------------------------------
284 LinkLaunch::LinkLaunch(Object *actionObj) {
285 Object obj1, obj2;
287 fileName = NULL;
288 params = NULL;
290 if (actionObj->isDict()) {
291 if (!actionObj->dictLookup("F", &obj1)->isNull()) {
292 fileName = getFileSpecName(&obj1);
293 } else {
294 obj1.free();
295 //~ This hasn't been defined by Adobe yet, so assume it looks
296 //~ just like the Win dictionary until they say otherwise.
297 if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
298 obj1.dictLookup("F", &obj2);
299 fileName = getFileSpecName(&obj2);
300 obj2.free();
301 if (obj1.dictLookup("P", &obj2)->isString())
302 params = obj2.getString()->copy();
303 obj2.free();
304 } else {
305 error(-1, "Bad launch-type link action");
308 obj1.free();
312 LinkLaunch::~LinkLaunch() {
313 if (fileName)
314 delete fileName;
315 if (params)
316 delete params;
319 //------------------------------------------------------------------------
320 // LinkURI
321 //------------------------------------------------------------------------
323 LinkURI::LinkURI(Object *uriObj, GString *baseURI) {
324 GString *uri2;
325 int n;
326 char c;
328 uri = NULL;
329 if (uriObj->isString()) {
330 uri2 = uriObj->getString()->copy();
331 if (baseURI) {
332 n = strcspn(uri2->getCString(), "/:");
333 if (n == uri2->getLength() || uri2->getChar(n) == '/') {
334 uri = baseURI->copy();
335 c = uri->getChar(uri->getLength() - 1);
336 if (c == '/' || c == '?') {
337 if (uri2->getChar(0) == '/') {
338 uri2->del(0);
340 } else {
341 if (uri2->getChar(0) != '/') {
342 uri->append('/');
345 uri->append(uri2);
346 delete uri2;
347 } else {
348 uri = uri2;
350 } else {
351 uri = uri2;
353 } else {
354 error(-1, "Illegal URI-type link");
358 LinkURI::~LinkURI() {
359 if (uri)
360 delete uri;
363 //------------------------------------------------------------------------
364 // LinkNamed
365 //------------------------------------------------------------------------
367 LinkNamed::LinkNamed(Object *nameObj) {
368 name = NULL;
369 if (nameObj->isName()) {
370 name = new GString(nameObj->getName());
374 LinkNamed::~LinkNamed() {
375 if (name) {
376 delete name;
380 //------------------------------------------------------------------------
381 // LinkUnknown
382 //------------------------------------------------------------------------
384 LinkUnknown::LinkUnknown(char *actionA) {
385 action = new GString(actionA);
388 LinkUnknown::~LinkUnknown() {
389 delete action;
392 //------------------------------------------------------------------------
393 // Link
394 //------------------------------------------------------------------------
396 Link::Link(Dict *dict, GString *baseURI) {
397 Object obj1, obj2, obj3, obj4;
398 double t;
400 action = NULL;
401 ok = gFalse;
403 // get rectangle
404 if (!dict->lookup("Rect", &obj1)->isArray()) {
405 error(-1, "Annotation rectangle is wrong type");
406 goto err2;
408 if (!obj1.arrayGet(0, &obj2)->isNum()) {
409 error(-1, "Bad annotation rectangle");
410 goto err1;
412 x1 = obj2.getNum();
413 obj2.free();
414 if (!obj1.arrayGet(1, &obj2)->isNum()) {
415 error(-1, "Bad annotation rectangle");
416 goto err1;
418 y1 = obj2.getNum();
419 obj2.free();
420 if (!obj1.arrayGet(2, &obj2)->isNum()) {
421 error(-1, "Bad annotation rectangle");
422 goto err1;
424 x2 = obj2.getNum();
425 obj2.free();
426 if (!obj1.arrayGet(3, &obj2)->isNum()) {
427 error(-1, "Bad annotation rectangle");
428 goto err1;
430 y2 = obj2.getNum();
431 obj2.free();
432 obj1.free();
433 if (x1 > x2) {
434 t = x1;
435 x1 = x2;
436 x2 = t;
438 if (y1 > y2) {
439 t = y1;
440 y1 = y2;
441 y2 = t;
444 // get border
445 borderW = 1;
446 if (!dict->lookup("Border", &obj1)->isNull()) {
447 if (obj1.isArray() && obj1.arrayGetLength() >= 3) {
448 if (obj1.arrayGet(2, &obj2)->isNum()) {
449 borderW = obj2.getNum();
450 } else {
451 error(-1, "Bad annotation border");
453 obj2.free();
456 obj1.free();
458 // look for destination
459 if (!dict->lookup("Dest", &obj1)->isNull()) {
460 action = new LinkGoTo(&obj1);
462 // look for action
463 } else {
464 obj1.free();
465 if (dict->lookup("A", &obj1)->isDict()) {
466 obj1.dictLookup("S", &obj2);
468 // GoTo action
469 if (obj2.isName("GoTo")) {
470 obj1.dictLookup("D", &obj3);
471 action = new LinkGoTo(&obj3);
472 obj3.free();
474 // GoToR action
475 } else if (obj2.isName("GoToR")) {
476 obj1.dictLookup("F", &obj3);
477 obj1.dictLookup("D", &obj4);
478 action = new LinkGoToR(&obj3, &obj4);
479 obj3.free();
480 obj4.free();
482 // Launch action
483 } else if (obj2.isName("Launch")) {
484 action = new LinkLaunch(&obj1);
486 // URI action
487 } else if (obj2.isName("URI")) {
488 obj1.dictLookup("URI", &obj3);
489 action = new LinkURI(&obj3, baseURI);
490 obj3.free();
492 // Named action
493 } else if (obj2.isName("Named")) {
494 obj1.dictLookup("N", &obj3);
495 action = new LinkNamed(&obj3);
496 obj3.free();
498 // unknown action
499 } else if (obj2.isName()) {
500 action = new LinkUnknown(obj2.getName());
502 // action is missing or wrong type
503 } else {
504 error(-1, "Bad annotation action");
505 action = NULL;
508 obj2.free();
510 } else {
511 error(-1, "Missing annotation destination/action");
512 action = NULL;
515 obj1.free();
517 // check for bad action
518 if (action && action->isOk())
519 ok = gTrue;
521 return;
523 err1:
524 obj2.free();
525 err2:
526 obj1.free();
529 Link::~Link() {
530 if (action)
531 delete action;
534 //------------------------------------------------------------------------
535 // Links
536 //------------------------------------------------------------------------
538 Links::Links(Object *annots, GString *baseURI) {
539 Link *link;
540 Object obj1, obj2;
541 int size;
542 int i;
544 links = NULL;
545 size = 0;
546 numLinks = 0;
548 if (annots->isArray()) {
549 for (i = 0; i < annots->arrayGetLength(); ++i) {
550 if (annots->arrayGet(i, &obj1)->isDict()) {
551 if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) {
552 link = new Link(obj1.getDict(), baseURI);
553 if (link->isOk()) {
554 if (numLinks >= size) {
555 size += 16;
556 links = (Link **)grealloc(links, size * sizeof(Link *));
558 links[numLinks++] = link;
559 } else {
560 delete link;
563 obj2.free();
565 obj1.free();
570 Links::~Links() {
571 int i;
573 for (i = 0; i < numLinks; ++i)
574 delete links[i];
575 gfree(links);
578 LinkAction *Links::find(double x, double y) {
579 int i;
581 for (i = numLinks - 1; i >= 0; --i) {
582 if (links[i]->inRect(x, y)) {
583 return links[i]->getAction();
586 return NULL;
589 GBool Links::onLink(double x, double y) {
590 int i;
592 for (i = 0; i < numLinks; ++i) {
593 if (links[i]->inRect(x, y))
594 return gTrue;
596 return gFalse;
599 //------------------------------------------------------------------------
601 // Extract a file name from a file specification (string or dictionary).
602 static GString *getFileSpecName(Object *fileSpecObj) {
603 GString *name;
604 Object obj1;
606 name = NULL;
608 // string
609 if (fileSpecObj->isString()) {
610 name = fileSpecObj->getString()->copy();
612 // dictionary
613 } else if (fileSpecObj->isDict()) {
614 if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) {
615 obj1.free();
616 fileSpecObj->dictLookup("F", &obj1);
618 if (obj1.isString())
619 name = obj1.getString()->copy();
620 else
621 error(-1, "Illegal file spec in link");
622 obj1.free();
624 // error
625 } else {
626 error(-1, "Illegal file spec in link");
629 return name;