1 // Copyright 2015 The PDFium Authors
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 <set>
6 #include <vector>
7
8 #include "core/fpdfapi/parser/cpdf_document.h"
9 #include "core/fxcrt/bytestring.h"
10 #include "fpdfsdk/cpdfsdk_helpers.h"
11 #include "public/cpp/fpdf_scopers.h"
12 #include "public/fpdf_doc.h"
13 #include "public/fpdf_edit.h"
14 #include "public/fpdfview.h"
15 #include "testing/embedder_test.h"
16 #include "testing/fx_string_testhelpers.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 class FPDFDocEmbedderTest : public EmbedderTest {};
20
TEST_F(FPDFDocEmbedderTest,MultipleSamePage)21 TEST_F(FPDFDocEmbedderTest, MultipleSamePage) {
22 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
23 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document());
24
25 std::set<FPDF_PAGE> unique_pages;
26 std::vector<ScopedFPDFPage> owned_pages(4);
27 for (auto& ref : owned_pages) {
28 ref.reset(FPDF_LoadPage(document(), 0));
29 unique_pages.insert(ref.get());
30 }
31 #ifdef PDF_ENABLE_XFA
32 EXPECT_EQ(1u, unique_pages.size());
33 EXPECT_EQ(1u, pDoc->GetParsedPageCountForTesting());
34 #else // PDF_ENABLE_XFA
35 EXPECT_EQ(4u, unique_pages.size());
36 EXPECT_EQ(4u, pDoc->GetParsedPageCountForTesting());
37 #endif // PDF_ENABLE_XFA
38 }
39
TEST_F(FPDFDocEmbedderTest,DestGetPageIndex)40 TEST_F(FPDFDocEmbedderTest, DestGetPageIndex) {
41 ASSERT_TRUE(OpenDocument("named_dests.pdf"));
42
43 // NULL argument cases.
44 EXPECT_EQ(-1, FPDFDest_GetDestPageIndex(nullptr, nullptr));
45 EXPECT_EQ(-1, FPDFDest_GetDestPageIndex(document(), nullptr));
46
47 // Page number directly in item from Dests NameTree.
48 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
49 EXPECT_TRUE(dest);
50 EXPECT_EQ(1, FPDFDest_GetDestPageIndex(document(), dest));
51
52 // Page number via object reference in item from Dests NameTree.
53 dest = FPDF_GetNamedDestByName(document(), "Next");
54 EXPECT_TRUE(dest);
55 EXPECT_EQ(1, FPDFDest_GetDestPageIndex(document(), dest));
56
57 // Page number directly in item from Dests dictionary.
58 dest = FPDF_GetNamedDestByName(document(), "FirstAlternate");
59 EXPECT_TRUE(dest);
60 EXPECT_EQ(11, FPDFDest_GetDestPageIndex(document(), dest));
61
62 // Invalid object reference in item from Dests NameTree.
63 dest = FPDF_GetNamedDestByName(document(), "LastAlternate");
64 EXPECT_TRUE(dest);
65 EXPECT_EQ(-1, FPDFDest_GetDestPageIndex(document(), dest));
66 }
67
TEST_F(FPDFDocEmbedderTest,DestGetView)68 TEST_F(FPDFDocEmbedderTest, DestGetView) {
69 ASSERT_TRUE(OpenDocument("named_dests.pdf"));
70
71 unsigned long numParams;
72 FS_FLOAT params[4];
73
74 numParams = 42;
75 std::fill_n(params, 4, 42.4242f);
76 EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_UNKNOWN_MODE),
77 FPDFDest_GetView(nullptr, &numParams, params));
78 EXPECT_EQ(0U, numParams);
79 EXPECT_FLOAT_EQ(42.4242f, params[0]);
80
81 numParams = 42;
82 std::fill_n(params, 4, 42.4242f);
83 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
84 EXPECT_TRUE(dest);
85 EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_XYZ),
86 FPDFDest_GetView(dest, &numParams, params));
87 EXPECT_EQ(3U, numParams);
88 EXPECT_FLOAT_EQ(0, params[0]);
89 EXPECT_FLOAT_EQ(0, params[1]);
90 EXPECT_FLOAT_EQ(1, params[2]);
91 EXPECT_FLOAT_EQ(42.4242f, params[3]);
92
93 numParams = 42;
94 std::fill_n(params, 4, 42.4242f);
95 dest = FPDF_GetNamedDestByName(document(), "Next");
96 EXPECT_TRUE(dest);
97 EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_FIT),
98 FPDFDest_GetView(dest, &numParams, params));
99 EXPECT_EQ(0U, numParams);
100 EXPECT_FLOAT_EQ(42.4242f, params[0]);
101
102 numParams = 42;
103 std::fill_n(params, 4, 42.4242f);
104 dest = FPDF_GetNamedDestByName(document(), "FirstAlternate");
105 EXPECT_TRUE(dest);
106 EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_XYZ),
107 FPDFDest_GetView(dest, &numParams, params));
108 EXPECT_EQ(3U, numParams);
109 EXPECT_FLOAT_EQ(200, params[0]);
110 EXPECT_FLOAT_EQ(400, params[1]);
111 EXPECT_FLOAT_EQ(800, params[2]);
112 EXPECT_FLOAT_EQ(42.4242f, params[3]);
113
114 numParams = 42;
115 std::fill_n(params, 4, 42.4242f);
116 dest = FPDF_GetNamedDestByName(document(), "LastAlternate");
117 EXPECT_TRUE(dest);
118 EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_XYZ),
119 FPDFDest_GetView(dest, &numParams, params));
120 EXPECT_EQ(3U, numParams);
121 EXPECT_FLOAT_EQ(0, params[0]);
122 EXPECT_FLOAT_EQ(0, params[1]);
123 EXPECT_FLOAT_EQ(-200, params[2]);
124 EXPECT_FLOAT_EQ(42.4242f, params[3]);
125 }
126
TEST_F(FPDFDocEmbedderTest,DestGetLocationInPage)127 TEST_F(FPDFDocEmbedderTest, DestGetLocationInPage) {
128 ASSERT_TRUE(OpenDocument("named_dests.pdf"));
129
130 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
131 EXPECT_TRUE(dest);
132
133 FPDF_BOOL hasX = 0;
134 FPDF_BOOL hasY = 0;
135 FPDF_BOOL hasZoom = 0;
136 FS_FLOAT x = -1.0f;
137 FS_FLOAT y = -1.0f;
138 FS_FLOAT zoom = -1.0f;
139
140 // NULL argument case
141 EXPECT_FALSE(FPDFDest_GetLocationInPage(nullptr, &hasX, &hasY, &hasZoom, &x,
142 &y, &zoom));
143
144 // Actual argument case.
145 EXPECT_TRUE(
146 FPDFDest_GetLocationInPage(dest, &hasX, &hasY, &hasZoom, &x, &y, &zoom));
147 EXPECT_TRUE(hasX);
148 EXPECT_TRUE(hasY);
149 EXPECT_TRUE(hasZoom);
150 EXPECT_EQ(0, x);
151 EXPECT_EQ(0, y);
152 EXPECT_EQ(1, zoom);
153 }
154
TEST_F(FPDFDocEmbedderTest,BUG_1506_1)155 TEST_F(FPDFDocEmbedderTest, BUG_1506_1) {
156 ASSERT_TRUE(OpenDocument("bug_1506.pdf"));
157
158 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
159 ASSERT_TRUE(dest);
160 EXPECT_EQ(3, FPDFDest_GetDestPageIndex(document(), dest));
161 }
162
TEST_F(FPDFDocEmbedderTest,BUG_1506_2)163 TEST_F(FPDFDocEmbedderTest, BUG_1506_2) {
164 ASSERT_TRUE(OpenDocument("bug_1506.pdf"));
165
166 std::vector<FPDF_PAGE> pages;
167 for (int i : {0, 2})
168 pages.push_back(LoadPage(i));
169
170 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
171 ASSERT_TRUE(dest);
172 EXPECT_EQ(3, FPDFDest_GetDestPageIndex(document(), dest));
173
174 for (FPDF_PAGE page : pages)
175 UnloadPage(page);
176 }
177
TEST_F(FPDFDocEmbedderTest,BUG_1506_3)178 TEST_F(FPDFDocEmbedderTest, BUG_1506_3) {
179 ASSERT_TRUE(OpenDocument("bug_1506.pdf"));
180
181 std::vector<FPDF_PAGE> pages;
182 for (int i : {0, 1, 3})
183 pages.push_back(LoadPage(i));
184
185 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
186 ASSERT_TRUE(dest);
187 EXPECT_EQ(3, FPDFDest_GetDestPageIndex(document(), dest));
188
189 for (FPDF_PAGE page : pages)
190 UnloadPage(page);
191 }
192
TEST_F(FPDFDocEmbedderTest,BUG_680376)193 TEST_F(FPDFDocEmbedderTest, BUG_680376) {
194 ASSERT_TRUE(OpenDocument("bug_680376.pdf"));
195
196 // Page number directly in item from Dests NameTree.
197 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
198 EXPECT_TRUE(dest);
199 EXPECT_EQ(-1, FPDFDest_GetDestPageIndex(document(), dest));
200 }
201
TEST_F(FPDFDocEmbedderTest,BUG_821454)202 TEST_F(FPDFDocEmbedderTest, BUG_821454) {
203 ASSERT_TRUE(OpenDocument("bug_821454.pdf"));
204
205 FPDF_PAGE page = LoadPage(0);
206 ASSERT_TRUE(page);
207
208 // Cover some invalid argument cases while we're at it.
209 EXPECT_FALSE(FPDFLink_GetLinkAtPoint(nullptr, 150, 360));
210 EXPECT_EQ(-1, FPDFLink_GetLinkZOrderAtPoint(nullptr, 150, 360));
211
212 FPDF_LINK link1 = FPDFLink_GetLinkAtPoint(page, 150, 360);
213 ASSERT_TRUE(link1);
214 FPDF_LINK link2 = FPDFLink_GetLinkAtPoint(page, 150, 420);
215 ASSERT_TRUE(link2);
216
217 EXPECT_EQ(0, FPDFLink_GetLinkZOrderAtPoint(page, 150, 360));
218 EXPECT_EQ(1, FPDFLink_GetLinkZOrderAtPoint(page, 150, 420));
219
220 FPDF_DEST dest1 = FPDFLink_GetDest(document(), link1);
221 ASSERT_TRUE(dest1);
222 FPDF_DEST dest2 = FPDFLink_GetDest(document(), link2);
223 ASSERT_TRUE(dest2);
224
225 // Cover more invalid argument cases while we're at it.
226 EXPECT_FALSE(FPDFLink_GetDest(nullptr, nullptr));
227 EXPECT_FALSE(FPDFLink_GetDest(nullptr, link1));
228 EXPECT_FALSE(FPDFLink_GetDest(document(), nullptr));
229
230 EXPECT_EQ(0, FPDFDest_GetDestPageIndex(document(), dest1));
231 EXPECT_EQ(0, FPDFDest_GetDestPageIndex(document(), dest2));
232
233 {
234 FPDF_BOOL has_x_coord;
235 FPDF_BOOL has_y_coord;
236 FPDF_BOOL has_zoom;
237 FS_FLOAT x;
238 FS_FLOAT y;
239 FS_FLOAT zoom;
240 FPDF_BOOL success = FPDFDest_GetLocationInPage(
241 dest1, &has_x_coord, &has_y_coord, &has_zoom, &x, &y, &zoom);
242 ASSERT_TRUE(success);
243 EXPECT_TRUE(has_x_coord);
244 EXPECT_TRUE(has_y_coord);
245 EXPECT_FALSE(has_zoom);
246 EXPECT_FLOAT_EQ(100.0f, x);
247 EXPECT_FLOAT_EQ(200.0f, y);
248 }
249 {
250 FPDF_BOOL has_x_coord;
251 FPDF_BOOL has_y_coord;
252 FPDF_BOOL has_zoom;
253 FS_FLOAT x;
254 FS_FLOAT y;
255 FS_FLOAT zoom;
256 FPDF_BOOL success = FPDFDest_GetLocationInPage(
257 dest2, &has_x_coord, &has_y_coord, &has_zoom, &x, &y, &zoom);
258 ASSERT_TRUE(success);
259 EXPECT_TRUE(has_x_coord);
260 EXPECT_TRUE(has_y_coord);
261 EXPECT_FALSE(has_zoom);
262 EXPECT_FLOAT_EQ(150.0f, x);
263 EXPECT_FLOAT_EQ(250.0f, y);
264 }
265
266 UnloadPage(page);
267 }
268
TEST_F(FPDFDocEmbedderTest,ActionBadArguments)269 TEST_F(FPDFDocEmbedderTest, ActionBadArguments) {
270 ASSERT_TRUE(OpenDocument("launch_action.pdf"));
271 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_UNSUPPORTED),
272 FPDFAction_GetType(nullptr));
273
274 EXPECT_FALSE(FPDFAction_GetDest(nullptr, nullptr));
275 EXPECT_FALSE(FPDFAction_GetDest(document(), nullptr));
276 EXPECT_EQ(0u, FPDFAction_GetFilePath(nullptr, nullptr, 0));
277 EXPECT_EQ(0u, FPDFAction_GetURIPath(nullptr, nullptr, nullptr, 0));
278 EXPECT_EQ(0u, FPDFAction_GetURIPath(document(), nullptr, nullptr, 0));
279 }
280
TEST_F(FPDFDocEmbedderTest,ActionLaunch)281 TEST_F(FPDFDocEmbedderTest, ActionLaunch) {
282 ASSERT_TRUE(OpenDocument("launch_action.pdf"));
283
284 FPDF_PAGE page = LoadPage(0);
285 ASSERT_TRUE(page);
286
287 // The target action is nearly the size of the whole page.
288 FPDF_LINK link = FPDFLink_GetLinkAtPoint(page, 100, 100);
289 ASSERT_TRUE(link);
290
291 FPDF_ACTION action = FPDFLink_GetAction(link);
292 ASSERT_TRUE(action);
293 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_LAUNCH),
294 FPDFAction_GetType(action));
295
296 const char kExpectedResult[] = "test.pdf";
297 const unsigned long kExpectedLength = sizeof(kExpectedResult);
298 unsigned long bufsize = FPDFAction_GetFilePath(action, nullptr, 0);
299 EXPECT_EQ(kExpectedLength, bufsize);
300
301 char buf[1024];
302 EXPECT_EQ(bufsize, FPDFAction_GetFilePath(action, buf, bufsize));
303 EXPECT_STREQ(kExpectedResult, buf);
304
305 // Other public methods are not appropriate for launch actions.
306 EXPECT_FALSE(FPDFAction_GetDest(document(), action));
307 EXPECT_EQ(0u, FPDFAction_GetURIPath(document(), action, buf, sizeof(buf)));
308
309 UnloadPage(page);
310 }
311
TEST_F(FPDFDocEmbedderTest,ActionUri)312 TEST_F(FPDFDocEmbedderTest, ActionUri) {
313 ASSERT_TRUE(OpenDocument("uri_action.pdf"));
314
315 FPDF_PAGE page = LoadPage(0);
316 ASSERT_TRUE(page);
317
318 // The target action is nearly the size of the whole page.
319 FPDF_LINK link = FPDFLink_GetLinkAtPoint(page, 100, 100);
320 ASSERT_TRUE(link);
321
322 FPDF_ACTION action = FPDFLink_GetAction(link);
323 ASSERT_TRUE(action);
324 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_URI),
325 FPDFAction_GetType(action));
326
327 const char kExpectedResult[] = "https://example.com/page.html";
328 const unsigned long kExpectedLength = sizeof(kExpectedResult);
329 unsigned long bufsize = FPDFAction_GetURIPath(document(), action, nullptr, 0);
330 ASSERT_EQ(kExpectedLength, bufsize);
331
332 char buf[1024];
333 EXPECT_EQ(bufsize, FPDFAction_GetURIPath(document(), action, buf, bufsize));
334 EXPECT_STREQ(kExpectedResult, buf);
335
336 // Other public methods are not appropriate for URI actions
337 EXPECT_FALSE(FPDFAction_GetDest(document(), action));
338 EXPECT_EQ(0u, FPDFAction_GetFilePath(action, buf, sizeof(buf)));
339
340 UnloadPage(page);
341 }
342
TEST_F(FPDFDocEmbedderTest,ActionUriNonAscii)343 TEST_F(FPDFDocEmbedderTest, ActionUriNonAscii) {
344 ASSERT_TRUE(OpenDocument("uri_action_nonascii.pdf"));
345
346 FPDF_PAGE page = LoadPage(0);
347 ASSERT_TRUE(page);
348
349 // The target action is nearly the size of the whole page.
350 FPDF_LINK link = FPDFLink_GetLinkAtPoint(page, 100, 100);
351 ASSERT_TRUE(link);
352
353 FPDF_ACTION action = FPDFLink_GetAction(link);
354 ASSERT_TRUE(action);
355 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_URI),
356 FPDFAction_GetType(action));
357
358 // FPDFAction_GetURIPath() may return data in any encoding, or even with bad
359 // encoding.
360 const char kExpectedResult[] =
361 "https://example.com/\xA5octal\xC7"
362 "chars";
363 const unsigned long kExpectedLength = sizeof(kExpectedResult);
364 unsigned long bufsize = FPDFAction_GetURIPath(document(), action, nullptr, 0);
365 ASSERT_EQ(kExpectedLength, bufsize);
366
367 char buf[1024];
368 EXPECT_EQ(bufsize, FPDFAction_GetURIPath(document(), action, buf, bufsize));
369 EXPECT_STREQ(kExpectedResult, buf);
370
371 UnloadPage(page);
372 }
373
TEST_F(FPDFDocEmbedderTest,LinkToAnnotConversion)374 TEST_F(FPDFDocEmbedderTest, LinkToAnnotConversion) {
375 ASSERT_TRUE(OpenDocument("annots.pdf"));
376 FPDF_PAGE page = LoadPage(0);
377 ASSERT_TRUE(page);
378 {
379 FPDF_LINK first_link = FPDFLink_GetLinkAtPoint(page, 69.00, 653.00);
380 ScopedFPDFAnnotation first_annot(FPDFLink_GetAnnot(page, first_link));
381 EXPECT_EQ(0, FPDFPage_GetAnnotIndex(page, first_annot.get()));
382
383 FPDF_LINK second_link = FPDFLink_GetLinkAtPoint(page, 80.00, 633.00);
384 ScopedFPDFAnnotation second_annot(FPDFLink_GetAnnot(page, second_link));
385 EXPECT_EQ(1, FPDFPage_GetAnnotIndex(page, second_annot.get()));
386
387 // Also test invalid arguments.
388 EXPECT_FALSE(FPDFLink_GetAnnot(nullptr, nullptr));
389 EXPECT_FALSE(FPDFLink_GetAnnot(page, nullptr));
390 EXPECT_FALSE(FPDFLink_GetAnnot(nullptr, second_link));
391 }
392
393 UnloadPage(page);
394 }
395
TEST_F(FPDFDocEmbedderTest,ActionGoto)396 TEST_F(FPDFDocEmbedderTest, ActionGoto) {
397 ASSERT_TRUE(OpenDocument("goto_action.pdf"));
398
399 FPDF_PAGE page = LoadPage(0);
400 ASSERT_TRUE(page);
401
402 // The target action is nearly the size of the whole page.
403 FPDF_LINK link = FPDFLink_GetLinkAtPoint(page, 100, 100);
404 ASSERT_TRUE(link);
405
406 FPDF_ACTION action = FPDFLink_GetAction(link);
407 ASSERT_TRUE(action);
408 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_GOTO),
409 FPDFAction_GetType(action));
410
411 EXPECT_TRUE(FPDFAction_GetDest(document(), action));
412
413 // Other public methods are not appropriate for GoTo actions.
414 char buf[1024];
415 EXPECT_EQ(0u, FPDFAction_GetFilePath(action, buf, sizeof(buf)));
416 EXPECT_EQ(0u, FPDFAction_GetURIPath(document(), action, buf, sizeof(buf)));
417
418 UnloadPage(page);
419 }
420
TEST_F(FPDFDocEmbedderTest,ActionEmbeddedGoto)421 TEST_F(FPDFDocEmbedderTest, ActionEmbeddedGoto) {
422 ASSERT_TRUE(OpenDocument("gotoe_action.pdf"));
423
424 FPDF_PAGE page = LoadPage(0);
425 ASSERT_TRUE(page);
426
427 // The target action is nearly the size of the whole page.
428 FPDF_LINK link = FPDFLink_GetLinkAtPoint(page, 100, 100);
429 ASSERT_TRUE(link);
430
431 FPDF_ACTION action = FPDFLink_GetAction(link);
432 ASSERT_TRUE(action);
433 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_EMBEDDEDGOTO),
434 FPDFAction_GetType(action));
435
436 FPDF_DEST dest = FPDFAction_GetDest(document(), action);
437 EXPECT_TRUE(dest);
438
439 unsigned long num_params = 42;
440 FS_FLOAT params[4];
441 std::fill_n(params, 4, 42.4242f);
442 EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_FIT),
443 FPDFDest_GetView(dest, &num_params, params));
444 EXPECT_EQ(0u, num_params);
445 EXPECT_FLOAT_EQ(42.4242f, params[0]);
446
447 const char kExpectedResult[] = "ExampleFile.pdf";
448 const unsigned long kExpectedLength = sizeof(kExpectedResult);
449 char buf[1024];
450 unsigned long bufsize = FPDFAction_GetFilePath(action, nullptr, 0);
451 EXPECT_EQ(kExpectedLength, bufsize);
452 EXPECT_EQ(kExpectedLength, FPDFAction_GetFilePath(action, buf, bufsize));
453 EXPECT_STREQ(kExpectedResult, buf);
454
455 UnloadPage(page);
456 }
457
TEST_F(FPDFDocEmbedderTest,ActionNonesuch)458 TEST_F(FPDFDocEmbedderTest, ActionNonesuch) {
459 ASSERT_TRUE(OpenDocument("nonesuch_action.pdf"));
460
461 FPDF_PAGE page = LoadPage(0);
462 ASSERT_TRUE(page);
463
464 // The target action is nearly the size of the whole page.
465 FPDF_LINK link = FPDFLink_GetLinkAtPoint(page, 100, 100);
466 ASSERT_TRUE(link);
467
468 FPDF_ACTION action = FPDFLink_GetAction(link);
469 ASSERT_TRUE(action);
470 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_UNSUPPORTED),
471 FPDFAction_GetType(action));
472
473 // No public methods are appropriate for unsupported actions.
474 char buf[1024];
475 EXPECT_FALSE(FPDFAction_GetDest(document(), action));
476 EXPECT_EQ(0u, FPDFAction_GetFilePath(action, buf, sizeof(buf)));
477 EXPECT_EQ(0u, FPDFAction_GetURIPath(document(), action, buf, sizeof(buf)));
478
479 UnloadPage(page);
480 }
481
TEST_F(FPDFDocEmbedderTest,NoBookmarks)482 TEST_F(FPDFDocEmbedderTest, NoBookmarks) {
483 unsigned short buf[128];
484
485 // Open a file with no bookmarks.
486 ASSERT_TRUE(OpenDocument("named_dests.pdf"));
487
488 // NULL argument cases.
489 EXPECT_EQ(0u, FPDFBookmark_GetTitle(nullptr, buf, sizeof(buf)));
490 EXPECT_FALSE(FPDFBookmark_GetFirstChild(nullptr, nullptr));
491 EXPECT_FALSE(FPDFBookmark_GetFirstChild(document(), nullptr));
492 EXPECT_FALSE(FPDFBookmark_GetNextSibling(nullptr, nullptr));
493 EXPECT_FALSE(FPDFBookmark_GetNextSibling(document(), nullptr));
494 EXPECT_FALSE(FPDFBookmark_Find(nullptr, nullptr));
495 EXPECT_FALSE(FPDFBookmark_Find(document(), nullptr));
496 EXPECT_FALSE(FPDFBookmark_GetDest(nullptr, nullptr));
497 EXPECT_FALSE(FPDFBookmark_GetDest(document(), nullptr));
498 EXPECT_FALSE(FPDFBookmark_GetAction(nullptr));
499 }
500
TEST_F(FPDFDocEmbedderTest,Bookmarks)501 TEST_F(FPDFDocEmbedderTest, Bookmarks) {
502 unsigned short buf[128];
503
504 // Open a file with many bookmarks.
505 ASSERT_TRUE(OpenDocument("bookmarks.pdf"));
506
507 FPDF_BOOKMARK child = FPDFBookmark_GetFirstChild(document(), nullptr);
508 EXPECT_TRUE(child);
509 EXPECT_EQ(34u, FPDFBookmark_GetTitle(child, buf, sizeof(buf)));
510 EXPECT_EQ(L"A Good Beginning", GetPlatformWString(buf));
511 EXPECT_EQ(0, FPDFBookmark_GetCount(child));
512 EXPECT_EQ(0, FPDFBookmark_GetCount(nullptr));
513
514 EXPECT_FALSE(FPDFBookmark_GetDest(document(), child));
515 EXPECT_FALSE(FPDFBookmark_GetAction(child));
516
517 FPDF_BOOKMARK grand_child = FPDFBookmark_GetFirstChild(document(), child);
518 EXPECT_FALSE(grand_child);
519
520 FPDF_BOOKMARK sibling = FPDFBookmark_GetNextSibling(document(), child);
521 EXPECT_TRUE(sibling);
522 EXPECT_EQ(24u, FPDFBookmark_GetTitle(sibling, buf, sizeof(buf)));
523 EXPECT_EQ(L"Open Middle", GetPlatformWString(buf));
524 EXPECT_TRUE(FPDFBookmark_GetAction(sibling));
525 EXPECT_EQ(1, FPDFBookmark_GetCount(sibling));
526
527 FPDF_BOOKMARK sibling2 = FPDFBookmark_GetNextSibling(document(), sibling);
528 EXPECT_TRUE(sibling2);
529 EXPECT_EQ(42u, FPDFBookmark_GetTitle(sibling2, buf, sizeof(buf)));
530 EXPECT_EQ(L"A Good Closed Ending", GetPlatformWString(buf));
531 EXPECT_EQ(-2, FPDFBookmark_GetCount(sibling2));
532
533 EXPECT_FALSE(FPDFBookmark_GetNextSibling(document(), sibling2));
534
535 grand_child = FPDFBookmark_GetFirstChild(document(), sibling);
536 EXPECT_TRUE(grand_child);
537 EXPECT_EQ(46u, FPDFBookmark_GetTitle(grand_child, buf, sizeof(buf)));
538 EXPECT_EQ(L"Open Middle Descendant", GetPlatformWString(buf));
539 EXPECT_EQ(0, FPDFBookmark_GetCount(grand_child));
540 EXPECT_TRUE(FPDFBookmark_GetDest(document(), grand_child));
541
542 EXPECT_FALSE(FPDFBookmark_GetNextSibling(document(), grand_child));
543 }
544
TEST_F(FPDFDocEmbedderTest,FindBookmarks)545 TEST_F(FPDFDocEmbedderTest, FindBookmarks) {
546 unsigned short buf[128];
547
548 // Open a file with many bookmarks.
549 ASSERT_TRUE(OpenDocument("bookmarks.pdf"));
550
551 // Find the first one, based on its known title.
552 ScopedFPDFWideString title = GetFPDFWideString(L"A Good Beginning");
553 FPDF_BOOKMARK child = FPDFBookmark_Find(document(), title.get());
554 EXPECT_TRUE(child);
555
556 // Check that the string matches.
557 EXPECT_EQ(34u, FPDFBookmark_GetTitle(child, buf, sizeof(buf)));
558 EXPECT_EQ(L"A Good Beginning", GetPlatformWString(buf));
559
560 // Check that it is them same as the one returned by GetFirstChild.
561 EXPECT_EQ(child, FPDFBookmark_GetFirstChild(document(), nullptr));
562
563 // Try to find one using a non-existent title.
564 ScopedFPDFWideString bad_title = GetFPDFWideString(L"A BAD Beginning");
565 EXPECT_FALSE(FPDFBookmark_Find(document(), bad_title.get()));
566 }
567
568 // Check circular bookmarks will not cause infinite loop.
TEST_F(FPDFDocEmbedderTest,FindBookmarks_bug420)569 TEST_F(FPDFDocEmbedderTest, FindBookmarks_bug420) {
570 // Open a file with circular bookmarks.
571 ASSERT_TRUE(OpenDocument("bookmarks_circular.pdf"));
572
573 // Try to find a title.
574 ScopedFPDFWideString title = GetFPDFWideString(L"anything");
575 EXPECT_FALSE(FPDFBookmark_Find(document(), title.get()));
576 }
577
TEST_F(FPDFDocEmbedderTest,DeletePage)578 TEST_F(FPDFDocEmbedderTest, DeletePage) {
579 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
580 EXPECT_EQ(1, FPDF_GetPageCount(document()));
581
582 FPDFPage_Delete(nullptr, 0);
583 EXPECT_EQ(1, FPDF_GetPageCount(document()));
584
585 FPDFPage_Delete(document(), -1);
586 EXPECT_EQ(1, FPDF_GetPageCount(document()));
587 FPDFPage_Delete(document(), 1);
588 EXPECT_EQ(1, FPDF_GetPageCount(document()));
589
590 FPDFPage_Delete(document(), 0);
591 EXPECT_EQ(0, FPDF_GetPageCount(document()));
592 }
593
TEST_F(FPDFDocEmbedderTest,GetFileIdentifier)594 TEST_F(FPDFDocEmbedderTest, GetFileIdentifier) {
595 ASSERT_TRUE(OpenDocument("split_streams.pdf"));
596 constexpr size_t kMd5Length = 17;
597 char buf[kMd5Length];
598 EXPECT_EQ(0u,
599 FPDF_GetFileIdentifier(document(), static_cast<FPDF_FILEIDTYPE>(-1),
600 buf, sizeof(buf)));
601 EXPECT_EQ(0u,
602 FPDF_GetFileIdentifier(document(), static_cast<FPDF_FILEIDTYPE>(2),
603 buf, sizeof(buf)));
604 EXPECT_EQ(0u, FPDF_GetFileIdentifier(nullptr, FILEIDTYPE_PERMANENT, buf,
605 sizeof(buf)));
606 EXPECT_EQ(kMd5Length, FPDF_GetFileIdentifier(document(), FILEIDTYPE_PERMANENT,
607 nullptr, 0));
608
609 constexpr char kExpectedPermanent[] =
610 "\xF3\x41\xAE\x65\x4A\x77\xAC\xD5\x06\x5A\x76\x45\xE5\x96\xE6\xE6";
611 ASSERT_EQ(kMd5Length, FPDF_GetFileIdentifier(document(), FILEIDTYPE_PERMANENT,
612 buf, sizeof(buf)));
613 EXPECT_EQ(kExpectedPermanent, ByteString(buf));
614
615 constexpr char kExpectedChanging[] =
616 "\xBC\x37\x29\x8A\x3F\x87\xF4\x79\x22\x9B\xCE\x99\x7C\xA7\x91\xF7";
617 ASSERT_EQ(kMd5Length, FPDF_GetFileIdentifier(document(), FILEIDTYPE_CHANGING,
618 buf, sizeof(buf)));
619 EXPECT_EQ(kExpectedChanging, ByteString(buf));
620 }
621
TEST_F(FPDFDocEmbedderTest,GetNonHexFileIdentifier)622 TEST_F(FPDFDocEmbedderTest, GetNonHexFileIdentifier) {
623 ASSERT_TRUE(OpenDocument("non_hex_file_id.pdf"));
624 char buf[18];
625
626 constexpr char kPermanentNonHex[] = "permanent non-hex";
627 ASSERT_EQ(18u, FPDF_GetFileIdentifier(document(), FILEIDTYPE_PERMANENT, buf,
628 sizeof(buf)));
629 EXPECT_EQ(kPermanentNonHex, ByteString(buf));
630
631 constexpr char kChangingNonHex[] = "changing non-hex";
632 ASSERT_EQ(17u, FPDF_GetFileIdentifier(document(), FILEIDTYPE_CHANGING, buf,
633 sizeof(buf)));
634 EXPECT_EQ(kChangingNonHex, ByteString(buf));
635 }
636
TEST_F(FPDFDocEmbedderTest,GetNonexistentFileIdentifier)637 TEST_F(FPDFDocEmbedderTest, GetNonexistentFileIdentifier) {
638 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
639 EXPECT_EQ(
640 0u, FPDF_GetFileIdentifier(document(), FILEIDTYPE_PERMANENT, nullptr, 0));
641 EXPECT_EQ(
642 0u, FPDF_GetFileIdentifier(document(), FILEIDTYPE_CHANGING, nullptr, 0));
643 }
644
TEST_F(FPDFDocEmbedderTest,GetMetaText)645 TEST_F(FPDFDocEmbedderTest, GetMetaText) {
646 ASSERT_TRUE(OpenDocument("bug_601362.pdf"));
647
648 // Invalid document / tag results in 0.
649 unsigned short buf[128];
650 EXPECT_EQ(0u, FPDF_GetMetaText(document(), nullptr, buf, sizeof(buf)));
651 EXPECT_EQ(0u, FPDF_GetMetaText(nullptr, "", buf, sizeof(buf)));
652
653 // Tags that do not eixst results in an empty wide string.
654 EXPECT_EQ(2u, FPDF_GetMetaText(document(), "", buf, sizeof(buf)));
655 EXPECT_EQ(2u, FPDF_GetMetaText(document(), "foo", buf, sizeof(buf)));
656 ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Title", buf, sizeof(buf)));
657 ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Author", buf, sizeof(buf)));
658 ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Subject", buf, sizeof(buf)));
659 ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Keywords", buf, sizeof(buf)));
660 ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Producer", buf, sizeof(buf)));
661
662 ASSERT_EQ(30u, FPDF_GetMetaText(document(), "Creator", buf, sizeof(buf)));
663 EXPECT_EQ(L"Microsoft Word", GetPlatformWString(buf));
664
665 ASSERT_EQ(48u,
666 FPDF_GetMetaText(document(), "CreationDate", buf, sizeof(buf)));
667 EXPECT_EQ(L"D:20160411190039+00'00'", GetPlatformWString(buf));
668
669 ASSERT_EQ(48u, FPDF_GetMetaText(document(), "ModDate", buf, sizeof(buf)));
670 EXPECT_EQ(L"D:20160411190039+00'00'", GetPlatformWString(buf));
671 }
672
TEST_F(FPDFDocEmbedderTest,Bug_182)673 TEST_F(FPDFDocEmbedderTest, Bug_182) {
674 ASSERT_TRUE(OpenDocument("bug_182.pdf"));
675
676 unsigned short buf[128];
677
678 ASSERT_EQ(48u, FPDF_GetMetaText(document(), "Title", buf, sizeof(buf)));
679 EXPECT_EQ(L"Super Visual Formade 印刷", GetPlatformWString(buf));
680 }
681
TEST_F(FPDFDocEmbedderTest,GetMetaTextSameObjectNumber)682 TEST_F(FPDFDocEmbedderTest, GetMetaTextSameObjectNumber) {
683 ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf"));
684
685 // The PDF has been edited. It has two %%EOF markers, and 2 objects numbered
686 // (1 0). Both objects are /Info dictionaries, but contain different data.
687 // Make sure ModDate is the date of the last modification.
688 unsigned short buf[128];
689 ASSERT_EQ(48u, FPDF_GetMetaText(document(), "ModDate", buf, sizeof(buf)));
690 EXPECT_EQ(L"D:20170612232940-04'00'", GetPlatformWString(buf));
691 }
692
TEST_F(FPDFDocEmbedderTest,GetMetaTextInAttachmentFile)693 TEST_F(FPDFDocEmbedderTest, GetMetaTextInAttachmentFile) {
694 ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
695
696 // Make sure this is the date from the PDF itself and not the attached PDF.
697 unsigned short buf[128];
698 ASSERT_EQ(48u, FPDF_GetMetaText(document(), "ModDate", buf, sizeof(buf)));
699 EXPECT_EQ(L"D:20170712214448-07'00'", GetPlatformWString(buf));
700 }
701
TEST_F(FPDFDocEmbedderTest,GetMetaTextFromNewDocument)702 TEST_F(FPDFDocEmbedderTest, GetMetaTextFromNewDocument) {
703 FPDF_DOCUMENT empty_doc = FPDF_CreateNewDocument();
704 unsigned short buf[128];
705 EXPECT_EQ(2u, FPDF_GetMetaText(empty_doc, "Title", buf, sizeof(buf)));
706 FPDF_CloseDocument(empty_doc);
707 }
708
TEST_F(FPDFDocEmbedderTest,GetPageAAction)709 TEST_F(FPDFDocEmbedderTest, GetPageAAction) {
710 ASSERT_TRUE(OpenDocument("get_page_aaction.pdf"));
711 FPDF_PAGE page = LoadPage(0);
712 EXPECT_TRUE(page);
713
714 EXPECT_FALSE(FPDF_GetPageAAction(nullptr, FPDFPAGE_AACTION_OPEN));
715 EXPECT_FALSE(FPDF_GetPageAAction(page, FPDFPAGE_AACTION_CLOSE));
716 EXPECT_FALSE(FPDF_GetPageAAction(page, -1));
717 EXPECT_FALSE(FPDF_GetPageAAction(page, 999));
718
719 FPDF_ACTION action = FPDF_GetPageAAction(page, FPDFPAGE_AACTION_OPEN);
720 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_EMBEDDEDGOTO),
721 FPDFAction_GetType(action));
722
723 const char kExpectedResult[] = "\\\\127.0.0.1\\c$\\Program Files\\test.exe";
724 const unsigned long kExpectedLength = sizeof(kExpectedResult);
725 char buf[1024];
726
727 unsigned long bufsize = FPDFAction_GetFilePath(action, nullptr, 0);
728 EXPECT_EQ(kExpectedLength, bufsize);
729 EXPECT_EQ(kExpectedLength, FPDFAction_GetFilePath(action, buf, bufsize));
730 EXPECT_STREQ(kExpectedResult, buf);
731
732 UnloadPage(page);
733
734 page = LoadPage(1);
735 EXPECT_TRUE(page);
736 EXPECT_FALSE(FPDF_GetPageAAction(page, -1));
737
738 UnloadPage(page);
739 }
740
TEST_F(FPDFDocEmbedderTest,NoPageLabels)741 TEST_F(FPDFDocEmbedderTest, NoPageLabels) {
742 ASSERT_TRUE(OpenDocument("about_blank.pdf"));
743 EXPECT_EQ(1, FPDF_GetPageCount(document()));
744
745 ASSERT_EQ(0u, FPDF_GetPageLabel(document(), 0, nullptr, 0));
746 }
747
TEST_F(FPDFDocEmbedderTest,GetPageLabels)748 TEST_F(FPDFDocEmbedderTest, GetPageLabels) {
749 ASSERT_TRUE(OpenDocument("page_labels.pdf"));
750 EXPECT_EQ(7, FPDF_GetPageCount(document()));
751
752 // We do not request labels, when use FPDFAvail_IsXXXAvail.
753 // Flush all data, to allow read labels.
754 SetWholeFileAvailable();
755
756 unsigned short buf[128];
757 EXPECT_EQ(0u, FPDF_GetPageLabel(document(), -2, buf, sizeof(buf)));
758 EXPECT_EQ(0u, FPDF_GetPageLabel(document(), -1, buf, sizeof(buf)));
759
760 ASSERT_EQ(4u, FPDF_GetPageLabel(document(), 0, buf, sizeof(buf)));
761 EXPECT_EQ(L"i", GetPlatformWString(buf));
762
763 ASSERT_EQ(6u, FPDF_GetPageLabel(document(), 1, buf, sizeof(buf)));
764 EXPECT_EQ(L"ii", GetPlatformWString(buf));
765
766 ASSERT_EQ(4u, FPDF_GetPageLabel(document(), 2, buf, sizeof(buf)));
767 EXPECT_EQ(L"1", GetPlatformWString(buf));
768
769 ASSERT_EQ(4u, FPDF_GetPageLabel(document(), 3, buf, sizeof(buf)));
770 EXPECT_EQ(L"2", GetPlatformWString(buf));
771
772 ASSERT_EQ(8u, FPDF_GetPageLabel(document(), 4, buf, sizeof(buf)));
773 EXPECT_EQ(L"zzA", GetPlatformWString(buf));
774
775 ASSERT_EQ(8u, FPDF_GetPageLabel(document(), 5, buf, sizeof(buf)));
776 EXPECT_EQ(L"zzB", GetPlatformWString(buf));
777
778 ASSERT_EQ(2u, FPDF_GetPageLabel(document(), 6, buf, sizeof(buf)));
779 EXPECT_EQ(L"", GetPlatformWString(buf));
780
781 ASSERT_EQ(0u, FPDF_GetPageLabel(document(), 7, buf, sizeof(buf)));
782 ASSERT_EQ(0u, FPDF_GetPageLabel(document(), 8, buf, sizeof(buf)));
783 }
784
785 #ifdef PDF_ENABLE_XFA
TEST_F(FPDFDocEmbedderTest,GetXFALinks)786 TEST_F(FPDFDocEmbedderTest, GetXFALinks) {
787 ASSERT_TRUE(OpenDocument("simple_xfa.pdf"));
788
789 ScopedFPDFPage page(FPDF_LoadPage(document(), 0));
790 ASSERT_TRUE(page);
791
792 FPDFLink_GetLinkAtPoint(page.get(), 150, 360);
793 FPDFLink_GetLinkAtPoint(page.get(), 150, 420);
794
795 // Test passes if it doesn't crash. See https://crbug.com/840922
796 }
797 #endif // PDF_ENABLE_XFA
798