xref: /aosp_15_r20/external/pdfium/core/fpdfapi/parser/cpdf_cross_ref_avail_unittest.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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