diff options
author | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2019-09-29 10:00:12 +0000 |
---|---|---|
committer | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2019-09-29 10:00:12 +0000 |
commit | 268dff1b06a01bd6be5f1ae08216c0beff08336c (patch) | |
tree | c8f90365823a9711e674704157dff65babb709b9 /Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.cc | |
parent | ee6ffc65c0eb84ded1fc7d19eeb90a87541f896d (diff) |
xpdf 4.02
git-svn-id: svn://tug.org/texlive/trunk@52203 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.cc')
-rw-r--r-- | Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.cc | 367 |
1 files changed, 270 insertions, 97 deletions
diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.cc index 470807314a6..bec30a8dcfd 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.cc @@ -89,6 +89,59 @@ EmbeddedFile::~EmbeddedFile() { } //------------------------------------------------------------------------ +// PageLabelNode +//------------------------------------------------------------------------ + +class PageLabelNode { +public: + + PageLabelNode(int firstPageA, Dict *dict); + ~PageLabelNode(); + + int firstPage; // first page number covered by this node + int lastPage; // last page number covered by this node + TextString *prefix; // label prefix (may be empty) + int start; // value of the numeric portion of this + // label for the first page in the range + char style; // page label style +}; + +PageLabelNode::PageLabelNode(int firstPageA, Dict *dict) { + Object prefixObj, styleObj, startObj; + + // convert page index to page number + firstPage = firstPageA + 1; + + // lastPage will be filled in later + lastPage = -1; + + if (dict->lookup("P", &prefixObj)->isString()) { + prefix = new TextString(prefixObj.getString()); + } else { + prefix = new TextString(); + } + prefixObj.free(); + + style = '\0'; + if (dict->lookup("S", &styleObj)->isName()) { + if (strlen(styleObj.getName()) == 1) { + style = styleObj.getName()[0]; + } + } + styleObj.free(); + + start = 1; + if (dict->lookup("St", &startObj)->isInt()) { + start = startObj.getInt(); + } + startObj.free(); +} + +PageLabelNode::~PageLabelNode() { + delete prefix; +} + +//------------------------------------------------------------------------ // Catalog //------------------------------------------------------------------------ @@ -185,6 +238,15 @@ Catalog::Catalog(PDFDoc *docA) { // get the list of embedded files readEmbeddedFileList(catDict.getDict()); + // get the ViewerPreferences object + catDict.dictLookupNF("ViewerPreferences", &viewerPrefs); + + pageLabels = NULL; + if (catDict.dictLookup("PageLabels", &obj)->isDict()) { + readPageLabelTree(&obj); + } + obj.free(); + catDict.free(); return; @@ -229,6 +291,10 @@ Catalog::~Catalog() { if (embeddedFiles) { deleteGList(embeddedFiles, EmbeddedFile); } + if (pageLabels) { + deleteGList(pageLabels, PageLabelNode); + } + viewerPrefs.free(); } Page *Catalog::getPage(int i) { @@ -833,107 +899,45 @@ Object *Catalog::getEmbeddedFileStreamObj(int idx, Object *strObj) { return strObj; } -TextString *Catalog::getPageLabel(int pageNum) { - Object catDict, node, pageLabelObj, start, prefix, style; - GString *label, *s; - TextString *ts; - int firstPageIndex, pageRangeNum; - - if (!xref->getCatalog(&catDict)->isDict()) { - catDict.free(); - return NULL; - } +void Catalog::readPageLabelTree(Object *root) { + PageLabelNode *label0, *label1; + int i; - label = NULL; - catDict.dictLookup("PageLabels", &node); - if (findPageLabel(&node, pageNum - 1, &pageLabelObj, &firstPageIndex)) { - if (pageLabelObj.isDict()) { - if (pageLabelObj.dictLookup("P", &prefix)->isString()) { - label = prefix.getString()->copy(); - } else { - label = new GString(); - } - prefix.free(); + pageLabels = new GList(); + readPageLabelTree2(root); - pageRangeNum = pageNum - firstPageIndex; - if (pageLabelObj.dictLookup("St", &start)->isInt()) { - pageRangeNum += start.getInt() - 1; - } - start.free(); - - if (pageLabelObj.dictLookup("S", &style)->isName()) { - if (style.isName("D")) { - label->appendf("{0:d}", pageRangeNum); - } else if (style.isName("R")) { - s = makeRomanNumeral(pageRangeNum, gTrue); - label->append(s); - delete s; - } else if (style.isName("r")) { - s = makeRomanNumeral(pageRangeNum, gFalse); - label->append(s); - delete s; - } else if (style.isName("A")) { - s = makeLetterLabel(pageRangeNum, gTrue); - label->append(s); - delete s; - } else if (style.isName("a")) { - s = makeLetterLabel(pageRangeNum, gFalse); - label->append(s); - delete s; - } - } - style.free(); - } - pageLabelObj.free(); + if (pageLabels->getLength() == 0) { + deleteGList(pageLabels, PageLabelNode); + pageLabels = NULL; + return; } - node.free(); - catDict.free(); - ts = new TextString(label); - delete label; - return ts; + // set lastPage in each node + label0 = (PageLabelNode *)pageLabels->get(0); + for (i = 1; i < pageLabels->getLength(); ++i) { + label1 = (PageLabelNode *)pageLabels->get(i); + label0->lastPage = label1->firstPage - 1; + label0 = label1; + } + label0->lastPage = numPages; } -GBool Catalog::findPageLabel(Object *node, int pageIndex, - Object *pageLabelObj, int *firstPageIndex) { - Object limits, limit, nums, num, kids, kid; +void Catalog::readPageLabelTree2(Object *node) { + Object nums, num, labelObj, kids, kid; int i; if (!node->isDict()) { - return gFalse; - } - - // we only check the lower limit because page labels are organized - // into ranges based on their first page number -- the Nums and Kids - // arrays are searched backward for the same reason - if (node->dictLookup("Limits", &limits)->isArray() && - limits.arrayGetLength() == 2) { - if (limits.arrayGet(0, &limit)->isInt()) { - if (pageIndex < limit.getInt()) { - limit.free(); - limits.free(); - return gFalse; - } - } - limit.free(); + return; } - limits.free(); if (node->dictLookup("Nums", &nums)->isArray()) { - for (i = nums.arrayGetLength() / 2 - 1; i >= 0; --i) { - if (nums.arrayGet(2*i, &num)->isInt()) { - if (num.getInt() <= pageIndex) { - nums.arrayGet(2*i + 1, pageLabelObj); - *firstPageIndex = num.getInt(); - num.free(); - nums.free(); - return gTrue; + for (i = 0; i < nums.arrayGetLength() - 1; i += 2) { + if (nums.arrayGet(i, &num)->isInt()) { + if (nums.arrayGet(i+1, &labelObj)->isDict()) { + pageLabels->append(new PageLabelNode(num.getInt(), + labelObj.getDict())); } - } else { - error(errSyntaxError, -1, "Invalid key in page label number tree"); - num.free(); - nums.free(); - return gFalse; + labelObj.free(); } num.free(); } @@ -941,20 +945,61 @@ GBool Catalog::findPageLabel(Object *node, int pageIndex, nums.free(); if (node->dictLookup("Kids", &kids)->isArray()) { - for (i = kids.arrayGetLength() - 1; i >= 0; --i) { - if (kids.arrayGet(i, &kid)->isDict()) { - if (findPageLabel(&kid, pageIndex, pageLabelObj, firstPageIndex)) { - kid.free(); - kids.free(); - return gTrue; - } - } + for (i = 0; i < kids.arrayGetLength(); ++i) { + kids.arrayGet(i, &kid); + readPageLabelTree2(&kid); kid.free(); } } kids.free(); +} - return gFalse; +TextString *Catalog::getPageLabel(int pageNum) { + PageLabelNode *label; + TextString *ts; + int pageRangeNum; + GString *suffix; + + if (!pageLabels || !(label = findPageLabel(pageNum))) { + return NULL; + } + + ts = new TextString(label->prefix); + + pageRangeNum = label->start + (pageNum - label->firstPage); + + suffix = NULL; + if (label->style == 'D') { + suffix = GString::format("{0:d}", pageRangeNum); + } else if (label->style == 'R') { + suffix = makeRomanNumeral(pageRangeNum, gTrue); + } else if (label->style == 'r') { + suffix = makeRomanNumeral(pageRangeNum, gFalse); + } else if (label->style == 'A') { + suffix = makeLetterLabel(pageRangeNum, gTrue); + } else if (label->style == 'a') { + suffix = makeLetterLabel(pageRangeNum, gFalse); + } + if (suffix) { + ts->append(suffix); + delete suffix; + } + + return ts; +} + +PageLabelNode *Catalog::findPageLabel(int pageNum) { + PageLabelNode *label; + int i; + + //~ this could use a binary search + for (i = 0; i < pageLabels->getLength(); ++i) { + label = (PageLabelNode *)pageLabels->get(i); + if (pageNum >= label->firstPage && pageNum <= label->lastPage) { + return label; + } + } + return NULL; } GString *Catalog::makeRomanNumeral(int num, GBool uppercase) { @@ -1022,3 +1067,131 @@ GString *Catalog::makeLetterLabel(int num, GBool uppercase) { } return s; } + +int Catalog::getPageNumFromPageLabel(TextString *pageLabel) { + PageLabelNode *label; + int pageNum, prefixLength, i, n; + + if (!pageLabels) { + return -1; + } + for (i = 0; i < pageLabels->getLength(); ++i) { + label = (PageLabelNode *)pageLabels->get(i); + prefixLength = label->prefix->getLength(); + if (pageLabel->getLength() < prefixLength || + memcmp(pageLabel->getUnicode(), label->prefix->getUnicode(), + prefixLength * sizeof(Unicode))) { + continue; + } + if (label->style == '\0' && pageLabel->getLength() == prefixLength) { + return label->firstPage; + } + if (!convertPageLabelToInt(pageLabel, prefixLength, label->style, &n)) { + continue; + } + if (n < label->start) { + continue; + } + pageNum = label->firstPage + n - label->start; + if (pageNum <= label->lastPage) { + return pageNum; + } + } + return -1; +} + +// Attempts to convert pageLabel[prefixLength .. end] to an integer, +// following the specified page label style. If successful, sets *n +// and returns true; else returns false. +GBool Catalog::convertPageLabelToInt(TextString *pageLabel, int prefixLength, + char style, int *n) { + Unicode *u; + Unicode delta; + int len, i; + + len = pageLabel->getLength(); + if (len <= prefixLength) { + return gFalse; + } + u = pageLabel->getUnicode(); + if (style == 'D') { + *n = 0; + for (i = prefixLength; i < len; ++i) { + if (u[i] < (Unicode)'0' || u[i] > (Unicode)'9') { + return gFalse; + } + *n = *n * 10 + (u[i] - (Unicode)'0'); + } + return gTrue; + } else if (style == 'R' || style == 'r') { + delta = style - 'R'; + *n = 0; + i = prefixLength; + while (i < len && u[i] == (Unicode)'M' + delta) { + *n += 1000; + ++i; + } + if (i+1 < len && u[i] == (Unicode)'C' + delta && + u[i+1] == (Unicode)'M' + delta) { + *n += 900; + i += 2; + } else if (i < len && u[i] == (Unicode)'D' + delta) { + *n += 500; + ++i; + } else if (i+1 < len && u[i] == (Unicode)'C' + delta && + u[i+1] == (Unicode)'D' + delta) { + *n += 400; + i += 2; + } + while (i < len && u[i] == (Unicode)'C' + delta) { + *n += 100; + ++i; + } + if (i+1 < len && u[i] == (Unicode)'X' + delta && + u[i+1] == (Unicode)'C' + delta) { + *n += 90; + i += 2; + } else if (i < len && u[i] == (Unicode)'L' + delta) { + *n += 50; + ++i; + } else if (i+1 < len && u[i] == (Unicode)'X' + delta && + u[i+1] == (Unicode)'L' + delta) { + *n += 40; + i += 2; + } + while (i < len && u[i] == (Unicode)'X' + delta) { + *n += 10; + ++i; + } + if (i+1 < len && u[i] == (Unicode)'I' + delta && + u[i+1] == (Unicode)'X' + delta) { + *n += 9; + i += 2; + } else if (i < len && u[i] == (Unicode)'V' + delta) { + *n += 5; + ++i; + } else if (i+1 < len && u[i] == (Unicode)'I' + delta && + u[i+1] == (Unicode)'V' + delta) { + *n += 4; + i += 2; + } + while (i < len && u[i] == (Unicode)'I' + delta) { + *n += 1; + ++i; + } + return i == len; + } else if (style == 'A' || style == 'a') { + if (u[prefixLength] < (Unicode)style || + u[prefixLength] > (Unicode)style + 25) { + return gFalse; + } + for (i = prefixLength + 1; i < len; ++i) { + if (u[i] != u[prefixLength]) { + return gFalse; + } + } + *n = (len - prefixLength - 1) * 26 + (u[i] - (Unicode)style) + 1; + return gTrue; + } + return gFalse; +} |