xref: /aosp_15_r20/external/pdfium/core/fpdfapi/parser/cpdf_object_stream.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2018 The PDFium Authors
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/fpdfapi/parser/fpdf_parser_utility.h"
17 #include "core/fxcrt/cfx_read_only_span_stream.h"
18 #include "core/fxcrt/fx_safe_types.h"
19 #include "third_party/base/check.h"
20 #include "third_party/base/memory/ptr_util.h"
21 
22 namespace {
23 
IsObjectStream(const CPDF_Object * object)24 bool IsObjectStream(const CPDF_Object* object) {
25   const CPDF_Stream* stream = ToStream(object);
26   if (!stream)
27     return false;
28 
29   // See ISO 32000-1:2008 spec, table 16.
30   RetainPtr<const CPDF_Dictionary> stream_dict = stream->GetDict();
31   if (!ValidateDictType(stream_dict.Get(), "ObjStm"))
32     return false;
33 
34   RetainPtr<const CPDF_Number> number_of_objects =
35       stream_dict->GetNumberFor("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   RetainPtr<const CPDF_Number> first_object_offset =
44       stream_dict->GetNumberFor("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 }  // namespace
54 
55 //  static
Create(RetainPtr<const CPDF_Stream> stream)56 std::unique_ptr<CPDF_ObjectStream> CPDF_ObjectStream::Create(
57     RetainPtr<const CPDF_Stream> stream) {
58   if (!IsObjectStream(stream.Get()))
59     return nullptr;
60 
61   // Protected constructor.
62   return pdfium::WrapUnique(new CPDF_ObjectStream(std::move(stream)));
63 }
64 
CPDF_ObjectStream(RetainPtr<const CPDF_Stream> obj_stream)65 CPDF_ObjectStream::CPDF_ObjectStream(RetainPtr<const CPDF_Stream> obj_stream)
66     : stream_acc_(pdfium::MakeRetain<CPDF_StreamAcc>(obj_stream)),
67       first_object_offset_(obj_stream->GetDict()->GetIntegerFor("First")) {
68   DCHECK(IsObjectStream(obj_stream.Get()));
69   Init(obj_stream.Get());
70 }
71 
72 CPDF_ObjectStream::~CPDF_ObjectStream() = default;
73 
ParseObject(CPDF_IndirectObjectHolder * pObjList,uint32_t obj_number,uint32_t archive_obj_index) const74 RetainPtr<CPDF_Object> CPDF_ObjectStream::ParseObject(
75     CPDF_IndirectObjectHolder* pObjList,
76     uint32_t obj_number,
77     uint32_t archive_obj_index) const {
78   if (archive_obj_index >= object_info_.size())
79     return nullptr;
80 
81   const auto& info = object_info_[archive_obj_index];
82   if (info.obj_num != obj_number)
83     return nullptr;
84 
85   RetainPtr<CPDF_Object> result =
86       ParseObjectAtOffset(pObjList, info.obj_offset);
87   if (result)
88     result->SetObjNum(obj_number);
89   return result;
90 }
91 
Init(const CPDF_Stream * stream)92 void CPDF_ObjectStream::Init(const CPDF_Stream* stream) {
93   stream_acc_->LoadAllDataFiltered();
94   data_stream_ =
95       pdfium::MakeRetain<CFX_ReadOnlySpanStream>(stream_acc_->GetSpan());
96 
97   CPDF_SyntaxParser syntax(data_stream_);
98   const int object_count = stream->GetDict()->GetIntegerFor("N");
99   for (int32_t i = object_count; i > 0; --i) {
100     if (syntax.GetPos() >= data_stream_->GetSize())
101       break;
102 
103     const uint32_t obj_num = syntax.GetDirectNum();
104     const uint32_t obj_offset = syntax.GetDirectNum();
105     if (!obj_num)
106       continue;
107 
108     object_info_.emplace_back(obj_num, obj_offset);
109   }
110 }
111 
ParseObjectAtOffset(CPDF_IndirectObjectHolder * pObjList,uint32_t object_offset) const112 RetainPtr<CPDF_Object> CPDF_ObjectStream::ParseObjectAtOffset(
113     CPDF_IndirectObjectHolder* pObjList,
114     uint32_t object_offset) const {
115   FX_SAFE_FILESIZE offset_in_stream = first_object_offset_;
116   offset_in_stream += object_offset;
117 
118   if (!offset_in_stream.IsValid())
119     return nullptr;
120 
121   if (offset_in_stream.ValueOrDie() >= data_stream_->GetSize())
122     return nullptr;
123 
124   CPDF_SyntaxParser syntax(data_stream_);
125   syntax.SetPos(offset_in_stream.ValueOrDie());
126   return syntax.GetObjectBody(pObjList);
127 }
128