Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "filterdet.hxx"
31 : : #include "inc/pdfparse.hxx"
32 : :
33 : : #include <osl/diagnose.h>
34 : : #include <osl/file.h>
35 : : #include <osl/thread.h>
36 : : #include <rtl/digest.h>
37 : : #include <rtl/ref.hxx>
38 : : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
39 : : #include <com/sun/star/beans/XPropertySet.hpp>
40 : : #include <com/sun/star/awt/XWindow.hpp>
41 : : #include <com/sun/star/awt/XListBox.hpp>
42 : : #include <com/sun/star/awt/XDialogEventHandler.hpp>
43 : : #include <com/sun/star/awt/XDialogProvider2.hpp>
44 : : #include <com/sun/star/awt/XControlContainer.hpp>
45 : : #include <com/sun/star/uno/RuntimeException.hpp>
46 : : #include <com/sun/star/io/XInputStream.hpp>
47 : : #include <com/sun/star/io/XStream.hpp>
48 : : #include <com/sun/star/io/XSeekable.hpp>
49 : :
50 : : #include <boost/scoped_ptr.hpp>
51 : :
52 : : using namespace com::sun::star;
53 : :
54 : : namespace pdfi
55 : : {
56 : :
57 : : // TODO(T3): locking/thread safety
58 : :
59 : : namespace {
60 : : typedef ::cppu::WeakComponentImplHelper1<
61 : : com::sun::star::awt::XDialogEventHandler > ChooserDialogHandlerBase;
62 : : class ChooserDialogHandler : private cppu::BaseMutex,
63 : : public ChooserDialogHandlerBase
64 : : {
65 : : uno::Reference<awt::XListBox> m_xListbox;
66 : : uno::Reference<awt::XWindow> m_xWriterText;
67 : : uno::Reference<awt::XWindow> m_xDrawText;
68 : : uno::Reference<awt::XWindow> m_xImpressText;
69 : :
70 : : enum{ DRAW_INDEX=0, IMPRESS_INDEX=1, WRITER_INDEX=2 };
71 : : void selectionChanged( sal_Int32 nIndex ) const
72 : : {
73 : : sal_Bool bWriterState(sal_False);
74 : : sal_Bool bDrawState(sal_False);
75 : : sal_Bool bImpressState(sal_False);
76 : : switch(nIndex)
77 : : {
78 : : default:
79 : : OSL_FAIL("Unexpected case!");
80 : : break;
81 : : case DRAW_INDEX:
82 : : bDrawState=sal_True;
83 : : break;
84 : : case IMPRESS_INDEX:
85 : : bImpressState=sal_True;
86 : : break;
87 : : case WRITER_INDEX:
88 : : bWriterState=sal_True;
89 : : break;
90 : : }
91 : : m_xWriterText->setVisible(bWriterState);
92 : : m_xDrawText->setVisible(bDrawState);
93 : : m_xImpressText->setVisible(bImpressState);
94 : : }
95 : : public:
96 : : ChooserDialogHandler() :
97 : : ChooserDialogHandlerBase(m_aMutex),
98 : : m_xListbox(),
99 : : m_xWriterText(),
100 : : m_xDrawText(),
101 : : m_xImpressText()
102 : : {}
103 : :
104 : : void initControls( const uno::Reference<awt::XControlContainer>& xControls,
105 : : const rtl::OUString& rFilename )
106 : : {
107 : : m_xListbox.set(xControls->getControl(
108 : : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ListBox" ))),
109 : : uno::UNO_QUERY_THROW );
110 : : m_xWriterText.set(xControls->getControl(
111 : : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InfoWriter" ))),
112 : : uno::UNO_QUERY_THROW );
113 : : m_xImpressText.set(xControls->getControl(
114 : : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InfoImpress" ))),
115 : : uno::UNO_QUERY_THROW );
116 : : m_xDrawText.set(xControls->getControl(
117 : : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InfoDraw" ))),
118 : : uno::UNO_QUERY_THROW );
119 : :
120 : : uno::Reference<awt::XWindow> xControl;
121 : : xControl.set(xControls->getControl(
122 : : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ListBoxWriter" ))),
123 : : uno::UNO_QUERY_THROW );
124 : : xControl->setVisible(sal_False);
125 : : xControl.set(xControls->getControl(
126 : : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ListBoxImpress" ))),
127 : : uno::UNO_QUERY_THROW );
128 : : xControl->setVisible(sal_False);
129 : : xControl.set(xControls->getControl(
130 : : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ListBoxDraw" ))),
131 : : uno::UNO_QUERY_THROW );
132 : : xControl->setVisible(sal_False);
133 : : uno::Reference<beans::XPropertySet> xPropSet(
134 : : xControls->getControl(
135 : : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ComboLabel" )))->getModel(),
136 : : uno::UNO_QUERY_THROW );
137 : : rtl::OUString aFilename( rFilename.copy(rFilename.lastIndexOf('/')+1) );
138 : : rtl::OUString aLabel;
139 : : xPropSet->getPropertyValue(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Label" ))) >>= aLabel;
140 : : const char pFileName[] = "%FILENAME";
141 : : aLabel = aLabel.replaceAt(
142 : : aLabel.indexOfAsciiL(pFileName,SAL_N_ELEMENTS(pFileName)-1),
143 : : SAL_N_ELEMENTS(pFileName)-1,
144 : : aFilename );
145 : : xPropSet->setPropertyValue(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Label" )),
146 : : uno::makeAny(aLabel));
147 : :
148 : : uno::Sequence<rtl::OUString> aListboxItems(3);
149 : : aListboxItems[DRAW_INDEX] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Drawing" ));
150 : : aListboxItems[IMPRESS_INDEX] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Presentation" ));
151 : : aListboxItems[WRITER_INDEX] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Text Document" ));
152 : :
153 : : m_xListbox->addItems(aListboxItems,0);
154 : : m_xListbox->selectItemPos(0,sal_True);
155 : : selectionChanged(0);
156 : : }
157 : :
158 : : sal_Int32 getSelectedItem() const
159 : : {
160 : : return m_xListbox->getSelectedItemPos();
161 : : }
162 : :
163 : : virtual ::sal_Bool SAL_CALL callHandlerMethod( const uno::Reference< awt::XDialog >& /*xDialog*/,
164 : : const uno::Any& /*EventObject*/,
165 : : const ::rtl::OUString& MethodName ) throw (lang::WrappedTargetException, uno::RuntimeException)
166 : : {
167 : : (void)MethodName;
168 : : OSL_ENSURE( MethodName.compareToAscii("SelectionChanged") == 0,
169 : : "Invalid event name" );
170 : : selectionChanged(getSelectedItem());
171 : : return sal_True;
172 : : }
173 : :
174 : : virtual uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedMethodNames( ) throw (uno::RuntimeException)
175 : : {
176 : : uno::Sequence< ::rtl::OUString > aMethods(1);
177 : : aMethods[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SelectionChanged" ));
178 : : return aMethods;
179 : : }
180 : : };
181 : : }
182 : :
183 : : class FileEmitContext : public pdfparse::EmitContext
184 : : {
185 : : private:
186 : : oslFileHandle m_aReadHandle;
187 : : unsigned int m_nReadLen;
188 : : uno::Reference< io::XStream > m_xContextStream;
189 : : uno::Reference< io::XSeekable > m_xSeek;
190 : : uno::Reference< io::XOutputStream > m_xOut;
191 : :
192 : : public:
193 : : FileEmitContext( const rtl::OUString& rOrigFile,
194 : : const uno::Reference< uno::XComponentContext >& xContext,
195 : : const pdfparse::PDFContainer* pTop );
196 : : virtual ~FileEmitContext();
197 : :
198 : : virtual bool write( const void* pBuf, unsigned int nLen );
199 : : virtual unsigned int getCurPos();
200 : : virtual bool copyOrigBytes( unsigned int nOrigOffset, unsigned int nLen );
201 : : virtual unsigned int readOrigBytes( unsigned int nOrigOffset, unsigned int nLen, void* pBuf );
202 : :
203 : 0 : const uno::Reference< io::XStream >& getContextStream() const { return m_xContextStream; }
204 : : };
205 : :
206 : 0 : FileEmitContext::FileEmitContext( const rtl::OUString& rOrigFile,
207 : : const uno::Reference< uno::XComponentContext >& xContext,
208 : : const pdfparse::PDFContainer* pTop ) :
209 : : pdfparse::EmitContext( pTop ),
210 : : m_aReadHandle(NULL),
211 : : m_nReadLen(0),
212 : : m_xContextStream(),
213 : : m_xSeek(),
214 : 0 : m_xOut()
215 : : {
216 : : m_xContextStream = uno::Reference< io::XStream >(
217 [ # # ][ # # ]: 0 : xContext->getServiceManager()->createInstanceWithContext(
[ # # ]
218 : : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ),
219 [ # # ][ # # ]: 0 : xContext ), uno::UNO_QUERY_THROW );
[ # # ][ # # ]
220 [ # # ][ # # ]: 0 : m_xOut = m_xContextStream->getOutputStream();
[ # # ]
221 [ # # ][ # # ]: 0 : m_xSeek = uno::Reference<io::XSeekable>(m_xOut, uno::UNO_QUERY_THROW );
222 : :
223 : 0 : oslFileError aErr = osl_File_E_None;
224 [ # # ][ # # ]: 0 : if( (aErr=osl_openFile( rOrigFile.pData,
225 : : &m_aReadHandle,
226 : 0 : osl_File_OpenFlag_Read )) == osl_File_E_None )
227 : : {
228 [ # # ][ # # ]: 0 : if( (aErr=osl_setFilePos( m_aReadHandle,
229 : : osl_Pos_End,
230 : 0 : 0 )) == osl_File_E_None )
231 : : {
232 : 0 : sal_uInt64 nFileSize = 0;
233 [ # # ][ # # ]: 0 : if( (aErr=osl_getFilePos( m_aReadHandle,
234 : 0 : &nFileSize )) == osl_File_E_None )
235 : : {
236 : 0 : m_nReadLen = static_cast<unsigned int>(nFileSize);
237 : : }
238 : : }
239 [ # # ]: 0 : if( aErr != osl_File_E_None )
240 : : {
241 [ # # ]: 0 : osl_closeFile( m_aReadHandle );
242 : 0 : m_aReadHandle = NULL;
243 : : }
244 : : }
245 : 0 : m_bDeflate = true;
246 : 0 : }
247 : :
248 : 0 : FileEmitContext::~FileEmitContext()
249 : : {
250 [ # # ]: 0 : if( m_aReadHandle )
251 [ # # ]: 0 : osl_closeFile( m_aReadHandle );
252 [ # # ]: 0 : }
253 : :
254 : 0 : bool FileEmitContext::write( const void* pBuf, unsigned int nLen )
255 : : {
256 [ # # ]: 0 : if( ! m_xOut.is() )
257 : 0 : return false;
258 : :
259 [ # # ]: 0 : uno::Sequence< sal_Int8 > aSeq( nLen );
260 [ # # ][ # # ]: 0 : rtl_copyMemory( aSeq.getArray(), pBuf, nLen );
261 [ # # ][ # # ]: 0 : m_xOut->writeBytes( aSeq );
262 [ # # ]: 0 : return true;
263 : : }
264 : :
265 : 0 : unsigned int FileEmitContext::getCurPos()
266 : : {
267 : 0 : unsigned int nPos = 0;
268 [ # # ]: 0 : if( m_xSeek.is() )
269 : : {
270 : 0 : nPos = static_cast<unsigned int>( m_xSeek->getPosition() );
271 : : }
272 : 0 : return nPos;
273 : : }
274 : :
275 : 0 : bool FileEmitContext::copyOrigBytes( unsigned int nOrigOffset, unsigned int nLen )
276 : : {
277 [ # # ]: 0 : if( nOrigOffset + nLen > m_nReadLen )
278 : 0 : return false;
279 : :
280 [ # # ][ # # ]: 0 : if( osl_setFilePos( m_aReadHandle, osl_Pos_Absolut, nOrigOffset ) != osl_File_E_None )
281 : 0 : return false;
282 : :
283 [ # # ]: 0 : uno::Sequence< sal_Int8 > aSeq( nLen );
284 : :
285 : 0 : sal_uInt64 nBytesRead = 0;
286 [ # # ][ # # ]: 0 : if( osl_readFile( m_aReadHandle,
[ # # ]
287 [ # # ]: 0 : aSeq.getArray(),
288 : : nLen,
289 [ # # ]: 0 : &nBytesRead ) != osl_File_E_None
290 : : || nBytesRead != static_cast<sal_uInt64>(nLen) )
291 : : {
292 : 0 : return false;
293 : : }
294 : :
295 [ # # ][ # # ]: 0 : m_xOut->writeBytes( aSeq );
296 [ # # ]: 0 : return true;
297 : : }
298 : :
299 : 0 : unsigned int FileEmitContext::readOrigBytes( unsigned int nOrigOffset, unsigned int nLen, void* pBuf )
300 : : {
301 [ # # ]: 0 : if( nOrigOffset + nLen > m_nReadLen )
302 : 0 : return 0;
303 : :
304 [ # # ]: 0 : if( osl_setFilePos( m_aReadHandle,
305 : : osl_Pos_Absolut,
306 [ # # ]: 0 : nOrigOffset ) != osl_File_E_None )
307 : : {
308 : 0 : return 0;
309 : : }
310 : :
311 : 0 : sal_uInt64 nBytesRead = 0;
312 [ # # ]: 0 : if( osl_readFile( m_aReadHandle,
313 : : pBuf,
314 : : nLen,
315 [ # # ]: 0 : &nBytesRead ) != osl_File_E_None )
316 : : {
317 : 0 : return 0;
318 : : }
319 : 0 : return static_cast<unsigned int>(nBytesRead);
320 : : }
321 : :
322 : :
323 : : ////////////////////////////////////////////////////////////////////////////////
324 : :
325 : :
326 : 10 : PDFDetector::PDFDetector( const uno::Reference< uno::XComponentContext >& xContext) :
327 : : PDFDetectorBase( m_aMutex ),
328 : 10 : m_xContext( xContext )
329 : 10 : {}
330 : :
331 : : // XExtendedFilterDetection
332 : 10 : rtl::OUString SAL_CALL PDFDetector::detect( uno::Sequence< beans::PropertyValue >& rFilterData ) throw( uno::RuntimeException )
333 : : {
334 [ + - ]: 10 : osl::MutexGuard const guard( m_aMutex );
335 : 10 : bool bSuccess = false;
336 : :
337 : : // get the InputStream carrying the PDF content
338 : 10 : uno::Reference< io::XInputStream > xInput;
339 : 10 : uno::Reference< io::XStream > xEmbedStream;
340 : 10 : rtl::OUString aOutFilterName, aOutTypeName;
341 : 10 : rtl::OUString aURL;
342 : 10 : rtl::OUString aPwd;
343 : 10 : const beans::PropertyValue* pAttribs = rFilterData.getConstArray();
344 : 10 : sal_Int32 nAttribs = rFilterData.getLength();
345 : 10 : sal_Int32 nFilterNamePos = -1;
346 : 10 : sal_Int32 nPwdPos = -1;
347 [ + + ]: 80 : for( sal_Int32 i = 0; i < nAttribs; i++ )
348 : : {
349 : : #if OSL_DEBUG_LEVEL > 1
350 : : rtl::OUString aVal( RTL_CONSTASCII_USTRINGPARAM( "<no string>" ) );
351 : : pAttribs[i].Value >>= aVal;
352 : : OSL_TRACE( "doDetection: Attrib: %s = %s\n",
353 : : rtl::OUStringToOString( pAttribs[i].Name, RTL_TEXTENCODING_UTF8 ).getStr(),
354 : : rtl::OUStringToOString( aVal, RTL_TEXTENCODING_UTF8 ).getStr() );
355 : : #endif
356 [ + + ]: 70 : if ( pAttribs[i].Name == "InputStream" )
357 [ + - ]: 10 : pAttribs[i].Value >>= xInput;
358 [ + + ]: 60 : else if ( pAttribs[i].Name == "URL" )
359 : 10 : pAttribs[i].Value >>= aURL;
360 [ - + ]: 50 : else if ( pAttribs[i].Name == "FilterName" )
361 : 0 : nFilterNamePos = i;
362 [ - + ]: 50 : else if ( pAttribs[i].Name == "Password" )
363 : : {
364 : 0 : nPwdPos = i;
365 : 0 : pAttribs[i].Value >>= aPwd;
366 : : }
367 : : }
368 [ + - ]: 10 : if( xInput.is() )
369 : : {
370 [ + - ]: 10 : uno::Reference< io::XSeekable > xSeek( xInput, uno::UNO_QUERY );
371 [ + - ]: 10 : if( xSeek.is() )
372 [ + - ][ + - ]: 10 : xSeek->seek( 0 );
373 : : // read the first 1024 byte (see PDF reference implementation note 12)
374 : 10 : const sal_Int32 nHeaderSize = 1024;
375 [ + - ]: 10 : uno::Sequence< sal_Int8 > aBuf( nHeaderSize );
376 : 10 : sal_uInt64 nBytes = 0;
377 [ + - ][ + - ]: 10 : nBytes = xInput->readBytes( aBuf, nHeaderSize );
378 [ + - ]: 10 : if( nBytes > 5 )
379 : : {
380 : 10 : const sal_Int8* pBytes = aBuf.getConstArray();
381 [ + + ]: 10200 : for( unsigned int i = 0; i < nBytes-5; i++ )
382 : : {
383 [ + + ][ - + ]: 10190 : if( pBytes[i] == '%' &&
[ # # ][ # # ]
[ # # ]
384 : 44 : pBytes[i+1] == 'P' &&
385 : 0 : pBytes[i+2] == 'D' &&
386 : 0 : pBytes[i+3] == 'F' &&
387 : 0 : pBytes[i+4] == '-' )
388 : : {
389 : 0 : bSuccess = true;
390 : 0 : break;
391 : : }
392 : : }
393 : : }
394 : :
395 : : // check for hybrid PDF
396 : 10 : oslFileHandle aFile = NULL;
397 [ - + # # : 10 : if( bSuccess &&
# # ][ - + ]
398 : 0 : ( aURL.isEmpty() || aURL.compareToAscii( "file:", 5 ) != 0 )
399 : : )
400 : : {
401 : 0 : sal_uInt64 nWritten = 0;
402 [ # # ][ # # ]: 0 : if( osl_createTempFile( NULL, &aFile, &aURL.pData ) != osl_File_E_None )
403 : : {
404 : 0 : bSuccess = false;
405 : : }
406 : : else
407 : : {
408 : : #if OSL_DEBUG_LEVEL > 1
409 : : OSL_TRACE( "created temp file %s\n",
410 : : rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() );
411 : : #endif
412 [ # # ]: 0 : osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
413 : :
414 : : OSL_ENSURE( nWritten == nBytes, "writing of header bytes failed" );
415 : :
416 [ # # ]: 0 : if( nWritten == nBytes )
417 : : {
418 : 0 : const sal_uInt32 nBufSize = 4096;
419 [ # # ][ # # ]: 0 : aBuf = uno::Sequence<sal_Int8>(nBufSize);
[ # # ]
420 : : // copy the bytes
421 [ # # ]: 0 : do
422 : : {
423 [ # # ][ # # ]: 0 : nBytes = xInput->readBytes( aBuf, nBufSize );
424 [ # # ]: 0 : if( nBytes > 0 )
425 : : {
426 [ # # ]: 0 : osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
427 [ # # ]: 0 : if( nWritten != nBytes )
428 : : {
429 : 0 : bSuccess = false;
430 : 0 : break;
431 : : }
432 : : }
433 : : } while( nBytes == nBufSize );
434 : : }
435 : : }
436 [ # # ]: 0 : osl_closeFile( aFile );
437 : : }
438 : 10 : rtl::OUString aEmbedMimetype;
439 [ + - ][ + - ]: 10 : xEmbedStream = getAdditionalStream( aURL, aEmbedMimetype, aPwd, m_xContext, rFilterData, false );
440 [ - + ]: 10 : if( aFile )
441 [ # # ]: 0 : osl_removeFile( aURL.pData );
442 [ - + ]: 10 : if( !aEmbedMimetype.isEmpty() )
443 : : {
444 [ # # # # ]: 0 : if( aEmbedMimetype.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "application/vnd.oasis.opendocument.text" ) )
[ # # ]
445 : 0 : || aEmbedMimetype.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "application/vnd.oasis.opendocument.text-master" ) ) )
446 [ # # ]: 0 : aOutFilterName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "writer_pdf_addstream_import" ) );
447 [ # # ]: 0 : else if ( aEmbedMimetype == "application/vnd.oasis.opendocument.presentation" )
448 [ # # ]: 0 : aOutFilterName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "impress_pdf_addstream_import" ) );
449 [ # # # # ]: 0 : else if( aEmbedMimetype.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "application/vnd.oasis.opendocument.graphics" ) )
[ # # ]
450 : 0 : || aEmbedMimetype.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "application/vnd.oasis.opendocument.drawing" ) ) )
451 [ # # ]: 0 : aOutFilterName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "draw_pdf_addstream_import" ) );
452 [ # # ]: 0 : else if ( aEmbedMimetype == "application/vnd.oasis.opendocument.spreadsheet" )
453 [ # # ]: 0 : aOutFilterName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "calc_pdf_addstream_import" ) );
454 [ + - ]: 10 : }
455 : : }
456 : :
457 [ - + ]: 10 : if( bSuccess )
458 : : {
459 [ # # ]: 0 : if( !aOutFilterName.isEmpty() )
460 : : {
461 [ # # ]: 0 : if( nFilterNamePos == -1 )
462 : : {
463 : 0 : nFilterNamePos = nAttribs;
464 [ # # ]: 0 : rFilterData.realloc( ++nAttribs );
465 [ # # ]: 0 : rFilterData[ nFilterNamePos ].Name =
466 [ # # ]: 0 : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ) );
467 : : }
468 [ # # ]: 0 : aOutTypeName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("pdf_Portable_Document_Format") );
469 : :
470 : : OSL_TRACE( "setting filter name %s, input stream %s\n",
471 : : rtl::OUStringToOString( aOutFilterName, RTL_TEXTENCODING_UTF8 ).getStr(),
472 : : xEmbedStream.is() ? "present" : "not present" );
473 : :
474 [ # # ][ # # ]: 0 : rFilterData[nFilterNamePos].Value <<= aOutFilterName;
475 [ # # ]: 0 : if( xEmbedStream.is() )
476 : : {
477 [ # # ]: 0 : rFilterData.realloc( ++nAttribs );
478 [ # # ][ # # ]: 0 : rFilterData[nAttribs-1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EmbeddedSubstream" ) );
479 [ # # ][ # # ]: 0 : rFilterData[nAttribs-1].Value <<= xEmbedStream;
480 : : }
481 [ # # ]: 0 : if( !aPwd.isEmpty() )
482 : : {
483 [ # # ]: 0 : if( nPwdPos == -1 )
484 : : {
485 : 0 : nPwdPos = nAttribs;
486 [ # # ]: 0 : rFilterData.realloc( ++nAttribs );
487 [ # # ][ # # ]: 0 : rFilterData[ nPwdPos ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Password" ) );
488 : : }
489 [ # # ][ # # ]: 0 : rFilterData[ nPwdPos ].Value <<= aPwd;
490 : : }
491 : : }
492 : : else
493 : : {
494 [ # # ]: 0 : if( nFilterNamePos == -1 )
495 : : {
496 : 0 : nFilterNamePos = nAttribs;
497 [ # # ]: 0 : rFilterData.realloc( ++nAttribs );
498 [ # # ][ # # ]: 0 : rFilterData[ nFilterNamePos ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ) );
499 : : }
500 : :
501 : 0 : const sal_Int32 nDocumentType = 0; //const sal_Int32 nDocumentType = queryDocumentTypeDialog(m_xContext,aURL);
502 : : if( nDocumentType < 0 )
503 : : {
504 : : return rtl::OUString();
505 : : }
506 : : else switch( nDocumentType )
507 : : {
508 : : case 0:
509 [ # # ][ # # ]: 0 : rFilterData[nFilterNamePos].Value <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "draw_pdf_import" ) );
[ # # ]
510 : 0 : break;
511 : :
512 : : case 1:
513 : : rFilterData[nFilterNamePos].Value <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "impress_pdf_import" ) );
514 : : break;
515 : :
516 : : case 2:
517 : : rFilterData[nFilterNamePos].Value <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "writer_pdf_import" ) );
518 : : break;
519 : :
520 : : default:
521 : : OSL_FAIL("Unexpected case");
522 : : }
523 : :
524 [ # # ]: 0 : aOutTypeName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("pdf_Portable_Document_Format") );
525 : : }
526 : : }
527 : :
528 [ + - ]: 10 : return aOutTypeName;
529 : : }
530 : :
531 : 0 : bool checkDocChecksum( const rtl::OUString& rInPDFFileURL,
532 : : sal_uInt32 nBytes,
533 : : const rtl::OUString& rChkSum )
534 : : {
535 : 0 : bool bRet = false;
536 [ # # ]: 0 : if( rChkSum.getLength() != 2* RTL_DIGEST_LENGTH_MD5 )
537 : : {
538 : : OSL_TRACE( "checksum of length %d, expected %d\n",
539 : : rChkSum.getLength(), 2*RTL_DIGEST_LENGTH_MD5 );
540 : 0 : return false;
541 : : }
542 : :
543 : : // prepare checksum to test
544 : : sal_uInt8 nTestChecksum[ RTL_DIGEST_LENGTH_MD5 ];
545 : 0 : const sal_Unicode* pChar = rChkSum.getStr();
546 [ # # ]: 0 : for( unsigned int i = 0; i < RTL_DIGEST_LENGTH_MD5; i++ )
547 : : {
548 : : sal_uInt8 nByte = sal_uInt8( ( (*pChar >= '0' && *pChar <= '9') ? *pChar - '0' :
549 : : ( (*pChar >= 'A' && *pChar <= 'F') ? *pChar - 'A' + 10 :
550 : : ( (*pChar >= 'a' && *pChar <= 'f') ? *pChar - 'a' + 10 :
551 [ # # ][ # # ]: 0 : 0 ) ) ) );
[ # # ][ # # ]
[ # # ][ # # ]
552 : 0 : nByte <<= 4;
553 : 0 : pChar++;
554 : : nByte |= ( (*pChar >= '0' && *pChar <= '9') ? *pChar - '0' :
555 : : ( (*pChar >= 'A' && *pChar <= 'F') ? *pChar - 'A' + 10 :
556 : : ( (*pChar >= 'a' && *pChar <= 'f') ? *pChar - 'a' + 10 :
557 [ # # ][ # # ]: 0 : 0 ) ) );
[ # # ][ # # ]
[ # # ][ # # ]
558 : 0 : pChar++;
559 : 0 : nTestChecksum[i] = nByte;
560 : : }
561 : :
562 : : // open file and calculate actual checksum up to index nBytes
563 : : sal_uInt8 nActualChecksum[ RTL_DIGEST_LENGTH_MD5 ];
564 [ # # ]: 0 : rtl_zeroMemory( nActualChecksum, sizeof(nActualChecksum) );
565 : 0 : rtlDigest aActualDigest = rtl_digest_createMD5();
566 : 0 : oslFileHandle aRead = NULL;
567 : 0 : oslFileError aErr = osl_File_E_None;
568 [ # # ][ # # ]: 0 : if( (aErr = osl_openFile(rInPDFFileURL.pData,
569 : : &aRead,
570 : 0 : osl_File_OpenFlag_Read )) == osl_File_E_None )
571 : : {
572 : : sal_Int8 aBuf[4096];
573 : 0 : sal_uInt32 nCur = 0;
574 : 0 : sal_uInt64 nBytesRead = 0;
575 [ # # ]: 0 : while( nCur < nBytes )
576 : : {
577 : 0 : sal_uInt32 nPass = (nBytes - nCur) > sizeof( aBuf ) ? sizeof( aBuf ) : nBytes - nCur;
578 [ # # ][ # # ]: 0 : if( (aErr = osl_readFile( aRead, aBuf, nPass, &nBytesRead)) != osl_File_E_None
[ # # ][ # # ]
579 : : || nBytesRead == 0 )
580 : : {
581 : 0 : break;
582 : : }
583 : 0 : nPass = static_cast<sal_uInt32>(nBytesRead);
584 : 0 : nCur += nPass;
585 : 0 : rtl_digest_updateMD5( aActualDigest, aBuf, nPass );
586 : : }
587 : 0 : rtl_digest_getMD5( aActualDigest, nActualChecksum, sizeof(nActualChecksum) );
588 [ # # ]: 0 : osl_closeFile( aRead );
589 : : }
590 : 0 : rtl_digest_destroyMD5( aActualDigest );
591 : :
592 : : // compare the contents
593 [ # # ]: 0 : bRet = (0 == rtl_compareMemory( nActualChecksum, nTestChecksum, sizeof( nActualChecksum ) ));
594 : : #if OSL_DEBUG_LEVEL > 1
595 : : OSL_TRACE( "test checksum: " );
596 : : for( unsigned int i = 0; i < sizeof(nTestChecksum); i++ )
597 : : OSL_TRACE( "%.2X", int(nTestChecksum[i]) );
598 : : OSL_TRACE( "\n" );
599 : : OSL_TRACE( "file checksum: " );
600 : : for( unsigned int i = 0; i < sizeof(nActualChecksum); i++ )
601 : : OSL_TRACE( "%.2X", int(nActualChecksum[i]) );
602 : : OSL_TRACE( "\n" );
603 : : #endif
604 : 0 : return bRet;
605 : : }
606 : :
607 : 10 : uno::Reference< io::XStream > getAdditionalStream( const rtl::OUString& rInPDFFileURL,
608 : : rtl::OUString& rOutMimetype,
609 : : rtl::OUString& io_rPwd,
610 : : const uno::Reference<uno::XComponentContext>& xContext,
611 : : const uno::Sequence<beans::PropertyValue>& rFilterData,
612 : : bool bMayUseUI )
613 : : {
614 : 10 : uno::Reference< io::XStream > xEmbed;
615 : 10 : rtl::OString aPDFFile;
616 : 10 : rtl::OUString aSysUPath;
617 [ + - ][ + - ]: 10 : if( osl_getSystemPathFromFileURL( rInPDFFileURL.pData, &aSysUPath.pData ) != osl_File_E_None )
618 : : return xEmbed;
619 [ + - ][ + - ]: 10 : aPDFFile = rtl::OUStringToOString( aSysUPath, osl_getThreadTextEncoding() );
620 : :
621 : 10 : pdfparse::PDFReader aParser;
622 [ + - ]: 10 : boost::scoped_ptr<pdfparse::PDFEntry> pEntry( aParser.read( aPDFFile.getStr() ));
623 [ - + ]: 10 : if( pEntry )
624 : : {
625 [ # # ]: 0 : pdfparse::PDFFile* pPDFFile = dynamic_cast<pdfparse::PDFFile*>(pEntry.get());
626 [ # # ]: 0 : if( pPDFFile )
627 : : {
628 : 0 : unsigned int nElements = pPDFFile->m_aSubElements.size();
629 [ # # ]: 0 : while( nElements-- > 0 )
630 : : {
631 [ # # ]: 0 : pdfparse::PDFTrailer* pTrailer = dynamic_cast<pdfparse::PDFTrailer*>(pPDFFile->m_aSubElements[nElements]);
632 [ # # ][ # # ]: 0 : if( pTrailer && pTrailer->m_pDict )
633 : : {
634 : : // search document checksum entry
635 : : boost::unordered_map< rtl::OString,
636 : : pdfparse::PDFEntry*,
637 : 0 : rtl::OStringHash >::iterator chk;
638 [ # # ]: 0 : chk = pTrailer->m_pDict->m_aMap.find( "DocChecksum" );
639 [ # # ]: 0 : if( chk == pTrailer->m_pDict->m_aMap.end() )
640 : : {
641 : : OSL_TRACE( "no DocChecksum entry" );
642 : 0 : continue;
643 : : }
644 [ # # ][ # # ]: 0 : pdfparse::PDFName* pChkSumName = dynamic_cast<pdfparse::PDFName*>(chk->second);
645 [ # # ]: 0 : if( pChkSumName == NULL )
646 : : {
647 : : OSL_TRACE( "no name for DocChecksum entry" );
648 : 0 : continue;
649 : : }
650 : :
651 : : // search for AdditionalStreams entry
652 : : boost::unordered_map< rtl::OString,
653 : : pdfparse::PDFEntry*,
654 : 0 : rtl::OStringHash >::iterator add_stream;
655 [ # # ]: 0 : add_stream = pTrailer->m_pDict->m_aMap.find( "AdditionalStreams" );
656 [ # # ]: 0 : if( add_stream == pTrailer->m_pDict->m_aMap.end() )
657 : : {
658 : : OSL_TRACE( "no AdditionalStreams entry" );
659 : 0 : continue;
660 : : }
661 [ # # ][ # # ]: 0 : pdfparse::PDFArray* pStreams = dynamic_cast<pdfparse::PDFArray*>(add_stream->second);
662 [ # # ][ # # ]: 0 : if( ! pStreams || pStreams->m_aSubElements.size() < 2 )
[ # # ]
663 : : {
664 : : OSL_TRACE( "AdditionalStreams array too small" );
665 : 0 : continue;
666 : : }
667 : :
668 : : // check checksum
669 [ # # ]: 0 : rtl::OUString aChkSum = pChkSumName->getFilteredName();
670 [ # # ][ # # ]: 0 : if( ! checkDocChecksum( rInPDFFileURL, pTrailer->m_nOffset, aChkSum ) )
671 : 0 : continue;
672 : :
673 : : // extract addstream and mimetype
674 [ # # ]: 0 : pdfparse::PDFName* pMimeType = dynamic_cast<pdfparse::PDFName*>(pStreams->m_aSubElements[0]);
675 [ # # ]: 0 : pdfparse::PDFObjectRef* pStreamRef = dynamic_cast<pdfparse::PDFObjectRef*>(pStreams->m_aSubElements[1]);
676 : :
677 : : OSL_ENSURE( pMimeType, "error: no mimetype element\n" );
678 : : OSL_ENSURE( pStreamRef, "error: no stream ref element\n" );
679 : :
680 [ # # ][ # # ]: 0 : if( pMimeType && pStreamRef )
681 : : {
682 [ # # ]: 0 : pdfparse::PDFObject* pObject = pPDFFile->findObject( pStreamRef->m_nNumber, pStreamRef->m_nGeneration );
683 : : OSL_ENSURE( pObject, "object not found\n" );
684 [ # # ]: 0 : if( pObject )
685 : : {
686 [ # # ][ # # ]: 0 : if( pPDFFile->isEncrypted() )
687 : : {
688 : 0 : bool bAuthenticated = false;
689 [ # # ]: 0 : if( !io_rPwd.isEmpty() )
690 : : {
691 : : rtl::OString aIsoPwd = rtl::OUStringToOString( io_rPwd,
692 [ # # ]: 0 : RTL_TEXTENCODING_ISO_8859_1 );
693 [ # # ]: 0 : bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() );
694 : : // trash password string on heap
695 [ # # ]: 0 : rtl_zeroMemory( (void*)aIsoPwd.getStr(), aIsoPwd.getLength() );
696 : : }
697 [ # # ]: 0 : if( ! bAuthenticated )
698 : : {
699 : 0 : const beans::PropertyValue* pAttribs = rFilterData.getConstArray();
700 : 0 : sal_Int32 nAttribs = rFilterData.getLength();
701 : 0 : uno::Reference< task::XInteractionHandler > xIntHdl;
702 [ # # ]: 0 : for( sal_Int32 i = 0; i < nAttribs; i++ )
703 : : {
704 [ # # ]: 0 : if ( pAttribs[i].Name == "InteractionHandler" )
705 [ # # ]: 0 : pAttribs[i].Value >>= xIntHdl;
706 : : }
707 [ # # ][ # # ]: 0 : if( ! bMayUseUI || ! xIntHdl.is() )
[ # # ]
708 : : {
709 [ # # ]: 0 : rOutMimetype = pMimeType->getFilteredName();
710 : 0 : xEmbed.clear();
711 : : break;
712 : : }
713 : :
714 : 0 : rtl::OUString aDocName( rInPDFFileURL.copy( rInPDFFileURL.lastIndexOf( sal_Unicode('/') )+1 ) );
715 : :
716 : 0 : bool bEntered = false;
717 [ # # ][ # # ]: 0 : do
[ # # ]
718 : : {
719 [ # # ]: 0 : bEntered = getPassword( xIntHdl, io_rPwd, ! bEntered, aDocName );
720 : : rtl::OString aIsoPwd = rtl::OUStringToOString( io_rPwd,
721 [ # # ]: 0 : RTL_TEXTENCODING_ISO_8859_1 );
722 [ # # ]: 0 : bAuthenticated = pPDFFile->setupDecryptionData( aIsoPwd.getStr() );
723 : : // trash password string on heap
724 [ # # ]: 0 : rtl_zeroMemory( (void*)aIsoPwd.getStr(), aIsoPwd.getLength() );
725 [ # # ]: 0 : } while( bEntered && ! bAuthenticated );
726 : : }
727 : :
728 : : OSL_TRACE( "password: %s", bAuthenticated ? "matches" : "does not match" );
729 [ # # ]: 0 : if( ! bAuthenticated )
730 : 0 : continue;
731 : : }
732 [ # # ]: 0 : rOutMimetype = pMimeType->getFilteredName();
733 : : FileEmitContext aContext( rInPDFFileURL,
734 : : xContext,
735 [ # # ]: 0 : pPDFFile );
736 [ # # ]: 0 : aContext.m_bDecrypt = pPDFFile->isEncrypted();
737 [ # # ]: 0 : pObject->writeStream( aContext, pPDFFile );
738 [ # # ]: 0 : xEmbed = aContext.getContextStream();
739 [ # # ]: 0 : break; // success
740 : : }
741 [ # # # ]: 0 : }
742 : : }
743 : : }
744 : : }
745 : : }
746 : :
747 : : OSL_TRACE( "extracted add stream: mimetype %s\n",
748 : : rtl::OUStringToOString( rOutMimetype,
749 : : RTL_TEXTENCODING_UTF8 ).getStr());
750 [ + - ]: 10 : return xEmbed;
751 : : }
752 : :
753 : : }
754 : :
755 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|