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