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