Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / embeddedobj / source / msole / ownview.cxx
blobd28f30b8ed36d34b8f174c464ade1cc9f33dea06
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 .
20 #include <com/sun/star/frame/Desktop.hpp>
21 #include <com/sun/star/frame/XFrame.hpp>
22 #include <com/sun/star/frame/XController.hpp>
23 #include <com/sun/star/frame/XComponentLoader.hpp>
24 #include <com/sun/star/awt/XTopWindow.hpp>
25 #include <com/sun/star/embed/XClassifiedObject.hpp>
26 #include <com/sun/star/io/TempFile.hpp>
27 #include <com/sun/star/io/XStream.hpp>
28 #include <com/sun/star/io/XInputStream.hpp>
29 #include <com/sun/star/io/XOutputStream.hpp>
30 #include <com/sun/star/io/XSeekable.hpp>
31 #include <com/sun/star/task/XInteractionHandler.hpp>
32 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
33 #include <com/sun/star/util/XCloseable.hpp>
34 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/document/XEventBroadcaster.hpp>
37 #include <com/sun/star/document/XEventListener.hpp>
38 #include <com/sun/star/document/XTypeDetection.hpp>
39 #include <com/sun/star/container/XNameAccess.hpp>
40 #include <cppuhelper/implbase1.hxx>
41 #include <comphelper/processfactory.hxx>
42 #include <comphelper/storagehelper.hxx>
43 #include <comphelper/mimeconfighelper.hxx>
45 #include "ownview.hxx"
48 using namespace ::com::sun::star;
49 using namespace ::comphelper;
51 OUString GetNewTempFileURL_Impl( const uno::Reference< lang::XMultiServiceFactory >& xFactory ) throw( io::IOException );
52 OUString GetNewFilledTempFile_Impl( const uno::Reference< io::XInputStream >& xInStream, const uno::Reference< lang::XMultiServiceFactory >& xFactory ) throw( io::IOException );
53 sal_Bool KillFile_Impl( const OUString& aURL, const uno::Reference< lang::XMultiServiceFactory >& xFactory );
54 uno::Reference< io::XStream > TryToGetAcceptableFormat_Impl( const uno::Reference< io::XStream >& xStream, const uno::Reference< lang::XMultiServiceFactory >& xFactory ) throw ( uno::Exception );
56 //========================================================
57 // Dummy interaction handler
58 //========================================================
59 //--------------------------------------------------------
60 class DummyHandler_Impl : public ::cppu::WeakImplHelper1< task::XInteractionHandler >
62 public:
63 DummyHandler_Impl() {}
64 ~DummyHandler_Impl();
66 virtual void SAL_CALL handle( const uno::Reference< task::XInteractionRequest >& xRequest )
67 throw( uno::RuntimeException );
70 //--------------------------------------------------------
71 DummyHandler_Impl::~DummyHandler_Impl()
75 //--------------------------------------------------------
76 void SAL_CALL DummyHandler_Impl::handle( const uno::Reference< task::XInteractionRequest >& )
77 throw( uno::RuntimeException )
79 return;
82 //========================================================
83 // Object viewer
84 //========================================================
85 //--------------------------------------------------------
86 OwnView_Impl::OwnView_Impl( const uno::Reference< lang::XMultiServiceFactory >& xFactory,
87 const uno::Reference< io::XInputStream >& xInputStream )
88 : m_xFactory( xFactory )
89 , m_bBusy( sal_False )
90 , m_bUseNative( sal_False )
92 if ( !xFactory.is() || !xInputStream.is() )
93 throw uno::RuntimeException();
95 m_aTempFileURL = GetNewFilledTempFile_Impl( xInputStream, m_xFactory );
98 //--------------------------------------------------------
99 OwnView_Impl::~OwnView_Impl()
101 try {
102 KillFile_Impl( m_aTempFileURL, m_xFactory );
103 } catch( uno::Exception& ) {}
105 try {
106 if ( !m_aNativeTempURL.isEmpty() )
107 KillFile_Impl( m_aNativeTempURL, m_xFactory );
108 } catch( uno::Exception& ) {}
111 //--------------------------------------------------------
112 sal_Bool OwnView_Impl::CreateModelFromURL( const OUString& aFileURL )
114 sal_Bool bResult = sal_False;
116 if ( !aFileURL.isEmpty() )
118 try {
119 uno::Reference < frame::XDesktop2 > xDocumentLoader = frame::Desktop::create(comphelper::getComponentContext(m_xFactory));
121 uno::Sequence< beans::PropertyValue > aArgs( m_aFilterName.isEmpty() ? 4 : 5 );
123 aArgs[0].Name = "URL";
124 aArgs[0].Value <<= aFileURL;
126 aArgs[1].Name = "ReadOnly";
127 aArgs[1].Value <<= sal_True;
129 aArgs[2].Name = "InteractionHandler";
130 aArgs[2].Value <<= uno::Reference< task::XInteractionHandler >(
131 static_cast< ::cppu::OWeakObject* >( new DummyHandler_Impl() ), uno::UNO_QUERY );
133 aArgs[3].Name = "DontEdit";
134 aArgs[3].Value <<= sal_True;
136 if ( !m_aFilterName.isEmpty() )
138 aArgs[4].Name = "FilterName";
139 aArgs[4].Value <<= m_aFilterName;
142 uno::Reference< frame::XModel > xModel( xDocumentLoader->loadComponentFromURL(
143 aFileURL,
144 OUString( "_blank" ),
146 aArgs ),
147 uno::UNO_QUERY );
149 if ( xModel.is() )
151 uno::Reference< document::XEventBroadcaster > xBroadCaster( xModel, uno::UNO_QUERY );
152 if ( xBroadCaster.is() )
153 xBroadCaster->addEventListener( uno::Reference< document::XEventListener >(
154 static_cast< ::cppu::OWeakObject* >( this ),
155 uno::UNO_QUERY ) );
157 uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
158 if ( xCloseable.is() )
160 xCloseable->addCloseListener( uno::Reference< util::XCloseListener >(
161 static_cast< ::cppu::OWeakObject* >( this ),
162 uno::UNO_QUERY ) );
164 ::osl::MutexGuard aGuard( m_aMutex );
165 m_xModel = xModel;
166 bResult = sal_True;
170 catch (uno::Exception const& e)
172 SAL_WARN("embeddedobj.ole", "OwnView_Impl::CreateModelFromURL:"
173 " exception caught: " << e.Message);
177 return bResult;
180 //--------------------------------------------------------
181 sal_Bool OwnView_Impl::CreateModel( sal_Bool bUseNative )
183 sal_Bool bResult = sal_False;
185 try {
186 bResult = CreateModelFromURL( bUseNative ? m_aNativeTempURL : m_aTempFileURL );
188 catch( uno::Exception& )
192 return bResult;
195 //--------------------------------------------------------
196 OUString OwnView_Impl::GetFilterNameFromExtentionAndInStream(
197 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory,
198 const OUString& aNameWithExtention,
199 const uno::Reference< io::XInputStream >& xInputStream )
201 if ( !xInputStream.is() )
202 throw uno::RuntimeException();
204 uno::Reference< document::XTypeDetection > xTypeDetection(
205 xFactory->createInstance("com.sun.star.document.TypeDetection"),
206 uno::UNO_QUERY_THROW );
208 OUString aTypeName;
210 if ( !aNameWithExtention.isEmpty() )
212 OUString aURLToAnalyze =
213 ( OUString( "file:///" ) + aNameWithExtention );
214 aTypeName = xTypeDetection->queryTypeByURL( aURLToAnalyze );
217 uno::Sequence< beans::PropertyValue > aArgs( aTypeName.isEmpty() ? 2 : 3 );
218 aArgs[0].Name = "URL";
219 aArgs[0].Value <<= OUString( "private:stream" );
220 aArgs[1].Name = "InputStream";
221 aArgs[1].Value <<= xInputStream;
222 if ( !aTypeName.isEmpty() )
224 aArgs[2].Name = "TypeName";
225 aArgs[2].Value <<= aTypeName;
228 aTypeName = xTypeDetection->queryTypeByDescriptor( aArgs, sal_True );
230 OUString aFilterName;
231 for ( sal_Int32 nInd = 0; nInd < aArgs.getLength(); nInd++ )
232 if ( aArgs[nInd].Name == "FilterName" )
233 aArgs[nInd].Value >>= aFilterName;
235 if ( aFilterName.isEmpty() && !aTypeName.isEmpty() )
237 // get the default filter name for the type
238 uno::Reference< container::XNameAccess > xNameAccess( xTypeDetection, uno::UNO_QUERY_THROW );
239 uno::Sequence< beans::PropertyValue > aTypes;
241 if ( xNameAccess.is() && ( xNameAccess->getByName( aTypeName ) >>= aTypes ) )
243 for ( sal_Int32 nInd = 0; nInd < aTypes.getLength(); nInd++ )
245 if ( aTypes[nInd].Name.startsWith( "PreferredFilter" ) && ( aTypes[nInd].Value >>= aFilterName ) )
247 aTypes[nInd].Value >>= aFilterName;
248 break;
254 return aFilterName;
257 //--------------------------------------------------------
258 sal_Bool OwnView_Impl::ReadContentsAndGenerateTempFile( const uno::Reference< io::XInputStream >& xInStream,
259 sal_Bool bParseHeader )
261 uno::Reference< io::XSeekable > xSeekable( xInStream, uno::UNO_QUERY_THROW );
262 xSeekable->seek( 0 );
264 // create m_aNativeTempURL
265 OUString aNativeTempURL;
266 uno::Reference < beans::XPropertySet > xNativeTempFile(
267 io::TempFile::create(comphelper::getComponentContext(m_xFactory)),
268 uno::UNO_QUERY_THROW );
269 uno::Reference < io::XStream > xNativeTempStream( xNativeTempFile, uno::UNO_QUERY_THROW );
270 uno::Reference < io::XOutputStream > xNativeOutTemp = xNativeTempStream->getOutputStream();
271 uno::Reference < io::XInputStream > xNativeInTemp = xNativeTempStream->getInputStream();
272 if ( !xNativeOutTemp.is() || !xNativeInTemp.is() )
273 throw uno::RuntimeException();
275 try {
276 xNativeTempFile->setPropertyValue("RemoveFile", uno::makeAny( sal_False ) );
277 uno::Any aUrl = xNativeTempFile->getPropertyValue("Uri");
278 aUrl >>= aNativeTempURL;
280 catch ( uno::Exception& )
284 sal_Bool bFailed = sal_False;
285 OUString aFileSuffix;
287 if ( bParseHeader )
289 uno::Sequence< sal_Int8 > aReadSeq( 4 );
290 // read the complete size of the Object Package
291 if ( xInStream->readBytes( aReadSeq, 4 ) != 4 )
292 return sal_False;
293 // read the first header ( have no idea what does this header mean )
294 if ( xInStream->readBytes( aReadSeq, 2 ) != 2 || aReadSeq[0] != 2 || aReadSeq[1] != 0 )
295 return sal_False;
297 // read file name
298 // only extension is interesting so only subset of symbols is accepted
301 if ( xInStream->readBytes( aReadSeq, 1 ) != 1 )
302 return sal_False;
304 if (
305 (aReadSeq[0] >= '0' && aReadSeq[0] <= '9') ||
306 (aReadSeq[0] >= 'a' && aReadSeq[0] <= 'z') ||
307 (aReadSeq[0] >= 'A' && aReadSeq[0] <= 'Z') ||
308 aReadSeq[0] == '.'
311 aFileSuffix += OUString( (sal_Unicode) aReadSeq[0] );
314 } while( aReadSeq[0] );
316 // skip url
319 if ( xInStream->readBytes( aReadSeq, 1 ) != 1 )
320 return sal_False;
321 } while( aReadSeq[0] );
323 // check the next header
324 if ( xInStream->readBytes( aReadSeq, 4 ) != 4
325 || aReadSeq[0] || aReadSeq[1] || aReadSeq[2] != 3 || aReadSeq[3] )
326 return sal_False;
328 // get the size of the next entry
329 if ( xInStream->readBytes( aReadSeq, 4 ) != 4 )
330 return sal_False;
332 sal_uInt32 nUrlSize = (sal_uInt8)aReadSeq[0]
333 + (sal_uInt8)aReadSeq[1] * 0x100
334 + (sal_uInt8)aReadSeq[2] * 0x10000
335 + (sal_uInt8)aReadSeq[3] * 0x1000000;
336 sal_Int64 nTargetPos = xSeekable->getPosition() + nUrlSize;
338 xSeekable->seek( nTargetPos );
340 // get the size of stored data
341 if ( xInStream->readBytes( aReadSeq, 4 ) != 4 )
342 return sal_False;
344 sal_uInt32 nDataSize = (sal_uInt8)aReadSeq[0]
345 + (sal_uInt8)aReadSeq[1] * 0x100
346 + (sal_uInt8)aReadSeq[2] * 0x10000
347 + (sal_uInt8)aReadSeq[3] * 0x1000000;
349 aReadSeq.realloc( 32000 );
350 sal_uInt32 nRead = 0;
351 while ( nRead < nDataSize )
353 sal_uInt32 nToRead = ( nDataSize - nRead > 32000 ) ? 32000 : nDataSize - nRead;
354 sal_uInt32 nLocalRead = xInStream->readBytes( aReadSeq, nToRead );
357 if ( !nLocalRead )
359 bFailed = sal_True;
360 break;
362 else if ( nLocalRead == 32000 )
363 xNativeOutTemp->writeBytes( aReadSeq );
364 else
366 uno::Sequence< sal_Int8 > aToWrite( aReadSeq );
367 aToWrite.realloc( nLocalRead );
368 xNativeOutTemp->writeBytes( aToWrite );
371 nRead += nLocalRead;
374 else
376 uno::Sequence< sal_Int8 > aData( 8 );
377 if ( xInStream->readBytes( aData, 8 ) == 8
378 && aData[0] == -1 && aData[1] == -1 && aData[2] == -1 && aData[3] == -1
379 && ( aData[4] == 2 || aData[4] == 3 ) && aData[5] == 0 && aData[6] == 0 && aData[7] == 0 )
381 // the header has to be removed
382 xSeekable->seek( 40 );
384 else
386 // the usual Ole10Native format
387 xSeekable->seek( 4 );
390 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xNativeOutTemp );
393 xNativeOutTemp->closeOutput();
395 // The temporary native file is created, now the filter must be detected
396 if ( !bFailed )
398 m_aFilterName = GetFilterNameFromExtentionAndInStream( m_xFactory, aFileSuffix, xNativeInTemp );
399 m_aNativeTempURL = aNativeTempURL;
402 return !bFailed;
405 //--------------------------------------------------------
406 void OwnView_Impl::CreateNative()
408 if ( !m_aNativeTempURL.isEmpty() )
409 return;
413 uno::Reference < ucb::XSimpleFileAccess3 > xAccess(
414 ucb::SimpleFileAccess::create( comphelper::getComponentContext(m_xFactory) ) );
416 uno::Reference< io::XInputStream > xInStream = xAccess->openFileRead( m_aTempFileURL );
417 if ( !xInStream.is() )
418 throw uno::RuntimeException();
420 uno::Sequence< uno::Any > aArgs( 1 );
421 aArgs[0] <<= xInStream;
422 uno::Reference< container::XNameAccess > xNameAccess(
423 m_xFactory->createInstanceWithArguments(
424 OUString( "com.sun.star.embed.OLESimpleStorage" ),
425 aArgs ),
426 uno::UNO_QUERY_THROW );
428 OUString aSubStreamName = "\1Ole10Native";
429 uno::Reference< embed::XClassifiedObject > xStor( xNameAccess, uno::UNO_QUERY_THROW );
430 uno::Sequence< sal_Int8 > aStorClassID = xStor->getClassID();
432 if ( xNameAccess->hasByName( aSubStreamName ) )
434 sal_uInt8 aClassID[] =
435 { 0x00, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
436 uno::Sequence< sal_Int8 > aPackageClassID( (sal_Int8*)aClassID, 16 );
438 uno::Reference< io::XStream > xSubStream;
439 xNameAccess->getByName( aSubStreamName ) >>= xSubStream;
440 if ( xSubStream.is() )
442 sal_Bool bOk = sal_False;
444 if ( MimeConfigurationHelper::ClassIDsEqual( aPackageClassID, aStorClassID ) )
446 // the storage represents Object Package
448 bOk = ReadContentsAndGenerateTempFile( xSubStream->getInputStream(), sal_True );
450 if ( !bOk && !m_aNativeTempURL.isEmpty() )
452 KillFile_Impl( m_aNativeTempURL, m_xFactory );
453 m_aNativeTempURL = OUString();
457 if ( !bOk )
459 bOk = ReadContentsAndGenerateTempFile( xSubStream->getInputStream(), sal_False );
461 if ( !bOk && !m_aNativeTempURL.isEmpty() )
463 KillFile_Impl( m_aNativeTempURL, m_xFactory );
464 m_aNativeTempURL = OUString();
469 else
471 // TODO/LATER: No native stream, needs a new solution
474 catch( uno::Exception& )
478 //--------------------------------------------------------
479 sal_Bool OwnView_Impl::Open()
481 sal_Bool bResult = sal_False;
483 uno::Reference< frame::XModel > xExistingModel;
486 ::osl::MutexGuard aGuard( m_aMutex );
487 xExistingModel = m_xModel;
488 if ( m_bBusy )
489 return sal_False;
491 m_bBusy = sal_True;
494 if ( xExistingModel.is() )
496 try {
497 uno::Reference< frame::XController > xController = xExistingModel->getCurrentController();
498 if ( xController.is() )
500 uno::Reference< frame::XFrame > xFrame = xController->getFrame();
501 if ( xFrame.is() )
503 xFrame->activate();
504 uno::Reference<awt::XTopWindow> xTopWindow( xFrame->getContainerWindow(), uno::UNO_QUERY );
505 if(xTopWindow.is())
506 xTopWindow->toFront();
508 bResult = sal_True;
512 catch( uno::Exception& )
516 else
518 bResult = CreateModel( m_bUseNative );
520 if ( !bResult && !m_bUseNative )
522 // the original storage can not be recognized
523 if ( m_aNativeTempURL.isEmpty() )
525 // create a temporary file for the native representation if there is no
526 CreateNative();
529 if ( !m_aNativeTempURL.isEmpty() )
531 bResult = CreateModel( sal_True );
532 if ( bResult )
533 m_bUseNative = sal_True;
538 m_bBusy = sal_False;
540 return bResult;
543 //--------------------------------------------------------
544 void OwnView_Impl::Close()
546 uno::Reference< frame::XModel > xModel;
549 ::osl::MutexGuard aGuard( m_aMutex );
550 if ( !m_xModel.is() )
551 return;
552 xModel = m_xModel;
553 m_xModel = uno::Reference< frame::XModel >();
555 if ( m_bBusy )
556 return;
558 m_bBusy = sal_True;
561 try {
562 uno::Reference< document::XEventBroadcaster > xBroadCaster( xModel, uno::UNO_QUERY );
563 if ( xBroadCaster.is() )
564 xBroadCaster->removeEventListener( uno::Reference< document::XEventListener >(
565 static_cast< ::cppu::OWeakObject* >( this ),
566 uno::UNO_QUERY ) );
568 uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
569 if ( xCloseable.is() )
571 xCloseable->removeCloseListener( uno::Reference< util::XCloseListener >(
572 static_cast< ::cppu::OWeakObject* >( this ),
573 uno::UNO_QUERY ) );
574 xCloseable->close( sal_True );
577 catch( uno::Exception& )
580 m_bBusy = sal_False;
583 //--------------------------------------------------------
584 void SAL_CALL OwnView_Impl::notifyEvent( const document::EventObject& aEvent )
585 throw ( uno::RuntimeException )
588 uno::Reference< frame::XModel > xModel;
591 ::osl::MutexGuard aGuard( m_aMutex );
592 if ( aEvent.Source == m_xModel && aEvent.EventName.startsWith( "OnSaveAsDone" ) )
594 // SaveAs operation took place, so just forget the model and deregister listeners
595 xModel = m_xModel;
596 m_xModel = uno::Reference< frame::XModel >();
600 if ( xModel.is() )
602 try {
603 uno::Reference< document::XEventBroadcaster > xBroadCaster( xModel, uno::UNO_QUERY );
604 if ( xBroadCaster.is() )
605 xBroadCaster->removeEventListener( uno::Reference< document::XEventListener >(
606 static_cast< ::cppu::OWeakObject* >( this ),
607 uno::UNO_QUERY ) );
609 uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
610 if ( xCloseable.is() )
611 xCloseable->removeCloseListener( uno::Reference< util::XCloseListener >(
612 static_cast< ::cppu::OWeakObject* >( this ),
613 uno::UNO_QUERY ) );
615 catch( uno::Exception& )
620 //--------------------------------------------------------
621 void SAL_CALL OwnView_Impl::queryClosing( const lang::EventObject&, sal_Bool )
622 throw ( util::CloseVetoException,
623 uno::RuntimeException )
627 //--------------------------------------------------------
628 void SAL_CALL OwnView_Impl::notifyClosing( const lang::EventObject& Source )
629 throw ( uno::RuntimeException )
631 ::osl::MutexGuard aGuard( m_aMutex );
632 if ( Source.Source == m_xModel )
633 m_xModel = uno::Reference< frame::XModel >();
636 //--------------------------------------------------------
637 void SAL_CALL OwnView_Impl::disposing( const lang::EventObject& Source )
638 throw (uno::RuntimeException)
640 ::osl::MutexGuard aGuard( m_aMutex );
641 if ( Source.Source == m_xModel )
642 m_xModel = uno::Reference< frame::XModel >();
645 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */