Home | History | Annotate | Download | only in fpdfsdk
      1 // Copyright 2015 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 #include <memory>
      6 #include <string>
      7 
      8 #include "core/fxcrt/fx_string.h"
      9 #include "public/fpdf_doc.h"
     10 #include "public/fpdf_edit.h"
     11 #include "public/fpdfview.h"
     12 #include "testing/embedder_test.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 #include "testing/test_support.h"
     15 
     16 class FPDFDocEmbeddertest : public EmbedderTest {};
     17 
     18 TEST_F(FPDFDocEmbeddertest, DestGetPageIndex) {
     19   EXPECT_TRUE(OpenDocument("named_dests.pdf"));
     20 
     21   // NULL FPDF_DEST case.
     22   EXPECT_EQ(0U, FPDFDest_GetPageIndex(document(), nullptr));
     23 
     24   // Page number directly in item from Dests NameTree.
     25   FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
     26   EXPECT_TRUE(dest);
     27   EXPECT_EQ(1U, FPDFDest_GetPageIndex(document(), dest));
     28 
     29   // Page number via object reference in item from Dests NameTree.
     30   dest = FPDF_GetNamedDestByName(document(), "Next");
     31   EXPECT_TRUE(dest);
     32   EXPECT_EQ(1U, FPDFDest_GetPageIndex(document(), dest));
     33 
     34   // Page number directly in item from Dests dictionary.
     35   dest = FPDF_GetNamedDestByName(document(), "FirstAlternate");
     36   EXPECT_TRUE(dest);
     37   EXPECT_EQ(11U, FPDFDest_GetPageIndex(document(), dest));
     38 
     39   // Invalid object reference in item from Dests NameTree.
     40   dest = FPDF_GetNamedDestByName(document(), "LastAlternate");
     41   EXPECT_TRUE(dest);
     42   EXPECT_EQ(0U, FPDFDest_GetPageIndex(document(), dest));
     43 }
     44 
     45 TEST_F(FPDFDocEmbeddertest, DestGetView) {
     46   EXPECT_TRUE(OpenDocument("named_dests.pdf"));
     47 
     48   unsigned long numParams;
     49   FS_FLOAT params[4];
     50 
     51   numParams = 42;
     52   std::fill_n(params, 4, 42.4242f);
     53   EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_UNKNOWN_MODE),
     54             FPDFDest_GetView(nullptr, &numParams, params));
     55   EXPECT_EQ(0U, numParams);
     56   EXPECT_FLOAT_EQ(42.4242f, params[0]);
     57 
     58   numParams = 42;
     59   std::fill_n(params, 4, 42.4242f);
     60   FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
     61   EXPECT_TRUE(dest);
     62   EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_XYZ),
     63             FPDFDest_GetView(dest, &numParams, params));
     64   EXPECT_EQ(3U, numParams);
     65   EXPECT_FLOAT_EQ(0, params[0]);
     66   EXPECT_FLOAT_EQ(0, params[1]);
     67   EXPECT_FLOAT_EQ(1, params[2]);
     68   EXPECT_FLOAT_EQ(42.4242f, params[3]);
     69 
     70   numParams = 42;
     71   std::fill_n(params, 4, 42.4242f);
     72   dest = FPDF_GetNamedDestByName(document(), "Next");
     73   EXPECT_TRUE(dest);
     74   EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_FIT),
     75             FPDFDest_GetView(dest, &numParams, params));
     76   EXPECT_EQ(0U, numParams);
     77   EXPECT_FLOAT_EQ(42.4242f, params[0]);
     78 
     79   numParams = 42;
     80   std::fill_n(params, 4, 42.4242f);
     81   dest = FPDF_GetNamedDestByName(document(), "FirstAlternate");
     82   EXPECT_TRUE(dest);
     83   EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_XYZ),
     84             FPDFDest_GetView(dest, &numParams, params));
     85   EXPECT_EQ(3U, numParams);
     86   EXPECT_FLOAT_EQ(200, params[0]);
     87   EXPECT_FLOAT_EQ(400, params[1]);
     88   EXPECT_FLOAT_EQ(800, params[2]);
     89   EXPECT_FLOAT_EQ(42.4242f, params[3]);
     90 
     91   numParams = 42;
     92   std::fill_n(params, 4, 42.4242f);
     93   dest = FPDF_GetNamedDestByName(document(), "LastAlternate");
     94   EXPECT_TRUE(dest);
     95   EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_XYZ),
     96             FPDFDest_GetView(dest, &numParams, params));
     97   EXPECT_EQ(3U, numParams);
     98   EXPECT_FLOAT_EQ(0, params[0]);
     99   EXPECT_FLOAT_EQ(0, params[1]);
    100   EXPECT_FLOAT_EQ(-200, params[2]);
    101   EXPECT_FLOAT_EQ(42.4242f, params[3]);
    102 }
    103 
    104 TEST_F(FPDFDocEmbeddertest, DestGetLocationInPage) {
    105   EXPECT_TRUE(OpenDocument("named_dests.pdf"));
    106 
    107   // NULL FPDF_DEST case.
    108   EXPECT_EQ(0U, FPDFDest_GetPageIndex(document(), nullptr));
    109 
    110   FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
    111   EXPECT_TRUE(dest);
    112 
    113   FPDF_BOOL hasX;
    114   FPDF_BOOL hasY;
    115   FPDF_BOOL hasZoom;
    116   FS_FLOAT x;
    117   FS_FLOAT y;
    118   FS_FLOAT zoom;
    119   EXPECT_TRUE(
    120       FPDFDest_GetLocationInPage(dest, &hasX, &hasY, &hasZoom, &x, &y, &zoom));
    121   EXPECT_TRUE(hasX);
    122   EXPECT_TRUE(hasY);
    123   EXPECT_TRUE(hasZoom);
    124   EXPECT_EQ(0, x);
    125   EXPECT_EQ(0, y);
    126   EXPECT_EQ(1, zoom);
    127 }
    128 
    129 TEST_F(FPDFDocEmbeddertest, BUG_680376) {
    130   EXPECT_TRUE(OpenDocument("bug_680376.pdf"));
    131 
    132   // Page number directly in item from Dests NameTree.
    133   FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
    134   EXPECT_TRUE(dest);
    135   EXPECT_EQ(static_cast<unsigned long>(-1),
    136             FPDFDest_GetPageIndex(document(), dest));
    137 }
    138 
    139 TEST_F(FPDFDocEmbeddertest, ActionGetFilePath) {
    140   EXPECT_TRUE(OpenDocument("launch_action.pdf"));
    141 
    142   FPDF_PAGE page = FPDF_LoadPage(document(), 0);
    143   ASSERT_TRUE(page);
    144 
    145   // The target action is nearly the size of the whole page.
    146   FPDF_LINK link = FPDFLink_GetLinkAtPoint(page, 100, 100);
    147   ASSERT_TRUE(link);
    148 
    149   FPDF_ACTION action = FPDFLink_GetAction(link);
    150   ASSERT_TRUE(action);
    151 
    152   const char kExpectedResult[] = "test.pdf";
    153   const unsigned long kExpectedLength = sizeof(kExpectedResult);
    154   unsigned long bufsize = FPDFAction_GetFilePath(action, nullptr, 0);
    155   ASSERT_EQ(kExpectedLength, bufsize);
    156 
    157   char buf[kExpectedLength];
    158   EXPECT_EQ(bufsize, FPDFAction_GetFilePath(action, buf, bufsize));
    159   EXPECT_EQ(std::string(kExpectedResult), std::string(buf));
    160 
    161   FPDF_ClosePage(page);
    162 }
    163 
    164 TEST_F(FPDFDocEmbeddertest, NoBookmarks) {
    165   // Open a file with no bookmarks.
    166   EXPECT_TRUE(OpenDocument("named_dests.pdf"));
    167 
    168   // The non-existent top-level bookmark has no title.
    169   unsigned short buf[128];
    170   EXPECT_EQ(0u, FPDFBookmark_GetTitle(nullptr, buf, sizeof(buf)));
    171 
    172   // The non-existent top-level bookmark has no children.
    173   EXPECT_EQ(nullptr, FPDFBookmark_GetFirstChild(document(), nullptr));
    174 }
    175 
    176 TEST_F(FPDFDocEmbeddertest, Bookmarks) {
    177   // Open a file with two bookmarks.
    178   EXPECT_TRUE(OpenDocument("bookmarks.pdf"));
    179 
    180   // The existent top-level bookmark has no title.
    181   unsigned short buf[128];
    182   EXPECT_EQ(0u, FPDFBookmark_GetTitle(nullptr, buf, sizeof(buf)));
    183 
    184   FPDF_BOOKMARK child = FPDFBookmark_GetFirstChild(document(), nullptr);
    185   EXPECT_TRUE(child);
    186   EXPECT_EQ(34u, FPDFBookmark_GetTitle(child, buf, sizeof(buf)));
    187   EXPECT_EQ(WideString(L"A Good Beginning"), WideString::FromUTF16LE(buf, 16));
    188 
    189   EXPECT_EQ(nullptr, FPDFBookmark_GetFirstChild(document(), child));
    190 
    191   FPDF_BOOKMARK sibling = FPDFBookmark_GetNextSibling(document(), child);
    192   EXPECT_TRUE(sibling);
    193   EXPECT_EQ(28u, FPDFBookmark_GetTitle(sibling, buf, sizeof(buf)));
    194   EXPECT_EQ(WideString(L"A Good Ending"), WideString::FromUTF16LE(buf, 13));
    195 
    196   EXPECT_EQ(nullptr, FPDFBookmark_GetNextSibling(document(), sibling));
    197 }
    198 
    199 TEST_F(FPDFDocEmbeddertest, FindBookmarks) {
    200   // Open a file with two bookmarks.
    201   EXPECT_TRUE(OpenDocument("bookmarks.pdf"));
    202 
    203   // Find the first one, based on its known title.
    204   std::unique_ptr<unsigned short, pdfium::FreeDeleter> title =
    205       GetFPDFWideString(L"A Good Beginning");
    206   FPDF_BOOKMARK child = FPDFBookmark_Find(document(), title.get());
    207   EXPECT_TRUE(child);
    208 
    209   // Check that the string matches.
    210   unsigned short buf[128];
    211   EXPECT_EQ(34u, FPDFBookmark_GetTitle(child, buf, sizeof(buf)));
    212   EXPECT_EQ(WideString(L"A Good Beginning"), WideString::FromUTF16LE(buf, 16));
    213 
    214   // Check that it is them same as the one returned by GetFirstChild.
    215   EXPECT_EQ(child, FPDFBookmark_GetFirstChild(document(), nullptr));
    216 
    217   // Try to find one using a non-existent title.
    218   std::unique_ptr<unsigned short, pdfium::FreeDeleter> bad_title =
    219       GetFPDFWideString(L"A BAD Beginning");
    220   EXPECT_EQ(nullptr, FPDFBookmark_Find(document(), bad_title.get()));
    221 }
    222 
    223 // Check circular bookmarks will not cause infinite loop.
    224 TEST_F(FPDFDocEmbeddertest, FindBookmarks_bug420) {
    225   // Open a file with circular bookmarks.
    226   EXPECT_TRUE(OpenDocument("bookmarks_circular.pdf"));
    227 
    228   // Try to find a title.
    229   std::unique_ptr<unsigned short, pdfium::FreeDeleter> title =
    230       GetFPDFWideString(L"anything");
    231   EXPECT_EQ(nullptr, FPDFBookmark_Find(document(), title.get()));
    232 }
    233 
    234 TEST_F(FPDFDocEmbeddertest, DeletePage) {
    235   EXPECT_TRUE(OpenDocument("hello_world.pdf"));
    236   EXPECT_EQ(1, FPDF_GetPageCount(document()));
    237   FPDFPage_Delete(document(), 0);
    238   EXPECT_EQ(0, FPDF_GetPageCount(document()));
    239 }
    240 
    241 TEST_F(FPDFDocEmbeddertest, GetMetaText) {
    242   ASSERT_TRUE(OpenDocument("bug_601362.pdf"));
    243 
    244   // Invalid document / tag results in 0.
    245   unsigned short buf[128];
    246   EXPECT_EQ(0u, FPDF_GetMetaText(document(), nullptr, buf, sizeof(buf)));
    247   EXPECT_EQ(0u, FPDF_GetMetaText(nullptr, "", buf, sizeof(buf)));
    248 
    249   // Tags that do not eixst results in an empty wide string.
    250   EXPECT_EQ(2u, FPDF_GetMetaText(document(), "", buf, sizeof(buf)));
    251   EXPECT_EQ(2u, FPDF_GetMetaText(document(), "foo", buf, sizeof(buf)));
    252   ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Title", buf, sizeof(buf)));
    253   ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Author", buf, sizeof(buf)));
    254   ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Subject", buf, sizeof(buf)));
    255   ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Keywords", buf, sizeof(buf)));
    256   ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Producer", buf, sizeof(buf)));
    257 
    258   constexpr wchar_t kExpectedCreator[] = L"Microsoft Word";
    259   ASSERT_EQ(30u, FPDF_GetMetaText(document(), "Creator", buf, sizeof(buf)));
    260   EXPECT_EQ(WideString(kExpectedCreator),
    261             WideString::FromUTF16LE(buf, FXSYS_len(kExpectedCreator)));
    262 
    263   constexpr wchar_t kExpectedCreationDate[] = L"D:20160411190039+00'00'";
    264   ASSERT_EQ(48u,
    265             FPDF_GetMetaText(document(), "CreationDate", buf, sizeof(buf)));
    266   EXPECT_EQ(WideString(kExpectedCreationDate),
    267             WideString::FromUTF16LE(buf, FXSYS_len(kExpectedCreationDate)));
    268 
    269   constexpr wchar_t kExpectedModDate[] = L"D:20160411190039+00'00'";
    270   ASSERT_EQ(48u, FPDF_GetMetaText(document(), "ModDate", buf, sizeof(buf)));
    271   EXPECT_EQ(WideString(kExpectedModDate),
    272             WideString::FromUTF16LE(buf, FXSYS_len(kExpectedModDate)));
    273 }
    274 
    275 TEST_F(FPDFDocEmbeddertest, GetMetaTextSameObjectNumber) {
    276   ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf"));
    277 
    278   // The PDF has been edited. It has two %%EOF markers, and 2 objects numbered
    279   // (1 0). Both objects are /Info dictionaries, but contain different data.
    280   // Make sure ModDate is the date of the last modification.
    281   unsigned short buf[128];
    282   constexpr wchar_t kExpectedModDate[] = L"D:20170612232940-04'00'";
    283   ASSERT_EQ(48u, FPDF_GetMetaText(document(), "ModDate", buf, sizeof(buf)));
    284   EXPECT_EQ(WideString(kExpectedModDate),
    285             WideString::FromUTF16LE(buf, FXSYS_len(kExpectedModDate)));
    286 }
    287 
    288 TEST_F(FPDFDocEmbeddertest, GetMetaTextInAttachmentFile) {
    289   ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
    290 
    291   // Make sure this is the date from the PDF itself and not the attached PDF.
    292   unsigned short buf[128];
    293   constexpr wchar_t kExpectedModDate[] = L"D:20170712214448-07'00'";
    294   ASSERT_EQ(48u, FPDF_GetMetaText(document(), "ModDate", buf, sizeof(buf)));
    295   EXPECT_EQ(WideString(kExpectedModDate),
    296             WideString::FromUTF16LE(buf, FXSYS_len(kExpectedModDate)));
    297 }
    298 
    299 TEST_F(FPDFDocEmbeddertest, GetMetaTextFromNewDocument) {
    300   FPDF_DOCUMENT empty_doc = FPDF_CreateNewDocument();
    301   unsigned short buf[128];
    302   EXPECT_EQ(2u, FPDF_GetMetaText(empty_doc, "Title", buf, sizeof(buf)));
    303   FPDF_CloseDocument(empty_doc);
    304 }
    305 
    306 TEST_F(FPDFDocEmbeddertest, NoPageLabels) {
    307   EXPECT_TRUE(OpenDocument("about_blank.pdf"));
    308   EXPECT_EQ(1, FPDF_GetPageCount(document()));
    309 
    310   ASSERT_EQ(0u, FPDF_GetPageLabel(document(), 0, nullptr, 0));
    311 }
    312 
    313 TEST_F(FPDFDocEmbeddertest, GetPageLabels) {
    314   EXPECT_TRUE(OpenDocument("page_labels.pdf"));
    315   EXPECT_EQ(7, FPDF_GetPageCount(document()));
    316 
    317   // We do not request labels, when use FPDFAvail_IsXXXAvail.
    318   // Flush all data, to allow read labels.
    319   SetWholeFileAvailable();
    320 
    321   unsigned short buf[128];
    322   EXPECT_EQ(0u, FPDF_GetPageLabel(document(), -2, buf, sizeof(buf)));
    323   EXPECT_EQ(0u, FPDF_GetPageLabel(document(), -1, buf, sizeof(buf)));
    324 
    325   const wchar_t kExpectedPageLabel0[] = L"i";
    326   ASSERT_EQ(4u, FPDF_GetPageLabel(document(), 0, buf, sizeof(buf)));
    327   EXPECT_EQ(WideString(kExpectedPageLabel0),
    328             WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel0)));
    329 
    330   const wchar_t kExpectedPageLabel1[] = L"ii";
    331   ASSERT_EQ(6u, FPDF_GetPageLabel(document(), 1, buf, sizeof(buf)));
    332   EXPECT_EQ(WideString(kExpectedPageLabel1),
    333             WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel1)));
    334 
    335   const wchar_t kExpectedPageLabel2[] = L"1";
    336   ASSERT_EQ(4u, FPDF_GetPageLabel(document(), 2, buf, sizeof(buf)));
    337   EXPECT_EQ(WideString(kExpectedPageLabel2),
    338             WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel2)));
    339 
    340   const wchar_t kExpectedPageLabel3[] = L"2";
    341   ASSERT_EQ(4u, FPDF_GetPageLabel(document(), 3, buf, sizeof(buf)));
    342   EXPECT_EQ(WideString(kExpectedPageLabel3),
    343             WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel3)));
    344 
    345   const wchar_t kExpectedPageLabel4[] = L"zzA";
    346   ASSERT_EQ(8u, FPDF_GetPageLabel(document(), 4, buf, sizeof(buf)));
    347   EXPECT_EQ(WideString(kExpectedPageLabel4),
    348             WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel4)));
    349 
    350   const wchar_t kExpectedPageLabel5[] = L"zzB";
    351   ASSERT_EQ(8u, FPDF_GetPageLabel(document(), 5, buf, sizeof(buf)));
    352   EXPECT_EQ(WideString(kExpectedPageLabel5),
    353             WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel5)));
    354 
    355   const wchar_t kExpectedPageLabel6[] = L"";
    356   ASSERT_EQ(2u, FPDF_GetPageLabel(document(), 6, buf, sizeof(buf)));
    357   EXPECT_EQ(WideString(kExpectedPageLabel6),
    358             WideString::FromUTF16LE(buf, FXSYS_len(kExpectedPageLabel6)));
    359 
    360   ASSERT_EQ(0u, FPDF_GetPageLabel(document(), 7, buf, sizeof(buf)));
    361   ASSERT_EQ(0u, FPDF_GetPageLabel(document(), 8, buf, sizeof(buf)));
    362 }
    363