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