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