mirror of
https://github.com/encounter/aurora.git
synced 2026-07-09 18:19:33 -07:00
Fix handling of Unicode paths on Windows (#166)
* Fix handling of Unicode paths on Windows I love C++ * Reduce the amount of reinterpret_casts * Okay? Don't commit the file CLion? Why not? * Fix texture replacements too
This commit is contained in:
committed by
GitHub
parent
22c2e5e55a
commit
d61a1824ac
+15
-12
@@ -1,6 +1,7 @@
|
||||
#include "CardGciFolder.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include "../fs_helper.hpp"
|
||||
|
||||
#include "Directory.hpp"
|
||||
#include "FileIO.hpp"
|
||||
@@ -102,13 +103,13 @@ ECardResult CardGciFolder::createFile(const char* filename, size_t size, FileHan
|
||||
gciFileHeader->m_blockCount = neededBlocks;
|
||||
gciFileHeader->m_firstBlock = m_bat.allocateBlocks(neededBlocks, maxBlocks);
|
||||
|
||||
m_files.push_back({*gciFileHeader, fileSize, gciFilename, false}); // push non-endian swapped header first
|
||||
m_files.push_back({*gciFileHeader, fileSize, reinterpret_cast<const char8_t*>(gciFilename.c_str()), false}); // push non-endian swapped header first
|
||||
|
||||
handleOut = FileHandle(m_files.size() - 1, 0);
|
||||
|
||||
// write big endian header for dolphin compat
|
||||
gciFileHeader->swapEndian();
|
||||
FileIO file((m_folderPath / gciFilename).string(), true);
|
||||
FileIO file(m_folderPath / gciFilename, true);
|
||||
file.fileWrite(fileBuf.data(), fileBuf.size(), 0);
|
||||
|
||||
return ECardResult::READY;
|
||||
@@ -129,7 +130,7 @@ void CardGciFolder::deleteFile(const FileHandle& fh) {
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
FileIO fileIO((m_folderPath / file->filename).string(), true);
|
||||
FileIO fileIO(m_folderPath / file->filename, true);
|
||||
if (fileIO)
|
||||
fileIO.deleteFile();
|
||||
}
|
||||
@@ -152,7 +153,7 @@ ECardResult CardGciFolder::renameFile(const char* oldName, const char* newName)
|
||||
ECardResult CardGciFolder::fileWrite(FileHandle& fh, const void* buf, size_t size) {
|
||||
auto file = getFile(fh);
|
||||
if (file) {
|
||||
FileIO fileIO((m_folderPath / file->filename).string());
|
||||
FileIO fileIO(m_folderPath / file->filename);
|
||||
if (fileIO) {
|
||||
if (fileIO.fileWrite(buf, size, sizeof(File) + fh.offset))
|
||||
return ECardResult::READY;
|
||||
@@ -167,7 +168,7 @@ ECardResult CardGciFolder::fileWrite(FileHandle& fh, const void* buf, size_t siz
|
||||
ECardResult CardGciFolder::fileRead(FileHandle& fh, void* dst, size_t size) {
|
||||
auto file = getFile(fh);
|
||||
if (file) {
|
||||
FileIO fileIO((m_folderPath / file->filename).string());
|
||||
FileIO fileIO(m_folderPath / file->filename);
|
||||
if (fileIO) {
|
||||
if (fileIO.fileRead(dst, size, sizeof(File) + fh.offset))
|
||||
return ECardResult::READY;
|
||||
@@ -320,14 +321,14 @@ void CardGciFolder::format(ECardSlot deviceId, ECardSize size, EEncoding encodin
|
||||
m_encoding = encoding;
|
||||
|
||||
if (!std::filesystem::create_directories(m_folderPath)) {
|
||||
Log.error("Failed to create directory: {}", m_folderPath.string());
|
||||
Log.error("Failed to create directory: {}", fs_path_to_string(m_folderPath));
|
||||
}
|
||||
}
|
||||
|
||||
void CardGciFolder::commit() {
|
||||
for (auto& gciFile : m_files) {
|
||||
if (gciFile.opened) {
|
||||
FileIO file((m_folderPath / gciFile.filename).string());
|
||||
FileIO file(m_folderPath / gciFile.filename);
|
||||
|
||||
File tempFile = gciFile.file;
|
||||
tempFile.swapEndian();
|
||||
@@ -336,7 +337,7 @@ void CardGciFolder::commit() {
|
||||
}
|
||||
}
|
||||
|
||||
bool CardGciFolder::open(std::string_view filepath) {
|
||||
bool CardGciFolder::open(const std::filesystem::path& filepath) {
|
||||
m_folderPath = filepath;
|
||||
|
||||
if (!std::filesystem::exists(filepath) || !std::filesystem::is_directory(filepath))
|
||||
@@ -351,13 +352,13 @@ bool CardGciFolder::open(std::string_view filepath) {
|
||||
if (path.extension() != ".gci")
|
||||
continue;
|
||||
|
||||
FileIO file(path.string());
|
||||
FileIO file(path);
|
||||
|
||||
File fileData;
|
||||
file.fileRead((void*)&fileData, sizeof(File), 0);
|
||||
fileData.swapEndian();
|
||||
|
||||
m_files.push_back({fileData, file.fileSize(), path.filename().string(), false});
|
||||
m_files.push_back({fileData, file.fileSize(), path.filename().u8string(), false});
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -369,11 +370,13 @@ void CardGciFolder::close() {
|
||||
m_bat = BlockAllocationTable();
|
||||
}
|
||||
|
||||
std::string_view CardGciFolder::cardFilename() const { return ""; }
|
||||
static std::filesystem::path g_cardFileNameEmpty = "";
|
||||
|
||||
const std::filesystem::path& CardGciFolder::cardFilename() const { return g_cardFileNameEmpty; }
|
||||
|
||||
ECardResult CardGciFolder::getError() const { return ECardResult::READY; }
|
||||
|
||||
ProbeResults CardGciFolder::probeCardFile(std::string_view filename) {
|
||||
ProbeResults CardGciFolder::probeCardFile(const std::filesystem::path& filename) {
|
||||
if (!std::filesystem::exists(filename) || !std::filesystem::is_directory(filename))
|
||||
return {ECardResult::NOCARD, 0, 0};
|
||||
return {ECardResult::READY, static_cast<uint32_t>(ECardSize::Card2043Mb), BlockSize};
|
||||
|
||||
@@ -14,7 +14,7 @@ private:
|
||||
struct GciFile {
|
||||
File file;
|
||||
size_t fileSize;
|
||||
std::string filename;
|
||||
std::u8string filename;
|
||||
bool opened = false;
|
||||
};
|
||||
|
||||
@@ -67,11 +67,11 @@ public:
|
||||
void getEncoding(uint16_t& encoding) const override;
|
||||
void format(ECardSlot deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII) override;
|
||||
void commit() override;
|
||||
bool open(std::string_view filepath) override;
|
||||
bool open(const std::filesystem::path& filepath) override;
|
||||
void close() override;
|
||||
std::string_view cardFilename() const override;
|
||||
const std::filesystem::path& cardFilename() const override;
|
||||
ECardResult getError() const override;
|
||||
ProbeResults probeCardFile(std::string_view filename) override;
|
||||
ProbeResults probeCardFile(const std::filesystem::path& filename) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -761,7 +761,7 @@ void CardRawFile::format(ECardSlot id, ECardSize size, EEncoding encoding) {
|
||||
m_currentBat = 1;
|
||||
|
||||
m_fileHandle = {};
|
||||
m_fileHandle = FileIO(m_filename.c_str(), true);
|
||||
m_fileHandle = FileIO(m_filename, true);
|
||||
|
||||
if (m_fileHandle) {
|
||||
const uint32_t blockCount = (static_cast<uint32_t>(size) * MbitToBlocks) - 5;
|
||||
@@ -790,11 +790,10 @@ void CardRawFile::format(ECardSlot id, ECardSize size, EEncoding encoding) {
|
||||
}
|
||||
}
|
||||
|
||||
ProbeResults CardRawFile::probeCardFile(std::string_view filename) {
|
||||
std::filesystem::path path(filename);
|
||||
if (!std::filesystem::exists(path))
|
||||
ProbeResults CardRawFile::probeCardFile(const std::filesystem::path& filename) {
|
||||
if (!std::filesystem::exists(filename))
|
||||
return {ECardResult::NOCARD, 0, 0};
|
||||
return {ECardResult::READY, static_cast<uint32_t>(std::filesystem::file_size(path) / BlockSize) / MbitToBlocks,
|
||||
return {ECardResult::READY, static_cast<uint32_t>(std::filesystem::file_size(filename) / BlockSize) / MbitToBlocks,
|
||||
BlockSize};
|
||||
}
|
||||
|
||||
@@ -825,7 +824,7 @@ void CardRawFile::commit() {
|
||||
}
|
||||
}
|
||||
|
||||
bool CardRawFile::open(std::string_view filepath) {
|
||||
bool CardRawFile::open(const std::filesystem::path& filepath) {
|
||||
m_opened = false;
|
||||
m_filename = filepath;
|
||||
m_fileHandle = FileIO(m_filename);
|
||||
|
||||
@@ -42,7 +42,7 @@ class CardRawFile : public ICard {
|
||||
CardHeader m_ch;
|
||||
CardHeader m_tmpCh;
|
||||
|
||||
std::string m_filename;
|
||||
std::filesystem::path m_filename;
|
||||
FileIO m_fileHandle;
|
||||
std::array<Directory, 2> m_dirs;
|
||||
std::array<BlockAllocationTable, 2> m_bats;
|
||||
@@ -398,7 +398,7 @@ public:
|
||||
*
|
||||
* @return ProbeResults structure.
|
||||
*/
|
||||
ProbeResults probeCardFile(std::string_view filename) override;
|
||||
ProbeResults probeCardFile(const std::filesystem::path& filename) override;
|
||||
|
||||
/**
|
||||
* @brief Writes any changes to the Card instance immediately to disk. <br />
|
||||
@@ -409,7 +409,7 @@ public:
|
||||
/**
|
||||
* @brief Opens card image (does nothing if currently open path matches).
|
||||
*/
|
||||
bool open(std::string_view filepath) override;
|
||||
bool open(const std::filesystem::path& filepath) override;
|
||||
|
||||
/**
|
||||
* @brief Commits changes to disk and closes host file.
|
||||
@@ -421,7 +421,7 @@ public:
|
||||
*
|
||||
* @return A view to the card's filename.
|
||||
*/
|
||||
std::string_view cardFilename() const override { return m_filename; }
|
||||
const std::filesystem::path& cardFilename() const override { return m_filename; }
|
||||
|
||||
/**
|
||||
* @brief Gets card-scope error state.
|
||||
|
||||
+6
-3
@@ -6,13 +6,15 @@
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
#include "../fs_helper.hpp"
|
||||
|
||||
namespace aurora::card {
|
||||
|
||||
FileIO::FileIO(std::string_view filename, bool truncate) {
|
||||
m_path = filename;
|
||||
FileIO::FileIO(const std::filesystem::path& filename, bool truncate) {
|
||||
m_path = fs_path_to_string(filename);;
|
||||
SDL_IOStream* stream = nullptr;
|
||||
|
||||
stream = fileOpen(m_path.c_str(), truncate ? "w+b" : "r+b");
|
||||
stream = fileOpen(m_path, truncate ? "w+b" : "r+b");
|
||||
|
||||
if (stream != nullptr) {
|
||||
SDL_FlushIO(stream);
|
||||
@@ -101,6 +103,7 @@ bool FileIO::fileWrite(const void* buf, size_t length, off_t offset) {
|
||||
|
||||
size_t FileIO::fileSize() const {
|
||||
SDL_PathInfo info;
|
||||
const auto tr = fs_path_to_string(m_path);
|
||||
if (SDL_GetPathInfo(m_path.c_str(), &info)) {
|
||||
return info.size;
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
#include <SDL3/SDL_iostream.h>
|
||||
|
||||
@@ -15,7 +16,7 @@ class FileIO {
|
||||
|
||||
public:
|
||||
FileIO() = default;
|
||||
explicit FileIO(std::string_view filename, bool truncate = false);
|
||||
explicit FileIO(const std::filesystem::path& filename, bool truncate = false);
|
||||
~FileIO() = default;
|
||||
|
||||
FileIO(FileIO&& other) noexcept;
|
||||
|
||||
+4
-3
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Util.hpp"
|
||||
#include <filesystem>
|
||||
|
||||
namespace aurora::card {
|
||||
class ICard {
|
||||
@@ -35,10 +36,10 @@ public:
|
||||
virtual void getEncoding(uint16_t& encoding) const = 0;
|
||||
virtual void format(ECardSlot deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII) = 0;
|
||||
virtual void commit() = 0;
|
||||
virtual bool open(std::string_view filepath) = 0;
|
||||
virtual bool open(const std::filesystem::path& filepath) = 0;
|
||||
virtual void close() = 0;
|
||||
virtual std::string_view cardFilename() const = 0;
|
||||
virtual const std::filesystem::path& cardFilename() const = 0;
|
||||
virtual ECardResult getError() const = 0;
|
||||
virtual ProbeResults probeCardFile(std::string_view filename) = 0;
|
||||
virtual ProbeResults probeCardFile(const std::filesystem::path& filename) = 0;
|
||||
};
|
||||
}
|
||||
+18
-16
@@ -9,11 +9,12 @@
|
||||
#include "../card/DolphinCardPath.hpp"
|
||||
#include "../logging.hpp"
|
||||
#include "../card/CardGciFolder.hpp"
|
||||
#include "../fs_helper.hpp"
|
||||
|
||||
namespace {
|
||||
aurora::Module Log("aurora::card");
|
||||
std::array<std::unique_ptr<aurora::card::ICard>, 2> CardChannels = {{}};
|
||||
std::array<std::string, 2> cardPaths;
|
||||
std::array<std::filesystem::path, 2> cardPaths;
|
||||
|
||||
constexpr uint16_t CARD_SECTOR_SIZE = 8192;
|
||||
|
||||
@@ -48,16 +49,14 @@ aurora::card::FileHandle CreateKabuFileHandleFromDolphin(const CARDFileInfo* fil
|
||||
return aurora::card::FileHandle{static_cast<u32>(fileInfo->fileNo), fileInfo->offset};
|
||||
}
|
||||
|
||||
std::string GetCardFullPath(const std::string& path, const aurora::card::ECardSlot slot) {
|
||||
std::filesystem::path GetCardFullPath(const std::filesystem::path& path, const aurora::card::ECardSlot slot) {
|
||||
if (path.empty())
|
||||
return "";
|
||||
|
||||
std::filesystem::path filePath(path);
|
||||
|
||||
if (CARD_USE_GCI_FOLDER) {
|
||||
return (filePath / GetCardRegion() / (slot == aurora::card::ECardSlot::SlotA ? "Card A" : "Card B")).string();
|
||||
return path / GetCardRegion() / (slot == aurora::card::ECardSlot::SlotA ? "Card A" : "Card B");
|
||||
} else {
|
||||
return (filePath / fmt::format("MemoryCard{}.{}.raw", slot == aurora::card::ECardSlot::SlotA ? "A" : "B", GetCardRegion())).string();
|
||||
return path / fmt::format("MemoryCard{}.{}.raw", slot == aurora::card::ECardSlot::SlotA ? "A" : "B", GetCardRegion());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
@@ -114,7 +113,7 @@ void CARDDetectDolphin(const s32 chan) {
|
||||
Log.error("Failed to detect Dolphin Card!");
|
||||
return;
|
||||
}
|
||||
Log.info("Detected Dolphin Card at: {}", cardPaths[chan]);
|
||||
Log.info("Detected Dolphin Card at: {}", fs_path_to_string(cardPaths[chan]));
|
||||
} else {
|
||||
cardPaths[0] = aurora::card::ResolveDolphinCardPath(aurora::card::ECardSlot::SlotA, GetCardRegion(), CARD_USE_GCI_FOLDER);
|
||||
cardPaths[1] = aurora::card::ResolveDolphinCardPath(aurora::card::ECardSlot::SlotB, GetCardRegion(), CARD_USE_GCI_FOLDER);
|
||||
@@ -124,7 +123,10 @@ void CARDDetectDolphin(const s32 chan) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.info("Detected Dolphin Card at: {} and {}", cardPaths[0], cardPaths[1]);
|
||||
Log.info(
|
||||
"Detected Dolphin Card at: {} and {}",
|
||||
fs_path_to_string(cardPaths[0]),
|
||||
fs_path_to_string(cardPaths[1]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,14 +139,14 @@ void CARDSetBasePath(const char* path, const s32 chan) {
|
||||
|
||||
if (filePath.has_filename() && !std::filesystem::is_directory(filePath)) {
|
||||
filePath = filePath.remove_filename();
|
||||
Log.warn("Path supplied a filename, discarding. New Path: {}", filePath.string());
|
||||
Log.warn("Path supplied a filename, discarding. New Path: {}", fs_path_to_string(filePath));
|
||||
}
|
||||
|
||||
if (chan == 0 || chan == 1) {
|
||||
cardPaths[chan] = GetCardFullPath(filePath.string(), static_cast<aurora::card::ECardSlot>(chan));
|
||||
cardPaths[chan] = GetCardFullPath(filePath, static_cast<aurora::card::ECardSlot>(chan));
|
||||
} else {
|
||||
cardPaths[0] = GetCardFullPath(filePath.string(), aurora::card::ECardSlot::SlotA);
|
||||
cardPaths[1] = GetCardFullPath(filePath.string(), aurora::card::ECardSlot::SlotB);
|
||||
cardPaths[0] = GetCardFullPath(filePath, aurora::card::ECardSlot::SlotA);
|
||||
cardPaths[1] = GetCardFullPath(filePath, aurora::card::ECardSlot::SlotB);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,11 +173,11 @@ void CARDInit(const char* game, const char* maker) {
|
||||
CardChannels[i]->InitCard(game, maker);
|
||||
}
|
||||
|
||||
std::string cardWorkingDir;
|
||||
std::filesystem::path cardWorkingDir;
|
||||
if (aurora::g_config.configPath != nullptr)
|
||||
cardWorkingDir = aurora::g_config.configPath;
|
||||
cardWorkingDir = reinterpret_cast<const char8_t*>(aurora::g_config.configPath);
|
||||
else
|
||||
cardWorkingDir = std::filesystem::current_path().string();
|
||||
cardWorkingDir = std::filesystem::current_path();
|
||||
|
||||
bool loadedCard = false;
|
||||
|
||||
@@ -190,7 +192,7 @@ void CARDInit(const char* game, const char* maker) {
|
||||
if (std::filesystem::exists(curPath)) {
|
||||
CardChannels[i]->open(curPath);
|
||||
loadedCard = true;
|
||||
Log.info("Loaded GC Card Image: {}", curPath);
|
||||
Log.info("Loaded GC Card Image: {}", fs_path_to_string(curPath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
/**
|
||||
* Converts a std::filesystem::path to a std::string, UTF-8, without exploding on Windows.
|
||||
*/
|
||||
inline std::string fs_path_to_string(const std::filesystem::path& path) {
|
||||
const auto u8str = path.u8string();
|
||||
return { reinterpret_cast<const char*>(u8str.c_str()) };
|
||||
}
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "../fs_helper.hpp"
|
||||
|
||||
using namespace aurora::gx;
|
||||
using aurora::webgpu::g_device;
|
||||
|
||||
@@ -371,7 +373,7 @@ std::optional<RuntimeTextureKey> parse_replacement_filename(std::string_view fil
|
||||
std::optional<ConvertedTexture> load_replacement(const std::filesystem::path& path, bool hasMips) noexcept {
|
||||
auto base = dds::load_dds_file(path);
|
||||
if (!base.has_value()) {
|
||||
Log.warn("texture_replacement: failed to load texture {}", path.string());
|
||||
Log.warn("texture_replacement: failed to load texture {}", fs_path_to_string(path.string()));
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!hasMips) {
|
||||
@@ -393,9 +395,9 @@ std::optional<ConvertedTexture> load_replacement(const std::filesystem::path& pa
|
||||
if (!ok) {
|
||||
if (more.empty()) {
|
||||
if (!lvl.has_value()) {
|
||||
Log.warn("texture_replacement: could not load mip {}", mipPath.string());
|
||||
Log.warn("texture_replacement: could not load mip {}", fs_path_to_string(mipPath));
|
||||
} else {
|
||||
Log.warn("texture_replacement: expected {}x{} for mip {}, got {}x{}", mipPath.string(), ew, eh, lvl->width, lvl->height);
|
||||
Log.warn("texture_replacement: expected {}x{} for mip {}, got {}x{}", fs_path_to_string(mipPath), ew, eh, lvl->width, lvl->height);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -474,8 +476,10 @@ void build_index() noexcept {
|
||||
return;
|
||||
}
|
||||
|
||||
s_replacementRoot = std::filesystem::path{g_config.configPath} / "texture_replacements";
|
||||
s_dumpRoot = std::filesystem::path{g_config.configPath} / "texture_dumps";
|
||||
auto configPath = std::filesystem::path{reinterpret_cast<const char8_t*>(g_config.configPath)};
|
||||
|
||||
s_replacementRoot = configPath / "texture_replacements";
|
||||
s_dumpRoot = configPath / "texture_dumps";
|
||||
|
||||
if (!ensure_directory(s_replacementRoot)) {
|
||||
return;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
#include "../fs_helper.hpp"
|
||||
#include "../internal.hpp"
|
||||
#include "../sqlite_utils.hpp"
|
||||
|
||||
@@ -91,7 +92,7 @@ INSERT INTO aurora_schema VALUES ({});)",
|
||||
static bool cache_init_core() {
|
||||
Log.debug("SQLite version {}", sqlite3_libversion());
|
||||
|
||||
std::string file = (std::filesystem::path{g_config.configPath} / "dawn_cache.db").string();
|
||||
std::string file = fs_path_to_string(std::filesystem::path{reinterpret_cast<const char8_t*>(g_config.configPath)} / "dawn_cache.db");
|
||||
Log.debug("Using dawn cache at {}", file);
|
||||
auto ret = sqlite3_open(file.c_str(), &db);
|
||||
if (ret != SQLITE_OK) {
|
||||
|
||||
Reference in New Issue
Block a user