mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
428 lines
10 KiB
C++
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;
|
|
}
|