reorganize file i/o

This commit is contained in:
Tropical 2026-04-07 17:32:19 -05:00
parent 32aaafeb7e
commit 2f1a6f265f
24 changed files with 193 additions and 169 deletions

View file

@ -9,7 +9,7 @@
#include "minecraft/client/Minecraft.h"
#include "minecraft/client/skins/TexturePack.h"
#include "minecraft/client/skins/TexturePackRepository.h"
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
#include "platform/PlatformTypes.h"
ArchiveManager::ArchiveManager()
@ -26,7 +26,7 @@ void ArchiveManager::loadMediaArchive() {
if (!mediapath.empty()) {
#if defined(__linux__)
std::wstring exeDirW = PlatformFileIO.getBasePath().wstring();
std::wstring exeDirW = PlatformFilesystem.getBasePath().wstring();
std::wstring candidate = exeDirW + File::pathSeparator + mediapath;
if (File(candidate).exists()) {
m_mediaArchive = new ArchiveFile(File(candidate));

View file

@ -16,7 +16,7 @@
#include "app/linux/Iggy/include/rrCore.h"
#include "app/linux/LinuxGame.h"
#include "platform/C4JThread.h"
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
#include "java/Random.h"
#include "minecraft/client/Minecraft.h"
#include "minecraft/client/multiplayer/MultiPlayerLocalPlayer.h"
@ -183,7 +183,7 @@ void SoundEngine::play(int iSound, float x, float y, float z, float volume,
for (int i = 0; szId[i]; i++)
if (szId[i] == '.') szId[i] = '/';
std::string base = PlatformFileIO.getBasePath().string() + "/";
std::string base = PlatformFilesystem.getBasePath().string() + "/";
const char* roots[] = {
"Sound/Minecraft/", "app/common/Sound/Minecraft/",
"app/common/res/TitleUpdate/res/Sound/Minecraft/"};
@ -197,7 +197,7 @@ void SoundEngine::play(int iSound, float x, float y, float z, float volume,
for (int i = 1; i <= 16; i++) {
char tryP[512];
snprintf(tryP, 512, "%s%s%d%s", fullRoot.c_str(), szId, i, ext);
if (PlatformFileIO.exists(tryP))
if (PlatformFilesystem.exists(tryP))
count = i;
else
break;
@ -210,7 +210,7 @@ void SoundEngine::play(int iSound, float x, float y, float z, float volume,
}
char tryP[512];
snprintf(tryP, 512, "%s%s%s", fullRoot.c_str(), szId, ext);
if (PlatformFileIO.exists(tryP)) {
if (PlatformFilesystem.exists(tryP)) {
strncpy(finalPath, tryP, 511);
found = true;
break;
@ -250,7 +250,7 @@ void SoundEngine::playUI(int iSound, float volume, float pitch) {
wcstombs(szIdentifier, wchUISoundNames[iSound], 255);
for (int i = 0; szIdentifier[i]; i++)
if (szIdentifier[i] == '.') szIdentifier[i] = '/';
std::string base = PlatformFileIO.getBasePath().string() + "/";
std::string base = PlatformFilesystem.getBasePath().string() + "/";
const char* roots[] = {
"Sound/Minecraft/UI/",
"Sound/Minecraft/",
@ -265,7 +265,7 @@ void SoundEngine::playUI(int iSound, float volume, float pitch) {
char tryP[512];
snprintf(tryP, 512, "%s%s%s%s", base.c_str(), root, szIdentifier,
ext);
if (PlatformFileIO.exists(tryP)) {
if (PlatformFilesystem.exists(tryP)) {
strncpy(finalPath, tryP, 511);
found = true;
break;
@ -452,7 +452,7 @@ void SoundEngine::playMusicTick() {
return;
}
if (m_musicID != -1) {
std::string base = PlatformFileIO.getBasePath().string() + "/";
std::string base = PlatformFilesystem.getBasePath().string() + "/";
bool isCD = (m_musicID >= m_iStream_CD_1);
const char* folder = isCD ? "cds/" : "music/";
const char* track = m_szStreamFileA[m_musicID];
@ -467,13 +467,13 @@ void SoundEngine::playMusicTick() {
// try with folder prefix (music/ or cds/)
snprintf(m_szStreamName, sizeof(m_szStreamName), "%s%s%s%s%s", base.c_str(), r, folder,
track, e);
if (PlatformFileIO.exists(m_szStreamName)) {
if (PlatformFilesystem.exists(m_szStreamName)) {
found = true;
break;
}
// try without folder prefix
snprintf(m_szStreamName, sizeof(m_szStreamName), "%s%s%s%s", base.c_str(), r, track, e);
if (PlatformFileIO.exists(m_szStreamName)) {
if (PlatformFilesystem.exists(m_szStreamName)) {
found = true;
break;
}

View file

@ -20,7 +20,7 @@
#include "app/common/GameRules/GameRuleManager.h"
#include "app/linux/LinuxGame.h"
#include "app/linux/Linux_UIController.h"
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
#include "util/StringHelpers.h"
#include "minecraft/client/Minecraft.h"
#include "minecraft/client/skins/TexturePackRepository.h"
@ -105,14 +105,14 @@ bool readOwnedDlcFile(const std::string& path, std::uint8_t** ppData,
*pBytesRead = 0;
const std::wstring readPath = getMountedDlcReadPath(path);
const std::size_t fSize = PlatformFileIO.fileSize(readPath);
const std::size_t fSize = PlatformFilesystem.fileSize(readPath);
if (fSize == 0 || fSize > std::numeric_limits<unsigned int>::max()) {
return false;
}
std::uint8_t* data = new std::uint8_t[fSize];
auto result = PlatformFileIO.readFile(readPath, data, fSize);
if (result.status != IPlatformFileIO::ReadStatus::Ok) {
auto result = PlatformFilesystem.readFile(readPath, data, fSize);
if (result.status != IPlatformFilesystem::ReadStatus::Ok) {
delete[] data;
return false;
}

View file

@ -30,7 +30,7 @@
#include "minecraft/world/level/dimension/Dimension.h"
#include "minecraft/world/level/levelgen/structure/BoundingBox.h"
#include "minecraft/world/phys/AABB.h"
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
#include "platform/profile/profile.h"
#include "platform/storage/storage.h"
#include "strings.h"
@ -599,10 +599,10 @@ int LevelGenerationOptions::onPackMounted(int iPad, uint32_t dwErr,
uint32_t dwFileSize = grf.length();
if (dwFileSize > 0) {
uint8_t* pbData = (uint8_t*)new uint8_t[dwFileSize];
auto readResult = PlatformFileIO.readFile(
auto readResult = PlatformFilesystem.readFile(
grf.getPath(), pbData, dwFileSize);
if (readResult.status !=
IPlatformFileIO::ReadStatus::Ok) {
IPlatformFilesystem::ReadStatus::Ok) {
app.FatalLoadError();
}
@ -623,12 +623,12 @@ int LevelGenerationOptions::onPackMounted(int iPad, uint32_t dwErr,
lgo->getBaseSavePath(), true, L"WPACK:"));
if (save.exists()) {
std::size_t dwFileSize =
PlatformFileIO.fileSize(save.getPath());
PlatformFilesystem.fileSize(save.getPath());
if (dwFileSize > 0) {
uint8_t* pbData = (uint8_t*)new uint8_t[dwFileSize];
auto readResult = PlatformFileIO.readFile(
auto readResult = PlatformFilesystem.readFile(
save.getPath(), pbData, dwFileSize);
if (readResult.status != IPlatformFileIO::ReadStatus::Ok) {
if (readResult.status != IPlatformFilesystem::ReadStatus::Ok) {
app.FatalLoadError();
}

View file

@ -28,7 +28,7 @@
#include "Socket.h"
#include "platform/XboxStubs.h"
#include "util/StringHelpers.h"
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
#include "minecraft/world/level/storage/ConsoleSaveFileIO/compression.h"
#include "java/File.h"
#include "minecraft/client/Minecraft.h"
@ -160,14 +160,14 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft* minecraft,
File grf(fileRoot);
if (grf.exists()) {
std::size_t dwFileSize =
PlatformFileIO.fileSize(grf.getPath());
PlatformFilesystem.fileSize(grf.getPath());
if (dwFileSize > 0) {
uint8_t* pbData =
(uint8_t*)new uint8_t[dwFileSize];
auto readResult = PlatformFileIO.readFile(
auto readResult = PlatformFilesystem.readFile(
grf.getPath(), pbData, dwFileSize);
if (readResult.status !=
IPlatformFileIO::ReadStatus::Ok) {
IPlatformFilesystem::ReadStatus::Ok) {
app.FatalLoadError();
}

View file

@ -7,7 +7,7 @@
#include "app/linux/LinuxGame.h"
#include "app/linux/Stubs/winapi_stubs.h"
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
#include "minecraft/world/level/storage/ConsoleSaveFileIO/compression.h"
#include "java/InputOutputStream/ByteArrayInputStream.h"
#include "java/InputOutputStream/DataInputStream.h"
@ -117,11 +117,11 @@ std::vector<uint8_t> ArchiveFile::getFile(const std::wstring& filename) {
std::uint8_t* pbData = new std::uint8_t[fileSize == 0 ? 1 : fileSize];
out = std::vector<uint8_t>(pbData, pbData + fileSize);
auto readResult =
PlatformFileIO.readFileSegment(
PlatformFilesystem.readFileSegment(
m_sourcefile.getPath(), static_cast<std::size_t>(data->ptr),
out.data(), static_cast<std::size_t>(data->filesize));
if (readResult.status != IPlatformFileIO::ReadStatus::Ok) {
if (readResult.status != IPlatformFilesystem::ReadStatus::Ok) {
app.DebugPrintf("Failed to read archive file segment\n");
app.FatalLoadError();
}

View file

@ -9,7 +9,7 @@
#include "app/linux/Iggy/include/rrCore.h"
#include "app/linux/LinuxGame.h"
#include "util/StringHelpers.h"
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
UITTFFont::UITTFFont(const std::string& name, const std::string& path,
S32 fallbackCharacter)
@ -17,11 +17,11 @@ UITTFFont::UITTFFont(const std::string& name, const std::string& path,
app.DebugPrintf("UITTFFont opening %s\n", path.c_str());
pbData = nullptr;
const std::size_t fileSize = PlatformFileIO.fileSize(path);
const std::size_t fileSize = PlatformFilesystem.fileSize(path);
if (fileSize != 0) {
pbData = new std::uint8_t[fileSize];
auto result = PlatformFileIO.readFile(path, pbData, fileSize);
if (result.status != IPlatformFileIO::ReadStatus::Ok) {
auto result = PlatformFilesystem.readFile(path, pbData, fileSize);
if (result.status != IPlatformFilesystem::ReadStatus::Ok) {
app.DebugPrintf("Failed to open TTF file\n");
delete[] pbData;
pbData = nullptr;

View file

@ -9,7 +9,7 @@
#include <vector>
#include "util/StringHelpers.h" // 4jcraft TODO
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
#include "java/FileFilter.h"
const wchar_t File::pathSeparator = L'/';
@ -68,7 +68,7 @@ File::File(const std::wstring& pathname) {
while (!request.empty() && request[0] == '/') request.erase(0, 1);
if (request.find("res/") == 0) request.erase(0, 4);
std::string exeDir = PlatformFileIO.getBasePath().string();
std::string exeDir = PlatformFilesystem.getBasePath().string();
std::string fileName = request;
size_t lastSlash = fileName.find_last_of('/');
if (lastSlash != std::string::npos)
@ -84,11 +84,11 @@ File::File(const std::wstring& pathname) {
for (const char* base : bases) {
std::string tryFull = exeDir + base + request;
std::string tryFile = exeDir + base + fileName;
if (PlatformFileIO.exists(tryFull)) {
if (PlatformFilesystem.exists(tryFull)) {
m_abstractPathName = convStringToWstring(tryFull);
return;
}
if (PlatformFileIO.exists(tryFile)) {
if (PlatformFilesystem.exists(tryFile)) {
m_abstractPathName = convStringToWstring(tryFile);
return;
}

View file

@ -14,7 +14,7 @@
#include "app/linux/Stubs/winapi_stubs.h"
#include "PlatformTypes.h"
#include "util/StringHelpers.h"
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
BufferedImage::BufferedImage(int width, int height, int type) {
data[0] = new int[width * height];
@ -61,7 +61,7 @@ BufferedImage::BufferedImage(const std::wstring& File,
baseName = baseName.substr(1);
if (baseName.find(L"res/") == 0) baseName = baseName.substr(4);
std::wstring exeDir = PlatformFileIO.getBasePath().wstring();
std::wstring exeDir = PlatformFilesystem.getBasePath().wstring();
for (int l = 0; l < 10; l++) {
std::wstring mipSuffix =
@ -82,7 +82,7 @@ BufferedImage::BufferedImage(const std::wstring& File,
size_t p;
while ((p = attempt.find(L"//")) != std::wstring::npos)
attempt.replace(p, 2, L"/");
if (PlatformFileIO.exists(attempt)) {
if (PlatformFilesystem.exists(attempt)) {
finalPath = attempt;
foundOnDisk = true;
break;

View file

@ -29,7 +29,7 @@
#include "app/linux/Linux_UIController.h"
#include "app/linux/Stubs/winapi_stubs.h"
#include "minecraft/client/BufferedImage.h"
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
#include "java/File.h"
#include "minecraft/client/Minecraft.h"
#include "minecraft/client/skins/AbstractTexturePack.h"
@ -55,8 +55,8 @@ bool ReadPortableBinaryFile(File& file, std::uint8_t*& data,
const std::size_t capacity = static_cast<std::size_t>(fileLength);
std::uint8_t* buffer = new std::uint8_t[capacity == 0 ? 1 : capacity];
auto readResult =
PlatformFileIO.readFile(file.getPath(), buffer, capacity);
if (readResult.status != IPlatformFileIO::ReadStatus::Ok ||
PlatformFilesystem.readFile(file.getPath(), buffer, capacity);
if (readResult.status != IPlatformFilesystem::ReadStatus::Ok ||
readResult.fileSize > std::numeric_limits<unsigned int>::max()) {
delete[] buffer;
data = nullptr;

View file

@ -8,7 +8,7 @@
#include "app/common/GameRules/LevelGeneration/LevelGenerationOptions.h"
#include "app/linux/LinuxGame.h"
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
#include "minecraft/world/level/biome/Biome.h"
#include "minecraft/world/level/chunk/ChunkSource.h"
#if defined(__linux__)
@ -47,12 +47,12 @@ CustomLevelSource::CustomLevelSource(Level* level, int64_t seed,
{
const char* path = "GameRules/heightmap.bin";
auto result = PlatformFileIO.readFile(
auto result = PlatformFilesystem.readFile(
path, m_heightmapOverride.data(), m_heightmapOverride.size());
if (result.status == IPlatformFileIO::ReadStatus::TooLarge) {
if (result.status == IPlatformFilesystem::ReadStatus::TooLarge) {
Log::info("Heightmap binary is too large!!\n");
__debugbreak();
} else if (result.status != IPlatformFileIO::ReadStatus::Ok) {
} else if (result.status != IPlatformFilesystem::ReadStatus::Ok) {
gameServices().fatalLoadError();
assert(false);
}
@ -63,16 +63,16 @@ CustomLevelSource::CustomLevelSource(Level* level, int64_t seed,
{
const char* waterHeightPath = "GameRules/waterheight.bin";
auto result = PlatformFileIO.readFile(
auto result = PlatformFilesystem.readFile(
waterHeightPath, m_waterheightOverride.data(),
m_waterheightOverride.size());
if (result.status == IPlatformFileIO::ReadStatus::NotFound) {
if (result.status == IPlatformFilesystem::ReadStatus::NotFound) {
memset(m_waterheightOverride.data(), level->seaLevel,
m_waterheightOverride.size());
} else if (result.status == IPlatformFileIO::ReadStatus::TooLarge) {
} else if (result.status == IPlatformFilesystem::ReadStatus::TooLarge) {
Log::info("waterheight binary is too large!!\n");
__debugbreak();
} else if (result.status != IPlatformFileIO::ReadStatus::Ok) {
} else if (result.status != IPlatformFilesystem::ReadStatus::Ok) {
gameServices().fatalLoadError();
}
}

View file

@ -4,7 +4,7 @@
#include <string.h>
#include "minecraft/IGameServices.h"
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
#include "minecraft/world/level/newbiome/layer/Layer.h"
#if defined(__linux__)
#include "app/linux/Stubs/winapi_stubs.h"
@ -16,16 +16,16 @@ BiomeOverrideLayer::BiomeOverrideLayer(int seedMixup) : Layer(seedMixup) {
{
const char* path = "GameRules/biomemap.bin";
auto result = PlatformFileIO.readFile(
auto result = PlatformFilesystem.readFile(
path, m_biomeOverride.data(), m_biomeOverride.size());
if (result.status == IPlatformFileIO::ReadStatus::NotFound) {
if (result.status == IPlatformFilesystem::ReadStatus::NotFound) {
Log::info("Biome override not found, using plains as default\n");
memset(m_biomeOverride.data(), Biome::plains->id,
m_biomeOverride.size());
} else if (result.status == IPlatformFileIO::ReadStatus::TooLarge) {
} else if (result.status == IPlatformFilesystem::ReadStatus::TooLarge) {
Log::info("Biomemap binary is too large!!\n");
__debugbreak();
} else if (result.status != IPlatformFileIO::ReadStatus::Ok) {
} else if (result.status != IPlatformFilesystem::ReadStatus::Ok) {
gameServices().fatalLoadError();
}
}

View file

@ -34,7 +34,7 @@
#include "minecraft/world/level/storage/ConsoleSaveFileIO/FileHeader.h"
#include "minecraft/world/level/storage/LevelData.h"
#include "platform/storage/storage.h"
#include "platform/PlatformServices.h"
#include "platform/fs/fs.h"
#define RESERVE_ALLOCATION MEM_RESERVE
#define COMMIT_ALLOCATION MEM_COMMIT
@ -745,13 +745,13 @@ void ConsoleSaveFileOriginal::DebugFlushToFile(
bool writeSucceeded = false;
if (compressedData != nullptr && compressedDataSize > 0) {
writeSucceeded = PlatformFileIO.writeFile(
writeSucceeded = PlatformFilesystem.writeFile(
outputPath, compressedData, compressedDataSize);
numberOfBytesWritten = writeSucceeded ? compressedDataSize : 0;
assert(numberOfBytesWritten == compressedDataSize);
} else {
writeSucceeded =
PlatformFileIO.writeFile(outputPath, pvSaveMem, fileSize);
PlatformFilesystem.writeFile(outputPath, pvSaveMem, fileSize);
numberOfBytesWritten = writeSucceeded ? fileSize : 0;
assert(numberOfBytesWritten == fileSize);
}

View file

@ -1464,13 +1464,13 @@ void ConsoleSaveFileSplit::DebugFlushToFile(
bool writeSucceeded = false;
if (compressedData != nullptr && compressedDataSize > 0) {
writeSucceeded = PlatformFileIO.writeFile(
writeSucceeded = PlatformFilesystem.writeFile(
outputPath, compressedData, compressedDataSize);
numberOfBytesWritten = writeSucceeded ? compressedDataSize : 0;
assert(numberOfBytesWritten == compressedDataSize);
} else {
writeSucceeded =
PlatformFileIO.writeFile(outputPath, pvSaveMem, fileSize);
PlatformFilesystem.writeFile(outputPath, pvSaveMem, fileSize);
numberOfBytesWritten = writeSucceeded ? fileSize : 0;
assert(numberOfBytesWritten == fileSize);
}

View file

@ -1,6 +1,6 @@
#pragma once
#include "IPlatformFileIO.h"
#include "IPlatformFilesystem.h"
#include "platform/input/input.h"
#include "IPlatformLeaderboard.h"
#include "IPlatformNetwork.h"

View file

@ -1,6 +1 @@
#include "PlatformServices.h"
#include "StdFileIO.h"
static StdFileIO s_stdFileIO;
IPlatformFileIO& PlatformFileIO = s_stdFileIO;
#include "PlatformServices.h"

View file

@ -1,11 +1,4 @@
#pragma once
#include "IPlatformFileIO.h"
#include "IPlatformLeaderboard.h"
#include "IPlatformNetwork.h"
// Interface references to platform services. Game code uses these
// instead of concrete globals directly. Bindings are established
// by the app layer at startup.
extern IPlatformFileIO& PlatformFileIO;

View file

@ -1,92 +0,0 @@
#pragma once
#include "IPlatformFileIO.h"
#include <filesystem>
#include <fstream>
#include <vector>
#if defined(__linux__)
#include <unistd.h>
#endif
// Standard filesystem implementation for desktop platforms.
class StdFileIO : public IPlatformFileIO {
public:
ReadResult readFile(const std::filesystem::path& path, void* buffer,
std::size_t capacity) override {
std::error_code ec;
auto size = std::filesystem::file_size(path, ec);
if (ec) return {ReadStatus::NotFound, 0, 0};
if (size > capacity) return {ReadStatus::TooLarge, 0, static_cast<std::size_t>(size)};
std::ifstream f(path, std::ios::binary);
if (!f) return {ReadStatus::NotFound, 0, 0};
f.read(static_cast<char*>(buffer), static_cast<std::streamsize>(size));
auto read = static_cast<std::size_t>(f.gcount());
return {f ? ReadStatus::Ok : ReadStatus::ReadError, read, static_cast<std::size_t>(size)};
}
ReadResult readFileSegment(const std::filesystem::path& path,
std::size_t offset, void* buffer,
std::size_t bytesToRead) override {
std::error_code ec;
auto size = std::filesystem::file_size(path, ec);
if (ec) return {ReadStatus::NotFound, 0, 0};
if (offset + bytesToRead > size) return {ReadStatus::TooLarge, 0, static_cast<std::size_t>(size)};
std::ifstream f(path, std::ios::binary);
if (!f) return {ReadStatus::NotFound, 0, 0};
f.seekg(static_cast<std::streamoff>(offset));
f.read(static_cast<char*>(buffer), static_cast<std::streamsize>(bytesToRead));
auto read = static_cast<std::size_t>(f.gcount());
return {f ? ReadStatus::Ok : ReadStatus::ReadError, read, static_cast<std::size_t>(size)};
}
std::vector<std::uint8_t> readFileToVec(
const std::filesystem::path& path) override {
std::error_code ec;
auto size = std::filesystem::file_size(path, ec);
if (ec) return {};
std::vector<std::uint8_t> data(static_cast<std::size_t>(size));
std::ifstream f(path, std::ios::binary);
if (!f) return {};
f.read(reinterpret_cast<char*>(data.data()), static_cast<std::streamsize>(size));
return data;
}
bool writeFile(const std::filesystem::path& path, const void* buffer,
std::size_t bytesToWrite) override {
std::ofstream f(path, std::ios::binary);
if (!f) return false;
f.write(static_cast<const char*>(buffer), static_cast<std::streamsize>(bytesToWrite));
return f.good();
}
bool exists(const std::filesystem::path& path) override {
return std::filesystem::exists(path);
}
std::size_t fileSize(const std::filesystem::path& path) override {
std::error_code ec;
auto size = std::filesystem::file_size(path, ec);
return ec ? 0 : static_cast<std::size_t>(size);
}
std::filesystem::path getBasePath() override {
#if defined(__linux__)
char buf[4096];
ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
if (len > 0) {
buf[len] = '\0';
return std::filesystem::path(buf).parent_path();
}
#endif
return std::filesystem::current_path();
}
std::filesystem::path getUserDataPath() override {
return getBasePath();
}
};

View file

@ -6,7 +6,7 @@
#include <vector>
// Platform-agnostic file I/O interface.
class IPlatformFileIO {
class IPlatformFilesystem {
public:
enum class ReadStatus {
Ok,
@ -21,7 +21,7 @@ public:
std::size_t fileSize;
};
virtual ~IPlatformFileIO() = default;
virtual ~IPlatformFilesystem() = default;
// Read an entire file into a caller-provided buffer.
[[nodiscard]] virtual ReadResult readFile(

3
targets/platform/fs/fs.h Normal file
View file

@ -0,0 +1,3 @@
#include "IPlatformFilesystem.h"
extern IPlatformFilesystem& PlatformFilesystem;

View file

@ -0,0 +1,92 @@
#include "StdFilesystem.h"
#include <fstream>
#if defined(__linux__)
#include <unistd.h>
#endif
StdFilesystem std_filesystem_instance;
IPlatformFilesystem& PlatformFilesystem = std_filesystem_instance;
IPlatformFilesystem::ReadResult StdFilesystem::readFile(const std::filesystem::path& path,
void* buffer, std::size_t capacity) {
std::error_code ec;
auto size = std::filesystem::file_size(path, ec);
if (ec) return {ReadStatus::NotFound, 0, 0};
if (size > capacity)
return {ReadStatus::TooLarge, 0, static_cast<std::size_t>(size)};
std::ifstream f(path, std::ios::binary);
if (!f) return {ReadStatus::NotFound, 0, 0};
f.read(static_cast<char*>(buffer), static_cast<std::streamsize>(size));
auto read = static_cast<std::size_t>(f.gcount());
return {f ? ReadStatus::Ok : ReadStatus::ReadError, read,
static_cast<std::size_t>(size)};
}
IPlatformFilesystem::ReadResult StdFilesystem::readFileSegment(const std::filesystem::path& path,
std::size_t offset, void* buffer,
std::size_t bytesToRead) {
std::error_code ec;
auto size = std::filesystem::file_size(path, ec);
if (ec) return {ReadStatus::NotFound, 0, 0};
if (offset + bytesToRead > size)
return {ReadStatus::TooLarge, 0, static_cast<std::size_t>(size)};
std::ifstream f(path, std::ios::binary);
if (!f) return {ReadStatus::NotFound, 0, 0};
f.seekg(static_cast<std::streamoff>(offset));
f.read(static_cast<char*>(buffer),
static_cast<std::streamsize>(bytesToRead));
auto read = static_cast<std::size_t>(f.gcount());
return {f ? ReadStatus::Ok : ReadStatus::ReadError, read,
static_cast<std::size_t>(size)};
}
std::vector<std::uint8_t> StdFilesystem::readFileToVec(
const std::filesystem::path& path) {
std::error_code ec;
auto size = std::filesystem::file_size(path, ec);
if (ec) return {};
std::vector<std::uint8_t> data(static_cast<std::size_t>(size));
std::ifstream f(path, std::ios::binary);
if (!f) return {};
f.read(reinterpret_cast<char*>(data.data()),
static_cast<std::streamsize>(size));
return data;
}
bool StdFilesystem::writeFile(const std::filesystem::path& path,
const void* buffer, std::size_t bytesToWrite) {
std::ofstream f(path, std::ios::binary);
if (!f) return false;
f.write(static_cast<const char*>(buffer),
static_cast<std::streamsize>(bytesToWrite));
return f.good();
}
bool StdFilesystem::exists(const std::filesystem::path& path) {
return std::filesystem::exists(path);
}
std::size_t StdFilesystem::fileSize(const std::filesystem::path& path) {
std::error_code ec;
auto size = std::filesystem::file_size(path, ec);
return ec ? 0 : static_cast<std::size_t>(size);
}
std::filesystem::path StdFilesystem::getBasePath() {
#if defined(__linux__)
char buf[4096];
ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
if (len > 0) {
buf[len] = '\0';
return std::filesystem::path(buf).parent_path();
}
#endif
return std::filesystem::current_path();
}
std::filesystem::path StdFilesystem::getUserDataPath() { return getBasePath(); }

View file

@ -0,0 +1,32 @@
#pragma once
#include "../IPlatformFilesystem.h"
#include <filesystem>
#include <vector>
#include <cstdint>
// Standard filesystem implementation for desktop platforms.
class StdFilesystem : public IPlatformFilesystem {
public:
ReadResult readFile(const std::filesystem::path& path, void* buffer,
std::size_t capacity) override;
ReadResult readFileSegment(const std::filesystem::path& path,
std::size_t offset, void* buffer,
std::size_t bytesToRead) override;
std::vector<std::uint8_t> readFileToVec(
const std::filesystem::path& path) override;
bool writeFile(const std::filesystem::path& path, const void* buffer,
std::size_t bytesToWrite) override;
bool exists(const std::filesystem::path& path) override;
std::size_t fileSize(const std::filesystem::path& path) override;
std::filesystem::path getBasePath() override;
std::filesystem::path getUserDataPath() override;
};

View file

@ -30,6 +30,7 @@ sdl2_sources = files(
'storage/stub/StubStorage.cpp',
'renderer/gl/GLRenderer.cpp',
'renderer/gl/render_stubs.cpp',
'fs/std/StdFilesystem.cpp',
)
lib_platform_sdl2 = static_library('platform_sdl2',

View file

@ -1,4 +1,4 @@
#include "IPlatformRenderer.h"
#include "./gl/GLRenderer.h"
#include "./gl/GLRenderer.h" // 4jcraft TODO: find a way to handle OpenGL stubs through a facade
extern IPlatformRenderer& PlatformRenderer;