Migrate IOFile implementation to io_file.cpp

Makes the implementation of `IOFile` private, allowing inclusions and
defines such as `#define fseeko` and `#include <io.h>` to not poison
client-code or the global namespace.
This commit is contained in:
Wunkolo 2023-06-19 19:37:05 -07:00
parent c042dbc293
commit 1b9f270b19
3 changed files with 138 additions and 114 deletions

View file

@ -1,136 +1,45 @@
#pragma once
#include <cstdint>
#include <cstdio>
#include <filesystem>
#include <optional>
#include <utility>
#ifdef _MSC_VER
// 64 bit offsets for MSVC
#define fseeko _fseeki64
#define ftello _ftelli64
#define fileno _fileno
#pragma warning(disable : 4996)
#endif
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifdef WIN32
#include <io.h> // For _chsize_s
#else
#include <unistd.h> // For ftruncate
#endif
class IOFile {
FILE* handle = nullptr;
static inline std::filesystem::path appData = ""; // Directory for holding app data. AppData on Windows
FILE* handle = nullptr;
static inline std::filesystem::path appData = ""; // Directory for holding app data. AppData on Windows
public:
IOFile() {}
IOFile(FILE* handle) : handle(handle) {}
IOFile(const std::filesystem::path& path, const char* permissions = "rb") {
open(path, permissions);
}
public:
IOFile();
IOFile(FILE* handle);
IOFile(const std::filesystem::path& path, const char* permissions = "rb");
bool isOpen() {
return handle != nullptr;
}
bool isOpen();
bool open(const std::filesystem::path& path, const char* permissions = "rb") {
const auto str = path.string(); // For some reason converting paths directly with c_str() doesn't work
return open(str.c_str(), permissions);
}
bool open(const std::filesystem::path& path, const char* permissions = "rb");
bool open(const char* filename, const char* permissions = "rb") {
handle = std::fopen(filename, permissions);
return isOpen();
}
bool open(const char* filename, const char* permissions = "rb");
void close() {
if (isOpen()) {
fclose(handle);
handle = nullptr;
}
}
void close();
std::pair<bool, std::size_t> read(void* data, std::size_t length, std::size_t dataSize) {
if (!isOpen()) {
return { false, std::numeric_limits<std::size_t>::max() };
}
std::pair<bool, std::size_t> read(void* data, std::size_t length, std::size_t dataSize);
if (length == 0) return { true, 0 };
return { true, std::fread(data, dataSize, length, handle) };
}
std::pair<bool, std::size_t> readBytes(void* data, std::size_t count);
auto readBytes(void* data, std::size_t count) {
return read(data, count, sizeof(std::uint8_t));
}
std::pair<bool, std::size_t> write(const void* data, std::size_t length, std::size_t dataSize);
std::pair<bool, std::size_t> write(const void* data, std::size_t length, std::size_t dataSize) {
if (!isOpen()) {
return { false, std::numeric_limits<std::size_t>::max() };
}
std::pair<bool, std::size_t> writeBytes(const void* data, std::size_t count);
if (length == 0) return { true, 0 };
return { true, std::fwrite(data, dataSize, length, handle) };
}
std::optional<std::uint64_t> size();
auto writeBytes(const void* data, std::size_t count) {
return write(data, count, sizeof(std::uint8_t));
}
bool seek(std::int64_t offset, int origin = SEEK_SET);
std::optional<std::uint64_t> size() {
if (!isOpen()) return {};
bool rewind();
std::uint64_t pos = ftello(handle);
if (fseeko(handle, 0, SEEK_END) != 0) {
return {};
}
FILE* getHandle();
std::uint64_t size = ftello(handle);
if ((size != pos) && (fseeko(handle, pos, SEEK_SET) != 0)) {
return {};
}
static void setAppDataDir(const std::filesystem::path& dir);
return size;
}
// Sets the size of the file to "size" and returns whether it succeeded or not
bool setSize(std::uint64_t size);
bool seek(std::int64_t offset, int origin = SEEK_SET) {
if (!isOpen() || fseeko(handle, offset, origin) != 0)
return false;
return true;
}
bool rewind() {
return seek(0, SEEK_SET);
}
FILE* getHandle() {
return handle;
}
static void setAppDataDir(const std::filesystem::path& dir) {
if (dir == "") Helpers::panic("Failed to set app data directory");
appData = dir;
}
// Sets the size of the file to "size" and returns whether it succeeded or not
bool setSize(std::uint64_t size) {
if (!isOpen()) return false;
bool success;
#ifdef WIN32
success = _chsize_s(_fileno(handle), size) == 0;
#else
success = ftruncate(fileno(handle), size) == 0;
#endif
fflush(handle);
return success;
}
static std::filesystem::path getAppData() { return IOFile::appData; }
static std::filesystem::path getAppData();
};