• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The PDFium Authors
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 <array>
10 #include <iterator>
11 #include <utility>
12 
13 #include "constants/stream_dict_common.h"
14 #include "core/fpdfapi/parser/cpdf_array.h"
15 #include "core/fpdfapi/parser/cpdf_dictionary.h"
16 #include "core/fpdfapi/parser/cpdf_document.h"
17 #include "core/fpdfapi/parser/cpdf_name.h"
18 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
19 #include "core/fpdfdoc/cpdf_filespec.h"
20 #include "core/fxcrt/stl_util.h"
21 
22 namespace {
23 
24 constexpr auto kActionTypeStrings = fxcrt::ToArray<const char*>({
25     "GoTo",
26     "GoToR",
27     "GoToE",
28     "Launch",
29     "Thread",
30     "URI",
31     "Sound",
32     "Movie",
33     "Hide",
34     "Named",
35     "SubmitForm",
36     "ResetForm",
37     "ImportData",
38     "JavaScript",
39     "SetOCGState",
40     "Rendition",
41     "Trans",
42     "GoTo3DView",
43 });
44 
45 }  // namespace
46 
CPDF_Action(RetainPtr<const CPDF_Dictionary> pDict)47 CPDF_Action::CPDF_Action(RetainPtr<const CPDF_Dictionary> pDict)
48     : m_pDict(std::move(pDict)) {}
49 
50 CPDF_Action::CPDF_Action(const CPDF_Action& that) = default;
51 
52 CPDF_Action::~CPDF_Action() = default;
53 
GetType() const54 CPDF_Action::Type CPDF_Action::GetType() const {
55   // See ISO 32000-1:2008 spec, table 193.
56   if (!ValidateDictOptionalType(m_pDict.Get(), "Action"))
57     return Type::kUnknown;
58 
59   ByteString csType = m_pDict->GetNameFor("S");
60   if (csType.IsEmpty())
61     return Type::kUnknown;
62 
63   static_assert(
64       std::size(kActionTypeStrings) == static_cast<size_t>(Type::kLast),
65       "Type mismatch");
66   for (size_t i = 0; i < std::size(kActionTypeStrings); ++i) {
67     if (csType == kActionTypeStrings[i])
68       return static_cast<Type>(i + 1);
69   }
70   return Type::kUnknown;
71 }
72 
GetDest(CPDF_Document * pDoc) const73 CPDF_Dest CPDF_Action::GetDest(CPDF_Document* pDoc) const {
74   Type type = GetType();
75   if (type != Type::kGoTo && type != Type::kGoToR && type != Type::kGoToE) {
76     return CPDF_Dest(nullptr);
77   }
78   return CPDF_Dest::Create(pDoc, m_pDict->GetDirectObjectFor("D"));
79 }
80 
GetFilePath() const81 WideString CPDF_Action::GetFilePath() const {
82   Type type = GetType();
83   if (type != Type::kGoToR && type != Type::kGoToE && type != Type::kLaunch &&
84       type != Type::kSubmitForm && type != Type::kImportData) {
85     return WideString();
86   }
87 
88   RetainPtr<const CPDF_Object> pFile =
89       m_pDict->GetDirectObjectFor(pdfium::stream::kF);
90   if (pFile)
91     return CPDF_FileSpec(std::move(pFile)).GetFileName();
92 
93   if (type != Type::kLaunch)
94     return WideString();
95 
96   RetainPtr<const CPDF_Dictionary> pWinDict = m_pDict->GetDictFor("Win");
97   if (!pWinDict)
98     return WideString();
99 
100   return WideString::FromDefANSI(
101       pWinDict->GetByteStringFor(pdfium::stream::kF).AsStringView());
102 }
103 
GetURI(const CPDF_Document * pDoc) const104 ByteString CPDF_Action::GetURI(const CPDF_Document* pDoc) const {
105   if (GetType() != Type::kURI)
106     return ByteString();
107 
108   ByteString csURI = m_pDict->GetByteStringFor("URI");
109   RetainPtr<const CPDF_Dictionary> pURI = pDoc->GetRoot()->GetDictFor("URI");
110   if (pURI) {
111     auto result = csURI.Find(":");
112     if (!result.has_value() || result.value() == 0) {
113       RetainPtr<const CPDF_Object> pBase = pURI->GetDirectObjectFor("Base");
114       if (pBase && (pBase->IsString() || pBase->IsStream()))
115         csURI = pBase->GetString() + csURI;
116     }
117   }
118   return csURI;
119 }
120 
GetHideStatus() const121 bool CPDF_Action::GetHideStatus() const {
122   return m_pDict->GetBooleanFor("H", true);
123 }
124 
GetNamedAction() const125 ByteString CPDF_Action::GetNamedAction() const {
126   return m_pDict->GetByteStringFor("N");
127 }
128 
GetFlags() const129 uint32_t CPDF_Action::GetFlags() const {
130   return m_pDict->GetIntegerFor("Flags");
131 }
132 
HasFields() const133 bool CPDF_Action::HasFields() const {
134   return m_pDict->KeyExist("Fields");
135 }
136 
GetAllFields() const137 std::vector<RetainPtr<const CPDF_Object>> CPDF_Action::GetAllFields() const {
138   std::vector<RetainPtr<const CPDF_Object>> result;
139   if (!m_pDict)
140     return result;
141 
142   ByteString csType = m_pDict->GetByteStringFor("S");
143   RetainPtr<const CPDF_Object> pFields = csType == "Hide"
144                                              ? m_pDict->GetDirectObjectFor("T")
145                                              : m_pDict->GetArrayFor("Fields");
146   if (!pFields)
147     return result;
148 
149   if (pFields->IsDictionary() || pFields->IsString()) {
150     result.push_back(std::move(pFields));
151     return result;
152   }
153 
154   const CPDF_Array* pArray = pFields->AsArray();
155   if (!pArray)
156     return result;
157 
158   for (size_t i = 0; i < pArray->size(); ++i) {
159     RetainPtr<const CPDF_Object> pObj = pArray->GetDirectObjectAt(i);
160     if (pObj)
161       result.push_back(std::move(pObj));
162   }
163   return result;
164 }
165 
MaybeGetJavaScript() const166 std::optional<WideString> CPDF_Action::MaybeGetJavaScript() const {
167   RetainPtr<const CPDF_Object> pObject = GetJavaScriptObject();
168   if (!pObject)
169     return std::nullopt;
170   return pObject->GetUnicodeText();
171 }
172 
GetJavaScript() const173 WideString CPDF_Action::GetJavaScript() const {
174   RetainPtr<const CPDF_Object> pObject = GetJavaScriptObject();
175   return pObject ? pObject->GetUnicodeText() : WideString();
176 }
177 
GetSubActionsCount() const178 size_t CPDF_Action::GetSubActionsCount() const {
179   if (!m_pDict || !m_pDict->KeyExist("Next"))
180     return 0;
181 
182   RetainPtr<const CPDF_Object> pNext = m_pDict->GetDirectObjectFor("Next");
183   if (!pNext)
184     return 0;
185   if (pNext->IsDictionary())
186     return 1;
187   const CPDF_Array* pArray = pNext->AsArray();
188   return pArray ? pArray->size() : 0;
189 }
190 
GetSubAction(size_t iIndex) const191 CPDF_Action CPDF_Action::GetSubAction(size_t iIndex) const {
192   if (!m_pDict || !m_pDict->KeyExist("Next"))
193     return CPDF_Action(nullptr);
194 
195   RetainPtr<const CPDF_Object> pNext = m_pDict->GetDirectObjectFor("Next");
196   if (!pNext)
197     return CPDF_Action(nullptr);
198 
199   if (const CPDF_Array* pArray = pNext->AsArray())
200     return CPDF_Action(pArray->GetDictAt(iIndex));
201 
202   if (const CPDF_Dictionary* pDict = pNext->AsDictionary()) {
203     if (iIndex == 0)
204       return CPDF_Action(pdfium::WrapRetain(pDict));
205   }
206   return CPDF_Action(nullptr);
207 }
208 
GetJavaScriptObject() const209 RetainPtr<const CPDF_Object> CPDF_Action::GetJavaScriptObject() const {
210   if (!m_pDict)
211     return nullptr;
212 
213   RetainPtr<const CPDF_Object> pJS = m_pDict->GetDirectObjectFor("JS");
214   return (pJS && (pJS->IsString() || pJS->IsStream())) ? pJS : nullptr;
215 }
216