| // Copyright 2018 PDFium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "core/fpdfapi/parser/cpdf_object_stream.h" |
| |
| #include <utility> |
| |
| #include "core/fpdfapi/parser/cpdf_dictionary.h" |
| #include "core/fpdfapi/parser/cpdf_number.h" |
| #include "core/fpdfapi/parser/cpdf_parser.h" |
| #include "core/fpdfapi/parser/cpdf_reference.h" |
| #include "core/fpdfapi/parser/cpdf_stream.h" |
| #include "core/fpdfapi/parser/cpdf_stream_acc.h" |
| #include "core/fpdfapi/parser/cpdf_syntax_parser.h" |
| #include "core/fxcrt/cfx_memorystream.h" |
| #include "third_party/base/stl_util.h" |
| |
| // static |
| bool CPDF_ObjectStream::IsObjectsStreamObject(const CPDF_Object* object) { |
| const CPDF_Stream* stream = ToStream(object); |
| if (!stream) |
| return false; |
| |
| const CPDF_Dictionary* stream_dict = stream->GetDict(); |
| if (!stream_dict) |
| return false; |
| |
| if (stream_dict->GetStringFor("Type") != "ObjStm") |
| return false; |
| |
| const CPDF_Number* number_of_objects = |
| ToNumber(stream_dict->GetObjectFor("N")); |
| if (!number_of_objects || !number_of_objects->IsInteger() || |
| number_of_objects->GetInteger() < 0 || |
| number_of_objects->GetInteger() >= |
| static_cast<int>(CPDF_Parser::kMaxObjectNumber)) { |
| return false; |
| } |
| |
| const CPDF_Number* first_object_offset = |
| ToNumber(stream_dict->GetObjectFor("First")); |
| if (!first_object_offset || !first_object_offset->IsInteger() || |
| first_object_offset->GetInteger() < 0) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| // static |
| std::unique_ptr<CPDF_ObjectStream> CPDF_ObjectStream::Create( |
| const CPDF_Stream* stream) { |
| if (!IsObjectsStreamObject(stream)) |
| return nullptr; |
| // The ctor of CPDF_ObjectStream is protected. Use WrapUnique instead |
| // MakeUnique. |
| return pdfium::WrapUnique(new CPDF_ObjectStream(stream)); |
| } |
| |
| CPDF_ObjectStream::CPDF_ObjectStream(const CPDF_Stream* obj_stream) |
| : obj_num_(obj_stream->GetObjNum()), |
| first_object_offset_(obj_stream->GetDict()->GetIntegerFor("First")) { |
| ASSERT(IsObjectsStreamObject(obj_stream)); |
| if (const auto* extends_ref = |
| ToReference(obj_stream->GetDict()->GetObjectFor("Extends"))) { |
| extends_obj_num_ = extends_ref->GetRefObjNum(); |
| } |
| Init(obj_stream); |
| } |
| |
| CPDF_ObjectStream::~CPDF_ObjectStream() = default; |
| |
| bool CPDF_ObjectStream::HasObject(uint32_t obj_number) const { |
| return pdfium::ContainsKey(objects_offsets_, obj_number); |
| } |
| |
| std::unique_ptr<CPDF_Object> CPDF_ObjectStream::ParseObject( |
| CPDF_IndirectObjectHolder* pObjList, |
| uint32_t obj_number) const { |
| const auto it = objects_offsets_.find(obj_number); |
| if (it == objects_offsets_.end()) |
| return nullptr; |
| |
| std::unique_ptr<CPDF_Object> result = |
| ParseObjectAtOffset(pObjList, it->second); |
| if (!result) |
| return nullptr; |
| |
| result->SetObjNum(obj_number); |
| return result; |
| } |
| |
| void CPDF_ObjectStream::Init(const CPDF_Stream* stream) { |
| { |
| auto stream_acc = pdfium::MakeRetain<CPDF_StreamAcc>(stream); |
| stream_acc->LoadAllDataFiltered(); |
| const uint32_t data_size = stream_acc->GetSize(); |
| data_stream_ = pdfium::MakeRetain<CFX_MemoryStream>( |
| stream_acc->DetachData(), data_size); |
| } |
| |
| CPDF_SyntaxParser syntax(data_stream_); |
| const int object_count = stream->GetDict()->GetIntegerFor("N"); |
| for (int32_t i = object_count; i > 0; --i) { |
| if (syntax.GetPos() >= data_stream_->GetSize()) |
| break; |
| |
| const uint32_t obj_num = syntax.GetDirectNum(); |
| const uint32_t obj_offset = syntax.GetDirectNum(); |
| if (!obj_num) |
| continue; |
| |
| objects_offsets_[obj_num] = obj_offset; |
| } |
| } |
| |
| std::unique_ptr<CPDF_Object> CPDF_ObjectStream::ParseObjectAtOffset( |
| CPDF_IndirectObjectHolder* pObjList, |
| uint32_t object_offset) const { |
| FX_SAFE_FILESIZE offset_in_stream = first_object_offset_; |
| offset_in_stream += object_offset; |
| |
| if (!offset_in_stream.IsValid()) |
| return nullptr; |
| |
| if (offset_in_stream.ValueOrDie() >= data_stream_->GetSize()) |
| return nullptr; |
| |
| CPDF_SyntaxParser syntax(data_stream_); |
| syntax.SetPos(offset_in_stream.ValueOrDie()); |
| return syntax.GetObjectBody(pObjList); |
| } |