Complete UTF-16 (Unicode) support added for Windows.

ROM names with Unicode characters are supported, as well as running ES from a directory that has Unicode characters in its name.
This commit is contained in:
Leon Styhre 2020-07-10 18:32:23 +02:00
parent adb5cb6664
commit 31da561695
20 changed files with 251 additions and 68 deletions

View file

@ -13,7 +13,7 @@ v1.0.0
* Full navigation sound support, configurable per theme * Full navigation sound support, configurable per theme
* New default theme rbsimple-DE bundled with the software, this theme is largely based on recalbox-multi by the Recalbox community * New default theme rbsimple-DE bundled with the software, this theme is largely based on recalbox-multi by the Recalbox community
* Added extensive es_systems.cfg templates for Unix and Windows * Added extensive es_systems.cfg templates for Unix and Windows
* Updated the application to compile and work on Microsoft Windows * Updated the application to compile and work on Microsoft Windows, including full UTF-16 (Unicode) support
* Seamless (almost) launch of games without showing the desktop when starting and returning from RetroArch and other emulators * Seamless (almost) launch of games without showing the desktop when starting and returning from RetroArch and other emulators
* Per-game launch command override, so that different cores or emulators can be used on a per-game basis (saved to gamelist.xml) * Per-game launch command override, so that different cores or emulators can be used on a per-game basis (saved to gamelist.xml)
* Core location can be defined relative to the emulator binary using the %EMUPATH% varible in es_systems.cfg (mostly useful for Windows) * Core location can be defined relative to the emulator binary using the %EMUPATH% varible in es_systems.cfg (mostly useful for Windows)

View file

@ -128,10 +128,15 @@ void CollectionSystemManager::saveCustomCollection(SystemData* sys)
CollectionSystemData sysData = mCustomCollectionSystemsData.at(name); CollectionSystemData sysData = mCustomCollectionSystemsData.at(name);
if (sysData.needsSave) { if (sysData.needsSave) {
std::ofstream configFile; std::ofstream configFile;
#ifdef _WIN64
configFile.open(Utils::String::
stringToWideString(getCustomCollectionConfigPath(name)).c_str());
#else
configFile.open(getCustomCollectionConfigPath(name)); configFile.open(getCustomCollectionConfigPath(name));
#endif
for (std::unordered_map<std::string, FileData*>::const_iterator for (std::unordered_map<std::string, FileData*>::const_iterator
iter = games.cbegin(); iter != games.cend(); ++iter) { iter = games.cbegin(); iter != games.cend(); ++iter) {
std::string path = iter->first; std::string path = iter->first;
// If the ROM path of the game begins with the path from the setting // If the ROM path of the game begins with the path from the setting
// ROMDirectory (or the default ROM directory), then replace it with %ROMPATH%. // ROMDirectory (or the default ROM directory), then replace it with %ROMPATH%.
if (path.find(rompath) == 0) if (path.find(rompath) == 0)
@ -143,7 +148,7 @@ void CollectionSystemManager::saveCustomCollection(SystemData* sys)
} }
} }
else { else {
LOG(LogError) << "Couldn't find collection to save! " << name; LOG(LogError) << "Error - Couldn't find collection to save! " << name;
} }
} }
@ -838,7 +843,7 @@ void CollectionSystemManager::populateAutoCollection(CollectionSystemData* sysDa
sysData->isPopulated = true; sysData->isPopulated = true;
} }
// Populate a custom collection system // Populate a custom collection system.
void CollectionSystemManager::populateCustomCollection(CollectionSystemData* sysData) void CollectionSystemManager::populateCustomCollection(CollectionSystemData* sysData)
{ {
SystemData* newSys = sysData->system; SystemData* newSys = sysData->system;
@ -856,7 +861,11 @@ void CollectionSystemManager::populateCustomCollection(CollectionSystemData* sys
FileFilterIndex* index = newSys->getIndex(); FileFilterIndex* index = newSys->getIndex();
// Get configuration for this custom collection. // Get configuration for this custom collection.
#if _WIN64
std::ifstream input(Utils::String::stringToWideString(path).c_str());
#else
std::ifstream input(path); std::ifstream input(path);
#endif
// Get all files map. // Get all files map.
std::unordered_map<std::string,FileData*> std::unordered_map<std::string,FileData*>
@ -970,7 +979,11 @@ std::vector<std::string> CollectionSystemManager::getSystemsFromConfig()
return systems; return systems;
pugi::xml_document doc; pugi::xml_document doc;
#ifdef _WIN64
pugi::xml_parse_result res = doc.load_file(Utils::String::stringToWideString(path).c_str());
#else
pugi::xml_parse_result res = doc.load_file(path.c_str()); pugi::xml_parse_result res = doc.load_file(path.c_str());
#endif
if (!res) if (!res)
return systems; return systems;

View file

@ -465,7 +465,7 @@ void FileData::launchGame(Window* window)
command = Utils::String::replace(command, "%ROM_RAW%", rom_raw); command = Utils::String::replace(command, "%ROM_RAW%", rom_raw);
#ifdef _WIN64 #ifdef _WIN64
std::wstring commandWide = Utils::String::charToWideChar(command); std::wstring commandWide = Utils::String::stringToWideString(command);
#endif #endif
Scripting::fireEvent("game-start", rom, basename); Scripting::fireEvent("game-start", rom, basename);
@ -494,7 +494,7 @@ void FileData::launchGame(Window* window)
std::wstring emuExecutableWide; std::wstring emuExecutableWide;
std::wstring emuPathWide; std::wstring emuPathWide;
emuExecutableWide = Utils::String::charToWideChar(emuExecutable); emuExecutableWide = Utils::String::stringToWideString(emuExecutable);
// Search for the emulator using the PATH environmental variable. // Search for the emulator using the PATH environmental variable.
DWORD size = SearchPathW(nullptr, emuExecutableWide.c_str(), L".exe", 0, nullptr, nullptr); DWORD size = SearchPathW(nullptr, emuExecutableWide.c_str(), L".exe", 0, nullptr, nullptr);
@ -525,7 +525,7 @@ void FileData::launchGame(Window* window)
LOG(LogInfo) << "Expanded emulator launch command:"; LOG(LogInfo) << "Expanded emulator launch command:";
#ifdef _WIN64 #ifdef _WIN64
LOG(LogInfo) << Utils::String::wideCharToChar(commandWide); LOG(LogInfo) << Utils::String::wideStringToString(commandWide);
exitCode = launchEmulatorWindows(commandWide); exitCode = launchEmulatorWindows(commandWide);
#else #else
LOG(LogInfo) << command; LOG(LogInfo) << command;

View file

@ -9,6 +9,7 @@
#include <chrono> #include <chrono>
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
#include "utils/StringUtil.h"
#include "FileData.h" #include "FileData.h"
#include "FileFilterIndex.h" #include "FileFilterIndex.h"
#include "Log.h" #include "Log.h"
@ -93,7 +94,12 @@ void parseGamelist(SystemData* system)
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"..."; LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"...";
pugi::xml_document doc; pugi::xml_document doc;
#ifdef _WIN64
pugi::xml_parse_result result =
doc.load_file(Utils::String::stringToWideString(xmlpath).c_str());
#else
pugi::xml_parse_result result = doc.load_file(xmlpath.c_str()); pugi::xml_parse_result result = doc.load_file(xmlpath.c_str());
#endif
if (!result) { if (!result) {
LOG(LogError) << "Error parsing XML file \"" << xmlpath << LOG(LogError) << "Error parsing XML file \"" << xmlpath <<
@ -189,7 +195,12 @@ void updateGamelist(SystemData* system)
if (Utils::FileSystem::exists(xmlReadPath)) { if (Utils::FileSystem::exists(xmlReadPath)) {
// Parse an existing file first. // Parse an existing file first.
#ifdef _WIN64
pugi::xml_parse_result result =
doc.load_file(Utils::String::stringToWideString(xmlReadPath).c_str());
#else
pugi::xml_parse_result result = doc.load_file(xmlReadPath.c_str()); pugi::xml_parse_result result = doc.load_file(xmlReadPath.c_str());
#endif
if (!result) { if (!result) {
LOG(LogError) << "Error parsing XML file \"" << xmlReadPath << "\"!\n " << LOG(LogError) << "Error parsing XML file \"" << xmlReadPath << "\"!\n " <<
@ -264,7 +275,11 @@ void updateGamelist(SystemData* system)
LOG(LogInfo) << "Added/Updated " << numUpdated << LOG(LogInfo) << "Added/Updated " << numUpdated <<
" entities in '" << xmlReadPath << "'"; " entities in '" << xmlReadPath << "'";
#ifdef _WIN64
if (!doc.save_file(Utils::String::stringToWideString(xmlWritePath).c_str())) {
#else
if (!doc.save_file(xmlWritePath.c_str())) { if (!doc.save_file(xmlWritePath.c_str())) {
#endif
LOG(LogError) << "Error saving gamelist.xml to \"" << LOG(LogError) << "Error saving gamelist.xml to \"" <<
xmlWritePath << "\" (for system " << system->getName() << ")!"; xmlWritePath << "\" (for system " << system->getName() << ")!";
} }

View file

@ -226,7 +226,11 @@ bool SystemData::loadConfig()
} }
pugi::xml_document doc; pugi::xml_document doc;
#ifdef _WIN64
pugi::xml_parse_result res = doc.load_file(Utils::String::stringToWideString(path).c_str());
#else
pugi::xml_parse_result res = doc.load_file(path.c_str()); pugi::xml_parse_result res = doc.load_file(path.c_str());
#endif
if (!res) { if (!res) {
LOG(LogError) << "Error - Could not parse es_systems.cfg"; LOG(LogError) << "Error - Could not parse es_systems.cfg";

View file

@ -21,8 +21,7 @@ class FileData;
class FileFilterIndex; class FileFilterIndex;
class ThemeData; class ThemeData;
struct SystemEnvironmentData struct SystemEnvironmentData {
{
std::string mStartPath; std::string mStartPath;
std::vector<std::string> mSearchExtensions; std::vector<std::string> mSearchExtensions;
std::string mLaunchCommand; std::string mLaunchCommand;
@ -32,7 +31,8 @@ struct SystemEnvironmentData
class SystemData class SystemData
{ {
public: public:
SystemData(const std::string& name, SystemData(
const std::string& name,
const std::string& fullName, const std::string& fullName,
SystemEnvironmentData* envData, SystemEnvironmentData* envData,
const std::string& themeFolder, const std::string& themeFolder,

View file

@ -19,6 +19,7 @@
#include "guis/GuiDetectDevice.h" #include "guis/GuiDetectDevice.h"
#include "guis/GuiMsgBox.h" #include "guis/GuiMsgBox.h"
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
#include "utils/StringUtil.h"
#include "views/ViewController.h" #include "views/ViewController.h"
#include "CollectionSystemManager.h" #include "CollectionSystemManager.h"
#include "EmulationStation.h" #include "EmulationStation.h"
@ -342,8 +343,7 @@ bool loadSystemConfigFile(std::string& errorMsg)
return true; return true;
} }
if (SystemData::sSystemVector.size() == 0) if (SystemData::sSystemVector.size() == 0) {
{
LOG(LogError) << "Error - No systems found, does at least one system have a game present? " LOG(LogError) << "Error - No systems found, does at least one system have a game present? "
"(Check that the file extensions are supported.)"; "(Check that the file extensions are supported.)";
errorMsg = "THE SYSTEMS CONFIGURATION FILE EXISTS, BUT NO\n" errorMsg = "THE SYSTEMS CONFIGURATION FILE EXISTS, BUT NO\n"
@ -354,7 +354,12 @@ bool loadSystemConfigFile(std::string& errorMsg)
"THE GAME SYSTEMS SUBDIRECTORIES ALSO NEED TO\n" "THE GAME SYSTEMS SUBDIRECTORIES ALSO NEED TO\n"
"MATCH THE PLATFORM TAGS IN ES_SYSTEMS.CFG.\n" "MATCH THE PLATFORM TAGS IN ES_SYSTEMS.CFG.\n"
"THIS IS THE CURRENTLY CONFIGURED ROM DIRECTORY:\n"; "THIS IS THE CURRENTLY CONFIGURED ROM DIRECTORY:\n";
#ifdef _WIN64
errorMsg += Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
#else
errorMsg += FileData::getROMDirectory(); errorMsg += FileData::getROMDirectory();
#endif
return true; return true;
} }

View file

@ -8,6 +8,7 @@
#include "scrapers/Scraper.h" #include "scrapers/Scraper.h"
#include "utils/StringUtil.h"
#include "FileData.h" #include "FileData.h"
#include "GamesDBJSONScraper.h" #include "GamesDBJSONScraper.h"
#include "ScreenScraper.h" #include "ScreenScraper.h"
@ -231,7 +232,12 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
if(it->existingMediaFile != "") if(it->existingMediaFile != "")
Utils::FileSystem::removeFile(it->existingMediaFile); Utils::FileSystem::removeFile(it->existingMediaFile);
#ifdef _WIN64
std::ofstream stream(Utils::String::stringToWideString(filePath).c_str(),
std::ios_base::out | std::ios_base::binary);
#else
std::ofstream stream(filePath, std::ios_base::out | std::ios_base::binary); std::ofstream stream(filePath, std::ios_base::out | std::ios_base::binary);
#endif
if (stream.bad()) { if (stream.bad()) {
setError("Failed to open image path to write. Permission error? Disk full?"); setError("Failed to open image path to write. Permission error? Disk full?");
return; return;
@ -331,7 +337,12 @@ void ImageDownloadHandle::update()
if(mExistingMediaFile != "") if(mExistingMediaFile != "")
Utils::FileSystem::removeFile(mExistingMediaFile); Utils::FileSystem::removeFile(mExistingMediaFile);
#ifdef _WIN64
std::ofstream stream(Utils::String::stringToWideString(mSavePath).c_str(),
std::ios_base::out | std::ios_base::binary);
#else
std::ofstream stream(mSavePath, std::ios_base::out | std::ios_base::binary); std::ofstream stream(mSavePath, std::ios_base::out | std::ios_base::binary);
#endif
if (stream.bad()) { if (stream.bad()) {
setError("Failed to open image path to write. Permission error? Disk full?"); setError("Failed to open image path to write. Permission error? Disk full?");
return; return;

View file

@ -9,6 +9,7 @@
#include "InputManager.h" #include "InputManager.h"
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
#include "utils/StringUtil.h"
#include "CECInput.h" #include "CECInput.h"
#include "Log.h" #include "Log.h"
#include "Platform.h" #include "Platform.h"
@ -83,7 +84,7 @@ void InputManager::init()
loadInputConfig(mKeyboardInputConfig); loadInputConfig(mKeyboardInputConfig);
SDL_USER_CECBUTTONDOWN = SDL_RegisterEvents(2); SDL_USER_CECBUTTONDOWN = SDL_RegisterEvents(2);
SDL_USER_CECBUTTONUP = SDL_USER_CECBUTTONDOWN + 1; SDL_USER_CECBUTTONUP = SDL_USER_CECBUTTONDOWN + 1;
CECInput::init(); CECInput::init();
mCECInputConfig = new InputConfig(DEVICE_CEC, "CEC", CEC_GUID_STRING); mCECInputConfig = new InputConfig(DEVICE_CEC, "CEC", CEC_GUID_STRING);
loadInputConfig(mCECInputConfig); loadInputConfig(mCECInputConfig);
@ -302,7 +303,11 @@ bool InputManager::loadInputConfig(InputConfig* config)
return false; return false;
pugi::xml_document doc; pugi::xml_document doc;
#ifdef _WIN64
pugi::xml_parse_result res = doc.load_file(Utils::String::stringToWideString(path).c_str());
#else
pugi::xml_parse_result res = doc.load_file(path.c_str()); pugi::xml_parse_result res = doc.load_file(path.c_str());
#endif
if (!res) { if (!res) {
LOG(LogError) << "Error parsing input config: " << res.description(); LOG(LogError) << "Error parsing input config: " << res.description();
@ -362,7 +367,12 @@ void InputManager::writeDeviceConfig(InputConfig* config)
if (Utils::FileSystem::exists(path)) { if (Utils::FileSystem::exists(path)) {
// Merge files. // Merge files.
#ifdef _WIN64
pugi::xml_parse_result result =
doc.load_file(Utils::String::stringToWideString(path).c_str());
#else
pugi::xml_parse_result result = doc.load_file(path.c_str()); pugi::xml_parse_result result = doc.load_file(path.c_str());
#endif
if (!result) { if (!result) {
LOG(LogError) << "Error parsing input config: " << result.description(); LOG(LogError) << "Error parsing input config: " << result.description();
} }
@ -400,7 +410,12 @@ void InputManager::writeDeviceConfig(InputConfig* config)
root = doc.append_child("inputList"); root = doc.append_child("inputList");
config->writeToXML(root); config->writeToXML(root);
#ifdef _WIN64
doc.save_file(Utils::String::stringToWideString(path).c_str());
#else
doc.save_file(path.c_str()); doc.save_file(path.c_str());
#endif
Scripting::fireEvent("config-changed"); Scripting::fireEvent("config-changed");
Scripting::fireEvent("controls-changed"); Scripting::fireEvent("controls-changed");
@ -417,7 +432,13 @@ void InputManager::doOnFinish()
pugi::xml_document doc; pugi::xml_document doc;
if (Utils::FileSystem::exists(path)) { if (Utils::FileSystem::exists(path)) {
#ifdef _WIN64
pugi::xml_parse_result result =
doc.load_file(Utils::String::stringToWideString(path).c_str());
#else
pugi::xml_parse_result result = doc.load_file(path.c_str()); pugi::xml_parse_result result = doc.load_file(path.c_str());
#endif
if (!result) { if (!result) {
LOG(LogError) << "Error parsing input config: " << result.description(); LOG(LogError) << "Error parsing input config: " << result.description();
} }

View file

@ -7,13 +7,15 @@
#include "Log.h" #include "Log.h"
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
#include "utils/StringUtil.h"
#include "Platform.h" #include "Platform.h"
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <fstream>
LogLevel Log::reportingLevel = LogInfo; LogLevel Log::reportingLevel = LogInfo;
FILE* Log::file = nullptr; // fopen(getLogPath().c_str(), "w"); std::ofstream file;
LogLevel Log::getReportingLevel() LogLevel Log::getReportingLevel()
{ {
@ -32,15 +34,19 @@ void Log::setReportingLevel(LogLevel level)
void Log::init() void Log::init()
{ {
remove((getLogPath() + ".bak").c_str()); Utils::FileSystem::removeFile(getLogPath() + ".bak");
// Rename previous log file. // Rename the previous log file.
rename(getLogPath().c_str(), (getLogPath() + ".bak").c_str()); Utils::FileSystem::renameFile(getLogPath(), getLogPath() + ".bak", true);
return; return;
} }
void Log::open() void Log::open()
{ {
file = fopen(getLogPath().c_str(), "w"); #ifdef _WIN64
file.open(Utils::String::stringToWideString(getLogPath()).c_str());
#else
file.open(getLogPath().c_str());
#endif
} }
std::ostringstream& Log::get(LogLevel level) std::ostringstream& Log::get(LogLevel level)
@ -54,36 +60,30 @@ std::ostringstream& Log::get(LogLevel level)
void Log::flush() void Log::flush()
{ {
fflush(getOutput()); file.flush();
} }
void Log::close() void Log::close()
{ {
fclose(file); file.close();
file = nullptr;
}
FILE* Log::getOutput()
{
return file;
} }
Log::~Log() Log::~Log()
{ {
os << std::endl; os << std::endl;
if (getOutput() == nullptr) { if (!file.is_open()) {
// not open yet, print to stdout // Not open yet, print to stdout.
std::cerr << "ERROR - tried to write to log file before it was open! " std::cerr << "ERROR - tried to write to log file before it was open! "
"The following won't be logged:\n"; "The following won't be logged:\n";
std::cerr << os.str(); std::cerr << os.str();
return; return;
} }
fprintf(getOutput(), "%s", os.str().c_str()); file << os.str();
// If it's an error, also print to console. // If it's an error, also print to console.
// Print all messages if using --debug. // Print all messages if using --debug.
if (messageLevel == LogError || reportingLevel >= LogDebug) if (messageLevel == LogError || reportingLevel >= LogDebug)
fprintf(stderr, "%s", os.str().c_str()); std::cerr << os.str();
} }

View file

@ -24,7 +24,6 @@ enum LogLevel {
class Log class Log
{ {
public: public:
//Log();
~Log(); ~Log();
std::ostringstream& get(LogLevel level = LogInfo); std::ostringstream& get(LogLevel level = LogInfo);
@ -40,11 +39,9 @@ public:
protected: protected:
std::ostringstream os; std::ostringstream os;
static FILE* file;
private: private:
static LogLevel reportingLevel; static LogLevel reportingLevel;
static FILE* getOutput();
LogLevel messageLevel; LogLevel messageLevel;
}; };

View file

@ -50,7 +50,12 @@ MameNames::MameNames()
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"..."; LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"...";
pugi::xml_document doc; pugi::xml_document doc;
#ifdef _WIN64
pugi::xml_parse_result result =
doc.load_file(Utils::String::stringToWideString(xmlpath).c_str());
#else
pugi::xml_parse_result result = doc.load_file(xmlpath.c_str()); pugi::xml_parse_result result = doc.load_file(xmlpath.c_str());
#endif
if (!result) { if (!result) {
LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n " LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n "
@ -75,7 +80,11 @@ MameNames::MameNames()
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"..."; LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"...";
#ifdef _WIN64
result = doc.load_file(Utils::String::stringToWideString(xmlpath).c_str());
#else
result = doc.load_file(xmlpath.c_str()); result = doc.load_file(xmlpath.c_str());
#endif
if (!result) { if (!result) {
LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n " LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n "
@ -97,7 +106,11 @@ MameNames::MameNames()
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"..."; LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"...";
#ifdef _WIN64
result = doc.load_file(Utils::String::stringToWideString(xmlpath).c_str());
#else
result = doc.load_file(xmlpath.c_str()); result = doc.load_file(xmlpath.c_str());
#endif
if (!result) { if (!result) {
LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n " LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n "

View file

@ -50,7 +50,7 @@ int runSystemCommand(const std::string& cmd_utf8)
#ifdef _WIN64 #ifdef _WIN64
// On Windows we use _wsystem to support non-ASCII paths // On Windows we use _wsystem to support non-ASCII paths
// which requires converting from UTF-8 to a wstring. // which requires converting from UTF-8 to a wstring.
std::wstring wchar_str = Utils::String::charToWideChar(cmd_utf8); std::wstring wchar_str = Utils::String::stringToWideString(cmd_utf8);
return _wsystem(wchar_str.c_str()); return _wsystem(wchar_str.c_str());
#else #else
return system(cmd_utf8.c_str()); return system(cmd_utf8.c_str());
@ -111,7 +111,7 @@ int launchEmulatorWindows(const std::wstring& cmd_utf16)
errorCode = GetLastError(); errorCode = GetLastError();
std::string errorMessage = Utils::String::wideCharToChar(pBuffer); std::string errorMessage = Utils::String::wideStringToString(pBuffer);
// Remove trailing newline from the error message. // Remove trailing newline from the error message.
if (errorMessage.back() == '\n'); if (errorMessage.back() == '\n');
errorMessage.pop_back(); errorMessage.pop_back();

View file

@ -8,6 +8,7 @@
#include "Settings.h" #include "Settings.h"
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
#include "utils/StringUtil.h"
#include "Log.h" #include "Log.h"
#include "Scripting.h" #include "Scripting.h"
#include "Platform.h" #include "Platform.h"
@ -268,7 +269,11 @@ void Settings::saveFile()
node.append_attribute("value").set_value(iter->second.c_str()); node.append_attribute("value").set_value(iter->second.c_str());
} }
#ifdef _WIN64
doc.save_file(Utils::String::stringToWideString(path).c_str());
#else
doc.save_file(path.c_str()); doc.save_file(path.c_str());
#endif
Scripting::fireEvent("config-changed"); Scripting::fireEvent("config-changed");
Scripting::fireEvent("settings-changed"); Scripting::fireEvent("settings-changed");
@ -283,7 +288,11 @@ void Settings::loadFile()
return; return;
pugi::xml_document doc; pugi::xml_document doc;
#ifdef _WIN64
pugi::xml_parse_result result = doc.load_file(Utils::String::stringToWideString(path).c_str());
#else
pugi::xml_parse_result result = doc.load_file(path.c_str()); pugi::xml_parse_result result = doc.load_file(path.c_str());
#endif
if (!result) { if (!result) {
LOG(LogError) << "Error - Could not parse Settings file!\n " << result.description(); LOG(LogError) << "Error - Could not parse Settings file!\n " << result.description();
return; return;

View file

@ -260,7 +260,11 @@ void ThemeData::loadFile(std::map<std::string, std::string> sysDataMap, const st
mVariables.insert(sysDataMap.cbegin(), sysDataMap.cend()); mVariables.insert(sysDataMap.cbegin(), sysDataMap.cend());
pugi::xml_document doc; pugi::xml_document doc;
#ifdef _WIN64
pugi::xml_parse_result res = doc.load_file(Utils::String::stringToWideString(path).c_str());
#else
pugi::xml_parse_result res = doc.load_file(path.c_str()); pugi::xml_parse_result res = doc.load_file(path.c_str());
#endif
if (!res) if (!res)
throw error << "XML parsing error: \n " << res.description(); throw error << "XML parsing error: \n " << res.description();
@ -302,7 +306,12 @@ void ThemeData::parseIncludes(const pugi::xml_node& root)
mPaths.push_back(path); mPaths.push_back(path);
pugi::xml_document includeDoc; pugi::xml_document includeDoc;
#ifdef _WIN64
pugi::xml_parse_result result =
includeDoc.load_file(Utils::String::stringToWideString(path).c_str());
#else
pugi::xml_parse_result result = includeDoc.load_file(path.c_str()); pugi::xml_parse_result result = includeDoc.load_file(path.c_str());
#endif
if (!result) if (!result)
throw error << "Error parsing file: \n " << result.description(); throw error << "Error parsing file: \n " << result.description();

View file

@ -8,6 +8,7 @@
#include "ResourceManager.h" #include "ResourceManager.h"
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
#include "utils/StringUtil.h"
#include "Log.h" #include "Log.h"
#include "Platform.h" #include "Platform.h"
#include "Scripting.h" #include "Scripting.h"
@ -88,7 +89,11 @@ const ResourceData ResourceManager::getFileData(const std::string& path) const
ResourceData ResourceManager::loadFile(const std::string& path) const ResourceData ResourceManager::loadFile(const std::string& path) const
{ {
#ifdef _WIN64
std::ifstream stream(Utils::String::stringToWideString(path).c_str(), std::ios::binary);
#else
std::ifstream stream(path, std::ios::binary); std::ifstream stream(path, std::ios::binary);
#endif
stream.seekg(0, stream.end); stream.seekg(0, stream.end);
size_t size = (size_t)stream.tellg(); size_t size = (size_t)stream.tellg();

View file

@ -9,6 +9,8 @@
#define _FILE_OFFSET_BITS 64 #define _FILE_OFFSET_BITS 64
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
#include "utils/StringUtil.h"
#include "Log.h" #include "Log.h"
#include <sys/stat.h> #include <sys/stat.h>
@ -16,14 +18,8 @@
#include <string.h> #include <string.h>
#if defined(_WIN64) #if defined(_WIN64)
// Because windows...
#include <direct.h> #include <direct.h>
#include <Windows.h> #include <Windows.h>
#define getcwd _getcwd
#define mkdir(x,y) _mkdir(x)
#define snprintf _snprintf
#define stat64 _stat64
#define unlink _unlink
//#define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) //#define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
//#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) //#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
#else #else
@ -49,21 +45,6 @@ namespace Utils
static std::string homePath = ""; static std::string homePath = "";
static std::string exePath = ""; static std::string exePath = "";
#if defined(_WIN64)
static std::string convertFromWideString(const std::wstring wstring)
{
int numBytes = WideCharToMultiByte(CP_UTF8, 0, wstring.c_str(),
(int)wstring.length(), nullptr, 0, nullptr, nullptr);
std::string string;
string.resize(numBytes);
WideCharToMultiByte(CP_UTF8, 0, wstring.c_str(), (int)wstring.length(),
(char*)string.c_str(), numBytes, nullptr, nullptr);
return std::string(string);
}
#endif
stringList getDirContent(const std::string& _path, const bool _recursive) stringList getDirContent(const std::string& _path, const bool _recursive)
{ {
std::string path = getGenericPath(_path); std::string path = getGenericPath(_path);
@ -74,14 +55,13 @@ namespace Utils
#if defined(_WIN64) #if defined(_WIN64)
WIN32_FIND_DATAW findData; WIN32_FIND_DATAW findData;
std::string wildcard = path + "/*"; std::wstring wildcard = Utils::String::stringToWideString(path) + L"/*";
HANDLE hFind = FindFirstFileW(std::wstring(wildcard.begin(), HANDLE hFind = FindFirstFileW(wildcard.c_str(), &findData);
wildcard.end()).c_str(), &findData);
if (hFind != INVALID_HANDLE_VALUE) { if (hFind != INVALID_HANDLE_VALUE) {
// Loop over all files in the directory. // Loop over all files in the directory.
do { do {
std::string name = convertFromWideString(findData.cFileName); std::string name = Utils::String::wideStringToString(findData.cFileName);
// Ignore "." and ".." // Ignore "." and ".."
if ((name != ".") && (name != "..")) { if ((name != ".") && (name != "..")) {
std::string fullName(getGenericPath(path + "/" + name)); std::string fullName(getGenericPath(path + "/" + name));
@ -154,8 +134,15 @@ namespace Utils
#if defined(_WIN64) #if defined(_WIN64)
// On Windows we need to check HOMEDRIVE and HOMEPATH. // On Windows we need to check HOMEDRIVE and HOMEPATH.
if (!homePath.length()) { if (!homePath.length()) {
#ifdef _WIN64
std::string envHomeDrive =
Utils::String::wideStringToString(_wgetenv(L"HOMEDRIVE"));
std::string envHomePath =
Utils::String::wideStringToString(_wgetenv(L"HOMEPATH"));
#else
std::string envHomeDrive = getenv("HOMEDRIVE"); std::string envHomeDrive = getenv("HOMEDRIVE");
std::string envHomePath = getenv("HOMEPATH"); std::string envHomePath = getenv("HOMEPATH");
#endif
if (envHomeDrive.length() && envHomePath.length()) if (envHomeDrive.length() && envHomePath.length())
homePath = getGenericPath(envHomeDrive + "/" + envHomePath); homePath = getGenericPath(envHomeDrive + "/" + envHomePath);
} }
@ -180,7 +167,13 @@ namespace Utils
char temp[512]; char temp[512];
// Return current working directory. // Return current working directory.
#ifdef _WIN64
wchar_t tempWide[512];
return (_wgetcwd(tempWide, 512) ?
getGenericPath(Utils::String::wideStringToString(tempWide)) : "");
#else
return (getcwd(temp, 512) ? getGenericPath(temp) : ""); return (getcwd(temp, 512) ? getGenericPath(temp) : "");
#endif
} }
void setExePath(const std::string& _path) void setExePath(const std::string& _path)
@ -189,7 +182,7 @@ namespace Utils
#if defined(_WIN64) #if defined(_WIN64)
std::wstring result(path_max, 0); std::wstring result(path_max, 0);
if (GetModuleFileNameW(nullptr, &result[0], path_max) != 0) if (GetModuleFileNameW(nullptr, &result[0], path_max) != 0)
exePath = convertFromWideString(result); exePath = Utils::String::wideStringToString(result);
#else #else
std::string result(path_max, 0); std::string result(path_max, 0);
if (readlink("/proc/self/exe", &result[0], path_max) != -1) if (readlink("/proc/self/exe", &result[0], path_max) != -1)
@ -539,7 +532,12 @@ namespace Utils
return true; return true;
} }
#ifdef _WIN64
std::ifstream sourceFile(Utils::String::stringToWideString(_source_path).c_str(),
std::ios::binary);
#else
std::ifstream sourceFile(_source_path, std::ios::binary); std::ifstream sourceFile(_source_path, std::ios::binary);
#endif
if (sourceFile.fail()) { if (sourceFile.fail()) {
LOG(LogError) << "Error - Couldn't read from source file (" << _source_path << LOG(LogError) << "Error - Couldn't read from source file (" << _source_path <<
@ -548,7 +546,12 @@ namespace Utils
return true; return true;
} }
#ifdef _WIN64
std::ofstream targetFile(Utils::String::stringToWideString(_destination_path).c_str(),
std::ios::binary);
#else
std::ofstream targetFile(_destination_path, std::ios::binary); std::ofstream targetFile(_destination_path, std::ios::binary);
#endif
if (targetFile.fail()) { if (targetFile.fail()) {
LOG(LogError) << "Error - Couldn't write to target file (" << _destination_path << LOG(LogError) << "Error - Couldn't write to target file (" << _destination_path <<
@ -565,6 +568,38 @@ namespace Utils
return false; return false;
} }
bool renameFile(const std::string& _source_path,
const std::string& _destination_path, bool _overwrite)
{
// Don't print any error message for a missing source file as Log will use this
// function when initializing the logging. It would always generate an error in
// case it's the first application start (as an old log file would then not exist).
if (!exists(_source_path)) {
return true;
}
if(isDirectory(_destination_path)) {
LOG(LogError) << "Error - Destination file is actually a directory:";
LOG(LogError) << _destination_path;
return true;
}
if (!_overwrite && exists(_destination_path)) {
LOG(LogError) << "Error - Destination file exists and the overwrite flag "
"has not been set.";
return true;
}
#ifdef _WIN64
_wrename(Utils::String::stringToWideString(_source_path).c_str(),
Utils::String::stringToWideString(_destination_path).c_str());
#else
std::rename(_source_path.c_str(), _destination_path.c_str());
#endif
return false;
}
bool removeFile(const std::string& _path) bool removeFile(const std::string& _path)
{ {
std::string path = getGenericPath(_path); std::string path = getGenericPath(_path);
@ -574,7 +609,26 @@ namespace Utils
return true; return true;
// Try to remove file. // Try to remove file.
#ifdef _WIN64
if (_wunlink(Utils::String::stringToWideString(path).c_str()) != 0) {
LOG(LogError) << "Error - Couldn't delete file, permission problems?";
LOG(LogError) << path;
return true;
}
else {
return false;
}
#else
if (unlink(path.c_str()) != 0) {
LOG(LogError) << "Error - Couldn't delete file, permission problems?";
LOG(LogError) << path;
return true;
}
else {
return false;
}
return (unlink(path.c_str()) == 0); return (unlink(path.c_str()) == 0);
#endif
} }
bool createDirectory(const std::string& _path) bool createDirectory(const std::string& _path)
@ -586,8 +640,13 @@ namespace Utils
return true; return true;
// Try to create directory. // Try to create directory.
#ifdef _WIN64
if (_wmkdir(Utils::String::stringToWideString(path).c_str()) == 0)
return true;
#else
if (mkdir(path.c_str(), 0755) == 0) if (mkdir(path.c_str(), 0755) == 0)
return true; return true;
#endif
// Failed to create directory, try to create the parent. // Failed to create directory, try to create the parent.
std::string parent = getParent(path); std::string parent = getParent(path);
@ -597,15 +656,24 @@ namespace Utils
createDirectory(parent); createDirectory(parent);
// Try to create directory again now that the parent should exist. // Try to create directory again now that the parent should exist.
#ifdef _WIN64
return (_wmkdir(Utils::String::stringToWideString(path).c_str()) == 0);
#else
return (mkdir(path.c_str(), 0755) == 0); return (mkdir(path.c_str(), 0755) == 0);
#endif
} }
bool exists(const std::string& _path) bool exists(const std::string& _path)
{ {
std::string path = getGenericPath(_path); std::string path = getGenericPath(_path);
struct stat64 info;
#ifdef _WIN64
struct _stat64 info;
return (_wstat64(Utils::String::stringToWideString(path).c_str(), &info) == 0);
#else
struct stat64 info;
return (stat64(path.c_str(), &info) == 0); return (stat64(path.c_str(), &info) == 0);
#endif
} }
bool isAbsolute(const std::string& _path) bool isAbsolute(const std::string& _path)
@ -624,8 +692,13 @@ namespace Utils
std::string path = getGenericPath(_path); std::string path = getGenericPath(_path);
struct stat64 info; struct stat64 info;
#ifdef _WIN64
if (_wstat64(Utils::String::stringToWideString(path).c_str(), &info) != 0)
return false;
#else
if (stat64(path.c_str(), &info) != 0) if (stat64(path.c_str(), &info) != 0)
return false; return false;
#endif
// Check for S_IFREG attribute. // Check for S_IFREG attribute.
return (S_ISREG(info.st_mode)); return (S_ISREG(info.st_mode));
@ -634,10 +707,15 @@ namespace Utils
bool isDirectory(const std::string& _path) bool isDirectory(const std::string& _path)
{ {
std::string path = getGenericPath(_path); std::string path = getGenericPath(_path);
struct stat info; struct stat64 info;
if (stat(path.c_str(), &info) != 0) #ifdef _WIN64
if (_wstat64(Utils::String::stringToWideString(path).c_str(), &info) != 0)
return false; return false;
#else
if (stat64(path.c_str(), &info) != 0)
return false;
#endif
// Check for S_IFDIR attribute. // Check for S_IFDIR attribute.
return (S_ISDIR(info.st_mode)); return (S_ISDIR(info.st_mode));

View file

@ -47,7 +47,10 @@ namespace Utils
std::string resolveSymlink(const std::string& _path); std::string resolveSymlink(const std::string& _path);
bool copyFile(const std::string& _source_path, bool copyFile(const std::string& _source_path,
const std::string& _destination_path, bool _overwrite); const std::string& _destination_path, bool _overwrite);
bool renameFile(const std::string& _source_path,
const std::string& _destination_path, bool _overwrite);
bool removeFile(const std::string& _path); bool removeFile(const std::string& _path);
bool createDirectory(const std::string& _path); bool createDirectory(const std::string& _path);
bool exists(const std::string& _path); bool exists(const std::string& _path);
bool isAbsolute(const std::string& _path); bool isAbsolute(const std::string& _path);

View file

@ -187,7 +187,7 @@ namespace Utils
return string; return string;
} }
std::wstring charToWideChar(const std::string& _string) std::wstring stringToWideString(const std::string& _string)
{ {
typedef std::codecvt_utf8<wchar_t> convert_type; typedef std::codecvt_utf8<wchar_t> convert_type;
std::wstring_convert<convert_type, wchar_t> stringConverter; std::wstring_convert<convert_type, wchar_t> stringConverter;
@ -195,7 +195,7 @@ namespace Utils
return stringConverter.from_bytes(_string); return stringConverter.from_bytes(_string);
} }
std::string wideCharToChar(const std::wstring& _string) std::string wideStringToString(const std::wstring& _string)
{ {
typedef std::codecvt_utf8<wchar_t> convert_type; typedef std::codecvt_utf8<wchar_t> convert_type;
std::wstring_convert<convert_type, wchar_t> stringConverter; std::wstring_convert<convert_type, wchar_t> stringConverter;

View file

@ -28,8 +28,8 @@ namespace Utils
std::string trim(const std::string& _string); std::string trim(const std::string& _string);
std::string replace(const std::string& _string, const std::string& _replace, std::string replace(const std::string& _string, const std::string& _replace,
const std::string& _with); const std::string& _with);
std::wstring charToWideChar(const std::string& _string); std::wstring stringToWideString(const std::string& _string);
std::string wideCharToChar(const std::wstring& _string); std::string wideStringToString(const std::wstring& _string);
bool startsWith(const std::string& _string, const std::string& _start); bool startsWith(const std::string& _string, const std::string& _start);
bool endsWith(const std::string& _string, const std::string& _end); bool endsWith(const std::string& _string, const std::string& _end);
std::string removeParenthesis(const std::string& _string); std::string removeParenthesis(const std::string& _string);