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 <array>
6 #include <set>
7 #include <string>
8 #include <vector>
9
10 #include "core/fpdfapi/parser/cpdf_dictionary.h"
11 #include "core/fpdfapi/parser/cpdf_document.h"
12 #include "core/fpdfapi/parser/cpdf_reference.h"
13 #include "core/fxcrt/bytestring.h"
14 #include "core/fxcrt/fx_safe_types.h"
15 #include "core/fxge/cfx_defaultrenderdevice.h"
16 #include "fpdfsdk/cpdfsdk_helpers.h"
17 #include "public/cpp/fpdf_scopers.h"
18 #include "public/fpdf_doc.h"
19 #include "public/fpdf_edit.h"
20 #include "public/fpdfview.h"
21 #include "testing/embedder_test.h"
22 #include "testing/fx_string_testhelpers.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace {
26
27 // Look for "/Type/Page" but ignore "/Type/Pages".
CountPageEntries(const std::string & data)28 int CountPageEntries(const std::string& data) {
29 static constexpr char kNeedle[] = "/Type/Page";
30 static constexpr size_t kNeedleLen = std::size(kNeedle) - 1;
31
32 size_t pos = 0;
33 int count = 0;
34 while (pos < data.size()) {
35 const size_t found_pos = data.find(kNeedle, pos);
36 if (found_pos == std::string::npos) {
37 break;
38 }
39
40 FX_SAFE_SIZE_T next_pos = found_pos;
41 next_pos += kNeedleLen;
42 pos = next_pos.ValueOrDefault(std::string::npos);
43 if (pos < data.size() && data[pos] == 's') {
44 // Ignore "/Type/Pages".
45 ++pos;
46 } else {
47 ++count;
48 }
49 }
50 return count;
51 }
52
53 // Look for ">stream\r\n".
CountStreamEntries(const std::string & data)54 int CountStreamEntries(const std::string& data) {
55 static constexpr char kNeedle[] = ">stream\r\n";
56 static constexpr size_t kNeedleLen = std::size(kNeedle) - 1;
57
58 size_t pos = 0;
59 int count = 0;
60 while (pos < data.size()) {
61 const size_t found_pos = data.find(kNeedle, pos);
62 if (found_pos == std::string::npos) {
63 break;
64 }
65
66 FX_SAFE_SIZE_T next_pos = found_pos;
67 next_pos += kNeedleLen;
68 pos = next_pos.ValueOrDefault(std::string::npos);
69 ++count;
70 }
71 return count;
72 }
73
74 } // namespace
75
76 class FPDFDocEmbedderTest : public EmbedderTest {};
77
TEST_F(FPDFDocEmbedderTest,MultipleSamePage)78 TEST_F(FPDFDocEmbedderTest, MultipleSamePage) {
79 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
80 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document());
81
82 std::set<FPDF_PAGE> unique_pages;
83 std::vector<ScopedFPDFPage> owned_pages(4);
84 for (auto& ref : owned_pages) {
85 ref.reset(FPDF_LoadPage(document(), 0));
86 unique_pages.insert(ref.get());
87 }
88 #ifdef PDF_ENABLE_XFA
89 EXPECT_EQ(1u, unique_pages.size());
90 EXPECT_EQ(1u, pDoc->GetParsedPageCountForTesting());
91 #else // PDF_ENABLE_XFA
92 EXPECT_EQ(4u, unique_pages.size());
93 EXPECT_EQ(4u, pDoc->GetParsedPageCountForTesting());
94 #endif // PDF_ENABLE_XFA
95 }
96
TEST_F(FPDFDocEmbedderTest,DestGetPageIndex)97 TEST_F(FPDFDocEmbedderTest, DestGetPageIndex) {
98 ASSERT_TRUE(OpenDocument("named_dests.pdf"));
99
100 // NULL argument cases.
101 EXPECT_EQ(-1, FPDFDest_GetDestPageIndex(nullptr, nullptr));
102 EXPECT_EQ(-1, FPDFDest_GetDestPageIndex(document(), nullptr));
103
104 // Page number directly in item from Dests NameTree.
105 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
106 EXPECT_TRUE(dest);
107 EXPECT_EQ(1, FPDFDest_GetDestPageIndex(document(), dest));
108
109 // Page number via object reference in item from Dests NameTree.
110 dest = FPDF_GetNamedDestByName(document(), "Next");
111 EXPECT_TRUE(dest);
112 EXPECT_EQ(1, FPDFDest_GetDestPageIndex(document(), dest));
113
114 // Page number directly in item from Dests dictionary.
115 dest = FPDF_GetNamedDestByName(document(), "FirstAlternate");
116 EXPECT_TRUE(dest);
117 EXPECT_EQ(11, FPDFDest_GetDestPageIndex(document(), dest));
118
119 // Invalid object reference in item from Dests NameTree.
120 dest = FPDF_GetNamedDestByName(document(), "LastAlternate");
121 EXPECT_TRUE(dest);
122 EXPECT_EQ(-1, FPDFDest_GetDestPageIndex(document(), dest));
123 }
124
TEST_F(FPDFDocEmbedderTest,DestGetView)125 TEST_F(FPDFDocEmbedderTest, DestGetView) {
126 ASSERT_TRUE(OpenDocument("named_dests.pdf"));
127
128 unsigned long numParams;
129 FS_FLOAT params[4];
130
131 numParams = 42;
132 std::fill_n(params, 4, 42.4242f);
133 EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_UNKNOWN_MODE),
134 FPDFDest_GetView(nullptr, &numParams, params));
135 EXPECT_EQ(0U, numParams);
136 EXPECT_FLOAT_EQ(42.4242f, params[0]);
137
138 numParams = 42;
139 std::fill_n(params, 4, 42.4242f);
140 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
141 EXPECT_TRUE(dest);
142 EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_XYZ),
143 FPDFDest_GetView(dest, &numParams, params));
144 EXPECT_EQ(3U, numParams);
145 EXPECT_FLOAT_EQ(0, params[0]);
146 EXPECT_FLOAT_EQ(0, params[1]);
147 EXPECT_FLOAT_EQ(1, params[2]);
148 EXPECT_FLOAT_EQ(42.4242f, params[3]);
149
150 numParams = 42;
151 std::fill_n(params, 4, 42.4242f);
152 dest = FPDF_GetNamedDestByName(document(), "Next");
153 EXPECT_TRUE(dest);
154 EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_FIT),
155 FPDFDest_GetView(dest, &numParams, params));
156 EXPECT_EQ(0U, numParams);
157 EXPECT_FLOAT_EQ(42.4242f, params[0]);
158
159 numParams = 42;
160 std::fill_n(params, 4, 42.4242f);
161 dest = FPDF_GetNamedDestByName(document(), "FirstAlternate");
162 EXPECT_TRUE(dest);
163 EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_XYZ),
164 FPDFDest_GetView(dest, &numParams, params));
165 EXPECT_EQ(3U, numParams);
166 EXPECT_FLOAT_EQ(200, params[0]);
167 EXPECT_FLOAT_EQ(400, params[1]);
168 EXPECT_FLOAT_EQ(800, params[2]);
169 EXPECT_FLOAT_EQ(42.4242f, params[3]);
170
171 numParams = 42;
172 std::fill_n(params, 4, 42.4242f);
173 dest = FPDF_GetNamedDestByName(document(), "LastAlternate");
174 EXPECT_TRUE(dest);
175 EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_XYZ),
176 FPDFDest_GetView(dest, &numParams, params));
177 EXPECT_EQ(3U, numParams);
178 EXPECT_FLOAT_EQ(0, params[0]);
179 EXPECT_FLOAT_EQ(0, params[1]);
180 EXPECT_FLOAT_EQ(-200, params[2]);
181 EXPECT_FLOAT_EQ(42.4242f, params[3]);
182 }
183
TEST_F(FPDFDocEmbedderTest,DestGetLocationInPage)184 TEST_F(FPDFDocEmbedderTest, DestGetLocationInPage) {
185 ASSERT_TRUE(OpenDocument("named_dests.pdf"));
186
187 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
188 EXPECT_TRUE(dest);
189
190 FPDF_BOOL hasX = 0;
191 FPDF_BOOL hasY = 0;
192 FPDF_BOOL hasZoom = 0;
193 FS_FLOAT x = -1.0f;
194 FS_FLOAT y = -1.0f;
195 FS_FLOAT zoom = -1.0f;
196
197 // NULL argument case
198 EXPECT_FALSE(FPDFDest_GetLocationInPage(nullptr, &hasX, &hasY, &hasZoom, &x,
199 &y, &zoom));
200
201 // Actual argument case.
202 EXPECT_TRUE(
203 FPDFDest_GetLocationInPage(dest, &hasX, &hasY, &hasZoom, &x, &y, &zoom));
204 EXPECT_TRUE(hasX);
205 EXPECT_TRUE(hasY);
206 EXPECT_TRUE(hasZoom);
207 EXPECT_EQ(0, x);
208 EXPECT_EQ(0, y);
209 EXPECT_EQ(1, zoom);
210 }
211
TEST_F(FPDFDocEmbedderTest,Bug1506First)212 TEST_F(FPDFDocEmbedderTest, Bug1506First) {
213 ASSERT_TRUE(OpenDocument("bug_1506.pdf"));
214
215 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
216 ASSERT_TRUE(dest);
217 EXPECT_EQ(3, FPDFDest_GetDestPageIndex(document(), dest));
218 }
219
TEST_F(FPDFDocEmbedderTest,Bug1506Second)220 TEST_F(FPDFDocEmbedderTest, Bug1506Second) {
221 ASSERT_TRUE(OpenDocument("bug_1506.pdf"));
222
223 std::vector<ScopedEmbedderTestPage> pages;
224 for (int i : {0, 2}) {
225 pages.push_back(LoadScopedPage(i));
226 }
227
228 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
229 ASSERT_TRUE(dest);
230 EXPECT_EQ(3, FPDFDest_GetDestPageIndex(document(), dest));
231 }
232
TEST_F(FPDFDocEmbedderTest,Bug1506Third)233 TEST_F(FPDFDocEmbedderTest, Bug1506Third) {
234 ASSERT_TRUE(OpenDocument("bug_1506.pdf"));
235
236 std::vector<ScopedEmbedderTestPage> pages;
237 for (int i : {0, 1, 3}) {
238 pages.push_back(LoadScopedPage(i));
239 }
240
241 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
242 ASSERT_TRUE(dest);
243 EXPECT_EQ(3, FPDFDest_GetDestPageIndex(document(), dest));
244 }
245
TEST_F(FPDFDocEmbedderTest,Bug680376)246 TEST_F(FPDFDocEmbedderTest, Bug680376) {
247 ASSERT_TRUE(OpenDocument("bug_680376.pdf"));
248
249 // Page number directly in item from Dests NameTree.
250 FPDF_DEST dest = FPDF_GetNamedDestByName(document(), "First");
251 EXPECT_TRUE(dest);
252 EXPECT_EQ(-1, FPDFDest_GetDestPageIndex(document(), dest));
253 }
254
TEST_F(FPDFDocEmbedderTest,Bug821454)255 TEST_F(FPDFDocEmbedderTest, Bug821454) {
256 ASSERT_TRUE(OpenDocument("bug_821454.pdf"));
257
258 ScopedEmbedderTestPage page = LoadScopedPage(0);
259 ASSERT_TRUE(page);
260
261 // Cover some invalid argument cases while we're at it.
262 EXPECT_FALSE(FPDFLink_GetLinkAtPoint(nullptr, 150, 360));
263 EXPECT_EQ(-1, FPDFLink_GetLinkZOrderAtPoint(nullptr, 150, 360));
264
265 FPDF_LINK link1 = FPDFLink_GetLinkAtPoint(page.get(), 150, 360);
266 ASSERT_TRUE(link1);
267 FPDF_LINK link2 = FPDFLink_GetLinkAtPoint(page.get(), 150, 420);
268 ASSERT_TRUE(link2);
269
270 EXPECT_EQ(0, FPDFLink_GetLinkZOrderAtPoint(page.get(), 150, 360));
271 EXPECT_EQ(1, FPDFLink_GetLinkZOrderAtPoint(page.get(), 150, 420));
272
273 FPDF_DEST dest1 = FPDFLink_GetDest(document(), link1);
274 ASSERT_TRUE(dest1);
275 FPDF_DEST dest2 = FPDFLink_GetDest(document(), link2);
276 ASSERT_TRUE(dest2);
277
278 // Cover more invalid argument cases while we're at it.
279 EXPECT_FALSE(FPDFLink_GetDest(nullptr, nullptr));
280 EXPECT_FALSE(FPDFLink_GetDest(nullptr, link1));
281 EXPECT_FALSE(FPDFLink_GetDest(document(), nullptr));
282
283 EXPECT_EQ(0, FPDFDest_GetDestPageIndex(document(), dest1));
284 EXPECT_EQ(0, FPDFDest_GetDestPageIndex(document(), dest2));
285
286 {
287 FPDF_BOOL has_x_coord;
288 FPDF_BOOL has_y_coord;
289 FPDF_BOOL has_zoom;
290 FS_FLOAT x;
291 FS_FLOAT y;
292 FS_FLOAT zoom;
293 FPDF_BOOL success = FPDFDest_GetLocationInPage(
294 dest1, &has_x_coord, &has_y_coord, &has_zoom, &x, &y, &zoom);
295 ASSERT_TRUE(success);
296 EXPECT_TRUE(has_x_coord);
297 EXPECT_TRUE(has_y_coord);
298 EXPECT_FALSE(has_zoom);
299 EXPECT_FLOAT_EQ(100.0f, x);
300 EXPECT_FLOAT_EQ(200.0f, y);
301 }
302 {
303 FPDF_BOOL has_x_coord;
304 FPDF_BOOL has_y_coord;
305 FPDF_BOOL has_zoom;
306 FS_FLOAT x;
307 FS_FLOAT y;
308 FS_FLOAT zoom;
309 FPDF_BOOL success = FPDFDest_GetLocationInPage(
310 dest2, &has_x_coord, &has_y_coord, &has_zoom, &x, &y, &zoom);
311 ASSERT_TRUE(success);
312 EXPECT_TRUE(has_x_coord);
313 EXPECT_TRUE(has_y_coord);
314 EXPECT_FALSE(has_zoom);
315 EXPECT_FLOAT_EQ(150.0f, x);
316 EXPECT_FLOAT_EQ(250.0f, y);
317 }
318 }
319
TEST_F(FPDFDocEmbedderTest,ActionBadArguments)320 TEST_F(FPDFDocEmbedderTest, ActionBadArguments) {
321 ASSERT_TRUE(OpenDocument("launch_action.pdf"));
322 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_UNSUPPORTED),
323 FPDFAction_GetType(nullptr));
324
325 EXPECT_FALSE(FPDFAction_GetDest(nullptr, nullptr));
326 EXPECT_FALSE(FPDFAction_GetDest(document(), nullptr));
327 EXPECT_EQ(0u, FPDFAction_GetFilePath(nullptr, nullptr, 0));
328 EXPECT_EQ(0u, FPDFAction_GetURIPath(nullptr, nullptr, nullptr, 0));
329 EXPECT_EQ(0u, FPDFAction_GetURIPath(document(), nullptr, nullptr, 0));
330 }
331
TEST_F(FPDFDocEmbedderTest,ActionLaunch)332 TEST_F(FPDFDocEmbedderTest, ActionLaunch) {
333 ASSERT_TRUE(OpenDocument("launch_action.pdf"));
334
335 ScopedEmbedderTestPage page = LoadScopedPage(0);
336 ASSERT_TRUE(page);
337
338 // The target action is nearly the size of the whole page.
339 FPDF_LINK link = FPDFLink_GetLinkAtPoint(page.get(), 100, 100);
340 ASSERT_TRUE(link);
341
342 FPDF_ACTION action = FPDFLink_GetAction(link);
343 ASSERT_TRUE(action);
344 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_LAUNCH),
345 FPDFAction_GetType(action));
346
347 const char kExpectedResult[] = "test.pdf";
348 const unsigned long kExpectedLength = sizeof(kExpectedResult);
349 unsigned long bufsize = FPDFAction_GetFilePath(action, nullptr, 0);
350 EXPECT_EQ(kExpectedLength, bufsize);
351
352 char buf[1024];
353 EXPECT_EQ(bufsize, FPDFAction_GetFilePath(action, buf, bufsize));
354 EXPECT_STREQ(kExpectedResult, buf);
355
356 // Other public methods are not appropriate for launch actions.
357 EXPECT_FALSE(FPDFAction_GetDest(document(), action));
358 EXPECT_EQ(0u, FPDFAction_GetURIPath(document(), action, buf, sizeof(buf)));
359 }
360
TEST_F(FPDFDocEmbedderTest,ActionUri)361 TEST_F(FPDFDocEmbedderTest, ActionUri) {
362 ASSERT_TRUE(OpenDocument("uri_action.pdf"));
363
364 ScopedEmbedderTestPage page = LoadScopedPage(0);
365 ASSERT_TRUE(page);
366
367 // The target action is nearly the size of the whole page.
368 FPDF_LINK link = FPDFLink_GetLinkAtPoint(page.get(), 100, 100);
369 ASSERT_TRUE(link);
370
371 FPDF_ACTION action = FPDFLink_GetAction(link);
372 ASSERT_TRUE(action);
373 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_URI),
374 FPDFAction_GetType(action));
375
376 const char kExpectedResult[] = "https://example.com/page.html";
377 const unsigned long kExpectedLength = sizeof(kExpectedResult);
378 unsigned long bufsize = FPDFAction_GetURIPath(document(), action, nullptr, 0);
379 ASSERT_EQ(kExpectedLength, bufsize);
380
381 char buf[1024];
382 EXPECT_EQ(bufsize, FPDFAction_GetURIPath(document(), action, buf, bufsize));
383 EXPECT_STREQ(kExpectedResult, buf);
384
385 // Other public methods are not appropriate for URI actions
386 EXPECT_FALSE(FPDFAction_GetDest(document(), action));
387 EXPECT_EQ(0u, FPDFAction_GetFilePath(action, buf, sizeof(buf)));
388 }
389
TEST_F(FPDFDocEmbedderTest,ActionUriNonAscii)390 TEST_F(FPDFDocEmbedderTest, ActionUriNonAscii) {
391 ASSERT_TRUE(OpenDocument("uri_action_nonascii.pdf"));
392
393 ScopedEmbedderTestPage page = LoadScopedPage(0);
394 ASSERT_TRUE(page);
395
396 // The target action is nearly the size of the whole page.
397 FPDF_LINK link = FPDFLink_GetLinkAtPoint(page.get(), 100, 100);
398 ASSERT_TRUE(link);
399
400 FPDF_ACTION action = FPDFLink_GetAction(link);
401 ASSERT_TRUE(action);
402 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_URI),
403 FPDFAction_GetType(action));
404
405 // FPDFAction_GetURIPath() may return data in any encoding, or even with bad
406 // encoding.
407 const char kExpectedResult[] =
408 "https://example.com/\xA5octal\xC7"
409 "chars";
410 const unsigned long kExpectedLength = sizeof(kExpectedResult);
411 unsigned long bufsize = FPDFAction_GetURIPath(document(), action, nullptr, 0);
412 ASSERT_EQ(kExpectedLength, bufsize);
413
414 char buf[1024];
415 EXPECT_EQ(bufsize, FPDFAction_GetURIPath(document(), action, buf, bufsize));
416 EXPECT_STREQ(kExpectedResult, buf);
417 }
418
TEST_F(FPDFDocEmbedderTest,LinkToAnnotConversion)419 TEST_F(FPDFDocEmbedderTest, LinkToAnnotConversion) {
420 ASSERT_TRUE(OpenDocument("annots.pdf"));
421 ScopedEmbedderTestPage page = LoadScopedPage(0);
422 ASSERT_TRUE(page);
423 {
424 FPDF_LINK first_link = FPDFLink_GetLinkAtPoint(page.get(), 69.00, 653.00);
425 ScopedFPDFAnnotation first_annot(FPDFLink_GetAnnot(page.get(), first_link));
426 EXPECT_EQ(0, FPDFPage_GetAnnotIndex(page.get(), first_annot.get()));
427
428 FPDF_LINK second_link = FPDFLink_GetLinkAtPoint(page.get(), 80.00, 633.00);
429 ScopedFPDFAnnotation second_annot(
430 FPDFLink_GetAnnot(page.get(), second_link));
431 EXPECT_EQ(1, FPDFPage_GetAnnotIndex(page.get(), second_annot.get()));
432
433 // Also test invalid arguments.
434 EXPECT_FALSE(FPDFLink_GetAnnot(nullptr, nullptr));
435 EXPECT_FALSE(FPDFLink_GetAnnot(page.get(), nullptr));
436 EXPECT_FALSE(FPDFLink_GetAnnot(nullptr, second_link));
437 }
438 }
439
TEST_F(FPDFDocEmbedderTest,ActionGoto)440 TEST_F(FPDFDocEmbedderTest, ActionGoto) {
441 ASSERT_TRUE(OpenDocument("goto_action.pdf"));
442
443 ScopedEmbedderTestPage page = LoadScopedPage(0);
444 ASSERT_TRUE(page);
445
446 // The target action is nearly the size of the whole page.
447 FPDF_LINK link = FPDFLink_GetLinkAtPoint(page.get(), 100, 100);
448 ASSERT_TRUE(link);
449
450 FPDF_ACTION action = FPDFLink_GetAction(link);
451 ASSERT_TRUE(action);
452 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_GOTO),
453 FPDFAction_GetType(action));
454
455 EXPECT_TRUE(FPDFAction_GetDest(document(), action));
456
457 // Other public methods are not appropriate for GoTo actions.
458 char buf[1024];
459 EXPECT_EQ(0u, FPDFAction_GetFilePath(action, buf, sizeof(buf)));
460 EXPECT_EQ(0u, FPDFAction_GetURIPath(document(), action, buf, sizeof(buf)));
461 }
462
TEST_F(FPDFDocEmbedderTest,ActionEmbeddedGoto)463 TEST_F(FPDFDocEmbedderTest, ActionEmbeddedGoto) {
464 ASSERT_TRUE(OpenDocument("gotoe_action.pdf"));
465
466 ScopedEmbedderTestPage page = LoadScopedPage(0);
467 ASSERT_TRUE(page);
468
469 // The target action is nearly the size of the whole page.
470 FPDF_LINK link = FPDFLink_GetLinkAtPoint(page.get(), 100, 100);
471 ASSERT_TRUE(link);
472
473 FPDF_ACTION action = FPDFLink_GetAction(link);
474 ASSERT_TRUE(action);
475 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_EMBEDDEDGOTO),
476 FPDFAction_GetType(action));
477
478 FPDF_DEST dest = FPDFAction_GetDest(document(), action);
479 EXPECT_TRUE(dest);
480
481 unsigned long num_params = 42;
482 FS_FLOAT params[4];
483 std::fill_n(params, 4, 42.4242f);
484 EXPECT_EQ(static_cast<unsigned long>(PDFDEST_VIEW_FIT),
485 FPDFDest_GetView(dest, &num_params, params));
486 EXPECT_EQ(0u, num_params);
487 EXPECT_FLOAT_EQ(42.4242f, params[0]);
488
489 const char kExpectedResult[] = "ExampleFile.pdf";
490 const unsigned long kExpectedLength = sizeof(kExpectedResult);
491 char buf[1024];
492 unsigned long bufsize = FPDFAction_GetFilePath(action, nullptr, 0);
493 EXPECT_EQ(kExpectedLength, bufsize);
494 EXPECT_EQ(kExpectedLength, FPDFAction_GetFilePath(action, buf, bufsize));
495 EXPECT_STREQ(kExpectedResult, buf);
496 }
497
TEST_F(FPDFDocEmbedderTest,ActionNonesuch)498 TEST_F(FPDFDocEmbedderTest, ActionNonesuch) {
499 ASSERT_TRUE(OpenDocument("nonesuch_action.pdf"));
500
501 ScopedEmbedderTestPage page = LoadScopedPage(0);
502 ASSERT_TRUE(page);
503
504 // The target action is nearly the size of the whole page.
505 FPDF_LINK link = FPDFLink_GetLinkAtPoint(page.get(), 100, 100);
506 ASSERT_TRUE(link);
507
508 FPDF_ACTION action = FPDFLink_GetAction(link);
509 ASSERT_TRUE(action);
510 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_UNSUPPORTED),
511 FPDFAction_GetType(action));
512
513 // No public methods are appropriate for unsupported actions.
514 char buf[1024];
515 EXPECT_FALSE(FPDFAction_GetDest(document(), action));
516 EXPECT_EQ(0u, FPDFAction_GetFilePath(action, buf, sizeof(buf)));
517 EXPECT_EQ(0u, FPDFAction_GetURIPath(document(), action, buf, sizeof(buf)));
518 }
519
TEST_F(FPDFDocEmbedderTest,NoBookmarks)520 TEST_F(FPDFDocEmbedderTest, NoBookmarks) {
521 unsigned short buf[128];
522
523 // Open a file with no bookmarks.
524 ASSERT_TRUE(OpenDocument("named_dests.pdf"));
525
526 // NULL argument cases.
527 EXPECT_EQ(0u, FPDFBookmark_GetTitle(nullptr, buf, sizeof(buf)));
528 EXPECT_FALSE(FPDFBookmark_GetFirstChild(nullptr, nullptr));
529 EXPECT_FALSE(FPDFBookmark_GetFirstChild(document(), nullptr));
530 EXPECT_FALSE(FPDFBookmark_GetNextSibling(nullptr, nullptr));
531 EXPECT_FALSE(FPDFBookmark_GetNextSibling(document(), nullptr));
532 EXPECT_FALSE(FPDFBookmark_Find(nullptr, nullptr));
533 EXPECT_FALSE(FPDFBookmark_Find(document(), nullptr));
534 EXPECT_FALSE(FPDFBookmark_GetDest(nullptr, nullptr));
535 EXPECT_FALSE(FPDFBookmark_GetDest(document(), nullptr));
536 EXPECT_FALSE(FPDFBookmark_GetAction(nullptr));
537 }
538
TEST_F(FPDFDocEmbedderTest,Bookmarks)539 TEST_F(FPDFDocEmbedderTest, Bookmarks) {
540 unsigned short buf[128];
541
542 // Open a file with many bookmarks.
543 ASSERT_TRUE(OpenDocument("bookmarks.pdf"));
544
545 FPDF_BOOKMARK child = FPDFBookmark_GetFirstChild(document(), nullptr);
546 EXPECT_TRUE(child);
547 EXPECT_EQ(34u, FPDFBookmark_GetTitle(child, buf, sizeof(buf)));
548 EXPECT_EQ(L"A Good Beginning", GetPlatformWString(buf));
549 EXPECT_EQ(0, FPDFBookmark_GetCount(child));
550 EXPECT_EQ(0, FPDFBookmark_GetCount(nullptr));
551
552 EXPECT_FALSE(FPDFBookmark_GetDest(document(), child));
553 EXPECT_FALSE(FPDFBookmark_GetAction(child));
554
555 FPDF_BOOKMARK grand_child = FPDFBookmark_GetFirstChild(document(), child);
556 EXPECT_FALSE(grand_child);
557
558 FPDF_BOOKMARK sibling = FPDFBookmark_GetNextSibling(document(), child);
559 EXPECT_TRUE(sibling);
560 EXPECT_EQ(24u, FPDFBookmark_GetTitle(sibling, buf, sizeof(buf)));
561 EXPECT_EQ(L"Open Middle", GetPlatformWString(buf));
562 EXPECT_TRUE(FPDFBookmark_GetAction(sibling));
563 EXPECT_EQ(1, FPDFBookmark_GetCount(sibling));
564
565 FPDF_BOOKMARK sibling2 = FPDFBookmark_GetNextSibling(document(), sibling);
566 EXPECT_TRUE(sibling2);
567 EXPECT_EQ(42u, FPDFBookmark_GetTitle(sibling2, buf, sizeof(buf)));
568 EXPECT_EQ(L"A Good Closed Ending", GetPlatformWString(buf));
569 EXPECT_EQ(-2, FPDFBookmark_GetCount(sibling2));
570
571 EXPECT_FALSE(FPDFBookmark_GetNextSibling(document(), sibling2));
572
573 grand_child = FPDFBookmark_GetFirstChild(document(), sibling);
574 EXPECT_TRUE(grand_child);
575 EXPECT_EQ(46u, FPDFBookmark_GetTitle(grand_child, buf, sizeof(buf)));
576 EXPECT_EQ(L"Open Middle Descendant", GetPlatformWString(buf));
577 EXPECT_EQ(0, FPDFBookmark_GetCount(grand_child));
578 EXPECT_TRUE(FPDFBookmark_GetDest(document(), grand_child));
579
580 EXPECT_FALSE(FPDFBookmark_GetNextSibling(document(), grand_child));
581 }
582
TEST_F(FPDFDocEmbedderTest,FindBookmarks)583 TEST_F(FPDFDocEmbedderTest, FindBookmarks) {
584 unsigned short buf[128];
585
586 // Open a file with many bookmarks.
587 ASSERT_TRUE(OpenDocument("bookmarks.pdf"));
588
589 // Find the first one, based on its known title.
590 ScopedFPDFWideString title = GetFPDFWideString(L"A Good Beginning");
591 FPDF_BOOKMARK child = FPDFBookmark_Find(document(), title.get());
592 EXPECT_TRUE(child);
593
594 // Check that the string matches.
595 EXPECT_EQ(34u, FPDFBookmark_GetTitle(child, buf, sizeof(buf)));
596 EXPECT_EQ(L"A Good Beginning", GetPlatformWString(buf));
597
598 // Check that it is them same as the one returned by GetFirstChild.
599 EXPECT_EQ(child, FPDFBookmark_GetFirstChild(document(), nullptr));
600
601 // Try to find one using a non-existent title.
602 ScopedFPDFWideString bad_title = GetFPDFWideString(L"A BAD Beginning");
603 EXPECT_FALSE(FPDFBookmark_Find(document(), bad_title.get()));
604 }
605
606 // Check circular bookmarks will not cause infinite loop.
TEST_F(FPDFDocEmbedderTest,FindBookmarksBug420)607 TEST_F(FPDFDocEmbedderTest, FindBookmarksBug420) {
608 // Open a file with circular bookmarks.
609 ASSERT_TRUE(OpenDocument("bookmarks_circular.pdf"));
610
611 // Try to find a title.
612 ScopedFPDFWideString title = GetFPDFWideString(L"anything");
613 EXPECT_FALSE(FPDFBookmark_Find(document(), title.get()));
614 }
615
TEST_F(FPDFDocEmbedderTest,DeletePage)616 TEST_F(FPDFDocEmbedderTest, DeletePage) {
617 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
618 EXPECT_EQ(1, FPDF_GetPageCount(document()));
619
620 FPDFPage_Delete(nullptr, 0);
621 EXPECT_EQ(1, FPDF_GetPageCount(document()));
622
623 FPDFPage_Delete(document(), -1);
624 EXPECT_EQ(1, FPDF_GetPageCount(document()));
625 FPDFPage_Delete(document(), 1);
626 EXPECT_EQ(1, FPDF_GetPageCount(document()));
627
628 FPDFPage_Delete(document(), 0);
629 EXPECT_EQ(0, FPDF_GetPageCount(document()));
630 }
631
TEST_F(FPDFDocEmbedderTest,DeletePageAndRender)632 TEST_F(FPDFDocEmbedderTest, DeletePageAndRender) {
633 struct PageData {
634 int width;
635 int height;
636 const char* checksum;
637 };
638 const std::array<const PageData, 5> expected_page_data = {{
639 {200, 250,
640 []() {
641 return CFX_DefaultRenderDevice::UseSkiaRenderer()
642 ? "4b6590a267eae90b8be1607e808fb57f"
643 : "1e5d1cf19ffbb9cf9dbf099483cea327";
644 }()},
645 {250, 200,
646 []() {
647 return CFX_DefaultRenderDevice::UseSkiaRenderer()
648 ? "e8edd3655f6629ff489bd8c3bb110c82"
649 : "65c80685916aa36e767dd2270ba4d72b";
650 }()},
651 {200, 250,
652 []() {
653 return CFX_DefaultRenderDevice::UseSkiaRenderer()
654 ? "a2bde6b68d7981e665ab25bc633746aa"
655 : "a53b21c68edf43c1cddb5c06e361bb45";
656 }()},
657 {200, 250,
658 []() {
659 return CFX_DefaultRenderDevice::UseSkiaRenderer()
660 ? "a8c5b3e626f665eddf593c6d4c32ae9e"
661 : "dcd768be15efb9c6e5093cf74508752c";
662 }()},
663 {200, 250,
664 []() {
665 return CFX_DefaultRenderDevice::UseSkiaRenderer()
666 ? "72eb157853ae2d19b70ea62e3f5ac202"
667 : "7a3f8f79ebcb350854c0d69607729ec5";
668 }()},
669 }};
670
671 // Render the original document. (page indices 0-4)
672 ASSERT_TRUE(OpenDocument("rectangles_multi_pages.pdf"));
673 EXPECT_EQ(5, FPDF_GetPageCount(document()));
674 for (int i = 0; i < 5; ++i) {
675 ScopedEmbedderTestPage page = LoadScopedPage(i);
676 ASSERT_TRUE(page);
677 ScopedFPDFBitmap bitmap = RenderLoadedPage(page.get());
678 const PageData& expected = expected_page_data[i];
679 CompareBitmap(bitmap.get(), expected.width, expected.height,
680 expected.checksum);
681 }
682
683 // Delete the first page and render again. (original page indices 1-4)
684 FPDFPage_Delete(document(), 0);
685 EXPECT_EQ(4, FPDF_GetPageCount(document()));
686 for (int i = 0; i < 4; ++i) {
687 ScopedEmbedderTestPage page = LoadScopedPage(i);
688 ASSERT_TRUE(page);
689 ScopedFPDFBitmap bitmap = RenderLoadedPage(page.get());
690 const PageData& expected = expected_page_data[i + 1];
691 CompareBitmap(bitmap.get(), expected.width, expected.height,
692 expected.checksum);
693 }
694
695 // Delete the last page and render again. (original page indices 1-3)
696 FPDFPage_Delete(document(), 3);
697 EXPECT_EQ(3, FPDF_GetPageCount(document()));
698 for (int i = 0; i < 3; ++i) {
699 ScopedEmbedderTestPage page = LoadScopedPage(i);
700 ASSERT_TRUE(page);
701 ScopedFPDFBitmap bitmap = RenderLoadedPage(page.get());
702 const PageData& expected = expected_page_data[i + 1];
703 CompareBitmap(bitmap.get(), expected.width, expected.height,
704 expected.checksum);
705 }
706
707 // Delete the middle page and render again. (original page indices 1, 3)
708 FPDFPage_Delete(document(), 1);
709 EXPECT_EQ(2, FPDF_GetPageCount(document()));
710 for (int i = 0; i < 2; ++i) {
711 ScopedEmbedderTestPage page = LoadScopedPage(i);
712 ASSERT_TRUE(page);
713 ScopedFPDFBitmap bitmap = RenderLoadedPage(page.get());
714 int adjusted_index = i == 0 ? 1 : 3;
715 const PageData& expected = expected_page_data[adjusted_index];
716 CompareBitmap(bitmap.get(), expected.width, expected.height,
717 expected.checksum);
718 }
719 }
720
TEST_F(FPDFDocEmbedderTest,DeletePageAndSaveWithBookmarks)721 TEST_F(FPDFDocEmbedderTest, DeletePageAndSaveWithBookmarks) {
722 // The bookmarks reference the deleted page.
723 ASSERT_TRUE(OpenDocument("bookmarks.pdf"));
724
725 EXPECT_EQ(2, FPDF_GetPageCount(document()));
726 FPDFPage_Delete(document(), 0);
727 EXPECT_EQ(1, FPDF_GetPageCount(document()));
728
729 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
730 EXPECT_EQ(1, CountPageEntries(GetString()));
731 EXPECT_EQ(1, CountStreamEntries(GetString()));
732 }
733
TEST_F(FPDFDocEmbedderTest,DeletePageAndSaveWithCustomObject)734 TEST_F(FPDFDocEmbedderTest, DeletePageAndSaveWithCustomObject) {
735 // There exists a non-standard object that references the deleted page.
736 ASSERT_TRUE(OpenDocument("hello_world_2_pages_custom_object.pdf"));
737
738 EXPECT_EQ(2, FPDF_GetPageCount(document()));
739 FPDFPage_Delete(document(), 0);
740 EXPECT_EQ(1, FPDF_GetPageCount(document()));
741
742 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
743 EXPECT_EQ(1, CountPageEntries(GetString()));
744 EXPECT_EQ(1, CountStreamEntries(GetString()));
745 }
746
TEST_F(FPDFDocEmbedderTest,DeletePageAndSaveWithCustomObjectForNewPage)747 TEST_F(FPDFDocEmbedderTest, DeletePageAndSaveWithCustomObjectForNewPage) {
748 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
749
750 EXPECT_EQ(1, FPDF_GetPageCount(document()));
751
752 {
753 ScopedFPDFPage new_page(FPDFPage_New(document(), 1, 300, 200));
754 ASSERT_TRUE(new_page);
755 EXPECT_EQ(2, FPDF_GetPageCount(document()));
756
757 // Add a non-standard object that references the newly created page.
758 CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document());
759 ASSERT_TRUE(doc);
760
761 CPDF_Page* page = CPDFPageFromFPDFPage(new_page.get());
762 ASSERT_TRUE(page);
763
764 RetainPtr<CPDF_Dictionary> root_dict = doc->GetMutableRoot();
765 ASSERT_TRUE(root_dict);
766 root_dict->SetNewFor<CPDF_Reference>("CustomField", doc,
767 page->GetDict()->GetObjNum());
768 }
769
770 FPDFPage_Delete(document(), 1);
771 EXPECT_EQ(1, FPDF_GetPageCount(document()));
772
773 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
774 EXPECT_EQ(1, CountPageEntries(GetString()));
775 EXPECT_EQ(1, CountStreamEntries(GetString()));
776 }
777
TEST_F(FPDFDocEmbedderTest,DeletePageAndSaveForPageWithMultipleUses)778 TEST_F(FPDFDocEmbedderTest, DeletePageAndSaveForPageWithMultipleUses) {
779 // The deleted pages both use the same /Page object.
780 ASSERT_TRUE(OpenDocument("bug_1229106.pdf"));
781
782 EXPECT_EQ(4, FPDF_GetPageCount(document()));
783 FPDFPage_Delete(document(), 0);
784 EXPECT_EQ(3, FPDF_GetPageCount(document()));
785
786 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
787 EXPECT_EQ(2, CountPageEntries(GetString()));
788 EXPECT_EQ(2, CountStreamEntries(GetString()));
789
790 ClearString();
791 FPDFPage_Delete(document(), 0);
792 EXPECT_EQ(2, FPDF_GetPageCount(document()));
793
794 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
795 EXPECT_EQ(1, CountPageEntries(GetString()));
796 EXPECT_EQ(1, CountStreamEntries(GetString()));
797 }
798
TEST_F(FPDFDocEmbedderTest,GetFileIdentifier)799 TEST_F(FPDFDocEmbedderTest, GetFileIdentifier) {
800 ASSERT_TRUE(OpenDocument("split_streams.pdf"));
801 constexpr size_t kMd5Length = 17;
802 char buf[kMd5Length];
803 EXPECT_EQ(0u,
804 FPDF_GetFileIdentifier(document(), static_cast<FPDF_FILEIDTYPE>(-1),
805 buf, sizeof(buf)));
806 EXPECT_EQ(0u,
807 FPDF_GetFileIdentifier(document(), static_cast<FPDF_FILEIDTYPE>(2),
808 buf, sizeof(buf)));
809 EXPECT_EQ(0u, FPDF_GetFileIdentifier(nullptr, FILEIDTYPE_PERMANENT, buf,
810 sizeof(buf)));
811 EXPECT_EQ(kMd5Length, FPDF_GetFileIdentifier(document(), FILEIDTYPE_PERMANENT,
812 nullptr, 0));
813
814 constexpr char kExpectedPermanent[] =
815 "\xF3\x41\xAE\x65\x4A\x77\xAC\xD5\x06\x5A\x76\x45\xE5\x96\xE6\xE6";
816 ASSERT_EQ(kMd5Length, FPDF_GetFileIdentifier(document(), FILEIDTYPE_PERMANENT,
817 buf, sizeof(buf)));
818 EXPECT_EQ(kExpectedPermanent, ByteString(buf));
819
820 constexpr char kExpectedChanging[] =
821 "\xBC\x37\x29\x8A\x3F\x87\xF4\x79\x22\x9B\xCE\x99\x7C\xA7\x91\xF7";
822 ASSERT_EQ(kMd5Length, FPDF_GetFileIdentifier(document(), FILEIDTYPE_CHANGING,
823 buf, sizeof(buf)));
824 EXPECT_EQ(kExpectedChanging, ByteString(buf));
825 }
826
TEST_F(FPDFDocEmbedderTest,GetNonHexFileIdentifier)827 TEST_F(FPDFDocEmbedderTest, GetNonHexFileIdentifier) {
828 ASSERT_TRUE(OpenDocument("non_hex_file_id.pdf"));
829 char buf[18];
830
831 constexpr char kPermanentNonHex[] = "permanent non-hex";
832 ASSERT_EQ(18u, FPDF_GetFileIdentifier(document(), FILEIDTYPE_PERMANENT, buf,
833 sizeof(buf)));
834 EXPECT_EQ(kPermanentNonHex, ByteString(buf));
835
836 constexpr char kChangingNonHex[] = "changing non-hex";
837 ASSERT_EQ(17u, FPDF_GetFileIdentifier(document(), FILEIDTYPE_CHANGING, buf,
838 sizeof(buf)));
839 EXPECT_EQ(kChangingNonHex, ByteString(buf));
840 }
841
TEST_F(FPDFDocEmbedderTest,GetNonexistentFileIdentifier)842 TEST_F(FPDFDocEmbedderTest, GetNonexistentFileIdentifier) {
843 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
844 EXPECT_EQ(
845 0u, FPDF_GetFileIdentifier(document(), FILEIDTYPE_PERMANENT, nullptr, 0));
846 EXPECT_EQ(
847 0u, FPDF_GetFileIdentifier(document(), FILEIDTYPE_CHANGING, nullptr, 0));
848 }
849
TEST_F(FPDFDocEmbedderTest,GetMetaText)850 TEST_F(FPDFDocEmbedderTest, GetMetaText) {
851 ASSERT_TRUE(OpenDocument("bug_601362.pdf"));
852
853 // Invalid document / tag results in 0.
854 unsigned short buf[128];
855 EXPECT_EQ(0u, FPDF_GetMetaText(document(), nullptr, buf, sizeof(buf)));
856 EXPECT_EQ(0u, FPDF_GetMetaText(nullptr, "", buf, sizeof(buf)));
857
858 // Tags that do not eixst results in an empty wide string.
859 EXPECT_EQ(2u, FPDF_GetMetaText(document(), "", buf, sizeof(buf)));
860 EXPECT_EQ(2u, FPDF_GetMetaText(document(), "foo", buf, sizeof(buf)));
861 ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Title", buf, sizeof(buf)));
862 ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Author", buf, sizeof(buf)));
863 ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Subject", buf, sizeof(buf)));
864 ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Keywords", buf, sizeof(buf)));
865 ASSERT_EQ(2u, FPDF_GetMetaText(document(), "Producer", buf, sizeof(buf)));
866
867 ASSERT_EQ(30u, FPDF_GetMetaText(document(), "Creator", buf, sizeof(buf)));
868 EXPECT_EQ(L"Microsoft Word", GetPlatformWString(buf));
869
870 ASSERT_EQ(48u,
871 FPDF_GetMetaText(document(), "CreationDate", buf, sizeof(buf)));
872 EXPECT_EQ(L"D:20160411190039+00'00'", GetPlatformWString(buf));
873
874 ASSERT_EQ(48u, FPDF_GetMetaText(document(), "ModDate", buf, sizeof(buf)));
875 EXPECT_EQ(L"D:20160411190039+00'00'", GetPlatformWString(buf));
876 }
877
TEST_F(FPDFDocEmbedderTest,Utf8Metadata)878 TEST_F(FPDFDocEmbedderTest, Utf8Metadata) {
879 ASSERT_TRUE(OpenDocument("utf-8.pdf"));
880
881 unsigned short buf[128];
882
883 ASSERT_EQ(34u, FPDF_GetMetaText(document(), "Producer", buf, sizeof(buf)));
884 EXPECT_EQ(L"Manüally Created", GetPlatformWString(buf));
885
886 FPDF_BOOKMARK child = FPDFBookmark_GetFirstChild(document(), nullptr);
887 EXPECT_TRUE(child);
888 EXPECT_EQ(16u, FPDFBookmark_GetTitle(child, buf, sizeof(buf)));
889 EXPECT_EQ(L"Titlè 1", GetPlatformWString(buf));
890 }
891
TEST_F(FPDFDocEmbedderTest,Bug182)892 TEST_F(FPDFDocEmbedderTest, Bug182) {
893 ASSERT_TRUE(OpenDocument("bug_182.pdf"));
894
895 unsigned short buf[128];
896
897 ASSERT_EQ(48u, FPDF_GetMetaText(document(), "Title", buf, sizeof(buf)));
898 EXPECT_EQ(L"Super Visual Formade 印刷", GetPlatformWString(buf));
899 }
900
TEST_F(FPDFDocEmbedderTest,GetMetaTextSameObjectNumber)901 TEST_F(FPDFDocEmbedderTest, GetMetaTextSameObjectNumber) {
902 ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf"));
903
904 // The PDF has been edited. It has two %%EOF markers, and 2 objects numbered
905 // (1 0). Both objects are /Info dictionaries, but contain different data.
906 // Make sure ModDate is the date of the last modification.
907 unsigned short buf[128];
908 ASSERT_EQ(48u, FPDF_GetMetaText(document(), "ModDate", buf, sizeof(buf)));
909 EXPECT_EQ(L"D:20170612232940-04'00'", GetPlatformWString(buf));
910 }
911
TEST_F(FPDFDocEmbedderTest,GetMetaTextInAttachmentFile)912 TEST_F(FPDFDocEmbedderTest, GetMetaTextInAttachmentFile) {
913 ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
914
915 // Make sure this is the date from the PDF itself and not the attached PDF.
916 unsigned short buf[128];
917 ASSERT_EQ(48u, FPDF_GetMetaText(document(), "ModDate", buf, sizeof(buf)));
918 EXPECT_EQ(L"D:20170712214448-07'00'", GetPlatformWString(buf));
919 }
920
TEST_F(FPDFDocEmbedderTest,GetMetaTextFromNewDocument)921 TEST_F(FPDFDocEmbedderTest, GetMetaTextFromNewDocument) {
922 ScopedFPDFDocument empty_doc(FPDF_CreateNewDocument());
923 unsigned short buf[128];
924 EXPECT_EQ(2u, FPDF_GetMetaText(empty_doc.get(), "Title", buf, sizeof(buf)));
925 }
926
TEST_F(FPDFDocEmbedderTest,GetPageAAction)927 TEST_F(FPDFDocEmbedderTest, GetPageAAction) {
928 ASSERT_TRUE(OpenDocument("get_page_aaction.pdf"));
929 ScopedEmbedderTestPage page = LoadScopedPage(0);
930 EXPECT_TRUE(page);
931
932 EXPECT_FALSE(FPDF_GetPageAAction(nullptr, FPDFPAGE_AACTION_OPEN));
933 EXPECT_FALSE(FPDF_GetPageAAction(page.get(), FPDFPAGE_AACTION_CLOSE));
934 EXPECT_FALSE(FPDF_GetPageAAction(page.get(), -1));
935 EXPECT_FALSE(FPDF_GetPageAAction(page.get(), 999));
936
937 FPDF_ACTION action = FPDF_GetPageAAction(page.get(), FPDFPAGE_AACTION_OPEN);
938 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_EMBEDDEDGOTO),
939 FPDFAction_GetType(action));
940
941 const char kExpectedResult[] = "\\\\127.0.0.1\\c$\\Program Files\\test.exe";
942 const unsigned long kExpectedLength = sizeof(kExpectedResult);
943 char buf[1024];
944
945 unsigned long bufsize = FPDFAction_GetFilePath(action, nullptr, 0);
946 EXPECT_EQ(kExpectedLength, bufsize);
947 EXPECT_EQ(kExpectedLength, FPDFAction_GetFilePath(action, buf, bufsize));
948 EXPECT_STREQ(kExpectedResult, buf);
949
950 ScopedEmbedderTestPage page1 = LoadScopedPage(1);
951
952 EXPECT_TRUE(page1.get());
953 EXPECT_FALSE(FPDF_GetPageAAction(page1.get(), -1));
954 }
955
TEST_F(FPDFDocEmbedderTest,NoPageLabels)956 TEST_F(FPDFDocEmbedderTest, NoPageLabels) {
957 ASSERT_TRUE(OpenDocument("about_blank.pdf"));
958 EXPECT_EQ(1, FPDF_GetPageCount(document()));
959
960 ASSERT_EQ(0u, FPDF_GetPageLabel(document(), 0, nullptr, 0));
961 }
962
TEST_F(FPDFDocEmbedderTest,GetPageLabels)963 TEST_F(FPDFDocEmbedderTest, GetPageLabels) {
964 ASSERT_TRUE(OpenDocument("page_labels.pdf"));
965 EXPECT_EQ(7, FPDF_GetPageCount(document()));
966
967 // We do not request labels, when use FPDFAvail_IsXXXAvail.
968 // Flush all data, to allow read labels.
969 SetWholeFileAvailable();
970
971 unsigned short buf[128];
972 EXPECT_EQ(0u, FPDF_GetPageLabel(document(), -2, buf, sizeof(buf)));
973 EXPECT_EQ(0u, FPDF_GetPageLabel(document(), -1, buf, sizeof(buf)));
974
975 ASSERT_EQ(4u, FPDF_GetPageLabel(document(), 0, buf, sizeof(buf)));
976 EXPECT_EQ(L"i", GetPlatformWString(buf));
977
978 ASSERT_EQ(6u, FPDF_GetPageLabel(document(), 1, buf, sizeof(buf)));
979 EXPECT_EQ(L"ii", GetPlatformWString(buf));
980
981 ASSERT_EQ(4u, FPDF_GetPageLabel(document(), 2, buf, sizeof(buf)));
982 EXPECT_EQ(L"1", GetPlatformWString(buf));
983
984 ASSERT_EQ(4u, FPDF_GetPageLabel(document(), 3, buf, sizeof(buf)));
985 EXPECT_EQ(L"2", GetPlatformWString(buf));
986
987 ASSERT_EQ(8u, FPDF_GetPageLabel(document(), 4, buf, sizeof(buf)));
988 EXPECT_EQ(L"zzA", GetPlatformWString(buf));
989
990 ASSERT_EQ(8u, FPDF_GetPageLabel(document(), 5, buf, sizeof(buf)));
991 EXPECT_EQ(L"zzB", GetPlatformWString(buf));
992
993 ASSERT_EQ(2u, FPDF_GetPageLabel(document(), 6, buf, sizeof(buf)));
994 EXPECT_EQ(L"", GetPlatformWString(buf));
995
996 ASSERT_EQ(0u, FPDF_GetPageLabel(document(), 7, buf, sizeof(buf)));
997 ASSERT_EQ(0u, FPDF_GetPageLabel(document(), 8, buf, sizeof(buf)));
998 }
999
1000 #ifdef PDF_ENABLE_XFA
TEST_F(FPDFDocEmbedderTest,GetXFALinks)1001 TEST_F(FPDFDocEmbedderTest, GetXFALinks) {
1002 ASSERT_TRUE(OpenDocument("simple_xfa.pdf"));
1003
1004 ScopedFPDFPage page(FPDF_LoadPage(document(), 0));
1005 ASSERT_TRUE(page);
1006
1007 FPDFLink_GetLinkAtPoint(page.get(), 150, 360);
1008 FPDFLink_GetLinkAtPoint(page.get(), 150, 420);
1009
1010 // Test passes if it doesn't crash. See https://crbug.com/840922
1011 }
1012 #endif // PDF_ENABLE_XFA
1013