/src/xpdf-4.05/xpdf/Link.cc
Line | Count | Source (jump to first uncovered line) |
1 | | //======================================================================== |
2 | | // |
3 | | // Link.cc |
4 | | // |
5 | | // Copyright 1996-2003 Glyph & Cog, LLC |
6 | | // |
7 | | //======================================================================== |
8 | | |
9 | | #include <aconf.h> |
10 | | |
11 | | #include <stddef.h> |
12 | | #include <string.h> |
13 | | #include "gmem.h" |
14 | | #include "gmempp.h" |
15 | | #include "GString.h" |
16 | | #include "Error.h" |
17 | | #include "Object.h" |
18 | | #include "Array.h" |
19 | | #include "Dict.h" |
20 | | #include "Link.h" |
21 | | |
22 | | //------------------------------------------------------------------------ |
23 | | // LinkAction |
24 | | //------------------------------------------------------------------------ |
25 | | |
26 | 0 | LinkAction *LinkAction::parseDest(Object *obj) { |
27 | 0 | LinkAction *action; |
28 | |
|
29 | 0 | action = new LinkGoTo(obj); |
30 | 0 | if (!action->isOk()) { |
31 | 0 | delete action; |
32 | 0 | return NULL; |
33 | 0 | } |
34 | 0 | return action; |
35 | 0 | } |
36 | | |
37 | 101 | LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) { |
38 | 101 | LinkAction *action; |
39 | 101 | Object obj2, obj3, obj4, obj5; |
40 | | |
41 | 101 | if (!obj->isDict()) { |
42 | 10 | error(errSyntaxWarning, -1, "Bad annotation action"); |
43 | 10 | return NULL; |
44 | 10 | } |
45 | | |
46 | 91 | obj->dictLookup("S", &obj2); |
47 | | |
48 | | // GoTo action |
49 | 91 | if (obj2.isName("GoTo")) { |
50 | 65 | obj->dictLookup("D", &obj3); |
51 | 65 | action = new LinkGoTo(&obj3); |
52 | 65 | obj3.free(); |
53 | | |
54 | | // GoToR action |
55 | 65 | } else if (obj2.isName("GoToR")) { |
56 | 0 | obj->dictLookup("F", &obj3); |
57 | 0 | obj->dictLookup("D", &obj4); |
58 | 0 | action = new LinkGoToR(&obj3, &obj4); |
59 | 0 | obj3.free(); |
60 | 0 | obj4.free(); |
61 | | |
62 | | // Launch action |
63 | 26 | } else if (obj2.isName("Launch")) { |
64 | 0 | action = new LinkLaunch(obj); |
65 | | |
66 | | // URI action |
67 | 26 | } else if (obj2.isName("URI")) { |
68 | 21 | obj->dictLookup("URI", &obj3); |
69 | 21 | action = new LinkURI(&obj3, baseURI); |
70 | 21 | obj3.free(); |
71 | | |
72 | | // Named action |
73 | 21 | } else if (obj2.isName("Named")) { |
74 | 0 | obj->dictLookup("N", &obj3); |
75 | 0 | action = new LinkNamed(&obj3); |
76 | 0 | obj3.free(); |
77 | | |
78 | | // Movie action |
79 | 5 | } else if (obj2.isName("Movie")) { |
80 | 0 | obj->dictLookupNF("Annot", &obj3); |
81 | 0 | obj->dictLookup("T", &obj4); |
82 | 0 | action = new LinkMovie(&obj3, &obj4); |
83 | 0 | obj3.free(); |
84 | 0 | obj4.free(); |
85 | | |
86 | | // JavaScript action |
87 | 5 | } else if (obj2.isName("JavaScript")) { |
88 | 0 | obj->dictLookup("JS", &obj3); |
89 | 0 | action = new LinkJavaScript(&obj3); |
90 | 0 | obj3.free(); |
91 | | |
92 | | // SubmitForm action |
93 | 5 | } else if (obj2.isName("SubmitForm")) { |
94 | 0 | obj->dictLookup("F", &obj3); |
95 | 0 | obj->dictLookup("Fields", &obj4); |
96 | 0 | obj->dictLookup("Flags", &obj5); |
97 | 0 | action = new LinkSubmitForm(&obj3, &obj4, &obj5); |
98 | 0 | obj3.free(); |
99 | 0 | obj4.free(); |
100 | 0 | obj5.free(); |
101 | | |
102 | | // Hide action |
103 | 5 | } else if (obj2.isName("Hide")) { |
104 | 0 | obj->dictLookupNF("T", &obj3); |
105 | 0 | obj->dictLookup("H", &obj4); |
106 | 0 | action = new LinkHide(&obj3, &obj4); |
107 | 0 | obj3.free(); |
108 | 0 | obj4.free(); |
109 | | |
110 | | // unknown action |
111 | 5 | } else if (obj2.isName()) { |
112 | 2 | action = new LinkUnknown(obj2.getName()); |
113 | | |
114 | | // action is missing or wrong type |
115 | 3 | } else { |
116 | 3 | error(errSyntaxWarning, -1, "Bad annotation action"); |
117 | 3 | action = NULL; |
118 | 3 | } |
119 | | |
120 | 91 | obj2.free(); |
121 | | |
122 | 91 | if (action && !action->isOk()) { |
123 | 39 | delete action; |
124 | 39 | return NULL; |
125 | 39 | } |
126 | 52 | return action; |
127 | 91 | } |
128 | | |
129 | 0 | GString *LinkAction::getFileSpecName(Object *fileSpecObj) { |
130 | 0 | GString *name; |
131 | 0 | Object obj1; |
132 | |
|
133 | 0 | name = NULL; |
134 | | |
135 | | // string |
136 | 0 | if (fileSpecObj->isString()) { |
137 | 0 | name = fileSpecObj->getString()->copy(); |
138 | | |
139 | | // dictionary |
140 | 0 | } else if (fileSpecObj->isDict()) { |
141 | | #ifdef _WIN32 |
142 | | if (!fileSpecObj->dictLookup("DOS", &obj1)->isString()) { |
143 | | #else |
144 | 0 | if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { |
145 | 0 | #endif |
146 | 0 | obj1.free(); |
147 | 0 | fileSpecObj->dictLookup("F", &obj1); |
148 | 0 | } |
149 | 0 | if (obj1.isString()) { |
150 | 0 | name = obj1.getString()->copy(); |
151 | 0 | } else { |
152 | 0 | error(errSyntaxWarning, -1, "Illegal file spec in link"); |
153 | 0 | } |
154 | 0 | obj1.free(); |
155 | | |
156 | | // error |
157 | 0 | } else { |
158 | 0 | error(errSyntaxWarning, -1, "Illegal file spec in link"); |
159 | 0 | } |
160 | | |
161 | | // system-dependent path manipulation |
162 | 0 | if (name) { |
163 | | #ifdef _WIN32 |
164 | | int i, j; |
165 | | |
166 | | // "//...." --> "\...." |
167 | | // "/x/...." --> "x:\...." |
168 | | // "/server/share/...." --> "\\server\share\...." |
169 | | // convert escaped slashes to slashes and unescaped slashes to backslashes |
170 | | i = 0; |
171 | | if (name->getChar(0) == '/') { |
172 | | if (name->getLength() >= 2 && name->getChar(1) == '/') { |
173 | | name->del(0); |
174 | | i = 0; |
175 | | } else if (name->getLength() >= 2 && |
176 | | ((name->getChar(1) >= 'a' && name->getChar(1) <= 'z') || |
177 | | (name->getChar(1) >= 'A' && name->getChar(1) <= 'Z')) && |
178 | | (name->getLength() == 2 || name->getChar(2) == '/')) { |
179 | | name->setChar(0, name->getChar(1)); |
180 | | name->setChar(1, ':'); |
181 | | i = 2; |
182 | | } else { |
183 | | for (j = 2; j < name->getLength(); ++j) { |
184 | | if (name->getChar(j-1) != '\\' && |
185 | | name->getChar(j) == '/') { |
186 | | break; |
187 | | } |
188 | | } |
189 | | if (j < name->getLength()) { |
190 | | name->setChar(0, '\\'); |
191 | | name->insert(0, '\\'); |
192 | | i = 2; |
193 | | } |
194 | | } |
195 | | } |
196 | | for (; i < name->getLength(); ++i) { |
197 | | if (name->getChar(i) == '/') { |
198 | | name->setChar(i, '\\'); |
199 | | } else if (name->getChar(i) == '\\' && |
200 | | i+1 < name->getLength() && |
201 | | name->getChar(i+1) == '/') { |
202 | | name->del(i); |
203 | | } |
204 | | } |
205 | | #else |
206 | | // no manipulation needed for Unix |
207 | 0 | #endif |
208 | 0 | } |
209 | |
|
210 | 0 | return name; |
211 | 0 | } |
212 | | |
213 | | //------------------------------------------------------------------------ |
214 | | // LinkDest |
215 | | //------------------------------------------------------------------------ |
216 | | |
217 | 61 | LinkDest::LinkDest(Array *a) { |
218 | 61 | Object obj1, obj2; |
219 | | |
220 | | // initialize fields |
221 | 61 | left = bottom = right = top = zoom = 0; |
222 | 61 | ok = gFalse; |
223 | | |
224 | | // get page |
225 | 61 | if (a->getLength() < 2) { |
226 | 0 | error(errSyntaxWarning, -1, "Annotation destination array is too short"); |
227 | 0 | return; |
228 | 0 | } |
229 | 61 | a->getNF(0, &obj1); |
230 | 61 | if (obj1.isInt()) { |
231 | 0 | pageNum = obj1.getInt() + 1; |
232 | 0 | pageIsRef = gFalse; |
233 | 61 | } else if (obj1.isRef()) { |
234 | 57 | pageRef.num = obj1.getRefNum(); |
235 | 57 | pageRef.gen = obj1.getRefGen(); |
236 | 57 | pageIsRef = gTrue; |
237 | 57 | } else { |
238 | 4 | error(errSyntaxWarning, -1, "Bad annotation destination"); |
239 | 4 | goto err2; |
240 | 4 | } |
241 | 57 | obj1.free(); |
242 | | |
243 | | // get destination type |
244 | 57 | a->get(1, &obj1); |
245 | | |
246 | | // XYZ link |
247 | 57 | if (obj1.isName("XYZ")) { |
248 | 29 | kind = destXYZ; |
249 | 29 | if (a->getLength() < 3) { |
250 | 0 | changeLeft = gFalse; |
251 | 29 | } else { |
252 | 29 | a->get(2, &obj2); |
253 | 29 | if (obj2.isNull()) { |
254 | 0 | changeLeft = gFalse; |
255 | 29 | } else if (obj2.isNum()) { |
256 | 29 | changeLeft = gTrue; |
257 | 29 | left = obj2.getNum(); |
258 | 29 | } else { |
259 | 0 | error(errSyntaxWarning, -1, "Bad annotation destination position"); |
260 | 0 | goto err1; |
261 | 0 | } |
262 | 29 | obj2.free(); |
263 | 29 | } |
264 | 29 | if (a->getLength() < 4) { |
265 | 0 | changeTop = gFalse; |
266 | 29 | } else { |
267 | 29 | a->get(3, &obj2); |
268 | 29 | if (obj2.isNull()) { |
269 | 0 | changeTop = gFalse; |
270 | 29 | } else if (obj2.isNum()) { |
271 | 29 | changeTop = gTrue; |
272 | 29 | top = obj2.getNum(); |
273 | 29 | } else { |
274 | 0 | error(errSyntaxWarning, -1, "Bad annotation destination position"); |
275 | 0 | goto err1; |
276 | 0 | } |
277 | 29 | obj2.free(); |
278 | 29 | } |
279 | 29 | if (a->getLength() < 5) { |
280 | 0 | changeZoom = gFalse; |
281 | 29 | } else { |
282 | 29 | a->get(4, &obj2); |
283 | 29 | if (obj2.isNull()) { |
284 | 3 | changeZoom = gFalse; |
285 | 26 | } else if (obj2.isNum()) { |
286 | 19 | changeZoom = gTrue; |
287 | 19 | zoom = obj2.getNum(); |
288 | 19 | } else { |
289 | 7 | error(errSyntaxWarning, -1, "Bad annotation destination position"); |
290 | 7 | goto err1; |
291 | 7 | } |
292 | 22 | obj2.free(); |
293 | 22 | } |
294 | | |
295 | | // Fit link |
296 | 29 | } else if (obj1.isName("Fit")) { |
297 | 15 | if (a->getLength() < 2) { |
298 | 0 | error(errSyntaxWarning, -1, "Annotation destination array is too short"); |
299 | 0 | goto err2; |
300 | 0 | } |
301 | 15 | kind = destFit; |
302 | | |
303 | | // FitH link |
304 | 15 | } else if (obj1.isName("FitH")) { |
305 | 2 | if (a->getLength() < 3) { |
306 | 0 | error(errSyntaxWarning, -1, "Annotation destination array is too short"); |
307 | 0 | goto err2; |
308 | 0 | } |
309 | 2 | kind = destFitH; |
310 | 2 | if (a->get(2, &obj2)->isNum()) { |
311 | 2 | top = obj2.getNum(); |
312 | 2 | changeTop = gTrue; |
313 | 2 | } else if (obj2.isNull()) { |
314 | 0 | changeTop = gFalse; |
315 | 0 | } else { |
316 | 0 | error(errSyntaxWarning, -1, "Bad annotation destination position"); |
317 | 0 | kind = destFit; |
318 | 0 | } |
319 | 2 | obj2.free(); |
320 | | |
321 | | // FitV link |
322 | 11 | } else if (obj1.isName("FitV")) { |
323 | 0 | if (a->getLength() < 3) { |
324 | 0 | error(errSyntaxWarning, -1, "Annotation destination array is too short"); |
325 | 0 | goto err2; |
326 | 0 | } |
327 | 0 | kind = destFitV; |
328 | 0 | if (a->get(2, &obj2)->isNum()) { |
329 | 0 | left = obj2.getNum(); |
330 | 0 | changeLeft = gTrue; |
331 | 0 | } else if (obj2.isNull()) { |
332 | 0 | changeLeft = gFalse; |
333 | 0 | } else { |
334 | 0 | error(errSyntaxWarning, -1, "Bad annotation destination position"); |
335 | 0 | kind = destFit; |
336 | 0 | } |
337 | 0 | obj2.free(); |
338 | | |
339 | | // FitR link |
340 | 11 | } else if (obj1.isName("FitR")) { |
341 | 0 | if (a->getLength() < 6) { |
342 | 0 | error(errSyntaxWarning, -1, "Annotation destination array is too short"); |
343 | 0 | goto err2; |
344 | 0 | } |
345 | 0 | kind = destFitR; |
346 | 0 | if (a->get(2, &obj2)->isNum()) { |
347 | 0 | left = obj2.getNum(); |
348 | 0 | } else { |
349 | 0 | error(errSyntaxWarning, -1, "Bad annotation destination position"); |
350 | 0 | kind = destFit; |
351 | 0 | } |
352 | 0 | obj2.free(); |
353 | 0 | if (!a->get(3, &obj2)->isNum()) { |
354 | 0 | error(errSyntaxWarning, -1, "Bad annotation destination position"); |
355 | 0 | kind = destFit; |
356 | 0 | } |
357 | 0 | bottom = obj2.getNum(); |
358 | 0 | obj2.free(); |
359 | 0 | if (!a->get(4, &obj2)->isNum()) { |
360 | 0 | error(errSyntaxWarning, -1, "Bad annotation destination position"); |
361 | 0 | kind = destFit; |
362 | 0 | } |
363 | 0 | right = obj2.getNum(); |
364 | 0 | obj2.free(); |
365 | 0 | if (!a->get(5, &obj2)->isNum()) { |
366 | 0 | error(errSyntaxWarning, -1, "Bad annotation destination position"); |
367 | 0 | kind = destFit; |
368 | 0 | } |
369 | 0 | top = obj2.getNum(); |
370 | 0 | obj2.free(); |
371 | | |
372 | | // FitB link |
373 | 11 | } else if (obj1.isName("FitB")) { |
374 | 0 | if (a->getLength() < 2) { |
375 | 0 | error(errSyntaxWarning, -1, "Annotation destination array is too short"); |
376 | 0 | goto err2; |
377 | 0 | } |
378 | 0 | kind = destFitB; |
379 | | |
380 | | // FitBH link |
381 | 11 | } else if (obj1.isName("FitBH")) { |
382 | 0 | if (a->getLength() < 3) { |
383 | 0 | error(errSyntaxWarning, -1, "Annotation destination array is too short"); |
384 | 0 | goto err2; |
385 | 0 | } |
386 | 0 | kind = destFitBH; |
387 | 0 | if (a->get(2, &obj2)->isNum()) { |
388 | 0 | top = obj2.getNum(); |
389 | 0 | changeTop = gTrue; |
390 | 0 | } else if (obj2.isNull()) { |
391 | 0 | changeTop = gFalse; |
392 | 0 | } else { |
393 | 0 | error(errSyntaxWarning, -1, "Bad annotation destination position"); |
394 | 0 | kind = destFit; |
395 | 0 | } |
396 | 0 | obj2.free(); |
397 | | |
398 | | // FitBV link |
399 | 11 | } else if (obj1.isName("FitBV")) { |
400 | 0 | if (a->getLength() < 3) { |
401 | 0 | error(errSyntaxWarning, -1, "Annotation destination array is too short"); |
402 | 0 | goto err2; |
403 | 0 | } |
404 | 0 | kind = destFitBV; |
405 | 0 | if (a->get(2, &obj2)->isNum()) { |
406 | 0 | left = obj2.getNum(); |
407 | 0 | changeLeft = gTrue; |
408 | 0 | } else if (obj2.isNull()) { |
409 | 0 | changeLeft = gFalse; |
410 | 0 | } else { |
411 | 0 | error(errSyntaxWarning, -1, "Bad annotation destination position"); |
412 | 0 | kind = destFit; |
413 | 0 | } |
414 | 0 | obj2.free(); |
415 | | |
416 | | // unknown link kind |
417 | 11 | } else { |
418 | 11 | error(errSyntaxWarning, -1, "Unknown annotation destination type"); |
419 | 11 | goto err2; |
420 | 11 | } |
421 | | |
422 | 39 | obj1.free(); |
423 | 39 | ok = gTrue; |
424 | 39 | return; |
425 | | |
426 | 7 | err1: |
427 | 7 | obj2.free(); |
428 | 22 | err2: |
429 | 22 | obj1.free(); |
430 | 22 | } |
431 | | |
432 | 0 | LinkDest::LinkDest(LinkDest *dest) { |
433 | 0 | kind = dest->kind; |
434 | 0 | pageIsRef = dest->pageIsRef; |
435 | 0 | if (pageIsRef) |
436 | 0 | pageRef = dest->pageRef; |
437 | 0 | else |
438 | 0 | pageNum = dest->pageNum; |
439 | 0 | left = dest->left; |
440 | 0 | bottom = dest->bottom; |
441 | 0 | right = dest->right; |
442 | 0 | top = dest->top; |
443 | 0 | zoom = dest->zoom; |
444 | 0 | changeLeft = dest->changeLeft; |
445 | 0 | changeTop = dest->changeTop; |
446 | 0 | changeZoom = dest->changeZoom; |
447 | 0 | ok = gTrue; |
448 | 0 | } |
449 | | |
450 | | //------------------------------------------------------------------------ |
451 | | // LinkGoTo |
452 | | //------------------------------------------------------------------------ |
453 | | |
454 | 65 | LinkGoTo::LinkGoTo(Object *destObj) { |
455 | 65 | dest = NULL; |
456 | 65 | namedDest = NULL; |
457 | | |
458 | | // named destination |
459 | 65 | if (destObj->isName()) { |
460 | 0 | namedDest = new GString(destObj->getName()); |
461 | 65 | } else if (destObj->isString()) { |
462 | 0 | namedDest = destObj->getString()->copy(); |
463 | | |
464 | | // destination dictionary |
465 | 65 | } else if (destObj->isArray()) { |
466 | 61 | dest = new LinkDest(destObj->getArray()); |
467 | 61 | if (!dest->isOk()) { |
468 | 22 | delete dest; |
469 | 22 | dest = NULL; |
470 | 22 | } |
471 | | |
472 | | // error |
473 | 61 | } else { |
474 | 4 | error(errSyntaxWarning, -1, "Illegal annotation destination"); |
475 | 4 | } |
476 | 65 | } |
477 | | |
478 | 65 | LinkGoTo::~LinkGoTo() { |
479 | 65 | if (dest) |
480 | 39 | delete dest; |
481 | 65 | if (namedDest) |
482 | 0 | delete namedDest; |
483 | 65 | } |
484 | | |
485 | | //------------------------------------------------------------------------ |
486 | | // LinkGoToR |
487 | | //------------------------------------------------------------------------ |
488 | | |
489 | 0 | LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) { |
490 | 0 | dest = NULL; |
491 | 0 | namedDest = NULL; |
492 | | |
493 | | // get file name |
494 | 0 | fileName = getFileSpecName(fileSpecObj); |
495 | | |
496 | | // named destination |
497 | 0 | if (destObj->isName()) { |
498 | 0 | namedDest = new GString(destObj->getName()); |
499 | 0 | } else if (destObj->isString()) { |
500 | 0 | namedDest = destObj->getString()->copy(); |
501 | | |
502 | | // destination dictionary |
503 | 0 | } else if (destObj->isArray()) { |
504 | 0 | dest = new LinkDest(destObj->getArray()); |
505 | 0 | if (!dest->isOk()) { |
506 | 0 | delete dest; |
507 | 0 | dest = NULL; |
508 | 0 | } |
509 | | |
510 | | // error |
511 | 0 | } else { |
512 | 0 | error(errSyntaxWarning, -1, "Illegal annotation destination"); |
513 | 0 | } |
514 | 0 | } |
515 | | |
516 | 0 | LinkGoToR::~LinkGoToR() { |
517 | 0 | if (fileName) |
518 | 0 | delete fileName; |
519 | 0 | if (dest) |
520 | 0 | delete dest; |
521 | 0 | if (namedDest) |
522 | 0 | delete namedDest; |
523 | 0 | } |
524 | | |
525 | | |
526 | | //------------------------------------------------------------------------ |
527 | | // LinkLaunch |
528 | | //------------------------------------------------------------------------ |
529 | | |
530 | 0 | LinkLaunch::LinkLaunch(Object *actionObj) { |
531 | 0 | Object obj1, obj2; |
532 | |
|
533 | 0 | fileName = NULL; |
534 | 0 | params = NULL; |
535 | |
|
536 | 0 | if (actionObj->isDict()) { |
537 | 0 | if (!actionObj->dictLookup("F", &obj1)->isNull()) { |
538 | 0 | fileName = getFileSpecName(&obj1); |
539 | 0 | } else { |
540 | 0 | obj1.free(); |
541 | | #ifdef _WIN32 |
542 | | if (actionObj->dictLookup("Win", &obj1)->isDict()) { |
543 | | obj1.dictLookup("F", &obj2); |
544 | | fileName = getFileSpecName(&obj2); |
545 | | obj2.free(); |
546 | | if (obj1.dictLookup("P", &obj2)->isString()) { |
547 | | params = obj2.getString()->copy(); |
548 | | } |
549 | | obj2.free(); |
550 | | } else { |
551 | | error(errSyntaxWarning, -1, "Bad launch-type link action"); |
552 | | } |
553 | | #else |
554 | | //~ This hasn't been defined by Adobe yet, so assume it looks |
555 | | //~ just like the Win dictionary until they say otherwise. |
556 | 0 | if (actionObj->dictLookup("Unix", &obj1)->isDict()) { |
557 | 0 | obj1.dictLookup("F", &obj2); |
558 | 0 | fileName = getFileSpecName(&obj2); |
559 | 0 | obj2.free(); |
560 | 0 | if (obj1.dictLookup("P", &obj2)->isString()) { |
561 | 0 | params = obj2.getString()->copy(); |
562 | 0 | } |
563 | 0 | obj2.free(); |
564 | 0 | } else { |
565 | 0 | error(errSyntaxWarning, -1, "Bad launch-type link action"); |
566 | 0 | } |
567 | 0 | #endif |
568 | 0 | } |
569 | 0 | obj1.free(); |
570 | 0 | } |
571 | 0 | } |
572 | | |
573 | 0 | LinkLaunch::~LinkLaunch() { |
574 | 0 | if (fileName) |
575 | 0 | delete fileName; |
576 | 0 | if (params) |
577 | 0 | delete params; |
578 | 0 | } |
579 | | |
580 | | //------------------------------------------------------------------------ |
581 | | // LinkURI |
582 | | //------------------------------------------------------------------------ |
583 | | |
584 | 21 | LinkURI::LinkURI(Object *uriObj, GString *baseURI) { |
585 | 21 | GString *uri2; |
586 | 21 | int n; |
587 | 21 | char c; |
588 | | |
589 | 21 | uri = NULL; |
590 | 21 | if (uriObj->isString()) { |
591 | 8 | uri2 = uriObj->getString(); |
592 | 8 | n = (int)strcspn(uri2->getCString(), "/:"); |
593 | 8 | if (n < uri2->getLength() && uri2->getChar(n) == ':') { |
594 | | // "http:..." etc. |
595 | 3 | uri = uri2->copy(); |
596 | 5 | } else if (!uri2->cmpN("www.", 4)) { |
597 | | // "www.[...]" without the leading "http://" |
598 | 0 | uri = new GString("http://"); |
599 | 0 | uri->append(uri2); |
600 | 5 | } else { |
601 | | // relative URI |
602 | 5 | if (baseURI) { |
603 | 0 | uri = baseURI->copy(); |
604 | 0 | c = uri->getChar(uri->getLength() - 1); |
605 | 0 | if (c != '/' && c != '?') { |
606 | 0 | uri->append('/'); |
607 | 0 | } |
608 | 0 | if (uri2->getChar(0) == '/') { |
609 | 0 | uri->append(uri2->getCString() + 1, uri2->getLength() - 1); |
610 | 0 | } else { |
611 | 0 | uri->append(uri2); |
612 | 0 | } |
613 | 5 | } else { |
614 | 5 | uri = uri2->copy(); |
615 | 5 | } |
616 | 5 | } |
617 | 13 | } else { |
618 | 13 | error(errSyntaxWarning, -1, "Illegal URI-type link"); |
619 | 13 | } |
620 | 21 | } |
621 | | |
622 | 21 | LinkURI::~LinkURI() { |
623 | 21 | if (uri) |
624 | 8 | delete uri; |
625 | 21 | } |
626 | | |
627 | | //------------------------------------------------------------------------ |
628 | | // LinkNamed |
629 | | //------------------------------------------------------------------------ |
630 | | |
631 | 0 | LinkNamed::LinkNamed(Object *nameObj) { |
632 | 0 | name = NULL; |
633 | 0 | if (nameObj->isName()) { |
634 | 0 | name = new GString(nameObj->getName()); |
635 | 0 | } |
636 | 0 | } |
637 | | |
638 | 0 | LinkNamed::~LinkNamed() { |
639 | 0 | if (name) { |
640 | 0 | delete name; |
641 | 0 | } |
642 | 0 | } |
643 | | |
644 | | //------------------------------------------------------------------------ |
645 | | // LinkMovie |
646 | | //------------------------------------------------------------------------ |
647 | | |
648 | 0 | LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) { |
649 | 0 | annotRef.num = -1; |
650 | 0 | title = NULL; |
651 | 0 | if (annotObj->isRef()) { |
652 | 0 | annotRef = annotObj->getRef(); |
653 | 0 | } else if (titleObj->isString()) { |
654 | 0 | title = titleObj->getString()->copy(); |
655 | 0 | } else { |
656 | 0 | error(errSyntaxError, -1, |
657 | 0 | "Movie action is missing both the Annot and T keys"); |
658 | 0 | } |
659 | 0 | } |
660 | | |
661 | 0 | LinkMovie::~LinkMovie() { |
662 | 0 | if (title) { |
663 | 0 | delete title; |
664 | 0 | } |
665 | 0 | } |
666 | | |
667 | | //------------------------------------------------------------------------ |
668 | | // LinkJavaScript |
669 | | //------------------------------------------------------------------------ |
670 | | |
671 | 0 | LinkJavaScript::LinkJavaScript(Object *jsObj) { |
672 | 0 | char buf[4096]; |
673 | 0 | int n; |
674 | |
|
675 | 0 | if (jsObj->isString()) { |
676 | 0 | js = jsObj->getString()->copy(); |
677 | 0 | } else if (jsObj->isStream()) { |
678 | 0 | js = new GString(); |
679 | 0 | jsObj->streamReset(); |
680 | 0 | while ((n = jsObj->getStream()->getBlock(buf, sizeof(buf))) > 0) { |
681 | 0 | js->append(buf, n); |
682 | 0 | } |
683 | 0 | jsObj->streamClose(); |
684 | 0 | } else { |
685 | 0 | error(errSyntaxError, -1, "JavaScript action JS key is wrong type"); |
686 | 0 | js = NULL; |
687 | 0 | } |
688 | 0 | } |
689 | | |
690 | 0 | LinkJavaScript::~LinkJavaScript() { |
691 | 0 | if (js) { |
692 | 0 | delete js; |
693 | 0 | } |
694 | 0 | } |
695 | | |
696 | | //------------------------------------------------------------------------ |
697 | | // LinkSubmitForm |
698 | | //------------------------------------------------------------------------ |
699 | | |
700 | | LinkSubmitForm::LinkSubmitForm(Object *urlObj, Object *fieldsObj, |
701 | 0 | Object *flagsObj) { |
702 | 0 | if (urlObj->isString()) { |
703 | 0 | url = urlObj->getString()->copy(); |
704 | 0 | } else { |
705 | 0 | error(errSyntaxError, -1, "SubmitForm action URL is wrong type"); |
706 | 0 | url = NULL; |
707 | 0 | } |
708 | |
|
709 | 0 | if (fieldsObj->isArray()) { |
710 | 0 | fieldsObj->copy(&fields); |
711 | 0 | } else { |
712 | 0 | if (!fieldsObj->isNull()) { |
713 | 0 | error(errSyntaxError, -1, "SubmitForm action Fields value is wrong type"); |
714 | 0 | } |
715 | 0 | fields.initNull(); |
716 | 0 | } |
717 | |
|
718 | 0 | if (flagsObj->isInt()) { |
719 | 0 | flags = flagsObj->getInt(); |
720 | 0 | } else { |
721 | 0 | if (!flagsObj->isNull()) { |
722 | 0 | error(errSyntaxError, -1, "SubmitForm action Flags value is wrong type"); |
723 | 0 | } |
724 | 0 | flags = 0; |
725 | 0 | } |
726 | 0 | } |
727 | | |
728 | 0 | LinkSubmitForm::~LinkSubmitForm() { |
729 | 0 | if (url) { |
730 | 0 | delete url; |
731 | 0 | } |
732 | 0 | fields.free(); |
733 | 0 | } |
734 | | |
735 | | //------------------------------------------------------------------------ |
736 | | // LinkHide |
737 | | //------------------------------------------------------------------------ |
738 | | |
739 | 0 | LinkHide::LinkHide(Object *fieldsObj, Object *hideFlagObj) { |
740 | 0 | if (fieldsObj->isRef() || fieldsObj->isString() || fieldsObj->isArray()) { |
741 | 0 | fieldsObj->copy(&fields); |
742 | 0 | } else { |
743 | 0 | error(errSyntaxError, -1, "Hide action T value is wrong type"); |
744 | 0 | fields.initNull(); |
745 | 0 | } |
746 | |
|
747 | 0 | if (hideFlagObj->isBool()) { |
748 | 0 | hideFlag = hideFlagObj->getBool(); |
749 | 0 | } else { |
750 | 0 | error(errSyntaxError, -1, "Hide action H value is wrong type"); |
751 | 0 | hideFlag = gFalse; |
752 | 0 | } |
753 | 0 | } |
754 | | |
755 | 0 | LinkHide::~LinkHide() { |
756 | 0 | fields.free(); |
757 | 0 | } |
758 | | |
759 | | //------------------------------------------------------------------------ |
760 | | // LinkUnknown |
761 | | //------------------------------------------------------------------------ |
762 | | |
763 | 2 | LinkUnknown::LinkUnknown(char *actionA) { |
764 | 2 | action = new GString(actionA); |
765 | 2 | } |
766 | | |
767 | 2 | LinkUnknown::~LinkUnknown() { |
768 | 2 | delete action; |
769 | 2 | } |
770 | | |
771 | | //------------------------------------------------------------------------ |
772 | | // Link |
773 | | //------------------------------------------------------------------------ |
774 | | |
775 | 0 | Link::Link(Dict *dict, GString *baseURI) { |
776 | 0 | Object obj1, obj2; |
777 | 0 | double t; |
778 | |
|
779 | 0 | action = NULL; |
780 | 0 | ok = gFalse; |
781 | | |
782 | | // get rectangle |
783 | 0 | if (!dict->lookup("Rect", &obj1)->isArray()) { |
784 | 0 | error(errSyntaxError, -1, "Annotation rectangle is wrong type"); |
785 | 0 | goto err2; |
786 | 0 | } |
787 | 0 | if (!obj1.arrayGet(0, &obj2)->isNum()) { |
788 | 0 | error(errSyntaxError, -1, "Bad annotation rectangle"); |
789 | 0 | goto err1; |
790 | 0 | } |
791 | 0 | x1 = obj2.getNum(); |
792 | 0 | obj2.free(); |
793 | 0 | if (!obj1.arrayGet(1, &obj2)->isNum()) { |
794 | 0 | error(errSyntaxError, -1, "Bad annotation rectangle"); |
795 | 0 | goto err1; |
796 | 0 | } |
797 | 0 | y1 = obj2.getNum(); |
798 | 0 | obj2.free(); |
799 | 0 | if (!obj1.arrayGet(2, &obj2)->isNum()) { |
800 | 0 | error(errSyntaxError, -1, "Bad annotation rectangle"); |
801 | 0 | goto err1; |
802 | 0 | } |
803 | 0 | x2 = obj2.getNum(); |
804 | 0 | obj2.free(); |
805 | 0 | if (!obj1.arrayGet(3, &obj2)->isNum()) { |
806 | 0 | error(errSyntaxError, -1, "Bad annotation rectangle"); |
807 | 0 | goto err1; |
808 | 0 | } |
809 | 0 | y2 = obj2.getNum(); |
810 | 0 | obj2.free(); |
811 | 0 | obj1.free(); |
812 | 0 | if (x1 > x2) { |
813 | 0 | t = x1; |
814 | 0 | x1 = x2; |
815 | 0 | x2 = t; |
816 | 0 | } |
817 | 0 | if (y1 > y2) { |
818 | 0 | t = y1; |
819 | 0 | y1 = y2; |
820 | 0 | y2 = t; |
821 | 0 | } |
822 | | |
823 | | // look for destination |
824 | 0 | if (!dict->lookup("Dest", &obj1)->isNull()) { |
825 | 0 | action = LinkAction::parseDest(&obj1); |
826 | | |
827 | | // look for action |
828 | 0 | } else { |
829 | 0 | obj1.free(); |
830 | 0 | if (dict->lookup("A", &obj1)->isDict()) { |
831 | 0 | action = LinkAction::parseAction(&obj1, baseURI); |
832 | 0 | } |
833 | 0 | } |
834 | 0 | obj1.free(); |
835 | | |
836 | | // check for bad action |
837 | 0 | if (action) { |
838 | 0 | ok = gTrue; |
839 | 0 | } |
840 | |
|
841 | 0 | return; |
842 | | |
843 | 0 | err1: |
844 | 0 | obj2.free(); |
845 | 0 | err2: |
846 | 0 | obj1.free(); |
847 | 0 | } |
848 | | |
849 | 0 | Link::~Link() { |
850 | 0 | if (action) { |
851 | 0 | delete action; |
852 | 0 | } |
853 | 0 | } |
854 | | |
855 | | //------------------------------------------------------------------------ |
856 | | // Links |
857 | | //------------------------------------------------------------------------ |
858 | | |
859 | 0 | Links::Links(Object *annots, GString *baseURI) { |
860 | 0 | Link *link; |
861 | 0 | Object obj1, obj2, obj3; |
862 | 0 | int size; |
863 | 0 | int i; |
864 | |
|
865 | 0 | links = NULL; |
866 | 0 | size = 0; |
867 | 0 | numLinks = 0; |
868 | |
|
869 | 0 | if (annots->isArray()) { |
870 | 0 | for (i = 0; i < annots->arrayGetLength(); ++i) { |
871 | 0 | if (annots->arrayGet(i, &obj1)->isDict()) { |
872 | 0 | obj1.dictLookup("Subtype", &obj2); |
873 | 0 | obj1.dictLookup("FT", &obj3); |
874 | 0 | if (obj2.isName("Link") || |
875 | 0 | (obj2.isName("Widget") && (obj3.isName("Btn") || obj3.isNull()))) { |
876 | 0 | link = new Link(obj1.getDict(), baseURI); |
877 | 0 | if (link->isOk()) { |
878 | 0 | if (numLinks >= size) { |
879 | 0 | size += 16; |
880 | 0 | links = (Link **)greallocn(links, size, sizeof(Link *)); |
881 | 0 | } |
882 | 0 | links[numLinks++] = link; |
883 | 0 | } else { |
884 | 0 | delete link; |
885 | 0 | } |
886 | 0 | } |
887 | 0 | obj3.free(); |
888 | 0 | obj2.free(); |
889 | 0 | } |
890 | 0 | obj1.free(); |
891 | 0 | } |
892 | 0 | } |
893 | 0 | } |
894 | | |
895 | 0 | Links::~Links() { |
896 | 0 | int i; |
897 | |
|
898 | 0 | for (i = 0; i < numLinks; ++i) |
899 | 0 | delete links[i]; |
900 | 0 | gfree(links); |
901 | 0 | } |
902 | | |
903 | 0 | LinkAction *Links::find(double x, double y) { |
904 | 0 | int i; |
905 | |
|
906 | 0 | for (i = numLinks - 1; i >= 0; --i) { |
907 | 0 | if (links[i]->inRect(x, y)) { |
908 | 0 | return links[i]->getAction(); |
909 | 0 | } |
910 | 0 | } |
911 | 0 | return NULL; |
912 | 0 | } |
913 | | |
914 | 0 | GBool Links::onLink(double x, double y) { |
915 | 0 | int i; |
916 | |
|
917 | 0 | for (i = 0; i < numLinks; ++i) { |
918 | 0 | if (links[i]->inRect(x, y)) |
919 | 0 | return gTrue; |
920 | 0 | } |
921 | 0 | return gFalse; |
922 | 0 | } |