Convert all line endings to LF.
[pdfium.git] / core / src / fpdfdoc / doc_basic.cpp
index 4ec8fb7..199a9a6 100644 (file)
-// Copyright 2014 PDFium Authors. All rights reserved.\r
-// Use of this source code is governed by a BSD-style license that can be\r
-// found in the LICENSE file.\r
\r
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
-\r
-#include "../../include/fpdfdoc/fpdf_doc.h"\r
-const int nMaxRecursion = 32;\r
-int CPDF_Dest::GetPageIndex(CPDF_Document* pDoc)\r
-{\r
-    if (m_pObj == NULL || m_pObj->GetType() != PDFOBJ_ARRAY) {\r
-        return 0;\r
-    }\r
-    CPDF_Object* pPage = ((CPDF_Array*)m_pObj)->GetElementValue(0);\r
-    if (pPage == NULL) {\r
-        return 0;\r
-    }\r
-    if (pPage->GetType() == PDFOBJ_NUMBER) {\r
-        return pPage->GetInteger();\r
-    }\r
-    if (pPage->GetType() != PDFOBJ_DICTIONARY) {\r
-        return 0;\r
-    }\r
-    return pDoc->GetPageIndex(pPage->GetObjNum());\r
-}\r
-FX_DWORD CPDF_Dest::GetPageObjNum()\r
-{\r
-    if (m_pObj == NULL || m_pObj->GetType() != PDFOBJ_ARRAY) {\r
-        return 0;\r
-    }\r
-    CPDF_Object* pPage = ((CPDF_Array*)m_pObj)->GetElementValue(0);\r
-    if (pPage == NULL) {\r
-        return 0;\r
-    }\r
-    if (pPage->GetType() == PDFOBJ_NUMBER) {\r
-        return pPage->GetInteger();\r
-    }\r
-    if (pPage->GetType() == PDFOBJ_DICTIONARY) {\r
-        return pPage->GetObjNum();\r
-    }\r
-    return 0;\r
-}\r
-const FX_CHAR* g_sZoomModes[] = {"XYZ", "Fit", "FitH", "FitV", "FitR", "FitB", "FitBH", "FitBV", ""};\r
-int CPDF_Dest::GetZoomMode()\r
-{\r
-    if (m_pObj == NULL || m_pObj->GetType() != PDFOBJ_ARRAY) {\r
-        return 0;\r
-    }\r
-    CFX_ByteString mode = ((CPDF_Array*)m_pObj)->GetElementValue(1)->GetString();\r
-    int i = 0;\r
-    while (g_sZoomModes[i][0] != '\0') {\r
-        if (mode == g_sZoomModes[i]) {\r
-            return i + 1;\r
-        }\r
-        i ++;\r
-    }\r
-    return 0;\r
-}\r
-FX_FLOAT CPDF_Dest::GetParam(int index)\r
-{\r
-    if (m_pObj == NULL || m_pObj->GetType() != PDFOBJ_ARRAY) {\r
-        return 0;\r
-    }\r
-    return ((CPDF_Array*)m_pObj)->GetNumber(2 + index);\r
-}\r
-CFX_ByteString CPDF_Dest::GetRemoteName()\r
-{\r
-    if (m_pObj == NULL) {\r
-        return CFX_ByteString();\r
-    }\r
-    return m_pObj->GetString();\r
-}\r
-CPDF_NameTree::CPDF_NameTree(CPDF_Document* pDoc, FX_BSTR category)\r
-{\r
-    m_pRoot = pDoc->GetRoot()->GetDict(FX_BSTRC("Names"))->GetDict(category);\r
-}\r
-static CPDF_Object* SearchNameNode(CPDF_Dictionary* pNode, const CFX_ByteString& csName,\r
-                                   int& nIndex, CPDF_Array** ppFind, int nLevel = 0)\r
-{\r
-    if (nLevel > nMaxRecursion) {\r
-        return NULL;\r
-    }\r
-    CPDF_Array* pLimits = pNode->GetArray(FX_BSTRC("Limits"));\r
-    if (pLimits != NULL) {\r
-        CFX_ByteString csLeft = pLimits->GetString(0);\r
-        CFX_ByteString csRight = pLimits->GetString(1);\r
-        if (csLeft.Compare(csRight) > 0) {\r
-            CFX_ByteString csTmp = csRight;\r
-            csRight = csLeft;\r
-            csLeft = csTmp;\r
-        }\r
-        if (csName.Compare(csLeft) < 0 || csName.Compare(csRight) > 0) {\r
-            return NULL;\r
-        }\r
-    }\r
-    CPDF_Array* pNames = pNode->GetArray(FX_BSTRC("Names"));\r
-    if (pNames) {\r
-        FX_DWORD dwCount = pNames->GetCount() / 2;\r
-        for (FX_DWORD i = 0; i < dwCount; i ++) {\r
-            CFX_ByteString csValue = pNames->GetString(i * 2);\r
-            FX_INT32 iCompare = csValue.Compare(csName);\r
-            if (iCompare <= 0) {\r
-                if (ppFind != NULL) {\r
-                    *ppFind = pNames;\r
-                }\r
-                if (iCompare < 0) {\r
-                    continue;\r
-                }\r
-            } else {\r
-                break;\r
-            }\r
-            nIndex += i;\r
-            return pNames->GetElementValue(i * 2 + 1);\r
-        }\r
-        nIndex += dwCount;\r
-        return NULL;\r
-    }\r
-    CPDF_Array* pKids = pNode->GetArray(FX_BSTRC("Kids"));\r
-    if (pKids == NULL) {\r
-        return NULL;\r
-    }\r
-    for (FX_DWORD i = 0; i < pKids->GetCount(); i ++) {\r
-        CPDF_Dictionary* pKid = pKids->GetDict(i);\r
-        if (pKid == NULL) {\r
-            continue;\r
-        }\r
-        CPDF_Object* pFound = SearchNameNode(pKid, csName, nIndex, ppFind, nLevel + 1);\r
-        if (pFound) {\r
-            return pFound;\r
-        }\r
-    }\r
-    return NULL;\r
-}\r
-static CPDF_Object* SearchNameNode(CPDF_Dictionary* pNode, int nIndex, int& nCurIndex,\r
-                                   CFX_ByteString& csName, CPDF_Array** ppFind, int nLevel = 0)\r
-{\r
-    if (nLevel > nMaxRecursion) {\r
-        return NULL;\r
-    }\r
-    CPDF_Array* pNames = pNode->GetArray(FX_BSTRC("Names"));\r
-    if (pNames) {\r
-        int nCount = pNames->GetCount() / 2;\r
-        if (nIndex >= nCurIndex + nCount) {\r
-            nCurIndex += nCount;\r
-            return NULL;\r
-        } else {\r
-            if (ppFind != NULL) {\r
-                *ppFind = pNames;\r
-            }\r
-            csName = pNames->GetString((nIndex - nCurIndex) * 2);\r
-            return pNames->GetElementValue((nIndex - nCurIndex) * 2 + 1);\r
-        }\r
-    }\r
-    CPDF_Array* pKids = pNode->GetArray(FX_BSTRC("Kids"));\r
-    if (pKids == NULL) {\r
-        return NULL;\r
-    }\r
-    for (FX_DWORD i = 0; i < pKids->GetCount(); i ++) {\r
-        CPDF_Dictionary* pKid = pKids->GetDict(i);\r
-        if (pKid == NULL) {\r
-            continue;\r
-        }\r
-        CPDF_Object* pFound = SearchNameNode(pKid, nIndex, nCurIndex, csName, ppFind, nLevel + 1);\r
-        if (pFound) {\r
-            return pFound;\r
-        }\r
-    }\r
-    return NULL;\r
-}\r
-static int CountNames(CPDF_Dictionary* pNode, int nLevel = 0)\r
-{\r
-    if (nLevel > nMaxRecursion) {\r
-        return 0;\r
-    }\r
-    CPDF_Array* pNames = pNode->GetArray(FX_BSTRC("Names"));\r
-    if (pNames) {\r
-        return pNames->GetCount() / 2;\r
-    }\r
-    CPDF_Array* pKids = pNode->GetArray(FX_BSTRC("Kids"));\r
-    if (pKids == NULL) {\r
-        return 0;\r
-    }\r
-    int nCount = 0;\r
-    for (FX_DWORD i = 0; i < pKids->GetCount(); i ++) {\r
-        CPDF_Dictionary* pKid = pKids->GetDict(i);\r
-        if (pKid == NULL) {\r
-            continue;\r
-        }\r
-        nCount += CountNames(pKid, nLevel + 1);\r
-    }\r
-    return nCount;\r
-}\r
-int CPDF_NameTree::GetCount() const\r
-{\r
-    if (m_pRoot == NULL) {\r
-        return 0;\r
-    }\r
-    return ::CountNames(m_pRoot);\r
-}\r
-int CPDF_NameTree::GetIndex(const CFX_ByteString& csName) const\r
-{\r
-    if (m_pRoot == NULL) {\r
-        return -1;\r
-    }\r
-    int nIndex = 0;\r
-    if (SearchNameNode(m_pRoot, csName, nIndex, NULL) == NULL) {\r
-        return -1;\r
-    }\r
-    return nIndex;\r
-}\r
-CPDF_Object* CPDF_NameTree::LookupValue(int nIndex, CFX_ByteString& csName) const\r
-{\r
-    if (m_pRoot == NULL) {\r
-        return NULL;\r
-    }\r
-    int nCurIndex = 0;\r
-    return SearchNameNode(m_pRoot, nIndex, nCurIndex, csName, NULL);\r
-}\r
-CPDF_Object* CPDF_NameTree::LookupValue(const CFX_ByteString& csName) const\r
-{\r
-    if (m_pRoot == NULL) {\r
-        return NULL;\r
-    }\r
-    int nIndex = 0;\r
-    return SearchNameNode(m_pRoot, csName, nIndex, NULL);\r
-}\r
-CPDF_Array*    CPDF_NameTree::LookupNamedDest(CPDF_Document* pDoc, FX_BSTR sName)\r
-{\r
-    CPDF_Object* pValue = LookupValue(sName);\r
-    if (pValue == NULL) {\r
-        CPDF_Dictionary* pDests = pDoc->GetRoot()->GetDict(FX_BSTRC("Dests"));\r
-        if (pDests == NULL) {\r
-            return NULL;\r
-        }\r
-        pValue = pDests->GetElementValue(sName);\r
-    }\r
-    if (pValue == NULL) {\r
-        return NULL;\r
-    }\r
-    if (pValue->GetType() == PDFOBJ_ARRAY) {\r
-        return (CPDF_Array*)pValue;\r
-    }\r
-    if (pValue->GetType() == PDFOBJ_DICTIONARY) {\r
-        return ((CPDF_Dictionary*)pValue)->GetArray(FX_BSTRC("D"));\r
-    }\r
-    return NULL;\r
-}\r
-static CFX_WideString ChangeSlashToPlatform(FX_LPCWSTR str)\r
-{\r
-    CFX_WideString result;\r
-    while (*str) {\r
-        if (*str == '/') {\r
-#if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_\r
-            result += ':';\r
-#elif _FXM_PLATFORM_  == _FXM_PLATFORM_WINDOWS_\r
-            result += '\\';\r
-#else\r
-            result += *str;\r
-#endif\r
-        } else {\r
-            result += *str;\r
-        }\r
-        str++;\r
-    }\r
-    return result;\r
-}\r
-static CFX_WideString FILESPEC_DecodeFileName(FX_WSTR filepath)\r
-{\r
-    if (filepath.GetLength() <= 1) {\r
-        return CFX_WideString();\r
-    }\r
-#if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_\r
-    if (filepath.Left(sizeof("/Mac") - 1) == CFX_WideStringC(L"/Mac")) {\r
-        return ChangeSlashToPlatform(filepath.GetPtr() + 1);\r
-    }\r
-    return ChangeSlashToPlatform(filepath.GetPtr());\r
-#elif _FXM_PLATFORM_  == _FXM_PLATFORM_WINDOWS_\r
-    if (filepath.GetAt(0) != '/') {\r
-        return ChangeSlashToPlatform(filepath.GetPtr());\r
-    }\r
-    if (filepath.GetAt(1) == '/') {\r
-        return ChangeSlashToPlatform(filepath.GetPtr() + 1);\r
-    }\r
-    if (filepath.GetAt(2) == '/') {\r
-        CFX_WideString result;\r
-        result += filepath.GetAt(1);\r
-        result += ':';\r
-        result += ChangeSlashToPlatform(filepath.GetPtr() + 2);\r
-        return result;\r
-    }\r
-    CFX_WideString result;\r
-    result += '\\';\r
-    result += ChangeSlashToPlatform(filepath.GetPtr());\r
-    return result;\r
-#else\r
-    return filepath;\r
-#endif\r
-}\r
-FX_BOOL CPDF_FileSpec::GetFileName(CFX_WideString &csFileName) const\r
-{\r
-    if (m_pObj == NULL) {\r
-        return FALSE;\r
-    }\r
-    if (m_pObj->GetType() == PDFOBJ_DICTIONARY) {\r
-        CPDF_Dictionary* pDict = (CPDF_Dictionary*)m_pObj;\r
-        csFileName = pDict->GetUnicodeText(FX_BSTRC("UF"));\r
-        if (csFileName.IsEmpty()) {\r
-            csFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("F")));\r
-        }\r
-        if (pDict->GetString(FX_BSTRC("FS")) == FX_BSTRC("URL")) {\r
-            return TRUE;\r
-        }\r
-        if (csFileName.IsEmpty()) {\r
-            if (pDict->KeyExist(FX_BSTRC("DOS"))) {\r
-                csFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("DOS")));\r
-            } else if (pDict->KeyExist(FX_BSTRC("Mac"))) {\r
-                csFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("Mac")));\r
-            } else if (pDict->KeyExist(FX_BSTRC("Unix"))) {\r
-                csFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("Unix")));\r
-            } else {\r
-                return FALSE;\r
-            }\r
-        }\r
-    } else {\r
-        csFileName = CFX_WideString::FromLocal(m_pObj->GetString());\r
-    }\r
-    csFileName = FILESPEC_DecodeFileName(csFileName);\r
-    return TRUE;\r
-}\r
-CPDF_FileSpec::CPDF_FileSpec()\r
-{\r
-    m_pObj = CPDF_Dictionary::Create();\r
-    if (m_pObj != NULL) {\r
-        ((CPDF_Dictionary*)m_pObj)->SetAtName(FX_BSTRC("Type"), FX_BSTRC("Filespec"));\r
-    }\r
-}\r
-FX_BOOL CPDF_FileSpec::IsURL() const\r
-{\r
-    if (m_pObj == NULL) {\r
-        return FALSE;\r
-    }\r
-    if (m_pObj->GetType() != PDFOBJ_DICTIONARY) {\r
-        return FALSE;\r
-    }\r
-    return ((CPDF_Dictionary*)m_pObj)->GetString(FX_BSTRC("FS")) == FX_BSTRC("URL");\r
-}\r
-static CFX_WideString ChangeSlashToPDF(FX_LPCWSTR str)\r
-{\r
-    CFX_WideString result;\r
-    while (*str) {\r
-        if (*str == '\\' || *str == ':') {\r
-            result += '/';\r
-        } else {\r
-            result += *str;\r
-        }\r
-        str++;\r
-    }\r
-    return result;\r
-}\r
-CFX_WideString FILESPEC_EncodeFileName(FX_WSTR filepath)\r
-{\r
-    if (filepath.GetLength() <= 1) {\r
-        return CFX_WideString();\r
-    }\r
-#if _FXM_PLATFORM_  == _FXM_PLATFORM_WINDOWS_\r
-    if (filepath.GetAt(1) == ':') {\r
-        CFX_WideString result;\r
-        result = '/';\r
-        result += filepath.GetAt(0);\r
-        if (filepath.GetAt(2) != '\\') {\r
-            result += '/';\r
-        }\r
-        result += ChangeSlashToPDF(filepath.GetPtr() + 2);\r
-        return result;\r
-    }\r
-    if (filepath.GetAt(0) == '\\' && filepath.GetAt(1) == '\\') {\r
-        return ChangeSlashToPDF(filepath.GetPtr() + 1);\r
-    }\r
-    if (filepath.GetAt(0) == '\\') {\r
-        CFX_WideString result;\r
-        result = '/';\r
-        result += ChangeSlashToPDF(filepath.GetPtr());\r
-        return result;\r
-    }\r
-    return ChangeSlashToPDF(filepath.GetPtr());\r
-#elif _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_\r
-    if (filepath.Left(sizeof("Mac") - 1) == FX_WSTRC(L"Mac")) {\r
-        CFX_WideString result;\r
-        result = '/';\r
-        result += ChangeSlashToPDF(filepath.GetPtr());\r
-        return result;\r
-    }\r
-    return ChangeSlashToPDF(filepath.GetPtr());\r
-#else\r
-    return filepath;\r
-#endif\r
-}\r
-CPDF_Stream* CPDF_FileSpec::GetFileStream() const\r
-{\r
-    if (m_pObj == NULL) {\r
-        return NULL;\r
-    }\r
-    FX_INT32 iType = m_pObj->GetType();\r
-    if (iType == PDFOBJ_STREAM) {\r
-        return (CPDF_Stream*)m_pObj;\r
-    } else if (iType == PDFOBJ_DICTIONARY) {\r
-        CPDF_Dictionary *pEF = ((CPDF_Dictionary*)m_pObj)->GetDict(FX_BSTRC("EF"));\r
-        if (pEF == NULL) {\r
-            return NULL;\r
-        }\r
-        return pEF->GetStream(FX_BSTRC("F"));\r
-    }\r
-    return NULL;\r
-}\r
-static void FPDFDOC_FILESPEC_SetFileName(CPDF_Object *pObj, FX_WSTR wsFileName, FX_BOOL bURL)\r
-{\r
-    ASSERT(pObj != NULL);\r
-    CFX_WideString wsStr;\r
-    if (bURL) {\r
-        wsStr = wsFileName;\r
-    } else {\r
-        wsStr = FILESPEC_EncodeFileName(wsFileName);\r
-    }\r
-    FX_INT32 iType = pObj->GetType();\r
-    if (iType == PDFOBJ_STRING) {\r
-        pObj->SetString(CFX_ByteString::FromUnicode(wsStr));\r
-    } else if (iType == PDFOBJ_DICTIONARY) {\r
-        CPDF_Dictionary* pDict = (CPDF_Dictionary*)pObj;\r
-        pDict->SetAtString(FX_BSTRC("F"), CFX_ByteString::FromUnicode(wsStr));\r
-        pDict->SetAtString(FX_BSTRC("UF"), PDF_EncodeText(wsStr));\r
-    }\r
-}\r
-void CPDF_FileSpec::SetFileName(FX_WSTR wsFileName, FX_BOOL bURL)\r
-{\r
-    ASSERT(m_pObj != NULL);\r
-    if (m_pObj->GetType() == PDFOBJ_DICTIONARY && bURL) {\r
-        ((CPDF_Dictionary*)m_pObj)->SetAtName(FX_BSTRC("FS"), "URL");\r
-    }\r
-    FPDFDOC_FILESPEC_SetFileName(m_pObj, wsFileName, bURL);\r
-}\r
-static CFX_WideString _MakeRoman(int num)\r
-{\r
-    const int arabic[] = {\r
-        1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1\r
-    };\r
-    const CFX_WideString roman[] = {\r
-        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"\r
-    };\r
-    const int nMaxNum = 1000000;\r
-    num %= nMaxNum;\r
-    int i = 0;\r
-    CFX_WideString wsRomanNumber;\r
-    while (num > 0) {\r
-        while (num >= arabic[i]) {\r
-            num = num - arabic[i];\r
-            wsRomanNumber += roman[i];\r
-        }\r
-        i = i + 1;\r
-    }\r
-    return wsRomanNumber;\r
-}\r
-static CFX_WideString _MakeLetters(int num)\r
-{\r
-    if (num == 0) {\r
-        return CFX_WideString();\r
-    }\r
-    CFX_WideString wsLetters;\r
-    const int nMaxCount = 1000;\r
-    const int nLetterCount = 26;\r
-    num -= 1;\r
-    int count = num / nLetterCount + 1;\r
-    count %= nMaxCount;\r
-    FX_WCHAR ch = L'a' + num % nLetterCount;\r
-    for (int i = 0; i < count; i++) {\r
-        wsLetters += ch;\r
-    }\r
-    return wsLetters;\r
-}\r
-static CFX_WideString _GetLabelNumPortion(int num, const CFX_ByteString& bsStyle)\r
-{\r
-    CFX_WideString wsNumPortion;\r
-    if         (bsStyle.IsEmpty()) {\r
-        return wsNumPortion;\r
-    }\r
-    if (bsStyle == "D") {\r
-        wsNumPortion.Format((FX_LPCWSTR)L"%d", num);\r
-    } else if (bsStyle == "R") {\r
-        wsNumPortion = _MakeRoman(num);\r
-        wsNumPortion.MakeUpper();\r
-    } else if (bsStyle == "r") {\r
-        wsNumPortion = _MakeRoman(num);\r
-    } else if (bsStyle == "A") {\r
-        wsNumPortion = _MakeLetters(num);\r
-        wsNumPortion.MakeUpper();\r
-    } else if (bsStyle == "a") {\r
-        wsNumPortion = _MakeLetters(num);\r
-    }\r
-    return wsNumPortion;\r
-}\r
-CFX_WideString CPDF_PageLabel::GetLabel(int nPage) const\r
-{\r
-    CFX_WideString wsLabel;\r
-    if (m_pDocument == NULL) {\r
-        return wsLabel;\r
-    }\r
-    CPDF_Dictionary* pPDFRoot = m_pDocument->GetRoot();\r
-    if (pPDFRoot == NULL) {\r
-        return wsLabel;\r
-    }\r
-    CPDF_Dictionary* pLabels = pPDFRoot->GetDict(FX_BSTRC("PageLabels"));\r
-    CPDF_NumberTree numberTree(pLabels);\r
-    CPDF_Object* pValue = NULL;\r
-    int n = nPage;\r
-    while (n >= 0) {\r
-        pValue = numberTree.LookupValue(n);\r
-        if (pValue != NULL) {\r
-            break;\r
-        }\r
-        n--;\r
-    }\r
-    if (pValue != NULL) {\r
-        pValue = pValue->GetDirect();\r
-        if (pValue->GetType() == PDFOBJ_DICTIONARY) {\r
-            CPDF_Dictionary* pLabel = (CPDF_Dictionary*)pValue;\r
-            if (pLabel->KeyExist(FX_BSTRC("P"))) {\r
-                wsLabel += pLabel->GetUnicodeText(FX_BSTRC("P"));\r
-            }\r
-            CFX_ByteString bsNumberingStyle = pLabel->GetString(FX_BSTRC("S"), NULL);\r
-            int nLabelNum = nPage - n + pLabel->GetInteger(FX_BSTRC("St"), 1);\r
-            CFX_WideString wsNumPortion = _GetLabelNumPortion(nLabelNum, bsNumberingStyle);\r
-            wsLabel += wsNumPortion;\r
-            return wsLabel;\r
-        }\r
-    }\r
-    wsLabel.Format((FX_LPCWSTR)L"%d", nPage + 1);\r
-    return wsLabel;\r
-}\r
-FX_INT32 CPDF_PageLabel::GetPageByLabel(FX_BSTR bsLabel) const\r
-{\r
-    if (m_pDocument == NULL) {\r
-        return -1;\r
-    }\r
-    CPDF_Dictionary* pPDFRoot = m_pDocument->GetRoot();\r
-    if (pPDFRoot == NULL) {\r
-        return -1;\r
-    }\r
-    int nPages = m_pDocument->GetPageCount();\r
-    CFX_ByteString bsLbl;\r
-    CFX_ByteString bsOrig = bsLabel;\r
-    for (int i = 0; i < nPages; i++) {\r
-        bsLbl = PDF_EncodeText(GetLabel(i));\r
-        if (!bsLbl.Compare(bsOrig)) {\r
-            return i;\r
-        }\r
-    }\r
-    bsLbl = bsOrig;\r
-    int nPage = FXSYS_atoi(bsLbl);\r
-    if (nPage > 0 && nPage <= nPages) {\r
-        return nPage;\r
-    }\r
-    return -1;\r
-}\r
-FX_INT32 CPDF_PageLabel::GetPageByLabel(FX_WSTR wsLabel) const\r
-{\r
-    CFX_ByteString bsLabel = PDF_EncodeText((CFX_WideString)wsLabel);\r
-    return GetPageByLabel(bsLabel);\r
-}\r
+// 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 "../../include/fpdfdoc/fpdf_doc.h"
+const int nMaxRecursion = 32;
+int CPDF_Dest::GetPageIndex(CPDF_Document* pDoc)
+{
+    if (m_pObj == NULL || m_pObj->GetType() != PDFOBJ_ARRAY) {
+        return 0;
+    }
+    CPDF_Object* pPage = ((CPDF_Array*)m_pObj)->GetElementValue(0);
+    if (pPage == NULL) {
+        return 0;
+    }
+    if (pPage->GetType() == PDFOBJ_NUMBER) {
+        return pPage->GetInteger();
+    }
+    if (pPage->GetType() != PDFOBJ_DICTIONARY) {
+        return 0;
+    }
+    return pDoc->GetPageIndex(pPage->GetObjNum());
+}
+FX_DWORD CPDF_Dest::GetPageObjNum()
+{
+    if (m_pObj == NULL || m_pObj->GetType() != PDFOBJ_ARRAY) {
+        return 0;
+    }
+    CPDF_Object* pPage = ((CPDF_Array*)m_pObj)->GetElementValue(0);
+    if (pPage == NULL) {
+        return 0;
+    }
+    if (pPage->GetType() == PDFOBJ_NUMBER) {
+        return pPage->GetInteger();
+    }
+    if (pPage->GetType() == PDFOBJ_DICTIONARY) {
+        return pPage->GetObjNum();
+    }
+    return 0;
+}
+const FX_CHAR* g_sZoomModes[] = {"XYZ", "Fit", "FitH", "FitV", "FitR", "FitB", "FitBH", "FitBV", ""};
+int CPDF_Dest::GetZoomMode()
+{
+    if (m_pObj == NULL || m_pObj->GetType() != PDFOBJ_ARRAY) {
+        return 0;
+    }
+    CFX_ByteString mode = ((CPDF_Array*)m_pObj)->GetElementValue(1)->GetString();
+    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)
+{
+    if (m_pObj == NULL || m_pObj->GetType() != PDFOBJ_ARRAY) {
+        return 0;
+    }
+    return ((CPDF_Array*)m_pObj)->GetNumber(2 + index);
+}
+CFX_ByteString CPDF_Dest::GetRemoteName()
+{
+    if (m_pObj == NULL) {
+        return CFX_ByteString();
+    }
+    return m_pObj->GetString();
+}
+CPDF_NameTree::CPDF_NameTree(CPDF_Document* pDoc, FX_BSTR category)
+{
+    m_pRoot = pDoc->GetRoot()->GetDict(FX_BSTRC("Names"))->GetDict(category);
+}
+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->GetArray(FX_BSTRC("Limits"));
+    if (pLimits != NULL) {
+        CFX_ByteString csLeft = pLimits->GetString(0);
+        CFX_ByteString csRight = pLimits->GetString(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->GetArray(FX_BSTRC("Names"));
+    if (pNames) {
+        FX_DWORD dwCount = pNames->GetCount() / 2;
+        for (FX_DWORD i = 0; i < dwCount; i ++) {
+            CFX_ByteString csValue = pNames->GetString(i * 2);
+            FX_INT32 iCompare = csValue.Compare(csName);
+            if (iCompare <= 0) {
+                if (ppFind != NULL) {
+                    *ppFind = pNames;
+                }
+                if (iCompare < 0) {
+                    continue;
+                }
+            } else {
+                break;
+            }
+            nIndex += i;
+            return pNames->GetElementValue(i * 2 + 1);
+        }
+        nIndex += dwCount;
+        return NULL;
+    }
+    CPDF_Array* pKids = pNode->GetArray(FX_BSTRC("Kids"));
+    if (pKids == NULL) {
+        return NULL;
+    }
+    for (FX_DWORD i = 0; i < pKids->GetCount(); i ++) {
+        CPDF_Dictionary* pKid = pKids->GetDict(i);
+        if (pKid == NULL) {
+            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->GetArray(FX_BSTRC("Names"));
+    if (pNames) {
+        int nCount = pNames->GetCount() / 2;
+        if (nIndex >= nCurIndex + nCount) {
+            nCurIndex += nCount;
+            return NULL;
+        } else {
+            if (ppFind != NULL) {
+                *ppFind = pNames;
+            }
+            csName = pNames->GetString((nIndex - nCurIndex) * 2);
+            return pNames->GetElementValue((nIndex - nCurIndex) * 2 + 1);
+        }
+    }
+    CPDF_Array* pKids = pNode->GetArray(FX_BSTRC("Kids"));
+    if (pKids == NULL) {
+        return NULL;
+    }
+    for (FX_DWORD i = 0; i < pKids->GetCount(); i ++) {
+        CPDF_Dictionary* pKid = pKids->GetDict(i);
+        if (pKid == NULL) {
+            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->GetArray(FX_BSTRC("Names"));
+    if (pNames) {
+        return pNames->GetCount() / 2;
+    }
+    CPDF_Array* pKids = pNode->GetArray(FX_BSTRC("Kids"));
+    if (pKids == NULL) {
+        return 0;
+    }
+    int nCount = 0;
+    for (FX_DWORD i = 0; i < pKids->GetCount(); i ++) {
+        CPDF_Dictionary* pKid = pKids->GetDict(i);
+        if (pKid == NULL) {
+            continue;
+        }
+        nCount += CountNames(pKid, nLevel + 1);
+    }
+    return nCount;
+}
+int CPDF_NameTree::GetCount() const
+{
+    if (m_pRoot == NULL) {
+        return 0;
+    }
+    return ::CountNames(m_pRoot);
+}
+int CPDF_NameTree::GetIndex(const CFX_ByteString& csName) const
+{
+    if (m_pRoot == NULL) {
+        return -1;
+    }
+    int nIndex = 0;
+    if (SearchNameNode(m_pRoot, csName, nIndex, NULL) == NULL) {
+        return -1;
+    }
+    return nIndex;
+}
+CPDF_Object* CPDF_NameTree::LookupValue(int nIndex, CFX_ByteString& csName) const
+{
+    if (m_pRoot == NULL) {
+        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 == NULL) {
+        return NULL;
+    }
+    int nIndex = 0;
+    return SearchNameNode(m_pRoot, csName, nIndex, NULL);
+}
+CPDF_Array*    CPDF_NameTree::LookupNamedDest(CPDF_Document* pDoc, FX_BSTR sName)
+{
+    CPDF_Object* pValue = LookupValue(sName);
+    if (pValue == NULL) {
+        CPDF_Dictionary* pDests = pDoc->GetRoot()->GetDict(FX_BSTRC("Dests"));
+        if (pDests == NULL) {
+            return NULL;
+        }
+        pValue = pDests->GetElementValue(sName);
+    }
+    if (pValue == NULL) {
+        return NULL;
+    }
+    if (pValue->GetType() == PDFOBJ_ARRAY) {
+        return (CPDF_Array*)pValue;
+    }
+    if (pValue->GetType() == PDFOBJ_DICTIONARY) {
+        return ((CPDF_Dictionary*)pValue)->GetArray(FX_BSTRC("D"));
+    }
+    return NULL;
+}
+static CFX_WideString ChangeSlashToPlatform(FX_LPCWSTR str)
+{
+    CFX_WideString result;
+    while (*str) {
+        if (*str == '/') {
+#if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
+            result += ':';
+#elif _FXM_PLATFORM_  == _FXM_PLATFORM_WINDOWS_
+            result += '\\';
+#else
+            result += *str;
+#endif
+        } else {
+            result += *str;
+        }
+        str++;
+    }
+    return result;
+}
+static CFX_WideString FILESPEC_DecodeFileName(FX_WSTR 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
+}
+FX_BOOL CPDF_FileSpec::GetFileName(CFX_WideString &csFileName) const
+{
+    if (m_pObj == NULL) {
+        return FALSE;
+    }
+    if (m_pObj->GetType() == PDFOBJ_DICTIONARY) {
+        CPDF_Dictionary* pDict = (CPDF_Dictionary*)m_pObj;
+        csFileName = pDict->GetUnicodeText(FX_BSTRC("UF"));
+        if (csFileName.IsEmpty()) {
+            csFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("F")));
+        }
+        if (pDict->GetString(FX_BSTRC("FS")) == FX_BSTRC("URL")) {
+            return TRUE;
+        }
+        if (csFileName.IsEmpty()) {
+            if (pDict->KeyExist(FX_BSTRC("DOS"))) {
+                csFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("DOS")));
+            } else if (pDict->KeyExist(FX_BSTRC("Mac"))) {
+                csFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("Mac")));
+            } else if (pDict->KeyExist(FX_BSTRC("Unix"))) {
+                csFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("Unix")));
+            } else {
+                return FALSE;
+            }
+        }
+    } else {
+        csFileName = CFX_WideString::FromLocal(m_pObj->GetString());
+    }
+    csFileName = FILESPEC_DecodeFileName(csFileName);
+    return TRUE;
+}
+CPDF_FileSpec::CPDF_FileSpec()
+{
+    m_pObj = CPDF_Dictionary::Create();
+    if (m_pObj != NULL) {
+        ((CPDF_Dictionary*)m_pObj)->SetAtName(FX_BSTRC("Type"), FX_BSTRC("Filespec"));
+    }
+}
+FX_BOOL CPDF_FileSpec::IsURL() const
+{
+    if (m_pObj == NULL) {
+        return FALSE;
+    }
+    if (m_pObj->GetType() != PDFOBJ_DICTIONARY) {
+        return FALSE;
+    }
+    return ((CPDF_Dictionary*)m_pObj)->GetString(FX_BSTRC("FS")) == FX_BSTRC("URL");
+}
+static CFX_WideString ChangeSlashToPDF(FX_LPCWSTR str)
+{
+    CFX_WideString result;
+    while (*str) {
+        if (*str == '\\' || *str == ':') {
+            result += '/';
+        } else {
+            result += *str;
+        }
+        str++;
+    }
+    return result;
+}
+CFX_WideString FILESPEC_EncodeFileName(FX_WSTR 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
+}
+CPDF_Stream* CPDF_FileSpec::GetFileStream() const
+{
+    if (m_pObj == NULL) {
+        return NULL;
+    }
+    FX_INT32 iType = m_pObj->GetType();
+    if (iType == PDFOBJ_STREAM) {
+        return (CPDF_Stream*)m_pObj;
+    } else if (iType == PDFOBJ_DICTIONARY) {
+        CPDF_Dictionary *pEF = ((CPDF_Dictionary*)m_pObj)->GetDict(FX_BSTRC("EF"));
+        if (pEF == NULL) {
+            return NULL;
+        }
+        return pEF->GetStream(FX_BSTRC("F"));
+    }
+    return NULL;
+}
+static void FPDFDOC_FILESPEC_SetFileName(CPDF_Object *pObj, FX_WSTR wsFileName, FX_BOOL bURL)
+{
+    ASSERT(pObj != NULL);
+    CFX_WideString wsStr;
+    if (bURL) {
+        wsStr = wsFileName;
+    } else {
+        wsStr = FILESPEC_EncodeFileName(wsFileName);
+    }
+    FX_INT32 iType = pObj->GetType();
+    if (iType == PDFOBJ_STRING) {
+        pObj->SetString(CFX_ByteString::FromUnicode(wsStr));
+    } else if (iType == PDFOBJ_DICTIONARY) {
+        CPDF_Dictionary* pDict = (CPDF_Dictionary*)pObj;
+        pDict->SetAtString(FX_BSTRC("F"), CFX_ByteString::FromUnicode(wsStr));
+        pDict->SetAtString(FX_BSTRC("UF"), PDF_EncodeText(wsStr));
+    }
+}
+void CPDF_FileSpec::SetFileName(FX_WSTR wsFileName, FX_BOOL bURL)
+{
+    ASSERT(m_pObj != NULL);
+    if (m_pObj->GetType() == PDFOBJ_DICTIONARY && bURL) {
+        ((CPDF_Dictionary*)m_pObj)->SetAtName(FX_BSTRC("FS"), "URL");
+    }
+    FPDFDOC_FILESPEC_SetFileName(m_pObj, wsFileName, bURL);
+}
+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((FX_LPCWSTR)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 == NULL) {
+        return wsLabel;
+    }
+    CPDF_Dictionary* pPDFRoot = m_pDocument->GetRoot();
+    if (pPDFRoot == NULL) {
+        return wsLabel;
+    }
+    CPDF_Dictionary* pLabels = pPDFRoot->GetDict(FX_BSTRC("PageLabels"));
+    CPDF_NumberTree numberTree(pLabels);
+    CPDF_Object* pValue = NULL;
+    int n = nPage;
+    while (n >= 0) {
+        pValue = numberTree.LookupValue(n);
+        if (pValue != NULL) {
+            break;
+        }
+        n--;
+    }
+    if (pValue != NULL) {
+        pValue = pValue->GetDirect();
+        if (pValue->GetType() == PDFOBJ_DICTIONARY) {
+            CPDF_Dictionary* pLabel = (CPDF_Dictionary*)pValue;
+            if (pLabel->KeyExist(FX_BSTRC("P"))) {
+                wsLabel += pLabel->GetUnicodeText(FX_BSTRC("P"));
+            }
+            CFX_ByteString bsNumberingStyle = pLabel->GetString(FX_BSTRC("S"), NULL);
+            int nLabelNum = nPage - n + pLabel->GetInteger(FX_BSTRC("St"), 1);
+            CFX_WideString wsNumPortion = _GetLabelNumPortion(nLabelNum, bsNumberingStyle);
+            wsLabel += wsNumPortion;
+            return wsLabel;
+        }
+    }
+    wsLabel.Format((FX_LPCWSTR)L"%d", nPage + 1);
+    return wsLabel;
+}
+FX_INT32 CPDF_PageLabel::GetPageByLabel(FX_BSTR bsLabel) const
+{
+    if (m_pDocument == NULL) {
+        return -1;
+    }
+    CPDF_Dictionary* pPDFRoot = m_pDocument->GetRoot();
+    if (pPDFRoot == NULL) {
+        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;
+}
+FX_INT32 CPDF_PageLabel::GetPageByLabel(FX_WSTR wsLabel) const
+{
+    CFX_ByteString bsLabel = PDF_EncodeText((CFX_WideString)wsLabel);
+    return GetPageByLabel(bsLabel);
+}