Core: Handle paths with non-ASCII characters

This commit is contained in:
zilmar 2024-10-10 18:01:10 +10:30
parent 7aa77a3840
commit a2e479a705
9 changed files with 160 additions and 128 deletions

View File

@ -1,4 +1,5 @@
#include "DynamicLibrary.h"
#include "StdString.h"
#ifdef _WIN32
#include <windows.h>
#else
@ -15,7 +16,7 @@ DynLibHandle DynamicLibraryOpen(const char * pccLibraryPath, bool ShowErrors)
}
#ifdef _WIN32
UINT LastErrorMode = SetErrorMode(ShowErrors ? 0 : SEM_FAILCRITICALERRORS);
DynLibHandle Lib = (DynLibHandle)LoadLibraryA(pccLibraryPath);
DynLibHandle Lib = (DynLibHandle)LoadLibrary(stdstr(pccLibraryPath).ToUTF16().c_str());
SetErrorMode(LastErrorMode);
#else
DynLibHandle Lib = (DynLibHandle)dlopen(pccLibraryPath, RTLD_NOW);

View File

@ -1,4 +1,5 @@
#include "File.h"
#include "StdString.h"
#include "path.h"
#include <stdio.h>
#include <string.h>
@ -122,7 +123,7 @@ bool CFile::Open(const char * lpszFileName, uint32_t nOpenFlags)
}
// Attempt file creation
HANDLE hFile = ::CreateFileA(lpszFileName, dwAccess, dwShareMode, &sa, dwCreateFlag, FILE_ATTRIBUTE_NORMAL, nullptr);
HANDLE hFile = ::CreateFile(stdstr(lpszFileName).ToUTF16().c_str(), dwAccess, dwShareMode, &sa, dwCreateFlag, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile == INVALID_HANDLE_VALUE)
{ //#define ERROR_PATH_NOT_FOUND 3L
//ULONG err = GetLastError();
@ -235,7 +236,9 @@ bool CFile::Flush()
return ::FlushFileBuffers(m_hFile) != 0;
#else
fflush((FILE *)m_hFile);
#ifndef WIN32
fsync(fileno((FILE *)m_hFile));
#endif
return true;
#endif
}
@ -268,6 +271,49 @@ bool CFile::Write(const void * lpBuf, uint32_t nCount)
return true;
}
bool CFile::ReadInterger(int32_t & Value)
{
#ifdef USE_WINDOWS_API
LARGE_INTEGER CurrentPos;
LARGE_INTEGER Zero = {0};
if (!SetFilePointerEx(m_hFile, Zero, &CurrentPos, FILE_CURRENT))
{
return false;
}
char buffer[256];
DWORD bytesRead = 0;
if (!::ReadFile(m_hFile, buffer, sizeof(buffer) - 1, &bytesRead, nullptr) || bytesRead == 0)
{
return false;
}
buffer[bytesRead] = '\0';
int CharsRead = 0;
int Number;
sscanf(buffer, "%d%n", &Number, &CharsRead);
LARGE_INTEGER NewPos;
NewPos.QuadPart = CurrentPos.QuadPart + CharsRead;
if (!SetFilePointerEx(m_hFile, NewPos, NULL, FILE_BEGIN))
{
return false;
}
if (CharsRead == 0)
{
return false;
}
Value = Number;
return true;
#else
va_list args;
va_start(args, Format);
int Result = vfscanf((FILE *)m_hFile, "%d", args);
va_end(args);
return Result != 0;
#endif
}
uint32_t CFile::Read(void * lpBuf, uint32_t nCount)
{
if (nCount == 0)

View File

@ -62,6 +62,7 @@ public:
virtual uint32_t GetLength() const;
virtual uint32_t Read(void * lpBuf, uint32_t nCount);
virtual bool ReadInterger(int32_t & Value);
virtual bool Write(const void * lpBuf, uint32_t nCount);
virtual bool Flush();

View File

@ -871,15 +871,16 @@ void CPath::UpDirectory(std::string * pLastDirectory /*= nullptr*/)
void CPath::CurrentDirectory()
{
char buff_path[260];
memset(buff_path, 0, sizeof(buff_path));
Empty();
#ifdef _WIN32
::GetCurrentDirectoryA(sizeof(buff_path), buff_path);
SetDriveDirectory(buff_path);
wchar_t buff_path[260];
memset(buff_path, 0, sizeof(buff_path));
::GetCurrentDirectory(sizeof(buff_path), buff_path);
SetDriveDirectory(stdstr().FromUTF16(buff_path).c_str());
#else
char buff_path[260];
memset(buff_path, 0, sizeof(buff_path));
getcwd(buff_path, sizeof(buff_path));
SetDirectory(buff_path);
#endif
@ -890,12 +891,10 @@ void CPath::CurrentDirectory()
#ifdef _WIN32
void CPath::Module(void * hInstance)
{
char buff_path[MAX_PATH];
wchar_t buff_path[MAX_PATH];
memset(buff_path, 0, sizeof(buff_path));
GetModuleFileNameA((HINSTANCE)hInstance, buff_path, MAX_PATH);
m_strPath = buff_path;
GetModuleFileName((HINSTANCE)hInstance, buff_path, MAX_PATH);
m_strPath = stdstr().FromUTF16(buff_path);
}
// Task: Set path to the name of current module
@ -954,8 +953,8 @@ bool CPath::DirectoryExists() const
TestPath.UpDirectory(&DirName);
TestPath.SetNameExtension(DirName.c_str());
WIN32_FIND_DATAA FindData;
HANDLE hFindFile = FindFirstFileA((const char *)TestPath, &FindData); // Find anything
WIN32_FIND_DATA FindData;
HANDLE hFindFile = FindFirstFile(stdstr((const char *)TestPath).ToUTF16().c_str(), &FindData); // Find anything
bool res = (hFindFile != INVALID_HANDLE_VALUE);
if (hFindFile != nullptr) // Make sure we close the search
@ -982,8 +981,8 @@ bool CPath::DirectoryExists() const
bool CPath::Exists() const
{
#ifdef _WIN32
WIN32_FIND_DATAA FindData;
HANDLE hFindFile = FindFirstFileA(m_strPath.c_str(), &FindData);
WIN32_FIND_DATA FindData;
HANDLE hFindFile = FindFirstFile(stdstr(m_strPath).ToUTF16().c_str(), &FindData);
bool bSuccess = (hFindFile != INVALID_HANDLE_VALUE);
if (hFindFile != nullptr) // Make sure we close the search
@ -1002,21 +1001,23 @@ bool CPath::Exists() const
bool CPath::SelectFile(void * hwndOwner, const char * InitialDir, const char * FileFilter, bool FileMustExist)
{
CPath CurrentDir(CURRENT_DIRECTORY);
std::wstring FileFilterW = stdstr(FileFilter).ToUTF16();
std::wstring InitialDirW = stdstr(InitialDir).ToUTF16();
OPENFILENAMEA openfilename;
char FileName[MAX_PATH];
OPENFILENAME openfilename;
wchar_t FileName[MAX_PATH];
memset(&FileName, 0, sizeof(FileName));
memset(&openfilename, 0, sizeof(openfilename));
openfilename.lStructSize = sizeof(openfilename);
openfilename.hwndOwner = (HWND)hwndOwner;
openfilename.lpstrFilter = FileFilter;
openfilename.lpstrFilter = FileFilterW.c_str();
openfilename.lpstrFile = FileName;
openfilename.lpstrInitialDir = InitialDir;
openfilename.lpstrInitialDir = InitialDirW.c_str();
openfilename.nMaxFile = MAX_PATH;
openfilename.Flags = OFN_HIDEREADONLY | (FileMustExist ? OFN_FILEMUSTEXIST : 0);
bool res = GetOpenFileNameA(&openfilename) != 0;
bool res = GetOpenFileName(&openfilename) != 0;
if (CPath(CURRENT_DIRECTORY) != CurrentDir)
{
CurrentDir.ChangeDirectory();
@ -1025,7 +1026,7 @@ bool CPath::SelectFile(void * hwndOwner, const char * InitialDir, const char * F
{
return false;
}
m_strPath = FileName;
m_strPath = stdstr().FromUTF16(FileName);
cleanPathString(m_strPath);
return true;
}
@ -1037,7 +1038,8 @@ bool CPath::SelectFile(void * hwndOwner, const char * InitialDir, const char * F
bool CPath::Delete(bool bEvenIfReadOnly) const
{
#ifdef _WIN32
uint32_t dwAttr = ::GetFileAttributesA(m_strPath.c_str());
std::wstring FilePath = stdstr(m_strPath).ToUTF16();
uint32_t dwAttr = ::GetFileAttributes(FilePath.c_str());
if (dwAttr == (uint32_t)-1)
{
// File does not exist
@ -1050,8 +1052,8 @@ bool CPath::Delete(bool bEvenIfReadOnly) const
return false;
}
SetFileAttributesA(m_strPath.c_str(), FILE_ATTRIBUTE_NORMAL);
return DeleteFileA(m_strPath.c_str()) != 0;
SetFileAttributes(FilePath.c_str(), FILE_ATTRIBUTE_NORMAL);
return DeleteFile(FilePath.c_str()) != 0;
#else
return unlink(m_strPath.c_str()) == 0;
#endif
@ -1093,7 +1095,7 @@ bool CPath::CopyTo(const char * lpcszTargetFile, bool bOverwrite)
// CopyFile will set the target's attributes to the same as
// the source after copying
return CopyFileA(m_strPath.c_str(), lpcszTargetFile, !bOverwrite) != 0;
return CopyFile(stdstr(m_strPath).ToUTF16().c_str(), stdstr(lpcszTargetFile).ToUTF16().c_str(), !bOverwrite) != 0;
#else
bool res = true;
@ -1206,7 +1208,7 @@ bool CPath::MoveTo(const char * lpcszTargetFile, bool bOverwrite)
}
}
return MoveFileA(m_strPath.c_str(), lpcszTargetFile) != 0;
return MoveFile(stdstr(m_strPath).ToUTF16().c_str(), stdstr(lpcszTargetFile).ToUTF16().c_str()) != 0;
#else
return false;
#endif
@ -1261,8 +1263,8 @@ bool CPath::FindFirst(uint32_t dwAttributes /*= FIND_ATTRIBUTE_FILES*/)
BOOL bWantSubdirectory = (BOOL)(FIND_ATTRIBUTE_SUBDIR & dwAttributes);
// Finding first candidate file
WIN32_FIND_DATAA FindData;
m_hFindFile = FindFirstFileA(m_strPath.c_str(), &FindData);
WIN32_FIND_DATA FindData;
m_hFindFile = FindFirstFile(stdstr(m_strPath).ToUTF16().c_str(), &FindData);
bGotFile = (m_hFindFile != INVALID_HANDLE_VALUE);
while (bGotFile)
@ -1277,7 +1279,7 @@ bool CPath::FindFirst(uint32_t dwAttributes /*= FIND_ATTRIBUTE_FILES*/)
if ((FIND_ATTRIBUTE_SUBDIR & FindData.dwFileAttributes) != 0)
StripTrailingBackslash(m_strPath);
SetNameExtension(FindData.cFileName);
SetNameExtension(stdstr().FromUTF16(FindData.cFileName).c_str());
if ((FIND_ATTRIBUTE_SUBDIR & FindData.dwFileAttributes) != 0)
EnsureTrailingBackslash(m_strPath);
@ -1285,7 +1287,7 @@ bool CPath::FindFirst(uint32_t dwAttributes /*= FIND_ATTRIBUTE_FILES*/)
// Not found a match, get another
LABEL_GetAnother:
bGotFile = FindNextFileA(m_hFindFile, &FindData);
bGotFile = FindNextFile(m_hFindFile, &FindData);
}
#else
std::string Directory, Name, Extension;
@ -1316,8 +1318,8 @@ bool CPath::FindNext()
return false;
}
WIN32_FIND_DATAA FindData;
while (FindNextFileA(m_hFindFile, &FindData) != false)
WIN32_FIND_DATA FindData;
while (FindNextFile(m_hFindFile, &FindData) != false)
{ // while(FindNext(...))
if (AttributesMatch(m_dwFindFileAttributes, FindData.dwFileAttributes))
{ // if(AttributesMatch(...)
@ -1332,7 +1334,7 @@ bool CPath::FindNext()
{
SetNameExtension("");
}
AppendDirectory(FindData.cFileName);
AppendDirectory(stdstr().FromUTF16(FindData.cFileName).c_str());
}
else
{
@ -1342,7 +1344,7 @@ bool CPath::FindNext()
// Found a directory
UpDirectory();
}
SetNameExtension(FindData.cFileName);
SetNameExtension(stdstr().FromUTF16(FindData.cFileName).c_str());
}
if ((_A_SUBDIR & FindData.dwFileAttributes) == _A_SUBDIR)
{
@ -1413,7 +1415,7 @@ bool CPath::ChangeDirectory()
std::string DriveDirectory;
GetDriveDirectory(DriveDirectory);
return SetCurrentDirectoryA(DriveDirectory.c_str()) != 0;
return SetCurrentDirectory(stdstr(DriveDirectory).ToUTF16().c_str()) != 0;
#else
std::string Dir;
GetDirectory(Dir);
@ -1490,9 +1492,9 @@ bool CPath::DirectoryCreate(bool bCreateIntermediates /*= TRUE*/)
GetDriveDirectory(PathText);
StripTrailingBackslash(PathText);
WriteTrace(TracePath, TraceDebug, "Create %s", PathText.c_str());
bSuccess = ::CreateDirectoryA(PathText.c_str(), nullptr) != 0;
bSuccess = ::CreateDirectory(stdstr(PathText).ToUTF16().c_str(), nullptr) != 0;
#else
GetDirectory(PathText);
GetDirectory(PathText);7
StripTrailingBackslash(PathText);
WriteTrace(TracePath, TraceDebug, "Create %s", PathText.c_str());
bSuccess = mkdir(PathText.c_str(), S_IRWXU) == 0;

View File

@ -589,7 +589,6 @@ CLanguage::~CLanguage()
bool CLanguage::LoadCurrentStrings(void)
{
// Clear all the current strings loaded
m_CurrentStrings.clear();
if (g_Settings->LoadBool(Debugger_DebugLanguage))
@ -601,7 +600,6 @@ bool CLanguage::LoadCurrentStrings(void)
LanguageList LangList = GetLangList();
stdstr Filename;
// Find the file name of the current language
for (LanguageList::iterator Language = LangList.begin(); Language != LangList.end(); Language++)
{
if (g_Lang->IsCurrentLang(*Language))
@ -616,30 +614,31 @@ bool CLanguage::LoadCurrentStrings(void)
return false;
}
// Process the file
FILE * file = fopen(Filename.c_str(), "rb");
if (file == nullptr)
CFile File(Filename.c_str(), CFileBase::modeRead);
if (!File.IsOpen())
{
return false;
}
// Search for UTF8 file marker
uint8_t utf_bom[3];
if (fread(&utf_bom, sizeof(utf_bom), 1, file) != 1 ||
if (!File.Read(&utf_bom, sizeof(utf_bom)) ||
utf_bom[0] != 0xEF ||
utf_bom[1] != 0xBB ||
utf_bom[2] != 0xBF)
{
fclose(file);
return false;
}
// String
while (!feof(file))
for (;;)
{
m_CurrentStrings.insert(GetNextLangString(file));
LANG_STR LangStr = GetNextLangString(File);
if (LangStr.first == 0)
{
break;
}
m_CurrentStrings.insert(LangStr);
}
fclose(file);
m_LanguageLoaded = true;
return true;
}
@ -657,8 +656,7 @@ LanguageList & CLanguage::GetLangList(void)
{
do
{
LanguageFile File; // We temporally store the values in here to add to the list
LanguageFile File;
File.Filename = (const std::string &)LanguageFiles;
File.LanguageName = GetLangString(LanguageFiles, LANGUAGE_NAME);
@ -666,8 +664,6 @@ LanguageList & CLanguage::GetLangList(void)
{
continue;
}
// Get the name of the language from inside the file
m_LanguageList.push_back(File);
} while (LanguageFiles.FindNext());
}
@ -704,38 +700,38 @@ const std::string & CLanguage::GetString(LanguageStringID StringID)
std::string CLanguage::GetLangString(const char * FileName, LanguageStringID ID)
{
FILE * file = fopen(FileName, "rb");
if (file == nullptr)
CFile file;
if (!file.Open(FileName, CFileBase::modeRead))
{
return "";
}
// Search for UTF8 file marker
uint8_t utf_bom[3];
if (fread(&utf_bom, sizeof(utf_bom), 1, file) != 1 ||
if (!file.Read(&utf_bom, sizeof(utf_bom)) ||
utf_bom[0] != 0xEF ||
utf_bom[1] != 0xBB ||
utf_bom[2] != 0xBF)
{
fclose(file);
return "";
}
// String
while (!feof(file))
for (;;)
{
LANG_STR String = GetNextLangString(file);
if (String.first == ID)
{
fclose(file);
return String.second;
}
if (String.first == 0)
{
break;
}
}
fclose(file);
return "";
}
LANG_STR CLanguage::GetNextLangString(void * OpenFile)
LANG_STR CLanguage::GetNextLangString(CFile & File)
{
enum
{
@ -744,56 +740,47 @@ LANG_STR CLanguage::GetNextLangString(void * OpenFile)
int32_t StringID;
char szString[MAX_STRING_LEN]; // Temporarily store the string from the file
FILE * file = (FILE *)OpenFile;
//while(token!='#' && !feof(file)) { fread(&token, 1, 1, file); }
if (feof(file))
{
return LANG_STR(0, "");
}
// Search for token number
char token = 0;
while (token != '#' && !feof(file))
while (token != '#')
{
fread(&token, 1, 1, file);
if (!File.Read(&token, 1))
{
return LANG_STR(0, "");
}
}
if (feof(file))
if (!File.ReadInterger(StringID))
{
return LANG_STR(0, "");
}
// Get StringID after token
fscanf(file, "%d", &StringID);
// Search for token number
while (token != '#' && !feof(file))
token = 0;
while (token != '#')
{
fread(&token, 1, 1, file);
}
if (feof(file))
{
StringID = EMPTY_STRING;
return LANG_STR(0, "");
if (!File.Read(&token, 1))
{
return LANG_STR(0, "");
}
}
// Search for start of string '"'
while (token != '"' && !feof(file))
while (token != '"')
{
fread(&token, 1, 1, file);
}
if (feof(file))
{
StringID = EMPTY_STRING;
return LANG_STR(0, "");
if (!File.Read(&token, 1))
{
return LANG_STR(0, "");
}
}
int32_t pos = 0;
fread(&token, 1, 1, file);
while (token != '"' && !feof(file))
if (!File.Read(&token, 1))
{
return LANG_STR(0, "");
}
while (token != '"')
{
szString[pos++] = token;
fread(&token, 1, 1, file);
if (!File.Read(&token, 1))
{
return LANG_STR(0, "");
}
if (pos == MAX_STRING_LEN - 2)
{
token = '"';

View File

@ -6,6 +6,8 @@
#include <stdint.h>
#include <string>
class CFile;
typedef std::map<int32_t, std::string, std::less<int32_t>> LANG_STRINGS;
typedef LANG_STRINGS::value_type LANG_STR;
@ -51,7 +53,7 @@ private:
LanguageList m_LanguageList;
std::string GetLangString(const char * FileName, LanguageStringID ID);
LANG_STR GetNextLangString(void * OpenFile);
LANG_STR GetNextLangString(CFile & File);
void LoadDefaultStrings(void);
bool m_LanguageLoaded;

View File

@ -222,41 +222,40 @@ void CMainMenu::OnScreenShot(void)
void CMainMenu::OnSaveAs(HWND hWnd)
{
char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
char Directory[255], SaveFile[255];
OPENFILENAMEA openfilename;
char Directory[255];
wchar_t SaveFileString[255];
OPENFILENAME openfilename;
memset(&SaveFile, 0, sizeof(SaveFile));
memset(&SaveFileString, 0, sizeof(SaveFileString));
memset(&openfilename, 0, sizeof(openfilename));
UISettingsLoadStringVal(Directory_LastSave, Directory, sizeof(Directory));
std::wstring InitialDirectory = stdstr((const char *)(CPath(Directory,"").NormalizePath(CPath(CPath::MODULE_DIRECTORY)))).ToUTF16();
openfilename.lStructSize = sizeof(openfilename);
openfilename.hwndOwner = (HWND)hWnd;
openfilename.lpstrFilter = "Project64 saves (*.zip, *.pj)\0*.pj?;*.pj;*.zip;";
openfilename.lpstrFile = SaveFile;
openfilename.lpstrInitialDir = Directory;
openfilename.lpstrFilter = L"Project64 saves (*.zip, *.pj)\0*.pj?;*.pj;*.zip;";
openfilename.lpstrFile = SaveFileString;
openfilename.lpstrInitialDir = InitialDirectory.c_str();
openfilename.nMaxFile = MAX_PATH;
openfilename.Flags = OFN_HIDEREADONLY;
g_BaseSystem->ExternalEvent(SysEvent_PauseCPU_SaveGame);
if (GetSaveFileNameA(&openfilename))
if (GetSaveFileName(&openfilename))
{
_splitpath(SaveFile, drive, dir, fname, ext);
if (_stricmp(ext, ".pj") == 0 || _stricmp(ext, ".zip") == 0)
CPath SaveFile(stdstr().FromUTF16(SaveFileString));
std::string ext = SaveFile.GetExtension();
if (_stricmp(ext.c_str(), "pj") == 0 || _stricmp(ext.c_str(), "zip") == 0)
{
_makepath(SaveFile, drive, dir, fname, nullptr);
_splitpath(SaveFile, drive, dir, fname, ext);
if (_stricmp(ext, ".pj") == 0)
SaveFile.SetExtension("");
ext = SaveFile.GetExtension();
if (_stricmp(ext.c_str(), "pj") == 0)
{
_makepath(SaveFile, drive, dir, fname, nullptr);
SaveFile.SetExtension("");
}
}
g_Settings->SaveString(GameRunning_InstantSaveFile, SaveFile);
char SaveDir[MAX_PATH];
_makepath(SaveDir, drive, dir, nullptr, nullptr);
UISettingsSaveString(Directory_LastSave, SaveDir);
g_Settings->SaveString(GameRunning_InstantSaveFile, (const char *)SaveFile);
UISettingsSaveString(Directory_LastSave, SaveFile.GetDriveDirectory());
g_BaseSystem->ExternalEvent(SysEvent_SaveMachineState);
}
g_BaseSystem->ExternalEvent(SysEvent_ResumeCPU_SaveGame);

View File

@ -289,21 +289,15 @@ void CRomBrowser::RomAddedToList(int32_t ListPos)
void CRomBrowser::RomListReset(void)
{
WriteTrace(TraceUserInterface, TraceDebug, "1");
ListView_DeleteAllItems(m_hRomList);
WriteTrace(TraceUserInterface, TraceDebug, "2");
InvalidateRect(m_hRomList, nullptr, TRUE);
Sleep(100);
WriteTrace(TraceUserInterface, TraceDebug, "3");
m_LastRom = UISettingsLoadStringIndex(File_RecentGameFileIndex, 0);
if (m_WatchRomDir != g_Settings->LoadStringVal(RomList_GameDir))
if (m_WatchRomDir != stdstr(g_Settings->LoadStringVal(RomList_GameDir)).ToUTF16())
{
WriteTrace(TraceUserInterface, TraceDebug, "4");
WatchThreadStop();
WriteTrace(TraceUserInterface, TraceDebug, "5");
WatchThreadStart();
WriteTrace(TraceUserInterface, TraceDebug, "6");
}
}
@ -1301,14 +1295,14 @@ void CRomBrowser::WatchRomDirChanged(CRomBrowser * _this)
{
try
{
_this->m_WatchRomDir = g_Settings->LoadStringVal(RomList_GameDir);
_this->m_WatchRomDir = stdstr(g_Settings->LoadStringVal(RomList_GameDir)).ToUTF16();
if (_this->RomDirNeedsRefresh())
{
_this->RomDirChanged();
}
HANDLE hChange[] = {
_this->m_WatchStopEvent,
FindFirstChangeNotificationA(_this->m_WatchRomDir.c_str(), g_Settings->LoadBool(RomList_GameDirRecursive), FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE),
FindFirstChangeNotification(_this->m_WatchRomDir.c_str(), g_Settings->LoadBool(RomList_GameDirRecursive), FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE),
};
for (;;)
{

View File

@ -198,5 +198,5 @@ private:
static std::string m_UnknownGoodName;
HBRUSH_MAP m_Brushes;
std::string m_LastRom;
stdstr m_WatchRomDir;
std::wstring m_WatchRomDir;
};