Fix a NULL dereference introduced from https://pdfium.googlesource.com/pdfium/+/5d9ac...
[pdfium.git] / fpdfsdk / src / fpdfdoc.cpp
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/fsdk_define.h"
8 #include "../include/fpdfdoc.h"
9 #include "../include/fpdfxfa/fpdfxfa_doc.h"
10 #include "../include/fpdfxfa/fpdfxfa_page.h"
11
12 static int THISMODULE = 0;
13
14 static CPDF_Bookmark FindBookmark(const CPDF_BookmarkTree& tree, CPDF_Bookmark bookmark, const CFX_WideString& title)
15 {
16         if (bookmark && bookmark.GetTitle().CompareNoCase(title) == 0) {
17                 // First check this item
18                 return bookmark;
19         }
20         // go into children items
21         CPDF_Bookmark child = tree.GetFirstChild(bookmark);
22         while (child) {
23                 // check if this item
24                 CPDF_Bookmark found = FindBookmark(tree, child, title);
25                 if (found)
26                         return found;
27                 child = tree.GetNextSibling(child);
28         }
29         return CPDF_Bookmark();
30 }
31
32 DLLEXPORT FPDF_BOOKMARK STDCALL FPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title)
33 {
34         if (!document)
35                 return NULL;
36         if (!title || title[0] == 0)
37                 return NULL;
38         CPDF_Document* pDoc = ((CPDFXFA_Document*)document)->GetPDFDoc();
39         CPDF_BookmarkTree tree(pDoc);
40         FX_STRSIZE len = CFX_WideString::WStringLength(title);
41         CFX_WideString encodedTitle = CFX_WideString::FromUTF16LE(title, len);
42         return FindBookmark(tree, CPDF_Bookmark(), encodedTitle).GetDict();
43 }
44
45 DLLEXPORT FPDF_DEST STDCALL FPDFBookmark_GetDest(FPDF_DOCUMENT document, FPDF_BOOKMARK pDict)
46 {
47         if (!document)
48                 return NULL;
49         if (!pDict)
50                 return NULL;
51         CPDF_Bookmark bookmark((CPDF_Dictionary*)pDict);
52         CPDF_Document* pDoc = ((CPDFXFA_Document*)document)->GetPDFDoc();
53         CPDF_Dest dest = bookmark.GetDest(pDoc);
54         if (dest)
55                 return dest;
56         // If this bookmark is not directly associated with a dest, we try to get action
57         CPDF_Action action = bookmark.GetAction();
58         if (!action)
59                 return NULL;
60         return action.GetDest(pDoc);
61 }
62
63 DLLEXPORT FPDF_ACTION STDCALL FPDFBookmark_GetAction(FPDF_BOOKMARK pDict)
64 {
65         if (!pDict)
66                 return NULL;
67         CPDF_Bookmark bookmark((CPDF_Dictionary*)pDict);
68         return bookmark.GetAction();
69 }
70
71 DLLEXPORT unsigned long STDCALL FPDFAction_GetType(FPDF_ACTION pDict)
72 {
73         if (!pDict)
74                 return 0;
75         CPDF_Action action = (CPDF_Dictionary*)pDict;
76         CPDF_Action::ActionType type = action.GetType();
77         switch (type) {
78                 case CPDF_Action::GoTo:
79                         return PDFACTION_GOTO;
80                 case CPDF_Action::GoToR:
81                         return PDFACTION_REMOTEGOTO;
82                 case CPDF_Action::URI:
83                         return PDFACTION_URI;
84                 case CPDF_Action::Launch:
85                         return PDFACTION_LAUNCH;
86                 default:
87                         return PDFACTION_UNSUPPORTED;
88         }
89         return PDFACTION_UNSUPPORTED;
90 }
91
92 DLLEXPORT FPDF_DEST STDCALL FPDFAction_GetDest(FPDF_DOCUMENT document, FPDF_ACTION pDict)
93 {
94         if (!document)
95                 return NULL;
96         if (!pDict)
97                 return NULL;
98         CPDF_Document* pDoc = ((CPDFXFA_Document*)document)->GetPDFDoc();
99         CPDF_Action action = (CPDF_Dictionary*)pDict;
100         return action.GetDest(pDoc);
101 }
102
103 DLLEXPORT unsigned long STDCALL FPDFAction_GetURIPath(FPDF_DOCUMENT document, FPDF_ACTION pDict,
104                                                                                           void* buffer, unsigned long buflen)
105 {
106         if (!document)
107                 return 0;
108         if (!pDict)
109                 return 0;
110         CPDF_Document* pDoc = ((CPDFXFA_Document*)document)->GetPDFDoc();
111         CPDF_Action action = (CPDF_Dictionary*)pDict;
112         CFX_ByteString path = action.GetURI(pDoc);
113         unsigned long len = path.GetLength() + 1;
114         if (buffer != NULL && buflen >= len)
115                 FXSYS_memcpy(buffer, path.c_str(), len);
116         return len;
117 }
118
119 DLLEXPORT unsigned long STDCALL FPDFDest_GetPageIndex(FPDF_DOCUMENT document, FPDF_DEST pDict)
120 {
121         if (!document)
122                 return 0;
123         if (!pDict)
124                 return 0;
125         CPDF_Document* pDoc = ((CPDFXFA_Document*)document)->GetPDFDoc();
126         CPDF_Dest dest = (CPDF_Array*)pDict;
127         return dest.GetPageIndex(pDoc);
128 }
129
130 static void ReleaseLinkList(FX_LPVOID data)
131 {
132         delete (CPDF_LinkList*)data;
133 }
134
135 DLLEXPORT FPDF_LINK STDCALL FPDFLink_GetLinkAtPoint(FPDF_PAGE page, double x, double y)
136 {
137         if (!page)
138                 return NULL;
139     CPDF_Page* pPage = ((CPDFXFA_Page*)page)->GetPDFPage();
140         if (!pPage)
141                 return NULL;
142         // Link list is stored with the document
143         CPDF_Document* pDoc = pPage->m_pDocument;
144         CPDF_LinkList* pLinkList = (CPDF_LinkList*)pDoc->GetPrivateData(&THISMODULE);
145         if (!pLinkList) {
146                 pLinkList = FX_NEW CPDF_LinkList(pDoc);
147                 pDoc->SetPrivateData(&THISMODULE, pLinkList, ReleaseLinkList);
148         }
149         return pLinkList->GetLinkAtPoint(pPage, (FX_FLOAT)x, (FX_FLOAT)y);
150 }
151
152 DLLEXPORT FPDF_DEST STDCALL FPDFLink_GetDest(FPDF_DOCUMENT document, FPDF_LINK pDict)
153 {
154         if (!document)
155                 return NULL;
156     CPDF_Document* pDoc = ((CPDFXFA_Document*)document)->GetPDFDoc();
157         if (!pDict)
158                 return NULL;
159         CPDF_Link link = (CPDF_Dictionary*)pDict;
160
161         FPDF_DEST dest = link.GetDest(pDoc);
162         if (dest)
163                 return dest;
164         // If this link is not directly associated with a dest, we try to get action
165         CPDF_Action action = link.GetAction();
166         if (!action)
167                 return NULL;
168         return action.GetDest(pDoc);
169 }
170
171 DLLEXPORT FPDF_ACTION STDCALL FPDFLink_GetAction(FPDF_LINK pDict)
172 {
173         if (!pDict)
174                 return NULL;
175         CPDF_Link link = (CPDF_Dictionary*)pDict;
176         return link.GetAction();
177 }
178
179 DLLEXPORT FPDF_BOOL STDCALL FPDFLink_Enumerate(FPDF_PAGE page, int* startPos, FPDF_LINK* linkAnnot)
180 {
181         if(!page || !startPos || !linkAnnot)
182                 return FALSE;
183     CPDF_Page* pPage = ((CPDFXFA_Page*)page)->GetPDFPage();
184         if(!pPage->m_pFormDict)
185                 return FALSE;
186         CPDF_Array* pAnnots = pPage->m_pFormDict->GetArray("Annots");
187         if(!pAnnots)
188                 return FALSE;
189         for (int i = *startPos; i < (int)pAnnots->GetCount(); i++) {
190                 CPDF_Dictionary* pDict = (CPDF_Dictionary*)pAnnots->GetElementValue(i);
191                 if (!pDict || pDict->GetType() != PDFOBJ_DICTIONARY)
192                         continue;
193                 if(pDict->GetString(FX_BSTRC("Subtype")).Equal(FX_BSTRC("Link"))) {
194                         *startPos = i + 1;
195                         *linkAnnot = (FPDF_LINK)pDict; 
196                         return TRUE;
197                 }
198         }
199         return FALSE;
200 }
201
202 DLLEXPORT FPDF_BOOL STDCALL FPDFLink_GetAnnotRect(FPDF_LINK linkAnnot, FS_RECTF* rect)
203 {
204         if(!linkAnnot || !rect)
205                 return FALSE;
206         CPDF_Dictionary* pAnnotDict = (CPDF_Dictionary*)linkAnnot;
207         CPDF_Rect rt = pAnnotDict->GetRect(FX_BSTRC("Rect"));
208         rect->left = rt.left;
209         rect->bottom = rt.bottom;
210         rect->right = rt.right;
211         rect->top = rt.top;
212         return TRUE;
213 }
214
215 DLLEXPORT int STDCALL FPDFLink_CountQuadPoints(FPDF_LINK linkAnnot)
216 {
217         if(!linkAnnot)
218                 return 0;
219         CPDF_Dictionary* pAnnotDict = (CPDF_Dictionary*)linkAnnot;
220         CPDF_Array* pArray = pAnnotDict->GetArray(FX_BSTRC("QuadPoints"));
221         if (!pArray)
222                 return 0;
223         else
224                 return pArray->GetCount() / 8;
225 }
226
227 DLLEXPORT FPDF_BOOL STDCALL FPDFLink_GetQuadPoints(FPDF_LINK linkAnnot, int quadIndex, FS_QUADPOINTSF* quadPoints)
228 {
229         if(!linkAnnot || !quadPoints)
230                 return FALSE;
231         CPDF_Dictionary* pAnnotDict = (CPDF_Dictionary*)linkAnnot;
232         CPDF_Array* pArray = pAnnotDict->GetArray(FX_BSTRC("QuadPoints"));
233         if (pArray) {
234                 if (quadIndex < 0 || quadIndex >= (int)pArray->GetCount()/8 || ((quadIndex*8+7) >= (int)pArray->GetCount()))
235                         return FALSE;
236                 quadPoints->x1 = pArray->GetNumber(quadIndex*8);
237                 quadPoints->y1 = pArray->GetNumber(quadIndex*8+1);
238                 quadPoints->x2 = pArray->GetNumber(quadIndex*8+2);
239                 quadPoints->y2 = pArray->GetNumber(quadIndex*8+3);
240                 quadPoints->x3 = pArray->GetNumber(quadIndex*8+4);
241                 quadPoints->y3 = pArray->GetNumber(quadIndex*8+5);
242                 quadPoints->x4 = pArray->GetNumber(quadIndex*8+6);
243                 quadPoints->y4 = pArray->GetNumber(quadIndex*8+7);
244                 return TRUE;
245         } 
246         return FALSE;
247 }
248
249 DLLEXPORT unsigned long STDCALL FPDF_GetMetaText(FPDF_DOCUMENT doc, FPDF_BYTESTRING tag,
250                                                                                                  void* buffer, unsigned long buflen)
251 {
252         if (!doc || !tag)
253                 return 0;
254     CPDF_Document* pDoc = ((CPDFXFA_Document*)doc)->GetPDFDoc();
255         // Get info dictionary
256         CPDF_Dictionary* pInfo = pDoc->GetInfo();
257         if (!pInfo)
258                 return 0;
259         CFX_WideString text = pInfo->GetUnicodeText(tag);
260         // Use UTF-16LE encoding
261         CFX_ByteString encodedText = text.UTF16LE_Encode();
262         unsigned long len = encodedText.GetLength();
263         if (buffer && buflen >= len + 2) {
264                 FXSYS_memcpy(buffer, encodedText.c_str(), len);
265                 // use double zero as trailer
266                 ((FX_BYTE*)buffer)[len] = 0;
267                 ((FX_BYTE*)buffer)[len + 1] = 0;
268         }
269         return len+2;
270 }