lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / sal / osl / w32 / file.cxx
blob0c3f3d9621fe227ea55328a8e9a406342be5155d
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 #include <systools/win32/uwinapi.h>
22 #include <osl/file.hxx>
23 #include <rtl/alloc.h>
24 #include <rtl/byteseq.h>
25 #include <sal/log.hxx>
26 #include <o3tl/char16_t2wchar_t.hxx>
28 #include "file-impl.hxx"
29 #include "file_url.hxx"
30 #include "file_error.hxx"
32 #include <cassert>
33 #include <algorithm>
34 #include <limits>
36 #ifdef max /* conflict w/ std::numeric_limits<T>::max() */
37 #undef max
38 #endif
39 #ifdef min
40 #undef min
41 #endif
43 /** File handle implementation.
45 struct FileHandle_Impl
47 CRITICAL_SECTION m_mutex;
48 HANDLE m_hFile;
50 /** State
52 enum StateBits
54 STATE_SEEKABLE = 1, /*< open() sets, iff regular file */
55 STATE_READABLE = 2, /*< open() sets, read() requires */
56 STATE_WRITEABLE = 4, /*< open() sets, write() requires */
57 STATE_MODIFIED = 8 /* write() sets, flush() resets */
59 int m_state;
61 sal_uInt64 m_size; /*< file size */
62 LONGLONG m_offset; /*< physical offset from begin of file */
63 LONGLONG m_filepos; /*< logical offset from begin of file */
65 LONGLONG m_bufptr; /*< buffer offset from begin of file */
66 SIZE_T m_buflen; /*< buffer filled [0, m_bufsiz - 1] */
68 SIZE_T m_bufsiz;
69 sal_uInt8 * m_buffer;
71 explicit FileHandle_Impl (HANDLE hFile);
72 ~FileHandle_Impl();
74 static void* operator new(size_t n);
75 static void operator delete(void * p, size_t);
76 static SIZE_T getpagesize();
78 sal_uInt64 getPos() const;
79 oslFileError setPos (sal_uInt64 uPos);
81 sal_uInt64 getSize() const;
82 oslFileError setSize (sal_uInt64 uPos);
84 oslFileError readAt(
85 LONGLONG nOffset,
86 void * pBuffer,
87 DWORD nBytesRequested,
88 sal_uInt64 * pBytesRead);
90 oslFileError writeAt(
91 LONGLONG nOffset,
92 void const * pBuffer,
93 DWORD nBytesToWrite,
94 sal_uInt64 * pBytesWritten);
96 oslFileError readFileAt(
97 LONGLONG nOffset,
98 void * pBuffer,
99 sal_uInt64 uBytesRequested,
100 sal_uInt64 * pBytesRead);
102 oslFileError writeFileAt(
103 LONGLONG nOffset,
104 void const * pBuffer,
105 sal_uInt64 uBytesToWrite,
106 sal_uInt64 * pBytesWritten);
108 oslFileError readLineAt(
109 LONGLONG nOffset,
110 sal_Sequence ** ppSequence,
111 sal_uInt64 * pBytesRead);
113 static oslFileError writeSequence_Impl (
114 sal_Sequence ** ppSequence,
115 SIZE_T * pnOffset,
116 const void * pBuffer,
117 SIZE_T nBytes);
119 oslFileError syncFile();
121 /** Guard.
123 class Guard
125 LPCRITICAL_SECTION m_mutex;
127 public:
128 explicit Guard(LPCRITICAL_SECTION pMutex);
129 ~Guard();
133 FileHandle_Impl::Guard::Guard(LPCRITICAL_SECTION pMutex)
134 : m_mutex (pMutex)
136 assert(pMutex);
137 ::EnterCriticalSection (m_mutex);
140 FileHandle_Impl::Guard::~Guard()
142 ::LeaveCriticalSection (m_mutex);
145 FileHandle_Impl::FileHandle_Impl(HANDLE hFile)
146 : m_hFile (hFile),
147 m_state (STATE_READABLE | STATE_WRITEABLE),
148 m_size (0),
149 m_offset (0),
150 m_filepos (0),
151 m_bufptr (-1),
152 m_buflen (0),
153 m_bufsiz (getpagesize()),
154 m_buffer (nullptr)
156 ::InitializeCriticalSection (&m_mutex);
157 m_buffer = static_cast<sal_uInt8 *>(malloc(m_bufsiz));
158 if (m_buffer)
159 memset (m_buffer, 0, m_bufsiz);
162 FileHandle_Impl::~FileHandle_Impl()
164 free(m_buffer);
165 m_buffer = nullptr;
166 ::DeleteCriticalSection (&m_mutex);
169 void * FileHandle_Impl::operator new(size_t n)
171 return malloc(n);
174 void FileHandle_Impl::operator delete(void * p, size_t)
176 free(p);
179 SIZE_T FileHandle_Impl::getpagesize()
181 SYSTEM_INFO info;
182 ::GetSystemInfo(&info);
183 return sal::static_int_cast< SIZE_T >(info.dwPageSize);
186 sal_uInt64 FileHandle_Impl::getPos() const
188 return sal::static_int_cast< sal_uInt64 >(m_filepos);
191 oslFileError FileHandle_Impl::setPos(sal_uInt64 uPos)
193 m_filepos = sal::static_int_cast< LONGLONG >(uPos);
194 return osl_File_E_None;
197 sal_uInt64 FileHandle_Impl::getSize() const
199 LONGLONG bufend = std::max(LONGLONG(0), m_bufptr) + m_buflen;
200 return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend));
203 oslFileError FileHandle_Impl::setSize(sal_uInt64 uSize)
205 LARGE_INTEGER nDstPos; nDstPos.QuadPart = sal::static_int_cast< LONGLONG >(uSize);
206 if (!::SetFilePointerEx(m_hFile, nDstPos, nullptr, FILE_BEGIN))
207 return oslTranslateFileError(GetLastError());
209 if (!::SetEndOfFile(m_hFile))
210 return oslTranslateFileError(GetLastError());
211 m_size = uSize;
213 nDstPos.QuadPart = m_offset;
214 if (!::SetFilePointerEx(m_hFile, nDstPos, nullptr, FILE_BEGIN))
215 return oslTranslateFileError(GetLastError());
217 return osl_File_E_None;
220 oslFileError FileHandle_Impl::readAt(
221 LONGLONG nOffset,
222 void * pBuffer,
223 DWORD nBytesRequested,
224 sal_uInt64 * pBytesRead)
226 SAL_WARN_IF(!(m_state & STATE_SEEKABLE), "sal.osl", "FileHandle_Impl::readAt(): not seekable");
227 if (!(m_state & STATE_SEEKABLE))
228 return osl_File_E_SPIPE;
230 SAL_WARN_IF(!(m_state & STATE_READABLE), "sal.osl", "FileHandle_Impl::readAt(): not readable");
231 if (!(m_state & STATE_READABLE))
232 return osl_File_E_BADF;
234 if (nOffset != m_offset)
236 LARGE_INTEGER liOffset; liOffset.QuadPart = nOffset;
237 if (!::SetFilePointerEx(m_hFile, liOffset, nullptr, FILE_BEGIN))
238 return oslTranslateFileError(GetLastError());
239 m_offset = nOffset;
242 DWORD dwDone = 0;
243 if (!::ReadFile(m_hFile, pBuffer, nBytesRequested, &dwDone, nullptr))
244 return oslTranslateFileError(GetLastError());
245 m_offset += dwDone;
247 *pBytesRead = dwDone;
248 return osl_File_E_None;
251 oslFileError FileHandle_Impl::writeAt(
252 LONGLONG nOffset,
253 void const * pBuffer,
254 DWORD nBytesToWrite,
255 sal_uInt64 * pBytesWritten)
257 SAL_WARN_IF(!(m_state & STATE_SEEKABLE), "sal.osl", "FileHandle_Impl::writeAt(): not seekable");
258 if (!(m_state & STATE_SEEKABLE))
259 return osl_File_E_SPIPE;
261 SAL_WARN_IF(!(m_state & STATE_WRITEABLE), "sal.osl", "FileHandle_Impl::writeAt(): not writeable");
262 if (!(m_state & STATE_WRITEABLE))
263 return osl_File_E_BADF;
265 if (nOffset != m_offset)
267 LARGE_INTEGER liOffset; liOffset.QuadPart = nOffset;
268 if (!::SetFilePointerEx (m_hFile, liOffset, nullptr, FILE_BEGIN))
269 return oslTranslateFileError(GetLastError());
270 m_offset = nOffset;
273 DWORD dwDone = 0;
274 if (!::WriteFile(m_hFile, pBuffer, nBytesToWrite, &dwDone, nullptr))
275 return oslTranslateFileError(GetLastError());
276 m_offset += dwDone;
278 m_size = std::max(m_size, sal::static_int_cast< sal_uInt64 >(m_offset));
280 *pBytesWritten = dwDone;
281 return osl_File_E_None;
284 oslFileError FileHandle_Impl::readFileAt(
285 LONGLONG nOffset,
286 void * pBuffer,
287 sal_uInt64 uBytesRequested,
288 sal_uInt64 * pBytesRead)
290 static sal_uInt64 const g_limit_dword = std::numeric_limits< DWORD >::max();
291 if (g_limit_dword < uBytesRequested)
292 return osl_File_E_OVERFLOW;
293 DWORD nBytesRequested = sal::static_int_cast< DWORD >(uBytesRequested);
295 if ((m_state & STATE_SEEKABLE) == 0)
297 // not seekable (pipe)
298 DWORD dwDone = 0;
299 if (!::ReadFile(m_hFile, pBuffer, nBytesRequested, &dwDone, nullptr))
300 return oslTranslateFileError(GetLastError());
301 *pBytesRead = dwDone;
302 return osl_File_E_None;
304 else if (!m_buffer)
306 // not buffered
307 return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
309 else
311 sal_uInt8 * buffer = static_cast< sal_uInt8* >(pBuffer);
312 for (*pBytesRead = 0; nBytesRequested > 0;)
314 LONGLONG const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
315 SIZE_T const bufpos = (nOffset % m_bufsiz);
317 if (bufptr != m_bufptr)
319 // flush current buffer
320 oslFileError result = syncFile();
321 if (result != osl_File_E_None)
322 return result;
323 m_bufptr = -1;
324 m_buflen = 0;
326 if (nBytesRequested >= m_bufsiz)
328 // buffer too small, read through from file
329 sal_uInt64 uDone = 0;
330 result = readAt (nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone);
331 if (result != osl_File_E_None)
332 return result;
334 nBytesRequested -= sal::static_int_cast< DWORD >(uDone);
335 *pBytesRead += uDone;
336 return osl_File_E_None;
339 // update buffer (pointer)
340 sal_uInt64 uDone = 0;
341 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
342 if (result != osl_File_E_None)
343 return result;
344 m_bufptr = bufptr;
345 m_buflen = sal::static_int_cast< SIZE_T >(uDone);
347 if (bufpos >= m_buflen)
349 // end of file
350 return osl_File_E_None;
353 SIZE_T const bytes = std::min(m_buflen - bufpos, static_cast<SIZE_T>(nBytesRequested));
354 memcpy(&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes);
355 nBytesRequested -= bytes;
356 *pBytesRead += bytes;
357 nOffset += bytes;
359 return osl_File_E_None;
363 oslFileError FileHandle_Impl::writeFileAt(
364 LONGLONG nOffset,
365 void const * pBuffer,
366 sal_uInt64 uBytesToWrite,
367 sal_uInt64 * pBytesWritten)
369 static sal_uInt64 const g_limit_dword = std::numeric_limits< DWORD >::max();
370 if (g_limit_dword < uBytesToWrite)
371 return osl_File_E_OVERFLOW;
372 DWORD nBytesToWrite = sal::static_int_cast< DWORD >(uBytesToWrite);
374 if ((m_state & STATE_SEEKABLE) == 0)
376 // not seekable (pipe)
377 DWORD dwDone = 0;
378 if (!::WriteFile(m_hFile, pBuffer, nBytesToWrite, &dwDone, nullptr))
379 return oslTranslateFileError(GetLastError());
380 *pBytesWritten = dwDone;
381 return osl_File_E_None;
383 else if (!m_buffer)
385 // not buffered
386 return writeAt(nOffset, pBuffer, nBytesToWrite, pBytesWritten);
388 else
390 sal_uInt8 const * buffer = static_cast< sal_uInt8 const* >(pBuffer);
391 for (*pBytesWritten = 0; nBytesToWrite > 0;)
393 LONGLONG const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
394 SIZE_T const bufpos = (nOffset % m_bufsiz);
395 if (bufptr != m_bufptr)
397 // flush current buffer
398 oslFileError result = syncFile();
399 if (result != osl_File_E_None)
400 return result;
401 m_bufptr = -1;
402 m_buflen = 0;
404 if (nBytesToWrite >= m_bufsiz)
406 // buffer too small, write through to file
407 sal_uInt64 uDone = 0;
408 result = writeAt(nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone);
409 if (result != osl_File_E_None)
410 return result;
411 if (uDone != nBytesToWrite)
412 return osl_File_E_IO;
414 nBytesToWrite -= sal::static_int_cast< DWORD >(uDone);
415 *pBytesWritten += uDone;
416 return osl_File_E_None;
419 // update buffer (pointer)
420 sal_uInt64 uDone = 0;
421 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
422 if (result != osl_File_E_None)
423 return result;
424 m_bufptr = bufptr;
425 m_buflen = sal::static_int_cast< SIZE_T >(uDone);
428 SIZE_T const bytes = std::min(m_bufsiz - bufpos, static_cast<SIZE_T>(nBytesToWrite));
429 memcpy(&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes);
430 nBytesToWrite -= bytes;
431 *pBytesWritten += bytes;
432 nOffset += bytes;
434 m_buflen = std::max(m_buflen, bufpos + bytes);
435 m_state |= STATE_MODIFIED;
437 return osl_File_E_None;
441 oslFileError FileHandle_Impl::readLineAt(
442 LONGLONG nOffset,
443 sal_Sequence ** ppSequence,
444 sal_uInt64 * pBytesRead)
446 oslFileError result = osl_File_E_None;
448 LONGLONG bufptr = (nOffset / m_bufsiz) * m_bufsiz;
449 if (bufptr != m_bufptr)
451 /* flush current buffer */
452 result = syncFile();
453 if (result != osl_File_E_None)
454 return result;
456 /* update buffer (pointer) */
457 sal_uInt64 uDone = 0;
458 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
459 if (result != osl_File_E_None)
460 return result;
462 m_bufptr = bufptr;
463 m_buflen = sal::static_int_cast< SIZE_T >(uDone);
466 static int const LINE_STATE_BEGIN = 0;
467 static int const LINE_STATE_CR = 1;
468 static int const LINE_STATE_LF = 2;
470 SIZE_T bufpos = sal::static_int_cast< SIZE_T >(nOffset - m_bufptr), curpos = bufpos, dstpos = 0;
471 int state = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN;
473 for (; state != LINE_STATE_LF;)
475 if (curpos >= m_buflen)
477 /* buffer examined */
478 if (curpos > bufpos) // actually, curpos can't become less than bufpos, so != could do
480 /* flush buffer to sequence */
481 result = writeSequence_Impl(
482 ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos);
483 if (result != osl_File_E_None)
484 return result;
485 *pBytesRead += curpos - bufpos;
486 nOffset += curpos - bufpos;
489 bufptr = nOffset / m_bufsiz * m_bufsiz;
490 if (bufptr != m_bufptr)
492 /* update buffer (pointer) */
493 sal_uInt64 uDone = 0;
494 result = readAt(bufptr, m_buffer, m_bufsiz, &uDone);
495 if (result != osl_File_E_None)
496 return result;
497 m_bufptr = bufptr;
498 m_buflen = sal::static_int_cast< SIZE_T >(uDone);
501 bufpos = sal::static_int_cast< SIZE_T >(nOffset - m_bufptr);
502 curpos = bufpos;
503 if (bufpos >= m_buflen)
504 break;
506 switch (state)
508 case LINE_STATE_CR:
509 state = LINE_STATE_LF;
510 switch (m_buffer[curpos])
512 case 0x0A: /* CRLF */
513 /* eat current char */
514 curpos++;
515 break;
516 default: /* single CR */
517 /* keep current char */
518 break;
520 break;
521 default:
522 /* determine next state */
523 switch (m_buffer[curpos])
525 case 0x0A: /* single LF */
526 state = LINE_STATE_LF;
527 break;
528 case 0x0D: /* CR */
529 state = LINE_STATE_CR;
530 break;
531 default: /* advance to next char */
532 curpos++;
533 break;
535 if (state != LINE_STATE_BEGIN)
537 /* store (and eat) the newline char */
538 m_buffer[curpos] = 0x0A;
539 curpos++;
541 /* flush buffer to sequence */
542 result = writeSequence_Impl(
543 ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1);
544 if (result != osl_File_E_None)
545 return result;
546 *pBytesRead += curpos - bufpos;
547 nOffset += curpos - bufpos;
549 break;
553 result = writeSequence_Impl(ppSequence, &dstpos, nullptr, 0);
554 if (result != osl_File_E_None)
555 return result;
556 if (dstpos > 0)
557 return osl_File_E_None;
558 if (bufpos >= m_buflen)
559 return osl_File_E_AGAIN;
560 return osl_File_E_None;
563 oslFileError FileHandle_Impl::writeSequence_Impl(
564 sal_Sequence ** ppSequence,
565 SIZE_T * pnOffset,
566 const void * pBuffer,
567 SIZE_T nBytes)
569 sal_Int32 nElements = *pnOffset + nBytes;
570 if (!*ppSequence)
572 /* construct sequence */
573 rtl_byte_sequence_constructNoDefault(ppSequence, nElements);
575 else if (nElements != (*ppSequence)->nElements)
577 /* resize sequence */
578 rtl_byte_sequence_realloc(ppSequence, nElements);
580 if (*ppSequence)
582 /* fill sequence */
583 memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes);
584 *pnOffset += nBytes;
586 return (*ppSequence) ? osl_File_E_None : osl_File_E_NOMEM;
589 oslFileError FileHandle_Impl::syncFile()
591 oslFileError result = osl_File_E_None;
592 if (m_state & STATE_MODIFIED)
594 sal_uInt64 uDone = 0;
595 result = writeAt(m_bufptr, m_buffer, m_buflen, &uDone);
596 if (result != osl_File_E_None)
597 return result;
598 if (uDone != m_buflen)
599 return osl_File_E_IO;
600 m_state &= ~STATE_MODIFIED;
602 return result;
605 extern "C" oslFileHandle osl_createFileHandleFromOSHandle(
606 HANDLE hFile,
607 sal_uInt32 uFlags)
609 if (!IsValidHandle(hFile))
610 return nullptr; // EINVAL
612 FileHandle_Impl * pImpl = new FileHandle_Impl(hFile);
614 /* check for regular file */
615 if (GetFileType(hFile) == FILE_TYPE_DISK)
617 /* mark seekable */
618 pImpl->m_state |= FileHandle_Impl::STATE_SEEKABLE;
620 /* init current size */
621 LARGE_INTEGER uSize = { { 0, 0 } };
622 (void) ::GetFileSizeEx(hFile, &uSize);
623 pImpl->m_size = (sal::static_int_cast<sal_uInt64>(uSize.HighPart) << 32) + uSize.LowPart;
626 if (!(uFlags & osl_File_OpenFlag_Read))
627 pImpl->m_state &= ~FileHandle_Impl::STATE_READABLE;
628 if (!(uFlags & osl_File_OpenFlag_Write))
629 pImpl->m_state &= ~FileHandle_Impl::STATE_WRITEABLE;
631 SAL_WARN_IF(
632 !((uFlags & osl_File_OpenFlag_Read) || (uFlags & osl_File_OpenFlag_Write)),
633 "sal.osl",
634 "osl_createFileHandleFromOSHandle(): missing read/write access flags");
635 return static_cast<oslFileHandle>(pImpl);
638 oslFileError SAL_CALL osl_openFile(
639 rtl_uString * strPath,
640 oslFileHandle * pHandle,
641 sal_uInt32 uFlags)
643 rtl_uString * strSysPath = nullptr;
644 oslFileError result = osl_getSystemPathFromFileURL_(strPath, &strSysPath, false);
645 if (result != osl_File_E_None)
646 return result;
648 DWORD dwAccess = GENERIC_READ, dwShare = FILE_SHARE_READ, dwCreation = 0;
650 if (uFlags & osl_File_OpenFlag_Write)
651 dwAccess |= GENERIC_WRITE;
652 else
653 dwShare |= FILE_SHARE_WRITE;
655 if (uFlags & osl_File_OpenFlag_NoLock)
656 dwShare |= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
658 if (uFlags & osl_File_OpenFlag_Create)
659 dwCreation |= CREATE_NEW;
660 else
661 dwCreation |= OPEN_EXISTING;
663 HANDLE hFile = CreateFileW(
664 o3tl::toW(rtl_uString_getStr(strSysPath)),
665 dwAccess, dwShare, nullptr, dwCreation, 0, nullptr);
667 // @@@ ERROR HANDLING @@@
668 if (!IsValidHandle(hFile))
669 result = oslTranslateFileError(GetLastError());
671 *pHandle = osl_createFileHandleFromOSHandle(hFile, uFlags | osl_File_OpenFlag_Read);
673 rtl_uString_release(strSysPath);
674 return result;
677 oslFileError SAL_CALL osl_syncFile(oslFileHandle Handle)
679 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
680 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile))
681 return osl_File_E_INVAL;
683 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
685 oslFileError result = pImpl->syncFile();
686 if (result != osl_File_E_None)
687 return result;
689 if (!FlushFileBuffers(pImpl->m_hFile))
690 return oslTranslateFileError(GetLastError());
692 return osl_File_E_None;
695 oslFileError SAL_CALL osl_closeFile(oslFileHandle Handle)
697 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
698 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile))
699 return osl_File_E_INVAL;
701 ::EnterCriticalSection(&(pImpl->m_mutex));
703 oslFileError result = pImpl->syncFile();
704 if (result != osl_File_E_None)
706 /* ignore double failure */
707 (void)::CloseHandle(pImpl->m_hFile);
709 else if (!::CloseHandle(pImpl->m_hFile))
711 /* translate error code */
712 result = oslTranslateFileError(GetLastError());
715 ::LeaveCriticalSection(&(pImpl->m_mutex));
716 delete pImpl;
717 return result;
720 namespace {
722 // coverity[result_independent_of_operands] - crossplatform requirement
723 template<typename T> bool exceedsMaxSIZE_T(T n)
724 { return n > std::numeric_limits< SIZE_T >::max(); }
728 oslFileError SAL_CALL osl_mapFile(
729 oslFileHandle Handle,
730 void** ppAddr,
731 sal_uInt64 uLength,
732 sal_uInt64 uOffset,
733 sal_uInt32 uFlags)
735 struct FileMapping
737 HANDLE m_handle;
739 explicit FileMapping(HANDLE hMap)
740 : m_handle(hMap)
743 ~FileMapping()
745 (void)::CloseHandle(m_handle);
749 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
750 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!ppAddr))
751 return osl_File_E_INVAL;
752 *ppAddr = nullptr;
754 if (exceedsMaxSIZE_T(uLength))
755 return osl_File_E_OVERFLOW;
756 SIZE_T const nLength = sal::static_int_cast< SIZE_T >(uLength);
758 FileMapping aMap(::CreateFileMappingW(pImpl->m_hFile, nullptr, SEC_COMMIT | PAGE_READONLY, 0, 0, nullptr));
759 if (!IsValidHandle(aMap.m_handle))
760 return oslTranslateFileError(GetLastError());
762 DWORD const dwOffsetHi = sal::static_int_cast<DWORD>(uOffset >> 32);
763 DWORD const dwOffsetLo = sal::static_int_cast<DWORD>(uOffset & 0xFFFFFFFF);
765 *ppAddr = ::MapViewOfFile(aMap.m_handle, FILE_MAP_READ, dwOffsetHi, dwOffsetLo, nLength);
766 if (!*ppAddr)
767 return oslTranslateFileError(GetLastError());
769 if (uFlags & osl_File_MapFlag_RandomAccess)
771 // Determine memory pagesize.
772 SYSTEM_INFO info;
773 ::GetSystemInfo(&info);
774 DWORD const dwPageSize = info.dwPageSize;
777 * Pagein, touching first byte of each memory page.
778 * Note: volatile disables optimizing the loop away.
780 BYTE * pData(static_cast<BYTE*>(*ppAddr));
781 SIZE_T nSize(nLength);
783 volatile BYTE c = 0;
784 while (nSize > dwPageSize)
786 c ^= pData[0];
787 pData += dwPageSize;
788 nSize -= dwPageSize;
790 if (nSize > 0)
792 c ^= pData[0];
795 return osl_File_E_None;
798 oslFileError SAL_CALL osl_unmapFile(void* pAddr, sal_uInt64 /* uLength */)
800 if (!pAddr)
801 return osl_File_E_INVAL;
803 if (!::UnmapViewOfFile(pAddr))
804 return oslTranslateFileError(GetLastError());
806 return osl_File_E_None;
809 oslFileError SAL_CALL osl_unmapMappedFile(oslFileHandle /* Handle */, void* pAddr, sal_uInt64 uLength)
811 return osl_unmapFile(pAddr, uLength);
814 oslFileError
815 SAL_CALL osl_readLine(
816 oslFileHandle Handle,
817 sal_Sequence ** ppSequence)
819 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
820 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!ppSequence))
821 return osl_File_E_INVAL;
822 sal_uInt64 uBytesRead = 0;
824 // read at current filepos; filepos += uBytesRead;
825 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
826 oslFileError result = pImpl->readLineAt(
827 pImpl->m_filepos, ppSequence, &uBytesRead);
828 if (result == osl_File_E_None)
829 pImpl->m_filepos += uBytesRead;
830 return result;
833 oslFileError SAL_CALL osl_readFile(
834 oslFileHandle Handle,
835 void * pBuffer,
836 sal_uInt64 uBytesRequested,
837 sal_uInt64 * pBytesRead)
839 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
840 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pBuffer) || (!pBytesRead))
841 return osl_File_E_INVAL;
843 // read at current filepos; filepos += *pBytesRead;
844 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
845 oslFileError result = pImpl->readFileAt(
846 pImpl->m_filepos, pBuffer, uBytesRequested, pBytesRead);
847 if (result == osl_File_E_None)
848 pImpl->m_filepos += *pBytesRead;
849 return result;
852 oslFileError SAL_CALL osl_writeFile(
853 oslFileHandle Handle,
854 const void * pBuffer,
855 sal_uInt64 uBytesToWrite,
856 sal_uInt64 * pBytesWritten)
858 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
860 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pBuffer) || (!pBytesWritten))
861 return osl_File_E_INVAL;
863 // write at current filepos; filepos += *pBytesWritten;
864 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
865 oslFileError result = pImpl->writeFileAt(
866 pImpl->m_filepos, pBuffer, uBytesToWrite, pBytesWritten);
867 if (result == osl_File_E_None)
868 pImpl->m_filepos += *pBytesWritten;
869 return result;
872 LONGLONG const g_limit_longlong = std::numeric_limits< LONGLONG >::max();
874 namespace {
876 // coverity[result_independent_of_operands] - crossplatform requirement
877 template<typename T> bool exceedsMaxLONGLONG(T n)
878 { return n > g_limit_longlong; }
880 template<typename T> bool exceedsMinLONGLONG(T n)
881 { return n < std::numeric_limits<LONGLONG>::min(); }
885 oslFileError SAL_CALL osl_readFileAt(
886 oslFileHandle Handle,
887 sal_uInt64 uOffset,
888 void* pBuffer,
889 sal_uInt64 uBytesRequested,
890 sal_uInt64* pBytesRead)
892 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
894 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pBuffer) || (!pBytesRead))
895 return osl_File_E_INVAL;
896 if ((pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE) == 0)
897 return osl_File_E_SPIPE;
899 if (exceedsMaxLONGLONG(uOffset))
900 return osl_File_E_OVERFLOW;
901 LONGLONG const nOffset = sal::static_int_cast< LONGLONG >(uOffset);
903 // read at specified fileptr
904 FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
905 return pImpl->readFileAt(nOffset, pBuffer, uBytesRequested, pBytesRead);
908 oslFileError SAL_CALL osl_writeFileAt(
909 oslFileHandle Handle,
910 sal_uInt64 uOffset,
911 const void* pBuffer,
912 sal_uInt64 uBytesToWrite,
913 sal_uInt64* pBytesWritten)
915 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
917 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pBuffer) || (!pBytesWritten))
918 return osl_File_E_INVAL;
919 if ((pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE) == 0)
920 return osl_File_E_SPIPE;
922 if (exceedsMaxLONGLONG(uOffset))
923 return osl_File_E_OVERFLOW;
924 LONGLONG const nOffset = sal::static_int_cast< LONGLONG >(uOffset);
926 // write at specified fileptr
927 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
928 return pImpl->writeFileAt(nOffset, pBuffer, uBytesToWrite, pBytesWritten);
931 oslFileError SAL_CALL osl_isEndOfFile(oslFileHandle Handle, sal_Bool *pIsEOF)
933 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
935 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pIsEOF))
936 return osl_File_E_INVAL;
938 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
939 *pIsEOF = (pImpl->getPos() == pImpl->getSize());
940 return osl_File_E_None;
943 oslFileError SAL_CALL osl_getFilePos(oslFileHandle Handle, sal_uInt64 *pPos)
945 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
946 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pPos))
947 return osl_File_E_INVAL;
949 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
950 *pPos = pImpl->getPos();
951 return osl_File_E_None;
954 oslFileError SAL_CALL osl_setFilePos(oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset)
956 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
957 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile))
958 return osl_File_E_INVAL;
960 if (exceedsMaxLONGLONG(uOffset) || exceedsMinLONGLONG(uOffset))
961 return osl_File_E_OVERFLOW;
962 LONGLONG nPos = 0, nOffset = sal::static_int_cast< LONGLONG >(uOffset);
964 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
965 switch (uHow)
967 case osl_Pos_Absolut:
968 if (nOffset < 0)
969 return osl_File_E_INVAL;
970 break;
972 case osl_Pos_Current:
973 nPos = sal::static_int_cast< LONGLONG >(pImpl->getPos());
974 if ((nOffset < 0) && (nPos < -1*nOffset))
975 return osl_File_E_INVAL;
976 assert(nPos >= 0);
977 if (nOffset > g_limit_longlong - nPos)
978 return osl_File_E_OVERFLOW;
979 break;
981 case osl_Pos_End:
982 nPos = sal::static_int_cast< LONGLONG >(pImpl->getSize());
983 if ((nOffset < 0) && (nPos < -1*nOffset))
984 return osl_File_E_INVAL;
985 assert(nPos >= 0);
986 if (nOffset > g_limit_longlong - nPos)
987 return osl_File_E_OVERFLOW;
988 break;
990 default:
991 return osl_File_E_INVAL;
994 return pImpl->setPos(nPos + nOffset);
997 oslFileError SAL_CALL osl_getFileSize(oslFileHandle Handle, sal_uInt64 *pSize)
999 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
1001 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile) || (!pSize))
1002 return osl_File_E_INVAL;
1004 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1005 *pSize = pImpl->getSize();
1006 return osl_File_E_None;
1009 oslFileError SAL_CALL osl_setFileSize(oslFileHandle Handle, sal_uInt64 uSize)
1011 FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
1013 if ((!pImpl) || !IsValidHandle(pImpl->m_hFile))
1014 return osl_File_E_INVAL;
1015 if ((pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE) == 0)
1016 return osl_File_E_BADF;
1018 if (exceedsMaxLONGLONG(uSize))
1019 return osl_File_E_OVERFLOW;
1021 FileHandle_Impl::Guard lock(&(pImpl->m_mutex));
1022 oslFileError result = pImpl->syncFile();
1023 if (result != osl_File_E_None)
1024 return result;
1025 pImpl->m_bufptr = -1;
1026 pImpl->m_buflen = 0;
1028 return pImpl->setSize(uSize);
1031 oslFileError SAL_CALL osl_removeFile(rtl_uString* strPath)
1033 rtl_uString *strSysPath = nullptr;
1034 oslFileError error = osl_getSystemPathFromFileURL_(strPath, &strSysPath, false);
1036 if (error == osl_File_E_None)
1038 if (DeleteFileW(o3tl::toW(rtl_uString_getStr(strSysPath))))
1039 error = osl_File_E_None;
1040 else
1041 error = oslTranslateFileError(GetLastError());
1043 rtl_uString_release(strSysPath);
1045 return error;
1048 oslFileError SAL_CALL osl_copyFile(rtl_uString* strPath, rtl_uString *strDestPath)
1050 rtl_uString *strSysPath = nullptr, *strSysDestPath = nullptr;
1051 oslFileError error = osl_getSystemPathFromFileURL_(strPath, &strSysPath, false);
1053 if (error == osl_File_E_None)
1054 error = osl_getSystemPathFromFileURL_(strDestPath, &strSysDestPath, false);
1056 if (error == osl_File_E_None)
1058 LPCWSTR src = o3tl::toW(rtl_uString_getStr(strSysPath));
1059 LPCWSTR dst = o3tl::toW(rtl_uString_getStr(strSysDestPath));
1061 if (CopyFileW(src, dst, FALSE))
1062 error = osl_File_E_None;
1063 else
1064 error = oslTranslateFileError(GetLastError());
1067 if (strSysPath)
1068 rtl_uString_release(strSysPath);
1069 if (strSysDestPath)
1070 rtl_uString_release(strSysDestPath);
1072 return error;
1075 oslFileError SAL_CALL osl_moveFile(rtl_uString* strPath, rtl_uString *strDestPath)
1077 rtl_uString *strSysPath = nullptr, *strSysDestPath = nullptr;
1078 oslFileError error = osl_getSystemPathFromFileURL_(strPath, &strSysPath, false);
1080 if (error == osl_File_E_None)
1081 error = osl_getSystemPathFromFileURL_(strDestPath, &strSysDestPath, false);
1083 if (error == osl_File_E_None)
1085 LPCWSTR src = o3tl::toW(rtl_uString_getStr(strSysPath));
1086 LPCWSTR dst = o3tl::toW(rtl_uString_getStr(strSysDestPath));
1088 if (MoveFileExW(src, dst, MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH | MOVEFILE_REPLACE_EXISTING))
1089 error = osl_File_E_None;
1090 else
1091 error = oslTranslateFileError(GetLastError());
1094 if (strSysPath)
1095 rtl_uString_release(strSysPath);
1096 if (strSysDestPath)
1097 rtl_uString_release(strSysDestPath);
1099 return error;
1102 oslFileError SAL_CALL osl_replaceFile(rtl_uString* strPath, rtl_uString* strDestPath)
1104 rtl_uString *strSysPath = nullptr, *strSysDestPath = nullptr;
1105 oslFileError error = osl_getSystemPathFromFileURL_(strPath, &strSysPath, false);
1107 if (error == osl_File_E_None)
1108 error = osl_getSystemPathFromFileURL_(strDestPath, &strSysDestPath, false);
1110 if (error == osl_File_E_None)
1112 LPCWSTR src = o3tl::toW(rtl_uString_getStr(strSysPath));
1113 LPCWSTR dst = o3tl::toW(rtl_uString_getStr(strSysDestPath));
1115 if (!ReplaceFileW(dst, src, nullptr,
1116 REPLACEFILE_WRITE_THROUGH | REPLACEFILE_IGNORE_MERGE_ERRORS
1117 | REPLACEFILE_IGNORE_ACL_ERRORS,
1118 nullptr, nullptr))
1120 DWORD dwError = GetLastError();
1121 if (dwError == ERROR_FILE_NOT_FOUND) // no strDestPath file?
1122 error = osl_moveFile(strPath, strDestPath);
1123 else
1124 error = oslTranslateFileError(dwError);
1128 if (strSysPath)
1129 rtl_uString_release(strSysPath);
1130 if (strSysDestPath)
1131 rtl_uString_release(strSysDestPath);
1133 return error;
1136 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */