INTEGRATION: CWS pdf25 (1.1.2); FILE ADDED

2008/08/05 09:59:16 akhva 1.1.2.2: #i90061
2008/07/24 11:45:27 akhva 1.1.2.1: #90061
This commit is contained in:
Kurt Zenker 2008-08-14 16:05:40 +00:00
parent 9ffa9e3e68
commit 49ade4a409
4 changed files with 1243 additions and 0 deletions

View file

@ -0,0 +1,165 @@
#*************************************************************************
#
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# Copyright 2008 by Sun Microsystems, Inc.
#
# OpenOffice.org - a multi-platform office productivity suite
#
# $RCSfile: makefile.mk,v $
#
# $Revision: 1.2 $
#
# This file is part of OpenOffice.org.
#
# OpenOffice.org is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version 3
# only, as published by the Free Software Foundation.
#
# OpenOffice.org is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License version 3 for more details
# (a copy is included in the LICENSE file that accompanied this code).
#
# You should have received a copy of the GNU Lesser General Public License
# version 3 along with OpenOffice.org. If not, see
# <http://www.openoffice.org/license.html>
# for a copy of the LGPLv3 License.
#
#*************************************************************************
PRJ=..$/..$/..
PRJNAME=sdext
TARGET=tests
TARGETTYPE=CUI
ENABLE_EXCEPTIONS=TRUE
# --- Settings -----------------------------------------------------
.INCLUDE: settings.mk
# --- test lib ------------------------------------------------------
.IF "$(ENABLE_PDFIMPORT)" == "NO"
@all:
@echo "PDF Import extension disabled."
.ENDIF
.IF "$(SYSTEM_ZLIB)" == "YES"
CFLAGS+=-DSYSTEM_ZLIB
.ENDIF
SHL1OBJS= \
$(SLO)$/tests.obj
SHL1LIBS=\
$(SLB)$/pdfmisc.lib \
$(SLB)$/pdfparse.lib \
$(SLB)$/pdfsax.lib \
$(SLB)$/pdfparsetree.lib \
$(SLB)$/pdfodf.lib \
$(SLB)$/xpdfwrapper.lib \
$(SLB)$/pdfimport.lib
SHL1TARGET=$(TARGET)
SHL1STDLIBS=\
$(BASEGFXLIB) \
$(UNOTOOLSLIB) \
$(CANVASTOOLSLIB) \
$(COMPHELPERLIB) \
$(CPPUHELPERLIB) \
$(CPPUNITLIB) \
$(ZLIB3RDLIB) \
$(CPPULIB) \
$(SALLIB)
SHL1IMPLIB= i$(SHL1TARGET)
DEF1NAME =$(SHL1TARGET)
SHL1VERSIONMAP = export.map
# --- pdf2xml binary ------------------------------------------------------
TARGET2=pdf2xml
APP1TARGET=$(TARGET2)
APP1LIBSALCPPRT=
APP1OBJS=$(SLO)$/pdf2xml.obj
APP1LIBS=\
$(SLB)$/pdfmisc.lib \
$(SLB)$/pdfparse.lib \
$(SLB)$/pdfsax.lib \
$(SLB)$/pdfparsetree.lib \
$(SLB)$/pdfodf.lib \
$(SLB)$/xpdfwrapper.lib \
$(SLB)$/pdfimport.lib
APP1STDLIBS=\
$(BASEGFXLIB) \
$(UNOTOOLSLIB) \
$(CANVASTOOLSLIB) \
$(COMPHELPERLIB) \
$(CPPUHELPERLIB) \
$(CPPUNITLIB) \
$(ZLIB3RDLIB) \
$(CPPULIB) \
$(SALLIB)
# --- pdfunzip binary ------------------------------------------------------
TARGET3=pdfunzip
APP2TARGET=$(TARGET3)
APP2LIBSALCPPRT=
APP2OBJS=$(SLO)$/pdfunzip.obj
APP2LIBS=\
$(SLB)$/pdfmisc.lib \
$(SLB)$/pdfparse.lib \
$(SLB)$/pdfsax.lib \
$(SLB)$/pdfparsetree.lib \
$(SLB)$/pdfodf.lib \
$(SLB)$/xpdfwrapper.lib \
$(SLB)$/pdfimport.lib
APP2STDLIBS=\
$(BASEGFXLIB) \
$(UNOTOOLSLIB) \
$(CANVASTOOLSLIB) \
$(COMPHELPERLIB) \
$(CPPUHELPERLIB) \
$(CPPUNITLIB) \
$(ZLIB3RDLIB) \
$(CPPULIB) \
$(SALLIB)
# --- Targets ------------------------------------------------------
.INCLUDE : target.mk
.INCLUDE : _cppunit.mk
# --- Fake uno bootstrap & copy testfile ------------------------
$(BIN)$/pdfi_unittest_test.pdf : testinput.pdf
rm -f $@
$(GNUCOPY) testinput.pdf $@
$(BIN)$/pdfi_unittest_test.ini : makefile.mk
rm -f $@
@echo UNO_SERVICES= > $@
@echo UNO_TYPES=$(UNOUCRRDB:s/\/\\/) >> $@
# --- Enable testshl2 execution in normal build ------------------------
$(MISC)$/pdfi_unittest_succeeded : $(SHL1TARGETN) $(BIN)$/pdfi_unittest_test.pdf $(BIN)$/pdfi_unittest_test.ini
rm -f $(BIN)$/pdfi_unittest_draw.xml
rm -f $(BIN)$/pdfi_unittest_writer.xml
@echo ----------------------------------------------------------
@echo - start unit test on library $(SHL1TARGETN)
@echo ----------------------------------------------------------
testshl2 -forward $(BIN)$/ $(SHL1TARGETN)
$(TOUCH) $@
#ALLTAR : $(MISC)$/pdfi_unittest_succeeded

