LibreOffice Module oox (master) 1
olestorage.cxx
Go to the documentation of this file.
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
21
22#include <com/sun/star/container/XNameContainer.hpp>
23#include <com/sun/star/embed/XTransactedObject.hpp>
24#include <com/sun/star/io/IOException.hpp>
25#include <com/sun/star/io/NotConnectedException.hpp>
26#include <com/sun/star/io/TempFile.hpp>
27#include <com/sun/star/io/XInputStream.hpp>
28#include <com/sun/star/io/XOutputStream.hpp>
29#include <com/sun/star/io/XSeekable.hpp>
30#include <com/sun/star/io/XStream.hpp>
31#include <com/sun/star/lang/XMultiServiceFactory.hpp>
32#include <com/sun/star/uno/XComponentContext.hpp>
34#include <osl/diagnose.h>
38#include <utility>
39
40namespace oox::ole {
41
42using namespace ::com::sun::star::container;
43using namespace ::com::sun::star::embed;
44using namespace ::com::sun::star::io;
45using namespace ::com::sun::star::lang;
46using namespace ::com::sun::star::uno;
47
48namespace {
49
53class OleOutputStream : public ::cppu::WeakImplHelper< XSeekable, XOutputStream >
54{
55public:
56 explicit OleOutputStream(
57 const Reference< XComponentContext >& rxContext,
58 const Reference< XNameContainer >& rxStorage,
59 OUString aElementName );
60
61 virtual void SAL_CALL seek( sal_Int64 nPos ) override;
62 virtual sal_Int64 SAL_CALL getPosition() override;
63 virtual sal_Int64 SAL_CALL getLength() override;
64
65 virtual void SAL_CALL writeBytes( const Sequence< sal_Int8 >& rData ) override;
66 virtual void SAL_CALL flush() override;
67 virtual void SAL_CALL closeOutput() override;
68
69private:
71 void ensureSeekable() const;
73 void ensureConnected() const;
74
75private:
76 Reference< XNameContainer > mxStorage;
77 Reference< XStream > mxTempFile;
78 Reference< XOutputStream > mxOutStrm;
79 Reference< XSeekable > mxSeekable;
80 OUString maElementName;
81};
82
83OleOutputStream::OleOutputStream( const Reference< XComponentContext >& rxContext,
84 const Reference< XNameContainer >& rxStorage, OUString aElementName ) :
85 mxStorage( rxStorage ),
86 maElementName(std::move( aElementName ))
87{
88 try
89 {
90 mxTempFile.set( TempFile::create(rxContext), UNO_QUERY_THROW );
91 mxOutStrm = mxTempFile->getOutputStream();
92 mxSeekable.set( mxOutStrm, UNO_QUERY );
93 }
94 catch(const Exception& )
95 {
96 }
97}
98
99void SAL_CALL OleOutputStream::seek( sal_Int64 nPos )
100{
101 ensureSeekable();
102 mxSeekable->seek( nPos );
103}
104
105sal_Int64 SAL_CALL OleOutputStream::getPosition()
106{
107 ensureSeekable();
108 return mxSeekable->getPosition();
109}
110
111sal_Int64 SAL_CALL OleOutputStream::getLength()
112{
113 ensureSeekable();
114 return mxSeekable->getLength();
115}
116
117void SAL_CALL OleOutputStream::writeBytes( const Sequence< sal_Int8 >& rData )
118{
119 ensureConnected();
120 mxOutStrm->writeBytes( rData );
121}
122
123void SAL_CALL OleOutputStream::flush()
124{
125 ensureConnected();
126 mxOutStrm->flush();
127}
128
129void SAL_CALL OleOutputStream::closeOutput()
130{
131 ensureConnected();
132 ensureSeekable();
133 // remember the class members
134 Reference< XOutputStream > xOutStrm = mxOutStrm;
135 Reference< XSeekable > xSeekable = mxSeekable;
136 // reset all class members
137 mxOutStrm.clear();
138 mxSeekable.clear();
139 // close stream (and let it throw something if needed)
140 xOutStrm->closeOutput();
141 // on success, insert the stream into the OLE storage (must be seek-ed back before)
142 xSeekable->seek( 0 );
143 if( !ContainerHelper::insertByName( mxStorage, maElementName, Any( mxTempFile ) ) )
144 throw IOException();
145}
146
147void OleOutputStream::ensureSeekable() const
148{
149 if( !mxSeekable.is() )
150 throw IOException();
151}
152
153void OleOutputStream::ensureConnected() const
154{
155 if( !mxOutStrm.is() )
156 throw NotConnectedException();
157}
158
159} // namespace
160
161OleStorage::OleStorage( const Reference< XComponentContext >& rxContext,
162 const Reference< XInputStream >& rxInStream, bool bBaseStreamAccess ) :
163 StorageBase( rxInStream, bBaseStreamAccess ),
164 mxContext( rxContext ),
165 mpParentStorage( nullptr )
166{
167 OSL_ENSURE( mxContext.is(), "OleStorage::OleStorage - missing component context" );
168 initStorage( rxInStream );
169}
170
171OleStorage::OleStorage( const Reference< XComponentContext >& rxContext,
172 const Reference< XStream >& rxOutStream, bool bBaseStreamAccess ) :
173 StorageBase( rxOutStream, bBaseStreamAccess ),
174 mxContext( rxContext ),
175 mpParentStorage( nullptr )
176{
177 OSL_ENSURE( mxContext.is(), "OleStorage::OleStorage - missing component context" );
178 initStorage( rxOutStream );
179}
180
181OleStorage::OleStorage( const OleStorage& rParentStorage,
182 const Reference< XNameContainer >& rxStorage, const OUString& rElementName, bool bReadOnly ) :
183 StorageBase( rParentStorage, rElementName, bReadOnly ),
184 mxContext( rParentStorage.mxContext ),
185 mxStorage( rxStorage ),
186 mpParentStorage( &rParentStorage )
187{
188 OSL_ENSURE( mxStorage.is(), "OleStorage::OleStorage - missing substorage elements" );
189}
190
191OleStorage::OleStorage( const OleStorage& rParentStorage,
192 const Reference< XStream >& rxOutStream, const OUString& rElementName ) :
193 StorageBase( rParentStorage, rElementName, false ),
194 mxContext( rParentStorage.mxContext ),
195 mpParentStorage( &rParentStorage )
196{
197 initStorage( rxOutStream );
198}
199
200OleStorage::~OleStorage()
201{
202}
203
204void OleStorage::initStorage( const Reference< XInputStream >& rxInStream )
205{
206 // if stream is not seekable, create temporary copy
207 Reference< XInputStream > xInStrm = rxInStream;
208 if( !Reference< XSeekable >( xInStrm, UNO_QUERY ).is() ) try
209 {
210 Reference< XStream > xTempFile( TempFile::create(mxContext), UNO_QUERY_THROW );
211 {
212 Reference< XOutputStream > xOutStrm( xTempFile->getOutputStream(), UNO_SET_THROW );
213 /* Pass false to both binary stream objects to keep the UNO
214 streams alive. Life time of these streams is controlled by the
215 tempfile implementation. */
216 BinaryXOutputStream aOutStrm( xOutStrm, false );
217 BinaryXInputStream aInStrm( xInStrm, false );
218 aInStrm.copyToStream( aOutStrm );
219 } // scope closes output stream of tempfile
220 xInStrm = xTempFile->getInputStream();
221 }
222 catch(const Exception& )
223 {
224 OSL_FAIL( "OleStorage::initStorage - cannot create temporary copy of input stream" );
225 }
226
227 // create base storage object
228 if( xInStrm.is() ) try
229 {
230 Reference< XMultiServiceFactory > xFactory( mxContext->getServiceManager(), UNO_QUERY_THROW );
231 Sequence< Any > aArgs{ Any(xInStrm),
232 Any(true) };// true = do not create a copy of the input stream
233 mxStorage.set( xFactory->createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", aArgs ), UNO_QUERY_THROW );
234 }
235 catch(const Exception& )
236 {
237 }
238}
239
240void OleStorage::initStorage( const Reference< XStream >& rxOutStream )
241{
242 // create base storage object
243 if( rxOutStream.is() ) try
244 {
245 Reference< XMultiServiceFactory > xFactory( mxContext->getServiceManager(), UNO_QUERY_THROW );
246 Sequence< Any > aArgs{ Any(rxOutStream),
247 Any(true) }; // true = do not create a copy of the stream
248 mxStorage.set( xFactory->createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", aArgs ), UNO_QUERY_THROW );
249 }
250 catch(const Exception& )
251 {
252 }
253}
254
255// StorageBase interface ------------------------------------------------------
256
257bool OleStorage::implIsStorage() const
258{
259 if( mxStorage.is() ) try
260 {
261 /* If this is not an OLE storage, hasElements() of the OLESimpleStorage
262 implementation throws an exception. But we do not return the result
263 of hasElements(), because an empty storage is a valid storage too. */
264 (void)mxStorage->hasElements();
265 return true;
266 }
267 catch(const Exception& )
268 {
269 }
270 return false;
271}
272
273Reference< XStorage > OleStorage::implGetXStorage() const
274{
275 OSL_FAIL( "OleStorage::getXStorage - not implemented" );
276 return Reference< XStorage >();
277}
278
279void OleStorage::implGetElementNames( ::std::vector< OUString >& orElementNames ) const
280{
281 if( mxStorage.is() ) try
282 {
283 const Sequence<OUString> aNames = mxStorage->getElementNames();
284 if( aNames.hasElements() )
285 orElementNames.insert( orElementNames.end(), aNames.begin(), aNames.end() );
286 }
287 catch(const Exception& )
288 {
289 }
290}
291
292StorageRef OleStorage::implOpenSubStorage( const OUString& rElementName, bool bCreateMissing )
293{
294 StorageRef xSubStorage;
295 if( mxStorage.is() && !rElementName.isEmpty() )
296 {
297 try
298 {
299 Reference< XNameContainer > xSubElements( mxStorage->getByName( rElementName ), UNO_QUERY_THROW );
300 xSubStorage.reset( new OleStorage( *this, xSubElements, rElementName, true ) );
301 }
302 catch(const Exception& )
303 {
304 }
305
306 /* The OLESimpleStorage API implementation seems to be buggy in the
307 area of writable inplace substorage (sometimes it overwrites other
308 unrelated streams with zero bytes). We go the save way and create a
309 new OLE storage based on a temporary file. All operations are
310 performed on this clean storage. On committing, the storage will be
311 completely re-inserted into the parent storage. */
312 if( !isReadOnly() && (bCreateMissing || xSubStorage) ) try
313 {
314 // create new storage based on a temp file
315 Reference< XStream > xTempFile( TempFile::create(mxContext), UNO_QUERY_THROW );
316 StorageRef xTempStorage( new OleStorage( *this, xTempFile, rElementName ) );
317 // copy existing substorage into temp storage
318 if( xSubStorage )
319 xSubStorage->copyStorageToStorage( *xTempStorage );
320 // return the temp storage to caller
321 xSubStorage = xTempStorage;
322 }
323 catch(const Exception& )
324 {
325 }
326 }
327 return xSubStorage;
328}
329
330Reference< XInputStream > OleStorage::implOpenInputStream( const OUString& rElementName )
331{
332 Reference< XInputStream > xInStream;
333 if( mxStorage.is() ) try
334 {
335 xInStream.set( mxStorage->getByName( rElementName ), UNO_QUERY );
336 }
337 catch(const Exception& )
338 {
339 }
340 return xInStream;
341}
342
343Reference< XOutputStream > OleStorage::implOpenOutputStream( const OUString& rElementName )
344{
345 Reference< XOutputStream > xOutStream;
346 if( mxStorage.is() && !rElementName.isEmpty() )
347 xOutStream.set( new OleOutputStream( mxContext, mxStorage, rElementName ) );
348 return xOutStream;
349}
350
351void OleStorage::implCommit() const
352{
353 try
354 {
355 // commit this storage (finalizes the file this storage is based on)
356 Reference< XTransactedObject >( mxStorage, UNO_QUERY_THROW )->commit();
357 // re-insert this storage into the parent storage
358 if( mpParentStorage )
359 {
360 if( mpParentStorage->mxStorage->hasByName( getName() ) )
361 {
362 // replaceByName() does not work (#i109539#)
363 mpParentStorage->mxStorage->removeByName( getName() );
364 Reference< XTransactedObject >( mpParentStorage->mxStorage, UNO_QUERY_THROW )->commit();
365 }
366 mpParentStorage->mxStorage->insertByName( getName(), Any( mxStorage ) );
367 // this requires another commit(), which will be performed by the parent storage
368 }
369 }
370 catch(const Exception& )
371 {
372 }
373}
374
375} // namespace oox::ole
376
377/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Wraps a UNO input stream and provides convenient access functions.
Wraps a UNO output stream and provides convenient access functions.
Implements stream access for binary OLE storages.
Definition: olestorage.hxx:44
uno::Reference< uno::XComponentContext > mxContext
Reference< XSingleServiceFactory > xFactory
bool bReadOnly
double getLength(const B2DPolygon &rCandidate)
@ Exception
std::shared_ptr< StorageBase > StorageRef
Definition: storagebase.hxx:42
Reference< XNameContainer > mxStorage
Definition: olestorage.cxx:76
Reference< XStream > mxTempFile
Definition: olestorage.cxx:77
Reference< XSeekable > mxSeekable
Definition: olestorage.cxx:79
OUString maElementName
Definition: olestorage.cxx:80
Reference< XOutputStream > mxOutStrm
Definition: olestorage.cxx:78