Files
core/PdfReader/Src/PDFDoc.cpp
Ilya.Kirillov eb965c1d6d Добавлен новый проект PdfReader для кроссплатформенного чтения Pdf.
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@62480 954022d7-b5bf-4e40-9824-e11837661b57
2016-05-21 00:01:53 +03:00

309 lines
8.1 KiB
C++

#include "../../DesktopEditor/common/File.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "StringExt.h"
#include "Constants.h"
#include "GlobalParams.h"
#include "Page.h"
#include "Catalog.h"
#include "Stream.h"
#include "XRef.h"
#include "Link.h"
#include "OutputDevice.h"
#include "ErrorConstants.h"
#include "Lexer.h"
#include "Parser.h"
#include "SecurityHandler.h"
#include "Outline.h"
#include "PDFDoc.h"
#define HeaderSearchSize 1024 // Ìàêñèìàëüíîå êîëè÷åñòâî áàéò äëÿ ñ÷èòûâàíèÿ ñ íà÷àëà ôàéëà, â êîòîðûõ ìû èùåì çàïèñü '%PDF'
namespace PdfReader
{
//-------------------------------------------------------------------------------------------------------------------------------
// PDFDoc
//-------------------------------------------------------------------------------------------------------------------------------
PDFDoc::PDFDoc(GlobalParams *pGlobalParams, const wchar_t* wsFileName, StringExt *seOwnerPassword, StringExt *seUserPassword)
{
m_pGlobalParams = pGlobalParams;
m_bValid = false;
m_eErrorCode = errorNone;
m_pFile = NULL;
m_pFileBuffer = NULL;
m_pStream = NULL;
m_pXref = NULL;
m_pCatalog = NULL;
m_pOutline = NULL;
m_wsFileName = wsFileName;
NSFile::CFileBinary oFile;
oFile.OpenFile(wsFileName);
long lFileSize = oFile.GetFileSize();
m_pFileBuffer = new unsigned char[lFileSize];
if (!m_pFileBuffer)
{
// Íå ñìîãëè âûäåëèòü ïàìÿòü ïîä âåñü ôàéë, òîãäà ðàáîòàåì íåïîñðåäñòâåííî ñ ñàìèì ôàéëîì
m_pFileBuffer = NULL;
m_pFile = oFile.GetFileNative();
// Ñîçäàåì ïîòîê
Object oTemp;
oTemp.InitNull();
m_pStream = new FileStream(m_pFile, 0, false, 0, &oTemp);
}
else
{
DWORD lReadedSize;
DWORD lTotallReadedSize = 0;
DWORD lCounter = 0;
while (lTotallReadedSize != lFileSize)
{
oFile.ReadFile(m_pFileBuffer + lTotallReadedSize, lFileSize - lTotallReadedSize, lReadedSize);
lTotallReadedSize += lReadedSize;
lCounter++;
if (lCounter > 0x0FFFFFFF)
{
lTotallReadedSize = 0;
break;
}
}
oFile.CloseFile();
if (lTotallReadedSize != lFileSize)
{
m_pFileBuffer = NULL;
m_bValid = false;
return;
}
// Ñîçäàåì ïîòîê
Object oTemp;
oTemp.InitNull();
m_pStream = new MemoryStream((char*)m_pFileBuffer, 0, lFileSize, &oTemp);
}
if (!m_pStream)
m_bValid = false;
m_bValid = Setup(seOwnerPassword, seUserPassword);
}
bool PDFDoc::Setup(StringExt *seOwnerPassword, StringExt *seUserPassword)
{
m_pStream->Reset();
// Ïðîâåðÿåì çàãîëîâîê PDF ôàéëà
CheckHeader();
// Ñ÷èòûâàåì òàáëèöó Xref
m_pXref = new XRef(m_pStream);
if (!m_pXref->CheckValidate())
{
// TO DO: Error "Couldn't read xref table"
m_eErrorCode = (EError)m_pXref->GetErrorCode();
return false;
}
// Ïðîâåðÿåì çàøèôðîâàí ëè äîêóìåíò
if (!CheckEncryption(seOwnerPassword, seUserPassword))
{
m_eErrorCode = errorEncrypted;
return false;
}
// Ñ÷èòûâàåì îáúåêò Catalog
m_pCatalog = new Catalog(m_pGlobalParams, m_pXref);
if (!m_pCatalog->CheckValidation())
{
// TO DO: Error "Couldn't read page catalog"
m_eErrorCode = errorBadCatalog;
return false;
}
// Ñ÷èòûâàåì îáúåêò Outline
m_pOutline = new Outline(m_pCatalog->GetOutline(), m_pXref);
return true;
}
PDFDoc::~PDFDoc()
{
if (m_pOutline)
{
delete m_pOutline;
}
if (m_pCatalog)
{
delete m_pCatalog;
}
if (m_pXref)
{
delete m_pXref;
}
if (m_pStream)
{
delete m_pStream;
}
if (m_pFileBuffer)
{
delete[] m_pFileBuffer;
}
if (m_pFile)
{
fclose(m_pFile);
}
}
void PDFDoc::CheckHeader()
{
char hdrBuf[HeaderSearchSize + 1];
char *p;
int nIndex = 0;
m_dPDFVersion = 0;
for (nIndex = 0; nIndex < HeaderSearchSize; ++nIndex)
{
hdrBuf[nIndex] = m_pStream->GetChar();
}
hdrBuf[HeaderSearchSize] = '\0';
for (nIndex = 0; nIndex < HeaderSearchSize - 5; ++nIndex)
{
if (!strncmp(&hdrBuf[nIndex], "%PDF-", 5))
{
break;
}
}
if (nIndex >= HeaderSearchSize - 5)
{
// TO DO: Error "May not be a PDF file"
return;
}
m_pStream->SetStartPos(nIndex);
if (!(p = strtok(&hdrBuf[nIndex + 5], " \t\n\r")))
{
// TO DO: Error "May not be a PDF file"
return;
}
m_dPDFVersion = atof(p);
if (!(hdrBuf[nIndex + 5] >= '0' && hdrBuf[nIndex + 5] <= '9') || m_dPDFVersion > SupportedPDFVersionNum + 0.0001)
{
// TO DO: Error "Unsupported PDF version"
}
}
bool PDFDoc::CheckEncryption(StringExt *ownerPassword, StringExt *userPassword)
{
bool bEncrypted = false;
bool bResult = true;
Object oEncypt;
m_pXref->GetTrailerDict()->DictLookup("Encrypt", &oEncypt);
if ((bEncrypted = oEncypt.IsDict()))
{
SecurityHandler *pSecurityHandler = NULL;
if ((pSecurityHandler = SecurityHandler::Make(this, &oEncypt)))
{
if (pSecurityHandler->CheckEncryption(ownerPassword, userPassword))
{
// Àâòîðèçàöèÿ ïðîéäåíà
m_pXref->SetEncryption(pSecurityHandler->GetPermissionFlags(), pSecurityHandler->GetOwnerPasswordValid(), pSecurityHandler->GetFileKey(), pSecurityHandler->GetFileKeyLength(), pSecurityHandler->GetEncodingVersion(), pSecurityHandler->GetEncodingAlgorithm());
bResult = true;
}
else
{
// Àâòîðèçàöèÿ íå ïðîéäåíà
bResult = false;
}
delete pSecurityHandler;
}
else
{
bResult = false;
}
}
else
{
// Äàííûé PDF ôàéë íå çàøèôðîâàí
bResult = true;
}
oEncypt.Free();
return bResult;
}
void PDFDoc::DisplayPage(OutputDev *pOut, int nPageIndex, double dHorDPI, double dVerDPI, int nRotate, bool bUseMediaBox, bool bCrop, bool bPrinting, bool(*pAbortCheckCbk)(void *pData), void *pAbortCheckCbkData)
{
m_pCatalog->GetPage(nPageIndex)->Display(pOut, dHorDPI, dVerDPI, nRotate, bUseMediaBox, bCrop, bPrinting, m_pCatalog, pAbortCheckCbk, pAbortCheckCbkData);
}
void PDFDoc::DisplayPages(OutputDev *pOut, int nFirstPageIndex, int nLastPageIndex, double dHorDPI, double dVerDPI, int nRotate, bool bUseMediaBox, bool bCrop, bool bPrinting, bool(*pAbortCheckCbk)(void *pData), void *pAbortCheckCbkData)
{
for (int nPageIndex = nFirstPageIndex; nPageIndex <= nLastPageIndex; ++nPageIndex)
{
DisplayPage(pOut, nPageIndex, dHorDPI, dVerDPI, nRotate, bUseMediaBox, bCrop, bPrinting, pAbortCheckCbk, pAbortCheckCbkData);
}
}
void PDFDoc::DisplayPageSlice(OutputDev *pOut, int nPageIndex, double dHorDPI, double dVerDPI, int nRotate, bool bUseMediaBox, bool bCrop, bool bPrinting, int nSliceX, int nSliceY, int nSliceW, int nSliceH, bool(*pAbortCheckCbk)(void *pData), void *pAbortCheckCbkData)
{
m_pCatalog->GetPage(nPageIndex)->DisplaySlice(pOut, dHorDPI, dVerDPI, nRotate, bUseMediaBox, bCrop, nSliceX, nSliceY, nSliceW, nSliceH, bPrinting, m_pCatalog, pAbortCheckCbk, pAbortCheckCbkData);
}
Links *PDFDoc::GetLinks(int nPageIndex)
{
return m_pCatalog->GetPage(nPageIndex)->GetLinks(m_pCatalog);
}
void PDFDoc::ProcessLinks(OutputDev *pOut, int nPageIndex)
{
m_pCatalog->GetPage(nPageIndex)->ProcessLinks(pOut, m_pCatalog);
}
bool PDFDoc::IsLinearized()
{
bool bLinearized = false;
Object oTemp;
oTemp.InitNull();
Parser *pParser = new Parser(m_pXref, new Lexer(m_pXref, m_pStream->MakeSubStream(m_pStream->GetStartPos(), false, 0, &oTemp)), true);
if (!pParser)
{
// TO DO: Error "Can't allocate memory"
oTemp.Free();
return false;
}
oTemp.Free();
Object oNum, oGen, oObj, oDict;
pParser->GetObject(&oNum);
pParser->GetObject(&oGen);
pParser->GetObject(&oObj);
pParser->GetObject(&oDict);
if (oNum.IsInt() && oGen.IsInt() && oObj.IsCommand("obj") && oDict.IsDict())
{
Object oVersion;
oDict.DictLookup("Linearized", &oVersion);
if (oVersion.IsNum() && oVersion.GetNum() > 0)
{
bLinearized = true;
}
oVersion.Free();
}
oDict.Free();
oObj.Free();
oGen.Free();
oNum.Free();
delete pParser;
return bLinearized;
}
}