tsMuxer/libmediation/fs/osdep/file_win32.cpp
Daniel Kamil Kozar 1bead15c8f
Don't use POSIX APIs in Windows builds (#212)
The POSIX compatibility layer provided by the Microsoft C Runtime Library
treats its string arguments as if they were passed to the A-family of WinAPI
functions, which means that they undergo conversion to the ACP before being
passed to the actual WinAPI call. Passing UTF-8 encoded strings could have
never really worked.
2020-02-27 22:20:36 +01:00

228 lines
6.2 KiB
C++

#include <io.h>
#include <windows.h>
#include <sstream>
#include "../directory.h"
#include "../file.h"
void throwFileError()
{
char msgBuf[32 * 1024];
memset(msgBuf, 0, sizeof(msgBuf));
DWORD dw = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&msgBuf,
sizeof(msgBuf), NULL);
throw std::runtime_error(msgBuf);
}
void makeWin32OpenFlags(unsigned int oflag, DWORD* const dwDesiredAccess, DWORD* const dwCreationDisposition,
DWORD* const dwShareMode)
{
*dwDesiredAccess = 0;
*dwCreationDisposition = CREATE_ALWAYS;
if (oflag & File::ofRead)
{
*dwDesiredAccess = GENERIC_READ & ~SYNCHRONIZE;
*dwCreationDisposition = OPEN_EXISTING;
*dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
}
if (oflag & File::ofWrite)
{
*dwDesiredAccess |= GENERIC_WRITE & ~SYNCHRONIZE;
*dwCreationDisposition = CREATE_ALWAYS;
*dwShareMode = FILE_SHARE_READ;
}
if (oflag & File::ofAppend)
*dwCreationDisposition = OPEN_ALWAYS;
if (oflag & File::ofNoTruncate)
*dwCreationDisposition = OPEN_ALWAYS;
if (oflag & File::ofOpenExisting)
*dwCreationDisposition = OPEN_EXISTING;
if (oflag & File::ofCreateNew)
*dwCreationDisposition = CREATE_NEW;
}
File::File() : AbstractOutputStream(), m_impl(INVALID_HANDLE_VALUE), m_name(""), m_pos(0) {}
File::File(const char* fName, unsigned int oflag, unsigned int systemDependentFlags) /* throw ( std::runtime_error ) */
: AbstractOutputStream(), m_impl(INVALID_HANDLE_VALUE), m_name(fName), m_pos(0)
{
DWORD dwDesiredAccess = 0;
DWORD dwCreationDisposition = CREATE_ALWAYS;
DWORD dwShareMode = 0;
makeWin32OpenFlags(oflag, &dwDesiredAccess, &dwCreationDisposition, &dwShareMode);
if (!systemDependentFlags)
{
if ((oflag & ofRead) && !(oflag & ofWrite))
systemDependentFlags = FILE_FLAG_SEQUENTIAL_SCAN;
else
systemDependentFlags = FILE_FLAG_RANDOM_ACCESS;
}
m_impl = CreateFile(toWide(fName).data(), dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition,
systemDependentFlags, NULL);
if (m_impl == INVALID_HANDLE_VALUE)
{
throwFileError();
}
else
{
if (oflag & File::ofAppend)
{
long hiword = 0;
DWORD newPointerLow = SetFilePointer(m_impl, 0, &hiword, FILE_END);
if (newPointerLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
throwFileError();
}
}
}
File::~File()
{
if (isOpen())
close();
}
bool File::open(const char* fName, unsigned int oflag, unsigned int systemDependentFlags)
{
m_name = fName;
m_pos = 0;
DWORD dwDesiredAccess = 0;
DWORD dwCreationDisposition = CREATE_ALWAYS;
DWORD dwShareMode = 0;
makeWin32OpenFlags(oflag, &dwDesiredAccess, &dwCreationDisposition, &dwShareMode);
if (!systemDependentFlags)
{
if ((oflag & ofRead) && !(oflag & ofWrite))
systemDependentFlags = FILE_FLAG_SEQUENTIAL_SCAN;
else
systemDependentFlags = FILE_FLAG_RANDOM_ACCESS;
}
if ((oflag & File::ofOpenExisting) == 0)
{
createDir(extractFileDir(fName), true);
}
m_impl = CreateFile(toWide(fName).data(), dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition,
systemDependentFlags, NULL);
if (m_impl == INVALID_HANDLE_VALUE)
{
return false;
}
else
{
if (oflag & File::ofAppend)
{
long hiword = 0;
DWORD newPointerLow = SetFilePointer(m_impl, 0, &hiword, FILE_END);
if (newPointerLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
throwFileError();
}
}
return true;
}
bool File::close()
{
// sync();
BOOL res = CloseHandle(m_impl);
m_impl = INVALID_HANDLE_VALUE;
return res != 0;
}
int File::read(void* buffer, uint32_t count) const
{
if (!isOpen())
return -1;
DWORD bytesRead = 0;
BOOL res = ReadFile(m_impl, buffer, count, &bytesRead, NULL);
if (!res)
return -1;
m_pos += bytesRead;
return (int)bytesRead;
}
int File::write(const void* buffer, uint32_t count)
{
if (!isOpen())
return -1;
DWORD bytesWritten = 0;
BOOL res = WriteFile(m_impl, buffer, count, &bytesWritten, NULL);
if (!res)
{
throwFileError();
}
if (!res)
return -1;
m_pos += bytesWritten;
return (int)bytesWritten;
}
void File::sync() { FlushFileBuffers(m_impl); }
bool File::isOpen() const { return m_impl != INVALID_HANDLE_VALUE; }
bool File::size(uint64_t* const fileSize) const
{
DWORD highDw;
DWORD lowDw = GetFileSize(m_impl, &highDw);
if ((lowDw == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
return false;
*fileSize = highDw;
*fileSize <<= 32;
*fileSize |= lowDw;
return true;
}
uint64_t File::seek(int64_t offset, SeekMethod whence)
{
if (!isOpen())
return (uint64_t)-1;
DWORD moveMethod = 0;
switch (whence)
{
case smBegin:
moveMethod = FILE_BEGIN;
break;
case smCurrent:
moveMethod = FILE_CURRENT;
break;
case smEnd:
moveMethod = FILE_END;
break;
}
LONG distanceToMoveLow = (uint32_t)(offset & 0xffffffff);
LONG distanceToMoveHigh = (uint32_t)((offset & 0xffffffff00000000ull) >> 32);
DWORD newPointerLow = SetFilePointer(m_impl, distanceToMoveLow, &distanceToMoveHigh, moveMethod);
if (newPointerLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
return (uint64_t)-1;
m_pos = newPointerLow | ((uint64_t)distanceToMoveHigh << 32);
return m_pos;
}
bool File::truncate(uint64_t newFileSize)
{
LONG distanceToMoveLow = (uint32_t)(newFileSize & 0xffffffff);
LONG distanceToMoveHigh = (uint32_t)((newFileSize & 0xffffffff00000000ull) >> 32);
DWORD newPointerLow = SetFilePointer(m_impl, distanceToMoveLow, &distanceToMoveHigh, FILE_BEGIN);
int errCode = GetLastError();
if ((newPointerLow == INVALID_SET_FILE_POINTER) && (errCode != NO_ERROR))
// return false;
throwFileError();
return SetEndOfFile(m_impl) > 0;
}