125 lines
3.2 KiB
C++
125 lines
3.2 KiB
C++
// Copyright 2016 The PDFium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
|
|
|
|
#include "core/fpdfdoc/cpdf_pagelabel.h"
|
|
|
|
#include <utility>
|
|
|
|
#include "core/fpdfapi/parser/cpdf_dictionary.h"
|
|
#include "core/fpdfapi/parser/cpdf_document.h"
|
|
#include "core/fpdfapi/parser/fpdf_parser_decode.h"
|
|
#include "core/fpdfdoc/cpdf_numbertree.h"
|
|
|
|
namespace {
|
|
|
|
WideString MakeRoman(int num) {
|
|
const int kArabic[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
|
|
const WideStringView kRoman[] = {L"m", L"cm", L"d", L"cd", L"c",
|
|
L"xc", L"l", L"xl", L"x", L"ix",
|
|
L"v", L"iv", L"i"};
|
|
const int kMaxNum = 1000000;
|
|
|
|
num %= kMaxNum;
|
|
int i = 0;
|
|
WideString wsRomanNumber;
|
|
while (num > 0) {
|
|
while (num >= kArabic[i]) {
|
|
num = num - kArabic[i];
|
|
wsRomanNumber += kRoman[i];
|
|
}
|
|
i = i + 1;
|
|
}
|
|
return wsRomanNumber;
|
|
}
|
|
|
|
WideString MakeLetters(int num) {
|
|
if (num == 0)
|
|
return WideString();
|
|
|
|
WideString wsLetters;
|
|
const int nMaxCount = 1000;
|
|
const int nLetterCount = 26;
|
|
--num;
|
|
|
|
int count = num / nLetterCount + 1;
|
|
count %= nMaxCount;
|
|
wchar_t ch = L'a' + num % nLetterCount;
|
|
for (int i = 0; i < count; i++)
|
|
wsLetters += ch;
|
|
return wsLetters;
|
|
}
|
|
|
|
WideString GetLabelNumPortion(int num, const ByteString& bsStyle) {
|
|
if (bsStyle.IsEmpty())
|
|
return WideString();
|
|
if (bsStyle == "D")
|
|
return WideString::FormatInteger(num);
|
|
if (bsStyle == "R") {
|
|
WideString wsNumPortion = MakeRoman(num);
|
|
wsNumPortion.MakeUpper();
|
|
return wsNumPortion;
|
|
}
|
|
if (bsStyle == "r")
|
|
return MakeRoman(num);
|
|
if (bsStyle == "A") {
|
|
WideString wsNumPortion = MakeLetters(num);
|
|
wsNumPortion.MakeUpper();
|
|
return wsNumPortion;
|
|
}
|
|
if (bsStyle == "a")
|
|
return MakeLetters(num);
|
|
return WideString();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
CPDF_PageLabel::CPDF_PageLabel(CPDF_Document* pDocument)
|
|
: m_pDocument(pDocument) {}
|
|
|
|
CPDF_PageLabel::~CPDF_PageLabel() = default;
|
|
|
|
absl::optional<WideString> CPDF_PageLabel::GetLabel(int nPage) const {
|
|
if (!m_pDocument)
|
|
return absl::nullopt;
|
|
|
|
if (nPage < 0 || nPage >= m_pDocument->GetPageCount())
|
|
return absl::nullopt;
|
|
|
|
const CPDF_Dictionary* pPDFRoot = m_pDocument->GetRoot();
|
|
if (!pPDFRoot)
|
|
return absl::nullopt;
|
|
|
|
RetainPtr<const CPDF_Dictionary> pLabels = pPDFRoot->GetDictFor("PageLabels");
|
|
if (!pLabels)
|
|
return absl::nullopt;
|
|
|
|
CPDF_NumberTree numberTree(std::move(pLabels));
|
|
RetainPtr<const CPDF_Object> pValue;
|
|
int n = nPage;
|
|
while (n >= 0) {
|
|
pValue = numberTree.LookupValue(n);
|
|
if (pValue)
|
|
break;
|
|
n--;
|
|
}
|
|
|
|
if (pValue) {
|
|
pValue = pValue->GetDirect();
|
|
if (const CPDF_Dictionary* pLabel = pValue->AsDictionary()) {
|
|
WideString label;
|
|
if (pLabel->KeyExist("P"))
|
|
label += pLabel->GetUnicodeTextFor("P");
|
|
|
|
ByteString bsNumberingStyle = pLabel->GetByteStringFor("S", ByteString());
|
|
int nLabelNum = nPage - n + pLabel->GetIntegerFor("St", 1);
|
|
WideString wsNumPortion = GetLabelNumPortion(nLabelNum, bsNumberingStyle);
|
|
label += wsNumPortion;
|
|
return label;
|
|
}
|
|
}
|
|
return WideString::FormatInteger(nPage + 1);
|
|
}
|