| // Copyright 2014 PDFium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| #include "../../../include/fpdfapi/fpdf_parser.h" | |
| #include "../../../include/fpdfapi/fpdf_module.h" | |
| #include "../../../include/fpdfapi/fpdf_page.h" | |
| #include "../fpdf_page/pageint.h" | |
| #include <limits.h> | |
| #define _PARSER_OBJECT_LEVLE_ 64 | |
| extern const FX_LPCSTR _PDF_CharType; | |
| FX_BOOL IsSignatureDict(const CPDF_Dictionary* pDict) | |
| { | |
| CPDF_Object* pType = pDict->GetElementValue(FX_BSTRC("Type")); | |
| if (!pType) { | |
| pType = pDict->GetElementValue(FX_BSTRC("FT")); | |
| if (!pType) { | |
| return FALSE; | |
| } | |
| } | |
| if (pType->GetString() == FX_BSTRC("Sig")) { | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| static FX_INT32 _CompareDWord(const void* p1, const void* p2) | |
| { | |
| return (*(FX_DWORD*)p1) - (*(FX_DWORD*)p2); | |
| } | |
| static int _CompareFileSize(const void* p1, const void* p2) | |
| { | |
| FX_FILESIZE ret = (*(FX_FILESIZE*)p1) - (*(FX_FILESIZE*)p2); | |
| if (ret > 0) { | |
| return 1; | |
| } | |
| if (ret < 0) { | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| CPDF_Parser::CPDF_Parser() | |
| { | |
| m_pDocument = NULL; | |
| m_pTrailer = NULL; | |
| m_pEncryptDict = NULL; | |
| m_pSecurityHandler = NULL; | |
| m_pLinearized = NULL; | |
| m_dwFirstPageNo = 0; | |
| m_dwXrefStartObjNum = 0; | |
| m_bOwnFileRead = TRUE; | |
| m_bForceUseSecurityHandler = FALSE; | |
| } | |
| CPDF_Parser::~CPDF_Parser() | |
| { | |
| CloseParser(FALSE); | |
| } | |
| FX_DWORD CPDF_Parser::GetLastObjNum() | |
| { | |
| FX_DWORD dwSize = m_CrossRef.GetSize(); | |
| return dwSize ? dwSize - 1 : 0; | |
| } | |
| void CPDF_Parser::SetEncryptDictionary(CPDF_Dictionary* pDict) | |
| { | |
| m_pEncryptDict = pDict; | |
| } | |
| void CPDF_Parser::CloseParser(FX_BOOL bReParse) | |
| { | |
| m_bVersionUpdated = FALSE; | |
| if (m_pDocument && !bReParse) { | |
| delete m_pDocument; | |
| m_pDocument = NULL; | |
| } | |
| if (m_pTrailer) { | |
| m_pTrailer->Release(); | |
| m_pTrailer = NULL; | |
| } | |
| ReleaseEncryptHandler(); | |
| SetEncryptDictionary(NULL); | |
| if (m_bOwnFileRead && m_Syntax.m_pFileAccess != NULL) { | |
| m_Syntax.m_pFileAccess->Release(); | |
| m_Syntax.m_pFileAccess = NULL; | |
| } | |
| FX_POSITION pos = m_ObjectStreamMap.GetStartPosition(); | |
| while (pos) { | |
| FX_LPVOID objnum; | |
| CPDF_StreamAcc* pStream; | |
| m_ObjectStreamMap.GetNextAssoc(pos, objnum, (void*&)pStream); | |
| delete pStream; | |
| } | |
| m_ObjectStreamMap.RemoveAll(); | |
| m_SortedOffset.RemoveAll(); | |
| m_CrossRef.RemoveAll(); | |
| m_V5Type.RemoveAll(); | |
| m_ObjVersion.RemoveAll(); | |
| FX_INT32 iLen = m_Trailers.GetSize(); | |
| for (FX_INT32 i = 0; i < iLen; ++i) { | |
| m_Trailers.GetAt(i)->Release(); | |
| } | |
| m_Trailers.RemoveAll(); | |
| if (m_pLinearized) { | |
| m_pLinearized->Release(); | |
| m_pLinearized = NULL; | |
| } | |
| } | |
| static FX_INT32 GetHeaderOffset(IFX_FileRead* pFile) | |
| { | |
| FX_DWORD tag = FXDWORD_FROM_LSBFIRST(0x46445025); | |
| FX_BYTE buf[4]; | |
| FX_INT32 offset = 0; | |
| while (1) { | |
| if (!pFile->ReadBlock(buf, offset, 4)) { | |
| return -1; | |
| } | |
| if (*(FX_DWORD*)buf == tag) { | |
| return offset; | |
| } | |
| offset ++; | |
| if (offset > 1024) { | |
| return -1; | |
| } | |
| } | |
| return -1; | |
| } | |
| FX_DWORD CPDF_Parser::StartParse(FX_LPCSTR filename, FX_BOOL bReParse) | |
| { | |
| IFX_FileRead* pFileAccess = FX_CreateFileRead(filename); | |
| if (!pFileAccess) { | |
| return PDFPARSE_ERROR_FILE; | |
| } | |
| return StartParse(pFileAccess, bReParse); | |
| } | |
| FX_DWORD CPDF_Parser::StartParse(FX_LPCWSTR filename, FX_BOOL bReParse) | |
| { | |
| IFX_FileRead* pFileAccess = FX_CreateFileRead(filename); | |
| if (!pFileAccess) { | |
| return PDFPARSE_ERROR_FILE; | |
| } | |
| return StartParse(pFileAccess, bReParse); | |
| } | |
| CPDF_SecurityHandler* FPDF_CreateStandardSecurityHandler(); | |
| CPDF_SecurityHandler* FPDF_CreatePubKeyHandler(void*); | |
| FX_DWORD CPDF_Parser::StartParse(IFX_FileRead* pFileAccess, FX_BOOL bReParse, FX_BOOL bOwnFileRead) | |
| { | |
| CloseParser(bReParse); | |
| m_bXRefStream = FALSE; | |
| m_LastXRefOffset = 0; | |
| m_bOwnFileRead = bOwnFileRead; | |
| FX_INT32 offset = GetHeaderOffset(pFileAccess); | |
| if (offset == -1) { | |
| if (bOwnFileRead && pFileAccess) { | |
| pFileAccess->Release(); | |
| } | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| m_Syntax.InitParser(pFileAccess, offset); | |
| FX_BYTE ch; | |
| m_Syntax.GetCharAt(5, ch); | |
| m_FileVersion = (ch - '0') * 10; | |
| m_Syntax.GetCharAt(7, ch); | |
| m_FileVersion += ch - '0'; | |
| m_Syntax.RestorePos(m_Syntax.m_FileLen - m_Syntax.m_HeaderOffset - 9); | |
| if (!bReParse) { | |
| m_pDocument = FX_NEW CPDF_Document(this); | |
| } | |
| FX_BOOL bXRefRebuilt = FALSE; | |
| if (m_Syntax.SearchWord(FX_BSTRC("startxref"), TRUE, FALSE, 4096)) { | |
| FX_FILESIZE startxref_offset = m_Syntax.SavePos(); | |
| FX_LPVOID pResult = FXSYS_bsearch(&startxref_offset, m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| m_SortedOffset.Add(startxref_offset); | |
| } | |
| m_Syntax.GetKeyword(); | |
| FX_BOOL bNumber; | |
| CFX_ByteString xrefpos_str = m_Syntax.GetNextWord(bNumber); | |
| if (!bNumber) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| m_LastXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str); | |
| if (!LoadAllCrossRefV4(m_LastXRefOffset) && !LoadAllCrossRefV5(m_LastXRefOffset)) { | |
| if (!RebuildCrossRef()) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| bXRefRebuilt = TRUE; | |
| m_LastXRefOffset = 0; | |
| } | |
| } else { | |
| if (!RebuildCrossRef()) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| bXRefRebuilt = TRUE; | |
| } | |
| FX_DWORD dwRet = SetEncryptHandler(); | |
| if (dwRet != PDFPARSE_ERROR_SUCCESS) { | |
| return dwRet; | |
| } | |
| m_pDocument->LoadDoc(); | |
| if (m_pDocument->GetRoot() == NULL || m_pDocument->GetPageCount() == 0) { | |
| if (bXRefRebuilt) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| ReleaseEncryptHandler(); | |
| if (!RebuildCrossRef()) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| dwRet = SetEncryptHandler(); | |
| if (dwRet != PDFPARSE_ERROR_SUCCESS) { | |
| return dwRet; | |
| } | |
| m_pDocument->LoadDoc(); | |
| if (m_pDocument->GetRoot() == NULL) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| } | |
| FXSYS_qsort(m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| FX_DWORD RootObjNum = GetRootObjNum(); | |
| if (RootObjNum == 0) { | |
| ReleaseEncryptHandler(); | |
| RebuildCrossRef(); | |
| RootObjNum = GetRootObjNum(); | |
| if (RootObjNum == 0) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| dwRet = SetEncryptHandler(); | |
| if (dwRet != PDFPARSE_ERROR_SUCCESS) { | |
| return dwRet; | |
| } | |
| } | |
| if (m_pSecurityHandler && !m_pSecurityHandler->IsMetadataEncrypted()) { | |
| CPDF_Reference* pMetadata = (CPDF_Reference*)m_pDocument->GetRoot()->GetElement(FX_BSTRC("Metadata")); | |
| if (pMetadata && pMetadata->GetType() == PDFOBJ_REFERENCE) { | |
| m_Syntax.m_MetadataObjnum = pMetadata->GetRefObjNum(); | |
| } | |
| } | |
| return PDFPARSE_ERROR_SUCCESS; | |
| } | |
| FX_DWORD CPDF_Parser::SetEncryptHandler() | |
| { | |
| ReleaseEncryptHandler(); | |
| SetEncryptDictionary(NULL); | |
| if (m_pTrailer == NULL) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| CPDF_Object* pEncryptObj = m_pTrailer->GetElement(FX_BSTRC("Encrypt")); | |
| if (pEncryptObj) { | |
| if (pEncryptObj->GetType() == PDFOBJ_DICTIONARY) { | |
| SetEncryptDictionary((CPDF_Dictionary*)pEncryptObj); | |
| } else if (pEncryptObj->GetType() == PDFOBJ_REFERENCE) { | |
| pEncryptObj = m_pDocument->GetIndirectObject(((CPDF_Reference*)pEncryptObj)->GetRefObjNum()); | |
| if (pEncryptObj) { | |
| SetEncryptDictionary(pEncryptObj->GetDict()); | |
| } | |
| } | |
| } | |
| if (m_bForceUseSecurityHandler) { | |
| FX_DWORD err = PDFPARSE_ERROR_HANDLER; | |
| if (m_pSecurityHandler == NULL) { | |
| return PDFPARSE_ERROR_HANDLER; | |
| } | |
| if (!m_pSecurityHandler->OnInit(this, m_pEncryptDict)) { | |
| return err; | |
| } | |
| CPDF_CryptoHandler* pCryptoHandler = m_pSecurityHandler->CreateCryptoHandler(); | |
| if (!pCryptoHandler->Init(m_pEncryptDict, m_pSecurityHandler)) { | |
| delete pCryptoHandler; | |
| pCryptoHandler = NULL; | |
| return PDFPARSE_ERROR_HANDLER; | |
| } | |
| m_Syntax.SetEncrypt(pCryptoHandler); | |
| } else if (m_pEncryptDict) { | |
| CFX_ByteString filter = m_pEncryptDict->GetString(FX_BSTRC("Filter")); | |
| CPDF_SecurityHandler* pSecurityHandler = NULL; | |
| FX_DWORD err = PDFPARSE_ERROR_HANDLER; | |
| if (filter == FX_BSTRC("Standard")) { | |
| pSecurityHandler = FPDF_CreateStandardSecurityHandler(); | |
| err = PDFPARSE_ERROR_PASSWORD; | |
| } | |
| if (pSecurityHandler == NULL) { | |
| return PDFPARSE_ERROR_HANDLER; | |
| } | |
| if (!pSecurityHandler->OnInit(this, m_pEncryptDict)) { | |
| delete pSecurityHandler; | |
| pSecurityHandler = NULL; | |
| return err; | |
| } | |
| m_pSecurityHandler = pSecurityHandler; | |
| CPDF_CryptoHandler* pCryptoHandler = pSecurityHandler->CreateCryptoHandler(); | |
| if (!pCryptoHandler->Init(m_pEncryptDict, m_pSecurityHandler)) { | |
| delete pCryptoHandler; | |
| pCryptoHandler = NULL; | |
| return PDFPARSE_ERROR_HANDLER; | |
| } | |
| m_Syntax.SetEncrypt(pCryptoHandler); | |
| } | |
| return PDFPARSE_ERROR_SUCCESS; | |
| } | |
| void CPDF_Parser::ReleaseEncryptHandler() | |
| { | |
| if (m_Syntax.m_pCryptoHandler) { | |
| delete m_Syntax.m_pCryptoHandler; | |
| m_Syntax.m_pCryptoHandler = NULL; | |
| } | |
| if (m_pSecurityHandler && !m_bForceUseSecurityHandler) { | |
| delete m_pSecurityHandler; | |
| m_pSecurityHandler = NULL; | |
| } | |
| } | |
| FX_FILESIZE CPDF_Parser::GetObjectOffset(FX_DWORD objnum) | |
| { | |
| if (objnum >= (FX_DWORD)m_CrossRef.GetSize()) { | |
| return 0; | |
| } | |
| if (m_V5Type[objnum] == 1) { | |
| return m_CrossRef[objnum]; | |
| } | |
| if (m_V5Type[objnum] == 2) { | |
| return m_CrossRef[(FX_INT32)m_CrossRef[objnum]]; | |
| } | |
| return 0; | |
| } | |
| static FX_INT32 GetDirectInteger(CPDF_Dictionary* pDict, FX_BSTR key) | |
| { | |
| CPDF_Object* pObj = pDict->GetElement(key); | |
| if (pObj == NULL) { | |
| return 0; | |
| } | |
| if (pObj->GetType() == PDFOBJ_NUMBER) { | |
| return ((CPDF_Number*)pObj)->GetInteger(); | |
| } | |
| return 0; | |
| } | |
| static FX_BOOL CheckDirectType(CPDF_Dictionary* pDict, FX_BSTR key, FX_INT32 iType) | |
| { | |
| CPDF_Object* pObj = pDict->GetElement(key); | |
| if (!pObj) { | |
| return TRUE; | |
| } | |
| return pObj->GetType() == iType; | |
| } | |
| FX_BOOL CPDF_Parser::LoadAllCrossRefV4(FX_FILESIZE xrefpos) | |
| { | |
| if (!LoadCrossRefV4(xrefpos, 0, TRUE, FALSE)) { | |
| return FALSE; | |
| } | |
| m_pTrailer = LoadTrailerV4(); | |
| if (m_pTrailer == NULL) { | |
| return FALSE; | |
| } | |
| FX_INT32 xrefsize = GetDirectInteger(m_pTrailer, FX_BSTRC("Size")); | |
| if (xrefsize <= 0 || xrefsize > (1 << 20)) { | |
| return FALSE; | |
| } | |
| m_CrossRef.SetSize(xrefsize); | |
| m_V5Type.SetSize(xrefsize); | |
| CFX_FileSizeArray CrossRefList, XRefStreamList; | |
| CrossRefList.Add(xrefpos); | |
| XRefStreamList.Add(GetDirectInteger(m_pTrailer, FX_BSTRC("XRefStm"))); | |
| if (!CheckDirectType(m_pTrailer, FX_BSTRC("Prev"), PDFOBJ_NUMBER)) { | |
| return FALSE; | |
| } | |
| FX_FILESIZE newxrefpos = GetDirectInteger(m_pTrailer, FX_BSTRC("Prev")); | |
| if (newxrefpos == xrefpos) { | |
| return FALSE; | |
| } | |
| xrefpos = newxrefpos; | |
| while (xrefpos) { | |
| CrossRefList.InsertAt(0, xrefpos); | |
| LoadCrossRefV4(xrefpos, 0, TRUE, FALSE); | |
| CPDF_Dictionary* pDict = LoadTrailerV4(); | |
| if (pDict == NULL) { | |
| return FALSE; | |
| } | |
| if (!CheckDirectType(pDict, FX_BSTRC("Prev"), PDFOBJ_NUMBER)) { | |
| pDict->Release(); | |
| return FALSE; | |
| } | |
| newxrefpos = GetDirectInteger(pDict, FX_BSTRC("Prev")); | |
| if (newxrefpos == xrefpos) { | |
| pDict->Release(); | |
| return FALSE; | |
| } | |
| xrefpos = newxrefpos; | |
| XRefStreamList.InsertAt(0, pDict->GetInteger(FX_BSTRC("XRefStm"))); | |
| m_Trailers.Add(pDict); | |
| } | |
| for (FX_INT32 i = 0; i < CrossRefList.GetSize(); i ++) | |
| if (!LoadCrossRefV4(CrossRefList[i], XRefStreamList[i], FALSE, i == 0)) { | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_Parser::LoadLinearizedAllCrossRefV4(FX_FILESIZE xrefpos, FX_DWORD dwObjCount) | |
| { | |
| if (!LoadLinearizedCrossRefV4(xrefpos, dwObjCount)) { | |
| return FALSE; | |
| } | |
| m_pTrailer = LoadTrailerV4(); | |
| if (m_pTrailer == NULL) { | |
| return FALSE; | |
| } | |
| FX_INT32 xrefsize = GetDirectInteger(m_pTrailer, FX_BSTRC("Size")); | |
| if (xrefsize == 0) { | |
| return FALSE; | |
| } | |
| CFX_FileSizeArray CrossRefList, XRefStreamList; | |
| CrossRefList.Add(xrefpos); | |
| XRefStreamList.Add(GetDirectInteger(m_pTrailer, FX_BSTRC("XRefStm"))); | |
| xrefpos = GetDirectInteger(m_pTrailer, FX_BSTRC("Prev")); | |
| while (xrefpos) { | |
| CrossRefList.InsertAt(0, xrefpos); | |
| LoadCrossRefV4(xrefpos, 0, TRUE, FALSE); | |
| CPDF_Dictionary* pDict = LoadTrailerV4(); | |
| if (pDict == NULL) { | |
| return FALSE; | |
| } | |
| xrefpos = GetDirectInteger(pDict, FX_BSTRC("Prev")); | |
| XRefStreamList.InsertAt(0, pDict->GetInteger(FX_BSTRC("XRefStm"))); | |
| m_Trailers.Add(pDict); | |
| } | |
| for (FX_INT32 i = 1; i < CrossRefList.GetSize(); i ++) | |
| if (!LoadCrossRefV4(CrossRefList[i], XRefStreamList[i], FALSE, i == 0)) { | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_Parser::LoadLinearizedCrossRefV4(FX_FILESIZE pos, FX_DWORD dwObjCount) | |
| { | |
| FX_FILESIZE dwStartPos = pos - m_Syntax.m_HeaderOffset; | |
| m_Syntax.RestorePos(dwStartPos); | |
| FX_LPVOID pResult = FXSYS_bsearch(&pos, m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| m_SortedOffset.Add(pos); | |
| } | |
| FX_DWORD start_objnum = 0; | |
| FX_DWORD count = dwObjCount; | |
| FX_FILESIZE SavedPos = m_Syntax.SavePos(); | |
| FX_INT32 recordsize = 20; | |
| char* pBuf = FX_Alloc(char, 1024 * recordsize + 1); | |
| pBuf[1024 * recordsize] = '\0'; | |
| FX_INT32 nBlocks = count / 1024 + 1; | |
| for (FX_INT32 block = 0; block < nBlocks; block ++) { | |
| FX_INT32 block_size = block == nBlocks - 1 ? count % 1024 : 1024; | |
| FX_DWORD dwReadSize = block_size * recordsize; | |
| if ((FX_FILESIZE)(dwStartPos + dwReadSize) > m_Syntax.m_FileLen) { | |
| FX_Free(pBuf); | |
| return FALSE; | |
| } | |
| if (!m_Syntax.ReadBlock((FX_LPBYTE)pBuf, dwReadSize)) { | |
| FX_Free(pBuf); | |
| return FALSE; | |
| } | |
| for (FX_INT32 i = 0; i < block_size; i ++) { | |
| FX_DWORD objnum = start_objnum + block * 1024 + i; | |
| char* pEntry = pBuf + i * recordsize; | |
| if (pEntry[17] == 'f') { | |
| m_CrossRef.SetAtGrow(objnum, 0); | |
| m_V5Type.SetAtGrow(objnum, 0); | |
| } else { | |
| FX_INT32 offset = FXSYS_atoi(pEntry); | |
| if (offset == 0) { | |
| for (FX_INT32 c = 0; c < 10; c ++) { | |
| if (pEntry[c] < '0' || pEntry[c] > '9') { | |
| FX_Free(pBuf); | |
| return FALSE; | |
| } | |
| } | |
| } | |
| m_CrossRef.SetAtGrow(objnum, offset); | |
| FX_INT32 version = FXSYS_atoi(pEntry + 11); | |
| if (version >= 1) { | |
| m_bVersionUpdated = TRUE; | |
| } | |
| m_ObjVersion.SetAtGrow(objnum, version); | |
| if (m_CrossRef[objnum] < m_Syntax.m_FileLen) { | |
| FX_LPVOID pResult = FXSYS_bsearch(&m_CrossRef[objnum], m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| m_SortedOffset.Add(m_CrossRef[objnum]); | |
| } | |
| } | |
| m_V5Type.SetAtGrow(objnum, 1); | |
| } | |
| } | |
| } | |
| FX_Free(pBuf); | |
| m_Syntax.RestorePos(SavedPos + count * recordsize); | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_Parser::LoadCrossRefV4(FX_FILESIZE pos, FX_FILESIZE streampos, FX_BOOL bSkip, FX_BOOL bFirst) | |
| { | |
| m_Syntax.RestorePos(pos); | |
| if (m_Syntax.GetKeyword() != FX_BSTRC("xref")) { | |
| return FALSE; | |
| } | |
| FX_LPVOID pResult = FXSYS_bsearch(&pos, m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| m_SortedOffset.Add(pos); | |
| } | |
| if (streampos) { | |
| FX_LPVOID pResult = FXSYS_bsearch(&streampos, m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| m_SortedOffset.Add(streampos); | |
| } | |
| } | |
| while (1) { | |
| FX_FILESIZE SavedPos = m_Syntax.SavePos(); | |
| FX_BOOL bIsNumber; | |
| CFX_ByteString word = m_Syntax.GetNextWord(bIsNumber); | |
| if (word.IsEmpty()) { | |
| return FALSE; | |
| } | |
| if (!bIsNumber) { | |
| m_Syntax.RestorePos(SavedPos); | |
| break; | |
| } | |
| FX_DWORD start_objnum = FXSYS_atoi(word); | |
| if (start_objnum >= (1 << 20)) { | |
| return FALSE; | |
| } | |
| FX_DWORD count = m_Syntax.GetDirectNum(); | |
| m_Syntax.ToNextWord(); | |
| SavedPos = m_Syntax.SavePos(); | |
| FX_BOOL bFirstItem = FALSE; | |
| FX_INT32 recordsize = 20; | |
| if (bFirst) { | |
| bFirstItem = TRUE; | |
| } | |
| m_dwXrefStartObjNum = start_objnum; | |
| if (!bSkip) { | |
| char* pBuf = FX_Alloc(char, 1024 * recordsize + 1); | |
| pBuf[1024 * recordsize] = '\0'; | |
| FX_INT32 nBlocks = count / 1024 + 1; | |
| FX_BOOL bFirstBlock = TRUE; | |
| for (FX_INT32 block = 0; block < nBlocks; block ++) { | |
| FX_INT32 block_size = block == nBlocks - 1 ? count % 1024 : 1024; | |
| m_Syntax.ReadBlock((FX_LPBYTE)pBuf, block_size * recordsize); | |
| for (FX_INT32 i = 0; i < block_size; i ++) { | |
| FX_DWORD objnum = start_objnum + block * 1024 + i; | |
| char* pEntry = pBuf + i * recordsize; | |
| if (pEntry[17] == 'f') { | |
| if (bFirstItem) { | |
| objnum = 0; | |
| bFirstItem = FALSE; | |
| } | |
| if (bFirstBlock) { | |
| FX_FILESIZE offset = (FX_FILESIZE)FXSYS_atoi64(pEntry); | |
| FX_INT32 version = FXSYS_atoi(pEntry + 11); | |
| if (offset == 0 && version == 65535 && start_objnum != 0) { | |
| start_objnum--; | |
| objnum = 0; | |
| } | |
| } | |
| m_CrossRef.SetAtGrow(objnum, 0); | |
| m_V5Type.SetAtGrow(objnum, 0); | |
| } else { | |
| FX_FILESIZE offset = (FX_FILESIZE)FXSYS_atoi64(pEntry); | |
| if (offset == 0) { | |
| for (FX_INT32 c = 0; c < 10; c ++) { | |
| if (pEntry[c] < '0' || pEntry[c] > '9') { | |
| FX_Free(pBuf); | |
| return FALSE; | |
| } | |
| } | |
| } | |
| m_CrossRef.SetAtGrow(objnum, offset); | |
| FX_INT32 version = FXSYS_atoi(pEntry + 11); | |
| if (version >= 1) { | |
| m_bVersionUpdated = TRUE; | |
| } | |
| m_ObjVersion.SetAtGrow(objnum, version); | |
| if (m_CrossRef[objnum] < m_Syntax.m_FileLen) { | |
| FX_LPVOID pResult = FXSYS_bsearch(&m_CrossRef[objnum], m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| m_SortedOffset.Add(m_CrossRef[objnum]); | |
| } | |
| } | |
| m_V5Type.SetAtGrow(objnum, 1); | |
| } | |
| if (bFirstBlock) { | |
| bFirstBlock = FALSE; | |
| } | |
| } | |
| } | |
| FX_Free(pBuf); | |
| } | |
| m_Syntax.RestorePos(SavedPos + count * recordsize); | |
| } | |
| if (streampos) | |
| if (!LoadCrossRefV5(streampos, streampos, FALSE)) { | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_Parser::LoadAllCrossRefV5(FX_FILESIZE xrefpos) | |
| { | |
| if (!LoadCrossRefV5(xrefpos, xrefpos, TRUE)) { | |
| return FALSE; | |
| } | |
| while (xrefpos) | |
| if (!LoadCrossRefV5(xrefpos, xrefpos, FALSE)) { | |
| return FALSE; | |
| } | |
| m_ObjectStreamMap.InitHashTable(101, FALSE); | |
| m_bXRefStream = TRUE; | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_Parser::RebuildCrossRef() | |
| { | |
| m_CrossRef.RemoveAll(); | |
| m_V5Type.RemoveAll(); | |
| m_SortedOffset.RemoveAll(); | |
| m_ObjVersion.RemoveAll(); | |
| if (m_pTrailer) { | |
| m_pTrailer->Release(); | |
| m_pTrailer = NULL; | |
| } | |
| FX_INT32 status = 0; | |
| FX_INT32 inside_index = 0; | |
| FX_DWORD objnum, gennum; | |
| FX_INT32 depth = 0; | |
| FX_LPBYTE buffer = FX_Alloc(FX_BYTE, 4096); | |
| FX_FILESIZE pos = m_Syntax.m_HeaderOffset; | |
| FX_FILESIZE start_pos, start_pos1; | |
| FX_FILESIZE last_obj = -1, last_xref = -1, last_trailer = -1; | |
| FX_BOOL bInUpdate = FALSE; | |
| while (pos < m_Syntax.m_FileLen) { | |
| FX_BOOL bOverFlow = FALSE; | |
| FX_DWORD size = (FX_DWORD)(m_Syntax.m_FileLen - pos); | |
| if (size > 4096) { | |
| size = 4096; | |
| } | |
| if (!m_Syntax.m_pFileAccess->ReadBlock(buffer, pos, size)) { | |
| break; | |
| } | |
| for (FX_DWORD i = 0; i < size; i ++) { | |
| FX_BYTE byte = buffer[i]; | |
| FX_LPBYTE pData = buffer + i; | |
| switch (status) { | |
| case 0: | |
| if (_PDF_CharType[byte] == 'W') { | |
| status = 1; | |
| } | |
| if (byte <= '9' && byte >= '0') { | |
| --i; | |
| status = 1; | |
| } | |
| if (byte == '%') { | |
| inside_index = 0; | |
| status = 9; | |
| } | |
| if (byte == '(') { | |
| status = 10; | |
| depth = 1; | |
| } | |
| if (byte == '<') { | |
| inside_index = 1; | |
| status = 11; | |
| } | |
| if (byte == '\\') { | |
| status = 13; | |
| } | |
| if (byte == 't') { | |
| status = 7; | |
| inside_index = 1; | |
| } | |
| break; | |
| case 1: | |
| if (_PDF_CharType[byte] == 'W') { | |
| break; | |
| } else if (byte <= '9' && byte >= '0') { | |
| start_pos = pos + i; | |
| status = 2; | |
| objnum = byte - '0'; | |
| } else if (byte == 't') { | |
| status = 7; | |
| inside_index = 1; | |
| } else if (byte == 'x') { | |
| status = 8; | |
| inside_index = 1; | |
| } else { | |
| --i; | |
| status = 0; | |
| } | |
| break; | |
| case 2: | |
| if (byte <= '9' && byte >= '0') { | |
| objnum = objnum * 10 + byte - '0'; | |
| break; | |
| } else if (_PDF_CharType[byte] == 'W') { | |
| status = 3; | |
| } else { | |
| --i; | |
| status = 14; | |
| inside_index = 0; | |
| } | |
| break; | |
| case 3: | |
| if (byte <= '9' && byte >= '0') { | |
| start_pos1 = pos + i; | |
| status = 4; | |
| gennum = byte - '0'; | |
| } else if (_PDF_CharType[byte] == 'W') { | |
| break; | |
| } else if (byte == 't') { | |
| status = 7; | |
| inside_index = 1; | |
| } else { | |
| --i; | |
| status = 0; | |
| } | |
| break; | |
| case 4: | |
| if (byte <= '9' && byte >= '0') { | |
| gennum = gennum * 10 + byte - '0'; | |
| break; | |
| } else if (_PDF_CharType[byte] == 'W') { | |
| status = 5; | |
| } else { | |
| --i; | |
| status = 0; | |
| } | |
| break; | |
| case 5: | |
| if (byte == 'o') { | |
| status = 6; | |
| inside_index = 1; | |
| } else if (_PDF_CharType[byte] == 'W') { | |
| break; | |
| } else if (byte <= '9' && byte >= '0') { | |
| objnum = gennum; | |
| gennum = byte - '0'; | |
| start_pos = start_pos1; | |
| start_pos1 = pos + i; | |
| status = 4; | |
| } else if (byte == 't') { | |
| status = 7; | |
| inside_index = 1; | |
| } else { | |
| --i; | |
| status = 0; | |
| } | |
| break; | |
| case 6: | |
| switch (inside_index) { | |
| case 1: | |
| if (byte != 'b') { | |
| --i; | |
| status = 0; | |
| } else { | |
| inside_index ++; | |
| } | |
| break; | |
| case 2: | |
| if (byte != 'j') { | |
| --i; | |
| status = 0; | |
| } else { | |
| inside_index ++; | |
| } | |
| break; | |
| case 3: | |
| if (_PDF_CharType[byte] == 'W' || _PDF_CharType[byte] == 'D') { | |
| if (objnum > 0x1000000) { | |
| status = 0; | |
| break; | |
| } | |
| FX_FILESIZE obj_pos = start_pos - m_Syntax.m_HeaderOffset; | |
| last_obj = start_pos; | |
| FX_LPVOID pResult = FXSYS_bsearch(&obj_pos, m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| m_SortedOffset.Add(obj_pos); | |
| } | |
| FX_FILESIZE obj_end = 0; | |
| CPDF_Object *pObject = ParseIndirectObjectAtByStrict(m_pDocument, obj_pos, objnum, NULL, &obj_end); | |
| if (pObject) { | |
| int iType = pObject->GetType(); | |
| if (iType == PDFOBJ_STREAM) { | |
| CPDF_Stream* pStream = (CPDF_Stream*)pObject; | |
| CPDF_Dictionary* pDict = pStream->GetDict(); | |
| if (pDict) { | |
| if (pDict->KeyExist(FX_BSTRC("Type"))) { | |
| CFX_ByteString bsValue = pDict->GetString(FX_BSTRC("Type")); | |
| if (bsValue == FX_BSTRC("XRef") && pDict->KeyExist(FX_BSTRC("Size"))) { | |
| CPDF_Object* pRoot = pDict->GetElement(FX_BSTRC("Root")); | |
| if (pRoot && pRoot->GetDict() && pRoot->GetDict()->GetElement(FX_BSTRC("Pages"))) { | |
| if (m_pTrailer) { | |
| m_pTrailer->Release(); | |
| } | |
| m_pTrailer = (CPDF_Dictionary*)pDict->Clone(); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| FX_FILESIZE offset = 0; | |
| m_Syntax.RestorePos(obj_pos); | |
| offset = m_Syntax.FindTag(FX_BSTRC("obj"), 0); | |
| if (offset == -1) { | |
| offset = 0; | |
| } else { | |
| offset += 3; | |
| } | |
| FX_FILESIZE nLen = obj_end - obj_pos - offset; | |
| if ((FX_DWORD)nLen > size - i) { | |
| pos = obj_end + m_Syntax.m_HeaderOffset; | |
| bOverFlow = TRUE; | |
| } else { | |
| i += (FX_DWORD)nLen; | |
| } | |
| if (m_CrossRef.GetSize() > (FX_INT32)objnum && m_CrossRef[objnum]) { | |
| if (pObject) { | |
| FX_DWORD oldgen = m_ObjVersion.GetAt(objnum); | |
| m_CrossRef[objnum] = obj_pos; | |
| m_ObjVersion.SetAt(objnum, (FX_SHORT)gennum); | |
| if (oldgen != gennum) { | |
| m_bVersionUpdated = TRUE; | |
| } | |
| } | |
| } else { | |
| m_CrossRef.SetAtGrow(objnum, obj_pos); | |
| m_V5Type.SetAtGrow(objnum, 1); | |
| m_ObjVersion.SetAtGrow(objnum, (FX_SHORT)gennum); | |
| } | |
| if (pObject) { | |
| pObject->Release(); | |
| } | |
| } | |
| --i; | |
| status = 0; | |
| break; | |
| } | |
| break; | |
| case 7: | |
| if (inside_index == 7) { | |
| if (_PDF_CharType[byte] == 'W' || _PDF_CharType[byte] == 'D') { | |
| last_trailer = pos + i - 7; | |
| m_Syntax.RestorePos(pos + i - m_Syntax.m_HeaderOffset); | |
| CPDF_Object* pObj = m_Syntax.GetObject(m_pDocument, 0, 0, 0); | |
| if (pObj) { | |
| if (pObj->GetType() != PDFOBJ_DICTIONARY && pObj->GetType() != PDFOBJ_STREAM) { | |
| pObj->Release(); | |
| } else { | |
| CPDF_Dictionary* pTrailer = NULL; | |
| if (pObj->GetType() == PDFOBJ_STREAM) { | |
| pTrailer = ((CPDF_Stream*)pObj)->GetDict(); | |
| } else { | |
| pTrailer = (CPDF_Dictionary*)pObj; | |
| } | |
| if (pTrailer) { | |
| if (m_pTrailer) { | |
| CPDF_Object* pRoot = pTrailer->GetElement(FX_BSTRC("Root")); | |
| if (pRoot == NULL || (pRoot->GetType() == PDFOBJ_REFERENCE && | |
| (FX_DWORD)m_CrossRef.GetSize() > ((CPDF_Reference*)pRoot)->GetRefObjNum() && | |
| m_CrossRef.GetAt(((CPDF_Reference*)pRoot)->GetRefObjNum()) != 0)) { | |
| FX_POSITION pos = pTrailer->GetStartPos(); | |
| while (pos) { | |
| CFX_ByteString key; | |
| CPDF_Object* pObj = pTrailer->GetNextElement(pos, key); | |
| m_pTrailer->SetAt(key, pObj->Clone(), m_pDocument); | |
| } | |
| pObj->Release(); | |
| } else { | |
| pObj->Release(); | |
| } | |
| } else { | |
| if (pObj->GetType() == PDFOBJ_STREAM) { | |
| m_pTrailer = (CPDF_Dictionary*)pTrailer->Clone(); | |
| pObj->Release(); | |
| } else { | |
| m_pTrailer = pTrailer; | |
| } | |
| FX_FILESIZE dwSavePos = m_Syntax.SavePos(); | |
| CFX_ByteString strWord = m_Syntax.GetKeyword(); | |
| if (!strWord.Compare(FX_BSTRC("startxref"))) { | |
| FX_BOOL bNumber = FALSE; | |
| CFX_ByteString bsOffset = m_Syntax.GetNextWord(bNumber); | |
| if (bNumber) { | |
| m_LastXRefOffset = FXSYS_atoi(bsOffset); | |
| } | |
| } | |
| m_Syntax.RestorePos(dwSavePos); | |
| } | |
| } else { | |
| pObj->Release(); | |
| } | |
| bInUpdate = TRUE; | |
| } | |
| } | |
| } | |
| --i; | |
| status = 0; | |
| } else if (byte == "trailer"[inside_index]) { | |
| inside_index ++; | |
| } else { | |
| --i; | |
| status = 0; | |
| } | |
| break; | |
| case 8: | |
| if (inside_index == 4) { | |
| last_xref = pos + i - 4; | |
| status = 1; | |
| } else if (byte == "xref"[inside_index]) { | |
| inside_index ++; | |
| } else { | |
| --i; | |
| status = 0; | |
| } | |
| break; | |
| case 9: | |
| if (byte == '\r' || byte == '\n') { | |
| status = 0; | |
| } | |
| break; | |
| case 10: | |
| if (byte == ')') { | |
| if (depth > 0) { | |
| depth--; | |
| } | |
| } else if (byte == '(') { | |
| depth++; | |
| } | |
| if (!depth) { | |
| status = 0; | |
| } | |
| break; | |
| case 11: | |
| if (byte == '<' && inside_index == 1) { | |
| status = 12; | |
| } else if (byte == '>') { | |
| status = 0; | |
| } | |
| inside_index = 0; | |
| break; | |
| case 12: | |
| --i; | |
| status = 0; | |
| break; | |
| case 13: | |
| if (_PDF_CharType[byte] == 'D' || _PDF_CharType[byte] == 'W') { | |
| --i; | |
| status = 0; | |
| } | |
| break; | |
| case 14: | |
| if (_PDF_CharType[byte] == 'W') { | |
| status = 0; | |
| } else if (byte == '%' || byte == '(' || byte == '<' || byte == '\\') { | |
| status = 0; | |
| --i; | |
| } else if (inside_index == 6) { | |
| status = 0; | |
| --i; | |
| } else if (byte == "endobj"[inside_index]) { | |
| inside_index++; | |
| } | |
| break; | |
| } | |
| if (bOverFlow) { | |
| size = 0; | |
| break; | |
| } | |
| } | |
| pos += size; | |
| } | |
| if (last_xref != -1 && last_xref > last_obj) { | |
| last_trailer = last_xref; | |
| } else if (last_trailer == -1 || last_xref < last_obj) { | |
| last_trailer = m_Syntax.m_FileLen; | |
| } | |
| FX_FILESIZE offset = last_trailer - m_Syntax.m_HeaderOffset; | |
| FX_LPVOID pResult = FXSYS_bsearch(&offset, m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| m_SortedOffset.Add(offset); | |
| } | |
| FX_Free(buffer); | |
| return TRUE; | |
| } | |
| static FX_DWORD _GetVarInt(FX_LPCBYTE p, FX_INT32 n) | |
| { | |
| FX_DWORD result = 0; | |
| for (FX_INT32 i = 0; i < n; i ++) { | |
| result = result * 256 + p[i]; | |
| } | |
| return result; | |
| } | |
| FX_BOOL CPDF_Parser::LoadCrossRefV5(FX_FILESIZE pos, FX_FILESIZE& prev, FX_BOOL bMainXRef) | |
| { | |
| CPDF_Stream* pStream = (CPDF_Stream*)ParseIndirectObjectAt(m_pDocument, pos, 0, NULL); | |
| if (!pStream) { | |
| return FALSE; | |
| } | |
| if (m_pDocument) { | |
| m_pDocument->InsertIndirectObject(pStream->m_ObjNum, pStream); | |
| } | |
| if (pStream->GetType() != PDFOBJ_STREAM) { | |
| return FALSE; | |
| } | |
| prev = pStream->GetDict()->GetInteger(FX_BSTRC("Prev")); | |
| FX_INT32 size = pStream->GetDict()->GetInteger(FX_BSTRC("Size")); | |
| if (size < 0) { | |
| pStream->Release(); | |
| return FALSE; | |
| } | |
| if (bMainXRef) { | |
| m_pTrailer = (CPDF_Dictionary*)pStream->GetDict()->Clone(); | |
| m_CrossRef.SetSize(size); | |
| if (m_V5Type.SetSize(size)) { | |
| FXSYS_memset32(m_V5Type.GetData(), 0, size); | |
| } | |
| } else { | |
| m_Trailers.Add((CPDF_Dictionary*)pStream->GetDict()->Clone()); | |
| } | |
| CFX_DWordArray IndexArray, WidthArray; | |
| FX_DWORD nSegs = 0; | |
| CPDF_Array* pArray = pStream->GetDict()->GetArray(FX_BSTRC("Index")); | |
| if (pArray == NULL) { | |
| IndexArray.Add(0); | |
| IndexArray.Add(size); | |
| nSegs = 1; | |
| } else { | |
| for (FX_DWORD i = 0; i < pArray->GetCount(); i ++) { | |
| IndexArray.Add(pArray->GetInteger(i)); | |
| } | |
| nSegs = pArray->GetCount() / 2; | |
| } | |
| pArray = pStream->GetDict()->GetArray(FX_BSTRC("W")); | |
| if (pArray == NULL) { | |
| pStream->Release(); | |
| return FALSE; | |
| } | |
| FX_DWORD totalwidth = 0; | |
| FX_DWORD i; | |
| for (i = 0; i < pArray->GetCount(); i ++) { | |
| WidthArray.Add(pArray->GetInteger(i)); | |
| if (totalwidth + WidthArray[i] < totalwidth) { | |
| pStream->Release(); | |
| return FALSE; | |
| } | |
| totalwidth += WidthArray[i]; | |
| } | |
| if (totalwidth == 0 || WidthArray.GetSize() < 3) { | |
| pStream->Release(); | |
| return FALSE; | |
| } | |
| CPDF_StreamAcc acc; | |
| acc.LoadAllData(pStream); | |
| FX_LPCBYTE pData = acc.GetData(); | |
| FX_DWORD dwTotalSize = acc.GetSize(); | |
| FX_DWORD segindex = 0; | |
| for (i = 0; i < nSegs; i ++) { | |
| FX_INT32 startnum = IndexArray[i * 2]; | |
| if (startnum < 0) { | |
| continue; | |
| } | |
| m_dwXrefStartObjNum = startnum; | |
| FX_DWORD count = IndexArray[i * 2 + 1]; | |
| if (segindex + count < segindex || segindex + count == 0 || | |
| (FX_DWORD)totalwidth >= UINT_MAX / (segindex + count) || (segindex + count) * (FX_DWORD)totalwidth > dwTotalSize) { | |
| continue; | |
| } | |
| FX_LPCBYTE segstart = pData + segindex * (FX_DWORD)totalwidth; | |
| if ((FX_DWORD)startnum + count < (FX_DWORD)startnum || | |
| (FX_DWORD)startnum + count > (FX_DWORD)m_V5Type.GetSize()) { | |
| continue; | |
| } | |
| for (FX_DWORD j = 0; j < count; j ++) { | |
| FX_INT32 type = 1; | |
| FX_LPCBYTE entrystart = segstart + j * totalwidth; | |
| if (WidthArray[0]) { | |
| type = _GetVarInt(entrystart, WidthArray[0]); | |
| } | |
| if (m_V5Type[startnum + j] == 255) { | |
| FX_FILESIZE offset = _GetVarInt(entrystart + WidthArray[0], WidthArray[1]); | |
| m_CrossRef[startnum + j] = offset; | |
| FX_LPVOID pResult = FXSYS_bsearch(&offset, m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| m_SortedOffset.Add(offset); | |
| } | |
| continue; | |
| } | |
| if (m_V5Type[startnum + j]) { | |
| continue; | |
| } | |
| m_V5Type[startnum + j] = type; | |
| if (type == 0) { | |
| m_CrossRef[startnum + j] = 0; | |
| } else { | |
| FX_FILESIZE offset = _GetVarInt(entrystart + WidthArray[0], WidthArray[1]); | |
| m_CrossRef[startnum + j] = offset; | |
| if (type == 1) { | |
| FX_LPVOID pResult = FXSYS_bsearch(&offset, m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| m_SortedOffset.Add(offset); | |
| } | |
| } else { | |
| if (offset < 0 || offset >= m_V5Type.GetSize()) { | |
| pStream->Release(); | |
| return FALSE; | |
| } | |
| m_V5Type[offset] = 255; | |
| } | |
| } | |
| } | |
| segindex += count; | |
| } | |
| pStream->Release(); | |
| return TRUE; | |
| } | |
| CPDF_Array* CPDF_Parser::GetIDArray() | |
| { | |
| CPDF_Object* pID = m_pTrailer->GetElement(FX_BSTRC("ID")); | |
| if (pID == NULL) { | |
| return NULL; | |
| } | |
| if (pID->GetType() == PDFOBJ_REFERENCE) { | |
| pID = ParseIndirectObject(NULL, ((CPDF_Reference*)pID)->GetRefObjNum()); | |
| m_pTrailer->SetAt(FX_BSTRC("ID"), pID); | |
| } | |
| if (pID == NULL || pID->GetType() != PDFOBJ_ARRAY) { | |
| return NULL; | |
| } | |
| return (CPDF_Array*)pID; | |
| } | |
| FX_DWORD CPDF_Parser::GetRootObjNum() | |
| { | |
| CPDF_Reference* pRef = (CPDF_Reference*)m_pTrailer->GetElement(FX_BSTRC("Root")); | |
| if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) { | |
| return 0; | |
| } | |
| return pRef->GetRefObjNum(); | |
| } | |
| FX_DWORD CPDF_Parser::GetInfoObjNum() | |
| { | |
| CPDF_Reference* pRef = (CPDF_Reference*)m_pTrailer->GetElement(FX_BSTRC("Info")); | |
| if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) { | |
| return 0; | |
| } | |
| return pRef->GetRefObjNum(); | |
| } | |
| FX_BOOL CPDF_Parser::IsFormStream(FX_DWORD objnum, FX_BOOL& bForm) | |
| { | |
| bForm = FALSE; | |
| if (objnum >= (FX_DWORD)m_CrossRef.GetSize()) { | |
| return TRUE; | |
| } | |
| if (m_V5Type[objnum] == 0) { | |
| return TRUE; | |
| } | |
| if (m_V5Type[objnum] == 2) { | |
| return TRUE; | |
| } | |
| FX_FILESIZE pos = m_CrossRef[objnum]; | |
| FX_LPVOID pResult = FXSYS_bsearch(&pos, m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| return TRUE; | |
| } | |
| if ((FX_FILESIZE*)pResult - (FX_FILESIZE*)m_SortedOffset.GetData() == m_SortedOffset.GetSize() - 1) { | |
| return FALSE; | |
| } | |
| FX_FILESIZE size = ((FX_FILESIZE*)pResult)[1] - pos; | |
| FX_FILESIZE SavedPos = m_Syntax.SavePos(); | |
| m_Syntax.RestorePos(pos); | |
| bForm = m_Syntax.SearchMultiWord(FX_BSTRC("/Form\0stream"), TRUE, size) == 0; | |
| m_Syntax.RestorePos(SavedPos); | |
| return TRUE; | |
| } | |
| CPDF_Object* CPDF_Parser::ParseIndirectObject(CPDF_IndirectObjects* pObjList, FX_DWORD objnum, PARSE_CONTEXT* pContext) | |
| { | |
| if (objnum >= (FX_DWORD)m_CrossRef.GetSize()) { | |
| return NULL; | |
| } | |
| if (m_V5Type[objnum] == 1 || m_V5Type[objnum] == 255) { | |
| FX_FILESIZE pos = m_CrossRef[objnum]; | |
| if (pos <= 0) { | |
| return NULL; | |
| } | |
| return ParseIndirectObjectAt(pObjList, pos, objnum, pContext); | |
| } | |
| if (m_V5Type[objnum] == 2) { | |
| CPDF_StreamAcc* pObjStream = GetObjectStream((FX_DWORD)m_CrossRef[objnum]); | |
| if (pObjStream == NULL) { | |
| return NULL; | |
| } | |
| FX_INT32 n = pObjStream->GetDict()->GetInteger(FX_BSTRC("N")); | |
| FX_INT32 offset = pObjStream->GetDict()->GetInteger(FX_BSTRC("First")); | |
| CPDF_SyntaxParser syntax; | |
| CFX_SmartPointer<IFX_FileStream> file(FX_CreateMemoryStream((FX_LPBYTE)pObjStream->GetData(), (size_t)pObjStream->GetSize(), FALSE)); | |
| syntax.InitParser((IFX_FileStream*)file, 0); | |
| CPDF_Object* pRet = NULL; | |
| while (n) { | |
| FX_DWORD thisnum = syntax.GetDirectNum(); | |
| FX_DWORD thisoff = syntax.GetDirectNum(); | |
| if (thisnum == objnum) { | |
| syntax.RestorePos(offset + thisoff); | |
| pRet = syntax.GetObject(pObjList, 0, 0, 0, pContext); | |
| break; | |
| } | |
| n --; | |
| } | |
| return pRet; | |
| } | |
| return NULL; | |
| } | |
| CPDF_StreamAcc* CPDF_Parser::GetObjectStream(FX_DWORD objnum) | |
| { | |
| CPDF_StreamAcc* pStreamAcc = NULL; | |
| if (m_ObjectStreamMap.Lookup((void*)(FX_UINTPTR)objnum, (void*&)pStreamAcc)) { | |
| return pStreamAcc; | |
| } | |
| const CPDF_Stream* pStream = (CPDF_Stream*)m_pDocument->GetIndirectObject(objnum); | |
| if (pStream == NULL || pStream->GetType() != PDFOBJ_STREAM) { | |
| return NULL; | |
| } | |
| pStreamAcc = FX_NEW CPDF_StreamAcc; | |
| pStreamAcc->LoadAllData(pStream); | |
| m_ObjectStreamMap.SetAt((void*)(FX_UINTPTR)objnum, pStreamAcc); | |
| return pStreamAcc; | |
| } | |
| FX_FILESIZE CPDF_Parser::GetObjectSize(FX_DWORD objnum) | |
| { | |
| if (objnum >= (FX_DWORD)m_CrossRef.GetSize()) { | |
| return 0; | |
| } | |
| if (m_V5Type[objnum] == 2) { | |
| objnum = (FX_DWORD)m_CrossRef[objnum]; | |
| } | |
| if (m_V5Type[objnum] == 1 || m_V5Type[objnum] == 255) { | |
| FX_FILESIZE offset = m_CrossRef[objnum]; | |
| if (offset == 0) { | |
| return 0; | |
| } | |
| FX_LPVOID pResult = FXSYS_bsearch(&offset, m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| return 0; | |
| } | |
| if ((FX_FILESIZE*)pResult - (FX_FILESIZE*)m_SortedOffset.GetData() == m_SortedOffset.GetSize() - 1) { | |
| return 0; | |
| } | |
| return ((FX_FILESIZE*)pResult)[1] - offset; | |
| } | |
| return 0; | |
| } | |
| void CPDF_Parser::GetIndirectBinary(FX_DWORD objnum, FX_LPBYTE& pBuffer, FX_DWORD& size) | |
| { | |
| pBuffer = NULL; | |
| size = 0; | |
| if (objnum >= (FX_DWORD)m_CrossRef.GetSize()) { | |
| return; | |
| } | |
| if (m_V5Type[objnum] == 2) { | |
| CPDF_StreamAcc* pObjStream = GetObjectStream((FX_DWORD)m_CrossRef[objnum]); | |
| if (pObjStream == NULL) { | |
| return; | |
| } | |
| FX_INT32 n = pObjStream->GetDict()->GetInteger(FX_BSTRC("N")); | |
| FX_INT32 offset = pObjStream->GetDict()->GetInteger(FX_BSTRC("First")); | |
| CPDF_SyntaxParser syntax; | |
| FX_LPCBYTE pData = pObjStream->GetData(); | |
| FX_DWORD totalsize = pObjStream->GetSize(); | |
| CFX_SmartPointer<IFX_FileStream> file(FX_CreateMemoryStream((FX_LPBYTE)pData, (size_t)totalsize, FALSE)); | |
| syntax.InitParser((IFX_FileStream*)file, 0); | |
| while (n) { | |
| FX_DWORD thisnum = syntax.GetDirectNum(); | |
| FX_DWORD thisoff = syntax.GetDirectNum(); | |
| if (thisnum == objnum) { | |
| if (n == 1) { | |
| size = totalsize - (thisoff + offset); | |
| } else { | |
| FX_DWORD nextnum = syntax.GetDirectNum(); | |
| FX_DWORD nextoff = syntax.GetDirectNum(); | |
| size = nextoff - thisoff; | |
| } | |
| pBuffer = FX_Alloc(FX_BYTE, size); | |
| FXSYS_memcpy32(pBuffer, pData + thisoff + offset, size); | |
| return; | |
| } | |
| n --; | |
| } | |
| return; | |
| } | |
| if (m_V5Type[objnum] == 1) { | |
| FX_FILESIZE pos = m_CrossRef[objnum]; | |
| if (pos == 0) { | |
| return; | |
| } | |
| FX_FILESIZE SavedPos = m_Syntax.SavePos(); | |
| m_Syntax.RestorePos(pos); | |
| FX_BOOL bIsNumber; | |
| CFX_ByteString word = m_Syntax.GetNextWord(bIsNumber); | |
| if (!bIsNumber) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return; | |
| } | |
| FX_DWORD real_objnum = FXSYS_atoi(word); | |
| if (real_objnum && real_objnum != objnum) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return; | |
| } | |
| word = m_Syntax.GetNextWord(bIsNumber); | |
| if (!bIsNumber) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return; | |
| } | |
| if (m_Syntax.GetKeyword() != FX_BSTRC("obj")) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return; | |
| } | |
| FX_LPVOID pResult = FXSYS_bsearch(&pos, m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return; | |
| } | |
| FX_FILESIZE nextoff = ((FX_FILESIZE*)pResult)[1]; | |
| FX_BOOL bNextOffValid = FALSE; | |
| if (nextoff != pos) { | |
| m_Syntax.RestorePos(nextoff); | |
| word = m_Syntax.GetNextWord(bIsNumber); | |
| if (word == FX_BSTRC("xref")) { | |
| bNextOffValid = TRUE; | |
| } else if (bIsNumber) { | |
| word = m_Syntax.GetNextWord(bIsNumber); | |
| if (bIsNumber && m_Syntax.GetKeyword() == FX_BSTRC("obj")) { | |
| bNextOffValid = TRUE; | |
| } | |
| } | |
| } | |
| if (!bNextOffValid) { | |
| m_Syntax.RestorePos(pos); | |
| while (1) { | |
| if (m_Syntax.GetKeyword() == FX_BSTRC("endobj")) { | |
| break; | |
| } | |
| if (m_Syntax.SavePos() == m_Syntax.m_FileLen) { | |
| break; | |
| } | |
| } | |
| nextoff = m_Syntax.SavePos(); | |
| } | |
| size = (FX_DWORD)(nextoff - pos); | |
| pBuffer = FX_Alloc(FX_BYTE, size); | |
| m_Syntax.RestorePos(pos); | |
| m_Syntax.ReadBlock(pBuffer, size); | |
| m_Syntax.RestorePos(SavedPos); | |
| } | |
| } | |
| CPDF_Object* CPDF_Parser::ParseIndirectObjectAt(CPDF_IndirectObjects* pObjList, FX_FILESIZE pos, FX_DWORD objnum, | |
| PARSE_CONTEXT* pContext) | |
| { | |
| FX_FILESIZE SavedPos = m_Syntax.SavePos(); | |
| m_Syntax.RestorePos(pos); | |
| FX_BOOL bIsNumber; | |
| CFX_ByteString word = m_Syntax.GetNextWord(bIsNumber); | |
| if (!bIsNumber) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return NULL; | |
| } | |
| FX_FILESIZE objOffset = m_Syntax.SavePos(); | |
| objOffset -= word.GetLength(); | |
| FX_DWORD real_objnum = FXSYS_atoi(word); | |
| if (objnum && real_objnum != objnum) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return NULL; | |
| } | |
| word = m_Syntax.GetNextWord(bIsNumber); | |
| if (!bIsNumber) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return NULL; | |
| } | |
| FX_DWORD gennum = FXSYS_atoi(word); | |
| if (m_Syntax.GetKeyword() != FX_BSTRC("obj")) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return NULL; | |
| } | |
| CPDF_Object* pObj = m_Syntax.GetObject(pObjList, objnum, gennum, 0, pContext); | |
| FX_FILESIZE endOffset = m_Syntax.SavePos(); | |
| CFX_ByteString bsWord = m_Syntax.GetKeyword(); | |
| if (bsWord == FX_BSTRC("endobj")) { | |
| endOffset = m_Syntax.SavePos(); | |
| } | |
| FX_DWORD objSize = endOffset - objOffset; | |
| m_Syntax.RestorePos(SavedPos); | |
| if (pObj && !objnum) { | |
| pObj->m_ObjNum = real_objnum; | |
| } | |
| return pObj; | |
| } | |
| CPDF_Object* CPDF_Parser::ParseIndirectObjectAtByStrict(CPDF_IndirectObjects* pObjList, FX_FILESIZE pos, FX_DWORD objnum, | |
| struct PARSE_CONTEXT* pContext, FX_FILESIZE *pResultPos) | |
| { | |
| FX_FILESIZE SavedPos = m_Syntax.SavePos(); | |
| m_Syntax.RestorePos(pos); | |
| FX_BOOL bIsNumber; | |
| CFX_ByteString word = m_Syntax.GetNextWord(bIsNumber); | |
| if (!bIsNumber) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return NULL; | |
| } | |
| FX_DWORD real_objnum = FXSYS_atoi(word); | |
| if (objnum && real_objnum != objnum) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return NULL; | |
| } | |
| word = m_Syntax.GetNextWord(bIsNumber); | |
| if (!bIsNumber) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return NULL; | |
| } | |
| FX_DWORD gennum = FXSYS_atoi(word); | |
| if (m_Syntax.GetKeyword() != FX_BSTRC("obj")) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return NULL; | |
| } | |
| CPDF_Object* pObj = m_Syntax.GetObjectByStrict(pObjList, objnum, gennum, 0, pContext); | |
| if (pResultPos) { | |
| *pResultPos = m_Syntax.m_Pos; | |
| } | |
| m_Syntax.RestorePos(SavedPos); | |
| return pObj; | |
| } | |
| CPDF_Dictionary* CPDF_Parser::LoadTrailerV4() | |
| { | |
| if (m_Syntax.GetKeyword() != FX_BSTRC("trailer")) { | |
| return NULL; | |
| } | |
| CPDF_Object* pObj = m_Syntax.GetObject(m_pDocument, 0, 0, 0); | |
| if (pObj == NULL || pObj->GetType() != PDFOBJ_DICTIONARY) { | |
| if (pObj) { | |
| pObj->Release(); | |
| } | |
| return NULL; | |
| } | |
| return (CPDF_Dictionary*)pObj; | |
| } | |
| FX_DWORD CPDF_Parser::GetPermissions(FX_BOOL bCheckRevision) | |
| { | |
| if (m_pSecurityHandler == NULL) { | |
| return (FX_DWORD) - 1; | |
| } | |
| FX_DWORD dwPermission = m_pSecurityHandler->GetPermissions(); | |
| if (m_pEncryptDict && m_pEncryptDict->GetString(FX_BSTRC("Filter")) == FX_BSTRC("Standard")) { | |
| dwPermission &= 0xFFFFFFFC; | |
| dwPermission |= 0xFFFFF0C0; | |
| if(bCheckRevision && m_pEncryptDict->GetInteger(FX_BSTRC("R")) == 2) { | |
| dwPermission &= 0xFFFFF0FF; | |
| } | |
| } | |
| return dwPermission; | |
| } | |
| FX_BOOL CPDF_Parser::IsOwner() | |
| { | |
| return m_pSecurityHandler == NULL ? TRUE : m_pSecurityHandler->IsOwner(); | |
| } | |
| void CPDF_Parser::SetSecurityHandler(CPDF_SecurityHandler* pSecurityHandler, FX_BOOL bForced) | |
| { | |
| ASSERT(m_pSecurityHandler == NULL); | |
| if (m_pSecurityHandler && !m_bForceUseSecurityHandler) { | |
| delete m_pSecurityHandler; | |
| m_pSecurityHandler = NULL; | |
| } | |
| m_bForceUseSecurityHandler = bForced; | |
| m_pSecurityHandler = pSecurityHandler; | |
| if (m_bForceUseSecurityHandler) { | |
| return; | |
| } | |
| m_Syntax.m_pCryptoHandler = pSecurityHandler->CreateCryptoHandler(); | |
| m_Syntax.m_pCryptoHandler->Init(NULL, pSecurityHandler); | |
| } | |
| FX_BOOL CPDF_Parser::IsLinearizedFile(IFX_FileRead* pFileAccess, FX_DWORD offset) | |
| { | |
| m_Syntax.InitParser(pFileAccess, offset); | |
| m_Syntax.RestorePos(m_Syntax.m_HeaderOffset + 9); | |
| FX_FILESIZE SavedPos = m_Syntax.SavePos(); | |
| FX_BOOL bIsNumber; | |
| CFX_ByteString word = m_Syntax.GetNextWord(bIsNumber); | |
| if (!bIsNumber) { | |
| return FALSE; | |
| } | |
| FX_DWORD objnum = FXSYS_atoi(word); | |
| word = m_Syntax.GetNextWord(bIsNumber); | |
| if (!bIsNumber) { | |
| return FALSE; | |
| } | |
| FX_DWORD gennum = FXSYS_atoi(word); | |
| if (m_Syntax.GetKeyword() != FX_BSTRC("obj")) { | |
| m_Syntax.RestorePos(SavedPos); | |
| return FALSE; | |
| } | |
| m_pLinearized = m_Syntax.GetObject(NULL, objnum, gennum, 0); | |
| if (!m_pLinearized) { | |
| return FALSE; | |
| } | |
| if (m_pLinearized->GetDict()->GetElement(FX_BSTRC("Linearized"))) { | |
| m_Syntax.GetNextWord(bIsNumber); | |
| CPDF_Object *pLen = m_pLinearized->GetDict()->GetElement(FX_BSTRC("L")); | |
| if (!pLen) { | |
| m_pLinearized->Release(); | |
| return FALSE; | |
| } | |
| if (pLen->GetInteger() != (int)pFileAccess->GetSize()) { | |
| return FALSE; | |
| } | |
| CPDF_Object *pNo = m_pLinearized->GetDict()->GetElement(FX_BSTRC("P")); | |
| if (pNo && pNo->GetType() == PDFOBJ_NUMBER) { | |
| m_dwFirstPageNo = pNo->GetInteger(); | |
| } | |
| CPDF_Object *pTable = m_pLinearized->GetDict()->GetElement(FX_BSTRC("T")); | |
| if (pTable && pTable->GetType() == PDFOBJ_NUMBER) { | |
| m_LastXRefOffset = pTable->GetInteger(); | |
| } | |
| return TRUE; | |
| } | |
| m_pLinearized->Release(); | |
| m_pLinearized = NULL; | |
| return FALSE; | |
| } | |
| FX_DWORD CPDF_Parser::StartAsynParse(IFX_FileRead* pFileAccess, FX_BOOL bReParse, FX_BOOL bOwnFileRead) | |
| { | |
| CloseParser(bReParse); | |
| m_bXRefStream = FALSE; | |
| m_LastXRefOffset = 0; | |
| m_bOwnFileRead = bOwnFileRead; | |
| FX_INT32 offset = GetHeaderOffset(pFileAccess); | |
| if (offset == -1) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| if (!IsLinearizedFile(pFileAccess, offset)) { | |
| m_Syntax.m_pFileAccess = NULL; | |
| return StartParse(pFileAccess, bReParse, bOwnFileRead); | |
| } | |
| if (!bReParse) { | |
| m_pDocument = FX_NEW CPDF_Document(this); | |
| } | |
| FX_FILESIZE dwFirstXRefOffset = m_Syntax.SavePos(); | |
| FX_BOOL bXRefRebuilt = FALSE; | |
| FX_BOOL bLoadV4 = FALSE; | |
| if (!(bLoadV4 = LoadCrossRefV4(dwFirstXRefOffset, 0, FALSE, FALSE)) && !LoadCrossRefV5(dwFirstXRefOffset, dwFirstXRefOffset, TRUE)) { | |
| if (!RebuildCrossRef()) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| bXRefRebuilt = TRUE; | |
| m_LastXRefOffset = 0; | |
| } | |
| if (bLoadV4) { | |
| m_pTrailer = LoadTrailerV4(); | |
| if (m_pTrailer == NULL) { | |
| return FALSE; | |
| } | |
| FX_INT32 xrefsize = GetDirectInteger(m_pTrailer, FX_BSTRC("Size")); | |
| if (xrefsize == 0) { | |
| return FALSE; | |
| } | |
| m_CrossRef.SetSize(xrefsize); | |
| m_V5Type.SetSize(xrefsize); | |
| } | |
| FX_DWORD dwRet = SetEncryptHandler(); | |
| if (dwRet != PDFPARSE_ERROR_SUCCESS) { | |
| return dwRet; | |
| } | |
| m_pDocument->LoadAsynDoc(m_pLinearized->GetDict()); | |
| if (m_pDocument->GetRoot() == NULL || m_pDocument->GetPageCount() == 0) { | |
| if (bXRefRebuilt) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| ReleaseEncryptHandler(); | |
| if (!RebuildCrossRef()) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| dwRet = SetEncryptHandler(); | |
| if (dwRet != PDFPARSE_ERROR_SUCCESS) { | |
| return dwRet; | |
| } | |
| m_pDocument->LoadAsynDoc(m_pLinearized->GetDict()); | |
| if (m_pDocument->GetRoot() == NULL) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| } | |
| FXSYS_qsort(m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| FX_DWORD RootObjNum = GetRootObjNum(); | |
| if (RootObjNum == 0) { | |
| ReleaseEncryptHandler(); | |
| RebuildCrossRef(); | |
| RootObjNum = GetRootObjNum(); | |
| if (RootObjNum == 0) { | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| dwRet = SetEncryptHandler(); | |
| if (dwRet != PDFPARSE_ERROR_SUCCESS) { | |
| return dwRet; | |
| } | |
| } | |
| if (m_pSecurityHandler && m_pSecurityHandler->IsMetadataEncrypted()) { | |
| CPDF_Reference* pMetadata = (CPDF_Reference*)m_pDocument->GetRoot()->GetElement(FX_BSTRC("Metadata")); | |
| if (pMetadata && pMetadata->GetType() == PDFOBJ_REFERENCE) { | |
| m_Syntax.m_MetadataObjnum = pMetadata->GetRefObjNum(); | |
| } | |
| } | |
| return PDFPARSE_ERROR_SUCCESS; | |
| } | |
| FX_BOOL CPDF_Parser::LoadLinearizedAllCrossRefV5(FX_FILESIZE xrefpos) | |
| { | |
| if (!LoadCrossRefV5(xrefpos, xrefpos, FALSE)) { | |
| return FALSE; | |
| } | |
| while (xrefpos) | |
| if (!LoadCrossRefV5(xrefpos, xrefpos, FALSE)) { | |
| return FALSE; | |
| } | |
| m_ObjectStreamMap.InitHashTable(101, FALSE); | |
| m_bXRefStream = TRUE; | |
| return TRUE; | |
| } | |
| FX_DWORD CPDF_Parser::LoadLinearizedMainXRefTable() | |
| { | |
| FX_DWORD dwSaveMetadataObjnum = m_Syntax.m_MetadataObjnum; | |
| m_Syntax.m_MetadataObjnum = 0; | |
| if (m_pTrailer) { | |
| m_pTrailer->Release(); | |
| m_pTrailer = NULL; | |
| } | |
| m_Syntax.RestorePos(m_LastXRefOffset - m_Syntax.m_HeaderOffset); | |
| FX_FILESIZE dwSavedPos = m_Syntax.SavePos(); | |
| FX_BYTE ch = 0; | |
| FX_DWORD dwCount = 0; | |
| m_Syntax.GetNextChar(ch); | |
| FX_INT32 type = _PDF_CharType[ch]; | |
| while (type == 'W') { | |
| ++dwCount; | |
| if (m_Syntax.m_FileLen >= (FX_FILESIZE)(m_Syntax.SavePos() + m_Syntax.m_HeaderOffset)) { | |
| break; | |
| } | |
| m_Syntax.GetNextChar(ch); | |
| type = _PDF_CharType[ch]; | |
| } | |
| m_LastXRefOffset += dwCount; | |
| FX_POSITION pos = m_ObjectStreamMap.GetStartPosition(); | |
| while (pos) { | |
| FX_LPVOID objnum; | |
| CPDF_StreamAcc* pStream; | |
| m_ObjectStreamMap.GetNextAssoc(pos, objnum, (void*&)pStream); | |
| delete pStream; | |
| } | |
| m_ObjectStreamMap.RemoveAll(); | |
| if (!LoadLinearizedAllCrossRefV4(m_LastXRefOffset, m_dwXrefStartObjNum) && !LoadLinearizedAllCrossRefV5(m_LastXRefOffset)) { | |
| m_LastXRefOffset = 0; | |
| m_Syntax.m_MetadataObjnum = dwSaveMetadataObjnum; | |
| return PDFPARSE_ERROR_FORMAT; | |
| } | |
| FXSYS_qsort(m_SortedOffset.GetData(), m_SortedOffset.GetSize(), sizeof(FX_DWORD), _CompareDWord); | |
| m_Syntax.m_MetadataObjnum = dwSaveMetadataObjnum; | |
| return PDFPARSE_ERROR_SUCCESS; | |
| } | |
| CPDF_SyntaxParser::CPDF_SyntaxParser() | |
| { | |
| m_pFileAccess = NULL; | |
| m_pCryptoHandler = NULL; | |
| m_pFileBuf = NULL; | |
| m_BufSize = CPDF_ModuleMgr::Get()->m_FileBufSize; | |
| m_pFileBuf = NULL; | |
| m_MetadataObjnum = 0; | |
| m_dwWordPos = 0; | |
| #if defined(_FPDFAPI_MINI_) | |
| m_bFileStream = TRUE; | |
| #else | |
| m_bFileStream = FALSE; | |
| #endif | |
| } | |
| CPDF_SyntaxParser::~CPDF_SyntaxParser() | |
| { | |
| if (m_pFileBuf) { | |
| FX_Free(m_pFileBuf); | |
| } | |
| } | |
| FX_BOOL CPDF_SyntaxParser::GetCharAt(FX_FILESIZE pos, FX_BYTE& ch) | |
| { | |
| FX_FILESIZE save_pos = m_Pos; | |
| m_Pos = pos; | |
| FX_BOOL ret = GetNextChar(ch); | |
| m_Pos = save_pos; | |
| return ret; | |
| } | |
| FX_BOOL CPDF_SyntaxParser::GetNextChar(FX_BYTE& ch) | |
| { | |
| FX_FILESIZE pos = m_Pos + m_HeaderOffset; | |
| if (pos >= m_FileLen) { | |
| return FALSE; | |
| } | |
| if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) { | |
| FX_FILESIZE read_pos = pos; | |
| FX_DWORD read_size = m_BufSize; | |
| if ((FX_FILESIZE)read_size > m_FileLen) { | |
| read_size = (FX_DWORD)m_FileLen; | |
| } | |
| if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) { | |
| if (m_FileLen < (FX_FILESIZE)read_size) { | |
| read_pos = 0; | |
| read_size = (FX_DWORD)m_FileLen; | |
| } else { | |
| read_pos = m_FileLen - read_size; | |
| } | |
| } | |
| if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size)) { | |
| return FALSE; | |
| } | |
| m_BufOffset = read_pos; | |
| } | |
| ch = m_pFileBuf[pos - m_BufOffset]; | |
| m_Pos ++; | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_SyntaxParser::GetCharAtBackward(FX_FILESIZE pos, FX_BYTE& ch) | |
| { | |
| pos += m_HeaderOffset; | |
| if (pos >= m_FileLen) { | |
| return FALSE; | |
| } | |
| if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) { | |
| FX_FILESIZE read_pos; | |
| if (pos < (FX_FILESIZE)m_BufSize) { | |
| read_pos = 0; | |
| } else { | |
| read_pos = pos - m_BufSize + 1; | |
| } | |
| FX_DWORD read_size = m_BufSize; | |
| if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) { | |
| if (m_FileLen < (FX_FILESIZE)read_size) { | |
| read_pos = 0; | |
| read_size = (FX_DWORD)m_FileLen; | |
| } else { | |
| read_pos = m_FileLen - read_size; | |
| } | |
| } | |
| if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size)) { | |
| return FALSE; | |
| } | |
| m_BufOffset = read_pos; | |
| } | |
| ch = m_pFileBuf[pos - m_BufOffset]; | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_SyntaxParser::ReadBlock(FX_LPBYTE pBuf, FX_DWORD size) | |
| { | |
| if (!m_pFileAccess->ReadBlock(pBuf, m_Pos + m_HeaderOffset, size)) { | |
| return FALSE; | |
| } | |
| m_Pos += size; | |
| return TRUE; | |
| } | |
| #define MAX_WORD_BUFFER 256 | |
| void CPDF_SyntaxParser::GetNextWord() | |
| { | |
| m_WordSize = 0; | |
| m_bIsNumber = TRUE; | |
| FX_BYTE ch; | |
| if (!GetNextChar(ch)) { | |
| return; | |
| } | |
| FX_BYTE type = _PDF_CharType[ch]; | |
| while (1) { | |
| while (type == 'W') { | |
| if (!GetNextChar(ch)) { | |
| return; | |
| } | |
| type = _PDF_CharType[ch]; | |
| } | |
| if (ch != '%') { | |
| break; | |
| } | |
| while (1) { | |
| if (!GetNextChar(ch)) { | |
| return; | |
| } | |
| if (ch == '\r' || ch == '\n') { | |
| break; | |
| } | |
| } | |
| type = _PDF_CharType[ch]; | |
| } | |
| if (type == 'D') { | |
| m_bIsNumber = FALSE; | |
| m_WordBuffer[m_WordSize++] = ch; | |
| if (ch == '/') { | |
| while (1) { | |
| if (!GetNextChar(ch)) { | |
| return; | |
| } | |
| type = _PDF_CharType[ch]; | |
| if (type != 'R' && type != 'N') { | |
| m_Pos --; | |
| return; | |
| } | |
| if (m_WordSize < MAX_WORD_BUFFER) { | |
| m_WordBuffer[m_WordSize++] = ch; | |
| } | |
| } | |
| } else if (ch == '<') { | |
| if (!GetNextChar(ch)) { | |
| return; | |
| } | |
| if (ch == '<') { | |
| m_WordBuffer[m_WordSize++] = ch; | |
| } else { | |
| m_Pos --; | |
| } | |
| } else if (ch == '>') { | |
| if (!GetNextChar(ch)) { | |
| return; | |
| } | |
| if (ch == '>') { | |
| m_WordBuffer[m_WordSize++] = ch; | |
| } else { | |
| m_Pos --; | |
| } | |
| } | |
| return; | |
| } | |
| while (1) { | |
| if (m_WordSize < MAX_WORD_BUFFER) { | |
| m_WordBuffer[m_WordSize++] = ch; | |
| } | |
| if (type != 'N') { | |
| m_bIsNumber = FALSE; | |
| } | |
| if (!GetNextChar(ch)) { | |
| return; | |
| } | |
| type = _PDF_CharType[ch]; | |
| if (type == 'D' || type == 'W') { | |
| m_Pos --; | |
| break; | |
| } | |
| } | |
| } | |
| CFX_ByteString CPDF_SyntaxParser::ReadString() | |
| { | |
| FX_BYTE ch; | |
| if (!GetNextChar(ch)) { | |
| return CFX_ByteString(); | |
| } | |
| CFX_ByteTextBuf buf; | |
| FX_INT32 parlevel = 0; | |
| FX_INT32 status = 0, iEscCode = 0; | |
| while (1) { | |
| switch (status) { | |
| case 0: | |
| if (ch == ')') { | |
| if (parlevel == 0) { | |
| return buf.GetByteString(); | |
| } | |
| parlevel --; | |
| buf.AppendChar(')'); | |
| } else if (ch == '(') { | |
| parlevel ++; | |
| buf.AppendChar('('); | |
| } else if (ch == '\\') { | |
| status = 1; | |
| } else { | |
| buf.AppendChar(ch); | |
| } | |
| break; | |
| case 1: | |
| if (ch >= '0' && ch <= '7') { | |
| iEscCode = ch - '0'; | |
| status = 2; | |
| break; | |
| } | |
| if (ch == 'n') { | |
| buf.AppendChar('\n'); | |
| } else if (ch == 'r') { | |
| buf.AppendChar('\r'); | |
| } else if (ch == 't') { | |
| buf.AppendChar('\t'); | |
| } else if (ch == 'b') { | |
| buf.AppendChar('\b'); | |
| } else if (ch == 'f') { | |
| buf.AppendChar('\f'); | |
| } else if (ch == '\r') { | |
| status = 4; | |
| break; | |
| } else if (ch == '\n') { | |
| } else { | |
| buf.AppendChar(ch); | |
| } | |
| status = 0; | |
| break; | |
| case 2: | |
| if (ch >= '0' && ch <= '7') { | |
| iEscCode = iEscCode * 8 + ch - '0'; | |
| status = 3; | |
| } else { | |
| buf.AppendChar(iEscCode); | |
| status = 0; | |
| continue; | |
| } | |
| break; | |
| case 3: | |
| if (ch >= '0' && ch <= '7') { | |
| iEscCode = iEscCode * 8 + ch - '0'; | |
| buf.AppendChar(iEscCode); | |
| status = 0; | |
| } else { | |
| buf.AppendChar(iEscCode); | |
| status = 0; | |
| continue; | |
| } | |
| break; | |
| case 4: | |
| status = 0; | |
| if (ch != '\n') { | |
| continue; | |
| } | |
| break; | |
| } | |
| if (!GetNextChar(ch)) { | |
| break; | |
| } | |
| } | |
| GetNextChar(ch); | |
| return buf.GetByteString(); | |
| } | |
| CFX_ByteString CPDF_SyntaxParser::ReadHexString() | |
| { | |
| FX_BYTE ch; | |
| if (!GetNextChar(ch)) { | |
| return CFX_ByteString(); | |
| } | |
| CFX_BinaryBuf buf; | |
| FX_BOOL bFirst = TRUE; | |
| FX_BYTE code = 0; | |
| while (1) { | |
| if (ch == '>') { | |
| break; | |
| } | |
| if (ch >= '0' && ch <= '9') { | |
| if (bFirst) { | |
| code = (ch - '0') * 16; | |
| } else { | |
| code += ch - '0'; | |
| buf.AppendByte((FX_BYTE)code); | |
| } | |
| bFirst = !bFirst; | |
| } else if (ch >= 'A' && ch <= 'F') { | |
| if (bFirst) { | |
| code = (ch - 'A' + 10) * 16; | |
| } else { | |
| code += ch - 'A' + 10; | |
| buf.AppendByte((FX_BYTE)code); | |
| } | |
| bFirst = !bFirst; | |
| } else if (ch >= 'a' && ch <= 'f') { | |
| if (bFirst) { | |
| code = (ch - 'a' + 10) * 16; | |
| } else { | |
| code += ch - 'a' + 10; | |
| buf.AppendByte((FX_BYTE)code); | |
| } | |
| bFirst = !bFirst; | |
| } | |
| if (!GetNextChar(ch)) { | |
| break; | |
| } | |
| } | |
| if (!bFirst) { | |
| buf.AppendByte((FX_BYTE)code); | |
| } | |
| return buf.GetByteString(); | |
| } | |
| void CPDF_SyntaxParser::ToNextLine() | |
| { | |
| FX_BYTE ch; | |
| while (1) { | |
| if (!GetNextChar(ch)) { | |
| return; | |
| } | |
| if (ch == '\n') { | |
| return; | |
| } | |
| if (ch == '\r') { | |
| GetNextChar(ch); | |
| if (ch == '\n') { | |
| return; | |
| } else { | |
| m_Pos --; | |
| return; | |
| } | |
| } | |
| } | |
| } | |
| void CPDF_SyntaxParser::ToNextWord() | |
| { | |
| FX_BYTE ch; | |
| if (!GetNextChar(ch)) { | |
| return; | |
| } | |
| FX_BYTE type = _PDF_CharType[ch]; | |
| while (1) { | |
| while (type == 'W') { | |
| m_dwWordPos = m_Pos; | |
| if (!GetNextChar(ch)) { | |
| return; | |
| } | |
| type = _PDF_CharType[ch]; | |
| } | |
| if (ch != '%') { | |
| break; | |
| } | |
| while (1) { | |
| if (!GetNextChar(ch)) { | |
| return; | |
| } | |
| if (ch == '\r' || ch == '\n') { | |
| break; | |
| } | |
| } | |
| type = _PDF_CharType[ch]; | |
| } | |
| m_Pos --; | |
| } | |
| CFX_ByteString CPDF_SyntaxParser::GetNextWord(FX_BOOL& bIsNumber) | |
| { | |
| GetNextWord(); | |
| bIsNumber = m_bIsNumber; | |
| return CFX_ByteString((FX_LPCSTR)m_WordBuffer, m_WordSize); | |
| } | |
| CFX_ByteString CPDF_SyntaxParser::GetKeyword() | |
| { | |
| GetNextWord(); | |
| return CFX_ByteString((FX_LPCSTR)m_WordBuffer, m_WordSize); | |
| } | |
| CPDF_Object* CPDF_SyntaxParser::GetObject(CPDF_IndirectObjects* pObjList, FX_DWORD objnum, FX_DWORD gennum, FX_INT32 level, PARSE_CONTEXT* pContext, FX_BOOL bDecrypt) | |
| { | |
| if (level > _PARSER_OBJECT_LEVLE_) { | |
| return NULL; | |
| } | |
| FX_FILESIZE SavedPos = m_Pos; | |
| FX_BOOL bTypeOnly = pContext && (pContext->m_Flags & PDFPARSE_TYPEONLY); | |
| FX_BOOL bIsNumber; | |
| CFX_ByteString word = GetNextWord(bIsNumber); | |
| CPDF_Object* pRet = NULL; | |
| if (word.GetLength() == 0) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_INVALID; | |
| } | |
| return NULL; | |
| } | |
| FX_FILESIZE wordOffset = m_Pos - word.GetLength(); | |
| if (bIsNumber) { | |
| FX_FILESIZE SavedPos = m_Pos; | |
| CFX_ByteString nextword = GetNextWord(bIsNumber); | |
| if (bIsNumber) { | |
| CFX_ByteString nextword2 = GetNextWord(bIsNumber); | |
| if (nextword2 == FX_BSTRC("R")) { | |
| FX_DWORD objnum = FXSYS_atoi(word); | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_REFERENCE; | |
| } | |
| pRet = CPDF_Reference::Create(pObjList, objnum); | |
| return pRet; | |
| } else { | |
| m_Pos = SavedPos; | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_NUMBER; | |
| } | |
| pRet = CPDF_Number::Create(word); | |
| return pRet; | |
| } | |
| } else { | |
| m_Pos = SavedPos; | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_NUMBER; | |
| } | |
| pRet = CPDF_Number::Create(word); | |
| return pRet; | |
| } | |
| } | |
| if (word == FX_BSTRC("true") || word == FX_BSTRC("false")) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_BOOLEAN; | |
| } | |
| pRet = CPDF_Boolean::Create(word == FX_BSTRC("true")); | |
| return pRet; | |
| } | |
| if (word == FX_BSTRC("null")) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_NULL; | |
| } | |
| pRet = CPDF_Null::Create(); | |
| return pRet; | |
| } | |
| if (word == FX_BSTRC("(")) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_STRING; | |
| } | |
| FX_FILESIZE SavedPos = m_Pos - 1; | |
| CFX_ByteString str = ReadString(); | |
| if (m_pCryptoHandler && bDecrypt) { | |
| m_pCryptoHandler->Decrypt(objnum, gennum, str); | |
| } | |
| pRet = CPDF_String::Create(str, FALSE); | |
| return pRet; | |
| } | |
| if (word == FX_BSTRC("<")) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_STRING; | |
| } | |
| FX_FILESIZE SavedPos = m_Pos - 1; | |
| CFX_ByteString str = ReadHexString(); | |
| if (m_pCryptoHandler && bDecrypt) { | |
| m_pCryptoHandler->Decrypt(objnum, gennum, str); | |
| } | |
| pRet = CPDF_String::Create(str, TRUE); | |
| return pRet; | |
| } | |
| if (word == FX_BSTRC("[")) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_ARRAY; | |
| } | |
| CPDF_Array* pArray = CPDF_Array::Create(); | |
| FX_FILESIZE firstPos = m_Pos - 1; | |
| while (1) { | |
| FX_FILESIZE SavedPos = m_Pos; | |
| CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, level + 1); | |
| if (pObj == NULL) { | |
| return pArray; | |
| } | |
| pArray->Add(pObj); | |
| } | |
| } | |
| if (word[0] == '/') { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_NAME; | |
| } | |
| pRet = CPDF_Name::Create(PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1))); | |
| return pRet; | |
| } | |
| if (word == FX_BSTRC("<<")) { | |
| FX_FILESIZE saveDictOffset = m_Pos - 2; | |
| FX_DWORD dwDictSize = 0; | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_DICTIONARY; | |
| } | |
| if (pContext) { | |
| pContext->m_DictStart = SavedPos; | |
| } | |
| CPDF_Dictionary* pDict = CPDF_Dictionary::Create(); | |
| FX_INT32 nKeys = 0; | |
| FX_FILESIZE dwSignValuePos = 0; | |
| while (1) { | |
| FX_BOOL bIsNumber; | |
| CFX_ByteString key = GetNextWord(bIsNumber); | |
| if (key.IsEmpty()) { | |
| pDict->Release(); | |
| return NULL; | |
| } | |
| FX_FILESIZE SavedPos = m_Pos - key.GetLength(); | |
| if (key == FX_BSTRC(">>")) { | |
| dwDictSize = m_Pos - saveDictOffset; | |
| break; | |
| } | |
| if (key == FX_BSTRC("endobj")) { | |
| dwDictSize = m_Pos - 6 - saveDictOffset; | |
| m_Pos = SavedPos; | |
| break; | |
| } | |
| if (key[0] != '/') { | |
| continue; | |
| } | |
| nKeys ++; | |
| key = PDF_NameDecode(key); | |
| if (key == FX_BSTRC("/Contents")) { | |
| dwSignValuePos = m_Pos; | |
| } | |
| CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, level + 1); | |
| if (pObj == NULL) { | |
| continue; | |
| } | |
| if (key.GetLength() == 1) { | |
| pDict->SetAt(CFX_ByteStringC(((FX_LPCSTR)key) + 1, key.GetLength() - 1), pObj); | |
| } else { | |
| if (nKeys < 32) { | |
| pDict->SetAt(CFX_ByteStringC(((FX_LPCSTR)key) + 1, key.GetLength() - 1), pObj); | |
| } else { | |
| pDict->AddValue(CFX_ByteStringC(((FX_LPCSTR)key) + 1, key.GetLength() - 1), pObj); | |
| } | |
| } | |
| } | |
| if (IsSignatureDict(pDict)) { | |
| FX_FILESIZE dwSavePos = m_Pos; | |
| m_Pos = dwSignValuePos; | |
| CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, level + 1, NULL, FALSE); | |
| pDict->SetAt(FX_BSTRC("Contents"), pObj); | |
| m_Pos = dwSavePos; | |
| } | |
| if (pContext) { | |
| pContext->m_DictEnd = m_Pos; | |
| if (pContext->m_Flags & PDFPARSE_NOSTREAM) { | |
| return pDict; | |
| } | |
| } | |
| FX_FILESIZE SavedPos = m_Pos; | |
| FX_BOOL bIsNumber; | |
| CFX_ByteString nextword = GetNextWord(bIsNumber); | |
| if (nextword == FX_BSTRC("stream")) { | |
| CPDF_Stream* pStream = ReadStream(pDict, pContext, objnum, gennum); | |
| if (pStream) { | |
| return pStream; | |
| } | |
| pDict->Release(); | |
| return NULL; | |
| } else { | |
| m_Pos = SavedPos; | |
| return pDict; | |
| } | |
| } | |
| if (word == FX_BSTRC(">>")) { | |
| m_Pos = SavedPos; | |
| return NULL; | |
| } | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_INVALID; | |
| } | |
| return NULL; | |
| } | |
| CPDF_Object* CPDF_SyntaxParser::GetObjectByStrict(CPDF_IndirectObjects* pObjList, FX_DWORD objnum, FX_DWORD gennum, | |
| FX_INT32 level, struct PARSE_CONTEXT* pContext) | |
| { | |
| if (level > _PARSER_OBJECT_LEVLE_) { | |
| return NULL; | |
| } | |
| FX_FILESIZE SavedPos = m_Pos; | |
| FX_BOOL bTypeOnly = pContext && (pContext->m_Flags & PDFPARSE_TYPEONLY); | |
| FX_BOOL bIsNumber; | |
| CFX_ByteString word = GetNextWord(bIsNumber); | |
| if (word.GetLength() == 0) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_INVALID; | |
| } | |
| return NULL; | |
| } | |
| if (bIsNumber) { | |
| FX_FILESIZE SavedPos = m_Pos; | |
| CFX_ByteString nextword = GetNextWord(bIsNumber); | |
| if (bIsNumber) { | |
| CFX_ByteString nextword2 = GetNextWord(bIsNumber); | |
| if (nextword2 == FX_BSTRC("R")) { | |
| FX_DWORD objnum = FXSYS_atoi(word); | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_REFERENCE; | |
| } | |
| return CPDF_Reference::Create(pObjList, objnum); | |
| } else { | |
| m_Pos = SavedPos; | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_NUMBER; | |
| } | |
| return CPDF_Number::Create(word); | |
| } | |
| } else { | |
| m_Pos = SavedPos; | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_NUMBER; | |
| } | |
| return CPDF_Number::Create(word); | |
| } | |
| } | |
| if (word == FX_BSTRC("true") || word == FX_BSTRC("false")) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_BOOLEAN; | |
| } | |
| return CPDF_Boolean::Create(word == FX_BSTRC("true")); | |
| } | |
| if (word == FX_BSTRC("null")) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_NULL; | |
| } | |
| return CPDF_Null::Create(); | |
| } | |
| if (word == FX_BSTRC("(")) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_STRING; | |
| } | |
| CFX_ByteString str = ReadString(); | |
| if (m_pCryptoHandler) { | |
| m_pCryptoHandler->Decrypt(objnum, gennum, str); | |
| } | |
| return CPDF_String::Create(str, FALSE); | |
| } | |
| if (word == FX_BSTRC("<")) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_STRING; | |
| } | |
| CFX_ByteString str = ReadHexString(); | |
| if (m_pCryptoHandler) { | |
| m_pCryptoHandler->Decrypt(objnum, gennum, str); | |
| } | |
| return CPDF_String::Create(str, TRUE); | |
| } | |
| if (word == FX_BSTRC("[")) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_ARRAY; | |
| } | |
| CPDF_Array* pArray = CPDF_Array::Create(); | |
| while (1) { | |
| CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, level + 1); | |
| if (pObj == NULL) { | |
| if (m_WordBuffer[0] == ']') { | |
| return pArray; | |
| } | |
| pArray->Release(); | |
| return NULL; | |
| } | |
| pArray->Add(pObj); | |
| } | |
| } | |
| if (word[0] == '/') { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_NAME; | |
| } | |
| return CPDF_Name::Create(PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1))); | |
| } | |
| if (word == FX_BSTRC("<<")) { | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_DICTIONARY; | |
| } | |
| if (pContext) { | |
| pContext->m_DictStart = SavedPos; | |
| } | |
| CPDF_Dictionary* pDict = CPDF_Dictionary::Create(); | |
| while (1) { | |
| FX_BOOL bIsNumber; | |
| FX_FILESIZE SavedPos = m_Pos; | |
| CFX_ByteString key = GetNextWord(bIsNumber); | |
| if (key.IsEmpty()) { | |
| pDict->Release(); | |
| return NULL; | |
| } | |
| if (key == FX_BSTRC(">>")) { | |
| break; | |
| } | |
| if (key == FX_BSTRC("endobj")) { | |
| m_Pos = SavedPos; | |
| break; | |
| } | |
| if (key[0] != '/') { | |
| continue; | |
| } | |
| key = PDF_NameDecode(key); | |
| CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, level + 1); | |
| if (pObj == NULL) { | |
| pDict->Release(); | |
| FX_BYTE ch; | |
| while (1) { | |
| if (!GetNextChar(ch)) { | |
| break; | |
| } | |
| if (ch == 0x0A || ch == 0x0D) { | |
| break; | |
| } | |
| } | |
| return NULL; | |
| } | |
| if (key.GetLength() == 1) { | |
| pDict->SetAt(CFX_ByteStringC(((FX_LPCSTR)key) + 1, key.GetLength() - 1), pObj); | |
| } else { | |
| pDict->AddValue(CFX_ByteStringC(((FX_LPCSTR)key) + 1, key.GetLength() - 1), pObj); | |
| } | |
| } | |
| if (pContext) { | |
| pContext->m_DictEnd = m_Pos; | |
| if (pContext->m_Flags & PDFPARSE_NOSTREAM) { | |
| return pDict; | |
| } | |
| } | |
| FX_FILESIZE SavedPos = m_Pos; | |
| FX_BOOL bIsNumber; | |
| CFX_ByteString nextword = GetNextWord(bIsNumber); | |
| if (nextword == FX_BSTRC("stream")) { | |
| CPDF_Stream* pStream = ReadStream(pDict, pContext, objnum, gennum); | |
| if (pStream) { | |
| return pStream; | |
| } | |
| pDict->Release(); | |
| return NULL; | |
| } else { | |
| m_Pos = SavedPos; | |
| return pDict; | |
| } | |
| } | |
| if (word == FX_BSTRC(">>")) { | |
| m_Pos = SavedPos; | |
| return NULL; | |
| } | |
| if (bTypeOnly) { | |
| return (CPDF_Object*)PDFOBJ_INVALID; | |
| } | |
| return NULL; | |
| } | |
| CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict, PARSE_CONTEXT* pContext, | |
| FX_DWORD objnum, FX_DWORD gennum) | |
| { | |
| CPDF_Object* pLenObj = pDict->GetElement(FX_BSTRC("Length")); | |
| FX_DWORD len = 0; | |
| if (pLenObj && (pLenObj->GetType() != PDFOBJ_REFERENCE || | |
| (((CPDF_Reference*)pLenObj)->GetObjList() != NULL) && | |
| ((CPDF_Reference*)pLenObj)->GetRefObjNum() != objnum)) { | |
| FX_FILESIZE pos = m_Pos; | |
| if (pLenObj) { | |
| len = pLenObj->GetInteger(); | |
| } | |
| m_Pos = pos; | |
| if (len > 0x40000000) { | |
| return NULL; | |
| } | |
| } | |
| ToNextLine(); | |
| FX_FILESIZE StreamStartPos = m_Pos; | |
| if (pContext) { | |
| pContext->m_DataStart = m_Pos; | |
| } | |
| m_Pos += len; | |
| CPDF_CryptoHandler* pCryptoHandler = objnum == (FX_DWORD)m_MetadataObjnum ? NULL : m_pCryptoHandler; | |
| if (pCryptoHandler == NULL) { | |
| FX_FILESIZE SavedPos = m_Pos; | |
| GetNextWord(); | |
| if (m_WordSize < 9 || FXSYS_memcmp32(m_WordBuffer, "endstream", 9)) { | |
| m_Pos = StreamStartPos; | |
| FX_FILESIZE offset = FindTag(FX_BSTRC("endstream"), 0); | |
| if (offset >= 0) { | |
| FX_FILESIZE curPos = m_Pos; | |
| m_Pos = StreamStartPos; | |
| FX_FILESIZE endobjOffset = FindTag(FX_BSTRC("endobj"), 0); | |
| if (endobjOffset < offset && endobjOffset >= 0) { | |
| offset = endobjOffset; | |
| } else { | |
| m_Pos = curPos; | |
| } | |
| FX_BYTE byte1, byte2; | |
| GetCharAt(StreamStartPos + offset - 1, byte1); | |
| GetCharAt(StreamStartPos + offset - 2, byte2); | |
| if (byte1 == 0x0a && byte2 == 0x0d) { | |
| len -= 2; | |
| } else if (byte1 == 0x0a || byte1 == 0x0d) { | |
| len --; | |
| } | |
| len = (FX_DWORD)offset; | |
| pDict->SetAtInteger(FX_BSTRC("Length"), len); | |
| } else { | |
| m_Pos = StreamStartPos; | |
| if (FindTag(FX_BSTRC("endobj"), 0) < 0) { | |
| return NULL; | |
| } | |
| } | |
| } | |
| } | |
| m_Pos = StreamStartPos; | |
| CPDF_Stream* pStream; | |
| #if defined(_FPDFAPI_MINI_) && !defined(_FXCORE_FEATURE_ALL_) | |
| pStream = FX_NEW CPDF_Stream(m_pFileAccess, pCryptoHandler, m_HeaderOffset + m_Pos, len, pDict, gennum); | |
| m_Pos += len; | |
| #else | |
| FX_LPBYTE pData = FX_Alloc(FX_BYTE, len); | |
| if (!pData) { | |
| return NULL; | |
| } | |
| ReadBlock(pData, len); | |
| if (pCryptoHandler) { | |
| CFX_BinaryBuf dest_buf; | |
| dest_buf.EstimateSize(pCryptoHandler->DecryptGetSize(len)); | |
| FX_LPVOID context = pCryptoHandler->DecryptStart(objnum, gennum); | |
| pCryptoHandler->DecryptStream(context, pData, len, dest_buf); | |
| pCryptoHandler->DecryptFinish(context, dest_buf); | |
| FX_Free(pData); | |
| pData = dest_buf.GetBuffer(); | |
| len = dest_buf.GetSize(); | |
| dest_buf.DetachBuffer(); | |
| } | |
| pStream = FX_NEW CPDF_Stream(pData, len, pDict); | |
| #endif | |
| if (pContext) { | |
| pContext->m_DataEnd = pContext->m_DataStart + len; | |
| } | |
| StreamStartPos = m_Pos; | |
| GetNextWord(); | |
| if (m_WordSize == 6 && 0 == FXSYS_memcmp32(m_WordBuffer, "endobj", 6)) { | |
| m_Pos = StreamStartPos; | |
| } | |
| return pStream; | |
| } | |
| void CPDF_SyntaxParser::InitParser(IFX_FileRead* pFileAccess, FX_DWORD HeaderOffset) | |
| { | |
| if (m_pFileBuf) { | |
| FX_Free(m_pFileBuf); | |
| m_pFileBuf = NULL; | |
| } | |
| m_pFileBuf = FX_Alloc(FX_BYTE, m_BufSize); | |
| m_HeaderOffset = HeaderOffset; | |
| m_FileLen = pFileAccess->GetSize(); | |
| m_Pos = 0; | |
| m_pFileAccess = pFileAccess; | |
| m_BufOffset = 0; | |
| pFileAccess->ReadBlock(m_pFileBuf, 0, (size_t)((FX_FILESIZE)m_BufSize > m_FileLen ? m_FileLen : m_BufSize)); | |
| } | |
| FX_INT32 CPDF_SyntaxParser::GetDirectNum() | |
| { | |
| GetNextWord(); | |
| if (!m_bIsNumber) { | |
| return 0; | |
| } | |
| m_WordBuffer[m_WordSize] = 0; | |
| return FXSYS_atoi((FX_LPCSTR)m_WordBuffer); | |
| } | |
| FX_BOOL CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos, FX_FILESIZE limit, FX_LPCBYTE tag, FX_DWORD taglen) | |
| { | |
| FX_BYTE type = _PDF_CharType[tag[0]]; | |
| FX_BOOL bCheckLeft = type != 'D' && type != 'W'; | |
| type = _PDF_CharType[tag[taglen - 1]]; | |
| FX_BOOL bCheckRight = type != 'D' || type != 'W'; | |
| FX_BYTE ch; | |
| if (bCheckRight && startpos + (FX_INT32)taglen <= limit && GetCharAt(startpos + (FX_INT32)taglen, ch)) { | |
| FX_BYTE type = _PDF_CharType[ch]; | |
| if (type == 'N' || type == 'R') { | |
| return FALSE; | |
| } | |
| } | |
| if (bCheckLeft && startpos > 0 && GetCharAt(startpos - 1, ch)) { | |
| FX_BYTE type = _PDF_CharType[ch]; | |
| if (type == 'N' || type == 'R') { | |
| return FALSE; | |
| } | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_SyntaxParser::SearchWord(FX_BSTR tag, FX_BOOL bWholeWord, FX_BOOL bForward, FX_FILESIZE limit) | |
| { | |
| FX_INT32 taglen = tag.GetLength(); | |
| if (taglen == 0) { | |
| return FALSE; | |
| } | |
| FX_FILESIZE pos = m_Pos; | |
| FX_INT32 offset = 0; | |
| if (!bForward) { | |
| offset = taglen - 1; | |
| } | |
| FX_LPCBYTE tag_data = tag; | |
| FX_BYTE byte; | |
| while (1) { | |
| if (bForward) { | |
| if (limit) { | |
| if (pos >= m_Pos + limit) { | |
| return FALSE; | |
| } | |
| } | |
| if (!GetCharAt(pos, byte)) { | |
| return FALSE; | |
| } | |
| } else { | |
| if (limit) { | |
| if (pos <= m_Pos - limit) { | |
| return FALSE; | |
| } | |
| } | |
| if (!GetCharAtBackward(pos, byte)) { | |
| return FALSE; | |
| } | |
| } | |
| if (byte == tag_data[offset]) { | |
| if (bForward) { | |
| offset ++; | |
| if (offset < taglen) { | |
| pos ++; | |
| continue; | |
| } | |
| } else { | |
| offset --; | |
| if (offset >= 0) { | |
| pos --; | |
| continue; | |
| } | |
| } | |
| FX_FILESIZE startpos = bForward ? pos - taglen + 1 : pos; | |
| if (!bWholeWord || IsWholeWord(startpos, limit, tag, taglen)) { | |
| m_Pos = startpos; | |
| return TRUE; | |
| } | |
| } | |
| if (bForward) { | |
| offset = byte == tag_data[0] ? 1 : 0; | |
| pos ++; | |
| } else { | |
| offset = byte == tag_data[taglen - 1] ? taglen - 2 : taglen - 1; | |
| pos --; | |
| } | |
| if (pos < 0) { | |
| return FALSE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| struct _SearchTagRecord { | |
| FX_LPCBYTE m_pTag; | |
| FX_DWORD m_Len; | |
| FX_DWORD m_Offset; | |
| }; | |
| FX_INT32 CPDF_SyntaxParser::SearchMultiWord(FX_BSTR tags, FX_BOOL bWholeWord, FX_FILESIZE limit) | |
| { | |
| FX_INT32 ntags = 1, i; | |
| for (i = 0; i < tags.GetLength(); i ++) | |
| if (tags[i] == 0) { | |
| ntags ++; | |
| } | |
| _SearchTagRecord* pPatterns = FX_Alloc(_SearchTagRecord, ntags); | |
| FX_DWORD start = 0, itag = 0, max_len = 0; | |
| for (i = 0; i <= tags.GetLength(); i ++) { | |
| if (tags[i] == 0) { | |
| FX_DWORD len = i - start; | |
| if (len > max_len) { | |
| max_len = len; | |
| } | |
| pPatterns[itag].m_pTag = tags.GetPtr() + start; | |
| pPatterns[itag].m_Len = len; | |
| pPatterns[itag].m_Offset = 0; | |
| start = i + 1; | |
| itag ++; | |
| } | |
| } | |
| FX_FILESIZE pos = m_Pos; | |
| FX_BYTE byte; | |
| GetCharAt(pos++, byte); | |
| FX_INT32 found = -1; | |
| while (1) { | |
| for (i = 0; i < ntags; i ++) { | |
| if (pPatterns[i].m_pTag[pPatterns[i].m_Offset] == byte) { | |
| pPatterns[i].m_Offset ++; | |
| if (pPatterns[i].m_Offset == pPatterns[i].m_Len) { | |
| if (!bWholeWord || IsWholeWord(pos - pPatterns[i].m_Len, limit, pPatterns[i].m_pTag, pPatterns[i].m_Len)) { | |
| found = i; | |
| goto end; | |
| } else { | |
| if (pPatterns[i].m_pTag[0] == byte) { | |
| pPatterns[i].m_Offset = 1; | |
| } else { | |
| pPatterns[i].m_Offset = 0; | |
| } | |
| } | |
| } | |
| } else { | |
| if (pPatterns[i].m_pTag[0] == byte) { | |
| pPatterns[i].m_Offset = 1; | |
| } else { | |
| pPatterns[i].m_Offset = 0; | |
| } | |
| } | |
| } | |
| if (limit && pos >= m_Pos + limit) { | |
| goto end; | |
| } | |
| if (!GetCharAt(pos, byte)) { | |
| goto end; | |
| } | |
| pos ++; | |
| } | |
| end: | |
| FX_Free(pPatterns); | |
| return found; | |
| } | |
| FX_FILESIZE CPDF_SyntaxParser::FindTag(FX_BSTR tag, FX_FILESIZE limit) | |
| { | |
| FX_INT32 taglen = tag.GetLength(); | |
| FX_INT32 match = 0; | |
| limit += m_Pos; | |
| FX_FILESIZE startpos = m_Pos; | |
| while (1) { | |
| FX_BYTE ch; | |
| if (!GetNextChar(ch)) { | |
| return -1; | |
| } | |
| if (ch == tag[match]) { | |
| match ++; | |
| if (match == taglen) { | |
| return m_Pos - startpos - taglen; | |
| } | |
| } else { | |
| match = ch == tag[0] ? 1 : 0; | |
| } | |
| if (limit && m_Pos == limit) { | |
| return -1; | |
| } | |
| } | |
| return -1; | |
| } | |
| void CPDF_SyntaxParser::GetBinary(FX_BYTE* buffer, FX_DWORD size) | |
| { | |
| FX_DWORD offset = 0; | |
| FX_BYTE ch; | |
| while (1) { | |
| if (!GetNextChar(ch)) { | |
| return; | |
| } | |
| buffer[offset++] = ch; | |
| if (offset == size) { | |
| break; | |
| } | |
| } | |
| } | |
| CPDF_DataAvail::CPDF_DataAvail(IFX_FileAvail* pFileAvail, IFX_FileRead* pFileRead) | |
| { | |
| m_pFileAvail = pFileAvail; | |
| m_pFileRead = pFileRead; | |
| m_Pos = 0; | |
| m_dwFileLen = 0; | |
| if (m_pFileRead) { | |
| m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize(); | |
| } | |
| m_dwCurrentOffset = 0; | |
| m_WordSize = 0; | |
| m_dwXRefOffset = 0; | |
| m_bufferOffset = 0; | |
| m_dwFirstPageNo = 0; | |
| m_bufferSize = 0; | |
| m_PagesObjNum = 0; | |
| m_dwCurrentXRefSteam = 0; | |
| m_dwAcroFormObjNum = 0; | |
| m_dwInfoObjNum = 0; | |
| m_pDocument = 0; | |
| m_dwEncryptObjNum = 0; | |
| m_dwPrevXRefOffset = 0; | |
| m_dwLastXRefOffset = 0; | |
| m_bDocAvail = FALSE; | |
| m_bMainXRefLoad = FALSE; | |
| m_bDocAvail = FALSE; | |
| m_bLinearized = FALSE; | |
| m_bPagesLoad = FALSE; | |
| m_bPagesTreeLoad = FALSE; | |
| m_bMainXRefLoadedOK = FALSE; | |
| m_bAnnotsLoad = FALSE; | |
| m_bHaveAcroForm = FALSE; | |
| m_bAcroFormLoad = FALSE; | |
| m_bPageLoadedOK = FALSE; | |
| m_bNeedDownLoadResource = FALSE; | |
| m_bLinearizedFormParamLoad = FALSE; | |
| m_pLinearized = NULL; | |
| m_pRoot = NULL; | |
| m_pTrailer = NULL; | |
| m_pCurrentParser = NULL; | |
| m_pAcroForm = NULL; | |
| m_pPageDict = NULL; | |
| m_pPageResource = NULL; | |
| m_pageMapCheckState = NULL; | |
| m_docStatus = PDF_DATAAVAIL_HEADER; | |
| m_parser.m_bOwnFileRead = FALSE; | |
| m_bTotalLoadPageTree = FALSE; | |
| m_bCurPageDictLoadOK = FALSE; | |
| m_bLinearedDataOK = FALSE; | |
| m_pagesLoadState = NULL; | |
| } | |
| CPDF_DataAvail::~CPDF_DataAvail() | |
| { | |
| if (m_pLinearized) { | |
| m_pLinearized->Release(); | |
| } | |
| if (m_pRoot) { | |
| m_pRoot->Release(); | |
| } | |
| if (m_pTrailer) { | |
| m_pTrailer->Release(); | |
| } | |
| if (m_pageMapCheckState) { | |
| delete m_pageMapCheckState; | |
| } | |
| if (m_pagesLoadState) { | |
| delete m_pagesLoadState; | |
| } | |
| FX_INT32 i = 0; | |
| FX_INT32 iSize = m_arrayAcroforms.GetSize(); | |
| for (i = 0; i < iSize; ++i) { | |
| ((CPDF_Object *)m_arrayAcroforms.GetAt(i))->Release(); | |
| } | |
| } | |
| void CPDF_DataAvail::SetDocument(CPDF_Document* pDoc) | |
| { | |
| m_pDocument = pDoc; | |
| } | |
| FX_DWORD CPDF_DataAvail::GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset) | |
| { | |
| CPDF_Parser *pParser = (CPDF_Parser *)(m_pDocument->GetParser()); | |
| if (pParser == NULL) { | |
| return 0; | |
| } | |
| if (objnum >= (FX_DWORD)pParser->m_CrossRef.GetSize()) { | |
| return 0; | |
| } | |
| if (pParser->m_V5Type[objnum] == 2) { | |
| objnum = (FX_DWORD)pParser->m_CrossRef[objnum]; | |
| } | |
| if (pParser->m_V5Type[objnum] == 1 || pParser->m_V5Type[objnum] == 255) { | |
| offset = pParser->m_CrossRef[objnum]; | |
| if (offset == 0) { | |
| return 0; | |
| } | |
| FX_LPVOID pResult = FXSYS_bsearch(&offset, pParser->m_SortedOffset.GetData(), pParser->m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| if (pResult == NULL) { | |
| return 0; | |
| } | |
| if ((FX_FILESIZE*)pResult - (FX_FILESIZE*)pParser->m_SortedOffset.GetData() == pParser->m_SortedOffset.GetSize() - 1) { | |
| return 0; | |
| } | |
| return (FX_DWORD)(((FX_FILESIZE*)pResult)[1] - offset); | |
| } | |
| return 0; | |
| } | |
| FX_BOOL CPDF_DataAvail::IsObjectsAvail(CFX_PtrArray& obj_array, FX_BOOL bParsePage, IFX_DownloadHints* pHints, CFX_PtrArray &ret_array) | |
| { | |
| if (!obj_array.GetSize()) { | |
| return TRUE; | |
| } | |
| FX_DWORD count = 0; | |
| CFX_PtrArray new_obj_array; | |
| FX_INT32 i = 0; | |
| for (i = 0; i < obj_array.GetSize(); i++) { | |
| CPDF_Object *pObj = (CPDF_Object *)obj_array[i]; | |
| if (!pObj) { | |
| continue; | |
| } | |
| FX_INT32 type = pObj->GetType(); | |
| switch (type) { | |
| case PDFOBJ_ARRAY: { | |
| CPDF_Array *pArray = pObj->GetArray(); | |
| for (FX_DWORD k = 0; k < pArray->GetCount(); k++) { | |
| new_obj_array.Add(pArray->GetElement(k)); | |
| } | |
| } | |
| break; | |
| case PDFOBJ_STREAM: | |
| pObj = pObj->GetDict(); | |
| case PDFOBJ_DICTIONARY: { | |
| CPDF_Dictionary *pDict = pObj->GetDict(); | |
| if (pDict->GetString("Type") == "Page" && !bParsePage) { | |
| continue; | |
| } | |
| FX_POSITION pos = pDict->GetStartPos(); | |
| while (pos) { | |
| CPDF_Object *value; | |
| CFX_ByteString key; | |
| value = pDict->GetNextElement(pos, key); | |
| if (key != "Parent") { | |
| new_obj_array.Add(value); | |
| } | |
| } | |
| } | |
| break; | |
| case PDFOBJ_REFERENCE: { | |
| CPDF_Reference *pRef = (CPDF_Reference*)pObj; | |
| FX_DWORD dwNum = pRef->GetRefObjNum(); | |
| FX_FILESIZE offset; | |
| FX_DWORD size = GetObjectSize(pRef->GetRefObjNum(), offset); | |
| if (!size) { | |
| break; | |
| } | |
| size = (FX_DWORD)((FX_FILESIZE)(offset + size + 512) > m_dwFileLen ? m_dwFileLen - offset : size + 512); | |
| if (!m_pFileAvail->IsDataAvail(offset, size)) { | |
| pHints->AddSegment(offset, size); | |
| ret_array.Add(pObj); | |
| count++; | |
| } else if (!m_objnum_array.Find(dwNum)) { | |
| m_objnum_array.AddObjNum(dwNum); | |
| CPDF_Object *pReferred = m_pDocument->GetIndirectObject(pRef->GetRefObjNum(), NULL); | |
| if (pReferred) { | |
| new_obj_array.Add(pReferred); | |
| } | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| if (count > 0) { | |
| FX_INT32 iSize = new_obj_array.GetSize(); | |
| for (i = 0; i < iSize; ++i) { | |
| CPDF_Object *pObj = (CPDF_Object *)new_obj_array[i]; | |
| FX_INT32 type = pObj->GetType(); | |
| if (type == PDFOBJ_REFERENCE) { | |
| CPDF_Reference *pRef = (CPDF_Reference *)pObj; | |
| FX_DWORD dwNum = pRef->GetRefObjNum(); | |
| if (!m_objnum_array.Find(dwNum)) { | |
| ret_array.Add(pObj); | |
| } | |
| } else { | |
| ret_array.Add(pObj); | |
| } | |
| } | |
| return FALSE; | |
| } | |
| obj_array.RemoveAll(); | |
| obj_array.Append(new_obj_array); | |
| return IsObjectsAvail(obj_array, FALSE, pHints, ret_array); | |
| } | |
| FX_BOOL CPDF_DataAvail::IsDocAvail(IFX_DownloadHints* pHints) | |
| { | |
| if (!m_dwFileLen && m_pFileRead) { | |
| m_dwFileLen = (FX_DWORD)m_pFileRead->GetSize(); | |
| if (!m_dwFileLen) { | |
| return TRUE; | |
| } | |
| } | |
| while (!m_bDocAvail) { | |
| if (!CheckDocStatus(pHints)) { | |
| return FALSE; | |
| } | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckAcroFormSubObject(IFX_DownloadHints* pHints) | |
| { | |
| if (!m_objs_array.GetSize()) { | |
| m_objs_array.RemoveAll(); | |
| m_objnum_array.RemoveAll(); | |
| CFX_PtrArray obj_array; | |
| obj_array.Append(m_arrayAcroforms); | |
| FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); | |
| if (bRet) { | |
| m_objs_array.RemoveAll(); | |
| } | |
| return bRet; | |
| } else { | |
| CFX_PtrArray new_objs_array; | |
| FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| if (bRet) { | |
| FX_INT32 iSize = m_arrayAcroforms.GetSize(); | |
| for (FX_INT32 i = 0; i < iSize; ++i) { | |
| ((CPDF_Object *)m_arrayAcroforms.GetAt(i))->Release(); | |
| } | |
| m_arrayAcroforms.RemoveAll(); | |
| } else { | |
| m_objs_array.RemoveAll(); | |
| m_objs_array.Append(new_objs_array); | |
| } | |
| return bRet; | |
| } | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckAcroForm(IFX_DownloadHints* pHints) | |
| { | |
| FX_BOOL bExist = FALSE; | |
| m_pAcroForm = GetObject(m_dwAcroFormObjNum, pHints, &bExist); | |
| if (!bExist) { | |
| m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
| return TRUE; | |
| } | |
| if (!m_pAcroForm) { | |
| if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| m_arrayAcroforms.Add(m_pAcroForm); | |
| m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckDocStatus(IFX_DownloadHints *pHints) | |
| { | |
| switch (m_docStatus) { | |
| case PDF_DATAAVAIL_HEADER: | |
| return CheckHeader(pHints); | |
| case PDF_DATAAVAIL_FIRSTPAGE: | |
| case PDF_DATAAVAIL_FIRSTPAGE_PREPARE: | |
| return CheckFirstPage(pHints); | |
| case PDF_DATAAVAIL_END: | |
| return CheckEnd(pHints); | |
| case PDF_DATAAVAIL_CROSSREF: | |
| return CheckCrossRef(pHints); | |
| case PDF_DATAAVAIL_CROSSREF_ITEM: | |
| return CheckCrossRefItem(pHints); | |
| case PDF_DATAAVAIL_CROSSREF_STREAM: | |
| return CheckAllCrossRefStream(pHints); | |
| case PDF_DATAAVAIL_TRAILER: | |
| return CheckTrailer(pHints); | |
| case PDF_DATAAVAIL_TRAILER_APPEND: | |
| return CheckTrailerAppend(pHints); | |
| case PDF_DATAAVAIL_LOADALLCRSOSSREF: | |
| return LoadAllXref(pHints); | |
| case PDF_DATAAVAIL_LOADALLFILE: | |
| return LoadAllFile(pHints); | |
| case PDF_DATAAVAIL_ROOT: | |
| return CheckRoot(pHints); | |
| case PDF_DATAAVAIL_INFO: | |
| return CheckInfo(pHints); | |
| case PDF_DATAAVAIL_ACROFORM: | |
| return CheckAcroForm(pHints); | |
| case PDF_DATAAVAIL_PAGETREE: | |
| if (m_bTotalLoadPageTree) { | |
| return CheckPages(pHints); | |
| } else { | |
| return LoadDocPages(pHints); | |
| } | |
| case PDF_DATAAVAIL_PAGE: | |
| if (m_bTotalLoadPageTree) { | |
| return CheckPage(pHints); | |
| } else { | |
| m_docStatus = PDF_DATAAVAIL_PAGE_LATERLOAD; | |
| return TRUE; | |
| } | |
| case PDF_DATAAVAIL_ERROR: | |
| return LoadAllFile(pHints); | |
| case PDF_DATAAVAIL_PAGE_LATERLOAD: | |
| m_docStatus = PDF_DATAAVAIL_PAGE; | |
| default: | |
| m_bDocAvail = TRUE; | |
| return TRUE; | |
| } | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckPageStatus(IFX_DownloadHints* pHints) | |
| { | |
| switch (m_docStatus) { | |
| case PDF_DATAAVAIL_PAGETREE: | |
| return CheckPages(pHints); | |
| case PDF_DATAAVAIL_PAGE: | |
| return CheckPage(pHints); | |
| case PDF_DATAAVAIL_ERROR: | |
| return LoadAllFile(pHints); | |
| default: | |
| m_bPagesTreeLoad = TRUE; | |
| m_bPagesLoad = TRUE; | |
| return TRUE; | |
| } | |
| } | |
| FX_BOOL CPDF_DataAvail::LoadAllFile(IFX_DownloadHints* pHints) | |
| { | |
| if (m_pFileAvail->IsDataAvail(0, (FX_DWORD)m_dwFileLen)) { | |
| m_docStatus = PDF_DATAAVAIL_DONE; | |
| return TRUE; | |
| } | |
| pHints->AddSegment(0, (FX_DWORD)m_dwFileLen); | |
| return FALSE; | |
| } | |
| FX_BOOL CPDF_DataAvail::LoadAllXref(IFX_DownloadHints* pHints) | |
| { | |
| m_parser.m_Syntax.InitParser(m_pFileRead, (FX_DWORD)m_dwHeaderOffset); | |
| m_parser.m_bOwnFileRead = FALSE; | |
| if (!m_parser.LoadAllCrossRefV4(m_dwLastXRefOffset) && !m_parser.LoadAllCrossRefV5(m_dwLastXRefOffset)) { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| return FALSE; | |
| } | |
| FXSYS_qsort(m_parser.m_SortedOffset.GetData(), m_parser.m_SortedOffset.GetSize(), sizeof(FX_FILESIZE), _CompareFileSize); | |
| m_dwRootObjNum = m_parser.GetRootObjNum(); | |
| m_dwInfoObjNum = m_parser.GetInfoObjNum(); | |
| m_pCurrentParser = &m_parser; | |
| m_docStatus = PDF_DATAAVAIL_ROOT; | |
| return TRUE; | |
| } | |
| CPDF_Object* CPDF_DataAvail::GetObject(FX_DWORD objnum, IFX_DownloadHints* pHints, FX_BOOL *pExistInFile) | |
| { | |
| CPDF_Object *pRet = NULL; | |
| if (pExistInFile) { | |
| *pExistInFile = TRUE; | |
| } | |
| if (m_pDocument == NULL) { | |
| FX_FILESIZE offset = m_parser.GetObjectOffset(objnum); | |
| if (offset < 0) { | |
| *pExistInFile = FALSE; | |
| return NULL; | |
| } | |
| FX_DWORD size = (FX_DWORD)m_parser.GetObjectSize(objnum); | |
| size = (FX_DWORD)(((FX_FILESIZE)(offset + size + 512)) > m_dwFileLen ? m_dwFileLen - offset : size + 512); | |
| if (!m_pFileAvail->IsDataAvail(offset, size)) { | |
| pHints->AddSegment(offset, size); | |
| return NULL; | |
| } | |
| pRet = m_parser.ParseIndirectObject(NULL, objnum); | |
| if (!pRet && pExistInFile) { | |
| *pExistInFile = FALSE; | |
| } | |
| return pRet; | |
| } | |
| FX_FILESIZE offset; | |
| FX_DWORD size = GetObjectSize(objnum, offset); | |
| size = (FX_DWORD)((FX_FILESIZE)(offset + size + 512) > m_dwFileLen ? m_dwFileLen - offset : size + 512); | |
| if (!m_pFileAvail->IsDataAvail(offset, size)) { | |
| pHints->AddSegment(offset, size); | |
| return NULL; | |
| } | |
| CPDF_Parser *pParser = (CPDF_Parser *)(m_pDocument->GetParser()); | |
| pRet = pParser->ParseIndirectObject(NULL, objnum, NULL); | |
| if (!pRet && pExistInFile) { | |
| *pExistInFile = FALSE; | |
| } | |
| return pRet; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckInfo(IFX_DownloadHints* pHints) | |
| { | |
| FX_BOOL bExist = FALSE; | |
| CPDF_Object *pInfo = GetObject(m_dwInfoObjNum, pHints, &bExist); | |
| if (!bExist) { | |
| if (m_bHaveAcroForm) { | |
| m_docStatus = PDF_DATAAVAIL_ACROFORM; | |
| } else { | |
| m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
| } | |
| return TRUE; | |
| } | |
| if (!pInfo) { | |
| if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| return TRUE; | |
| } | |
| if (m_Pos == m_dwFileLen) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| } | |
| return FALSE; | |
| } | |
| if (pInfo) { | |
| pInfo->Release(); | |
| } | |
| if (m_bHaveAcroForm) { | |
| m_docStatus = PDF_DATAAVAIL_ACROFORM; | |
| } else { | |
| m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckRoot(IFX_DownloadHints* pHints) | |
| { | |
| FX_BOOL bExist = FALSE; | |
| m_pRoot = GetObject(m_dwRootObjNum, pHints, &bExist); | |
| if (!bExist) { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| return TRUE; | |
| } | |
| if (!m_pRoot) { | |
| if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| CPDF_Reference* pRef = (CPDF_Reference*)m_pRoot->GetDict()->GetElement(FX_BSTRC("Pages")); | |
| if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| m_PagesObjNum = pRef->GetRefObjNum(); | |
| CPDF_Reference* pAcroFormRef = (CPDF_Reference*)m_pRoot->GetDict()->GetElement(FX_BSTRC("AcroForm")); | |
| if (pAcroFormRef && pAcroFormRef->GetType() == PDFOBJ_REFERENCE) { | |
| m_bHaveAcroForm = TRUE; | |
| m_dwAcroFormObjNum = pAcroFormRef->GetRefObjNum(); | |
| } | |
| if (m_dwInfoObjNum) { | |
| m_docStatus = PDF_DATAAVAIL_INFO; | |
| } else { | |
| if (m_bHaveAcroForm) { | |
| m_docStatus = PDF_DATAAVAIL_ACROFORM; | |
| } else { | |
| m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
| } | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::PreparePageItem() | |
| { | |
| CPDF_Dictionary *pRoot = m_pDocument->GetRoot(); | |
| CPDF_Reference* pRef = (CPDF_Reference*)pRoot->GetElement(FX_BSTRC("Pages")); | |
| if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| m_PagesObjNum = pRef->GetRefObjNum(); | |
| m_pCurrentParser = (CPDF_Parser *)m_pDocument->GetParser(); | |
| m_docStatus = PDF_DATAAVAIL_PAGETREE; | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::IsFirstCheck(int iPage) | |
| { | |
| if (NULL == m_pageMapCheckState) { | |
| m_pageMapCheckState = FX_NEW CFX_CMapDWordToDWord(); | |
| } | |
| FX_DWORD dwValue = 0; | |
| if (!m_pageMapCheckState->Lookup(iPage, dwValue)) { | |
| m_pageMapCheckState->SetAt(iPage, 1); | |
| return TRUE; | |
| } | |
| if (dwValue != 0) { | |
| return FALSE; | |
| } | |
| m_pageMapCheckState->SetAt(iPage, 1); | |
| return TRUE; | |
| } | |
| void CPDF_DataAvail::ResetFirstCheck(int iPage) | |
| { | |
| if (NULL == m_pageMapCheckState) { | |
| m_pageMapCheckState = FX_NEW CFX_CMapDWordToDWord(); | |
| } | |
| FX_DWORD dwValue = 1; | |
| if (!m_pageMapCheckState->Lookup(iPage, dwValue)) { | |
| return; | |
| } | |
| m_pageMapCheckState->SetAt(iPage, 0); | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckPage(IFX_DownloadHints* pHints) | |
| { | |
| FX_DWORD i = 0; | |
| FX_DWORD iLen = m_PageObjList.GetSize(); | |
| CFX_DWordArray UnavailObjList; | |
| for (; i < iLen; ++i) { | |
| FX_DWORD dwPageObjNum = m_PageObjList.GetAt(i); | |
| FX_BOOL bExist = FALSE; | |
| CPDF_Object *pObj = GetObject(dwPageObjNum, pHints, &bExist); | |
| if (!pObj) { | |
| if (bExist) { | |
| UnavailObjList.Add(dwPageObjNum); | |
| } | |
| continue; | |
| } | |
| if (pObj->GetType() == PDFOBJ_ARRAY) { | |
| CPDF_Array *pArray = pObj->GetArray(); | |
| if (pArray) { | |
| FX_INT32 iSize = pArray->GetCount(); | |
| CPDF_Object *pItem = NULL; | |
| for (FX_INT32 j = 0; j < iSize; ++j) { | |
| pItem = pArray->GetElement(j); | |
| if (pItem && pItem->GetType() == PDFOBJ_REFERENCE) { | |
| UnavailObjList.Add(((CPDF_Reference *)pItem)->GetRefObjNum()); | |
| } | |
| } | |
| } | |
| } | |
| if (pObj->GetType() != PDFOBJ_DICTIONARY) { | |
| pObj->Release(); | |
| continue; | |
| } | |
| CFX_ByteString type = pObj->GetDict()->GetString(FX_BSTRC("Type")); | |
| if (type == FX_BSTRC("Pages")) { | |
| m_PagesArray.Add(pObj); | |
| continue; | |
| } | |
| pObj->Release(); | |
| } | |
| m_PageObjList.RemoveAll(); | |
| if (UnavailObjList.GetSize()) { | |
| m_PageObjList.Append(UnavailObjList); | |
| return FALSE; | |
| } | |
| i = 0; | |
| iLen = m_PagesArray.GetSize(); | |
| for (; i < iLen; ++i) { | |
| CPDF_Object *pPages = (CPDF_Object *)m_PagesArray.GetAt(i); | |
| if (!pPages) { | |
| continue; | |
| } | |
| if (!GetPageKids(m_pCurrentParser, pPages)) { | |
| pPages->Release(); | |
| while (i++ < iLen) { | |
| pPages = (CPDF_Object *)m_PagesArray.GetAt(i); | |
| pPages->Release(); | |
| } | |
| m_PagesArray.RemoveAll(); | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| pPages->Release(); | |
| } | |
| m_PagesArray.RemoveAll(); | |
| if (!m_PageObjList.GetSize()) { | |
| m_docStatus = PDF_DATAAVAIL_DONE; | |
| return TRUE; | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::GetPageKids(CPDF_Parser *pParser, CPDF_Object *pPages) | |
| { | |
| if (!pParser) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| CPDF_Object *pKids = pPages->GetDict()->GetElement(FX_BSTRC("Kids")); | |
| if (!pKids) { | |
| return TRUE; | |
| } | |
| switch (pKids->GetType()) { | |
| case PDFOBJ_REFERENCE: { | |
| CPDF_Reference *pKid = (CPDF_Reference *)pKids; | |
| m_PageObjList.Add(pKid->GetRefObjNum()); | |
| } | |
| break; | |
| case PDFOBJ_ARRAY: { | |
| CPDF_Array *pKidsArray = (CPDF_Array *)pKids; | |
| for (FX_DWORD i = 0; i < pKidsArray->GetCount(); ++i) { | |
| CPDF_Reference *pKid = (CPDF_Reference *)pKidsArray->GetElement(i); | |
| m_PageObjList.Add(pKid->GetRefObjNum()); | |
| } | |
| } | |
| break; | |
| default: | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckPages(IFX_DownloadHints* pHints) | |
| { | |
| FX_BOOL bExist = FALSE; | |
| CPDF_Object *pPages = GetObject(m_PagesObjNum, pHints, &bExist); | |
| if (!bExist) { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| return TRUE; | |
| } | |
| if (!pPages) { | |
| if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| FX_BOOL bNeedLoad = FALSE; | |
| if (!GetPageKids(m_pCurrentParser, pPages)) { | |
| pPages->Release(); | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| pPages->Release(); | |
| m_docStatus = PDF_DATAAVAIL_PAGE; | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckHeader(IFX_DownloadHints* pHints) | |
| { | |
| FX_DWORD req_size = 1024; | |
| if ((FX_FILESIZE)req_size > m_dwFileLen) { | |
| req_size = (FX_DWORD)m_dwFileLen; | |
| } | |
| if (m_pFileAvail->IsDataAvail(0, req_size)) { | |
| FX_BYTE buffer[1024]; | |
| m_pFileRead->ReadBlock(buffer, 0, req_size); | |
| if (IsLinearizedFile(buffer, req_size)) { | |
| m_docStatus = PDF_DATAAVAIL_FIRSTPAGE; | |
| } else { | |
| if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| return FALSE; | |
| } | |
| m_docStatus = PDF_DATAAVAIL_END; | |
| } | |
| return TRUE; | |
| } | |
| pHints->AddSegment(0, req_size); | |
| return FALSE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckFirstPage(IFX_DownloadHints *pHints) | |
| { | |
| FX_DWORD dwFirstPageEndOffset = 0; | |
| CPDF_Object *pEndOffSet = m_pLinearized->GetDict()->GetElement(FX_BSTRC("E")); | |
| if (!pEndOffSet) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| CPDF_Object *pXRefOffset = m_pLinearized->GetDict()->GetElement(FX_BSTRC("T")); | |
| if (!pXRefOffset) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| CPDF_Object *pFileLen = m_pLinearized->GetDict()->GetElement(FX_BSTRC("L")); | |
| if (!pFileLen) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| FX_BOOL bNeedDownLoad = FALSE; | |
| if (pEndOffSet->GetType() == PDFOBJ_NUMBER) { | |
| FX_DWORD dwEnd = pEndOffSet->GetInteger(); | |
| dwEnd += 512; | |
| if ((FX_FILESIZE)dwEnd > m_dwFileLen) { | |
| dwEnd = (FX_DWORD)m_dwFileLen; | |
| } | |
| FX_INT32 iStartPos = (FX_INT32)(m_dwFileLen > 1024 ? 1024 : m_dwFileLen); | |
| FX_INT32 iSize = dwEnd > 1024 ? dwEnd - 1024 : 0; | |
| if (!m_pFileAvail->IsDataAvail(iStartPos, iSize)) { | |
| pHints->AddSegment(iStartPos, iSize); | |
| bNeedDownLoad = TRUE; | |
| } | |
| } | |
| m_dwLastXRefOffset = 0; | |
| FX_FILESIZE dwFileLen = 0; | |
| if (pXRefOffset->GetType() == PDFOBJ_NUMBER) { | |
| m_dwLastXRefOffset = pXRefOffset->GetInteger(); | |
| } | |
| if (pFileLen->GetType() == PDFOBJ_NUMBER) { | |
| dwFileLen = pFileLen->GetInteger(); | |
| } | |
| if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, (FX_DWORD)(dwFileLen - m_dwLastXRefOffset))) { | |
| if (m_docStatus == PDF_DATAAVAIL_FIRSTPAGE) { | |
| FX_DWORD dwSize = (FX_DWORD)(dwFileLen - m_dwLastXRefOffset); | |
| FX_FILESIZE offset = m_dwLastXRefOffset; | |
| if (dwSize < 512 && dwFileLen > 512) { | |
| dwSize = 512; | |
| offset = dwFileLen - 512; | |
| } | |
| pHints->AddSegment(offset, dwSize); | |
| } | |
| } else { | |
| m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; | |
| } | |
| if (!bNeedDownLoad && m_docStatus == PDF_DATAAVAIL_FIRSTPAGE_PREPARE) { | |
| m_docStatus = PDF_DATAAVAIL_DONE; | |
| return TRUE; | |
| } | |
| m_docStatus = PDF_DATAAVAIL_FIRSTPAGE_PREPARE; | |
| return FALSE; | |
| } | |
| CPDF_Object * CPDF_DataAvail::ParseIndirectObjectAt(FX_FILESIZE pos, FX_DWORD objnum) | |
| { | |
| FX_FILESIZE SavedPos = m_syntaxParser.SavePos(); | |
| m_syntaxParser.RestorePos(pos); | |
| FX_BOOL bIsNumber; | |
| CFX_ByteString word = m_syntaxParser.GetNextWord(bIsNumber); | |
| if (!bIsNumber) { | |
| return NULL; | |
| } | |
| FX_DWORD real_objnum = FXSYS_atoi(word); | |
| if (objnum && real_objnum != objnum) { | |
| return NULL; | |
| } | |
| word = m_syntaxParser.GetNextWord(bIsNumber); | |
| if (!bIsNumber) { | |
| return NULL; | |
| } | |
| FX_DWORD gennum = FXSYS_atoi(word); | |
| if (m_syntaxParser.GetKeyword() != FX_BSTRC("obj")) { | |
| m_syntaxParser.RestorePos(SavedPos); | |
| return NULL; | |
| } | |
| CPDF_Object* pObj = m_syntaxParser.GetObject(NULL, objnum, gennum, 0); | |
| m_syntaxParser.RestorePos(SavedPos); | |
| return pObj; | |
| } | |
| FX_INT32 CPDF_DataAvail::IsLinearizedPDF() | |
| { | |
| FX_DWORD req_size = 1024; | |
| if (!m_pFileAvail->IsDataAvail(0, req_size)) { | |
| return PDF_UNKNOW_LINEARIZED; | |
| } | |
| if (!m_pFileRead) { | |
| return PDF_NOT_LINEARIZED; | |
| } | |
| FX_FILESIZE dwSize = m_pFileRead->GetSize(); | |
| if (dwSize < (FX_FILESIZE)req_size) { | |
| return PDF_UNKNOW_LINEARIZED; | |
| } | |
| FX_BYTE buffer[1024]; | |
| m_pFileRead->ReadBlock(buffer, 0, req_size); | |
| if (IsLinearizedFile(buffer, req_size)) { | |
| return PDF_IS_LINEARIZED; | |
| } | |
| return PDF_NOT_LINEARIZED; | |
| } | |
| FX_BOOL CPDF_DataAvail::IsLinearizedFile(FX_LPBYTE pData, FX_DWORD dwLen) | |
| { | |
| CFX_SmartPointer<IFX_FileStream> file(FX_CreateMemoryStream(pData, (size_t)dwLen, FALSE)); | |
| FX_INT32 offset = GetHeaderOffset((IFX_FileStream*)file); | |
| if (offset == -1) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| m_dwHeaderOffset = offset; | |
| m_syntaxParser.InitParser((IFX_FileStream*)file, offset); | |
| m_syntaxParser.RestorePos(m_syntaxParser.m_HeaderOffset + 9); | |
| FX_BOOL bNumber = FALSE; | |
| FX_FILESIZE dwSavePos = m_syntaxParser.SavePos(); | |
| CFX_ByteString wordObjNum = m_syntaxParser.GetNextWord(bNumber); | |
| if (!bNumber) { | |
| return FALSE; | |
| } | |
| FX_DWORD objnum = FXSYS_atoi(wordObjNum); | |
| if (m_pLinearized) { | |
| m_pLinearized->Release(); | |
| m_pLinearized = NULL; | |
| } | |
| m_pLinearized = ParseIndirectObjectAt(m_syntaxParser.m_HeaderOffset + 9, objnum); | |
| if (!m_pLinearized) { | |
| return FALSE; | |
| } | |
| if (m_pLinearized->GetDict()->GetElement(FX_BSTRC("Linearized"))) { | |
| CPDF_Object *pLen = m_pLinearized->GetDict()->GetElement(FX_BSTRC("L")); | |
| if (!pLen) { | |
| return FALSE; | |
| } | |
| if ((FX_FILESIZE)pLen->GetInteger() != m_pFileRead->GetSize()) { | |
| return FALSE; | |
| } | |
| m_bLinearized = TRUE; | |
| CPDF_Object *pNo = m_pLinearized->GetDict()->GetElement(FX_BSTRC("P")); | |
| if (pNo && pNo->GetType() == PDFOBJ_NUMBER) { | |
| m_dwFirstPageNo = pNo->GetInteger(); | |
| } | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckEnd(IFX_DownloadHints* pHints) | |
| { | |
| FX_DWORD req_pos = (FX_DWORD)(m_dwFileLen > 1024 ? m_dwFileLen - 1024 : 0); | |
| FX_DWORD dwSize = (FX_DWORD)(m_dwFileLen - req_pos); | |
| if (m_pFileAvail->IsDataAvail(req_pos, dwSize)) { | |
| FX_BYTE buffer[1024]; | |
| m_pFileRead->ReadBlock(buffer, req_pos, dwSize); | |
| CFX_SmartPointer<IFX_FileStream> file(FX_CreateMemoryStream(buffer, (size_t)dwSize, FALSE)); | |
| m_syntaxParser.InitParser((IFX_FileStream*)file, 0); | |
| m_syntaxParser.RestorePos(dwSize - 1); | |
| if (m_syntaxParser.SearchWord(FX_BSTRC("startxref"), TRUE, FALSE, dwSize)) { | |
| FX_BOOL bNumber; | |
| m_syntaxParser.GetNextWord(bNumber); | |
| CFX_ByteString xrefpos_str = m_syntaxParser.GetNextWord(bNumber); | |
| if (!bNumber) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| m_dwXRefOffset = (FX_FILESIZE)FXSYS_atoi64(xrefpos_str); | |
| if (!m_dwXRefOffset || m_dwXRefOffset > m_dwFileLen) { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| return TRUE; | |
| } | |
| m_dwLastXRefOffset = m_dwXRefOffset; | |
| SetStartOffset(m_dwXRefOffset); | |
| m_docStatus = PDF_DATAAVAIL_CROSSREF; | |
| return TRUE; | |
| } else { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| return TRUE; | |
| } | |
| } | |
| pHints->AddSegment(req_pos, dwSize); | |
| return FALSE; | |
| } | |
| FX_DWORD CPDF_DataAvail::CheckCrossRefStream(IFX_DownloadHints* pHints, FX_FILESIZE &xref_offset) | |
| { | |
| xref_offset = 0; | |
| FX_DWORD req_size = (FX_DWORD)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| if (m_pFileAvail->IsDataAvail(m_Pos, req_size)) { | |
| FX_INT32 iSize = (FX_INT32)(m_Pos + req_size - m_dwCurrentXRefSteam); | |
| CFX_BinaryBuf buf(iSize); | |
| FX_LPBYTE pBuf = buf.GetBuffer(); | |
| m_pFileRead->ReadBlock(pBuf, m_dwCurrentXRefSteam, iSize); | |
| CFX_SmartPointer<IFX_FileStream> file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); | |
| m_parser.m_Syntax.InitParser((IFX_FileStream*)file, 0); | |
| FX_BOOL bNumber = FALSE; | |
| FX_FILESIZE dwSavePos = m_parser.m_Syntax.SavePos(); | |
| CFX_ByteString objnum = m_parser.m_Syntax.GetNextWord(bNumber); | |
| if (!bNumber) { | |
| return -1; | |
| } | |
| FX_DWORD objNum = FXSYS_atoi(objnum); | |
| CPDF_Object *pObj = m_parser.ParseIndirectObjectAt(NULL, 0, objNum, NULL); | |
| if (!pObj) { | |
| m_Pos += m_parser.m_Syntax.SavePos(); | |
| return 0; | |
| } | |
| CPDF_Object *pName = pObj->GetDict()->GetElement(FX_BSTRC("Type")); | |
| if (pName && pName->GetType() == PDFOBJ_NAME) { | |
| if (pName->GetString() == FX_BSTRC("XRef")) { | |
| m_Pos += m_parser.m_Syntax.SavePos(); | |
| xref_offset = pObj->GetDict()->GetInteger(FX_BSTRC("Prev")); | |
| pObj->Release(); | |
| return 1; | |
| } else { | |
| pObj->Release(); | |
| return -1; | |
| } | |
| } | |
| pObj->Release(); | |
| return -1; | |
| } | |
| pHints->AddSegment(m_Pos, req_size); | |
| return 0; | |
| } | |
| inline void CPDF_DataAvail::SetStartOffset(FX_FILESIZE dwOffset) | |
| { | |
| m_Pos = dwOffset; | |
| } | |
| #define MAX_WORD_BUFFER 256 | |
| FX_BOOL CPDF_DataAvail::GetNextToken(CFX_ByteString &token) | |
| { | |
| m_WordSize = 0; | |
| FX_BYTE ch; | |
| if (!GetNextChar(ch)) { | |
| return FALSE; | |
| } | |
| FX_BYTE type = _PDF_CharType[ch]; | |
| while (1) { | |
| while (type == 'W') { | |
| if (!GetNextChar(ch)) { | |
| return FALSE; | |
| } | |
| type = _PDF_CharType[ch]; | |
| } | |
| if (ch != '%') { | |
| break; | |
| } | |
| while (1) { | |
| if (!GetNextChar(ch)) { | |
| return FALSE; | |
| } | |
| if (ch == '\r' || ch == '\n') { | |
| break; | |
| } | |
| } | |
| type = _PDF_CharType[ch]; | |
| } | |
| if (type == 'D') { | |
| m_WordBuffer[m_WordSize++] = ch; | |
| if (ch == '/') { | |
| while (1) { | |
| if (!GetNextChar(ch)) { | |
| return FALSE; | |
| } | |
| type = _PDF_CharType[ch]; | |
| if (type != 'R' && type != 'N') { | |
| m_Pos --; | |
| CFX_ByteString ret(m_WordBuffer, m_WordSize); | |
| token = ret; | |
| return TRUE; | |
| } | |
| if (m_WordSize < MAX_WORD_BUFFER) { | |
| m_WordBuffer[m_WordSize++] = ch; | |
| } | |
| } | |
| } else if (ch == '<') { | |
| if (!GetNextChar(ch)) { | |
| return FALSE; | |
| } | |
| if (ch == '<') { | |
| m_WordBuffer[m_WordSize++] = ch; | |
| } else { | |
| m_Pos --; | |
| } | |
| } else if (ch == '>') { | |
| if (!GetNextChar(ch)) { | |
| return FALSE; | |
| } | |
| if (ch == '>') { | |
| m_WordBuffer[m_WordSize++] = ch; | |
| } else { | |
| m_Pos --; | |
| } | |
| } | |
| CFX_ByteString ret(m_WordBuffer, m_WordSize); | |
| token = ret; | |
| return TRUE; | |
| } | |
| while (1) { | |
| if (m_WordSize < MAX_WORD_BUFFER) { | |
| m_WordBuffer[m_WordSize++] = ch; | |
| } | |
| if (!GetNextChar(ch)) { | |
| return FALSE; | |
| } | |
| type = _PDF_CharType[ch]; | |
| if (type == 'D' || type == 'W') { | |
| m_Pos --; | |
| break; | |
| } | |
| } | |
| CFX_ByteString ret(m_WordBuffer, m_WordSize); | |
| token = ret; | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::GetNextChar(FX_BYTE &ch) | |
| { | |
| FX_FILESIZE pos = m_Pos; | |
| if (pos >= m_dwFileLen) { | |
| return FALSE; | |
| } | |
| if (m_bufferOffset >= pos || (FX_FILESIZE)(m_bufferOffset + m_bufferSize) <= pos) { | |
| FX_FILESIZE read_pos = pos; | |
| FX_DWORD read_size = 512; | |
| if ((FX_FILESIZE)read_size > m_dwFileLen) { | |
| read_size = (FX_DWORD)m_dwFileLen; | |
| } | |
| if ((FX_FILESIZE)(read_pos + read_size) > m_dwFileLen) { | |
| read_pos = m_dwFileLen - read_size; | |
| } | |
| if (!m_pFileRead->ReadBlock(m_bufferData, read_pos, read_size)) { | |
| return FALSE; | |
| } | |
| m_bufferOffset = read_pos; | |
| m_bufferSize = read_size; | |
| } | |
| ch = m_bufferData[pos - m_bufferOffset]; | |
| m_Pos ++; | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckCrossRefItem(IFX_DownloadHints *pHints) | |
| { | |
| FX_INT32 iSize = 0; | |
| CFX_ByteString token; | |
| while (1) { | |
| if (!GetNextToken(token)) { | |
| iSize = (FX_INT32)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| pHints->AddSegment(m_Pos, iSize); | |
| return FALSE; | |
| } | |
| if (token == "trailer") { | |
| m_dwTrailerOffset = m_Pos; | |
| m_docStatus = PDF_DATAAVAIL_TRAILER; | |
| return TRUE; | |
| } | |
| } | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckAllCrossRefStream(IFX_DownloadHints *pHints) | |
| { | |
| FX_FILESIZE xref_offset = 0; | |
| FX_DWORD dwRet = CheckCrossRefStream(pHints, xref_offset); | |
| if (dwRet == 1) { | |
| if (!xref_offset) { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLCRSOSSREF; | |
| } else { | |
| m_dwCurrentXRefSteam = xref_offset; | |
| m_Pos = xref_offset; | |
| } | |
| return TRUE; | |
| } else if (dwRet == -1) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| } | |
| return FALSE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckCrossRef(IFX_DownloadHints* pHints) | |
| { | |
| FX_FILESIZE dwSavePos = m_Pos; | |
| FX_INT32 iSize = 0; | |
| CFX_ByteString token; | |
| if (!GetNextToken(token)) { | |
| iSize = (FX_INT32)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| pHints->AddSegment(m_Pos, iSize); | |
| return FALSE; | |
| } | |
| if (token == "xref") { | |
| m_CrossOffset.InsertAt(0, m_dwXRefOffset); | |
| while (1) { | |
| if (!GetNextToken(token)) { | |
| iSize = (FX_INT32)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| pHints->AddSegment(m_Pos, iSize); | |
| m_docStatus = PDF_DATAAVAIL_CROSSREF_ITEM; | |
| return FALSE; | |
| } | |
| if (token == "trailer") { | |
| m_dwTrailerOffset = m_Pos; | |
| m_docStatus = PDF_DATAAVAIL_TRAILER; | |
| return TRUE; | |
| } | |
| } | |
| } else { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckTrailerAppend(IFX_DownloadHints* pHints) | |
| { | |
| if (m_Pos < m_dwFileLen) { | |
| FX_FILESIZE dwAppendPos = m_Pos + m_syntaxParser.SavePos(); | |
| FX_INT32 iSize = (FX_INT32)(dwAppendPos + 512 > m_dwFileLen ? m_dwFileLen - dwAppendPos : 512); | |
| if (!m_pFileAvail->IsDataAvail(dwAppendPos, iSize)) { | |
| pHints->AddSegment(dwAppendPos, iSize); | |
| return FALSE; | |
| } | |
| } | |
| if (m_dwPrevXRefOffset) { | |
| SetStartOffset(m_dwPrevXRefOffset); | |
| m_docStatus = PDF_DATAAVAIL_CROSSREF; | |
| } else { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLCRSOSSREF; | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckTrailer(IFX_DownloadHints* pHints) | |
| { | |
| FX_INT32 iTrailerSize = (FX_INT32)(m_Pos + 512 > m_dwFileLen ? m_dwFileLen - m_Pos : 512); | |
| if (m_pFileAvail->IsDataAvail(m_Pos, iTrailerSize)) { | |
| FX_INT32 iSize = (FX_INT32)(m_Pos + iTrailerSize - m_dwTrailerOffset); | |
| CFX_BinaryBuf buf(iSize); | |
| FX_LPBYTE pBuf = buf.GetBuffer(); | |
| if (!pBuf) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| if (!m_pFileRead->ReadBlock(pBuf, m_dwTrailerOffset, iSize)) { | |
| return FALSE; | |
| } | |
| CFX_SmartPointer<IFX_FileStream> file(FX_CreateMemoryStream(pBuf, (size_t)iSize, FALSE)); | |
| m_syntaxParser.InitParser((IFX_FileStream*)file, 0); | |
| CPDF_Object *pTrailer = m_syntaxParser.GetObject(NULL, 0, 0, 0); | |
| if (!pTrailer) { | |
| m_Pos += m_syntaxParser.SavePos(); | |
| pHints->AddSegment(m_Pos, iTrailerSize); | |
| return FALSE; | |
| } | |
| CPDF_Dictionary *pTrailerDict = pTrailer->GetDict(); | |
| if (pTrailerDict) { | |
| CPDF_Object *pEncrypt = pTrailerDict->GetElement("Encrypt"); | |
| if (pEncrypt && pEncrypt->GetType() == PDFOBJ_REFERENCE) { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| pTrailer->Release(); | |
| return TRUE; | |
| } | |
| } | |
| FX_DWORD xrefpos = GetDirectInteger(pTrailer->GetDict(), FX_BSTRC("Prev")); | |
| if (xrefpos) { | |
| m_dwPrevXRefOffset = GetDirectInteger(pTrailer->GetDict(), FX_BSTRC("XRefStm")); | |
| pTrailer->Release(); | |
| if (m_dwPrevXRefOffset) { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| } else { | |
| m_dwPrevXRefOffset = xrefpos; | |
| if (m_dwPrevXRefOffset >= m_dwFileLen) { | |
| m_docStatus = PDF_DATAAVAIL_LOADALLFILE; | |
| } else { | |
| SetStartOffset(m_dwPrevXRefOffset); | |
| m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; | |
| } | |
| } | |
| return TRUE; | |
| } else { | |
| m_dwPrevXRefOffset = 0; | |
| m_docStatus = PDF_DATAAVAIL_TRAILER_APPEND; | |
| pTrailer->Release(); | |
| } | |
| return TRUE; | |
| } | |
| pHints->AddSegment(m_Pos, iTrailerSize); | |
| return FALSE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckPage(FX_INT32 iPage, IFX_DownloadHints* pHints) | |
| { | |
| while (TRUE) { | |
| switch (m_docStatus) { | |
| case PDF_DATAAVAIL_PAGETREE: | |
| if (!LoadDocPages(pHints)) { | |
| return FALSE; | |
| } | |
| break; | |
| case PDF_DATAAVAIL_PAGE: | |
| if (!LoadDocPage(iPage, pHints)) { | |
| return FALSE; | |
| } | |
| break; | |
| case PDF_DATAAVAIL_ERROR: | |
| return LoadAllFile(pHints); | |
| default: | |
| m_bPagesTreeLoad = TRUE; | |
| m_bPagesLoad = TRUE; | |
| m_bCurPageDictLoadOK = TRUE; | |
| m_docStatus = PDF_DATAAVAIL_PAGE; | |
| return TRUE; | |
| } | |
| } | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckArrayPageNode(FX_DWORD dwPageNo, CPDF_PageNode *pPageNode, IFX_DownloadHints* pHints) | |
| { | |
| FX_BOOL bExist = FALSE; | |
| CPDF_Object *pPages = GetObject(dwPageNo, pHints, &bExist); | |
| if (!bExist) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| if (!pPages) { | |
| if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| return FALSE; | |
| } | |
| if (pPages->GetType() != PDFOBJ_ARRAY) { | |
| pPages->Release(); | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| pPageNode->m_type = PDF_PAGENODE_PAGES; | |
| CPDF_Array* pArray = (CPDF_Array*)pPages; | |
| for (FX_DWORD i = 0; i < pArray->GetCount(); ++i) { | |
| CPDF_Object *pKid = (CPDF_Object *)pArray->GetElement(i); | |
| if (!pKid || pKid->GetType() != PDFOBJ_REFERENCE) { | |
| continue; | |
| } | |
| CPDF_PageNode *pNode = FX_NEW CPDF_PageNode(); | |
| pPageNode->m_childNode.Add(pNode); | |
| pNode->m_dwPageNo = ((CPDF_Reference*)pKid)->GetRefObjNum(); | |
| } | |
| pPages->Release(); | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckUnkownPageNode(FX_DWORD dwPageNo, CPDF_PageNode *pPageNode, IFX_DownloadHints* pHints) | |
| { | |
| FX_BOOL bExist = FALSE; | |
| CPDF_Object *pPage = GetObject(dwPageNo, pHints, &bExist); | |
| if (!bExist) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| if (!pPage) { | |
| if (m_docStatus == PDF_DATAAVAIL_ERROR) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| return FALSE; | |
| } | |
| if (pPage->GetType() == PDFOBJ_ARRAY) { | |
| pPageNode->m_dwPageNo = dwPageNo; | |
| pPageNode->m_type = PDF_PAGENODE_ARRAY; | |
| pPage->Release(); | |
| return TRUE; | |
| } | |
| if (pPage->GetType() != PDFOBJ_DICTIONARY) { | |
| pPage->Release(); | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| pPageNode->m_dwPageNo = dwPageNo; | |
| CFX_ByteString type = pPage->GetDict()->GetString(FX_BSTRC("Type")); | |
| if (type == FX_BSTRC("Pages")) { | |
| pPageNode->m_type = PDF_PAGENODE_PAGES; | |
| CPDF_Object *pKids = pPage->GetDict()->GetElement(FX_BSTRC("Kids")); | |
| if (!pKids) { | |
| m_docStatus = PDF_DATAAVAIL_PAGE; | |
| return TRUE; | |
| } | |
| switch (pKids->GetType()) { | |
| case PDFOBJ_REFERENCE: { | |
| CPDF_Reference *pKid = (CPDF_Reference *)pKids; | |
| CPDF_PageNode *pNode = FX_NEW CPDF_PageNode(); | |
| pPageNode->m_childNode.Add(pNode); | |
| pNode->m_dwPageNo = pKid->GetRefObjNum(); | |
| } | |
| break; | |
| case PDFOBJ_ARRAY: { | |
| CPDF_Array *pKidsArray = (CPDF_Array *)pKids; | |
| for (FX_DWORD i = 0; i < pKidsArray->GetCount(); ++i) { | |
| CPDF_Object *pKid = (CPDF_Object *)pKidsArray->GetElement(i); | |
| if (!pKid || pKid->GetType() != PDFOBJ_REFERENCE) { | |
| continue; | |
| } | |
| CPDF_PageNode *pNode = FX_NEW CPDF_PageNode(); | |
| pPageNode->m_childNode.Add(pNode); | |
| pNode->m_dwPageNo = ((CPDF_Reference*)pKid)->GetRefObjNum(); | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| } else if (type == FX_BSTRC("Page")) { | |
| pPageNode->m_type = PDF_PAGENODE_PAGE; | |
| } else { | |
| pPage->Release(); | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| pPage->Release(); | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckPageNode(CPDF_PageNode &pageNodes, FX_INT32 iPage, FX_INT32 &iCount, IFX_DownloadHints* pHints) | |
| { | |
| FX_INT32 iSize = pageNodes.m_childNode.GetSize(); | |
| if (!iSize) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| for (FX_INT32 i = 0; i < iSize; ++i) { | |
| CPDF_PageNode *pNode = (CPDF_PageNode*)pageNodes.m_childNode.GetAt(i); | |
| if (!pNode) { | |
| continue; | |
| } | |
| switch (pNode->m_type) { | |
| case PDF_PAGENODE_UNKOWN: | |
| if (!CheckUnkownPageNode(pNode->m_dwPageNo, pNode, pHints)) { | |
| return FALSE; | |
| } | |
| --i; | |
| break; | |
| case PDF_PAGENODE_PAGE: | |
| iCount++; | |
| if (iPage == iCount && m_pDocument) { | |
| m_pDocument->m_PageList.SetAt(iPage, pNode->m_dwPageNo); | |
| } | |
| break; | |
| case PDF_PAGENODE_PAGES: | |
| if (!CheckPageNode(*pNode, iPage, iCount, pHints)) { | |
| return FALSE; | |
| } | |
| break; | |
| case PDF_PAGENODE_ARRAY: | |
| if (!CheckArrayPageNode(pNode->m_dwPageNo, pNode, pHints)) { | |
| return FALSE; | |
| } | |
| --i; | |
| break; | |
| } | |
| if (iPage == iCount) { | |
| m_docStatus = PDF_DATAAVAIL_DONE; | |
| return TRUE; | |
| } | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::LoadDocPage(FX_INT32 iPage, IFX_DownloadHints* pHints) | |
| { | |
| if (m_pDocument->GetPageCount() <= iPage || m_pDocument->m_PageList.GetAt(iPage)) { | |
| m_docStatus = PDF_DATAAVAIL_DONE; | |
| return TRUE; | |
| } | |
| if (m_pageNodes.m_type == PDF_PAGENODE_PAGE) { | |
| if (iPage == 0) { | |
| m_docStatus = PDF_DATAAVAIL_DONE; | |
| return TRUE; | |
| } | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return TRUE; | |
| } | |
| FX_INT32 iCount = -1; | |
| return CheckPageNode(m_pageNodes, iPage, iCount, pHints); | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckPageCount(IFX_DownloadHints* pHints) | |
| { | |
| FX_BOOL bExist = FALSE; | |
| CPDF_Object *pPages = GetObject(m_PagesObjNum, pHints, &bExist); | |
| if (!bExist) { | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| if (!pPages) { | |
| return FALSE; | |
| } | |
| CPDF_Dictionary* pPagesDict = pPages->GetDict(); | |
| if (!pPagesDict) { | |
| pPages->Release(); | |
| m_docStatus = PDF_DATAAVAIL_ERROR; | |
| return FALSE; | |
| } | |
| if (!pPagesDict->KeyExist(FX_BSTRC("Kids"))) { | |
| pPages->Release(); | |
| return TRUE; | |
| } | |
| int count = pPagesDict->GetInteger(FX_BSTRC("Count")); | |
| if (count > 0) { | |
| pPages->Release(); | |
| return TRUE; | |
| } | |
| pPages->Release(); | |
| return FALSE; | |
| } | |
| FX_BOOL CPDF_DataAvail::LoadDocPages(IFX_DownloadHints* pHints) | |
| { | |
| if (!CheckUnkownPageNode(m_PagesObjNum, &m_pageNodes, pHints)) { | |
| return FALSE; | |
| } | |
| if (CheckPageCount(pHints)) { | |
| m_docStatus = PDF_DATAAVAIL_PAGE; | |
| return TRUE; | |
| } else { | |
| m_bTotalLoadPageTree = TRUE; | |
| } | |
| return FALSE; | |
| } | |
| FX_BOOL CPDF_DataAvail::LoadPages(IFX_DownloadHints* pHints) | |
| { | |
| while (!m_bPagesTreeLoad) { | |
| if (!CheckPageStatus(pHints)) { | |
| return FALSE; | |
| } | |
| } | |
| if (m_bPagesLoad) { | |
| return TRUE; | |
| } | |
| m_pDocument->LoadPages(); | |
| return FALSE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckLinearizedData(IFX_DownloadHints* pHints) | |
| { | |
| if (m_bLinearedDataOK) { | |
| return TRUE; | |
| } | |
| if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset, (FX_DWORD)(m_dwFileLen - m_dwLastXRefOffset))) { | |
| pHints->AddSegment(m_dwLastXRefOffset, (FX_DWORD)(m_dwFileLen - m_dwLastXRefOffset)); | |
| return FALSE; | |
| } | |
| FX_DWORD dwRet = 0; | |
| if (!m_bMainXRefLoad) { | |
| dwRet = ((CPDF_Parser *)m_pDocument->GetParser())->LoadLinearizedMainXRefTable(); | |
| if (dwRet == PDFPARSE_ERROR_SUCCESS) { | |
| if (!PreparePageItem()) { | |
| return FALSE; | |
| } | |
| m_bMainXRefLoadedOK = TRUE; | |
| } | |
| m_bMainXRefLoad = TRUE; | |
| } | |
| m_bLinearedDataOK = TRUE; | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckPageAnnots(FX_INT32 iPage, IFX_DownloadHints* pHints) | |
| { | |
| if (!m_objs_array.GetSize()) { | |
| m_objs_array.RemoveAll(); | |
| m_objnum_array.RemoveAll(); | |
| CPDF_Dictionary *pPageDict = m_pDocument->GetPage(iPage); | |
| if (!pPageDict) { | |
| return TRUE; | |
| } | |
| CPDF_Object *pAnnots = pPageDict->GetElement(FX_BSTRC("Annots")); | |
| if (!pAnnots) { | |
| return TRUE; | |
| } | |
| CFX_PtrArray obj_array; | |
| obj_array.Add(pAnnots); | |
| FX_BOOL bRet = IsObjectsAvail(obj_array, FALSE, pHints, m_objs_array); | |
| if (bRet) { | |
| m_objs_array.RemoveAll(); | |
| } | |
| return bRet; | |
| } else { | |
| CFX_PtrArray new_objs_array; | |
| FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| m_objs_array.RemoveAll(); | |
| if (!bRet) { | |
| m_objs_array.Append(new_objs_array); | |
| } | |
| return bRet; | |
| } | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckLinearizedFirstPage(FX_INT32 iPage, IFX_DownloadHints* pHints) | |
| { | |
| if (!m_bAnnotsLoad) { | |
| if (!CheckPageAnnots(iPage, pHints)) { | |
| return FALSE; | |
| } | |
| m_bAnnotsLoad = TRUE; | |
| } | |
| if (m_bAnnotsLoad) | |
| if (!CheckLinearizedData(pHints)) { | |
| return FALSE; | |
| } | |
| m_bPageLoadedOK = FALSE; | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::HaveResourceAncestor(CPDF_Dictionary *pDict) | |
| { | |
| CPDF_Object *pParent = pDict->GetElement("Parent"); | |
| if (!pParent) { | |
| return FALSE; | |
| } | |
| CPDF_Dictionary *pParentDict = pParent->GetDict(); | |
| if (!pParentDict) { | |
| return FALSE; | |
| } | |
| CPDF_Object *pRet = pParentDict->GetElement("Resource"); | |
| if (pRet) { | |
| m_pPageResource = pRet; | |
| return TRUE; | |
| } else { | |
| return HaveResourceAncestor(pParentDict); | |
| } | |
| } | |
| FX_BOOL CPDF_DataAvail::IsPageAvail(FX_INT32 iPage, IFX_DownloadHints* pHints) | |
| { | |
| if (!m_pDocument) { | |
| return FALSE; | |
| } | |
| if (IsFirstCheck(iPage)) { | |
| m_bCurPageDictLoadOK = FALSE; | |
| m_bPageLoadedOK = FALSE; | |
| m_bAnnotsLoad = FALSE; | |
| m_bNeedDownLoadResource = FALSE; | |
| m_objs_array.RemoveAll(); | |
| m_objnum_array.RemoveAll(); | |
| } | |
| if (m_pagesLoadState == NULL) { | |
| m_pagesLoadState = FX_NEW CFX_CMapDWordToDWord(); | |
| } | |
| FX_DWORD dwPageLoad = 0; | |
| if (m_pagesLoadState->Lookup(iPage, dwPageLoad) && dwPageLoad != 0) { | |
| return TRUE; | |
| } | |
| if (m_bLinearized) { | |
| if ((FX_DWORD)iPage == m_dwFirstPageNo) { | |
| m_pagesLoadState->SetAt(iPage, TRUE); | |
| return TRUE; | |
| } | |
| if (!CheckLinearizedData(pHints)) { | |
| return FALSE; | |
| } | |
| if (m_bMainXRefLoadedOK) { | |
| if (m_bTotalLoadPageTree) { | |
| if (!LoadPages(pHints)) { | |
| return FALSE; | |
| } | |
| } else { | |
| if (!m_bCurPageDictLoadOK && !CheckPage(iPage, pHints)) { | |
| return FALSE; | |
| } | |
| } | |
| } else { | |
| if (!LoadAllFile(pHints)) { | |
| return FALSE; | |
| } | |
| ((CPDF_Parser *)m_pDocument->GetParser())->RebuildCrossRef(); | |
| ResetFirstCheck(iPage); | |
| return TRUE; | |
| } | |
| } else { | |
| if (!m_bTotalLoadPageTree) { | |
| if (!m_bCurPageDictLoadOK && !CheckPage(iPage, pHints)) { | |
| return FALSE; | |
| } | |
| } | |
| } | |
| if (m_bHaveAcroForm && !m_bAcroFormLoad) { | |
| if (!CheckAcroFormSubObject(pHints)) { | |
| return FALSE; | |
| } | |
| m_bAcroFormLoad = TRUE; | |
| } | |
| if (!m_bPageLoadedOK) { | |
| if (!m_objs_array.GetSize()) { | |
| m_objs_array.RemoveAll(); | |
| m_objnum_array.RemoveAll(); | |
| m_pPageDict = m_pDocument->GetPage(iPage); | |
| if (!m_pPageDict) { | |
| ResetFirstCheck(iPage); | |
| return TRUE; | |
| } | |
| CFX_PtrArray obj_array; | |
| obj_array.Add(m_pPageDict); | |
| FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); | |
| if (bRet) { | |
| m_objs_array.RemoveAll(); | |
| m_bPageLoadedOK = TRUE; | |
| } else { | |
| return bRet; | |
| } | |
| } else { | |
| CFX_PtrArray new_objs_array; | |
| FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| m_objs_array.RemoveAll(); | |
| if (bRet) { | |
| m_bPageLoadedOK = TRUE; | |
| } else { | |
| m_objs_array.Append(new_objs_array); | |
| return bRet; | |
| } | |
| } | |
| } | |
| if (m_bPageLoadedOK) { | |
| if (!m_bAnnotsLoad) { | |
| if (!CheckPageAnnots(iPage, pHints)) { | |
| return FALSE; | |
| } | |
| m_bAnnotsLoad = TRUE; | |
| } | |
| } | |
| if (m_pPageDict && !m_bNeedDownLoadResource) { | |
| CPDF_Object *pRes = m_pPageDict->GetElement("Resource"); | |
| if (!pRes) { | |
| m_bNeedDownLoadResource = HaveResourceAncestor(m_pPageDict); | |
| } | |
| m_bNeedDownLoadResource = FALSE; | |
| } | |
| if (m_bNeedDownLoadResource) { | |
| FX_BOOL bRet = CheckResources(pHints); | |
| if (!bRet) { | |
| return FALSE; | |
| } | |
| m_bNeedDownLoadResource = FALSE; | |
| } | |
| m_bPageLoadedOK = FALSE; | |
| m_bAnnotsLoad = FALSE; | |
| m_bCurPageDictLoadOK = FALSE; | |
| ResetFirstCheck(iPage); | |
| m_pagesLoadState->SetAt(iPage, TRUE); | |
| return TRUE; | |
| } | |
| FX_BOOL CPDF_DataAvail::CheckResources(IFX_DownloadHints* pHints) | |
| { | |
| if (!m_objs_array.GetSize()) { | |
| m_objs_array.RemoveAll(); | |
| CFX_PtrArray obj_array; | |
| obj_array.Add(m_pPageResource); | |
| FX_BOOL bRet = IsObjectsAvail(obj_array, TRUE, pHints, m_objs_array); | |
| if (bRet) { | |
| m_objs_array.RemoveAll(); | |
| } | |
| return bRet; | |
| } else { | |
| CFX_PtrArray new_objs_array; | |
| FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| m_objs_array.RemoveAll(); | |
| if (!bRet) { | |
| m_objs_array.Append(new_objs_array); | |
| } | |
| return bRet; | |
| } | |
| } | |
| void CPDF_DataAvail::GetLinearizedMainXRefInfo(FX_FILESIZE *pPos, FX_DWORD *pSize) | |
| { | |
| if (pPos) { | |
| *pPos = m_dwLastXRefOffset; | |
| } | |
| if (pSize) { | |
| *pSize = (FX_DWORD)(m_dwFileLen - m_dwLastXRefOffset); | |
| } | |
| } | |
| FX_INT32 CPDF_DataAvail::IsFormAvail(IFX_DownloadHints *pHints) | |
| { | |
| if (!m_pDocument) { | |
| return PDFFORM_AVAIL; | |
| } | |
| if (!m_bLinearizedFormParamLoad) { | |
| CPDF_Dictionary *pRoot = m_pDocument->GetRoot(); | |
| if (!pRoot) { | |
| return PDFFORM_AVAIL; | |
| } | |
| CPDF_Object *pAcroForm = pRoot->GetElement(FX_BSTRC("AcroForm")); | |
| if (!pAcroForm) { | |
| return PDFFORM_NOTEXIST; | |
| } | |
| if (!m_bMainXRefLoad && !CheckLinearizedData(pHints)) { | |
| return PDFFORM_NOTAVAIL; | |
| } | |
| if (!m_objs_array.GetSize()) { | |
| m_objs_array.Add(pAcroForm->GetDict()); | |
| } | |
| m_bLinearizedFormParamLoad = TRUE; | |
| } | |
| CFX_PtrArray new_objs_array; | |
| FX_BOOL bRet = IsObjectsAvail(m_objs_array, FALSE, pHints, new_objs_array); | |
| m_objs_array.RemoveAll(); | |
| if (!bRet) { | |
| m_objs_array.Append(new_objs_array); | |
| return PDFFORM_NOTAVAIL; | |
| } | |
| return PDFFORM_AVAIL; | |
| } | |
| void CPDF_SortObjNumArray::AddObjNum(FX_DWORD dwObjNum) | |
| { | |
| FX_INT32 iNext = 0; | |
| if (BinarySearch(dwObjNum, iNext)) { | |
| return; | |
| } | |
| m_number_array.InsertAt(iNext, dwObjNum); | |
| } | |
| FX_BOOL CPDF_SortObjNumArray::Find(FX_DWORD dwObjNum) | |
| { | |
| FX_INT32 iNext = 0; | |
| return BinarySearch(dwObjNum, iNext); | |
| } | |
| FX_BOOL CPDF_SortObjNumArray::BinarySearch(FX_DWORD value, FX_INT32 &iNext) | |
| { | |
| FX_INT32 iLen = m_number_array.GetSize(); | |
| FX_INT32 iLow = 0; | |
| FX_INT32 iHigh = iLen - 1; | |
| FX_INT32 iMid = 0; | |
| while (iLow <= iHigh) { | |
| iMid = (iLow + iHigh) / 2; | |
| FX_DWORD tt = m_number_array.GetAt(iMid); | |
| if (m_number_array.GetAt(iMid) == value) { | |
| iNext = iMid; | |
| return TRUE; | |
| } else if (m_number_array.GetAt(iMid) > value) { | |
| iHigh = iMid - 1; | |
| } else if (m_number_array.GetAt(iMid) < value) { | |
| iLow = iMid + 1; | |
| } | |
| } | |
| iNext = iLow; | |
| return FALSE; | |
| } | |
| CPDF_PageNode::~CPDF_PageNode() | |
| { | |
| FX_INT32 iSize = m_childNode.GetSize(); | |
| for (FX_INT32 i = 0; i < iSize; ++i) { | |
| CPDF_PageNode *pNode = (CPDF_PageNode*)m_childNode[i]; | |
| if (pNode) { | |
| delete pNode; | |
| } | |
| } | |
| m_childNode.RemoveAll(); | |
| } |