00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <aconf.h>
00010
00011 #ifdef USE_GCC_PRAGMAS
00012 #pragma implementation
00013 #endif
00014
00015 #include <stddef.h>
00016 #include <string.h>
00017 #include "gmem.h"
00018 #include "GString.h"
00019 #include "Error.h"
00020 #include "Object.h"
00021 #include "Array.h"
00022 #include "Dict.h"
00023 #include "Link.h"
00024
00025
00026
00027
00028
00029 LinkAction *LinkAction::parseDest(Object *obj) {
00030 LinkAction *action;
00031
00032 action = new LinkGoTo(obj);
00033 if (!action->isOk()) {
00034 delete action;
00035 return NULL;
00036 }
00037 return action;
00038 }
00039
00040 LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) {
00041 LinkAction *action;
00042 Object obj2, obj3, obj4;
00043
00044 if (!obj->isDict()) {
00045 error(-1, "Bad annotation action");
00046 return NULL;
00047 }
00048
00049 obj->dictLookup("S", &obj2);
00050
00051
00052 if (obj2.isName("GoTo")) {
00053 obj->dictLookup("D", &obj3);
00054 action = new LinkGoTo(&obj3);
00055 obj3.free();
00056
00057
00058 } else if (obj2.isName("GoToR")) {
00059 obj->dictLookup("F", &obj3);
00060 obj->dictLookup("D", &obj4);
00061 action = new LinkGoToR(&obj3, &obj4);
00062 obj3.free();
00063 obj4.free();
00064
00065
00066 } else if (obj2.isName("Launch")) {
00067 action = new LinkLaunch(obj);
00068
00069
00070 } else if (obj2.isName("URI")) {
00071 obj->dictLookup("URI", &obj3);
00072 action = new LinkURI(&obj3, baseURI);
00073 obj3.free();
00074
00075
00076 } else if (obj2.isName("Named")) {
00077 obj->dictLookup("N", &obj3);
00078 action = new LinkNamed(&obj3);
00079 obj3.free();
00080
00081
00082 } else if (obj2.isName("Movie")) {
00083 obj->dictLookupNF("Annot", &obj3);
00084 obj->dictLookup("T", &obj4);
00085 action = new LinkMovie(&obj3, &obj4);
00086 obj3.free();
00087 obj4.free();
00088
00089
00090 } else if (obj2.isName()) {
00091 action = new LinkUnknown(obj2.getName());
00092
00093
00094 } else {
00095 error(-1, "Bad annotation action");
00096 action = NULL;
00097 }
00098
00099 obj2.free();
00100
00101 if (action && !action->isOk()) {
00102 delete action;
00103 return NULL;
00104 }
00105 return action;
00106 }
00107
00108 GString *LinkAction::getFileSpecName(Object *fileSpecObj) {
00109 GString *name;
00110 Object obj1;
00111
00112 name = NULL;
00113
00114
00115 if (fileSpecObj->isString()) {
00116 name = fileSpecObj->getString()->copy();
00117
00118
00119 } else if (fileSpecObj->isDict()) {
00120 if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) {
00121 obj1.free();
00122 fileSpecObj->dictLookup("F", &obj1);
00123 }
00124 if (obj1.isString())
00125 name = obj1.getString()->copy();
00126 else
00127 error(-1, "Illegal file spec in link");
00128 obj1.free();
00129
00130
00131 } else {
00132 error(-1, "Illegal file spec in link");
00133 }
00134
00135 return name;
00136 }
00137
00138
00139
00140
00141
00142 LinkDest::LinkDest(Array *a) {
00143 Object obj1, obj2;
00144
00145
00146 left = bottom = right = top = zoom = 0;
00147 ok = gFalse;
00148
00149
00150 if (a->getLength() < 2) {
00151 error(-1, "Annotation destination array has wrong length");
00152 return;
00153 }
00154 a->getNF(0, &obj1);
00155 if (obj1.isInt()) {
00156 pageNum = obj1.getInt() + 1;
00157 pageIsRef = gFalse;
00158 } else if (obj1.isRef()) {
00159 pageRef.num = obj1.getRefNum();
00160 pageRef.gen = obj1.getRefGen();
00161 pageIsRef = gTrue;
00162 } else {
00163 error(-1, "Bad annotation destination");
00164 goto err2;
00165 }
00166 obj1.free();
00167
00168
00169 a->get(1, &obj1);
00170
00171
00172 if (obj1.isName("XYZ")) {
00173 if (a->getLength() != 5) {
00174 error(-1, "Annotation destination array has wrong length");
00175 goto err2;
00176 }
00177 kind = destXYZ;
00178 a->get(2, &obj2);
00179 if (obj2.isNull()) {
00180 changeLeft = gFalse;
00181 } else if (obj2.isNum()) {
00182 changeLeft = gTrue;
00183 left = obj2.getNum();
00184 } else {
00185 error(-1, "Bad annotation destination position");
00186 goto err1;
00187 }
00188 obj2.free();
00189 a->get(3, &obj2);
00190 if (obj2.isNull()) {
00191 changeTop = gFalse;
00192 } else if (obj2.isNum()) {
00193 changeTop = gTrue;
00194 top = obj2.getNum();
00195 } else {
00196 error(-1, "Bad annotation destination position");
00197 goto err1;
00198 }
00199 obj2.free();
00200 a->get(4, &obj2);
00201 if (obj2.isNull()) {
00202 changeZoom = gFalse;
00203 } else if (obj2.isNum()) {
00204 changeZoom = gTrue;
00205 zoom = obj2.getNum();
00206 } else {
00207 error(-1, "Bad annotation destination position");
00208 goto err1;
00209 }
00210 obj2.free();
00211
00212
00213 } else if (obj1.isName("Fit")) {
00214 if (a->getLength() != 2) {
00215 error(-1, "Annotation destination array has wrong length");
00216 goto err2;
00217 }
00218 kind = destFit;
00219
00220
00221 } else if (obj1.isName("FitH")) {
00222 if (a->getLength() != 3) {
00223 error(-1, "Annotation destination array has wrong length");
00224 goto err2;
00225 }
00226 kind = destFitH;
00227 if (!a->get(2, &obj2)->isNum()) {
00228 error(-1, "Bad annotation destination position");
00229 goto err1;
00230 }
00231 top = obj2.getNum();
00232 obj2.free();
00233
00234
00235 } else if (obj1.isName("FitV")) {
00236 if (a->getLength() != 3) {
00237 error(-1, "Annotation destination array has wrong length");
00238 goto err2;
00239 }
00240 kind = destFitV;
00241 if (!a->get(2, &obj2)->isNum()) {
00242 error(-1, "Bad annotation destination position");
00243 goto err1;
00244 }
00245 left = obj2.getNum();
00246 obj2.free();
00247
00248
00249 } else if (obj1.isName("FitR")) {
00250 if (a->getLength() != 6) {
00251 error(-1, "Annotation destination array has wrong length");
00252 goto err2;
00253 }
00254 kind = destFitR;
00255 if (!a->get(2, &obj2)->isNum()) {
00256 error(-1, "Bad annotation destination position");
00257 goto err1;
00258 }
00259 left = obj2.getNum();
00260 obj2.free();
00261 if (!a->get(3, &obj2)->isNum()) {
00262 error(-1, "Bad annotation destination position");
00263 goto err1;
00264 }
00265 bottom = obj2.getNum();
00266 obj2.free();
00267 if (!a->get(4, &obj2)->isNum()) {
00268 error(-1, "Bad annotation destination position");
00269 goto err1;
00270 }
00271 right = obj2.getNum();
00272 obj2.free();
00273 if (!a->get(5, &obj2)->isNum()) {
00274 error(-1, "Bad annotation destination position");
00275 goto err1;
00276 }
00277 top = obj2.getNum();
00278 obj2.free();
00279
00280
00281 } else if (obj1.isName("FitB")) {
00282 if (a->getLength() != 2) {
00283 error(-1, "Annotation destination array has wrong length");
00284 goto err2;
00285 }
00286 kind = destFitB;
00287
00288
00289 } else if (obj1.isName("FitBH")) {
00290 if (a->getLength() != 3) {
00291 error(-1, "Annotation destination array has wrong length");
00292 goto err2;
00293 }
00294 kind = destFitBH;
00295 if (!a->get(2, &obj2)->isNum()) {
00296 error(-1, "Bad annotation destination position");
00297 goto err1;
00298 }
00299 top = obj2.getNum();
00300 obj2.free();
00301
00302
00303 } else if (obj1.isName("FitBV")) {
00304 if (a->getLength() != 3) {
00305 error(-1, "Annotation destination array has wrong length");
00306 goto err2;
00307 }
00308 kind = destFitBV;
00309 if (!a->get(2, &obj2)->isNum()) {
00310 error(-1, "Bad annotation destination position");
00311 goto err1;
00312 }
00313 left = obj2.getNum();
00314 obj2.free();
00315
00316
00317 } else {
00318 error(-1, "Unknown annotation destination type");
00319 goto err2;
00320 }
00321
00322 obj1.free();
00323 ok = gTrue;
00324 return;
00325
00326 err1:
00327 obj2.free();
00328 err2:
00329 obj1.free();
00330 }
00331
00332 LinkDest::LinkDest(LinkDest *dest) {
00333 kind = dest->kind;
00334 pageIsRef = dest->pageIsRef;
00335 if (pageIsRef)
00336 pageRef = dest->pageRef;
00337 else
00338 pageNum = dest->pageNum;
00339 left = dest->left;
00340 bottom = dest->bottom;
00341 right = dest->right;
00342 top = dest->top;
00343 zoom = dest->zoom;
00344 changeLeft = dest->changeLeft;
00345 changeTop = dest->changeTop;
00346 changeZoom = dest->changeZoom;
00347 ok = gTrue;
00348 }
00349
00350
00351
00352
00353
00354 LinkGoTo::LinkGoTo(Object *destObj) {
00355 dest = NULL;
00356 namedDest = NULL;
00357
00358
00359 if (destObj->isName()) {
00360 namedDest = new GString(destObj->getName());
00361 } else if (destObj->isString()) {
00362 namedDest = destObj->getString()->copy();
00363
00364
00365 } else if (destObj->isArray()) {
00366 dest = new LinkDest(destObj->getArray());
00367 if (!dest->isOk()) {
00368 delete dest;
00369 dest = NULL;
00370 }
00371
00372
00373 } else {
00374 error(-1, "Illegal annotation destination");
00375 }
00376 }
00377
00378 LinkGoTo::~LinkGoTo() {
00379 if (dest)
00380 delete dest;
00381 if (namedDest)
00382 delete namedDest;
00383 }
00384
00385
00386
00387
00388
00389 LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) {
00390 dest = NULL;
00391 namedDest = NULL;
00392
00393
00394 fileName = getFileSpecName(fileSpecObj);
00395
00396
00397 if (destObj->isName()) {
00398 namedDest = new GString(destObj->getName());
00399 } else if (destObj->isString()) {
00400 namedDest = destObj->getString()->copy();
00401
00402
00403 } else if (destObj->isArray()) {
00404 dest = new LinkDest(destObj->getArray());
00405 if (!dest->isOk()) {
00406 delete dest;
00407 dest = NULL;
00408 }
00409
00410
00411 } else {
00412 error(-1, "Illegal annotation destination");
00413 }
00414 }
00415
00416 LinkGoToR::~LinkGoToR() {
00417 if (fileName)
00418 delete fileName;
00419 if (dest)
00420 delete dest;
00421 if (namedDest)
00422 delete namedDest;
00423 }
00424
00425
00426
00427
00428
00429
00430 LinkLaunch::LinkLaunch(Object *actionObj) {
00431 Object obj1, obj2;
00432
00433 fileName = NULL;
00434 params = NULL;
00435
00436 if (actionObj->isDict()) {
00437 if (!actionObj->dictLookup("F", &obj1)->isNull()) {
00438 fileName = getFileSpecName(&obj1);
00439 } else {
00440 obj1.free();
00441 #ifdef WIN32
00442 if (actionObj->dictLookup("Win", &obj1)->isDict()) {
00443 obj1.dictLookup("F", &obj2);
00444 fileName = getFileSpecName(&obj2);
00445 obj2.free();
00446 if (obj1.dictLookup("P", &obj2)->isString()) {
00447 params = obj2.getString()->copy();
00448 }
00449 obj2.free();
00450 } else {
00451 error(-1, "Bad launch-type link action");
00452 }
00453 #else
00454
00455
00456 if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
00457 obj1.dictLookup("F", &obj2);
00458 fileName = getFileSpecName(&obj2);
00459 obj2.free();
00460 if (obj1.dictLookup("P", &obj2)->isString()) {
00461 params = obj2.getString()->copy();
00462 }
00463 obj2.free();
00464 } else {
00465 error(-1, "Bad launch-type link action");
00466 }
00467 #endif
00468 }
00469 obj1.free();
00470 }
00471 }
00472
00473 LinkLaunch::~LinkLaunch() {
00474 if (fileName)
00475 delete fileName;
00476 if (params)
00477 delete params;
00478 }
00479
00480
00481
00482
00483
00484 LinkURI::LinkURI(Object *uriObj, GString *baseURI) {
00485 GString *uri2;
00486 int n;
00487 char c;
00488
00489 uri = NULL;
00490 if (uriObj->isString()) {
00491 uri2 = uriObj->getString()->copy();
00492 if (baseURI) {
00493 n = strcspn(uri2->getCString(), "/:");
00494 if (n == uri2->getLength() || uri2->getChar(n) == '/') {
00495 uri = baseURI->copy();
00496 c = uri->getChar(uri->getLength() - 1);
00497 if (c == '/' || c == '?') {
00498 if (uri2->getChar(0) == '/') {
00499 uri2->del(0);
00500 }
00501 } else {
00502 if (uri2->getChar(0) != '/') {
00503 uri->append('/');
00504 }
00505 }
00506 uri->append(uri2);
00507 delete uri2;
00508 } else {
00509 uri = uri2;
00510 }
00511 } else {
00512 uri = uri2;
00513 }
00514 } else {
00515 error(-1, "Illegal URI-type link");
00516 }
00517 }
00518
00519 LinkURI::~LinkURI() {
00520 if (uri)
00521 delete uri;
00522 }
00523
00524
00525
00526
00527
00528 LinkNamed::LinkNamed(Object *nameObj) {
00529 name = NULL;
00530 if (nameObj->isName()) {
00531 name = new GString(nameObj->getName());
00532 }
00533 }
00534
00535 LinkNamed::~LinkNamed() {
00536 if (name) {
00537 delete name;
00538 }
00539 }
00540
00541
00542
00543
00544
00545 LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) {
00546 annotRef.num = -1;
00547 title = NULL;
00548 if (annotObj->isRef()) {
00549 annotRef = annotObj->getRef();
00550 } else if (titleObj->isString()) {
00551 title = titleObj->getString()->copy();
00552 } else {
00553 error(-1, "Movie action is missing both the Annot and T keys");
00554 }
00555 }
00556
00557 LinkMovie::~LinkMovie() {
00558 if (title) {
00559 delete title;
00560 }
00561 }
00562
00563
00564
00565
00566
00567 LinkUnknown::LinkUnknown(char *actionA) {
00568 action = new GString(actionA);
00569 }
00570
00571 LinkUnknown::~LinkUnknown() {
00572 delete action;
00573 }
00574
00575
00576
00577
00578
00579 Link::Link(Dict *dict, GString *baseURI) {
00580 Object obj1, obj2;
00581 double t;
00582
00583 action = NULL;
00584 ok = gFalse;
00585
00586
00587 if (!dict->lookup("Rect", &obj1)->isArray()) {
00588 error(-1, "Annotation rectangle is wrong type");
00589 goto err2;
00590 }
00591 if (!obj1.arrayGet(0, &obj2)->isNum()) {
00592 error(-1, "Bad annotation rectangle");
00593 goto err1;
00594 }
00595 x1 = obj2.getNum();
00596 obj2.free();
00597 if (!obj1.arrayGet(1, &obj2)->isNum()) {
00598 error(-1, "Bad annotation rectangle");
00599 goto err1;
00600 }
00601 y1 = obj2.getNum();
00602 obj2.free();
00603 if (!obj1.arrayGet(2, &obj2)->isNum()) {
00604 error(-1, "Bad annotation rectangle");
00605 goto err1;
00606 }
00607 x2 = obj2.getNum();
00608 obj2.free();
00609 if (!obj1.arrayGet(3, &obj2)->isNum()) {
00610 error(-1, "Bad annotation rectangle");
00611 goto err1;
00612 }
00613 y2 = obj2.getNum();
00614 obj2.free();
00615 obj1.free();
00616 if (x1 > x2) {
00617 t = x1;
00618 x1 = x2;
00619 x2 = t;
00620 }
00621 if (y1 > y2) {
00622 t = y1;
00623 y1 = y2;
00624 y2 = t;
00625 }
00626
00627
00628 borderW = 1;
00629 if (!dict->lookup("Border", &obj1)->isNull()) {
00630 if (obj1.isArray() && obj1.arrayGetLength() >= 3) {
00631 if (obj1.arrayGet(2, &obj2)->isNum()) {
00632 borderW = obj2.getNum();
00633 } else {
00634 error(-1, "Bad annotation border");
00635 }
00636 obj2.free();
00637 }
00638 }
00639 obj1.free();
00640
00641
00642 if (!dict->lookup("Dest", &obj1)->isNull()) {
00643 action = LinkAction::parseDest(&obj1);
00644
00645
00646 } else {
00647 obj1.free();
00648 if (dict->lookup("A", &obj1)->isDict()) {
00649 action = LinkAction::parseAction(&obj1, baseURI);
00650 }
00651 }
00652 obj1.free();
00653
00654
00655 if (action) {
00656 ok = gTrue;
00657 }
00658
00659 return;
00660
00661 err1:
00662 obj2.free();
00663 err2:
00664 obj1.free();
00665 }
00666
00667 Link::~Link() {
00668 if (action)
00669 delete action;
00670 }
00671
00672
00673
00674
00675
00676 Links::Links(Object *annots, GString *baseURI) {
00677 Link *link;
00678 Object obj1, obj2;
00679 int size;
00680 int i;
00681
00682 links = NULL;
00683 size = 0;
00684 numLinks = 0;
00685
00686 if (annots->isArray()) {
00687 for (i = 0; i < annots->arrayGetLength(); ++i) {
00688 if (annots->arrayGet(i, &obj1)->isDict()) {
00689 if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) {
00690 link = new Link(obj1.getDict(), baseURI);
00691 if (link->isOk()) {
00692 if (numLinks >= size) {
00693 size += 16;
00694 links = (Link **)grealloc(links, size * sizeof(Link *));
00695 }
00696 links[numLinks++] = link;
00697 } else {
00698 delete link;
00699 }
00700 }
00701 obj2.free();
00702 }
00703 obj1.free();
00704 }
00705 }
00706 }
00707
00708 Links::~Links() {
00709 int i;
00710
00711 for (i = 0; i < numLinks; ++i)
00712 delete links[i];
00713 gfree(links);
00714 }
00715
00716 LinkAction *Links::find(double x, double y) {
00717 int i;
00718
00719 for (i = numLinks - 1; i >= 0; --i) {
00720 if (links[i]->inRect(x, y)) {
00721 return links[i]->getAction();
00722 }
00723 }
00724 return NULL;
00725 }
00726
00727 GBool Links::onLink(double x, double y) {
00728 int i;
00729
00730 for (i = 0; i < numLinks; ++i) {
00731 if (links[i]->inRect(x, y))
00732 return gTrue;
00733 }
00734 return gFalse;
00735 }