summaryrefslogtreecommitdiffstats
path: root/embeddedobj/source/msole
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--embeddedobj/source/msole/advisesink.cxx124
-rw-r--r--embeddedobj/source/msole/advisesink.hxx51
-rw-r--r--embeddedobj/source/msole/closepreventer.cxx42
-rw-r--r--embeddedobj/source/msole/emboleobj.component28
-rw-r--r--embeddedobj/source/msole/emboleobj.windows.component34
-rw-r--r--embeddedobj/source/msole/graphconvert.cxx132
-rw-r--r--embeddedobj/source/msole/graphconvert.hxx33
-rw-r--r--embeddedobj/source/msole/mtnotification.hxx48
-rw-r--r--embeddedobj/source/msole/olecomponent.cxx1672
-rw-r--r--embeddedobj/source/msole/olecomponent.hxx161
-rw-r--r--embeddedobj/source/msole/oleembed.cxx1179
-rw-r--r--embeddedobj/source/msole/olemisc.cxx700
-rw-r--r--embeddedobj/source/msole/olepersist.cxx2019
-rw-r--r--embeddedobj/source/msole/olepersist.hxx42
-rw-r--r--embeddedobj/source/msole/olevisual.cxx432
-rw-r--r--embeddedobj/source/msole/olewrapclient.cxx148
-rw-r--r--embeddedobj/source/msole/olewrapclient.hxx51
-rw-r--r--embeddedobj/source/msole/ownview.cxx609
-rw-r--r--embeddedobj/source/msole/ownview.hxx83
-rw-r--r--embeddedobj/source/msole/platform.h31
-rw-r--r--embeddedobj/source/msole/xdialogcreator.cxx356
-rw-r--r--embeddedobj/source/msole/xdialogcreator.hxx59
-rw-r--r--embeddedobj/source/msole/xolefactory.cxx251
-rw-r--r--embeddedobj/source/msole/xolefactory.hxx62
24 files changed, 8347 insertions, 0 deletions
diff --git a/embeddedobj/source/msole/advisesink.cxx b/embeddedobj/source/msole/advisesink.cxx
new file mode 100644
index 000000000..5601c8d9e
--- /dev/null
+++ b/embeddedobj/source/msole/advisesink.cxx
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+#include "advisesink.hxx"
+#include "olecomponent.hxx"
+
+#include <rtl/ref.hxx>
+
+OleWrapperAdviseSink::OleWrapperAdviseSink( OleComponent* pOleComp )
+: m_nRefCount( 0 )
+, m_pOleComp( pOleComp )
+{
+ OSL_ENSURE( m_pOleComp, "No ole component is provided!" );
+}
+
+OleWrapperAdviseSink::~OleWrapperAdviseSink()
+{
+}
+
+STDMETHODIMP OleWrapperAdviseSink::QueryInterface( REFIID riid , void** ppv )
+{
+ *ppv=nullptr;
+
+ if ( riid == IID_IUnknown )
+ *ppv = static_cast<IUnknown*>(this);
+
+ if ( riid == IID_IAdviseSink )
+ *ppv = static_cast<IAdviseSink*>(this);
+
+ if ( *ppv != nullptr )
+ {
+ static_cast<IUnknown*>(*ppv)->AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) OleWrapperAdviseSink::AddRef()
+{
+ return osl_atomic_increment( &m_nRefCount);
+}
+
+STDMETHODIMP_(ULONG) OleWrapperAdviseSink::Release()
+{
+ ULONG nReturn = --m_nRefCount;
+ if ( m_nRefCount == 0 )
+ delete this;
+
+ return nReturn;
+}
+
+void OleWrapperAdviseSink::disconnectOleComponent()
+{
+ // must not be called from the descructor of OleComponent!!!
+ osl::MutexGuard aGuard( m_aMutex );
+ m_pOleComp = nullptr;
+}
+
+STDMETHODIMP_(void) OleWrapperAdviseSink::OnDataChange(FORMATETC *, STGMEDIUM *)
+{
+ // Unused for now ( no registration for IDataObject events )
+}
+
+STDMETHODIMP_(void) OleWrapperAdviseSink::OnViewChange(DWORD dwAspect, LONG)
+{
+ ::rtl::Reference< OleComponent > xLockComponent;
+
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ if ( m_pOleComp )
+ xLockComponent = m_pOleComp;
+ }
+
+ if ( xLockComponent.is() )
+ xLockComponent->OnViewChange_Impl( dwAspect );
+}
+
+STDMETHODIMP_(void) OleWrapperAdviseSink::OnRename(IMoniker *)
+{
+ // handled by default inprocess handler
+}
+
+STDMETHODIMP_(void) OleWrapperAdviseSink::OnSave()
+{
+ // TODO: ???
+ // The object already knows about document saving, since it controls it as ClientSide
+ // other interested listeners must be registered for the object
+}
+
+STDMETHODIMP_(void) OleWrapperAdviseSink::OnClose()
+{
+ ::rtl::Reference< OleComponent > xLockComponent;
+
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ if ( m_pOleComp )
+ xLockComponent = m_pOleComp;
+ }
+
+ if ( xLockComponent.is() )
+ xLockComponent->OnClose_Impl();
+
+ // TODO: sometimes it can be necessary to simulate OnShowWindow( False ) here
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/advisesink.hxx b/embeddedobj/source/msole/advisesink.hxx
new file mode 100644
index 000000000..cd1bc3892
--- /dev/null
+++ b/embeddedobj/source/msole/advisesink.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <osl/interlck.h>
+#include <osl/mutex.hxx>
+#include "platform.h"
+
+class OleComponent;
+class OleWrapperAdviseSink : public IAdviseSink
+{
+protected:
+ osl::Mutex m_aMutex;
+ oslInterlockedCount m_nRefCount;
+ OleComponent* m_pOleComp;
+
+public:
+ OleWrapperAdviseSink(OleComponent* pOleComp);
+ OleWrapperAdviseSink();
+ virtual ~OleWrapperAdviseSink();
+
+ void disconnectOleComponent();
+ STDMETHODIMP QueryInterface(REFIID, void**) override;
+ STDMETHODIMP_(ULONG) AddRef() override;
+ STDMETHODIMP_(ULONG) Release() override;
+
+ STDMETHODIMP_(void) OnDataChange(FORMATETC*, STGMEDIUM*) override;
+ STDMETHODIMP_(void) OnViewChange(DWORD, LONG) override;
+ STDMETHODIMP_(void) OnRename(IMoniker*) override;
+ STDMETHODIMP_(void) OnSave() override;
+ STDMETHODIMP_(void) OnClose() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/closepreventer.cxx b/embeddedobj/source/msole/closepreventer.cxx
new file mode 100644
index 000000000..466975898
--- /dev/null
+++ b/embeddedobj/source/msole/closepreventer.cxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <closepreventer.hxx>
+
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <osl/diagnose.h>
+
+void SAL_CALL OClosePreventer::queryClosing(const css::lang::EventObject&, sal_Bool)
+{
+ throw css::util::CloseVetoException();
+}
+
+void SAL_CALL OClosePreventer::notifyClosing(const css::lang::EventObject&)
+{
+ // just a disaster
+ OSL_FAIL("The object can not be prevented from closing!");
+}
+
+void SAL_CALL OClosePreventer::disposing(const css::lang::EventObject&)
+{
+ // just a disaster
+ OSL_FAIL("The object can not be prevented from closing!");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/emboleobj.component b/embeddedobj/source/msole/emboleobj.component
new file mode 100644
index 000000000..ac09d3a6d
--- /dev/null
+++ b/embeddedobj/source/msole/emboleobj.component
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.embed.OLEEmbeddedObjectFactory"
+ constructor="embeddedobj_OleEmbeddedObjectFactory_get_implementation"
+ single-instance="true">
+ <service name="com.sun.star.comp.embed.OLEEmbeddedObjectFactory"/>
+ <service name="com.sun.star.embed.OLEEmbeddedObjectFactory"/>
+ </implementation>
+</component>
diff --git a/embeddedobj/source/msole/emboleobj.windows.component b/embeddedobj/source/msole/emboleobj.windows.component
new file mode 100644
index 000000000..89b644fc7
--- /dev/null
+++ b/embeddedobj/source/msole/emboleobj.windows.component
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.embed.MSOLEObjectSystemCreator"
+ constructor="embeddedobj_MSOLEDialogObjectCreator_get_implementation"
+ single-instance="true">
+ <service name="com.sun.star.comp.embed.MSOLEObjectSystemCreator"/>
+ <service name="com.sun.star.embed.MSOLEObjectSystemCreator"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.embed.OLEEmbeddedObjectFactory"
+ constructor="embeddedobj_OleEmbeddedObjectFactory_get_implementation"
+ single-instance="true">
+ <service name="com.sun.star.comp.embed.OLEEmbeddedObjectFactory"/>
+ <service name="com.sun.star.embed.OLEEmbeddedObjectFactory"/>
+ </implementation>
+</component>
diff --git a/embeddedobj/source/msole/graphconvert.cxx b/embeddedobj/source/msole/graphconvert.cxx
new file mode 100644
index 000000000..f853f03dc
--- /dev/null
+++ b/embeddedobj/source/msole/graphconvert.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/graphic/XGraphicProvider.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <unotools/streamwrap.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/seqstream.hxx>
+#include <tools/stream.hxx>
+#include <vcl/graphicfilter.hxx>
+
+#include "graphconvert.hxx"
+#include "mtnotification.hxx"
+#include <oleembobj.hxx>
+
+
+using namespace ::com::sun::star;
+
+
+bool ConvertBufferToFormat( void* pBuf,
+ sal_uInt32 nBufSize,
+ const OUString& aMimeType,
+ uno::Any& aResult )
+{
+ // produces sequence with data in requested format and returns it in aResult
+ if ( pBuf )
+ {
+ // First, in case the buffer is already in the requested format, then avoid a conversion.
+ SvMemoryStream aMemoryStream(pBuf, nBufSize, StreamMode::READ);
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ sal_uInt16 nRetFormat = 0;
+ if (rFilter.CanImportGraphic(u"", aMemoryStream, GRFILTER_FORMAT_DONTKNOW, &nRetFormat) == ERRCODE_NONE &&
+ rFilter.GetImportFormatMediaType(nRetFormat) == aMimeType)
+ {
+ aResult <<= uno::Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemoryStream.GetData() ), aMemoryStream.TellEnd() );
+ return true;
+ }
+
+ uno::Sequence < sal_Int8 > aData( static_cast<sal_Int8*>(pBuf), nBufSize );
+ uno::Reference < io::XInputStream > xIn = new comphelper::SequenceInputStream( aData );
+ try
+ {
+ uno::Reference < graphic::XGraphicProvider > xGraphicProvider( graphic::GraphicProvider::create(comphelper::getProcessComponentContext()));
+ uno::Sequence< beans::PropertyValue > aMediaProperties{ comphelper::makePropertyValue(
+ "InputStream", xIn) };
+ uno::Reference< graphic::XGraphic > xGraphic( xGraphicProvider->queryGraphic( aMediaProperties ) );
+ if( xGraphic.is() )
+ {
+ SvMemoryStream aNewStream( 65535, 65535 );
+ uno::Reference < io::XStream > xOut = new utl::OStreamWrapper( aNewStream );
+ uno::Sequence< beans::PropertyValue > aOutMediaProperties{
+ comphelper::makePropertyValue("OutputStream", xOut),
+ comphelper::makePropertyValue("MimeType", aMimeType)
+ };
+
+ xGraphicProvider->storeGraphic( xGraphic, aOutMediaProperties );
+ aResult <<= uno::Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aNewStream.GetData() ), aNewStream.TellEnd() );
+ return true;
+ }
+ }
+ catch (const uno::Exception&)
+ {}
+ }
+
+ return false;
+}
+
+
+// MainThreadNotificationRequest
+
+MainThreadNotificationRequest::MainThreadNotificationRequest( const ::rtl::Reference< OleEmbeddedObject >& xObj, sal_uInt16 nNotificationType, sal_uInt32 nAspect )
+: m_pObject( xObj.get() )
+, m_xObject( static_cast< embed::XEmbeddedObject* >( xObj.get() ) )
+, m_nNotificationType( nNotificationType )
+, m_nAspect( nAspect )
+{}
+
+void SAL_CALL MainThreadNotificationRequest::notify (const uno::Any& )
+{
+ if ( m_pObject )
+ {
+ try
+ {
+ uno::Reference< uno::XInterface > xLock = m_xObject.get();
+ if ( xLock.is() )
+ {
+ // this is the main thread, the solar mutex must be locked
+ if ( m_nNotificationType == OLECOMP_ONCLOSE )
+ m_pObject->OnClosed_Impl();
+ else if ( m_nAspect == embed::Aspects::MSOLE_CONTENT )
+ m_pObject->OnViewChanged_Impl();
+ else if ( m_nAspect == embed::Aspects::MSOLE_ICON )
+ OleEmbeddedObject::OnIconChanged_Impl();
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ // ignore all the errors
+ }
+ }
+}
+
+MainThreadNotificationRequest::~MainThreadNotificationRequest()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/graphconvert.hxx b/embeddedobj/source/msole/graphconvert.hxx
new file mode 100644
index 000000000..cc5066de5
--- /dev/null
+++ b/embeddedobj/source/msole/graphconvert.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+namespace com::sun::star::uno { class Any; }
+
+bool ConvertBufferToFormat(
+ void * pBuf, sal_uInt32 nBufSize, OUString const & aFormatShortName,
+ css::uno::Any & aResult);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/mtnotification.hxx b/embeddedobj/source/msole/mtnotification.hxx
new file mode 100644
index 000000000..09888d04a
--- /dev/null
+++ b/embeddedobj/source/msole/mtnotification.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/awt/XCallback.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <rtl/ref.hxx>
+
+class OleEmbeddedObject;
+
+#define OLECOMP_ONVIEWCHANGE 1
+#define OLECOMP_ONCLOSE 2
+
+class MainThreadNotificationRequest : public cppu::WeakImplHelper< css::awt::XCallback >
+{
+ OleEmbeddedObject* m_pObject;
+ css::uno::WeakReference< css::embed::XEmbeddedObject > m_xObject;
+
+ sal_uInt16 m_nNotificationType;
+ sal_uInt32 m_nAspect;
+
+public:
+ virtual void SAL_CALL notify (const css::uno::Any& rUserData) override;
+ MainThreadNotificationRequest( const ::rtl::Reference< OleEmbeddedObject >& xObj, sal_uInt16 nNotificationType, sal_uInt32 nAspect = 0 );
+ ~MainThreadNotificationRequest() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/olecomponent.cxx b/embeddedobj/source/msole/olecomponent.cxx
new file mode 100644
index 000000000..f31113023
--- /dev/null
+++ b/embeddedobj/source/msole/olecomponent.cxx
@@ -0,0 +1,1672 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/embed/WrongStateException.hpp>
+#include <com/sun/star/embed/UnreachableStateException.hpp>
+#include <com/sun/star/ucb/XSimpleFileAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/io/TempFile.hpp>
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/awt/XRequestCallback.hpp>
+
+#include "platform.h"
+#include <comphelper/multicontainer2.hxx>
+#include <comphelper/mimeconfighelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/windowserrorstring.hxx>
+#include <osl/file.hxx>
+#include <rtl/ref.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <systools/win32/comtools.hxx>
+#include <vcl/threadex.hxx>
+
+#include "graphconvert.hxx"
+#include "olecomponent.hxx"
+#include "olepersist.hxx"
+#include "olewrapclient.hxx"
+#include "advisesink.hxx"
+#include <oleembobj.hxx>
+#include "mtnotification.hxx"
+#include <memory>
+#include <string>
+
+using namespace ::com::sun::star;
+using namespace ::comphelper;
+#define MAX_ENUM_ELE 20
+#define FORMATS_NUM 3
+
+typedef std::vector< FORMATETC* > FormatEtcList;
+
+FORMATETC const pFormatTemplates[FORMATS_NUM] = {
+ { CF_ENHMETAFILE, nullptr, 0, -1, TYMED_ENHMF },
+ { CF_METAFILEPICT, nullptr, 0, -1, TYMED_MFPICT },
+ { CF_BITMAP, nullptr, 0, -1, TYMED_GDI } };
+
+
+struct OleComponentNative_Impl {
+ sal::systools::COMReference< IUnknown > m_pObj;
+ sal::systools::COMReference< IOleObject > m_pOleObject;
+ sal::systools::COMReference< IViewObject2 > m_pViewObject2;
+ sal::systools::COMReference< IStorage > m_pIStorage;
+ FormatEtcList m_aFormatsList;
+ uno::Sequence< datatransfer::DataFlavor > m_aSupportedGraphFormats;
+
+ OleComponentNative_Impl()
+ {
+ // TODO: Extend format list
+ m_aSupportedGraphFormats = {
+
+ datatransfer::DataFlavor(
+ "application/x-openoffice-emf;windows_formatname=\"Image EMF\"",
+ "Windows Enhanced Metafile",
+ cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ),
+
+ datatransfer::DataFlavor(
+ "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"",
+ "Windows Metafile",
+ cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ),
+
+ datatransfer::DataFlavor(
+ "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"",
+ "Bitmap",
+ cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ),
+
+ datatransfer::DataFlavor(
+ "image/png",
+ "PNG",
+ cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ),
+
+ datatransfer::DataFlavor(
+ "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"",
+ "GDIMetafile",
+ cppu::UnoType<uno::Sequence< sal_Int8 >>::get() )
+ };
+ }
+
+ bool ConvertDataForFlavor( const STGMEDIUM& aMedium,
+ const datatransfer::DataFlavor& aFlavor,
+ uno::Any& aResult );
+
+ bool GraphicalFlavor( const datatransfer::DataFlavor& aFlavor );
+
+ uno::Sequence< datatransfer::DataFlavor > GetFlavorsForAspects( sal_uInt32 nSupportedAspects );
+};
+
+
+static DWORD GetAspectFromFlavor( const datatransfer::DataFlavor& aFlavor )
+{
+ if ( aFlavor.MimeType.indexOf( ";Aspect=THUMBNAIL" ) != -1 )
+ return DVASPECT_THUMBNAIL;
+ else if ( aFlavor.MimeType.indexOf( ";Aspect=ICON" ) != -1 )
+ return DVASPECT_ICON;
+ else if ( aFlavor.MimeType.indexOf( ";Aspect=DOCPRINT" ) != -1 )
+ return DVASPECT_DOCPRINT;
+ else
+ return DVASPECT_CONTENT;
+}
+
+
+static OUString GetFlavorSuffixFromAspect( DWORD nAsp )
+{
+ OUString aResult;
+
+ if ( nAsp == DVASPECT_THUMBNAIL )
+ aResult = ";Aspect=THUMBNAIL";
+ else if ( nAsp == DVASPECT_ICON )
+ aResult = ";Aspect=ICON";
+ else if ( nAsp == DVASPECT_DOCPRINT )
+ aResult = ";Aspect=DOCPRINT";
+
+ // no suffix for DVASPECT_CONTENT
+
+ return aResult;
+}
+
+
+static HRESULT OpenIStorageFromURL_Impl( const OUString& aURL, IStorage** ppIStorage )
+{
+ OSL_ENSURE( ppIStorage, "The pointer must not be empty!" );
+
+ OUString aFilePath;
+ if ( !ppIStorage || ::osl::FileBase::getSystemPathFromFileURL( aURL, aFilePath ) != ::osl::FileBase::E_None )
+ throw uno::RuntimeException(); // TODO: something dangerous happened
+
+ return StgOpenStorage( o3tl::toW(aFilePath.getStr()),
+ nullptr,
+ STGM_READWRITE | STGM_TRANSACTED, // | STGM_DELETEONRELEASE,
+ nullptr,
+ 0,
+ ppIStorage );
+}
+
+
+bool OleComponentNative_Impl::ConvertDataForFlavor( const STGMEDIUM& aMedium,
+ const datatransfer::DataFlavor& aFlavor,
+ uno::Any& aResult )
+{
+ bool bAnyIsReady = false;
+
+ // try to convert data from Medium format to specified Flavor format
+ if ( aFlavor.DataType == cppu::UnoType<uno::Sequence< sal_Int8 >>::get() )
+ {
+ // first the GDI-metafile must be generated
+
+ std::unique_ptr<sal_Int8[]> pBuf;
+ sal_uInt32 nBufSize = 0;
+ OUString aFormat;
+
+ if ( aMedium.tymed == TYMED_MFPICT ) // Win Metafile
+ {
+ aFormat = "image/x-wmf";
+ METAFILEPICT* pMF = static_cast<METAFILEPICT*>(GlobalLock( aMedium.hMetaFilePict ));
+ if ( pMF )
+ {
+ nBufSize = GetMetaFileBitsEx( pMF->hMF, 0, nullptr ) + 22;
+ pBuf.reset(new sal_Int8[nBufSize]);
+
+
+ // TODO/LATER: the unit size must be calculated correctly
+ *reinterpret_cast<long*>( pBuf.get() ) = 0x9ac6cdd7L;
+ *reinterpret_cast<short*>( pBuf.get()+6 ) = SHORT(0);
+ *reinterpret_cast<short*>( pBuf.get()+8 ) = SHORT(0);
+ *reinterpret_cast<short*>( pBuf.get()+10 ) = static_cast<SHORT>(pMF->xExt);
+ *reinterpret_cast<short*>( pBuf.get()+12 ) = static_cast<SHORT>(pMF->yExt);
+ *reinterpret_cast<short*>( pBuf.get()+14 ) = USHORT(2540);
+
+
+ if ( nBufSize && nBufSize == GetMetaFileBitsEx( pMF->hMF, nBufSize - 22, pBuf.get() + 22 ) )
+ {
+ if ( aFlavor.MimeType.matchAsciiL( "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"", 57 ) )
+ {
+ aResult <<= uno::Sequence< sal_Int8 >( pBuf.get(), nBufSize );
+ bAnyIsReady = true;
+ }
+ }
+
+ GlobalUnlock( aMedium.hMetaFilePict );
+ }
+ }
+ else if ( aMedium.tymed == TYMED_ENHMF ) // Enh Metafile
+ {
+ aFormat = "image/x-emf";
+ nBufSize = GetEnhMetaFileBits( aMedium.hEnhMetaFile, 0, nullptr );
+ pBuf.reset(new sal_Int8[nBufSize]);
+ if ( nBufSize && nBufSize == GetEnhMetaFileBits( aMedium.hEnhMetaFile, nBufSize, reinterpret_cast<LPBYTE>(pBuf.get()) ) )
+ {
+ if ( aFlavor.MimeType.matchAsciiL( "application/x-openoffice-emf;windows_formatname=\"Image EMF\"", 57 ) )
+ {
+ aResult <<= uno::Sequence< sal_Int8 >( pBuf.get(), nBufSize );
+ bAnyIsReady = true;
+ }
+ }
+ }
+ else if ( aMedium.tymed == TYMED_GDI ) // Bitmap
+ {
+ aFormat = "image/x-MS-bmp";
+
+ // Find out size of buffer: deprecated GetBitmapBits does not have a mode to return
+ // required buffer size
+ BITMAP aBmp;
+ GetObjectW(aMedium.hBitmap, sizeof(aBmp), &aBmp);
+ nBufSize = aBmp.bmWidthBytes * aBmp.bmHeight;
+
+ pBuf.reset(new sal_Int8[nBufSize]);
+ if ( nBufSize && nBufSize == sal::static_int_cast< ULONG >( GetBitmapBits( aMedium.hBitmap, nBufSize, pBuf.get() ) ) )
+ {
+ if ( aFlavor.MimeType.matchAsciiL( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"", 54 ) )
+ {
+ aResult <<= uno::Sequence< sal_Int8 >( pBuf.get(), nBufSize );
+ bAnyIsReady = true;
+ }
+ }
+ }
+
+ if ( pBuf && !bAnyIsReady )
+ {
+ for ( auto const & supportedFormat : std::as_const(m_aSupportedGraphFormats) )
+ if ( aFlavor.MimeType.match( supportedFormat.MimeType )
+ && aFlavor.DataType == supportedFormat.DataType
+ && aFlavor.DataType == cppu::UnoType<uno::Sequence< sal_Int8 >>::get() )
+ {
+ bAnyIsReady = ConvertBufferToFormat( pBuf.get(), nBufSize, aFormat, aResult );
+ break;
+ }
+ }
+ }
+
+ return bAnyIsReady;
+}
+
+
+bool OleComponentNative_Impl::GraphicalFlavor( const datatransfer::DataFlavor& aFlavor )
+{
+ // Actually all the required graphical formats must be supported
+ for ( auto const & supportedFormat : std::as_const(m_aSupportedGraphFormats) )
+ if ( aFlavor.MimeType.match( supportedFormat.MimeType )
+ && aFlavor.DataType == supportedFormat.DataType )
+ return true;
+
+ return false;
+}
+
+
+static bool GetClassIDFromSequence_Impl( uno::Sequence< sal_Int8 > const & aSeq, CLSID& aResult )
+{
+ if ( aSeq.getLength() == 16 )
+ {
+ aResult.Data1 = ( ( ( ( ( static_cast<sal_uInt8>(aSeq[0]) << 8 ) + static_cast<sal_uInt8>(aSeq[1]) ) << 8 ) + static_cast<sal_uInt8>(aSeq[2]) ) << 8 ) + static_cast<sal_uInt8>(aSeq[3]);
+ aResult.Data2 = ( static_cast<sal_uInt8>(aSeq[4]) << 8 ) + static_cast<sal_uInt8>(aSeq[5]);
+ aResult.Data3 = ( static_cast<sal_uInt8>(aSeq[6]) << 8 ) + static_cast<sal_uInt8>(aSeq[7]);
+ for( int nInd = 0; nInd < 8; nInd++ )
+ aResult.Data4[nInd] = static_cast<sal_uInt8>(aSeq[nInd+8]);
+
+ return true;
+ }
+
+ return false;
+}
+
+
+static OUString WinAccToVcl_Impl( const sal_Unicode* pStr )
+{
+ OUString aResult;
+
+ if( pStr )
+ {
+ while ( *pStr )
+ {
+ if ( *pStr == '&' )
+ {
+ aResult += "~";
+ while( *( ++pStr ) == '&' );
+ }
+ else
+ {
+ aResult += OUStringChar( *pStr );
+ pStr++;
+ }
+ }
+ }
+
+ return aResult;
+}
+
+
+OleComponent::OleComponent( const uno::Reference< uno::XComponentContext >& xContext, OleEmbeddedObject* pUnoOleObject )
+: m_pInterfaceContainer( nullptr )
+, m_bDisposed( false )
+, m_bModified( false )
+, m_pNativeImpl( new OleComponentNative_Impl() )
+, m_pUnoOleObject( pUnoOleObject )
+, m_pOleWrapClientSite( nullptr )
+, m_pImplAdviseSink( nullptr )
+, m_nOLEMiscFlags( 0 )
+, m_nAdvConn( 0 )
+, m_xContext( xContext )
+, m_bOleInitialized( false )
+, m_bWorkaroundActive( false )
+{
+ OSL_ENSURE( m_pUnoOleObject, "No owner object is provided!" );
+
+ HRESULT hr = OleInitialize( nullptr );
+ if ( hr == S_OK || hr == S_FALSE )
+ m_bOleInitialized = true;
+ else
+ {
+ SAL_WARN("embeddedobj.ole", "OleComponent ctor: OleInitialize() failed with 0x"
+ << OUString::number(static_cast<sal_uInt32>(hr), 16) << ": "
+ << WindowsErrorStringFromHRESULT(hr));
+ }
+
+ m_pOleWrapClientSite = new OleWrapperClientSite( this );
+ m_pOleWrapClientSite->AddRef();
+
+ m_pImplAdviseSink = new OleWrapperAdviseSink( this );
+ m_pImplAdviseSink->AddRef();
+
+}
+
+
+OleComponent::~OleComponent()
+{
+ OSL_ENSURE( !m_pOleWrapClientSite && !m_pImplAdviseSink && !m_pInterfaceContainer && !m_bOleInitialized,
+ "The object was not closed successfully! DISASTER is possible!" );
+
+ if ( m_pOleWrapClientSite || m_pImplAdviseSink || m_pInterfaceContainer || m_bOleInitialized )
+ {
+ osl_atomic_increment(&m_refCount);
+ try {
+ Dispose();
+ } catch( const uno::Exception& ) {}
+ }
+
+ for (auto const& format : m_pNativeImpl->m_aFormatsList)
+ {
+ delete format;
+ }
+ m_pNativeImpl->m_aFormatsList.clear();
+
+ delete m_pNativeImpl;
+}
+
+void OleComponent::Dispose()
+{
+ if ( m_bDisposed )
+ return;
+
+ // Call CloseObject() without m_aMutex locked, since it will call
+ // IOleObject::Close(), which can call event listeners, which can run on a
+ // different thread.
+ CloseObject();
+
+ osl::MutexGuard aGuard(m_aMutex);
+ if ( m_pOleWrapClientSite )
+ {
+ m_pOleWrapClientSite->disconnectOleComponent();
+ m_pOleWrapClientSite->Release();
+ m_pOleWrapClientSite = nullptr;
+ }
+
+ if ( m_pImplAdviseSink )
+ {
+ m_pImplAdviseSink->disconnectOleComponent();
+ m_pImplAdviseSink->Release();
+ m_pImplAdviseSink = nullptr;
+ }
+
+ if ( m_pInterfaceContainer )
+ {
+ lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >( this ) );
+ m_pInterfaceContainer->disposeAndClear( aEvent );
+
+ delete m_pInterfaceContainer;
+ m_pInterfaceContainer = nullptr;
+ }
+
+ if ( m_bOleInitialized )
+ {
+ // since the disposing can happen not only from main thread but also from a clipboard
+ // the deinitialization might lead to a disaster, SO7 does not deinitialize OLE at all
+ // so currently the same approach is selected as workaround
+ // OleUninitialize();
+ m_bOleInitialized = false;
+ }
+
+ m_bDisposed = true;
+}
+
+
+void OleComponent::disconnectEmbeddedObject()
+{
+ // must not be called from destructor of UNO OLE object!!!
+ osl::MutexGuard aGuard( m_aMutex );
+ m_pUnoOleObject = nullptr;
+}
+
+
+void OleComponent::CreateNewIStorage_Impl()
+{
+ // TODO: in future a global memory could be used instead of file.
+
+ // write the stream to the temporary file
+ OUString aTempURL;
+
+ OSL_ENSURE( m_pUnoOleObject, "Unexpected object absence!" );
+ if ( m_pUnoOleObject )
+ aTempURL = m_pUnoOleObject->CreateTempURLEmpty_Impl();
+ else
+ aTempURL = GetNewTempFileURL_Impl( m_xContext );
+
+ if ( !aTempURL.getLength() )
+ throw uno::RuntimeException(); // TODO
+
+ // open an IStorage based on the temporary file
+ OUString aTempFilePath;
+ if ( ::osl::FileBase::getSystemPathFromFileURL( aTempURL, aTempFilePath ) != ::osl::FileBase::E_None )
+ throw uno::RuntimeException(); // TODO: something dangerous happened
+
+ HRESULT hr = StgCreateDocfile( o3tl::toW(aTempFilePath.getStr()), STGM_CREATE | STGM_READWRITE | STGM_TRANSACTED | STGM_DELETEONRELEASE, 0, &m_pNativeImpl->m_pIStorage );
+ if ( FAILED( hr ) || !m_pNativeImpl->m_pIStorage )
+ throw io::IOException(); // TODO: transport error code?
+}
+
+
+uno::Sequence< datatransfer::DataFlavor > OleComponentNative_Impl::GetFlavorsForAspects( sal_uInt32 nSupportedAspects )
+{
+ uno::Sequence< datatransfer::DataFlavor > aResult;
+ for ( sal_uInt32 nAsp = 1; nAsp <= 8; nAsp *= 2 )
+ if ( ( nSupportedAspects & nAsp ) == nAsp )
+ {
+ OUString aAspectSuffix = GetFlavorSuffixFromAspect( nAsp );
+
+ sal_Int32 nLength = aResult.getLength();
+ aResult.realloc( nLength + m_aSupportedGraphFormats.getLength() );
+ auto pResult = aResult.getArray();
+
+ for ( sal_Int32 nInd = 0; nInd < m_aSupportedGraphFormats.getLength(); nInd++ )
+ {
+ pResult[nLength + nInd].MimeType = m_aSupportedGraphFormats[nInd].MimeType + aAspectSuffix;
+ pResult[nLength + nInd].HumanPresentableName = m_aSupportedGraphFormats[nInd].HumanPresentableName;
+ pResult[nLength + nInd].DataType = m_aSupportedGraphFormats[nInd].DataType;
+ }
+ }
+
+ return aResult;
+}
+
+
+void OleComponent::RetrieveObjectDataFlavors_Impl()
+{
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ if ( !m_aDataFlavors.getLength() )
+ {
+ sal::systools::COMReference< IDataObject > pDataObject(m_pNativeImpl->m_pObj, sal::systools::COM_QUERY);
+ if ( pDataObject )
+ {
+ sal::systools::COMReference< IEnumFORMATETC > pFormatEnum;
+ HRESULT hr = pDataObject->EnumFormatEtc( DATADIR_GET, &pFormatEnum );
+ if ( SUCCEEDED( hr ) && pFormatEnum )
+ {
+ FORMATETC pElem[ MAX_ENUM_ELE ];
+ ULONG nNum = 0;
+
+ // if it is possible to retrieve at least one supported graphical format for an aspect
+ // this format can be converted to other supported formats
+ sal_uInt32 nSupportedAspects = 0;
+ do
+ {
+ HRESULT hr2 = pFormatEnum->Next( MAX_ENUM_ELE, pElem, &nNum );
+ if( hr2 == S_OK || hr2 == S_FALSE )
+ {
+ for( sal_uInt32 nInd = 0; nInd < FORMATS_NUM; nInd++ )
+ {
+ if ( pElem[nInd].cfFormat == pFormatTemplates[nInd].cfFormat
+ && pElem[nInd].tymed == pFormatTemplates[nInd].tymed )
+ nSupportedAspects |= pElem[nInd].dwAspect;
+ }
+ }
+ else
+ break;
+ }
+ while( nNum == MAX_ENUM_ELE );
+
+ m_aDataFlavors = m_pNativeImpl->GetFlavorsForAspects( nSupportedAspects );
+ }
+ }
+
+ if ( !m_aDataFlavors.getLength() )
+ {
+ // TODO:
+ // for any reason the object could not provide this information
+ // try to get access to the cached representation
+ }
+ }
+}
+
+
+bool OleComponent::InitializeObject_Impl()
+// There will be no static objects!
+{
+ if ( !m_pNativeImpl->m_pObj )
+ return false;
+
+ // the linked object will be detected here
+ OSL_ENSURE( m_pUnoOleObject, "Unexpected object absence!" );
+ if ( m_pUnoOleObject )
+ m_pUnoOleObject->SetObjectIsLink_Impl( m_pNativeImpl->m_pObj.QueryInterface<IOleLink>(sal::systools::COM_QUERY).is() );
+
+ if ( !m_pNativeImpl->m_pViewObject2.set(m_pNativeImpl->m_pObj, sal::systools::COM_QUERY) )
+ return false;
+
+ // remove all the caches
+ if ( sal::systools::COMReference< IOleCache > pIOleCache{ m_pNativeImpl->m_pObj, sal::systools::COM_QUERY } )
+ {
+ IEnumSTATDATA* pEnumSD = nullptr;
+ HRESULT hr2 = pIOleCache->EnumCache( &pEnumSD );
+
+ if ( SUCCEEDED( hr2 ) && pEnumSD )
+ {
+ pEnumSD->Reset();
+ STATDATA aSD;
+ DWORD nNum;
+ while( SUCCEEDED( pEnumSD->Next( 1, &aSD, &nNum ) ) && nNum == 1 )
+ hr2 = pIOleCache->Uncache( aSD.dwConnection );
+ }
+
+ // No IDataObject implementation, caching must be used instead
+ DWORD nConn;
+ FORMATETC aFormat = { 0, nullptr, DVASPECT_CONTENT, -1, TYMED_MFPICT };
+ hr2 = pIOleCache->Cache( &aFormat, ADVFCACHE_ONSAVE, &nConn );
+ }
+
+ if ( !m_pNativeImpl->m_pOleObject.set(m_pNativeImpl->m_pObj, sal::systools::COM_QUERY) )
+ return false; // Static objects are not supported, they should be inserted as graphics
+
+ m_pNativeImpl->m_pOleObject->GetMiscStatus( DVASPECT_CONTENT, reinterpret_cast<DWORD*>(&m_nOLEMiscFlags) );
+ // TODO: use other misc flags also
+ // the object should have drawable aspect even in case it supports only iconic representation
+ // if ( m_nOLEMiscFlags & OLEMISC_ONLYICONIC )
+
+ m_pNativeImpl->m_pOleObject->SetClientSite( m_pOleWrapClientSite );
+
+ // the only need in this registration is workaround for close notification
+ m_pNativeImpl->m_pOleObject->Advise( m_pImplAdviseSink, reinterpret_cast<DWORD*>(&m_nAdvConn) );
+ m_pNativeImpl->m_pViewObject2->SetAdvise( DVASPECT_CONTENT, 0, m_pImplAdviseSink );
+
+ OleSetContainedObject( m_pNativeImpl->m_pOleObject, TRUE );
+
+ return true;
+}
+
+namespace
+{
+ HRESULT OleLoadSeh(LPSTORAGE pIStorage, LPVOID* ppObj)
+ {
+ HRESULT hr = E_FAIL;
+ // tdf#119039: there is a nasty bug in OleLoad, that may call an unpaired
+ // IUnknown::Release on pIStorage on STG_E_FILENOTFOUND: see
+ // https://developercommunity.visualstudio.com/t/10144795
+ // Workaround it here to avoid crash in smart COM pointer destructor that
+ // would try to release already released object. Since we don't know if
+ // the bug appears each time STG_E_FILENOTFOUND is returned, this might
+ // potentially leak the storge object.
+ if (pIStorage)
+ pIStorage->AddRef();
+
+ __try {
+ hr = OleLoad(pIStorage, IID_IUnknown, nullptr, ppObj);
+ } __except( EXCEPTION_EXECUTE_HANDLER ) {
+ hr = E_FAIL;
+ }
+ if (pIStorage && hr != STG_E_FILENOTFOUND)
+ pIStorage->Release();
+
+ return hr;
+ }
+}
+
+void OleComponent::LoadEmbeddedObject( const OUString& aTempURL )
+{
+ if ( !aTempURL.getLength() )
+ throw lang::IllegalArgumentException(); // TODO
+
+ if ( m_pNativeImpl->m_pIStorage )
+ throw io::IOException(); // TODO the object is already initialized or wrong initialization is done
+
+ // open an IStorage based on the temporary file
+ HRESULT hr = OpenIStorageFromURL_Impl( aTempURL, &m_pNativeImpl->m_pIStorage );
+
+ if ( FAILED( hr ) || !m_pNativeImpl->m_pIStorage )
+ throw io::IOException(); // TODO: transport error code?
+
+ hr = OleLoadSeh(m_pNativeImpl->m_pIStorage, reinterpret_cast<void**>(&m_pNativeImpl->m_pObj));
+ if ( FAILED( hr ) || !m_pNativeImpl->m_pObj )
+ {
+ throw uno::RuntimeException();
+ }
+
+ if ( !InitializeObject_Impl() )
+ throw uno::RuntimeException(); // TODO
+}
+
+
+void OleComponent::CreateObjectFromClipboard()
+{
+ if ( m_pNativeImpl->m_pIStorage )
+ throw io::IOException(); // TODO:the object is already initialized
+
+ CreateNewIStorage_Impl();
+ if ( !m_pNativeImpl->m_pIStorage )
+ throw uno::RuntimeException(); // TODO
+
+ IDataObject * pDO = nullptr;
+ HRESULT hr = OleGetClipboard( &pDO );
+ if( SUCCEEDED( hr ) && pDO )
+ {
+ hr = OleQueryCreateFromData( pDO );
+ if( S_OK == GetScode( hr ) )
+ {
+ hr = OleCreateFromData( pDO,
+ IID_IUnknown,
+ OLERENDER_DRAW, // OLERENDER_FORMAT
+ nullptr, // &aFormat,
+ nullptr,
+ m_pNativeImpl->m_pIStorage,
+ reinterpret_cast<void**>(&m_pNativeImpl->m_pObj) );
+ }
+ else
+ {
+ // Static objects are not supported
+ pDO->Release();
+ }
+ }
+
+ if ( FAILED( hr ) || !m_pNativeImpl->m_pObj )
+ throw uno::RuntimeException();
+
+ if ( !InitializeObject_Impl() )
+ throw uno::RuntimeException(); // TODO
+}
+
+
+void OleComponent::CreateNewEmbeddedObject( const uno::Sequence< sal_Int8 >& aSeqCLSID )
+{
+ CLSID aClsID;
+
+ if ( !GetClassIDFromSequence_Impl( aSeqCLSID, aClsID ) )
+ throw lang::IllegalArgumentException(); // TODO
+
+ if ( m_pNativeImpl->m_pIStorage )
+ throw io::IOException(); // TODO:the object is already initialized
+
+ CreateNewIStorage_Impl();
+ if ( !m_pNativeImpl->m_pIStorage )
+ throw uno::RuntimeException(); // TODO
+
+ // FORMATETC aFormat = { CF_METAFILEPICT, NULL, nAspect, -1, TYMED_MFPICT }; // for OLE..._DRAW should be NULL
+
+ HRESULT hr = OleCreate( aClsID,
+ IID_IUnknown,
+ OLERENDER_DRAW, // OLERENDER_FORMAT
+ nullptr, // &aFormat,
+ nullptr,
+ m_pNativeImpl->m_pIStorage,
+ reinterpret_cast<void**>(&m_pNativeImpl->m_pObj) );
+
+ if ( FAILED( hr ) || !m_pNativeImpl->m_pObj )
+ throw uno::RuntimeException(); // TODO
+
+ if ( !InitializeObject_Impl() )
+ throw uno::RuntimeException(); // TODO
+
+ // TODO: getExtent???
+}
+
+
+void OleComponent::CreateObjectFromData( const uno::Reference< datatransfer::XTransferable >& )
+// Static objects are not supported, they should be inserted as graphics
+{
+ // TODO: May be this call is useless since there are no static objects
+ // and nonstatic objects will be created based on OLEstorage ( stream ).
+ // ???
+
+ // OleQueryCreateFromData...
+}
+
+
+void OleComponent::CreateObjectFromFile( const OUString& aFileURL )
+{
+ if ( m_pNativeImpl->m_pIStorage )
+ throw io::IOException(); // TODO:the object is already initialized
+
+ CreateNewIStorage_Impl();
+ if ( !m_pNativeImpl->m_pIStorage )
+ throw uno::RuntimeException(); // TODO:
+
+ OUString aFilePath;
+ if ( ::osl::FileBase::getSystemPathFromFileURL( aFileURL, aFilePath ) != ::osl::FileBase::E_None )
+ throw uno::RuntimeException(); // TODO: something dangerous happened
+
+ HRESULT hr = OleCreateFromFile( CLSID_NULL,
+ o3tl::toW(aFilePath.getStr()),
+ IID_IUnknown,
+ OLERENDER_DRAW, // OLERENDER_FORMAT
+ nullptr,
+ nullptr,
+ m_pNativeImpl->m_pIStorage,
+ reinterpret_cast<void**>(&m_pNativeImpl->m_pObj) );
+
+ if ( FAILED( hr ) || !m_pNativeImpl->m_pObj )
+ throw uno::RuntimeException(); // TODO
+
+ if ( !InitializeObject_Impl() )
+ throw uno::RuntimeException(); // TODO
+}
+
+
+void OleComponent::CreateLinkFromFile( const OUString& aFileURL )
+{
+ if ( m_pNativeImpl->m_pIStorage )
+ throw io::IOException(); // TODO:the object is already initialized
+
+ CreateNewIStorage_Impl();
+ if ( !m_pNativeImpl->m_pIStorage )
+ throw uno::RuntimeException(); // TODO:
+
+ OUString aFilePath;
+ if ( ::osl::FileBase::getSystemPathFromFileURL( aFileURL, aFilePath ) != ::osl::FileBase::E_None )
+ throw uno::RuntimeException(); // TODO: something dangerous happened
+
+ HRESULT hr = OleCreateLinkToFile( o3tl::toW(aFilePath.getStr()),
+ IID_IUnknown,
+ OLERENDER_DRAW, // OLERENDER_FORMAT
+ nullptr,
+ nullptr,
+ m_pNativeImpl->m_pIStorage,
+ reinterpret_cast<void**>(&m_pNativeImpl->m_pObj) );
+
+ if ( FAILED( hr ) || !m_pNativeImpl->m_pObj )
+ throw uno::RuntimeException(); // TODO
+
+ if ( !InitializeObject_Impl() )
+ throw uno::RuntimeException(); // TODO
+}
+
+
+void OleComponent::InitEmbeddedCopyOfLink( rtl::Reference<OleComponent> const & pOleLinkComponent )
+{
+ if ( !pOleLinkComponent || !pOleLinkComponent->m_pNativeImpl->m_pObj )
+ throw lang::IllegalArgumentException(); // TODO
+
+ if ( m_pNativeImpl->m_pIStorage )
+ throw io::IOException(); // TODO:the object is already initialized
+
+ sal::systools::COMReference< IDataObject > pDataObject(pOleLinkComponent->m_pNativeImpl->m_pObj, sal::systools::COM_QUERY);
+ if ( pDataObject && SUCCEEDED( OleQueryCreateFromData( pDataObject ) ) )
+ {
+ // the object must be already disconnected from the temporary URL
+ CreateNewIStorage_Impl();
+ if ( !m_pNativeImpl->m_pIStorage )
+ throw uno::RuntimeException(); // TODO:
+
+ OleCreateFromData( pDataObject,
+ IID_IUnknown,
+ OLERENDER_DRAW,
+ nullptr,
+ nullptr,
+ m_pNativeImpl->m_pIStorage,
+ reinterpret_cast<void**>(&m_pNativeImpl->m_pObj) );
+ }
+
+ if ( !m_pNativeImpl->m_pObj )
+ {
+ sal::systools::COMReference< IOleLink > pOleLink(m_pNativeImpl->m_pObj, sal::systools::COM_QUERY);
+ if ( !pOleLink )
+ throw io::IOException(); // TODO: the object doesn't support IOleLink
+
+ sal::systools::COMReference< IMoniker > pMoniker;
+ HRESULT hr = pOleLink->GetSourceMoniker( &pMoniker );
+ if ( FAILED( hr ) || !pMoniker )
+ throw io::IOException(); // TODO: can not retrieve moniker
+
+ // In case of file moniker life is easy : )
+ DWORD aMonType = 0;
+ hr = pMoniker->IsSystemMoniker( &aMonType );
+ if ( SUCCEEDED( hr ) && aMonType == MKSYS_FILEMONIKER )
+ {
+ sal::systools::COMReference< IMalloc > pMalloc;
+ hr = CoGetMalloc( 1, &pMalloc ); // if fails there will be a memory leak
+ OSL_ENSURE(SUCCEEDED(hr) && pMalloc, "CoGetMalloc() failed!");
+
+ LPOLESTR pOleStr = nullptr;
+ hr = pOleLink->GetSourceDisplayName( &pOleStr );
+ if ( SUCCEEDED( hr ) && pOleStr )
+ {
+ std::wstring aFilePath( pOleStr );
+ if ( pMalloc )
+ pMalloc->Free( pOleStr );
+
+ hr = OleCreateFromFile( CLSID_NULL,
+ aFilePath.c_str(),
+ IID_IUnknown,
+ OLERENDER_DRAW, // OLERENDER_FORMAT
+ nullptr,
+ nullptr,
+ m_pNativeImpl->m_pIStorage,
+ reinterpret_cast<void**>(&m_pNativeImpl->m_pObj) );
+ }
+ }
+
+ // in case of other moniker types the only way is to get storage
+ if ( !m_pNativeImpl->m_pObj )
+ {
+ sal::systools::COMReference< IBindCtx > pBindCtx;
+ hr = CreateBindCtx( 0, &pBindCtx );
+ if ( SUCCEEDED( hr ) && pBindCtx )
+ {
+ sal::systools::COMReference< IStorage > pObjectStorage;
+ hr = pMoniker->BindToStorage( pBindCtx, nullptr, IID_IStorage, reinterpret_cast<void**>(&pObjectStorage) );
+ if ( SUCCEEDED( hr ) && pObjectStorage )
+ {
+ hr = pObjectStorage->CopyTo( 0, nullptr, nullptr, m_pNativeImpl->m_pIStorage );
+ if ( SUCCEEDED( hr ) )
+ hr = OleLoadSeh(m_pNativeImpl->m_pIStorage, reinterpret_cast<void**>(&m_pNativeImpl->m_pObj));
+ }
+ }
+ }
+ }
+
+ // If object could not be created the only way is to use graphical representation
+ if ( !m_pNativeImpl->m_pObj )
+ throw uno::RuntimeException(); // TODO
+
+ if ( !InitializeObject_Impl() )
+ throw uno::RuntimeException(); // TODO
+}
+
+
+void OleComponent::RunObject()
+{
+ OSL_ENSURE( m_pNativeImpl->m_pOleObject, "The pointer can not be set to NULL here!" );
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ if ( !OleIsRunning( m_pNativeImpl->m_pOleObject ) )
+ {
+ HRESULT hr = OleRun( m_pNativeImpl->m_pObj );
+
+ if ( FAILED( hr ) )
+ {
+ if ( hr == REGDB_E_CLASSNOTREG )
+ throw embed::UnreachableStateException(); // the object server is not installed
+ else
+ throw io::IOException();
+ }
+ }
+}
+
+
+awt::Size OleComponent::CalculateWithFactor( const awt::Size& aSize,
+ const awt::Size& aMultiplier,
+ const awt::Size& aDivisor )
+{
+ awt::Size aResult;
+
+ sal_Int64 nWidth = static_cast<sal_Int64>(aSize.Width) * static_cast<sal_Int64>(aMultiplier.Width) / static_cast<sal_Int64>(aDivisor.Width);
+ sal_Int64 nHeight = static_cast<sal_Int64>(aSize.Height) * static_cast<sal_Int64>(aMultiplier.Height) / static_cast<sal_Int64>(aDivisor.Height);
+ OSL_ENSURE( nWidth < SAL_MAX_INT32 && nWidth > SAL_MIN_INT32
+ && nHeight < SAL_MAX_INT32 && nHeight > SAL_MIN_INT32,
+ "Unacceptable result size!" );
+
+ aResult.Width = static_cast<sal_Int32>(nWidth);
+ aResult.Height = static_cast<sal_Int32>(nHeight);
+
+ return aResult;
+}
+
+
+void OleComponent::CloseObject()
+{
+ if ( m_pNativeImpl->m_pOleObject && OleIsRunning( m_pNativeImpl->m_pOleObject ) )
+ m_pNativeImpl->m_pOleObject->Close( OLECLOSE_NOSAVE ); // must be saved before
+}
+
+
+uno::Sequence< embed::VerbDescriptor > OleComponent::GetVerbList()
+{
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ if( !m_aVerbList.getLength() )
+ {
+ sal::systools::COMReference< IEnumOLEVERB > pEnum;
+ if( SUCCEEDED( m_pNativeImpl->m_pOleObject->EnumVerbs( &pEnum ) ) )
+ {
+ OLEVERB szEle[ MAX_ENUM_ELE ];
+ ULONG nNum = 0;
+ sal_Int32 nSeqSize = 0;
+
+ do
+ {
+ HRESULT hr = pEnum->Next( MAX_ENUM_ELE, szEle, &nNum );
+ if( hr == S_OK || hr == S_FALSE )
+ {
+ m_aVerbList.realloc( nSeqSize += nNum );
+ auto pVerbList = m_aVerbList.getArray();
+ for( sal_uInt32 nInd = 0; nInd < nNum; nInd++ )
+ {
+ pVerbList[nSeqSize-nNum+nInd].VerbID = szEle[ nInd ].lVerb;
+ pVerbList[nSeqSize-nNum+nInd].VerbName = WinAccToVcl_Impl( o3tl::toU(szEle[ nInd ].lpszVerbName) );
+ pVerbList[nSeqSize-nNum+nInd].VerbFlags = szEle[ nInd ].fuFlags;
+ pVerbList[nSeqSize-nNum+nInd].VerbAttributes = szEle[ nInd ].grfAttribs;
+ }
+ }
+ else
+ break;
+ }
+ while( nNum == MAX_ENUM_ELE );
+ }
+ }
+
+ return m_aVerbList;
+}
+
+
+void OleComponent::ExecuteVerb( sal_Int32 nVerbID )
+{
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO
+
+ HRESULT hr = OleRun( m_pNativeImpl->m_pOleObject );
+ if ( FAILED( hr ) )
+ throw io::IOException(); // TODO: a specific exception that transport error code can be thrown here
+
+ // TODO: probably extents should be set here and stored in aRect
+ // TODO: probably the parent window also should be set
+ hr = m_pNativeImpl->m_pOleObject->DoVerb( nVerbID, nullptr, m_pOleWrapClientSite, 0, nullptr, nullptr );
+
+ if ( FAILED( hr ) )
+ throw io::IOException(); // TODO
+}
+
+
+void OleComponent::SetHostName( const OUString& aEmbDocName )
+{
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ m_pNativeImpl->m_pOleObject->SetHostNames( L"app name", o3tl::toW( aEmbDocName.getStr() ) );
+}
+
+
+void OleComponent::SetExtent( const awt::Size& aVisAreaSize, sal_Int64 nAspect )
+{
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ DWORD nMSAspect = static_cast<DWORD>(nAspect); // first 32 bits are for MS aspects
+
+ SIZEL aSize = { aVisAreaSize.Width, aVisAreaSize.Height };
+ HRESULT hr = m_pNativeImpl->m_pOleObject->SetExtent( nMSAspect, &aSize );
+
+ if ( FAILED( hr ) )
+ {
+ // TODO/LATER: is it correct? In future user code probably should be ready for the exception.
+ // if the object is running but not activated, RPC_E_SERVER_DIED error code is returned by OLE package
+ // in this case just do nothing
+ // Also Visio returns E_FAIL on resize if it is in running state
+ // if ( hr != RPC_E_SERVER_DIED )
+ throw io::IOException(); // TODO
+ }
+}
+
+
+awt::Size OleComponent::GetExtent( sal_Int64 nAspect )
+{
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ DWORD nMSAspect = static_cast<DWORD>(nAspect); // first 32 bits are for MS aspects
+ awt::Size aSize;
+ bool bGotSize = false;
+
+ if ( nMSAspect == DVASPECT_CONTENT )
+ {
+ // Try to get the size from the replacement image first
+ sal::systools::COMReference< IDataObject > pDataObject(m_pNativeImpl->m_pObj, sal::systools::COM_QUERY);
+ if ( pDataObject )
+ {
+ STGMEDIUM aMedium;
+ FORMATETC aFormat = pFormatTemplates[1]; // use windows metafile format
+ aFormat.dwAspect = nMSAspect;
+
+ HRESULT hr = pDataObject->GetData( &aFormat, &aMedium );
+
+ if (hr == RPC_E_WRONG_THREAD)
+ {
+ // Assume that the OLE object was loaded on the main thread.
+ vcl::solarthread::syncExecute([this, &hr, &pDataObject, &aFormat, &aMedium]() {
+ // Make sure that the current state is embed::EmbedStates::RUNNING.
+ RunObject();
+ // Now try again on the correct thread.
+ hr = pDataObject->GetData(&aFormat, &aMedium);
+ });
+ }
+
+ if ( SUCCEEDED( hr ) && aMedium.tymed == TYMED_MFPICT ) // Win Metafile
+ {
+ METAFILEPICT* pMF = static_cast<METAFILEPICT*>(GlobalLock( aMedium.hMetaFilePict ));
+ if ( pMF )
+ {
+ // the object uses 0.01 mm as unit, so the metafile size should be converted to object unit
+ o3tl::Length eFrom = o3tl::Length::mm100;
+ switch( pMF->mm )
+ {
+ case MM_HIENGLISH:
+ eFrom = o3tl::Length::in1000;
+ break;
+
+ case MM_LOENGLISH:
+ eFrom = o3tl::Length::in100;
+ break;
+
+ case MM_LOMETRIC:
+ eFrom = o3tl::Length::mm10;
+ break;
+
+ case MM_TWIPS:
+ eFrom = o3tl::Length::twip;
+ break;
+
+ case MM_ISOTROPIC:
+ case MM_ANISOTROPIC:
+ case MM_HIMETRIC:
+ // do nothing
+ break;
+ }
+
+ sal_Int64 nX = o3tl::convert(abs( pMF->xExt ), eFrom, o3tl::Length::mm100);
+ sal_Int64 nY = o3tl::convert(abs( pMF->yExt ), eFrom, o3tl::Length::mm100);
+ if ( nX < SAL_MAX_INT32 && nY < SAL_MAX_INT32 )
+ {
+ aSize.Width = static_cast<sal_Int32>(nX);
+ aSize.Height = static_cast<sal_Int32>(nY);
+ bGotSize = true;
+ }
+ else
+ OSL_FAIL( "Unexpected size is provided!" );
+ }
+ }
+ else if (!SUCCEEDED(hr))
+ {
+ SAL_WARN("embeddedobj.ole", " OleComponent::GetExtent: GetData() failed");
+ }
+ // i113605, to release storage medium
+ if ( SUCCEEDED( hr ) )
+ ::ReleaseStgMedium(&aMedium);
+ }
+ }
+
+ if ( !bGotSize )
+ throw lang::IllegalArgumentException();
+
+ return aSize;
+}
+
+
+awt::Size OleComponent::GetCachedExtent( sal_Int64 nAspect )
+{
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ DWORD nMSAspect = static_cast<DWORD>(nAspect); // first 32 bits are for MS aspects
+ SIZEL aSize;
+
+ HRESULT hr = m_pNativeImpl->m_pViewObject2->GetExtent( nMSAspect, -1, nullptr, &aSize );
+
+ if ( FAILED( hr ) )
+ {
+ // TODO/LATER: is it correct?
+ // if there is no appropriate cache for the aspect, OLE_E_BLANK error code is returned
+ // if ( hr == OLE_E_BLANK )
+ // throw lang::IllegalArgumentException();
+ //else
+ // throw io::IOException(); // TODO
+
+ SAL_WARN("embeddedobj.ole", " OleComponent::GetCachedExtent: GetExtent() failed");
+ throw lang::IllegalArgumentException();
+ }
+
+ return awt::Size( aSize.cx, aSize.cy );
+}
+
+
+awt::Size OleComponent::GetRecommendedExtent( sal_Int64 nAspect )
+{
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ DWORD nMSAspect = static_cast<DWORD>(nAspect); // first 32 bits are for MS aspects
+ SIZEL aSize;
+ HRESULT hr = m_pNativeImpl->m_pOleObject->GetExtent( nMSAspect, &aSize );
+ if ( FAILED( hr ) )
+ {
+ SAL_WARN("embeddedobj.ole", " OleComponent::GetRecommendedExtent: GetExtent() failed");
+ throw lang::IllegalArgumentException();
+ }
+
+ return awt::Size( aSize.cx, aSize.cy );
+}
+
+
+sal_Int64 OleComponent::GetMiscStatus( sal_Int64 nAspect )
+{
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ DWORD nResult;
+ m_pNativeImpl->m_pOleObject->GetMiscStatus( static_cast<DWORD>(nAspect), &nResult );
+ return static_cast<sal_Int64>(nResult); // first 32 bits are for MS flags
+}
+
+
+uno::Sequence< sal_Int8 > OleComponent::GetCLSID()
+{
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ GUID aCLSID;
+ HRESULT hr = m_pNativeImpl->m_pOleObject->GetUserClassID( &aCLSID );
+ if ( FAILED( hr ) )
+ throw io::IOException(); // TODO:
+
+ return MimeConfigurationHelper::GetSequenceClassID( aCLSID.Data1, aCLSID.Data2, aCLSID.Data3,
+ aCLSID.Data4[0], aCLSID.Data4[1],
+ aCLSID.Data4[2], aCLSID.Data4[3],
+ aCLSID.Data4[4], aCLSID.Data4[5],
+ aCLSID.Data4[6], aCLSID.Data4[7] );
+}
+
+
+bool OleComponent::IsDirty()
+{
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ if ( IsWorkaroundActive() )
+ return true;
+
+ sal::systools::COMReference< IPersistStorage > pPersistStorage(m_pNativeImpl->m_pObj, sal::systools::COM_QUERY);
+ if ( !pPersistStorage )
+ throw io::IOException(); // TODO
+
+ HRESULT hr = pPersistStorage->IsDirty();
+ return ( hr != S_FALSE );
+}
+
+
+void OleComponent::StoreOwnTmpIfNecessary()
+{
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ sal::systools::COMReference< IPersistStorage > pPersistStorage(m_pNativeImpl->m_pObj, sal::systools::COM_QUERY);
+ if ( !pPersistStorage )
+ throw io::IOException(); // TODO
+
+ if ( m_bWorkaroundActive || pPersistStorage->IsDirty() != S_FALSE )
+ {
+ HRESULT hr = OleSave( pPersistStorage, m_pNativeImpl->m_pIStorage, TRUE );
+ if ( FAILED( hr ) )
+ {
+ // Till now was required only for AcrobatReader7.0.8
+ GUID aCLSID;
+ hr = m_pNativeImpl->m_pOleObject->GetUserClassID( &aCLSID );
+ if ( FAILED( hr ) )
+ {
+ SAL_WARN("embeddedobj.ole", "OleComponent::StoreOwnTmpIfNecessary: GetUserClassID() failed");
+ throw io::IOException(); // TODO
+ }
+
+ hr = WriteClassStg( m_pNativeImpl->m_pIStorage, aCLSID );
+ if ( FAILED( hr ) )
+ throw io::IOException(); // TODO
+
+ // the result of the following call is not checked because some objects, for example AcrobatReader7.0.8
+ // return error even in case the saving was done correctly
+ hr = pPersistStorage->Save( m_pNativeImpl->m_pIStorage, TRUE );
+
+ // another workaround for AcrobatReader7.0.8 object, this object might think that it is not changed
+ // when it has been created from file, although it must be saved
+ m_bWorkaroundActive = true;
+ }
+
+ hr = m_pNativeImpl->m_pIStorage->Commit( STGC_DEFAULT );
+ if ( FAILED( hr ) )
+ throw io::IOException(); // TODO
+
+ hr = pPersistStorage->SaveCompleted( nullptr );
+ if ( FAILED( hr ) && hr != E_UNEXPECTED )
+ throw io::IOException(); // TODO
+
+ }
+}
+
+
+bool OleComponent::SaveObject_Impl()
+{
+ bool bResult = false;
+ OleEmbeddedObject* pLockObject = nullptr;
+
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ if ( m_pUnoOleObject )
+ {
+ pLockObject = m_pUnoOleObject;
+ pLockObject->acquire();
+ }
+ }
+
+ if ( pLockObject )
+ {
+ bResult = pLockObject->SaveObject_Impl();
+ pLockObject->release();
+ }
+
+ return bResult;
+}
+
+
+bool OleComponent::OnShowWindow_Impl( bool bShow )
+{
+ bool bResult = false;
+ OleEmbeddedObject* pLockObject = nullptr;
+
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pUnoOleObject )
+ {
+ pLockObject = m_pUnoOleObject;
+ pLockObject->acquire();
+ }
+ }
+
+ if ( pLockObject )
+ {
+ bResult = pLockObject->OnShowWindow_Impl( bShow );
+ pLockObject->release();
+ }
+
+ return bResult;
+}
+
+
+void OleComponent::OnViewChange_Impl( sal_uInt32 dwAspect )
+{
+ // TODO: check if it is enough or may be saving notifications are required for Visio2000
+ ::rtl::Reference< OleEmbeddedObject > xLockObject;
+
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ if ( m_pUnoOleObject )
+ xLockObject = m_pUnoOleObject;
+ }
+
+ if ( xLockObject.is() )
+ {
+ uno::Reference < awt::XRequestCallback > xRequestCallback(
+ m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.awt.AsyncCallback", m_xContext),
+ uno::UNO_QUERY );
+ xRequestCallback->addCallback( new MainThreadNotificationRequest( xLockObject, OLECOMP_ONVIEWCHANGE, dwAspect ), uno::Any() );
+ }
+}
+
+
+void OleComponent::OnClose_Impl()
+{
+ ::rtl::Reference< OleEmbeddedObject > xLockObject;
+
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ if ( m_pUnoOleObject )
+ xLockObject = m_pUnoOleObject;
+ }
+
+ if ( xLockObject.is() )
+ {
+ uno::Reference < awt::XRequestCallback > xRequestCallback(
+ m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.awt.AsyncCallback", m_xContext),
+ uno::UNO_QUERY );
+ xRequestCallback->addCallback( new MainThreadNotificationRequest( xLockObject, OLECOMP_ONCLOSE ), uno::Any() );
+ }
+}
+
+// XCloseable
+
+void SAL_CALL OleComponent::close( sal_Bool bDeliverOwnership )
+{
+ uno::Reference< uno::XInterface > xSelfHold;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw lang::DisposedException(); // TODO
+
+ xSelfHold.set(static_cast<::cppu::OWeakObject*>(this));
+ lang::EventObject aSource(static_cast<::cppu::OWeakObject*>(this));
+
+ if (m_pInterfaceContainer)
+ {
+ comphelper::OInterfaceContainerHelper2* pContainer
+ = m_pInterfaceContainer->getContainer(cppu::UnoType<util::XCloseListener>::get());
+ if (pContainer != nullptr)
+ {
+ comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer);
+ while (pIterator.hasMoreElements())
+ {
+ try
+ {
+ static_cast<util::XCloseListener*>(pIterator.next())
+ ->queryClosing(aSource, bDeliverOwnership);
+ }
+ catch (const uno::RuntimeException&)
+ {
+ pIterator.remove();
+ }
+ }
+ }
+
+ pContainer
+ = m_pInterfaceContainer->getContainer(cppu::UnoType<util::XCloseListener>::get());
+ if (pContainer != nullptr)
+ {
+ comphelper::OInterfaceIteratorHelper2 pCloseIterator(*pContainer);
+ while (pCloseIterator.hasMoreElements())
+ {
+ try
+ {
+ static_cast<util::XCloseListener*>(pCloseIterator.next())
+ ->notifyClosing(aSource);
+ }
+ catch (const uno::RuntimeException&)
+ {
+ pCloseIterator.remove();
+ }
+ }
+ }
+ }
+ }
+
+ Dispose();
+}
+
+
+void SAL_CALL OleComponent::addCloseListener( const uno::Reference< util::XCloseListener >& xListener )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !m_pInterfaceContainer )
+ m_pInterfaceContainer = new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex );
+
+ m_pInterfaceContainer->addInterface( cppu::UnoType<util::XCloseListener>::get(), xListener );
+}
+
+
+void SAL_CALL OleComponent::removeCloseListener( const uno::Reference< util::XCloseListener >& xListener )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_pInterfaceContainer )
+ m_pInterfaceContainer->removeInterface( cppu::UnoType<util::XCloseListener>::get(),
+ xListener );
+}
+
+// XTransferable
+
+uno::Any SAL_CALL OleComponent::getTransferData( const datatransfer::DataFlavor& aFlavor )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ uno::Any aResult;
+ bool bSupportedFlavor = false;
+
+ if ( m_pNativeImpl->GraphicalFlavor( aFlavor ) )
+ {
+ DWORD nRequestedAspect = GetAspectFromFlavor( aFlavor );
+ // if own icon is set and icon aspect is requested the own icon can be returned directly
+
+ sal::systools::COMReference< IDataObject > pDataObject(m_pNativeImpl->m_pObj, sal::systools::COM_QUERY);
+ if ( !pDataObject )
+ throw io::IOException(); // TODO: transport error code
+
+ // The following optimization does not make much sense currently just because
+ // only one aspect is supported, and only three formats for the aspect are supported
+ // and moreover it is not guaranteed that the once returned format will be supported further
+ // example - i52106
+ // TODO/LATER: bring the optimization back when other aspects are supported
+
+ // FORMATETC* pFormatEtc = m_pNativeImpl->GetSupportedFormatForAspect( nRequestedAspect );
+ // if ( pFormatEtc )
+ // {
+ // STGMEDIUM aMedium;
+ // hr = pDataObject->GetData( pFormatEtc, &aMedium );
+ // if ( SUCCEEDED( hr ) )
+ // bSupportedFlavor = m_pNativeImpl->ConvertDataForFlavor( aMedium, aFlavor, aResult );
+ // }
+ // else
+ {
+ // the supported format of the application is still not found, find one
+ for ( sal_Int32 nInd = 0; nInd < FORMATS_NUM; nInd++ )
+ {
+ STGMEDIUM aMedium;
+ FORMATETC aFormat = pFormatTemplates[nInd];
+ aFormat.dwAspect = nRequestedAspect;
+
+ HRESULT hr = pDataObject->GetData( &aFormat, &aMedium );
+ if ( SUCCEEDED( hr ) )
+ {
+ bSupportedFlavor = m_pNativeImpl->ConvertDataForFlavor( aMedium, aFlavor, aResult );
+ ::ReleaseStgMedium(&aMedium); // i113605, to release storage medium
+ if ( bSupportedFlavor )
+ {
+ // TODO/LATER: bring the optimization back when other aspects are supported
+ // m_pNativeImpl->AddSupportedFormat( aFormat );
+ break;
+ }
+ }
+ }
+ }
+
+ // If the replacement could not be retrieved, the cached representation should be used
+ // currently it is not necessary to retrieve it here, so it is implemented in the object itself
+ }
+ // TODO: Investigate if there is already the format name
+ // and whether this format is really required
+ else if ( aFlavor.DataType == cppu::UnoType<io::XInputStream>::get()
+ && aFlavor.MimeType == "application/x-openoffice-contentstream" )
+ {
+ // allow to retrieve stream-representation of the object persistence
+ bSupportedFlavor = true;
+ uno::Reference < io::XStream > xTempFileStream(
+ io::TempFile::create(m_xContext),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference< io::XOutputStream > xTempOutStream = xTempFileStream->getOutputStream();
+ uno::Reference< io::XInputStream > xTempInStream = xTempFileStream->getInputStream();
+ if ( !(xTempOutStream.is() && xTempInStream.is()) )
+ throw io::IOException(); // TODO:
+
+ OSL_ENSURE( m_pUnoOleObject, "Unexpected object absence!" );
+ if ( !m_pUnoOleObject )
+ throw uno::RuntimeException();
+
+ m_pUnoOleObject->StoreObjectToStream( xTempOutStream );
+
+ xTempOutStream->closeOutput();
+ xTempOutStream.clear();
+
+ aResult <<= xTempInStream;
+ }
+
+ if ( !bSupportedFlavor )
+ throw datatransfer::UnsupportedFlavorException();
+
+ return aResult;
+}
+
+
+uno::Sequence< datatransfer::DataFlavor > SAL_CALL OleComponent::getTransferDataFlavors()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ RetrieveObjectDataFlavors_Impl();
+
+ return m_aDataFlavors;
+}
+
+
+sal_Bool SAL_CALL OleComponent::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !m_pNativeImpl->m_pOleObject )
+ throw embed::WrongStateException(); // TODO: the object is in wrong state
+
+ if ( !m_aDataFlavors.getLength() )
+ {
+ RetrieveObjectDataFlavors_Impl();
+ }
+
+ for ( auto const & supportedFormat : std::as_const(m_aDataFlavors) )
+ if ( supportedFormat.MimeType.equals( aFlavor.MimeType ) && supportedFormat.DataType == aFlavor.DataType )
+ return true;
+
+ return false;
+}
+
+void SAL_CALL OleComponent::dispose()
+{
+ try
+ {
+ close( true );
+ }
+ catch ( const uno::Exception& )
+ {
+ }
+}
+
+void SAL_CALL OleComponent::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !m_pInterfaceContainer )
+ m_pInterfaceContainer = new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex );
+
+ m_pInterfaceContainer->addInterface( cppu::UnoType<lang::XEventListener>::get(), xListener );
+}
+
+
+void SAL_CALL OleComponent::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_pInterfaceContainer )
+ m_pInterfaceContainer->removeInterface( cppu::UnoType<lang::XEventListener>::get(),
+ xListener );
+}
+
+sal_Int64 SAL_CALL OleComponent::getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier )
+{
+ try
+ {
+ uno::Sequence < sal_Int8 > aCLSID = GetCLSID();
+ if ( MimeConfigurationHelper::ClassIDsEqual( aIdentifier, aCLSID ) )
+ return comphelper::getSomething_cast(static_cast<IUnknown*>(m_pNativeImpl->m_pObj));
+
+ // compatibility hack for old versions: CLSID was used in wrong order (SvGlobalName order)
+ sal_Int32 nLength = aIdentifier.getLength();
+ if ( nLength == 16 )
+ {
+ for ( sal_Int32 n=8; n<16; n++ )
+ if ( aIdentifier[n] != aCLSID[n] )
+ return 0;
+ if ( aIdentifier[7] == aCLSID[6] &&
+ aIdentifier[6] == aCLSID[7] &&
+ aIdentifier[5] == aCLSID[4] &&
+ aIdentifier[4] == aCLSID[5] &&
+ aIdentifier[3] == aCLSID[0] &&
+ aIdentifier[2] == aCLSID[1] &&
+ aIdentifier[1] == aCLSID[2] &&
+ aIdentifier[0] == aCLSID[3] )
+ return reinterpret_cast<sal_Int64>(static_cast<IUnknown*>(m_pNativeImpl->m_pObj));
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ }
+
+ return 0;
+}
+
+sal_Bool SAL_CALL OleComponent::isModified()
+{
+ return m_bModified;
+}
+
+void SAL_CALL OleComponent::setModified( sal_Bool bModified )
+{
+ m_bModified = bModified;
+
+ if ( bModified && m_pInterfaceContainer )
+ {
+ comphelper::OInterfaceContainerHelper2* pContainer =
+ m_pInterfaceContainer->getContainer( cppu::UnoType<util::XModifyListener>::get());
+ if ( pContainer != nullptr )
+ {
+ comphelper::OInterfaceIteratorHelper2 pIterator( *pContainer );
+ while ( pIterator.hasMoreElements() )
+ {
+ try
+ {
+ lang::EventObject aEvent( static_cast<util::XModifiable*>(this) );
+ static_cast<util::XModifyListener*>(pIterator.next())->modified( aEvent );
+ }
+ catch( const uno::RuntimeException& )
+ {
+ pIterator.remove();
+ }
+ }
+ }
+ }
+}
+
+void SAL_CALL OleComponent::addModifyListener( const css::uno::Reference < css::util::XModifyListener >& xListener )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !m_pInterfaceContainer )
+ m_pInterfaceContainer = new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex );
+
+ m_pInterfaceContainer->addInterface( cppu::UnoType<util::XModifyListener>::get(), xListener );
+}
+
+void SAL_CALL OleComponent::removeModifyListener( const css::uno::Reference < css::util::XModifyListener >& xListener)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_pInterfaceContainer )
+ m_pInterfaceContainer->removeInterface( cppu::UnoType<util::XModifyListener>::get(),
+ xListener );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/olecomponent.hxx b/embeddedobj/source/msole/olecomponent.hxx
new file mode 100644
index 000000000..5a96b64fc
--- /dev/null
+++ b/embeddedobj/source/msole/olecomponent.hxx
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/embed/VerbDescriptor.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <rtl/ref.hxx>
+
+namespace comphelper {
+ class OMultiTypeInterfaceContainerHelper2;
+}
+
+class OleWrapperClientSite;
+class OleWrapperAdviseSink;
+class OleEmbeddedObject;
+struct OleComponentNative_Impl;
+
+class OleComponent : public ::cppu::WeakImplHelper< css::util::XCloseable, css::lang::XComponent,
+ css::lang::XUnoTunnel, css::util::XModifiable,
+ css::datatransfer::XTransferable >
+{
+ ::osl::Mutex m_aMutex;
+ comphelper::OMultiTypeInterfaceContainerHelper2* m_pInterfaceContainer;
+
+ bool m_bDisposed;
+ bool m_bModified;
+ OleComponentNative_Impl* m_pNativeImpl;
+
+ OleEmbeddedObject* m_pUnoOleObject;
+ OleWrapperClientSite* m_pOleWrapClientSite;
+ OleWrapperAdviseSink* m_pImplAdviseSink;
+
+ sal_Int32 m_nOLEMiscFlags;
+ sal_Int32 m_nAdvConn;
+
+ css::uno::Sequence< css::embed::VerbDescriptor > m_aVerbList;
+ css::uno::Sequence< css::datatransfer::DataFlavor > m_aDataFlavors;
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ bool m_bOleInitialized;
+
+ // specifies whether the workaround for some rare embedded objects is activated ( f.e. AcrobatReader 7.0.8 object )
+ // such objects report the dirty state wrongly sometimes and do not allow to store them any time
+ bool m_bWorkaroundActive;
+
+ bool InitializeObject_Impl();
+
+ void CreateNewIStorage_Impl();
+ void RetrieveObjectDataFlavors_Impl();
+ void Dispose();
+
+
+public:
+ OleComponent( const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ OleEmbeddedObject* pOleObj );
+
+ virtual ~OleComponent() override;
+
+ OleComponent* createEmbeddedCopyOfLink();
+
+ void disconnectEmbeddedObject();
+
+ static css::awt::Size CalculateWithFactor( const css::awt::Size& aSize,
+ const css::awt::Size& aMultiplier,
+ const css::awt::Size& aDivisor );
+
+ css::awt::Size CalculateTheRealSize( const css::awt::Size& aContSize, bool bUpdate );
+
+ // ==== Initialization ==================================================
+ void LoadEmbeddedObject( const OUString& aTempURL );
+ void CreateObjectFromClipboard();
+ void CreateNewEmbeddedObject( const css::uno::Sequence< sal_Int8 >& aSeqCLSID );
+ static void CreateObjectFromData(
+ const css::uno::Reference< css::datatransfer::XTransferable >& xTransfer );
+ void CreateObjectFromFile( const OUString& aFileName );
+ void CreateLinkFromFile( const OUString& aFileName );
+ void InitEmbeddedCopyOfLink( rtl::Reference<OleComponent> const & pOleLinkComponent );
+
+
+ void RunObject(); // switch OLE object to running state
+ void CloseObject(); // switch OLE object to loaded state
+
+ css::uno::Sequence< css::embed::VerbDescriptor > GetVerbList();
+
+ void ExecuteVerb( sal_Int32 nVerbID );
+ void SetHostName( const OUString& aEmbDocName );
+ void SetExtent( const css::awt::Size& aVisAreaSize, sal_Int64 nAspect );
+
+ css::awt::Size GetExtent( sal_Int64 nAspect );
+ css::awt::Size GetCachedExtent( sal_Int64 nAspect );
+ css::awt::Size GetRecommendedExtent( sal_Int64 nAspect );
+
+ sal_Int64 GetMiscStatus( sal_Int64 nAspect );
+
+ css::uno::Sequence< sal_Int8 > GetCLSID();
+
+ bool IsWorkaroundActive() const { return m_bWorkaroundActive; }
+ bool IsDirty();
+
+ void StoreOwnTmpIfNecessary();
+
+ bool SaveObject_Impl();
+ bool OnShowWindow_Impl( bool bShow );
+ void OnViewChange_Impl( sal_uInt32 dwAspect );
+ void OnClose_Impl();
+
+ // XCloseable
+ virtual void SAL_CALL close( sal_Bool DeliverOwnership ) override;
+ virtual void SAL_CALL addCloseListener( const css::uno::Reference< css::util::XCloseListener >& Listener ) override;
+ virtual void SAL_CALL removeCloseListener( const css::uno::Reference< css::util::XCloseListener >& Listener ) override;
+
+ // XTransferable
+ virtual css::uno::Any SAL_CALL getTransferData( const css::datatransfer::DataFlavor& aFlavor ) override;
+ virtual css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) override;
+ virtual sal_Bool SAL_CALL isDataFlavorSupported( const css::datatransfer::DataFlavor& aFlavor ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+ virtual void SAL_CALL addEventListener(const css::uno::Reference < css::lang::XEventListener >& aListener) override;
+ virtual void SAL_CALL removeEventListener(const css::uno::Reference < css::lang::XEventListener >& aListener) override;
+
+ // XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+
+ // XModifiable
+ virtual sal_Bool SAL_CALL isModified() override;
+ virtual void SAL_CALL setModified( sal_Bool bModified ) override;
+ virtual void SAL_CALL addModifyListener( const css::uno::Reference < css::util::XModifyListener >& xListener ) override;
+ virtual void SAL_CALL removeModifyListener( const css::uno::Reference < css::util::XModifyListener >& xListener) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/oleembed.cxx b/embeddedobj/source/msole/oleembed.cxx
new file mode 100644
index 000000000..6a3f4e926
--- /dev/null
+++ b/embeddedobj/source/msole/oleembed.cxx
@@ -0,0 +1,1179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <oleembobj.hxx>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/EmbedVerbs.hpp>
+#include <com/sun/star/embed/UnreachableStateException.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/EmbedUpdateModes.hpp>
+#include <com/sun/star/embed/NeedsRunningStateException.hpp>
+#include <com/sun/star/embed/StateChangeInProgressException.hpp>
+#include <com/sun/star/embed/EmbedMisc.hpp>
+#include <com/sun/star/embed/XEmbedObjectCreator.hpp>
+#include <com/sun/star/io/TempFile.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XLoadable.hpp>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/system/SystemShellExecute.hpp>
+#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <comphelper/multicontainer2.hxx>
+#include <comphelper/mimeconfighelper.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+
+
+#include <targetstatecontrol.hxx>
+
+#include "ownview.hxx"
+
+#if defined(_WIN32)
+#include "olecomponent.hxx"
+#endif
+
+using namespace ::com::sun::star;
+
+#ifdef _WIN32
+
+void OleEmbeddedObject::SwitchComponentToRunningState_Impl()
+{
+ if ( !m_pOleComponent )
+ {
+ throw embed::UnreachableStateException();
+ }
+ try
+ {
+ m_pOleComponent->RunObject();
+ }
+ catch( const embed::UnreachableStateException& )
+ {
+ GetRidOfComponent();
+ throw;
+ }
+ catch( const embed::WrongStateException& )
+ {
+ GetRidOfComponent();
+ throw;
+ }
+}
+
+
+uno::Sequence< sal_Int32 > OleEmbeddedObject::GetReachableStatesList_Impl(
+ const uno::Sequence< embed::VerbDescriptor >& aVerbList )
+{
+ uno::Sequence< sal_Int32 > aStates { embed::EmbedStates::LOADED, embed::EmbedStates::RUNNING };
+ for ( embed::VerbDescriptor const & vd : aVerbList )
+ if ( vd.VerbID == embed::EmbedVerbs::MS_OLEVERB_OPEN )
+ {
+ aStates.realloc(3);
+ aStates.getArray()[2] = embed::EmbedStates::ACTIVE;
+ break;
+ }
+
+ return aStates;
+}
+
+
+uno::Sequence< sal_Int32 > OleEmbeddedObject::GetIntermediateVerbsSequence_Impl( sal_Int32 nNewState )
+{
+ SAL_WARN_IF( m_nObjectState == embed::EmbedStates::LOADED, "embeddedobj.ole", "Loaded object is switched to running state without verbs using!" );
+
+ // actually there will be only one verb
+ if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
+ {
+ return { embed::EmbedVerbs::MS_OLEVERB_OPEN };
+ }
+
+ return uno::Sequence< sal_Int32 >();
+}
+#endif
+
+void OleEmbeddedObject::MoveListeners()
+{
+ if ( !m_pInterfaceContainer )
+ return;
+
+ // move state change listeners
+ {
+ comphelper::OInterfaceContainerHelper2* pStateChangeContainer =
+ m_pInterfaceContainer->getContainer( cppu::UnoType<embed::XStateChangeListener>::get());
+ if ( pStateChangeContainer != nullptr )
+ {
+ if ( m_xWrappedObject.is() )
+ {
+ comphelper::OInterfaceIteratorHelper2 pIterator( *pStateChangeContainer );
+ while ( pIterator.hasMoreElements() )
+ {
+ try
+ {
+ m_xWrappedObject->addStateChangeListener( static_cast<embed::XStateChangeListener*>(pIterator.next()) );
+ }
+ catch( const uno::RuntimeException& )
+ {
+ pIterator.remove();
+ }
+ }
+ }
+ }
+ }
+
+ // move event listeners
+ {
+ comphelper::OInterfaceContainerHelper2* pEventContainer =
+ m_pInterfaceContainer->getContainer( cppu::UnoType<document::XEventListener>::get());
+ if ( pEventContainer != nullptr )
+ {
+ if ( m_xWrappedObject.is() )
+ {
+ comphelper::OInterfaceIteratorHelper2 pIterator( *pEventContainer );
+ while ( pIterator.hasMoreElements() )
+ {
+ try
+ {
+ m_xWrappedObject->addEventListener( static_cast<document::XEventListener*>(pIterator.next()) );
+ }
+ catch( const uno::RuntimeException& )
+ {
+ pIterator.remove();
+ }
+ }
+ }
+ }
+ }
+
+ // move close listeners
+ {
+ comphelper::OInterfaceContainerHelper2* pCloseContainer =
+ m_pInterfaceContainer->getContainer( cppu::UnoType<util::XCloseListener>::get());
+ if ( pCloseContainer != nullptr )
+ {
+ if ( m_xWrappedObject.is() )
+ {
+ comphelper::OInterfaceIteratorHelper2 pIterator( *pCloseContainer );
+ while ( pIterator.hasMoreElements() )
+ {
+ try
+ {
+ m_xWrappedObject->addCloseListener( static_cast<util::XCloseListener*>(pIterator.next()) );
+ }
+ catch( const uno::RuntimeException& )
+ {
+ pIterator.remove();
+ }
+ }
+ }
+ }
+ }
+
+ m_pInterfaceContainer.reset();
+}
+
+
+uno::Reference< embed::XStorage > OleEmbeddedObject::CreateTemporarySubstorage( OUString& o_aStorageName )
+{
+ uno::Reference< embed::XStorage > xResult;
+
+ for ( sal_Int32 nInd = 0; nInd < 32000 && !xResult.is(); nInd++ )
+ {
+ OUString aName = OUString::number( nInd ) + "TMPSTOR" + m_aEntryName;
+ if ( !m_xParentStorage->hasByName( aName ) )
+ {
+ xResult = m_xParentStorage->openStorageElement( aName, embed::ElementModes::READWRITE );
+ o_aStorageName = aName;
+ }
+ }
+
+ if ( !xResult.is() )
+ {
+ o_aStorageName.clear();
+ throw uno::RuntimeException();
+ }
+
+ return xResult;
+}
+
+
+OUString OleEmbeddedObject::MoveToTemporarySubstream()
+{
+ OUString aResult;
+ for ( sal_Int32 nInd = 0; nInd < 32000 && aResult.isEmpty(); nInd++ )
+ {
+ OUString aName = OUString::number( nInd ) + "TMPSTREAM" + m_aEntryName;
+ if ( !m_xParentStorage->hasByName( aName ) )
+ {
+ m_xParentStorage->renameElement( m_aEntryName, aName );
+ aResult = aName;
+ }
+ }
+
+ if ( aResult.isEmpty() )
+ throw uno::RuntimeException();
+
+ return aResult;
+}
+
+
+bool OleEmbeddedObject::TryToConvertToOOo( const uno::Reference< io::XStream >& xStream )
+{
+ bool bResult = false;
+
+ OUString aStorageName;
+ OUString aTmpStreamName;
+ sal_Int32 nStep = 0;
+
+ if ( m_pOleComponent || m_bReadOnly )
+ return false;
+
+ try
+ {
+ changeState( embed::EmbedStates::LOADED );
+
+ // the stream must be seekable
+ uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY_THROW );
+ xSeekable->seek( 0 );
+ m_aFilterName = OwnView_Impl::GetFilterNameFromExtentionAndInStream( m_xContext, std::u16string_view(), xStream->getInputStream() );
+
+ if ( !m_aFilterName.isEmpty()
+ && ( m_aFilterName == "Calc MS Excel 2007 XML" || m_aFilterName == "Impress MS PowerPoint 2007 XML" || m_aFilterName == "MS Word 2007 XML"
+ || m_aFilterName == "MS Excel 97 Vorlage/Template" || m_aFilterName == "MS Word 97 Vorlage" ) )
+ {
+ uno::Reference< container::XNameAccess > xFilterFactory(
+ m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", m_xContext),
+ uno::UNO_QUERY_THROW );
+
+ OUString aDocServiceName;
+ uno::Any aFilterAnyData = xFilterFactory->getByName( m_aFilterName );
+ uno::Sequence< beans::PropertyValue > aFilterData;
+ if ( aFilterAnyData >>= aFilterData )
+ {
+ for ( beans::PropertyValue const & prop : std::as_const(aFilterData) )
+ if ( prop.Name == "DocumentService" )
+ prop.Value >>= aDocServiceName;
+ }
+
+ if ( !aDocServiceName.isEmpty() )
+ {
+ // create the model
+ uno::Sequence< uno::Any > aArguments{ uno::Any(
+ beans::NamedValue( "EmbeddedObject", uno::Any( true ))) };
+
+ uno::Reference< util::XCloseable > xDocument( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( aDocServiceName, aArguments, m_xContext ), uno::UNO_QUERY_THROW );
+ uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
+ uno::Reference< document::XStorageBasedDocument > xStorDoc( xDocument, uno::UNO_QUERY_THROW );
+
+ // let the model behave as embedded one
+ uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY_THROW );
+ uno::Sequence< beans::PropertyValue > aSeq{ comphelper::makePropertyValue(
+ "SetEmbedded", true) };
+ xModel->attachResource( OUString(), aSeq );
+
+ // load the model from the stream
+ uno::Sequence< beans::PropertyValue > aArgs{
+ comphelper::makePropertyValue("HierarchicalDocumentName", m_aEntryName),
+ comphelper::makePropertyValue("ReadOnly", true),
+ comphelper::makePropertyValue("FilterName", m_aFilterName),
+ comphelper::makePropertyValue("URL", OUString( "private:stream" )),
+ comphelper::makePropertyValue("InputStream", xStream->getInputStream())
+ };
+
+ xSeekable->seek( 0 );
+ xLoadable->load( aArgs );
+
+ // the model is successfully loaded, create a new storage and store the model to the storage
+ uno::Reference< embed::XStorage > xTmpStorage = CreateTemporarySubstorage( aStorageName );
+ xStorDoc->storeToStorage( xTmpStorage, uno::Sequence< beans::PropertyValue >() );
+ xDocument->close( true );
+ uno::Reference< beans::XPropertySet > xStorProps( xTmpStorage, uno::UNO_QUERY_THROW );
+ OUString aMediaType;
+ xStorProps->getPropertyValue("MediaType") >>= aMediaType;
+ xTmpStorage->dispose();
+
+ // look for the related embedded object factory
+ ::comphelper::MimeConfigurationHelper aConfigHelper( m_xContext );
+ OUString aEmbedFactory;
+ if ( !aMediaType.isEmpty() )
+ aEmbedFactory = aConfigHelper.GetFactoryNameByMediaType( aMediaType );
+
+ if ( aEmbedFactory.isEmpty() )
+ throw uno::RuntimeException();
+
+ uno::Reference< uno::XInterface > xFact = m_xContext->getServiceManager()->createInstanceWithContext( aEmbedFactory, m_xContext );
+
+ uno::Reference< embed::XEmbedObjectCreator > xEmbCreator( xFact, uno::UNO_QUERY_THROW );
+
+ // now the object should be adjusted to become the wrapper
+ nStep = 1;
+ uno::Reference< lang::XComponent > xComp( m_xObjectStream, uno::UNO_QUERY_THROW );
+ xComp->dispose();
+ m_xObjectStream.clear();
+ m_nObjectState = -1;
+
+ nStep = 2;
+ aTmpStreamName = MoveToTemporarySubstream();
+
+ nStep = 3;
+ m_xParentStorage->renameElement( aStorageName, m_aEntryName );
+
+ nStep = 4;
+ m_xWrappedObject.set( xEmbCreator->createInstanceInitFromEntry( m_xParentStorage, m_aEntryName, uno::Sequence< beans::PropertyValue >(), uno::Sequence< beans::PropertyValue >() ), uno::UNO_QUERY_THROW );
+
+ // remember parent document name to show in the title bar
+ m_xWrappedObject->setContainerName( m_aContainerName );
+
+ bResult = true; // the change is no more revertable
+ try
+ {
+ m_xParentStorage->removeElement( aTmpStreamName );
+ }
+ catch( const uno::Exception& )
+ {
+ // the success of the removing is not so important
+ }
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ // repair the object if necessary
+ switch( nStep )
+ {
+ case 4:
+ case 3:
+ if ( !aTmpStreamName.isEmpty() && aTmpStreamName != m_aEntryName )
+ try
+ {
+ if ( m_xParentStorage->hasByName( m_aEntryName ) )
+ m_xParentStorage->removeElement( m_aEntryName );
+ m_xParentStorage->renameElement( aTmpStreamName, m_aEntryName );
+ }
+ catch ( const uno::Exception& ex )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ try {
+ close( true );
+ } catch( const uno::Exception& ) {}
+
+ m_xParentStorage->dispose(); // ??? the storage has information loss, it should be closed without committing!
+ throw css::lang::WrappedTargetRuntimeException( ex.Message,
+ nullptr, anyEx ); // the repairing is not possible
+ }
+ [[fallthrough]];
+ case 2:
+ try
+ {
+ m_xObjectStream = m_xParentStorage->openStreamElement( m_aEntryName, m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE );
+ m_nObjectState = embed::EmbedStates::LOADED;
+ }
+ catch( const uno::Exception& ex )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ try {
+ close( true );
+ } catch( const uno::Exception& ) {}
+
+ throw css::lang::WrappedTargetRuntimeException( ex.Message,
+ nullptr, anyEx ); // the repairing is not possible
+ }
+ [[fallthrough]];
+
+ case 1:
+ case 0:
+ if ( !aStorageName.isEmpty() )
+ try {
+ m_xParentStorage->removeElement( aStorageName );
+ } catch( const uno::Exception& ) { SAL_WARN( "embeddedobj.ole", "Can not remove temporary storage!" ); }
+ break;
+ }
+ }
+
+ if ( bResult )
+ {
+ // the conversion was done successfully, now the additional initializations should happen
+
+ MoveListeners();
+ m_xWrappedObject->setClientSite( m_xClientSite );
+ if ( m_xParent.is() )
+ {
+ uno::Reference< container::XChild > xChild( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xChild.is() )
+ xChild->setParent( m_xParent );
+ }
+
+ }
+
+ return bResult;
+}
+
+
+void SAL_CALL OleEmbeddedObject::changeState( sal_Int32 nNewState )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->changeState( nNewState );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::ResettableMutexGuard aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object has no persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ // in case the object is already in requested state
+ if ( m_nObjectState == nNewState )
+ return;
+
+#ifdef _WIN32
+ if ( m_pOleComponent )
+ {
+ if ( m_nTargetState != -1 )
+ {
+ // means that the object is currently trying to reach the target state
+ throw embed::StateChangeInProgressException( OUString(),
+ uno::Reference< uno::XInterface >(),
+ m_nTargetState );
+ }
+
+ TargetStateControl_Impl aControl( m_nTargetState, nNewState );
+
+ // TODO: additional verbs can be a problem, since nobody knows how the object
+ // will behave after activation
+
+ sal_Int32 nOldState = m_nObjectState;
+ aGuard.clear();
+ StateChangeNotification_Impl( true, nOldState, nNewState );
+ aGuard.reset();
+
+ try
+ {
+ if ( nNewState == embed::EmbedStates::LOADED )
+ {
+ // This means just closing of the current object
+ // If component can not be closed the object stays in loaded state
+ // and it holds reference to "incomplete" component
+ // If the object is switched to running state later
+ // the component will become "complete"
+
+ // the loaded state must be set before, because of notifications!
+ m_nObjectState = nNewState;
+
+ {
+ VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
+ m_pOleComponent->CloseObject();
+ }
+
+ aGuard.clear();
+ StateChangeNotification_Impl( false, nOldState, m_nObjectState );
+ aGuard.reset();
+ }
+ else if ( nNewState == embed::EmbedStates::RUNNING || nNewState == embed::EmbedStates::ACTIVE )
+ {
+ if ( m_nObjectState == embed::EmbedStates::LOADED )
+ {
+ // if the target object is in loaded state and a different state is specified
+ // as a new one the object first must be switched to running state.
+
+ // the component can exist already in nonrunning state
+ // it can be created during loading to detect type of object
+ CreateOleComponentAndLoad_Impl( m_pOleComponent );
+
+ SwitchComponentToRunningState_Impl();
+ m_nObjectState = embed::EmbedStates::RUNNING;
+ aGuard.clear();
+ StateChangeNotification_Impl( false, nOldState, m_nObjectState );
+ aGuard.reset();
+
+ if ( m_pOleComponent && m_bHasSizeToSet )
+ {
+ aGuard.clear();
+ try {
+ m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
+ m_bHasSizeToSet = false;
+ }
+ catch( const uno::Exception& ) {}
+ aGuard.reset();
+ }
+
+ if ( m_nObjectState == nNewState )
+ return;
+ }
+
+ // so now the object is either switched from Active to Running state or viceversa
+ // the notification about object state change will be done asynchronously
+ if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
+ {
+ // execute OPEN verb, if object does not reach active state it is an object's problem
+ aGuard.clear();
+ m_pOleComponent->ExecuteVerb( embed::EmbedVerbs::MS_OLEVERB_OPEN );
+ aGuard.reset();
+
+ // some objects do not allow to set the size even in running state
+ if ( m_pOleComponent && m_bHasSizeToSet )
+ {
+ aGuard.clear();
+ try {
+ m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
+ m_bHasSizeToSet = false;
+ }
+ catch( uno::Exception& ) {}
+ aGuard.reset();
+ }
+
+ m_nObjectState = nNewState;
+ }
+ else if ( m_nObjectState == embed::EmbedStates::ACTIVE && nNewState == embed::EmbedStates::RUNNING )
+ {
+ aGuard.clear();
+ m_pOleComponent->CloseObject();
+ m_pOleComponent->RunObject(); // Should not fail, the object already was active
+ aGuard.reset();
+ m_nObjectState = nNewState;
+ }
+ else
+ {
+ throw embed::UnreachableStateException();
+ }
+ }
+ else
+ throw embed::UnreachableStateException();
+ }
+ catch( uno::Exception& )
+ {
+ aGuard.clear();
+ StateChangeNotification_Impl( false, nOldState, m_nObjectState );
+ throw;
+ }
+ }
+ else
+#endif
+ {
+ throw embed::UnreachableStateException();
+ }
+}
+
+
+uno::Sequence< sal_Int32 > SAL_CALL OleEmbeddedObject::getReachableStates()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getReachableStates();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object has no persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+#ifdef _WIN32
+ if ( m_pOleComponent )
+ {
+ if ( m_nObjectState == embed::EmbedStates::LOADED )
+ {
+ // the list of supported verbs can be retrieved only when object is in running state
+ throw embed::NeedsRunningStateException(); // TODO:
+ }
+
+ // the list of states can only be guessed based on standard verbs,
+ // since there is no way to detect what additional verbs do
+ return GetReachableStatesList_Impl( m_pOleComponent->GetVerbList() );
+ }
+ else
+#endif
+ {
+ return uno::Sequence< sal_Int32 >();
+ }
+}
+
+
+sal_Int32 SAL_CALL OleEmbeddedObject::getCurrentState()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getCurrentState();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object has no persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ // TODO: Shouldn't we ask object? ( I guess no )
+ return m_nObjectState;
+}
+
+namespace
+{
+ bool lcl_CopyStream(const uno::Reference<io::XInputStream>& xIn, const uno::Reference<io::XOutputStream>& xOut, sal_Int32 nMaxCopy = SAL_MAX_INT32)
+ {
+ if (nMaxCopy <= 0)
+ return false;
+
+ const sal_Int32 nChunkSize = 4096;
+ uno::Sequence< sal_Int8 > aData(nChunkSize);
+ sal_Int32 nTotalRead = 0;
+ sal_Int32 nRead;
+ do
+ {
+ if (nTotalRead + aData.getLength() > nMaxCopy)
+ {
+ aData.realloc(nMaxCopy - nTotalRead);
+ }
+ nRead = xIn->readBytes(aData, aData.getLength());
+ nTotalRead += nRead;
+ xOut->writeBytes(aData);
+ } while (nRead == nChunkSize && nTotalRead <= nMaxCopy);
+ return nTotalRead != 0;
+ }
+
+ uno::Reference < io::XStream > lcl_GetExtractedStream( OUString& rUrl,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::io::XStream >& xObjectStream )
+ {
+ uno::Reference <io::XTempFile> xNativeTempFile(
+ io::TempFile::create(xContext),
+ uno::UNO_SET_THROW);
+ uno::Reference < io::XStream > xStream(xNativeTempFile);
+
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xObjectStream),
+ uno::Any(true) }; // do not create copy
+ uno::Reference< container::XNameContainer > xNameContainer(
+ xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.embed.OLESimpleStorage",
+ aArgs, xContext ), uno::UNO_QUERY_THROW );
+
+ //various stream names that can contain the real document contents for
+ //this object in a straightforward direct way
+ static const std::u16string_view aStreamNames[] =
+ {
+ u"CONTENTS",
+ u"Package",
+ u"EmbeddedOdf",
+ u"WordDocument",
+ u"Workbook",
+ u"PowerPoint Document"
+ };
+
+ bool bCopied = false;
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aStreamNames) && !bCopied; ++i)
+ {
+ uno::Reference<io::XStream> xEmbeddedFile;
+ try
+ {
+ xNameContainer->getByName(OUString(aStreamNames[i])) >>= xEmbeddedFile;
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ // ignore
+ }
+ bCopied = xEmbeddedFile.is() && lcl_CopyStream(xEmbeddedFile->getInputStream(), xStream->getOutputStream());
+ }
+
+ if (!bCopied)
+ {
+ uno::Reference< io::XStream > xOle10Native;
+ try
+ {
+ xNameContainer->getByName("\1Ole10Native") >>= xOle10Native;
+ }
+ catch (container::NoSuchElementException const&)
+ {
+ // ignore
+ }
+ if (xOle10Native.is())
+ {
+ const uno::Reference<io::XInputStream> xIn = xOle10Native->getInputStream();
+ xIn->skipBytes(4); //size of the entire stream minus 4 bytes
+ xIn->skipBytes(2); //word that represent the directory type
+ uno::Sequence< sal_Int8 > aData(1);
+ sal_Int32 nRead;
+ do
+ {
+ nRead = xIn->readBytes(aData, 1);
+ } while (nRead == 1 && aData[0] != 0); // file name plus extension of the attachment null terminated
+ do
+ {
+ nRead = xIn->readBytes(aData, 1);
+ } while (nRead == 1 && aData[0] != 0); // Fully Qualified File name with extension
+ xIn->skipBytes(1); //single byte
+ xIn->skipBytes(1); //single byte
+ xIn->skipBytes(2); //Word that represent the directory type
+ xIn->skipBytes(4); //len of string
+ do
+ {
+ nRead = xIn->readBytes(aData, 1);
+ } while (nRead == 1 && aData[0] != 0); // Actual string representing the file path
+ uno::Sequence< sal_Int8 > aLenData(4);
+ xIn->readBytes(aLenData, 4); //len of attachment
+ sal_uInt32 nLen = static_cast<sal_uInt32>(
+ (aLenData[0] & 0xFF) |
+ ((aLenData[1] & 0xFF) << 8) |
+ ((aLenData[2] & 0xFF) << 16) |
+ ((aLenData[3] & 0xFF) << 24));
+
+ bCopied = lcl_CopyStream(xIn, xStream->getOutputStream(), nLen);
+ }
+ }
+
+ uno::Reference< io::XSeekable > xSeekableStor(xObjectStream, uno::UNO_QUERY);
+ if (xSeekableStor.is())
+ xSeekableStor->seek(0);
+
+ if (!bCopied)
+ bCopied = lcl_CopyStream(xObjectStream->getInputStream(), xStream->getOutputStream());
+
+ if (bCopied)
+ {
+ xNativeTempFile->setRemoveFile(false);
+ rUrl = xNativeTempFile->getUri();
+
+ xNativeTempFile.clear();
+
+ uno::Reference < ucb::XSimpleFileAccess3 > xSimpleFileAccess(
+ ucb::SimpleFileAccess::create( xContext ) );
+
+ xSimpleFileAccess->setReadOnly(rUrl, true);
+ }
+ else
+ {
+ xNativeTempFile->setRemoveFile(true);
+ }
+
+ return xStream;
+ }
+
+ //Dump the objects content to a tempfile, just the "CONTENTS" stream if
+ //there is one for non-compound documents, otherwise the whole content.
+ //On success a file is returned which must be removed by the caller
+ OUString lcl_ExtractObject(const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::io::XStream >& xObjectStream)
+ {
+ OUString sUrl;
+
+ // the solution is only active for Unix systems
+#ifndef _WIN32
+ lcl_GetExtractedStream(sUrl, xContext, xObjectStream);
+#else
+ (void) xContext;
+ (void) xObjectStream;
+#endif
+ return sUrl;
+ }
+
+ uno::Reference < io::XStream > lcl_ExtractObjectStream( const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::io::XStream >& xObjectStream )
+ {
+ OUString sUrl;
+ return lcl_GetExtractedStream( sUrl, xContext, xObjectStream );
+ }
+}
+
+
+void SAL_CALL OleEmbeddedObject::doVerb( sal_Int32 nVerbID )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->doVerb(embed::EmbedVerbs::MS_OLEVERB_OPEN); // open content in the window not in-place
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::ResettableMutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object has no persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+#ifdef _WIN32
+ if ( m_pOleComponent )
+ {
+ sal_Int32 nOldState = m_nObjectState;
+
+ // TODO/LATER detect target state here and do a notification
+ // StateChangeNotification_Impl( sal_True, nOldState, nNewState );
+ if ( m_nObjectState == embed::EmbedStates::LOADED )
+ {
+ // if the target object is in loaded state
+ // it must be switched to running state to execute verb
+ aGuard.clear();
+ changeState( embed::EmbedStates::RUNNING );
+ aGuard.reset();
+ }
+
+ try {
+ if ( !m_pOleComponent )
+ throw uno::RuntimeException();
+
+ // ==== the STAMPIT related solution =============================
+ m_aVerbExecutionController.StartControlExecution();
+
+
+ m_pOleComponent->ExecuteVerb( nVerbID );
+ m_pOleComponent->SetHostName( m_aContainerName );
+
+ // ==== the STAMPIT related solution =============================
+ bool bModifiedOnExecution = m_aVerbExecutionController.EndControlExecution_WasModified();
+
+ // this workaround is implemented for STAMPIT object
+ // if object was modified during verb execution it is saved here
+ if ( bModifiedOnExecution && m_pOleComponent->IsDirty() )
+ SaveObject_Impl();
+
+ }
+ catch( uno::Exception& )
+ {
+ // ==== the STAMPIT related solution =============================
+ m_aVerbExecutionController.EndControlExecution_WasModified();
+
+
+ aGuard.clear();
+ StateChangeNotification_Impl( false, nOldState, m_nObjectState );
+ throw;
+ }
+
+ }
+ else
+#endif
+ {
+ if ( nVerbID != -9 )
+ {
+
+ throw embed::UnreachableStateException();
+ }
+
+ // the workaround verb to show the object in case no server is available
+
+ // if it is possible, the object will be converted to OOo format
+ if ( !m_bTriedConversion )
+ {
+ m_bTriedConversion = true;
+ if ( TryToConvertToOOo( m_xObjectStream ) )
+ {
+ changeState( embed::EmbedStates::ACTIVE );
+ return;
+ }
+ }
+
+ if ( !m_xOwnView.is() && m_xObjectStream.is() && m_aFilterName != "Text" )
+ {
+ try {
+ uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY );
+ if ( xSeekable.is() )
+ xSeekable->seek( 0 );
+
+ m_xOwnView = new OwnView_Impl( m_xContext, m_xObjectStream->getInputStream() );
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OleEmbeddedObject::doVerb: -9 fallback path:");
+ }
+ }
+
+ // it may be the OLE Storage, try to extract stream
+ if ( !m_xOwnView.is() && m_xObjectStream.is() && m_aFilterName == "Text" )
+ {
+ uno::Reference< io::XStream > xStream = lcl_ExtractObjectStream( m_xContext, m_xObjectStream );
+
+ if ( TryToConvertToOOo( xStream ) )
+ {
+ changeState( embed::EmbedStates::ACTIVE );
+ return;
+ }
+ }
+
+ if (!m_xOwnView.is() || !m_xOwnView->Open())
+ {
+ //Make a RO copy and see if the OS can find something to at
+ //least display the content for us
+ if (m_aTempDumpURL.isEmpty())
+ m_aTempDumpURL = lcl_ExtractObject(m_xContext, m_xObjectStream);
+
+ if (m_aTempDumpURL.isEmpty())
+ throw embed::UnreachableStateException();
+
+ uno::Reference< css::system::XSystemShellExecute > xSystemShellExecute(
+ css::system::SystemShellExecute::create( m_xContext ) );
+ xSystemShellExecute->execute(m_aTempDumpURL, OUString(), css::system::SystemShellExecuteFlags::URIS_ONLY);
+
+ }
+
+ }
+}
+
+
+uno::Sequence< embed::VerbDescriptor > SAL_CALL OleEmbeddedObject::getSupportedVerbs()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getSupportedVerbs();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object has no persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+#ifdef _WIN32
+ if ( m_pOleComponent )
+ {
+ // registry could be used in this case
+ // if ( m_nObjectState == embed::EmbedStates::LOADED )
+ // {
+ // // the list of supported verbs can be retrieved only when object is in running state
+ // throw embed::NeedsRunningStateException(); // TODO:
+ // }
+
+ return m_pOleComponent->GetVerbList();
+ }
+ else
+#endif
+ {
+ // tdf#140079 Claim support for the OleEmbeddedObject::doVerb -9 fallback.
+ // So in SfxViewFrame::GetState_Impl in case SID_OBJECT hasVerbs is not
+ // empty, so that the doVerb attempt with -9 fallback is attempted
+ uno::Sequence<embed::VerbDescriptor> aRet(1);
+ aRet.getArray()[0].VerbID = -9;
+ return aRet;
+ }
+}
+
+
+void SAL_CALL OleEmbeddedObject::setClientSite(
+ const uno::Reference< embed::XEmbeddedClient >& xClient )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->setClientSite( xClient );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_xClientSite != xClient)
+ {
+ if ( m_nObjectState != embed::EmbedStates::LOADED && m_nObjectState != embed::EmbedStates::RUNNING )
+ throw embed::WrongStateException(
+ "The client site can not be set currently!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ m_xClientSite = xClient;
+ }
+}
+
+
+uno::Reference< embed::XEmbeddedClient > SAL_CALL OleEmbeddedObject::getClientSite()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getClientSite();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object has no persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ return m_xClientSite;
+}
+
+
+void SAL_CALL OleEmbeddedObject::update()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->update();
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object has no persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ if ( m_nUpdateMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE )
+ {
+ // TODO: update view representation
+ }
+ else
+ {
+ // the object must be up to date
+ SAL_WARN_IF( m_nUpdateMode != embed::EmbedUpdateModes::ALWAYS_UPDATE, "embeddedobj.ole", "Unknown update mode!" );
+ }
+}
+
+
+void SAL_CALL OleEmbeddedObject::setUpdateMode( sal_Int32 nMode )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->setUpdateMode( nMode );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object has no persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ OSL_ENSURE( nMode == embed::EmbedUpdateModes::ALWAYS_UPDATE
+ || nMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE,
+ "Unknown update mode!" );
+ m_nUpdateMode = nMode;
+}
+
+
+sal_Int64 SAL_CALL OleEmbeddedObject::getStatus( sal_Int64
+ nAspect
+)
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getStatus( nAspect );
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object must be in running state!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ sal_Int64 nResult = 0;
+
+#ifdef _WIN32
+ if ( m_bGotStatus && m_nStatusAspect == nAspect )
+ nResult = m_nStatus;
+ else if ( m_pOleComponent )
+ {
+
+ m_nStatus = m_pOleComponent->GetMiscStatus( nAspect );
+ m_nStatusAspect = nAspect;
+ m_bGotStatus = true;
+ nResult = m_nStatus;
+ }
+#endif
+
+ // this implementation needs size to be provided after object loading/creating to work in optimal way
+ return ( nResult | embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD );
+}
+
+
+void SAL_CALL OleEmbeddedObject::setContainerName( const OUString& sName )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->setContainerName( sName );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ m_aContainerName = sName;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/olemisc.cxx b/embeddedobj/source/msole/olemisc.cxx
new file mode 100644
index 000000000..e1007fbb1
--- /dev/null
+++ b/embeddedobj/source/msole/olemisc.cxx
@@ -0,0 +1,700 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <com/sun/star/embed/EmbedUpdateModes.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/WrongStateException.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+
+#include <comphelper/multicontainer2.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <osl/diagnose.h>
+
+#include <oleembobj.hxx>
+#include "olepersist.hxx"
+
+#include "ownview.hxx"
+
+#include "olecomponent.hxx"
+
+using namespace ::com::sun::star;
+
+
+OleEmbeddedObject::OleEmbeddedObject( const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Sequence< sal_Int8 >& aClassID,
+ const OUString& aClassName )
+: m_bReadOnly( false )
+, m_bDisposed( false )
+, m_nObjectState( -1 )
+, m_nTargetState( -1 )
+, m_nUpdateMode ( embed::EmbedUpdateModes::ALWAYS_UPDATE )
+, m_xContext( xContext )
+, m_aClassID( aClassID )
+, m_aClassName( aClassName )
+, m_bWaitSaveCompleted( false )
+, m_bNewVisReplInStream( true )
+, m_bStoreLoaded( false )
+, m_bVisReplInitialized( false )
+, m_bVisReplInStream( false )
+, m_bStoreVisRepl( false )
+, m_bIsLink( false )
+, m_bHasCachedSize( false )
+, m_nCachedAspect( 0 )
+, m_bHasSizeToSet( false )
+, m_nAspectToSet( 0 )
+, m_bGotStatus( false )
+, m_nStatus( 0 )
+, m_nStatusAspect( 0 )
+, m_bFromClipboard( false )
+, m_bTriedConversion( false )
+{
+}
+
+
+// In case of loading from persistent entry the classID of the object
+// will be retrieved from the entry, during construction it is unknown
+OleEmbeddedObject::OleEmbeddedObject( const uno::Reference< uno::XComponentContext >& xContext, bool bLink )
+: m_bReadOnly( false )
+, m_bDisposed( false )
+, m_nObjectState( -1 )
+, m_nTargetState( -1 )
+, m_nUpdateMode( embed::EmbedUpdateModes::ALWAYS_UPDATE )
+, m_xContext( xContext )
+, m_bWaitSaveCompleted( false )
+, m_bNewVisReplInStream( true )
+, m_bStoreLoaded( false )
+, m_bVisReplInitialized( false )
+, m_bVisReplInStream( false )
+, m_bStoreVisRepl( false )
+, m_bIsLink( bLink )
+, m_bHasCachedSize( false )
+, m_nCachedAspect( 0 )
+, m_bHasSizeToSet( false )
+, m_nAspectToSet( 0 )
+, m_bGotStatus( false )
+, m_nStatus( 0 )
+, m_nStatusAspect( 0 )
+, m_bFromClipboard( false )
+, m_bTriedConversion( false )
+{
+}
+#ifdef _WIN32
+
+// this constructor let object be initialized from clipboard
+OleEmbeddedObject::OleEmbeddedObject( const uno::Reference< uno::XComponentContext >& xContext )
+: m_bReadOnly( false )
+, m_bDisposed( false )
+, m_nObjectState( -1 )
+, m_nTargetState( -1 )
+, m_nUpdateMode( embed::EmbedUpdateModes::ALWAYS_UPDATE )
+, m_xContext( xContext )
+, m_bWaitSaveCompleted( false )
+, m_bNewVisReplInStream( true )
+, m_bStoreLoaded( false )
+, m_bVisReplInitialized( false )
+, m_bVisReplInStream( false )
+, m_bStoreVisRepl( false )
+, m_bIsLink( false )
+, m_bHasCachedSize( false )
+, m_nCachedAspect( 0 )
+, m_bHasSizeToSet( false )
+, m_nAspectToSet( 0 )
+, m_bGotStatus( false )
+, m_nStatus( 0 )
+, m_nStatusAspect( 0 )
+, m_bFromClipboard( true )
+, m_bTriedConversion( false )
+{
+}
+#endif
+
+OleEmbeddedObject::~OleEmbeddedObject()
+{
+ OSL_ENSURE( !m_pInterfaceContainer && !m_pOleComponent && !m_xObjectStream.is(),
+ "The object is not closed! DISASTER is possible!" );
+
+ if ( m_pOleComponent || m_pInterfaceContainer || m_xObjectStream.is() )
+ {
+ // the component must be cleaned during closing
+ osl_atomic_increment(&m_refCount); // to avoid crash
+ try {
+ Dispose();
+ } catch( const uno::Exception& ) {}
+ }
+
+ if ( !m_aTempURL.isEmpty() )
+ KillFile_Impl( m_aTempURL, m_xContext );
+
+ if ( !m_aTempDumpURL.isEmpty() )
+ KillFile_Impl( m_aTempDumpURL, m_xContext );
+}
+
+
+void OleEmbeddedObject::MakeEventListenerNotification_Impl( const OUString& aEventName )
+{
+ if ( !m_pInterfaceContainer )
+ return;
+
+ comphelper::OInterfaceContainerHelper2* pContainer =
+ m_pInterfaceContainer->getContainer(
+ cppu::UnoType<document::XEventListener>::get());
+ if ( pContainer == nullptr )
+ return;
+
+ document::EventObject aEvent( static_cast< ::cppu::OWeakObject* >( this ), aEventName );
+ comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer);
+ while (pIterator.hasMoreElements())
+ {
+ try
+ {
+ static_cast<document::XEventListener*>(pIterator.next())->notifyEvent( aEvent );
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ }
+}
+#ifdef _WIN32
+
+void OleEmbeddedObject::StateChangeNotification_Impl( bool bBeforeChange, sal_Int32 nOldState, sal_Int32 nNewState )
+{
+ if ( m_pInterfaceContainer )
+ {
+ comphelper::OInterfaceContainerHelper2* pContainer = m_pInterfaceContainer->getContainer(
+ cppu::UnoType<embed::XStateChangeListener>::get());
+ if ( pContainer != nullptr )
+ {
+ lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >( this ) );
+ comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer);
+
+ while (pIterator.hasMoreElements())
+ {
+ if ( bBeforeChange )
+ {
+ try
+ {
+ static_cast<embed::XStateChangeListener*>(pIterator.next())->changingState( aSource, nOldState, nNewState );
+ }
+ catch( const uno::Exception& )
+ {
+ // even if the listener complains ignore it for now
+ }
+ }
+ else
+ {
+ try
+ {
+ static_cast<embed::XStateChangeListener*>(pIterator.next())->stateChanged( aSource, nOldState, nNewState );
+ }
+ catch( const uno::Exception& )
+ {
+ // if anything happened it is problem of listener, ignore it
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
+void OleEmbeddedObject::GetRidOfComponent()
+{
+#ifdef _WIN32
+ if ( m_pOleComponent )
+ {
+ if ( m_nObjectState != -1 && m_nObjectState != embed::EmbedStates::LOADED )
+ SaveObject_Impl();
+
+ m_pOleComponent->removeCloseListener( m_xClosePreventer );
+ try
+ {
+ m_pOleComponent->close( false );
+ }
+ catch( const uno::Exception& )
+ {
+ // TODO: there should be a special listener to wait for component closing
+ // and to notify object, may be object itself can be such a listener
+ m_pOleComponent->addCloseListener( m_xClosePreventer );
+ throw;
+ }
+
+ m_pOleComponent->disconnectEmbeddedObject();
+ m_pOleComponent.clear();
+ }
+#endif
+}
+
+
+void OleEmbeddedObject::Dispose()
+{
+ if ( m_pInterfaceContainer )
+ {
+ lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >( this ) );
+ m_pInterfaceContainer->disposeAndClear( aSource );
+ m_pInterfaceContainer.reset();
+ }
+
+ if ( m_xOwnView.is() )
+ {
+ m_xOwnView->Close();
+ m_xOwnView.clear();
+ }
+
+ if ( m_pOleComponent )
+ try {
+ GetRidOfComponent();
+ } catch( const uno::Exception& )
+ {
+ m_bDisposed = true;
+ throw; // TODO: there should be a special listener that will close object when
+ // component is finally closed
+ }
+
+ if ( m_xObjectStream.is() )
+ {
+ uno::Reference< lang::XComponent > xComp( m_xObjectStream, uno::UNO_QUERY );
+ OSL_ENSURE( xComp.is(), "Storage stream doesn't support XComponent!" );
+
+ if ( xComp.is() )
+ {
+ try {
+ xComp->dispose();
+ } catch( const uno::Exception& ) {}
+ }
+ m_xObjectStream.clear();
+ }
+
+ m_xParentStorage.clear();
+
+ m_bDisposed = true;
+}
+
+
+uno::Sequence< sal_Int8 > SAL_CALL OleEmbeddedObject::getClassID()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getClassID();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ return m_aClassID;
+}
+
+
+OUString SAL_CALL OleEmbeddedObject::getClassName()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getClassName();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ return m_aClassName;
+}
+
+
+void SAL_CALL OleEmbeddedObject::setClassInfo(
+ const uno::Sequence< sal_Int8 >& aClassID, const OUString& aClassName )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->setClassInfo( aClassID, aClassName );
+ return;
+ }
+ // end wrapping related part ====================
+
+ // the object class info can not be changed explicitly
+ throw lang::NoSupportException(); //TODO:
+}
+
+
+uno::Reference< util::XCloseable > SAL_CALL OleEmbeddedObject::getComponent()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getComponent();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 ) // || m_nObjectState == embed::EmbedStates::LOADED )
+ {
+ // the object is still not running
+ throw uno::RuntimeException( "The object is not loaded!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+#if defined(_WIN32)
+ if (m_pOleComponent.is())
+ {
+ return uno::Reference< util::XCloseable >( m_pOleComponent );
+ }
+#endif
+
+ assert(!m_pOleComponent.is());
+ // TODO/LATER: Is it correct???
+ return uno::Reference< util::XCloseable >();
+ // throw uno::RuntimeException(); // TODO
+}
+
+
+void SAL_CALL OleEmbeddedObject::addStateChangeListener( const uno::Reference< embed::XStateChangeListener >& xListener )
+{
+ // begin wrapping related part ====================
+ if ( m_xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ m_xWrappedObject->addStateChangeListener( xListener );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !m_pInterfaceContainer )
+ m_pInterfaceContainer.reset(new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex ));
+
+ m_pInterfaceContainer->addInterface( cppu::UnoType<embed::XStateChangeListener>::get(),
+ xListener );
+}
+
+
+void SAL_CALL OleEmbeddedObject::removeStateChangeListener(
+ const uno::Reference< embed::XStateChangeListener >& xListener )
+{
+ // begin wrapping related part ====================
+ if ( m_xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ m_xWrappedObject->removeStateChangeListener( xListener );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_pInterfaceContainer )
+ m_pInterfaceContainer->removeInterface( cppu::UnoType<embed::XStateChangeListener>::get(),
+ xListener );
+}
+
+
+void SAL_CALL OleEmbeddedObject::close( sal_Bool bDeliverOwnership )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->close( bDeliverOwnership );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >( this ) );
+ lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >( this ) );
+
+ if ( m_pInterfaceContainer )
+ {
+ comphelper::OInterfaceContainerHelper2* pContainer =
+ m_pInterfaceContainer->getContainer( cppu::UnoType<util::XCloseListener>::get());
+ if ( pContainer != nullptr )
+ {
+ comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer);
+ while (pIterator.hasMoreElements())
+ {
+ try
+ {
+ static_cast<util::XCloseListener*>(pIterator.next())->queryClosing( aSource, bDeliverOwnership );
+ }
+ catch( const uno::RuntimeException& )
+ {
+ pIterator.remove();
+ }
+ }
+ }
+
+ pContainer = m_pInterfaceContainer->getContainer(
+ cppu::UnoType<util::XCloseListener>::get());
+ if ( pContainer != nullptr )
+ {
+ comphelper::OInterfaceIteratorHelper2 pCloseIterator(*pContainer);
+ while (pCloseIterator.hasMoreElements())
+ {
+ try
+ {
+ static_cast<util::XCloseListener*>(pCloseIterator.next())->notifyClosing( aSource );
+ }
+ catch( const uno::RuntimeException& )
+ {
+ pCloseIterator.remove();
+ }
+ }
+ }
+ }
+
+ Dispose();
+}
+
+
+void SAL_CALL OleEmbeddedObject::addCloseListener( const uno::Reference< util::XCloseListener >& xListener )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->addCloseListener( xListener );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !m_pInterfaceContainer )
+ m_pInterfaceContainer.reset(new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex ));
+
+ m_pInterfaceContainer->addInterface( cppu::UnoType<util::XCloseListener>::get(), xListener );
+}
+
+
+void SAL_CALL OleEmbeddedObject::removeCloseListener( const uno::Reference< util::XCloseListener >& xListener )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->removeCloseListener( xListener );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_pInterfaceContainer )
+ m_pInterfaceContainer->removeInterface( cppu::UnoType<util::XCloseListener>::get(),
+ xListener );
+}
+
+
+void SAL_CALL OleEmbeddedObject::addEventListener( const uno::Reference< document::XEventListener >& xListener )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->addEventListener( xListener );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !m_pInterfaceContainer )
+ m_pInterfaceContainer.reset(new comphelper::OMultiTypeInterfaceContainerHelper2( m_aMutex ));
+
+ m_pInterfaceContainer->addInterface( cppu::UnoType<document::XEventListener>::get(), xListener );
+}
+
+
+void SAL_CALL OleEmbeddedObject::removeEventListener(
+ const uno::Reference< document::XEventListener >& xListener )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->removeEventListener( xListener );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_pInterfaceContainer )
+ m_pInterfaceContainer->removeInterface( cppu::UnoType<document::XEventListener>::get(),
+ xListener );
+}
+
+// XInplaceObject ( wrapper related implementation )
+
+void SAL_CALL OleEmbeddedObject::setObjectRectangles( const awt::Rectangle& aPosRect,
+ const awt::Rectangle& aClipRect )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XInplaceObject > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->setObjectRectangles( aPosRect, aClipRect );
+ return;
+ }
+ // end wrapping related part ====================
+
+ throw embed::WrongStateException();
+}
+
+
+void SAL_CALL OleEmbeddedObject::enableModeless( sal_Bool bEnable )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XInplaceObject > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->enableModeless( bEnable );
+ return;
+ }
+ // end wrapping related part ====================
+
+ throw embed::WrongStateException();
+}
+
+
+void SAL_CALL OleEmbeddedObject::translateAccelerators(
+ const uno::Sequence< awt::KeyEvent >& aKeys )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XInplaceObject > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->translateAccelerators( aKeys );
+ return;
+ }
+ // end wrapping related part ====================
+
+}
+
+// XChild
+
+css::uno::Reference< css::uno::XInterface > SAL_CALL OleEmbeddedObject::getParent()
+{
+ // begin wrapping related part ====================
+ uno::Reference< container::XChild > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getParent();
+ }
+ // end wrapping related part ====================
+
+ return m_xParent;
+}
+
+
+void SAL_CALL OleEmbeddedObject::setParent( const css::uno::Reference< css::uno::XInterface >& xParent )
+{
+ // begin wrapping related part ====================
+ uno::Reference< container::XChild > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->setParent( xParent );
+ return;
+ }
+ // end wrapping related part ====================
+
+ m_xParent = xParent;
+}
+
+void OleEmbeddedObject::setStream(const css::uno::Reference<css::io::XStream>& xStream)
+{
+ m_xObjectStream = xStream;
+}
+
+css::uno::Reference<css::io::XStream> OleEmbeddedObject::getStream()
+{
+ return m_xObjectStream;
+}
+
+void OleEmbeddedObject::initialize(const uno::Sequence<uno::Any>& rArguments)
+{
+ if (!rArguments.hasElements())
+ return;
+
+ comphelper::SequenceAsHashMap aValues(rArguments[0]);
+ auto it = aValues.find("StreamReadOnly");
+ if (it != aValues.end())
+ it->second >>= m_bStreamReadOnly;
+}
+
+OUString SAL_CALL OleEmbeddedObject::getImplementationName()
+{
+ return "com.sun.star.comp.embed.OleEmbeddedObject";
+}
+
+sal_Bool SAL_CALL OleEmbeddedObject::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL OleEmbeddedObject::getSupportedServiceNames()
+{
+ return { "com.sun.star.comp.embed.OleEmbeddedObject" };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/olepersist.cxx b/embeddedobj/source/msole/olepersist.cxx
new file mode 100644
index 000000000..86403f41b
--- /dev/null
+++ b/embeddedobj/source/msole/olepersist.cxx
@@ -0,0 +1,2019 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <oleembobj.hxx>
+#include "olepersist.hxx"
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/EmbedVerbs.hpp>
+#include <com/sun/star/embed/EntryInitModes.hpp>
+#include <com/sun/star/embed/WrongStateException.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/EmbedUpdateModes.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XOptimizedStorage.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/io/TempFile.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/packages/WrongPasswordException.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/io/IOException.hpp>
+
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/mimeconfighelper.hxx>
+#include <comphelper/classids.hxx>
+#include <osl/diagnose.h>
+#include <osl/thread.hxx>
+#include <rtl/ref.hxx>
+#include <sal/log.hxx>
+
+#include <closepreventer.hxx>
+
+#if defined(_WIN32)
+#include "olecomponent.hxx"
+#endif
+
+using namespace ::com::sun::star;
+using namespace ::comphelper;
+
+
+bool KillFile_Impl( const OUString& aURL, const uno::Reference< uno::XComponentContext >& xContext )
+{
+ if ( !xContext.is() )
+ return false;
+
+ bool bRet = false;
+
+ try
+ {
+ uno::Reference < ucb::XSimpleFileAccess3 > xAccess(
+ ucb::SimpleFileAccess::create( xContext ) );
+
+ xAccess->kill( aURL );
+ bRet = true;
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ return bRet;
+}
+
+
+OUString GetNewTempFileURL_Impl( const uno::Reference< uno::XComponentContext >& xContext )
+{
+ SAL_WARN_IF( !xContext.is(), "embeddedobj.ole", "No factory is provided!" );
+
+ OUString aResult;
+
+ uno::Reference < io::XTempFile > xTempFile(
+ io::TempFile::create(xContext),
+ uno::UNO_SET_THROW );
+
+ try {
+ xTempFile->setRemoveFile( false );
+ aResult = xTempFile->getUri();
+ }
+ catch ( const uno::Exception& )
+ {
+ }
+
+ if ( aResult.isEmpty() )
+ throw uno::RuntimeException("Cannot create tempfile.");
+
+ return aResult;
+}
+
+
+OUString GetNewFilledTempFile_Impl( const uno::Reference< io::XInputStream >& xInStream,
+ const uno::Reference< uno::XComponentContext >& xContext )
+{
+ OSL_ENSURE( xInStream.is() && xContext.is(), "Wrong parameters are provided!" );
+
+ OUString aResult = GetNewTempFileURL_Impl( xContext );
+
+ if ( !aResult.isEmpty() )
+ {
+ try {
+ uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
+ ucb::SimpleFileAccess::create( xContext ) );
+
+ uno::Reference< io::XOutputStream > xTempOutStream = xTempAccess->openFileWrite( aResult );
+ if ( !xTempOutStream.is() )
+ throw io::IOException(); // TODO:
+ // copy stream contents to the file
+ ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xTempOutStream );
+ xTempOutStream->closeOutput();
+ xTempOutStream.clear();
+ }
+ catch( const packages::WrongPasswordException& )
+ {
+ KillFile_Impl( aResult, xContext );
+ throw io::IOException(); //TODO:
+ }
+ catch( const io::IOException& )
+ {
+ KillFile_Impl( aResult, xContext );
+ throw;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ KillFile_Impl( aResult, xContext );
+ throw;
+ }
+ catch( const uno::Exception& )
+ {
+ KillFile_Impl( aResult, xContext );
+ aResult.clear();
+ }
+ }
+
+ return aResult;
+}
+#ifdef _WIN32
+/// @throws io::IOException
+/// @throws uno::RuntimeException
+static OUString GetNewFilledTempFile_Impl( const uno::Reference< embed::XOptimizedStorage >& xParentStorage, const OUString& aEntryName, const uno::Reference< uno::XComponentContext >& xContext )
+{
+ OUString aResult;
+
+ try
+ {
+ uno::Reference < io::XTempFile > xTempFile(
+ io::TempFile::create(xContext),
+ uno::UNO_SET_THROW );
+
+ xParentStorage->copyStreamElementData( aEntryName, xTempFile );
+
+ xTempFile->setRemoveFile( false );
+ aResult = xTempFile->getUri();
+ }
+ catch( const uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ if ( aResult.isEmpty() )
+ throw io::IOException();
+
+ return aResult;
+}
+
+
+static void SetStreamMediaType_Impl( const uno::Reference< io::XStream >& xStream, const OUString& aMediaType )
+{
+ uno::Reference< beans::XPropertySet > xPropSet( xStream, uno::UNO_QUERY_THROW );
+ xPropSet->setPropertyValue("MediaType", uno::Any( aMediaType ) );
+}
+#endif
+
+static void LetCommonStoragePassBeUsed_Impl( const uno::Reference< io::XStream >& xStream )
+{
+ uno::Reference< beans::XPropertySet > xPropSet( xStream, uno::UNO_QUERY_THROW );
+ xPropSet->setPropertyValue("UseCommonStoragePasswordEncryption",
+ uno::Any( true ) );
+}
+#ifdef _WIN32
+
+void VerbExecutionController::StartControlExecution()
+{
+ osl::MutexGuard aGuard( m_aVerbExecutionMutex );
+
+ // the class is used to detect STAMPIT object, that can never be active
+ if ( !m_bVerbExecutionInProgress && !m_bWasEverActive )
+ {
+ m_bVerbExecutionInProgress = true;
+ m_nVerbExecutionThreadIdentifier = osl::Thread::getCurrentIdentifier();
+ m_bChangedOnVerbExecution = false;
+ }
+}
+
+
+bool VerbExecutionController::EndControlExecution_WasModified()
+{
+ osl::MutexGuard aGuard( m_aVerbExecutionMutex );
+
+ bool bResult = false;
+ if ( m_bVerbExecutionInProgress && m_nVerbExecutionThreadIdentifier == osl::Thread::getCurrentIdentifier() )
+ {
+ bResult = m_bChangedOnVerbExecution;
+ m_bVerbExecutionInProgress = false;
+ }
+
+ return bResult;
+}
+
+
+void VerbExecutionController::ModificationNotificationIsDone()
+{
+ osl::MutexGuard aGuard( m_aVerbExecutionMutex );
+
+ if ( m_bVerbExecutionInProgress && osl::Thread::getCurrentIdentifier() == m_nVerbExecutionThreadIdentifier )
+ m_bChangedOnVerbExecution = true;
+}
+#endif
+
+void VerbExecutionController::LockNotification()
+{
+ osl::MutexGuard aGuard( m_aVerbExecutionMutex );
+ if ( m_nNotificationLock < SAL_MAX_INT32 )
+ m_nNotificationLock++;
+}
+
+
+void VerbExecutionController::UnlockNotification()
+{
+ osl::MutexGuard aGuard( m_aVerbExecutionMutex );
+ if ( m_nNotificationLock > 0 )
+ m_nNotificationLock--;
+}
+
+
+uno::Reference< io::XStream > OleEmbeddedObject::GetNewFilledTempStream_Impl( const uno::Reference< io::XInputStream >& xInStream )
+{
+ SAL_WARN_IF( !xInStream.is(), "embeddedobj.ole", "Wrong parameter is provided!" );
+
+ uno::Reference < io::XStream > xTempFile(
+ io::TempFile::create(m_xContext),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference< io::XOutputStream > xTempOutStream = xTempFile->getOutputStream();
+ if ( !xTempOutStream.is() )
+ throw io::IOException(); // TODO:
+ ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xTempOutStream );
+ xTempOutStream->flush();
+ return xTempFile;
+}
+
+
+uno::Reference< io::XStream > OleEmbeddedObject::TryToGetAcceptableFormat_Impl( const uno::Reference< io::XStream >& xStream )
+{
+ // TODO/LATER: Actually this should be done by a centralized component ( may be a graphical filter )
+ if ( !m_xContext.is() )
+ throw uno::RuntimeException();
+
+ uno::Reference< io::XInputStream > xInStream = xStream->getInputStream();
+ if ( !xInStream.is() )
+ throw uno::RuntimeException();
+
+ uno::Reference< io::XSeekable > xSeek( xStream, uno::UNO_QUERY_THROW );
+ xSeek->seek( 0 );
+
+ uno::Sequence< sal_Int8 > aData( 8 );
+ sal_Int32 nRead = xInStream->readBytes( aData, 8 );
+ xSeek->seek( 0 );
+
+ if ( ( nRead >= 2 && aData[0] == 'B' && aData[1] == 'M' )
+ || ( nRead >= 4 && aData[0] == 1 && aData[1] == 0 && aData[2] == 9 && aData[3] == 0 ) )
+ {
+ // it should be a bitmap or a Metafile
+ return xStream;
+ }
+
+
+ sal_uInt32 nHeaderOffset = 0;
+ if ( ( nRead >= 8 && aData[0] == -1 && aData[1] == -1 && aData[2] == -1 && aData[3] == -1 )
+ && ( aData[4] == 2 || aData[4] == 3 || aData[4] == 14 ) && aData[5] == 0 && aData[6] == 0 && aData[7] == 0 )
+ {
+ nHeaderOffset = 40;
+ xSeek->seek( 8 );
+
+ // TargetDevice might be used in future, currently the cache has specified NULL
+ uno::Sequence< sal_Int8 > aHeadData( 4 );
+ nRead = xInStream->readBytes( aHeadData, 4 );
+ sal_uInt32 nLen = 0;
+ if ( nRead == 4 && aHeadData.getLength() == 4 )
+ nLen = ( ( ( static_cast<sal_uInt32>(aHeadData[3]) * 0x100 + static_cast<sal_uInt32>(aHeadData[2]) ) * 0x100 ) + static_cast<sal_uInt32>(aHeadData[1]) ) * 0x100 + static_cast<sal_uInt32>(aHeadData[0]);
+ if ( nLen > 4 )
+ {
+ xInStream->skipBytes( nLen - 4 );
+ nHeaderOffset += nLen - 4;
+ }
+
+ }
+ else if ( nRead > 4 )
+ {
+ // check whether the first bytes represent the size
+ sal_uInt32 nSize = 0;
+ for ( sal_Int32 nInd = 3; nInd >= 0; nInd-- )
+ nSize = ( nSize << 8 ) + static_cast<sal_uInt8>(aData[nInd]);
+
+ if ( nSize == xSeek->getLength() - 4 )
+ nHeaderOffset = 4;
+ }
+
+ if ( nHeaderOffset )
+ {
+ // this is either a bitmap or a metafile clipboard format, retrieve the pure stream
+ uno::Reference < io::XStream > xResult(
+ io::TempFile::create(m_xContext),
+ uno::UNO_QUERY_THROW );
+ uno::Reference < io::XSeekable > xResultSeek( xResult, uno::UNO_QUERY_THROW );
+ uno::Reference < io::XOutputStream > xResultOut = xResult->getOutputStream();
+ uno::Reference < io::XInputStream > xResultIn = xResult->getInputStream();
+ if ( !xResultOut.is() || !xResultIn.is() )
+ throw uno::RuntimeException();
+
+ xSeek->seek( nHeaderOffset ); // header size for these formats
+ ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xResultOut );
+ xResultOut->closeOutput();
+ xResultSeek->seek( 0 );
+ xSeek->seek( 0 );
+
+ return xResult;
+ }
+
+ return uno::Reference< io::XStream >();
+}
+
+
+void OleEmbeddedObject::InsertVisualCache_Impl( const uno::Reference< io::XStream >& xTargetStream,
+ const uno::Reference< io::XStream >& xCachedVisualRepresentation )
+{
+ OSL_ENSURE( xTargetStream.is() && xCachedVisualRepresentation.is(), "Invalid arguments!" );
+
+ if ( !xTargetStream.is() || !xCachedVisualRepresentation.is() )
+ throw uno::RuntimeException();
+
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xTargetStream),
+ uno::Any(true) }; // do not create copy
+
+ uno::Reference< container::XNameContainer > xNameContainer(
+ m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.embed.OLESimpleStorage",
+ aArgs, m_xContext ),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference< io::XSeekable > xCachedSeek( xCachedVisualRepresentation, uno::UNO_QUERY_THROW );
+ xCachedSeek->seek( 0 );
+
+ uno::Reference < io::XStream > xTempFile(
+ io::TempFile::create(m_xContext),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference< io::XSeekable > xTempSeek( xTempFile, uno::UNO_QUERY_THROW );
+ uno::Reference< io::XOutputStream > xTempOutStream = xTempFile->getOutputStream();
+ if ( !xTempOutStream.is() )
+ throw io::IOException(); // TODO:
+
+ // the OlePres stream must have additional header
+ // TODO/LATER: might need to be extended in future (actually makes sense only for SO7 format)
+ uno::Reference< io::XInputStream > xInCacheStream = xCachedVisualRepresentation->getInputStream();
+ if ( !xInCacheStream.is() )
+ throw uno::RuntimeException();
+
+ // write 0xFFFFFFFF at the beginning
+ uno::Sequence< sal_Int8 > aData( 4 );
+ auto pData = aData.getArray();
+ * reinterpret_cast<sal_uInt32*>(pData) = 0xFFFFFFFF;
+
+ xTempOutStream->writeBytes( aData );
+
+ // write clipboard format
+ uno::Sequence< sal_Int8 > aSigData( 2 );
+ xInCacheStream->readBytes( aSigData, 2 );
+ if ( aSigData.getLength() < 2 )
+ throw io::IOException();
+
+ if ( aSigData[0] == 'B' && aSigData[1] == 'M' )
+ {
+ // it's a bitmap
+ pData[0] = 0x02; pData[1] = 0; pData[2] = 0; pData[3] = 0;
+ }
+ else
+ {
+ // treat it as a metafile
+ pData[0] = 0x03; pData[1] = 0; pData[2] = 0; pData[3] = 0;
+ }
+ xTempOutStream->writeBytes( aData );
+
+ // write job related information
+ pData[0] = 0x04; pData[1] = 0; pData[2] = 0; pData[3] = 0;
+ xTempOutStream->writeBytes( aData );
+
+ // write aspect
+ pData[0] = 0x01; pData[1] = 0; pData[2] = 0; pData[3] = 0;
+ xTempOutStream->writeBytes( aData );
+
+ // write l-index
+ * reinterpret_cast<sal_uInt32*>(pData) = 0xFFFFFFFF;
+ xTempOutStream->writeBytes( aData );
+
+ // write adv. flags
+ pData[0] = 0x02; pData[1] = 0; pData[2] = 0; pData[3] = 0;
+ xTempOutStream->writeBytes( aData );
+
+ // write compression
+ * reinterpret_cast<sal_uInt32*>(pData) = 0x0;
+ xTempOutStream->writeBytes( aData );
+
+ // get the size
+ awt::Size aSize = getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
+ sal_Int32 nIndex = 0;
+
+ // write width
+ for ( nIndex = 0; nIndex < 4; nIndex++ )
+ {
+ pData[nIndex] = static_cast<sal_Int8>( aSize.Width % 0x100 );
+ aSize.Width /= 0x100;
+ }
+ xTempOutStream->writeBytes( aData );
+
+ // write height
+ for ( nIndex = 0; nIndex < 4; nIndex++ )
+ {
+ pData[nIndex] = static_cast<sal_Int8>( aSize.Height % 0x100 );
+ aSize.Height /= 0x100;
+ }
+ xTempOutStream->writeBytes( aData );
+
+ // write garbage, it will be overwritten by the size
+ xTempOutStream->writeBytes( aData );
+
+ // write first bytes that was used to detect the type
+ xTempOutStream->writeBytes( aSigData );
+
+ // write the rest of the stream
+ ::comphelper::OStorageHelper::CopyInputToOutput( xInCacheStream, xTempOutStream );
+
+ // write the size of the stream
+ sal_Int64 nLength = xTempSeek->getLength() - 40;
+ if ( nLength < 0 || nLength >= 0xFFFFFFFF )
+ {
+ SAL_WARN( "embeddedobj.ole", "Length is not acceptable!" );
+ return;
+ }
+ for ( sal_Int32 nInd = 0; nInd < 4; nInd++ )
+ {
+ pData[nInd] = static_cast<sal_Int8>( static_cast<sal_uInt64>(nLength) % 0x100 );
+ nLength /= 0x100;
+ }
+ xTempSeek->seek( 36 );
+ xTempOutStream->writeBytes( aData );
+
+ xTempOutStream->flush();
+
+ xTempSeek->seek( 0 );
+ if ( xCachedSeek.is() )
+ xCachedSeek->seek( 0 );
+
+ // insert the result file as replacement image
+ OUString aCacheName = "\002OlePres000";
+ if ( xNameContainer->hasByName( aCacheName ) )
+ xNameContainer->replaceByName( aCacheName, uno::Any( xTempFile ) );
+ else
+ xNameContainer->insertByName( aCacheName, uno::Any( xTempFile ) );
+
+ uno::Reference< embed::XTransactedObject > xTransacted( xNameContainer, uno::UNO_QUERY_THROW );
+ xTransacted->commit();
+}
+
+
+void OleEmbeddedObject::RemoveVisualCache_Impl( const uno::Reference< io::XStream >& xTargetStream )
+{
+ OSL_ENSURE( xTargetStream.is(), "Invalid argument!" );
+ if ( !xTargetStream.is() )
+ throw uno::RuntimeException();
+
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xTargetStream),
+ uno::Any(true) }; // do not create copy
+ uno::Reference< container::XNameContainer > xNameContainer(
+ m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.embed.OLESimpleStorage",
+ aArgs, m_xContext ),
+ uno::UNO_QUERY_THROW );
+
+ for ( sal_uInt8 nInd = 0; nInd < 10; nInd++ )
+ {
+ OUString aStreamName = "\002OlePres00" + OUString::number( nInd );
+ if ( xNameContainer->hasByName( aStreamName ) )
+ xNameContainer->removeByName( aStreamName );
+ }
+
+ uno::Reference< embed::XTransactedObject > xTransacted( xNameContainer, uno::UNO_QUERY_THROW );
+ xTransacted->commit();
+}
+
+
+void OleEmbeddedObject::SetVisReplInStream( bool bExists )
+{
+ m_bVisReplInitialized = true;
+ m_bVisReplInStream = bExists;
+}
+
+
+bool OleEmbeddedObject::HasVisReplInStream()
+{
+ if ( !m_bVisReplInitialized )
+ {
+ if ( m_xCachedVisualRepresentation.is() )
+ SetVisReplInStream( true );
+ else
+ {
+ SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::HasVisualReplInStream, analyzing" );
+
+ uno::Reference< io::XInputStream > xStream;
+
+ OSL_ENSURE( !m_pOleComponent || !m_aTempURL.isEmpty(), "The temporary file must exist if there is a component!" );
+ if ( !m_aTempURL.isEmpty() )
+ {
+ try
+ {
+ // open temporary file for reading
+ uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
+ ucb::SimpleFileAccess::create( m_xContext ) );
+
+ xStream = xTempAccess->openFileRead( m_aTempURL );
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+
+ if ( !xStream.is() )
+ xStream = m_xObjectStream->getInputStream();
+
+ if ( xStream.is() )
+ {
+ bool bExists = false;
+
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xStream),
+ uno::Any(true) }; // do not create copy
+ uno::Reference< container::XNameContainer > xNameContainer(
+ m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.embed.OLESimpleStorage",
+ aArgs, m_xContext ),
+ uno::UNO_QUERY );
+
+ if ( xNameContainer.is() )
+ {
+ for ( sal_uInt8 nInd = 0; nInd < 10 && !bExists; nInd++ )
+ {
+ OUString aStreamName = "\002OlePres00" + OUString::number( nInd );
+ try
+ {
+ bExists = xNameContainer->hasByName( aStreamName );
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+ }
+
+ SetVisReplInStream( bExists );
+ }
+ }
+ }
+
+ return m_bVisReplInStream;
+}
+
+
+uno::Reference< io::XStream > OleEmbeddedObject::TryToRetrieveCachedVisualRepresentation_Impl(
+ const uno::Reference< io::XStream >& xStream,
+ bool bAllowToRepair50 )
+ noexcept
+{
+ uno::Reference< io::XStream > xResult;
+
+ if ( xStream.is() )
+ {
+ SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::TryToRetrieveCachedVisualRepresentation, retrieving" );
+
+ uno::Reference< container::XNameContainer > xNameContainer;
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xStream),
+ uno::Any(true) }; // do not create copy
+ try
+ {
+ xNameContainer.set(
+ m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.embed.OLESimpleStorage",
+ aArgs, m_xContext ),
+ uno::UNO_QUERY );
+ }
+ catch( const uno::Exception& )
+ {}
+
+ if ( xNameContainer.is() )
+ {
+ for ( sal_uInt8 nInd = 0; nInd < 10; nInd++ )
+ {
+ OUString aStreamName = "\002OlePres00" + OUString::number( nInd );
+ uno::Reference< io::XStream > xCachedCopyStream;
+ try
+ {
+ if ( ( xNameContainer->getByName( aStreamName ) >>= xCachedCopyStream ) && xCachedCopyStream.is() )
+ {
+ xResult = TryToGetAcceptableFormat_Impl( xCachedCopyStream );
+ if ( xResult.is() )
+ break;
+ }
+ }
+ catch( const uno::Exception& )
+ {}
+
+ if ( nInd == 0 )
+ {
+ // to be compatible with the old versions Ole10Native is checked after OlePress000
+ aStreamName = "\001Ole10Native";
+ try
+ {
+ if ( ( xNameContainer->getByName( aStreamName ) >>= xCachedCopyStream ) && xCachedCopyStream.is() )
+ {
+ xResult = TryToGetAcceptableFormat_Impl( xCachedCopyStream );
+ if ( xResult.is() )
+ break;
+ }
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+ }
+
+ try
+ {
+ if ( bAllowToRepair50 && !xResult.is() )
+ {
+ OUString aOrigContName( "Ole-Object" );
+ if ( xNameContainer->hasByName( aOrigContName ) )
+ {
+ uno::Reference< embed::XClassifiedObject > xClassified( xNameContainer, uno::UNO_QUERY_THROW );
+ if ( MimeConfigurationHelper::ClassIDsEqual( xClassified->getClassID(), MimeConfigurationHelper::GetSequenceClassID( SO3_OUT_CLASSID ) ) )
+ {
+ // this is an OLE object wrongly stored in 5.0 format
+ // this object must be repaired since SO7 has done it
+
+ uno::Reference< io::XOutputStream > xOutputStream = xStream->getOutputStream();
+ uno::Reference< io::XTruncate > xTruncate( xOutputStream, uno::UNO_QUERY_THROW );
+
+ uno::Reference< io::XInputStream > xOrigInputStream;
+ if ( ( xNameContainer->getByName( aOrigContName ) >>= xOrigInputStream )
+ && xOrigInputStream.is() )
+ {
+ // the provided input stream must be based on temporary medium and must be independent
+ // from the stream the storage is based on
+ uno::Reference< io::XSeekable > xOrigSeekable( xOrigInputStream, uno::UNO_QUERY );
+ if ( xOrigSeekable.is() )
+ xOrigSeekable->seek( 0 );
+
+ uno::Reference< lang::XComponent > xNameContDisp( xNameContainer, uno::UNO_QUERY_THROW );
+ xNameContDisp->dispose(); // free the original stream
+
+ xTruncate->truncate();
+ ::comphelper::OStorageHelper::CopyInputToOutput( xOrigInputStream, xOutputStream );
+ xOutputStream->flush();
+
+ if ( xStream == m_xObjectStream )
+ {
+ if ( !m_aTempURL.isEmpty() )
+ {
+ // this is the own stream, so the temporary URL must be cleaned if it exists
+ KillFile_Impl( m_aTempURL, m_xContext );
+ m_aTempURL.clear();
+ }
+
+#ifdef _WIN32
+ // retry to create the component after recovering
+ GetRidOfComponent();
+
+ try
+ {
+ CreateOleComponentAndLoad_Impl();
+ m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
+ }
+ catch( const uno::Exception& )
+ {
+ GetRidOfComponent();
+ }
+#endif
+ }
+
+ xResult = TryToRetrieveCachedVisualRepresentation_Impl( xStream );
+ }
+ }
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+ }
+
+ return xResult;
+}
+
+
+void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
+ const uno::Reference< io::XStream >& xNewObjectStream,
+ const OUString& aNewName )
+{
+ if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
+ {
+ SAL_WARN_IF( xNewObjectStream != m_xObjectStream, "embeddedobj.ole", "The streams must be the same!" );
+ return;
+ }
+
+ uno::Reference<io::XSeekable> xNewSeekable(xNewObjectStream, uno::UNO_QUERY);
+ if (xNewSeekable.is() && xNewSeekable->getLength() == 0)
+ {
+ uno::Reference<io::XSeekable> xOldSeekable(m_xObjectStream, uno::UNO_QUERY);
+ if (xOldSeekable.is() && xOldSeekable->getLength() > 0)
+ {
+ SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::SwitchOwnPersistence(stream version): "
+ "empty new stream, reusing old one");
+ uno::Reference<io::XInputStream> xInput = m_xObjectStream->getInputStream();
+ uno::Reference<io::XOutputStream> xOutput = xNewObjectStream->getOutputStream();
+ xOldSeekable->seek(0);
+ comphelper::OStorageHelper::CopyInputToOutput(xInput, xOutput);
+ xNewSeekable->seek(0);
+ }
+ }
+
+ try {
+ uno::Reference< lang::XComponent > xComponent( m_xObjectStream, uno::UNO_QUERY );
+ OSL_ENSURE( !m_xObjectStream.is() || xComponent.is(), "Wrong stream implementation!" );
+ if ( xComponent.is() )
+ xComponent->dispose();
+ }
+ catch ( const uno::Exception& )
+ {
+ }
+
+ m_xObjectStream = xNewObjectStream;
+ m_xParentStorage = xNewParentStorage;
+ m_aEntryName = aNewName;
+}
+
+
+void OleEmbeddedObject::SwitchOwnPersistence( const uno::Reference< embed::XStorage >& xNewParentStorage,
+ const OUString& aNewName )
+{
+ if ( xNewParentStorage == m_xParentStorage && aNewName == m_aEntryName )
+ return;
+
+ sal_Int32 nStreamMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
+
+ uno::Reference< io::XStream > xNewOwnStream = xNewParentStorage->openStreamElement( aNewName, nStreamMode );
+
+ uno::Reference<io::XSeekable> xNewSeekable (xNewOwnStream, uno::UNO_QUERY);
+ if (xNewSeekable.is() && xNewSeekable->getLength() == 0)
+ {
+ uno::Reference<io::XSeekable> xOldSeekable(m_xObjectStream, uno::UNO_QUERY);
+ if (xOldSeekable.is() && xOldSeekable->getLength() > 0)
+ {
+ SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::SwitchOwnPersistence: empty new stream, reusing old one");
+ uno::Reference<io::XInputStream> xInput = m_xObjectStream->getInputStream();
+ uno::Reference<io::XOutputStream> xOutput = xNewOwnStream->getOutputStream();
+ comphelper::OStorageHelper::CopyInputToOutput(xInput, xOutput);
+ xNewSeekable->seek(0);
+ }
+ }
+
+ SAL_WARN_IF( !xNewOwnStream.is(), "embeddedobj.ole", "The method can not return empty reference!" );
+
+ SwitchOwnPersistence( xNewParentStorage, xNewOwnStream, aNewName );
+}
+
+#ifdef _WIN32
+
+bool OleEmbeddedObject::SaveObject_Impl()
+{
+ bool bResult = false;
+
+ if ( m_xClientSite.is() )
+ {
+ try
+ {
+ m_xClientSite->saveObject();
+ bResult = true;
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ return bResult;
+}
+
+
+bool OleEmbeddedObject::OnShowWindow_Impl( bool bShow )
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ bool bResult = false;
+
+ SAL_WARN_IF( m_nObjectState == -1, "embeddedobj.ole", "The object has no persistence!" );
+ SAL_WARN_IF( m_nObjectState == embed::EmbedStates::LOADED, "embeddedobj.ole", "The object get OnShowWindow in loaded state!" );
+ if ( m_nObjectState == -1 || m_nObjectState == embed::EmbedStates::LOADED )
+ return false;
+
+ // the object is either activated or deactivated
+ sal_Int32 nOldState = m_nObjectState;
+ if ( bShow && m_nObjectState == embed::EmbedStates::RUNNING )
+ {
+ m_nObjectState = embed::EmbedStates::ACTIVE;
+ m_aVerbExecutionController.ObjectIsActive();
+
+ aGuard.clear();
+ StateChangeNotification_Impl( false, nOldState, m_nObjectState );
+ }
+ else if ( !bShow && m_nObjectState == embed::EmbedStates::ACTIVE )
+ {
+ m_nObjectState = embed::EmbedStates::RUNNING;
+ aGuard.clear();
+ StateChangeNotification_Impl( false, nOldState, m_nObjectState );
+ }
+
+ if ( m_xClientSite.is() )
+ {
+ try
+ {
+ m_xClientSite->visibilityChanged( bShow );
+ bResult = true;
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ return bResult;
+}
+
+
+void OleEmbeddedObject::OnIconChanged_Impl()
+{
+ // TODO/LATER: currently this notification seems to be impossible
+ // MakeEventListenerNotification_Impl( OUString( "OnIconChanged" ) );
+}
+
+
+void OleEmbeddedObject::OnViewChanged_Impl()
+{
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ // For performance reasons the notification currently is ignored, STAMPIT object is the exception,
+ // it can never be active and never call SaveObject, so it is the only way to detect that it is changed
+
+ // ==== the STAMPIT related solution =============================
+ // the following variable is used to detect whether the object was modified during verb execution
+ m_aVerbExecutionController.ModificationNotificationIsDone();
+
+ // The following things are controlled by VerbExecutionController:
+ // - if the verb execution is in progress and the view is changed the object will be stored
+ // after the execution, so there is no need to send the notification.
+ // - the STAMPIT object can never be active.
+ if (m_aVerbExecutionController.CanDoNotification() &&
+ m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE &&
+ (MimeConfigurationHelper::ClassIDsEqual(m_aClassID, MimeConfigurationHelper::GetSequenceClassID(0x852ee1c9, 0x9058, 0x44ba, 0x8c, 0x6c, 0x0c, 0x5f, 0xc6, 0x6b, 0xdb, 0x8d)) ||
+ MimeConfigurationHelper::ClassIDsEqual(m_aClassID, MimeConfigurationHelper::GetSequenceClassID(0xcf1b4491, 0xbea3, 0x4c9f, 0xa7, 0x0f, 0x22, 0x1b, 0x1e, 0xca, 0xef, 0x3e)))
+ )
+ {
+ // The view is changed while the object is in running state, save the new object
+ m_xCachedVisualRepresentation.clear();
+ SaveObject_Impl();
+ MakeEventListenerNotification_Impl( "OnVisAreaChanged" );
+ }
+
+}
+
+
+void OleEmbeddedObject::OnClosed_Impl()
+{
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( m_nObjectState != embed::EmbedStates::LOADED )
+ {
+ sal_Int32 nOldState = m_nObjectState;
+ m_nObjectState = embed::EmbedStates::LOADED;
+ StateChangeNotification_Impl( false, nOldState, m_nObjectState );
+ }
+}
+
+
+OUString OleEmbeddedObject::CreateTempURLEmpty_Impl()
+{
+ SAL_WARN_IF( !m_aTempURL.isEmpty(), "embeddedobj.ole", "The object has already the temporary file!" );
+ m_aTempURL = GetNewTempFileURL_Impl( m_xContext );
+
+ return m_aTempURL;
+}
+
+
+OUString OleEmbeddedObject::GetTempURL_Impl()
+{
+ if ( m_aTempURL.isEmpty() )
+ {
+ SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::GetTempURL_Impl, tempfile creation" );
+
+ // if there is no temporary file, it will be created from the own entry
+ uno::Reference< embed::XOptimizedStorage > xOptParStorage( m_xParentStorage, uno::UNO_QUERY );
+ if ( xOptParStorage.is() )
+ {
+ m_aTempURL = GetNewFilledTempFile_Impl( xOptParStorage, m_aEntryName, m_xContext );
+ }
+ else if ( m_xObjectStream.is() )
+ {
+ // load object from the stream
+ uno::Reference< io::XInputStream > xInStream = m_xObjectStream->getInputStream();
+ if ( !xInStream.is() )
+ throw io::IOException(); // TODO: access denied
+
+ m_aTempURL = GetNewFilledTempFile_Impl( xInStream, m_xContext );
+ }
+ }
+
+ return m_aTempURL;
+}
+
+
+void OleEmbeddedObject::CreateOleComponent_Impl(
+ rtl::Reference<OleComponent> const & pOleComponent )
+{
+ if ( !m_pOleComponent )
+ {
+ m_pOleComponent = pOleComponent ? pOleComponent : new OleComponent( m_xContext, this );
+
+ if ( !m_xClosePreventer.is() )
+ m_xClosePreventer = new OClosePreventer;
+
+ m_pOleComponent->addCloseListener( m_xClosePreventer );
+ }
+}
+
+
+void OleEmbeddedObject::CreateOleComponentAndLoad_Impl(
+ rtl::Reference<OleComponent> const & pOleComponent )
+{
+ if ( !m_pOleComponent )
+ {
+ if ( !m_xObjectStream.is() )
+ throw uno::RuntimeException();
+
+ CreateOleComponent_Impl( pOleComponent );
+
+ // after the loading the object can appear as a link
+ // will be detected later by olecomponent
+
+ GetTempURL_Impl();
+ if ( m_aTempURL.isEmpty() )
+ throw uno::RuntimeException(); // TODO
+
+ m_pOleComponent->LoadEmbeddedObject( m_aTempURL );
+ }
+}
+
+
+void OleEmbeddedObject::CreateOleComponentFromClipboard_Impl( OleComponent* pOleComponent )
+{
+ if ( !m_pOleComponent )
+ {
+ if ( !m_xObjectStream.is() )
+ throw uno::RuntimeException();
+
+ CreateOleComponent_Impl( pOleComponent );
+
+ // after the loading the object can appear as a link
+ // will be detected later by olecomponent
+ m_pOleComponent->CreateObjectFromClipboard();
+ }
+}
+
+
+uno::Reference< io::XOutputStream > OleEmbeddedObject::GetStreamForSaving()
+{
+ if ( !m_xObjectStream.is() )
+ throw uno::RuntimeException(); //TODO:
+
+ uno::Reference< io::XOutputStream > xOutStream = m_xObjectStream->getOutputStream();
+ if ( !xOutStream.is() )
+ throw io::IOException(); //TODO: access denied
+
+ uno::Reference< io::XTruncate > xTruncate( xOutStream, uno::UNO_QUERY_THROW );
+ xTruncate->truncate();
+
+ return xOutStream;
+}
+
+
+void OleEmbeddedObject::StoreObjectToStream( uno::Reference< io::XOutputStream > const & xOutStream )
+{
+ // this method should be used only on windows
+ if ( m_pOleComponent )
+ m_pOleComponent->StoreOwnTmpIfNecessary();
+
+ // now all the changes should be in temporary location
+ if ( m_aTempURL.isEmpty() )
+ throw uno::RuntimeException();
+
+ // open temporary file for reading
+ uno::Reference < ucb::XSimpleFileAccess3 > xTempAccess(
+ ucb::SimpleFileAccess::create( m_xContext ) );
+
+ uno::Reference< io::XInputStream > xTempInStream = xTempAccess->openFileRead( m_aTempURL );
+ SAL_WARN_IF( !xTempInStream.is(), "embeddedobj.ole", "The object's temporary file can not be reopened for reading!" );
+
+ // TODO: use bStoreVisReplace
+
+ if ( !xTempInStream.is() )
+ {
+ throw io::IOException(); // TODO:
+ }
+
+ // write all the contents to XOutStream
+ uno::Reference< io::XTruncate > xTrunc( xOutStream, uno::UNO_QUERY_THROW );
+ xTrunc->truncate();
+
+ ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutStream );
+
+ // TODO: should the view replacement be in the stream ???
+ // probably it must be specified on storing
+}
+#endif
+
+void OleEmbeddedObject::StoreToLocation_Impl(
+ const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs,
+ bool bSaveAs )
+{
+ // TODO: use lObjArgs
+ // TODO: exchange StoreVisualReplacement by SO file format version?
+
+ if ( m_nObjectState == -1 )
+ {
+ // the object is still not loaded
+ throw embed::WrongStateException( "Can't store object without persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ OSL_ENSURE( m_xParentStorage.is() && m_xObjectStream.is(), "The object has no valid persistence!" );
+
+ bool bVisReplIsStored = false;
+
+ bool bTryOptimization = false;
+ bool bStoreVis = m_bStoreVisRepl;
+ uno::Reference< io::XStream > xCachedVisualRepresentation;
+ for ( beans::PropertyValue const & prop : lObjArgs )
+ {
+ if ( prop.Name == "StoreVisualReplacement" )
+ prop.Value >>= bStoreVis;
+ else if ( prop.Name == "VisualReplacement" )
+ prop.Value >>= xCachedVisualRepresentation;
+ else if ( prop.Name == "CanTryOptimization" )
+ prop.Value >>= bTryOptimization;
+ }
+
+ // ignore visual representation provided from outside if it should not be stored
+ if ( !bStoreVis )
+ xCachedVisualRepresentation.clear();
+
+ if ( bStoreVis && !HasVisReplInStream() && !xCachedVisualRepresentation.is() )
+ throw io::IOException(); // TODO: there is no cached visual representation and nothing is provided from outside
+
+ // if the representation is provided from outside it should be copied to a local stream
+ bool bNeedLocalCache = xCachedVisualRepresentation.is();
+
+ uno::Reference< io::XStream > xTargetStream;
+
+ bool bStoreLoaded = false;
+ if ( m_nObjectState == embed::EmbedStates::LOADED
+#ifdef _WIN32
+ // if the object was NOT modified after storing it can be just copied
+ // as if it was in loaded state
+ || ( m_pOleComponent && !m_pOleComponent->IsDirty() )
+#endif
+ )
+ {
+ bool bOptimizedCopyingDone = false;
+
+ if ( bTryOptimization && bStoreVis == HasVisReplInStream() )
+ {
+ try
+ {
+ uno::Reference< embed::XOptimizedStorage > xSourceOptStor( m_xParentStorage, uno::UNO_QUERY_THROW );
+ uno::Reference< embed::XOptimizedStorage > xTargetOptStor( xStorage, uno::UNO_QUERY_THROW );
+ xSourceOptStor->copyElementDirectlyTo( m_aEntryName, xTargetOptStor, sEntName );
+ bOptimizedCopyingDone = true;
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ if ( !bOptimizedCopyingDone )
+ {
+ // if optimized copying fails a normal one should be tried
+ m_xParentStorage->copyElementTo( m_aEntryName, xStorage, sEntName );
+ }
+
+ // the locally retrieved representation is always preferable
+ // since the object is in loaded state the representation is unchanged
+ if ( m_xCachedVisualRepresentation.is() )
+ {
+ xCachedVisualRepresentation = m_xCachedVisualRepresentation;
+ bNeedLocalCache = false;
+ }
+
+ bVisReplIsStored = HasVisReplInStream();
+ bStoreLoaded = true;
+ }
+#ifdef _WIN32
+ else if ( m_pOleComponent )
+ {
+ xTargetStream =
+ xStorage->openStreamElement( sEntName, embed::ElementModes::READWRITE );
+ if ( !xTargetStream.is() )
+ throw io::IOException(); //TODO: access denied
+
+ SetStreamMediaType_Impl( xTargetStream, "application/vnd.sun.star.oleobject" );
+ uno::Reference< io::XOutputStream > xOutStream = xTargetStream->getOutputStream();
+ if ( !xOutStream.is() )
+ throw io::IOException(); //TODO: access denied
+
+ StoreObjectToStream( xOutStream );
+ bVisReplIsStored = true;
+
+ if ( bSaveAs )
+ {
+ // no need to do it on StoreTo since in this case the replacement is in the stream
+ // and there is no need to cache it even if it is thrown away because the object
+ // is not changed by StoreTo action
+
+ uno::Reference< io::XStream > xTmpCVRepresentation =
+ TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream );
+
+ // the locally retrieved representation is always preferable
+ if ( xTmpCVRepresentation.is() )
+ {
+ xCachedVisualRepresentation = xTmpCVRepresentation;
+ bNeedLocalCache = false;
+ }
+ }
+ }
+#endif
+ else if (true) // loplugin:flatten
+ {
+ throw io::IOException(); // TODO
+ }
+
+ if ( !xTargetStream.is() )
+ {
+ xTargetStream =
+ xStorage->openStreamElement( sEntName, embed::ElementModes::READWRITE );
+ if ( !xTargetStream.is() )
+ throw io::IOException(); //TODO: access denied
+ }
+
+ LetCommonStoragePassBeUsed_Impl( xTargetStream );
+
+ if ( bStoreVis != bVisReplIsStored )
+ {
+ if ( bStoreVis )
+ {
+ if ( !xCachedVisualRepresentation.is() )
+ xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream );
+
+ SAL_WARN_IF( !xCachedVisualRepresentation.is(), "embeddedobj.ole", "No representation is available!" );
+
+ // the following copying will be done in case it is SaveAs anyway
+ // if it is not SaveAs the seekable access is not required currently
+ // TODO/LATER: may be required in future
+ if ( bSaveAs )
+ {
+ uno::Reference< io::XSeekable > xCachedSeek( xCachedVisualRepresentation, uno::UNO_QUERY );
+ if ( !xCachedSeek.is() )
+ {
+ xCachedVisualRepresentation
+ = GetNewFilledTempStream_Impl( xCachedVisualRepresentation->getInputStream() );
+ bNeedLocalCache = false;
+ }
+ }
+
+ InsertVisualCache_Impl( xTargetStream, xCachedVisualRepresentation );
+ }
+ else
+ {
+ // the removed representation could be cached by this method
+ if ( !xCachedVisualRepresentation.is() )
+ xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( xTargetStream );
+
+ if (!m_bStreamReadOnly)
+ RemoveVisualCache_Impl(xTargetStream);
+ }
+ }
+
+ if ( bSaveAs )
+ {
+ m_bWaitSaveCompleted = true;
+ m_xNewObjectStream = xTargetStream;
+ m_xNewParentStorage = xStorage;
+ m_aNewEntryName = sEntName;
+ m_bNewVisReplInStream = bStoreVis;
+ m_bStoreLoaded = bStoreLoaded;
+
+ if ( xCachedVisualRepresentation.is() )
+ {
+ if ( bNeedLocalCache )
+ m_xNewCachedVisRepl = GetNewFilledTempStream_Impl( xCachedVisualRepresentation->getInputStream() );
+ else
+ m_xNewCachedVisRepl = xCachedVisualRepresentation;
+ }
+
+ // TODO: register listeners for storages above, in case they are disposed
+ // an exception will be thrown on saveCompleted( true )
+ }
+ else
+ {
+ uno::Reference< lang::XComponent > xComp( xTargetStream, uno::UNO_QUERY );
+ if ( xComp.is() )
+ {
+ try {
+ xComp->dispose();
+ } catch( const uno::Exception& )
+ {
+ }
+ }
+ }
+}
+
+
+void SAL_CALL OleEmbeddedObject::setPersistentEntry(
+ const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ sal_Int32 nEntryConnectionMode,
+ const uno::Sequence< beans::PropertyValue >& lArguments,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->setPersistentEntry( xStorage, sEntName, nEntryConnectionMode, lArguments, lObjArgs );
+ return;
+ }
+ // end wrapping related part ====================
+
+ // TODO: use lObjArgs
+
+ // the type of the object must be already set
+ // a kind of typedetection should be done in the factory;
+ // the only exception is object initialized from a stream,
+ // the class ID will be detected from the stream
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !xStorage.is() )
+ throw lang::IllegalArgumentException( "No parent storage is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 1 );
+
+ if ( sEntName.isEmpty() )
+ throw lang::IllegalArgumentException( "Empty element name is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 2 );
+
+ // May be LOADED should be forbidden here ???
+ if ( ( m_nObjectState != -1 || nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
+ && ( m_nObjectState == -1 || nEntryConnectionMode != embed::EntryInitModes::NO_INIT ) )
+ {
+ // if the object is not loaded
+ // it can not get persistent representation without initialization
+
+ // if the object is loaded
+ // it can switch persistent representation only without initialization
+
+ throw embed::WrongStateException(
+ "Can't change persistent representation of activated object!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bWaitSaveCompleted )
+ {
+ if ( nEntryConnectionMode != embed::EntryInitModes::NO_INIT )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ saveCompleted( m_xParentStorage != xStorage || m_aEntryName != sEntName );
+ }
+
+ uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
+
+ // detect entry existence
+ bool bElExists = xNameAccess->hasByName( sEntName );
+
+ m_bReadOnly = false;
+ for ( beans::PropertyValue const & prop : lArguments )
+ if ( prop.Name == "ReadOnly" )
+ prop.Value >>= m_bReadOnly;
+
+#ifdef _WIN32
+ sal_Int32 nStorageMode = m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE;
+#endif
+
+ SwitchOwnPersistence( xStorage, sEntName );
+
+ for ( beans::PropertyValue const & prop : lObjArgs )
+ if ( prop.Name == "StoreVisualReplacement" )
+ prop.Value >>= m_bStoreVisRepl;
+
+#ifdef _WIN32
+ if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT )
+ {
+ if ( m_bFromClipboard )
+ {
+ // the object should be initialized from clipboard
+ // impossibility to initialize the object means error here
+ CreateOleComponentFromClipboard_Impl();
+ m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
+ m_pOleComponent->RunObject();
+ m_nObjectState = embed::EmbedStates::RUNNING;
+ }
+ else if ( bElExists )
+ {
+ // load object from the stream
+ // after the loading the object can appear as a link
+ // will be detected by olecomponent
+ try
+ {
+ CreateOleComponentAndLoad_Impl();
+ m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
+ }
+ catch( const uno::Exception& )
+ {
+ // TODO/LATER: detect classID of the object if possible
+ // means that the object inprocess server could not be successfully instantiated
+ GetRidOfComponent();
+ }
+
+ m_nObjectState = embed::EmbedStates::LOADED;
+ }
+ else
+ {
+ // create a new object
+ CreateOleComponent_Impl();
+ m_pOleComponent->CreateNewEmbeddedObject( m_aClassID );
+ m_pOleComponent->RunObject();
+ m_nObjectState = embed::EmbedStates::RUNNING;
+ }
+ }
+ else
+ {
+ if ( ( nStorageMode & embed::ElementModes::READWRITE ) != embed::ElementModes::READWRITE )
+ throw io::IOException();
+
+ if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
+ {
+ // the document just already changed its stream to store to;
+ // the links to OLE documents switch their persistence in the same way
+ // as normal embedded objects
+ }
+ else if ( nEntryConnectionMode == embed::EntryInitModes::TRUNCATE_INIT )
+ {
+ // create a new object, that will be stored in specified stream
+ CreateOleComponent_Impl();
+
+ m_pOleComponent->CreateNewEmbeddedObject( m_aClassID );
+ m_pOleComponent->RunObject();
+ m_nObjectState = embed::EmbedStates::RUNNING;
+ }
+ else if ( nEntryConnectionMode == embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT )
+ {
+ // use URL ( may be content or stream later ) from MediaDescriptor to initialize object
+ OUString aURL;
+ for ( beans::PropertyValue const & prop : lArguments )
+ if ( prop.Name == "URL" )
+ prop.Value >>= aURL;
+
+ if ( aURL.isEmpty() )
+ throw lang::IllegalArgumentException(
+ "Empty URL is provided in the media descriptor!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 4 );
+
+ CreateOleComponent_Impl();
+
+ // TODO: the m_bIsLink value must be set already
+ if ( !m_bIsLink )
+ m_pOleComponent->CreateObjectFromFile( aURL );
+ else
+ m_pOleComponent->CreateLinkFromFile( aURL );
+
+ m_pOleComponent->RunObject();
+ m_aClassID = m_pOleComponent->GetCLSID(); // was not set during construction
+
+ m_nObjectState = embed::EmbedStates::RUNNING;
+ }
+ //else if ( nEntryConnectionMode == embed::EntryInitModes::TRANSFERABLE_INIT )
+ //{
+ //TODO:
+ //}
+ else
+ throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 3 );
+ }
+#else
+ // On Unix the OLE object can not do anything except storing itself somewhere
+ if ( nEntryConnectionMode == embed::EntryInitModes::DEFAULT_INIT && bElExists )
+ {
+ // TODO/LATER: detect classID of the object
+ // can be a real problem for the links
+
+ m_nObjectState = embed::EmbedStates::LOADED;
+ }
+ else if ( nEntryConnectionMode == embed::EntryInitModes::NO_INIT )
+ {
+ // do nothing, the object has already switched it's persistence
+ }
+ else
+ throw lang::IllegalArgumentException( "Wrong connection mode is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 3 );
+
+#endif
+}
+
+
+void SAL_CALL OleEmbeddedObject::storeToEntry( const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ const uno::Sequence< beans::PropertyValue >& lArguments,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->storeToEntry( xStorage, sEntName, lArguments, lObjArgs );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
+
+ StoreToLocation_Impl( xStorage, sEntName, lObjArgs, false );
+
+ // TODO: should the listener notification be done?
+}
+
+
+void SAL_CALL OleEmbeddedObject::storeAsEntry( const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ const uno::Sequence< beans::PropertyValue >& lArguments,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->storeAsEntry( xStorage, sEntName, lArguments, lObjArgs );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
+
+ StoreToLocation_Impl( xStorage, sEntName, lObjArgs, true );
+
+ // TODO: should the listener notification be done here or in saveCompleted?
+}
+
+
+void SAL_CALL OleEmbeddedObject::saveCompleted( sal_Bool bUseNew )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->saveCompleted( bUseNew );
+ return;
+ }
+ // end wrapping related part ====================
+
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ {
+ // the object is still not loaded
+ throw embed::WrongStateException( "Can't store object without persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ // it is allowed to call saveCompleted( false ) for nonstored objects
+ if ( !m_bWaitSaveCompleted && !bUseNew )
+ return;
+
+ SAL_WARN_IF( !m_bWaitSaveCompleted, "embeddedobj.ole", "Unexpected saveCompleted() call!" );
+ if ( !m_bWaitSaveCompleted )
+ throw io::IOException(); // TODO: illegal call
+
+ OSL_ENSURE( m_xNewObjectStream.is() && m_xNewParentStorage.is() , "Internal object information is broken!" );
+ if ( !m_xNewObjectStream.is() || !m_xNewParentStorage.is() )
+ throw uno::RuntimeException(); // TODO: broken internal information
+
+ if ( bUseNew )
+ {
+ SwitchOwnPersistence( m_xNewParentStorage, m_xNewObjectStream, m_aNewEntryName );
+ m_bStoreVisRepl = m_bNewVisReplInStream;
+ SetVisReplInStream( m_bNewVisReplInStream );
+ m_xCachedVisualRepresentation = m_xNewCachedVisRepl;
+ }
+ else
+ {
+ // close remembered stream
+ try {
+ uno::Reference< lang::XComponent > xComponent( m_xNewObjectStream, uno::UNO_QUERY );
+ SAL_WARN_IF( !xComponent.is(), "embeddedobj.ole", "Wrong storage implementation!" );
+ if ( xComponent.is() )
+ xComponent->dispose();
+ }
+ catch ( const uno::Exception& )
+ {
+ }
+ }
+
+ bool bStoreLoaded = m_bStoreLoaded;
+
+ m_xNewObjectStream.clear();
+ m_xNewParentStorage.clear();
+ m_aNewEntryName.clear();
+ m_bWaitSaveCompleted = false;
+ m_bNewVisReplInStream = false;
+ m_xNewCachedVisRepl.clear();
+ m_bStoreLoaded = false;
+
+ if ( bUseNew && m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded
+ && m_nObjectState != embed::EmbedStates::LOADED )
+ {
+ // the object replacement image should be updated, so the cached size as well
+ m_bHasCachedSize = false;
+ try
+ {
+ // the call will cache the size in case of success
+ // probably it might need to be done earlier, while the object is in active state
+ getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+
+ aGuard.clear();
+ if ( bUseNew )
+ {
+ MakeEventListenerNotification_Impl( "OnSaveAsDone");
+
+ // the object can be changed only on windows
+ // the notification should be done only if the object is not in loaded state
+ if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
+ {
+ MakeEventListenerNotification_Impl( "OnVisAreaChanged");
+ }
+ }
+}
+
+
+sal_Bool SAL_CALL OleEmbeddedObject::hasEntry()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->hasEntry();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ if ( m_xObjectStream.is() )
+ return true;
+
+ return false;
+}
+
+
+OUString SAL_CALL OleEmbeddedObject::getEntryName()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getEntryName();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ {
+ // the object is still not loaded
+ throw embed::WrongStateException( "The object persistence is not initialized!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ return m_aEntryName;
+}
+
+
+void SAL_CALL OleEmbeddedObject::storeOwn()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->storeOwn();
+ return;
+ }
+ // end wrapping related part ====================
+
+ // during switching from Activated to Running and from Running to Loaded states the object will
+ // ask container to store the object, the container has to make decision
+ // to do so or not
+
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
+
+ if ( m_nObjectState == -1 )
+ {
+ // the object is still not loaded
+ throw embed::WrongStateException( "Can't store object without persistence!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ if ( m_bReadOnly )
+ throw io::IOException(); // TODO: access denied
+
+ LetCommonStoragePassBeUsed_Impl( m_xObjectStream );
+
+ bool bStoreLoaded = true;
+
+#ifdef _WIN32
+ if ( m_nObjectState != embed::EmbedStates::LOADED && m_pOleComponent && m_pOleComponent->IsDirty() )
+ {
+ bStoreLoaded = false;
+
+ OSL_ENSURE( m_xParentStorage.is() && m_xObjectStream.is(), "The object has no valid persistence!" );
+
+ if ( !m_xObjectStream.is() )
+ throw io::IOException(); //TODO: access denied
+
+ SetStreamMediaType_Impl( m_xObjectStream, "application/vnd.sun.star.oleobject" );
+ uno::Reference< io::XOutputStream > xOutStream = m_xObjectStream->getOutputStream();
+ if ( !xOutStream.is() )
+ throw io::IOException(); //TODO: access denied
+
+ // TODO: does this work for links too?
+ StoreObjectToStream( GetStreamForSaving() );
+
+ // the replacement is changed probably, and it must be in the object stream
+ if ( !m_pOleComponent->IsWorkaroundActive() )
+ m_xCachedVisualRepresentation.clear();
+ SetVisReplInStream( true );
+ }
+#endif
+
+ if ( m_bStoreVisRepl != HasVisReplInStream() )
+ {
+ if ( m_bStoreVisRepl )
+ {
+ // the m_xCachedVisualRepresentation must be set or it should be already stored
+ if ( m_xCachedVisualRepresentation.is() )
+ InsertVisualCache_Impl( m_xObjectStream, m_xCachedVisualRepresentation );
+ else
+ {
+ m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream );
+ SAL_WARN_IF( !m_xCachedVisualRepresentation.is(), "embeddedobj.ole", "No representation is available!" );
+ }
+ }
+ else
+ {
+ if ( !m_xCachedVisualRepresentation.is() )
+ m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream );
+ RemoveVisualCache_Impl( m_xObjectStream );
+ }
+
+ SetVisReplInStream( m_bStoreVisRepl );
+ }
+
+ if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
+ {
+ // the object replacement image should be updated, so the cached size as well
+ m_bHasCachedSize = false;
+ try
+ {
+ // the call will cache the size in case of success
+ // probably it might need to be done earlier, while the object is in active state
+ getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+
+ aGuard.clear();
+
+ MakeEventListenerNotification_Impl( "OnSaveDone");
+
+ // the object can be changed only on Windows
+ // the notification should be done only if the object is not in loaded state
+ if ( m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE && !bStoreLoaded )
+ MakeEventListenerNotification_Impl( "OnVisAreaChanged");
+}
+
+
+sal_Bool SAL_CALL OleEmbeddedObject::isReadonly()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->isReadonly();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ {
+ // the object is still not loaded
+ throw embed::WrongStateException( "The object persistence is not initialized!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ return m_bReadOnly;
+}
+
+
+void SAL_CALL OleEmbeddedObject::reload(
+ const uno::Sequence< beans::PropertyValue >& lArguments,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbedPersist > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->reload( lArguments, lObjArgs );
+ return;
+ }
+ // end wrapping related part ====================
+
+ // TODO: use lObjArgs
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_nObjectState == -1 )
+ {
+ // the object is still not loaded
+ throw embed::WrongStateException( "The object persistence is not initialized!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ // TODO:
+ // throw away current document
+ // load new document from current storage
+ // use meaningful part of lArguments
+}
+
+
+void SAL_CALL OleEmbeddedObject::breakLink( const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->breakLink( xStorage, sEntName );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( !xStorage.is() )
+ throw lang::IllegalArgumentException( "No parent storage is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 1 );
+
+ if ( sEntName.isEmpty() )
+ throw lang::IllegalArgumentException( "Empty element name is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 2 );
+
+ // TODO: The object must be at least in Running state;
+ if ( !m_bIsLink || m_nObjectState == -1 || !m_pOleComponent )
+ {
+ // it must be a linked initialized object
+ throw embed::WrongStateException(
+ "The object is not a valid linked object!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ if ( m_bReadOnly )
+ throw io::IOException(); // TODO: Access denied
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+
+#ifdef _WIN32
+ // TODO: create an object based on the link
+
+ // disconnect the old temporary URL
+ OUString aOldTempURL = m_aTempURL;
+ m_aTempURL.clear();
+
+ rtl::Reference<OleComponent> pNewOleComponent = new OleComponent(m_xContext, this);
+ try {
+ pNewOleComponent->InitEmbeddedCopyOfLink(m_pOleComponent);
+ }
+ catch (const uno::Exception&)
+ {
+ if (!m_aTempURL.isEmpty())
+ KillFile_Impl(m_aTempURL, m_xContext);
+ m_aTempURL = aOldTempURL;
+ throw;
+ }
+
+ try {
+ GetRidOfComponent();
+ }
+ catch (const uno::Exception&)
+ {
+ if (!m_aTempURL.isEmpty())
+ KillFile_Impl(m_aTempURL, m_xContext);
+ m_aTempURL = aOldTempURL;
+ throw;
+ }
+
+ KillFile_Impl(aOldTempURL, m_xContext);
+
+ CreateOleComponent_Impl(pNewOleComponent);
+
+ if (m_xParentStorage != xStorage || !m_aEntryName.equals(sEntName))
+ SwitchOwnPersistence(xStorage, sEntName);
+
+ if (m_nObjectState != embed::EmbedStates::LOADED)
+ {
+ // TODO: should we activate the new object if the link was activated?
+
+ const sal_Int32 nTargetState = m_nObjectState;
+ m_nObjectState = embed::EmbedStates::LOADED;
+
+ if (nTargetState == embed::EmbedStates::RUNNING)
+ m_pOleComponent->RunObject(); // the object already was in running state, the server must be installed
+ else // nTargetState == embed::EmbedStates::ACTIVE
+ {
+ m_pOleComponent->RunObject(); // the object already was in running state, the server must be installed
+ m_pOleComponent->ExecuteVerb(embed::EmbedVerbs::MS_OLEVERB_OPEN);
+ }
+
+ m_nObjectState = nTargetState;
+ }
+
+ m_bIsLink = false;
+ m_aLinkURL.clear();
+#else // ! _WIN32
+ throw io::IOException(); //TODO:
+#endif // _WIN32
+}
+
+
+sal_Bool SAL_CALL OleEmbeddedObject::isLink()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->isLink();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ return m_bIsLink;
+}
+
+
+OUString SAL_CALL OleEmbeddedObject::getLinkURL()
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XLinkageSupport > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getLinkURL();
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ if ( m_bWaitSaveCompleted )
+ throw embed::WrongStateException(
+ "The object waits for saveCompleted() call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ if ( !m_bIsLink )
+ throw embed::WrongStateException(
+ "The object is not a link object!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ // TODO: probably the link URL can be retrieved from OLE
+
+ return m_aLinkURL;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/olepersist.hxx b/embeddedobj/source/msole/olepersist.hxx
new file mode 100644
index 000000000..9a3e76c68
--- /dev/null
+++ b/embeddedobj/source/msole/olepersist.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <rtl/ustring.hxx>
+
+namespace com::sun::star {
+ namespace io { class XInputStream; }
+ namespace uno { class XComponentContext; }
+}
+
+OUString GetNewTempFileURL_Impl( const css::uno::Reference< css::uno::XComponentContext >& xContext );
+
+/// @throws css::io::IOException
+/// @throws css::uno::RuntimeException
+OUString GetNewFilledTempFile_Impl(
+ css::uno::Reference<css::io::XInputStream > const & xInStream,
+ css::uno::Reference<css::uno::XComponentContext> const & xContext);
+
+bool KillFile_Impl( const OUString& aURL, const css::uno::Reference< css::uno::XComponentContext >& xContext );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/olevisual.cxx b/embeddedobj/source/msole/olevisual.cxx
new file mode 100644
index 000000000..2201d7113
--- /dev/null
+++ b/embeddedobj/source/msole/olevisual.cxx
@@ -0,0 +1,432 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/EmbedMapUnits.hpp>
+#include <com/sun/star/embed/EmbedMisc.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/WrongStateException.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+
+#include <oleembobj.hxx>
+#if defined (_WIN32)
+#include <comphelper/mimeconfighelper.hxx>
+#endif
+#include <comphelper/seqstream.hxx>
+#include <filter/msfilter/classids.hxx>
+#include <sal/log.hxx>
+
+#if defined(_WIN32)
+#include "olecomponent.hxx"
+#include <tools/diagnose_ex.h>
+#endif
+
+using namespace ::com::sun::star;
+using namespace ::comphelper;
+
+embed::VisualRepresentation OleEmbeddedObject::GetVisualRepresentationInNativeFormat_Impl(
+ const uno::Reference< io::XStream >& xCachedVisRepr )
+{
+ embed::VisualRepresentation aVisualRepr;
+
+ // TODO: detect the format in the future for now use workaround
+ uno::Reference< io::XInputStream > xInStream = xCachedVisRepr->getInputStream();
+ if ( !xInStream.is() )
+ throw uno::RuntimeException();
+ uno::Reference< io::XSeekable > xSeekable( xCachedVisRepr, uno::UNO_QUERY_THROW );
+
+ uno::Sequence< sal_Int8 > aSeq( 2 );
+ xInStream->readBytes( aSeq, 2 );
+ xSeekable->seek( 0 );
+ if ( aSeq.getLength() == 2 && aSeq[0] == 'B' && aSeq[1] == 'M' )
+ {
+ // it's a bitmap
+ aVisualRepr.Flavor = datatransfer::DataFlavor(
+ "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"",
+ "Bitmap",
+ cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
+ }
+ else
+ {
+ // it's a metafile
+ aVisualRepr.Flavor = datatransfer::DataFlavor(
+ "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"",
+ "Windows Metafile",
+ cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
+ }
+
+ sal_Int32 nStreamLength = static_cast<sal_Int32>(xSeekable->getLength());
+ uno::Sequence< sal_Int8 > aRepresent( nStreamLength );
+ xInStream->readBytes( aRepresent, nStreamLength );
+ aVisualRepr.Data <<= aRepresent;
+
+ return aVisualRepr;
+}
+
+void SAL_CALL OleEmbeddedObject::setVisualAreaSize( sal_Int64 nAspect, const awt::Size& aSize )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ xWrappedObject->setVisualAreaSize( nAspect, aSize );
+ return;
+ }
+ // end wrapping related part ====================
+
+ ::osl::ResettableMutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ SAL_WARN_IF( nAspect == embed::Aspects::MSOLE_ICON, "embeddedobj.ole", "For iconified objects no graphical replacement is required!" );
+ if ( nAspect == embed::Aspects::MSOLE_ICON )
+ // no representation can be retrieved
+ throw embed::WrongStateException( "Illegal call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object is not loaded!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+#ifdef _WIN32
+ // RECOMPOSE_ON_RESIZE misc flag means that the object has to be switched to running state on resize.
+ // SetExtent() is called only for objects that require it,
+ // it should not be called for MSWord documents to workaround problem i49369
+ // If cached size is not set, that means that this is the size initialization, so there is no need to set the real size
+ bool bAllowToSetExtent =
+ ( ( getStatus( nAspect ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE )
+ && !MimeConfigurationHelper::ClassIDsEqual(m_aClassID, MimeConfigurationHelper::GetSequenceClassID(MSO_WW8_CLASSID))
+ && m_bHasCachedSize );
+
+ if ( m_nObjectState == embed::EmbedStates::LOADED && bAllowToSetExtent )
+ {
+ aGuard.clear();
+ try {
+ changeState( embed::EmbedStates::RUNNING );
+ }
+ catch( const uno::Exception& )
+ {
+ SAL_WARN( "embeddedobj.ole", "The object should not be resized without activation!" );
+ }
+ aGuard.reset();
+ }
+
+ if ( m_pOleComponent && m_nObjectState != embed::EmbedStates::LOADED && bAllowToSetExtent )
+ {
+ awt::Size aSizeToSet = aSize;
+ aGuard.clear();
+ try {
+ m_pOleComponent->SetExtent( aSizeToSet, nAspect ); // will throw an exception in case of failure
+ m_bHasSizeToSet = false;
+ }
+ catch( const uno::Exception& )
+ {
+ // some objects do not allow to set the size even in running state
+ m_bHasSizeToSet = true;
+ m_aSizeToSet = aSizeToSet;
+ m_nAspectToSet = nAspect;
+ }
+ aGuard.reset();
+ }
+#endif
+
+ // cache the values
+ m_bHasCachedSize = true;
+ m_aCachedSize = aSize;
+ m_nCachedAspect = nAspect;
+}
+
+awt::Size SAL_CALL OleEmbeddedObject::getVisualAreaSize( sal_Int64 nAspect )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getVisualAreaSize( nAspect );
+ }
+ // end wrapping related part ====================
+
+ ::osl::ResettableMutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ SAL_WARN_IF( nAspect == embed::Aspects::MSOLE_ICON, "embeddedobj.ole", "For iconified objects no graphical replacement is required!" );
+ if ( nAspect == embed::Aspects::MSOLE_ICON )
+ // no representation can be retrieved
+ throw embed::WrongStateException( "Illegal call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object is not loaded!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ awt::Size aResult;
+
+#ifdef _WIN32
+ // TODO/LATER: Support different aspects
+ if ( m_pOleComponent && !m_bHasSizeToSet && nAspect == embed::Aspects::MSOLE_CONTENT )
+ {
+ try
+ {
+ // the cached size updated every time the object is stored
+ if ( m_bHasCachedSize )
+ {
+ aResult = m_aCachedSize;
+ }
+ else
+ {
+ // there is no internal cache
+ awt::Size aSize;
+ aGuard.clear();
+
+ bool bBackToLoaded = false;
+
+ bool bSuccess = false;
+ if ( getCurrentState() == embed::EmbedStates::LOADED )
+ {
+ SAL_WARN( "embeddedobj.ole", "Loaded object has no cached size!" );
+
+ // try to switch the object to RUNNING state and request the value again
+ try {
+ changeState( embed::EmbedStates::RUNNING );
+ // the links should be switched back to loaded state to avoid too
+ // many open MathType instances
+ bBackToLoaded = true;
+ }
+ catch( const uno::Exception& )
+ {
+ throw embed::NoVisualAreaSizeException(
+ "No size available!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+ }
+
+ try
+ {
+ // first try to get size using replacement image
+ aSize = m_pOleComponent->GetExtent( nAspect ); // will throw an exception in case of failure
+ bSuccess = true;
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OleEmbeddedObject::getVisualAreaSize: GetExtent() failed:");
+ }
+
+ if (bBackToLoaded)
+ {
+ try
+ {
+ changeState(embed::EmbedStates::LOADED);
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("embeddedobj.ole", "ignoring ");
+ }
+ }
+
+ if ( !bSuccess )
+ {
+ try
+ {
+ // second try the cached replacement image
+ aSize = m_pOleComponent->GetCachedExtent( nAspect ); // will throw an exception in case of failure
+ bSuccess = true;
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OleEmbeddedObject::getVisualAreaSize: GetCachedExtent() failed:");
+ }
+ }
+
+ if ( !bSuccess )
+ {
+ try
+ {
+ // third try the size reported by the object
+ aSize = m_pOleComponent->GetRecommendedExtent( nAspect ); // will throw an exception in case of failure
+ bSuccess = true;
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OleEmbeddedObject::getVisualAreaSize: GetRecommendedExtent() failed:");
+ }
+ }
+
+ if ( !bSuccess )
+ throw embed::NoVisualAreaSizeException(
+ "No size available!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ aGuard.reset();
+
+ m_aCachedSize = aSize;
+ m_nCachedAspect = nAspect;
+ m_bHasCachedSize = true;
+
+ aResult = m_aCachedSize;
+ }
+ }
+ catch ( const embed::NoVisualAreaSizeException& )
+ {
+ throw;
+ }
+ catch ( const uno::Exception& )
+ {
+ throw embed::NoVisualAreaSizeException(
+ "No size available!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+ }
+ else
+#endif
+ {
+ // return cached value
+ if ( !m_bHasCachedSize )
+ {
+ throw embed::NoVisualAreaSizeException(
+ "No size available!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+ SAL_WARN_IF( nAspect != m_nCachedAspect, "embeddedobj.ole", "Unexpected aspect is requested!" );
+ aResult = m_aCachedSize;
+ }
+
+ return aResult;
+}
+
+embed::VisualRepresentation SAL_CALL OleEmbeddedObject::getPreferredVisualRepresentation( sal_Int64 nAspect )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getPreferredVisualRepresentation( nAspect );
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ SAL_WARN_IF( nAspect == embed::Aspects::MSOLE_ICON, "embeddedobj.ole", "For iconified objects no graphical replacement is required!" );
+ if ( nAspect == embed::Aspects::MSOLE_ICON )
+ // no representation can be retrieved
+ throw embed::WrongStateException( "Illegal call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ // TODO: if the object has cached representation then it should be returned
+ // TODO: if the object has no cached representation and is in loaded state it should switch itself to the running state
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object is not loaded!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ // TODO: in case of different aspects they must be applied to the mediatype and XTransferable must be used
+ // the cache is used only as a fallback if object is not in loaded state
+ if ( !m_xCachedVisualRepresentation.is() && ( !m_bVisReplInitialized || m_bVisReplInStream )
+ && m_nObjectState == embed::EmbedStates::LOADED )
+ {
+ m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream, true );
+ SetVisReplInStream( m_xCachedVisualRepresentation.is() );
+ }
+
+#ifdef _WIN32
+ if ( !m_xCachedVisualRepresentation.is() && m_pOleComponent )
+ {
+ try
+ {
+ if ( m_nObjectState == embed::EmbedStates::LOADED )
+ changeState( embed::EmbedStates::RUNNING );
+
+ datatransfer::DataFlavor aDataFlavor(
+ "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"",
+ "Windows Metafile",
+ cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
+
+ embed::VisualRepresentation aVisualRepr;
+ aVisualRepr.Data = m_pOleComponent->getTransferData( aDataFlavor );
+ aVisualRepr.Flavor = aDataFlavor;
+
+ uno::Sequence< sal_Int8 > aVisReplSeq;
+ aVisualRepr.Data >>= aVisReplSeq;
+ if ( aVisReplSeq.getLength() )
+ {
+ m_xCachedVisualRepresentation = GetNewFilledTempStream_Impl(
+ uno::Reference< io::XInputStream >(
+ new ::comphelper::SequenceInputStream(aVisReplSeq)));
+ }
+
+ return aVisualRepr;
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+#endif
+
+ // the cache is used only as a fallback if object is not in loaded state
+ if ( !m_xCachedVisualRepresentation.is() && ( !m_bVisReplInitialized || m_bVisReplInStream ) )
+ {
+ m_xCachedVisualRepresentation = TryToRetrieveCachedVisualRepresentation_Impl( m_xObjectStream );
+ SetVisReplInStream( m_xCachedVisualRepresentation.is() );
+ }
+
+ if ( !m_xCachedVisualRepresentation.is() )
+ {
+ // no representation can be retrieved
+ throw embed::WrongStateException( "Illegal call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+ }
+
+ return GetVisualRepresentationInNativeFormat_Impl( m_xCachedVisualRepresentation );
+}
+
+sal_Int32 SAL_CALL OleEmbeddedObject::getMapUnit( sal_Int64 nAspect )
+{
+ // begin wrapping related part ====================
+ uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
+ if ( xWrappedObject.is() )
+ {
+ // the object was converted to OOo embedded object, the current implementation is now only a wrapper
+ return xWrappedObject->getMapUnit( nAspect );
+ }
+ // end wrapping related part ====================
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bDisposed )
+ throw lang::DisposedException(); // TODO
+
+ SAL_WARN_IF( nAspect == embed::Aspects::MSOLE_ICON, "embeddedobj.ole", "For iconified objects no graphical replacement is required!" );
+ if ( nAspect == embed::Aspects::MSOLE_ICON )
+ // no representation can be retrieved
+ throw embed::WrongStateException( "Illegal call!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ if ( m_nObjectState == -1 )
+ throw embed::WrongStateException( "The object is not loaded!",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ return embed::EmbedMapUnits::ONE_100TH_MM;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/olewrapclient.cxx b/embeddedobj/source/msole/olewrapclient.cxx
new file mode 100644
index 000000000..15d5f1663
--- /dev/null
+++ b/embeddedobj/source/msole/olewrapclient.cxx
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+
+#include "olewrapclient.hxx"
+#include "olecomponent.hxx"
+
+// TODO: May be a mutex must be introduced
+
+OleWrapperClientSite::OleWrapperClientSite( OleComponent* pOleComp )
+: m_nRefCount( 0 )
+, m_pOleComp( pOleComp )
+{
+ OSL_ENSURE( m_pOleComp, "No ole component is provided!" );
+}
+
+OleWrapperClientSite::~OleWrapperClientSite()
+{
+}
+
+STDMETHODIMP OleWrapperClientSite::QueryInterface( REFIID riid , void** ppv )
+{
+ *ppv=nullptr;
+
+ if ( riid == IID_IUnknown )
+ *ppv = static_cast<IUnknown*>(this);
+
+ if ( riid == IID_IOleClientSite )
+ *ppv = static_cast<IOleClientSite*>(this);
+
+ if ( *ppv != nullptr )
+ {
+ static_cast<IUnknown*>(*ppv)->AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) OleWrapperClientSite::AddRef()
+{
+ return osl_atomic_increment( &m_nRefCount);
+}
+
+STDMETHODIMP_(ULONG) OleWrapperClientSite::Release()
+{
+ ULONG nReturn = --m_nRefCount;
+ if ( m_nRefCount == 0 )
+ delete this;
+
+ return nReturn;
+}
+
+void OleWrapperClientSite::disconnectOleComponent()
+{
+ // must not be called from the descructor of OleComponent!!!
+ osl::MutexGuard aGuard( m_aMutex );
+ m_pOleComp = nullptr;
+}
+
+STDMETHODIMP OleWrapperClientSite::SaveObject()
+{
+ OleComponent* pLockComponent = nullptr;
+ HRESULT hResult = E_FAIL;
+
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ if ( m_pOleComp )
+ {
+ pLockComponent = m_pOleComp;
+ pLockComponent->acquire();
+ }
+ }
+
+ if ( pLockComponent )
+ {
+ if ( pLockComponent->SaveObject_Impl() )
+ hResult = S_OK;
+
+ pLockComponent->release();
+ }
+
+ return hResult;
+}
+
+STDMETHODIMP OleWrapperClientSite::GetMoniker( DWORD, DWORD, IMoniker **ppmk )
+{
+ *ppmk = nullptr;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP OleWrapperClientSite::GetContainer( IOleContainer** ppContainer )
+{
+ *ppContainer = nullptr;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP OleWrapperClientSite::ShowObject()
+{
+ return S_OK;
+}
+
+STDMETHODIMP OleWrapperClientSite::OnShowWindow( BOOL bShow )
+{
+ OleComponent* pLockComponent = nullptr;
+
+ // TODO/LATER: redirect the notification to the main thread so that SolarMutex can be locked
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ if ( m_pOleComp )
+ {
+ pLockComponent = m_pOleComp;
+ pLockComponent->acquire();
+ }
+ }
+
+ if ( pLockComponent )
+ {
+ pLockComponent->OnShowWindow_Impl( bShow ); // the result is not interesting
+ pLockComponent->release();
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP OleWrapperClientSite::RequestNewObjectLayout()
+{
+ return E_NOTIMPL;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/olewrapclient.hxx b/embeddedobj/source/msole/olewrapclient.hxx
new file mode 100644
index 000000000..99f4e16ea
--- /dev/null
+++ b/embeddedobj/source/msole/olewrapclient.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <osl/interlck.h>
+#include <osl/mutex.hxx>
+#include "platform.h"
+
+class OleComponent;
+class OleWrapperClientSite : public IOleClientSite
+{
+ osl::Mutex m_aMutex;
+ oslInterlockedCount m_nRefCount;
+ OleComponent* m_pOleComp;
+
+public:
+ explicit OleWrapperClientSite(OleComponent* pOleComp);
+ virtual ~OleWrapperClientSite();
+
+ void disconnectOleComponent();
+
+ STDMETHODIMP QueryInterface(REFIID, void**) override;
+ STDMETHODIMP_(ULONG) AddRef() override;
+ STDMETHODIMP_(ULONG) Release() override;
+
+ STDMETHODIMP SaveObject() override;
+ STDMETHODIMP GetMoniker(DWORD, DWORD, IMoniker**) override;
+ STDMETHODIMP GetContainer(IOleContainer**) override;
+ STDMETHODIMP ShowObject() override;
+ STDMETHODIMP OnShowWindow(BOOL) override;
+ STDMETHODIMP RequestNewObjectLayout() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/ownview.cxx b/embeddedobj/source/msole/ownview.cxx
new file mode 100644
index 000000000..26f74f039
--- /dev/null
+++ b/embeddedobj/source/msole/ownview.cxx
@@ -0,0 +1,609 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/embed/XClassifiedObject.hpp>
+#include <com/sun/star/io/TempFile.hpp>
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+
+#include <com/sun/star/document/XEventBroadcaster.hpp>
+#include <com/sun/star/document/XEventListener.hpp>
+#include <com/sun/star/document/XTypeDetection.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/mimeconfighelper.hxx>
+#include <tools/diagnose_ex.h>
+
+#include "olepersist.hxx"
+#include "ownview.hxx"
+
+
+using namespace ::com::sun::star;
+using namespace ::comphelper;
+
+namespace {
+
+class DummyHandler_Impl : public ::cppu::WeakImplHelper< task::XInteractionHandler >
+{
+public:
+ DummyHandler_Impl() {}
+
+ virtual void SAL_CALL handle( const uno::Reference< task::XInteractionRequest >& xRequest ) override;
+};
+
+}
+
+void SAL_CALL DummyHandler_Impl::handle( const uno::Reference< task::XInteractionRequest >& )
+{
+}
+
+
+// Object viewer
+
+
+OwnView_Impl::OwnView_Impl( const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< io::XInputStream >& xInputStream )
+: m_xContext( xContext )
+, m_bBusy( false )
+, m_bUseNative( false )
+{
+ if ( !xContext.is() || !xInputStream.is() )
+ throw uno::RuntimeException();
+
+ m_aTempFileURL = GetNewFilledTempFile_Impl( xInputStream, m_xContext );
+}
+
+
+OwnView_Impl::~OwnView_Impl()
+{
+ try {
+ KillFile_Impl( m_aTempFileURL, m_xContext );
+ } catch( uno::Exception& ) {}
+
+ try {
+ if ( !m_aNativeTempURL.isEmpty() )
+ KillFile_Impl( m_aNativeTempURL, m_xContext );
+ } catch( uno::Exception& ) {}
+}
+
+
+bool OwnView_Impl::CreateModelFromURL( const OUString& aFileURL )
+{
+ bool bResult = false;
+
+ if ( !aFileURL.isEmpty() )
+ {
+ try {
+ uno::Reference < frame::XDesktop2 > xDocumentLoader = frame::Desktop::create(m_xContext);
+
+ uno::Sequence< beans::PropertyValue > aArgs( m_aFilterName.isEmpty() ? 4 : 5 );
+ auto pArgs = aArgs.getArray();
+
+ pArgs[0].Name = "URL";
+ pArgs[0].Value <<= aFileURL;
+
+ pArgs[1].Name = "ReadOnly";
+ pArgs[1].Value <<= true;
+
+ pArgs[2].Name = "InteractionHandler";
+ pArgs[2].Value <<= uno::Reference< task::XInteractionHandler >( new DummyHandler_Impl() );
+
+ pArgs[3].Name = "DontEdit";
+ pArgs[3].Value <<= true;
+
+ if ( !m_aFilterName.isEmpty() )
+ {
+ pArgs[4].Name = "FilterName";
+ pArgs[4].Value <<= m_aFilterName;
+ }
+
+ uno::Reference< frame::XModel > xModel( xDocumentLoader->loadComponentFromURL(
+ aFileURL,
+ "_blank",
+ 0,
+ aArgs ),
+ uno::UNO_QUERY );
+
+ if ( xModel.is() )
+ {
+ uno::Reference< document::XEventBroadcaster > xBroadCaster( xModel, uno::UNO_QUERY );
+ if ( xBroadCaster.is() )
+ xBroadCaster->addEventListener( uno::Reference< document::XEventListener >(this) );
+
+ uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
+ if ( xCloseable.is() )
+ {
+ xCloseable->addCloseListener( uno::Reference< util::XCloseListener >(this) );
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_xModel = xModel;
+ bResult = true;
+ }
+ }
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("embeddedobj.ole", "OwnView_Impl::CreateModelFromURL:");
+ }
+ }
+
+ return bResult;
+}
+
+
+bool OwnView_Impl::CreateModel( bool bUseNative )
+{
+ bool bResult = false;
+
+ try {
+ bResult = CreateModelFromURL( bUseNative ? m_aNativeTempURL : m_aTempFileURL );
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ return bResult;
+}
+
+
+OUString OwnView_Impl::GetFilterNameFromExtentionAndInStream(
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ std::u16string_view aNameWithExtention,
+ const uno::Reference< io::XInputStream >& xInputStream )
+{
+ if ( !xInputStream.is() )
+ throw uno::RuntimeException();
+
+ uno::Reference< document::XTypeDetection > xTypeDetection(
+ xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", xContext),
+ uno::UNO_QUERY_THROW );
+
+ OUString aTypeName;
+
+ if ( !aNameWithExtention.empty() )
+ {
+ OUString aURLToAnalyze = OUString::Concat("file:///") + aNameWithExtention;
+ aTypeName = xTypeDetection->queryTypeByURL( aURLToAnalyze );
+ }
+
+ uno::Sequence< beans::PropertyValue > aArgs( aTypeName.isEmpty() ? 2 : 3 );
+ auto pArgs = aArgs.getArray();
+ pArgs[0].Name = "URL";
+ pArgs[0].Value <<= OUString( "private:stream" );
+ pArgs[1].Name = "InputStream";
+ pArgs[1].Value <<= xInputStream;
+ if ( !aTypeName.isEmpty() )
+ {
+ pArgs[2].Name = "TypeName";
+ pArgs[2].Value <<= aTypeName;
+ }
+
+ aTypeName = xTypeDetection->queryTypeByDescriptor( aArgs, true );
+
+ OUString aFilterName;
+ for ( beans::PropertyValue const & prop : std::as_const(aArgs) )
+ if ( prop.Name == "FilterName" )
+ prop.Value >>= aFilterName;
+
+ if ( aFilterName.isEmpty() && !aTypeName.isEmpty() )
+ {
+ // get the default filter name for the type
+ uno::Reference< container::XNameAccess > xNameAccess( xTypeDetection, uno::UNO_QUERY_THROW );
+ uno::Sequence< beans::PropertyValue > aTypes;
+
+ if ( xNameAccess.is() && ( xNameAccess->getByName( aTypeName ) >>= aTypes ) )
+ {
+ for ( beans::PropertyValue const & prop : std::as_const(aTypes) )
+ {
+ if ( prop.Name == "PreferredFilter" && ( prop.Value >>= aFilterName ) )
+ {
+ prop.Value >>= aFilterName;
+ break;
+ }
+ }
+ }
+ }
+
+ return aFilterName;
+}
+
+
+bool OwnView_Impl::ReadContentsAndGenerateTempFile( const uno::Reference< io::XInputStream >& xInStream,
+ bool bParseHeader )
+{
+ uno::Reference< io::XSeekable > xSeekable( xInStream, uno::UNO_QUERY_THROW );
+ xSeekable->seek( 0 );
+
+ // create m_aNativeTempURL
+ OUString aNativeTempURL;
+ uno::Reference < io::XTempFile > xNativeTempFile(
+ io::TempFile::create(m_xContext),
+ uno::UNO_SET_THROW );
+ uno::Reference < io::XOutputStream > xNativeOutTemp = xNativeTempFile->getOutputStream();
+ uno::Reference < io::XInputStream > xNativeInTemp = xNativeTempFile->getInputStream();
+ if ( !xNativeOutTemp.is() || !xNativeInTemp.is() )
+ throw uno::RuntimeException();
+
+ try {
+ xNativeTempFile->setRemoveFile( false );
+ aNativeTempURL = xNativeTempFile->getUri();
+ }
+ catch ( uno::Exception& )
+ {
+ }
+
+ bool bFailed = false;
+ OUString aFileSuffix;
+
+ if ( bParseHeader )
+ {
+ uno::Sequence< sal_Int8 > aReadSeq( 4 );
+ // read the complete size of the Object Package
+ if ( xInStream->readBytes( aReadSeq, 4 ) != 4 )
+ return false;
+ // read the first header ( have no idea what does this header mean )
+ if ( xInStream->readBytes( aReadSeq, 2 ) != 2 || aReadSeq[0] != 2 || aReadSeq[1] != 0 )
+ return false;
+
+ // read file name
+ // only extension is interesting so only subset of symbols is accepted
+ do
+ {
+ if ( xInStream->readBytes( aReadSeq, 1 ) != 1 )
+ return false;
+
+ if (
+ (aReadSeq[0] >= '0' && aReadSeq[0] <= '9') ||
+ (aReadSeq[0] >= 'a' && aReadSeq[0] <= 'z') ||
+ (aReadSeq[0] >= 'A' && aReadSeq[0] <= 'Z') ||
+ aReadSeq[0] == '.'
+ )
+ {
+ aFileSuffix += OUStringChar( sal_Unicode(aReadSeq[0]) );
+ }
+
+ } while( aReadSeq[0] );
+
+ // skip url
+ do
+ {
+ if ( xInStream->readBytes( aReadSeq, 1 ) != 1 )
+ return false;
+ } while( aReadSeq[0] );
+
+ // check the next header
+ if ( xInStream->readBytes( aReadSeq, 4 ) != 4
+ || aReadSeq[0] || aReadSeq[1] || aReadSeq[2] != 3 || aReadSeq[3] )
+ return false;
+
+ // get the size of the next entry
+ if ( xInStream->readBytes( aReadSeq, 4 ) != 4 )
+ return false;
+
+ sal_uInt32 nUrlSize = static_cast<sal_uInt8>(aReadSeq[0])
+ + static_cast<sal_uInt8>(aReadSeq[1]) * 0x100
+ + static_cast<sal_uInt8>(aReadSeq[2]) * 0x10000
+ + static_cast<sal_uInt8>(aReadSeq[3]) * 0x1000000;
+ sal_Int64 nTargetPos = xSeekable->getPosition() + nUrlSize;
+
+ xSeekable->seek( nTargetPos );
+
+ // get the size of stored data
+ if ( xInStream->readBytes( aReadSeq, 4 ) != 4 )
+ return false;
+
+ sal_uInt32 nDataSize = static_cast<sal_uInt8>(aReadSeq[0])
+ + static_cast<sal_uInt8>(aReadSeq[1]) * 0x100
+ + static_cast<sal_uInt8>(aReadSeq[2]) * 0x10000
+ + static_cast<sal_uInt8>(aReadSeq[3]) * 0x1000000;
+
+ aReadSeq.realloc( 32000 );
+ sal_uInt32 nRead = 0;
+ while ( nRead < nDataSize )
+ {
+ sal_uInt32 nToRead = std::min<sal_uInt32>( nDataSize - nRead, 32000 );
+ sal_uInt32 nLocalRead = xInStream->readBytes( aReadSeq, nToRead );
+
+
+ if ( !nLocalRead )
+ {
+ bFailed = true;
+ break;
+ }
+ else if ( nLocalRead == 32000 )
+ xNativeOutTemp->writeBytes( aReadSeq );
+ else
+ {
+ uno::Sequence< sal_Int8 > aToWrite( aReadSeq );
+ aToWrite.realloc( nLocalRead );
+ xNativeOutTemp->writeBytes( aToWrite );
+ }
+
+ nRead += nLocalRead;
+ }
+ }
+ else
+ {
+ uno::Sequence< sal_Int8 > aData( 8 );
+ if ( xInStream->readBytes( aData, 8 ) == 8
+ && aData[0] == -1 && aData[1] == -1 && aData[2] == -1 && aData[3] == -1
+ && ( aData[4] == 2 || aData[4] == 3 ) && aData[5] == 0 && aData[6] == 0 && aData[7] == 0 )
+ {
+ // the header has to be removed
+ xSeekable->seek( 40 );
+ }
+ else
+ {
+ // the usual Ole10Native format
+ xSeekable->seek( 4 );
+ }
+
+ ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xNativeOutTemp );
+ }
+
+ xNativeOutTemp->closeOutput();
+
+ // The temporary native file is created, now the filter must be detected
+ if ( !bFailed )
+ {
+ m_aFilterName = GetFilterNameFromExtentionAndInStream( m_xContext, aFileSuffix, xNativeInTemp );
+ m_aNativeTempURL = aNativeTempURL;
+ }
+
+ return !bFailed;
+}
+
+
+void OwnView_Impl::CreateNative()
+{
+ if ( !m_aNativeTempURL.isEmpty() )
+ return;
+
+ try
+ {
+ uno::Reference < ucb::XSimpleFileAccess3 > xAccess(
+ ucb::SimpleFileAccess::create( m_xContext ) );
+
+ uno::Reference< io::XInputStream > xInStream = xAccess->openFileRead( m_aTempFileURL );
+ if ( !xInStream.is() )
+ throw uno::RuntimeException();
+
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xInStream) };
+ uno::Reference< container::XNameAccess > xNameAccess(
+ m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.embed.OLESimpleStorage",
+ aArgs, m_xContext ),
+ uno::UNO_QUERY_THROW );
+
+ OUString aSubStreamName = "\1Ole10Native";
+ uno::Reference< embed::XClassifiedObject > xStor( xNameAccess, uno::UNO_QUERY_THROW );
+ uno::Sequence< sal_Int8 > aStorClassID = xStor->getClassID();
+
+ if ( xNameAccess->hasByName( aSubStreamName ) )
+ {
+ sal_uInt8 const aClassID[] =
+ { 0x00, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
+ // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence
+ uno::Sequence< sal_Int8 > aPackageClassID( reinterpret_cast<sal_Int8 const *>(aClassID), 16 );
+
+ uno::Reference< io::XStream > xSubStream;
+ xNameAccess->getByName( aSubStreamName ) >>= xSubStream;
+ if ( xSubStream.is() )
+ {
+ bool bOk = false;
+
+ if ( MimeConfigurationHelper::ClassIDsEqual( aPackageClassID, aStorClassID ) )
+ {
+ // the storage represents Object Package
+
+ bOk = ReadContentsAndGenerateTempFile( xSubStream->getInputStream(), true );
+
+ if ( !bOk && !m_aNativeTempURL.isEmpty() )
+ {
+ KillFile_Impl( m_aNativeTempURL, m_xContext );
+ m_aNativeTempURL.clear();
+ }
+ }
+
+ if ( !bOk )
+ {
+ bOk = ReadContentsAndGenerateTempFile( xSubStream->getInputStream(), false );
+
+ if ( !bOk && !m_aNativeTempURL.isEmpty() )
+ {
+ KillFile_Impl( m_aNativeTempURL, m_xContext );
+ m_aNativeTempURL.clear();
+ }
+ }
+ }
+ }
+ else
+ {
+ // TODO/LATER: No native stream, needs a new solution
+ }
+ }
+ catch( uno::Exception& )
+ {}
+}
+
+
+bool OwnView_Impl::Open()
+{
+ bool bResult = false;
+
+ uno::Reference< frame::XModel > xExistingModel;
+
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ xExistingModel = m_xModel;
+ if ( m_bBusy )
+ return false;
+
+ m_bBusy = true;
+ }
+
+ if ( xExistingModel.is() )
+ {
+ try {
+ uno::Reference< frame::XController > xController = xExistingModel->getCurrentController();
+ if ( xController.is() )
+ {
+ uno::Reference< frame::XFrame > xFrame = xController->getFrame();
+ if ( xFrame.is() )
+ {
+ xFrame->activate();
+ uno::Reference<awt::XTopWindow> xTopWindow( xFrame->getContainerWindow(), uno::UNO_QUERY );
+ if(xTopWindow.is())
+ xTopWindow->toFront();
+
+ bResult = true;
+ }
+ }
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ else
+ {
+ bResult = CreateModel( m_bUseNative );
+
+ if ( !bResult && !m_bUseNative )
+ {
+ // the original storage can not be recognized
+ if ( m_aNativeTempURL.isEmpty() )
+ {
+ // create a temporary file for the native representation if there is no
+ CreateNative();
+ }
+
+ if ( !m_aNativeTempURL.isEmpty() )
+ {
+ bResult = CreateModel( true );
+ if ( bResult )
+ m_bUseNative = true;
+ }
+ }
+ }
+
+ m_bBusy = false;
+
+ return bResult;
+}
+
+
+void OwnView_Impl::Close()
+{
+ uno::Reference< frame::XModel > xModel;
+
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !m_xModel.is() )
+ return;
+ xModel = m_xModel;
+ m_xModel.clear();
+
+ if ( m_bBusy )
+ return;
+
+ m_bBusy = true;
+ }
+
+ try {
+ uno::Reference< document::XEventBroadcaster > xBroadCaster( xModel, uno::UNO_QUERY );
+ if ( xBroadCaster.is() )
+ xBroadCaster->removeEventListener( uno::Reference< document::XEventListener >( this ) );
+
+ uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
+ if ( xCloseable.is() )
+ {
+ xCloseable->removeCloseListener( uno::Reference< util::XCloseListener >( this ) );
+ xCloseable->close( true );
+ }
+ }
+ catch( uno::Exception& )
+ {}
+
+ m_bBusy = false;
+}
+
+
+void SAL_CALL OwnView_Impl::notifyEvent( const document::EventObject& aEvent )
+{
+
+ uno::Reference< frame::XModel > xModel;
+
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( aEvent.Source == m_xModel && aEvent.EventName == "OnSaveAsDone" )
+ {
+ // SaveAs operation took place, so just forget the model and deregister listeners
+ xModel = m_xModel;
+ m_xModel.clear();
+ }
+ }
+
+ if ( !xModel.is() )
+ return;
+
+ try {
+ uno::Reference< document::XEventBroadcaster > xBroadCaster( xModel, uno::UNO_QUERY );
+ if ( xBroadCaster.is() )
+ xBroadCaster->removeEventListener( uno::Reference< document::XEventListener >( this ) );
+
+ uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
+ if ( xCloseable.is() )
+ xCloseable->removeCloseListener( uno::Reference< util::XCloseListener >( this ) );
+ }
+ catch( uno::Exception& )
+ {}
+}
+
+
+void SAL_CALL OwnView_Impl::queryClosing( const lang::EventObject&, sal_Bool )
+{
+}
+
+
+void SAL_CALL OwnView_Impl::notifyClosing( const lang::EventObject& Source )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( Source.Source == m_xModel )
+ m_xModel.clear();
+}
+
+
+void SAL_CALL OwnView_Impl::disposing( const lang::EventObject& Source )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( Source.Source == m_xModel )
+ m_xModel.clear();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/ownview.hxx b/embeddedobj/source/msole/ownview.hxx
new file mode 100644
index 000000000..d939aff86
--- /dev/null
+++ b/embeddedobj/source/msole/ownview.hxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <com/sun/star/util/XCloseListener.hpp>
+#include <com/sun/star/document/XEventListener.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include <osl/mutex.hxx>
+
+class OwnView_Impl : public ::cppu::WeakImplHelper < css::util::XCloseListener,
+ css::document::XEventListener >
+{
+ ::osl::Mutex m_aMutex;
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::frame::XModel > m_xModel;
+
+ OUString m_aTempFileURL;
+ OUString m_aNativeTempURL;
+
+ OUString m_aFilterName;
+
+ bool m_bBusy;
+
+ bool m_bUseNative;
+
+private:
+ bool CreateModelFromURL( const OUString& aFileURL );
+
+ bool CreateModel( bool bUseNative );
+
+ bool ReadContentsAndGenerateTempFile( const css::uno::Reference< css::io::XInputStream >& xStream, bool bParseHeader );
+
+ void CreateNative();
+
+public:
+ static OUString GetFilterNameFromExtentionAndInStream(
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ std::u16string_view aNameWithExtention,
+ const css::uno::Reference< css::io::XInputStream >& xInputStream );
+
+ OwnView_Impl( const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::io::XInputStream >& xStream );
+ virtual ~OwnView_Impl() override;
+
+ bool Open();
+
+ void Close();
+
+ virtual void SAL_CALL notifyEvent( const css::document::EventObject& Event ) override;
+
+ virtual void SAL_CALL queryClosing( const css::lang::EventObject& Source, sal_Bool GetsOwnership ) override;
+ virtual void SAL_CALL notifyClosing( const css::lang::EventObject& Source ) override;
+
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/platform.h b/embeddedobj/source/msole/platform.h
new file mode 100644
index 000000000..68127b662
--- /dev/null
+++ b/embeddedobj/source/msole/platform.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#define STRICT
+#define _ATL_APARTMENT_THREADED
+
+#if !defined WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <ole2.h>
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/xdialogcreator.cxx b/embeddedobj/source/msole/xdialogcreator.cxx
new file mode 100644
index 000000000..7e4e99156
--- /dev/null
+++ b/embeddedobj/source/msole/xdialogcreator.cxx
@@ -0,0 +1,356 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <com/sun/star/embed/EmbeddedObjectCreator.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/EntryInitModes.hpp>
+#include <com/sun/star/embed/OLEEmbeddedObjectFactory.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/ucb/CommandAbortedException.hpp>
+#include <com/sun/star/task/XStatusIndicatorFactory.hpp>
+
+#include <osl/thread.h>
+#include <osl/file.hxx>
+#include <osl/module.hxx>
+#include <comphelper/classids.hxx>
+
+#include "platform.h"
+#include <comphelper/mimeconfighelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+
+#include "xdialogcreator.hxx"
+#include <oleembobj.hxx>
+
+
+#ifdef _WIN32
+
+#include <oledlg.h>
+#include <vcl/winscheduler.hxx>
+
+namespace {
+
+class InitializedOleGuard
+{
+public:
+ InitializedOleGuard()
+ {
+ if ( !SUCCEEDED( OleInitialize( nullptr ) ) )
+ throw css::uno::RuntimeException();
+ }
+
+ ~InitializedOleGuard()
+ {
+ OleUninitialize();
+ }
+};
+
+}
+
+extern "C" {
+typedef UINT STDAPICALLTYPE OleUIInsertObjectA_Type(LPOLEUIINSERTOBJECTA);
+}
+
+#endif
+
+
+using namespace ::com::sun::star;
+using namespace ::comphelper;
+
+static uno::Sequence< sal_Int8 > GetRelatedInternalID_Impl( const uno::Sequence< sal_Int8 >& aClassID )
+{
+ // Writer
+ if ( MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SW_OLE_EMBED_CLASSID_60 ) )
+ || MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SW_OLE_EMBED_CLASSID_8 ) ) )
+ return MimeConfigurationHelper::GetSequenceClassID( SO3_SW_CLASSID_60 );
+
+ // Calc
+ if ( MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SC_OLE_EMBED_CLASSID_60 ) )
+ || MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SC_OLE_EMBED_CLASSID_8 ) ) )
+ return MimeConfigurationHelper::GetSequenceClassID( SO3_SC_CLASSID_60 );
+
+ // Impress
+ if ( MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SIMPRESS_OLE_EMBED_CLASSID_60 ) )
+ || MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) ) )
+ return MimeConfigurationHelper::GetSequenceClassID( SO3_SIMPRESS_CLASSID_60 );
+
+ // Draw
+ if ( MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SDRAW_OLE_EMBED_CLASSID_60 ) )
+ || MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) ) )
+ return MimeConfigurationHelper::GetSequenceClassID( SO3_SDRAW_CLASSID_60 );
+
+ // Chart
+ if ( MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SCH_OLE_EMBED_CLASSID_60 ) )
+ || MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SCH_OLE_EMBED_CLASSID_8 ) ) )
+ return MimeConfigurationHelper::GetSequenceClassID( SO3_SCH_CLASSID_60 );
+
+ // Math
+ if ( MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SM_OLE_EMBED_CLASSID_60 ) )
+ || MimeConfigurationHelper::ClassIDsEqual( aClassID, MimeConfigurationHelper::GetSequenceClassID( SO3_SM_OLE_EMBED_CLASSID_8 ) ) )
+ return MimeConfigurationHelper::GetSequenceClassID( SO3_SM_CLASSID_60 );
+
+ return aClassID;
+}
+
+
+embed::InsertedObjectInfo SAL_CALL MSOLEDialogObjectCreator::createInstanceByDialog(
+ const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ const uno::Sequence< beans::PropertyValue >& aInObjArgs )
+{
+ embed::InsertedObjectInfo aObjectInfo;
+ uno::Sequence< beans::PropertyValue > aObjArgs( aInObjArgs );
+
+#ifdef _WIN32
+
+ if ( !xStorage.is() )
+ throw lang::IllegalArgumentException( "No parent storage is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 1 );
+
+ if ( !sEntName.getLength() )
+ throw lang::IllegalArgumentException( "Empty element name is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 2 );
+
+ InitializedOleGuard aGuard;
+
+ OLEUIINSERTOBJECT io = {};
+ char szFile[MAX_PATH];
+ UINT uTemp;
+
+ io.cbStruct = sizeof(io);
+ io.hWndOwner = GetActiveWindow();
+
+ szFile[0] = 0;
+ io.lpszFile = szFile;
+ io.cchFile = MAX_PATH;
+
+ io.dwFlags = IOF_SELECTCREATENEW | IOF_DISABLELINK;
+
+
+ ::osl::Module aOleDlgLib;
+ if( !aOleDlgLib.load( "oledlg" ))
+ throw uno::RuntimeException();
+
+ OleUIInsertObjectA_Type * pInsertFct = reinterpret_cast<OleUIInsertObjectA_Type *>(
+ aOleDlgLib.getSymbol( "OleUIInsertObjectA" ));
+ if( !pInsertFct )
+ throw uno::RuntimeException();
+
+ // Disable any event loop shortcuts by enabling a real timer.
+ // This way the native windows dialog won't block our own processing.
+ WinScheduler::SetForceRealTimer();
+
+ uTemp=pInsertFct(&io);
+
+ if ( OLEUI_OK != uTemp )
+ throw ucb::CommandAbortedException();
+
+ if (io.dwFlags & IOF_SELECTCREATENEW)
+ {
+ uno::Reference< embed::XEmbeddedObjectCreator > xEmbCreator = embed::EmbeddedObjectCreator::create( m_xContext );
+
+ uno::Sequence< sal_Int8 > aClassID = MimeConfigurationHelper::GetSequenceClassID( io.clsid.Data1,
+ io.clsid.Data2,
+ io.clsid.Data3,
+ io.clsid.Data4[0],
+ io.clsid.Data4[1],
+ io.clsid.Data4[2],
+ io.clsid.Data4[3],
+ io.clsid.Data4[4],
+ io.clsid.Data4[5],
+ io.clsid.Data4[6],
+ io.clsid.Data4[7] );
+
+ aClassID = GetRelatedInternalID_Impl( aClassID );
+
+ //TODO: retrieve ClassName
+ aObjectInfo.Object.set( xEmbCreator->createInstanceInitNew( aClassID, OUString(), xStorage, sEntName, aObjArgs ),
+ uno::UNO_QUERY );
+ }
+ else
+ {
+ OUString aFileName
+ = OStringToOUString( std::string_view( szFile ), osl_getThreadTextEncoding() );
+ OUString aFileURL;
+ if ( osl::FileBase::getFileURLFromSystemPath( aFileName, aFileURL ) != osl::FileBase::E_None )
+ throw uno::RuntimeException();
+
+ uno::Sequence< beans::PropertyValue > aMediaDescr{ comphelper::makePropertyValue("URL",
+ aFileURL) };
+
+ // TODO: use config helper for type detection
+ uno::Reference< embed::XEmbeddedObjectCreator > xEmbCreator;
+ ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
+
+ if ( aHelper.AddFilterNameCheckOwnFile( aMediaDescr ) )
+ xEmbCreator = embed::EmbeddedObjectCreator::create( m_xContext );
+ else
+ xEmbCreator = embed::OLEEmbeddedObjectFactory::create( m_xContext );
+
+ if ( !xEmbCreator.is() )
+ throw uno::RuntimeException();
+
+ uno::Reference<task::XStatusIndicator> xProgress;
+ OUString aProgressText;
+ comphelper::SequenceAsHashMap aMap(aInObjArgs);
+ auto it = aMap.find("StatusIndicator");
+ if (it != aMap.end())
+ {
+ it->second >>= xProgress;
+ }
+ it = aMap.find("StatusIndicatorText");
+ if (it != aMap.end())
+ {
+ it->second >>= aProgressText;
+ }
+ if (xProgress.is())
+ {
+ xProgress->start(aProgressText, 100);
+ }
+
+ aObjectInfo.Object.set( xEmbCreator->createInstanceInitFromMediaDescriptor( xStorage, sEntName, aMediaDescr, aObjArgs ),
+ uno::UNO_QUERY );
+
+ if (xProgress.is())
+ {
+ xProgress->end();
+ }
+ }
+
+ if ( ( io.dwFlags & IOF_CHECKDISPLAYASICON) && io.hMetaPict != nullptr )
+ {
+ METAFILEPICT* pMF = static_cast<METAFILEPICT*>(GlobalLock( io.hMetaPict ));
+ if ( pMF )
+ {
+ sal_uInt32 nBufSize = GetMetaFileBitsEx( pMF->hMF, 0, nullptr );
+ uno::Sequence< sal_Int8 > aMetafile( nBufSize + 22 );
+ sal_Int8* pBuf = aMetafile.getArray();
+ *reinterpret_cast<long*>( pBuf ) = 0x9ac6cdd7L;
+ *reinterpret_cast<short*>( pBuf+6 ) = SHORT(0);
+ *reinterpret_cast<short*>( pBuf+8 ) = SHORT(0);
+ *reinterpret_cast<short*>( pBuf+10 ) = static_cast<SHORT>(pMF->xExt);
+ *reinterpret_cast<short*>( pBuf+12 ) = static_cast<SHORT>(pMF->yExt);
+ *reinterpret_cast<short*>( pBuf+14 ) = USHORT(2540);
+
+ if ( nBufSize && nBufSize == GetMetaFileBitsEx( pMF->hMF, nBufSize, pBuf+22 ) )
+ {
+ datatransfer::DataFlavor aFlavor(
+ "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"",
+ "Image WMF",
+ cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
+
+ aObjectInfo.Options = { { "Icon", css::uno::Any(aMetafile) },
+ { "IconFormat", css::uno::Any(aFlavor) } };
+ }
+
+ GlobalUnlock( io.hMetaPict );
+ }
+ }
+
+ OSL_ENSURE( aObjectInfo.Object.is(), "No object was created!" );
+ if ( !aObjectInfo.Object.is() )
+ throw uno::RuntimeException();
+
+ return aObjectInfo;
+#else
+ throw lang::NoSupportException(); // TODO:
+#endif
+}
+
+
+embed::InsertedObjectInfo SAL_CALL MSOLEDialogObjectCreator::createInstanceInitFromClipboard(
+ const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntryName,
+ const uno::Sequence< beans::PropertyValue >& aObjectArgs )
+{
+ embed::InsertedObjectInfo aObjectInfo;
+
+#ifdef _WIN32
+ if ( !xStorage.is() )
+ throw lang::IllegalArgumentException( "No parent storage is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 1 );
+
+ if ( !sEntryName.getLength() )
+ throw lang::IllegalArgumentException( "Empty element name is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 2 );
+
+ uno::Reference< embed::XEmbeddedObject > xResult(
+ new OleEmbeddedObject( m_xContext ) );
+
+ uno::Reference< embed::XEmbedPersist > xPersist( xResult, uno::UNO_QUERY_THROW );
+ xPersist->setPersistentEntry( xStorage,
+ sEntryName,
+ embed::EntryInitModes::DEFAULT_INIT,
+ uno::Sequence< beans::PropertyValue >(),
+ aObjectArgs );
+
+ aObjectInfo.Object = xResult;
+
+ // TODO/LATER: in case of iconify object the icon should be stored in aObjectInfo
+
+ OSL_ENSURE( aObjectInfo.Object.is(), "No object was created!" );
+ if ( !aObjectInfo.Object.is() )
+ throw uno::RuntimeException();
+
+ return aObjectInfo;
+#else
+ throw lang::NoSupportException(); // TODO:
+#endif
+}
+
+
+OUString SAL_CALL MSOLEDialogObjectCreator::getImplementationName()
+{
+ return "com.sun.star.comp.embed.MSOLEObjectSystemCreator";
+}
+
+
+sal_Bool SAL_CALL MSOLEDialogObjectCreator::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+
+uno::Sequence< OUString > SAL_CALL MSOLEDialogObjectCreator::getSupportedServiceNames()
+{
+ return { "com.sun.star.embed.MSOLEObjectSystemCreator",
+ "com.sun.star.comp.embed.MSOLEObjectSystemCreator" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+embeddedobj_MSOLEDialogObjectCreator_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new MSOLEDialogObjectCreator(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/xdialogcreator.hxx b/embeddedobj/source/msole/xdialogcreator.hxx
new file mode 100644
index 000000000..a7c28df80
--- /dev/null
+++ b/embeddedobj/source/msole/xdialogcreator.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/embed/XInsertObjectDialog.hpp>
+#include <com/sun/star/embed/XEmbedObjectClipboardCreator.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <osl/diagnose.h>
+
+
+class MSOLEDialogObjectCreator : public ::cppu::WeakImplHelper<
+ css::embed::XInsertObjectDialog,
+ css::embed::XEmbedObjectClipboardCreator,
+ css::lang::XServiceInfo >
+{
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+public:
+ explicit MSOLEDialogObjectCreator(
+ const css::uno::Reference< css::uno::XComponentContext >& xContext )
+ : m_xContext( xContext )
+ {
+ OSL_ENSURE( xContext.is(), "No service manager is provided!" );
+ }
+
+ // XInsertObjectDialog
+ virtual css::embed::InsertedObjectInfo SAL_CALL createInstanceByDialog( const css::uno::Reference< css::embed::XStorage >& xStorage, const OUString& sEntName, const css::uno::Sequence< css::beans::PropertyValue >& lObjArgs ) override;
+
+ // XEmbedObjectClipboardCreator
+ virtual css::embed::InsertedObjectInfo SAL_CALL createInstanceInitFromClipboard( const css::uno::Reference< css::embed::XStorage >& xStorage, const OUString& sEntryName, const css::uno::Sequence< css::beans::PropertyValue >& aObjectArgs ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/xolefactory.cxx b/embeddedobj/source/msole/xolefactory.cxx
new file mode 100644
index 000000000..1a7728ef8
--- /dev/null
+++ b/embeddedobj/source/msole/xolefactory.cxx
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/embed/EntryInitModes.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+#include "xolefactory.hxx"
+#include <oleembobj.hxx>
+
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+
+using namespace ::com::sun::star;
+
+// TODO: do not create OLE objects that represent OOo documents
+
+
+uno::Reference< uno::XInterface > SAL_CALL OleEmbeddedObjectFactory::createInstanceInitFromEntry(
+ const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ const uno::Sequence< beans::PropertyValue >& aMedDescr,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ if ( !xStorage.is() )
+ throw lang::IllegalArgumentException( "No parent storage is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 1 );
+
+ if ( sEntName.isEmpty() )
+ throw lang::IllegalArgumentException( "Empty element name is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 2 );
+
+ uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY_THROW );
+
+ // detect entry existence
+ if ( !xNameAccess->hasByName( sEntName ) )
+ throw container::NoSuchElementException();
+
+ if ( !xStorage->isStreamElement( sEntName ) )
+ {
+ // if it is not an OLE object throw an exception
+ throw io::IOException(); // TODO:
+ }
+
+ uno::Reference< uno::XInterface > xResult(
+ static_cast< ::cppu::OWeakObject* > ( new OleEmbeddedObject( m_xContext, false ) ),
+ uno::UNO_QUERY );
+
+ uno::Reference< embed::XEmbedPersist > xPersist( xResult, uno::UNO_QUERY_THROW );
+ xPersist->setPersistentEntry( xStorage,
+ sEntName,
+ embed::EntryInitModes::DEFAULT_INIT,
+ aMedDescr,
+ lObjArgs );
+
+ for ( beans::PropertyValue const & prop : lObjArgs )
+ {
+ if ( prop.Name == "CloneFrom" )
+ {
+ try
+ {
+ uno::Reference < embed::XEmbeddedObject > xObj;
+ uno::Reference < embed::XEmbeddedObject > xNew( xResult, uno::UNO_QUERY );
+ prop.Value >>= xObj;
+ if ( xObj.is() )
+ xNew->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) );
+ }
+ catch ( const uno::Exception& ) {}
+ break;
+ }
+ }
+
+ return xResult;
+}
+
+
+uno::Reference< uno::XInterface > SAL_CALL OleEmbeddedObjectFactory::createInstanceInitFromMediaDescriptor(
+ const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ const uno::Sequence< beans::PropertyValue >& aMediaDescr,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ if ( !xStorage.is() )
+ throw lang::IllegalArgumentException( "No parent storage is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 1 );
+
+ if ( sEntName.isEmpty() )
+ throw lang::IllegalArgumentException( "Empty element name is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 2 );
+
+ uno::Reference< uno::XInterface > xResult(
+ static_cast< ::cppu::OWeakObject* > ( new OleEmbeddedObject( m_xContext, false ) ),
+ uno::UNO_QUERY );
+
+ uno::Reference< embed::XEmbedPersist > xPersist( xResult, uno::UNO_QUERY_THROW );
+ xPersist->setPersistentEntry( xStorage,
+ sEntName,
+ embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT,
+ aMediaDescr,
+ lObjArgs );
+
+ return xResult;
+}
+
+
+uno::Reference< uno::XInterface > SAL_CALL OleEmbeddedObjectFactory::createInstanceInitNew(
+ const uno::Sequence< sal_Int8 >& aClassID,
+ const OUString& aClassName,
+ const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ if ( !xStorage.is() )
+ throw lang::IllegalArgumentException( "No parent storage is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 3 );
+
+ if ( sEntName.isEmpty() )
+ throw lang::IllegalArgumentException( "Empty element name is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 4 );
+
+ uno::Reference< uno::XInterface > xResult(
+ static_cast< ::cppu::OWeakObject* > ( new OleEmbeddedObject( m_xContext, aClassID, aClassName ) ),
+ uno::UNO_QUERY );
+
+ uno::Reference< embed::XEmbedPersist > xPersist( xResult, uno::UNO_QUERY_THROW );
+ xPersist->setPersistentEntry( xStorage,
+ sEntName,
+ embed::EntryInitModes::TRUNCATE_INIT,
+ uno::Sequence< beans::PropertyValue >(),
+ lObjArgs );
+
+ return xResult;
+}
+
+
+uno::Reference< uno::XInterface > SAL_CALL OleEmbeddedObjectFactory::createInstanceLink(
+ const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ const uno::Sequence< beans::PropertyValue >& aMediaDescr,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ if ( !xStorage.is() )
+ throw lang::IllegalArgumentException( "No parent storage is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 1 );
+
+ if ( sEntName.isEmpty() )
+ throw lang::IllegalArgumentException( "Empty element name is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 2 );
+
+ uno::Reference< uno::XInterface > xResult(
+ static_cast< ::cppu::OWeakObject* > ( new OleEmbeddedObject( m_xContext, true ) ),
+ uno::UNO_QUERY );
+
+ uno::Reference< embed::XEmbedPersist > xPersist( xResult, uno::UNO_QUERY_THROW );
+ xPersist->setPersistentEntry( xStorage,
+ sEntName,
+ embed::EntryInitModes::MEDIA_DESCRIPTOR_INIT,
+ aMediaDescr,
+ lObjArgs );
+
+ return xResult;
+}
+
+
+uno::Reference< uno::XInterface > SAL_CALL OleEmbeddedObjectFactory::createInstanceUserInit(
+ const uno::Sequence< sal_Int8 >& aClassID,
+ const OUString& aClassName,
+ const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& sEntName,
+ sal_Int32 /*nEntryConnectionMode*/,
+ const uno::Sequence< beans::PropertyValue >& /*lArguments*/,
+ const uno::Sequence< beans::PropertyValue >& lObjArgs )
+{
+ // the initialization is completely controlled by user
+ if ( !xStorage.is() )
+ throw lang::IllegalArgumentException( "No parent storage is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 1 );
+
+ if ( sEntName.isEmpty() )
+ throw lang::IllegalArgumentException( "Empty element name is provided!",
+ static_cast< ::cppu::OWeakObject* >(this),
+ 2 );
+
+ uno::Reference< uno::XInterface > xResult(
+ static_cast< ::cppu::OWeakObject* > ( new OleEmbeddedObject( m_xContext, aClassID, aClassName ) ),
+ uno::UNO_QUERY );
+
+ uno::Reference< embed::XEmbedPersist > xPersist( xResult, uno::UNO_QUERY_THROW );
+ xPersist->setPersistentEntry( xStorage,
+ sEntName,
+ embed::EntryInitModes::DEFAULT_INIT,
+ uno::Sequence< beans::PropertyValue >(),
+ lObjArgs );
+
+ return xResult;
+}
+
+
+OUString SAL_CALL OleEmbeddedObjectFactory::getImplementationName()
+{
+ return "com.sun.star.comp.embed.OLEEmbeddedObjectFactory";
+}
+
+sal_Bool SAL_CALL OleEmbeddedObjectFactory::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+
+uno::Sequence< OUString > SAL_CALL OleEmbeddedObjectFactory::getSupportedServiceNames()
+{
+ return { "com.sun.star.embed.OLEEmbeddedObjectFactory",
+ "com.sun.star.comp.embed.OLEEmbeddedObjectFactory" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+embeddedobj_OleEmbeddedObjectFactory_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new OleEmbeddedObjectFactory(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/embeddedobj/source/msole/xolefactory.hxx b/embeddedobj/source/msole/xolefactory.hxx
new file mode 100644
index 000000000..56e632202
--- /dev/null
+++ b/embeddedobj/source/msole/xolefactory.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/embed/XEmbeddedObjectCreator.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <osl/diagnose.h>
+
+
+class OleEmbeddedObjectFactory : public ::cppu::WeakImplHelper<
+ css::embed::XEmbeddedObjectCreator,
+ css::lang::XServiceInfo >
+{
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+public:
+ explicit OleEmbeddedObjectFactory(
+ const css::uno::Reference< css::uno::XComponentContext >& xContext )
+ : m_xContext( xContext )
+ {
+ OSL_ENSURE( xContext.is(), "No service manager is provided!" );
+ }
+
+ // XEmbedObjectCreator
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceInitNew( const css::uno::Sequence< sal_Int8 >& aClassID, const OUString& aClassName, const css::uno::Reference< css::embed::XStorage >& xStorage, const OUString& sEntName, const css::uno::Sequence< css::beans::PropertyValue >& lObjArgs ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceInitFromEntry( const css::uno::Reference< css::embed::XStorage >& xStorage, const OUString& sEntName, const css::uno::Sequence< css::beans::PropertyValue >& aMedDescr, const css::uno::Sequence< css::beans::PropertyValue >& lObjArgs ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceInitFromMediaDescriptor( const css::uno::Reference< css::embed::XStorage >& xStorage, const OUString& sEntName, const css::uno::Sequence< css::beans::PropertyValue >& aMediaDescr, const css::uno::Sequence< css::beans::PropertyValue >& lObjArgs ) override;
+
+ // XEmbedObjectFactory
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceUserInit( const css::uno::Sequence< sal_Int8 >& aClassID, const OUString& aClassName, const css::uno::Reference< css::embed::XStorage >& xStorage, const OUString& sEntName, sal_Int32 nEntryConnectionMode, const css::uno::Sequence< css::beans::PropertyValue >& lArguments, const css::uno::Sequence< css::beans::PropertyValue >& lObjArgs ) override;
+
+ // XLinkCreator
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceLink( const css::uno::Reference< css::embed::XStorage >& xStorage, const OUString& sEntName, const css::uno::Sequence< css::beans::PropertyValue >& aMediaDescr, const css::uno::Sequence< css::beans::PropertyValue >& lObjArgs ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */