summaryrefslogtreecommitdiffstats
path: root/unotools/source/ucbhelper/tempfile.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'unotools/source/ucbhelper/tempfile.cxx')
-rw-r--r--unotools/source/ucbhelper/tempfile.cxx808
1 files changed, 808 insertions, 0 deletions
diff --git a/unotools/source/ucbhelper/tempfile.cxx b/unotools/source/ucbhelper/tempfile.cxx
new file mode 100644
index 0000000000..992ff8814d
--- /dev/null
+++ b/unotools/source/ucbhelper/tempfile.cxx
@@ -0,0 +1,808 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <utility>
+
+#include <com/sun/star/io/BufferSizeExceededException.hpp>
+#include <com/sun/star/io/NotConnectedException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <unotools/tempfile.hxx>
+#include <rtl/ustring.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/mutex.hxx>
+#include <osl/detail/file.h>
+#include <osl/file.hxx>
+#include <tools/time.hxx>
+#include <tools/debug.hxx>
+#include <tools/Guid.hxx>
+#include <comphelper/DirectoryHelper.hxx>
+
+#ifdef UNX
+#include <unistd.h>
+#elif defined( _WIN32 )
+#include <process.h>
+#endif
+
+using namespace osl;
+
+namespace
+{
+ OUString gTempNameBase_Impl;
+}
+
+namespace utl
+{
+
+static OUString getParentName( std::u16string_view aFileName )
+{
+ size_t lastIndex = aFileName.rfind( '/' );
+ OUString aParent;
+
+ if (lastIndex != std::u16string_view::npos)
+ {
+ aParent = aFileName.substr(0, lastIndex);
+
+ if (aParent.endsWith(":") && aParent.getLength() == 6)
+ aParent += "/";
+
+ if (aParent.equalsIgnoreAsciiCase("file://"))
+ aParent = "file:///";
+ }
+
+ return aParent;
+}
+
+static bool ensuredir( const OUString& rUnqPath )
+{
+ OUString aPath;
+ if ( rUnqPath.isEmpty() )
+ return false;
+
+ // remove trailing slash
+ if ( rUnqPath.endsWith("/") )
+ aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
+ else
+ aPath = rUnqPath;
+
+ // HACK: create directory on a mount point with nobrowse option
+ // returns ENOSYS in any case !!
+ osl::Directory aDirectory( aPath );
+ osl::FileBase::RC nError = aDirectory.open();
+ aDirectory.close();
+ if( nError == osl::File::E_None )
+ return true;
+
+ // try to create the directory
+ nError = osl::Directory::create( aPath );
+ bool bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
+ if( !bSuccess )
+ {
+ // perhaps parent(s) don't exist
+ OUString aParentDir = getParentName( aPath );
+ if ( aParentDir != aPath )
+ {
+ bSuccess = ensuredir( getParentName( aPath ) );
+
+ // After parent directory structure exists try it one's more
+ if ( bSuccess )
+ {
+ // Parent directory exists, retry creation of directory
+ nError = osl::Directory::create( aPath );
+ bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
+ }
+ }
+ }
+
+ return bSuccess;
+}
+
+static OUString ConstructTempDir_Impl( const OUString* pParent, bool bCreateParentDirs )
+{
+ OUString aName;
+
+ // Ignore pParent on iOS. We don't want to create any temp files
+ // in the same directory where the document being edited is.
+#ifndef IOS
+ if ( pParent && !pParent->isEmpty() )
+ {
+ // test for valid filename
+ OUString aRet;
+ if ((osl::FileBase::getSystemPathFromFileURL(*pParent, aRet)
+ == osl::FileBase::E_None)
+ && (osl::FileBase::getFileURLFromSystemPath(aRet, aRet)
+ == osl::FileBase::E_None))
+ {
+ ::osl::DirectoryItem aItem;
+ sal_Int32 i = aRet.getLength();
+ if ( aRet[i-1] == '/' )
+ i--;
+
+ if ( DirectoryItem::get( aRet.copy(0, i), aItem ) == FileBase::E_None || bCreateParentDirs )
+ aName = aRet;
+ }
+ }
+#else
+ (void) pParent;
+ (void) bCreateParentDirs;
+#endif
+
+ if ( aName.isEmpty() )
+ {
+ if (gTempNameBase_Impl.isEmpty())
+ {
+ OUString ustrTempDirURL;
+ ::osl::FileBase::RC rc = ::osl::File::getTempDirURL(
+ ustrTempDirURL );
+ if (rc == ::osl::FileBase::E_None)
+ gTempNameBase_Impl = ustrTempDirURL;
+ ensuredir( aName );
+ }
+ // if no parent or invalid parent : use default directory
+ DBG_ASSERT( !gTempNameBase_Impl.isEmpty(), "No TempDir!" );
+ aName = gTempNameBase_Impl;
+ }
+
+ // Make sure that directory ends with a separator
+ if( !aName.isEmpty() && !aName.endsWith("/") )
+ aName += "/";
+
+ return aName;
+}
+
+namespace {
+
+class Tokens {
+public:
+ virtual bool next(OUString *) = 0;
+
+protected:
+ virtual ~Tokens() {} // avoid warnings
+};
+
+class SequentialTokens: public Tokens {
+public:
+ explicit SequentialTokens(bool showZero): m_value(0), m_show(showZero) {}
+
+ bool next(OUString * token) override {
+ assert(token != nullptr);
+ if (m_value == SAL_MAX_UINT32) {
+ return false;
+ }
+ *token = m_show ? OUString::number(m_value) : OUString();
+ ++m_value;
+ m_show = true;
+ return true;
+ }
+
+private:
+ sal_uInt32 m_value;
+ bool m_show;
+};
+
+class UniqueTokens: public Tokens {
+public:
+ UniqueTokens(): m_count(0) {}
+
+ bool next(OUString * token) override {
+ assert(token != nullptr);
+ // Because of the shared globalValue, no single instance of UniqueTokens
+ // is guaranteed to exhaustively test all 36^6 possible values, but stop
+ // after that many attempts anyway:
+ sal_uInt32 radix = 36;
+ sal_uInt32 max = radix * radix * radix * radix * radix * radix;
+ // 36^6 == 2'176'782'336 < SAL_MAX_UINT32 == 4'294'967'295
+ if (m_count == max) {
+ return false;
+ }
+ sal_uInt32 v;
+ {
+ osl::MutexGuard g(osl::Mutex::getGlobalMutex());
+ globalValue
+ = ((globalValue == SAL_MAX_UINT32
+ ? tools::Time::GetSystemTicks() : globalValue + 1)
+ % max);
+ v = globalValue;
+ }
+ *token = OUString::number(v, radix);
+ ++m_count;
+ return true;
+ }
+
+private:
+ static sal_uInt32 globalValue;
+
+ sal_uInt32 m_count;
+};
+
+}
+
+sal_uInt32 UniqueTokens::globalValue = SAL_MAX_UINT32;
+
+namespace
+{
+ class TempDirCreatedObserver : public DirectoryCreationObserver
+ {
+ public:
+ virtual void DirectoryCreated(const OUString& aDirectoryUrl) override
+ {
+ File::setAttributes( aDirectoryUrl, osl_File_Attribute_OwnRead |
+ osl_File_Attribute_OwnWrite | osl_File_Attribute_OwnExe );
+ };
+ };
+};
+
+static OUString lcl_createName(
+ std::u16string_view rLeadingChars, Tokens & tokens, std::u16string_view pExtension,
+ const OUString* pParent, bool bDirectory, bool bKeep, bool bLock,
+ bool bCreateParentDirs )
+{
+ OUString aName = ConstructTempDir_Impl( pParent, bCreateParentDirs );
+ if ( bCreateParentDirs )
+ {
+ size_t nOffset = rLeadingChars.rfind(u"/");
+ OUString aDirName;
+ if (std::u16string_view::npos != nOffset)
+ aDirName = aName + rLeadingChars.substr( 0, nOffset );
+ else
+ aDirName = aName;
+ TempDirCreatedObserver observer;
+ FileBase::RC err = Directory::createPath( aDirName, &observer );
+ if ( err != FileBase::E_None && err != FileBase::E_EXIST )
+ return OUString();
+ }
+ aName += rLeadingChars;
+
+ OUString token;
+ while (tokens.next(&token))
+ {
+ OUString aTmp( aName + token );
+ if ( !pExtension.empty() )
+ aTmp += pExtension;
+ else
+ aTmp += ".tmp";
+ if ( bDirectory )
+ {
+ FileBase::RC err = Directory::create(
+ aTmp,
+ (osl_File_OpenFlag_Read | osl_File_OpenFlag_Write
+ | osl_File_OpenFlag_Private));
+ if ( err == FileBase::E_None )
+ {
+ // !bKeep: only for creating a name, not a file or directory
+ if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None )
+ return aTmp;
+ else
+ return OUString();
+ }
+ else if ( err != FileBase::E_EXIST )
+ // if f.e. name contains invalid chars stop trying to create dirs
+ return OUString();
+ }
+ else
+ {
+ DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" );
+ File aFile( aTmp );
+ FileBase::RC err = aFile.open(
+ osl_File_OpenFlag_Create | osl_File_OpenFlag_Private
+ | (bLock ? 0 : osl_File_OpenFlag_NoLock));
+ if ( err == FileBase::E_None || (bLock && err == FileBase::E_NOLCK) )
+ {
+ aFile.close();
+ return aTmp;
+ }
+ else if ( err != FileBase::E_EXIST )
+ {
+ // if f.e. name contains invalid chars stop trying to create dirs
+ // but if there is a folder with such name proceed further
+
+ DirectoryItem aTmpItem;
+ FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
+ if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
+ || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
+ || aTmpStatus.getFileType() != FileStatus::Directory )
+ return OUString();
+ }
+ }
+ }
+ return OUString();
+}
+
+static OUString CreateTempName_Impl( const OUString* pParent, bool bKeep, bool bDir = true )
+{
+ OUString aEyeCatcher = "lu";
+#ifdef UNX
+#ifdef DBG_UTIL
+ const char* eye = getenv("LO_TESTNAME");
+ if(eye)
+ {
+ aEyeCatcher = OUString(eye, strlen(eye), RTL_TEXTENCODING_ASCII_US);
+ }
+#else
+ static const pid_t pid = getpid();
+ static const OUString aPidString = OUString::number(pid);
+ aEyeCatcher += aPidString;
+#endif
+#elif defined(_WIN32)
+ static const int pid = _getpid();
+ static const OUString aPidString = OUString::number(pid);
+ aEyeCatcher += aPidString;
+#endif
+ UniqueTokens t;
+ return lcl_createName( aEyeCatcher, t, u"", pParent, bDir, bKeep,
+ false, false);
+}
+
+static OUString CreateTempNameFast()
+{
+ OUString aEyeCatcher = "lu";
+#ifdef UNX
+#ifdef DBG_UTIL
+ const char* eye = getenv("LO_TESTNAME");
+ if(eye)
+ {
+ aEyeCatcher = OUString(eye, strlen(eye), RTL_TEXTENCODING_ASCII_US);
+ }
+#else
+ static const pid_t pid = getpid();
+ static const OUString aPidString = OUString::number(pid);
+ aEyeCatcher += aPidString;
+#endif
+#elif defined(_WIN32)
+ static const int pid = _getpid();
+ static const OUString aPidString = OUString::number(pid);
+ aEyeCatcher += aPidString;
+#endif
+
+ OUString aName = ConstructTempDir_Impl( /*pParent*/nullptr, /*bCreateParentDirs*/false ) + aEyeCatcher;
+
+ tools::Guid aGuid(tools::Guid::Generate);
+
+ return aName + aGuid.getOUString() + ".tmp" ;
+}
+
+OUString CreateTempName()
+{
+ OUString aName(CreateTempName_Impl( nullptr, false ));
+
+ // convert to file URL
+ OUString aTmp;
+ if ( !aName.isEmpty() )
+ FileBase::getSystemPathFromFileURL( aName, aTmp );
+ return aTmp;
+}
+
+TempFileFast::TempFileFast( )
+{
+}
+
+TempFileFast::TempFileFast(TempFileFast && other) noexcept :
+ mxStream(std::move(other.mxStream))
+{
+}
+
+TempFileFast::~TempFileFast()
+{
+ CloseStream();
+}
+
+SvStream* TempFileFast::GetStream( StreamMode eMode )
+{
+ if (!mxStream)
+ {
+ OUString aName = CreateTempNameFast();
+#ifdef _WIN32
+ mxStream.reset(new SvFileStream(aName, eMode | StreamMode::TEMPORARY | StreamMode::DELETE_ON_CLOSE));
+#else
+ mxStream.reset(new SvFileStream(aName, eMode | StreamMode::TEMPORARY));
+#endif
+ }
+ return mxStream.get();
+}
+
+void TempFileFast::CloseStream()
+{
+ if (mxStream)
+ {
+#if !defined _WIN32
+ OUString aName = mxStream->GetFileName();
+#endif
+ mxStream.reset();
+#ifdef _WIN32
+ // On Windows, the file is opened with FILE_FLAG_DELETE_ON_CLOSE, so it will delete as soon as the handle closes.
+ // On other platforms, we need to explicitly delete it.
+#else
+ if (!aName.isEmpty() && (osl::FileBase::getFileURLFromSystemPath(aName, aName) == osl::FileBase::E_None))
+ File::remove(aName);
+#endif
+ }
+}
+
+OUString CreateTempURL( const OUString* pParent, bool bDirectory )
+{
+ return CreateTempName_Impl( pParent, true, bDirectory );
+}
+
+OUString CreateTempURL( std::u16string_view rLeadingChars, bool _bStartWithZero,
+ std::u16string_view pExtension, const OUString* pParent,
+ bool bCreateParentDirs )
+{
+ SequentialTokens t(_bStartWithZero);
+ return lcl_createName( rLeadingChars, t, pExtension, pParent, false,
+ true, true, bCreateParentDirs );
+}
+
+TempFileNamed::TempFileNamed( const OUString* pParent, bool bDirectory )
+ : bIsDirectory( bDirectory )
+ , bKillingFileEnabled( false )
+{
+ aName = CreateTempName_Impl( pParent, true, bDirectory );
+}
+
+TempFileNamed::TempFileNamed( std::u16string_view rLeadingChars, bool _bStartWithZero,
+ std::u16string_view pExtension, const OUString* pParent,
+ bool bCreateParentDirs )
+ : bIsDirectory( false )
+ , bKillingFileEnabled( false )
+{
+ SequentialTokens t(_bStartWithZero);
+ aName = lcl_createName( rLeadingChars, t, pExtension, pParent, false,
+ true, true, bCreateParentDirs );
+}
+
+TempFileNamed::TempFileNamed(TempFileNamed && other) noexcept :
+ aName(std::move(other.aName)), pStream(std::move(other.pStream)), bIsDirectory(other.bIsDirectory),
+ bKillingFileEnabled(other.bKillingFileEnabled)
+{
+ other.bKillingFileEnabled = false;
+}
+
+TempFileNamed::~TempFileNamed()
+{
+ if ( !bKillingFileEnabled )
+ return;
+
+ pStream.reset();
+ if ( bIsDirectory )
+ {
+ comphelper::DirectoryHelper::deleteDirRecursively(aName);
+ }
+ else
+ {
+ File::remove( aName );
+ }
+}
+
+bool TempFileNamed::IsValid() const
+{
+ return !aName.isEmpty();
+}
+
+OUString TempFileNamed::GetFileName() const
+{
+ OUString aTmp;
+ FileBase::getSystemPathFromFileURL(aName, aTmp);
+ return aTmp;
+}
+
+OUString const & TempFileNamed::GetURL() const
+{
+ // if you request the URL, then you presumably want to access this via UCB,
+ // and UCB will want to open the file via a separate file handle, which means
+ // we have to make this file data actually hit disk. We do this here (and not
+ // elsewhere) to make the other (normal) paths fast. Flushing to disk
+ // really slows temp files down.
+ if (pStream)
+ pStream->Flush();
+ return aName;
+}
+
+SvStream* TempFileNamed::GetStream( StreamMode eMode )
+{
+ if (!pStream)
+ {
+ if (!aName.isEmpty())
+ pStream.reset(new SvFileStream(aName, eMode | StreamMode::TEMPORARY));
+ else
+ pStream.reset(new SvMemoryStream);
+ }
+
+ return pStream.get();
+}
+
+void TempFileNamed::CloseStream()
+{
+ pStream.reset();
+}
+
+OUString SetTempNameBaseDirectory( const OUString &rBaseName )
+{
+ if( rBaseName.isEmpty() )
+ return OUString();
+
+ OUString aUnqPath( rBaseName );
+
+ // remove trailing slash
+ if ( rBaseName.endsWith("/") )
+ aUnqPath = rBaseName.copy( 0, rBaseName.getLength() - 1 );
+
+ // try to create the directory
+ bool bRet = false;
+ osl::FileBase::RC err = osl::Directory::create( aUnqPath );
+ if ( err != FileBase::E_None && err != FileBase::E_EXIST )
+ // perhaps parent(s) don't exist
+ bRet = ensuredir( aUnqPath );
+ else
+ bRet = true;
+
+ // failure to create base directory means returning an empty string
+ OUString aTmp;
+ if ( bRet )
+ {
+ // append own internal directory
+ OUString &rTempNameBase_Impl = gTempNameBase_Impl;
+ rTempNameBase_Impl = rBaseName + "/";
+
+ TempFileNamed aBase( {}, true );
+ if ( aBase.IsValid() )
+ // use it in case of success
+ rTempNameBase_Impl = aBase.aName;
+
+ // return system path of used directory
+ FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
+ }
+
+ return aTmp;
+}
+
+OUString GetTempNameBaseDirectory()
+{
+ return ConstructTempDir_Impl(nullptr, false);
+}
+
+
+TempFileFastService::TempFileFastService()
+: mbInClosed( false )
+, mbOutClosed( false )
+{
+ mpTempFile.emplace();
+ mpStream = mpTempFile->GetStream(StreamMode::READWRITE);
+}
+
+TempFileFastService::~TempFileFastService ()
+{
+}
+
+// XInputStream
+
+sal_Int32 SAL_CALL TempFileFastService::readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
+{
+ std::unique_lock aGuard( maMutex );
+ if ( mbInClosed )
+ throw css::io::NotConnectedException ( OUString(), getXWeak() );
+
+ checkConnected();
+ if (nBytesToRead < 0)
+ throw css::io::BufferSizeExceededException( OUString(), getXWeak());
+
+ if (aData.getLength() < nBytesToRead)
+ aData.realloc(nBytesToRead);
+
+ sal_uInt32 nRead = mpStream->ReadBytes(static_cast<void*>(aData.getArray()), nBytesToRead);
+ checkError();
+
+ if (nRead < o3tl::make_unsigned(aData.getLength()))
+ aData.realloc( nRead );
+
+ return nRead;
+}
+
+sal_Int32 SAL_CALL TempFileFastService::readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
+{
+ {
+ std::unique_lock aGuard( maMutex );
+ if ( mbInClosed )
+ throw css::io::NotConnectedException ( OUString(), getXWeak() );
+
+ checkConnected();
+ checkError();
+
+ if (nMaxBytesToRead < 0)
+ throw css::io::BufferSizeExceededException( OUString(), getXWeak() );
+
+ if (mpStream->eof())
+ {
+ aData.realloc(0);
+ return 0;
+ }
+ }
+ return readBytes(aData, nMaxBytesToRead);
+}
+
+void SAL_CALL TempFileFastService::skipBytes( sal_Int32 nBytesToSkip )
+{
+ std::unique_lock aGuard( maMutex );
+ if ( mbInClosed )
+ throw css::io::NotConnectedException ( OUString(), getXWeak() );
+
+ checkConnected();
+ checkError();
+ mpStream->SeekRel(nBytesToSkip);
+ checkError();
+}
+
+sal_Int32 SAL_CALL TempFileFastService::available()
+{
+ std::unique_lock aGuard( maMutex );
+ if ( mbInClosed )
+ throw css::io::NotConnectedException ( OUString(), getXWeak() );
+
+ checkConnected();
+
+ sal_Int64 nAvailable = mpStream->remainingSize();
+ checkError();
+
+ return std::min<sal_Int64>(SAL_MAX_INT32, nAvailable);
+}
+
+void SAL_CALL TempFileFastService::closeInput()
+{
+ std::unique_lock aGuard( maMutex );
+ if ( mbInClosed )
+ throw css::io::NotConnectedException ( OUString(), getXWeak() );
+
+ mbInClosed = true;
+
+ if ( mbOutClosed )
+ {
+ // stream will be deleted by TempFile implementation
+ mpStream = nullptr;
+ mpTempFile.reset();
+ }
+}
+
+// XOutputStream
+
+void SAL_CALL TempFileFastService::writeBytes( const css::uno::Sequence< sal_Int8 >& aData )
+{
+ std::unique_lock aGuard( maMutex );
+ if ( mbOutClosed )
+ throw css::io::NotConnectedException ( OUString(), getXWeak() );
+
+ checkConnected();
+ sal_uInt32 nWritten = mpStream->WriteBytes(aData.getConstArray(), aData.getLength());
+ checkError();
+ if ( nWritten != static_cast<sal_uInt32>(aData.getLength()))
+ throw css::io::BufferSizeExceededException( OUString(), getXWeak() );
+}
+
+void SAL_CALL TempFileFastService::flush()
+{
+ std::unique_lock aGuard( maMutex );
+ if ( mbOutClosed )
+ throw css::io::NotConnectedException ( OUString(), getXWeak() );
+
+ checkConnected();
+ mpStream->Flush();
+ checkError();
+}
+
+void SAL_CALL TempFileFastService::closeOutput()
+{
+ std::unique_lock aGuard( maMutex );
+ if ( mbOutClosed )
+ throw css::io::NotConnectedException ( OUString(), getXWeak() );
+
+ mbOutClosed = true;
+ if (mpStream)
+ {
+ // so that if you then open the InputStream, you can read the content
+ mpStream->FlushBuffer();
+ mpStream->Seek(0);
+ }
+
+ if ( mbInClosed )
+ {
+ // stream will be deleted by TempFile implementation
+ mpStream = nullptr;
+ mpTempFile.reset();
+ }
+}
+
+void TempFileFastService::checkError() const
+{
+ if (!mpStream || mpStream->SvStream::GetError () != ERRCODE_NONE )
+ throw css::io::NotConnectedException ( OUString(), const_cast < TempFileFastService * > (this)->getXWeak() );
+}
+
+void TempFileFastService::checkConnected()
+{
+ if (!mpStream)
+ throw css::io::NotConnectedException ( OUString(), getXWeak() );
+}
+
+// XSeekable
+
+void SAL_CALL TempFileFastService::seek( sal_Int64 nLocation )
+{
+ std::unique_lock aGuard( maMutex );
+ checkConnected();
+ checkError();
+ if ( nLocation < 0 )
+ throw css::lang::IllegalArgumentException();
+
+ sal_Int64 nNewLoc = mpStream->Seek(static_cast<sal_uInt32>(nLocation) );
+ if ( nNewLoc != nLocation )
+ throw css::lang::IllegalArgumentException();
+ checkError();
+}
+
+sal_Int64 SAL_CALL TempFileFastService::getPosition()
+{
+ std::unique_lock aGuard( maMutex );
+ checkConnected();
+
+ sal_uInt64 nPos = mpStream->Tell();
+ checkError();
+ return static_cast<sal_Int64>(nPos);
+}
+
+sal_Int64 SAL_CALL TempFileFastService::getLength()
+{
+ std::unique_lock aGuard( maMutex );
+ checkConnected();
+
+ checkError();
+
+ sal_Int64 nEndPos = mpStream->TellEnd();
+
+ return nEndPos;
+}
+
+// XStream
+
+css::uno::Reference< css::io::XInputStream > SAL_CALL TempFileFastService::getInputStream()
+{
+ return this;
+}
+
+css::uno::Reference< css::io::XOutputStream > SAL_CALL TempFileFastService::getOutputStream()
+{
+ return this;
+}
+
+// XTruncate
+
+void SAL_CALL TempFileFastService::truncate()
+{
+ std::unique_lock aGuard( maMutex );
+ checkConnected();
+ // SetStreamSize() call does not change the position
+ mpStream->Seek( 0 );
+ mpStream->SetStreamSize( 0 );
+ checkError();
+}
+
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */