UTF8 paths are now properly handled on windows.

This commit is contained in:
Mr_Goldberg 2021-04-25 12:44:41 -04:00
parent b8eae2b709
commit 51702b898e
No known key found for this signature in database
GPG key ID: 8597D87419DEF278
5 changed files with 147 additions and 96 deletions

View file

@ -28,14 +28,14 @@ randombytes(char * const buf, const size_t size)
std::string get_env_variable(std::string name)
{
char env_variable[1024];
DWORD ret = GetEnvironmentVariableA(name.c_str(), env_variable, sizeof(env_variable));
wchar_t env_variable[1024];
DWORD ret = GetEnvironmentVariableW(utf8_decode(name).c_str(), env_variable, _countof(env_variable));
if (ret <= 0) {
return std::string();
}
env_variable[ret] = 0;
return std::string(env_variable);
return utf8_encode(env_variable);
}
#else
@ -194,9 +194,9 @@ std::string get_full_lib_path()
{
std::string program_path;
#if defined(__WINDOWS__)
char DllPath[MAX_PATH] = {0};
GetModuleFileName((HINSTANCE)&__ImageBase, DllPath, _countof(DllPath));
program_path = DllPath;
wchar_t DllPath[2048] = {0};
GetModuleFileNameW((HINSTANCE)&__ImageBase, DllPath, _countof(DllPath));
program_path = utf8_encode(DllPath);
#else
program_path = get_lib_path();
#endif
@ -240,15 +240,18 @@ std::string canonical_path(std::string path)
{
std::string output;
#if defined(STEAM_WIN32)
char *buffer = _fullpath(NULL, path.c_str(), 0);
wchar_t *buffer = _wfullpath(NULL, utf8_decode(path).c_str(), 0);
if (buffer) {
output = utf8_encode(buffer);
free(buffer);
}
#else
char *buffer = canonicalize_file_name(path.c_str());
#endif
if (buffer) {
output = buffer;
free(buffer);
}
#endif
return output;
}
@ -633,7 +636,7 @@ static void load_dll()
PRINT_DEBUG("Crack file %s\n", path.c_str());
if (file_exists(path)) {
redirect_crackdll();
crack_dll_handle = LoadLibraryA(path.c_str());
crack_dll_handle = LoadLibraryW(utf8_decode(path).c_str());
unredirect_crackdll();
PRINT_DEBUG("Loaded crack file\n");
}
@ -657,7 +660,7 @@ static void load_dlls()
if (full_path[length - 4] != '.') continue;
PRINT_DEBUG("Trying to load %s\n", full_path.c_str());
if (LoadLibraryA(full_path.c_str())) {
if (LoadLibraryW(utf8_decode(full_path).c_str())) {
PRINT_DEBUG("LOADED %s\n", full_path.c_str());
}
}

View file

@ -84,6 +84,27 @@
#endif
#endif
#include <string>
// Convert a wide Unicode string to an UTF8 string
inline std::string utf8_encode(const std::wstring &wstr)
{
if( wstr.empty() ) return std::string();
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
std::string strTo( size_needed, 0 );
WideCharToMultiByte (CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
return strTo;
}
// Convert an UTF8 string to a wide Unicode String
inline std::wstring utf8_decode(const std::string &str)
{
if( str.empty() ) return std::wstring();
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
std::wstring wstrTo( size_needed, 0 );
MultiByteToWideChar (CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
return wstrTo;
}
#elif defined(__LINUX__)
#include <arpa/inet.h>
@ -112,6 +133,8 @@
#define PRINT_DEBUG(...) {FILE *t = fopen("STEAM_LOG.txt", "a"); fprintf(t, __VA_ARGS__); fclose(t);}
#endif
#define PATH_SEPARATOR "/"
#define utf8_decode(a) a
#endif
//#define PRINT_DEBUG(...) fprintf(stdout, __VA_ARGS__)
#ifdef EMU_RELEASE_BUILD

View file

@ -49,7 +49,7 @@ static void load_old_interface_versions()
static bool loaded = false;
if (loaded) return;
std::string interfaces_path = Local_Storage::get_program_path() + "steam_interfaces.txt";
std::ifstream input( interfaces_path );
std::ifstream input( utf8_decode(interfaces_path) );
PRINT_DEBUG("load from: %s\n", interfaces_path.c_str());
for( std::string line; getline( input, line ); )

View file

@ -21,6 +21,9 @@
#define STB_IMAGE_STATIC
#define STBI_ONLY_PNG
#define STBI_ONLY_JPEG
#if defined(__WINDOWS__)
#define STBI_WINDOWS_UTF8
#endif
#include "../stb/stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
@ -166,49 +169,93 @@ bool Local_Storage::save_screenshot(std::string const& image_path, uint8_t* img_
#else
#if defined(__WINDOWS__)
static BOOL DirectoryExists(LPCSTR szPath)
static BOOL DirectoryExists(LPCWSTR szPath)
{
DWORD dwAttrib = GetFileAttributesA(szPath);
DWORD dwAttrib = GetFileAttributesW(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
static void createDirectoryRecursively(std::string path)
static void createDirectoryRecursively(std::wstring path)
{
unsigned long long pos = 0;
do
{
pos = path.find_first_of("\\/", pos + 1);
CreateDirectoryA(path.substr(0, pos).c_str(), NULL);
pos = path.find_first_of(L"\\/", pos + 1);
CreateDirectoryW(path.substr(0, pos).c_str(), NULL);
} while (pos != std::string::npos);
}
static void create_directory(std::string strPath)
static void create_directory(std::string in_path)
{
std::wstring strPath = utf8_decode(in_path);
if (DirectoryExists(strPath.c_str()) == FALSE)
createDirectoryRecursively(strPath);
}
static std::vector<struct File_Data> get_filenames(std::string strPath)
static std::vector<struct File_Data> get_filenames(std::string in_path)
{
std::vector<struct File_Data> output;
strPath = strPath.append("\\*");
WIN32_FIND_DATAA ffd;
in_path = in_path.append("\\*");
WIN32_FIND_DATAW ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
std::wstring strPath = utf8_decode(in_path);
// Start iterating over the files in the path directory.
hFind = ::FindFirstFileA (strPath.c_str(), &ffd);
hFind = ::FindFirstFileW (strPath.c_str(), &ffd);
if (hFind != INVALID_HANDLE_VALUE)
{
do // Managed to locate and create an handle to that folder.
{
if (strcmp(".", ffd.cFileName) == 0) continue;
if (strcmp("..", ffd.cFileName) == 0) continue;
if (wcscmp(L".", ffd.cFileName) == 0) continue;
if (wcscmp(L"..", ffd.cFileName) == 0) continue;
struct File_Data f_data;
f_data.name = ffd.cFileName;
f_data.name = utf8_encode(ffd.cFileName);
output.push_back(f_data);
} while (::FindNextFileA(hFind, &ffd) == TRUE);
} while (::FindNextFileW(hFind, &ffd) == TRUE);
::FindClose(hFind);
} else {
//printf("Failed to find path: %s", strPath.c_str());
}
return output;
}
static std::vector<struct File_Data> get_filenames_recursive_w(std::wstring base_path)
{
if (base_path.back() == *L"\\")
base_path.pop_back();
std::vector<struct File_Data> output;
std::wstring strPath = base_path;
strPath = strPath.append(L"\\*");
WIN32_FIND_DATAW ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
// Start iterating over the files in the path directory.
hFind = ::FindFirstFileW (strPath.c_str(), &ffd);
if (hFind != INVALID_HANDLE_VALUE)
{
do // Managed to locate and create an handle to that folder.
{
if (wcscmp(L".", ffd.cFileName) == 0) continue;
if (wcscmp(L"..", ffd.cFileName) == 0) continue;
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// Construct new path from our base path
std::wstring dir_name = ffd.cFileName;
std::wstring path = base_path;
path += L"\\";
path += dir_name;
std::vector<struct File_Data> lower = get_filenames_recursive_w(path);
std::transform(lower.begin(), lower.end(), std::back_inserter(output), [&dir_name](File_Data f) {f.name = utf8_encode(dir_name) + "\\" + f.name; return f;});
} else {
File_Data f;
f.name = utf8_encode(ffd.cFileName);
output.push_back(f);
}
} while (::FindNextFileW(hFind, &ffd) == TRUE);
::FindClose(hFind);
} else {
//printf("Failed to find path: %s", strPath.c_str());
@ -219,44 +266,7 @@ static std::vector<struct File_Data> get_filenames(std::string strPath)
static std::vector<struct File_Data> get_filenames_recursive(std::string base_path)
{
if (base_path.back() == *PATH_SEPARATOR)
base_path.pop_back();
std::vector<struct File_Data> output;
std::string strPath = base_path;
strPath = strPath.append("\\*");
WIN32_FIND_DATAA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
// Start iterating over the files in the path directory.
hFind = ::FindFirstFileA (strPath.c_str(), &ffd);
if (hFind != INVALID_HANDLE_VALUE)
{
do // Managed to locate and create an handle to that folder.
{
if (strcmp(".", ffd.cFileName) == 0) continue;
if (strcmp("..", ffd.cFileName) == 0) continue;
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// Construct new path from our base path
std::string dir_name = ffd.cFileName;
std::string path = base_path;
path += PATH_SEPARATOR;
path += dir_name;
std::vector<struct File_Data> lower = get_filenames_recursive(path);
std::transform(lower.begin(), lower.end(), std::back_inserter(output), [&dir_name](File_Data f) {f.name = dir_name + "\\" + f.name; return f;});
} else {
File_Data f;
f.name = ffd.cFileName;
output.push_back(f);
}
} while (::FindNextFileA(hFind, &ffd) == TRUE);
::FindClose(hFind);
} else {
//printf("Failed to find path: %s", strPath.c_str());
}
return output;
return get_filenames_recursive_w(utf8_decode(base_path));
}
#else
@ -403,12 +413,12 @@ std::string Local_Storage::get_user_appdata_path()
{
std::string user_appdata_path = "SAVE";
#if defined(STEAM_WIN32)
CHAR szPath[MAX_PATH] = {};
WCHAR szPath[MAX_PATH] = {};
HRESULT hr = SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, szPath);
HRESULT hr = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, szPath);
if (SUCCEEDED(hr)) {
user_appdata_path = szPath;
user_appdata_path = utf8_encode(szPath);
}
#else
@ -504,7 +514,7 @@ int Local_Storage::store_file_data(std::string folder, std::string file, char *d
create_directory(folder + file_folder);
std::ofstream myfile;
myfile.open(folder + file, std::ios::binary | std::ios::out);
myfile.open(utf8_decode(folder + file), std::ios::binary | std::ios::out);
if (!myfile.is_open()) return -1;
myfile.write(data, length);
int position = myfile.tellp();
@ -553,7 +563,7 @@ int Local_Storage::store_data_settings(std::string file, char *data, unsigned in
int Local_Storage::get_file_data(std::string full_path, char *data, unsigned int max_length, unsigned int offset)
{
std::ifstream myfile;
myfile.open(full_path, std::ios::binary | std::ios::in);
myfile.open(utf8_decode(full_path), std::ios::binary | std::ios::in);
if (!myfile.is_open()) return -1;
myfile.seekg (offset, std::ios::beg);
@ -597,15 +607,19 @@ bool Local_Storage::file_exists(std::string folder, std::string file)
}
std::string full_path = save_directory + appid + folder + file;
struct stat buffer;
if (stat(full_path.c_str(), &buffer) != 0)
return false;
#if defined(STEAM_WIN32)
struct _stat buffer;
if (_wstat(utf8_decode(full_path).c_str(), &buffer) != 0)
return false;
if ( buffer.st_mode & _S_IFDIR)
return false;
#else
struct stat buffer;
if (stat(full_path.c_str(), &buffer) != 0)
return false;
if (S_ISDIR(buffer.st_mode))
return false;
#endif
@ -621,8 +635,14 @@ unsigned int Local_Storage::file_size(std::string folder, std::string file)
}
std::string full_path = save_directory + appid + folder + file;
#if defined(STEAM_WIN32)
struct _stat buffer = {};
if (_wstat(utf8_decode(full_path).c_str(), &buffer) != 0) return 0;
#else
struct stat buffer = {};
if (stat (full_path.c_str(), &buffer) != 0) return 0;
#endif
return buffer.st_size;
}
@ -634,7 +654,11 @@ bool Local_Storage::file_delete(std::string folder, std::string file)
}
std::string full_path = save_directory + appid + folder + file;
#if defined(STEAM_WIN32)
return _wremove(utf8_decode(full_path).c_str()) == 0;
#else
return remove(full_path.c_str()) == 0;
#endif
}
uint64_t Local_Storage::file_timestamp(std::string folder, std::string file)
@ -645,8 +669,14 @@ uint64_t Local_Storage::file_timestamp(std::string folder, std::string file)
}
std::string full_path = save_directory + appid + folder + file;
#if defined(STEAM_WIN32)
struct _stat buffer = {};
if (_wstat(utf8_decode(full_path).c_str(), &buffer) != 0) return 0;
#else
struct stat buffer = {};
if (stat (full_path.c_str(), &buffer) != 0) return 0;
#endif
return buffer.st_mtime;
}
@ -695,7 +725,7 @@ bool Local_Storage::update_save_filenames(std::string folder)
bool Local_Storage::load_json(std::string full_path, nlohmann::json& json)
{
std::ifstream inventory_file(full_path);
std::ifstream inventory_file(utf8_decode(full_path));
// If there is a file and we opened it
if (inventory_file)
{
@ -745,7 +775,7 @@ bool Local_Storage::write_json_file(std::string folder, std::string const&file,
create_directory(inv_path);
std::ofstream inventory_file(full_path, std::ios::trunc | std::ios::out);
std::ofstream inventory_file(utf8_decode(full_path), std::ios::trunc | std::ios::out);
if (inventory_file)
{
inventory_file << std::setw(2) << json;
@ -760,11 +790,8 @@ bool Local_Storage::write_json_file(std::string folder, std::string const&file,
std::vector<image_pixel_t> Local_Storage::load_image(std::string const& image_path)
{
std::vector<image_pixel_t> res;
FILE* hFile = fopen(image_path.c_str(), "r");
if (hFile != nullptr)
{
int width, height;
image_pixel_t* img = (image_pixel_t*)stbi_load_from_file(hFile, &width, &height, nullptr, 4);
image_pixel_t* img = (image_pixel_t*)stbi_load(image_path.c_str(), &width, &height, nullptr, 4);
if (img != nullptr)
{
res.resize(width*height);
@ -772,8 +799,6 @@ std::vector<image_pixel_t> Local_Storage::load_image(std::string const& image_pa
stbi_image_free(img);
}
fclose(hFile);
}
return res;
}

View file

@ -31,7 +31,7 @@ static void consume_bom(std::ifstream &input)
static void load_custom_broadcasts(std::string broadcasts_filepath, std::set<uint32> &custom_broadcasts)
{
PRINT_DEBUG("Broadcasts file path: %s\n", broadcasts_filepath.c_str());
std::ifstream broadcasts_file(broadcasts_filepath);
std::ifstream broadcasts_file(utf8_decode(broadcasts_filepath));
consume_bom(broadcasts_file);
if (broadcasts_file.is_open()) {
std::string line;
@ -69,7 +69,7 @@ static void load_gamecontroller_settings(Settings *settings)
std::transform(action_set_name.begin(), action_set_name.end(), action_set_name.begin(),[](unsigned char c){ return std::toupper(c); });
std::string controller_config_path = path + PATH_SEPARATOR + p;
std::ifstream input( controller_config_path );
std::ifstream input( utf8_decode(controller_config_path) );
if (input.is_open()) {
consume_bom(input);
std::map<std::string, std::pair<std::set<std::string>, std::string>> button_pairs;
@ -307,7 +307,7 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
{
std::string dlc_config_path = Local_Storage::get_game_settings_path() + "DLC.txt";
std::ifstream input( dlc_config_path );
std::ifstream input( utf8_decode(dlc_config_path) );
if (input.is_open()) {
consume_bom(input);
settings_client->unlockAllDLC(false);
@ -349,7 +349,7 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
{
std::string dlc_config_path = Local_Storage::get_game_settings_path() + "app_paths.txt";
std::ifstream input( dlc_config_path );
std::ifstream input( utf8_decode(dlc_config_path) );
if (input.is_open()) {
consume_bom(input);
@ -384,7 +384,7 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
{
std::string dlc_config_path = Local_Storage::get_game_settings_path() + "leaderboards.txt";
std::ifstream input( dlc_config_path );
std::ifstream input( utf8_decode(dlc_config_path) );
if (input.is_open()) {
consume_bom(input);
settings_client->setCreateUnknownLeaderboards(false);
@ -426,7 +426,7 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
{
std::string stats_config_path = Local_Storage::get_game_settings_path() + "stats.txt";
std::ifstream input( stats_config_path );
std::ifstream input( utf8_decode(stats_config_path) );
if (input.is_open()) {
consume_bom(input);
for( std::string line; getline( input, line ); ) {
@ -491,7 +491,7 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
{
std::string depots_config_path = Local_Storage::get_game_settings_path() + "depots.txt";
std::ifstream input( depots_config_path );
std::ifstream input( utf8_decode(depots_config_path) );
if (input.is_open()) {
consume_bom(input);
for( std::string line; getline( input, line ); ) {
@ -513,7 +513,7 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
{
std::string depots_config_path = Local_Storage::get_game_settings_path() + "subscribed_groups.txt";
std::ifstream input( depots_config_path );
std::ifstream input( utf8_decode(depots_config_path) );
if (input.is_open()) {
consume_bom(input);
for( std::string line; getline( input, line ); ) {