/src/libreoffice/unotools/source/ucbhelper/tempfile.cxx
Line | Count | Source |
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 <sal/config.h> |
21 | | |
22 | | #include <cassert> |
23 | | #include <utility> |
24 | | |
25 | | #include <com/sun/star/io/BufferSizeExceededException.hpp> |
26 | | #include <com/sun/star/io/NotConnectedException.hpp> |
27 | | #include <com/sun/star/lang/IllegalArgumentException.hpp> |
28 | | #include <unotools/tempfile.hxx> |
29 | | #include <rtl/ustring.hxx> |
30 | | #include <tools/stream.hxx> |
31 | | #include <o3tl/safeint.hxx> |
32 | | #include <o3tl/char16_t2wchar_t.hxx> |
33 | | #include <osl/mutex.hxx> |
34 | | #include <osl/detail/file.h> |
35 | | #include <osl/file.hxx> |
36 | | #include <tools/debug.hxx> |
37 | | #include <tools/Guid.hxx> |
38 | | #include <comphelper/DirectoryHelper.hxx> |
39 | | |
40 | | #ifdef UNX |
41 | | #include <unistd.h> |
42 | | #elif defined( _WIN32 ) |
43 | | #include <process.h> |
44 | | #endif |
45 | | |
46 | | sal_uInt32 UniqueTokens::globalValue = SAL_MAX_UINT32; |
47 | | |
48 | | namespace |
49 | | { |
50 | | OUString gTempNameBase_Impl; |
51 | | |
52 | | OUString ensureTrailingSlash(const OUString& url) |
53 | 516k | { |
54 | 516k | if (!url.isEmpty() && !url.endsWith("/")) |
55 | 9.19k | return url + "/"; |
56 | 507k | return url; |
57 | 516k | } |
58 | | |
59 | | OUString stripTrailingSlash(const OUString& url) |
60 | 0 | { |
61 | 0 | if (url.endsWith("/")) |
62 | 0 | return url.copy(0, url.getLength() - 1); |
63 | 0 | return url; |
64 | 0 | } |
65 | | |
66 | | bool okOrExists(osl::FileBase::RC ret) |
67 | 0 | { |
68 | 0 | return ret == osl::FileBase::E_None || ret == osl::FileBase::E_EXIST; |
69 | 0 | } |
70 | | |
71 | | const OUString& getTempNameBase_Impl() |
72 | 605k | { |
73 | 605k | if (gTempNameBase_Impl.isEmpty()) |
74 | 16 | { |
75 | 16 | OUString ustrTempDirURL; |
76 | 16 | osl::FileBase::RC rc = osl::File::getTempDirURL(ustrTempDirURL); |
77 | 16 | if (rc == osl::FileBase::E_None) |
78 | 16 | { |
79 | 16 | gTempNameBase_Impl = ensureTrailingSlash(ustrTempDirURL); |
80 | 16 | osl::Directory::createPath(gTempNameBase_Impl); |
81 | 16 | } |
82 | 16 | } |
83 | 605k | assert(gTempNameBase_Impl.isEmpty() || gTempNameBase_Impl.endsWith("/")); |
84 | 605k | DBG_ASSERT(!gTempNameBase_Impl.isEmpty(), "No TempDir!"); |
85 | 605k | return gTempNameBase_Impl; |
86 | 605k | } |
87 | | |
88 | | OUString ConstructTempDir_Impl( const OUString* pParent, bool bCreateParentDirs ) |
89 | 516k | { |
90 | 516k | OUString aName; |
91 | | |
92 | | // Ignore pParent on iOS. We don't want to create any temp files |
93 | | // in the same directory where the document being edited is. |
94 | 516k | #ifndef IOS |
95 | 516k | if ( pParent && !pParent->isEmpty() ) |
96 | 9.17k | { |
97 | | // test for valid filename |
98 | 9.17k | OUString aRet; |
99 | 9.17k | if ((osl::FileBase::getSystemPathFromFileURL(*pParent, aRet) |
100 | 9.17k | == osl::FileBase::E_None) |
101 | 9.17k | && (osl::FileBase::getFileURLFromSystemPath(aRet, aRet) |
102 | 9.17k | == osl::FileBase::E_None)) |
103 | 9.17k | { |
104 | 9.17k | osl::DirectoryItem aItem; |
105 | 9.17k | sal_Int32 i = aRet.getLength(); |
106 | 9.17k | if ( aRet[i-1] == '/' ) |
107 | 0 | i--; |
108 | | |
109 | 9.17k | if ( osl::DirectoryItem::get( aRet.copy(0, i), aItem ) == osl::FileBase::E_None || bCreateParentDirs ) |
110 | 9.17k | aName = aRet; |
111 | 9.17k | } |
112 | 9.17k | } |
113 | | #else |
114 | | (void) pParent; |
115 | | (void) bCreateParentDirs; |
116 | | #endif |
117 | | |
118 | 516k | if ( aName.isEmpty() ) |
119 | 507k | { |
120 | | // if no parent or invalid parent : use default directory |
121 | 507k | aName = getTempNameBase_Impl(); |
122 | 507k | osl::Directory::createPath(aName); // tdf#159769: always make sure it exists |
123 | 507k | } |
124 | | |
125 | | // Make sure that directory ends with a separator |
126 | 516k | return ensureTrailingSlash(aName); |
127 | 516k | } |
128 | | |
129 | | |
130 | | class TempDirCreatedObserver : public osl::DirectoryCreationObserver |
131 | | { |
132 | | public: |
133 | | virtual void DirectoryCreated(const OUString& aDirectoryUrl) override |
134 | 0 | { |
135 | 0 | osl::File::setAttributes( aDirectoryUrl, osl_File_Attribute_OwnRead | |
136 | 0 | osl_File_Attribute_OwnWrite | osl_File_Attribute_OwnExe ); |
137 | 0 | }; |
138 | | }; |
139 | | |
140 | | OUString lcl_createName( |
141 | | std::u16string_view rLeadingChars, Tokens & tokens, std::u16string_view pExtension, |
142 | | const OUString* pParent, bool bDirectory, bool bKeep, bool bLock, |
143 | | bool bCreateParentDirs, |
144 | | const std::function<OUString(OUString,OUString)>& rConcatFunc = |
145 | 516k | [](OUString aName, OUString token) -> OUString { return aName + token; }) |
146 | 516k | { |
147 | 516k | OUString aName = ConstructTempDir_Impl( pParent, bCreateParentDirs ); |
148 | 516k | if ( bCreateParentDirs ) |
149 | 0 | { |
150 | 0 | size_t nOffset = rLeadingChars.rfind(u"/"); |
151 | 0 | OUString aDirName; |
152 | 0 | if (std::u16string_view::npos != nOffset) |
153 | 0 | aDirName = aName + rLeadingChars.substr( 0, nOffset ); |
154 | 0 | else |
155 | 0 | aDirName = aName; |
156 | 0 | TempDirCreatedObserver observer; |
157 | 0 | if (!okOrExists(osl::Directory::createPath(aDirName, &observer))) |
158 | 0 | return OUString(); |
159 | 0 | } |
160 | | |
161 | 516k | OUString token; |
162 | 516k | while (tokens.next(&token)) |
163 | 516k | { |
164 | 516k | OUString aTmp(aName + rConcatFunc(OUString(rLeadingChars), token)); |
165 | 516k | if ( !pExtension.empty() ) |
166 | 31.2k | aTmp += pExtension; |
167 | 484k | else |
168 | 484k | aTmp += ".tmp"; |
169 | 516k | if ( bDirectory ) |
170 | 9.17k | { |
171 | 9.17k | osl::FileBase::RC err = osl::Directory::create( |
172 | 9.17k | aTmp, |
173 | 9.17k | (osl_File_OpenFlag_Read | osl_File_OpenFlag_Write |
174 | 9.17k | | osl_File_OpenFlag_Private)); |
175 | 9.17k | if (err == osl::FileBase::E_None) |
176 | 9.17k | { |
177 | | // !bKeep: only for creating a name, not a file or directory |
178 | 9.17k | if (bKeep || osl::Directory::remove(aTmp) == osl::FileBase::E_None) |
179 | 9.17k | return aTmp; |
180 | 0 | else |
181 | 0 | return OUString(); |
182 | 9.17k | } |
183 | 0 | else if (err != osl::FileBase::E_EXIST) |
184 | | // if f.e. name contains invalid chars stop trying to create dirs |
185 | 0 | return OUString(); |
186 | 9.17k | } |
187 | 507k | else |
188 | 507k | { |
189 | 507k | DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" ); |
190 | 507k | osl::File aFile(aTmp); |
191 | 507k | osl::FileBase::RC err = aFile.open( |
192 | 507k | osl_File_OpenFlag_Create | osl_File_OpenFlag_Private |
193 | 507k | | (bLock ? 0 : osl_File_OpenFlag_NoLock)); |
194 | 507k | if (err == osl::FileBase::E_None || (bLock && err == osl::FileBase::E_NOLCK)) |
195 | 507k | { |
196 | 507k | aFile.close(); |
197 | 507k | return aTmp; |
198 | 507k | } |
199 | 0 | else if (err != osl::FileBase::E_EXIST) |
200 | 0 | { |
201 | | // if f.e. name contains invalid chars stop trying to create dirs |
202 | | // but if there is a folder with such name proceed further |
203 | |
|
204 | 0 | osl::DirectoryItem aTmpItem; |
205 | 0 | osl::FileStatus aTmpStatus(osl_FileStatus_Mask_Type); |
206 | 0 | if (osl::DirectoryItem::get(aTmp, aTmpItem) != osl::FileBase::E_None |
207 | 0 | || aTmpItem.getFileStatus(aTmpStatus) != osl::FileBase::E_None |
208 | 0 | || aTmpStatus.getFileType() != osl::FileStatus::Directory) |
209 | 0 | return OUString(); |
210 | 0 | } |
211 | 507k | } |
212 | 516k | } |
213 | 0 | return OUString(); |
214 | 516k | } |
215 | | |
216 | | OUString createEyeCatcher() |
217 | 16 | { |
218 | 16 | OUString eyeCatcher = u"lu"_ustr; |
219 | | #ifdef DBG_UTIL |
220 | | #ifdef UNX |
221 | | if (const char* eye = getenv("LO_TESTNAME")) |
222 | | eyeCatcher = OUString(eye, strlen(eye), RTL_TEXTENCODING_ASCII_US); |
223 | | #elif defined(_WIN32) |
224 | | if (const wchar_t* eye = _wgetenv(L"LO_TESTNAME")) |
225 | | eyeCatcher = OUString(o3tl::toU(eye)); |
226 | | #endif |
227 | | #else |
228 | 16 | #ifdef UNX |
229 | 16 | eyeCatcher += OUString::number(getpid()); |
230 | | #elif defined(_WIN32) |
231 | | eyeCatcher += OUString::number(_getpid()); |
232 | | #endif |
233 | 16 | #endif |
234 | 16 | return eyeCatcher; |
235 | 16 | } |
236 | | |
237 | | const OUString& getEyeCatcher() |
238 | 583k | { |
239 | 583k | static const OUString sEyeCatcher = createEyeCatcher(); |
240 | 583k | return sEyeCatcher; |
241 | 583k | } |
242 | | |
243 | | OUString CreateTempName_Impl( const OUString* pParent, bool bKeep, bool bDir = true ) |
244 | 484k | { |
245 | 484k | UniqueTokens t; |
246 | 484k | return lcl_createName( getEyeCatcher(), t, u"", pParent, bDir, bKeep, |
247 | 484k | false, false); |
248 | 484k | } |
249 | | |
250 | | OUString CreateTempNameFast() |
251 | 98.2k | { |
252 | 98.2k | OUString aName = getTempNameBase_Impl() + getEyeCatcher(); |
253 | | |
254 | 98.2k | tools::Guid aGuid(tools::Guid::Generate); |
255 | | |
256 | 98.2k | return aName + aGuid.getOUString() + ".tmp" ; |
257 | 98.2k | } |
258 | | } |
259 | | |
260 | | namespace utl |
261 | | { |
262 | | |
263 | | OUString CreateTempName() |
264 | 0 | { |
265 | 0 | OUString aName(CreateTempName_Impl( nullptr, false )); |
266 | | |
267 | | // convert to file URL |
268 | 0 | OUString aTmp; |
269 | 0 | if ( !aName.isEmpty() ) |
270 | 0 | osl::FileBase::getSystemPathFromFileURL(aName, aTmp); |
271 | 0 | return aTmp; |
272 | 0 | } |
273 | | |
274 | | TempFileFast::TempFileFast( ) |
275 | 98.2k | { |
276 | 98.2k | } |
277 | | |
278 | | TempFileFast::TempFileFast(TempFileFast && other) noexcept : |
279 | 16 | mxStream(std::move(other.mxStream)) |
280 | 16 | { |
281 | 16 | } |
282 | | |
283 | | TempFileFast::~TempFileFast() |
284 | 98.1k | { |
285 | 98.1k | CloseStream(); |
286 | 98.1k | } |
287 | | |
288 | | SvStream* TempFileFast::GetStream( StreamMode eMode ) |
289 | 99.0k | { |
290 | 99.0k | if (!mxStream) |
291 | 98.2k | { |
292 | 98.2k | OUString aName = CreateTempNameFast(); |
293 | | #ifdef _WIN32 |
294 | | mxStream.reset(new SvFileStream(aName, eMode | StreamMode::TEMPORARY | StreamMode::DELETE_ON_CLOSE)); |
295 | | #else |
296 | 98.2k | mxStream.reset(new SvFileStream(aName, eMode | StreamMode::TEMPORARY)); |
297 | 98.2k | #endif |
298 | 98.2k | } |
299 | 99.0k | return mxStream.get(); |
300 | 99.0k | } |
301 | | |
302 | | void TempFileFast::CloseStream() |
303 | 100k | { |
304 | 100k | if (mxStream) |
305 | 98.1k | { |
306 | 98.1k | #if !defined _WIN32 |
307 | 98.1k | OUString aName = mxStream->GetFileName(); |
308 | 98.1k | #endif |
309 | 98.1k | mxStream.reset(); |
310 | | #ifdef _WIN32 |
311 | | // On Windows, the file is opened with FILE_FLAG_DELETE_ON_CLOSE, so it will delete as soon as the handle closes. |
312 | | // On other platforms, we need to explicitly delete it. |
313 | | #else |
314 | 98.1k | if (!aName.isEmpty() && (osl::FileBase::getFileURLFromSystemPath(aName, aName) == osl::FileBase::E_None)) |
315 | 98.1k | osl::File::remove(aName); |
316 | 98.1k | #endif |
317 | 98.1k | } |
318 | 100k | } |
319 | | |
320 | | OUString CreateTempURL( const OUString* pParent, bool bDirectory ) |
321 | 15.4k | { |
322 | 15.4k | return CreateTempName_Impl( pParent, true, bDirectory ); |
323 | 15.4k | } |
324 | | |
325 | | OUString CreateTempURL(std::u16string_view rLeadingChars, bool _bStartWithZero, |
326 | | std::u16string_view pExtension, const OUString* pParent, |
327 | | bool bCreateParentDirs, |
328 | | const std::function<OUString(OUString, OUString)>& rConcatFunc) |
329 | 0 | { |
330 | 0 | PaddedSequentialTokens<3,1> t(_bStartWithZero); |
331 | 0 | return lcl_createName(rLeadingChars, t, pExtension, pParent, false, |
332 | 0 | true, true, bCreateParentDirs, rConcatFunc); |
333 | 0 | } |
334 | | |
335 | | TempFileNamed::TempFileNamed( const OUString* pParent, bool bDirectory ) |
336 | 469k | : bIsDirectory( bDirectory ) |
337 | 469k | , bKillingFileEnabled( false ) |
338 | 469k | { |
339 | 469k | aName = CreateTempName_Impl( pParent, true, bDirectory ); |
340 | 469k | } |
341 | | |
342 | | TempFileNamed::TempFileNamed( std::u16string_view rLeadingChars, bool _bStartWithZero, |
343 | | std::u16string_view pExtension, const OUString* pParent, |
344 | | bool bCreateParentDirs ) |
345 | 31.2k | : bIsDirectory( false ) |
346 | 31.2k | , bKillingFileEnabled( false ) |
347 | 31.2k | { |
348 | 31.2k | SequentialTokens t(_bStartWithZero); |
349 | 31.2k | aName = lcl_createName( rLeadingChars, t, pExtension, pParent, false, |
350 | 31.2k | true, true, bCreateParentDirs ); |
351 | 31.2k | } |
352 | | |
353 | | TempFileNamed::TempFileNamed(TempFileNamed && other) noexcept : |
354 | 0 | aName(std::move(other.aName)), pStream(std::move(other.pStream)), bIsDirectory(other.bIsDirectory), |
355 | 0 | bKillingFileEnabled(other.bKillingFileEnabled) |
356 | 0 | { |
357 | 0 | other.bKillingFileEnabled = false; |
358 | 0 | } |
359 | | |
360 | | TempFileNamed::~TempFileNamed() |
361 | 500k | { |
362 | 500k | if ( !bKillingFileEnabled ) |
363 | 0 | return; |
364 | | |
365 | 500k | pStream.reset(); |
366 | 500k | if ( bIsDirectory ) |
367 | 9.17k | { |
368 | 9.17k | comphelper::DirectoryHelper::deleteDirRecursively(aName); |
369 | 9.17k | } |
370 | 491k | else |
371 | 491k | { |
372 | 491k | osl::File::remove(aName); |
373 | 491k | } |
374 | 500k | } |
375 | | |
376 | | bool TempFileNamed::IsValid() const |
377 | 0 | { |
378 | 0 | return !aName.isEmpty(); |
379 | 0 | } |
380 | | |
381 | | OUString TempFileNamed::GetFileName() const |
382 | 0 | { |
383 | 0 | OUString aTmp; |
384 | 0 | osl::FileBase::getSystemPathFromFileURL(aName, aTmp); |
385 | 0 | return aTmp; |
386 | 0 | } |
387 | | |
388 | | OUString const & TempFileNamed::GetURL() const |
389 | 87.4k | { |
390 | | // if you request the URL, then you presumably want to access this via UCB, |
391 | | // and UCB will want to open the file via a separate file handle, which means |
392 | | // we have to make this file data actually hit disk. We do this here (and not |
393 | | // elsewhere) to make the other (normal) paths fast. Flushing to disk |
394 | | // really slows temp files down. |
395 | 87.4k | if (pStream) |
396 | 0 | pStream->Flush(); |
397 | 87.4k | return aName; |
398 | 87.4k | } |
399 | | |
400 | | SvStream* TempFileNamed::GetStream( StreamMode eMode ) |
401 | 462k | { |
402 | 462k | if (!pStream) |
403 | 462k | { |
404 | 462k | if (!aName.isEmpty()) |
405 | 462k | pStream.reset(new SvFileStream(aName, eMode | StreamMode::TEMPORARY)); |
406 | 0 | else |
407 | 0 | pStream.reset(new SvMemoryStream); |
408 | 462k | } |
409 | | |
410 | 462k | return pStream.get(); |
411 | 462k | } |
412 | | |
413 | | void TempFileNamed::CloseStream() |
414 | 31.2k | { |
415 | 31.2k | pStream.reset(); |
416 | 31.2k | } |
417 | | |
418 | | OUString SetTempNameBaseDirectory( const OUString &rBaseName ) |
419 | 0 | { |
420 | 0 | if( rBaseName.isEmpty() ) |
421 | 0 | return OUString(); |
422 | | |
423 | | // remove trailing slash |
424 | 0 | OUString aUnqPath(stripTrailingSlash(rBaseName)); |
425 | | |
426 | | // try to create the directory |
427 | 0 | bool bRet = okOrExists(osl::Directory::createPath(aUnqPath)); |
428 | | |
429 | | // failure to create base directory means returning an empty string |
430 | 0 | OUString aTmp; |
431 | 0 | if ( bRet ) |
432 | 0 | { |
433 | | // append own internal directory |
434 | 0 | gTempNameBase_Impl = ensureTrailingSlash(rBaseName); |
435 | |
|
436 | 0 | TempFileNamed aBase( {}, true ); |
437 | 0 | if ( aBase.IsValid() ) |
438 | | // use it in case of success |
439 | 0 | gTempNameBase_Impl = ensureTrailingSlash(aBase.GetURL()); |
440 | | |
441 | | // return system path of used directory |
442 | 0 | osl::FileBase::getSystemPathFromFileURL(gTempNameBase_Impl, aTmp); |
443 | 0 | } |
444 | |
|
445 | 0 | return aTmp; |
446 | 0 | } |
447 | | |
448 | | OUString GetTempNameBaseDirectory() |
449 | 0 | { |
450 | 0 | return ConstructTempDir_Impl(nullptr, false); |
451 | 0 | } |
452 | | |
453 | | |
454 | | TempFileFastService::TempFileFastService() |
455 | 87.5k | : mbInClosed( false ) |
456 | 87.5k | , mbOutClosed( false ) |
457 | 87.5k | { |
458 | 87.5k | mpTempFile.emplace(); |
459 | 87.5k | mpStream = mpTempFile->GetStream(StreamMode::READWRITE); |
460 | 87.5k | } |
461 | | |
462 | | TempFileFastService::~TempFileFastService () |
463 | 87.3k | { |
464 | 87.3k | } |
465 | | |
466 | | // XInputStream |
467 | | |
468 | | sal_Int32 SAL_CALL TempFileFastService::readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) |
469 | 0 | { |
470 | 0 | std::unique_lock aGuard( maMutex ); |
471 | 0 | if ( mbInClosed ) |
472 | 0 | throw css::io::NotConnectedException ( OUString(), getXWeak() ); |
473 | | |
474 | 0 | checkConnected(); |
475 | 0 | if (nBytesToRead < 0) |
476 | 0 | throw css::io::BufferSizeExceededException( OUString(), getXWeak()); |
477 | | |
478 | 0 | if (aData.getLength() < nBytesToRead) |
479 | 0 | aData.realloc(nBytesToRead); |
480 | |
|
481 | 0 | sal_uInt32 nRead = mpStream->ReadBytes(static_cast<void*>(aData.getArray()), nBytesToRead); |
482 | 0 | checkError(); |
483 | |
|
484 | 0 | if (nRead < o3tl::make_unsigned(aData.getLength())) |
485 | 0 | aData.realloc( nRead ); |
486 | |
|
487 | 0 | return nRead; |
488 | 0 | } |
489 | | |
490 | | sal_Int32 SAL_CALL TempFileFastService::readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) |
491 | 0 | { |
492 | 0 | { |
493 | 0 | std::unique_lock aGuard( maMutex ); |
494 | 0 | if ( mbInClosed ) |
495 | 0 | throw css::io::NotConnectedException ( OUString(), getXWeak() ); |
496 | | |
497 | 0 | checkConnected(); |
498 | 0 | checkError(); |
499 | |
|
500 | 0 | if (nMaxBytesToRead < 0) |
501 | 0 | throw css::io::BufferSizeExceededException( OUString(), getXWeak() ); |
502 | | |
503 | 0 | if (mpStream->eof()) |
504 | 0 | { |
505 | 0 | aData.realloc(0); |
506 | 0 | return 0; |
507 | 0 | } |
508 | 0 | } |
509 | 0 | return readBytes(aData, nMaxBytesToRead); |
510 | 0 | } |
511 | | |
512 | | // comphelper::ByteReader |
513 | | sal_Int32 TempFileFastService::readSomeBytes( sal_Int8* aData, sal_Int32 nBytesToRead ) |
514 | 36.2M | { |
515 | 36.2M | std::unique_lock aGuard( maMutex ); |
516 | 36.2M | if ( mbInClosed ) |
517 | 0 | throw css::io::NotConnectedException ( OUString(), getXWeak() ); |
518 | | |
519 | 36.2M | checkConnected(); |
520 | 36.2M | checkError(); |
521 | | |
522 | 36.2M | if (nBytesToRead < 0) |
523 | 0 | throw css::io::BufferSizeExceededException( OUString(), getXWeak() ); |
524 | | |
525 | 36.2M | if (mpStream->eof()) |
526 | 0 | return 0; |
527 | | |
528 | 36.2M | sal_uInt32 nRead = mpStream->ReadBytes(aData, nBytesToRead); |
529 | 36.2M | checkError(); |
530 | | |
531 | 36.2M | return nRead; |
532 | 36.2M | } |
533 | | |
534 | | void SAL_CALL TempFileFastService::skipBytes( sal_Int32 nBytesToSkip ) |
535 | 0 | { |
536 | 0 | std::unique_lock aGuard( maMutex ); |
537 | 0 | if ( mbInClosed ) |
538 | 0 | throw css::io::NotConnectedException ( OUString(), getXWeak() ); |
539 | | |
540 | 0 | checkConnected(); |
541 | 0 | checkError(); |
542 | 0 | mpStream->SeekRel(nBytesToSkip); |
543 | 0 | checkError(); |
544 | 0 | } |
545 | | |
546 | | sal_Int32 SAL_CALL TempFileFastService::available() |
547 | 0 | { |
548 | 0 | std::unique_lock aGuard( maMutex ); |
549 | 0 | if ( mbInClosed ) |
550 | 0 | throw css::io::NotConnectedException ( OUString(), getXWeak() ); |
551 | | |
552 | 0 | checkConnected(); |
553 | |
|
554 | 0 | sal_Int64 nAvailable = mpStream->remainingSize(); |
555 | 0 | checkError(); |
556 | |
|
557 | 0 | return std::min<sal_Int64>(SAL_MAX_INT32, nAvailable); |
558 | 0 | } |
559 | | |
560 | | void SAL_CALL TempFileFastService::closeInput() |
561 | 0 | { |
562 | 0 | std::unique_lock aGuard( maMutex ); |
563 | 0 | if ( mbInClosed ) |
564 | 0 | throw css::io::NotConnectedException ( OUString(), getXWeak() ); |
565 | | |
566 | 0 | mbInClosed = true; |
567 | |
|
568 | 0 | if ( mbOutClosed ) |
569 | 0 | { |
570 | | // stream will be deleted by TempFile implementation |
571 | 0 | mpStream = nullptr; |
572 | 0 | mpTempFile.reset(); |
573 | 0 | } |
574 | 0 | } |
575 | | |
576 | | // XOutputStream |
577 | | |
578 | | void SAL_CALL TempFileFastService::writeBytes( const css::uno::Sequence< sal_Int8 >& aData ) |
579 | 0 | { |
580 | 0 | std::unique_lock aGuard( maMutex ); |
581 | 0 | if ( mbOutClosed ) |
582 | 0 | throw css::io::NotConnectedException ( OUString(), getXWeak() ); |
583 | | |
584 | 0 | checkConnected(); |
585 | 0 | sal_uInt32 nWritten = mpStream->WriteBytes(aData.getConstArray(), aData.getLength()); |
586 | 0 | checkError(); |
587 | 0 | if ( nWritten != static_cast<sal_uInt32>(aData.getLength())) |
588 | 0 | throw css::io::BufferSizeExceededException( OUString(), getXWeak() ); |
589 | 0 | } |
590 | | |
591 | | // comphelper::ByteWriter |
592 | | |
593 | | void TempFileFastService::writeBytes( const sal_Int8* aData, sal_Int32 nBytesToWrite ) |
594 | 14.9k | { |
595 | 14.9k | std::unique_lock aGuard( maMutex ); |
596 | 14.9k | if ( mbOutClosed ) |
597 | 0 | throw css::io::NotConnectedException ( OUString(), getXWeak() ); |
598 | | |
599 | 14.9k | checkConnected(); |
600 | 14.9k | sal_uInt32 nWritten = mpStream->WriteBytes(aData, nBytesToWrite); |
601 | 14.9k | checkError(); |
602 | 14.9k | if ( nWritten != o3tl::make_unsigned(nBytesToWrite) ) |
603 | 0 | throw css::io::BufferSizeExceededException( OUString(), getXWeak() ); |
604 | 14.9k | } |
605 | | |
606 | | void SAL_CALL TempFileFastService::flush() |
607 | 0 | { |
608 | 0 | std::unique_lock aGuard( maMutex ); |
609 | 0 | if ( mbOutClosed ) |
610 | 0 | throw css::io::NotConnectedException ( OUString(), getXWeak() ); |
611 | | |
612 | 0 | checkConnected(); |
613 | 0 | mpStream->Flush(); |
614 | 0 | checkError(); |
615 | 0 | } |
616 | | |
617 | | void SAL_CALL TempFileFastService::closeOutput() |
618 | 0 | { |
619 | 0 | std::unique_lock aGuard( maMutex ); |
620 | 0 | if ( mbOutClosed ) |
621 | 0 | throw css::io::NotConnectedException ( OUString(), getXWeak() ); |
622 | | |
623 | 0 | mbOutClosed = true; |
624 | 0 | if (mpStream) |
625 | 0 | { |
626 | | // so that if you then open the InputStream, you can read the content |
627 | 0 | mpStream->FlushBuffer(); |
628 | 0 | mpStream->Seek(0); |
629 | 0 | } |
630 | |
|
631 | 0 | if ( mbInClosed ) |
632 | 0 | { |
633 | | // stream will be deleted by TempFile implementation |
634 | 0 | mpStream = nullptr; |
635 | 0 | mpTempFile.reset(); |
636 | 0 | } |
637 | 0 | } |
638 | | |
639 | | void TempFileFastService::checkError() const |
640 | 147M | { |
641 | 147M | if (!mpStream || mpStream->SvStream::GetError () != ERRCODE_NONE ) |
642 | 0 | throw css::io::NotConnectedException ( OUString(), const_cast < TempFileFastService * > (this)->getXWeak() ); |
643 | 147M | } |
644 | | |
645 | | void TempFileFastService::checkConnected() |
646 | 74.9M | { |
647 | 74.9M | if (!mpStream) |
648 | 0 | throw css::io::NotConnectedException ( OUString(), getXWeak() ); |
649 | 74.9M | } |
650 | | |
651 | | // XSeekable |
652 | | |
653 | | void SAL_CALL TempFileFastService::seek( sal_Int64 nLocation ) |
654 | 36.2M | { |
655 | 36.2M | std::unique_lock aGuard( maMutex ); |
656 | 36.2M | checkConnected(); |
657 | 36.2M | checkError(); |
658 | 36.2M | if ( nLocation < 0 ) |
659 | 0 | throw css::lang::IllegalArgumentException(); |
660 | | |
661 | 36.2M | sal_Int64 nNewLoc = mpStream->Seek(static_cast<sal_uInt32>(nLocation) ); |
662 | 36.2M | if ( nNewLoc != nLocation ) |
663 | 0 | throw css::lang::IllegalArgumentException(); |
664 | 36.2M | checkError(); |
665 | 36.2M | } |
666 | | |
667 | | sal_Int64 SAL_CALL TempFileFastService::getPosition() |
668 | 0 | { |
669 | 0 | std::unique_lock aGuard( maMutex ); |
670 | 0 | checkConnected(); |
671 | |
|
672 | 0 | sal_uInt64 nPos = mpStream->Tell(); |
673 | 0 | checkError(); |
674 | 0 | return static_cast<sal_Int64>(nPos); |
675 | 0 | } |
676 | | |
677 | | sal_Int64 SAL_CALL TempFileFastService::getLength() |
678 | 2.44M | { |
679 | 2.44M | std::unique_lock aGuard( maMutex ); |
680 | 2.44M | checkConnected(); |
681 | | |
682 | 2.44M | checkError(); |
683 | | |
684 | 2.44M | sal_Int64 nEndPos = mpStream->TellEnd(); |
685 | | |
686 | 2.44M | return nEndPos; |
687 | 2.44M | } |
688 | | |
689 | | // XStream |
690 | | |
691 | | css::uno::Reference< css::io::XInputStream > SAL_CALL TempFileFastService::getInputStream() |
692 | 72.7k | { |
693 | 72.7k | return this; |
694 | 72.7k | } |
695 | | |
696 | | css::uno::Reference< css::io::XOutputStream > SAL_CALL TempFileFastService::getOutputStream() |
697 | 72.7k | { |
698 | 72.7k | return this; |
699 | 72.7k | } |
700 | | |
701 | | // XTruncate |
702 | | |
703 | | void SAL_CALL TempFileFastService::truncate() |
704 | 0 | { |
705 | 0 | std::unique_lock aGuard( maMutex ); |
706 | 0 | checkConnected(); |
707 | | // SetStreamSize() call does not change the position |
708 | 0 | mpStream->Seek( 0 ); |
709 | 0 | mpStream->SetStreamSize( 0 ); |
710 | 0 | checkError(); |
711 | 0 | } |
712 | | |
713 | | |
714 | | |
715 | | } |
716 | | |
717 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |