Files
tech5/source/shared/idlib/filesystem/file_permanent.cpp
T
2026-08-08 19:30:03 -07:00

163 lines
5.7 KiB
C++

#include "file_permanent.h"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
namespace {
HANDLE FileHandle(const void* handle) {
return static_cast<HANDLE>(const_cast<void*>(handle));
}
}
idFile_Permanent::idFile_Permanent(const char* relativePath,
const char* osPath, const fsMode_t fileMode, const bool create)
: idFile(), name(relativePath), fullPath(osPath), mode(fileMode),
fileSize(0), sectorSize(1), device(FS_DEVICE_HARD_DISK_DRIVE),
handle(nullptr) {
DWORD access = GENERIC_READ;
DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE;
DWORD disposition = OPEN_EXISTING;
if (mode == FS_WRITE) {
access = GENERIC_WRITE;
share = 0;
disposition = CREATE_ALWAYS;
} else if (mode == FS_READ_WRITE) {
access = GENERIC_READ | GENERIC_WRITE;
disposition = create ? OPEN_ALWAYS : OPEN_EXISTING;
} else if (mode == FS_APPEND) {
access = FILE_APPEND_DATA;
share |= FILE_SHARE_DELETE;
disposition = OPEN_ALWAYS;
}
HANDLE file = CreateFileA(fullPath.c_str(), access,
share, nullptr, disposition,
FILE_ATTRIBUTE_NORMAL, nullptr);
if (file == INVALID_HANDLE_VALUE) return;
handle = file;
LARGE_INTEGER size;
if (GetFileSizeEx(file, &size)) fileSize = size.QuadPart;
if (mode == FS_APPEND) Seek(0, FS_SEEK_END);
}
idFile_Permanent::~idFile_Permanent() {
if (handle != nullptr) CloseHandle(FileHandle(handle));
handle = nullptr;
}
unsigned int idFile_Permanent::Read(void* data, const unsigned int length) {
if (handle == nullptr || data == nullptr) return 0;
DWORD amount = 0;
return ReadFile(FileHandle(handle), data, length, &amount, nullptr)
? amount : 0;
}
unsigned int idFile_Permanent::Write(const void* data,
const unsigned int length) {
if (handle == nullptr || data == nullptr || mode == FS_READ) return 0;
DWORD amount = 0;
if (!WriteFile(FileHandle(handle), data, length, &amount, nullptr)) return 0;
const std::int64_t position = Tell();
if (position > fileSize) fileSize = position;
return amount;
}
unsigned int idFile_Permanent::ReadOfs(const std::int64_t offset, void* data,
const unsigned int length) {
if (handle == nullptr || offset < 0) return 0;
OVERLAPPED overlapped = {};
overlapped.Offset = static_cast<DWORD>(offset);
overlapped.OffsetHigh = static_cast<DWORD>(
static_cast<std::uint64_t>(offset) >> 32);
DWORD amount = 0;
return ReadFile(FileHandle(handle), data, length, &amount, &overlapped)
? amount : 0;
}
unsigned int idFile_Permanent::WriteOfs(const std::int64_t offset,
const void* data, const unsigned int length) {
if (handle == nullptr || offset < 0 || mode == FS_READ) return 0;
OVERLAPPED overlapped = {};
overlapped.Offset = static_cast<DWORD>(offset);
overlapped.OffsetHigh = static_cast<DWORD>(
static_cast<std::uint64_t>(offset) >> 32);
DWORD amount = 0;
if (!WriteFile(FileHandle(handle), data, length, &amount, &overlapped)) return 0;
const std::int64_t end = offset + amount;
if (end > fileSize) fileSize = end;
return amount;
}
bool idFile_Permanent::Lock(const std::int64_t offset,
const unsigned int length, const fsLock_t lock) {
if (handle == nullptr || offset < 0) return false;
OVERLAPPED overlapped = {};
overlapped.Offset = static_cast<DWORD>(offset);
overlapped.OffsetHigh = static_cast<DWORD>(
static_cast<std::uint64_t>(offset) >> 32);
return LockFileEx(FileHandle(handle),
lock == FS_LOCK_EXCLUSIVE ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0,
length, 0, &overlapped) != FALSE;
}
bool idFile_Permanent::Unlock(const std::int64_t offset,
const unsigned int length) {
if (handle == nullptr || offset < 0) return false;
OVERLAPPED overlapped = {};
overlapped.Offset = static_cast<DWORD>(offset);
overlapped.OffsetHigh = static_cast<DWORD>(
static_cast<std::uint64_t>(offset) >> 32);
return UnlockFileEx(FileHandle(handle), 0, length, 0, &overlapped) != FALSE;
}
std::int64_t idFile_Permanent::Length() const {
return fileSize;
}
void idFile_Permanent::SetLength(const unsigned int length) {
if (handle == nullptr || mode == FS_READ) return;
const std::int64_t oldPosition = Tell();
if (Seek(length, FS_SEEK_SET) == 0 && SetEndOfFile(FileHandle(handle)))
fileSize = length;
Seek(oldPosition < fileSize ? oldPosition : fileSize, FS_SEEK_SET);
}
std::int64_t idFile_Permanent::Tell() const {
if (handle == nullptr) return 0;
LARGE_INTEGER distance = {}, position = {};
return SetFilePointerEx(FileHandle(handle), distance, &position, FILE_CURRENT)
? position.QuadPart : 0;
}
int idFile_Permanent::Seek(const std::int64_t offset, const fsOrigin_t origin) {
if (handle == nullptr) return -1;
DWORD method = FILE_BEGIN;
if (origin == FS_SEEK_CUR) method = FILE_CURRENT;
else if (origin == FS_SEEK_END) method = FILE_END;
LARGE_INTEGER distance;
distance.QuadPart = offset;
return SetFilePointerEx(FileHandle(handle), distance, nullptr, method)
? 0 : -1;
}
unsigned int idFile_Permanent::Timestamp() const {
if (handle == nullptr) return 0;
FILETIME writeTime;
if (!GetFileTime(FileHandle(handle), nullptr, nullptr, &writeTime)) return 0;
ULARGE_INTEGER value;
value.LowPart = writeTime.dwLowDateTime;
value.HighPart = writeTime.dwHighDateTime;
const std::uint64_t unixTicks = value.QuadPart > 116444736000000000ULL
? value.QuadPart - 116444736000000000ULL : 0;
return static_cast<unsigned int>(unixTicks / 10000000ULL);
}
void idFile_Permanent::Flush() {
if (handle != nullptr) FlushFileBuffers(FileHandle(handle));
}
void idFile_Permanent::ForceFlush() {
Flush();
}