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 FX_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 
GetDest(CPDF_Document * pDoc) const24 CPDF_Dest CPDF_Action::GetDest(CPDF_Document* pDoc) const {
25   if (!m_pDict)
26     return CPDF_Dest();
27 
28   CFX_ByteString type = m_pDict->GetStringFor("S");
29   if (type != "GoTo" && type != "GoToR")
30     return CPDF_Dest();
31 
32   CPDF_Object* pDest = m_pDict->GetDirectObjectFor("D");
33   if (!pDest)
34     return CPDF_Dest();
35   if (pDest->IsString() || pDest->IsName()) {
36     CPDF_NameTree name_tree(pDoc, "Dests");
37     return CPDF_Dest(name_tree.LookupNamedDest(pDoc, pDest->GetString()));
38   }
39   if (CPDF_Array* pArray = pDest->AsArray())
40     return CPDF_Dest(pArray);
41 
42   return CPDF_Dest();
43 }
44 
GetType() const45 CPDF_Action::ActionType CPDF_Action::GetType() const {
46   if (!m_pDict)
47     return Unknown;
48 
49   CFX_ByteString csType = m_pDict->GetStringFor("S");
50   if (csType.IsEmpty())
51     return Unknown;
52 
53   for (int i = 0; g_sATypes[i]; ++i) {
54     if (csType == g_sATypes[i])
55       return static_cast<ActionType>(i);
56   }
57   return Unknown;
58 }
59 
GetFilePath() const60 CFX_WideString CPDF_Action::GetFilePath() const {
61   CFX_ByteString type = m_pDict->GetStringFor("S");
62   if (type != "GoToR" && type != "Launch" && type != "SubmitForm" &&
63       type != "ImportData") {
64     return CFX_WideString();
65   }
66 
67   CPDF_Object* pFile = m_pDict->GetDirectObjectFor("F");
68   CFX_WideString path;
69   if (!pFile) {
70     if (type == "Launch") {
71       CPDF_Dictionary* pWinDict = m_pDict->GetDictFor("Win");
72       if (pWinDict) {
73         return CFX_WideString::FromLocal(
74             pWinDict->GetStringFor("F").AsStringC());
75       }
76     }
77     return path;
78   }
79 
80   CPDF_FileSpec filespec(pFile);
81   filespec.GetFileName(&path);
82   return path;
83 }
84 
GetURI(CPDF_Document * pDoc) const85 CFX_ByteString CPDF_Action::GetURI(CPDF_Document* pDoc) const {
86   CFX_ByteString csURI;
87   if (!m_pDict)
88     return csURI;
89   if (m_pDict->GetStringFor("S") != "URI")
90     return csURI;
91 
92   csURI = m_pDict->GetStringFor("URI");
93   CPDF_Dictionary* pRoot = pDoc->GetRoot();
94   CPDF_Dictionary* pURI = pRoot->GetDictFor("URI");
95   if (pURI) {
96     if (csURI.Find(":", 0) < 1)
97       csURI = pURI->GetStringFor("Base") + csURI;
98   }
99   return csURI;
100 }
101 
GetJavaScript() const102 CFX_WideString CPDF_Action::GetJavaScript() const {
103   CFX_WideString csJS;
104   if (!m_pDict)
105     return csJS;
106 
107   CPDF_Object* pJS = m_pDict->GetDirectObjectFor("JS");
108   return pJS ? pJS->GetUnicodeText() : csJS;
109 }
110 
GetSubActionsCount() const111 size_t CPDF_Action::GetSubActionsCount() const {
112   if (!m_pDict || !m_pDict->KeyExist("Next"))
113     return 0;
114 
115   CPDF_Object* pNext = m_pDict->GetDirectObjectFor("Next");
116   if (!pNext)
117     return 0;
118   if (pNext->IsDictionary())
119     return 1;
120   if (CPDF_Array* pArray = pNext->AsArray())
121     return pArray->GetCount();
122   return 0;
123 }
124 
GetSubAction(size_t iIndex) const125 CPDF_Action CPDF_Action::GetSubAction(size_t iIndex) const {
126   if (!m_pDict || !m_pDict->KeyExist("Next"))
127     return CPDF_Action();
128 
129   CPDF_Object* pNext = m_pDict->GetDirectObjectFor("Next");
130   if (CPDF_Dictionary* pDict = ToDictionary(pNext)) {
131     if (iIndex == 0)
132       return CPDF_Action(pDict);
133   } else if (CPDF_Array* pArray = ToArray(pNext)) {
134     return CPDF_Action(pArray->GetDictAt(iIndex));
135   }
136   return CPDF_Action();
137 }
138