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