// Copyright 2018 The PDFium Authors // 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 #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/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fxcrt/cfx_read_only_span_stream.h" #include "core/fxcrt/check.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxcrt/ptr_util.h" namespace { bool IsObjectStream(const CPDF_Stream* stream) { if (!stream) return false; // See ISO 32000-1:2008 spec, table 16. RetainPtr stream_dict = stream->GetDict(); if (!ValidateDictType(stream_dict.Get(), "ObjStm")) return false; RetainPtr number_of_objects = stream_dict->GetNumberFor("N"); if (!number_of_objects || !number_of_objects->IsInteger() || number_of_objects->GetInteger() < 0 || number_of_objects->GetInteger() >= static_cast(CPDF_Parser::kMaxObjectNumber)) { return false; } RetainPtr first_object_offset = stream_dict->GetNumberFor("First"); if (!first_object_offset || !first_object_offset->IsInteger() || first_object_offset->GetInteger() < 0) { return false; } return true; } } // namespace // static std::unique_ptr CPDF_ObjectStream::Create( RetainPtr stream) { if (!IsObjectStream(stream.Get())) return nullptr; // Protected constructor. return pdfium::WrapUnique(new CPDF_ObjectStream(std::move(stream))); } CPDF_ObjectStream::CPDF_ObjectStream(RetainPtr obj_stream) : stream_acc_(pdfium::MakeRetain(obj_stream)), first_object_offset_(obj_stream->GetDict()->GetIntegerFor("First")) { DCHECK(IsObjectStream(obj_stream.Get())); Init(obj_stream.Get()); } CPDF_ObjectStream::~CPDF_ObjectStream() = default; RetainPtr CPDF_ObjectStream::ParseObject( CPDF_IndirectObjectHolder* pObjList, uint32_t obj_number, uint32_t archive_obj_index) const { if (archive_obj_index >= object_info_.size()) return nullptr; const auto& info = object_info_[archive_obj_index]; if (info.obj_num != obj_number) return nullptr; RetainPtr result = ParseObjectAtOffset(pObjList, info.obj_offset); if (result) result->SetObjNum(obj_number); return result; } void CPDF_ObjectStream::Init(const CPDF_Stream* stream) { stream_acc_->LoadAllDataFiltered(); data_stream_ = pdfium::MakeRetain(stream_acc_->GetSpan()); 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; object_info_.emplace_back(obj_num, obj_offset); } } RetainPtr 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); }