Coverage Report

Created: 2025-08-08 06:36

/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
}