1 // Copyright 2018 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 "fpdfsdk/cpdfsdk_helpers.h"
8
9 #include "build/build_config.h"
10 #include "constants/form_fields.h"
11 #include "constants/stream_dict_common.h"
12 #include "core/fpdfapi/page/cpdf_page.h"
13 #include "core/fpdfapi/parser/cpdf_array.h"
14 #include "core/fpdfapi/parser/cpdf_dictionary.h"
15 #include "core/fpdfapi/parser/cpdf_document.h"
16 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
17 #include "core/fpdfdoc/cpdf_annot.h"
18 #include "core/fpdfdoc/cpdf_interactiveform.h"
19 #include "core/fpdfdoc/cpdf_metadata.h"
20 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
21
22 namespace {
23
24 constexpr char kQuadPoints[] = "QuadPoints";
25
26 // 0 bit: FPDF_POLICY_MACHINETIME_ACCESS
27 uint32_t g_sandbox_policy = 0xFFFFFFFF;
28
29 UNSUPPORT_INFO* g_unsupport_info = nullptr;
30
RaiseUnsupportedError(int nError)31 bool RaiseUnsupportedError(int nError) {
32 if (!g_unsupport_info)
33 return false;
34
35 if (g_unsupport_info->FSDK_UnSupport_Handler)
36 g_unsupport_info->FSDK_UnSupport_Handler(g_unsupport_info, nError);
37 return true;
38 }
39
GetStreamMaybeCopyAndReturnLengthImpl(const CPDF_Stream * stream,void * buffer,unsigned long buflen,bool decode)40 unsigned long GetStreamMaybeCopyAndReturnLengthImpl(const CPDF_Stream* stream,
41 void* buffer,
42 unsigned long buflen,
43 bool decode) {
44 ASSERT(stream);
45 auto stream_acc = pdfium::MakeRetain<CPDF_StreamAcc>(stream);
46
47 if (decode)
48 stream_acc->LoadAllDataFiltered();
49 else
50 stream_acc->LoadAllDataRaw();
51
52 const auto stream_data_size = stream_acc->GetSize();
53 if (!buffer || buflen < stream_data_size)
54 return stream_data_size;
55
56 memcpy(buffer, stream_acc->GetData(), stream_data_size);
57 return stream_data_size;
58 }
59
60 #ifdef PDF_ENABLE_XFA
61 class FPDF_FileHandlerContext final : public IFX_SeekableStream {
62 public:
63 template <typename T, typename... Args>
64 friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
65
66 // IFX_SeekableStream:
67 FX_FILESIZE GetSize() override;
68 bool IsEOF() override;
69 FX_FILESIZE GetPosition() override;
70 bool ReadBlockAtOffset(void* buffer,
71 FX_FILESIZE offset,
72 size_t size) override;
73 size_t ReadBlock(void* buffer, size_t size) override;
74 bool WriteBlockAtOffset(const void* buffer,
75 FX_FILESIZE offset,
76 size_t size) override;
77 bool Flush() override;
78
SetPosition(FX_FILESIZE pos)79 void SetPosition(FX_FILESIZE pos) { m_nCurPos = pos; }
80
81 private:
82 explicit FPDF_FileHandlerContext(FPDF_FILEHANDLER* pFS);
83 ~FPDF_FileHandlerContext() override;
84
85 FPDF_FILEHANDLER* m_pFS;
86 FX_FILESIZE m_nCurPos;
87 };
88
FPDF_FileHandlerContext(FPDF_FILEHANDLER * pFS)89 FPDF_FileHandlerContext::FPDF_FileHandlerContext(FPDF_FILEHANDLER* pFS) {
90 m_pFS = pFS;
91 m_nCurPos = 0;
92 }
93
~FPDF_FileHandlerContext()94 FPDF_FileHandlerContext::~FPDF_FileHandlerContext() {
95 if (m_pFS && m_pFS->Release)
96 m_pFS->Release(m_pFS->clientData);
97 }
98
GetSize()99 FX_FILESIZE FPDF_FileHandlerContext::GetSize() {
100 if (m_pFS && m_pFS->GetSize)
101 return (FX_FILESIZE)m_pFS->GetSize(m_pFS->clientData);
102 return 0;
103 }
104
IsEOF()105 bool FPDF_FileHandlerContext::IsEOF() {
106 return m_nCurPos >= GetSize();
107 }
108
GetPosition()109 FX_FILESIZE FPDF_FileHandlerContext::GetPosition() {
110 return m_nCurPos;
111 }
112
ReadBlockAtOffset(void * buffer,FX_FILESIZE offset,size_t size)113 bool FPDF_FileHandlerContext::ReadBlockAtOffset(void* buffer,
114 FX_FILESIZE offset,
115 size_t size) {
116 if (!buffer || !size || !m_pFS->ReadBlock)
117 return false;
118
119 if (m_pFS->ReadBlock(m_pFS->clientData, (FPDF_DWORD)offset, buffer,
120 (FPDF_DWORD)size) == 0) {
121 m_nCurPos = offset + size;
122 return true;
123 }
124 return false;
125 }
126
ReadBlock(void * buffer,size_t size)127 size_t FPDF_FileHandlerContext::ReadBlock(void* buffer, size_t size) {
128 if (!buffer || !size || !m_pFS->ReadBlock)
129 return 0;
130
131 FX_FILESIZE nSize = GetSize();
132 if (m_nCurPos >= nSize)
133 return 0;
134 FX_FILESIZE dwAvail = nSize - m_nCurPos;
135 if (dwAvail < (FX_FILESIZE)size)
136 size = static_cast<size_t>(dwAvail);
137 if (m_pFS->ReadBlock(m_pFS->clientData, (FPDF_DWORD)m_nCurPos, buffer,
138 (FPDF_DWORD)size) == 0) {
139 m_nCurPos += size;
140 return size;
141 }
142
143 return 0;
144 }
145
WriteBlockAtOffset(const void * buffer,FX_FILESIZE offset,size_t size)146 bool FPDF_FileHandlerContext::WriteBlockAtOffset(const void* buffer,
147 FX_FILESIZE offset,
148 size_t size) {
149 if (!m_pFS || !m_pFS->WriteBlock)
150 return false;
151
152 if (m_pFS->WriteBlock(m_pFS->clientData, (FPDF_DWORD)offset, buffer,
153 (FPDF_DWORD)size) == 0) {
154 m_nCurPos = offset + size;
155 return true;
156 }
157 return false;
158 }
159
Flush()160 bool FPDF_FileHandlerContext::Flush() {
161 if (!m_pFS || !m_pFS->Flush)
162 return true;
163
164 return m_pFS->Flush(m_pFS->clientData) == 0;
165 }
166 #endif // PDF_ENABLE_XFA
167
168 } // namespace
169
IPDFPageFromFPDFPage(FPDF_PAGE page)170 IPDF_Page* IPDFPageFromFPDFPage(FPDF_PAGE page) {
171 return reinterpret_cast<IPDF_Page*>(page);
172 }
173
FPDFPageFromIPDFPage(IPDF_Page * page)174 FPDF_PAGE FPDFPageFromIPDFPage(IPDF_Page* page) {
175 return reinterpret_cast<FPDF_PAGE>(page);
176 }
177
CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc)178 CPDF_Document* CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc) {
179 return reinterpret_cast<CPDF_Document*>(doc);
180 }
181
FPDFDocumentFromCPDFDocument(CPDF_Document * doc)182 FPDF_DOCUMENT FPDFDocumentFromCPDFDocument(CPDF_Document* doc) {
183 return reinterpret_cast<FPDF_DOCUMENT>(doc);
184 }
185
CPDFPageFromFPDFPage(FPDF_PAGE page)186 CPDF_Page* CPDFPageFromFPDFPage(FPDF_PAGE page) {
187 return page ? IPDFPageFromFPDFPage(page)->AsPDFPage() : nullptr;
188 }
189
FormHandleToInteractiveForm(FPDF_FORMHANDLE hHandle)190 CPDFSDK_InteractiveForm* FormHandleToInteractiveForm(FPDF_FORMHANDLE hHandle) {
191 CPDFSDK_FormFillEnvironment* pFormFillEnv =
192 CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle);
193 return pFormFillEnv ? pFormFillEnv->GetInteractiveForm() : nullptr;
194 }
195
ByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string)196 ByteString ByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string) {
197 return WideStringFromFPDFWideString(wide_string).ToUTF8();
198 }
199
WideStringFromFPDFWideString(FPDF_WIDESTRING wide_string)200 WideString WideStringFromFPDFWideString(FPDF_WIDESTRING wide_string) {
201 return WideString::FromUTF16LE(wide_string,
202 WideString::WStringLength(wide_string));
203 }
204
205 #ifdef PDF_ENABLE_XFA
MakeSeekableStream(FPDF_FILEHANDLER * pFilehandler)206 RetainPtr<IFX_SeekableStream> MakeSeekableStream(
207 FPDF_FILEHANDLER* pFilehandler) {
208 return pdfium::MakeRetain<FPDF_FileHandlerContext>(pFilehandler);
209 }
210 #endif // PDF_ENABLE_XFA
211
GetQuadPointsArrayFromDictionary(const CPDF_Dictionary * dict)212 const CPDF_Array* GetQuadPointsArrayFromDictionary(
213 const CPDF_Dictionary* dict) {
214 return dict->GetArrayFor("QuadPoints");
215 }
216
GetQuadPointsArrayFromDictionary(CPDF_Dictionary * dict)217 CPDF_Array* GetQuadPointsArrayFromDictionary(CPDF_Dictionary* dict) {
218 return dict->GetArrayFor("QuadPoints");
219 }
220
AddQuadPointsArrayToDictionary(CPDF_Dictionary * dict)221 CPDF_Array* AddQuadPointsArrayToDictionary(CPDF_Dictionary* dict) {
222 return dict->SetNewFor<CPDF_Array>(kQuadPoints);
223 }
224
IsValidQuadPointsIndex(const CPDF_Array * array,size_t index)225 bool IsValidQuadPointsIndex(const CPDF_Array* array, size_t index) {
226 return array && index < array->size() / 8;
227 }
228
GetQuadPointsAtIndex(const CPDF_Array * array,size_t quad_index,FS_QUADPOINTSF * quad_points)229 bool GetQuadPointsAtIndex(const CPDF_Array* array,
230 size_t quad_index,
231 FS_QUADPOINTSF* quad_points) {
232 ASSERT(quad_points);
233 ASSERT(array);
234
235 if (!IsValidQuadPointsIndex(array, quad_index))
236 return false;
237
238 quad_index *= 8;
239 quad_points->x1 = array->GetNumberAt(quad_index);
240 quad_points->y1 = array->GetNumberAt(quad_index + 1);
241 quad_points->x2 = array->GetNumberAt(quad_index + 2);
242 quad_points->y2 = array->GetNumberAt(quad_index + 3);
243 quad_points->x3 = array->GetNumberAt(quad_index + 4);
244 quad_points->y3 = array->GetNumberAt(quad_index + 5);
245 quad_points->x4 = array->GetNumberAt(quad_index + 6);
246 quad_points->y4 = array->GetNumberAt(quad_index + 7);
247 return true;
248 }
249
CFXPointFFromFSPointF(const FS_POINTF & point)250 CFX_PointF CFXPointFFromFSPointF(const FS_POINTF& point) {
251 return CFX_PointF(point.x, point.y);
252 }
253
CFXFloatRectFromFSRectF(const FS_RECTF & rect)254 CFX_FloatRect CFXFloatRectFromFSRectF(const FS_RECTF& rect) {
255 return CFX_FloatRect(rect.left, rect.bottom, rect.right, rect.top);
256 }
257
FSRectFFromCFXFloatRect(const CFX_FloatRect & rect)258 FS_RECTF FSRectFFromCFXFloatRect(const CFX_FloatRect& rect) {
259 return {rect.left, rect.top, rect.right, rect.bottom};
260 }
261
CFXMatrixFromFSMatrix(const FS_MATRIX & matrix)262 CFX_Matrix CFXMatrixFromFSMatrix(const FS_MATRIX& matrix) {
263 return CFX_Matrix(matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f);
264 }
265
FSMatrixFromCFXMatrix(const CFX_Matrix & matrix)266 FS_MATRIX FSMatrixFromCFXMatrix(const CFX_Matrix& matrix) {
267 return {matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f};
268 }
269
Utf16EncodeMaybeCopyAndReturnLength(const WideString & text,void * buffer,unsigned long buflen)270 unsigned long Utf16EncodeMaybeCopyAndReturnLength(const WideString& text,
271 void* buffer,
272 unsigned long buflen) {
273 ByteString encoded_text = text.ToUTF16LE();
274 unsigned long len = encoded_text.GetLength();
275 if (buffer && len <= buflen)
276 memcpy(buffer, encoded_text.c_str(), len);
277 return len;
278 }
279
GetRawStreamMaybeCopyAndReturnLength(const CPDF_Stream * stream,void * buffer,unsigned long buflen)280 unsigned long GetRawStreamMaybeCopyAndReturnLength(const CPDF_Stream* stream,
281 void* buffer,
282 unsigned long buflen) {
283 return GetStreamMaybeCopyAndReturnLengthImpl(stream, buffer, buflen,
284 /*decode=*/false);
285 }
286
DecodeStreamMaybeCopyAndReturnLength(const CPDF_Stream * stream,void * buffer,unsigned long buflen)287 unsigned long DecodeStreamMaybeCopyAndReturnLength(const CPDF_Stream* stream,
288 void* buffer,
289 unsigned long buflen) {
290 return GetStreamMaybeCopyAndReturnLengthImpl(stream, buffer, buflen,
291 /*decode=*/true);
292 }
293
SetPDFSandboxPolicy(FPDF_DWORD policy,FPDF_BOOL enable)294 void SetPDFSandboxPolicy(FPDF_DWORD policy, FPDF_BOOL enable) {
295 switch (policy) {
296 case FPDF_POLICY_MACHINETIME_ACCESS: {
297 uint32_t mask = 1 << policy;
298 if (enable)
299 g_sandbox_policy |= mask;
300 else
301 g_sandbox_policy &= ~mask;
302 } break;
303 default:
304 break;
305 }
306 }
307
IsPDFSandboxPolicyEnabled(FPDF_DWORD policy)308 FPDF_BOOL IsPDFSandboxPolicyEnabled(FPDF_DWORD policy) {
309 switch (policy) {
310 case FPDF_POLICY_MACHINETIME_ACCESS: {
311 uint32_t mask = 1 << policy;
312 return !!(g_sandbox_policy & mask);
313 }
314 default:
315 return false;
316 }
317 }
318
SetPDFUnsupportInfo(UNSUPPORT_INFO * unsp_info)319 void SetPDFUnsupportInfo(UNSUPPORT_INFO* unsp_info) {
320 g_unsupport_info = unsp_info;
321 }
322
GetPDFUnssuportInto()323 UNSUPPORT_INFO* GetPDFUnssuportInto() {
324 return g_unsupport_info;
325 }
326
ReportUnsupportedFeatures(CPDF_Document * pDoc)327 void ReportUnsupportedFeatures(CPDF_Document* pDoc) {
328 const CPDF_Dictionary* pRootDict = pDoc->GetRoot();
329 if (pRootDict) {
330 // Portfolios and Packages
331 if (pRootDict->KeyExist("Collection")) {
332 RaiseUnsupportedError(FPDF_UNSP_DOC_PORTABLECOLLECTION);
333 return;
334 }
335 if (pRootDict->KeyExist("Names")) {
336 const CPDF_Dictionary* pNameDict = pRootDict->GetDictFor("Names");
337 if (pNameDict && pNameDict->KeyExist("EmbeddedFiles")) {
338 RaiseUnsupportedError(FPDF_UNSP_DOC_ATTACHMENT);
339 return;
340 }
341 if (pNameDict && pNameDict->KeyExist("JavaScript")) {
342 const CPDF_Dictionary* pJSDict = pNameDict->GetDictFor("JavaScript");
343 const CPDF_Array* pArray =
344 pJSDict ? pJSDict->GetArrayFor("Names") : nullptr;
345 if (pArray) {
346 for (size_t i = 0; i < pArray->size(); i++) {
347 ByteString cbStr = pArray->GetStringAt(i);
348 if (cbStr.Compare("com.adobe.acrobat.SharedReview.Register") == 0) {
349 RaiseUnsupportedError(FPDF_UNSP_DOC_SHAREDREVIEW);
350 return;
351 }
352 }
353 }
354 }
355 }
356
357 // SharedForm
358 const CPDF_Stream* pStream = pRootDict->GetStreamFor("Metadata");
359 if (pStream) {
360 CPDF_Metadata metaData(pStream);
361 for (const auto& err : metaData.CheckForSharedForm())
362 RaiseUnsupportedError(static_cast<int>(err));
363 }
364 }
365 }
366
ReportUnsupportedXFA(CPDF_Document * pDoc)367 void ReportUnsupportedXFA(CPDF_Document* pDoc) {
368 // XFA Forms
369 if (!pDoc->GetExtension() && CPDF_InteractiveForm(pDoc).HasXFAForm())
370 RaiseUnsupportedError(FPDF_UNSP_DOC_XFAFORM);
371 }
372
CheckForUnsupportedAnnot(const CPDF_Annot * pAnnot)373 void CheckForUnsupportedAnnot(const CPDF_Annot* pAnnot) {
374 switch (pAnnot->GetSubtype()) {
375 case CPDF_Annot::Subtype::FILEATTACHMENT:
376 RaiseUnsupportedError(FPDF_UNSP_ANNOT_ATTACHMENT);
377 break;
378 case CPDF_Annot::Subtype::MOVIE:
379 RaiseUnsupportedError(FPDF_UNSP_ANNOT_MOVIE);
380 break;
381 case CPDF_Annot::Subtype::RICHMEDIA:
382 RaiseUnsupportedError(FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA);
383 break;
384 case CPDF_Annot::Subtype::SCREEN: {
385 const CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
386 ByteString cbString = pAnnotDict->GetStringFor("IT");
387 if (cbString != "Img")
388 RaiseUnsupportedError(FPDF_UNSP_ANNOT_SCREEN_MEDIA);
389 break;
390 }
391 case CPDF_Annot::Subtype::SOUND:
392 RaiseUnsupportedError(FPDF_UNSP_ANNOT_SOUND);
393 break;
394 case CPDF_Annot::Subtype::THREED:
395 RaiseUnsupportedError(FPDF_UNSP_ANNOT_3DANNOT);
396 break;
397 case CPDF_Annot::Subtype::WIDGET: {
398 const CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
399 ByteString cbString = pAnnotDict->GetStringFor(pdfium::form_fields::kFT);
400 if (cbString == pdfium::form_fields::kSig)
401 RaiseUnsupportedError(FPDF_UNSP_ANNOT_SIG);
402 break;
403 }
404 default:
405 break;
406 }
407 }
408
ProcessParseError(CPDF_Parser::Error err)409 void ProcessParseError(CPDF_Parser::Error err) {
410 uint32_t err_code = FPDF_ERR_SUCCESS;
411 // Translate FPDFAPI error code to FPDFVIEW error code
412 switch (err) {
413 case CPDF_Parser::SUCCESS:
414 err_code = FPDF_ERR_SUCCESS;
415 break;
416 case CPDF_Parser::FILE_ERROR:
417 err_code = FPDF_ERR_FILE;
418 break;
419 case CPDF_Parser::FORMAT_ERROR:
420 err_code = FPDF_ERR_FORMAT;
421 break;
422 case CPDF_Parser::PASSWORD_ERROR:
423 err_code = FPDF_ERR_PASSWORD;
424 break;
425 case CPDF_Parser::HANDLER_ERROR:
426 err_code = FPDF_ERR_SECURITY;
427 break;
428 }
429 FXSYS_SetLastError(err_code);
430 }
431