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