From ea051c6d5fcc2eddbf749664340f283c88d058e3 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Fri, 20 May 2022 00:46:33 +1000 Subject: [PATCH] Everything: Get rid of wx entirely from the Qt build --- PCSX2_qt.sln | 50 -- cmake/ApiValidation.cmake | 52 +- cmake/SearchForStuff.cmake | 128 ++-- common/CMakeLists.txt | 2 - common/FileSystem.cpp | 432 ++++++++++++- common/FileSystem.h | 46 +- common/Path.h | 276 ++------- common/RedtapeWindows.h | 1 + common/StringUtil.cpp | 60 +- common/StringUtil.h | 72 ++- common/common.vcxproj | 6 +- common/common.vcxproj.filters | 3 - common/emitter/LnxCpuDetect.cpp | 11 +- common/vsprops/BaseProperties.props | 2 +- pcsx2-qt/EmuThread.cpp | 2 +- pcsx2-qt/GameList/GameListModel.cpp | 11 +- pcsx2-qt/MainWindow.cpp | 2 +- pcsx2-qt/QtHost.cpp | 44 +- pcsx2-qt/QtUtils.cpp | 11 - pcsx2-qt/QtUtils.h | 7 - pcsx2-qt/Settings/BIOSSettingsWidget.cpp | 2 +- pcsx2-qt/Settings/CreateMemoryCardDialog.cpp | 3 +- pcsx2-qt/Settings/DEV9SettingsWidget.cpp | 16 +- pcsx2-qt/Settings/SettingsDialog.cpp | 5 +- pcsx2-qt/pcsx2-qt.vcxproj | 16 - pcsx2-qt/pcsx2-qt.vcxproj.filters | 21 - pcsx2/CDVD/CDVD.cpp | 40 +- pcsx2/CDVD/CDVDaccess.cpp | 22 +- pcsx2/CDVD/ChdFileReader.cpp | 5 +- pcsx2/CDVD/GzippedFileReader.cpp | 40 +- pcsx2/CDVD/IsoFS/IsoFS.cpp | 3 +- pcsx2/CMakeLists.txt | 16 +- pcsx2/Config.h | 38 +- pcsx2/DEV9/ATA/ATA.h | 4 +- pcsx2/DEV9/ATA/ATA_State.cpp | 6 +- pcsx2/DEV9/ATA/HddCreate.cpp | 14 +- pcsx2/DEV9/ATA/HddCreate.h | 6 +- pcsx2/DEV9/ConfigUI.cpp | 2 +- pcsx2/DEV9/DEV9.cpp | 15 +- pcsx2/DEV9/DEV9Config.cpp | 5 +- pcsx2/DebugTools/Debug.h | 2 +- pcsx2/Dmac.h | 24 +- pcsx2/Dump.cpp | 11 +- pcsx2/Frontend/D3D11HostDisplay.cpp | 1 + pcsx2/Frontend/GameList.cpp | 17 +- pcsx2/GS/GS.cpp | 19 +- pcsx2/GS/GSCapture.cpp | 5 +- pcsx2/GS/GSCrc.cpp | 3 +- pcsx2/GS/GSExtra.h | 31 - pcsx2/GS/GSPng.cpp | 3 +- pcsx2/GS/GSState.cpp | 4 +- pcsx2/GS/GSUtil.cpp | 5 +- pcsx2/GS/Renderers/Common/GSRenderer.cpp | 16 +- pcsx2/GS/Renderers/DX11/GSDevice11.cpp | 3 +- pcsx2/GS/Renderers/DX12/GSDevice12.cpp | 3 +- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 21 +- .../HW/GSTextureReplacementLoaders.cpp | 3 +- .../GS/Renderers/HW/GSTextureReplacements.cpp | 18 +- pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp | 116 ++-- pcsx2/GS/Renderers/SW/GSRendererSW.cpp | 31 +- pcsx2/GS/Window/GSCaptureDlg.cpp | 9 +- pcsx2/GS/Window/GSDialog.h | 1 + pcsx2/IPU/IPU.cpp | 2 +- pcsx2/IopBios.cpp | 8 + pcsx2/MTGS.cpp | 1 - pcsx2/Memory.cpp | 1 - pcsx2/MemoryCardFile.cpp | 349 +++++------ pcsx2/MemoryCardFile.h | 4 +- pcsx2/MemoryCardFolder.cpp | 574 +++++++++--------- pcsx2/MemoryCardFolder.h | 127 ++-- pcsx2/MultipartFileReader.cpp | 44 +- pcsx2/PAD/Linux/Config.cpp | 7 +- pcsx2/PAD/Windows/Diagnostics.cpp | 2 + pcsx2/PAD/Windows/Global.h | 1 + pcsx2/PAD/Windows/PADConfig.cpp | 6 +- pcsx2/PAD/Windows/WndProcEater.h | 4 +- pcsx2/Patch.cpp | 14 +- pcsx2/Patch.h | 3 +- pcsx2/Pcsx2Config.cpp | 139 +++-- pcsx2/R5900.cpp | 4 +- pcsx2/SPU2/Host/CfgHelpers.cpp | 75 --- pcsx2/SPU2/Host/Config.cpp | 2 +- pcsx2/SPU2/Host/Config.h | 1 - pcsx2/SPU2/Host/ConfigDebug.cpp | 6 +- pcsx2/SPU2/Host/Dialogs.cpp | 49 +- pcsx2/SPU2/Host/Dialogs.h | 12 - pcsx2/SPU2/Linux/CfgHelpers.cpp | 6 +- pcsx2/SPU2/Linux/Config.cpp | 5 +- pcsx2/SPU2/Linux/ConfigDebug.cpp | 23 +- pcsx2/SPU2/SndOut.cpp | 12 +- pcsx2/SPU2/SndOut.h | 6 +- pcsx2/SPU2/SndOut_Cubeb.cpp | 24 +- pcsx2/SPU2/Timestretcher.cpp | 12 +- pcsx2/SPU2/Windows/CfgHelpers.cpp | 4 +- pcsx2/SPU2/Windows/Config.cpp | 7 +- pcsx2/SPU2/Windows/ConfigDebug.cpp | 8 +- pcsx2/SPU2/Windows/SndOut_XAudio2.cpp | 8 +- pcsx2/SaveState.cpp | 3 +- pcsx2/SaveState.h | 2 + pcsx2/Sio.cpp | 9 +- pcsx2/Sio.h | 6 +- pcsx2/SourceLog.cpp | 2 +- pcsx2/System.h | 6 +- pcsx2/USB/configuration.cpp | 9 +- pcsx2/Utilities/folderdesc.txt | 7 - pcsx2/VMManager.cpp | 9 +- pcsx2/gui/App.h | 1 - pcsx2/gui/AppAssert.cpp | 9 +- pcsx2/gui/AppConfig.cpp | 106 +++- pcsx2/gui/AppConfig.h | 2 + pcsx2/gui/AppCoreThread.cpp | 4 +- pcsx2/gui/AppHost.cpp | 4 +- pcsx2/gui/AppInit.cpp | 3 +- pcsx2/gui/AppMain.cpp | 10 +- pcsx2/gui/Debugger/DisassemblyDialog.cpp | 4 +- pcsx2/gui/Dialogs/ConvertMemoryCardDialog.cpp | 6 +- pcsx2/gui/Dialogs/GSDumpDialog.cpp | 2 +- pcsx2/gui/Dialogs/PINEDialog.cpp | 2 +- pcsx2/{Utilities => gui}/FileUtils.cpp | 1 + pcsx2/gui/IniInterface.h | 1 + pcsx2/{ => gui}/PathDefs.h | 2 +- {common => pcsx2/gui}/PathUtils.cpp | 33 +- pcsx2/gui/StringHelpers.h | 17 + pcsx2/gui/wxAppWithHelpers.cpp | 2 +- pcsx2/gui/wxDirName.h | 239 ++++++++ pcsx2/gui/wxSettingsInterface.cpp | 1 + pcsx2/pcsx2.vcxproj | 4 +- pcsx2/pcsx2.vcxproj.filters | 12 +- pcsx2/pcsx2core.vcxproj | 12 - pcsx2/pcsx2core.vcxproj.filters | 11 - pcsx2/ps2/BiosTools.cpp | 10 +- pcsx2/x86/iR3000A.cpp | 5 +- pcsx2/x86/microVU_Log.inl | 3 +- tests/ctest/CMakeLists.txt | 1 + tests/ctest/common/CMakeLists.txt | 1 + tests/ctest/common/path_tests.cpp | 207 +++++++ updater/Updater.cpp | 2 +- 137 files changed, 2249 insertions(+), 1914 deletions(-) delete mode 100644 pcsx2/SPU2/Host/CfgHelpers.cpp delete mode 100644 pcsx2/Utilities/folderdesc.txt rename pcsx2/{Utilities => gui}/FileUtils.cpp (99%) rename pcsx2/{ => gui}/PathDefs.h (99%) rename {common => pcsx2/gui}/PathUtils.cpp (82%) create mode 100644 pcsx2/gui/wxDirName.h create mode 100644 tests/ctest/common/CMakeLists.txt create mode 100644 tests/ctest/common/path_tests.cpp diff --git a/PCSX2_qt.sln b/PCSX2_qt.sln index bdeb0d63a6..550be41b0a 100644 --- a/PCSX2_qt.sln +++ b/PCSX2_qt.sln @@ -4,11 +4,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 17.0.31606.5 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rdparty", "3rdparty", "{78EBE642-7A4D-4EA7-86BE-5639C6646C38}" - ProjectSection(SolutionItems) = preProject - 3rdparty\svn_readme.txt = 3rdparty\svn_readme.txt - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{2D6F0A62-A247-4CCF-947F-FCD54BE16103}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcsx2-qt", "pcsx2-qt\pcsx2-qt.vcxproj", "{2A016F21-87AE-4154-8271-1F57E91408E9}" EndProject @@ -16,14 +11,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "3rdparty\soun EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "3rdparty\zlib\zlib.vcxproj", "{2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bin2cpp", "tools\bin2cpp\bin2c.vcxproj", "{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "3rdparty\libjpeg\libjpeg.vcxproj", "{BC236261-77E8-4567-8D09-45CD02965EB6}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wx30_config", "3rdparty\wxwidgets3.0\build\msw\wx30_config.vcxproj", "{01F4CE10-2CFB-41A8-B41F-E54337868A1D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wx30_base", "3rdparty\wxwidgets3.0\build\msw\wx30_base.vcxproj", "{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "3rdparty\libpng\projects\vstudio\libpng\libpng.vcxproj", "{D6973076-9317-4EF2-A0B8-B7A18AC0713E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "baseclasses", "3rdparty\baseclasses\baseclasses.vcxproj", "{27F17499-A372-4408-8AFA-4F9F4584FBD3}" @@ -112,18 +101,6 @@ Global {2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release AVX2|x64.Build.0 = Release|x64 {2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release|x64.ActiveCfg = Release|x64 {2F6C0388-20CB-4242-9F6C-A6EBB6A83F47}.Release|x64.Build.0 = Release|x64 - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug AVX2|x64.ActiveCfg = Debug|x64 - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug AVX2|x64.Build.0 = Debug|x64 - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug|x64.ActiveCfg = Debug|x64 - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Debug|x64.Build.0 = Debug|x64 - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel AVX2|x64.ActiveCfg = Devel|x64 - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel AVX2|x64.Build.0 = Devel|x64 - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel|x64.ActiveCfg = Devel|x64 - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Devel|x64.Build.0 = Devel|x64 - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release AVX2|x64.ActiveCfg = Release|x64 - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release AVX2|x64.Build.0 = Release|x64 - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release|x64.ActiveCfg = Release|x64 - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213}.Release|x64.Build.0 = Release|x64 {BC236261-77E8-4567-8D09-45CD02965EB6}.Debug AVX2|x64.ActiveCfg = Debug|x64 {BC236261-77E8-4567-8D09-45CD02965EB6}.Debug AVX2|x64.Build.0 = Debug|x64 {BC236261-77E8-4567-8D09-45CD02965EB6}.Debug|x64.ActiveCfg = Debug|x64 @@ -136,30 +113,6 @@ Global {BC236261-77E8-4567-8D09-45CD02965EB6}.Release AVX2|x64.Build.0 = Release|x64 {BC236261-77E8-4567-8D09-45CD02965EB6}.Release|x64.ActiveCfg = Release|x64 {BC236261-77E8-4567-8D09-45CD02965EB6}.Release|x64.Build.0 = Release|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug AVX2|x64.ActiveCfg = Debug|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug AVX2|x64.Build.0 = Debug|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.ActiveCfg = Debug|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.Build.0 = Debug|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel AVX2|x64.ActiveCfg = Devel|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel AVX2|x64.Build.0 = Devel|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel|x64.ActiveCfg = Devel|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Devel|x64.Build.0 = Devel|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release AVX2|x64.ActiveCfg = Release|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release AVX2|x64.Build.0 = Release|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|x64.ActiveCfg = Release|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|x64.Build.0 = Release|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug AVX2|x64.ActiveCfg = Debug|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug AVX2|x64.Build.0 = Debug|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.ActiveCfg = Debug|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.Build.0 = Debug|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel AVX2|x64.ActiveCfg = Devel|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel AVX2|x64.Build.0 = Devel|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel|x64.ActiveCfg = Devel|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Devel|x64.Build.0 = Devel|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release AVX2|x64.ActiveCfg = Release|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release AVX2|x64.Build.0 = Release|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|x64.ActiveCfg = Release|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|x64.Build.0 = Release|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug AVX2|x64.ActiveCfg = Debug|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug AVX2|x64.Build.0 = Debug|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug|x64 @@ -419,10 +372,7 @@ Global GlobalSection(NestedProjects) = preSolution {E9B51944-7E6D-4BCD-83F2-7BBD5A46182D} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} {2F6C0388-20CB-4242-9F6C-A6EBB6A83F47} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} - {677B7D11-D5E1-40B3-88B1-9A4DF83D2213} = {2D6F0A62-A247-4CCF-947F-FCD54BE16103} {BC236261-77E8-4567-8D09-45CD02965EB6} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} - {01F4CE10-2CFB-41A8-B41F-E54337868A1D} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} {D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} {27F17499-A372-4408-8AFA-4F9F4584FBD3} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} {12728250-16EC-4DC6-94D7-E21DD88947F8} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} diff --git a/cmake/ApiValidation.cmake b/cmake/ApiValidation.cmake index 10051fcf2a..deb103d999 100644 --- a/cmake/ApiValidation.cmake +++ b/cmake/ApiValidation.cmake @@ -84,35 +84,37 @@ int main() } ") -function(WX_vs_SDL) - file(WRITE "${CMAKE_BINARY_DIR}/wx_sdl.c" "${wx_sdl_c_code}") - enable_language(C) +if (NOT PCSX2_CORE) + function(WX_vs_SDL) + file(WRITE "${CMAKE_BINARY_DIR}/wx_sdl.c" "${wx_sdl_c_code}") + enable_language(C) - try_compile( - wx_linked_to_sdl - "${CMAKE_BINARY_DIR}" - "${CMAKE_BINARY_DIR}/wx_sdl.c" - CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${wxWidgets_INCLUDE_DIRS}" - LINK_LIBRARIES "${wxWidgets_LIBRARIES}" - COPY_FILE "${CMAKE_BINARY_DIR}/wx_sdl" - ) + try_compile( + wx_linked_to_sdl + "${CMAKE_BINARY_DIR}" + "${CMAKE_BINARY_DIR}/wx_sdl.c" + CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${wxWidgets_INCLUDE_DIRS}" + LINK_LIBRARIES "${wxWidgets_LIBRARIES}" + COPY_FILE "${CMAKE_BINARY_DIR}/wx_sdl" + ) - if (NOT wx_linked_to_sdl) - return() - endif() + if (NOT wx_linked_to_sdl) + return() + endif() - execute_process( - COMMAND ldd "${CMAKE_BINARY_DIR}/wx_sdl" - COMMAND grep -c SDL2 - OUTPUT_VARIABLE sdl2_count - ) + execute_process( + COMMAND ldd "${CMAKE_BINARY_DIR}/wx_sdl" + COMMAND grep -c SDL2 + OUTPUT_VARIABLE sdl2_count + ) - if (SDL2_API AND sdl2_count STREQUAL "0") - message(FATAL_ERROR "wxWidgets is linked to SDL1.2. Please use -DSDL2_API=FALSE.") - elseif (NOT SDL2_API AND NOT sdl2_count STREQUAL "0") - message(FATAL_ERROR "wxWidgets is linked to SDL2. Please use -DSDL2_API=TRUE") - endif() -endfunction() + if (SDL2_API AND sdl2_count STREQUAL "0") + message(FATAL_ERROR "wxWidgets is linked to SDL1.2. Please use -DSDL2_API=FALSE.") + elseif (NOT SDL2_API AND NOT sdl2_count STREQUAL "0") + message(FATAL_ERROR "wxWidgets is linked to SDL2. Please use -DSDL2_API=TRUE") + endif() + endfunction() +endif() function(GCC7_BUG) # try_run doesn't work when cross-compiling is enabled. It is completely silly in our case diff --git a/cmake/SearchForStuff.cmake b/cmake/SearchForStuff.cmake index 12a9f3c8ef..0ee7485d95 100644 --- a/cmake/SearchForStuff.cmake +++ b/cmake/SearchForStuff.cmake @@ -14,7 +14,9 @@ if (WIN32) add_subdirectory(3rdparty/pthreads4w EXCLUDE_FROM_ALL) add_subdirectory(3rdparty/soundtouch EXCLUDE_FROM_ALL) add_subdirectory(3rdparty/wil EXCLUDE_FROM_ALL) - add_subdirectory(3rdparty/wxwidgets3.0 EXCLUDE_FROM_ALL) + if (NOT PCSX2_CORE) + add_subdirectory(3rdparty/wxwidgets3.0 EXCLUDE_FROM_ALL) + endif() add_subdirectory(3rdparty/xz EXCLUDE_FROM_ALL) add_subdirectory(3rdparty/D3D12MemAlloc EXCLUDE_FROM_ALL) else() @@ -37,74 +39,76 @@ else() find_package(PNG REQUIRED) find_package(Vtune) - # Does not require the module (allow to compile non-wx plugins) - # Force the unicode build (the variable is only supported on cmake 2.8.3 and above) - # Warning do not put any double-quote for the argument... - # set(wxWidgets_CONFIG_OPTIONS --unicode=yes --debug=yes) # In case someone want to debug inside wx - # - # Fedora uses an extra non-standard option ... Arch must be the first option. - # They do uname -m if missing so only fix for cross compilations. - # http://pkgs.fedoraproject.org/cgit/wxGTK.git/plain/wx-config - if(Fedora AND CMAKE_CROSSCOMPILING) - set(wxWidgets_CONFIG_OPTIONS --arch ${PCSX2_TARGET_ARCHITECTURES} --unicode=yes) - else() - set(wxWidgets_CONFIG_OPTIONS --unicode=yes) - endif() + if(NOT PCSX2_CORE) + # Does not require the module (allow to compile non-wx plugins) + # Force the unicode build (the variable is only supported on cmake 2.8.3 and above) + # Warning do not put any double-quote for the argument... + # set(wxWidgets_CONFIG_OPTIONS --unicode=yes --debug=yes) # In case someone want to debug inside wx + # + # Fedora uses an extra non-standard option ... Arch must be the first option. + # They do uname -m if missing so only fix for cross compilations. + # http://pkgs.fedoraproject.org/cgit/wxGTK.git/plain/wx-config + if(Fedora AND CMAKE_CROSSCOMPILING) + set(wxWidgets_CONFIG_OPTIONS --arch ${PCSX2_TARGET_ARCHITECTURES} --unicode=yes) + else() + set(wxWidgets_CONFIG_OPTIONS --unicode=yes) + endif() - # I'm removing the version check, because it excludes newer versions and requires specifically 3.0. - #list(APPEND wxWidgets_CONFIG_OPTIONS --version=3.0) + # I'm removing the version check, because it excludes newer versions and requires specifically 3.0. + #list(APPEND wxWidgets_CONFIG_OPTIONS --version=3.0) - # The wx version must be specified so a mix of gtk2 and gtk3 isn't used - # as that can cause compile errors. - if(GTK2_API AND NOT APPLE) - list(APPEND wxWidgets_CONFIG_OPTIONS --toolkit=gtk2) - elseif(NOT APPLE) - list(APPEND wxWidgets_CONFIG_OPTIONS --toolkit=gtk3) - endif() + # The wx version must be specified so a mix of gtk2 and gtk3 isn't used + # as that can cause compile errors. + if(GTK2_API AND NOT APPLE) + list(APPEND wxWidgets_CONFIG_OPTIONS --toolkit=gtk2) + elseif(NOT APPLE) + list(APPEND wxWidgets_CONFIG_OPTIONS --toolkit=gtk3) + endif() - # wx2.8 => /usr/bin/wx-config-2.8 - # lib32-wx2.8 => /usr/bin/wx-config32-2.8 - # wx3.0 => /usr/bin/wx-config-3.0 - # I'm going to take a wild guess and predict this: - # lib32-wx3.0 => /usr/bin/wx-config32-3.0 - # FindwxWidgets only searches for wx-config. - if(CMAKE_CROSSCOMPILING) - # May need to fix the filenames for lib32-wx3.0. - if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "i386") - if (Fedora AND EXISTS "/usr/bin/wx-config-3.0") + # wx2.8 => /usr/bin/wx-config-2.8 + # lib32-wx2.8 => /usr/bin/wx-config32-2.8 + # wx3.0 => /usr/bin/wx-config-3.0 + # I'm going to take a wild guess and predict this: + # lib32-wx3.0 => /usr/bin/wx-config32-3.0 + # FindwxWidgets only searches for wx-config. + if(CMAKE_CROSSCOMPILING) + # May need to fix the filenames for lib32-wx3.0. + if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "i386") + if (Fedora AND EXISTS "/usr/bin/wx-config-3.0") + set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config-3.0") + endif() + if (EXISTS "/usr/bin/wx-config32") + set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config32") + endif() + if (EXISTS "/usr/bin/wx-config32-3.0") + set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config32-3.0") + endif() + endif() + else() + if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + set(wxWidgets_CONFIG_EXECUTABLE "/usr/local/bin/wxgtk3u-3.0-config") + endif() + if(EXISTS "/usr/bin/wx-config-3.2") + set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config-3.2") + endif() + if(EXISTS "/usr/bin/wx-config-3.1") + set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config-3.1") + endif() + if(EXISTS "/usr/bin/wx-config-3.0") set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config-3.0") endif() - if (EXISTS "/usr/bin/wx-config32") - set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config32") + if(EXISTS "/usr/bin/wx-config") + set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config") endif() - if (EXISTS "/usr/bin/wx-config32-3.0") - set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config32-3.0") + if(NOT GTK2_API AND EXISTS "/usr/bin/wx-config-gtk3") + set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config-gtk3") endif() endif() - else() - if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") - set(wxWidgets_CONFIG_EXECUTABLE "/usr/local/bin/wxgtk3u-3.0-config") - endif() - if(EXISTS "/usr/bin/wx-config-3.2") - set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config-3.2") - endif() - if(EXISTS "/usr/bin/wx-config-3.1") - set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config-3.1") - endif() - if(EXISTS "/usr/bin/wx-config-3.0") - set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config-3.0") - endif() - if(EXISTS "/usr/bin/wx-config") - set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config") - endif() - if(NOT GTK2_API AND EXISTS "/usr/bin/wx-config-gtk3") - set(wxWidgets_CONFIG_EXECUTABLE "/usr/bin/wx-config-gtk3") - endif() - endif() - find_package(wxWidgets REQUIRED base core adv) - include(${wxWidgets_USE_FILE}) - make_imported_target_if_missing(wxWidgets::all wxWidgets) + find_package(wxWidgets REQUIRED base core adv) + include(${wxWidgets_USE_FILE}) + make_imported_target_if_missing(wxWidgets::all wxWidgets) + endif() find_package(ZLIB REQUIRED) @@ -189,7 +193,9 @@ endif() #---------------------------------------- include(ApiValidation) -WX_vs_SDL() +if(NOT PCSX2_CORE) + WX_vs_SDL() +endif() # Blacklist bad GCC if(GCC_VERSION VERSION_EQUAL "7.0" OR GCC_VERSION VERSION_EQUAL "7.1") diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index ad82a8ff20..22bd3f08c5 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -21,7 +21,6 @@ target_sources(common PRIVATE FileSystem.cpp Misc.cpp MD5Digest.cpp - PathUtils.cpp PrecompiledHeader.cpp Perf.cpp ProgressCallback.cpp @@ -261,7 +260,6 @@ target_link_libraries(common PRIVATE ) target_link_libraries(common PUBLIC - wxWidgets::all fmt::fmt ) diff --git a/common/FileSystem.cpp b/common/FileSystem.cpp index 201e234b81..1248823a09 100644 --- a/common/FileSystem.cpp +++ b/common/FileSystem.cpp @@ -14,6 +14,7 @@ */ #include "FileSystem.h" +#include "Path.h" #include "Assertions.h" #include "Console.h" #include "StringUtil.h" @@ -21,6 +22,7 @@ #include #include #include +#include #ifdef __APPLE__ #include @@ -33,12 +35,10 @@ #endif #if defined(_WIN32) +#include "RedtapeWindows.h" +#include #include -// We can't guarantee that windows.h isn't included before here, so we have to undef. -#undef min -#undef max - #if defined(_UWP) #include #include @@ -87,7 +87,50 @@ static inline bool FileSystemCharacterIsSane(char c, bool StripSlashes) return true; } -void FileSystem::SanitizeFileName(char* Destination, u32 cbDestination, const char* FileName, bool StripSlashes /* = true */) +template +static inline void PathAppendString(std::string& dst, const T& src) +{ + if (dst.capacity() < (dst.length() + src.length())) + dst.reserve(dst.length() + src.length()); + + bool last_separator = (!dst.empty() && dst.back() == FS_OSPATH_SEPARATOR_CHARACTER); + + size_t index = 0; + +#ifdef _WIN32 + // special case for UNC paths here + if (dst.empty() && src.length() >= 3 && src[0] == '\\' && src[1] == '\\' && src[2] != '\\') + { + dst.append("\\\\"); + index = 2; + } +#endif + + for (; index < src.length(); index++) + { + const char ch = src[index]; + +#ifdef _WIN32 + // convert forward slashes to backslashes + if (ch == '\\' || ch == '/') +#else + if (ch == '/') +#endif + { + if (last_separator) + continue; + last_separator = true; + dst.push_back(FS_OSPATH_SEPARATOR_CHARACTER); + } + else + { + last_separator = false; + dst.push_back(ch); + } + } +} + +void Path::SanitizeFileName(char* Destination, u32 cbDestination, const char* FileName, bool StripSlashes /* = true */) { u32 i; u32 fileNameLength = static_cast(std::strlen(FileName)); @@ -112,7 +155,7 @@ void FileSystem::SanitizeFileName(char* Destination, u32 cbDestination, const ch } } -void FileSystem::SanitizeFileName(std::string& Destination, bool StripSlashes /* = true*/) +void Path::SanitizeFileName(std::string& Destination, bool StripSlashes /* = true*/) { const std::size_t len = Destination.length(); for (std::size_t i = 0; i < len; i++) @@ -122,26 +165,129 @@ void FileSystem::SanitizeFileName(std::string& Destination, bool StripSlashes /* } } -bool FileSystem::IsAbsolutePath(const std::string_view& path) +bool Path::IsAbsolute(const std::string_view& path) { #ifdef _WIN32 return (path.length() >= 3 && ((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z')) && - path[1] == ':' && (path[2] == '/' || path[2] == '\\')); + path[1] == ':' && (path[2] == '/' || path[2] == '\\')) || (path.length() >= 3 && path[0] == '\\' && path[1] == '\\'); #else return (path.length() >= 1 && path[0] == '/'); #endif } -std::string_view FileSystem::GetExtension(const std::string_view& path) +std::string Path::ToNativePath(const std::string_view& path) +{ + std::string ret; + PathAppendString(ret, path); + + // remove trailing slashes + if (ret.length() > 1) + { + while (ret.back() == FS_OSPATH_SEPARATOR_CHARACTER) + ret.pop_back(); + } + + return ret; +} + +void Path::ToNativePath(std::string* path) +{ + *path = Path::ToNativePath(*path); +} + +std::string Path::Canonicalize(const std::string_view& path) +{ + std::vector components = Path::SplitNativePath(path); + std::vector new_components; + new_components.reserve(components.size()); + for (const std::string_view& component : components) + { + if (component == ".") + { + // current directory, so it can be skipped, unless it's the only component + if (components.size() == 1) + new_components.push_back(std::move(component)); + } + else if (component == "..") + { + // parent directory, pop one off if we're not at the beginning, otherwise preserve. + if (!new_components.empty()) + new_components.pop_back(); + else + new_components.push_back(std::move(component)); + } + else + { + // anything else, preserve + new_components.push_back(std::move(component)); + } + } + + return Path::JoinNativePath(new_components); +} + +void Path::Canonicalize(std::string* path) +{ + *path = Canonicalize(*path); +} + +std::string Path::MakeRelative(const std::string_view& path, const std::string_view& relative_to) +{ + // simple algorithm, we just work on the components. could probably be better, but it'll do for now. + std::vector path_components(SplitNativePath(path)); + std::vector relative_components(SplitNativePath(relative_to)); + std::vector new_components; + + // both must be absolute paths + if (Path::IsAbsolute(path) && Path::IsAbsolute(relative_to)) + { + // find the number of same components + size_t num_same = 0; + for (size_t i = 0; i < path_components.size() && i < relative_components.size(); i++) + { + if (path_components[i] == relative_components[i]) + num_same++; + else + break; + } + + // we need at least one same component + if (num_same > 0) + { + // from the relative_to directory, back up to the start of the common components + const size_t num_ups = relative_components.size() - num_same; + for (size_t i = 0; i < num_ups; i++) + new_components.emplace_back(".."); + + // and add the remainder of the path components + for (size_t i = num_same; i < path_components.size(); i++) + new_components.push_back(std::move(path_components[i])); + } + else + { + // no similarity + new_components = std::move(path_components); + } + } + else + { + // not absolute + new_components = std::move(path_components); + } + + return JoinNativePath(new_components); +} + +std::string_view Path::GetExtension(const std::string_view& path) { const std::string_view::size_type pos = path.rfind('.'); if (pos == std::string_view::npos) - return path; - - return path.substr(pos + 1); + return std::string_view(); + else + return path.substr(pos + 1); } -std::string_view FileSystem::StripExtension(const std::string_view& path) +std::string_view Path::StripExtension(const std::string_view& path) { const std::string_view::size_type pos = path.rfind('.'); if (pos == std::string_view::npos) @@ -150,7 +296,7 @@ std::string_view FileSystem::StripExtension(const std::string_view& path) return path.substr(0, pos); } -std::string FileSystem::ReplaceExtension(const std::string_view& path, const std::string_view& new_extension) +std::string Path::ReplaceExtension(const std::string_view& path, const std::string_view& new_extension) { const std::string_view::size_type pos = path.rfind('.'); if (pos == std::string_view::npos) @@ -183,10 +329,10 @@ static std::string_view::size_type GetLastSeperatorPosition(const std::string_vi std::string FileSystem::GetDisplayNameFromPath(const std::string_view& path) { - return std::string(GetFileNameFromPath(path)); + return std::string(Path::GetFileName(path)); } -std::string_view FileSystem::GetPathDirectory(const std::string_view& path) +std::string_view Path::GetDirectory(const std::string_view& path) { const std::string::size_type pos = GetLastSeperatorPosition(path, false); if (pos == std::string_view::npos) @@ -195,7 +341,7 @@ std::string_view FileSystem::GetPathDirectory(const std::string_view& path) return path.substr(0, pos); } -std::string_view FileSystem::GetFileNameFromPath(const std::string_view& path) +std::string_view Path::GetFileName(const std::string_view& path) { const std::string_view::size_type pos = GetLastSeperatorPosition(path, true); if (pos == std::string_view::npos) @@ -204,9 +350,9 @@ std::string_view FileSystem::GetFileNameFromPath(const std::string_view& path) return path.substr(pos); } -std::string_view FileSystem::GetFileTitleFromPath(const std::string_view& path) +std::string_view Path::GetFileTitle(const std::string_view& path) { - const std::string_view filename(GetFileNameFromPath(path)); + const std::string_view filename(GetFileName(path)); const std::string::size_type pos = filename.rfind('.'); if (pos == std::string_view::npos) return filename; @@ -214,7 +360,86 @@ std::string_view FileSystem::GetFileTitleFromPath(const std::string_view& path) return filename.substr(0, pos); } -std::vector FileSystem::SplitWindowsPath(const std::string_view& path) +std::string Path::ChangeFileName(const std::string_view& path, const std::string_view& new_filename) +{ + std::string ret; + PathAppendString(ret, path); + + const std::string_view::size_type pos = GetLastSeperatorPosition(ret, true); + if (pos == std::string_view::npos) + { + ret.clear(); + PathAppendString(ret, new_filename); + } + else + { + if (!new_filename.empty()) + { + ret.erase(pos); + PathAppendString(ret, new_filename); + } + else + { + ret.erase(pos - 1); + } + } + + return ret; +} + +void Path::ChangeFileName(std::string* path, const std::string_view& new_filename) +{ + *path = ChangeFileName(*path, new_filename); +} + +std::string Path::AppendDirectory(const std::string_view& path, const std::string_view& new_dir) +{ + std::string ret; + if (!new_dir.empty()) + { + const std::string_view::size_type pos = GetLastSeperatorPosition(path, true); + + ret.reserve(path.length() + new_dir.length() + 1); + if (pos != std::string_view::npos) + PathAppendString(ret, path.substr(0, pos)); + + while (!ret.empty() && ret.back() == FS_OSPATH_SEPARATOR_CHARACTER) + ret.pop_back(); + + if (!ret.empty()) + ret += FS_OSPATH_SEPARATOR_CHARACTER; + + PathAppendString(ret, new_dir); + + if (pos != std::string_view::npos) + { + const std::string_view filepart(path.substr(pos)); + if (!filepart.empty()) + { + ret += FS_OSPATH_SEPARATOR_CHARACTER; + PathAppendString(ret, filepart); + } + } + else if (!path.empty()) + { + ret += FS_OSPATH_SEPARATOR_CHARACTER; + PathAppendString(ret, path); + } + } + else + { + PathAppendString(ret, path); + } + + return ret; +} + +void Path::AppendDirectory(std::string* path, const std::string_view& new_dir) +{ + *path = AppendDirectory(*path, new_dir); +} + +std::vector Path::SplitWindowsPath(const std::string_view& path) { std::vector parts; @@ -242,9 +467,48 @@ std::vector FileSystem::SplitWindowsPath(const std::string_vie return parts; } -std::vector FileSystem::SplitNativePath(const std::string_view& path) +std::string Path::JoinWindowsPath(const std::vector& components) { - return StringUtil::SplitString(path, FS_OSPATH_SEPARATOR_CHARACTER, true); + return StringUtil::JoinString(components.begin(), components.end(), '\\'); +} + +std::vector Path::SplitNativePath(const std::string_view& path) +{ +#ifdef _WIN32 + return SplitWindowsPath(path); +#else + std::vector parts; + + std::string::size_type start = 0; + std::string::size_type pos = 0; + while (pos < path.size()) + { + if (path[pos] != '/') + { + pos++; + continue; + } + + // skip consecutive separators + // for unix, we create an empty element at the beginning when it's an absolute path + // that way, when it's re-joined later, we preserve the starting slash. + if (pos != start || pos == 0) + parts.push_back(path.substr(start, pos - start)); + + pos++; + start = pos; + } + + if (start != pos) + parts.push_back(path.substr(start)); + + return parts; +#endif +} + +std::string Path::JoinNativePath(const std::vector& components) +{ + return StringUtil::JoinString(components.begin(), components.end(), FS_OSPATH_SEPARATOR_CHARACTER); } std::vector FileSystem::GetRootDirectoryList() @@ -297,7 +561,7 @@ std::vector FileSystem::GetRootDirectoryList() return results; } -std::string FileSystem::BuildRelativePath(const std::string_view& filename, const std::string_view& new_filename) +std::string Path::BuildRelativePath(const std::string_view& filename, const std::string_view& new_filename) { std::string new_string; @@ -308,10 +572,21 @@ std::string FileSystem::BuildRelativePath(const std::string_view& filename, cons return new_string; } -std::string FileSystem::JoinPath(const std::string_view& base, const std::string_view& next) +std::string Path::Combine(const std::string_view& base, const std::string_view& next) { - // TODO: Rewrite this natively when wxDirName is dropped. - return Path::CombineStdString(base, next); + std::string ret; + ret.reserve(base.length() + next.length() + 1); + + PathAppendString(ret, base); + while (!ret.empty() && ret.back() == FS_OSPATH_SEPARATOR_CHARACTER) + ret.pop_back(); + + ret += FS_OSPATH_SEPARATOR_CHARACTER; + PathAppendString(ret, next); + while (!ret.empty() && ret.back() == FS_OSPATH_SEPARATOR_CHARACTER) + ret.pop_back(); + + return ret; } #ifdef _UWP @@ -631,6 +906,49 @@ bool FileSystem::RecursiveDeleteDirectory(const char* path) return DeleteDirectory(path); } +bool FileSystem::CopyFilePath(const char* source, const char* destination, bool replace) +{ +#ifndef _WIN32 + // TODO: There's technically a race here between checking and opening the file.. + // But fopen doesn't specify any way to say "don't create if it exists"... + if (!replace && FileExists(destination)) + return false; + + auto in_fp = OpenManagedCFile(source, "rb"); + if (!in_fp) + return false; + + auto out_fp = OpenManagedCFile(destination, "wb"); + if (!out_fp) + return false; + + u8 buf[4096]; + while (!std::feof(in_fp.get())) + { + size_t bytes_in = std::fread(buf, 1, sizeof(buf), in_fp.get()); + if ((bytes_in == 0 && !std::feof(in_fp.get())) || + (bytes_in > 0 && std::fwrite(buf, 1, bytes_in, out_fp.get()) != bytes_in)) + { + out_fp.reset(); + DeleteFilePath(destination); + return false; + } + } + + if (std::fflush(out_fp.get()) != 0) + { + out_fp.reset(); + DeleteFilePath(destination); + return false; + } + + return true; +#else + return CopyFileW(StringUtil::UTF8StringToWideString(source).c_str(), + StringUtil::UTF8StringToWideString(destination).c_str(), !replace); +#endif +} + #ifdef _WIN32 static u32 TranslateWin32Attributes(u32 Win32Attributes) @@ -783,6 +1101,7 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path, outData.FileName = utf8_filename; } + outData.CreationTime = ConvertFileTimeToUnixTime(wfd.ftCreationTime); outData.ModificationTime = ConvertFileTimeToUnixTime(wfd.ftLastWriteTime); outData.Size = (static_cast(wfd.nFileSizeHigh) << 32) | static_cast(wfd.nFileSizeLow); @@ -904,6 +1223,7 @@ bool FileSystem::StatFile(const char* path, FILESYSTEM_STAT_DATA* sd) // fill in the stat data sd->Attributes = TranslateWin32Attributes(bhfi.dwFileAttributes); + sd->CreationTime = ConvertFileTimeToUnixTime(bhfi.ftCreationTime); sd->ModificationTime = ConvertFileTimeToUnixTime(bhfi.ftLastWriteTime); sd->Size = static_cast(((u64)bhfi.nFileSizeHigh) << 32 | (u64)bhfi.nFileSizeLow); return true; @@ -913,6 +1233,7 @@ bool FileSystem::StatFile(const char* path, FILESYSTEM_STAT_DATA* sd) return false; sd->Attributes = TranslateWin32Attributes(fad.dwFileAttributes); + sd->CreationTime = ConvertFileTimeToUnixTime(fad.ftCreationTime); sd->ModificationTime = ConvertFileTimeToUnixTime(fad.ftLastWriteTime); sd->Size = static_cast(((u64)fad.nFileSizeHigh) << 32 | (u64)fad.nFileSizeLow); return true; @@ -930,6 +1251,7 @@ bool FileSystem::StatFile(std::FILE* fp, FILESYSTEM_STAT_DATA* sd) return false; // parse attributes + sd->CreationTime = st.st_ctime; sd->ModificationTime = st.st_mtime; sd->Attributes = 0; if ((st.st_mode & _S_IFMT) == _S_IFDIR) @@ -988,6 +1310,37 @@ bool FileSystem::DirectoryExists(const char* path) return false; } +bool FileSystem::DirectoryIsEmpty(const char* path) +{ + std::wstring wpath(StringUtil::UTF8StringToWideString(path)); + wpath += L"\\*"; + + WIN32_FIND_DATAW wfd; +#ifndef _UWP + HANDLE hFind = FindFirstFileW(wpath.c_str(), &wfd); +#else + HANDLE hFind = FindFirstFileExFromAppW(wpath.c_str(), FindExInfoBasic, &wfd, FindExSearchNameMatch, nullptr, 0); +#endif + + if (hFind == INVALID_HANDLE_VALUE) + return true; + + do + { + if (wfd.cFileName[0] == L'.') + { + if (wfd.cFileName[1] == L'\0' || (wfd.cFileName[1] == L'.' && wfd.cFileName[2] == L'\0')) + continue; + } + + FindClose(hFind); + return false; + } while (FindNextFileW(hFind, &wfd)); + + FindClose(hFind); + return true; +} + bool FileSystem::CreateDirectoryPath(const char* Path, bool Recursive) { const std::wstring wpath(StringUtil::UTF8StringToWideString(Path)); @@ -1317,6 +1670,7 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co } outData.Size = static_cast(sDir.st_size); + outData.CreationTime = sDir.st_ctime; outData.ModificationTime = sDir.st_mtime; // match the filename @@ -1400,6 +1754,7 @@ bool FileSystem::StatFile(const char* path, FILESYSTEM_STAT_DATA* sd) return false; // parse attributes + sd->CreationTime = sysStatData.st_ctime; sd->ModificationTime = sysStatData.st_mtime; sd->Attributes = 0; if (S_ISDIR(sysStatData.st_mode)) @@ -1432,6 +1787,7 @@ bool FileSystem::StatFile(std::FILE* fp, FILESYSTEM_STAT_DATA* sd) return false; // parse attributes + sd->CreationTime = sysStatData.st_ctime; sd->ModificationTime = sysStatData.st_mtime; sd->Attributes = 0; if (S_ISDIR(sysStatData.st_mode)) @@ -1491,6 +1847,30 @@ bool FileSystem::DirectoryExists(const char* path) return false; } +bool FileSystem::DirectoryIsEmpty(const char* path) +{ + DIR* pDir = opendir(path); + if (pDir == nullptr) + return true; + + // iterate results + struct dirent* pDirEnt; + while ((pDirEnt = readdir(pDir)) != nullptr) + { + if (pDirEnt->d_name[0] == '.') + { + if (pDirEnt->d_name[1] == '\0' || (pDirEnt->d_name[1] == '.' && pDirEnt->d_name[2] == '\0')) + continue; + } + + closedir(pDir); + return false; + } + + closedir(pDir); + return true; +} + bool FileSystem::CreateDirectoryPath(const char* path, bool recursive) { // has a path diff --git a/common/FileSystem.h b/common/FileSystem.h index 81d4cf21bb..9314e32f48 100644 --- a/common/FileSystem.h +++ b/common/FileSystem.h @@ -50,6 +50,7 @@ enum FILESYSTEM_FIND_FLAGS struct FILESYSTEM_STAT_DATA { + std::time_t CreationTime; // actually inode change time on linux std::time_t ModificationTime; s64 Size; u32 Attributes; @@ -57,6 +58,7 @@ struct FILESYSTEM_STAT_DATA struct FILESYSTEM_FIND_DATA { + std::time_t CreationTime; // actually inode change time on linux std::time_t ModificationTime; std::string FileName; s64 Size; @@ -65,49 +67,11 @@ struct FILESYSTEM_FIND_DATA namespace FileSystem { - using FindResultsArray = std::vector; - /// Builds a path relative to the specified file - std::string BuildRelativePath(const std::string_view& filename, const std::string_view& new_filename); - - /// Joins path components together, producing a new path. - std::string JoinPath(const std::string_view& base, const std::string_view& next); - - /// Sanitizes a filename for use in a filesystem. - void SanitizeFileName(char* Destination, u32 cbDestination, const char* FileName, bool StripSlashes /* = true */); - void SanitizeFileName(std::string& Destination, bool StripSlashes = true); - - /// Returns true if the specified path is an absolute path (C:\Path on Windows or /path on Unix). - bool IsAbsolutePath(const std::string_view& path); - - /// Returns a view of the extension of a filename. - std::string_view GetExtension(const std::string_view& path); - - /// Removes the extension of a filename. - std::string_view StripExtension(const std::string_view& path); - - /// Replaces the extension of a filename with another. - std::string ReplaceExtension(const std::string_view& path, const std::string_view& new_extension); - /// Returns the display name of a filename. Usually this is the same as the path. std::string GetDisplayNameFromPath(const std::string_view& path); - /// Returns the directory component of a filename. - std::string_view GetPathDirectory(const std::string_view& path); - - /// Returns the filename component of a filename. - std::string_view GetFileNameFromPath(const std::string_view& path); - - /// Returns the file title (less the extension and path) from a filename. - std::string_view GetFileTitleFromPath(const std::string_view& path); - - /// Splits a path into its components, handling both Windows and Unix separators. - std::vector SplitWindowsPath(const std::string_view& path); - - /// Splits a path into its components, only handling native separators. - std::vector SplitNativePath(const std::string_view& path); - /// Returns a list of "root directories" (i.e. root/home directories on Linux, drive letters on Windows). std::vector GetRootDirectoryList(); @@ -127,6 +91,9 @@ namespace FileSystem /// Directory exists? bool DirectoryExists(const char* path); + /// Directory does not contain any files? + bool DirectoryIsEmpty(const char* path); + /// Delete file bool DeleteFilePath(const char* path); @@ -166,6 +133,9 @@ namespace FileSystem /// Recursively removes a directory and all subdirectories/files. bool RecursiveDeleteDirectory(const char* path); + /// Copies one file to another, optionally replacing it if it already exists. + bool CopyFilePath(const char* source, const char* destination, bool replace); + /// Returns the path to the current executable. std::string GetProgramPath(); diff --git a/common/Path.h b/common/Path.h index 7958dc0b93..08ea6af293 100644 --- a/common/Path.h +++ b/common/Path.h @@ -17,226 +17,68 @@ #include "common/Pcsx2Defs.h" -#include +#include +#include +#include -#include "ghc/filesystem.h" - -namespace fs = ghc::filesystem; - -#define g_MaxPath 255 // 255 is safer with antiquated Win32 ASCII APIs. - -// -------------------------------------------------------------------------------------- -// wxDirName -// -------------------------------------------------------------------------------------- -class wxDirName : protected wxFileName -{ -public: - explicit wxDirName(const wxFileName& src) - { - Assign(src.GetPath(), wxEmptyString); - } - - wxDirName() - : wxFileName() - { - } - wxDirName(const wxDirName& src) - : wxFileName(src) - { - } - explicit wxDirName(const char* src) { Assign(wxString(src, wxMBConvUTF8())); } - explicit wxDirName(const wxString& src) { Assign(src); } - - // ------------------------------------------------------------------------ - void Assign(const wxString& volume, const wxString& path) - { - wxFileName::Assign(volume, path, wxEmptyString); - } - - void Assign(const wxString& path) - { - wxFileName::Assign(path, wxEmptyString); - } - - void Assign(const wxDirName& path) - { - wxFileName::Assign(path); - } - - void Clear() { wxFileName::Clear(); } - - wxCharBuffer ToUTF8() const { return GetPath().ToUTF8(); } - wxCharBuffer ToAscii() const { return GetPath().ToAscii(); } - wxString ToString() const { return GetPath(); } - - // ------------------------------------------------------------------------ - bool IsWritable() const { return IsDirWritable(); } - bool IsReadable() const { return IsDirReadable(); } - bool Exists() const { return DirExists(); } - bool FileExists() const { return wxFileName::FileExists(); } - bool IsOk() const { return wxFileName::IsOk(); } - bool IsRelative() const { return wxFileName::IsRelative(); } - bool IsAbsolute() const { return wxFileName::IsAbsolute(); } - - bool SameAs(const wxDirName& filepath) const - { - return wxFileName::SameAs(filepath); - } - - //Returns true if the file is somewhere inside this directory (and both file and directory are not relative). - bool IsContains(const wxFileName& file) const - { - if (this->IsRelative() || file.IsRelative()) - return false; - - wxFileName f(file); - - while (1) - { - if (this->SameAs(wxDirName(f.GetPath()))) - return true; - - if (f.GetDirCount() == 0) - return false; - - f.RemoveLastDir(); - } - - return false; - } - - bool IsContains(const wxDirName& dir) const - { - return IsContains((wxFileName)dir); - } - - - //Auto relative works as follows: - // 1. if either base or subject are relative, return subject (should never be used with relative paths). - // 2. else if subject is somewhere inside base folder, then result is subject relative to base. - // 3. (windows only, implicitly) else if subject is on the same driveletter as base, result is absolute path of subject without the driveletter. - // 4. else, result is absolute path of subject. - // - // returns ok if both this and base are absolute paths. - static wxString MakeAutoRelativeTo(const wxFileName _subject, const wxString& pathbase) - { - wxFileName subject(_subject); - wxDirName base(pathbase); - if (base.IsRelative() || subject.IsRelative()) - return subject.GetFullPath(); - - wxString bv(base.GetVolume()); - bv.MakeUpper(); - wxString sv(subject.GetVolume()); - sv.MakeUpper(); - - if (base.IsContains(subject)) - { - subject.MakeRelativeTo(base.GetFullPath()); - } - else if (base.HasVolume() && subject.HasVolume() && bv == sv) - { - wxString unusedVolume; - wxString pathSansVolume; - subject.SplitVolume(subject.GetFullPath(), &unusedVolume, &pathSansVolume); - subject = pathSansVolume; - } - //implicit else: this stays fully absolute - - return subject.GetFullPath(); - } - - static wxString MakeAutoRelativeTo(const wxDirName subject, const wxString& pathbase) - { - return MakeAutoRelativeTo(wxFileName(subject), pathbase); - } - - // Returns the number of sub folders in this directory path - size_t GetCount() const { return GetDirCount(); } - - // ------------------------------------------------------------------------ - wxFileName Combine(const wxFileName& right) const; - wxDirName Combine(const wxDirName& right) const; - - // removes the lastmost directory from the path - void RemoveLast() { wxFileName::RemoveDir(GetCount() - 1); } - - wxDirName& Normalize(int flags = wxPATH_NORM_ALL, const wxString& cwd = wxEmptyString); - wxDirName& MakeRelativeTo(const wxString& pathBase = wxEmptyString); - wxDirName& MakeAbsolute(const wxString& cwd = wxEmptyString); - - // ------------------------------------------------------------------------ - - void AssignCwd(const wxString& volume = wxEmptyString) { wxFileName::AssignCwd(volume); } - bool SetCwd() { return wxFileName::SetCwd(); } - - // wxWidgets is missing the const qualifier for this one! Shame! - void Rmdir() const; - bool Mkdir() const; - - // ------------------------------------------------------------------------ - - wxDirName& operator=(const wxDirName& dirname) - { - Assign(dirname); - return *this; - } - wxDirName& operator=(const wxString& dirname) - { - Assign(dirname); - return *this; - } - wxDirName& operator=(const char* dirname) - { - Assign(wxString(dirname, wxMBConvUTF8())); - return *this; - } - - wxFileName operator+(const wxFileName& right) const { return Combine(right); } - wxDirName operator+(const wxDirName& right) const { return Combine(right); } - wxFileName operator+(const wxString& right) const { return Combine(wxFileName(right)); } - wxFileName operator+(const char* right) const { return Combine(wxFileName(wxString(right, wxMBConvUTF8()))); } - - bool operator==(const wxDirName& filename) const { return SameAs(filename); } - bool operator!=(const wxDirName& filename) const { return !SameAs(filename); } - - bool operator==(const wxFileName& filename) const { return SameAs(wxDirName(filename)); } - bool operator!=(const wxFileName& filename) const { return !SameAs(wxDirName(filename)); } - - // compare with a filename string interpreted as a native file name - bool operator==(const wxString& filename) const { return SameAs(wxDirName(filename)); } - bool operator!=(const wxString& filename) const { return !SameAs(wxDirName(filename)); } - - const wxFileName& GetFilename() const { return *this; } - wxFileName& GetFilename() { return *this; } -}; - -// -------------------------------------------------------------------------------------- -// Path Namespace -// -------------------------------------------------------------------------------------- -// Cross-platform utilities for manipulation of paths and filenames. Mostly these fall -// back on wxWidgets APIs internally, but are still helpful because some of wx's file stuff -// has minor glitches, or requires sloppy wxFileName typecasting. -// namespace Path { - extern bool IsRelative(const wxString& path); - extern s64 GetFileSize(const wxString& path); + /// Converts any forward slashes to backslashes on Win32. + std::string ToNativePath(const std::string_view& path); + void ToNativePath(std::string* path); - extern wxString Normalize(const wxString& srcpath); - extern wxString Normalize(const wxDirName& srcpath); - extern wxString MakeAbsolute(const wxString& srcpath); + /// Builds a path relative to the specified file + std::string BuildRelativePath(const std::string_view& filename, const std::string_view& new_filename); - extern wxString Combine(const wxString& srcPath, const wxString& srcFile); - extern wxString Combine(const wxDirName& srcPath, const wxFileName& srcFile); - extern wxString Combine(const wxString& srcPath, const wxDirName& srcFile); - extern std::string CombineStdString(const wxDirName& srcPath, const std::string_view& srcFile); - extern std::string CombineStdString(const std::string_view& srcPath, const std::string_view& srcFile); - extern wxString ReplaceExtension(const wxString& src, const wxString& ext); - extern wxString ReplaceFilename(const wxString& src, const wxString& newfilename); - extern wxString GetFilename(const wxString& src); - extern wxString GetDirectory(const wxString& src); - extern wxString GetFilenameWithoutExt(const wxString& src); - extern wxString GetRootDirectory(const wxString& src); - extern fs::path FromWxString(const wxString& path); + /// Joins path components together, producing a new path. + std::string Combine(const std::string_view& base, const std::string_view& next); + + /// Removes all .. and . components from a path. + std::string Canonicalize(const std::string_view& path); + void Canonicalize(std::string* path); + + /// Sanitizes a filename for use in a filesystem. + void SanitizeFileName(char* Destination, u32 cbDestination, const char* FileName, bool StripSlashes /* = true */); + void SanitizeFileName(std::string& Destination, bool StripSlashes = true); + + /// Returns true if the specified path is an absolute path (C:\Path on Windows or /path on Unix). + bool IsAbsolute(const std::string_view& path); + + /// Makes the specified path relative to another (e.g. /a/b/c, /a/b -> ../c). + /// Both paths must be relative, otherwise this function will just return the input path. + std::string MakeRelative(const std::string_view& path, const std::string_view& relative_to); + + /// Returns a view of the extension of a filename. + std::string_view GetExtension(const std::string_view& path); + + /// Removes the extension of a filename. + std::string_view StripExtension(const std::string_view& path); + + /// Replaces the extension of a filename with another. + std::string ReplaceExtension(const std::string_view& path, const std::string_view& new_extension); + + /// Returns the directory component of a filename. + std::string_view GetDirectory(const std::string_view& path); + + /// Returns the filename component of a filename. + std::string_view GetFileName(const std::string_view& path); + + /// Returns the file title (less the extension and path) from a filename. + std::string_view GetFileTitle(const std::string_view& path); + + /// Changes the filename in a path. + std::string ChangeFileName(const std::string_view& path, const std::string_view& new_filename); + void ChangeFileName(std::string* path, const std::string_view& new_filename); + + /// Appends a directory to a path. + std::string AppendDirectory(const std::string_view& path, const std::string_view& new_dir); + void AppendDirectory(std::string* path, const std::string_view& new_dir); + + /// Splits a path into its components, handling both Windows and Unix separators. + std::vector SplitWindowsPath(const std::string_view& path); + std::string JoinWindowsPath(const std::vector& components); + + /// Splits a path into its components, only handling native separators. + std::vector SplitNativePath(const std::string_view& path); + std::string JoinNativePath(const std::vector& components); } // namespace Path diff --git a/common/RedtapeWindows.h b/common/RedtapeWindows.h index c4411184c8..d9474bb186 100644 --- a/common/RedtapeWindows.h +++ b/common/RedtapeWindows.h @@ -31,5 +31,6 @@ #include #include #include +#include #endif diff --git a/common/StringUtil.cpp b/common/StringUtil.cpp index 428cc7881d..1d6443fc1c 100644 --- a/common/StringUtil.cpp +++ b/common/StringUtil.cpp @@ -223,6 +223,14 @@ namespace StringUtil return newStr; } + std::string toUpper(const std::string_view& input) + { + std::string newStr; + std::transform(input.begin(), input.end(), std::back_inserter(newStr), + [](unsigned char c) { return std::toupper(c); }); + return newStr; + } + bool compareNoCase(const std::string_view& str1, const std::string_view& str2) { if (str1.length() != str2.length()) @@ -304,6 +312,21 @@ namespace StringUtil return res; } + std::string ReplaceAll(const std::string_view& subject, const std::string_view& search, const std::string_view& replacement) + { + std::string ret(subject); + if (!ret.empty()) + { + std::string::size_type start_pos = 0; + while ((start_pos = ret.find(search, start_pos)) != std::string::npos) + { + ret.replace(start_pos, search.length(), replacement); + start_pos += replacement.length(); + } + } + return ret; + } + bool ParseAssignmentString(const std::string_view& str, std::string_view* key, std::string_view* value) { const std::string_view::size_type pos = str.find('='); @@ -342,6 +365,7 @@ namespace StringUtil } } +#ifdef _WIN32 std::wstring UTF8StringToWideString(const std::string_view& str) { std::wstring ret; @@ -353,7 +377,6 @@ namespace StringUtil bool UTF8StringToWideString(std::wstring& dest, const std::string_view& str) { -#ifdef _WIN32 int wlen = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.length()), nullptr, 0); if (wlen < 0) return false; @@ -363,22 +386,6 @@ namespace StringUtil return false; return true; -#else - // This depends on wxString, which isn't great. But hopefully we won't need any wide strings outside - // of windows once wx is gone anyway. - if (str.empty()) - { - dest.clear(); - return true; - } - - const wxString wxstr(wxString::FromUTF8(str.data(), str.length())); - if (wxstr.IsEmpty()) - return false; - - dest = wxstr.ToStdWstring(); - return true; -#endif } std::string WideStringToUTF8String(const std::wstring_view& str) @@ -392,7 +399,6 @@ namespace StringUtil bool WideStringToUTF8String(std::string& dest, const std::wstring_view& str) { -#ifdef _WIN32 int mblen = WideCharToMultiByte(CP_UTF8, 0, str.data(), static_cast(str.length()), nullptr, 0, nullptr, nullptr); if (mblen < 0) return false; @@ -405,24 +411,8 @@ namespace StringUtil } return true; -#else - // This depends on wxString, which isn't great. But hopefully we won't need any wide strings outside - // of windows once wx is gone anyway. - if (str.empty()) - { - dest.clear(); - return true; - } - - const wxString wxstr(str.data(), str.data() + str.length()); - if (wxstr.IsEmpty()) - return false; - - const auto buf = wxstr.ToUTF8(); - dest.assign(buf.data(), buf.length()); - return true; -#endif } +#endif std::string U128ToString(const u128& u) { diff --git a/common/StringUtil.h b/common/StringUtil.h index 3a57996951..aaa59ba411 100644 --- a/common/StringUtil.h +++ b/common/StringUtil.h @@ -33,9 +33,6 @@ #include #endif -// TODO: Remove me once wx is gone. -#include - namespace StringUtil { /// Constructs a std::string from a format string. @@ -143,25 +140,25 @@ namespace StringUtil std::string EncodeHex(const u8* data, int length); /// starts_with from C++20 - static inline bool StartsWith(const std::string_view& str, const char* prefix) + static inline bool StartsWith(const std::string_view& str, const std::string_view& prefix) { - return (str.compare(0, std::strlen(prefix), prefix) == 0); + return (str.compare(0, prefix.length(), prefix) == 0); } - static inline bool EndsWith(const std::string_view& str, const char* suffix) + static inline bool EndsWith(const std::string_view& str, const std::string_view& suffix) { - const std::size_t suffix_length = std::strlen(suffix); + const std::size_t suffix_length = suffix.length(); return (str.length() >= suffix_length && str.compare(str.length() - suffix_length, suffix_length, suffix) == 0); } /// StartsWith/EndsWith variants which aren't case sensitive. - static inline bool StartsWithNoCase(const std::string_view& str, const char* prefix) + static inline bool StartsWithNoCase(const std::string_view& str, const std::string_view& prefix) { - return (Strncasecmp(str.data(), prefix, std::strlen(prefix)) == 0); + return (!str.empty() && Strncasecmp(str.data(), prefix.data(), prefix.length()) == 0); } - static inline bool EndsWithNoCase(const std::string_view& str, const char* suffix) + static inline bool EndsWithNoCase(const std::string_view& str, const std::string_view& suffix) { - const std::size_t suffix_length = std::strlen(suffix); - return (str.length() >= suffix_length && Strncasecmp(str.data() + (str.length() - suffix_length), suffix, suffix_length) == 0); + const std::size_t suffix_length = suffix.length(); + return (str.length() >= suffix_length && Strncasecmp(str.data() + (str.length() - suffix_length), suffix.data(), suffix_length) == 0); } /// Strip whitespace from the start/end of the string. @@ -171,6 +168,35 @@ namespace StringUtil /// Splits a string based on a single character delimiter. std::vector SplitString(const std::string_view& str, char delimiter, bool skip_empty = true); + /// Joins a string together using the specified delimiter. + template + static inline std::string JoinString(const T& start, const T& end, char delimiter) + { + std::string ret; + for (auto it = start; it != end; ++it) + { + if (it != start) + ret += delimiter; + ret.append(*it); + } + return ret; + } + template + static inline std::string JoinString(const T& start, const T& end, const std::string_view& delimiter) + { + std::string ret; + for (auto it = start; it != end; ++it) + { + if (it != start) + ret.append(delimiter); + ret.append(*it); + } + return ret; + } + + /// Replaces all instances of search in subject with replacement. + std::string ReplaceAll(const std::string_view& subject, const std::string_view& search, const std::string_view& replacement); + /// Parses an assignment string (Key = Value) into its two components. bool ParseAssignmentString(const std::string_view& str, std::string_view* key, std::string_view* value); @@ -218,28 +244,11 @@ namespace StringUtil } std::string toLower(const std::string_view& str); + std::string toUpper(const std::string_view& str); bool compareNoCase(const std::string_view& str1, const std::string_view& str2); std::vector splitOnNewLine(const std::string& str); - /// Converts a wxString to a UTF-8 std::string. - static inline std::string wxStringToUTF8String(const wxString& str) - { - const wxScopedCharBuffer buf(str.ToUTF8()); - return std::string(buf.data(), buf.length()); - } - - /// Converts a UTF-8 std::string to a wxString. - static inline wxString UTF8StringToWxString(const std::string_view& str) - { - return wxString::FromUTF8(str.data(), str.length()); - } - - /// Converts a UTF-8 std::string to a wxString. - static inline wxString UTF8StringToWxString(const std::string& str) - { - return wxString::FromUTF8(str.data(), str.length()); - } - +#ifdef _WIN32 /// Converts the specified UTF-8 string to a wide string. std::wstring UTF8StringToWideString(const std::string_view& str); bool UTF8StringToWideString(std::wstring& dest, const std::string_view& str); @@ -247,6 +256,7 @@ namespace StringUtil /// Converts the specified wide string to a UTF-8 string. std::string WideStringToUTF8String(const std::wstring_view& str); bool WideStringToUTF8String(std::string& dest, const std::wstring_view& str); +#endif /// Converts unsigned 128-bit data to string. std::string U128ToString(const u128& u); diff --git a/common/common.vcxproj b/common/common.vcxproj index e55db5a091..861365fa69 100644 --- a/common/common.vcxproj +++ b/common/common.vcxproj @@ -82,7 +82,6 @@ - Create @@ -204,12 +203,9 @@ {ef6834a9-11f3-4331-bc34-21b325abb180} - - {3fcc50c2-81e9-5db2-b8d8-2129427568b1} - - \ No newline at end of file + diff --git a/common/common.vcxproj.filters b/common/common.vcxproj.filters index 931534f27c..55cf5d1c09 100644 --- a/common/common.vcxproj.filters +++ b/common/common.vcxproj.filters @@ -49,9 +49,6 @@ Source Files - - Source Files - Source Files diff --git a/common/emitter/LnxCpuDetect.cpp b/common/emitter/LnxCpuDetect.cpp index 80ea32027c..2b2393fd81 100644 --- a/common/emitter/LnxCpuDetect.cpp +++ b/common/emitter/LnxCpuDetect.cpp @@ -15,19 +15,24 @@ #ifndef _WIN32 #include "common/emitter/cpudetect_internal.h" -#include + +#include // Note: Apparently this solution is Linux/Solaris only. // FreeBSD/OsX need something far more complicated (apparently) void x86capabilities::CountLogicalCores() { +#ifdef __linux__ // Note : GetCPUCount uses sysconf( _SC_NPROCESSORS_ONLN ) internally, which can return 1 // if sysconf info isn't available (a long standing linux bug). There are no fallbacks or // alternatives, apparently. - LogicalCores = wxThread::GetCPUCount(); + LogicalCores = sysconf(_SC_NPROCESSORS_ONLN); +#else + LogicalCores = 1; +#endif } // Not implemented yet for linux (see cpudetect_internal.h for details) SingleCoreAffinity::SingleCoreAffinity() = default; SingleCoreAffinity::~SingleCoreAffinity() = default; -#endif \ No newline at end of file +#endif diff --git a/common/vsprops/BaseProperties.props b/common/vsprops/BaseProperties.props index e6dd744b79..eec343552b 100644 --- a/common/vsprops/BaseProperties.props +++ b/common/vsprops/BaseProperties.props @@ -10,7 +10,7 @@ true - $(SolutionDir);$(SolutionDir)\3rdparty\wxWidgets3.0\include;%(AdditionalIncludeDirectories) + $(SolutionDir);%(AdditionalIncludeDirectories) __WIN32__;WIN32;_WINDOWS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;WINVER=0x0603;_WIN32_WINNT=0x0603;%(PreprocessorDefinitions) 16Bytes true diff --git a/pcsx2-qt/EmuThread.cpp b/pcsx2-qt/EmuThread.cpp index 34c9623f05..6351088606 100644 --- a/pcsx2-qt/EmuThread.cpp +++ b/pcsx2-qt/EmuThread.cpp @@ -666,7 +666,7 @@ HostDisplay* EmuThread::acquireHostDisplay(HostDisplay::RenderAPI api) return nullptr; } - if (!s_host_display->InitializeRenderDevice(StringUtil::wxStringToUTF8String(EmuFolders::Cache.ToString()), false) || + if (!s_host_display->InitializeRenderDevice(EmuFolders::Cache, false) || !ImGuiManager::Initialize()) { Console.Error("Failed to initialize device/imgui"); diff --git a/pcsx2-qt/GameList/GameListModel.cpp b/pcsx2-qt/GameList/GameListModel.cpp index 663cec25f0..5f0fe98a5b 100644 --- a/pcsx2-qt/GameList/GameListModel.cpp +++ b/pcsx2-qt/GameList/GameListModel.cpp @@ -17,6 +17,7 @@ #include "GameListModel.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" #include #include @@ -201,7 +202,7 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const case Column_FileTitle: { - const std::string_view file_title(FileSystem::GetFileTitleFromPath(ge->path)); + const std::string_view file_title(Path::GetFileTitle(ge->path)); return QString::fromUtf8(file_title.data(), static_cast(file_title.length())); } @@ -240,7 +241,7 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const case Column_FileTitle: { - const std::string_view file_title(FileSystem::GetFileTitleFromPath(ge->path)); + const std::string_view file_title(Path::GetFileTitle(ge->path)); return QString::fromUtf8(file_title.data(), static_cast(file_title.length())); } @@ -415,8 +416,8 @@ bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& r case Column_FileTitle: { - const std::string_view file_title_left(FileSystem::GetFileTitleFromPath(left->path)); - const std::string_view file_title_right(FileSystem::GetFileTitleFromPath(right->path)); + const std::string_view file_title_left(Path::GetFileTitle(left->path)); + const std::string_view file_title_right(Path::GetFileTitle(right->path)); if (file_title_left == file_title_right) return titlesLessThan(left_row, right_row); @@ -474,7 +475,7 @@ void GameListModel::loadCommonImages() for (u32 i = 1; i < GameList::CompatibilityRatingCount; i++) m_compatibiliy_pixmaps[i].load(QStringLiteral(":/icons/star-%1.png").arg(i - 1)); - m_placeholder_pixmap.load(QString::fromStdString(Path::CombineStdString(EmuFolders::Resources, "cover-placeholder.png"))); + m_placeholder_pixmap.load(QString::fromStdString(Path::Combine(EmuFolders::Resources, "cover-placeholder.png"))); } void GameListModel::setColumnDisplayNames() diff --git a/pcsx2-qt/MainWindow.cpp b/pcsx2-qt/MainWindow.cpp index 28d2589de6..e8b0c99261 100644 --- a/pcsx2-qt/MainWindow.cpp +++ b/pcsx2-qt/MainWindow.cpp @@ -1143,7 +1143,7 @@ void MainWindow::startupUpdateCheck() void MainWindow::onToolsOpenDataDirectoryTriggered() { - const QString path(QtUtils::WxStringToQString(EmuFolders::DataRoot.ToString())); + const QString path(QString::fromStdString(EmuFolders::DataRoot)); QtUtils::OpenURL(this, QUrl::fromLocalFile(path)); } diff --git a/pcsx2-qt/QtHost.cpp b/pcsx2-qt/QtHost.cpp index 7f81017fb5..7a1e55fd1a 100644 --- a/pcsx2-qt/QtHost.cpp +++ b/pcsx2-qt/QtHost.cpp @@ -30,6 +30,7 @@ #include "common/Console.h" #include "common/CrashHandler.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "common/SettingsWrapper.h" #include "common/StringUtil.h" @@ -108,20 +109,19 @@ void QtHost::Shutdown() bool QtHost::SetCriticalFolders() { - std::string program_path(FileSystem::GetProgramPath()); - EmuFolders::AppRoot = wxDirName(wxFileName(StringUtil::UTF8StringToWxString(program_path))); + EmuFolders::AppRoot = Path::Canonicalize(Path::GetDirectory(FileSystem::GetProgramPath())); SetResourcesDirectory(); SetDataDirectory(); // allow SetDataDirectory() to change settings directory (if we want to split config later on) - if (!EmuFolders::Settings.IsOk()) - EmuFolders::Settings = EmuFolders::DataRoot.Combine(wxDirName(L"inis")); + if (EmuFolders::Settings.empty()) + EmuFolders::Settings = Path::Combine(EmuFolders::DataRoot, "inis"); // Write crash dumps to the data directory, since that'll be accessible for certain. - CrashHandler::SetWriteDirectory(EmuFolders::DataRoot.ToUTF8().data()); + CrashHandler::SetWriteDirectory(EmuFolders::DataRoot); // the resources directory should exist, bail out if not - if (!EmuFolders::Resources.Exists()) + if (!FileSystem::DirectoryExists(EmuFolders::Resources.c_str())) { QMessageBox::critical(nullptr, QStringLiteral("Error"), QStringLiteral("Resources directory is missing, your installation is incomplete.")); @@ -134,17 +134,17 @@ bool QtHost::SetCriticalFolders() bool QtHost::ShouldUsePortableMode() { // Check whether portable.ini exists in the program directory. - return FileSystem::FileExists(Path::CombineStdString(EmuFolders::AppRoot, "portable.ini").c_str()); + return FileSystem::FileExists(Path::Combine(EmuFolders::AppRoot, "portable.ini").c_str()); } void QtHost::SetResourcesDirectory() { #ifndef __APPLE__ // On Windows/Linux, these are in the binary directory. - EmuFolders::Resources = EmuFolders::AppRoot.Combine(wxDirName(L"resources")); + EmuFolders::Resources = Path::Combine(EmuFolders::AppRoot, "resources"); #else // On macOS, this is in the bundle resources directory. - EmuFolders::Resources = EmuFolders::AppRoot.Combine(wxDirName("../Resources")); + EmuFolders::Resources = Path::Canonicalize(Path::Combine(EmuFolders::AppRoot, "../Resources")); #endif } @@ -162,16 +162,16 @@ void QtHost::SetDataDirectory() if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory))) { if (std::wcslen(documents_directory) > 0) - EmuFolders::DataRoot = wxDirName(Path::Combine(wxString(documents_directory), L"PCSX2")); + EmuFolders::DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "PCSX2"); CoTaskMemFree(documents_directory); } #elif defined(__linux__) // Check for $HOME/PCSX2 first, for legacy installs. const char* home_dir = getenv("HOME"); - const std::string legacy_dir(home_dir ? Path::CombineStdString(home_dir, "PCSX2") : std::string()); + const std::string legacy_dir(home_dir ? Path::Combine(home_dir, "PCSX2") : std::string()); if (!legacy_dir.empty() && FileSystem::DirectoryExists(legacy_dir.c_str())) { - EmuFolders::DataRoot = wxDirName(StringUtil::UTF8StringToWxString(legacy_dir)); + EmuFolders::DataRoot = std::move(legacy_dir); } else { @@ -179,31 +179,31 @@ void QtHost::SetDataDirectory() const char* xdg_config_home = getenv("XDG_CONFIG_HOME"); if (xdg_config_home && xdg_config_home[0] == '/' && FileSystem::DirectoryExists(xdg_config_home)) { - EmuFolders::DataRoot = wxDirName(StringUtil::UTF8StringToWxString(Path::CombineStdString(xdg_config_home, "PCSX2"))); + EmuFolders::DataRoot = Path::Combine(xdg_config_home, "PCSX2"); } else if (!legacy_dir.empty()) { // fall back to the legacy PCSX2-in-home. - EmuFolders::DataRoot = wxDirName(StringUtil::UTF8StringToWxString(legacy_dir)); + EmuFolders::DataRoot = std::move(legacy_dir); } } #elif defined(__APPLE__) static constexpr char MAC_DATA_DIR[] = "Library/Application Support/PCSX2"; const char* home_dir = getenv("HOME"); if (home_dir) - EmuFolders::DataRoot = wxDirName(StringUtil::UTF8StringToWxString(Path::CombineStdString(home_dir, MAC_DATA_DIR))); + EmuFolders::DataRoot = Path::Combine(home_dir, MAC_DATA_DIR); #endif // make sure it exists - if (EmuFolders::DataRoot.IsOk() && !EmuFolders::DataRoot.Exists()) + if (!EmuFolders::DataRoot.empty() && !FileSystem::DirectoryExists(EmuFolders::DataRoot.c_str())) { // we're in trouble if we fail to create this directory... but try to hobble on with portable - if (!EmuFolders::DataRoot.Mkdir()) - EmuFolders::DataRoot.Clear(); + if (!FileSystem::CreateDirectoryPath(EmuFolders::DataRoot.c_str(), false)) + EmuFolders::DataRoot.clear(); } // couldn't determine the data directory? fallback to portable. - if (!EmuFolders::DataRoot.IsOk()) + if (EmuFolders::DataRoot.empty()) EmuFolders::DataRoot = EmuFolders::AppRoot; } @@ -220,7 +220,7 @@ bool QtHost::InitializeConfig() if (!SetCriticalFolders()) return false; - const std::string path(Path::CombineStdString(EmuFolders::Settings, "PCSX2.ini")); + const std::string path(Path::Combine(EmuFolders::Settings, "PCSX2.ini")); s_base_settings_interface = std::make_unique(std::move(path)); Host::Internal::SetBaseSettingsLayer(s_base_settings_interface.get()); @@ -437,7 +437,7 @@ QString QtHost::GetAppConfigSuffix() std::optional> Host::ReadResourceFile(const char* filename) { - const std::string path(Path::CombineStdString(EmuFolders::Resources, filename)); + const std::string path(Path::Combine(EmuFolders::Resources, filename)); std::optional> ret(FileSystem::ReadBinaryFile(path.c_str())); if (!ret.has_value()) Console.Error("Failed to read resource file '%s'", filename); @@ -446,7 +446,7 @@ std::optional> Host::ReadResourceFile(const char* filename) std::optional Host::ReadResourceFileToString(const char* filename) { - const std::string path(Path::CombineStdString(EmuFolders::Resources, filename)); + const std::string path(Path::Combine(EmuFolders::Resources, filename)); std::optional ret(FileSystem::ReadFileToString(path.c_str())); if (!ret.has_value()) Console.Error("Failed to read resource file to string '%s'", filename); diff --git a/pcsx2-qt/QtUtils.cpp b/pcsx2-qt/QtUtils.cpp index cc0d121c9e..cc8aa47dc2 100644 --- a/pcsx2-qt/QtUtils.cpp +++ b/pcsx2-qt/QtUtils.cpp @@ -690,15 +690,4 @@ namespace QtUtils { return str.empty() ? QString() : QString::fromUtf8(str.data(), str.size()); } - - wxString QStringToWxString(const QString& str) - { - return wxString(str.toStdWString()); - } - - QString WxStringToQString(const wxString& str) - { - return QString::fromStdWString(str.ToStdWstring()); - } - } // namespace QtUtils diff --git a/pcsx2-qt/QtUtils.h b/pcsx2-qt/QtUtils.h index 5d7d7dd3bf..dda073d7fe 100644 --- a/pcsx2-qt/QtUtils.h +++ b/pcsx2-qt/QtUtils.h @@ -34,9 +34,6 @@ class QVariant; class QWidget; class QUrl; -// TODO: Get rid of wx interoperability later on. -#include - namespace QtUtils { /// Marks an action as the "default" - i.e. makes the text bold. @@ -79,8 +76,4 @@ namespace QtUtils /// Converts a std::string_view to a QString safely. QString StringViewToQString(const std::string_view& str); - - // TODO: Get rid of wx interoperability later on. - wxString QStringToWxString(const QString& str); - QString WxStringToQString(const wxString& str); } // namespace QtUtils \ No newline at end of file diff --git a/pcsx2-qt/Settings/BIOSSettingsWidget.cpp b/pcsx2-qt/Settings/BIOSSettingsWidget.cpp index acfda670f7..c67d498740 100644 --- a/pcsx2-qt/Settings/BIOSSettingsWidget.cpp +++ b/pcsx2-qt/Settings/BIOSSettingsWidget.cpp @@ -105,7 +105,7 @@ void BIOSSettingsWidget::openSearchDirectory() void BIOSSettingsWidget::updateSearchDirectory() { // this will generate a full path - m_ui.searchDirectory->setText(QtUtils::WxStringToQString(EmuFolders::Bios.ToString())); + m_ui.searchDirectory->setText(QString::fromStdString(EmuFolders::Bios)); } void BIOSSettingsWidget::listRefreshed(const QVector& items) diff --git a/pcsx2-qt/Settings/CreateMemoryCardDialog.cpp b/pcsx2-qt/Settings/CreateMemoryCardDialog.cpp index c965672505..dc5494fd49 100644 --- a/pcsx2-qt/Settings/CreateMemoryCardDialog.cpp +++ b/pcsx2-qt/Settings/CreateMemoryCardDialog.cpp @@ -16,6 +16,7 @@ #include "PrecompiledHeader.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" #include @@ -127,7 +128,7 @@ void CreateMemoryCardDialog::createCard() #ifdef _WIN32 if (m_ui.ntfsCompression->isChecked() && m_type == MemoryCardType::File) { - const std::string fullPath(Path::CombineStdString(EmuFolders::MemoryCards, nameStr)); + const std::string fullPath(Path::Combine(EmuFolders::MemoryCards, nameStr)); FileSystem::SetPathCompression(fullPath.c_str(), true); } #endif diff --git a/pcsx2-qt/Settings/DEV9SettingsWidget.cpp b/pcsx2-qt/Settings/DEV9SettingsWidget.cpp index db78f0b521..4788677bda 100644 --- a/pcsx2-qt/Settings/DEV9SettingsWidget.cpp +++ b/pcsx2-qt/Settings/DEV9SettingsWidget.cpp @@ -605,21 +605,21 @@ void DEV9SettingsWidget::onHddFileEdit() { //Check if file exists, if so set HddSize to correct value //GHC uses UTF8 on all platforms - fs::path hddPath(m_ui.hddFile->text().toUtf8().constData()); + ghc::filesystem::path hddPath(m_ui.hddFile->text().toUtf8().constData()); if (hddPath.empty()) return; if (hddPath.is_relative()) { - fs::path path(EmuFolders::Settings.ToString().wx_str()); + ghc::filesystem::path path(EmuFolders::Settings); hddPath = path / hddPath; } - if (!fs::exists(hddPath)) + if (!ghc::filesystem::exists(hddPath)) return; - const uintmax_t size = fs::file_size(hddPath); + const uintmax_t size = ghc::filesystem::file_size(hddPath); const u32 sizeSectors = (size / 512); const int sizeGB = size / 1024 / 1024 / 1024; @@ -655,7 +655,7 @@ void DEV9SettingsWidget::onHddSizeSpin(int i) void DEV9SettingsWidget::onHddCreateClicked() { //Do the thing - fs::path hddPath(m_ui.hddFile->text().toUtf8().constData()); + ghc::filesystem::path hddPath(m_ui.hddFile->text().toUtf8().constData()); u64 sizeBytes = (u64)m_dialog->getEffectiveIntValue("DEV9/Hdd", "HddSizeSectors", 0) * 512; if (sizeBytes == 0 || hddPath.empty()) @@ -669,11 +669,11 @@ void DEV9SettingsWidget::onHddCreateClicked() if (hddPath.is_relative()) { //Note, EmuFolders is still wx strings - fs::path path(EmuFolders::Settings.ToString().wx_str()); + ghc::filesystem::path path(EmuFolders::Settings); hddPath = path / hddPath; } - if (fs::exists(hddPath)) + if (ghc::filesystem::exists(hddPath)) { //GHC uses UTF8 on all platforms QMessageBox::StandardButton selection = @@ -685,7 +685,7 @@ void DEV9SettingsWidget::onHddCreateClicked() if (selection == QMessageBox::No) return; else - fs::remove(hddPath); + ghc::filesystem::remove(hddPath); } HddCreateQt hddCreator(this); diff --git a/pcsx2-qt/Settings/SettingsDialog.cpp b/pcsx2-qt/Settings/SettingsDialog.cpp index 511f801362..fe00f6c5aa 100644 --- a/pcsx2-qt/Settings/SettingsDialog.cpp +++ b/pcsx2-qt/Settings/SettingsDialog.cpp @@ -16,6 +16,7 @@ #include "PrecompiledHeader.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" #include "pcsx2/Frontend/GameList.h" #include "pcsx2/Frontend/INISettingsInterface.h" @@ -427,13 +428,13 @@ void SettingsDialog::openGamePropertiesDialog(const GameList::Entry* game, u32 c } std::unique_ptr sif = - std::make_unique(Path::CombineStdString(EmuFolders::GameSettings, StringUtil::StdStringFromFormat("%08X.ini", crc))); + std::make_unique(Path::Combine(EmuFolders::GameSettings, StringUtil::StdStringFromFormat("%08X.ini", crc))); if (FileSystem::FileExists(sif->GetFileName().c_str())) sif->Load(); const QString window_title(tr("%1 [%2]") .arg(game ? QtUtils::StringViewToQString(game->title) : QStringLiteral("")) - .arg(QtUtils::StringViewToQString(FileSystem::GetFileNameFromPath(sif->GetFileName())))); + .arg(QtUtils::StringViewToQString(Path::GetFileName(sif->GetFileName())))); SettingsDialog* dialog = new SettingsDialog(std::move(sif), game, crc); dialog->setWindowTitle(window_title); diff --git a/pcsx2-qt/pcsx2-qt.vcxproj b/pcsx2-qt/pcsx2-qt.vcxproj index 292ba89d3f..fa6db9c7f5 100644 --- a/pcsx2-qt/pcsx2-qt.vcxproj +++ b/pcsx2-qt/pcsx2-qt.vcxproj @@ -79,16 +79,7 @@ - - $(SolutionDir)3rdparty\wxwidgets3.0\$(PlatformName);$(SolutionDir)3rdparty\wxwidgets3.0\include;%(AdditionalIncludeDirectories) - - - - - - - @@ -110,9 +101,6 @@ {e9b51944-7e6d-4bcd-83f2-7bbd5a46182d} - - {3fcc50c2-81e9-5db2-b8d8-2129427568b1} - {12728250-16ec-4dc6-94d7-e21dd88947f8} @@ -123,10 +111,6 @@ {2f6c0388-20cb-4242-9f6c-a6ebb6a83f47} false - - {677b7d11-d5e1-40b3-88b1-9a4df83d2213} - false - {ed2f21fd-0a36-4a8f-9b90-e7d92a2acb63} diff --git a/pcsx2-qt/pcsx2-qt.vcxproj.filters b/pcsx2-qt/pcsx2-qt.vcxproj.filters index a4bb8ddb10..155560ce8d 100644 --- a/pcsx2-qt/pcsx2-qt.vcxproj.filters +++ b/pcsx2-qt/pcsx2-qt.vcxproj.filters @@ -15,30 +15,9 @@ - - Resources - - - Resources - - - Resources - Resources - - Resources - - - Resources - - - Resources - - - Resources - Resources diff --git a/pcsx2/CDVD/CDVD.cpp b/pcsx2/CDVD/CDVD.cpp index 4336402f10..3c7a1c81f3 100644 --- a/pcsx2/CDVD/CDVD.cpp +++ b/pcsx2/CDVD/CDVD.cpp @@ -19,11 +19,12 @@ #include "IopHw.h" #include "IopDma.h" +#include +#include #include -#include -#include #include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" #include "common/Threading.h" @@ -128,7 +129,7 @@ static int mg_BIToffset(u8* buffer) static void cdvdGetMechaVer(u8* ver) { - std::string mecfile(FileSystem::ReplaceExtension(BiosPath, "mec")); + std::string mecfile(Path::ReplaceExtension(BiosPath, "mec")); auto fp = FileSystem::OpenManagedCFile(mecfile.c_str(), "rb"); if (!fp || FileSystem::FSize64(fp.get()) < 4) { @@ -188,7 +189,7 @@ static void cdvdCreateNewNVM(std::FILE* fp) static void cdvdNVM(u8* buffer, int offset, size_t bytes, bool read) { - std::string nvmfile(FileSystem::ReplaceExtension(BiosPath, "nvm")); + std::string nvmfile(Path::ReplaceExtension(BiosPath, "nvm")); auto fp = FileSystem::OpenManagedCFile(nvmfile.c_str(), "r+b"); if (!fp || FileSystem::FSize64(fp.get()) < 1024) { @@ -852,28 +853,25 @@ void cdvdReset() cdvd.RTC.year = 20; } else +#endif { // CDVD internally uses GMT+9. If you think the time's wrong, you're wrong. // Set up your time zone and winter/summer in the BIOS. No PS2 BIOS I know of features automatic DST. - wxDateTime curtime(wxDateTime::GetTimeNow()); - cdvd.RTC.second = (u8)curtime.GetSecond(); - cdvd.RTC.minute = (u8)curtime.GetMinute(); - cdvd.RTC.hour = (u8)curtime.GetHour(wxDateTime::GMT9); - cdvd.RTC.day = (u8)curtime.GetDay(wxDateTime::GMT9); - cdvd.RTC.month = (u8)curtime.GetMonth(wxDateTime::GMT9) + 1; // WX returns Jan as "0" - cdvd.RTC.year = (u8)(curtime.GetYear(wxDateTime::GMT9) - 2000); - } + const std::time_t utc_time = std::time(nullptr); + const std::time_t gmt9_time = (utc_time + (60 * 60 * 9)); + struct tm curtime = {}; +#ifdef _MSC_VER + gmtime_s(&curtime, &gmt9_time); #else - // CDVD internally uses GMT+9. If you think the time's wrong, you're wrong. - // Set up your time zone and winter/summer in the BIOS. No PS2 BIOS I know of features automatic DST. - wxDateTime curtime(wxDateTime::GetTimeNow()); - cdvd.RTC.second = (u8)curtime.GetSecond(); - cdvd.RTC.minute = (u8)curtime.GetMinute(); - cdvd.RTC.hour = (u8)curtime.GetHour(wxDateTime::GMT9); - cdvd.RTC.day = (u8)curtime.GetDay(wxDateTime::GMT9); - cdvd.RTC.month = (u8)curtime.GetMonth(wxDateTime::GMT9) + 1; // WX returns Jan as "0" - cdvd.RTC.year = (u8)(curtime.GetYear(wxDateTime::GMT9) - 2000); + gmtime_r(&gmt9_time, &curtime); #endif + cdvd.RTC.second = (u8)curtime.tm_sec; + cdvd.RTC.minute = (u8)curtime.tm_min; + cdvd.RTC.hour = (u8)curtime.tm_hour; + cdvd.RTC.day = (u8)curtime.tm_mday; + cdvd.RTC.month = (u8)curtime.tm_mon + 1; // WX returns Jan as "0" + cdvd.RTC.year = (u8)(curtime.tm_year - 100); // offset from 2000 + } g_GameStarted = false; g_GameLoading = false; diff --git a/pcsx2/CDVD/CDVDaccess.cpp b/pcsx2/CDVD/CDVDaccess.cpp index 41a1e7a757..e0f0564f88 100644 --- a/pcsx2/CDVD/CDVDaccess.cpp +++ b/pcsx2/CDVD/CDVDaccess.cpp @@ -18,13 +18,8 @@ #define ENABLE_TIMESTAMPS -#ifdef _WIN32 -#include -#endif - #include #include -#include #include #include @@ -35,6 +30,7 @@ #include "common/Assertions.h" #include "common/Exceptions.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" #include "DebugTools/SymbolMap.h" #include "Config.h" @@ -381,7 +377,7 @@ bool DoCDVDopen() return true; } - std::string somepick(FileSystem::StripExtension(FileSystem::GetDisplayNameFromPath(m_SourceFilename[CurrentSourceType]))); + std::string somepick(Path::StripExtension(FileSystem::GetDisplayNameFromPath(m_SourceFilename[CurrentSourceType]))); //FWIW Disc serial availability doesn't seem reliable enough, sometimes it's there and sometime it's just null //Shouldn't the serial be available all time? Potentially need to look into Elfreloadinfo() reliability //TODO: Add extra fallback case for CRC. @@ -393,14 +389,20 @@ bool DoCDVDopen() if (EmuConfig.CurrentBlockdump.empty()) EmuConfig.CurrentBlockdump = FileSystem::GetWorkingDirectory(); - std::string temp(Path::CombineStdString(EmuConfig.CurrentBlockdump, somepick)); + std::string temp(Path::Combine(EmuConfig.CurrentBlockdump, somepick)); #ifdef ENABLE_TIMESTAMPS - wxDateTime curtime(wxDateTime::GetTimeNow()); + std::time_t curtime_t = std::time(nullptr); + struct tm curtime = {}; +#ifdef _MSC_VER + localtime_s(&curtime, &curtime_t); +#else + localtime_r(&curtime_t, &curtime); +#endif temp += StringUtil::StdStringFromFormat(" (%04d-%02d-%02d %02d-%02d-%02d)", - curtime.GetYear(), curtime.GetMonth(), curtime.GetDay(), - curtime.GetHour(), curtime.GetMinute(), curtime.GetSecond()); + curtime.tm_year + 1900, curtime.tm_mon + 1, curtime.tm_mday, + curtime.tm_hour, curtime.tm_min, curtime.tm_sec); #endif temp += ".dump"; diff --git a/pcsx2/CDVD/ChdFileReader.cpp b/pcsx2/CDVD/ChdFileReader.cpp index c14d762306..d818dc017e 100644 --- a/pcsx2/CDVD/ChdFileReader.cpp +++ b/pcsx2/CDVD/ChdFileReader.cpp @@ -18,6 +18,7 @@ #include "common/Assertions.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" ChdFileReader::~ChdFileReader() @@ -87,12 +88,12 @@ bool ChdFileReader::Open2(std::string fileName) } bool found_parent = false; - dirname = FileSystem::GetPathDirectory(chds[chd_depth]); + dirname = Path::GetDirectory(chds[chd_depth]); if (FileSystem::FindFiles(dirname.c_str(), "*.*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES, &results)) { for (const FILESYSTEM_FIND_DATA& fd : results) { - const std::string_view extension(FileSystem::GetExtension(fd.FileName)); + const std::string_view extension(Path::GetExtension(fd.FileName)); if (extension.empty() || StringUtil::Strncasecmp(extension.data(), "chd", 3) != 0) continue; diff --git a/pcsx2/CDVD/GzippedFileReader.cpp b/pcsx2/CDVD/GzippedFileReader.cpp index 376c6510dc..2bc8485ab0 100644 --- a/pcsx2/CDVD/GzippedFileReader.cpp +++ b/pcsx2/CDVD/GzippedFileReader.cpp @@ -14,9 +14,9 @@ */ #include "PrecompiledHeader.h" -#include #include #include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" #include "Config.h" #include "ChunksCache.h" @@ -104,7 +104,8 @@ static void WriteIndexToFile(Access* index, const char* filename) } } -static wxString INDEX_TEMPLATE_KEY(L"$(f)"); +static constexpr char* INDEX_TEMPLATE_KEY = "$(f)"; + // template: // must contain one and only one instance of '$(f)' (without the quotes) // if if !canEndWithKey -> must not end with $(f) @@ -114,34 +115,33 @@ static wxString INDEX_TEMPLATE_KEY(L"$(f)"); // then it's relative to base (not to cwd) // No checks are performed if the result file name can be created. // If this proves useful, we can move it into Path:: . Right now there's no need. -static wxString ApplyTemplate(const std::string& name, const wxDirName& base, +static std::string ApplyTemplate(const std::string& name, const std::string& base, const std::string& fileTemplate, const std::string& filename, bool canEndWithKey) { - wxString tem(StringUtil::UTF8StringToWxString(fileTemplate)); - wxString key = INDEX_TEMPLATE_KEY; - tem = tem.Trim(true).Trim(false); // both sides + // both sides + std::string trimmedTemplate(StringUtil::StripWhitespace(fileTemplate)); - size_t first = tem.find(key); - if (first == wxString::npos // not found - || first != tem.rfind(key) // more than one instance - || !canEndWithKey && first == tem.length() - key.length()) + std::string::size_type first = trimmedTemplate.find(INDEX_TEMPLATE_KEY); + if (first == std::string::npos // not found + || first != trimmedTemplate.rfind(INDEX_TEMPLATE_KEY) // more than one instance + || !canEndWithKey && first == trimmedTemplate.length() - std::strlen(INDEX_TEMPLATE_KEY)) { Console.Error("Invalid %s template '%s'.\n" "Template must contain exactly one '%s' and must not end with it. Abotring.", - name.c_str(), tem.ToUTF8().data(), key.ToUTF8().data()); - return L""; + name.c_str(), trimmedTemplate.c_str(), INDEX_TEMPLATE_KEY); + return {}; } - wxString fname(StringUtil::UTF8StringToWxString(filename)); + std::string fname(filename); if (first > 0) - fname = Path::GetFilename(fname); // without path + fname = Path::GetFileName(fname); // without path - tem.Replace(key, fname); + StringUtil::ReplaceAll(trimmedTemplate, INDEX_TEMPLATE_KEY, fname); if (first > 0) - tem = Path::Combine(base, tem); // ignores appRoot if tem is absolute + trimmedTemplate = Path::Combine(base, trimmedTemplate); // ignores appRoot if tem is absolute - return tem; + return trimmedTemplate; } /* @@ -173,6 +173,7 @@ static void TestTemplate(const wxDirName &base, const wxString &fname, bool canE static std::string iso2indexname(const std::string& isoname) { +#if 0 #ifndef PCSX2_CORE //testTemplate(isoname); wxDirName appRoot = // TODO: have only one of this in PCSX2. Right now have few... @@ -182,6 +183,11 @@ static std::string iso2indexname(const std::string& isoname) #endif //TestTemplate(appRoot, isoname, false); return StringUtil::wxStringToUTF8String(ApplyTemplate("gzip index", appRoot, EmuConfig.GzipIsoIndexTemplate, isoname, false)); +#else + //FIXME + abort(); + return {}; +#endif } GzippedFileReader::GzippedFileReader(void) diff --git a/pcsx2/CDVD/IsoFS/IsoFS.cpp b/pcsx2/CDVD/IsoFS/IsoFS.cpp index b2ba29f259..4a2a250760 100644 --- a/pcsx2/CDVD/IsoFS/IsoFS.cpp +++ b/pcsx2/CDVD/IsoFS/IsoFS.cpp @@ -22,6 +22,7 @@ #include "common/Assertions.h" #include "common/Exceptions.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" #include @@ -176,7 +177,7 @@ IsoFileDescriptor IsoDirectory::FindFile(const std::string_view& filePath) const // wxWidgets DOS-style parser should work fine for ISO 9660 path names. Only practical difference // is case sensitivity, and that won't matter for path splitting. - std::vector parts(FileSystem::SplitWindowsPath(filePath)); + std::vector parts(Path::SplitWindowsPath(filePath)); IsoFileDescriptor info; const IsoDirectory* dir = this; std::unique_ptr deleteme; diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 406a07a300..e4b5d2887d 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -227,7 +227,6 @@ set(pcsx2Headers MemoryCardFolder.h MemoryTypes.h Patch.h - PathDefs.h PCSX2Base.h PerformanceMetrics.h PrecompiledHeader.h @@ -812,7 +811,6 @@ endif() if(PCSX2_CORE) list(APPEND pcsx2SPU2Headers - SPU2/Host/CfgHelpers.cpp SPU2/Host/Config.cpp SPU2/Host/ConfigDebug.cpp SPU2/Host/ConfigSoundTouch.cpp @@ -1117,6 +1115,7 @@ set(pcsx2GuiSources gui/DriveList.cpp gui/ExecutorThread.cpp gui/FastFormatString.cpp + gui/FileUtils.cpp gui/FrameForGS.cpp gui/GlobalCommands.cpp gui/IniInterface.cpp @@ -1140,6 +1139,7 @@ set(pcsx2GuiSources gui/Panels/PathsPanel.cpp gui/Panels/SpeedhacksPanel.cpp gui/Panels/VideoPanel.cpp + gui/PathUtils.cpp gui/PersistentThread.cpp gui/pxCheckBox.cpp gui/pxRadioPanel.cpp @@ -1193,6 +1193,7 @@ set(pcsx2GuiHeaders gui/IsoDropTarget.h gui/MainFrame.h gui/MSWstuff.h + gui/PathDefs.h gui/Panels/ConfigurationPanels.h gui/Panels/LogOptionsPanels.h gui/Panels/MemoryCardPanels.h @@ -1208,6 +1209,7 @@ set(pcsx2GuiHeaders gui/SysThreads.h gui/ThreadingDialogs.h gui/ThreadingDialogs.cpp + gui/wxDirName.h gui/wxGuiTools.h gui/wxSettingsInterface.h ) @@ -1387,10 +1389,6 @@ set(pcsx2RecordingVirtualPadResources set(pcsx2SystemHeaders System/RecTypes.h) -# Utilities sources -set(pcsx2UtilitiesSources - Utilities/FileUtils.cpp) - # Windows sources set(pcsx2WindowsSources CDVD/Windows/DriveUtility.cpp @@ -1518,7 +1516,6 @@ target_sources(PCSX2 PRIVATE ${pcsx2ps2Sources} ${pcsx2ps2Headers} ${pcsx2SystemHeaders} - ${pcsx2UtilitiesSources} ) # gui sources when not doing a qt build @@ -1602,7 +1599,6 @@ target_link_libraries(PCSX2_FLAGS INTERFACE ryml chdr-static libzip::zip - wxWidgets::all ZLIB::ZLIB PkgConfig::SOUNDTOUCH PkgConfig::SAMPLERATE @@ -1616,6 +1612,10 @@ if(PCSX2_CORE) target_link_libraries(PCSX2_FLAGS INTERFACE simpleini ) +else() + target_link_libraries(PCSX2_FLAGS INTERFACE + wxWidgets::all + ) endif() if(WIN32) diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 8dbf5c13f8..7ee1508033 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -17,7 +17,6 @@ #include "common/emitter/tools.h" #include "common/General.h" -#include "common/Path.h" #include class SettingsInterface; @@ -964,7 +963,7 @@ struct Pcsx2Config HostFs : 1; // uses automatic ntfs compression when creating new memory cards (Win32 only) -#ifdef __WXMSW__ +#ifdef _WIN32 bool McdCompressNTFS; #endif BITFIELD_END @@ -1001,9 +1000,8 @@ struct Pcsx2Config void LoadSave(SettingsWrapper& wrap); void LoadSaveMemcards(SettingsWrapper& wrap); - // TODO: Make these std::string when we remove wxFile... std::string FullpathToBios() const; - wxString FullpathToMcd(uint slot) const; + std::string FullpathToMcd(uint slot) const; bool MultitapEnabled(uint port) const; @@ -1024,22 +1022,22 @@ extern Pcsx2Config EmuConfig; namespace EmuFolders { - extern wxDirName AppRoot; - extern wxDirName DataRoot; - extern wxDirName Settings; - extern wxDirName Bios; - extern wxDirName Snapshots; - extern wxDirName Savestates; - extern wxDirName MemoryCards; - extern wxDirName Langs; - extern wxDirName Logs; - extern wxDirName Cheats; - extern wxDirName CheatsWS; - extern wxDirName Resources; - extern wxDirName Cache; - extern wxDirName Covers; - extern wxDirName GameSettings; - extern wxDirName Textures; + extern std::string AppRoot; + extern std::string DataRoot; + extern std::string Settings; + extern std::string Bios; + extern std::string Snapshots; + extern std::string Savestates; + extern std::string MemoryCards; + extern std::string Langs; + extern std::string Logs; + extern std::string Cheats; + extern std::string CheatsWS; + extern std::string Resources; + extern std::string Cache; + extern std::string Covers; + extern std::string GameSettings; + extern std::string Textures; // Assumes that AppRoot and DataRoot have been initialized. void SetDefaults(); diff --git a/pcsx2/DEV9/ATA/ATA.h b/pcsx2/DEV9/ATA/ATA.h index 8176cd2f92..08c6ea50f8 100644 --- a/pcsx2/DEV9/ATA/ATA.h +++ b/pcsx2/DEV9/ATA/ATA.h @@ -22,6 +22,8 @@ #include #include +#include "ghc/filesystem.h" + #include "common/Path.h" #include "DEV9/SimpleQueue.h" @@ -154,7 +156,7 @@ private: public: ATA(); - int Open(fs::path hddPath); + int Open(ghc::filesystem::path hddPath); void Close(); void ATA_HardReset(); diff --git a/pcsx2/DEV9/ATA/ATA_State.cpp b/pcsx2/DEV9/ATA/ATA_State.cpp index cfb6521204..bea1f28d09 100644 --- a/pcsx2/DEV9/ATA/ATA_State.cpp +++ b/pcsx2/DEV9/ATA/ATA_State.cpp @@ -30,7 +30,7 @@ ATA::ATA() ResetEnd(true); } -int ATA::Open(fs::path hddPath) +int ATA::Open(ghc::filesystem::path hddPath) { readBufferLen = 256 * 512; readBuffer = new u8[readBufferLen]; @@ -38,7 +38,7 @@ int ATA::Open(fs::path hddPath) CreateHDDinfo(EmuConfig.DEV9.HddSizeSectors); //Open File - if (!fs::exists(hddPath)) + if (!ghc::filesystem::exists(hddPath)) { #ifndef PCSX2_CORE HddCreateWx hddCreator; @@ -52,7 +52,7 @@ int ATA::Open(fs::path hddPath) return -1; #endif } - hddImage = fs::fstream(hddPath, std::ios::in | std::ios::out | std::ios::binary); + hddImage = ghc::filesystem::fstream(hddPath, std::ios::in | std::ios::out | std::ios::binary); //Store HddImage size for later check hddImage.seekg(0, std::ios::end); diff --git a/pcsx2/DEV9/ATA/HddCreate.cpp b/pcsx2/DEV9/ATA/HddCreate.cpp index a4c746dac1..61f3388da5 100644 --- a/pcsx2/DEV9/ATA/HddCreate.cpp +++ b/pcsx2/DEV9/ATA/HddCreate.cpp @@ -26,19 +26,19 @@ void HddCreate::Start() Cleanup(); } -void HddCreate::WriteImage(fs::path hddPath, u64 reqSizeBytes) +void HddCreate::WriteImage(ghc::filesystem::path hddPath, u64 reqSizeBytes) { constexpr int buffsize = 4 * 1024; u8 buff[buffsize] = {0}; //4kb - if (fs::exists(hddPath)) + if (ghc::filesystem::exists(hddPath)) { errored.store(true); SetError(); return; } - std::fstream newImage = fs::fstream(hddPath, std::ios::out | std::ios::binary); + std::fstream newImage = ghc::filesystem::fstream(hddPath, std::ios::out | std::ios::binary); if (newImage.fail()) { @@ -55,7 +55,7 @@ void HddCreate::WriteImage(fs::path hddPath, u64 reqSizeBytes) if (newImage.fail()) { newImage.close(); - fs::remove(filePath); + ghc::filesystem::remove(filePath); errored.store(true); SetError(); return; @@ -77,7 +77,7 @@ void HddCreate::WriteImage(fs::path hddPath, u64 reqSizeBytes) if (newImage.fail()) { newImage.close(); - fs::remove(filePath); + ghc::filesystem::remove(filePath); errored.store(true); SetError(); return; @@ -91,7 +91,7 @@ void HddCreate::WriteImage(fs::path hddPath, u64 reqSizeBytes) if (newImage.fail()) { newImage.close(); - fs::remove(filePath); + ghc::filesystem::remove(filePath); errored.store(true); SetError(); return; @@ -107,7 +107,7 @@ void HddCreate::WriteImage(fs::path hddPath, u64 reqSizeBytes) if (canceled.load()) { newImage.close(); - fs::remove(filePath); + ghc::filesystem::remove(filePath); errored.store(true); SetError(); return; diff --git a/pcsx2/DEV9/ATA/HddCreate.h b/pcsx2/DEV9/ATA/HddCreate.h index a27d1f9474..d3b5b868af 100644 --- a/pcsx2/DEV9/ATA/HddCreate.h +++ b/pcsx2/DEV9/ATA/HddCreate.h @@ -20,10 +20,12 @@ #include "common/Path.h" +#include "ghc/filesystem.h" + class HddCreate { public: - fs::path filePath; + ghc::filesystem::path filePath; u64 neededSize; std::atomic_bool errored{false}; @@ -48,5 +50,5 @@ protected: void SetCanceled(); private: - void WriteImage(fs::path hddPath, u64 reqSizeBytes); + void WriteImage(ghc::filesystem::path hddPath, u64 reqSizeBytes); }; diff --git a/pcsx2/DEV9/ConfigUI.cpp b/pcsx2/DEV9/ConfigUI.cpp index 9e2d01939c..6718261266 100644 --- a/pcsx2/DEV9/ConfigUI.cpp +++ b/pcsx2/DEV9/ConfigUI.cpp @@ -422,7 +422,7 @@ void DEV9configure() if (hddPath.is_relative()) { //GHC uses UTF8 on all platforms - fs::path path(EmuFolders::Settings.ToString().wx_str()); + ghc::filesystem::path path(EmuFolders::Settings); hddPath = path / hddPath; } diff --git a/pcsx2/DEV9/DEV9.cpp b/pcsx2/DEV9/DEV9.cpp index e34e97ec2b..7018a3b58b 100644 --- a/pcsx2/DEV9/DEV9.cpp +++ b/pcsx2/DEV9/DEV9.cpp @@ -16,6 +16,7 @@ #include "PrecompiledHeader.h" #include "common/Assertions.h" +#include "common/StringUtil.h" #ifdef _WIN32 #include "common/RedtapeWindows.h" @@ -94,17 +95,21 @@ int mapping; bool isRunning = false; -fs::path GetHDDPath() +ghc::filesystem::path GetHDDPath() { //GHC uses UTF8 on all platforms - fs::path hddPath(EmuConfig.DEV9.HddFile); + ghc::filesystem::path hddPath(EmuConfig.DEV9.HddFile); if (hddPath.empty()) EmuConfig.DEV9.HddEnable = false; if (hddPath.is_relative()) { - fs::path path(EmuFolders::Settings.ToString().wx_str()); +#ifdef _WIN32 + ghc::filesystem::path path(StringUtil::UTF8StringToWideString(EmuFolders::Settings)); +#else + ghc::filesystem::path path(EmuFolders::Settings); +#endif hddPath = path / hddPath; } @@ -206,7 +211,7 @@ s32 DEV9open() #endif DevCon.WriteLn("DEV9: open r+: %s", EmuConfig.DEV9.HddFile.c_str()); - fs::path hddPath = GetHDDPath(); + ghc::filesystem::path hddPath = GetHDDPath(); if (EmuConfig.DEV9.HddEnable) { @@ -1070,7 +1075,7 @@ void DEV9CheckChanges(const Pcsx2Config& old_config) //Hdd //Hdd Validate Path - fs::path hddPath = GetHDDPath(); + ghc::filesystem::path hddPath = GetHDDPath(); //Hdd Compare with old config if (EmuConfig.DEV9.HddEnable) diff --git a/pcsx2/DEV9/DEV9Config.cpp b/pcsx2/DEV9/DEV9Config.cpp index 4c30f27c76..76ceeb4822 100644 --- a/pcsx2/DEV9/DEV9Config.cpp +++ b/pcsx2/DEV9/DEV9Config.cpp @@ -15,6 +15,7 @@ #include "PrecompiledHeader.h" +#include "common/StringUtil.h" #include "ghc/filesystem.h" #include @@ -38,7 +39,7 @@ void SaveDnsHosts() { #ifndef PCSX2_CORE - std::unique_ptr hini(OpenFileConfig(EmuFolders::Settings.Combine(wxString("DEV9Hosts.ini")).GetFullPath())); + std::unique_ptr hini(OpenFileConfig(StringUtil::UTF8StringToWxString(Path::Combine(EmuFolders::Settings, "DEV9Hosts.ini")))); #else std::unique_ptr hini(new wxFileConfig(wxEmptyString, wxEmptyString, EmuFolders::Settings.Combine(wxString("DEV9Hosts.ini")).GetFullPath(), wxEmptyString, wxCONFIG_USE_RELATIVE_PATH)); #endif @@ -68,7 +69,7 @@ void SaveDnsHosts() void LoadDnsHosts() { - wxFileName iniPath = EmuFolders::Settings.Combine(wxString("DEV9Hosts.ini")); + wxFileName iniPath = StringUtil::UTF8StringToWxString(Path::Combine(EmuFolders::Settings, "DEV9Hosts.ini")); config.EthHosts.clear(); //If no file exists, create one to provide an example config if (!iniPath.FileExists()) diff --git a/pcsx2/DebugTools/Debug.h b/pcsx2/DebugTools/Debug.h index ba85b979ba..afdd02f0f0 100644 --- a/pcsx2/DebugTools/Debug.h +++ b/pcsx2/DebugTools/Debug.h @@ -20,7 +20,7 @@ #include "Memory.h" extern FILE *emuLog; -extern wxString emuLogName; +extern std::string emuLogName; extern char* disVU0MicroUF(u32 code, u32 pc); extern char* disVU0MicroLF(u32 code, u32 pc); diff --git a/pcsx2/Dmac.h b/pcsx2/Dmac.h index 084edd5ac7..803b42cfae 100644 --- a/pcsx2/Dmac.h +++ b/pcsx2/Dmac.h @@ -280,21 +280,21 @@ union tDMAC_QUEUE bool empty() const { return (_u16 == 0); } }; -static __fi const wxChar* ChcrName(u32 addr) +static __fi const char* ChcrName(u32 addr) { switch (addr) { - case D0_CHCR: return L"Vif 0"; - case D1_CHCR: return L"Vif 1"; - case D2_CHCR: return L"GIF"; - case D3_CHCR: return L"Ipu 0"; - case D4_CHCR: return L"Ipu 1"; - case D5_CHCR: return L"Sif 0"; - case D6_CHCR: return L"Sif 1"; - case D7_CHCR: return L"Sif 2"; - case D8_CHCR: return L"SPR 0"; - case D9_CHCR: return L"SPR 1"; - default: return L"???"; + case D0_CHCR: return "Vif 0"; + case D1_CHCR: return "Vif 1"; + case D2_CHCR: return "GIF"; + case D3_CHCR: return "Ipu 0"; + case D4_CHCR: return "Ipu 1"; + case D5_CHCR: return "Sif 0"; + case D6_CHCR: return "Sif 1"; + case D7_CHCR: return "Sif 2"; + case D8_CHCR: return "SPR 0"; + case D9_CHCR: return "SPR 1"; + default: return "???"; } } diff --git a/pcsx2/Dump.cpp b/pcsx2/Dump.cpp index ea4744caf5..ddcb5e220c 100644 --- a/pcsx2/Dump.cpp +++ b/pcsx2/Dump.cpp @@ -24,6 +24,7 @@ #include "Config.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "fmt/core.h" @@ -210,8 +211,8 @@ void iDumpBlock(u32 ee_pc, u32 ee_size, uptr x86_pc, u32 x86_size) DbgCon.WriteLn( Color_Gray, "dump block %x:%x (x86:0x%x)", ee_pc, ee_end, x86_pc ); - EmuFolders::Logs.Mkdir(); - std::string dump_filename(Path::CombineStdString(EmuFolders::Logs, fmt::format("R5900dump_{:.8X}:{:.8X}.txt", ee_pc, ee_end) )); + FileSystem::CreateDirectoryPath(EmuFolders::Logs.c_str(), false); + std::string dump_filename(Path::Combine(EmuFolders::Logs, fmt::format("R5900dump_{:.8X}:{:.8X}.txt", ee_pc, ee_end) )); std::FILE* eff = FileSystem::OpenCFile(dump_filename.c_str(), "w"); if (!eff) return; @@ -251,7 +252,7 @@ void iDumpBlock(u32 ee_pc, u32 ee_size, uptr x86_pc, u32 x86_size) // handy but slow solution (system call) #ifdef __linux__ - std::string obj_filename(Path::CombineStdString(EmuFolders::Logs, "objdump_tmp.o")); + std::string obj_filename(Path::Combine(EmuFolders::Logs, "objdump_tmp.o")); std::FILE* objdump = FileSystem::OpenCFile(obj_filename.c_str(), "wb"); if (!objdump) return; @@ -278,8 +279,8 @@ void iDumpBlock( int startpc, u8 * ptr ) DbgCon.WriteLn( Color_Gray, "dump1 %x:%x, %x", startpc, pc, cpuRegs.cycle ); - EmuFolders::Logs.Mkdir(); - std::FILE* eff = FileSystem::OpenCFile(Path::CombineStdString(EmuFolders::Logs, fmt::format("R5900dump{:.8X}.txt", startpc)).c_str(), "w"); + FileSystem::CreateDirectoryPath(EmuFolders::Logs.c_str(), false); + std::FILE* eff = FileSystem::OpenCFile(Path::Combine(EmuFolders::Logs, fmt::format("R5900dump{:.8X}.txt", startpc)).c_str(), "w"); if (!eff) return; diff --git a/pcsx2/Frontend/D3D11HostDisplay.cpp b/pcsx2/Frontend/D3D11HostDisplay.cpp index b892013d35..e438bf374c 100644 --- a/pcsx2/Frontend/D3D11HostDisplay.cpp +++ b/pcsx2/Frontend/D3D11HostDisplay.cpp @@ -25,6 +25,7 @@ #include "common/Assertions.h" #include "common/Console.h" #include "common/StringUtil.h" +#include "common/RedtapeWindows.h" #include "Config.h" diff --git a/pcsx2/Frontend/GameList.cpp b/pcsx2/Frontend/GameList.cpp index c7c95180d8..eebd29b587 100644 --- a/pcsx2/Frontend/GameList.cpp +++ b/pcsx2/Frontend/GameList.cpp @@ -20,6 +20,7 @@ #include "common/Assertions.h" #include "common/Console.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "common/ProgressCallback.h" #include "common/StringUtil.h" #include @@ -161,7 +162,7 @@ bool GameList::GetElfListEntry(const std::string& path, GameList::Entry* entry) const std::string display_name(FileSystem::GetDisplayNameFromPath(path)); entry->path = path; entry->serial.clear(); - entry->title = FileSystem::StripExtension(display_name); + entry->title = Path::StripExtension(display_name); entry->region = Region::Other; entry->total_size = static_cast(file_size); entry->type = EntryType::ELF; @@ -231,7 +232,7 @@ bool GameList::GetIsoListEntry(const std::string& path, GameList::Entry* entry) } else { - entry->title = FileSystem::GetFileTitleFromPath(path); + entry->title = Path::GetFileTitle(path); entry->region = Region::Other; } @@ -358,7 +359,7 @@ bool GameList::LoadEntriesFromCache(std::FILE* stream) static std::string GetCacheFilename() { - return Path::CombineStdString(EmuFolders::Cache, "gamelist.cache"); + return Path::Combine(EmuFolders::Cache, "gamelist.cache"); } void GameList::LoadCache() @@ -680,13 +681,13 @@ std::string GameList::GetCoverImagePath(const std::string& path, const std::stri for (const char* extension : extensions) { // use the file title if it differs (e.g. modded games) - const std::string_view file_title(FileSystem::GetFileTitleFromPath(path)); + const std::string_view file_title(Path::GetFileTitle(path)); if (!file_title.empty() && title != file_title) { std::string cover_filename(file_title); cover_filename += extension; - cover_path = Path::CombineStdString(EmuFolders::Covers, cover_filename); + cover_path = Path::Combine(EmuFolders::Covers, cover_filename); if (FileSystem::FileExists(cover_path.c_str())) return cover_path; } @@ -695,7 +696,7 @@ std::string GameList::GetCoverImagePath(const std::string& path, const std::stri if (!title.empty()) { const std::string cover_filename(title + extension); - cover_path = Path::CombineStdString(EmuFolders::Covers, cover_filename); + cover_path = Path::Combine(EmuFolders::Covers, cover_filename); if (FileSystem::FileExists(cover_path.c_str())) return cover_path; } @@ -704,7 +705,7 @@ std::string GameList::GetCoverImagePath(const std::string& path, const std::stri if (!serial.empty()) { const std::string cover_filename(serial + extension); - cover_path = Path::CombineStdString(EmuFolders::Covers, cover_filename); + cover_path = Path::Combine(EmuFolders::Covers, cover_filename); if (FileSystem::FileExists(cover_path.c_str())) return cover_path; } @@ -729,5 +730,5 @@ std::string GameList::GetNewCoverImagePathForEntry(const Entry* entry, const cha } const std::string cover_filename(entry->title + extension); - return Path::CombineStdString(EmuFolders::Covers, cover_filename); + return Path::Combine(EmuFolders::Covers, cover_filename); } diff --git a/pcsx2/GS/GS.cpp b/pcsx2/GS/GS.cpp index 06a14e0487..d864112067 100644 --- a/pcsx2/GS/GS.cpp +++ b/pcsx2/GS/GS.cpp @@ -30,6 +30,8 @@ #include "GSLzma.h" #include "common/Console.h" +#include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" #include "pcsx2/Config.h" #include "pcsx2/Counters.h" @@ -648,7 +650,7 @@ void GSgetStats(std::string& info) { const double fps = GetVerticalFrequency(); const double fillrate = pm.Get(GSPerfMon::Fillrate); - info = format("%s SW | %d S | %d P | %d D | %.2f U | %.2f D | %.2f mpps", + info = StringUtil::StdStringFromFormat("%s SW | %d S | %d P | %d D | %.2f U | %.2f D | %.2f mpps", api_name, (int)pm.Get(GSPerfMon::SyncPoint), (int)pm.Get(GSPerfMon::Prim), @@ -659,13 +661,13 @@ void GSgetStats(std::string& info) } else if (GSConfig.Renderer == GSRendererType::Null) { - info = format("%s Null", api_name); + info = StringUtil::StdStringFromFormat("%s Null", api_name); } else { if (GSConfig.TexturePreloading == TexturePreloadingLevel::Full) { - info = format("%s HW | HC: %d MB | %d P | %d D | %d DC | %d B | %d RB | %d TC | %d TU", + info = StringUtil::StdStringFromFormat("%s HW | HC: %d MB | %d P | %d D | %d DC | %d B | %d RB | %d TC | %d TU", api_name, (int)std::ceil(GSRendererHW::GetInstance()->GetTextureCache()->GetHashCacheMemoryUsage() / 1048576.0f), (int)pm.Get(GSPerfMon::Prim), @@ -678,7 +680,7 @@ void GSgetStats(std::string& info) } else { - info = format("%s HW | %d P | %d D | %d DC | %d B | %d RB | %d TC | %d TU", + info = StringUtil::StdStringFromFormat("%s HW | %d P | %d D | %d DC | %d B | %d RB | %d TC | %d TU", api_name, (int)pm.Get(GSPerfMon::Prim), (int)pm.Get(GSPerfMon::Draw), @@ -989,6 +991,8 @@ void fifo_free(void* ptr, size_t size, size_t repeat) #else #include +#include +#include #include void* vmalloc(size_t size, bool code) @@ -1106,7 +1110,7 @@ bool GSApp::WriteIniString(const char* lpAppName, const char* lpKeyName, const c m_configuration_map[key] = value; // Save config to a file - FILE* f = px_fopen(lpFileName, "w"); + FILE* f = FileSystem::OpenCFile(lpFileName, "w"); if (f == NULL) return false; // FIXME print a nice message @@ -1427,7 +1431,7 @@ void GSApp::BuildConfigurationMap(const char* lpFileName) // Load config from file #ifdef _WIN32 - std::ifstream file(convert_utf8_to_utf16(lpFileName)); + std::ifstream file(StringUtil::UTF8StringToWideString(lpFileName)); #else std::ifstream file(lpFileName); #endif @@ -1467,8 +1471,7 @@ void GSApp::SetConfigDir() // we need to initialize the ini folder later at runtime than at theApp init, as // core settings aren't populated yet, thus we do populate it if needed either when // opening GS settings or init -- govanify - wxString iniName(L"GS.ini"); - m_ini = EmuFolders::Settings.Combine(iniName).GetFullPath().ToUTF8(); + m_ini = Path::Combine(EmuFolders::Settings, "GS.ini"); } std::string GSApp::GetConfigS(const char* entry) diff --git a/pcsx2/GS/GSCapture.cpp b/pcsx2/GS/GSCapture.cpp index 0af62ed953..99dd046030 100644 --- a/pcsx2/GS/GSCapture.cpp +++ b/pcsx2/GS/GSCapture.cpp @@ -18,6 +18,7 @@ #include "GSPng.h" #include "GSUtil.h" #include "GSExtra.h" +#include "common/StringUtil.h" #ifdef _WIN32 @@ -524,7 +525,7 @@ bool GSCapture::BeginCapture(float fps, GSVector2i recommendedResolution, float m_src.query()->DeliverNewSegment(); m_capturing = true; - filename = convert_utf16_to_utf8(dlg.m_filename.erase(dlg.m_filename.length() - 3, 3) + L"wav"); + filename = StringUtil::WideStringToUTF8String(dlg.m_filename.erase(dlg.m_filename.length() - 3, 3) + L"wav"); return true; #elif defined(__unix__) // Note I think it doesn't support multiple depth creation @@ -569,7 +570,7 @@ bool GSCapture::DeliverFrame(const void* bits, int pitch, bool rgba) #elif defined(__unix__) - std::string out_file = m_out_dir + format("/frame.%010d.png", m_frame); + std::string out_file = m_out_dir + StringUtil::StdStringFromFormat("/frame.%010d.png", m_frame); //GSPng::Save(GSPng::RGB_PNG, out_file, (u8*)bits, m_size.x, m_size.y, pitch, m_compression_level); m_workers[m_frame % m_threads]->Push(std::make_shared(GSPng::RGB_PNG, out_file, static_cast(bits), m_size.x, m_size.y, pitch, m_compression_level)); diff --git a/pcsx2/GS/GSCrc.cpp b/pcsx2/GS/GSCrc.cpp index 068499ec15..89a86edf1d 100644 --- a/pcsx2/GS/GSCrc.cpp +++ b/pcsx2/GS/GSCrc.cpp @@ -17,6 +17,7 @@ #include "GSCrc.h" #include "GSExtra.h" #include "GS.h" +#include "common/StringUtil.h" const CRC::Game CRC::m_games[] = { @@ -346,7 +347,7 @@ std::string ToLower(std::string str) // E.g. Disable hacks for these CRCs: CrcHacksExclusions=0x0F0C4A9C, 0x0EE5646B, 0x7ACF7E03 bool IsCrcExcluded(std::string exclusionList, u32 crc) { - std::string target = format("0x%08x", crc); + std::string target = StringUtil::StdStringFromFormat("0x%08x", crc); exclusionList = ToLower(exclusionList); return exclusionList.find(target) != std::string::npos || exclusionList.find("all") != std::string::npos; } diff --git a/pcsx2/GS/GSExtra.h b/pcsx2/GS/GSExtra.h index 32bc418b95..99cb6cb3f1 100644 --- a/pcsx2/GS/GSExtra.h +++ b/pcsx2/GS/GSExtra.h @@ -18,25 +18,6 @@ #include "GSVector.h" #include "pcsx2/Config.h" -#ifdef _WIN32 -#include "common/RedtapeWindows.h" -inline std::string convert_utf16_to_utf8(const std::wstring& utf16_string) -{ - const int size = WideCharToMultiByte(CP_UTF8, 0, utf16_string.c_str(), utf16_string.size(), nullptr, 0, nullptr, nullptr); - std::string converted_string(size, 0); - WideCharToMultiByte(CP_UTF8, 0, utf16_string.c_str(), utf16_string.size(), converted_string.data(), converted_string.size(), nullptr, nullptr); - return converted_string; -} - -inline std::wstring convert_utf8_to_utf16(const std::string& utf8_string) -{ - int size = MultiByteToWideChar(CP_UTF8, 0, utf8_string.c_str(), -1, nullptr, 0); - std::vector converted_string(size); - MultiByteToWideChar(CP_UTF8, 0, utf8_string.c_str(), -1, converted_string.data(), converted_string.size()); - return {converted_string.data()}; -} -#endif - /// Like `memcmp(&a, &b, sizeof(T)) == 0` but faster template __forceinline bool BitEqual(const T& a, const T& b) @@ -95,16 +76,6 @@ __forceinline bool BitEqual(const T& a, const T& b) return eqb; } -// _wfopen has to be used on Windows for pathnames containing non-ASCII characters. -inline FILE* px_fopen(const std::string& filename, const std::string& mode) -{ -#ifdef _WIN32 - return _wfopen(convert_utf8_to_utf16(filename).c_str(), convert_utf8_to_utf16(mode).c_str()); -#else - return fopen(filename.c_str(), mode.c_str()); -#endif -} - #ifdef ENABLE_ACCURATE_BUFFER_EMULATION static const GSVector2i default_rt_size(2048, 2048); #else @@ -150,8 +121,6 @@ static constexpr int MAXIMUM_TEXTURE_MIPMAP_LEVELS = 7; extern const std::string root_sw; extern const std::string root_hw; -extern std::string format(const char* fmt, ...); - extern void* vmalloc(size_t size, bool code); extern void vmfree(void* ptr, size_t size); diff --git a/pcsx2/GS/GSPng.cpp b/pcsx2/GS/GSPng.cpp index 790adde0c1..a81893b874 100644 --- a/pcsx2/GS/GSPng.cpp +++ b/pcsx2/GS/GSPng.cpp @@ -16,6 +16,7 @@ #include "PrecompiledHeader.h" #include "GSPng.h" #include "GSExtra.h" +#include "common/FileSystem.h" #include #include @@ -50,7 +51,7 @@ namespace GSPng const int offset = first_image ? 0 : pixel[fmt].bytes_per_pixel_out; const int bytes_per_pixel_out = first_image ? pixel[fmt].bytes_per_pixel_out : bytes_per_pixel_in - offset; - FILE* fp = px_fopen(file, "wb"); + FILE* fp = FileSystem::OpenCFile(file.c_str(), "wb"); if (fp == nullptr) return false; diff --git a/pcsx2/GS/GSState.cpp b/pcsx2/GS/GSState.cpp index 912e6f6c98..edae87a044 100644 --- a/pcsx2/GS/GSState.cpp +++ b/pcsx2/GS/GSState.cpp @@ -17,9 +17,11 @@ #include "GSState.h" #include "GSGL.h" #include "GSUtil.h" +#include "common/StringUtil.h" #include // clamp #include // FLT_MAX +#include #include // Dump Verticles int GSState::s_n = 0; @@ -1855,7 +1857,7 @@ void GSState::Read(u8* mem, int len) if (s_dump && s_save && s_n >= s_saven) { - std::string s = m_dump_root + format( + std::string s = m_dump_root + StringUtil::StdStringFromFormat( "%05d_read_%05x_%d_%d_%d_%d_%d_%d.bmp", s_n, (int)m_env.BITBLTBUF.SBP, (int)m_env.BITBLTBUF.SBW, (int)m_env.BITBLTBUF.SPSM, r.left, r.top, r.right, r.bottom); diff --git a/pcsx2/GS/GSUtil.cpp b/pcsx2/GS/GSUtil.cpp index ee27fa31ab..03f4ab7f77 100644 --- a/pcsx2/GS/GSUtil.cpp +++ b/pcsx2/GS/GSUtil.cpp @@ -17,8 +17,7 @@ #include "GS.h" #include "GSExtra.h" #include "GSUtil.h" -#include -#include +#include "common/StringUtil.h" #ifdef _WIN32 #include @@ -239,7 +238,7 @@ std::string GStempdir() #ifdef _WIN32 wchar_t path[MAX_PATH + 1]; GetTempPath(MAX_PATH, path); - return convert_utf16_to_utf8(path); + return StringUtil::WideStringToUTF8String(path); #else return "/tmp"; #endif diff --git a/pcsx2/GS/Renderers/Common/GSRenderer.cpp b/pcsx2/GS/Renderers/Common/GSRenderer.cpp index ba1c36d62e..68d8cc7f48 100644 --- a/pcsx2/GS/Renderers/Common/GSRenderer.cpp +++ b/pcsx2/GS/Renderers/Common/GSRenderer.cpp @@ -485,7 +485,7 @@ void GSRenderer::VSync(u32 field, bool registers_written) if (s_dump && s_n >= s_saven) { - m_regs->Dump(root_sw + format("%05d_f%lld_gs_reg.txt", s_n, g_perfmon.GetFrame())); + m_regs->Dump(root_sw + StringUtil::StdStringFromFormat("%05d_f%lld_gs_reg.txt", s_n, g_perfmon.GetFrame())); } const int fb_sprite_blits = g_perfmon.GetDisplayFramebufferSpriteBlits(); @@ -585,17 +585,17 @@ void GSRenderer::VSync(u32 field, bool registers_written) Host::AddKeyedOSDMessage("GSDump", fmt::format("Saving {0} GS dump {1} to '{2}'", (m_dump_frames == 1) ? "single frame" : "multi-frame", compression_str, - FileSystem::GetFileNameFromPath(m_dump->GetPath())), 10.0f); + Path::GetFileName(m_dump->GetPath())), 10.0f); } if (GSTexture* t = g_gs_device->GetCurrent()) { const std::string path(m_snapshot + ".png"); - const std::string_view filename(FileSystem::GetFileNameFromPath(path)); + const std::string_view filename(Path::GetFileName(path)); if (t->Save(path)) { Host::AddKeyedOSDMessage("GSScreenshot", - fmt::format("Screenshot saved to '{}'.", FileSystem::GetFileNameFromPath(path)), 10.0f); + fmt::format("Screenshot saved to '{}'.", Path::GetFileName(path)), 10.0f); } else { @@ -610,7 +610,7 @@ void GSRenderer::VSync(u32 field, bool registers_written) const bool last = (m_dump_frames == 0); if (m_dump->VSync(field, last, m_regs)) { - Host::AddKeyedOSDMessage("GSDump", fmt::format("Saved GS dump to '{}'.", FileSystem::GetFileNameFromPath(m_dump->GetPath())), 10.0f); + Host::AddKeyedOSDMessage("GSDump", fmt::format("Saved GS dump to '{}'.", Path::GetFileName(m_dump->GetPath())), 10.0f); m_dump.reset(); } else if (!last) @@ -680,19 +680,19 @@ void GSRenderer::QueueSnapshot(const std::string& path, u32 gsdump_frames) // append the game serial and title if (std::string name(GetDumpName()); !name.empty()) { - FileSystem::SanitizeFileName(name); + Path::SanitizeFileName(name); m_snapshot += '_'; m_snapshot += name; } if (std::string serial(GetDumpSerial()); !serial.empty()) { - FileSystem::SanitizeFileName(serial); + Path::SanitizeFileName(serial); m_snapshot += '_'; m_snapshot += serial; } // prepend snapshots directory - m_snapshot = Path::CombineStdString(EmuFolders::Snapshots, m_snapshot); + m_snapshot = Path::Combine(EmuFolders::Snapshots, m_snapshot); } // this is really gross, but wx we get the snapshot request after shift... diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 754d4d87a5..2c24bf95af 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -91,8 +91,7 @@ bool GSDevice11::Create(HostDisplay* display) if (!GSConfig.DisableShaderCache) { - if (!m_shader_cache.Open(StringUtil::wxStringToUTF8String(EmuFolders::Cache.ToString()), - m_dev->GetFeatureLevel(), SHADER_VERSION, GSConfig.UseDebugDevice)) + if (!m_shader_cache.Open(EmuFolders::Cache, m_dev->GetFeatureLevel(), SHADER_VERSION, GSConfig.UseDebugDevice)) { Console.Warning("Shader cache failed to open."); } diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp index 441c657c1d..ad3c1558e4 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp @@ -128,8 +128,7 @@ bool GSDevice12::Create(HostDisplay* display) if (!GSConfig.DisableShaderCache) { - if (!m_shader_cache.Open(StringUtil::wxStringToUTF8String(EmuFolders::Cache.ToString()), - g_d3d12_context->GetFeatureLevel(), SHADER_VERSION, GSConfig.UseDebugDevice)) + if (!m_shader_cache.Open(EmuFolders::Cache, g_d3d12_context->GetFeatureLevel(), SHADER_VERSION, GSConfig.UseDebugDevice)) { Console.Warning("Shader cache failed to open."); } diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index b9ec7591d3..e02bc845a9 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -18,6 +18,7 @@ #include "GSTextureReplacements.h" #include "GS/GSGL.h" #include "Host.h" +#include "common/StringUtil.h" GSRendererHW::GSRendererHW() : GSRenderer() @@ -299,7 +300,7 @@ GSTexture* GSRendererHW::GetOutput(int i, int& y_offset) { if (s_savef && s_n >= s_saven) { - t->Save(m_dump_root + format("%05d_f%lld_fr%d_%05x_%s.bmp", s_n, g_perfmon.GetFrame(), i, (int)TEX0.TBP0, psm_str(TEX0.PSM))); + t->Save(m_dump_root + StringUtil::StdStringFromFormat("%05d_f%lld_fr%d_%05x_%s.bmp", s_n, g_perfmon.GetFrame(), i, (int)TEX0.TBP0, psm_str(TEX0.PSM))); } } #endif @@ -322,7 +323,7 @@ GSTexture* GSRendererHW::GetFeedbackOutput() #ifdef ENABLE_OGL_DEBUG if (s_dump && s_savef && s_n >= s_saven) - t->Save(m_dump_root + format("%05d_f%lld_fr%d_%05x_%s.bmp", s_n, g_perfmon.GetFrame(), 3, (int)TEX0.TBP0, psm_str(TEX0.PSM))); + t->Save(m_dump_root + StringUtil::StdStringFromFormat("%05d_f%lld_fr%d_%05x_%s.bmp", s_n, g_perfmon.GetFrame(), 3, (int)TEX0.TBP0, psm_str(TEX0.PSM))); #endif return t; @@ -1215,13 +1216,13 @@ void GSRendererHW::Draw() std::string s; // Dump Register state - s = format("%05d_context.txt", s_n); + s = StringUtil::StdStringFromFormat("%05d_context.txt", s_n); m_env.Dump(m_dump_root + s); m_context->Dump(m_dump_root + s); // Dump vertices - s = format("%05d_vertex.txt", s_n); + s = StringUtil::StdStringFromFormat("%05d_vertex.txt", s_n); DumpVertices(m_dump_root + s); } if (IsBadFrame()) @@ -1633,7 +1634,7 @@ void GSRendererHW::Draw() if (s_savet && s_n >= s_saven && m_src) { - s = format("%05d_f%lld_itex_%05x_%s_%d%d_%02x_%02x_%02x_%02x.dds", + s = StringUtil::StdStringFromFormat("%05d_f%lld_itex_%05x_%s_%d%d_%02x_%02x_%02x_%02x.dds", s_n, frame, (int)context->TEX0.TBP0, psm_str(context->TEX0.PSM), (int)context->CLAMP.WMS, (int)context->CLAMP.WMT, (int)context->CLAMP.MINU, (int)context->CLAMP.MAXU, @@ -1643,7 +1644,7 @@ void GSRendererHW::Draw() if (m_src->m_palette) { - s = format("%05d_f%lld_itpx_%05x_%s.dds", s_n, frame, context->TEX0.CBP, psm_str(context->TEX0.CPSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_itpx_%05x_%s.dds", s_n, frame, context->TEX0.CBP, psm_str(context->TEX0.CPSM)); m_src->m_palette->Save(m_dump_root + s); } @@ -1651,7 +1652,7 @@ void GSRendererHW::Draw() if (s_save && s_n >= s_saven) { - s = format("%05d_f%lld_rt0_%05x_%s.bmp", s_n, frame, context->FRAME.Block(), psm_str(context->FRAME.PSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_rt0_%05x_%s.bmp", s_n, frame, context->FRAME.Block(), psm_str(context->FRAME.PSM)); if (rt_tex) rt_tex->Save(m_dump_root + s); @@ -1659,7 +1660,7 @@ void GSRendererHW::Draw() if (s_savez && s_n >= s_saven) { - s = format("%05d_f%lld_rz0_%05x_%s.bmp", s_n, frame, context->ZBUF.Block(), psm_str(context->ZBUF.PSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_rz0_%05x_%s.bmp", s_n, frame, context->ZBUF.Block(), psm_str(context->ZBUF.PSM)); if (ds_tex) ds_tex->Save(m_dump_root + s); @@ -1796,7 +1797,7 @@ void GSRendererHW::Draw() if (s_save && s_n >= s_saven) { - s = format("%05d_f%lld_rt1_%05x_%s.bmp", s_n, frame, context->FRAME.Block(), psm_str(context->FRAME.PSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_rt1_%05x_%s.bmp", s_n, frame, context->FRAME.Block(), psm_str(context->FRAME.PSM)); if (rt_tex) rt_tex->Save(m_dump_root + s); @@ -1804,7 +1805,7 @@ void GSRendererHW::Draw() if (s_savez && s_n >= s_saven) { - s = format("%05d_f%lld_rz1_%05x_%s.bmp", s_n, frame, context->ZBUF.Block(), psm_str(context->ZBUF.PSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_rz1_%05x_%s.bmp", s_n, frame, context->ZBUF.Block(), psm_str(context->ZBUF.PSM)); if (ds_tex) ds_tex->Save(m_dump_root + s); diff --git a/pcsx2/GS/Renderers/HW/GSTextureReplacementLoaders.cpp b/pcsx2/GS/Renderers/HW/GSTextureReplacementLoaders.cpp index 3fc9625dcf..b8614c09e1 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureReplacementLoaders.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureReplacementLoaders.cpp @@ -17,6 +17,7 @@ #include "common/Align.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" #include "common/ScopedGuard.h" @@ -42,7 +43,7 @@ static constexpr LoaderDefinition s_loaders[] = { GSTextureReplacements::ReplacementTextureLoader GSTextureReplacements::GetLoader(const std::string_view& filename) { - const std::string_view extension(FileSystem::GetExtension(filename)); + const std::string_view extension(Path::GetExtension(filename)); if (extension.empty()) return nullptr; diff --git a/pcsx2/GS/Renderers/HW/GSTextureReplacements.cpp b/pcsx2/GS/Renderers/HW/GSTextureReplacements.cpp index 908b4d5f9d..dfa4da3277 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureReplacements.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureReplacements.cpp @@ -209,7 +209,7 @@ std::optional GSTextureReplacements::ParseReplacementName(const std std::string GSTextureReplacements::GetGameTextureDirectory() { - return Path::CombineStdString(EmuFolders::Textures, s_current_serial); + return Path::Combine(EmuFolders::Textures, s_current_serial); } std::string GSTextureReplacements::GetDumpFilename(const TextureName& name, u32 level) @@ -223,15 +223,15 @@ std::string GSTextureReplacements::GetDumpFilename(const TextureName& name, u32 { // create both dumps and replacements if (!FileSystem::CreateDirectoryPath(game_dir.c_str(), false) || - !FileSystem::EnsureDirectoryExists(Path::CombineStdString(game_dir, "dumps").c_str(), false) || - !FileSystem::EnsureDirectoryExists(Path::CombineStdString(game_dir, "replacements").c_str(), false)) + !FileSystem::EnsureDirectoryExists(Path::Combine(game_dir, "dumps").c_str(), false) || + !FileSystem::EnsureDirectoryExists(Path::Combine(game_dir, "replacements").c_str(), false)) { // if it fails to create, we're not going to be able to use it anyway return ret; } } - const std::string game_subdir(Path::CombineStdString(game_dir, TEXTURE_DUMP_SUBDIRECTORY_NAME)); + const std::string game_subdir(Path::Combine(game_dir, TEXTURE_DUMP_SUBDIRECTORY_NAME)); if (name.HasPalette()) { @@ -239,7 +239,7 @@ std::string GSTextureReplacements::GetDumpFilename(const TextureName& name, u32 (level > 0) ? StringUtil::StdStringFromFormat(TEXTURE_FILENAME_CLUT_FORMAT_STRING "-mip%u.png", name.TEX0Hash, name.CLUTHash, name.bits, level) : StringUtil::StdStringFromFormat(TEXTURE_FILENAME_CLUT_FORMAT_STRING ".png", name.TEX0Hash, name.CLUTHash, name.bits)); - ret = Path::CombineStdString(game_subdir, filename); + ret = Path::Combine(game_subdir, filename); } else { @@ -247,7 +247,7 @@ std::string GSTextureReplacements::GetDumpFilename(const TextureName& name, u32 (level > 0) ? StringUtil::StdStringFromFormat(TEXTURE_FILENAME_FORMAT_STRING "-mip%u.png", name.TEX0Hash, name.bits, level) : StringUtil::StdStringFromFormat(TEXTURE_FILENAME_FORMAT_STRING ".png", name.TEX0Hash, name.bits)); - ret = Path::CombineStdString(game_subdir, filename); + ret = Path::Combine(game_subdir, filename); } return ret; @@ -306,7 +306,7 @@ void GSTextureReplacements::ReloadReplacementMap() if (s_current_serial.empty() || !GSConfig.LoadTextureReplacements) return; - const std::string replacement_dir(Path::CombineStdString(GetGameTextureDirectory(), TEXTURE_REPLACEMENT_SUBDIRECTORY_NAME)); + const std::string replacement_dir(Path::Combine(GetGameTextureDirectory(), TEXTURE_REPLACEMENT_SUBDIRECTORY_NAME)); FileSystem::FindResultsArray files; if (!FileSystem::FindFiles(replacement_dir.c_str(), "*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RECURSIVE, &files)) @@ -316,7 +316,7 @@ void GSTextureReplacements::ReloadReplacementMap() for (FILESYSTEM_FIND_DATA& fd : files) { // file format we can handle? - filename = FileSystem::GetFileNameFromPath(fd.FileName); + filename = Path::GetFileName(fd.FileName); if (!GetLoader(filename)) continue; @@ -595,7 +595,7 @@ void GSTextureReplacements::DumpTexture(const GSTextureCache::HashCacheKey& hash if (filename.empty() || FileSystem::FileExists(filename.c_str())) return; - const std::string_view title(FileSystem::GetFileTitleFromPath(filename)); + const std::string_view title(Path::GetFileTitle(filename)); DevCon.WriteLn("Dumping %ux%u texture '%.*s'.", name.Width(), name.Height(), static_cast(title.size()), title.data()); // compute width/height diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index b8f5f38ebf..ca0a07ff40 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -206,7 +206,7 @@ bool GSDeviceOGL::Create(HostDisplay* display) if (!theApp.GetConfigB("disable_shader_cache")) { - if (!m_shader_cache.Open(false, StringUtil::wxStringToUTF8String(EmuFolders::Cache.ToString()), SHADER_VERSION)) + if (!m_shader_cache.Open(false, EmuFolders::Cache, SHADER_VERSION)) Console.Warning("Shader cache failed to open."); } else @@ -369,7 +369,7 @@ bool GSDeviceOGL::Create(HostDisplay* display) { const char* name = shaderName(static_cast(i)); const std::string macro_sel = (static_cast(i) == ShaderConvert::RGBA_TO_8I) ? - format("#define PS_SCALE_FACTOR %d\n", GSConfig.UpscaleMultiplier) : + StringUtil::StdStringFromFormat("#define PS_SCALE_FACTOR %d\n", GSConfig.UpscaleMultiplier) : std::string(); const std::string ps(GetShaderSource(name, GL_FRAGMENT_SHADER, m_shader_common_header, *shader, macro_sel)); if (!m_shader_cache.GetProgram(&m_convert.ps[i], m_convert.vs, {}, ps)) @@ -408,7 +408,7 @@ bool GSDeviceOGL::Create(HostDisplay* display) for (size_t i = 0; i < std::size(m_merge_obj.ps); i++) { - const std::string ps(GetShaderSource(format("ps_main%d", i), GL_FRAGMENT_SHADER, m_shader_common_header, *shader, {})); + const std::string ps(GetShaderSource(StringUtil::StdStringFromFormat("ps_main%d", i), GL_FRAGMENT_SHADER, m_shader_common_header, *shader, {})); if (!m_shader_cache.GetProgram(&m_merge_obj.ps[i], m_convert.vs, {}, ps)) return false; m_merge_obj.ps[i].SetFormattedName("Merge pipe %zu", i); @@ -431,7 +431,7 @@ bool GSDeviceOGL::Create(HostDisplay* display) for (size_t i = 0; i < std::size(m_interlace.ps); i++) { - const std::string ps(GetShaderSource(format("ps_main%d", i), GL_FRAGMENT_SHADER, m_shader_common_header, *shader, {})); + const std::string ps(GetShaderSource(StringUtil::StdStringFromFormat("ps_main%d", i), GL_FRAGMENT_SHADER, m_shader_common_header, *shader, {})); if (!m_shader_cache.GetProgram(&m_interlace.ps[i], m_convert.vs, {}, ps)) return false; m_interlace.ps[i].SetFormattedName("Merge pipe %zu", i); @@ -1020,11 +1020,11 @@ std::string GSDeviceOGL::GetVSSource(VSSelector sel) Console.WriteLn("Compiling new vertex shader with selector 0x%" PRIX64, sel.key); #endif - std::string macro = format("#define VS_INT_FST %d\n", sel.int_fst) - + format("#define VS_IIP %d\n", sel.iip) - + format("#define VS_POINT_SIZE %d\n", sel.point_size); + std::string macro = StringUtil::StdStringFromFormat("#define VS_INT_FST %d\n", sel.int_fst) + + StringUtil::StdStringFromFormat("#define VS_IIP %d\n", sel.iip) + + StringUtil::StdStringFromFormat("#define VS_POINT_SIZE %d\n", sel.point_size); if (sel.point_size) - macro += format("#define VS_POINT_SIZE_VALUE %d\n", GSConfig.UpscaleMultiplier); + macro += StringUtil::StdStringFromFormat("#define VS_POINT_SIZE_VALUE %d\n", GSConfig.UpscaleMultiplier); std::string src = GenGlslHeader("vs_main", GL_VERTEX_SHADER, macro); src += m_shader_common_header; @@ -1038,9 +1038,9 @@ std::string GSDeviceOGL::GetGSSource(GSSelector sel) Console.WriteLn("Compiling new geometry shader with selector 0x%" PRIX64, sel.key); #endif - std::string macro = format("#define GS_POINT %d\n", sel.point) - + format("#define GS_LINE %d\n", sel.line) - + format("#define GS_IIP %d\n", sel.iip); + std::string macro = StringUtil::StdStringFromFormat("#define GS_POINT %d\n", sel.point) + + StringUtil::StdStringFromFormat("#define GS_LINE %d\n", sel.line) + + StringUtil::StdStringFromFormat("#define GS_IIP %d\n", sel.iip); std::string src = GenGlslHeader("gs_main", GL_GEOMETRY_SHADER, macro); src += m_shader_common_header; @@ -1054,52 +1054,52 @@ std::string GSDeviceOGL::GetPSSource(const PSSelector& sel) Console.WriteLn("Compiling new pixel shader with selector 0x%" PRIX64 "%08X", sel.key_hi, sel.key_lo); #endif - std::string macro = format("#define PS_FST %d\n", sel.fst) - + format("#define PS_WMS %d\n", sel.wms) - + format("#define PS_WMT %d\n", sel.wmt) - + format("#define PS_AEM_FMT %d\n", sel.aem_fmt) - + format("#define PS_PAL_FMT %d\n", sel.pal_fmt) - + format("#define PS_DFMT %d\n", sel.dfmt) - + format("#define PS_DEPTH_FMT %d\n", sel.depth_fmt) - + format("#define PS_CHANNEL_FETCH %d\n", sel.channel) - + format("#define PS_URBAN_CHAOS_HLE %d\n", sel.urban_chaos_hle) - + format("#define PS_TALES_OF_ABYSS_HLE %d\n", sel.tales_of_abyss_hle) - + format("#define PS_TEX_IS_FB %d\n", sel.tex_is_fb) - + format("#define PS_INVALID_TEX0 %d\n", sel.invalid_tex0) - + format("#define PS_AEM %d\n", sel.aem) - + format("#define PS_TFX %d\n", sel.tfx) - + format("#define PS_TCC %d\n", sel.tcc) - + format("#define PS_ATST %d\n", sel.atst) - + format("#define PS_FOG %d\n", sel.fog) - + format("#define PS_CLR_HW %d\n", sel.clr_hw) - + format("#define PS_FBA %d\n", sel.fba) - + format("#define PS_LTF %d\n", sel.ltf) - + format("#define PS_AUTOMATIC_LOD %d\n", sel.automatic_lod) - + format("#define PS_MANUAL_LOD %d\n", sel.manual_lod) - + format("#define PS_COLCLIP %d\n", sel.colclip) - + format("#define PS_DATE %d\n", sel.date) - + format("#define PS_TCOFFSETHACK %d\n", sel.tcoffsethack) - + format("#define PS_POINT_SAMPLER %d\n", sel.point_sampler) - + format("#define PS_BLEND_A %d\n", sel.blend_a) - + format("#define PS_BLEND_B %d\n", sel.blend_b) - + format("#define PS_BLEND_C %d\n", sel.blend_c) - + format("#define PS_BLEND_D %d\n", sel.blend_d) - + format("#define PS_IIP %d\n", sel.iip) - + format("#define PS_SHUFFLE %d\n", sel.shuffle) - + format("#define PS_READ_BA %d\n", sel.read_ba) - + format("#define PS_WRITE_RG %d\n", sel.write_rg) - + format("#define PS_FBMASK %d\n", sel.fbmask) - + format("#define PS_HDR %d\n", sel.hdr) - + format("#define PS_DITHER %d\n", sel.dither) - + format("#define PS_ZCLAMP %d\n", sel.zclamp) - + format("#define PS_BLEND_MIX %d\n", sel.blend_mix) - + format("#define PS_PABE %d\n", sel.pabe) - + format("#define PS_SCANMSK %d\n", sel.scanmsk) - + format("#define PS_SCALE_FACTOR %d\n", GSConfig.UpscaleMultiplier) - + format("#define PS_NO_COLOR %d\n", sel.no_color) - + format("#define PS_NO_COLOR1 %d\n", sel.no_color1) - + format("#define PS_NO_ABLEND %d\n", sel.no_ablend) - + format("#define PS_ONLY_ALPHA %d\n", sel.only_alpha) + std::string macro = StringUtil::StdStringFromFormat("#define PS_FST %d\n", sel.fst) + + StringUtil::StdStringFromFormat("#define PS_WMS %d\n", sel.wms) + + StringUtil::StdStringFromFormat("#define PS_WMT %d\n", sel.wmt) + + StringUtil::StdStringFromFormat("#define PS_AEM_FMT %d\n", sel.aem_fmt) + + StringUtil::StdStringFromFormat("#define PS_PAL_FMT %d\n", sel.pal_fmt) + + StringUtil::StdStringFromFormat("#define PS_DFMT %d\n", sel.dfmt) + + StringUtil::StdStringFromFormat("#define PS_DEPTH_FMT %d\n", sel.depth_fmt) + + StringUtil::StdStringFromFormat("#define PS_CHANNEL_FETCH %d\n", sel.channel) + + StringUtil::StdStringFromFormat("#define PS_URBAN_CHAOS_HLE %d\n", sel.urban_chaos_hle) + + StringUtil::StdStringFromFormat("#define PS_TALES_OF_ABYSS_HLE %d\n", sel.tales_of_abyss_hle) + + StringUtil::StdStringFromFormat("#define PS_TEX_IS_FB %d\n", sel.tex_is_fb) + + StringUtil::StdStringFromFormat("#define PS_INVALID_TEX0 %d\n", sel.invalid_tex0) + + StringUtil::StdStringFromFormat("#define PS_AEM %d\n", sel.aem) + + StringUtil::StdStringFromFormat("#define PS_TFX %d\n", sel.tfx) + + StringUtil::StdStringFromFormat("#define PS_TCC %d\n", sel.tcc) + + StringUtil::StdStringFromFormat("#define PS_ATST %d\n", sel.atst) + + StringUtil::StdStringFromFormat("#define PS_FOG %d\n", sel.fog) + + StringUtil::StdStringFromFormat("#define PS_CLR_HW %d\n", sel.clr_hw) + + StringUtil::StdStringFromFormat("#define PS_FBA %d\n", sel.fba) + + StringUtil::StdStringFromFormat("#define PS_LTF %d\n", sel.ltf) + + StringUtil::StdStringFromFormat("#define PS_AUTOMATIC_LOD %d\n", sel.automatic_lod) + + StringUtil::StdStringFromFormat("#define PS_MANUAL_LOD %d\n", sel.manual_lod) + + StringUtil::StdStringFromFormat("#define PS_COLCLIP %d\n", sel.colclip) + + StringUtil::StdStringFromFormat("#define PS_DATE %d\n", sel.date) + + StringUtil::StdStringFromFormat("#define PS_TCOFFSETHACK %d\n", sel.tcoffsethack) + + StringUtil::StdStringFromFormat("#define PS_POINT_SAMPLER %d\n", sel.point_sampler) + + StringUtil::StdStringFromFormat("#define PS_BLEND_A %d\n", sel.blend_a) + + StringUtil::StdStringFromFormat("#define PS_BLEND_B %d\n", sel.blend_b) + + StringUtil::StdStringFromFormat("#define PS_BLEND_C %d\n", sel.blend_c) + + StringUtil::StdStringFromFormat("#define PS_BLEND_D %d\n", sel.blend_d) + + StringUtil::StdStringFromFormat("#define PS_IIP %d\n", sel.iip) + + StringUtil::StdStringFromFormat("#define PS_SHUFFLE %d\n", sel.shuffle) + + StringUtil::StdStringFromFormat("#define PS_READ_BA %d\n", sel.read_ba) + + StringUtil::StdStringFromFormat("#define PS_WRITE_RG %d\n", sel.write_rg) + + StringUtil::StdStringFromFormat("#define PS_FBMASK %d\n", sel.fbmask) + + StringUtil::StdStringFromFormat("#define PS_HDR %d\n", sel.hdr) + + StringUtil::StdStringFromFormat("#define PS_DITHER %d\n", sel.dither) + + StringUtil::StdStringFromFormat("#define PS_ZCLAMP %d\n", sel.zclamp) + + StringUtil::StdStringFromFormat("#define PS_BLEND_MIX %d\n", sel.blend_mix) + + StringUtil::StdStringFromFormat("#define PS_PABE %d\n", sel.pabe) + + StringUtil::StdStringFromFormat("#define PS_SCANMSK %d\n", sel.scanmsk) + + StringUtil::StdStringFromFormat("#define PS_SCALE_FACTOR %d\n", GSConfig.UpscaleMultiplier) + + StringUtil::StdStringFromFormat("#define PS_NO_COLOR %d\n", sel.no_color) + + StringUtil::StdStringFromFormat("#define PS_NO_COLOR1 %d\n", sel.no_color1) + + StringUtil::StdStringFromFormat("#define PS_NO_ABLEND %d\n", sel.no_ablend) + + StringUtil::StdStringFromFormat("#define PS_ONLY_ALPHA %d\n", sel.only_alpha) ; std::string src = GenGlslHeader("ps_main", GL_FRAGMENT_SHADER, macro); @@ -1122,7 +1122,7 @@ bool GSDeviceOGL::DownloadTexture(GSTexture* src, const GSVector4i& rect, GSText // Copy a sub part of texture (same as below but force a conversion) void GSDeviceOGL::BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2i& dsize, bool at_origin, bool linear) { - GL_PUSH(format("CopyRectConv from %d", static_cast(sTex)->GetID()).c_str()); + GL_PUSH(StringUtil::StdStringFromFormat("CopyRectConv from %d", static_cast(sTex)->GetID()).c_str()); g_perfmon.Put(GSPerfMon::TextureCopies, 1); // NOTE: This previously used glCopyTextureSubImage2D(), but this appears to leak memory in diff --git a/pcsx2/GS/Renderers/SW/GSRendererSW.cpp b/pcsx2/GS/Renderers/SW/GSRendererSW.cpp index 44dd4f3ce6..2b19419517 100644 --- a/pcsx2/GS/Renderers/SW/GSRendererSW.cpp +++ b/pcsx2/GS/Renderers/SW/GSRendererSW.cpp @@ -16,6 +16,7 @@ #include "PrecompiledHeader.h" #include "GSRendererSW.h" #include "GS/GSGL.h" +#include "common/StringUtil.h" #define LOG 0 @@ -169,7 +170,7 @@ GSTexture* GSRendererSW::GetOutput(int i, int& y_offset) { if (s_savef && s_n >= s_saven) { - m_texture[i]->Save(m_dump_root + format("%05d_f%lld_fr%d_%05x_%s.bmp", s_n, g_perfmon.GetFrame(), i, (int)DISPFB.Block(), psm_str(DISPFB.PSM))); + m_texture[i]->Save(m_dump_root + StringUtil::StdStringFromFormat("%05d_f%lld_fr%d_%05x_%s.bmp", s_n, g_perfmon.GetFrame(), i, (int)DISPFB.Block(), psm_str(DISPFB.PSM))); } } } @@ -339,13 +340,13 @@ void GSRendererSW::Draw() if (s_n >= s_saven) { // Dump Register state - s = format("%05d_context.txt", s_n); + s = StringUtil::StdStringFromFormat("%05d_context.txt", s_n); m_env.Dump(m_dump_root + s); m_context->Dump(m_dump_root + s); // Dump vertices - s = format("%05d_vertex.txt", s_n); + s = StringUtil::StdStringFromFormat("%05d_vertex.txt", s_n); DumpVertices(m_dump_root + s); } } @@ -471,11 +472,11 @@ void GSRendererSW::Draw() if (texture_shuffle) { // Dump the RT in 32 bits format. It helps to debug texture shuffle effect - s = format("%05d_f%lld_itexraw_%05x_32bits.bmp", s_n, frame, (int)m_context->TEX0.TBP0); + s = StringUtil::StdStringFromFormat("%05d_f%lld_itexraw_%05x_32bits.bmp", s_n, frame, (int)m_context->TEX0.TBP0); m_mem.SaveBMP(m_dump_root + s, m_context->TEX0.TBP0, m_context->TEX0.TBW, 0, 1 << m_context->TEX0.TW, 1 << m_context->TEX0.TH); } - s = format("%05d_f%lld_itexraw_%05x_%s.bmp", s_n, frame, (int)m_context->TEX0.TBP0, psm_str(m_context->TEX0.PSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_itexraw_%05x_%s.bmp", s_n, frame, (int)m_context->TEX0.TBP0, psm_str(m_context->TEX0.PSM)); m_mem.SaveBMP(m_dump_root + s, m_context->TEX0.TBP0, m_context->TEX0.TBW, m_context->TEX0.PSM, 1 << m_context->TEX0.TW, 1 << m_context->TEX0.TH); } @@ -485,17 +486,17 @@ void GSRendererSW::Draw() if (texture_shuffle) { // Dump the RT in 32 bits format. It helps to debug texture shuffle effect - s = format("%05d_f%lld_rt0_%05x_32bits.bmp", s_n, frame, m_context->FRAME.Block()); + s = StringUtil::StdStringFromFormat("%05d_f%lld_rt0_%05x_32bits.bmp", s_n, frame, m_context->FRAME.Block()); m_mem.SaveBMP(m_dump_root + s, m_context->FRAME.Block(), m_context->FRAME.FBW, 0, GetFrameRect().width(), 512); } - s = format("%05d_f%lld_rt0_%05x_%s.bmp", s_n, frame, m_context->FRAME.Block(), psm_str(m_context->FRAME.PSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_rt0_%05x_%s.bmp", s_n, frame, m_context->FRAME.Block(), psm_str(m_context->FRAME.PSM)); m_mem.SaveBMP(m_dump_root + s, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameRect().width(), 512); } if (s_savez && s_n >= s_saven) { - s = format("%05d_f%lld_rz0_%05x_%s.bmp", s_n, frame, m_context->ZBUF.Block(), psm_str(m_context->ZBUF.PSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_rz0_%05x_%s.bmp", s_n, frame, m_context->ZBUF.Block(), psm_str(m_context->ZBUF.PSM)); m_mem.SaveBMP(m_dump_root + s, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameRect().width(), 512); } @@ -509,17 +510,17 @@ void GSRendererSW::Draw() if (texture_shuffle) { // Dump the RT in 32 bits format. It helps to debug texture shuffle effect - s = format("%05d_f%lld_rt1_%05x_32bits.bmp", s_n, frame, m_context->FRAME.Block()); + s = StringUtil::StdStringFromFormat("%05d_f%lld_rt1_%05x_32bits.bmp", s_n, frame, m_context->FRAME.Block()); m_mem.SaveBMP(m_dump_root + s, m_context->FRAME.Block(), m_context->FRAME.FBW, 0, GetFrameRect().width(), 512); } - s = format("%05d_f%lld_rt1_%05x_%s.bmp", s_n, frame, m_context->FRAME.Block(), psm_str(m_context->FRAME.PSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_rt1_%05x_%s.bmp", s_n, frame, m_context->FRAME.Block(), psm_str(m_context->FRAME.PSM)); m_mem.SaveBMP(m_dump_root + s, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameRect().width(), 512); } if (s_savez && s_n >= s_saven) { - s = format("%05d_f%lld_rz1_%05x_%s.bmp", s_n, frame, m_context->ZBUF.Block(), psm_str(m_context->ZBUF.PSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_rz1_%05x_%s.bmp", s_n, frame, m_context->ZBUF.Block(), psm_str(m_context->ZBUF.PSM)); m_mem.SaveBMP(m_dump_root + s, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameRect().width(), 512); } @@ -607,14 +608,14 @@ void GSRendererSW::Sync(int reason) if (s_save) { - s = format("%05d_f%lld_rt1_%05x_%s.bmp", s_n, g_perfmon.GetFrame(), m_context->FRAME.Block(), psm_str(m_context->FRAME.PSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_rt1_%05x_%s.bmp", s_n, g_perfmon.GetFrame(), m_context->FRAME.Block(), psm_str(m_context->FRAME.PSM)); m_mem.SaveBMP(m_dump_root + s, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameRect().width(), 512); } if (s_savez) { - s = format("%05d_f%lld_zb1_%05x_%s.bmp", s_n, g_perfmon.GetFrame(), m_context->ZBUF.Block(), psm_str(m_context->ZBUF.PSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_zb1_%05x_%s.bmp", s_n, g_perfmon.GetFrame(), m_context->ZBUF.Block(), psm_str(m_context->ZBUF.PSM)); m_mem.SaveBMP(m_dump_root + s, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameRect().width(), 512); } @@ -1571,7 +1572,7 @@ void GSRendererSW::SharedData::UpdateSource() { const GIFRegTEX0& TEX0 = g_gs_renderer->GetTex0Layer(i); - s = format("%05d_f%lld_itex%d_%05x_%s.bmp", g_gs_renderer->s_n, frame, i, TEX0.TBP0, psm_str(TEX0.PSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_itex%d_%05x_%s.bmp", g_gs_renderer->s_n, frame, i, TEX0.TBP0, psm_str(TEX0.PSM)); m_tex[i].t->Save(root_sw + s); } @@ -1582,7 +1583,7 @@ void GSRendererSW::SharedData::UpdateSource() t->Update(GSVector4i(0, 0, 256, 1), global.clut, sizeof(u32) * 256); - s = format("%05d_f%lld_itexp_%05x_%s.bmp", g_gs_renderer->s_n, frame, (int)g_gs_renderer->m_context->TEX0.CBP, psm_str(g_gs_renderer->m_context->TEX0.CPSM)); + s = StringUtil::StdStringFromFormat("%05d_f%lld_itexp_%05x_%s.bmp", g_gs_renderer->s_n, frame, (int)g_gs_renderer->m_context->TEX0.CBP, psm_str(g_gs_renderer->m_context->TEX0.CPSM)); t->Save(root_sw + s); diff --git a/pcsx2/GS/Window/GSCaptureDlg.cpp b/pcsx2/GS/Window/GSCaptureDlg.cpp index d4b3f07c79..e5411201c8 100644 --- a/pcsx2/GS/Window/GSCaptureDlg.cpp +++ b/pcsx2/GS/Window/GSCaptureDlg.cpp @@ -17,6 +17,7 @@ #include "GS.h" #include "GSCaptureDlg.h" #include "GS/GSExtra.h" +#include "common/StringUtil.h" #include // Ideally this belongs in WIL, but CAUUID is used by a *single* COM function in WinAPI. @@ -57,7 +58,7 @@ GSCaptureDlg::GSCaptureDlg() { m_width = theApp.GetConfigI("CaptureWidth"); m_height = theApp.GetConfigI("CaptureHeight"); - m_filename = convert_utf8_to_utf16(theApp.GetConfigS("CaptureFileName")); + m_filename = StringUtil::UTF8StringToWideString(theApp.GetConfigS("CaptureFileName")); } int GSCaptureDlg::GetSelCodec(Codec& c) @@ -118,7 +119,7 @@ void GSCaptureDlg::OnInit() m_codecs.clear(); - const std::wstring selected = convert_utf8_to_utf16(theApp.GetConfigS("CaptureVideoCodecDisplayName")); + const std::wstring selected = StringUtil::UTF8StringToWideString(theApp.GetConfigS("CaptureVideoCodecDisplayName")); ComboBoxAppend(IDC_CODECS, "Uncompressed", 0, true); ComboBoxAppend(IDC_COLORSPACE, "YUY2", 0, true); @@ -244,10 +245,10 @@ bool GSCaptureDlg::OnCommand(HWND hWnd, UINT id, UINT code) theApp.SetConfig("CaptureWidth", m_width); theApp.SetConfig("CaptureHeight", m_height); - theApp.SetConfig("CaptureFileName", convert_utf16_to_utf8(m_filename).c_str()); + theApp.SetConfig("CaptureFileName", StringUtil::WideStringToUTF8String(m_filename).c_str()); if (ris != 2) - theApp.SetConfig("CaptureVideoCodecDisplayName", convert_utf16_to_utf8(c.DisplayName).c_str()); + theApp.SetConfig("CaptureVideoCodecDisplayName", StringUtil::WideStringToUTF8String(c.DisplayName).c_str()); else theApp.SetConfig("CaptureVideoCodecDisplayName", ""); break; diff --git a/pcsx2/GS/Window/GSDialog.h b/pcsx2/GS/Window/GSDialog.h index a1537f6ccc..98056fbd04 100644 --- a/pcsx2/GS/Window/GSDialog.h +++ b/pcsx2/GS/Window/GSDialog.h @@ -16,6 +16,7 @@ #pragma once #include "GSSetting.h" +#include "common/RedtapeWindows.h" class GSDialog { diff --git a/pcsx2/IPU/IPU.cpp b/pcsx2/IPU/IPU.cpp index 8ca323b5d7..6d39f09a19 100644 --- a/pcsx2/IPU/IPU.cpp +++ b/pcsx2/IPU/IPU.cpp @@ -653,7 +653,7 @@ static __ri bool ipuPACK(tIPU_CMD_CSC csc) ipu_cmd.pos[1] = 0; } - return TRUE; + return true; } static void ipuSETTH(u32 val) diff --git a/pcsx2/IopBios.cpp b/pcsx2/IopBios.cpp index a16f9c9ff1..2fa9e55f52 100644 --- a/pcsx2/IopBios.cpp +++ b/pcsx2/IopBios.cpp @@ -27,6 +27,14 @@ #include "ghc/filesystem.h" #include "common/FileSystem.h" +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + #if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) #define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) #endif diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 7e7b23b8bb..933f03236f 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -17,7 +17,6 @@ #include "Common.h" #include -#include #include "common/ScopedGuard.h" #include "common/StringUtil.h" diff --git a/pcsx2/Memory.cpp b/pcsx2/Memory.cpp index 9316740d93..670f411151 100644 --- a/pcsx2/Memory.cpp +++ b/pcsx2/Memory.cpp @@ -35,7 +35,6 @@ BIOS */ #include "PrecompiledHeader.h" -#include #include "IopHw.h" #include "GS.h" diff --git a/pcsx2/MemoryCardFile.cpp b/pcsx2/MemoryCardFile.cpp index cac703428f..91fc9a1d4a 100644 --- a/pcsx2/MemoryCardFile.cpp +++ b/pcsx2/MemoryCardFile.cpp @@ -16,10 +16,8 @@ #include "PrecompiledHeader.h" #include "common/FileSystem.h" #include "common/SafeArray.inl" +#include "common/Path.h" #include "common/StringUtil.h" -#include -#include -#include #include #include @@ -35,7 +33,6 @@ #include "fmt/core.h" -#include #include static const int MCD_SIZE = 1024 * 8 * 16; // Legacy PSX card default size @@ -91,67 +88,73 @@ static u32 CalculateECC(u8* buf) return column_parity | (line_parity_0 << 8) | (line_parity_1 << 16); } -static bool ConvertNoECCtoRAW(wxString file_in, wxString file_out) +static bool ConvertNoECCtoRAW(const char* file_in, const char* file_out) { - bool result = false; - wxFFile fin(file_in, "rb"); + auto fin = FileSystem::OpenManagedCFile(file_in, "rb"); + if (!fin) + return false; - if (fin.IsOpened()) + auto fout = FileSystem::OpenManagedCFile(file_out, "wb"); + if (!fout) + return false; + + const s64 size = FileSystem::FSize64(fin.get()); + u8 buffer[512]; + + for (s64 i = 0; i < (size / 512); i++) { - wxFFile fout(file_out, "wb"); - - if (fout.IsOpened()) + if (std::fread(buffer, sizeof(buffer), 1, fin.get()) != 1 || + std::fwrite(buffer, sizeof(buffer), 1, fout.get()) != 1) { - u8 buffer[512]; - size_t size = fin.Length(); - - for (size_t i = 0; i < (size / 512); i++) - { - fin.Read(buffer, 512); - fout.Write(buffer, 512); - - for (int j = 0; j < 4; j++) - { - u32 checksum = CalculateECC(&buffer[j * 128]); - fout.Write(&checksum, 3); - } - - fout.Write("\0\0\0\0", 4); - } - - result = true; + return false; } + + for (int j = 0; j < 4; j++) + { + u32 checksum = CalculateECC(&buffer[j * 128]); + if (std::fwrite(&checksum, 3, 1, fout.get()) != 1) + return false; + } + + u32 nullbytes = 0; + if (std::fwrite(&nullbytes, sizeof(nullbytes), 1, fout.get()) != 1) + return false; } - return result; + if (std::fflush(fout.get()) != 0) + return false; + + return true; } -static bool ConvertRAWtoNoECC(wxString file_in, wxString file_out) +static bool ConvertRAWtoNoECC(const char* file_in, const char* file_out) { - bool result = false; - wxFFile fout(file_out, "wb"); + auto fin = FileSystem::OpenManagedCFile(file_in, "rb"); + if (!fin) + return false; - if (fout.IsOpened()) + auto fout = FileSystem::OpenManagedCFile(file_out, "wb"); + if (!fout) + return false; + + const s64 size = FileSystem::FSize64(fin.get()); + u8 buffer[512]; + u8 checksum[16]; + + for (s64 i = 0; i < (size / 528); i++) { - wxFFile fin(file_in, "rb"); - - if (fin.IsOpened()) + if (std::fread(buffer, sizeof(buffer), 1, fin.get()) != 1 || + std::fwrite(buffer, sizeof(buffer), 1, fout.get()) != 1 || + std::fread(checksum, sizeof(checksum), 1, fin.get()) != 1) { - u8 buffer[512]; - size_t size = fin.Length(); - - for (size_t i = 0; i < (size / 528); i++) - { - fin.Read(buffer, 512); - fout.Write(buffer, 512); - fin.Read(buffer, 16); - } - - result = true; + return false; } } - return result; + if (std::fflush(fout.get()) != 0) + return false; + + return true; } // -------------------------------------------------------------------------------------- @@ -162,7 +165,8 @@ static bool ConvertRAWtoNoECC(wxString file_in, wxString file_out) class FileMemoryCard { protected: - wxFFile m_file[8]; + std::FILE* m_file[8]; + std::string m_filenames[8]; u8 m_effeffs[528 * 16]; SafeArray m_currentdata; u64 m_chksum[8]; @@ -188,14 +192,8 @@ public: u64 GetCRC(uint slot); protected: - bool Seek(wxFFile& f, u32 adr); - bool Create(const wxString& mcdFile, uint sizeInMB); - - std::string GetDisabledMessage(uint slot) const - { - return fmt::format("The PS2-slot {} has been automatically disabled. You can correct the problem\nand re-enable it at any time using Config:Memory cards from the main menu.", slot //TODO: translate internal slot index to human-readable slot description - ); - } + bool Seek(std::FILE* f, u32 adr); + bool Create(const char* mcdFile, uint sizeInMB); }; uint FileMcd_GetMtapPort(uint slot) @@ -276,6 +274,8 @@ void FileMemoryCard::Open() { for (int slot = 0; slot < 8; ++slot) { + m_filenames[slot] = {}; + if (FileMcd_IsMultitapSlot(slot)) { if (!EmuConfig.MultitapPort0_Enabled && (FileMcd_GetMtapPort(slot) == 0)) @@ -284,46 +284,43 @@ void FileMemoryCard::Open() continue; } - wxFileName fname(EmuConfig.FullpathToMcd(slot)); - wxString str(fname.GetFullPath()); + std::string fname(EmuConfig.FullpathToMcd(slot)); + std::string_view str(fname); bool cont = false; - if (fname.GetFullName().IsEmpty()) + if (fname.empty()) { - str = L"[empty filename]"; + str = "[empty filename]"; cont = true; } if (!EmuConfig.Mcd[slot].Enabled) { - str = L"[disabled]"; + str = "[disabled]"; cont = true; } if (EmuConfig.Mcd[slot].Type != MemoryCardType::File) { - str = L"[is not memcard file]"; + str = "[is not memcard file]"; cont = true; } - Console.WriteLn(cont ? Color_Gray : Color_Green, "McdSlot %u [File]: %s", slot, StringUtil::wxStringToUTF8String(str).c_str()); + Console.WriteLn(cont ? Color_Gray : Color_Green, "McdSlot %u [File]: %.*s", slot, + static_cast(str.size()), str.data()); if (cont) continue; - const wxULongLong fsz = fname.GetSize(); - if ((fsz == 0) || (fsz == wxInvalidSize)) + if (FileSystem::GetPathFileSize(fname.c_str()) <= 0) { // FIXME : Ideally this should prompt the user for the size of the // memory card file they would like to create, instead of trying to // create one automatically. - if (!Create(str, 8)) + if (!Create(fname.c_str(), 8)) { -#ifndef PCSX2_CORE - Msgbox::Alert( - wxString::Format(_("Could not create a memory card: \n\n%s\n\n"), str.c_str()) + - StringUtil::UTF8StringToWxString(GetDisabledMessage(slot))); -#endif + Host::ReportFormattedErrorAsync("Memory Card", "Could not create a memory card: \n\n%s\n\n", + fname.c_str()); } } @@ -331,38 +328,43 @@ void FileMemoryCard::Open() // (8MB, 256Mb, formatted, unformatted, etc ...) #ifdef _WIN32 - FileSystem::SetPathCompression(StringUtil::wxStringToUTF8String(str).c_str(), EmuConfig.McdCompressNTFS); + FileSystem::SetPathCompression(fname.c_str(), EmuConfig.McdCompressNTFS); #endif - if (str.EndsWith(".bin")) + if (StringUtil::EndsWith(fname, ".bin")) { - wxString newname = str + "x"; - if (!ConvertNoECCtoRAW(str, newname)) + std::string newname(fname + "x"); + if (!ConvertNoECCtoRAW(fname.c_str(), newname.c_str())) { - Console.Error("Could convert memory card: %s", str.ToUTF8().data()); - wxRemoveFile(newname); + Console.Error("Could convert memory card: %s", fname.c_str()); + FileSystem::DeleteFilePath(newname.c_str()); continue; } - str = newname; + + // store the original filename + m_file[slot] = FileSystem::OpenCFile(newname.c_str(), "r+b"); + } + else + { + m_file[slot] = FileSystem::OpenCFile(fname.c_str(), "r+b"); } - if (!m_file[slot].Open(str.c_str(), L"r+b")) + if (!m_file[slot]) { // Translation note: detailed description should mention that the memory card will be disabled // for the duration of this session. -#ifndef PCSX2_CORE - Msgbox::Alert( - wxString::Format(_("Access denied to memory card: \n\n%s\n\n"), str.c_str()) + - StringUtil::UTF8StringToWxString(GetDisabledMessage(slot))); -#endif + Host::ReportFormattedErrorAsync("Memory Card", "Access denied to memory card: \n\n%s\n\n" + "The PS2-slot %d has been automatically disabled. You can correct the problem\nand re-enable it at any time using Config:Memory cards from the main menu.", + fname.c_str(), slot); } else // Load checksum { - m_ispsx[slot] = m_file[slot].Length() == 0x20000; + m_filenames[slot] = std::move(fname); + m_ispsx[slot] = FileSystem::FSize64(m_file[slot]) == 0x20000; m_chkaddr = 0x210; - if (!m_ispsx[slot] && !!m_file[slot].Seek(m_chkaddr)) - m_file[slot].Read(&m_chksum[slot], 8); + if (!m_ispsx[slot] && FileSystem::FSeek64(m_file[slot], m_chkaddr, SEEK_SET) == 0) + std::fread(&m_chksum[slot], sizeof(m_chksum[slot]), 1, m_file[slot]); } } } @@ -371,29 +373,31 @@ void FileMemoryCard::Close() { for (int slot = 0; slot < 8; ++slot) { - if (m_file[slot].IsOpened()) + if (!m_file[slot]) + continue; + + // Store checksum + if (!m_ispsx[slot] && FileSystem::FSeek64(m_file[slot], m_chkaddr, SEEK_SET) == 0) + std::fwrite(&m_chksum[slot], sizeof(m_chksum[slot]), 1, m_file[slot]); + + std::fclose(m_file[slot]); + m_file[slot] = nullptr; + + if (StringUtil::EndsWith(m_filenames[slot], ".bin")) { - // Store checksum - if (!m_ispsx[slot] && !!m_file[slot].Seek(m_chkaddr)) - m_file[slot].Write(&m_chksum[slot], 8); - - m_file[slot].Close(); - - if (m_file[slot].GetName().EndsWith(".binx")) - { - wxString name = m_file[slot].GetName(); - wxString name_old = name.SubString(0, name.Last('.')) + "bin"; - if (ConvertRAWtoNoECC(name, name_old)) - wxRemoveFile(name); - } + const std::string name_in(m_filenames[slot] + 'x'); + if (ConvertRAWtoNoECC(name_in.c_str(), m_filenames[slot].c_str())) + FileSystem::DeleteFilePath(name_in.c_str()); } + + m_filenames[slot] = {}; } } // Returns FALSE if the seek failed (is outside the bounds of the file). -bool FileMemoryCard::Seek(wxFFile& f, u32 adr) +bool FileMemoryCard::Seek(std::FILE* f, u32 adr) { - const u32 size = f.Length(); + const s64 size = FileSystem::FSize64(f); // If anyone knows why this filesize logic is here (it appears to be related to legacy PSX // cards, perhaps hacked support for some special emulator-specific memcard formats that @@ -410,23 +414,23 @@ bool FileMemoryCard::Seek(wxFFile& f, u32 adr) // perform sanity checks here? } - return f.Seek(adr + offset); + return (FileSystem::FSeek64(f, adr + offset, SEEK_SET) == 0); } // returns FALSE if an error occurred (either permission denied or disk full) -bool FileMemoryCard::Create(const wxString& mcdFile, uint sizeInMB) +bool FileMemoryCard::Create(const char* mcdFile, uint sizeInMB) { //int enc[16] = {0x77,0x7f,0x7f,0x77,0x7f,0x7f,0x77,0x7f,0x7f,0x77,0x7f,0x7f,0,0,0,0}; - Console.WriteLn("(FileMcd) Creating new %uMB memory card: %s", sizeInMB, mcdFile.ToUTF8().data()); + Console.WriteLn("(FileMcd) Creating new %uMB memory card: %s", sizeInMB, mcdFile); - wxFFile fp(mcdFile, L"wb"); - if (!fp.IsOpened()) + auto fp = FileSystem::OpenManagedCFile(mcdFile, "wb"); + if (!fp) return false; for (uint i = 0; i < (MC2_MBSIZE * sizeInMB) / sizeof(m_effeffs); i++) { - if (fp.Write(m_effeffs, sizeof(m_effeffs)) == 0) + if (std::fwrite(m_effeffs, sizeof(m_effeffs), 1, fp.get()) != 1) return false; } return true; @@ -434,7 +438,7 @@ bool FileMemoryCard::Create(const wxString& mcdFile, uint sizeInMB) s32 FileMemoryCard::IsPresent(uint slot) { - return m_file[slot].IsOpened(); + return m_file[slot] != nullptr; } void FileMemoryCard::GetSizeInfo(uint slot, McdSizeInfo& outways) @@ -443,8 +447,8 @@ void FileMemoryCard::GetSizeInfo(uint slot, McdSizeInfo& outways) outways.EraseBlockSizeInSectors = 16; // 0x0010 outways.Xor = 18; // 0x12, XOR 02 00 00 10 - if (pxAssert(m_file[slot].IsOpened())) - outways.McdSizeInSectors = m_file[slot].Length() / (outways.SectorSize + outways.EraseBlockSizeInSectors); + if (pxAssert(m_file[slot])) + outways.McdSizeInSectors = static_cast(FileSystem::FSize64(m_file[slot])) / (outways.SectorSize + outways.EraseBlockSizeInSectors); else outways.McdSizeInSectors = 0x4000; @@ -459,8 +463,8 @@ bool FileMemoryCard::IsPSX(uint slot) s32 FileMemoryCard::Read(uint slot, u8* dest, u32 adr, int size) { - wxFFile& mcfp(m_file[slot]); - if (!mcfp.IsOpened()) + std::FILE* mcfp = m_file[slot]; + if (!mcfp) { DevCon.Error("(FileMcd) Ignoring attempted read from disabled slot."); memset(dest, 0, size); @@ -468,14 +472,14 @@ s32 FileMemoryCard::Read(uint slot, u8* dest, u32 adr, int size) } if (!Seek(mcfp, adr)) return 0; - return mcfp.Read(dest, size) != 0; + return std::fread(dest, size, 1, mcfp) == 1; } s32 FileMemoryCard::Save(uint slot, const u8* src, u32 adr, int size) { - wxFFile& mcfp(m_file[slot]); + std::FILE* mcfp = m_file[slot]; - if (!mcfp.IsOpened()) + if (!mcfp) { DevCon.Error("(FileMcd) Ignoring attempted save/write to disabled slot."); return 1; @@ -492,7 +496,7 @@ s32 FileMemoryCard::Save(uint slot, const u8* src, u32 adr, int size) if (!Seek(mcfp, adr)) return 0; m_currentdata.MakeRoomFor(size); - mcfp.Read(m_currentdata.GetPtr(), size); + std::fread(m_currentdata.GetPtr(), size, 1, mcfp); for (int i = 0; i < size; i++) @@ -518,18 +522,16 @@ s32 FileMemoryCard::Save(uint slot, const u8* src, u32 adr, int size) if (!Seek(mcfp, adr)) return 0; - int status = mcfp.Write(m_currentdata.GetPtr(), size); - - if (status) + if (std::fwrite(m_currentdata.GetPtr(), size, 1, mcfp) == 1) { static auto last = std::chrono::time_point(); std::chrono::duration elapsed = std::chrono::system_clock::now() - last; if (elapsed > std::chrono::seconds(5)) { - wxString name, ext; - wxFileName::SplitPath(m_file[slot].GetName(), NULL, NULL, &name, &ext); - Host::AddOSDMessage(StringUtil::StdStringFromFormat("Memory Card %s written.", (const char*)(name + "." + ext).c_str()), 10.0f); + const std::string_view filename(Path::GetFileName(m_filenames[slot])); + Host::AddKeyedFormattedOSDMessage(StringUtil::StdStringFromFormat("MemoryCardSave%u", slot), 10.0f, + "Memory Card %.*s written.", static_cast(filename.size()), static_cast(filename.data())); last = std::chrono::system_clock::now(); } return 1; @@ -540,9 +542,8 @@ s32 FileMemoryCard::Save(uint slot, const u8* src, u32 adr, int size) s32 FileMemoryCard::EraseBlock(uint slot, u32 adr) { - wxFFile& mcfp(m_file[slot]); - - if (!mcfp.IsOpened()) + std::FILE* mcfp = m_file[slot]; + if (!mcfp) { DevCon.Error("MemoryCard: Ignoring erase for disabled slot."); return 1; @@ -550,13 +551,13 @@ s32 FileMemoryCard::EraseBlock(uint slot, u32 adr) if (!Seek(mcfp, adr)) return 0; - return mcfp.Write(m_effeffs, sizeof(m_effeffs)) != 0; + return std::fwrite(m_effeffs, sizeof(m_effeffs), 1, mcfp) == 1; } u64 FileMemoryCard::GetCRC(uint slot) { - wxFFile& mcfp(m_file[slot]); - if (!mcfp.IsOpened()) + std::FILE* mcfp = m_file[slot]; + if (!mcfp) return 0; u64 retval = 0; @@ -566,14 +567,20 @@ u64 FileMemoryCard::GetCRC(uint slot) if (!Seek(mcfp, 0)) return 0; + const s64 mcfpsize = FileSystem::FSize64(mcfp); + if (mcfpsize < 0) + return 0; + // Process the file in 4k chunks. Speeds things up significantly. u64 buffer[528 * 8]; // use 528 (sector size), ensures even divisibility - const uint filesize = mcfp.Length() / sizeof(buffer); + const uint filesize = static_cast(mcfpsize) / sizeof(buffer); for (uint i = filesize; i; --i) { - mcfp.Read(&buffer, sizeof(buffer)); + if (std::fread(buffer, sizeof(buffer), 1, mcfp) != 1) + return 0; + for (uint t = 0; t < std::size(buffer); ++t) retval ^= buffer[t]; } @@ -616,15 +623,9 @@ void FileMcd_EmuOpen() { MemoryCardType type = MemoryCardType::File; // default to file if we can't find anything at the path so it gets auto-generated - const wxString path = EmuConfig.FullpathToMcd(slot); - if (wxFileExists(path)) - { - type = MemoryCardType::File; - } - else if (wxDirExists(path)) - { + const std::string path(EmuConfig.FullpathToMcd(slot)); + if (FileSystem::DirectoryExists(path.c_str())) type = MemoryCardType::Folder; - } EmuConfig.Mcd[slot].Type = type; } @@ -760,7 +761,7 @@ void FileMcd_NextFrame(uint port, uint slot) } } -bool FileMcd_ReIndex(uint port, uint slot, const wxString& filter) +bool FileMcd_ReIndex(uint port, uint slot, const std::string& filter) { const uint combinedSlot = FileMcd_ConvertToSlot(port, slot); switch (EmuConfig.Mcd[combinedSlot].Type) @@ -780,50 +781,6 @@ bool FileMcd_ReIndex(uint port, uint slot, const wxString& filter) // Library API Implementations // -------------------------------------------------------------------------------------- -//Tests if a string is a valid name for a new file within a specified directory. -//returns true if: -// - the file name has a minimum length of minNumCharacters chars (default is 5 chars: at least 1 char + '.' + 3-chars extension) -// and - the file name is within the basepath directory (doesn't contain .. , / , \ , etc) -// and - file name doesn't already exist -// and - can be created on current system (it is actually created and deleted for this test). -bool isValidNewFilename(wxString filenameStringToTest, wxDirName atBasePath, wxString& out_errorMessage, uint minNumCharacters) -{ - if (filenameStringToTest.Length() < 1 || filenameStringToTest.Length() < minNumCharacters) - { - out_errorMessage = _("File name empty or too short"); - return false; - } - - if ((atBasePath + wxFileName(filenameStringToTest)).GetFullPath() != (atBasePath + wxFileName(filenameStringToTest).GetFullName()).GetFullPath()) - { - out_errorMessage = _("File name outside of required directory"); - return false; - } - - if (wxFileExists((atBasePath + wxFileName(filenameStringToTest)).GetFullPath())) - { - out_errorMessage = _("File name already exists"); - return false; - } - if (wxDirExists((atBasePath + wxFileName(filenameStringToTest)).GetFullPath())) - { - out_errorMessage = _("File name already exists"); - return false; - } - - wxFile fp; - if (!fp.Create((atBasePath + wxFileName(filenameStringToTest)).GetFullPath())) - { - out_errorMessage = _("The Operating-System prevents this file from being created"); - return false; - } - fp.Close(); - wxRemoveFile((atBasePath + wxFileName(filenameStringToTest)).GetFullPath()); - - out_errorMessage = L"[OK - New file name is valid]"; //shouldn't be displayed on success, hence not translatable. - return true; -} - static MemoryCardFileType GetMemoryCardFileTypeFromSize(s64 size) { if (size == (8 * MC2_MBSIZE)) @@ -842,7 +799,7 @@ static MemoryCardFileType GetMemoryCardFileTypeFromSize(s64 size) static bool IsMemoryCardFolder(const std::string& path) { - const std::string superblock_path(Path::CombineStdString(path, s_folder_mem_card_id_file)); + const std::string superblock_path(Path::Combine(path, s_folder_mem_card_id_file)); return FileSystem::FileExists(superblock_path.c_str()); } @@ -867,7 +824,7 @@ static bool IsMemoryCardFormatted(const std::string& path) std::vector FileMcd_GetAvailableCards(bool include_in_use_cards) { std::vector files; - FileSystem::FindFiles(EmuFolders::MemoryCards.ToUTF8(), "*", + FileSystem::FindFiles(EmuFolders::MemoryCards.c_str(), "*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_FOLDERS | FILESYSTEM_FIND_HIDDEN_FILES, &files); std::vector mcds; @@ -875,7 +832,7 @@ std::vector FileMcd_GetAvailableCards(bool include_in_use_card for (FILESYSTEM_FIND_DATA& fd : files) { - std::string basename(FileSystem::GetFileNameFromPath(fd.FileName)); + std::string basename(Path::GetFileName(fd.FileName)); if (!include_in_use_cards) { bool in_use = false; @@ -919,7 +876,7 @@ std::optional FileMcd_GetCardInfo(const std::string_view& name std::optional ret; std::string basename(name); - std::string path(Path::CombineStdString(EmuFolders::MemoryCards, basename)); + std::string path(Path::Combine(EmuFolders::MemoryCards, basename)); FILESYSTEM_STAT_DATA sd; if (!FileSystem::StatFile(path.c_str(), &sd)) @@ -949,7 +906,7 @@ std::optional FileMcd_GetCardInfo(const std::string_view& name bool FileMcd_CreateNewCard(const std::string_view& name, MemoryCardType type, MemoryCardFileType file_type) { - const std::string full_path(Path::CombineStdString(EmuFolders::MemoryCards, name)); + const std::string full_path(Path::Combine(EmuFolders::MemoryCards, name)); if (type == MemoryCardType::Folder) { @@ -962,7 +919,7 @@ bool FileMcd_CreateNewCard(const std::string_view& name, MemoryCardType type, Me } // write the superblock - auto fp = FileSystem::OpenManagedCFile(Path::CombineStdString(full_path, s_folder_mem_card_id_file).c_str(), "wb"); + auto fp = FileSystem::OpenManagedCFile(Path::Combine(full_path, s_folder_mem_card_id_file).c_str(), "wb"); if (!fp) { Host::ReportFormattedErrorAsync("Memory Card Creation Failed", "Failed to write memory card folder superblock '%s'.", full_path.c_str()); @@ -1038,8 +995,8 @@ bool FileMcd_CreateNewCard(const std::string_view& name, MemoryCardType type, Me bool FileMcd_RenameCard(const std::string_view& name, const std::string_view& new_name) { - const std::string name_path(Path::CombineStdString(EmuFolders::MemoryCards, name)); - const std::string new_name_path(Path::CombineStdString(EmuFolders::MemoryCards, new_name)); + const std::string name_path(Path::Combine(EmuFolders::MemoryCards, name)); + const std::string new_name_path(Path::Combine(EmuFolders::MemoryCards, new_name)); FILESYSTEM_STAT_DATA sd, new_sd; if (!FileSystem::StatFile(name_path.c_str(), &sd) || FileSystem::StatFile(new_name_path.c_str(), &new_sd)) @@ -1063,7 +1020,7 @@ bool FileMcd_RenameCard(const std::string_view& name, const std::string_view& ne bool FileMcd_DeleteCard(const std::string_view& name) { - const std::string name_path(Path::CombineStdString(EmuFolders::MemoryCards, name)); + const std::string name_path(Path::Combine(EmuFolders::MemoryCards, name)); FILESYSTEM_STAT_DATA sd; if (!FileSystem::StatFile(name_path.c_str(), &sd)) diff --git a/pcsx2/MemoryCardFile.h b/pcsx2/MemoryCardFile.h index 79d909e6b4..e055ec560f 100644 --- a/pcsx2/MemoryCardFile.h +++ b/pcsx2/MemoryCardFile.h @@ -44,8 +44,6 @@ extern uint FileMcd_GetMtapSlot(uint slot); extern bool FileMcd_IsMultitapSlot(uint slot); //extern wxFileName FileMcd_GetSimpleName(uint slot); extern std::string FileMcd_GetDefaultName(uint slot); -extern bool isValidNewFilename(wxString filenameStringToTest, wxDirName atBasePath, wxString& out_errorMessage, uint minNumCharacters = 5); - uint FileMcd_ConvertToSlot(uint port, uint slot); void FileMcd_EmuOpen(); @@ -58,7 +56,7 @@ s32 FileMcd_Save(uint port, uint slot, const u8* src, u32 adr, int size); s32 FileMcd_EraseBlock(uint port, uint slot, u32 adr); u64 FileMcd_GetCRC(uint port, uint slot); void FileMcd_NextFrame(uint port, uint slot); -bool FileMcd_ReIndex(uint port, uint slot, const wxString& filter); +bool FileMcd_ReIndex(uint port, uint slot, const std::string& filter); std::vector FileMcd_GetAvailableCards(bool include_in_use_cards); std::optional FileMcd_GetCardInfo(const std::string_view& name); diff --git a/pcsx2/MemoryCardFolder.cpp b/pcsx2/MemoryCardFolder.cpp index 9722ff4d13..124c15ebf1 100644 --- a/pcsx2/MemoryCardFolder.cpp +++ b/pcsx2/MemoryCardFolder.cpp @@ -23,22 +23,21 @@ #include "Config.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" +#include "common/Timer.h" #include "fmt/core.h" #include "ryml_std.hpp" #include "ryml.hpp" -#include "common/Path.h" -#include #include "svnrev.h" #include +#include #include -bool RemoveWxDirectory(const wxString& dirname); - -ryml::Tree parseYamlStr(const std::string& str) +static ryml::Tree parseYamlStr(const std::string& str) { ryml::Callbacks rymlCallbacks = ryml::get_callbacks(); rymlCallbacks.m_error = [](const char* msg, size_t msg_len, ryml::Location loc, void*) { @@ -57,16 +56,11 @@ ryml::Tree parseYamlStr(const std::string& str) } // A helper function to parse the YAML file -std::optional loadYamlFile(const wxString& filePath) +static std::optional loadYamlFile(const char* filePath) { try { - auto file = FileSystem::OpenManagedCFile(StringUtil::wxStringToUTF8String(filePath).c_str(), "rb"); - if (!file) - { - return std::nullopt; - } - std::optional buffer = FileSystem::ReadFileToString(file.get()); + std::optional buffer = FileSystem::ReadFileToString(filePath); if (!buffer.has_value()) { return std::nullopt; @@ -76,21 +70,58 @@ std::optional loadYamlFile(const wxString& filePath) } catch (const std::exception& e) { - Console.Error(fmt::format("[MemoryCard] Error occured when parsing folder memory card at path '{}': {}", StringUtil::wxStringToUTF8String(filePath), e.what())); + Console.Error(fmt::format("[MemoryCard] Error occured when parsing folder memory card at path '{}': {}", filePath, e.what())); ryml::reset_callbacks(); return std::nullopt; } } /// A helper function to write a YAML file -void SaveYAMLToFile(const wxString& filename, const ryml::NodeRef& node) +static void SaveYAMLToFile(const char* filename, const ryml::NodeRef& node) { - auto file = FileSystem::OpenCFile(StringUtil::wxStringToUTF8String(filename).c_str(), "w"); + auto file = FileSystem::OpenCFile(filename, "w"); ryml::emit(node, file); std::fflush(file); std::fclose(file); } +static constexpr time_t MEMORY_CARD_FILE_ENTRY_DATE_TIME_OFFSET = 60 * 60 * 9; // 9 hours from UTC + +MemoryCardFileEntryDateTime MemoryCardFileEntryDateTime::FromTime(time_t time) +{ + // TODO: Is this safe with regard to DST? + time += MEMORY_CARD_FILE_ENTRY_DATE_TIME_OFFSET; + + struct tm converted = {}; +#ifdef _MSC_VER + gmtime_s(&converted, &time); +#else + gmtime_r(&time, &converted); +#endif + + MemoryCardFileEntryDateTime ret; + ret.unused = 0; + ret.second = converted.tm_sec; + ret.minute = converted.tm_min; + ret.hour = converted.tm_hour; + ret.day = converted.tm_mday; + ret.month = converted.tm_mon + 1; + ret.year = converted.tm_year + 1900; + return ret; +} + +time_t MemoryCardFileEntryDateTime::ToTime() const +{ + struct tm converted = {}; + converted.tm_sec = second; + converted.tm_min = minute; + converted.tm_hour = hour; + converted.tm_mday = day; + converted.tm_mon = std::max(static_cast(month) - 1, 0); + converted.tm_year = std::max(static_cast(year) - 1900, 0); + return mktime(&converted); +} + FolderMemoryCard::FolderMemoryCard() { m_slot = 0; @@ -99,7 +130,6 @@ FolderMemoryCard::FolderMemoryCard() m_framesUntilFlush = 0; m_timeLastWritten = 0; m_filteringEnabled = false; - m_filteringString = L""; } void FolderMemoryCard::InitializeInternalData() @@ -118,7 +148,7 @@ void FolderMemoryCard::InitializeInternalData() m_framesUntilFlush = 0; m_performFileWrites = true; m_filteringEnabled = false; - m_filteringString = L""; + m_filteringString = {}; } bool FolderMemoryCard::IsFormatted() const @@ -127,40 +157,39 @@ bool FolderMemoryCard::IsFormatted() const return m_superBlock.raw[0x16] == 0x6F; } -void FolderMemoryCard::Open(const bool enableFiltering, const wxString& filter) +void FolderMemoryCard::Open(const bool enableFiltering, std::string filter) { - Open(EmuConfig.FullpathToMcd(m_slot), EmuConfig.Mcd[m_slot], 0, enableFiltering, filter, false); + Open(EmuConfig.FullpathToMcd(m_slot), EmuConfig.Mcd[m_slot], 0, enableFiltering, std::move(filter), false); } -void FolderMemoryCard::Open(const wxString& fullPath, const Pcsx2Config::McdOptions& mcdOptions, const u32 sizeInClusters, const bool enableFiltering, const wxString& filter, bool simulateFileWrites) +void FolderMemoryCard::Open(std::string fullPath, const Pcsx2Config::McdOptions& mcdOptions, const u32 sizeInClusters, const bool enableFiltering, std::string filter, bool simulateFileWrites) { InitializeInternalData(); m_performFileWrites = !simulateFileWrites; - wxFileName configuredFileName(fullPath); - m_folderName = wxFileName(configuredFileName.GetFullPath() + L"/"); - wxString str(configuredFileName.GetFullPath()); + m_folderName = Path::Canonicalize(fullPath); + std::string_view str(fullPath); bool disabled = false; if (mcdOptions.Enabled && mcdOptions.Type == MemoryCardType::Folder) { - if (configuredFileName.GetFullName().IsEmpty()) + if (fullPath.empty()) { - str = L"[empty filename]"; + str = "[empty filename]"; disabled = true; } - if (!disabled && configuredFileName.FileExists()) + if (!disabled && FileSystem::FileExists(fullPath.c_str())) { - str = L"[is file, should be folder]"; + str = "[is file, should be folder]"; disabled = true; } // if nothing exists at a valid location, create a directory for the memory card - if (!disabled && m_performFileWrites && !m_folderName.DirExists()) + if (!disabled && m_performFileWrites && !FileSystem::DirectoryExists(fullPath.c_str())) { - if (!m_folderName.Mkdir()) + if (!FileSystem::CreateDirectoryPath(fullPath.c_str(), false)) { - str = L"[couldn't create folder]"; + str = "[couldn't create folder]"; disabled = true; } } @@ -171,14 +200,15 @@ void FolderMemoryCard::Open(const wxString& fullPath, const Pcsx2Config::McdOpti return; } - Console.WriteLn(disabled ? Color_Gray : Color_Green, "McdSlot %u: [Folder] %s", m_slot, str.ToUTF8().data()); + Console.WriteLn(disabled ? Color_Gray : Color_Green, "McdSlot %u: [Folder] %.*s", + m_slot, static_cast(str.size()), str.data()); if (disabled) return; m_isEnabled = true; m_filteringEnabled = enableFiltering; - m_filteringString = filter; - LoadMemoryCardData(sizeInClusters, enableFiltering, filter); + m_filteringString = std::move(filter); + LoadMemoryCardData(sizeInClusters, enableFiltering, m_filteringString); SetTimeLastWrittenToNow(); m_framesUntilFlush = 0; @@ -202,7 +232,7 @@ void FolderMemoryCard::Close(bool flush) m_fileMetadataQuickAccess.clear(); } -bool FolderMemoryCard::ReIndex(bool enableFiltering, const wxString& filter) +bool FolderMemoryCard::ReIndex(bool enableFiltering, const std::string& filter) { if (!m_isEnabled) { @@ -219,16 +249,16 @@ bool FolderMemoryCard::ReIndex(bool enableFiltering, const wxString& filter) return false; } -void FolderMemoryCard::LoadMemoryCardData(const u32 sizeInClusters, const bool enableFiltering, const wxString& filter) +void FolderMemoryCard::LoadMemoryCardData(const u32 sizeInClusters, const bool enableFiltering, const std::string& filter) { bool formatted = false; // read superblock if it exists - wxFileName superBlockFileName(m_folderName.GetPath(), L"_pcsx2_superblock"); - if (superBlockFileName.FileExists()) + const std::string superBlockFileName(Path::Combine(m_folderName, "_pcsx2_superblock")); + if (FileSystem::FileExists(superBlockFileName.c_str())) { - wxFFile superBlockFile(superBlockFileName.GetFullPath().c_str(), L"rb"); - if (superBlockFile.IsOpened() && superBlockFile.Read(&m_superBlock.raw, sizeof(m_superBlock.raw)) >= sizeof(m_superBlock.data)) + auto superBlockFile = FileSystem::OpenManagedCFile(superBlockFileName.c_str(), "rb"); + if (superBlockFile && std::fread(&m_superBlock.raw, sizeof(m_superBlock.raw), 1, superBlockFile.get()) == 1) { formatted = IsFormatted(); } @@ -245,7 +275,7 @@ void FolderMemoryCard::LoadMemoryCardData(const u32 sizeInClusters, const bool e { if (enableFiltering) { - Console.WriteLn(Color_Green, "(FolderMcd) Indexing slot %u with filter \"%s\".", m_slot, filter.ToUTF8().data()); + Console.WriteLn(Color_Green, "(FolderMcd) Indexing slot %u with filter \"%s\".", m_slot, filter.c_str()); } else { @@ -255,7 +285,7 @@ void FolderMemoryCard::LoadMemoryCardData(const u32 sizeInClusters, const bool e CreateFat(); CreateRootDir(); MemoryCardFileEntry* const rootDirEntry = &m_fileEntryDict[m_superBlock.data.rootdir_cluster].entries[0]; - AddFolder(rootDirEntry, m_folderName.GetPath(), nullptr, enableFiltering, filter); + AddFolder(rootDirEntry, m_folderName, nullptr, enableFiltering, filter); #ifdef DEBUG_WRITE_FOLDER_CARD_IN_MEMORY_TO_FILE_ON_CHANGE WriteToFile(m_folderName.GetFullPath().RemoveLast() + L"-debug_" + wxDateTime::Now().Format(L"%Y-%m-%d-%H-%M-%S") + L"_load.ps2"); @@ -410,20 +440,20 @@ MemoryCardFileEntry* FolderMemoryCard::AppendFileEntryToDir(const MemoryCardFile return newFileEntry; } -bool FilterMatches(const wxString& fileName, const wxString& filter) +static bool FilterMatches(const std::string_view& fileName, const std::string_view& filter) { - size_t start = 0; - size_t len = filter.Len(); + std::string_view::size_type start = 0; + std::string_view::size_type len = filter.length(); while (start < len) { - size_t end = filter.find('/', start); - if (end == wxString::npos) + std::string_view::size_type end = filter.find('/', start); + if (end == std::string_view::npos) { end = len; } - wxString singleFilter = filter.Mid(start, end - start); - if (fileName.Contains(singleFilter)) + std::string_view singleFilter(filter.substr(start, end - start)); + if (fileName.find(singleFilter) != std::string_view::npos) { return true; } @@ -434,31 +464,27 @@ bool FilterMatches(const wxString& fileName, const wxString& filter) return false; } -bool FolderMemoryCard::AddFolder(MemoryCardFileEntry* const dirEntry, const wxString& dirPath, MemoryCardFileMetadataReference* parent, const bool enableFiltering, const wxString& filter) +bool FolderMemoryCard::AddFolder(MemoryCardFileEntry* const dirEntry, const std::string& dirPath, MemoryCardFileMetadataReference* parent /* = nullptr */, const bool enableFiltering /* = false */, const std::string_view& filter /* = "" */) { - if (wxDir::Exists(dirPath)) + if (FileSystem::DirectoryExists(dirPath.c_str())) { - - wxString localFilter; + std::string localFilter; if (enableFiltering) { - bool hasFilter = !filter.IsEmpty(); + bool hasFilter = !filter.empty(); if (hasFilter) { - localFilter = L"DATA-SYSTEM/BWNETCNF/" + filter; + localFilter = fmt::format("DATA-SYSTEM/BWNETCNF/{}", filter); } else { - localFilter = L"DATA-SYSTEM/BWNETCNF"; + localFilter = "DATA-SYSTEM/BWNETCNF"; } } int entryNumber = 2; // include . and .. for (const auto& file : GetOrderedFiles(dirPath)) { - - wxFileName fileInfo(dirPath, file.m_fileName); - if (file.m_isFile) { // don't load files in the root dir if we're filtering; no official software stores files there @@ -481,34 +507,28 @@ bool FolderMemoryCard::AddFolder(MemoryCardFileEntry* const dirEntry, const wxSt continue; } + // is a subdirectory + const std::string filePath(Path::Combine(dirPath, file.m_fileName)); + // make sure we have enough space on the memcard for the directory - const u32 newNeededClusters = CalculateRequiredClustersOfDirectory(dirPath + L"/" + file.m_fileName) + ((dirEntry->entry.data.length % 2) == 0 ? 1 : 0); + const u32 newNeededClusters = CalculateRequiredClustersOfDirectory(filePath) + ((dirEntry->entry.data.length % 2) == 0 ? 1 : 0); if (newNeededClusters > GetAmountFreeDataClusters()) { - Console.Warning(GetCardFullMessage(StringUtil::wxStringToUTF8String(file.m_fileName))); + Console.Warning(GetCardFullMessage(file.m_fileName)); continue; } - // is a subdirectory - fileInfo.AppendDir(fileInfo.GetFullName()); - fileInfo.SetName(L""); - fileInfo.ClearExt(); - // add entry for subdir in parent dir MemoryCardFileEntry* newDirEntry = AppendFileEntryToDir(dirEntry); dirEntry->entry.data.length++; // set metadata - wxFileName metaFileName(dirPath, L"_pcsx2_meta_directory"); - metaFileName.AppendDir(file.m_fileName); - wxFFile metaFile; - if (metaFileName.FileExists() && metaFile.Open(metaFileName.GetFullPath(), L"rb")) + const std::string metaFileName(Path::Combine(Path::Combine(dirPath, "_pcsx2_meta_directory"), file.m_fileName)); + if (auto metaFile = FileSystem::OpenManagedCFile(metaFileName.c_str(), "rb"); metaFile) { - size_t bytesRead = metaFile.Read(&newDirEntry->entry.raw, sizeof(newDirEntry->entry.raw)); - metaFile.Close(); - if (bytesRead < 0x60) + if (std::fread(&newDirEntry->entry.raw, 1, sizeof(newDirEntry->entry.raw), metaFile.get()) < 0x60) { - strcpy(reinterpret_cast(newDirEntry->entry.data.name), file.m_fileName.mbc_str()); + StringUtil::Strlcpy(reinterpret_cast(newDirEntry->entry.data.name), file.m_fileName.c_str(), sizeof(newDirEntry->entry.data.name)); } } else @@ -516,7 +536,7 @@ bool FolderMemoryCard::AddFolder(MemoryCardFileEntry* const dirEntry, const wxSt newDirEntry->entry.data.mode = MemoryCardFileEntry::DefaultDirMode; newDirEntry->entry.data.timeCreated = MemoryCardFileEntryDateTime::FromTime(file.m_timeCreated); newDirEntry->entry.data.timeModified = MemoryCardFileEntryDateTime::FromTime(file.m_timeModified); - strcpy(reinterpret_cast(newDirEntry->entry.data.name), file.m_fileName.mbc_str()); + StringUtil::Strlcpy(reinterpret_cast(newDirEntry->entry.data.name), file.m_fileName.c_str(), sizeof(newDirEntry->entry.data.name)); } // create new cluster for . and .. entries @@ -541,7 +561,7 @@ bool FolderMemoryCard::AddFolder(MemoryCardFileEntry* const dirEntry, const wxSt ++entryNumber; // and add all files in subdir - AddFolder(newDirEntry, fileInfo.GetFullPath(), dirRef); + AddFolder(newDirEntry, filePath, dirRef); } } @@ -551,23 +571,22 @@ bool FolderMemoryCard::AddFolder(MemoryCardFileEntry* const dirEntry, const wxSt return false; } -bool FolderMemoryCard::AddFile(MemoryCardFileEntry* const dirEntry, const wxString& dirPath, const EnumeratedFileEntry& fileEntry, MemoryCardFileMetadataReference* parent) +bool FolderMemoryCard::AddFile(MemoryCardFileEntry* const dirEntry, const std::string& dirPath, const EnumeratedFileEntry& fileEntry, MemoryCardFileMetadataReference* parent) { - wxFileName relativeFilePath(dirPath, fileEntry.m_fileName); - relativeFilePath.MakeRelativeTo(m_folderName.GetPath()); + const std::string filePath(Path::Combine(dirPath, fileEntry.m_fileName)); + pxAssertMsg(StringUtil::StartsWith(filePath, m_folderName.c_str()), "Full file path starts with MC folder path"); + const std::string relativeFilePath(filePath.substr(m_folderName.length() + 1)); - wxFileName fileInfo(dirPath, fileEntry.m_fileName); - wxFFile file(fileInfo.GetFullPath(), L"rb"); - if (file.IsOpened()) + if (auto file = FileSystem::OpenManagedCFile(filePath.c_str(), "rb"); file) { // make sure we have enough space on the memcard to hold the data const u32 clusterSize = m_superBlock.data.pages_per_cluster * m_superBlock.data.page_len; - const u32 filesize = file.Length(); + const u32 filesize = static_cast(std::clamp(FileSystem::FSize64(file.get()), 0, std::numeric_limits::max())); const u32 countClusters = (filesize % clusterSize) != 0 ? (filesize / clusterSize + 1) : (filesize / clusterSize); const u32 newNeededClusters = (dirEntry->entry.data.length % 2) == 0 ? countClusters + 1 : countClusters; if (newNeededClusters > GetAmountFreeDataClusters()) { - Console.Warning(GetCardFullMessage(StringUtil::wxStringToUTF8String(relativeFilePath.GetFullPath()))); + Console.Warning(GetCardFullMessage(relativeFilePath)); return false; } @@ -576,16 +595,13 @@ bool FolderMemoryCard::AddFile(MemoryCardFileEntry* const dirEntry, const wxStri // set file entry metadata memset(newFileEntry->entry.raw, 0x00, sizeof(newFileEntry->entry.raw)); - wxFileName metaFileName(dirPath, fileEntry.m_fileName); - metaFileName.AppendDir(L"_pcsx2_meta"); - wxFFile metaFile; - if (metaFileName.FileExists() && metaFile.Open(metaFileName.GetFullPath(), L"rb")) + std::string metaFileName(Path::Combine(Path::Combine(dirPath, "_pcsx2_meta"), fileEntry.m_fileName)); + if (auto metaFile = FileSystem::OpenManagedCFile(metaFileName.c_str(), "rb"); metaFile) { - size_t bytesRead = metaFile.Read(&newFileEntry->entry.raw, sizeof(newFileEntry->entry.raw)); - metaFile.Close(); + size_t bytesRead = std::fread(&newFileEntry->entry.raw, 1, sizeof(newFileEntry->entry.raw), metaFile.get()); if (bytesRead < 0x60) { - strcpy(reinterpret_cast(newFileEntry->entry.data.name), fileEntry.m_fileName.mbc_str()); + StringUtil::Strlcpy(reinterpret_cast(newFileEntry->entry.data.name), fileEntry.m_fileName.c_str(), sizeof(newFileEntry->entry.data.name)); } } else @@ -593,7 +609,7 @@ bool FolderMemoryCard::AddFile(MemoryCardFileEntry* const dirEntry, const wxStri newFileEntry->entry.data.mode = MemoryCardFileEntry::DefaultFileMode; newFileEntry->entry.data.timeCreated = MemoryCardFileEntryDateTime::FromTime(fileEntry.m_timeCreated); newFileEntry->entry.data.timeModified = MemoryCardFileEntryDateTime::FromTime(fileEntry.m_timeModified); - strcpy(reinterpret_cast(newFileEntry->entry.data.name), fileEntry.m_fileName.mbc_str()); + StringUtil::Strlcpy(reinterpret_cast(newFileEntry->entry.data.name), fileEntry.m_fileName.c_str(), sizeof(newFileEntry->entry.data.name)); } newFileEntry->entry.data.length = filesize; @@ -618,7 +634,7 @@ bool FolderMemoryCard::AddFile(MemoryCardFileEntry* const dirEntry, const wxStri newFileEntry->entry.data.cluster = MemoryCardFileEntry::EmptyFileCluster; } - file.Close(); + file.reset(); MemoryCardFileMetadataReference* fileRef = AddFileEntryToMetadataQuickAccess(newFileEntry, parent); if (fileRef != nullptr) @@ -634,46 +650,37 @@ bool FolderMemoryCard::AddFile(MemoryCardFileEntry* const dirEntry, const wxStri } else { - Console.WriteLn("(FolderMcd) Could not open file: %s", relativeFilePath.GetFullPath().ToUTF8().data()); + Console.WriteLn("(FolderMcd) Could not open file: %s", relativeFilePath.c_str()); return false; } } -u32 FolderMemoryCard::CalculateRequiredClustersOfDirectory(const wxString& dirPath) const +u32 FolderMemoryCard::CalculateRequiredClustersOfDirectory(const std::string& dirPath) const { const u32 clusterSize = m_superBlock.data.pages_per_cluster * m_superBlock.data.page_len; u32 requiredFileEntryPages = 2; u32 requiredClusters = 0; // No need to read the index file as we are only counting space required; order of files is irrelevant. - wxDir dir(dirPath); - wxString fileName; - bool hasNext = dir.GetFirst(&fileName); - while (hasNext) + FileSystem::FindResultsArray files; + FileSystem::FindFiles(dirPath.c_str(), "*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_FOLDERS | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RELATIVE_PATHS, &files); + for (const FILESYSTEM_FIND_DATA& fd : files) { - if (fileName.StartsWith(L"_pcsx2_")) - { - hasNext = dir.GetNext(&fileName); + if (StringUtil::StartsWith(fd.FileName, "_pcsx2_")) continue; - } ++requiredFileEntryPages; - wxFileName file(dirPath, fileName); - wxString path = file.GetFullPath(); - bool isFile = wxFile::Exists(path); - if (isFile) + if (!(fd.Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY)) { - const u32 filesize = file.GetSize().GetValue(); + const u32 filesize = static_cast(std::min(fd.Size, std::numeric_limits::max())); const u32 countClusters = (filesize % clusterSize) != 0 ? (filesize / clusterSize + 1) : (filesize / clusterSize); requiredClusters += countClusters; } else { - requiredClusters += CalculateRequiredClustersOfDirectory(path); + requiredClusters += CalculateRequiredClustersOfDirectory(Path::Combine(dirPath, fd.FileName)); } - - hasNext = dir.GetNext(&fileName); } return requiredClusters + requiredFileEntryPages / 2 + (requiredFileEntryPages % 2 == 0 ? 0 : 1); @@ -849,7 +856,7 @@ MemoryCardFileEntryCluster* FolderMemoryCard::GetFileEntryCluster(const u32 curr // This method is actually unused since the introduction of m_fileMetadataQuickAccess. // I'll leave it here anyway though to show how you traverse the file system. -MemoryCardFileEntry* FolderMemoryCard::GetFileEntryFromFileDataCluster(const u32 currentCluster, const u32 searchCluster, wxFileName* fileName, const size_t originalDirCount, u32* outClusterNumber) +MemoryCardFileEntry* FolderMemoryCard::GetFileEntryFromFileDataCluster(const u32 currentCluster, const u32 searchCluster, std::string* fileName, const size_t originalDirCount, u32* outClusterNumber) { // check both entries of the current cluster if they're the file we're searching for, and if yes return it for (int i = 0; i < 2; ++i) @@ -863,7 +870,7 @@ MemoryCardFileEntry* FolderMemoryCard::GetFileEntryFromFileDataCluster(const u32 { if (fileCluster == searchCluster) { - fileName->SetName(wxString::FromAscii((const char*)entry->entry.data.name)); + Path::ChangeFileName(fileName, (const char*)entry->entry.data.name); *outClusterNumber = clusterNumber; return entry; } @@ -893,7 +900,9 @@ MemoryCardFileEntry* FolderMemoryCard::GetFileEntryFromFileDataCluster(const u32 MemoryCardFileEntry* ptr = GetFileEntryFromFileDataCluster(entry->entry.data.cluster, searchCluster, fileName, originalDirCount, outClusterNumber); if (ptr != nullptr) { - fileName->InsertDir(originalDirCount, wxString::FromAscii((const char*)entry->entry.data.name)); + std::vector components(Path::SplitNativePath(*fileName)); + components.insert(components.begin() + originalDirCount, (const char*)entry->entry.data.name); + *fileName = Path::JoinNativePath(components); return ptr; } } @@ -920,17 +929,15 @@ bool FolderMemoryCard::ReadFromFile(u8* dest, u32 adr, u32 dataLength) if (it != m_fileMetadataQuickAccess.end()) { const u32 clusterNumber = it->second.consecutiveCluster; - wxFFile* file = m_lastAccessedFile.ReOpen(m_folderName, &it->second); - if (file->IsOpened()) + std::FILE* file = m_lastAccessedFile.ReOpen(m_folderName, &it->second); + if (file) { const u32 clusterOffset = (page % 2) * PageSize + offset; const u32 fileOffset = clusterNumber * ClusterSize + clusterOffset; - if (fileOffset != file->Tell()) - { - file->Seek(fileOffset); - } - size_t bytesRead = file->Read(dest, dataLength); + size_t bytesRead = 0; + if (fileOffset == FileSystem::FTell64(file) || FileSystem::FSeek64(file, fileOffset, SEEK_SET) == 0) + bytesRead = std::fread(dest, 1, dataLength, file); // if more bytes were requested than actually exist, fill the rest with 0xFF if (bytesRead < dataLength) @@ -1088,7 +1095,7 @@ void FolderMemoryCard::Flush() #endif Console.WriteLn("(FolderMcd) Writing data for slot %u to file system...", m_slot); - const u64 timeFlushStart = wxGetLocalTimeMillis().GetValue(); + Common::Timer timeFlushStart; // Keep a copy of the old file entries so we can figure out which files and directories, if any, have been deleted from the memory card. std::vector oldFileEntryTree; @@ -1155,8 +1162,7 @@ void FolderMemoryCard::Flush() m_lastAccessedFile.ClearMetadataWriteState(); m_oldDataCache.clear(); - const u64 timeFlushEnd = wxGetLocalTimeMillis().GetValue(); - Console.WriteLn("(FolderMcd) Done! Took %u ms.", timeFlushEnd - timeFlushStart); + Console.WriteLn("(FolderMcd) Done! Took %.2f ms.", timeFlushStart.GetTimeMilliseconds()); #ifdef DEBUG_WRITE_FOLDER_CARD_IN_MEMORY_TO_FILE_ON_CHANGE WriteToFile(m_folderName.GetFullPath().RemoveLast() + L"-debug_" + wxDateTime::Now().Format(L"%Y-%m-%d-%H-%M-%S") + L"_post-flush.ps2"); @@ -1208,11 +1214,10 @@ void FolderMemoryCard::FlushSuperBlock() { if (FlushBlock(0) && m_performFileWrites) { - wxFileName superBlockFileName(m_folderName.GetPath(), L"_pcsx2_superblock"); - wxFFile superBlockFile(superBlockFileName.GetFullPath().c_str(), L"wb"); - if (superBlockFile.IsOpened()) + const std::string superBlockFileName(Path::Combine(m_folderName, "_pcsx2_superblock")); + if (auto superBlockFile = FileSystem::OpenManagedCFile(superBlockFileName.c_str(), "wb"); superBlockFile) { - superBlockFile.Write(&m_superBlock.raw, sizeof(m_superBlock.raw)); + std::fwrite(&m_superBlock.raw, sizeof(m_superBlock.raw), 1, superBlockFile.get()); } } } @@ -1229,7 +1234,7 @@ void FolderMemoryCard::FlushFileEntries() } } -void FolderMemoryCard::FlushFileEntries(const u32 dirCluster, const u32 remainingFiles, const wxString& dirPath, MemoryCardFileMetadataReference* parent) +void FolderMemoryCard::FlushFileEntries(const u32 dirCluster, const u32 remainingFiles, const std::string& dirPath, MemoryCardFileMetadataReference* parent) { // flush the current cluster FlushCluster(dirCluster + m_superBlock.data.alloc_offset); @@ -1249,38 +1254,38 @@ void FolderMemoryCard::FlushFileEntries(const u32 dirCluster, const u32 remainin char cleanName[sizeof(entry->entry.data.name)]; memcpy(cleanName, (const char*)entry->entry.data.name, sizeof(cleanName)); bool filenameCleaned = FileAccessHelper::CleanMemcardFilename(cleanName); - const wxString subDirName = wxString::FromAscii((const char*)cleanName); - const wxString subDirPath = dirPath + L"/" + subDirName; + const std::string subDirPath(Path::Combine(dirPath, cleanName)); if (m_performFileWrites) { // if this directory has nonstandard metadata, write that to the file system - wxFileName metaFileName(m_folderName.GetFullPath() + subDirPath, L"_pcsx2_meta_directory"); - if (!metaFileName.DirExists()) + const std::string fullSubDirPath(Path::Combine(m_folderName, subDirPath)); + std::string metaFileName(Path::Combine(fullSubDirPath, "_pcsx2_meta_directory")); + if (!FileSystem::DirectoryExists(fullSubDirPath.c_str())) { - metaFileName.Mkdir(); + FileSystem::CreateDirectoryPath(fullSubDirPath.c_str(), false); } + // TODO: This logic doesn't make sense. If it's not a directory, create it, then open it as a file?! if (filenameCleaned || entry->entry.data.mode != MemoryCardFileEntry::DefaultDirMode || entry->entry.data.attr != 0) { - wxFFile metaFile(metaFileName.GetFullPath(), L"wb"); - if (metaFile.IsOpened()) + if (auto metaFile = FileSystem::OpenManagedCFile(metaFileName.c_str(), "wb"); metaFile) { - metaFile.Write(entry->entry.raw, sizeof(entry->entry.raw)); + std::fwrite(entry->entry.raw, sizeof(entry->entry.raw), 1, metaFile.get()); } } else { // if metadata is standard make sure to remove a possibly existing metadata file - if (metaFileName.FileExists()) + if (FileSystem::FileExists(metaFileName.c_str())) { - wxRemoveFile(metaFileName.GetFullPath()); + FileSystem::DeleteFilePath(metaFileName.c_str()); } } // write the directory index - metaFileName.SetName(L"_pcsx2_index"); - std::optional yaml = loadYamlFile(metaFileName.GetFullPath()); + metaFileName = Path::Combine(fullSubDirPath, "_pcsx2_index"); + std::optional yaml = loadYamlFile(metaFileName.c_str()); // if _pcsx2_index hasn't been made yet, start a new file if (!yaml.has_value()) @@ -1290,7 +1295,7 @@ void FolderMemoryCard::FlushFileEntries(const u32 dirCluster, const u32 remainin ryml::NodeRef newNode = newYaml.rootref()["$ROOT"]; newNode["timeCreated"] << entry->entry.data.timeCreated.ToTime(); newNode["timeModified"] << entry->entry.data.timeModified.ToTime(); - SaveYAMLToFile(metaFileName.GetFullPath(), newYaml); + SaveYAMLToFile(metaFileName.c_str(), newYaml); } else if (!yaml.value().empty()) { @@ -1299,8 +1304,8 @@ void FolderMemoryCard::FlushFileEntries(const u32 dirCluster, const u32 remainin // Detect broken index files, every index file should have atleast ONE child ('[$%]ROOT') if (!index.has_children()) { - AttemptToRecreateIndexFile(Path::FromWxString(m_folderName.GetFullPath() + subDirPath)); - yaml = loadYamlFile(metaFileName.GetFullPath()); + AttemptToRecreateIndexFile(fullSubDirPath); + yaml = loadYamlFile(metaFileName.c_str()); index = yaml.value().rootref(); } @@ -1321,7 +1326,7 @@ void FolderMemoryCard::FlushFileEntries(const u32 dirCluster, const u32 remainin entryNode["timeModified"] << entry->entry.data.timeModified.ToTime(); // Write out the changes - SaveYAMLToFile(metaFileName.GetFullPath(), index); + SaveYAMLToFile(metaFileName.c_str(), index); } } } @@ -1343,24 +1348,24 @@ void FolderMemoryCard::FlushFileEntries(const u32 dirCluster, const u32 remainin char cleanName[sizeof(entry->entry.data.name)]; memcpy(cleanName, (const char*)entry->entry.data.name, sizeof(cleanName)); FileAccessHelper::CleanMemcardFilename(cleanName); - const wxString filePath = dirPath + L"/" + wxString::FromAscii((const char*)cleanName); - wxFileName fn(m_folderName.GetFullPath() + filePath); + const std::string fullDirPath(Path::Combine(m_folderName, dirPath)); + const std::string fn(Path::Combine(fullDirPath, cleanName)); - if (!fn.FileExists()) + if (!FileSystem::FileExists(fn.c_str())) { - if (!fn.DirExists()) + if (!FileSystem::DirectoryExists(fullDirPath.c_str())) { - fn.Mkdir(0777, wxPATH_MKDIR_FULL); + FileSystem::CreateDirectoryPath(fullDirPath.c_str(), false); } - wxFFile createEmptyFile(fn.GetFullPath(), L"wb"); - createEmptyFile.Close(); + + auto createEmptyFile = FileSystem::OpenManagedCFile(fn.c_str(), "wb"); } } } if (m_performFileWrites) { - FileAccessHelper::WriteIndex(m_folderName.GetFullPath() + dirPath, entry, parent); + FileAccessHelper::WriteIndex(m_folderName, entry, parent); } } } @@ -1381,7 +1386,7 @@ void FolderMemoryCard::FlushDeletedFilesAndRemoveUnchangedDataFromCache(const st FlushDeletedFilesAndRemoveUnchangedDataFromCache(oldFileEntries, newRootDirCluster, newFileCount, ""); } -void FolderMemoryCard::FlushDeletedFilesAndRemoveUnchangedDataFromCache(const std::vector& oldFileEntries, const u32 newCluster, const u32 newFileCount, const wxString& dirPath) +void FolderMemoryCard::FlushDeletedFilesAndRemoveUnchangedDataFromCache(const std::vector& oldFileEntries, const u32 newCluster, const u32 newFileCount, const std::string& dirPath) { // go through all file entires of the current directory of the old data for (auto it = oldFileEntries.cbegin(); it != oldFileEntries.cend(); ++it) @@ -1397,17 +1402,17 @@ void FolderMemoryCard::FlushDeletedFilesAndRemoveUnchangedDataFromCache(const st char cleanName[sizeof(entry->entry.data.name)]; memcpy(cleanName, (const char*)entry->entry.data.name, sizeof(cleanName)); FileAccessHelper::CleanMemcardFilename(cleanName); - const wxString fileName = wxString::FromAscii(cleanName); - const wxString filePath = m_folderName.GetFullPath() + dirPath + L"/" + fileName; + const std::string fullDirPath(Path::Combine(m_folderName, dirPath)); + const std::string filePath(Path::Combine(fullDirPath, cleanName)); m_lastAccessedFile.CloseMatching(filePath); - const wxString newFilePath = m_folderName.GetFullPath() + dirPath + L"/_pcsx2_deleted_" + fileName; - if (wxFileName::DirExists(newFilePath)) + const std::string newFilePath(Path::Combine(Path::Combine(m_folderName, dirPath), fmt::format("_pcsx2_deleted_{}", cleanName))); + if (FileSystem::DirectoryExists(newFilePath.c_str())) { // wxRenameFile doesn't overwrite directories, so we have to remove the old one first - RemoveWxDirectory(newFilePath); + FileSystem::RecursiveDeleteDirectory(newFilePath.c_str()); } - wxRenameFile(filePath, newFilePath); - DeleteFromIndex(m_folderName.GetFullPath() + dirPath, fileName); + FileSystem::RenamePath(filePath.c_str(), newFilePath.c_str()); + DeleteFromIndex(fullDirPath, cleanName); } else if (entry->IsDir()) { @@ -1415,8 +1420,7 @@ void FolderMemoryCard::FlushDeletedFilesAndRemoveUnchangedDataFromCache(const st char cleanName[sizeof(entry->entry.data.name)]; memcpy(cleanName, (const char*)entry->entry.data.name, sizeof(cleanName)); FileAccessHelper::CleanMemcardFilename(cleanName); - const wxString subDirName = wxString::FromAscii(cleanName); - const wxString subDirPath = dirPath + L"/" + subDirName; + const std::string subDirPath(Path::Combine(dirPath, cleanName)); FlushDeletedFilesAndRemoveUnchangedDataFromCache(it->subdir, newEntry->entry.data.cluster, newEntry->entry.data.length, subDirPath); } else if (entry->IsFile()) @@ -1533,8 +1537,8 @@ bool FolderMemoryCard::WriteToFile(const u8* src, u32 adr, u32 dataLength) if (m_performFileWrites) { - wxFFile* file = m_lastAccessedFile.ReOpen(m_folderName, &it->second, true); - if (file->IsOpened()) + std::FILE* file = m_lastAccessedFile.ReOpen(m_folderName, &it->second, true); + if (file) { const u32 clusterOffset = (page % 2) * PageSize + offset; const u32 fileSize = entry->entry.data.length; @@ -1542,26 +1546,24 @@ bool FolderMemoryCard::WriteToFile(const u8* src, u32 adr, u32 dataLength) const u32 fileOffsetEnd = std::min(fileOffsetStart + dataLength, fileSize); const u32 bytesToWrite = fileOffsetEnd - fileOffsetStart; - wxFileOffset actualFileSize = file->Length(); + u32 actualFileSize = static_cast(std::clamp(FileSystem::FSize64(file), 0, std::numeric_limits::max())); if (actualFileSize < fileOffsetStart) { - file->Seek(actualFileSize); + FileSystem::FSeek64(file, actualFileSize, SEEK_SET); const u32 diff = fileOffsetStart - actualFileSize; u8 temp = 0xFF; for (u32 i = 0; i < diff; ++i) { - file->Write(&temp, 1); + std::fwrite(&temp, 1, 1, file); } } - const wxFileOffset fileOffset = file->Tell(); - if (fileOffset != fileOffsetStart) + if (FileSystem::FTell64(file) == fileOffsetStart || FileSystem::FSeek64(file, fileOffsetStart, SEEK_SET) == 0) { - file->Seek(fileOffsetStart); - } - if (bytesToWrite > 0) - { - file->Write(src, bytesToWrite); + if (bytesToWrite > 0) + { + std::fwrite(src, bytesToWrite, 1, file); + } } } else @@ -1714,18 +1716,20 @@ void FolderMemoryCard::SetTimeLastReadToNow() void FolderMemoryCard::SetTimeLastWrittenToNow() { - m_timeLastWritten = wxGetLocalTimeMillis().GetValue(); + // CHANGE: this was local time milliseconds, which might be problematic... + m_timeLastWritten = std::time(nullptr);// wxGetLocalTimeMillis().GetValue(); m_framesUntilFlush = FramesAfterWriteUntilFlush; } -void FolderMemoryCard::AttemptToRecreateIndexFile(fs::path directory) const +void FolderMemoryCard::AttemptToRecreateIndexFile(const std::string& directory) const { // Attempt to fix broken index files (potentially broken in v1.7.2115, fixed in 1.7.2307 Console.Error(fmt::format("[Memcard] Folder memory card index file is malformed, backing up and attempting to re-create. This may not work for all games (ie. GTA), so backing up the current index file!. '{}'", - directory.string())); + directory)); // This isn't full-proof, so we backup the broken index file - fs::copy_file(directory / "_pcsx2_index", directory / "_pcsx2_index.invalid.bak", fs::copy_options::overwrite_existing); + FileSystem::CopyFilePath(Path::Combine(directory, "_pcsx2_index").c_str(), + Path::Combine(directory, "_pcsx2_index.invalid.bak").c_str(), true); // Create everything relative to a point in time, with an artifical delay to minimize edge-cases auto currTime = std::time(nullptr) - 1000; @@ -1736,16 +1740,17 @@ void FolderMemoryCard::AttemptToRecreateIndexFile(fs::path directory) const root.append_child() << ryml::key("$ROOT") |= ryml::MAP; root["$ROOT"]["timeCreated"] << currTime++; - for (const auto& entry : fs::directory_iterator(directory)) + FileSystem::FindResultsArray results; + FileSystem::FindFiles(directory.c_str(), "*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_RELATIVE_PATHS | FILESYSTEM_FIND_HIDDEN_FILES, &results); + for (const FILESYSTEM_FIND_DATA& fd : results) { - auto fileName = entry.path().filename().string(); - if (entry.is_directory() || fileName.rfind("_pcsx2_", 0) == 0) + if (fd.FileName.rfind("_pcsx2_", 0) == 0) { continue; } - root.append_child() << ryml::key(fileName) |= ryml::MAP; - ryml::NodeRef newNode = root[c4::to_csubstr(fileName)]; + root.append_child() << ryml::key(fd.FileName) |= ryml::MAP; + ryml::NodeRef newNode = root[c4::to_csubstr(fd.FileName)]; newNode["order"] << currOrder++; newNode["timeCreated"] << currTime++; newNode["timeModified"] << currTime++; @@ -1753,19 +1758,28 @@ void FolderMemoryCard::AttemptToRecreateIndexFile(fs::path directory) const root["$ROOT"]["timeModified"] << currTime; - auto file = FileSystem::OpenCFile((directory / "_pcsx2_index").string().c_str(), "w"); - - ryml::emit(tree, file); - std::fflush(file); - std::fclose(file); + auto file = FileSystem::OpenManagedCFile(Path::Combine(directory, "_pcsx2_index").c_str(), "w"); + if (file) + ryml::emit(tree, file.get()); } -std::vector FolderMemoryCard::GetOrderedFiles(const wxString& dirPath) const +std::string FolderMemoryCard::GetDisabledMessage(uint slot) const +{ + return fmt::format("The PS2-slot {} has been automatically disabled. You can correct the problem\nand re-enable it at any time using Config:Memory cards from the main menu.", slot); //TODO: translate internal slot index to human-readable slot description +} + +std::string FolderMemoryCard::GetCardFullMessage(const std::string& filePath) const +{ + return fmt::format("(FolderMcd) Memory Card is full, could not add: {}", filePath); +} + +std::vector FolderMemoryCard::GetOrderedFiles(const std::string& dirPath) const { std::vector result; - wxDir dir(dirPath); - if (dir.IsOpened()) + FileSystem::FindResultsArray results; + FileSystem::FindFiles(dirPath.c_str(), "*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_FOLDERS | FILESYSTEM_FIND_RELATIVE_PATHS | FILESYSTEM_FIND_HIDDEN_FILES, &results); + if (!results.empty()) { // We must be able to support legacy folder memcards without the index file, so for those // track an order variable and make it negative - this way new files get their order preserved @@ -1778,26 +1792,17 @@ std::vector FolderMemoryCard::GetOrderedF int64_t orderForDirectories = 1; int64_t orderForLegacyFiles = -1; - wxString fileName; - bool hasNext = dir.GetFirst(&fileName); - while (hasNext) + for (FILESYSTEM_FIND_DATA& fd : results) { - if (fileName.StartsWith(L"_pcsx2_")) - { - hasNext = dir.GetNext(&fileName); + if (StringUtil::StartsWith(fd.FileName, "_pcsx2_")) continue; - } - wxFileName fileInfo(dirPath, fileName); - if (wxFile::Exists(fileInfo.GetFullPath())) + std::string filePath(Path::Combine(dirPath, fd.FileName)); + if (!(fd.Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY)) { - wxDateTime creationTime, modificationTime; - fileInfo.GetTimes(nullptr, &modificationTime, &creationTime); + std::optional yaml = loadYamlFile(Path::Combine(dirPath, "_pcsx2_index").c_str()); - std::optional yaml = loadYamlFile(wxFileName(dirPath, "_pcsx2_index").GetFullPath()); - - EnumeratedFileEntry entry{fileName, creationTime.GetTicks(), modificationTime.GetTicks(), true}; - const wxCharTypeBuffer fileNameUTF8(fileName.ToUTF8()); + EnumeratedFileEntry entry{fd.FileName, fd.CreationTime, fd.ModificationTime, true}; int64_t newOrder = orderForLegacyFiles--; if (yaml.has_value() && !yaml.value().empty()) { @@ -1806,9 +1811,9 @@ std::vector FolderMemoryCard::GetOrderedF { auto key = std::string(n.key().str, n.key().len); } - if (index.has_child(c4::to_csubstr(fileNameUTF8))) + if (index.has_child(c4::to_csubstr(fd.FileName))) { - const ryml::NodeRef& node = index[c4::to_csubstr(fileNameUTF8)]; + const ryml::NodeRef& node = index[c4::to_csubstr(fd.FileName)]; if (node.has_child("timeCreated")) { node["timeCreated"] >> entry.m_timeCreated; @@ -1830,16 +1835,12 @@ std::vector FolderMemoryCard::GetOrderedF } else { - fileInfo.AppendDir(fileInfo.GetFullName()); - fileInfo.SetName(L""); + std::string subDirPath(Path::Combine(dirPath, fd.FileName)); - wxDateTime creationTime, modificationTime; - fileInfo.GetTimes(nullptr, &modificationTime, &creationTime); + std::string subDirIndexPath(Path::Combine(subDirPath, "_pcsx2_index")); + std::optional yaml = loadYamlFile(subDirIndexPath.c_str()); - auto fullPath = wxFileName(fileInfo.GetFullPath(), "_pcsx2_index").GetFullPath(); - std::optional yaml = loadYamlFile(fullPath); - - EnumeratedFileEntry entry{fileName, creationTime.GetTicks(), modificationTime.GetTicks(), false}; + EnumeratedFileEntry entry{fd.FileName, fd.CreationTime, fd.ModificationTime, false}; if (yaml.has_value() && !yaml.value().empty()) { ryml::NodeRef indexForDirectory = yaml.value().rootref(); @@ -1847,8 +1848,8 @@ std::vector FolderMemoryCard::GetOrderedF // Detect broken index files, every index file should have atleast ONE child ('[$%]ROOT') if (!indexForDirectory.has_children()) { - AttemptToRecreateIndexFile(Path::FromWxString(fileInfo.GetFullPath())); - yaml = loadYamlFile(fullPath); + AttemptToRecreateIndexFile(subDirPath); + yaml = loadYamlFile(subDirIndexPath.c_str()); indexForDirectory = yaml.value().rootref(); } @@ -1886,8 +1887,6 @@ std::vector FolderMemoryCard::GetOrderedF auto key = std::make_pair(false, orderForDirectories++); sortContainer.try_emplace(std::move(key), std::move(entry)); } - - hasNext = dir.GetNext(&fileName); } // Move items from the intermediate map to a final vector @@ -1901,19 +1900,18 @@ std::vector FolderMemoryCard::GetOrderedF return result; } -void FolderMemoryCard::DeleteFromIndex(const wxString& filePath, const wxString& entry) const +void FolderMemoryCard::DeleteFromIndex(const std::string& filePath, const std::string_view& entry) const { - const wxString indexName = wxFileName(filePath, "_pcsx2_index").GetFullPath(); + const std::string indexName(Path::Combine(filePath, "_pcsx2_index")); - std::optional yaml = loadYamlFile(indexName); + std::optional yaml = loadYamlFile(indexName.c_str()); if (yaml.has_value() && !yaml.value().empty()) { ryml::NodeRef index = yaml.value().rootref(); - const wxCharTypeBuffer key(entry.ToUTF8()); - index.remove_child(c4::to_csubstr(key)); + index.remove_child(c4::csubstr(entry.data(), entry.length())); // Write out the changes - SaveYAMLToFile(indexName, index); + SaveYAMLToFile(indexName.c_str(), index); } } @@ -1965,16 +1963,21 @@ void FolderMemoryCard::CalculateECC(u8* ecc, const u8* data) return; } -void FolderMemoryCard::WriteToFile(const wxString& filename) +void FolderMemoryCard::WriteToFile(const std::string& filename) { - wxFFile targetFile(filename, L"wb"); + auto targetFile = FileSystem::OpenManagedCFile(filename.c_str(), "wb"); + if (!targetFile) + { + Console.Error("(FolderMemoryCard::WriteToFile) Failed to open '%s'.", filename.c_str()); + return; + } u8 buffer[FolderMemoryCard::PageSizeRaw]; u32 adr = 0; while (adr < GetSizeInClusters() * FolderMemoryCard::ClusterSizeRaw) { Read(buffer, adr, FolderMemoryCard::PageSizeRaw); - targetFile.Write(buffer, FolderMemoryCard::PageSizeRaw); + std::fwrite(buffer, FolderMemoryCard::PageSizeRaw, 1, targetFile.get()); adr += FolderMemoryCard::PageSizeRaw; } } @@ -1989,23 +1992,21 @@ FileAccessHelper::~FileAccessHelper() this->CloseAll(); } -wxFFile* FileAccessHelper::Open(const wxFileName& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata) +std::FILE* FileAccessHelper::Open(const std::string_view& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata /* = false */) { - wxFileName fn(folderName); - fileRef->GetPath(&fn); - wxString filename(fn.GetFullPath()); + std::string filename(folderName); + fileRef->GetPath(&filename); - if (!fn.FileExists()) + if (!FileSystem::FileExists(filename.c_str())) { - if (!fn.DirExists()) - { - fn.Mkdir(0777, wxPATH_MKDIR_FULL); - } - wxFFile createEmptyFile(filename, L"wb"); - createEmptyFile.Close(); + const std::string directory(Path::GetDirectory(filename)); + if (!FileSystem::DirectoryExists(directory.c_str())) + FileSystem::CreateDirectoryPath(directory.c_str(), true); + + auto createEmptyFile = FileSystem::OpenManagedCFile(filename.c_str(), "wb"); } - wxFFile* file = new wxFFile(filename, L"r+b"); + std::FILE* file = FileSystem::OpenCFile(filename.c_str(), "r+b"); std::string internalPath; fileRef->GetInternalPath(&internalPath); @@ -2022,10 +2023,12 @@ wxFFile* FileAccessHelper::Open(const wxFileName& folderName, MemoryCardFileMeta return file; } -void FileAccessHelper::WriteMetadata(wxFileName folderName, const MemoryCardFileMetadataReference* fileRef) +void FileAccessHelper::WriteMetadata(const std::string_view& folderName, const MemoryCardFileMetadataReference* fileRef) { - const bool cleanedFilename = fileRef->GetPath(&folderName); - folderName.AppendDir(L"_pcsx2_meta"); + std::string fileName(folderName); + const bool cleanedFilename = fileRef->GetPath(&fileName); + std::string metaFileName(Path::AppendDirectory(fileName, "_pcsx2_meta")); + std::string metaDirName(Path::GetDirectory(metaFileName)); const auto* entry = &fileRef->entry->entry; const bool metadataIsNonstandard = cleanedFilename || entry->data.mode != MemoryCardFileEntry::DefaultFileMode || entry->data.attr != 0; @@ -2033,54 +2036,43 @@ void FileAccessHelper::WriteMetadata(wxFileName folderName, const MemoryCardFile if (metadataIsNonstandard) { // write metadata of file if it's nonstandard - if (!folderName.DirExists()) + if (!FileSystem::DirectoryExists(metaDirName.c_str())) { - folderName.Mkdir(); - } - wxFFile metaFile(folderName.GetFullPath(), L"wb"); - if (metaFile.IsOpened()) - { - metaFile.Write(entry->raw, sizeof(entry->raw)); + FileSystem::CreateDirectoryPath(metaDirName.c_str(), false); } + + auto metaFile = FileSystem::OpenManagedCFile(metaFileName.c_str(), "wb"); + if (metaFile) + std::fwrite(entry->raw, sizeof(entry->raw), 1, metaFile.get()); } else { // if metadata is standard remove metadata file if it exists - if (folderName.FileExists()) + if (FileSystem::DirectoryExists(metaDirName.c_str())) { - wxRemoveFile(folderName.GetFullPath()); + FileSystem::DeleteFilePath(metaFileName.c_str()); // and remove the metadata dir if it's now empty - wxDir metaDir(folderName.GetPath()); - if (metaDir.IsOpened() && !metaDir.HasFiles()) - { - wxRmdir(folderName.GetPath()); - } + if (FileSystem::DirectoryIsEmpty(metaDirName.c_str())) + FileSystem::DeleteDirectory(metaDirName.c_str()); } } } -void FileAccessHelper::WriteIndex(wxFileName folderName, MemoryCardFileEntry* const entry, MemoryCardFileMetadataReference* const parent) +void FileAccessHelper::WriteIndex(const std::string& baseFolderName, MemoryCardFileEntry* const entry, MemoryCardFileMetadataReference* const parent) { + // Not called for directories atm. + pxAssert(entry->IsFile()); + + std::string folderName(baseFolderName); parent->GetPath(&folderName); char cleanName[sizeof(entry->entry.data.name)]; memcpy(cleanName, (const char*)entry->entry.data.name, sizeof(cleanName)); FileAccessHelper::CleanMemcardFilename(cleanName); - if (entry->IsDir()) - { - folderName.AppendDir(wxString::FromAscii(cleanName)); - } - else if (entry->IsFile()) - { - folderName.SetName(wxString::FromAscii(cleanName)); - } - - const wxCharTypeBuffer fileName(folderName.GetName().ToUTF8()); - folderName.SetName(L"_pcsx2_index"); - - const c4::csubstr key = c4::to_csubstr(fileName); - std::optional yaml = loadYamlFile(folderName.GetFullPath()); + const std::string indexFileName(Path::Combine(folderName, "_pcsx2_index")); + const c4::csubstr key = c4::to_csubstr(cleanName); + std::optional yaml = loadYamlFile(indexFileName.c_str()); if (yaml.has_value() && !yaml.value().empty()) { @@ -2111,11 +2103,11 @@ void FileAccessHelper::WriteIndex(wxFileName folderName, MemoryCardFileEntry* co entryNode["timeModified"] << e->timeModified.ToTime(); // Write out the changes - SaveYAMLToFile(folderName.GetFullPath(), index); + SaveYAMLToFile(indexFileName.c_str(), index); } } -wxFFile* FileAccessHelper::ReOpen(const wxFileName& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata) +std::FILE* FileAccessHelper::ReOpen(const std::string_view& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata /* = false */) { std::string internalPath; fileRef->GetInternalPath(&internalPath); @@ -2152,22 +2144,20 @@ wxFFile* FileAccessHelper::ReOpen(const wxFileName& folderName, MemoryCardFileMe } } -void FileAccessHelper::CloseFileHandle(wxFFile* file, const MemoryCardFileEntry* entry) +void FileAccessHelper::CloseFileHandle(std::FILE*& file, const MemoryCardFileEntry* entry /* = nullptr */) { - file->Close(); - - delete file; + if (file) + { + std::fclose(file); + file = nullptr; + } } -void FileAccessHelper::CloseMatching(const wxString& path) +void FileAccessHelper::CloseMatching(const std::string_view& path) { - wxFileName fn(path); - fn.Normalize(); - wxString pathNormalized = fn.GetFullPath(); for (auto it = m_files.begin(); it != m_files.end();) { - wxString openPath = it->second.fileHandle->GetName(); - if (openPath.StartsWith(pathNormalized)) + if (StringUtil::StartsWith(it->second.hostFilePath, path)) { CloseFileHandle(it->second.fileHandle, it->second.fileRef->entry); it = m_files.erase(it); @@ -2192,7 +2182,7 @@ void FileAccessHelper::FlushAll() { for (auto it = m_files.begin(); it != m_files.end(); ++it) { - it->second.fileHandle->Flush(); + std::fflush(it->second.fileHandle); } } @@ -2248,7 +2238,7 @@ bool FileAccessHelper::CleanMemcardFilenameEndDotOrSpace(char* name, size_t leng return cleaned; } -bool MemoryCardFileMetadataReference::GetPath(wxFileName* fileName) const +bool MemoryCardFileMetadataReference::GetPath(std::string* fileName) const { bool parentCleaned = false; if (parent) @@ -2260,13 +2250,9 @@ bool MemoryCardFileMetadataReference::GetPath(wxFileName* fileName) const memcpy(cleanName, (const char*)entry->entry.data.name, sizeof(cleanName)); bool localCleaned = FileAccessHelper::CleanMemcardFilename(cleanName); - if (entry->IsDir()) + if (entry->IsDir() || entry->IsFile()) { - fileName->AppendDir(wxString::FromAscii(cleanName)); - } - else if (entry->IsFile()) - { - fileName->SetName(wxString::FromAscii(cleanName)); + *fileName = Path::Combine(*fileName, cleanName); } return parentCleaned || localCleaned; @@ -2356,7 +2342,7 @@ void FolderMemoryCardAggregator::NextFrame(uint slot) m_cards[slot].NextFrame(); } -bool FolderMemoryCardAggregator::ReIndex(uint slot, const bool enableFiltering, const wxString& filter) +bool FolderMemoryCardAggregator::ReIndex(uint slot, const bool enableFiltering, const std::string& filter) { if (m_cards[slot].ReIndex(enableFiltering, filter)) { diff --git a/pcsx2/MemoryCardFolder.h b/pcsx2/MemoryCardFolder.h index 3218774871..8d3d91b67f 100644 --- a/pcsx2/MemoryCardFolder.h +++ b/pcsx2/MemoryCardFolder.h @@ -15,10 +15,9 @@ #pragma once -#include -#include -#include #include +#include +#include #include #include "Config.h" @@ -64,61 +63,9 @@ struct MemoryCardFileEntryDateTime u8 month; u16 year; - static MemoryCardFileEntryDateTime FromWxDateTime(const wxDateTime& time) - { - MemoryCardFileEntryDateTime t; + static MemoryCardFileEntryDateTime FromTime(time_t time); - if (time.IsValid()) - { - wxDateTime::Tm tm = time.GetTm(wxDateTime::GMT9); - - t.unused = 0; - t.second = tm.sec; - t.minute = tm.min; - t.hour = tm.hour; - t.day = tm.mday; - t.month = tm.mon + 1; - t.year = tm.year; - } - else - { - t.unused = 0; - t.second = 0; - t.minute = 0; - t.hour = 0; - t.day = 0; - t.month = 0; - t.year = 0; - } - - return t; - } - - static MemoryCardFileEntryDateTime FromTime(time_t time) - { - // TODO: When wx is gone, this will have to be handled differently; for now, rely on wx - return FromWxDateTime(wxDateTime(time)); - } - - wxDateTime ToWxDateTime() const - { - wxDateTime::Tm tm; - tm.sec = this->second; - tm.min = this->minute; - tm.hour = this->hour; - tm.mday = this->day; - tm.mon = (wxDateTime::Month)(this->month - 1); - tm.year = this->year; - - wxDateTime time(tm); - return time.FromTimezone(wxDateTime::GMT9); - } - - time_t ToTime() const - { - // TODO: When wx is gone, this will have to be handled differently; for now, rely on wx - return ToWxDateTime().GetTicks(); - } + time_t ToTime() const; bool operator==(const MemoryCardFileEntryDateTime& other) const { @@ -228,7 +175,7 @@ struct MemoryCardFileMetadataReference u32 consecutiveCluster; // returns true if filename was modified and metadata containing the actual filename should be written - bool GetPath(wxFileName* fileName) const; + bool GetPath(std::string* fileName) const; // gives the internal memory card file system path, not to be used for writes to the host file system void GetInternalPath(std::string* fileName) const; @@ -237,7 +184,8 @@ struct MemoryCardFileMetadataReference struct MemoryCardFileHandleStructure { MemoryCardFileMetadataReference* fileRef; - wxFFile* fileHandle; + std::string hostFilePath; + std::FILE* fileHandle; }; // -------------------------------------------------------------------------------------- @@ -255,9 +203,9 @@ public: ~FileAccessHelper(); // Get an already opened file if possible, or open a new one and remember it - wxFFile* ReOpen(const wxFileName& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata = false); + std::FILE* ReOpen(const std::string_view& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata = false); // Close all open files that start with the given path, so either a file if a filename is given or all files in a directory and its subdirectories when a directory is given - void CloseMatching(const wxString& path); + void CloseMatching(const std::string_view& path); // Close all open files void CloseAll(); // Flush the written data of all open files to the file system @@ -270,19 +218,19 @@ public: // returns true if any changes were made static bool CleanMemcardFilename(char* name); - static void WriteIndex(wxFileName folderName, MemoryCardFileEntry* const entry, MemoryCardFileMetadataReference* const parent); + static void WriteIndex(const std::string& baseFolderName, MemoryCardFileEntry* const entry, MemoryCardFileMetadataReference* const parent); private: // helper function for CleanMemcardFilename() static bool CleanMemcardFilenameEndDotOrSpace(char* name, size_t length); // Open a new file and remember it for later - wxFFile* Open(const wxFileName& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata = false); + std::FILE* Open(const std::string_view& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata = false); // Close a file and delete its handle // If entry is given, it also attempts to set the created and modified timestamps of the file according to the entry - void CloseFileHandle(wxFFile* file, const MemoryCardFileEntry* entry = nullptr); + void CloseFileHandle(std::FILE*& file, const MemoryCardFileEntry* entry = nullptr); - void WriteMetadata(wxFileName folderName, const MemoryCardFileMetadataReference* fileRef); + void WriteMetadata(const std::string_view& folderName, const MemoryCardFileMetadataReference* fileRef); }; // -------------------------------------------------------------------------------------- @@ -357,7 +305,7 @@ protected: FileAccessHelper m_lastAccessedFile; // path to the folder that contains the files of this memory card - wxFileName m_folderName; + std::string m_folderName; // PS2 memory card slot this card is inserted into uint m_slot; @@ -369,7 +317,7 @@ protected: // currently active filter settings bool m_filteringEnabled; - wxString m_filteringString; + std::string m_filteringString; public: FolderMemoryCard(); @@ -379,16 +327,16 @@ public: void Unlock(); // Initialize & Load Memory Card with values configured in the Memory Card Manager - void Open(const bool enableFiltering, const wxString& filter); + void Open(const bool enableFiltering, std::string filter); // Initialize & Load Memory Card with provided custom values - void Open(const wxString& fullPath, const Pcsx2Config::McdOptions& mcdOptions, const u32 sizeInClusters, const bool enableFiltering, const wxString& filter, bool simulateFileWrites = false); + void Open(std::string fullPath, const Pcsx2Config::McdOptions& mcdOptions, const u32 sizeInClusters, const bool enableFiltering, std::string filter, bool simulateFileWrites = false); // Close the memory card and flush changes to the file system. Set flush to false to not store changes. void Close(bool flush = true); // Closes and reopens card with given filter options if they differ from the current ones (returns true), // or does nothing if they match already (returns false). // Does nothing and returns false when called on a closed memory card. - bool ReIndex(bool enableFiltering, const wxString& filter); + bool ReIndex(bool enableFiltering, const std::string& filter); s32 IsPresent() const; void GetSizeInfo(McdSizeInfo& outways) const; @@ -413,12 +361,12 @@ public: static void CalculateECC(u8* ecc, const u8* data); - void WriteToFile(const wxString& filename); + void WriteToFile(const std::string& filename); protected: struct EnumeratedFileEntry { - wxString m_fileName; // TODO: Replace with std::string + std::string m_fileName; time_t m_timeCreated; time_t m_timeModified; bool m_isFile; @@ -457,14 +405,14 @@ protected: // - originalDirCount: the point in fileName where to insert the found folder path, usually fileName->GetDirCount() // - outClusterNumber: the cluster's sequential number of the file will be written to this pointer, // which can be used to calculate the in-file offset of the address being accessed - MemoryCardFileEntry* GetFileEntryFromFileDataCluster(const u32 currentCluster, const u32 searchCluster, wxFileName* fileName, const size_t originalDirCount, u32* outClusterNumber); + MemoryCardFileEntry* GetFileEntryFromFileDataCluster(const u32 currentCluster, const u32 searchCluster, std::string* fileName, const size_t originalDirCount, u32* outClusterNumber); // loads files and folders from the host file system if a superblock exists in the root directory // - sizeInClusters: total memory card size in clusters, 0 for default // - enableFiltering: if set to true, only folders whose name contain the filter string are loaded // - filter: can include multiple filters by separating them with "/" - void LoadMemoryCardData(const u32 sizeInClusters, const bool enableFiltering, const wxString& filter); + void LoadMemoryCardData(const u32 sizeInClusters, const bool enableFiltering, const std::string& filter); // creates the FAT and indirect FAT void CreateFat(); @@ -500,17 +448,17 @@ protected: // - dirPath: the full path to the directory in the host file system // - parent: pointer to the parent dir's quick-access reference element // - enableFiltering and filter: filter loaded contents, see LoadMemoryCardData() - bool AddFolder(MemoryCardFileEntry* const dirEntry, const wxString& dirPath, MemoryCardFileMetadataReference* parent = nullptr, const bool enableFiltering = false, const wxString& filter = L""); + bool AddFolder(MemoryCardFileEntry* const dirEntry, const std::string& dirPath, MemoryCardFileMetadataReference* parent = nullptr, const bool enableFiltering = false, const std::string_view& filter = ""); // adds a file in the host file sytem to the memory card // - dirEntry: the entry of the directory in the parent directory, or the root "." entry // - dirPath: the full path to the directory containing the file in the host file system // - fileName: the name of the file, without path // - parent: pointer to the parent dir's quick-access reference element - bool AddFile(MemoryCardFileEntry* const dirEntry, const wxString& dirPath, const EnumeratedFileEntry& fileEntry, MemoryCardFileMetadataReference* parent = nullptr); + bool AddFile(MemoryCardFileEntry* const dirEntry, const std::string& dirPath, const EnumeratedFileEntry& fileEntry, MemoryCardFileMetadataReference* parent = nullptr); // calculates the amount of clusters a directory would use up if put into a memory card - u32 CalculateRequiredClustersOfDirectory(const wxString& dirPath) const; + u32 CalculateRequiredClustersOfDirectory(const std::string& dirPath) const; // adds a file to the quick-access dictionary, so it can be accessed more efficiently (ie, without searching through the entire file system) later @@ -549,7 +497,7 @@ protected: void FlushFileEntries(); // flush a directory's file entries and all its subdirectories to the internal data - void FlushFileEntries(const u32 dirCluster, const u32 remainingFiles, const wxString& dirPath = L"", MemoryCardFileMetadataReference* parent = nullptr); + void FlushFileEntries(const u32 dirCluster, const u32 remainingFiles, const std::string& dirPath = {}, MemoryCardFileMetadataReference* parent = nullptr); // "delete" (prepend '_pcsx2_deleted_' to) any files that exist in oldFileEntries but no longer exist in m_fileEntryDict // also calls RemoveUnchangedDataFromCache() since both operate on comparing with the old file entires @@ -559,7 +507,7 @@ protected: // - newCluster: Current directory dotdir cluster of the new entries. // - newFileCount: Number of file entries in the new directory. // - dirPath: Path to the current directory relative to the root of the memcard. Must be identical for both entries. - void FlushDeletedFilesAndRemoveUnchangedDataFromCache(const std::vector& oldFileEntries, const u32 newCluster, const u32 newFileCount, const wxString& dirPath); + void FlushDeletedFilesAndRemoveUnchangedDataFromCache(const std::vector& oldFileEntries, const u32 newCluster, const u32 newFileCount, const std::string& dirPath); // try and remove unchanged data from m_cache // oldEntry and newEntry should be equivalent entries found by FindEquivalent() @@ -577,23 +525,16 @@ protected: void SetTimeLastReadToNow(); void SetTimeLastWrittenToNow(); - void AttemptToRecreateIndexFile(fs::path directory) const; + void AttemptToRecreateIndexFile(const std::string& directory) const; - std::string GetDisabledMessage(uint slot) const - { - return fmt::format("The PS2-slot {} has been automatically disabled. You can correct the problem\nand re-enable it at any time using Config:Memory cards from the main menu.", slot //TODO: translate internal slot index to human-readable slot description - ); - } - std::string GetCardFullMessage(const std::string_view& filePath) const - { - return fmt::format("(FolderMcd) Memory Card is full, could not add: {}", filePath); - } + std::string GetDisabledMessage(uint slot) const; + std::string GetCardFullMessage(const std::string& filePath) const; // get the list of files (and their timestamps) in directory ordered as specified by the index file // for legacy entries without an entry in the index file, order is unspecified and should not be relied on - std::vector GetOrderedFiles(const wxString& dirPath) const; + std::vector GetOrderedFiles(const std::string& dirPath) const; - void DeleteFromIndex(const wxString& filePath, const wxString& entry) const; + void DeleteFromIndex(const std::string& filePath, const std::string_view& entry) const; }; // -------------------------------------------------------------------------------------- @@ -609,7 +550,7 @@ protected: // stores the specifics of the current filtering settings, so they can be // re-applied automatically when memory cards are reloaded bool m_enableFiltering = true; - wxString m_lastKnownFilter = L""; + std::string m_lastKnownFilter; public: FolderMemoryCardAggregator(); @@ -628,5 +569,5 @@ public: s32 EraseBlock(uint slot, u32 adr); u64 GetCRC(uint slot); void NextFrame(uint slot); - bool ReIndex(uint slot, const bool enableFiltering, const wxString& filter); + bool ReIndex(uint slot, const bool enableFiltering, const std::string& filter); }; diff --git a/pcsx2/MultipartFileReader.cpp b/pcsx2/MultipartFileReader.cpp index 5265beee95..480279d232 100644 --- a/pcsx2/MultipartFileReader.cpp +++ b/pcsx2/MultipartFileReader.cpp @@ -16,21 +16,25 @@ #include "PrecompiledHeader.h" #include "AsyncFileReader.h" #include "common/Assertions.h" +#include "common/FileSystem.h" #include "common/Path.h" #include "common/StringUtil.h" // Tests for a filename extension in both upper and lower case, if the filesystem happens // to be case-sensitive. -bool pxFileExists_WithExt( const wxFileName& filename, const wxString& ext ) +static bool pxFileExists_WithExt( const std::string& filename, const std::string& ext ) { - wxFileName part1 = filename; - part1.SetExt( ext.Lower() ); + std::string temp(Path::ReplaceExtension(filename, StringUtil::toLower(ext))); + if (FileSystem::FileExists(temp.c_str())) + return true; - if (part1.FileExists()) return true; - if (!wxFileName::IsCaseSensitive()) return false; +#if defined(_WIN32) || defined(__DARWIN__) + temp = Path::ReplaceExtension(filename, StringUtil::toUpper(ext)); + if (FileSystem::FileExists(temp.c_str())) + return true; +#endif - part1.SetExt( ext.Upper() ); - return part1.FileExists(); + return false; } AsyncFileReader* MultipartFileReader::DetectMultipart(AsyncFileReader* reader) @@ -69,9 +73,11 @@ MultipartFileReader::~MultipartFileReader(void) void MultipartFileReader::FindParts() { - wxFileName nameparts( StringUtil::UTF8StringToWxString(m_filename) ); - wxString curext( nameparts.GetExt() ); - wxChar prefixch = wxTolower(curext[0]); + std::string curext(Path::GetExtension(m_filename)); + if (curext.empty()) + return; + + char prefixch = std::tolower(curext[0]); // Multi-part rules! // * The first part can either be the proper extension (ISO, MDF, etc) or the numerical @@ -81,18 +87,18 @@ void MultipartFileReader::FindParts() uint i = 0; - if ((curext.Length() == 3) && (curext[1] == L'0') && (curext[2] == L'0')) + if ((curext.length() == 3) && (curext[1] == '0') && (curext[2] == '0')) { // First file is an OO, so skip 0 in the loop below: i = 1; } - wxString extbuf = wxString::Format(L"%c%02u", prefixch, i ); - nameparts.SetExt( extbuf ); + std::string extbuf(StringUtil::StdStringFromFormat("%c%02u", prefixch, i)); + std::string nameparts(Path::ReplaceExtension(m_filename, extbuf)); if (!pxFileExists_WithExt(nameparts, extbuf)) return; - DevCon.WriteLn( Color_Blue, "isoFile: multi-part %s detected...", curext.Upper().ToUTF8().data() ); + DevCon.WriteLn( Color_Blue, "isoFile: multi-part %s detected...", StringUtil::toUpper(curext).c_str() ); ConsoleIndentScope indent; int bsize = m_parts[0].reader->GetBlockSize(); @@ -102,17 +108,15 @@ void MultipartFileReader::FindParts() for (; i < MaxParts; ++i) { - extbuf = wxString::Format(L"%c%02u", prefixch, i ); - nameparts.SetExt( extbuf ); + extbuf = StringUtil::StdStringFromFormat("%c%02u", prefixch, i ); + nameparts = Path::ReplaceExtension(m_filename, extbuf); if (!pxFileExists_WithExt(nameparts, extbuf)) break; Part* thispart = m_parts + m_numparts; AsyncFileReader* thisreader = thispart->reader = new FlatFileReader(); - wxString name = nameparts.GetFullPath(); - - thisreader->Open(StringUtil::wxStringToUTF8String(name)); + thisreader->Open(nameparts); thisreader->SetBlockSize(bsize); thispart->start = blocks; @@ -124,7 +128,7 @@ void MultipartFileReader::FindParts() DevCon.WriteLn( Color_Blue, "\tblocks %u - %u in: %s", thispart->start, thispart->end, - nameparts.GetFullPath().ToUTF8().data() + nameparts.c_str() ); ++m_numparts; diff --git a/pcsx2/PAD/Linux/Config.cpp b/pcsx2/PAD/Linux/Config.cpp index 1d8b666bf1..f74af285a8 100644 --- a/pcsx2/PAD/Linux/Config.cpp +++ b/pcsx2/PAD/Linux/Config.cpp @@ -17,6 +17,7 @@ #include "Global.h" #include "Device.h" #include "keyboard.h" +#include "common/Path.h" #ifdef __APPLE__ #include #endif @@ -60,8 +61,7 @@ void PADSaveConfig() { FILE* f; - wxString iniName(L"PAD.ini"); - const std::string iniFile = std::string(EmuFolders::Settings.Combine(iniName).GetFullPath()); // default path, just in case + const std::string iniFile = Path::Combine(EmuFolders::Settings, "PAD.ini"); // default path, just in case f = fopen(iniFile.c_str(), "w"); if (f == NULL) { @@ -97,8 +97,7 @@ void PADLoadConfig() g_conf.init(); - wxString iniName(L"PAD.ini"); - const std::string iniFile = std::string(EmuFolders::Settings.Combine(iniName).GetFullPath()); // default path, just in case + const std::string iniFile = Path::Combine(EmuFolders::Settings, "PAD.ini"); // default path, just in case f = fopen(iniFile.c_str(), "r"); if (f == nullptr) { diff --git a/pcsx2/PAD/Windows/Diagnostics.cpp b/pcsx2/PAD/Windows/Diagnostics.cpp index 1e863a57d2..ae0fa2eaaa 100644 --- a/pcsx2/PAD/Windows/Diagnostics.cpp +++ b/pcsx2/PAD/Windows/Diagnostics.cpp @@ -14,6 +14,8 @@ */ #include "PrecompiledHeader.h" +#include "common/RedtapeWindows.h" + #include "Global.h" #include "DeviceEnumerator.h" #include "KeyboardQueue.h" diff --git a/pcsx2/PAD/Windows/Global.h b/pcsx2/PAD/Windows/Global.h index 0a8b747be0..6287746489 100644 --- a/pcsx2/PAD/Windows/Global.h +++ b/pcsx2/PAD/Windows/Global.h @@ -21,6 +21,7 @@ #include #include #include "common/Console.h" +#include "common/RedtapeWindows.h" #include #include diff --git a/pcsx2/PAD/Windows/PADConfig.cpp b/pcsx2/PAD/Windows/PADConfig.cpp index c43c737921..8bd3f977f2 100644 --- a/pcsx2/PAD/Windows/PADConfig.cpp +++ b/pcsx2/PAD/Windows/PADConfig.cpp @@ -16,6 +16,9 @@ #include "PrecompiledHeader.h" #include "Global.h" +#include "common/Path.h" +#include "common/StringUtil.h" + #include "resource_pad.h" #include "InputManager.h" #include "PADConfig.h" @@ -335,8 +338,7 @@ void PADsetSettingsDir(const char* dir) //swprintf_s( iniFileUSB, L"%S", (dir==NULL) ? "inis" : dir ); //uint targlen = MultiByteToWideChar(CP_ACP, 0, dir, -1, NULL, 0); - wxString iniName = "PAD.ini"; - StrCpyNW(iniFileUSB, EmuFolders::Settings.Combine(iniName).GetFullPath(), std::size(iniFileUSB)); + StrCpyNW(iniFileUSB, StringUtil::UTF8StringToWideString(Path::Combine(EmuFolders::Settings, "PAD.ini")).c_str(), std::size(iniFileUSB)); createIniDir = false; diff --git a/pcsx2/PAD/Windows/WndProcEater.h b/pcsx2/PAD/Windows/WndProcEater.h index 80c24daeb8..e14b08e96e 100644 --- a/pcsx2/PAD/Windows/WndProcEater.h +++ b/pcsx2/PAD/Windows/WndProcEater.h @@ -10,9 +10,11 @@ * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . + * If not, see .4 */ +#include "common/RedtapeWindows.h" + #define EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES 1 /* Need this to let window be subclassed multiple times but still clean up nicely. diff --git a/pcsx2/Patch.cpp b/pcsx2/Patch.cpp index a0f217c547..9871775a21 100644 --- a/pcsx2/Patch.cpp +++ b/pcsx2/Patch.cpp @@ -18,12 +18,12 @@ #define _PC_ // disables MIPS opcode macros. #include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" #include "common/ZipHelpers.h" #include "Config.h" #include "Patch.h" -#include "PathDefs.h" #include #include @@ -165,29 +165,29 @@ int LoadPatchesFromZip(const std::string& crc, const u8* zip_data, size_t zip_da // This routine loads patches from *.pnach files // Returns number of patches loaded // Note: does not reset previously loaded patches (use ForgetLoadedPatches() for that) -int LoadPatchesFromDir(const std::string& crc, const wxDirName& folder, const char* friendly_name, bool show_error_when_missing) +int LoadPatchesFromDir(const std::string& crc, const std::string& folder, const char* friendly_name, bool show_error_when_missing) { - if (!folder.Exists()) + if (!FileSystem::DirectoryExists(folder.c_str())) { - Console.WriteLn(Color_Red, "The %s folder ('%s') is inaccessible. Skipping...", friendly_name, folder.ToUTF8().data()); + Console.WriteLn(Color_Red, "The %s folder ('%s') is inaccessible. Skipping...", friendly_name, folder.c_str()); return 0; } FileSystem::FindResultsArray files; - FileSystem::FindFiles(folder.ToUTF8(), StringUtil::StdStringFromFormat("*.pnach", crc.c_str()).c_str(), + FileSystem::FindFiles(folder.c_str(), StringUtil::StdStringFromFormat("*.pnach", crc.c_str()).c_str(), FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES, &files); if (show_error_when_missing && files.empty()) { PatchesCon->WriteLn(Color_Gray, "Not found %s file: %s" FS_OSPATH_SEPARATOR_STR "%s.pnach", - friendly_name, folder.ToUTF8().data(), crc.c_str()); + friendly_name, folder.c_str(), crc.c_str()); } int total_loaded = 0; for (const FILESYSTEM_FIND_DATA& fd : files) { - const std::string_view name(FileSystem::GetFileNameFromPath(fd.FileName)); + const std::string_view name(Path::GetFileName(fd.FileName)); if (name.length() < crc.length() || StringUtil::Strncasecmp(name.data(), crc.c_str(), crc.size()) != 0) continue; diff --git a/pcsx2/Patch.h b/pcsx2/Patch.h index 1dd733dd7b..5707097687 100644 --- a/pcsx2/Patch.h +++ b/pcsx2/Patch.h @@ -38,6 +38,7 @@ #include "common/Pcsx2Defs.h" #include "SysForwardDefs.h" #include "GameDatabase.h" +#include #include enum patch_cpu_type { @@ -108,7 +109,7 @@ namespace PatchFunc // - do not reset/unload previously loaded patches (use ForgetLoadedPatches() for that) // - do not actually patch the emulation memory (that happens at ApplyLoadedPatches(...) ) extern int LoadPatchesFromString(const std::string& patches); -extern int LoadPatchesFromDir(const std::string& crc, const wxDirName& folder, const char* friendly_name, bool show_error_when_missing); +extern int LoadPatchesFromDir(const std::string& crc, const std::string& folder, const char* friendly_name, bool show_error_when_missing); extern int LoadPatchesFromZip(const std::string& crc, const u8* zip_data, size_t zip_data_size); // Patches the emulation memory by applying all the loaded patches with a specific place value. diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 573a827234..4119c84fed 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -15,8 +15,8 @@ #include "PrecompiledHeader.h" -#include - +#include "common/FileSystem.h" +#include "common/Path.h" #include "common/SettingsInterface.h" #include "common/SettingsWrapper.h" #include "common/StringUtil.h" @@ -33,22 +33,22 @@ namespace EmuFolders { - wxDirName AppRoot; - wxDirName DataRoot; - wxDirName Settings; - wxDirName Bios; - wxDirName Snapshots; - wxDirName Savestates; - wxDirName MemoryCards; - wxDirName Langs; - wxDirName Logs; - wxDirName Cheats; - wxDirName CheatsWS; - wxDirName Resources; - wxDirName Cache; - wxDirName Covers; - wxDirName GameSettings; - wxDirName Textures; + std::string AppRoot; + std::string DataRoot; + std::string Settings; + std::string Bios; + std::string Snapshots; + std::string Savestates; + std::string MemoryCards; + std::string Langs; + std::string Logs; + std::string Cheats; + std::string CheatsWS; + std::string Resources; + std::string Cache; + std::string Covers; + std::string GameSettings; + std::string Textures; } // namespace EmuFolders void TraceLogFilters::LoadSave(SettingsWrapper& wrap) @@ -1127,13 +1127,13 @@ std::string Pcsx2Config::FullpathToBios() const { std::string ret; if (!BaseFilenames.Bios.empty()) - ret = Path::CombineStdString(EmuFolders::Bios, BaseFilenames.Bios); + ret = Path::Combine(EmuFolders::Bios, BaseFilenames.Bios); return ret; } -wxString Pcsx2Config::FullpathToMcd(uint slot) const +std::string Pcsx2Config::FullpathToMcd(uint slot) const { - return Path::Combine(EmuFolders::MemoryCards, StringUtil::UTF8StringToWxString(Mcd[slot].Filename)); + return Path::Combine(EmuFolders::MemoryCards, Mcd[slot].Filename); } bool Pcsx2Config::operator==(const Pcsx2Config& right) const @@ -1212,27 +1212,25 @@ void Pcsx2Config::CopyConfig(const Pcsx2Config& cfg) void EmuFolders::SetDefaults() { - Bios = DataRoot.Combine(wxDirName("bios")); - Snapshots = DataRoot.Combine(wxDirName("snaps")); - Savestates = DataRoot.Combine(wxDirName("sstates")); - MemoryCards = DataRoot.Combine(wxDirName("memcards")); - Logs = DataRoot.Combine(wxDirName("logs")); - Cheats = DataRoot.Combine(wxDirName("cheats")); - CheatsWS = DataRoot.Combine(wxDirName("cheats_ws")); - Covers = DataRoot.Combine(wxDirName("covers")); - GameSettings = DataRoot.Combine(wxDirName("gamesettings")); - Cache = DataRoot.Combine(wxDirName("cache")); - - Textures = DataRoot.Combine(wxDirName("textures")); + Bios = Path::Combine(DataRoot, "bios"); + Snapshots = Path::Combine(DataRoot, "snaps"); + Savestates = Path::Combine(DataRoot, "sstates"); + MemoryCards = Path::Combine(DataRoot, "memcards"); + Logs = Path::Combine(DataRoot, "logs"); + Cheats = Path::Combine(DataRoot, "cheats"); + CheatsWS = Path::Combine(DataRoot, "cheats_ws"); + Covers = Path::Combine(DataRoot, "covers"); + GameSettings = Path::Combine(DataRoot, "gamesettings"); + Cache = Path::Combine(DataRoot, "cache"); + Textures = Path::Combine(DataRoot, "textures"); } -static wxDirName LoadPathFromSettings(SettingsInterface& si, const wxDirName& root, const char* name, const char* def) +static std::string LoadPathFromSettings(SettingsInterface& si, const std::string& root, const char* name, const char* def) { std::string value = si.GetStringValue("Folders", name, def); - wxDirName ret(StringUtil::UTF8StringToWxString(value)); - if (!ret.IsAbsolute()) - ret = root.Combine(ret); - return ret; + if (!Path::IsAbsolute(value)) + value = Path::Combine(root, value); + return value; } void EmuFolders::LoadConfig(SettingsInterface& si) @@ -1249,47 +1247,46 @@ void EmuFolders::LoadConfig(SettingsInterface& si) Cache = LoadPathFromSettings(si, DataRoot, "Cache", "cache"); Textures = LoadPathFromSettings(si, DataRoot, "Textures", "textures"); - Console.WriteLn("BIOS Directory: %s", Bios.ToString().c_str().AsChar()); - Console.WriteLn("Snapshots Directory: %s", Snapshots.ToString().c_str().AsChar()); - Console.WriteLn("Savestates Directory: %s", Savestates.ToString().c_str().AsChar()); - Console.WriteLn("MemoryCards Directory: %s", MemoryCards.ToString().c_str().AsChar()); - Console.WriteLn("Logs Directory: %s", Logs.ToString().c_str().AsChar()); - Console.WriteLn("Cheats Directory: %s", Cheats.ToString().c_str().AsChar()); - Console.WriteLn("CheatsWS Directory: %s", CheatsWS.ToString().c_str().AsChar()); - Console.WriteLn("Covers Directory: %s", Covers.ToString().c_str().AsChar()); - Console.WriteLn("Game Settings Directory: %s", GameSettings.ToString().c_str().AsChar()); - Console.WriteLn("Cache Directory: %s", Cache.ToString().c_str().AsChar()); - Console.WriteLn("Textures Directory: %s", Textures.ToString().c_str().AsChar()); + Console.WriteLn("BIOS Directory: %s", Bios.c_str()); + Console.WriteLn("Snapshots Directory: %s", Snapshots.c_str()); + Console.WriteLn("Savestates Directory: %s", Savestates.c_str()); + Console.WriteLn("MemoryCards Directory: %s", MemoryCards.c_str()); + Console.WriteLn("Logs Directory: %s", Logs.c_str()); + Console.WriteLn("Cheats Directory: %s", Cheats.c_str()); + Console.WriteLn("CheatsWS Directory: %s", CheatsWS.c_str()); + Console.WriteLn("Covers Directory: %s", Covers.c_str()); + Console.WriteLn("Game Settings Directory: %s", GameSettings.c_str()); + Console.WriteLn("Cache Directory: %s", Cache.c_str()); + Console.WriteLn("Textures Directory: %s", Textures.c_str()); } void EmuFolders::Save(SettingsInterface& si) { // convert back to relative - const wxString datarel(DataRoot.ToString()); - si.SetStringValue("Folders", "Bios", wxDirName::MakeAutoRelativeTo(Bios, datarel).c_str()); - si.SetStringValue("Folders", "Snapshots", wxDirName::MakeAutoRelativeTo(Snapshots, datarel).c_str()); - si.SetStringValue("Folders", "Savestates", wxDirName::MakeAutoRelativeTo(Savestates, datarel).c_str()); - si.SetStringValue("Folders", "MemoryCards", wxDirName::MakeAutoRelativeTo(MemoryCards, datarel).c_str()); - si.SetStringValue("Folders", "Logs", wxDirName::MakeAutoRelativeTo(Logs, datarel).c_str()); - si.SetStringValue("Folders", "Cheats", wxDirName::MakeAutoRelativeTo(Cheats, datarel).c_str()); - si.SetStringValue("Folders", "CheatsWS", wxDirName::MakeAutoRelativeTo(CheatsWS, datarel).c_str()); - si.SetStringValue("Folders", "Cache", wxDirName::MakeAutoRelativeTo(Cache, datarel).c_str()); - si.SetStringValue("Folders", "Textures", wxDirName::MakeAutoRelativeTo(Textures, datarel).c_str()); + si.SetStringValue("Folders", "Bios", Path::MakeRelative(Bios, DataRoot).c_str()); + si.SetStringValue("Folders", "Snapshots", Path::MakeRelative(Snapshots, DataRoot).c_str()); + si.SetStringValue("Folders", "Savestates", Path::MakeRelative(Savestates, DataRoot).c_str()); + si.SetStringValue("Folders", "MemoryCards", Path::MakeRelative(MemoryCards, DataRoot).c_str()); + si.SetStringValue("Folders", "Logs", Path::MakeRelative(Logs, DataRoot).c_str()); + si.SetStringValue("Folders", "Cheats", Path::MakeRelative(Cheats, DataRoot).c_str()); + si.SetStringValue("Folders", "CheatsWS", Path::MakeRelative(CheatsWS, DataRoot).c_str()); + si.SetStringValue("Folders", "Cache", Path::MakeRelative(Cache, DataRoot).c_str()); + si.SetStringValue("Folders", "Textures", Path::MakeRelative(Textures, DataRoot).c_str()); } bool EmuFolders::EnsureFoldersExist() { - bool result = Bios.Mkdir(); - result = Settings.Mkdir() && result; - result = Snapshots.Mkdir() && result; - result = Savestates.Mkdir() && result; - result = MemoryCards.Mkdir() && result; - result = Logs.Mkdir() && result; - result = Cheats.Mkdir() && result; - result = CheatsWS.Mkdir() && result; - result = Covers.Mkdir() && result; - result = GameSettings.Mkdir() && result; - result = Cache.Mkdir() && result; - result = Textures.Mkdir() && result; + bool result = FileSystem::CreateDirectoryPath(Bios.c_str(), false); + result = FileSystem::CreateDirectoryPath(Settings.c_str(), false) && result; + result = FileSystem::CreateDirectoryPath(Snapshots.c_str(), false) && result; + result = FileSystem::CreateDirectoryPath(Savestates.c_str(), false) && result; + result = FileSystem::CreateDirectoryPath(MemoryCards.c_str(), false) && result; + result = FileSystem::CreateDirectoryPath(Logs.c_str(), false) && result; + result = FileSystem::CreateDirectoryPath(Cheats.c_str(), false) && result; + result = FileSystem::CreateDirectoryPath(CheatsWS.c_str(), false) && result; + result = FileSystem::CreateDirectoryPath(Covers.c_str(), false) && result; + result = FileSystem::CreateDirectoryPath(GameSettings.c_str(), false) && result; + result = FileSystem::CreateDirectoryPath(Cache.c_str(), false) && result; + result = FileSystem::CreateDirectoryPath(Textures.c_str(), false) && result; return result; } diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index 3931eb89ab..2d5c0653cf 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -141,7 +141,7 @@ __ri void cpuException(u32 code, u32 bd) if(cpuRegs.CP0.n.Status.b.ERL == 0) { //Error Level 0-1 - errLevel2 = FALSE; + errLevel2 = false; checkStatus = (cpuRegs.CP0.n.Status.b.BEV == 0); // for TLB/general exceptions if (((code & 0x7C) >= 0x8) && ((code & 0x7C) <= 0xC)) @@ -154,7 +154,7 @@ __ri void cpuException(u32 code, u32 bd) else { //Error Level 2 - errLevel2 = TRUE; + errLevel2 = true; checkStatus = (cpuRegs.CP0.n.Status.b.DEV == 0); // for perf/debug exceptions Console.Error("*PCSX2* FIX ME: Level 2 cpuException"); diff --git a/pcsx2/SPU2/Host/CfgHelpers.cpp b/pcsx2/SPU2/Host/CfgHelpers.cpp deleted file mode 100644 index 21ecb9eb1d..0000000000 --- a/pcsx2/SPU2/Host/CfgHelpers.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "common/StringUtil.h" -#include "SPU2/Host/Config.h" -#include "SPU2/Host/Dialogs.h" -#include "HostSettings.h" - -bool CfgReadBool(const wchar_t* Section, const wchar_t* Name, bool Default) -{ - return Host::GetBoolSettingValue(StringUtil::WideStringToUTF8String(Section).c_str(), - StringUtil::WideStringToUTF8String(Name).c_str(), Default); -} - -int CfgReadInt(const wchar_t* Section, const wchar_t* Name, int Default) -{ - return Host::GetIntSettingValue(StringUtil::WideStringToUTF8String(Section).c_str(), - StringUtil::WideStringToUTF8String(Name).c_str(), Default); -} - -float CfgReadFloat(const wchar_t* Section, const wchar_t* Name, float Default) -{ - return Host::GetFloatSettingValue(StringUtil::WideStringToUTF8String(Section).c_str(), - StringUtil::WideStringToUTF8String(Name).c_str(), Default); -} - -void CfgReadStr(const wchar_t* Section, const wchar_t* Name, wchar_t* Data, int DataSize, const wchar_t* Default) -{ - const std::wstring res(StringUtil::UTF8StringToWideString( - Host::GetStringSettingValue( - StringUtil::WideStringToUTF8String(Section).c_str(), - StringUtil::WideStringToUTF8String(Name).c_str(), - StringUtil::WideStringToUTF8String(Default).c_str()))); - - std::wcsncpy(Data, res.c_str(), DataSize); - Data[DataSize - 1] = 0; -} - -void CfgReadStr(const wchar_t* Section, const wchar_t* Name, wxString& Data, const wchar_t* Default) -{ - Data = StringUtil::UTF8StringToWxString( - Host::GetStringSettingValue( - StringUtil::WideStringToUTF8String(Section).c_str(), - StringUtil::WideStringToUTF8String(Name).c_str(), - StringUtil::WideStringToUTF8String(Default).c_str())); -} - -void CfgWriteBool(const wchar_t* Section, const wchar_t* Name, bool Value) -{ -} - -void CfgWriteInt(const wchar_t* Section, const wchar_t* Name, int Value) -{ -} - -void CfgWriteFloat(const wchar_t* Section, const wchar_t* Name, float Value) -{ -} - -void CfgWriteStr(const wchar_t* Section, const wchar_t* Name, const wxString& Data) -{ -} \ No newline at end of file diff --git a/pcsx2/SPU2/Host/Config.cpp b/pcsx2/SPU2/Host/Config.cpp index 5307f12385..1c9e55b69e 100644 --- a/pcsx2/SPU2/Host/Config.cpp +++ b/pcsx2/SPU2/Host/Config.cpp @@ -97,7 +97,7 @@ void ReadSettings() VolumeAdjustLFE = powf(10, VolumeAdjustLFEdb / 10); const std::string modname(Host::GetStringSettingValue("SPU2/Output", "OutputModule", "cubeb")); - OutputModule = FindOutputModuleById(StringUtil::UTF8StringToWideString(modname).c_str()); // Find the driver index of this module... + OutputModule = FindOutputModuleById(modname.c_str()); // Find the driver index of this module... SndOutLatencyMS = Host::GetIntSettingValue("SPU2/Output", "Latency", 100); SynchMode = Host::GetIntSettingValue("SPU2/Output", "SynchMode", 0); diff --git a/pcsx2/SPU2/Host/Config.h b/pcsx2/SPU2/Host/Config.h index 7bcea7c6e2..062fcd91d8 100644 --- a/pcsx2/SPU2/Host/Config.h +++ b/pcsx2/SPU2/Host/Config.h @@ -17,7 +17,6 @@ #define CONFIG_H_INCLUDED #include -#include extern bool DebugEnabled; diff --git a/pcsx2/SPU2/Host/ConfigDebug.cpp b/pcsx2/SPU2/Host/ConfigDebug.cpp index b6c0d960d9..0148280eb4 100644 --- a/pcsx2/SPU2/Host/ConfigDebug.cpp +++ b/pcsx2/SPU2/Host/ConfigDebug.cpp @@ -61,17 +61,17 @@ void CfgSetLogDir(const char* dir) FILE* OpenBinaryLog(const char* logfile) { - return FileSystem::OpenCFile(Path::CombineStdString(EmuFolders::Logs, logfile).c_str(), "wb"); + return FileSystem::OpenCFile(Path::Combine(EmuFolders::Logs, logfile).c_str(), "wb"); } FILE* OpenLog(const char* logfile) { - return FileSystem::OpenCFile(Path::CombineStdString(EmuFolders::Logs, logfile).c_str(), "w"); + return FileSystem::OpenCFile(Path::Combine(EmuFolders::Logs, logfile).c_str(), "w"); } FILE* OpenDump(const char* logfile) { - return FileSystem::OpenCFile(Path::CombineStdString(EmuFolders::Logs, logfile).c_str(), "w"); + return FileSystem::OpenCFile(Path::Combine(EmuFolders::Logs, logfile).c_str(), "w"); } namespace DebugConfig diff --git a/pcsx2/SPU2/Host/Dialogs.cpp b/pcsx2/SPU2/Host/Dialogs.cpp index 92bf825765..de3c899e48 100644 --- a/pcsx2/SPU2/Host/Dialogs.cpp +++ b/pcsx2/SPU2/Host/Dialogs.cpp @@ -18,41 +18,7 @@ #include "PrecompiledHeader.h" #include "Dialogs.h" #include - -#if !defined(PCSX2_CORE) && (defined(__unix__) || defined(__APPLE__)) -#include - -void SysMessage(const char* fmt, ...) -{ - va_list list; - char msg[512]; - - va_start(list, fmt); - vsprintf(msg, fmt, list); - va_end(list); - - if (msg[strlen(msg) - 1] == '\n') - msg[strlen(msg) - 1] = 0; - - wxMessageDialog dialog(nullptr, msg, "Info", wxOK); - dialog.ShowModal(); -} - -void SysMessage(const wchar_t* fmt, ...) -{ - va_list list; - va_start(list, fmt); - wxString msg; - msg.PrintfV(fmt, list); - va_end(list); - - wxMessageDialog dialog(nullptr, msg, "Info", wxOK); - dialog.ShowModal(); -} - -#else - -#include +#include void SysMessage(const char* fmt, ...) { @@ -62,19 +28,6 @@ void SysMessage(const char* fmt, ...) va_end(list); } -void SysMessage(const wchar_t* fmt, ...) -{ - va_list list; - va_start(list, fmt); - wxString msg; - msg.PrintfV(fmt, list); - va_end(list); - - fprintf(stderr, "%s\n", msg.ToStdString().c_str()); -} - -#endif - void DspUpdate() { } diff --git a/pcsx2/SPU2/Host/Dialogs.h b/pcsx2/SPU2/Host/Dialogs.h index 35691a7396..aeda5f9824 100644 --- a/pcsx2/SPU2/Host/Dialogs.h +++ b/pcsx2/SPU2/Host/Dialogs.h @@ -19,8 +19,6 @@ #include "SPU2/Global.h" #include "SPU2/Config.h" -#include - namespace DebugConfig { extern void ReadSettings(); @@ -29,14 +27,4 @@ namespace DebugConfig extern void CfgSetSettingsDir(const char* dir); extern void CfgSetLogDir(const char* dir); -extern bool CfgReadBool(const wchar_t* Section, const wchar_t* Name, bool Default); -extern void CfgReadStr(const wchar_t* Section, const wchar_t* Name, wxString& Data, const wchar_t* Default); -extern int CfgReadInt(const wchar_t* Section, const wchar_t* Name, int Default); -extern float CfgReadFloat(const wchar_t* Section, const wchar_t* Name, float Default); - -extern void CfgWriteBool(const wchar_t* Section, const wchar_t* Name, bool Value); -extern void CfgWriteInt(const wchar_t* Section, const wchar_t* Name, int Value); -extern void CfgWriteFloat(const wchar_t* Section, const wchar_t* Name, float Value); -extern void CfgWriteStr(const wchar_t* Section, const wchar_t* Name, const wxString& Data); - #endif diff --git a/pcsx2/SPU2/Linux/CfgHelpers.cpp b/pcsx2/SPU2/Linux/CfgHelpers.cpp index 5dd715b19c..5f3bd622c9 100644 --- a/pcsx2/SPU2/Linux/CfgHelpers.cpp +++ b/pcsx2/SPU2/Linux/CfgHelpers.cpp @@ -17,6 +17,8 @@ #include "Config.h" #include "Dialogs.h" #include "pcsx2/Config.h" +#include "common/Path.h" +#include "gui/StringHelpers.h" #include wxFileConfig* spuConfig = nullptr; @@ -27,7 +29,7 @@ void initIni() { if (!pathSet) { - path = EmuFolders::Settings.Combine(path).GetFullPath(); + path = StringUtil::UTF8StringToWxString(Path::Combine(EmuFolders::Settings, "SPU2.ini")); pathSet = true; } if (spuConfig == nullptr) @@ -43,7 +45,7 @@ void setIni(const wchar_t* Section) void CfgSetSettingsDir(const char* dir) { FileLog("CfgSetSettingsDir(%s)\n", dir); - path = Path::Combine((dir == nullptr) ? wxString(L"inis") : wxString::FromUTF8(dir), L"SPU2.ini"); + path = StringUtil::UTF8StringToWxString(Path::Combine((dir == nullptr) ? std::string("inis") : std::string(dir), "SPU2.ini")); pathSet = true; } diff --git a/pcsx2/SPU2/Linux/Config.cpp b/pcsx2/SPU2/Linux/Config.cpp index 4784d059a8..545679f752 100644 --- a/pcsx2/SPU2/Linux/Config.cpp +++ b/pcsx2/SPU2/Linux/Config.cpp @@ -17,6 +17,7 @@ #include "SPU2/Global.h" #include "Dialogs.h" #include "Config.h" +#include "gui/StringHelpers.h" #if defined(__unix__) || defined(__APPLE__) #include @@ -108,8 +109,8 @@ void ReadSettings() #endif wxString temp; - CfgReadStr(L"OUTPUT", L"Output_Module", temp, defaultModule->GetIdent()); - OutputModule = FindOutputModuleById(temp.c_str()); // Find the driver index of this module... + CfgReadStr(L"OUTPUT", L"Output_Module", temp, StringUtil::UTF8StringToWxString(defaultModule->GetIdent()).wc_str()); + OutputModule = FindOutputModuleById(temp.ToUTF8()); // Find the driver index of this module... SndOutLatencyMS = CfgReadInt(L"OUTPUT", L"Latency", 100); SynchMode = CfgReadInt(L"OUTPUT", L"Synch_Mode", 0); diff --git a/pcsx2/SPU2/Linux/ConfigDebug.cpp b/pcsx2/SPU2/Linux/ConfigDebug.cpp index 3ba6d037b4..a2fa78da88 100644 --- a/pcsx2/SPU2/Linux/ConfigDebug.cpp +++ b/pcsx2/SPU2/Linux/ConfigDebug.cpp @@ -18,6 +18,8 @@ #include "Dialogs.h" #include "Config.h" #include "pcsx2/Config.h" +#include "gui/StringHelpers.h" +#include "gui/wxDirName.h" #include "common/FileSystem.h" #include "common/StringUtil.h" #include "common/Path.h" @@ -64,32 +66,17 @@ void CfgSetLogDir(const char* dir) FILE* OpenBinaryLog(const char* logfile) { - return FileSystem::OpenCFile(Path::CombineStdString(EmuFolders::Logs, logfile).c_str(), "wb"); + return FileSystem::OpenCFile(Path::Combine(EmuFolders::Logs, logfile).c_str(), "wb"); } FILE* OpenLog(const char* logfile) { - return FileSystem::OpenCFile(Path::CombineStdString(EmuFolders::Logs, logfile).c_str(), "w"); + return FileSystem::OpenCFile(Path::Combine(EmuFolders::Logs, logfile).c_str(), "w"); } FILE* OpenDump(const char* logfile) { - return FileSystem::OpenCFile(Path::CombineStdString(EmuFolders::Logs, logfile).c_str(), "w"); -} - -FILE* OpenBinaryLog(const wxString& logfile) -{ - return wxFopen(Path::Combine(LogsFolder, logfile), L"wb"); -} - -FILE* OpenLog(const wxString& logfile) -{ - return wxFopen(Path::Combine(LogsFolder, logfile), L"w"); -} - -FILE* OpenDump(const wxString& logfile) -{ - return wxFopen(Path::Combine(DumpsFolder, logfile), L"w"); + return FileSystem::OpenCFile(Path::Combine(EmuFolders::Logs, logfile).c_str(), "w"); } namespace DebugConfig diff --git a/pcsx2/SPU2/SndOut.cpp b/pcsx2/SPU2/SndOut.cpp index ebe1859fd6..3b919f979a 100644 --- a/pcsx2/SPU2/SndOut.cpp +++ b/pcsx2/SPU2/SndOut.cpp @@ -55,14 +55,14 @@ public: void SetPaused(bool paused) override {} int GetEmptySampleCount() override { return 0; } - const wchar_t* GetIdent() const override + const char* GetIdent() const override { - return L"nullout"; + return "nullout"; } - const wchar_t* GetLongName() const override + const char* GetLongName() const override { - return L"No Sound (Emulate SPU2 only)"; + return "No Sound (Emulate SPU2 only)"; } }; @@ -81,12 +81,12 @@ SndOutModule* mods[] = nullptr // signals the end of our list }; -int FindOutputModuleById(const wchar_t* omodid) +int FindOutputModuleById(const char* omodid) { int modcnt = 0; while (mods[modcnt] != nullptr) { - if (wcscmp(mods[modcnt]->GetIdent(), omodid) == 0) + if (std::strcmp(mods[modcnt]->GetIdent(), omodid) == 0) break; ++modcnt; } diff --git a/pcsx2/SPU2/SndOut.h b/pcsx2/SPU2/SndOut.h index a539f94793..00cc0363eb 100644 --- a/pcsx2/SPU2/SndOut.h +++ b/pcsx2/SPU2/SndOut.h @@ -32,7 +32,7 @@ static const int SndOutVolumeShift32 = 16 - SndOutVolumeShift; // shift up, not // is too problematic. :) extern int SampleRate; -extern int FindOutputModuleById(const wchar_t* omodid); +extern int FindOutputModuleById(const char* omodid); // Implemented in Config.cpp extern float VolumeAdjustFL; @@ -636,11 +636,11 @@ public: // Returns a unique identification string for this driver. // (usually just matches the driver's cpp filename) - virtual const wchar_t* GetIdent() const = 0; + virtual const char* GetIdent() const = 0; // Returns the long name / description for this driver. // (for use in configuration screen) - virtual const wchar_t* GetLongName() const = 0; + virtual const char* GetLongName() const = 0; virtual bool Init() = 0; virtual void Close() = 0; diff --git a/pcsx2/SPU2/SndOut_Cubeb.cpp b/pcsx2/SPU2/SndOut_Cubeb.cpp index e10aecb8e2..773e9b32be 100644 --- a/pcsx2/SPU2/SndOut_Cubeb.cpp +++ b/pcsx2/SPU2/SndOut_Cubeb.cpp @@ -23,10 +23,20 @@ #include "Global.h" #include "SndOut.h" +#ifdef PCSX2_CORE + +#include "HostSettings.h" + +#else + +#include "gui/StringHelpers.h" + extern bool CfgReadBool(const wchar_t* Section, const wchar_t* Name, bool Default); extern int CfgReadInt(const wchar_t* Section, const wchar_t* Name, int Default); extern void CfgReadStr(const wchar_t* Section, const wchar_t* Name, wxString& Data, const wchar_t* Default); +#endif + class Cubeb : public SndOutModule { private: @@ -343,18 +353,19 @@ public: return playedSinceLastTime; } - const wchar_t* GetIdent() const override + const char* GetIdent() const override { - return L"cubeb"; + return "cubeb"; } - const wchar_t* GetLongName() const override + const char* GetLongName() const override { - return L"Cubeb (Cross-platform)"; + return "Cubeb (Cross-platform)"; } void ReadSettings() { +#ifndef PCSX2_CORE m_SuggestedLatencyMinimal = CfgReadBool(L"Cubeb", L"MinimalSuggestedLatency", false); m_SuggestedLatencyMS = std::clamp(CfgReadInt(L"Cubeb", L"ManualSuggestedLatencyMS", MINIMUM_LATENCY_MS), MINIMUM_LATENCY_MS, MAXIMUM_LATENCY_MS); @@ -362,6 +373,11 @@ public: wxString backend; CfgReadStr(L"Cubeb", L"BackendName", backend, L""); m_Backend = StringUtil::wxStringToUTF8String(backend); +#else + m_SuggestedLatencyMinimal = Host::GetBoolSettingValue("Cubeb", "MinimalSuggestedLatency", false); + m_SuggestedLatencyMS = std::clamp(Host::GetIntSettingValue("Cubeb", "ManualSuggestedLatencyMS", MINIMUM_LATENCY_MS), MINIMUM_LATENCY_MS, MAXIMUM_LATENCY_MS); + m_Backend = Host::GetStringSettingValue("Cubeb", "BackendName", ""); +#endif } }; diff --git a/pcsx2/SPU2/Timestretcher.cpp b/pcsx2/SPU2/Timestretcher.cpp index 9dd025aa30..911a442629 100644 --- a/pcsx2/SPU2/Timestretcher.cpp +++ b/pcsx2/SPU2/Timestretcher.cpp @@ -16,7 +16,7 @@ #include "PrecompiledHeader.h" #include "Global.h" #include "SoundTouch.h" -#include +#include "common/Timer.h" #include #include @@ -246,15 +246,15 @@ void SndBuffer::UpdateTempoChangeSoundTouch2() if (MsgOverruns()) { static int iters = 0; - static wxDateTime last = wxDateTime::UNow(); - wxDateTime unow = wxDateTime::UNow(); - wxTimeSpan delta = unow.Subtract(last); + static u64 last = 0; - if (delta.GetMilliseconds() > 1000) + const u64 now = Common::Timer::GetCurrentValue(); + + if (Common::Timer::ConvertValueToSeconds(now - last) > 1.0f) { //report buffers state and tempo adjust every second ConLog("buffers: %4d ms (%3.0f%%), tempo: %f, comp: %2.3f, iters: %d, (N-IPS:%d -> avg:%d, minokc:%d, div:%d) reset:%d\n", (int)(data / 48), (double)(100.0 * bufferFullness / baseTargetFullness), (double)tempoAdjust, (double)(dynamicTargetFullness / baseTargetFullness), iters, (int)targetIPS, AVERAGING_WINDOW, hys_min_ok_count, compensationDivider, gRequestStretcherReset); - last = unow; + last = now; iters = 0; } iters++; diff --git a/pcsx2/SPU2/Windows/CfgHelpers.cpp b/pcsx2/SPU2/Windows/CfgHelpers.cpp index 9ab3f9fcbb..8211ae41b0 100644 --- a/pcsx2/SPU2/Windows/CfgHelpers.cpp +++ b/pcsx2/SPU2/Windows/CfgHelpers.cpp @@ -17,6 +17,8 @@ #include "Config.h" #include "SPU2/Global.h" #include "Dialogs.h" +#include "common/StringUtil.h" +#include "gui/StringHelpers.h" void SysMessage(const char* fmt, ...) { @@ -54,7 +56,7 @@ void initIni() { if (!pathSet) { - CfgFile = EmuFolders::Settings.Combine(CfgFile).GetFullPath(); + CfgFile = StringUtil::UTF8StringToWxString(Path::Combine(EmuFolders::Settings, "SPU2.ini")); pathSet = true; } } diff --git a/pcsx2/SPU2/Windows/Config.cpp b/pcsx2/SPU2/Windows/Config.cpp index 7d4e8bff3e..c71e13971c 100644 --- a/pcsx2/SPU2/Windows/Config.cpp +++ b/pcsx2/SPU2/Windows/Config.cpp @@ -16,6 +16,7 @@ #include "PrecompiledHeader.h" #include "SPU2/Global.h" #include "Dialogs.h" +#include "common/StringUtil.h" #ifdef PCSX2_DEVBUILD static const int LATENCY_MAX = 3000; @@ -117,10 +118,10 @@ void ReadSettings() // Let's use xaudio2 until this is sorted (rama). // CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, PortaudioOut->GetIdent()); - CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, XAudio2Out->GetIdent()); + CfgReadStr(L"OUTPUT", L"Output_Module", omodid, 127, StringUtil::UTF8StringToWideString(XAudio2Out->GetIdent()).c_str()); // Find the driver index of this module: - OutputModule = FindOutputModuleById(omodid); + OutputModule = FindOutputModuleById(StringUtil::WideStringToUTF8String(omodid).c_str()); CfgReadStr(L"DSP PLUGIN", L"Filename", dspPlugin, 255, L""); dspPluginModule = CfgReadInt(L"DSP PLUGIN", L"ModuleNum", 0); @@ -342,7 +343,7 @@ BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) int modidx = 0; while (mods[modidx] != nullptr) { - swprintf_s(temp, 72, L"%d - %s", modidx, mods[modidx]->GetLongName()); + swprintf_s(temp, 72, L"%d - %s", modidx, StringUtil::UTF8StringToWideString(mods[modidx]->GetLongName()).c_str()); SendDialogMsg(hWnd, IDC_OUTPUT, CB_ADDSTRING, 0, (LPARAM)temp); ++modidx; } diff --git a/pcsx2/SPU2/Windows/ConfigDebug.cpp b/pcsx2/SPU2/Windows/ConfigDebug.cpp index 890b8d8963..614f988356 100644 --- a/pcsx2/SPU2/Windows/ConfigDebug.cpp +++ b/pcsx2/SPU2/Windows/ConfigDebug.cpp @@ -20,6 +20,8 @@ #include "common/FileSystem.h" #include "common/StringUtil.h" #include "common/Path.h" +#include "gui/StringHelpers.h" +#include "gui/wxDirName.h" bool DebugEnabled = false; @@ -68,17 +70,17 @@ void CfgSetLogDir(const char* dir) FILE* OpenBinaryLog(const char* logfile) { - return FileSystem::OpenCFile(Path::CombineStdString(EmuFolders::Logs, logfile).c_str(), "wb"); + return FileSystem::OpenCFile(Path::Combine(EmuFolders::Logs, logfile).c_str(), "wb"); } FILE* OpenLog(const char* logfile) { - return FileSystem::OpenCFile(Path::CombineStdString(EmuFolders::Logs, logfile).c_str(), "w"); + return FileSystem::OpenCFile(Path::Combine(EmuFolders::Logs, logfile).c_str(), "w"); } FILE* OpenDump(const char* logfile) { - return FileSystem::OpenCFile(Path::CombineStdString(EmuFolders::Logs, logfile).c_str(), "w"); + return FileSystem::OpenCFile(Path::Combine(EmuFolders::Logs, logfile).c_str(), "w"); } namespace DebugConfig diff --git a/pcsx2/SPU2/Windows/SndOut_XAudio2.cpp b/pcsx2/SPU2/Windows/SndOut_XAudio2.cpp index c5b6b337a1..f4c91ad432 100644 --- a/pcsx2/SPU2/Windows/SndOut_XAudio2.cpp +++ b/pcsx2/SPU2/Windows/SndOut_XAudio2.cpp @@ -360,14 +360,14 @@ public: m_paused = paused; } - const wchar_t* GetIdent() const override + const char* GetIdent() const override { - return L"xaudio2"; + return "xaudio2"; } - const wchar_t* GetLongName() const override + const char* GetLongName() const override { - return L"XAudio 2 (Recommended)"; + return "XAudio 2 (Recommended)"; } } static XA2; diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index 7bcfff567d..32ec00f156 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -18,6 +18,7 @@ #include "SaveState.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "common/SafeArray.inl" #include "common/ScopedGuard.h" #include "common/StringUtil.h" @@ -128,7 +129,7 @@ std::string SaveStateBase::GetSavestateFolder(int slot, bool isSavingOrLoading) } } - return Path::CombineStdString(dir, StringUtil::StdStringFromFormat("%s (%s).%02d.p2s", + return Path::Combine(dir, StringUtil::StdStringFromFormat("%s (%s).%02d.p2s", serialName.c_str(), CRCvalue.c_str(), slot)); } #endif diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index cabc8fcf77..b018bc1f91 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -15,6 +15,8 @@ #pragma once +#include + #include "System.h" #include "common/Exceptions.h" diff --git a/pcsx2/Sio.cpp b/pcsx2/Sio.cpp index 6fd5849e0d..ab13b67fbe 100644 --- a/pcsx2/Sio.cpp +++ b/pcsx2/Sio.cpp @@ -23,6 +23,8 @@ #include "sio_internal.h" #include "PAD/Gamepad.h" +#include "common/Timer.h" + #ifndef DISABLE_RECORDING # include "Recording/InputRecording.h" #endif @@ -609,12 +611,11 @@ SIO_WRITE memcardInit() //minimum tries reached. start counting millisec timeout. if(numTimesAccessed == FORCED_MCD_EJECTION_MIN_TRIES) - mcd->ForceEjection_Timestamp = wxDateTime::UNow(); + mcd->ForceEjection_Timestamp = Common::Timer::GetCurrentValue(); if(numTimesAccessed > FORCED_MCD_EJECTION_MIN_TRIES) { - wxTimeSpan delta = wxDateTime::UNow().Subtract(mcd->ForceEjection_Timestamp); - if(delta.GetMilliseconds() >= FORCED_MCD_EJECTION_MAX_MS_AFTER_MIN_TRIES) + if(Common::Timer::ConvertValueToMilliseconds(Common::Timer::GetCurrentValue() - mcd->ForceEjection_Timestamp) >= FORCED_MCD_EJECTION_MAX_MS_AFTER_MIN_TRIES) { DevCon.Warning( "Auto-eject: Timeout reached after mcd was accessed %d times [port:%d, slot:%d]", numTimesAccessed, sio.GetPort(), sio.GetSlot()); mcd->ForceEjection_Timeout = 0; //Done. on next sio access the card will be seen as inserted. @@ -1006,7 +1007,7 @@ void sioNextFrame() { } } -void sioSetGameSerial( const wxString& serial ) { +void sioSetGameSerial( const std::string& serial ) { for ( uint port = 0; port < 2; ++port ) { for ( uint slot = 0; slot < 4; ++slot ) { if ( mcds[port][slot].ReIndex( serial ) ) { diff --git a/pcsx2/Sio.h b/pcsx2/Sio.h index 8d03c6e737..afcb851b93 100644 --- a/pcsx2/Sio.h +++ b/pcsx2/Sio.h @@ -32,7 +32,7 @@ struct _mcd // Auto Eject u32 ForceEjection_Timeout; // in SIO checks - wxDateTime ForceEjection_Timestamp; + u64 ForceEjection_Timestamp; void GetSizeInfo(McdSizeInfo &info) { @@ -82,7 +82,7 @@ struct _mcd FileMcd_NextFrame( port, slot ); } - bool ReIndex(const wxString& filter = L"") { + bool ReIndex(const std::string& filter) { return FileMcd_ReIndex(port, slot, filter); } }; @@ -124,5 +124,5 @@ extern void sioInterruptR(); extern void SetForceMcdEjectTimeoutNow(); extern void ClearMcdEjectTimeoutNow(); extern void sioStatRead(); -extern void sioSetGameSerial(const wxString& serial); +extern void sioSetGameSerial(const std::string& serial); extern void sioNextFrame(); diff --git a/pcsx2/SourceLog.cpp b/pcsx2/SourceLog.cpp index 4bd622b42d..301c94912c 100644 --- a/pcsx2/SourceLog.cpp +++ b/pcsx2/SourceLog.cpp @@ -40,7 +40,7 @@ using namespace R5900; FILE* emuLog; -wxString emuLogName; +std::string emuLogName; SysTraceLogPack SysTrace; SysConsoleLogPack SysConsole; diff --git a/pcsx2/System.h b/pcsx2/System.h index 7c6bd9c1c2..286ce1478b 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -190,9 +190,9 @@ extern SysMainMemory& GetVmMemory(); namespace Msgbox { - extern bool Alert( const wxString& text, const wxString& caption=_("PCSX2 Message"), int icon=wxICON_EXCLAMATION ); - extern bool OkCancel( const wxString& text, const wxString& caption=_("PCSX2 Message"), int icon=0 ); - extern bool YesNo( const wxString& text, const wxString& caption=_("PCSX2 Message"), int icon=wxICON_QUESTION ); + extern bool Alert( const wxString& text, const wxString& caption="PCSX2 Message", int icon=wxICON_EXCLAMATION ); + extern bool OkCancel( const wxString& text, const wxString& caption="PCSX2 Message", int icon=0 ); + extern bool YesNo( const wxString& text, const wxString& caption="PCSX2 Message", int icon=wxICON_QUESTION ); extern int Assertion( const wxString& text, const wxString& stacktrace ); } diff --git a/pcsx2/USB/configuration.cpp b/pcsx2/USB/configuration.cpp index e30d13cd16..ec4e6d63fe 100644 --- a/pcsx2/USB/configuration.cpp +++ b/pcsx2/USB/configuration.cpp @@ -19,6 +19,9 @@ #include "shared/inifile_usb.h" #include "platcompat.h" #include "Config.h" +#include "common/Path.h" +#include "common/StringUtil.h" +#include "gui/StringHelpers.h" #include #include @@ -35,11 +38,7 @@ void USBsetSettingsDir() { if(!USBpathSet) { -#ifdef _WIN32 - IniPath = EmuFolders::Settings.Combine( iniFileUSB ).GetFullPath(); // default path, just in case -#else - IniPath = std::string(EmuFolders::Settings.Combine( iniFileUSB ).GetFullPath()); // default path, just in case -#endif + IniPath = StringUtil::UTF8StringToWxString(Path::Combine(EmuFolders::Settings, "USB.ini")); // default path, just in case USBpathSet = true; } } diff --git a/pcsx2/Utilities/folderdesc.txt b/pcsx2/Utilities/folderdesc.txt deleted file mode 100644 index 06d7ebae36..0000000000 --- a/pcsx2/Utilities/folderdesc.txt +++ /dev/null @@ -1,7 +0,0 @@ -Folder: pcsx2/Utilities -Purpose: To hold general non-pcsx2-specific utility classes which may (or may not) be shared out into a - common folder at a later date. This includes unicode utils, file manipulators, threading, etc. - -Details: I plan to move files into this folder here ont he wxGui branch over time, and then move the - whole lot over to common as a whole library of sorts. I thinkit'll be easier that way than trying - to piecemeal individual files over (especially since some of them have inter-dependencies) \ No newline at end of file diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index b017013708..2eae155704 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -19,7 +19,6 @@ #include #include -#include #include "common/Console.h" #include "common/FileSystem.h" @@ -265,7 +264,7 @@ void VMManager::ApplyGameFixes() std::string VMManager::GetGameSettingsPath(u32 game_crc) { - return Path::CombineStdString(EmuFolders::GameSettings, StringUtil::StdStringFromFormat("%08X.ini", game_crc)); + return Path::Combine(EmuFolders::GameSettings, StringUtil::StdStringFromFormat("%08X.ini", game_crc)); } void VMManager::RequestDisplaySize(float scale /*= 0.0f*/) @@ -459,7 +458,7 @@ void VMManager::UpdateRunningGame(bool force) s_game_name = "Booting PS2 BIOS..."; } - sioSetGameSerial(StringUtil::UTF8StringToWxString(memcardFilters.empty() ? s_game_serial : memcardFilters)); + sioSetGameSerial(memcardFilters.empty() ? s_game_serial : memcardFilters); } UpdateGameSettingsLayer(); @@ -854,7 +853,7 @@ std::string VMManager::GetSaveStateFileName(const char* game_serial, u32 game_cr else filename = StringUtil::StdStringFromFormat("%s (%08X).%02d.p2s", game_serial, game_crc, slot); - filename = Path::CombineStdString(EmuFolders::Savestates, filename); + filename = Path::Combine(EmuFolders::Savestates, filename); } return filename; @@ -1332,7 +1331,7 @@ void VMManager::CheckForMemoryCardConfigChanges(const Pcsx2Config& old_config) if (sioSerial.empty()) sioSerial = s_game_serial; } - sioSetGameSerial(StringUtil::UTF8StringToWxString(sioSerial)); + sioSetGameSerial(sioSerial); } void VMManager::CheckForConfigChanges(const Pcsx2Config& old_config) diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index cc748b10b1..51a6633583 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -765,7 +765,6 @@ extern void UI_EnableSysActions(); extern void UI_DisableSysShutdown(); - #define AffinityAssert_AllowFrom_SysExecutor() \ pxAssertMsg(wxGetApp().SysExecutorThread.IsSelf(), "Thread affinity violation: Call allowed from SysExecutor thread only.") diff --git a/pcsx2/gui/AppAssert.cpp b/pcsx2/gui/AppAssert.cpp index d184dcb839..017ef25d21 100644 --- a/pcsx2/gui/AppAssert.cpp +++ b/pcsx2/gui/AppAssert.cpp @@ -16,6 +16,7 @@ #include "PrecompiledHeader.h" #include "App.h" #include "common/Threading.h" +#include "StringHelpers.h" #include @@ -109,10 +110,10 @@ void Pcsx2App::OnAssertFailure( const wxChar *file, int line, const wxChar *func RecursionGuard guard( _reentrant_lock ); if( guard.IsReentrant() ) pxTrap(); - std::string nfile(StringUtil::WideStringToUTF8String(file)); - std::string nfunc(StringUtil::WideStringToUTF8String(func)); - std::string ncond(StringUtil::WideStringToUTF8String(cond)); - std::string nmsg(StringUtil::WideStringToUTF8String(msg)); + std::string nfile(StringUtil::wxStringToUTF8String(file)); + std::string nfunc(StringUtil::wxStringToUTF8String(func)); + std::string ncond(StringUtil::wxStringToUTF8String(cond)); + std::string nmsg(StringUtil::wxStringToUTF8String(msg)); if( AppDoAssert( DiagnosticOrigin( nfile.c_str(), line, nfunc.c_str(), ncond.c_str()), nmsg.c_str())) { pxTrap(); diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index 6877b46d80..3640a2358a 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -17,6 +17,7 @@ #include "App.h" #include "MainFrame.h" #include "IniInterface.h" +#include "common/FileSystem.h" #include "common/SettingsWrapper.h" #include "wxSettingsInterface.h" @@ -170,7 +171,7 @@ namespace PathDefs return GetUserLocalDataDir(); #else case DocsFolder_User: - return (wxDirName)Path::Combine(wxStandardPaths::Get().GetDocumentsDir(), pxGetAppName()); + return (wxDirName)Path::CombineWx(wxStandardPaths::Get().GetDocumentsDir(), pxGetAppName()); #endif case DocsFolder_Custom: return CustomDocumentsFolder; @@ -472,43 +473,43 @@ void AppConfig::FolderOptions::Set(FoldersEnum_t folderidx, const wxString& src, case FolderId_Settings: SettingsFolder = src; UseDefaultSettingsFolder = useDefault; - EmuFolders::Settings = GetSettingsFolder(); + EmuFolders::Settings = GetSettingsFolder().ToUTF8(); break; case FolderId_Bios: Bios = src; UseDefaultBios = useDefault; - EmuFolders::Bios = GetResolvedFolder(FolderId_Bios); + EmuFolders::Bios = GetResolvedFolder(FolderId_Bios).ToUTF8(); break; case FolderId_Snapshots: Snapshots = src; UseDefaultSnapshots = useDefault; - EmuFolders::Snapshots = GetResolvedFolder(FolderId_Snapshots); + EmuFolders::Snapshots = GetResolvedFolder(FolderId_Snapshots).ToUTF8(); break; case FolderId_Savestates: Savestates = src; UseDefaultSavestates = useDefault; - EmuFolders::Savestates = GetResolvedFolder(FolderId_Savestates); + EmuFolders::Savestates = GetResolvedFolder(FolderId_Savestates).ToUTF8(); break; case FolderId_MemoryCards: MemoryCards = src; UseDefaultMemoryCards = useDefault; - EmuFolders::MemoryCards = GetResolvedFolder(FolderId_MemoryCards); + EmuFolders::MemoryCards = GetResolvedFolder(FolderId_MemoryCards).ToUTF8(); break; case FolderId_Logs: Logs = src; UseDefaultLogs = useDefault; - EmuFolders::Logs = GetResolvedFolder(FolderId_Logs); + EmuFolders::Logs = GetResolvedFolder(FolderId_Logs).ToUTF8(); break; case FolderId_Langs: Langs = src; UseDefaultLangs = useDefault; - EmuFolders::Langs = GetResolvedFolder(FolderId_Langs); + EmuFolders::Langs = GetResolvedFolder(FolderId_Langs).ToUTF8(); break; case FolderId_Documents: @@ -518,27 +519,27 @@ void AppConfig::FolderOptions::Set(FoldersEnum_t folderidx, const wxString& src, case FolderId_Cheats: Cheats = src; UseDefaultCheats = useDefault; - EmuFolders::Cheats = GetResolvedFolder(FolderId_Cheats); + EmuFolders::Cheats = GetResolvedFolder(FolderId_Cheats).ToUTF8(); break; case FolderId_CheatsWS: CheatsWS = src; UseDefaultCheatsWS = useDefault; - EmuFolders::CheatsWS = GetResolvedFolder(FolderId_CheatsWS); + EmuFolders::CheatsWS = GetResolvedFolder(FolderId_CheatsWS).ToUTF8(); break; case FolderId_Cache: Cache = src; UseDefaultCache = useDefault; - EmuFolders::Cache = GetResolvedFolder(FolderId_Cache); - EmuFolders::Cache.Mkdir(); + EmuFolders::Cache = GetResolvedFolder(FolderId_Cache).ToUTF8(); + FileSystem::CreateDirectoryPath(EmuFolders::Cache.c_str(), false); break; case FolderId_Textures: Textures = src; UseDefaultTextures = useDefault; - EmuFolders::Textures = GetResolvedFolder(FolderId_Textures); - EmuFolders::Textures.Mkdir(); + EmuFolders::Textures = GetResolvedFolder(FolderId_Textures).ToUTF8(); + FileSystem::CreateDirectoryPath(EmuFolders::Textures.c_str(), false); break; jNO_DEFAULT @@ -809,21 +810,21 @@ void AppConfig::FolderOptions::LoadSave(IniInterface& ini) void AppSetEmuFolders() { - EmuFolders::Settings = GetSettingsFolder(); - EmuFolders::Bios = GetResolvedFolder(FolderId_Bios); - EmuFolders::Snapshots = GetResolvedFolder(FolderId_Snapshots); - EmuFolders::Savestates = GetResolvedFolder(FolderId_Savestates); - EmuFolders::MemoryCards = GetResolvedFolder(FolderId_MemoryCards); - EmuFolders::Logs = GetResolvedFolder(FolderId_Logs); - EmuFolders::Langs = GetResolvedFolder(FolderId_Langs); - EmuFolders::Cheats = GetResolvedFolder(FolderId_Cheats); - EmuFolders::CheatsWS = GetResolvedFolder(FolderId_CheatsWS); - EmuFolders::Resources = g_Conf->Folders.Resources; - EmuFolders::Cache = GetResolvedFolder(FolderId_Cache); - EmuFolders::Textures = GetResolvedFolder(FolderId_Textures); + EmuFolders::Settings = GetSettingsFolder().ToUTF8(); + EmuFolders::Bios = GetResolvedFolder(FolderId_Bios).ToUTF8(); + EmuFolders::Snapshots = GetResolvedFolder(FolderId_Snapshots).ToUTF8(); + EmuFolders::Savestates = GetResolvedFolder(FolderId_Savestates).ToUTF8(); + EmuFolders::MemoryCards = GetResolvedFolder(FolderId_MemoryCards).ToUTF8(); + EmuFolders::Logs = GetResolvedFolder(FolderId_Logs).ToUTF8(); + EmuFolders::Langs = GetResolvedFolder(FolderId_Langs).ToUTF8(); + EmuFolders::Cheats = GetResolvedFolder(FolderId_Cheats).ToUTF8(); + EmuFolders::CheatsWS = GetResolvedFolder(FolderId_CheatsWS).ToUTF8(); + EmuFolders::Resources = g_Conf->Folders.Resources.ToUTF8(); + EmuFolders::Cache = GetResolvedFolder(FolderId_Cache).ToUTF8(); + EmuFolders::Textures = GetResolvedFolder(FolderId_Textures).ToUTF8(); // Ensure cache directory exists, since we're going to write to it (e.g. game database) - EmuFolders::Cache.Mkdir(); + FileSystem::CreateDirectoryPath(EmuFolders::Cache.c_str(), false); } // ------------------------------------------------------------------------ @@ -1098,11 +1099,11 @@ void RelocateLogfile() { g_Conf->Folders.Logs.Mkdir(); - wxString newlogname(Path::Combine(g_Conf->Folders.Logs.ToString(), L"emuLog.txt")); + std::string newlogname(StringUtil::wxStringToUTF8String(Path::CombineWx(g_Conf->Folders.Logs.ToString(), L"emuLog.txt"))); if ((emuLog != NULL) && (emuLogName != newlogname)) { - Console.WriteLn("\nRelocating Logfile...\n\tFrom: %ls\n\tTo : %ls\n", WX_STR(emuLogName), WX_STR(newlogname)); + Console.WriteLn("\nRelocating Logfile...\n\tFrom: %ls\n\tTo : %ls\n", emuLogName.c_str(), newlogname.c_str()); wxGetApp().DisableDiskLogging(); fclose(emuLog); @@ -1112,7 +1113,7 @@ void RelocateLogfile() if (emuLog == NULL) { emuLogName = newlogname; - emuLog = wxFopen(emuLogName, "wb"); + emuLog = FileSystem::OpenCFile(emuLogName.c_str(), "wb"); } wxGetApp().EnableAllLogging(); @@ -1360,3 +1361,48 @@ wxConfigBase* GetAppConfig() { return wxConfigBase::Get(false); } + + +//Tests if a string is a valid name for a new file within a specified directory. +//returns true if: +// - the file name has a minimum length of minNumCharacters chars (default is 5 chars: at least 1 char + '.' + 3-chars extension) +// and - the file name is within the basepath directory (doesn't contain .. , / , \ , etc) +// and - file name doesn't already exist +// and - can be created on current system (it is actually created and deleted for this test). +bool isValidNewFilename(wxString filenameStringToTest, wxDirName atBasePath, wxString& out_errorMessage, uint minNumCharacters) +{ + if (filenameStringToTest.Length() < 1 || filenameStringToTest.Length() < minNumCharacters) + { + out_errorMessage = _("File name empty or too short"); + return false; + } + + if ((atBasePath + wxFileName(filenameStringToTest)).GetFullPath() != (atBasePath + wxFileName(filenameStringToTest).GetFullName()).GetFullPath()) + { + out_errorMessage = _("File name outside of required directory"); + return false; + } + + if (wxFileExists((atBasePath + wxFileName(filenameStringToTest)).GetFullPath())) + { + out_errorMessage = _("File name already exists"); + return false; + } + if (wxDirExists((atBasePath + wxFileName(filenameStringToTest)).GetFullPath())) + { + out_errorMessage = _("File name already exists"); + return false; + } + + wxFile fp; + if (!fp.Create((atBasePath + wxFileName(filenameStringToTest)).GetFullPath())) + { + out_errorMessage = _("The Operating-System prevents this file from being created"); + return false; + } + fp.Close(); + wxRemoveFile((atBasePath + wxFileName(filenameStringToTest)).GetFullPath()); + + out_errorMessage = L"[OK - New file name is valid]"; //shouldn't be displayed on success, hence not translatable. + return true; +} diff --git a/pcsx2/gui/AppConfig.h b/pcsx2/gui/AppConfig.h index 2ded240d22..6729bc7fc9 100644 --- a/pcsx2/gui/AppConfig.h +++ b/pcsx2/gui/AppConfig.h @@ -341,3 +341,5 @@ extern void AppConfig_OnChangedSettingsFolder( bool overwrite = false ); extern wxConfigBase* GetAppConfig(); extern std::unique_ptr g_Conf; + +extern bool isValidNewFilename(wxString filenameStringToTest, wxDirName atBasePath, wxString& out_errorMessage, uint minNumCharacters = 5); diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp index 5bc32a2329..5ce8cf05d5 100644 --- a/pcsx2/gui/AppCoreThread.cpp +++ b/pcsx2/gui/AppCoreThread.cpp @@ -410,9 +410,9 @@ static void _ApplySettings(const Pcsx2Config& src, Pcsx2Config& fixup) } if (!gameMemCardFilter.IsEmpty()) - sioSetGameSerial(gameMemCardFilter); + sioSetGameSerial(StringUtil::wxStringToUTF8String(gameMemCardFilter)); else - sioSetGameSerial(curGameKey); + sioSetGameSerial(StringUtil::wxStringToUTF8String(curGameKey)); if (GameInfo::gameName.IsEmpty() && GameInfo::gameSerial.IsEmpty() && GameInfo::gameCRC.IsEmpty()) { diff --git a/pcsx2/gui/AppHost.cpp b/pcsx2/gui/AppHost.cpp index 2628ea626a..71cb97598d 100644 --- a/pcsx2/gui/AppHost.cpp +++ b/pcsx2/gui/AppHost.cpp @@ -41,7 +41,7 @@ static auto OpenResourceCFile(const char* filename, const char* mode) { - const std::string full_filename(Path::CombineStdString(EmuFolders::Resources, filename)); + const std::string full_filename(Path::Combine(EmuFolders::Resources, filename)); auto fp = FileSystem::OpenManagedCFile(full_filename.c_str(), mode); if (!fp) Console.Error("Failed to open resource file '%s'", filename); @@ -118,7 +118,7 @@ HostDisplay* Host::AcquireHostDisplay(HostDisplay::RenderAPI api) if (!s_host_display->CreateRenderDevice(g_gs_window_info, GSConfig.Adapter, EmuConfig.GetEffectiveVsyncMode(), GSConfig.ThreadedPresentation, GSConfig.UseDebugDevice) || - !s_host_display->InitializeRenderDevice(StringUtil::wxStringToUTF8String(EmuFolders::Cache.ToString()), GSConfig.UseDebugDevice) || + !s_host_display->InitializeRenderDevice(EmuFolders::Cache, GSConfig.UseDebugDevice) || !ImGuiManager::Initialize()) { s_host_display->DestroyRenderDevice(); diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index ab090179c0..3b64c5237e 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -22,6 +22,7 @@ #include "IniInterface.h" #include "StringHelpers.h" +#include "common/FileSystem.h" #include "common/StringUtil.h" #include "DebugTools/Debug.h" #include "Dialogs/ModalPopups.h" @@ -72,7 +73,7 @@ void Pcsx2App::DetectCpuAndUserMode() EstablishAppUserMode(); // Check that the resources directory exists and contains our data files. - if (!EmuFolders::Resources.Exists()) + if (!FileSystem::DirectoryExists(EmuFolders::Resources.c_str())) { throw Exception::RuntimeError() .SetDiagMsg("Resources directory does not exist.") diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index fde0db8f89..7d8b81434b 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -303,7 +303,7 @@ class Pcsx2StandardPaths : public wxStandardPaths public: wxString GetResourcesDir() const { - return Path::Combine( GetDataDir(), L"Langs" ); + return Path::CombineWx( GetDataDir(), L"Langs" ); } #ifdef __POSIX__ @@ -317,18 +317,18 @@ public: // Note: GetUserLocalDataDir() on linux return $HOME/.pcsx2 unfortunately it does not follow the XDG standard // So we re-implement it, to follow the standard. wxDirName user_local_dir; - wxDirName default_config_dir = (wxDirName)Path::Combine( L".config", pxGetAppName() ); + wxDirName default_config_dir = (wxDirName)Path::CombineWx( L".config", pxGetAppName() ); wxString xdg_home_value; if( wxGetEnv(L"XDG_CONFIG_HOME", &xdg_home_value) ) { if ( xdg_home_value.IsEmpty() ) { // variable exist but it is empty. So use the default value - user_local_dir = (wxDirName)Path::Combine( GetUserConfigDir() , default_config_dir); + user_local_dir = (wxDirName)Path::CombineWx( GetUserConfigDir() , default_config_dir); } else { - user_local_dir = (wxDirName)Path::Combine( xdg_home_value, pxGetAppName()); + user_local_dir = (wxDirName)Path::CombineWx( xdg_home_value, pxGetAppName()); } } else { // variable do not exist - user_local_dir = (wxDirName)Path::Combine( GetUserConfigDir() , default_config_dir); + user_local_dir = (wxDirName)Path::CombineWx( GetUserConfigDir() , default_config_dir); } cache_dir = user_local_dir.ToString(); diff --git a/pcsx2/gui/Debugger/DisassemblyDialog.cpp b/pcsx2/gui/Debugger/DisassemblyDialog.cpp index f3fef82d98..bcf98f0849 100644 --- a/pcsx2/gui/Debugger/DisassemblyDialog.cpp +++ b/pcsx2/gui/Debugger/DisassemblyDialog.cpp @@ -17,13 +17,13 @@ #include "gui/App.h" #include "gui/MainFrame.h" +#include "gui/PathDefs.h" #include "DisassemblyDialog.h" #include "DebugTools/DebugInterface.h" #include "DebugTools/DisassemblyManager.h" #include "DebugTools/Breakpoints.h" #include "DebugTools/MipsStackWalk.h" #include "BreakpointWindow.h" -#include "PathDefs.h" #include "wx/busyinfo.h" #ifdef _WIN32 @@ -57,7 +57,7 @@ DebuggerHelpDialog::DebuggerHelpDialog(wxWindow* parent) { wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); - auto fileName = Path::Combine(PathDefs::GetDocs(), wxFileName(L"debugger.txt")); + auto fileName = Path::CombineWx(PathDefs::GetDocs(), wxFileName(L"debugger.txt")); wxTextFile file(fileName); wxString text(L""); diff --git a/pcsx2/gui/Dialogs/ConvertMemoryCardDialog.cpp b/pcsx2/gui/Dialogs/ConvertMemoryCardDialog.cpp index dac99fecdc..22399a8768 100644 --- a/pcsx2/gui/Dialogs/ConvertMemoryCardDialog.cpp +++ b/pcsx2/gui/Dialogs/ConvertMemoryCardDialog.cpp @@ -178,7 +178,7 @@ bool Dialogs::ConvertMemoryCardDialog::ConvertToFile( const wxFileName& sourcePa Pcsx2Config::McdOptions config; config.Enabled = true; config.Type = MemoryCardType::Folder; - sourceFolderMemoryCard.Open( sourcePath.GetFullPath(), config, ( sizeInMB * 1024 * 1024 ) / FolderMemoryCard::ClusterSize, false, L"" ); + sourceFolderMemoryCard.Open( StringUtil::wxStringToUTF8String(sourcePath.GetFullPath()), config, ( sizeInMB * 1024 * 1024 ) / FolderMemoryCard::ClusterSize, false, "" ); u8 buffer[FolderMemoryCard::PageSizeRaw]; u32 adr = 0; @@ -214,7 +214,7 @@ bool Dialogs::ConvertMemoryCardDialog::ConvertToFolder( const wxFileName& source // This ensures that if we crash/fail due to a corrupted memory card file system or similar, we do so during // the simulation run, and don't actually write out any partial data to the host file system. bool simulateWrites = i == 0; - targetFolderMemoryCard.Open( targetPath.GetFullPath(), config, 0, false, L"", simulateWrites ); + targetFolderMemoryCard.Open(StringUtil::wxStringToUTF8String(targetPath.GetFullPath()), config, 0, false, "", simulateWrites ); adr = 0; sourceFile.Seek( 0 ); @@ -233,7 +233,7 @@ bool Dialogs::ConvertMemoryCardDialog::ConvertToFolder( const wxFileName& source if ( adr != FolderMemoryCard::TotalSizeRaw ) { // reset memory card metrics in superblock to the default 8MB, since the converted card was different - targetFolderMemoryCard.Open( targetPath.GetFullPath(), config, 0, true, L"" ); + targetFolderMemoryCard.Open(StringUtil::wxStringToUTF8String(targetPath.GetFullPath()), config, 0, true, "" ); targetFolderMemoryCard.SetSizeInMB( 8 ); targetFolderMemoryCard.Close(); } diff --git a/pcsx2/gui/Dialogs/GSDumpDialog.cpp b/pcsx2/gui/Dialogs/GSDumpDialog.cpp index f9f54995f1..1c23f62558 100644 --- a/pcsx2/gui/Dialogs/GSDumpDialog.cpp +++ b/pcsx2/gui/Dialogs/GSDumpDialog.cpp @@ -27,7 +27,7 @@ #include "gui/Resources/NoIcon.h" #include "HostDisplay.h" -#include "PathDefs.h" +#include "gui/PathDefs.h" #include "gui/AppConfig.h" #include "gui/GSFrame.h" #include "Counters.h" diff --git a/pcsx2/gui/Dialogs/PINEDialog.cpp b/pcsx2/gui/Dialogs/PINEDialog.cpp index e8b9888dd0..acd02aa7ab 100644 --- a/pcsx2/gui/Dialogs/PINEDialog.cpp +++ b/pcsx2/gui/Dialogs/PINEDialog.cpp @@ -22,7 +22,7 @@ #include "gui/SysThreads.h" -#include "PathDefs.h" +#include "gui/PathDefs.h" #include "gui/AppConfig.h" using namespace pxSizerFlags; diff --git a/pcsx2/Utilities/FileUtils.cpp b/pcsx2/gui/FileUtils.cpp similarity index 99% rename from pcsx2/Utilities/FileUtils.cpp rename to pcsx2/gui/FileUtils.cpp index e1869f3cfa..7b873f5c8c 100644 --- a/pcsx2/Utilities/FileUtils.cpp +++ b/pcsx2/gui/FileUtils.cpp @@ -15,6 +15,7 @@ #include "PrecompiledHeader.h" #include "common/Path.h" +#include "wxDirName.h" #include #include diff --git a/pcsx2/gui/IniInterface.h b/pcsx2/gui/IniInterface.h index 5a639d4c73..5c43208141 100644 --- a/pcsx2/gui/IniInterface.h +++ b/pcsx2/gui/IniInterface.h @@ -17,6 +17,7 @@ #include "common/Assertions.h" #include "common/Path.h" +#include "wxDirName.h" #include "StringHelpers.h" #include #include diff --git a/pcsx2/PathDefs.h b/pcsx2/gui/PathDefs.h similarity index 99% rename from pcsx2/PathDefs.h rename to pcsx2/gui/PathDefs.h index 00d8ad09e0..7502fb81c2 100644 --- a/pcsx2/PathDefs.h +++ b/pcsx2/gui/PathDefs.h @@ -15,7 +15,7 @@ #pragma once -#include "common/Path.h" +#include "wxDirName.h" enum FoldersEnum_t { diff --git a/common/PathUtils.cpp b/pcsx2/gui/PathUtils.cpp similarity index 82% rename from common/PathUtils.cpp rename to pcsx2/gui/PathUtils.cpp index 2ce75bfe3a..e5f13ef535 100644 --- a/common/PathUtils.cpp +++ b/pcsx2/gui/PathUtils.cpp @@ -16,6 +16,7 @@ #include "common/Path.h" #include "common/Assertions.h" #include "common/Exceptions.h" +#include "wxDirName.h" #include #include @@ -136,45 +137,21 @@ wxString Path::MakeAbsolute(const wxString& src) // Concatenates two pathnames together, inserting delimiters (backslash on win32) // as needed! Assumes the 'dest' is allocated to at least g_MaxPath length. // -wxString Path::Combine(const wxString& srcPath, const wxString& srcFile) +wxString Path::CombineWx(const wxString& srcPath, const wxString& srcFile) { return (wxDirName(srcPath) + srcFile).GetFullPath(); } -wxString Path::Combine(const wxDirName& srcPath, const wxFileName& srcFile) +wxString Path::CombineWx(const wxDirName& srcPath, const wxFileName& srcFile) { return (srcPath + srcFile).GetFullPath(); } -wxString Path::Combine(const wxString& srcPath, const wxDirName& srcFile) +wxString Path::CombineWx(const wxString& srcPath, const wxDirName& srcFile) { return (wxDirName(srcPath) + srcFile).ToString(); } -std::string Path::CombineStdString(const wxDirName& srcPath, const std::string_view& srcFile) -{ - const wxString wxResult((srcPath + wxString::FromUTF8(srcFile.data(), srcFile.length())).GetFullPath()); - const wxCharBuffer wxBuf(wxResult.ToUTF8()); - return std::string(wxBuf.data(), wxBuf.length()); -} - -std::string Path::CombineStdString(const std::string_view& srcPath, const std::string_view& srcFile) -{ - const wxDirName srcPathDir(wxString::FromUTF8(srcPath.data(), srcPath.length())); - const wxString wxResult((srcPathDir + wxString::FromUTF8(srcFile.data(), srcFile.length())).GetFullPath()); - const wxCharBuffer wxBuf(wxResult.ToUTF8()); - return std::string(wxBuf.data(), wxBuf.length()); -} - -// Replaces the extension of the file with the one given. -// This function works for path names as well as file names. -wxString Path::ReplaceExtension(const wxString& src, const wxString& ext) -{ - wxFileName jojo(src); - jojo.SetExt(ext); - return jojo.GetFullPath(); -} - wxString Path::ReplaceFilename(const wxString& src, const wxString& newfilename) { wxFileName jojo(src); @@ -215,4 +192,4 @@ fs::path Path::FromWxString(const wxString& path) #else return fs::path(path.ToStdString()); #endif -} \ No newline at end of file +} diff --git a/pcsx2/gui/StringHelpers.h b/pcsx2/gui/StringHelpers.h index 7ac01c58f6..274b230d43 100644 --- a/pcsx2/gui/StringHelpers.h +++ b/pcsx2/gui/StringHelpers.h @@ -16,6 +16,7 @@ #pragma once #include +#include #include #include #include "common/Pcsx2Defs.h" @@ -234,3 +235,19 @@ extern wxString fromAscii(const char* src); extern const wxChar* pxExpandMsg(const wxChar* message); extern const wxChar* pxGetTranslation(const wxChar* message); extern bool pxIsEnglish(int id); + +namespace StringUtil +{ + /// Converts a wxString to a UTF-8 std::string. + static inline std::string wxStringToUTF8String(const wxString& str) + { + const wxScopedCharBuffer buf(str.ToUTF8()); + return std::string(buf.data(), buf.length()); + } + + /// Converts a UTF-8 std::string to a wxString. + static inline wxString UTF8StringToWxString(const std::string_view& str) + { + return wxString::FromUTF8(str.data(), str.length()); + } +} diff --git a/pcsx2/gui/wxAppWithHelpers.cpp b/pcsx2/gui/wxAppWithHelpers.cpp index 27929b649f..02a6367ad7 100644 --- a/pcsx2/gui/wxAppWithHelpers.cpp +++ b/pcsx2/gui/wxAppWithHelpers.cpp @@ -175,7 +175,7 @@ void pxActionEvent::SetException(const BaseException& ex) void pxActionEvent::SetException(BaseException* ex) { - ex->DiagMsg() = StringUtil::WideStringToUTF8String(GetClassInfo()->GetClassName()) + ex->DiagMsg(); + ex->DiagMsg() = StringUtil::wxStringToUTF8String(GetClassInfo()->GetClassName()) + ex->DiagMsg(); if (!m_state) { diff --git a/pcsx2/gui/wxDirName.h b/pcsx2/gui/wxDirName.h new file mode 100644 index 0000000000..6888e2ae3c --- /dev/null +++ b/pcsx2/gui/wxDirName.h @@ -0,0 +1,239 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2010 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once + +#include "common/Pcsx2Defs.h" + +#include + +#include "ghc/filesystem.h" + +namespace fs = ghc::filesystem; + +#define g_MaxPath 255 // 255 is safer with antiquated Win32 ASCII APIs. + +// -------------------------------------------------------------------------------------- +// wxDirName +// -------------------------------------------------------------------------------------- +class wxDirName : protected wxFileName +{ +public: + explicit wxDirName(const wxFileName& src) + { + Assign(src.GetPath(), wxEmptyString); + } + + wxDirName() + : wxFileName() + { + } + wxDirName(const wxDirName& src) + : wxFileName(src) + { + } + explicit wxDirName(const char* src) { Assign(wxString(src, wxMBConvUTF8())); } + explicit wxDirName(const wxString& src) { Assign(src); } + + // ------------------------------------------------------------------------ + void Assign(const wxString& volume, const wxString& path) + { + wxFileName::Assign(volume, path, wxEmptyString); + } + + void Assign(const wxString& path) + { + wxFileName::Assign(path, wxEmptyString); + } + + void Assign(const wxDirName& path) + { + wxFileName::Assign(path); + } + + void Clear() { wxFileName::Clear(); } + + wxCharBuffer ToUTF8() const { return GetPath().ToUTF8(); } + wxCharBuffer ToAscii() const { return GetPath().ToAscii(); } + wxString ToString() const { return GetPath(); } + + // ------------------------------------------------------------------------ + bool IsWritable() const { return IsDirWritable(); } + bool IsReadable() const { return IsDirReadable(); } + bool Exists() const { return DirExists(); } + bool FileExists() const { return wxFileName::FileExists(); } + bool IsOk() const { return wxFileName::IsOk(); } + bool IsRelative() const { return wxFileName::IsRelative(); } + bool IsAbsolute() const { return wxFileName::IsAbsolute(); } + + bool SameAs(const wxDirName& filepath) const + { + return wxFileName::SameAs(filepath); + } + + //Returns true if the file is somewhere inside this directory (and both file and directory are not relative). + bool IsContains(const wxFileName& file) const + { + if (this->IsRelative() || file.IsRelative()) + return false; + + wxFileName f(file); + + while (1) + { + if (this->SameAs(wxDirName(f.GetPath()))) + return true; + + if (f.GetDirCount() == 0) + return false; + + f.RemoveLastDir(); + } + + return false; + } + + bool IsContains(const wxDirName& dir) const + { + return IsContains((wxFileName)dir); + } + + + //Auto relative works as follows: + // 1. if either base or subject are relative, return subject (should never be used with relative paths). + // 2. else if subject is somewhere inside base folder, then result is subject relative to base. + // 3. (windows only, implicitly) else if subject is on the same driveletter as base, result is absolute path of subject without the driveletter. + // 4. else, result is absolute path of subject. + // + // returns ok if both this and base are absolute paths. + static wxString MakeAutoRelativeTo(const wxFileName _subject, const wxString& pathbase) + { + wxFileName subject(_subject); + wxDirName base(pathbase); + if (base.IsRelative() || subject.IsRelative()) + return subject.GetFullPath(); + + wxString bv(base.GetVolume()); + bv.MakeUpper(); + wxString sv(subject.GetVolume()); + sv.MakeUpper(); + + if (base.IsContains(subject)) + { + subject.MakeRelativeTo(base.GetFullPath()); + } + else if (base.HasVolume() && subject.HasVolume() && bv == sv) + { + wxString unusedVolume; + wxString pathSansVolume; + subject.SplitVolume(subject.GetFullPath(), &unusedVolume, &pathSansVolume); + subject = pathSansVolume; + } + //implicit else: this stays fully absolute + + return subject.GetFullPath(); + } + + static wxString MakeAutoRelativeTo(const wxDirName subject, const wxString& pathbase) + { + return MakeAutoRelativeTo(wxFileName(subject), pathbase); + } + + // Returns the number of sub folders in this directory path + size_t GetCount() const { return GetDirCount(); } + + // ------------------------------------------------------------------------ + wxFileName Combine(const wxFileName& right) const; + wxDirName Combine(const wxDirName& right) const; + + // removes the lastmost directory from the path + void RemoveLast() { wxFileName::RemoveDir(GetCount() - 1); } + + wxDirName& Normalize(int flags = wxPATH_NORM_ALL, const wxString& cwd = wxEmptyString); + wxDirName& MakeRelativeTo(const wxString& pathBase = wxEmptyString); + wxDirName& MakeAbsolute(const wxString& cwd = wxEmptyString); + + // ------------------------------------------------------------------------ + + void AssignCwd(const wxString& volume = wxEmptyString) { wxFileName::AssignCwd(volume); } + bool SetCwd() { return wxFileName::SetCwd(); } + + // wxWidgets is missing the const qualifier for this one! Shame! + void Rmdir() const; + bool Mkdir() const; + + // ------------------------------------------------------------------------ + + wxDirName& operator=(const wxDirName& dirname) + { + Assign(dirname); + return *this; + } + wxDirName& operator=(const wxString& dirname) + { + Assign(dirname); + return *this; + } + wxDirName& operator=(const char* dirname) + { + Assign(wxString(dirname, wxMBConvUTF8())); + return *this; + } + + wxFileName operator+(const wxFileName& right) const { return Combine(right); } + wxDirName operator+(const wxDirName& right) const { return Combine(right); } + wxFileName operator+(const wxString& right) const { return Combine(wxFileName(right)); } + wxFileName operator+(const char* right) const { return Combine(wxFileName(wxString(right, wxMBConvUTF8()))); } + + bool operator==(const wxDirName& filename) const { return SameAs(filename); } + bool operator!=(const wxDirName& filename) const { return !SameAs(filename); } + + bool operator==(const wxFileName& filename) const { return SameAs(wxDirName(filename)); } + bool operator!=(const wxFileName& filename) const { return !SameAs(wxDirName(filename)); } + + // compare with a filename string interpreted as a native file name + bool operator==(const wxString& filename) const { return SameAs(wxDirName(filename)); } + bool operator!=(const wxString& filename) const { return !SameAs(wxDirName(filename)); } + + const wxFileName& GetFilename() const { return *this; } + wxFileName& GetFilename() { return *this; } +}; + +// -------------------------------------------------------------------------------------- +// Path Namespace +// -------------------------------------------------------------------------------------- +// Cross-platform utilities for manipulation of paths and filenames. Mostly these fall +// back on wxWidgets APIs internally, but are still helpful because some of wx's file stuff +// has minor glitches, or requires sloppy wxFileName typecasting. +// +namespace Path +{ + extern bool IsRelative(const wxString& path); + extern s64 GetFileSize(const wxString& path); + + extern wxString Normalize(const wxString& srcpath); + extern wxString Normalize(const wxDirName& srcpath); + extern wxString MakeAbsolute(const wxString& srcpath); + + extern wxString CombineWx(const wxString& srcPath, const wxString& srcFile); + extern wxString CombineWx(const wxDirName& srcPath, const wxFileName& srcFile); + extern wxString CombineWx(const wxString& srcPath, const wxDirName& srcFile); + extern wxString ReplaceFilename(const wxString& src, const wxString& newfilename); + extern wxString GetFilename(const wxString& src); + extern wxString GetDirectory(const wxString& src); + extern wxString GetFilenameWithoutExt(const wxString& src); + extern wxString GetRootDirectory(const wxString& src); + extern fs::path FromWxString(const wxString& path); +} // namespace Path diff --git a/pcsx2/gui/wxSettingsInterface.cpp b/pcsx2/gui/wxSettingsInterface.cpp index 934bbb036b..ac74a2278a 100644 --- a/pcsx2/gui/wxSettingsInterface.cpp +++ b/pcsx2/gui/wxSettingsInterface.cpp @@ -15,6 +15,7 @@ #include "PrecompiledHeader.h" +#include "StringHelpers.h" #include "wxSettingsInterface.h" #include "common/Assertions.h" #include "common/StringUtil.h" diff --git a/pcsx2/pcsx2.vcxproj b/pcsx2/pcsx2.vcxproj index 4efbf32f2b..05997e0a46 100644 --- a/pcsx2/pcsx2.vcxproj +++ b/pcsx2/pcsx2.vcxproj @@ -34,6 +34,7 @@ + $(SolutionDir)3rdparty\wxWidgets3.0\include;%(AdditionalIncludeDirectories) $(SolutionDir)3rdparty\xbyak;%(AdditionalIncludeDirectories) $(SolutionDir)3rdparty\xz\xz\src\liblzma\api;%(AdditionalIncludeDirectories) $(SolutionDir)3rdparty\baseclasses;%(AdditionalIncludeDirectories) @@ -358,9 +359,11 @@ + + @@ -549,7 +552,6 @@ - diff --git a/pcsx2/pcsx2.vcxproj.filters b/pcsx2/pcsx2.vcxproj.filters index a57c7fce76..910c1771a9 100644 --- a/pcsx2/pcsx2.vcxproj.filters +++ b/pcsx2/pcsx2.vcxproj.filters @@ -4,9 +4,6 @@ {d1e5f218-107b-4e8c-9527-55cb9388b544} - - {acd41072-b36e-4653-a430-40ade53fb78a} - {5dc872c1-db13-4c70-9d44-a3fc4b6fc241} @@ -437,9 +434,6 @@ Misc - - Misc\Utilities - System @@ -1793,6 +1787,12 @@ AppHost + + AppHost + + + AppHost + diff --git a/pcsx2/pcsx2core.vcxproj b/pcsx2/pcsx2core.vcxproj index d222b11aec..fa5b556517 100644 --- a/pcsx2/pcsx2core.vcxproj +++ b/pcsx2/pcsx2core.vcxproj @@ -225,7 +225,6 @@ - @@ -311,7 +310,6 @@ - @@ -739,9 +737,6 @@ - - - {27f17499-a372-4408-8afa-4f9f4584fbd3} @@ -761,9 +756,6 @@ {e9b51944-7e6d-4bcd-83f2-7bbd5a46182d} - - {3fcc50c2-81e9-5db2-b8d8-2129427568b1} - {12728250-16ec-4dc6-94d7-e21dd88947f8} @@ -774,10 +766,6 @@ {2f6c0388-20cb-4242-9f6c-a6ebb6a83f47} false - - {677b7d11-d5e1-40b3-88b1-9a4df83d2213} - false - {ed2f21fd-0a36-4a8f-9b90-e7d92a2acb63} diff --git a/pcsx2/pcsx2core.vcxproj.filters b/pcsx2/pcsx2core.vcxproj.filters index 2425226fb3..e45a8f36e9 100644 --- a/pcsx2/pcsx2core.vcxproj.filters +++ b/pcsx2/pcsx2core.vcxproj.filters @@ -347,9 +347,6 @@ Misc - - Misc\Utilities - System @@ -1193,9 +1190,6 @@ System\Ps2\SPU2 - - System\Ps2\SPU2 - System\Ps2\SPU2 @@ -2078,11 +2072,6 @@ Host - - - System\Ps2\GS - - System\Ps2\Debug\rdebug diff --git a/pcsx2/ps2/BiosTools.cpp b/pcsx2/ps2/BiosTools.cpp index 4167a9ae4b..a2573dc4ee 100644 --- a/pcsx2/ps2/BiosTools.cpp +++ b/pcsx2/ps2/BiosTools.cpp @@ -19,6 +19,7 @@ #include #include "common/FileSystem.h" +#include "common/Path.h" #include "common/StringUtil.h" #include "Common.h" @@ -180,7 +181,7 @@ static void LoadExtraRom(const char* ext, u8 (&dest)[_size]) if ((filesize = FileSystem::GetPathFileSize(Bios1.c_str())) <= 0) { // Try the name properly extensioned next (name.rom1) - Bios1 = FileSystem::ReplaceExtension(BiosPath, ext); + Bios1 = Path::ReplaceExtension(BiosPath, ext); if ((filesize = FileSystem::GetPathFileSize(Bios1.c_str())) <= 0) { Console.WriteLn(Color_Gray, "BIOS %s module not found, skipping...", ext); @@ -215,11 +216,10 @@ static void LoadIrx(const std::string& filename, u8* dest, size_t maxSize) static std::string FindBiosImage() { - const std::string dir(StringUtil::wxStringToUTF8String(EmuFolders::Bios.ToString())); - Console.WriteLn("Searching for a BIOS image in '%s'...", dir.c_str()); + Console.WriteLn("Searching for a BIOS image in '%s'...", EmuFolders::Bios.c_str()); FileSystem::FindResultsArray results; - if (!FileSystem::FindFiles(dir.c_str(), "*.*", FILESYSTEM_FIND_FILES, &results)) + if (!FileSystem::FindFiles(EmuFolders::Bios.c_str(), "*", FILESYSTEM_FIND_FILES, &results)) return std::string(); u32 version, region; @@ -322,7 +322,7 @@ bool LoadBIOS() bool IsBIOS(const char* filename, u32& version, std::string& description, u32& region, std::string& zone) { - const std::string bios_path(Path::CombineStdString(EmuFolders::Bios, filename)); + const std::string bios_path(Path::Combine(EmuFolders::Bios, filename)); const auto fp = FileSystem::OpenManagedCFile(filename, "rb"); if (!fp) return false; diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index e551b13a06..059e83b9b9 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -41,6 +41,7 @@ #include "common/AlignedMalloc.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "common/Perf.h" #include "DebugTools/Breakpoints.h" @@ -238,9 +239,9 @@ static void iIopDumpBlock(int startpc, u8* ptr) int numused, count; Console.WriteLn("dump1 %x:%x, %x", startpc, psxpc, psxRegs.cycle); - EmuFolders::Logs.Mkdir(); + FileSystem::CreateDirectoryPath(EmuFolders::Logs.c_str(), false); - std::string filename(Path::CombineStdString(EmuFolders::Logs, fmt::format("psxdump{:.8X}.txt", startpc))); + std::string filename(Path::Combine(EmuFolders::Logs, fmt::format("psxdump{:.8X}.txt", startpc))); std::FILE* f = FileSystem::OpenCFile(filename.c_str(), "w"); if (!f) return; diff --git a/pcsx2/x86/microVU_Log.inl b/pcsx2/x86/microVU_Log.inl index ddd8bf33b4..718849f649 100644 --- a/pcsx2/x86/microVU_Log.inl +++ b/pcsx2/x86/microVU_Log.inl @@ -18,6 +18,7 @@ #include "Config.h" #include "common/FileSystem.h" +#include "common/Path.h" #include "fmt/core.h" @@ -55,7 +56,7 @@ void __mVUdumpProgram(microVU& mVU, microProgram& prog) mVUbranch = 0; const std::string logname(fmt::format("microVU{} prog - {:02d}.html"), mVU.index, prog.idx); - mVU.logFile = FileSystem::OpenCFile(Path::CombineStdString(EmuFolders::Logs, logname).c_str(), "w"); + mVU.logFile = FileSystem::OpenCFile(Path::Combine(EmuFolders::Logs, logname).c_str(), "w"); if (!mVU.logFile) return; diff --git a/tests/ctest/CMakeLists.txt b/tests/ctest/CMakeLists.txt index cbb5d15bca..a57e3ca802 100644 --- a/tests/ctest/CMakeLists.txt +++ b/tests/ctest/CMakeLists.txt @@ -70,3 +70,4 @@ endmacro() add_subdirectory(x86emitter) add_subdirectory(GS) +add_subdirectory(common) \ No newline at end of file diff --git a/tests/ctest/common/CMakeLists.txt b/tests/ctest/common/CMakeLists.txt new file mode 100644 index 0000000000..974be98089 --- /dev/null +++ b/tests/ctest/common/CMakeLists.txt @@ -0,0 +1 @@ +add_pcsx2_test(common_test path_tests.cpp) diff --git a/tests/ctest/common/path_tests.cpp b/tests/ctest/common/path_tests.cpp new file mode 100644 index 0000000000..8703c2aa8a --- /dev/null +++ b/tests/ctest/common/path_tests.cpp @@ -0,0 +1,207 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2021 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "common/Pcsx2Defs.h" +#include "common/Path.h" +#include + +TEST(FileSystem, ToNativePath) +{ + ASSERT_EQ(Path::ToNativePath(""), ""); + +#ifdef _WIN32 + ASSERT_EQ(Path::ToNativePath("foo"), "foo"); + ASSERT_EQ(Path::ToNativePath("foo\\"), "foo"); + ASSERT_EQ(Path::ToNativePath("foo\\\\bar"), "foo\\bar"); + ASSERT_EQ(Path::ToNativePath("foo\\bar"), "foo\\bar"); + ASSERT_EQ(Path::ToNativePath("foo\\bar\\baz"), "foo\\bar\\baz"); + ASSERT_EQ(Path::ToNativePath("foo\\bar/baz"), "foo\\bar\\baz"); + ASSERT_EQ(Path::ToNativePath("foo/bar/baz"), "foo\\bar\\baz"); + ASSERT_EQ(Path::ToNativePath("foo/🙃bar/b🙃az"), "foo\\🙃bar\\b🙃az"); +#else + ASSERT_EQ(Path::ToNativePath("foo"), "foo"); + ASSERT_EQ(Path::ToNativePath("foo/"), "foo"); + ASSERT_EQ(Path::ToNativePath("foo//bar"), "foo/bar"); + ASSERT_EQ(Path::ToNativePath("foo/bar"), "foo/bar"); + ASSERT_EQ(Path::ToNativePath("foo/bar/baz"), "foo/bar/baz"); + ASSERT_EQ(Path::ToNativePath("/foo/bar/baz"), "/foo/bar/baz"); +#endif +} + +TEST(FileSystem, IsAbsolute) +{ + ASSERT_FALSE(Path::IsAbsolute("")); + ASSERT_FALSE(Path::IsAbsolute("foo")); + ASSERT_FALSE(Path::IsAbsolute("foo/bar")); + ASSERT_FALSE(Path::IsAbsolute("foo/b🙃ar")); +#ifdef _WIN32 + ASSERT_TRUE(Path::IsAbsolute("C:\\foo/bar")); + ASSERT_TRUE(Path::IsAbsolute("C://foo\\bar")); + ASSERT_FALSE(Path::IsAbsolute("\\foo/bar")); +#else + ASSERT_TRUE(Path::IsAbsolute("/foo/bar")); +#endif +} + +TEST(FileSystem, Canonicalize) +{ + ASSERT_EQ(Path::Canonicalize(""), Path::ToNativePath("")); + ASSERT_EQ(Path::Canonicalize("foo/bar/../baz"), Path::ToNativePath("foo/baz")); + ASSERT_EQ(Path::Canonicalize("foo/bar/./baz"), Path::ToNativePath("foo/bar/baz")); + ASSERT_EQ(Path::Canonicalize("foo/./bar/./baz"), Path::ToNativePath("foo/bar/baz")); + ASSERT_EQ(Path::Canonicalize("foo/bar/../baz/../foo"), Path::ToNativePath("foo/foo")); + ASSERT_EQ(Path::Canonicalize("foo/bar/../baz/./foo"), Path::ToNativePath("foo/baz/foo")); + ASSERT_EQ(Path::Canonicalize("./foo"), Path::ToNativePath("foo")); + ASSERT_EQ(Path::Canonicalize("../foo"), Path::ToNativePath("../foo")); + ASSERT_EQ(Path::Canonicalize("foo/b🙃ar/../b🙃az/./foo"), Path::ToNativePath("foo/b🙃az/foo")); + ASSERT_EQ(Path::Canonicalize("ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱/b🙃az/../foℹ︎o"), Path::ToNativePath("ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱/foℹ︎o")); +#ifdef _WIN32 + ASSERT_EQ(Path::Canonicalize("C:\\foo\\bar\\..\\baz\\.\\foo"), "C:\\foo\\baz\\foo"); + ASSERT_EQ(Path::Canonicalize("C:/foo\\bar\\..\\baz\\.\\foo"), "C:\\foo\\baz\\foo"); + ASSERT_EQ(Path::Canonicalize("foo\\bar\\..\\baz\\.\\foo"), "foo\\baz\\foo"); + ASSERT_EQ(Path::Canonicalize("foo\\bar/..\\baz/.\\foo"), "foo\\baz\\foo"); +#else + ASSERT_EQ(Path::Canonicalize("/foo/bar/../baz/./foo"), "/foo/baz/foo"); +#endif +} + +TEST(FileSystem, Combine) +{ + ASSERT_EQ(Path::Combine("", ""), Path::ToNativePath("")); + ASSERT_EQ(Path::Combine("foo", "bar"), Path::ToNativePath("foo/bar")); + ASSERT_EQ(Path::Combine("foo/bar", "baz"), Path::ToNativePath("foo/bar/baz")); + ASSERT_EQ(Path::Combine("foo/bar", "../baz"), Path::ToNativePath("foo/bar/../baz")); + ASSERT_EQ(Path::Combine("foo/bar/", "/baz/"), Path::ToNativePath("foo/bar/baz")); + ASSERT_EQ(Path::Combine("foo//bar", "baz/"), Path::ToNativePath("foo/bar/baz")); + ASSERT_EQ(Path::Combine("foo//ba🙃r", "b🙃az/"), Path::ToNativePath("foo/ba🙃r/b🙃az")); +#ifdef _WIN32 + ASSERT_EQ(Path::Combine("C:\\foo\\bar", "baz"), "C:\\foo\\bar\\baz"); + ASSERT_EQ(Path::Combine("\\\\server\\foo\\bar", "baz"), "\\\\server\\foo\\bar\\baz"); + ASSERT_EQ(Path::Combine("foo\\bar", "baz"), "foo\\bar\\baz"); + ASSERT_EQ(Path::Combine("foo\\bar\\", "baz"), "foo\\bar\\baz"); + ASSERT_EQ(Path::Combine("foo/bar\\", "\\baz"), "foo\\bar\\baz"); +#else + ASSERT_EQ(Path::Combine("/foo/bar", "baz"), "/foo/bar/baz"); +#endif +} + +TEST(FileSystem, AppendDirectory) +{ + ASSERT_EQ(Path::AppendDirectory("foo/bar", "baz"), Path::ToNativePath("foo/baz/bar")); + ASSERT_EQ(Path::AppendDirectory("", "baz"), Path::ToNativePath("baz")); + ASSERT_EQ(Path::AppendDirectory("", ""), Path::ToNativePath("")); + ASSERT_EQ(Path::AppendDirectory("foo/bar", "🙃"), Path::ToNativePath("foo/🙃/bar")); +#ifdef _WIN32 + ASSERT_EQ(Path::AppendDirectory("foo\\bar", "baz"), "foo\\baz\\bar"); + ASSERT_EQ(Path::AppendDirectory("\\\\foo\\bar", "baz"), "\\\\foo\\baz\\bar"); +#else + ASSERT_EQ(Path::AppendDirectory("/foo/bar", "baz"), "/foo/baz/bar"); +#endif +} + +TEST(FileSystem, MakeRelative) +{ + ASSERT_EQ(Path::MakeRelative("", ""), Path::ToNativePath("")); + ASSERT_EQ(Path::MakeRelative("foo", ""), Path::ToNativePath("foo")); + ASSERT_EQ(Path::MakeRelative("", "foo"), Path::ToNativePath("")); + ASSERT_EQ(Path::MakeRelative("foo", "bar"), Path::ToNativePath("foo")); + +#ifdef _WIN32 +#define A "C:\\" +#else +#define A "/" +#endif + + ASSERT_EQ(Path::MakeRelative(A "foo", A "bar"), Path::ToNativePath("../foo")); + ASSERT_EQ(Path::MakeRelative(A "foo/bar", A "foo"), Path::ToNativePath("bar")); + ASSERT_EQ(Path::MakeRelative(A "foo/bar", A "foo/baz"), Path::ToNativePath("../bar")); + ASSERT_EQ(Path::MakeRelative(A "foo/b🙃ar", A "foo/b🙃az"), Path::ToNativePath("../b🙃ar")); + ASSERT_EQ(Path::MakeRelative(A "f🙃oo/b🙃ar", A "f🙃oo/b🙃az"), Path::ToNativePath("../b🙃ar")); + ASSERT_EQ(Path::MakeRelative(A "ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱/b🙃ar", A "ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱/b🙃az"), Path::ToNativePath("../b🙃ar")); + +#undef A +} + +TEST(FileSystem, GetExtension) +{ + ASSERT_EQ(Path::GetExtension("foo"), ""); + ASSERT_EQ(Path::GetExtension("foo.txt"), "txt"); + ASSERT_EQ(Path::GetExtension("foo.t🙃t"), "t🙃t"); + ASSERT_EQ(Path::GetExtension("foo."), ""); + ASSERT_EQ(Path::GetExtension("a/b/foo.txt"), "txt"); + ASSERT_EQ(Path::GetExtension("a/b/foo"), ""); +} + +TEST(FileSystem, GetFileName) +{ + ASSERT_EQ(Path::GetFileName(""), ""); + ASSERT_EQ(Path::GetFileName("foo"), "foo"); + ASSERT_EQ(Path::GetFileName("foo.txt"), "foo.txt"); + ASSERT_EQ(Path::GetFileName("foo"), "foo"); + ASSERT_EQ(Path::GetFileName("foo/bar/."), "."); + ASSERT_EQ(Path::GetFileName("foo/bar/baz"), "baz"); + ASSERT_EQ(Path::GetFileName("foo/bar/baz.txt"), "baz.txt"); +#ifdef _WIN32 + ASSERT_EQ(Path::GetFileName("foo/bar\\baz"), "baz"); + ASSERT_EQ(Path::GetFileName("foo\\bar\\baz.txt"), "baz.txt"); +#endif +} + +TEST(FileSystem, GetFileTitle) +{ + ASSERT_EQ(Path::GetFileTitle(""), ""); + ASSERT_EQ(Path::GetFileTitle("foo"), "foo"); + ASSERT_EQ(Path::GetFileTitle("foo.txt"), "foo"); + ASSERT_EQ(Path::GetFileTitle("foo/bar/."), ""); + ASSERT_EQ(Path::GetFileTitle("foo/bar/baz"), "baz"); + ASSERT_EQ(Path::GetFileTitle("foo/bar/baz.txt"), "baz"); +#ifdef _WIN32 + ASSERT_EQ(Path::GetFileTitle("foo/bar\\baz"), "baz"); + ASSERT_EQ(Path::GetFileTitle("foo\\bar\\baz.txt"), "baz"); +#endif +} + +TEST(FileSystem, GetDirectory) +{ + ASSERT_EQ(Path::GetDirectory(""), ""); + ASSERT_EQ(Path::GetDirectory("foo"), ""); + ASSERT_EQ(Path::GetDirectory("foo.txt"), ""); + ASSERT_EQ(Path::GetDirectory("foo/bar/."), "foo/bar"); + ASSERT_EQ(Path::GetDirectory("foo/bar/baz"), "foo/bar"); + ASSERT_EQ(Path::GetDirectory("foo/bar/baz.txt"), "foo/bar"); +#ifdef _WIN32 + ASSERT_EQ(Path::GetDirectory("foo\\bar\\baz"), "foo\\bar"); + ASSERT_EQ(Path::GetDirectory("foo\\bar/baz.txt"), "foo\\bar"); +#endif +} + +TEST(FileSystem, ChangeFileName) +{ + ASSERT_EQ(Path::ChangeFileName("", ""), Path::ToNativePath("")); + ASSERT_EQ(Path::ChangeFileName("", "bar"), Path::ToNativePath("bar")); + ASSERT_EQ(Path::ChangeFileName("bar", ""), Path::ToNativePath("")); + ASSERT_EQ(Path::ChangeFileName("foo/bar", ""), Path::ToNativePath("foo")); + ASSERT_EQ(Path::ChangeFileName("foo/", "bar"), Path::ToNativePath("foo/bar")); + ASSERT_EQ(Path::ChangeFileName("foo/bar", "baz"), Path::ToNativePath("foo/baz")); + ASSERT_EQ(Path::ChangeFileName("foo//bar", "baz"), Path::ToNativePath("foo/baz")); + ASSERT_EQ(Path::ChangeFileName("foo//bar.txt", "baz.txt"), Path::ToNativePath("foo/baz.txt")); + ASSERT_EQ(Path::ChangeFileName("foo//ba🙃r.txt", "ba🙃z.txt"), Path::ToNativePath("foo/ba🙃z.txt")); +#ifdef _WIN32 + ASSERT_EQ(Path::ChangeFileName("foo/bar", "baz"), "foo\\baz"); + ASSERT_EQ(Path::ChangeFileName("foo//bar\\foo", "baz"), "foo\\bar\\baz"); +#else + ASSERT_EQ(Path::ChangeFileName("/foo/bar", "baz"), "/foo/baz"); +#endif +} \ No newline at end of file diff --git a/updater/Updater.cpp b/updater/Updater.cpp index 28ee8cbdc9..6d6288c758 100644 --- a/updater/Updater.cpp +++ b/updater/Updater.cpp @@ -94,7 +94,7 @@ Updater::~Updater() void Updater::SetupLogging(ProgressCallback* progress, const std::string& destination_directory) { - const std::string log_path(Path::CombineStdString(destination_directory, "updater.log")); + const std::string log_path(Path::Combine(destination_directory, "updater.log")); s_file_console_stream = FileSystem::OpenCFile(log_path.c_str(), "w"); if (!s_file_console_stream) {