• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The PDFium Authors
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 <utility>
10 
11 #include "build/build_config.h"
12 #include "constants/form_fields.h"
13 #include "constants/stream_dict_common.h"
14 #include "core/fpdfapi/page/cpdf_page.h"
15 #include "core/fpdfapi/parser/cpdf_array.h"
16 #include "core/fpdfapi/parser/cpdf_dictionary.h"
17 #include "core/fpdfapi/parser/cpdf_document.h"
18 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
19 #include "core/fpdfapi/render/cpdf_renderoptions.h"
20 #include "core/fpdfdoc/cpdf_annot.h"
21 #include "core/fpdfdoc/cpdf_interactiveform.h"
22 #include "core/fpdfdoc/cpdf_metadata.h"
23 #include "core/fxcrt/check.h"
24 #include "core/fxcrt/compiler_specific.h"
25 #include "core/fxcrt/fx_memcpy_wrappers.h"
26 #include "core/fxcrt/fx_safe_types.h"
27 #include "core/fxcrt/numerics/safe_conversions.h"
28 #include "core/fxcrt/span_util.h"
29 #include "core/fxcrt/stl_util.h"
30 #include "core/fxcrt/unowned_ptr.h"
31 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
32 
33 namespace {
34 
35 constexpr char kQuadPoints[] = "QuadPoints";
36 
37 // 0 bit: FPDF_POLICY_MACHINETIME_ACCESS
38 uint32_t g_sandbox_policy = 0xFFFFFFFF;
39 
40 UNSUPPORT_INFO* g_unsupport_info = nullptr;
41 
RaiseUnsupportedError(int nError)42 bool RaiseUnsupportedError(int nError) {
43   if (!g_unsupport_info)
44     return false;
45 
46   if (g_unsupport_info->FSDK_UnSupport_Handler)
47     g_unsupport_info->FSDK_UnSupport_Handler(g_unsupport_info, nError);
48   return true;
49 }
50 
51 // Use the existence of the XFA array as a signal for XFA forms.
DocHasXFA(const CPDF_Document * doc)52 bool DocHasXFA(const CPDF_Document* doc) {
53   const CPDF_Dictionary* root = doc->GetRoot();
54   if (!root)
55     return false;
56 
57   RetainPtr<const CPDF_Dictionary> form = root->GetDictFor("AcroForm");
58   return form && form->GetArrayFor("XFA");
59 }
60 
GetStreamMaybeCopyAndReturnLengthImpl(RetainPtr<const CPDF_Stream> stream,pdfium::span<uint8_t> buffer,bool decode)61 unsigned long GetStreamMaybeCopyAndReturnLengthImpl(
62     RetainPtr<const CPDF_Stream> stream,
63     pdfium::span<uint8_t> buffer,
64     bool decode) {
65   DCHECK(stream);
66   auto stream_acc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(stream));
67   if (decode)
68     stream_acc->LoadAllDataFiltered();
69   else
70     stream_acc->LoadAllDataRaw();
71 
72   pdfium::span<const uint8_t> stream_data_span = stream_acc->GetSpan();
73   if (!buffer.empty() && buffer.size() <= stream_data_span.size()) {
74     fxcrt::Copy(stream_data_span, buffer);
75   }
76   return pdfium::checked_cast<unsigned long>(stream_data_span.size());
77 }
78 
79 // TODO(tsepez): should be UNSAFE_BUFFER_USAGE.
FPDFWideStringLength(const unsigned short * str)80 size_t FPDFWideStringLength(const unsigned short* str) {
81   if (!str) {
82     return 0;
83   }
84   size_t len = 0;
85   // SAFETY: NUL-termination required from caller.
86   UNSAFE_BUFFERS({
87     while (str[len]) {
88       len++;
89     }
90   });
91   return len;
92 }
93 
94 #ifdef PDF_ENABLE_XFA
95 class FPDF_FileHandlerContext final : public IFX_SeekableStream {
96  public:
97   CONSTRUCT_VIA_MAKE_RETAIN;
98 
99   // IFX_SeekableStream:
100   FX_FILESIZE GetSize() override;
101   FX_FILESIZE GetPosition() override;
102   bool IsEOF() override;
103   bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
104                          FX_FILESIZE offset) override;
105   bool WriteBlock(pdfium::span<const uint8_t> buffer) override;
106   bool Flush() override;
107 
108  private:
109   explicit FPDF_FileHandlerContext(FPDF_FILEHANDLER* pFS);
110   ~FPDF_FileHandlerContext() override;
111 
112   UnownedPtr<FPDF_FILEHANDLER> const m_pFS;
113   FX_FILESIZE m_nCurPos = 0;
114 };
115 
FPDF_FileHandlerContext(FPDF_FILEHANDLER * pFS)116 FPDF_FileHandlerContext::FPDF_FileHandlerContext(FPDF_FILEHANDLER* pFS)
117     : m_pFS(pFS) {
118   CHECK(m_pFS);
119 }
120 
~FPDF_FileHandlerContext()121 FPDF_FileHandlerContext::~FPDF_FileHandlerContext() {
122   if (m_pFS->Release) {
123     m_pFS->Release(m_pFS->clientData);
124   }
125 }
126 
GetSize()127 FX_FILESIZE FPDF_FileHandlerContext::GetSize() {
128   if (m_pFS->GetSize) {
129     return static_cast<FX_FILESIZE>(m_pFS->GetSize(m_pFS->clientData));
130   }
131   return 0;
132 }
133 
IsEOF()134 bool FPDF_FileHandlerContext::IsEOF() {
135   return m_nCurPos >= GetSize();
136 }
137 
GetPosition()138 FX_FILESIZE FPDF_FileHandlerContext::GetPosition() {
139   return m_nCurPos;
140 }
141 
ReadBlockAtOffset(pdfium::span<uint8_t> buffer,FX_FILESIZE offset)142 bool FPDF_FileHandlerContext::ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
143                                                 FX_FILESIZE offset) {
144   if (buffer.empty() || !m_pFS->ReadBlock) {
145     return false;
146   }
147 
148   FX_SAFE_FILESIZE new_position = offset;
149   new_position += buffer.size();
150   if (!new_position.IsValid()) {
151     return false;
152   }
153 
154   if (m_pFS->ReadBlock(m_pFS->clientData, static_cast<FPDF_DWORD>(offset),
155                        buffer.data(),
156                        static_cast<FPDF_DWORD>(buffer.size())) != 0) {
157     return false;
158   }
159 
160   m_nCurPos = new_position.ValueOrDie();
161   return true;
162 }
163 
WriteBlock(pdfium::span<const uint8_t> buffer)164 bool FPDF_FileHandlerContext::WriteBlock(pdfium::span<const uint8_t> buffer) {
165   if (!m_pFS->WriteBlock) {
166     return false;
167   }
168 
169   const FX_FILESIZE size = GetSize();
170   FX_SAFE_FILESIZE new_position = size;
171   new_position += buffer.size();
172   if (!new_position.IsValid()) {
173     return false;
174   }
175 
176   if (m_pFS->WriteBlock(m_pFS->clientData, static_cast<FPDF_DWORD>(size),
177                         buffer.data(),
178                         static_cast<FPDF_DWORD>(buffer.size())) != 0) {
179     return false;
180   }
181 
182   m_nCurPos = new_position.ValueOrDie();
183   return true;
184 }
185 
Flush()186 bool FPDF_FileHandlerContext::Flush() {
187   if (!m_pFS->Flush) {
188     return true;
189   }
190 
191   return m_pFS->Flush(m_pFS->clientData) == 0;
192 }
193 #endif  // PDF_ENABLE_XFA
194 
195 }  // namespace
196 
IPDFPageFromFPDFPage(FPDF_PAGE page)197 IPDF_Page* IPDFPageFromFPDFPage(FPDF_PAGE page) {
198   return reinterpret_cast<IPDF_Page*>(page);
199 }
200 
FPDFPageFromIPDFPage(IPDF_Page * page)201 FPDF_PAGE FPDFPageFromIPDFPage(IPDF_Page* page) {
202   return reinterpret_cast<FPDF_PAGE>(page);
203 }
204 
CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc)205 CPDF_Document* CPDFDocumentFromFPDFDocument(FPDF_DOCUMENT doc) {
206   return reinterpret_cast<CPDF_Document*>(doc);
207 }
208 
FPDFDocumentFromCPDFDocument(CPDF_Document * doc)209 FPDF_DOCUMENT FPDFDocumentFromCPDFDocument(CPDF_Document* doc) {
210   return reinterpret_cast<FPDF_DOCUMENT>(doc);
211 }
212 
CPDFPageFromFPDFPage(FPDF_PAGE page)213 CPDF_Page* CPDFPageFromFPDFPage(FPDF_PAGE page) {
214   return page ? IPDFPageFromFPDFPage(page)->AsPDFPage() : nullptr;
215 }
216 
FXDIBFormatFromFPDFFormat(int format)217 FXDIB_Format FXDIBFormatFromFPDFFormat(int format) {
218   switch (format) {
219     case FPDFBitmap_Gray:
220       return FXDIB_Format::k8bppRgb;
221     case FPDFBitmap_BGR:
222       return FXDIB_Format::kBgr;
223     case FPDFBitmap_BGRx:
224       return FXDIB_Format::kBgrx;
225     case FPDFBitmap_BGRA:
226       return FXDIB_Format::kBgra;
227     default:
228       return FXDIB_Format::kInvalid;
229   }
230 }
231 
FormHandleToInteractiveForm(FPDF_FORMHANDLE hHandle)232 CPDFSDK_InteractiveForm* FormHandleToInteractiveForm(FPDF_FORMHANDLE hHandle) {
233   CPDFSDK_FormFillEnvironment* pFormFillEnv =
234       CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle);
235   return pFormFillEnv ? pFormFillEnv->GetInteractiveForm() : nullptr;
236 }
237 
ByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string)238 ByteString ByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string) {
239   // SAFETY: caller ensures `wide_string` is NUL-terminated and enforced
240   // by UNSAFE_BUFFER_USAGE in header file.
241   return UNSAFE_BUFFERS(WideStringFromFPDFWideString(wide_string).ToUTF8());
242 }
243 
WideStringFromFPDFWideString(FPDF_WIDESTRING wide_string)244 WideString WideStringFromFPDFWideString(FPDF_WIDESTRING wide_string) {
245   // SAFETY: caller ensures `wide_string` is NUL-terminated and enforced
246   // by UNSAFE_BUFFER_USAGE in header file.
247   return WideString::FromUTF16LE(UNSAFE_BUFFERS(
248       pdfium::make_span(reinterpret_cast<const uint8_t*>(wide_string),
249                         FPDFWideStringLength(wide_string) * 2)));
250 }
251 
SpanFromFPDFApiArgs(void * buffer,pdfium::StrictNumeric<size_t> buflen)252 UNSAFE_BUFFER_USAGE pdfium::span<char> SpanFromFPDFApiArgs(
253     void* buffer,
254     pdfium::StrictNumeric<size_t> buflen) {
255   if (!buffer) {
256     // API convention is to ignore `buflen` arg when `buffer` is NULL.
257     return pdfium::span<char>();
258   }
259   // SAFETY: required from caller, enforced by UNSAFE_BUFFER_USAGE in header.
260   return UNSAFE_BUFFERS(pdfium::make_span(static_cast<char*>(buffer), buflen));
261 }
262 
263 #ifdef PDF_ENABLE_XFA
MakeSeekableStream(FPDF_FILEHANDLER * pFilehandler)264 RetainPtr<IFX_SeekableStream> MakeSeekableStream(
265     FPDF_FILEHANDLER* pFilehandler) {
266   return pdfium::MakeRetain<FPDF_FileHandlerContext>(pFilehandler);
267 }
268 #endif  // PDF_ENABLE_XFA
269 
GetQuadPointsArrayFromDictionary(const CPDF_Dictionary * dict)270 RetainPtr<const CPDF_Array> GetQuadPointsArrayFromDictionary(
271     const CPDF_Dictionary* dict) {
272   return dict->GetArrayFor("QuadPoints");
273 }
274 
GetMutableQuadPointsArrayFromDictionary(CPDF_Dictionary * dict)275 RetainPtr<CPDF_Array> GetMutableQuadPointsArrayFromDictionary(
276     CPDF_Dictionary* dict) {
277   return pdfium::WrapRetain(
278       const_cast<CPDF_Array*>(GetQuadPointsArrayFromDictionary(dict).Get()));
279 }
280 
AddQuadPointsArrayToDictionary(CPDF_Dictionary * dict)281 RetainPtr<CPDF_Array> AddQuadPointsArrayToDictionary(CPDF_Dictionary* dict) {
282   return dict->SetNewFor<CPDF_Array>(kQuadPoints);
283 }
284 
IsValidQuadPointsIndex(const CPDF_Array * array,size_t index)285 bool IsValidQuadPointsIndex(const CPDF_Array* array, size_t index) {
286   return array && index < array->size() / 8;
287 }
288 
GetQuadPointsAtIndex(RetainPtr<const CPDF_Array> array,size_t quad_index,FS_QUADPOINTSF * quad_points)289 bool GetQuadPointsAtIndex(RetainPtr<const CPDF_Array> array,
290                           size_t quad_index,
291                           FS_QUADPOINTSF* quad_points) {
292   DCHECK(quad_points);
293   DCHECK(array);
294 
295   if (!IsValidQuadPointsIndex(array, quad_index))
296     return false;
297 
298   quad_index *= 8;
299   quad_points->x1 = array->GetFloatAt(quad_index);
300   quad_points->y1 = array->GetFloatAt(quad_index + 1);
301   quad_points->x2 = array->GetFloatAt(quad_index + 2);
302   quad_points->y2 = array->GetFloatAt(quad_index + 3);
303   quad_points->x3 = array->GetFloatAt(quad_index + 4);
304   quad_points->y3 = array->GetFloatAt(quad_index + 5);
305   quad_points->x4 = array->GetFloatAt(quad_index + 6);
306   quad_points->y4 = array->GetFloatAt(quad_index + 7);
307   return true;
308 }
309 
CFXPointFFromFSPointF(const FS_POINTF & point)310 CFX_PointF CFXPointFFromFSPointF(const FS_POINTF& point) {
311   return CFX_PointF(point.x, point.y);
312 }
313 
CFXFloatRectFromFSRectF(const FS_RECTF & rect)314 CFX_FloatRect CFXFloatRectFromFSRectF(const FS_RECTF& rect) {
315   return CFX_FloatRect(rect.left, rect.bottom, rect.right, rect.top);
316 }
317 
FSRectFFromCFXFloatRect(const CFX_FloatRect & rect)318 FS_RECTF FSRectFFromCFXFloatRect(const CFX_FloatRect& rect) {
319   return {rect.left, rect.top, rect.right, rect.bottom};
320 }
321 
CFXMatrixFromFSMatrix(const FS_MATRIX & matrix)322 CFX_Matrix CFXMatrixFromFSMatrix(const FS_MATRIX& matrix) {
323   return CFX_Matrix(matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f);
324 }
325 
FSMatrixFromCFXMatrix(const CFX_Matrix & matrix)326 FS_MATRIX FSMatrixFromCFXMatrix(const CFX_Matrix& matrix) {
327   return {matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f};
328 }
329 
NulTerminateMaybeCopyAndReturnLength(const ByteString & text,pdfium::span<char> result_span)330 unsigned long NulTerminateMaybeCopyAndReturnLength(
331     const ByteString& text,
332     pdfium::span<char> result_span) {
333   pdfium::span<const char> text_span = text.span_with_terminator();
334   fxcrt::try_spancpy(result_span, text_span);
335   return pdfium::checked_cast<unsigned long>(text_span.size());
336 }
337 
Utf16EncodeMaybeCopyAndReturnLength(const WideString & text,pdfium::span<char> result_span)338 unsigned long Utf16EncodeMaybeCopyAndReturnLength(
339     const WideString& text,
340     pdfium::span<char> result_span) {
341   ByteString encoded_text = text.ToUTF16LE();
342   pdfium::span<const char> encoded_text_span = encoded_text.span();
343   fxcrt::try_spancpy(result_span, encoded_text_span);
344   return pdfium::checked_cast<unsigned long>(encoded_text_span.size());
345 }
346 
GetRawStreamMaybeCopyAndReturnLength(RetainPtr<const CPDF_Stream> stream,pdfium::span<uint8_t> buffer)347 unsigned long GetRawStreamMaybeCopyAndReturnLength(
348     RetainPtr<const CPDF_Stream> stream,
349     pdfium::span<uint8_t> buffer) {
350   return GetStreamMaybeCopyAndReturnLengthImpl(std::move(stream), buffer,
351                                                /*decode=*/false);
352 }
353 
DecodeStreamMaybeCopyAndReturnLength(RetainPtr<const CPDF_Stream> stream,pdfium::span<uint8_t> buffer)354 unsigned long DecodeStreamMaybeCopyAndReturnLength(
355     RetainPtr<const CPDF_Stream> stream,
356     pdfium::span<uint8_t> buffer) {
357   return GetStreamMaybeCopyAndReturnLengthImpl(std::move(stream), buffer,
358                                                /*decode=*/true);
359 }
360 
SetPDFSandboxPolicy(FPDF_DWORD policy,FPDF_BOOL enable)361 void SetPDFSandboxPolicy(FPDF_DWORD policy, FPDF_BOOL enable) {
362   switch (policy) {
363     case FPDF_POLICY_MACHINETIME_ACCESS: {
364       uint32_t mask = 1 << policy;
365       if (enable)
366         g_sandbox_policy |= mask;
367       else
368         g_sandbox_policy &= ~mask;
369     } break;
370     default:
371       break;
372   }
373 }
374 
IsPDFSandboxPolicyEnabled(FPDF_DWORD policy)375 FPDF_BOOL IsPDFSandboxPolicyEnabled(FPDF_DWORD policy) {
376   switch (policy) {
377     case FPDF_POLICY_MACHINETIME_ACCESS: {
378       uint32_t mask = 1 << policy;
379       return !!(g_sandbox_policy & mask);
380     }
381     default:
382       return false;
383   }
384 }
385 
SetPDFUnsupportInfo(UNSUPPORT_INFO * unsp_info)386 void SetPDFUnsupportInfo(UNSUPPORT_INFO* unsp_info) {
387   g_unsupport_info = unsp_info;
388 }
389 
ReportUnsupportedFeatures(const CPDF_Document * pDoc)390 void ReportUnsupportedFeatures(const CPDF_Document* pDoc) {
391   const CPDF_Dictionary* pRootDict = pDoc->GetRoot();
392   if (!pRootDict)
393     return;
394 
395   // Portfolios and Packages
396   if (pRootDict->KeyExist("Collection"))
397     RaiseUnsupportedError(FPDF_UNSP_DOC_PORTABLECOLLECTION);
398 
399   RetainPtr<const CPDF_Dictionary> pNameDict = pRootDict->GetDictFor("Names");
400   if (pNameDict) {
401     if (pNameDict->KeyExist("EmbeddedFiles"))
402       RaiseUnsupportedError(FPDF_UNSP_DOC_ATTACHMENT);
403 
404     RetainPtr<const CPDF_Dictionary> pJSDict =
405         pNameDict->GetDictFor("JavaScript");
406     if (pJSDict) {
407       RetainPtr<const CPDF_Array> pArray = pJSDict->GetArrayFor("Names");
408       if (pArray) {
409         for (size_t i = 0; i < pArray->size(); i++) {
410           ByteString cbStr = pArray->GetByteStringAt(i);
411           if (cbStr == "com.adobe.acrobat.SharedReview.Register") {
412             RaiseUnsupportedError(FPDF_UNSP_DOC_SHAREDREVIEW);
413             break;
414           }
415         }
416       }
417     }
418   }
419 
420   // SharedForm
421   RetainPtr<const CPDF_Stream> pStream = pRootDict->GetStreamFor("Metadata");
422   if (pStream) {
423     CPDF_Metadata metadata(std::move(pStream));
424     for (const UnsupportedFeature& feature : metadata.CheckForSharedForm())
425       RaiseUnsupportedError(static_cast<int>(feature));
426   }
427 }
428 
ReportUnsupportedXFA(const CPDF_Document * pDoc)429 void ReportUnsupportedXFA(const CPDF_Document* pDoc) {
430   if (!pDoc->GetExtension() && DocHasXFA(pDoc))
431     RaiseUnsupportedError(FPDF_UNSP_DOC_XFAFORM);
432 }
433 
CheckForUnsupportedAnnot(const CPDF_Annot * pAnnot)434 void CheckForUnsupportedAnnot(const CPDF_Annot* pAnnot) {
435   switch (pAnnot->GetSubtype()) {
436     case CPDF_Annot::Subtype::FILEATTACHMENT:
437       RaiseUnsupportedError(FPDF_UNSP_ANNOT_ATTACHMENT);
438       break;
439     case CPDF_Annot::Subtype::MOVIE:
440       RaiseUnsupportedError(FPDF_UNSP_ANNOT_MOVIE);
441       break;
442     case CPDF_Annot::Subtype::RICHMEDIA:
443       RaiseUnsupportedError(FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA);
444       break;
445     case CPDF_Annot::Subtype::SCREEN: {
446       const CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
447       ByteString cbString = pAnnotDict->GetByteStringFor("IT");
448       if (cbString != "Img")
449         RaiseUnsupportedError(FPDF_UNSP_ANNOT_SCREEN_MEDIA);
450       break;
451     }
452     case CPDF_Annot::Subtype::SOUND:
453       RaiseUnsupportedError(FPDF_UNSP_ANNOT_SOUND);
454       break;
455     case CPDF_Annot::Subtype::THREED:
456       RaiseUnsupportedError(FPDF_UNSP_ANNOT_3DANNOT);
457       break;
458     case CPDF_Annot::Subtype::WIDGET: {
459       const CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
460       ByteString cbString =
461           pAnnotDict->GetByteStringFor(pdfium::form_fields::kFT);
462       if (cbString == pdfium::form_fields::kSig)
463         RaiseUnsupportedError(FPDF_UNSP_ANNOT_SIG);
464       break;
465     }
466     default:
467       break;
468   }
469 }
470 
ProcessParseError(CPDF_Parser::Error err)471 void ProcessParseError(CPDF_Parser::Error err) {
472   uint32_t err_code = FPDF_ERR_SUCCESS;
473   // Translate FPDFAPI error code to FPDFVIEW error code
474   switch (err) {
475     case CPDF_Parser::SUCCESS:
476       err_code = FPDF_ERR_SUCCESS;
477       break;
478     case CPDF_Parser::FILE_ERROR:
479       err_code = FPDF_ERR_FILE;
480       break;
481     case CPDF_Parser::FORMAT_ERROR:
482       err_code = FPDF_ERR_FORMAT;
483       break;
484     case CPDF_Parser::PASSWORD_ERROR:
485       err_code = FPDF_ERR_PASSWORD;
486       break;
487     case CPDF_Parser::HANDLER_ERROR:
488       err_code = FPDF_ERR_SECURITY;
489       break;
490   }
491   FXSYS_SetLastError(err_code);
492 }
493 
SetColorFromScheme(const FPDF_COLORSCHEME * pColorScheme,CPDF_RenderOptions * pRenderOptions)494 void SetColorFromScheme(const FPDF_COLORSCHEME* pColorScheme,
495                         CPDF_RenderOptions* pRenderOptions) {
496   CPDF_RenderOptions::ColorScheme color_scheme;
497   color_scheme.path_fill_color =
498       static_cast<FX_ARGB>(pColorScheme->path_fill_color);
499   color_scheme.path_stroke_color =
500       static_cast<FX_ARGB>(pColorScheme->path_stroke_color);
501   color_scheme.text_fill_color =
502       static_cast<FX_ARGB>(pColorScheme->text_fill_color);
503   color_scheme.text_stroke_color =
504       static_cast<FX_ARGB>(pColorScheme->text_stroke_color);
505   pRenderOptions->SetColorScheme(color_scheme);
506 }
507 
ParsePageRangeString(const ByteString & bsPageRange,uint32_t nCount)508 std::vector<uint32_t> ParsePageRangeString(const ByteString& bsPageRange,
509                                            uint32_t nCount) {
510   ByteStringView alphabet(" 0123456789-,");
511   for (const auto& ch : bsPageRange) {
512     if (!alphabet.Contains(ch))
513       return std::vector<uint32_t>();
514   }
515 
516   ByteString bsStrippedPageRange = bsPageRange;
517   bsStrippedPageRange.Remove(' ');
518 
519   std::vector<uint32_t> results;
520   for (const auto& entry : fxcrt::Split(bsStrippedPageRange, ',')) {
521     std::vector<ByteString> args = fxcrt::Split(entry, '-');
522     if (args.size() == 1) {
523       uint32_t page_num = pdfium::checked_cast<uint32_t>(atoi(args[0].c_str()));
524       if (page_num == 0 || page_num > nCount)
525         return std::vector<uint32_t>();
526       results.push_back(page_num - 1);
527     } else if (args.size() == 2) {
528       uint32_t first_num =
529           pdfium::checked_cast<uint32_t>(atoi(args[0].c_str()));
530       if (first_num == 0)
531         return std::vector<uint32_t>();
532       uint32_t last_num = pdfium::checked_cast<uint32_t>(atoi(args[1].c_str()));
533       if (last_num == 0 || first_num > last_num || last_num > nCount)
534         return std::vector<uint32_t>();
535       for (uint32_t i = first_num; i <= last_num; ++i)
536         results.push_back(i - 1);
537     } else {
538       return std::vector<uint32_t>();
539     }
540   }
541   return results;
542 }
543