1 // Copyright 2018 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_object_stream.h" 6 7 #include <utility> 8 9 #include "core/fpdfapi/parser/cpdf_dictionary.h" 10 #include "core/fpdfapi/parser/cpdf_number.h" 11 #include "core/fpdfapi/parser/cpdf_parser.h" 12 #include "core/fpdfapi/parser/cpdf_reference.h" 13 #include "core/fpdfapi/parser/cpdf_stream.h" 14 #include "core/fpdfapi/parser/cpdf_stream_acc.h" 15 #include "core/fpdfapi/parser/cpdf_syntax_parser.h" 16 #include "core/fxcrt/cfx_readonlymemorystream.h" 17 #include "core/fxcrt/fx_safe_types.h" 18 #include "third_party/base/ptr_util.h" 19 #include "third_party/base/stl_util.h" 20 21 // static IsObjectsStreamObject(const CPDF_Object * object)22bool CPDF_ObjectStream::IsObjectsStreamObject(const CPDF_Object* object) { 23 const CPDF_Stream* stream = ToStream(object); 24 if (!stream) 25 return false; 26 27 const CPDF_Dictionary* stream_dict = stream->GetDict(); 28 if (!stream_dict) 29 return false; 30 31 if (stream_dict->GetStringFor("Type") != "ObjStm") 32 return false; 33 34 const CPDF_Number* number_of_objects = 35 ToNumber(stream_dict->GetObjectFor("N")); 36 if (!number_of_objects || !number_of_objects->IsInteger() || 37 number_of_objects->GetInteger() < 0 || 38 number_of_objects->GetInteger() >= 39 static_cast<int>(CPDF_Parser::kMaxObjectNumber)) { 40 return false; 41 } 42 43 const CPDF_Number* first_object_offset = 44 ToNumber(stream_dict->GetObjectFor("First")); 45 if (!first_object_offset || !first_object_offset->IsInteger() || 46 first_object_offset->GetInteger() < 0) { 47 return false; 48 } 49 50 return true; 51 } 52 53 // static Create(const CPDF_Stream * stream)54std::unique_ptr<CPDF_ObjectStream> CPDF_ObjectStream::Create( 55 const CPDF_Stream* stream) { 56 if (!IsObjectsStreamObject(stream)) 57 return nullptr; 58 // The ctor of CPDF_ObjectStream is protected. Use WrapUnique instead 59 // MakeUnique. 60 return pdfium::WrapUnique(new CPDF_ObjectStream(stream)); 61 } 62 CPDF_ObjectStream(const CPDF_Stream * obj_stream)63CPDF_ObjectStream::CPDF_ObjectStream(const CPDF_Stream* obj_stream) 64 : obj_num_(obj_stream->GetObjNum()), 65 first_object_offset_(obj_stream->GetDict()->GetIntegerFor("First")) { 66 ASSERT(IsObjectsStreamObject(obj_stream)); 67 if (const auto* extends_ref = 68 ToReference(obj_stream->GetDict()->GetObjectFor("Extends"))) { 69 extends_obj_num_ = extends_ref->GetRefObjNum(); 70 } 71 Init(obj_stream); 72 } 73 74 CPDF_ObjectStream::~CPDF_ObjectStream() = default; 75 HasObject(uint32_t obj_number) const76bool CPDF_ObjectStream::HasObject(uint32_t obj_number) const { 77 return pdfium::ContainsKey(objects_offsets_, obj_number); 78 } 79 ParseObject(CPDF_IndirectObjectHolder * pObjList,uint32_t obj_number) const80RetainPtr<CPDF_Object> CPDF_ObjectStream::ParseObject( 81 CPDF_IndirectObjectHolder* pObjList, 82 uint32_t obj_number) const { 83 const auto it = objects_offsets_.find(obj_number); 84 if (it == objects_offsets_.end()) 85 return nullptr; 86 87 RetainPtr<CPDF_Object> result = ParseObjectAtOffset(pObjList, it->second); 88 if (!result) 89 return nullptr; 90 91 result->SetObjNum(obj_number); 92 return result; 93 } 94 Init(const CPDF_Stream * stream)95void CPDF_ObjectStream::Init(const CPDF_Stream* stream) { 96 { 97 auto stream_acc = pdfium::MakeRetain<CPDF_StreamAcc>(stream); 98 stream_acc->LoadAllDataFiltered(); 99 const uint32_t data_size = stream_acc->GetSize(); 100 data_stream_ = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( 101 stream_acc->DetachData(), data_size); 102 } 103 104 CPDF_SyntaxParser syntax(data_stream_); 105 const int object_count = stream->GetDict()->GetIntegerFor("N"); 106 for (int32_t i = object_count; i > 0; --i) { 107 if (syntax.GetPos() >= data_stream_->GetSize()) 108 break; 109 110 const uint32_t obj_num = syntax.GetDirectNum(); 111 const uint32_t obj_offset = syntax.GetDirectNum(); 112 if (!obj_num) 113 continue; 114 115 objects_offsets_[obj_num] = obj_offset; 116 } 117 } 118 ParseObjectAtOffset(CPDF_IndirectObjectHolder * pObjList,uint32_t object_offset) const119RetainPtr<CPDF_Object> CPDF_ObjectStream::ParseObjectAtOffset( 120 CPDF_IndirectObjectHolder* pObjList, 121 uint32_t object_offset) const { 122 FX_SAFE_FILESIZE offset_in_stream = first_object_offset_; 123 offset_in_stream += object_offset; 124 125 if (!offset_in_stream.IsValid()) 126 return nullptr; 127 128 if (offset_in_stream.ValueOrDie() >= data_stream_->GetSize()) 129 return nullptr; 130 131 CPDF_SyntaxParser syntax(data_stream_); 132 syntax.SetPos(offset_in_stream.ValueOrDie()); 133 return syntax.GetObjectBody(pObjList); 134 } 135