1// Copyright 2014 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 "../../include/fpdfdoc/fpdf_doc.h"
8CPDF_Dest CPDF_Action::GetDest(CPDF_Document* pDoc) const
9{
10    if (!m_pDict) {
11        return CPDF_Dest();
12    }
13    CFX_ByteString type = m_pDict->GetString("S");
14    if (type != "GoTo" && type != "GoToR") {
15        return CPDF_Dest();
16    }
17    CPDF_Object* pDest = m_pDict->GetElementValue("D");
18    if (!pDest) {
19        return CPDF_Dest();
20    }
21    if (pDest->GetType() == PDFOBJ_STRING || pDest->GetType() == PDFOBJ_NAME) {
22        CPDF_NameTree name_tree(pDoc, FX_BSTRC("Dests"));
23        CFX_ByteStringC name = pDest->GetString();
24        return CPDF_Dest(name_tree.LookupNamedDest(pDoc, name));
25    }
26    if (pDest->GetType() == PDFOBJ_ARRAY) {
27        return CPDF_Dest((CPDF_Array*)pDest);
28    }
29    return CPDF_Dest();
30}
31const FX_CHAR* g_sATypes[] = {"Unknown", "GoTo", "GoToR", "GoToE", "Launch", "Thread", "URI", "Sound", "Movie",
32                              "Hide",	"Named", "SubmitForm", "ResetForm", "ImportData", "JavaScript", "SetOCGState",
33                              "Rendition", "Trans", "GoTo3DView", ""
34                             };
35CPDF_Action::ActionType CPDF_Action::GetType() const
36{
37    ActionType eType = Unknown;
38    if (m_pDict != NULL) {
39        CFX_ByteString csType = m_pDict->GetString("S");
40        if (!csType.IsEmpty()) {
41            int i = 0;
42            while (g_sATypes[i][0] != '\0') {
43                if (csType == g_sATypes[i]) {
44                    return (ActionType)i;
45                }
46                i ++;
47            }
48        }
49    }
50    return eType;
51}
52CFX_WideString CPDF_Action::GetFilePath() const
53{
54    CFX_ByteString type = m_pDict->GetString("S");
55    if (type != "GoToR" && type != "Launch" &&
56            type != "SubmitForm" && type != "ImportData") {
57        return CFX_WideString();
58    }
59    CPDF_Object* pFile = m_pDict->GetElementValue("F");
60    CFX_WideString path;
61    if (pFile == NULL) {
62        if (type == "Launch") {
63            CPDF_Dictionary* pWinDict = m_pDict->GetDict(FX_BSTRC("Win"));
64            if (pWinDict) {
65                return CFX_WideString::FromLocal(pWinDict->GetString(FX_BSTRC("F")));
66            }
67        }
68        return path;
69    }
70    CPDF_FileSpec filespec(pFile);
71    filespec.GetFileName(path);
72    return path;
73}
74CFX_ByteString CPDF_Action::GetURI(CPDF_Document* pDoc) const
75{
76    CFX_ByteString csURI;
77    if (m_pDict == NULL) {
78        return csURI;
79    }
80    if (m_pDict->GetString("S") != "URI") {
81        return csURI;
82    }
83    csURI = m_pDict->GetString("URI");
84    CPDF_Dictionary* pRoot = pDoc->GetRoot();
85    CPDF_Dictionary* pURI = pRoot->GetDict("URI");
86    if (pURI != NULL) {
87        if (csURI.Find(FX_BSTRC(":"), 0) < 1) {
88            csURI = pURI->GetString("Base") + csURI;
89        }
90    }
91    return csURI;
92}
93FX_DWORD CPDF_ActionFields::GetFieldsCount() const
94{
95    if (m_pAction == NULL) {
96        return 0;
97    }
98    CPDF_Dictionary* pDict = m_pAction->GetDict();
99    if (pDict == NULL) {
100        return 0;
101    }
102    CFX_ByteString csType = pDict->GetString("S");
103    CPDF_Object* pFields = NULL;
104    if (csType == "Hide") {
105        pFields = pDict->GetElementValue("T");
106    } else {
107        pFields = pDict->GetArray("Fields");
108    }
109    if (pFields == NULL) {
110        return 0;
111    }
112    int iType = pFields->GetType();
113    if (iType == PDFOBJ_DICTIONARY) {
114        return 1;
115    } else if (iType == PDFOBJ_STRING) {
116        return 1;
117    } else if (iType == PDFOBJ_ARRAY) {
118        return ((CPDF_Array*)pFields)->GetCount();
119    }
120    return 0;
121}
122void CPDF_ActionFields::GetAllFields(CFX_PtrArray& fieldObjects) const
123{
124    fieldObjects.RemoveAll();
125    if (m_pAction == NULL) {
126        return;
127    }
128    CPDF_Dictionary* pDict = m_pAction->GetDict();
129    if (pDict == NULL) {
130        return;
131    }
132    CFX_ByteString csType = pDict->GetString("S");
133    CPDF_Object* pFields = NULL;
134    if (csType == "Hide") {
135        pFields = pDict->GetElementValue("T");
136    } else {
137        pFields = pDict->GetArray("Fields");
138    }
139    if (pFields == NULL) {
140        return;
141    }
142    int iType = pFields->GetType();
143    if (iType == PDFOBJ_DICTIONARY || iType == PDFOBJ_STRING) {
144        fieldObjects.Add(pFields);
145    } else if (iType == PDFOBJ_ARRAY) {
146        CPDF_Array* pArray = (CPDF_Array*)pFields;
147        FX_DWORD iCount = pArray->GetCount();
148        for (FX_DWORD i = 0; i < iCount; i ++) {
149            CPDF_Object* pObj = pArray->GetElementValue(i);
150            if (pObj != NULL) {
151                fieldObjects.Add(pObj);
152            }
153        }
154    }
155}
156CPDF_Object* CPDF_ActionFields::GetField(FX_DWORD iIndex) const
157{
158    if (m_pAction == NULL) {
159        return NULL;
160    }
161    CPDF_Dictionary* pDict = m_pAction->GetDict();
162    if (pDict == NULL) {
163        return NULL;
164    }
165    CFX_ByteString csType = pDict->GetString("S");
166    CPDF_Object* pFields = NULL;
167    if (csType == "Hide") {
168        pFields = pDict->GetElementValue("T");
169    } else {
170        pFields = pDict->GetArray("Fields");
171    }
172    if (pFields == NULL) {
173        return NULL;
174    }
175    CPDF_Object* pFindObj = NULL;
176    int iType = pFields->GetType();
177    if (iType == PDFOBJ_DICTIONARY || iType == PDFOBJ_STRING) {
178        if (iIndex == 0) {
179            pFindObj = pFields;
180        }
181    } else if (iType == PDFOBJ_ARRAY) {
182        pFindObj = ((CPDF_Array*)pFields)->GetElementValue(iIndex);
183    }
184    return pFindObj;
185}
186CPDF_LWinParam CPDF_Action::GetWinParam() const
187{
188    if (m_pDict == NULL) {
189        return NULL;
190    }
191    if (m_pDict->GetString("S") != "Launch") {
192        return NULL;
193    }
194    return m_pDict->GetDict("Win");
195}
196CFX_WideString CPDF_Action::GetJavaScript() const
197{
198    CFX_WideString csJS;
199    if (m_pDict == NULL) {
200        return csJS;
201    }
202    CPDF_Object* pJS = m_pDict->GetElementValue("JS");
203    if (pJS != NULL) {
204        return pJS->GetUnicodeText();
205    }
206    return csJS;
207}
208CPDF_Dictionary* CPDF_Action::GetAnnot() const
209{
210    if (m_pDict == NULL) {
211        return NULL;
212    }
213    CFX_ByteString csType = m_pDict->GetString("S");
214    if (csType == FX_BSTRC("Rendition")) {
215        return m_pDict->GetDict("AN");
216    } else if (csType == FX_BSTRC("Movie")) {
217        return m_pDict->GetDict("Annotation");
218    }
219    return NULL;
220}
221FX_INT32 CPDF_Action::GetOperationType() const
222{
223    if (m_pDict == NULL) {
224        return 0;
225    }
226    CFX_ByteString csType = m_pDict->GetString("S");
227    if (csType == FX_BSTRC("Rendition")) {
228        return m_pDict->GetInteger("OP");
229    } else if (csType == FX_BSTRC("Movie")) {
230        CFX_ByteString csOP = m_pDict->GetString("Operation");
231        if (csOP == FX_BSTRC("Play")) {
232            return 0;
233        } else if (csOP == FX_BSTRC("Stop")) {
234            return 1;
235        } else if (csOP == FX_BSTRC("Pause")) {
236            return 2;
237        } else if (csOP == FX_BSTRC("Resume")) {
238            return 3;
239        }
240    }
241    return 0;
242}
243FX_DWORD CPDF_Action::GetSubActionsCount() const
244{
245    if (m_pDict == NULL || !m_pDict->KeyExist("Next")) {
246        return 0;
247    }
248    CPDF_Object* pNext = m_pDict->GetElementValue("Next");
249    if (!pNext) {
250        return 0;
251    }
252    int iObjType = pNext->GetType();
253    if (iObjType == PDFOBJ_DICTIONARY) {
254        return 1;
255    }
256    if (iObjType == PDFOBJ_ARRAY) {
257        return ((CPDF_Array*)pNext)->GetCount();
258    }
259    return 0;
260}
261CPDF_Action CPDF_Action::GetSubAction(FX_DWORD iIndex) const
262{
263    if (m_pDict == NULL || !m_pDict->KeyExist("Next")) {
264        return CPDF_Action();
265    }
266    CPDF_Object* pNext = m_pDict->GetElementValue("Next");
267    int iObjType = pNext->GetType();
268    if (iObjType == PDFOBJ_DICTIONARY) {
269        CPDF_Dictionary *pDict = static_cast<CPDF_Dictionary*>(pNext);
270        if (iIndex == 0) {
271            return CPDF_Action(pDict);
272        }
273    } else if (iObjType == PDFOBJ_ARRAY) {
274        CPDF_Array* pArray = static_cast<CPDF_Array*>(pNext);
275        return CPDF_Action(pArray->GetDict(iIndex));
276    }
277    return CPDF_Action();
278}
279const FX_CHAR* g_sAATypes[] = {"E", "X", "D", "U", "Fo", "Bl", "PO", "PC", "PV", "PI",
280                               "O", "C",
281                               "K", "F", "V", "C",
282                               "WC", "WS", "DS", "WP", "DP",
283                               ""
284                              };
285FX_BOOL CPDF_AAction::ActionExist(AActionType eType) const
286{
287    if (m_pDict == NULL) {
288        return FALSE;
289    }
290    return m_pDict->KeyExist(g_sAATypes[(int)eType]);
291}
292CPDF_Action CPDF_AAction::GetAction(AActionType eType) const
293{
294    if (!m_pDict) {
295        return CPDF_Action();
296    }
297    return CPDF_Action(m_pDict->GetDict(g_sAATypes[(int)eType]));
298}
299FX_POSITION CPDF_AAction::GetStartPos() const
300{
301    if (m_pDict == NULL) {
302        return NULL;
303    }
304    return m_pDict->GetStartPos();
305}
306CPDF_Action CPDF_AAction::GetNextAction(FX_POSITION& pos, AActionType& eType) const
307{
308    if (m_pDict == NULL) {
309        return CPDF_Action();
310    }
311    CFX_ByteString csKey;
312    CPDF_Object* pObj = m_pDict->GetNextElement(pos, csKey);
313    if (!pObj) {
314        return CPDF_Action();
315    }
316    CPDF_Object* pDirect = pObj->GetDirect();
317    if (!pDirect || pDirect->GetType() != PDFOBJ_DICTIONARY) {
318        return CPDF_Action();
319    }
320    int i = 0;
321    while (g_sAATypes[i][0] != '\0') {
322        if (csKey == g_sAATypes[i]) {
323            break;
324        }
325        i++;
326    }
327    eType = (AActionType)i;
328    return CPDF_Action(static_cast<CPDF_Dictionary*>(pDirect));
329}
330CPDF_DocJSActions::CPDF_DocJSActions(CPDF_Document* pDoc)
331{
332    m_pDocument = pDoc;
333}
334int CPDF_DocJSActions::CountJSActions() const
335{
336    ASSERT(m_pDocument != NULL);
337    CPDF_NameTree name_tree(m_pDocument, FX_BSTRC("JavaScript"));
338    return name_tree.GetCount();
339}
340CPDF_Action CPDF_DocJSActions::GetJSAction(int index, CFX_ByteString& csName) const
341{
342    ASSERT(m_pDocument != NULL);
343    CPDF_NameTree name_tree(m_pDocument, FX_BSTRC("JavaScript"));
344    CPDF_Object *pAction = name_tree.LookupValue(index, csName);
345    if (pAction == NULL || pAction->GetType() != PDFOBJ_DICTIONARY) {
346        return CPDF_Action();
347    }
348    return CPDF_Action(pAction->GetDict());
349}
350CPDF_Action CPDF_DocJSActions::GetJSAction(const CFX_ByteString& csName) const
351{
352    ASSERT(m_pDocument != NULL);
353    CPDF_NameTree name_tree(m_pDocument, FX_BSTRC("JavaScript"));
354    CPDF_Object *pAction = name_tree.LookupValue(csName);
355    if (pAction == NULL || pAction->GetType() != PDFOBJ_DICTIONARY) {
356        return CPDF_Action();
357    }
358    return CPDF_Action(pAction->GetDict());
359}
360int CPDF_DocJSActions::FindJSAction(const CFX_ByteString& csName) const
361{
362    ASSERT(m_pDocument != NULL);
363    CPDF_NameTree name_tree(m_pDocument, FX_BSTRC("JavaScript"));
364    return name_tree.GetIndex(csName);
365}
366