diff --git a/es-app/src/CollectionSystemManager.cpp b/es-app/src/CollectionSystemManager.cpp index 372c64bf41..d6ba58790b 100644 --- a/es-app/src/CollectionSystemManager.cpp +++ b/es-app/src/CollectionSystemManager.cpp @@ -108,7 +108,11 @@ void CollectionSystemManager::saveCustomCollection(SystemData* sys) if (sysData.needsSave) { std::ofstream configFile; +#if defined(_WIN32) + configFile.open(Utils::FileSystem::convertToWideString(getCustomCollectionConfigPath(name))); +#else configFile.open(getCustomCollectionConfigPath(name)); +#endif for(std::unordered_map::const_iterator iter = games.cbegin(); iter != games.cend(); ++iter) { std::string path = iter->first; @@ -771,7 +775,11 @@ void CollectionSystemManager::populateCustomCollection(CollectionSystemData* sys FileFilterIndex* index = newSys->getIndex(); // get Configuration for this Custom System +#if defined(_WIN32) + std::ifstream input(Utils::FileSystem::convertToWideString(path)); +#else std::ifstream input(path); +#endif // get all files map std::unordered_map allFilesMap = getAllGamesCollection()->getRootFolder()->getChildrenByFilename(); @@ -873,7 +881,11 @@ std::vector CollectionSystemManager::getSystemsFromConfig() } pugi::xml_document doc; +#if defined(_WIN32) + pugi::xml_parse_result res = doc.load_file(Utils::FileSystem::convertToWideString(path).c_str()); +#else pugi::xml_parse_result res = doc.load_file(path.c_str()); +#endif if(!res) { diff --git a/es-app/src/Gamelist.cpp b/es-app/src/Gamelist.cpp index c4c712b553..bc001e9a90 100644 --- a/es-app/src/Gamelist.cpp +++ b/es-app/src/Gamelist.cpp @@ -92,7 +92,11 @@ void parseGamelist(SystemData* system) LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"..."; pugi::xml_document doc; +#if defined(_WIN32) + pugi::xml_parse_result result = doc.load_file(Utils::FileSystem::convertToWideString(xmlpath).c_str()); +#else pugi::xml_parse_result result = doc.load_file(xmlpath.c_str()); +#endif if(!result) { @@ -188,7 +192,11 @@ void updateGamelist(SystemData* system) if(Utils::FileSystem::exists(xmlReadPath)) { //parse an existing file first +#if defined(_WIN32) + pugi::xml_parse_result result = doc.load_file(Utils::FileSystem::convertToWideString(xmlReadPath).c_str()); +#else pugi::xml_parse_result result = doc.load_file(xmlReadPath.c_str()); +#endif if(!result) { @@ -303,7 +311,11 @@ void updateGamelist(SystemData* system) LOG(LogInfo) << "Added/Updated " << numUpdated << " entities in '" << xmlReadPath << "'"; +#if defined(_WIN32) + if (!doc.save_file(Utils::FileSystem::convertToWideString(xmlWritePath).c_str())) { +#else if (!doc.save_file(xmlWritePath.c_str())) { +#endif LOG(LogError) << "Error saving gamelist.xml to \"" << xmlWritePath << "\" (for system " << system->getName() << ")!"; } diff --git a/es-app/src/SystemData.cpp b/es-app/src/SystemData.cpp index 66b1cf83e7..43e4039076 100644 --- a/es-app/src/SystemData.cpp +++ b/es-app/src/SystemData.cpp @@ -271,7 +271,11 @@ bool SystemData::loadConfig(Window* window) } pugi::xml_document doc; +#if defined(_WIN32) + pugi::xml_parse_result res = doc.load_file(Utils::FileSystem::convertToWideString(path).c_str()); +#else pugi::xml_parse_result res = doc.load_file(path.c_str()); +#endif if(!res) { @@ -387,7 +391,11 @@ bool SystemData::loadConfig(Window* window) void SystemData::writeExampleConfig(const std::string& path) { +#if defined(_WIN32) + std::ofstream file(Utils::FileSystem::convertToWideString(path)); +#else std::ofstream file(path.c_str()); +#endif file << "\n" diff --git a/es-app/src/scrapers/GamesDBJSONScraperResources.cpp b/es-app/src/scrapers/GamesDBJSONScraperResources.cpp index 517fd3369e..3992a48568 100644 --- a/es-app/src/scrapers/GamesDBJSONScraperResources.cpp +++ b/es-app/src/scrapers/GamesDBJSONScraperResources.cpp @@ -144,7 +144,11 @@ bool TheGamesDBJSONRequestResources::saveResource(HttpReq* req, std::unordered_m ensureScrapersResourcesDir(); +#if defined(_WIN32) + std::ofstream fout(Utils::FileSystem::convertToWideString(file_name)); +#else std::ofstream fout(file_name); +#endif fout << req->getContent(); fout.close(); loadResource(resource, resource_name, file_name); @@ -166,7 +170,11 @@ int TheGamesDBJSONRequestResources::loadResource( { +#if defined(_WIN32) + std::ifstream fin(Utils::FileSystem::convertToWideString(file_name)); +#else std::ifstream fin(file_name); +#endif if (!fin.good()) { return 1; diff --git a/es-app/src/scrapers/Scraper.cpp b/es-app/src/scrapers/Scraper.cpp index bc3e6b00dd..8fa2011e67 100644 --- a/es-app/src/scrapers/Scraper.cpp +++ b/es-app/src/scrapers/Scraper.cpp @@ -218,7 +218,11 @@ void ImageDownloadHandle::update() } // download is done, save it to disk +#if defined(_WIN32) + std::ofstream stream(Utils::FileSystem::convertToWideString(mSavePath), std::ios_base::out | std::ios_base::binary); +#else std::ofstream stream(mSavePath, std::ios_base::out | std::ios_base::binary); +#endif if(stream.bad()) { setError("Failed to open image path to write. Permission error? Disk full?"); diff --git a/es-core/src/InputManager.cpp b/es-core/src/InputManager.cpp index 57c64b404f..e9cbdc6041 100644 --- a/es-core/src/InputManager.cpp +++ b/es-core/src/InputManager.cpp @@ -289,7 +289,11 @@ bool InputManager::loadInputConfig(InputConfig* config) return false; pugi::xml_document doc; +#if defined(_WIN32) + pugi::xml_parse_result res = doc.load_file(Utils::FileSystem::convertToWideString(path).c_str()); +#else pugi::xml_parse_result res = doc.load_file(path.c_str()); +#endif if(!res) { @@ -343,7 +347,11 @@ void InputManager::writeDeviceConfig(InputConfig* config) if(Utils::FileSystem::exists(path)) { // merge files +#if defined(_WIN32) + pugi::xml_parse_result result = doc.load_file(Utils::FileSystem::convertToWideString(path).c_str()); +#else pugi::xml_parse_result result = doc.load_file(path.c_str()); +#endif if(!result) { LOG(LogError) << "Error parsing input config: " << result.description(); @@ -388,7 +396,11 @@ void InputManager::writeDeviceConfig(InputConfig* config) root = doc.append_child("inputList"); config->writeToXML(root); +#if defined(_WIN32) + doc.save_file(Utils::FileSystem::convertToWideString(path).c_str()); +#else doc.save_file(path.c_str()); +#endif Scripting::fireEvent("config-changed"); Scripting::fireEvent("controls-changed"); @@ -406,7 +418,11 @@ void InputManager::doOnFinish() if(Utils::FileSystem::exists(path)) { +#if defined(_WIN32) + pugi::xml_parse_result result = doc.load_file(Utils::FileSystem::convertToWideString(path).c_str()); +#else pugi::xml_parse_result result = doc.load_file(path.c_str()); +#endif if(!result) { LOG(LogError) << "Error parsing input config: " << result.description(); diff --git a/es-core/src/Log.cpp b/es-core/src/Log.cpp index bcae38488d..a447432b9a 100644 --- a/es-core/src/Log.cpp +++ b/es-core/src/Log.cpp @@ -26,15 +26,25 @@ void Log::setReportingLevel(LogLevel level) void Log::init() { +#if defined(_WIN32) + _wunlink(Utils::FileSystem::convertToWideString(getLogPath() + ".bak").c_str()); + _wrename(Utils::FileSystem::convertToWideString(getLogPath()).c_str(), + Utils::FileSystem::convertToWideString(getLogPath() + ".bak").c_str()); +#else remove((getLogPath() + ".bak").c_str()); // rename previous log file rename(getLogPath().c_str(), (getLogPath() + ".bak").c_str()); +#endif return; } void Log::open() { +#if defined(_WIN32) + file = _wfopen(Utils::FileSystem::convertToWideString(getLogPath()).c_str(), L"w"); +#else file = fopen(getLogPath().c_str(), "w"); +#endif } std::ostringstream& Log::get(LogLevel level) diff --git a/es-core/src/MameNames.cpp b/es-core/src/MameNames.cpp index e0dee5c4b6..0fc68540e4 100644 --- a/es-core/src/MameNames.cpp +++ b/es-core/src/MameNames.cpp @@ -44,7 +44,11 @@ MameNames::MameNames() LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"..."; pugi::xml_document doc; +#if defined(_WIN32) + pugi::xml_parse_result result = doc.load_file(Utils::FileSystem::convertToWideString(xmlpath).c_str()); +#else pugi::xml_parse_result result = doc.load_file(xmlpath.c_str()); +#endif if(!result) { @@ -66,7 +70,11 @@ MameNames::MameNames() LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"..."; +#if defined(_WIN32) + result = doc.load_file(Utils::FileSystem::convertToWideString(xmlpath).c_str()); +#else result = doc.load_file(xmlpath.c_str()); +#endif if(!result) { @@ -88,7 +96,11 @@ MameNames::MameNames() LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"..."; +#if defined(_WIN32) + result = doc.load_file(Utils::FileSystem::convertToWideString(xmlpath).c_str()); +#else result = doc.load_file(xmlpath.c_str()); +#endif if(!result) { diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index 5ffefbcfc5..fcd51fb944 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -213,7 +213,11 @@ void Settings::saveFile() node.append_attribute("value").set_value(iter->second.c_str()); } +#if defined(_WIN32) + doc.save_file(Utils::FileSystem::convertToWideString(path).c_str()); +#else doc.save_file(path.c_str()); +#endif Scripting::fireEvent("config-changed"); Scripting::fireEvent("settings-changed"); @@ -227,7 +231,11 @@ void Settings::loadFile() return; pugi::xml_document doc; +#if defined(_WIN32) + pugi::xml_parse_result result = doc.load_file(Utils::FileSystem::convertToWideString(path).c_str()); +#else pugi::xml_parse_result result = doc.load_file(path.c_str()); +#endif if(!result) { LOG(LogError) << "Could not parse Settings file!\n " << result.description(); diff --git a/es-core/src/ThemeData.cpp b/es-core/src/ThemeData.cpp index cb1b2656c2..4dbcc159f4 100644 --- a/es-core/src/ThemeData.cpp +++ b/es-core/src/ThemeData.cpp @@ -241,7 +241,11 @@ void ThemeData::loadFile(std::map sysDataMap, const st mVariables.insert(sysDataMap.cbegin(), sysDataMap.cend()); pugi::xml_document doc; +#if defined(_WIN32) + pugi::xml_parse_result res = doc.load_file(Utils::FileSystem::convertToWideString(path).c_str()); +#else pugi::xml_parse_result res = doc.load_file(path.c_str()); +#endif if(!res) throw error << "XML parsing error: \n " << res.description(); @@ -297,7 +301,11 @@ void ThemeData::parseIncludes(const pugi::xml_node& root) mPaths.push_back(path); pugi::xml_document includeDoc; +#if defined(_WIN32) + pugi::xml_parse_result result = includeDoc.load_file(Utils::FileSystem::convertToWideString(path).c_str()); +#else pugi::xml_parse_result result = includeDoc.load_file(path.c_str()); +#endif if(!result) throw error << "Error parsing file: \n " << result.description(); diff --git a/es-core/src/platform.cpp b/es-core/src/platform.cpp index 81262310b7..cb88ae5ad9 100644 --- a/es-core/src/platform.cpp +++ b/es-core/src/platform.cpp @@ -9,6 +9,10 @@ #include #include "Log.h" +#ifdef WIN32 +#include +#include "utils/FileSystemUtil.h" +#endif int runShutdownCommand() { @@ -31,12 +35,26 @@ int runRestartCommand() int runSystemCommand(const std::string& cmd_utf8) { #ifdef WIN32 - // on Windows we use _wsystem to support non-ASCII paths - // which requires converting from utf8 to a wstring - typedef std::codecvt_utf8 convert_type; - std::wstring_convert converter; - std::wstring wchar_str = converter.from_bytes(cmd_utf8); - return _wsystem(wchar_str.c_str()); + STARTUPINFOW + si; + PROCESS_INFORMATION + pi; + DWORD + rcode = 0; + + memset(&si, 0, sizeof si); + memset(&pi, 0, sizeof pi); + si.cb = sizeof si; + + if(!CreateProcessW(NULL, (LPWSTR)Utils::FileSystem::convertToWideString(cmd_utf8).c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + return 9009; + + CloseHandle(pi.hThread); + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, &rcode); + CloseHandle(pi.hProcess); + + return rcode; #else return system(cmd_utf8.c_str()); #endif @@ -54,18 +72,17 @@ int quitES(QuitMode mode) return 0; } -void touch(const std::string& filename) -{ #ifdef WIN32 - FILE* fp = fopen(filename.c_str(), "ab+"); - if (fp != NULL) - fclose(fp); +// Windows hasn't /tmp directory usualy so nothing to touch. +inline void touch(const std::string&) {} #else +void touch(const std::string& filename) +{ int fd = open(filename.c_str(), O_CREAT|O_WRONLY, 0644); if (fd >= 0) close(fd); -#endif } +#endif void processQuitMode() { diff --git a/es-core/src/resources/ResourceManager.cpp b/es-core/src/resources/ResourceManager.cpp index 9353dda703..c340c9074f 100644 --- a/es-core/src/resources/ResourceManager.cpp +++ b/es-core/src/resources/ResourceManager.cpp @@ -65,7 +65,11 @@ const ResourceData ResourceManager::getFileData(const std::string& path) const ResourceData ResourceManager::loadFile(const std::string& path) const { +#if defined(_WIN32) + std::ifstream stream(Utils::FileSystem::convertToWideString(path), std::ios::binary); +#else std::ifstream stream(path, std::ios::binary); +#endif stream.seekg(0, stream.end); std::ifstream::pos_type size = stream.tellg(); diff --git a/es-core/src/utils/FileSystemUtil.cpp b/es-core/src/utils/FileSystemUtil.cpp index 4a028547b3..ce9531bd71 100644 --- a/es-core/src/utils/FileSystemUtil.cpp +++ b/es-core/src/utils/FileSystemUtil.cpp @@ -12,10 +12,9 @@ #include #include #define getcwd _getcwd -#define mkdir(x,y) _mkdir(x) #define snprintf _snprintf +#define stat _stat #define stat64 _stat64 -#define unlink _unlink #define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) #else // _WIN32 @@ -48,6 +47,38 @@ namespace Utils return std::string(string); } // convertFromWideString + std::wstring convertToWideString(const std::string string) + { + int numChars = MultiByteToWideChar(CP_UTF8, 0, string.c_str(), (int)string.length(), nullptr, 0); + std::wstring wstring; + + wstring.resize(numChars); + MultiByteToWideChar(CP_UTF8, 0, string.c_str(), (int)string.length(), (wchar_t*)wstring.c_str(), numChars); + + return std::wstring(wstring); + + } // convertToWideString + static void getenv(const char* name, std::string &val) + { + wchar_t* r = ::_wgetenv(convertToWideString(name).c_str()); + val = r ? convertFromWideString(r) : ""; + } // getenv + static int stat(const char* pathname, struct stat* buf) + { + return _wstat(convertToWideString(pathname).c_str(), buf); + } // stat + static int stat64(const char* pathname, struct stat64* buf) + { + return _wstat64(convertToWideString(pathname).c_str(), buf); + } // stat64 + static int unlink(const char* pathname) + { + return _wunlink(convertToWideString(pathname).c_str()); + } // unlink + static int mkdir(const char *pathname, int) + { + return _wmkdir(convertToWideString(pathname).c_str()); + } // mkdir #endif // _WIN32 ////////////////////////////////////////////////////////////////////////// @@ -66,7 +97,7 @@ namespace Utils WIN32_FIND_DATAW findData; const std::string wildcard = path + "/*"; - const HANDLE hFind = FindFirstFileW(std::wstring(wildcard.begin(), wildcard.end()).c_str(), &findData); + const HANDLE hFind = FindFirstFileW(convertToWideString(wildcard).c_str(), &findData); if(hFind != INVALID_HANDLE_VALUE) { @@ -174,23 +205,33 @@ namespace Utils if(Utils::FileSystem::exists(getExePath() + "/.emulationstation/es_systems.cfg")) homePath = getExePath(); +#if defined(_WIN32) // check for HOME environment variable if(!homePath.length()) { - const char* envHome = getenv("HOME"); - if(envHome) + std::string envHome; + getenv("HOME", envHome); + if(!envHome.empty()) homePath = getGenericPath(envHome); } -#if defined(_WIN32) // on Windows we need to check HOMEDRIVE and HOMEPATH if(!homePath.length()) { - const char* envHomeDrive = getenv("HOMEDRIVE"); - const char* envHomePath = getenv("HOMEPATH"); - if(envHomeDrive && envHomePath) + std::string envHomeDrive, envHomePath; + getenv("HOMEDRIVE", envHomeDrive); + getenv("HOMEPATH", envHomePath); + if(!envHomeDrive.empty() && !envHomePath.empty()) homePath = getGenericPath(std::string(envHomeDrive) + "/" + envHomePath); } +#else // _WIN32 + // check for HOME environment variable + if(!homePath.length()) + { + char* envHome = getenv("HOME"); + if(envHome) + homePath = getGenericPath(envHome); + } #endif // _WIN32 // no homepath found, fall back to current working directory @@ -221,8 +262,11 @@ namespace Utils #if defined(_WIN32) std::wstring result(path_max, 0); - if(GetModuleFileNameW(nullptr, &result[0], path_max) != 0) + DWORD r; + if((r = GetModuleFileNameW(nullptr, (LPWSTR)result.data(), result.size())) != 0){ + result.resize(r); exePath = convertFromWideString(result); + } #else // _WIN32 std::string result(path_max, 0); if(readlink("/proc/self/exe", &result[0], path_max) != -1) @@ -563,14 +607,17 @@ namespace Utils std::string resolved; #if defined(_WIN32) - const HANDLE hFile = CreateFile(path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + const HANDLE hFile = CreateFileW(convertToWideString(path).c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); if(hFile != INVALID_HANDLE_VALUE) { - resolved.resize(GetFinalPathNameByHandle(hFile, nullptr, 0, FILE_NAME_NORMALIZED) + 1); - if(GetFinalPathNameByHandle(hFile, (LPSTR)resolved.data(), (DWORD)resolved.size(), FILE_NAME_NORMALIZED) > 0) + std::wstring wresolved; + DWORD r; + wresolved.resize(GetFinalPathNameByHandleW(hFile, nullptr, 0, FILE_NAME_NORMALIZED)); + if((r = GetFinalPathNameByHandleW(hFile, (LPWSTR)wresolved.data(), wresolved.size(), FILE_NAME_NORMALIZED)) > 0) { - resolved.resize(resolved.size() - 1); + wresolved.resize(r); + resolved = convertFromWideString(wresolved); resolved = getGenericPath(resolved); } CloseHandle(hFile); @@ -709,7 +756,7 @@ namespace Utils #if defined(_WIN32) // check for symlink attribute - const DWORD Attributes = GetFileAttributes(path.c_str()); + const DWORD Attributes = GetFileAttributesW(convertToWideString(path).c_str()); if((Attributes != INVALID_FILE_ATTRIBUTES) && (Attributes & FILE_ATTRIBUTE_REPARSE_POINT)) return true; #else // _WIN32 @@ -736,7 +783,7 @@ namespace Utils #if defined(_WIN32) // check for hidden attribute - const DWORD Attributes = GetFileAttributes(path.c_str()); + const DWORD Attributes = GetFileAttributesW(convertToWideString(path).c_str()); if((Attributes != INVALID_FILE_ATTRIBUTES) && (Attributes & FILE_ATTRIBUTE_HIDDEN)) return true; #endif // _WIN32 diff --git a/es-core/src/utils/FileSystemUtil.h b/es-core/src/utils/FileSystemUtil.h index 20a00a26f3..53e49ffd4e 100644 --- a/es-core/src/utils/FileSystemUtil.h +++ b/es-core/src/utils/FileSystemUtil.h @@ -42,6 +42,9 @@ namespace Utils #if !defined(_WIN32) bool isExecutable (const std::string& _path); #endif // !_WIN32 +#if defined(_WIN32) + std::wstring convertToWideString(const std::string string); +#endif } // FileSystem::