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