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/check.h"
19 #include "core/fxcrt/fx_safe_types.h"
20 #include "core/fxcrt/ptr_util.h"
21
22 namespace {
23
IsObjectStream(const CPDF_Stream * stream)24 bool IsObjectStream(const CPDF_Stream* stream) {
25 if (!stream)
26 return false;
27
28 // See ISO 32000-1:2008 spec, table 16.
29 RetainPtr<const CPDF_Dictionary> stream_dict = stream->GetDict();
30 if (!ValidateDictType(stream_dict.Get(), "ObjStm"))
31 return false;
32
33 RetainPtr<const CPDF_Number> number_of_objects =
34 stream_dict->GetNumberFor("N");
35 if (!number_of_objects || !number_of_objects->IsInteger() ||
36 number_of_objects->GetInteger() < 0 ||
37 number_of_objects->GetInteger() >=
38 static_cast<int>(CPDF_Parser::kMaxObjectNumber)) {
39 return false;
40 }
41
42 RetainPtr<const CPDF_Number> first_object_offset =
43 stream_dict->GetNumberFor("First");
44 if (!first_object_offset || !first_object_offset->IsInteger() ||
45 first_object_offset->GetInteger() < 0) {
46 return false;
47 }
48
49 return true;
50 }
51
52 } // namespace
53
54 // static
Create(RetainPtr<const CPDF_Stream> stream)55 std::unique_ptr<CPDF_ObjectStream> CPDF_ObjectStream::Create(
56 RetainPtr<const CPDF_Stream> stream) {
57 if (!IsObjectStream(stream.Get()))
58 return nullptr;
59
60 // Protected constructor.
61 return pdfium::WrapUnique(new CPDF_ObjectStream(std::move(stream)));
62 }
63
CPDF_ObjectStream(RetainPtr<const CPDF_Stream> obj_stream)64 CPDF_ObjectStream::CPDF_ObjectStream(RetainPtr<const CPDF_Stream> obj_stream)
65 : stream_acc_(pdfium::MakeRetain<CPDF_StreamAcc>(obj_stream)),
66 first_object_offset_(obj_stream->GetDict()->GetIntegerFor("First")) {
67 DCHECK(IsObjectStream(obj_stream.Get()));
68 Init(obj_stream.Get());
69 }
70
71 CPDF_ObjectStream::~CPDF_ObjectStream() = default;
72
ParseObject(CPDF_IndirectObjectHolder * pObjList,uint32_t obj_number,uint32_t archive_obj_index) const73 RetainPtr<CPDF_Object> CPDF_ObjectStream::ParseObject(
74 CPDF_IndirectObjectHolder* pObjList,
75 uint32_t obj_number,
76 uint32_t archive_obj_index) const {
77 if (archive_obj_index >= object_info_.size())
78 return nullptr;
79
80 const auto& info = object_info_[archive_obj_index];
81 if (info.obj_num != obj_number)
82 return nullptr;
83
84 RetainPtr<CPDF_Object> result =
85 ParseObjectAtOffset(pObjList, info.obj_offset);
86 if (result)
87 result->SetObjNum(obj_number);
88 return result;
89 }
90
Init(const CPDF_Stream * stream)91 void CPDF_ObjectStream::Init(const CPDF_Stream* stream) {
92 stream_acc_->LoadAllDataFiltered();
93 data_stream_ =
94 pdfium::MakeRetain<CFX_ReadOnlySpanStream>(stream_acc_->GetSpan());
95
96 CPDF_SyntaxParser syntax(data_stream_);
97 const int object_count = stream->GetDict()->GetIntegerFor("N");
98 for (int32_t i = object_count; i > 0; --i) {
99 if (syntax.GetPos() >= data_stream_->GetSize())
100 break;
101
102 const uint32_t obj_num = syntax.GetDirectNum();
103 const uint32_t obj_offset = syntax.GetDirectNum();
104 if (!obj_num)
105 continue;
106
107 object_info_.emplace_back(obj_num, obj_offset);
108 }
109 }
110
ParseObjectAtOffset(CPDF_IndirectObjectHolder * pObjList,uint32_t object_offset) const111 RetainPtr<CPDF_Object> CPDF_ObjectStream::ParseObjectAtOffset(
112 CPDF_IndirectObjectHolder* pObjList,
113 uint32_t object_offset) const {
114 FX_SAFE_FILESIZE offset_in_stream = first_object_offset_;
115 offset_in_stream += object_offset;
116
117 if (!offset_in_stream.IsValid())
118 return nullptr;
119
120 if (offset_in_stream.ValueOrDie() >= data_stream_->GetSize())
121 return nullptr;
122
123 CPDF_SyntaxParser syntax(data_stream_);
124 syntax.SetPos(offset_in_stream.ValueOrDie());
125 return syntax.GetObjectBody(pObjList);
126 }
127