blob: 3bf8245045de9756153db219a544f399f6b70d7e [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_filter.hxx"
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/embed/XEmbedPersist.hpp>
#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
#include <com/sun/star/embed/EmbedStates.hpp>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/awt/Size.hpp>
#include <com/sun/star/embed/Aspects.hpp>
#include <sot/clsids.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/docfac.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/fcontnr.hxx>
#include <sot/formats.hxx>
#include <comphelper/processfactory.hxx>
#include <unotools/streamwrap.hxx>
#include <comphelper/storagehelper.hxx>
#include <svtools/embedhlp.hxx>
#include <filter/msfilter/msdffimp.hxx> // extern sichtbare Header-Datei
#include "filter/msfilter/msoleexp.hxx"
#define CREATE_CONST_ASC(s) String::CreateFromAscii( \
RTL_CONSTASCII_STRINGPARAM(s))
using namespace ::com::sun::star;
SvGlobalName GetEmbeddedVersion( const SvGlobalName& aAppName )
{
if ( aAppName == SvGlobalName( SO3_SM_CLASSID_60 ) )
return SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 );
else if ( aAppName == SvGlobalName( SO3_SW_CLASSID_60 ) )
return SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 );
else if ( aAppName == SvGlobalName( SO3_SC_CLASSID_60 ) )
return SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 );
else if ( aAppName == SvGlobalName( SO3_SDRAW_CLASSID_60 ) )
return SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 );
else if ( aAppName == SvGlobalName( SO3_SIMPRESS_CLASSID_60 ) )
return SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 );
else if ( aAppName == SvGlobalName( SO3_SCH_CLASSID_60 ) )
return SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 );
return SvGlobalName();
}
String GetStorageType( const SvGlobalName& aEmbName )
{
if ( aEmbName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) )
return String::CreateFromAscii( "opendocument.MathDocument.1" );
else if ( aEmbName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) )
return String::CreateFromAscii( "opendocument.WriterDocument.1" );
else if ( aEmbName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) )
return String::CreateFromAscii( "opendocument.CalcDocument.1" );
else if ( aEmbName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) )
return String::CreateFromAscii( "opendocument.DrawDocument.1" );
else if ( aEmbName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) )
return String::CreateFromAscii( "opendocument.ImpressDocument.1" );
else if ( aEmbName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) )
return String::CreateFromAscii( "opendocument.ChartDocument.1" );
return String();
}
sal_Bool UseOldMSExport()
{
uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
if ( xFactory.is() )
{
uno::Reference< lang::XMultiServiceFactory > xProvider( xFactory->createInstance(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider"))),
uno::UNO_QUERY);
if ( xProvider.is() )
{
try {
uno::Sequence< uno::Any > aArg( 1 );
aArg[0] <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/InternalMSExport") );
uno::Reference< container::XNameAccess > xNameAccess(
xProvider->createInstanceWithArguments(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationUpdateAccess" ) ),
aArg ),
uno::UNO_QUERY );
if ( xNameAccess.is() )
{
uno::Any aResult = xNameAccess->getByName(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseOldExport" ) ) );
sal_Bool bResult = sal_Bool();
if ( aResult >>= bResult )
return bResult;
}
}
catch( uno::Exception& )
{
}
}
}
OSL_ENSURE( sal_False, "Could not get access to configuration entry!\n" );
return sal_False;
}
void SvxMSExportOLEObjects::ExportOLEObject( const com::sun::star::uno::Reference < com::sun::star::embed::XEmbeddedObject>& rObj, SotStorage& rDestStg )
{
svt::EmbeddedObjectRef aObj( rObj, embed::Aspects::MSOLE_CONTENT );
ExportOLEObject( aObj, rDestStg );
}
void SvxMSExportOLEObjects::ExportOLEObject( svt::EmbeddedObjectRef& rObj, SvStorage& rDestStg )
{
SvGlobalName aOwnGlobalName;
SvGlobalName aObjName( rObj->getClassID() );
const SfxFilter* pExpFilter = NULL;
{
static struct _ObjExpType {
sal_uInt32 nFlag;
const char* pFilterNm;
// GlobalNameId
struct _GlobalNameIds {
sal_uInt32 n1;
sal_uInt16 n2, n3;
sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15;
}
aGlNmIds[4];
} aArr[] = {
{ OLE_STARMATH_2_MATHTYPE, "MathType 3.x",
{{SO3_SM_CLASSID_60}, {SO3_SM_CLASSID_50},
{SO3_SM_CLASSID_40}, {SO3_SM_CLASSID_30 }}},
{ OLE_STARWRITER_2_WINWORD, "MS Word 97",
{{SO3_SW_CLASSID_60}, {SO3_SW_CLASSID_50},
{SO3_SW_CLASSID_40}, {SO3_SW_CLASSID_30 }}},
{ OLE_STARCALC_2_EXCEL, "MS Excel 97",
{{SO3_SC_CLASSID_60}, {SO3_SC_CLASSID_50},
{SO3_SC_CLASSID_40}, {SO3_SC_CLASSID_30 }}},
{ OLE_STARIMPRESS_2_POWERPOINT, "MS PowerPoint 97",
{{SO3_SIMPRESS_CLASSID_60}, {SO3_SIMPRESS_CLASSID_50},
{SO3_SIMPRESS_CLASSID_40}, {SO3_SIMPRESS_CLASSID_30 }}},
{ 0, "",
{{SO3_SCH_CLASSID_60}, {SO3_SCH_CLASSID_50},
{SO3_SCH_CLASSID_40}, {SO3_SCH_CLASSID_30 }}},
{ 0, "",
{{SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50}, // SJ: !!!! SO3_SDRAW_CLASSID is only available up from
{SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50 }}}, // ver 5.0, it is purpose to have double entrys here.
{ 0xffff,0,
{{SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50},
{SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50}}}
};
for( const _ObjExpType* pArr = aArr; !pExpFilter && ( pArr->nFlag != 0xffff ); ++pArr )
{
for ( int n = 0; n < 4; ++n )
{
const _ObjExpType::_GlobalNameIds& rId = pArr->aGlNmIds[ n ];
SvGlobalName aGlbNm( rId.n1, rId.n2, rId.n3,
rId.b8, rId.b9, rId.b10, rId.b11,
rId.b12, rId.b13, rId.b14, rId.b15 );
if( aObjName == aGlbNm )
{
aOwnGlobalName = aGlbNm;
// flags for checking if conversion is wanted at all (SaveOptions?!)
if( GetFlags() & pArr->nFlag )
{
pExpFilter = SfxFilterMatcher().GetFilter4FilterName(String::CreateFromAscii(pArr->pFilterNm));
break;
}
}
}
}
}
if( pExpFilter ) // use this filter for the export
{
try
{
if ( rObj->getCurrentState() == embed::EmbedStates::LOADED )
rObj->changeState( embed::EmbedStates::RUNNING );
//TODO/LATER: is stream instead of outputstream a better choice?!
//TODO/LATER: a "StoreTo" method at embedded object would be nice
uno::Sequence < beans::PropertyValue > aSeq(2);
SvStream* pStream = new SvMemoryStream;
aSeq[0].Name = ::rtl::OUString::createFromAscii( "OutputStream" );
::uno::Reference < io::XOutputStream > xOut = new ::utl::OOutputStreamWrapper( *pStream );
aSeq[0].Value <<= xOut;
aSeq[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ) );
aSeq[1].Value <<= ::rtl::OUString( pExpFilter->GetName() );
uno::Reference < frame::XStorable > xStor( rObj->getComponent(), uno::UNO_QUERY );
xStor->storeToURL( ::rtl::OUString::createFromAscii( "private:stream" ), aSeq );
SotStorageRef xOLEStor = new SotStorage( pStream, sal_True );
xOLEStor->CopyTo( &rDestStg );
rDestStg.Commit();
}
catch( uno::Exception& )
{
// TODO/LATER: Error handling
DBG_ERROR( "The object could not be exported!" );
}
}
else if( aOwnGlobalName != SvGlobalName() )
{
// own format, maybe SO6 format or lower
SvGlobalName aEmbName = GetEmbeddedVersion( aOwnGlobalName );
if ( aEmbName != SvGlobalName() && !UseOldMSExport() )
{
// this is a SO6 embedded object, save in old binary format
rDestStg.SetVersion( SOFFICE_FILEFORMAT_31 );
rDestStg.SetClass( aEmbName,
SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE,
GetStorageType( aEmbName ) );
SotStorageStreamRef xExtStm = rDestStg.OpenSotStream(
String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "properties_stream" ) ),
STREAM_STD_READWRITE );
sal_Bool bExtentSuccess = sal_False;
if( !xExtStm->GetError() )
{
// write extent
//TODO/MBA: check if writing a size is enough
if( rObj.GetObject().is() )
{
// MSOLE objects don't need to be in running state for VisualArea access
awt::Size aSize;
try
{
// this is an own object, the content size must be stored in the
// extension stream
aSize = rObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
}
catch( embed::NoVisualAreaSizeException& )
{
OSL_ENSURE( sal_False, "Could not get visual area size!\n" );
aSize.Width = 5000;
aSize.Height = 5000;
}
catch( uno::Exception& )
{
OSL_ENSURE( sal_False, "Unexpected exception while getting visual area size!\n" );
aSize.Width = 5000;
aSize.Height = 5000;
}
//Rectangle aVisArea = xSfxIPObj->GetVisArea( ASPECT_CONTENT );
sal_Int32 pRect[4];
//pRect[0] = aVisArea.Left();
//pRect[1] = aVisArea.Right();
//pRect[2] = aVisArea.Top();
//pRect[3] = aVisArea.Bottom();
pRect[0] = 0;
pRect[1] = aSize.Width;
pRect[2] = 0;
pRect[3] = aSize.Height;
sal_Int8 aWriteSet[16];
for ( int ind = 0; ind < 4; ind++ )
{
sal_Int32 nVal = pRect[ind];
for ( int nByte = 0; nByte < 4; nByte++ )
{
aWriteSet[ind*4+nByte] = (sal_Int8) nVal % 0x100;
nVal /= 0x100;
}
}
bExtentSuccess = ( xExtStm->Write( aWriteSet, 16 ) == 16 );
}
}
if ( bExtentSuccess )
{
SotStorageStreamRef xEmbStm = rDestStg.OpenSotStream(
String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "package_stream" ) ),
STREAM_STD_READWRITE );
if( !xEmbStm->GetError() )
{
try
{
if ( rObj->getCurrentState() == embed::EmbedStates::LOADED )
rObj->changeState( embed::EmbedStates::RUNNING );
//TODO/LATER: is stream instead of outputstream a better choice?!
//TODO/LATER: a "StoreTo" method at embedded object would be nice
uno::Sequence < beans::PropertyValue > aSeq(1);
aSeq[0].Name = ::rtl::OUString::createFromAscii( "OutputStream" );
::uno::Reference < io::XOutputStream > xOut = new ::utl::OOutputStreamWrapper( *xEmbStm );
aSeq[0].Value <<= xOut;
uno::Reference < frame::XStorable > xStor( rObj->getComponent(), uno::UNO_QUERY );
xStor->storeToURL( ::rtl::OUString::createFromAscii( "private:stream" ), aSeq );
}
catch( uno::Exception& )
{
// TODO/LATER: Error handling
DBG_ERROR( "The object could not be exported!" );
}
}
}
}
else
{
DBG_ERROR("Own binary format inside own container document!");
}
}
else
{
// alien objects
//TODO/LATER: a "StoreTo" method at embedded object would be nice
rDestStg.SetVersion( SOFFICE_FILEFORMAT_31 );
uno::Reference < embed::XStorage > xStor = ::comphelper::OStorageHelper::GetTemporaryStorage();
uno::Reference < embed::XEmbedPersist > xPers( rObj.GetObject(), uno::UNO_QUERY );
if ( xPers.is() )
{
uno::Sequence < beans::PropertyValue > aEmptySeq;
::rtl::OUString aTempName(::rtl::OUString::createFromAscii("bla"));
try
{
xPers->storeToEntry( xStor, aTempName, aEmptySeq, aEmptySeq );
}
catch ( uno::Exception& )
{}
SotStorageRef xOLEStor = SotStorage::OpenOLEStorage( xStor, aTempName, STREAM_STD_READ );
xOLEStor->CopyTo( &rDestStg );
rDestStg.Commit();
}
}
//We never need this stream: See #99809# and #i2179#
rDestStg.Remove(CREATE_CONST_ASC(SVEXT_PERSIST_STREAM));
}