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