View file

@ -0,0 +1,109 @@
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: pdf2xml.cxx,v $
*
* $Revision: 1.2 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sdext.hxx"
#include "outputwrap.hxx"
#include "contentsink.hxx"
#include "pdfihelper.hxx"
#include "wrapper.hxx"
#include "pdfparse.hxx"
#include "../pdfiadaptor.hxx"
#include <sal/main.h>
#include <osl/process.h>
#include <rtl/bootstrap.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <cppuhelper/servicefactory.hxx>
#include <comphelper/processfactory.hxx>
using namespace ::pdfi;
using namespace ::com::sun::star;
SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
{
if( argc != 5 )
return 1;
::rtl::OUString aBaseURL, aTmpURL, aSrcURL, aDstURL, aIniUrl;
TreeVisitorFactorySharedPtr pTreeFactory;
if( rtl_str_compare(argv[1], "-writer") == 0 )
pTreeFactory = createWriterTreeVisitorFactory();
else if( rtl_str_compare(argv[1], "-draw") == 0 )
pTreeFactory = createDrawTreeVisitorFactory();
else if( rtl_str_compare(argv[1], "-impress") == 0 )
pTreeFactory = createImpressTreeVisitorFactory();
else
return 1;
osl_getProcessWorkingDir(&aBaseURL.pData);
osl_getFileURLFromSystemPath( rtl::OUString::createFromAscii(argv[2]).pData,
&aTmpURL.pData );
osl_getAbsoluteFileURL(aBaseURL.pData,aTmpURL.pData,&aSrcURL.pData);
osl_getFileURLFromSystemPath( rtl::OUString::createFromAscii(argv[3]).pData,
&aTmpURL.pData );
osl_getAbsoluteFileURL(aBaseURL.pData,aTmpURL.pData,&aDstURL.pData);
osl_getFileURLFromSystemPath( rtl::OUString::createFromAscii(argv[4]).pData,
&aTmpURL.pData );
osl_getAbsoluteFileURL(aBaseURL.pData,aTmpURL.pData,&aIniUrl.pData);
// bootstrap UNO
uno::Reference< lang::XMultiServiceFactory > xFactory;
uno::Reference< uno::XComponentContext > xCtx;
try
{
xCtx = ::cppu::defaultBootstrap_InitialComponentContext(aIniUrl);
xFactory = uno::Reference< lang::XMultiServiceFactory >( xCtx->getServiceManager(),
uno::UNO_QUERY );
if( xFactory.is() )
::comphelper::setProcessServiceFactory( xFactory );
}
catch( uno::Exception& )
{
}
if( !xFactory.is() )
{
OSL_TRACE( "Could not bootstrap UNO, installation must be in disorder. Exiting.\n" );
return 1;
}
pdfi::PDFIRawAdaptor aAdaptor( xCtx );
aAdaptor.setTreeVisitorFactory(pTreeFactory);
aAdaptor.odfConvert( aSrcURL, new OutputWrap(aDstURL), NULL );
return 0;
}

View file

