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