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