Coverage Report

Created: 2026-02-14 09:37

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