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/fpdfview.h" 8 9#include <memory> 10#include <utility> 11 12#include "core/fpdfapi/cpdf_modulemgr.h" 13#include "core/fpdfapi/cpdf_pagerendercontext.h" 14#include "core/fpdfapi/page/cpdf_page.h" 15#include "core/fpdfapi/parser/cpdf_array.h" 16#include "core/fpdfapi/parser/cpdf_document.h" 17#include "core/fpdfapi/parser/fpdf_parser_decode.h" 18#include "core/fpdfapi/render/cpdf_progressiverenderer.h" 19#include "core/fpdfapi/render/cpdf_renderoptions.h" 20#include "core/fpdfdoc/cpdf_annotlist.h" 21#include "core/fpdfdoc/cpdf_nametree.h" 22#include "core/fpdfdoc/cpdf_occontext.h" 23#include "core/fpdfdoc/cpdf_viewerpreferences.h" 24#include "core/fxcodec/fx_codec.h" 25#include "core/fxcrt/fx_memory.h" 26#include "core/fxcrt/fx_safe_types.h" 27#include "core/fxge/cfx_fxgedevice.h" 28#include "core/fxge/cfx_gemodule.h" 29#include "fpdfsdk/cpdfsdk_formfillenvironment.h" 30#include "fpdfsdk/cpdfsdk_pageview.h" 31#include "fpdfsdk/fsdk_define.h" 32#include "fpdfsdk/fsdk_pauseadapter.h" 33#include "fpdfsdk/javascript/ijs_runtime.h" 34#include "public/fpdf_ext.h" 35#include "public/fpdf_progressive.h" 36#include "third_party/base/numerics/safe_conversions_impl.h" 37#include "third_party/base/ptr_util.h" 38 39#ifdef PDF_ENABLE_XFA 40#include "fpdfsdk/fpdfxfa/cpdfxfa_context.h" 41#include "fpdfsdk/fpdfxfa/cpdfxfa_page.h" 42#include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h" 43#include "public/fpdf_formfill.h" 44#include "xfa/fxbarcode/BC_Library.h" 45#endif // PDF_ENABLE_XFA 46 47#ifdef PDF_ENABLE_XFA_BMP 48#include "core/fxcodec/codec/ccodec_bmpmodule.h" 49#endif 50 51#ifdef PDF_ENABLE_XFA_GIF 52#include "core/fxcodec/codec/ccodec_gifmodule.h" 53#endif 54 55#ifdef PDF_ENABLE_XFA_PNG 56#include "core/fxcodec/codec/ccodec_pngmodule.h" 57#endif 58 59#ifdef PDF_ENABLE_XFA_TIFF 60#include "core/fxcodec/codec/ccodec_tiffmodule.h" 61#endif 62 63#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ 64#include "core/fxge/cfx_windowsdevice.h" 65#endif 66 67namespace { 68 69// Also indicates whether library is currently initialized. 70CCodec_ModuleMgr* g_pCodecModule = nullptr; 71 72void RenderPageImpl(CPDF_PageRenderContext* pContext, 73 CPDF_Page* pPage, 74 const CFX_Matrix& matrix, 75 const FX_RECT& clipping_rect, 76 int flags, 77 bool bNeedToRestore, 78 IFSDK_PAUSE_Adapter* pause) { 79 if (!pContext->m_pOptions) 80 pContext->m_pOptions = pdfium::MakeUnique<CPDF_RenderOptions>(); 81 82 if (flags & FPDF_LCD_TEXT) 83 pContext->m_pOptions->m_Flags |= RENDER_CLEARTYPE; 84 else 85 pContext->m_pOptions->m_Flags &= ~RENDER_CLEARTYPE; 86 87 if (flags & FPDF_NO_NATIVETEXT) 88 pContext->m_pOptions->m_Flags |= RENDER_NO_NATIVETEXT; 89 if (flags & FPDF_RENDER_LIMITEDIMAGECACHE) 90 pContext->m_pOptions->m_Flags |= RENDER_LIMITEDIMAGECACHE; 91 if (flags & FPDF_RENDER_FORCEHALFTONE) 92 pContext->m_pOptions->m_Flags |= RENDER_FORCE_HALFTONE; 93#ifndef PDF_ENABLE_XFA 94 if (flags & FPDF_RENDER_NO_SMOOTHTEXT) 95 pContext->m_pOptions->m_Flags |= RENDER_NOTEXTSMOOTH; 96 if (flags & FPDF_RENDER_NO_SMOOTHIMAGE) 97 pContext->m_pOptions->m_Flags |= RENDER_NOIMAGESMOOTH; 98 if (flags & FPDF_RENDER_NO_SMOOTHPATH) 99 pContext->m_pOptions->m_Flags |= RENDER_NOPATHSMOOTH; 100#endif // PDF_ENABLE_XFA 101 102 // Grayscale output 103 if (flags & FPDF_GRAYSCALE) { 104 pContext->m_pOptions->m_ColorMode = RENDER_COLOR_GRAY; 105 pContext->m_pOptions->m_ForeColor = 0; 106 pContext->m_pOptions->m_BackColor = 0xffffff; 107 } 108 109 const CPDF_OCContext::UsageType usage = 110 (flags & FPDF_PRINTING) ? CPDF_OCContext::Print : CPDF_OCContext::View; 111 pContext->m_pOptions->m_AddFlags = flags >> 8; 112 pContext->m_pOptions->m_pOCContext = 113 pdfium::MakeRetain<CPDF_OCContext>(pPage->m_pDocument, usage); 114 115 pContext->m_pDevice->SaveState(); 116 pContext->m_pDevice->SetClip_Rect(clipping_rect); 117 118 pContext->m_pContext = pdfium::MakeUnique<CPDF_RenderContext>(pPage); 119 pContext->m_pContext->AppendLayer(pPage, &matrix); 120 121 if (flags & FPDF_ANNOT) { 122 pContext->m_pAnnots = pdfium::MakeUnique<CPDF_AnnotList>(pPage); 123 bool bPrinting = pContext->m_pDevice->GetDeviceClass() != FXDC_DISPLAY; 124 pContext->m_pAnnots->DisplayAnnots(pPage, pContext->m_pContext.get(), 125 bPrinting, &matrix, false, nullptr); 126 } 127 128 pContext->m_pRenderer = pdfium::MakeUnique<CPDF_ProgressiveRenderer>( 129 pContext->m_pContext.get(), pContext->m_pDevice.get(), 130 pContext->m_pOptions.get()); 131 pContext->m_pRenderer->Start(pause); 132 if (bNeedToRestore) 133 pContext->m_pDevice->RestoreState(false); 134} 135 136class CPDF_CustomAccess final : public IFX_SeekableReadStream { 137 public: 138 static CFX_RetainPtr<CPDF_CustomAccess> Create(FPDF_FILEACCESS* pFileAccess) { 139 return CFX_RetainPtr<CPDF_CustomAccess>(new CPDF_CustomAccess(pFileAccess)); 140 } 141 142 // IFX_SeekableReadStream 143 FX_FILESIZE GetSize() override; 144 bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override; 145 146 private: 147 explicit CPDF_CustomAccess(FPDF_FILEACCESS* pFileAccess); 148 149 FPDF_FILEACCESS m_FileAccess; 150}; 151 152CPDF_CustomAccess::CPDF_CustomAccess(FPDF_FILEACCESS* pFileAccess) 153 : m_FileAccess(*pFileAccess) {} 154 155FX_FILESIZE CPDF_CustomAccess::GetSize() { 156 return m_FileAccess.m_FileLen; 157} 158 159bool CPDF_CustomAccess::ReadBlock(void* buffer, 160 FX_FILESIZE offset, 161 size_t size) { 162 if (offset < 0) 163 return false; 164 165 FX_SAFE_FILESIZE newPos = pdfium::base::checked_cast<FX_FILESIZE>(size); 166 newPos += offset; 167 if (!newPos.IsValid() || 168 newPos.ValueOrDie() > static_cast<FX_FILESIZE>(m_FileAccess.m_FileLen)) { 169 return false; 170 } 171 return !!m_FileAccess.m_GetBlock(m_FileAccess.m_Param, offset, 172 reinterpret_cast<uint8_t*>(buffer), size); 173} 174 175#ifdef PDF_ENABLE_XFA 176class CFPDF_FileStream : public IFX_SeekableStream { 177 public: 178 static CFX_RetainPtr<CFPDF_FileStream> Create(FPDF_FILEHANDLER* pFS) { 179 return CFX_RetainPtr<CFPDF_FileStream>(new CFPDF_FileStream(pFS)); 180 } 181 ~CFPDF_FileStream() override; 182 183 // IFX_SeekableStream: 184 FX_FILESIZE GetSize() override; 185 bool IsEOF() override; 186 FX_FILESIZE GetPosition() override; 187 bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override; 188 size_t ReadBlock(void* buffer, size_t size) override; 189 bool WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size) override; 190 bool Flush() override; 191 192 void SetPosition(FX_FILESIZE pos) { m_nCurPos = pos; } 193 194 protected: 195 explicit CFPDF_FileStream(FPDF_FILEHANDLER* pFS); 196 197 FPDF_FILEHANDLER* m_pFS; 198 FX_FILESIZE m_nCurPos; 199}; 200 201CFPDF_FileStream::CFPDF_FileStream(FPDF_FILEHANDLER* pFS) { 202 m_pFS = pFS; 203 m_nCurPos = 0; 204} 205 206CFPDF_FileStream::~CFPDF_FileStream() { 207 if (m_pFS && m_pFS->Release) 208 m_pFS->Release(m_pFS->clientData); 209} 210 211FX_FILESIZE CFPDF_FileStream::GetSize() { 212 if (m_pFS && m_pFS->GetSize) 213 return (FX_FILESIZE)m_pFS->GetSize(m_pFS->clientData); 214 return 0; 215} 216 217bool CFPDF_FileStream::IsEOF() { 218 return m_nCurPos >= GetSize(); 219} 220 221FX_FILESIZE CFPDF_FileStream::GetPosition() { 222 return m_nCurPos; 223} 224 225bool CFPDF_FileStream::ReadBlock(void* buffer, 226 FX_FILESIZE offset, 227 size_t size) { 228 if (!buffer || !size || !m_pFS->ReadBlock) 229 return false; 230 231 if (m_pFS->ReadBlock(m_pFS->clientData, (FPDF_DWORD)offset, buffer, 232 (FPDF_DWORD)size) == 0) { 233 m_nCurPos = offset + size; 234 return true; 235 } 236 return false; 237} 238 239size_t CFPDF_FileStream::ReadBlock(void* buffer, size_t size) { 240 if (!buffer || !size || !m_pFS->ReadBlock) 241 return 0; 242 243 FX_FILESIZE nSize = GetSize(); 244 if (m_nCurPos >= nSize) 245 return 0; 246 FX_FILESIZE dwAvail = nSize - m_nCurPos; 247 if (dwAvail < (FX_FILESIZE)size) 248 size = (size_t)dwAvail; 249 if (m_pFS->ReadBlock(m_pFS->clientData, (FPDF_DWORD)m_nCurPos, buffer, 250 (FPDF_DWORD)size) == 0) { 251 m_nCurPos += size; 252 return size; 253 } 254 255 return 0; 256} 257 258bool CFPDF_FileStream::WriteBlock(const void* buffer, 259 FX_FILESIZE offset, 260 size_t size) { 261 if (!m_pFS || !m_pFS->WriteBlock) 262 return false; 263 264 if (m_pFS->WriteBlock(m_pFS->clientData, (FPDF_DWORD)offset, buffer, 265 (FPDF_DWORD)size) == 0) { 266 m_nCurPos = offset + size; 267 return true; 268 } 269 return false; 270} 271 272bool CFPDF_FileStream::Flush() { 273 if (!m_pFS || !m_pFS->Flush) 274 return true; 275 276 return m_pFS->Flush(m_pFS->clientData) == 0; 277} 278#endif // PDF_ENABLE_XFA 279 280} // namespace 281 282UnderlyingDocumentType* UnderlyingFromFPDFDocument(FPDF_DOCUMENT doc) { 283 return static_cast<UnderlyingDocumentType*>(doc); 284} 285 286FPDF_DOCUMENT FPDFDocumentFromUnderlying(UnderlyingDocumentType* doc) { 287 return static_cast<FPDF_DOCUMENT>(doc); 288} 289 290UnderlyingPageType* UnderlyingFromFPDFPage(FPDF_PAGE page) { 291 return static_cast<UnderlyingPageType*>(page); 292} 293 294CPDF_Document* CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc) { 295#ifdef PDF_ENABLE_XFA 296 return doc ? UnderlyingFromFPDFDocument(doc)->GetPDFDoc() : nullptr; 297#else // PDF_ENABLE_XFA 298 return UnderlyingFromFPDFDocument(doc); 299#endif // PDF_ENABLE_XFA 300} 301 302FPDF_DOCUMENT FPDFDocumentFromCPDFDocument(CPDF_Document* doc) { 303#ifdef PDF_ENABLE_XFA 304 return doc ? FPDFDocumentFromUnderlying( 305 new CPDFXFA_Context(pdfium::WrapUnique(doc))) 306 : nullptr; 307#else // PDF_ENABLE_XFA 308 return FPDFDocumentFromUnderlying(doc); 309#endif // PDF_ENABLE_XFA 310} 311 312CPDF_Page* CPDFPageFromFPDFPage(FPDF_PAGE page) { 313#ifdef PDF_ENABLE_XFA 314 return page ? UnderlyingFromFPDFPage(page)->GetPDFPage() : nullptr; 315#else // PDF_ENABLE_XFA 316 return UnderlyingFromFPDFPage(page); 317#endif // PDF_ENABLE_XFA 318} 319 320CFX_DIBitmap* CFXBitmapFromFPDFBitmap(FPDF_BITMAP bitmap) { 321 return static_cast<CFX_DIBitmap*>(bitmap); 322} 323 324CFX_RetainPtr<IFX_SeekableReadStream> MakeSeekableReadStream( 325 FPDF_FILEACCESS* pFileAccess) { 326 return CPDF_CustomAccess::Create(pFileAccess); 327} 328 329#ifdef PDF_ENABLE_XFA 330CFX_RetainPtr<IFX_SeekableStream> MakeSeekableStream( 331 FPDF_FILEHANDLER* pFilehandler) { 332 return CFPDF_FileStream::Create(pFilehandler); 333} 334#endif // PDF_ENABLE_XFA 335 336// 0 bit: FPDF_POLICY_MACHINETIME_ACCESS 337static uint32_t foxit_sandbox_policy = 0xFFFFFFFF; 338 339void FSDK_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable) { 340 switch (policy) { 341 case FPDF_POLICY_MACHINETIME_ACCESS: { 342 if (enable) 343 foxit_sandbox_policy |= 0x01; 344 else 345 foxit_sandbox_policy &= 0xFFFFFFFE; 346 } break; 347 default: 348 break; 349 } 350} 351 352FPDF_BOOL FSDK_IsSandBoxPolicyEnabled(FPDF_DWORD policy) { 353 switch (policy) { 354 case FPDF_POLICY_MACHINETIME_ACCESS: 355 return !!(foxit_sandbox_policy & 0x01); 356 default: 357 return false; 358 } 359} 360 361DLLEXPORT void STDCALL FPDF_InitLibrary() { 362 FPDF_InitLibraryWithConfig(nullptr); 363} 364 365DLLEXPORT void STDCALL 366FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* cfg) { 367 if (g_pCodecModule) 368 return; 369 370 g_pCodecModule = new CCodec_ModuleMgr(); 371 372 CFX_GEModule* pModule = CFX_GEModule::Get(); 373 pModule->Init(cfg ? cfg->m_pUserFontPaths : nullptr, g_pCodecModule); 374 375 CPDF_ModuleMgr* pModuleMgr = CPDF_ModuleMgr::Get(); 376 pModuleMgr->SetCodecModule(g_pCodecModule); 377 pModuleMgr->InitPageModule(); 378 pModuleMgr->LoadEmbeddedGB1CMaps(); 379 pModuleMgr->LoadEmbeddedJapan1CMaps(); 380 pModuleMgr->LoadEmbeddedCNS1CMaps(); 381 pModuleMgr->LoadEmbeddedKorea1CMaps(); 382 383#ifdef PDF_ENABLE_XFA_BMP 384 pModuleMgr->GetCodecModule()->SetBmpModule( 385 pdfium::MakeUnique<CCodec_BmpModule>()); 386#endif 387 388#ifdef PDF_ENABLE_XFA_GIF 389 pModuleMgr->GetCodecModule()->SetGifModule( 390 pdfium::MakeUnique<CCodec_GifModule>()); 391#endif 392 393#ifdef PDF_ENABLE_XFA_PNG 394 pModuleMgr->GetCodecModule()->SetPngModule( 395 pdfium::MakeUnique<CCodec_PngModule>()); 396#endif 397 398#ifdef PDF_ENABLE_XFA_TIFF 399 pModuleMgr->GetCodecModule()->SetTiffModule( 400 pdfium::MakeUnique<CCodec_TiffModule>()); 401#endif 402 403#ifdef PDF_ENABLE_XFA 404 FXJSE_Initialize(); 405 BC_Library_Init(); 406#endif // PDF_ENABLE_XFA 407 if (cfg && cfg->version >= 2) 408 IJS_Runtime::Initialize(cfg->m_v8EmbedderSlot, cfg->m_pIsolate); 409} 410 411DLLEXPORT void STDCALL FPDF_DestroyLibrary() { 412 if (!g_pCodecModule) 413 return; 414 415#ifdef PDF_ENABLE_XFA 416 BC_Library_Destory(); 417 FXJSE_Finalize(); 418#endif // PDF_ENABLE_XFA 419 420 CPDF_ModuleMgr::Destroy(); 421 CFX_GEModule::Destroy(); 422 423 delete g_pCodecModule; 424 g_pCodecModule = nullptr; 425 426 IJS_Runtime::Destroy(); 427} 428 429#ifndef _WIN32 430int g_LastError; 431void SetLastError(int err) { 432 g_LastError = err; 433} 434 435int GetLastError() { 436 return g_LastError; 437} 438#endif // _WIN32 439 440void ProcessParseError(CPDF_Parser::Error err) { 441 uint32_t err_code = FPDF_ERR_SUCCESS; 442 // Translate FPDFAPI error code to FPDFVIEW error code 443 switch (err) { 444 case CPDF_Parser::SUCCESS: 445 err_code = FPDF_ERR_SUCCESS; 446 break; 447 case CPDF_Parser::FILE_ERROR: 448 err_code = FPDF_ERR_FILE; 449 break; 450 case CPDF_Parser::FORMAT_ERROR: 451 err_code = FPDF_ERR_FORMAT; 452 break; 453 case CPDF_Parser::PASSWORD_ERROR: 454 err_code = FPDF_ERR_PASSWORD; 455 break; 456 case CPDF_Parser::HANDLER_ERROR: 457 err_code = FPDF_ERR_SECURITY; 458 break; 459 } 460 SetLastError(err_code); 461} 462 463DLLEXPORT void STDCALL FPDF_SetSandBoxPolicy(FPDF_DWORD policy, 464 FPDF_BOOL enable) { 465 return FSDK_SetSandBoxPolicy(policy, enable); 466} 467 468#if defined(_WIN32) 469#if defined(PDFIUM_PRINT_TEXT_WITH_GDI) 470DLLEXPORT void STDCALL 471FPDF_SetTypefaceAccessibleFunc(PDFiumEnsureTypefaceCharactersAccessible func) { 472 g_pdfium_typeface_accessible_func = func; 473} 474 475DLLEXPORT void STDCALL FPDF_SetPrintTextWithGDI(FPDF_BOOL use_gdi) { 476 g_pdfium_print_text_with_gdi = !!use_gdi; 477} 478#endif // PDFIUM_PRINT_TEXT_WITH_GDI 479 480DLLEXPORT FPDF_BOOL STDCALL FPDF_SetPrintPostscriptLevel(int postscript_level) { 481 if (postscript_level != 0 && postscript_level != 2 && postscript_level != 3) 482 return FALSE; 483 g_pdfium_print_postscript_level = postscript_level; 484 return TRUE; 485} 486#endif // defined(_WIN32) 487 488DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_LoadDocument(FPDF_STRING file_path, 489 FPDF_BYTESTRING password) { 490 // NOTE: the creation of the file needs to be by the embedder on the 491 // other side of this API. 492 CFX_RetainPtr<IFX_SeekableReadStream> pFileAccess = 493 IFX_SeekableReadStream::CreateFromFilename((const FX_CHAR*)file_path); 494 if (!pFileAccess) 495 return nullptr; 496 497 auto pParser = pdfium::MakeUnique<CPDF_Parser>(); 498 pParser->SetPassword(password); 499 500 auto pDocument = pdfium::MakeUnique<CPDF_Document>(std::move(pParser)); 501 CPDF_Parser::Error error = 502 pDocument->GetParser()->StartParse(pFileAccess, pDocument.get()); 503 if (error != CPDF_Parser::SUCCESS) { 504 ProcessParseError(error); 505 return nullptr; 506 } 507 return FPDFDocumentFromCPDFDocument(pDocument.release()); 508} 509 510#ifdef PDF_ENABLE_XFA 511DLLEXPORT FPDF_BOOL STDCALL FPDF_HasXFAField(FPDF_DOCUMENT document, 512 int* docType) { 513 if (!document) 514 return false; 515 516 CPDF_Document* pdfDoc = 517 (static_cast<CPDFXFA_Context*>(document))->GetPDFDoc(); 518 if (!pdfDoc) 519 return false; 520 521 CPDF_Dictionary* pRoot = pdfDoc->GetRoot(); 522 if (!pRoot) 523 return false; 524 525 CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm"); 526 if (!pAcroForm) 527 return false; 528 529 CPDF_Object* pXFA = pAcroForm->GetObjectFor("XFA"); 530 if (!pXFA) 531 return false; 532 533 bool bDynamicXFA = pRoot->GetBooleanFor("NeedsRendering", false); 534 *docType = bDynamicXFA ? DOCTYPE_DYNAMIC_XFA : DOCTYPE_STATIC_XFA; 535 return true; 536} 537 538DLLEXPORT FPDF_BOOL STDCALL FPDF_LoadXFA(FPDF_DOCUMENT document) { 539 return document && (static_cast<CPDFXFA_Context*>(document))->LoadXFADoc(); 540} 541#endif // PDF_ENABLE_XFA 542 543class CMemFile final : public IFX_SeekableReadStream { 544 public: 545 static CFX_RetainPtr<CMemFile> Create(uint8_t* pBuf, FX_FILESIZE size) { 546 return CFX_RetainPtr<CMemFile>(new CMemFile(pBuf, size)); 547 } 548 549 FX_FILESIZE GetSize() override { return m_size; } 550 bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override { 551 if (offset < 0) 552 return false; 553 554 FX_SAFE_FILESIZE newPos = pdfium::base::checked_cast<FX_FILESIZE>(size); 555 newPos += offset; 556 if (!newPos.IsValid() || newPos.ValueOrDie() > m_size) 557 return false; 558 559 FXSYS_memcpy(buffer, m_pBuf + offset, size); 560 return true; 561 } 562 563 private: 564 CMemFile(uint8_t* pBuf, FX_FILESIZE size) : m_pBuf(pBuf), m_size(size) {} 565 566 uint8_t* const m_pBuf; 567 const FX_FILESIZE m_size; 568}; 569 570DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_LoadMemDocument(const void* data_buf, 571 int size, 572 FPDF_BYTESTRING password) { 573 CFX_RetainPtr<CMemFile> pMemFile = CMemFile::Create((uint8_t*)data_buf, size); 574 auto pParser = pdfium::MakeUnique<CPDF_Parser>(); 575 pParser->SetPassword(password); 576 577 auto pDocument = pdfium::MakeUnique<CPDF_Document>(std::move(pParser)); 578 CPDF_Parser::Error error = 579 pDocument->GetParser()->StartParse(pMemFile, pDocument.get()); 580 if (error != CPDF_Parser::SUCCESS) { 581 ProcessParseError(error); 582 return nullptr; 583 } 584 CheckUnSupportError(pDocument.get(), error); 585 return FPDFDocumentFromCPDFDocument(pDocument.release()); 586} 587 588DLLEXPORT FPDF_DOCUMENT STDCALL 589FPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, 590 FPDF_BYTESTRING password) { 591 CFX_RetainPtr<CPDF_CustomAccess> pFile = 592 CPDF_CustomAccess::Create(pFileAccess); 593 auto pParser = pdfium::MakeUnique<CPDF_Parser>(); 594 pParser->SetPassword(password); 595 596 auto pDocument = pdfium::MakeUnique<CPDF_Document>(std::move(pParser)); 597 CPDF_Parser::Error error = 598 pDocument->GetParser()->StartParse(pFile, pDocument.get()); 599 if (error != CPDF_Parser::SUCCESS) { 600 ProcessParseError(error); 601 return nullptr; 602 } 603 CheckUnSupportError(pDocument.get(), error); 604 return FPDFDocumentFromCPDFDocument(pDocument.release()); 605} 606 607DLLEXPORT FPDF_BOOL STDCALL FPDF_GetFileVersion(FPDF_DOCUMENT doc, 608 int* fileVersion) { 609 if (!fileVersion) 610 return false; 611 612 *fileVersion = 0; 613 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(doc); 614 if (!pDoc) 615 return false; 616 617 CPDF_Parser* pParser = pDoc->GetParser(); 618 if (!pParser) 619 return false; 620 621 *fileVersion = pParser->GetFileVersion(); 622 return true; 623} 624 625// jabdelmalek: changed return type from uint32_t to build on Linux (and match 626// header). 627DLLEXPORT unsigned long STDCALL FPDF_GetDocPermissions(FPDF_DOCUMENT document) { 628 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 629 // https://bugs.chromium.org/p/pdfium/issues/detail?id=499 630 if (!pDoc) { 631#ifndef PDF_ENABLE_XFA 632 return 0; 633#else // PDF_ENABLE_XFA 634 return 0xFFFFFFFF; 635#endif // PDF_ENABLE_XFA 636 } 637 638 return pDoc->GetUserPermissions(); 639} 640 641DLLEXPORT int STDCALL FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document) { 642 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 643 if (!pDoc || !pDoc->GetParser()) 644 return -1; 645 646 CPDF_Dictionary* pDict = pDoc->GetParser()->GetEncryptDict(); 647 return pDict ? pDict->GetIntegerFor("R") : -1; 648} 649 650DLLEXPORT int STDCALL FPDF_GetPageCount(FPDF_DOCUMENT document) { 651 UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document); 652 return pDoc ? pDoc->GetPageCount() : 0; 653} 654 655DLLEXPORT FPDF_PAGE STDCALL FPDF_LoadPage(FPDF_DOCUMENT document, 656 int page_index) { 657 UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document); 658 if (!pDoc) 659 return nullptr; 660 661 if (page_index < 0 || page_index >= pDoc->GetPageCount()) 662 return nullptr; 663 664#ifdef PDF_ENABLE_XFA 665 return pDoc->GetXFAPage(page_index); 666#else // PDF_ENABLE_XFA 667 CPDF_Dictionary* pDict = pDoc->GetPage(page_index); 668 if (!pDict) 669 return nullptr; 670 671 CPDF_Page* pPage = new CPDF_Page(pDoc, pDict, true); 672 pPage->ParseContent(); 673 return pPage; 674#endif // PDF_ENABLE_XFA 675} 676 677DLLEXPORT double STDCALL FPDF_GetPageWidth(FPDF_PAGE page) { 678 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 679 return pPage ? pPage->GetPageWidth() : 0.0; 680} 681 682DLLEXPORT double STDCALL FPDF_GetPageHeight(FPDF_PAGE page) { 683 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 684 return pPage ? pPage->GetPageHeight() : 0.0; 685} 686 687#if defined(_WIN32) 688DLLEXPORT void STDCALL FPDF_RenderPage(HDC dc, 689 FPDF_PAGE page, 690 int start_x, 691 int start_y, 692 int size_x, 693 int size_y, 694 int rotate, 695 int flags) { 696 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 697 if (!pPage) 698 return; 699 700 CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext; 701 pPage->SetRenderContext(pdfium::WrapUnique(pContext)); 702 703 std::unique_ptr<CFX_DIBitmap> pBitmap; 704 // TODO: This results in unnecessary rasterization of some PDFs due to 705 // HasImageMask() returning true. If any image on the page is a mask, the 706 // entire page gets rasterized and the spool size gets huge. 707 const bool bNewBitmap = 708 pPage->BackgroundAlphaNeeded() || pPage->HasImageMask(); 709 if (bNewBitmap) { 710 pBitmap = pdfium::MakeUnique<CFX_DIBitmap>(); 711 pBitmap->Create(size_x, size_y, FXDIB_Argb); 712 pBitmap->Clear(0x00ffffff); 713 CFX_FxgeDevice* pDevice = new CFX_FxgeDevice; 714 pContext->m_pDevice = pdfium::WrapUnique(pDevice); 715 pDevice->Attach(pBitmap.get(), false, nullptr, false); 716 } else { 717 pContext->m_pDevice = pdfium::MakeUnique<CFX_WindowsDevice>(dc); 718 } 719 720 FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y, 721 rotate, flags, true, nullptr); 722 723 if (bNewBitmap) { 724 CFX_WindowsDevice WinDC(dc); 725 if (WinDC.GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) { 726 std::unique_ptr<CFX_DIBitmap> pDst = pdfium::MakeUnique<CFX_DIBitmap>(); 727 int pitch = pBitmap->GetPitch(); 728 pDst->Create(size_x, size_y, FXDIB_Rgb32); 729 FXSYS_memset(pDst->GetBuffer(), -1, pitch * size_y); 730 pDst->CompositeBitmap(0, 0, size_x, size_y, pBitmap.get(), 0, 0, 731 FXDIB_BLEND_NORMAL, nullptr, false, nullptr); 732 WinDC.StretchDIBits(pDst.get(), 0, 0, size_x, size_y); 733 } else { 734 WinDC.SetDIBits(pBitmap.get(), 0, 0); 735 } 736 } 737 738 pPage->SetRenderContext(nullptr); 739} 740#endif // defined(_WIN32) 741 742DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, 743 FPDF_PAGE page, 744 int start_x, 745 int start_y, 746 int size_x, 747 int size_y, 748 int rotate, 749 int flags) { 750 if (!bitmap) 751 return; 752 753 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 754 if (!pPage) 755 return; 756 757 CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext; 758 pPage->SetRenderContext(pdfium::WrapUnique(pContext)); 759 CFX_FxgeDevice* pDevice = new CFX_FxgeDevice; 760 pContext->m_pDevice.reset(pDevice); 761 CFX_DIBitmap* pBitmap = CFXBitmapFromFPDFBitmap(bitmap); 762 pDevice->Attach(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER), nullptr, false); 763 764 FPDF_RenderPage_Retail(pContext, page, start_x, start_y, size_x, size_y, 765 rotate, flags, true, nullptr); 766 767#ifdef _SKIA_SUPPORT_PATHS_ 768 pDevice->Flush(); 769 pBitmap->UnPreMultiply(); 770#endif 771 pPage->SetRenderContext(nullptr); 772} 773 774DLLEXPORT void STDCALL FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap, 775 FPDF_PAGE page, 776 const FS_MATRIX* matrix, 777 const FS_RECTF* clipping, 778 int flags) { 779 if (!bitmap) 780 return; 781 782 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 783 if (!pPage) 784 return; 785 786 CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext; 787 pPage->SetRenderContext(pdfium::WrapUnique(pContext)); 788 CFX_FxgeDevice* pDevice = new CFX_FxgeDevice; 789 pContext->m_pDevice.reset(pDevice); 790 CFX_DIBitmap* pBitmap = CFXBitmapFromFPDFBitmap(bitmap); 791 pDevice->Attach(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER), nullptr, false); 792 793 CFX_Matrix transform_matrix = pPage->GetPageMatrix(); 794 if (matrix) { 795 transform_matrix.Concat(CFX_Matrix(matrix->a, matrix->b, matrix->c, 796 matrix->d, matrix->e, matrix->f)); 797 } 798 799 CFX_FloatRect clipping_rect; 800 if (clipping) { 801 clipping_rect.left = clipping->left; 802 clipping_rect.bottom = clipping->bottom; 803 clipping_rect.right = clipping->right; 804 clipping_rect.top = clipping->top; 805 } 806 RenderPageImpl(pContext, pPage, transform_matrix, clipping_rect.ToFxRect(), 807 flags, true, nullptr); 808 809 pPage->SetRenderContext(nullptr); 810} 811 812#ifdef _SKIA_SUPPORT_ 813DLLEXPORT FPDF_RECORDER STDCALL FPDF_RenderPageSkp(FPDF_PAGE page, 814 int size_x, 815 int size_y) { 816 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 817 if (!pPage) 818 return nullptr; 819 820 CPDF_PageRenderContext* pContext = new CPDF_PageRenderContext; 821 pPage->SetRenderContext(pdfium::WrapUnique(pContext)); 822 CFX_FxgeDevice* skDevice = new CFX_FxgeDevice; 823 FPDF_RECORDER recorder = skDevice->CreateRecorder(size_x, size_y); 824 pContext->m_pDevice.reset(skDevice); 825 FPDF_RenderPage_Retail(pContext, page, 0, 0, size_x, size_y, 0, 0, true, 826 nullptr); 827 pPage->SetRenderContext(nullptr); 828 return recorder; 829} 830#endif 831 832DLLEXPORT void STDCALL FPDF_ClosePage(FPDF_PAGE page) { 833 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 834 if (!page) 835 return; 836#ifdef PDF_ENABLE_XFA 837 pPage->Release(); 838#else // PDF_ENABLE_XFA 839 CPDFSDK_PageView* pPageView = 840 static_cast<CPDFSDK_PageView*>(pPage->GetView()); 841 if (pPageView) { 842 // We're already destroying the pageview, so bail early. 843 if (pPageView->IsBeingDestroyed()) 844 return; 845 846 if (pPageView->IsLocked()) { 847 pPageView->TakePageOwnership(); 848 return; 849 } 850 851 bool owned = pPageView->OwnsPage(); 852 // This will delete the |pPageView| object. We must cleanup the PageView 853 // first because it will attempt to reset the View on the |pPage| during 854 // destruction. 855 pPageView->GetFormFillEnv()->RemovePageView(pPage); 856 // If the page was owned then the pageview will have deleted the page. 857 if (owned) 858 return; 859 } 860 delete pPage; 861#endif // PDF_ENABLE_XFA 862} 863 864DLLEXPORT void STDCALL FPDF_CloseDocument(FPDF_DOCUMENT document) { 865 delete UnderlyingFromFPDFDocument(document); 866} 867 868DLLEXPORT unsigned long STDCALL FPDF_GetLastError() { 869 return GetLastError(); 870} 871 872DLLEXPORT void STDCALL FPDF_DeviceToPage(FPDF_PAGE page, 873 int start_x, 874 int start_y, 875 int size_x, 876 int size_y, 877 int rotate, 878 int device_x, 879 int device_y, 880 double* page_x, 881 double* page_y) { 882 if (!page || !page_x || !page_y) 883 return; 884 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 885#ifdef PDF_ENABLE_XFA 886 pPage->DeviceToPage(start_x, start_y, size_x, size_y, rotate, device_x, 887 device_y, page_x, page_y); 888#else // PDF_ENABLE_XFA 889 CFX_Matrix page2device = 890 pPage->GetDisplayMatrix(start_x, start_y, size_x, size_y, rotate); 891 CFX_Matrix device2page; 892 device2page.SetReverse(page2device); 893 894 CFX_PointF pos = device2page.Transform(CFX_PointF( 895 static_cast<FX_FLOAT>(device_x), static_cast<FX_FLOAT>(device_y))); 896 897 *page_x = pos.x; 898 *page_y = pos.y; 899#endif // PDF_ENABLE_XFA 900} 901 902DLLEXPORT void STDCALL FPDF_PageToDevice(FPDF_PAGE page, 903 int start_x, 904 int start_y, 905 int size_x, 906 int size_y, 907 int rotate, 908 double page_x, 909 double page_y, 910 int* device_x, 911 int* device_y) { 912 if (!device_x || !device_y) 913 return; 914 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page); 915 if (!pPage) 916 return; 917#ifdef PDF_ENABLE_XFA 918 pPage->PageToDevice(start_x, start_y, size_x, size_y, rotate, page_x, page_y, 919 device_x, device_y); 920#else // PDF_ENABLE_XFA 921 CFX_Matrix page2device = 922 pPage->GetDisplayMatrix(start_x, start_y, size_x, size_y, rotate); 923 CFX_PointF pos = page2device.Transform( 924 CFX_PointF(static_cast<FX_FLOAT>(page_x), static_cast<FX_FLOAT>(page_y))); 925 926 *device_x = FXSYS_round(pos.x); 927 *device_y = FXSYS_round(pos.y); 928#endif // PDF_ENABLE_XFA 929} 930 931DLLEXPORT FPDF_BITMAP STDCALL FPDFBitmap_Create(int width, 932 int height, 933 int alpha) { 934 auto pBitmap = pdfium::MakeUnique<CFX_DIBitmap>(); 935 if (!pBitmap->Create(width, height, alpha ? FXDIB_Argb : FXDIB_Rgb32)) 936 return nullptr; 937 938 return pBitmap.release(); 939} 940 941DLLEXPORT FPDF_BITMAP STDCALL FPDFBitmap_CreateEx(int width, 942 int height, 943 int format, 944 void* first_scan, 945 int stride) { 946 FXDIB_Format fx_format; 947 switch (format) { 948 case FPDFBitmap_Gray: 949 fx_format = FXDIB_8bppRgb; 950 break; 951 case FPDFBitmap_BGR: 952 fx_format = FXDIB_Rgb; 953 break; 954 case FPDFBitmap_BGRx: 955 fx_format = FXDIB_Rgb32; 956 break; 957 case FPDFBitmap_BGRA: 958 fx_format = FXDIB_Argb; 959 break; 960 default: 961 return nullptr; 962 } 963 CFX_DIBitmap* pBitmap = new CFX_DIBitmap; 964 pBitmap->Create(width, height, fx_format, (uint8_t*)first_scan, stride); 965 return pBitmap; 966} 967 968DLLEXPORT void STDCALL FPDFBitmap_FillRect(FPDF_BITMAP bitmap, 969 int left, 970 int top, 971 int width, 972 int height, 973 FPDF_DWORD color) { 974 if (!bitmap) 975 return; 976 977 CFX_FxgeDevice device; 978 CFX_DIBitmap* pBitmap = CFXBitmapFromFPDFBitmap(bitmap); 979 device.Attach(pBitmap, false, nullptr, false); 980 if (!pBitmap->HasAlpha()) 981 color |= 0xFF000000; 982 FX_RECT rect(left, top, left + width, top + height); 983 device.FillRect(&rect, color); 984} 985 986DLLEXPORT void* STDCALL FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap) { 987 return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetBuffer() : nullptr; 988} 989 990DLLEXPORT int STDCALL FPDFBitmap_GetWidth(FPDF_BITMAP bitmap) { 991 return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetWidth() : 0; 992} 993 994DLLEXPORT int STDCALL FPDFBitmap_GetHeight(FPDF_BITMAP bitmap) { 995 return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetHeight() : 0; 996} 997 998DLLEXPORT int STDCALL FPDFBitmap_GetStride(FPDF_BITMAP bitmap) { 999 return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetPitch() : 0; 1000} 1001 1002DLLEXPORT void STDCALL FPDFBitmap_Destroy(FPDF_BITMAP bitmap) { 1003 delete CFXBitmapFromFPDFBitmap(bitmap); 1004} 1005 1006void FPDF_RenderPage_Retail(CPDF_PageRenderContext* pContext, 1007 FPDF_PAGE page, 1008 int start_x, 1009 int start_y, 1010 int size_x, 1011 int size_y, 1012 int rotate, 1013 int flags, 1014 bool bNeedToRestore, 1015 IFSDK_PAUSE_Adapter* pause) { 1016 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 1017 if (!pPage) 1018 return; 1019 1020 RenderPageImpl(pContext, pPage, pPage->GetDisplayMatrix( 1021 start_x, start_y, size_x, size_y, rotate), 1022 FX_RECT(start_x, start_y, start_x + size_x, start_y + size_y), 1023 flags, bNeedToRestore, pause); 1024} 1025 1026DLLEXPORT int STDCALL FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document, 1027 int page_index, 1028 double* width, 1029 double* height) { 1030 UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document); 1031 if (!pDoc) 1032 return false; 1033 1034#ifdef PDF_ENABLE_XFA 1035 int count = pDoc->GetPageCount(); 1036 if (page_index < 0 || page_index >= count) 1037 return false; 1038 CPDFXFA_Page* pPage = pDoc->GetXFAPage(page_index); 1039 if (!pPage) 1040 return false; 1041 *width = pPage->GetPageWidth(); 1042 *height = pPage->GetPageHeight(); 1043#else // PDF_ENABLE_XFA 1044 CPDF_Dictionary* pDict = pDoc->GetPage(page_index); 1045 if (!pDict) 1046 return false; 1047 1048 CPDF_Page page(pDoc, pDict, true); 1049 *width = page.GetPageWidth(); 1050 *height = page.GetPageHeight(); 1051#endif // PDF_ENABLE_XFA 1052 1053 return true; 1054} 1055 1056DLLEXPORT FPDF_BOOL STDCALL 1057FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document) { 1058 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1059 if (!pDoc) 1060 return true; 1061 CPDF_ViewerPreferences viewRef(pDoc); 1062 return viewRef.PrintScaling(); 1063} 1064 1065DLLEXPORT int STDCALL FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document) { 1066 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1067 if (!pDoc) 1068 return 1; 1069 CPDF_ViewerPreferences viewRef(pDoc); 1070 return viewRef.NumCopies(); 1071} 1072 1073DLLEXPORT FPDF_PAGERANGE STDCALL 1074FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document) { 1075 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1076 if (!pDoc) 1077 return nullptr; 1078 CPDF_ViewerPreferences viewRef(pDoc); 1079 return viewRef.PrintPageRange(); 1080} 1081 1082DLLEXPORT FPDF_DUPLEXTYPE STDCALL 1083FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document) { 1084 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1085 if (!pDoc) 1086 return DuplexUndefined; 1087 CPDF_ViewerPreferences viewRef(pDoc); 1088 CFX_ByteString duplex = viewRef.Duplex(); 1089 if ("Simplex" == duplex) 1090 return Simplex; 1091 if ("DuplexFlipShortEdge" == duplex) 1092 return DuplexFlipShortEdge; 1093 if ("DuplexFlipLongEdge" == duplex) 1094 return DuplexFlipLongEdge; 1095 return DuplexUndefined; 1096} 1097 1098DLLEXPORT unsigned long STDCALL FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document, 1099 FPDF_BYTESTRING key, 1100 char* buffer, 1101 unsigned long length) { 1102 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1103 if (!pDoc) 1104 return 0; 1105 1106 CPDF_ViewerPreferences viewRef(pDoc); 1107 CFX_ByteString bsVal; 1108 if (!viewRef.GenericName(key, &bsVal)) 1109 return 0; 1110 1111 unsigned long dwStringLen = bsVal.GetLength() + 1; 1112 if (buffer && length >= dwStringLen) 1113 memcpy(buffer, bsVal.c_str(), dwStringLen); 1114 return dwStringLen; 1115} 1116 1117DLLEXPORT FPDF_DWORD STDCALL FPDF_CountNamedDests(FPDF_DOCUMENT document) { 1118 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1119 if (!pDoc) 1120 return 0; 1121 1122 CPDF_Dictionary* pRoot = pDoc->GetRoot(); 1123 if (!pRoot) 1124 return 0; 1125 1126 CPDF_NameTree nameTree(pDoc, "Dests"); 1127 pdfium::base::CheckedNumeric<FPDF_DWORD> count = nameTree.GetCount(); 1128 CPDF_Dictionary* pDest = pRoot->GetDictFor("Dests"); 1129 if (pDest) 1130 count += pDest->GetCount(); 1131 1132 if (!count.IsValid()) 1133 return 0; 1134 1135 return count.ValueOrDie(); 1136} 1137 1138DLLEXPORT FPDF_DEST STDCALL FPDF_GetNamedDestByName(FPDF_DOCUMENT document, 1139 FPDF_BYTESTRING name) { 1140 if (!name || name[0] == 0) 1141 return nullptr; 1142 1143 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1144 if (!pDoc) 1145 return nullptr; 1146 1147 CPDF_NameTree name_tree(pDoc, "Dests"); 1148 return name_tree.LookupNamedDest(pDoc, name); 1149} 1150 1151#ifdef PDF_ENABLE_XFA 1152DLLEXPORT FPDF_RESULT STDCALL FPDF_BStr_Init(FPDF_BSTR* str) { 1153 if (!str) 1154 return -1; 1155 1156 FXSYS_memset(str, 0, sizeof(FPDF_BSTR)); 1157 return 0; 1158} 1159 1160DLLEXPORT FPDF_RESULT STDCALL FPDF_BStr_Set(FPDF_BSTR* str, 1161 FPDF_LPCSTR bstr, 1162 int length) { 1163 if (!str) 1164 return -1; 1165 if (!bstr || !length) 1166 return -1; 1167 if (length == -1) 1168 length = FXSYS_strlen(bstr); 1169 1170 if (length == 0) { 1171 if (str->str) { 1172 FX_Free(str->str); 1173 str->str = nullptr; 1174 } 1175 str->len = 0; 1176 return 0; 1177 } 1178 1179 if (str->str && str->len < length) 1180 str->str = FX_Realloc(char, str->str, length + 1); 1181 else if (!str->str) 1182 str->str = FX_Alloc(char, length + 1); 1183 1184 str->str[length] = 0; 1185 FXSYS_memcpy(str->str, bstr, length); 1186 str->len = length; 1187 1188 return 0; 1189} 1190 1191DLLEXPORT FPDF_RESULT STDCALL FPDF_BStr_Clear(FPDF_BSTR* str) { 1192 if (!str) 1193 return -1; 1194 1195 if (str->str) { 1196 FX_Free(str->str); 1197 str->str = nullptr; 1198 } 1199 str->len = 0; 1200 return 0; 1201} 1202#endif // PDF_ENABLE_XFA 1203 1204DLLEXPORT FPDF_DEST STDCALL FPDF_GetNamedDest(FPDF_DOCUMENT document, 1205 int index, 1206 void* buffer, 1207 long* buflen) { 1208 if (!buffer) 1209 *buflen = 0; 1210 1211 if (index < 0) 1212 return nullptr; 1213 1214 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); 1215 if (!pDoc) 1216 return nullptr; 1217 1218 CPDF_Dictionary* pRoot = pDoc->GetRoot(); 1219 if (!pRoot) 1220 return nullptr; 1221 1222 CPDF_Object* pDestObj = nullptr; 1223 CFX_ByteString bsName; 1224 CPDF_NameTree nameTree(pDoc, "Dests"); 1225 int count = nameTree.GetCount(); 1226 if (index >= count) { 1227 CPDF_Dictionary* pDest = pRoot->GetDictFor("Dests"); 1228 if (!pDest) 1229 return nullptr; 1230 1231 pdfium::base::CheckedNumeric<int> checked_count = count; 1232 checked_count += pDest->GetCount(); 1233 if (!checked_count.IsValid() || index >= checked_count.ValueOrDie()) 1234 return nullptr; 1235 1236 index -= count; 1237 int i = 0; 1238 for (const auto& it : *pDest) { 1239 bsName = it.first; 1240 pDestObj = it.second.get(); 1241 if (!pDestObj) 1242 continue; 1243 if (i == index) 1244 break; 1245 i++; 1246 } 1247 } else { 1248 pDestObj = nameTree.LookupValue(index, bsName); 1249 } 1250 if (!pDestObj) 1251 return nullptr; 1252 if (CPDF_Dictionary* pDict = pDestObj->AsDictionary()) { 1253 pDestObj = pDict->GetArrayFor("D"); 1254 if (!pDestObj) 1255 return nullptr; 1256 } 1257 if (!pDestObj->IsArray()) 1258 return nullptr; 1259 1260 CFX_WideString wsName = PDF_DecodeText(bsName); 1261 CFX_ByteString utf16Name = wsName.UTF16LE_Encode(); 1262 int len = utf16Name.GetLength(); 1263 if (!buffer) { 1264 *buflen = len; 1265 } else if (len <= *buflen) { 1266 memcpy(buffer, utf16Name.c_str(), len); 1267 *buflen = len; 1268 } else { 1269 *buflen = -1; 1270 } 1271 return (FPDF_DEST)pDestObj; 1272} 1273