Files
core/ASCOfficePDFReader/PDFDoc.cpp

428 lines
10 KiB
C++

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <windows.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'
//-------------------------------------------------------------------------------------------------------------------------------
// PDFDoc
//-------------------------------------------------------------------------------------------------------------------------------
PDFDoc::PDFDoc(GlobalParams *pGlobalParams, CString wsFileName, StringExt *seOwnerPassword, StringExt *seUserPassword)
{
m_pGlobalParams = pGlobalParams;
m_bValid = FALSE;
m_nErrorCode = ErrorNone;
m_pFile = NULL;
m_hFile = NULL;
m_hMapFile = NULL;
m_pFileBuffer = NULL;
m_pStream = NULL;
m_pXref = NULL;
m_pCatalog = NULL;
m_pOutline = NULL;
m_wsFileName = wsFileName;
// Ïûòàåìñÿ îòêðûòü ôàéë
// îòêðûâàåì ôàéë
HANDLE hFile = CreateFile( wsFileName.GetBuffer(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile)
return; // Íåâîçìîæíî îòêðûòü ôàéë
// ìàïèì ýòîò ôàéë â ïàìÿòü - òàê áûñòðåå ÷èòàþòñÿ äàííûå èç ôàéëà
DWORD nFileSize = GetFileSize(hFile, NULL);
HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, nFileSize, NULL);
if (NULL == hMapFile)
{
CloseHandle( hFile );
return; // Íåâîçìîæíî ñîçäàòü îòîáðàæåíèå ôàéëà
}
// ñîçäàåì view of file
VOID* pBaseAddress = MapViewOfFile( hMapFile, FILE_MAP_READ, 0, 0, 0 );
if ( !pBaseAddress )
{
CloseHandle( hMapFile );
CloseHandle( hFile );
return;
}
m_pFileBuffer = (char*)pBaseAddress;//(char *)MemUtilsMalloc( sizeof(char) * nFileSize );
m_hMapFile = hMapFile;
m_hFile = hFile;
// Ñîçäàåì ïîòîê
Object oTemp;
oTemp.InitNull();
m_pStream = new MemoryStream( m_pFileBuffer, 0, nFileSize, &oTemp );//FileStream( m_pFileBuffer, nFileSize, /*m_pFile,*/ 0, FALSE, 0, &oTemp );
m_bValid = Setup( seOwnerPassword, seUserPassword );
}
PDFDoc::PDFDoc(GlobalParams *pGlobalParams, wchar_t *sFileName, int nFileNameLen, StringExt *seOwnerPassword, StringExt *seUserPassword)
{
m_pGlobalParams = pGlobalParams;
wchar_t sTempFileName[_MAX_PATH + 1];
int nIndex = 0;
m_bValid = FALSE;
m_nErrorCode = ErrorNone;
m_hFile = NULL;
m_hMapFile = NULL;
m_pFileBuffer = NULL;
m_pFile = NULL;
m_pStream = NULL;
m_pXref = NULL;
m_pCatalog = NULL;
m_pOutline = NULL;
m_wsFileName = CString( sFileName );
for ( nIndex = 0; nIndex < nFileNameLen && nIndex < _MAX_PATH; ++nIndex )
{
sTempFileName[nIndex] = sFileName[nIndex];
}
sTempFileName[nIndex] = 0;
// Ïûòàåìñÿ îòêðûòü ôàéë
OSVERSIONINFO oVersion;
oVersion.dwOSVersionInfoSize = sizeof( oVersion );
GetVersionEx( &oVersion );
if ( oVersion.dwPlatformId == VER_PLATFORM_WIN32_NT )
{
m_pFile = _wfopen( sTempFileName, _T("rb") );
}
else
{
m_pFile = _wfopen( m_wsFileName.GetBuffer(), _T("rb") );
}
if ( !m_pFile )
{
// TO DO: Error "Couldn't open file"
m_nErrorCode = ErrorOpenFile;
return;
}
// Ñîçäàåì ïîòîê
Object oTemp;
oTemp.InitNull();
m_pStream = new FileStream( m_pFile, 0, FALSE, 0, &oTemp );
m_bValid = Setup( seOwnerPassword, seUserPassword );
}
PDFDoc::PDFDoc(GlobalParams *pGlobalParams, BaseStream *pStream, StringExt *seOwnerPassword, StringExt *seUserPassword )
{
m_pGlobalParams = pGlobalParams;
m_bValid = FALSE;
m_nErrorCode = ErrorNone;
if ( pStream->GetFileName() )
{
m_wsFileName = CString( pStream->GetFileName()->GetBuffer() );
}
else
{
m_wsFileName = _T("");
}
m_hFile = NULL;
m_hMapFile = NULL;
m_pFileBuffer = NULL;
m_pFile = NULL;
m_pXref = NULL;
m_pCatalog = NULL;
m_pOutline = NULL;
m_pStream = pStream;
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_nErrorCode = m_pXref->GetErrorCode();
return FALSE;
}
// Ïðîâåðÿåì çàøèôðîâàí ëè äîêóìåíò
if ( !CheckEncryption( seOwnerPassword, seUserPassword ) )
{
m_nErrorCode = 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_nErrorCode = 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 )
{
UnmapViewOfFile( (void *)m_pFileBuffer );
}
if ( m_hMapFile )
{
CloseHandle( m_hMapFile);
}
if ( m_hFile )
{
CloseHandle( m_hFile );
}
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)
{
if ( m_pGlobalParams && m_pGlobalParams->GetPrintCommands() )
{
//printf("***** page %d *****\n", nPageIndex);
}
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;
}
BOOL PDFDoc::SaveAs(CStringW wsName)
{
FILE *pFile = NULL;
if ( !( pFile = _wfopen( wsName.GetBuffer(), _T("wb") ) ) )
{
// TO DO: Error "Couldn't open file"
return FALSE;
}
m_pStream->Reset();
int nChar = 0;
while ( ( nChar = m_pStream->GetChar() ) != EOF )
{
fputc( nChar, pFile );
}
m_pStream->Close();
fclose( pFile );
return TRUE;
}