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_action.h"
      8 
      9 #include "core/fpdfapi/parser/cpdf_array.h"
     10 #include "core/fpdfapi/parser/cpdf_document.h"
     11 #include "core/fpdfdoc/cpdf_filespec.h"
     12 #include "core/fpdfdoc/cpdf_nametree.h"
     13 
     14 namespace {
     15 
     16 const char* const g_sATypes[] = {
     17     "Unknown",     "GoTo",       "GoToR",     "GoToE",      "Launch",
     18     "Thread",      "URI",        "Sound",     "Movie",      "Hide",
     19     "Named",       "SubmitForm", "ResetForm", "ImportData", "JavaScript",
     20     "SetOCGState", "Rendition",  "Trans",     "GoTo3DView", nullptr};
     21 
     22 }  // namespace
     23 
     24 CPDF_Action::CPDF_Action(CPDF_Dictionary* pDict) : m_pDict(pDict) {}
     25 
     26 CPDF_Action::CPDF_Action(const CPDF_Action& that) = default;
     27 
     28 CPDF_Action::~CPDF_Action() {}
     29 
     30 CPDF_Dest CPDF_Action::GetDest(CPDF_Document* pDoc) const {
     31   if (!m_pDict)
     32     return CPDF_Dest();
     33 
     34   ByteString type = m_pDict->GetStringFor("S");
     35   if (type != "GoTo" && type != "GoToR")
     36     return CPDF_Dest();
     37 
     38   CPDF_Object* pDest = m_pDict->GetDirectObjectFor("D");
     39   if (!pDest)
     40     return CPDF_Dest();
     41   if (pDest->IsString() || pDest->IsName()) {
     42     CPDF_NameTree name_tree(pDoc, "Dests");
     43     return CPDF_Dest(name_tree.LookupNamedDest(pDoc, pDest->GetUnicodeText()));
     44   }
     45   if (CPDF_Array* pArray = pDest->AsArray())
     46     return CPDF_Dest(pArray);
     47 
     48   return CPDF_Dest();
     49 }
     50 
     51 CPDF_Action::ActionType CPDF_Action::GetType() const {
     52   if (!m_pDict)
     53     return Unknown;
     54 
     55   ByteString csType = m_pDict->GetStringFor("S");
     56   if (csType.IsEmpty())
     57     return Unknown;
     58 
     59   for (int i = 0; g_sATypes[i]; ++i) {
     60     if (csType == g_sATypes[i])
     61       return static_cast<ActionType>(i);
     62   }
     63   return Unknown;
     64 }
     65 
     66 WideString CPDF_Action::GetFilePath() const {
     67   ByteString type = m_pDict->GetStringFor("S");
     68   if (type != "GoToR" && type != "Launch" && type != "SubmitForm" &&
     69       type != "ImportData") {
     70     return WideString();
     71   }
     72 
     73   CPDF_Object* pFile = m_pDict->GetDirectObjectFor("F");
     74   if (pFile)
     75     return CPDF_FileSpec(pFile).GetFileName();
     76 
     77   if (type == "Launch") {
     78     CPDF_Dictionary* pWinDict = m_pDict->GetDictFor("Win");
     79     if (pWinDict) {
     80       return WideString::FromLocal(pWinDict->GetStringFor("F").AsStringView());
     81     }
     82   }
     83   return WideString();
     84 }
     85 
     86 ByteString CPDF_Action::GetURI(const CPDF_Document* pDoc) const {
     87   ByteString csURI;
     88   if (!m_pDict)
     89     return csURI;
     90   if (m_pDict->GetStringFor("S") != "URI")
     91     return csURI;
     92 
     93   csURI = m_pDict->GetStringFor("URI");
     94   const CPDF_Dictionary* pRoot = pDoc->GetRoot();
     95   CPDF_Dictionary* pURI = pRoot->GetDictFor("URI");
     96   if (pURI) {
     97     auto result = csURI.Find(":");
     98     if (!result.has_value() || result.value() == 0)
     99       csURI = pURI->GetStringFor("Base") + csURI;
    100   }
    101   return csURI;
    102 }
    103 
    104 WideString CPDF_Action::GetJavaScript() const {
    105   WideString csJS;
    106   if (!m_pDict)
    107     return csJS;
    108 
    109   CPDF_Object* pJS = m_pDict->GetDirectObjectFor("JS");
    110   return pJS ? pJS->GetUnicodeText() : csJS;
    111 }
    112 
    113 size_t CPDF_Action::GetSubActionsCount() const {
    114   if (!m_pDict || !m_pDict->KeyExist("Next"))
    115     return 0;
    116 
    117   CPDF_Object* pNext = m_pDict->GetDirectObjectFor("Next");
    118   if (!pNext)
    119     return 0;
    120   if (pNext->IsDictionary())
    121     return 1;
    122   if (CPDF_Array* pArray = pNext->AsArray())
    123     return pArray->GetCount();
    124   return 0;
    125 }
    126 
    127 CPDF_Action CPDF_Action::GetSubAction(size_t iIndex) const {
    128   if (!m_pDict || !m_pDict->KeyExist("Next"))
    129     return CPDF_Action(nullptr);
    130 
    131   CPDF_Object* pNext = m_pDict->GetDirectObjectFor("Next");
    132   if (CPDF_Array* pArray = ToArray(pNext))
    133     return CPDF_Action(pArray->GetDictAt(iIndex));
    134   if (CPDF_Dictionary* pDict = ToDictionary(pNext)) {
    135     if (iIndex == 0)
    136       return CPDF_Action(pDict);
    137   }
    138   return CPDF_Action(nullptr);
    139 }
    140