From a35a2838b6bd2681d87d3ecd15b9fec2427bc968 Mon Sep 17 00:00:00 2001 From: Silent Date: Sun, 13 Sep 2020 19:57:35 +0200 Subject: [PATCH 1/2] Fix XML loading not handling UTF-8 paths --- src/frontend-common/game_list.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/frontend-common/game_list.cpp b/src/frontend-common/game_list.cpp index 0cd9c88f7..d2a3ff126 100644 --- a/src/frontend-common/game_list.cpp +++ b/src/frontend-common/game_list.cpp @@ -740,8 +740,12 @@ void GameList::LoadDatabase() if (m_database_filename.empty()) return; + auto fp = FileSystem::OpenManagedCFile(m_database_filename.c_str(), "rb"); + if (!fp) + return; + tinyxml2::XMLDocument doc; - tinyxml2::XMLError error = doc.LoadFile(m_database_filename.c_str()); + tinyxml2::XMLError error = doc.LoadFile(fp.get()); if (error != tinyxml2::XML_SUCCESS) { Log_ErrorPrintf("Failed to parse redump dat '%s': %s", m_database_filename.c_str(), @@ -858,8 +862,12 @@ void GameList::LoadCompatibilityList() if (m_compatibility_list_filename.empty()) return; + auto fp = FileSystem::OpenManagedCFile(m_compatibility_list_filename.c_str(), "rb"); + if (!fp) + return; + tinyxml2::XMLDocument doc; - tinyxml2::XMLError error = doc.LoadFile(m_compatibility_list_filename.c_str()); + tinyxml2::XMLError error = doc.LoadFile(fp.get()); if (error != tinyxml2::XML_SUCCESS) { Log_ErrorPrintf("Failed to parse compatibility list '%s': %s", m_compatibility_list_filename.c_str(), @@ -989,11 +997,12 @@ bool GameList::SaveCompatibilityDatabaseForEntry(const GameListCompatibilityEntr if (m_compatibility_list_filename.empty()) return false; - if (!FileSystem::FileExists(m_compatibility_list_filename.c_str())) + auto fp = FileSystem::OpenManagedCFile(m_compatibility_list_filename.c_str(), "rb"); + if (!fp) return SaveCompatibilityDatabase(); tinyxml2::XMLDocument doc; - tinyxml2::XMLError error = doc.LoadFile(m_compatibility_list_filename.c_str()); + tinyxml2::XMLError error = doc.LoadFile(fp.get()); if (error != tinyxml2::XML_SUCCESS) { Log_ErrorPrintf("Failed to parse compatibility list '%s': %s", m_compatibility_list_filename.c_str(), From 1918a5ddd4537115941093aac8c252a28fc35b2f Mon Sep 17 00:00:00 2001 From: Silent Date: Mon, 14 Sep 2020 21:27:22 +0200 Subject: [PATCH 2/2] STBI: Handle UTF-8 paths correctly --- src/common/image.cpp | 9 ++++++++- src/core/gpu.cpp | 18 +++++++++++++++--- src/core/host_display.cpp | 38 ++++++++++++++++++++++++++------------ 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/common/image.cpp b/src/common/image.cpp index b80e10dd5..1fe92feb3 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -1,4 +1,5 @@ #include "image.h" +#include "file_system.h" #include "log.h" #include "stb_image.h" Log_SetChannel(Common::Image); @@ -6,8 +7,14 @@ Log_SetChannel(Common::Image); namespace Common { bool LoadImageFromFile(Common::RGBA8Image* image, const char* filename) { + auto fp = FileSystem::OpenManagedCFile(filename, "rb"); + if (!fp) + { + return false; + } + int width, height, file_channels; - u8* pixel_data = stbi_load(filename, &width, &height, &file_channels, 4); + u8* pixel_data = stbi_load_from_file(fp.get(), &width, &height, &file_channels, 4); if (!pixel_data) { const char* error_reason = stbi_failure_reason(); diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 32d36ddcf..086865c83 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -1,4 +1,5 @@ #include "gpu.h" +#include "common/file_system.h" #include "common/heap_array.h" #include "common/log.h" #include "common/state_wrapper.h" @@ -1320,10 +1321,17 @@ void GPU::SetTextureWindow(u32 value) bool GPU::DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride, const void* buffer, bool remove_alpha) { - std::vector rgba8_buf(width * height); + auto fp = FileSystem::OpenManagedCFile(filename, "wb"); + if (!fp) + { + Log_ErrorPrintf("Can't open file '%s'", filename); + return false; + } + + auto rgba8_buf = std::make_unique(width * height); const char* ptr_in = static_cast(buffer); - u32* ptr_out = rgba8_buf.data(); + u32* ptr_out = rgba8_buf.get(); for (u32 row = 0; row < height; row++) { const char* row_ptr_in = ptr_in; @@ -1338,7 +1346,11 @@ bool GPU::DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride ptr_in += stride; } - return (stbi_write_png(filename, width, height, 4, rgba8_buf.data(), sizeof(u32) * width) != 0); + + const auto write_func = [](void* context, void* data, int size) { + std::fwrite(data, 1, size, static_cast(context)); + }; + return (stbi_write_png_to_func(write_func, fp.get(), width, height, 4, rgba8_buf.get(), sizeof(u32) * width) != 0); } void GPU::DrawDebugStateWindow() diff --git a/src/core/host_display.cpp b/src/core/host_display.cpp index 5b81ccb4c..06db6768d 100644 --- a/src/core/host_display.cpp +++ b/src/core/host_display.cpp @@ -1,4 +1,5 @@ #include "host_display.h" +#include "common/file_system.h" #include "common/log.h" #include "common/string_util.h" #include "stb_image.h" @@ -31,8 +32,14 @@ bool HostDisplay::SetSoftwareCursor(const void* pixels, u32 width, u32 height, u bool HostDisplay::SetSoftwareCursor(const char* path, float scale /*= 1.0f*/) { + auto fp = FileSystem::OpenManagedCFile(path, "rb"); + if (!fp) + { + return false; + } + int width, height, file_channels; - u8* pixel_data = stbi_load(path, &width, &height, &file_channels, 4); + u8* pixel_data = stbi_load_from_file(fp.get(), &width, &height, &file_channels, 4); if (!pixel_data) { const char* error_reason = stbi_failure_reason(); @@ -257,32 +264,39 @@ bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u texture_data_stride = resized_texture_stride; } - bool result; + auto fp = FileSystem::OpenManagedCFile(filename, "wb"); + if (!fp) + { + Log_ErrorPrintf("Can't open file '%s'", filename); + return false; + } + + const auto write_func = [](void* context, void* data, int size) { + std::fwrite(data, 1, size, static_cast(context)); + }; + + bool result = false; if (StringUtil::Strcasecmp(extension, ".png") == 0) { - result = (stbi_write_png(filename, width, height, 4, texture_data.data(), texture_data_stride) != 0); + result = + (stbi_write_png_to_func(write_func, fp.get(), width, height, 4, texture_data.data(), texture_data_stride) != 0); } else if (StringUtil::Strcasecmp(filename, ".jpg") == 0) { - result = (stbi_write_jpg(filename, width, height, 4, texture_data.data(), 95) != 0); + result = (stbi_write_jpg_to_func(write_func, fp.get(), width, height, 4, texture_data.data(), 95) != 0); } else if (StringUtil::Strcasecmp(filename, ".tga") == 0) { - result = (stbi_write_tga(filename, width, height, 4, texture_data.data()) != 0); + result = (stbi_write_tga_to_func(write_func, fp.get(), width, height, 4, texture_data.data()) != 0); } else if (StringUtil::Strcasecmp(filename, ".bmp") == 0) { - result = (stbi_write_bmp(filename, width, height, 4, texture_data.data()) != 0); - } - else - { - Log_ErrorPrintf("Unknown extension in filename '%s': '%s'", filename, extension); - return false; + result = (stbi_write_bmp_to_func(write_func, fp.get(), width, height, 4, texture_data.data()) != 0); } if (!result) { - Log_ErrorPrintf("Failed to save texture to '%s'", filename); + Log_ErrorPrintf("Unknown extension in filename '%s' or save error: '%s'", filename, extension); return false; }