• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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