1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2014 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker
5*3ac0a46fSAndroid Build Coastguard Worker // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6*3ac0a46fSAndroid Build Coastguard Worker
7*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_dataavail.h"
8*3ac0a46fSAndroid Build Coastguard Worker
9*3ac0a46fSAndroid Build Coastguard Worker #include <memory>
10*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
11*3ac0a46fSAndroid Build Coastguard Worker
12*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_docpagedata.h"
13*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_data_avail.h"
14*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_document.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/render/cpdf_docrenderdata.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_safe_types.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_stream.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/retain_ptr.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/unowned_ptr.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/unowned_ptr_exclusion.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "fpdfsdk/cpdfsdk_helpers.h"
22*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_formfill.h"
23*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/numerics/safe_conversions.h"
24*3ac0a46fSAndroid Build Coastguard Worker
25*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_XFA
26*3ac0a46fSAndroid Build Coastguard Worker #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
27*3ac0a46fSAndroid Build Coastguard Worker #endif // PDF_ENABLE_XFA
28*3ac0a46fSAndroid Build Coastguard Worker
29*3ac0a46fSAndroid Build Coastguard Worker // These checks are here because core/ and public/ cannot depend on each other.
30*3ac0a46fSAndroid Build Coastguard Worker static_assert(CPDF_DataAvail::kDataError == PDF_DATA_ERROR,
31*3ac0a46fSAndroid Build Coastguard Worker "CPDF_DataAvail::kDataError value mismatch");
32*3ac0a46fSAndroid Build Coastguard Worker static_assert(CPDF_DataAvail::kDataNotAvailable == PDF_DATA_NOTAVAIL,
33*3ac0a46fSAndroid Build Coastguard Worker "CPDF_DataAvail::kDataNotAvailable value mismatch");
34*3ac0a46fSAndroid Build Coastguard Worker static_assert(CPDF_DataAvail::kDataAvailable == PDF_DATA_AVAIL,
35*3ac0a46fSAndroid Build Coastguard Worker "CPDF_DataAvail::kDataAvailable value mismatch");
36*3ac0a46fSAndroid Build Coastguard Worker
37*3ac0a46fSAndroid Build Coastguard Worker static_assert(CPDF_DataAvail::kLinearizationUnknown ==
38*3ac0a46fSAndroid Build Coastguard Worker PDF_LINEARIZATION_UNKNOWN,
39*3ac0a46fSAndroid Build Coastguard Worker "CPDF_DataAvail::kLinearizationUnknown value mismatch");
40*3ac0a46fSAndroid Build Coastguard Worker static_assert(CPDF_DataAvail::kNotLinearized == PDF_NOT_LINEARIZED,
41*3ac0a46fSAndroid Build Coastguard Worker "CPDF_DataAvail::kNotLinearized value mismatch");
42*3ac0a46fSAndroid Build Coastguard Worker static_assert(CPDF_DataAvail::kLinearized == PDF_LINEARIZED,
43*3ac0a46fSAndroid Build Coastguard Worker "CPDF_DataAvail::kLinearized value mismatch");
44*3ac0a46fSAndroid Build Coastguard Worker
45*3ac0a46fSAndroid Build Coastguard Worker static_assert(CPDF_DataAvail::kFormError == PDF_FORM_ERROR,
46*3ac0a46fSAndroid Build Coastguard Worker "CPDF_DataAvail::kFormError value mismatch");
47*3ac0a46fSAndroid Build Coastguard Worker static_assert(CPDF_DataAvail::kFormNotAvailable == PDF_FORM_NOTAVAIL,
48*3ac0a46fSAndroid Build Coastguard Worker "CPDF_DataAvail::kFormNotAvailable value mismatch");
49*3ac0a46fSAndroid Build Coastguard Worker static_assert(CPDF_DataAvail::kFormAvailable == PDF_FORM_AVAIL,
50*3ac0a46fSAndroid Build Coastguard Worker "CPDF_DataAvail::kFormAvailable value mismatch");
51*3ac0a46fSAndroid Build Coastguard Worker static_assert(CPDF_DataAvail::kFormNotExist == PDF_FORM_NOTEXIST,
52*3ac0a46fSAndroid Build Coastguard Worker "CPDF_DataAvail::kFormNotExist value mismatch");
53*3ac0a46fSAndroid Build Coastguard Worker
54*3ac0a46fSAndroid Build Coastguard Worker namespace {
55*3ac0a46fSAndroid Build Coastguard Worker
56*3ac0a46fSAndroid Build Coastguard Worker class FPDF_FileAvailContext final : public CPDF_DataAvail::FileAvail {
57*3ac0a46fSAndroid Build Coastguard Worker public:
FPDF_FileAvailContext(FX_FILEAVAIL * avail)58*3ac0a46fSAndroid Build Coastguard Worker explicit FPDF_FileAvailContext(FX_FILEAVAIL* avail) : avail_(avail) {}
59*3ac0a46fSAndroid Build Coastguard Worker ~FPDF_FileAvailContext() override = default;
60*3ac0a46fSAndroid Build Coastguard Worker
61*3ac0a46fSAndroid Build Coastguard Worker // CPDF_DataAvail::FileAvail:
IsDataAvail(FX_FILESIZE offset,size_t size)62*3ac0a46fSAndroid Build Coastguard Worker bool IsDataAvail(FX_FILESIZE offset, size_t size) override {
63*3ac0a46fSAndroid Build Coastguard Worker return !!avail_->IsDataAvail(
64*3ac0a46fSAndroid Build Coastguard Worker avail_, pdfium::base::checked_cast<size_t>(offset), size);
65*3ac0a46fSAndroid Build Coastguard Worker }
66*3ac0a46fSAndroid Build Coastguard Worker
67*3ac0a46fSAndroid Build Coastguard Worker private:
68*3ac0a46fSAndroid Build Coastguard Worker // TODO(tsepez): fix murky ownership in tests.
69*3ac0a46fSAndroid Build Coastguard Worker UNOWNED_PTR_EXCLUSION FX_FILEAVAIL* const avail_;
70*3ac0a46fSAndroid Build Coastguard Worker };
71*3ac0a46fSAndroid Build Coastguard Worker
72*3ac0a46fSAndroid Build Coastguard Worker class FPDF_FileAccessContext final : public IFX_SeekableReadStream {
73*3ac0a46fSAndroid Build Coastguard Worker public:
74*3ac0a46fSAndroid Build Coastguard Worker CONSTRUCT_VIA_MAKE_RETAIN;
75*3ac0a46fSAndroid Build Coastguard Worker
76*3ac0a46fSAndroid Build Coastguard Worker // IFX_SeekableReadStream:
GetSize()77*3ac0a46fSAndroid Build Coastguard Worker FX_FILESIZE GetSize() override { return file_->m_FileLen; }
78*3ac0a46fSAndroid Build Coastguard Worker
ReadBlockAtOffset(pdfium::span<uint8_t> buffer,FX_FILESIZE offset)79*3ac0a46fSAndroid Build Coastguard Worker bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
80*3ac0a46fSAndroid Build Coastguard Worker FX_FILESIZE offset) override {
81*3ac0a46fSAndroid Build Coastguard Worker if (buffer.empty() || offset < 0)
82*3ac0a46fSAndroid Build Coastguard Worker return false;
83*3ac0a46fSAndroid Build Coastguard Worker
84*3ac0a46fSAndroid Build Coastguard Worker if (!pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(buffer.size()))
85*3ac0a46fSAndroid Build Coastguard Worker return false;
86*3ac0a46fSAndroid Build Coastguard Worker
87*3ac0a46fSAndroid Build Coastguard Worker FX_SAFE_FILESIZE new_pos = buffer.size();
88*3ac0a46fSAndroid Build Coastguard Worker new_pos += offset;
89*3ac0a46fSAndroid Build Coastguard Worker return new_pos.IsValid() && new_pos.ValueOrDie() <= GetSize() &&
90*3ac0a46fSAndroid Build Coastguard Worker file_->m_GetBlock(
91*3ac0a46fSAndroid Build Coastguard Worker file_->m_Param,
92*3ac0a46fSAndroid Build Coastguard Worker pdfium::base::checked_cast<unsigned long>(offset), buffer.data(),
93*3ac0a46fSAndroid Build Coastguard Worker pdfium::base::checked_cast<unsigned long>(buffer.size()));
94*3ac0a46fSAndroid Build Coastguard Worker }
95*3ac0a46fSAndroid Build Coastguard Worker
96*3ac0a46fSAndroid Build Coastguard Worker private:
FPDF_FileAccessContext(FPDF_FILEACCESS * file)97*3ac0a46fSAndroid Build Coastguard Worker explicit FPDF_FileAccessContext(FPDF_FILEACCESS* file) : file_(file) {}
98*3ac0a46fSAndroid Build Coastguard Worker ~FPDF_FileAccessContext() override = default;
99*3ac0a46fSAndroid Build Coastguard Worker
100*3ac0a46fSAndroid Build Coastguard Worker // TODO(tsepez): fix murky ownership in tests.
101*3ac0a46fSAndroid Build Coastguard Worker UNOWNED_PTR_EXCLUSION FPDF_FILEACCESS* const file_;
102*3ac0a46fSAndroid Build Coastguard Worker };
103*3ac0a46fSAndroid Build Coastguard Worker
104*3ac0a46fSAndroid Build Coastguard Worker class FPDF_DownloadHintsContext final : public CPDF_DataAvail::DownloadHints {
105*3ac0a46fSAndroid Build Coastguard Worker public:
FPDF_DownloadHintsContext(FX_DOWNLOADHINTS * pDownloadHints)106*3ac0a46fSAndroid Build Coastguard Worker explicit FPDF_DownloadHintsContext(FX_DOWNLOADHINTS* pDownloadHints)
107*3ac0a46fSAndroid Build Coastguard Worker : m_pDownloadHints(pDownloadHints) {}
108*3ac0a46fSAndroid Build Coastguard Worker ~FPDF_DownloadHintsContext() override = default;
109*3ac0a46fSAndroid Build Coastguard Worker
110*3ac0a46fSAndroid Build Coastguard Worker // IFX_DownloadHints
AddSegment(FX_FILESIZE offset,size_t size)111*3ac0a46fSAndroid Build Coastguard Worker void AddSegment(FX_FILESIZE offset, size_t size) override {
112*3ac0a46fSAndroid Build Coastguard Worker if (m_pDownloadHints) {
113*3ac0a46fSAndroid Build Coastguard Worker m_pDownloadHints->AddSegment(m_pDownloadHints,
114*3ac0a46fSAndroid Build Coastguard Worker static_cast<size_t>(offset), size);
115*3ac0a46fSAndroid Build Coastguard Worker }
116*3ac0a46fSAndroid Build Coastguard Worker }
117*3ac0a46fSAndroid Build Coastguard Worker
118*3ac0a46fSAndroid Build Coastguard Worker private:
119*3ac0a46fSAndroid Build Coastguard Worker UnownedPtr<FX_DOWNLOADHINTS> m_pDownloadHints;
120*3ac0a46fSAndroid Build Coastguard Worker };
121*3ac0a46fSAndroid Build Coastguard Worker
122*3ac0a46fSAndroid Build Coastguard Worker class FPDF_AvailContext {
123*3ac0a46fSAndroid Build Coastguard Worker public:
FPDF_AvailContext(FX_FILEAVAIL * file_avail,FPDF_FILEACCESS * file)124*3ac0a46fSAndroid Build Coastguard Worker FPDF_AvailContext(FX_FILEAVAIL* file_avail, FPDF_FILEACCESS* file)
125*3ac0a46fSAndroid Build Coastguard Worker : file_avail_(std::make_unique<FPDF_FileAvailContext>(file_avail)),
126*3ac0a46fSAndroid Build Coastguard Worker file_read_(pdfium::MakeRetain<FPDF_FileAccessContext>(file)),
127*3ac0a46fSAndroid Build Coastguard Worker data_avail_(
128*3ac0a46fSAndroid Build Coastguard Worker std::make_unique<CPDF_DataAvail>(file_avail_.get(), file_read_)) {}
129*3ac0a46fSAndroid Build Coastguard Worker ~FPDF_AvailContext() = default;
130*3ac0a46fSAndroid Build Coastguard Worker
data_avail()131*3ac0a46fSAndroid Build Coastguard Worker CPDF_DataAvail* data_avail() { return data_avail_.get(); }
132*3ac0a46fSAndroid Build Coastguard Worker
133*3ac0a46fSAndroid Build Coastguard Worker private:
134*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<FPDF_FileAvailContext> const file_avail_;
135*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<FPDF_FileAccessContext> const file_read_;
136*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<CPDF_DataAvail> const data_avail_;
137*3ac0a46fSAndroid Build Coastguard Worker };
138*3ac0a46fSAndroid Build Coastguard Worker
FPDFAvailContextFromFPDFAvail(FPDF_AVAIL avail)139*3ac0a46fSAndroid Build Coastguard Worker FPDF_AvailContext* FPDFAvailContextFromFPDFAvail(FPDF_AVAIL avail) {
140*3ac0a46fSAndroid Build Coastguard Worker return reinterpret_cast<FPDF_AvailContext*>(avail);
141*3ac0a46fSAndroid Build Coastguard Worker }
142*3ac0a46fSAndroid Build Coastguard Worker
FPDFAvailFromFPDFAvailContext(FPDF_AvailContext * pAvailContext)143*3ac0a46fSAndroid Build Coastguard Worker FPDF_AVAIL FPDFAvailFromFPDFAvailContext(FPDF_AvailContext* pAvailContext) {
144*3ac0a46fSAndroid Build Coastguard Worker return reinterpret_cast<FPDF_AVAIL>(pAvailContext);
145*3ac0a46fSAndroid Build Coastguard Worker }
146*3ac0a46fSAndroid Build Coastguard Worker
147*3ac0a46fSAndroid Build Coastguard Worker } // namespace
148*3ac0a46fSAndroid Build Coastguard Worker
FPDFAvail_Create(FX_FILEAVAIL * file_avail,FPDF_FILEACCESS * file)149*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL* file_avail,
150*3ac0a46fSAndroid Build Coastguard Worker FPDF_FILEACCESS* file) {
151*3ac0a46fSAndroid Build Coastguard Worker auto pAvail = std::make_unique<FPDF_AvailContext>(file_avail, file);
152*3ac0a46fSAndroid Build Coastguard Worker
153*3ac0a46fSAndroid Build Coastguard Worker // Caller takes ownership.
154*3ac0a46fSAndroid Build Coastguard Worker return FPDFAvailFromFPDFAvailContext(pAvail.release());
155*3ac0a46fSAndroid Build Coastguard Worker }
156*3ac0a46fSAndroid Build Coastguard Worker
FPDFAvail_Destroy(FPDF_AVAIL avail)157*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT void FPDF_CALLCONV FPDFAvail_Destroy(FPDF_AVAIL avail) {
158*3ac0a46fSAndroid Build Coastguard Worker // Take ownership back from caller and destroy.
159*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<FPDF_AvailContext>(FPDFAvailContextFromFPDFAvail(avail));
160*3ac0a46fSAndroid Build Coastguard Worker }
161*3ac0a46fSAndroid Build Coastguard Worker
FPDFAvail_IsDocAvail(FPDF_AVAIL avail,FX_DOWNLOADHINTS * hints)162*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsDocAvail(FPDF_AVAIL avail,
163*3ac0a46fSAndroid Build Coastguard Worker FX_DOWNLOADHINTS* hints) {
164*3ac0a46fSAndroid Build Coastguard Worker auto* avail_context = FPDFAvailContextFromFPDFAvail(avail);
165*3ac0a46fSAndroid Build Coastguard Worker if (!avail_context)
166*3ac0a46fSAndroid Build Coastguard Worker return PDF_DATA_ERROR;
167*3ac0a46fSAndroid Build Coastguard Worker FPDF_DownloadHintsContext hints_context(hints);
168*3ac0a46fSAndroid Build Coastguard Worker return avail_context->data_avail()->IsDocAvail(&hints_context);
169*3ac0a46fSAndroid Build Coastguard Worker }
170*3ac0a46fSAndroid Build Coastguard Worker
171*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
FPDFAvail_GetDocument(FPDF_AVAIL avail,FPDF_BYTESTRING password)172*3ac0a46fSAndroid Build Coastguard Worker FPDFAvail_GetDocument(FPDF_AVAIL avail, FPDF_BYTESTRING password) {
173*3ac0a46fSAndroid Build Coastguard Worker auto* avail_context = FPDFAvailContextFromFPDFAvail(avail);
174*3ac0a46fSAndroid Build Coastguard Worker if (!avail_context)
175*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
176*3ac0a46fSAndroid Build Coastguard Worker CPDF_Parser::Error error;
177*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<CPDF_Document> document;
178*3ac0a46fSAndroid Build Coastguard Worker std::tie(error, document) = avail_context->data_avail()->ParseDocument(
179*3ac0a46fSAndroid Build Coastguard Worker std::make_unique<CPDF_DocRenderData>(),
180*3ac0a46fSAndroid Build Coastguard Worker std::make_unique<CPDF_DocPageData>(), password);
181*3ac0a46fSAndroid Build Coastguard Worker if (error != CPDF_Parser::SUCCESS) {
182*3ac0a46fSAndroid Build Coastguard Worker ProcessParseError(error);
183*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
184*3ac0a46fSAndroid Build Coastguard Worker }
185*3ac0a46fSAndroid Build Coastguard Worker
186*3ac0a46fSAndroid Build Coastguard Worker ReportUnsupportedFeatures(document.get());
187*3ac0a46fSAndroid Build Coastguard Worker return FPDFDocumentFromCPDFDocument(document.release());
188*3ac0a46fSAndroid Build Coastguard Worker }
189*3ac0a46fSAndroid Build Coastguard Worker
FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc)190*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc) {
191*3ac0a46fSAndroid Build Coastguard Worker CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(doc);
192*3ac0a46fSAndroid Build Coastguard Worker return pDoc ? pDoc->GetParser()->GetFirstPageNo() : 0;
193*3ac0a46fSAndroid Build Coastguard Worker }
194*3ac0a46fSAndroid Build Coastguard Worker
FPDFAvail_IsPageAvail(FPDF_AVAIL avail,int page_index,FX_DOWNLOADHINTS * hints)195*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsPageAvail(FPDF_AVAIL avail,
196*3ac0a46fSAndroid Build Coastguard Worker int page_index,
197*3ac0a46fSAndroid Build Coastguard Worker FX_DOWNLOADHINTS* hints) {
198*3ac0a46fSAndroid Build Coastguard Worker auto* avail_context = FPDFAvailContextFromFPDFAvail(avail);
199*3ac0a46fSAndroid Build Coastguard Worker if (!avail_context)
200*3ac0a46fSAndroid Build Coastguard Worker return PDF_DATA_ERROR;
201*3ac0a46fSAndroid Build Coastguard Worker if (page_index < 0)
202*3ac0a46fSAndroid Build Coastguard Worker return PDF_DATA_NOTAVAIL;
203*3ac0a46fSAndroid Build Coastguard Worker FPDF_DownloadHintsContext hints_context(hints);
204*3ac0a46fSAndroid Build Coastguard Worker return avail_context->data_avail()->IsPageAvail(page_index, &hints_context);
205*3ac0a46fSAndroid Build Coastguard Worker }
206*3ac0a46fSAndroid Build Coastguard Worker
FPDFAvail_IsFormAvail(FPDF_AVAIL avail,FX_DOWNLOADHINTS * hints)207*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsFormAvail(FPDF_AVAIL avail,
208*3ac0a46fSAndroid Build Coastguard Worker FX_DOWNLOADHINTS* hints) {
209*3ac0a46fSAndroid Build Coastguard Worker auto* avail_context = FPDFAvailContextFromFPDFAvail(avail);
210*3ac0a46fSAndroid Build Coastguard Worker if (!avail_context)
211*3ac0a46fSAndroid Build Coastguard Worker return PDF_FORM_ERROR;
212*3ac0a46fSAndroid Build Coastguard Worker FPDF_DownloadHintsContext hints_context(hints);
213*3ac0a46fSAndroid Build Coastguard Worker return avail_context->data_avail()->IsFormAvail(&hints_context);
214*3ac0a46fSAndroid Build Coastguard Worker }
215*3ac0a46fSAndroid Build Coastguard Worker
FPDFAvail_IsLinearized(FPDF_AVAIL avail)216*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsLinearized(FPDF_AVAIL avail) {
217*3ac0a46fSAndroid Build Coastguard Worker auto* avail_context = FPDFAvailContextFromFPDFAvail(avail);
218*3ac0a46fSAndroid Build Coastguard Worker if (!avail_context)
219*3ac0a46fSAndroid Build Coastguard Worker return PDF_LINEARIZATION_UNKNOWN;
220*3ac0a46fSAndroid Build Coastguard Worker return avail_context->data_avail()->IsLinearizedPDF();
221*3ac0a46fSAndroid Build Coastguard Worker }
222