xref: /aosp_15_r20/external/pdfium/core/fpdfapi/parser/cpdf_page_object_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_page_object_avail.h"
6 
7 #include <map>
8 #include <utility>
9 
10 #include "core/fpdfapi/parser/cpdf_array.h"
11 #include "core/fpdfapi/parser/cpdf_dictionary.h"
12 #include "core/fpdfapi/parser/cpdf_indirect_object_holder.h"
13 #include "core/fpdfapi/parser/cpdf_name.h"
14 #include "core/fpdfapi/parser/cpdf_read_validator.h"
15 #include "core/fpdfapi/parser/cpdf_reference.h"
16 #include "core/fpdfapi/parser/cpdf_string.h"
17 #include "core/fxcrt/fx_stream.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "testing/invalid_seekable_read_stream.h"
20 #include "third_party/base/check.h"
21 
22 namespace {
23 
24 class TestReadValidator final : public CPDF_ReadValidator {
25  public:
26   CONSTRUCT_VIA_MAKE_RETAIN;
27 
SimulateReadError()28   void SimulateReadError() { ReadBlockAtOffset({}, 0); }
29 
30  private:
TestReadValidator()31   TestReadValidator()
32       : CPDF_ReadValidator(pdfium::MakeRetain<InvalidSeekableReadStream>(100),
33                            nullptr) {}
34   ~TestReadValidator() override = default;
35 };
36 
37 class TestHolder final : public CPDF_IndirectObjectHolder {
38  public:
39   enum class ObjectState {
40     Unavailable,
41     Available,
42   };
TestHolder()43   TestHolder() : validator_(pdfium::MakeRetain<TestReadValidator>()) {}
44   ~TestHolder() override = default;
45 
46   // CPDF_IndirectObjectHolder overrides:
ParseIndirectObject(uint32_t objnum)47   RetainPtr<CPDF_Object> ParseIndirectObject(uint32_t objnum) override {
48     auto it = objects_data_.find(objnum);
49     if (it == objects_data_.end())
50       return nullptr;
51 
52     ObjectData& obj_data = it->second;
53     if (obj_data.state == ObjectState::Unavailable) {
54       validator_->SimulateReadError();
55       return nullptr;
56     }
57     return obj_data.object;
58   }
59 
GetValidator()60   RetainPtr<CPDF_ReadValidator> GetValidator() { return validator_; }
61 
AddObject(uint32_t objnum,RetainPtr<CPDF_Object> object,ObjectState state)62   void AddObject(uint32_t objnum,
63                  RetainPtr<CPDF_Object> object,
64                  ObjectState state) {
65     ObjectData object_data;
66     object_data.object = std::move(object);
67     object_data.state = state;
68     DCHECK(objects_data_.find(objnum) == objects_data_.end());
69     objects_data_[objnum] = std::move(object_data);
70   }
71 
SetObjectState(uint32_t objnum,ObjectState state)72   void SetObjectState(uint32_t objnum, ObjectState state) {
73     auto it = objects_data_.find(objnum);
74     DCHECK(it != objects_data_.end());
75     ObjectData& obj_data = it->second;
76     obj_data.state = state;
77   }
78 
GetTestObject(uint32_t objnum)79   CPDF_Object* GetTestObject(uint32_t objnum) {
80     auto it = objects_data_.find(objnum);
81     if (it == objects_data_.end())
82       return nullptr;
83     return it->second.object.Get();
84   }
85 
86  private:
87   struct ObjectData {
88     RetainPtr<CPDF_Object> object;
89     ObjectState state = ObjectState::Unavailable;
90   };
91   std::map<uint32_t, ObjectData> objects_data_;
92   RetainPtr<TestReadValidator> validator_;
93 };
94 
95 }  // namespace
96 
TEST(PageObjectAvailTest,ExcludePages)97 TEST(PageObjectAvailTest, ExcludePages) {
98   TestHolder holder;
99   holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(),
100                    TestHolder::ObjectState::Available);
101   holder.GetTestObject(1)->GetMutableDict()->SetNewFor<CPDF_Reference>(
102       "Kids", &holder, 2);
103   holder.AddObject(2, pdfium::MakeRetain<CPDF_Array>(),
104                    TestHolder::ObjectState::Available);
105   holder.GetTestObject(2)->AsMutableArray()->AppendNew<CPDF_Reference>(&holder,
106                                                                        3);
107 
108   holder.AddObject(3, pdfium::MakeRetain<CPDF_Dictionary>(),
109                    TestHolder::ObjectState::Available);
110   holder.GetTestObject(3)->GetMutableDict()->SetFor(
111       "Type", pdfium::MakeRetain<CPDF_Name>(nullptr, "Page"));
112   holder.GetTestObject(3)->GetMutableDict()->SetNewFor<CPDF_Reference>(
113       "OtherPageData", &holder, 4);
114   // Add unavailable object related to other page.
115   holder.AddObject(
116       4, pdfium::MakeRetain<CPDF_String>(nullptr, "Other page data", false),
117       TestHolder::ObjectState::Unavailable);
118 
119   CPDF_PageObjectAvail avail(holder.GetValidator(), &holder, 1);
120   // Now object should be available, although the object '4' is not available,
121   // because it is in skipped other page.
122   EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail());
123 }
124