nss: upgrade to release 3.73
[LibreOffice.git] / embeddedobj / source / msole / ownview.cxx
blob9cb811b7c6722631b21469222e8b4b33adabfb5f
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/awt/XTopWindow.hpp>
24 #include <com/sun/star/embed/XClassifiedObject.hpp>
25 #include <com/sun/star/io/TempFile.hpp>
26 #include <com/sun/star/io/XStream.hpp>
27 #include <com/sun/star/io/XOutputStream.hpp>
28 #include <com/sun/star/io/XSeekable.hpp>
29 #include <com/sun/star/task/XInteractionHandler.hpp>
30 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
31 #include <com/sun/star/util/XCloseable.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/document/XEventBroadcaster.hpp>
35 #include <com/sun/star/document/XEventListener.hpp>
36 #include <com/sun/star/document/XTypeDetection.hpp>
37 #include <com/sun/star/container/XNameAccess.hpp>
38 #include <cppuhelper/implbase.hxx>
39 #include <comphelper/processfactory.hxx>
40 #include <comphelper/storagehelper.hxx>
41 #include <comphelper/mimeconfighelper.hxx>
42 #include <tools/diagnose_ex.h>
44 #include "olepersist.hxx"
45 #include "ownview.hxx"
48 using namespace ::com::sun::star;
49 using namespace ::comphelper;
51 namespace {
53 class DummyHandler_Impl : public ::cppu::WeakImplHelper< task::XInteractionHandler >
55 public:
56 DummyHandler_Impl() {}
58 virtual void SAL_CALL handle( const uno::Reference< task::XInteractionRequest >& xRequest ) override;
63 void SAL_CALL DummyHandler_Impl::handle( const uno::Reference< task::XInteractionRequest >& )
68 // Object viewer
71 OwnView_Impl::OwnView_Impl( const uno::Reference< uno::XComponentContext >& xContext,
72 const uno::Reference< io::XInputStream >& xInputStream )
73 : m_xContext( xContext )
74 , m_bBusy( false )
75 , m_bUseNative( false )
77 if ( !xContext.is() || !xInputStream.is() )
78 throw uno::RuntimeException();
80 m_aTempFileURL = GetNewFilledTempFile_Impl( xInputStream, m_xContext );
84 OwnView_Impl::~OwnView_Impl()
86 try {
87 KillFile_Impl( m_aTempFileURL, m_xContext );
88 } catch( uno::Exception& ) {}
90 try {
91 if ( !m_aNativeTempURL.isEmpty() )
92 KillFile_Impl( m_aNativeTempURL, m_xContext );
93 } catch( uno::Exception& ) {}
97 bool OwnView_Impl::CreateModelFromURL( const OUString& aFileURL )
99 bool bResult = false;
101 if ( !aFileURL.isEmpty() )
103 try {
104 uno::Reference < frame::XDesktop2 > xDocumentLoader = frame::Desktop::create(m_xContext);
106 uno::Sequence< beans::PropertyValue > aArgs( m_aFilterName.isEmpty() ? 4 : 5 );
108 aArgs[0].Name = "URL";
109 aArgs[0].Value <<= aFileURL;
111 aArgs[1].Name = "ReadOnly";
112 aArgs[1].Value <<= true;
114 aArgs[2].Name = "InteractionHandler";
115 aArgs[2].Value <<= uno::Reference< task::XInteractionHandler >(
116 static_cast< ::cppu::OWeakObject* >( new DummyHandler_Impl() ), uno::UNO_QUERY );
118 aArgs[3].Name = "DontEdit";
119 aArgs[3].Value <<= true;
121 if ( !m_aFilterName.isEmpty() )
123 aArgs[4].Name = "FilterName";
124 aArgs[4].Value <<= m_aFilterName;
127 uno::Reference< frame::XModel > xModel( xDocumentLoader->loadComponentFromURL(
128 aFileURL,
129 "_blank",
131 aArgs ),
132 uno::UNO_QUERY );
134 if ( xModel.is() )
136 uno::Reference< document::XEventBroadcaster > xBroadCaster( xModel, uno::UNO_QUERY );
137 if ( xBroadCaster.is() )
138 xBroadCaster->addEventListener( uno::Reference< document::XEventListener >(
139 static_cast< ::cppu::OWeakObject* >( this ),
140 uno::UNO_QUERY ) );
142 uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
143 if ( xCloseable.is() )
145 xCloseable->addCloseListener( uno::Reference< util::XCloseListener >(
146 static_cast< ::cppu::OWeakObject* >( this ),
147 uno::UNO_QUERY ) );
149 ::osl::MutexGuard aGuard( m_aMutex );
150 m_xModel = xModel;
151 bResult = true;
155 catch (uno::Exception const&)
157 TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OwnView_Impl::CreateModelFromURL:");
161 return bResult;
165 bool OwnView_Impl::CreateModel( bool bUseNative )
167 bool bResult = false;
169 try {
170 bResult = CreateModelFromURL( bUseNative ? m_aNativeTempURL : m_aTempFileURL );
172 catch( uno::Exception& )
176 return bResult;
180 OUString OwnView_Impl::GetFilterNameFromExtentionAndInStream(
181 const css::uno::Reference< css::uno::XComponentContext >& xContext,
182 const OUString& aNameWithExtention,
183 const uno::Reference< io::XInputStream >& xInputStream )
185 if ( !xInputStream.is() )
186 throw uno::RuntimeException();
188 uno::Reference< document::XTypeDetection > xTypeDetection(
189 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", xContext),
190 uno::UNO_QUERY_THROW );
192 OUString aTypeName;
194 if ( !aNameWithExtention.isEmpty() )
196 OUString aURLToAnalyze = "file:///" + aNameWithExtention;
197 aTypeName = xTypeDetection->queryTypeByURL( aURLToAnalyze );
200 uno::Sequence< beans::PropertyValue > aArgs( aTypeName.isEmpty() ? 2 : 3 );
201 aArgs[0].Name = "URL";
202 aArgs[0].Value <<= OUString( "private:stream" );
203 aArgs[1].Name = "InputStream";
204 aArgs[1].Value <<= xInputStream;
205 if ( !aTypeName.isEmpty() )
207 aArgs[2].Name = "TypeName";
208 aArgs[2].Value <<= aTypeName;
211 aTypeName = xTypeDetection->queryTypeByDescriptor( aArgs, true );
213 OUString aFilterName;
214 for ( beans::PropertyValue const & prop : std::as_const(aArgs) )
215 if ( prop.Name == "FilterName" )
216 prop.Value >>= aFilterName;
218 if ( aFilterName.isEmpty() && !aTypeName.isEmpty() )
220 // get the default filter name for the type
221 uno::Reference< container::XNameAccess > xNameAccess( xTypeDetection, uno::UNO_QUERY_THROW );
222 uno::Sequence< beans::PropertyValue > aTypes;
224 if ( xNameAccess.is() && ( xNameAccess->getByName( aTypeName ) >>= aTypes ) )
226 for ( beans::PropertyValue const & prop : std::as_const(aTypes) )
228 if ( prop.Name == "PreferredFilter" && ( prop.Value >>= aFilterName ) )
230 prop.Value >>= aFilterName;
231 break;
237 return aFilterName;
241 bool OwnView_Impl::ReadContentsAndGenerateTempFile( const uno::Reference< io::XInputStream >& xInStream,
242 bool bParseHeader )
244 uno::Reference< io::XSeekable > xSeekable( xInStream, uno::UNO_QUERY_THROW );
245 xSeekable->seek( 0 );
247 // create m_aNativeTempURL
248 OUString aNativeTempURL;
249 uno::Reference < beans::XPropertySet > xNativeTempFile(
250 io::TempFile::create(m_xContext),
251 uno::UNO_QUERY_THROW );
252 uno::Reference < io::XStream > xNativeTempStream( xNativeTempFile, uno::UNO_QUERY_THROW );
253 uno::Reference < io::XOutputStream > xNativeOutTemp = xNativeTempStream->getOutputStream();
254 uno::Reference < io::XInputStream > xNativeInTemp = xNativeTempStream->getInputStream();
255 if ( !xNativeOutTemp.is() || !xNativeInTemp.is() )
256 throw uno::RuntimeException();
258 try {
259 xNativeTempFile->setPropertyValue("RemoveFile", uno::makeAny( false ) );
260 uno::Any aUrl = xNativeTempFile->getPropertyValue("Uri");
261 aUrl >>= aNativeTempURL;
263 catch ( uno::Exception& )
267 bool bFailed = false;
268 OUString aFileSuffix;
270 if ( bParseHeader )
272 uno::Sequence< sal_Int8 > aReadSeq( 4 );
273 // read the complete size of the Object Package
274 if ( xInStream->readBytes( aReadSeq, 4 ) != 4 )
275 return false;
276 // read the first header ( have no idea what does this header mean )
277 if ( xInStream->readBytes( aReadSeq, 2 ) != 2 || aReadSeq[0] != 2 || aReadSeq[1] != 0 )
278 return false;
280 // read file name
281 // only extension is interesting so only subset of symbols is accepted
284 if ( xInStream->readBytes( aReadSeq, 1 ) != 1 )
285 return false;
287 if (
288 (aReadSeq[0] >= '0' && aReadSeq[0] <= '9') ||
289 (aReadSeq[0] >= 'a' && aReadSeq[0] <= 'z') ||
290 (aReadSeq[0] >= 'A' && aReadSeq[0] <= 'Z') ||
291 aReadSeq[0] == '.'
294 aFileSuffix += OUStringChar( sal_Unicode(aReadSeq[0]) );
297 } while( aReadSeq[0] );
299 // skip url
302 if ( xInStream->readBytes( aReadSeq, 1 ) != 1 )
303 return false;
304 } while( aReadSeq[0] );
306 // check the next header
307 if ( xInStream->readBytes( aReadSeq, 4 ) != 4
308 || aReadSeq[0] || aReadSeq[1] || aReadSeq[2] != 3 || aReadSeq[3] )
309 return false;
311 // get the size of the next entry
312 if ( xInStream->readBytes( aReadSeq, 4 ) != 4 )
313 return false;
315 sal_uInt32 nUrlSize = static_cast<sal_uInt8>(aReadSeq[0])
316 + static_cast<sal_uInt8>(aReadSeq[1]) * 0x100
317 + static_cast<sal_uInt8>(aReadSeq[2]) * 0x10000
318 + static_cast<sal_uInt8>(aReadSeq[3]) * 0x1000000;
319 sal_Int64 nTargetPos = xSeekable->getPosition() + nUrlSize;
321 xSeekable->seek( nTargetPos );
323 // get the size of stored data
324 if ( xInStream->readBytes( aReadSeq, 4 ) != 4 )
325 return false;
327 sal_uInt32 nDataSize = static_cast<sal_uInt8>(aReadSeq[0])
328 + static_cast<sal_uInt8>(aReadSeq[1]) * 0x100
329 + static_cast<sal_uInt8>(aReadSeq[2]) * 0x10000
330 + static_cast<sal_uInt8>(aReadSeq[3]) * 0x1000000;
332 aReadSeq.realloc( 32000 );
333 sal_uInt32 nRead = 0;
334 while ( nRead < nDataSize )
336 sal_uInt32 nToRead = std::min<sal_uInt32>( nDataSize - nRead, 32000 );
337 sal_uInt32 nLocalRead = xInStream->readBytes( aReadSeq, nToRead );
340 if ( !nLocalRead )
342 bFailed = true;
343 break;
345 else if ( nLocalRead == 32000 )
346 xNativeOutTemp->writeBytes( aReadSeq );
347 else
349 uno::Sequence< sal_Int8 > aToWrite( aReadSeq );
350 aToWrite.realloc( nLocalRead );
351 xNativeOutTemp->writeBytes( aToWrite );
354 nRead += nLocalRead;
357 else
359 uno::Sequence< sal_Int8 > aData( 8 );
360 if ( xInStream->readBytes( aData, 8 ) == 8
361 && aData[0] == -1 && aData[1] == -1 && aData[2] == -1 && aData[3] == -1
362 && ( aData[4] == 2 || aData[4] == 3 ) && aData[5] == 0 && aData[6] == 0 && aData[7] == 0 )
364 // the header has to be removed
365 xSeekable->seek( 40 );
367 else
369 // the usual Ole10Native format
370 xSeekable->seek( 4 );
373 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xNativeOutTemp );
376 xNativeOutTemp->closeOutput();
378 // The temporary native file is created, now the filter must be detected
379 if ( !bFailed )
381 m_aFilterName = GetFilterNameFromExtentionAndInStream( m_xContext, aFileSuffix, xNativeInTemp );
382 m_aNativeTempURL = aNativeTempURL;
385 return !bFailed;
389 void OwnView_Impl::CreateNative()
391 if ( !m_aNativeTempURL.isEmpty() )
392 return;
396 uno::Reference < ucb::XSimpleFileAccess3 > xAccess(
397 ucb::SimpleFileAccess::create( m_xContext ) );
399 uno::Reference< io::XInputStream > xInStream = xAccess->openFileRead( m_aTempFileURL );
400 if ( !xInStream.is() )
401 throw uno::RuntimeException();
403 uno::Sequence< uno::Any > aArgs( 1 );
404 aArgs[0] <<= xInStream;
405 uno::Reference< container::XNameAccess > xNameAccess(
406 m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
407 "com.sun.star.embed.OLESimpleStorage",
408 aArgs, m_xContext ),
409 uno::UNO_QUERY_THROW );
411 OUString aSubStreamName = "\1Ole10Native";
412 uno::Reference< embed::XClassifiedObject > xStor( xNameAccess, uno::UNO_QUERY_THROW );
413 uno::Sequence< sal_Int8 > aStorClassID = xStor->getClassID();
415 if ( xNameAccess->hasByName( aSubStreamName ) )
417 sal_uInt8 const aClassID[] =
418 { 0x00, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
419 uno::Sequence< sal_Int8 > aPackageClassID( reinterpret_cast<sal_Int8 const *>(aClassID), 16 );
421 uno::Reference< io::XStream > xSubStream;
422 xNameAccess->getByName( aSubStreamName ) >>= xSubStream;
423 if ( xSubStream.is() )
425 bool bOk = false;
427 if ( MimeConfigurationHelper::ClassIDsEqual( aPackageClassID, aStorClassID ) )
429 // the storage represents Object Package
431 bOk = ReadContentsAndGenerateTempFile( xSubStream->getInputStream(), true );
433 if ( !bOk && !m_aNativeTempURL.isEmpty() )
435 KillFile_Impl( m_aNativeTempURL, m_xContext );
436 m_aNativeTempURL.clear();
440 if ( !bOk )
442 bOk = ReadContentsAndGenerateTempFile( xSubStream->getInputStream(), false );
444 if ( !bOk && !m_aNativeTempURL.isEmpty() )
446 KillFile_Impl( m_aNativeTempURL, m_xContext );
447 m_aNativeTempURL.clear();
452 else
454 // TODO/LATER: No native stream, needs a new solution
457 catch( uno::Exception& )
462 bool OwnView_Impl::Open()
464 bool bResult = false;
466 uno::Reference< frame::XModel > xExistingModel;
469 ::osl::MutexGuard aGuard( m_aMutex );
470 xExistingModel = m_xModel;
471 if ( m_bBusy )
472 return false;
474 m_bBusy = true;
477 if ( xExistingModel.is() )
479 try {
480 uno::Reference< frame::XController > xController = xExistingModel->getCurrentController();
481 if ( xController.is() )
483 uno::Reference< frame::XFrame > xFrame = xController->getFrame();
484 if ( xFrame.is() )
486 xFrame->activate();
487 uno::Reference<awt::XTopWindow> xTopWindow( xFrame->getContainerWindow(), uno::UNO_QUERY );
488 if(xTopWindow.is())
489 xTopWindow->toFront();
491 bResult = true;
495 catch( uno::Exception& )
499 else
501 bResult = CreateModel( m_bUseNative );
503 if ( !bResult && !m_bUseNative )
505 // the original storage can not be recognized
506 if ( m_aNativeTempURL.isEmpty() )
508 // create a temporary file for the native representation if there is no
509 CreateNative();
512 if ( !m_aNativeTempURL.isEmpty() )
514 bResult = CreateModel( true );
515 if ( bResult )
516 m_bUseNative = true;
521 m_bBusy = false;
523 return bResult;
527 void OwnView_Impl::Close()
529 uno::Reference< frame::XModel > xModel;
532 ::osl::MutexGuard aGuard( m_aMutex );
533 if ( !m_xModel.is() )
534 return;
535 xModel = m_xModel;
536 m_xModel.clear();
538 if ( m_bBusy )
539 return;
541 m_bBusy = true;
544 try {
545 uno::Reference< document::XEventBroadcaster > xBroadCaster( xModel, uno::UNO_QUERY );
546 if ( xBroadCaster.is() )
547 xBroadCaster->removeEventListener( uno::Reference< document::XEventListener >(
548 static_cast< ::cppu::OWeakObject* >( this ),
549 uno::UNO_QUERY ) );
551 uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
552 if ( xCloseable.is() )
554 xCloseable->removeCloseListener( uno::Reference< util::XCloseListener >(
555 static_cast< ::cppu::OWeakObject* >( this ),
556 uno::UNO_QUERY ) );
557 xCloseable->close( true );
560 catch( uno::Exception& )
563 m_bBusy = false;
567 void SAL_CALL OwnView_Impl::notifyEvent( const document::EventObject& aEvent )
570 uno::Reference< frame::XModel > xModel;
573 ::osl::MutexGuard aGuard( m_aMutex );
574 if ( aEvent.Source == m_xModel && aEvent.EventName == "OnSaveAsDone" )
576 // SaveAs operation took place, so just forget the model and deregister listeners
577 xModel = m_xModel;
578 m_xModel.clear();
582 if ( !xModel.is() )
583 return;
585 try {
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 ),
590 uno::UNO_QUERY ) );
592 uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
593 if ( xCloseable.is() )
594 xCloseable->removeCloseListener( uno::Reference< util::XCloseListener >(
595 static_cast< ::cppu::OWeakObject* >( this ),
596 uno::UNO_QUERY ) );
598 catch( uno::Exception& )
603 void SAL_CALL OwnView_Impl::queryClosing( const lang::EventObject&, sal_Bool )
608 void SAL_CALL OwnView_Impl::notifyClosing( const lang::EventObject& Source )
610 ::osl::MutexGuard aGuard( m_aMutex );
611 if ( Source.Source == m_xModel )
612 m_xModel.clear();
616 void SAL_CALL OwnView_Impl::disposing( const lang::EventObject& Source )
618 ::osl::MutexGuard aGuard( m_aMutex );
619 if ( Source.Source == m_xModel )
620 m_xModel.clear();
623 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */