1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_filter.hxx" 30 #include <com/sun/star/uno/Reference.hxx> 31 #include <com/sun/star/uno/Sequence.hxx> 32 #include <com/sun/star/uno/Any.hxx> 33 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 34 #include <com/sun/star/container/XNameAccess.hpp> 35 #include <com/sun/star/embed/XEmbedPersist.hpp> 36 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp> 37 #include <com/sun/star/embed/EmbedStates.hpp> 38 #include <com/sun/star/frame/XStorable.hpp> 39 #include <com/sun/star/awt/Size.hpp> 40 #include <com/sun/star/embed/Aspects.hpp> 41 #include <sot/clsids.hxx> 42 #include <sfx2/objsh.hxx> 43 #include <sfx2/docfac.hxx> 44 #include <sfx2/docfilt.hxx> 45 #include <sfx2/docfile.hxx> 46 #include <sfx2/fcontnr.hxx> 47 #include <sot/formats.hxx> 48 #include <comphelper/processfactory.hxx> 49 #include <unotools/streamwrap.hxx> 50 #include <comphelper/storagehelper.hxx> 51 #include <svtools/embedhlp.hxx> 52 #include <filter/msfilter/msdffimp.hxx> // extern sichtbare Header-Datei 53 54 #include "filter/msfilter/msoleexp.hxx" 55 56 #define CREATE_CONST_ASC(s) String::CreateFromAscii( \ 57 RTL_CONSTASCII_STRINGPARAM(s)) 58 59 using namespace ::com::sun::star; 60 61 SvGlobalName GetEmbeddedVersion( const SvGlobalName& aAppName ) 62 { 63 if ( aAppName == SvGlobalName( SO3_SM_CLASSID_60 ) ) 64 return SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ); 65 else if ( aAppName == SvGlobalName( SO3_SW_CLASSID_60 ) ) 66 return SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ); 67 else if ( aAppName == SvGlobalName( SO3_SC_CLASSID_60 ) ) 68 return SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ); 69 else if ( aAppName == SvGlobalName( SO3_SDRAW_CLASSID_60 ) ) 70 return SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ); 71 else if ( aAppName == SvGlobalName( SO3_SIMPRESS_CLASSID_60 ) ) 72 return SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ); 73 else if ( aAppName == SvGlobalName( SO3_SCH_CLASSID_60 ) ) 74 return SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ); 75 76 return SvGlobalName(); 77 } 78 79 String GetStorageType( const SvGlobalName& aEmbName ) 80 { 81 if ( aEmbName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) ) 82 return String::CreateFromAscii( "opendocument.MathDocument.1" ); 83 else if ( aEmbName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) ) 84 return String::CreateFromAscii( "opendocument.WriterDocument.1" ); 85 else if ( aEmbName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) ) 86 return String::CreateFromAscii( "opendocument.CalcDocument.1" ); 87 else if ( aEmbName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) ) 88 return String::CreateFromAscii( "opendocument.DrawDocument.1" ); 89 else if ( aEmbName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) ) 90 return String::CreateFromAscii( "opendocument.ImpressDocument.1" ); 91 else if ( aEmbName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) ) 92 return String::CreateFromAscii( "opendocument.ChartDocument.1" ); 93 94 return String(); 95 } 96 97 sal_Bool UseOldMSExport() 98 { 99 uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); 100 101 if ( xFactory.is() ) 102 { 103 uno::Reference< lang::XMultiServiceFactory > xProvider( xFactory->createInstance( 104 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider"))), 105 uno::UNO_QUERY); 106 if ( xProvider.is() ) 107 { 108 try { 109 uno::Sequence< uno::Any > aArg( 1 ); 110 aArg[0] <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/InternalMSExport") ); 111 uno::Reference< container::XNameAccess > xNameAccess( 112 xProvider->createInstanceWithArguments( 113 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationUpdateAccess" ) ), 114 aArg ), 115 uno::UNO_QUERY ); 116 if ( xNameAccess.is() ) 117 { 118 uno::Any aResult = xNameAccess->getByName( 119 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseOldExport" ) ) ); 120 121 sal_Bool bResult = sal_Bool(); 122 if ( aResult >>= bResult ) 123 return bResult; 124 } 125 } 126 catch( uno::Exception& ) 127 { 128 } 129 } 130 } 131 132 OSL_ENSURE( sal_False, "Could not get access to configuration entry!\n" ); 133 return sal_False; 134 } 135 136 void SvxMSExportOLEObjects::ExportOLEObject( const com::sun::star::uno::Reference < com::sun::star::embed::XEmbeddedObject>& rObj, SotStorage& rDestStg ) 137 { 138 svt::EmbeddedObjectRef aObj( rObj, embed::Aspects::MSOLE_CONTENT ); 139 ExportOLEObject( aObj, rDestStg ); 140 } 141 142 void SvxMSExportOLEObjects::ExportOLEObject( svt::EmbeddedObjectRef& rObj, SvStorage& rDestStg ) 143 { 144 SvGlobalName aOwnGlobalName; 145 SvGlobalName aObjName( rObj->getClassID() ); 146 const SfxFilter* pExpFilter = NULL; 147 { 148 static struct _ObjExpType { 149 sal_uInt32 nFlag; 150 const char* pFilterNm; 151 // GlobalNameId 152 struct _GlobalNameIds { 153 sal_uInt32 n1; 154 sal_uInt16 n2, n3; 155 sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15; 156 } 157 aGlNmIds[4]; 158 } aArr[] = { 159 { OLE_STARMATH_2_MATHTYPE, "MathType 3.x", 160 {{SO3_SM_CLASSID_60}, {SO3_SM_CLASSID_50}, 161 {SO3_SM_CLASSID_40}, {SO3_SM_CLASSID_30 }}}, 162 { OLE_STARWRITER_2_WINWORD, "MS Word 97", 163 {{SO3_SW_CLASSID_60}, {SO3_SW_CLASSID_50}, 164 {SO3_SW_CLASSID_40}, {SO3_SW_CLASSID_30 }}}, 165 { OLE_STARCALC_2_EXCEL, "MS Excel 97", 166 {{SO3_SC_CLASSID_60}, {SO3_SC_CLASSID_50}, 167 {SO3_SC_CLASSID_40}, {SO3_SC_CLASSID_30 }}}, 168 { OLE_STARIMPRESS_2_POWERPOINT, "MS PowerPoint 97", 169 {{SO3_SIMPRESS_CLASSID_60}, {SO3_SIMPRESS_CLASSID_50}, 170 {SO3_SIMPRESS_CLASSID_40}, {SO3_SIMPRESS_CLASSID_30 }}}, 171 { 0, "", 172 {{SO3_SCH_CLASSID_60}, {SO3_SCH_CLASSID_50}, 173 {SO3_SCH_CLASSID_40}, {SO3_SCH_CLASSID_30 }}}, 174 { 0, "", 175 {{SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50}, // SJ: !!!! SO3_SDRAW_CLASSID is only available up from 176 {SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50 }}}, // ver 5.0, it is purpose to have double entrys here. 177 178 { 0xffff,0, 179 {{SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50}, 180 {SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50}}} 181 }; 182 183 for( const _ObjExpType* pArr = aArr; !pExpFilter && ( pArr->nFlag != 0xffff ); ++pArr ) 184 { 185 for ( int n = 0; n < 4; ++n ) 186 { 187 const _ObjExpType::_GlobalNameIds& rId = pArr->aGlNmIds[ n ]; 188 SvGlobalName aGlbNm( rId.n1, rId.n2, rId.n3, 189 rId.b8, rId.b9, rId.b10, rId.b11, 190 rId.b12, rId.b13, rId.b14, rId.b15 ); 191 if( aObjName == aGlbNm ) 192 { 193 aOwnGlobalName = aGlbNm; 194 195 // flags for checking if conversion is wanted at all (SaveOptions?!) 196 if( GetFlags() & pArr->nFlag ) 197 { 198 pExpFilter = SfxFilterMatcher().GetFilter4FilterName(String::CreateFromAscii(pArr->pFilterNm)); 199 break; 200 } 201 } 202 } 203 } 204 } 205 206 if( pExpFilter ) // use this filter for the export 207 { 208 try 209 { 210 if ( rObj->getCurrentState() == embed::EmbedStates::LOADED ) 211 rObj->changeState( embed::EmbedStates::RUNNING ); 212 //TODO/LATER: is stream instead of outputstream a better choice?! 213 //TODO/LATER: a "StoreTo" method at embedded object would be nice 214 uno::Sequence < beans::PropertyValue > aSeq(2); 215 SvStream* pStream = new SvMemoryStream; 216 aSeq[0].Name = ::rtl::OUString::createFromAscii( "OutputStream" ); 217 ::uno::Reference < io::XOutputStream > xOut = new ::utl::OOutputStreamWrapper( *pStream ); 218 aSeq[0].Value <<= xOut; 219 aSeq[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ) ); 220 aSeq[1].Value <<= ::rtl::OUString( pExpFilter->GetName() ); 221 uno::Reference < frame::XStorable > xStor( rObj->getComponent(), uno::UNO_QUERY ); 222 xStor->storeToURL( ::rtl::OUString::createFromAscii( "private:stream" ), aSeq ); 223 SotStorageRef xOLEStor = new SotStorage( pStream, sal_True ); 224 xOLEStor->CopyTo( &rDestStg ); 225 rDestStg.Commit(); 226 } 227 catch( uno::Exception& ) 228 { 229 // TODO/LATER: Error handling 230 DBG_ERROR( "The object could not be exported!" ); 231 } 232 } 233 else if( aOwnGlobalName != SvGlobalName() ) 234 { 235 // own format, maybe SO6 format or lower 236 SvGlobalName aEmbName = GetEmbeddedVersion( aOwnGlobalName ); 237 if ( aEmbName != SvGlobalName() && !UseOldMSExport() ) 238 { 239 // this is a SO6 embedded object, save in old binary format 240 rDestStg.SetVersion( SOFFICE_FILEFORMAT_31 ); 241 rDestStg.SetClass( aEmbName, 242 SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE, 243 GetStorageType( aEmbName ) ); 244 SotStorageStreamRef xExtStm = rDestStg.OpenSotStream( 245 String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "properties_stream" ) ), 246 STREAM_STD_READWRITE ); 247 248 sal_Bool bExtentSuccess = sal_False; 249 if( !xExtStm->GetError() ) 250 { 251 // write extent 252 //TODO/MBA: check if writing a size is enough 253 if( rObj.GetObject().is() ) 254 { 255 // MSOLE objects don't need to be in running state for VisualArea access 256 awt::Size aSize; 257 try 258 { 259 // this is an own object, the content size must be stored in the 260 // extension stream 261 aSize = rObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); 262 } 263 catch( embed::NoVisualAreaSizeException& ) 264 { 265 OSL_ENSURE( sal_False, "Could not get visual area size!\n" ); 266 aSize.Width = 5000; 267 aSize.Height = 5000; 268 } 269 catch( uno::Exception& ) 270 { 271 OSL_ENSURE( sal_False, "Unexpected exception while getting visual area size!\n" ); 272 aSize.Width = 5000; 273 aSize.Height = 5000; 274 } 275 276 //Rectangle aVisArea = xSfxIPObj->GetVisArea( ASPECT_CONTENT ); 277 sal_Int32 pRect[4]; 278 //pRect[0] = aVisArea.Left(); 279 //pRect[1] = aVisArea.Right(); 280 //pRect[2] = aVisArea.Top(); 281 //pRect[3] = aVisArea.Bottom(); 282 pRect[0] = 0; 283 pRect[1] = aSize.Width; 284 pRect[2] = 0; 285 pRect[3] = aSize.Height; 286 287 sal_Int8 aWriteSet[16]; 288 for ( int ind = 0; ind < 4; ind++ ) 289 { 290 sal_Int32 nVal = pRect[ind]; 291 for ( int nByte = 0; nByte < 4; nByte++ ) 292 { 293 aWriteSet[ind*4+nByte] = (sal_Int8) nVal % 0x100; 294 nVal /= 0x100; 295 } 296 } 297 298 bExtentSuccess = ( xExtStm->Write( aWriteSet, 16 ) == 16 ); 299 } 300 } 301 302 if ( bExtentSuccess ) 303 { 304 SotStorageStreamRef xEmbStm = rDestStg.OpenSotStream( 305 String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "package_stream" ) ), 306 STREAM_STD_READWRITE ); 307 if( !xEmbStm->GetError() ) 308 { 309 try 310 { 311 if ( rObj->getCurrentState() == embed::EmbedStates::LOADED ) 312 rObj->changeState( embed::EmbedStates::RUNNING ); 313 //TODO/LATER: is stream instead of outputstream a better choice?! 314 //TODO/LATER: a "StoreTo" method at embedded object would be nice 315 uno::Sequence < beans::PropertyValue > aSeq(1); 316 aSeq[0].Name = ::rtl::OUString::createFromAscii( "OutputStream" ); 317 ::uno::Reference < io::XOutputStream > xOut = new ::utl::OOutputStreamWrapper( *xEmbStm ); 318 aSeq[0].Value <<= xOut; 319 uno::Reference < frame::XStorable > xStor( rObj->getComponent(), uno::UNO_QUERY ); 320 xStor->storeToURL( ::rtl::OUString::createFromAscii( "private:stream" ), aSeq ); 321 } 322 catch( uno::Exception& ) 323 { 324 // TODO/LATER: Error handling 325 DBG_ERROR( "The object could not be exported!" ); 326 } 327 } 328 } 329 } 330 else 331 { 332 DBG_ERROR("Own binary format inside own container document!"); 333 } 334 } 335 else 336 { 337 // alien objects 338 //TODO/LATER: a "StoreTo" method at embedded object would be nice 339 rDestStg.SetVersion( SOFFICE_FILEFORMAT_31 ); 340 uno::Reference < embed::XStorage > xStor = ::comphelper::OStorageHelper::GetTemporaryStorage(); 341 uno::Reference < embed::XEmbedPersist > xPers( rObj.GetObject(), uno::UNO_QUERY ); 342 if ( xPers.is() ) 343 { 344 uno::Sequence < beans::PropertyValue > aEmptySeq; 345 ::rtl::OUString aTempName(::rtl::OUString::createFromAscii("bla")); 346 try 347 { 348 xPers->storeToEntry( xStor, aTempName, aEmptySeq, aEmptySeq ); 349 } 350 catch ( uno::Exception& ) 351 {} 352 353 SotStorageRef xOLEStor = SotStorage::OpenOLEStorage( xStor, aTempName, STREAM_STD_READ ); 354 xOLEStor->CopyTo( &rDestStg ); 355 rDestStg.Commit(); 356 } 357 } 358 359 //We never need this stream: See #99809# and #i2179# 360 rDestStg.Remove(CREATE_CONST_ASC(SVEXT_PERSIST_STREAM)); 361 } 362 363 364 365