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