blob: f62f36b40e4e03193d31f575e3ec9cafa3798b01 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sdext.hxx"
#include "filterdet.hxx"
#include "inc/pdfparse.hxx"
#include <osl/diagnose.h>
#include <osl/file.h>
#include <osl/thread.h>
#include <rtl/digest.h>
#include <rtl/ref.hxx>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/awt/XWindow.hpp>
#include <com/sun/star/awt/XListBox.hpp>
#include <com/sun/star/awt/XDialogEventHandler.hpp>
#include <com/sun/star/awt/XDialogProvider2.hpp>
#include <com/sun/star/awt/XControlContainer.hpp>
#include <com/sun/star/uno/RuntimeException.hpp>
#include <com/sun/star/io/XInputStream.hpp>
#include <com/sun/star/io/XStream.hpp>
#include <com/sun/star/io/XSeekable.hpp>
#include <boost/scoped_ptr.hpp>
using namespace com::sun::star;
namespace pdfi
{
// TODO(T3): locking/thread safety
namespace {
typedef ::cppu::WeakComponentImplHelper1<
com::sun::star::awt::XDialogEventHandler > ChooserDialogHandlerBase;
class ChooserDialogHandler : private cppu::BaseMutex,
public ChooserDialogHandlerBase
{
uno::Reference<awt::XListBox> m_xListbox;
uno::Reference<awt::XWindow> m_xWriterText;
uno::Reference<awt::XWindow> m_xDrawText;
uno::Reference<awt::XWindow> m_xImpressText;
enum{ DRAW_INDEX=0, IMPRESS_INDEX=1, WRITER_INDEX=2 };
void selectionChanged( sal_Int32 nIndex ) const
{
sal_Bool bWriterState(sal_False);
sal_Bool bDrawState(sal_False);
sal_Bool bImpressState(sal_False);
switch(nIndex)
{
default:
OSL_ENSURE(false,"Unexpected case!");
break;
case DRAW_INDEX:
bDrawState=sal_True;
break;
case IMPRESS_INDEX:
bImpressState=sal_True;
break;
case WRITER_INDEX:
bWriterState=sal_True;
break;
}
m_xWriterText->setVisible(bWriterState);
m_xDrawText->setVisible(bDrawState);
m_xImpressText->setVisible(bImpressState);
}
public:
ChooserDialogHandler() :
ChooserDialogHandlerBase(m_aMutex),
m_xListbox(),
m_xWriterText(),
m_xDrawText(),
m_xImpressText()
{}
void initControls( const uno::Reference<awt::XControlContainer>& xControls,
const rtl::OUString& rFilename )
{
m_xListbox.set(xControls->getControl(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ListBox" ))),
uno::UNO_QUERY_THROW );
m_xWriterText.set(xControls->getControl(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InfoWriter" ))),
uno::UNO_QUERY_THROW );
m_xImpressText.set(xControls->getControl(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InfoImpress" ))),
uno::UNO_QUERY_THROW );
m_xDrawText.set(xControls->getControl(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InfoDraw" ))),
uno::UNO_QUERY_THROW );
uno::Reference<awt::XWindow> xControl;
xControl.set(xControls->getControl(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ListBoxWriter" ))),
uno::UNO_QUERY_THROW );
xControl->setVisible(sal_False);
xControl.set(xControls->getControl(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ListBoxImpress" ))),
uno::UNO_QUERY_THROW );
xControl->setVisible(sal_False);
xControl.set(xControls->getControl(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ListBoxDraw" ))),
uno::UNO_QUERY_THROW );
xControl->setVisible(sal_False);
uno::Reference<beans::XPropertySet> xPropSet(
xControls->getControl(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ComboLabel" )))->getModel(),
uno::UNO_QUERY_THROW );
rtl::OUString aFilename( rFilename.copy(rFilename.lastIndexOf('/')+1) );
rtl::OUString aLabel;
xPropSet->getPropertyValue(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Label" ))) >>= aLabel;
const char pFileName[] = "%FILENAME";
aLabel = aLabel.replaceAt(
aLabel.indexOfAsciiL(pFileName,sizeof(pFileName)/sizeof(*pFileName)-1),
sizeof(pFileName)/sizeof(*pFileName)-1,
aFilename );
xPropSet->setPropertyValue(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Label" )),
uno::makeAny(aLabel));
uno::Sequence<rtl::OUString> aListboxItems(3);
aListboxItems[DRAW_INDEX] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Drawing" ));
aListboxItems[IMPRESS_INDEX] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Presentation" ));
aListboxItems[WRITER_INDEX] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Text Document" ));
m_xListbox->addItems(aListboxItems,0);
m_xListbox->selectItemPos(0,sal_True);
selectionChanged(0);
}
sal_Int32 getSelectedItem() const
{
return m_xListbox->getSelectedItemPos();
}
virtual ::sal_Bool SAL_CALL callHandlerMethod( const uno::Reference< awt::XDialog >& /*xDialog*/,
const uno::Any& /*EventObject*/,
const ::rtl::OUString& MethodName ) throw (lang::WrappedTargetException, uno::RuntimeException)
{
(void)MethodName;
OSL_ENSURE( MethodName.compareToAscii("SelectionChanged") == 0,
"Invalid event name" );
selectionChanged(getSelectedItem());
return sal_True;
}
virtual uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedMethodNames( ) throw (uno::RuntimeException)
{
uno::Sequence< ::rtl::OUString > aMethods(1);
aMethods[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SelectionChanged" ));
return aMethods;
}
};
#if 0 // code currently unused (see below)
sal_Int32 queryDocumentTypeDialog( const uno::Reference<uno::XComponentContext>& xContext,
const rtl::OUString& rFilename )
{
uno::Reference<awt::XDialogProvider2> xDialogProvider(
xContext->getServiceManager()->createInstanceWithContext(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DialogProvider2" ) ),
xContext ),
uno::UNO_QUERY_THROW );
rtl::Reference<ChooserDialogHandler> xHandler(new ChooserDialogHandler);
uno::Reference<awt::XDialog> xDialog = xDialogProvider->createDialogWithHandler(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("vnd.sun.star.script:PDFImport.TargetChooser?location=application") ),
uno::Reference<awt::XDialogEventHandler>(
static_cast<cppu::OWeakObject*>(xHandler.get()), uno::UNO_QUERY_THROW));
xHandler->initControls(
uno::Reference<awt::XControlContainer>(
xDialog,
uno::UNO_QUERY_THROW ),
rFilename );
if( !xDialog->execute() )
return -1;
else
return xHandler->getSelectedItem();
}
#endif
}
class FileEmitContext : public pdfparse::EmitContext
{
private:
oslFileHandle m_aReadHandle;
unsigned int m_nReadLen;
uno::Reference< io::XStream > m_xContextStream;
uno::Reference< io::XSeekable > m_xSeek;
uno::Reference< io::XOutputStream > m_xOut;
public:
FileEmitContext( const rtl::OUString& rOrigFile,
const uno::Reference< uno::XComponentContext >& xContext,
const pdfparse::PDFContainer* pTop );
virtual ~FileEmitContext();
virtual bool write( const void* pBuf, unsigned int nLen );
virtual unsigned int getCurPos();
virtual bool copyOrigBytes( unsigned int nOrigOffset, unsigned int nLen );
virtual unsigned int readOrigBytes( unsigned int nOrigOffset, unsigned int nLen, void* pBuf );
const uno::Reference< io::XStream >& getContextStream() const { return m_xContextStream; }
};
FileEmitContext::FileEmitContext( const rtl::OUString& rOrigFile,
const uno::Reference< uno::XComponentContext >& xContext,
const pdfparse::PDFContainer* pTop ) :
pdfparse::EmitContext( pTop ),
m_aReadHandle(NULL),
m_nReadLen(0),
m_xContextStream(),
m_xSeek(),
m_xOut()
{
m_xContextStream = uno::Reference< io::XStream >(
xContext->getServiceManager()->createInstanceWithContext(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ),
xContext ), uno::UNO_QUERY_THROW );
m_xOut = m_xContextStream->getOutputStream();
m_xSeek = uno::Reference<io::XSeekable>(m_xOut, uno::UNO_QUERY_THROW );
oslFileError aErr = osl_File_E_None;
if( (aErr=osl_openFile( rOrigFile.pData,
&m_aReadHandle,
osl_File_OpenFlag_Read )) == osl_File_E_None )
{
if( (aErr=osl_setFilePos( m_aReadHandle,
osl_Pos_End,
0 )) == osl_File_E_None )
{
sal_uInt64 nFileSize = 0;
if( (aErr=osl_getFilePos( m_aReadHandle,
&nFileSize )) == osl_File_E_None )
{
m_nReadLen = static_cast<unsigned int>(nFileSize);
}
}
if( aErr != osl_File_E_None )
{
osl_closeFile( m_aReadHandle );
m_aReadHandle = NULL;
}
}
m_bDeflate = true;
}
FileEmitContext::~FileEmitContext()
{
if( m_aReadHandle )
osl_closeFile( m_aReadHandle );
}
bool FileEmitContext::write( const void* pBuf, unsigned int nLen )
{
if( ! m_xOut.is() )
return false;
uno::Sequence< sal_Int8 > aSeq( nLen );
rtl_copyMemory( aSeq.getArray(), pBuf, nLen );
m_xOut->writeBytes( aSeq );
return true;
}
unsigned int FileEmitContext::getCurPos()
{
unsigned int nPos = 0;
if( m_xSeek.is() )
{
nPos = static_cast<unsigned int>( m_xSeek->getPosition() );
}
return nPos;
}
bool FileEmitContext::copyOrigBytes( unsigned int nOrigOffset, unsigned int nLen )
{
if( nOrigOffset + nLen > m_nReadLen )
return false;
if( osl_setFilePos( m_aReadHandle, osl_Pos_Absolut, nOrigOffset ) != osl_File_E_None )
return false;
uno::Sequence< sal_Int8 > aSeq( nLen );
sal_uInt64 nBytesRead = 0;
if( osl_readFile( m_aReadHandle,
aSeq.getArray(),
nLen,
&nBytesRead ) != osl_File_E_None
|| nBytesRead != static_cast<sal_uInt64>(nLen) )
{
return false;
}
m_xOut->writeBytes( aSeq );
return true;
}
unsigned int FileEmitContext::readOrigBytes( unsigned int nOrigOffset, unsigned int nLen, void* pBuf )
{
if( nOrigOffset + nLen > m_nReadLen )
return 0;
if( osl_setFilePos( m_aReadHandle,
osl_Pos_Absolut,
nOrigOffset ) != osl_File_E_None )
{
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);
}
////////////////////////////////////////////////////////////////////////////////
PDFDetector::PDFDetector( const uno::Reference< uno::XComponentContext >& xContext) :
PDFDetectorBase( m_aMutex ),
m_xContext( xContext )
{}
// XExtendedFilterDetection
rtl::OUString SAL_CALL PDFDetector::detect( uno::Sequence< beans::PropertyValue >& rFilterData ) throw( uno::RuntimeException )
{
osl::MutexGuard const guard( m_aMutex );
bool bSuccess = false;
// get the InputStream carrying the PDF content
uno::Reference< io::XInputStream > xInput;
uno::Reference< io::XStream > xEmbedStream;
rtl::OUString aOutFilterName, aOutTypeName;
rtl::OUString aURL;
rtl::OUString aPwd;
const beans::PropertyValue* pAttribs = rFilterData.getConstArray();
sal_Int32 nAttribs = rFilterData.getLength();
sal_Int32 nFilterNamePos = -1;
sal_Int32 nPwdPos = -1;
for( sal_Int32 i = 0; i < nAttribs; i++ )
{
#if OSL_DEBUG_LEVEL > 1
rtl::OUString aVal( RTL_CONSTASCII_USTRINGPARAM( "<no string>" ) );
pAttribs[i].Value >>= aVal;
OSL_TRACE( "doDetection: Attrib: %s = %s\n",
rtl::OUStringToOString( pAttribs[i].Name, RTL_TEXTENCODING_UTF8 ).getStr(),
rtl::OUStringToOString( aVal, RTL_TEXTENCODING_UTF8 ).getStr() );
#endif
if( pAttribs[i].Name.equalsAscii( "InputStream" ) )
pAttribs[i].Value >>= xInput;
else if( pAttribs[i].Name.equalsAscii( "URL" ) )
pAttribs[i].Value >>= aURL;
else if( pAttribs[i].Name.equalsAscii( "FilterName" ) )
nFilterNamePos = i;
else if( pAttribs[i].Name.equalsAscii( "Password" ) )
{
nPwdPos = i;
pAttribs[i].Value >>= aPwd;
}
}
if( xInput.is() )
{
uno::Reference< io::XSeekable > xSeek( xInput, uno::UNO_QUERY );
if( xSeek.is() )
xSeek->seek( 0 );
// read the first 1024 byte (see PDF reference implementation note 12)
const sal_Int32 nHeaderSize = 1024;
uno::Sequence< sal_Int8 > aBuf( nHeaderSize );
sal_uInt64 nBytes = 0;
nBytes = xInput->readBytes( aBuf, nHeaderSize );
if( nBytes > 5 )
{
const sal_Int8* pBytes = aBuf.getConstArray();
for( unsigned int i = 0; i < nBytes-5; i++ )
{
if( pBytes[i] == '%' &&
pBytes[i+1] == 'P' &&
pBytes[i+2] == 'D' &&
pBytes[i+3] == 'F' &&
pBytes[i+4] == '-' )
{
bSuccess = true;
break;
}
}
}
// check for hybrid PDF
oslFileHandle aFile = NULL;
if( bSuccess &&
( aURL.getLength() == 0 || aURL.compareToAscii( "file:", 5 ) != 0 )
)
{
sal_uInt64 nWritten = 0;
if( osl_createTempFile( NULL, &aFile, &aURL.pData ) != osl_File_E_None )
{
bSuccess = false;
}
else
{
#if OSL_DEBUG_LEVEL > 1
OSL_TRACE( "created temp file %s\n",
rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() );
#endif
osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
OSL_ENSURE( nWritten == nBytes, "writing of header bytes failed" );
if( nWritten == nBytes )
{
const sal_uInt32 nBufSize = 4096;
aBuf = uno::Sequence<sal_Int8>(nBufSize);
// copy the bytes
do
{
nBytes = xInput->readBytes( aBuf, nBufSize );
if( nBytes > 0 )
{
osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
if( nWritten != nBytes )
{
bSuccess = false;
break;
}
}
} while( nBytes == nBufSize );
}
}
osl_closeFile( aFile );
}
rtl::OUString aEmbedMimetype;
xEmbedStream = getAdditionalStream( aURL, aEmbedMimetype, aPwd, m_xContext, rFilterData, false );
if( aFile )
osl_removeFile( aURL.pData );
if( aEmbedMimetype.getLength() )
{
if( aEmbedMimetype.equalsAscii( "application/vnd.oasis.opendocument.text" )
|| aEmbedMimetype.equalsAscii( "application/vnd.oasis.opendocument.text-master" ) )
aOutFilterName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "writer_pdf_addstream_import" ) );
else if( aEmbedMimetype.equalsAscii( "application/vnd.oasis.opendocument.presentation" ) )
aOutFilterName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "impress_pdf_addstream_import" ) );
else if( aEmbedMimetype.equalsAscii( "application/vnd.oasis.opendocument.graphics" )
|| aEmbedMimetype.equalsAscii( "application/vnd.oasis.opendocument.drawing" ) )
aOutFilterName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "draw_pdf_addstream_import" ) );
else if( aEmbedMimetype.equalsAscii( "application/vnd.oasis.opendocument.spreadsheet" ) )
aOutFilterName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "calc_pdf_addstream_import" ) );
}
}
if( bSuccess )
{
if( aOutFilterName.getLength() )
{
if( nFilterNamePos == -1 )
{
nFilterNamePos = nAttribs;
rFilterData.realloc( ++nAttribs );
rFilterData[ nFilterNamePos ].Name =
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ) );
}
aOutTypeName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("pdf_Portable_Document_Format") );
OSL_TRACE( "setting filter name %s, input stream %s\n",
rtl::OUStringToOString( aOutFilterName, RTL_TEXTENCODING_UTF8 ).getStr(),
xEmbedStream.is() ? "present" : "not present" );
rFilterData[nFilterNamePos].Value <<= aOutFilterName;
if( xEmbedStream.is() )
{
rFilterData.realloc( ++nAttribs );
rFilterData[nAttribs-1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EmbeddedSubstream" ) );
rFilterData[nAttribs-1].Value <<= xEmbedStream;
}
if( aPwd.getLength() )
{
if( nPwdPos == -1 )
{
nPwdPos = nAttribs;
rFilterData.realloc( ++nAttribs );
rFilterData[ nPwdPos ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Password" ) );
}
rFilterData[ nPwdPos ].Value <<= aPwd;
}
}
else
{
if( nFilterNamePos == -1 )
{
nFilterNamePos = nAttribs;
rFilterData.realloc( ++nAttribs );
rFilterData[ nFilterNamePos ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ) );
}
const sal_Int32 nDocumentType = 0; //const sal_Int32 nDocumentType = queryDocumentTypeDialog(m_xContext,aURL);
if( nDocumentType < 0 )
{
return rtl::OUString();
}
else switch( nDocumentType )
{
case 0:
rFilterData[nFilterNamePos].Value <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "draw_pdf_import" ) );
break;
case 1:
rFilterData[nFilterNamePos].Value <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "impress_pdf_import" ) );
break;
case 2:
rFilterData[nFilterNamePos].Value <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "writer_pdf_import" ) );
break;
default:
OSL_ENSURE(false,"Unexpected case");
}
aOutTypeName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("pdf_Portable_Document_Format") );
}
}
return aOutTypeName;
}
bool checkDocChecksum( const rtl::OUString& rInPDFFileURL,
sal_uInt32 nBytes,
const rtl::OUString& rChkSum )
{
bool bRet = false;
if( rChkSum.getLength() != 2* RTL_DIGEST_LENGTH_MD5 )
{
OSL_TRACE( "checksum of length %d, expected %d\n",
rChkSum.getLength(), 2*RTL_DIGEST_LENGTH_MD5 );
return false;
}
// prepare checksum to test
sal_uInt8 nTestChecksum[ RTL_DIGEST_LENGTH_MD5 ];
const sal_Unicode* pChar = rChkSum.getStr();
for( unsigned int i = 0; i < RTL_DIGEST_LENGTH_MD5; i++ )
{
sal_uInt8 nByte = sal_uInt8( ( (*pChar >= '0' && *pChar <= '9') ? *pChar - '0' :
( (*pChar >= 'A' && *pChar <= 'F') ? *pChar - 'A' + 10 :
( (*pChar >= 'a' && *pChar <= 'f') ? *pChar - 'a' + 10 :
0 ) ) ) );
nByte <<= 4;
pChar++;
nByte |= ( (*pChar >= '0' && *pChar <= '9') ? *pChar - '0' :
( (*pChar >= 'A' && *pChar <= 'F') ? *pChar - 'A' + 10 :
( (*pChar >= 'a' && *pChar <= 'f') ? *pChar - 'a' + 10 :
0 ) ) );
pChar++;
nTestChecksum[i] = nByte;
}
// open file and calculate actual checksum up to index nBytes
sal_uInt8 nActualChecksum[ RTL_DIGEST_LENGTH_MD5 ];
rtl_zeroMemory( nActualChecksum, sizeof(nActualChecksum) );
rtlDigest aActualDigest = rtl_digest_createMD5();
oslFileHandle aRead = NULL;
oslFileError aErr = osl_File_E_None;
if( (aErr = osl_openFile(rInPDFFileURL.pData,
&aRead,
osl_File_OpenFlag_Read )) == osl_File_E_None )
{
sal_Int8 aBuf[4096];
sal_uInt32 nCur = 0;
sal_uInt64 nBytesRead = 0;
while( nCur < nBytes )
{
sal_uInt32 nPass = (nBytes - nCur) > sizeof( aBuf ) ? sizeof( aBuf ) : nBytes - nCur;
if( (aErr = osl_readFile( aRead, aBuf, nPass, &nBytesRead)) != osl_File_E_None
|| nBytesRead == 0 )
{
break;
}
nPass = static_cast<sal_uInt32>(nBytesRead);
nCur += nPass;
rtl_digest_updateMD5( aActualDigest, aBuf, nPass );
}
rtl_digest_getMD5( aActualDigest, nActualChecksum, sizeof(nActualChecksum) );
osl_closeFile( aRead );
}
rtl_digest_destroyMD5( aActualDigest );
// compare the contents
bRet = (0 == rtl_compareMemory( nActualChecksum, nTestChecksum, sizeof( nActualChecksum ) ));
#if OSL_DEBUG_LEVEL > 1
OSL_TRACE( "test checksum: " );
for( unsigned int i = 0; i < sizeof(nTestChecksum); i++ )
OSL_TRACE( "%.2X", int(nTestChecksum[i]) );
OSL_TRACE( "\n" );
OSL_TRACE( "file checksum: " );
for( unsigned int i = 0; i < sizeof(nActualChecksum); i++ )
OSL_TRACE( "%.2X", int(nActualChecksum[i]) );
OSL_TRACE( "\n" );
#endif
return bRet;
}
uno::Reference< io::XStream > getAdditionalStream( const rtl::OUString& rInPDFFileURL,
rtl::OUString& rOutMimetype,
rtl::OUString& io_rPwd,
const uno::Reference<uno::XComponentContext>& xContext,
const uno::Sequence<beans::PropertyValue>& rFilterData,
bool bMayUseUI )
{
uno::Reference< io::XStream > xEmbed;
rtl::OString aPDFFile;
rtl::OUString aSysUPath;
if( osl_getSystemPathFromFileURL( rInPDFFileURL.pData, &aSysUPath.pData ) != osl_File_E_None )
return xEmbed;
aPDFFile = rtl::OUStringToOString( aSysUPath, osl_getThreadTextEncoding() );
pdfparse::PDFReader aParser;
boost::scoped_ptr<pdfparse::PDFEntry> pEntry( aParser.read( aPDFFile.getStr() ));
if( pEntry )
{
pdfparse::PDFFile* pPDFFile = dynamic_cast<pdfparse::PDFFile*>(pEntry.get());
if( pPDFFile )
{
unsigned int nElements = pPDFFile->m_aSubElements.size();
while( nElements-- > 0 )
{
pdfparse::PDFTrailer* pTrailer = dynamic_cast<pdfparse::PDFTrailer*>(pPDFFile->m_aSubElements[nElements]);
if( pTrailer && pTrailer->m_pDict )
{
// search document checksum entry
std::hash_map< rtl::OString,
pdfparse::PDFEntry*,
rtl::OStringHash >::iterator chk;
chk = pTrailer->m_pDict->m_aMap.find( "DocChecksum" );
if( chk == pTrailer->m_pDict->m_aMap.end() )
{
OSL_TRACE( "no DocChecksum entry\n" );
continue;
}
pdfparse::PDFName* pChkSumName = dynamic_cast<pdfparse::PDFName*>(chk->second);
if( pChkSumName == NULL )
{
OSL_TRACE( "no name for DocChecksum entry\n" );
continue;
}
// search for AdditionalStreams entry
std::hash_map< rtl::OString,
pdfparse::PDFEntry*,
rtl::OStringHash >::iterator add_stream;
add_stream = pTrailer->m_pDict->m_aMap.find( "AdditionalStreams" );
if( add_stream == pTrailer->m_pDict->m_aMap.end() )
{
OSL_TRACE( "no AdditionalStreams entry\n" );
continue;
}
pdfparse::PDFArray* pStreams = dynamic_cast<pdfparse::PDFArray*>(add_stream->second);
if( ! pStreams || pStreams->m_aSubElements.size() < 2 )
{
OSL_TRACE( "AdditionalStreams array too small\n" );
continue;
}
// check checksum
rtl::OUString aChkSum = pChkSumName->getFilteredName();
if( ! checkDocChecksum( rInPDFFileURL, pTrailer->m_nOffset, aChkSum ) )
continue;
// extract addstream and mimetype
pdfparse::PDFName* pMimeType = dynamic_cast<pdfparse::PDFName*>(pStreams->m_aSubElements[0]);
pdfparse::PDFObjectRef* pStreamRef = dynamic_cast<pdfparse::PDFObjectRef*>(pStreams->m_aSubElements[1]);
OSL_ENSURE( pMimeType, "error: no mimetype element\n" );
OSL_ENSURE( pStreamRef, "error: no stream ref element\n" );
if( pMimeType && pStreamRef )
{
pdfparse::PDFObject* pObject = pPDFFile->findObject( pStreamRef->m_nNumber, pStreamRef->m_nGeneration );
OSL_ENSURE( pObject, "object not found\n" );
if( pObject )
{
if( pPDFFile->isEncrypted() )
{
bool bAuthenticated = false;
if( io_rPwd.getLength() )
{
rtl::OString aIsoPwd = rtl::OUStringToOString( io_rPwd,
RTL_TEXTENCODING_ISO_8859_1 );
bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() );
// trash password string on heap
rtl_zeroMemory( (void*)aIsoPwd.getStr(), aIsoPwd.getLength() );
}
if( ! bAuthenticated )
{
const beans::PropertyValue* pAttribs = rFilterData.getConstArray();
sal_Int32 nAttribs = rFilterData.getLength();
uno::Reference< task::XInteractionHandler > xIntHdl;
for( sal_Int32 i = 0; i < nAttribs; i++ )
{
if( pAttribs[i].Name.equalsAscii( "InteractionHandler" ) )
pAttribs[i].Value >>= xIntHdl;
}
if( ! bMayUseUI || ! xIntHdl.is() )
{
rOutMimetype = pMimeType->getFilteredName();
xEmbed.clear();
break;
}
rtl::OUString aDocName( rInPDFFileURL.copy( rInPDFFileURL.lastIndexOf( sal_Unicode('/') )+1 ) );
bool bEntered = false;
do
{
bEntered = getPassword( xIntHdl, io_rPwd, ! bEntered, aDocName );
rtl::OString aIsoPwd = rtl::OUStringToOString( io_rPwd,
RTL_TEXTENCODING_ISO_8859_1 );
bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() );
// trash password string on heap
rtl_zeroMemory( (void*)aIsoPwd.getStr(), aIsoPwd.getLength() );
} while( bEntered && ! bAuthenticated );
}
OSL_TRACE( "password: %s\n", bAuthenticated ? "matches" : "does not match" );
if( ! bAuthenticated )
continue;
}
rOutMimetype = pMimeType->getFilteredName();
FileEmitContext aContext( rInPDFFileURL,
xContext,
pPDFFile );
aContext.m_bDecrypt = pPDFFile->isEncrypted();
pObject->writeStream( aContext, pPDFFile );
xEmbed = aContext.getContextStream();
break; // success
}
}
}
}
}
}
OSL_TRACE( "extracted add stream: mimetype %s\n",
rtl::OUStringToOString( rOutMimetype,
RTL_TEXTENCODING_UTF8 ).getStr());
return xEmbed;
}
}