1// Copyright 2015 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <limits>
6#include <string>
7
8#include "fpdfsdk/src/fpdfview_c_api_test.h"
9#include "public/fpdfview.h"
10#include "testing/embedder_test.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13TEST(fpdf, CApiTest) {
14  EXPECT_TRUE(CheckPDFiumCApi());
15}
16
17class FPDFViewEmbeddertest : public EmbedderTest {};
18
19TEST_F(FPDFViewEmbeddertest, Document) {
20  EXPECT_TRUE(OpenDocument("about_blank.pdf"));
21  EXPECT_EQ(1, GetPageCount());
22  EXPECT_EQ(0, GetFirstPageNum());
23
24  int version;
25  EXPECT_TRUE(FPDF_GetFileVersion(document(), &version));
26  EXPECT_EQ(14, version);
27
28  EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocPermissions(document()));
29  EXPECT_EQ(-1, FPDF_GetSecurityHandlerRevision(document()));
30}
31
32TEST_F(FPDFViewEmbeddertest, Page) {
33  EXPECT_TRUE(OpenDocument("about_blank.pdf"));
34  FPDF_PAGE page = LoadPage(0);
35  EXPECT_NE(nullptr, page);
36  EXPECT_EQ(612.0, FPDF_GetPageWidth(page));
37  EXPECT_EQ(792.0, FPDF_GetPageHeight(page));
38  UnloadPage(page);
39  EXPECT_EQ(nullptr, LoadPage(1));
40}
41
42TEST_F(FPDFViewEmbeddertest, ViewerRef) {
43  EXPECT_TRUE(OpenDocument("about_blank.pdf"));
44  EXPECT_TRUE(FPDF_VIEWERREF_GetPrintScaling(document()));
45  EXPECT_EQ(1, FPDF_VIEWERREF_GetNumCopies(document()));
46  EXPECT_EQ(DuplexUndefined, FPDF_VIEWERREF_GetDuplex(document()));
47}
48
49TEST_F(FPDFViewEmbeddertest, NamedDests) {
50  EXPECT_TRUE(OpenDocument("named_dests.pdf"));
51  long buffer_size;
52  char fixed_buffer[512];
53  FPDF_DEST dest;
54
55  // Query the size of the first item.
56  buffer_size = 2000000;  // Absurdly large, check not used for this case.
57  dest = FPDF_GetNamedDest(document(), 0, nullptr, &buffer_size);
58  EXPECT_NE(nullptr, dest);
59  EXPECT_EQ(12u, buffer_size);
60
61  // Try to retrieve the first item with too small a buffer.
62  buffer_size = 10;
63  dest = FPDF_GetNamedDest(document(), 0, fixed_buffer, &buffer_size);
64  EXPECT_NE(nullptr, dest);
65  EXPECT_EQ(-1, buffer_size);
66
67  // Try to retrieve the first item with correctly sized buffer. Item is
68  // taken from Dests NameTree in named_dests.pdf.
69  buffer_size = 12;
70  dest = FPDF_GetNamedDest(document(), 0, fixed_buffer, &buffer_size);
71  EXPECT_NE(nullptr, dest);
72  EXPECT_EQ(12u, buffer_size);
73  EXPECT_EQ(std::string("F\0i\0r\0s\0t\0\0\0", 12),
74            std::string(fixed_buffer, buffer_size));
75
76  // Try to retrieve the second item with ample buffer. Item is taken
77  // from Dests NameTree but has a sub-dictionary in named_dests.pdf.
78  buffer_size = sizeof(fixed_buffer);
79  dest = FPDF_GetNamedDest(document(), 1, fixed_buffer, &buffer_size);
80  EXPECT_NE(nullptr, dest);
81  EXPECT_EQ(10u, buffer_size);
82  EXPECT_EQ(std::string("N\0e\0x\0t\0\0\0", 10),
83            std::string(fixed_buffer, buffer_size));
84
85  // Try to retrieve third item with ample buffer. Item is taken
86  // from Dests NameTree but has a bad sub-dictionary in named_dests.pdf.
87  // in named_dests.pdf).
88  buffer_size = sizeof(fixed_buffer);
89  dest = FPDF_GetNamedDest(document(), 2, fixed_buffer, &buffer_size);
90  EXPECT_EQ(nullptr, dest);
91  EXPECT_EQ(sizeof(fixed_buffer), buffer_size);  // unmodified.
92
93  // Try to retrieve the forth item with ample buffer. Item is taken
94  // from Dests NameTree but has a vale of the wrong type in named_dests.pdf.
95  buffer_size = sizeof(fixed_buffer);
96  dest = FPDF_GetNamedDest(document(), 3, fixed_buffer, &buffer_size);
97  EXPECT_EQ(nullptr, dest);
98  EXPECT_EQ(sizeof(fixed_buffer), buffer_size);  // unmodified.
99
100  // Try to retrieve fifth item with ample buffer. Item taken from the
101  // old-style Dests dictionary object in named_dests.pdf.
102  buffer_size = sizeof(fixed_buffer);
103  dest = FPDF_GetNamedDest(document(), 4, fixed_buffer, &buffer_size);
104  EXPECT_NE(nullptr, dest);
105  EXPECT_EQ(30u, buffer_size);
106  EXPECT_EQ(std::string("F\0i\0r\0s\0t\0A\0l\0t\0e\0r\0n\0a\0t\0e\0\0\0", 30),
107            std::string(fixed_buffer, buffer_size));
108
109  // Try to retrieve sixth item with ample buffer. Item istaken from the
110  // old-style Dests dictionary object but has a sub-dictionary in
111  // named_dests.pdf.
112  buffer_size = sizeof(fixed_buffer);
113  dest = FPDF_GetNamedDest(document(), 5, fixed_buffer, &buffer_size);
114  EXPECT_NE(nullptr, dest);
115  EXPECT_EQ(28u, buffer_size);
116  EXPECT_EQ(std::string("L\0a\0s\0t\0A\0l\0t\0e\0r\0n\0a\0t\0e\0\0\0", 28),
117            std::string(fixed_buffer, buffer_size));
118
119  // Try to retrieve non-existent item with ample buffer.
120  buffer_size = sizeof(fixed_buffer);
121  dest = FPDF_GetNamedDest(document(), 6, fixed_buffer, &buffer_size);
122  EXPECT_EQ(nullptr, dest);
123  EXPECT_EQ(sizeof(fixed_buffer), buffer_size);  // unmodified.
124
125  // Try to underflow/overflow the integer index.
126  buffer_size = sizeof(fixed_buffer);
127  dest = FPDF_GetNamedDest(document(), std::numeric_limits<int>::max(),
128                           fixed_buffer, &buffer_size);
129  EXPECT_EQ(nullptr, dest);
130  EXPECT_EQ(sizeof(fixed_buffer), buffer_size);  // unmodified.
131
132  buffer_size = sizeof(fixed_buffer);
133  dest = FPDF_GetNamedDest(document(), std::numeric_limits<int>::min(),
134                           fixed_buffer, &buffer_size);
135  EXPECT_EQ(nullptr, dest);
136  EXPECT_EQ(sizeof(fixed_buffer), buffer_size);  // unmodified.
137
138  buffer_size = sizeof(fixed_buffer);
139  dest = FPDF_GetNamedDest(document(), -1, fixed_buffer, &buffer_size);
140  EXPECT_EQ(nullptr, dest);
141  EXPECT_EQ(sizeof(fixed_buffer), buffer_size);  // unmodified.
142}
143
144TEST_F(FPDFViewEmbeddertest, NamedDestsByName) {
145  EXPECT_TRUE(OpenDocument("named_dests.pdf"));
146
147  // Null pointer returns NULL.
148  FPDF_DEST dest = FPDF_GetNamedDestByName(document(), nullptr);
149  EXPECT_EQ(nullptr, dest);
150
151  // Empty string returns NULL.
152  dest = FPDF_GetNamedDestByName(document(), "");
153  EXPECT_EQ(nullptr, dest);
154
155  // Item from Dests NameTree.
156  dest = FPDF_GetNamedDestByName(document(), "First");
157  EXPECT_NE(nullptr, dest);
158
159  long ignore_len = 0;
160  FPDF_DEST dest_by_index =
161      FPDF_GetNamedDest(document(), 0, nullptr, &ignore_len);
162  EXPECT_EQ(dest_by_index, dest);
163
164  // Item from Dests dictionary.
165  dest = FPDF_GetNamedDestByName(document(), "FirstAlternate");
166  EXPECT_NE(nullptr, dest);
167
168  ignore_len = 0;
169  dest_by_index = FPDF_GetNamedDest(document(), 4, nullptr, &ignore_len);
170  EXPECT_EQ(dest_by_index, dest);
171
172  // Bad value type for item from Dests NameTree array.
173  dest = FPDF_GetNamedDestByName(document(), "WrongType");
174  EXPECT_EQ(nullptr, dest);
175
176  // No such destination in either Dest NameTree or dictionary.
177  dest = FPDF_GetNamedDestByName(document(), "Bogus");
178  EXPECT_EQ(nullptr, dest);
179}
180
181// The following tests pass if the document opens without crashing.
182TEST_F(FPDFViewEmbeddertest, Crasher_113) {
183  EXPECT_TRUE(OpenDocument("bug_113.pdf"));
184}
185
186TEST_F(FPDFViewEmbeddertest, Crasher_451830) {
187  // Document is damaged and can't be opened.
188  EXPECT_FALSE(OpenDocument("bug_451830.pdf"));
189}
190
191TEST_F(FPDFViewEmbeddertest, Crasher_452455) {
192  EXPECT_TRUE(OpenDocument("bug_452455.pdf"));
193  FPDF_PAGE page = LoadPage(0);
194  EXPECT_NE(nullptr, page);
195  UnloadPage(page);
196}
197
198TEST_F(FPDFViewEmbeddertest, Crasher_454695) {
199  // Document is damaged and can't be opened.
200  EXPECT_FALSE(OpenDocument("bug_454695.pdf"));
201}
202
203TEST_F(FPDFViewEmbeddertest, Crasher_572871) {
204  EXPECT_TRUE(OpenDocument("bug_572871.pdf"));
205}
206
207// The following tests pass if the document opens without infinite looping.
208TEST_F(FPDFViewEmbeddertest, Hang_298) {
209  EXPECT_FALSE(OpenDocument("bug_298.pdf"));
210}
211
212// Test if the document opens without infinite looping.
213// Previously this test will hang in a loop inside LoadAllCrossRefV4. After
214// the fix, LoadAllCrossRefV4 will return false after detecting a cross
215// reference loop. Cross references will be rebuilt successfully.
216TEST_F(FPDFViewEmbeddertest, CrossRefV4Loop) {
217  EXPECT_TRUE(OpenDocument("bug_xrefv4_loop.pdf"));
218}
219
220// The test should pass when circular references to ParseIndirectObject will not
221// cause infinite loop.
222TEST_F(FPDFViewEmbeddertest, Hang_343) {
223  EXPECT_FALSE(OpenDocument("bug_343.pdf"));
224}
225
226// The test should pass when the absence of 'Contents' field in a signature
227// dictionary will not cause an infinite loop in CPDF_SyntaxParser::GetObject().
228TEST_F(FPDFViewEmbeddertest, Hang_344) {
229  EXPECT_FALSE(OpenDocument("bug_344.pdf"));
230}