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