Home | History | Annotate | Download | only in fpdfdoc
      1 // Copyright 2016 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "core/fpdfdoc/cpdf_pagelabel.h"
      8 
      9 #include "core/fpdfapi/parser/cpdf_dictionary.h"
     10 #include "core/fpdfapi/parser/cpdf_document.h"
     11 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
     12 #include "core/fpdfdoc/cpdf_numbertree.h"
     13 
     14 namespace {
     15 
     16 CFX_WideString MakeRoman(int num) {
     17   const int kArabic[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
     18   const CFX_WideString kRoman[] = {L"m",  L"cm", L"d",  L"cd", L"c",
     19                                    L"xc", L"l",  L"xl", L"x",  L"ix",
     20                                    L"v",  L"iv", L"i"};
     21   const int kMaxNum = 1000000;
     22 
     23   num %= kMaxNum;
     24   int i = 0;
     25   CFX_WideString wsRomanNumber;
     26   while (num > 0) {
     27     while (num >= kArabic[i]) {
     28       num = num - kArabic[i];
     29       wsRomanNumber += kRoman[i];
     30     }
     31     i = i + 1;
     32   }
     33   return wsRomanNumber;
     34 }
     35 
     36 CFX_WideString MakeLetters(int num) {
     37   if (num == 0)
     38     return CFX_WideString();
     39 
     40   CFX_WideString wsLetters;
     41   const int nMaxCount = 1000;
     42   const int nLetterCount = 26;
     43   --num;
     44 
     45   int count = num / nLetterCount + 1;
     46   count %= nMaxCount;
     47   FX_WCHAR ch = L'a' + num % nLetterCount;
     48   for (int i = 0; i < count; i++)
     49     wsLetters += ch;
     50   return wsLetters;
     51 }
     52 
     53 CFX_WideString GetLabelNumPortion(int num, const CFX_ByteString& bsStyle) {
     54   CFX_WideString wsNumPortion;
     55   if (bsStyle.IsEmpty())
     56     return wsNumPortion;
     57   if (bsStyle == "D") {
     58     wsNumPortion.Format(L"%d", num);
     59   } else if (bsStyle == "R") {
     60     wsNumPortion = MakeRoman(num);
     61     wsNumPortion.MakeUpper();
     62   } else if (bsStyle == "r") {
     63     wsNumPortion = MakeRoman(num);
     64   } else if (bsStyle == "A") {
     65     wsNumPortion = MakeLetters(num);
     66     wsNumPortion.MakeUpper();
     67   } else if (bsStyle == "a") {
     68     wsNumPortion = MakeLetters(num);
     69   }
     70   return wsNumPortion;
     71 }
     72 
     73 }  // namespace
     74 
     75 CPDF_PageLabel::CPDF_PageLabel(CPDF_Document* pDocument)
     76     : m_pDocument(pDocument) {}
     77 
     78 bool CPDF_PageLabel::GetLabel(int nPage, CFX_WideString* wsLabel) const {
     79   if (!m_pDocument)
     80     return false;
     81 
     82   if (nPage < 0 || nPage >= m_pDocument->GetPageCount())
     83     return false;
     84 
     85   CPDF_Dictionary* pPDFRoot = m_pDocument->GetRoot();
     86   if (!pPDFRoot)
     87     return false;
     88 
     89   CPDF_Dictionary* pLabels = pPDFRoot->GetDictFor("PageLabels");
     90   if (!pLabels)
     91     return false;
     92 
     93   CPDF_NumberTree numberTree(pLabels);
     94   CPDF_Object* pValue = nullptr;
     95   int n = nPage;
     96   while (n >= 0) {
     97     pValue = numberTree.LookupValue(n);
     98     if (pValue)
     99       break;
    100     n--;
    101   }
    102 
    103   if (pValue) {
    104     pValue = pValue->GetDirect();
    105     if (CPDF_Dictionary* pLabel = pValue->AsDictionary()) {
    106       if (pLabel->KeyExist("P"))
    107         *wsLabel += pLabel->GetUnicodeTextFor("P");
    108 
    109       CFX_ByteString bsNumberingStyle = pLabel->GetStringFor("S", "");
    110       int nLabelNum = nPage - n + pLabel->GetIntegerFor("St", 1);
    111       CFX_WideString wsNumPortion =
    112           GetLabelNumPortion(nLabelNum, bsNumberingStyle);
    113       *wsLabel += wsNumPortion;
    114       return true;
    115     }
    116   }
    117   wsLabel->Format(L"%d", nPage + 1);
    118   return true;
    119 }
    120 
    121 int32_t CPDF_PageLabel::GetPageByLabel(const CFX_ByteStringC& bsLabel) const {
    122   if (!m_pDocument)
    123     return -1;
    124 
    125   CPDF_Dictionary* pPDFRoot = m_pDocument->GetRoot();
    126   if (!pPDFRoot)
    127     return -1;
    128 
    129   int nPages = m_pDocument->GetPageCount();
    130   for (int i = 0; i < nPages; i++) {
    131     CFX_WideString str;
    132     if (!GetLabel(i, &str))
    133       continue;
    134     if (PDF_EncodeText(str).Compare(bsLabel))
    135       return i;
    136   }
    137 
    138   int nPage = FXSYS_atoi(CFX_ByteString(bsLabel).c_str());  // NUL terminate.
    139   return nPage > 0 && nPage <= nPages ? nPage : -1;
    140 }
    141 
    142 int32_t CPDF_PageLabel::GetPageByLabel(const CFX_WideStringC& wsLabel) const {
    143   return GetPageByLabel(PDF_EncodeText(wsLabel.c_str()).AsStringC());
    144 }
    145