summaryrefslogtreecommitdiff
path: root/sal/osl/w32/file.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sal/osl/w32/file.cxx')
-rw-r--r--sal/osl/w32/file.cxx1194
1 files changed, 1194 insertions, 0 deletions
diff --git a/sal/osl/w32/file.cxx b/sal/osl/w32/file.cxx
new file mode 100644
index 000000000000..7728189387cd
--- /dev/null
+++ b/sal/osl/w32/file.cxx
@@ -0,0 +1,1194 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sal.hxx"
+
+#define UNICODE
+#define _UNICODE
+#define _WIN32_WINNT 0x0500
+#include "systools/win32/uwinapi.h"
+
+#include "osl/file.hxx"
+
+#include "file_url.h"
+#include "file_error.h"
+
+#include "osl/diagnose.h"
+#include "rtl/alloc.h"
+#include "rtl/byteseq.h"
+#include "rtl/ustring.hxx"
+
+#include <stdio.h>
+#include <tchar.h>
+
+#ifdef __MINGW32__
+#include <wchar.h>
+#include <ctype.h>
+#endif
+
+#include <algorithm>
+#include <limits>
+
+#ifdef max /* conflict w/ std::numeric_limits<T>::max() */
+#undef max
+#endif
+#ifdef min
+#undef min
+#endif
+
+//##################################################################
+// File handle implementation
+//##################################################################
+struct FileHandle_Impl
+{
+ CRITICAL_SECTION m_mutex;
+ HANDLE m_hFile;
+
+ /** State
+ */
+ enum StateBits
+ {
+ STATE_SEEKABLE = 1, /* open() sets, iff regular file */
+ STATE_READABLE = 2, /* open() sets, read() requires */
+ STATE_WRITEABLE = 4, /* open() sets, write() requires */
+ STATE_MODIFIED = 8 /* write() sets, flush() resets */
+ };
+ int m_state;
+
+ sal_uInt64 m_size; /* file size */
+ LONGLONG m_offset; /* physical offset from begin of file */
+ LONGLONG m_filepos; /* logical offset from begin of file */
+
+ LONGLONG m_bufptr; /* buffer offset from begin of file */
+ SIZE_T m_buflen; /* buffer filled [0, m_bufsiz - 1] */
+
+ SIZE_T m_bufsiz;
+ sal_uInt8 * m_buffer;
+
+ explicit FileHandle_Impl (HANDLE hFile);
+ ~FileHandle_Impl();
+
+ static void* operator new(size_t n);
+ static void operator delete(void * p, size_t);
+ static SIZE_T getpagesize();
+
+ sal_uInt64 getPos() const;
+ oslFileError setPos (sal_uInt64 uPos);
+
+ sal_uInt64 getSize() const;
+ oslFileError setSize (sal_uInt64 uPos);
+
+ oslFileError readAt (
+ LONGLONG nOffset,
+ void * pBuffer,
+ DWORD nBytesRequested,
+ sal_uInt64 * pBytesRead);
+
+ oslFileError writeAt (
+ LONGLONG nOffset,
+ void const * pBuffer,
+ DWORD nBytesToWrite,
+ sal_uInt64 * pBytesWritten);
+
+ oslFileError readFileAt (
+ LONGLONG nOffset,
+ void * pBuffer,
+ sal_uInt64 uBytesRequested,
+ sal_uInt64 * pBytesRead);
+
+ oslFileError writeFileAt (
+ LONGLONG nOffset,
+ void const * pBuffer,
+ sal_uInt64 uBytesToWrite,
+ sal_uInt64 * pBytesWritten);
+
+ oslFileError readLineAt (
+ LONGLONG nOffset,
+ sal_Sequence ** ppSequence,
+ sal_uInt64 * pBytesRead);
+
+ oslFileError writeSequence_Impl (
+ sal_Sequence ** ppSequence,
+ SIZE_T * pnOffset,
+ const void * pBuffer,
+ SIZE_T nBytes);
+
+ oslFileError syncFile();
+
+ /** Buffer cache / allocator.
+ */
+ class Allocator
+ {
+ rtl_cache_type * m_cache;
+ SIZE_T m_bufsiz;
+
+ Allocator (Allocator const &);
+ Allocator & operator= (Allocator const &);
+
+ public:
+ static Allocator & get();
+
+ void allocate (sal_uInt8 ** ppBuffer, SIZE_T * pnSize);
+ void deallocate (sal_uInt8 * pBuffer);
+
+ protected:
+ Allocator();
+ ~Allocator();
+ };
+
+ /** Guard.
+ */
+ class Guard
+ {
+ LPCRITICAL_SECTION m_mutex;
+
+ public:
+ explicit Guard(LPCRITICAL_SECTION pMutex);
+ ~Guard();
+ };
+};
+
+FileHandle_Impl::Allocator &
+FileHandle_Impl::Allocator::get()
+{
+ static Allocator g_aBufferAllocator;
+ return g_aBufferAllocator;
+}
+
+FileHandle_Impl::Allocator::Allocator()
+ : m_cache (0),
+ m_bufsiz (0)
+{
+ SIZE_T const pagesize = FileHandle_Impl::getpagesize();
+ m_cache = rtl_cache_create (
+ "osl_file_buffer_cache", pagesize, 0, 0, 0, 0, 0, 0, 0);
+ if (0 != m_cache)
+ m_bufsiz = pagesize;
+}
+
+FileHandle_Impl::Allocator::~Allocator()
+{
+ rtl_cache_destroy(m_cache), m_cache = 0;
+}
+
+void FileHandle_Impl::Allocator::allocate (sal_uInt8 ** ppBuffer, SIZE_T * pnSize)
+{
+ OSL_PRECOND((0 != ppBuffer) && (0 != pnSize), "FileHandle_Impl::Allocator::allocate(): contract violation");
+ *ppBuffer = static_cast< sal_uInt8* >(rtl_cache_alloc(m_cache)), *pnSize = m_bufsiz;
+}
+
+void FileHandle_Impl::Allocator::deallocate (sal_uInt8 * pBuffer)
+{
+ if (0 != pBuffer)
+ rtl_cache_free (m_cache, pBuffer);
+}
+
+FileHandle_Impl::Guard::Guard(LPCRITICAL_SECTION pMutex)
+ : m_mutex (pMutex)
+{
+ OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::Guard(): null pointer.");
+ ::EnterCriticalSection (m_mutex);
+}
+FileHandle_Impl::Guard::~Guard()
+{
+ OSL_PRECOND (m_mutex != 0, "FileHandle_Impl::Guard::~Guard(): null pointer.");
+ ::LeaveCriticalSection (m_mutex);
+}
+
+FileHandle_Impl::FileHandle_Impl(HANDLE hFile)
+ : m_hFile (hFile),
+ m_state (STATE_READABLE | STATE_WRITEABLE),
+ m_size (0),
+ m_offset (0),
+ m_filepos (0),
+ m_bufptr (-1),
+ m_buflen (0),
+ m_bufsiz (0),
+ m_buffer (0)
+{
+ ::InitializeCriticalSection (&m_mutex);
+ Allocator::get().allocate (&m_buffer, &m_bufsiz);
+ if (m_buffer != 0)
+ memset (m_buffer, 0, m_bufsiz);
+}
+
+FileHandle_Impl::~FileHandle_Impl()
+{
+ Allocator::get().deallocate (m_buffer), m_buffer = 0;
+ ::DeleteCriticalSection (&m_mutex);
+}
+
+void * FileHandle_Impl::operator new(size_t n)
+{
+ return rtl_allocateMemory(n);
+}
+
+void FileHandle_Impl::operator delete(void * p, size_t)
+{
+ rtl_freeMemory(p);
+}
+
+SIZE_T FileHandle_Impl::getpagesize()
+{
+ SYSTEM_INFO info;
+ ::GetSystemInfo (&info);
+ return sal::static_int_cast< SIZE_T >(info.dwPageSize);
+}
+
+sal_uInt64 FileHandle_Impl::getPos() const
+{
+ return sal::static_int_cast< sal_uInt64 >(m_filepos);
+}
+
+oslFileError FileHandle_Impl::setPos (sal_uInt64 uPos)
+{
+ m_filepos = sal::static_int_cast< LONGLONG >(uPos);
+ return osl_File_E_None;
+}
+
+sal_uInt64 FileHandle_Impl::getSize() const
+{
+ LONGLONG bufend = std::max((LONGLONG)(0), m_bufptr) + m_buflen;
+ return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend));
+}
+
+oslFileError FileHandle_Impl::setSize (sal_uInt64 uSize)
+{
+ LARGE_INTEGER nDstPos; nDstPos.QuadPart = sal::static_int_cast< LONGLONG >(uSize);
+ if (!::SetFilePointerEx(m_hFile, nDstPos, 0, FILE_BEGIN))
+ return oslTranslateFileError( GetLastError() );
+
+ if (!::SetEndOfFile(m_hFile))
+ return oslTranslateFileError( GetLastError() );
+ m_size = uSize;
+
+ nDstPos.QuadPart = m_offset;
+ if (!::SetFilePointerEx(m_hFile, nDstPos, 0, FILE_BEGIN))
+ return oslTranslateFileError( GetLastError() );
+
+ return osl_File_E_None;
+}
+
+oslFileError FileHandle_Impl::readAt (
+ LONGLONG nOffset,
+ void * pBuffer,
+ DWORD nBytesRequested,
+ sal_uInt64 * pBytesRead)
+{
+ OSL_PRECOND(m_state & STATE_SEEKABLE, "FileHandle_Impl::readAt(): not seekable");
+ if (!(m_state & STATE_SEEKABLE))
+ return osl_File_E_SPIPE;
+
+ OSL_PRECOND(m_state & STATE_READABLE, "FileHandle_Impl::readAt(): not readable");
+ if (!(m_state & STATE_READABLE))
+ return osl_File_E_BADF;
+
+ if (nOffset != m_offset)
+ {
+ LARGE_INTEGER liOffset; liOffset.QuadPart = nOffset;
+ if (!::SetFilePointerEx(m_hFile, liOffset, 0, FILE_BEGIN))
+ return oslTranslateFileError( GetLastError() );
+ m_offset = nOffset;
+ }
+
+ DWORD dwDone = 0;
+ if (!::ReadFile(m_hFile, pBuffer, nBytesRequested, &dwDone, 0))
+ return oslTranslateFileError( GetLastError() );
+ m_offset += dwDone;
+
+ *pBytesRead = dwDone;
+ return osl_File_E_None;
+}
+
+oslFileError FileHandle_Impl::writeAt (
+ LONGLONG nOffset,
+ void const * pBuffer,
+ DWORD nBytesToWrite,
+ sal_uInt64 * pBytesWritten)
+{
+ OSL_PRECOND(m_state & STATE_SEEKABLE, "FileHandle_Impl::writeAt(): not seekable");
+ if (!(m_state & STATE_SEEKABLE))
+ return osl_File_E_SPIPE;
+
+ OSL_PRECOND(m_state & STATE_WRITEABLE, "FileHandle_Impl::writeAt(): not writeable");
+ if (!(m_state & STATE_WRITEABLE))
+ return osl_File_E_BADF;
+
+ if (nOffset != m_offset)
+ {
+ LARGE_INTEGER liOffset; liOffset.QuadPart = nOffset;
+ if (!::SetFilePointerEx (m_hFile, liOffset, 0, FILE_BEGIN))
+ return oslTranslateFileError( GetLastError() );
+ m_offset = nOffset;
+ }
+
+ DWORD dwDone = 0;
+ if (!::WriteFile(m_hFile, pBuffer, nBytesToWrite, &dwDone, 0))
+ return oslTranslateFileError( GetLastError() );
+ m_offset += dwDone;
+
+ m_size = std::max(m_size, sal::static_int_cast< sal_uInt64 >(m_offset));
+
+ *pBytesWritten = dwDone;
+ return osl_File_E_None;
+}
+
+oslFileError FileHandle_Impl::readFileAt (
+ LONGLONG nOffset,
+ void * pBuffer,
+ sal_uInt64 uBytesRequested,
+ sal_uInt64 * pBytesRead)
+{
+ static sal_uInt64 const g_limit_dword = std::numeric_limits< DWORD >::max();
+ if (g_limit_dword < uBytesRequested)
+ return osl_File_E_OVERFLOW;
+ DWORD nBytesRequested = sal::static_int_cast< DWORD >(uBytesRequested);
+
+ if (0 == (m_state & STATE_SEEKABLE))
+ {
+ // not seekable (pipe)
+ DWORD dwDone = 0;
+ if (!::ReadFile(m_hFile, pBuffer, nBytesRequested, &dwDone, 0))
+ return oslTranslateFileError( GetLastError() );
+ *pBytesRead = dwDone;
+ return osl_File_E_None;
+ }
+ else if (0 == m_buffer)
+ {
+ // not buffered
+ return readAt (nOffset, pBuffer, nBytesRequested, pBytesRead);
+ }
+ else
+ {
+ sal_uInt8 * buffer = static_cast< sal_uInt8* >(pBuffer);
+ for (*pBytesRead = 0; nBytesRequested > 0; )
+ {
+ LONGLONG const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
+ SIZE_T const bufpos = (nOffset % m_bufsiz);
+
+ if (bufptr != m_bufptr)
+ {
+ // flush current buffer
+ oslFileError result = syncFile();
+ if (result != osl_File_E_None)
+ return (result);
+ m_bufptr = -1, m_buflen = 0;
+
+ if (nBytesRequested >= m_bufsiz)
+ {
+ // buffer too small, read through from file
+ sal_uInt64 uDone = 0;
+ result = readAt (nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone);
+ if (result != osl_File_E_None)
+ return (result);
+
+ nBytesRequested -= sal::static_int_cast< DWORD >(uDone), *pBytesRead += uDone;
+ return osl_File_E_None;
+ }
+
+ // update buffer (pointer)
+ sal_uInt64 uDone = 0;
+ result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
+ if (result != osl_File_E_None)
+ return (result);
+ m_bufptr = bufptr, m_buflen = sal::static_int_cast< SIZE_T >(uDone);
+ }
+ if (bufpos >= m_buflen)
+ {
+ // end of file
+ return osl_File_E_None;
+ }
+
+ SIZE_T const bytes = std::min(m_buflen - bufpos, nBytesRequested);
+ memcpy (&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes);
+ nBytesRequested -= bytes, *pBytesRead += bytes, nOffset += bytes;
+ }
+ return osl_File_E_None;
+ }
+}
+
+oslFileError FileHandle_Impl::writeFileAt (
+ LONGLONG nOffset,
+ void const * pBuffer,
+ sal_uInt64 uBytesToWrite,
+ sal_uInt64 * pBytesWritten)
+{
+ static sal_uInt64 const g_limit_dword = std::numeric_limits< DWORD >::max();
+ if (g_limit_dword < uBytesToWrite)
+ return osl_File_E_OVERFLOW;
+ DWORD nBytesToWrite = sal::static_int_cast< DWORD >(uBytesToWrite);
+
+ if (0 == (m_state & STATE_SEEKABLE))
+ {
+ // not seekable (pipe)
+ DWORD dwDone = 0;
+ if (!::WriteFile(m_hFile, pBuffer, nBytesToWrite, &dwDone, 0))
+ return oslTranslateFileError( GetLastError() );
+ *pBytesWritten = dwDone;
+ return osl_File_E_None;
+ }
+ else if (0 == m_buffer)
+ {
+ // not buffered
+ return writeAt(nOffset, pBuffer, nBytesToWrite, pBytesWritten);
+ }
+ else
+ {
+ sal_uInt8 const * buffer = static_cast< sal_uInt8 const* >(pBuffer);
+ for (*pBytesWritten = 0; nBytesToWrite > 0; )
+ {
+ LONGLONG const bufptr = (nOffset / m_bufsiz) * m_bufsiz;
+ SIZE_T const bufpos = (nOffset % m_bufsiz);
+ if (bufptr != m_bufptr)
+ {
+ // flush current buffer
+ oslFileError result = syncFile();
+ if (result != osl_File_E_None)
+ return (result);
+ m_bufptr = -1, m_buflen = 0;
+
+ if (nBytesToWrite >= m_bufsiz)
+ {
+ // buffer too small, write through to file
+ sal_uInt64 uDone = 0;
+ result = writeAt (nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone);
+ if (result != osl_File_E_None)
+ return (result);
+ if (uDone != nBytesToWrite)
+ return osl_File_E_IO;
+
+ nBytesToWrite -= sal::static_int_cast< DWORD >(uDone), *pBytesWritten += uDone;
+ return osl_File_E_None;
+ }
+
+ // update buffer (pointer)
+ sal_uInt64 uDone = 0;
+ result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
+ if (result != osl_File_E_None)
+ return (result);
+ m_bufptr = bufptr, m_buflen = sal::static_int_cast< SIZE_T >(uDone);
+ }
+
+ SIZE_T const bytes = std::min(m_bufsiz - bufpos, nBytesToWrite);
+ memcpy (&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes);
+ nBytesToWrite -= bytes, *pBytesWritten += bytes, nOffset += bytes;
+
+ m_buflen = std::max(m_buflen, bufpos + bytes);
+ m_state |= STATE_MODIFIED;
+ }
+ return osl_File_E_None;
+ }
+}
+
+oslFileError FileHandle_Impl::readLineAt (
+ LONGLONG nOffset,
+ sal_Sequence ** ppSequence,
+ sal_uInt64 * pBytesRead)
+{
+ oslFileError result = osl_File_E_None;
+
+ LONGLONG bufptr = (nOffset / m_bufsiz) * m_bufsiz;
+ if (bufptr != m_bufptr)
+ {
+ /* flush current buffer */
+ result = syncFile();
+ if (result != osl_File_E_None)
+ return (result);
+
+ /* update buffer (pointer) */
+ sal_uInt64 uDone = 0;
+ result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
+ if (result != osl_File_E_None)
+ return (result);
+
+ m_bufptr = bufptr, m_buflen = sal::static_int_cast< SIZE_T >(uDone);
+ }
+
+ static int const LINE_STATE_BEGIN = 0;
+ static int const LINE_STATE_CR = 1;
+ static int const LINE_STATE_LF = 2;
+
+ SIZE_T bufpos = sal::static_int_cast< SIZE_T >(nOffset - m_bufptr), curpos = bufpos, dstpos = 0;
+ int state = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN;
+
+ for ( ; state != LINE_STATE_LF; )
+ {
+ if (curpos >= m_buflen)
+ {
+ /* buffer examined */
+ if (0 < (curpos - bufpos))
+ {
+ /* flush buffer to sequence */
+ result = writeSequence_Impl (
+ ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos);
+ if (result != osl_File_E_None)
+ return (result);
+ *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
+ }
+
+ bufptr = nOffset / m_bufsiz * m_bufsiz;
+ if (bufptr != m_bufptr)
+ {
+ /* update buffer (pointer) */
+ sal_uInt64 uDone = 0;
+ result = readAt (bufptr, m_buffer, m_bufsiz, &uDone);
+ if (result != osl_File_E_None)
+ return (result);
+ m_bufptr = bufptr, m_buflen = sal::static_int_cast< SIZE_T >(uDone);
+ }
+
+ bufpos = sal::static_int_cast< SIZE_T >(nOffset - m_bufptr), curpos = bufpos;
+ if (bufpos >= m_buflen)
+ break;
+ }
+ switch (state)
+ {
+ case LINE_STATE_CR:
+ state = LINE_STATE_LF;
+ switch (m_buffer[curpos])
+ {
+ case 0x0A: /* CRLF */
+ /* eat current char */
+ curpos++;
+ break;
+ default: /* single CR */
+ /* keep current char */
+ break;
+ }
+ break;
+ default:
+ /* determine next state */
+ switch (m_buffer[curpos])
+ {
+ case 0x0A: /* single LF */
+ state = LINE_STATE_LF;
+ break;
+ case 0x0D: /* CR */
+ state = LINE_STATE_CR;
+ break;
+ default: /* advance to next char */
+ curpos++;
+ break;
+ }
+ if (state != LINE_STATE_BEGIN)
+ {
+ /* store (and eat) the newline char */
+ m_buffer[curpos] = 0x0A, curpos++;
+
+ /* flush buffer to sequence */
+ result = writeSequence_Impl (
+ ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1);
+ if (result != osl_File_E_None)
+ return (result);
+ *pBytesRead += curpos - bufpos, nOffset += curpos - bufpos;
+ }
+ break;
+ }
+ }
+
+ result = writeSequence_Impl (ppSequence, &dstpos, 0, 0);
+ if (result != osl_File_E_None)
+ return (result);
+ if (0 < dstpos)
+ return osl_File_E_None;
+ if (bufpos >= m_buflen)
+ return osl_File_E_AGAIN;
+ return osl_File_E_None;
+}
+
+oslFileError FileHandle_Impl::writeSequence_Impl (
+ sal_Sequence ** ppSequence,
+ SIZE_T * pnOffset,
+ const void * pBuffer,
+ SIZE_T nBytes)
+{
+ sal_Int32 nElements = *pnOffset + nBytes;
+ if (!*ppSequence)
+ {
+ /* construct sequence */
+ rtl_byte_sequence_constructNoDefault(ppSequence, nElements);
+ }
+ else if (nElements != (*ppSequence)->nElements)
+ {
+ /* resize sequence */
+ rtl_byte_sequence_realloc(ppSequence, nElements);
+ }
+ if (*ppSequence != 0)
+ {
+ /* fill sequence */
+ memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes), *pnOffset += nBytes;
+ }
+ return (*ppSequence != 0) ? osl_File_E_None : osl_File_E_NOMEM;
+}
+
+oslFileError FileHandle_Impl::syncFile()
+{
+ oslFileError result = osl_File_E_None;
+ if (m_state & STATE_MODIFIED)
+ {
+ sal_uInt64 uDone = 0;
+ result = writeAt (m_bufptr, m_buffer, m_buflen, &uDone);
+ if (result != osl_File_E_None)
+ return (result);
+ if (uDone != m_buflen)
+ return osl_File_E_IO;
+ m_state &= ~STATE_MODIFIED;
+ }
+ return (result);
+}
+
+//##################################################################
+// File I/O functions
+//##################################################################
+
+extern "C" oslFileHandle
+SAL_CALL osl_createFileHandleFromOSHandle (
+ HANDLE hFile,
+ sal_uInt32 uFlags)
+{
+ if ( !IsValidHandle(hFile) )
+ return 0; // EINVAL
+
+ FileHandle_Impl * pImpl = new FileHandle_Impl(hFile);
+ if (pImpl == 0)
+ {
+ // cleanup and fail
+ (void) ::CloseHandle(hFile);
+ return 0; // ENOMEM
+ }
+
+ /* check for regular file */
+ if (FILE_TYPE_DISK == GetFileType(hFile))
+ {
+ /* mark seekable */
+ pImpl->m_state |= FileHandle_Impl::STATE_SEEKABLE;
+
+ /* init current size */
+ LARGE_INTEGER uSize = { 0, 0 };
+ (void) ::GetFileSizeEx(hFile, &uSize);
+ pImpl->m_size = (sal::static_int_cast<sal_uInt64>(uSize.HighPart) << 32) + uSize.LowPart;
+ }
+
+ if (!(uFlags & osl_File_OpenFlag_Read))
+ pImpl->m_state &= ~FileHandle_Impl::STATE_READABLE;
+ if (!(uFlags & osl_File_OpenFlag_Write))
+ pImpl->m_state &= ~FileHandle_Impl::STATE_WRITEABLE;
+
+ OSL_POSTCOND(
+ (uFlags & osl_File_OpenFlag_Read) || (uFlags & osl_File_OpenFlag_Write),
+ "osl_createFileHandleFromOSHandle(): missing read/write access flags");
+ return (oslFileHandle)(pImpl);
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_openFile(
+ rtl_uString * strPath,
+ oslFileHandle * pHandle,
+ sal_uInt32 uFlags )
+{
+ rtl_uString * strSysPath = 0;
+ oslFileError result = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False );
+ if (result != osl_File_E_None)
+ return (result);
+
+ DWORD dwAccess = GENERIC_READ, dwShare = FILE_SHARE_READ, dwCreation = 0, dwAttributes = 0;
+
+ if ( uFlags & osl_File_OpenFlag_Write )
+ dwAccess |= GENERIC_WRITE;
+ else
+ dwShare |= FILE_SHARE_WRITE;
+
+ if ( uFlags & osl_File_OpenFlag_NoLock )
+ dwShare |= FILE_SHARE_WRITE;
+
+ if ( uFlags & osl_File_OpenFlag_Create )
+ dwCreation |= CREATE_NEW;
+ else
+ dwCreation |= OPEN_EXISTING;
+
+ HANDLE hFile = CreateFileW(
+ reinterpret_cast<LPCWSTR>(rtl_uString_getStr( strSysPath )),
+ dwAccess, dwShare, NULL, dwCreation, dwAttributes, NULL );
+
+ // @@@ ERROR HANDLING @@@
+ if ( !IsValidHandle( hFile ) )
+ result = oslTranslateFileError( GetLastError() );
+
+ *pHandle = osl_createFileHandleFromOSHandle (hFile, uFlags | osl_File_OpenFlag_Read);
+
+ rtl_uString_release( strSysPath );
+ return (result);
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_syncFile(oslFileHandle Handle)
+{
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile))
+ return osl_File_E_INVAL;
+
+ FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
+
+ oslFileError result = pImpl->syncFile();
+ if (result != osl_File_E_None)
+ return result;
+
+ if (!FlushFileBuffers(pImpl->m_hFile))
+ return oslTranslateFileError(GetLastError());
+
+ return osl_File_E_None;
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_closeFile(oslFileHandle Handle)
+{
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile))
+ return osl_File_E_INVAL;
+
+ ::EnterCriticalSection (&(pImpl->m_mutex));
+
+ oslFileError result = pImpl->syncFile();
+ if (result != osl_File_E_None)
+ {
+ /* ignore double failure */
+ (void)::CloseHandle(pImpl->m_hFile);
+ }
+ else if (!::CloseHandle(pImpl->m_hFile))
+ {
+ /* translate error code */
+ result = oslTranslateFileError( GetLastError() );
+ }
+
+ ::LeaveCriticalSection (&(pImpl->m_mutex));
+ delete pImpl;
+ return (result);
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_mapFile(
+ oslFileHandle Handle,
+ void** ppAddr,
+ sal_uInt64 uLength,
+ sal_uInt64 uOffset,
+ sal_uInt32 uFlags)
+{
+ struct FileMapping
+ {
+ HANDLE m_handle;
+
+ explicit FileMapping (HANDLE hMap)
+ : m_handle (hMap)
+ {}
+
+ ~FileMapping()
+ {
+ (void)::CloseHandle(m_handle);
+ }
+ };
+
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == ppAddr))
+ return osl_File_E_INVAL;
+ *ppAddr = 0;
+
+ static SIZE_T const nLimit = std::numeric_limits< SIZE_T >::max();
+ if (uLength > nLimit)
+ return osl_File_E_OVERFLOW;
+ SIZE_T const nLength = sal::static_int_cast< SIZE_T >(uLength);
+
+ OSVERSIONINFO osinfo;
+ osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ (void)::GetVersionEx(&osinfo);
+
+ if (VER_PLATFORM_WIN32_NT != osinfo.dwPlatformId)
+ return osl_File_E_NOSYS; // Unsupported
+
+ FileMapping aMap( ::CreateFileMapping (pImpl->m_hFile, NULL, SEC_COMMIT | PAGE_READONLY, 0, 0, NULL) );
+ if (!IsValidHandle(aMap.m_handle))
+ return oslTranslateFileError( GetLastError() );
+
+ DWORD const dwOffsetHi = sal::static_int_cast<DWORD>(uOffset >> 32);
+ DWORD const dwOffsetLo = sal::static_int_cast<DWORD>(uOffset & 0xFFFFFFFF);
+
+ *ppAddr = ::MapViewOfFile( aMap.m_handle, FILE_MAP_READ, dwOffsetHi, dwOffsetLo, nLength );
+ if (0 == *ppAddr)
+ return oslTranslateFileError( GetLastError() );
+
+ if (uFlags & osl_File_MapFlag_RandomAccess)
+ {
+ // Determine memory pagesize.
+ SYSTEM_INFO info;
+ ::GetSystemInfo( &info );
+ DWORD const dwPageSize = info.dwPageSize;
+
+ /*
+ * Pagein, touching first byte of each memory page.
+ * Note: volatile disables optimizing the loop away.
+ */
+ BYTE * pData (reinterpret_cast<BYTE*>(*ppAddr));
+ SIZE_T nSize (nLength);
+
+ volatile BYTE c = 0;
+ while (nSize > dwPageSize)
+ {
+ c ^= pData[0];
+ pData += dwPageSize;
+ nSize -= dwPageSize;
+ }
+ if (nSize > 0)
+ {
+ c ^= pData[0];
+ pData += nSize;
+ nSize -= nSize;
+ }
+ }
+ return osl_File_E_None;
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_unmapFile(void* pAddr, sal_uInt64 /* uLength */)
+{
+ if (0 == pAddr)
+ return osl_File_E_INVAL;
+
+ if (!::UnmapViewOfFile (pAddr))
+ return oslTranslateFileError( GetLastError() );
+
+ return osl_File_E_None;
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_readLine(
+ oslFileHandle Handle,
+ sal_Sequence ** ppSequence)
+{
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == ppSequence))
+ return osl_File_E_INVAL;
+ sal_uInt64 uBytesRead = 0;
+
+ // read at current filepos; filepos += uBytesRead;
+ FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
+ oslFileError result = pImpl->readLineAt (
+ pImpl->m_filepos, ppSequence, &uBytesRead);
+ if (result == osl_File_E_None)
+ pImpl->m_filepos += uBytesRead;
+ return (result);
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_readFile(
+ oslFileHandle Handle,
+ void * pBuffer,
+ sal_uInt64 uBytesRequested,
+ sal_uInt64 * pBytesRead)
+{
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pBuffer) || (0 == pBytesRead))
+ return osl_File_E_INVAL;
+
+ // read at current filepos; filepos += *pBytesRead;
+ FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
+ oslFileError result = pImpl->readFileAt (
+ pImpl->m_filepos, pBuffer, uBytesRequested, pBytesRead);
+ if (result == osl_File_E_None)
+ pImpl->m_filepos += *pBytesRead;
+ return (result);
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_writeFile(
+ oslFileHandle Handle,
+ const void * pBuffer,
+ sal_uInt64 uBytesToWrite,
+ sal_uInt64 * pBytesWritten )
+{
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pBuffer) || (0 == pBytesWritten))
+ return osl_File_E_INVAL;
+
+ // write at current filepos; filepos += *pBytesWritten;
+ FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
+ oslFileError result = pImpl->writeFileAt (
+ pImpl->m_filepos, pBuffer, uBytesToWrite, pBytesWritten);
+ if (result == osl_File_E_None)
+ pImpl->m_filepos += *pBytesWritten;
+ return (result);
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_readFileAt(
+ oslFileHandle Handle,
+ sal_uInt64 uOffset,
+ void* pBuffer,
+ sal_uInt64 uBytesRequested,
+ sal_uInt64* pBytesRead)
+{
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pBuffer) || (0 == pBytesRead))
+ return osl_File_E_INVAL;
+ if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
+ return osl_File_E_SPIPE;
+
+ static sal_uInt64 const g_limit_longlong = std::numeric_limits< LONGLONG >::max();
+ if (g_limit_longlong < uOffset)
+ return osl_File_E_OVERFLOW;
+ LONGLONG const nOffset = sal::static_int_cast< LONGLONG >(uOffset);
+
+ // read at specified fileptr
+ FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
+ return pImpl->readFileAt (nOffset, pBuffer, uBytesRequested, pBytesRead);
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_writeFileAt(
+ oslFileHandle Handle,
+ sal_uInt64 uOffset,
+ const void* pBuffer,
+ sal_uInt64 uBytesToWrite,
+ sal_uInt64* pBytesWritten)
+{
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pBuffer) || (0 == pBytesWritten))
+ return osl_File_E_INVAL;
+ if (0 == (pImpl->m_state & FileHandle_Impl::STATE_SEEKABLE))
+ return osl_File_E_SPIPE;
+
+ static sal_uInt64 const g_limit_longlong = std::numeric_limits< LONGLONG >::max();
+ if (g_limit_longlong < uOffset)
+ return osl_File_E_OVERFLOW;
+ LONGLONG const nOffset = sal::static_int_cast< LONGLONG >(uOffset);
+
+ // write at specified fileptr
+ FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
+ return pImpl->writeFileAt (nOffset, pBuffer, uBytesToWrite, pBytesWritten);
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_isEndOfFile (oslFileHandle Handle, sal_Bool *pIsEOF)
+{
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pIsEOF))
+ return osl_File_E_INVAL;
+
+ FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
+ *pIsEOF = (pImpl->getPos() == pImpl->getSize());
+ return osl_File_E_None;
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_getFilePos(oslFileHandle Handle, sal_uInt64 *pPos)
+{
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pPos))
+ return osl_File_E_INVAL;
+
+ FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
+ *pPos = pImpl->getPos();
+ return osl_File_E_None;
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_setFilePos(oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset)
+{
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile))
+ return osl_File_E_INVAL;
+
+ static sal_Int64 const g_limit_longlong = std::numeric_limits< LONGLONG >::max();
+ if (g_limit_longlong < uOffset)
+ return osl_File_E_OVERFLOW;
+ LONGLONG nPos = 0, nOffset = sal::static_int_cast< LONGLONG >(uOffset);
+
+ FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
+ switch (uHow)
+ {
+ case osl_Pos_Absolut:
+ if (0 > nOffset)
+ return osl_File_E_INVAL;
+ break;
+
+ case osl_Pos_Current:
+ nPos = sal::static_int_cast< LONGLONG >(pImpl->getPos());
+ if ((0 > nOffset) && (-1*nOffset > nPos))
+ return osl_File_E_INVAL;
+ if (g_limit_longlong < nPos + nOffset)
+ return osl_File_E_OVERFLOW;
+ break;
+
+ case osl_Pos_End:
+ nPos = sal::static_int_cast< LONGLONG >(pImpl->getSize());
+ if ((0 > nOffset) && (-1*nOffset > nPos))
+ return osl_File_E_INVAL;
+ if (g_limit_longlong < nPos + nOffset)
+ return osl_File_E_OVERFLOW;
+ break;
+
+ default:
+ return osl_File_E_INVAL;
+ }
+
+ return pImpl->setPos (nPos + nOffset);
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_getFileSize (oslFileHandle Handle, sal_uInt64 *pSize)
+{
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile) || (0 == pSize))
+ return osl_File_E_INVAL;
+
+ FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
+ *pSize = pImpl->getSize();
+ return osl_File_E_None;
+}
+
+//#############################################
+oslFileError
+SAL_CALL osl_setFileSize (oslFileHandle Handle, sal_uInt64 uSize)
+{
+ FileHandle_Impl * pImpl = static_cast<FileHandle_Impl*>(Handle);
+
+ if ((0 == pImpl) || !IsValidHandle(pImpl->m_hFile))
+ return osl_File_E_INVAL;
+ if (0 == (pImpl->m_state & FileHandle_Impl::STATE_WRITEABLE))
+ return osl_File_E_BADF;
+
+ static sal_uInt64 const g_limit_longlong = std::numeric_limits< LONGLONG >::max();
+ if (g_limit_longlong < uSize)
+ return osl_File_E_OVERFLOW;
+
+ FileHandle_Impl::Guard lock (&(pImpl->m_mutex));
+ oslFileError result = pImpl->syncFile();
+ if (result != osl_File_E_None)
+ return (result);
+ pImpl->m_bufptr = -1, pImpl->m_buflen = 0;
+
+ return pImpl->setSize (uSize);
+}
+
+//##################################################################
+// File handling functions
+//##################################################################
+
+//#############################################
+oslFileError SAL_CALL osl_removeFile( rtl_uString* strPath )
+{
+ rtl_uString *strSysPath = NULL;
+ oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False );
+
+ if ( osl_File_E_None == error )
+ {
+ if ( DeleteFile( reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath )) ) )
+ error = osl_File_E_None;
+ else
+ error = oslTranslateFileError( GetLastError() );
+
+ rtl_uString_release( strSysPath );
+ }
+ return error;
+}
+
+//#############################################
+#define osl_File_CopyRecursive 0x0001
+#define osl_File_CopyOverwrite 0x0002
+
+oslFileError SAL_CALL osl_copyFile( rtl_uString* strPath, rtl_uString *strDestPath )
+{
+ rtl_uString *strSysPath = NULL, *strSysDestPath = NULL;
+ oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False );
+
+ if ( osl_File_E_None == error )
+ error = _osl_getSystemPathFromFileURL( strDestPath, &strSysDestPath, sal_False );
+
+ if ( osl_File_E_None == error )
+ {
+ LPCTSTR src = reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath ));
+ LPCTSTR dst = reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysDestPath ));
+
+ if ( CopyFile( src, dst, FALSE ) )
+ error = osl_File_E_None;
+ else
+ error = oslTranslateFileError( GetLastError() );
+ }
+
+ if ( strSysPath )
+ rtl_uString_release( strSysPath );
+ if ( strSysDestPath )
+ rtl_uString_release( strSysDestPath );
+
+ return error;
+}
+
+//#############################################
+oslFileError SAL_CALL osl_moveFile( rtl_uString* strPath, rtl_uString *strDestPath )
+{
+ rtl_uString *strSysPath = NULL, *strSysDestPath = NULL;
+ oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False );
+
+ if ( osl_File_E_None == error )
+ error = _osl_getSystemPathFromFileURL( strDestPath, &strSysDestPath, sal_False );
+
+ if ( osl_File_E_None == error )
+ {
+ LPCTSTR src = reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath ));
+ LPCTSTR dst = reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysDestPath ));
+
+ if ( MoveFileEx( src, dst, MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH | MOVEFILE_REPLACE_EXISTING ) )
+ error = osl_File_E_None;
+ else
+ error = oslTranslateFileError( GetLastError() );
+ }
+
+ if ( strSysPath )
+ rtl_uString_release( strSysPath );
+ if ( strSysDestPath )
+ rtl_uString_release( strSysDestPath );
+
+ return error;
+}