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
67 namespace {
68
69 // Also indicates whether library is currently initialized.
70 CCodec_ModuleMgr* g_pCodecModule = nullptr;
71
RenderPageImpl(CPDF_PageRenderContext * pContext,CPDF_Page * pPage,const CFX_Matrix & matrix,const FX_RECT & clipping_rect,int flags,bool bNeedToRestore,IFSDK_PAUSE_Adapter * pause)72 void 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
136 class CPDF_CustomAccess final : public IFX_SeekableReadStream {
137 public:
Create(FPDF_FILEACCESS * pFileAccess)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
CPDF_CustomAccess(FPDF_FILEACCESS * pFileAccess)152 CPDF_CustomAccess::CPDF_CustomAccess(FPDF_FILEACCESS* pFileAccess)
153 : m_FileAccess(*pFileAccess) {}
154
GetSize()155 FX_FILESIZE CPDF_CustomAccess::GetSize() {
156 return m_FileAccess.m_FileLen;
157 }
158
ReadBlock(void * buffer,FX_FILESIZE offset,size_t size)159 bool 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
176 class CFPDF_FileStream : public IFX_SeekableStream {
177 public:
Create(FPDF_FILEHANDLER * pFS)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
SetPosition(FX_FILESIZE pos)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
CFPDF_FileStream(FPDF_FILEHANDLER * pFS)201 CFPDF_FileStream::CFPDF_FileStream(FPDF_FILEHANDLER* pFS) {
202 m_pFS = pFS;
203 m_nCurPos = 0;
204 }
205
~CFPDF_FileStream()206 CFPDF_FileStream::~CFPDF_FileStream() {
207 if (m_pFS && m_pFS->Release)
208 m_pFS->Release(m_pFS->clientData);
209 }
210
GetSize()211 FX_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
IsEOF()217 bool CFPDF_FileStream::IsEOF() {
218 return m_nCurPos >= GetSize();
219 }
220
GetPosition()221 FX_FILESIZE CFPDF_FileStream::GetPosition() {
222 return m_nCurPos;
223 }
224
ReadBlock(void * buffer,FX_FILESIZE offset,size_t size)225 bool 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
ReadBlock(void * buffer,size_t size)239 size_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
WriteBlock(const void * buffer,FX_FILESIZE offset,size_t size)258 bool 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
Flush()272 bool 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
UnderlyingFromFPDFDocument(FPDF_DOCUMENT doc)282 UnderlyingDocumentType* UnderlyingFromFPDFDocument(FPDF_DOCUMENT doc) {
283 return static_cast<UnderlyingDocumentType*>(doc);
284 }
285
FPDFDocumentFromUnderlying(UnderlyingDocumentType * doc)286 FPDF_DOCUMENT FPDFDocumentFromUnderlying(UnderlyingDocumentType* doc) {
287 return static_cast<FPDF_DOCUMENT>(doc);
288 }
289
UnderlyingFromFPDFPage(FPDF_PAGE page)290 UnderlyingPageType* UnderlyingFromFPDFPage(FPDF_PAGE page) {
291 return static_cast<UnderlyingPageType*>(page);
292 }
293
CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc)294 CPDF_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
FPDFDocumentFromCPDFDocument(CPDF_Document * doc)302 FPDF_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
CPDFPageFromFPDFPage(FPDF_PAGE page)312 CPDF_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
CFXBitmapFromFPDFBitmap(FPDF_BITMAP bitmap)320 CFX_DIBitmap* CFXBitmapFromFPDFBitmap(FPDF_BITMAP bitmap) {
321 return static_cast<CFX_DIBitmap*>(bitmap);
322 }
323
MakeSeekableReadStream(FPDF_FILEACCESS * pFileAccess)324 CFX_RetainPtr<IFX_SeekableReadStream> MakeSeekableReadStream(
325 FPDF_FILEACCESS* pFileAccess) {
326 return CPDF_CustomAccess::Create(pFileAccess);
327 }
328
329 #ifdef PDF_ENABLE_XFA
MakeSeekableStream(FPDF_FILEHANDLER * pFilehandler)330 CFX_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
337 static uint32_t foxit_sandbox_policy = 0xFFFFFFFF;
338
FSDK_SetSandBoxPolicy(FPDF_DWORD policy,FPDF_BOOL enable)339 void 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
FSDK_IsSandBoxPolicyEnabled(FPDF_DWORD policy)352 FPDF_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
FPDF_InitLibrary()361 DLLEXPORT void STDCALL FPDF_InitLibrary() {
362 FPDF_InitLibraryWithConfig(nullptr);
363 }
364
365 DLLEXPORT void STDCALL
FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG * cfg)366 FPDF_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
FPDF_DestroyLibrary()411 DLLEXPORT 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
430 int g_LastError;
SetLastError(int err)431 void SetLastError(int err) {
432 g_LastError = err;
433 }
434
GetLastError()435 int GetLastError() {
436 return g_LastError;
437 }
438 #endif // _WIN32
439
ProcessParseError(CPDF_Parser::Error err)440 void 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
FPDF_SetSandBoxPolicy(FPDF_DWORD policy,FPDF_BOOL enable)463 DLLEXPORT 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)
470 DLLEXPORT void STDCALL
FPDF_SetTypefaceAccessibleFunc(PDFiumEnsureTypefaceCharactersAccessible func)471 FPDF_SetTypefaceAccessibleFunc(PDFiumEnsureTypefaceCharactersAccessible func) {
472 g_pdfium_typeface_accessible_func = func;
473 }
474
FPDF_SetPrintTextWithGDI(FPDF_BOOL use_gdi)475 DLLEXPORT 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
FPDF_SetPrintPostscriptLevel(int postscript_level)480 DLLEXPORT 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
FPDF_LoadDocument(FPDF_STRING file_path,FPDF_BYTESTRING password)488 DLLEXPORT 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
FPDF_HasXFAField(FPDF_DOCUMENT document,int * docType)511 DLLEXPORT 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
FPDF_LoadXFA(FPDF_DOCUMENT document)538 DLLEXPORT FPDF_BOOL STDCALL FPDF_LoadXFA(FPDF_DOCUMENT document) {
539 return document && (static_cast<CPDFXFA_Context*>(document))->LoadXFADoc();
540 }
541 #endif // PDF_ENABLE_XFA
542
543 class CMemFile final : public IFX_SeekableReadStream {
544 public:
Create(uint8_t * pBuf,FX_FILESIZE size)545 static CFX_RetainPtr<CMemFile> Create(uint8_t* pBuf, FX_FILESIZE size) {
546 return CFX_RetainPtr<CMemFile>(new CMemFile(pBuf, size));
547 }
548
GetSize()549 FX_FILESIZE GetSize() override { return m_size; }
ReadBlock(void * buffer,FX_FILESIZE offset,size_t 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:
CMemFile(uint8_t * pBuf,FX_FILESIZE size)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
FPDF_LoadMemDocument(const void * data_buf,int size,FPDF_BYTESTRING password)570 DLLEXPORT 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
588 DLLEXPORT FPDF_DOCUMENT STDCALL
FPDF_LoadCustomDocument(FPDF_FILEACCESS * pFileAccess,FPDF_BYTESTRING password)589 FPDF_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
FPDF_GetFileVersion(FPDF_DOCUMENT doc,int * fileVersion)607 DLLEXPORT 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).
FPDF_GetDocPermissions(FPDF_DOCUMENT document)627 DLLEXPORT 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
FPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document)641 DLLEXPORT 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
FPDF_GetPageCount(FPDF_DOCUMENT document)650 DLLEXPORT int STDCALL FPDF_GetPageCount(FPDF_DOCUMENT document) {
651 UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document);
652 return pDoc ? pDoc->GetPageCount() : 0;
653 }
654
FPDF_LoadPage(FPDF_DOCUMENT document,int page_index)655 DLLEXPORT 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
FPDF_GetPageWidth(FPDF_PAGE page)677 DLLEXPORT double STDCALL FPDF_GetPageWidth(FPDF_PAGE page) {
678 UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
679 return pPage ? pPage->GetPageWidth() : 0.0;
680 }
681
FPDF_GetPageHeight(FPDF_PAGE page)682 DLLEXPORT 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)
FPDF_RenderPage(HDC dc,FPDF_PAGE page,int start_x,int start_y,int size_x,int size_y,int rotate,int flags)688 DLLEXPORT 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
FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,FPDF_PAGE page,int start_x,int start_y,int size_x,int size_y,int rotate,int flags)742 DLLEXPORT 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
FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,FPDF_PAGE page,const FS_MATRIX * matrix,const FS_RECTF * clipping,int flags)774 DLLEXPORT 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_
FPDF_RenderPageSkp(FPDF_PAGE page,int size_x,int size_y)813 DLLEXPORT 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
FPDF_ClosePage(FPDF_PAGE page)832 DLLEXPORT 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
FPDF_CloseDocument(FPDF_DOCUMENT document)864 DLLEXPORT void STDCALL FPDF_CloseDocument(FPDF_DOCUMENT document) {
865 delete UnderlyingFromFPDFDocument(document);
866 }
867
FPDF_GetLastError()868 DLLEXPORT unsigned long STDCALL FPDF_GetLastError() {
869 return GetLastError();
870 }
871
FPDF_DeviceToPage(FPDF_PAGE page,int start_x,int start_y,int size_x,int size_y,int rotate,int device_x,int device_y,double * page_x,double * page_y)872 DLLEXPORT 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
FPDF_PageToDevice(FPDF_PAGE page,int start_x,int start_y,int size_x,int size_y,int rotate,double page_x,double page_y,int * device_x,int * device_y)902 DLLEXPORT 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
FPDFBitmap_Create(int width,int height,int alpha)931 DLLEXPORT 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
FPDFBitmap_CreateEx(int width,int height,int format,void * first_scan,int stride)941 DLLEXPORT 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
FPDFBitmap_FillRect(FPDF_BITMAP bitmap,int left,int top,int width,int height,FPDF_DWORD color)968 DLLEXPORT 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
FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap)986 DLLEXPORT void* STDCALL FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap) {
987 return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetBuffer() : nullptr;
988 }
989
FPDFBitmap_GetWidth(FPDF_BITMAP bitmap)990 DLLEXPORT int STDCALL FPDFBitmap_GetWidth(FPDF_BITMAP bitmap) {
991 return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetWidth() : 0;
992 }
993
FPDFBitmap_GetHeight(FPDF_BITMAP bitmap)994 DLLEXPORT int STDCALL FPDFBitmap_GetHeight(FPDF_BITMAP bitmap) {
995 return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetHeight() : 0;
996 }
997
FPDFBitmap_GetStride(FPDF_BITMAP bitmap)998 DLLEXPORT int STDCALL FPDFBitmap_GetStride(FPDF_BITMAP bitmap) {
999 return bitmap ? CFXBitmapFromFPDFBitmap(bitmap)->GetPitch() : 0;
1000 }
1001
FPDFBitmap_Destroy(FPDF_BITMAP bitmap)1002 DLLEXPORT void STDCALL FPDFBitmap_Destroy(FPDF_BITMAP bitmap) {
1003 delete CFXBitmapFromFPDFBitmap(bitmap);
1004 }
1005
FPDF_RenderPage_Retail(CPDF_PageRenderContext * pContext,FPDF_PAGE page,int start_x,int start_y,int size_x,int size_y,int rotate,int flags,bool bNeedToRestore,IFSDK_PAUSE_Adapter * pause)1006 void 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
FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,int page_index,double * width,double * height)1026 DLLEXPORT 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
1056 DLLEXPORT FPDF_BOOL STDCALL
FPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document)1057 FPDF_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
FPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document)1065 DLLEXPORT 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
1073 DLLEXPORT FPDF_PAGERANGE STDCALL
FPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document)1074 FPDF_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
1082 DLLEXPORT FPDF_DUPLEXTYPE STDCALL
FPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document)1083 FPDF_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
FPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,FPDF_BYTESTRING key,char * buffer,unsigned long length)1098 DLLEXPORT 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
FPDF_CountNamedDests(FPDF_DOCUMENT document)1117 DLLEXPORT 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
FPDF_GetNamedDestByName(FPDF_DOCUMENT document,FPDF_BYTESTRING name)1138 DLLEXPORT 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
FPDF_BStr_Init(FPDF_BSTR * str)1152 DLLEXPORT 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
FPDF_BStr_Set(FPDF_BSTR * str,FPDF_LPCSTR bstr,int length)1160 DLLEXPORT 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
FPDF_BStr_Clear(FPDF_BSTR * str)1191 DLLEXPORT 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
FPDF_GetNamedDest(FPDF_DOCUMENT document,int index,void * buffer,long * buflen)1204 DLLEXPORT 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