Remove usage of std::vector::data
[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 (PDF_CharType[byte] == 'W') {
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 (PDF_CharType[byte] == 'W') {
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 (PDF_CharType[byte] == 'W') {
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 (PDF_CharType[byte] == 'W') {
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 (PDF_CharType[byte] == 'W') {
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 (PDF_CharType[byte] == 'W') {
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 (PDF_CharType[byte] == 'W' || PDF_CharType[byte] == 'D') {
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 (PDF_CharType[byte] == 'W' || PDF_CharType[byte] == 'D') {
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 (PDF_CharType[byte] == 'D' || PDF_CharType[byte] == 'W') {
941             --i;
942             status = 0;
943           }
944           break;
945         case 14:
946           if (PDF_CharType[byte] == 'W') {
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   int32_t type = PDF_CharType[ch];
1650   while (type == 'W') {
1651     ++dwCount;
1652     if (m_Syntax.m_FileLen >=
1653         (FX_FILESIZE)(m_Syntax.SavePos() + m_Syntax.m_HeaderOffset)) {
1654       break;
1655     }
1656     m_Syntax.GetNextChar(ch);
1657     type = PDF_CharType[ch];
1658   }
1659   m_LastXRefOffset += dwCount;
1660   FX_POSITION pos = m_ObjectStreamMap.GetStartPosition();
1661   while (pos) {
1662     void* objnum;
1663     CPDF_StreamAcc* pStream;
1664     m_ObjectStreamMap.GetNextAssoc(pos, objnum, (void*&)pStream);
1665     delete pStream;
1666   }
1667   m_ObjectStreamMap.RemoveAll();
1668   if (!LoadLinearizedAllCrossRefV4(m_LastXRefOffset, m_dwXrefStartObjNum) &&
1669       !LoadLinearizedAllCrossRefV5(m_LastXRefOffset)) {
1670     m_LastXRefOffset = 0;
1671     m_Syntax.m_MetadataObjnum = dwSaveMetadataObjnum;
1672     return PDFPARSE_ERROR_FORMAT;
1673   }
1674   FXSYS_qsort(m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
1675               sizeof(FX_FILESIZE), CompareFileSize);
1676   m_Syntax.m_MetadataObjnum = dwSaveMetadataObjnum;
1677   return PDFPARSE_ERROR_SUCCESS;
1678 }
1679
1680 // static
1681 int CPDF_SyntaxParser::s_CurrentRecursionDepth = 0;
1682
1683 CPDF_SyntaxParser::CPDF_SyntaxParser() {
1684   m_pFileAccess = NULL;
1685   m_pFileBuf = NULL;
1686   m_BufSize = CPDF_ModuleMgr::kFileBufSize;
1687   m_pFileBuf = NULL;
1688   m_MetadataObjnum = 0;
1689   m_dwWordPos = 0;
1690   m_bFileStream = FALSE;
1691 }
1692 CPDF_SyntaxParser::~CPDF_SyntaxParser() {
1693   FX_Free(m_pFileBuf);
1694 }
1695
1696 FX_BOOL CPDF_SyntaxParser::GetCharAt(FX_FILESIZE pos, uint8_t& ch) {
1697   CFX_AutoRestorer<FX_FILESIZE> save_pos(&m_Pos);
1698   m_Pos = pos;
1699   return GetNextChar(ch);
1700 }
1701
1702 FX_BOOL CPDF_SyntaxParser::GetNextChar(uint8_t& ch) {
1703   FX_FILESIZE pos = m_Pos + m_HeaderOffset;
1704   if (pos >= m_FileLen) {
1705     return FALSE;
1706   }
1707   if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) {
1708     FX_FILESIZE read_pos = pos;
1709     FX_DWORD read_size = m_BufSize;
1710     if ((FX_FILESIZE)read_size > m_FileLen) {
1711       read_size = (FX_DWORD)m_FileLen;
1712     }
1713     if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) {
1714       if (m_FileLen < (FX_FILESIZE)read_size) {
1715         read_pos = 0;
1716         read_size = (FX_DWORD)m_FileLen;
1717       } else {
1718         read_pos = m_FileLen - read_size;
1719       }
1720     }
1721     if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size)) {
1722       return FALSE;
1723     }
1724     m_BufOffset = read_pos;
1725   }
1726   ch = m_pFileBuf[pos - m_BufOffset];
1727   m_Pos++;
1728   return TRUE;
1729 }
1730 FX_BOOL CPDF_SyntaxParser::GetCharAtBackward(FX_FILESIZE pos, uint8_t& ch) {
1731   pos += m_HeaderOffset;
1732   if (pos >= m_FileLen) {
1733     return FALSE;
1734   }
1735   if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) {
1736     FX_FILESIZE read_pos;
1737     if (pos < (FX_FILESIZE)m_BufSize) {
1738       read_pos = 0;
1739     } else {
1740       read_pos = pos - m_BufSize + 1;
1741     }
1742     FX_DWORD read_size = m_BufSize;
1743     if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) {
1744       if (m_FileLen < (FX_FILESIZE)read_size) {
1745         read_pos = 0;
1746         read_size = (FX_DWORD)m_FileLen;
1747       } else {
1748         read_pos = m_FileLen - read_size;
1749       }
1750     }
1751     if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size)) {
1752       return FALSE;
1753     }
1754     m_BufOffset = read_pos;
1755   }
1756   ch = m_pFileBuf[pos - m_BufOffset];
1757   return TRUE;
1758 }
1759 FX_BOOL CPDF_SyntaxParser::ReadBlock(uint8_t* pBuf, FX_DWORD size) {
1760   if (!m_pFileAccess->ReadBlock(pBuf, m_Pos + m_HeaderOffset, size)) {
1761     return FALSE;
1762   }
1763   m_Pos += size;
1764   return TRUE;
1765 }
1766 #define MAX_WORD_BUFFER 256
1767 void CPDF_SyntaxParser::GetNextWord() {
1768   m_WordSize = 0;
1769   m_bIsNumber = TRUE;
1770   uint8_t ch;
1771   if (!GetNextChar(ch)) {
1772     return;
1773   }
1774   uint8_t type = PDF_CharType[ch];
1775   while (1) {
1776     while (type == 'W') {
1777       if (!GetNextChar(ch)) {
1778         return;
1779       }
1780       type = PDF_CharType[ch];
1781     }
1782     if (ch != '%') {
1783       break;
1784     }
1785     while (1) {
1786       if (!GetNextChar(ch)) {
1787         return;
1788       }
1789       if (ch == '\r' || ch == '\n') {
1790         break;
1791       }
1792     }
1793     type = PDF_CharType[ch];
1794   }
1795   if (type == 'D') {
1796     m_bIsNumber = FALSE;
1797     m_WordBuffer[m_WordSize++] = ch;
1798     if (ch == '/') {
1799       while (1) {
1800         if (!GetNextChar(ch)) {
1801           return;
1802         }
1803         type = PDF_CharType[ch];
1804         if (type != 'R' && type != 'N') {
1805           m_Pos--;
1806           return;
1807         }
1808         if (m_WordSize < MAX_WORD_BUFFER) {
1809           m_WordBuffer[m_WordSize++] = ch;
1810         }
1811       }
1812     } else if (ch == '<') {
1813       if (!GetNextChar(ch)) {
1814         return;
1815       }
1816       if (ch == '<') {
1817         m_WordBuffer[m_WordSize++] = ch;
1818       } else {
1819         m_Pos--;
1820       }
1821     } else if (ch == '>') {
1822       if (!GetNextChar(ch)) {
1823         return;
1824       }
1825       if (ch == '>') {
1826         m_WordBuffer[m_WordSize++] = ch;
1827       } else {
1828         m_Pos--;
1829       }
1830     }
1831     return;
1832   }
1833   while (1) {
1834     if (m_WordSize < MAX_WORD_BUFFER) {
1835       m_WordBuffer[m_WordSize++] = ch;
1836     }
1837     if (type != 'N') {
1838       m_bIsNumber = FALSE;
1839     }
1840     if (!GetNextChar(ch)) {
1841       return;
1842     }
1843     type = PDF_CharType[ch];
1844     if (type == 'D' || type == 'W') {
1845       m_Pos--;
1846       break;
1847     }
1848   }
1849 }
1850 CFX_ByteString CPDF_SyntaxParser::ReadString() {
1851   uint8_t ch;
1852   if (!GetNextChar(ch)) {
1853     return CFX_ByteString();
1854   }
1855   CFX_ByteTextBuf buf;
1856   int32_t parlevel = 0;
1857   int32_t status = 0, iEscCode = 0;
1858   while (1) {
1859     switch (status) {
1860       case 0:
1861         if (ch == ')') {
1862           if (parlevel == 0) {
1863             return buf.GetByteString();
1864           }
1865           parlevel--;
1866           buf.AppendChar(')');
1867         } else if (ch == '(') {
1868           parlevel++;
1869           buf.AppendChar('(');
1870         } else if (ch == '\\') {
1871           status = 1;
1872         } else {
1873           buf.AppendChar(ch);
1874         }
1875         break;
1876       case 1:
1877         if (ch >= '0' && ch <= '7') {
1878           iEscCode = ch - '0';
1879           status = 2;
1880           break;
1881         }
1882         if (ch == 'n') {
1883           buf.AppendChar('\n');
1884         } else if (ch == 'r') {
1885           buf.AppendChar('\r');
1886         } else if (ch == 't') {
1887           buf.AppendChar('\t');
1888         } else if (ch == 'b') {
1889           buf.AppendChar('\b');
1890         } else if (ch == 'f') {
1891           buf.AppendChar('\f');
1892         } else if (ch == '\r') {
1893           status = 4;
1894           break;
1895         } else if (ch == '\n') {
1896         } else {
1897           buf.AppendChar(ch);
1898         }
1899         status = 0;
1900         break;
1901       case 2:
1902         if (ch >= '0' && ch <= '7') {
1903           iEscCode = iEscCode * 8 + ch - '0';
1904           status = 3;
1905         } else {
1906           buf.AppendChar(iEscCode);
1907           status = 0;
1908           continue;
1909         }
1910         break;
1911       case 3:
1912         if (ch >= '0' && ch <= '7') {
1913           iEscCode = iEscCode * 8 + ch - '0';
1914           buf.AppendChar(iEscCode);
1915           status = 0;
1916         } else {
1917           buf.AppendChar(iEscCode);
1918           status = 0;
1919           continue;
1920         }
1921         break;
1922       case 4:
1923         status = 0;
1924         if (ch != '\n') {
1925           continue;
1926         }
1927         break;
1928     }
1929     if (!GetNextChar(ch)) {
1930       break;
1931     }
1932   }
1933   GetNextChar(ch);
1934   return buf.GetByteString();
1935 }
1936 CFX_ByteString CPDF_SyntaxParser::ReadHexString() {
1937   uint8_t ch;
1938   if (!GetNextChar(ch)) {
1939     return CFX_ByteString();
1940   }
1941   CFX_BinaryBuf buf;
1942   FX_BOOL bFirst = TRUE;
1943   uint8_t code = 0;
1944   while (1) {
1945     if (ch == '>') {
1946       break;
1947     }
1948     if (ch >= '0' && ch <= '9') {
1949       if (bFirst) {
1950         code = (ch - '0') * 16;
1951       } else {
1952         code += ch - '0';
1953         buf.AppendByte((uint8_t)code);
1954       }
1955       bFirst = !bFirst;
1956     } else if (ch >= 'A' && ch <= 'F') {
1957       if (bFirst) {
1958         code = (ch - 'A' + 10) * 16;
1959       } else {
1960         code += ch - 'A' + 10;
1961         buf.AppendByte((uint8_t)code);
1962       }
1963       bFirst = !bFirst;
1964     } else if (ch >= 'a' && ch <= 'f') {
1965       if (bFirst) {
1966         code = (ch - 'a' + 10) * 16;
1967       } else {
1968         code += ch - 'a' + 10;
1969         buf.AppendByte((uint8_t)code);
1970       }
1971       bFirst = !bFirst;
1972     }
1973     if (!GetNextChar(ch)) {
1974       break;
1975     }
1976   }
1977   if (!bFirst) {
1978     buf.AppendByte((uint8_t)code);
1979   }
1980   return buf.GetByteString();
1981 }
1982 void CPDF_SyntaxParser::ToNextLine() {
1983   uint8_t ch;
1984   while (GetNextChar(ch)) {
1985     if (ch == '\n') {
1986       break;
1987     }
1988     if (ch == '\r') {
1989       GetNextChar(ch);
1990       if (ch != '\n') {
1991         --m_Pos;
1992       }
1993       break;
1994     }
1995   }
1996 }
1997 void CPDF_SyntaxParser::ToNextWord() {
1998   uint8_t ch;
1999   if (!GetNextChar(ch)) {
2000     return;
2001   }
2002   uint8_t type = PDF_CharType[ch];
2003   while (1) {
2004     while (type == 'W') {
2005       m_dwWordPos = m_Pos;
2006       if (!GetNextChar(ch)) {
2007         return;
2008       }
2009       type = PDF_CharType[ch];
2010     }
2011     if (ch != '%') {
2012       break;
2013     }
2014     while (1) {
2015       if (!GetNextChar(ch)) {
2016         return;
2017       }
2018       if (ch == '\r' || ch == '\n') {
2019         break;
2020       }
2021     }
2022     type = PDF_CharType[ch];
2023   }
2024   m_Pos--;
2025 }
2026 CFX_ByteString CPDF_SyntaxParser::GetNextWord(FX_BOOL& bIsNumber) {
2027   GetNextWord();
2028   bIsNumber = m_bIsNumber;
2029   return CFX_ByteString((const FX_CHAR*)m_WordBuffer, m_WordSize);
2030 }
2031 CFX_ByteString CPDF_SyntaxParser::GetKeyword() {
2032   GetNextWord();
2033   return CFX_ByteString((const FX_CHAR*)m_WordBuffer, m_WordSize);
2034 }
2035 CPDF_Object* CPDF_SyntaxParser::GetObject(CPDF_IndirectObjects* pObjList,
2036                                           FX_DWORD objnum,
2037                                           FX_DWORD gennum,
2038                                           PARSE_CONTEXT* pContext,
2039                                           FX_BOOL bDecrypt) {
2040   CFX_AutoRestorer<int> restorer(&s_CurrentRecursionDepth);
2041   if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth) {
2042     return NULL;
2043   }
2044   FX_FILESIZE SavedPos = m_Pos;
2045   FX_BOOL bTypeOnly = pContext && (pContext->m_Flags & PDFPARSE_TYPEONLY);
2046   FX_BOOL bIsNumber;
2047   CFX_ByteString word = GetNextWord(bIsNumber);
2048   if (word.GetLength() == 0) {
2049     if (bTypeOnly) {
2050       return (CPDF_Object*)PDFOBJ_INVALID;
2051     }
2052     return NULL;
2053   }
2054   if (bIsNumber) {
2055     FX_FILESIZE SavedPos = m_Pos;
2056     CFX_ByteString nextword = GetNextWord(bIsNumber);
2057     if (bIsNumber) {
2058       CFX_ByteString nextword2 = GetNextWord(bIsNumber);
2059       if (nextword2 == FX_BSTRC("R")) {
2060         FX_DWORD objnum = FXSYS_atoi(word);
2061         if (bTypeOnly) {
2062           return (CPDF_Object*)PDFOBJ_REFERENCE;
2063         }
2064         return new CPDF_Reference(pObjList, objnum);
2065       }
2066     }
2067     m_Pos = SavedPos;
2068     if (bTypeOnly) {
2069       return (CPDF_Object*)PDFOBJ_NUMBER;
2070     }
2071     return CPDF_Number::Create(word);
2072   }
2073   if (word == FX_BSTRC("true") || word == FX_BSTRC("false")) {
2074     if (bTypeOnly) {
2075       return (CPDF_Object*)PDFOBJ_BOOLEAN;
2076     }
2077     return CPDF_Boolean::Create(word == FX_BSTRC("true"));
2078   }
2079   if (word == FX_BSTRC("null")) {
2080     if (bTypeOnly) {
2081       return (CPDF_Object*)PDFOBJ_NULL;
2082     }
2083     return CPDF_Null::Create();
2084   }
2085   if (word == FX_BSTRC("(")) {
2086     if (bTypeOnly) {
2087       return (CPDF_Object*)PDFOBJ_STRING;
2088     }
2089     CFX_ByteString str = ReadString();
2090     if (m_pCryptoHandler && bDecrypt) {
2091       m_pCryptoHandler->Decrypt(objnum, gennum, str);
2092     }
2093     return CPDF_String::Create(str, FALSE);
2094   }
2095   if (word == FX_BSTRC("<")) {
2096     if (bTypeOnly) {
2097       return (CPDF_Object*)PDFOBJ_STRING;
2098     }
2099     CFX_ByteString str = ReadHexString();
2100     if (m_pCryptoHandler && bDecrypt) {
2101       m_pCryptoHandler->Decrypt(objnum, gennum, str);
2102     }
2103     return CPDF_String::Create(str, TRUE);
2104   }
2105   if (word == FX_BSTRC("[")) {
2106     if (bTypeOnly) {
2107       return (CPDF_Object*)PDFOBJ_ARRAY;
2108     }
2109     CPDF_Array* pArray = CPDF_Array::Create();
2110     while (CPDF_Object* pObj = GetObject(pObjList, objnum, gennum))
2111       pArray->Add(pObj);
2112
2113     return pArray;
2114   }
2115   if (word[0] == '/') {
2116     if (bTypeOnly) {
2117       return (CPDF_Object*)PDFOBJ_NAME;
2118     }
2119     return CPDF_Name::Create(
2120         PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)));
2121   }
2122   if (word == FX_BSTRC("<<")) {
2123     if (bTypeOnly)
2124       return (CPDF_Object*)PDFOBJ_DICTIONARY;
2125
2126     if (pContext)
2127       pContext->m_DictStart = SavedPos;
2128
2129     int32_t nKeys = 0;
2130     FX_FILESIZE dwSignValuePos = 0;
2131     nonstd::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>> pDict(
2132         CPDF_Dictionary::Create());
2133     while (1) {
2134       FX_BOOL bIsNumber;
2135       CFX_ByteString key = GetNextWord(bIsNumber);
2136       if (key.IsEmpty())
2137         return nullptr;
2138
2139       FX_FILESIZE SavedPos = m_Pos - key.GetLength();
2140       if (key == FX_BSTRC(">>"))
2141         break;
2142
2143       if (key == FX_BSTRC("endobj")) {
2144         m_Pos = SavedPos;
2145         break;
2146       }
2147       if (key[0] != '/')
2148         continue;
2149
2150       ++nKeys;
2151       key = PDF_NameDecode(key);
2152       if (key.IsEmpty())
2153         continue;
2154
2155       CFX_ByteStringC keyNoSlash(key.c_str() + 1, key.GetLength() - 1);
2156       if (keyNoSlash.IsEmpty())
2157         continue;
2158
2159       if (key == FX_BSTRC("/Contents"))
2160         dwSignValuePos = m_Pos;
2161
2162       CPDF_Object* pObj = GetObject(pObjList, objnum, gennum);
2163       if (!pObj)
2164         continue;
2165
2166       // TODO(thestig): Remove this conditional once CPDF_Dictionary has a
2167       // better underlying map implementation.
2168       if (nKeys < 32) {
2169         pDict->SetAt(keyNoSlash, pObj);
2170       } else {
2171         pDict->AddValue(keyNoSlash, pObj);
2172       }
2173     }
2174
2175     if (IsSignatureDict(pDict.get())) {
2176       FX_FILESIZE dwSavePos = m_Pos;
2177       m_Pos = dwSignValuePos;
2178       CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, NULL, FALSE);
2179       pDict->SetAt(FX_BSTRC("Contents"), pObj);
2180       m_Pos = dwSavePos;
2181     }
2182     if (pContext) {
2183       pContext->m_DictEnd = m_Pos;
2184       if (pContext->m_Flags & PDFPARSE_NOSTREAM) {
2185         return pDict.release();
2186       }
2187     }
2188     FX_FILESIZE SavedPos = m_Pos;
2189     FX_BOOL bIsNumber;
2190     CFX_ByteString nextword = GetNextWord(bIsNumber);
2191     if (nextword != FX_BSTRC("stream")) {
2192       m_Pos = SavedPos;
2193       return pDict.release();
2194     }
2195
2196     return ReadStream(pDict.release(), pContext, objnum, gennum);
2197   }
2198   if (word == FX_BSTRC(">>")) {
2199     m_Pos = SavedPos;
2200     return nullptr;
2201   }
2202   if (bTypeOnly)
2203     return (CPDF_Object*)PDFOBJ_INVALID;
2204
2205   return nullptr;
2206 }
2207
2208 CPDF_Object* CPDF_SyntaxParser::GetObjectByStrict(
2209     CPDF_IndirectObjects* pObjList,
2210     FX_DWORD objnum,
2211     FX_DWORD gennum,
2212     struct PARSE_CONTEXT* pContext) {
2213   CFX_AutoRestorer<int> restorer(&s_CurrentRecursionDepth);
2214   if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth) {
2215     return NULL;
2216   }
2217   FX_FILESIZE SavedPos = m_Pos;
2218   FX_BOOL bTypeOnly = pContext && (pContext->m_Flags & PDFPARSE_TYPEONLY);
2219   FX_BOOL bIsNumber;
2220   CFX_ByteString word = GetNextWord(bIsNumber);
2221   if (word.GetLength() == 0) {
2222     if (bTypeOnly) {
2223       return (CPDF_Object*)PDFOBJ_INVALID;
2224     }
2225     return NULL;
2226   }
2227   if (bIsNumber) {
2228     FX_FILESIZE SavedPos = m_Pos;
2229     CFX_ByteString nextword = GetNextWord(bIsNumber);
2230     if (bIsNumber) {
2231       CFX_ByteString nextword2 = GetNextWord(bIsNumber);
2232       if (nextword2 == FX_BSTRC("R")) {
2233         if (bTypeOnly) {
2234           return (CPDF_Object*)PDFOBJ_REFERENCE;
2235         }
2236         FX_DWORD objnum = FXSYS_atoi(word);
2237         return new CPDF_Reference(pObjList, objnum);
2238       }
2239     }
2240     m_Pos = SavedPos;
2241     if (bTypeOnly) {
2242       return (CPDF_Object*)PDFOBJ_NUMBER;
2243     }
2244     return CPDF_Number::Create(word);
2245   }
2246   if (word == FX_BSTRC("true") || word == FX_BSTRC("false")) {
2247     if (bTypeOnly) {
2248       return (CPDF_Object*)PDFOBJ_BOOLEAN;
2249     }
2250     return CPDF_Boolean::Create(word == FX_BSTRC("true"));
2251   }
2252   if (word == FX_BSTRC("null")) {
2253     if (bTypeOnly) {
2254       return (CPDF_Object*)PDFOBJ_NULL;
2255     }
2256     return CPDF_Null::Create();
2257   }
2258   if (word == FX_BSTRC("(")) {
2259     if (bTypeOnly) {
2260       return (CPDF_Object*)PDFOBJ_STRING;
2261     }
2262     CFX_ByteString str = ReadString();
2263     if (m_pCryptoHandler) {
2264       m_pCryptoHandler->Decrypt(objnum, gennum, str);
2265     }
2266     return CPDF_String::Create(str, FALSE);
2267   }
2268   if (word == FX_BSTRC("<")) {
2269     if (bTypeOnly) {
2270       return (CPDF_Object*)PDFOBJ_STRING;
2271     }
2272     CFX_ByteString str = ReadHexString();
2273     if (m_pCryptoHandler) {
2274       m_pCryptoHandler->Decrypt(objnum, gennum, str);
2275     }
2276     return CPDF_String::Create(str, TRUE);
2277   }
2278   if (word == FX_BSTRC("[")) {
2279     if (bTypeOnly) {
2280       return (CPDF_Object*)PDFOBJ_ARRAY;
2281     }
2282     nonstd::unique_ptr<CPDF_Array, ReleaseDeleter<CPDF_Array>> pArray(
2283         CPDF_Array::Create());
2284     while (CPDF_Object* pObj = GetObject(pObjList, objnum, gennum))
2285       pArray->Add(pObj);
2286     return m_WordBuffer[0] == ']' ? pArray.release() : nullptr;
2287   }
2288   if (word[0] == '/') {
2289     if (bTypeOnly) {
2290       return (CPDF_Object*)PDFOBJ_NAME;
2291     }
2292     return CPDF_Name::Create(
2293         PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)));
2294   }
2295   if (word == FX_BSTRC("<<")) {
2296     if (bTypeOnly) {
2297       return (CPDF_Object*)PDFOBJ_DICTIONARY;
2298     }
2299     if (pContext) {
2300       pContext->m_DictStart = SavedPos;
2301     }
2302     nonstd::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>> pDict(
2303         CPDF_Dictionary::Create());
2304     while (1) {
2305       FX_BOOL bIsNumber;
2306       FX_FILESIZE SavedPos = m_Pos;
2307       CFX_ByteString key = GetNextWord(bIsNumber);
2308       if (key.IsEmpty())
2309         return nullptr;
2310
2311       if (key == FX_BSTRC(">>"))
2312         break;
2313
2314       if (key == FX_BSTRC("endobj")) {
2315         m_Pos = SavedPos;
2316         break;
2317       }
2318       if (key[0] != '/')
2319         continue;
2320
2321       key = PDF_NameDecode(key);
2322       nonstd::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> obj(
2323           GetObject(pObjList, objnum, gennum));
2324       if (!obj) {
2325         uint8_t ch;
2326         while (GetNextChar(ch) && ch != 0x0A && ch != 0x0D) {
2327         }
2328         return nullptr;
2329       }
2330       if (key.GetLength() > 1) {
2331         pDict->AddValue(CFX_ByteStringC(key.c_str() + 1, key.GetLength() - 1),
2332                         obj.release());
2333       }
2334     }
2335     if (pContext) {
2336       pContext->m_DictEnd = m_Pos;
2337       if (pContext->m_Flags & PDFPARSE_NOSTREAM) {
2338         return pDict.release();
2339       }
2340     }
2341     FX_FILESIZE SavedPos = m_Pos;
2342     FX_BOOL bIsNumber;
2343     CFX_ByteString nextword = GetNextWord(bIsNumber);
2344     if (nextword != FX_BSTRC("stream")) {
2345       m_Pos = SavedPos;
2346       return pDict.release();
2347     }
2348
2349     return ReadStream(pDict.release(), pContext, objnum, gennum);
2350   }
2351   if (word == FX_BSTRC(">>")) {
2352     m_Pos = SavedPos;
2353     return nullptr;
2354   }
2355   if (bTypeOnly)
2356     return (CPDF_Object*)PDFOBJ_INVALID;
2357
2358   return nullptr;
2359 }
2360
2361 unsigned int CPDF_SyntaxParser::ReadEOLMarkers(FX_FILESIZE pos) {
2362   unsigned char byte1 = 0;
2363   unsigned char byte2 = 0;
2364   GetCharAt(pos, byte1);
2365   GetCharAt(pos + 1, byte2);
2366   unsigned int markers = 0;
2367   if (byte1 == '\r' && byte2 == '\n') {
2368     markers = 2;
2369   } else if (byte1 == '\r' || byte1 == '\n') {
2370     markers = 1;
2371   }
2372   return markers;
2373 }
2374 CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
2375                                            PARSE_CONTEXT* pContext,
2376                                            FX_DWORD objnum,
2377                                            FX_DWORD gennum) {
2378   CPDF_Object* pLenObj = pDict->GetElement(FX_BSTRC("Length"));
2379   FX_FILESIZE len = -1;
2380   CPDF_Reference* pLenObjRef = ToReference(pLenObj);
2381
2382   bool differingObjNum = !pLenObjRef || (pLenObjRef->GetObjList() &&
2383                                          pLenObjRef->GetRefObjNum() != objnum);
2384   if (pLenObj && differingObjNum)
2385     len = pLenObj->GetInteger();
2386
2387   // Locate the start of stream.
2388   ToNextLine();
2389   FX_FILESIZE streamStartPos = m_Pos;
2390   if (pContext) {
2391     pContext->m_DataStart = streamStartPos;
2392   }
2393   const unsigned int ENDSTREAM_LEN = sizeof("endstream") - 1;
2394   const unsigned int ENDOBJ_LEN = sizeof("endobj") - 1;
2395   CPDF_CryptoHandler* pCryptoHandler =
2396       objnum == (FX_DWORD)m_MetadataObjnum ? nullptr : m_pCryptoHandler.get();
2397   if (!pCryptoHandler) {
2398     FX_BOOL bSearchForKeyword = TRUE;
2399     if (len >= 0) {
2400       pdfium::base::CheckedNumeric<FX_FILESIZE> pos = m_Pos;
2401       pos += len;
2402       if (pos.IsValid() && pos.ValueOrDie() < m_FileLen) {
2403         m_Pos = pos.ValueOrDie();
2404       }
2405       m_Pos += ReadEOLMarkers(m_Pos);
2406       FXSYS_memset(m_WordBuffer, 0, ENDSTREAM_LEN + 1);
2407       GetNextWord();
2408       if (FXSYS_memcmp(m_WordBuffer, "endstream", ENDSTREAM_LEN) == 0 &&
2409           IsWholeWord(m_Pos - ENDSTREAM_LEN, m_FileLen,
2410                       FX_BSTRC("endstream").GetPtr(), ENDSTREAM_LEN, TRUE)) {
2411         bSearchForKeyword = FALSE;
2412       }
2413     }
2414     if (bSearchForKeyword) {
2415       // If len is not available, len needs to be calculated
2416       // by searching the keywords "endstream" or "endobj".
2417       m_Pos = streamStartPos;
2418       FX_FILESIZE endStreamOffset = 0;
2419       while (endStreamOffset >= 0) {
2420         endStreamOffset = FindTag(FX_BSTRC("endstream"), 0);
2421         if (endStreamOffset < 0) {
2422           // Can't find any "endstream".
2423           break;
2424         }
2425         if (IsWholeWord(m_Pos - ENDSTREAM_LEN, m_FileLen,
2426                         FX_BSTRC("endstream").GetPtr(), ENDSTREAM_LEN, TRUE)) {
2427           // Stop searching when the keyword "endstream" is found.
2428           endStreamOffset = m_Pos - streamStartPos - ENDSTREAM_LEN;
2429           break;
2430         }
2431       }
2432       m_Pos = streamStartPos;
2433       FX_FILESIZE endObjOffset = 0;
2434       while (endObjOffset >= 0) {
2435         endObjOffset = FindTag(FX_BSTRC("endobj"), 0);
2436         if (endObjOffset < 0) {
2437           // Can't find any "endobj".
2438           break;
2439         }
2440         if (IsWholeWord(m_Pos - ENDOBJ_LEN, m_FileLen,
2441                         FX_BSTRC("endobj").GetPtr(), ENDOBJ_LEN, TRUE)) {
2442           // Stop searching when the keyword "endobj" is found.
2443           endObjOffset = m_Pos - streamStartPos - ENDOBJ_LEN;
2444           break;
2445         }
2446       }
2447       if (endStreamOffset < 0 && endObjOffset < 0) {
2448         // Can't find "endstream" or "endobj".
2449         return nullptr;
2450       }
2451       if (endStreamOffset < 0 && endObjOffset >= 0) {
2452         // Correct the position of end stream.
2453         endStreamOffset = endObjOffset;
2454       } else if (endStreamOffset >= 0 && endObjOffset < 0) {
2455         // Correct the position of end obj.
2456         endObjOffset = endStreamOffset;
2457       } else if (endStreamOffset > endObjOffset) {
2458         endStreamOffset = endObjOffset;
2459       }
2460       len = endStreamOffset;
2461       int numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 2);
2462       if (numMarkers == 2) {
2463         len -= 2;
2464       } else {
2465         numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 1);
2466         if (numMarkers == 1) {
2467           len -= 1;
2468         }
2469       }
2470       if (len < 0) {
2471         return nullptr;
2472       }
2473       pDict->SetAtInteger(FX_BSTRC("Length"), len);
2474     }
2475     m_Pos = streamStartPos;
2476   }
2477   if (len < 0) {
2478     return nullptr;
2479   }
2480   uint8_t* pData = nullptr;
2481   if (len > 0) {
2482     pData = FX_Alloc(uint8_t, len);
2483     ReadBlock(pData, len);
2484     if (pCryptoHandler) {
2485       CFX_BinaryBuf dest_buf;
2486       dest_buf.EstimateSize(pCryptoHandler->DecryptGetSize(len));
2487       void* context = pCryptoHandler->DecryptStart(objnum, gennum);
2488       pCryptoHandler->DecryptStream(context, pData, len, dest_buf);
2489       pCryptoHandler->DecryptFinish(context, dest_buf);
2490       FX_Free(pData);
2491       pData = dest_buf.GetBuffer();
2492       len = dest_buf.GetSize();
2493       dest_buf.DetachBuffer();
2494     }
2495   }
2496   CPDF_Stream* pStream = new CPDF_Stream(pData, len, pDict);
2497   if (pContext) {
2498     pContext->m_DataEnd = pContext->m_DataStart + len;
2499   }
2500   streamStartPos = m_Pos;
2501   FXSYS_memset(m_WordBuffer, 0, ENDOBJ_LEN + 1);
2502   GetNextWord();
2503   int numMarkers = ReadEOLMarkers(m_Pos);
2504   if (m_WordSize == ENDOBJ_LEN && numMarkers != 0 &&
2505       FXSYS_memcmp(m_WordBuffer, "endobj", ENDOBJ_LEN) == 0) {
2506     m_Pos = streamStartPos;
2507   }
2508   return pStream;
2509 }
2510 void CPDF_SyntaxParser::InitParser(IFX_FileRead* pFileAccess,
2511                                    FX_DWORD HeaderOffset) {
2512   FX_Free(m_pFileBuf);
2513   m_pFileBuf = FX_Alloc(uint8_t, m_BufSize);
2514   m_HeaderOffset = HeaderOffset;
2515   m_FileLen = pFileAccess->GetSize();
2516   m_Pos = 0;
2517   m_pFileAccess = pFileAccess;
2518   m_BufOffset = 0;
2519   pFileAccess->ReadBlock(
2520       m_pFileBuf, 0,
2521       (size_t)((FX_FILESIZE)m_BufSize > m_FileLen ? m_FileLen : m_BufSize));
2522 }
2523 int32_t CPDF_SyntaxParser::GetDirectNum() {
2524   GetNextWord();
2525   if (!m_bIsNumber) {
2526     return 0;
2527   }
2528   m_WordBuffer[m_WordSize] = 0;
2529   return FXSYS_atoi((const FX_CHAR*)m_WordBuffer);
2530 }
2531 FX_BOOL CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos,
2532                                        FX_FILESIZE limit,
2533                                        const uint8_t* tag,
2534                                        FX_DWORD taglen,
2535                                        FX_BOOL checkKeyword) {
2536   uint8_t type = PDF_CharType[tag[0]];
2537   FX_BOOL bCheckLeft = type != 'D' && type != 'W';
2538   type = PDF_CharType[tag[taglen - 1]];
2539   FX_BOOL bCheckRight = type != 'D' && type != 'W';
2540   uint8_t ch;
2541   if (bCheckRight && startpos + (int32_t)taglen <= limit &&
2542       GetCharAt(startpos + (int32_t)taglen, ch)) {
2543     uint8_t type = PDF_CharType[ch];
2544     if (type == 'N' || type == 'R' || (checkKeyword && type == 'D')) {
2545       return FALSE;
2546     }
2547   }
2548   if (bCheckLeft && startpos > 0 && GetCharAt(startpos - 1, ch)) {
2549     uint8_t type = PDF_CharType[ch];
2550     if (type == 'N' || type == 'R' || (checkKeyword && type == 'D')) {
2551       return FALSE;
2552     }
2553   }
2554   return TRUE;
2555 }
2556 FX_BOOL CPDF_SyntaxParser::SearchWord(const CFX_ByteStringC& tag,
2557                                       FX_BOOL bWholeWord,
2558                                       FX_BOOL bForward,
2559                                       FX_FILESIZE limit) {
2560   int32_t taglen = tag.GetLength();
2561   if (taglen == 0) {
2562     return FALSE;
2563   }
2564   FX_FILESIZE pos = m_Pos;
2565   int32_t offset = 0;
2566   if (!bForward) {
2567     offset = taglen - 1;
2568   }
2569   const uint8_t* tag_data = tag.GetPtr();
2570   uint8_t byte;
2571   while (1) {
2572     if (bForward) {
2573       if (limit) {
2574         if (pos >= m_Pos + limit) {
2575           return FALSE;
2576         }
2577       }
2578       if (!GetCharAt(pos, byte)) {
2579         return FALSE;
2580       }
2581     } else {
2582       if (limit) {
2583         if (pos <= m_Pos - limit) {
2584           return FALSE;
2585         }
2586       }
2587       if (!GetCharAtBackward(pos, byte)) {
2588         return FALSE;
2589       }
2590     }
2591     if (byte == tag_data[offset]) {
2592       if (bForward) {
2593         offset++;
2594         if (offset < taglen) {
2595           pos++;
2596           continue;
2597         }
2598       } else {
2599         offset--;
2600         if (offset >= 0) {
2601           pos--;
2602           continue;
2603         }
2604       }
2605       FX_FILESIZE startpos = bForward ? pos - taglen + 1 : pos;
2606       if (!bWholeWord ||
2607           IsWholeWord(startpos, limit, tag.GetPtr(), taglen, FALSE)) {
2608         m_Pos = startpos;
2609         return TRUE;
2610       }
2611     }
2612     if (bForward) {
2613       offset = byte == tag_data[0] ? 1 : 0;
2614       pos++;
2615     } else {
2616       offset = byte == tag_data[taglen - 1] ? taglen - 2 : taglen - 1;
2617       pos--;
2618     }
2619     if (pos < 0) {
2620       return FALSE;
2621     }
2622   }
2623   return FALSE;
2624 }
2625
2626 int32_t CPDF_SyntaxParser::SearchMultiWord(const CFX_ByteStringC& tags,
2627                                            FX_BOOL bWholeWord,
2628                                            FX_FILESIZE limit) {
2629   int32_t ntags = 1;
2630   for (int i = 0; i < tags.GetLength(); ++i) {
2631     if (tags[i] == 0) {
2632       ++ntags;
2633     }
2634   }
2635
2636   std::vector<SearchTagRecord> patterns(ntags);
2637   FX_DWORD start = 0;
2638   FX_DWORD itag = 0;
2639   FX_DWORD max_len = 0;
2640   for (int i = 0; i <= tags.GetLength(); ++i) {
2641     if (tags[i] == 0) {
2642       FX_DWORD len = i - start;
2643       max_len = std::max(len, max_len);
2644       patterns[itag].m_pTag = tags.GetPtr() + start;
2645       patterns[itag].m_Len = len;
2646       patterns[itag].m_Offset = 0;
2647       start = i + 1;
2648       ++itag;
2649     }
2650   }
2651
2652   const FX_FILESIZE pos_limit = m_Pos + limit;
2653   for (FX_FILESIZE pos = m_Pos; !limit || pos < pos_limit; ++pos) {
2654     uint8_t byte;
2655     if (!GetCharAt(pos, byte))
2656       break;
2657
2658     for (int i = 0; i < ntags; ++i) {
2659       SearchTagRecord& pat = patterns[i];
2660       if (pat.m_pTag[pat.m_Offset] != byte) {
2661         pat.m_Offset = (pat.m_pTag[0] == byte) ? 1 : 0;
2662         continue;
2663       }
2664
2665       ++pat.m_Offset;
2666       if (pat.m_Offset != pat.m_Len)
2667         continue;
2668
2669       if (!bWholeWord ||
2670           IsWholeWord(pos - pat.m_Len, limit, pat.m_pTag, pat.m_Len, FALSE)) {
2671         return i;
2672       }
2673
2674       pat.m_Offset = (pat.m_pTag[0] == byte) ? 1 : 0;
2675     }
2676   }
2677   return -1;
2678 }
2679
2680 FX_FILESIZE CPDF_SyntaxParser::FindTag(const CFX_ByteStringC& tag,
2681                                        FX_FILESIZE limit) {
2682   int32_t taglen = tag.GetLength();
2683   int32_t match = 0;
2684   limit += m_Pos;
2685   FX_FILESIZE startpos = m_Pos;
2686   while (1) {
2687     uint8_t ch;
2688     if (!GetNextChar(ch)) {
2689       return -1;
2690     }
2691     if (ch == tag[match]) {
2692       match++;
2693       if (match == taglen) {
2694         return m_Pos - startpos - taglen;
2695       }
2696     } else {
2697       match = ch == tag[0] ? 1 : 0;
2698     }
2699     if (limit && m_Pos == limit) {
2700       return -1;
2701     }
2702   }
2703   return -1;
2704 }
2705 void CPDF_SyntaxParser::GetBinary(uint8_t* buffer, FX_DWORD size) {
2706   FX_DWORD offset = 0;
2707   uint8_t ch;
2708   while (1) {
2709     if (!GetNextChar(ch)) {
2710       return;
2711     }
2712     buffer[offset++] = ch;
2713     if (offset == size) {
2714       break;
2715     }
2716   }
2717 }
2718
2719 class CPDF_DataAvail final : public IPDF_DataAvail {
2720  public:
2721   CPDF_DataAvail(IFX_FileAvail* pFileAvail, IFX_FileRead* pFileRead);
2722   ~CPDF_DataAvail() override;
2723
2724   FX_BOOL IsDocAvail(IFX_DownloadHints* pHints) override;
2725
2726   void SetDocument(CPDF_Document* pDoc) override;
2727
2728   FX_BOOL IsPageAvail(int iPage, IFX_DownloadHints* pHints) override;
2729
2730   int32_t IsFormAvail(IFX_DownloadHints* pHints) override;
2731
2732   int32_t IsLinearizedPDF() override;
2733
2734   FX_BOOL IsLinearized() override { return m_bLinearized; }
2735
2736   void GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, FX_DWORD* pSize) override;
2737
2738  protected:
2739   static const int kMaxDataAvailRecursionDepth = 64;
2740   static int s_CurrentDataAvailRecursionDepth;
2741   static const int kMaxPageRecursionDepth = 1024;
2742
2743   FX_DWORD GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset);
2744   FX_BOOL IsObjectsAvail(CFX_PtrArray& obj_array,
2745                          FX_BOOL bParsePage,
2746                          IFX_DownloadHints* pHints,
2747                          CFX_PtrArray& ret_array);
2748   FX_BOOL CheckDocStatus(IFX_DownloadHints* pHints);
2749   FX_BOOL CheckHeader(IFX_DownloadHints* pHints);
2750   FX_BOOL CheckFirstPage(IFX_DownloadHints* pHints);
2751   FX_BOOL CheckEnd(IFX_DownloadHints* pHints);
2752   FX_BOOL CheckCrossRef(IFX_DownloadHints* pHints);
2753   FX_BOOL CheckCrossRefItem(IFX_DownloadHints* pHints);
2754   FX_BOOL CheckTrailer(IFX_DownloadHints* pHints);
2755   FX_BOOL CheckRoot(IFX_DownloadHints* pHints);
2756   FX_BOOL CheckInfo(IFX_DownloadHints* pHints);
2757   FX_BOOL CheckPages(IFX_DownloadHints* pHints);
2758   FX_BOOL CheckPage(IFX_DownloadHints* pHints);
2759   FX_BOOL CheckResources(IFX_DownloadHints* pHints);
2760   FX_BOOL CheckAnnots(IFX_DownloadHints* pHints);
2761   FX_BOOL CheckAcroForm(IFX_DownloadHints* pHints);
2762   FX_BOOL CheckAcroFormSubObject(IFX_DownloadHints* pHints);
2763   FX_BOOL CheckTrailerAppend(IFX_DownloadHints* pHints);
2764   FX_BOOL CheckPageStatus(IFX_DownloadHints* pHints);
2765   FX_BOOL CheckAllCrossRefStream(IFX_DownloadHints* pHints);
2766
2767   int32_t CheckCrossRefStream(IFX_DownloadHints* pHints,
2768                               FX_FILESIZE& xref_offset);
2769   FX_BOOL IsLinearizedFile(uint8_t* pData, FX_DWORD dwLen);
2770   void SetStartOffset(FX_FILESIZE dwOffset);
2771   FX_BOOL GetNextToken(CFX_ByteString& token);
2772   FX_BOOL GetNextChar(uint8_t& ch);
2773   CPDF_Object* ParseIndirectObjectAt(FX_FILESIZE pos, FX_DWORD objnum);
2774   CPDF_Object* GetObject(FX_DWORD objnum,
2775                          IFX_DownloadHints* pHints,
2776                          FX_BOOL* pExistInFile);
2777   FX_BOOL GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages);
2778   FX_BOOL PreparePageItem();
2779   FX_BOOL LoadPages(IFX_DownloadHints* pHints);
2780   FX_BOOL LoadAllXref(IFX_DownloadHints* pHints);
2781   FX_BOOL LoadAllFile(IFX_DownloadHints* pHints);
2782   FX_BOOL CheckLinearizedData(IFX_DownloadHints* pHints);
2783   FX_BOOL CheckFileResources(IFX_DownloadHints* pHints);
2784   FX_BOOL CheckPageAnnots(int iPage, IFX_DownloadHints* pHints);
2785
2786   FX_BOOL CheckLinearizedFirstPage(int iPage, IFX_DownloadHints* pHints);
2787   FX_BOOL HaveResourceAncestor(CPDF_Dictionary* pDict);
2788   FX_BOOL CheckPage(int32_t iPage, IFX_DownloadHints* pHints);
2789   FX_BOOL LoadDocPages(IFX_DownloadHints* pHints);
2790   FX_BOOL LoadDocPage(int32_t iPage, IFX_DownloadHints* pHints);
2791   FX_BOOL CheckPageNode(CPDF_PageNode& pageNodes,
2792                         int32_t iPage,
2793                         int32_t& iCount,
2794                         IFX_DownloadHints* pHints,
2795                         int level);
2796   FX_BOOL CheckUnkownPageNode(FX_DWORD dwPageNo,
2797                               CPDF_PageNode* pPageNode,
2798                               IFX_DownloadHints* pHints);
2799   FX_BOOL CheckArrayPageNode(FX_DWORD dwPageNo,
2800                              CPDF_PageNode* pPageNode,
2801                              IFX_DownloadHints* pHints);
2802   FX_BOOL CheckPageCount(IFX_DownloadHints* pHints);
2803   FX_BOOL IsFirstCheck(int iPage);
2804   void ResetFirstCheck(int iPage);
2805
2806   CPDF_Parser m_parser;
2807
2808   CPDF_SyntaxParser m_syntaxParser;
2809
2810   CPDF_Object* m_pRoot;
2811
2812   FX_DWORD m_dwRootObjNum;
2813
2814   FX_DWORD m_dwInfoObjNum;
2815
2816   CPDF_Object* m_pLinearized;
2817
2818   CPDF_Object* m_pTrailer;
2819
2820   FX_BOOL m_bDocAvail;
2821
2822   FX_FILESIZE m_dwHeaderOffset;
2823
2824   FX_FILESIZE m_dwLastXRefOffset;
2825
2826   FX_FILESIZE m_dwXRefOffset;
2827
2828   FX_FILESIZE m_dwTrailerOffset;
2829
2830   FX_FILESIZE m_dwCurrentOffset;
2831
2832   PDF_DATAAVAIL_STATUS m_docStatus;
2833
2834   FX_FILESIZE m_dwFileLen;
2835
2836   CPDF_Document* m_pDocument;
2837
2838   CPDF_SortObjNumArray m_objnum_array;
2839
2840   CFX_PtrArray m_objs_array;
2841
2842   FX_FILESIZE m_Pos;
2843
2844   FX_FILESIZE m_bufferOffset;
2845
2846   FX_DWORD m_bufferSize;
2847
2848   CFX_ByteString m_WordBuf;
2849
2850   uint8_t m_WordBuffer[257];
2851
2852   FX_DWORD m_WordSize;
2853
2854   uint8_t m_bufferData[512];
2855
2856   CFX_FileSizeArray m_CrossOffset;
2857
2858   CFX_DWordArray m_XRefStreamList;
2859
2860   CFX_DWordArray m_PageObjList;
2861
2862   FX_DWORD m_PagesObjNum;
2863
2864   FX_BOOL m_bLinearized;
2865
2866   FX_DWORD m_dwFirstPageNo;
2867
2868   FX_BOOL m_bLinearedDataOK;
2869
2870   FX_BOOL m_bMainXRefLoadTried;
2871
2872   FX_BOOL m_bMainXRefLoadedOK;
2873
2874   FX_BOOL m_bPagesTreeLoad;
2875
2876   FX_BOOL m_bPagesLoad;
2877
2878   CPDF_Parser* m_pCurrentParser;
2879
2880   FX_FILESIZE m_dwCurrentXRefSteam;
2881
2882   FX_BOOL m_bAnnotsLoad;
2883
2884   FX_BOOL m_bHaveAcroForm;
2885
2886   FX_DWORD m_dwAcroFormObjNum;
2887
2888   FX_BOOL m_bAcroFormLoad;
2889
2890   CPDF_Object* m_pAcroForm;
2891
2892   CFX_PtrArray m_arrayAcroforms;
2893
2894   CPDF_Dictionary* m_pPageDict;
2895
2896   CPDF_Object* m_pPageResource;
2897
2898   FX_BOOL m_bNeedDownLoadResource;
2899
2900   FX_BOOL m_bPageLoadedOK;
2901
2902   FX_BOOL m_bLinearizedFormParamLoad;
2903
2904   CFX_PtrArray m_PagesArray;
2905
2906   FX_DWORD m_dwEncryptObjNum;
2907
2908   FX_FILESIZE m_dwPrevXRefOffset;
2909
2910   FX_BOOL m_bTotalLoadPageTree;
2911
2912   FX_BOOL m_bCurPageDictLoadOK;
2913
2914   CPDF_PageNode m_pageNodes;
2915
2916   std::set<FX_DWORD> m_pageMapCheckState;
2917   std::set<FX_DWORD> m_pagesLoadState;
2918 };
2919
2920 IPDF_DataAvail::IPDF_DataAvail(IFX_FileAvail* pFileAvail,
2921                                IFX_FileRead* pFileRead)
2922     : m_pFileAvail(pFileAvail), m_pFileRead(pFileRead) {}
2923
2924 // static
2925 IPDF_DataAvail* IPDF_DataAvail::Create(IFX_FileAvail* pFileAvail,
2926                                        IFX_FileRead* pFileRead) {
2927   return new CPDF_DataAvail(pFileAvail, pFileRead);
2928 }
2929
2930 // static
2931 int CPDF_DataAvail::s_CurrentDataAvailRecursionDepth = 0;
2932
2933 CPDF_DataAvail::CPDF_DataAvail(IFX_FileAvail* pFileAvail,
2934                                IFX_FileRead* pFileRead)
2935     : IPDF_DataAvail(pFileAvail, pFileRead) {
2936   m_Pos = 0;
2937   m_dwFileLen = 0;
2938   if (m_pFileRead) {
2939     m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize();
2940   }
2941   m_dwCurrentOffset = 0;
2942   m_WordSize = 0;
2943   m_dwXRefOffset = 0;
2944   m_bufferOffset = 0;
2945   m_dwFirstPageNo = 0;
2946   m_bufferSize = 0;
2947   m_PagesObjNum = 0;
2948   m_dwCurrentXRefSteam = 0;
2949   m_dwAcroFormObjNum = 0;
2950   m_dwInfoObjNum = 0;
2951   m_pDocument = 0;
2952   m_dwEncryptObjNum = 0;
2953   m_dwPrevXRefOffset = 0;
2954   m_dwLastXRefOffset = 0;
2955   m_bDocAvail = FALSE;
2956   m_bMainXRefLoadTried = FALSE;
2957   m_bDocAvail = FALSE;
2958   m_bLinearized = FALSE;
2959   m_bPagesLoad = FALSE;
2960   m_bPagesTreeLoad = FALSE;
2961   m_bMainXRefLoadedOK = FALSE;
2962   m_bAnnotsLoad = FALSE;
2963   m_bHaveAcroForm = FALSE;
2964   m_bAcroFormLoad = FALSE;
2965   m_bPageLoadedOK = FALSE;
2966   m_bNeedDownLoadResource = FALSE;
2967   m_bLinearizedFormParamLoad = FALSE;
2968   m_pLinearized = NULL;
2969   m_pRoot = NULL;
2970   m_pTrailer = NULL;
2971   m_pCurrentParser = NULL;
2972   m_pAcroForm = NULL;
2973   m_pPageDict = NULL;
2974   m_pPageResource = NULL;
2975   m_docStatus = PDF_DATAAVAIL_HEADER;
2976   m_parser.m_bOwnFileRead = FALSE;
2977   m_bTotalLoadPageTree = FALSE;
2978   m_bCurPageDictLoadOK = FALSE;
2979   m_bLinearedDataOK = FALSE;
2980 }
2981 CPDF_DataAvail::~CPDF_DataAvail() {
2982   if (m_pLinearized) {
2983     m_pLinearized->Release();
2984   }
2985   if (m_pRoot) {
2986     m_pRoot->Release();
2987   }
2988   if (m_pTrailer) {
2989     m_pTrailer->Release();
2990   }
2991   int32_t i = 0;
2992   int32_t iSize = m_arrayAcroforms.GetSize();
2993   for (i = 0; i < iSize; ++i) {
2994     ((CPDF_Object*)m_arrayAcroforms.GetAt(i))->Release();
2995   }
2996 }
2997 void CPDF_DataAvail::SetDocument(CPDF_Document* pDoc) {
2998   m_pDocument = pDoc;
2999 }
3000 FX_DWORD CPDF_DataAvail::GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset) {
3001   CPDF_Parser* pParser = (CPDF_Parser*)(m_pDocument->GetParser());
3002   if (pParser == NULL) {
3003     return 0;
3004   }
3005   if (objnum >= (FX_DWORD)pParser->m_CrossRef.GetSize()) {
3006     return 0;
3007   }
3008   if (pParser->m_V5Type[objnum] == 2) {
3009     objnum = (FX_DWORD)pParser->m_CrossRef[objnum];
3010   }
3011   if (pParser->m_V5Type[objnum] == 1 || pParser->m_V5Type[objnum] == 255) {
3012     offset = pParser->m_CrossRef[objnum];
3013     if (offset == 0) {
3014       return 0;
3015     }
3016     void* pResult = FXSYS_bsearch(&offset, pParser->m_SortedOffset.GetData(),
3017                                   pParser->m_SortedOffset.GetSize(),
3018                                   sizeof(FX_FILESIZE), CompareFileSize);
3019     if (pResult == NULL) {
3020       return 0;
3021     }
3022     if ((FX_FILESIZE*)pResult -
3023             (FX_FILESIZE*)pParser->m_SortedOffset.GetData() ==
3024         pParser->m_SortedOffset.GetSize() - 1) {
3025       return 0;
3026     }
3027     return (FX_DWORD)(((FX_FILESIZE*)pResult)[1] - offset);
3028   }
3029   return 0;
3030 }
3031 FX_BOOL CPDF_DataAvail::IsObjectsAvail(CFX_PtrArray& obj_array,
3032                                        FX_BOOL bParsePage,
3033                                        IFX_DownloadHints* pHints,
3034                                        CFX_PtrArray& ret_array) {
3035   if (!obj_array.GetSize()) {
3036     return TRUE;
3037   }
3038   FX_DWORD count = 0;
3039   CFX_PtrArray new_obj_array;
3040   int32_t i = 0;
3041   for (i = 0; i < obj_array.GetSize(); i++) {
3042     CPDF_Object* pObj = (CPDF_Object*)obj_array[i];
3043     if (!pObj) {
3044       continue;
3045     }
3046     int32_t type = pObj->GetType();
3047     switch (type) {
3048       case PDFOBJ_ARRAY: {
3049         CPDF_Array* pArray = pObj->GetArray();
3050         for (FX_DWORD k = 0; k < pArray->GetCount(); k++) {
3051           new_obj_array.Add(pArray->GetElement(k));
3052         }
3053       } break;
3054       case PDFOBJ_STREAM:
3055         pObj = pObj->GetDict();
3056       case PDFOBJ_DICTIONARY: {
3057         CPDF_Dictionary* pDict = pObj->GetDict();
3058         if (pDict && pDict->GetString("Type") == "Page" && !bParsePage) {
3059           continue;
3060         }
3061         FX_POSITION pos = pDict->GetStartPos();
3062         while (pos) {
3063           CPDF_Object* value;
3064           CFX_ByteString key;
3065           value = pDict->GetNextElement(pos, key);
3066           if (key != "Parent") {
3067             new_obj_array.Add(value);
3068           }
3069         }
3070       } break;
3071       case PDFOBJ_REFERENCE: {
3072         CPDF_Reference* pRef = pObj->AsReference();
3073         FX_DWORD dwNum = pRef->GetRefObjNum();
3074         FX_FILESIZE offset;
3075         FX_DWORD original_size = GetObjectSize(dwNum, offset);
3076         pdfium::base::CheckedNumeric<FX_DWORD> size = original_size;
3077         if (size.ValueOrDefault(0) == 0 || offset < 0 ||
3078             offset >= m_dwFileLen) {
3079           break;
3080         }
3081
3082         size += offset;
3083         size += 512;
3084         if (!size.IsValid()) {
3085           break;
3086         }
3087         if (size.ValueOrDie() > m_dwFileLen) {
3088           size = m_dwFileLen - offset;
3089         } else {
3090           size = original_size + 512;
3091         }
3092         if (!size.IsValid()) {
3093           break;
3094         }
3095         if (!m_pFileAvail->IsDataAvail(offset, size.ValueOrDie())) {
3096           pHints->AddSegment(offset, size.ValueOrDie());
3097           ret_array.Add(pObj);
3098           count++;
3099         } else if (!m_objnum_array.Find(dwNum)) {
3100           m_objnum_array.AddObjNum(dwNum);
3101           CPDF_Object* pReferred =
3102               m_pDocument->GetIndirectObject(pRef->GetRefObjNum(), NULL);
3103           if (pReferred) {
3104             new_obj_array.Add(pReferred);
3105           }
3106         }
3107       } break;
3108     }
3109   }
3110   if (count > 0) {
3111     int32_t iSize = new_obj_array.GetSize();
3112     for (i = 0; i < iSize; ++i) {
3113       CPDF_Object* pObj = (CPDF_Object*)new_obj_array[i];
3114       if (CPDF_Reference* pRef = pObj->AsReference()) {
3115         FX_DWORD dwNum = pRef->GetRefObjNum();
3116         if (!m_objnum_array.Find(dwNum))
3117           ret_array.Add(pObj);
3118       } else {
3119         ret_array.Add(pObj);
3120       }
3121     }
3122     return FALSE;
3123   }
3124   obj_array.RemoveAll();
3125   obj_array.Append(new_obj_array);
3126   return IsObjectsAvail(obj_array, FALSE, pHints, ret_array);
3127 }
3128 FX_BOOL CPDF_DataAvail::IsDocAvail(IFX_DownloadHints* pHints) {
3129   if (!m_dwFileLen && m_pFileRead) {
3130     m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize();
3131     if (!m_dwFileLen) {
3132       return TRUE;
3133     }
3134   }
3135   while (!m_bDocAvail) {
3136     if (!CheckDocStatus(pHints)) {
3137       return FALSE;
3138     }
3139   }
3140   return TRUE;
3141 }
3142 FX_BOOL CPDF_DataAvail::CheckAcroFormSubObject(IFX_DownloadHints* pHints) {
3143   if (!m_objs_array.GetSize()) {
3144     m_objs_array.RemoveAll();
3145     m_objnum_array.RemoveAll();
3146     CFX_PtrArray obj_array;
3147     obj_array.Append(m_arrayAcroforms);
3148     FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array);
3149     if (bRet) {
3150       m_objs_array.RemoveAll();
3151     }
3152     return bRet;
3153   }
3154   CFX_PtrArray new_objs_array;
3155   FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array);
3156   if (bRet) {
3157     int32_t iSize = m_arrayAcroforms.GetSize();
3158     for (int32_t i = 0; i < iSize; ++i) {
3159       ((CPDF_Object*)m_arrayAcroforms.GetAt(i))->Release();
3160     }
3161     m_arrayAcroforms.RemoveAll();
3162   } else {
3163     m_objs_array.RemoveAll();
3164     m_objs_array.Append(new_objs_array);
3165   }
3166   return bRet;
3167 }
3168 FX_BOOL CPDF_DataAvail::CheckAcroForm(IFX_DownloadHints* pHints) {
3169   FX_BOOL bExist = FALSE;
3170   m_pAcroForm = GetObject(m_dwAcroFormObjNum, pHints, &bExist);
3171   if (!bExist) {
3172     m_docStatus = PDF_DATAAVAIL_PAGETREE;
3173     return TRUE;
3174   }
3175   if (!m_pAcroForm) {
3176     if (m_docStatus == PDF_DATAAVAIL_ERROR) {
3177       m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3178       return TRUE;
3179     }
3180     return FALSE;
3181   }
3182   m_arrayAcroforms.Add(m_pAcroForm);
3183   m_docStatus = PDF_DATAAVAIL_PAGETREE;
3184   return TRUE;
3185 }
3186 FX_BOOL CPDF_DataAvail::CheckDocStatus(IFX_DownloadHints* pHints) {
3187   switch (m_docStatus) {
3188     case PDF_DATAAVAIL_HEADER:
3189       return CheckHeader(pHints);
3190     case PDF_DATAAVAIL_FIRSTPAGE:
3191     case PDF_DATAAVAIL_FIRSTPAGE_PREPARE:
3192       return CheckFirstPage(pHints);
3193     case PDF_DATAAVAIL_END:
3194       return CheckEnd(pHints);
3195     case PDF_DATAAVAIL_CROSSREF:
3196       return CheckCrossRef(pHints);
3197     case PDF_DATAAVAIL_CROSSREF_ITEM:
3198       return CheckCrossRefItem(pHints);
3199     case PDF_DATAAVAIL_CROSSREF_STREAM:
3200       return CheckAllCrossRefStream(pHints);
3201     case PDF_DATAAVAIL_TRAILER:
3202       return CheckTrailer(pHints);
3203     case PDF_DATAAVAIL_TRAILER_APPEND:
3204       return CheckTrailerAppend(pHints);
3205     case PDF_DATAAVAIL_LOADALLCRSOSSREF:
3206       return LoadAllXref(pHints);
3207     case PDF_DATAAVAIL_LOADALLFILE:
3208       return LoadAllFile(pHints);
3209     case PDF_DATAAVAIL_ROOT:
3210       return CheckRoot(pHints);
3211     case PDF_DATAAVAIL_INFO:
3212       return CheckInfo(pHints);
3213     case PDF_DATAAVAIL_ACROFORM:
3214       return CheckAcroForm(pHints);
3215     case PDF_DATAAVAIL_PAGETREE:
3216       if (m_bTotalLoadPageTree) {
3217         return CheckPages(pHints);
3218       }
3219       return LoadDocPages(pHints);
3220     case PDF_DATAAVAIL_PAGE:
3221       if (m_bTotalLoadPageTree) {
3222         return CheckPage(pHints);
3223       }
3224       m_docStatus = PDF_DATAAVAIL_PAGE_LATERLOAD;
3225       return TRUE;
3226     case PDF_DATAAVAIL_ERROR:
3227       return LoadAllFile(pHints);
3228     case PDF_DATAAVAIL_PAGE_LATERLOAD:
3229       m_docStatus = PDF_DATAAVAIL_PAGE;
3230     default:
3231       m_bDocAvail = TRUE;
3232       return TRUE;
3233   }
3234 }
3235 FX_BOOL CPDF_DataAvail::CheckPageStatus(IFX_DownloadHints* pHints) {
3236   switch (m_docStatus) {
3237     case PDF_DATAAVAIL_PAGETREE:
3238       return CheckPages(pHints);
3239     case PDF_DATAAVAIL_PAGE:
3240       return CheckPage(pHints);
3241     case PDF_DATAAVAIL_ERROR:
3242       return LoadAllFile(pHints);
3243     default:
3244       m_bPagesTreeLoad = TRUE;
3245       m_bPagesLoad = TRUE;
3246       return TRUE;
3247   }
3248 }
3249 FX_BOOL CPDF_DataAvail::LoadAllFile(IFX_DownloadHints* pHints) {
3250   if (m_pFileAvail->IsDataAvail(0, (FX_DWORD)m_dwFileLen)) {
3251     m_docStatus = PDF_DATAAVAIL_DONE;
3252     return TRUE;
3253   }
3254   pHints->AddSegment(0, (FX_DWORD)m_dwFileLen);
3255   return FALSE;
3256 }
3257 FX_BOOL CPDF_DataAvail::LoadAllXref(IFX_DownloadHints* pHints) {
3258   m_parser.m_Syntax.InitParser(m_pFileRead, (FX_DWORD)m_dwHeaderOffset);
3259   m_parser.m_bOwnFileRead = FALSE;
3260   if (!m_parser.LoadAllCrossRefV4(m_dwLastXRefOffset) &&
3261       !m_parser.LoadAllCrossRefV5(m_dwLastXRefOffset)) {
3262     m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3263     return FALSE;
3264   }
3265   FXSYS_qsort(m_parser.m_SortedOffset.GetData(),
3266               m_parser.m_SortedOffset.GetSize(), sizeof(FX_FILESIZE),
3267               CompareFileSize);
3268   m_dwRootObjNum = m_parser.GetRootObjNum();
3269   m_dwInfoObjNum = m_parser.GetInfoObjNum();
3270   m_pCurrentParser = &m_parser;
3271   m_docStatus = PDF_DATAAVAIL_ROOT;
3272   return TRUE;
3273 }
3274 CPDF_Object* CPDF_DataAvail::GetObject(FX_DWORD objnum,
3275                                        IFX_DownloadHints* pHints,
3276                                        FX_BOOL* pExistInFile) {
3277   CPDF_Object* pRet = NULL;
3278   FX_DWORD original_size = 0;
3279   FX_FILESIZE offset = 0;
3280   CPDF_Parser* pParser = NULL;
3281
3282   if (pExistInFile) {
3283     *pExistInFile = TRUE;
3284   }
3285
3286   if (m_pDocument == NULL) {
3287     original_size = (FX_DWORD)m_parser.GetObjectSize(objnum);
3288     offset = m_parser.GetObjectOffset(objnum);
3289     pParser = &m_parser;
3290   } else {
3291     original_size = GetObjectSize(objnum, offset);
3292     pParser = (CPDF_Parser*)(m_pDocument->GetParser());
3293   }
3294
3295   pdfium::base::CheckedNumeric<FX_DWORD> size = original_size;
3296   if (size.ValueOrDefault(0) == 0 || offset < 0 || offset >= m_dwFileLen) {
3297     if (pExistInFile)
3298       *pExistInFile = FALSE;
3299
3300     return NULL;
3301   }
3302
3303   size += offset;
3304   size += 512;
3305   if (!size.IsValid()) {
3306     return NULL;
3307   }
3308
3309   if (size.ValueOrDie() > m_dwFileLen) {
3310     size = m_dwFileLen - offset;
3311   } else {
3312     size = original_size + 512;
3313   }
3314
3315   if (!size.IsValid()) {
3316     return NULL;
3317   }
3318
3319   if (!m_pFileAvail->IsDataAvail(offset, size.ValueOrDie())) {
3320     pHints->AddSegment(offset, size.ValueOrDie());
3321     return NULL;
3322   }
3323
3324   if (pParser) {
3325     pRet = pParser->ParseIndirectObject(NULL, objnum, NULL);
3326   }
3327
3328   if (!pRet && pExistInFile) {
3329     *pExistInFile = FALSE;
3330   }
3331
3332   return pRet;
3333 }
3334
3335 FX_BOOL CPDF_DataAvail::CheckInfo(IFX_DownloadHints* pHints) {
3336   FX_BOOL bExist = FALSE;
3337   CPDF_Object* pInfo = GetObject(m_dwInfoObjNum, pHints, &bExist);
3338   if (!bExist) {
3339     if (m_bHaveAcroForm) {
3340       m_docStatus = PDF_DATAAVAIL_ACROFORM;
3341     } else {
3342       m_docStatus = PDF_DATAAVAIL_PAGETREE;
3343     }
3344     return TRUE;
3345   }
3346   if (!pInfo) {
3347     if (m_docStatus == PDF_DATAAVAIL_ERROR) {
3348       m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3349       return TRUE;
3350     }
3351     if (m_Pos == m_dwFileLen) {
3352       m_docStatus = PDF_DATAAVAIL_ERROR;
3353     }
3354     return FALSE;
3355   }
3356   if (pInfo) {
3357     pInfo->Release();
3358   }
3359   if (m_bHaveAcroForm) {
3360     m_docStatus = PDF_DATAAVAIL_ACROFORM;
3361   } else {
3362     m_docStatus = PDF_DATAAVAIL_PAGETREE;
3363   }
3364   return TRUE;
3365 }
3366 FX_BOOL CPDF_DataAvail::CheckRoot(IFX_DownloadHints* pHints) {
3367   FX_BOOL bExist = FALSE;
3368   m_pRoot = GetObject(m_dwRootObjNum, pHints, &bExist);
3369   if (!bExist) {
3370     m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3371     return TRUE;
3372   }
3373   if (!m_pRoot) {
3374     if (m_docStatus == PDF_DATAAVAIL_ERROR) {
3375       m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3376       return TRUE;
3377     }
3378     return FALSE;
3379   }
3380   CPDF_Dictionary* pDict = m_pRoot->GetDict();
3381   if (!pDict) {
3382     m_docStatus = PDF_DATAAVAIL_ERROR;
3383     return FALSE;
3384   }