update dev300-m58
[ooovba.git] / sdext / source / pdfimport / filterdet.cxx
blobaa40165b6d4a57630f73857a4549416888e37550
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: filterdet.cxx,v $
11 * $Revision: 1.2 $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_sdext.hxx"
35 #include "filterdet.hxx"
36 #include "inc/pdfparse.hxx"
38 #include <osl/diagnose.h>
39 #include <osl/file.h>
40 #include <osl/thread.h>
41 #include <rtl/digest.h>
42 #include <rtl/ref.hxx>
43 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/awt/XWindow.hpp>
46 #include <com/sun/star/awt/XListBox.hpp>
47 #include <com/sun/star/awt/XDialogEventHandler.hpp>
48 #include <com/sun/star/awt/XDialogProvider2.hpp>
49 #include <com/sun/star/awt/XControlContainer.hpp>
50 #include <com/sun/star/uno/RuntimeException.hpp>
51 #include <com/sun/star/io/XInputStream.hpp>
52 #include <com/sun/star/io/XStream.hpp>
53 #include <com/sun/star/io/XSeekable.hpp>
55 #include <boost/scoped_ptr.hpp>
57 using namespace com::sun::star;
59 namespace pdfi
62 // TODO(T3): locking/thread safety
64 namespace {
65 typedef ::cppu::WeakComponentImplHelper1<
66 com::sun::star::awt::XDialogEventHandler > ChooserDialogHandlerBase;
67 class ChooserDialogHandler : private cppu::BaseMutex,
68 public ChooserDialogHandlerBase
70 uno::Reference<awt::XListBox> m_xListbox;
71 uno::Reference<awt::XWindow> m_xWriterText;
72 uno::Reference<awt::XWindow> m_xDrawText;
73 uno::Reference<awt::XWindow> m_xImpressText;
75 enum{ DRAW_INDEX=0, IMPRESS_INDEX=1, WRITER_INDEX=2 };
76 void selectionChanged( sal_Int32 nIndex ) const
78 sal_Bool bWriterState(sal_False);
79 sal_Bool bDrawState(sal_False);
80 sal_Bool bImpressState(sal_False);
81 switch(nIndex)
83 default:
84 OSL_ENSURE(false,"Unexpected case!");
85 break;
86 case DRAW_INDEX:
87 bDrawState=sal_True;
88 break;
89 case IMPRESS_INDEX:
90 bImpressState=sal_True;
91 break;
92 case WRITER_INDEX:
93 bWriterState=sal_True;
94 break;
96 m_xWriterText->setVisible(bWriterState);
97 m_xDrawText->setVisible(bDrawState);
98 m_xImpressText->setVisible(bImpressState);
100 public:
101 ChooserDialogHandler() :
102 ChooserDialogHandlerBase(m_aMutex),
103 m_xListbox(),
104 m_xWriterText(),
105 m_xDrawText(),
106 m_xImpressText()
109 void initControls( const uno::Reference<awt::XControlContainer>& xControls,
110 const rtl::OUString& rFilename )
112 m_xListbox.set(xControls->getControl(
113 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ListBox" ))),
114 uno::UNO_QUERY_THROW );
115 m_xWriterText.set(xControls->getControl(
116 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InfoWriter" ))),
117 uno::UNO_QUERY_THROW );
118 m_xImpressText.set(xControls->getControl(
119 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InfoImpress" ))),
120 uno::UNO_QUERY_THROW );
121 m_xDrawText.set(xControls->getControl(
122 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InfoDraw" ))),
123 uno::UNO_QUERY_THROW );
125 uno::Reference<awt::XWindow> xControl;
126 xControl.set(xControls->getControl(
127 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ListBoxWriter" ))),
128 uno::UNO_QUERY_THROW );
129 xControl->setVisible(sal_False);
130 xControl.set(xControls->getControl(
131 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ListBoxImpress" ))),
132 uno::UNO_QUERY_THROW );
133 xControl->setVisible(sal_False);
134 xControl.set(xControls->getControl(
135 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ListBoxDraw" ))),
136 uno::UNO_QUERY_THROW );
137 xControl->setVisible(sal_False);
138 uno::Reference<beans::XPropertySet> xPropSet(
139 xControls->getControl(
140 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ComboLabel" )))->getModel(),
141 uno::UNO_QUERY_THROW );
142 rtl::OUString aFilename( rFilename.copy(rFilename.lastIndexOf('/')+1) );
143 rtl::OUString aLabel;
144 xPropSet->getPropertyValue(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Label" ))) >>= aLabel;
145 const char pFileName[] = "%FILENAME";
146 aLabel = aLabel.replaceAt(
147 aLabel.indexOfAsciiL(pFileName,sizeof(pFileName)/sizeof(*pFileName)-1),
148 sizeof(pFileName)/sizeof(*pFileName)-1,
149 aFilename );
150 xPropSet->setPropertyValue(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Label" )),
151 uno::makeAny(aLabel));
153 uno::Sequence<rtl::OUString> aListboxItems(3);
154 aListboxItems[DRAW_INDEX] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Drawing" ));
155 aListboxItems[IMPRESS_INDEX] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Presentation" ));
156 aListboxItems[WRITER_INDEX] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Text Document" ));
158 m_xListbox->addItems(aListboxItems,0);
159 m_xListbox->selectItemPos(0,sal_True);
160 selectionChanged(0);
163 sal_Int32 getSelectedItem() const
165 return m_xListbox->getSelectedItemPos();
168 virtual ::sal_Bool SAL_CALL callHandlerMethod( const uno::Reference< awt::XDialog >& /*xDialog*/,
169 const uno::Any& /*EventObject*/,
170 const ::rtl::OUString& MethodName ) throw (lang::WrappedTargetException, uno::RuntimeException)
172 (void)MethodName;
173 OSL_ENSURE( MethodName.compareToAscii("SelectionChanged") == 0,
174 "Invalid event name" );
175 selectionChanged(getSelectedItem());
176 return sal_True;
179 virtual uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedMethodNames( ) throw (uno::RuntimeException)
181 uno::Sequence< ::rtl::OUString > aMethods(1);
182 aMethods[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SelectionChanged" ));
183 return aMethods;
186 #if 0 // code currently unused (see below)
187 sal_Int32 queryDocumentTypeDialog( const uno::Reference<uno::XComponentContext>& xContext,
188 const rtl::OUString& rFilename )
190 uno::Reference<awt::XDialogProvider2> xDialogProvider(
191 xContext->getServiceManager()->createInstanceWithContext(
192 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DialogProvider2" ) ),
193 xContext ),
194 uno::UNO_QUERY_THROW );
195 rtl::Reference<ChooserDialogHandler> xHandler(new ChooserDialogHandler);
196 uno::Reference<awt::XDialog> xDialog = xDialogProvider->createDialogWithHandler(
197 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("vnd.sun.star.script:PDFImport.TargetChooser?location=application") ),
198 uno::Reference<awt::XDialogEventHandler>(
199 static_cast<cppu::OWeakObject*>(xHandler.get()), uno::UNO_QUERY_THROW));
200 xHandler->initControls(
201 uno::Reference<awt::XControlContainer>(
202 xDialog,
203 uno::UNO_QUERY_THROW ),
204 rFilename );
206 if( !xDialog->execute() )
207 return -1;
208 else
209 return xHandler->getSelectedItem();
211 #endif
214 class FileEmitContext : public pdfparse::EmitContext
216 private:
217 oslFileHandle m_aReadHandle;
218 unsigned int m_nReadLen;
219 uno::Reference< io::XStream > m_xContextStream;
220 uno::Reference< io::XSeekable > m_xSeek;
221 uno::Reference< io::XOutputStream > m_xOut;
223 public:
224 FileEmitContext( const rtl::OUString& rOrigFile,
225 const uno::Reference< uno::XComponentContext >& xContext,
226 const pdfparse::PDFContainer* pTop );
227 virtual ~FileEmitContext();
229 virtual bool write( const void* pBuf, unsigned int nLen );
230 virtual unsigned int getCurPos();
231 virtual bool copyOrigBytes( unsigned int nOrigOffset, unsigned int nLen );
232 virtual unsigned int readOrigBytes( unsigned int nOrigOffset, unsigned int nLen, void* pBuf );
234 const uno::Reference< io::XStream >& getContextStream() const { return m_xContextStream; }
237 FileEmitContext::FileEmitContext( const rtl::OUString& rOrigFile,
238 const uno::Reference< uno::XComponentContext >& xContext,
239 const pdfparse::PDFContainer* pTop ) :
240 pdfparse::EmitContext( pTop ),
241 m_aReadHandle(NULL),
242 m_nReadLen(0),
243 m_xContextStream(),
244 m_xSeek(),
245 m_xOut()
247 m_xContextStream = uno::Reference< io::XStream >(
248 xContext->getServiceManager()->createInstanceWithContext(
249 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ),
250 xContext ), uno::UNO_QUERY_THROW );
251 m_xOut = m_xContextStream->getOutputStream();
252 m_xSeek = uno::Reference<io::XSeekable>(m_xOut, uno::UNO_QUERY_THROW );
254 oslFileError aErr = osl_File_E_None;
255 if( (aErr=osl_openFile( rOrigFile.pData,
256 &m_aReadHandle,
257 osl_File_OpenFlag_Read )) == osl_File_E_None )
259 if( (aErr=osl_setFilePos( m_aReadHandle,
260 osl_Pos_End,
261 0 )) == osl_File_E_None )
263 sal_uInt64 nFileSize = 0;
264 if( (aErr=osl_getFilePos( m_aReadHandle,
265 &nFileSize )) == osl_File_E_None )
267 m_nReadLen = static_cast<unsigned int>(nFileSize);
270 if( aErr != osl_File_E_None )
272 osl_closeFile( m_aReadHandle );
273 m_aReadHandle = NULL;
276 m_bDeflate = true;
279 FileEmitContext::~FileEmitContext()
281 if( m_aReadHandle )
282 osl_closeFile( m_aReadHandle );
285 bool FileEmitContext::write( const void* pBuf, unsigned int nLen )
287 if( ! m_xOut.is() )
288 return false;
290 uno::Sequence< sal_Int8 > aSeq( nLen );
291 rtl_copyMemory( aSeq.getArray(), pBuf, nLen );
292 m_xOut->writeBytes( aSeq );
293 return true;
296 unsigned int FileEmitContext::getCurPos()
298 unsigned int nPos = 0;
299 if( m_xSeek.is() )
301 nPos = static_cast<unsigned int>( m_xSeek->getPosition() );
303 return nPos;
306 bool FileEmitContext::copyOrigBytes( unsigned int nOrigOffset, unsigned int nLen )
308 if( nOrigOffset + nLen > m_nReadLen )
309 return false;
311 if( osl_setFilePos( m_aReadHandle, osl_Pos_Absolut, nOrigOffset ) != osl_File_E_None )
312 return false;
314 uno::Sequence< sal_Int8 > aSeq( nLen );
316 sal_uInt64 nBytesRead = 0;
317 if( osl_readFile( m_aReadHandle,
318 aSeq.getArray(),
319 nLen,
320 &nBytesRead ) != osl_File_E_None
321 || nBytesRead != static_cast<sal_uInt64>(nLen) )
323 return false;
326 m_xOut->writeBytes( aSeq );
327 return true;
330 unsigned int FileEmitContext::readOrigBytes( unsigned int nOrigOffset, unsigned int nLen, void* pBuf )
332 if( nOrigOffset + nLen > m_nReadLen )
333 return 0;
335 if( osl_setFilePos( m_aReadHandle,
336 osl_Pos_Absolut,
337 nOrigOffset ) != osl_File_E_None )
339 return 0;
342 sal_uInt64 nBytesRead = 0;
343 if( osl_readFile( m_aReadHandle,
344 pBuf,
345 nLen,
346 &nBytesRead ) != osl_File_E_None )
348 return 0;
350 return static_cast<unsigned int>(nBytesRead);
354 ////////////////////////////////////////////////////////////////////////////////
357 PDFDetector::PDFDetector( const uno::Reference< uno::XComponentContext >& xContext) :
358 PDFDetectorBase( m_aMutex ),
359 m_xContext( xContext )
362 // XExtendedFilterDetection
363 rtl::OUString SAL_CALL PDFDetector::detect( uno::Sequence< beans::PropertyValue >& rFilterData ) throw( uno::RuntimeException )
365 osl::MutexGuard const guard( m_aMutex );
366 bool bSuccess = false;
368 // get the InputStream carrying the PDF content
369 uno::Reference< io::XInputStream > xInput;
370 uno::Reference< io::XStream > xEmbedStream;
371 rtl::OUString aOutFilterName, aOutTypeName;
372 rtl::OUString aURL;
373 rtl::OUString aPwd;
374 const beans::PropertyValue* pAttribs = rFilterData.getConstArray();
375 sal_Int32 nAttribs = rFilterData.getLength();
376 sal_Int32 nFilterNamePos = -1;
377 sal_Int32 nPwdPos = -1;
378 for( sal_Int32 i = 0; i < nAttribs; i++ )
380 #if OSL_DEBUG_LEVEL > 1
381 rtl::OUString aVal( RTL_CONSTASCII_USTRINGPARAM( "<no string>" ) );
382 pAttribs[i].Value >>= aVal;
383 OSL_TRACE( "doDetection: Attrib: %s = %s\n",
384 rtl::OUStringToOString( pAttribs[i].Name, RTL_TEXTENCODING_UTF8 ).getStr(),
385 rtl::OUStringToOString( aVal, RTL_TEXTENCODING_UTF8 ).getStr() );
386 #endif
387 if( pAttribs[i].Name.equalsAscii( "InputStream" ) )
388 pAttribs[i].Value >>= xInput;
389 else if( pAttribs[i].Name.equalsAscii( "URL" ) )
390 pAttribs[i].Value >>= aURL;
391 else if( pAttribs[i].Name.equalsAscii( "FilterName" ) )
392 nFilterNamePos = i;
393 else if( pAttribs[i].Name.equalsAscii( "Password" ) )
395 nPwdPos = i;
396 pAttribs[i].Value >>= aPwd;
399 if( xInput.is() )
401 uno::Reference< io::XSeekable > xSeek( xInput, uno::UNO_QUERY );
402 if( xSeek.is() )
403 xSeek->seek( 0 );
404 // read the first 1024 byte (see PDF reference implementation note 12)
405 const sal_Int32 nHeaderSize = 1024;
406 uno::Sequence< sal_Int8 > aBuf( nHeaderSize );
407 sal_uInt64 nBytes = 0;
408 nBytes = xInput->readBytes( aBuf, nHeaderSize );
409 if( nBytes > 5 )
411 const sal_Int8* pBytes = aBuf.getConstArray();
412 for( unsigned int i = 0; i < nBytes-5; i++ )
414 if( pBytes[i] == '%' &&
415 pBytes[i+1] == 'P' &&
416 pBytes[i+2] == 'D' &&
417 pBytes[i+3] == 'F' &&
418 pBytes[i+4] == '-' )
420 bSuccess = true;
421 break;
426 // check for hybrid PDF
427 oslFileHandle aFile = NULL;
428 if( bSuccess &&
429 ( aURL.getLength() == 0 || aURL.compareToAscii( "file:", 5 ) != 0 )
432 sal_uInt64 nWritten = 0;
433 if( osl_createTempFile( NULL, &aFile, &aURL.pData ) != osl_File_E_None )
435 bSuccess = false;
437 else
439 #if OSL_DEBUG_LEVEL > 1
440 OSL_TRACE( "created temp file %s\n",
441 rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() );
442 #endif
443 osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
445 OSL_ENSURE( nWritten == nBytes, "writing of header bytes failed" );
447 if( nWritten == nBytes )
449 const sal_uInt32 nBufSize = 4096;
450 aBuf = uno::Sequence<sal_Int8>(nBufSize);
451 // copy the bytes
454 nBytes = xInput->readBytes( aBuf, nBufSize );
455 if( nBytes > 0 )
457 osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
458 if( nWritten != nBytes )
460 bSuccess = false;
461 break;
464 } while( nBytes == nBufSize );
467 osl_closeFile( aFile );
469 rtl::OUString aEmbedMimetype;
470 xEmbedStream = getAdditionalStream( aURL, aEmbedMimetype, aPwd, m_xContext, rFilterData, false );
471 if( aFile )
472 osl_removeFile( aURL.pData );
473 if( aEmbedMimetype.getLength() )
475 if( aEmbedMimetype.equalsAscii( "application/vnd.oasis.opendocument.text" )
476 || aEmbedMimetype.equalsAscii( "application/vnd.oasis.opendocument.text-master" ) )
477 aOutFilterName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "writer_pdf_addstream_import" ) );
478 else if( aEmbedMimetype.equalsAscii( "application/vnd.oasis.opendocument.presentation" ) )
479 aOutFilterName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "impress_pdf_addstream_import" ) );
480 else if( aEmbedMimetype.equalsAscii( "application/vnd.oasis.opendocument.graphics" )
481 || aEmbedMimetype.equalsAscii( "application/vnd.oasis.opendocument.drawing" ) )
482 aOutFilterName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "draw_pdf_addstream_import" ) );
483 else if( aEmbedMimetype.equalsAscii( "application/vnd.oasis.opendocument.spreadsheet" ) )
484 aOutFilterName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "calc_pdf_addstream_import" ) );
488 if( bSuccess )
490 if( aOutFilterName.getLength() )
492 if( nFilterNamePos == -1 )
494 nFilterNamePos = nAttribs;
495 rFilterData.realloc( ++nAttribs );
496 rFilterData[ nFilterNamePos ].Name =
497 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ) );
499 aOutTypeName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("pdf_Portable_Document_Format") );
501 OSL_TRACE( "setting filter name %s, input stream %s\n",
502 rtl::OUStringToOString( aOutFilterName, RTL_TEXTENCODING_UTF8 ).getStr(),
503 xEmbedStream.is() ? "present" : "not present" );
505 rFilterData[nFilterNamePos].Value <<= aOutFilterName;
506 if( xEmbedStream.is() )
508 rFilterData.realloc( ++nAttribs );
509 rFilterData[nAttribs-1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EmbeddedSubstream" ) );
510 rFilterData[nAttribs-1].Value <<= xEmbedStream;
512 if( aPwd.getLength() )
514 if( nPwdPos == -1 )
516 nPwdPos = nAttribs;
517 rFilterData.realloc( ++nAttribs );
518 rFilterData[ nPwdPos ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Password" ) );
520 rFilterData[ nPwdPos ].Value <<= aPwd;
523 else
525 if( nFilterNamePos == -1 )
527 nFilterNamePos = nAttribs;
528 rFilterData.realloc( ++nAttribs );
529 rFilterData[ nFilterNamePos ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ) );
532 const sal_Int32 nDocumentType = 0; //const sal_Int32 nDocumentType = queryDocumentTypeDialog(m_xContext,aURL);
533 if( nDocumentType < 0 )
535 return rtl::OUString();
537 else switch( nDocumentType )
539 case 0:
540 rFilterData[nFilterNamePos].Value <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "draw_pdf_import" ) );
541 break;
543 case 1:
544 rFilterData[nFilterNamePos].Value <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "impress_pdf_import" ) );
545 break;
547 case 2:
548 rFilterData[nFilterNamePos].Value <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "writer_pdf_import" ) );
549 break;
551 default:
552 OSL_ENSURE(false,"Unexpected case");
555 aOutTypeName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("pdf_Portable_Document_Format") );
559 return aOutTypeName;
562 bool checkDocChecksum( const rtl::OUString& rInPDFFileURL,
563 sal_uInt32 nBytes,
564 const rtl::OUString& rChkSum )
566 bool bRet = false;
567 if( rChkSum.getLength() != 2* RTL_DIGEST_LENGTH_MD5 )
569 OSL_TRACE( "checksum of length %d, expected %d\n",
570 rChkSum.getLength(), 2*RTL_DIGEST_LENGTH_MD5 );
571 return false;
574 // prepare checksum to test
575 sal_uInt8 nTestChecksum[ RTL_DIGEST_LENGTH_MD5 ];
576 const sal_Unicode* pChar = rChkSum.getStr();
577 for( unsigned int i = 0; i < RTL_DIGEST_LENGTH_MD5; i++ )
579 sal_uInt8 nByte = sal_uInt8( ( (*pChar >= '0' && *pChar <= '9') ? *pChar - '0' :
580 ( (*pChar >= 'A' && *pChar <= 'F') ? *pChar - 'A' + 10 :
581 ( (*pChar >= 'a' && *pChar <= 'f') ? *pChar - 'a' + 10 :
582 0 ) ) ) );
583 nByte <<= 4;
584 pChar++;
585 nByte |= ( (*pChar >= '0' && *pChar <= '9') ? *pChar - '0' :
586 ( (*pChar >= 'A' && *pChar <= 'F') ? *pChar - 'A' + 10 :
587 ( (*pChar >= 'a' && *pChar <= 'f') ? *pChar - 'a' + 10 :
588 0 ) ) );
589 pChar++;
590 nTestChecksum[i] = nByte;
593 // open file and calculate actual checksum up to index nBytes
594 sal_uInt8 nActualChecksum[ RTL_DIGEST_LENGTH_MD5 ];
595 rtl_zeroMemory( nActualChecksum, sizeof(nActualChecksum) );
596 rtlDigest aActualDigest = rtl_digest_createMD5();
597 oslFileHandle aRead = NULL;
598 oslFileError aErr = osl_File_E_None;
599 if( (aErr = osl_openFile(rInPDFFileURL.pData,
600 &aRead,
601 osl_File_OpenFlag_Read )) == osl_File_E_None )
603 sal_Int8 aBuf[4096];
604 sal_uInt32 nCur = 0;
605 sal_uInt64 nBytesRead = 0;
606 while( nCur < nBytes )
608 sal_uInt32 nPass = (nBytes - nCur) > sizeof( aBuf ) ? sizeof( aBuf ) : nBytes - nCur;
609 if( (aErr = osl_readFile( aRead, aBuf, nPass, &nBytesRead)) != osl_File_E_None
610 || nBytesRead == 0 )
612 break;
614 nPass = static_cast<sal_uInt32>(nBytesRead);
615 nCur += nPass;
616 rtl_digest_updateMD5( aActualDigest, aBuf, nPass );
618 rtl_digest_getMD5( aActualDigest, nActualChecksum, sizeof(nActualChecksum) );
619 osl_closeFile( aRead );
621 rtl_digest_destroyMD5( aActualDigest );
623 // compare the contents
624 bRet = (0 == rtl_compareMemory( nActualChecksum, nTestChecksum, sizeof( nActualChecksum ) ));
625 #if OSL_DEBUG_LEVEL > 1
626 OSL_TRACE( "test checksum: " );
627 for( unsigned int i = 0; i < sizeof(nTestChecksum); i++ )
628 OSL_TRACE( "%.2X", int(nTestChecksum[i]) );
629 OSL_TRACE( "\n" );
630 OSL_TRACE( "file checksum: " );
631 for( unsigned int i = 0; i < sizeof(nActualChecksum); i++ )
632 OSL_TRACE( "%.2X", int(nActualChecksum[i]) );
633 OSL_TRACE( "\n" );
634 #endif
635 return bRet;
638 uno::Reference< io::XStream > getAdditionalStream( const rtl::OUString& rInPDFFileURL,
639 rtl::OUString& rOutMimetype,
640 rtl::OUString& io_rPwd,
641 const uno::Reference<uno::XComponentContext>& xContext,
642 const uno::Sequence<beans::PropertyValue>& rFilterData,
643 bool bMayUseUI )
645 uno::Reference< io::XStream > xEmbed;
646 rtl::OString aPDFFile;
647 rtl::OUString aSysUPath;
648 if( osl_getSystemPathFromFileURL( rInPDFFileURL.pData, &aSysUPath.pData ) != osl_File_E_None )
649 return xEmbed;
650 aPDFFile = rtl::OUStringToOString( aSysUPath, osl_getThreadTextEncoding() );
652 pdfparse::PDFReader aParser;
653 boost::scoped_ptr<pdfparse::PDFEntry> pEntry( aParser.read( aPDFFile.getStr() ));
654 if( pEntry )
656 pdfparse::PDFFile* pPDFFile = dynamic_cast<pdfparse::PDFFile*>(pEntry.get());
657 if( pPDFFile )
659 unsigned int nElements = pPDFFile->m_aSubElements.size();
660 while( nElements-- > 0 )
662 pdfparse::PDFTrailer* pTrailer = dynamic_cast<pdfparse::PDFTrailer*>(pPDFFile->m_aSubElements[nElements]);
663 if( pTrailer && pTrailer->m_pDict )
665 // search document checksum entry
666 std::hash_map< rtl::OString,
667 pdfparse::PDFEntry*,
668 rtl::OStringHash >::iterator chk;
669 chk = pTrailer->m_pDict->m_aMap.find( "DocChecksum" );
670 if( chk == pTrailer->m_pDict->m_aMap.end() )
672 OSL_TRACE( "no DocChecksum entry\n" );
673 continue;
675 pdfparse::PDFName* pChkSumName = dynamic_cast<pdfparse::PDFName*>(chk->second);
676 if( pChkSumName == NULL )
678 OSL_TRACE( "no name for DocChecksum entry\n" );
679 continue;
682 // search for AdditionalStreams entry
683 std::hash_map< rtl::OString,
684 pdfparse::PDFEntry*,
685 rtl::OStringHash >::iterator add_stream;
686 add_stream = pTrailer->m_pDict->m_aMap.find( "AdditionalStreams" );
687 if( add_stream == pTrailer->m_pDict->m_aMap.end() )
689 OSL_TRACE( "no AdditionalStreams entry\n" );
690 continue;
692 pdfparse::PDFArray* pStreams = dynamic_cast<pdfparse::PDFArray*>(add_stream->second);
693 if( ! pStreams || pStreams->m_aSubElements.size() < 2 )
695 OSL_TRACE( "AdditionalStreams array too small\n" );
696 continue;
699 // check checksum
700 rtl::OUString aChkSum = pChkSumName->getFilteredName();
701 if( ! checkDocChecksum( rInPDFFileURL, pTrailer->m_nOffset, aChkSum ) )
702 continue;
704 // extract addstream and mimetype
705 pdfparse::PDFName* pMimeType = dynamic_cast<pdfparse::PDFName*>(pStreams->m_aSubElements[0]);
706 pdfparse::PDFObjectRef* pStreamRef = dynamic_cast<pdfparse::PDFObjectRef*>(pStreams->m_aSubElements[1]);
708 OSL_ENSURE( pMimeType, "error: no mimetype element\n" );
709 OSL_ENSURE( pStreamRef, "error: no stream ref element\n" );
711 if( pMimeType && pStreamRef )
713 pdfparse::PDFObject* pObject = pPDFFile->findObject( pStreamRef->m_nNumber, pStreamRef->m_nGeneration );
714 OSL_ENSURE( pObject, "object not found\n" );
715 if( pObject )
717 if( pPDFFile->isEncrypted() )
719 bool bAuthenticated = false;
720 if( io_rPwd.getLength() )
722 rtl::OString aIsoPwd = rtl::OUStringToOString( io_rPwd,
723 RTL_TEXTENCODING_ISO_8859_1 );
724 bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() );
726 if( ! bAuthenticated )
728 const beans::PropertyValue* pAttribs = rFilterData.getConstArray();
729 sal_Int32 nAttribs = rFilterData.getLength();
730 uno::Reference< task::XInteractionHandler > xIntHdl;
731 for( sal_Int32 i = 0; i < nAttribs; i++ )
733 if( pAttribs[i].Name.equalsAscii( "InteractionHandler" ) )
734 pAttribs[i].Value >>= xIntHdl;
736 if( ! bMayUseUI || ! xIntHdl.is() )
738 rOutMimetype = pMimeType->getFilteredName();
739 xEmbed.clear();
740 break;
743 bool bEntered = false;
746 bEntered = getPassword( xIntHdl, io_rPwd, ! bEntered );
747 rtl::OString aIsoPwd = rtl::OUStringToOString( io_rPwd,
748 RTL_TEXTENCODING_ISO_8859_1 );
749 bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() );
750 } while( bEntered && ! bAuthenticated );
753 OSL_TRACE( "password: %s\n", bAuthenticated ? "matches" : "does not match" );
754 if( ! bAuthenticated )
755 continue;
757 rOutMimetype = pMimeType->getFilteredName();
758 FileEmitContext aContext( rInPDFFileURL,
759 xContext,
760 pPDFFile );
761 aContext.m_bDecrypt = pPDFFile->isEncrypted();
762 pObject->writeStream( aContext, pPDFFile );
763 xEmbed = aContext.getContextStream();
764 break; // success
772 OSL_TRACE( "extracted add stream: mimetype %s\n",
773 rtl::OUStringToOString( rOutMimetype,
774 RTL_TEXTENCODING_UTF8 ).getStr());
775 return xEmbed;