From b6fae097aa158f84efa7d95cf20488801dc4949c Mon Sep 17 00:00:00 2001 From: Quentin Date: Sat, 8 Jul 2023 00:16:29 +0200 Subject: [PATCH] fix(cache): fs::path.string() can throw when it try to convert windows utf16 wstring to multi byte std::string when user code page isnt utf8 (#1641) --- src/services/gta_data/yim_fipackfile.cpp | 51 ++++++++++++++++++++---- src/services/gta_data/yim_fipackfile.hpp | 2 +- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/services/gta_data/yim_fipackfile.cpp b/src/services/gta_data/yim_fipackfile.cpp index ded1b8c5..2e38a3f0 100644 --- a/src/services/gta_data/yim_fipackfile.cpp +++ b/src/services/gta_data/yim_fipackfile.cpp @@ -17,12 +17,12 @@ namespace big m_wrapper_call_back.push_back(cb); } - void yim_fipackfile::traverse_rpf_file(const std::string& path, int depth) + void yim_fipackfile::traverse_rpf_file(const std::u8string& path, int depth) { std::string mount_path = std::format("temp{}:/", depth); rage::fiPackfile packfile; - packfile.OpenPackfile(path.c_str(), true, 0, 0); + packfile.OpenPackfile(reinterpret_cast(path.c_str()), true, 0, 0); packfile.Mount(mount_path.c_str()); yim_fipackfile rpf_wrapper = yim_fipackfile(&packfile, mount_path); @@ -32,7 +32,7 @@ namespace big { if (file.extension() == ".rpf") { - if (auto handle = ((rage::fiDevice*)&packfile)->Open(file.string().c_str(), true)) + if (auto handle = ((rage::fiDevice*)&packfile)->Open(reinterpret_cast(file.u8string().c_str()), true)) { uint32_t encryption_type{}; ((rage::fiDevice*)&packfile)->Seek(handle, 12, 0); @@ -42,7 +42,7 @@ namespace big if (encryption_type == 0xFFFFFF9) continue; // skip AES encrypted RPFs - traverse_rpf_file(file.string(), depth + 1); + traverse_rpf_file(file.u8string(), depth + 1); } } else @@ -57,17 +57,54 @@ namespace big packfile.ClosePackfile(); } + static std::string UTF16ToCP(uint32_t code_page, std::wstring_view input) + { + if (input.empty()) + return {}; + + const auto size = WideCharToMultiByte(code_page, 0, input.data(), static_cast(input.size()), nullptr, 0, nullptr, nullptr); + + std::string output(size, '\0'); + + if (size + != WideCharToMultiByte(code_page, + 0, + input.data(), + static_cast(input.size()), + output.data(), + static_cast(output.size()), + nullptr, + nullptr)) + { + const auto error_code = GetLastError(); + LOG(WARNING) << "WideCharToMultiByte Error in String " << error_code; + return {}; + } + + return output; + } + void yim_fipackfile::for_each_fipackfile() { for (auto& entry : std::filesystem::recursive_directory_iterator(std::filesystem::current_path())) { - auto rel_path = std::filesystem::relative(entry.path()); + if (!entry.is_regular_file()) + { + continue; + } - if (rel_path.string().contains("mods")) + const auto rel_path = std::filesystem::relative(entry.path()); + + const auto utf8_path = UTF16ToCP(CP_UTF8, entry.path().native()); + + if (utf8_path.empty()) + continue; + + if (utf8_path.contains("mods")) continue; if (rel_path.extension() == ".rpf") - traverse_rpf_file(rel_path.string()); + traverse_rpf_file(rel_path.u8string()); } } diff --git a/src/services/gta_data/yim_fipackfile.hpp b/src/services/gta_data/yim_fipackfile.hpp index 2586cee0..de0f7da3 100644 --- a/src/services/gta_data/yim_fipackfile.hpp +++ b/src/services/gta_data/yim_fipackfile.hpp @@ -17,7 +17,7 @@ namespace big static void add_wrapper_call_back(std::function cb); - static void traverse_rpf_file(const std::string& path, int depth = 0); + static void traverse_rpf_file(const std::u8string& path, int depth = 0); static void for_each_fipackfile(); std::vector get_file_paths(std::string parent = {});