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