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