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