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: ownview.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_embeddedobj.hxx"
33 #include <com/sun/star/frame/XFrame.hpp>
34 #include <com/sun/star/frame/XController.hpp>
35 #include <com/sun/star/frame/XComponentLoader.hpp>
36 #include <com/sun/star/awt/XTopWindow.hpp>
37 #include <com/sun/star/embed/XClassifiedObject.hpp>
38 #include <com/sun/star/io/XStream.hpp>
39 #include <com/sun/star/io/XInputStream.hpp>
40 #include <com/sun/star/io/XOutputStream.hpp>
41 #include <com/sun/star/io/XSeekable.hpp>
42 #include <com/sun/star/task/XInteractionHandler.hpp>
43 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
44 #include <com/sun/star/util/XCloseable.hpp>
45 #include <com/sun/star/beans/XPropertySet.hpp>
47 #ifndef _COM_SUN_STAR_DOCUMENT_XEVENTBRODCASTER_HPP_
48 #include <com/sun/star/document/XEventBroadcaster.hpp>
50 #include <com/sun/star/document/XEventListener.hpp>
51 #include <com/sun/star/document/XTypeDetection.hpp>
52 #include <com/sun/star/container/XNameAccess.hpp>
53 #include <cppuhelper/implbase1.hxx>
54 #include <comphelper/storagehelper.hxx>
55 #include <comphelper/mimeconfighelper.hxx>
57 #include "ownview.hxx"
60 using namespace ::com::sun::star
;
61 using namespace ::comphelper
;
63 ::rtl::OUString
GetNewTempFileURL_Impl( const uno::Reference
< lang::XMultiServiceFactory
>& xFactory
) throw( io::IOException
);
64 ::rtl::OUString
GetNewFilledTempFile_Impl( const uno::Reference
< io::XInputStream
>& xInStream
, const uno::Reference
< lang::XMultiServiceFactory
>& xFactory
) throw( io::IOException
);
65 sal_Bool
KillFile_Impl( const ::rtl::OUString
& aURL
, const uno::Reference
< lang::XMultiServiceFactory
>& xFactory
);
66 uno::Reference
< io::XStream
> TryToGetAcceptableFormat_Impl( const uno::Reference
< io::XStream
>& xStream
, const uno::Reference
< lang::XMultiServiceFactory
>& xFactory
) throw ( uno::Exception
);
68 //========================================================
69 // Dummy interaction handler
70 //========================================================
71 //--------------------------------------------------------
72 class DummyHandler_Impl
: public ::cppu::WeakImplHelper1
< task::XInteractionHandler
>
75 DummyHandler_Impl() {}
78 virtual void SAL_CALL
handle( const uno::Reference
< task::XInteractionRequest
>& xRequest
)
79 throw( uno::RuntimeException
);
82 //--------------------------------------------------------
83 DummyHandler_Impl::~DummyHandler_Impl()
87 //--------------------------------------------------------
88 void SAL_CALL
DummyHandler_Impl::handle( const uno::Reference
< task::XInteractionRequest
>& )
89 throw( uno::RuntimeException
)
94 //========================================================
96 //========================================================
97 //--------------------------------------------------------
98 OwnView_Impl::OwnView_Impl( const uno::Reference
< lang::XMultiServiceFactory
>& xFactory
,
99 const uno::Reference
< io::XInputStream
>& xInputStream
)
100 : m_xFactory( xFactory
)
101 , m_bBusy( sal_False
)
102 , m_bUseNative( sal_False
)
104 if ( !xFactory
.is() || !xInputStream
.is() )
105 throw uno::RuntimeException();
107 m_aTempFileURL
= GetNewFilledTempFile_Impl( xInputStream
, m_xFactory
);
110 //--------------------------------------------------------
111 OwnView_Impl::~OwnView_Impl()
114 KillFile_Impl( m_aTempFileURL
, m_xFactory
);
115 } catch( uno::Exception
& ) {}
118 if ( m_aNativeTempURL
.getLength() )
119 KillFile_Impl( m_aNativeTempURL
, m_xFactory
);
120 } catch( uno::Exception
& ) {}
123 //--------------------------------------------------------
124 sal_Bool
OwnView_Impl::CreateModelFromURL( const ::rtl::OUString
& aFileURL
)
126 sal_Bool bResult
= sal_False
;
128 if ( aFileURL
.getLength() )
131 uno::Reference
< frame::XComponentLoader
> xDocumentLoader(
132 m_xFactory
->createInstance (
133 ::rtl::OUString::createFromAscii( "com.sun.star.frame.Desktop" ) ),
136 if ( xDocumentLoader
.is() )
138 uno::Sequence
< beans::PropertyValue
> aArgs( m_aFilterName
.getLength() ? 5 : 4 );
140 aArgs
[0].Name
= ::rtl::OUString::createFromAscii( "URL" );
141 aArgs
[0].Value
<<= aFileURL
;
143 aArgs
[1].Name
= ::rtl::OUString::createFromAscii( "ReadOnly" );
144 aArgs
[1].Value
<<= sal_True
;
146 aArgs
[2].Name
= ::rtl::OUString::createFromAscii( "InteractionHandler" );
147 aArgs
[2].Value
<<= uno::Reference
< task::XInteractionHandler
>(
148 static_cast< ::cppu::OWeakObject
* >( new DummyHandler_Impl() ), uno::UNO_QUERY
);
150 aArgs
[3].Name
= ::rtl::OUString::createFromAscii( "DontEdit" );
151 aArgs
[3].Value
<<= sal_True
;
153 if ( m_aFilterName
.getLength() )
155 aArgs
[4].Name
= ::rtl::OUString::createFromAscii( "FilterName" );
156 aArgs
[4].Value
<<= m_aFilterName
;
159 uno::Reference
< frame::XModel
> xModel( xDocumentLoader
->loadComponentFromURL(
161 ::rtl::OUString::createFromAscii( "_blank" ),
168 uno::Reference
< document::XEventBroadcaster
> xBroadCaster( xModel
, uno::UNO_QUERY
);
169 if ( xBroadCaster
.is() )
170 xBroadCaster
->addEventListener( uno::Reference
< document::XEventListener
>(
171 static_cast< ::cppu::OWeakObject
* >( this ),
174 uno::Reference
< util::XCloseable
> xCloseable( xModel
, uno::UNO_QUERY
);
175 if ( xCloseable
.is() )
177 xCloseable
->addCloseListener( uno::Reference
< util::XCloseListener
>(
178 static_cast< ::cppu::OWeakObject
* >( this ),
181 ::osl::MutexGuard
aGuard( m_aMutex
);
188 catch( uno::Exception
& )
196 //--------------------------------------------------------
197 sal_Bool
OwnView_Impl::CreateModel( sal_Bool bUseNative
)
199 sal_Bool bResult
= sal_False
;
202 bResult
= CreateModelFromURL( bUseNative
? m_aNativeTempURL
: m_aTempFileURL
);
204 catch( uno::Exception
& )
211 //--------------------------------------------------------
212 ::rtl::OUString
OwnView_Impl::GetFilterNameFromExtentionAndInStream(
213 const ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
>& xFactory
,
214 const ::rtl::OUString
& aNameWithExtention
,
215 const uno::Reference
< io::XInputStream
>& xInputStream
)
217 if ( !xInputStream
.is() )
218 throw uno::RuntimeException();
220 uno::Reference
< document::XTypeDetection
> xTypeDetection(
221 xFactory
->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.TypeDetection" ) ),
222 uno::UNO_QUERY_THROW
);
224 ::rtl::OUString aTypeName
;
226 if ( aNameWithExtention
.getLength() )
228 ::rtl::OUString aURLToAnalyze
=
229 ( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "file:///" ) ) + aNameWithExtention
);
230 aTypeName
= xTypeDetection
->queryTypeByURL( aURLToAnalyze
);
233 uno::Sequence
< beans::PropertyValue
> aArgs( aTypeName
.getLength() ? 3 : 2 );
234 aArgs
[0].Name
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) );
235 aArgs
[0].Value
<<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:stream" ) );
236 aArgs
[1].Name
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InputStream" ) );
237 aArgs
[1].Value
<<= xInputStream
;
238 if ( aTypeName
.getLength() )
240 aArgs
[2].Name
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TypeName" ) );
241 aArgs
[2].Value
<<= aTypeName
;
244 aTypeName
= xTypeDetection
->queryTypeByDescriptor( aArgs
, sal_True
);
246 ::rtl::OUString aFilterName
;
247 for ( sal_Int32 nInd
= 0; nInd
< aArgs
.getLength(); nInd
++ )
248 if ( aArgs
[nInd
].Name
.equalsAscii( "FilterName" ) )
249 aArgs
[nInd
].Value
>>= aFilterName
;
251 if ( !aFilterName
.getLength() && aTypeName
.getLength() )
253 // get the default filter name for the type
254 uno::Reference
< container::XNameAccess
> xNameAccess( xTypeDetection
, uno::UNO_QUERY_THROW
);
255 uno::Sequence
< beans::PropertyValue
> aTypes
;
257 if ( xNameAccess
.is() && ( xNameAccess
->getByName( aTypeName
) >>= aTypes
) )
259 for ( sal_Int32 nInd
= 0; nInd
< aTypes
.getLength(); nInd
++ )
261 if ( aTypes
[nInd
].Name
.equalsAscii( "PreferredFilter" ) && ( aTypes
[nInd
].Value
>>= aFilterName
) )
263 aTypes
[nInd
].Value
>>= aFilterName
;
273 //--------------------------------------------------------
274 sal_Bool
OwnView_Impl::ReadContentsAndGenerateTempFile( const uno::Reference
< io::XInputStream
>& xInStream
,
275 sal_Bool bParseHeader
)
277 uno::Reference
< io::XSeekable
> xSeekable( xInStream
, uno::UNO_QUERY_THROW
);
278 xSeekable
->seek( 0 );
280 // create m_aNativeTempURL
281 ::rtl::OUString aNativeTempURL
;
282 uno::Reference
< beans::XPropertySet
> xNativeTempFile(
283 m_xFactory
->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ),
284 uno::UNO_QUERY_THROW
);
285 uno::Reference
< io::XStream
> xNativeTempStream( xNativeTempFile
, uno::UNO_QUERY_THROW
);
286 uno::Reference
< io::XOutputStream
> xNativeOutTemp
= xNativeTempStream
->getOutputStream();
287 uno::Reference
< io::XInputStream
> xNativeInTemp
= xNativeTempStream
->getInputStream();
288 if ( !xNativeOutTemp
.is() || !xNativeInTemp
.is() )
289 throw uno::RuntimeException();
292 xNativeTempFile
->setPropertyValue( ::rtl::OUString::createFromAscii( "RemoveFile" ), uno::makeAny( sal_False
) );
293 uno::Any aUrl
= xNativeTempFile
->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) );
294 aUrl
>>= aNativeTempURL
;
296 catch ( uno::Exception
& )
300 sal_Bool bFailed
= sal_False
;
301 ::rtl::OUString aFileSuffix
;
305 uno::Sequence
< sal_Int8
> aReadSeq( 4 );
306 // read the complete size of the Object Package
307 if ( xInStream
->readBytes( aReadSeq
, 4 ) != 4 )
310 sal_uInt32 nLength = (sal_uInt8)aReadSeq[0]
311 + (sal_uInt8)aReadSeq[1] * 0x100
312 + (sal_uInt8)aReadSeq[2] * 0x10000
313 + (sal_uInt8)aReadSeq[3] * 0x1000000;
315 // read the first header ( have no idea what does this header mean )
316 if ( xInStream
->readBytes( aReadSeq
, 2 ) != 2 || aReadSeq
[0] != 2 || aReadSeq
[1] != 0 )
320 // only extension is interesting so only subset of symbols is accepted
323 if ( xInStream
->readBytes( aReadSeq
, 1 ) != 1 )
327 (aReadSeq
[0] >= '0' && aReadSeq
[0] <= '9') ||
328 (aReadSeq
[0] >= 'a' && aReadSeq
[0] <= 'z') ||
329 (aReadSeq
[0] >= 'A' && aReadSeq
[0] <= 'Z') ||
333 aFileSuffix
+= ::rtl::OUString::valueOf( (sal_Unicode
) aReadSeq
[0] );
336 } while( aReadSeq
[0] );
341 if ( xInStream
->readBytes( aReadSeq
, 1 ) != 1 )
343 } while( aReadSeq
[0] );
345 // check the next header
346 if ( xInStream
->readBytes( aReadSeq
, 4 ) != 4
347 || aReadSeq
[0] || aReadSeq
[1] || aReadSeq
[2] != 3 || aReadSeq
[3] )
350 // get the size of the next entry
351 if ( xInStream
->readBytes( aReadSeq
, 4 ) != 4 )
354 sal_uInt32 nUrlSize
= (sal_uInt8
)aReadSeq
[0]
355 + (sal_uInt8
)aReadSeq
[1] * 0x100
356 + (sal_uInt8
)aReadSeq
[2] * 0x10000
357 + (sal_uInt8
)aReadSeq
[3] * 0x1000000;
358 sal_Int64 nTargetPos
= xSeekable
->getPosition() + nUrlSize
;
360 xSeekable
->seek( nTargetPos
);
362 // get the size of stored data
363 if ( xInStream
->readBytes( aReadSeq
, 4 ) != 4 )
366 sal_uInt32 nDataSize
= (sal_uInt8
)aReadSeq
[0]
367 + (sal_uInt8
)aReadSeq
[1] * 0x100
368 + (sal_uInt8
)aReadSeq
[2] * 0x10000
369 + (sal_uInt8
)aReadSeq
[3] * 0x1000000;
371 aReadSeq
.realloc( 32000 );
372 sal_uInt32 nRead
= 0;
373 while ( nRead
< nDataSize
)
375 sal_uInt32 nToRead
= ( nDataSize
- nRead
> 32000 ) ? 32000 : nDataSize
- nRead
;
376 sal_uInt32 nLocalRead
= xInStream
->readBytes( aReadSeq
, nToRead
);
384 else if ( nLocalRead
== 32000 )
385 xNativeOutTemp
->writeBytes( aReadSeq
);
388 uno::Sequence
< sal_Int8
> aToWrite( aReadSeq
);
389 aToWrite
.realloc( nLocalRead
);
390 xNativeOutTemp
->writeBytes( aToWrite
);
398 uno::Sequence
< sal_Int8
> aData( 8 );
399 if ( xInStream
->readBytes( aData
, 8 ) == 8
400 && aData
[0] == -1 && aData
[1] == -1 && aData
[2] == -1 && aData
[3] == -1
401 && ( aData
[4] == 2 || aData
[4] == 3 ) && aData
[5] == 0 && aData
[6] == 0 && aData
[7] == 0 )
403 // the header has to be removed
404 xSeekable
->seek( 40 );
408 // the usual Ole10Native format
409 xSeekable
->seek( 4 );
412 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream
, xNativeOutTemp
);
415 xNativeOutTemp
->closeOutput();
417 // The temporary native file is created, now the filter must be detected
420 m_aFilterName
= GetFilterNameFromExtentionAndInStream( m_xFactory
, aFileSuffix
, xNativeInTemp
);
421 m_aNativeTempURL
= aNativeTempURL
;
427 //--------------------------------------------------------
428 void OwnView_Impl::CreateNative()
430 if ( m_aNativeTempURL
.getLength() )
435 uno::Reference
< ucb::XSimpleFileAccess
> xAccess(
436 m_xFactory
->createInstance (
437 ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ),
438 uno::UNO_QUERY_THROW
);
440 uno::Reference
< io::XInputStream
> xInStream
= xAccess
->openFileRead( m_aTempFileURL
);
441 if ( !xInStream
.is() )
442 throw uno::RuntimeException();
444 uno::Sequence
< uno::Any
> aArgs( 1 );
445 aArgs
[0] <<= xInStream
;
446 uno::Reference
< container::XNameAccess
> xNameAccess(
447 m_xFactory
->createInstanceWithArguments(
448 ::rtl::OUString::createFromAscii( "com.sun.star.embed.OLESimpleStorage" ),
450 uno::UNO_QUERY_THROW
);
452 ::rtl::OUString aSubStreamName
= ::rtl::OUString::createFromAscii( "\1Ole10Native" );
453 uno::Reference
< embed::XClassifiedObject
> xStor( xNameAccess
, uno::UNO_QUERY_THROW
);
454 uno::Sequence
< sal_Int8
> aStorClassID
= xStor
->getClassID();
456 if ( xNameAccess
->hasByName( aSubStreamName
) )
458 sal_uInt8 aClassID
[] =
459 { 0x00, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
460 uno::Sequence
< sal_Int8
> aPackageClassID( (sal_Int8
*)aClassID
, 16 );
462 uno::Reference
< io::XStream
> xSubStream
;
463 xNameAccess
->getByName( aSubStreamName
) >>= xSubStream
;
464 if ( xSubStream
.is() )
466 sal_Bool bOk
= sal_False
;
468 if ( MimeConfigurationHelper::ClassIDsEqual( aPackageClassID
, aStorClassID
) )
470 // the storage represents Object Package
472 bOk
= ReadContentsAndGenerateTempFile( xSubStream
->getInputStream(), sal_True
);
474 if ( !bOk
&& m_aNativeTempURL
.getLength() )
476 KillFile_Impl( m_aNativeTempURL
, m_xFactory
);
477 m_aNativeTempURL
= ::rtl::OUString();
483 bOk
= ReadContentsAndGenerateTempFile( xSubStream
->getInputStream(), sal_False
);
485 if ( !bOk
&& m_aNativeTempURL
.getLength() )
487 KillFile_Impl( m_aNativeTempURL
, m_xFactory
);
488 m_aNativeTempURL
= ::rtl::OUString();
495 // TODO/LATER: No native stream, needs a new solution
498 catch( uno::Exception
& )
502 //--------------------------------------------------------
503 sal_Bool
OwnView_Impl::Open()
505 sal_Bool bResult
= sal_False
;
507 uno::Reference
< frame::XModel
> xExistingModel
;
510 ::osl::MutexGuard
aGuard( m_aMutex
);
511 xExistingModel
= m_xModel
;
518 if ( xExistingModel
.is() )
521 uno::Reference
< frame::XController
> xController
= xExistingModel
->getCurrentController();
522 if ( xController
.is() )
524 uno::Reference
< frame::XFrame
> xFrame
= xController
->getFrame();
528 uno::Reference
<awt::XTopWindow
> xTopWindow( xFrame
->getContainerWindow(), uno::UNO_QUERY
);
530 xTopWindow
->toFront();
536 catch( uno::Exception
& )
542 bResult
= CreateModel( m_bUseNative
);
544 if ( !bResult
&& !m_bUseNative
)
546 // the original storage can not be recognized
547 if ( !m_aNativeTempURL
.getLength() )
549 // create a temporary file for the native representation if there is no
553 if ( m_aNativeTempURL
.getLength() )
555 bResult
= CreateModel( sal_True
);
557 m_bUseNative
= sal_True
;
567 //--------------------------------------------------------
568 void OwnView_Impl::Close()
570 uno::Reference
< frame::XModel
> xModel
;
573 ::osl::MutexGuard
aGuard( m_aMutex
);
574 if ( !m_xModel
.is() )
577 m_xModel
= uno::Reference
< frame::XModel
>();
586 uno::Reference
< document::XEventBroadcaster
> xBroadCaster( xModel
, uno::UNO_QUERY
);
587 if ( xBroadCaster
.is() )
588 xBroadCaster
->removeEventListener( uno::Reference
< document::XEventListener
>(
589 static_cast< ::cppu::OWeakObject
* >( this ),
592 uno::Reference
< util::XCloseable
> xCloseable( xModel
, uno::UNO_QUERY
);
593 if ( xCloseable
.is() )
595 xCloseable
->removeCloseListener( uno::Reference
< util::XCloseListener
>(
596 static_cast< ::cppu::OWeakObject
* >( this ),
598 xCloseable
->close( sal_True
);
601 catch( uno::Exception
& )
607 //--------------------------------------------------------
608 void SAL_CALL
OwnView_Impl::notifyEvent( const document::EventObject
& aEvent
)
609 throw ( uno::RuntimeException
)
612 uno::Reference
< frame::XModel
> xModel
;
615 ::osl::MutexGuard
aGuard( m_aMutex
);
616 if ( aEvent
.Source
== m_xModel
&& aEvent
.EventName
.equalsAscii( "OnSaveAsDone" ) )
618 // SaveAs operation took place, so just forget the model and deregister listeners
620 m_xModel
= uno::Reference
< frame::XModel
>();
627 uno::Reference
< document::XEventBroadcaster
> xBroadCaster( xModel
, uno::UNO_QUERY
);
628 if ( xBroadCaster
.is() )
629 xBroadCaster
->removeEventListener( uno::Reference
< document::XEventListener
>(
630 static_cast< ::cppu::OWeakObject
* >( this ),
633 uno::Reference
< util::XCloseable
> xCloseable( xModel
, uno::UNO_QUERY
);
634 if ( xCloseable
.is() )
635 xCloseable
->removeCloseListener( uno::Reference
< util::XCloseListener
>(
636 static_cast< ::cppu::OWeakObject
* >( this ),
639 catch( uno::Exception
& )
644 //--------------------------------------------------------
645 void SAL_CALL
OwnView_Impl::queryClosing( const lang::EventObject
&, sal_Bool
)
646 throw ( util::CloseVetoException
,
647 uno::RuntimeException
)
651 //--------------------------------------------------------
652 void SAL_CALL
OwnView_Impl::notifyClosing( const lang::EventObject
& Source
)
653 throw ( uno::RuntimeException
)
655 ::osl::MutexGuard
aGuard( m_aMutex
);
656 if ( Source
.Source
== m_xModel
)
657 m_xModel
= uno::Reference
< frame::XModel
>();
660 //--------------------------------------------------------
661 void SAL_CALL
OwnView_Impl::disposing( const lang::EventObject
& Source
)
662 throw (uno::RuntimeException
)
664 ::osl::MutexGuard
aGuard( m_aMutex
);
665 if ( Source
.Source
== m_xModel
)
666 m_xModel
= uno::Reference
< frame::XModel
>();