xref: /trunk/main/filter/source/msfilter/msoleexp.cxx (revision cdf0e10c)
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