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