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