• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "constants/stream_dict_common.h"
10 #include "core/fpdfapi/parser/cpdf_array.h"
11 #include "core/fpdfapi/parser/cpdf_dictionary.h"
12 #include "core/fpdfapi/parser/cpdf_document.h"
13 #include "core/fpdfapi/parser/cpdf_name.h"
14 #include "core/fpdfdoc/cpdf_filespec.h"
15 #include "core/fpdfdoc/cpdf_nametree.h"
16 
17 namespace {
18 
19 const char* const g_sATypes[] = {
20     "Unknown",     "GoTo",       "GoToR",     "GoToE",      "Launch",
21     "Thread",      "URI",        "Sound",     "Movie",      "Hide",
22     "Named",       "SubmitForm", "ResetForm", "ImportData", "JavaScript",
23     "SetOCGState", "Rendition",  "Trans",     "GoTo3DView", nullptr};
24 
25 }  // namespace
26 
CPDF_Action(const CPDF_Dictionary * pDict)27 CPDF_Action::CPDF_Action(const CPDF_Dictionary* pDict) : m_pDict(pDict) {}
28 
29 CPDF_Action::CPDF_Action(const CPDF_Action& that) = default;
30 
31 CPDF_Action::~CPDF_Action() = default;
32 
GetType() const33 CPDF_Action::ActionType CPDF_Action::GetType() const {
34   if (!m_pDict)
35     return Unknown;
36 
37   // Validate |m_pDict|. Type is optional, but must be valid if present.
38   const CPDF_Object* pType = m_pDict->GetObjectFor("Type");
39   if (pType) {
40     const CPDF_Name* pName = pType->AsName();
41     if (!pName || pName->GetString() != "Action")
42       return Unknown;
43   }
44 
45   ByteString csType = m_pDict->GetStringFor("S");
46   if (csType.IsEmpty())
47     return Unknown;
48 
49   for (int i = 0; g_sATypes[i]; ++i) {
50     if (csType == g_sATypes[i])
51       return static_cast<ActionType>(i);
52   }
53   return Unknown;
54 }
55 
GetDest(CPDF_Document * pDoc) const56 CPDF_Dest CPDF_Action::GetDest(CPDF_Document* pDoc) const {
57   ActionType type = GetType();
58   if (type != GoTo && type != GoToR)
59     return CPDF_Dest();
60 
61   const CPDF_Object* pDest = m_pDict->GetDirectObjectFor("D");
62   if (!pDest)
63     return CPDF_Dest();
64   if (pDest->IsString() || pDest->IsName()) {
65     CPDF_NameTree name_tree(pDoc, "Dests");
66     return CPDF_Dest(name_tree.LookupNamedDest(pDoc, pDest->GetUnicodeText()));
67   }
68   if (const CPDF_Array* pArray = pDest->AsArray())
69     return CPDF_Dest(pArray);
70 
71   return CPDF_Dest();
72 }
73 
GetFilePath() const74 WideString CPDF_Action::GetFilePath() const {
75   ActionType type = GetType();
76   if (type != GoToR && type != Launch && type != SubmitForm &&
77       type != ImportData) {
78     return WideString();
79   }
80 
81   const CPDF_Object* pFile = m_pDict->GetDirectObjectFor(pdfium::stream::kF);
82   if (pFile)
83     return CPDF_FileSpec(pFile).GetFileName();
84 
85   if (type != Launch)
86     return WideString();
87 
88   const CPDF_Dictionary* pWinDict = m_pDict->GetDictFor("Win");
89   if (!pWinDict)
90     return WideString();
91 
92   return WideString::FromDefANSI(
93       pWinDict->GetStringFor(pdfium::stream::kF).AsStringView());
94 }
95 
GetURI(const CPDF_Document * pDoc) const96 ByteString CPDF_Action::GetURI(const CPDF_Document* pDoc) const {
97   ActionType type = GetType();
98   if (type != URI)
99     return ByteString();
100 
101   ByteString csURI = m_pDict->GetStringFor("URI");
102   const CPDF_Dictionary* pRoot = pDoc->GetRoot();
103   const CPDF_Dictionary* pURI = pRoot->GetDictFor("URI");
104   if (pURI) {
105     auto result = csURI.Find(":");
106     if (!result.has_value() || result.value() == 0) {
107       auto* pBase = pURI->GetDirectObjectFor("Base");
108       if (pBase && (pBase->IsString() || pBase->IsStream()))
109         csURI = pBase->GetString() + csURI;
110     }
111   }
112   return csURI;
113 }
114 
GetHideStatus() const115 bool CPDF_Action::GetHideStatus() const {
116   return m_pDict->GetBooleanFor("H", true);
117 }
118 
GetNamedAction() const119 ByteString CPDF_Action::GetNamedAction() const {
120   return m_pDict->GetStringFor("N");
121 }
122 
GetFlags() const123 uint32_t CPDF_Action::GetFlags() const {
124   return m_pDict->GetIntegerFor("Flags");
125 }
126 
GetAllFields() const127 std::vector<const CPDF_Object*> CPDF_Action::GetAllFields() const {
128   std::vector<const CPDF_Object*> result;
129   if (!m_pDict)
130     return result;
131 
132   ByteString csType = m_pDict->GetStringFor("S");
133   const CPDF_Object* pFields = csType == "Hide"
134                                    ? m_pDict->GetDirectObjectFor("T")
135                                    : m_pDict->GetArrayFor("Fields");
136   if (!pFields)
137     return result;
138 
139   if (pFields->IsDictionary() || pFields->IsString()) {
140     result.push_back(pFields);
141   } else if (const CPDF_Array* pArray = pFields->AsArray()) {
142     for (size_t i = 0; i < pArray->size(); ++i) {
143       const CPDF_Object* pObj = pArray->GetDirectObjectAt(i);
144       if (pObj)
145         result.push_back(pObj);
146     }
147   }
148   return result;
149 }
150 
MaybeGetJavaScript() const151 Optional<WideString> CPDF_Action::MaybeGetJavaScript() const {
152   const CPDF_Object* pObject = GetJavaScriptObject();
153   if (!pObject)
154     return pdfium::nullopt;
155   return pObject->GetUnicodeText();
156 }
157 
GetJavaScript() const158 WideString CPDF_Action::GetJavaScript() const {
159   const CPDF_Object* pObject = GetJavaScriptObject();
160   return pObject ? pObject->GetUnicodeText() : WideString();
161 }
162 
GetSubActionsCount() const163 size_t CPDF_Action::GetSubActionsCount() const {
164   if (!m_pDict || !m_pDict->KeyExist("Next"))
165     return 0;
166 
167   const CPDF_Object* pNext = m_pDict->GetDirectObjectFor("Next");
168   if (!pNext)
169     return 0;
170   if (pNext->IsDictionary())
171     return 1;
172   const CPDF_Array* pArray = pNext->AsArray();
173   return pArray ? pArray->size() : 0;
174 }
175 
GetSubAction(size_t iIndex) const176 CPDF_Action CPDF_Action::GetSubAction(size_t iIndex) const {
177   if (!m_pDict || !m_pDict->KeyExist("Next"))
178     return CPDF_Action(nullptr);
179 
180   const CPDF_Object* pNext = m_pDict->GetDirectObjectFor("Next");
181   if (const CPDF_Array* pArray = ToArray(pNext))
182     return CPDF_Action(pArray->GetDictAt(iIndex));
183   if (const CPDF_Dictionary* pDict = ToDictionary(pNext)) {
184     if (iIndex == 0)
185       return CPDF_Action(pDict);
186   }
187   return CPDF_Action(nullptr);
188 }
189 
GetJavaScriptObject() const190 const CPDF_Object* CPDF_Action::GetJavaScriptObject() const {
191   if (!m_pDict)
192     return nullptr;
193 
194   const CPDF_Object* pJS = m_pDict->GetDirectObjectFor("JS");
195   return (pJS && (pJS->IsString() || pJS->IsStream())) ? pJS : nullptr;
196 }
197