• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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