File: | home/maarten/src/libreoffice/core/sot/source/sdstor/ucbstorage.cxx |
Warning: | line 2415, column 40 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
66 | namespace com::sun::star::ucb { class XCommandEnvironment; } | |||
67 | ||||
68 | using namespace ::com::sun::star::lang; | |||
69 | using namespace ::com::sun::star::beans; | |||
70 | using namespace ::com::sun::star::uno; | |||
71 | using namespace ::com::sun::star::ucb; | |||
72 | using namespace ::com::sun::star::io; | |||
73 | using namespace ::com::sun::star::sdbc; | |||
74 | using namespace ::ucbhelper; | |||
75 | ||||
76 | #if OSL_DEBUG_LEVEL1 > 0 | |||
77 | static int nOpenFiles=0; | |||
78 | static int nOpenStreams=0; | |||
79 | #endif | |||
80 | ||||
81 | typedef ::cppu::WeakImplHelper < XInputStream, XSeekable > FileInputStreamWrapper_Base; | |||
82 | ||||
83 | namespace { | |||
84 | ||||
85 | class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base | |||
86 | { | |||
87 | protected: | |||
88 | ::osl::Mutex m_aMutex; | |||
89 | OUString m_aURL; | |||
90 | std::unique_ptr<SvStream> m_pSvStream; | |||
91 | ||||
92 | public: | |||
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 | ||||
105 | protected: | |||
106 | void checkConnected(); | |||
107 | void checkError(); | |||
108 | }; | |||
109 | ||||
110 | } | |||
111 | ||||
112 | FileStreamWrapper_Impl::FileStreamWrapper_Impl( const OUString& rName ) | |||
113 | : m_aURL( rName ) | |||
114 | { | |||
115 | // if no URL is provided the stream is empty | |||
116 | } | |||
117 | ||||
118 | ||||
119 | FileStreamWrapper_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 | ||||
134 | sal_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 | ||||
163 | sal_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 | ||||
186 | void 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 | ||||
199 | sal_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 | ||||
214 | void 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 | ||||
230 | void 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 | ||||
243 | sal_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 | ||||
257 | sal_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 | ||||
273 | void 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 | ||||
287 | void 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 | ||||
301 | static 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 | ||||
333 | static 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 | ||||
384 | class UCBStorageStream_Impl : public SvRefBase, public SvStream | |||
385 | { | |||
386 | virtual ~UCBStorageStream_Impl() override; | |||
387 | public: | |||
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 | ||||
442 | typedef tools::SvRef<UCBStorageStream_Impl> UCBStorageStream_ImplRef; | |||
443 | ||||
444 | struct UCBStorageElement_Impl; | |||
445 | typedef std::vector<std::unique_ptr<UCBStorageElement_Impl>> UCBStorageElementList_Impl; | |||
446 | ||||
447 | class UCBStorage_Impl : public SvRefBase | |||
448 | { | |||
449 | virtual ~UCBStorage_Impl() override; | |||
450 | public: | |||
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 | ||||
519 | typedef tools::SvRef<UCBStorage_Impl> UCBStorage_ImplRef; | |||
520 | ||||
521 | // this struct contains all necessary information on an element inside a UCBStorage | |||
522 | struct 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 | ||||
565 | OUString 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 | ||||
578 | void 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 | ||||
591 | OUString 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 | ||||
601 | bool 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 | ||||
615 | UCBStorageStream_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 | ||||
657 | UCBStorageStream_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 | ||||
671 | bool 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 | ||||
746 | void 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 | ||||
773 | sal_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 | ||||
808 | void 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 | |||
822 | std::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 | ||||
859 | std::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 | ||||
878 | sal_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 | ||||
938 | void 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 | ||||
964 | void UCBStorageStream_Impl::FlushData() | |||
965 | { | |||
966 | if( m_pStream ) | |||
967 | { | |||
968 | CopySourceToTemporary(); | |||
969 | m_pStream->Flush(); | |||
970 | } | |||
971 | ||||
972 | m_bCommited = true; | |||
973 | } | |||
974 | ||||
975 | void 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 | ||||
985 | void UCBStorageStream_Impl::ResetError() | |||
986 | { | |||
987 | m_nError = ERRCODE_NONEErrCode(0); | |||
988 | SvStream::ResetError(); | |||
989 | if ( m_pAntiImpl ) | |||
990 | m_pAntiImpl->ResetError(); | |||
991 | } | |||
992 | ||||
993 | sal_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 | ||||
1007 | BaseStorage* 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 | ||||
1022 | sal_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 | ||||
1089 | void 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 | ||||
1140 | bool 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 | ||||
1152 | void 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 | ||||
1168 | void 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 | ||||
1192 | UCBStorageStream::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 | ||||
1201 | UCBStorageStream::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 | ||||
1210 | UCBStorageStream::~UCBStorageStream() | |||
1211 | { | |||
1212 | if ( pImp->m_nMode & StreamMode::WRITE ) | |||
1213 | pImp->Flush(); | |||
1214 | pImp->m_pAntiImpl = nullptr; | |||
1215 | pImp->Free(); | |||
1216 | pImp->ReleaseRef(); | |||
1217 | } | |||
1218 | ||||
1219 | sal_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 | ||||
1225 | sal_uLong UCBStorageStream::Write( const void* pData, sal_uLong nSize ) | |||
1226 | { | |||
1227 | return pImp->PutData( pData, nSize ); | |||
1228 | } | |||
1229 | ||||
1230 | sal_uInt64 UCBStorageStream::Seek( sal_uInt64 nPos ) | |||
1231 | { | |||
1232 | //return pImp->m_pStream->Seek( nPos ); | |||
1233 | return pImp->Seek( nPos ); | |||
1234 | } | |||
1235 | ||||
1236 | sal_uLong UCBStorageStream::Tell() | |||
1237 | { | |||
1238 | if( !pImp->Init() ) | |||
1239 | return 0; | |||
1240 | return pImp->m_pStream->Tell(); | |||
1241 | } | |||
1242 | ||||
1243 | void UCBStorageStream::Flush() | |||
1244 | { | |||
1245 | // streams are never really transacted, so flush also means commit ! | |||
1246 | Commit(); | |||
1247 | } | |||
1248 | ||||
1249 | bool UCBStorageStream::SetSize( sal_uLong nNewSize ) | |||
1250 | { | |||
1251 | pImp->SetSize( nNewSize ); | |||
1252 | return !pImp->GetError(); | |||
1253 | } | |||
1254 | ||||
1255 | bool UCBStorageStream::Validate( bool bWrite ) const | |||
1256 | { | |||
1257 | return ( !bWrite || ( pImp->m_nMode & StreamMode::WRITE ) ); | |||
1258 | } | |||
1259 | ||||
1260 | bool 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 | ||||
1284 | SvStream* UCBStorageStream::GetModifySvStream() | |||
1285 | { | |||
1286 | return static_cast<SvStream*>(pImp); | |||
1287 | } | |||
1288 | ||||
1289 | bool UCBStorageStream::Equals( const BaseStorageStream& rStream ) const | |||
1290 | { | |||
1291 | // ??? | |||
1292 | return static_cast<BaseStorageStream const *>(this) == &rStream; | |||
1293 | } | |||
1294 | ||||
1295 | bool UCBStorageStream::Commit() | |||
1296 | { | |||
1297 | // mark this stream for sending it on root commit | |||
1298 | pImp->FlushData(); | |||
1299 | return true; | |||
1300 | } | |||
1301 | ||||
1302 | void 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 | ||||
1336 | bool 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 | ||||
1363 | sal_uLong UCBStorageStream::GetSize() const | |||
1364 | { | |||
1365 | return pImp->GetSize(); | |||
1366 | } | |||
1367 | ||||
1368 | UCBStorage::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 | ||||
1379 | UCBStorage::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 | ||||
1389 | UCBStorage::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 | ||||
1399 | UCBStorage::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 | ||||
1409 | UCBStorage::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 | ||||
1418 | UCBStorage::~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 | ||||
1428 | UCBStorage_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 | ||||
1458 | UCBStorage_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 | ||||
1505 | UCBStorage_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 | ||||
1549 | void 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 | ||||
1636 | void 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 | ||||
1666 | void 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 | ||||
1780 | void 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 | ||||
1789 | sal_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 | ||||
1802 | static 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 | ||||
1833 | void 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 | ||||
1874 | void 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 | ||||
1915 | UCBStorage_Impl::~UCBStorage_Impl() | |||
1916 | { | |||
1917 | m_aChildrenList.clear(); | |||
1918 | ||||
1919 | m_pContent.reset(); | |||
1920 | m_pTempFile.reset(); | |||
1921 | } | |||
1922 | ||||
1923 | bool 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 | ||||
1981 | sal_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 | ||||
2238 | void 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 | ||||
2266 | const OUString& UCBStorage::GetName() const | |||
2267 | { | |||
2268 | return pImp->m_aName; // pImp->m_aURL ?! | |||
2269 | } | |||
2270 | ||||
2271 | bool UCBStorage::IsRoot() const | |||
2272 | { | |||
2273 | return pImp->m_bIsRoot; | |||
2274 | } | |||
2275 | ||||
2276 | void UCBStorage::SetDirty() | |||
2277 | { | |||
2278 | } | |||
2279 | ||||
2280 | void 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 | ||||
2293 | void 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 | ||||
2314 | const ClsId& UCBStorage::GetClassId() const | |||
2315 | { | |||
2316 | return pImp->m_aClassId.GetCLSID(); | |||
2317 | } | |||
2318 | ||||
2319 | SvGlobalName UCBStorage::GetClassName() | |||
2320 | { | |||
2321 | return pImp->m_aClassId; | |||
2322 | } | |||
2323 | ||||
2324 | SotClipboardFormatId UCBStorage::GetFormat() | |||
2325 | { | |||
2326 | return pImp->m_nFormat; | |||
2327 | } | |||
2328 | ||||
2329 | OUString 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 | ||||
2335 | void 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 | ||||
2352 | bool 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 | ||||
2430 | UCBStorageElement_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 | ||||
2441 | bool 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 | ||||
2472 | bool 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 | ||||
2496 | bool 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 | ||||
2507 | bool UCBStorage::Revert() | |||
2508 | { | |||
2509 | pImp->Revert(); | |||
2510 | return true; | |||
2511 | } | |||
2512 | ||||
2513 | BaseStorageStream* 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 | ||||
2577 | void 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 | ||||
2583 | BaseStorage* UCBStorage::OpenUCBStorage( const OUString& rEleName, StreamMode nMode, bool bDirect ) | |||
2584 | { | |||
2585 | if( rEleName.isEmpty() ) | |||
2586 | return nullptr; | |||
2587 | ||||
2588 | return OpenStorage_Impl( rEleName, nMode, bDirect, true ); | |||
2589 | } | |||
2590 | ||||
2591 | BaseStorage* 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 | ||||
2599 | BaseStorage* 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 | ||||
2607 | BaseStorage* 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 ) | |||
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 ) ) | |||
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() ) | |||
2640 | { | |||
2641 | BaseStorageStream* pStr = OpenStream( rEleName, nMode, bDirect ); | |||
2642 | UCBStorageStream* pStream = dynamic_cast<UCBStorageStream*>( pStr ); | |||
2643 | if ( !pStream ) | |||
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; | |||
2651 | } | |||
2652 | ||||
2653 | pElement->m_xStream->PrepareCachedForReopen( nMode ); | |||
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 | ||||
2721 | UCBStorage_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 | ||||
2756 | bool 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 | ||||
2765 | bool 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 | ||||
2774 | bool 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 | ||||
2782 | void 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 | ||||
2796 | bool UCBStorage::ValidateFAT() | |||
2797 | { | |||
2798 | // ??? | |||
2799 | return true; | |||
2800 | } | |||
2801 | ||||
2802 | bool UCBStorage::Validate( bool bWrite ) const | |||
2803 | { | |||
2804 | // ??? | |||
2805 | return ( !bWrite || ( pImp->m_nMode & StreamMode::WRITE ) ); | |||
2806 | } | |||
2807 | ||||
2808 | bool 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 | ||||
2822 | bool UCBStorage::Equals( const BaseStorage& rStorage ) const | |||
2823 | { | |||
2824 | // ??? | |||
2825 | return static_cast<BaseStorage const *>(this) == &rStorage; | |||
2826 | } | |||
2827 | ||||
2828 | bool 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: */ |