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