OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "core/include/fpdfapi/fpdf_parser.h" | |
8 | |
9 #include <algorithm> | |
10 #include <memory> | |
11 #include <set> | |
12 #include <utility> | |
13 #include <vector> | |
14 | |
15 #include "core/include/fpdfapi/cpdf_document.h" | |
16 #include "core/include/fpdfapi/cpdf_parser.h" | |
17 #include "core/include/fpdfapi/fpdf_module.h" | |
18 #include "core/include/fpdfapi/fpdf_page.h" | |
19 #include "core/include/fxcrt/fx_ext.h" | |
20 #include "core/include/fxcrt/fx_safe_types.h" | |
21 #include "core/src/fpdfapi/fpdf_page/pageint.h" | |
22 #include "core/src/fpdfapi/fpdf_parser/cpdf_syntax_parser.h" | |
23 #include "core/src/fpdfapi/fpdf_parser/fpdf_parser_utility.h" | |
24 #include "core/src/fpdfapi/fpdf_parser/parser_int.h" | |
25 #include "third_party/base/stl_util.h" | |
26 | |
27 namespace { | |
28 | |
29 bool CanReadFromBitStream(const CFX_BitStream* hStream, | |
30 const FX_SAFE_DWORD& num_bits) { | |
31 return num_bits.IsValid() && | |
32 hStream->BitsRemaining() >= num_bits.ValueOrDie(); | |
33 } | |
34 | |
35 } // namespace | |
36 | |
37 bool IsSignatureDict(const CPDF_Dictionary* pDict) { | |
38 CPDF_Object* pType = pDict->GetElementValue("Type"); | |
39 if (!pType) | |
40 pType = pDict->GetElementValue("FT"); | |
41 return pType && pType->GetString() == "Sig"; | |
42 } | |
43 | |
44 | |
45 class CPDF_DataAvail final : public IPDF_DataAvail { | |
46 public: | |
47 CPDF_DataAvail(IFX_FileAvail* pFileAvail, | |
48 IFX_FileRead* pFileRead, | |
49 FX_BOOL bSupportHintTable); | |
50 ~CPDF_DataAvail() override; | |
51 | |
52 // IPDF_DataAvail: | |
53 DocAvailStatus IsDocAvail(IFX_DownloadHints* pHints) override; | |
54 void SetDocument(CPDF_Document* pDoc) override; | |
55 DocAvailStatus IsPageAvail(int iPage, IFX_DownloadHints* pHints) override; | |
56 DocFormStatus IsFormAvail(IFX_DownloadHints* pHints) override; | |
57 DocLinearizationStatus IsLinearizedPDF() override; | |
58 FX_BOOL IsLinearized() override { return m_bLinearized; } | |
59 void GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, FX_DWORD* pSize) override; | |
60 | |
61 int GetPageCount() const; | |
62 CPDF_Dictionary* GetPage(int index); | |
63 | |
64 friend class CPDF_HintTables; | |
65 | |
66 protected: | |
67 static const int kMaxDataAvailRecursionDepth = 64; | |
68 static int s_CurrentDataAvailRecursionDepth; | |
69 static const int kMaxPageRecursionDepth = 1024; | |
70 | |
71 FX_DWORD GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset); | |
72 FX_BOOL IsObjectsAvail(CFX_ArrayTemplate<CPDF_Object*>& obj_array, | |
73 FX_BOOL bParsePage, | |
74 IFX_DownloadHints* pHints, | |
75 CFX_ArrayTemplate<CPDF_Object*>& ret_array); | |
76 FX_BOOL CheckDocStatus(IFX_DownloadHints* pHints); | |
77 FX_BOOL CheckHeader(IFX_DownloadHints* pHints); | |
78 FX_BOOL CheckFirstPage(IFX_DownloadHints* pHints); | |
79 FX_BOOL CheckHintTables(IFX_DownloadHints* pHints); | |
80 FX_BOOL CheckEnd(IFX_DownloadHints* pHints); | |
81 FX_BOOL CheckCrossRef(IFX_DownloadHints* pHints); | |
82 FX_BOOL CheckCrossRefItem(IFX_DownloadHints* pHints); | |
83 FX_BOOL CheckTrailer(IFX_DownloadHints* pHints); | |
84 FX_BOOL CheckRoot(IFX_DownloadHints* pHints); | |
85 FX_BOOL CheckInfo(IFX_DownloadHints* pHints); | |
86 FX_BOOL CheckPages(IFX_DownloadHints* pHints); | |
87 FX_BOOL CheckPage(IFX_DownloadHints* pHints); | |
88 FX_BOOL CheckResources(IFX_DownloadHints* pHints); | |
89 FX_BOOL CheckAnnots(IFX_DownloadHints* pHints); | |
90 FX_BOOL CheckAcroForm(IFX_DownloadHints* pHints); | |
91 FX_BOOL CheckAcroFormSubObject(IFX_DownloadHints* pHints); | |
92 FX_BOOL CheckTrailerAppend(IFX_DownloadHints* pHints); | |
93 FX_BOOL CheckPageStatus(IFX_DownloadHints* pHints); | |
94 FX_BOOL CheckAllCrossRefStream(IFX_DownloadHints* pHints); | |
95 | |
96 int32_t CheckCrossRefStream(IFX_DownloadHints* pHints, | |
97 FX_FILESIZE& xref_offset); | |
98 FX_BOOL IsLinearizedFile(uint8_t* pData, FX_DWORD dwLen); | |
99 void SetStartOffset(FX_FILESIZE dwOffset); | |
100 FX_BOOL GetNextToken(CFX_ByteString& token); | |
101 FX_BOOL GetNextChar(uint8_t& ch); | |
102 CPDF_Object* ParseIndirectObjectAt( | |
103 FX_FILESIZE pos, | |
104 FX_DWORD objnum, | |
105 CPDF_IndirectObjectHolder* pObjList = nullptr); | |
106 CPDF_Object* GetObject(FX_DWORD objnum, | |
107 IFX_DownloadHints* pHints, | |
108 FX_BOOL* pExistInFile); | |
109 FX_BOOL GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages); | |
110 FX_BOOL PreparePageItem(); | |
111 FX_BOOL LoadPages(IFX_DownloadHints* pHints); | |
112 FX_BOOL LoadAllXref(IFX_DownloadHints* pHints); | |
113 FX_BOOL LoadAllFile(IFX_DownloadHints* pHints); | |
114 DocAvailStatus CheckLinearizedData(IFX_DownloadHints* pHints); | |
115 FX_BOOL CheckPageAnnots(int iPage, IFX_DownloadHints* pHints); | |
116 | |
117 DocAvailStatus CheckLinearizedFirstPage(int iPage, IFX_DownloadHints* pHints); | |
118 FX_BOOL HaveResourceAncestor(CPDF_Dictionary* pDict); | |
119 FX_BOOL CheckPage(int32_t iPage, IFX_DownloadHints* pHints); | |
120 FX_BOOL LoadDocPages(IFX_DownloadHints* pHints); | |
121 FX_BOOL LoadDocPage(int32_t iPage, IFX_DownloadHints* pHints); | |
122 FX_BOOL CheckPageNode(CPDF_PageNode& pageNodes, | |
123 int32_t iPage, | |
124 int32_t& iCount, | |
125 IFX_DownloadHints* pHints, | |
126 int level); | |
127 FX_BOOL CheckUnkownPageNode(FX_DWORD dwPageNo, | |
128 CPDF_PageNode* pPageNode, | |
129 IFX_DownloadHints* pHints); | |
130 FX_BOOL CheckArrayPageNode(FX_DWORD dwPageNo, | |
131 CPDF_PageNode* pPageNode, | |
132 IFX_DownloadHints* pHints); | |
133 FX_BOOL CheckPageCount(IFX_DownloadHints* pHints); | |
134 bool IsFirstCheck(int iPage); | |
135 void ResetFirstCheck(int iPage); | |
136 FX_BOOL IsDataAvail(FX_FILESIZE offset, | |
137 FX_DWORD size, | |
138 IFX_DownloadHints* pHints); | |
139 | |
140 CPDF_Parser m_parser; | |
141 CPDF_SyntaxParser m_syntaxParser; | |
142 CPDF_Object* m_pRoot; | |
143 FX_DWORD m_dwRootObjNum; | |
144 FX_DWORD m_dwInfoObjNum; | |
145 CPDF_Object* m_pLinearized; | |
146 CPDF_Object* m_pTrailer; | |
147 FX_BOOL m_bDocAvail; | |
148 FX_FILESIZE m_dwHeaderOffset; | |
149 FX_FILESIZE m_dwLastXRefOffset; | |
150 FX_FILESIZE m_dwXRefOffset; | |
151 FX_FILESIZE m_dwTrailerOffset; | |
152 FX_FILESIZE m_dwCurrentOffset; | |
153 PDF_DATAAVAIL_STATUS m_docStatus; | |
154 FX_FILESIZE m_dwFileLen; | |
155 CPDF_Document* m_pDocument; | |
156 std::set<FX_DWORD> m_ObjectSet; | |
157 CFX_ArrayTemplate<CPDF_Object*> m_objs_array; | |
158 FX_FILESIZE m_Pos; | |
159 FX_FILESIZE m_bufferOffset; | |
160 FX_DWORD m_bufferSize; | |
161 CFX_ByteString m_WordBuf; | |
162 uint8_t m_bufferData[512]; | |
163 CFX_DWordArray m_XRefStreamList; | |
164 CFX_DWordArray m_PageObjList; | |
165 FX_DWORD m_PagesObjNum; | |
166 FX_BOOL m_bLinearized; | |
167 FX_DWORD m_dwFirstPageNo; | |
168 FX_BOOL m_bLinearedDataOK; | |
169 FX_BOOL m_bMainXRefLoadTried; | |
170 FX_BOOL m_bMainXRefLoadedOK; | |
171 FX_BOOL m_bPagesTreeLoad; | |
172 FX_BOOL m_bPagesLoad; | |
173 CPDF_Parser* m_pCurrentParser; | |
174 FX_FILESIZE m_dwCurrentXRefSteam; | |
175 FX_BOOL m_bAnnotsLoad; | |
176 FX_BOOL m_bHaveAcroForm; | |
177 FX_DWORD m_dwAcroFormObjNum; | |
178 FX_BOOL m_bAcroFormLoad; | |
179 CPDF_Object* m_pAcroForm; | |
180 CFX_ArrayTemplate<CPDF_Object*> m_arrayAcroforms; | |
181 CPDF_Dictionary* m_pPageDict; | |
182 CPDF_Object* m_pPageResource; | |
183 FX_BOOL m_bNeedDownLoadResource; | |
184 FX_BOOL m_bPageLoadedOK; | |
185 FX_BOOL m_bLinearizedFormParamLoad; | |
186 CFX_ArrayTemplate<CPDF_Object*> m_PagesArray; | |
187 FX_DWORD m_dwEncryptObjNum; | |
188 FX_FILESIZE m_dwPrevXRefOffset; | |
189 FX_BOOL m_bTotalLoadPageTree; | |
190 FX_BOOL m_bCurPageDictLoadOK; | |
191 CPDF_PageNode m_pageNodes; | |
192 std::set<FX_DWORD> m_pageMapCheckState; | |
193 std::set<FX_DWORD> m_pagesLoadState; | |
194 std::unique_ptr<CPDF_HintTables> m_pHintTables; | |
195 FX_BOOL m_bSupportHintTable; | |
196 }; | |
197 | |
198 IPDF_DataAvail::IPDF_DataAvail(IFX_FileAvail* pFileAvail, | |
199 IFX_FileRead* pFileRead) | |
200 : m_pFileAvail(pFileAvail), m_pFileRead(pFileRead) {} | |
201 | |
202 // static | |
203 IPDF_DataAvail* IPDF_DataAvail::Create(IFX_FileAvail* pFileAvail, | |
204 IFX_FileRead* pFileRead) { | |
205 return new CPDF_DataAvail(pFileAvail, pFileRead, TRUE); | |
206 } | |
207 | |
208 // static | |
209 int CPDF_DataAvail::s_CurrentDataAvailRecursionDepth = 0; | |
210 | |
211 CPDF_DataAvail::CPDF_DataAvail(IFX_FileAvail* pFileAvail, | |
212 IFX_FileRead* pFileRead, | |
213 FX_BOOL bSupportHintTable) | |
214 : IPDF_DataAvail(pFileAvail, pFileRead) { | |
215 m_Pos = 0; | |
216 m_dwFileLen = 0; | |
217 if (m_pFileRead) { | |
218 m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize(); | |
219 } | |
220 m_dwCurrentOffset = 0; | |
221 m_dwXRefOffset = 0; | |
222 m_bufferOffset = 0; | |
223 m_dwFirstPageNo = 0; | |
224 m_bufferSize = 0; | |
225 m_PagesObjNum = 0; | |
226 m_dwCurrentXRefSteam = 0; | |
227 m_dwAcroFormObjNum = 0; | |
228 m_dwInfoObjNum = 0; | |
229 m_pDocument = 0; | |
230 m_dwEncryptObjNum = 0; | |
231 m_dwPrevXRefOffset = 0; | |
232 m_dwLastXRefOffset = 0; | |
233 m_bDocAvail = FALSE; | |
234 m_bMainXRefLoadTried = FALSE; | |
235 m_bDocAvail = FALSE; | |
236 m_bLinearized = FALSE; | |
237 m_bPagesLoad = FALSE; | |
238 m_bPagesTreeLoad = FALSE; | |
239 m_bMainXRefLoadedOK = FALSE; | |
240 m_bAnnotsLoad = FALSE; | |
241 m_bHaveAcroForm = FALSE; | |
242 m_bAcroFormLoad = FALSE; | |
243 m_bPageLoadedOK = FALSE; | |
244 m_bNeedDownLoadResource = FALSE; | |
245 m_bLinearizedFormParamLoad = FALSE; | |
246 m_pLinearized = NULL; | |
247 m_pRoot = NULL; | |
248 m_pTrailer = NULL; | |
249 m_pCurrentParser = NULL; | |
250 m_pAcroForm = NULL; | |
251 m_pPageDict = NULL; | |
252 m_pPageResource = NULL; | |
253 m_docStatus = PDF_DATAAVAIL_HEADER; | |
254 m_parser.m_bOwnFileRead = false; | |
255 m_bTotalLoadPageTree = FALSE; | |
256 m_bCurPageDictLoadOK = FALSE; | |
257 m_bLinearedDataOK = FALSE; | |
258 m_bSupportHintTable = bSupportHintTable; | |
259 } | |
260 CPDF_DataAvail::~CPDF_DataAvail() { | |
261 if (m_pLinearized) | |
262 m_pLinearized->Release(); | |
263 | |
264 if (m_pRoot) | |
265 m_pRoot->Release(); | |
266 | |
267 if (m_pTrailer) | |
268 m_pTrailer->Release(); | |
269 | |
270 int iSize = m_arrayAcroforms.GetSize(); | |
271 for (int i = 0; i < iSize; ++i) | |
272 m_arrayAcroforms.GetAt(i)->Release(); | |
273 } | |
274 | |
275 void CPDF_DataAvail::SetDocument(CPDF_Document* pDoc) { | |
276 m_pDocument = pDoc; | |
277 } | |
278 | |
279 FX_DWORD CPDF_DataAvail::GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset) { | |
280 CPDF_Parser* pParser = m_pDocument->GetParser(); | |
281 if (!pParser || !pParser->IsValidObjectNumber(objnum)) | |
282 return 0; | |
283 | |
284 if (pParser->GetObjectType(objnum) == 2) | |
285 objnum = pParser->GetObjectPositionOrZero(objnum); | |
286 | |
287 if (pParser->GetObjectType(objnum) != 1 && | |
288 pParser->GetObjectType(objnum) != 255) { | |
289 return 0; | |
290 } | |
291 | |
292 offset = pParser->GetObjectPositionOrZero(objnum); | |
293 if (offset == 0) | |
294 return 0; | |
295 | |
296 auto it = pParser->m_SortedOffset.find(offset); | |
297 if (it == pParser->m_SortedOffset.end() || | |
298 ++it == pParser->m_SortedOffset.end()) { | |
299 return 0; | |
300 } | |
301 return *it - offset; | |
302 } | |
303 | |
304 FX_BOOL CPDF_DataAvail::IsObjectsAvail( | |
305 CFX_ArrayTemplate<CPDF_Object*>& obj_array, | |
306 FX_BOOL bParsePage, | |
307 IFX_DownloadHints* pHints, | |
308 CFX_ArrayTemplate<CPDF_Object*>& ret_array) { | |
309 if (!obj_array.GetSize()) | |
310 return TRUE; | |
311 | |
312 FX_DWORD count = 0; | |
313 CFX_ArrayTemplate<CPDF_Object*> new_obj_array; | |
314 int32_t i = 0; | |
315 for (i = 0; i < obj_array.GetSize(); i++) { | |
316 CPDF_Object* pObj = obj_array[i]; | |
317 if (!pObj) | |
318 continue; | |
319 | |
320 int32_t type = pObj->GetType(); | |
321 switch (type) { | |
322 case CPDF_Object::ARRAY: { | |
323 CPDF_Array* pArray = pObj->GetArray(); | |
324 for (FX_DWORD k = 0; k < pArray->GetCount(); ++k) | |
325 new_obj_array.Add(pArray->GetElement(k)); | |
326 } break; | |
327 case CPDF_Object::STREAM: | |
328 pObj = pObj->GetDict(); | |
329 case CPDF_Object::DICTIONARY: { | |
330 CPDF_Dictionary* pDict = pObj->GetDict(); | |
331 if (pDict && pDict->GetStringBy("Type") == "Page" && !bParsePage) | |
332 continue; | |
333 | |
334 for (const auto& it : *pDict) { | |
335 const CFX_ByteString& key = it.first; | |
336 CPDF_Object* value = it.second; | |
337 if (key != "Parent") | |
338 new_obj_array.Add(value); | |
339 } | |
340 } break; | |
341 case CPDF_Object::REFERENCE: { | |
342 CPDF_Reference* pRef = pObj->AsReference(); | |
343 FX_DWORD dwNum = pRef->GetRefObjNum(); | |
344 | |
345 FX_FILESIZE offset; | |
346 FX_DWORD size = GetObjectSize(dwNum, offset); | |
347 if (size == 0 || offset < 0 || offset >= m_dwFileLen) | |
348 break; | |
349 | |
350 if (!IsDataAvail(offset, size, pHints)) { | |
351 ret_array.Add(pObj); | |
352 count++; | |
353 } else if (!pdfium::ContainsKey(m_ObjectSet, dwNum)) { | |
354 m_ObjectSet.insert(dwNum); | |
355 CPDF_Object* pReferred = | |
356 m_pDocument->GetIndirectObject(pRef->GetRefObjNum()); | |
357 if (pReferred) | |
358 new_obj_array.Add(pReferred); | |
359 } | |
360 } break; | |
361 } | |
362 } | |
363 | |
364 if (count > 0) { | |
365 int32_t iSize = new_obj_array.GetSize(); | |
366 for (i = 0; i < iSize; ++i) { | |
367 CPDF_Object* pObj = new_obj_array[i]; | |
368 if (CPDF_Reference* pRef = pObj->AsReference()) { | |
369 FX_DWORD dwNum = pRef->GetRefObjNum(); | |
370 if (!pdfium::ContainsKey(m_ObjectSet, dwNum)) | |
371 ret_array.Add(pObj); | |
372 } else { | |
373 ret_array.Add(pObj); | |
374 } | |
375 } | |
376 return FALSE; | |
377 } | |
378 | |
379 obj_array.RemoveAll(); | |
380 obj_array.Append(new_obj_array); | |
381 return IsObjectsAvail(obj_array, FALSE, pHints, ret_array); | |
382 } | |
383 | |
384 IPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsDocAvail( | |
385 IFX_DownloadHints* pHints) { | |
386 if (!m_dwFileLen && m_pFileRead) { | |
387 m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize(); | |
388 if (!m_dwFileLen) | |
389 return DataError; | |
390 } | |
391 | |
392 while (!m_bDocAvail) { | |
393 if (!CheckDocStatus(pHints)) | |
394 return DataNotAvailable; | |
395 } | |
396 | |
397 return DataAvailable; | |
398 } | |
399 | |
400 FX_BOOL CPDF_DataAvail::CheckAcroFormSubObject(IFX_DownloadHints* pHints) { | |
401 if (!m_objs_array.GetSize()) { | |
402 m_objs_array.RemoveAll(); | |
403 m_ObjectSet.clear(); | |
404 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
405 obj_array.Append(m_arrayAcroforms); | |
406 FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); | |
407 if (bRet) | |
408 m_objs_array.RemoveAll(); | |
409 return bRet; | |
410 } | |
411 | |
412 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
413 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
414 if (bRet) { | |
415 int32_t iSize = m_arrayAcroforms.GetSize(); | |
416 for (int32_t i = 0; i < iSize; ++i) { | |
417 m_arrayAcroforms.GetAt(i)->Release(); | |
418 } | |
419 m_arrayAcroforms.RemoveAll(); | |
420 } else { | |
421 m_objs_array.RemoveAll(); | |
422 m_objs_array.Append(new_objs_array); | |
423 } | |
424 return bRet; | |
425 } | |
426 | |
427 FX_BOOL CPDF_DataAvail::CheckAcroForm(IFX_DownloadHints* pHints) { | |
428 FX_BOOL bExist = FALSE; | |
429 m_pAcroForm = GetObject(m_dwAcroFormObjNum, pHints, &bExist); | |
430 if (!bExist) { | |
431 m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
432 return TRUE; | |
433 } | |
434 | |
435 if (!m_pAcroForm) { | |
436 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
437 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
438 return TRUE; | |
439 } | |
440 return FALSE; | |
441 } | |
442 | |
443 m_arrayAcroforms.Add(m_pAcroForm); | |
444 m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
445 return TRUE; | |
446 } | |
447 | |
448 FX_BOOL CPDF_DataAvail::CheckDocStatus(IFX_DownloadHints* pHints) { | |
449 switch (m_docStatus) { | |
450 case PDF_DATAAVAIL_HEADER: | |
451 return CheckHeader(pHints); | |
452 case PDF_DATAAVAIL_FIRSTPAGE: | |
453 case PDF_DATAAVAIL_FIRSTPAGE_PREPARE: | |
454 return CheckFirstPage(pHints); | |
455 case PDF_DATAAVAIL_HINTTABLE: | |
456 return CheckHintTables(pHints); | |
457 case PDF_DATAAVAIL_END: | |
458 return CheckEnd(pHints); | |
459 case PDF_DATAAVAIL_CROSSREF: | |
460 return CheckCrossRef(pHints); | |
461 case PDF_DATAAVAIL_CROSSREF_ITEM: | |
462 return CheckCrossRefItem(pHints); | |
463 case PDF_DATAAVAIL_CROSSREF_STREAM: | |
464 return CheckAllCrossRefStream(pHints); | |
465 case PDF_DATAAVAIL_TRAILER: | |
466 return CheckTrailer(pHints); | |
467 case PDF_DATAAVAIL_TRAILER_APPEND: | |
468 return CheckTrailerAppend(pHints); | |
469 case PDF_DATAAVAIL_LOADALLCROSSREF: | |
470 return LoadAllXref(pHints); | |
471 case PDF_DATAAVAIL_LOADALLFILE: | |
472 return LoadAllFile(pHints); | |
473 case PDF_DATAAVAIL_ROOT: | |
474 return CheckRoot(pHints); | |
475 case PDF_DATAAVAIL_INFO: | |
476 return CheckInfo(pHints); | |
477 case PDF_DATAAVAIL_ACROFORM: | |
478 return CheckAcroForm(pHints); | |
479 case PDF_DATAAVAIL_PAGETREE: | |
480 if (m_bTotalLoadPageTree) | |
481 return CheckPages(pHints); | |
482 return LoadDocPages(pHints); | |
483 case PDF_DATAAVAIL_PAGE: | |
484 if (m_bTotalLoadPageTree) | |
485 return CheckPage(pHints); | |
486 m_docStatus = PDF_DATAAVAIL_PAGE_LATERLOAD; | |
487 return TRUE; | |
488 case PDF_DATAAVAIL_ERROR: | |
489 return LoadAllFile(pHints); | |
490 case PDF_DATAAVAIL_PAGE_LATERLOAD: | |
491 m_docStatus = PDF_DATAAVAIL_PAGE; | |
492 default: | |
493 m_bDocAvail = TRUE; | |
494 return TRUE; | |
495 } | |
496 } | |
497 | |
498 FX_BOOL CPDF_DataAvail::CheckPageStatus(IFX_DownloadHints* pHints) { | |
499 switch (m_docStatus) { | |
500 case PDF_DATAAVAIL_PAGETREE: | |
501 return CheckPages(pHints); | |
502 case PDF_DATAAVAIL_PAGE: | |
503 return CheckPage(pHints); | |
504 case PDF_DATAAVAIL_ERROR: | |
505 return LoadAllFile(pHints); | |
506 default: | |
507 m_bPagesTreeLoad = TRUE; | |
508 m_bPagesLoad = TRUE; | |
509 return TRUE; | |
510 } | |
511 } | |
512 | |
513 FX_BOOL CPDF_DataAvail::LoadAllFile(IFX_DownloadHints* pHints) { | |
514 if (m_pFileAvail->IsDataAvail(0, (FX_DWORD)m_dwFileLen)) { | |
515 m_docStatus = PDF_DATAAVAIL_DONE; | |
516 return TRUE; | |
517 } | |
518 | |
519 pHints->AddSegment(0, (FX_DWORD)m_dwFileLen); | |
520 return FALSE; | |
521 } | |
522 | |
523 FX_BOOL CPDF_DataAvail::LoadAllXref(IFX_DownloadHints* pHints) { | |
524 m_parser.m_pSyntax->InitParser(m_pFileRead, (FX_DWORD)m_dwHeaderOffset); | |
525 m_parser.m_bOwnFileRead = false; | |
526 if (!m_parser.LoadAllCrossRefV4(m_dwLastXRefOffset) && | |
527 !m_parser.LoadAllCrossRefV5(m_dwLastXRefOffset)) { | |
528 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
529 return FALSE; | |
530 } | |
531 | |
532 m_dwRootObjNum = m_parser.GetRootObjNum(); | |
533 m_dwInfoObjNum = m_parser.GetInfoObjNum(); | |
534 m_pCurrentParser = &m_parser; | |
535 m_docStatus = PDF_DATAAVAIL_ROOT; | |
536 return TRUE; | |
537 } | |
538 | |
539 CPDF_Object* CPDF_DataAvail::GetObject(FX_DWORD objnum, | |
540 IFX_DownloadHints* pHints, | |
541 FX_BOOL* pExistInFile) { | |
542 CPDF_Object* pRet = nullptr; | |
543 FX_DWORD size = 0; | |
544 FX_FILESIZE offset = 0; | |
545 CPDF_Parser* pParser = nullptr; | |
546 | |
547 if (pExistInFile) | |
548 *pExistInFile = TRUE; | |
549 | |
550 if (m_pDocument) { | |
551 size = GetObjectSize(objnum, offset); | |
552 pParser = m_pDocument->GetParser(); | |
553 } else { | |
554 size = (FX_DWORD)m_parser.GetObjectSize(objnum); | |
555 offset = m_parser.GetObjectOffset(objnum); | |
556 pParser = &m_parser; | |
557 } | |
558 | |
559 if (!IsDataAvail(offset, size, pHints)) | |
560 return nullptr; | |
561 | |
562 if (pParser) | |
563 pRet = pParser->ParseIndirectObject(nullptr, objnum); | |
564 | |
565 if (!pRet && pExistInFile) | |
566 *pExistInFile = FALSE; | |
567 | |
568 return pRet; | |
569 } | |
570 | |
571 FX_BOOL CPDF_DataAvail::CheckInfo(IFX_DownloadHints* pHints) { | |
572 FX_BOOL bExist = FALSE; | |
573 CPDF_Object* pInfo = GetObject(m_dwInfoObjNum, pHints, &bExist); | |
574 if (!bExist) { | |
575 m_docStatus = | |
576 (m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE); | |
577 return TRUE; | |
578 } | |
579 | |
580 if (!pInfo) { | |
581 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
582 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
583 return TRUE; | |
584 } | |
585 | |
586 if (m_Pos == m_dwFileLen) | |
587 m_docStatus = PDF_DATAAVAIL_ERROR; | |
588 return FALSE; | |
589 } | |
590 | |
591 if (pInfo) | |
592 pInfo->Release(); | |
593 | |
594 m_docStatus = | |
595 (m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE); | |
596 | |
597 return TRUE; | |
598 } | |
599 | |
600 FX_BOOL CPDF_DataAvail::CheckRoot(IFX_DownloadHints* pHints) { | |
601 FX_BOOL bExist = FALSE; | |
602 m_pRoot = GetObject(m_dwRootObjNum, pHints, &bExist); | |
603 if (!bExist) { | |
604 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
605 return TRUE; | |
606 } | |
607 | |
608 if (!m_pRoot) { | |
609 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
610 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
611 return TRUE; | |
612 } | |
613 return FALSE; | |
614 } | |
615 | |
616 CPDF_Dictionary* pDict = m_pRoot->GetDict(); | |
617 if (!pDict) { | |
618 m_docStatus = PDF_DATAAVAIL_ERROR; | |
619 return FALSE; | |
620 } | |
621 | |
622 CPDF_Reference* pRef = ToReference(pDict->GetElement("Pages")); | |
623 if (!pRef) { | |
624 m_docStatus = PDF_DATAAVAIL_ERROR; | |
625 return FALSE; | |
626 } | |
627 | |
628 m_PagesObjNum = pRef->GetRefObjNum(); | |
629 CPDF_Reference* pAcroFormRef = | |
630 ToReference(m_pRoot->GetDict()->GetElement("AcroForm")); | |
631 if (pAcroFormRef) { | |
632 m_bHaveAcroForm = TRUE; | |
633 m_dwAcroFormObjNum = pAcroFormRef->GetRefObjNum(); | |
634 } | |
635 | |
636 if (m_dwInfoObjNum) { | |
637 m_docStatus = PDF_DATAAVAIL_INFO; | |
638 } else { | |
639 m_docStatus = | |
640 m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE; | |
641 } | |
642 return TRUE; | |
643 } | |
644 | |
645 FX_BOOL CPDF_DataAvail::PreparePageItem() { | |
646 CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); | |
647 CPDF_Reference* pRef = | |
648 ToReference(pRoot ? pRoot->GetElement("Pages") : nullptr); | |
649 if (!pRef) { | |
650 m_docStatus = PDF_DATAAVAIL_ERROR; | |
651 return FALSE; | |
652 } | |
653 | |
654 m_PagesObjNum = pRef->GetRefObjNum(); | |
655 m_pCurrentParser = m_pDocument->GetParser(); | |
656 m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
657 return TRUE; | |
658 } | |
659 | |
660 bool CPDF_DataAvail::IsFirstCheck(int iPage) { | |
661 return m_pageMapCheckState.insert(iPage).second; | |
662 } | |
663 | |
664 void CPDF_DataAvail::ResetFirstCheck(int iPage) { | |
665 m_pageMapCheckState.erase(iPage); | |
666 } | |
667 | |
668 FX_BOOL CPDF_DataAvail::CheckPage(IFX_DownloadHints* pHints) { | |
669 FX_DWORD iPageObjs = m_PageObjList.GetSize(); | |
670 CFX_DWordArray UnavailObjList; | |
671 for (FX_DWORD i = 0; i < iPageObjs; ++i) { | |
672 FX_DWORD dwPageObjNum = m_PageObjList.GetAt(i); | |
673 FX_BOOL bExist = FALSE; | |
674 CPDF_Object* pObj = GetObject(dwPageObjNum, pHints, &bExist); | |
675 if (!pObj) { | |
676 if (bExist) | |
677 UnavailObjList.Add(dwPageObjNum); | |
678 continue; | |
679 } | |
680 | |
681 if (pObj->IsArray()) { | |
682 CPDF_Array* pArray = pObj->GetArray(); | |
683 if (pArray) { | |
684 int32_t iSize = pArray->GetCount(); | |
685 for (int32_t j = 0; j < iSize; ++j) { | |
686 if (CPDF_Reference* pRef = ToReference(pArray->GetElement(j))) | |
687 UnavailObjList.Add(pRef->GetRefObjNum()); | |
688 } | |
689 } | |
690 } | |
691 | |
692 if (!pObj->IsDictionary()) { | |
693 pObj->Release(); | |
694 continue; | |
695 } | |
696 | |
697 CFX_ByteString type = pObj->GetDict()->GetStringBy("Type"); | |
698 if (type == "Pages") { | |
699 m_PagesArray.Add(pObj); | |
700 continue; | |
701 } | |
702 pObj->Release(); | |
703 } | |
704 | |
705 m_PageObjList.RemoveAll(); | |
706 if (UnavailObjList.GetSize()) { | |
707 m_PageObjList.Append(UnavailObjList); | |
708 return FALSE; | |
709 } | |
710 | |
711 FX_DWORD iPages = m_PagesArray.GetSize(); | |
712 for (FX_DWORD i = 0; i < iPages; i++) { | |
713 CPDF_Object* pPages = m_PagesArray.GetAt(i); | |
714 if (!pPages) | |
715 continue; | |
716 | |
717 if (!GetPageKids(m_pCurrentParser, pPages)) { | |
718 pPages->Release(); | |
719 while (++i < iPages) { | |
720 pPages = m_PagesArray.GetAt(i); | |
721 pPages->Release(); | |
722 } | |
723 m_PagesArray.RemoveAll(); | |
724 | |
725 m_docStatus = PDF_DATAAVAIL_ERROR; | |
726 return FALSE; | |
727 } | |
728 pPages->Release(); | |
729 } | |
730 | |
731 m_PagesArray.RemoveAll(); | |
732 if (!m_PageObjList.GetSize()) | |
733 m_docStatus = PDF_DATAAVAIL_DONE; | |
734 return TRUE; | |
735 } | |
736 | |
737 FX_BOOL CPDF_DataAvail::GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages) { | |
738 if (!pParser) { | |
739 m_docStatus = PDF_DATAAVAIL_ERROR; | |
740 return FALSE; | |
741 } | |
742 | |
743 CPDF_Dictionary* pDict = pPages->GetDict(); | |
744 CPDF_Object* pKids = pDict ? pDict->GetElement("Kids") : NULL; | |
745 if (!pKids) | |
746 return TRUE; | |
747 | |
748 switch (pKids->GetType()) { | |
749 case CPDF_Object::REFERENCE: | |
750 m_PageObjList.Add(pKids->AsReference()->GetRefObjNum()); | |
751 break; | |
752 case CPDF_Object::ARRAY: { | |
753 CPDF_Array* pKidsArray = pKids->AsArray(); | |
754 for (FX_DWORD i = 0; i < pKidsArray->GetCount(); ++i) { | |
755 if (CPDF_Reference* pRef = ToReference(pKidsArray->GetElement(i))) | |
756 m_PageObjList.Add(pRef->GetRefObjNum()); | |
757 } | |
758 } break; | |
759 default: | |
760 m_docStatus = PDF_DATAAVAIL_ERROR; | |
761 return FALSE; | |
762 } | |
763 return TRUE; | |
764 } | |
765 | |
766 FX_BOOL CPDF_DataAvail::CheckPages(IFX_DownloadHints* pHints) { | |
767 FX_BOOL bExist = FALSE; | |
768 CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist); | |
769 if (!bExist) { | |
770 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
771 return TRUE; | |
772 } | |
773 | |
774 if (!pPages) { | |
775 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
776 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
777 return TRUE; | |
778 } | |
779 return FALSE; | |
780 } | |
781 | |
782 if (!GetPageKids(m_pCurrentParser, pPages)) { | |
783 pPages->Release(); | |
784 m_docStatus = PDF_DATAAVAIL_ERROR; | |
785 return FALSE; | |
786 } | |
787 | |
788 pPages->Release(); | |
789 m_docStatus = PDF_DATAAVAIL_PAGE; | |
790 return TRUE; | |
791 } | |
792 | |
793 FX_BOOL CPDF_DataAvail::CheckHeader(IFX_DownloadHints* pHints) { | |
794 FX_DWORD req_size = 1024; | |
795 if ((FX_FILESIZE)req_size > m_dwFileLen) | |
796 req_size = (FX_DWORD)m_dwFileLen; | |
797 | |
798 if (m_pFileAvail->IsDataAvail(0, req_size)) { | |
799 uint8_t buffer[1024]; | |
800 m_pFileRead->ReadBlock(buffer, 0, req_size); | |
801 | |
802 if (IsLinearizedFile(buffer, req_size)) { | |
803 m_docStatus = PDF_DATAAVAIL_FIRSTPAGE; | |
804 } else { | |
805 if (m_docStatus == PDF_DATAAVAIL_ERROR) | |
806 return FALSE; | |
807 m_docStatus = PDF_DATAAVAIL_END; | |
808 } | |
809 return TRUE; | |
810 } | |
811 | |
812 pHints->AddSegment(0, req_size); | |
813 return FALSE; | |
814 } | |
815 | |
816 FX_BOOL CPDF_DataAvail::CheckFirstPage(IFX_DownloadHints* pHints) { | |
817 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
818 CPDF_Object* pEndOffSet = pDict ? pDict->GetElement("E") : NULL; | |
819 if (!pEndOffSet) { | |
820 m_docStatus = PDF_DATAAVAIL_ERROR; | |
821 return FALSE; | |
822 } | |
823 | |
824 CPDF_Object* pXRefOffset = pDict ? pDict->GetElement("T") : NULL; | |
825 if (!pXRefOffset) { | |
826 m_docStatus = PDF_DATAAVAIL_ERROR; | |
827 return FALSE; | |
828 } | |
829 | |
830 CPDF_Object* pFileLen = pDict ? pDict->GetElement("L") : NULL; | |
831 if (!pFileLen) { | |
832 m_docStatus = PDF_DATAAVAIL_ERROR; | |
833 return FALSE; | |
834 } | |
835 | |
836 FX_BOOL bNeedDownLoad = FALSE; | |
837 if (pEndOffSet->IsNumber()) { | |
838 FX_DWORD dwEnd = pEndOffSet->GetInteger(); | |
839 dwEnd += 512; | |
840 if ((FX_FILESIZE)dwEnd > m_dwFileLen) | |
841 dwEnd = (FX_DWORD)m_dwFileLen; | |
842 | |
843 int32_t iStartPos = (int32_t)(m_dwFileLen > 1024 ? 1024 : m_dwFileLen); | |
844 int32_t iSize = dwEnd > 1024 ? dwEnd - 1024 : 0; | |
845 if (!m_pFileAvail->IsDataAvail(iStartPos, iSize)) { | |
846 pHints->AddSegment(iStartPos, iSize); | |
847 bNeedDownLoad = TRUE; | |
848 } | |
849 } | |
850 | |
851 m_dwLastXRefOffset = 0; | |
852 FX_FILESIZE dwFileLen = 0; | |
853 if (pXRefOffset->IsNumber()) | |
854 m_dwLastXRefOffset = pXRefOffset->GetInteger(); | |
855 | |
856 if (pFileLen->IsNumber()) | |
857 dwFileLen = pFileLen->GetInteger(); | |
858 | |
859 if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, | |
860 (FX_DWORD)(dwFileLen - m_dwLastXRefOffset))) { | |
861 if (m_docStatus == PDF_DATAAVAIL_FIRSTPAGE) { | |
862 FX_DWORD dwSize = (FX_DWORD)(dwFileLen - m_dwLastXRefOffset); | |
863 FX_FILESIZE offset = m_dwLastXRefOffset; | |
864 if (dwSize < 512 && dwFileLen > 512) { | |
865 dwSize = 512; | |
866 offset = dwFileLen - 512; | |
867 } | |
868 pHints->AddSegment(offset, dwSize); | |
869 } | |
870 } else { | |
871 m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; | |
872 } | |
873 | |
874 if (bNeedDownLoad || m_docStatus != PDF_DATAAVAIL_FIRSTPAGE_PREPARE) { | |
875 m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; | |
876 return FALSE; | |
877 } | |
878 | |
879 m_docStatus = | |
880 m_bSupportHintTable ? PDF_DATAAVAIL_HINTTABLE : PDF_DATAAVAIL_DONE; | |
881 return TRUE; | |
882 } | |
883 | |
884 FX_BOOL CPDF_DataAvail::IsDataAvail(FX_FILESIZE offset, | |
885 FX_DWORD size, | |
886 IFX_DownloadHints* pHints) { | |
887 if (offset > m_dwFileLen) | |
888 return TRUE; | |
889 | |
890 FX_SAFE_DWORD safeSize = pdfium::base::checked_cast<FX_DWORD>(offset); | |
891 safeSize += size; | |
892 safeSize += 512; | |
893 if (!safeSize.IsValid() || safeSize.ValueOrDie() > m_dwFileLen) | |
894 size = m_dwFileLen - offset; | |
895 else | |
896 size += 512; | |
897 | |
898 if (!m_pFileAvail->IsDataAvail(offset, size)) { | |
899 pHints->AddSegment(offset, size); | |
900 return FALSE; | |
901 } | |
902 return TRUE; | |
903 } | |
904 | |
905 FX_BOOL CPDF_DataAvail::CheckHintTables(IFX_DownloadHints* pHints) { | |
906 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
907 if (!pDict) { | |
908 m_docStatus = PDF_DATAAVAIL_ERROR; | |
909 return FALSE; | |
910 } | |
911 | |
912 if (!pDict->KeyExist("H") || !pDict->KeyExist("O") || !pDict->KeyExist("N")) { | |
913 m_docStatus = PDF_DATAAVAIL_ERROR; | |
914 return FALSE; | |
915 } | |
916 | |
917 int nPageCount = pDict->GetElementValue("N")->GetInteger(); | |
918 if (nPageCount <= 1) { | |
919 m_docStatus = PDF_DATAAVAIL_DONE; | |
920 return TRUE; | |
921 } | |
922 | |
923 CPDF_Array* pHintStreamRange = pDict->GetArrayBy("H"); | |
924 FX_FILESIZE szHSStart = | |
925 pHintStreamRange->GetElementValue(0) | |
926 ? pHintStreamRange->GetElementValue(0)->GetInteger() | |
927 : 0; | |
928 FX_FILESIZE szHSLength = | |
929 pHintStreamRange->GetElementValue(1) | |
930 ? pHintStreamRange->GetElementValue(1)->GetInteger() | |
931 : 0; | |
932 if (szHSStart < 0 || szHSLength <= 0) { | |
933 m_docStatus = PDF_DATAAVAIL_ERROR; | |
934 return FALSE; | |
935 } | |
936 | |
937 if (!IsDataAvail(szHSStart, szHSLength, pHints)) | |
938 return FALSE; | |
939 | |
940 m_syntaxParser.InitParser(m_pFileRead, m_dwHeaderOffset); | |
941 | |
942 std::unique_ptr<CPDF_HintTables> pHintTables( | |
943 new CPDF_HintTables(this, pDict)); | |
944 std::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> pHintStream( | |
945 ParseIndirectObjectAt(szHSStart, 0)); | |
946 CPDF_Stream* pStream = ToStream(pHintStream.get()); | |
947 if (pStream && pHintTables->LoadHintStream(pStream)) | |
948 m_pHintTables = std::move(pHintTables); | |
949 | |
950 m_docStatus = PDF_DATAAVAIL_DONE; | |
951 return TRUE; | |
952 } | |
953 | |
954 CPDF_Object* CPDF_DataAvail::ParseIndirectObjectAt( | |
955 FX_FILESIZE pos, | |
956 FX_DWORD objnum, | |
957 CPDF_IndirectObjectHolder* pObjList) { | |
958 FX_FILESIZE SavedPos = m_syntaxParser.SavePos(); | |
959 m_syntaxParser.RestorePos(pos); | |
960 | |
961 bool bIsNumber; | |
962 CFX_ByteString word = m_syntaxParser.GetNextWord(&bIsNumber); | |
963 if (!bIsNumber) | |
964 return nullptr; | |
965 | |
966 FX_DWORD parser_objnum = FXSYS_atoui(word); | |
967 if (objnum && parser_objnum != objnum) | |
968 return nullptr; | |
969 | |
970 word = m_syntaxParser.GetNextWord(&bIsNumber); | |
971 if (!bIsNumber) | |
972 return nullptr; | |
973 | |
974 FX_DWORD gennum = FXSYS_atoui(word); | |
975 if (m_syntaxParser.GetKeyword() != "obj") { | |
976 m_syntaxParser.RestorePos(SavedPos); | |
977 return nullptr; | |
978 } | |
979 | |
980 CPDF_Object* pObj = | |
981 m_syntaxParser.GetObject(pObjList, parser_objnum, gennum, true); | |
982 m_syntaxParser.RestorePos(SavedPos); | |
983 return pObj; | |
984 } | |
985 | |
986 IPDF_DataAvail::DocLinearizationStatus CPDF_DataAvail::IsLinearizedPDF() { | |
987 FX_DWORD req_size = 1024; | |
988 if (!m_pFileAvail->IsDataAvail(0, req_size)) | |
989 return LinearizationUnknown; | |
990 | |
991 if (!m_pFileRead) | |
992 return NotLinearized; | |
993 | |
994 FX_FILESIZE dwSize = m_pFileRead->GetSize(); | |
995 if (dwSize < (FX_FILESIZE)req_size) | |
996 return LinearizationUnknown; | |
997 | |
998 uint8_t buffer[1024]; | |
999 m_pFileRead->ReadBlock(buffer, 0, req_size); | |
1000 if (IsLinearizedFile(buffer, req_size)) | |
1001 return Linearized; | |
1002 | |
1003 return NotLinearized; | |
1004 } | |
1005 FX_BOOL CPDF_DataAvail::IsLinearizedFile(uint8_t* pData, FX_DWORD dwLen) { | |
1006 ScopedFileStream file(FX_CreateMemoryStream(pData, (size_t)dwLen, FALSE)); | |
1007 | |
1008 int32_t offset = GetHeaderOffset(file.get()); | |
1009 if (offset == -1) { | |
1010 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1011 return FALSE; | |
1012 } | |
1013 | |
1014 m_dwHeaderOffset = offset; | |
1015 m_syntaxParser.InitParser(file.get(), offset); | |
1016 m_syntaxParser.RestorePos(m_syntaxParser.m_HeaderOffset + 9); | |
1017 | |
1018 bool bNumber; | |
1019 CFX_ByteString wordObjNum = m_syntaxParser.GetNextWord(&bNumber); | |
1020 if (!bNumber) | |
1021 return FALSE; | |
1022 | |
1023 FX_DWORD objnum = FXSYS_atoui(wordObjNum); | |
1024 if (m_pLinearized) { | |
1025 m_pLinearized->Release(); | |
1026 m_pLinearized = nullptr; | |
1027 } | |
1028 | |
1029 m_pLinearized = | |
1030 ParseIndirectObjectAt(m_syntaxParser.m_HeaderOffset + 9, objnum); | |
1031 if (!m_pLinearized) | |
1032 return FALSE; | |
1033 | |
1034 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
1035 if (pDict && pDict->GetElement("Linearized")) { | |
1036 CPDF_Object* pLen = pDict->GetElement("L"); | |
1037 if (!pLen) | |
1038 return FALSE; | |
1039 | |
1040 if ((FX_FILESIZE)pLen->GetInteger() != m_pFileRead->GetSize()) | |
1041 return FALSE; | |
1042 | |
1043 m_bLinearized = TRUE; | |
1044 | |
1045 if (CPDF_Number* pNo = ToNumber(pDict->GetElement("P"))) | |
1046 m_dwFirstPageNo = pNo->GetInteger(); | |
1047 | |
1048 return TRUE; | |
1049 } | |
1050 return FALSE; | |
1051 } | |
1052 | |
1053 FX_BOOL CPDF_DataAvail::CheckEnd(IFX_DownloadHints* pHints) { | |
1054 FX_DWORD req_pos = (FX_DWORD)(m_dwFileLen > 1024 ? m_dwFileLen - 1024 : 0); | |
1055 FX_DWORD dwSize = (FX_DWORD)(m_dwFileLen - req_pos); | |
1056 | |
1057 if (m_pFileAvail->IsDataAvail(req_pos, dwSize)) { | |
1058 uint8_t buffer[1024]; | |
1059 m_pFileRead->ReadBlock(buffer, req_pos, dwSize); | |
1060 | |
1061 ScopedFileStream file(FX_CreateMemoryStream(buffer, (size_t)dwSize, FALSE)); | |
1062 m_syntaxParser.InitParser(file.get(), 0); | |
1063 m_syntaxParser.RestorePos(dwSize - 1); | |
1064 | |
1065 if (m_syntaxParser.SearchWord("startxref", TRUE, FALSE, dwSize)) { | |
1066 m_syntaxParser.GetNextWord(nullptr); | |
1067 | |
1068 bool bNumber; | |
1069 CFX_ByteString xrefpos_str = m_syntaxParser.GetNextWord(&bNumber); | |
1070 if (!bNumber) { | |
1071 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1072 return FALSE; | |
1073 } | |
1074 | |
1075 m_dwXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str); | |
1076 if (!m_dwXRefOffset || m_dwXRefOffset > m_dwFileLen) { | |
1077 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
1078 return TRUE; | |
1079 } | |
1080 | |
1081 m_dwLastXRefOffset = m_dwXRefOffset; | |
1082 SetStartOffset(m_dwXRefOffset); | |
1083 m_docStatus = PDF_DATAAVAIL_CROSSREF; | |
1084 return TRUE; | |
1085 } | |
1086 | |
1087 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
1088 return TRUE; | |
1089 } | |
1090 | |
1091 pHints->AddSegment(req_pos, dwSize); | |
1092 return FALSE; | |
1093 } | |
1094 | |
1095 int32_t CPDF_DataAvail::CheckCrossRefStream(IFX_DownloadHints* pHints, | |
1096 FX_FILESIZE& xref_offset) { | |
1097 xref_offset = 0; | |
1098 FX_DWORD req_size = | |
1099 (FX_DWORD)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
1100 | |
1101 if (m_pFileAvail->IsDataAvail(m_Pos, req_size)) { | |
1102 int32_t iSize = (int32_t)(m_Pos + req_size - m_dwCurrentXRefSteam); | |
1103 CFX_BinaryBuf buf(iSize); | |
1104 uint8_t* pBuf = buf.GetBuffer(); | |
1105 | |
1106 m_pFileRead->ReadBlock(pBuf, m_dwCurrentXRefSteam, iSize); | |
1107 | |
1108 ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); | |
1109 m_parser.m_pSyntax->InitParser(file.get(), 0); | |
1110 | |
1111 bool bNumber; | |
1112 CFX_ByteString objnum = m_parser.m_pSyntax->GetNextWord(&bNumber); | |
1113 if (!bNumber) | |
1114 return -1; | |
1115 | |
1116 FX_DWORD objNum = FXSYS_atoui(objnum); | |
1117 CPDF_Object* pObj = m_parser.ParseIndirectObjectAt(nullptr, 0, objNum); | |
1118 if (!pObj) { | |
1119 m_Pos += m_parser.m_pSyntax->SavePos(); | |
1120 return 0; | |
1121 } | |
1122 | |
1123 CPDF_Dictionary* pDict = pObj->GetDict(); | |
1124 CPDF_Name* pName = ToName(pDict ? pDict->GetElement("Type") : nullptr); | |
1125 if (pName) { | |
1126 if (pName->GetString() == "XRef") { | |
1127 m_Pos += m_parser.m_pSyntax->SavePos(); | |
1128 xref_offset = pObj->GetDict()->GetIntegerBy("Prev"); | |
1129 pObj->Release(); | |
1130 return 1; | |
1131 } | |
1132 } | |
1133 pObj->Release(); | |
1134 return -1; | |
1135 } | |
1136 pHints->AddSegment(m_Pos, req_size); | |
1137 return 0; | |
1138 } | |
1139 | |
1140 inline void CPDF_DataAvail::SetStartOffset(FX_FILESIZE dwOffset) { | |
1141 m_Pos = dwOffset; | |
1142 } | |
1143 | |
1144 FX_BOOL CPDF_DataAvail::GetNextToken(CFX_ByteString& token) { | |
1145 uint8_t ch; | |
1146 if (!GetNextChar(ch)) | |
1147 return FALSE; | |
1148 | |
1149 while (1) { | |
1150 while (PDFCharIsWhitespace(ch)) { | |
1151 if (!GetNextChar(ch)) | |
1152 return FALSE; | |
1153 } | |
1154 | |
1155 if (ch != '%') | |
1156 break; | |
1157 | |
1158 while (1) { | |
1159 if (!GetNextChar(ch)) | |
1160 return FALSE; | |
1161 if (PDFCharIsLineEnding(ch)) | |
1162 break; | |
1163 } | |
1164 } | |
1165 | |
1166 uint8_t buffer[256]; | |
1167 FX_DWORD index = 0; | |
1168 if (PDFCharIsDelimiter(ch)) { | |
1169 buffer[index++] = ch; | |
1170 if (ch == '/') { | |
1171 while (1) { | |
1172 if (!GetNextChar(ch)) | |
1173 return FALSE; | |
1174 | |
1175 if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { | |
1176 m_Pos--; | |
1177 CFX_ByteString ret(buffer, index); | |
1178 token = ret; | |
1179 return TRUE; | |
1180 } | |
1181 | |
1182 if (index < sizeof(buffer)) | |
1183 buffer[index++] = ch; | |
1184 } | |
1185 } else if (ch == '<') { | |
1186 if (!GetNextChar(ch)) | |
1187 return FALSE; | |
1188 | |
1189 if (ch == '<') | |
1190 buffer[index++] = ch; | |
1191 else | |
1192 m_Pos--; | |
1193 } else if (ch == '>') { | |
1194 if (!GetNextChar(ch)) | |
1195 return FALSE; | |
1196 | |
1197 if (ch == '>') | |
1198 buffer[index++] = ch; | |
1199 else | |
1200 m_Pos--; | |
1201 } | |
1202 | |
1203 CFX_ByteString ret(buffer, index); | |
1204 token = ret; | |
1205 return TRUE; | |
1206 } | |
1207 | |
1208 while (1) { | |
1209 if (index < sizeof(buffer)) | |
1210 buffer[index++] = ch; | |
1211 | |
1212 if (!GetNextChar(ch)) | |
1213 return FALSE; | |
1214 | |
1215 if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { | |
1216 m_Pos--; | |
1217 break; | |
1218 } | |
1219 } | |
1220 | |
1221 token = CFX_ByteString(buffer, index); | |
1222 return TRUE; | |
1223 } | |
1224 | |
1225 FX_BOOL CPDF_DataAvail::GetNextChar(uint8_t& ch) { | |
1226 FX_FILESIZE pos = m_Pos; | |
1227 if (pos >= m_dwFileLen) | |
1228 return FALSE; | |
1229 | |
1230 if (m_bufferOffset >= pos || | |
1231 (FX_FILESIZE)(m_bufferOffset + m_bufferSize) <= pos) { | |
1232 FX_FILESIZE read_pos = pos; | |
1233 FX_DWORD read_size = 512; | |
1234 if ((FX_FILESIZE)read_size > m_dwFileLen) | |
1235 read_size = (FX_DWORD)m_dwFileLen; | |
1236 | |
1237 if ((FX_FILESIZE)(read_pos + read_size) > m_dwFileLen) | |
1238 read_pos = m_dwFileLen - read_size; | |
1239 | |
1240 if (!m_pFileRead->ReadBlock(m_bufferData, read_pos, read_size)) | |
1241 return FALSE; | |
1242 | |
1243 m_bufferOffset = read_pos; | |
1244 m_bufferSize = read_size; | |
1245 } | |
1246 ch = m_bufferData[pos - m_bufferOffset]; | |
1247 m_Pos++; | |
1248 return TRUE; | |
1249 } | |
1250 | |
1251 FX_BOOL CPDF_DataAvail::CheckCrossRefItem(IFX_DownloadHints* pHints) { | |
1252 int32_t iSize = 0; | |
1253 CFX_ByteString token; | |
1254 while (1) { | |
1255 if (!GetNextToken(token)) { | |
1256 iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
1257 pHints->AddSegment(m_Pos, iSize); | |
1258 return FALSE; | |
1259 } | |
1260 | |
1261 if (token == "trailer") { | |
1262 m_dwTrailerOffset = m_Pos; | |
1263 m_docStatus = PDF_DATAAVAIL_TRAILER; | |
1264 return TRUE; | |
1265 } | |
1266 } | |
1267 } | |
1268 | |
1269 FX_BOOL CPDF_DataAvail::CheckAllCrossRefStream(IFX_DownloadHints* pHints) { | |
1270 FX_FILESIZE xref_offset = 0; | |
1271 | |
1272 int32_t nRet = CheckCrossRefStream(pHints, xref_offset); | |
1273 if (nRet == 1) { | |
1274 if (!xref_offset) { | |
1275 m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF; | |
1276 } else { | |
1277 m_dwCurrentXRefSteam = xref_offset; | |
1278 m_Pos = xref_offset; | |
1279 } | |
1280 return TRUE; | |
1281 } | |
1282 | |
1283 if (nRet == -1) | |
1284 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1285 return FALSE; | |
1286 } | |
1287 | |
1288 FX_BOOL CPDF_DataAvail::CheckCrossRef(IFX_DownloadHints* pHints) { | |
1289 int32_t iSize = 0; | |
1290 CFX_ByteString token; | |
1291 if (!GetNextToken(token)) { | |
1292 iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
1293 pHints->AddSegment(m_Pos, iSize); | |
1294 return FALSE; | |
1295 } | |
1296 | |
1297 if (token == "xref") { | |
1298 while (1) { | |
1299 if (!GetNextToken(token)) { | |
1300 iSize = | |
1301 (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
1302 pHints->AddSegment(m_Pos, iSize); | |
1303 m_docStatus = PDF_DATAAVAIL_CROSSREF_ITEM; | |
1304 return FALSE; | |
1305 } | |
1306 | |
1307 if (token == "trailer") { | |
1308 m_dwTrailerOffset = m_Pos; | |
1309 m_docStatus = PDF_DATAAVAIL_TRAILER; | |
1310 return TRUE; | |
1311 } | |
1312 } | |
1313 } else { | |
1314 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
1315 return TRUE; | |
1316 } | |
1317 return FALSE; | |
1318 } | |
1319 | |
1320 FX_BOOL CPDF_DataAvail::CheckTrailerAppend(IFX_DownloadHints* pHints) { | |
1321 if (m_Pos < m_dwFileLen) { | |
1322 FX_FILESIZE dwAppendPos = m_Pos + m_syntaxParser.SavePos(); | |
1323 int32_t iSize = (int32_t)( | |
1324 dwAppendPos + 512 > m_dwFileLen ? m_dwFileLen - dwAppendPos : 512); | |
1325 | |
1326 if (!m_pFileAvail->IsDataAvail(dwAppendPos, iSize)) { | |
1327 pHints->AddSegment(dwAppendPos, iSize); | |
1328 return FALSE; | |
1329 } | |
1330 } | |
1331 | |
1332 if (m_dwPrevXRefOffset) { | |
1333 SetStartOffset(m_dwPrevXRefOffset); | |
1334 m_docStatus = PDF_DATAAVAIL_CROSSREF; | |
1335 } else { | |
1336 m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF; | |
1337 } | |
1338 return TRUE; | |
1339 } | |
1340 | |
1341 FX_BOOL CPDF_DataAvail::CheckTrailer(IFX_DownloadHints* pHints) { | |
1342 int32_t iTrailerSize = | |
1343 (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
1344 if (m_pFileAvail->IsDataAvail(m_Pos, iTrailerSize)) { | |
1345 int32_t iSize = (int32_t)(m_Pos + iTrailerSize - m_dwTrailerOffset); | |
1346 CFX_BinaryBuf buf(iSize); | |
1347 uint8_t* pBuf = buf.GetBuffer(); | |
1348 if (!pBuf) { | |
1349 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1350 return FALSE; | |
1351 } | |
1352 | |
1353 if (!m_pFileRead->ReadBlock(pBuf, m_dwTrailerOffset, iSize)) | |
1354 return FALSE; | |
1355 | |
1356 ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); | |
1357 m_syntaxParser.InitParser(file.get(), 0); | |
1358 | |
1359 std::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> pTrailer( | |
1360 m_syntaxParser.GetObject(nullptr, 0, 0, true)); | |
1361 if (!pTrailer) { | |
1362 m_Pos += m_syntaxParser.SavePos(); | |
1363 pHints->AddSegment(m_Pos, iTrailerSize); | |
1364 return FALSE; | |
1365 } | |
1366 | |
1367 if (!pTrailer->IsDictionary()) | |
1368 return FALSE; | |
1369 | |
1370 CPDF_Dictionary* pTrailerDict = pTrailer->GetDict(); | |
1371 CPDF_Object* pEncrypt = pTrailerDict->GetElement("Encrypt"); | |
1372 if (ToReference(pEncrypt)) { | |
1373 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
1374 return TRUE; | |
1375 } | |
1376 | |
1377 FX_DWORD xrefpos = GetDirectInteger(pTrailerDict, "Prev"); | |
1378 if (xrefpos) { | |
1379 m_dwPrevXRefOffset = GetDirectInteger(pTrailerDict, "XRefStm"); | |
1380 if (m_dwPrevXRefOffset) { | |
1381 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
1382 } else { | |
1383 m_dwPrevXRefOffset = xrefpos; | |
1384 if (m_dwPrevXRefOffset >= m_dwFileLen) { | |
1385 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
1386 } else { | |
1387 SetStartOffset(m_dwPrevXRefOffset); | |
1388 m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; | |
1389 } | |
1390 } | |
1391 return TRUE; | |
1392 } | |
1393 m_dwPrevXRefOffset = 0; | |
1394 m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; | |
1395 return TRUE; | |
1396 } | |
1397 pHints->AddSegment(m_Pos, iTrailerSize); | |
1398 return FALSE; | |
1399 } | |
1400 | |
1401 FX_BOOL CPDF_DataAvail::CheckPage(int32_t iPage, IFX_DownloadHints* pHints) { | |
1402 while (TRUE) { | |
1403 switch (m_docStatus) { | |
1404 case PDF_DATAAVAIL_PAGETREE: | |
1405 if (!LoadDocPages(pHints)) | |
1406 return FALSE; | |
1407 break; | |
1408 case PDF_DATAAVAIL_PAGE: | |
1409 if (!LoadDocPage(iPage, pHints)) | |
1410 return FALSE; | |
1411 break; | |
1412 case PDF_DATAAVAIL_ERROR: | |
1413 return LoadAllFile(pHints); | |
1414 default: | |
1415 m_bPagesTreeLoad = TRUE; | |
1416 m_bPagesLoad = TRUE; | |
1417 m_bCurPageDictLoadOK = TRUE; | |
1418 m_docStatus = PDF_DATAAVAIL_PAGE; | |
1419 return TRUE; | |
1420 } | |
1421 } | |
1422 } | |
1423 | |
1424 FX_BOOL CPDF_DataAvail::CheckArrayPageNode(FX_DWORD dwPageNo, | |
1425 CPDF_PageNode* pPageNode, | |
1426 IFX_DownloadHints* pHints) { | |
1427 FX_BOOL bExist = FALSE; | |
1428 CPDF_Object* pPages = GetObject(dwPageNo, pHints, &bExist); | |
1429 if (!bExist) { | |
1430 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1431 return FALSE; | |
1432 } | |
1433 | |
1434 if (!pPages) { | |
1435 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
1436 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1437 return FALSE; | |
1438 } | |
1439 return FALSE; | |
1440 } | |
1441 | |
1442 CPDF_Array* pArray = pPages->AsArray(); | |
1443 if (!pArray) { | |
1444 pPages->Release(); | |
1445 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1446 return FALSE; | |
1447 } | |
1448 | |
1449 pPageNode->m_type = PDF_PAGENODE_PAGES; | |
1450 for (FX_DWORD i = 0; i < pArray->GetCount(); ++i) { | |
1451 CPDF_Reference* pKid = ToReference(pArray->GetElement(i)); | |
1452 if (!pKid) | |
1453 continue; | |
1454 | |
1455 CPDF_PageNode* pNode = new CPDF_PageNode(); | |
1456 pPageNode->m_childNode.Add(pNode); | |
1457 pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
1458 } | |
1459 pPages->Release(); | |
1460 return TRUE; | |
1461 } | |
1462 | |
1463 FX_BOOL CPDF_DataAvail::CheckUnkownPageNode(FX_DWORD dwPageNo, | |
1464 CPDF_PageNode* pPageNode, | |
1465 IFX_DownloadHints* pHints) { | |
1466 FX_BOOL bExist = FALSE; | |
1467 CPDF_Object* pPage = GetObject(dwPageNo, pHints, &bExist); | |
1468 if (!bExist) { | |
1469 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1470 return FALSE; | |
1471 } | |
1472 | |
1473 if (!pPage) { | |
1474 if (m_docStatus == PDF_DATAAVAIL_ERROR) | |
1475 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1476 return FALSE; | |
1477 } | |
1478 | |
1479 if (pPage->IsArray()) { | |
1480 pPageNode->m_dwPageNo = dwPageNo; | |
1481 pPageNode->m_type = PDF_PAGENODE_ARRAY; | |
1482 pPage->Release(); | |
1483 return TRUE; | |
1484 } | |
1485 | |
1486 if (!pPage->IsDictionary()) { | |
1487 pPage->Release(); | |
1488 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1489 return FALSE; | |
1490 } | |
1491 | |
1492 pPageNode->m_dwPageNo = dwPageNo; | |
1493 CPDF_Dictionary* pDict = pPage->GetDict(); | |
1494 CFX_ByteString type = pDict->GetStringBy("Type"); | |
1495 if (type == "Pages") { | |
1496 pPageNode->m_type = PDF_PAGENODE_PAGES; | |
1497 CPDF_Object* pKids = pDict->GetElement("Kids"); | |
1498 if (!pKids) { | |
1499 m_docStatus = PDF_DATAAVAIL_PAGE; | |
1500 return TRUE; | |
1501 } | |
1502 | |
1503 switch (pKids->GetType()) { | |
1504 case CPDF_Object::REFERENCE: { | |
1505 CPDF_Reference* pKid = pKids->AsReference(); | |
1506 CPDF_PageNode* pNode = new CPDF_PageNode(); | |
1507 pPageNode->m_childNode.Add(pNode); | |
1508 pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
1509 } break; | |
1510 case CPDF_Object::ARRAY: { | |
1511 CPDF_Array* pKidsArray = pKids->AsArray(); | |
1512 for (FX_DWORD i = 0; i < pKidsArray->GetCount(); ++i) { | |
1513 CPDF_Reference* pKid = ToReference(pKidsArray->GetElement(i)); | |
1514 if (!pKid) | |
1515 continue; | |
1516 | |
1517 CPDF_PageNode* pNode = new CPDF_PageNode(); | |
1518 pPageNode->m_childNode.Add(pNode); | |
1519 pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
1520 } | |
1521 } break; | |
1522 default: | |
1523 break; | |
1524 } | |
1525 } else if (type == "Page") { | |
1526 pPageNode->m_type = PDF_PAGENODE_PAGE; | |
1527 } else { | |
1528 pPage->Release(); | |
1529 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1530 return FALSE; | |
1531 } | |
1532 pPage->Release(); | |
1533 return TRUE; | |
1534 } | |
1535 | |
1536 FX_BOOL CPDF_DataAvail::CheckPageNode(CPDF_PageNode& pageNodes, | |
1537 int32_t iPage, | |
1538 int32_t& iCount, | |
1539 IFX_DownloadHints* pHints, | |
1540 int level) { | |
1541 if (level >= kMaxPageRecursionDepth) | |
1542 return FALSE; | |
1543 | |
1544 int32_t iSize = pageNodes.m_childNode.GetSize(); | |
1545 if (iSize <= 0 || iPage >= iSize) { | |
1546 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1547 return FALSE; | |
1548 } | |
1549 | |
1550 for (int32_t i = 0; i < iSize; ++i) { | |
1551 CPDF_PageNode* pNode = pageNodes.m_childNode.GetAt(i); | |
1552 if (!pNode) | |
1553 continue; | |
1554 | |
1555 switch (pNode->m_type) { | |
1556 case PDF_PAGENODE_UNKNOWN: | |
1557 if (!CheckUnkownPageNode(pNode->m_dwPageNo, pNode, pHints)) { | |
1558 return FALSE; | |
1559 } | |
1560 --i; | |
1561 break; | |
1562 case PDF_PAGENODE_PAGE: | |
1563 iCount++; | |
1564 if (iPage == iCount && m_pDocument) | |
1565 m_pDocument->m_PageList.SetAt(iPage, pNode->m_dwPageNo); | |
1566 break; | |
1567 case PDF_PAGENODE_PAGES: | |
1568 if (!CheckPageNode(*pNode, iPage, iCount, pHints, level + 1)) | |
1569 return FALSE; | |
1570 break; | |
1571 case PDF_PAGENODE_ARRAY: | |
1572 if (!CheckArrayPageNode(pNode->m_dwPageNo, pNode, pHints)) | |
1573 return FALSE; | |
1574 --i; | |
1575 break; | |
1576 } | |
1577 | |
1578 if (iPage == iCount) { | |
1579 m_docStatus = PDF_DATAAVAIL_DONE; | |
1580 return TRUE; | |
1581 } | |
1582 } | |
1583 return TRUE; | |
1584 } | |
1585 | |
1586 FX_BOOL CPDF_DataAvail::LoadDocPage(int32_t iPage, IFX_DownloadHints* pHints) { | |
1587 if (m_pDocument->GetPageCount() <= iPage || | |
1588 m_pDocument->m_PageList.GetAt(iPage)) { | |
1589 m_docStatus = PDF_DATAAVAIL_DONE; | |
1590 return TRUE; | |
1591 } | |
1592 | |
1593 if (m_pageNodes.m_type == PDF_PAGENODE_PAGE) { | |
1594 if (iPage == 0) { | |
1595 m_docStatus = PDF_DATAAVAIL_DONE; | |
1596 return TRUE; | |
1597 } | |
1598 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1599 return TRUE; | |
1600 } | |
1601 int32_t iCount = -1; | |
1602 return CheckPageNode(m_pageNodes, iPage, iCount, pHints, 0); | |
1603 } | |
1604 | |
1605 FX_BOOL CPDF_DataAvail::CheckPageCount(IFX_DownloadHints* pHints) { | |
1606 FX_BOOL bExist = FALSE; | |
1607 CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist); | |
1608 if (!bExist) { | |
1609 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1610 return FALSE; | |
1611 } | |
1612 | |
1613 if (!pPages) | |
1614 return FALSE; | |
1615 | |
1616 CPDF_Dictionary* pPagesDict = pPages->GetDict(); | |
1617 if (!pPagesDict) { | |
1618 pPages->Release(); | |
1619 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1620 return FALSE; | |
1621 } | |
1622 | |
1623 if (!pPagesDict->KeyExist("Kids")) { | |
1624 pPages->Release(); | |
1625 return TRUE; | |
1626 } | |
1627 | |
1628 int count = pPagesDict->GetIntegerBy("Count"); | |
1629 if (count > 0) { | |
1630 pPages->Release(); | |
1631 return TRUE; | |
1632 } | |
1633 | |
1634 pPages->Release(); | |
1635 return FALSE; | |
1636 } | |
1637 | |
1638 FX_BOOL CPDF_DataAvail::LoadDocPages(IFX_DownloadHints* pHints) { | |
1639 if (!CheckUnkownPageNode(m_PagesObjNum, &m_pageNodes, pHints)) | |
1640 return FALSE; | |
1641 | |
1642 if (CheckPageCount(pHints)) { | |
1643 m_docStatus = PDF_DATAAVAIL_PAGE; | |
1644 return TRUE; | |
1645 } | |
1646 | |
1647 m_bTotalLoadPageTree = TRUE; | |
1648 return FALSE; | |
1649 } | |
1650 | |
1651 FX_BOOL CPDF_DataAvail::LoadPages(IFX_DownloadHints* pHints) { | |
1652 while (!m_bPagesTreeLoad) { | |
1653 if (!CheckPageStatus(pHints)) | |
1654 return FALSE; | |
1655 } | |
1656 | |
1657 if (m_bPagesLoad) | |
1658 return TRUE; | |
1659 | |
1660 m_pDocument->LoadPages(); | |
1661 return FALSE; | |
1662 } | |
1663 | |
1664 IPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedData( | |
1665 IFX_DownloadHints* pHints) { | |
1666 if (m_bLinearedDataOK) | |
1667 return DataAvailable; | |
1668 | |
1669 if (!m_bMainXRefLoadTried) { | |
1670 FX_SAFE_DWORD data_size = m_dwFileLen; | |
1671 data_size -= m_dwLastXRefOffset; | |
1672 if (!data_size.IsValid()) | |
1673 return DataError; | |
1674 | |
1675 if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, | |
1676 data_size.ValueOrDie())) { | |
1677 pHints->AddSegment(m_dwLastXRefOffset, data_size.ValueOrDie()); | |
1678 return DataNotAvailable; | |
1679 } | |
1680 | |
1681 CPDF_Parser::Error eRet = | |
1682 m_pDocument->GetParser()->LoadLinearizedMainXRefTable(); | |
1683 m_bMainXRefLoadTried = TRUE; | |
1684 if (eRet != CPDF_Parser::SUCCESS) | |
1685 return DataError; | |
1686 | |
1687 if (!PreparePageItem()) | |
1688 return DataNotAvailable; | |
1689 | |
1690 m_bMainXRefLoadedOK = TRUE; | |
1691 m_bLinearedDataOK = TRUE; | |
1692 } | |
1693 | |
1694 return m_bLinearedDataOK ? DataAvailable : DataNotAvailable; | |
1695 } | |
1696 | |
1697 FX_BOOL CPDF_DataAvail::CheckPageAnnots(int32_t iPage, | |
1698 IFX_DownloadHints* pHints) { | |
1699 if (!m_objs_array.GetSize()) { | |
1700 m_objs_array.RemoveAll(); | |
1701 m_ObjectSet.clear(); | |
1702 | |
1703 CPDF_Dictionary* pPageDict = m_pDocument->GetPage(iPage); | |
1704 if (!pPageDict) | |
1705 return TRUE; | |
1706 | |
1707 CPDF_Object* pAnnots = pPageDict->GetElement("Annots"); | |
1708 if (!pAnnots) | |
1709 return TRUE; | |
1710 | |
1711 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
1712 obj_array.Add(pAnnots); | |
1713 | |
1714 FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); | |
1715 if (bRet) | |
1716 m_objs_array.RemoveAll(); | |
1717 | |
1718 return bRet; | |
1719 } | |
1720 | |
1721 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
1722 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
1723 m_objs_array.RemoveAll(); | |
1724 if (!bRet) | |
1725 m_objs_array.Append(new_objs_array); | |
1726 | |
1727 return bRet; | |
1728 } | |
1729 | |
1730 IPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedFirstPage( | |
1731 int32_t iPage, | |
1732 IFX_DownloadHints* pHints) { | |
1733 if (!m_bAnnotsLoad) { | |
1734 if (!CheckPageAnnots(iPage, pHints)) | |
1735 return DataNotAvailable; | |
1736 m_bAnnotsLoad = TRUE; | |
1737 } | |
1738 | |
1739 DocAvailStatus nRet = CheckLinearizedData(pHints); | |
1740 if (nRet == DataAvailable) | |
1741 m_bPageLoadedOK = FALSE; | |
1742 return nRet; | |
1743 } | |
1744 | |
1745 FX_BOOL CPDF_DataAvail::HaveResourceAncestor(CPDF_Dictionary* pDict) { | |
1746 CFX_AutoRestorer<int> restorer(&s_CurrentDataAvailRecursionDepth); | |
1747 if (++s_CurrentDataAvailRecursionDepth > kMaxDataAvailRecursionDepth) | |
1748 return FALSE; | |
1749 | |
1750 CPDF_Object* pParent = pDict->GetElement("Parent"); | |
1751 if (!pParent) | |
1752 return FALSE; | |
1753 | |
1754 CPDF_Dictionary* pParentDict = pParent->GetDict(); | |
1755 if (!pParentDict) | |
1756 return FALSE; | |
1757 | |
1758 CPDF_Object* pRet = pParentDict->GetElement("Resources"); | |
1759 if (pRet) { | |
1760 m_pPageResource = pRet; | |
1761 return TRUE; | |
1762 } | |
1763 | |
1764 return HaveResourceAncestor(pParentDict); | |
1765 } | |
1766 | |
1767 IPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsPageAvail( | |
1768 int32_t iPage, | |
1769 IFX_DownloadHints* pHints) { | |
1770 if (!m_pDocument) | |
1771 return DataError; | |
1772 | |
1773 if (IsFirstCheck(iPage)) { | |
1774 m_bCurPageDictLoadOK = FALSE; | |
1775 m_bPageLoadedOK = FALSE; | |
1776 m_bAnnotsLoad = FALSE; | |
1777 m_bNeedDownLoadResource = FALSE; | |
1778 m_objs_array.RemoveAll(); | |
1779 m_ObjectSet.clear(); | |
1780 } | |
1781 | |
1782 if (pdfium::ContainsKey(m_pagesLoadState, iPage)) | |
1783 return DataAvailable; | |
1784 | |
1785 if (m_bLinearized) { | |
1786 if ((FX_DWORD)iPage == m_dwFirstPageNo) { | |
1787 DocAvailStatus nRet = CheckLinearizedFirstPage(iPage, pHints); | |
1788 if (nRet == DataAvailable) | |
1789 m_pagesLoadState.insert(iPage); | |
1790 return nRet; | |
1791 } | |
1792 | |
1793 DocAvailStatus nResult = CheckLinearizedData(pHints); | |
1794 if (nResult != DataAvailable) | |
1795 return nResult; | |
1796 | |
1797 if (m_pHintTables) { | |
1798 nResult = m_pHintTables->CheckPage(iPage, pHints); | |
1799 if (nResult != DataAvailable) | |
1800 return nResult; | |
1801 m_pagesLoadState.insert(iPage); | |
1802 return DataAvailable; | |
1803 } | |
1804 | |
1805 if (m_bMainXRefLoadedOK) { | |
1806 if (m_bTotalLoadPageTree) { | |
1807 if (!LoadPages(pHints)) | |
1808 return DataNotAvailable; | |
1809 } else { | |
1810 if (!m_bCurPageDictLoadOK && !CheckPage(iPage, pHints)) | |
1811 return DataNotAvailable; | |
1812 } | |
1813 } else { | |
1814 if (!LoadAllFile(pHints)) | |
1815 return DataNotAvailable; | |
1816 m_pDocument->GetParser()->RebuildCrossRef(); | |
1817 ResetFirstCheck(iPage); | |
1818 return DataAvailable; | |
1819 } | |
1820 } else { | |
1821 if (!m_bTotalLoadPageTree && !m_bCurPageDictLoadOK && | |
1822 !CheckPage(iPage, pHints)) { | |
1823 return DataNotAvailable; | |
1824 } | |
1825 } | |
1826 | |
1827 if (m_bHaveAcroForm && !m_bAcroFormLoad) { | |
1828 if (!CheckAcroFormSubObject(pHints)) | |
1829 return DataNotAvailable; | |
1830 m_bAcroFormLoad = TRUE; | |
1831 } | |
1832 | |
1833 if (!m_bPageLoadedOK) { | |
1834 if (!m_objs_array.GetSize()) { | |
1835 m_objs_array.RemoveAll(); | |
1836 m_ObjectSet.clear(); | |
1837 | |
1838 m_pPageDict = m_pDocument->GetPage(iPage); | |
1839 if (!m_pPageDict) { | |
1840 ResetFirstCheck(iPage); | |
1841 return DataAvailable; | |
1842 } | |
1843 | |
1844 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
1845 obj_array.Add(m_pPageDict); | |
1846 FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); | |
1847 if (!bRet) | |
1848 return DataNotAvailable; | |
1849 | |
1850 m_objs_array.RemoveAll(); | |
1851 } else { | |
1852 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
1853 FX_BOOL bRet = | |
1854 IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
1855 | |
1856 m_objs_array.RemoveAll(); | |
1857 if (!bRet) { | |
1858 m_objs_array.Append(new_objs_array); | |
1859 return DataNotAvailable; | |
1860 } | |
1861 } | |
1862 m_bPageLoadedOK = TRUE; | |
1863 } | |
1864 | |
1865 if (!m_bAnnotsLoad) { | |
1866 if (!CheckPageAnnots(iPage, pHints)) | |
1867 return DataNotAvailable; | |
1868 m_bAnnotsLoad = TRUE; | |
1869 } | |
1870 | |
1871 if (m_pPageDict && !m_bNeedDownLoadResource) { | |
1872 m_pPageResource = m_pPageDict->GetElement("Resources"); | |
1873 if (!m_pPageResource) | |
1874 m_bNeedDownLoadResource = HaveResourceAncestor(m_pPageDict); | |
1875 else | |
1876 m_bNeedDownLoadResource = TRUE; | |
1877 } | |
1878 | |
1879 if (m_bNeedDownLoadResource) { | |
1880 FX_BOOL bRet = CheckResources(pHints); | |
1881 if (!bRet) | |
1882 return DataNotAvailable; | |
1883 m_bNeedDownLoadResource = FALSE; | |
1884 } | |
1885 | |
1886 m_bPageLoadedOK = FALSE; | |
1887 m_bAnnotsLoad = FALSE; | |
1888 m_bCurPageDictLoadOK = FALSE; | |
1889 | |
1890 ResetFirstCheck(iPage); | |
1891 m_pagesLoadState.insert(iPage); | |
1892 return DataAvailable; | |
1893 } | |
1894 | |
1895 FX_BOOL CPDF_DataAvail::CheckResources(IFX_DownloadHints* pHints) { | |
1896 if (!m_objs_array.GetSize()) { | |
1897 m_objs_array.RemoveAll(); | |
1898 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
1899 obj_array.Add(m_pPageResource); | |
1900 | |
1901 FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); | |
1902 if (bRet) | |
1903 m_objs_array.RemoveAll(); | |
1904 return bRet; | |
1905 } | |
1906 | |
1907 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
1908 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
1909 m_objs_array.RemoveAll(); | |
1910 if (!bRet) | |
1911 m_objs_array.Append(new_objs_array); | |
1912 return bRet; | |
1913 } | |
1914 | |
1915 void CPDF_DataAvail::GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, | |
1916 FX_DWORD* pSize) { | |
1917 if (pPos) | |
1918 *pPos = m_dwLastXRefOffset; | |
1919 if (pSize) | |
1920 *pSize = (FX_DWORD)(m_dwFileLen - m_dwLastXRefOffset); | |
1921 } | |
1922 | |
1923 int CPDF_DataAvail::GetPageCount() const { | |
1924 if (m_pLinearized) { | |
1925 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
1926 CPDF_Object* pObj = pDict ? pDict->GetElementValue("N") : nullptr; | |
1927 return pObj ? pObj->GetInteger() : 0; | |
1928 } | |
1929 return m_pDocument ? m_pDocument->GetPageCount() : 0; | |
1930 } | |
1931 | |
1932 CPDF_Dictionary* CPDF_DataAvail::GetPage(int index) { | |
1933 if (!m_pDocument || index < 0 || index >= GetPageCount()) | |
1934 return nullptr; | |
1935 | |
1936 if (m_pLinearized) { | |
1937 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
1938 CPDF_Object* pObj = pDict ? pDict->GetElementValue("P") : nullptr; | |
1939 | |
1940 int pageNum = pObj ? pObj->GetInteger() : 0; | |
1941 if (m_pHintTables && index != pageNum) { | |
1942 FX_FILESIZE szPageStartPos = 0; | |
1943 FX_FILESIZE szPageLength = 0; | |
1944 FX_DWORD dwObjNum = 0; | |
1945 FX_BOOL bPagePosGot = m_pHintTables->GetPagePos(index, szPageStartPos, | |
1946 szPageLength, dwObjNum); | |
1947 if (!bPagePosGot) | |
1948 return nullptr; | |
1949 | |
1950 m_syntaxParser.InitParser(m_pFileRead, (FX_DWORD)szPageStartPos); | |
1951 CPDF_Object* pPageDict = ParseIndirectObjectAt(0, dwObjNum, m_pDocument); | |
1952 if (!pPageDict) | |
1953 return nullptr; | |
1954 | |
1955 if (!m_pDocument->InsertIndirectObject(dwObjNum, pPageDict)) | |
1956 return nullptr; | |
1957 return pPageDict->GetDict(); | |
1958 } | |
1959 } | |
1960 return m_pDocument->GetPage(index); | |
1961 } | |
1962 | |
1963 IPDF_DataAvail::DocFormStatus CPDF_DataAvail::IsFormAvail( | |
1964 IFX_DownloadHints* pHints) { | |
1965 if (!m_pDocument) | |
1966 return FormAvailable; | |
1967 | |
1968 if (!m_bLinearizedFormParamLoad) { | |
1969 CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); | |
1970 if (!pRoot) | |
1971 return FormAvailable; | |
1972 | |
1973 CPDF_Object* pAcroForm = pRoot->GetElement("AcroForm"); | |
1974 if (!pAcroForm) | |
1975 return FormNotExist; | |
1976 | |
1977 DocAvailStatus nDocStatus = CheckLinearizedData(pHints); | |
1978 if (nDocStatus == DataError) | |
1979 return FormError; | |
1980 if (nDocStatus == DataNotAvailable) | |
1981 return FormNotAvailable; | |
1982 | |
1983 if (!m_objs_array.GetSize()) | |
1984 m_objs_array.Add(pAcroForm->GetDict()); | |
1985 m_bLinearizedFormParamLoad = TRUE; | |
1986 } | |
1987 | |
1988 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
1989 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
1990 m_objs_array.RemoveAll(); | |
1991 if (!bRet) { | |
1992 m_objs_array.Append(new_objs_array); | |
1993 return FormNotAvailable; | |
1994 } | |
1995 return FormAvailable; | |
1996 } | |
1997 | |
1998 CPDF_PageNode::CPDF_PageNode() : m_type(PDF_PAGENODE_UNKNOWN) {} | |
1999 | |
2000 CPDF_PageNode::~CPDF_PageNode() { | |
2001 for (int32_t i = 0; i < m_childNode.GetSize(); ++i) | |
2002 delete m_childNode[i]; | |
2003 m_childNode.RemoveAll(); | |
2004 } | |
2005 | |
2006 CPDF_HintTables::~CPDF_HintTables() { | |
2007 m_dwDeltaNObjsArray.RemoveAll(); | |
2008 m_dwNSharedObjsArray.RemoveAll(); | |
2009 m_dwSharedObjNumArray.RemoveAll(); | |
2010 m_dwIdentifierArray.RemoveAll(); | |
2011 } | |
2012 | |
2013 FX_DWORD CPDF_HintTables::GetItemLength( | |
2014 int index, | |
2015 const std::vector<FX_FILESIZE>& szArray) { | |
2016 if (index < 0 || szArray.size() < 2 || | |
2017 static_cast<size_t>(index) > szArray.size() - 2 || | |
2018 szArray[index] > szArray[index + 1]) { | |
2019 return 0; | |
2020 } | |
2021 return szArray[index + 1] - szArray[index]; | |
2022 } | |
2023 | |
2024 FX_BOOL CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { | |
2025 if (!hStream || hStream->IsEOF()) | |
2026 return FALSE; | |
2027 | |
2028 int nStreamOffset = ReadPrimaryHintStreamOffset(); | |
2029 int nStreamLen = ReadPrimaryHintStreamLength(); | |
2030 if (nStreamOffset < 0 || nStreamLen < 1) | |
2031 return FALSE; | |
2032 | |
2033 const FX_DWORD kHeaderSize = 288; | |
2034 if (hStream->BitsRemaining() < kHeaderSize) | |
2035 return FALSE; | |
2036 | |
2037 // Item 1: The least number of objects in a page. | |
2038 FX_DWORD dwObjLeastNum = hStream->GetBits(32); | |
2039 | |
2040 // Item 2: The location of the first page's page object. | |
2041 FX_DWORD dwFirstObjLoc = hStream->GetBits(32); | |
2042 if (dwFirstObjLoc > nStreamOffset) { | |
2043 FX_SAFE_DWORD safeLoc = pdfium::base::checked_cast<FX_DWORD>(nStreamLen); | |
2044 safeLoc += dwFirstObjLoc; | |
2045 if (!safeLoc.IsValid()) | |
2046 return FALSE; | |
2047 m_szFirstPageObjOffset = | |
2048 pdfium::base::checked_cast<FX_FILESIZE>(safeLoc.ValueOrDie()); | |
2049 } else { | |
2050 m_szFirstPageObjOffset = | |
2051 pdfium::base::checked_cast<FX_FILESIZE>(dwFirstObjLoc); | |
2052 } | |
2053 | |
2054 // Item 3: The number of bits needed to represent the difference | |
2055 // between the greatest and least number of objects in a page. | |
2056 FX_DWORD dwDeltaObjectsBits = hStream->GetBits(16); | |
2057 | |
2058 // Item 4: The least length of a page in bytes. | |
2059 FX_DWORD dwPageLeastLen = hStream->GetBits(32); | |
2060 | |
2061 // Item 5: The number of bits needed to represent the difference | |
2062 // between the greatest and least length of a page, in bytes. | |
2063 FX_DWORD dwDeltaPageLenBits = hStream->GetBits(16); | |
2064 | |
2065 // Skip Item 6, 7, 8, 9 total 96 bits. | |
2066 hStream->SkipBits(96); | |
2067 | |
2068 // Item 10: The number of bits needed to represent the greatest | |
2069 // number of shared object references. | |
2070 FX_DWORD dwSharedObjBits = hStream->GetBits(16); | |
2071 | |
2072 // Item 11: The number of bits needed to represent the numerically | |
2073 // greatest shared object identifier used by the pages. | |
2074 FX_DWORD dwSharedIdBits = hStream->GetBits(16); | |
2075 | |
2076 // Item 12: The number of bits needed to represent the numerator of | |
2077 // the fractional position for each shared object reference. For each | |
2078 // shared object referenced from a page, there is an indication of | |
2079 // where in the page's content stream the object is first referenced. | |
2080 FX_DWORD dwSharedNumeratorBits = hStream->GetBits(16); | |
2081 | |
2082 // Item 13: Skip Item 13 which has 16 bits. | |
2083 hStream->SkipBits(16); | |
2084 | |
2085 CPDF_Object* pPageNum = m_pLinearizedDict->GetElementValue("N"); | |
2086 int nPages = pPageNum ? pPageNum->GetInteger() : 0; | |
2087 if (nPages < 1) | |
2088 return FALSE; | |
2089 | |
2090 FX_SAFE_DWORD required_bits = dwDeltaObjectsBits; | |
2091 required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages); | |
2092 if (!CanReadFromBitStream(hStream, required_bits)) | |
2093 return FALSE; | |
2094 | |
2095 for (int i = 0; i < nPages; ++i) { | |
2096 FX_SAFE_DWORD safeDeltaObj = hStream->GetBits(dwDeltaObjectsBits); | |
2097 safeDeltaObj += dwObjLeastNum; | |
2098 if (!safeDeltaObj.IsValid()) | |
2099 return FALSE; | |
2100 m_dwDeltaNObjsArray.Add(safeDeltaObj.ValueOrDie()); | |
2101 } | |
2102 hStream->ByteAlign(); | |
2103 | |
2104 required_bits = dwDeltaPageLenBits; | |
2105 required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages); | |
2106 if (!CanReadFromBitStream(hStream, required_bits)) | |
2107 return FALSE; | |
2108 | |
2109 CFX_DWordArray dwPageLenArray; | |
2110 for (int i = 0; i < nPages; ++i) { | |
2111 FX_SAFE_DWORD safePageLen = hStream->GetBits(dwDeltaPageLenBits); | |
2112 safePageLen += dwPageLeastLen; | |
2113 if (!safePageLen.IsValid()) | |
2114 return FALSE; | |
2115 dwPageLenArray.Add(safePageLen.ValueOrDie()); | |
2116 } | |
2117 | |
2118 CPDF_Object* pOffsetE = m_pLinearizedDict->GetElementValue("E"); | |
2119 int nOffsetE = pOffsetE ? pOffsetE->GetInteger() : -1; | |
2120 if (nOffsetE < 0) | |
2121 return FALSE; | |
2122 | |
2123 CPDF_Object* pFirstPageNum = m_pLinearizedDict->GetElementValue("P"); | |
2124 int nFirstPageNum = pFirstPageNum ? pFirstPageNum->GetInteger() : 0; | |
2125 for (int i = 0; i < nPages; ++i) { | |
2126 if (i == nFirstPageNum) { | |
2127 m_szPageOffsetArray.push_back(m_szFirstPageObjOffset); | |
2128 } else if (i == nFirstPageNum + 1) { | |
2129 if (i == 1) { | |
2130 m_szPageOffsetArray.push_back(nOffsetE); | |
2131 } else { | |
2132 m_szPageOffsetArray.push_back(m_szPageOffsetArray[i - 2] + | |
2133 dwPageLenArray[i - 2]); | |
2134 } | |
2135 } else { | |
2136 if (i == 0) { | |
2137 m_szPageOffsetArray.push_back(nOffsetE); | |
2138 } else { | |
2139 m_szPageOffsetArray.push_back(m_szPageOffsetArray[i - 1] + | |
2140 dwPageLenArray[i - 1]); | |
2141 } | |
2142 } | |
2143 } | |
2144 | |
2145 if (nPages > 0) { | |
2146 m_szPageOffsetArray.push_back(m_szPageOffsetArray[nPages - 1] + | |
2147 dwPageLenArray[nPages - 1]); | |
2148 } | |
2149 hStream->ByteAlign(); | |
2150 | |
2151 // Number of shared objects. | |
2152 required_bits = dwSharedObjBits; | |
2153 required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages); | |
2154 if (!CanReadFromBitStream(hStream, required_bits)) | |
2155 return FALSE; | |
2156 | |
2157 for (int i = 0; i < nPages; i++) | |
2158 m_dwNSharedObjsArray.Add(hStream->GetBits(dwSharedObjBits)); | |
2159 hStream->ByteAlign(); | |
2160 | |
2161 // Array of identifiers, size = nshared_objects. | |
2162 for (int i = 0; i < nPages; i++) { | |
2163 required_bits = dwSharedIdBits; | |
2164 required_bits *= m_dwNSharedObjsArray[i]; | |
2165 if (!CanReadFromBitStream(hStream, required_bits)) | |
2166 return FALSE; | |
2167 | |
2168 for (int j = 0; j < m_dwNSharedObjsArray[i]; j++) | |
2169 m_dwIdentifierArray.Add(hStream->GetBits(dwSharedIdBits)); | |
2170 } | |
2171 hStream->ByteAlign(); | |
2172 | |
2173 for (int i = 0; i < nPages; i++) { | |
2174 FX_SAFE_DWORD safeSize = m_dwNSharedObjsArray[i]; | |
2175 safeSize *= dwSharedNumeratorBits; | |
2176 if (!CanReadFromBitStream(hStream, safeSize)) | |
2177 return FALSE; | |
2178 | |
2179 hStream->SkipBits(safeSize.ValueOrDie()); | |
2180 } | |
2181 hStream->ByteAlign(); | |
2182 | |
2183 FX_SAFE_DWORD safeTotalPageLen = pdfium::base::checked_cast<FX_DWORD>(nPages); | |
2184 safeTotalPageLen *= dwDeltaPageLenBits; | |
2185 if (!CanReadFromBitStream(hStream, safeTotalPageLen)) | |
2186 return FALSE; | |
2187 | |
2188 hStream->SkipBits(safeTotalPageLen.ValueOrDie()); | |
2189 hStream->ByteAlign(); | |
2190 return TRUE; | |
2191 } | |
2192 | |
2193 FX_BOOL CPDF_HintTables::ReadSharedObjHintTable(CFX_BitStream* hStream, | |
2194 FX_DWORD offset) { | |
2195 if (!hStream || hStream->IsEOF()) | |
2196 return FALSE; | |
2197 | |
2198 int nStreamOffset = ReadPrimaryHintStreamOffset(); | |
2199 int nStreamLen = ReadPrimaryHintStreamLength(); | |
2200 if (nStreamOffset < 0 || nStreamLen < 1) | |
2201 return FALSE; | |
2202 | |
2203 FX_SAFE_DWORD bit_offset = offset; | |
2204 bit_offset *= 8; | |
2205 if (!bit_offset.IsValid() || hStream->GetPos() > bit_offset.ValueOrDie()) | |
2206 return FALSE; | |
2207 hStream->SkipBits(bit_offset.ValueOrDie() - hStream->GetPos()); | |
2208 | |
2209 const FX_DWORD kHeaderSize = 192; | |
2210 if (hStream->BitsRemaining() < kHeaderSize) | |
2211 return FALSE; | |
2212 | |
2213 // Item 1: The object number of the first object in the shared objects | |
2214 // section. | |
2215 FX_DWORD dwFirstSharedObjNum = hStream->GetBits(32); | |
2216 | |
2217 // Item 2: The location of the first object in the shared objects section. | |
2218 FX_DWORD dwFirstSharedObjLoc = hStream->GetBits(32); | |
2219 if (dwFirstSharedObjLoc > nStreamOffset) | |
2220 dwFirstSharedObjLoc += nStreamLen; | |
2221 | |
2222 // Item 3: The number of shared object entries for the first page. | |
2223 m_nFirstPageSharedObjs = hStream->GetBits(32); | |
2224 | |
2225 // Item 4: The number of shared object entries for the shared objects | |
2226 // section, including the number of shared object entries for the first page. | |
2227 FX_DWORD dwSharedObjTotal = hStream->GetBits(32); | |
2228 | |
2229 // Item 5: The number of bits needed to represent the greatest number of | |
2230 // objects in a shared object group. Skipped. | |
2231 hStream->SkipBits(16); | |
2232 | |
2233 // Item 6: The least length of a shared object group in bytes. | |
2234 FX_DWORD dwGroupLeastLen = hStream->GetBits(32); | |
2235 | |
2236 // Item 7: The number of bits needed to represent the difference between the | |
2237 // greatest and least length of a shared object group, in bytes. | |
2238 FX_DWORD dwDeltaGroupLen = hStream->GetBits(16); | |
2239 CPDF_Object* pFirstPageObj = m_pLinearizedDict->GetElementValue("O"); | |
2240 int nFirstPageObjNum = pFirstPageObj ? pFirstPageObj->GetInteger() : -1; | |
2241 if (nFirstPageObjNum < 0) | |
2242 return FALSE; | |
2243 | |
2244 FX_DWORD dwPrevObjLen = 0; | |
2245 FX_DWORD dwCurObjLen = 0; | |
2246 FX_SAFE_DWORD required_bits = dwSharedObjTotal; | |
2247 required_bits *= dwDeltaGroupLen; | |
2248 if (!CanReadFromBitStream(hStream, required_bits)) | |
2249 return FALSE; | |
2250 | |
2251 for (int i = 0; i < dwSharedObjTotal; ++i) { | |
2252 dwPrevObjLen = dwCurObjLen; | |
2253 FX_SAFE_DWORD safeObjLen = hStream->GetBits(dwDeltaGroupLen); | |
2254 safeObjLen += dwGroupLeastLen; | |
2255 if (!safeObjLen.IsValid()) | |
2256 return FALSE; | |
2257 | |
2258 dwCurObjLen = safeObjLen.ValueOrDie(); | |
2259 if (i < m_nFirstPageSharedObjs) { | |
2260 m_dwSharedObjNumArray.Add(nFirstPageObjNum + i); | |
2261 if (i == 0) | |
2262 m_szSharedObjOffsetArray.push_back(m_szFirstPageObjOffset); | |
2263 } else { | |
2264 FX_SAFE_DWORD safeObjNum = dwFirstSharedObjNum; | |
2265 safeObjNum += i - m_nFirstPageSharedObjs; | |
2266 if (!safeObjNum.IsValid()) | |
2267 return FALSE; | |
2268 | |
2269 m_dwSharedObjNumArray.Add(safeObjNum.ValueOrDie()); | |
2270 if (i == m_nFirstPageSharedObjs) { | |
2271 m_szSharedObjOffsetArray.push_back( | |
2272 pdfium::base::checked_cast<int32_t>(dwFirstSharedObjLoc)); | |
2273 } | |
2274 } | |
2275 | |
2276 if (i != 0 && i != m_nFirstPageSharedObjs) { | |
2277 FX_SAFE_INT32 safeLoc = pdfium::base::checked_cast<int32_t>(dwPrevObjLen); | |
2278 safeLoc += m_szSharedObjOffsetArray[i - 1]; | |
2279 if (!safeLoc.IsValid()) | |
2280 return FALSE; | |
2281 | |
2282 m_szSharedObjOffsetArray.push_back(safeLoc.ValueOrDie()); | |
2283 } | |
2284 } | |
2285 | |
2286 if (dwSharedObjTotal > 0) { | |
2287 FX_SAFE_INT32 safeLoc = pdfium::base::checked_cast<int32_t>(dwCurObjLen); | |
2288 safeLoc += m_szSharedObjOffsetArray[dwSharedObjTotal - 1]; | |
2289 if (!safeLoc.IsValid()) | |
2290 return FALSE; | |
2291 | |
2292 m_szSharedObjOffsetArray.push_back(safeLoc.ValueOrDie()); | |
2293 } | |
2294 | |
2295 hStream->ByteAlign(); | |
2296 if (hStream->BitsRemaining() < dwSharedObjTotal) | |
2297 return FALSE; | |
2298 | |
2299 hStream->SkipBits(dwSharedObjTotal); | |
2300 hStream->ByteAlign(); | |
2301 return TRUE; | |
2302 } | |
2303 | |
2304 FX_BOOL CPDF_HintTables::GetPagePos(int index, | |
2305 FX_FILESIZE& szPageStartPos, | |
2306 FX_FILESIZE& szPageLength, | |
2307 FX_DWORD& dwObjNum) { | |
2308 if (!m_pLinearizedDict) | |
2309 return FALSE; | |
2310 | |
2311 szPageStartPos = m_szPageOffsetArray[index]; | |
2312 szPageLength = GetItemLength(index, m_szPageOffsetArray); | |
2313 | |
2314 CPDF_Object* pFirstPageNum = m_pLinearizedDict->GetElementValue("P"); | |
2315 int nFirstPageNum = pFirstPageNum ? pFirstPageNum->GetInteger() : 0; | |
2316 | |
2317 CPDF_Object* pFirstPageObjNum = m_pLinearizedDict->GetElementValue("O"); | |
2318 if (!pFirstPageObjNum) | |
2319 return FALSE; | |
2320 | |
2321 int nFirstPageObjNum = pFirstPageObjNum->GetInteger(); | |
2322 if (index == nFirstPageNum) { | |
2323 dwObjNum = nFirstPageObjNum; | |
2324 return TRUE; | |
2325 } | |
2326 | |
2327 // The object number of remaining pages starts from 1. | |
2328 dwObjNum = 1; | |
2329 for (int i = 0; i < index; ++i) { | |
2330 if (i == nFirstPageNum) | |
2331 continue; | |
2332 dwObjNum += m_dwDeltaNObjsArray[i]; | |
2333 } | |
2334 return TRUE; | |
2335 } | |
2336 | |
2337 IPDF_DataAvail::DocAvailStatus CPDF_HintTables::CheckPage( | |
2338 int index, | |
2339 IFX_DownloadHints* pHints) { | |
2340 if (!m_pLinearizedDict || !pHints) | |
2341 return IPDF_DataAvail::DataError; | |
2342 | |
2343 CPDF_Object* pFirstAvailPage = m_pLinearizedDict->GetElementValue("P"); | |
2344 int nFirstAvailPage = pFirstAvailPage ? pFirstAvailPage->GetInteger() : 0; | |
2345 if (index == nFirstAvailPage) | |
2346 return IPDF_DataAvail::DataAvailable; | |
2347 | |
2348 FX_DWORD dwLength = GetItemLength(index, m_szPageOffsetArray); | |
2349 // If two pages have the same offset, it should be treated as an error. | |
2350 if (!dwLength) | |
2351 return IPDF_DataAvail::DataError; | |
2352 | |
2353 if (!m_pDataAvail->IsDataAvail(m_szPageOffsetArray[index], dwLength, pHints)) | |
2354 return IPDF_DataAvail::DataNotAvailable; | |
2355 | |
2356 // Download data of shared objects in the page. | |
2357 FX_DWORD offset = 0; | |
2358 for (int i = 0; i < index; ++i) | |
2359 offset += m_dwNSharedObjsArray[i]; | |
2360 | |
2361 CPDF_Object* pFirstPageObj = m_pLinearizedDict->GetElementValue("O"); | |
2362 int nFirstPageObjNum = pFirstPageObj ? pFirstPageObj->GetInteger() : -1; | |
2363 if (nFirstPageObjNum < 0) | |
2364 return IPDF_DataAvail::DataError; | |
2365 | |
2366 FX_DWORD dwIndex = 0; | |
2367 FX_DWORD dwObjNum = 0; | |
2368 for (int j = 0; j < m_dwNSharedObjsArray[index]; ++j) { | |
2369 dwIndex = m_dwIdentifierArray[offset + j]; | |
2370 if (dwIndex >= m_dwSharedObjNumArray.GetSize()) | |
2371 return IPDF_DataAvail::DataNotAvailable; | |
2372 | |
2373 dwObjNum = m_dwSharedObjNumArray[dwIndex]; | |
2374 if (dwObjNum >= nFirstPageObjNum && | |
2375 dwObjNum < nFirstPageObjNum + m_nFirstPageSharedObjs) { | |
2376 continue; | |
2377 } | |
2378 | |
2379 dwLength = GetItemLength(dwIndex, m_szSharedObjOffsetArray); | |
2380 // If two objects have the same offset, it should be treated as an error. | |
2381 if (!dwLength) | |
2382 return IPDF_DataAvail::DataError; | |
2383 | |
2384 if (!m_pDataAvail->IsDataAvail(m_szSharedObjOffsetArray[dwIndex], dwLength, | |
2385 pHints)) { | |
2386 return IPDF_DataAvail::DataNotAvailable; | |
2387 } | |
2388 } | |
2389 return IPDF_DataAvail::DataAvailable; | |
2390 } | |
2391 | |
2392 FX_BOOL CPDF_HintTables::LoadHintStream(CPDF_Stream* pHintStream) { | |
2393 if (!pHintStream || !m_pLinearizedDict) | |
2394 return FALSE; | |
2395 | |
2396 CPDF_Dictionary* pDict = pHintStream->GetDict(); | |
2397 CPDF_Object* pOffset = pDict ? pDict->GetElement("S") : nullptr; | |
2398 if (!pOffset || !pOffset->IsNumber()) | |
2399 return FALSE; | |
2400 | |
2401 int shared_hint_table_offset = pOffset->GetInteger(); | |
2402 CPDF_StreamAcc acc; | |
2403 acc.LoadAllData(pHintStream); | |
2404 | |
2405 FX_DWORD size = acc.GetSize(); | |
2406 // The header section of page offset hint table is 36 bytes. | |
2407 // The header section of shared object hint table is 24 bytes. | |
2408 // Hint table has at least 60 bytes. | |
2409 const FX_DWORD MIN_STREAM_LEN = 60; | |
2410 if (size < MIN_STREAM_LEN || shared_hint_table_offset <= 0 || | |
2411 size < shared_hint_table_offset) { | |
2412 return FALSE; | |
2413 } | |
2414 | |
2415 CFX_BitStream bs; | |
2416 bs.Init(acc.GetData(), size); | |
2417 return ReadPageHintTable(&bs) && | |
2418 ReadSharedObjHintTable(&bs, pdfium::base::checked_cast<FX_DWORD>( | |
2419 shared_hint_table_offset)); | |
2420 } | |
2421 | |
2422 int CPDF_HintTables::ReadPrimaryHintStreamOffset() const { | |
2423 if (!m_pLinearizedDict) | |
2424 return -1; | |
2425 | |
2426 CPDF_Array* pRange = m_pLinearizedDict->GetArrayBy("H"); | |
2427 if (!pRange) | |
2428 return -1; | |
2429 | |
2430 CPDF_Object* pStreamOffset = pRange->GetElementValue(0); | |
2431 if (!pStreamOffset) | |
2432 return -1; | |
2433 | |
2434 return pStreamOffset->GetInteger(); | |
2435 } | |
2436 | |
2437 int CPDF_HintTables::ReadPrimaryHintStreamLength() const { | |
2438 if (!m_pLinearizedDict) | |
2439 return -1; | |
2440 | |
2441 CPDF_Array* pRange = m_pLinearizedDict->GetArrayBy("H"); | |
2442 if (!pRange) | |
2443 return -1; | |
2444 | |
2445 CPDF_Object* pStreamLen = pRange->GetElementValue(1); | |
2446 if (!pStreamLen) | |
2447 return -1; | |
2448 | |
2449 return pStreamLen->GetInteger(); | |
2450 } | |
OLD | NEW |