2026-05-03 17:46:34 -07:00
|
|
|
#include "FileInterface_SDL.h"
|
|
|
|
|
|
|
|
|
|
#include "../logging.hpp"
|
|
|
|
|
|
2026-05-27 19:27:57 -05:00
|
|
|
#include <aurora/aurora.h>
|
|
|
|
|
|
2026-05-04 18:25:33 -06:00
|
|
|
#include <SDL3/SDL_filesystem.h>
|
|
|
|
|
#include <SDL3/SDL_iostream.h>
|
2026-05-03 17:46:34 -07:00
|
|
|
|
2026-05-04 18:25:33 -06:00
|
|
|
#include <string>
|
|
|
|
|
#include <string_view>
|
|
|
|
|
|
|
|
|
|
namespace aurora::rmlui {
|
2026-05-03 17:46:34 -07:00
|
|
|
namespace {
|
2026-05-04 18:25:33 -06:00
|
|
|
|
2026-05-03 17:46:34 -07:00
|
|
|
Module Log("aurora::rmlui::FileInterface");
|
2026-05-04 18:25:33 -06:00
|
|
|
|
|
|
|
|
bool is_absolute_path(std::string_view path) {
|
|
|
|
|
if (path.empty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (path.front() == '/' || path.front() == '\\') {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return path.size() >= 3 && path[1] == ':' && (path[2] == '/' || path[2] == '\\');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr std::string_view FileScheme = "file://";
|
|
|
|
|
|
|
|
|
|
std::string resolve_path(const Rml::String& source) {
|
|
|
|
|
std::string path(source);
|
|
|
|
|
if (path.compare(0, FileScheme.size(), FileScheme) == 0) {
|
|
|
|
|
path.erase(0, FileScheme.size());
|
|
|
|
|
}
|
|
|
|
|
if (path.empty() || is_absolute_path(path)) {
|
|
|
|
|
return path;
|
|
|
|
|
}
|
2026-05-27 19:27:57 -05:00
|
|
|
const char* basePath = g_config.resourcesPath;
|
2026-05-04 18:25:33 -06:00
|
|
|
if (basePath == nullptr || basePath[0] == '\0') {
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
return std::string(basePath) + path;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-03 17:46:34 -07:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
Rml::FileHandle FileInterface_SDL::Open(const Rml::String& path) {
|
2026-05-04 18:25:33 -06:00
|
|
|
const std::string resolvedPath = resolve_path(path);
|
|
|
|
|
SDL_IOStream* stream = SDL_IOFromFile(resolvedPath.c_str(), "rb");
|
2026-05-03 17:46:34 -07:00
|
|
|
if (stream == nullptr) {
|
2026-05-04 18:25:33 -06:00
|
|
|
Log.error("Failed to open file '{}': {}", resolvedPath, SDL_GetError());
|
|
|
|
|
return {};
|
2026-05-03 17:46:34 -07:00
|
|
|
}
|
2026-05-04 18:25:33 -06:00
|
|
|
return reinterpret_cast<Rml::FileHandle>(stream);
|
2026-05-03 17:46:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FileInterface_SDL::Close(Rml::FileHandle file) {
|
2026-05-04 18:25:33 -06:00
|
|
|
if (auto* stream = reinterpret_cast<SDL_IOStream*>(file)) {
|
2026-05-03 17:46:34 -07:00
|
|
|
SDL_CloseIO(stream);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t FileInterface_SDL::Read(void* buffer, size_t size, Rml::FileHandle file) {
|
2026-05-04 18:25:33 -06:00
|
|
|
auto* stream = reinterpret_cast<SDL_IOStream*>(file);
|
|
|
|
|
if (stream == nullptr) {
|
|
|
|
|
Log.warn("Attempted to read with null file handle");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (buffer == nullptr && size > 0) {
|
|
|
|
|
Log.warn("Attempted to read {} bytes into null buffer", size);
|
2026-05-03 17:46:34 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t total = 0;
|
|
|
|
|
auto* dst = static_cast<uint8_t*>(buffer);
|
|
|
|
|
while (total < size) {
|
|
|
|
|
const size_t read = SDL_ReadIO(stream, dst + total, size - total);
|
|
|
|
|
if (read == 0) {
|
2026-05-04 18:25:33 -06:00
|
|
|
if (SDL_GetIOStatus(stream) == SDL_IO_STATUS_EOF) {
|
2026-05-03 17:46:34 -07:00
|
|
|
return total;
|
|
|
|
|
}
|
2026-05-04 18:25:33 -06:00
|
|
|
Log.error("Failed to read {} bytes after {} bytes: {}", size, total, SDL_GetError());
|
|
|
|
|
return total;
|
2026-05-03 17:46:34 -07:00
|
|
|
}
|
|
|
|
|
total += read;
|
|
|
|
|
}
|
|
|
|
|
return total;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FileInterface_SDL::Seek(Rml::FileHandle file, long offset, int origin) {
|
2026-05-04 18:25:33 -06:00
|
|
|
auto* stream = reinterpret_cast<SDL_IOStream*>(file);
|
|
|
|
|
if (stream == nullptr) {
|
|
|
|
|
Log.warn("Attempted to seek null file handle");
|
|
|
|
|
return false;
|
2026-05-03 17:46:34 -07:00
|
|
|
}
|
2026-05-04 18:25:33 -06:00
|
|
|
if (SDL_SeekIO(stream, offset, static_cast<SDL_IOWhence>(origin)) < 0) {
|
|
|
|
|
Log.warn("Failed to seek to offset {} from origin {}: {}", offset, origin, SDL_GetError());
|
2026-05-03 17:46:34 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t FileInterface_SDL::Tell(Rml::FileHandle file) {
|
2026-05-04 18:25:33 -06:00
|
|
|
auto* stream = reinterpret_cast<SDL_IOStream*>(file);
|
|
|
|
|
if (stream == nullptr) {
|
|
|
|
|
Log.warn("Attempted to tell with null file handle");
|
2026-05-03 17:46:34 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
2026-05-04 18:25:33 -06:00
|
|
|
const Sint64 position = SDL_TellIO(stream);
|
|
|
|
|
if (position < 0) {
|
|
|
|
|
Log.warn("Failed to tell file position: {}", SDL_GetError());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return static_cast<size_t>(position);
|
2026-05-03 17:46:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t FileInterface_SDL::Length(Rml::FileHandle file) {
|
2026-05-04 18:25:33 -06:00
|
|
|
auto* stream = reinterpret_cast<SDL_IOStream*>(file);
|
|
|
|
|
if (stream == nullptr) {
|
|
|
|
|
Log.warn("Attempted to get length with null file handle");
|
2026-05-03 17:46:34 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
2026-05-04 18:25:33 -06:00
|
|
|
const Sint64 size = SDL_GetIOSize(stream);
|
|
|
|
|
if (size < 0) {
|
|
|
|
|
Log.warn("Failed to get file length: {}", SDL_GetError());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return static_cast<size_t>(size);
|
2026-05-03 17:46:34 -07:00
|
|
|
}
|
|
|
|
|
|
2026-05-03 22:12:46 -06:00
|
|
|
} // namespace aurora::rmlui
|