Add PDFCharIsLineEnding helper
[pdfium.git] / core / src / fpdfapi / fpdf_parser / fpdf_parser_parser.cpp
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 <set>
8 #include <utility>
9 #include <vector>
10
11 #include "../../../../third_party/base/nonstd_unique_ptr.h"
12 #include "../../../../third_party/base/stl_util.h"
13 #include "../../../include/fpdfapi/fpdf_module.h"
14 #include "../../../include/fpdfapi/fpdf_page.h"
15 #include "../../../include/fpdfapi/fpdf_parser.h"
16 #include "../../../include/fxcrt/fx_safe_types.h"
17 #include "../fpdf_page/pageint.h"
18
19 namespace {
20
21 struct SearchTagRecord {
22   const uint8_t* m_pTag;
23   FX_DWORD m_Len;
24   FX_DWORD m_Offset;
25 };
26
27 int CompareFileSize(const void* p1, const void* p2) {
28   return *(FX_FILESIZE*)p1 - *(FX_FILESIZE*)p2;
29 }
30
31 int32_t GetHeaderOffset(IFX_FileRead* pFile) {
32   const FX_DWORD tag = FXDWORD_FROM_LSBFIRST(0x46445025);
33   const size_t kBufSize = 4;
34   uint8_t buf[kBufSize];
35   int32_t offset = 0;
36   while (offset <= 1024) {
37     if (!pFile->ReadBlock(buf, offset, kBufSize))
38       return -1;
39
40     if (*(FX_DWORD*)buf == tag)
41       return offset;
42
43     ++offset;
44   }
45   return -1;
46 }
47
48 int32_t GetDirectInteger(CPDF_Dictionary* pDict, const CFX_ByteStringC& key) {
49   CPDF_Number* pObj = ToNumber(pDict->GetElement(key));
50   return pObj ? pObj->GetInteger() : 0;
51 }
52
53 bool CheckDirectType(CPDF_Dictionary* pDict,
54                      const CFX_ByteStringC& key,
55                      int32_t iType) {
56   CPDF_Object* pObj = pDict->GetElement(key);
57   return !pObj || pObj->GetType() == iType;
58 }
59
60 FX_DWORD GetVarInt(const uint8_t* p, int32_t n) {
61   FX_DWORD result = 0;
62   for (int32_t i = 0; i < n; ++i)
63     result = result * 256 + p[i];
64   return result;
65 }
66
67 int32_t GetStreamNCount(CPDF_StreamAcc* pObjStream) {
68   return pObjStream->GetDict()->GetInteger(FX_BSTRC("N"));
69 }
70
71 int32_t GetStreamFirst(CPDF_StreamAcc* pObjStream) {
72   return pObjStream->GetDict()->GetInteger(FX_BSTRC("First"));
73 }
74
75 }  // namespace
76
77 // TODO(thestig) Using unique_ptr with ReleaseDeleter is still not ideal.
78 // Come up or wait for something better.
79 using ScopedFileStream =
80     nonstd::unique_ptr<IFX_FileStream, ReleaseDeleter<IFX_FileStream>>;
81
82 FX_BOOL IsSignatureDict(const CPDF_Dictionary* pDict) {
83   CPDF_Object* pType = pDict->GetElementValue(FX_BSTRC("Type"));
84   if (!pType) {
85     pType = pDict->GetElementValue(FX_BSTRC("FT"));
86     if (!pType) {
87       return FALSE;
88     }
89   }
90   if (pType->GetString() == FX_BSTRC("Sig")) {
91     return TRUE;
92   }
93   return FALSE;
94 }
95
96 CPDF_Parser::CPDF_Parser() {
97   m_pDocument = NULL;
98   m_pTrailer = NULL;
99   m_pEncryptDict = NULL;
100   m_pLinearized = NULL;
101   m_dwFirstPageNo = 0;
102   m_dwXrefStartObjNum = 0;
103   m_bOwnFileRead = TRUE;
104   m_FileVersion = 0;
105   m_bForceUseSecurityHandler = FALSE;
106 }
107 CPDF_Parser::~CPDF_Parser() {
108   CloseParser(FALSE);
109 }
110 FX_DWORD CPDF_Parser::GetLastObjNum() {
111   FX_DWORD dwSize = m_CrossRef.GetSize();
112   return dwSize ? dwSize - 1 : 0;
113 }
114 void CPDF_Parser::SetEncryptDictionary(CPDF_Dictionary* pDict) {
115   m_pEncryptDict = pDict;
116 }
117 void CPDF_Parser::CloseParser(FX_BOOL bReParse) {
118   m_bVersionUpdated = FALSE;
119   if (!bReParse) {
120     delete m_pDocument;
121     m_pDocument = NULL;
122   }
123   if (m_pTrailer) {
124     m_pTrailer->Release();
125     m_pTrailer = NULL;
126   }
127   ReleaseEncryptHandler();
128   SetEncryptDictionary(NULL);
129   if (m_bOwnFileRead && m_Syntax.m_pFileAccess) {
130     m_Syntax.m_pFileAccess->Release();
131     m_Syntax.m_pFileAccess = NULL;
132   }
133   FX_POSITION pos = m_ObjectStreamMap.GetStartPosition();
134   while (pos) {
135     void* objnum;
136     CPDF_StreamAcc* pStream;
137     m_ObjectStreamMap.GetNextAssoc(pos, objnum, (void*&)pStream);
138     delete pStream;
139   }
140   m_ObjectStreamMap.RemoveAll();
141   m_SortedOffset.RemoveAll();
142   m_CrossRef.RemoveAll();
143   m_V5Type.RemoveAll();
144   m_ObjVersion.RemoveAll();
145   int32_t iLen = m_Trailers.GetSize();
146   for (int32_t i = 0; i < iLen; ++i) {
147     if (CPDF_Dictionary* trailer = m_Trailers.GetAt(i))
148       trailer->Release();
149   }
150   m_Trailers.RemoveAll();
151   if (m_pLinearized) {
152     m_pLinearized->Release();
153     m_pLinearized = NULL;
154   }
155 }
156 CPDF_SecurityHandler* FPDF_CreateStandardSecurityHandler();
157 CPDF_SecurityHandler* FPDF_CreatePubKeyHandler(void*);
158 FX_DWORD CPDF_Parser::StartParse(IFX_FileRead* pFileAccess,
159                                  FX_BOOL bReParse,
160                                  FX_BOOL bOwnFileRead) {
161   CloseParser(bReParse);
162   m_bXRefStream = FALSE;
163   m_LastXRefOffset = 0;
164   m_bOwnFileRead = bOwnFileRead;
165   int32_t offset = GetHeaderOffset(pFileAccess);
166   if (offset == -1) {
167     if (bOwnFileRead && pFileAccess) {
168       pFileAccess->Release();
169     }
170     return PDFPARSE_ERROR_FORMAT;
171   }
172   m_Syntax.InitParser(pFileAccess, offset);
173   uint8_t ch;
174   if (!m_Syntax.GetCharAt(5, ch)) {
175     return PDFPARSE_ERROR_FORMAT;
176   }
177   if (ch >= '0' && ch <= '9') {
178     m_FileVersion = (ch - '0') * 10;
179   }
180   if (!m_Syntax.GetCharAt(7, ch)) {
181     return PDFPARSE_ERROR_FORMAT;
182   }
183   if (ch >= '0' && ch <= '9') {
184     m_FileVersion += ch - '0';
185   }
186   if (m_Syntax.m_FileLen < m_Syntax.m_HeaderOffset + 9) {
187     return PDFPARSE_ERROR_FORMAT;
188   }
189   m_Syntax.RestorePos(m_Syntax.m_FileLen - m_Syntax.m_HeaderOffset - 9);
190   if (!bReParse) {
191     m_pDocument = new CPDF_Document(this);
192   }
193   FX_BOOL bXRefRebuilt = FALSE;
194   if (m_Syntax.SearchWord(FX_BSTRC("startxref"), TRUE, FALSE, 4096)) {
195     FX_FILESIZE startxref_offset = m_Syntax.SavePos();
196     void* pResult = FXSYS_bsearch(&startxref_offset, m_SortedOffset.GetData(),
197                                   m_SortedOffset.GetSize(), sizeof(FX_FILESIZE),
198                                   CompareFileSize);
199     if (pResult == NULL) {
200       m_SortedOffset.Add(startxref_offset);
201     }
202     m_Syntax.GetKeyword();
203     FX_BOOL bNumber;
204     CFX_ByteString xrefpos_str = m_Syntax.GetNextWord(bNumber);
205     if (!bNumber) {
206       return PDFPARSE_ERROR_FORMAT;
207     }
208     m_LastXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str);
209     if (!LoadAllCrossRefV4(m_LastXRefOffset) &&
210         !LoadAllCrossRefV5(m_LastXRefOffset)) {
211       if (!RebuildCrossRef()) {
212         return PDFPARSE_ERROR_FORMAT;
213       }
214       bXRefRebuilt = TRUE;
215       m_LastXRefOffset = 0;
216     }
217   } else {
218     if (!RebuildCrossRef()) {
219       return PDFPARSE_ERROR_FORMAT;
220     }
221     bXRefRebuilt = TRUE;
222   }
223   FX_DWORD dwRet = SetEncryptHandler();
224   if (dwRet != PDFPARSE_ERROR_SUCCESS) {
225     return dwRet;
226   }
227   m_pDocument->LoadDoc();
228   if (m_pDocument->GetRoot() == NULL || m_pDocument->GetPageCount() == 0) {
229     if (bXRefRebuilt) {
230       return PDFPARSE_ERROR_FORMAT;
231     }
232     ReleaseEncryptHandler();
233     if (!RebuildCrossRef()) {
234       return PDFPARSE_ERROR_FORMAT;
235     }
236     dwRet = SetEncryptHandler();
237     if (dwRet != PDFPARSE_ERROR_SUCCESS) {
238       return dwRet;
239     }
240     m_pDocument->LoadDoc();
241     if (m_pDocument->GetRoot() == NULL) {
242       return PDFPARSE_ERROR_FORMAT;
243     }
244   }
245   FXSYS_qsort(m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
246               sizeof(FX_FILESIZE), CompareFileSize);
247   FX_DWORD RootObjNum = GetRootObjNum();
248   if (RootObjNum == 0) {
249     ReleaseEncryptHandler();
250     RebuildCrossRef();
251     RootObjNum = GetRootObjNum();
252     if (RootObjNum == 0) {
253       return PDFPARSE_ERROR_FORMAT;
254     }
255     dwRet = SetEncryptHandler();
256     if (dwRet != PDFPARSE_ERROR_SUCCESS) {
257       return dwRet;
258     }
259   }
260   if (m_pSecurityHandler && !m_pSecurityHandler->IsMetadataEncrypted()) {
261     CPDF_Reference* pMetadata =
262         ToReference(m_pDocument->GetRoot()->GetElement(FX_BSTRC("Metadata")));
263     if (pMetadata)
264       m_Syntax.m_MetadataObjnum = pMetadata->GetRefObjNum();
265   }
266   return PDFPARSE_ERROR_SUCCESS;
267 }
268 FX_DWORD CPDF_Parser::SetEncryptHandler() {
269   ReleaseEncryptHandler();
270   SetEncryptDictionary(NULL);
271   if (m_pTrailer == NULL) {
272     return PDFPARSE_ERROR_FORMAT;
273   }
274   CPDF_Object* pEncryptObj = m_pTrailer->GetElement(FX_BSTRC("Encrypt"));
275   if (pEncryptObj) {
276     if (CPDF_Dictionary* pEncryptDict = pEncryptObj->AsDictionary()) {
277       SetEncryptDictionary(pEncryptDict);
278     } else if (CPDF_Reference* pRef = pEncryptObj->AsReference()) {
279       pEncryptObj = m_pDocument->GetIndirectObject(pRef->GetRefObjNum());
280       if (pEncryptObj)
281         SetEncryptDictionary(pEncryptObj->GetDict());
282     }
283   }
284   if (m_bForceUseSecurityHandler) {
285     FX_DWORD err = PDFPARSE_ERROR_HANDLER;
286     if (!m_pSecurityHandler) {
287       return PDFPARSE_ERROR_HANDLER;
288     }
289     if (!m_pSecurityHandler->OnInit(this, m_pEncryptDict)) {
290       return err;
291     }
292     nonstd::unique_ptr<CPDF_CryptoHandler> pCryptoHandler(
293         m_pSecurityHandler->CreateCryptoHandler());
294     if (!pCryptoHandler->Init(m_pEncryptDict, m_pSecurityHandler.get())) {
295       return PDFPARSE_ERROR_HANDLER;
296     }
297     m_Syntax.SetEncrypt(pCryptoHandler.release());
298   } else if (m_pEncryptDict) {
299     CFX_ByteString filter = m_pEncryptDict->GetString(FX_BSTRC("Filter"));
300     nonstd::unique_ptr<CPDF_SecurityHandler> pSecurityHandler;
301     FX_DWORD err = PDFPARSE_ERROR_HANDLER;
302     if (filter == FX_BSTRC("Standard")) {
303       pSecurityHandler.reset(FPDF_CreateStandardSecurityHandler());
304       err = PDFPARSE_ERROR_PASSWORD;
305     }
306     if (!pSecurityHandler) {
307       return PDFPARSE_ERROR_HANDLER;
308     }
309     if (!pSecurityHandler->OnInit(this, m_pEncryptDict)) {
310       return err;
311     }
312     m_pSecurityHandler = nonstd::move(pSecurityHandler);
313     nonstd::unique_ptr<CPDF_CryptoHandler> pCryptoHandler(
314         m_pSecurityHandler->CreateCryptoHandler());
315     if (!pCryptoHandler->Init(m_pEncryptDict, m_pSecurityHandler.get())) {
316       return PDFPARSE_ERROR_HANDLER;
317     }
318     m_Syntax.SetEncrypt(pCryptoHandler.release());
319   }
320   return PDFPARSE_ERROR_SUCCESS;
321 }
322 void CPDF_Parser::ReleaseEncryptHandler() {
323   m_Syntax.m_pCryptoHandler.reset();
324   if (!m_bForceUseSecurityHandler) {
325     m_pSecurityHandler.reset();
326   }
327 }
328 FX_FILESIZE CPDF_Parser::GetObjectOffset(FX_DWORD objnum) {
329   if (objnum >= (FX_DWORD)m_CrossRef.GetSize()) {
330     return 0;
331   }
332   if (m_V5Type[objnum] == 1) {
333     return m_CrossRef[objnum];
334   }
335   if (m_V5Type[objnum] == 2) {
336     return m_CrossRef[(int32_t)m_CrossRef[objnum]];
337   }
338   return 0;
339 }
340
341 FX_BOOL CPDF_Parser::LoadAllCrossRefV4(FX_FILESIZE xrefpos) {
342   if (!LoadCrossRefV4(xrefpos, 0, TRUE, FALSE)) {
343     return FALSE;
344   }
345   m_pTrailer = LoadTrailerV4();
346   if (m_pTrailer == NULL) {
347     return FALSE;
348   }
349   int32_t xrefsize = GetDirectInteger(m_pTrailer, FX_BSTRC("Size"));
350   if (xrefsize <= 0 || xrefsize > (1 << 20)) {
351     return FALSE;
352   }
353   m_CrossRef.SetSize(xrefsize);
354   m_V5Type.SetSize(xrefsize);
355   CFX_FileSizeArray CrossRefList, XRefStreamList;
356   CrossRefList.Add(xrefpos);
357   XRefStreamList.Add(GetDirectInteger(m_pTrailer, FX_BSTRC("XRefStm")));
358   if (!CheckDirectType(m_pTrailer, FX_BSTRC("Prev"), PDFOBJ_NUMBER)) {
359     return FALSE;
360   }
361   FX_FILESIZE newxrefpos = GetDirectInteger(m_pTrailer, FX_BSTRC("Prev"));
362   if (newxrefpos == xrefpos) {
363     return FALSE;
364   }
365   xrefpos = newxrefpos;
366   while (xrefpos) {
367     CrossRefList.InsertAt(0, xrefpos);
368     LoadCrossRefV4(xrefpos, 0, TRUE, FALSE);
369     nonstd::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>> pDict(
370         LoadTrailerV4());
371     if (!pDict)
372       return FALSE;
373
374     if (!CheckDirectType(pDict.get(), FX_BSTRC("Prev"), PDFOBJ_NUMBER))
375       return FALSE;
376
377     newxrefpos = GetDirectInteger(pDict.get(), FX_BSTRC("Prev"));
378     if (newxrefpos == xrefpos)
379       return FALSE;
380
381     xrefpos = newxrefpos;
382     XRefStreamList.InsertAt(0, pDict->GetInteger(FX_BSTRC("XRefStm")));
383     m_Trailers.Add(pDict.release());
384   }
385   for (int32_t i = 0; i < CrossRefList.GetSize(); i++) {
386     if (!LoadCrossRefV4(CrossRefList[i], XRefStreamList[i], FALSE, i == 0))
387       return FALSE;
388   }
389   return TRUE;
390 }
391 FX_BOOL CPDF_Parser::LoadLinearizedAllCrossRefV4(FX_FILESIZE xrefpos,
392                                                  FX_DWORD dwObjCount) {
393   if (!LoadLinearizedCrossRefV4(xrefpos, dwObjCount)) {
394     return FALSE;
395   }
396   m_pTrailer = LoadTrailerV4();
397   if (m_pTrailer == NULL) {
398     return FALSE;
399   }
400   int32_t xrefsize = GetDirectInteger(m_pTrailer, FX_BSTRC("Size"));
401   if (xrefsize == 0) {
402     return FALSE;
403   }
404   CFX_FileSizeArray CrossRefList, XRefStreamList;
405   CrossRefList.Add(xrefpos);
406   XRefStreamList.Add(GetDirectInteger(m_pTrailer, FX_BSTRC("XRefStm")));
407   xrefpos = GetDirectInteger(m_pTrailer, FX_BSTRC("Prev"));
408   while (xrefpos) {
409     CrossRefList.InsertAt(0, xrefpos);
410     LoadCrossRefV4(xrefpos, 0, TRUE, FALSE);
411     CPDF_Dictionary* pDict = LoadTrailerV4();
412     if (pDict == NULL) {
413       return FALSE;
414     }
415     xrefpos = GetDirectInteger(pDict, FX_BSTRC("Prev"));
416     XRefStreamList.InsertAt(0, pDict->GetInteger(FX_BSTRC("XRefStm")));
417     m_Trailers.Add(pDict);
418   }
419   for (int32_t i = 1; i < CrossRefList.GetSize(); i++)
420     if (!LoadCrossRefV4(CrossRefList[i], XRefStreamList[i], FALSE, i == 0)) {
421       return FALSE;
422     }
423   return TRUE;
424 }
425 FX_BOOL CPDF_Parser::LoadLinearizedCrossRefV4(FX_FILESIZE pos,
426                                               FX_DWORD dwObjCount) {
427   FX_FILESIZE dwStartPos = pos - m_Syntax.m_HeaderOffset;
428   m_Syntax.RestorePos(dwStartPos);
429   void* pResult =
430       FXSYS_bsearch(&pos, m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
431                     sizeof(FX_FILESIZE), CompareFileSize);
432   if (pResult == NULL) {
433     m_SortedOffset.Add(pos);
434   }
435   FX_DWORD start_objnum = 0;
436   FX_DWORD count = dwObjCount;
437   FX_FILESIZE SavedPos = m_Syntax.SavePos();
438   const int32_t recordsize = 20;
439   std::vector<char> buf(1024 * recordsize + 1);
440   char* pBuf = pdfium::vector_as_array(&buf);
441   pBuf[1024 * recordsize] = '\0';
442   int32_t nBlocks = count / 1024 + 1;
443   for (int32_t block = 0; block < nBlocks; block++) {
444     int32_t block_size = block == nBlocks - 1 ? count % 1024 : 1024;
445     FX_DWORD dwReadSize = block_size * recordsize;
446     if ((FX_FILESIZE)(dwStartPos + dwReadSize) > m_Syntax.m_FileLen) {
447       return FALSE;
448     }
449     if (!m_Syntax.ReadBlock(reinterpret_cast<uint8_t*>(pBuf), dwReadSize)) {
450       return FALSE;
451     }
452     for (int32_t i = 0; i < block_size; i++) {
453       FX_DWORD objnum = start_objnum + block * 1024 + i;
454       char* pEntry = pBuf + i * recordsize;
455       if (pEntry[17] == 'f') {
456         m_CrossRef.SetAtGrow(objnum, 0);
457         m_V5Type.SetAtGrow(objnum, 0);
458       } else {
459         int32_t offset = FXSYS_atoi(pEntry);
460         if (offset == 0) {
461           for (int32_t c = 0; c < 10; c++) {
462             if (pEntry[c] < '0' || pEntry[c] > '9') {
463               return FALSE;
464             }
465           }
466         }
467         m_CrossRef.SetAtGrow(objnum, offset);
468         int32_t version = FXSYS_atoi(pEntry + 11);
469         if (version >= 1) {
470           m_bVersionUpdated = TRUE;
471         }
472         m_ObjVersion.SetAtGrow(objnum, version);
473         if (m_CrossRef[objnum] < m_Syntax.m_FileLen) {
474           void* pResult = FXSYS_bsearch(
475               &m_CrossRef[objnum], m_SortedOffset.GetData(),
476               m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), CompareFileSize);
477           if (pResult == NULL) {
478             m_SortedOffset.Add(m_CrossRef[objnum]);
479           }
480         }
481         m_V5Type.SetAtGrow(objnum, 1);
482       }
483     }
484   }
485   m_Syntax.RestorePos(SavedPos + count * recordsize);
486   return TRUE;
487 }
488
489 bool CPDF_Parser::FindPosInOffsets(FX_FILESIZE pos) const {
490   return FXSYS_bsearch(&pos, m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
491                        sizeof(FX_FILESIZE), CompareFileSize);
492 }
493
494 bool CPDF_Parser::LoadCrossRefV4(FX_FILESIZE pos,
495                                  FX_FILESIZE streampos,
496                                  FX_BOOL bSkip,
497                                  FX_BOOL bFirst) {
498   m_Syntax.RestorePos(pos);
499   if (m_Syntax.GetKeyword() != FX_BSTRC("xref"))
500     return false;
501
502   if (!FindPosInOffsets(pos))
503     m_SortedOffset.Add(pos);
504
505   if (streampos && !FindPosInOffsets(streampos))
506       m_SortedOffset.Add(streampos);
507
508   while (1) {
509     FX_FILESIZE SavedPos = m_Syntax.SavePos();
510     FX_BOOL bIsNumber;
511     CFX_ByteString word = m_Syntax.GetNextWord(bIsNumber);
512     if (word.IsEmpty())
513       return false;
514
515     if (!bIsNumber) {
516       m_Syntax.RestorePos(SavedPos);
517       break;
518     }
519     FX_DWORD start_objnum = FXSYS_atoi(word);
520     if (start_objnum >= (1 << 20))
521       return false;
522
523     FX_DWORD count = m_Syntax.GetDirectNum();
524     m_Syntax.ToNextWord();
525     SavedPos = m_Syntax.SavePos();
526     FX_BOOL bFirstItem = FALSE;
527     const int32_t recordsize = 20;
528     if (bFirst)
529       bFirstItem = TRUE;
530     m_dwXrefStartObjNum = start_objnum;
531     if (!bSkip) {
532       std::vector<char> buf(1024 * recordsize + 1);
533       char* pBuf = pdfium::vector_as_array(&buf);
534       pBuf[1024 * recordsize] = '\0';
535       int32_t nBlocks = count / 1024 + 1;
536       FX_BOOL bFirstBlock = TRUE;
537       for (int32_t block = 0; block < nBlocks; block++) {
538         int32_t block_size = block == nBlocks - 1 ? count % 1024 : 1024;
539         m_Syntax.ReadBlock(reinterpret_cast<uint8_t*>(pBuf),
540                            block_size * recordsize);
541         for (int32_t i = 0; i < block_size; i++) {
542           FX_DWORD objnum = start_objnum + block * 1024 + i;
543           char* pEntry = pBuf + i * recordsize;
544           if (pEntry[17] == 'f') {
545             if (bFirstItem) {
546               objnum = 0;
547               bFirstItem = FALSE;
548             }
549             if (bFirstBlock) {
550               FX_FILESIZE offset = (FX_FILESIZE)FXSYS_atoi64(pEntry);
551               int32_t version = FXSYS_atoi(pEntry + 11);
552               if (offset == 0 && version == 65535 && start_objnum != 0) {
553                 start_objnum--;
554                 objnum = 0;
555               }
556             }
557             m_CrossRef.SetAtGrow(objnum, 0);
558             m_V5Type.SetAtGrow(objnum, 0);
559           } else {
560             FX_FILESIZE offset = (FX_FILESIZE)FXSYS_atoi64(pEntry);
561             if (offset == 0) {
562               for (int32_t c = 0; c < 10; c++) {
563                 if (pEntry[c] < '0' || pEntry[c] > '9') {
564                   return false;
565                 }
566               }
567             }
568             m_CrossRef.SetAtGrow(objnum, offset);
569             int32_t version = FXSYS_atoi(pEntry + 11);
570             if (version >= 1) {
571               m_bVersionUpdated = TRUE;
572             }
573             m_ObjVersion.SetAtGrow(objnum, version);
574             if (m_CrossRef[objnum] < m_Syntax.m_FileLen &&
575                 !FindPosInOffsets(m_CrossRef[objnum])) {
576               m_SortedOffset.Add(m_CrossRef[objnum]);
577             }
578             m_V5Type.SetAtGrow(objnum, 1);
579           }
580           if (bFirstBlock) {
581             bFirstBlock = FALSE;
582           }
583         }
584       }
585     }
586     m_Syntax.RestorePos(SavedPos + count * recordsize);
587   }
588   return !streampos || LoadCrossRefV5(streampos, streampos, FALSE);
589 }
590
591 FX_BOOL CPDF_Parser::LoadAllCrossRefV5(FX_FILESIZE xrefpos) {
592   if (!LoadCrossRefV5(xrefpos, xrefpos, TRUE)) {
593     return FALSE;
594   }
595   while (xrefpos)
596     if (!LoadCrossRefV5(xrefpos, xrefpos, FALSE)) {
597       return FALSE;
598     }
599   m_ObjectStreamMap.InitHashTable(101, FALSE);
600   m_bXRefStream = TRUE;
601   return TRUE;
602 }
603 FX_BOOL CPDF_Parser::RebuildCrossRef() {
604   m_CrossRef.RemoveAll();
605   m_V5Type.RemoveAll();
606   m_SortedOffset.RemoveAll();
607   m_ObjVersion.RemoveAll();
608   if (m_pTrailer) {
609     m_pTrailer->Release();
610     m_pTrailer = NULL;
611   }
612   int32_t status = 0;
613   int32_t inside_index = 0;
614   FX_DWORD objnum = 0, gennum = 0;
615   int32_t depth = 0;
616   uint8_t* buffer = FX_Alloc(uint8_t, 4096);
617   FX_FILESIZE pos = m_Syntax.m_HeaderOffset;
618   FX_FILESIZE start_pos = 0, start_pos1 = 0;
619   FX_FILESIZE last_obj = -1, last_xref = -1, last_trailer = -1;
620   while (pos < m_Syntax.m_FileLen) {
621     FX_BOOL bOverFlow = FALSE;
622     FX_DWORD size = (FX_DWORD)(m_Syntax.m_FileLen - pos);
623     if (size > 4096) {
624       size = 4096;
625     }
626     if (!m_Syntax.m_pFileAccess->ReadBlock(buffer, pos, size)) {
627       break;
628     }
629     for (FX_DWORD i = 0; i < size; i++) {
630       uint8_t byte = buffer[i];
631       switch (status) {
632         case 0:
633           if (PDFCharIsWhitespace(byte)) {
634             status = 1;
635           }
636           if (byte <= '9' && byte >= '0') {
637             --i;
638             status = 1;
639           }
640           if (byte == '%') {
641             inside_index = 0;
642             status = 9;
643           }
644           if (byte == '(') {
645             status = 10;
646             depth = 1;
647           }
648           if (byte == '<') {
649             inside_index = 1;
650             status = 11;
651           }
652           if (byte == '\\') {
653             status = 13;
654           }
655           if (byte == 't') {
656             status = 7;
657             inside_index = 1;
658           }
659           break;
660         case 1:
661           if (PDFCharIsWhitespace(byte)) {
662             break;
663           } else if (byte <= '9' && byte >= '0') {
664             start_pos = pos + i;
665             status = 2;
666             objnum = byte - '0';
667           } else if (byte == 't') {
668             status = 7;
669             inside_index = 1;
670           } else if (byte == 'x') {
671             status = 8;
672             inside_index = 1;
673           } else {
674             --i;
675             status = 0;
676           }
677           break;
678         case 2:
679           if (byte <= '9' && byte >= '0') {
680             objnum = objnum * 10 + byte - '0';
681             break;
682           } else if (PDFCharIsWhitespace(byte)) {
683             status = 3;
684           } else {
685             --i;
686             status = 14;
687             inside_index = 0;
688           }
689           break;
690         case 3:
691           if (byte <= '9' && byte >= '0') {
692             start_pos1 = pos + i;
693             status = 4;
694             gennum = byte - '0';
695           } else if (PDFCharIsWhitespace(byte)) {
696             break;
697           } else if (byte == 't') {
698             status = 7;
699             inside_index = 1;
700           } else {
701             --i;
702             status = 0;
703           }
704           break;
705         case 4:
706           if (byte <= '9' && byte >= '0') {
707             gennum = gennum * 10 + byte - '0';
708             break;
709           } else if (PDFCharIsWhitespace(byte)) {
710             status = 5;
711           } else {
712             --i;
713             status = 0;
714           }
715           break;
716         case 5:
717           if (byte == 'o') {
718             status = 6;
719             inside_index = 1;
720           } else if (PDFCharIsWhitespace(byte)) {
721             break;
722           } else if (byte <= '9' && byte >= '0') {
723             objnum = gennum;
724             gennum = byte - '0';
725             start_pos = start_pos1;
726             start_pos1 = pos + i;
727             status = 4;
728           } else if (byte == 't') {
729             status = 7;
730             inside_index = 1;
731           } else {
732             --i;
733             status = 0;
734           }
735           break;
736         case 6:
737           switch (inside_index) {
738             case 1:
739               if (byte != 'b') {
740                 --i;
741                 status = 0;
742               } else {
743                 inside_index++;
744               }
745               break;
746             case 2:
747               if (byte != 'j') {
748                 --i;
749                 status = 0;
750               } else {
751                 inside_index++;
752               }
753               break;
754             case 3:
755               if (PDFCharIsWhitespace(byte) || PDFCharIsDelimiter(byte)) {
756                 if (objnum > 0x1000000) {
757                   status = 0;
758                   break;
759                 }
760                 FX_FILESIZE obj_pos = start_pos - m_Syntax.m_HeaderOffset;
761                 last_obj = start_pos;
762                 void* pResult =
763                     FXSYS_bsearch(&obj_pos, m_SortedOffset.GetData(),
764                                   m_SortedOffset.GetSize(), sizeof(FX_FILESIZE),
765                                   CompareFileSize);
766                 if (pResult == NULL) {
767                   m_SortedOffset.Add(obj_pos);
768                 }
769                 FX_FILESIZE obj_end = 0;
770                 CPDF_Object* pObject = ParseIndirectObjectAtByStrict(
771                     m_pDocument, obj_pos, objnum, NULL, &obj_end);
772                 if (CPDF_Stream* pStream = ToStream(pObject)) {
773                   if (CPDF_Dictionary* pDict = pStream->GetDict()) {
774                     if ((pDict->KeyExist(FX_BSTRC("Type"))) &&
775                         (pDict->GetString(FX_BSTRC("Type")) ==
776                              FX_BSTRC("XRef") &&
777                          pDict->KeyExist(FX_BSTRC("Size")))) {
778                       CPDF_Object* pRoot = pDict->GetElement(FX_BSTRC("Root"));
779                       if (pRoot && pRoot->GetDict() &&
780                           pRoot->GetDict()->GetElement(FX_BSTRC("Pages"))) {
781                         if (m_pTrailer)
782                           m_pTrailer->Release();
783                         m_pTrailer = ToDictionary(pDict->Clone());
784                         }
785                       }
786                   }
787                 }
788                 FX_FILESIZE offset = 0;
789                 m_Syntax.RestorePos(obj_pos);
790                 offset = m_Syntax.FindTag(FX_BSTRC("obj"), 0);
791                 if (offset == -1) {
792                   offset = 0;
793                 } else {
794                   offset += 3;
795                 }
796                 FX_FILESIZE nLen = obj_end - obj_pos - offset;
797                 if ((FX_DWORD)nLen > size - i) {
798                   pos = obj_end + m_Syntax.m_HeaderOffset;
799                   bOverFlow = TRUE;
800                 } else {
801                   i += (FX_DWORD)nLen;
802                 }
803                 if (m_CrossRef.GetSize() > (int32_t)objnum &&
804                     m_CrossRef[objnum]) {
805                   if (pObject) {
806                     FX_DWORD oldgen = m_ObjVersion.GetAt(objnum);
807                     m_CrossRef[objnum] = obj_pos;
808                     m_ObjVersion.SetAt(objnum, (int16_t)gennum);
809                     if (oldgen != gennum) {
810                       m_bVersionUpdated = TRUE;
811                     }
812                   }
813                 } else {
814                   m_CrossRef.SetAtGrow(objnum, obj_pos);
815                   m_V5Type.SetAtGrow(objnum, 1);
816                   m_ObjVersion.SetAtGrow(objnum, (int16_t)gennum);
817                 }
818                 if (pObject) {
819                   pObject->Release();
820                 }
821               }
822               --i;
823               status = 0;
824               break;
825           }
826           break;
827         case 7:
828           if (inside_index == 7) {
829             if (PDFCharIsWhitespace(byte) || PDFCharIsDelimiter(byte)) {
830               last_trailer = pos + i - 7;
831               m_Syntax.RestorePos(pos + i - m_Syntax.m_HeaderOffset);
832               CPDF_Object* pObj = m_Syntax.GetObject(m_pDocument, 0, 0, 0);
833               if (pObj) {
834                 if (!pObj->IsDictionary() && !pObj->AsStream()) {
835                   pObj->Release();
836                 } else {
837                   CPDF_Stream* pStream = pObj->AsStream();
838                   if (CPDF_Dictionary* pTrailer =
839                           pStream ? pStream->GetDict() : pObj->AsDictionary()) {
840                     if (m_pTrailer) {
841                       CPDF_Object* pRoot =
842                           pTrailer->GetElement(FX_BSTRC("Root"));
843                       CPDF_Reference* pRef = ToReference(pRoot);
844                       if (!pRoot ||
845                           (pRef &&
846                            (FX_DWORD)m_CrossRef.GetSize() >
847                                pRef->GetRefObjNum() &&
848                            m_CrossRef.GetAt(pRef->GetRefObjNum()) != 0)) {
849                         FX_POSITION pos = pTrailer->GetStartPos();
850                         while (pos) {
851                           CFX_ByteString key;
852                           CPDF_Object* pElement =
853                               pTrailer->GetNextElement(pos, key);
854                           FX_DWORD dwObjNum = pElement->GetObjNum();
855                           if (dwObjNum) {
856                             m_pTrailer->SetAtReference(key, m_pDocument,
857                                                        dwObjNum);
858                           } else {
859                             m_pTrailer->SetAt(key, pElement->Clone());
860                           }
861                         }
862                         pObj->Release();
863                       } else {
864                         pObj->Release();
865                       }
866                     } else {
867                       if (pObj->IsStream()) {
868                         m_pTrailer = ToDictionary(pTrailer->Clone());
869                         pObj->Release();
870                       } else {
871                         m_pTrailer = pTrailer;
872                       }
873                       FX_FILESIZE dwSavePos = m_Syntax.SavePos();
874                       CFX_ByteString strWord = m_Syntax.GetKeyword();
875                       if (!strWord.Compare(FX_BSTRC("startxref"))) {
876                         FX_BOOL bNumber = FALSE;
877                         CFX_ByteString bsOffset = m_Syntax.GetNextWord(bNumber);
878                         if (bNumber) {
879                           m_LastXRefOffset = FXSYS_atoi(bsOffset);
880                         }
881                       }
882                       m_Syntax.RestorePos(dwSavePos);
883                     }
884                   } else {
885                     pObj->Release();
886                   }
887                 }
888               }
889             }
890             --i;
891             status = 0;
892           } else if (byte == "trailer"[inside_index]) {
893             inside_index++;
894           } else {
895             --i;
896             status = 0;
897           }
898           break;
899         case 8:
900           if (inside_index == 4) {
901             last_xref = pos + i - 4;
902             status = 1;
903           } else if (byte == "xref"[inside_index]) {
904             inside_index++;
905           } else {
906             --i;
907             status = 0;
908           }
909           break;
910         case 9:
911           if (byte == '\r' || byte == '\n') {
912             status = 0;
913           }
914           break;
915         case 10:
916           if (byte == ')') {
917             if (depth > 0) {
918               depth--;
919             }
920           } else if (byte == '(') {
921             depth++;
922           }
923           if (!depth) {
924             status = 0;
925           }
926           break;
927         case 11:
928           if (byte == '<' && inside_index == 1) {
929             status = 12;
930           } else if (byte == '>') {
931             status = 0;
932           }
933           inside_index = 0;
934           break;
935         case 12:
936           --i;
937           status = 0;
938           break;
939         case 13:
940           if (PDFCharIsDelimiter(byte) || PDFCharIsWhitespace(byte)) {
941             --i;
942             status = 0;
943           }
944           break;
945         case 14:
946           if (PDFCharIsWhitespace(byte)) {
947             status = 0;
948           } else if (byte == '%' || byte == '(' || byte == '<' ||
949                      byte == '\\') {
950             status = 0;
951             --i;
952           } else if (inside_index == 6) {
953             status = 0;
954             --i;
955           } else if (byte == "endobj"[inside_index]) {
956             inside_index++;
957           }
958           break;
959       }
960       if (bOverFlow) {
961         size = 0;
962         break;
963       }
964     }
965     pos += size;
966   }
967   if (last_xref != -1 && last_xref > last_obj) {
968     last_trailer = last_xref;
969   } else if (last_trailer == -1 || last_xref < last_obj) {
970     last_trailer = m_Syntax.m_FileLen;
971   }
972   FX_FILESIZE offset = last_trailer - m_Syntax.m_HeaderOffset;
973   void* pResult =
974       FXSYS_bsearch(&offset, m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
975                     sizeof(FX_FILESIZE), CompareFileSize);
976   if (pResult == NULL) {
977     m_SortedOffset.Add(offset);
978   }
979   FX_Free(buffer);
980   return TRUE;
981 }
982
983 FX_BOOL CPDF_Parser::LoadCrossRefV5(FX_FILESIZE pos,
984                                     FX_FILESIZE& prev,
985                                     FX_BOOL bMainXRef) {
986   CPDF_Object* pObject = ParseIndirectObjectAt(m_pDocument, pos, 0, nullptr);
987   if (!pObject)
988     return FALSE;
989
990   if (m_pDocument) {
991     CPDF_Dictionary* pDict = m_pDocument->GetRoot();
992     if (!pDict || pDict->GetObjNum() != pObject->m_ObjNum) {
993       m_pDocument->InsertIndirectObject(pObject->m_ObjNum, pObject);
994     } else {
995       if (pObject->IsStream())
996         pObject->Release();
997       return FALSE;
998     }
999   }
1000
1001   CPDF_Stream* pStream = pObject->AsStream();
1002   if (!pStream)
1003     return FALSE;
1004
1005   prev = pStream->GetDict()->GetInteger(FX_BSTRC("Prev"));
1006   int32_t size = pStream->GetDict()->GetInteger(FX_BSTRC("Size"));
1007   if (size < 0) {
1008     pStream->Release();
1009     return FALSE;
1010   }
1011   if (bMainXRef) {
1012     m_pTrailer = ToDictionary(pStream->GetDict()->Clone());
1013     m_CrossRef.SetSize(size);
1014     if (m_V5Type.SetSize(size)) {
1015       FXSYS_memset(m_V5Type.GetData(), 0, size);
1016     }
1017   } else {
1018     m_Trailers.Add(ToDictionary(pStream->GetDict()->Clone()));
1019   }
1020   std::vector<std::pair<int32_t, int32_t> > arrIndex;
1021   CPDF_Array* pArray = pStream->GetDict()->GetArray(FX_BSTRC("Index"));
1022   if (pArray) {
1023     FX_DWORD nPairSize = pArray->GetCount() / 2;
1024     for (FX_DWORD i = 0; i < nPairSize; i++) {
1025       CPDF_Object* pStartNumObj = pArray->GetElement(i * 2);
1026       CPDF_Object* pCountObj = pArray->GetElement(i * 2 + 1);
1027       if (ToNumber(pStartNumObj) && ToNumber(pCountObj)) {
1028         int nStartNum = pStartNumObj->GetInteger();
1029         int nCount = pCountObj->GetInteger();
1030         if (nStartNum >= 0 && nCount > 0) {
1031           arrIndex.push_back(std::make_pair(nStartNum, nCount));
1032         }
1033       }
1034     }
1035   }
1036   if (arrIndex.size() == 0) {
1037     arrIndex.push_back(std::make_pair(0, size));
1038   }
1039   pArray = pStream->GetDict()->GetArray(FX_BSTRC("W"));
1040   if (pArray == NULL) {
1041     pStream->Release();
1042     return FALSE;
1043   }
1044   CFX_DWordArray WidthArray;
1045   FX_SAFE_DWORD dwAccWidth = 0;
1046   for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
1047     WidthArray.Add(pArray->GetInteger(i));
1048     dwAccWidth += WidthArray[i];
1049   }
1050   if (!dwAccWidth.IsValid() || WidthArray.GetSize() < 3) {
1051     pStream->Release();
1052     return FALSE;
1053   }
1054   FX_DWORD totalWidth = dwAccWidth.ValueOrDie();
1055   CPDF_StreamAcc acc;
1056   acc.LoadAllData(pStream);
1057   const uint8_t* pData = acc.GetData();
1058   FX_DWORD dwTotalSize = acc.GetSize();
1059   FX_DWORD segindex = 0;
1060   for (FX_DWORD i = 0; i < arrIndex.size(); i++) {
1061     int32_t startnum = arrIndex[i].first;
1062     if (startnum < 0) {
1063       continue;
1064     }
1065     m_dwXrefStartObjNum =
1066         pdfium::base::checked_cast<FX_DWORD, int32_t>(startnum);
1067     FX_DWORD count =
1068         pdfium::base::checked_cast<FX_DWORD, int32_t>(arrIndex[i].second);
1069     FX_SAFE_DWORD dwCaculatedSize = segindex;
1070     dwCaculatedSize += count;
1071     dwCaculatedSize *= totalWidth;
1072     if (!dwCaculatedSize.IsValid() ||
1073         dwCaculatedSize.ValueOrDie() > dwTotalSize) {
1074       continue;
1075     }
1076     const uint8_t* segstart = pData + segindex * totalWidth;
1077     FX_SAFE_DWORD dwMaxObjNum = startnum;
1078     dwMaxObjNum += count;
1079     FX_DWORD dwV5Size =
1080         pdfium::base::checked_cast<FX_DWORD, int32_t>(m_V5Type.GetSize());
1081     if (!dwMaxObjNum.IsValid() || dwMaxObjNum.ValueOrDie() > dwV5Size) {
1082       continue;
1083     }
1084     for (FX_DWORD j = 0; j < count; j++) {
1085       int32_t type = 1;
1086       const uint8_t* entrystart = segstart + j * totalWidth;
1087       if (WidthArray[0]) {
1088         type = GetVarInt(entrystart, WidthArray[0]);
1089       }
1090       if (m_V5Type[startnum + j] == 255) {
1091         FX_FILESIZE offset =
1092             GetVarInt(entrystart + WidthArray[0], WidthArray[1]);
1093         m_CrossRef[startnum + j] = offset;
1094         void* pResult = FXSYS_bsearch(&offset, m_SortedOffset.GetData(),
1095                                       m_SortedOffset.GetSize(),
1096                                       sizeof(FX_FILESIZE), CompareFileSize);
1097         if (pResult == NULL) {
1098           m_SortedOffset.Add(offset);
1099         }
1100         continue;
1101       }
1102       if (m_V5Type[startnum + j]) {
1103         continue;
1104       }
1105       m_V5Type[startnum + j] = type;
1106       if (type == 0) {
1107         m_CrossRef[startnum + j] = 0;
1108       } else {
1109         FX_FILESIZE offset =
1110             GetVarInt(entrystart + WidthArray[0], WidthArray[1]);
1111         m_CrossRef[startnum + j] = offset;
1112         if (type == 1) {
1113           void* pResult = FXSYS_bsearch(&offset, m_SortedOffset.GetData(),
1114                                         m_SortedOffset.GetSize(),
1115                                         sizeof(FX_FILESIZE), CompareFileSize);
1116           if (pResult == NULL) {
1117             m_SortedOffset.Add(offset);
1118           }
1119         } else {
1120           if (offset < 0 || offset >= m_V5Type.GetSize()) {
1121             pStream->Release();
1122             return FALSE;
1123           }
1124           m_V5Type[offset] = 255;
1125         }
1126       }
1127     }
1128     segindex += count;
1129   }
1130   pStream->Release();
1131   return TRUE;
1132 }
1133 CPDF_Array* CPDF_Parser::GetIDArray() {
1134   CPDF_Object* pID = m_pTrailer ? m_pTrailer->GetElement(FX_BSTRC("ID")) : NULL;
1135   if (!pID)
1136     return nullptr;
1137
1138   if (CPDF_Reference* pRef = pID->AsReference()) {
1139     pID = ParseIndirectObject(nullptr, pRef->GetRefObjNum());
1140     m_pTrailer->SetAt(FX_BSTRC("ID"), pID);
1141   }
1142   return ToArray(pID);
1143 }
1144 FX_DWORD CPDF_Parser::GetRootObjNum() {
1145   CPDF_Reference* pRef = ToReference(
1146       m_pTrailer ? m_pTrailer->GetElement(FX_BSTRC("Root")) : nullptr);
1147   return pRef ? pRef->GetRefObjNum() : 0;
1148 }
1149 FX_DWORD CPDF_Parser::GetInfoObjNum() {
1150   CPDF_Reference* pRef = ToReference(
1151       m_pTrailer ? m_pTrailer->GetElement(FX_BSTRC("Info")) : nullptr);
1152   return pRef ? pRef->GetRefObjNum() : 0;
1153 }
1154 FX_BOOL CPDF_Parser::IsFormStream(FX_DWORD objnum, FX_BOOL& bForm) {
1155   bForm = FALSE;
1156   if (objnum >= (FX_DWORD)m_CrossRef.GetSize()) {
1157     return TRUE;
1158   }
1159   if (m_V5Type[objnum] == 0) {
1160     return TRUE;
1161   }
1162   if (m_V5Type[objnum] == 2) {
1163     return TRUE;
1164   }
1165   FX_FILESIZE pos = m_CrossRef[objnum];
1166   void* pResult =
1167       FXSYS_bsearch(&pos, m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
1168                     sizeof(FX_FILESIZE), CompareFileSize);
1169   if (pResult == NULL) {
1170     return TRUE;
1171   }
1172   if ((FX_FILESIZE*)pResult - (FX_FILESIZE*)m_SortedOffset.GetData() ==
1173       m_SortedOffset.GetSize() - 1) {
1174     return FALSE;
1175   }
1176   FX_FILESIZE size = ((FX_FILESIZE*)pResult)[1] - pos;
1177   FX_FILESIZE SavedPos = m_Syntax.SavePos();
1178   m_Syntax.RestorePos(pos);
1179   bForm = m_Syntax.SearchMultiWord(FX_BSTRC("/Form\0stream"), TRUE, size) == 0;
1180   m_Syntax.RestorePos(SavedPos);
1181   return TRUE;
1182 }
1183
1184 CPDF_Object* CPDF_Parser::ParseIndirectObject(CPDF_IndirectObjects* pObjList,
1185                                               FX_DWORD objnum,
1186                                               PARSE_CONTEXT* pContext) {
1187   if (objnum >= (FX_DWORD)m_CrossRef.GetSize())
1188     return nullptr;
1189
1190   if (m_V5Type[objnum] == 1 || m_V5Type[objnum] == 255) {
1191     FX_FILESIZE pos = m_CrossRef[objnum];
1192     if (pos <= 0)
1193       return nullptr;
1194     return ParseIndirectObjectAt(pObjList, pos, objnum, pContext);
1195   }
1196   if (m_V5Type[objnum] != 2)
1197     return nullptr;
1198
1199   CPDF_StreamAcc* pObjStream = GetObjectStream((FX_DWORD)m_CrossRef[objnum]);
1200   if (!pObjStream)
1201     return nullptr;
1202
1203   ScopedFileStream file(FX_CreateMemoryStream(
1204       (uint8_t*)pObjStream->GetData(), (size_t)pObjStream->GetSize(), FALSE));
1205   CPDF_SyntaxParser syntax;
1206   syntax.InitParser(file.get(), 0);
1207   int32_t offset = GetStreamFirst(pObjStream);
1208   for (int32_t i = GetStreamNCount(pObjStream); i > 0; --i) {
1209     FX_DWORD thisnum = syntax.GetDirectNum();
1210     FX_DWORD thisoff = syntax.GetDirectNum();
1211     if (thisnum == objnum) {
1212       syntax.RestorePos(offset + thisoff);
1213       return syntax.GetObject(pObjList, 0, 0, pContext);
1214     }
1215   }
1216   return nullptr;
1217 }
1218
1219 CPDF_StreamAcc* CPDF_Parser::GetObjectStream(FX_DWORD objnum) {
1220   CPDF_StreamAcc* pStreamAcc = nullptr;
1221   if (m_ObjectStreamMap.Lookup((void*)(uintptr_t)objnum, (void*&)pStreamAcc))
1222     return pStreamAcc;
1223
1224   const CPDF_Stream* pStream =
1225       ToStream(m_pDocument ? m_pDocument->GetIndirectObject(objnum) : nullptr);
1226   if (!pStream)
1227     return nullptr;
1228
1229   pStreamAcc = new CPDF_StreamAcc;
1230   pStreamAcc->LoadAllData(pStream);
1231   m_ObjectStreamMap.SetAt((void*)(uintptr_t)objnum, pStreamAcc);
1232   return pStreamAcc;
1233 }
1234 FX_FILESIZE CPDF_Parser::GetObjectSize(FX_DWORD objnum) {
1235   if (objnum >= (FX_DWORD)m_CrossRef.GetSize()) {
1236     return 0;
1237   }
1238   if (m_V5Type[objnum] == 2) {
1239     objnum = (FX_DWORD)m_CrossRef[objnum];
1240   }
1241   if (m_V5Type[objnum] == 1 || m_V5Type[objnum] == 255) {
1242     FX_FILESIZE offset = m_CrossRef[objnum];
1243     if (offset == 0) {
1244       return 0;
1245     }
1246     void* pResult = FXSYS_bsearch(&offset, m_SortedOffset.GetData(),
1247                                   m_SortedOffset.GetSize(), sizeof(FX_FILESIZE),
1248                                   CompareFileSize);
1249     if (pResult == NULL) {
1250       return 0;
1251     }
1252     if ((FX_FILESIZE*)pResult - (FX_FILESIZE*)m_SortedOffset.GetData() ==
1253         m_SortedOffset.GetSize() - 1) {
1254       return 0;
1255     }
1256     return ((FX_FILESIZE*)pResult)[1] - offset;
1257   }
1258   return 0;
1259 }
1260 void CPDF_Parser::GetIndirectBinary(FX_DWORD objnum,
1261                                     uint8_t*& pBuffer,
1262                                     FX_DWORD& size) {
1263   pBuffer = NULL;
1264   size = 0;
1265   if (objnum >= (FX_DWORD)m_CrossRef.GetSize()) {
1266     return;
1267   }
1268   if (m_V5Type[objnum] == 2) {
1269     CPDF_StreamAcc* pObjStream = GetObjectStream((FX_DWORD)m_CrossRef[objnum]);
1270     if (!pObjStream)
1271       return;
1272
1273     int32_t offset = GetStreamFirst(pObjStream);
1274     const uint8_t* pData = pObjStream->GetData();
1275     FX_DWORD totalsize = pObjStream->GetSize();
1276     ScopedFileStream file(
1277         FX_CreateMemoryStream((uint8_t*)pData, (size_t)totalsize, FALSE));
1278     CPDF_SyntaxParser syntax;
1279     syntax.InitParser(file.get(), 0);
1280     for (int i = GetStreamNCount(pObjStream); i > 0; --i) {
1281       FX_DWORD thisnum = syntax.GetDirectNum();
1282       FX_DWORD thisoff = syntax.GetDirectNum();
1283       if (thisnum != objnum)
1284         continue;
1285
1286       if (i == 1) {
1287         size = totalsize - (thisoff + offset);
1288       } else {
1289         syntax.GetDirectNum();  // Skip nextnum.
1290         FX_DWORD nextoff = syntax.GetDirectNum();
1291         size = nextoff - thisoff;
1292       }
1293       pBuffer = FX_Alloc(uint8_t, size);
1294       FXSYS_memcpy(pBuffer, pData + thisoff + offset, size);
1295       return;
1296     }
1297     return;
1298   }
1299
1300   if (m_V5Type[objnum] != 1)
1301     return;
1302
1303   FX_FILESIZE pos = m_CrossRef[objnum];
1304   if (pos == 0) {
1305     return;
1306   }
1307   FX_FILESIZE SavedPos = m_Syntax.SavePos();
1308   m_Syntax.RestorePos(pos);
1309   FX_BOOL bIsNumber;
1310   CFX_ByteString word = m_Syntax.GetNextWord(bIsNumber);
1311   if (!bIsNumber) {
1312     m_Syntax.RestorePos(SavedPos);
1313     return;
1314   }
1315   FX_DWORD parser_objnum = FXSYS_atoi(word);
1316   if (parser_objnum && parser_objnum != objnum) {
1317     m_Syntax.RestorePos(SavedPos);
1318     return;
1319   }
1320   word = m_Syntax.GetNextWord(bIsNumber);
1321   if (!bIsNumber) {
1322     m_Syntax.RestorePos(SavedPos);
1323     return;
1324   }
1325   if (m_Syntax.GetKeyword() != FX_BSTRC("obj")) {
1326     m_Syntax.RestorePos(SavedPos);
1327     return;
1328   }
1329   void* pResult =
1330       FXSYS_bsearch(&pos, m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
1331                     sizeof(FX_FILESIZE), CompareFileSize);
1332   if (pResult == NULL) {
1333     m_Syntax.RestorePos(SavedPos);
1334     return;
1335   }
1336   FX_FILESIZE nextoff = ((FX_FILESIZE*)pResult)[1];
1337   FX_BOOL bNextOffValid = FALSE;
1338   if (nextoff != pos) {
1339     m_Syntax.RestorePos(nextoff);
1340     word = m_Syntax.GetNextWord(bIsNumber);
1341     if (word == FX_BSTRC("xref")) {
1342       bNextOffValid = TRUE;
1343     } else if (bIsNumber) {
1344       word = m_Syntax.GetNextWord(bIsNumber);
1345       if (bIsNumber && m_Syntax.GetKeyword() == FX_BSTRC("obj")) {
1346         bNextOffValid = TRUE;
1347       }
1348     }
1349   }
1350   if (!bNextOffValid) {
1351     m_Syntax.RestorePos(pos);
1352     while (1) {
1353       if (m_Syntax.GetKeyword() == FX_BSTRC("endobj")) {
1354         break;
1355       }
1356       if (m_Syntax.SavePos() == m_Syntax.m_FileLen) {
1357         break;
1358       }
1359     }
1360     nextoff = m_Syntax.SavePos();
1361   }
1362   size = (FX_DWORD)(nextoff - pos);
1363   pBuffer = FX_Alloc(uint8_t, size);
1364   m_Syntax.RestorePos(pos);
1365   m_Syntax.ReadBlock(pBuffer, size);
1366   m_Syntax.RestorePos(SavedPos);
1367 }
1368
1369 CPDF_Object* CPDF_Parser::ParseIndirectObjectAt(CPDF_IndirectObjects* pObjList,
1370                                                 FX_FILESIZE pos,
1371                                                 FX_DWORD objnum,
1372                                                 PARSE_CONTEXT* pContext) {
1373   FX_FILESIZE SavedPos = m_Syntax.SavePos();
1374   m_Syntax.RestorePos(pos);
1375   FX_BOOL bIsNumber;
1376   CFX_ByteString word = m_Syntax.GetNextWord(bIsNumber);
1377   if (!bIsNumber) {
1378     m_Syntax.RestorePos(SavedPos);
1379     return NULL;
1380   }
1381   FX_FILESIZE objOffset = m_Syntax.SavePos();
1382   objOffset -= word.GetLength();
1383   FX_DWORD parser_objnum = FXSYS_atoi(word);
1384   if (objnum && parser_objnum != objnum) {
1385     m_Syntax.RestorePos(SavedPos);
1386     return NULL;
1387   }
1388   word = m_Syntax.GetNextWord(bIsNumber);
1389   if (!bIsNumber) {
1390     m_Syntax.RestorePos(SavedPos);
1391     return NULL;
1392   }
1393   FX_DWORD parser_gennum = FXSYS_atoi(word);
1394   if (m_Syntax.GetKeyword() != FX_BSTRC("obj")) {
1395     m_Syntax.RestorePos(SavedPos);
1396     return NULL;
1397   }
1398   CPDF_Object* pObj =
1399       m_Syntax.GetObject(pObjList, objnum, parser_gennum, pContext);
1400   m_Syntax.SavePos();
1401   CFX_ByteString bsWord = m_Syntax.GetKeyword();
1402   if (bsWord == FX_BSTRC("endobj")) {
1403     m_Syntax.SavePos();
1404   }
1405   m_Syntax.RestorePos(SavedPos);
1406   if (pObj) {
1407     if (!objnum) {
1408       pObj->m_ObjNum = parser_objnum;
1409     }
1410     pObj->m_GenNum = parser_gennum;
1411   }
1412   return pObj;
1413 }
1414 CPDF_Object* CPDF_Parser::ParseIndirectObjectAtByStrict(
1415     CPDF_IndirectObjects* pObjList,
1416     FX_FILESIZE pos,
1417     FX_DWORD objnum,
1418     struct PARSE_CONTEXT* pContext,
1419     FX_FILESIZE* pResultPos) {
1420   FX_FILESIZE SavedPos = m_Syntax.SavePos();
1421   m_Syntax.RestorePos(pos);
1422   FX_BOOL bIsNumber;
1423   CFX_ByteString word = m_Syntax.GetNextWord(bIsNumber);
1424   if (!bIsNumber) {
1425     m_Syntax.RestorePos(SavedPos);
1426     return NULL;
1427   }
1428   FX_DWORD parser_objnum = FXSYS_atoi(word);
1429   if (objnum && parser_objnum != objnum) {
1430     m_Syntax.RestorePos(SavedPos);
1431     return NULL;
1432   }
1433   word = m_Syntax.GetNextWord(bIsNumber);
1434   if (!bIsNumber) {
1435     m_Syntax.RestorePos(SavedPos);
1436     return NULL;
1437   }
1438   FX_DWORD gennum = FXSYS_atoi(word);
1439   if (m_Syntax.GetKeyword() != FX_BSTRC("obj")) {
1440     m_Syntax.RestorePos(SavedPos);
1441     return NULL;
1442   }
1443   CPDF_Object* pObj =
1444       m_Syntax.GetObjectByStrict(pObjList, objnum, gennum, pContext);
1445   if (pResultPos) {
1446     *pResultPos = m_Syntax.m_Pos;
1447   }
1448   m_Syntax.RestorePos(SavedPos);
1449   return pObj;
1450 }
1451
1452 CPDF_Dictionary* CPDF_Parser::LoadTrailerV4() {
1453   if (m_Syntax.GetKeyword() != FX_BSTRC("trailer"))
1454     return nullptr;
1455
1456   nonstd::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> pObj(
1457       m_Syntax.GetObject(m_pDocument, 0, 0, 0));
1458   if (!ToDictionary(pObj.get()))
1459     return nullptr;
1460   return pObj.release()->AsDictionary();
1461 }
1462
1463 FX_DWORD CPDF_Parser::GetPermissions(FX_BOOL bCheckRevision) {
1464   if (!m_pSecurityHandler) {
1465     return (FX_DWORD)-1;
1466   }
1467   FX_DWORD dwPermission = m_pSecurityHandler->GetPermissions();
1468   if (m_pEncryptDict &&
1469       m_pEncryptDict->GetString(FX_BSTRC("Filter")) == FX_BSTRC("Standard")) {
1470     dwPermission &= 0xFFFFFFFC;
1471     dwPermission |= 0xFFFFF0C0;
1472     if (bCheckRevision && m_pEncryptDict->GetInteger(FX_BSTRC("R")) == 2) {
1473       dwPermission &= 0xFFFFF0FF;
1474     }
1475   }
1476   return dwPermission;
1477 }
1478 FX_BOOL CPDF_Parser::IsOwner() {
1479   return m_pSecurityHandler == NULL ? TRUE : m_pSecurityHandler->IsOwner();
1480 }
1481 void CPDF_Parser::SetSecurityHandler(CPDF_SecurityHandler* pSecurityHandler,
1482                                      FX_BOOL bForced) {
1483   m_bForceUseSecurityHandler = bForced;
1484   m_pSecurityHandler.reset(pSecurityHandler);
1485   if (m_bForceUseSecurityHandler) {
1486     return;
1487   }
1488   m_Syntax.m_pCryptoHandler.reset(pSecurityHandler->CreateCryptoHandler());
1489   m_Syntax.m_pCryptoHandler->Init(NULL, pSecurityHandler);
1490 }
1491 FX_BOOL CPDF_Parser::IsLinearizedFile(IFX_FileRead* pFileAccess,
1492                                       FX_DWORD offset) {
1493   m_Syntax.InitParser(pFileAccess, offset);
1494   m_Syntax.RestorePos(m_Syntax.m_HeaderOffset + 9);
1495   FX_FILESIZE SavedPos = m_Syntax.SavePos();
1496   FX_BOOL bIsNumber;
1497   CFX_ByteString word = m_Syntax.GetNextWord(bIsNumber);
1498   if (!bIsNumber) {
1499     return FALSE;
1500   }
1501   FX_DWORD objnum = FXSYS_atoi(word);
1502   word = m_Syntax.GetNextWord(bIsNumber);
1503   if (!bIsNumber) {
1504     return FALSE;
1505   }
1506   FX_DWORD gennum = FXSYS_atoi(word);
1507   if (m_Syntax.GetKeyword() != FX_BSTRC("obj")) {
1508     m_Syntax.RestorePos(SavedPos);
1509     return FALSE;
1510   }
1511   m_pLinearized = m_Syntax.GetObject(NULL, objnum, gennum, 0);
1512   if (!m_pLinearized) {
1513     return FALSE;
1514   }
1515
1516   CPDF_Dictionary* pDict = m_pLinearized->GetDict();
1517   if (pDict && pDict->GetElement(FX_BSTRC("Linearized"))) {
1518     m_Syntax.GetNextWord(bIsNumber);
1519
1520     CPDF_Object* pLen = pDict->GetElement(FX_BSTRC("L"));
1521     if (!pLen) {
1522       m_pLinearized->Release();
1523       m_pLinearized = NULL;
1524       return FALSE;
1525     }
1526     if (pLen->GetInteger() != (int)pFileAccess->GetSize()) {
1527       return FALSE;
1528     }
1529
1530     if (CPDF_Number* pNo = ToNumber(pDict->GetElement(FX_BSTRC("P"))))
1531       m_dwFirstPageNo = pNo->GetInteger();
1532
1533     if (CPDF_Number* pTable = ToNumber(pDict->GetElement(FX_BSTRC("T"))))
1534       m_LastXRefOffset = pTable->GetInteger();
1535
1536     return TRUE;
1537   }
1538   m_pLinearized->Release();
1539   m_pLinearized = NULL;
1540   return FALSE;
1541 }
1542 FX_DWORD CPDF_Parser::StartAsynParse(IFX_FileRead* pFileAccess,
1543                                      FX_BOOL bReParse,
1544                                      FX_BOOL bOwnFileRead) {
1545   CloseParser(bReParse);
1546   m_bXRefStream = FALSE;
1547   m_LastXRefOffset = 0;
1548   m_bOwnFileRead = bOwnFileRead;
1549   int32_t offset = GetHeaderOffset(pFileAccess);
1550   if (offset == -1) {
1551     return PDFPARSE_ERROR_FORMAT;
1552   }
1553   if (!IsLinearizedFile(pFileAccess, offset)) {
1554     m_Syntax.m_pFileAccess = NULL;
1555     return StartParse(pFileAccess, bReParse, bOwnFileRead);
1556   }
1557   if (!bReParse) {
1558     m_pDocument = new CPDF_Document(this);
1559   }
1560   FX_FILESIZE dwFirstXRefOffset = m_Syntax.SavePos();
1561   FX_BOOL bXRefRebuilt = FALSE;
1562   FX_BOOL bLoadV4 = FALSE;
1563   if (!(bLoadV4 = LoadCrossRefV4(dwFirstXRefOffset, 0, FALSE, FALSE)) &&
1564       !LoadCrossRefV5(dwFirstXRefOffset, dwFirstXRefOffset, TRUE)) {
1565     if (!RebuildCrossRef()) {
1566       return PDFPARSE_ERROR_FORMAT;
1567     }
1568     bXRefRebuilt = TRUE;
1569     m_LastXRefOffset = 0;
1570   }
1571   if (bLoadV4) {
1572     m_pTrailer = LoadTrailerV4();
1573     if (m_pTrailer == NULL) {
1574       return FALSE;
1575     }
1576     int32_t xrefsize = GetDirectInteger(m_pTrailer, FX_BSTRC("Size"));
1577     if (xrefsize > 0) {
1578       m_CrossRef.SetSize(xrefsize);
1579       m_V5Type.SetSize(xrefsize);
1580     }
1581   }
1582   FX_DWORD dwRet = SetEncryptHandler();
1583   if (dwRet != PDFPARSE_ERROR_SUCCESS) {
1584     return dwRet;
1585   }
1586   m_pDocument->LoadAsynDoc(m_pLinearized->GetDict());
1587   if (m_pDocument->GetRoot() == NULL || m_pDocument->GetPageCount() == 0) {
1588     if (bXRefRebuilt) {
1589       return PDFPARSE_ERROR_FORMAT;
1590     }
1591     ReleaseEncryptHandler();
1592     if (!RebuildCrossRef()) {
1593       return PDFPARSE_ERROR_FORMAT;
1594     }
1595     dwRet = SetEncryptHandler();
1596     if (dwRet != PDFPARSE_ERROR_SUCCESS) {
1597       return dwRet;
1598     }
1599     m_pDocument->LoadAsynDoc(m_pLinearized->GetDict());
1600     if (m_pDocument->GetRoot() == NULL) {
1601       return PDFPARSE_ERROR_FORMAT;
1602     }
1603   }
1604   FXSYS_qsort(m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
1605               sizeof(FX_FILESIZE), CompareFileSize);
1606   FX_DWORD RootObjNum = GetRootObjNum();
1607   if (RootObjNum == 0) {
1608     ReleaseEncryptHandler();
1609     RebuildCrossRef();
1610     RootObjNum = GetRootObjNum();
1611     if (RootObjNum == 0) {
1612       return PDFPARSE_ERROR_FORMAT;
1613     }
1614     dwRet = SetEncryptHandler();
1615     if (dwRet != PDFPARSE_ERROR_SUCCESS) {
1616       return dwRet;
1617     }
1618   }
1619   if (m_pSecurityHandler && m_pSecurityHandler->IsMetadataEncrypted()) {
1620     if (CPDF_Reference* pMetadata = ToReference(
1621             m_pDocument->GetRoot()->GetElement(FX_BSTRC("Metadata"))))
1622       m_Syntax.m_MetadataObjnum = pMetadata->GetRefObjNum();
1623   }
1624   return PDFPARSE_ERROR_SUCCESS;
1625 }
1626 FX_BOOL CPDF_Parser::LoadLinearizedAllCrossRefV5(FX_FILESIZE xrefpos) {
1627   if (!LoadCrossRefV5(xrefpos, xrefpos, FALSE)) {
1628     return FALSE;
1629   }
1630   while (xrefpos)
1631     if (!LoadCrossRefV5(xrefpos, xrefpos, FALSE)) {
1632       return FALSE;
1633     }
1634   m_ObjectStreamMap.InitHashTable(101, FALSE);
1635   m_bXRefStream = TRUE;
1636   return TRUE;
1637 }
1638 FX_DWORD CPDF_Parser::LoadLinearizedMainXRefTable() {
1639   FX_DWORD dwSaveMetadataObjnum = m_Syntax.m_MetadataObjnum;
1640   m_Syntax.m_MetadataObjnum = 0;
1641   if (m_pTrailer) {
1642     m_pTrailer->Release();
1643     m_pTrailer = NULL;
1644   }
1645   m_Syntax.RestorePos(m_LastXRefOffset - m_Syntax.m_HeaderOffset);
1646   uint8_t ch = 0;
1647   FX_DWORD dwCount = 0;
1648   m_Syntax.GetNextChar(ch);
1649   while (PDFCharIsWhitespace(ch)) {
1650     ++dwCount;
1651     if (m_Syntax.m_FileLen >=
1652         (FX_FILESIZE)(m_Syntax.SavePos() + m_Syntax.m_HeaderOffset)) {
1653       break;
1654     }
1655     m_Syntax.GetNextChar(ch);
1656   }
1657   m_LastXRefOffset += dwCount;
1658   FX_POSITION pos = m_ObjectStreamMap.GetStartPosition();
1659   while (pos) {
1660     void* objnum;
1661     CPDF_StreamAcc* pStream;
1662     m_ObjectStreamMap.GetNextAssoc(pos, objnum, (void*&)pStream);
1663     delete pStream;
1664   }
1665   m_ObjectStreamMap.RemoveAll();
1666   if (!LoadLinearizedAllCrossRefV4(m_LastXRefOffset, m_dwXrefStartObjNum) &&
1667       !LoadLinearizedAllCrossRefV5(m_LastXRefOffset)) {
1668     m_LastXRefOffset = 0;
1669     m_Syntax.m_MetadataObjnum = dwSaveMetadataObjnum;
1670     return PDFPARSE_ERROR_FORMAT;
1671   }
1672   FXSYS_qsort(m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
1673               sizeof(FX_FILESIZE), CompareFileSize);
1674   m_Syntax.m_MetadataObjnum = dwSaveMetadataObjnum;
1675   return PDFPARSE_ERROR_SUCCESS;
1676 }
1677
1678 // static
1679 int CPDF_SyntaxParser::s_CurrentRecursionDepth = 0;
1680
1681 CPDF_SyntaxParser::CPDF_SyntaxParser() {
1682   m_pFileAccess = NULL;
1683   m_pFileBuf = NULL;
1684   m_BufSize = CPDF_ModuleMgr::kFileBufSize;
1685   m_pFileBuf = NULL;
1686   m_MetadataObjnum = 0;
1687   m_dwWordPos = 0;
1688   m_bFileStream = FALSE;
1689 }
1690 CPDF_SyntaxParser::~CPDF_SyntaxParser() {
1691   FX_Free(m_pFileBuf);
1692 }
1693
1694 FX_BOOL CPDF_SyntaxParser::GetCharAt(FX_FILESIZE pos, uint8_t& ch) {
1695   CFX_AutoRestorer<FX_FILESIZE> save_pos(&m_Pos);
1696   m_Pos = pos;
1697   return GetNextChar(ch);
1698 }
1699
1700 FX_BOOL CPDF_SyntaxParser::GetNextChar(uint8_t& ch) {
1701   FX_FILESIZE pos = m_Pos + m_HeaderOffset;
1702   if (pos >= m_FileLen) {
1703     return FALSE;
1704   }
1705   if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) {
1706     FX_FILESIZE read_pos = pos;
1707     FX_DWORD read_size = m_BufSize;
1708     if ((FX_FILESIZE)read_size > m_FileLen) {
1709       read_size = (FX_DWORD)m_FileLen;
1710     }
1711     if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) {
1712       if (m_FileLen < (FX_FILESIZE)read_size) {
1713         read_pos = 0;
1714         read_size = (FX_DWORD)m_FileLen;
1715       } else {
1716         read_pos = m_FileLen - read_size;
1717       }
1718     }
1719     if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size)) {
1720       return FALSE;
1721     }
1722     m_BufOffset = read_pos;
1723   }
1724   ch = m_pFileBuf[pos - m_BufOffset];
1725   m_Pos++;
1726   return TRUE;
1727 }
1728 FX_BOOL CPDF_SyntaxParser::GetCharAtBackward(FX_FILESIZE pos, uint8_t& ch) {
1729   pos += m_HeaderOffset;
1730   if (pos >= m_FileLen) {
1731     return FALSE;
1732   }
1733   if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) {
1734     FX_FILESIZE read_pos;
1735     if (pos < (FX_FILESIZE)m_BufSize) {
1736       read_pos = 0;
1737     } else {
1738       read_pos = pos - m_BufSize + 1;
1739     }
1740     FX_DWORD read_size = m_BufSize;
1741     if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) {
1742       if (m_FileLen < (FX_FILESIZE)read_size) {
1743         read_pos = 0;
1744         read_size = (FX_DWORD)m_FileLen;
1745       } else {
1746         read_pos = m_FileLen - read_size;
1747       }
1748     }
1749     if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size)) {
1750       return FALSE;
1751     }
1752     m_BufOffset = read_pos;
1753   }
1754   ch = m_pFileBuf[pos - m_BufOffset];
1755   return TRUE;
1756 }
1757 FX_BOOL CPDF_SyntaxParser::ReadBlock(uint8_t* pBuf, FX_DWORD size) {
1758   if (!m_pFileAccess->ReadBlock(pBuf, m_Pos + m_HeaderOffset, size)) {
1759     return FALSE;
1760   }
1761   m_Pos += size;
1762   return TRUE;
1763 }
1764 #define MAX_WORD_BUFFER 256
1765 void CPDF_SyntaxParser::GetNextWord() {
1766   m_WordSize = 0;
1767   m_bIsNumber = TRUE;
1768   uint8_t ch;
1769   if (!GetNextChar(ch)) {
1770     return;
1771   }
1772   while (1) {
1773     while (PDFCharIsWhitespace(ch)) {
1774       if (!GetNextChar(ch))
1775         return;
1776     }
1777     if (ch != '%')
1778       break;
1779
1780     while (1) {
1781       if (!GetNextChar(ch))
1782         return;
1783       if (PDFCharIsLineEnding(ch))
1784         break;
1785     }
1786   }
1787
1788   if (PDFCharIsDelimiter(ch)) {
1789     m_bIsNumber = FALSE;
1790     m_WordBuffer[m_WordSize++] = ch;
1791     if (ch == '/') {
1792       while (1) {
1793         if (!GetNextChar(ch))
1794           return;
1795
1796         if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) {
1797           m_Pos--;
1798           return;
1799         }
1800
1801         if (m_WordSize < MAX_WORD_BUFFER)
1802           m_WordBuffer[m_WordSize++] = ch;
1803       }
1804     } else if (ch == '<') {
1805       if (!GetNextChar(ch))
1806         return;
1807       if (ch == '<')
1808         m_WordBuffer[m_WordSize++] = ch;
1809       else
1810         m_Pos--;
1811     } else if (ch == '>') {
1812       if (!GetNextChar(ch))
1813         return;
1814       if (ch == '>')
1815         m_WordBuffer[m_WordSize++] = ch;
1816       else
1817         m_Pos--;
1818     }
1819     return;
1820   }
1821
1822   while (1) {
1823     if (m_WordSize < MAX_WORD_BUFFER)
1824       m_WordBuffer[m_WordSize++] = ch;
1825
1826     if (!PDFCharIsNumeric(ch))
1827       m_bIsNumber = FALSE;
1828     if (!GetNextChar(ch))
1829       return;
1830
1831     if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) {
1832       m_Pos--;
1833       break;
1834     }
1835   }
1836 }
1837 CFX_ByteString CPDF_SyntaxParser::ReadString() {
1838   uint8_t ch;
1839   if (!GetNextChar(ch)) {
1840     return CFX_ByteString();
1841   }
1842   CFX_ByteTextBuf buf;
1843   int32_t parlevel = 0;
1844   int32_t status = 0, iEscCode = 0;
1845   while (1) {
1846     switch (status) {
1847       case 0:
1848         if (ch == ')') {
1849           if (parlevel == 0) {
1850             return buf.GetByteString();
1851           }
1852           parlevel--;
1853           buf.AppendChar(')');
1854         } else if (ch == '(') {
1855           parlevel++;
1856           buf.AppendChar('(');
1857         } else if (ch == '\\') {
1858           status = 1;
1859         } else {
1860           buf.AppendChar(ch);
1861         }
1862         break;
1863       case 1:
1864         if (ch >= '0' && ch <= '7') {
1865           iEscCode = ch - '0';
1866           status = 2;
1867           break;
1868         }
1869         if (ch == 'n') {
1870           buf.AppendChar('\n');
1871         } else if (ch == 'r') {
1872           buf.AppendChar('\r');
1873         } else if (ch == 't') {
1874           buf.AppendChar('\t');
1875         } else if (ch == 'b') {
1876           buf.AppendChar('\b');
1877         } else if (ch == 'f') {
1878           buf.AppendChar('\f');
1879         } else if (ch == '\r') {
1880           status = 4;
1881           break;
1882         } else if (ch == '\n') {
1883         } else {
1884           buf.AppendChar(ch);
1885         }
1886         status = 0;
1887         break;
1888       case 2:
1889         if (ch >= '0' && ch <= '7') {
1890           iEscCode = iEscCode * 8 + ch - '0';
1891           status = 3;
1892         } else {
1893           buf.AppendChar(iEscCode);
1894           status = 0;
1895           continue;
1896         }
1897         break;
1898       case 3:
1899         if (ch >= '0' && ch <= '7') {
1900           iEscCode = iEscCode * 8 + ch - '0';
1901           buf.AppendChar(iEscCode);
1902           status = 0;
1903         } else {
1904           buf.AppendChar(iEscCode);
1905           status = 0;
1906           continue;
1907         }
1908         break;
1909       case 4:
1910         status = 0;
1911         if (ch != '\n') {
1912           continue;
1913         }
1914         break;
1915     }
1916     if (!GetNextChar(ch)) {
1917       break;
1918     }
1919   }
1920   GetNextChar(ch);
1921   return buf.GetByteString();
1922 }
1923 CFX_ByteString CPDF_SyntaxParser::ReadHexString() {
1924   uint8_t ch;
1925   if (!GetNextChar(ch)) {
1926     return CFX_ByteString();
1927   }
1928   CFX_BinaryBuf buf;
1929   FX_BOOL bFirst = TRUE;
1930   uint8_t code = 0;
1931   while (1) {
1932     if (ch == '>') {
1933       break;
1934     }
1935     if (ch >= '0' && ch <= '9') {
1936       if (bFirst) {
1937         code = (ch - '0') * 16;
1938       } else {
1939         code += ch - '0';
1940         buf.AppendByte((uint8_t)code);
1941       }
1942       bFirst = !bFirst;
1943     } else if (ch >= 'A' && ch <= 'F') {
1944       if (bFirst) {
1945         code = (ch - 'A' + 10) * 16;
1946       } else {
1947         code += ch - 'A' + 10;
1948         buf.AppendByte((uint8_t)code);
1949       }
1950       bFirst = !bFirst;
1951     } else if (ch >= 'a' && ch <= 'f') {
1952       if (bFirst) {
1953         code = (ch - 'a' + 10) * 16;
1954       } else {
1955         code += ch - 'a' + 10;
1956         buf.AppendByte((uint8_t)code);
1957       }
1958       bFirst = !bFirst;
1959     }
1960     if (!GetNextChar(ch)) {
1961       break;
1962     }
1963   }
1964   if (!bFirst) {
1965     buf.AppendByte((uint8_t)code);
1966   }
1967   return buf.GetByteString();
1968 }
1969 void CPDF_SyntaxParser::ToNextLine() {
1970   uint8_t ch;
1971   while (GetNextChar(ch)) {
1972     if (ch == '\n') {
1973       break;
1974     }
1975     if (ch == '\r') {
1976       GetNextChar(ch);
1977       if (ch != '\n') {
1978         --m_Pos;
1979       }
1980       break;
1981     }
1982   }
1983 }
1984 void CPDF_SyntaxParser::ToNextWord() {
1985   uint8_t ch;
1986   if (!GetNextChar(ch))
1987     return;
1988
1989   while (1) {
1990     while (PDFCharIsWhitespace(ch)) {
1991       m_dwWordPos = m_Pos;
1992       if (!GetNextChar(ch))
1993         return;
1994     }
1995
1996     if (ch != '%')
1997       break;
1998
1999     while (1) {
2000       if (!GetNextChar(ch))
2001         return;
2002       if (PDFCharIsLineEnding(ch))
2003         break;
2004     }
2005   }
2006   m_Pos--;
2007 }
2008
2009 CFX_ByteString CPDF_SyntaxParser::GetNextWord(FX_BOOL& bIsNumber) {
2010   GetNextWord();
2011   bIsNumber = m_bIsNumber;
2012   return CFX_ByteString((const FX_CHAR*)m_WordBuffer, m_WordSize);
2013 }
2014 CFX_ByteString CPDF_SyntaxParser::GetKeyword() {
2015   GetNextWord();
2016   return CFX_ByteString((const FX_CHAR*)m_WordBuffer, m_WordSize);
2017 }
2018 CPDF_Object* CPDF_SyntaxParser::GetObject(CPDF_IndirectObjects* pObjList,
2019                                           FX_DWORD objnum,
2020                                           FX_DWORD gennum,
2021                                           PARSE_CONTEXT* pContext,
2022                                           FX_BOOL bDecrypt) {
2023   CFX_AutoRestorer<int> restorer(&s_CurrentRecursionDepth);
2024   if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth) {
2025     return NULL;
2026   }
2027   FX_FILESIZE SavedPos = m_Pos;
2028   FX_BOOL bTypeOnly = pContext && (pContext->m_Flags & PDFPARSE_TYPEONLY);
2029   FX_BOOL bIsNumber;
2030   CFX_ByteString word = GetNextWord(bIsNumber);
2031   if (word.GetLength() == 0) {
2032     if (bTypeOnly)
2033       return (CPDF_Object*)PDFOBJ_INVALID;
2034     return NULL;
2035   }
2036   if (bIsNumber) {
2037     FX_FILESIZE SavedPos = m_Pos;
2038     CFX_ByteString nextword = GetNextWord(bIsNumber);
2039     if (bIsNumber) {
2040       CFX_ByteString nextword2 = GetNextWord(bIsNumber);
2041       if (nextword2 == FX_BSTRC("R")) {
2042         FX_DWORD objnum = FXSYS_atoi(word);
2043         if (bTypeOnly)
2044           return (CPDF_Object*)PDFOBJ_REFERENCE;
2045         return new CPDF_Reference(pObjList, objnum);
2046       }
2047     }
2048     m_Pos = SavedPos;
2049     if (bTypeOnly)
2050       return (CPDF_Object*)PDFOBJ_NUMBER;
2051     return CPDF_Number::Create(word);
2052   }
2053   if (word == FX_BSTRC("true") || word == FX_BSTRC("false")) {
2054     if (bTypeOnly)
2055       return (CPDF_Object*)PDFOBJ_BOOLEAN;
2056     return CPDF_Boolean::Create(word == FX_BSTRC("true"));
2057   }
2058   if (word == FX_BSTRC("null")) {
2059     if (bTypeOnly)
2060       return (CPDF_Object*)PDFOBJ_NULL;
2061     return CPDF_Null::Create();
2062   }
2063   if (word == FX_BSTRC("(")) {
2064     if (bTypeOnly)
2065       return (CPDF_Object*)PDFOBJ_STRING;
2066     CFX_ByteString str = ReadString();
2067     if (m_pCryptoHandler && bDecrypt) {
2068       m_pCryptoHandler->Decrypt(objnum, gennum, str);
2069     }
2070     return CPDF_String::Create(str, FALSE);
2071   }
2072   if (word == FX_BSTRC("<")) {
2073     if (bTypeOnly)
2074       return (CPDF_Object*)PDFOBJ_STRING;
2075     CFX_ByteString str = ReadHexString();
2076     if (m_pCryptoHandler && bDecrypt) {
2077       m_pCryptoHandler->Decrypt(objnum, gennum, str);
2078     }
2079     return CPDF_String::Create(str, TRUE);
2080   }
2081   if (word == FX_BSTRC("[")) {
2082     if (bTypeOnly)
2083       return (CPDF_Object*)PDFOBJ_ARRAY;
2084     CPDF_Array* pArray = CPDF_Array::Create();
2085     while (CPDF_Object* pObj = GetObject(pObjList, objnum, gennum))
2086       pArray->Add(pObj);
2087
2088     return pArray;
2089   }
2090   if (word[0] == '/') {
2091     if (bTypeOnly)
2092       return (CPDF_Object*)PDFOBJ_NAME;
2093     return CPDF_Name::Create(
2094         PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)));
2095   }
2096   if (word == FX_BSTRC("<<")) {
2097     if (bTypeOnly)
2098       return (CPDF_Object*)PDFOBJ_DICTIONARY;
2099
2100     if (pContext)
2101       pContext->m_DictStart = SavedPos;
2102
2103     int32_t nKeys = 0;
2104     FX_FILESIZE dwSignValuePos = 0;
2105     nonstd::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>> pDict(
2106         CPDF_Dictionary::Create());
2107     while (1) {
2108       FX_BOOL bIsNumber;
2109       CFX_ByteString key = GetNextWord(bIsNumber);
2110       if (key.IsEmpty())
2111         return nullptr;
2112
2113       FX_FILESIZE SavedPos = m_Pos - key.GetLength();
2114       if (key == FX_BSTRC(">>"))
2115         break;
2116
2117       if (key == FX_BSTRC("endobj")) {
2118         m_Pos = SavedPos;
2119         break;
2120       }
2121       if (key[0] != '/')
2122         continue;
2123
2124       ++nKeys;
2125       key = PDF_NameDecode(key);
2126       if (key.IsEmpty())
2127         continue;
2128
2129       CFX_ByteStringC keyNoSlash(key.c_str() + 1, key.GetLength() - 1);
2130       if (keyNoSlash.IsEmpty())
2131         continue;
2132
2133       if (key == FX_BSTRC("/Contents"))
2134         dwSignValuePos = m_Pos;
2135
2136       CPDF_Object* pObj = GetObject(pObjList, objnum, gennum);
2137       if (!pObj)
2138         continue;
2139
2140       // TODO(thestig): Remove this conditional once CPDF_Dictionary has a
2141       // better underlying map implementation.
2142       if (nKeys < 32) {
2143         pDict->SetAt(keyNoSlash, pObj);
2144       } else {
2145         pDict->AddValue(keyNoSlash, pObj);
2146       }
2147     }
2148
2149     if (IsSignatureDict(pDict.get())) {
2150       FX_FILESIZE dwSavePos = m_Pos;
2151       m_Pos = dwSignValuePos;
2152       CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, NULL, FALSE);
2153       pDict->SetAt(FX_BSTRC("Contents"), pObj);
2154       m_Pos = dwSavePos;
2155     }
2156     if (pContext) {
2157       pContext->m_DictEnd = m_Pos;
2158       if (pContext->m_Flags & PDFPARSE_NOSTREAM) {
2159         return pDict.release();
2160       }
2161     }
2162     FX_FILESIZE SavedPos = m_Pos;
2163     FX_BOOL bIsNumber;
2164     CFX_ByteString nextword = GetNextWord(bIsNumber);
2165     if (nextword != FX_BSTRC("stream")) {
2166       m_Pos = SavedPos;
2167       return pDict.release();
2168     }
2169
2170     return ReadStream(pDict.release(), pContext, objnum, gennum);
2171   }
2172   if (word == FX_BSTRC(">>")) {
2173     m_Pos = SavedPos;
2174     return nullptr;
2175   }
2176   if (bTypeOnly)
2177     return (CPDF_Object*)PDFOBJ_INVALID;
2178
2179   return nullptr;
2180 }
2181
2182 CPDF_Object* CPDF_SyntaxParser::GetObjectByStrict(
2183     CPDF_IndirectObjects* pObjList,
2184     FX_DWORD objnum,
2185     FX_DWORD gennum,
2186     struct PARSE_CONTEXT* pContext) {
2187   CFX_AutoRestorer<int> restorer(&s_CurrentRecursionDepth);
2188   if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth) {
2189     return NULL;
2190   }
2191   FX_FILESIZE SavedPos = m_Pos;
2192   FX_BOOL bTypeOnly = pContext && (pContext->m_Flags & PDFPARSE_TYPEONLY);
2193   FX_BOOL bIsNumber;
2194   CFX_ByteString word = GetNextWord(bIsNumber);
2195   if (word.GetLength() == 0) {
2196     if (bTypeOnly)
2197       return (CPDF_Object*)PDFOBJ_INVALID;
2198     return nullptr;
2199   }
2200   if (bIsNumber) {
2201     FX_FILESIZE SavedPos = m_Pos;
2202     CFX_ByteString nextword = GetNextWord(bIsNumber);
2203     if (bIsNumber) {
2204       CFX_ByteString nextword2 = GetNextWord(bIsNumber);
2205       if (nextword2 == FX_BSTRC("R")) {
2206         if (bTypeOnly)
2207           return (CPDF_Object*)PDFOBJ_REFERENCE;
2208         FX_DWORD objnum = FXSYS_atoi(word);
2209         return new CPDF_Reference(pObjList, objnum);
2210       }
2211     }
2212     m_Pos = SavedPos;
2213     if (bTypeOnly)
2214       return (CPDF_Object*)PDFOBJ_NUMBER;
2215     return CPDF_Number::Create(word);
2216   }
2217   if (word == FX_BSTRC("true") || word == FX_BSTRC("false")) {
2218     if (bTypeOnly)
2219       return (CPDF_Object*)PDFOBJ_BOOLEAN;
2220     return CPDF_Boolean::Create(word == FX_BSTRC("true"));
2221   }
2222   if (word == FX_BSTRC("null")) {
2223     if (bTypeOnly)
2224       return (CPDF_Object*)PDFOBJ_NULL;
2225     return CPDF_Null::Create();
2226   }
2227   if (word == FX_BSTRC("(")) {
2228     if (bTypeOnly)
2229       return (CPDF_Object*)PDFOBJ_STRING;
2230     CFX_ByteString str = ReadString();
2231     if (m_pCryptoHandler)
2232       m_pCryptoHandler->Decrypt(objnum, gennum, str);
2233     return CPDF_String::Create(str, FALSE);
2234   }
2235   if (word == FX_BSTRC("<")) {
2236     if (bTypeOnly)
2237       return (CPDF_Object*)PDFOBJ_STRING;
2238     CFX_ByteString str = ReadHexString();
2239     if (m_pCryptoHandler)
2240       m_pCryptoHandler->Decrypt(objnum, gennum, str);
2241     return CPDF_String::Create(str, TRUE);
2242   }
2243   if (word == FX_BSTRC("[")) {
2244     if (bTypeOnly)
2245       return (CPDF_Object*)PDFOBJ_ARRAY;
2246     nonstd::unique_ptr<CPDF_Array, ReleaseDeleter<CPDF_Array>> pArray(
2247         CPDF_Array::Create());
2248     while (CPDF_Object* pObj = GetObject(pObjList, objnum, gennum))
2249       pArray->Add(pObj);
2250     return m_WordBuffer[0] == ']' ? pArray.release() : nullptr;
2251   }
2252   if (word[0] == '/') {
2253     if (bTypeOnly)
2254       return (CPDF_Object*)PDFOBJ_NAME;
2255     return CPDF_Name::Create(
2256         PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)));
2257   }
2258   if (word == FX_BSTRC("<<")) {
2259     if (bTypeOnly)
2260       return (CPDF_Object*)PDFOBJ_DICTIONARY;
2261     if (pContext)
2262       pContext->m_DictStart = SavedPos;
2263
2264     nonstd::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>> pDict(
2265         CPDF_Dictionary::Create());
2266     while (1) {
2267       FX_BOOL bIsNumber;
2268       FX_FILESIZE SavedPos = m_Pos;
2269       CFX_ByteString key = GetNextWord(bIsNumber);
2270       if (key.IsEmpty())
2271         return nullptr;
2272
2273       if (key == FX_BSTRC(">>"))
2274         break;
2275
2276       if (key == FX_BSTRC("endobj")) {
2277         m_Pos = SavedPos;
2278         break;
2279       }
2280       if (key[0] != '/')
2281         continue;
2282
2283       key = PDF_NameDecode(key);
2284       nonstd::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> obj(
2285           GetObject(pObjList, objnum, gennum));
2286       if (!obj) {
2287         uint8_t ch;
2288         while (GetNextChar(ch) && ch != 0x0A && ch != 0x0D) {
2289         }
2290         return nullptr;
2291       }
2292       if (key.GetLength() > 1) {
2293         pDict->AddValue(CFX_ByteStringC(key.c_str() + 1, key.GetLength() - 1),
2294                         obj.release());
2295       }
2296     }
2297     if (pContext) {
2298       pContext->m_DictEnd = m_Pos;
2299       if (pContext->m_Flags & PDFPARSE_NOSTREAM) {
2300         return pDict.release();
2301       }
2302     }
2303     FX_FILESIZE SavedPos = m_Pos;
2304     FX_BOOL bIsNumber;
2305     CFX_ByteString nextword = GetNextWord(bIsNumber);
2306     if (nextword != FX_BSTRC("stream")) {
2307       m_Pos = SavedPos;
2308       return pDict.release();
2309     }
2310
2311     return ReadStream(pDict.release(), pContext, objnum, gennum);
2312   }
2313   if (word == FX_BSTRC(">>")) {
2314     m_Pos = SavedPos;
2315     return nullptr;
2316   }
2317   if (bTypeOnly)
2318     return (CPDF_Object*)PDFOBJ_INVALID;
2319   return nullptr;
2320 }
2321
2322 unsigned int CPDF_SyntaxParser::ReadEOLMarkers(FX_FILESIZE pos) {
2323   unsigned char byte1 = 0;
2324   unsigned char byte2 = 0;
2325   GetCharAt(pos, byte1);
2326   GetCharAt(pos + 1, byte2);
2327   unsigned int markers = 0;
2328   if (byte1 == '\r' && byte2 == '\n') {
2329     markers = 2;
2330   } else if (byte1 == '\r' || byte1 == '\n') {
2331     markers = 1;
2332   }
2333   return markers;
2334 }
2335 CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
2336                                            PARSE_CONTEXT* pContext,
2337                                            FX_DWORD objnum,
2338                                            FX_DWORD gennum) {
2339   CPDF_Object* pLenObj = pDict->GetElement(FX_BSTRC("Length"));
2340   FX_FILESIZE len = -1;
2341   CPDF_Reference* pLenObjRef = ToReference(pLenObj);
2342
2343   bool differingObjNum = !pLenObjRef || (pLenObjRef->GetObjList() &&
2344                                          pLenObjRef->GetRefObjNum() != objnum);
2345   if (pLenObj && differingObjNum)
2346     len = pLenObj->GetInteger();
2347
2348   // Locate the start of stream.
2349   ToNextLine();
2350   FX_FILESIZE streamStartPos = m_Pos;
2351   if (pContext) {
2352     pContext->m_DataStart = streamStartPos;
2353   }
2354   const unsigned int ENDSTREAM_LEN = sizeof("endstream") - 1;
2355   const unsigned int ENDOBJ_LEN = sizeof("endobj") - 1;
2356   CPDF_CryptoHandler* pCryptoHandler =
2357       objnum == (FX_DWORD)m_MetadataObjnum ? nullptr : m_pCryptoHandler.get();
2358   if (!pCryptoHandler) {
2359     FX_BOOL bSearchForKeyword = TRUE;
2360     if (len >= 0) {
2361       pdfium::base::CheckedNumeric<FX_FILESIZE> pos = m_Pos;
2362       pos += len;
2363       if (pos.IsValid() && pos.ValueOrDie() < m_FileLen) {
2364         m_Pos = pos.ValueOrDie();
2365       }
2366       m_Pos += ReadEOLMarkers(m_Pos);
2367       FXSYS_memset(m_WordBuffer, 0, ENDSTREAM_LEN + 1);
2368       GetNextWord();
2369       if (FXSYS_memcmp(m_WordBuffer, "endstream", ENDSTREAM_LEN) == 0 &&
2370           IsWholeWord(m_Pos - ENDSTREAM_LEN, m_FileLen,
2371                       FX_BSTRC("endstream").GetPtr(), ENDSTREAM_LEN, TRUE)) {
2372         bSearchForKeyword = FALSE;
2373       }
2374     }
2375     if (bSearchForKeyword) {
2376       // If len is not available, len needs to be calculated
2377       // by searching the keywords "endstream" or "endobj".
2378       m_Pos = streamStartPos;
2379       FX_FILESIZE endStreamOffset = 0;
2380       while (endStreamOffset >= 0) {
2381         endStreamOffset = FindTag(FX_BSTRC("endstream"), 0);
2382         if (endStreamOffset < 0) {
2383           // Can't find any "endstream".
2384           break;
2385         }
2386         if (IsWholeWord(m_Pos - ENDSTREAM_LEN, m_FileLen,
2387                         FX_BSTRC("endstream").GetPtr(), ENDSTREAM_LEN, TRUE)) {
2388           // Stop searching when the keyword "endstream" is found.
2389           endStreamOffset = m_Pos - streamStartPos - ENDSTREAM_LEN;
2390           break;
2391         }
2392       }
2393       m_Pos = streamStartPos;
2394       FX_FILESIZE endObjOffset = 0;
2395       while (endObjOffset >= 0) {
2396         endObjOffset = FindTag(FX_BSTRC("endobj"), 0);
2397         if (endObjOffset < 0) {
2398           // Can't find any "endobj".
2399           break;
2400         }
2401         if (IsWholeWord(m_Pos - ENDOBJ_LEN, m_FileLen,
2402                         FX_BSTRC("endobj").GetPtr(), ENDOBJ_LEN, TRUE)) {
2403           // Stop searching when the keyword "endobj" is found.
2404           endObjOffset = m_Pos - streamStartPos - ENDOBJ_LEN;
2405           break;
2406         }
2407       }
2408       if (endStreamOffset < 0 && endObjOffset < 0) {
2409         // Can't find "endstream" or "endobj".
2410         return nullptr;
2411       }
2412       if (endStreamOffset < 0 && endObjOffset >= 0) {
2413         // Correct the position of end stream.
2414         endStreamOffset = endObjOffset;
2415       } else if (endStreamOffset >= 0 && endObjOffset < 0) {
2416         // Correct the position of end obj.
2417         endObjOffset = endStreamOffset;
2418       } else if (endStreamOffset > endObjOffset) {
2419         endStreamOffset = endObjOffset;
2420       }
2421       len = endStreamOffset;
2422       int numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 2);
2423       if (numMarkers == 2) {
2424         len -= 2;
2425       } else {
2426         numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 1);
2427         if (numMarkers == 1) {
2428           len -= 1;
2429         }
2430       }
2431       if (len < 0) {
2432         return nullptr;
2433       }
2434       pDict->SetAtInteger(FX_BSTRC("Length"), len);
2435     }
2436     m_Pos = streamStartPos;
2437   }
2438   if (len < 0) {
2439     return nullptr;
2440   }
2441   uint8_t* pData = nullptr;
2442   if (len > 0) {
2443     pData = FX_Alloc(uint8_t, len);
2444     ReadBlock(pData, len);
2445     if (pCryptoHandler) {
2446       CFX_BinaryBuf dest_buf;
2447       dest_buf.EstimateSize(pCryptoHandler->DecryptGetSize(len));
2448       void* context = pCryptoHandler->DecryptStart(objnum, gennum);
2449       pCryptoHandler->DecryptStream(context, pData, len, dest_buf);
2450       pCryptoHandler->DecryptFinish(context, dest_buf);
2451       FX_Free(pData);
2452       pData = dest_buf.GetBuffer();
2453       len = dest_buf.GetSize();
2454       dest_buf.DetachBuffer();
2455     }
2456   }
2457   CPDF_Stream* pStream = new CPDF_Stream(pData, len, pDict);
2458   if (pContext) {
2459     pContext->m_DataEnd = pContext->m_DataStart + len;
2460   }
2461   streamStartPos = m_Pos;
2462   FXSYS_memset(m_WordBuffer, 0, ENDOBJ_LEN + 1);
2463   GetNextWord();
2464   int numMarkers = ReadEOLMarkers(m_Pos);
2465   if (m_WordSize == ENDOBJ_LEN && numMarkers != 0 &&
2466       FXSYS_memcmp(m_WordBuffer, "endobj", ENDOBJ_LEN) == 0) {
2467     m_Pos = streamStartPos;
2468   }
2469   return pStream;
2470 }
2471 void CPDF_SyntaxParser::InitParser(IFX_FileRead* pFileAccess,
2472                                    FX_DWORD HeaderOffset) {
2473   FX_Free(m_pFileBuf);
2474   m_pFileBuf = FX_Alloc(uint8_t, m_BufSize);
2475   m_HeaderOffset = HeaderOffset;
2476   m_FileLen = pFileAccess->GetSize();
2477   m_Pos = 0;
2478   m_pFileAccess = pFileAccess;
2479   m_BufOffset = 0;
2480   pFileAccess->ReadBlock(
2481       m_pFileBuf, 0,
2482       (size_t)((FX_FILESIZE)m_BufSize > m_FileLen ? m_FileLen : m_BufSize));
2483 }
2484 int32_t CPDF_SyntaxParser::GetDirectNum() {
2485   GetNextWord();
2486   if (!m_bIsNumber) {
2487     return 0;
2488   }
2489   m_WordBuffer[m_WordSize] = 0;
2490   return FXSYS_atoi((const FX_CHAR*)m_WordBuffer);
2491 }
2492 FX_BOOL CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos,
2493                                        FX_FILESIZE limit,
2494                                        const uint8_t* tag,
2495                                        FX_DWORD taglen,
2496                                        FX_BOOL checkKeyword) {
2497   bool bCheckLeft = !PDFCharIsDelimiter(tag[0]) && !PDFCharIsWhitespace(tag[0]);
2498   bool bCheckRight = !PDFCharIsDelimiter(tag[taglen - 1]) &&
2499                      !PDFCharIsWhitespace(tag[taglen - 1]);
2500   uint8_t ch;
2501   if (bCheckRight && startpos + (int32_t)taglen <= limit &&
2502       GetCharAt(startpos + (int32_t)taglen, ch)) {
2503     if (PDFCharIsNumeric(ch) || PDFCharIsOther(ch) ||
2504         (checkKeyword && PDFCharIsDelimiter(ch))) {
2505       return FALSE;
2506     }
2507   }
2508
2509   if (bCheckLeft && startpos > 0 && GetCharAt(startpos - 1, ch)) {
2510     if (PDFCharIsNumeric(ch) || PDFCharIsOther(ch) ||
2511         (checkKeyword && PDFCharIsDelimiter(ch))) {
2512       return FALSE;
2513     }
2514   }
2515   return TRUE;
2516 }
2517 FX_BOOL CPDF_SyntaxParser::SearchWord(const CFX_ByteStringC& tag,
2518                                       FX_BOOL bWholeWord,
2519                                       FX_BOOL bForward,
2520                                       FX_FILESIZE limit) {
2521   int32_t taglen = tag.GetLength();
2522   if (taglen == 0) {
2523     return FALSE;
2524   }
2525   FX_FILESIZE pos = m_Pos;
2526   int32_t offset = 0;
2527   if (!bForward) {
2528     offset = taglen - 1;
2529   }
2530   const uint8_t* tag_data = tag.GetPtr();
2531   uint8_t byte;
2532   while (1) {
2533     if (bForward) {
2534       if (limit) {
2535         if (pos >= m_Pos + limit) {
2536           return FALSE;
2537         }
2538       }
2539       if (!GetCharAt(pos, byte)) {
2540         return FALSE;
2541       }
2542     } else {
2543       if (limit) {
2544         if (pos <= m_Pos - limit) {
2545           return FALSE;
2546         }
2547       }
2548       if (!GetCharAtBackward(pos, byte)) {
2549         return FALSE;
2550       }
2551     }
2552     if (byte == tag_data[offset]) {
2553       if (bForward) {
2554         offset++;
2555         if (offset < taglen) {
2556           pos++;
2557           continue;
2558         }
2559       } else {
2560         offset--;
2561         if (offset >= 0) {
2562           pos--;
2563           continue;
2564         }
2565       }
2566       FX_FILESIZE startpos = bForward ? pos - taglen + 1 : pos;
2567       if (!bWholeWord ||
2568           IsWholeWord(startpos, limit, tag.GetPtr(), taglen, FALSE)) {
2569         m_Pos = startpos;
2570         return TRUE;
2571       }
2572     }
2573     if (bForward) {
2574       offset = byte == tag_data[0] ? 1 : 0;
2575       pos++;
2576     } else {
2577       offset = byte == tag_data[taglen - 1] ? taglen - 2 : taglen - 1;
2578       pos--;
2579     }
2580     if (pos < 0) {
2581       return FALSE;
2582     }
2583   }
2584   return FALSE;
2585 }
2586
2587 int32_t CPDF_SyntaxParser::SearchMultiWord(const CFX_ByteStringC& tags,
2588                                            FX_BOOL bWholeWord,
2589                                            FX_FILESIZE limit) {
2590   int32_t ntags = 1;
2591   for (int i = 0; i < tags.GetLength(); ++i) {
2592     if (tags[i] == 0) {
2593       ++ntags;
2594     }
2595   }
2596
2597   std::vector<SearchTagRecord> patterns(ntags);
2598   FX_DWORD start = 0;
2599   FX_DWORD itag = 0;
2600   FX_DWORD max_len = 0;
2601   for (int i = 0; i <= tags.GetLength(); ++i) {
2602     if (tags[i] == 0) {
2603       FX_DWORD len = i - start;
2604       max_len = std::max(len, max_len);
2605       patterns[itag].m_pTag = tags.GetPtr() + start;
2606       patterns[itag].m_Len = len;
2607       patterns[itag].m_Offset = 0;
2608       start = i + 1;
2609       ++itag;
2610     }
2611   }
2612
2613   const FX_FILESIZE pos_limit = m_Pos + limit;
2614   for (FX_FILESIZE pos = m_Pos; !limit || pos < pos_limit; ++pos) {
2615     uint8_t byte;
2616     if (!GetCharAt(pos, byte))
2617       break;
2618
2619     for (int i = 0; i < ntags; ++i) {
2620       SearchTagRecord& pat = patterns[i];
2621       if (pat.m_pTag[pat.m_Offset] != byte) {
2622         pat.m_Offset = (pat.m_pTag[0] == byte) ? 1 : 0;
2623         continue;
2624       }
2625
2626       ++pat.m_Offset;
2627       if (pat.m_Offset != pat.m_Len)
2628         continue;
2629
2630       if (!bWholeWord ||
2631           IsWholeWord(pos - pat.m_Len, limit, pat.m_pTag, pat.m_Len, FALSE)) {
2632         return i;
2633       }
2634
2635       pat.m_Offset = (pat.m_pTag[0] == byte) ? 1 : 0;
2636     }
2637   }
2638   return -1;
2639 }
2640
2641 FX_FILESIZE CPDF_SyntaxParser::FindTag(const CFX_ByteStringC& tag,
2642                                        FX_FILESIZE limit) {
2643   int32_t taglen = tag.GetLength();
2644   int32_t match = 0;
2645   limit += m_Pos;
2646   FX_FILESIZE startpos = m_Pos;
2647   while (1) {
2648     uint8_t ch;
2649     if (!GetNextChar(ch)) {
2650       return -1;
2651     }
2652     if (ch == tag[match]) {
2653       match++;
2654       if (match == taglen) {
2655         return m_Pos - startpos - taglen;
2656       }
2657     } else {
2658       match = ch == tag[0] ? 1 : 0;
2659     }
2660     if (limit && m_Pos == limit) {
2661       return -1;
2662     }
2663   }
2664   return -1;
2665 }
2666 void CPDF_SyntaxParser::GetBinary(uint8_t* buffer, FX_DWORD size) {
2667   FX_DWORD offset = 0;
2668   uint8_t ch;
2669   while (1) {
2670     if (!GetNextChar(ch)) {
2671       return;
2672     }
2673     buffer[offset++] = ch;
2674     if (offset == size) {
2675       break;
2676     }
2677   }
2678 }
2679
2680 class CPDF_DataAvail final : public IPDF_DataAvail {
2681  public:
2682   CPDF_DataAvail(IFX_FileAvail* pFileAvail, IFX_FileRead* pFileRead);
2683   ~CPDF_DataAvail() override;
2684
2685   FX_BOOL IsDocAvail(IFX_DownloadHints* pHints) override;
2686
2687   void SetDocument(CPDF_Document* pDoc) override;
2688
2689   FX_BOOL IsPageAvail(int iPage, IFX_DownloadHints* pHints) override;
2690
2691   int32_t IsFormAvail(IFX_DownloadHints* pHints) override;
2692
2693   int32_t IsLinearizedPDF() override;
2694
2695   FX_BOOL IsLinearized() override { return m_bLinearized; }
2696
2697   void GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, FX_DWORD* pSize) override;
2698
2699  protected:
2700   static const int kMaxDataAvailRecursionDepth = 64;
2701   static int s_CurrentDataAvailRecursionDepth;
2702   static const int kMaxPageRecursionDepth = 1024;
2703
2704   FX_DWORD GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset);
2705   FX_BOOL IsObjectsAvail(CFX_PtrArray& obj_array,
2706                          FX_BOOL bParsePage,
2707                          IFX_DownloadHints* pHints,
2708                          CFX_PtrArray& ret_array);
2709   FX_BOOL CheckDocStatus(IFX_DownloadHints* pHints);
2710   FX_BOOL CheckHeader(IFX_DownloadHints* pHints);
2711   FX_BOOL CheckFirstPage(IFX_DownloadHints* pHints);
2712   FX_BOOL CheckEnd(IFX_DownloadHints* pHints);
2713   FX_BOOL CheckCrossRef(IFX_DownloadHints* pHints);
2714   FX_BOOL CheckCrossRefItem(IFX_DownloadHints* pHints);
2715   FX_BOOL CheckTrailer(IFX_DownloadHints* pHints);
2716   FX_BOOL CheckRoot(IFX_DownloadHints* pHints);
2717   FX_BOOL CheckInfo(IFX_DownloadHints* pHints);
2718   FX_BOOL CheckPages(IFX_DownloadHints* pHints);
2719   FX_BOOL CheckPage(IFX_DownloadHints* pHints);
2720   FX_BOOL CheckResources(IFX_DownloadHints* pHints);
2721   FX_BOOL CheckAnnots(IFX_DownloadHints* pHints);
2722   FX_BOOL CheckAcroForm(IFX_DownloadHints* pHints);
2723   FX_BOOL CheckAcroFormSubObject(IFX_DownloadHints* pHints);
2724   FX_BOOL CheckTrailerAppend(IFX_DownloadHints* pHints);
2725   FX_BOOL CheckPageStatus(IFX_DownloadHints* pHints);
2726   FX_BOOL CheckAllCrossRefStream(IFX_DownloadHints* pHints);
2727
2728   int32_t CheckCrossRefStream(IFX_DownloadHints* pHints,
2729                               FX_FILESIZE& xref_offset);
2730   FX_BOOL IsLinearizedFile(uint8_t* pData, FX_DWORD dwLen);
2731   void SetStartOffset(FX_FILESIZE dwOffset);
2732   FX_BOOL GetNextToken(CFX_ByteString& token);
2733   FX_BOOL GetNextChar(uint8_t& ch);
2734   CPDF_Object* ParseIndirectObjectAt(FX_FILESIZE pos, FX_DWORD objnum);
2735   CPDF_Object* GetObject(FX_DWORD objnum,
2736                          IFX_DownloadHints* pHints,
2737                          FX_BOOL* pExistInFile);
2738   FX_BOOL GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages);
2739   FX_BOOL PreparePageItem();
2740   FX_BOOL LoadPages(IFX_DownloadHints* pHints);
2741   FX_BOOL LoadAllXref(IFX_DownloadHints* pHints);
2742   FX_BOOL LoadAllFile(IFX_DownloadHints* pHints);
2743   FX_BOOL CheckLinearizedData(IFX_DownloadHints* pHints);
2744   FX_BOOL CheckFileResources(IFX_DownloadHints* pHints);
2745   FX_BOOL CheckPageAnnots(int iPage, IFX_DownloadHints* pHints);
2746
2747   FX_BOOL CheckLinearizedFirstPage(int iPage, IFX_DownloadHints* pHints);
2748   FX_BOOL HaveResourceAncestor(CPDF_Dictionary* pDict);
2749   FX_BOOL CheckPage(int32_t iPage, IFX_DownloadHints* pHints);
2750   FX_BOOL LoadDocPages(IFX_DownloadHints* pHints);
2751   FX_BOOL LoadDocPage(int32_t iPage, IFX_DownloadHints* pHints);
2752   FX_BOOL CheckPageNode(CPDF_PageNode& pageNodes,
2753                         int32_t iPage,
2754                         int32_t& iCount,
2755                         IFX_DownloadHints* pHints,
2756                         int level);
2757   FX_BOOL CheckUnkownPageNode(FX_DWORD dwPageNo,
2758                               CPDF_PageNode* pPageNode,
2759                               IFX_DownloadHints* pHints);
2760   FX_BOOL CheckArrayPageNode(FX_DWORD dwPageNo,
2761                              CPDF_PageNode* pPageNode,
2762                              IFX_DownloadHints* pHints);
2763   FX_BOOL CheckPageCount(IFX_DownloadHints* pHints);
2764   FX_BOOL IsFirstCheck(int iPage);
2765   void ResetFirstCheck(int iPage);
2766
2767   CPDF_Parser m_parser;
2768
2769   CPDF_SyntaxParser m_syntaxParser;
2770
2771   CPDF_Object* m_pRoot;
2772
2773   FX_DWORD m_dwRootObjNum;
2774
2775   FX_DWORD m_dwInfoObjNum;
2776
2777   CPDF_Object* m_pLinearized;
2778
2779   CPDF_Object* m_pTrailer;
2780
2781   FX_BOOL m_bDocAvail;
2782
2783   FX_FILESIZE m_dwHeaderOffset;
2784
2785   FX_FILESIZE m_dwLastXRefOffset;
2786
2787   FX_FILESIZE m_dwXRefOffset;
2788
2789   FX_FILESIZE m_dwTrailerOffset;
2790
2791   FX_FILESIZE m_dwCurrentOffset;
2792
2793   PDF_DATAAVAIL_STATUS m_docStatus;
2794
2795   FX_FILESIZE m_dwFileLen;
2796
2797   CPDF_Document* m_pDocument;
2798
2799   CPDF_SortObjNumArray m_objnum_array;
2800
2801   CFX_PtrArray m_objs_array;
2802
2803   FX_FILESIZE m_Pos;
2804
2805   FX_FILESIZE m_bufferOffset;
2806
2807   FX_DWORD m_bufferSize;
2808
2809   CFX_ByteString m_WordBuf;
2810
2811   uint8_t m_WordBuffer[257];
2812
2813   FX_DWORD m_WordSize;
2814
2815   uint8_t m_bufferData[512];
2816
2817   CFX_FileSizeArray m_CrossOffset;
2818
2819   CFX_DWordArray m_XRefStreamList;
2820
2821   CFX_DWordArray m_PageObjList;
2822
2823   FX_DWORD m_PagesObjNum;
2824
2825   FX_BOOL m_bLinearized;
2826
2827   FX_DWORD m_dwFirstPageNo;
2828
2829   FX_BOOL m_bLinearedDataOK;
2830
2831   FX_BOOL m_bMainXRefLoadTried;
2832
2833   FX_BOOL m_bMainXRefLoadedOK;
2834
2835   FX_BOOL m_bPagesTreeLoad;
2836
2837   FX_BOOL m_bPagesLoad;
2838
2839   CPDF_Parser* m_pCurrentParser;
2840
2841   FX_FILESIZE m_dwCurrentXRefSteam;
2842
2843   FX_BOOL m_bAnnotsLoad;
2844
2845   FX_BOOL m_bHaveAcroForm;
2846
2847   FX_DWORD m_dwAcroFormObjNum;
2848
2849   FX_BOOL m_bAcroFormLoad;
2850
2851   CPDF_Object* m_pAcroForm;
2852
2853   CFX_PtrArray m_arrayAcroforms;
2854
2855   CPDF_Dictionary* m_pPageDict;
2856
2857   CPDF_Object* m_pPageResource;
2858
2859   FX_BOOL m_bNeedDownLoadResource;
2860
2861   FX_BOOL m_bPageLoadedOK;
2862
2863   FX_BOOL m_bLinearizedFormParamLoad;
2864
2865   CFX_PtrArray m_PagesArray;
2866
2867   FX_DWORD m_dwEncryptObjNum;
2868
2869   FX_FILESIZE m_dwPrevXRefOffset;
2870
2871   FX_BOOL m_bTotalLoadPageTree;
2872
2873   FX_BOOL m_bCurPageDictLoadOK;
2874
2875   CPDF_PageNode m_pageNodes;
2876
2877   std::set<FX_DWORD> m_pageMapCheckState;
2878   std::set<FX_DWORD> m_pagesLoadState;
2879 };
2880
2881 IPDF_DataAvail::IPDF_DataAvail(IFX_FileAvail* pFileAvail,
2882                                IFX_FileRead* pFileRead)
2883     : m_pFileAvail(pFileAvail), m_pFileRead(pFileRead) {}
2884
2885 // static
2886 IPDF_DataAvail* IPDF_DataAvail::Create(IFX_FileAvail* pFileAvail,
2887                                        IFX_FileRead* pFileRead) {
2888   return new CPDF_DataAvail(pFileAvail, pFileRead);
2889 }
2890
2891 // static
2892 int CPDF_DataAvail::s_CurrentDataAvailRecursionDepth = 0;
2893
2894 CPDF_DataAvail::CPDF_DataAvail(IFX_FileAvail* pFileAvail,
2895                                IFX_FileRead* pFileRead)
2896     : IPDF_DataAvail(pFileAvail, pFileRead) {
2897   m_Pos = 0;
2898   m_dwFileLen = 0;
2899   if (m_pFileRead) {
2900     m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize();
2901   }
2902   m_dwCurrentOffset = 0;
2903   m_WordSize = 0;
2904   m_dwXRefOffset = 0;
2905   m_bufferOffset = 0;
2906   m_dwFirstPageNo = 0;
2907   m_bufferSize = 0;
2908   m_PagesObjNum = 0;
2909   m_dwCurrentXRefSteam = 0;
2910   m_dwAcroFormObjNum = 0;
2911   m_dwInfoObjNum = 0;
2912   m_pDocument = 0;
2913   m_dwEncryptObjNum = 0;
2914   m_dwPrevXRefOffset = 0;
2915   m_dwLastXRefOffset = 0;
2916   m_bDocAvail = FALSE;
2917   m_bMainXRefLoadTried = FALSE;
2918   m_bDocAvail = FALSE;
2919   m_bLinearized = FALSE;
2920   m_bPagesLoad = FALSE;
2921   m_bPagesTreeLoad = FALSE;
2922   m_bMainXRefLoadedOK = FALSE;
2923   m_bAnnotsLoad = FALSE;
2924   m_bHaveAcroForm = FALSE;
2925   m_bAcroFormLoad = FALSE;
2926   m_bPageLoadedOK = FALSE;
2927   m_bNeedDownLoadResource = FALSE;
2928   m_bLinearizedFormParamLoad = FALSE;
2929   m_pLinearized = NULL;
2930   m_pRoot = NULL;
2931   m_pTrailer = NULL;
2932   m_pCurrentParser = NULL;
2933   m_pAcroForm = NULL;
2934   m_pPageDict = NULL;
2935   m_pPageResource = NULL;
2936   m_docStatus = PDF_DATAAVAIL_HEADER;
2937   m_parser.m_bOwnFileRead = FALSE;
2938   m_bTotalLoadPageTree = FALSE;
2939   m_bCurPageDictLoadOK = FALSE;
2940   m_bLinearedDataOK = FALSE;
2941 }
2942 CPDF_DataAvail::~CPDF_DataAvail() {
2943   if (m_pLinearized) {
2944     m_pLinearized->Release();
2945   }
2946   if (m_pRoot) {
2947     m_pRoot->Release();
2948   }
2949   if (m_pTrailer) {
2950     m_pTrailer->Release();
2951   }
2952   int32_t i = 0;
2953   int32_t iSize = m_arrayAcroforms.GetSize();
2954   for (i = 0; i < iSize; ++i) {
2955     static_cast<CPDF_Object*>(m_arrayAcroforms.GetAt(i))->Release();
2956   }
2957 }
2958 void CPDF_DataAvail::SetDocument(CPDF_Document* pDoc) {
2959   m_pDocument = pDoc;
2960 }
2961 FX_DWORD CPDF_DataAvail::GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset) {
2962   CPDF_Parser* pParser = (CPDF_Parser*)(m_pDocument->GetParser());
2963   if (pParser == NULL) {
2964     return 0;
2965   }
2966   if (objnum >= (FX_DWORD)pParser->m_CrossRef.GetSize()) {
2967     return 0;
2968   }
2969   if (pParser->m_V5Type[objnum] == 2) {
2970     objnum = (FX_DWORD)pParser->m_CrossRef[objnum];
2971   }
2972   if (pParser->m_V5Type[objnum] == 1 || pParser->m_V5Type[objnum] == 255) {
2973     offset = pParser->m_CrossRef[objnum];
2974     if (offset == 0) {
2975       return 0;
2976     }
2977     void* pResult = FXSYS_bsearch(&offset, pParser->m_SortedOffset.GetData(),
2978                                   pParser->m_SortedOffset.GetSize(),
2979                                   sizeof(FX_FILESIZE), CompareFileSize);
2980     if (pResult == NULL) {
2981       return 0;
2982     }
2983     if ((FX_FILESIZE*)pResult -
2984             (FX_FILESIZE*)pParser->m_SortedOffset.GetData() ==
2985         pParser->m_SortedOffset.GetSize() - 1) {
2986       return 0;
2987     }
2988     return (FX_DWORD)(((FX_FILESIZE*)pResult)[1] - offset);
2989   }
2990   return 0;
2991 }
2992 FX_BOOL CPDF_DataAvail::IsObjectsAvail(CFX_PtrArray& obj_array,
2993                                        FX_BOOL bParsePage,
2994                                        IFX_DownloadHints* pHints,
2995                                        CFX_PtrArray& ret_array) {
2996   if (!obj_array.GetSize()) {
2997     return TRUE;
2998   }
2999   FX_DWORD count = 0;
3000   CFX_PtrArray new_obj_array;
3001   int32_t i = 0;
3002   for (i = 0; i < obj_array.GetSize(); i++) {
3003     CPDF_Object* pObj = static_cast<CPDF_Object*>(obj_array[i]);
3004     if (!pObj)
3005       continue;
3006
3007     int32_t type = pObj->GetType();
3008     switch (type) {
3009       case PDFOBJ_ARRAY: {
3010         CPDF_Array* pArray = pObj->GetArray();
3011         for (FX_DWORD k = 0; k < pArray->GetCount(); k++) {
3012           new_obj_array.Add(pArray->GetElement(k));
3013         }
3014       } break;
3015       case PDFOBJ_STREAM:
3016         pObj = pObj->GetDict();
3017       case PDFOBJ_DICTIONARY: {
3018         CPDF_Dictionary* pDict = pObj->GetDict();
3019         if (pDict && pDict->GetString("Type") == "Page" && !bParsePage) {
3020           continue;
3021         }
3022         FX_POSITION pos = pDict->GetStartPos();
3023         while (pos) {
3024           CPDF_Object* value;
3025           CFX_ByteString key;
3026           value = pDict->GetNextElement(pos, key);
3027           if (key != "Parent") {
3028             new_obj_array.Add(value);
3029           }
3030         }
3031       } break;
3032       case PDFOBJ_REFERENCE: {
3033         CPDF_Reference* pRef = pObj->AsReference();
3034         FX_DWORD dwNum = pRef->GetRefObjNum();
3035         FX_FILESIZE offset;
3036         FX_DWORD original_size = GetObjectSize(dwNum, offset);
3037         pdfium::base::CheckedNumeric<FX_DWORD> size = original_size;
3038         if (size.ValueOrDefault(0) == 0 || offset < 0 ||
3039             offset >= m_dwFileLen) {
3040           break;
3041         }
3042
3043         size += offset;
3044         size += 512;
3045         if (!size.IsValid()) {
3046           break;
3047         }
3048         if (size.ValueOrDie() > m_dwFileLen) {
3049           size = m_dwFileLen - offset;
3050         } else {
3051           size = original_size + 512;
3052         }
3053         if (!size.IsValid()) {
3054           break;
3055         }
3056         if (!m_pFileAvail->IsDataAvail(offset, size.ValueOrDie())) {
3057           pHints->AddSegment(offset, size.ValueOrDie());
3058           ret_array.Add(pObj);
3059           count++;
3060         } else if (!m_objnum_array.Find(dwNum)) {
3061           m_objnum_array.AddObjNum(dwNum);
3062           CPDF_Object* pReferred =
3063               m_pDocument->GetIndirectObject(pRef->GetRefObjNum(), NULL);
3064           if (pReferred) {
3065             new_obj_array.Add(pReferred);
3066           }
3067         }
3068       } break;
3069     }
3070   }
3071   if (count > 0) {
3072     int32_t iSize = new_obj_array.GetSize();
3073     for (i = 0; i < iSize; ++i) {
3074       CPDF_Object* pObj = static_cast<CPDF_Object*>(new_obj_array[i]);
3075       if (CPDF_Reference* pRef = pObj->AsReference()) {
3076         FX_DWORD dwNum = pRef->GetRefObjNum();
3077         if (!m_objnum_array.Find(dwNum))
3078           ret_array.Add(pObj);
3079       } else {
3080         ret_array.Add(pObj);
3081       }
3082     }
3083     return FALSE;
3084   }
3085   obj_array.RemoveAll();
3086   obj_array.Append(new_obj_array);
3087   return IsObjectsAvail(obj_array, FALSE, pHints, ret_array);
3088 }
3089 FX_BOOL CPDF_DataAvail::IsDocAvail(IFX_DownloadHints* pHints) {
3090   if (!m_dwFileLen && m_pFileRead) {
3091     m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize();
3092     if (!m_dwFileLen) {
3093       return TRUE;
3094     }
3095   }
3096   while (!m_bDocAvail) {
3097     if (!CheckDocStatus(pHints)) {
3098       return FALSE;
3099     }
3100   }
3101   return TRUE;
3102 }
3103 FX_BOOL CPDF_DataAvail::CheckAcroFormSubObject(IFX_DownloadHints* pHints) {
3104   if (!m_objs_array.GetSize()) {
3105     m_objs_array.RemoveAll();
3106     m_objnum_array.RemoveAll();
3107     CFX_PtrArray obj_array;
3108     obj_array.Append(m_arrayAcroforms);
3109     FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array);
3110     if (bRet) {
3111       m_objs_array.RemoveAll();
3112     }
3113     return bRet;
3114   }
3115   CFX_PtrArray new_objs_array;
3116   FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array);
3117   if (bRet) {
3118     int32_t iSize = m_arrayAcroforms.GetSize();
3119     for (int32_t i = 0; i < iSize; ++i) {
3120       static_cast<CPDF_Object*>(m_arrayAcroforms.GetAt(i))->Release();
3121     }
3122     m_arrayAcroforms.RemoveAll();
3123   } else {
3124     m_objs_array.RemoveAll();
3125     m_objs_array.Append(new_objs_array);
3126   }
3127   return bRet;
3128 }
3129 FX_BOOL CPDF_DataAvail::CheckAcroForm(IFX_DownloadHints* pHints) {
3130   FX_BOOL bExist = FALSE;
3131   m_pAcroForm = GetObject(m_dwAcroFormObjNum, pHints, &bExist);
3132   if (!bExist) {
3133     m_docStatus = PDF_DATAAVAIL_PAGETREE;
3134     return TRUE;
3135   }
3136   if (!m_pAcroForm) {
3137     if (m_docStatus == PDF_DATAAVAIL_ERROR) {
3138       m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3139       return TRUE;
3140     }
3141     return FALSE;
3142   }
3143   m_arrayAcroforms.Add(m_pAcroForm);
3144   m_docStatus = PDF_DATAAVAIL_PAGETREE;
3145   return TRUE;
3146 }
3147 FX_BOOL CPDF_DataAvail::CheckDocStatus(IFX_DownloadHints* pHints) {
3148   switch (m_docStatus) {
3149     case PDF_DATAAVAIL_HEADER:
3150       return CheckHeader(pHints);
3151     case PDF_DATAAVAIL_FIRSTPAGE:
3152     case PDF_DATAAVAIL_FIRSTPAGE_PREPARE:
3153       return CheckFirstPage(pHints);
3154     case PDF_DATAAVAIL_END:
3155       return CheckEnd(pHints);
3156     case PDF_DATAAVAIL_CROSSREF:
3157       return CheckCrossRef(pHints);
3158     case PDF_DATAAVAIL_CROSSREF_ITEM:
3159       return CheckCrossRefItem(pHints);
3160     case PDF_DATAAVAIL_CROSSREF_STREAM:
3161       return CheckAllCrossRefStream(pHints);
3162     case PDF_DATAAVAIL_TRAILER:
3163       return CheckTrailer(pHints);
3164     case PDF_DATAAVAIL_TRAILER_APPEND:
3165       return CheckTrailerAppend(pHints);
3166     case PDF_DATAAVAIL_LOADALLCRSOSSREF:
3167       return LoadAllXref(pHints);
3168     case PDF_DATAAVAIL_LOADALLFILE:
3169       return LoadAllFile(pHints);
3170     case PDF_DATAAVAIL_ROOT:
3171       return CheckRoot(pHints);
3172     case PDF_DATAAVAIL_INFO:
3173       return CheckInfo(pHints);
3174     case PDF_DATAAVAIL_ACROFORM:
3175       return CheckAcroForm(pHints);
3176     case PDF_DATAAVAIL_PAGETREE:
3177       if (m_bTotalLoadPageTree) {
3178         return CheckPages(pHints);
3179       }
3180       return LoadDocPages(pHints);
3181     case PDF_DATAAVAIL_PAGE:
3182       if (m_bTotalLoadPageTree) {
3183         return CheckPage(pHints);
3184       }
3185       m_docStatus = PDF_DATAAVAIL_PAGE_LATERLOAD;
3186       return TRUE;
3187     case PDF_DATAAVAIL_ERROR:
3188       return LoadAllFile(pHints);
3189     case PDF_DATAAVAIL_PAGE_LATERLOAD:
3190       m_docStatus = PDF_DATAAVAIL_PAGE;
3191     default:
3192       m_bDocAvail = TRUE;
3193       return TRUE;
3194   }
3195 }
3196 FX_BOOL CPDF_DataAvail::CheckPageStatus(IFX_DownloadHints* pHints) {
3197   switch (m_docStatus) {
3198     case PDF_DATAAVAIL_PAGETREE:
3199       return CheckPages(pHints);
3200     case PDF_DATAAVAIL_PAGE:
3201       return CheckPage(pHints);
3202     case PDF_DATAAVAIL_ERROR:
3203       return LoadAllFile(pHints);
3204     default:
3205       m_bPagesTreeLoad = TRUE;
3206       m_bPagesLoad = TRUE;
3207       return TRUE;
3208   }
3209 }
3210 FX_BOOL CPDF_DataAvail::LoadAllFile(IFX_DownloadHints* pHints) {
3211   if (m_pFileAvail->IsDataAvail(0, (FX_DWORD)m_dwFileLen)) {
3212     m_docStatus = PDF_DATAAVAIL_DONE;
3213     return TRUE;
3214   }
3215   pHints->AddSegment(0, (FX_DWORD)m_dwFileLen);
3216   return FALSE;
3217 }
3218 FX_BOOL CPDF_DataAvail::LoadAllXref(IFX_DownloadHints* pHints) {
3219   m_parser.m_Syntax.InitParser(m_pFileRead, (FX_DWORD)m_dwHeaderOffset);
3220   m_parser.m_bOwnFileRead = FALSE;
3221   if (!m_parser.LoadAllCrossRefV4(m_dwLastXRefOffset) &&
3222       !m_parser.LoadAllCrossRefV5(m_dwLastXRefOffset)) {
3223     m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3224     return FALSE;
3225   }
3226   FXSYS_qsort(m_parser.m_SortedOffset.GetData(),
3227               m_parser.m_SortedOffset.GetSize(), sizeof(FX_FILESIZE),
3228               CompareFileSize);
3229   m_dwRootObjNum = m_parser.GetRootObjNum();
3230   m_dwInfoObjNum = m_parser.GetInfoObjNum();
3231   m_pCurrentParser = &m_parser;
3232   m_docStatus = PDF_DATAAVAIL_ROOT;
3233   return TRUE;
3234 }
3235 CPDF_Object* CPDF_DataAvail::GetObject(FX_DWORD objnum,
3236                                        IFX_DownloadHints* pHints,
3237                                        FX_BOOL* pExistInFile) {
3238   CPDF_Object* pRet = NULL;
3239   FX_DWORD original_size = 0;
3240   FX_FILESIZE offset = 0;
3241   CPDF_Parser* pParser = NULL;
3242
3243   if (pExistInFile) {
3244     *pExistInFile = TRUE;
3245   }
3246
3247   if (m_pDocument == NULL) {
3248     original_size = (FX_DWORD)m_parser.GetObjectSize(objnum);
3249     offset = m_parser.GetObjectOffset(objnum);
3250     pParser = &m_parser;
3251   } else {
3252     original_size = GetObjectSize(objnum, offset);
3253     pParser = (CPDF_Parser*)(m_pDocument->GetParser());
3254   }
3255
3256   pdfium::base::CheckedNumeric<FX_DWORD> size = original_size;
3257   if (size.ValueOrDefault(0) == 0 || offset < 0 || offset >= m_dwFileLen) {
3258     if (pExistInFile)
3259       *pExistInFile = FALSE;
3260
3261     return NULL;
3262   }
3263
3264   size += offset;
3265   size += 512;
3266   if (!size.IsValid()) {
3267     return NULL;
3268   }
3269
3270   if (size.ValueOrDie() > m_dwFileLen) {
3271     size = m_dwFileLen - offset;
3272   } else {
3273     size = original_size + 512;
3274   }
3275
3276   if (!size.IsValid()) {
3277     return NULL;
3278   }
3279
3280   if (!m_pFileAvail->IsDataAvail(offset, size.ValueOrDie())) {
3281     pHints->AddSegment(offset, size.ValueOrDie());
3282     return NULL;
3283   }
3284
3285   if (pParser) {
3286     pRet = pParser->ParseIndirectObject(NULL, objnum, NULL);
3287   }
3288
3289   if (!pRet && pExistInFile) {
3290     *pExistInFile = FALSE;
3291   }
3292
3293   return pRet;
3294 }
3295
3296 FX_BOOL CPDF_DataAvail::CheckInfo(IFX_DownloadHints* pHints) {
3297   FX_BOOL bExist = FALSE;
3298   CPDF_Object* pInfo = GetObject(m_dwInfoObjNum, pHints, &bExist);
3299   if (!bExist) {
3300     if (m_bHaveAcroForm) {
3301       m_docStatus = PDF_DATAAVAIL_ACROFORM;
3302     } else {
3303       m_docStatus = PDF_DATAAVAIL_PAGETREE;
3304     }
3305     return TRUE;
3306   }
3307   if (!pInfo) {
3308     if (m_docStatus == PDF_DATAAVAIL_ERROR) {
3309       m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3310       return TRUE;
3311     }
3312     if (m_Pos == m_dwFileLen) {
3313       m_docStatus = PDF_DATAAVAIL_ERROR;
3314     }
3315     return FALSE;
3316   }
3317   if (pInfo) {
3318     pInfo->Release();
3319   }
3320   if (m_bHaveAcroForm) {
3321     m_docStatus = PDF_DATAAVAIL_ACROFORM;
3322   } else {
3323     m_docStatus = PDF_DATAAVAIL_PAGETREE;
3324   }
3325   return TRUE;
3326 }
3327 FX_BOOL CPDF_DataAvail::CheckRoot(IFX_DownloadHints* pHints) {
3328   FX_BOOL bExist = FALSE;
3329   m_pRoot = GetObject(m_dwRootObjNum, pHints, &bExist);
3330   if (!bExist) {
3331     m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3332     return TRUE;
3333   }
3334   if (!m_pRoot) {
3335     if (m_docStatus == PDF_DATAAVAIL_ERROR) {
3336       m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3337       return TRUE;
3338     }
3339     return FALSE;
3340   }
3341   CPDF_Dictionary* pDict = m_pRoot->GetDict();
3342   if (!pDict) {
3343     m_docStatus = PDF_DATAAVAIL_ERROR;
3344     return FALSE;
3345   }
3346   CPDF_Reference* pRef = ToReference(pDict->GetElement(FX_BSTRC("Pages")));
3347   if (!pRef) {
3348     m_docStatus = PDF_DATAAVAIL_ERROR;
3349     return FALSE;
3350   }
3351
3352   m_PagesObjNum = pRef->GetRefObjNum();
3353   CPDF_Reference* pAcroFormRef =
3354       ToReference(m_pRoot->GetDict()->GetElement(FX_BSTRC("AcroForm")));
3355   if (pAcroFormRef) {
3356     m_bHaveAcroForm = TRUE;
3357     m_dwAcroFormObjNum = pAcroFormRef->GetRefObjNum();
3358   }
3359
3360   if (m_dwInfoObjNum) {
3361     m_docStatus = PDF_DATAAVAIL_INFO;
3362   } else {
3363     m_docStatus =
3364         m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE;
3365   }
3366   return TRUE;
3367 }
3368 FX_BOOL CPDF_DataAvail::PreparePageItem() {
3369   CPDF_Dictionary* pRoot = m_pDocument->GetRoot();
3370   CPDF_Reference* pRef =
3371       ToReference(pRoot ? pRoot->GetElement(FX_BSTRC("Pages")) : nullptr);
3372   if (!pRef) {
3373     m_docStatus = PDF_DATAAVAIL_ERROR;
3374     return FALSE;
3375   }
3376
3377   m_PagesObjNum = pRef->GetRefObjNum();
3378   m_pCurrentParser = (CPDF_Parser*)m_pDocument->GetParser();
3379   m_docStatus = PDF_DATAAVAIL_PAGETREE;
3380   return TRUE;
3381 }
3382 FX_BOOL CPDF_DataAvail::IsFirstCheck(int iPage) {
3383   if (m_pageMapCheckState.find(iPage) != m_pageMapCheckState.end())
3384     return FALSE;
3385
3386   m_pageMapCheckState.insert(iPage);
3387   return TRUE;
3388 }
3389 void CPDF_DataAvail::ResetFirstCheck(int iPage) {
3390   m_pageMapCheckState.erase(iPage);
3391 }
3392 FX_BOOL CPDF_DataAvail::CheckPage(IFX_DownloadHints* pHints) {
3393   FX_DWORD iPageObjs = m_PageObjList.GetSize();
3394   CFX_DWordArray UnavailObjList;
3395   for (FX_DWORD i = 0; i < iPageObjs; ++i) {
3396     FX_DWORD dwPageObjNum = m_PageObjList.GetAt(i);
3397     FX_BOOL bExist = FALSE;
3398     CPDF_Object* pObj = GetObject(dwPageObjNum, pHints, &bExist);
3399     if (!pObj) {
3400       if (bExist) {
3401         UnavailObjList.Add(dwPageObjNum);
3402       }
3403       continue;
3404     }
3405     if (pObj->IsArray()) {
3406       CPDF_Array* pArray = pObj->GetArray();
3407       if (pArray) {
3408         int32_t iSize = pArray->GetCount();
3409         for (int32_t j = 0; j < iSize; ++j) {
3410           if (CPDF_Reference* pRef = ToReference(pArray->GetElement(j)))
3411             UnavailObjList.Add(pRef->GetRefObjNum());
3412         }
3413       }
3414     }
3415     if (!pObj->IsDictionary()) {
3416       pObj->Release();
3417       continue;
3418     }
3419     CFX_ByteString type = pObj->GetDict()->GetString(FX_BSTRC("Type"));
3420     if (type == FX_BSTRC("Pages")) {
3421       m_PagesArray.Add(pObj);
3422       continue;
3423     }
3424     pObj->Release();
3425   }
3426   m_PageObjList.RemoveAll();
3427   if (UnavailObjList.GetSize()) {
3428     m_PageObjList.Append(UnavailObjList);
3429     return FALSE;
3430   }
3431   FX_DWORD iPages = m_PagesArray.GetSize();
3432   for (FX_DWORD i = 0; i < iPages; i++) {
3433     CPDF_Object* pPages = static_cast<CPDF_Object*>(m_PagesArray.GetAt(i));
3434     if (!pPages)
3435       continue;
3436
3437     if (!GetPageKids(m_pCurrentParser, pPages)) {
3438       pPages->Release();
3439       while (++i < iPages) {
3440         pPages = static_cast<CPDF_Object*>(m_PagesArray.GetAt(i));
3441         pPages->Release();
3442       }
3443       m_PagesArray.RemoveAll();
3444       m_docStatus = PDF_DATAAVAIL_ERROR;
3445       return FALSE;
3446     }
3447     pPages->Release();
3448   }
3449   m_PagesArray.RemoveAll();
3450   if (!m_PageObjList.GetSize()) {
3451     m_docStatus = PDF_DATAAVAIL_DONE;
3452   }
3453   return TRUE;
3454 }
3455 FX_BOOL CPDF_DataAvail::GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages) {
3456   if (!pParser) {
3457     m_docStatus = PDF_DATAAVAIL_ERROR;
3458     return FALSE;
3459   }
3460   CPDF_Dictionary* pDict = pPages->GetDict();
3461   CPDF_Object* pKids = pDict ? pDict->GetElement(FX_BSTRC("Kids")) : NULL;
3462   if (!pKids) {
3463     return TRUE;
3464   }
3465   switch (pKids->GetType()) {
3466     case PDFOBJ_REFERENCE:
3467       m_PageObjList.Add(pKids->AsReference()->GetRefObjNum());
3468       break;
3469     case PDFOBJ_ARRAY: {
3470       CPDF_Array* pKidsArray = pKids->AsArray();
3471       for (FX_DWORD i = 0; i < pKidsArray->GetCount(); ++i) {
3472         if (CPDF_Reference* pRef = ToReference(pKidsArray->GetElement(i)))
3473           m_PageObjList.Add(pRef->GetRefObjNum());
3474       }
3475     } break;
3476     default:
3477       m_docStatus = PDF_DATAAVAIL_ERROR;
3478       return FALSE;
3479   }
3480   return TRUE;
3481 }
3482 FX_BOOL CPDF_DataAvail::CheckPages(IFX_DownloadHints* pHints) {
3483   FX_BOOL bExist = FALSE;
3484   CPDF_Object* pPages = GetObject(m_PagesObjNum, pHints, &bExist);
3485   if (!bExist) {
3486     m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3487     return TRUE;
3488   }
3489   if (!pPages) {
3490     if (m_docStatus == PDF_DATAAVAIL_ERROR) {
3491       m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3492       return TRUE;
3493     }
3494     return FALSE;
3495   }
3496   if (!GetPageKids(m_pCurrentParser, pPages)) {
3497     pPages->Release();
3498     m_docStatus = PDF_DATAAVAIL_ERROR;
3499     return FALSE;
3500   }
3501   pPages->Release();
3502   m_docStatus = PDF_DATAAVAIL_PAGE;
3503   return TRUE;
3504 }
3505 FX_BOOL CPDF_DataAvail::CheckHeader(IFX_DownloadHints* pHints) {
3506   FX_DWORD req_size = 1024;
3507   if ((FX_FILESIZE)req_size > m_dwFileLen) {
3508     req_size = (FX_DWORD)m_dwFileLen;
3509   }
3510   if (m_pFileAvail->IsDataAvail(0, req_size)) {
3511     uint8_t buffer[1024];
3512     m_pFileRead->ReadBlock(buffer, 0, req_size);
3513     if (IsLinearizedFile(buffer, req_size)) {
3514       m_docStatus = PDF_DATAAVAIL_FIRSTPAGE;
3515     } else {
3516       if (m_docStatus == PDF_DATAAVAIL_ERROR) {
3517         return FALSE;
3518       }
3519       m_docStatus = PDF_DATAAVAIL_END;
3520     }
3521     return TRUE;
3522   }
3523   pHints->AddSegment(0, req_size);
3524   return FALSE;
3525 }
3526 FX_BOOL CPDF_DataAvail::CheckFirstPage(IFX_DownloadHints* pHints) {
3527   CPDF_Dictionary* pDict = m_pLinearized->GetDict();
3528   CPDF_Object* pEndOffSet = pDict ? pDict->GetElement(FX_BSTRC("E")) : NULL;
3529   if (!pEndOffSet) {
3530     m_docStatus = PDF_DATAAVAIL_ERROR;
3531     return FALSE;
3532   }
3533   CPDF_Object* pXRefOffset = pDict ? pDict->GetElement(FX_BSTRC("T")) : NULL;
3534   if (!pXRefOffset) {
3535     m_docStatus = PDF_DATAAVAIL_ERROR;
3536     return FALSE;
3537   }
3538   CPDF_Object* pFileLen = pDict ? pDict->GetElement(FX_BSTRC("L")) : NULL;
3539   if (!pFileLen) {
3540     m_docStatus = PDF_DATAAVAIL_ERROR;
3541     return FALSE;
3542   }
3543   FX_BOOL bNeedDownLoad = FALSE;
3544   if (pEndOffSet->IsNumber()) {
3545     FX_DWORD dwEnd = pEndOffSet->GetInteger();
3546     dwEnd += 512;
3547     if ((FX_FILESIZE)dwEnd > m_dwFileLen) {
3548       dwEnd = (FX_DWORD)m_dwFileLen;
3549     }
3550     int32_t iStartPos = (int32_t)(m_dwFileLen > 1024 ? 1024 : m_dwFileLen);
3551     int32_t iSize = dwEnd > 1024 ? dwEnd - 1024 : 0;
3552     if (!m_pFileAvail->IsDataAvail(iStartPos, iSize)) {
3553       pHints->AddSegment(iStartPos, iSize);
3554       bNeedDownLoad = TRUE;
3555     }
3556   }
3557   m_dwLastXRefOffset = 0;
3558   FX_FILESIZE dwFileLen = 0;
3559   if (pXRefOffset->IsNumber())
3560     m_dwLastXRefOffset = pXRefOffset->GetInteger();
3561
3562   if (pFileLen->IsNumber())
3563     dwFileLen = pFileLen->GetInteger();
3564
3565   if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset,
3566                                  (FX_DWORD)(dwFileLen - m_dwLastXRefOffset))) {
3567     if (m_docStatus == PDF_DATAAVAIL_FIRSTPAGE) {
3568       FX_DWORD dwSize = (FX_DWORD)(dwFileLen - m_dwLastXRefOffset);
3569       FX_FILESIZE offset = m_dwLastXRefOffset;
3570       if (dwSize < 512 && dwFileLen > 512) {
3571         dwSize = 512;
3572         offset = dwFileLen - 512;
3573       }
3574       pHints->AddSegment(offset, dwSize);
3575     }
3576   } else {
3577     m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE;
3578   }
3579   if (!bNeedDownLoad && m_docStatus == PDF_DATAAVAIL_FIRSTPAGE_PREPARE) {
3580     m_docStatus = PDF_DATAAVAIL_DONE;
3581     return TRUE;
3582   }
3583   m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE;
3584   return FALSE;
3585 }
3586 CPDF_Object* CPDF_DataAvail::ParseIndirectObjectAt(FX_FILESIZE pos,
3587                                                    FX_DWORD objnum) {
3588   FX_FILESIZE SavedPos = m_syntaxParser.SavePos();
3589   m_syntaxParser.RestorePos(pos);
3590   FX_BOOL bIsNumber;
3591   CFX_ByteString word = m_syntaxParser.GetNextWord(bIsNumber);
3592   if (!bIsNumber) {
3593     return NULL;
3594   }
3595   FX_DWORD parser_objnum = FXSYS_atoi(word);
3596   if (objnum && parser_objnum != objnum) {
3597     return NULL;
3598   }
3599   word = m_syntaxParser.GetNextWord(bIsNumber);
3600   if (!bIsNumber) {
3601     return NULL;
3602   }
3603   FX_DWORD gennum = FXSYS_atoi(word);
3604   if (m_syntaxParser.GetKeyword() != FX_BSTRC("obj")) {
3605     m_syntaxParser.RestorePos(SavedPos);
3606     return NULL;
3607   }
3608   CPDF_Object* pObj = m_syntaxParser.GetObject(NULL, objnum, gennum, 0);
3609   m_syntaxParser.RestorePos(SavedPos);
3610   return pObj;
3611 }
3612 int32_t CPDF_DataAvail::IsLinearizedPDF() {
3613   FX_DWORD req_size = 1024;
3614   if (!m_pFileAvail->IsDataAvail(0, req_size)) {
3615     return PDF_UNKNOW_LINEARIZED;
3616   }
3617   if (!m_pFileRead) {
3618     return PDF_NOT_LINEARIZED;
3619   }
3620   FX_FILESIZE dwSize = m_pFileRead->GetSize();
3621   if (dwSize < (FX_FILESIZE)req_size) {
3622     return PDF_UNKNOW_LINEARIZED;
3623   }
3624   uint8_t buffer[1024];
3625   m_pFileRead->ReadBlock(buffer, 0, req_size);
3626   if (IsLinearizedFile(buffer, req_size)) {
3627     return PDF_IS_LINEARIZED;
3628   }
3629   return PDF_NOT_LINEARIZED;
3630 }
3631 FX_BOOL CPDF_DataAvail::IsLinearizedFile(uint8_t* pData, FX_DWORD dwLen) {
3632   ScopedFileStream file(FX_CreateMemoryStream(pData, (size_t)dwLen, FALSE));
3633   int32_t offset = GetHeaderOffset(file.get());
3634   if (offset == -1) {
3635     m_docStatus = PDF_DATAAVAIL_ERROR;
3636     return FALSE;
3637   }
3638   m_dwHeaderOffset = offset;
3639   m_syntaxParser.InitParser(file.get(), offset);
3640   m_syntaxParser.RestorePos(m_syntaxParser.m_HeaderOffset + 9);
3641   FX_BOOL bNumber = FALSE;
3642   CFX_ByteString wordObjNum = m_syntaxParser.GetNextWord(bNumber);
3643   if (!bNumber) {
3644     return FALSE;
3645   }
3646   FX_DWORD objnum = FXSYS_atoi(wordObjNum);
3647   if (m_pLinearized) {
3648     m_pLinearized->Release();
3649     m_pLinearized = NULL;
3650   }
3651   m_pLinearized =
3652       ParseIndirectObjectAt(m_syntaxParser.m_HeaderOffset + 9, objnum);
3653   if (!m_pLinearized) {
3654     return FALSE;
3655   }
3656
3657   CPDF_Dictionary* pDict = m_pLinearized->GetDict();
3658   if (pDict && pDict->GetElement(FX_BSTRC("Linearized"))) {
3659     CPDF_Object* pLen = pDict->GetElement(FX_BSTRC("L"));
3660     if (!pLen) {
3661       return FALSE;
3662     }
3663     if ((FX_FILESIZE)pLen->GetInteger() != m_pFileRead->GetSize()) {
3664       return FALSE;
3665     }
3666     m_bLinearized = TRUE;
3667
3668     if (CPDF_Number* pNo = ToNumber(pDict->GetElement(FX_BSTRC("P"))))
3669       m_dwFirstPageNo = pNo->GetInteger();
3670
3671     return TRUE;
3672   }
3673   return FALSE;
3674 }
3675 FX_BOOL CPDF_DataAvail::CheckEnd(IFX_DownloadHints* pHints) {
3676   FX_DWORD req_pos = (FX_DWORD)(m_dwFileLen > 1024 ? m_dwFileLen - 1024 : 0);
3677   FX_DWORD dwSize = (FX_DWORD)(m_dwFileLen - req_pos);
3678   if (m_pFileAvail->IsDataAvail(req_pos, dwSize)) {
3679     uint8_t buffer[1024];
3680     m_pFileRead->ReadBlock(buffer, req_pos, dwSize);
3681     ScopedFileStream file(FX_CreateMemoryStream(buffer, (size_t)dwSize, FALSE));
3682     m_syntaxParser.InitParser(file.get(), 0);
3683     m_syntaxParser.RestorePos(dwSize - 1);
3684     if (m_syntaxParser.SearchWord(FX_BSTRC("startxref"), TRUE, FALSE, dwSize)) {
3685       FX_BOOL bNumber;
3686       m_syntaxParser.GetNextWord(bNumber);
3687       CFX_ByteString xrefpos_str = m_syntaxParser.GetNextWord(bNumber);
3688       if (!bNumber) {
3689         m_docStatus = PDF_DATAAVAIL_ERROR;
3690         return FALSE;
3691       }
3692       m_dwXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str);
3693       if (!m_dwXRefOffset || m_dwXRefOffset > m_dwFileLen) {
3694         m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3695         return TRUE;
3696       }
3697       m_dwLastXRefOffset = m_dwXRefOffset;
3698       SetStartOffset(m_dwXRefOffset);
3699       m_docStatus = PDF_DATAAVAIL_CROSSREF;
3700       return TRUE;
3701     }
3702     m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3703     return TRUE;
3704   }
3705   pHints->AddSegment(req_pos, dwSize);
3706   return FALSE;
3707 }
3708 int32_t CPDF_DataAvail::CheckCrossRefStream(IFX_DownloadHints* pHints,
3709                                             FX_FILESIZE& xref_offset) {
3710   xref_offset = 0;
3711   FX_DWORD req_size =
3712       (FX_DWORD)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512);
3713   if (m_pFileAvail->IsDataAvail(m_Pos, req_size)) {
3714     int32_t iSize = (int32_t)(m_Pos + req_size - m_dwCurrentXRefSteam);
3715     CFX_BinaryBuf buf(iSize);
3716     uint8_t* pBuf = buf.GetBuffer();
3717     m_pFileRead->ReadBlock(pBuf, m_dwCurrentXRefSteam, iSize);
3718     ScopedFileStream file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE));
3719     m_parser.m_Syntax.InitParser(file.get(), 0);
3720     FX_BOOL bNumber = FALSE;
3721     CFX_ByteString objnum = m_parser.m_Syntax.GetNextWord(bNumber);
3722     if (!bNumber) {
3723       return -1;
3724     }
3725     FX_DWORD objNum = FXSYS_atoi(objnum);
3726     CPDF_Object* pObj = m_parser.ParseIndirectObjectAt(NULL, 0, objNum, NULL);
3727     if (!pObj) {
3728       m_Pos += m_parser.m_Syntax.SavePos();
3729       return 0;
3730     }
3731     CPDF_Dictionary* pDict = pObj->GetDict();
3732     CPDF_Name* pName =
3733         ToName(pDict ? pDict->GetElement(FX_BSTRC("Type")) : nullptr);
3734     if (pName) {
3735       if (pName->GetString() == FX_BSTRC("XRef")) {
3736         m_Pos += m_parser.m_Syntax.SavePos();
3737         xref_offset = pObj->GetDict()->GetInteger(FX_BSTRC("Prev"));
3738         pObj->Release();
3739         return 1;
3740       }
3741     }
3742     pObj->Release();
3743     return -1;
3744   }
3745   pHints->AddSegment(m_Pos, req_size);
3746   return 0;
3747 }
3748 inline void CPDF_DataAvail::SetStartOffset(FX_FILESIZE dwOffset) {
3749   m_Pos = dwOffset;
3750 }
3751 #define MAX_WORD_BUFFER 256
3752 FX_BOOL CPDF_DataAvail::GetNextToken(CFX_ByteString& token) {
3753   m_WordSize = 0;
3754   uint8_t ch;
3755   if (!GetNextChar(ch))
3756     return FALSE;
3757
3758   while (1) {
3759     while (PDFCharIsWhitespace(ch)) {
3760       if (!GetNextChar(ch))
3761         return FALSE;
3762     }
3763
3764     if (ch != '%')
3765       break;
3766
3767     while (1) {
3768       if (!GetNextChar(ch))
3769         return FALSE;
3770       if (PDFCharIsLineEnding(ch))
3771         break;
3772     }
3773   }
3774
3775   if (PDFCharIsDelimiter(ch)) {
3776     m_WordBuffer[m_WordSize++] = ch;
3777     if (ch == '/') {
3778       while (1) {
3779         if (!GetNextChar(ch))
3780           return FALSE;
3781
3782         if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) {
3783           m_Pos--;
3784           CFX_ByteString ret(m_WordBuffer, m_WordSize);
3785           token = ret;
3786           return TRUE;
3787         }
3788
3789         if (m_WordSize < MAX_WORD_BUFFER)
3790           m_WordBuffer[m_WordSize++] = ch;
3791       }
3792     } else if (ch == '<') {
3793       if (!GetNextChar(ch))
3794         return FALSE;
3795
3796       if (ch == '<')
3797         m_WordBuffer[m_WordSize++] = ch;
3798       else
3799         m_Pos--;
3800     } else if (ch == '>') {
3801       if (!GetNextChar(ch))
3802         return FALSE;
3803
3804       if (ch == '>')
3805         m_WordBuffer[m_WordSize++] = ch;
3806       else
3807         m_Pos--;
3808     }
3809
3810     CFX_ByteString ret(m_WordBuffer, m_WordSize);
3811     token = ret;
3812     return TRUE;
3813   }
3814
3815   while (1) {
3816     if (m_WordSize < MAX_WORD_BUFFER)
3817       m_WordBuffer[m_WordSize++] = ch;
3818
3819     if (!GetNextChar(ch))
3820       return FALSE;
3821
3822     if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) {
3823       m_Pos--;
3824       break;
3825     }
3826   }
3827
3828   CFX_ByteString ret(m_WordBuffer, m_WordSize);
3829   token = ret;
3830   return TRUE;
3831 }
3832 FX_BOOL CPDF_DataAvail::GetNextChar(uint8_t& ch) {
3833   FX_FILESIZE pos = m_Pos;
3834   if (pos >= m_dwFileLen) {
3835     return FALSE;
3836   }
3837   if (m_bufferOffset >= pos ||
3838       (FX_FILESIZE)(m_bufferOffset + m_bufferSize) <= pos) {
3839     FX_FILESIZE read_pos = pos;
3840     FX_DWORD read_size = 512;
3841     if ((FX_FILESIZE)read_size > m_dwFileLen) {
3842       read_size = (FX_DWORD)m_dwFileLen;
3843     }
3844     if ((FX_FILESIZE)(read_pos + read_size) > m_dwFileLen) {
3845       read_pos = m_dwFileLen - read_size;
3846     }
3847     if (!m_pFileRead->ReadBlock(m_bufferData, read_pos, read_size)) {
3848       return FALSE;
3849     }
3850     m_bufferOffset = read_pos;
3851     m_bufferSize = read_size;
3852   }
3853   ch = m_bufferData[pos - m_bufferOffset];
3854   m_Pos++;
3855   return TRUE;
3856 }
3857 FX_BOOL CPDF_DataAvail::CheckCrossRefItem(IFX_DownloadHints* pHints) {
3858   int32_t iSize = 0;
3859   CFX_ByteString token;
3860   while (1) {
3861     if (!GetNextToken(token)) {
3862       iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512);
3863       pHints->AddSegment(m_Pos, iSize);
3864       return FALSE;
3865     }
3866     if (token == "trailer") {
3867       m_dwTrailerOffset = m_Pos;
3868       m_docStatus = PDF_DATAAVAIL_TRAILER;
3869       return TRUE;
3870     }
3871   }
3872 }
3873 FX_BOOL CPDF_DataAvail::CheckAllCrossRefStream(IFX_DownloadHints* pHints) {
3874   FX_FILESIZE xref_offset = 0;
3875   int32_t nRet = CheckCrossRefStream(pHints, xref_offset);
3876   if (nRet == 1) {
3877     if (!xref_offset) {
3878       m_docStatus = PDF_DATAAVAIL_LOADALLCRSOSSREF;
3879     } else {
3880       m_dwCurrentXRefSteam = xref_offset;
3881       m_Pos = xref_offset;
3882     }
3883     return TRUE;
3884   }
3885   if (nRet == -1) {
3886     m_docStatus = PDF_DATAAVAIL_ERROR;
3887   }
3888   return FALSE;
3889 }
3890 FX_BOOL CPDF_DataAvail::CheckCrossRef(IFX_DownloadHints* pHints) {
3891   int32_t iSize = 0;
3892   CFX_ByteString token;
3893   if (!GetNextToken(token)) {
3894     iSize = (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512);
3895     pHints->AddSegment(m_Pos, iSize);
3896     return FALSE;
3897   }
3898   if (token == "xref") {
3899     m_CrossOffset.InsertAt(0, m_dwXRefOffset);
3900     while (1) {
3901       if (!GetNextToken(token)) {
3902         iSize =
3903             (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512);
3904         pHints->AddSegment(m_Pos, iSize);
3905         m_docStatus = PDF_DATAAVAIL_CROSSREF_ITEM;
3906         return FALSE;
3907       }
3908       if (token == "trailer") {
3909         m_dwTrailerOffset = m_Pos;
3910         m_docStatus = PDF_DATAAVAIL_TRAILER;
3911         return TRUE;
3912       }
3913     }
3914   } else {
3915     m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3916     return TRUE;
3917   }
3918   return FALSE;
3919 }
3920 FX_BOOL CPDF_DataAvail::CheckTrailerAppend(IFX_DownloadHints* pHints) {
3921   if (m_Pos < m_dwFileLen) {
3922     FX_FILESIZE dwAppendPos = m_Pos + m_syntaxParser.SavePos();
3923     int32_t iSize = (int32_t)(
3924         dwAppendPos + 512 > m_dwFileLen ? m_dwFileLen - dwAppendPos : 512);
3925     if (!m_pFileAvail->IsDataAvail(dwAppendPos, iSize)) {
3926       pHints->AddSegment(dwAppendPos, iSize);
3927       return FALSE;
3928     }
3929   }
3930   if (m_dwPrevXRefOffset) {
3931     SetStartOffset(m_dwPrevXRefOffset);
3932     m_docStatus = PDF_DATAAVAIL_CROSSREF;
3933   } else {
3934     m_docStatus = PDF_DATAAVAIL_LOADALLCRSOSSREF;
3935   }
3936   return TRUE;
3937 }
3938
3939 FX_BOOL CPDF_DataAvail::CheckTrailer(IFX_DownloadHints* pHints) {
3940   int32_t iTrailerSize =
3941       (int32_t)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512);
3942   if (m_pFileAvail->IsDataAvail(m_Pos, iTrailerSize)) {
3943     int32_t iSize = (int32_t)(m_Pos + iTrailerSize - m_dwTrailerOffset);
3944     CFX_BinaryBuf buf(iSize);
3945     uint8_t* pBuf = buf.GetBuffer();
3946     if (!pBuf) {
3947       m_docStatus = PDF_DATAAVAIL_ERROR;
3948       return FALSE;
3949     }
3950     if (!m_pFileRead->ReadBlock(pBuf, m_dwTrailerOffset, iSize)) {
3951       return FALSE;
3952     }