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