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