b2f7eb6d7e670205998f30ed8e3fe363c4076a51
[pdfium.git] / core / src / fpdfapi / fpdf_parser / fpdf_parser_parser.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include <set>
8 #include <utility>
9 #include <vector>
10
11 #include "../../../../third_party/base/nonstd_unique_ptr.h"
12 #include "../../../include/fpdfapi/fpdf_module.h"
13 #include "../../../include/fpdfapi/fpdf_page.h"
14 #include "../../../include/fpdfapi/fpdf_parser.h"
15 #include "../../../include/fxcrt/fx_safe_types.h"
16 #include "../fpdf_page/pageint.h"
17
18 namespace {
19
20 struct SearchTagRecord {
21   const uint8_t* m_pTag;
22   FX_DWORD m_Len;
23   FX_DWORD m_Offset;
24 };
25
26 int CompareFileSize(const void* p1, const void* p2) {
27   return *(FX_FILESIZE*)p1 - *(FX_FILESIZE*)p2;
28 }
29
30 int32_t GetHeaderOffset(IFX_FileRead* pFile) {
31   const FX_DWORD tag = FXDWORD_FROM_LSBFIRST(0x46445025);
32   const size_t kBufSize = 4;
33   uint8_t buf[kBufSize];
34   int32_t offset = 0;
35   while (offset <= 1024) {
36     if (!pFile->ReadBlock(buf, offset, kBufSize))
37       return -1;
38
39     if (*(FX_DWORD*)buf == tag)
40       return offset;
41
42     ++offset;
43   }
44   return -1;
45 }
46
47 int32_t GetDirectInteger(CPDF_Dictionary* pDict, const CFX_ByteStringC& key) {
48   CPDF_Number* pObj = ToNumber(pDict->GetElement(key));
49   return pObj ? pObj->GetInteger() : 0;
50 }
51
52 bool CheckDirectType(CPDF_Dictionary* pDict,
53                      const CFX_ByteStringC& key,
54                      int32_t iType) {
55   CPDF_Object* pObj = pDict->GetElement(key);
56   return !pObj || pObj->GetType() == iType;
57 }
58
59 FX_DWORD GetVarInt(const uint8_t* p, int32_t n) {
60   FX_DWORD result = 0;
61   for (int32_t i = 0; i < n; ++i)
62     result = result * 256 + p[i];
63   return result;
64 }
65
66 int32_t GetStreamNCount(CPDF_StreamAcc* pObjStream) {
67   return pObjStream->GetDict()->GetInteger(FX_BSTRC("N"));
68 }
69
70 int32_t GetStreamFirst(CPDF_StreamAcc* pObjStream) {
71   return pObjStream->GetDict()->GetInteger(FX_BSTRC("First"));
72 }
73
74 }  // namespace
75
76 // TODO(thestig) Using unique_ptr with ReleaseDeleter is still not ideal.
77 // Come up or wait for something better.
78 using ScopedFileStream =
79     nonstd::unique_ptr<IFX_FileStream, ReleaseDeleter<IFX_FileStream>>;
80
81 FX_BOOL IsSignatureDict(const CPDF_Dictionary* pDict) {
82   CPDF_Object* pType = pDict->GetElementValue(FX_BSTRC("Type"));
83   if (!pType) {
84     pType = pDict->GetElementValue(FX_BSTRC("FT"));
85     if (!pType) {
86       return FALSE;
87     }
88   }
89   if (pType->GetString() == FX_BSTRC("Sig")) {
90     return TRUE;
91   }
92   return FALSE;
93 }
94
95 CPDF_Parser::CPDF_Parser() {
96   m_pDocument = NULL;
97   m_pTrailer = NULL;
98   m_pEncryptDict = NULL;
99   m_pLinearized = NULL;
100   m_dwFirstPageNo = 0;
101   m_dwXrefStartObjNum = 0;
102   m_bOwnFileRead = TRUE;
103   m_FileVersion = 0;
104   m_bForceUseSecurityHandler = FALSE;
105 }
106 CPDF_Parser::~CPDF_Parser() {
107   CloseParser(FALSE);
108 }
109 FX_DWORD CPDF_Parser::GetLastObjNum() {
110   FX_DWORD dwSize = m_CrossRef.GetSize();
111   return dwSize ? dwSize - 1 : 0;
112 }
113 void CPDF_Parser::SetEncryptDictionary(CPDF_Dictionary* pDict) {
114   m_pEncryptDict = pDict;
115 }
116 void CPDF_Parser::CloseParser(FX_BOOL bReParse) {
117   m_bVersionUpdated = FALSE;
118   if (!bReParse) {
119     delete m_pDocument;
120     m_pDocument = NULL;
121   }
122   if (m_pTrailer) {
123     m_pTrailer->Release();
124     m_pTrailer = NULL;
125   }
126   ReleaseEncryptHandler();
127   SetEncryptDictionary(NULL);
128   if (m_bOwnFileRead && m_Syntax.m_pFileAccess) {
129     m_Syntax.m_pFileAccess->Release();
130     m_Syntax.m_pFileAccess = NULL;
131   }
132   FX_POSITION pos = m_ObjectStreamMap.GetStartPosition();
133   while (pos) {
134     void* objnum;
135     CPDF_StreamAcc* pStream;
136     m_ObjectStreamMap.GetNextAssoc(pos, objnum, (void*&)pStream);
137     delete pStream;
138   }
139   m_ObjectStreamMap.RemoveAll();
140   m_SortedOffset.RemoveAll();
141   m_CrossRef.RemoveAll();
142   m_V5Type.RemoveAll();
143   m_ObjVersion.RemoveAll();
144   int32_t iLen = m_Trailers.GetSize();
145   for (int32_t i = 0; i < iLen; ++i) {
146     if (CPDF_Dictionary* trailer = m_Trailers.GetAt(i))
147       trailer->Release();
148   }
149   m_Trailers.RemoveAll();
150   if (m_pLinearized) {
151     m_pLinearized->Release();
152     m_pLinearized = NULL;
153   }
154 }
155 CPDF_SecurityHandler* FPDF_CreateStandardSecurityHandler();
156 CPDF_SecurityHandler* FPDF_CreatePubKeyHandler(void*);
157 FX_DWORD CPDF_Parser::StartParse(IFX_FileRead* pFileAccess,
158                                  FX_BOOL bReParse,
159                                  FX_BOOL bOwnFileRead) {
160   CloseParser(bReParse);
161   m_bXRefStream = FALSE;
162   m_LastXRefOffset = 0;
163   m_bOwnFileRead = bOwnFileRead;
164   int32_t offset = GetHeaderOffset(pFileAccess);
165   if (offset == -1) {
166     if (bOwnFileRead && pFileAccess) {
167       pFileAccess->Release();
168     }
169     return PDFPARSE_ERROR_FORMAT;
170   }
171   m_Syntax.InitParser(pFileAccess, offset);
172   uint8_t ch;
173   if (!m_Syntax.GetCharAt(5, ch)) {
174     return PDFPARSE_ERROR_FORMAT;
175   }
176   if (ch >= '0' && ch <= '9') {
177     m_FileVersion = (ch - '0') * 10;
178   }
179   if (!m_Syntax.GetCharAt(7, ch)) {
180     return PDFPARSE_ERROR_FORMAT;
181   }
182   if (ch >= '0' && ch <= '9') {
183     m_FileVersion += ch - '0';
184   }
185   if (m_Syntax.m_FileLen < m_Syntax.m_HeaderOffset + 9) {
186     return PDFPARSE_ERROR_FORMAT;
187   }
188   m_Syntax.RestorePos(m_Syntax.m_FileLen - m_Syntax.m_HeaderOffset - 9);
189   if (!bReParse) {
190     m_pDocument = new CPDF_Document(this);
191   }
192   FX_BOOL bXRefRebuilt = FALSE;
193   if (m_Syntax.SearchWord(FX_BSTRC("startxref"), TRUE, FALSE, 4096)) {
194     FX_FILESIZE startxref_offset = m_Syntax.SavePos();
195     void* pResult = FXSYS_bsearch(&startxref_offset, m_SortedOffset.GetData(),
196                                   m_SortedOffset.GetSize(), sizeof(FX_FILESIZE),
197                                   CompareFileSize);
198     if (pResult == NULL) {
199       m_SortedOffset.Add(startxref_offset);
200     }
201     m_Syntax.GetKeyword();
202     FX_BOOL bNumber;
203     CFX_ByteString xrefpos_str = m_Syntax.GetNextWord(bNumber);
204     if (!bNumber) {
205       return PDFPARSE_ERROR_FORMAT;
206     }
207     m_LastXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str);
208     if (!LoadAllCrossRefV4(m_LastXRefOffset) &&
209         !LoadAllCrossRefV5(m_LastXRefOffset)) {
210       if (!RebuildCrossRef()) {
211         return PDFPARSE_ERROR_FORMAT;
212       }
213       bXRefRebuilt = TRUE;
214       m_LastXRefOffset = 0;
215     }
216   } else {
217     if (!RebuildCrossRef()) {
218       return PDFPARSE_ERROR_FORMAT;
219     }
220     bXRefRebuilt = TRUE;
221   }
222   FX_DWORD dwRet = SetEncryptHandler();
223   if (dwRet != PDFPARSE_ERROR_SUCCESS) {
224     return dwRet;
225   }
226   m_pDocument->LoadDoc();
227   if (m_pDocument->GetRoot() == NULL || m_pDocument->GetPageCount() == 0) {
228     if (bXRefRebuilt) {
229       return PDFPARSE_ERROR_FORMAT;
230     }
231     ReleaseEncryptHandler();
232     if (!RebuildCrossRef()) {
233       return PDFPARSE_ERROR_FORMAT;
234     }
235     dwRet = SetEncryptHandler();
236     if (dwRet != PDFPARSE_ERROR_SUCCESS) {
237       return dwRet;
238     }
239     m_pDocument->LoadDoc();
240     if (m_pDocument->GetRoot() == NULL) {
241       return PDFPARSE_ERROR_FORMAT;
242     }
243   }
244   FXSYS_qsort(m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
245               sizeof(FX_FILESIZE), CompareFileSize);
246   FX_DWORD RootObjNum = GetRootObjNum();
247   if (RootObjNum == 0) {
248     ReleaseEncryptHandler();
249     RebuildCrossRef();
250     RootObjNum = GetRootObjNum();
251     if (RootObjNum == 0) {
252       return PDFPARSE_ERROR_FORMAT;
253     }
254     dwRet = SetEncryptHandler();
255     if (dwRet != PDFPARSE_ERROR_SUCCESS) {
256       return dwRet;
257     }
258   }
259   if (m_pSecurityHandler && !m_pSecurityHandler->IsMetadataEncrypted()) {
260     CPDF_Reference* pMetadata =
261         (CPDF_Reference*)m_pDocument->GetRoot()->GetElement(
262             FX_BSTRC("Metadata"));
263     if (pMetadata && pMetadata->GetType() == PDFOBJ_REFERENCE) {
264       m_Syntax.m_MetadataObjnum = pMetadata->GetRefObjNum();
265     }
266   }
267   return PDFPARSE_ERROR_SUCCESS;
268 }
269 FX_DWORD CPDF_Parser::SetEncryptHandler() {
270   ReleaseEncryptHandler();
271   SetEncryptDictionary(NULL);
272   if (m_pTrailer == NULL) {
273     return PDFPARSE_ERROR_FORMAT;
274   }
275   CPDF_Object* pEncryptObj = m_pTrailer->GetElement(FX_BSTRC("Encrypt"));
276   if (pEncryptObj) {
277     if (CPDF_Dictionary* pEncryptDict = pEncryptObj->AsDictionary()) {
278       SetEncryptDictionary(pEncryptDict);
279     } else if (pEncryptObj->GetType() == PDFOBJ_REFERENCE) {
280       pEncryptObj = m_pDocument->GetIndirectObject(
281           ((CPDF_Reference*)pEncryptObj)->GetRefObjNum());
282       if (pEncryptObj) {
283         SetEncryptDictionary(pEncryptObj->GetDict());
284       }
285     }
286   }
287   if (m_bForceUseSecurityHandler) {
288     FX_DWORD err = PDFPARSE_ERROR_HANDLER;
289     if (!m_pSecurityHandler) {
290       return PDFPARSE_ERROR_HANDLER;
291     }
292     if (!m_pSecurityHandler->OnInit(this, m_pEncryptDict)) {
293       return err;
294     }
295     nonstd::unique_ptr<CPDF_CryptoHandler> pCryptoHandler(
296         m_pSecurityHandler->CreateCryptoHandler());
297     if (!pCryptoHandler->Init(m_pEncryptDict, m_pSecurityHandler.get())) {
298       return PDFPARSE_ERROR_HANDLER;
299     }
300     m_Syntax.SetEncrypt(pCryptoHandler.release());
301   } else if (m_pEncryptDict) {
302     CFX_ByteString filter = m_pEncryptDict->GetString(FX_BSTRC("Filter"));
303     nonstd::unique_ptr<CPDF_SecurityHandler> pSecurityHandler;
304     FX_DWORD err = PDFPARSE_ERROR_HANDLER;
305     if (filter == FX_BSTRC("Standard")) {
306       pSecurityHandler.reset(FPDF_CreateStandardSecurityHandler());
307       err = PDFPARSE_ERROR_PASSWORD;
308     }
309     if (!pSecurityHandler) {
310       return PDFPARSE_ERROR_HANDLER;
311     }
312     if (!pSecurityHandler->OnInit(this, m_pEncryptDict)) {
313       return err;
314     }
315     m_pSecurityHandler = nonstd::move(pSecurityHandler);
316     nonstd::unique_ptr<CPDF_CryptoHandler> pCryptoHandler(
317         m_pSecurityHandler->CreateCryptoHandler());
318     if (!pCryptoHandler->Init(m_pEncryptDict, m_pSecurityHandler.get())) {
319       return PDFPARSE_ERROR_HANDLER;
320     }
321     m_Syntax.SetEncrypt(pCryptoHandler.release());
322   }
323   return PDFPARSE_ERROR_SUCCESS;
324 }
325 void CPDF_Parser::ReleaseEncryptHandler() {
326   m_Syntax.m_pCryptoHandler.reset();
327   if (!m_bForceUseSecurityHandler) {
328     m_pSecurityHandler.reset();
329   }
330 }
331 FX_FILESIZE CPDF_Parser::GetObjectOffset(FX_DWORD objnum) {
332   if (objnum >= (FX_DWORD)m_CrossRef.GetSize()) {
333     return 0;
334   }
335   if (m_V5Type[objnum] == 1) {
336     return m_CrossRef[objnum];
337   }
338   if (m_V5Type[objnum] == 2) {
339     return m_CrossRef[(int32_t)m_CrossRef[objnum]];
340   }
341   return 0;
342 }
343
344 FX_BOOL CPDF_Parser::LoadAllCrossRefV4(FX_FILESIZE xrefpos) {
345   if (!LoadCrossRefV4(xrefpos, 0, TRUE, FALSE)) {
346     return FALSE;
347   }
348   m_pTrailer = LoadTrailerV4();
349   if (m_pTrailer == NULL) {
350     return FALSE;
351   }
352   int32_t xrefsize = GetDirectInteger(m_pTrailer, FX_BSTRC("Size"));
353   if (xrefsize <= 0 || xrefsize > (1 << 20)) {
354     return FALSE;
355   }
356   m_CrossRef.SetSize(xrefsize);
357   m_V5Type.SetSize(xrefsize);
358   CFX_FileSizeArray CrossRefList, XRefStreamList;
359   CrossRefList.Add(xrefpos);
360   XRefStreamList.Add(GetDirectInteger(m_pTrailer, FX_BSTRC("XRefStm")));
361   if (!CheckDirectType(m_pTrailer, FX_BSTRC("Prev"), PDFOBJ_NUMBER)) {
362     return FALSE;
363   }
364   FX_FILESIZE newxrefpos = GetDirectInteger(m_pTrailer, FX_BSTRC("Prev"));
365   if (newxrefpos == xrefpos) {
366     return FALSE;
367   }
368   xrefpos = newxrefpos;
369   while (xrefpos) {
370     CrossRefList.InsertAt(0, xrefpos);
371     LoadCrossRefV4(xrefpos, 0, TRUE, FALSE);
372     nonstd::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>> pDict(
373         LoadTrailerV4());
374     if (!pDict)
375       return FALSE;
376
377     if (!CheckDirectType(pDict.get(), FX_BSTRC("Prev"), PDFOBJ_NUMBER))
378       return FALSE;
379
380     newxrefpos = GetDirectInteger(pDict.get(), FX_BSTRC("Prev"));
381     if (newxrefpos == xrefpos)
382       return FALSE;
383
384     xrefpos = newxrefpos;
385     XRefStreamList.InsertAt(0, pDict->GetInteger(FX_BSTRC("XRefStm")));
386     m_Trailers.Add(pDict.release());
387   }
388   for (int32_t i = 0; i < CrossRefList.GetSize(); i++) {
389     if (!LoadCrossRefV4(CrossRefList[i], XRefStreamList[i], FALSE, i == 0))
390       return FALSE;
391   }
392   return TRUE;
393 }
394 FX_BOOL CPDF_Parser::LoadLinearizedAllCrossRefV4(FX_FILESIZE xrefpos,
395                                                  FX_DWORD dwObjCount) {
396   if (!LoadLinearizedCrossRefV4(xrefpos, dwObjCount)) {
397     return FALSE;
398   }
399   m_pTrailer = LoadTrailerV4();
400   if (m_pTrailer == NULL) {
401     return FALSE;
402   }
403   int32_t xrefsize = GetDirectInteger(m_pTrailer, FX_BSTRC("Size"));
404   if (xrefsize == 0) {
405     return FALSE;
406   }
407   CFX_FileSizeArray CrossRefList, XRefStreamList;
408   CrossRefList.Add(xrefpos);
409   XRefStreamList.Add(GetDirectInteger(m_pTrailer, FX_BSTRC("XRefStm")));
410   xrefpos = GetDirectInteger(m_pTrailer, FX_BSTRC("Prev"));
411   while (xrefpos) {
412     CrossRefList.InsertAt(0, xrefpos);
413     LoadCrossRefV4(xrefpos, 0, TRUE, FALSE);
414     CPDF_Dictionary* pDict = LoadTrailerV4();
415     if (pDict == NULL) {
416       return FALSE;
417     }
418     xrefpos = GetDirectInteger(pDict, FX_BSTRC("Prev"));
419     XRefStreamList.InsertAt(0, pDict->GetInteger(FX_BSTRC("XRefStm")));
420     m_Trailers.Add(pDict);
421   }
422   for (int32_t i = 1; i < CrossRefList.GetSize(); i++)
423     if (!LoadCrossRefV4(CrossRefList[i], XRefStreamList[i], FALSE, i == 0)) {
424       return FALSE;
425     }
426   return TRUE;
427 }
428 FX_BOOL CPDF_Parser::LoadLinearizedCrossRefV4(FX_FILESIZE pos,
429                                               FX_DWORD dwObjCount) {
430   FX_FILESIZE dwStartPos = pos - m_Syntax.m_HeaderOffset;
431   m_Syntax.RestorePos(dwStartPos);
432   void* pResult =
433       FXSYS_bsearch(&pos, m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
434                     sizeof(FX_FILESIZE), CompareFileSize);
435   if (pResult == NULL) {
436     m_SortedOffset.Add(pos);
437   }
438   FX_DWORD start_objnum = 0;
439   FX_DWORD count = dwObjCount;
440   FX_FILESIZE SavedPos = m_Syntax.SavePos();
441   const int32_t recordsize = 20;
442   std::vector<char> buf(1024 * recordsize + 1);
443   buf[1024 * recordsize] = '\0';
444   int32_t nBlocks = count / 1024 + 1;
445   for (int32_t block = 0; block < nBlocks; block++) {
446     int32_t block_size = block == nBlocks - 1 ? count % 1024 : 1024;
447     FX_DWORD dwReadSize = block_size * recordsize;
448     if ((FX_FILESIZE)(dwStartPos + dwReadSize) > m_Syntax.m_FileLen) {
449       return FALSE;
450     }
451     if (!m_Syntax.ReadBlock((uint8_t*)buf.data(), dwReadSize)) {
452       return FALSE;
453     }
454     for (int32_t i = 0; i < block_size; i++) {
455       FX_DWORD objnum = start_objnum + block * 1024 + i;
456       char* pEntry = buf.data() + i * recordsize;
457       if (pEntry[17] == 'f') {
458         m_CrossRef.SetAtGrow(objnum, 0);
459         m_V5Type.SetAtGrow(objnum, 0);
460       } else {
461         int32_t offset = FXSYS_atoi(pEntry);
462         if (offset == 0) {
463           for (int32_t c = 0; c < 10; c++) {
464             if (pEntry[c] < '0' || pEntry[c] > '9') {
465               return FALSE;
466             }
467           }
468         }
469         m_CrossRef.SetAtGrow(objnum, offset);
470         int32_t version = FXSYS_atoi(pEntry + 11);
471         if (version >= 1) {
472           m_bVersionUpdated = TRUE;
473         }
474         m_ObjVersion.SetAtGrow(objnum, version);
475         if (m_CrossRef[objnum] < m_Syntax.m_FileLen) {
476           void* pResult = FXSYS_bsearch(
477               &m_CrossRef[objnum], m_SortedOffset.GetData(),
478               m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), CompareFileSize);
479           if (pResult == NULL) {
480             m_SortedOffset.Add(m_CrossRef[objnum]);
481           }
482         }
483         m_V5Type.SetAtGrow(objnum, 1);
484       }
485     }
486   }
487   m_Syntax.RestorePos(SavedPos + count * recordsize);
488   return TRUE;
489 }
490
491 bool CPDF_Parser::FindPosInOffsets(FX_FILESIZE pos) const {
492   return FXSYS_bsearch(&pos, m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
493                        sizeof(FX_FILESIZE), CompareFileSize);
494 }
495
496 bool CPDF_Parser::LoadCrossRefV4(FX_FILESIZE pos,
497                                  FX_FILESIZE streampos,
498                                  FX_BOOL bSkip,
499                                  FX_BOOL bFirst) {
500   m_Syntax.RestorePos(pos);
501   if (m_Syntax.GetKeyword() != FX_BSTRC("xref"))
502     return false;
503
504   if (!FindPosInOffsets(pos))
505     m_SortedOffset.Add(pos);
506
507   if (streampos && !FindPosInOffsets(streampos))
508       m_SortedOffset.Add(streampos);
509
510   while (1) {
511     FX_FILESIZE SavedPos = m_Syntax.SavePos();
512     FX_BOOL bIsNumber;
513     CFX_ByteString word = m_Syntax.GetNextWord(bIsNumber);
514     if (word.IsEmpty())
515       return false;
516
517     if (!bIsNumber) {
518       m_Syntax.RestorePos(SavedPos);
519       break;
520     }
521     FX_DWORD start_objnum = FXSYS_atoi(word);
522     if (start_objnum >= (1 << 20))
523       return false;
524
525     FX_DWORD count = m_Syntax.GetDirectNum();
526     m_Syntax.ToNextWord();
527     SavedPos = m_Syntax.SavePos();
528     FX_BOOL bFirstItem = FALSE;
529     const int32_t recordsize = 20;
530     if (bFirst)
531       bFirstItem = TRUE;
532     m_dwXrefStartObjNum = start_objnum;
533     if (!bSkip) {
534       std::vector<char> buf(1024 * recordsize + 1);
535       buf[1024 * recordsize] = '\0';
536       int32_t nBlocks = count / 1024 + 1;
537       FX_BOOL bFirstBlock = TRUE;
538       for (int32_t block = 0; block < nBlocks; block++) {
539         int32_t block_size = block == nBlocks - 1 ? count % 1024 : 1024;
540         m_Syntax.ReadBlock((uint8_t*)buf.data(), 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 = buf.data() + 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                       if (pRoot == NULL ||
844                           (pRoot->GetType() == PDFOBJ_REFERENCE &&
845                            (FX_DWORD)m_CrossRef.GetSize() >
846                                ((CPDF_Reference*)pRoot)->GetRefObjNum() &&
847                            m_CrossRef.GetAt(((CPDF_Reference*)pRoot)
848                                                 ->GetRefObjNum()) != 0)) {
849                         FX_POSITION pos = pTrailer->GetStartPos();
850                         while (pos) {
851                           CFX_ByteString key;
852                           CPDF_Object* pObj =
853                               pTrailer->GetNextElement(pos, key);
854                           m_pTrailer->SetAt(key, pObj->Clone(), m_pDocument);
855                         }
856                         pObj->Release();
857                       } else {
858                         pObj->Release();
859                       }
860                     } else {
861                       if (pObj->IsStream()) {
862                         m_pTrailer = ToDictionary(pTrailer->Clone());
863                         pObj->Release();
864                       } else {
865                         m_pTrailer = pTrailer;
866                       }
867                       FX_FILESIZE dwSavePos = m_Syntax.SavePos();
868                       CFX_ByteString strWord = m_Syntax.GetKeyword();
869                       if (!strWord.Compare(FX_BSTRC("startxref"))) {
870                         FX_BOOL bNumber = FALSE;
871                         CFX_ByteString bsOffset = m_Syntax.GetNextWord(bNumber);
872                         if (bNumber) {
873                           m_LastXRefOffset = FXSYS_atoi(bsOffset);
874                         }
875                       }
876                       m_Syntax.RestorePos(dwSavePos);
877                     }
878                   } else {
879                     pObj->Release();
880                   }
881                 }
882               }
883             }
884             --i;
885             status = 0;
886           } else if (byte == "trailer"[inside_index]) {
887             inside_index++;
888           } else {
889             --i;
890             status = 0;
891           }
892           break;
893         case 8:
894           if (inside_index == 4) {
895             last_xref = pos + i - 4;
896             status = 1;
897           } else if (byte == "xref"[inside_index]) {
898             inside_index++;
899           } else {
900             --i;
901             status = 0;
902           }
903           break;
904         case 9:
905           if (byte == '\r' || byte == '\n') {
906             status = 0;
907           }
908           break;
909         case 10:
910           if (byte == ')') {
911             if (depth > 0) {
912               depth--;
913             }
914           } else if (byte == '(') {
915             depth++;
916           }
917           if (!depth) {
918             status = 0;
919           }
920           break;
921         case 11:
922           if (byte == '<' && inside_index == 1) {
923             status = 12;
924           } else if (byte == '>') {
925             status = 0;
926           }
927           inside_index = 0;
928           break;
929         case 12:
930           --i;
931           status = 0;
932           break;
933         case 13:
934           if (PDF_CharType[byte] == 'D' || PDF_CharType[byte] == 'W') {
935             --i;
936             status = 0;
937           }
938           break;
939         case 14:
940           if (PDF_CharType[byte] == 'W') {
941             status = 0;
942           } else if (byte == '%' || byte == '(' || byte == '<' ||
943                      byte == '\\') {
944             status = 0;
945             --i;
946           } else if (inside_index == 6) {
947             status = 0;
948             --i;
949           } else if (byte == "endobj"[inside_index]) {
950             inside_index++;
951           }
952           break;
953       }
954       if (bOverFlow) {
955         size = 0;
956         break;
957       }
958     }
959     pos += size;
960   }
961   if (last_xref != -1 && last_xref > last_obj) {
962     last_trailer = last_xref;
963   } else if (last_trailer == -1 || last_xref < last_obj) {
964     last_trailer = m_Syntax.m_FileLen;
965   }
966   FX_FILESIZE offset = last_trailer - m_Syntax.m_HeaderOffset;
967   void* pResult =
968       FXSYS_bsearch(&offset, m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
969                     sizeof(FX_FILESIZE), CompareFileSize);
970   if (pResult == NULL) {
971     m_SortedOffset.Add(offset);
972   }
973   FX_Free(buffer);
974   return TRUE;
975 }
976
977 FX_BOOL CPDF_Parser::LoadCrossRefV5(FX_FILESIZE pos,
978                                     FX_FILESIZE& prev,
979                                     FX_BOOL bMainXRef) {
980   CPDF_Object* pObject = ParseIndirectObjectAt(m_pDocument, pos, 0, nullptr);
981   if (!pObject)
982     return FALSE;
983
984   if (m_pDocument) {
985     CPDF_Dictionary* pDict = m_pDocument->GetRoot();
986     if (!pDict || pDict->GetObjNum() != pObject->m_ObjNum) {
987       m_pDocument->InsertIndirectObject(pObject->m_ObjNum, pObject);
988     } else {
989       if (pObject->IsStream())
990         pObject->Release();
991       return FALSE;
992     }
993   }
994
995   CPDF_Stream* pStream = pObject->AsStream();
996   if (!pStream)
997     return FALSE;
998
999   prev = pStream->GetDict()->GetInteger(FX_BSTRC("Prev"));
1000   int32_t size = pStream->GetDict()->GetInteger(FX_BSTRC("Size"));
1001   if (size < 0) {
1002     pStream->Release();
1003     return FALSE;
1004   }
1005   if (bMainXRef) {
1006     m_pTrailer = ToDictionary(pStream->GetDict()->Clone());
1007     m_CrossRef.SetSize(size);
1008     if (m_V5Type.SetSize(size)) {
1009       FXSYS_memset(m_V5Type.GetData(), 0, size);
1010     }
1011   } else {
1012     m_Trailers.Add(ToDictionary(pStream->GetDict()->Clone()));
1013   }
1014   std::vector<std::pair<int32_t, int32_t> > arrIndex;
1015   CPDF_Array* pArray = pStream->GetDict()->GetArray(FX_BSTRC("Index"));
1016   if (pArray) {
1017     FX_DWORD nPairSize = pArray->GetCount() / 2;
1018     for (FX_DWORD i = 0; i < nPairSize; i++) {
1019       CPDF_Object* pStartNumObj = pArray->GetElement(i * 2);
1020       CPDF_Object* pCountObj = pArray->GetElement(i * 2 + 1);
1021       if (ToNumber(pStartNumObj) && ToNumber(pCountObj)) {
1022         int nStartNum = pStartNumObj->GetInteger();
1023         int nCount = pCountObj->GetInteger();
1024         if (nStartNum >= 0 && nCount > 0) {
1025           arrIndex.push_back(std::make_pair(nStartNum, nCount));
1026         }
1027       }
1028     }
1029   }
1030   if (arrIndex.size() == 0) {
1031     arrIndex.push_back(std::make_pair(0, size));
1032   }
1033   pArray = pStream->GetDict()->GetArray(FX_BSTRC("W"));
1034   if (pArray == NULL) {
1035     pStream->Release();
1036     return FALSE;
1037   }
1038   CFX_DWordArray WidthArray;
1039   FX_SAFE_DWORD dwAccWidth = 0;
1040   for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
1041     WidthArray.Add(pArray->GetInteger(i));
1042     dwAccWidth += WidthArray[i];
1043   }
1044   if (!dwAccWidth.IsValid() || WidthArray.GetSize() < 3) {
1045     pStream->Release();
1046     return FALSE;
1047   }
1048   FX_DWORD totalWidth = dwAccWidth.ValueOrDie();
1049   CPDF_StreamAcc acc;
1050   acc.LoadAllData(pStream);
1051   const uint8_t* pData = acc.GetData();
1052   FX_DWORD dwTotalSize = acc.GetSize();
1053   FX_DWORD segindex = 0;
1054   for (FX_DWORD i = 0; i < arrIndex.size(); i++) {
1055     int32_t startnum = arrIndex[i].first;
1056     if (startnum < 0) {
1057       continue;
1058     }
1059     m_dwXrefStartObjNum =
1060         pdfium::base::checked_cast<FX_DWORD, int32_t>(startnum);
1061     FX_DWORD count =
1062         pdfium::base::checked_cast<FX_DWORD, int32_t>(arrIndex[i].second);
1063     FX_SAFE_DWORD dwCaculatedSize = segindex;
1064     dwCaculatedSize += count;
1065     dwCaculatedSize *= totalWidth;
1066     if (!dwCaculatedSize.IsValid() ||
1067         dwCaculatedSize.ValueOrDie() > dwTotalSize) {
1068       continue;
1069     }
1070     const uint8_t* segstart = pData + segindex * totalWidth;
1071     FX_SAFE_DWORD dwMaxObjNum = startnum;
1072     dwMaxObjNum += count;
1073     FX_DWORD dwV5Size =
1074         pdfium::base::checked_cast<FX_DWORD, int32_t>(m_V5Type.GetSize());
1075     if (!dwMaxObjNum.IsValid() || dwMaxObjNum.ValueOrDie() > dwV5Size) {
1076       continue;
1077     }
1078     for (FX_DWORD j = 0; j < count; j++) {
1079       int32_t type = 1;
1080       const uint8_t* entrystart = segstart + j * totalWidth;
1081       if (WidthArray[0]) {
1082         type = GetVarInt(entrystart, WidthArray[0]);
1083       }
1084       if (m_V5Type[startnum + j] == 255) {
1085         FX_FILESIZE offset =
1086             GetVarInt(entrystart + WidthArray[0], WidthArray[1]);
1087         m_CrossRef[startnum + j] = offset;
1088         void* pResult = FXSYS_bsearch(&offset, m_SortedOffset.GetData(),
1089                                       m_SortedOffset.GetSize(),
1090                                       sizeof(FX_FILESIZE), CompareFileSize);
1091         if (pResult == NULL) {
1092           m_SortedOffset.Add(offset);
1093         }
1094         continue;
1095       }
1096       if (m_V5Type[startnum + j]) {
1097         continue;
1098       }
1099       m_V5Type[startnum + j] = type;
1100       if (type == 0) {
1101         m_CrossRef[startnum + j] = 0;
1102       } else {
1103         FX_FILESIZE offset =
1104             GetVarInt(entrystart + WidthArray[0], WidthArray[1]);
1105         m_CrossRef[startnum + j] = offset;
1106         if (type == 1) {
1107           void* pResult = FXSYS_bsearch(&offset, m_SortedOffset.GetData(),
1108                                         m_SortedOffset.GetSize(),
1109                                         sizeof(FX_FILESIZE), CompareFileSize);
1110           if (pResult == NULL) {
1111             m_SortedOffset.Add(offset);
1112           }
1113         } else {
1114           if (offset < 0 || offset >= m_V5Type.GetSize()) {
1115             pStream->Release();
1116             return FALSE;
1117           }
1118           m_V5Type[offset] = 255;
1119         }
1120       }
1121     }
1122     segindex += count;
1123   }
1124   pStream->Release();
1125   return TRUE;
1126 }
1127 CPDF_Array* CPDF_Parser::GetIDArray() {
1128   CPDF_Object* pID = m_pTrailer ? m_pTrailer->GetElement(FX_BSTRC("ID")) : NULL;
1129   if (!pID)
1130     return nullptr;
1131
1132   if (pID->GetType() == PDFOBJ_REFERENCE) {
1133     pID = ParseIndirectObject(NULL, ((CPDF_Reference*)pID)->GetRefObjNum());
1134     m_pTrailer->SetAt(FX_BSTRC("ID"), pID);
1135   }
1136   return ToArray(pID);
1137 }
1138 FX_DWORD CPDF_Parser::GetRootObjNum() {
1139   CPDF_Object* pRef =
1140       m_pTrailer ? m_pTrailer->GetElement(FX_BSTRC("Root")) : NULL;
1141   if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) {
1142     return 0;
1143   }
1144   return ((CPDF_Reference*)pRef)->GetRefObjNum();
1145 }
1146 FX_DWORD CPDF_Parser::GetInfoObjNum() {
1147   CPDF_Object* pRef =
1148       m_pTrailer ? m_pTrailer->GetElement(FX_BSTRC("Info")) : NULL;
1149   if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) {
1150     return 0;
1151   }
1152   return ((CPDF_Reference*)pRef)->GetRefObjNum();
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     CPDF_Object* pMetadata =
1621         m_pDocument->GetRoot()->GetElement(FX_BSTRC("Metadata"));
1622     if (pMetadata && pMetadata->GetType() == PDFOBJ_REFERENCE) {
1623       m_Syntax.m_MetadataObjnum = ((CPDF_Reference*)pMetadata)->GetRefObjNum();
1624     }
1625   }
1626   return PDFPARSE_ERROR_SUCCESS;
1627 }
1628 FX_BOOL CPDF_Parser::LoadLinearizedAllCrossRefV5(FX_FILESIZE xrefpos) {
1629   if (!LoadCrossRefV5(xrefpos, xrefpos, FALSE)) {
1630     return FALSE;
1631   }
1632   while (xrefpos)
1633     if (!LoadCrossRefV5(xrefpos, xrefpos, FALSE)) {
1634       return FALSE;
1635     }
1636   m_ObjectStreamMap.InitHashTable(101, FALSE);
1637   m_bXRefStream = TRUE;
1638   return TRUE;
1639 }
1640 FX_DWORD CPDF_Parser::LoadLinearizedMainXRefTable() {
1641   FX_DWORD dwSaveMetadataObjnum = m_Syntax.m_MetadataObjnum;
1642   m_Syntax.m_MetadataObjnum = 0;
1643   if (m_pTrailer) {
1644     m_pTrailer->Release();
1645     m_pTrailer = NULL;
1646   }
1647   m_Syntax.RestorePos(m_LastXRefOffset - m_Syntax.m_HeaderOffset);
1648   uint8_t ch = 0;
1649   FX_DWORD dwCount = 0;
1650   m_Syntax.GetNextChar(ch);
1651   int32_t type = PDF_CharType[ch];
1652   while (type == 'W') {
1653     ++dwCount;
1654     if (m_Syntax.m_FileLen >=
1655         (FX_FILESIZE)(m_Syntax.SavePos() + m_Syntax.m_HeaderOffset)) {
1656       break;
1657     }
1658     m_Syntax.GetNextChar(ch);
1659     type = PDF_CharType[ch];
1660   }
1661   m_LastXRefOffset += dwCount;
1662   FX_POSITION pos = m_ObjectStreamMap.GetStartPosition();
1663   while (pos) {
1664     void* objnum;
1665     CPDF_StreamAcc* pStream;
1666     m_ObjectStreamMap.GetNextAssoc(pos, objnum, (void*&)pStream);
1667     delete pStream;
1668   }
1669   m_ObjectStreamMap.RemoveAll();
1670   if (!LoadLinearizedAllCrossRefV4(m_LastXRefOffset, m_dwXrefStartObjNum) &&
1671       !LoadLinearizedAllCrossRefV5(m_LastXRefOffset)) {
1672     m_LastXRefOffset = 0;
1673     m_Syntax.m_MetadataObjnum = dwSaveMetadataObjnum;
1674     return PDFPARSE_ERROR_FORMAT;
1675   }
1676   FXSYS_qsort(m_SortedOffset.GetData(), m_SortedOffset.GetSize(),
1677               sizeof(FX_FILESIZE), CompareFileSize);
1678   m_Syntax.m_MetadataObjnum = dwSaveMetadataObjnum;
1679   return PDFPARSE_ERROR_SUCCESS;
1680 }
1681
1682 // static
1683 int CPDF_SyntaxParser::s_CurrentRecursionDepth = 0;
1684
1685 CPDF_SyntaxParser::CPDF_SyntaxParser() {
1686   m_pFileAccess = NULL;
1687   m_pFileBuf = NULL;
1688   m_BufSize = CPDF_ModuleMgr::kFileBufSize;
1689   m_pFileBuf = NULL;
1690   m_MetadataObjnum = 0;
1691   m_dwWordPos = 0;
1692   m_bFileStream = FALSE;
1693 }
1694 CPDF_SyntaxParser::~CPDF_SyntaxParser() {
1695   FX_Free(m_pFileBuf);
1696 }
1697
1698 FX_BOOL CPDF_SyntaxParser::GetCharAt(FX_FILESIZE pos, uint8_t& ch) {
1699   CFX_AutoRestorer<FX_FILESIZE> save_pos(&m_Pos);
1700   m_Pos = pos;
1701   return GetNextChar(ch);
1702 }
1703
1704 FX_BOOL CPDF_SyntaxParser::GetNextChar(uint8_t& ch) {
1705   FX_FILESIZE pos = m_Pos + m_HeaderOffset;
1706   if (pos >= m_FileLen) {
1707     return FALSE;
1708   }
1709   if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) {
1710     FX_FILESIZE read_pos = pos;
1711     FX_DWORD read_size = m_BufSize;
1712     if ((FX_FILESIZE)read_size > m_FileLen) {
1713       read_size = (FX_DWORD)m_FileLen;
1714     }
1715     if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) {
1716       if (m_FileLen < (FX_FILESIZE)read_size) {
1717         read_pos = 0;
1718         read_size = (FX_DWORD)m_FileLen;
1719       } else {
1720         read_pos = m_FileLen - read_size;
1721       }
1722     }
1723     if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size)) {
1724       return FALSE;
1725     }
1726     m_BufOffset = read_pos;
1727   }
1728   ch = m_pFileBuf[pos - m_BufOffset];
1729   m_Pos++;
1730   return TRUE;
1731 }
1732 FX_BOOL CPDF_SyntaxParser::GetCharAtBackward(FX_FILESIZE pos, uint8_t& ch) {
1733   pos += m_HeaderOffset;
1734   if (pos >= m_FileLen) {
1735     return FALSE;
1736   }
1737   if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) {
1738     FX_FILESIZE read_pos;
1739     if (pos < (FX_FILESIZE)m_BufSize) {
1740       read_pos = 0;
1741     } else {
1742       read_pos = pos - m_BufSize + 1;
1743     }
1744     FX_DWORD read_size = m_BufSize;
1745     if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) {
1746       if (m_FileLen < (FX_FILESIZE)read_size) {
1747         read_pos = 0;
1748         read_size = (FX_DWORD)m_FileLen;
1749       } else {
1750         read_pos = m_FileLen - read_size;
1751       }
1752     }
1753     if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size)) {
1754       return FALSE;
1755     }
1756     m_BufOffset = read_pos;
1757   }
1758   ch = m_pFileBuf[pos - m_BufOffset];
1759   return TRUE;
1760 }
1761 FX_BOOL CPDF_SyntaxParser::ReadBlock(uint8_t* pBuf, FX_DWORD size) {
1762   if (!m_pFileAccess->ReadBlock(pBuf, m_Pos + m_HeaderOffset, size)) {
1763     return FALSE;
1764   }
1765   m_Pos += size;
1766   return TRUE;
1767 }
1768 #define MAX_WORD_BUFFER 256
1769 void CPDF_SyntaxParser::GetNextWord() {
1770   m_WordSize = 0;
1771   m_bIsNumber = TRUE;
1772   uint8_t ch;
1773   if (!GetNextChar(ch)) {
1774     return;
1775   }
1776   uint8_t type = PDF_CharType[ch];
1777   while (1) {
1778     while (type == 'W') {
1779       if (!GetNextChar(ch)) {
1780         return;
1781       }
1782       type = PDF_CharType[ch];
1783     }
1784     if (ch != '%') {
1785       break;
1786     }
1787     while (1) {
1788       if (!GetNextChar(ch)) {
1789         return;
1790       }
1791       if (ch == '\r' || ch == '\n') {
1792         break;
1793       }
1794     }
1795     type = PDF_CharType[ch];
1796   }
1797   if (type == 'D') {
1798     m_bIsNumber = FALSE;
1799     m_WordBuffer[m_WordSize++] = ch;
1800     if (ch == '/') {
1801       while (1) {
1802         if (!GetNextChar(ch)) {
1803           return;
1804         }
1805         type = PDF_CharType[ch];
1806         if (type != 'R' && type != 'N') {
1807           m_Pos--;
1808           return;
1809         }
1810         if (m_WordSize < MAX_WORD_BUFFER) {
1811           m_WordBuffer[m_WordSize++] = ch;
1812         }
1813       }
1814     } else if (ch == '<') {
1815       if (!GetNextChar(ch)) {
1816         return;
1817       }
1818       if (ch == '<') {
1819         m_WordBuffer[m_WordSize++] = ch;
1820       } else {
1821         m_Pos--;
1822       }
1823     } else if (ch == '>') {
1824       if (!GetNextChar(ch)) {
1825         return;
1826       }
1827       if (ch == '>') {
1828         m_WordBuffer[m_WordSize++] = ch;
1829       } else {
1830         m_Pos--;
1831       }
1832     }
1833     return;
1834   }
1835   while (1) {
1836     if (m_WordSize < MAX_WORD_BUFFER) {
1837       m_WordBuffer[m_WordSize++] = ch;
1838     }
1839     if (type != 'N') {
1840       m_bIsNumber = FALSE;
1841     }
1842     if (!GetNextChar(ch)) {
1843       return;
1844     }
1845     type = PDF_CharType[ch];
1846     if (type == 'D' || type == 'W') {
1847       m_Pos--;
1848       break;
1849     }
1850   }
1851 }
1852 CFX_ByteString CPDF_SyntaxParser::ReadString() {
1853   uint8_t ch;
1854   if (!GetNextChar(ch)) {
1855     return CFX_ByteString();
1856   }
1857   CFX_ByteTextBuf buf;
1858   int32_t parlevel = 0;
1859   int32_t status = 0, iEscCode = 0;
1860   while (1) {
1861     switch (status) {
1862       case 0:
1863         if (ch == ')') {
1864           if (parlevel == 0) {
1865             return buf.GetByteString();
1866           }
1867           parlevel--;
1868           buf.AppendChar(')');
1869         } else if (ch == '(') {
1870           parlevel++;
1871           buf.AppendChar('(');
1872         } else if (ch == '\\') {
1873           status = 1;
1874         } else {
1875           buf.AppendChar(ch);
1876         }
1877         break;
1878       case 1:
1879         if (ch >= '0' && ch <= '7') {
1880           iEscCode = ch - '0';
1881           status = 2;
1882           break;
1883         }
1884         if (ch == 'n') {
1885           buf.AppendChar('\n');
1886         } else if (ch == 'r') {
1887           buf.AppendChar('\r');
1888         } else if (ch == 't') {
1889           buf.AppendChar('\t');
1890         } else if (ch == 'b') {
1891           buf.AppendChar('\b');
1892         } else if (ch == 'f') {
1893           buf.AppendChar('\f');
1894         } else if (ch == '\r') {
1895           status = 4;
1896           break;
1897         } else if (ch == '\n') {
1898         } else {
1899           buf.AppendChar(ch);
1900         }
1901         status = 0;
1902         break;
1903       case 2:
1904         if (ch >= '0' && ch <= '7') {
1905           iEscCode = iEscCode * 8 + ch - '0';
1906           status = 3;
1907         } else {
1908           buf.AppendChar(iEscCode);
1909           status = 0;
1910           continue;
1911         }
1912         break;
1913       case 3:
1914         if (ch >= '0' && ch <= '7') {
1915           iEscCode = iEscCode * 8 + ch - '0';
1916           buf.AppendChar(iEscCode);
1917           status = 0;
1918         } else {
1919           buf.AppendChar(iEscCode);
1920           status = 0;
1921           continue;
1922         }
1923         break;
1924       case 4:
1925         status = 0;
1926         if (ch != '\n') {
1927           continue;
1928         }
1929         break;
1930     }
1931     if (!GetNextChar(ch)) {
1932       break;
1933     }
1934   }
1935   GetNextChar(ch);
1936   return buf.GetByteString();
1937 }
1938 CFX_ByteString CPDF_SyntaxParser::ReadHexString() {
1939   uint8_t ch;
1940   if (!GetNextChar(ch)) {
1941     return CFX_ByteString();
1942   }
1943   CFX_BinaryBuf buf;
1944   FX_BOOL bFirst = TRUE;
1945   uint8_t code = 0;
1946   while (1) {
1947     if (ch == '>') {
1948       break;
1949     }
1950     if (ch >= '0' && ch <= '9') {
1951       if (bFirst) {
1952         code = (ch - '0') * 16;
1953       } else {
1954         code += ch - '0';
1955         buf.AppendByte((uint8_t)code);
1956       }
1957       bFirst = !bFirst;
1958     } else if (ch >= 'A' && ch <= 'F') {
1959       if (bFirst) {
1960         code = (ch - 'A' + 10) * 16;
1961       } else {
1962         code += ch - 'A' + 10;
1963         buf.AppendByte((uint8_t)code);
1964       }
1965       bFirst = !bFirst;
1966     } else if (ch >= 'a' && ch <= 'f') {
1967       if (bFirst) {
1968         code = (ch - 'a' + 10) * 16;
1969       } else {
1970         code += ch - 'a' + 10;
1971         buf.AppendByte((uint8_t)code);
1972       }
1973       bFirst = !bFirst;
1974     }
1975     if (!GetNextChar(ch)) {
1976       break;
1977     }
1978   }
1979   if (!bFirst) {
1980     buf.AppendByte((uint8_t)code);
1981   }
1982   return buf.GetByteString();
1983 }
1984 void CPDF_SyntaxParser::ToNextLine() {
1985   uint8_t ch;
1986   while (GetNextChar(ch)) {
1987     if (ch == '\n') {
1988       break;
1989     }
1990     if (ch == '\r') {
1991       GetNextChar(ch);
1992       if (ch != '\n') {
1993         --m_Pos;
1994       }
1995       break;
1996     }
1997   }
1998 }
1999 void CPDF_SyntaxParser::ToNextWord() {
2000   uint8_t ch;
2001   if (!GetNextChar(ch)) {
2002     return;
2003   }
2004   uint8_t type = PDF_CharType[ch];
2005   while (1) {
2006     while (type == 'W') {
2007       m_dwWordPos = m_Pos;
2008       if (!GetNextChar(ch)) {
2009         return;
2010       }
2011       type = PDF_CharType[ch];
2012     }
2013     if (ch != '%') {
2014       break;
2015     }
2016     while (1) {
2017       if (!GetNextChar(ch)) {
2018         return;
2019       }
2020       if (ch == '\r' || ch == '\n') {
2021         break;
2022       }
2023     }
2024     type = PDF_CharType[ch];
2025   }
2026   m_Pos--;
2027 }
2028 CFX_ByteString CPDF_SyntaxParser::GetNextWord(FX_BOOL& bIsNumber) {
2029   GetNextWord();
2030   bIsNumber = m_bIsNumber;
2031   return CFX_ByteString((const FX_CHAR*)m_WordBuffer, m_WordSize);
2032 }
2033 CFX_ByteString CPDF_SyntaxParser::GetKeyword() {
2034   GetNextWord();
2035   return CFX_ByteString((const FX_CHAR*)m_WordBuffer, m_WordSize);
2036 }
2037 CPDF_Object* CPDF_SyntaxParser::GetObject(CPDF_IndirectObjects* pObjList,
2038                                           FX_DWORD objnum,
2039                                           FX_DWORD gennum,
2040                                           PARSE_CONTEXT* pContext,
2041                                           FX_BOOL bDecrypt) {
2042   CFX_AutoRestorer<int> restorer(&s_CurrentRecursionDepth);
2043   if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth) {
2044     return NULL;
2045   }
2046   FX_FILESIZE SavedPos = m_Pos;
2047   FX_BOOL bTypeOnly = pContext && (pContext->m_Flags & PDFPARSE_TYPEONLY);
2048   FX_BOOL bIsNumber;
2049   CFX_ByteString word = GetNextWord(bIsNumber);
2050   if (word.GetLength() == 0) {
2051     if (bTypeOnly) {
2052       return (CPDF_Object*)PDFOBJ_INVALID;
2053     }
2054     return NULL;
2055   }
2056   if (bIsNumber) {
2057     FX_FILESIZE SavedPos = m_Pos;
2058     CFX_ByteString nextword = GetNextWord(bIsNumber);
2059     if (bIsNumber) {
2060       CFX_ByteString nextword2 = GetNextWord(bIsNumber);
2061       if (nextword2 == FX_BSTRC("R")) {
2062         FX_DWORD objnum = FXSYS_atoi(word);
2063         if (bTypeOnly) {
2064           return (CPDF_Object*)PDFOBJ_REFERENCE;
2065         }
2066         return new CPDF_Reference(pObjList, objnum);
2067       }
2068     }
2069     m_Pos = SavedPos;
2070     if (bTypeOnly) {
2071       return (CPDF_Object*)PDFOBJ_NUMBER;
2072     }
2073     return CPDF_Number::Create(word);
2074   }
2075   if (word == FX_BSTRC("true") || word == FX_BSTRC("false")) {
2076     if (bTypeOnly) {
2077       return (CPDF_Object*)PDFOBJ_BOOLEAN;
2078     }
2079     return CPDF_Boolean::Create(word == FX_BSTRC("true"));
2080   }
2081   if (word == FX_BSTRC("null")) {
2082     if (bTypeOnly) {
2083       return (CPDF_Object*)PDFOBJ_NULL;
2084     }
2085     return CPDF_Null::Create();
2086   }
2087   if (word == FX_BSTRC("(")) {
2088     if (bTypeOnly) {
2089       return (CPDF_Object*)PDFOBJ_STRING;
2090     }
2091     CFX_ByteString str = ReadString();
2092     if (m_pCryptoHandler && bDecrypt) {
2093       m_pCryptoHandler->Decrypt(objnum, gennum, str);
2094     }
2095     return CPDF_String::Create(str, FALSE);
2096   }
2097   if (word == FX_BSTRC("<")) {
2098     if (bTypeOnly) {
2099       return (CPDF_Object*)PDFOBJ_STRING;
2100     }
2101     CFX_ByteString str = ReadHexString();
2102     if (m_pCryptoHandler && bDecrypt) {
2103       m_pCryptoHandler->Decrypt(objnum, gennum, str);
2104     }
2105     return CPDF_String::Create(str, TRUE);
2106   }
2107   if (word == FX_BSTRC("[")) {
2108     if (bTypeOnly) {
2109       return (CPDF_Object*)PDFOBJ_ARRAY;
2110     }
2111     CPDF_Array* pArray = CPDF_Array::Create();
2112     while (CPDF_Object* pObj = GetObject(pObjList, objnum, gennum))
2113       pArray->Add(pObj);
2114
2115     return pArray;
2116   }
2117   if (word[0] == '/') {
2118     if (bTypeOnly) {
2119       return (CPDF_Object*)PDFOBJ_NAME;
2120     }
2121     return CPDF_Name::Create(
2122         PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)));
2123   }
2124   if (word == FX_BSTRC("<<")) {
2125     if (bTypeOnly)
2126       return (CPDF_Object*)PDFOBJ_DICTIONARY;
2127
2128     if (pContext)
2129       pContext->m_DictStart = SavedPos;
2130
2131     int32_t nKeys = 0;
2132     FX_FILESIZE dwSignValuePos = 0;
2133     nonstd::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>> pDict(
2134         CPDF_Dictionary::Create());
2135     while (1) {
2136       FX_BOOL bIsNumber;
2137       CFX_ByteString key = GetNextWord(bIsNumber);
2138       if (key.IsEmpty())
2139         return nullptr;
2140
2141       FX_FILESIZE SavedPos = m_Pos - key.GetLength();
2142       if (key == FX_BSTRC(">>"))
2143         break;
2144
2145       if (key == FX_BSTRC("endobj")) {
2146         m_Pos = SavedPos;
2147         break;
2148       }
2149       if (key[0] != '/')
2150         continue;
2151
2152       ++nKeys;
2153       key = PDF_NameDecode(key);
2154       if (key == FX_BSTRC("/Contents"))
2155         dwSignValuePos = m_Pos;
2156
2157       CPDF_Object* pObj = GetObject(pObjList, objnum, gennum);
2158       if (!pObj)
2159         continue;
2160
2161       if (key.GetLength() >= 1) {
2162         if (nKeys < 32) {
2163           pDict->SetAt(CFX_ByteStringC(key.c_str() + 1, key.GetLength() - 1),
2164                        pObj);
2165         } else {
2166           pDict->AddValue(CFX_ByteStringC(key.c_str() + 1, key.GetLength() - 1),
2167                           pObj);
2168         }
2169       }
2170     }
2171
2172     if (IsSignatureDict(pDict.get())) {
2173       FX_FILESIZE dwSavePos = m_Pos;
2174       m_Pos = dwSignValuePos;
2175       CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, NULL, FALSE);
2176       pDict->SetAt(FX_BSTRC("Contents"), pObj);
2177       m_Pos = dwSavePos;
2178     }
2179     if (pContext) {
2180       pContext->m_DictEnd = m_Pos;
2181       if (pContext->m_Flags & PDFPARSE_NOSTREAM) {
2182         return pDict.release();
2183       }
2184     }
2185     FX_FILESIZE SavedPos = m_Pos;
2186     FX_BOOL bIsNumber;
2187     CFX_ByteString nextword = GetNextWord(bIsNumber);
2188     if (nextword != FX_BSTRC("stream")) {
2189       m_Pos = SavedPos;
2190       return pDict.release();
2191     }
2192
2193     return ReadStream(pDict.release(), pContext, objnum, gennum);
2194   }
2195   if (word == FX_BSTRC(">>")) {
2196     m_Pos = SavedPos;
2197     return nullptr;
2198   }
2199   if (bTypeOnly)
2200     return (CPDF_Object*)PDFOBJ_INVALID;
2201
2202   return nullptr;
2203 }
2204
2205 CPDF_Object* CPDF_SyntaxParser::GetObjectByStrict(
2206     CPDF_IndirectObjects* pObjList,
2207     FX_DWORD objnum,
2208     FX_DWORD gennum,
2209     struct PARSE_CONTEXT* pContext) {
2210   CFX_AutoRestorer<int> restorer(&s_CurrentRecursionDepth);
2211   if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth) {
2212     return NULL;
2213   }
2214   FX_FILESIZE SavedPos = m_Pos;
2215   FX_BOOL bTypeOnly = pContext && (pContext->m_Flags & PDFPARSE_TYPEONLY);
2216   FX_BOOL bIsNumber;
2217   CFX_ByteString word = GetNextWord(bIsNumber);
2218   if (word.GetLength() == 0) {
2219     if (bTypeOnly) {
2220       return (CPDF_Object*)PDFOBJ_INVALID;
2221     }
2222     return NULL;
2223   }
2224   if (bIsNumber) {
2225     FX_FILESIZE SavedPos = m_Pos;
2226     CFX_ByteString nextword = GetNextWord(bIsNumber);
2227     if (bIsNumber) {
2228       CFX_ByteString nextword2 = GetNextWord(bIsNumber);
2229       if (nextword2 == FX_BSTRC("R")) {
2230         if (bTypeOnly) {
2231           return (CPDF_Object*)PDFOBJ_REFERENCE;
2232         }
2233         FX_DWORD objnum = FXSYS_atoi(word);
2234         return new CPDF_Reference(pObjList, objnum);
2235       }
2236     }
2237     m_Pos = SavedPos;
2238     if (bTypeOnly) {
2239       return (CPDF_Object*)PDFOBJ_NUMBER;
2240     }
2241     return CPDF_Number::Create(word);
2242   }
2243   if (word == FX_BSTRC("true") || word == FX_BSTRC("false")) {
2244     if (bTypeOnly) {
2245       return (CPDF_Object*)PDFOBJ_BOOLEAN;
2246     }
2247     return CPDF_Boolean::Create(word == FX_BSTRC("true"));
2248   }
2249   if (word == FX_BSTRC("null")) {
2250     if (bTypeOnly) {
2251       return (CPDF_Object*)PDFOBJ_NULL;
2252     }
2253     return CPDF_Null::Create();
2254   }
2255   if (word == FX_BSTRC("(")) {
2256     if (bTypeOnly) {
2257       return (CPDF_Object*)PDFOBJ_STRING;
2258     }
2259     CFX_ByteString str = ReadString();
2260     if (m_pCryptoHandler) {
2261       m_pCryptoHandler->Decrypt(objnum, gennum, str);
2262     }
2263     return CPDF_String::Create(str, FALSE);
2264   }
2265   if (word == FX_BSTRC("<")) {
2266     if (bTypeOnly) {
2267       return (CPDF_Object*)PDFOBJ_STRING;
2268     }
2269     CFX_ByteString str = ReadHexString();
2270     if (m_pCryptoHandler) {
2271       m_pCryptoHandler->Decrypt(objnum, gennum, str);
2272     }
2273     return CPDF_String::Create(str, TRUE);
2274   }
2275   if (word == FX_BSTRC("[")) {
2276     if (bTypeOnly) {
2277       return (CPDF_Object*)PDFOBJ_ARRAY;
2278     }
2279     nonstd::unique_ptr<CPDF_Array, ReleaseDeleter<CPDF_Array>> pArray(
2280         CPDF_Array::Create());
2281     while (CPDF_Object* pObj = GetObject(pObjList, objnum, gennum))
2282       pArray->Add(pObj);
2283     return m_WordBuffer[0] == ']' ? pArray.release() : nullptr;
2284   }
2285   if (word[0] == '/') {
2286     if (bTypeOnly) {
2287       return (CPDF_Object*)PDFOBJ_NAME;
2288     }
2289     return CPDF_Name::Create(
2290         PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)));
2291   }
2292   if (word == FX_BSTRC("<<")) {
2293     if (bTypeOnly) {
2294       return (CPDF_Object*)PDFOBJ_DICTIONARY;
2295     }
2296     if (pContext) {
2297       pContext->m_DictStart = SavedPos;
2298     }
2299     nonstd::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>> pDict(
2300         CPDF_Dictionary::Create());
2301     while (1) {
2302       FX_BOOL bIsNumber;
2303       FX_FILESIZE SavedPos = m_Pos;
2304       CFX_ByteString key = GetNextWord(bIsNumber);
2305       if (key.IsEmpty())
2306         return nullptr;
2307
2308       if (key == FX_BSTRC(">>"))
2309         break;
2310
2311       if (key == FX_BSTRC("endobj")) {
2312         m_Pos = SavedPos;
2313         break;
2314       }
2315       if (key[0] != '/')
2316         continue;
2317
2318       key = PDF_NameDecode(key);
2319       nonstd::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> obj(
2320           GetObject(pObjList, objnum, gennum));
2321       if (!obj) {
2322         uint8_t ch;
2323         while (GetNextChar(ch) && ch != 0x0A && ch != 0x0D) {
2324         }
2325         return nullptr;
2326       }
2327       if (key.GetLength() > 1) {
2328         pDict->AddValue(CFX_ByteStringC(key.c_str() + 1, key.GetLength() - 1),
2329                         obj.release());
2330       }
2331     }
2332     if (pContext) {
2333       pContext->m_DictEnd = m_Pos;
2334       if (pContext->m_Flags & PDFPARSE_NOSTREAM) {
2335         return pDict.release();
2336       }
2337     }
2338     FX_FILESIZE SavedPos = m_Pos;
2339     FX_BOOL bIsNumber;
2340     CFX_ByteString nextword = GetNextWord(bIsNumber);
2341     if (nextword != FX_BSTRC("stream")) {
2342       m_Pos = SavedPos;
2343       return pDict.release();
2344     }
2345
2346     return ReadStream(pDict.release(), pContext, objnum, gennum);
2347   }
2348   if (word == FX_BSTRC(">>")) {
2349     m_Pos = SavedPos;
2350     return nullptr;
2351   }
2352   if (bTypeOnly)
2353     return (CPDF_Object*)PDFOBJ_INVALID;
2354
2355   return nullptr;
2356 }
2357
2358 unsigned int CPDF_SyntaxParser::ReadEOLMarkers(FX_FILESIZE pos) {
2359   unsigned char byte1 = 0;
2360   unsigned char byte2 = 0;
2361   GetCharAt(pos, byte1);
2362   GetCharAt(pos + 1, byte2);
2363   unsigned int markers = 0;
2364   if (byte1 == '\r' && byte2 == '\n') {
2365     markers = 2;
2366   } else if (byte1 == '\r' || byte1 == '\n') {
2367     markers = 1;
2368   }
2369   return markers;
2370 }
2371 CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
2372                                            PARSE_CONTEXT* pContext,
2373                                            FX_DWORD objnum,
2374                                            FX_DWORD gennum) {
2375   CPDF_Object* pLenObj = pDict->GetElement(FX_BSTRC("Length"));
2376   FX_FILESIZE len = -1;
2377   if (pLenObj && ((pLenObj->GetType() != PDFOBJ_REFERENCE) ||
2378                   ((((CPDF_Reference*)pLenObj)->GetObjList()) &&
2379                    ((CPDF_Reference*)pLenObj)->GetRefObjNum() != objnum))) {
2380     len = pLenObj->GetInteger();
2381   }
2382   // Locate the start of stream.
2383   ToNextLine();
2384   FX_FILESIZE streamStartPos = m_Pos;
2385   if (pContext) {
2386     pContext->m_DataStart = streamStartPos;
2387   }
2388   const unsigned int ENDSTREAM_LEN = sizeof("endstream") - 1;
2389   const unsigned int ENDOBJ_LEN = sizeof("endobj") - 1;
2390   CPDF_CryptoHandler* pCryptoHandler =
2391       objnum == (FX_DWORD)m_MetadataObjnum ? nullptr : m_pCryptoHandler.get();
2392   if (!pCryptoHandler) {
2393     FX_BOOL bSearchForKeyword = TRUE;
2394     if (len >= 0) {
2395       pdfium::base::CheckedNumeric<FX_FILESIZE> pos = m_Pos;
2396       pos += len;
2397       if (pos.IsValid() && pos.ValueOrDie() < m_FileLen) {
2398         m_Pos = pos.ValueOrDie();
2399       }
2400       m_Pos += ReadEOLMarkers(m_Pos);
2401       FXSYS_memset(m_WordBuffer, 0, ENDSTREAM_LEN + 1);
2402       GetNextWord();
2403       if (FXSYS_memcmp(m_WordBuffer, "endstream", ENDSTREAM_LEN) == 0 &&
2404           IsWholeWord(m_Pos - ENDSTREAM_LEN, m_FileLen,
2405                       FX_BSTRC("endstream").GetPtr(), ENDSTREAM_LEN, TRUE)) {
2406         bSearchForKeyword = FALSE;
2407       }
2408     }
2409     if (bSearchForKeyword) {
2410       // If len is not available, len needs to be calculated
2411       // by searching the keywords "endstream" or "endobj".
2412       m_Pos = streamStartPos;
2413       FX_FILESIZE endStreamOffset = 0;
2414       while (endStreamOffset >= 0) {
2415         endStreamOffset = FindTag(FX_BSTRC("endstream"), 0);
2416         if (endStreamOffset < 0) {
2417           // Can't find any "endstream".
2418           break;
2419         }
2420         if (IsWholeWord(m_Pos - ENDSTREAM_LEN, m_FileLen,
2421                         FX_BSTRC("endstream").GetPtr(), ENDSTREAM_LEN, TRUE)) {
2422           // Stop searching when the keyword "endstream" is found.
2423           endStreamOffset = m_Pos - streamStartPos - ENDSTREAM_LEN;
2424           break;
2425         }
2426       }
2427       m_Pos = streamStartPos;
2428       FX_FILESIZE endObjOffset = 0;
2429       while (endObjOffset >= 0) {
2430         endObjOffset = FindTag(FX_BSTRC("endobj"), 0);
2431         if (endObjOffset < 0) {
2432           // Can't find any "endobj".
2433           break;
2434         }
2435         if (IsWholeWord(m_Pos - ENDOBJ_LEN, m_FileLen,
2436                         FX_BSTRC("endobj").GetPtr(), ENDOBJ_LEN, TRUE)) {
2437           // Stop searching when the keyword "endobj" is found.
2438           endObjOffset = m_Pos - streamStartPos - ENDOBJ_LEN;
2439           break;
2440         }
2441       }
2442       if (endStreamOffset < 0 && endObjOffset < 0) {
2443         // Can't find "endstream" or "endobj".
2444         return nullptr;
2445       }
2446       if (endStreamOffset < 0 && endObjOffset >= 0) {
2447         // Correct the position of end stream.
2448         endStreamOffset = endObjOffset;
2449       } else if (endStreamOffset >= 0 && endObjOffset < 0) {
2450         // Correct the position of end obj.
2451         endObjOffset = endStreamOffset;
2452       } else if (endStreamOffset > endObjOffset) {
2453         endStreamOffset = endObjOffset;
2454       }
2455       len = endStreamOffset;
2456       int numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 2);
2457       if (numMarkers == 2) {
2458         len -= 2;
2459       } else {
2460         numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 1);
2461         if (numMarkers == 1) {
2462           len -= 1;
2463         }
2464       }
2465       if (len < 0) {
2466         return nullptr;
2467       }
2468       pDict->SetAtInteger(FX_BSTRC("Length"), len);
2469     }
2470     m_Pos = streamStartPos;
2471   }
2472   if (len < 0) {
2473     return nullptr;
2474   }
2475   uint8_t* pData = nullptr;
2476   if (len > 0) {
2477     pData = FX_Alloc(uint8_t, len);
2478     ReadBlock(pData, len);
2479     if (pCryptoHandler) {
2480       CFX_BinaryBuf dest_buf;
2481       dest_buf.EstimateSize(pCryptoHandler->DecryptGetSize(len));
2482       void* context = pCryptoHandler->DecryptStart(objnum, gennum);
2483       pCryptoHandler->DecryptStream(context, pData, len, dest_buf);
2484       pCryptoHandler->DecryptFinish(context, dest_buf);
2485       FX_Free(pData);
2486       pData = dest_buf.GetBuffer();
2487       len = dest_buf.GetSize();
2488       dest_buf.DetachBuffer();
2489     }
2490   }
2491   CPDF_Stream* pStream = new CPDF_Stream(pData, len, pDict);
2492   if (pContext) {
2493     pContext->m_DataEnd = pContext->m_DataStart + len;
2494   }
2495   streamStartPos = m_Pos;
2496   FXSYS_memset(m_WordBuffer, 0, ENDOBJ_LEN + 1);
2497   GetNextWord();
2498   int numMarkers = ReadEOLMarkers(m_Pos);
2499   if (m_WordSize == ENDOBJ_LEN && numMarkers != 0 &&
2500       FXSYS_memcmp(m_WordBuffer, "endobj", ENDOBJ_LEN) == 0) {
2501     m_Pos = streamStartPos;
2502   }
2503   return pStream;
2504 }
2505 void CPDF_SyntaxParser::InitParser(IFX_FileRead* pFileAccess,
2506                                    FX_DWORD HeaderOffset) {
2507   FX_Free(m_pFileBuf);
2508   m_pFileBuf = FX_Alloc(uint8_t, m_BufSize);
2509   m_HeaderOffset = HeaderOffset;
2510   m_FileLen = pFileAccess->GetSize();
2511   m_Pos = 0;
2512   m_pFileAccess = pFileAccess;
2513   m_BufOffset = 0;
2514   pFileAccess->ReadBlock(
2515       m_pFileBuf, 0,
2516       (size_t)((FX_FILESIZE)m_BufSize > m_FileLen ? m_FileLen : m_BufSize));
2517 }
2518 int32_t CPDF_SyntaxParser::GetDirectNum() {
2519   GetNextWord();
2520   if (!m_bIsNumber) {
2521     return 0;
2522   }
2523   m_WordBuffer[m_WordSize] = 0;
2524   return FXSYS_atoi((const FX_CHAR*)m_WordBuffer);
2525 }
2526 FX_BOOL CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos,
2527                                        FX_FILESIZE limit,
2528                                        const uint8_t* tag,
2529                                        FX_DWORD taglen,
2530                                        FX_BOOL checkKeyword) {
2531   uint8_t type = PDF_CharType[tag[0]];
2532   FX_BOOL bCheckLeft = type != 'D' && type != 'W';
2533   type = PDF_CharType[tag[taglen - 1]];
2534   FX_BOOL bCheckRight = type != 'D' && type != 'W';
2535   uint8_t ch;
2536   if (bCheckRight && startpos + (int32_t)taglen <= limit &&
2537       GetCharAt(startpos + (int32_t)taglen, ch)) {
2538     uint8_t type = PDF_CharType[ch];
2539     if (type == 'N' || type == 'R' || (checkKeyword && type == 'D')) {
2540       return FALSE;
2541     }
2542   }
2543   if (bCheckLeft && startpos > 0 && GetCharAt(startpos - 1, ch)) {
2544     uint8_t type = PDF_CharType[ch];
2545     if (type == 'N' || type == 'R' || (checkKeyword && type == 'D')) {
2546       return FALSE;
2547     }
2548   }
2549   return TRUE;
2550 }
2551 FX_BOOL CPDF_SyntaxParser::SearchWord(const CFX_ByteStringC& tag,
2552                                       FX_BOOL bWholeWord,
2553                                       FX_BOOL bForward,
2554                                       FX_FILESIZE limit) {
2555   int32_t taglen = tag.GetLength();
2556   if (taglen == 0) {
2557     return FALSE;
2558   }
2559   FX_FILESIZE pos = m_Pos;
2560   int32_t offset = 0;
2561   if (!bForward) {
2562     offset = taglen - 1;
2563   }
2564   const uint8_t* tag_data = tag.GetPtr();
2565   uint8_t byte;
2566   while (1) {
2567     if (bForward) {
2568       if (limit) {
2569         if (pos >= m_Pos + limit) {
2570           return FALSE;
2571         }
2572       }
2573       if (!GetCharAt(pos, byte)) {
2574         return FALSE;
2575       }
2576     } else {
2577       if (limit) {
2578         if (pos <= m_Pos - limit) {
2579           return FALSE;
2580         }
2581       }
2582       if (!GetCharAtBackward(pos, byte)) {
2583         return FALSE;
2584       }
2585     }
2586     if (byte == tag_data[offset]) {
2587       if (bForward) {
2588         offset++;
2589         if (offset < taglen) {
2590           pos++;
2591           continue;
2592         }
2593       } else {
2594         offset--;
2595         if (offset >= 0) {
2596           pos--;
2597           continue;
2598         }
2599       }
2600       FX_FILESIZE startpos = bForward ? pos - taglen + 1 : pos;
2601       if (!bWholeWord ||
2602           IsWholeWord(startpos, limit, tag.GetPtr(), taglen, FALSE)) {
2603         m_Pos = startpos;
2604         return TRUE;
2605       }
2606     }
2607     if (bForward) {
2608       offset = byte == tag_data[0] ? 1 : 0;
2609       pos++;
2610     } else {
2611       offset = byte == tag_data[taglen - 1] ? taglen - 2 : taglen - 1;
2612       pos--;
2613     }
2614     if (pos < 0) {
2615       return FALSE;
2616     }
2617   }
2618   return FALSE;
2619 }
2620
2621 int32_t CPDF_SyntaxParser::SearchMultiWord(const CFX_ByteStringC& tags,
2622                                            FX_BOOL bWholeWord,
2623                                            FX_FILESIZE limit) {
2624   int32_t ntags = 1;
2625   for (int i = 0; i < tags.GetLength(); ++i) {
2626     if (tags[i] == 0) {
2627       ++ntags;
2628     }
2629   }
2630
2631   std::vector<SearchTagRecord> patterns(ntags);
2632   FX_DWORD start = 0;
2633   FX_DWORD itag = 0;
2634   FX_DWORD max_len = 0;
2635   for (int i = 0; i <= tags.GetLength(); ++i) {
2636     if (tags[i] == 0) {
2637       FX_DWORD len = i - start;
2638       max_len = std::max(len, max_len);
2639       patterns[itag].m_pTag = tags.GetPtr() + start;
2640       patterns[itag].m_Len = len;
2641       patterns[itag].m_Offset = 0;
2642       start = i + 1;
2643       ++itag;
2644     }
2645   }
2646
2647   const FX_FILESIZE pos_limit = m_Pos + limit;
2648   for (FX_FILESIZE pos = m_Pos; !limit || pos < pos_limit; ++pos) {
2649     uint8_t byte;
2650     if (!GetCharAt(pos, byte))
2651       break;
2652
2653     for (int i = 0; i < ntags; ++i) {
2654       SearchTagRecord& pat = patterns[i];
2655       if (pat.m_pTag[pat.m_Offset] != byte) {
2656         pat.m_Offset = (pat.m_pTag[0] == byte) ? 1 : 0;
2657         continue;
2658       }
2659
2660       ++pat.m_Offset;
2661       if (pat.m_Offset != pat.m_Len)
2662         continue;
2663
2664       if (!bWholeWord ||
2665           IsWholeWord(pos - pat.m_Len, limit, pat.m_pTag, pat.m_Len, FALSE)) {
2666         return i;
2667       }
2668
2669       pat.m_Offset = (pat.m_pTag[0] == byte) ? 1 : 0;
2670     }
2671   }
2672   return -1;
2673 }
2674
2675 FX_FILESIZE CPDF_SyntaxParser::FindTag(const CFX_ByteStringC& tag,
2676                                        FX_FILESIZE limit) {
2677   int32_t taglen = tag.GetLength();
2678   int32_t match = 0;
2679   limit += m_Pos;
2680   FX_FILESIZE startpos = m_Pos;
2681   while (1) {
2682     uint8_t ch;
2683     if (!GetNextChar(ch)) {
2684       return -1;
2685     }
2686     if (ch == tag[match]) {
2687       match++;
2688       if (match == taglen) {
2689         return m_Pos - startpos - taglen;
2690       }
2691     } else {
2692       match = ch == tag[0] ? 1 : 0;
2693     }
2694     if (limit && m_Pos == limit) {
2695       return -1;
2696     }
2697   }
2698   return -1;
2699 }
2700 void CPDF_SyntaxParser::GetBinary(uint8_t* buffer, FX_DWORD size) {
2701   FX_DWORD offset = 0;
2702   uint8_t ch;
2703   while (1) {
2704     if (!GetNextChar(ch)) {
2705       return;
2706     }
2707     buffer[offset++] = ch;
2708     if (offset == size) {
2709       break;
2710     }
2711   }
2712 }
2713
2714 class CPDF_DataAvail final : public IPDF_DataAvail {
2715  public:
2716   CPDF_DataAvail(IFX_FileAvail* pFileAvail, IFX_FileRead* pFileRead);
2717   ~CPDF_DataAvail() override;
2718
2719   FX_BOOL IsDocAvail(IFX_DownloadHints* pHints) override;
2720
2721   void SetDocument(CPDF_Document* pDoc) override;
2722
2723   FX_BOOL IsPageAvail(int iPage, IFX_DownloadHints* pHints) override;
2724
2725   int32_t IsFormAvail(IFX_DownloadHints* pHints) override;
2726
2727   int32_t IsLinearizedPDF() override;
2728
2729   FX_BOOL IsLinearized() override { return m_bLinearized; }
2730
2731   void GetLinearizedMainXRefInfo(FX_FILESIZE* pPos, FX_DWORD* pSize) override;
2732
2733  protected:
2734   static const int kMaxDataAvailRecursionDepth = 64;
2735   static int s_CurrentDataAvailRecursionDepth;
2736   static const int kMaxPageRecursionDepth = 1024;
2737
2738   FX_DWORD GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset);
2739   FX_BOOL IsObjectsAvail(CFX_PtrArray& obj_array,
2740                          FX_BOOL bParsePage,
2741                          IFX_DownloadHints* pHints,
2742                          CFX_PtrArray& ret_array);
2743   FX_BOOL CheckDocStatus(IFX_DownloadHints* pHints);
2744   FX_BOOL CheckHeader(IFX_DownloadHints* pHints);
2745   FX_BOOL CheckFirstPage(IFX_DownloadHints* pHints);
2746   FX_BOOL CheckEnd(IFX_DownloadHints* pHints);
2747   FX_BOOL CheckCrossRef(IFX_DownloadHints* pHints);
2748   FX_BOOL CheckCrossRefItem(IFX_DownloadHints* pHints);
2749   FX_BOOL CheckTrailer(IFX_DownloadHints* pHints);
2750   FX_BOOL CheckRoot(IFX_DownloadHints* pHints);
2751   FX_BOOL CheckInfo(IFX_DownloadHints* pHints);
2752   FX_BOOL CheckPages(IFX_DownloadHints* pHints);
2753   FX_BOOL CheckPage(IFX_DownloadHints* pHints);
2754   FX_BOOL CheckResources(IFX_DownloadHints* pHints);
2755   FX_BOOL CheckAnnots(IFX_DownloadHints* pHints);
2756   FX_BOOL CheckAcroForm(IFX_DownloadHints* pHints);
2757   FX_BOOL CheckAcroFormSubObject(IFX_DownloadHints* pHints);
2758   FX_BOOL CheckTrailerAppend(IFX_DownloadHints* pHints);
2759   FX_BOOL CheckPageStatus(IFX_DownloadHints* pHints);
2760   FX_BOOL CheckAllCrossRefStream(IFX_DownloadHints* pHints);
2761
2762   int32_t CheckCrossRefStream(IFX_DownloadHints* pHints,
2763                               FX_FILESIZE& xref_offset);
2764   FX_BOOL IsLinearizedFile(uint8_t* pData, FX_DWORD dwLen);
2765   void SetStartOffset(FX_FILESIZE dwOffset);
2766   FX_BOOL GetNextToken(CFX_ByteString& token);
2767   FX_BOOL GetNextChar(uint8_t& ch);
2768   CPDF_Object* ParseIndirectObjectAt(FX_FILESIZE pos, FX_DWORD objnum);
2769   CPDF_Object* GetObject(FX_DWORD objnum,
2770                          IFX_DownloadHints* pHints,
2771                          FX_BOOL* pExistInFile);
2772   FX_BOOL GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages);
2773   FX_BOOL PreparePageItem();
2774   FX_BOOL LoadPages(IFX_DownloadHints* pHints);
2775   FX_BOOL LoadAllXref(IFX_DownloadHints* pHints);
2776   FX_BOOL LoadAllFile(IFX_DownloadHints* pHints);
2777   FX_BOOL CheckLinearizedData(IFX_DownloadHints* pHints);
2778   FX_BOOL CheckFileResources(IFX_DownloadHints* pHints);
2779   FX_BOOL CheckPageAnnots(int iPage, IFX_DownloadHints* pHints);
2780
2781   FX_BOOL CheckLinearizedFirstPage(int iPage, IFX_DownloadHints* pHints);
2782   FX_BOOL HaveResourceAncestor(CPDF_Dictionary* pDict);
2783   FX_BOOL CheckPage(int32_t iPage, IFX_DownloadHints* pHints);
2784   FX_BOOL LoadDocPages(IFX_DownloadHints* pHints);
2785   FX_BOOL LoadDocPage(int32_t iPage, IFX_DownloadHints* pHints);
2786   FX_BOOL CheckPageNode(CPDF_PageNode& pageNodes,
2787                         int32_t iPage,
2788                         int32_t& iCount,
2789                         IFX_DownloadHints* pHints,
2790                         int level);
2791   FX_BOOL CheckUnkownPageNode(FX_DWORD dwPageNo,
2792                               CPDF_PageNode* pPageNode,
2793                               IFX_DownloadHints* pHints);
2794   FX_BOOL CheckArrayPageNode(FX_DWORD dwPageNo,
2795                              CPDF_PageNode* pPageNode,
2796                              IFX_DownloadHints* pHints);
2797   FX_BOOL CheckPageCount(IFX_DownloadHints* pHints);
2798   FX_BOOL IsFirstCheck(int iPage);
2799   void ResetFirstCheck(int iPage);
2800
2801   CPDF_Parser m_parser;
2802
2803   CPDF_SyntaxParser m_syntaxParser;
2804
2805   CPDF_Object* m_pRoot;
2806
2807   FX_DWORD m_dwRootObjNum;
2808
2809   FX_DWORD m_dwInfoObjNum;
2810
2811   CPDF_Object* m_pLinearized;
2812
2813   CPDF_Object* m_pTrailer;
2814
2815   FX_BOOL m_bDocAvail;
2816
2817   FX_FILESIZE m_dwHeaderOffset;
2818
2819   FX_FILESIZE m_dwLastXRefOffset;
2820
2821   FX_FILESIZE m_dwXRefOffset;
2822
2823   FX_FILESIZE m_dwTrailerOffset;
2824
2825   FX_FILESIZE m_dwCurrentOffset;
2826
2827   PDF_DATAAVAIL_STATUS m_docStatus;
2828
2829   FX_FILESIZE m_dwFileLen;
2830
2831   CPDF_Document* m_pDocument;
2832
2833   CPDF_SortObjNumArray m_objnum_array;
2834
2835   CFX_PtrArray m_objs_array;
2836
2837   FX_FILESIZE m_Pos;
2838
2839   FX_FILESIZE m_bufferOffset;
2840
2841   FX_DWORD m_bufferSize;
2842
2843   CFX_ByteString m_WordBuf;
2844
2845   uint8_t m_WordBuffer[257];
2846
2847   FX_DWORD m_WordSize;
2848
2849   uint8_t m_bufferData[512];
2850
2851   CFX_FileSizeArray m_CrossOffset;
2852
2853   CFX_DWordArray m_XRefStreamList;
2854
2855   CFX_DWordArray m_PageObjList;
2856
2857   FX_DWORD m_PagesObjNum;
2858
2859   FX_BOOL m_bLinearized;
2860
2861   FX_DWORD m_dwFirstPageNo;
2862
2863   FX_BOOL m_bLinearedDataOK;
2864
2865   FX_BOOL m_bMainXRefLoadTried;
2866
2867   FX_BOOL m_bMainXRefLoadedOK;
2868
2869   FX_BOOL m_bPagesTreeLoad;
2870
2871   FX_BOOL m_bPagesLoad;
2872
2873   CPDF_Parser* m_pCurrentParser;
2874
2875   FX_FILESIZE m_dwCurrentXRefSteam;
2876
2877   FX_BOOL m_bAnnotsLoad;
2878
2879   FX_BOOL m_bHaveAcroForm;
2880
2881   FX_DWORD m_dwAcroFormObjNum;
2882
2883   FX_BOOL m_bAcroFormLoad;
2884
2885   CPDF_Object* m_pAcroForm;
2886
2887   CFX_PtrArray m_arrayAcroforms;
2888
2889   CPDF_Dictionary* m_pPageDict;
2890
2891   CPDF_Object* m_pPageResource;
2892
2893   FX_BOOL m_bNeedDownLoadResource;
2894
2895   FX_BOOL m_bPageLoadedOK;
2896
2897   FX_BOOL m_bLinearizedFormParamLoad;
2898
2899   CFX_PtrArray m_PagesArray;
2900
2901   FX_DWORD m_dwEncryptObjNum;
2902
2903   FX_FILESIZE m_dwPrevXRefOffset;
2904
2905   FX_BOOL m_bTotalLoadPageTree;
2906
2907   FX_BOOL m_bCurPageDictLoadOK;
2908
2909   CPDF_PageNode m_pageNodes;
2910
2911   std::set<FX_DWORD> m_pageMapCheckState;
2912   std::set<FX_DWORD> m_pagesLoadState;
2913 };
2914
2915 IPDF_DataAvail::IPDF_DataAvail(IFX_FileAvail* pFileAvail,
2916                                IFX_FileRead* pFileRead)
2917     : m_pFileAvail(pFileAvail), m_pFileRead(pFileRead) {}
2918
2919 // static
2920 IPDF_DataAvail* IPDF_DataAvail::Create(IFX_FileAvail* pFileAvail,
2921                                        IFX_FileRead* pFileRead) {
2922   return new CPDF_DataAvail(pFileAvail, pFileRead);
2923 }
2924
2925 // static
2926 int CPDF_DataAvail::s_CurrentDataAvailRecursionDepth = 0;
2927
2928 CPDF_DataAvail::CPDF_DataAvail(IFX_FileAvail* pFileAvail,
2929                                IFX_FileRead* pFileRead)
2930     : IPDF_DataAvail(pFileAvail, pFileRead) {
2931   m_Pos = 0;
2932   m_dwFileLen = 0;
2933   if (m_pFileRead) {
2934     m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize();
2935   }
2936   m_dwCurrentOffset = 0;
2937   m_WordSize = 0;
2938   m_dwXRefOffset = 0;
2939   m_bufferOffset = 0;
2940   m_dwFirstPageNo = 0;
2941   m_bufferSize = 0;
2942   m_PagesObjNum = 0;
2943   m_dwCurrentXRefSteam = 0;
2944   m_dwAcroFormObjNum = 0;
2945   m_dwInfoObjNum = 0;
2946   m_pDocument = 0;
2947   m_dwEncryptObjNum = 0;
2948   m_dwPrevXRefOffset = 0;
2949   m_dwLastXRefOffset = 0;
2950   m_bDocAvail = FALSE;
2951   m_bMainXRefLoadTried = FALSE;
2952   m_bDocAvail = FALSE;
2953   m_bLinearized = FALSE;
2954   m_bPagesLoad = FALSE;
2955   m_bPagesTreeLoad = FALSE;
2956   m_bMainXRefLoadedOK = FALSE;
2957   m_bAnnotsLoad = FALSE;
2958   m_bHaveAcroForm = FALSE;
2959   m_bAcroFormLoad = FALSE;
2960   m_bPageLoadedOK = FALSE;
2961   m_bNeedDownLoadResource = FALSE;
2962   m_bLinearizedFormParamLoad = FALSE;
2963   m_pLinearized = NULL;
2964   m_pRoot = NULL;
2965   m_pTrailer = NULL;
2966   m_pCurrentParser = NULL;
2967   m_pAcroForm = NULL;
2968   m_pPageDict = NULL;
2969   m_pPageResource = NULL;
2970   m_docStatus = PDF_DATAAVAIL_HEADER;
2971   m_parser.m_bOwnFileRead = FALSE;
2972   m_bTotalLoadPageTree = FALSE;
2973   m_bCurPageDictLoadOK = FALSE;
2974   m_bLinearedDataOK = FALSE;
2975 }
2976 CPDF_DataAvail::~CPDF_DataAvail() {
2977   if (m_pLinearized) {
2978     m_pLinearized->Release();
2979   }
2980   if (m_pRoot) {
2981     m_pRoot->Release();
2982   }
2983   if (m_pTrailer) {
2984     m_pTrailer->Release();
2985   }
2986   int32_t i = 0;
2987   int32_t iSize = m_arrayAcroforms.GetSize();
2988   for (i = 0; i < iSize; ++i) {
2989     ((CPDF_Object*)m_arrayAcroforms.GetAt(i))->Release();
2990   }
2991 }
2992 void CPDF_DataAvail::SetDocument(CPDF_Document* pDoc) {
2993   m_pDocument = pDoc;
2994 }
2995 FX_DWORD CPDF_DataAvail::GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset) {
2996   CPDF_Parser* pParser = (CPDF_Parser*)(m_pDocument->GetParser());
2997   if (pParser == NULL) {
2998     return 0;
2999   }
3000   if (objnum >= (FX_DWORD)pParser->m_CrossRef.GetSize()) {
3001     return 0;
3002   }
3003   if (pParser->m_V5Type[objnum] == 2) {
3004     objnum = (FX_DWORD)pParser->m_CrossRef[objnum];
3005   }
3006   if (pParser->m_V5Type[objnum] == 1 || pParser->m_V5Type[objnum] == 255) {
3007     offset = pParser->m_CrossRef[objnum];
3008     if (offset == 0) {
3009       return 0;
3010     }
3011     void* pResult = FXSYS_bsearch(&offset, pParser->m_SortedOffset.GetData(),
3012                                   pParser->m_SortedOffset.GetSize(),
3013                                   sizeof(FX_FILESIZE), CompareFileSize);
3014     if (pResult == NULL) {
3015       return 0;
3016     }
3017     if ((FX_FILESIZE*)pResult -
3018             (FX_FILESIZE*)pParser->m_SortedOffset.GetData() ==
3019         pParser->m_SortedOffset.GetSize() - 1) {
3020       return 0;
3021     }
3022     return (FX_DWORD)(((FX_FILESIZE*)pResult)[1] - offset);
3023   }
3024   return 0;
3025 }
3026 FX_BOOL CPDF_DataAvail::IsObjectsAvail(CFX_PtrArray& obj_array,
3027                                        FX_BOOL bParsePage,
3028                                        IFX_DownloadHints* pHints,
3029                                        CFX_PtrArray& ret_array) {
3030   if (!obj_array.GetSize()) {
3031     return TRUE;
3032   }
3033   FX_DWORD count = 0;
3034   CFX_PtrArray new_obj_array;
3035   int32_t i = 0;
3036   for (i = 0; i < obj_array.GetSize(); i++) {
3037     CPDF_Object* pObj = (CPDF_Object*)obj_array[i];
3038     if (!pObj) {
3039       continue;
3040     }
3041     int32_t type = pObj->GetType();
3042     switch (type) {
3043       case PDFOBJ_ARRAY: {
3044         CPDF_Array* pArray = pObj->GetArray();
3045         for (FX_DWORD k = 0; k < pArray->GetCount(); k++) {
3046           new_obj_array.Add(pArray->GetElement(k));
3047         }
3048       } break;
3049       case PDFOBJ_STREAM:
3050         pObj = pObj->GetDict();
3051       case PDFOBJ_DICTIONARY: {
3052         CPDF_Dictionary* pDict = pObj->GetDict();
3053         if (pDict && pDict->GetString("Type") == "Page" && !bParsePage) {
3054           continue;
3055         }
3056         FX_POSITION pos = pDict->GetStartPos();
3057         while (pos) {
3058           CPDF_Object* value;
3059           CFX_ByteString key;
3060           value = pDict->GetNextElement(pos, key);
3061           if (key != "Parent") {
3062             new_obj_array.Add(value);
3063           }
3064         }
3065       } break;
3066       case PDFOBJ_REFERENCE: {
3067         CPDF_Reference* pRef = (CPDF_Reference*)pObj;
3068         FX_DWORD dwNum = pRef->GetRefObjNum();
3069         FX_FILESIZE offset;
3070         FX_DWORD original_size = GetObjectSize(dwNum, offset);
3071         pdfium::base::CheckedNumeric<FX_DWORD> size = original_size;
3072         if (size.ValueOrDefault(0) == 0 || offset < 0 ||
3073             offset >= m_dwFileLen) {
3074           break;
3075         }
3076
3077         size += offset;
3078         size += 512;
3079         if (!size.IsValid()) {
3080           break;
3081         }
3082         if (size.ValueOrDie() > m_dwFileLen) {
3083           size = m_dwFileLen - offset;
3084         } else {
3085           size = original_size + 512;
3086         }
3087         if (!size.IsValid()) {
3088           break;
3089         }
3090         if (!m_pFileAvail->IsDataAvail(offset, size.ValueOrDie())) {
3091           pHints->AddSegment(offset, size.ValueOrDie());
3092           ret_array.Add(pObj);
3093           count++;
3094         } else if (!m_objnum_array.Find(dwNum)) {
3095           m_objnum_array.AddObjNum(dwNum);
3096           CPDF_Object* pReferred =
3097               m_pDocument->GetIndirectObject(pRef->GetRefObjNum(), NULL);
3098           if (pReferred) {
3099             new_obj_array.Add(pReferred);
3100           }
3101         }
3102       } break;
3103     }
3104   }
3105   if (count > 0) {
3106     int32_t iSize = new_obj_array.GetSize();
3107     for (i = 0; i < iSize; ++i) {
3108       CPDF_Object* pObj = (CPDF_Object*)new_obj_array[i];
3109       int32_t type = pObj->GetType();
3110       if (type == PDFOBJ_REFERENCE) {
3111         CPDF_Reference* pRef = (CPDF_Reference*)pObj;
3112         FX_DWORD dwNum = pRef->GetRefObjNum();
3113         if (!m_objnum_array.Find(dwNum)) {
3114           ret_array.Add(pObj);
3115         }
3116       } else {
3117         ret_array.Add(pObj);
3118       }
3119     }
3120     return FALSE;
3121   }
3122   obj_array.RemoveAll();
3123   obj_array.Append(new_obj_array);
3124   return IsObjectsAvail(obj_array, FALSE, pHints, ret_array);
3125 }
3126 FX_BOOL CPDF_DataAvail::IsDocAvail(IFX_DownloadHints* pHints) {
3127   if (!m_dwFileLen && m_pFileRead) {
3128     m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize();
3129     if (!m_dwFileLen) {
3130       return TRUE;
3131     }
3132   }
3133   while (!m_bDocAvail) {
3134     if (!CheckDocStatus(pHints)) {
3135       return FALSE;
3136     }
3137   }
3138   return TRUE;
3139 }
3140 FX_BOOL CPDF_DataAvail::CheckAcroFormSubObject(IFX_DownloadHints* pHints) {
3141   if (!m_objs_array.GetSize()) {
3142     m_objs_array.RemoveAll();
3143     m_objnum_array.RemoveAll();
3144     CFX_PtrArray obj_array;
3145     obj_array.Append(m_arrayAcroforms);
3146     FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array);
3147     if (bRet) {
3148       m_objs_array.RemoveAll();
3149     }
3150     return bRet;
3151   }
3152   CFX_PtrArray new_objs_array;
3153   FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array);
3154   if (bRet) {
3155     int32_t iSize = m_arrayAcroforms.GetSize();
3156     for (int32_t i = 0; i < iSize; ++i) {
3157       ((CPDF_Object*)m_arrayAcroforms.GetAt(i))->Release();
3158     }
3159     m_arrayAcroforms.RemoveAll();
3160   } else {
3161     m_objs_array.RemoveAll();
3162     m_objs_array.Append(new_objs_array);
3163   }
3164   return bRet;
3165 }
3166 FX_BOOL CPDF_DataAvail::CheckAcroForm(IFX_DownloadHints* pHints) {
3167   FX_BOOL bExist = FALSE;
3168   m_pAcroForm = GetObject(m_dwAcroFormObjNum, pHints, &bExist);
3169   if (!bExist) {
3170     m_docStatus = PDF_DATAAVAIL_PAGETREE;
3171     return TRUE;
3172   }
3173   if (!m_pAcroForm) {
3174     if (m_docStatus == PDF_DATAAVAIL_ERROR) {
3175       m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3176       return TRUE;
3177     }
3178     return FALSE;
3179   }
3180   m_arrayAcroforms.Add(m_pAcroForm);
3181   m_docStatus = PDF_DATAAVAIL_PAGETREE;
3182   return TRUE;
3183 }
3184 FX_BOOL CPDF_DataAvail::CheckDocStatus(IFX_DownloadHints* pHints) {
3185   switch (m_docStatus) {
3186     case PDF_DATAAVAIL_HEADER:
3187       return CheckHeader(pHints);
3188     case PDF_DATAAVAIL_FIRSTPAGE:
3189     case PDF_DATAAVAIL_FIRSTPAGE_PREPARE:
3190       return CheckFirstPage(pHints);
3191     case PDF_DATAAVAIL_END:
3192       return CheckEnd(pHints);
3193     case PDF_DATAAVAIL_CROSSREF:
3194       return CheckCrossRef(pHints);
3195     case PDF_DATAAVAIL_CROSSREF_ITEM:
3196       return CheckCrossRefItem(pHints);
3197     case PDF_DATAAVAIL_CROSSREF_STREAM:
3198       return CheckAllCrossRefStream(pHints);
3199     case PDF_DATAAVAIL_TRAILER:
3200       return CheckTrailer(pHints);
3201     case PDF_DATAAVAIL_TRAILER_APPEND:
3202       return CheckTrailerAppend(pHints);
3203     case PDF_DATAAVAIL_LOADALLCRSOSSREF:
3204       return LoadAllXref(pHints);
3205     case PDF_DATAAVAIL_LOADALLFILE:
3206       return LoadAllFile(pHints);
3207     case PDF_DATAAVAIL_ROOT:
3208       return CheckRoot(pHints);
3209     case PDF_DATAAVAIL_INFO:
3210       return CheckInfo(pHints);
3211     case PDF_DATAAVAIL_ACROFORM:
3212       return CheckAcroForm(pHints);
3213     case PDF_DATAAVAIL_PAGETREE:
3214       if (m_bTotalLoadPageTree) {
3215         return CheckPages(pHints);
3216       }
3217       return LoadDocPages(pHints);
3218     case PDF_DATAAVAIL_PAGE:
3219       if (m_bTotalLoadPageTree) {
3220         return CheckPage(pHints);
3221       }
3222       m_docStatus = PDF_DATAAVAIL_PAGE_LATERLOAD;
3223       return TRUE;
3224     case PDF_DATAAVAIL_ERROR:
3225       return LoadAllFile(pHints);
3226     case PDF_DATAAVAIL_PAGE_LATERLOAD:
3227       m_docStatus = PDF_DATAAVAIL_PAGE;
3228     default:
3229       m_bDocAvail = TRUE;
3230       return TRUE;
3231   }
3232 }
3233 FX_BOOL CPDF_DataAvail::CheckPageStatus(IFX_DownloadHints* pHints) {
3234   switch (m_docStatus) {
3235     case PDF_DATAAVAIL_PAGETREE:
3236       return CheckPages(pHints);
3237     case PDF_DATAAVAIL_PAGE:
3238       return CheckPage(pHints);
3239     case PDF_DATAAVAIL_ERROR:
3240       return LoadAllFile(pHints);
3241     default:
3242       m_bPagesTreeLoad = TRUE;
3243       m_bPagesLoad = TRUE;
3244       return TRUE;
3245   }
3246 }
3247 FX_BOOL CPDF_DataAvail::LoadAllFile(IFX_DownloadHints* pHints) {
3248   if (m_pFileAvail->IsDataAvail(0, (FX_DWORD)m_dwFileLen)) {
3249     m_docStatus = PDF_DATAAVAIL_DONE;
3250     return TRUE;
3251   }
3252   pHints->AddSegment(0, (FX_DWORD)m_dwFileLen);
3253   return FALSE;
3254 }
3255 FX_BOOL CPDF_DataAvail::LoadAllXref(IFX_DownloadHints* pHints) {
3256   m_parser.m_Syntax.InitParser(m_pFileRead, (FX_DWORD)m_dwHeaderOffset);
3257   m_parser.m_bOwnFileRead = FALSE;
3258   if (!m_parser.LoadAllCrossRefV4(m_dwLastXRefOffset) &&
3259       !m_parser.LoadAllCrossRefV5(m_dwLastXRefOffset)) {
3260     m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3261     return FALSE;
3262   }
3263   FXSYS_qsort(m_parser.m_SortedOffset.GetData(),
3264               m_parser.m_SortedOffset.GetSize(), sizeof(FX_FILESIZE),
3265               CompareFileSize);
3266   m_dwRootObjNum = m_parser.GetRootObjNum();
3267   m_dwInfoObjNum = m_parser.GetInfoObjNum();
3268   m_pCurrentParser = &m_parser;
3269   m_docStatus = PDF_DATAAVAIL_ROOT;
3270   return TRUE;
3271 }
3272 CPDF_Object* CPDF_DataAvail::GetObject(FX_DWORD objnum,
3273                                        IFX_DownloadHints* pHints,
3274                                        FX_BOOL* pExistInFile) {
3275   CPDF_Object* pRet = NULL;
3276   FX_DWORD original_size = 0;
3277   FX_FILESIZE offset = 0;
3278   CPDF_Parser* pParser = NULL;
3279
3280   if (pExistInFile) {
3281     *pExistInFile = TRUE;
3282   }
3283
3284   if (m_pDocument == NULL) {
3285     original_size = (FX_DWORD)m_parser.GetObjectSize(objnum);
3286     offset = m_parser.GetObjectOffset(objnum);
3287     pParser = &m_parser;
3288   } else {
3289     original_size = GetObjectSize(objnum, offset);
3290     pParser = (CPDF_Parser*)(m_pDocument->GetParser());
3291   }
3292
3293   pdfium::base::CheckedNumeric<FX_DWORD> size = original_size;
3294   if (size.ValueOrDefault(0) == 0 || offset < 0 || offset >= m_dwFileLen) {
3295     if (pExistInFile)
3296       *pExistInFile = FALSE;
3297
3298     return NULL;
3299   }
3300
3301   size += offset;
3302   size += 512;
3303   if (!size.IsValid()) {
3304     return NULL;
3305   }
3306
3307   if (size.ValueOrDie() > m_dwFileLen) {
3308     size = m_dwFileLen - offset;
3309   } else {
3310     size = original_size + 512;
3311   }
3312
3313   if (!size.IsValid()) {
3314     return NULL;
3315   }
3316
3317   if (!m_pFileAvail->IsDataAvail(offset, size.ValueOrDie())) {
3318     pHints->AddSegment(offset, size.ValueOrDie());
3319     return NULL;
3320   }
3321
3322   if (pParser) {
3323     pRet = pParser->ParseIndirectObject(NULL, objnum, NULL);
3324   }
3325
3326   if (!pRet && pExistInFile) {
3327     *pExistInFile = FALSE;
3328   }
3329
3330   return pRet;
3331 }
3332
3333 FX_BOOL CPDF_DataAvail::CheckInfo(IFX_DownloadHints* pHints) {
3334   FX_BOOL bExist = FALSE;
3335   CPDF_Object* pInfo = GetObject(m_dwInfoObjNum, pHints, &bExist);
3336   if (!bExist) {
3337     if (m_bHaveAcroForm) {
3338       m_docStatus = PDF_DATAAVAIL_ACROFORM;
3339     } else {
3340       m_docStatus = PDF_DATAAVAIL_PAGETREE;
3341     }
3342     return TRUE;
3343   }
3344   if (!pInfo) {
3345     if (m_docStatus == PDF_DATAAVAIL_ERROR) {
3346       m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3347       return TRUE;
3348     }
3349     if (m_Pos == m_dwFileLen) {
3350       m_docStatus = PDF_DATAAVAIL_ERROR;
3351     }
3352     return FALSE;
3353   }
3354   if (pInfo) {
3355     pInfo->Release();
3356   }
3357   if (m_bHaveAcroForm) {
3358     m_docStatus = PDF_DATAAVAIL_ACROFORM;
3359   } else {
3360     m_docStatus = PDF_DATAAVAIL_PAGETREE;
3361   }
3362   return TRUE;
3363 }
3364 FX_BOOL CPDF_DataAvail::CheckRoot(IFX_DownloadHints* pHints) {
3365   FX_BOOL bExist = FALSE;
3366   m_pRoot = GetObject(m_dwRootObjNum, pHints, &bExist);
3367   if (!bExist) {
3368     m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3369     return TRUE;
3370   }
3371   if (!m_pRoot) {
3372     if (m_docStatus == PDF_DATAAVAIL_ERROR) {
3373       m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
3374       return TRUE;
3375     }
3376     return FALSE;
3377   }
3378   CPDF_Dictionary* pDict = m_pRoot->GetDict();
3379   if (!pDict) {
3380     m_docStatus = PDF_DATAAVAIL_ERROR;
3381     return FALSE;
3382   }
3383   CPDF_Reference* pRef = (CPDF_Reference*)pDict->GetElement(FX_BSTRC("Pages"));
3384   if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) {
3385     m_docStatus = PDF_DATAAVAIL_ERROR;
3386     return FALSE;
3387   }
3388   m_PagesObjNum = pRef->GetRefObjNum();
3389   CPDF_Reference* pAcroFormRef =
3390