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