project64/Source/Common/File.cpp

409 lines
8.6 KiB
C++
Raw Permalink Normal View History

2021-04-14 05:34:15 +00:00
#include "File.h"
#include "StdString.h"
#include "path.h"
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#define USE_WINDOWS_API
#include <Windows.h>
#else
#include <unistd.h>
#endif
#if defined(_MSC_VER)
#include <crtdbg.h>
#else
2022-10-03 08:04:42 +00:00
#define _ASSERTE(expr) ((void)0)
#endif
CFile::CFile() :
#ifdef USE_WINDOWS_API
m_hFile(INVALID_HANDLE_VALUE),
#else
m_hFile(nullptr),
#endif
m_bCloseOnDelete(false)
{
}
CFile::CFile(void * hFile) :
m_hFile(hFile),
m_bCloseOnDelete(true)
{
2015-10-25 10:50:28 +00:00
if (hFile == 0)
{
_ASSERTE(hFile != 0);
}
}
CFile::CFile(const char * lpszFileName, uint32_t nOpenFlags) :
#ifdef USE_WINDOWS_API
m_hFile(INVALID_HANDLE_VALUE),
#else
m_hFile(nullptr),
#endif
m_bCloseOnDelete(true)
{
Open(lpszFileName, nOpenFlags);
}
CFile::~CFile()
{
#ifdef USE_WINDOWS_API
2015-10-25 10:50:28 +00:00
if (m_hFile != INVALID_HANDLE_VALUE && m_bCloseOnDelete)
#else
2021-04-12 11:35:39 +00:00
if (m_hFile != nullptr && m_bCloseOnDelete)
#endif
2015-10-25 10:50:28 +00:00
{
Close();
}
2015-10-25 10:50:28 +00:00
}
bool CFile::Open(const char * lpszFileName, uint32_t nOpenFlags)
{
if (!Close())
{
return false;
}
2021-04-12 11:35:39 +00:00
if (lpszFileName == nullptr || strlen(lpszFileName) == 0)
2015-10-25 10:50:28 +00:00
{
return false;
}
m_bCloseOnDelete = true;
#ifdef USE_WINDOWS_API
2015-10-25 10:50:28 +00:00
m_hFile = INVALID_HANDLE_VALUE;
ULONG dwAccess = 0;
switch (nOpenFlags & 3)
{
case modeRead:
dwAccess = GENERIC_READ;
break;
case modeWrite:
dwAccess = GENERIC_WRITE;
break;
case modeReadWrite:
dwAccess = GENERIC_READ | GENERIC_WRITE;
2015-10-25 10:50:28 +00:00
break;
default:
_ASSERTE(false);
}
// Map share mode
2015-10-25 10:50:28 +00:00
ULONG dwShareMode = 0;
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
2022-10-03 08:04:42 +00:00
if ((nOpenFlags & shareDenyWrite) == shareDenyWrite)
{
dwShareMode &= ~FILE_SHARE_WRITE;
}
if ((nOpenFlags & shareDenyRead) == shareDenyRead)
{
dwShareMode &= ~FILE_SHARE_READ;
}
if ((nOpenFlags & shareExclusive) == shareExclusive)
{
dwShareMode = 0;
}
2015-10-25 10:50:28 +00:00
// Map modeNoInherit flag
2015-10-25 10:50:28 +00:00
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
2021-04-12 11:35:39 +00:00
sa.lpSecurityDescriptor = nullptr;
2015-10-25 10:50:28 +00:00
sa.bInheritHandle = (nOpenFlags & modeNoInherit) == 0;
// Map creation flags
2015-11-11 17:43:57 +00:00
ULONG dwCreateFlag = OPEN_EXISTING;
2015-10-25 10:50:28 +00:00
if (nOpenFlags & modeCreate)
{
2015-11-11 23:08:24 +00:00
dwCreateFlag = ((nOpenFlags & modeNoTruncate) != 0) ? OPEN_ALWAYS : CREATE_ALWAYS;
}
2015-10-25 10:50:28 +00:00
// Attempt file creation
HANDLE hFile = ::CreateFile(stdstr(lpszFileName).ToUTF16().c_str(), dwAccess, dwShareMode, &sa, dwCreateFlag, FILE_ATTRIBUTE_NORMAL, nullptr);
2015-10-25 10:50:28 +00:00
if (hFile == INVALID_HANDLE_VALUE)
{ //#define ERROR_PATH_NOT_FOUND 3L
//ULONG err = GetLastError();
return false;
}
m_hFile = hFile;
#else
2016-08-03 11:25:24 +00:00
if ((nOpenFlags & modeNoTruncate) == 0 && (nOpenFlags & CFileBase::modeCreate) == CFileBase::modeCreate)
{
CPath(lpszFileName).Delete();
}
if ((nOpenFlags & CFileBase::modeCreate) != CFileBase::modeCreate)
{
if (!CPath(lpszFileName).Exists())
{
return false;
}
}
if ((nOpenFlags & CFileBase::modeCreate) == CFileBase::modeCreate)
{
CPath file(lpszFileName);
if (!file.Exists())
{
2022-10-03 08:04:42 +00:00
FILE * fp = fopen(lpszFileName, "wb");
if (fp)
{
fclose(fp);
}
if (!file.Exists())
{
return false;
}
}
}
if ((nOpenFlags & CFileBase::modeWrite) == CFileBase::modeWrite ||
(nOpenFlags & CFileBase::modeReadWrite) == CFileBase::modeReadWrite)
{
m_hFile = fopen(lpszFileName, "rb+");
2021-04-12 11:35:39 +00:00
if (m_hFile != nullptr)
{
SeekToBegin();
}
}
else if ((nOpenFlags & CFileBase::modeRead) == CFileBase::modeRead)
{
m_hFile = fopen(lpszFileName, "rb");
2021-04-12 11:35:39 +00:00
if (m_hFile != nullptr)
{
SeekToBegin();
}
}
else
{
return false;
}
#endif
m_bCloseOnDelete = true;
return true;
}
bool CFile::Close()
{
2015-10-25 10:50:28 +00:00
bool bError = true;
#ifdef USE_WINDOWS_API
2015-10-25 10:50:28 +00:00
if (m_hFile != INVALID_HANDLE_VALUE)
{
bError = !::CloseHandle(m_hFile);
}
m_hFile = INVALID_HANDLE_VALUE;
#else
2021-04-12 11:35:39 +00:00
if (m_hFile != nullptr)
{
fclose((FILE *)m_hFile);
2021-04-12 11:35:39 +00:00
m_hFile = nullptr;
}
#endif
2015-10-25 10:50:28 +00:00
m_bCloseOnDelete = false;
return bError;
}
uint32_t CFile::SeekToEnd(void)
2015-10-25 10:50:28 +00:00
{
return Seek(0, CFile::end);
}
void CFile::SeekToBegin(void)
{
2015-10-25 10:50:28 +00:00
Seek(0, CFile::begin);
}
bool CFile::IsOpen(void) const
{
#ifdef USE_WINDOWS_API
2015-10-25 10:50:28 +00:00
return m_hFile != INVALID_HANDLE_VALUE;
#else
2021-04-12 11:35:39 +00:00
return m_hFile != nullptr;
#endif
}
bool CFile::Flush()
{
#ifdef USE_WINDOWS_API
2015-10-25 10:50:28 +00:00
if (m_hFile == INVALID_HANDLE_VALUE)
{
return true;
}
2015-10-25 10:50:28 +00:00
return ::FlushFileBuffers(m_hFile) != 0;
#else
2017-01-03 05:21:35 +00:00
fflush((FILE *)m_hFile);
#ifndef WIN32
2017-01-03 05:21:35 +00:00
fsync(fileno((FILE *)m_hFile));
#endif
2017-01-03 05:21:35 +00:00
return true;
#endif
}
2022-10-03 08:04:42 +00:00
bool CFile::Write(const void * lpBuf, uint32_t nCount)
{
2015-10-25 10:50:28 +00:00
if (nCount == 0)
{
2022-10-03 08:04:42 +00:00
return true; // Avoid Win32 "null-write" option
2015-10-25 10:50:28 +00:00
}
#ifdef USE_WINDOWS_API
ULONG nWritten = 0;
2021-04-12 11:35:39 +00:00
if (!::WriteFile(m_hFile, lpBuf, nCount, &nWritten, nullptr))
2015-10-25 10:50:28 +00:00
{
return false;
}
2015-10-25 10:50:28 +00:00
if (nWritten != nCount)
{
// Win32s will not return an error all the time (usually DISK_FULL)
return false;
}
#else
if (fwrite(lpBuf, 1, nCount, (FILE *)m_hFile) != nCount)
{
return false;
}
#endif
2015-10-25 10:50:28 +00:00
return true;
}
bool CFile::ReadInterger(int32_t & Value)
{
#ifdef USE_WINDOWS_API
LARGE_INTEGER CurrentPos;
LARGE_INTEGER Zero = {0};
if (!SetFilePointerEx(m_hFile, Zero, &CurrentPos, FILE_CURRENT))
{
return false;
}
char buffer[256];
DWORD bytesRead = 0;
if (!::ReadFile(m_hFile, buffer, sizeof(buffer) - 1, &bytesRead, nullptr) || bytesRead == 0)
{
return false;
}
buffer[bytesRead] = '\0';
int CharsRead = 0;
int Number;
sscanf(buffer, "%d%n", &Number, &CharsRead);
LARGE_INTEGER NewPos;
NewPos.QuadPart = CurrentPos.QuadPart + CharsRead;
if (!SetFilePointerEx(m_hFile, NewPos, NULL, FILE_BEGIN))
{
return false;
}
if (CharsRead == 0)
{
return false;
}
Value = Number;
return true;
#else
va_list args;
va_start(args, Format);
int Result = vfscanf((FILE *)m_hFile, "%d", args);
va_end(args);
return Result != 0;
#endif
}
2022-10-03 08:04:42 +00:00
uint32_t CFile::Read(void * lpBuf, uint32_t nCount)
{
2015-10-25 10:50:28 +00:00
if (nCount == 0)
{
2022-10-03 08:04:42 +00:00
return 0; // Avoid Win32 "null-read"
2015-10-25 10:50:28 +00:00
}
#ifdef USE_WINDOWS_API
DWORD dwRead = 0;
2021-04-12 11:35:39 +00:00
if (!::ReadFile(m_hFile, lpBuf, nCount, &dwRead, nullptr))
2015-10-25 10:50:28 +00:00
{
return 0;
}
return (uint32_t)dwRead;
#else
uint32_t res = fread(lpBuf, sizeof(uint8_t), nCount, (FILE *)m_hFile);
return res;
#endif
}
int32_t CFile::Seek(int32_t lOff, SeekPosition nFrom)
{
#ifdef USE_WINDOWS_API
2021-04-12 11:35:39 +00:00
ULONG dwNew = ::SetFilePointer(m_hFile, lOff, nullptr, (ULONG)nFrom);
if (dwNew == (ULONG)-1)
2015-10-25 10:50:28 +00:00
{
return -1;
}
return dwNew;
#else
2021-04-12 11:35:39 +00:00
if (m_hFile == nullptr)
{
return -1;
}
int origin;
switch (nFrom)
{
case begin: origin = SEEK_SET; break;
case current: origin = SEEK_CUR; break;
case end: origin = SEEK_END; break;
default:
return -1;
}
Flush();
int res = fseek((FILE *)m_hFile, lOff, origin);
return res;
#endif
}
2015-10-25 10:50:28 +00:00
uint32_t CFile::GetPosition() const
{
#ifdef USE_WINDOWS_API
2021-04-12 11:35:39 +00:00
return ::SetFilePointer(m_hFile, 0, nullptr, FILE_CURRENT);
#else
return (uint32_t)ftell((FILE *)m_hFile);
#endif
}
2015-10-25 10:50:28 +00:00
bool CFile::SetLength(uint32_t dwNewLen)
{
Seek((int32_t)dwNewLen, begin);
return SetEndOfFile();
}
2015-10-25 10:50:28 +00:00
uint32_t CFile::GetLength() const
{
#ifdef USE_WINDOWS_API
return GetFileSize(m_hFile, 0);
#else
uint32_t pos = GetPosition();
fseek((FILE *)m_hFile, 0, SEEK_END);
uint32_t FileSize = GetPosition();
fseek((FILE *)m_hFile, (int32_t)pos, SEEK_SET);
return FileSize;
#endif
}
bool CFile::SetEndOfFile()
{
#ifdef USE_WINDOWS_API
2015-10-25 10:50:28 +00:00
return ::SetEndOfFile(m_hFile) != 0;
#else
Flush();
#ifdef _WIN32
2022-10-03 08:04:42 +00:00
return _chsize(_fileno((FILE *)m_hFile), GetPosition()) == 0;
#else
2022-10-03 08:04:42 +00:00
return ftruncate(fileno((FILE *)m_hFile), GetPosition()) == 0;
#endif
#endif
}