OLD | NEW |
| (Empty) |
1 // Copyright 2016 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/fpdfapi/fpdf_parser/cpdf_data_avail.h" | |
8 | |
9 #include <algorithm> | |
10 #include <memory> | |
11 #include <utility> | |
12 | |
13 #include "core/fpdfapi/cpdf_modulemgr.h" | |
14 #include "core/fpdfapi/fpdf_parser/cpdf_array.h" | |
15 #include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" | |
16 #include "core/fpdfapi/fpdf_parser/cpdf_document.h" | |
17 #include "core/fpdfapi/fpdf_parser/cpdf_hint_tables.h" | |
18 #include "core/fpdfapi/fpdf_parser/cpdf_name.h" | |
19 #include "core/fpdfapi/fpdf_parser/cpdf_number.h" | |
20 #include "core/fpdfapi/fpdf_parser/cpdf_reference.h" | |
21 #include "core/fpdfapi/fpdf_parser/cpdf_stream.h" | |
22 #include "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h" | |
23 #include "core/fxcrt/fx_ext.h" | |
24 #include "core/fxcrt/fx_safe_types.h" | |
25 #include "third_party/base/stl_util.h" | |
26 | |
27 CPDF_DataAvail::FileAvail::~FileAvail() {} | |
28 | |
29 CPDF_DataAvail::DownloadHints::~DownloadHints() {} | |
30 | |
31 // static | |
32 int CPDF_DataAvail::s_CurrentDataAvailRecursionDepth = 0; | |
33 | |
34 CPDF_DataAvail::CPDF_DataAvail(FileAvail* pFileAvail, | |
35 IFX_FileRead* pFileRead, | |
36 FX_BOOL bSupportHintTable) | |
37 : m_pFileAvail(pFileAvail), m_pFileRead(pFileRead) { | |
38 m_Pos = 0; | |
39 m_dwFileLen = 0; | |
40 if (m_pFileRead) { | |
41 m_dwFileLen = (uint32_t)m_pFileRead->GetSize(); | |
42 } | |
43 m_dwCurrentOffset = 0; | |
44 m_dwXRefOffset = 0; | |
45 m_bufferOffset = 0; | |
46 m_dwFirstPageNo = 0; | |
47 m_bufferSize = 0; | |
48 m_PagesObjNum = 0; | |
49 m_dwCurrentXRefSteam = 0; | |
50 m_dwAcroFormObjNum = 0; | |
51 m_dwInfoObjNum = 0; | |
52 m_pDocument = 0; | |
53 m_dwEncryptObjNum = 0; | |
54 m_dwPrevXRefOffset = 0; | |
55 m_dwLastXRefOffset = 0; | |
56 m_bDocAvail = FALSE; | |
57 m_bMainXRefLoadTried = FALSE; | |
58 m_bDocAvail = FALSE; | |
59 m_bLinearized = FALSE; | |
60 m_bPagesLoad = FALSE; | |
61 m_bPagesTreeLoad = FALSE; | |
62 m_bMainXRefLoadedOK = FALSE; | |
63 m_bAnnotsLoad = FALSE; | |
64 m_bHaveAcroForm = FALSE; | |
65 m_bAcroFormLoad = FALSE; | |
66 m_bPageLoadedOK = FALSE; | |
67 m_bNeedDownLoadResource = FALSE; | |
68 m_bLinearizedFormParamLoad = FALSE; | |
69 m_pLinearized = nullptr; | |
70 m_pRoot = nullptr; | |
71 m_pTrailer = nullptr; | |
72 m_pCurrentParser = nullptr; | |
73 m_pAcroForm = nullptr; | |
74 m_pPageDict = nullptr; | |
75 m_pPageResource = nullptr; | |
76 m_docStatus = PDF_DATAAVAIL_HEADER; | |
77 m_parser.m_bOwnFileRead = false; | |
78 m_bTotalLoadPageTree = FALSE; | |
79 m_bCurPageDictLoadOK = FALSE; | |
80 m_bLinearedDataOK = FALSE; | |
81 m_bSupportHintTable = bSupportHintTable; | |
82 } | |
83 CPDF_DataAvail::~CPDF_DataAvail() { | |
84 m_pHintTables.reset(); | |
85 if (m_pLinearized) | |
86 m_pLinearized->Release(); | |
87 | |
88 if (m_pRoot) | |
89 m_pRoot->Release(); | |
90 | |
91 if (m_pTrailer) | |
92 m_pTrailer->Release(); | |
93 | |
94 int iSize = m_arrayAcroforms.GetSize(); | |
95 for (int i = 0; i < iSize; ++i) | |
96 m_arrayAcroforms.GetAt(i)->Release(); | |
97 } | |
98 | |
99 void CPDF_DataAvail::SetDocument(CPDF_Document* pDoc) { | |
100 m_pDocument = pDoc; | |
101 } | |
102 | |
103 uint32_t CPDF_DataAvail::GetObjectSize(uint32_t objnum, FX_FILESIZE& offset) { | |
104 CPDF_Parser* pParser = m_pDocument->GetParser(); | |
105 if (!pParser || !pParser->IsValidObjectNumber(objnum)) | |
106 return 0; | |
107 | |
108 if (pParser->GetObjectType(objnum) == 2) | |
109 objnum = pParser->GetObjectPositionOrZero(objnum); | |
110 | |
111 if (pParser->GetObjectType(objnum) != 1 && | |
112 pParser->GetObjectType(objnum) != 255) { | |
113 return 0; | |
114 } | |
115 | |
116 offset = pParser->GetObjectPositionOrZero(objnum); | |
117 if (offset == 0) | |
118 return 0; | |
119 | |
120 auto it = pParser->m_SortedOffset.find(offset); | |
121 if (it == pParser->m_SortedOffset.end() || | |
122 ++it == pParser->m_SortedOffset.end()) { | |
123 return 0; | |
124 } | |
125 return *it - offset; | |
126 } | |
127 | |
128 FX_BOOL CPDF_DataAvail::IsObjectsAvail( | |
129 CFX_ArrayTemplate<CPDF_Object*>& obj_array, | |
130 FX_BOOL bParsePage, | |
131 DownloadHints* pHints, | |
132 CFX_ArrayTemplate<CPDF_Object*>& ret_array) { | |
133 if (!obj_array.GetSize()) | |
134 return TRUE; | |
135 | |
136 uint32_t count = 0; | |
137 CFX_ArrayTemplate<CPDF_Object*> new_obj_array; | |
138 for (int i = 0; i < obj_array.GetSize(); i++) { | |
139 CPDF_Object* pObj = obj_array[i]; | |
140 if (!pObj) | |
141 continue; | |
142 | |
143 int32_t type = pObj->GetType(); | |
144 switch (type) { | |
145 case CPDF_Object::ARRAY: { | |
146 CPDF_Array* pArray = pObj->AsArray(); | |
147 for (size_t k = 0; k < pArray->GetCount(); ++k) | |
148 new_obj_array.Add(pArray->GetObjectAt(k)); | |
149 } break; | |
150 case CPDF_Object::STREAM: | |
151 pObj = pObj->GetDict(); | |
152 case CPDF_Object::DICTIONARY: { | |
153 CPDF_Dictionary* pDict = pObj->GetDict(); | |
154 if (pDict && pDict->GetStringFor("Type") == "Page" && !bParsePage) | |
155 continue; | |
156 | |
157 for (const auto& it : *pDict) { | |
158 const CFX_ByteString& key = it.first; | |
159 CPDF_Object* value = it.second; | |
160 if (key != "Parent") | |
161 new_obj_array.Add(value); | |
162 } | |
163 } break; | |
164 case CPDF_Object::REFERENCE: { | |
165 CPDF_Reference* pRef = pObj->AsReference(); | |
166 uint32_t dwNum = pRef->GetRefObjNum(); | |
167 | |
168 FX_FILESIZE offset; | |
169 uint32_t size = GetObjectSize(dwNum, offset); | |
170 if (size == 0 || offset < 0 || offset >= m_dwFileLen) | |
171 break; | |
172 | |
173 if (!IsDataAvail(offset, size, pHints)) { | |
174 ret_array.Add(pObj); | |
175 count++; | |
176 } else if (!pdfium::ContainsKey(m_ObjectSet, dwNum)) { | |
177 m_ObjectSet.insert(dwNum); | |
178 CPDF_Object* pReferred = | |
179 m_pDocument->GetOrParseIndirectObject(pRef->GetRefObjNum()); | |
180 if (pReferred) | |
181 new_obj_array.Add(pReferred); | |
182 } | |
183 } break; | |
184 } | |
185 } | |
186 | |
187 if (count > 0) { | |
188 for (int i = 0; i < new_obj_array.GetSize(); ++i) { | |
189 CPDF_Object* pObj = new_obj_array[i]; | |
190 if (CPDF_Reference* pRef = pObj->AsReference()) { | |
191 uint32_t dwNum = pRef->GetRefObjNum(); | |
192 if (!pdfium::ContainsKey(m_ObjectSet, dwNum)) | |
193 ret_array.Add(pObj); | |
194 } else { | |
195 ret_array.Add(pObj); | |
196 } | |
197 } | |
198 return FALSE; | |
199 } | |
200 | |
201 obj_array.RemoveAll(); | |
202 obj_array.Append(new_obj_array); | |
203 return IsObjectsAvail(obj_array, FALSE, pHints, ret_array); | |
204 } | |
205 | |
206 CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsDocAvail( | |
207 DownloadHints* pHints) { | |
208 if (!m_dwFileLen && m_pFileRead) { | |
209 m_dwFileLen = (uint32_t)m_pFileRead->GetSize(); | |
210 if (!m_dwFileLen) | |
211 return DataError; | |
212 } | |
213 | |
214 while (!m_bDocAvail) { | |
215 if (!CheckDocStatus(pHints)) | |
216 return DataNotAvailable; | |
217 } | |
218 | |
219 return DataAvailable; | |
220 } | |
221 | |
222 FX_BOOL CPDF_DataAvail::CheckAcroFormSubObject(DownloadHints* pHints) { | |
223 if (!m_objs_array.GetSize()) { | |
224 m_objs_array.RemoveAll(); | |
225 m_ObjectSet.clear(); | |
226 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
227 obj_array.Append(m_arrayAcroforms); | |
228 FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); | |
229 if (bRet) | |
230 m_objs_array.RemoveAll(); | |
231 return bRet; | |
232 } | |
233 | |
234 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
235 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
236 if (bRet) { | |
237 int32_t iSize = m_arrayAcroforms.GetSize(); | |
238 for (int32_t i = 0; i < iSize; ++i) { | |
239 m_arrayAcroforms.GetAt(i)->Release(); | |
240 } | |
241 m_arrayAcroforms.RemoveAll(); | |
242 } else { | |
243 m_objs_array.RemoveAll(); | |
244 m_objs_array.Append(new_objs_array); | |
245 } | |
246 return bRet; | |
247 } | |
248 | |
249 FX_BOOL CPDF_DataAvail::CheckAcroForm(DownloadHints* pHints) { | |
250 FX_BOOL bExist = FALSE; | |
251 m_pAcroForm = GetObject(m_dwAcroFormObjNum, pHints, &bExist); | |
252 if (!bExist) { | |
253 m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
254 return TRUE; | |
255 } | |
256 | |
257 if (!m_pAcroForm) { | |
258 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
259 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
260 return TRUE; | |
261 } | |
262 return FALSE; | |
263 } | |
264 | |
265 m_arrayAcroforms.Add(m_pAcroForm); | |
266 m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
267 return TRUE; | |
268 } | |
269 | |
270 FX_BOOL CPDF_DataAvail::CheckDocStatus(DownloadHints* pHints) { | |
271 switch (m_docStatus) { | |
272 case PDF_DATAAVAIL_HEADER: | |
273 return CheckHeader(pHints); | |
274 case PDF_DATAAVAIL_FIRSTPAGE: | |
275 case PDF_DATAAVAIL_FIRSTPAGE_PREPARE: | |
276 return CheckFirstPage(pHints); | |
277 case PDF_DATAAVAIL_HINTTABLE: | |
278 return CheckHintTables(pHints); | |
279 case PDF_DATAAVAIL_END: | |
280 return CheckEnd(pHints); | |
281 case PDF_DATAAVAIL_CROSSREF: | |
282 return CheckCrossRef(pHints); | |
283 case PDF_DATAAVAIL_CROSSREF_ITEM: | |
284 return CheckCrossRefItem(pHints); | |
285 case PDF_DATAAVAIL_CROSSREF_STREAM: | |
286 return CheckAllCrossRefStream(pHints); | |
287 case PDF_DATAAVAIL_TRAILER: | |
288 return CheckTrailer(pHints); | |
289 case PDF_DATAAVAIL_TRAILER_APPEND: | |
290 return CheckTrailerAppend(pHints); | |
291 case PDF_DATAAVAIL_LOADALLCROSSREF: | |
292 return LoadAllXref(pHints); | |
293 case PDF_DATAAVAIL_LOADALLFILE: | |
294 return LoadAllFile(pHints); | |
295 case PDF_DATAAVAIL_ROOT: | |
296 return CheckRoot(pHints); | |
297 case PDF_DATAAVAIL_INFO: | |
298 return CheckInfo(pHints); | |
299 case PDF_DATAAVAIL_ACROFORM: | |
300 return CheckAcroForm(pHints); | |
301 case PDF_DATAAVAIL_PAGETREE: | |
302 if (m_bTotalLoadPageTree) | |
303 return CheckPages(pHints); | |
304 return LoadDocPages(pHints); | |
305 case PDF_DATAAVAIL_PAGE: | |
306 if (m_bTotalLoadPageTree) | |
307 return CheckPage(pHints); | |
308 m_docStatus = PDF_DATAAVAIL_PAGE_LATERLOAD; | |
309 return TRUE; | |
310 case PDF_DATAAVAIL_ERROR: | |
311 return LoadAllFile(pHints); | |
312 case PDF_DATAAVAIL_PAGE_LATERLOAD: | |
313 m_docStatus = PDF_DATAAVAIL_PAGE; | |
314 default: | |
315 m_bDocAvail = TRUE; | |
316 return TRUE; | |
317 } | |
318 } | |
319 | |
320 FX_BOOL CPDF_DataAvail::CheckPageStatus(DownloadHints* pHints) { | |
321 switch (m_docStatus) { | |
322 case PDF_DATAAVAIL_PAGETREE: | |
323 return CheckPages(pHints); | |
324 case PDF_DATAAVAIL_PAGE: | |
325 return CheckPage(pHints); | |
326 case PDF_DATAAVAIL_ERROR: | |
327 return LoadAllFile(pHints); | |
328 default: | |
329 m_bPagesTreeLoad = TRUE; | |
330 m_bPagesLoad = TRUE; | |
331 return TRUE; | |
332 } | |
333 } | |
334 | |
335 FX_BOOL CPDF_DataAvail::LoadAllFile(DownloadHints* pHints) { | |
336 if (m_pFileAvail->IsDataAvail(0, (uint32_t)m_dwFileLen)) { | |
337 m_docStatus = PDF_DATAAVAIL_DONE; | |
338 return TRUE; | |
339 } | |
340 | |
341 pHints->AddSegment(0, (uint32_t)m_dwFileLen); | |
342 return FALSE; | |
343 } | |
344 | |
345 FX_BOOL CPDF_DataAvail::LoadAllXref(DownloadHints* pHints) { | |
346 m_parser.m_pSyntax->InitParser(m_pFileRead, (uint32_t)m_dwHeaderOffset); | |
347 m_parser.m_bOwnFileRead = false; | |
348 if (!m_parser.LoadAllCrossRefV4(m_dwLastXRefOffset) && | |
349 !m_parser.LoadAllCrossRefV5(m_dwLastXRefOffset)) { | |
350 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
351 return FALSE; | |
352 } | |
353 | |
354 m_dwRootObjNum = m_parser.GetRootObjNum(); | |
355 m_dwInfoObjNum = m_parser.GetInfoObjNum(); | |
356 m_pCurrentParser = &m_parser; | |
357 m_docStatus = PDF_DATAAVAIL_ROOT; | |
358 return TRUE; | |
359 } | |
360 | |
361 CPDF_Object* CPDF_DataAvail::GetObject(uint32_t objnum, | |
362 DownloadHints* pHints, | |
363 FX_BOOL* pExistInFile) { | |
364 CPDF_Object* pRet = nullptr; | |
365 uint32_t size = 0; | |
366 FX_FILESIZE offset = 0; | |
367 CPDF_Parser* pParser = nullptr; | |
368 | |
369 if (pExistInFile) | |
370 *pExistInFile = TRUE; | |
371 | |
372 if (m_pDocument) { | |
373 size = GetObjectSize(objnum, offset); | |
374 pParser = m_pDocument->GetParser(); | |
375 } else { | |
376 size = (uint32_t)m_parser.GetObjectSize(objnum); | |
377 offset = m_parser.GetObjectOffset(objnum); | |
378 pParser = &m_parser; | |
379 } | |
380 | |
381 if (!IsDataAvail(offset, size, pHints)) | |
382 return nullptr; | |
383 | |
384 if (pParser) | |
385 pRet = pParser->ParseIndirectObject(nullptr, objnum); | |
386 | |
387 if (!pRet && pExistInFile) | |
388 *pExistInFile = FALSE; | |
389 | |
390 return pRet; | |
391 } | |
392 | |
393 FX_BOOL CPDF_DataAvail::CheckInfo(DownloadHints* pHints) { | |
394 FX_BOOL bExist = FALSE; | |
395 CPDF_Object* pInfo = GetObject(m_dwInfoObjNum, pHints, &bExist); | |
396 if (!bExist) { | |
397 m_docStatus = | |
398 (m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE); | |
399 return TRUE; | |
400 } | |
401 | |
402 if (!pInfo) { | |
403 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
404 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
405 return TRUE; | |
406 } | |
407 | |
408 if (m_Pos == m_dwFileLen) | |
409 m_docStatus = PDF_DATAAVAIL_ERROR; | |
410 return FALSE; | |
411 } | |
412 | |
413 if (pInfo) | |
414 pInfo->Release(); | |
415 | |
416 m_docStatus = | |
417 (m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE); | |
418 | |
419 return TRUE; | |
420 } | |
421 | |
422 FX_BOOL CPDF_DataAvail::CheckRoot(DownloadHints* pHints) { | |
423 FX_BOOL bExist = FALSE; | |
424 m_pRoot = GetObject(m_dwRootObjNum, pHints, &bExist); | |
425 if (!bExist) { | |
426 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
427 return TRUE; | |
428 } | |
429 | |
430 if (!m_pRoot) { | |
431 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
432 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
433 return TRUE; | |
434 } | |
435 return FALSE; | |
436 } | |
437 | |
438 CPDF_Dictionary* pDict = m_pRoot->GetDict(); | |
439 if (!pDict) { | |
440 m_docStatus = PDF_DATAAVAIL_ERROR; | |
441 return FALSE; | |
442 } | |
443 | |
444 CPDF_Reference* pRef = ToReference(pDict->GetObjectFor("Pages")); | |
445 if (!pRef) { | |
446 m_docStatus = PDF_DATAAVAIL_ERROR; | |
447 return FALSE; | |
448 } | |
449 | |
450 m_PagesObjNum = pRef->GetRefObjNum(); | |
451 CPDF_Reference* pAcroFormRef = | |
452 ToReference(m_pRoot->GetDict()->GetObjectFor("AcroForm")); | |
453 if (pAcroFormRef) { | |
454 m_bHaveAcroForm = TRUE; | |
455 m_dwAcroFormObjNum = pAcroFormRef->GetRefObjNum(); | |
456 } | |
457 | |
458 if (m_dwInfoObjNum) { | |
459 m_docStatus = PDF_DATAAVAIL_INFO; | |
460 } else { | |
461 m_docStatus = | |
462 m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE; | |
463 } | |
464 return TRUE; | |
465 } | |
466 | |
467 FX_BOOL CPDF_DataAvail::PreparePageItem() { | |
468 CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); | |
469 CPDF_Reference* pRef = | |
470 ToReference(pRoot ? pRoot->GetObjectFor("Pages") : nullptr); | |
471 if (!pRef) { | |
472 m_docStatus = PDF_DATAAVAIL_ERROR; | |
473 return FALSE; | |
474 } | |
475 | |
476 m_PagesObjNum = pRef->GetRefObjNum(); | |
477 m_pCurrentParser = m_pDocument->GetParser(); | |
478 m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
479 return TRUE; | |
480 } | |
481 | |
482 bool CPDF_DataAvail::IsFirstCheck(uint32_t dwPage) { | |
483 return m_pageMapCheckState.insert(dwPage).second; | |
484 } | |
485 | |
486 void CPDF_DataAvail::ResetFirstCheck(uint32_t dwPage) { | |
487 m_pageMapCheckState.erase(dwPage); | |
488 } | |
489 | |
490 FX_BOOL CPDF_DataAvail::CheckPage(DownloadHints* pHints) { | |
491 uint32_t iPageObjs = m_PageObjList.GetSize(); | |
492 CFX_ArrayTemplate<uint32_t> UnavailObjList; | |
493 for (uint32_t i = 0; i < iPageObjs; ++i) { | |
494 uint32_t dwPageObjNum = m_PageObjList.GetAt(i); | |
495 FX_BOOL bExist = FALSE; | |
496 CPDF_Object* pObj = GetObject(dwPageObjNum, pHints, &bExist); | |
497 if (!pObj) { | |
498 if (bExist) | |
499 UnavailObjList.Add(dwPageObjNum); | |
500 continue; | |
501 } | |
502 | |
503 CPDF_Array* pArray = ToArray(pObj); | |
504 if (pArray) { | |
505 for (CPDF_Object* pArrayObj : *pArray) { | |
506 if (CPDF_Reference* pRef = ToReference(pArrayObj)) | |
507 UnavailObjList.Add(pRef->GetRefObjNum()); | |
508 } | |
509 } | |
510 | |
511 if (!pObj->IsDictionary()) { | |
512 pObj->Release(); | |
513 continue; | |
514 } | |
515 | |
516 CFX_ByteString type = pObj->GetDict()->GetStringFor("Type"); | |
517 if (type == "Pages") { | |
518 m_PagesArray.Add(pObj); | |
519 continue; | |
520 } | |
521 pObj->Release(); | |
522 } | |
523 | |
524 m_PageObjList.RemoveAll(); | |
525 if (UnavailObjList.GetSize()) { | |
526 m_PageObjList.Append(UnavailObjList); | |
527 return FALSE; | |
528 } | |
529 | |
530 uint32_t iPages = m_PagesArray.GetSize(); | |
531 for (uint32_t i = 0; i < iPages; i++) { | |
532 CPDF_Object* pPages = m_PagesArray.GetAt(i); | |
533 if (!pPages) | |
534 continue; | |
535 | |
536 if (!GetPageKids(m_pCurrentParser, pPages)) { | |
537 pPages->Release(); | |
538 while (++i < iPages) { | |
539 pPages = m_PagesArray.GetAt(i); | |
540 pPages->Release(); | |
541 } | |
542 m_PagesArray.RemoveAll(); | |
543 | |
544 m_docStatus = PDF_DATAAVAIL_ERROR; | |
545 return FALSE; | |
546 } | |
547 pPages->Release(); | |
548 } | |
549 | |
550 m_PagesArray.RemoveAll(); | |
551 if (!m_PageObjList.GetSize()) | |
552 m_docStatus = PDF_DATAAVAIL_DONE; | |
553 return TRUE; | |
554 } | |
555 | |
556 FX_BOOL CPDF_DataAvail::GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages) { | |
557 if (!pParser) { | |
558 m_docStatus = PDF_DATAAVAIL_ERROR; | |
559 return FALSE; | |
560 } | |
561 | |
562 CPDF_Dictionary* pDict = pPages->GetDict(); | |
563 CPDF_Object* pKids = pDict ? pDict->GetObjectFor("Kids") : nullptr; | |
564 if (!pKids) | |
565 return TRUE; | |
566 | |
567 switch (pKids->GetType()) { | |
568 case CPDF_Object::REFERENCE: | |
569 m_PageObjList.Add(pKids->AsReference()->GetRefObjNum()); | |
570 break; | |
571 case CPDF_Object::ARRAY: { | |
572 CPDF_Array* pKidsArray = pKids->AsArray(); | |
573 for (size_t i = 0; i < pKidsArray->GetCount(); ++i) { | |
574 if (CPDF_Reference* pRef = ToReference(pKidsArray->GetObjectAt(i))) | |
575 m_PageObjList.Add(pRef->GetRefObjNum()); | |
576 } | |
577 } break; | |
578 default: | |
579 m_docStatus = PDF_DATAAVAIL_ERROR; | |
580 return FALSE; | |
581 } | |
582 return TRUE; | |
583 } | |
584 | |
585 FX_BOOL CPDF_DataAvail::CheckPages(DownloadHints* pHints) { | |
586 FX_BOOL bExist = FALSE; | |
587 CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist); | |
588 if (!bExist) { | |
589 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
590 return TRUE; | |
591 } | |
592 | |
593 if (!pPages) { | |
594 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
595 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
596 return TRUE; | |
597 } | |
598 return FALSE; | |
599 } | |
600 | |
601 if (!GetPageKids(m_pCurrentParser, pPages)) { | |
602 pPages->Release(); | |
603 m_docStatus = PDF_DATAAVAIL_ERROR; | |
604 return FALSE; | |
605 } | |
606 | |
607 pPages->Release(); | |
608 m_docStatus = PDF_DATAAVAIL_PAGE; | |
609 return TRUE; | |
610 } | |
611 | |
612 FX_BOOL CPDF_DataAvail::CheckHeader(DownloadHints* pHints) { | |
613 ASSERT(m_dwFileLen >= 0); | |
614 const uint32_t kReqSize = std::min(static_cast<uint32_t>(m_dwFileLen), 1024U); | |
615 | |
616 if (m_pFileAvail->IsDataAvail(0, kReqSize)) { | |
617 uint8_t buffer[1024]; | |
618 m_pFileRead->ReadBlock(buffer, 0, kReqSize); | |
619 | |
620 if (IsLinearizedFile(buffer, kReqSize)) { | |
621 m_docStatus = PDF_DATAAVAIL_FIRSTPAGE; | |
622 } else { | |
623 if (m_docStatus == PDF_DATAAVAIL_ERROR) | |
624 return FALSE; | |
625 m_docStatus = PDF_DATAAVAIL_END; | |
626 } | |
627 return TRUE; | |
628 } | |
629 | |
630 pHints->AddSegment(0, kReqSize); | |
631 return FALSE; | |
632 } | |
633 | |
634 FX_BOOL CPDF_DataAvail::CheckFirstPage(DownloadHints* pHints) { | |
635 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
636 CPDF_Object* pEndOffSet = pDict ? pDict->GetObjectFor("E") : nullptr; | |
637 if (!pEndOffSet) { | |
638 m_docStatus = PDF_DATAAVAIL_ERROR; | |
639 return FALSE; | |
640 } | |
641 | |
642 CPDF_Object* pXRefOffset = pDict ? pDict->GetObjectFor("T") : nullptr; | |
643 if (!pXRefOffset) { | |
644 m_docStatus = PDF_DATAAVAIL_ERROR; | |
645 return FALSE; | |
646 } | |
647 | |
648 CPDF_Object* pFileLen = pDict ? pDict->GetObjectFor("L") : nullptr; | |
649 if (!pFileLen) { | |
650 m_docStatus = PDF_DATAAVAIL_ERROR; | |
651 return FALSE; | |
652 } | |
653 | |
654 FX_BOOL bNeedDownLoad = FALSE; | |
655 if (pEndOffSet->IsNumber()) { | |
656 uint32_t dwEnd = pEndOffSet->GetInteger(); | |
657 dwEnd += 512; | |
658 if ((FX_FILESIZE)dwEnd > m_dwFileLen) | |
659 dwEnd = (uint32_t)m_dwFileLen; | |
660 | |
661 int32_t iStartPos = (int32_t)(m_dwFileLen > 1024 ? 1024 : m_dwFileLen); | |
662 int32_t iSize = dwEnd > 1024 ? dwEnd - 1024 : 0; | |
663 if (!m_pFileAvail->IsDataAvail(iStartPos, iSize)) { | |
664 pHints->AddSegment(iStartPos, iSize); | |
665 bNeedDownLoad = TRUE; | |
666 } | |
667 } | |
668 | |
669 m_dwLastXRefOffset = 0; | |
670 FX_FILESIZE dwFileLen = 0; | |
671 if (pXRefOffset->IsNumber()) | |
672 m_dwLastXRefOffset = pXRefOffset->GetInteger(); | |
673 | |
674 if (pFileLen->IsNumber()) | |
675 dwFileLen = pFileLen->GetInteger(); | |
676 | |
677 if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, | |
678 (uint32_t)(dwFileLen - m_dwLastXRefOffset))) { | |
679 if (m_docStatus == PDF_DATAAVAIL_FIRSTPAGE) { | |
680 uint32_t dwSize = (uint32_t)(dwFileLen - m_dwLastXRefOffset); | |
681 FX_FILESIZE offset = m_dwLastXRefOffset; | |
682 if (dwSize < 512 && dwFileLen > 512) { | |
683 dwSize = 512; | |
684 offset = dwFileLen - 512; | |
685 } | |
686 pHints->AddSegment(offset, dwSize); | |
687 } | |
688 } else { | |
689 m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; | |
690 } | |
691 | |
692 if (bNeedDownLoad || m_docStatus != PDF_DATAAVAIL_FIRSTPAGE_PREPARE) { | |
693 m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; | |
694 return FALSE; | |
695 } | |
696 | |
697 m_docStatus = | |
698 m_bSupportHintTable ? PDF_DATAAVAIL_HINTTABLE : PDF_DATAAVAIL_DONE; | |
699 return TRUE; | |
700 } | |
701 | |
702 FX_BOOL CPDF_DataAvail::IsDataAvail(FX_FILESIZE offset, | |
703 uint32_t size, | |
704 DownloadHints* pHints) { | |
705 if (offset < 0 || offset > m_dwFileLen) | |
706 return TRUE; | |
707 | |
708 FX_SAFE_FILESIZE safeSize = offset; | |
709 safeSize += size; | |
710 safeSize += 512; | |
711 if (!safeSize.IsValid() || safeSize.ValueOrDie() > m_dwFileLen) | |
712 size = m_dwFileLen - offset; | |
713 else | |
714 size += 512; | |
715 | |
716 if (!m_pFileAvail->IsDataAvail(offset, size)) { | |
717 pHints->AddSegment(offset, size); | |
718 return FALSE; | |
719 } | |
720 return TRUE; | |
721 } | |
722 | |
723 FX_BOOL CPDF_DataAvail::CheckHintTables(DownloadHints* pHints) { | |
724 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
725 if (!pDict) { | |
726 m_docStatus = PDF_DATAAVAIL_ERROR; | |
727 return FALSE; | |
728 } | |
729 | |
730 // The actual value is not required here, but validate its existence and type. | |
731 CPDF_Number* pFirstPage = ToNumber(pDict->GetDirectObjectFor("O")); | |
732 if (!pFirstPage || !pFirstPage->IsInteger()) { | |
733 m_docStatus = PDF_DATAAVAIL_ERROR; | |
734 return FALSE; | |
735 } | |
736 | |
737 CPDF_Number* pPageCount = ToNumber(pDict->GetDirectObjectFor("N")); | |
738 if (!pPageCount || !pPageCount->IsInteger()) { | |
739 m_docStatus = PDF_DATAAVAIL_ERROR; | |
740 return FALSE; | |
741 } | |
742 | |
743 int nPageCount = pPageCount->GetInteger(); | |
744 if (nPageCount <= 1) { | |
745 m_docStatus = PDF_DATAAVAIL_DONE; | |
746 return TRUE; | |
747 } | |
748 | |
749 CPDF_Array* pHintStreamRange = pDict->GetArrayFor("H"); | |
750 size_t nHintStreamSize = pHintStreamRange ? pHintStreamRange->GetCount() : 0; | |
751 if (nHintStreamSize != 2 && nHintStreamSize != 4) { | |
752 m_docStatus = PDF_DATAAVAIL_ERROR; | |
753 return FALSE; | |
754 } | |
755 | |
756 for (const CPDF_Object* pArrayObject : *pHintStreamRange) { | |
757 const CPDF_Number* pNumber = ToNumber(pArrayObject->GetDirect()); | |
758 if (!pNumber || !pNumber->IsInteger()) { | |
759 m_docStatus = PDF_DATAAVAIL_ERROR; | |
760 return FALSE; | |
761 } | |
762 } | |
763 | |
764 FX_FILESIZE szHintStart = pHintStreamRange->GetIntegerAt(0); | |
765 FX_FILESIZE szHintLength = pHintStreamRange->GetIntegerAt(1); | |
766 if (szHintStart < 0 || szHintLength <= 0) { | |
767 m_docStatus = PDF_DATAAVAIL_ERROR; | |
768 return FALSE; | |
769 } | |
770 | |
771 if (!IsDataAvail(szHintStart, szHintLength, pHints)) | |
772 return FALSE; | |
773 | |
774 m_syntaxParser.InitParser(m_pFileRead, m_dwHeaderOffset); | |
775 | |
776 std::unique_ptr<CPDF_HintTables> pHintTables( | |
777 new CPDF_HintTables(this, pDict)); | |
778 std::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> pHintStream( | |
779 ParseIndirectObjectAt(szHintStart, 0)); | |
780 CPDF_Stream* pStream = ToStream(pHintStream.get()); | |
781 if (pStream && pHintTables->LoadHintStream(pStream)) | |
782 m_pHintTables = std::move(pHintTables); | |
783 | |
784 m_docStatus = PDF_DATAAVAIL_DONE; | |
785 return TRUE; | |
786 } | |
787 | |
788 CPDF_Object* CPDF_DataAvail::ParseIndirectObjectAt( | |
789 FX_FILESIZE pos, | |
790 uint32_t objnum, | |
791 CPDF_IndirectObjectHolder* pObjList) { | |
792 FX_FILESIZE SavedPos = m_syntaxParser.SavePos(); | |
793 m_syntaxParser.RestorePos(pos); | |
794 | |
795 bool bIsNumber; | |
796 CFX_ByteString word = m_syntaxParser.GetNextWord(&bIsNumber); | |
797 if (!bIsNumber) | |
798 return nullptr; | |
799 | |
800 uint32_t parser_objnum = FXSYS_atoui(word.c_str()); | |
801 if (objnum && parser_objnum != objnum) | |
802 return nullptr; | |
803 | |
804 word = m_syntaxParser.GetNextWord(&bIsNumber); | |
805 if (!bIsNumber) | |
806 return nullptr; | |
807 | |
808 uint32_t gennum = FXSYS_atoui(word.c_str()); | |
809 if (m_syntaxParser.GetKeyword() != "obj") { | |
810 m_syntaxParser.RestorePos(SavedPos); | |
811 return nullptr; | |
812 } | |
813 | |
814 CPDF_Object* pObj = | |
815 m_syntaxParser.GetObject(pObjList, parser_objnum, gennum, true); | |
816 m_syntaxParser.RestorePos(SavedPos); | |
817 return pObj; | |
818 } | |
819 | |
820 CPDF_DataAvail::DocLinearizationStatus CPDF_DataAvail::IsLinearizedPDF() { | |
821 const uint32_t kReqSize = 1024; | |
822 if (!m_pFileAvail->IsDataAvail(0, kReqSize)) | |
823 return LinearizationUnknown; | |
824 | |
825 if (!m_pFileRead) | |
826 return NotLinearized; | |
827 | |
828 FX_FILESIZE dwSize = m_pFileRead->GetSize(); | |
829 if (dwSize < (FX_FILESIZE)kReqSize) | |
830 return LinearizationUnknown; | |
831 | |
832 uint8_t buffer[1024]; | |
833 m_pFileRead->ReadBlock(buffer, 0, kReqSize); | |
834 if (IsLinearizedFile(buffer, kReqSize)) | |
835 return Linearized; | |
836 | |
837 return NotLinearized; | |
838 } | |
839 | |
840 FX_BOOL CPDF_DataAvail::IsLinearized() { | |
841 return m_bLinearized; | |
842 } | |
843 | |
844 FX_BOOL CPDF_DataAvail::IsLinearizedFile(uint8_t* pData, uint32_t dwLen) { | |
845 if (m_pLinearized) | |
846 return m_bLinearized; | |
847 | |
848 ScopedFileStream file(FX_CreateMemoryStream(pData, (size_t)dwLen, FALSE)); | |
849 | |
850 int32_t offset = GetHeaderOffset(file.get()); | |
851 if (offset == -1) { | |
852 m_docStatus = PDF_DATAAVAIL_ERROR; | |
853 return FALSE; | |
854 } | |
855 | |
856 m_dwHeaderOffset = offset; | |
857 m_syntaxParser.InitParser(file.get(), offset); | |
858 m_syntaxParser.RestorePos(m_syntaxParser.m_HeaderOffset + 9); | |
859 | |
860 bool bNumber; | |
861 CFX_ByteString wordObjNum = m_syntaxParser.GetNextWord(&bNumber); | |
862 if (!bNumber) | |
863 return FALSE; | |
864 | |
865 uint32_t objnum = FXSYS_atoui(wordObjNum.c_str()); | |
866 m_pLinearized = | |
867 ParseIndirectObjectAt(m_syntaxParser.m_HeaderOffset + 9, objnum); | |
868 if (!m_pLinearized) | |
869 return FALSE; | |
870 | |
871 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
872 if (!pDict || !pDict->GetObjectFor("Linearized")) | |
873 return FALSE; | |
874 | |
875 CPDF_Object* pLen = pDict->GetObjectFor("L"); | |
876 if (!pLen) | |
877 return FALSE; | |
878 | |
879 if ((FX_FILESIZE)pLen->GetInteger() != m_pFileRead->GetSize()) | |
880 return FALSE; | |
881 | |
882 m_bLinearized = TRUE; | |
883 | |
884 if (CPDF_Number* pNo = ToNumber(pDict->GetObjectFor("P"))) | |
885 m_dwFirstPageNo = pNo->GetInteger(); | |
886 | |
887 return TRUE; | |
888 } | |
889 | |
890 FX_BOOL CPDF_DataAvail::CheckEnd(DownloadHints* pHints) { | |
891 uint32_t req_pos = (uint32_t)(m_dwFileLen > 1024 ? m_dwFileLen - 1024 : 0); | |
892 uint32_t dwSize = (uint32_t)(m_dwFileLen - req_pos); | |
893 | |
894 if (m_pFileAvail->IsDataAvail(req_pos, dwSize)) { | |
895 uint8_t buffer[1024]; | |
896 m_pFileRead->ReadBlock(buffer, req_pos, dwSize); | |
897 | |
898 ScopedFileStream file(FX_CreateMemoryStream(buffer, (size_t)dwSize, FALSE)); | |
899 m_syntaxParser.InitParser(file.get(), 0); | |
900 m_syntaxParser.RestorePos(dwSize - 1); | |
901 | |
902 if (m_syntaxParser.SearchWord("startxref", TRUE, FALSE, dwSize)) { | |
903 m_syntaxParser.GetNextWord(nullptr); | |
904 | |
905 bool bNumber; | |
906 CFX_ByteString xrefpos_str = m_syntaxParser.GetNextWord(&bNumber); | |
907 if (!bNumber) { | |
908 m_docStatus = PDF_DATAAVAIL_ERROR; | |
909 return FALSE; | |
910 } | |
911 | |
912 m_dwXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str.c_str()); | |
913 if (!m_dwXRefOffset || m_dwXRefOffset > m_dwFileLen) { | |
914 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
915 return TRUE; | |
916 } | |
917 | |
918 m_dwLastXRefOffset = m_dwXRefOffset; | |
919 SetStartOffset(m_dwXRefOffset); | |
920 m_docStatus = PDF_DATAAVAIL_CROSSREF; | |
921 return TRUE; | |
922 } | |
923 | |
924 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
925 return TRUE; | |
926 } | |
927 | |
928 pHints->AddSegment(req_pos, dwSize); | |
929 return FALSE; | |
930 } | |
931 | |
932 int32_t CPDF_DataAvail::CheckCrossRefStream(DownloadHints* pHints, | |
933 FX_FILESIZE& xref_offset) { | |
934 xref_offset = 0; | |
935 uint32_t req_size = | |
936 (uint32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
937 | |
938 if (m_pFileAvail->IsDataAvail(m_Pos, req_size)) { | |
939 int32_t iSize = (int32_t)(m_Pos + req_size - m_dwCurrentXRefSteam); | |
940 CFX_BinaryBuf buf(iSize); | |
941 uint8_t* pBuf = buf.GetBuffer(); | |
942 | |
943 m_pFileRead->ReadBlock(pBuf, m_dwCurrentXRefSteam, iSize); | |
944 | |
945 ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); | |
946 m_parser.m_pSyntax->InitParser(file.get(), 0); | |
947 | |
948 bool bNumber; | |
949 CFX_ByteString objnum = m_parser.m_pSyntax->GetNextWord(&bNumber); | |
950 if (!bNumber) | |
951 return -1; | |
952 | |
953 uint32_t objNum = FXSYS_atoui(objnum.c_str()); | |
954 CPDF_Object* pObj = m_parser.ParseIndirectObjectAt(nullptr, 0, objNum); | |
955 if (!pObj) { | |
956 m_Pos += m_parser.m_pSyntax->SavePos(); | |
957 return 0; | |
958 } | |
959 | |
960 CPDF_Dictionary* pDict = pObj->GetDict(); | |
961 CPDF_Name* pName = ToName(pDict ? pDict->GetObjectFor("Type") : nullptr); | |
962 if (pName) { | |
963 if (pName->GetString() == "XRef") { | |
964 m_Pos += m_parser.m_pSyntax->SavePos(); | |
965 xref_offset = pObj->GetDict()->GetIntegerFor("Prev"); | |
966 pObj->Release(); | |
967 return 1; | |
968 } | |
969 } | |
970 pObj->Release(); | |
971 return -1; | |
972 } | |
973 pHints->AddSegment(m_Pos, req_size); | |
974 return 0; | |
975 } | |
976 | |
977 void CPDF_DataAvail::SetStartOffset(FX_FILESIZE dwOffset) { | |
978 m_Pos = dwOffset; | |
979 } | |
980 | |
981 FX_BOOL CPDF_DataAvail::GetNextToken(CFX_ByteString& token) { | |
982 uint8_t ch; | |
983 if (!GetNextChar(ch)) | |
984 return FALSE; | |
985 | |
986 while (1) { | |
987 while (PDFCharIsWhitespace(ch)) { | |
988 if (!GetNextChar(ch)) | |
989 return FALSE; | |
990 } | |
991 | |
992 if (ch != '%') | |
993 break; | |
994 | |
995 while (1) { | |
996 if (!GetNextChar(ch)) | |
997 return FALSE; | |
998 if (PDFCharIsLineEnding(ch)) | |
999 break; | |
1000 } | |
1001 } | |
1002 | |
1003 uint8_t buffer[256]; | |
1004 uint32_t index = 0; | |
1005 if (PDFCharIsDelimiter(ch)) { | |
1006 buffer[index++] = ch; | |
1007 if (ch == '/') { | |
1008 while (1) { | |
1009 if (!GetNextChar(ch)) | |
1010 return FALSE; | |
1011 | |
1012 if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { | |
1013 m_Pos--; | |
1014 CFX_ByteString ret(buffer, index); | |
1015 token = ret; | |
1016 return TRUE; | |
1017 } | |
1018 | |
1019 if (index < sizeof(buffer)) | |
1020 buffer[index++] = ch; | |
1021 } | |
1022 } else if (ch == '<') { | |
1023 if (!GetNextChar(ch)) | |
1024 return FALSE; | |
1025 | |
1026 if (ch == '<') | |
1027 buffer[index++] = ch; | |
1028 else | |
1029 m_Pos--; | |
1030 } else if (ch == '>') { | |
1031 if (!GetNextChar(ch)) | |
1032 return FALSE; | |
1033 | |
1034 if (ch == '>') | |
1035 buffer[index++] = ch; | |
1036 else | |
1037 m_Pos--; | |
1038 } | |
1039 | |
1040 CFX_ByteString ret(buffer, index); | |
1041 token = ret; | |
1042 return TRUE; | |
1043 } | |
1044 | |
1045 while (1) { | |
1046 if (index < sizeof(buffer)) | |
1047 buffer[index++] = ch; | |
1048 | |
1049 if (!GetNextChar(ch)) | |
1050 return FALSE; | |
1051 | |
1052 if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { | |
1053 m_Pos--; | |
1054 break; | |
1055 } | |
1056 } | |
1057 | |
1058 token = CFX_ByteString(buffer, index); | |
1059 return TRUE; | |
1060 } | |
1061 | |
1062 FX_BOOL CPDF_DataAvail::GetNextChar(uint8_t& ch) { | |
1063 FX_FILESIZE pos = m_Pos; | |
1064 if (pos >= m_dwFileLen) | |
1065 return FALSE; | |
1066 | |
1067 if (m_bufferOffset >= pos || | |
1068 (FX_FILESIZE)(m_bufferOffset + m_bufferSize) <= pos) { | |
1069 FX_FILESIZE read_pos = pos; | |
1070 uint32_t read_size = 512; | |
1071 if ((FX_FILESIZE)read_size > m_dwFileLen) | |
1072 read_size = (uint32_t)m_dwFileLen; | |
1073 | |
1074 if ((FX_FILESIZE)(read_pos + read_size) > m_dwFileLen) | |
1075 read_pos = m_dwFileLen - read_size; | |
1076 | |
1077 if (!m_pFileRead->ReadBlock(m_bufferData, read_pos, read_size)) | |
1078 return FALSE; | |
1079 | |
1080 m_bufferOffset = read_pos; | |
1081 m_bufferSize = read_size; | |
1082 } | |
1083 ch = m_bufferData[pos - m_bufferOffset]; | |
1084 m_Pos++; | |
1085 return TRUE; | |
1086 } | |
1087 | |
1088 FX_BOOL CPDF_DataAvail::CheckCrossRefItem(DownloadHints* pHints) { | |
1089 int32_t iSize = 0; | |
1090 CFX_ByteString token; | |
1091 while (1) { | |
1092 if (!GetNextToken(token)) { | |
1093 iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
1094 pHints->AddSegment(m_Pos, iSize); | |
1095 return FALSE; | |
1096 } | |
1097 | |
1098 if (token == "trailer") { | |
1099 m_dwTrailerOffset = m_Pos; | |
1100 m_docStatus = PDF_DATAAVAIL_TRAILER; | |
1101 return TRUE; | |
1102 } | |
1103 } | |
1104 } | |
1105 | |
1106 FX_BOOL CPDF_DataAvail::CheckAllCrossRefStream(DownloadHints* pHints) { | |
1107 FX_FILESIZE xref_offset = 0; | |
1108 | |
1109 int32_t nRet = CheckCrossRefStream(pHints, xref_offset); | |
1110 if (nRet == 1) { | |
1111 if (!xref_offset) { | |
1112 m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF; | |
1113 } else { | |
1114 m_dwCurrentXRefSteam = xref_offset; | |
1115 m_Pos = xref_offset; | |
1116 } | |
1117 return TRUE; | |
1118 } | |
1119 | |
1120 if (nRet == -1) | |
1121 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1122 return FALSE; | |
1123 } | |
1124 | |
1125 FX_BOOL CPDF_DataAvail::CheckCrossRef(DownloadHints* pHints) { | |
1126 int32_t iSize = 0; | |
1127 CFX_ByteString token; | |
1128 if (!GetNextToken(token)) { | |
1129 iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
1130 pHints->AddSegment(m_Pos, iSize); | |
1131 return FALSE; | |
1132 } | |
1133 | |
1134 if (token == "xref") { | |
1135 while (1) { | |
1136 if (!GetNextToken(token)) { | |
1137 iSize = | |
1138 (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
1139 pHints->AddSegment(m_Pos, iSize); | |
1140 m_docStatus = PDF_DATAAVAIL_CROSSREF_ITEM; | |
1141 return FALSE; | |
1142 } | |
1143 | |
1144 if (token == "trailer") { | |
1145 m_dwTrailerOffset = m_Pos; | |
1146 m_docStatus = PDF_DATAAVAIL_TRAILER; | |
1147 return TRUE; | |
1148 } | |
1149 } | |
1150 } else { | |
1151 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
1152 return TRUE; | |
1153 } | |
1154 return FALSE; | |
1155 } | |
1156 | |
1157 FX_BOOL CPDF_DataAvail::CheckTrailerAppend(DownloadHints* pHints) { | |
1158 if (m_Pos < m_dwFileLen) { | |
1159 FX_FILESIZE dwAppendPos = m_Pos + m_syntaxParser.SavePos(); | |
1160 int32_t iSize = (int32_t)( | |
1161 dwAppendPos + 512 > m_dwFileLen ? m_dwFileLen - dwAppendPos : 512); | |
1162 | |
1163 if (!m_pFileAvail->IsDataAvail(dwAppendPos, iSize)) { | |
1164 pHints->AddSegment(dwAppendPos, iSize); | |
1165 return FALSE; | |
1166 } | |
1167 } | |
1168 | |
1169 if (m_dwPrevXRefOffset) { | |
1170 SetStartOffset(m_dwPrevXRefOffset); | |
1171 m_docStatus = PDF_DATAAVAIL_CROSSREF; | |
1172 } else { | |
1173 m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF; | |
1174 } | |
1175 return TRUE; | |
1176 } | |
1177 | |
1178 FX_BOOL CPDF_DataAvail::CheckTrailer(DownloadHints* pHints) { | |
1179 int32_t iTrailerSize = | |
1180 (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
1181 if (m_pFileAvail->IsDataAvail(m_Pos, iTrailerSize)) { | |
1182 int32_t iSize = (int32_t)(m_Pos + iTrailerSize - m_dwTrailerOffset); | |
1183 CFX_BinaryBuf buf(iSize); | |
1184 uint8_t* pBuf = buf.GetBuffer(); | |
1185 if (!pBuf) { | |
1186 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1187 return FALSE; | |
1188 } | |
1189 | |
1190 if (!m_pFileRead->ReadBlock(pBuf, m_dwTrailerOffset, iSize)) | |
1191 return FALSE; | |
1192 | |
1193 ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); | |
1194 m_syntaxParser.InitParser(file.get(), 0); | |
1195 | |
1196 std::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> pTrailer( | |
1197 m_syntaxParser.GetObject(nullptr, 0, 0, true)); | |
1198 if (!pTrailer) { | |
1199 m_Pos += m_syntaxParser.SavePos(); | |
1200 pHints->AddSegment(m_Pos, iTrailerSize); | |
1201 return FALSE; | |
1202 } | |
1203 | |
1204 if (!pTrailer->IsDictionary()) | |
1205 return FALSE; | |
1206 | |
1207 CPDF_Dictionary* pTrailerDict = pTrailer->GetDict(); | |
1208 CPDF_Object* pEncrypt = pTrailerDict->GetObjectFor("Encrypt"); | |
1209 if (ToReference(pEncrypt)) { | |
1210 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
1211 return TRUE; | |
1212 } | |
1213 | |
1214 uint32_t xrefpos = GetDirectInteger(pTrailerDict, "Prev"); | |
1215 if (xrefpos) { | |
1216 m_dwPrevXRefOffset = GetDirectInteger(pTrailerDict, "XRefStm"); | |
1217 if (m_dwPrevXRefOffset) { | |
1218 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
1219 } else { | |
1220 m_dwPrevXRefOffset = xrefpos; | |
1221 if (m_dwPrevXRefOffset >= m_dwFileLen) { | |
1222 m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
1223 } else { | |
1224 SetStartOffset(m_dwPrevXRefOffset); | |
1225 m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; | |
1226 } | |
1227 } | |
1228 return TRUE; | |
1229 } | |
1230 m_dwPrevXRefOffset = 0; | |
1231 m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; | |
1232 return TRUE; | |
1233 } | |
1234 pHints->AddSegment(m_Pos, iTrailerSize); | |
1235 return FALSE; | |
1236 } | |
1237 | |
1238 FX_BOOL CPDF_DataAvail::CheckPage(uint32_t dwPage, DownloadHints* pHints) { | |
1239 while (TRUE) { | |
1240 switch (m_docStatus) { | |
1241 case PDF_DATAAVAIL_PAGETREE: | |
1242 if (!LoadDocPages(pHints)) | |
1243 return FALSE; | |
1244 break; | |
1245 case PDF_DATAAVAIL_PAGE: | |
1246 if (!LoadDocPage(dwPage, pHints)) | |
1247 return FALSE; | |
1248 break; | |
1249 case PDF_DATAAVAIL_ERROR: | |
1250 return LoadAllFile(pHints); | |
1251 default: | |
1252 m_bPagesTreeLoad = TRUE; | |
1253 m_bPagesLoad = TRUE; | |
1254 m_bCurPageDictLoadOK = TRUE; | |
1255 m_docStatus = PDF_DATAAVAIL_PAGE; | |
1256 return TRUE; | |
1257 } | |
1258 } | |
1259 } | |
1260 | |
1261 FX_BOOL CPDF_DataAvail::CheckArrayPageNode(uint32_t dwPageNo, | |
1262 PageNode* pPageNode, | |
1263 DownloadHints* pHints) { | |
1264 FX_BOOL bExist = FALSE; | |
1265 CPDF_Object* pPages = GetObject(dwPageNo, pHints, &bExist); | |
1266 if (!bExist) { | |
1267 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1268 return FALSE; | |
1269 } | |
1270 | |
1271 if (!pPages) { | |
1272 if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
1273 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1274 return FALSE; | |
1275 } | |
1276 return FALSE; | |
1277 } | |
1278 | |
1279 CPDF_Array* pArray = pPages->AsArray(); | |
1280 if (!pArray) { | |
1281 pPages->Release(); | |
1282 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1283 return FALSE; | |
1284 } | |
1285 | |
1286 pPageNode->m_type = PDF_PAGENODE_PAGES; | |
1287 for (size_t i = 0; i < pArray->GetCount(); ++i) { | |
1288 CPDF_Reference* pKid = ToReference(pArray->GetObjectAt(i)); | |
1289 if (!pKid) | |
1290 continue; | |
1291 | |
1292 PageNode* pNode = new PageNode(); | |
1293 pPageNode->m_childNode.Add(pNode); | |
1294 pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
1295 } | |
1296 pPages->Release(); | |
1297 return TRUE; | |
1298 } | |
1299 | |
1300 FX_BOOL CPDF_DataAvail::CheckUnkownPageNode(uint32_t dwPageNo, | |
1301 PageNode* pPageNode, | |
1302 DownloadHints* pHints) { | |
1303 FX_BOOL bExist = FALSE; | |
1304 CPDF_Object* pPage = GetObject(dwPageNo, pHints, &bExist); | |
1305 if (!bExist) { | |
1306 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1307 return FALSE; | |
1308 } | |
1309 | |
1310 if (!pPage) { | |
1311 if (m_docStatus == PDF_DATAAVAIL_ERROR) | |
1312 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1313 return FALSE; | |
1314 } | |
1315 | |
1316 if (pPage->IsArray()) { | |
1317 pPageNode->m_dwPageNo = dwPageNo; | |
1318 pPageNode->m_type = PDF_PAGENODE_ARRAY; | |
1319 pPage->Release(); | |
1320 return TRUE; | |
1321 } | |
1322 | |
1323 if (!pPage->IsDictionary()) { | |
1324 pPage->Release(); | |
1325 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1326 return FALSE; | |
1327 } | |
1328 | |
1329 pPageNode->m_dwPageNo = dwPageNo; | |
1330 CPDF_Dictionary* pDict = pPage->GetDict(); | |
1331 CFX_ByteString type = pDict->GetStringFor("Type"); | |
1332 if (type == "Pages") { | |
1333 pPageNode->m_type = PDF_PAGENODE_PAGES; | |
1334 CPDF_Object* pKids = pDict->GetObjectFor("Kids"); | |
1335 if (!pKids) { | |
1336 m_docStatus = PDF_DATAAVAIL_PAGE; | |
1337 return TRUE; | |
1338 } | |
1339 | |
1340 switch (pKids->GetType()) { | |
1341 case CPDF_Object::REFERENCE: { | |
1342 CPDF_Reference* pKid = pKids->AsReference(); | |
1343 PageNode* pNode = new PageNode(); | |
1344 pPageNode->m_childNode.Add(pNode); | |
1345 pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
1346 } break; | |
1347 case CPDF_Object::ARRAY: { | |
1348 CPDF_Array* pKidsArray = pKids->AsArray(); | |
1349 for (size_t i = 0; i < pKidsArray->GetCount(); ++i) { | |
1350 CPDF_Reference* pKid = ToReference(pKidsArray->GetObjectAt(i)); | |
1351 if (!pKid) | |
1352 continue; | |
1353 | |
1354 PageNode* pNode = new PageNode(); | |
1355 pPageNode->m_childNode.Add(pNode); | |
1356 pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
1357 } | |
1358 } break; | |
1359 default: | |
1360 break; | |
1361 } | |
1362 } else if (type == "Page") { | |
1363 pPageNode->m_type = PDF_PAGENODE_PAGE; | |
1364 } else { | |
1365 pPage->Release(); | |
1366 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1367 return FALSE; | |
1368 } | |
1369 pPage->Release(); | |
1370 return TRUE; | |
1371 } | |
1372 | |
1373 FX_BOOL CPDF_DataAvail::CheckPageNode(CPDF_DataAvail::PageNode& pageNodes, | |
1374 int32_t iPage, | |
1375 int32_t& iCount, | |
1376 DownloadHints* pHints, | |
1377 int level) { | |
1378 if (level >= kMaxPageRecursionDepth) | |
1379 return FALSE; | |
1380 | |
1381 int32_t iSize = pageNodes.m_childNode.GetSize(); | |
1382 if (iSize <= 0 || iPage >= iSize) { | |
1383 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1384 return FALSE; | |
1385 } | |
1386 | |
1387 for (int32_t i = 0; i < iSize; ++i) { | |
1388 PageNode* pNode = pageNodes.m_childNode.GetAt(i); | |
1389 if (!pNode) | |
1390 continue; | |
1391 | |
1392 switch (pNode->m_type) { | |
1393 case PDF_PAGENODE_UNKNOWN: | |
1394 if (!CheckUnkownPageNode(pNode->m_dwPageNo, pNode, pHints)) { | |
1395 return FALSE; | |
1396 } | |
1397 --i; | |
1398 break; | |
1399 case PDF_PAGENODE_PAGE: | |
1400 iCount++; | |
1401 if (iPage == iCount && m_pDocument) | |
1402 m_pDocument->SetPageObjNum(iPage, pNode->m_dwPageNo); | |
1403 break; | |
1404 case PDF_PAGENODE_PAGES: | |
1405 if (!CheckPageNode(*pNode, iPage, iCount, pHints, level + 1)) | |
1406 return FALSE; | |
1407 break; | |
1408 case PDF_PAGENODE_ARRAY: | |
1409 if (!CheckArrayPageNode(pNode->m_dwPageNo, pNode, pHints)) | |
1410 return FALSE; | |
1411 --i; | |
1412 break; | |
1413 } | |
1414 | |
1415 if (iPage == iCount) { | |
1416 m_docStatus = PDF_DATAAVAIL_DONE; | |
1417 return TRUE; | |
1418 } | |
1419 } | |
1420 return TRUE; | |
1421 } | |
1422 | |
1423 FX_BOOL CPDF_DataAvail::LoadDocPage(uint32_t dwPage, DownloadHints* pHints) { | |
1424 FX_SAFE_INT32 safePage = pdfium::base::checked_cast<int32_t>(dwPage); | |
1425 int32_t iPage = safePage.ValueOrDie(); | |
1426 if (m_pDocument->GetPageCount() <= iPage || | |
1427 m_pDocument->IsPageLoaded(iPage)) { | |
1428 m_docStatus = PDF_DATAAVAIL_DONE; | |
1429 return TRUE; | |
1430 } | |
1431 | |
1432 if (m_pageNodes.m_type == PDF_PAGENODE_PAGE) { | |
1433 if (iPage == 0) { | |
1434 m_docStatus = PDF_DATAAVAIL_DONE; | |
1435 return TRUE; | |
1436 } | |
1437 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1438 return TRUE; | |
1439 } | |
1440 int32_t iCount = -1; | |
1441 return CheckPageNode(m_pageNodes, iPage, iCount, pHints, 0); | |
1442 } | |
1443 | |
1444 FX_BOOL CPDF_DataAvail::CheckPageCount(DownloadHints* pHints) { | |
1445 FX_BOOL bExist = FALSE; | |
1446 CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist); | |
1447 if (!bExist) { | |
1448 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1449 return FALSE; | |
1450 } | |
1451 | |
1452 if (!pPages) | |
1453 return FALSE; | |
1454 | |
1455 CPDF_Dictionary* pPagesDict = pPages->GetDict(); | |
1456 if (!pPagesDict) { | |
1457 pPages->Release(); | |
1458 m_docStatus = PDF_DATAAVAIL_ERROR; | |
1459 return FALSE; | |
1460 } | |
1461 | |
1462 if (!pPagesDict->KeyExist("Kids")) { | |
1463 pPages->Release(); | |
1464 return TRUE; | |
1465 } | |
1466 | |
1467 int count = pPagesDict->GetIntegerFor("Count"); | |
1468 if (count > 0) { | |
1469 pPages->Release(); | |
1470 return TRUE; | |
1471 } | |
1472 | |
1473 pPages->Release(); | |
1474 return FALSE; | |
1475 } | |
1476 | |
1477 FX_BOOL CPDF_DataAvail::LoadDocPages(DownloadHints* pHints) { | |
1478 if (!CheckUnkownPageNode(m_PagesObjNum, &m_pageNodes, pHints)) | |
1479 return FALSE; | |
1480 | |
1481 if (CheckPageCount(pHints)) { | |
1482 m_docStatus = PDF_DATAAVAIL_PAGE; | |
1483 return TRUE; | |
1484 } | |
1485 | |
1486 m_bTotalLoadPageTree = TRUE; | |
1487 return FALSE; | |
1488 } | |
1489 | |
1490 FX_BOOL CPDF_DataAvail::LoadPages(DownloadHints* pHints) { | |
1491 while (!m_bPagesTreeLoad) { | |
1492 if (!CheckPageStatus(pHints)) | |
1493 return FALSE; | |
1494 } | |
1495 | |
1496 if (m_bPagesLoad) | |
1497 return TRUE; | |
1498 | |
1499 m_pDocument->LoadPages(); | |
1500 return FALSE; | |
1501 } | |
1502 | |
1503 CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedData( | |
1504 DownloadHints* pHints) { | |
1505 if (m_bLinearedDataOK) | |
1506 return DataAvailable; | |
1507 | |
1508 if (!m_bMainXRefLoadTried) { | |
1509 FX_SAFE_UINT32 data_size = m_dwFileLen; | |
1510 data_size -= m_dwLastXRefOffset; | |
1511 if (!data_size.IsValid()) | |
1512 return DataError; | |
1513 | |
1514 if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, | |
1515 data_size.ValueOrDie())) { | |
1516 pHints->AddSegment(m_dwLastXRefOffset, data_size.ValueOrDie()); | |
1517 return DataNotAvailable; | |
1518 } | |
1519 | |
1520 CPDF_Parser::Error eRet = | |
1521 m_pDocument->GetParser()->LoadLinearizedMainXRefTable(); | |
1522 m_bMainXRefLoadTried = TRUE; | |
1523 if (eRet != CPDF_Parser::SUCCESS) | |
1524 return DataError; | |
1525 | |
1526 if (!PreparePageItem()) | |
1527 return DataNotAvailable; | |
1528 | |
1529 m_bMainXRefLoadedOK = TRUE; | |
1530 m_bLinearedDataOK = TRUE; | |
1531 } | |
1532 | |
1533 return m_bLinearedDataOK ? DataAvailable : DataNotAvailable; | |
1534 } | |
1535 | |
1536 FX_BOOL CPDF_DataAvail::CheckPageAnnots(uint32_t dwPage, | |
1537 DownloadHints* pHints) { | |
1538 if (!m_objs_array.GetSize()) { | |
1539 m_objs_array.RemoveAll(); | |
1540 m_ObjectSet.clear(); | |
1541 | |
1542 FX_SAFE_INT32 safePage = pdfium::base::checked_cast<int32_t>(dwPage); | |
1543 CPDF_Dictionary* pPageDict = m_pDocument->GetPage(safePage.ValueOrDie()); | |
1544 if (!pPageDict) | |
1545 return TRUE; | |
1546 | |
1547 CPDF_Object* pAnnots = pPageDict->GetObjectFor("Annots"); | |
1548 if (!pAnnots) | |
1549 return TRUE; | |
1550 | |
1551 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
1552 obj_array.Add(pAnnots); | |
1553 | |
1554 FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); | |
1555 if (bRet) | |
1556 m_objs_array.RemoveAll(); | |
1557 | |
1558 return bRet; | |
1559 } | |
1560 | |
1561 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
1562 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
1563 m_objs_array.RemoveAll(); | |
1564 if (!bRet) | |
1565 m_objs_array.Append(new_objs_array); | |
1566 | |
1567 return bRet; | |
1568 } | |
1569 | |
1570 CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedFirstPage( | |
1571 uint32_t dwPage, | |
1572 DownloadHints* pHints) { | |
1573 if (!m_bAnnotsLoad) { | |
1574 if (!CheckPageAnnots(dwPage, pHints)) | |
1575 return DataNotAvailable; | |
1576 m_bAnnotsLoad = TRUE; | |
1577 } | |
1578 | |
1579 DocAvailStatus nRet = CheckLinearizedData(pHints); | |
1580 if (nRet == DataAvailable) | |
1581 m_bPageLoadedOK = FALSE; | |
1582 return nRet; | |
1583 } | |
1584 | |
1585 FX_BOOL CPDF_DataAvail::HaveResourceAncestor(CPDF_Dictionary* pDict) { | |
1586 CFX_AutoRestorer<int> restorer(&s_CurrentDataAvailRecursionDepth); | |
1587 if (++s_CurrentDataAvailRecursionDepth > kMaxDataAvailRecursionDepth) | |
1588 return FALSE; | |
1589 | |
1590 CPDF_Object* pParent = pDict->GetObjectFor("Parent"); | |
1591 if (!pParent) | |
1592 return FALSE; | |
1593 | |
1594 CPDF_Dictionary* pParentDict = pParent->GetDict(); | |
1595 if (!pParentDict) | |
1596 return FALSE; | |
1597 | |
1598 CPDF_Object* pRet = pParentDict->GetObjectFor("Resources"); | |
1599 if (pRet) { | |
1600 m_pPageResource = pRet; | |
1601 return TRUE; | |
1602 } | |
1603 | |
1604 return HaveResourceAncestor(pParentDict); | |
1605 } | |
1606 | |
1607 CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsPageAvail( | |
1608 uint32_t dwPage, | |
1609 DownloadHints* pHints) { | |
1610 if (!m_pDocument) | |
1611 return DataError; | |
1612 | |
1613 if (IsFirstCheck(dwPage)) { | |
1614 m_bCurPageDictLoadOK = FALSE; | |
1615 m_bPageLoadedOK = FALSE; | |
1616 m_bAnnotsLoad = FALSE; | |
1617 m_bNeedDownLoadResource = FALSE; | |
1618 m_objs_array.RemoveAll(); | |
1619 m_ObjectSet.clear(); | |
1620 } | |
1621 | |
1622 if (pdfium::ContainsKey(m_pagesLoadState, dwPage)) | |
1623 return DataAvailable; | |
1624 | |
1625 if (m_bLinearized) { | |
1626 if (dwPage == m_dwFirstPageNo) { | |
1627 DocAvailStatus nRet = CheckLinearizedFirstPage(dwPage, pHints); | |
1628 if (nRet == DataAvailable) | |
1629 m_pagesLoadState.insert(dwPage); | |
1630 return nRet; | |
1631 } | |
1632 | |
1633 DocAvailStatus nResult = CheckLinearizedData(pHints); | |
1634 if (nResult != DataAvailable) | |
1635 return nResult; | |
1636 | |
1637 if (m_pHintTables) { | |
1638 nResult = m_pHintTables->CheckPage(dwPage, pHints); | |
1639 if (nResult != DataAvailable) | |
1640 return nResult; | |
1641 m_pagesLoadState.insert(dwPage); | |
1642 return DataAvailable; | |
1643 } | |
1644 | |
1645 if (m_bMainXRefLoadedOK) { | |
1646 if (m_bTotalLoadPageTree) { | |
1647 if (!LoadPages(pHints)) | |
1648 return DataNotAvailable; | |
1649 } else { | |
1650 if (!m_bCurPageDictLoadOK && !CheckPage(dwPage, pHints)) | |
1651 return DataNotAvailable; | |
1652 } | |
1653 } else { | |
1654 if (!LoadAllFile(pHints)) | |
1655 return DataNotAvailable; | |
1656 m_pDocument->GetParser()->RebuildCrossRef(); | |
1657 ResetFirstCheck(dwPage); | |
1658 return DataAvailable; | |
1659 } | |
1660 } else { | |
1661 if (!m_bTotalLoadPageTree && !m_bCurPageDictLoadOK && | |
1662 !CheckPage(dwPage, pHints)) { | |
1663 return DataNotAvailable; | |
1664 } | |
1665 } | |
1666 | |
1667 if (m_bHaveAcroForm && !m_bAcroFormLoad) { | |
1668 if (!CheckAcroFormSubObject(pHints)) | |
1669 return DataNotAvailable; | |
1670 m_bAcroFormLoad = TRUE; | |
1671 } | |
1672 | |
1673 if (!m_bPageLoadedOK) { | |
1674 if (!m_objs_array.GetSize()) { | |
1675 m_objs_array.RemoveAll(); | |
1676 m_ObjectSet.clear(); | |
1677 | |
1678 FX_SAFE_INT32 safePage = pdfium::base::checked_cast<int32_t>(dwPage); | |
1679 m_pPageDict = m_pDocument->GetPage(safePage.ValueOrDie()); | |
1680 if (!m_pPageDict) { | |
1681 ResetFirstCheck(dwPage); | |
1682 return DataAvailable; | |
1683 } | |
1684 | |
1685 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
1686 obj_array.Add(m_pPageDict); | |
1687 FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); | |
1688 if (!bRet) | |
1689 return DataNotAvailable; | |
1690 | |
1691 m_objs_array.RemoveAll(); | |
1692 } else { | |
1693 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
1694 FX_BOOL bRet = | |
1695 IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
1696 | |
1697 m_objs_array.RemoveAll(); | |
1698 if (!bRet) { | |
1699 m_objs_array.Append(new_objs_array); | |
1700 return DataNotAvailable; | |
1701 } | |
1702 } | |
1703 m_bPageLoadedOK = TRUE; | |
1704 } | |
1705 | |
1706 if (!m_bAnnotsLoad) { | |
1707 if (!CheckPageAnnots(dwPage, pHints)) | |
1708 return DataNotAvailable; | |
1709 m_bAnnotsLoad = TRUE; | |
1710 } | |
1711 | |
1712 if (m_pPageDict && !m_bNeedDownLoadResource) { | |
1713 m_pPageResource = m_pPageDict->GetObjectFor("Resources"); | |
1714 m_bNeedDownLoadResource = | |
1715 m_pPageResource || HaveResourceAncestor(m_pPageDict); | |
1716 } | |
1717 | |
1718 if (m_bNeedDownLoadResource) { | |
1719 if (!CheckResources(pHints)) | |
1720 return DataNotAvailable; | |
1721 m_bNeedDownLoadResource = FALSE; | |
1722 } | |
1723 | |
1724 m_bPageLoadedOK = FALSE; | |
1725 m_bAnnotsLoad = FALSE; | |
1726 m_bCurPageDictLoadOK = FALSE; | |
1727 | |
1728 ResetFirstCheck(dwPage); | |
1729 m_pagesLoadState.insert(dwPage); | |
1730 return DataAvailable; | |
1731 } | |
1732 | |
1733 FX_BOOL CPDF_DataAvail::CheckResources(DownloadHints* pHints) { | |
1734 if (!m_objs_array.GetSize()) { | |
1735 m_objs_array.RemoveAll(); | |
1736 CFX_ArrayTemplate<CPDF_Object*> obj_array; | |
1737 obj_array.Add(m_pPageResource); | |
1738 | |
1739 FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); | |
1740 if (bRet) | |
1741 m_objs_array.RemoveAll(); | |
1742 return bRet; | |
1743 } | |
1744 | |
1745 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
1746 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
1747 m_objs_array.RemoveAll(); | |
1748 if (!bRet) | |
1749 m_objs_array.Append(new_objs_array); | |
1750 return bRet; | |
1751 } | |
1752 | |
1753 void CPDF_DataAvail::GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, | |
1754 uint32_t* pSize) { | |
1755 if (pPos) | |
1756 *pPos = m_dwLastXRefOffset; | |
1757 if (pSize) | |
1758 *pSize = (uint32_t)(m_dwFileLen - m_dwLastXRefOffset); | |
1759 } | |
1760 | |
1761 int CPDF_DataAvail::GetPageCount() const { | |
1762 if (m_pLinearized) { | |
1763 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
1764 CPDF_Object* pObj = pDict ? pDict->GetDirectObjectFor("N") : nullptr; | |
1765 return pObj ? pObj->GetInteger() : 0; | |
1766 } | |
1767 return m_pDocument ? m_pDocument->GetPageCount() : 0; | |
1768 } | |
1769 | |
1770 CPDF_Dictionary* CPDF_DataAvail::GetPage(int index) { | |
1771 if (!m_pDocument || index < 0 || index >= GetPageCount()) | |
1772 return nullptr; | |
1773 | |
1774 if (m_pLinearized) { | |
1775 CPDF_Dictionary* pDict = m_pLinearized->GetDict(); | |
1776 CPDF_Object* pObj = pDict ? pDict->GetDirectObjectFor("P") : nullptr; | |
1777 | |
1778 int pageNum = pObj ? pObj->GetInteger() : 0; | |
1779 if (m_pHintTables && index != pageNum) { | |
1780 FX_FILESIZE szPageStartPos = 0; | |
1781 FX_FILESIZE szPageLength = 0; | |
1782 uint32_t dwObjNum = 0; | |
1783 bool bPagePosGot = m_pHintTables->GetPagePos(index, &szPageStartPos, | |
1784 &szPageLength, &dwObjNum); | |
1785 if (!bPagePosGot) | |
1786 return nullptr; | |
1787 | |
1788 m_syntaxParser.InitParser(m_pFileRead, (uint32_t)szPageStartPos); | |
1789 CPDF_Object* pPageDict = ParseIndirectObjectAt(0, dwObjNum, m_pDocument); | |
1790 if (!pPageDict) | |
1791 return nullptr; | |
1792 | |
1793 if (!m_pDocument->ReplaceIndirectObjectIfHigherGeneration(dwObjNum, | |
1794 pPageDict)) { | |
1795 return nullptr; | |
1796 } | |
1797 return pPageDict->GetDict(); | |
1798 } | |
1799 } | |
1800 return m_pDocument->GetPage(index); | |
1801 } | |
1802 | |
1803 CPDF_DataAvail::DocFormStatus CPDF_DataAvail::IsFormAvail( | |
1804 DownloadHints* pHints) { | |
1805 if (!m_pDocument) | |
1806 return FormAvailable; | |
1807 | |
1808 if (!m_bLinearizedFormParamLoad) { | |
1809 CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); | |
1810 if (!pRoot) | |
1811 return FormAvailable; | |
1812 | |
1813 CPDF_Object* pAcroForm = pRoot->GetObjectFor("AcroForm"); | |
1814 if (!pAcroForm) | |
1815 return FormNotExist; | |
1816 | |
1817 DocAvailStatus nDocStatus = CheckLinearizedData(pHints); | |
1818 if (nDocStatus == DataError) | |
1819 return FormError; | |
1820 if (nDocStatus == DataNotAvailable) | |
1821 return FormNotAvailable; | |
1822 | |
1823 if (!m_objs_array.GetSize()) | |
1824 m_objs_array.Add(pAcroForm->GetDict()); | |
1825 m_bLinearizedFormParamLoad = TRUE; | |
1826 } | |
1827 | |
1828 CFX_ArrayTemplate<CPDF_Object*> new_objs_array; | |
1829 FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
1830 m_objs_array.RemoveAll(); | |
1831 if (!bRet) { | |
1832 m_objs_array.Append(new_objs_array); | |
1833 return FormNotAvailable; | |
1834 } | |
1835 return FormAvailable; | |
1836 } | |
1837 | |
1838 CPDF_DataAvail::PageNode::PageNode() : m_type(PDF_PAGENODE_UNKNOWN) {} | |
1839 | |
1840 CPDF_DataAvail::PageNode::~PageNode() { | |
1841 for (int32_t i = 0; i < m_childNode.GetSize(); ++i) | |
1842 delete m_childNode[i]; | |
1843 m_childNode.RemoveAll(); | |
1844 } | |
OLD | NEW |