Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cpdf_object_avail_unittest.cpp
Go to the documentation of this file.
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_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_read_validator.h"
14#include "core/fpdfapi/parser/cpdf_reference.h"
15#include "core/fpdfapi/parser/cpdf_string.h"
16#include "core/fxcrt/check.h"
17#include "core/fxcrt/fx_stream.h"
18#include "core/fxcrt/notreached.h"
19#include "testing/gtest/include/gtest/gtest.h"
20#include "testing/invalid_seekable_read_stream.h"
21
22namespace {
23
24class TestReadValidator final : public CPDF_ReadValidator {
25 public:
27
28 void SimulateReadError() { ReadBlockAtOffset({}, 0); }
29
30 private:
31 TestReadValidator()
32 : CPDF_ReadValidator(pdfium::MakeRetain<InvalidSeekableReadStream>(100),
33 nullptr) {}
34 ~TestReadValidator() override = default;
35};
36
37class TestHolder final : public CPDF_IndirectObjectHolder {
38 public:
39 enum class ObjectState {
40 Unavailable,
41 Available,
42 };
43 TestHolder() : validator_(pdfium::MakeRetain<TestReadValidator>()) {}
44 ~TestHolder() override = default;
45
46 // CPDF_IndirectObjectHolder overrides:
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
60 RetainPtr<CPDF_ReadValidator> GetValidator() { return validator_; }
61
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
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
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
95class CPDF_ObjectAvailFailOnExclude final : public CPDF_ObjectAvail {
96 public:
97 using CPDF_ObjectAvail::CPDF_ObjectAvail;
98 ~CPDF_ObjectAvailFailOnExclude() override = default;
99 bool ExcludeObject(const CPDF_Object* object) const override {
101 }
102};
103
104class CPDF_ObjectAvailExcludeArray final : public CPDF_ObjectAvail {
105 public:
106 using CPDF_ObjectAvail::CPDF_ObjectAvail;
107 ~CPDF_ObjectAvailExcludeArray() override = default;
108 bool ExcludeObject(const CPDF_Object* object) const override {
109 return object->IsArray();
110 }
111};
112
113class CPDF_ObjectAvailExcludeTypeKey final : public CPDF_ObjectAvail {
114 public:
115 using CPDF_ObjectAvail::CPDF_ObjectAvail;
116 ~CPDF_ObjectAvailExcludeTypeKey() override = default;
117 bool ExcludeObject(const CPDF_Object* object) const override {
118 // The value of "Type" may be reference, and if it is not available, we can
119 // incorrect filter objects.
120 // In this case CPDF_ObjectAvail should wait availability of this item and
121 // call ExcludeObject again.
122 return object->IsDictionary() &&
123 object->GetDict()->GetByteStringFor("Type") == "Exclude me";
124 }
125};
126
127} // namespace
128
130 TestHolder holder;
131 holder.AddObject(1, pdfium::MakeRetain<CPDF_String>(nullptr, "string"),
132 TestHolder::ObjectState::Unavailable);
133 CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 1);
134 EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail());
135 holder.SetObjectState(1, TestHolder::ObjectState::Available);
136 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail());
137}
138
140 TestHolder holder;
141 holder.AddObject(1, pdfium::MakeRetain<CPDF_Reference>(&holder, 2),
142 TestHolder::ObjectState::Unavailable);
143 holder.AddObject(2, pdfium::MakeRetain<CPDF_String>(nullptr, "string"),
144 TestHolder::ObjectState::Unavailable);
145 CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 1);
146 EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail());
147
148 holder.SetObjectState(1, TestHolder::ObjectState::Available);
149 EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail());
150
151 holder.SetObjectState(2, TestHolder::ObjectState::Available);
152 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail());
153}
154
156 TestHolder holder;
157 holder.AddObject(1, pdfium::MakeRetain<CPDF_Reference>(&holder, 2),
158 TestHolder::ObjectState::Unavailable);
159 holder.AddObject(2, pdfium::MakeRetain<CPDF_Reference>(&holder, 3),
160 TestHolder::ObjectState::Unavailable);
161 holder.AddObject(3, pdfium::MakeRetain<CPDF_Reference>(&holder, 1),
162 TestHolder::ObjectState::Unavailable);
163
164 CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 1);
165 EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail());
166
167 holder.SetObjectState(1, TestHolder::ObjectState::Available);
168 EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail());
169
170 holder.SetObjectState(2, TestHolder::ObjectState::Available);
171 EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail());
172
173 holder.SetObjectState(3, TestHolder::ObjectState::Available);
174 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail());
175}
176
178 TestHolder holder;
179 holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(),
180 TestHolder::ObjectState::Unavailable);
181 holder.AddObject(2, pdfium::MakeRetain<CPDF_Dictionary>(),
182 TestHolder::ObjectState::Unavailable);
183
184 holder.GetTestObject(2)->GetMutableDict()->SetNewFor<CPDF_Reference>(
185 "Parent", &holder, 1);
186
187 CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 2);
188 EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail());
189
190 holder.SetObjectState(2, TestHolder::ObjectState::Available);
191 // Object should be available in case when "Parent" object is unavailable.
192 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail());
193}
194
196 TestHolder holder;
197 const uint32_t kDepth = 100;
198 for (uint32_t i = 1; i < kDepth; ++i) {
199 holder.AddObject(i, pdfium::MakeRetain<CPDF_Dictionary>(),
200 TestHolder::ObjectState::Unavailable);
201 // Add ref to next dictionary.
202 holder.GetTestObject(i)->GetMutableDict()->SetNewFor<CPDF_Reference>(
203 "Child", &holder, i + 1);
204 }
205 // Add final object
206 holder.AddObject(kDepth, pdfium::MakeRetain<CPDF_Dictionary>(),
207 TestHolder::ObjectState::Unavailable);
208
209 CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 1);
210 for (uint32_t i = 1; i <= kDepth; ++i) {
211 EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail());
212 holder.SetObjectState(i, TestHolder::ObjectState::Available);
213 }
214 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail());
215}
216
218 TestHolder holder;
219 holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(),
220 TestHolder::ObjectState::Available);
221 CPDF_ObjectAvailFailOnExclude avail(holder.GetValidator(), &holder, 1);
222 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail());
223}
224
226 TestHolder holder;
227 holder.AddObject(1, pdfium::MakeRetain<CPDF_Reference>(&holder, 2),
228 TestHolder::ObjectState::Available);
229 holder.AddObject(2, pdfium::MakeRetain<CPDF_Dictionary>(),
230 TestHolder::ObjectState::Available);
231 CPDF_ObjectAvailFailOnExclude avail(holder.GetValidator(), &holder, 1);
232 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail());
233}
234
236 TestHolder holder;
237 holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(),
238 TestHolder::ObjectState::Available);
239 holder.GetTestObject(1)->GetMutableDict()->SetNewFor<CPDF_Reference>(
240 "ArrayRef", &holder, 2);
241 holder.AddObject(2, pdfium::MakeRetain<CPDF_Array>(),
242 TestHolder::ObjectState::Available);
243 holder.GetTestObject(2)->AsMutableArray()->AppendNew<CPDF_Reference>(&holder,
244 2);
245
246 // Add string, which is refered by array item. It is should not be checked.
247 holder.AddObject(
248 3, pdfium::MakeRetain<CPDF_String>(nullptr, "Not available string"),
249 TestHolder::ObjectState::Unavailable);
250 CPDF_ObjectAvailExcludeArray avail(holder.GetValidator(), &holder, 1);
251 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail());
252}
253
255 TestHolder holder;
256 holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(),
257 TestHolder::ObjectState::Available);
258 holder.GetTestObject(1)->GetMutableDict()->SetNewFor<CPDF_Reference>(
259 "DictRef", &holder, 2);
260 holder.AddObject(2, pdfium::MakeRetain<CPDF_Dictionary>(),
261 TestHolder::ObjectState::Available);
262
263 holder.GetTestObject(2)->GetMutableDict()->SetNewFor<CPDF_Reference>(
264 "Type", &holder, 3);
265 // The value of "Type" key is not available at start
266 holder.AddObject(3, pdfium::MakeRetain<CPDF_String>(nullptr, "Exclude me"),
267 TestHolder::ObjectState::Unavailable);
268
269 holder.GetTestObject(2)->GetMutableDict()->SetNewFor<CPDF_Reference>(
270 "OtherData", &holder, 4);
271 // Add string, which is referred by dictionary item. It is should not be
272 // checked, because the dictionary with it, should be skipped.
273 holder.AddObject(
274 4, pdfium::MakeRetain<CPDF_String>(nullptr, "Not available string"),
275 TestHolder::ObjectState::Unavailable);
276
277 CPDF_ObjectAvailExcludeTypeKey avail(holder.GetValidator(), &holder, 1);
278
279 EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail());
280
281 // Make "Type" value object available.
282 holder.SetObjectState(3, TestHolder::ObjectState::Available);
283
284 // Now object should be available, although the object '4' is not available,
285 // because it is in skipped dictionary.
286 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail());
287}
288
290 TestHolder holder;
291 holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(),
292 TestHolder::ObjectState::Available);
293 holder.GetTestObject(1)->GetMutableDict()->SetNewFor<CPDF_Reference>(
294 "NotExistsObjRef", &holder, 2);
295 CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 1);
296 // Now object should be available, although the object '2' is not exists. But
297 // all exists in file related data are checked.
298 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail());
299}
300
302 TestHolder holder;
303 holder.AddObject(1, pdfium::MakeRetain<CPDF_String>(nullptr, "string"),
304 TestHolder::ObjectState::Unavailable);
305
306 CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 1);
307 EXPECT_EQ(avail.CheckAvail(), avail.CheckAvail());
308
309 holder.SetObjectState(1, TestHolder::ObjectState::Available);
310 EXPECT_EQ(avail.CheckAvail(), avail.CheckAvail());
311}
312
314 TestHolder holder;
315 holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(),
316 TestHolder::ObjectState::Available);
317
318 holder.GetTestObject(1)->GetMutableDict()->SetNewFor<CPDF_Reference>(
319 "Data", &holder, 2);
320 auto root =
321 holder.GetTestObject(1)->GetMutableDict()->SetNewFor<CPDF_Dictionary>(
322 "Dict");
323
324 root->SetNewFor<CPDF_Reference>("Self", &holder, 1);
325 holder.AddObject(2, pdfium::MakeRetain<CPDF_String>(nullptr, "Data"),
326 TestHolder::ObjectState::Unavailable);
327
328 CPDF_ObjectAvail avail(holder.GetValidator(), &holder, root);
329 EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail());
330
331 holder.SetObjectState(2, TestHolder::ObjectState::Available);
332 EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail());
333}
#define DCHECK
Definition check.h:33
std::vector< RetainPtr< CPDF_Object > >::const_iterator const_iterator
Definition cpdf_array.h:29
std::map< ByteString, RetainPtr< CPDF_Object >, std::less<> > DictMap
CPDF_DataAvail::DocAvailStatus CheckAvail()
bool IsArray() const
virtual CPDF_Array * AsMutableArray()
TEST(FXCRYPT, MD5GenerateEmtpyData)
#define NOTREACHED_NORETURN()
Definition notreached.h:22
#define CONSTRUCT_VIA_MAKE_RETAIN
Definition retain_ptr.h:222