1 // Copyright 2021 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_object_stream.h"
6
7 #include <iterator>
8 #include <utility>
9
10 #include "core/fpdfapi/parser/cpdf_dictionary.h"
11 #include "core/fpdfapi/parser/cpdf_indirect_object_holder.h"
12 #include "core/fpdfapi/parser/cpdf_name.h"
13 #include "core/fpdfapi/parser/cpdf_number.h"
14 #include "core/fpdfapi/parser/cpdf_stream.h"
15 #include "core/fpdfapi/parser/cpdf_string.h"
16 #include "core/fxcrt/data_vector.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 using testing::ElementsAre;
21
22 namespace {
23
24 constexpr char kNormalStreamContent[] =
25 "10 0 11 14 12 21<</Name /Foo>>[1 2 3]4";
26 constexpr int kNormalStreamContentOffset = 16;
27 static_assert(kNormalStreamContent[kNormalStreamContentOffset] == '<',
28 "Wrong offset");
29 static_assert(kNormalStreamContent[kNormalStreamContentOffset + 1] == '<',
30 "Wrong offset");
31
32 } // namespace
33
TEST(ObjectStreamTest,StreamDictNormal)34 TEST(ObjectStreamTest, StreamDictNormal) {
35 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
36 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
37 dict->SetNewFor<CPDF_Number>("N", 3);
38 dict->SetNewFor<CPDF_Number>("First", kNormalStreamContentOffset);
39
40 ByteStringView contents_view(kNormalStreamContent);
41 auto stream = pdfium::MakeRetain<CPDF_Stream>(
42 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
43 auto obj_stream = CPDF_ObjectStream::Create(std::move(stream));
44 ASSERT_TRUE(obj_stream);
45
46 EXPECT_THAT(obj_stream->object_info(),
47 ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0),
48 CPDF_ObjectStream::ObjectInfo(11, 14),
49 CPDF_ObjectStream::ObjectInfo(12, 21)));
50
51 // Check expected indices.
52 CPDF_IndirectObjectHolder holder;
53 RetainPtr<CPDF_Object> obj10 = obj_stream->ParseObject(&holder, 10, 0);
54 ASSERT_TRUE(obj10);
55 EXPECT_EQ(10u, obj10->GetObjNum());
56 EXPECT_EQ(0u, obj10->GetGenNum());
57 EXPECT_TRUE(obj10->IsDictionary());
58
59 RetainPtr<CPDF_Object> obj11 = obj_stream->ParseObject(&holder, 11, 1);
60 ASSERT_TRUE(obj11);
61 EXPECT_EQ(11u, obj11->GetObjNum());
62 EXPECT_EQ(0u, obj11->GetGenNum());
63 EXPECT_TRUE(obj11->IsArray());
64
65 RetainPtr<CPDF_Object> obj12 = obj_stream->ParseObject(&holder, 12, 2);
66 ASSERT_TRUE(obj12);
67 EXPECT_EQ(12u, obj12->GetObjNum());
68 EXPECT_EQ(0u, obj12->GetGenNum());
69 EXPECT_TRUE(obj12->IsNumber());
70
71 // Check bad indices.
72 EXPECT_FALSE(obj_stream->ParseObject(&holder, 10, 1));
73 EXPECT_FALSE(obj_stream->ParseObject(&holder, 10, 2));
74 EXPECT_FALSE(obj_stream->ParseObject(&holder, 10, 3));
75 EXPECT_FALSE(obj_stream->ParseObject(&holder, 11, 0));
76 EXPECT_FALSE(obj_stream->ParseObject(&holder, 11, 2));
77 EXPECT_FALSE(obj_stream->ParseObject(&holder, 11, 3));
78 EXPECT_FALSE(obj_stream->ParseObject(&holder, 12, 0));
79 EXPECT_FALSE(obj_stream->ParseObject(&holder, 12, 1));
80 EXPECT_FALSE(obj_stream->ParseObject(&holder, 12, 3));
81 }
82
TEST(ObjectStreamTest,StreamNoDict)83 TEST(ObjectStreamTest, StreamNoDict) {
84 ByteStringView contents_view(kNormalStreamContent);
85 auto stream = pdfium::MakeRetain<CPDF_Stream>(
86 DataVector<uint8_t>(contents_view.begin(), contents_view.end()),
87 /*pDict=*/nullptr);
88 EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream)));
89 }
90
TEST(ObjectStreamTest,StreamDictNoType)91 TEST(ObjectStreamTest, StreamDictNoType) {
92 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
93 dict->SetNewFor<CPDF_Number>("N", 3);
94 dict->SetNewFor<CPDF_Number>("First", 5);
95
96 ByteStringView contents_view(kNormalStreamContent);
97 auto stream = pdfium::MakeRetain<CPDF_Stream>(
98 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
99 EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream)));
100 }
101
TEST(ObjectStreamTest,StreamDictWrongType)102 TEST(ObjectStreamTest, StreamDictWrongType) {
103 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
104 dict->SetNewFor<CPDF_String>("Type", "ObjStm", /*bHex=*/false);
105 dict->SetNewFor<CPDF_Number>("N", 3);
106 dict->SetNewFor<CPDF_Number>("First", 5);
107
108 ByteStringView contents_view(kNormalStreamContent);
109 auto stream = pdfium::MakeRetain<CPDF_Stream>(
110 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
111 EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream)));
112 }
113
TEST(ObjectStreamTest,StreamDictWrongTypeValue)114 TEST(ObjectStreamTest, StreamDictWrongTypeValue) {
115 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
116 dict->SetNewFor<CPDF_Name>("Type", "ObjStmmmm");
117 dict->SetNewFor<CPDF_Number>("N", 3);
118 dict->SetNewFor<CPDF_Number>("First", 5);
119
120 ByteStringView contents_view(kNormalStreamContent);
121 auto stream = pdfium::MakeRetain<CPDF_Stream>(
122 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
123 EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream)));
124 }
125
TEST(ObjectStreamTest,StreamDictNoCount)126 TEST(ObjectStreamTest, StreamDictNoCount) {
127 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
128 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
129 dict->SetNewFor<CPDF_Number>("First", 5);
130
131 ByteStringView contents_view(kNormalStreamContent);
132 auto stream = pdfium::MakeRetain<CPDF_Stream>(
133 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
134 EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream)));
135 }
136
TEST(ObjectStreamTest,StreamDictFloatCount)137 TEST(ObjectStreamTest, StreamDictFloatCount) {
138 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
139 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
140 dict->SetNewFor<CPDF_Number>("N", 2.2f);
141 dict->SetNewFor<CPDF_Number>("First", 5);
142
143 ByteStringView contents_view(kNormalStreamContent);
144 auto stream = pdfium::MakeRetain<CPDF_Stream>(
145 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
146 EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream)));
147 }
148
TEST(ObjectStreamTest,StreamDictNegativeCount)149 TEST(ObjectStreamTest, StreamDictNegativeCount) {
150 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
151 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
152 dict->SetNewFor<CPDF_Number>("N", -1);
153 dict->SetNewFor<CPDF_Number>("First", 5);
154
155 ByteStringView contents_view(kNormalStreamContent);
156 auto stream = pdfium::MakeRetain<CPDF_Stream>(
157 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
158 EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream)));
159 }
160
TEST(ObjectStreamTest,StreamDictCountTooBig)161 TEST(ObjectStreamTest, StreamDictCountTooBig) {
162 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
163 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
164 dict->SetNewFor<CPDF_Number>("N", 999999999);
165 dict->SetNewFor<CPDF_Number>("First", 5);
166
167 ByteStringView contents_view(kNormalStreamContent);
168 auto stream = pdfium::MakeRetain<CPDF_Stream>(
169 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
170 EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream)));
171 }
172
TEST(ObjectStreamTest,StreamDictNoOffset)173 TEST(ObjectStreamTest, StreamDictNoOffset) {
174 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
175 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
176 dict->SetNewFor<CPDF_Number>("N", 3);
177
178 ByteStringView contents_view(kNormalStreamContent);
179 auto stream = pdfium::MakeRetain<CPDF_Stream>(
180 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
181 EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream)));
182 }
183
TEST(ObjectStreamTest,StreamDictFloatOffset)184 TEST(ObjectStreamTest, StreamDictFloatOffset) {
185 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
186 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
187 dict->SetNewFor<CPDF_Number>("N", 3);
188 dict->SetNewFor<CPDF_Number>("First", 5.5f);
189
190 ByteStringView contents_view(kNormalStreamContent);
191 auto stream = pdfium::MakeRetain<CPDF_Stream>(
192 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
193 EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream)));
194 }
195
TEST(ObjectStreamTest,StreamDictNegativeOffset)196 TEST(ObjectStreamTest, StreamDictNegativeOffset) {
197 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
198 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
199 dict->SetNewFor<CPDF_Number>("N", 3);
200 dict->SetNewFor<CPDF_Number>("First", -5);
201
202 ByteStringView contents_view(kNormalStreamContent);
203 auto stream = pdfium::MakeRetain<CPDF_Stream>(
204 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
205 EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream)));
206 }
207
TEST(ObjectStreamTest,StreamDictOffsetTooBig)208 TEST(ObjectStreamTest, StreamDictOffsetTooBig) {
209 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
210 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
211 dict->SetNewFor<CPDF_Number>("N", 3);
212 constexpr int kTooBigOffset = std::size(kNormalStreamContent);
213 dict->SetNewFor<CPDF_Number>("First", kTooBigOffset);
214
215 ByteStringView contents_view(kNormalStreamContent);
216 auto stream = pdfium::MakeRetain<CPDF_Stream>(
217 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
218 auto obj_stream = CPDF_ObjectStream::Create(std::move(stream));
219 ASSERT_TRUE(obj_stream);
220
221 EXPECT_THAT(obj_stream->object_info(),
222 ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0),
223 CPDF_ObjectStream::ObjectInfo(11, 14),
224 CPDF_ObjectStream::ObjectInfo(12, 21)));
225
226 CPDF_IndirectObjectHolder holder;
227 EXPECT_FALSE(obj_stream->ParseObject(&holder, 10, 0));
228 EXPECT_FALSE(obj_stream->ParseObject(&holder, 11, 1));
229 EXPECT_FALSE(obj_stream->ParseObject(&holder, 12, 2));
230 }
231
TEST(ObjectStreamTest,StreamDictTooFewCount)232 TEST(ObjectStreamTest, StreamDictTooFewCount) {
233 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
234 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
235 dict->SetNewFor<CPDF_Number>("N", 2);
236 dict->SetNewFor<CPDF_Number>("First", kNormalStreamContentOffset);
237
238 ByteStringView contents_view(kNormalStreamContent);
239 auto stream = pdfium::MakeRetain<CPDF_Stream>(
240 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
241 auto obj_stream = CPDF_ObjectStream::Create(std::move(stream));
242 ASSERT_TRUE(obj_stream);
243
244 EXPECT_THAT(obj_stream->object_info(),
245 ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0),
246 CPDF_ObjectStream::ObjectInfo(11, 14)));
247
248 CPDF_IndirectObjectHolder holder;
249 RetainPtr<CPDF_Object> obj10 = obj_stream->ParseObject(&holder, 10, 0);
250 ASSERT_TRUE(obj10);
251 EXPECT_EQ(10u, obj10->GetObjNum());
252 EXPECT_EQ(0u, obj10->GetGenNum());
253 EXPECT_TRUE(obj10->IsDictionary());
254
255 RetainPtr<CPDF_Object> obj11 = obj_stream->ParseObject(&holder, 11, 1);
256 ASSERT_TRUE(obj11);
257 EXPECT_EQ(11u, obj11->GetObjNum());
258 EXPECT_EQ(0u, obj11->GetGenNum());
259 EXPECT_TRUE(obj11->IsArray());
260
261 EXPECT_FALSE(obj_stream->ParseObject(&holder, 12, 2));
262 }
263
TEST(ObjectStreamTest,StreamDictTooManyObject)264 TEST(ObjectStreamTest, StreamDictTooManyObject) {
265 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
266 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
267 dict->SetNewFor<CPDF_Number>("N", 9);
268 dict->SetNewFor<CPDF_Number>("First", kNormalStreamContentOffset);
269
270 ByteStringView contents_view(kNormalStreamContent);
271 auto stream = pdfium::MakeRetain<CPDF_Stream>(
272 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
273 auto obj_stream = CPDF_ObjectStream::Create(std::move(stream));
274 ASSERT_TRUE(obj_stream);
275
276 // TODO(thestig): Can this avoid finding object 2?
277 EXPECT_THAT(obj_stream->object_info(),
278 ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0),
279 CPDF_ObjectStream::ObjectInfo(11, 14),
280 CPDF_ObjectStream::ObjectInfo(12, 21),
281 CPDF_ObjectStream::ObjectInfo(2, 3)));
282
283 CPDF_IndirectObjectHolder holder;
284 EXPECT_FALSE(obj_stream->ParseObject(&holder, 2, 0));
285 EXPECT_FALSE(obj_stream->ParseObject(&holder, 2, 1));
286 EXPECT_FALSE(obj_stream->ParseObject(&holder, 2, 2));
287 EXPECT_FALSE(obj_stream->ParseObject(&holder, 2, 3));
288 EXPECT_FALSE(obj_stream->ParseObject(&holder, 2, 4));
289 }
290
TEST(ObjectStreamTest,StreamDictGarbageObjNum)291 TEST(ObjectStreamTest, StreamDictGarbageObjNum) {
292 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
293 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
294 dict->SetNewFor<CPDF_Number>("N", 3);
295 dict->SetNewFor<CPDF_Number>("First", 19);
296
297 const char kStreamContent[] = "10 0 hi 14 12 21<</Name /Foo>>[1 2 3]4";
298 ByteStringView contents_view(kStreamContent);
299 auto stream = pdfium::MakeRetain<CPDF_Stream>(
300 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
301 auto obj_stream = CPDF_ObjectStream::Create(std::move(stream));
302 ASSERT_TRUE(obj_stream);
303
304 EXPECT_THAT(obj_stream->object_info(),
305 ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0),
306 CPDF_ObjectStream::ObjectInfo(12, 21)));
307 }
308
TEST(ObjectStreamTest,StreamDictGarbageObjectOffset)309 TEST(ObjectStreamTest, StreamDictGarbageObjectOffset) {
310 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
311 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
312 dict->SetNewFor<CPDF_Number>("N", 3);
313 dict->SetNewFor<CPDF_Number>("First", 16);
314
315 const char kStreamContent[] = "10 0 11 hi 12 21<</Name /Foo>>[1 2 3]4";
316 ByteStringView contents_view(kStreamContent);
317 auto stream = pdfium::MakeRetain<CPDF_Stream>(
318 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
319 auto obj_stream = CPDF_ObjectStream::Create(std::move(stream));
320 ASSERT_TRUE(obj_stream);
321
322 // TODO(thestig): Should object 11 be rejected?
323 EXPECT_THAT(obj_stream->object_info(),
324 ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0),
325 CPDF_ObjectStream::ObjectInfo(11, 0),
326 CPDF_ObjectStream::ObjectInfo(12, 21)));
327
328 CPDF_IndirectObjectHolder holder;
329 RetainPtr<CPDF_Object> obj10 = obj_stream->ParseObject(&holder, 10, 0);
330 ASSERT_TRUE(obj10);
331 EXPECT_EQ(10u, obj10->GetObjNum());
332 EXPECT_EQ(0u, obj10->GetGenNum());
333 EXPECT_TRUE(obj10->IsDictionary());
334
335 RetainPtr<CPDF_Object> obj11 = obj_stream->ParseObject(&holder, 11, 1);
336 ASSERT_TRUE(obj11);
337 EXPECT_EQ(11u, obj11->GetObjNum());
338 EXPECT_EQ(0u, obj11->GetGenNum());
339 EXPECT_TRUE(obj11->IsDictionary());
340 }
341
TEST(ObjectStreamTest,StreamDictNegativeObjectOffset)342 TEST(ObjectStreamTest, StreamDictNegativeObjectOffset) {
343 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
344 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
345 dict->SetNewFor<CPDF_Number>("N", 3);
346 dict->SetNewFor<CPDF_Number>("First", 16);
347
348 const char kStreamContent[] = "10 0 11 -1 12 21<</Name /Foo>>[1 2 3]4";
349 ByteStringView contents_view(kStreamContent);
350 auto stream = pdfium::MakeRetain<CPDF_Stream>(
351 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
352 auto obj_stream = CPDF_ObjectStream::Create(std::move(stream));
353 ASSERT_TRUE(obj_stream);
354
355 // TODO(thestig): Should object 11 be rejected?
356 EXPECT_THAT(obj_stream->object_info(),
357 ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0),
358 CPDF_ObjectStream::ObjectInfo(11, 4294967295),
359 CPDF_ObjectStream::ObjectInfo(12, 21)));
360
361 CPDF_IndirectObjectHolder holder;
362 EXPECT_FALSE(obj_stream->ParseObject(&holder, 11, 1));
363 }
364
TEST(ObjectStreamTest,StreamDictObjectOffsetTooBig)365 TEST(ObjectStreamTest, StreamDictObjectOffsetTooBig) {
366 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
367 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
368 dict->SetNewFor<CPDF_Number>("N", 3);
369 dict->SetNewFor<CPDF_Number>("First", 17);
370
371 const char kStreamContent[] = "10 0 11 999 12 21<</Name /Foo>>[1 2 3]4";
372 ByteStringView contents_view(kStreamContent);
373 auto stream = pdfium::MakeRetain<CPDF_Stream>(
374 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
375 auto obj_stream = CPDF_ObjectStream::Create(std::move(stream));
376 ASSERT_TRUE(obj_stream);
377
378 // TODO(thestig): Should object 11 be rejected?
379 EXPECT_THAT(obj_stream->object_info(),
380 ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0),
381 CPDF_ObjectStream::ObjectInfo(11, 999),
382 CPDF_ObjectStream::ObjectInfo(12, 21)));
383
384 CPDF_IndirectObjectHolder holder;
385 EXPECT_FALSE(obj_stream->ParseObject(&holder, 11, 1));
386 }
387
TEST(ObjectStreamTest,StreamDictDuplicateObjNum)388 TEST(ObjectStreamTest, StreamDictDuplicateObjNum) {
389 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
390 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
391 dict->SetNewFor<CPDF_Number>("N", 3);
392 dict->SetNewFor<CPDF_Number>("First", 16);
393
394 const char kStreamContent[] = "10 0 10 14 12 21<</Name /Foo>>[1 2 3]4";
395 ByteStringView contents_view(kStreamContent);
396 auto stream = pdfium::MakeRetain<CPDF_Stream>(
397 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
398 auto obj_stream = CPDF_ObjectStream::Create(std::move(stream));
399 ASSERT_TRUE(obj_stream);
400
401 EXPECT_THAT(obj_stream->object_info(),
402 ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0),
403 CPDF_ObjectStream::ObjectInfo(10, 14),
404 CPDF_ObjectStream::ObjectInfo(12, 21)));
405
406 CPDF_IndirectObjectHolder holder;
407 RetainPtr<CPDF_Object> obj10 = obj_stream->ParseObject(&holder, 10, 0);
408 ASSERT_TRUE(obj10);
409 EXPECT_EQ(10u, obj10->GetObjNum());
410 EXPECT_EQ(0u, obj10->GetGenNum());
411 EXPECT_TRUE(obj10->IsDictionary());
412
413 obj10 = obj_stream->ParseObject(&holder, 10, 1);
414 ASSERT_TRUE(obj10);
415 EXPECT_EQ(10u, obj10->GetObjNum());
416 EXPECT_EQ(0u, obj10->GetGenNum());
417 EXPECT_TRUE(obj10->IsArray());
418
419 EXPECT_FALSE(obj_stream->ParseObject(&holder, 10, 2));
420 EXPECT_FALSE(obj_stream->ParseObject(&holder, 10, 3));
421
422 RetainPtr<CPDF_Object> obj12 = obj_stream->ParseObject(&holder, 12, 2);
423 ASSERT_TRUE(obj12);
424 EXPECT_EQ(12u, obj12->GetObjNum());
425 EXPECT_EQ(0u, obj12->GetGenNum());
426 EXPECT_TRUE(obj12->IsNumber());
427 }
428
TEST(ObjectStreamTest,StreamDictUnorderedObjectNumbers)429 TEST(ObjectStreamTest, StreamDictUnorderedObjectNumbers) {
430 // ISO 32000-1:2008 spec. section 7.5.7, note 6 says there is no restriction
431 // on object number ordering.
432 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
433 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
434 dict->SetNewFor<CPDF_Number>("N", 3);
435 dict->SetNewFor<CPDF_Number>("First", 16);
436
437 const char kStreamContent[] = "11 0 12 14 10 21<</Name /Foo>>[1 2 3]4";
438 ByteStringView contents_view(kStreamContent);
439 auto stream = pdfium::MakeRetain<CPDF_Stream>(
440 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
441 auto obj_stream = CPDF_ObjectStream::Create(std::move(stream));
442 ASSERT_TRUE(obj_stream);
443
444 EXPECT_THAT(obj_stream->object_info(),
445 ElementsAre(CPDF_ObjectStream::ObjectInfo(11, 0),
446 CPDF_ObjectStream::ObjectInfo(12, 14),
447 CPDF_ObjectStream::ObjectInfo(10, 21)));
448
449 CPDF_IndirectObjectHolder holder;
450 RetainPtr<CPDF_Object> obj10 = obj_stream->ParseObject(&holder, 10, 2);
451 ASSERT_TRUE(obj10);
452 EXPECT_EQ(10u, obj10->GetObjNum());
453 EXPECT_EQ(0u, obj10->GetGenNum());
454 EXPECT_TRUE(obj10->IsNumber());
455
456 RetainPtr<CPDF_Object> obj11 = obj_stream->ParseObject(&holder, 11, 0);
457 ASSERT_TRUE(obj11);
458 EXPECT_EQ(11u, obj11->GetObjNum());
459 EXPECT_EQ(0u, obj11->GetGenNum());
460 EXPECT_TRUE(obj11->IsDictionary());
461
462 RetainPtr<CPDF_Object> obj12 = obj_stream->ParseObject(&holder, 12, 1);
463 ASSERT_TRUE(obj12);
464 EXPECT_EQ(12u, obj12->GetObjNum());
465 EXPECT_EQ(0u, obj12->GetGenNum());
466 EXPECT_TRUE(obj12->IsArray());
467 }
468
TEST(ObjectStreamTest,StreamDictUnorderedObjectOffsets)469 TEST(ObjectStreamTest, StreamDictUnorderedObjectOffsets) {
470 // ISO 32000-1:2008 spec. section 7.5.7, says offsets shall be in increasing
471 // order.
472 // TODO(thestig): Should CPDF_ObjectStream check for this and reject this
473 // object stream?
474 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
475 dict->SetNewFor<CPDF_Name>("Type", "ObjStm");
476 dict->SetNewFor<CPDF_Number>("N", 3);
477 dict->SetNewFor<CPDF_Number>("First", 16);
478
479 const char kStreamContent[] = "10 21 11 0 12 14<</Name /Foo>>[1 2 3]4";
480 ByteStringView contents_view(kStreamContent);
481 auto stream = pdfium::MakeRetain<CPDF_Stream>(
482 DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict);
483 auto obj_stream = CPDF_ObjectStream::Create(std::move(stream));
484 ASSERT_TRUE(obj_stream);
485
486 EXPECT_THAT(obj_stream->object_info(),
487 ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 21),
488 CPDF_ObjectStream::ObjectInfo(11, 0),
489 CPDF_ObjectStream::ObjectInfo(12, 14)));
490
491 CPDF_IndirectObjectHolder holder;
492 RetainPtr<CPDF_Object> obj10 = obj_stream->ParseObject(&holder, 10, 0);
493 ASSERT_TRUE(obj10);
494 EXPECT_EQ(10u, obj10->GetObjNum());
495 EXPECT_EQ(0u, obj10->GetGenNum());
496 EXPECT_TRUE(obj10->IsNumber());
497
498 RetainPtr<CPDF_Object> obj11 = obj_stream->ParseObject(&holder, 11, 1);
499 ASSERT_TRUE(obj11);
500 EXPECT_EQ(11u, obj11->GetObjNum());
501 EXPECT_EQ(0u, obj11->GetGenNum());
502 EXPECT_TRUE(obj11->IsDictionary());
503
504 RetainPtr<CPDF_Object> obj12 = obj_stream->ParseObject(&holder, 12, 2);
505 ASSERT_TRUE(obj12);
506 EXPECT_EQ(12u, obj12->GetObjNum());
507 EXPECT_EQ(0u, obj12->GetGenNum());
508 EXPECT_TRUE(obj12->IsArray());
509 }
510