mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 02:47:02 +02:00
handle UTF-8 command-line paths
This commit is contained in:
+17
-12
@@ -245,28 +245,33 @@ void File::Printf(const char* format, ...) {
|
||||
Write(s.data(), static_cast<uint32_t>(s.size()));
|
||||
}
|
||||
|
||||
static std::filesystem::path WithoutTrailingSeparator(
|
||||
const std::filesystem::path& path) {
|
||||
if (!path.empty() && !path.has_filename() &&
|
||||
path != path.root_path()) {
|
||||
return path.parent_path();
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
bool File::IsDirectoryExisting(const std::filesystem::path& path) {
|
||||
auto path_str = PathToGenericString(path);
|
||||
return SysFileIsDirectoryExisting(path_str.ends_with("/") ? Common::RemoveLast(path_str, 1)
|
||||
: path_str);
|
||||
return SysFileIsDirectoryExisting(WithoutTrailingSeparator(path));
|
||||
}
|
||||
|
||||
bool File::IsFileExisting(const std::filesystem::path& name) {
|
||||
return SysFileIsFileExisting(name);
|
||||
}
|
||||
|
||||
bool File::CreateDirectory(
|
||||
const std::filesystem::path& path) // @suppress("Member declaration not found")
|
||||
{
|
||||
auto path_str = PathToGenericString(path);
|
||||
return SysFileCreateDirectory(path_str.ends_with("/") ? Common::RemoveLast(path_str, 1)
|
||||
: path_str);
|
||||
bool File::CreateDirectory(const std::filesystem::path& path) {
|
||||
return SysFileCreateDirectory(
|
||||
WithoutTrailingSeparator(path));
|
||||
}
|
||||
|
||||
bool File::DeleteDirectory(const std::filesystem::path& path) {
|
||||
auto path_str = PathToGenericString(path);
|
||||
return SysFileDeleteDirectory(path_str.ends_with("/") ? Common::RemoveLast(path_str, 1)
|
||||
: path_str);
|
||||
return SysFileDeleteDirectory(
|
||||
WithoutTrailingSeparator(path));
|
||||
}
|
||||
|
||||
bool File::CreateDirectories(const std::filesystem::path& path) {
|
||||
|
||||
@@ -34,6 +34,23 @@ inline std::string PathToGenericString(const std::filesystem::path& path) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline std::filesystem::path PathFromUtf8(std::string_view text) {
|
||||
#if defined(__cpp_char8_t)
|
||||
std::u8string utf8;
|
||||
utf8.reserve(text.size());
|
||||
|
||||
for (const char ch: text) {
|
||||
utf8.push_back(
|
||||
static_cast<char8_t>(static_cast<unsigned char>(ch))
|
||||
);
|
||||
}
|
||||
|
||||
return std::filesystem::path(utf8);
|
||||
#else
|
||||
return std::filesystem::u8path(text.begin(), text.end());
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool EqualNoCase(std::string_view lhs, std::string_view rhs) {
|
||||
if (lhs.size() != rhs.size()) {
|
||||
return false;
|
||||
|
||||
@@ -251,16 +251,15 @@ void FileDescriptors::CloseAll() {
|
||||
void MountPoints::Mount(const std::filesystem::path& folder, const std::string& point) {
|
||||
Common::LockGuard lock(m_mutex);
|
||||
|
||||
auto folder_str = Common::FixDirectorySlash(Common::PathToGenericString(folder));
|
||||
auto point_str = Common::FixDirectorySlash(point);
|
||||
|
||||
Umount(point_str);
|
||||
|
||||
MountPair p;
|
||||
p.dir = folder_str;
|
||||
p.dir = folder;
|
||||
p.point = point_str;
|
||||
|
||||
m_mount_pairs.push_back(p);
|
||||
m_mount_pairs.push_back(std::move(p));
|
||||
}
|
||||
|
||||
void MountPoints::Umount(const std::string& folder_or_point) {
|
||||
@@ -343,14 +342,17 @@ std::filesystem::path MountPoints::ResolvePath(const std::string& mounted_name)
|
||||
while (rel_path.starts_with('/')) {
|
||||
rel_path = Common::RemoveFirst(rel_path, 1);
|
||||
}
|
||||
|
||||
const auto native_rel_path = Common::PathFromUtf8(rel_path);
|
||||
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
if (HasWindowsForbiddenFilenameCharacter(rel_path)) {
|
||||
::printf("FileSystem: Windows-incompatible guest filename: %s\n",
|
||||
mounted_name.c_str());
|
||||
}
|
||||
return p.dir / rel_path;
|
||||
return p.dir / native_rel_path;
|
||||
#else
|
||||
return ResolvePathIgnoringCase(p.dir / rel_path);
|
||||
return ResolvePathIgnoringCase(p.dir / native_rel_path);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+49
-10
@@ -10,6 +10,8 @@
|
||||
|
||||
#include <charconv>
|
||||
#include <cstdio>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <fmt/format.h>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
@@ -207,15 +209,19 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
||||
}
|
||||
|
||||
value = Common::FixFilenameSlash(value);
|
||||
if (Common::File::IsDirectoryExisting(value)) {
|
||||
options.app0_dir = value;
|
||||
const auto path = Common::PathFromUtf8(value);
|
||||
|
||||
if (Common::File::IsDirectoryExisting(path)) {
|
||||
options.app0_dir = path;
|
||||
options.elf = "/app0/eboot.bin";
|
||||
} else if (Common::File::IsFileExisting(value)) {
|
||||
options.app0_dir = Common::DirectoryWithoutFilename(value);
|
||||
} else if (Common::File::IsFileExisting(path)) {
|
||||
options.app0_dir = path.parent_path();
|
||||
|
||||
if (options.app0_dir.empty()) {
|
||||
options.app0_dir = ".";
|
||||
}
|
||||
options.elf = "/app0/" + Common::FilenameWithoutDirectory(value);
|
||||
|
||||
options.elf = std::filesystem::path("/app0") / path.filename();
|
||||
} else {
|
||||
::printf("--game must point to an existing directory or ELF: %s\n", value.c_str());
|
||||
return false;
|
||||
@@ -226,7 +232,9 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
||||
return false;
|
||||
}
|
||||
value = Common::FixFilenameSlash(value);
|
||||
if (!Common::File::IsFileExisting(value)) {
|
||||
const auto path = Common::PathFromUtf8(value);
|
||||
|
||||
if (!Common::File::IsFileExisting(path)) {
|
||||
::printf("--game-patch must point to an existing file: %s\n", value.c_str());
|
||||
return false;
|
||||
}
|
||||
@@ -291,14 +299,14 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
||||
return false;
|
||||
}
|
||||
} else if (arg == "--shader-log-folder") {
|
||||
options.config.shader_log_folder = value;
|
||||
options.config.shader_log_folder = Common::PathFromUtf8(value);
|
||||
} else if (arg == "--command-buffer-dump") {
|
||||
if (!ParseBool(value, options.config.command_buffer_dump_enabled)) {
|
||||
::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str());
|
||||
return false;
|
||||
}
|
||||
} else if (arg == "--command-buffer-dump-folder") {
|
||||
options.config.command_buffer_dump_folder = value;
|
||||
options.config.command_buffer_dump_folder = Common::PathFromUtf8(value);
|
||||
} else if (arg == "--graphics-debug-dump") {
|
||||
if (!ParseBool(value, options.config.graphics_debug_dump_enabled)) {
|
||||
::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str());
|
||||
@@ -310,7 +318,7 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
||||
return false;
|
||||
}
|
||||
} else if (arg == "--printf-output-file") {
|
||||
options.config.printf_output_file = value;
|
||||
options.config.printf_output_file = Common::PathFromUtf8(value);
|
||||
} else if (arg == "--spirv-debug-printf") {
|
||||
if (!ParseBool(value, options.config.spirv_debug_printf_enabled)) {
|
||||
::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str());
|
||||
@@ -341,7 +349,7 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
||||
return show_help || (!options.app0_dir.empty() && !options.elf.empty());
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
static int Main(int argc, char* argv[]) {
|
||||
VirtualMemory::Init();
|
||||
InitializeThreads();
|
||||
|
||||
@@ -367,3 +375,34 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
|
||||
int wmain(int argc, wchar_t* argv[]) {
|
||||
std::vector<std::string> utf8_args;
|
||||
utf8_args.reserve(static_cast<size_t>(argc));
|
||||
|
||||
for (int index = 0; index < argc; index++) {
|
||||
const std::wstring_view wide(argv[index]);
|
||||
const std::u16string utf16(wide.begin(), wide.end());
|
||||
|
||||
utf8_args.push_back(Common::Utf16ToUtf8(utf16));
|
||||
}
|
||||
|
||||
std::vector<char*> utf8_argv;
|
||||
utf8_argv.reserve(utf8_args.size());
|
||||
|
||||
for (auto& argument: utf8_args) {
|
||||
utf8_argv.push_back(argument.data());
|
||||
}
|
||||
|
||||
return Main(argc, utf8_argv.data());
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
return Main(argc, argv);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user