Update git submodules
[LibreOffice.git] / svl / source / misc / sharecontrolfile.cxx
blob740e10eaa19c06928a5c6125a8eea015e11df1a6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
22 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
23 #include <com/sun/star/ucb/XContent.hpp>
24 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
25 #include <com/sun/star/ucb/InteractiveIOException.hpp>
26 #include <com/sun/star/io/NotConnectedException.hpp>
28 #include <o3tl/enumrange.hxx>
30 #include <rtl/string.hxx>
31 #include <rtl/ustring.hxx>
32 #include <rtl/ustrbuf.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <ucbhelper/content.hxx>
37 #include <tools/stream.hxx>
38 #include <unotools/streamwrap.hxx>
40 #include <svl/sharecontrolfile.hxx>
42 using namespace ::com::sun::star;
44 namespace svt {
47 ShareControlFile::ShareControlFile( std::u16string_view aOrigURL )
48 : LockFileCommon(GenerateOwnLockFileURL(aOrigURL, u".~sharing."))
50 if ( !m_xStream.is() && !GetURL().isEmpty() )
52 uno::Reference< ucb::XCommandEnvironment > xDummyEnv;
53 ::ucbhelper::Content aContent( GetURL(), xDummyEnv, comphelper::getProcessComponentContext() );
55 uno::Reference< ucb::XContentIdentifier > xContId( aContent.get().is() ? aContent.get()->getIdentifier() : nullptr );
56 if ( !xContId.is() || xContId->getContentProviderScheme() != "file" )
57 throw io::IOException(); // the implementation supports only local files for now
59 uno::Reference< io::XStream > xStream;
61 // Currently the locking of the original document is intended to be used.
62 // 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.
63 // TODO/LATER: should the own file locking be used?
65 try
67 xStream = aContent.openWriteableStreamNoLock();
69 catch ( ucb::InteractiveIOException const & e )
71 if ( e.Code == ucb::IOErrorCode_NOT_EXISTING )
73 // Create file...
74 SvMemoryStream aStream(0,0);
75 uno::Reference< io::XInputStream > xInput( new ::utl::OInputStreamWrapper( aStream ) );
76 ucb::InsertCommandArgument aInsertArg;
77 aInsertArg.Data = xInput;
78 aInsertArg.ReplaceExisting = false;
79 aContent.executeCommand( "insert", uno::Any( aInsertArg ) );
81 // try to let the file be hidden if possible
82 try {
83 aContent.setPropertyValue("IsHidden", uno::Any( true ) );
84 } catch( uno::Exception& ) {}
86 // Try to open one more time
87 xStream = aContent.openWriteableStreamNoLock();
89 else
90 throw;
93 m_xSeekable.set( xStream, uno::UNO_QUERY_THROW );
94 m_xInputStream.set( xStream->getInputStream(), uno::UNO_SET_THROW );
95 m_xOutputStream.set( xStream->getOutputStream(), uno::UNO_SET_THROW );
96 m_xTruncate.set( m_xOutputStream, uno::UNO_QUERY_THROW );
97 m_xStream = xStream;
100 if ( !IsValid() )
101 throw io::NotConnectedException();
104 ShareControlFile::~ShareControlFile()
108 Close();
110 catch( uno::Exception& )
114 void ShareControlFile::Close()
116 // if it is called outside of destructor the mutex must be locked
118 if ( !m_xStream.is() )
119 return;
123 if ( m_xInputStream.is() )
124 m_xInputStream->closeInput();
125 if ( m_xOutputStream.is() )
126 m_xOutputStream->closeOutput();
128 catch( uno::Exception& )
131 m_xStream.clear();
132 m_xInputStream.clear();
133 m_xOutputStream.clear();
134 m_xSeekable.clear();
135 m_xTruncate.clear();
136 m_aUsersData.clear();
140 std::vector< o3tl::enumarray< LockFileComponent, OUString > > ShareControlFile::GetUsersData()
142 ::osl::MutexGuard aGuard( m_aMutex );
144 if ( !IsValid() )
145 throw io::NotConnectedException();
147 if ( m_aUsersData.empty() )
149 sal_Int64 nLength = m_xSeekable->getLength();
150 if ( nLength > SAL_MAX_INT32 )
151 throw uno::RuntimeException();
153 uno::Sequence< sal_Int8 > aBuffer( static_cast<sal_Int32>(nLength) );
154 m_xSeekable->seek( 0 );
156 sal_Int32 nRead = m_xInputStream->readBytes( aBuffer, static_cast<sal_Int32>(nLength) );
157 auto aBufferRange = asNonConstRange(aBuffer);
158 nLength -= nRead;
159 while ( nLength > 0 )
161 uno::Sequence< sal_Int8 > aTmpBuf( static_cast<sal_Int32>(nLength) );
162 nRead = m_xInputStream->readBytes( aTmpBuf, static_cast<sal_Int32>(nLength) );
163 if ( nRead > nLength )
164 throw uno::RuntimeException();
166 for ( sal_Int32 nInd = 0; nInd < nRead; nInd++ )
167 aBufferRange[aBuffer.getLength() - static_cast<sal_Int32>(nLength) + nInd] = aTmpBuf[nInd];
168 nLength -= nRead;
171 ParseList( aBuffer, m_aUsersData );
174 return m_aUsersData;
178 void ShareControlFile::SetUsersDataAndStore( std::vector< LockFileEntry >&& aUsersData )
180 ::osl::MutexGuard aGuard( m_aMutex );
182 if ( !IsValid() )
183 throw io::NotConnectedException();
185 if ( !m_xTruncate.is() || !m_xOutputStream.is() || !m_xSeekable.is() )
186 throw uno::RuntimeException();
188 m_xTruncate->truncate();
189 m_xSeekable->seek( 0 );
191 OUStringBuffer aBuffer;
192 for (const auto & rData : aUsersData)
194 for ( LockFileComponent nEntryInd : o3tl::enumrange<LockFileComponent>() )
196 aBuffer.append( EscapeCharacters( rData[nEntryInd] ) );
197 if ( nEntryInd < LockFileComponent::LAST )
198 aBuffer.append( ',' );
199 else
200 aBuffer.append( ';' );
204 OString aStringData( OUStringToOString( aBuffer, RTL_TEXTENCODING_UTF8 ) );
205 uno::Sequence< sal_Int8 > aData( reinterpret_cast<sal_Int8 const *>(aStringData.getStr()), aStringData.getLength() );
206 m_xOutputStream->writeBytes( aData );
207 m_aUsersData = aUsersData;
211 LockFileEntry ShareControlFile::InsertOwnEntry()
213 ::osl::MutexGuard aGuard( m_aMutex );
215 if ( !IsValid() )
216 throw io::NotConnectedException();
218 GetUsersData();
219 std::vector< LockFileEntry > aNewData( m_aUsersData );
220 LockFileEntry aNewEntry = GenerateOwnEntry();
222 bool bExists = false;
223 sal_Int32 nNewInd = 0;
224 for (LockFileEntry & rEntry : m_aUsersData)
226 if ( rEntry[LockFileComponent::LOCALHOST] == aNewEntry[LockFileComponent::LOCALHOST]
227 && rEntry[LockFileComponent::SYSUSERNAME] == aNewEntry[LockFileComponent::SYSUSERNAME]
228 && rEntry[LockFileComponent::USERURL] == aNewEntry[LockFileComponent::USERURL] )
230 if ( !bExists )
232 aNewData[nNewInd] = aNewEntry;
233 bExists = true;
236 else
238 aNewData[nNewInd] = rEntry;
241 nNewInd++;
244 if ( !bExists )
245 aNewData.push_back( aNewEntry );
247 SetUsersDataAndStore( std::move(aNewData) );
249 return aNewEntry;
253 bool ShareControlFile::HasOwnEntry()
255 ::osl::MutexGuard aGuard( m_aMutex );
257 if ( !IsValid() )
259 throw io::NotConnectedException();
262 GetUsersData();
263 LockFileEntry aEntry = GenerateOwnEntry();
265 for (LockFileEntry & rEntry : m_aUsersData)
267 if ( rEntry[LockFileComponent::LOCALHOST] == aEntry[LockFileComponent::LOCALHOST] &&
268 rEntry[LockFileComponent::SYSUSERNAME] == aEntry[LockFileComponent::SYSUSERNAME] &&
269 rEntry[LockFileComponent::USERURL] == aEntry[LockFileComponent::USERURL] )
271 return true;
275 return false;
279 void ShareControlFile::RemoveEntry()
281 RemoveEntry(GenerateOwnEntry());
284 void ShareControlFile::RemoveEntry( const LockFileEntry& aEntry )
286 ::osl::MutexGuard aGuard( m_aMutex );
288 if ( !IsValid() )
289 throw io::NotConnectedException();
291 GetUsersData();
293 std::vector< LockFileEntry > aNewData;
295 for (LockFileEntry & rEntry : m_aUsersData)
297 if ( rEntry[LockFileComponent::LOCALHOST] != aEntry[LockFileComponent::LOCALHOST]
298 || rEntry[LockFileComponent::SYSUSERNAME] != aEntry[LockFileComponent::SYSUSERNAME]
299 || rEntry[LockFileComponent::USERURL] != aEntry[LockFileComponent::USERURL] )
301 aNewData.push_back( rEntry );
305 const bool bNewDataEmpty = aNewData.empty();
306 SetUsersDataAndStore( std::move(aNewData) );
308 if ( bNewDataEmpty )
310 // try to remove the file if it is empty
311 RemoveFile();
316 void ShareControlFile::RemoveFile()
318 ::osl::MutexGuard aGuard( m_aMutex );
320 if ( !IsValid() )
321 throw io::NotConnectedException();
323 Close();
325 uno::Reference<ucb::XSimpleFileAccess3> xSimpleFileAccess(ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()));
326 xSimpleFileAccess->kill( GetURL() );
329 } // namespace svt
331 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */