#include "FileInterface_SDL.h" #include "../logging.hpp" #include #include #include #include namespace aurora::rmlui { namespace { Module Log("aurora::rmlui::FileInterface"); 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; } const char* basePath = SDL_GetBasePath(); if (basePath == nullptr || basePath[0] == '\0') { return path; } return std::string(basePath) + path; } } // namespace Rml::FileHandle FileInterface_SDL::Open(const Rml::String& path) { const std::string resolvedPath = resolve_path(path); SDL_IOStream* stream = SDL_IOFromFile(resolvedPath.c_str(), "rb"); if (stream == nullptr) { Log.error("Failed to open file '{}': {}", resolvedPath, SDL_GetError()); return {}; } return reinterpret_cast(stream); } void FileInterface_SDL::Close(Rml::FileHandle file) { if (auto* stream = reinterpret_cast(file)) { SDL_CloseIO(stream); } } size_t FileInterface_SDL::Read(void* buffer, size_t size, Rml::FileHandle file) { auto* stream = reinterpret_cast(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); return 0; } size_t total = 0; auto* dst = static_cast(buffer); while (total < size) { const size_t read = SDL_ReadIO(stream, dst + total, size - total); if (read == 0) { if (SDL_GetIOStatus(stream) == SDL_IO_STATUS_EOF) { return total; } Log.error("Failed to read {} bytes after {} bytes: {}", size, total, SDL_GetError()); return total; } total += read; } return total; } bool FileInterface_SDL::Seek(Rml::FileHandle file, long offset, int origin) { auto* stream = reinterpret_cast(file); if (stream == nullptr) { Log.warn("Attempted to seek null file handle"); return false; } if (SDL_SeekIO(stream, offset, static_cast(origin)) < 0) { Log.warn("Failed to seek to offset {} from origin {}: {}", offset, origin, SDL_GetError()); return false; } return true; } size_t FileInterface_SDL::Tell(Rml::FileHandle file) { auto* stream = reinterpret_cast(file); if (stream == nullptr) { Log.warn("Attempted to tell with null file handle"); return 0; } const Sint64 position = SDL_TellIO(stream); if (position < 0) { Log.warn("Failed to tell file position: {}", SDL_GetError()); return 0; } return static_cast(position); } size_t FileInterface_SDL::Length(Rml::FileHandle file) { auto* stream = reinterpret_cast(file); if (stream == nullptr) { Log.warn("Attempted to get length with null file handle"); return 0; } const Sint64 size = SDL_GetIOSize(stream); if (size < 0) { Log.warn("Failed to get file length: {}", SDL_GetError()); return 0; } return static_cast(size); } } // namespace aurora::rmlui