summaryrefslogtreecommitdiff
path: root/core/fpdfdoc/doc_basic.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/fpdfdoc/doc_basic.cpp')
-rw-r--r--core/fpdfdoc/doc_basic.cpp510
1 files changed, 510 insertions, 0 deletions
diff --git a/core/fpdfdoc/doc_basic.cpp b/core/fpdfdoc/doc_basic.cpp
new file mode 100644
index 0000000000..b3a6511734
--- /dev/null
+++ b/core/fpdfdoc/doc_basic.cpp
@@ -0,0 +1,510 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// 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/doc_utils.h"
+#include "core/include/fpdfapi/cpdf_array.h"
+#include "core/include/fpdfapi/cpdf_document.h"
+#include "core/include/fpdfdoc/fpdf_doc.h"
+
+const int nMaxRecursion = 32;
+int CPDF_Dest::GetPageIndex(CPDF_Document* pDoc) {
+ CPDF_Array* pArray = ToArray(m_pObj);
+ if (!pArray)
+ return 0;
+
+ CPDF_Object* pPage = pArray->GetElementValue(0);
+ if (!pPage)
+ return 0;
+ if (pPage->IsNumber())
+ return pPage->GetInteger();
+ if (!pPage->IsDictionary())
+ return 0;
+ return pDoc->GetPageIndex(pPage->GetObjNum());
+}
+FX_DWORD CPDF_Dest::GetPageObjNum() {
+ CPDF_Array* pArray = ToArray(m_pObj);
+ if (!pArray)
+ return 0;
+
+ CPDF_Object* pPage = pArray->GetElementValue(0);
+ if (!pPage)
+ return 0;
+ if (pPage->IsNumber())
+ return pPage->GetInteger();
+ if (pPage->IsDictionary())
+ return pPage->GetObjNum();
+ return 0;
+}
+const FX_CHAR* g_sZoomModes[] = {"XYZ", "Fit", "FitH", "FitV", "FitR",
+ "FitB", "FitBH", "FitBV", ""};
+int CPDF_Dest::GetZoomMode() {
+ CPDF_Array* pArray = ToArray(m_pObj);
+ if (!pArray)
+ return 0;
+
+ CFX_ByteString mode;
+ CPDF_Object* pObj = pArray->GetElementValue(1);
+ mode = pObj ? pObj->GetString() : CFX_ByteString();
+ int i = 0;
+ while (g_sZoomModes[i][0] != '\0') {
+ if (mode == g_sZoomModes[i]) {
+ return i + 1;
+ }
+ i++;
+ }
+ return 0;
+}
+FX_FLOAT CPDF_Dest::GetParam(int index) {
+ CPDF_Array* pArray = ToArray(m_pObj);
+ return pArray ? pArray->GetNumberAt(2 + index) : 0;
+}
+CFX_ByteString CPDF_Dest::GetRemoteName() {
+ return m_pObj ? m_pObj->GetString() : CFX_ByteString();
+}
+CPDF_NameTree::CPDF_NameTree(CPDF_Document* pDoc,
+ const CFX_ByteStringC& category) {
+ if (pDoc->GetRoot() && pDoc->GetRoot()->GetDictBy("Names"))
+ m_pRoot = pDoc->GetRoot()->GetDictBy("Names")->GetDictBy(category);
+ else
+ m_pRoot = NULL;
+}
+static CPDF_Object* SearchNameNode(CPDF_Dictionary* pNode,
+ const CFX_ByteString& csName,
+ int& nIndex,
+ CPDF_Array** ppFind,
+ int nLevel = 0) {
+ if (nLevel > nMaxRecursion) {
+ return NULL;
+ }
+ CPDF_Array* pLimits = pNode->GetArrayBy("Limits");
+ if (pLimits) {
+ CFX_ByteString csLeft = pLimits->GetStringAt(0);
+ CFX_ByteString csRight = pLimits->GetStringAt(1);
+ if (csLeft.Compare(csRight) > 0) {
+ CFX_ByteString csTmp = csRight;
+ csRight = csLeft;
+ csLeft = csTmp;
+ }
+ if (csName.Compare(csLeft) < 0 || csName.Compare(csRight) > 0) {
+ return NULL;
+ }
+ }
+ CPDF_Array* pNames = pNode->GetArrayBy("Names");
+ if (pNames) {
+ FX_DWORD dwCount = pNames->GetCount() / 2;
+ for (FX_DWORD i = 0; i < dwCount; i++) {
+ CFX_ByteString csValue = pNames->GetStringAt(i * 2);
+ int32_t iCompare = csValue.Compare(csName);
+ if (iCompare <= 0) {
+ if (ppFind) {
+ *ppFind = pNames;
+ }
+ if (iCompare < 0) {
+ continue;
+ }
+ } else {
+ break;
+ }
+ nIndex += i;
+ return pNames->GetElementValue(i * 2 + 1);
+ }
+ nIndex += dwCount;
+ return NULL;
+ }
+ CPDF_Array* pKids = pNode->GetArrayBy("Kids");
+ if (!pKids) {
+ return NULL;
+ }
+ for (FX_DWORD i = 0; i < pKids->GetCount(); i++) {
+ CPDF_Dictionary* pKid = pKids->GetDictAt(i);
+ if (!pKid) {
+ continue;
+ }
+ CPDF_Object* pFound =
+ SearchNameNode(pKid, csName, nIndex, ppFind, nLevel + 1);
+ if (pFound) {
+ return pFound;
+ }
+ }
+ return NULL;
+}
+static CPDF_Object* SearchNameNode(CPDF_Dictionary* pNode,
+ int nIndex,
+ int& nCurIndex,
+ CFX_ByteString& csName,
+ CPDF_Array** ppFind,
+ int nLevel = 0) {
+ if (nLevel > nMaxRecursion) {
+ return NULL;
+ }
+ CPDF_Array* pNames = pNode->GetArrayBy("Names");
+ if (pNames) {
+ int nCount = pNames->GetCount() / 2;
+ if (nIndex >= nCurIndex + nCount) {
+ nCurIndex += nCount;
+ return NULL;
+ }
+ if (ppFind) {
+ *ppFind = pNames;
+ }
+ csName = pNames->GetStringAt((nIndex - nCurIndex) * 2);
+ return pNames->GetElementValue((nIndex - nCurIndex) * 2 + 1);
+ }
+ CPDF_Array* pKids = pNode->GetArrayBy("Kids");
+ if (!pKids) {
+ return NULL;
+ }
+ for (FX_DWORD i = 0; i < pKids->GetCount(); i++) {
+ CPDF_Dictionary* pKid = pKids->GetDictAt(i);
+ if (!pKid) {
+ continue;
+ }
+ CPDF_Object* pFound =
+ SearchNameNode(pKid, nIndex, nCurIndex, csName, ppFind, nLevel + 1);
+ if (pFound) {
+ return pFound;
+ }
+ }
+ return NULL;
+}
+static int CountNames(CPDF_Dictionary* pNode, int nLevel = 0) {
+ if (nLevel > nMaxRecursion) {
+ return 0;
+ }
+ CPDF_Array* pNames = pNode->GetArrayBy("Names");
+ if (pNames) {
+ return pNames->GetCount() / 2;
+ }
+ CPDF_Array* pKids = pNode->GetArrayBy("Kids");
+ if (!pKids) {
+ return 0;
+ }
+ int nCount = 0;
+ for (FX_DWORD i = 0; i < pKids->GetCount(); i++) {
+ CPDF_Dictionary* pKid = pKids->GetDictAt(i);
+ if (!pKid) {
+ continue;
+ }
+ nCount += CountNames(pKid, nLevel + 1);
+ }
+ return nCount;
+}
+int CPDF_NameTree::GetCount() const {
+ if (!m_pRoot) {
+ return 0;
+ }
+ return ::CountNames(m_pRoot);
+}
+int CPDF_NameTree::GetIndex(const CFX_ByteString& csName) const {
+ if (!m_pRoot) {
+ return -1;
+ }
+ int nIndex = 0;
+ if (!SearchNameNode(m_pRoot, csName, nIndex, NULL)) {
+ return -1;
+ }
+ return nIndex;
+}
+CPDF_Object* CPDF_NameTree::LookupValue(int nIndex,
+ CFX_ByteString& csName) const {
+ if (!m_pRoot) {
+ return NULL;
+ }
+ int nCurIndex = 0;
+ return SearchNameNode(m_pRoot, nIndex, nCurIndex, csName, NULL);
+}
+CPDF_Object* CPDF_NameTree::LookupValue(const CFX_ByteString& csName) const {
+ if (!m_pRoot) {
+ return NULL;
+ }
+ int nIndex = 0;
+ return SearchNameNode(m_pRoot, csName, nIndex, NULL);
+}
+CPDF_Array* CPDF_NameTree::LookupNamedDest(CPDF_Document* pDoc,
+ const CFX_ByteStringC& sName) {
+ CPDF_Object* pValue = LookupValue(sName);
+ if (!pValue) {
+ CPDF_Dictionary* pDests = pDoc->GetRoot()->GetDictBy("Dests");
+ if (!pDests)
+ return nullptr;
+ pValue = pDests->GetElementValue(sName);
+ }
+ if (!pValue)
+ return nullptr;
+ if (CPDF_Array* pArray = pValue->AsArray())
+ return pArray;
+ if (CPDF_Dictionary* pDict = pValue->AsDictionary())
+ return pDict->GetArrayBy("D");
+ return nullptr;
+}
+
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ || \
+ _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
+static CFX_WideString ChangeSlashToPlatform(const FX_WCHAR* str) {
+ CFX_WideString result;
+ while (*str) {
+ if (*str == '/') {
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+ result += ':';
+#else
+ result += '\\';
+#endif
+ } else {
+ result += *str;
+ }
+ str++;
+ }
+ return result;
+}
+
+static CFX_WideString ChangeSlashToPDF(const FX_WCHAR* str) {
+ CFX_WideString result;
+ while (*str) {
+ if (*str == '\\' || *str == ':') {
+ result += '/';
+ } else {
+ result += *str;
+ }
+ str++;
+ }
+ return result;
+}
+#endif // _FXM_PLATFORM_APPLE_ || _FXM_PLATFORM_WINDOWS_
+
+CFX_WideString CPDF_FileSpec::DecodeFileName(const CFX_WideStringC& filepath) {
+ if (filepath.GetLength() <= 1)
+ return CFX_WideString();
+
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+ if (filepath.Left(sizeof("/Mac") - 1) == CFX_WideStringC(L"/Mac"))
+ return ChangeSlashToPlatform(filepath.GetPtr() + 1);
+ return ChangeSlashToPlatform(filepath.GetPtr());
+#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
+ if (filepath.GetAt(0) != '/')
+ return ChangeSlashToPlatform(filepath.GetPtr());
+ if (filepath.GetAt(1) == '/')
+ return ChangeSlashToPlatform(filepath.GetPtr() + 1);
+ if (filepath.GetAt(2) == '/') {
+ CFX_WideString result;
+ result += filepath.GetAt(1);
+ result += ':';
+ result += ChangeSlashToPlatform(filepath.GetPtr() + 2);
+ return result;
+ }
+ CFX_WideString result;
+ result += '\\';
+ result += ChangeSlashToPlatform(filepath.GetPtr());
+ return result;
+#else
+ return filepath;
+#endif
+}
+
+bool CPDF_FileSpec::GetFileName(CFX_WideString* csFileName) const {
+ if (CPDF_Dictionary* pDict = m_pObj->AsDictionary()) {
+ *csFileName = pDict->GetUnicodeTextBy("UF");
+ if (csFileName->IsEmpty()) {
+ *csFileName = CFX_WideString::FromLocal(pDict->GetStringBy("F"));
+ }
+ if (pDict->GetStringBy("FS") == "URL")
+ return true;
+ if (csFileName->IsEmpty()) {
+ if (pDict->KeyExist("DOS")) {
+ *csFileName = CFX_WideString::FromLocal(pDict->GetStringBy("DOS"));
+ } else if (pDict->KeyExist("Mac")) {
+ *csFileName = CFX_WideString::FromLocal(pDict->GetStringBy("Mac"));
+ } else if (pDict->KeyExist("Unix")) {
+ *csFileName = CFX_WideString::FromLocal(pDict->GetStringBy("Unix"));
+ } else {
+ return false;
+ }
+ }
+ } else if (m_pObj->IsString()) {
+ *csFileName = CFX_WideString::FromLocal(m_pObj->GetString());
+ } else {
+ return false;
+ }
+ *csFileName = DecodeFileName(*csFileName);
+ return true;
+}
+
+CPDF_FileSpec::CPDF_FileSpec() {
+ m_pObj = new CPDF_Dictionary;
+ m_pObj->AsDictionary()->SetAtName("Type", "Filespec");
+}
+
+CFX_WideString CPDF_FileSpec::EncodeFileName(const CFX_WideStringC& filepath) {
+ if (filepath.GetLength() <= 1) {
+ return CFX_WideString();
+ }
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
+ if (filepath.GetAt(1) == ':') {
+ CFX_WideString result;
+ result = '/';
+ result += filepath.GetAt(0);
+ if (filepath.GetAt(2) != '\\') {
+ result += '/';
+ }
+ result += ChangeSlashToPDF(filepath.GetPtr() + 2);
+ return result;
+ }
+ if (filepath.GetAt(0) == '\\' && filepath.GetAt(1) == '\\') {
+ return ChangeSlashToPDF(filepath.GetPtr() + 1);
+ }
+ if (filepath.GetAt(0) == '\\') {
+ CFX_WideString result;
+ result = '/';
+ result += ChangeSlashToPDF(filepath.GetPtr());
+ return result;
+ }
+ return ChangeSlashToPDF(filepath.GetPtr());
+#elif _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+ if (filepath.Left(sizeof("Mac") - 1) == FX_WSTRC(L"Mac")) {
+ CFX_WideString result;
+ result = '/';
+ result += ChangeSlashToPDF(filepath.GetPtr());
+ return result;
+ }
+ return ChangeSlashToPDF(filepath.GetPtr());
+#else
+ return filepath;
+#endif
+}
+
+void CPDF_FileSpec::SetFileName(const CFX_WideStringC& wsFileName) {
+ if (!m_pObj)
+ return;
+
+ CFX_WideString wsStr = EncodeFileName(wsFileName);
+ if (m_pObj->IsString()) {
+ m_pObj->SetString(CFX_ByteString::FromUnicode(wsStr));
+ } else if (CPDF_Dictionary* pDict = m_pObj->AsDictionary()) {
+ pDict->SetAtString("F", CFX_ByteString::FromUnicode(wsStr));
+ pDict->SetAtString("UF", PDF_EncodeText(wsStr));
+ }
+}
+
+static CFX_WideString _MakeRoman(int num) {
+ const int arabic[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
+ const CFX_WideString roman[] = {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 nMaxNum = 1000000;
+ num %= nMaxNum;
+ int i = 0;
+ CFX_WideString wsRomanNumber;
+ while (num > 0) {
+ while (num >= arabic[i]) {
+ num = num - arabic[i];
+ wsRomanNumber += roman[i];
+ }
+ i = i + 1;
+ }
+ return wsRomanNumber;
+}
+
+static CFX_WideString _MakeLetters(int num) {
+ if (num == 0) {
+ return CFX_WideString();
+ }
+ CFX_WideString wsLetters;
+ const int nMaxCount = 1000;
+ const int nLetterCount = 26;
+ num -= 1;
+ int count = num / nLetterCount + 1;
+ count %= nMaxCount;
+ FX_WCHAR ch = L'a' + num % nLetterCount;
+ for (int i = 0; i < count; i++) {
+ wsLetters += ch;
+ }
+ return wsLetters;
+}
+static CFX_WideString _GetLabelNumPortion(int num,
+ const CFX_ByteString& bsStyle) {
+ CFX_WideString wsNumPortion;
+ if (bsStyle.IsEmpty()) {
+ return wsNumPortion;
+ }
+ if (bsStyle == "D") {
+ wsNumPortion.Format(L"%d", num);
+ } else if (bsStyle == "R") {
+ wsNumPortion = _MakeRoman(num);
+ wsNumPortion.MakeUpper();
+ } else if (bsStyle == "r") {
+ wsNumPortion = _MakeRoman(num);
+ } else if (bsStyle == "A") {
+ wsNumPortion = _MakeLetters(num);
+ wsNumPortion.MakeUpper();
+ } else if (bsStyle == "a") {
+ wsNumPortion = _MakeLetters(num);
+ }
+ return wsNumPortion;
+}
+CFX_WideString CPDF_PageLabel::GetLabel(int nPage) const {
+ CFX_WideString wsLabel;
+ if (!m_pDocument) {
+ return wsLabel;
+ }
+ CPDF_Dictionary* pPDFRoot = m_pDocument->GetRoot();
+ if (!pPDFRoot) {
+ return wsLabel;
+ }
+ CPDF_Dictionary* pLabels = pPDFRoot->GetDictBy("PageLabels");
+ CPDF_NumberTree numberTree(pLabels);
+ CPDF_Object* pValue = NULL;
+ int n = nPage;
+ while (n >= 0) {
+ pValue = numberTree.LookupValue(n);
+ if (pValue) {
+ break;
+ }
+ n--;
+ }
+ if (pValue) {
+ pValue = pValue->GetDirect();
+ if (CPDF_Dictionary* pLabel = pValue->AsDictionary()) {
+ if (pLabel->KeyExist("P")) {
+ wsLabel += pLabel->GetUnicodeTextBy("P");
+ }
+ CFX_ByteString bsNumberingStyle = pLabel->GetStringBy("S", NULL);
+ int nLabelNum = nPage - n + pLabel->GetIntegerBy("St", 1);
+ CFX_WideString wsNumPortion =
+ _GetLabelNumPortion(nLabelNum, bsNumberingStyle);
+ wsLabel += wsNumPortion;
+ return wsLabel;
+ }
+ }
+ wsLabel.Format(L"%d", nPage + 1);
+ return wsLabel;
+}
+int32_t CPDF_PageLabel::GetPageByLabel(const CFX_ByteStringC& bsLabel) const {
+ if (!m_pDocument) {
+ return -1;
+ }
+ CPDF_Dictionary* pPDFRoot = m_pDocument->GetRoot();
+ if (!pPDFRoot) {
+ return -1;
+ }
+ int nPages = m_pDocument->GetPageCount();
+ CFX_ByteString bsLbl;
+ CFX_ByteString bsOrig = bsLabel;
+ for (int i = 0; i < nPages; i++) {
+ bsLbl = PDF_EncodeText(GetLabel(i));
+ if (!bsLbl.Compare(bsOrig)) {
+ return i;
+ }
+ }
+ bsLbl = bsOrig;
+ int nPage = FXSYS_atoi(bsLbl);
+ if (nPage > 0 && nPage <= nPages) {
+ return nPage;
+ }
+ return -1;
+}
+int32_t CPDF_PageLabel::GetPageByLabel(const CFX_WideStringC& wsLabel) const {
+ CFX_ByteString bsLabel = PDF_EncodeText(wsLabel.GetPtr());
+ return GetPageByLabel(bsLabel);
+}