Home | History | Annotate | Download | only in src
      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 
     30 UnderlyingDocumentType* UnderlyingFromFPDFDocument(FPDF_DOCUMENT doc) {
     31   return static_cast<UnderlyingDocumentType*>(doc);
     32 }
     33 
     34 FPDF_DOCUMENT FPDFDocumentFromUnderlying(UnderlyingDocumentType* doc) {
     35   return static_cast<FPDF_DOCUMENT>(doc);
     36 }
     37 
     38 UnderlyingPageType* UnderlyingFromFPDFPage(FPDF_PAGE page) {
     39   return static_cast<UnderlyingPageType*>(page);
     40 }
     41 
     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 
     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 
     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
     69 CFPDF_FileStream::CFPDF_FileStream(FPDF_FILEHANDLER* pFS) {
     70   m_pFS = pFS;
     71   m_nCurPos = 0;
     72 }
     73 
     74 IFX_FileStream* CFPDF_FileStream::Retain() {
     75   return this;
     76 }
     77 
     78 void CFPDF_FileStream::Release() {
     79   if (m_pFS && m_pFS->Release)
     80     m_pFS->Release(m_pFS->clientData);
     81   delete this;
     82 }
     83 
     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 
     90 FX_BOOL CFPDF_FileStream::IsEOF() {
     91   return m_nCurPos >= GetSize();
     92 }
     93 
     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 
    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 
    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 
    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 
    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
    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 
    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 
    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 
    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 
    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 
    227 DLLEXPORT void STDCALL FPDF_InitLibrary() {
    228   FPDF_InitLibraryWithConfig(nullptr);
    229 }
    230 
    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 
    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;
    268 void SetLastError(int err) {
    269   g_LastError = err;
    270 }
    271 
    272 int GetLastError() {
    273   return g_LastError;
    274 }
    275 #endif  // _WIN32
    276 
    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 
    296 DLLEXPORT void STDCALL FPDF_SetSandBoxPolicy(FPDF_DWORD policy,
    297                                              FPDF_BOOL enable) {
    298   return FSDK_SetSandBoxPolicy(policy, enable);
    299 }
    300 
    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
    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 
    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:
    371   CMemFile(uint8_t* pBuf, FX_FILESIZE size) : m_pBuf(pBuf), m_size(size) {}
    372 
    373   void Release() override { delete this; }
    374   FX_FILESIZE GetSize() override { return m_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:
    390   ~CMemFile() override {}
    391 
    392   uint8_t* const m_pBuf;
    393   const FX_FILESIZE m_size;
    394 };
    395 
    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
    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 
    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).
    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 
    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 
    474 DLLEXPORT int STDCALL FPDF_GetPageCount(FPDF_DOCUMENT document) {
    475   UnderlyingDocumentType* pDoc = UnderlyingFromFPDFDocument(document);
    476   return pDoc ? pDoc->GetPageCount() : 0;
    477 }
    478 
    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 
    501 DLLEXPORT double STDCALL FPDF_GetPageWidth(FPDF_PAGE page) {
    502   UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
    503   return pPage ? pPage->GetPageWidth() : 0.0;
    504 }
    505 
    506 DLLEXPORT double STDCALL FPDF_GetPageHeight(FPDF_PAGE page) {
    507   UnderlyingPageType* pPage = UnderlyingFromFPDFPage(page);
    508   return pPage ? pPage->GetPageHeight() : 0.0;
    509 }
    510 
    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)
    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 
    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 
    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 
    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 
    754 DLLEXPORT unsigned long STDCALL FPDF_GetLastError() {
    755   return GetLastError();
    756 }
    757 
    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 
    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 
    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 
    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 
    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 
    875 DLLEXPORT void* STDCALL FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap) {
    876   return bitmap ? ((CFX_DIBitmap*)bitmap)->GetBuffer() : nullptr;
    877 }
    878 
    879 DLLEXPORT int STDCALL FPDFBitmap_GetWidth(FPDF_BITMAP bitmap) {
    880   return bitmap ? ((CFX_DIBitmap*)bitmap)->GetWidth() : 0;
    881 }
    882 
    883 DLLEXPORT int STDCALL FPDFBitmap_GetHeight(FPDF_BITMAP bitmap) {
    884   return bitmap ? ((CFX_DIBitmap*)bitmap)->GetHeight() : 0;
    885 }
    886 
    887 DLLEXPORT int STDCALL FPDFBitmap_GetStride(FPDF_BITMAP bitmap) {
    888   return bitmap ? ((CFX_DIBitmap*)bitmap)->GetPitch() : 0;
    889 }
    890 
    891 DLLEXPORT void STDCALL FPDFBitmap_Destroy(FPDF_BITMAP bitmap) {
    892   delete (CFX_DIBitmap*)bitmap;
    893 }
    894 
    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 
    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
   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 
   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
   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
   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 
   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 
   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
   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 
   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 
   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 
   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