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