Updated core
[LibreOffice.git] / sdext / source / pdfimport / filterdet.cxx
blob032ac577772140f21b702fff89779f8ccfb56e05
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "filterdet.hxx"
22 #include "inc/pdfparse.hxx"
24 #include <osl/diagnose.h>
25 #include <osl/file.h>
26 #include <osl/thread.h>
27 #include <rtl/digest.h>
28 #include <rtl/ref.hxx>
29 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/awt/XWindow.hpp>
32 #include <com/sun/star/awt/XListBox.hpp>
33 #include <com/sun/star/awt/XDialogEventHandler.hpp>
34 #include <com/sun/star/awt/XDialogProvider2.hpp>
35 #include <com/sun/star/awt/XControlContainer.hpp>
36 #include <com/sun/star/uno/RuntimeException.hpp>
37 #include <com/sun/star/io/XInputStream.hpp>
38 #include <com/sun/star/io/XStream.hpp>
39 #include <com/sun/star/io/XSeekable.hpp>
40 #include <com/sun/star/io/TempFile.hpp>
42 #include <boost/scoped_ptr.hpp>
43 #include <string.h>
45 using namespace com::sun::star;
47 namespace pdfi
50 // TODO(T3): locking/thread safety
52 namespace {
53 typedef ::cppu::WeakComponentImplHelper1<
54 com::sun::star::awt::XDialogEventHandler > ChooserDialogHandlerBase;
55 class ChooserDialogHandler : private cppu::BaseMutex,
56 public ChooserDialogHandlerBase
58 uno::Reference<awt::XListBox> m_xListbox;
59 uno::Reference<awt::XWindow> m_xWriterText;
60 uno::Reference<awt::XWindow> m_xDrawText;
61 uno::Reference<awt::XWindow> m_xImpressText;
63 enum{ DRAW_INDEX=0, IMPRESS_INDEX=1, WRITER_INDEX=2 };
64 void selectionChanged( sal_Int32 nIndex ) const
66 sal_Bool bWriterState(sal_False);
67 sal_Bool bDrawState(sal_False);
68 sal_Bool bImpressState(sal_False);
69 switch(nIndex)
71 default:
72 OSL_FAIL("Unexpected case!");
73 break;
74 case DRAW_INDEX:
75 bDrawState=sal_True;
76 break;
77 case IMPRESS_INDEX:
78 bImpressState=sal_True;
79 break;
80 case WRITER_INDEX:
81 bWriterState=sal_True;
82 break;
84 m_xWriterText->setVisible(bWriterState);
85 m_xDrawText->setVisible(bDrawState);
86 m_xImpressText->setVisible(bImpressState);
88 public:
89 ChooserDialogHandler() :
90 ChooserDialogHandlerBase(m_aMutex),
91 m_xListbox(),
92 m_xWriterText(),
93 m_xDrawText(),
94 m_xImpressText()
97 void initControls( const uno::Reference<awt::XControlContainer>& xControls,
98 const OUString& rFilename )
100 m_xListbox.set(xControls->getControl(
101 OUString( "ListBox" )),
102 uno::UNO_QUERY_THROW );
103 m_xWriterText.set(xControls->getControl(
104 OUString( "InfoWriter" )),
105 uno::UNO_QUERY_THROW );
106 m_xImpressText.set(xControls->getControl(
107 OUString( "InfoImpress" )),
108 uno::UNO_QUERY_THROW );
109 m_xDrawText.set(xControls->getControl(
110 OUString( "InfoDraw" )),
111 uno::UNO_QUERY_THROW );
113 uno::Reference<awt::XWindow> xControl;
114 xControl.set(xControls->getControl(
115 OUString( "ListBoxWriter" )),
116 uno::UNO_QUERY_THROW );
117 xControl->setVisible(sal_False);
118 xControl.set(xControls->getControl(
119 OUString( "ListBoxImpress" )),
120 uno::UNO_QUERY_THROW );
121 xControl->setVisible(sal_False);
122 xControl.set(xControls->getControl(
123 OUString( "ListBoxDraw" )),
124 uno::UNO_QUERY_THROW );
125 xControl->setVisible(sal_False);
126 uno::Reference<beans::XPropertySet> xPropSet(
127 xControls->getControl(
128 OUString( "ComboLabel" ))->getModel(),
129 uno::UNO_QUERY_THROW );
130 OUString aFilename( rFilename.copy(rFilename.lastIndexOf('/')+1) );
131 OUString aLabel;
132 xPropSet->getPropertyValue(OUString( "Label" )) >>= aLabel;
133 const char pFileName[] = "%FILENAME";
134 aLabel = aLabel.replaceAt(
135 aLabel.indexOfAsciiL(pFileName,SAL_N_ELEMENTS(pFileName)-1),
136 SAL_N_ELEMENTS(pFileName)-1,
137 aFilename );
138 xPropSet->setPropertyValue(OUString( "Label" ),
139 uno::makeAny(aLabel));
141 uno::Sequence<OUString> aListboxItems(3);
142 aListboxItems[DRAW_INDEX] = OUString( "Drawing" );
143 aListboxItems[IMPRESS_INDEX] = OUString( "Presentation" );
144 aListboxItems[WRITER_INDEX] = OUString( "Text Document" );
146 m_xListbox->addItems(aListboxItems,0);
147 m_xListbox->selectItemPos(0,sal_True);
148 selectionChanged(0);
151 sal_Int32 getSelectedItem() const
153 return m_xListbox->getSelectedItemPos();
156 virtual ::sal_Bool SAL_CALL callHandlerMethod( const uno::Reference< awt::XDialog >& /*xDialog*/,
157 const uno::Any& /*EventObject*/,
158 const OUString& MethodName ) throw (lang::WrappedTargetException, uno::RuntimeException)
160 (void)MethodName;
161 OSL_ENSURE( MethodName.compareToAscii("SelectionChanged") == 0,
162 "Invalid event name" );
163 selectionChanged(getSelectedItem());
164 return sal_True;
167 virtual uno::Sequence< OUString > SAL_CALL getSupportedMethodNames( ) throw (uno::RuntimeException)
169 uno::Sequence< OUString > aMethods(1);
170 aMethods[0] = OUString( "SelectionChanged" );
171 return aMethods;
176 class FileEmitContext : public pdfparse::EmitContext
178 private:
179 oslFileHandle m_aReadHandle;
180 unsigned int m_nReadLen;
181 uno::Reference< io::XStream > m_xContextStream;
182 uno::Reference< io::XSeekable > m_xSeek;
183 uno::Reference< io::XOutputStream > m_xOut;
185 public:
186 FileEmitContext( const OUString& rOrigFile,
187 const uno::Reference< uno::XComponentContext >& xContext,
188 const pdfparse::PDFContainer* pTop );
189 virtual ~FileEmitContext();
191 virtual bool write( const void* pBuf, unsigned int nLen );
192 virtual unsigned int getCurPos();
193 virtual bool copyOrigBytes( unsigned int nOrigOffset, unsigned int nLen );
194 virtual unsigned int readOrigBytes( unsigned int nOrigOffset, unsigned int nLen, void* pBuf );
196 const uno::Reference< io::XStream >& getContextStream() const { return m_xContextStream; }
199 FileEmitContext::FileEmitContext( const OUString& rOrigFile,
200 const uno::Reference< uno::XComponentContext >& xContext,
201 const pdfparse::PDFContainer* pTop ) :
202 pdfparse::EmitContext( pTop ),
203 m_aReadHandle(NULL),
204 m_nReadLen(0),
205 m_xContextStream(),
206 m_xSeek(),
207 m_xOut()
209 m_xContextStream = uno::Reference< io::XStream >(
210 io::TempFile::create(xContext), uno::UNO_QUERY_THROW );
211 m_xOut = m_xContextStream->getOutputStream();
212 m_xSeek = uno::Reference<io::XSeekable>(m_xOut, uno::UNO_QUERY_THROW );
214 oslFileError aErr = osl_File_E_None;
215 if( (aErr=osl_openFile( rOrigFile.pData,
216 &m_aReadHandle,
217 osl_File_OpenFlag_Read )) == osl_File_E_None )
219 if( (aErr=osl_setFilePos( m_aReadHandle,
220 osl_Pos_End,
221 0 )) == osl_File_E_None )
223 sal_uInt64 nFileSize = 0;
224 if( (aErr=osl_getFilePos( m_aReadHandle,
225 &nFileSize )) == osl_File_E_None )
227 m_nReadLen = static_cast<unsigned int>(nFileSize);
230 if( aErr != osl_File_E_None )
232 osl_closeFile( m_aReadHandle );
233 m_aReadHandle = NULL;
236 m_bDeflate = true;
239 FileEmitContext::~FileEmitContext()
241 if( m_aReadHandle )
242 osl_closeFile( m_aReadHandle );
245 bool FileEmitContext::write( const void* pBuf, unsigned int nLen )
247 if( ! m_xOut.is() )
248 return false;
250 uno::Sequence< sal_Int8 > aSeq( nLen );
251 memcpy( aSeq.getArray(), pBuf, nLen );
252 m_xOut->writeBytes( aSeq );
253 return true;
256 unsigned int FileEmitContext::getCurPos()
258 unsigned int nPos = 0;
259 if( m_xSeek.is() )
261 nPos = static_cast<unsigned int>( m_xSeek->getPosition() );
263 return nPos;
266 bool FileEmitContext::copyOrigBytes( unsigned int nOrigOffset, unsigned int nLen )
268 if( nOrigOffset + nLen > m_nReadLen )
269 return false;
271 if( osl_setFilePos( m_aReadHandle, osl_Pos_Absolut, nOrigOffset ) != osl_File_E_None )
272 return false;
274 uno::Sequence< sal_Int8 > aSeq( nLen );
276 sal_uInt64 nBytesRead = 0;
277 if( osl_readFile( m_aReadHandle,
278 aSeq.getArray(),
279 nLen,
280 &nBytesRead ) != osl_File_E_None
281 || nBytesRead != static_cast<sal_uInt64>(nLen) )
283 return false;
286 m_xOut->writeBytes( aSeq );
287 return true;
290 unsigned int FileEmitContext::readOrigBytes( unsigned int nOrigOffset, unsigned int nLen, void* pBuf )
292 if( nOrigOffset + nLen > m_nReadLen )
293 return 0;
295 if( osl_setFilePos( m_aReadHandle,
296 osl_Pos_Absolut,
297 nOrigOffset ) != osl_File_E_None )
299 return 0;
302 sal_uInt64 nBytesRead = 0;
303 if( osl_readFile( m_aReadHandle,
304 pBuf,
305 nLen,
306 &nBytesRead ) != osl_File_E_None )
308 return 0;
310 return static_cast<unsigned int>(nBytesRead);
314 ////////////////////////////////////////////////////////////////////////////////
317 PDFDetector::PDFDetector( const uno::Reference< uno::XComponentContext >& xContext) :
318 PDFDetectorBase( m_aMutex ),
319 m_xContext( xContext )
322 // XExtendedFilterDetection
323 OUString SAL_CALL PDFDetector::detect( uno::Sequence< beans::PropertyValue >& rFilterData ) throw( uno::RuntimeException )
325 osl::MutexGuard const guard( m_aMutex );
326 bool bSuccess = false;
328 // get the InputStream carrying the PDF content
329 uno::Reference< io::XInputStream > xInput;
330 uno::Reference< io::XStream > xEmbedStream;
331 OUString aOutFilterName, aOutTypeName;
332 OUString aURL;
333 OUString aPwd;
334 const beans::PropertyValue* pAttribs = rFilterData.getConstArray();
335 sal_Int32 nAttribs = rFilterData.getLength();
336 sal_Int32 nFilterNamePos = -1;
337 sal_Int32 nPwdPos = -1;
338 for( sal_Int32 i = 0; i < nAttribs; i++ )
340 #if OSL_DEBUG_LEVEL > 1
341 OUString aVal( "<no string>" );
342 pAttribs[i].Value >>= aVal;
343 OSL_TRACE( "doDetection: Attrib: %s = %s\n",
344 OUStringToOString( pAttribs[i].Name, RTL_TEXTENCODING_UTF8 ).getStr(),
345 OUStringToOString( aVal, RTL_TEXTENCODING_UTF8 ).getStr() );
346 #endif
347 if ( pAttribs[i].Name == "InputStream" )
348 pAttribs[i].Value >>= xInput;
349 else if ( pAttribs[i].Name == "URL" )
350 pAttribs[i].Value >>= aURL;
351 else if ( pAttribs[i].Name == "FilterName" )
352 nFilterNamePos = i;
353 else if ( pAttribs[i].Name == "Password" )
355 nPwdPos = i;
356 pAttribs[i].Value >>= aPwd;
359 if( xInput.is() )
361 uno::Reference< io::XSeekable > xSeek( xInput, uno::UNO_QUERY );
362 if( xSeek.is() )
363 xSeek->seek( 0 );
364 // read the first 1024 byte (see PDF reference implementation note 12)
365 const sal_Int32 nHeaderSize = 1024;
366 uno::Sequence< sal_Int8 > aBuf( nHeaderSize );
367 sal_uInt64 nBytes = 0;
368 nBytes = xInput->readBytes( aBuf, nHeaderSize );
369 if( nBytes > 5 )
371 const sal_Int8* pBytes = aBuf.getConstArray();
372 for( unsigned int i = 0; i < nBytes-5; i++ )
374 if( pBytes[i] == '%' &&
375 pBytes[i+1] == 'P' &&
376 pBytes[i+2] == 'D' &&
377 pBytes[i+3] == 'F' &&
378 pBytes[i+4] == '-' )
380 bSuccess = true;
381 break;
386 // check for hybrid PDF
387 oslFileHandle aFile = NULL;
388 if( bSuccess &&
389 ( aURL.isEmpty() || !aURL.startsWith( "file:" ) )
392 sal_uInt64 nWritten = 0;
393 if( osl_createTempFile( NULL, &aFile, &aURL.pData ) != osl_File_E_None )
395 bSuccess = false;
397 else
399 #if OSL_DEBUG_LEVEL > 1
400 OSL_TRACE( "created temp file %s\n",
401 OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() );
402 #endif
403 osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
405 OSL_ENSURE( nWritten == nBytes, "writing of header bytes failed" );
407 if( nWritten == nBytes )
409 const sal_uInt32 nBufSize = 4096;
410 aBuf = uno::Sequence<sal_Int8>(nBufSize);
411 // copy the bytes
414 nBytes = xInput->readBytes( aBuf, nBufSize );
415 if( nBytes > 0 )
417 osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
418 if( nWritten != nBytes )
420 bSuccess = false;
421 break;
424 } while( nBytes == nBufSize );
427 osl_closeFile( aFile );
429 OUString aEmbedMimetype;
430 xEmbedStream = getAdditionalStream( aURL, aEmbedMimetype, aPwd, m_xContext, rFilterData, false );
431 if( aFile )
432 osl_removeFile( aURL.pData );
433 if( !aEmbedMimetype.isEmpty() )
435 if( aEmbedMimetype.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "application/vnd.oasis.opendocument.text" ) )
436 || aEmbedMimetype.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "application/vnd.oasis.opendocument.text-master" ) ) )
437 aOutFilterName = OUString( "writer_pdf_addstream_import" );
438 else if ( aEmbedMimetype == "application/vnd.oasis.opendocument.presentation" )
439 aOutFilterName = OUString( "impress_pdf_addstream_import" );
440 else if( aEmbedMimetype.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "application/vnd.oasis.opendocument.graphics" ) )
441 || aEmbedMimetype.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "application/vnd.oasis.opendocument.drawing" ) ) )
442 aOutFilterName = OUString( "draw_pdf_addstream_import" );
443 else if ( aEmbedMimetype == "application/vnd.oasis.opendocument.spreadsheet" )
444 aOutFilterName = OUString( "calc_pdf_addstream_import" );
448 if( bSuccess )
450 if( !aOutFilterName.isEmpty() )
452 if( nFilterNamePos == -1 )
454 nFilterNamePos = nAttribs;
455 rFilterData.realloc( ++nAttribs );
456 rFilterData[ nFilterNamePos ].Name =
457 OUString( "FilterName" );
459 aOutTypeName = OUString("pdf_Portable_Document_Format");
461 OSL_TRACE( "setting filter name %s, input stream %s\n",
462 OUStringToOString( aOutFilterName, RTL_TEXTENCODING_UTF8 ).getStr(),
463 xEmbedStream.is() ? "present" : "not present" );
465 rFilterData[nFilterNamePos].Value <<= aOutFilterName;
466 if( xEmbedStream.is() )
468 rFilterData.realloc( ++nAttribs );
469 rFilterData[nAttribs-1].Name = OUString( "EmbeddedSubstream" );
470 rFilterData[nAttribs-1].Value <<= xEmbedStream;
472 if( !aPwd.isEmpty() )
474 if( nPwdPos == -1 )
476 nPwdPos = nAttribs;
477 rFilterData.realloc( ++nAttribs );
478 rFilterData[ nPwdPos ].Name = OUString( "Password" );
480 rFilterData[ nPwdPos ].Value <<= aPwd;
483 else
485 if( nFilterNamePos == -1 )
487 nFilterNamePos = nAttribs;
488 rFilterData.realloc( ++nAttribs );
489 rFilterData[ nFilterNamePos ].Name = OUString( "FilterName" );
492 const sal_Int32 nDocumentType = 0; //const sal_Int32 nDocumentType = queryDocumentTypeDialog(m_xContext,aURL);
493 if( nDocumentType < 0 )
495 return OUString();
497 else switch( nDocumentType )
499 case 0:
500 rFilterData[nFilterNamePos].Value <<= OUString( "draw_pdf_import" );
501 break;
503 case 1:
504 rFilterData[nFilterNamePos].Value <<= OUString( "impress_pdf_import" );
505 break;
507 case 2:
508 rFilterData[nFilterNamePos].Value <<= OUString( "writer_pdf_import" );
509 break;
511 default:
512 OSL_FAIL("Unexpected case");
515 aOutTypeName = OUString("pdf_Portable_Document_Format");
519 return aOutTypeName;
522 bool checkDocChecksum( const OUString& rInPDFFileURL,
523 sal_uInt32 nBytes,
524 const OUString& rChkSum )
526 bool bRet = false;
527 if( rChkSum.getLength() != 2* RTL_DIGEST_LENGTH_MD5 )
529 OSL_TRACE( "checksum of length %d, expected %d\n",
530 rChkSum.getLength(), 2*RTL_DIGEST_LENGTH_MD5 );
531 return false;
534 // prepare checksum to test
535 sal_uInt8 nTestChecksum[ RTL_DIGEST_LENGTH_MD5 ];
536 const sal_Unicode* pChar = rChkSum.getStr();
537 for( unsigned int i = 0; i < RTL_DIGEST_LENGTH_MD5; i++ )
539 sal_uInt8 nByte = sal_uInt8( ( (*pChar >= '0' && *pChar <= '9') ? *pChar - '0' :
540 ( (*pChar >= 'A' && *pChar <= 'F') ? *pChar - 'A' + 10 :
541 ( (*pChar >= 'a' && *pChar <= 'f') ? *pChar - 'a' + 10 :
542 0 ) ) ) );
543 nByte <<= 4;
544 pChar++;
545 nByte |= ( (*pChar >= '0' && *pChar <= '9') ? *pChar - '0' :
546 ( (*pChar >= 'A' && *pChar <= 'F') ? *pChar - 'A' + 10 :
547 ( (*pChar >= 'a' && *pChar <= 'f') ? *pChar - 'a' + 10 :
548 0 ) ) );
549 pChar++;
550 nTestChecksum[i] = nByte;
553 // open file and calculate actual checksum up to index nBytes
554 sal_uInt8 nActualChecksum[ RTL_DIGEST_LENGTH_MD5 ];
555 memset( nActualChecksum, 0, sizeof(nActualChecksum) );
556 rtlDigest aActualDigest = rtl_digest_createMD5();
557 oslFileHandle aRead = NULL;
558 oslFileError aErr = osl_File_E_None;
559 if( (aErr = osl_openFile(rInPDFFileURL.pData,
560 &aRead,
561 osl_File_OpenFlag_Read )) == osl_File_E_None )
563 sal_Int8 aBuf[4096];
564 sal_uInt32 nCur = 0;
565 sal_uInt64 nBytesRead = 0;
566 while( nCur < nBytes )
568 sal_uInt32 nPass = (nBytes - nCur) > sizeof( aBuf ) ? sizeof( aBuf ) : nBytes - nCur;
569 if( (aErr = osl_readFile( aRead, aBuf, nPass, &nBytesRead)) != osl_File_E_None
570 || nBytesRead == 0 )
572 break;
574 nPass = static_cast<sal_uInt32>(nBytesRead);
575 nCur += nPass;
576 rtl_digest_updateMD5( aActualDigest, aBuf, nPass );
578 rtl_digest_getMD5( aActualDigest, nActualChecksum, sizeof(nActualChecksum) );
579 osl_closeFile( aRead );
581 rtl_digest_destroyMD5( aActualDigest );
583 // compare the contents
584 bRet = (0 == memcmp( nActualChecksum, nTestChecksum, sizeof( nActualChecksum ) ));
585 #if OSL_DEBUG_LEVEL > 1
586 OSL_TRACE( "test checksum: " );
587 for( unsigned int i = 0; i < sizeof(nTestChecksum); i++ )
588 OSL_TRACE( "%.2X", int(nTestChecksum[i]) );
589 OSL_TRACE( "\n" );
590 OSL_TRACE( "file checksum: " );
591 for( unsigned int i = 0; i < sizeof(nActualChecksum); i++ )
592 OSL_TRACE( "%.2X", int(nActualChecksum[i]) );
593 OSL_TRACE( "\n" );
594 #endif
595 return bRet;
598 uno::Reference< io::XStream > getAdditionalStream( const OUString& rInPDFFileURL,
599 OUString& rOutMimetype,
600 OUString& io_rPwd,
601 const uno::Reference<uno::XComponentContext>& xContext,
602 const uno::Sequence<beans::PropertyValue>& rFilterData,
603 bool bMayUseUI )
605 uno::Reference< io::XStream > xEmbed;
606 OString aPDFFile;
607 OUString aSysUPath;
608 if( osl_getSystemPathFromFileURL( rInPDFFileURL.pData, &aSysUPath.pData ) != osl_File_E_None )
609 return xEmbed;
610 aPDFFile = OUStringToOString( aSysUPath, osl_getThreadTextEncoding() );
612 pdfparse::PDFReader aParser;
613 boost::scoped_ptr<pdfparse::PDFEntry> pEntry( aParser.read( aPDFFile.getStr() ));
614 if( pEntry )
616 pdfparse::PDFFile* pPDFFile = dynamic_cast<pdfparse::PDFFile*>(pEntry.get());
617 if( pPDFFile )
619 unsigned int nElements = pPDFFile->m_aSubElements.size();
620 while( nElements-- > 0 )
622 pdfparse::PDFTrailer* pTrailer = dynamic_cast<pdfparse::PDFTrailer*>(pPDFFile->m_aSubElements[nElements]);
623 if( pTrailer && pTrailer->m_pDict )
625 // search document checksum entry
626 boost::unordered_map< OString,
627 pdfparse::PDFEntry*,
628 OStringHash >::iterator chk;
629 chk = pTrailer->m_pDict->m_aMap.find( "DocChecksum" );
630 if( chk == pTrailer->m_pDict->m_aMap.end() )
632 OSL_TRACE( "no DocChecksum entry" );
633 continue;
635 pdfparse::PDFName* pChkSumName = dynamic_cast<pdfparse::PDFName*>(chk->second);
636 if( pChkSumName == NULL )
638 OSL_TRACE( "no name for DocChecksum entry" );
639 continue;
642 // search for AdditionalStreams entry
643 boost::unordered_map< OString,
644 pdfparse::PDFEntry*,
645 OStringHash >::iterator add_stream;
646 add_stream = pTrailer->m_pDict->m_aMap.find( "AdditionalStreams" );
647 if( add_stream == pTrailer->m_pDict->m_aMap.end() )
649 OSL_TRACE( "no AdditionalStreams entry" );
650 continue;
652 pdfparse::PDFArray* pStreams = dynamic_cast<pdfparse::PDFArray*>(add_stream->second);
653 if( ! pStreams || pStreams->m_aSubElements.size() < 2 )
655 OSL_TRACE( "AdditionalStreams array too small" );
656 continue;
659 // check checksum
660 OUString aChkSum = pChkSumName->getFilteredName();
661 if( ! checkDocChecksum( rInPDFFileURL, pTrailer->m_nOffset, aChkSum ) )
662 continue;
664 // extract addstream and mimetype
665 pdfparse::PDFName* pMimeType = dynamic_cast<pdfparse::PDFName*>(pStreams->m_aSubElements[0]);
666 pdfparse::PDFObjectRef* pStreamRef = dynamic_cast<pdfparse::PDFObjectRef*>(pStreams->m_aSubElements[1]);
668 OSL_ENSURE( pMimeType, "error: no mimetype element\n" );
669 OSL_ENSURE( pStreamRef, "error: no stream ref element\n" );
671 if( pMimeType && pStreamRef )
673 pdfparse::PDFObject* pObject = pPDFFile->findObject( pStreamRef->m_nNumber, pStreamRef->m_nGeneration );
674 OSL_ENSURE( pObject, "object not found\n" );
675 if( pObject )
677 if( pPDFFile->isEncrypted() )
679 bool bAuthenticated = false;
680 if( !io_rPwd.isEmpty() )
682 OString aIsoPwd = OUStringToOString( io_rPwd,
683 RTL_TEXTENCODING_ISO_8859_1 );
684 bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() );
686 if( ! bAuthenticated )
688 const beans::PropertyValue* pAttribs = rFilterData.getConstArray();
689 sal_Int32 nAttribs = rFilterData.getLength();
690 uno::Reference< task::XInteractionHandler > xIntHdl;
691 for( sal_Int32 i = 0; i < nAttribs; i++ )
693 if ( pAttribs[i].Name == "InteractionHandler" )
694 pAttribs[i].Value >>= xIntHdl;
696 if( ! bMayUseUI || ! xIntHdl.is() )
698 rOutMimetype = pMimeType->getFilteredName();
699 xEmbed.clear();
700 break;
703 OUString aDocName( rInPDFFileURL.copy( rInPDFFileURL.lastIndexOf( sal_Unicode('/') )+1 ) );
705 bool bEntered = false;
708 bEntered = getPassword( xIntHdl, io_rPwd, ! bEntered, aDocName );
709 OString aIsoPwd = OUStringToOString( io_rPwd,
710 RTL_TEXTENCODING_ISO_8859_1 );
711 bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() );
712 } while( bEntered && ! bAuthenticated );
715 OSL_TRACE( "password: %s", bAuthenticated ? "matches" : "does not match" );
716 if( ! bAuthenticated )
717 continue;
719 rOutMimetype = pMimeType->getFilteredName();
720 FileEmitContext aContext( rInPDFFileURL,
721 xContext,
722 pPDFFile );
723 aContext.m_bDecrypt = pPDFFile->isEncrypted();
724 pObject->writeStream( aContext, pPDFFile );
725 xEmbed = aContext.getContextStream();
726 break; // success
734 OSL_TRACE( "extracted add stream: mimetype %s\n",
735 OUStringToOString( rOutMimetype,
736 RTL_TEXTENCODING_UTF8 ).getStr());
737 return xEmbed;
742 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */