diff options
Diffstat (limited to 'src/common/file_util.cpp')
-rw-r--r-- | src/common/file_util.cpp | 194 |
1 files changed, 117 insertions, 77 deletions
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index b6ff2e40b..35da07306 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -4,9 +4,7 @@ #include "common/common.h" -#include "common/common_paths.h" #include "common/file_util.h" -#include "common/string_util.h" #ifdef _WIN32 #include <windows.h> @@ -15,11 +13,9 @@ #include <commdlg.h> // for GetSaveFileName #include <io.h> #include <direct.h> // getcwd +#include <tchar.h> #else -#include <cerrno> -#include <cstdlib> #include <sys/param.h> -#include <sys/types.h> #include <dirent.h> #endif @@ -32,8 +28,6 @@ #include <algorithm> #include <sys/stat.h> -#include "common/string_util.h" - #ifndef S_ISDIR #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) #endif @@ -46,7 +40,7 @@ // This namespace has various generic functions related to files and paths. // The code still needs a ton of cleanup. // REMEMBER: strdup considered harmful! -namespace File +namespace FileUtil { // Remove any ending forward slashes from directory paths @@ -71,7 +65,7 @@ bool Exists(const std::string &filename) StripTailDirSlashes(copy); #ifdef _WIN32 - int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); + int result = _tstat64(Common::UTF8ToTStr(copy).c_str(), &file_info); #else int result = stat64(copy.c_str(), &file_info); #endif @@ -88,7 +82,7 @@ bool IsDirectory(const std::string &filename) StripTailDirSlashes(copy); #ifdef _WIN32 - int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); + int result = _tstat64(Common::UTF8ToTStr(copy).c_str(), &file_info); #else int result = stat64(copy.c_str(), &file_info); #endif @@ -124,7 +118,7 @@ bool Delete(const std::string &filename) } #ifdef _WIN32 - if (!DeleteFile(UTF8ToTStr(filename).c_str())) + if (!DeleteFile(Common::UTF8ToTStr(filename).c_str())) { WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg()); @@ -146,7 +140,7 @@ bool CreateDir(const std::string &path) { INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); #ifdef _WIN32 - if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL)) + if (::CreateDirectory(Common::UTF8ToTStr(path).c_str(), NULL)) return true; DWORD error = GetLastError(); if (error == ERROR_ALREADY_EXISTS) @@ -179,7 +173,7 @@ bool CreateFullPath(const std::string &fullPath) int panicCounter = 100; INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); - if (File::Exists(fullPath)) + if (FileUtil::Exists(fullPath)) { INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); return true; @@ -197,8 +191,10 @@ bool CreateFullPath(const std::string &fullPath) // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") std::string const subPath(fullPath.substr(0, position + 1)); - if (!File::IsDirectory(subPath)) - File::CreateDir(subPath); + if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) { + ERROR_LOG(COMMON, "CreateFullPath: directory creation failed"); + return false; + } // A safety check panicCounter--; @@ -218,14 +214,14 @@ bool DeleteDir(const std::string &filename) INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str()); // check if a directory - if (!File::IsDirectory(filename)) + if (!FileUtil::IsDirectory(filename)) { ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str()); return false; } #ifdef _WIN32 - if (::RemoveDirectory(UTF8ToTStr(filename).c_str())) + if (::RemoveDirectory(Common::UTF8ToTStr(filename).c_str())) return true; #else if (rmdir(filename.c_str()) == 0) @@ -254,7 +250,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) INFO_LOG(COMMON, "Copy: %s --> %s", srcFilename.c_str(), destFilename.c_str()); #ifdef _WIN32 - if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE)) + if (CopyFile(Common::UTF8ToTStr(srcFilename).c_str(), Common::UTF8ToTStr(destFilename).c_str(), FALSE)) return true; ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", @@ -342,7 +338,7 @@ u64 GetSize(const std::string &filename) struct stat64 buf; #ifdef _WIN32 - if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0) + if (_tstat64(Common::UTF8ToTStr(filename).c_str(), &buf) == 0) #else if (stat64(filename.c_str(), &buf) == 0) #endif @@ -393,7 +389,7 @@ bool CreateEmptyFile(const std::string &filename) { INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); - if (!File::IOFile(filename, "wb")) + if (!FileUtil::IOFile(filename, "wb")) { ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", filename.c_str(), GetLastErrorMsg()); @@ -415,7 +411,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) // Find the first file in the directory. WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); + HANDLE hFind = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd); if (hFind == INVALID_HANDLE_VALUE) { FindClose(hFind); @@ -425,7 +421,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) do { FSTEntry entry; - const std::string virtualName(TStrToUTF8(ffd.cFileName)); + const std::string virtualName(Common::TStrToUTF8(ffd.cFileName)); #else struct dirent dirent, *result = NULL; @@ -482,7 +478,7 @@ bool DeleteDirRecursively(const std::string &directory) #ifdef _WIN32 // Find the first file in the directory. WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); + HANDLE hFind = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd); if (hFind == INVALID_HANDLE_VALUE) { @@ -493,7 +489,7 @@ bool DeleteDirRecursively(const std::string &directory) // windows loop do { - const std::string virtualName(TStrToUTF8(ffd.cFileName)); + const std::string virtualName(Common::TStrToUTF8(ffd.cFileName)); #else struct dirent dirent, *result = NULL; DIR *dirp = opendir(directory.c_str()); @@ -526,7 +522,7 @@ bool DeleteDirRecursively(const std::string &directory) } else { - if (!File::Delete(newPath)) + if (!FileUtil::Delete(newPath)) { #ifndef _WIN32 closedir(dirp); @@ -543,7 +539,7 @@ bool DeleteDirRecursively(const std::string &directory) } closedir(dirp); #endif - File::DeleteDir(directory); + FileUtil::DeleteDir(directory); return true; } @@ -553,8 +549,8 @@ void CopyDir(const std::string &source_path, const std::string &dest_path) { #ifndef _WIN32 if (source_path == dest_path) return; - if (!File::Exists(source_path)) return; - if (!File::Exists(dest_path)) File::CreateFullPath(dest_path); + if (!FileUtil::Exists(source_path)) return; + if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path); struct dirent dirent, *result = NULL; DIR *dirp = opendir(source_path.c_str()); @@ -576,10 +572,10 @@ void CopyDir(const std::string &source_path, const std::string &dest_path) { source += '/'; dest += '/'; - if (!File::Exists(dest)) File::CreateFullPath(dest); + if (!FileUtil::Exists(dest)) FileUtil::CreateFullPath(dest); CopyDir(source, dest); } - else if (!File::Exists(dest)) File::Copy(source, dest); + else if (!FileUtil::Exists(dest)) FileUtil::Copy(source, dest); } closedir(dirp); #endif @@ -631,7 +627,7 @@ std::string& GetExeDirectory() { TCHAR Dolphin_exe_Path[2048]; GetModuleFileName(NULL, Dolphin_exe_Path, 2048); - DolphinPath = TStrToUTF8(Dolphin_exe_Path); + DolphinPath = Common::TStrToUTF8(Dolphin_exe_Path); DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); } return DolphinPath; @@ -655,7 +651,7 @@ std::string GetSysDirectory() return sysDir; } -// Returns a string with a Dolphin data dir or file in the user's home +// Returns a string with a Citra data dir or file in the user's home // directory. To be used in "multi-user" mode (that is, installed). const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath) { @@ -667,7 +663,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new #ifdef _WIN32 paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; #else - if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) + if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; else paths[D_USER_IDX] = std::string(getenv("HOME") ? @@ -675,27 +671,28 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new getenv("PWD") : "") + DIR_SEP EMU_DATA_DIR DIR_SEP; #endif - paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; - paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; - paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; - paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; + paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; + paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; + paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; - paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; + paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; - paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; - paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; - paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; - paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; + paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; + paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; + paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; } if (!newPath.empty()) { - if (!File::IsDirectory(newPath)) + if (!FileUtil::IsDirectory(newPath)) { WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str()); return paths[DirIDX]; @@ -708,43 +705,44 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new switch (DirIDX) { case D_ROOT_IDX: - paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; - paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; - paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; + paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; + paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; + paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; break; case D_USER_IDX: - paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; - paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; - paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; - paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; - paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; + paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; + paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; + paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; + paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; - paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; + paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; - paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; - paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; - paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; + paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; + paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP; - paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; - paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; + paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; + paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; break; case D_CONFIG_IDX: - paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; - paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; + paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; + paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; break; case D_DUMP_IDX: - paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; break; case D_LOGS_IDX: @@ -757,25 +755,25 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new //std::string GetThemeDir(const std::string& theme_name) //{ -// std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/"; +// std::string dir = FileUtil::GetUserPath(D_THEMES_IDX) + theme_name + "/"; // //#if !defined(_WIN32) // // If theme does not exist in user's dir load from shared directory -// if (!File::Exists(dir)) +// if (!FileUtil::Exists(dir)) // dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/"; //#endif // // return dir; //} -bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) +size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename) { - return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); + return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); } -bool ReadFileToString(bool text_file, const char *filename, std::string &str) +size_t ReadFileToString(bool text_file, const char *filename, std::string &str) { - File::IOFile file(filename, text_file ? "r" : "rb"); + FileUtil::IOFile file(filename, text_file ? "r" : "rb"); auto const f = file.GetHandle(); if (!f) @@ -785,6 +783,48 @@ bool ReadFileToString(bool text_file, const char *filename, std::string &str) return file.ReadArray(&str[0], str.size()); } +/** + * Splits the filename into 8.3 format + * Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename + * @param filename The normal filename to use + * @param short_name A 9-char array in which the short name will be written + * @param extension A 4-char array in which the extension will be written + */ +void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name, + std::array<char, 4>& extension) { + const std::string forbidden_characters = ".\"/\\[]:;=, "; + + // On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces. + short_name = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'}; + extension = {' ', ' ', ' ', '\0'}; + + std::string::size_type point = filename.rfind('.'); + if (point == filename.size() - 1) + point = filename.rfind('.', point); + + // Get short name. + int j = 0; + for (char letter : filename.substr(0, point)) { + if (forbidden_characters.find(letter, 0) != std::string::npos) + continue; + if (j == 8) { + // TODO(Link Mauve): also do that for filenames containing a space. + // TODO(Link Mauve): handle multiple files having the same short name. + short_name[6] = '~'; + short_name[7] = '1'; + break; + } + short_name[j++] = toupper(letter); + } + + // Get extension. + if (point != std::string::npos) { + j = 0; + for (char letter : filename.substr(point + 1, 3)) + extension[j++] = toupper(letter); + } +} + IOFile::IOFile() : m_file(NULL), m_good(true) {} @@ -826,7 +866,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[]) { Close(); #ifdef _WIN32 - _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()); + _tfopen_s(&m_file, Common::UTF8ToTStr(filename).c_str(), Common::UTF8ToTStr(openmode).c_str()); #else m_file = fopen(filename.c_str(), openmode); #endif @@ -861,7 +901,7 @@ void IOFile::SetHandle(std::FILE* file) u64 IOFile::GetSize() { if (IsOpen()) - return File::GetSize(m_file); + return FileUtil::GetSize(m_file); else return 0; } |