mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-11 02:44:13 +08:00
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@62550 954022d7-b5bf-4e40-9824-e11837661b57
1038 lines
26 KiB
C++
1038 lines
26 KiB
C++
#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 "../../DesktopEditor/graphics/TemporaryCS.h"
|
||
|
||
namespace PdfReader
|
||
{
|
||
#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)
|
||
{
|
||
m_oCS.InitializeCriticalSection();
|
||
|
||
m_bValidXref = true;
|
||
m_eErrorCode = 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_eErrorCode = errorDamaged;
|
||
return;
|
||
}
|
||
}
|
||
else // читаем таблицу Xref
|
||
{
|
||
while (ReadXRef(&nPos));
|
||
|
||
// Если возникла проблема при поиске 'startxref', пытаемся восстановить
|
||
// таблицу xref
|
||
if (!m_bValidXref)
|
||
{
|
||
if (!(m_bValidXref = ConstructXRef()))
|
||
{
|
||
m_eErrorCode = 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_eErrorCode = 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;
|
||
}
|
||
|
||
m_oCS.DeleteCriticalSection();
|
||
}
|
||
|
||
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;
|
||
}
|
||
unsigned char *pCur = (unsigned char*)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;
|
||
}
|
||
} |