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