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