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>
36 #include <osl/file.hxx>
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
},
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
95 if( errArr
[i
].wnt
== nWntError
)
97 nRetVal
= errArr
[i
].sv
;
101 } while( errArr
[i
].wnt
!= DWORD(0xFFFFFFFF) );
105 SvFileStream::SvFileStream( const OUString
& rFileName
, StreamMode nMode
)
109 m_isWritable
= false;
110 mbDontFlushOnClose
= 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 mbDontFlushOnClose
= false;
128 pInstanceData
.reset( new StreamData
);
130 SetBufferSize( 8192 );
133 SvFileStream::~SvFileStream()
138 /// Does not check for EOF, makes isEof callable
139 std::size_t SvFileStream::GetData( void* pData
, std::size_t nSize
)
144 bool bResult
= ReadFile(pInstanceData
->hFile
,pData
,nSize
,&nCount
,nullptr);
147 std::size_t nTestError
= GetLastError();
148 SetError(::GetSvError( nTestError
) );
154 std::size_t SvFileStream::PutData( const void* pData
, std::size_t nSize
)
159 if(!WriteFile(pInstanceData
->hFile
,pData
,nSize
,&nCount
,nullptr))
160 SetError(::GetSvError( GetLastError() ) );
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
);
172 if( nPos
!= STREAM_SEEK_TO_END
)
173 // 64-Bit files are not supported
174 nNewPos
=SetFilePointer(pInstanceData
->hFile
,nPos
,nullptr,FILE_BEGIN
);
176 nNewPos
=SetFilePointer(pInstanceData
->hFile
,0L,nullptr,FILE_END
);
178 if( nNewPos
== 0xFFFFFFFF )
180 SetError(::GetSvError( GetLastError() ) );
185 SetError( SVSTREAM_GENERALERROR
);
186 return static_cast<sal_uInt64
>(nNewPos
);
189 void SvFileStream::FlushData()
193 if( !FlushFileBuffers(pInstanceData
->hFile
) )
194 SetError(::GetSvError(GetLastError()));
198 bool SvFileStream::LockFile()
200 bool bRetVal
= false;
205 bRetVal
= ::LockFile(pInstanceData
->hFile
,0L,0L,LONG_MAX
,0L );
211 SetError(::GetSvError(GetLastError()));
222 void SvFileStream::UnlockFile()
224 if( nLockCounter
> 0)
226 if( nLockCounter
== 1)
230 if( ::UnlockFile(pInstanceData
->hFile
,0L,0L,LONG_MAX
,0L ) )
235 SetError(::GetSvError(GetLastError()));
246 NOCREATE TRUNC NT-Action
247 ----------------------------------------------
248 0 (Create) 0 OPEN_ALWAYS
249 0 (Create) 1 CREATE_ALWAYS
251 1 1 TRUNCATE_EXISTING
253 void SvFileStream::Open( const OUString
& rFilename
, StreamMode nMode
)
255 OUString
aParsedFilename(rFilename
);
257 SetLastError( ERROR_SUCCESS
);
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
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
)
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
;
295 nOpenAction
= OPEN_ALWAYS
;
299 if( nMode
& StreamMode::TRUNC
)
300 nOpenAction
= TRUNCATE_EXISTING
;
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()),
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
))
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()),
350 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,
353 if( GetLastError() == ERROR_ALREADY_EXISTS
)
354 SetLastError( ERROR_SUCCESS
);
358 if( GetLastError() != ERROR_SUCCESS
)
361 SetError(::GetSvError( GetLastError() ) );
366 // pInstanceData->bIsEof = false;
367 if( nAccessMode
& GENERIC_WRITE
)
370 SetErrorMode( nOldErrorMode
);
373 void SvFileStream::Close()
382 if ( !mbDontFlushOnClose
)
384 CloseHandle( pInstanceData
->hFile
);
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
)
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
);
415 if( SetFilePointer( hFile
,nOld
,nullptr,FILE_BEGIN
) == 0xffffffff)
419 SetError(::GetSvError( GetLastError() ) );
423 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */