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