Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / tools / source / stream / strmwnt.cxx
bloba0aa5c769b1c55f7a87b82e90fb56dd46186d2fd
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 .
20 // TODO: StreamMode <-> AllocateMemory
22 #include <string.h>
23 #include <limits.h>
25 #ifdef _WIN32
26 #if !defined WIN32_LEAN_AND_MEAN
27 # define WIN32_LEAN_AND_MEAN
28 #endif
29 #include <windows.h>
30 #endif
32 #include <osl/thread.h>
33 #include <tools/stream.hxx>
34 #include <o3tl/char16_t2wchar_t.hxx>
36 // class FileBase
37 #include <osl/file.hxx>
38 using namespace osl;
40 class StreamData
42 public:
43 HANDLE hFile;
45 StreamData() : hFile(nullptr)
50 static ErrCode GetSvError( DWORD nWntError )
52 static struct { DWORD wnt; ErrCode sv; } errArr[] =
54 { ERROR_SUCCESS, ERRCODE_NONE },
55 { ERROR_ACCESS_DENIED, SVSTREAM_ACCESS_DENIED },
56 { ERROR_ACCOUNT_DISABLED, SVSTREAM_ACCESS_DENIED },
57 { ERROR_ACCOUNT_EXPIRED, SVSTREAM_ACCESS_DENIED },
58 { ERROR_ACCOUNT_RESTRICTION, SVSTREAM_ACCESS_DENIED },
59 { ERROR_ATOMIC_LOCKS_NOT_SUPPORTED, SVSTREAM_INVALID_PARAMETER },
60 { ERROR_BAD_PATHNAME, SVSTREAM_PATH_NOT_FOUND },
61 // Filename too long
62 { ERROR_BUFFER_OVERFLOW, SVSTREAM_INVALID_PARAMETER },
63 { ERROR_DIRECTORY, SVSTREAM_INVALID_PARAMETER },
64 { ERROR_DRIVE_LOCKED, SVSTREAM_LOCKING_VIOLATION },
65 { ERROR_FILE_NOT_FOUND, SVSTREAM_FILE_NOT_FOUND },
66 { ERROR_FILENAME_EXCED_RANGE, SVSTREAM_INVALID_PARAMETER },
67 { ERROR_INVALID_ACCESS, SVSTREAM_INVALID_ACCESS },
68 { ERROR_INVALID_DRIVE, SVSTREAM_PATH_NOT_FOUND },
69 { ERROR_INVALID_HANDLE, SVSTREAM_INVALID_HANDLE },
70 { ERROR_INVALID_NAME, SVSTREAM_PATH_NOT_FOUND },
71 { ERROR_INVALID_PARAMETER, SVSTREAM_INVALID_PARAMETER },
72 { ERROR_IS_SUBST_PATH, SVSTREAM_INVALID_PARAMETER },
73 { ERROR_IS_SUBST_TARGET, SVSTREAM_INVALID_PARAMETER },
74 { ERROR_LOCK_FAILED, SVSTREAM_LOCKING_VIOLATION },
75 { ERROR_LOCK_VIOLATION, SVSTREAM_LOCKING_VIOLATION },
76 { ERROR_NEGATIVE_SEEK, SVSTREAM_SEEK_ERROR },
77 { ERROR_PATH_NOT_FOUND, SVSTREAM_PATH_NOT_FOUND },
78 { ERROR_READ_FAULT, SVSTREAM_READ_ERROR },
79 { ERROR_SEEK, SVSTREAM_SEEK_ERROR },
80 { ERROR_SEEK_ON_DEVICE, SVSTREAM_SEEK_ERROR },
81 { ERROR_SHARING_BUFFER_EXCEEDED,SVSTREAM_SHARE_BUFF_EXCEEDED },
82 { ERROR_SHARING_PAUSED, SVSTREAM_SHARING_VIOLATION },
83 { ERROR_SHARING_VIOLATION, SVSTREAM_SHARING_VIOLATION },
84 { ERROR_TOO_MANY_OPEN_FILES, SVSTREAM_TOO_MANY_OPEN_FILES },
85 { ERROR_WRITE_FAULT, SVSTREAM_WRITE_ERROR },
86 { ERROR_WRITE_PROTECT, SVSTREAM_ACCESS_DENIED },
87 { ERROR_DISK_FULL, SVSTREAM_DISK_FULL },
89 { DWORD(0xFFFFFFFF), SVSTREAM_GENERALERROR }
92 ErrCode nRetVal = SVSTREAM_GENERALERROR; // default error
93 int i=0;
96 if( errArr[i].wnt == nWntError )
98 nRetVal = errArr[i].sv;
99 break;
101 i++;
102 } while( errArr[i].wnt != DWORD(0xFFFFFFFF) );
103 return nRetVal;
106 SvFileStream::SvFileStream( const OUString& rFileName, StreamMode nMode )
108 bIsOpen = false;
109 nLockCounter = 0;
110 m_isWritable = false;
111 pInstanceData.reset( new StreamData );
113 SetBufferSize( 8192 );
114 // convert URL to SystemPath, if necessary
115 OUString aFileName;
117 if ( FileBase::getSystemPathFromFileURL( rFileName, aFileName ) != FileBase::E_None )
118 aFileName = rFileName;
119 Open( aFileName, nMode );
122 SvFileStream::SvFileStream()
124 bIsOpen = false;
125 nLockCounter = 0;
126 m_isWritable = false;
127 pInstanceData.reset( new StreamData );
129 SetBufferSize( 8192 );
132 SvFileStream::~SvFileStream()
134 Close();
137 /// Does not check for EOF, makes isEof callable
138 std::size_t SvFileStream::GetData( void* pData, std::size_t nSize )
140 DWORD nCount = 0;
141 if( IsOpen() )
143 bool bResult = ReadFile(pInstanceData->hFile,pData,nSize,&nCount,nullptr);
144 if( !bResult )
146 std::size_t nTestError = GetLastError();
147 SetError(::GetSvError( nTestError ) );
150 return nCount;
153 std::size_t SvFileStream::PutData( const void* pData, std::size_t nSize )
155 DWORD nCount = 0;
156 if( IsOpen() )
158 if(!WriteFile(pInstanceData->hFile,pData,nSize,&nCount,nullptr))
159 SetError(::GetSvError( GetLastError() ) );
161 return nCount;
164 sal_uInt64 SvFileStream::SeekPos(sal_uInt64 const nPos)
166 // check if a truncated STREAM_SEEK_TO_END was passed
167 assert(nPos != SAL_MAX_UINT32);
168 DWORD nNewPos = 0;
169 if( IsOpen() )
171 if( nPos != STREAM_SEEK_TO_END )
172 // 64-Bit files are not supported
173 nNewPos=SetFilePointer(pInstanceData->hFile,nPos,nullptr,FILE_BEGIN);
174 else
175 nNewPos=SetFilePointer(pInstanceData->hFile,0L,nullptr,FILE_END);
177 if( nNewPos == 0xFFFFFFFF )
179 SetError(::GetSvError( GetLastError() ) );
180 nNewPos = 0;
183 else
184 SetError( SVSTREAM_GENERALERROR );
185 return static_cast<sal_uInt64>(nNewPos);
188 void SvFileStream::FlushData()
190 if( IsOpen() )
192 if( !FlushFileBuffers(pInstanceData->hFile) )
193 SetError(::GetSvError(GetLastError()));
197 bool SvFileStream::LockRange(sal_uInt64 const nByteOffset, std::size_t nBytes)
199 bool bRetVal = false;
200 if( IsOpen() )
202 bRetVal = ::LockFile(pInstanceData->hFile,nByteOffset,0L,nBytes,0L );
203 if( !bRetVal )
204 SetError(::GetSvError(GetLastError()));
206 return bRetVal;
209 bool SvFileStream::UnlockRange(sal_uInt64 const nByteOffset, std::size_t nBytes)
211 bool bRetVal = false;
212 if( IsOpen() )
214 bRetVal = ::UnlockFile(pInstanceData->hFile,nByteOffset,0L,nBytes,0L );
215 if( !bRetVal )
216 SetError(::GetSvError(GetLastError()));
218 return bRetVal;
221 bool SvFileStream::LockFile()
223 bool bRetVal = false;
224 if( !nLockCounter )
226 if( LockRange( 0L, LONG_MAX ) )
228 nLockCounter = 1;
229 bRetVal = true;
232 else
234 nLockCounter++;
235 bRetVal = true;
237 return bRetVal;
240 void SvFileStream::UnlockFile()
242 if( nLockCounter > 0)
244 if( nLockCounter == 1)
246 if( UnlockRange( 0L, LONG_MAX ) )
248 nLockCounter = 0;
251 else
253 nLockCounter--;
259 NOCREATE TRUNC NT-Action
260 ----------------------------------------------
261 0 (Create) 0 OPEN_ALWAYS
262 0 (Create) 1 CREATE_ALWAYS
263 1 0 OPEN_EXISTING
264 1 1 TRUNCATE_EXISTING
266 void SvFileStream::Open( const OUString& rFilename, StreamMode nMode )
268 OUString aParsedFilename(rFilename);
270 SetLastError( ERROR_SUCCESS );
271 Close();
272 SvStream::ClearBuffer();
274 m_eStreamMode = nMode;
275 m_eStreamMode &= ~StreamMode::TRUNC; // don't truncate on reopen
277 aFilename = aParsedFilename;
278 SetLastError( ERROR_SUCCESS ); // might be changed by Redirector
280 DWORD nOpenAction;
281 DWORD nShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
282 DWORD nAccessMode = 0;
283 UINT nOldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX );
285 if( nMode & StreamMode::SHARE_DENYREAD)
286 nShareMode &= ~FILE_SHARE_READ;
288 if( nMode & StreamMode::SHARE_DENYWRITE)
289 nShareMode &= ~FILE_SHARE_WRITE;
291 if( nMode & StreamMode::SHARE_DENYALL)
292 nShareMode = 0;
294 if( nMode & StreamMode::READ )
295 nAccessMode |= GENERIC_READ;
296 if( nMode & StreamMode::WRITE )
297 nAccessMode |= GENERIC_WRITE;
299 if( nAccessMode == GENERIC_READ ) // ReadOnly ?
300 nMode |= StreamMode::NOCREATE; // Don't create if readonly
302 // Assignment based on true/false table above
303 if( !(nMode & StreamMode::NOCREATE) )
305 if( nMode & StreamMode::TRUNC )
306 nOpenAction = CREATE_ALWAYS;
307 else
308 nOpenAction = OPEN_ALWAYS;
310 else
312 if( nMode & StreamMode::TRUNC )
313 nOpenAction = TRUNCATE_EXISTING;
314 else
315 nOpenAction = OPEN_EXISTING;
318 pInstanceData->hFile = CreateFileW(
319 o3tl::toW(aFilename.getStr()),
320 nAccessMode,
321 nShareMode,
322 nullptr,
323 nOpenAction,
324 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
325 nullptr
328 if( pInstanceData->hFile!=INVALID_HANDLE_VALUE && (
329 // Did Create Always overwrite a file?
330 GetLastError() == ERROR_ALREADY_EXISTS ||
331 // Did Create Always open a new file?
332 GetLastError() == ERROR_FILE_NOT_FOUND ))
334 // If so, no error
335 if( nOpenAction == OPEN_ALWAYS || nOpenAction == CREATE_ALWAYS )
336 SetLastError( ERROR_SUCCESS );
339 // Otherwise, determine if we're allowed to read
340 if( (pInstanceData->hFile==INVALID_HANDLE_VALUE) &&
341 (nAccessMode & GENERIC_WRITE))
343 ErrCode nErr = ::GetSvError( GetLastError() );
344 if(nErr==SVSTREAM_ACCESS_DENIED || nErr==SVSTREAM_SHARING_VIOLATION)
346 nMode &= ~StreamMode::WRITE;
347 nAccessMode = GENERIC_READ;
348 // OV, 28.1.97: Win32 sets file to length 0
349 // if Openaction is CREATE_ALWAYS
350 nOpenAction = OPEN_EXISTING;
351 SetLastError( ERROR_SUCCESS );
352 pInstanceData->hFile = CreateFileW(
353 o3tl::toW(aFilename.getStr()),
354 GENERIC_READ,
355 nShareMode,
356 nullptr,
357 nOpenAction,
358 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
359 nullptr
361 if( GetLastError() == ERROR_ALREADY_EXISTS )
362 SetLastError( ERROR_SUCCESS );
366 if( GetLastError() != ERROR_SUCCESS )
368 bIsOpen = false;
369 SetError(::GetSvError( GetLastError() ) );
371 else
373 bIsOpen = true;
374 // pInstanceData->bIsEof = false;
375 if( nAccessMode & GENERIC_WRITE )
376 m_isWritable = true;
378 SetErrorMode( nOldErrorMode );
381 void SvFileStream::Close()
383 if( IsOpen() )
385 if( nLockCounter )
387 nLockCounter = 1;
388 UnlockFile();
390 Flush();
391 CloseHandle( pInstanceData->hFile );
393 bIsOpen = false;
394 nLockCounter= 0;
395 m_isWritable = false;
396 SvStream::ClearBuffer();
397 SvStream::ClearError();
400 /// Reset filepointer to beginning of file
401 void SvFileStream::ResetError()
403 SvStream::ClearError();
406 void SvFileStream::SetSize(sal_uInt64 const nSize)
409 if( IsOpen() )
411 bool bError = false;
412 HANDLE hFile = pInstanceData->hFile;
413 DWORD const nOld = SetFilePointer( hFile, 0L, nullptr, FILE_CURRENT );
414 if( nOld != 0xffffffff )
416 if( SetFilePointer(hFile,nSize,nullptr,FILE_BEGIN ) != 0xffffffff)
418 bool bSucc = SetEndOfFile( hFile );
419 if( !bSucc )
420 bError = true;
422 if( SetFilePointer( hFile,nOld,nullptr,FILE_BEGIN ) == 0xffffffff)
423 bError = true;
425 if( bError )
426 SetError(::GetSvError( GetLastError() ) );
430 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */