summaryrefslogtreecommitdiff
path: root/noncore/unsupported/qpdf/xpdf/Link.cc
Unidiff
Diffstat (limited to 'noncore/unsupported/qpdf/xpdf/Link.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/unsupported/qpdf/xpdf/Link.cc634
1 files changed, 634 insertions, 0 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/Link.cc b/noncore/unsupported/qpdf/xpdf/Link.cc
new file mode 100644
index 0000000..79a5f6e
--- a/dev/null
+++ b/noncore/unsupported/qpdf/xpdf/Link.cc
@@ -0,0 +1,634 @@
1//========================================================================
2//
3// Link.cc
4//
5// Copyright 1996 Derek B. Noonburg
6//
7//========================================================================
8
9#ifdef __GNUC__
10#pragma implementation
11#endif
12
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"
23
24//------------------------------------------------------------------------
25
26static GString *getFileSpecName(Object *fileSpecObj);
27
28//------------------------------------------------------------------------
29// LinkDest
30//------------------------------------------------------------------------
31
32LinkDest::LinkDest(Array *a, GBool pageIsRefA) {
33 Object obj1, obj2;
34
35 // initialize fields
36 pageIsRef = pageIsRefA;
37 left = bottom = right = top = zoom = 0;
38 ok = gFalse;
39
40 // get page
41 if (pageIsRef) {
42 if (!a->getNF(0, &obj1)->isRef()) {
43 error(-1, "Bad annotation destination");
44 goto err2;
45 }
46 pageRef.num = obj1.getRefNum();
47 pageRef.gen = obj1.getRefGen();
48 obj1.free();
49 } else {
50 if (!a->get(0, &obj1)->isInt()) {
51 error(-1, "Bad annotation destination");
52 goto err2;
53 }
54 pageNum = obj1.getInt() + 1;
55 obj1.free();
56 }
57
58 // get destination type
59 a->get(1, &obj1);
60
61 // XYZ link
62 if (obj1.isName("XYZ")) {
63 kind = destXYZ;
64 a->get(2, &obj2);
65 if (obj2.isNull()) {
66 changeLeft = gFalse;
67 } else if (obj2.isNum()) {
68 changeLeft = gTrue;
69 left = obj2.getNum();
70 } else {
71 error(-1, "Bad annotation destination position");
72 goto err1;
73 }
74 obj2.free();
75 a->get(3, &obj2);
76 if (obj2.isNull()) {
77 changeTop = gFalse;
78 } else if (obj2.isNum()) {
79 changeTop = gTrue;
80 top = obj2.getNum();
81 } else {
82 error(-1, "Bad annotation destination position");
83 goto err1;
84 }
85 obj2.free();
86 a->get(4, &obj2);
87 if (obj2.isNull()) {
88 changeZoom = gFalse;
89 } else if (obj2.isNum()) {
90 changeZoom = gTrue;
91 zoom = obj2.getNum();
92 } else {
93 error(-1, "Bad annotation destination position");
94 goto err1;
95 }
96 obj2.free();
97
98 // Fit link
99 } else if (obj1.isName("Fit")) {
100 kind = destFit;
101
102 // FitH link
103 } else if (obj1.isName("FitH")) {
104 kind = destFitH;
105 if (!a->get(2, &obj2)->isNum()) {
106 error(-1, "Bad annotation destination position");
107 goto err1;
108 }
109 top = obj2.getNum();
110 obj2.free();
111
112 // FitV link
113 } else if (obj1.isName("FitV")) {
114 kind = destFitV;
115 if (!a->get(2, &obj2)->isNum()) {
116 error(-1, "Bad annotation destination position");
117 goto err1;
118 }
119 left = obj2.getNum();
120 obj2.free();
121
122 // FitR link
123 } else if (obj1.isName("FitR")) {
124 kind = destFitR;
125 if (!a->get(2, &obj2)->isNum()) {
126 error(-1, "Bad annotation destination position");
127 goto err1;
128 }
129 left = obj2.getNum();
130 obj2.free();
131 if (!a->get(3, &obj2)->isNum()) {
132 error(-1, "Bad annotation destination position");
133 goto err1;
134 }
135 bottom = obj2.getNum();
136 obj2.free();
137 if (!a->get(4, &obj2)->isNum()) {
138 error(-1, "Bad annotation destination position");
139 goto err1;
140 }
141 right = obj2.getNum();
142 obj2.free();
143 if (!a->get(5, &obj2)->isNum()) {
144 error(-1, "Bad annotation destination position");
145 goto err1;
146 }
147 top = obj2.getNum();
148 obj2.free();
149
150 // FitB link
151 } else if (obj1.isName("FitB")) {
152 kind = destFitB;
153
154 // FitBH link
155 } else if (obj1.isName("FitBH")) {
156 kind = destFitBH;
157 if (!a->get(2, &obj2)->isNum()) {
158 error(-1, "Bad annotation destination position");
159 goto err1;
160 }
161 top = obj2.getNum();
162 obj2.free();
163
164 // FitBV link
165 } else if (obj1.isName("FitBV")) {
166 kind = destFitBV;
167 if (!a->get(2, &obj2)->isNum()) {
168 error(-1, "Bad annotation destination position");
169 goto err1;
170 }
171 left = obj2.getNum();
172 obj2.free();
173
174 // unknown link kind
175 } else {
176 error(-1, "Unknown annotation destination type");
177 goto err2;
178 }
179
180 obj1.free();
181 ok = gTrue;
182 return;
183
184 err1:
185 obj2.free();
186 err2:
187 obj1.free();
188}
189
190LinkDest::LinkDest(LinkDest *dest) {
191 kind = dest->kind;
192 pageIsRef = dest->pageIsRef;
193 if (pageIsRef)
194 pageRef = dest->pageRef;
195 else
196 pageNum = dest->pageNum;
197 left = dest->left;
198 bottom = dest->bottom;
199 right = dest->right;
200 top = dest->top;
201 zoom = dest->zoom;
202 changeLeft = dest->changeLeft;
203 changeTop = dest->changeTop;
204 changeZoom = dest->changeZoom;
205 ok = gTrue;
206}
207
208//------------------------------------------------------------------------
209// LinkGoTo
210//------------------------------------------------------------------------
211
212LinkGoTo::LinkGoTo(Object *destObj) {
213 dest = NULL;
214 namedDest = NULL;
215
216 // named destination
217 if (destObj->isName()) {
218 namedDest = new GString(destObj->getName());
219 } else if (destObj->isString()) {
220 namedDest = destObj->getString()->copy();
221
222 // destination dictionary
223 } else if (destObj->isArray()) {
224 dest = new LinkDest(destObj->getArray(), gTrue);
225 if (!dest->isOk()) {
226 delete dest;
227 dest = NULL;
228 }
229
230 // error
231 } else {
232 error(-1, "Illegal annotation destination");
233 }
234}
235
236LinkGoTo::~LinkGoTo() {
237 if (dest)
238 delete dest;
239 if (namedDest)
240 delete namedDest;
241}
242
243//------------------------------------------------------------------------
244// LinkGoToR
245//------------------------------------------------------------------------
246
247LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) {
248 dest = NULL;
249 namedDest = NULL;
250
251 // get file name
252 fileName = getFileSpecName(fileSpecObj);
253
254 // named destination
255 if (destObj->isName()) {
256 namedDest = new GString(destObj->getName());
257 } else if (destObj->isString()) {
258 namedDest = destObj->getString()->copy();
259
260 // destination dictionary
261 } else if (destObj->isArray()) {
262 dest = new LinkDest(destObj->getArray(), gFalse);
263 if (!dest->isOk()) {
264 delete dest;
265 dest = NULL;
266 }
267
268 // error
269 } else {
270 error(-1, "Illegal annotation destination");
271 }
272}
273
274LinkGoToR::~LinkGoToR() {
275 if (fileName)
276 delete fileName;
277 if (dest)
278 delete dest;
279 if (namedDest)
280 delete namedDest;
281}
282
283
284//------------------------------------------------------------------------
285// LinkLaunch
286//------------------------------------------------------------------------
287
288LinkLaunch::LinkLaunch(Object *actionObj) {
289 Object obj1, obj2;
290
291 fileName = NULL;
292 params = NULL;
293
294 if (actionObj->isDict()) {
295 if (!actionObj->dictLookup("F", &obj1)->isNull()) {
296 fileName = getFileSpecName(&obj1);
297 } else {
298 obj1.free();
299 //~ This hasn't been defined by Adobe yet, so assume it looks
300 //~ just like the Win dictionary until they say otherwise.
301 if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
302 obj1.dictLookup("F", &obj2);
303 fileName = getFileSpecName(&obj2);
304 obj2.free();
305 if (obj1.dictLookup("P", &obj2)->isString())
306 params = obj2.getString()->copy();
307 obj2.free();
308 } else {
309 error(-1, "Bad launch-type link action");
310 }
311 }
312 obj1.free();
313 }
314}
315
316LinkLaunch::~LinkLaunch() {
317 if (fileName)
318 delete fileName;
319 if (params)
320 delete params;
321}
322
323//------------------------------------------------------------------------
324// LinkURI
325//------------------------------------------------------------------------
326
327LinkURI::LinkURI(Object *uriObj, GString *baseURI) {
328 GString *uri2;
329 int n;
330 char c;
331
332 uri = NULL;
333 if (uriObj->isString()) {
334 uri2 = uriObj->getString()->copy();
335 if (baseURI) {
336 n = strcspn(uri2->getCString(), "/:");
337 if (n == uri2->getLength() || uri2->getChar(n) == '/') {
338 uri = baseURI->copy();
339 c = uri->getChar(uri->getLength() - 1);
340 if (c == '/' || c == '?') {
341 if (uri2->getChar(0) == '/') {
342 uri2->del(0);
343 }
344 } else {
345 if (uri2->getChar(0) != '/') {
346 uri->append('/');
347 }
348 }
349 uri->append(uri2);
350 delete uri2;
351 } else {
352 uri = uri2;
353 }
354 } else {
355 uri = uri2;
356 }
357 } else {
358 error(-1, "Illegal URI-type link");
359 }
360}
361
362LinkURI::~LinkURI() {
363 if (uri)
364 delete uri;
365}
366
367//------------------------------------------------------------------------
368// LinkNamed
369//------------------------------------------------------------------------
370
371LinkNamed::LinkNamed(Object *nameObj) {
372 name = NULL;
373 if (nameObj->isName()) {
374 name = new GString(nameObj->getName());
375 }
376}
377
378LinkNamed::~LinkNamed() {
379 if (name) {
380 delete name;
381 }
382}
383
384//------------------------------------------------------------------------
385// LinkUnknown
386//------------------------------------------------------------------------
387
388LinkUnknown::LinkUnknown(char *actionA) {
389 action = new GString(actionA);
390}
391
392LinkUnknown::~LinkUnknown() {
393 delete action;
394}
395
396//------------------------------------------------------------------------
397// Link
398//------------------------------------------------------------------------
399
400Link::Link(Dict *dict, GString *baseURI) {
401 Object obj1, obj2, obj3, obj4;
402 fouble t;
403
404 action = NULL;
405 ok = gFalse;
406
407 // get rectangle
408 if (!dict->lookup("Rect", &obj1)->isArray()) {
409 error(-1, "Annotation rectangle is wrong type");
410 goto err2;
411 }
412 if (!obj1.arrayGet(0, &obj2)->isNum()) {
413 error(-1, "Bad annotation rectangle");
414 goto err1;
415 }
416 x1 = obj2.getNum();
417 obj2.free();
418 if (!obj1.arrayGet(1, &obj2)->isNum()) {
419 error(-1, "Bad annotation rectangle");
420 goto err1;
421 }
422 y1 = obj2.getNum();
423 obj2.free();
424 if (!obj1.arrayGet(2, &obj2)->isNum()) {
425 error(-1, "Bad annotation rectangle");
426 goto err1;
427 }
428 x2 = obj2.getNum();
429 obj2.free();
430 if (!obj1.arrayGet(3, &obj2)->isNum()) {
431 error(-1, "Bad annotation rectangle");
432 goto err1;
433 }
434 y2 = obj2.getNum();
435 obj2.free();
436 obj1.free();
437 if (x1 > x2) {
438 t = x1;
439 x1 = x2;
440 x2 = t;
441 }
442 if (y1 > y2) {
443 t = y1;
444 y1 = y2;
445 y2 = t;
446 }
447
448 // get border
449 borderW = 0;
450 if (!dict->lookup("Border", &obj1)->isNull()) {
451 if (obj1.isArray() && obj1.arrayGetLength() >= 3) {
452 if (obj1.arrayGet(2, &obj2)->isNum()) {
453 borderW = obj2.getNum();
454 } else {
455 error(-1, "Bad annotation border");
456 }
457 obj2.free();
458 }
459 }
460 obj1.free();
461
462 // look for destination
463 if (!dict->lookup("Dest", &obj1)->isNull()) {
464 action = new LinkGoTo(&obj1);
465
466 // look for action
467 } else {
468 obj1.free();
469 if (dict->lookup("A", &obj1)->isDict()) {
470 obj1.dictLookup("S", &obj2);
471
472 // GoTo action
473 if (obj2.isName("GoTo")) {
474 obj1.dictLookup("D", &obj3);
475 action = new LinkGoTo(&obj3);
476 obj3.free();
477
478 // GoToR action
479 } else if (obj2.isName("GoToR")) {
480 obj1.dictLookup("F", &obj3);
481 obj1.dictLookup("D", &obj4);
482 action = new LinkGoToR(&obj3, &obj4);
483 obj3.free();
484 obj4.free();
485
486 // Launch action
487 } else if (obj2.isName("Launch")) {
488 action = new LinkLaunch(&obj1);
489
490 // URI action
491 } else if (obj2.isName("URI")) {
492 obj1.dictLookup("URI", &obj3);
493 action = new LinkURI(&obj3, baseURI);
494 obj3.free();
495
496 // Named action
497 } else if (obj2.isName("Named")) {
498 obj1.dictLookup("N", &obj3);
499 action = new LinkNamed(&obj3);
500 obj3.free();
501
502 // unknown action
503 } else if (obj2.isName()) {
504 action = new LinkUnknown(obj2.getName());
505
506 // action is missing or wrong type
507 } else {
508 error(-1, "Bad annotation action");
509 action = NULL;
510 }
511
512 obj2.free();
513
514 } else {
515 error(-1, "Missing annotation destination/action");
516 action = NULL;
517 }
518 }
519 obj1.free();
520
521 // check for bad action
522 if (action && action->isOk())
523 ok = gTrue;
524
525 return;
526
527 err1:
528 obj2.free();
529 err2:
530 obj1.free();
531}
532
533Link::~Link() {
534 if (action)
535 delete action;
536}
537
538//------------------------------------------------------------------------
539// Links
540//------------------------------------------------------------------------
541
542Links::Links(Object *annots, GString *baseURI) {
543 Link *link;
544 Object obj1, obj2;
545 int size;
546 int i;
547
548 links = NULL;
549 size = 0;
550 numLinks = 0;
551
552 if (annots->isArray()) {
553 for (i = 0; i < annots->arrayGetLength(); ++i) {
554 if (annots->arrayGet(i, &obj1)->isDict()) {
555 if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) {
556 link = new Link(obj1.getDict(), baseURI);
557 if (link->isOk()) {
558 if (numLinks >= size) {
559 size += 16;
560 links = (Link **)grealloc(links, size * sizeof(Link *));
561 }
562 links[numLinks++] = link;
563 } else {
564 delete link;
565 }
566 }
567 obj2.free();
568 }
569 obj1.free();
570 }
571 }
572}
573
574Links::~Links() {
575 int i;
576
577 for (i = 0; i < numLinks; ++i)
578 delete links[i];
579 gfree(links);
580}
581
582LinkAction *Links::find(fouble x, fouble y) {
583 int i;
584
585 for (i = 0; i < numLinks; ++i) {
586 if (links[i]->inRect(x, y)) {
587 return links[i]->getAction();
588 }
589 }
590 return NULL;
591}
592
593GBool Links::onLink(fouble x, fouble y) {
594 int i;
595
596 for (i = 0; i < numLinks; ++i) {
597 if (links[i]->inRect(x, y))
598 return gTrue;
599 }
600 return gFalse;
601}
602
603//------------------------------------------------------------------------
604
605// Extract a file name from a file specification (string or dictionary).
606static GString *getFileSpecName(Object *fileSpecObj) {
607 GString *name;
608 Object obj1;
609
610 name = NULL;
611
612 // string
613 if (fileSpecObj->isString()) {
614 name = fileSpecObj->getString()->copy();
615
616 // dictionary
617 } else if (fileSpecObj->isDict()) {
618 if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) {
619 obj1.free();
620 fileSpecObj->dictLookup("F", &obj1);
621 }
622 if (obj1.isString())
623 name = obj1.getString()->copy();
624 else
625 error(-1, "Illegal file spec in link");
626 obj1.free();
627
628 // error
629 } else {
630 error(-1, "Illegal file spec in link");
631 }
632
633 return name;
634}