Bump version to 6.4.7.2.M8
[LibreOffice.git] / embeddedobj / source / msole / ownview.cxx
blob7d938cfd15bad1cb74335fec1d236ef17d0e4bcd
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/XInputStream.hpp>
28 #include <com/sun/star/io/XOutputStream.hpp>
29 #include <com/sun/star/io/XSeekable.hpp>
30 #include <com/sun/star/task/XInteractionHandler.hpp>
31 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
32 #include <com/sun/star/util/XCloseable.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/document/XEventBroadcaster.hpp>
36 #include <com/sun/star/document/XEventListener.hpp>
37 #include <com/sun/star/document/XTypeDetection.hpp>
38 #include <com/sun/star/container/XNameAccess.hpp>
39 #include <cppuhelper/implbase.hxx>
40 #include <comphelper/processfactory.hxx>
41 #include <comphelper/storagehelper.hxx>
42 #include <comphelper/mimeconfighelper.hxx>
43 #include <tools/diagnose_ex.h>
45 #include "olepersist.hxx"
46 #include "ownview.hxx"
49 using namespace ::com::sun::star;
50 using namespace ::comphelper;
52 class DummyHandler_Impl : public ::cppu::WeakImplHelper< task::XInteractionHandler >
54 public:
55 DummyHandler_Impl() {}
57 virtual void SAL_CALL handle( const uno::Reference< task::XInteractionRequest >& xRequest ) override;
61 void SAL_CALL DummyHandler_Impl::handle( const uno::Reference< task::XInteractionRequest >& )
66 // Object viewer
69 OwnView_Impl::OwnView_Impl( const uno::Reference< lang::XMultiServiceFactory >& xFactory,
70 const uno::Reference< io::XInputStream >& xInputStream )
71 : m_xFactory( xFactory )
72 , m_bBusy( false )
73 , m_bUseNative( false )
75 if ( !xFactory.is() || !xInputStream.is() )
76 throw uno::RuntimeException();
78 m_aTempFileURL = GetNewFilledTempFile_Impl( xInputStream, m_xFactory );
82 OwnView_Impl::~OwnView_Impl()
84 try {
85 KillFile_Impl( m_aTempFileURL, m_xFactory );
86 } catch( uno::Exception& ) {}
88 try {
89 if ( !m_aNativeTempURL.isEmpty() )
90 KillFile_Impl( m_aNativeTempURL, m_xFactory );
91 } catch( uno::Exception& ) {}
95 bool OwnView_Impl::CreateModelFromURL( const OUString& aFileURL )
97 bool bResult = false;
99 if ( !aFileURL.isEmpty() )
101 try {
102 uno::Reference < frame::XDesktop2 > xDocumentLoader = frame::Desktop::create(comphelper::getComponentContext(m_xFactory));
104 uno::Sequence< beans::PropertyValue > aArgs( m_aFilterName.isEmpty() ? 4 : 5 );
106 aArgs[0].Name = "URL";
107 aArgs[0].Value <<= aFileURL;
109 aArgs[1].Name = "ReadOnly";
110 aArgs[1].Value <<= true;
112 aArgs[2].Name = "InteractionHandler";
113 aArgs[2].Value <<= uno::Reference< task::XInteractionHandler >(
114 static_cast< ::cppu::OWeakObject* >( new DummyHandler_Impl() ), uno::UNO_QUERY );
116 aArgs[3].Name = "DontEdit";
117 aArgs[3].Value <<= true;
119 if ( !m_aFilterName.isEmpty() )
121 aArgs[4].Name = "FilterName";
122 aArgs[4].Value <<= m_aFilterName;
125 uno::Reference< frame::XModel > xModel( xDocumentLoader->loadComponentFromURL(
126 aFileURL,
127 "_blank",
129 aArgs ),
130 uno::UNO_QUERY );
132 if ( xModel.is() )
134 uno::Reference< document::XEventBroadcaster > xBroadCaster( xModel, uno::UNO_QUERY );
135 if ( xBroadCaster.is() )
136 xBroadCaster->addEventListener( uno::Reference< document::XEventListener >(
137 static_cast< ::cppu::OWeakObject* >( this ),
138 uno::UNO_QUERY ) );
140 uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
141 if ( xCloseable.is() )
143 xCloseable->addCloseListener( uno::Reference< util::XCloseListener >(
144 static_cast< ::cppu::OWeakObject* >( this ),
145 uno::UNO_QUERY ) );
147 ::osl::MutexGuard aGuard( m_aMutex );
148 m_xModel = xModel;
149 bResult = true;
153 catch (uno::Exception const&)
155 TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OwnView_Impl::CreateModelFromURL:");
159 return bResult;
163 bool OwnView_Impl::CreateModel( bool bUseNative )
165 bool bResult = false;
167 try {
168 bResult = CreateModelFromURL( bUseNative ? m_aNativeTempURL : m_aTempFileURL );
170 catch( uno::Exception& )
174 return bResult;
178 OUString OwnView_Impl::GetFilterNameFromExtentionAndInStream(
179 const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory,
180 const OUString& aNameWithExtention,
181 const uno::Reference< io::XInputStream >& xInputStream )
183 if ( !xInputStream.is() )
184 throw uno::RuntimeException();
186 uno::Reference< document::XTypeDetection > xTypeDetection(
187 xFactory->createInstance("com.sun.star.document.TypeDetection"),
188 uno::UNO_QUERY_THROW );
190 OUString aTypeName;
192 if ( !aNameWithExtention.isEmpty() )
194 OUString aURLToAnalyze = "file:///" + aNameWithExtention;
195 aTypeName = xTypeDetection->queryTypeByURL( aURLToAnalyze );
198 uno::Sequence< beans::PropertyValue > aArgs( aTypeName.isEmpty() ? 2 : 3 );
199 aArgs[0].Name = "URL";
200 aArgs[0].Value <<= OUString( "private:stream" );
201 aArgs[1].Name = "InputStream";
202 aArgs[1].Value <<= xInputStream;
203 if ( !aTypeName.isEmpty() )
205 aArgs[2].Name = "TypeName";
206 aArgs[2].Value <<= aTypeName;
209 aTypeName = xTypeDetection->queryTypeByDescriptor( aArgs, true );
211 OUString aFilterName;
212 for ( sal_Int32 nInd = 0; nInd < aArgs.getLength(); nInd++ )
213 if ( aArgs[nInd].Name == "FilterName" )
214 aArgs[nInd].Value >>= aFilterName;
216 if ( aFilterName.isEmpty() && !aTypeName.isEmpty() )
218 // get the default filter name for the type
219 uno::Reference< container::XNameAccess > xNameAccess( xTypeDetection, uno::UNO_QUERY_THROW );
220 uno::Sequence< beans::PropertyValue > aTypes;
222 if ( xNameAccess.is() && ( xNameAccess->getByName( aTypeName ) >>= aTypes ) )
224 for ( sal_Int32 nInd = 0; nInd < aTypes.getLength(); nInd++ )
226 if ( aTypes[nInd].Name == "PreferredFilter" && ( aTypes[nInd].Value >>= aFilterName ) )
228 aTypes[nInd].Value >>= aFilterName;
229 break;
235 return aFilterName;
239 bool OwnView_Impl::ReadContentsAndGenerateTempFile( const uno::Reference< io::XInputStream >& xInStream,
240 bool bParseHeader )
242 uno::Reference< io::XSeekable > xSeekable( xInStream, uno::UNO_QUERY_THROW );
243 xSeekable->seek( 0 );
245 // create m_aNativeTempURL
246 OUString aNativeTempURL;
247 uno::Reference < beans::XPropertySet > xNativeTempFile(
248 io::TempFile::create(comphelper::getComponentContext(m_xFactory)),
249 uno::UNO_QUERY_THROW );
250 uno::Reference < io::XStream > xNativeTempStream( xNativeTempFile, uno::UNO_QUERY_THROW );
251 uno::Reference < io::XOutputStream > xNativeOutTemp = xNativeTempStream->getOutputStream();
252 uno::Reference < io::XInputStream > xNativeInTemp = xNativeTempStream->getInputStream();
253 if ( !xNativeOutTemp.is() || !xNativeInTemp.is() )
254 throw uno::RuntimeException();
256 try {
257 xNativeTempFile->setPropertyValue("RemoveFile", uno::makeAny( false ) );
258 uno::Any aUrl = xNativeTempFile->getPropertyValue("Uri");
259 aUrl >>= aNativeTempURL;
261 catch ( uno::Exception& )
265 bool bFailed = false;
266 OUString aFileSuffix;
268 if ( bParseHeader )
270 uno::Sequence< sal_Int8 > aReadSeq( 4 );
271 // read the complete size of the Object Package
272 if ( xInStream->readBytes( aReadSeq, 4 ) != 4 )
273 return false;
274 // read the first header ( have no idea what does this header mean )
275 if ( xInStream->readBytes( aReadSeq, 2 ) != 2 || aReadSeq[0] != 2 || aReadSeq[1] != 0 )
276 return false;
278 // read file name
279 // only extension is interesting so only subset of symbols is accepted
282 if ( xInStream->readBytes( aReadSeq, 1 ) != 1 )
283 return false;
285 if (
286 (aReadSeq[0] >= '0' && aReadSeq[0] <= '9') ||
287 (aReadSeq[0] >= 'a' && aReadSeq[0] <= 'z') ||
288 (aReadSeq[0] >= 'A' && aReadSeq[0] <= 'Z') ||
289 aReadSeq[0] == '.'
292 aFileSuffix += OUStringChar( sal_Unicode(aReadSeq[0]) );
295 } while( aReadSeq[0] );
297 // skip url
300 if ( xInStream->readBytes( aReadSeq, 1 ) != 1 )
301 return false;
302 } while( aReadSeq[0] );
304 // check the next header
305 if ( xInStream->readBytes( aReadSeq, 4 ) != 4
306 || aReadSeq[0] || aReadSeq[1] || aReadSeq[2] != 3 || aReadSeq[3] )
307 return false;
309 // get the size of the next entry
310 if ( xInStream->readBytes( aReadSeq, 4 ) != 4 )
311 return false;
313 sal_uInt32 nUrlSize = static_cast<sal_uInt8>(aReadSeq[0])
314 + static_cast<sal_uInt8>(aReadSeq[1]) * 0x100
315 + static_cast<sal_uInt8>(aReadSeq[2]) * 0x10000
316 + static_cast<sal_uInt8>(aReadSeq[3]) * 0x1000000;
317 sal_Int64 nTargetPos = xSeekable->getPosition() + nUrlSize;
319 xSeekable->seek( nTargetPos );
321 // get the size of stored data
322 if ( xInStream->readBytes( aReadSeq, 4 ) != 4 )
323 return false;
325 sal_uInt32 nDataSize = static_cast<sal_uInt8>(aReadSeq[0])
326 + static_cast<sal_uInt8>(aReadSeq[1]) * 0x100
327 + static_cast<sal_uInt8>(aReadSeq[2]) * 0x10000
328 + static_cast<sal_uInt8>(aReadSeq[3]) * 0x1000000;
330 aReadSeq.realloc( 32000 );
331 sal_uInt32 nRead = 0;
332 while ( nRead < nDataSize )
334 sal_uInt32 nToRead = std::min<sal_uInt32>( nDataSize - nRead, 32000 );
335 sal_uInt32 nLocalRead = xInStream->readBytes( aReadSeq, nToRead );
338 if ( !nLocalRead )
340 bFailed = true;
341 break;
343 else if ( nLocalRead == 32000 )
344 xNativeOutTemp->writeBytes( aReadSeq );
345 else
347 uno::Sequence< sal_Int8 > aToWrite( aReadSeq );
348 aToWrite.realloc( nLocalRead );
349 xNativeOutTemp->writeBytes( aToWrite );
352 nRead += nLocalRead;
355 else
357 uno::Sequence< sal_Int8 > aData( 8 );
358 if ( xInStream->readBytes( aData, 8 ) == 8
359 && aData[0] == -1 && aData[1] == -1 && aData[2] == -1 && aData[3] == -1
360 && ( aData[4] == 2 || aData[4] == 3 ) && aData[5] == 0 && aData[6] == 0 && aData[7] == 0 )
362 // the header has to be removed
363 xSeekable->seek( 40 );
365 else
367 // the usual Ole10Native format
368 xSeekable->seek( 4 );
371 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xNativeOutTemp );
374 xNativeOutTemp->closeOutput();
376 // The temporary native file is created, now the filter must be detected
377 if ( !bFailed )
379 m_aFilterName = GetFilterNameFromExtentionAndInStream( m_xFactory, aFileSuffix, xNativeInTemp );
380 m_aNativeTempURL = aNativeTempURL;
383 return !bFailed;
387 void OwnView_Impl::CreateNative()
389 if ( !m_aNativeTempURL.isEmpty() )
390 return;
394 uno::Reference < ucb::XSimpleFileAccess3 > xAccess(
395 ucb::SimpleFileAccess::create( comphelper::getComponentContext(m_xFactory) ) );
397 uno::Reference< io::XInputStream > xInStream = xAccess->openFileRead( m_aTempFileURL );
398 if ( !xInStream.is() )
399 throw uno::RuntimeException();
401 uno::Sequence< uno::Any > aArgs( 1 );
402 aArgs[0] <<= xInStream;
403 uno::Reference< container::XNameAccess > xNameAccess(
404 m_xFactory->createInstanceWithArguments(
405 "com.sun.star.embed.OLESimpleStorage",
406 aArgs ),
407 uno::UNO_QUERY_THROW );
409 OUString aSubStreamName = "\1Ole10Native";
410 uno::Reference< embed::XClassifiedObject > xStor( xNameAccess, uno::UNO_QUERY_THROW );
411 uno::Sequence< sal_Int8 > aStorClassID = xStor->getClassID();
413 if ( xNameAccess->hasByName( aSubStreamName ) )
415 sal_uInt8 const aClassID[] =
416 { 0x00, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
417 uno::Sequence< sal_Int8 > aPackageClassID( reinterpret_cast<sal_Int8 const *>(aClassID), 16 );
419 uno::Reference< io::XStream > xSubStream;
420 xNameAccess->getByName( aSubStreamName ) >>= xSubStream;
421 if ( xSubStream.is() )
423 bool bOk = false;
425 if ( MimeConfigurationHelper::ClassIDsEqual( aPackageClassID, aStorClassID ) )
427 // the storage represents Object Package
429 bOk = ReadContentsAndGenerateTempFile( xSubStream->getInputStream(), true );
431 if ( !bOk && !m_aNativeTempURL.isEmpty() )
433 KillFile_Impl( m_aNativeTempURL, m_xFactory );
434 m_aNativeTempURL.clear();
438 if ( !bOk )
440 bOk = ReadContentsAndGenerateTempFile( xSubStream->getInputStream(), false );
442 if ( !bOk && !m_aNativeTempURL.isEmpty() )
444 KillFile_Impl( m_aNativeTempURL, m_xFactory );
445 m_aNativeTempURL.clear();
450 else
452 // TODO/LATER: No native stream, needs a new solution
455 catch( uno::Exception& )
460 bool OwnView_Impl::Open()
462 bool bResult = false;
464 uno::Reference< frame::XModel > xExistingModel;
467 ::osl::MutexGuard aGuard( m_aMutex );
468 xExistingModel = m_xModel;
469 if ( m_bBusy )
470 return false;
472 m_bBusy = true;
475 if ( xExistingModel.is() )
477 try {
478 uno::Reference< frame::XController > xController = xExistingModel->getCurrentController();
479 if ( xController.is() )
481 uno::Reference< frame::XFrame > xFrame = xController->getFrame();
482 if ( xFrame.is() )
484 xFrame->activate();
485 uno::Reference<awt::XTopWindow> xTopWindow( xFrame->getContainerWindow(), uno::UNO_QUERY );
486 if(xTopWindow.is())
487 xTopWindow->toFront();
489 bResult = true;
493 catch( uno::Exception& )
497 else
499 bResult = CreateModel( m_bUseNative );
501 if ( !bResult && !m_bUseNative )
503 // the original storage can not be recognized
504 if ( m_aNativeTempURL.isEmpty() )
506 // create a temporary file for the native representation if there is no
507 CreateNative();
510 if ( !m_aNativeTempURL.isEmpty() )
512 bResult = CreateModel( true );
513 if ( bResult )
514 m_bUseNative = true;
519 m_bBusy = false;
521 return bResult;
525 void OwnView_Impl::Close()
527 uno::Reference< frame::XModel > xModel;
530 ::osl::MutexGuard aGuard( m_aMutex );
531 if ( !m_xModel.is() )
532 return;
533 xModel = m_xModel;
534 m_xModel.clear();
536 if ( m_bBusy )
537 return;
539 m_bBusy = true;
542 try {
543 uno::Reference< document::XEventBroadcaster > xBroadCaster( xModel, uno::UNO_QUERY );
544 if ( xBroadCaster.is() )
545 xBroadCaster->removeEventListener( uno::Reference< document::XEventListener >(
546 static_cast< ::cppu::OWeakObject* >( this ),
547 uno::UNO_QUERY ) );
549 uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
550 if ( xCloseable.is() )
552 xCloseable->removeCloseListener( uno::Reference< util::XCloseListener >(
553 static_cast< ::cppu::OWeakObject* >( this ),
554 uno::UNO_QUERY ) );
555 xCloseable->close( true );
558 catch( uno::Exception& )
561 m_bBusy = false;
565 void SAL_CALL OwnView_Impl::notifyEvent( const document::EventObject& aEvent )
568 uno::Reference< frame::XModel > xModel;
571 ::osl::MutexGuard aGuard( m_aMutex );
572 if ( aEvent.Source == m_xModel && aEvent.EventName == "OnSaveAsDone" )
574 // SaveAs operation took place, so just forget the model and deregister listeners
575 xModel = m_xModel;
576 m_xModel.clear();
580 if ( xModel.is() )
582 try {
583 uno::Reference< document::XEventBroadcaster > xBroadCaster( xModel, uno::UNO_QUERY );
584 if ( xBroadCaster.is() )
585 xBroadCaster->removeEventListener( uno::Reference< document::XEventListener >(
586 static_cast< ::cppu::OWeakObject* >( this ),
587 uno::UNO_QUERY ) );
589 uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
590 if ( xCloseable.is() )
591 xCloseable->removeCloseListener( uno::Reference< util::XCloseListener >(
592 static_cast< ::cppu::OWeakObject* >( this ),
593 uno::UNO_QUERY ) );
595 catch( uno::Exception& )
601 void SAL_CALL OwnView_Impl::queryClosing( const lang::EventObject&, sal_Bool )
606 void SAL_CALL OwnView_Impl::notifyClosing( const lang::EventObject& Source )
608 ::osl::MutexGuard aGuard( m_aMutex );
609 if ( Source.Source == m_xModel )
610 m_xModel.clear();
614 void SAL_CALL OwnView_Impl::disposing( const lang::EventObject& Source )
616 ::osl::MutexGuard aGuard( m_aMutex );
617 if ( Source.Source == m_xModel )
618 m_xModel.clear();
621 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */