1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/uno/Reference.hxx>
21 #include <com/sun/star/uno/Sequence.hxx>
22 #include <com/sun/star/embed/XEmbeddedObject.hpp>
23 #include <com/sun/star/embed/XEmbedPersist.hpp>
24 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
25 #include <com/sun/star/embed/EmbedStates.hpp>
26 #include <com/sun/star/frame/XStorable.hpp>
27 #include <com/sun/star/awt/Size.hpp>
28 #include <com/sun/star/embed/Aspects.hpp>
29 #include <comphelper/classids.hxx>
30 #include <sfx2/docfilt.hxx>
31 #include <sfx2/fcontnr.hxx>
32 #include <sot/formats.hxx>
33 #include <sot/storage.hxx>
34 #include <comphelper/diagnose_ex.hxx>
35 #include <comphelper/fileformat.h>
36 #include <comphelper/propertyvalue.hxx>
37 #include <unotools/streamwrap.hxx>
38 #include <comphelper/storagehelper.hxx>
39 #include <svtools/embedhlp.hxx>
40 #include <filter/msfilter/msdffimp.hxx>
42 #include <filter/msfilter/msoleexp.hxx>
44 using namespace ::com::sun::star
;
46 static SvGlobalName
GetEmbeddedVersion( const SvGlobalName
& aAppName
)
48 if ( aAppName
== SvGlobalName( SO3_SM_CLASSID_60
) )
49 return SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8
);
50 else if ( aAppName
== SvGlobalName( SO3_SW_CLASSID_60
) )
51 return SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8
);
52 else if ( aAppName
== SvGlobalName( SO3_SC_CLASSID_60
) )
53 return SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8
);
54 else if ( aAppName
== SvGlobalName( SO3_SDRAW_CLASSID_60
) )
55 return SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8
);
56 else if ( aAppName
== SvGlobalName( SO3_SIMPRESS_CLASSID_60
) )
57 return SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8
);
58 else if ( aAppName
== SvGlobalName( SO3_SCH_CLASSID_60
) )
59 return SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8
);
61 return SvGlobalName();
64 static OUString
GetStorageType( const SvGlobalName
& aEmbName
)
66 if ( aEmbName
== SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8
) )
67 return u
"LibreOffice.MathDocument.1"_ustr
;
68 else if ( aEmbName
== SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8
) )
69 return u
"LibreOffice.WriterDocument.1"_ustr
;
70 else if ( aEmbName
== SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8
) )
71 return u
"LibreOffice.CalcDocument.1"_ustr
;
72 else if ( aEmbName
== SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8
) )
73 return u
"LibreOffice.DrawDocument.1"_ustr
;
74 else if ( aEmbName
== SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8
) )
75 return u
"LibreOffice.ImpressDocument.1"_ustr
;
76 else if ( aEmbName
== SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8
) )
77 return u
"LibreOffice.ChartDocument.1"_ustr
;
81 void SvxMSExportOLEObjects::ExportOLEObject( const css::uno::Reference
< css::embed::XEmbeddedObject
>& rObj
, SotStorage
& rDestStg
)
83 svt::EmbeddedObjectRef
aObj( rObj
, embed::Aspects::MSOLE_CONTENT
);
84 ExportOLEObject( aObj
, rDestStg
);
87 void SvxMSExportOLEObjects::ExportOLEObject( svt::EmbeddedObjectRef
const & rObj
, SotStorage
& rDestStg
)
89 SvGlobalName aOwnGlobalName
;
90 SvGlobalName
aObjName( rObj
->getClassID() );
91 std::shared_ptr
<const SfxFilter
> pExpFilter
;
93 static struct ObjExpType
{
95 const char* pFilterNm
;
97 struct GlobalNameIds
{
100 sal_uInt8 b8
, b9
, b10
, b11
, b12
, b13
, b14
, b15
;
104 { OLE_STARMATH_2_MATHTYPE
, "MathType 3.x",
105 {{SO3_SM_CLASSID_60
}, {SO3_SM_CLASSID_50
},
106 {SO3_SM_CLASSID_40
}, {SO3_SM_CLASSID_30
}}},
107 { OLE_STARWRITER_2_WINWORD
, "MS Word 97",
108 {{SO3_SW_CLASSID_60
}, {SO3_SW_CLASSID_50
},
109 {SO3_SW_CLASSID_40
}, {SO3_SW_CLASSID_30
}}},
110 { OLE_STARCALC_2_EXCEL
, "MS Excel 97",
111 {{SO3_SC_CLASSID_60
}, {SO3_SC_CLASSID_50
},
112 {SO3_SC_CLASSID_40
}, {SO3_SC_CLASSID_30
}}},
113 { OLE_STARIMPRESS_2_POWERPOINT
, "MS PowerPoint 97",
114 {{SO3_SIMPRESS_CLASSID_60
}, {SO3_SIMPRESS_CLASSID_50
},
115 {SO3_SIMPRESS_CLASSID_40
}, {SO3_SIMPRESS_CLASSID_30
}}},
117 {{SO3_SCH_CLASSID_60
}, {SO3_SCH_CLASSID_50
},
118 {SO3_SCH_CLASSID_40
}, {SO3_SCH_CLASSID_30
}}},
120 {{SO3_SDRAW_CLASSID_60
}, {SO3_SDRAW_CLASSID_50
}, // SJ: !!!! SO3_SDRAW_CLASSID is only available up from
121 {SO3_SDRAW_CLASSID_60
}, {SO3_SDRAW_CLASSID_50
}}}, // ver 5.0, it is purpose to have double entries here.
124 {{SO3_SDRAW_CLASSID_60
}, {SO3_SDRAW_CLASSID_50
},
125 {SO3_SDRAW_CLASSID_60
}, {SO3_SDRAW_CLASSID_50
}}}
128 for( const ObjExpType
* pArr
= aArr
; !pExpFilter
&& ( pArr
->nFlag
!= 0xffff ); ++pArr
)
130 for (const ObjExpType::GlobalNameIds
& rId
: pArr
->aGlNmIds
)
132 SvGlobalName
aGlbNm( rId
.n1
, rId
.n2
, rId
.n3
,
133 rId
.b8
, rId
.b9
, rId
.b10
, rId
.b11
,
134 rId
.b12
, rId
.b13
, rId
.b14
, rId
.b15
);
135 if( aObjName
== aGlbNm
)
137 aOwnGlobalName
= aGlbNm
;
139 // flags for checking if conversion is wanted at all (SaveOptions?!)
140 if( nConvertFlags
& pArr
->nFlag
)
142 pExpFilter
= SfxFilterMatcher().GetFilter4FilterName(OUString::createFromAscii(pArr
->pFilterNm
));
150 if( pExpFilter
) // use this filter for the export
154 if ( rObj
->getCurrentState() == embed::EmbedStates::LOADED
)
155 rObj
->changeState( embed::EmbedStates::RUNNING
);
156 //TODO/LATER: is stream instead of outputstream a better choice?!
157 //TODO/LATER: a "StoreTo" method at embedded object would be nice
158 SvStream
* pStream
= new SvMemoryStream
;
159 ::uno::Reference
< io::XOutputStream
> xOut
= new ::utl::OOutputStreamWrapper( *pStream
);
160 uno::Sequence
< beans::PropertyValue
> aSeq
{
161 comphelper::makePropertyValue(u
"OutputStream"_ustr
, xOut
),
162 comphelper::makePropertyValue(u
"FilterName"_ustr
, pExpFilter
->GetName())
164 uno::Reference
< frame::XStorable
> xStor( rObj
->getComponent(), uno::UNO_QUERY
);
167 xStor
->storeToURL( u
"private:stream"_ustr
, aSeq
);
169 catch( const uno::Exception
& ) {} // #TODO really handle exceptions - interactionalhandler etc. ?
171 rtl::Reference
<SotStorage
> xOLEStor
= new SotStorage( pStream
, true );
172 xOLEStor
->CopyTo( &rDestStg
);
175 catch( const uno::Exception
& )
177 // TODO/LATER: Error handling
178 OSL_FAIL( "The object could not be exported!" );
181 else if( aOwnGlobalName
!= SvGlobalName() )
183 // own format, maybe SO6 format or lower
184 SvGlobalName aEmbName
= GetEmbeddedVersion( aOwnGlobalName
);
185 if ( aEmbName
!= SvGlobalName() )
187 // this is a SO6 embedded object, save in old binary format
188 rDestStg
.SetVersion( SOFFICE_FILEFORMAT_31
);
189 rDestStg
.SetClass( aEmbName
,
190 SotClipboardFormatId::EMBEDDED_OBJ_OLE
,
191 GetStorageType( aEmbName
) );
192 rtl::Reference
<SotStorageStream
> xExtStm
= rDestStg
.OpenSotStream(
193 u
"properties_stream"_ustr
);
195 bool bExtentSuccess
= false;
196 if( !xExtStm
->GetError() )
199 //TODO/MBA: check if writing a size is enough
200 if( rObj
.GetObject().is() )
202 // MSOLE objects don't need to be in running state for VisualArea access
206 // this is an own object, the content size must be stored in the
208 aSize
= rObj
->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
);
210 catch( const embed::NoVisualAreaSizeException
& )
212 OSL_FAIL( "Could not get visual area size!" );
216 catch( const uno::Exception
& )
218 TOOLS_WARN_EXCEPTION(
219 "filter.ms", "Unexpected exception while getting visual area size!");
226 pRect
[1] = aSize
.Width
;
228 pRect
[3] = aSize
.Height
;
230 sal_Int8 aWriteSet
[16];
231 for ( int ind
= 0; ind
< 4; ind
++ )
233 sal_Int32 nVal
= pRect
[ind
];
234 for ( int nByte
= 0; nByte
< 4; nByte
++ )
236 aWriteSet
[ind
*4+nByte
] = static_cast<sal_Int8
>(nVal
) % 0x100;
241 bExtentSuccess
= (xExtStm
->WriteBytes(aWriteSet
, 16) == 16);
245 if ( bExtentSuccess
)
247 rtl::Reference
<SotStorageStream
> xEmbStm
= rDestStg
.OpenSotStream(
248 u
"package_stream"_ustr
);
249 if( !xEmbStm
->GetError() )
253 if ( rObj
->getCurrentState() == embed::EmbedStates::LOADED
)
254 rObj
->changeState( embed::EmbedStates::RUNNING
);
255 //TODO/LATER: is stream instead of outputstream a better choice?!
256 //TODO/LATER: a "StoreTo" method at embedded object would be nice
257 ::uno::Reference
< io::XOutputStream
> xOut
= new ::utl::OOutputStreamWrapper( *xEmbStm
);
258 uno::Sequence
< beans::PropertyValue
> aSeq
{ comphelper::makePropertyValue(
259 u
"OutputStream"_ustr
, xOut
) };
260 uno::Reference
< frame::XStorable
> xStor( rObj
->getComponent(), uno::UNO_QUERY
);
261 xStor
->storeToURL( u
"private:stream"_ustr
, aSeq
);
263 catch( const uno::Exception
& )
265 // TODO/LATER: Error handling
266 OSL_FAIL( "The object could not be exported!" );
273 OSL_FAIL("Own binary format inside own container document!");
279 //TODO/LATER: a "StoreTo" method at embedded object would be nice
280 rDestStg
.SetVersion( SOFFICE_FILEFORMAT_31
);
281 uno::Reference
< embed::XStorage
> xStor
= ::comphelper::OStorageHelper::GetTemporaryStorage();
282 uno::Reference
< embed::XEmbedPersist
> xPers( rObj
.GetObject(), uno::UNO_QUERY
);
285 uno::Sequence
< beans::PropertyValue
> aEmptySeq
;
286 OUString
aTempName( u
"bla"_ustr
);
289 xPers
->storeToEntry( xStor
, aTempName
, aEmptySeq
, aEmptySeq
);
291 catch ( const uno::Exception
& )
294 rtl::Reference
<SotStorage
> xOLEStor
= SotStorage::OpenOLEStorage( xStor
, aTempName
, StreamMode::STD_READ
);
295 xOLEStor
->CopyTo( &rDestStg
);
300 //We never need this stream: See #99809# and #i2179#
301 rDestStg
.Remove( SVEXT_PERSIST_STREAM
);
305 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */