1 //========================================================================
5 // Copyright 1996-2002 Glyph & Cog, LLC
7 //========================================================================
10 #pragma implementation
24 //------------------------------------------------------------------------
26 static GString
*getFileSpecName(Object
*fileSpecObj
);
28 //------------------------------------------------------------------------
30 //------------------------------------------------------------------------
32 LinkDest::LinkDest(Array
*a
) {
36 left
= bottom
= right
= top
= zoom
= 0;
42 pageNum
= obj1
.getInt() + 1;
44 } else if (obj1
.isRef()) {
45 pageRef
.num
= obj1
.getRefNum();
46 pageRef
.gen
= obj1
.getRefGen();
49 error(-1, "Bad annotation destination");
54 // get destination type
58 if (obj1
.isName("XYZ")) {
63 } else if (obj2
.isNum()) {
67 error(-1, "Bad annotation destination position");
74 } else if (obj2
.isNum()) {
78 error(-1, "Bad annotation destination position");
85 } else if (obj2
.isNum()) {
89 error(-1, "Bad annotation destination position");
95 } else if (obj1
.isName("Fit")) {
99 } else if (obj1
.isName("FitH")) {
101 if (!a
->get(2, &obj2
)->isNum()) {
102 error(-1, "Bad annotation destination position");
109 } else if (obj1
.isName("FitV")) {
111 if (!a
->get(2, &obj2
)->isNum()) {
112 error(-1, "Bad annotation destination position");
115 left
= obj2
.getNum();
119 } else if (obj1
.isName("FitR")) {
121 if (!a
->get(2, &obj2
)->isNum()) {
122 error(-1, "Bad annotation destination position");
125 left
= obj2
.getNum();
127 if (!a
->get(3, &obj2
)->isNum()) {
128 error(-1, "Bad annotation destination position");
131 bottom
= obj2
.getNum();
133 if (!a
->get(4, &obj2
)->isNum()) {
134 error(-1, "Bad annotation destination position");
137 right
= obj2
.getNum();
139 if (!a
->get(5, &obj2
)->isNum()) {
140 error(-1, "Bad annotation destination position");
147 } else if (obj1
.isName("FitB")) {
151 } else if (obj1
.isName("FitBH")) {
153 if (!a
->get(2, &obj2
)->isNum()) {
154 error(-1, "Bad annotation destination position");
161 } else if (obj1
.isName("FitBV")) {
163 if (!a
->get(2, &obj2
)->isNum()) {
164 error(-1, "Bad annotation destination position");
167 left
= obj2
.getNum();
172 error(-1, "Unknown annotation destination type");
186 LinkDest::LinkDest(LinkDest
*dest
) {
188 pageIsRef
= dest
->pageIsRef
;
190 pageRef
= dest
->pageRef
;
192 pageNum
= dest
->pageNum
;
194 bottom
= dest
->bottom
;
198 changeLeft
= dest
->changeLeft
;
199 changeTop
= dest
->changeTop
;
200 changeZoom
= dest
->changeZoom
;
204 //------------------------------------------------------------------------
206 //------------------------------------------------------------------------
208 LinkGoTo::LinkGoTo(Object
*destObj
) {
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());
228 error(-1, "Illegal annotation destination");
232 LinkGoTo::~LinkGoTo() {
239 //------------------------------------------------------------------------
241 //------------------------------------------------------------------------
243 LinkGoToR::LinkGoToR(Object
*fileSpecObj
, Object
*destObj
) {
248 fileName
= getFileSpecName(fileSpecObj
);
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());
266 error(-1, "Illegal annotation destination");
270 LinkGoToR::~LinkGoToR() {
280 //------------------------------------------------------------------------
282 //------------------------------------------------------------------------
284 LinkLaunch::LinkLaunch(Object
*actionObj
) {
290 if (actionObj
->isDict()) {
291 if (!actionObj
->dictLookup("F", &obj1
)->isNull()) {
292 fileName
= getFileSpecName(&obj1
);
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
);
301 if (obj1
.dictLookup("P", &obj2
)->isString())
302 params
= obj2
.getString()->copy();
305 error(-1, "Bad launch-type link action");
312 LinkLaunch::~LinkLaunch() {
319 //------------------------------------------------------------------------
321 //------------------------------------------------------------------------
323 LinkURI::LinkURI(Object
*uriObj
, GString
*baseURI
) {
329 if (uriObj
->isString()) {
330 uri2
= uriObj
->getString()->copy();
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) == '/') {
341 if (uri2
->getChar(0) != '/') {
354 error(-1, "Illegal URI-type link");
358 LinkURI::~LinkURI() {
363 //------------------------------------------------------------------------
365 //------------------------------------------------------------------------
367 LinkNamed::LinkNamed(Object
*nameObj
) {
369 if (nameObj
->isName()) {
370 name
= new GString(nameObj
->getName());
374 LinkNamed::~LinkNamed() {
380 //------------------------------------------------------------------------
382 //------------------------------------------------------------------------
384 LinkUnknown::LinkUnknown(char *actionA
) {
385 action
= new GString(actionA
);
388 LinkUnknown::~LinkUnknown() {
392 //------------------------------------------------------------------------
394 //------------------------------------------------------------------------
396 Link::Link(Dict
*dict
, GString
*baseURI
) {
397 Object obj1
, obj2
, obj3
, obj4
;
404 if (!dict
->lookup("Rect", &obj1
)->isArray()) {
405 error(-1, "Annotation rectangle is wrong type");
408 if (!obj1
.arrayGet(0, &obj2
)->isNum()) {
409 error(-1, "Bad annotation rectangle");
414 if (!obj1
.arrayGet(1, &obj2
)->isNum()) {
415 error(-1, "Bad annotation rectangle");
420 if (!obj1
.arrayGet(2, &obj2
)->isNum()) {
421 error(-1, "Bad annotation rectangle");
426 if (!obj1
.arrayGet(3, &obj2
)->isNum()) {
427 error(-1, "Bad annotation rectangle");
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();
451 error(-1, "Bad annotation border");
458 // look for destination
459 if (!dict
->lookup("Dest", &obj1
)->isNull()) {
460 action
= new LinkGoTo(&obj1
);
465 if (dict
->lookup("A", &obj1
)->isDict()) {
466 obj1
.dictLookup("S", &obj2
);
469 if (obj2
.isName("GoTo")) {
470 obj1
.dictLookup("D", &obj3
);
471 action
= new LinkGoTo(&obj3
);
475 } else if (obj2
.isName("GoToR")) {
476 obj1
.dictLookup("F", &obj3
);
477 obj1
.dictLookup("D", &obj4
);
478 action
= new LinkGoToR(&obj3
, &obj4
);
483 } else if (obj2
.isName("Launch")) {
484 action
= new LinkLaunch(&obj1
);
487 } else if (obj2
.isName("URI")) {
488 obj1
.dictLookup("URI", &obj3
);
489 action
= new LinkURI(&obj3
, baseURI
);
493 } else if (obj2
.isName("Named")) {
494 obj1
.dictLookup("N", &obj3
);
495 action
= new LinkNamed(&obj3
);
499 } else if (obj2
.isName()) {
500 action
= new LinkUnknown(obj2
.getName());
502 // action is missing or wrong type
504 error(-1, "Bad annotation action");
511 error(-1, "Missing annotation destination/action");
517 // check for bad action
518 if (action
&& action
->isOk())
534 //------------------------------------------------------------------------
536 //------------------------------------------------------------------------
538 Links::Links(Object
*annots
, GString
*baseURI
) {
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
);
554 if (numLinks
>= size
) {
556 links
= (Link
**)grealloc(links
, size
* sizeof(Link
*));
558 links
[numLinks
++] = link
;
573 for (i
= 0; i
< numLinks
; ++i
)
578 LinkAction
*Links::find(double x
, double y
) {
581 for (i
= numLinks
- 1; i
>= 0; --i
) {
582 if (links
[i
]->inRect(x
, y
)) {
583 return links
[i
]->getAction();
589 GBool
Links::onLink(double x
, double y
) {
592 for (i
= 0; i
< numLinks
; ++i
) {
593 if (links
[i
]->inRect(x
, y
))
599 //------------------------------------------------------------------------
601 // Extract a file name from a file specification (string or dictionary).
602 static GString
*getFileSpecName(Object
*fileSpecObj
) {
609 if (fileSpecObj
->isString()) {
610 name
= fileSpecObj
->getString()->copy();
613 } else if (fileSpecObj
->isDict()) {
614 if (!fileSpecObj
->dictLookup("Unix", &obj1
)->isString()) {
616 fileSpecObj
->dictLookup("F", &obj1
);
619 name
= obj1
.getString()->copy();
621 error(-1, "Illegal file spec in link");
626 error(-1, "Illegal file spec in link");