// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "fpdfsdk/cpdfsdk_helpers.h" #include #include "build/build_config.h" #include "constants/form_fields.h" #include "constants/stream_dict_common.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fpdfapi/render/cpdf_renderoptions.h" #include "core/fpdfdoc/cpdf_annot.h" #include "core/fpdfdoc/cpdf_interactiveform.h" #include "core/fpdfdoc/cpdf_metadata.h" #include "core/fxcrt/check.h" #include "core/fxcrt/compiler_specific.h" #include "core/fxcrt/fx_memcpy_wrappers.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxcrt/numerics/safe_conversions.h" #include "core/fxcrt/span_util.h" #include "core/fxcrt/stl_util.h" #include "core/fxcrt/unowned_ptr.h" #include "fpdfsdk/cpdfsdk_formfillenvironment.h" namespace { constexpr char kQuadPoints[] = "QuadPoints"; // 0 bit: FPDF_POLICY_MACHINETIME_ACCESS uint32_t g_sandbox_policy = 0xFFFFFFFF; UNSUPPORT_INFO* g_unsupport_info = nullptr; bool RaiseUnsupportedError(int nError) { if (!g_unsupport_info) return false; if (g_unsupport_info->FSDK_UnSupport_Handler) g_unsupport_info->FSDK_UnSupport_Handler(g_unsupport_info, nError); return true; } // Use the existence of the XFA array as a signal for XFA forms. bool DocHasXFA(const CPDF_Document* doc) { const CPDF_Dictionary* root = doc->GetRoot(); if (!root) return false; RetainPtr form = root->GetDictFor("AcroForm"); return form && form->GetArrayFor("XFA"); } unsigned long GetStreamMaybeCopyAndReturnLengthImpl( RetainPtr stream, pdfium::span buffer, bool decode) { DCHECK(stream); auto stream_acc = pdfium::MakeRetain(std::move(stream)); if (decode) stream_acc->LoadAllDataFiltered(); else stream_acc->LoadAllDataRaw(); pdfium::span stream_data_span = stream_acc->GetSpan(); if (!buffer.empty() && buffer.size() <= stream_data_span.size()) { fxcrt::Copy(stream_data_span, buffer); } return pdfium::checked_cast(stream_data_span.size()); } // TODO(tsepez): should be UNSAFE_BUFFER_USAGE. size_t FPDFWideStringLength(const unsigned short* str) { if (!str) { return 0; } size_t len = 0; // SAFETY: NUL-termination required from caller. UNSAFE_BUFFERS({ while (str[len]) { len++; } }); return len; } #ifdef PDF_ENABLE_XFA class FPDF_FileHandlerContext final : public IFX_SeekableStream { public: CONSTRUCT_VIA_MAKE_RETAIN; // IFX_SeekableStream: FX_FILESIZE GetSize() override; FX_FILESIZE GetPosition() override; bool IsEOF() override; bool ReadBlockAtOffset(pdfium::span buffer, FX_FILESIZE offset) override; bool WriteBlock(pdfium::span buffer) override; bool Flush() override; private: explicit FPDF_FileHandlerContext(FPDF_FILEHANDLER* pFS); ~FPDF_FileHandlerContext() override; UnownedPtr const m_pFS; FX_FILESIZE m_nCurPos = 0; }; FPDF_FileHandlerContext::FPDF_FileHandlerContext(FPDF_FILEHANDLER* pFS) : m_pFS(pFS) { CHECK(m_pFS); } FPDF_FileHandlerContext::~FPDF_FileHandlerContext() { if (m_pFS->Release) { m_pFS->Release(m_pFS->clientData); } } FX_FILESIZE FPDF_FileHandlerContext::GetSize() { if (m_pFS->GetSize) { return static_cast(m_pFS->GetSize(m_pFS->clientData)); } return 0; } bool FPDF_FileHandlerContext::IsEOF() { return m_nCurPos >= GetSize(); } FX_FILESIZE FPDF_FileHandlerContext::GetPosition() { return m_nCurPos; } bool FPDF_FileHandlerContext::ReadBlockAtOffset(pdfium::span buffer, FX_FILESIZE offset) { if (buffer.empty() || !m_pFS->ReadBlock) { return false; } FX_SAFE_FILESIZE new_position = offset; new_position += buffer.size(); if (!new_position.IsValid()) { return false; } if (m_pFS->ReadBlock(m_pFS->clientData, static_cast(offset), buffer.data(), static_cast(buffer.size())) != 0) { return false; } m_nCurPos = new_position.ValueOrDie(); return true; } bool FPDF_FileHandlerContext::WriteBlock(pdfium::span buffer) { if (!m_pFS->WriteBlock) { return false; } const FX_FILESIZE size = GetSize(); FX_SAFE_FILESIZE new_position = size; new_position += buffer.size(); if (!new_position.IsValid()) { return false; } if (m_pFS->WriteBlock(m_pFS->clientData, static_cast(size), buffer.data(), static_cast(buffer.size())) != 0) { return false; } m_nCurPos = new_position.ValueOrDie(); return true; } bool FPDF_FileHandlerContext::Flush() { if (!m_pFS->Flush) { return true; } return m_pFS->Flush(m_pFS->clientData) == 0; } #endif // PDF_ENABLE_XFA } // namespace IPDF_Page* IPDFPageFromFPDFPage(FPDF_PAGE page) { return reinterpret_cast(page); } FPDF_PAGE FPDFPageFromIPDFPage(IPDF_Page* page) { return reinterpret_cast(page); } CPDF_Document* CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc) { return reinterpret_cast(doc); } FPDF_DOCUMENT FPDFDocumentFromCPDFDocument(CPDF_Document* doc) { return reinterpret_cast(doc); } CPDF_Page* CPDFPageFromFPDFPage(FPDF_PAGE page) { return page ? IPDFPageFromFPDFPage(page)->AsPDFPage() : nullptr; } FXDIB_Format FXDIBFormatFromFPDFFormat(int format) { switch (format) { case FPDFBitmap_Gray: return FXDIB_Format::k8bppRgb; case FPDFBitmap_BGR: return FXDIB_Format::kBgr; case FPDFBitmap_BGRx: return FXDIB_Format::kBgrx; case FPDFBitmap_BGRA: return FXDIB_Format::kBgra; default: return FXDIB_Format::kInvalid; } } CPDFSDK_InteractiveForm* FormHandleToInteractiveForm(FPDF_FORMHANDLE hHandle) { CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); return pFormFillEnv ? pFormFillEnv->GetInteractiveForm() : nullptr; } ByteString ByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string) { // SAFETY: caller ensures `wide_string` is NUL-terminated and enforced // by UNSAFE_BUFFER_USAGE in header file. return UNSAFE_BUFFERS(WideStringFromFPDFWideString(wide_string).ToUTF8()); } WideString WideStringFromFPDFWideString(FPDF_WIDESTRING wide_string) { // SAFETY: caller ensures `wide_string` is NUL-terminated and enforced // by UNSAFE_BUFFER_USAGE in header file. return WideString::FromUTF16LE(UNSAFE_BUFFERS( pdfium::make_span(reinterpret_cast(wide_string), FPDFWideStringLength(wide_string) * 2))); } UNSAFE_BUFFER_USAGE pdfium::span SpanFromFPDFApiArgs( void* buffer, pdfium::StrictNumeric buflen) { if (!buffer) { // API convention is to ignore `buflen` arg when `buffer` is NULL. return pdfium::span(); } // SAFETY: required from caller, enforced by UNSAFE_BUFFER_USAGE in header. return UNSAFE_BUFFERS(pdfium::make_span(static_cast(buffer), buflen)); } #ifdef PDF_ENABLE_XFA RetainPtr MakeSeekableStream( FPDF_FILEHANDLER* pFilehandler) { return pdfium::MakeRetain(pFilehandler); } #endif // PDF_ENABLE_XFA RetainPtr GetQuadPointsArrayFromDictionary( const CPDF_Dictionary* dict) { return dict->GetArrayFor("QuadPoints"); } RetainPtr GetMutableQuadPointsArrayFromDictionary( CPDF_Dictionary* dict) { return pdfium::WrapRetain( const_cast(GetQuadPointsArrayFromDictionary(dict).Get())); } RetainPtr AddQuadPointsArrayToDictionary(CPDF_Dictionary* dict) { return dict->SetNewFor(kQuadPoints); } bool IsValidQuadPointsIndex(const CPDF_Array* array, size_t index) { return array && index < array->size() / 8; } bool GetQuadPointsAtIndex(RetainPtr array, size_t quad_index, FS_QUADPOINTSF* quad_points) { DCHECK(quad_points); DCHECK(array); if (!IsValidQuadPointsIndex(array, quad_index)) return false; quad_index *= 8; quad_points->x1 = array->GetFloatAt(quad_index); quad_points->y1 = array->GetFloatAt(quad_index + 1); quad_points->x2 = array->GetFloatAt(quad_index + 2); quad_points->y2 = array->GetFloatAt(quad_index + 3); quad_points->x3 = array->GetFloatAt(quad_index + 4); quad_points->y3 = array->GetFloatAt(quad_index + 5); quad_points->x4 = array->GetFloatAt(quad_index + 6); quad_points->y4 = array->GetFloatAt(quad_index + 7); return true; } CFX_PointF CFXPointFFromFSPointF(const FS_POINTF& point) { return CFX_PointF(point.x, point.y); } CFX_FloatRect CFXFloatRectFromFSRectF(const FS_RECTF& rect) { return CFX_FloatRect(rect.left, rect.bottom, rect.right, rect.top); } FS_RECTF FSRectFFromCFXFloatRect(const CFX_FloatRect& rect) { return {rect.left, rect.top, rect.right, rect.bottom}; } CFX_Matrix CFXMatrixFromFSMatrix(const FS_MATRIX& matrix) { return CFX_Matrix(matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f); } FS_MATRIX FSMatrixFromCFXMatrix(const CFX_Matrix& matrix) { return {matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f}; } unsigned long NulTerminateMaybeCopyAndReturnLength( const ByteString& text, pdfium::span result_span) { pdfium::span text_span = text.span_with_terminator(); fxcrt::try_spancpy(result_span, text_span); return pdfium::checked_cast(text_span.size()); } unsigned long Utf16EncodeMaybeCopyAndReturnLength( const WideString& text, pdfium::span result_span) { ByteString encoded_text = text.ToUTF16LE(); pdfium::span encoded_text_span = encoded_text.span(); fxcrt::try_spancpy(result_span, encoded_text_span); return pdfium::checked_cast(encoded_text_span.size()); } unsigned long GetRawStreamMaybeCopyAndReturnLength( RetainPtr stream, pdfium::span buffer) { return GetStreamMaybeCopyAndReturnLengthImpl(std::move(stream), buffer, /*decode=*/false); } unsigned long DecodeStreamMaybeCopyAndReturnLength( RetainPtr stream, pdfium::span buffer) { return GetStreamMaybeCopyAndReturnLengthImpl(std::move(stream), buffer, /*decode=*/true); } void SetPDFSandboxPolicy(FPDF_DWORD policy, FPDF_BOOL enable) { switch (policy) { case FPDF_POLICY_MACHINETIME_ACCESS: { uint32_t mask = 1 << policy; if (enable) g_sandbox_policy |= mask; else g_sandbox_policy &= ~mask; } break; default: break; } } FPDF_BOOL IsPDFSandboxPolicyEnabled(FPDF_DWORD policy) { switch (policy) { case FPDF_POLICY_MACHINETIME_ACCESS: { uint32_t mask = 1 << policy; return !!(g_sandbox_policy & mask); } default: return false; } } void SetPDFUnsupportInfo(UNSUPPORT_INFO* unsp_info) { g_unsupport_info = unsp_info; } void ReportUnsupportedFeatures(const CPDF_Document* pDoc) { const CPDF_Dictionary* pRootDict = pDoc->GetRoot(); if (!pRootDict) return; // Portfolios and Packages if (pRootDict->KeyExist("Collection")) RaiseUnsupportedError(FPDF_UNSP_DOC_PORTABLECOLLECTION); RetainPtr pNameDict = pRootDict->GetDictFor("Names"); if (pNameDict) { if (pNameDict->KeyExist("EmbeddedFiles")) RaiseUnsupportedError(FPDF_UNSP_DOC_ATTACHMENT); RetainPtr pJSDict = pNameDict->GetDictFor("JavaScript"); if (pJSDict) { RetainPtr pArray = pJSDict->GetArrayFor("Names"); if (pArray) { for (size_t i = 0; i < pArray->size(); i++) { ByteString cbStr = pArray->GetByteStringAt(i); if (cbStr == "com.adobe.acrobat.SharedReview.Register") { RaiseUnsupportedError(FPDF_UNSP_DOC_SHAREDREVIEW); break; } } } } } // SharedForm RetainPtr pStream = pRootDict->GetStreamFor("Metadata"); if (pStream) { CPDF_Metadata metadata(std::move(pStream)); for (const UnsupportedFeature& feature : metadata.CheckForSharedForm()) RaiseUnsupportedError(static_cast(feature)); } } void ReportUnsupportedXFA(const CPDF_Document* pDoc) { if (!pDoc->GetExtension() && DocHasXFA(pDoc)) RaiseUnsupportedError(FPDF_UNSP_DOC_XFAFORM); } void CheckForUnsupportedAnnot(const CPDF_Annot* pAnnot) { switch (pAnnot->GetSubtype()) { case CPDF_Annot::Subtype::FILEATTACHMENT: RaiseUnsupportedError(FPDF_UNSP_ANNOT_ATTACHMENT); break; case CPDF_Annot::Subtype::MOVIE: RaiseUnsupportedError(FPDF_UNSP_ANNOT_MOVIE); break; case CPDF_Annot::Subtype::RICHMEDIA: RaiseUnsupportedError(FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA); break; case CPDF_Annot::Subtype::SCREEN: { const CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict(); ByteString cbString = pAnnotDict->GetByteStringFor("IT"); if (cbString != "Img") RaiseUnsupportedError(FPDF_UNSP_ANNOT_SCREEN_MEDIA); break; } case CPDF_Annot::Subtype::SOUND: RaiseUnsupportedError(FPDF_UNSP_ANNOT_SOUND); break; case CPDF_Annot::Subtype::THREED: RaiseUnsupportedError(FPDF_UNSP_ANNOT_3DANNOT); break; case CPDF_Annot::Subtype::WIDGET: { const CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict(); ByteString cbString = pAnnotDict->GetByteStringFor(pdfium::form_fields::kFT); if (cbString == pdfium::form_fields::kSig) RaiseUnsupportedError(FPDF_UNSP_ANNOT_SIG); break; } default: break; } } void ProcessParseError(CPDF_Parser::Error err) { uint32_t err_code = FPDF_ERR_SUCCESS; // Translate FPDFAPI error code to FPDFVIEW error code switch (err) { case CPDF_Parser::SUCCESS: err_code = FPDF_ERR_SUCCESS; break; case CPDF_Parser::FILE_ERROR: err_code = FPDF_ERR_FILE; break; case CPDF_Parser::FORMAT_ERROR: err_code = FPDF_ERR_FORMAT; break; case CPDF_Parser::PASSWORD_ERROR: err_code = FPDF_ERR_PASSWORD; break; case CPDF_Parser::HANDLER_ERROR: err_code = FPDF_ERR_SECURITY; break; } FXSYS_SetLastError(err_code); } void SetColorFromScheme(const FPDF_COLORSCHEME* pColorScheme, CPDF_RenderOptions* pRenderOptions) { CPDF_RenderOptions::ColorScheme color_scheme; color_scheme.path_fill_color = static_cast(pColorScheme->path_fill_color); color_scheme.path_stroke_color = static_cast(pColorScheme->path_stroke_color); color_scheme.text_fill_color = static_cast(pColorScheme->text_fill_color); color_scheme.text_stroke_color = static_cast(pColorScheme->text_stroke_color); pRenderOptions->SetColorScheme(color_scheme); } std::vector ParsePageRangeString(const ByteString& bsPageRange, uint32_t nCount) { ByteStringView alphabet(" 0123456789-,"); for (const auto& ch : bsPageRange) { if (!alphabet.Contains(ch)) return std::vector(); } ByteString bsStrippedPageRange = bsPageRange; bsStrippedPageRange.Remove(' '); std::vector results; for (const auto& entry : fxcrt::Split(bsStrippedPageRange, ',')) { std::vector args = fxcrt::Split(entry, '-'); if (args.size() == 1) { uint32_t page_num = pdfium::checked_cast(atoi(args[0].c_str())); if (page_num == 0 || page_num > nCount) return std::vector(); results.push_back(page_num - 1); } else if (args.size() == 2) { uint32_t first_num = pdfium::checked_cast(atoi(args[0].c_str())); if (first_num == 0) return std::vector(); uint32_t last_num = pdfium::checked_cast(atoi(args[1].c_str())); if (last_num == 0 || first_num > last_num || last_num > nCount) return std::vector(); for (uint32_t i = first_num; i <= last_num; ++i) results.push_back(i - 1); } else { return std::vector(); } } return results; }