1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "public/fpdf_dataavail.h"
8
9#include <memory>
10#include <utility>
11
12#include "core/fpdfapi/parser/cpdf_data_avail.h"
13#include "core/fpdfapi/parser/cpdf_document.h"
14#include "core/fxcrt/fx_stream.h"
15#include "core/fxcrt/retain_ptr.h"
16#include "fpdfsdk/fsdk_define.h"
17#include "public/fpdf_formfill.h"
18#include "third_party/base/ptr_util.h"
19
20// These checks are here because core/ and public/ cannot depend on each other.
21static_assert(CPDF_DataAvail::DataError == PDF_DATA_ERROR,
22              "CPDF_DataAvail::DataError value mismatch");
23static_assert(CPDF_DataAvail::DataNotAvailable == PDF_DATA_NOTAVAIL,
24              "CPDF_DataAvail::DataNotAvailable value mismatch");
25static_assert(CPDF_DataAvail::DataAvailable == PDF_DATA_AVAIL,
26              "CPDF_DataAvail::DataAvailable value mismatch");
27
28static_assert(CPDF_DataAvail::LinearizationUnknown == PDF_LINEARIZATION_UNKNOWN,
29              "CPDF_DataAvail::LinearizationUnknown value mismatch");
30static_assert(CPDF_DataAvail::NotLinearized == PDF_NOT_LINEARIZED,
31              "CPDF_DataAvail::NotLinearized value mismatch");
32static_assert(CPDF_DataAvail::Linearized == PDF_LINEARIZED,
33              "CPDF_DataAvail::Linearized value mismatch");
34
35static_assert(CPDF_DataAvail::FormError == PDF_FORM_ERROR,
36              "CPDF_DataAvail::FormError value mismatch");
37static_assert(CPDF_DataAvail::FormNotAvailable == PDF_FORM_NOTAVAIL,
38              "CPDF_DataAvail::FormNotAvailable value mismatch");
39static_assert(CPDF_DataAvail::FormAvailable == PDF_FORM_AVAIL,
40              "CPDF_DataAvail::FormAvailable value mismatch");
41static_assert(CPDF_DataAvail::FormNotExist == PDF_FORM_NOTEXIST,
42              "CPDF_DataAvail::FormNotExist value mismatch");
43
44namespace {
45
46class FPDF_FileAvailContext : public CPDF_DataAvail::FileAvail {
47 public:
48  FPDF_FileAvailContext() : m_pfileAvail(nullptr) {}
49  ~FPDF_FileAvailContext() override {}
50
51  void Set(FX_FILEAVAIL* pfileAvail) { m_pfileAvail = pfileAvail; }
52
53  // CPDF_DataAvail::FileAvail:
54  bool IsDataAvail(FX_FILESIZE offset, size_t size) override {
55    return !!m_pfileAvail->IsDataAvail(m_pfileAvail, offset, size);
56  }
57
58 private:
59  FX_FILEAVAIL* m_pfileAvail;
60};
61
62class FPDF_FileAccessContext : public IFX_SeekableReadStream {
63 public:
64  template <typename T, typename... Args>
65  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
66
67  ~FPDF_FileAccessContext() override {}
68
69  void Set(FPDF_FILEACCESS* pFile) { m_pFileAccess = pFile; }
70
71  // IFX_SeekableReadStream
72  FX_FILESIZE GetSize() override { return m_pFileAccess->m_FileLen; }
73
74  bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override {
75    return !!m_pFileAccess->m_GetBlock(m_pFileAccess->m_Param, offset,
76                                       (uint8_t*)buffer, size);
77  }
78
79 private:
80  FPDF_FileAccessContext() : m_pFileAccess(nullptr) {}
81
82  FPDF_FILEACCESS* m_pFileAccess;
83};
84
85class FPDF_DownloadHintsContext : public CPDF_DataAvail::DownloadHints {
86 public:
87  explicit FPDF_DownloadHintsContext(FX_DOWNLOADHINTS* pDownloadHints) {
88    m_pDownloadHints = pDownloadHints;
89  }
90  ~FPDF_DownloadHintsContext() override {}
91
92 public:
93  // IFX_DownloadHints
94  void AddSegment(FX_FILESIZE offset, size_t size) override {
95    if (m_pDownloadHints)
96      m_pDownloadHints->AddSegment(m_pDownloadHints, offset, size);
97  }
98
99 private:
100  FX_DOWNLOADHINTS* m_pDownloadHints;
101};
102
103class FPDF_AvailContext {
104 public:
105  FPDF_AvailContext()
106      : m_FileAvail(pdfium::MakeUnique<FPDF_FileAvailContext>()),
107        m_FileRead(pdfium::MakeRetain<FPDF_FileAccessContext>()) {}
108  ~FPDF_AvailContext() {}
109
110  std::unique_ptr<FPDF_FileAvailContext> m_FileAvail;
111  RetainPtr<FPDF_FileAccessContext> m_FileRead;
112  std::unique_ptr<CPDF_DataAvail> m_pDataAvail;
113};
114
115FPDF_AvailContext* FPDFAvailContextFromFPDFAvail(FPDF_AVAIL avail) {
116  return static_cast<FPDF_AvailContext*>(avail);
117}
118
119}  // namespace
120
121FPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL* file_avail,
122                                                      FPDF_FILEACCESS* file) {
123  auto pAvail = pdfium::MakeUnique<FPDF_AvailContext>();
124  pAvail->m_FileAvail->Set(file_avail);
125  pAvail->m_FileRead->Set(file);
126  pAvail->m_pDataAvail = pdfium::MakeUnique<CPDF_DataAvail>(
127      pAvail->m_FileAvail.get(), pAvail->m_FileRead, true);
128  return pAvail.release();  // Caller takes ownership.
129}
130
131FPDF_EXPORT void FPDF_CALLCONV FPDFAvail_Destroy(FPDF_AVAIL avail) {
132  // Take ownership back from caller and destroy.
133  std::unique_ptr<FPDF_AvailContext>(FPDFAvailContextFromFPDFAvail(avail));
134}
135
136FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsDocAvail(FPDF_AVAIL avail,
137                                                   FX_DOWNLOADHINTS* hints) {
138  if (!avail)
139    return PDF_DATA_ERROR;
140  FPDF_DownloadHintsContext hints_context(hints);
141  return FPDFAvailContextFromFPDFAvail(avail)->m_pDataAvail->IsDocAvail(
142      &hints_context);
143}
144
145FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
146FPDFAvail_GetDocument(FPDF_AVAIL avail, FPDF_BYTESTRING password) {
147  auto* pDataAvail = FPDFAvailContextFromFPDFAvail(avail);
148  if (!pDataAvail)
149    return nullptr;
150  CPDF_Parser::Error error;
151  std::unique_ptr<CPDF_Document> document;
152  std::tie(error, document) = pDataAvail->m_pDataAvail->ParseDocument(password);
153  if (error != CPDF_Parser::SUCCESS) {
154    ProcessParseError(error);
155    return nullptr;
156  }
157  CheckUnSupportError(document.get(), FPDF_ERR_SUCCESS);
158  return FPDFDocumentFromCPDFDocument(document.release());
159}
160
161FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc) {
162  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(doc);
163  return pDoc ? pDoc->GetParser()->GetFirstPageNo() : 0;
164}
165
166FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsPageAvail(FPDF_AVAIL avail,
167                                                    int page_index,
168                                                    FX_DOWNLOADHINTS* hints) {
169  if (!avail)
170    return PDF_DATA_ERROR;
171  if (page_index < 0)
172    return PDF_DATA_NOTAVAIL;
173  FPDF_DownloadHintsContext hints_context(hints);
174  return FPDFAvailContextFromFPDFAvail(avail)->m_pDataAvail->IsPageAvail(
175      page_index, &hints_context);
176}
177
178FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsFormAvail(FPDF_AVAIL avail,
179                                                    FX_DOWNLOADHINTS* hints) {
180  if (!avail)
181    return PDF_FORM_ERROR;
182  FPDF_DownloadHintsContext hints_context(hints);
183  return FPDFAvailContextFromFPDFAvail(avail)->m_pDataAvail->IsFormAvail(
184      &hints_context);
185}
186
187FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsLinearized(FPDF_AVAIL avail) {
188  if (!avail)
189    return PDF_LINEARIZATION_UNKNOWN;
190  return FPDFAvailContextFromFPDFAvail(avail)->m_pDataAvail->IsLinearizedPDF();
191}
192