26 #include <osl/thread.h>
27 #include <rtl/digest.h>
29 #include <com/sun/star/io/IOException.hpp>
30 #include <com/sun/star/io/XInputStream.hpp>
31 #include <com/sun/star/io/XStream.hpp>
32 #include <com/sun/star/io/XSeekable.hpp>
33 #include <com/sun/star/io/TempFile.hpp>
34 #include <com/sun/star/task/XInteractionHandler.hpp>
58 uno::Reference< io::XOutputStream >
m_xOut;
61 FileEmitContext(
const OUString& rOrigFile,
62 const uno::Reference< uno::XComponentContext >& xContext,
64 virtual ~FileEmitContext()
override;
66 virtual bool write(
const void* pBuf,
unsigned int nLen )
override;
67 virtual unsigned int getCurPos()
override;
68 virtual bool copyOrigBytes(
unsigned int nOrigOffset,
unsigned int nLen )
override;
69 virtual unsigned int readOrigBytes(
unsigned int nOrigOffset,
unsigned int nLen,
void* pBuf )
override;
71 const uno::Reference< io::XStream >& getContextStream()
const {
return m_xContextStream; }
76 FileEmitContext::FileEmitContext(
const OUString& rOrigFile,
77 const uno::Reference< uno::XComponentContext >& xContext,
86 m_xContextStream.set( io::TempFile::create(xContext), uno::UNO_QUERY_THROW );
90 if( osl_openFile( rOrigFile.pData,
92 osl_File_OpenFlag_Read ) == osl_File_E_None )
94 oslFileError aErr = osl_setFilePos(
m_aReadHandle, osl_Pos_End, 0 );
95 if( aErr == osl_File_E_None )
97 sal_uInt64 nFileSize = 0;
99 &nFileSize )) == osl_File_E_None )
101 m_nReadLen =
static_cast<unsigned int>(nFileSize);
104 if( aErr != osl_File_E_None )
113 FileEmitContext::~FileEmitContext()
119 bool FileEmitContext::write(
const void* pBuf,
unsigned int nLen )
124 uno::Sequence< sal_Int8 >
aSeq( nLen );
125 memcpy(
aSeq.getArray(), pBuf, nLen );
126 m_xOut->writeBytes( aSeq );
130 unsigned int FileEmitContext::getCurPos()
132 unsigned int nPos = 0;
135 nPos =
static_cast<unsigned int>(
m_xSeek->getPosition() );
140 bool FileEmitContext::copyOrigBytes(
unsigned int nOrigOffset,
unsigned int nLen )
145 if( osl_setFilePos(
m_aReadHandle, osl_Pos_Absolut, nOrigOffset ) != osl_File_E_None )
148 uno::Sequence< sal_Int8 >
aSeq( nLen );
150 sal_uInt64 nBytesRead = 0;
154 &nBytesRead ) != osl_File_E_None
155 || nBytesRead != static_cast<sal_uInt64>(nLen) )
160 m_xOut->writeBytes( aSeq );
164 unsigned int FileEmitContext::readOrigBytes(
unsigned int nOrigOffset,
unsigned int nLen,
void* pBuf )
171 nOrigOffset ) != osl_File_E_None )
176 sal_uInt64 nBytesRead = 0;
180 &nBytesRead ) != osl_File_E_None )
184 return static_cast<unsigned int>(nBytesRead);
188 PDFDetector::PDFDetector(
const uno::Reference< uno::XComponentContext >& xContext) :
196 osl::MutexGuard
const guard(
m_aMutex );
197 bool bSuccess =
false;
200 uno::Reference< io::XInputStream > xInput;
201 uno::Reference< io::XStream > xEmbedStream;
202 OUString aOutFilterName, aOutTypeName;
205 const beans::PropertyValue* pAttribs = rFilterData.getConstArray();
206 sal_Int32 nAttribs = rFilterData.getLength();
207 sal_Int32 nFilterNamePos = -1;
208 sal_Int32 nPwdPos = -1;
209 for( sal_Int32
i = 0;
i < nAttribs;
i++ )
211 OUString aVal(
"<no string>" );
212 pAttribs[
i].Value >>= aVal;
213 SAL_INFO(
"sdext.pdfimport",
"doDetection: Attrib: " + pAttribs[
i].
Name +
" = " + aVal);
215 if ( pAttribs[
i].
Name ==
"InputStream" )
216 pAttribs[
i].Value >>= xInput;
217 else if ( pAttribs[
i].
Name ==
"URL" )
218 pAttribs[
i].Value >>= aURL;
219 else if ( pAttribs[
i].
Name ==
"FilterName" )
221 else if ( pAttribs[
i].
Name ==
"Password" )
224 pAttribs[
i].Value >>= aPwd;
229 oslFileHandle aFile =
nullptr;
231 uno::Reference< io::XSeekable > xSeek( xInput, uno::UNO_QUERY );
235 const sal_Int32 nHeaderSize = 1024;
236 uno::Sequence< sal_Int8 >
aBuf( nHeaderSize );
237 sal_uInt64 nBytes = xInput->readBytes( aBuf, nHeaderSize );
240 const sal_Int8* pBytes = aBuf.getConstArray();
241 for( sal_uInt64
i = 0;
i < nBytes-5;
i++ )
243 if( pBytes[
i] ==
'%' &&
244 pBytes[
i+1] ==
'P' &&
245 pBytes[
i+2] ==
'D' &&
246 pBytes[
i+3] ==
'F' &&
260 sal_uInt64 nWritten = 0;
261 if( osl_createTempFile(
nullptr, &aFile, &aURL.pData ) != osl_File_E_None )
267 SAL_INFO(
"sdext.pdfimport",
"created temp file " + aURL );
269 osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
271 SAL_WARN_IF( nWritten != nBytes,
"sdext.pdfimport",
"writing of header bytes failed" );
273 if( nWritten == nBytes )
275 const sal_uInt32 nBufSize = 4096;
276 aBuf = uno::Sequence<sal_Int8>(nBufSize);
280 nBytes = xInput->readBytes( aBuf, nBufSize );
283 osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
284 if( nWritten != nBytes )
290 }
while( nBytes == nBufSize );
293 osl_closeFile( aFile );
295 }
catch (
const css::io::IOException &) {
299 OUString aEmbedMimetype;
302 osl_removeFile( aURL.pData );
303 if( !aEmbedMimetype.isEmpty() )
305 if( aEmbedMimetype ==
"application/vnd.oasis.opendocument.text"
306 || aEmbedMimetype ==
"application/vnd.oasis.opendocument.text-master" )
307 aOutFilterName =
"writer_pdf_addstream_import";
308 else if ( aEmbedMimetype ==
"application/vnd.oasis.opendocument.presentation" )
309 aOutFilterName =
"impress_pdf_addstream_import";
310 else if( aEmbedMimetype ==
"application/vnd.oasis.opendocument.graphics"
311 || aEmbedMimetype ==
"application/vnd.oasis.opendocument.drawing" )
312 aOutFilterName =
"draw_pdf_addstream_import";
313 else if ( aEmbedMimetype ==
"application/vnd.oasis.opendocument.spreadsheet" )
314 aOutFilterName =
"calc_pdf_addstream_import";
320 if( !aOutFilterName.isEmpty() )
322 if( nFilterNamePos == -1 )
324 nFilterNamePos = nAttribs;
325 rFilterData.realloc( ++nAttribs );
326 rFilterData[ nFilterNamePos ].Name =
"FilterName";
328 aOutTypeName =
"pdf_Portable_Document_Format";
330 rFilterData[nFilterNamePos].Value <<= aOutFilterName;
331 if( xEmbedStream.is() )
333 rFilterData.realloc( ++nAttribs );
334 rFilterData[nAttribs-1].Name =
"EmbeddedSubstream";
335 rFilterData[nAttribs-1].Value <<= xEmbedStream;
337 if( !aPwd.isEmpty() )
342 rFilterData.realloc( ++nAttribs );
343 rFilterData[ nPwdPos ].Name =
"Password";
345 rFilterData[ nPwdPos ].Value <<= aPwd;
350 if( nFilterNamePos == -1 )
352 nFilterNamePos = nAttribs;
353 rFilterData.realloc( ++nAttribs );
354 rFilterData[ nFilterNamePos ].Name =
"FilterName";
357 const sal_Int32 nDocumentType = 0;
358 if( nDocumentType < 0 )
362 else switch( nDocumentType )
365 rFilterData[nFilterNamePos].Value <<= OUString(
"draw_pdf_import" );
369 rFilterData[nFilterNamePos].Value <<= OUString(
"impress_pdf_import" );
373 rFilterData[nFilterNamePos].Value <<= OUString(
"writer_pdf_import" );
377 assert(!
"Unexpected case");
380 aOutTypeName =
"pdf_Portable_Document_Format";
389 return "org.libreoffice.comp.documents.PDFDetector";
399 return {
"com.sun.star.document.ImportFilter"};
404 const OUString& rChkSum )
406 if( rChkSum.getLength() != 2* RTL_DIGEST_LENGTH_MD5 )
410 "checksum of length " << rChkSum.getLength() <<
", expected "
411 << 2*RTL_DIGEST_LENGTH_MD5);
416 sal_uInt8 nTestChecksum[ RTL_DIGEST_LENGTH_MD5 ];
421 ( (*pChar >=
'A' && *pChar <=
'F') ? *pChar -
'A' + 10 :
422 ( (*pChar >=
'a' && *pChar <=
'f') ? *pChar -
'a' + 10 :
426 nByte |= ( (*pChar >=
'0' && *pChar <=
'9') ? *pChar -
'0' :
427 ( (*pChar >=
'A' && *pChar <=
'F') ? *pChar -
'A' + 10 :
428 ( (*pChar >=
'a' && *pChar <=
'f') ? *pChar -
'a' + 10 :
435 ::std::vector<unsigned char> nChecksum;
437 oslFileHandle aRead =
nullptr;
438 if( osl_openFile(rInPDFFileURL.pData,
440 osl_File_OpenFlag_Read ) == osl_File_E_None )
444 sal_uInt64 nBytesRead = 0;
445 while( nCur < nBytes )
447 sal_uInt32 nPass = std::min<sal_uInt32>(nBytes - nCur,
sizeof( aBuf ));
448 if( osl_readFile( aRead, aBuf, nPass, &nBytesRead) != osl_File_E_None
453 nPass =
static_cast<sal_uInt32
>(nBytesRead);
455 aDigest.
update(aBuf, nPass);
459 osl_closeFile( aRead );
463 return nChecksum.size() == RTL_DIGEST_LENGTH_MD5
464 && (0 == memcmp(nChecksum.data(), nTestChecksum, nChecksum.size()));
468 OUString& rOutMimetype,
470 const uno::Reference<uno::XComponentContext>& xContext,
471 const uno::Sequence<beans::PropertyValue>& rFilterData,
474 uno::Reference< io::XStream > xEmbed;
477 if( osl_getSystemPathFromFileURL( rInPDFFileURL.pData, &aSysUPath.pData ) != osl_File_E_None )
488 while( nElements-- > 0 )
491 if( pTrailer && pTrailer->
m_pDict )
497 SAL_INFO(
"sdext.pdfimport",
"no DocChecksum entry" );
501 if( pChkSumName ==
nullptr )
503 SAL_INFO(
"sdext.pdfimport",
"no name for DocChecksum entry" );
508 auto add_stream = pTrailer->
m_pDict->
m_aMap.find(
"AdditionalStreams" );
511 SAL_INFO(
"sdext.pdfimport",
"no AdditionalStreams entry" );
517 SAL_INFO(
"sdext.pdfimport",
"AdditionalStreams array too small" );
530 SAL_WARN_IF( !pMimeType,
"sdext.pdfimport",
"error: no mimetype element" );
531 SAL_WARN_IF( !pStreamRef,
"sdext.pdfimport",
"error: no stream ref element" );
533 if( pMimeType && pStreamRef )
536 SAL_WARN_IF( !pObject,
"sdext.pdfimport",
"object not found" );
541 bool bAuthenticated =
false;
542 if( !io_rPwd.isEmpty() )
545 RTL_TEXTENCODING_ISO_8859_1 );
548 if( ! bAuthenticated )
550 uno::Reference< task::XInteractionHandler > xIntHdl;
551 for(
const beans::PropertyValue& rAttrib : rFilterData )
553 if ( rAttrib.Name ==
"InteractionHandler" )
554 rAttrib.Value >>= xIntHdl;
556 if( ! bMayUseUI || ! xIntHdl.is() )
563 OUString aDocName( rInPDFFileURL.copy( rInPDFFileURL.lastIndexOf(
'/' )+1 ) );
565 bool bEntered =
false;
568 bEntered =
getPassword( xIntHdl, io_rPwd, ! bEntered, aDocName );
570 RTL_TEXTENCODING_ISO_8859_1 );
572 }
while( bEntered && ! bAuthenticated );
575 if( ! bAuthenticated )
579 FileEmitContext aContext( rInPDFFileURL,
584 xEmbed = aContext.getContextStream();
597 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
599 css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any>
const&)
static std::unique_ptr< PDFEntry > read(const char *pFileName)
PDFObject * findObject(unsigned int nNumber, unsigned int nGeneration) const
mutable::osl::Mutex m_aMutex
unsigned int m_nGeneration
EmbeddedObjectRef * pObject
std::vector< std::unique_ptr< PDFEntry > > m_aSubElements
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
uno::Reference< io::XStream > getAdditionalStream(const OUString &rInPDFFileURL, OUString &rOutMimetype, OUString &io_rPwd, const uno::Reference< uno::XComponentContext > &xContext, const uno::Sequence< beans::PropertyValue > &rFilterData, bool bMayUseUI)
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
bool checkDocChecksum(const OUString &rInPDFFileURL, sal_uInt32 nBytes, const OUString &rChkSum)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * sdext_PDFDetector_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
::cppu::WeakComponentImplHelper< css::document::XExtendedFilterDetection, css::lang::XServiceInfo > PDFDetectorBase
OUString getFilteredName() const
uno::Reference< io::XOutputStream > m_xOut
#define TOOLS_WARN_EXCEPTION(area, stream)
css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
oslFileHandle m_aReadHandle
bool getPassword(const css::uno::Reference< css::task::XInteractionHandler > &xHandler, OUString &rOutPwd, bool bFirstTry, const OUString &rDocName)
retrieve password from user
css::uno::Reference< css::uno::XComponentContext > m_xContext
uno::Reference< io::XSeekable > m_xSeek
uno::Reference< io::XStream > m_xContextStream
#define SAL_WARN_IF(condition, area, stream)
void update(const unsigned char *pInput, size_t length)
COMPHELPER_DLLPUBLIC bool isFileUrl(OUString const &url)
#define SAL_INFO(area, stream)
Sequence< sal_Int8 > aSeq
virtual OUString SAL_CALL detect(css::uno::Sequence< css::beans::PropertyValue > &io_rDescriptor) override
bool setupDecryptionData(const OString &rPwd) const
std::vector< unsigned char > finalize()
OUString SAL_CALL getImplementationName() override
sal_Bool SAL_CALL supportsService(OUString const &ServiceName) override
const uno::Reference< uno::XComponentContext > m_xContext
void writeStream(EmitContext &rContext, const PDFFile *pPDFFile) const