Bug Summary

File:home/maarten/src/libreoffice/core/include/tools/ref.hxx
Warning:line 97, column 56
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ucbstorage.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SOT_DLLIMPLEMENTATION -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/sot/inc -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx

/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx

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/io/NotConnectedException.hpp>
21#include <com/sun/star/io/BufferSizeExceededException.hpp>
22#include <com/sun/star/uno/RuntimeException.hpp>
23#include <ucbhelper/content.hxx>
24#include <com/sun/star/uno/Reference.h>
25#include <com/sun/star/ucb/NameClash.hpp>
26#include <unotools/tempfile.hxx>
27#include <unotools/ucbstreamhelper.hxx>
28#include <com/sun/star/io/XInputStream.hpp>
29#include <com/sun/star/ucb/InsertCommandArgument.hpp>
30#include <com/sun/star/ucb/ResultSetException.hpp>
31#include <com/sun/star/uno/Sequence.h>
32#include <com/sun/star/sdbc/XResultSet.hpp>
33#include <com/sun/star/sdbc/XRow.hpp>
34#include <com/sun/star/ucb/CommandAbortedException.hpp>
35#include <com/sun/star/datatransfer/DataFlavor.hpp>
36#include <com/sun/star/ucb/ContentInfo.hpp>
37#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
38#include <com/sun/star/beans/Property.hpp>
39#include <com/sun/star/packages/manifest/ManifestWriter.hpp>
40#include <com/sun/star/packages/manifest/ManifestReader.hpp>
41#include <com/sun/star/ucb/InteractiveIOException.hpp>
42#include <com/sun/star/ucb/ContentCreationException.hpp>
43
44#include <memory>
45#include <osl/diagnose.h>
46#include <osl/file.hxx>
47#include <sal/log.hxx>
48#include <tools/diagnose_ex.h>
49#include <tools/ref.hxx>
50#include <tools/debug.hxx>
51#include <unotools/streamwrap.hxx>
52#include <unotools/ucbhelper.hxx>
53#include <tools/urlobj.hxx>
54#include <comphelper/processfactory.hxx>
55#include <cppuhelper/implbase.hxx>
56#include <ucbhelper/commandenvironment.hxx>
57
58#include <sot/stg.hxx>
59#include <sot/storinfo.hxx>
60#include <sot/exchange.hxx>
61#include <sot/formats.hxx>
62#include <comphelper/classids.hxx>
63
64#include <vector>
65
66namespace com::sun::star::ucb { class XCommandEnvironment; }
67
68using namespace ::com::sun::star::lang;
69using namespace ::com::sun::star::beans;
70using namespace ::com::sun::star::uno;
71using namespace ::com::sun::star::ucb;
72using namespace ::com::sun::star::io;
73using namespace ::com::sun::star::sdbc;
74using namespace ::ucbhelper;
75
76#if OSL_DEBUG_LEVEL1 > 0
77static int nOpenFiles=0;
78static int nOpenStreams=0;
79#endif
80
81typedef ::cppu::WeakImplHelper < XInputStream, XSeekable > FileInputStreamWrapper_Base;
82
83namespace {
84
85class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base
86{
87protected:
88 ::osl::Mutex m_aMutex;
89 OUString m_aURL;
90 std::unique_ptr<SvStream> m_pSvStream;
91
92public:
93 explicit FileStreamWrapper_Impl(const OUString& rName);
94 virtual ~FileStreamWrapper_Impl() override;
95
96 virtual void SAL_CALL seek( sal_Int64 _nLocation ) override;
97 virtual sal_Int64 SAL_CALL getPosition( ) override;
98 virtual sal_Int64 SAL_CALL getLength( ) override;
99 virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override;
100 virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override;
101 virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
102 virtual sal_Int32 SAL_CALL available() override;
103 virtual void SAL_CALL closeInput() override;
104
105protected:
106 void checkConnected();
107 void checkError();
108};
109
110}
111
112FileStreamWrapper_Impl::FileStreamWrapper_Impl( const OUString& rName )
113 : m_aURL( rName )
114{
115 // if no URL is provided the stream is empty
116}
117
118
119FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
120{
121 if ( m_pSvStream )
122 {
123 m_pSvStream.reset();
124#if OSL_DEBUG_LEVEL1 > 0
125 --nOpenFiles;
126#endif
127 }
128
129 if (!m_aURL.isEmpty())
130 osl::File::remove(m_aURL);
131}
132
133
134sal_Int32 SAL_CALL FileStreamWrapper_Impl::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
135{
136 if ( m_aURL.isEmpty() )
137 {
138 aData.realloc( 0 );
139 return 0;
140 }
141
142 checkConnected();
143
144 if (nBytesToRead < 0)
145 throw BufferSizeExceededException(OUString(),static_cast<XWeak*>(this));
146
147 ::osl::MutexGuard aGuard( m_aMutex );
148
149 if (aData.getLength() < nBytesToRead)
150 aData.realloc(nBytesToRead);
151
152 sal_uInt32 nRead = m_pSvStream->ReadBytes(static_cast<void*>(aData.getArray()), nBytesToRead);
153 checkError();
154
155 // if read characters < MaxLength, adjust sequence
156 if (static_cast<sal_Int32>(nRead) < aData.getLength())
157 aData.realloc( nRead );
158
159 return nRead;
160}
161
162
163sal_Int32 SAL_CALL FileStreamWrapper_Impl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
164{
165 if ( m_aURL.isEmpty() )
166 {
167 aData.realloc( 0 );
168 return 0;
169 }
170
171 checkError();
172
173 if (nMaxBytesToRead < 0)
174 throw BufferSizeExceededException(OUString(),static_cast<XWeak*>(this));
175
176 if (m_pSvStream->eof())
177 {
178 aData.realloc(0);
179 return 0;
180 }
181 else
182 return readBytes(aData, nMaxBytesToRead);
183}
184
185
186void SAL_CALL FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip)
187{
188 if ( m_aURL.isEmpty() )
189 return;
190
191 ::osl::MutexGuard aGuard( m_aMutex );
192 checkError();
193
194 m_pSvStream->SeekRel(nBytesToSkip);
195 checkError();
196}
197
198
199sal_Int32 SAL_CALL FileStreamWrapper_Impl::available()
200{
201 if ( m_aURL.isEmpty() )
202 return 0;
203
204 ::osl::MutexGuard aGuard( m_aMutex );
205 checkConnected();
206
207 sal_Int64 nAvailable = m_pSvStream->remainingSize();
208 checkError();
209
210 return std::min<sal_Int64>(SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF), nAvailable);
211}
212
213
214void SAL_CALL FileStreamWrapper_Impl::closeInput()
215{
216 if ( m_aURL.isEmpty() )
217 return;
218
219 ::osl::MutexGuard aGuard( m_aMutex );
220 checkConnected();
221 m_pSvStream.reset();
222#if OSL_DEBUG_LEVEL1 > 0
223 --nOpenFiles;
224#endif
225 osl::File::remove(m_aURL);
226 m_aURL.clear();
227}
228
229
230void SAL_CALL FileStreamWrapper_Impl::seek( sal_Int64 _nLocation )
231{
232 if ( m_aURL.isEmpty() )
233 return;
234
235 ::osl::MutexGuard aGuard( m_aMutex );
236 checkConnected();
237
238 m_pSvStream->Seek(static_cast<sal_uInt32>(_nLocation));
239 checkError();
240}
241
242
243sal_Int64 SAL_CALL FileStreamWrapper_Impl::getPosition( )
244{
245 if ( m_aURL.isEmpty() )
246 return 0;
247
248 ::osl::MutexGuard aGuard( m_aMutex );
249 checkConnected();
250
251 sal_uInt32 nPos = m_pSvStream->Tell();
252 checkError();
253 return static_cast<sal_Int64>(nPos);
254}
255
256
257sal_Int64 SAL_CALL FileStreamWrapper_Impl::getLength( )
258{
259 if ( m_aURL.isEmpty() )
260 return 0;
261
262 ::osl::MutexGuard aGuard( m_aMutex );
263 checkConnected();
264
265 checkError();
266
267 sal_Int64 nEndPos = m_pSvStream->TellEnd();
268
269 return nEndPos;
270}
271
272
273void FileStreamWrapper_Impl::checkConnected()
274{
275 if ( m_aURL.isEmpty() )
276 throw NotConnectedException(OUString(), static_cast<XWeak*>(this));
277 if ( !m_pSvStream )
278 {
279 m_pSvStream = ::utl::UcbStreamHelper::CreateStream( m_aURL, StreamMode::STD_READ );
280#if OSL_DEBUG_LEVEL1 > 0
281 ++nOpenFiles;
282#endif
283 }
284}
285
286
287void FileStreamWrapper_Impl::checkError()
288{
289 checkConnected();
290
291 if (m_pSvStream->SvStream::GetError() != ERRCODE_NONEErrCode(0))
292 // TODO: really evaluate the error
293 throw NotConnectedException(OUString(), static_cast<XWeak*>(this));
294}
295
296
297#define COMMIT_RESULT_FAILURE0 0
298#define COMMIT_RESULT_NOTHING_TO_DO1 1
299#define COMMIT_RESULT_SUCCESS2 2
300
301static SotClipboardFormatId GetFormatId_Impl( const SvGlobalName& aName )
302{
303 if ( aName == SvGlobalName( SO3_SW_CLASSID_600x8BC6B165, 0xB1B2, 0x4EDD, 0xAA, 0x47, 0xDA, 0xE2, 0xEE, 0x68
, 0x9D, 0xD6
) )
304 return SotClipboardFormatId::STARWRITER_60;
305 if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_600xA8BBA60C, 0x7C60, 0x4550, 0x91, 0xCE, 0x39, 0xC3, 0x90, 0x3F
, 0xAC, 0x5E
) )
306 return SotClipboardFormatId::STARWRITERWEB_60;
307 if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_600xB21A0A7C, 0xE403, 0x41FE, 0x95, 0x62, 0xBD, 0x13, 0xEA, 0x6F
, 0x15, 0xA0
) )
308 return SotClipboardFormatId::STARWRITERGLOB_60;
309 if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_600x4BAB8970, 0x8A3B, 0x45B3, 0x99, 0x1C, 0xCB, 0xEE, 0xAC, 0x6B
, 0xD5, 0xE3
) )
310 return SotClipboardFormatId::STARDRAW_60;
311 if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_600x9176E48A, 0x637A, 0x4D1F, 0x80, 0x3B, 0x99, 0xD9, 0xBF, 0xAC
, 0x10, 0x47
) )
312 return SotClipboardFormatId::STARIMPRESS_60;
313 if ( aName == SvGlobalName( SO3_SC_CLASSID_600x47BBB4CB, 0xCE4C, 0x4E80, 0xA5, 0x91, 0x42, 0xD9, 0xAE, 0x74
, 0x95, 0x0F
) )
314 return SotClipboardFormatId::STARCALC_60;
315 if ( aName == SvGlobalName( SO3_SCH_CLASSID_600x12DCAE26, 0x281F, 0x416F, 0xA2, 0x34, 0xC3, 0x08, 0x61, 0x27
, 0x38, 0x2E
) )
316 return SotClipboardFormatId::STARCHART_60;
317 if ( aName == SvGlobalName( SO3_SM_CLASSID_600x078B7ABA, 0x54FC, 0x457F, 0x85, 0x51, 0x61, 0x47, 0xE7, 0x76
, 0xA9, 0x97
) )
318 return SotClipboardFormatId::STARMATH_60;
319 if ( aName == SvGlobalName( SO3_OUT_CLASSID0x970b1e82, 0xcf2d, 0x11cf, 0x89, 0xca, 0x00, 0x80, 0x29, 0xe4
, 0xb0, 0xb1
) ||
320 aName == SvGlobalName( SO3_APPLET_CLASSID0x970b1e81, 0xcf2d, 0x11cf, 0x89,0xca,0x00,0x80,0x29,0xe4,0xb0
,0xb1
) ||
321 aName == SvGlobalName( SO3_PLUGIN_CLASSID0x4caa7761, 0x6b8b, 0x11cf, 0x89,0xca,0x0,0x80,0x29,0xe4,0xb0
,0xb1
) ||
322 aName == SvGlobalName( SO3_IFRAME_CLASSID0x1a8a6701, 0xde58, 0x11cf, 0x89, 0xca, 0x0, 0x80, 0x29, 0xe4
, 0xb0, 0xb1
) )
323 // allowed, but not supported
324 return SotClipboardFormatId::NONE;
325 else
326 {
327 OSL_FAIL( "Unknown UCB storage format!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "327" ": "), "%s", "Unknown UCB storage format!"); } } while
(false)
;
328 return SotClipboardFormatId::NONE;
329 }
330}
331
332
333static SvGlobalName GetClassId_Impl( SotClipboardFormatId nFormat )
334{
335 switch ( nFormat )
336 {
337 case SotClipboardFormatId::STARWRITER_8 :
338 case SotClipboardFormatId::STARWRITER_8_TEMPLATE :
339 return SvGlobalName( SO3_SW_CLASSID_600x8BC6B165, 0xB1B2, 0x4EDD, 0xAA, 0x47, 0xDA, 0xE2, 0xEE, 0x68
, 0x9D, 0xD6
);
340 case SotClipboardFormatId::STARWRITERWEB_8 :
341 return SvGlobalName( SO3_SWWEB_CLASSID_600xA8BBA60C, 0x7C60, 0x4550, 0x91, 0xCE, 0x39, 0xC3, 0x90, 0x3F
, 0xAC, 0x5E
);
342 case SotClipboardFormatId::STARWRITERGLOB_8 :
343 case SotClipboardFormatId::STARWRITERGLOB_8_TEMPLATE :
344 return SvGlobalName( SO3_SWGLOB_CLASSID_600xB21A0A7C, 0xE403, 0x41FE, 0x95, 0x62, 0xBD, 0x13, 0xEA, 0x6F
, 0x15, 0xA0
);
345 case SotClipboardFormatId::STARDRAW_8 :
346 case SotClipboardFormatId::STARDRAW_8_TEMPLATE :
347 return SvGlobalName( SO3_SDRAW_CLASSID_600x4BAB8970, 0x8A3B, 0x45B3, 0x99, 0x1C, 0xCB, 0xEE, 0xAC, 0x6B
, 0xD5, 0xE3
);
348 case SotClipboardFormatId::STARIMPRESS_8 :
349 case SotClipboardFormatId::STARIMPRESS_8_TEMPLATE :
350 return SvGlobalName( SO3_SIMPRESS_CLASSID_600x9176E48A, 0x637A, 0x4D1F, 0x80, 0x3B, 0x99, 0xD9, 0xBF, 0xAC
, 0x10, 0x47
);
351 case SotClipboardFormatId::STARCALC_8 :
352 case SotClipboardFormatId::STARCALC_8_TEMPLATE :
353 return SvGlobalName( SO3_SC_CLASSID_600x47BBB4CB, 0xCE4C, 0x4E80, 0xA5, 0x91, 0x42, 0xD9, 0xAE, 0x74
, 0x95, 0x0F
);
354 case SotClipboardFormatId::STARCHART_8 :
355 case SotClipboardFormatId::STARCHART_8_TEMPLATE :
356 return SvGlobalName( SO3_SCH_CLASSID_600x12DCAE26, 0x281F, 0x416F, 0xA2, 0x34, 0xC3, 0x08, 0x61, 0x27
, 0x38, 0x2E
);
357 case SotClipboardFormatId::STARMATH_8 :
358 case SotClipboardFormatId::STARMATH_8_TEMPLATE :
359 return SvGlobalName( SO3_SM_CLASSID_600x078B7ABA, 0x54FC, 0x457F, 0x85, 0x51, 0x61, 0x47, 0xE7, 0x76
, 0xA9, 0x97
);
360 case SotClipboardFormatId::STARWRITER_60 :
361 return SvGlobalName( SO3_SW_CLASSID_600x8BC6B165, 0xB1B2, 0x4EDD, 0xAA, 0x47, 0xDA, 0xE2, 0xEE, 0x68
, 0x9D, 0xD6
);
362 case SotClipboardFormatId::STARWRITERWEB_60 :
363 return SvGlobalName( SO3_SWWEB_CLASSID_600xA8BBA60C, 0x7C60, 0x4550, 0x91, 0xCE, 0x39, 0xC3, 0x90, 0x3F
, 0xAC, 0x5E
);
364 case SotClipboardFormatId::STARWRITERGLOB_60 :
365 return SvGlobalName( SO3_SWGLOB_CLASSID_600xB21A0A7C, 0xE403, 0x41FE, 0x95, 0x62, 0xBD, 0x13, 0xEA, 0x6F
, 0x15, 0xA0
);
366 case SotClipboardFormatId::STARDRAW_60 :
367 return SvGlobalName( SO3_SDRAW_CLASSID_600x4BAB8970, 0x8A3B, 0x45B3, 0x99, 0x1C, 0xCB, 0xEE, 0xAC, 0x6B
, 0xD5, 0xE3
);
368 case SotClipboardFormatId::STARIMPRESS_60 :
369 return SvGlobalName( SO3_SIMPRESS_CLASSID_600x9176E48A, 0x637A, 0x4D1F, 0x80, 0x3B, 0x99, 0xD9, 0xBF, 0xAC
, 0x10, 0x47
);
370 case SotClipboardFormatId::STARCALC_60 :
371 return SvGlobalName( SO3_SC_CLASSID_600x47BBB4CB, 0xCE4C, 0x4E80, 0xA5, 0x91, 0x42, 0xD9, 0xAE, 0x74
, 0x95, 0x0F
);
372 case SotClipboardFormatId::STARCHART_60 :
373 return SvGlobalName( SO3_SCH_CLASSID_600x12DCAE26, 0x281F, 0x416F, 0xA2, 0x34, 0xC3, 0x08, 0x61, 0x27
, 0x38, 0x2E
);
374 case SotClipboardFormatId::STARMATH_60 :
375 return SvGlobalName( SO3_SM_CLASSID_600x078B7ABA, 0x54FC, 0x457F, 0x85, 0x51, 0x61, 0x47, 0xE7, 0x76
, 0xA9, 0x97
);
376 default :
377 return SvGlobalName();
378 }
379}
380
381// All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle
382// class, that uses the refcounted object as impl-class.
383
384class UCBStorageStream_Impl : public SvRefBase, public SvStream
385{
386 virtual ~UCBStorageStream_Impl() override;
387public:
388
389 virtual std::size_t GetData(void* pData, std::size_t nSize) override;
390 virtual std::size_t PutData(const void* pData, std::size_t nSize) override;
391 virtual sal_uInt64 SeekPos( sal_uInt64 nPos ) override;
392 virtual void SetSize( sal_uInt64 nSize ) override;
393 virtual void FlushData() override;
394 virtual void ResetError() override;
395
396 UCBStorageStream* m_pAntiImpl; // only valid if an external reference exists
397
398 OUString m_aOriginalName;// the original name before accessing the stream
399 OUString m_aName; // the actual name ( changed with a Rename command at the parent )
400 OUString m_aURL; // the full path name to create the content
401 OUString m_aContentType;
402 OUString m_aOriginalContentType;
403 OString m_aKey;
404 ::ucbhelper::Content* m_pContent; // the content that provides the data
405 Reference<XInputStream> m_rSource; // the stream covering the original data of the content
406 std::unique_ptr<SvStream> m_pStream; // the stream worked on; for readonly streams it is the original stream of the content
407 // for read/write streams it's a copy into a temporary file
408 OUString m_aTempURL; // URL of this temporary stream
409 ErrCode m_nError;
410 StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing )
411 bool m_bSourceRead; // Source still contains useful information
412 bool m_bModified; // only modified streams will be sent to the original content
413 bool m_bCommited; // sending the streams is coordinated by the root storage of the package
414 bool m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages
415 // this means that the root storage does an autocommit when its external
416 // reference is destroyed
417 bool m_bIsOLEStorage;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream
418
419 UCBStorageStream_Impl( const OUString&, StreamMode, UCBStorageStream*, bool,
420 bool bRepair, Reference< XProgressHandler > const & xProgress );
421
422 void Free();
423 bool Init();
424 bool Clear();
425 sal_Int16 Commit(); // if modified and committed: transfer an XInputStream to the content
426 void Revert(); // discard all changes
427 BaseStorage* CreateStorage();// create an OLE Storage on the UCBStorageStream
428 sal_uLong GetSize();
429
430 sal_uInt64 ReadSourceWriteTemporary( sal_uInt64 aLength ); // read aLength from source and copy to temporary,
431 // no seeking is produced
432 void ReadSourceWriteTemporary(); // read source till the end and copy to temporary,
433
434 void CopySourceToTemporary(); // same as ReadSourceWriteToTemporary()
435 // but the writing is done at the end of temporary
436 // pointer position is not changed
437 using SvStream::SetError;
438 void SetError( ErrCode nError );
439 void PrepareCachedForReopen( StreamMode nMode );
440};
441
442typedef tools::SvRef<UCBStorageStream_Impl> UCBStorageStream_ImplRef;
443
444struct UCBStorageElement_Impl;
445typedef std::vector<std::unique_ptr<UCBStorageElement_Impl>> UCBStorageElementList_Impl;
446
447class UCBStorage_Impl : public SvRefBase
448{
449 virtual ~UCBStorage_Impl() override;
450public:
451 UCBStorage* m_pAntiImpl; // only valid if external references exists
452
453 OUString m_aName; // the actual name ( changed with a Rename command at the parent )
454 OUString m_aURL; // the full path name to create the content
455 OUString m_aContentType;
456 OUString m_aOriginalContentType;
457 std::unique_ptr<::ucbhelper::Content> m_pContent; // the content that provides the storage elements
458 std::unique_ptr<::utl::TempFile> m_pTempFile; // temporary file, only for storages on stream
459 SvStream* m_pSource; // original stream, only for storages on a stream
460 ErrCode m_nError;
461 StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing )
462 bool m_bCommited; // sending the streams is coordinated by the root storage of the package
463 bool m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages
464 // this means that the root storage does an autocommit when its external
465 // reference is destroyed
466 bool m_bIsRoot; // marks this storage as root storages that manages all commits and reverts
467 bool m_bIsLinked;
468 bool m_bListCreated;
469 SotClipboardFormatId m_nFormat;
470 OUString m_aUserTypeName;
471 SvGlobalName m_aClassId;
472
473 UCBStorageElementList_Impl m_aChildrenList;
474
475 bool m_bRepairPackage;
476 Reference< XProgressHandler > m_xProgressHandler;
477
478 UCBStorage_Impl( const ::ucbhelper::Content&, const OUString&, StreamMode, UCBStorage*, bool,
479 bool, bool = false, Reference< XProgressHandler > const & = Reference< XProgressHandler >() );
480 UCBStorage_Impl( const OUString&, StreamMode, UCBStorage*, bool, bool,
481 bool, Reference< XProgressHandler > const & );
482 UCBStorage_Impl( SvStream&, UCBStorage*, bool );
483 void Init();
484 sal_Int16 Commit();
485 void Revert();
486 bool Insert( ::ucbhelper::Content *pContent );
487 UCBStorage_Impl* OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect );
488 void OpenStream( UCBStorageElement_Impl*, StreamMode, bool );
489 void SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& );
490 void GetProps( sal_Int32&, Sequence < Sequence < PropertyValue > >& rSequence, const OUString& );
491 sal_Int32 GetObjectCount();
492 void ReadContent();
493 void CreateContent();
494 ::ucbhelper::Content* GetContent()
495 {
496 if ( !m_pContent )
497 CreateContent();
498 return m_pContent.get();
499 }
500 UCBStorageElementList_Impl& GetChildrenList()
501 {
502 const ErrCode nError = m_nError;
503 ReadContent();
504 if ( m_nMode & StreamMode::WRITE )
505 {
506 m_nError = nError;
507 if ( m_pAntiImpl )
508 {
509 m_pAntiImpl->ResetError();
510 m_pAntiImpl->SetError( nError );
511 }
512 }
513 return m_aChildrenList;
514 }
515
516 void SetError( ErrCode nError );
517};
518
519typedef tools::SvRef<UCBStorage_Impl> UCBStorage_ImplRef;
520
521// this struct contains all necessary information on an element inside a UCBStorage
522struct UCBStorageElement_Impl
523{
524 OUString m_aName; // the actual URL relative to the root "folder"
525 OUString m_aOriginalName;// the original name in the content
526 sal_uLong m_nSize;
527 bool m_bIsFolder; // Only true when it is a UCBStorage !
528 bool m_bIsStorage; // Also true when it is an OLEStorage !
529 bool m_bIsRemoved; // element will be removed on commit
530 bool m_bIsInserted; // element will be removed on revert
531 UCBStorage_ImplRef m_xStorage; // reference to the "real" storage
532 UCBStorageStream_ImplRef m_xStream; // reference to the "real" stream
533
534 UCBStorageElement_Impl( const OUString& rName,
535 bool bIsFolder = false, sal_uLong nSize = 0 )
536 : m_aName( rName )
537 , m_aOriginalName( rName )
538 , m_nSize( nSize )
539 , m_bIsFolder( bIsFolder )
540 , m_bIsStorage( bIsFolder )
541 , m_bIsRemoved( false )
542 , m_bIsInserted( false )
543 {
544 }
545
546 ::ucbhelper::Content* GetContent();
547 bool IsModified() const;
548 OUString GetContentType() const;
549 void SetContentType( const OUString& );
550 OUString GetOriginalContentType() const;
551 bool IsLoaded() const
552 { return m_xStream.is() || m_xStorage.is(); }
553};
554
555::ucbhelper::Content* UCBStorageElement_Impl::GetContent()
556{
557 if ( m_xStream.is() )
558 return m_xStream->m_pContent;
559 else if ( m_xStorage.is() )
560 return m_xStorage->GetContent();
561 else
562 return nullptr;
563}
564
565OUString UCBStorageElement_Impl::GetContentType() const
566{
567 if ( m_xStream.is() )
568 return m_xStream->m_aContentType;
569 else if ( m_xStorage.is() )
570 return m_xStorage->m_aContentType;
571 else
572 {
573 OSL_FAIL("Element not loaded!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "573" ": "), "%s", "Element not loaded!"); } } while (false
)
;
574 return OUString();
575 }
576}
577
578void UCBStorageElement_Impl::SetContentType( const OUString& rType )
579{
580 if ( m_xStream.is() ) {
581 m_xStream->m_aContentType = m_xStream->m_aOriginalContentType = rType;
582 }
583 else if ( m_xStorage.is() ) {
584 m_xStorage->m_aContentType = m_xStorage->m_aOriginalContentType = rType;
585 }
586 else {
587 OSL_FAIL("Element not loaded!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "587" ": "), "%s", "Element not loaded!"); } } while (false
)
;
588 }
589}
590
591OUString UCBStorageElement_Impl::GetOriginalContentType() const
592{
593 if ( m_xStream.is() )
594 return m_xStream->m_aOriginalContentType;
595 else if ( m_xStorage.is() )
596 return m_xStorage->m_aOriginalContentType;
597 else
598 return OUString();
599}
600
601bool UCBStorageElement_Impl::IsModified() const
602{
603 bool bModified = m_bIsRemoved || m_bIsInserted || m_aName != m_aOriginalName;
604 if ( bModified )
605 {
606 if ( m_xStream.is() )
607 bModified = m_xStream->m_aContentType != m_xStream->m_aOriginalContentType;
608 else if ( m_xStorage.is() )
609 bModified = m_xStorage->m_aContentType != m_xStorage->m_aOriginalContentType;
610 }
611
612 return bModified;
613}
614
615UCBStorageStream_Impl::UCBStorageStream_Impl( const OUString& rName, StreamMode nMode, UCBStorageStream* pStream, bool bDirect, bool bRepair, Reference< XProgressHandler > const & xProgress )
616 : m_pAntiImpl( pStream )
617 , m_aURL( rName )
618 , m_pContent( nullptr )
619 , m_nError( ERRCODE_NONEErrCode(0) )
620 , m_nMode( nMode )
621 , m_bSourceRead( !( nMode & StreamMode::TRUNC ) )
622 , m_bModified( false )
623 , m_bCommited( false )
624 , m_bDirect( bDirect )
625 , m_bIsOLEStorage( false )
626{
627 // name is last segment in URL
628 INetURLObject aObj( rName );
629 m_aName = m_aOriginalName = aObj.GetLastName();
630 try
631 {
632 // create the content
633 Reference< css::ucb::XCommandEnvironment > xComEnv;
634
635 OUString aTemp( rName );
636
637 if ( bRepair )
638 {
639 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(), xProgress );
640 aTemp += "?repairpackage";
641 }
642
643 m_pContent = new ::ucbhelper::Content( aTemp, xComEnv, comphelper::getProcessComponentContext() );
644 }
645 catch (const ContentCreationException&)
646 {
647 // content could not be created
648 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
649 }
650 catch (const RuntimeException&)
651 {
652 // any other error - not specified
653 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
654 }
655}
656
657UCBStorageStream_Impl::~UCBStorageStream_Impl()
658{
659 if( m_rSource.is() )
660 m_rSource.clear();
661
662 m_pStream.reset();
663
664 if (!m_aTempURL.isEmpty())
665 osl::File::remove(m_aTempURL);
666
667 delete m_pContent;
668}
669
670
671bool UCBStorageStream_Impl::Init()
672{
673 if( !m_pStream )
674 {
675 // no temporary stream was created
676 // create one
677
678 if ( m_aTempURL.isEmpty() )
679 m_aTempURL = ::utl::TempFile().GetURL();
680
681 m_pStream = ::utl::UcbStreamHelper::CreateStream( m_aTempURL, StreamMode::STD_READWRITE, true /* bFileExists */ );
682#if OSL_DEBUG_LEVEL1 > 0
683 ++nOpenFiles;
684#endif
685
686 if( !m_pStream )
687 {
688 OSL_FAIL( "Suspicious temporary stream creation!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "688" ": "), "%s", "Suspicious temporary stream creation!"
); } } while (false)
;
689 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
690 return false;
691 }
692
693 SetError( m_pStream->GetError() );
694 }
695
696 if( m_bSourceRead && !m_rSource.is() )
697 {
698 // source file contain useful information and is not opened
699 // open it from the point of noncopied data
700
701 try
702 {
703 m_rSource = m_pContent->openStream();
704 }
705 catch (const Exception&)
706 {
707 // usually means that stream could not be opened
708 }
709
710 if( m_rSource.is() )
711 {
712 m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
713
714 try
715 {
716 m_rSource->skipBytes( m_pStream->Tell() );
717 }
718 catch (const BufferSizeExceededException&)
719 {
720 // the temporary stream already contain all the data
721 m_bSourceRead = false;
722 }
723 catch (const Exception&)
724 {
725 // something is really wrong
726 m_bSourceRead = false;
727 OSL_FAIL( "Can not operate original stream!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "727" ": "), "%s", "Can not operate original stream!"); }
} while (false)
;
728 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
729 }
730
731 m_pStream->Seek( 0 );
732 }
733 else
734 {
735 // if the new file is edited then no source exist
736 m_bSourceRead = false;
737 //SetError( SVSTREAM_CANNOT_MAKE );
738 }
739 }
740
741 DBG_ASSERT( m_rSource.is() || !m_bSourceRead, "Unreadable source stream!" )do { if (true && (!(m_rSource.is() || !m_bSourceRead)
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "741" ": "), "%s", "Unreadable source stream!"); } } while
(false)
;
742
743 return true;
744}
745
746void UCBStorageStream_Impl::ReadSourceWriteTemporary()
747{
748 // read source stream till the end and copy all the data to
749 // the current position of the temporary stream
750
751 if( m_bSourceRead )
752 {
753 Sequence<sal_Int8> aData(32000);
754
755 try
756 {
757 sal_uLong aReaded;
758 do
759 {
760 aReaded = m_rSource->readBytes( aData, 32000 );
761 m_pStream->WriteBytes(aData.getArray(), aReaded);
762 } while( aReaded == 32000 );
763 }
764 catch (const Exception &)
765 {
766 TOOLS_WARN_EXCEPTION("sot", "")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "766" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "766" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "766" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "766" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
767 }
768 }
769
770 m_bSourceRead = false;
771}
772
773sal_uInt64 UCBStorageStream_Impl::ReadSourceWriteTemporary(sal_uInt64 aLength)
774{
775 // read aLength bite from the source stream and copy them to the current
776 // position of the temporary stream
777
778 sal_uInt64 aResult = 0;
779
780 if( m_bSourceRead )
781 {
782 Sequence<sal_Int8> aData(32000);
783
784 try
785 {
786
787 sal_uLong aReaded = 32000;
788
789 for (sal_uInt64 nInd = 0; nInd < aLength && aReaded == 32000 ; nInd += 32000)
790 {
791 sal_uLong aToCopy = std::min<sal_uInt64>( aLength - nInd, 32000 );
792 aReaded = m_rSource->readBytes( aData, aToCopy );
793 aResult += m_pStream->WriteBytes(aData.getArray(), aReaded);
794 }
795
796 if( aResult < aLength )
797 m_bSourceRead = false;
798 }
799 catch( const Exception & )
800 {
801 TOOLS_WARN_EXCEPTION("sot", "")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "801" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "801" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "801" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "801" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
802 }
803 }
804
805 return aResult;
806}
807
808void UCBStorageStream_Impl::CopySourceToTemporary()
809{
810 // current position of the temporary stream is not changed
811 if( m_bSourceRead )
812 {
813 sal_uInt64 aPos = m_pStream->Tell();
814 m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
815 ReadSourceWriteTemporary();
816 m_pStream->Seek( aPos );
817 }
818}
819
820// UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream
821// of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified
822std::size_t UCBStorageStream_Impl::GetData(void* pData, std::size_t const nSize)
823{
824 std::size_t aResult = 0;
825
826 if( !Init() )
827 return 0;
828
829
830 // read data that is in temporary stream
831 aResult = m_pStream->ReadBytes( pData, nSize );
832 if( m_bSourceRead && aResult < nSize )
833 {
834 // read the tail of the data from original stream
835 // copy this tail to the temporary stream
836
837 std::size_t aToRead = nSize - aResult;
838 pData = static_cast<void*>( static_cast<char*>(pData) + aResult );
839
840 try
841 {
842 Sequence<sal_Int8> aData( aToRead );
843 std::size_t aReaded = m_rSource->readBytes( aData, aToRead );
844 aResult += m_pStream->WriteBytes(static_cast<void*>(aData.getArray()), aReaded);
845 memcpy( pData, aData.getArray(), aReaded );
846 }
847 catch (const Exception &)
848 {
849 TOOLS_WARN_EXCEPTION("sot", "")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "849" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "849" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "849" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "849" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
850 }
851
852 if( aResult < nSize )
853 m_bSourceRead = false;
854 }
855
856 return aResult;
857}
858
859std::size_t UCBStorageStream_Impl::PutData(const void* pData, std::size_t const nSize)
860{
861 if ( !(m_nMode & StreamMode::WRITE) )
862 {
863 SetError( ERRCODE_IO_ACCESSDENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 ) );
864 return 0; // ?mav?
865 }
866
867 if( !nSize || !Init() )
868 return 0;
869
870 std::size_t aResult = m_pStream->WriteBytes( pData, nSize );
871
872 m_bModified = aResult > 0;
873
874 return aResult;
875
876}
877
878sal_uInt64 UCBStorageStream_Impl::SeekPos(sal_uInt64 const nPos)
879{
880 // check if a truncated STREAM_SEEK_TO_END was passed
881 assert(nPos != SAL_MAX_UINT32)(static_cast <bool> (nPos != ((sal_uInt32) 0xFFFFFFFF))
? void (0) : __assert_fail ("nPos != SAL_MAX_UINT32", "/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
, 881, __extension__ __PRETTY_FUNCTION__))
;
882
883 if( !Init() )
884 return 0;
885
886 sal_uInt64 aResult;
887
888 if( nPos == STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) )
889 {
890 m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
891 ReadSourceWriteTemporary();
892 aResult = m_pStream->Tell();
893 }
894 else
895 {
896 // the problem is that even if nPos is larger the length
897 // of the stream, the stream pointer will be moved to this position
898 // so we have to check if temporary stream does not contain required position
899
900 if( m_pStream->Tell() > nPos
901 || m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) ) > nPos )
902 {
903 // no copying is required
904 aResult = m_pStream->Seek( nPos );
905 }
906 else
907 {
908 // the temp stream pointer points to the end now
909 aResult = m_pStream->Tell();
910
911 if( aResult < nPos )
912 {
913 if( m_bSourceRead )
914 {
915 aResult += ReadSourceWriteTemporary( nPos - aResult );
916 if( aResult < nPos )
917 m_bSourceRead = false;
918
919 DBG_ASSERT( aResult == m_pStream->Tell(), "Error in stream arithmetic!\n" )do { if (true && (!(aResult == m_pStream->Tell()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "919" ": "), "%s", "Error in stream arithmetic!\n"); } }
while (false)
;
920 }
921
922 if( (m_nMode & StreamMode::WRITE) && !m_bSourceRead && aResult < nPos )
923 {
924 // it means that all the Source stream was copied already
925 // but the required position still was not reached
926 // for writable streams it should be done
927 m_pStream->SetStreamSize( nPos );
928 aResult = m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
929 DBG_ASSERT( aResult == nPos, "Error in stream arithmetic!\n" )do { if (true && (!(aResult == nPos))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "929" ": "), "%s", "Error in stream arithmetic!\n"); } }
while (false)
;
930 }
931 }
932 }
933 }
934
935 return aResult;
936}
937
938void UCBStorageStream_Impl::SetSize(sal_uInt64 const nSize)
939{
940 if ( !(m_nMode & StreamMode::WRITE) )
941 {
942 SetError( ERRCODE_IO_ACCESSDENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 ) );
943 return;
944 }
945
946 if( !Init() )
947 return;
948
949 m_bModified = true;
950
951 if( m_bSourceRead )
952 {
953 sal_uInt64 const aPos = m_pStream->Tell();
954 m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
955 if( m_pStream->Tell() < nSize )
956 ReadSourceWriteTemporary( nSize - m_pStream->Tell() );
957 m_pStream->Seek( aPos );
958 }
959
960 m_pStream->SetStreamSize( nSize );
961 m_bSourceRead = false;
962}
963
964void UCBStorageStream_Impl::FlushData()
965{
966 if( m_pStream )
967 {
968 CopySourceToTemporary();
969 m_pStream->Flush();
970 }
971
972 m_bCommited = true;
973}
974
975void UCBStorageStream_Impl::SetError( ErrCode nErr )
976{
977 if ( !m_nError )
978 {
979 m_nError = nErr;
980 SvStream::SetError( nErr );
981 if ( m_pAntiImpl ) m_pAntiImpl->SetError( nErr );
982 }
983}
984
985void UCBStorageStream_Impl::ResetError()
986{
987 m_nError = ERRCODE_NONEErrCode(0);
988 SvStream::ResetError();
989 if ( m_pAntiImpl )
990 m_pAntiImpl->ResetError();
991}
992
993sal_uLong UCBStorageStream_Impl::GetSize()
994{
995 if( !Init() )
996 return 0;
997
998 sal_uInt64 nPos = m_pStream->Tell();
999 m_pStream->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
1000 ReadSourceWriteTemporary();
1001 sal_uInt64 nRet = m_pStream->Tell();
1002 m_pStream->Seek( nPos );
1003
1004 return nRet;
1005}
1006
1007BaseStorage* UCBStorageStream_Impl::CreateStorage()
1008{
1009 // create an OLEStorage on a SvStream ( = this )
1010 // it gets the root attribute because otherwise it would probably not write before my root is committed
1011 UCBStorageStream* pNewStorageStream = new UCBStorageStream( this );
1012 Storage *pStorage = new Storage( *pNewStorageStream, m_bDirect );
1013
1014 // GetError() call clears error code for OLE storages, must be changed in future
1015 const ErrCode nTmpErr = pStorage->GetError();
1016 pStorage->SetError( nTmpErr );
1017
1018 m_bIsOLEStorage = !nTmpErr;
1019 return static_cast< BaseStorage* > ( pStorage );
1020}
1021
1022sal_Int16 UCBStorageStream_Impl::Commit()
1023{
1024 // send stream to the original content
1025 // the parent storage is responsible for the correct handling of deleted contents
1026 if ( m_bCommited || m_bIsOLEStorage || m_bDirect )
1027 {
1028 // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage
1029 // was committed as well ( if not opened in direct mode )
1030
1031 if ( m_bModified )
1032 {
1033 try
1034 {
1035 CopySourceToTemporary();
1036
1037 // release all stream handles
1038 Free();
1039
1040 // the temporary file does not exist only for truncated streams
1041 DBG_ASSERT( !m_aTempURL.isEmpty() || ( m_nMode & StreamMode::TRUNC ), "No temporary file to read from!")do { if (true && (!(!m_aTempURL.isEmpty() || ( m_nMode
& StreamMode::TRUNC )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1041" ": "), "%s", "No temporary file to read from!"); }
} while (false)
;
1042 if ( m_aTempURL.isEmpty() && !( m_nMode & StreamMode::TRUNC ) )
1043 throw RuntimeException();
1044
1045 // create wrapper to stream that is only used while reading inside package component
1046 Reference < XInputStream > xStream = new FileStreamWrapper_Impl( m_aTempURL );
1047
1048 InsertCommandArgument aArg;
1049 aArg.Data = xStream;
1050 aArg.ReplaceExisting = true;
1051 m_pContent->executeCommand( "insert", Any(aArg) );
1052
1053 // wrapper now controls lifetime of temporary file
1054 m_aTempURL.clear();
1055
1056 INetURLObject aObj( m_aURL );
1057 aObj.setName( m_aName );
1058 m_aURL = aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1059 m_bModified = false;
1060 m_bSourceRead = true;
1061 }
1062 catch (const CommandAbortedException&)
1063 {
1064 // any command wasn't executed successfully - not specified
1065 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1066 return COMMIT_RESULT_FAILURE0;
1067 }
1068 catch (const RuntimeException&)
1069 {
1070 // any other error - not specified
1071 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1072 return COMMIT_RESULT_FAILURE0;
1073 }
1074 catch (const Exception&)
1075 {
1076 // any other error - not specified
1077 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1078 return COMMIT_RESULT_FAILURE0;
1079 }
1080
1081 m_bCommited = false;
1082 return COMMIT_RESULT_SUCCESS2;
1083 }
1084 }
1085
1086 return COMMIT_RESULT_NOTHING_TO_DO1;
1087}
1088
1089void UCBStorageStream_Impl::Revert()
1090{
1091 // if an OLEStorage is created on this stream, no "revert" is necessary because OLEStorages do nothing on "Revert" !
1092 if ( m_bCommited )
1093 {
1094 OSL_FAIL("Revert while commit is in progress!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1094" ": "), "%s", "Revert while commit is in progress!"
); } } while (false)
;
1095 return; // ???
1096 }
1097
1098 Free();
1099 if ( !m_aTempURL.isEmpty() )
1100 {
1101 osl::File::remove(m_aTempURL);
1102 m_aTempURL.clear();
1103 }
1104
1105 m_bSourceRead = false;
1106 try
1107 {
1108 m_rSource = m_pContent->openStream();
1109 if( m_rSource.is() )
1110 {
1111 if ( m_pAntiImpl && ( m_nMode & StreamMode::TRUNC ) )
1112 // stream is in use and should be truncated
1113 m_bSourceRead = false;
1114 else
1115 {
1116 m_nMode &= ~StreamMode::TRUNC;
1117 m_bSourceRead = true;
1118 }
1119 }
1120 else
1121 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
1122 }
1123 catch (const ContentCreationException&)
1124 {
1125 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1126 }
1127 catch (const RuntimeException&)
1128 {
1129 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1130 }
1131 catch (const Exception&)
1132 {
1133 }
1134
1135 m_bModified = false;
1136 m_aName = m_aOriginalName;
1137 m_aContentType = m_aOriginalContentType;
1138}
1139
1140bool UCBStorageStream_Impl::Clear()
1141{
1142 bool bRet = ( m_pAntiImpl == nullptr );
1143 DBG_ASSERT( bRet, "Removing used stream!" )do { if (true && (!(bRet))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1143" ": "), "%s", "Removing used stream!"); } } while (
false)
;
1144 if( bRet )
1145 {
1146 Free();
1147 }
1148
1149 return bRet;
1150}
1151
1152void UCBStorageStream_Impl::Free()
1153{
1154#if OSL_DEBUG_LEVEL1 > 0
1155 if ( m_pStream )
1156 {
1157 if ( !m_aTempURL.isEmpty() )
1158 --nOpenFiles;
1159 else
1160 --nOpenStreams;
1161 }
1162#endif
1163
1164 m_rSource.clear();
1165 m_pStream.reset();
1166}
1167
1168void UCBStorageStream_Impl::PrepareCachedForReopen( StreamMode nMode )
1169{
1170 bool isWritable = bool( m_nMode & StreamMode::WRITE );
1171 if ( isWritable )
1172 {
1173 // once stream was writable, never reset to readonly
1174 nMode |= StreamMode::WRITE;
1175 }
1176
1177 m_nMode = nMode;
1178 Free();
1179
1180 if ( nMode & StreamMode::TRUNC )
1181 {
1182 m_bSourceRead = false; // usually it should be 0 already but just in case...
1183
1184 if ( !m_aTempURL.isEmpty() )
1185 {
1186 osl::File::remove(m_aTempURL);
1187 m_aTempURL.clear();
1188 }
1189 }
1190}
1191
1192UCBStorageStream::UCBStorageStream( const OUString& rName, StreamMode nMode, bool bDirect, bool bRepair, Reference< XProgressHandler > const & xProgress )
1193{
1194 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1195 // to class UCBStorageStream !
1196 pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, bRepair, xProgress );
1197 pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
1198 StorageBase::m_nMode = pImp->m_nMode;
1199}
1200
1201UCBStorageStream::UCBStorageStream( UCBStorageStream_Impl *pImpl )
1202 : pImp( pImpl )
1203{
1204 pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
1205 pImp->m_pAntiImpl = this;
1206 SetError( pImp->m_nError );
1207 StorageBase::m_nMode = pImp->m_nMode;
1208}
1209
1210UCBStorageStream::~UCBStorageStream()
1211{
1212 if ( pImp->m_nMode & StreamMode::WRITE )
10
Taking false branch
1213 pImp->Flush();
1214 pImp->m_pAntiImpl = nullptr;
1215 pImp->Free();
1216 pImp->ReleaseRef();
11
Calling 'SvRefBase::ReleaseRef'
16
Returning; memory was released
1217}
1218
1219sal_uLong UCBStorageStream::Read( void * pData, sal_uLong nSize )
1220{
1221 //return pImp->m_pStream->Read( pData, nSize );
1222 return pImp->GetData( pData, nSize );
1223}
1224
1225sal_uLong UCBStorageStream::Write( const void* pData, sal_uLong nSize )
1226{
1227 return pImp->PutData( pData, nSize );
1228}
1229
1230sal_uInt64 UCBStorageStream::Seek( sal_uInt64 nPos )
1231{
1232 //return pImp->m_pStream->Seek( nPos );
1233 return pImp->Seek( nPos );
1234}
1235
1236sal_uLong UCBStorageStream::Tell()
1237{
1238 if( !pImp->Init() )
1239 return 0;
1240 return pImp->m_pStream->Tell();
1241}
1242
1243void UCBStorageStream::Flush()
1244{
1245 // streams are never really transacted, so flush also means commit !
1246 Commit();
1247}
1248
1249bool UCBStorageStream::SetSize( sal_uLong nNewSize )
1250{
1251 pImp->SetSize( nNewSize );
1252 return !pImp->GetError();
1253}
1254
1255bool UCBStorageStream::Validate( bool bWrite ) const
1256{
1257 return ( !bWrite || ( pImp->m_nMode & StreamMode::WRITE ) );
1258}
1259
1260bool UCBStorageStream::ValidateMode( StreamMode m ) const
1261{
1262 // ???
1263 if( m == ( StreamMode::READ | StreamMode::TRUNC ) ) // from stg.cxx
1264 return true;
1265 if( ( m & StreamMode::READWRITE) == StreamMode::READ )
1266 {
1267 // only SHARE_DENYWRITE or SHARE_DENYALL allowed
1268 if( ( m & StreamMode::SHARE_DENYWRITE )
1269 || ( m & StreamMode::SHARE_DENYALL ) )
1270 return true;
1271 }
1272 else
1273 {
1274 // only SHARE_DENYALL allowed
1275 // storages open in r/o mode are OK, since only
1276 // the commit may fail
1277 if( m & StreamMode::SHARE_DENYALL )
1278 return true;
1279 }
1280
1281 return true;
1282}
1283
1284SvStream* UCBStorageStream::GetModifySvStream()
1285{
1286 return static_cast<SvStream*>(pImp);
1287}
1288
1289bool UCBStorageStream::Equals( const BaseStorageStream& rStream ) const
1290{
1291 // ???
1292 return static_cast<BaseStorageStream const *>(this) == &rStream;
1293}
1294
1295bool UCBStorageStream::Commit()
1296{
1297 // mark this stream for sending it on root commit
1298 pImp->FlushData();
1299 return true;
1300}
1301
1302void UCBStorageStream::CopyTo( BaseStorageStream* pDestStm )
1303{
1304 if( !pImp->Init() )
1305 return;
1306
1307 UCBStorageStream* pStg = dynamic_cast<UCBStorageStream*>( pDestStm );
1308 if ( pStg )
1309 pStg->pImp->m_aContentType = pImp->m_aContentType;
1310
1311 pDestStm->SetSize( 0 );
1312 Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
1313 sal_Int32 n = Tell();
1314 if( n < 0 )
1315 return;
1316
1317 if( !pDestStm->SetSize( n ) || !n )
1318 return;
1319
1320 std::unique_ptr<sal_uInt8[]> p(new sal_uInt8[ 4096 ]);
1321 Seek( 0 );
1322 pDestStm->Seek( 0 );
1323 while( n )
1324 {
1325 sal_uInt32 nn = n;
1326 if( nn > 4096 )
1327 nn = 4096;
1328 if( Read( p.get(), nn ) != nn )
1329 break;
1330 if( pDestStm->Write( p.get(), nn ) != nn )
1331 break;
1332 n -= nn;
1333 }
1334}
1335
1336bool UCBStorageStream::SetProperty( const OUString& rName, const css::uno::Any& rValue )
1337{
1338 if ( rName == "Title")
1339 return false;
1340
1341 if ( rName == "MediaType")
1342 {
1343 OUString aTmp;
1344 rValue >>= aTmp;
1345 pImp->m_aContentType = aTmp;
1346 }
1347
1348 try
1349 {
1350 if ( pImp->m_pContent )
1351 {
1352 pImp->m_pContent->setPropertyValue( rName, rValue );
1353 return true;
1354 }
1355 }
1356 catch (const Exception&)
1357 {
1358 }
1359
1360 return false;
1361}
1362
1363sal_uLong UCBStorageStream::GetSize() const
1364{
1365 return pImp->GetSize();
1366}
1367
1368UCBStorage::UCBStorage( SvStream& rStrm, bool bDirect )
1369{
1370 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1371 // to class UCBStorage !
1372 pImp = new UCBStorage_Impl( rStrm, this, bDirect );
1373
1374 pImp->AddFirstRef();
1375 pImp->Init();
1376 StorageBase::m_nMode = pImp->m_nMode;
1377}
1378
1379UCBStorage::UCBStorage( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
1380{
1381 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1382 // to class UCBStorage !
1383 pImp = new UCBStorage_Impl( rContent, rName, nMode, this, bDirect, bIsRoot );
1384 pImp->AddFirstRef();
1385 pImp->Init();
1386 StorageBase::m_nMode = pImp->m_nMode;
1387}
1388
1389UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1390{
1391 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1392 // to class UCBStorage !
1393 pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, bIsRepair, xProgressHandler );
1394 pImp->AddFirstRef();
1395 pImp->Init();
1396 StorageBase::m_nMode = pImp->m_nMode;
1397}
1398
1399UCBStorage::UCBStorage( const OUString& rName, StreamMode nMode, bool bDirect, bool bIsRoot )
1400{
1401 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1402 // to class UCBStorage !
1403 pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, false, Reference< XProgressHandler >() );
1404 pImp->AddFirstRef();
1405 pImp->Init();
1406 StorageBase::m_nMode = pImp->m_nMode;
1407}
1408
1409UCBStorage::UCBStorage( UCBStorage_Impl *pImpl )
1410 : pImp( pImpl )
1411{
1412 pImp->m_pAntiImpl = this;
1413 SetError( pImp->m_nError );
1414 pImp->AddFirstRef(); // use direct refcounting because in header file only a pointer should be used
1415 StorageBase::m_nMode = pImp->m_nMode;
1416}
1417
1418UCBStorage::~UCBStorage()
1419{
1420 if ( pImp->m_bIsRoot && pImp->m_bDirect && ( !pImp->m_pTempFile || pImp->m_pSource ) )
1421 // DirectMode is simulated with an AutoCommit
1422 Commit();
1423
1424 pImp->m_pAntiImpl = nullptr;
1425 pImp->ReleaseRef();
1426}
1427
1428UCBStorage_Impl::UCBStorage_Impl( const ::ucbhelper::Content& rContent, const OUString& rName, StreamMode nMode, UCBStorage* pStorage, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1429 : m_pAntiImpl( pStorage )
1430 , m_pContent( new ::ucbhelper::Content( rContent ) )
1431 , m_pSource( nullptr )
1432 //, m_pStream( NULL )
1433 , m_nError( ERRCODE_NONEErrCode(0) )
1434 , m_nMode( nMode )
1435 , m_bCommited( false )
1436 , m_bDirect( bDirect )
1437 , m_bIsRoot( bIsRoot )
1438 , m_bIsLinked( true )
1439 , m_bListCreated( false )
1440 , m_nFormat( SotClipboardFormatId::NONE )
1441 , m_aClassId( SvGlobalName() )
1442 , m_bRepairPackage( bIsRepair )
1443 , m_xProgressHandler( xProgressHandler )
1444{
1445 OUString aName( rName );
1446 if( aName.isEmpty() )
1447 {
1448 // no name given = use temporary name!
1449 DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" )do { if (true && (!(m_bIsRoot))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1449" ": "), "%s", "SubStorage must have a name!"); } }
while (false)
;
1450 m_pTempFile.reset(new ::utl::TempFile);
1451 m_pTempFile->EnableKillingFile();
1452 m_aName = aName = m_pTempFile->GetURL();
1453 }
1454
1455 m_aURL = rName;
1456}
1457
1458UCBStorage_Impl::UCBStorage_Impl( const OUString& rName, StreamMode nMode, UCBStorage* pStorage, bool bDirect, bool bIsRoot, bool bIsRepair, Reference< XProgressHandler > const & xProgressHandler )
1459 : m_pAntiImpl( pStorage )
1460 , m_pSource( nullptr )
1461 //, m_pStream( NULL )
1462 , m_nError( ERRCODE_NONEErrCode(0) )
1463 , m_nMode( nMode )
1464 , m_bCommited( false )
1465 , m_bDirect( bDirect )
1466 , m_bIsRoot( bIsRoot )
1467 , m_bIsLinked( false )
1468 , m_bListCreated( false )
1469 , m_nFormat( SotClipboardFormatId::NONE )
1470 , m_aClassId( SvGlobalName() )
1471 , m_bRepairPackage( bIsRepair )
1472 , m_xProgressHandler( xProgressHandler )
1473{
1474 OUString aName( rName );
1475 if( aName.isEmpty() )
1476 {
1477 // no name given = use temporary name!
1478 DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" )do { if (true && (!(m_bIsRoot))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1478" ": "), "%s", "SubStorage must have a name!"); } }
while (false)
;
1479 m_pTempFile.reset(new ::utl::TempFile);
1480 m_pTempFile->EnableKillingFile();
1481 m_aName = aName = m_pTempFile->GetURL();
1482 }
1483
1484 if ( m_bIsRoot )
1485 {
1486 // create the special package URL for the package content
1487 m_aURL = "vnd.sun.star.pkg://" +
1488 INetURLObject::encode( aName, INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All );
1489
1490 if ( m_nMode & StreamMode::WRITE )
1491 {
1492 // the root storage opens the package, so make sure that there is any
1493 ::utl::UcbStreamHelper::CreateStream( aName, StreamMode::STD_READWRITE, m_pTempFile != nullptr /* bFileExists */ );
1494 }
1495 }
1496 else
1497 {
1498 // substorages are opened like streams: the URL is a "child URL" of the root package URL
1499 m_aURL = rName;
1500 if ( !m_aURL.startsWith( "vnd.sun.star.pkg://") )
1501 m_bIsLinked = true;
1502 }
1503}
1504
1505UCBStorage_Impl::UCBStorage_Impl( SvStream& rStream, UCBStorage* pStorage, bool bDirect )
1506 : m_pAntiImpl( pStorage )
1507 , m_pTempFile( new ::utl::TempFile )
1508 , m_pSource( &rStream )
1509 , m_nError( ERRCODE_NONEErrCode(0) )
1510 , m_bCommited( false )
1511 , m_bDirect( bDirect )
1512 , m_bIsRoot( true )
1513 , m_bIsLinked( false )
1514 , m_bListCreated( false )
1515 , m_nFormat( SotClipboardFormatId::NONE )
1516 , m_aClassId( SvGlobalName() )
1517 , m_bRepairPackage( false )
1518{
1519 // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call,
1520 // which will be called in the storages' dtor
1521 m_pTempFile->EnableKillingFile();
1522 DBG_ASSERT( !bDirect, "Storage on a stream must not be opened in direct mode!" )do { if (true && (!(!bDirect))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1522" ": "), "%s", "Storage on a stream must not be opened in direct mode!"
); } } while (false)
;
1523
1524 // UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only
1525 // accessed readonly
1526 // the root storage opens the package; create the special package URL for the package content
1527 m_aURL = "vnd.sun.star.pkg://" +
1528 INetURLObject::encode( m_pTempFile->GetURL(), INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All );
1529
1530 // copy data into the temporary file
1531 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), StreamMode::STD_READWRITE, true /* bFileExists */ ));
1532 if ( pStream )
1533 {
1534 rStream.Seek(0);
1535 rStream.ReadStream( *pStream );
1536 pStream->Flush();
1537 pStream.reset();
1538 }
1539
1540 // close stream and let content access the file
1541 m_pSource->Seek(0);
1542
1543 // check opening mode
1544 m_nMode = StreamMode::READ;
1545 if( rStream.IsWritable() )
1546 m_nMode = StreamMode::READ | StreamMode::WRITE;
1547}
1548
1549void UCBStorage_Impl::Init()
1550{
1551 // name is last segment in URL
1552 INetURLObject aObj( m_aURL );
1553 if ( m_aName.isEmpty() )
1554 // if the name was not already set to a temp name
1555 m_aName = aObj.GetLastName();
1556
1557 if ( !m_pContent )
1558 CreateContent();
1559
1560 if ( m_pContent )
1561 {
1562 if ( m_bIsLinked )
1563 {
1564 if( m_bIsRoot )
1565 {
1566 ReadContent();
1567 if ( m_nError == ERRCODE_NONEErrCode(0) )
1568 {
1569 // read the manifest.xml file
1570 aObj.Append( "META-INF" );
1571 aObj.Append( "manifest.xml" );
1572
1573 // create input stream
1574 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::STD_READ ));
1575 // no stream means no manifest.xml
1576 if ( pStream )
1577 {
1578 if ( !pStream->GetError() )
1579 {
1580 ::utl::OInputStreamWrapper* pHelper = new ::utl::OInputStreamWrapper( *pStream );
1581 css::uno::Reference < css::io::XInputStream > xInputStream( pHelper );
1582
1583 // create a manifest reader object that will read in the manifest from the stream
1584 Reference < css::packages::manifest::XManifestReader > xReader =
1585 css::packages::manifest::ManifestReader::create(
1586 ::comphelper::getProcessComponentContext() ) ;
1587 Sequence < Sequence < PropertyValue > > aProps = xReader->readManifestSequence( xInputStream );
1588
1589 // cleanup
1590 xReader = nullptr;
1591 xInputStream = nullptr;
1592 SetProps( aProps, OUString() );
1593 }
1594 }
1595 }
1596 }
1597 else
1598 ReadContent();
1599 }
1600 else
1601 {
1602 // get the manifest information from the package
1603 try {
1604 Any aAny = m_pContent->getPropertyValue("MediaType");
1605 OUString aTmp;
1606 if ( ( aAny >>= aTmp ) && !aTmp.isEmpty() )
1607 m_aContentType = m_aOriginalContentType = aTmp;
1608 }
1609 catch (const Exception&)
1610 {
1611 SAL_WARN( "sot",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"
), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "getPropertyValue has thrown an exception! Please let developers know the scenario!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"),
("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"
), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "getPropertyValue has thrown an exception! Please let developers know the scenario!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"),
("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1612 "getPropertyValue has thrown an exception! Please let developers know the scenario!" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"
), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "getPropertyValue has thrown an exception! Please let developers know the scenario!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"),
("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"
), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getPropertyValue has thrown an exception! Please let developers know the scenario!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "getPropertyValue has thrown an exception! Please let developers know the scenario!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"),
("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1612" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1613 }
1614 }
1615 }
1616
1617 if ( m_aContentType.isEmpty() )
1618 return;
1619
1620 // get the clipboard format using the content type
1621 css::datatransfer::DataFlavor aDataFlavor;
1622 aDataFlavor.MimeType = m_aContentType;
1623 m_nFormat = SotExchange::GetFormat( aDataFlavor );
1624
1625 // get the ClassId using the clipboard format ( internal table )
1626 m_aClassId = GetClassId_Impl( m_nFormat );
1627
1628 // get human presentable name using the clipboard format
1629 SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
1630 m_aUserTypeName = aDataFlavor.HumanPresentableName;
1631
1632 if( m_pContent && !m_bIsLinked && m_aClassId != SvGlobalName() )
1633 ReadContent();
1634}
1635
1636void UCBStorage_Impl::CreateContent()
1637{
1638 try
1639 {
1640 // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
1641 Reference< css::ucb::XCommandEnvironment > xComEnv;
1642
1643 OUString aTemp( m_aURL );
1644
1645 if ( m_bRepairPackage )
1646 {
1647 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(),
1648 m_xProgressHandler );
1649 aTemp += "?repairpackage";
1650 }
1651
1652 m_pContent.reset(new ::ucbhelper::Content( aTemp, xComEnv, comphelper::getProcessComponentContext() ));
1653 }
1654 catch (const ContentCreationException&)
1655 {
1656 // content could not be created
1657 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
1658 }
1659 catch (const RuntimeException&)
1660 {
1661 // any other error - not specified
1662 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
1663 }
1664}
1665
1666void UCBStorage_Impl::ReadContent()
1667{
1668 if ( m_bListCreated )
1669 return;
1670
1671 m_bListCreated = true;
1672
1673 // create cursor for access to children
1674 Sequence< OUString > aProps(4);
1675 aProps[0] = "Title";
1676 aProps[1] = "IsFolder";
1677 aProps[2] = "MediaType";
1678 aProps[3] = "Size";
1679
1680 try
1681 {
1682 GetContent();
1683 if ( !m_pContent )
1684 return;
1685
1686 Reference< XResultSet > xResultSet = m_pContent->createCursor( aProps, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS );
1687 Reference< XRow > xRow( xResultSet, UNO_QUERY );
1688 if ( xResultSet.is() )
1689 {
1690 while ( xResultSet->next() )
1691 {
1692 // insert all into the children list
1693 OUString aTitle( xRow->getString(1) );
1694 if ( m_bIsLinked )
1695 {
1696 // unpacked storages have to deal with the meta-inf folder by themselves
1697 if ( aTitle == "META-INF" )
1698 continue;
1699 }
1700
1701 bool bIsFolder( xRow->getBoolean(2) );
1702 sal_Int64 nSize = xRow->getLong(4);
1703 UCBStorageElement_Impl* pElement = new UCBStorageElement_Impl( aTitle, bIsFolder, static_cast<sal_uLong>(nSize) );
1704 m_aChildrenList.emplace_back( pElement );
1705
1706 bool bIsOfficeDocument = m_bIsLinked || ( m_aClassId != SvGlobalName() );
1707 if ( bIsFolder )
1708 {
1709 if ( m_bIsLinked )
1710 OpenStorage( pElement, m_nMode, m_bDirect );
1711 if ( pElement->m_xStorage.is() )
1712 pElement->m_xStorage->Init();
1713 }
1714 else if ( bIsOfficeDocument )
1715 {
1716 // streams can be external OLE objects, so they are now folders, but storages!
1717 OUString aName( m_aURL + "/" + xRow->getString(1));
1718
1719 Reference< css::ucb::XCommandEnvironment > xComEnv;
1720 if ( m_bRepairPackage )
1721 {
1722 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< css::task::XInteractionHandler >(),
1723 m_xProgressHandler );
1724 aName += "?repairpackage";
1725 }
1726
1727 ::ucbhelper::Content aContent( aName, xComEnv, comphelper::getProcessComponentContext() );
1728
1729 OUString aMediaType;
1730 Any aAny = aContent.getPropertyValue("MediaType");
1731 if ( ( aAny >>= aMediaType ) && ( aMediaType == "application/vnd.sun.star.oleobject" ) )
1732 pElement->m_bIsStorage = true;
1733 else if ( aMediaType.isEmpty() )
1734 {
1735 // older files didn't have that special content type, so they must be detected
1736 OpenStream( pElement, StreamMode::STD_READ, m_bDirect );
1737 if ( Storage::IsStorageFile( pElement->m_xStream.get() ) )
1738 pElement->m_bIsStorage = true;
1739 else
1740 pElement->m_xStream->Free();
1741 }
1742 }
1743 }
1744 }
1745 }
1746 catch (const InteractiveIOException& r)
1747 {
1748 if ( r.Code != IOErrorCode_NOT_EXISTING )
1749 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1750 }
1751 catch (const CommandAbortedException&)
1752 {
1753 // any command wasn't executed successfully - not specified
1754 if ( !( m_nMode & StreamMode::WRITE ) )
1755 // if the folder was just inserted and not already committed, this is not an error!
1756 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1757 }
1758 catch (const RuntimeException&)
1759 {
1760 // any other error - not specified
1761 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1762 }
1763 catch (const ResultSetException&)
1764 {
1765 // means that the package file is broken
1766 SetError( ERRCODE_IO_BROKENPACKAGEErrCode( ErrCodeArea::Io, ErrCodeClass::Format, 38 ) );
1767 }
1768 catch (const SQLException&)
1769 {
1770 // means that the file can be broken
1771 SetError( ERRCODE_IO_WRONGFORMATErrCode( ErrCodeArea::Io, ErrCodeClass::Format, 21 ) );
1772 }
1773 catch (const Exception&)
1774 {
1775 // any other error - not specified
1776 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1777 }
1778}
1779
1780void UCBStorage_Impl::SetError( ErrCode nError )
1781{
1782 if ( !m_nError )
1783 {
1784 m_nError = nError;
1785 if ( m_pAntiImpl ) m_pAntiImpl->SetError( nError );
1786 }
1787}
1788
1789sal_Int32 UCBStorage_Impl::GetObjectCount()
1790{
1791 sal_Int32 nCount = m_aChildrenList.size();
1792 for (auto& pElement : m_aChildrenList)
1793 {
1794 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" )do { if (true && (!(!pElement->m_bIsFolder || pElement
->m_xStorage.is()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1794" ": "), "%s", "Storage should be open!"); } } while
(false)
;
1795 if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1796 nCount += pElement->m_xStorage->GetObjectCount();
1797 }
1798
1799 return nCount;
1800}
1801
1802static OUString Find_Impl( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1803{
1804 bool bFound = false;
1805 for ( const Sequence < PropertyValue >& rMyProps : rSequence )
1806 {
1807 OUString aType;
1808
1809 for ( const PropertyValue& rAny : rMyProps )
1810 {
1811 if ( rAny.Name == "FullPath" )
1812 {
1813 OUString aTmp;
1814 if ( ( rAny.Value >>= aTmp ) && aTmp == rPath )
1815 bFound = true;
1816 if ( !aType.isEmpty() )
1817 break;
1818 }
1819 else if ( rAny.Name == "MediaType" )
1820 {
1821 if ( ( rAny.Value >>= aType ) && !aType.isEmpty() && bFound )
1822 break;
1823 }
1824 }
1825
1826 if ( bFound )
1827 return aType;
1828 }
1829
1830 return OUString();
1831}
1832
1833void UCBStorage_Impl::SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1834{
1835 OUString aPath( rPath );
1836 if ( !m_bIsRoot )
1837 aPath += m_aName;
1838 aPath += "/";
1839
1840 m_aContentType = m_aOriginalContentType = Find_Impl( rSequence, aPath );
1841
1842 if ( m_bIsRoot )
1843 // the "FullPath" of a child always starts without '/'
1844 aPath.clear();
1845
1846 for (auto& pElement : m_aChildrenList)
1847 {
1848 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" )do { if (true && (!(!pElement->m_bIsFolder || pElement
->m_xStorage.is()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1848" ": "), "%s", "Storage should be open!"); } } while
(false)
;
1849 if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1850 pElement->m_xStorage->SetProps( rSequence, aPath );
1851 else
1852 {
1853 OUString aElementPath = aPath + pElement->m_aName;
1854 pElement->SetContentType( Find_Impl( rSequence, aElementPath ) );
1855 }
1856 }
1857
1858 if ( m_aContentType.isEmpty() )
1859 return;
1860
1861 // get the clipboard format using the content type
1862 css::datatransfer::DataFlavor aDataFlavor;
1863 aDataFlavor.MimeType = m_aContentType;
1864 m_nFormat = SotExchange::GetFormat( aDataFlavor );
1865
1866 // get the ClassId using the clipboard format ( internal table )
1867 m_aClassId = GetClassId_Impl( m_nFormat );
1868
1869 // get human presentable name using the clipboard format
1870 SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
1871 m_aUserTypeName = aDataFlavor.HumanPresentableName;
1872}
1873
1874void UCBStorage_Impl::GetProps( sal_Int32& nProps, Sequence < Sequence < PropertyValue > >& rSequence, const OUString& rPath )
1875{
1876 // first my own properties
1877 Sequence < PropertyValue > aProps(2);
1878
1879 // first property is the "FullPath" name
1880 // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
1881 OUString aPath( rPath );
1882 if ( !m_bIsRoot )
1883 aPath += m_aName;
1884 aPath += "/";
1885 aProps[0].Name = "MediaType";
1886 aProps[0].Value <<= m_aContentType;
1887 aProps[1].Name = "FullPath";
1888 aProps[1].Value <<= aPath;
1889 rSequence[ nProps++ ] = aProps;
1890
1891 if ( m_bIsRoot )
1892 // the "FullPath" of a child always starts without '/'
1893 aPath.clear();
1894
1895 // now the properties of my elements
1896 for (auto& pElement : m_aChildrenList)
1897 {
1898 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.is(), "Storage should be open!" )do { if (true && (!(!pElement->m_bIsFolder || pElement
->m_xStorage.is()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "1898" ": "), "%s", "Storage should be open!"); } } while
(false)
;
1899 if ( pElement->m_bIsFolder && pElement->m_xStorage.is() )
1900 // storages add there properties by themselves ( see above )
1901 pElement->m_xStorage->GetProps( nProps, rSequence, aPath );
1902 else
1903 {
1904 // properties of streams
1905 OUString aElementPath = aPath + pElement->m_aName;
1906 aProps[0].Name = "MediaType";
1907 aProps[0].Value <<= pElement->GetContentType();
1908 aProps[1].Name = "FullPath";
1909 aProps[1].Value <<= aElementPath;
1910 rSequence[ nProps++ ] = aProps;
1911 }
1912 }
1913}
1914
1915UCBStorage_Impl::~UCBStorage_Impl()
1916{
1917 m_aChildrenList.clear();
1918
1919 m_pContent.reset();
1920 m_pTempFile.reset();
1921}
1922
1923bool UCBStorage_Impl::Insert( ::ucbhelper::Content *pContent )
1924{
1925 // a new substorage is inserted into a UCBStorage ( given by the parameter pContent )
1926 // it must be inserted with a title and a type
1927 bool bRet = false;
1928
1929 try
1930 {
1931 const Sequence< ContentInfo > aInfo = pContent->queryCreatableContentsInfo();
1932 if ( !aInfo.hasElements() )
1933 return false;
1934
1935 for ( const ContentInfo & rCurr : aInfo )
1936 {
1937 // Simply look for the first KIND_FOLDER...
1938 if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
1939 {
1940 // Make sure the only required bootstrap property is "Title",
1941 const Sequence< Property > & rProps = rCurr.Properties;
1942 if ( rProps.getLength() != 1 )
1943 continue;
1944
1945 if ( rProps[ 0 ].Name != "Title" )
1946 continue;
1947
1948 Sequence < OUString > aNames { "Title" };
1949 Sequence < Any > aValues(1);
1950 aValues[0] <<= m_aName;
1951
1952 Content aNewFolder;
1953 if ( !pContent->insertNewContent( rCurr.Type, aNames, aValues, aNewFolder ) )
1954 continue;
1955
1956 // remove old content, create an "empty" new one and initialize it with the new inserted
1957 m_pContent.reset(new ::ucbhelper::Content( aNewFolder ));
1958 bRet = true;
1959 }
1960 }
1961 }
1962 catch (const CommandAbortedException&)
1963 {
1964 // any command wasn't executed successfully - not specified
1965 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1966 }
1967 catch (const RuntimeException&)
1968 {
1969 // any other error - not specified
1970 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1971 }
1972 catch (const Exception&)
1973 {
1974 // any other error - not specified
1975 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
1976 }
1977
1978 return bRet;
1979}
1980
1981sal_Int16 UCBStorage_Impl::Commit()
1982{
1983 // send all changes to the package
1984 sal_Int16 nRet = COMMIT_RESULT_NOTHING_TO_DO1;
1985
1986 // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no
1987 // commit command has been sent
1988 if ( ( m_nMode & StreamMode::WRITE ) && ( m_bCommited || m_bDirect ) )
1989 {
1990 try
1991 {
1992 // all errors will be caught in the "catch" statement outside the loop
1993 for ( size_t i = 0; i < m_aChildrenList.size() && nRet; ++i )
1994 {
1995 auto& pElement = m_aChildrenList[ i ];
1996 ::ucbhelper::Content* pContent = pElement->GetContent();
1997 std::unique_ptr< ::ucbhelper::Content > xDeleteContent;
1998 if ( !pContent && pElement->IsModified() )
1999 {
2000 // if the element has never been opened, no content has been created until now
2001 OUString aName = m_aURL + "/" + pElement->m_aOriginalName;
2002 pContent = new ::ucbhelper::Content( aName, Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2003 xDeleteContent.reset(pContent); // delete it later on exit scope
2004 }
2005
2006 if ( pElement->m_bIsRemoved )
2007 {
2008 // was it inserted, then removed (so there would be nothing to do!)
2009 if ( !pElement->m_bIsInserted )
2010 {
2011 // first remove all open stream handles
2012 if (pContent && (!pElement->m_xStream.is() || pElement->m_xStream->Clear()))
2013 {
2014 pContent->executeCommand( "delete", makeAny( true ) );
2015 nRet = COMMIT_RESULT_SUCCESS2;
2016 }
2017 else
2018 // couldn't release stream because there are external references to it
2019 nRet = COMMIT_RESULT_FAILURE0;
2020 }
2021 }
2022 else
2023 {
2024 sal_Int16 nLocalRet = COMMIT_RESULT_NOTHING_TO_DO1;
2025 if ( pElement->m_xStorage.is() )
2026 {
2027 // element is a storage
2028 // do a commit in the following cases:
2029 // - if storage is already inserted, and changed
2030 // - storage is not in a package
2031 // - it's a new storage, try to insert and commit if successful inserted
2032 if ( !pElement->m_bIsInserted || m_bIsLinked || pElement->m_xStorage->Insert( m_pContent.get() ) )
2033 {
2034 nLocalRet = pElement->m_xStorage->Commit();
2035 pContent = pElement->GetContent();
2036 }
2037 }
2038 else if ( pElement->m_xStream.is() )
2039 {
2040 // element is a stream
2041 nLocalRet = pElement->m_xStream->Commit();
2042 if ( pElement->m_xStream->m_bIsOLEStorage )
2043 {
2044 // OLE storage should be stored encrypted, if the storage uses encryption
2045 pElement->m_xStream->m_aContentType = "application/vnd.sun.star.oleobject";
2046 Any aValue;
2047 aValue <<= true;
2048 pElement->m_xStream->m_pContent->setPropertyValue("Encrypted", aValue );
2049 }
2050
2051 pContent = pElement->GetContent();
2052 }
2053
2054 if (pContent && pElement->m_aName != pElement->m_aOriginalName)
2055 {
2056 // name ( title ) of the element was changed
2057 nLocalRet = COMMIT_RESULT_SUCCESS2;
2058 pContent->setPropertyValue("Title", Any(pElement->m_aName) );
2059 }
2060
2061 if (pContent && pElement->IsLoaded() && pElement->GetContentType() != pElement->GetOriginalContentType())
2062 {
2063 // mediatype of the element was changed
2064 nLocalRet = COMMIT_RESULT_SUCCESS2;
2065 pContent->setPropertyValue("MediaType", Any(pElement->GetContentType()) );
2066 }
2067
2068 if ( nLocalRet != COMMIT_RESULT_NOTHING_TO_DO1 )
2069 nRet = nLocalRet;
2070 }
2071
2072 if ( nRet == COMMIT_RESULT_FAILURE0 )
2073 break;
2074 }
2075 }
2076 catch (const ContentCreationException&)
2077 {
2078 // content could not be created
2079 SetError( ERRCODE_IO_NOTEXISTSErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2080 return COMMIT_RESULT_FAILURE0;
2081 }
2082 catch (const CommandAbortedException&)
2083 {
2084 // any command wasn't executed successfully - not specified
2085 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2086 return COMMIT_RESULT_FAILURE0;
2087 }
2088 catch (const RuntimeException&)
2089 {
2090 // any other error - not specified
2091 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2092 return COMMIT_RESULT_FAILURE0;
2093 }
2094 catch (const Exception&)
2095 {
2096 // any other error - not specified
2097 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2098 return COMMIT_RESULT_FAILURE0;
2099 }
2100
2101 if ( m_bIsRoot && m_pContent )
2102 {
2103 // the root storage must flush the root package content
2104 if ( nRet == COMMIT_RESULT_SUCCESS2 )
2105 {
2106 try
2107 {
2108 // commit the media type to the JAR file
2109 // clipboard format and ClassId will be retrieved from the media type when the file is loaded again
2110 Any aType;
2111 aType <<= m_aContentType;
2112 m_pContent->setPropertyValue("MediaType", aType );
2113
2114 if ( m_bIsLinked )
2115 {
2116 // write a manifest file
2117 // first create a subfolder "META-inf"
2118 Content aNewSubFolder;
2119 bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, "META-INF", aNewSubFolder );
2120 if ( bRet )
2121 {
2122 // create a stream to write the manifest file - use a temp file
2123 OUString aURL( aNewSubFolder.getURL() );
2124 std::unique_ptr< ::utl::TempFile> pTempFile(new ::utl::TempFile( &aURL ));
2125
2126 // get the stream from the temp file and create an output stream wrapper
2127 SvStream* pStream = pTempFile->GetStream( StreamMode::STD_READWRITE );
2128 ::utl::OOutputStreamWrapper* pHelper = new ::utl::OOutputStreamWrapper( *pStream );
2129 css::uno::Reference < css::io::XOutputStream > xOutputStream( pHelper );
2130
2131 // create a manifest writer object that will fill the stream
2132 Reference < css::packages::manifest::XManifestWriter > xWriter =
2133 css::packages::manifest::ManifestWriter::create(
2134 ::comphelper::getProcessComponentContext() );
2135 sal_Int32 nCount = GetObjectCount() + 1;
2136 Sequence < Sequence < PropertyValue > > aProps( nCount );
2137 sal_Int32 nProps = 0;
2138 GetProps( nProps, aProps, OUString() );
2139 xWriter->writeManifestSequence( xOutputStream, aProps );
2140
2141 // move the stream to its desired location
2142 Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2143 xWriter = nullptr;
2144 xOutputStream = nullptr;
2145 pTempFile.reset();
2146 aNewSubFolder.transferContent( aSource, InsertOperation::Move, "manifest.xml", NameClash::OVERWRITE );
2147 }
2148 }
2149 else
2150 {
2151#if OSL_DEBUG_LEVEL1 > 0
2152 SAL_INFO("sot", "Files: " << nOpenFiles)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Files: " << nOpenFiles) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2152" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Files: " << nOpenFiles), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Files: " << nOpenFiles; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2152" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Files: " << nOpenFiles) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2152" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Files: " << nOpenFiles), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Files: " << nOpenFiles; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2152" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2153 SAL_INFO("sot", "Streams: " << nOpenStreams)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Streams: " << nOpenStreams) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2153" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Streams: " << nOpenStreams), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Streams: " << nOpenStreams; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2153" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Streams: " << nOpenStreams) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2153" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Streams: " << nOpenStreams), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Streams: " << nOpenStreams; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2153" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2154#endif
2155 // force writing
2156 Any aAny;
2157 m_pContent->executeCommand( "flush", aAny );
2158 if ( m_pSource != nullptr )
2159 {
2160 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), StreamMode::STD_READ ));
2161 m_pSource->SetStreamSize(0);
2162 // m_pSource->Seek(0);
2163 pStream->ReadStream( *m_pSource );
2164 pStream.reset();
2165 m_pSource->Seek(0);
2166 }
2167 }
2168 }
2169 catch (const CommandAbortedException&)
2170 {
2171 // how to tell the content : forget all changes ?!
2172 // or should we assume that the content does it by itself because he threw an exception ?!
2173 // any command wasn't executed successfully - not specified
2174 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2175 return COMMIT_RESULT_FAILURE0;
2176 }
2177 catch (const RuntimeException&)
2178 {
2179 // how to tell the content : forget all changes ?!
2180 // or should we assume that the content does it by itself because he threw an exception ?!
2181 // any other error - not specified
2182 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2183 return COMMIT_RESULT_FAILURE0;
2184 }
2185 catch (const InteractiveIOException& r)
2186 {
2187 if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
2188 SetError( ERRCODE_IO_ACCESSDENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 ) );
2189 else if ( r.Code == IOErrorCode_NOT_EXISTING )
2190 SetError( ERRCODE_IO_NOTEXISTSErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2191 else if ( r.Code == IOErrorCode_CANT_READ )
2192 SetError( ERRCODE_IO_CANTREADErrCode( ErrCodeArea::Io, ErrCodeClass::Read, 15 ) );
2193 else if ( r.Code == IOErrorCode_CANT_WRITE )
2194 SetError( ERRCODE_IO_CANTWRITEErrCode( ErrCodeArea::Io, ErrCodeClass::Write, 16 ) );
2195 else
2196 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2197
2198 return COMMIT_RESULT_FAILURE0;
2199 }
2200 catch (const Exception&)
2201 {
2202 // how to tell the content : forget all changes ?!
2203 // or should we assume that the content does it by itself because he threw an exception ?!
2204 // any other error - not specified
2205 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2206 return COMMIT_RESULT_FAILURE0;
2207 }
2208 }
2209 else if ( nRet != COMMIT_RESULT_NOTHING_TO_DO1 )
2210 {
2211 // how to tell the content : forget all changes ?! Should we ?!
2212 SetError( ERRCODE_IO_GENERALErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) );
2213 return nRet;
2214 }
2215
2216 // after successful root commit all elements names and types are adjusted and all removed elements
2217 // are also removed from the lists
2218 for ( size_t i = 0; i < m_aChildrenList.size(); )
2219 {
2220 auto& pInnerElement = m_aChildrenList[ i ];
2221 if ( pInnerElement->m_bIsRemoved )
2222 m_aChildrenList.erase( m_aChildrenList.begin() + i );
2223 else
2224 {
2225 pInnerElement->m_aOriginalName = pInnerElement->m_aName;
2226 pInnerElement->m_bIsInserted = false;
2227 ++i;
2228 }
2229 }
2230 }
2231
2232 m_bCommited = false;
2233 }
2234
2235 return nRet;
2236}
2237
2238void UCBStorage_Impl::Revert()
2239{
2240 for ( size_t i = 0; i < m_aChildrenList.size(); )
2241 {
2242 auto& pElement = m_aChildrenList[ i ];
2243 pElement->m_bIsRemoved = false;
2244 if ( pElement->m_bIsInserted )
2245 m_aChildrenList.erase( m_aChildrenList.begin() + i );
2246 else
2247 {
2248 if ( pElement->m_xStream.is() )
2249 {
2250 pElement->m_xStream->m_bCommited = false;
2251 pElement->m_xStream->Revert();
2252 }
2253 else if ( pElement->m_xStorage.is() )
2254 {
2255 pElement->m_xStorage->m_bCommited = false;
2256 pElement->m_xStorage->Revert();
2257 }
2258
2259 pElement->m_aName = pElement->m_aOriginalName;
2260 pElement->m_bIsRemoved = false;
2261 ++i;
2262 }
2263 }
2264}
2265
2266const OUString& UCBStorage::GetName() const
2267{
2268 return pImp->m_aName; // pImp->m_aURL ?!
2269}
2270
2271bool UCBStorage::IsRoot() const
2272{
2273 return pImp->m_bIsRoot;
2274}
2275
2276void UCBStorage::SetDirty()
2277{
2278}
2279
2280void UCBStorage::SetClass( const SvGlobalName & rClass, SotClipboardFormatId nOriginalClipFormat, const OUString & rUserTypeName )
2281{
2282 pImp->m_aClassId = rClass;
2283 pImp->m_nFormat = nOriginalClipFormat;
2284 pImp->m_aUserTypeName = rUserTypeName;
2285
2286 // in UCB storages only the content type will be stored, all other information can be reconstructed
2287 // ( see the UCBStorage_Impl::Init() method )
2288 css::datatransfer::DataFlavor aDataFlavor;
2289 SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2290 pImp->m_aContentType = aDataFlavor.MimeType;
2291}
2292
2293void UCBStorage::SetClassId( const ClsId& rClsId )
2294{
2295 pImp->m_aClassId = SvGlobalName( rClsId );
2296 if ( pImp->m_aClassId == SvGlobalName() )
2297 return;
2298
2299 // in OLE storages the clipboard format and the user name will be transferred when a storage is copied because both are
2300 // stored in one the substreams
2301 // UCB storages store the content type information as content type in the manifest file and so this information must be
2302 // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from
2303 // the content type
2304 pImp->m_nFormat = GetFormatId_Impl( pImp->m_aClassId );
2305 if ( pImp->m_nFormat != SotClipboardFormatId::NONE )
2306 {
2307 css::datatransfer::DataFlavor aDataFlavor;
2308 SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2309 pImp->m_aUserTypeName = aDataFlavor.HumanPresentableName;
2310 pImp->m_aContentType = aDataFlavor.MimeType;
2311 }
2312}
2313
2314const ClsId& UCBStorage::GetClassId() const
2315{
2316 return pImp->m_aClassId.GetCLSID();
2317}
2318
2319SvGlobalName UCBStorage::GetClassName()
2320{
2321 return pImp->m_aClassId;
2322}
2323
2324SotClipboardFormatId UCBStorage::GetFormat()
2325{
2326 return pImp->m_nFormat;
2327}
2328
2329OUString UCBStorage::GetUserName()
2330{
2331 OSL_FAIL("UserName is not implemented in UCB storages!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2331" ": "), "%s", "UserName is not implemented in UCB storages!"
); } } while (false)
;
2332 return pImp->m_aUserTypeName;
2333}
2334
2335void UCBStorage::FillInfoList( SvStorageInfoList* pList ) const
2336{
2337 // put information in childrenlist into StorageInfoList
2338 for (auto& pElement : pImp->GetChildrenList())
2339 {
2340 if ( !pElement->m_bIsRemoved )
2341 {
2342 // problem: what about the size of a substorage ?!
2343 sal_uLong nSize = pElement->m_nSize;
2344 if ( pElement->m_xStream.is() )
2345 nSize = pElement->m_xStream->GetSize();
2346 SvStorageInfo aInfo( pElement->m_aName, nSize, pElement->m_bIsStorage );
2347 pList->push_back( aInfo );
2348 }
2349 }
2350}
2351
2352bool UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl const & rElement, BaseStorage* pDest, const OUString& rNew ) const
2353{
2354 // insert stream or storage into the list or stream of the destination storage
2355 // not into the content, this will be done on commit !
2356 // be aware of name changes !
2357 if ( !rElement.m_bIsStorage )
2358 {
2359 // copy the streams data
2360 // the destination stream must not be open
2361 tools::SvRef<BaseStorageStream> pOtherStream(pDest->OpenStream( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ));
2362 BaseStorageStream* pStream = nullptr;
2363 bool bDeleteStream = false;
2364
2365 // if stream is already open, it is allowed to copy it, so be aware of this
2366 if ( rElement.m_xStream.is() )
2367 pStream = rElement.m_xStream->m_pAntiImpl;
2368 if ( !pStream )
2369 {
2370 pStream = const_cast< UCBStorage* >(this)->OpenStream( rElement.m_aName, StreamMode::STD_READ, pImp->m_bDirect );
2371 bDeleteStream = true;
2372 }
2373
2374 pStream->CopyTo( pOtherStream.get() );
2375 SetError( pStream->GetError() );
2376 if( pOtherStream->GetError() )
2377 pDest->SetError( pOtherStream->GetError() );
2378 else
2379 pOtherStream->Commit();
2380
2381 if ( bDeleteStream )
2382 delete pStream;
2383 }
2384 else
2385 {
2386 // copy the storage content
2387 // the destination storage must not be open
2388 BaseStorage* pStorage = nullptr;
2389
2390 // if stream is already open, it is allowed to copy it, so be aware of this
2391 bool bDeleteStorage = false;
2392 if ( rElement.m_xStorage.is() )
2393 pStorage = rElement.m_xStorage->m_pAntiImpl;
2394 if ( !pStorage )
2395 {
2396 pStorage = const_cast<UCBStorage*>(this)->OpenStorage( rElement.m_aName, pImp->m_nMode, pImp->m_bDirect );
2397 bDeleteStorage = true;
2398 }
2399
2400 UCBStorage* pUCBDest = dynamic_cast<UCBStorage*>( pDest );
2401 UCBStorage* pUCBCopy = dynamic_cast<UCBStorage*>( pStorage );
2402
2403 bool bOpenUCBStorage = pUCBDest && pUCBCopy;
2404 tools::SvRef<BaseStorage> pOtherStorage(bOpenUCBStorage ?
2405 pDest->OpenUCBStorage( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ) :
2406 pDest->OpenOLEStorage( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pImp->m_bDirect ));
2407
2408 // For UCB storages, the class id and the format id may differ,
2409 // do passing the class id is not sufficient.
2410 if( bOpenUCBStorage )
2411 pOtherStorage->SetClass( pStorage->GetClassName(),
2412 pStorage->GetFormat(),
2413 pUCBCopy->pImp->m_aUserTypeName );
2414 else
2415 pOtherStorage->SetClassId( pStorage->GetClassId() );
2416 pStorage->CopyTo( pOtherStorage.get() );
2417 SetError( pStorage->GetError() );
2418 if( pOtherStorage->GetError() )
2419 pDest->SetError( pOtherStorage->GetError() );
2420 else
2421 pOtherStorage->Commit();
2422
2423 if ( bDeleteStorage )
2424 delete pStorage;
2425 }
2426
2427 return Good() && pDest->Good();
2428}
2429
2430UCBStorageElement_Impl* UCBStorage::FindElement_Impl( const OUString& rName ) const
2431{
2432 DBG_ASSERT( !rName.isEmpty(), "Name is empty!" )do { if (true && (!(!rName.isEmpty()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2432" ": "), "%s", "Name is empty!"); } } while (false)
;
2433 for (const auto& pElement : pImp->GetChildrenList())
2434 {
2435 if ( pElement->m_aName == rName && !pElement->m_bIsRemoved )
2436 return pElement.get();
2437 }
2438 return nullptr;
2439}
2440
2441bool UCBStorage::CopyTo( BaseStorage* pDestStg ) const
2442{
2443 DBG_ASSERT( pDestStg != static_cast<BaseStorage const *>(this), "Self-Copying is not possible!" )do { if (true && (!(pDestStg != static_cast<BaseStorage
const *>(this)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2443" ": "), "%s", "Self-Copying is not possible!"); } }
while (false)
;
2444 if ( pDestStg == static_cast<BaseStorage const *>(this) )
2445 return false;
2446
2447 // perhaps it's also a problem if one storage is a parent of the other ?!
2448 // or if not: could be optimized ?!
2449
2450 // For UCB storages, the class id and the format id may differ,
2451 // do passing the class id is not sufficient.
2452 if( dynamic_cast<const UCBStorage *>(pDestStg) != nullptr )
2453 pDestStg->SetClass( pImp->m_aClassId, pImp->m_nFormat,
2454 pImp->m_aUserTypeName );
2455 else
2456 pDestStg->SetClassId( GetClassId() );
2457 pDestStg->SetDirty();
2458
2459 bool bRet = true;
2460 for ( size_t i = 0; i < pImp->GetChildrenList().size() && bRet; ++i )
2461 {
2462 auto& pElement = pImp->GetChildrenList()[ i ];
2463 if ( !pElement->m_bIsRemoved )
2464 bRet = CopyStorageElement_Impl( *pElement, pDestStg, pElement->m_aName );
2465 }
2466
2467 if( !bRet )
2468 SetError( pDestStg->GetError() );
2469 return Good() && pDestStg->Good();
2470}
2471
2472bool UCBStorage::CopyTo( const OUString& rElemName, BaseStorage* pDest, const OUString& rNew )
2473{
2474 if( rElemName.isEmpty() )
2475 return false;
2476
2477 if ( pDest == static_cast<BaseStorage*>(this) )
2478 {
2479 // can't double an element
2480 return false;
2481 }
2482 else
2483 {
2484 // for copying no optimization is useful, because in every case the stream data must be copied
2485 UCBStorageElement_Impl* pElement = FindElement_Impl( rElemName );
2486 if ( pElement )
2487 return CopyStorageElement_Impl( *pElement, pDest, rNew );
2488 else
2489 {
2490 SetError( SVSTREAM_FILE_NOT_FOUNDErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2491 return false;
2492 }
2493 }
2494}
2495
2496bool UCBStorage::Commit()
2497{
2498 // mark this storage for sending it on root commit
2499 pImp->m_bCommited = true;
2500 if ( pImp->m_bIsRoot )
2501 // the root storage coordinates committing by sending a Commit command to its content
2502 return ( pImp->Commit() != COMMIT_RESULT_FAILURE0 );
2503 else
2504 return true;
2505}
2506
2507bool UCBStorage::Revert()
2508{
2509 pImp->Revert();
2510 return true;
2511}
2512
2513BaseStorageStream* UCBStorage::OpenStream( const OUString& rEleName, StreamMode nMode, bool bDirect )
2514{
2515 if( rEleName.isEmpty() )
2516 return nullptr;
2517
2518 // try to find the storage element
2519 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2520 if ( !pElement )
2521 {
2522 // element does not exist, check if creation is allowed
2523 if( nMode & StreamMode::NOCREATE )
2524 {
2525 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) : SVSTREAM_FILE_NOT_FOUNDErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2526 OUString aName = pImp->m_aURL + "/" + rEleName;
2527 UCBStorageStream* pStream = new UCBStorageStream( aName, nMode, bDirect, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2528 pStream->SetError( GetError() );
2529 pStream->pImp->m_aName = rEleName;
2530 return pStream;
2531 }
2532 else
2533 {
2534 // create a new UCBStorageElement and insert it into the list
2535 pElement = new UCBStorageElement_Impl( rEleName );
2536 pElement->m_bIsInserted = true;
2537 pImp->m_aChildrenList.emplace_back( pElement );
2538 }
2539 }
2540
2541 if ( !pElement->m_bIsFolder )
2542 {
2543 // check if stream is already created
2544 if ( pElement->m_xStream.is() )
2545 {
2546 // stream has already been created; if it has no external reference, it may be opened another time
2547 if ( pElement->m_xStream->m_pAntiImpl )
2548 {
2549 OSL_FAIL("Stream is already open!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2549" ": "), "%s", "Stream is already open!"); } } while
(false)
;
2550 SetError( SVSTREAM_ACCESS_DENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 ) ); // ???
2551 return nullptr;
2552 }
2553 else
2554 {
2555 // check if stream is opened with the same keyword as before
2556 // if not, generate a new stream because it could be encrypted vs. decrypted!
2557 if ( pElement->m_xStream->m_aKey.isEmpty() )
2558 {
2559 pElement->m_xStream->PrepareCachedForReopen( nMode );
2560
2561 return new UCBStorageStream( pElement->m_xStream.get() );
2562 }
2563 }
2564 }
2565
2566 // stream is opened the first time
2567 pImp->OpenStream( pElement, nMode, bDirect );
2568
2569 // if name has been changed before creating the stream: set name!
2570 pElement->m_xStream->m_aName = rEleName;
2571 return new UCBStorageStream( pElement->m_xStream.get() );
2572 }
2573
2574 return nullptr;
2575}
2576
2577void UCBStorage_Impl::OpenStream( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect )
2578{
2579 OUString aName = m_aURL + "/" +pElement->m_aOriginalName;
2580 pElement->m_xStream = new UCBStorageStream_Impl( aName, nMode, nullptr, bDirect, m_bRepairPackage, m_xProgressHandler );
2581}
2582
2583BaseStorage* UCBStorage::OpenUCBStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2584{
2585 if( rEleName.isEmpty() )
1
Taking false branch
2586 return nullptr;
2587
2588 return OpenStorage_Impl( rEleName, nMode, bDirect, true );
2
Calling 'UCBStorage::OpenStorage_Impl'
2589}
2590
2591BaseStorage* UCBStorage::OpenOLEStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2592{
2593 if( rEleName.isEmpty() )
2594 return nullptr;
2595
2596 return OpenStorage_Impl( rEleName, nMode, bDirect, false );
2597}
2598
2599BaseStorage* UCBStorage::OpenStorage( const OUString& rEleName, StreamMode nMode, bool bDirect )
2600{
2601 if( rEleName.isEmpty() )
2602 return nullptr;
2603
2604 return OpenStorage_Impl( rEleName, nMode, bDirect, true );
2605}
2606
2607BaseStorage* UCBStorage::OpenStorage_Impl( const OUString& rEleName, StreamMode nMode, bool bDirect, bool bForceUCBStorage )
2608{
2609 // try to find the storage element
2610 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2611 if ( !pElement )
3
Assuming 'pElement' is non-null
4
Taking false branch
2612 {
2613 // element does not exist, check if creation is allowed
2614 if( nMode & StreamMode::NOCREATE )
2615 {
2616 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) : SVSTREAM_FILE_NOT_FOUNDErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2617 OUString aName = pImp->m_aURL + "/" + rEleName; // ???
2618 UCBStorage *pStorage = new UCBStorage( aName, nMode, bDirect, false, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2619 pStorage->pImp->m_bIsRoot = false;
2620 pStorage->pImp->m_bListCreated = true; // the storage is pretty new, nothing to read
2621 pStorage->SetError( GetError() );
2622 return pStorage;
2623 }
2624
2625 // create a new UCBStorageElement and insert it into the list
2626 // problem: perhaps an OLEStorage should be created ?!
2627 // Because nothing is known about the element that should be created, an external parameter is needed !
2628 pElement = new UCBStorageElement_Impl( rEleName );
2629 pElement->m_bIsInserted = true;
2630 pImp->m_aChildrenList.emplace_back( pElement );
2631 }
2632
2633 if ( !pElement->m_bIsFolder && ( pElement->m_bIsStorage || !bForceUCBStorage ) )
5
Assuming field 'm_bIsFolder' is false
6
Assuming field 'm_bIsStorage' is true
2634 {
2635 // create OLE storages on a stream ( see ctor of SotStorage )
2636 // Such a storage will be created on a UCBStorageStream; it will write into the stream
2637 // if it is opened in direct mode or when it is committed. In this case the stream will be
2638 // modified and then it MUST be treated as committed.
2639 if ( !pElement->m_xStream.is() )
7
Taking true branch
2640 {
2641 BaseStorageStream* pStr = OpenStream( rEleName, nMode, bDirect );
2642 UCBStorageStream* pStream = dynamic_cast<UCBStorageStream*>( pStr );
2643 if ( !pStream
7.1
'pStream' is non-null
7.1
'pStream' is non-null
)
8
Taking false branch
2644 {
2645 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) : SVSTREAM_FILE_NOT_FOUNDErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2646 return nullptr;
2647 }
2648
2649 pElement->m_xStream = pStream->pImp;
2650 delete pStream;
9
Calling '~UCBStorageStream'
17
Returning from '~UCBStorageStream'
2651 }
2652
2653 pElement->m_xStream->PrepareCachedForReopen( nMode );
18
Calling 'SvRef::operator->'
2654 bool bInited = pElement->m_xStream->Init();
2655 if (!bInited)
2656 {
2657 SetError( ( nMode & StreamMode::WRITE ) ? SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) : SVSTREAM_FILE_NOT_FOUNDErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2658 return nullptr;
2659 }
2660
2661 pElement->m_bIsStorage = true;
2662 return pElement->m_xStream->CreateStorage(); // can only be created in transacted mode
2663 }
2664 else if ( pElement->m_xStorage.is() )
2665 {
2666 // storage has already been opened; if it has no external reference, it may be opened another time
2667 if ( pElement->m_xStorage->m_pAntiImpl )
2668 {
2669 OSL_FAIL("Storage is already open!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx"
":" "2669" ": "), "%s", "Storage is already open!"); } } while
(false)
;
2670 SetError( SVSTREAM_ACCESS_DENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 ) ); // ???
2671 }
2672 else
2673 {
2674 bool bIsWritable = bool( pElement->m_xStorage->m_nMode & StreamMode::WRITE );
2675 if ( !bIsWritable && ( nMode & StreamMode::WRITE ) )
2676 {
2677 OUString aName = pImp->m_aURL + "/" + pElement->m_aOriginalName;
2678 UCBStorage* pStorage = new UCBStorage( aName, nMode, bDirect, false, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2679 pElement->m_xStorage = pStorage->pImp;
2680 return pStorage;
2681 }
2682 else
2683 {
2684 return new UCBStorage( pElement->m_xStorage.get() );
2685 }
2686 }
2687 }
2688 else if ( !pElement->m_xStream.is() )
2689 {
2690 // storage is opened the first time
2691 bool bIsWritable = bool(pImp->m_nMode & StreamMode::WRITE);
2692 if ( pImp->m_bIsLinked && pImp->m_bIsRoot && bIsWritable )
2693 {
2694 // make sure that the root storage object has been created before substorages will be created
2695 INetURLObject aFolderObj( pImp->m_aURL );
2696 aFolderObj.removeSegment();
2697
2698 Content aFolder( aFolderObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2699 pImp->m_pContent.reset(new Content);
2700 bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, pImp->m_aName, *pImp->m_pContent );
2701 if ( !bRet )
2702 {
2703 SetError( SVSTREAM_CANNOT_MAKEErrCode( ErrCodeArea::Io, ErrCodeClass::Create, 25 ) );
2704 return nullptr;
2705 }
2706 }
2707
2708 UCBStorage_Impl* pStor = pImp->OpenStorage( pElement, nMode, bDirect );
2709 if ( pStor )
2710 {
2711 if ( pElement->m_bIsInserted )
2712 pStor->m_bListCreated = true; // the storage is pretty new, nothing to read
2713
2714 return new UCBStorage( pStor );
2715 }
2716 }
2717
2718 return nullptr;
2719}
2720
2721UCBStorage_Impl* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, bool bDirect )
2722{
2723 UCBStorage_Impl* pRet = nullptr;
2724 OUString aName = m_aURL + "/" + pElement->m_aOriginalName; // ???
2725
2726 pElement->m_bIsStorage = pElement->m_bIsFolder = true;
2727
2728 if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) )
2729 {
2730 Content aNewFolder;
2731 bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, pElement->m_aOriginalName, aNewFolder );
2732 if ( bRet )
2733 pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, nullptr, bDirect, false, m_bRepairPackage, m_xProgressHandler );
2734 }
2735 else
2736 {
2737 pRet = new UCBStorage_Impl( aName, nMode, nullptr, bDirect, false, m_bRepairPackage, m_xProgressHandler );
2738 }
2739
2740 if ( pRet )
2741 {
2742 pRet->m_bIsLinked = m_bIsLinked;
2743 pRet->m_bIsRoot = false;
2744
2745 // if name has been changed before creating the stream: set name!
2746 pRet->m_aName = pElement->m_aOriginalName;
2747 pElement->m_xStorage = pRet;
2748 }
2749
2750 if ( pRet )
2751 pRet->Init();
2752
2753 return pRet;
2754}
2755
2756bool UCBStorage::IsStorage( const OUString& rEleName ) const
2757{
2758 if( rEleName.isEmpty() )
2759 return false;
2760
2761 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2762 return ( pElement && pElement->m_bIsStorage );
2763}
2764
2765bool UCBStorage::IsStream( const OUString& rEleName ) const
2766{
2767 if( rEleName.isEmpty() )
2768 return false;
2769
2770 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2771 return ( pElement && !pElement->m_bIsStorage );
2772}
2773
2774bool UCBStorage::IsContained( const OUString & rEleName ) const
2775{
2776 if( rEleName.isEmpty() )
2777 return false;
2778 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2779 return ( pElement != nullptr );
2780}
2781
2782void UCBStorage::Remove( const OUString& rEleName )
2783{
2784 if( rEleName.isEmpty() )
2785 return;
2786
2787 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2788 if ( pElement )
2789 {
2790 pElement->m_bIsRemoved = true;
2791 }
2792 else
2793 SetError( SVSTREAM_FILE_NOT_FOUNDErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 ) );
2794}
2795
2796bool UCBStorage::ValidateFAT()
2797{
2798 // ???
2799 return true;
2800}
2801
2802bool UCBStorage::Validate( bool bWrite ) const
2803{
2804 // ???
2805 return ( !bWrite || ( pImp->m_nMode & StreamMode::WRITE ) );
2806}
2807
2808bool UCBStorage::ValidateMode( StreamMode m ) const
2809{
2810 // ???
2811 if( m == ( StreamMode::READ | StreamMode::TRUNC ) ) // from stg.cxx
2812 return true;
2813 // only SHARE_DENYALL allowed
2814 // storages open in r/o mode are OK, since only
2815 // the commit may fail
2816 if( m & StreamMode::SHARE_DENYALL )
2817 return true;
2818
2819 return true;
2820}
2821
2822bool UCBStorage::Equals( const BaseStorage& rStorage ) const
2823{
2824 // ???
2825 return static_cast<BaseStorage const *>(this) == &rStorage;
2826}
2827
2828bool UCBStorage::IsStorageFile( SvStream* pFile )
2829{
2830 if ( !pFile )
2831 return false;
2832
2833 sal_uInt64 nPos = pFile->Tell();
2834 if ( pFile->TellEnd() < 4 )
2835 return false;
2836
2837 pFile->Seek(0);
2838 sal_uInt32 nBytes(0);
2839 pFile->ReadUInt32( nBytes );
2840
2841 // search for the magic bytes
2842 bool bRet = ( nBytes == 0x04034b50 );
2843 if ( !bRet )
2844 {
2845 // disk spanned file have an additional header in front of the usual one
2846 bRet = ( nBytes == 0x08074b50 );
2847 if ( bRet )
2848 {
2849 nBytes = 0;
2850 pFile->ReadUInt32( nBytes );
2851 bRet = ( nBytes == 0x04034b50 );
2852 }
2853 }
2854
2855 pFile->Seek( nPos );
2856 return bRet;
2857}
2858
2859/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/tools/ref.hxx

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#ifndef INCLUDED_TOOLS_REF_HXX
20#define INCLUDED_TOOLS_REF_HXX
21
22#include <sal/config.h>
23#include <cassert>
24#include <tools/toolsdllapi.h>
25#include <utility>
26
27/**
28 This implements similar functionality to boost::intrusive_ptr
29*/
30
31namespace tools {
32
33/** T must be a class that extends SvRefBase */
34template<typename T> class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SvRef final {
35public:
36 SvRef(): pObj(nullptr) {}
37
38 SvRef(SvRef&& rObj) noexcept
39 {
40 pObj = rObj.pObj;
41 rObj.pObj = nullptr;
42 }
43
44 SvRef(SvRef const & rObj): pObj(rObj.pObj)
45 {
46 if (pObj != nullptr) pObj->AddNextRef();
47 }
48
49 SvRef(T * pObjP): pObj(pObjP)
50 {
51 if (pObj != nullptr) pObj->AddFirstRef();
52 }
53
54 ~SvRef()
55 {
56 if (pObj != nullptr) pObj->ReleaseRef();
57 }
58
59 void clear()
60 {
61 if (pObj != nullptr) {
62 T * pRefObj = pObj;
63 pObj = nullptr;
64 pRefObj->ReleaseRef();
65 }
66 }
67
68 SvRef & operator =(SvRef const & rObj)
69 {
70 if (rObj.pObj != nullptr) {
71 rObj.pObj->AddNextRef();
72 }
73 T * pRefObj = pObj;
74 pObj = rObj.pObj;
75 if (pRefObj != nullptr) {
76 pRefObj->ReleaseRef();
77 }
78 return *this;
79 }
80
81 SvRef & operator =(SvRef && rObj)
82 {
83 if (pObj != nullptr) {
84 pObj->ReleaseRef();
85 }
86 pObj = rObj.pObj;
87 rObj.pObj = nullptr;
88 return *this;
89 }
90
91 bool is() const { return pObj != nullptr; }
92
93 explicit operator bool() const { return is(); }
94
95 T * get() const { return pObj; }
96
97 T * operator ->() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail
("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 97, __extension__ __PRETTY_FUNCTION__))
; return pObj; }
19
'?' condition is true
20
Use of memory after it is freed
98
99 T & operator *() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail
("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 99, __extension__ __PRETTY_FUNCTION__))
; return *pObj; }
100
101 bool operator ==(const SvRef<T> &rhs) const { return pObj == rhs.pObj; }
102 bool operator !=(const SvRef<T> &rhs) const { return !(*this == rhs); }
103
104private:
105 T * pObj;
106};
107
108/**
109 * This implements similar functionality to std::make_shared.
110 */
111template<typename T, typename... Args>
112SvRef<T> make_ref(Args&& ... args)
113{
114 return SvRef<T>(new T(std::forward<Args>(args)...));
115}
116
117}
118
119/** Classes that want to be referenced-counted via SvRef<T>, should extend this base class */
120class TOOLS_DLLPUBLIC__attribute__ ((visibility("default"))) SvRefBase
121{
122 // work around a clang 3.5 optimization bug: if the bNoDelete is *first*
123 // it mis-compiles "if (--nRefCount == 0)" and never deletes any object
124 unsigned int nRefCount : 31;
125 // the only reason this is not bool is because MSVC cannot handle mixed type bitfields
126 unsigned int bNoDelete : 1;
127
128protected:
129 virtual ~SvRefBase() COVERITY_NOEXCEPT_FALSE;
130
131public:
132 SvRefBase() : nRefCount(0), bNoDelete(1) {}
133 SvRefBase(const SvRefBase &) : nRefCount(0), bNoDelete(1) {}
134
135 SvRefBase & operator=(const SvRefBase &) { return *this; }
136
137 void RestoreNoDelete()
138 { bNoDelete = 1; }
139
140 void AddNextRef()
141 {
142 assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) &&
"Do not add refs to dead objects") ? void (0) : __assert_fail
("nRefCount < (1 << 30) && \"Do not add refs to dead objects\""
, "/home/maarten/src/libreoffice/core/include/tools/ref.hxx",
142, __extension__ __PRETTY_FUNCTION__))
;
143 ++nRefCount;
144 }
145
146 void AddFirstRef()
147 {
148 assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) &&
"Do not add refs to dead objects") ? void (0) : __assert_fail
("nRefCount < (1 << 30) && \"Do not add refs to dead objects\""
, "/home/maarten/src/libreoffice/core/include/tools/ref.hxx",
148, __extension__ __PRETTY_FUNCTION__))
;
149 if( bNoDelete )
150 bNoDelete = 0;
151 ++nRefCount;
152 }
153
154 void ReleaseRef()
155 {
156 assert( nRefCount >= 1)(static_cast <bool> (nRefCount >= 1) ? void (0) : __assert_fail
("nRefCount >= 1", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 156, __extension__ __PRETTY_FUNCTION__))
;
12
'?' condition is true
157 if( --nRefCount == 0 && !bNoDelete
13.1
Field 'bNoDelete' is 0
13.1
Field 'bNoDelete' is 0
)
13
Assuming the condition is true
14
Taking true branch
158 {
159 // I'm not sure about the original purpose of this line, but right now
160 // it serves the purpose that anything that attempts to do an AddRef()
161 // after an object is deleted will trip an assert.
162 nRefCount = 1 << 30;
163 delete this;
15
Memory is released
164 }
165 }
166
167 unsigned int GetRefCount() const
168 { return nRefCount; }
169};
170
171template<typename T>
172class SvCompatWeakBase;
173
174/** SvCompatWeakHdl acts as an intermediary between SvCompatWeakRef<T> and T.
175*/
176template<typename T>
177class SvCompatWeakHdl final : public SvRefBase
178{
179 friend class SvCompatWeakBase<T>;
180 T* _pObj;
181
182 SvCompatWeakHdl( T* pObj ) : _pObj( pObj ) {}
183
184public:
185 void ResetWeakBase( ) { _pObj = nullptr; }
186 T* GetObj() { return _pObj; }
187};
188
189/** We only have one place that extends this, in include/sfx2/frame.hxx, class SfxFrame.
190 Its function is to notify the SvCompatWeakHdl when an SfxFrame object is deleted.
191*/
192template<typename T>
193class SvCompatWeakBase
194{
195 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
196
197public:
198 /** Does not use initializer due to compiler warnings,
199 because the lifetime of the _xHdl object can exceed the lifetime of this class.
200 */
201 SvCompatWeakBase( T* pObj ) { _xHdl = new SvCompatWeakHdl<T>( pObj ); }
202
203 ~SvCompatWeakBase() { _xHdl->ResetWeakBase(); }
204
205 SvCompatWeakHdl<T>* GetHdl() { return _xHdl.get(); }
206};
207
208/** We only have one weak reference in LO, in include/sfx2/frame.hxx, class SfxFrameWeak.
209*/
210template<typename T>
211class SAL_WARN_UNUSED__attribute__((warn_unused)) SvCompatWeakRef
212{
213 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
214public:
215 SvCompatWeakRef( ) {}
216 SvCompatWeakRef( T* pObj )
217 { if( pObj ) _xHdl = pObj->GetHdl(); }
218#if defined(__COVERITY__)
219 ~SvCompatWeakRef() COVERITY_NOEXCEPT_FALSE {}
220#endif
221 SvCompatWeakRef& operator = ( T * pObj )
222 { _xHdl = pObj ? pObj->GetHdl() : nullptr; return *this; }
223 bool is() const
224 { return _xHdl.is() && _xHdl->GetObj(); }
225 explicit operator bool() const { return is(); }
226 T* operator -> () const
227 { return _xHdl.is() ? _xHdl->GetObj() : nullptr; }
228 operator T* () const
229 { return _xHdl.is() ? _xHdl->GetObj() : nullptr; }
230};
231
232#endif
233
234/* vim:set shiftwidth=4 softtabstop=4 expandtab: */