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