@ -0,0 +1,392 @@
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: pdfunzip.cxx,v $
*
* $Revision: 1.2 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sdext.hxx"
#include <stdio.h>
#include <sal/main.h>
#include <osl/file.h>
#include <osl/thread.h>
#include <rtl/alloc.h>
#include <rtl/ustring.hxx>
#include <rtl/strbuf.hxx>
#include "pdfparse.hxx"
using namespace rtl;
using namespace pdfparse;
void printHelp( const char* pExe )
{
fprintf( stdout,
"USAGE: %s [-h,--help] [-a, --extract-add-streams] [-pw, --password <password>] <inputfile> [<outputfile>]\n"
" -h, --help: show help\n"
" -a, --extract-add-streams: extracts additional streams to outputfile_object\n"
" and prints the mimetype found to stdout\n"
" -pw, --password: use password for decryption\n"
, pExe );
}
class FileEmitContext : public EmitContext
{
oslFileHandle m_aHandle;
oslFileHandle m_aReadHandle;
unsigned int m_nReadLen;
void openReadFile( const char* pOrigName );
public:
FileEmitContext( const char* pFileName, const char* pOrigName, const PDFContainer* pTop );
virtual ~FileEmitContext();
virtual bool write( const void* pBuf, unsigned int nLen ) throw();
virtual unsigned int getCurPos() throw();
virtual bool copyOrigBytes( unsigned int nOrigOffset, unsigned int nLen ) throw();
virtual unsigned int readOrigBytes( unsigned int nOrigOffset, unsigned int nLen, void* pBuf ) throw();
};
FileEmitContext::FileEmitContext( const char* pFileName, const char* pOrigName, const PDFContainer* pTop )
: EmitContext( pTop ),
m_aHandle( NULL ),
m_aReadHandle( NULL ),
m_nReadLen( 0 )
{
OUString aSysFile( OStringToOUString( OString( pFileName ), osl_getThreadTextEncoding() ) );
OUString aURL;
if( osl_getFileURLFromSystemPath( aSysFile.pData, &aURL.pData ) != osl_File_E_None )
{
fprintf( stderr, "filename conversion \"%s\" failed\n", pFileName );
return;
}
if( osl_openFile( aURL.pData, &m_aHandle, osl_File_OpenFlag_Write ) == osl_File_E_None )
{
if( osl_setFileSize( m_aHandle, 0 ) != osl_File_E_None )
{
fprintf( stderr, "could not truncate %s\n", pFileName );
osl_closeFile( m_aHandle );
m_aHandle = NULL;
}
}
else if( osl_openFile( aURL.pData, &m_aHandle,
osl_File_OpenFlag_Write |osl_File_OpenFlag_Create ) != osl_File_E_None )
{
fprintf( stderr, "could not open %s\n", pFileName );
return;
}
m_bDeflate = true;
openReadFile( pOrigName );
}
FileEmitContext::~FileEmitContext()
{
if( m_aHandle )
osl_closeFile( m_aHandle );
if( m_aReadHandle )
osl_closeFile( m_aReadHandle );
}
void FileEmitContext::openReadFile( const char* pInFile )
{
OUString aSysFile( OStringToOUString( OString( pInFile ), osl_getThreadTextEncoding() ) );
OUString aURL;
if( osl_getFileURLFromSystemPath( aSysFile.pData, &aURL.pData ) != osl_File_E_None )
{
fprintf( stderr, "filename conversion \"%s\" failed\n", pInFile );
return;
}
if( osl_openFile( aURL.pData, &m_aReadHandle, osl_File_OpenFlag_Read ) != osl_File_E_None )
{
fprintf( stderr, "could not open %s\n", pInFile );
return;
}
if( osl_setFilePos( m_aReadHandle, osl_Pos_End, 0 ) != osl_File_E_None )
{
fprintf( stderr, "could not seek to end of %s\n", pInFile );
osl_closeFile( m_aReadHandle );
return;
}
sal_uInt64 nFileSize = 0;
if( osl_getFilePos( m_aReadHandle, &nFileSize ) != osl_File_E_None )
{
fprintf( stderr, "could not get end pos of %s\n", pInFile );
osl_closeFile( m_aReadHandle );
return;
}
m_nReadLen = static_cast<unsigned int>(nFileSize);
}
bool FileEmitContext::write( const void* pBuf, unsigned int nLen ) throw()
{
if( ! m_aHandle )
return false;
sal_uInt64 nWrite = static_cast<sal_uInt64>(nLen);
sal_uInt64 nWritten = 0;
return (osl_writeFile( m_aHandle, pBuf, nWrite, &nWritten ) == osl_File_E_None)
&& nWrite == nWritten;
}
unsigned int FileEmitContext::getCurPos() throw()
{
sal_uInt64 nFileSize = 0;
if( m_aHandle )
{
if( osl_getFilePos( m_aHandle, &nFileSize ) != osl_File_E_None )
nFileSize = 0;
}
return static_cast<unsigned int>(nFileSize);
}
bool FileEmitContext::copyOrigBytes( unsigned int nOrigOffset, unsigned int nLen ) throw()
{
if( nOrigOffset + nLen > m_nReadLen )
return false;
if( osl_setFilePos( m_aReadHandle, osl_Pos_Absolut, nOrigOffset ) != osl_File_E_None )
{
fprintf( stderr, "could not seek to offset %u\n", nOrigOffset );
return false;
}
void* pBuf = rtl_allocateMemory( nLen );
if( ! pBuf )
return false;
sal_uInt64 nBytesRead = 0;
if( osl_readFile( m_aReadHandle, pBuf, nLen, &nBytesRead ) != osl_File_E_None
|| nBytesRead != static_cast<sal_uInt64>(nLen) )
{
fprintf( stderr, "could not read %u bytes\n", nLen );
rtl_freeMemory( pBuf );
return false;
}
bool bRet = write( pBuf, nLen );
rtl_freeMemory( pBuf );
return bRet;
}
unsigned int FileEmitContext::readOrigBytes( unsigned int nOrigOffset, unsigned int nLen, void* pBuf ) throw()
{
if( nOrigOffset + nLen > m_nReadLen )
return 0;
if( osl_setFilePos( m_aReadHandle, osl_Pos_Absolut, nOrigOffset ) != osl_File_E_None )
{
fprintf( stderr, "could not seek to offset %u\n", nOrigOffset );
return 0;
}
sal_uInt64 nBytesRead = 0;
if( osl_readFile( m_aReadHandle, pBuf, nLen, &nBytesRead ) != osl_File_E_None )
return 0;
return static_cast<unsigned int>(nBytesRead);
}
typedef int(*PDFFileHdl)(const char*, const char*, PDFFile*);
int handleFile( const char* pInFile, const char* pOutFile, const char* pPassword, PDFFileHdl pHdl )
{
PDFReader aParser;
int nRet = 0;
PDFEntry* pEntry = aParser.read( pInFile );
if( pEntry )
{
PDFFile* pPDFFile = dynamic_cast<PDFFile*>(pEntry);
if( pPDFFile )
{
fprintf( stdout, "have a %s PDF file\n", pPDFFile->isEncrypted() ? "encrypted" : "unencrypted" );
if( pPassword )
fprintf( stdout, "password %s\n",
pPDFFile->setupDecryptionData( pPassword ) ? "matches" : "does not match" );
nRet = pHdl( pInFile, pOutFile, pPDFFile );
}
else
nRet = 20;
delete pEntry;
}
return nRet;
}
int write_unzipFile( const char* pInFile, const char* pOutFile, PDFFile* pPDFFile )
{
FileEmitContext aContext( pOutFile, pInFile, pPDFFile );
aContext.m_bDecrypt = pPDFFile->isEncrypted();
pPDFFile->emit(aContext);
return 0;
}
int write_addStreamArray( const char* pOutFile, PDFArray* pStreams, PDFFile* pPDFFile, const char* pInFile )
{
int nRet = 0;
unsigned int nArrayElements = pStreams->m_aSubElements.size();
for( unsigned int i = 0; i < nArrayElements-1 && nRet == 0; i++ )
{
PDFName* pMimeType = dynamic_cast<PDFName*>(pStreams->m_aSubElements[i]);
PDFObjectRef* pStreamRef = dynamic_cast<PDFObjectRef*>(pStreams->m_aSubElements[i+1]);
if( ! pMimeType )
fprintf( stderr, "error: no mimetype element\n" );
if( ! pStreamRef )
fprintf( stderr, "error: no stream ref element\n" );
if( pMimeType && pStreamRef )
{
fprintf( stdout, "found stream %d %d with mimetype %s\n",
pStreamRef->m_nNumber, pStreamRef->m_nGeneration,
pMimeType->m_aName.getStr() );
PDFObject* pObject = pPDFFile->findObject( pStreamRef->m_nNumber, pStreamRef->m_nGeneration );
if( pObject )
{
rtl::OStringBuffer aOutStream( pOutFile );
aOutStream.append( "_stream_" );
aOutStream.append( sal_Int32(pStreamRef->m_nNumber) );
aOutStream.append( "_" );
aOutStream.append( sal_Int32(pStreamRef->m_nGeneration) );
FileEmitContext aContext( aOutStream.getStr(), pInFile, pPDFFile );
aContext.m_bDecrypt = pPDFFile->isEncrypted();
pObject->writeStream( aContext, pPDFFile );
}
else
{
fprintf( stderr, "object not found\n" );
nRet = 121;
}
}
else
nRet = 120;
}
return nRet;
}
int write_addStreams( const char* pInFile, const char* pOutFile, PDFFile* pPDFFile )
{
// find all trailers
int nRet = 0;
unsigned int nElements = pPDFFile->m_aSubElements.size();
for( unsigned i = 0; i < nElements && nRet == 0; i++ )
{
PDFTrailer* pTrailer = dynamic_cast<PDFTrailer*>(pPDFFile->m_aSubElements[i]);
if( pTrailer && pTrailer->m_pDict )
{
// search for AdditionalStreams entry
std::hash_map<rtl::OString,PDFEntry*,rtl::OStringHash>::iterator add_stream;
add_stream = pTrailer->m_pDict->m_aMap.find( "AdditionalStreams" );
if( add_stream != pTrailer->m_pDict->m_aMap.end() )
{
PDFArray* pStreams = dynamic_cast<PDFArray*>(add_stream->second);
if( pStreams )
nRet = write_addStreamArray( pOutFile, pStreams, pPDFFile, pInFile );
}
}
}
return nRet;
}
SAL_IMPLEMENT_MAIN_WITH_ARGS( argc, argv )
{
const char* pInFile = NULL;
const char* pOutFile = NULL;
const char* pPassword = NULL;
OStringBuffer aOutFile( 256 );
PDFFileHdl aHdl = write_unzipFile;
for( int nArg = 1; nArg < argc; nArg++ )
{
if( argv[nArg][0] == '-' )
{
if( ! rtl_str_compare( "-pw", argv[nArg] ) ||
! rtl_str_compare( "--password" , argv[nArg] ) )
{
if( nArg == argc-1 )
{
fprintf( stderr, "no password given\n" );
return 1;
}
nArg++;
pPassword = argv[nArg];
}
else if( ! rtl_str_compare( "-h", argv[nArg] ) ||
! rtl_str_compare( "--help", argv[nArg] ) )
{
printHelp( argv[0] );
return 0;
}
else if( ! rtl_str_compare( "-a", argv[nArg] ) ||
! rtl_str_compare( "--extract-add-streams", argv[nArg] ) )
{
aHdl = write_addStreams;
}
else
{
fprintf( stderr, "unrecognized option \"%s\"\n",
argv[nArg] );
printHelp( argv[0] );
return 1;
}
}
else if( pInFile == NULL )
pInFile = argv[nArg];
else if( pOutFile == NULL )
pOutFile = argv[nArg];
}
if( ! pInFile )
{
fprintf( stderr, "no input file given\n" );
return 10;
}
if( ! pOutFile )
{
OString aFile( pInFile );
if( aFile.getLength() > 0 )
{
if( aFile.getLength() > 4 )
{
if( aFile.matchIgnoreAsciiCase( OString( ".pdf" ), aFile.getLength()-4 ) )
aOutFile.append( pInFile, aFile.getLength() - 4 );
else
aOutFile.append( aFile );
}
aOutFile.append( "_unzip.pdf" );
pOutFile = aOutFile.getStr();
}
else
{
fprintf( stderr, "no output file given\n" );
return 11;
}
}
return handleFile( pInFile, pOutFile, pPassword, aHdl );
}

