1 // Copyright 2017 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 "core/fpdfapi/parser/cpdf_cross_ref_avail.h"
6
7 #include <memory>
8 #include <string>
9
10 #include "core/fpdfapi/parser/cpdf_syntax_parser.h"
11 #include "core/fxcrt/cfx_read_only_span_stream.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace {
15
MakeParserForBuffer(pdfium::span<const uint8_t> buffer)16 std::unique_ptr<CPDF_SyntaxParser> MakeParserForBuffer(
17 pdfium::span<const uint8_t> buffer) {
18 return std::make_unique<CPDF_SyntaxParser>(
19 pdfium::MakeRetain<CFX_ReadOnlySpanStream>(buffer));
20 }
21
22 } // namespace
23
TEST(CrossRefAvailTest,CheckCrossRefV4)24 TEST(CrossRefAvailTest, CheckCrossRefV4) {
25 const unsigned char xref_table[] =
26 "xref \n"
27 "0 6 \n"
28 "0000000003 65535 f \n"
29 "0000000017 00000 n \n"
30 "0000000081 00000 n \n"
31 "0000000000 00007 f \n"
32 "0000000331 00000 n \n"
33 "0000000409 00000 n \n"
34 "trailer\n"
35 "<</Root 14 0 R/ID "
36 "[<afbb0f593c2d2aea5b519cb61da1c17b><4f9bb2e7978401808f8f1f2a75c322c8>]"
37 "/Info 15 0 R/Size 16>>";
38 const FX_FILESIZE last_crossref_offset = 0;
39
40 auto parser = MakeParserForBuffer(xref_table);
41 auto cross_ref_avail =
42 std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset);
43
44 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, cross_ref_avail->CheckAvail());
45 }
46
TEST(CrossRefAvailTest,CheckCrossRefStream)47 TEST(CrossRefAvailTest, CheckCrossRefStream) {
48 const unsigned char xref_stream[] =
49 "16 0 obj\n"
50 "<</Filter /FlateDecode>>"
51 " stream \n"
52 "STREAM DATA STREAM DATA STREAM DATA\n"
53 "endstream\n"
54 "endobj\n";
55 const FX_FILESIZE last_crossref_offset = 0;
56
57 auto parser = MakeParserForBuffer(xref_stream);
58 auto cross_ref_avail =
59 std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset);
60
61 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, cross_ref_avail->CheckAvail());
62 }
63
TEST(CrossRefAvailTest,IncorrectStartOffset)64 TEST(CrossRefAvailTest, IncorrectStartOffset) {
65 const unsigned char xref_stream[] =
66 "16 0 obj\n"
67 "<</Filter /FlateDecode>>"
68 " stream \n"
69 "STREAM DATA STREAM DATA STREAM DATA\n"
70 "endstream\n"
71 "endobj\n";
72
73 const FX_FILESIZE last_crossref_offset = 70000;
74
75 auto parser = MakeParserForBuffer(xref_stream);
76 auto cross_ref_avail =
77 std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset);
78
79 EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail());
80 }
81
TEST(CrossRefAvailTest,IncorrectPrevOffset)82 TEST(CrossRefAvailTest, IncorrectPrevOffset) {
83 const unsigned char xref_stream[] =
84 "16 0 obj\n"
85 "<</Type /XRef /Prev 70000>>"
86 " stream \n"
87 "STREAM DATA STREAM DATA STREAM DATA\n"
88 "endstream\n"
89 "endobj\n";
90 const FX_FILESIZE last_crossref_offset = 0;
91
92 auto parser = MakeParserForBuffer(xref_stream);
93 auto cross_ref_avail =
94 std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset);
95 EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail());
96 }
97
TEST(CrossRefAvailTest,IncorrectPrevStreamOffset)98 TEST(CrossRefAvailTest, IncorrectPrevStreamOffset) {
99 const unsigned char xref_table[] =
100 "xref \n"
101 "0 6 \n"
102 "0000000003 65535 f \n"
103 "0000000017 00000 n \n"
104 "0000000081 00000 n \n"
105 "0000000000 00007 f \n"
106 "0000000331 00000 n \n"
107 "0000000409 00000 n \n"
108 "trailer\n"
109 "<</Root 14 0 R/ID "
110 "[<afbb0f593c2d2aea5b519cb61da1c17b><4f9bb2e7978401808f8f1f2a75c322c8>]"
111 "/Info 15 0 R/Size 16 /XRefStm 70000>>";
112 const FX_FILESIZE last_crossref_offset = 0;
113
114 auto parser = MakeParserForBuffer(xref_table);
115 auto cross_ref_avail =
116 std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset);
117 EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail());
118 }
119
TEST(CrossRefAvailTest,IncorrectData)120 TEST(CrossRefAvailTest, IncorrectData) {
121 const unsigned char incorrect_data[] =
122 "fiajaoilf w9ifaoihwoiafhja wfijaofijoiaw fhj oiawhfoiah "
123 "wfoihoiwfghouiafghwoigahfi";
124 const FX_FILESIZE last_crossref_offset = 0;
125
126 auto parser = MakeParserForBuffer(incorrect_data);
127 auto cross_ref_avail =
128 std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset);
129 EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail());
130 }
131
TEST(CrossRefAvailTest,ThreeCrossRefV4)132 TEST(CrossRefAvailTest, ThreeCrossRefV4) {
133 char int_buffer[100];
134 std::string table = "pdf blah blah blah\n";
135 size_t cur_offset = table.size();
136 table +=
137 "xref \n"
138 "0 6 \n"
139 "0000000003 65535 f \n"
140 "trailer\n"
141 "<</Root 14 0 R/ID "
142 "[<afbb0f593c2d2aea5b519cb61da1c17b><4f9bb2e7978401808f8f1f2a75c322c8>]"
143 "/Info 15 0 R/Size 16>>\n";
144 table += "Dummy Data jgwhughouiwbahng";
145 size_t prev_offset = cur_offset;
146 cur_offset = table.size();
147 table += std::string(
148 "xref \n"
149 "0 6 \n"
150 "0000000003 65535 f \n"
151 "trailer\n"
152 "<</Root 14 0 R/ID "
153 "[<afbb0f593c2d2aea5b519cb61da1c17b><"
154 "4f9bb2e7978401808f8f1f2a75c322c8>]"
155 "/Info 15 0 R/Size 16"
156 "/Prev ") +
157 FXSYS_itoa(static_cast<int>(prev_offset), int_buffer, 10) + ">>\n";
158 table += "More Dummy Data jgwhughouiwbahng";
159 prev_offset = cur_offset;
160 cur_offset = table.size();
161 table += std::string(
162 "xref \n"
163 "0 6 \n"
164 "0000000003 65535 f \n"
165 "trailer\n"
166 "<</Root 14 0 R/ID "
167 "[<afbb0f593c2d2aea5b519cb61da1c17b><"
168 "4f9bb2e7978401808f8f1f2a75c322c8>]"
169 "/Info 15 0 R/Size 16"
170 "/Prev ") +
171 FXSYS_itoa(static_cast<int>(prev_offset), int_buffer, 10) + ">>\n";
172 const FX_FILESIZE last_crossref_offset = static_cast<FX_FILESIZE>(cur_offset);
173
174 auto parser = MakeParserForBuffer(pdfium::as_bytes(pdfium::make_span(table)));
175 auto cross_ref_avail =
176 std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset);
177 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, cross_ref_avail->CheckAvail());
178 }
179
TEST(CrossRefAvailTest,ThreeCrossRefV5)180 TEST(CrossRefAvailTest, ThreeCrossRefV5) {
181 char int_buffer[100];
182 std::string table = "pdf blah blah blah\n";
183 size_t cur_offset = table.size();
184 table +=
185 "16 0 obj\n"
186 "<</Type /XRef>>"
187 " stream \n"
188 "STREAM DATA STREAM DATA STREAM DATA ahfcuabfkuabfu\n"
189 "endstream\n"
190 "endobj\n";
191 table += "Dummy Data jgwhughouiwbahng";
192
193 size_t prev_offset = cur_offset;
194 cur_offset = table.size();
195 table += std::string(
196 "55 0 obj\n"
197 "<</Type /XRef /Prev ") +
198 FXSYS_itoa(static_cast<int>(prev_offset), int_buffer, 10) +
199 ">>"
200 " stream \n"
201 "STREAM DATA STREAM DATA STREAM DATA\n"
202 "endstream\n"
203 "endobj\n";
204 table += "More Dummy Data jgwhughouiwbahng";
205 prev_offset = cur_offset;
206 cur_offset = table.size();
207 table += std::string(
208 "88 0 obj\n"
209 "<</Type /XRef /NNNN /Prev ") +
210 FXSYS_itoa(static_cast<int>(prev_offset), int_buffer, 10) +
211 ">>"
212 " stream \n"
213 "STREAM DATA STREAM DATA STREAM DATA favav\n"
214 "endstream\n"
215 "endobj\n";
216 const FX_FILESIZE last_crossref_offset = static_cast<FX_FILESIZE>(cur_offset);
217
218 auto parser = MakeParserForBuffer(pdfium::as_bytes(pdfium::make_span(table)));
219 auto cross_ref_avail =
220 std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset);
221 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, cross_ref_avail->CheckAvail());
222 }
223
TEST(CrossRefAvailTest,Mixed)224 TEST(CrossRefAvailTest, Mixed) {
225 char int_buffer[100];
226 std::string table = "pdf blah blah blah\n";
227
228 const int first_v5_table_offset = static_cast<int>(table.size());
229 table +=
230 "16 0 obj\n"
231 "<</Type /XRef>>"
232 " stream \n"
233 "STREAM DATA STREAM DATA STREAM DATA ahfcuabfkuabfu\n"
234 "endstream\n"
235 "endobj\n";
236 table += "Dummy Data jgwhughouiwbahng";
237
238 const int second_v4_table_offset = static_cast<int>(table.size());
239 table += std::string(
240 "xref \n"
241 "0 6 \n"
242 "0000000003 65535 f \n"
243 "trailer\n"
244 "<</Root 14 0 R/ID "
245 "[<afbb0f593c2d2aea5b519cb61da1c17b><"
246 "4f9bb2e7978401808f8f1f2a75c322c8>]"
247 "/Info 15 0 R/Size 16"
248 "/Prev ") +
249 FXSYS_itoa(first_v5_table_offset, int_buffer, 10) + ">>\n";
250 table += "More Dummy Data jgwhughouiwbahng";
251
252 const int last_v4_table_offset = static_cast<int>(table.size());
253 table += std::string(
254 "xref \n"
255 "0 6 \n"
256 "0000000003 65535 f \n"
257 "trailer\n"
258 "<</Root 14 0 R/ID "
259 "[<afbb0f593c2d2aea5b519cb61da1c17b><"
260 "4f9bb2e7978401808f8f1f2a75c322c8>]"
261 "/Info 15 0 R/Size 16"
262 "/Prev ") +
263 FXSYS_itoa(second_v4_table_offset, int_buffer, 10) + " /XRefStm " +
264 FXSYS_itoa(first_v5_table_offset, int_buffer, 10) + ">>\n";
265 const FX_FILESIZE last_crossref_offset = last_v4_table_offset;
266
267 auto parser = MakeParserForBuffer(pdfium::as_bytes(pdfium::make_span(table)));
268 auto cross_ref_avail =
269 std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset);
270 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, cross_ref_avail->CheckAvail());
271 }
272
TEST(CrossRefAvailTest,CrossRefV5IsNotStream)273 TEST(CrossRefAvailTest, CrossRefV5IsNotStream) {
274 const unsigned char invalid_xref_stream[] =
275 "16 0 obj\n"
276 "[/array /object]\n"
277 "endstream\n"
278 "endobj\n";
279 const FX_FILESIZE last_crossref_offset = 0;
280
281 auto parser = MakeParserForBuffer(invalid_xref_stream);
282 auto cross_ref_avail =
283 std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset);
284 EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail());
285 }
286
TEST(CrossRefAvailTest,CrossRefV4WithEncryptRef)287 TEST(CrossRefAvailTest, CrossRefV4WithEncryptRef) {
288 const unsigned char xref_table[] =
289 "xref \n"
290 "0 6 \n"
291 "0000000003 65535 f \n"
292 "0000000017 00000 n \n"
293 "0000000081 00000 n \n"
294 "0000000000 00007 f \n"
295 "0000000331 00000 n \n"
296 "0000000409 00000 n \n"
297 "trailer\n"
298 "<</Root 14 0 R/ID "
299 "[<afbb0f593c2d2aea5b519cb61da1c17b><4f9bb2e7978401808f8f1f2a75c322c8>]"
300 "/Encrypt 77 0 R"
301 "/Info 15 0 R/Size 16>>";
302 const FX_FILESIZE last_crossref_offset = 0;
303
304 auto parser = MakeParserForBuffer(xref_table);
305 auto cross_ref_avail =
306 std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset);
307 EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail());
308 }
309
TEST(CrossRefAvailTest,CrossRefStreamWithEncryptRef)310 TEST(CrossRefAvailTest, CrossRefStreamWithEncryptRef) {
311 const unsigned char xref_stream[] =
312 "16 0 obj\n"
313 "<</Filter /FlateDecode /Encrypt 77 0 R>>"
314 " stream \n"
315 "STREAM DATA STREAM DATA STREAM DATA\n"
316 "endstream\n"
317 "endobj\n";
318 const FX_FILESIZE last_crossref_offset = 0;
319
320 auto parser = MakeParserForBuffer(xref_stream);
321 auto cross_ref_avail =
322 std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset);
323 EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail());
324 }
325