mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@52670 954022d7-b5bf-4e40-9824-e11837661b57
1040 lines
24 KiB
C++
1040 lines
24 KiB
C++
#include "stdafx.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "MemoryUtils.h"
|
|
#include "Object.h"
|
|
#include "Stream.h"
|
|
#include "Lexer.h"
|
|
#include "Parser.h"
|
|
#include "Dict.h"
|
|
#include "ErrorConstants.h"
|
|
#include "XRef.h"
|
|
#include "../Common/TemporaryCS.h"
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------------
|
|
|
|
#define XrefSearchSize 1024 // ×èòàåì ñòîëüêî áàéò, íà÷èíàÿ ñ êîíöà ôàéëà, ÷òîáû íàéòè 'startxref'
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------------
|
|
// Permission bits
|
|
//---------------------------------------------------------------------------------------------------------------------------
|
|
|
|
#define PermissionPrint ( 1 << 2 )
|
|
#define PermissionChange ( 1 << 3 )
|
|
#define PermissionCopy ( 1 << 4 )
|
|
#define PermissionNotes ( 1 << 5 )
|
|
#define DefaultPermissionFlags 0xfffc
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------------
|
|
// ObjectStream
|
|
//---------------------------------------------------------------------------------------------------------------------------
|
|
|
|
class ObjectStream
|
|
{
|
|
public:
|
|
|
|
ObjectStream(XRef *pXref, int nObjectStreamNum);
|
|
|
|
~ObjectStream();
|
|
|
|
int GetObjectStreamNum()
|
|
{
|
|
return m_nObjectStreamNum;
|
|
}
|
|
|
|
Object *GetObject(int nObjectIndex, int nObjectNum, Object *pObject);
|
|
|
|
private:
|
|
|
|
int m_nObjectStreamNum; // Ïîðÿäêîâûé íîìåð îáúåêòà(Stream Objects)
|
|
int m_nObjectsCount; // Êîëè÷åñòâî îáúåêòîâ â ïîòîêå
|
|
Object *m_arrObjects; // Ñïèñîê îáúåêòîâ â ïîòîêå
|
|
int *m_arrObjectsNums; // Ïîðÿäêîâûå íîìåðà îáúåêòîâ â ïîòîêå
|
|
|
|
};
|
|
|
|
ObjectStream::ObjectStream(XRef *pXref, int nObjectStreamNum)
|
|
{
|
|
Object oTempObject1, oTempObject2;
|
|
|
|
m_nObjectStreamNum = nObjectStreamNum;
|
|
m_nObjectsCount = 0;
|
|
m_arrObjects = NULL;
|
|
m_arrObjectsNums = NULL;
|
|
|
|
Object oObjectStream;
|
|
if ( !pXref->Fetch( m_nObjectStreamNum, 0, &oObjectStream)->IsStream() )
|
|
{
|
|
oObjectStream.Free();
|
|
return;
|
|
}
|
|
|
|
if ( !oObjectStream.StreamGetDict()->Search("N", &oTempObject1)->IsInt() )
|
|
{
|
|
oTempObject1.Free();
|
|
oObjectStream.Free();
|
|
return;
|
|
}
|
|
m_nObjectsCount = oTempObject1.GetInt();
|
|
oTempObject1.Free();
|
|
|
|
if ( m_nObjectsCount <= 0 )
|
|
{
|
|
oObjectStream.Free();
|
|
return;
|
|
}
|
|
|
|
if ( !oObjectStream.StreamGetDict()->Search("First", &oTempObject1)->IsInt() )
|
|
{
|
|
oTempObject1.Free();
|
|
oObjectStream.Free();
|
|
return;
|
|
}
|
|
|
|
int nFirst = oTempObject1.GetInt();
|
|
oTempObject1.Free();
|
|
|
|
if ( nFirst < 0 )
|
|
{
|
|
oObjectStream.Free();
|
|
return;
|
|
}
|
|
|
|
m_arrObjects = new Object[ m_nObjectsCount ];
|
|
m_arrObjectsNums = (int *)MemUtilsMallocArray( m_nObjectsCount, sizeof(int));
|
|
int *arrnOffsets = (int *)MemUtilsMallocArray( m_nObjectsCount, sizeof(int));
|
|
|
|
oObjectStream.StreamReset();
|
|
oTempObject1.InitNull();
|
|
|
|
Stream *pStream = new EmbedStream( oObjectStream.GetStream(), &oTempObject1, TRUE, nFirst);
|
|
Parser *pParser = new Parser( pXref, new Lexer( pXref, pStream), FALSE);
|
|
for (int nIndex = 0; nIndex < m_nObjectsCount; ++nIndex )
|
|
{
|
|
pParser->GetObject( &oTempObject1 );
|
|
pParser->GetObject( &oTempObject2 );
|
|
|
|
if ( !oTempObject1.IsInt() || !oTempObject2.IsInt() )
|
|
{
|
|
oTempObject1.Free();
|
|
oTempObject2.Free();
|
|
delete pParser;
|
|
MemUtilsFree( arrnOffsets );
|
|
oObjectStream.Free();
|
|
return;
|
|
}
|
|
m_arrObjectsNums[ nIndex ] = oTempObject1.GetInt();
|
|
arrnOffsets[ nIndex ] = oTempObject2.GetInt();
|
|
oTempObject1.Free();
|
|
oTempObject2.Free();
|
|
if ( m_arrObjectsNums[ nIndex ] < 0 || arrnOffsets[ nIndex ] < 0 || ( nIndex > 0 && arrnOffsets[ nIndex ] < arrnOffsets[ nIndex - 1 ] ) )
|
|
{
|
|
delete pParser;
|
|
MemUtilsFree(arrnOffsets);
|
|
oObjectStream.Free();
|
|
return;
|
|
}
|
|
}
|
|
while ( pStream->GetChar() != EOF) ;
|
|
delete pParser;
|
|
|
|
// Ñäâèãàåìñÿ ê íà÷àëó ïåðâîãî îáúåêòà
|
|
for ( int nIndex = nFirst; nIndex < arrnOffsets[0]; ++nIndex )
|
|
{
|
|
oObjectStream.GetStream()->GetChar();
|
|
}
|
|
|
|
for (int nIndex = 0; nIndex < m_nObjectsCount; ++nIndex )
|
|
{
|
|
oTempObject1.InitNull();
|
|
if ( nIndex == m_nObjectsCount - 1)
|
|
{
|
|
pStream = new EmbedStream(oObjectStream.GetStream(), &oTempObject1, FALSE, 0);
|
|
}
|
|
else
|
|
{
|
|
pStream = new EmbedStream(oObjectStream.GetStream(), &oTempObject1, TRUE, arrnOffsets[ nIndex + 1 ] - arrnOffsets[ nIndex ]);
|
|
}
|
|
pParser = new Parser( pXref, new Lexer( pXref, pStream), FALSE);
|
|
pParser->GetObject(&m_arrObjects[ nIndex ]);
|
|
while ( pStream->GetChar() != EOF) ;
|
|
delete pParser;
|
|
}
|
|
|
|
MemUtilsFree(arrnOffsets);
|
|
|
|
oObjectStream.Free();
|
|
return;
|
|
}
|
|
|
|
ObjectStream::~ObjectStream()
|
|
{
|
|
if ( m_arrObjects )
|
|
{
|
|
for ( int nIndex = 0; nIndex < m_nObjectsCount; ++nIndex )
|
|
{
|
|
m_arrObjects[ nIndex ].Free();
|
|
}
|
|
delete[] m_arrObjects;
|
|
}
|
|
MemUtilsFree(m_arrObjectsNums);
|
|
}
|
|
|
|
Object *ObjectStream::GetObject(int nObjectIndex, int nObjectNum, Object *pObject )
|
|
{
|
|
if ( nObjectIndex < 0 || nObjectIndex >= m_nObjectsCount || nObjectNum != m_arrObjectsNums[ nObjectIndex ] )
|
|
{
|
|
return pObject->InitNull();
|
|
}
|
|
return m_arrObjects[ nObjectIndex ].Copy( pObject );
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// XRef
|
|
//------------------------------------------------------------------------
|
|
|
|
XRef::XRef(BaseStream *pStream)
|
|
{
|
|
InitializeCriticalSection(&m_oCS);
|
|
|
|
m_bValidXref = TRUE;
|
|
m_nErrorCode = ErrorNone;
|
|
m_nEntrySize = 0;
|
|
m_arrEntries = NULL;
|
|
m_punStreamEnds = NULL;
|
|
m_nStreamEndsCount = 0;
|
|
m_pObjectStream = NULL;
|
|
|
|
m_bEncrypted = FALSE;
|
|
m_nPermissionFlags = DefaultPermissionFlags;
|
|
m_bOwnerPassword = FALSE;
|
|
|
|
// ×èòàåì Trailer
|
|
m_pStream = pStream;
|
|
m_nStart = m_pStream->GetStartPos();
|
|
unsigned int nPos = GetStartXref();
|
|
|
|
// Åñëè âîçíèêëà ïðîáëåìà ïðè ïîèñêå 'startxref', ïûòàåìñÿ âîññòàíîâèòü
|
|
// òàáëèöó xref
|
|
|
|
if ( 0 == nPos )
|
|
{
|
|
if ( !( m_bValidXref = ConstructXRef() ) )
|
|
{
|
|
m_nErrorCode = ErrorDamaged;
|
|
return;
|
|
}
|
|
}
|
|
else // ÷èòàåì òàáëèöó Xref
|
|
{
|
|
while ( ReadXRef(&nPos) ) ;
|
|
|
|
// Åñëè âîçíèêëà ïðîáëåìà ïðè ïîèñêå 'startxref', ïûòàåìñÿ âîññòàíîâèòü
|
|
// òàáëèöó xref
|
|
if ( !m_bValidXref )
|
|
{
|
|
if ( !( m_bValidXref = ConstructXRef() ) )
|
|
{
|
|
m_nErrorCode = ErrorDamaged;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
Object oTempObject;
|
|
|
|
m_oTrailerDict.DictLookupAndCopy( "Root", &oTempObject);
|
|
if ( oTempObject.IsRef() )
|
|
{
|
|
m_nRootNum = oTempObject.GetRefNum();
|
|
m_nRootGen = oTempObject.GetRefGen();
|
|
oTempObject.Free();
|
|
}
|
|
else
|
|
{
|
|
oTempObject.Free();
|
|
if ( !( m_bValidXref = ConstructXRef() ) )
|
|
{
|
|
m_nErrorCode = ErrorDamaged;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Òåïåðü óñòàíàâëèâàåì â ñëîâàðü Trailer ññûëêó íà òàáëèó xref, ÷òîáû ìû ìîãëè
|
|
// ïî äàííîé òàáëèöå íàõîäèòü êîñâåííûå îáúåêòû
|
|
m_oTrailerDict.GetDict()->SetXRef(this);
|
|
}
|
|
|
|
XRef::~XRef()
|
|
{
|
|
MemUtilsFree(m_arrEntries);
|
|
m_oTrailerDict.Free();
|
|
if (m_punStreamEnds)
|
|
{
|
|
MemUtilsFree(m_punStreamEnds);
|
|
}
|
|
if (m_pObjectStream)
|
|
{
|
|
delete m_pObjectStream;
|
|
}
|
|
|
|
DeleteCriticalSection(&m_oCS);
|
|
}
|
|
|
|
unsigned int XRef::GetStartXref()
|
|
{
|
|
char sBuffer[ XrefSearchSize + 1 ];
|
|
char *pCurChar;
|
|
int nChar = 0, nPos = 0, nCur = 0;
|
|
|
|
// ñ÷èòûâàåì ïîñëåäíèå xrefSearchSize áàéò
|
|
m_pStream->SetPos( XrefSearchSize, -1);
|
|
for ( nPos = 0; nPos < XrefSearchSize; ++nPos )
|
|
{
|
|
if ( ( nChar = m_pStream->GetChar() ) == EOF)
|
|
{
|
|
break;
|
|
}
|
|
sBuffer[ nPos ] = nChar;
|
|
}
|
|
sBuffer[ nPos ] = '\0';
|
|
|
|
// èùåì startxref
|
|
for ( nCur = nPos - 9; nCur >= 0; --nCur )
|
|
{
|
|
if ( !strncmp( &sBuffer[ nCur ], "startxref", 9 ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if ( nCur < 0 )
|
|
return 0;
|
|
|
|
for ( pCurChar = &sBuffer[ nCur + 9 ]; isspace(*pCurChar); ++pCurChar ) ;
|
|
|
|
m_unLastXRefOffset = StrintToUInt( pCurChar );
|
|
|
|
return m_unLastXRefOffset;
|
|
}
|
|
|
|
// Ñ÷èòûâàåì îäíó ñåêöèþ òàáëèöû Xref. Òàêæå ñ÷èòûâàåì ñîîòâåòñòâóþùèé ñëîâàðü Trailer
|
|
// è âîçâðàùàåì óêàçàòåëü íà ïðåäûäóùèé.
|
|
BOOL XRef::ReadXRef(unsigned int *punPos)
|
|
{
|
|
Object oObject;
|
|
BOOL bResult = TRUE;
|
|
|
|
oObject.InitNull();
|
|
Parser *pParser = new Parser( NULL, new Lexer(NULL, m_pStream->MakeSubStream( m_nStart + *punPos, FALSE, 0, &oObject ) ), TRUE );
|
|
pParser->GetObject( &oObject );
|
|
|
|
// Ïàðñèì òàáëèöó xref â ñòàðîé ôîðìå
|
|
if ( oObject.IsCommand("xref") )
|
|
{
|
|
oObject.Free();
|
|
bResult = ReadXRefTable( pParser, punPos);
|
|
}
|
|
// Ïàðñèì òàáëèöó xref, êîãäà îíà çàïèñàíà â âèäå ïîòîêà
|
|
else if ( oObject.IsInt() )
|
|
{
|
|
oObject.Free();
|
|
if ( !pParser->GetObject( &oObject )->IsInt() )
|
|
{
|
|
oObject.Free();
|
|
delete pParser;
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
oObject.Free();
|
|
if ( !pParser->GetObject( &oObject )->IsCommand("obj") )
|
|
{
|
|
oObject.Free();
|
|
delete pParser;
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
oObject.Free();
|
|
if ( !pParser->GetObject( &oObject )->IsStream() )
|
|
{
|
|
oObject.Free();
|
|
delete pParser;
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
bResult = ReadXRefStream( oObject.GetStream(), punPos);
|
|
oObject.Free();
|
|
|
|
}
|
|
else
|
|
{
|
|
oObject.Free();
|
|
delete pParser;
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
delete pParser;
|
|
return bResult;
|
|
}
|
|
|
|
BOOL XRef::ReadXRefTable(Parser *pParser, unsigned int *punPos)
|
|
{
|
|
Object oTempObject;
|
|
|
|
while (1)
|
|
{
|
|
// ñíà÷àëà â ñåêöèè èäóò íîìåð ïåðâîãî îáúåêòà è êîëè÷åñòâî îáúåêòîâ
|
|
pParser->GetObject( &oTempObject );
|
|
if ( oTempObject.IsCommand("trailer") )
|
|
{
|
|
oTempObject.Free();
|
|
break;
|
|
}
|
|
if ( !oTempObject.IsInt() )
|
|
{
|
|
oTempObject.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
int nFirst = oTempObject.GetInt();
|
|
oTempObject.Free();
|
|
if ( !pParser->GetObject( &oTempObject )->IsInt() )
|
|
{
|
|
oTempObject.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
int nCount = oTempObject.GetInt();
|
|
oTempObject.Free();
|
|
|
|
if ( nFirst < 0 || nCount < 0 || nFirst + nCount < 0 )
|
|
{
|
|
oTempObject.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
if ( nFirst + nCount > m_nEntrySize )
|
|
{
|
|
int nNewSize = 0;
|
|
for ( nNewSize = m_nEntrySize ? 2 * m_nEntrySize : 1024; nFirst + nCount > nNewSize && nNewSize > 0; nNewSize <<= 1) ;
|
|
if ( nNewSize < 0 )
|
|
{
|
|
oTempObject.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
m_arrEntries = (XRefEntry *)MemUtilsReallocArray( m_arrEntries, nNewSize, sizeof(XRefEntry));
|
|
for (int nIndex = m_nEntrySize; nIndex < nNewSize; ++nIndex )
|
|
{
|
|
m_arrEntries[nIndex].unOffset = 0xffffffff;
|
|
m_arrEntries[nIndex].eType = xrefEntryFree;
|
|
}
|
|
m_nEntrySize = nNewSize;
|
|
}
|
|
for (int nIndex = nFirst; nIndex < nFirst + nCount; ++nIndex )
|
|
{
|
|
// ôîðìàò: nnnnnnnnnn ggggg n eol
|
|
// nnnnnnnnnn - áàéòîâûé ñäâèã
|
|
// ggggg - Generation number(íîìåð âåðñèè îáúåêòà)
|
|
// n - Êëþ÷, îïðåäåëÿþùèé èñïîëüçóåòñÿ ëè îáúåêò
|
|
// eol - Êîíåö ñòðîêè(äâà ñèìâîëà)
|
|
if ( !pParser->GetObject( &oTempObject )->IsInt() )
|
|
{
|
|
oTempObject.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
XRefEntry oEntry;
|
|
oEntry.unOffset = (unsigned int)oTempObject.GetInt();
|
|
oTempObject.Free();
|
|
if ( !pParser->GetObject(&oTempObject)->IsInt() )
|
|
{
|
|
oTempObject.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
oEntry.nGen = oTempObject.GetInt();
|
|
oTempObject.Free();
|
|
pParser->GetObject( &oTempObject );
|
|
if ( oTempObject.IsCommand("n") )
|
|
{
|
|
oEntry.eType = xrefEntryUncompressed;
|
|
}
|
|
else if ( oTempObject.IsCommand("f") )
|
|
{
|
|
oEntry.eType = xrefEntryFree;
|
|
}
|
|
else
|
|
{
|
|
oTempObject.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
oTempObject.Free();
|
|
if ( m_arrEntries[ nIndex ].unOffset == 0xffffffff )
|
|
{
|
|
m_arrEntries[ nIndex ] = oEntry;
|
|
// â PDF ôàéëàõ, ñîçäàííûõ ñ ïîìîùüþ Intellectual Property
|
|
// Network, èìååòñÿ áàã: òàáëèöà Xref íà÷èíàåòñÿ ñ îáúåêòà
|
|
// ïîä íîìåðîì 1, âìåñòî 0.
|
|
if ( nIndex == 1 && nFirst == 1 && m_arrEntries[1].unOffset == 0 && m_arrEntries[1].nGen == 65535 && m_arrEntries[1].eType == xrefEntryFree )
|
|
{
|
|
nIndex = nFirst = 0;
|
|
m_arrEntries[0] = m_arrEntries[1];
|
|
m_arrEntries[1].unOffset = 0xffffffff;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ×èòàåì ñëîâàðü Trailer
|
|
if ( !pParser->GetObject( &oTempObject )->IsDict() )
|
|
{
|
|
oTempObject.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
// Ñ÷èòûâàåì óêàçàòåëü 'Prev'
|
|
Object oPrev;
|
|
BOOL bPrev = FALSE;
|
|
oTempObject.GetDict()->SearchAndCopy("Prev", &oPrev);
|
|
if ( oPrev.IsInt() )
|
|
{
|
|
*punPos = (unsigned int)oPrev.GetInt();
|
|
bPrev = TRUE;
|
|
}
|
|
else if ( oPrev.IsRef() )
|
|
{
|
|
// Íåêîòîðûå ïðîãðàììû ïèøóò "/Prev NNN 0 R" âìåñòî "/Prev NNN"
|
|
*punPos = (unsigned int)oPrev.GetRefNum();
|
|
bPrev = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bPrev = FALSE;
|
|
}
|
|
oPrev.Free();
|
|
|
|
// Ñîõðàíÿåì ïåðâûé ñëîâàðü Trailer
|
|
if ( m_oTrailerDict.IsNone() )
|
|
{
|
|
oTempObject.Copy( &m_oTrailerDict );
|
|
}
|
|
|
|
// Ïðîâåðÿåì åñòü ëè ýëåìåíò 'XRefStm'
|
|
if ( oTempObject.GetDict()->Search("XRefStm", &oPrev)->IsInt() )
|
|
{
|
|
unsigned int unPos2 = (unsigned int)oPrev.GetInt();
|
|
ReadXRef( &unPos2 );
|
|
if ( !m_bValidXref )
|
|
{
|
|
oPrev.Free();
|
|
oTempObject.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
oPrev.Free();
|
|
|
|
oTempObject.Free();
|
|
return bPrev;
|
|
}
|
|
|
|
BOOL XRef::ReadXRefStream(Stream *pXrefStream, unsigned int *punPos)
|
|
{
|
|
int arrW[3];
|
|
|
|
Dict *pDict = pXrefStream->GetDict();
|
|
Object oTemp;
|
|
|
|
if ( !pDict->SearchAndCopy("Size", &oTemp)->IsInt() )
|
|
{
|
|
oTemp.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
int nNewSize = oTemp.GetInt();
|
|
oTemp.Free();
|
|
|
|
if ( nNewSize < 0 )
|
|
{
|
|
oTemp.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
if ( nNewSize > m_nEntrySize )
|
|
{
|
|
m_arrEntries = (XRefEntry *)MemUtilsReallocArray( m_arrEntries, nNewSize, sizeof(XRefEntry));
|
|
for ( int nIndex = m_nEntrySize; nIndex < nNewSize; ++nIndex )
|
|
{
|
|
m_arrEntries[nIndex].unOffset = 0xffffffff;
|
|
m_arrEntries[nIndex].eType = xrefEntryFree;
|
|
}
|
|
m_nEntrySize = nNewSize;
|
|
}
|
|
|
|
if ( !pDict->SearchAndCopy("W", &oTemp)->IsArray() || oTemp.ArrayGetLength() < 3 )
|
|
{
|
|
oTemp.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
for ( int nIndex = 0; nIndex < 3; ++nIndex )
|
|
{
|
|
Object oWItem;
|
|
if ( !oTemp.ArrayGet( nIndex, &oWItem)->IsInt() )
|
|
{
|
|
oWItem.Free();
|
|
oTemp.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
arrW[nIndex] = oWItem.GetInt();
|
|
oWItem.Free();
|
|
if ( arrW[nIndex] < 0 || arrW[nIndex] > 4 )
|
|
{
|
|
oTemp.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
oTemp.Free();
|
|
|
|
pXrefStream->Reset();
|
|
Object oIndex;
|
|
pDict->SearchAndCopy("Index", &oIndex);
|
|
|
|
if ( oIndex.IsArray() )
|
|
{
|
|
for (int nIndex = 0; nIndex + 1 < oIndex.ArrayGetLength(); nIndex += 2)
|
|
{
|
|
if ( !oIndex.ArrayGet( nIndex, &oTemp)->IsInt() )
|
|
{
|
|
oIndex.Free();
|
|
oTemp.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
int nFirst = oTemp.GetInt();
|
|
oTemp.Free();
|
|
if ( !oIndex.ArrayGet( nIndex + 1, &oTemp)->IsInt() )
|
|
{
|
|
oIndex.Free();
|
|
oTemp.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
int nCount = oTemp.GetInt();
|
|
oTemp.Free();
|
|
if ( nFirst < 0 || nCount < 0 || !ReadXRefStreamSection( pXrefStream, arrW, nFirst, nCount) )
|
|
{
|
|
oIndex.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !ReadXRefStreamSection( pXrefStream, arrW, 0, nNewSize) )
|
|
{
|
|
oIndex.Free();
|
|
m_bValidXref = FALSE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
oIndex.Free();
|
|
|
|
pDict->SearchAndCopy("Prev", &oTemp);
|
|
BOOL bPrev = FALSE;
|
|
if ( oTemp.IsInt() )
|
|
{
|
|
*punPos = (unsigned int)oTemp.GetInt();
|
|
bPrev = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bPrev = FALSE;
|
|
}
|
|
oTemp.Free();
|
|
if ( m_oTrailerDict.IsNone() )
|
|
{
|
|
m_oTrailerDict.InitDict( pDict );
|
|
}
|
|
|
|
return bPrev;
|
|
}
|
|
|
|
BOOL XRef::ReadXRefStreamSection(Stream *pXrefStream, int *arrW, int nFirst, int nCount)
|
|
{
|
|
if ( nFirst + nCount < 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ( nFirst + nCount > m_nEntrySize )
|
|
{
|
|
int nNewSize = 0;
|
|
for ( nNewSize = m_nEntrySize ? 2 * m_nEntrySize : 1024; nFirst + nCount > nNewSize && nNewSize > 0; nNewSize <<= 1) ;
|
|
if ( nNewSize < 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
m_arrEntries = (XRefEntry *)MemUtilsReallocArray( m_arrEntries, nNewSize, sizeof(XRefEntry));
|
|
for ( int nIndex = m_nEntrySize; nIndex < nNewSize; ++nIndex )
|
|
{
|
|
m_arrEntries[nIndex].unOffset = 0xffffffff;
|
|
m_arrEntries[nIndex].eType = xrefEntryFree;
|
|
}
|
|
m_nEntrySize = nNewSize;
|
|
}
|
|
for ( int nIndex = nFirst; nIndex < nFirst + nCount; ++nIndex )
|
|
{
|
|
int nType = -1;
|
|
int nChar = 0, nGen = 0, nJ = 0;
|
|
unsigned int unOffset = 0;
|
|
if ( arrW[0] == 0 )
|
|
{
|
|
nType = 1;
|
|
}
|
|
else
|
|
{
|
|
for ( nType = 0, nJ = 0; nJ < arrW[0]; ++nJ )
|
|
{
|
|
if ( ( nChar = pXrefStream->GetChar() ) == EOF )
|
|
{
|
|
return FALSE;
|
|
}
|
|
nType = (nType << 8) + nChar;
|
|
}
|
|
}
|
|
for ( unOffset = 0, nJ = 0; nJ < arrW[1]; ++nJ )
|
|
{
|
|
if ( ( nChar = pXrefStream->GetChar() ) == EOF )
|
|
{
|
|
return FALSE;
|
|
}
|
|
unOffset = (unOffset << 8) + nChar;
|
|
}
|
|
for ( nGen = 0, nJ = 0; nJ < arrW[2]; ++nJ )
|
|
{
|
|
if ( ( nChar = pXrefStream->GetChar() ) == EOF )
|
|
{
|
|
return FALSE;
|
|
}
|
|
nGen = (nGen << 8) + nChar;
|
|
}
|
|
if ( m_arrEntries[nIndex].unOffset == 0xffffffff )
|
|
{
|
|
switch (nType)
|
|
{
|
|
case 0:
|
|
m_arrEntries[nIndex].unOffset = unOffset;
|
|
m_arrEntries[nIndex].nGen = nGen;
|
|
m_arrEntries[nIndex].eType = xrefEntryFree;
|
|
break;
|
|
case 1:
|
|
m_arrEntries[nIndex].unOffset = unOffset;
|
|
m_arrEntries[nIndex].nGen = nGen;
|
|
m_arrEntries[nIndex].eType = xrefEntryUncompressed;
|
|
break;
|
|
case 2:
|
|
m_arrEntries[nIndex].unOffset = unOffset;
|
|
m_arrEntries[nIndex].nGen = nGen;
|
|
m_arrEntries[nIndex].eType = xrefEntryCompressed;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Ïðîáóåì ïîñòðîèòü òàáëèöó Xref äëÿ ïîâðåæäåííîãî ôàéëà.
|
|
BOOL XRef::ConstructXRef()
|
|
{
|
|
BOOL bGetRoot = FALSE;
|
|
|
|
MemUtilsFree( m_arrEntries );
|
|
m_nEntrySize = 0;
|
|
m_arrEntries = NULL;
|
|
|
|
// TO DO : Error "PDF file is damaged - attempting to reconstruct xref table..."
|
|
m_nStreamEndsCount = 0;
|
|
|
|
int nStreamEndsSize = 0;
|
|
|
|
m_pStream->Reset();
|
|
|
|
while (1)
|
|
{
|
|
unsigned int nPos = m_pStream->GetPos();
|
|
char sBuffer[256];
|
|
if ( !m_pStream->GetLine( sBuffer, 256) )
|
|
{
|
|
break;
|
|
}
|
|
BYTE *pCur = (BYTE*)sBuffer;
|
|
|
|
// Ïðîïóñêàåì ïðîáåëû
|
|
while ( *pCur && Lexer::IsSpace(*pCur & 0xff) ) ++pCur;
|
|
|
|
// C÷èòûâàåì ñëîâàðü Trailer
|
|
if ( !strncmp( (char*)pCur, "trailer", 7) )
|
|
{
|
|
Object oTemp;
|
|
oTemp.InitNull();
|
|
Parser *pParser = new Parser( NULL, new Lexer( NULL, m_pStream->MakeSubStream( nPos + 7, FALSE, 0, &oTemp ) ), FALSE);
|
|
Object oNewTrailerDict;
|
|
pParser->GetObject( &oNewTrailerDict );
|
|
if ( oNewTrailerDict.IsDict() )
|
|
{
|
|
oNewTrailerDict.DictLookupAndCopy("Root", &oTemp);
|
|
if ( oTemp.IsRef() )
|
|
{
|
|
m_nRootNum = oTemp.GetRefNum();
|
|
m_nRootGen = oTemp.GetRefGen();
|
|
if ( !m_oTrailerDict.IsNone() )
|
|
{
|
|
m_oTrailerDict.Free();
|
|
}
|
|
oNewTrailerDict.Copy( &m_oTrailerDict );
|
|
bGetRoot = TRUE;
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
oNewTrailerDict.Free();
|
|
delete pParser;
|
|
}
|
|
else if ( isdigit( *pCur ) ) // Èùåì îáúåêò
|
|
{
|
|
int nNum = atoi( (char*)pCur );
|
|
if ( nNum > 0 )
|
|
{
|
|
do {
|
|
++pCur;
|
|
} while (*pCur && isdigit( *pCur ));
|
|
if ( isspace(*pCur) )
|
|
{
|
|
do {
|
|
++pCur;
|
|
} while (*pCur && isspace( *pCur ));
|
|
if (isdigit(*pCur))
|
|
{
|
|
int nGen = atoi( (char*)pCur );
|
|
do {
|
|
++pCur;
|
|
} while (*pCur && isdigit( *pCur ));
|
|
if (isspace(*pCur))
|
|
{
|
|
do {
|
|
++pCur;
|
|
} while (*pCur && isspace( *pCur ));
|
|
if ( !strncmp( (char*)pCur, "obj", 3) )
|
|
{
|
|
if ( nNum >= m_nEntrySize )
|
|
{
|
|
int nNewSize = ( nNum + 1 + 255) & ~255;
|
|
if ( nNewSize < 0 )
|
|
{
|
|
// TO DO: Error "Bad object number"
|
|
return FALSE;
|
|
}
|
|
m_arrEntries = (XRefEntry *) MemUtilsReallocArray( m_arrEntries, nNewSize, sizeof(XRefEntry));
|
|
for (int nIndex = m_nEntrySize; nIndex < nNewSize; ++nIndex)
|
|
{
|
|
m_arrEntries[ nIndex ].unOffset = 0xffffffff;
|
|
m_arrEntries[ nIndex ].eType = xrefEntryFree;
|
|
}
|
|
m_nEntrySize = nNewSize;
|
|
}
|
|
if (m_arrEntries[ nNum ].eType == xrefEntryFree || nGen >= m_arrEntries[ nNum ].nGen )
|
|
{
|
|
m_arrEntries[ nNum ].unOffset = nPos - m_nStart;
|
|
m_arrEntries[ nNum ].nGen = nGen;
|
|
m_arrEntries[ nNum ].eType = xrefEntryUncompressed;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
else if (!strncmp( (char*)pCur, "endstream", 9))
|
|
{
|
|
if ( m_nStreamEndsCount == nStreamEndsSize )
|
|
{
|
|
nStreamEndsSize += 64;
|
|
m_punStreamEnds = (unsigned int *)MemUtilsReallocArray( m_punStreamEnds, nStreamEndsSize, sizeof(int) );
|
|
}
|
|
m_punStreamEnds[m_nStreamEndsCount++] = nPos;
|
|
}
|
|
}
|
|
|
|
if ( bGetRoot )
|
|
return TRUE;
|
|
|
|
// TO DO: Error "Couldn't find trailer dictionary"
|
|
return FALSE;
|
|
}
|
|
|
|
void XRef::SetEncryption(int nPermissionFlags, BOOL bOwnerPassword, unsigned char *sDecryptKey, int nKeyLength, int nEncryptVersion, CryptAlgorithm eEncryptAlgorithm)
|
|
{
|
|
m_bEncrypted = TRUE;
|
|
m_nPermissionFlags = nPermissionFlags;
|
|
m_bOwnerPassword = bOwnerPassword;
|
|
if ( nKeyLength <= 16 )
|
|
{
|
|
m_nKeyLength = nKeyLength;
|
|
}
|
|
else
|
|
{
|
|
m_nKeyLength = 16;
|
|
}
|
|
for ( int nIndex = 0; nIndex < m_nKeyLength; ++nIndex )
|
|
{
|
|
m_arrDecryptKey[nIndex] = sDecryptKey[nIndex];
|
|
}
|
|
m_nEncryptVersion = nEncryptVersion;
|
|
m_eEncryptAlgorithm = eEncryptAlgorithm;
|
|
}
|
|
|
|
BOOL XRef::CheckPrint(BOOL bIgnoreOwnerPassword)
|
|
{
|
|
return ( !bIgnoreOwnerPassword && m_bOwnerPassword ) || ( m_nPermissionFlags & PermissionPrint );
|
|
}
|
|
|
|
BOOL XRef::CheckChange(BOOL bIgnoreOwnerPassword)
|
|
{
|
|
return ( !bIgnoreOwnerPassword && m_bOwnerPassword ) || ( m_nPermissionFlags & PermissionChange );
|
|
}
|
|
|
|
BOOL XRef::CheckCopy(BOOL bIgnoreOwnerPassword)
|
|
{
|
|
return ( !bIgnoreOwnerPassword && m_bOwnerPassword ) || ( m_nPermissionFlags & PermissionCopy );
|
|
}
|
|
|
|
BOOL XRef::CheckAddNotes(BOOL bIgnoreOwnerPassword)
|
|
{
|
|
return ( !bIgnoreOwnerPassword && m_bOwnerPassword ) || ( m_nPermissionFlags & PermissionNotes );
|
|
}
|
|
|
|
Object *XRef::Fetch(int nNum, int nGen, Object *pObject)
|
|
{
|
|
CTemporaryCS oCS( &m_oCS );
|
|
|
|
Object oObjNum, oObjGen, oObjContent;
|
|
|
|
if ( nNum < 0 || nNum >= m_nEntrySize )
|
|
{
|
|
return pObject->InitNull();
|
|
}
|
|
Parser *pParser = NULL;
|
|
XRefEntry *pEntry = &m_arrEntries[nNum];
|
|
switch ( pEntry->eType )
|
|
{
|
|
case xrefEntryUncompressed:
|
|
if ( pEntry->nGen != nGen )
|
|
{
|
|
return pObject->InitNull();
|
|
}
|
|
oObjNum.InitNull();
|
|
pParser = new Parser( this, new Lexer(this, m_pStream->MakeSubStream( m_nStart + pEntry->unOffset, FALSE, 0, &oObjNum ) ), TRUE);
|
|
pParser->GetObject( &oObjNum );
|
|
pParser->GetObject( &oObjGen );
|
|
pParser->GetObject( &oObjContent );
|
|
if ( !oObjNum.IsInt() || oObjNum.GetInt() != nNum || !oObjGen.IsInt() || oObjGen.GetInt() != nGen || !oObjContent.IsCommand("obj") )
|
|
{
|
|
oObjNum.Free();
|
|
oObjGen.Free();
|
|
oObjContent.Free();
|
|
delete pParser;
|
|
return pObject->InitNull();
|
|
}
|
|
pParser->GetObject( pObject, m_bEncrypted ? m_arrDecryptKey : (unsigned char *)NULL, m_eEncryptAlgorithm, m_nKeyLength, nNum, nGen );
|
|
oObjNum.Free();
|
|
oObjGen.Free();
|
|
oObjContent.Free();
|
|
delete pParser;
|
|
break;
|
|
|
|
case xrefEntryCompressed:
|
|
if ( nGen != 0 )
|
|
{
|
|
return pObject->InitNull();
|
|
}
|
|
if ( !m_pObjectStream || m_pObjectStream->GetObjectStreamNum() != (int)pEntry->unOffset )
|
|
{
|
|
if (m_pObjectStream)
|
|
{
|
|
delete m_pObjectStream;
|
|
}
|
|
m_pObjectStream = new ObjectStream( this, pEntry->unOffset );
|
|
}
|
|
m_pObjectStream->GetObject( pEntry->nGen, nNum, pObject);
|
|
break;
|
|
|
|
default:
|
|
return pObject->InitNull();
|
|
}
|
|
|
|
return pObject;
|
|
}
|
|
|
|
Object *XRef::GetDocInfo(Object *pObject)
|
|
{
|
|
CTemporaryCS oCS( &m_oCS );
|
|
|
|
return m_oTrailerDict.DictLookup( "Info", pObject);
|
|
}
|
|
Object *XRef::GetDocInfoCopy(Object *pObject)
|
|
{
|
|
CTemporaryCS oCS( &m_oCS );
|
|
|
|
return m_oTrailerDict.DictLookupAndCopy( "Info", pObject);
|
|
}
|
|
|
|
BOOL XRef::GetStreamEnd(unsigned int nStreamStart, unsigned int *pnStreamEnd)
|
|
{
|
|
if ( m_nStreamEndsCount == 0 || nStreamStart > m_punStreamEnds[m_nStreamEndsCount - 1] )
|
|
return FALSE;
|
|
|
|
int nStart = -1;
|
|
int nEnd = m_nStreamEndsCount - 1;
|
|
// m_punStreamEnds[ nStart ] < streamStart <= m_punStreamEnds[ nEnd ]
|
|
while ( nEnd - nStart > 1 )
|
|
{
|
|
int nMid = ( nStart + nEnd) / 2;
|
|
if ( nStreamStart <= m_punStreamEnds[ nMid ] )
|
|
{
|
|
nEnd = nMid;
|
|
}
|
|
else
|
|
{
|
|
nStart = nMid;
|
|
}
|
|
}
|
|
*pnStreamEnd = m_punStreamEnds[ nEnd ];
|
|
return TRUE;
|
|
}
|
|
|
|
unsigned int XRef::StrintToUInt(char *sString)
|
|
{
|
|
char *pCur;
|
|
int nIndex = 0;
|
|
|
|
unsigned int unRes = 0;
|
|
for ( pCur = sString, nIndex = 0; *pCur && isdigit(*pCur) && nIndex < 10; ++pCur, ++nIndex )
|
|
{
|
|
unRes = 10 * unRes + (*pCur - '0');
|
|
}
|
|
return unRes;
|
|
}
|