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 "public/fpdf_doc.h" 8 9 #include "fpdfsdk/include/fsdk_define.h" 10 11 namespace { 12 13 int THISMODULE = 0; 14 15 CPDF_Bookmark FindBookmark(const CPDF_BookmarkTree& tree, 16 CPDF_Bookmark bookmark, 17 const CFX_WideString& title) { 18 if (bookmark && bookmark.GetTitle().CompareNoCase(title.c_str()) == 0) { 19 // First check this item 20 return bookmark; 21 } 22 // go into children items 23 CPDF_Bookmark child = tree.GetFirstChild(bookmark); 24 while (child) { 25 // check if this item 26 CPDF_Bookmark found = FindBookmark(tree, child, title); 27 if (found) 28 return found; 29 child = tree.GetNextSibling(child); 30 } 31 return CPDF_Bookmark(); 32 } 33 34 void ReleaseLinkList(void* data) { 35 delete (CPDF_LinkList*)data; 36 } 37 38 CPDF_LinkList* GetLinkList(CPDF_Page* page) { 39 if (!page) 40 return nullptr; 41 42 // Link list is stored with the document 43 CPDF_Document* pDoc = page->m_pDocument; 44 CPDF_LinkList* pLinkList = (CPDF_LinkList*)pDoc->GetPrivateData(&THISMODULE); 45 if (!pLinkList) { 46 pLinkList = new CPDF_LinkList; 47 pDoc->SetPrivateData(&THISMODULE, pLinkList, ReleaseLinkList); 48 } 49 return pLinkList; 50 } 51 52 } // namespace 53 54 DLLEXPORT FPDF_BOOKMARK STDCALL 55 FPDFBookmark_GetFirstChild(FPDF_DOCUMENT document, FPDF_BOOKMARK pDict) { 56 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 57 if (!pDoc) 58 return nullptr; 59 CPDF_BookmarkTree tree(pDoc); 60 CPDF_Bookmark bookmark = 61 CPDF_Bookmark(ToDictionary(static_cast<CPDF_Object*>(pDict))); 62 return tree.GetFirstChild(bookmark).GetDict(); 63 } 64 65 DLLEXPORT FPDF_BOOKMARK STDCALL 66 FPDFBookmark_GetNextSibling(FPDF_DOCUMENT document, FPDF_BOOKMARK pDict) { 67 if (!pDict) 68 return nullptr; 69 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 70 if (!pDoc) 71 return nullptr; 72 CPDF_BookmarkTree tree(pDoc); 73 CPDF_Bookmark bookmark = 74 CPDF_Bookmark(ToDictionary(static_cast<CPDF_Object*>(pDict))); 75 return tree.GetNextSibling(bookmark).GetDict(); 76 } 77 78 DLLEXPORT unsigned long STDCALL FPDFBookmark_GetTitle(FPDF_BOOKMARK pDict, 79 void* buffer, 80 unsigned long buflen) { 81 if (!pDict) 82 return 0; 83 CPDF_Bookmark bookmark(ToDictionary(static_cast<CPDF_Object*>(pDict))); 84 CFX_WideString title = bookmark.GetTitle(); 85 CFX_ByteString encodedTitle = title.UTF16LE_Encode(); 86 unsigned long len = encodedTitle.GetLength(); 87 if (buffer && buflen >= len) { 88 FXSYS_memcpy(buffer, encodedTitle.c_str(), len); 89 } 90 return len; 91 } 92 93 DLLEXPORT FPDF_BOOKMARK STDCALL FPDFBookmark_Find(FPDF_DOCUMENT document, 94 FPDF_WIDESTRING title) { 95 if (!title || title[0] == 0) 96 return nullptr; 97 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 98 if (!pDoc) 99 return nullptr; 100 CPDF_BookmarkTree tree(pDoc); 101 FX_STRSIZE len = CFX_WideString::WStringLength(title); 102 CFX_WideString encodedTitle = CFX_WideString::FromUTF16LE(title, len); 103 return FindBookmark(tree, CPDF_Bookmark(), encodedTitle).GetDict(); 104 } 105 106 DLLEXPORT FPDF_DEST STDCALL FPDFBookmark_GetDest(FPDF_DOCUMENT document, 107 FPDF_BOOKMARK pDict) { 108 if (!pDict) 109 return nullptr; 110 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 111 if (!pDoc) 112 return nullptr; 113 CPDF_Bookmark bookmark(ToDictionary(static_cast<CPDF_Object*>(pDict))); 114 CPDF_Dest dest = bookmark.GetDest(pDoc); 115 if (dest) 116 return dest.GetObject(); 117 // If this bookmark is not directly associated with a dest, we try to get 118 // action 119 CPDF_Action action = bookmark.GetAction(); 120 if (!action) 121 return nullptr; 122 return action.GetDest(pDoc).GetObject(); 123 } 124 125 DLLEXPORT FPDF_ACTION STDCALL FPDFBookmark_GetAction(FPDF_BOOKMARK pDict) { 126 if (!pDict) 127 return NULL; 128 CPDF_Bookmark bookmark(ToDictionary(static_cast<CPDF_Object*>(pDict))); 129 return bookmark.GetAction().GetDict(); 130 } 131 132 DLLEXPORT unsigned long STDCALL FPDFAction_GetType(FPDF_ACTION pDict) { 133 if (!pDict) 134 return PDFACTION_UNSUPPORTED; 135 136 CPDF_Action action(ToDictionary(static_cast<CPDF_Object*>(pDict))); 137 CPDF_Action::ActionType type = action.GetType(); 138 switch (type) { 139 case CPDF_Action::GoTo: 140 return PDFACTION_GOTO; 141 case CPDF_Action::GoToR: 142 return PDFACTION_REMOTEGOTO; 143 case CPDF_Action::URI: 144 return PDFACTION_URI; 145 case CPDF_Action::Launch: 146 return PDFACTION_LAUNCH; 147 default: 148 return PDFACTION_UNSUPPORTED; 149 } 150 } 151 152 DLLEXPORT FPDF_DEST STDCALL FPDFAction_GetDest(FPDF_DOCUMENT document, 153 FPDF_ACTION pDict) { 154 if (!pDict) 155 return nullptr; 156 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 157 if (!pDoc) 158 return nullptr; 159 CPDF_Action action(ToDictionary(static_cast<CPDF_Object*>(pDict))); 160 return action.GetDest(pDoc).GetObject(); 161 } 162 163 DLLEXPORT unsigned long STDCALL 164 FPDFAction_GetFilePath(FPDF_ACTION pDict, void* buffer, unsigned long buflen) { 165 unsigned long type = FPDFAction_GetType(pDict); 166 if (type != PDFACTION_REMOTEGOTO && type != PDFACTION_LAUNCH) 167 return 0; 168 169 CPDF_Action action(ToDictionary(static_cast<CPDF_Object*>(pDict))); 170 CFX_ByteString path = action.GetFilePath().UTF8Encode(); 171 unsigned long len = path.GetLength() + 1; 172 if (buffer && buflen >= len) 173 FXSYS_memcpy(buffer, path.c_str(), len); 174 return len; 175 } 176 177 DLLEXPORT unsigned long STDCALL FPDFAction_GetURIPath(FPDF_DOCUMENT document, 178 FPDF_ACTION pDict, 179 void* buffer, 180 unsigned long buflen) { 181 if (!pDict) 182 return 0; 183 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 184 if (!pDoc) 185 return 0; 186 CPDF_Action action(ToDictionary(static_cast<CPDF_Object*>(pDict))); 187 CFX_ByteString path = action.GetURI(pDoc); 188 unsigned long len = path.GetLength() + 1; 189 if (buffer && buflen >= len) 190 FXSYS_memcpy(buffer, path.c_str(), len); 191 return len; 192 } 193 194 DLLEXPORT unsigned long STDCALL FPDFDest_GetPageIndex(FPDF_DOCUMENT document, 195 FPDF_DEST pDict) { 196 if (!pDict) 197 return 0; 198 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 199 if (!pDoc) 200 return 0; 201 CPDF_Dest dest(static_cast<CPDF_Array*>(pDict)); 202 return dest.GetPageIndex(pDoc); 203 } 204 205 DLLEXPORT FPDF_LINK STDCALL 206 FPDFLink_GetLinkAtPoint(FPDF_PAGE page, double x, double y) { 207 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 208 if (!pPage) 209 return nullptr; 210 211 CPDF_LinkList* pLinkList = GetLinkList(pPage); 212 if (!pLinkList) 213 return nullptr; 214 215 return pLinkList->GetLinkAtPoint(pPage, (FX_FLOAT)x, (FX_FLOAT)y, nullptr) 216 .GetDict(); 217 } 218 219 DLLEXPORT int STDCALL 220 FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page, double x, double y) { 221 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 222 if (!pPage) 223 return -1; 224 225 CPDF_LinkList* pLinkList = GetLinkList(pPage); 226 if (!pLinkList) 227 return -1; 228 229 int z_order = -1; 230 pLinkList->GetLinkAtPoint(pPage, (FX_FLOAT)x, (FX_FLOAT)y, &z_order); 231 return z_order; 232 } 233 234 DLLEXPORT FPDF_DEST STDCALL FPDFLink_GetDest(FPDF_DOCUMENT document, 235 FPDF_LINK pDict) { 236 if (!pDict) 237 return nullptr; 238 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 239 if (!pDoc) 240 return nullptr; 241 CPDF_Link link(ToDictionary(static_cast<CPDF_Object*>(pDict))); 242 FPDF_DEST dest = link.GetDest(pDoc).GetObject(); 243 if (dest) 244 return dest; 245 // If this link is not directly associated with a dest, we try to get action 246 CPDF_Action action = link.GetAction(); 247 if (!action) 248 return nullptr; 249 return action.GetDest(pDoc).GetObject(); 250 } 251 252 DLLEXPORT FPDF_ACTION STDCALL FPDFLink_GetAction(FPDF_LINK pDict) { 253 if (!pDict) 254 return nullptr; 255 256 CPDF_Link link(ToDictionary(static_cast<CPDF_Object*>(pDict))); 257 return link.GetAction().GetDict(); 258 } 259 260 DLLEXPORT FPDF_BOOL STDCALL FPDFLink_Enumerate(FPDF_PAGE page, 261 int* startPos, 262 FPDF_LINK* linkAnnot) { 263 if (!startPos || !linkAnnot) 264 return FALSE; 265 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 266 if (!pPage || !pPage->m_pFormDict) 267 return FALSE; 268 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArray("Annots"); 269 if (!pAnnots) 270 return FALSE; 271 for (int i = *startPos; i < (int)pAnnots->GetCount(); i++) { 272 CPDF_Dictionary* pDict = 273 ToDictionary(static_cast<CPDF_Object*>(pAnnots->GetElementValue(i))); 274 if (!pDict) 275 continue; 276 if (pDict->GetString("Subtype").Equal("Link")) { 277 *startPos = i + 1; 278 *linkAnnot = (FPDF_LINK)pDict; 279 return TRUE; 280 } 281 } 282 return FALSE; 283 } 284 285 DLLEXPORT FPDF_BOOL STDCALL FPDFLink_GetAnnotRect(FPDF_LINK linkAnnot, 286 FS_RECTF* rect) { 287 if (!linkAnnot || !rect) 288 return FALSE; 289 CPDF_Dictionary* pAnnotDict = 290 ToDictionary(static_cast<CPDF_Object*>(linkAnnot)); 291 CPDF_Rect rt = pAnnotDict->GetRect("Rect"); 292 rect->left = rt.left; 293 rect->bottom = rt.bottom; 294 rect->right = rt.right; 295 rect->top = rt.top; 296 return TRUE; 297 } 298 299 DLLEXPORT int STDCALL FPDFLink_CountQuadPoints(FPDF_LINK linkAnnot) { 300 if (!linkAnnot) 301 return 0; 302 CPDF_Dictionary* pAnnotDict = 303 ToDictionary(static_cast<CPDF_Object*>(linkAnnot)); 304 CPDF_Array* pArray = pAnnotDict->GetArray("QuadPoints"); 305 if (!pArray) 306 return 0; 307 return pArray->GetCount() / 8; 308 } 309 310 DLLEXPORT FPDF_BOOL STDCALL FPDFLink_GetQuadPoints(FPDF_LINK linkAnnot, 311 int quadIndex, 312 FS_QUADPOINTSF* quadPoints) { 313 if (!linkAnnot || !quadPoints) 314 return FALSE; 315 CPDF_Dictionary* pAnnotDict = 316 ToDictionary(static_cast<CPDF_Object*>(linkAnnot)); 317 CPDF_Array* pArray = pAnnotDict->GetArray("QuadPoints"); 318 if (pArray) { 319 if (quadIndex < 0 || quadIndex >= (int)pArray->GetCount() / 8 || 320 ((quadIndex * 8 + 7) >= (int)pArray->GetCount())) 321 return FALSE; 322 quadPoints->x1 = pArray->GetNumber(quadIndex * 8); 323 quadPoints->y1 = pArray->GetNumber(quadIndex * 8 + 1); 324 quadPoints->x2 = pArray->GetNumber(quadIndex * 8 + 2); 325 quadPoints->y2 = pArray->GetNumber(quadIndex * 8 + 3); 326 quadPoints->x3 = pArray->GetNumber(quadIndex * 8 + 4); 327 quadPoints->y3 = pArray->GetNumber(quadIndex * 8 + 5); 328 quadPoints->x4 = pArray->GetNumber(quadIndex * 8 + 6); 329 quadPoints->y4 = pArray->GetNumber(quadIndex * 8 + 7); 330 return TRUE; 331 } 332 return FALSE; 333 } 334 335 DLLEXPORT unsigned long STDCALL FPDF_GetMetaText(FPDF_DOCUMENT doc, 336 FPDF_BYTESTRING tag, 337 void* buffer, 338 unsigned long buflen) { 339 if (!tag) 340 return 0; 341 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(doc); 342 if (!pDoc) 343 return 0; 344 CPDF_Dictionary* pInfo = pDoc->GetInfo(); 345 if (!pInfo) 346 return 0; 347 CFX_WideString text = pInfo->GetUnicodeText(tag); 348 // Use UTF-16LE encoding 349 CFX_ByteString encodedText = text.UTF16LE_Encode(); 350 unsigned long len = encodedText.GetLength(); 351 if (buffer && buflen >= len) { 352 FXSYS_memcpy(buffer, encodedText.c_str(), len); 353 } 354 return len; 355 } 356