View file

@ -0,0 +1,577 @@
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: tests.cxx,v $
*
* $Revision: 1.2 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sdext.hxx"
#ifdef SYSTEM_ZLIB
#include "zlib.h"
#else
#include <zlib/zlib.h>
#endif
#include "outputwrap.hxx"
#include "contentsink.hxx"
#include "pdfihelper.hxx"
#include "wrapper.hxx"
#include "pdfparse.hxx"
#include "../pdfiadaptor.hxx"
#include <rtl/math.hxx>
#include <osl/file.hxx>
#include <osl/process.h>
#include <cppunit/simpleheader.hxx>
#include <cppuhelper/compbase1.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <cppuhelper/basemutex.hxx>
#include <comphelper/sequence.hxx>
#include <com/sun/star/rendering/XCanvas.hpp>
#include <com/sun/star/rendering/XColorSpace.hpp>
#include <com/sun/star/rendering/PathJoinType.hpp>
#include <com/sun/star/rendering/PathCapType.hpp>
#include <com/sun/star/rendering/BlendMode.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/registry/XSimpleRegistry.hpp>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/tools/canvastools.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/polygon/b2dpolygonclipper.hxx>
#include <vector>
#include <hash_map>
using namespace ::pdfparse;
using namespace ::pdfi;
using namespace ::com::sun::star;
namespace
{
class TestSink : public ContentSink
{
public:
TestSink() :
m_nNextFontId( 1 ),
m_aIdToFont(),
m_aFontToId(),
m_aGCStack(1),
m_aPageSize(),
m_aHyperlinkBounds(),
m_aURI(),
m_aTextOut(),
m_nNumPages(0),
m_bPageEnded(false),
m_bRedCircleSeen(false),
m_bGreenStrokeSeen(false),
m_bDashedLineSeen(false)
{}
~TestSink()
{
CPPUNIT_ASSERT_MESSAGE( "A4 page size (in 100th of points)",
m_aPageSize.Width == 79400 && m_aPageSize.Height == 59500 );
CPPUNIT_ASSERT_MESSAGE( "endPage() called", m_bPageEnded );
CPPUNIT_ASSERT_MESSAGE( "Num pages equal one", m_nNumPages == 1 );
CPPUNIT_ASSERT_MESSAGE( "Correct hyperlink bounding box",
rtl::math::approxEqual(m_aHyperlinkBounds.X1,34.7 ) &&
rtl::math::approxEqual(m_aHyperlinkBounds.Y1,386.0) &&
rtl::math::approxEqual(m_aHyperlinkBounds.X2,166.7) &&
rtl::math::approxEqual(m_aHyperlinkBounds.Y2,406.2) );
CPPUNIT_ASSERT_MESSAGE( "Correct hyperlink URI",
m_aURI == ::rtl::OUString::createFromAscii( "http://download.openoffice.org/" ) );
const char* sText = " \n \nThis is a testtext\nNew paragraph,\nnew line\n"
"Hyperlink, this is\n?\nThis is more text\noutline mode\n?\nNew paragraph\n";
::rtl::OString aTmp;
m_aTextOut.makeStringAndClear().convertToString( &aTmp,
RTL_TEXTENCODING_ASCII_US,
OUSTRING_TO_OSTRING_CVTFLAGS );
CPPUNIT_ASSERT_MESSAGE( "Imported text is \"This is a testtext New paragraph, new line"
" Hyperlink, this is * This is more text outline mode * New paragraph\"",
sText == aTmp );
CPPUNIT_ASSERT_MESSAGE( "red circle seen in input", m_bRedCircleSeen );
CPPUNIT_ASSERT_MESSAGE( "green stroke seen in input", m_bGreenStrokeSeen );
CPPUNIT_ASSERT_MESSAGE( "dashed line seen in input", m_bDashedLineSeen );
}
private:
GraphicsContext& getCurrentContext() { return m_aGCStack.back(); }
// ContentSink interface implementation
virtual void setPageNum( sal_Int32 nNumPages )
{
m_nNumPages = nNumPages;
}
virtual void startPage( const geometry::RealSize2D& rSize )
{
m_aPageSize = rSize;
}
virtual void endPage()
{
m_bPageEnded = true;
}
virtual void hyperLink( const geometry::RealRectangle2D& rBounds,
const ::rtl::OUString& rURI )
{
m_aHyperlinkBounds = rBounds;
m_aURI = rURI;
}
virtual void pushState()
{
m_aGCStack.push_back( m_aGCStack.back() );
}
virtual void popState()
{
m_aGCStack.pop_back();
}
virtual void setTransformation( const geometry::AffineMatrix2D& rMatrix )
{
basegfx::unotools::homMatrixFromAffineMatrix(
getCurrentContext().Transformation,
rMatrix );
}
virtual void setLineDash( const uno::Sequence<double>& dashes,
double start )
{
GraphicsContext& rContext( getCurrentContext() );
if( dashes.getLength() )
comphelper::sequenceToContainer(rContext.DashArray,dashes);
CPPUNIT_ASSERT_MESSAGE( "line dashing start offset", start == 0.0 );
}
virtual void setFlatness( double nFlatness )
{
getCurrentContext().Flatness = nFlatness;
}
virtual void setLineJoin(sal_Int8 nJoin)
{
getCurrentContext().LineJoin = nJoin;
}
virtual void setLineCap(sal_Int8 nCap)
{
getCurrentContext().LineCap = nCap;
}
virtual void setMiterLimit(double nVal)
{
getCurrentContext().MiterLimit = nVal;
}
virtual void setLineWidth(double nVal)
{
getCurrentContext().LineWidth = nVal;
}
virtual void setFillColor( const rendering::ARGBColor& rColor )
{
getCurrentContext().FillColor = rColor;
}
virtual void setStrokeColor( const rendering::ARGBColor& rColor )
{
getCurrentContext().LineColor = rColor;
}
virtual void setBlendMode(sal_Int8 nMode)
{
getCurrentContext().BlendMode = nMode;
}
virtual void setFont( const FontAttributes& rFont )
{
FontToIdMap::const_iterator it = m_aFontToId.find( rFont );
if( it != m_aFontToId.end() )
getCurrentContext().FontId = it->second;
else
{
m_aFontToId[ rFont ] = m_nNextFontId;
m_aIdToFont[ m_nNextFontId ] = rFont;
getCurrentContext().FontId = m_nNextFontId;
m_nNextFontId++;
}
}
virtual void strokePath( const uno::Reference<rendering::XPolyPolygon2D>& rPath )
{
GraphicsContext& rContext( getCurrentContext() );
basegfx::B2DPolyPolygon aPath = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
aPath.transform( rContext.Transformation );
if( rContext.DashArray.empty() )
{
CPPUNIT_ASSERT_MESSAGE( "Line color is green",
rContext.LineColor.Alpha == 1.0 &&
rContext.LineColor.Red == 0.0 &&
rContext.LineColor.Green == 1.0 &&
rContext.LineColor.Blue == 0.0 );
CPPUNIT_ASSERT_MESSAGE( "Line width is 0",
rtl::math::approxEqual(rContext.LineWidth, 28.3) );
const char* sExportString = "m53570 7650-35430 24100";
CPPUNIT_ASSERT_MESSAGE( "Stroke is m535.7 518.5-354.3-241",
basegfx::tools::exportToSvgD( aPath ).compareToAscii(sExportString) == 0 );
m_bGreenStrokeSeen = true;
}
else
{
CPPUNIT_ASSERT_MESSAGE( "Dash array cons ists of four entries",
rContext.DashArray.size() == 4 &&
rtl::math::approxEqual(rContext.DashArray[0],14.3764) &&
rContext.DashArray[0] == rContext.DashArray[1] &&
rContext.DashArray[1] == rContext.DashArray[2] &&
rContext.DashArray[2] == rContext.DashArray[3] );
CPPUNIT_ASSERT_MESSAGE( "Line color is black",
rContext.LineColor.Alpha == 1.0 &&
rContext.LineColor.Red == 0.0 &&
rContext.LineColor.Green == 0.0 &&
rContext.LineColor.Blue == 0.0 );
CPPUNIT_ASSERT_MESSAGE( "Line width is 0",
rContext.LineWidth == 0 );
const char* sExportString = "m49890 5670.00000000001-35430 24090";
CPPUNIT_ASSERT_MESSAGE( "Stroke is m49890 5670.00000000001-35430 24090",
basegfx::tools::exportToSvgD( aPath ).compareToAscii(sExportString) == 0 );
m_bDashedLineSeen = true;
}
CPPUNIT_ASSERT_MESSAGE( "Blend mode is normal",
rContext.BlendMode == rendering::BlendMode::NORMAL );
CPPUNIT_ASSERT_MESSAGE( "Join type is round",
rContext.LineJoin == rendering::PathJoinType::ROUND );
CPPUNIT_ASSERT_MESSAGE( "Cap type is butt",
rContext.LineCap == rendering::PathCapType::BUTT );
CPPUNIT_ASSERT_MESSAGE( "Line miter limit is 10",
rContext.MiterLimit == 10 );
CPPUNIT_ASSERT_MESSAGE( "Flatness is 0",
rContext.Flatness == 1 );
CPPUNIT_ASSERT_MESSAGE( "Font id is 0",
rContext.FontId == 0 );
}
virtual void fillPath( const uno::Reference<rendering::XPolyPolygon2D>& rPath )
{
GraphicsContext& rContext( getCurrentContext() );
basegfx::B2DPolyPolygon aPath = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
aPath.transform( rContext.Transformation );
CPPUNIT_ASSERT_MESSAGE( "Fill color is black",
rContext.FillColor.Alpha == 1.0 &&
rContext.FillColor.Red == 0.0 &&
rContext.FillColor.Green == 0.0 &&
rContext.FillColor.Blue == 0.0 );
CPPUNIT_ASSERT_MESSAGE( "Blend mode is normal",
rContext.BlendMode == rendering::BlendMode::NORMAL );
CPPUNIT_ASSERT_MESSAGE( "Flatness is 10",
rContext.Flatness == 10 );
CPPUNIT_ASSERT_MESSAGE( "Font id is 0",
rContext.FontId == 0 );
}
virtual void eoFillPath( const uno::Reference<rendering::XPolyPolygon2D>& rPath )
{
GraphicsContext& rContext( getCurrentContext() );
basegfx::B2DPolyPolygon aPath = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
aPath.transform( rContext.Transformation );
CPPUNIT_ASSERT_MESSAGE( "Fill color is black",
rContext.FillColor.Alpha == 1.0 &&
rContext.FillColor.Red == 1.0 &&
rContext.FillColor.Green == 0.0 &&
rContext.FillColor.Blue == 0.0 );
CPPUNIT_ASSERT_MESSAGE( "Blend mode is normal",
rContext.BlendMode == rendering::BlendMode::NORMAL );
CPPUNIT_ASSERT_MESSAGE( "Flatness is 0",
rContext.Flatness == 1 );
CPPUNIT_ASSERT_MESSAGE( "Font id is 0",
rContext.FontId == 0 );
const char* sExportString = "m12050 49610c-4310 0-7800-3490-7800-7800 0-4300 "
"3490-7790 7800-7790 4300 0 7790 3490 7790 7790 0 4310-3490 7800-7790 7800z";
CPPUNIT_ASSERT_MESSAGE( "Stroke is a 4-bezier circle",
basegfx::tools::exportToSvgD( aPath ).compareToAscii(sExportString) == 0 );
m_bRedCircleSeen = true;
}
virtual void intersectClip(const uno::Reference<rendering::XPolyPolygon2D>& rPath)
{
basegfx::B2DPolyPolygon aNewClip = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
basegfx::B2DPolyPolygon aCurClip = getCurrentContext().Clip;
if( aCurClip.count() )
aNewClip = basegfx::tools::clipPolyPolygonOnPolyPolygon( aCurClip, aNewClip, false );
getCurrentContext().Clip = aNewClip;
}
virtual void intersectEoClip(const uno::Reference<rendering::XPolyPolygon2D>& rPath)
{
basegfx::B2DPolyPolygon aNewClip = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
basegfx::B2DPolyPolygon aCurClip = getCurrentContext().Clip;
if( aCurClip.count() )
aNewClip = basegfx::tools::clipPolyPolygonOnPolyPolygon( aCurClip, aNewClip, false );
getCurrentContext().Clip = aNewClip;
}
virtual void drawGlyphs( const rtl::OUString& rGlyphs,
const geometry::RealRectangle2D& /*rRect*/,
const geometry::Matrix2D& /*rFontMatrix*/ )
{
m_aTextOut.append(rGlyphs);
}
virtual void endText()
{
m_aTextOut.append( ::rtl::OUString::createFromAscii("\n") );
}
virtual void drawMask(const uno::Sequence<beans::PropertyValue>& xBitmap,
bool /*bInvert*/ )
{
CPPUNIT_ASSERT_MESSAGE( "drawMask received two properties",
xBitmap.getLength()==3 );
CPPUNIT_ASSERT_MESSAGE( "drawMask got URL param",
xBitmap[0].Name.compareToAscii( "URL" ) == 0 );
CPPUNIT_ASSERT_MESSAGE( "drawMask got InputStream param",
xBitmap[1].Name.compareToAscii( "InputStream" ) == 0 );
}
virtual void drawImage(const uno::Sequence<beans::PropertyValue>& xBitmap )
{
CPPUNIT_ASSERT_MESSAGE( "drawImage received two properties",
xBitmap.getLength()==3 );
CPPUNIT_ASSERT_MESSAGE( "drawImage got URL param",
xBitmap[0].Name.compareToAscii( "URL" ) == 0 );
CPPUNIT_ASSERT_MESSAGE( "drawImage got InputStream param",
xBitmap[1].Name.compareToAscii( "InputStream" ) == 0 );
}
virtual void drawColorMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
const uno::Sequence<uno::Any>& /*xMaskColors*/ )
{
CPPUNIT_ASSERT_MESSAGE( "drawColorMaskedImage received two properties",
xBitmap.getLength()==3 );
CPPUNIT_ASSERT_MESSAGE( "drawColorMaskedImage got URL param",
xBitmap[0].Name.compareToAscii( "URL" ) == 0 );
CPPUNIT_ASSERT_MESSAGE( "drawColorMaskedImage got InputStream param",
xBitmap[1].Name.compareToAscii( "InputStream" ) == 0 );
}
virtual void drawMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
const uno::Sequence<beans::PropertyValue>& xMask,
bool /*bInvertMask*/)
{
CPPUNIT_ASSERT_MESSAGE( "drawMaskedImage received two properties #1",
xBitmap.getLength()==3 );
CPPUNIT_ASSERT_MESSAGE( "drawMaskedImage got URL param #1",
xBitmap[0].Name.compareToAscii( "URL" ) == 0 );
CPPUNIT_ASSERT_MESSAGE( "drawMaskedImage got InputStream param #1",
xBitmap[1].Name.compareToAscii( "InputStream" ) == 0 );
CPPUNIT_ASSERT_MESSAGE( "drawMaskedImage received two properties #2",
xMask.getLength()==3 );
CPPUNIT_ASSERT_MESSAGE( "drawMaskedImage got URL param #2",
xMask[0].Name.compareToAscii( "URL" ) == 0 );
CPPUNIT_ASSERT_MESSAGE( "drawMaskedImage got InputStream param #2",
xMask[1].Name.compareToAscii( "InputStream" ) == 0 );
}
virtual void drawAlphaMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
const uno::Sequence<beans::PropertyValue>& xMask)
{
CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage received two properties #1",
xBitmap.getLength()==3 );
CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage got URL param #1",
xBitmap[0].Name.compareToAscii( "URL" ) == 0 );
CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage got InputStream param #1",
xBitmap[1].Name.compareToAscii( "InputStream" ) == 0 );
CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage received two properties #2",
xMask.getLength()==3 );
CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage got URL param #2",
xMask[0].Name.compareToAscii( "URL" ) == 0 );
CPPUNIT_ASSERT_MESSAGE( "drawAlphaMaskedImage got InputStream param #2",
xMask[1].Name.compareToAscii( "InputStream" ) == 0 );
}
typedef std::hash_map<sal_Int32,FontAttributes> IdToFontMap;
typedef std::hash_map<FontAttributes,sal_Int32,FontAttrHash> FontToIdMap;
typedef std::hash_map<sal_Int32,GraphicsContext> IdToGCMap;
typedef std::hash_map<GraphicsContext,sal_Int32,GraphicsContextHash> GCToIdMap;
typedef std::vector<GraphicsContext> GraphicsContextStack;
sal_Int32 m_nNextFontId;
IdToFontMap m_aIdToFont;
FontToIdMap m_aFontToId;
GraphicsContextStack m_aGCStack;
geometry::RealSize2D m_aPageSize;
geometry::RealRectangle2D m_aHyperlinkBounds;
::rtl::OUString m_aURI;
::rtl::OUStringBuffer m_aTextOut;
sal_Int32 m_nNumPages;
bool m_bPageEnded;
bool m_bRedCircleSeen;
bool m_bGreenStrokeSeen;
bool m_bDashedLineSeen;
};
class PDFITest : public CppUnit::TestFixture
{
uno::Reference<uno::XComponentContext> mxCtx;
rtl::OUString msBaseDir;
bool mbUnoInitialized;
public:
PDFITest() : mxCtx(),msBaseDir(),mbUnoInitialized(false)
{}
void setUp()
{
if( !mbUnoInitialized )
{
const char* pArgs( getForwardString() );
CPPUNIT_ASSERT_MESSAGE("Test file parameter", pArgs);
msBaseDir = rtl::OUString::createFromAscii(pArgs);
// bootstrap UNO
try
{
::rtl::OUString aIniUrl;
CPPUNIT_ASSERT_MESSAGE(
"Converting ini file to URL",
osl_getFileURLFromSystemPath(
(msBaseDir+rtl::OUString::createFromAscii("pdfi_unittest_test.ini")).pData,
&aIniUrl.pData ) == osl_File_E_None );
mxCtx = ::cppu::defaultBootstrap_InitialComponentContext(aIniUrl);
CPPUNIT_ASSERT_MESSAGE("Getting component context", mxCtx.is());
}
catch( uno::Exception& )
{
CPPUNIT_ASSERT_MESSAGE("Bootstrapping UNO", false);
}
mbUnoInitialized = true;
}
}
void tearDown()
{
}
void testXPDFParser()
{
pdfi::ContentSinkSharedPtr pSink( new TestSink() );
pdfi::xpdf_ImportFromFile( msBaseDir + rtl::OUString::createFromAscii("pdfi_unittest_test.pdf"),
pSink,
mxCtx );
// make destruction explicit, a bunch of things are
// checked in the destructor
pSink.reset();
}
void testOdfDrawExport()
{
pdfi::PDFIRawAdaptor aAdaptor( mxCtx );
aAdaptor.setTreeVisitorFactory( createDrawTreeVisitorFactory() );
::rtl::OUString aURL, aAbsURL, aBaseURL;
osl_getFileURLFromSystemPath( (msBaseDir + rtl::OUString::createFromAscii("pdfi_unittest_draw.xml")).pData,
&aURL.pData );
osl_getProcessWorkingDir(&aBaseURL.pData);
osl_getAbsoluteFileURL(aBaseURL.pData,aURL.pData,&aAbsURL.pData);
CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
aAdaptor.odfConvert( msBaseDir + rtl::OUString::createFromAscii("pdfi_unittest_test.pdf"),
new OutputWrap(aAbsURL),
NULL ));
}
void testOdfWriterExport()
{
pdfi::PDFIRawAdaptor aAdaptor( mxCtx );
aAdaptor.setTreeVisitorFactory( createWriterTreeVisitorFactory() );
::rtl::OUString aURL, aAbsURL, aBaseURL;
osl_getFileURLFromSystemPath( (msBaseDir + rtl::OUString::createFromAscii("pdfi_unittest_writer.xml")).pData,
&aURL.pData );
osl_getProcessWorkingDir(&aBaseURL.pData);
osl_getAbsoluteFileURL(aBaseURL.pData,aURL.pData,&aAbsURL.pData);
CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
aAdaptor.odfConvert( msBaseDir + rtl::OUString::createFromAscii("pdfi_unittest_test.pdf"),
new OutputWrap(aAbsURL),
NULL ));
}
CPPUNIT_TEST_SUITE(PDFITest);
CPPUNIT_TEST(testXPDFParser);
CPPUNIT_TEST(testOdfWriterExport);
CPPUNIT_TEST(testOdfDrawExport);
CPPUNIT_TEST_SUITE_END();
};
}
// =======================================================================
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(PDFITest, "PDFITest");
// -----------------------------------------------------------------------------
// this macro creates an empty function, which will called by the RegisterAllFunctions()
// to let the user the possibility to also register some functions by hand.
NOADDITIONAL;