Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cpdf_cross_ref_avail.cpp
Go to the documentation of this file.
1// Copyright 2017 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_cross_ref_avail.h"
6
7#include "core/fpdfapi/parser/cpdf_dictionary.h"
8#include "core/fpdfapi/parser/cpdf_read_validator.h"
9#include "core/fpdfapi/parser/cpdf_reference.h"
10#include "core/fpdfapi/parser/cpdf_syntax_parser.h"
11#include "core/fpdfapi/parser/fpdf_parser_utility.h"
12#include "third_party/base/check.h"
13#include "third_party/base/containers/contains.h"
14#include "third_party/base/numerics/safe_conversions.h"
15
16namespace {
17
18constexpr char kCrossRefKeyword[] = "xref";
19constexpr char kTrailerKeyword[] = "trailer";
20constexpr char kPrevCrossRefFieldKey[] = "Prev";
21constexpr char kTypeFieldKey[] = "Type";
22constexpr char kPrevCrossRefStreamOffsetFieldKey[] = "XRefStm";
23constexpr char kXRefKeyword[] = "XRef";
24constexpr char kEncryptKey[] = "Encrypt";
25
26} // namespace
27
29 FX_FILESIZE last_crossref_offset)
30 : parser_(parser), last_crossref_offset_(last_crossref_offset) {
31 DCHECK(parser_);
32 AddCrossRefForCheck(last_crossref_offset);
33}
34
36
38 if (status_ == CPDF_DataAvail::kDataAvailable)
39 return CPDF_DataAvail::kDataAvailable;
40
41 CPDF_ReadValidator::ScopedSession read_session(GetValidator());
42 while (true) {
43 bool check_result = false;
44 switch (state_) {
45 case State::kCrossRefCheck:
46 check_result = CheckCrossRef();
47 break;
48 case State::kCrossRefV4ItemCheck:
49 check_result = CheckCrossRefV4Item();
50 break;
51 case State::kCrossRefV4TrailerCheck:
52 check_result = CheckCrossRefV4Trailer();
53 break;
54 case State::kDone:
55 break;
56 }
57 if (!check_result)
58 break;
59
60 DCHECK(!GetValidator()->has_read_problems());
61 }
62 return status_;
63}
64
65bool CPDF_CrossRefAvail::CheckReadProblems() {
66 if (GetValidator()->read_error()) {
67 status_ = CPDF_DataAvail::kDataError;
68 return true;
69 }
70 return GetValidator()->has_unavailable_data();
71}
72
73bool CPDF_CrossRefAvail::CheckCrossRef() {
74 if (cross_refs_for_check_.empty()) {
75 // All cross refs were checked.
76 state_ = State::kDone;
77 status_ = CPDF_DataAvail::kDataAvailable;
78 return true;
79 }
80 parser_->SetPos(cross_refs_for_check_.front());
81
82 const ByteString first_word = parser_->PeekNextWord();
83 if (CheckReadProblems())
84 return false;
85
86 const bool result = (first_word == kCrossRefKeyword) ? CheckCrossRefV4()
87 : CheckCrossRefStream();
88
89 if (result)
90 cross_refs_for_check_.pop();
91
92 return result;
93}
94
95bool CPDF_CrossRefAvail::CheckCrossRefV4() {
96 const ByteString keyword = parser_->GetKeyword();
97 if (CheckReadProblems())
98 return false;
99
100 if (keyword != kCrossRefKeyword) {
101 status_ = CPDF_DataAvail::kDataError;
102 return false;
103 }
104
105 state_ = State::kCrossRefV4ItemCheck;
106 offset_ = parser_->GetPos();
107 return true;
108}
109
110bool CPDF_CrossRefAvail::CheckCrossRefV4Item() {
111 parser_->SetPos(offset_);
112 const ByteString keyword = parser_->GetKeyword();
113 if (CheckReadProblems())
114 return false;
115
116 if (keyword.IsEmpty()) {
117 status_ = CPDF_DataAvail::kDataError;
118 return false;
119 }
120
121 if (keyword == kTrailerKeyword)
122 state_ = State::kCrossRefV4TrailerCheck;
123
124 // Go to next item.
125 offset_ = parser_->GetPos();
126 return true;
127}
128
129bool CPDF_CrossRefAvail::CheckCrossRefV4Trailer() {
130 parser_->SetPos(offset_);
131
132 RetainPtr<CPDF_Dictionary> trailer =
133 ToDictionary(parser_->GetObjectBody(nullptr));
134 if (CheckReadProblems())
135 return false;
136
137 if (!trailer) {
138 status_ = CPDF_DataAvail::kDataError;
139 return false;
140 }
141
142 if (ToReference(trailer->GetObjectFor(kEncryptKey))) {
143 status_ = CPDF_DataAvail::kDataError;
144 return false;
145 }
146
147 const int32_t xrefpos = trailer->GetDirectIntegerFor(kPrevCrossRefFieldKey);
148 if (xrefpos > 0 &&
149 pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(xrefpos))
150 AddCrossRefForCheck(static_cast<FX_FILESIZE>(xrefpos));
151
152 const int32_t stream_xref_offset =
153 trailer->GetDirectIntegerFor(kPrevCrossRefStreamOffsetFieldKey);
154 if (stream_xref_offset > 0 &&
155 pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(
156 stream_xref_offset))
157 AddCrossRefForCheck(static_cast<FX_FILESIZE>(stream_xref_offset));
158
159 // Goto check next crossref
160 state_ = State::kCrossRefCheck;
161 return true;
162}
163
164bool CPDF_CrossRefAvail::CheckCrossRefStream() {
165 auto cross_ref =
166 parser_->GetIndirectObject(nullptr, CPDF_SyntaxParser::ParseType::kLoose);
167 if (CheckReadProblems())
168 return false;
169
170 RetainPtr<const CPDF_Dictionary> trailer =
171 cross_ref && cross_ref->IsStream() ? cross_ref->GetDict() : nullptr;
172 if (!trailer) {
173 status_ = CPDF_DataAvail::kDataError;
174 return false;
175 }
176
177 if (ToReference(trailer->GetObjectFor(kEncryptKey))) {
178 status_ = CPDF_DataAvail::kDataError;
179 return false;
180 }
181
182 if (trailer->GetNameFor(kTypeFieldKey) == kXRefKeyword) {
183 const int32_t xrefpos = trailer->GetIntegerFor(kPrevCrossRefFieldKey);
184 if (xrefpos > 0 &&
185 pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(xrefpos)) {
186 AddCrossRefForCheck(static_cast<FX_FILESIZE>(xrefpos));
187 }
188 }
189 // Goto check next crossref
190 state_ = State::kCrossRefCheck;
191 return true;
192}
193
194void CPDF_CrossRefAvail::AddCrossRefForCheck(FX_FILESIZE crossref_offset) {
195 if (pdfium::Contains(registered_crossrefs_, crossref_offset))
196 return;
197
198 cross_refs_for_check_.push(crossref_offset);
199 registered_crossrefs_.insert(crossref_offset);
200}
201
203 return parser_->GetValidator();
204}
CPDF_CrossRefAvail(CPDF_SyntaxParser *parser, FX_FILESIZE last_crossref_offset)
CPDF_DataAvail::DocAvailStatus CheckAvail()
bool operator==(const char *ptr) const
bool IsEmpty() const
Definition bytestring.h:119
bool operator!=(const char *ptr) const
Definition bytestring.h:130
#define FX_FILESIZE
Definition fx_types.h:19