Version 7.3.5.2, tag libreoffice-7.3.5.2
[LibreOffice.git] / tools / source / stream / strmwnt.cxx
blobc91628b55091ba67e16fdd836fceec0614181325
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 #include <osl/file.hxx>
37 using namespace osl;
39 class StreamData
41 public:
42 HANDLE hFile;
44 StreamData() : hFile(nullptr)
49 static ErrCode GetSvError( DWORD nWntError )
51 static struct { DWORD wnt; ErrCode sv; } errArr[] =
53 { ERROR_SUCCESS, ERRCODE_NONE },
54 { ERROR_ACCESS_DENIED, SVSTREAM_ACCESS_DENIED },
55 { ERROR_ACCOUNT_DISABLED, SVSTREAM_ACCESS_DENIED },
56 { ERROR_ACCOUNT_EXPIRED, SVSTREAM_ACCESS_DENIED },
57 { ERROR_ACCOUNT_RESTRICTION, SVSTREAM_ACCESS_DENIED },
58 { ERROR_ATOMIC_LOCKS_NOT_SUPPORTED, SVSTREAM_INVALID_PARAMETER },
59 { ERROR_BAD_PATHNAME, SVSTREAM_PATH_NOT_FOUND },
60 // Filename too long
61 { ERROR_BUFFER_OVERFLOW, SVSTREAM_INVALID_PARAMETER },
62 { ERROR_DIRECTORY, SVSTREAM_INVALID_PARAMETER },
63 { ERROR_DRIVE_LOCKED, SVSTREAM_LOCKING_VIOLATION },
64 { ERROR_FILE_NOT_FOUND, SVSTREAM_FILE_NOT_FOUND },
65 { ERROR_FILENAME_EXCED_RANGE, SVSTREAM_INVALID_PARAMETER },
66 { ERROR_INVALID_ACCESS, SVSTREAM_INVALID_ACCESS },
67 { ERROR_INVALID_DRIVE, SVSTREAM_PATH_NOT_FOUND },
68 { ERROR_INVALID_HANDLE, SVSTREAM_INVALID_HANDLE },
69 { ERROR_INVALID_NAME, SVSTREAM_PATH_NOT_FOUND },
70 { ERROR_INVALID_PARAMETER, SVSTREAM_INVALID_PARAMETER },
71 { ERROR_IS_SUBST_PATH, SVSTREAM_INVALID_PARAMETER },
72 { ERROR_IS_SUBST_TARGET, SVSTREAM_INVALID_PARAMETER },
73 { ERROR_LOCK_FAILED, SVSTREAM_LOCKING_VIOLATION },
74 { ERROR_LOCK_VIOLATION, SVSTREAM_LOCKING_VIOLATION },
75 { ERROR_NEGATIVE_SEEK, SVSTREAM_SEEK_ERROR },
76 { ERROR_PATH_NOT_FOUND, SVSTREAM_PATH_NOT_FOUND },
77 { ERROR_READ_FAULT, SVSTREAM_READ_ERROR },
78 { ERROR_SEEK, SVSTREAM_SEEK_ERROR },
79 { ERROR_SEEK_ON_DEVICE, SVSTREAM_SEEK_ERROR },
80 { ERROR_SHARING_BUFFER_EXCEEDED,SVSTREAM_SHARE_BUFF_EXCEEDED },
81 { ERROR_SHARING_PAUSED, SVSTREAM_SHARING_VIOLATION },
82 { ERROR_SHARING_VIOLATION, SVSTREAM_SHARING_VIOLATION },
83 { ERROR_TOO_MANY_OPEN_FILES, SVSTREAM_TOO_MANY_OPEN_FILES },
84 { ERROR_WRITE_FAULT, SVSTREAM_WRITE_ERROR },
85 { ERROR_WRITE_PROTECT, SVSTREAM_ACCESS_DENIED },
86 { ERROR_DISK_FULL, SVSTREAM_DISK_FULL },
88 { DWORD(0xFFFFFFFF), SVSTREAM_GENERALERROR }
91 ErrCode nRetVal = SVSTREAM_GENERALERROR; // default error
92 int i=0;
95 if( errArr[i].wnt == nWntError )
97 nRetVal = errArr[i].sv;
98 break;
100 i++;
101 } while( errArr[i].wnt != DWORD(0xFFFFFFFF) );
102 return nRetVal;
105 SvFileStream::SvFileStream( const OUString& rFileName, StreamMode nMode )
107 bIsOpen = false;
108 nLockCounter = 0;
109 m_isWritable = false;
110 mbDontFlushOnClose = 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 mbDontFlushOnClose = false;
128 pInstanceData.reset( new StreamData );
130 SetBufferSize( 8192 );
133 SvFileStream::~SvFileStream()
135 Close();
138 /// Does not check for EOF, makes isEof callable
139 std::size_t SvFileStream::GetData( void* pData, std::size_t nSize )
141 DWORD nCount = 0;
142 if( IsOpen() )
144 bool bResult = ReadFile(pInstanceData->hFile,pData,nSize,&nCount,nullptr);
145 if( !bResult )
147 std::size_t nTestError = GetLastError();
148 SetError(::GetSvError( nTestError ) );
151 return nCount;
154 std::size_t SvFileStream::PutData( const void* pData, std::size_t nSize )
156 DWORD nCount = 0;
157 if( IsOpen() )
159 if(!WriteFile(pInstanceData->hFile,pData,nSize,&nCount,nullptr))
160 SetError(::GetSvError( GetLastError() ) );
162 return nCount;
165 sal_uInt64 SvFileStream::SeekPos(sal_uInt64 const nPos)
167 // check if a truncated STREAM_SEEK_TO_END was passed
168 assert(nPos != SAL_MAX_UINT32);
169 DWORD nNewPos = 0;
170 if( IsOpen() )
172 if( nPos != STREAM_SEEK_TO_END )
173 // 64-Bit files are not supported
174 nNewPos=SetFilePointer(pInstanceData->hFile,nPos,nullptr,FILE_BEGIN);
175 else
176 nNewPos=SetFilePointer(pInstanceData->hFile,0L,nullptr,FILE_END);
178 if( nNewPos == 0xFFFFFFFF )
180 SetError(::GetSvError( GetLastError() ) );
181 nNewPos = 0;
184 else
185 SetError( SVSTREAM_GENERALERROR );
186 return static_cast<sal_uInt64>(nNewPos);
189 void SvFileStream::FlushData()
191 if( IsOpen() )
193 if( !FlushFileBuffers(pInstanceData->hFile) )
194 SetError(::GetSvError(GetLastError()));
198 bool SvFileStream::LockFile()
200 bool bRetVal = false;
201 if( !nLockCounter )
203 if( IsOpen() )
205 bRetVal = ::LockFile(pInstanceData->hFile,0L,0L,LONG_MAX,0L );
206 if( bRetVal )
208 nLockCounter = 1;
210 else
211 SetError(::GetSvError(GetLastError()));
214 else
216 nLockCounter++;
217 bRetVal = true;
219 return bRetVal;
222 void SvFileStream::UnlockFile()
224 if( nLockCounter > 0)
226 if( nLockCounter == 1)
228 if( IsOpen() )
230 if( ::UnlockFile(pInstanceData->hFile,0L,0L,LONG_MAX,0L ) )
232 nLockCounter = 0;
234 else
235 SetError(::GetSvError(GetLastError()));
238 else
240 nLockCounter--;
246 NOCREATE TRUNC NT-Action
247 ----------------------------------------------
248 0 (Create) 0 OPEN_ALWAYS
249 0 (Create) 1 CREATE_ALWAYS
250 1 0 OPEN_EXISTING
251 1 1 TRUNCATE_EXISTING
253 void SvFileStream::Open( const OUString& rFilename, StreamMode nMode )
255 OUString aParsedFilename(rFilename);
257 SetLastError( ERROR_SUCCESS );
258 Close();
259 SvStream::ClearBuffer();
261 m_eStreamMode = nMode;
262 m_eStreamMode &= ~StreamMode::TRUNC; // don't truncate on reopen
264 aFilename = aParsedFilename;
265 SetLastError( ERROR_SUCCESS ); // might be changed by Redirector
267 DWORD nOpenAction;
268 DWORD nShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
269 DWORD nAccessMode = 0;
270 UINT nOldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX );
272 if( nMode & StreamMode::SHARE_DENYREAD)
273 nShareMode &= ~FILE_SHARE_READ;
275 if( nMode & StreamMode::SHARE_DENYWRITE)
276 nShareMode &= ~FILE_SHARE_WRITE;
278 if( nMode & StreamMode::SHARE_DENYALL)
279 nShareMode = 0;
281 if( nMode & StreamMode::READ )
282 nAccessMode |= GENERIC_READ;
283 if( nMode & StreamMode::WRITE )
284 nAccessMode |= GENERIC_WRITE;
286 if( nAccessMode == GENERIC_READ ) // ReadOnly ?
287 nMode |= StreamMode::NOCREATE; // Don't create if readonly
289 // Assignment based on true/false table above
290 if( !(nMode & StreamMode::NOCREATE) )
292 if( nMode & StreamMode::TRUNC )
293 nOpenAction = CREATE_ALWAYS;
294 else
295 nOpenAction = OPEN_ALWAYS;
297 else
299 if( nMode & StreamMode::TRUNC )
300 nOpenAction = TRUNCATE_EXISTING;
301 else
302 nOpenAction = OPEN_EXISTING;
305 DWORD nAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
307 if ( nMode & StreamMode::TEMPORARY )
308 nAttributes |= FILE_ATTRIBUTE_TEMPORARY;
310 pInstanceData->hFile = CreateFileW(
311 o3tl::toW(aFilename.getStr()),
312 nAccessMode,
313 nShareMode,
314 nullptr,
315 nOpenAction,
316 nAttributes,
317 nullptr
320 if( pInstanceData->hFile!=INVALID_HANDLE_VALUE && (
321 // Did Create Always overwrite a file?
322 GetLastError() == ERROR_ALREADY_EXISTS ||
323 // Did Create Always open a new file?
324 GetLastError() == ERROR_FILE_NOT_FOUND ))
326 // If so, no error
327 if( nOpenAction == OPEN_ALWAYS || nOpenAction == CREATE_ALWAYS )
328 SetLastError( ERROR_SUCCESS );
331 // Otherwise, determine if we're allowed to read
332 if( (pInstanceData->hFile==INVALID_HANDLE_VALUE) &&
333 (nAccessMode & GENERIC_WRITE))
335 ErrCode nErr = ::GetSvError( GetLastError() );
336 if(nErr==SVSTREAM_ACCESS_DENIED || nErr==SVSTREAM_SHARING_VIOLATION)
338 nMode &= ~StreamMode::WRITE;
339 nAccessMode = GENERIC_READ;
340 // OV, 28.1.97: Win32 sets file to length 0
341 // if Openaction is CREATE_ALWAYS
342 nOpenAction = OPEN_EXISTING;
343 SetLastError( ERROR_SUCCESS );
344 pInstanceData->hFile = CreateFileW(
345 o3tl::toW(aFilename.getStr()),
346 GENERIC_READ,
347 nShareMode,
348 nullptr,
349 nOpenAction,
350 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
351 nullptr
353 if( GetLastError() == ERROR_ALREADY_EXISTS )
354 SetLastError( ERROR_SUCCESS );
358 if( GetLastError() != ERROR_SUCCESS )
360 bIsOpen = false;
361 SetError(::GetSvError( GetLastError() ) );
363 else
365 bIsOpen = true;
366 // pInstanceData->bIsEof = false;
367 if( nAccessMode & GENERIC_WRITE )
368 m_isWritable = true;
370 SetErrorMode( nOldErrorMode );
373 void SvFileStream::Close()
375 if( IsOpen() )
377 if( nLockCounter )
379 nLockCounter = 1;
380 UnlockFile();
382 if ( !mbDontFlushOnClose )
383 Flush();
384 CloseHandle( pInstanceData->hFile );
386 bIsOpen = false;
387 nLockCounter= 0;
388 m_isWritable = false;
389 SvStream::ClearBuffer();
390 SvStream::ClearError();
393 /// Reset filepointer to beginning of file
394 void SvFileStream::ResetError()
396 SvStream::ClearError();
399 void SvFileStream::SetSize(sal_uInt64 const nSize)
402 if( IsOpen() )
404 bool bError = false;
405 HANDLE hFile = pInstanceData->hFile;
406 DWORD const nOld = SetFilePointer( hFile, 0L, nullptr, FILE_CURRENT );
407 if( nOld != 0xffffffff )
409 if( SetFilePointer(hFile,nSize,nullptr,FILE_BEGIN ) != 0xffffffff)
411 bool bSucc = SetEndOfFile( hFile );
412 if( !bSucc )
413 bError = true;
415 if( SetFilePointer( hFile,nOld,nullptr,FILE_BEGIN ) == 0xffffffff)
416 bError = true;
418 if( bError )
419 SetError(::GetSvError( GetLastError() ) );
423 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */