• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 PDFium Authors. All rights reserved.
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 <memory>
9 #include <utility>
10 
11 #include "core/fpdfapi/parser/cpdf_array.h"
12 #include "core/fpdfapi/parser/cpdf_dictionary.h"
13 #include "core/fpdfapi/parser/cpdf_indirect_object_holder.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/ptr_util.h"
21 
22 namespace {
23 
24 class TestReadValidator final : public CPDF_ReadValidator {
25  public:
26   template <typename T, typename... Args>
27   friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
28 
SimulateReadError()29   void SimulateReadError() { ReadBlockAtOffset(nullptr, 0, 1); }
30 
31  private:
TestReadValidator()32   TestReadValidator()
33       : CPDF_ReadValidator(pdfium::MakeRetain<InvalidSeekableReadStream>(100),
34                            nullptr) {}
~TestReadValidator()35   ~TestReadValidator() override {}
36 };
37 
38 class TestHolder final : public CPDF_IndirectObjectHolder {
39  public:
40   enum class ObjectState {
41     Unavailable,
42     Available,
43   };
TestHolder()44   TestHolder() : validator_(pdfium::MakeRetain<TestReadValidator>()) {}
~TestHolder()45   ~TestHolder() override {}
46 
47   // CPDF_IndirectObjectHolder overrides:
GetOrParseIndirectObject(uint32_t objnum)48   CPDF_Object* GetOrParseIndirectObject(uint32_t objnum) override {
49     auto it = objects_data_.find(objnum);
50     if (it == objects_data_.end())
51       return nullptr;
52 
53     ObjectData& obj_data = it->second;
54     if (obj_data.state == ObjectState::Unavailable) {
55       validator_->SimulateReadError();
56       return nullptr;
57     }
58     return obj_data.object.Get();
59   }
60 
GetValidator()61   RetainPtr<CPDF_ReadValidator> GetValidator() { return validator_; }
62 
AddObject(uint32_t objnum,RetainPtr<CPDF_Object> object,ObjectState state)63   void AddObject(uint32_t objnum,
64                  RetainPtr<CPDF_Object> object,
65                  ObjectState state) {
66     ObjectData object_data;
67     object_data.object = std::move(object);
68     object_data.state = state;
69     ASSERT(objects_data_.find(objnum) == objects_data_.end());
70     objects_data_[objnum] = std::move(object_data);
71   }
72 
SetObjectState(uint32_t objnum,ObjectState state)73   void SetObjectState(uint32_t objnum, ObjectState state) {
74     auto it = objects_data_.find(objnum);
75     ASSERT(it != objects_data_.end());
76     ObjectData& obj_data = it->second;
77     obj_data.state = state;
78   }
79 
GetTestObject(uint32_t objnum)80   CPDF_Object* GetTestObject(uint32_t objnum) {
81     auto it = objects_data_.find(objnum);
82     if (it == objects_data_.end())
83       return nullptr;
84     return it->second.object.Get();
85   }
86 
87  private:
88   struct ObjectData {
89     RetainPtr<CPDF_Object> object;
90     ObjectState state = ObjectState::Unavailable;
91   };
92   std::map<uint32_t, ObjectData> objects_data_;
93   RetainPtr<TestReadValidator> validator_;
94 };
95 
96 }  // namespace
97 
TEST(CPDF_PageObjectAvailTest,ExcludePages)98 TEST(CPDF_PageObjectAvailTest, ExcludePages) {
99   TestHolder holder;
100   holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(),
101                    TestHolder::ObjectState::Available);
102   holder.GetTestObject(1)->GetDict()->SetNewFor<CPDF_Reference>("Kids", &holder,
103                                                                 2);
104   holder.AddObject(2, pdfium::MakeRetain<CPDF_Array>(),
105                    TestHolder::ObjectState::Available);
106   holder.GetTestObject(2)->AsArray()->AddNew<CPDF_Reference>(&holder, 3);
107 
108   holder.AddObject(3, pdfium::MakeRetain<CPDF_Dictionary>(),
109                    TestHolder::ObjectState::Available);
110   holder.GetTestObject(3)->GetDict()->SetFor(
111       "Type", pdfium::MakeRetain<CPDF_String>(nullptr, "Page", false));
112   holder.GetTestObject(3)->GetDict()->SetNewFor<CPDF_Reference>("OtherPageData",
113                                                                 &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::DocAvailStatus::DataAvailable, avail.CheckAvail());
123 }
124