office-gobmx/svl/source/misc/sharecontrolfile.cxx
Stephan Bergmann 042033f1e6 loplugin:stringviewparam: operator +
Change-Id: I044dd21b63d7eb03224675584fa143009c6b6008
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/108418
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2020-12-29 16:42:33 +01:00

329 lines
9.6 KiB
C++

/* -*- 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 <com/sun/star/ucb/SimpleFileAccess.hpp>
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
#include <com/sun/star/ucb/XContent.hpp>
#include <com/sun/star/ucb/InsertCommandArgument.hpp>
#include <com/sun/star/ucb/InteractiveIOException.hpp>
#include <com/sun/star/io/NotConnectedException.hpp>
#include <o3tl/enumrange.hxx>
#include <rtl/string.hxx>
#include <rtl/ustring.hxx>
#include <rtl/ustrbuf.hxx>
#include <comphelper/processfactory.hxx>
#include <ucbhelper/content.hxx>
#include <tools/stream.hxx>
#include <unotools/streamwrap.hxx>
#include <svl/sharecontrolfile.hxx>
using namespace ::com::sun::star;
namespace svt {
ShareControlFile::ShareControlFile( const OUString& aOrigURL )
: LockFileCommon(GenerateOwnLockFileURL(aOrigURL, u".~sharing."))
{
if ( !m_xStream.is() && !GetURL().isEmpty() )
{
uno::Reference< ucb::XCommandEnvironment > xDummyEnv;
::ucbhelper::Content aContent( GetURL(), xDummyEnv, comphelper::getProcessComponentContext() );
uno::Reference< ucb::XContentIdentifier > xContId( aContent.get().is() ? aContent.get()->getIdentifier() : nullptr );
if ( !xContId.is() || xContId->getContentProviderScheme() != "file" )
throw io::IOException(); // the implementation supports only local files for now
uno::Reference< io::XStream > xStream;
// Currently the locking of the original document is intended to be used.
// That means that the shared file should be accessed only when the original document is locked and only by user who has locked the document.
// TODO/LATER: should the own file locking be used?
try
{
xStream = aContent.openWriteableStreamNoLock();
}
catch ( ucb::InteractiveIOException const & e )
{
if ( e.Code == ucb::IOErrorCode_NOT_EXISTING )
{
// Create file...
SvMemoryStream aStream(0,0);
uno::Reference< io::XInputStream > xInput( new ::utl::OInputStreamWrapper( aStream ) );
ucb::InsertCommandArgument aInsertArg;
aInsertArg.Data = xInput;
aInsertArg.ReplaceExisting = false;
aContent.executeCommand( "insert", uno::makeAny( aInsertArg ) );
// try to let the file be hidden if possible
try {
aContent.setPropertyValue("IsHidden", uno::makeAny( true ) );
} catch( uno::Exception& ) {}
// Try to open one more time
xStream = aContent.openWriteableStreamNoLock();
}
else
throw;
}
m_xSeekable.set( xStream, uno::UNO_QUERY_THROW );
m_xInputStream.set( xStream->getInputStream(), uno::UNO_SET_THROW );
m_xOutputStream.set( xStream->getOutputStream(), uno::UNO_SET_THROW );
m_xTruncate.set( m_xOutputStream, uno::UNO_QUERY_THROW );
m_xStream = xStream;
}
if ( !IsValid() )
throw io::NotConnectedException();
}
ShareControlFile::~ShareControlFile()
{
try
{
Close();
}
catch( uno::Exception& )
{}
}
void ShareControlFile::Close()
{
// if it is called outside of destructor the mutex must be locked
if ( !m_xStream.is() )
return;
try
{
if ( m_xInputStream.is() )
m_xInputStream->closeInput();
if ( m_xOutputStream.is() )
m_xOutputStream->closeOutput();
}
catch( uno::Exception& )
{}
m_xStream.clear();
m_xInputStream.clear();
m_xOutputStream.clear();
m_xSeekable.clear();
m_xTruncate.clear();
m_aUsersData.clear();
}
std::vector< o3tl::enumarray< LockFileComponent, OUString > > ShareControlFile::GetUsersData()
{
::osl::MutexGuard aGuard( m_aMutex );
if ( !IsValid() )
throw io::NotConnectedException();
if ( m_aUsersData.empty() )
{
sal_Int64 nLength = m_xSeekable->getLength();
if ( nLength > SAL_MAX_INT32 )
throw uno::RuntimeException();
uno::Sequence< sal_Int8 > aBuffer( static_cast<sal_Int32>(nLength) );
m_xSeekable->seek( 0 );
sal_Int32 nRead = m_xInputStream->readBytes( aBuffer, static_cast<sal_Int32>(nLength) );
nLength -= nRead;
while ( nLength > 0 )
{
uno::Sequence< sal_Int8 > aTmpBuf( static_cast<sal_Int32>(nLength) );
nRead = m_xInputStream->readBytes( aTmpBuf, static_cast<sal_Int32>(nLength) );
if ( nRead > nLength )
throw uno::RuntimeException();
for ( sal_Int32 nInd = 0; nInd < nRead; nInd++ )
aBuffer[aBuffer.getLength() - static_cast<sal_Int32>(nLength) + nInd] = aTmpBuf[nInd];
nLength -= nRead;
}
ParseList( aBuffer, m_aUsersData );
}
return m_aUsersData;
}
void ShareControlFile::SetUsersDataAndStore( const std::vector< LockFileEntry >& aUsersData )
{
::osl::MutexGuard aGuard( m_aMutex );
if ( !IsValid() )
throw io::NotConnectedException();
if ( !m_xTruncate.is() || !m_xOutputStream.is() || !m_xSeekable.is() )
throw uno::RuntimeException();
m_xTruncate->truncate();
m_xSeekable->seek( 0 );
OUStringBuffer aBuffer;
for (const auto & rData : aUsersData)
{
for ( LockFileComponent nEntryInd : o3tl::enumrange<LockFileComponent>() )
{
aBuffer.append( EscapeCharacters( rData[nEntryInd] ) );
if ( nEntryInd < LockFileComponent::LAST )
aBuffer.append( ',' );
else
aBuffer.append( ';' );
}
}
OString aStringData( OUStringToOString( aBuffer.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ) );
uno::Sequence< sal_Int8 > aData( reinterpret_cast<sal_Int8 const *>(aStringData.getStr()), aStringData.getLength() );
m_xOutputStream->writeBytes( aData );
m_aUsersData = aUsersData;
}
LockFileEntry ShareControlFile::InsertOwnEntry()
{
::osl::MutexGuard aGuard( m_aMutex );
if ( !IsValid() )
throw io::NotConnectedException();
GetUsersData();
std::vector< LockFileEntry > aNewData( m_aUsersData );
LockFileEntry aNewEntry = GenerateOwnEntry();
bool bExists = false;
sal_Int32 nNewInd = 0;
for (LockFileEntry & rEntry : m_aUsersData)
{
if ( rEntry[LockFileComponent::LOCALHOST] == aNewEntry[LockFileComponent::LOCALHOST]
&& rEntry[LockFileComponent::SYSUSERNAME] == aNewEntry[LockFileComponent::SYSUSERNAME]
&& rEntry[LockFileComponent::USERURL] == aNewEntry[LockFileComponent::USERURL] )
{
if ( !bExists )
{
aNewData[nNewInd] = aNewEntry;
bExists = true;
}
}
else
{
aNewData[nNewInd] = rEntry;
}
nNewInd++;
}
if ( !bExists )
aNewData.push_back( aNewEntry );
SetUsersDataAndStore( aNewData );
return aNewEntry;
}
bool ShareControlFile::HasOwnEntry()
{
::osl::MutexGuard aGuard( m_aMutex );
if ( !IsValid() )
{
throw io::NotConnectedException();
}
GetUsersData();
LockFileEntry aEntry = GenerateOwnEntry();
for (LockFileEntry & rEntry : m_aUsersData)
{
if ( rEntry[LockFileComponent::LOCALHOST] == aEntry[LockFileComponent::LOCALHOST] &&
rEntry[LockFileComponent::SYSUSERNAME] == aEntry[LockFileComponent::SYSUSERNAME] &&
rEntry[LockFileComponent::USERURL] == aEntry[LockFileComponent::USERURL] )
{
return true;
}
}
return false;
}
void ShareControlFile::RemoveEntry()
{
RemoveEntry(GenerateOwnEntry());
}
void ShareControlFile::RemoveEntry( const LockFileEntry& aEntry )
{
::osl::MutexGuard aGuard( m_aMutex );
if ( !IsValid() )
throw io::NotConnectedException();
GetUsersData();
std::vector< LockFileEntry > aNewData;
for (LockFileEntry & rEntry : m_aUsersData)
{
if ( rEntry[LockFileComponent::LOCALHOST] != aEntry[LockFileComponent::LOCALHOST]
|| rEntry[LockFileComponent::SYSUSERNAME] != aEntry[LockFileComponent::SYSUSERNAME]
|| rEntry[LockFileComponent::USERURL] != aEntry[LockFileComponent::USERURL] )
{
aNewData.push_back( rEntry );
}
}
SetUsersDataAndStore( aNewData );
if ( aNewData.empty() )
{
// try to remove the file if it is empty
RemoveFile();
}
}
void ShareControlFile::RemoveFile()
{
::osl::MutexGuard aGuard( m_aMutex );
if ( !IsValid() )
throw io::NotConnectedException();
Close();
uno::Reference<ucb::XSimpleFileAccess3> xSimpleFileAccess(ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()));
xSimpleFileAccess->kill( GetURL() );
}
} // namespace svt
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */