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