Home | History | Annotate | Download | only in src
      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