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