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