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. 21 static_assert(CPDF_DataAvail::DataError == PDF_DATA_ERROR, 22 "CPDF_DataAvail::DataError value mismatch"); 23 static_assert(CPDF_DataAvail::DataNotAvailable == PDF_DATA_NOTAVAIL, 24 "CPDF_DataAvail::DataNotAvailable value mismatch"); 25 static_assert(CPDF_DataAvail::DataAvailable == PDF_DATA_AVAIL, 26 "CPDF_DataAvail::DataAvailable value mismatch"); 27 28 static_assert(CPDF_DataAvail::LinearizationUnknown == PDF_LINEARIZATION_UNKNOWN, 29 "CPDF_DataAvail::LinearizationUnknown value mismatch"); 30 static_assert(CPDF_DataAvail::NotLinearized == PDF_NOT_LINEARIZED, 31 "CPDF_DataAvail::NotLinearized value mismatch"); 32 static_assert(CPDF_DataAvail::Linearized == PDF_LINEARIZED, 33 "CPDF_DataAvail::Linearized value mismatch"); 34 35 static_assert(CPDF_DataAvail::FormError == PDF_FORM_ERROR, 36 "CPDF_DataAvail::FormError value mismatch"); 37 static_assert(CPDF_DataAvail::FormNotAvailable == PDF_FORM_NOTAVAIL, 38 "CPDF_DataAvail::FormNotAvailable value mismatch"); 39 static_assert(CPDF_DataAvail::FormAvailable == PDF_FORM_AVAIL, 40 "CPDF_DataAvail::FormAvailable value mismatch"); 41 static_assert(CPDF_DataAvail::FormNotExist == PDF_FORM_NOTEXIST, 42 "CPDF_DataAvail::FormNotExist value mismatch"); 43 44 namespace { 45 46 class 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 62 class 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 85 class 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 103 class 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 115 FPDF_AvailContext* FPDFAvailContextFromFPDFAvail(FPDF_AVAIL avail) { 116 return static_cast<FPDF_AvailContext*>(avail); 117 } 118 119 } // namespace 120 121 FPDF_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 131 FPDF_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 136 FPDF_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 145 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV 146 FPDFAvail_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 161 FPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc) { 162 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(doc); 163 return pDoc ? pDoc->GetParser()->GetFirstPageNo() : 0; 164 } 165 166 FPDF_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 178 FPDF_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 187 FPDF_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