Home | History | Annotate | Download | only in parser
      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/fx_string_testhelpers.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 #include "third_party/base/ptr_util.h"
     21 
     22 namespace {
     23 
     24 
     25 class TestReadValidator : public CPDF_ReadValidator {
     26  public:
     27   template <typename T, typename... Args>
     28   friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
     29 
     30   void SimulateReadError() { ReadBlock(nullptr, 0, 1); }
     31 
     32  protected:
     33   TestReadValidator()
     34       : CPDF_ReadValidator(
     35             pdfium::MakeRetain<CFX_InvalidSeekableReadStream>(100),
     36             nullptr) {}
     37   ~TestReadValidator() override {}
     38 };
     39 
     40 class TestHolder : public CPDF_IndirectObjectHolder {
     41  public:
     42   enum class ObjectState {
     43     Unavailable,
     44     Available,
     45   };
     46   TestHolder() : validator_(pdfium::MakeRetain<TestReadValidator>()) {}
     47   ~TestHolder() override {}
     48 
     49   // CPDF_IndirectObjectHolder overrides:
     50   CPDF_Object* GetOrParseIndirectObject(uint32_t objnum) override {
     51     auto it = objects_data_.find(objnum);
     52     if (it == objects_data_.end())
     53       return nullptr;
     54 
     55     ObjectData& obj_data = it->second;
     56     if (obj_data.state == ObjectState::Unavailable) {
     57       validator_->SimulateReadError();
     58       return nullptr;
     59     }
     60     return obj_data.object.get();
     61   }
     62 
     63   RetainPtr<CPDF_ReadValidator> GetValidator() { return validator_; }
     64 
     65   void AddObject(uint32_t objnum,
     66                  std::unique_ptr<CPDF_Object> object,
     67                  ObjectState state) {
     68     ObjectData object_data;
     69     object_data.object = std::move(object);
     70     object_data.state = state;
     71     ASSERT(objects_data_.find(objnum) == objects_data_.end());
     72     objects_data_[objnum] = std::move(object_data);
     73   }
     74 
     75   void SetObjectState(uint32_t objnum, ObjectState state) {
     76     auto it = objects_data_.find(objnum);
     77     ASSERT(it != objects_data_.end());
     78     ObjectData& obj_data = it->second;
     79     obj_data.state = state;
     80   }
     81 
     82   CPDF_Object* GetTestObject(uint32_t objnum) {
     83     auto it = objects_data_.find(objnum);
     84     if (it == objects_data_.end())
     85       return nullptr;
     86     return it->second.object.get();
     87   }
     88 
     89  private:
     90   struct ObjectData {
     91     std::unique_ptr<CPDF_Object> object;
     92     ObjectState state = ObjectState::Unavailable;
     93   };
     94   std::map<uint32_t, ObjectData> objects_data_;
     95   RetainPtr<TestReadValidator> validator_;
     96 };
     97 
     98 }  // namespace
     99 
    100 TEST(CPDF_PageObjectAvailTest, ExcludePages) {
    101   TestHolder holder;
    102   holder.AddObject(1, pdfium::MakeUnique<CPDF_Dictionary>(),
    103                    TestHolder::ObjectState::Available);
    104   holder.GetTestObject(1)->GetDict()->SetNewFor<CPDF_Reference>("Kids", &holder,
    105                                                                 2);
    106   holder.AddObject(2, pdfium::MakeUnique<CPDF_Array>(),
    107                    TestHolder::ObjectState::Available);
    108   holder.GetTestObject(2)->AsArray()->AddNew<CPDF_Reference>(&holder, 3);
    109 
    110   holder.AddObject(3, pdfium::MakeUnique<CPDF_Dictionary>(),
    111                    TestHolder::ObjectState::Available);
    112   holder.GetTestObject(3)->GetDict()->SetFor(
    113       "Type", pdfium::MakeUnique<CPDF_String>(nullptr, "Page", false));
    114   holder.GetTestObject(3)->GetDict()->SetNewFor<CPDF_Reference>("OtherPageData",
    115                                                                 &holder, 4);
    116   // Add unavailable object related to other page.
    117   holder.AddObject(
    118       4, pdfium::MakeUnique<CPDF_String>(nullptr, "Other page data", false),
    119       TestHolder::ObjectState::Unavailable);
    120 
    121   CPDF_PageObjectAvail avail(holder.GetValidator().Get(), &holder, 1);
    122   // Now object should be available, although the object '4' is not available,
    123   // because it is in skipped other page.
    124   EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail());
    125 }
    126