1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
26 #if !defined WIN32_LEAN_AND_MEAN
27 # define WIN32_LEAN_AND_MEAN
32 #include <osl/thread.h>
33 #include <tools/stream.hxx>
34 #include <o3tl/char16_t2wchar_t.hxx>
37 #include <osl/file.hxx>
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
},
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
96 if( errArr
[i
].wnt
== nWntError
)
98 nRetVal
= errArr
[i
].sv
;
102 } while( errArr
[i
].wnt
!= DWORD(0xFFFFFFFF) );
106 SvFileStream::SvFileStream( const OUString
& rFileName
, StreamMode nMode
)
110 m_isWritable
= false;
111 pInstanceData
.reset( new StreamData
);
113 SetBufferSize( 8192 );
114 // convert URL to SystemPath, if necessary
117 if ( FileBase::getSystemPathFromFileURL( rFileName
, aFileName
) != FileBase::E_None
)
118 aFileName
= rFileName
;
119 Open( aFileName
, nMode
);
122 SvFileStream::SvFileStream()
126 m_isWritable
= false;
127 pInstanceData
.reset( new StreamData
);
129 SetBufferSize( 8192 );
132 SvFileStream::~SvFileStream()
137 /// Does not check for EOF, makes isEof callable
138 std::size_t SvFileStream::GetData( void* pData
, std::size_t nSize
)
143 bool bResult
= ReadFile(pInstanceData
->hFile
,pData
,nSize
,&nCount
,nullptr);
146 std::size_t nTestError
= GetLastError();
147 SetError(::GetSvError( nTestError
) );
153 std::size_t SvFileStream::PutData( const void* pData
, std::size_t nSize
)
158 if(!WriteFile(pInstanceData
->hFile
,pData
,nSize
,&nCount
,nullptr))
159 SetError(::GetSvError( GetLastError() ) );
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
);
171 if( nPos
!= STREAM_SEEK_TO_END
)
172 // 64-Bit files are not supported
173 nNewPos
=SetFilePointer(pInstanceData
->hFile
,nPos
,nullptr,FILE_BEGIN
);
175 nNewPos
=SetFilePointer(pInstanceData
->hFile
,0L,nullptr,FILE_END
);
177 if( nNewPos
== 0xFFFFFFFF )
179 SetError(::GetSvError( GetLastError() ) );
184 SetError( SVSTREAM_GENERALERROR
);
185 return static_cast<sal_uInt64
>(nNewPos
);
188 void SvFileStream::FlushData()
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;
202 bRetVal
= ::LockFile(pInstanceData
->hFile
,nByteOffset
,0L,nBytes
,0L );
204 SetError(::GetSvError(GetLastError()));
209 bool SvFileStream::UnlockRange(sal_uInt64
const nByteOffset
, std::size_t nBytes
)
211 bool bRetVal
= false;
214 bRetVal
= ::UnlockFile(pInstanceData
->hFile
,nByteOffset
,0L,nBytes
,0L );
216 SetError(::GetSvError(GetLastError()));
221 bool SvFileStream::LockFile()
223 bool bRetVal
= false;
226 if( LockRange( 0L, LONG_MAX
) )
240 void SvFileStream::UnlockFile()
242 if( nLockCounter
> 0)
244 if( nLockCounter
== 1)
246 if( UnlockRange( 0L, LONG_MAX
) )
259 NOCREATE TRUNC NT-Action
260 ----------------------------------------------
261 0 (Create) 0 OPEN_ALWAYS
262 0 (Create) 1 CREATE_ALWAYS
264 1 1 TRUNCATE_EXISTING
266 void SvFileStream::Open( const OUString
& rFilename
, StreamMode nMode
)
268 OUString
aParsedFilename(rFilename
);
270 SetLastError( ERROR_SUCCESS
);
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
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
)
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
;
308 nOpenAction
= OPEN_ALWAYS
;
312 if( nMode
& StreamMode::TRUNC
)
313 nOpenAction
= TRUNCATE_EXISTING
;
315 nOpenAction
= OPEN_EXISTING
;
318 pInstanceData
->hFile
= CreateFileW(
319 o3tl::toW(aFilename
.getStr()),
324 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,
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
))
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()),
358 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,
361 if( GetLastError() == ERROR_ALREADY_EXISTS
)
362 SetLastError( ERROR_SUCCESS
);
366 if( GetLastError() != ERROR_SUCCESS
)
369 SetError(::GetSvError( GetLastError() ) );
374 // pInstanceData->bIsEof = false;
375 if( nAccessMode
& GENERIC_WRITE
)
378 SetErrorMode( nOldErrorMode
);
381 void SvFileStream::Close()
391 CloseHandle( pInstanceData
->hFile
);
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
)
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
);
422 if( SetFilePointer( hFile
,nOld
,nullptr,FILE_BEGIN
) == 0xffffffff)
426 SetError(::GetSvError( GetLastError() ) );
430 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */