Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */