Compare commits
400 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 04e52ffed0 | |||
| 91f559a71f | |||
| 65b389da70 | |||
| 348ca07e0d | |||
| 0a6f685ad0 | |||
| 185e405bc1 | |||
| 519ddfae04 | |||
| 1914a1d21c | |||
| f34176996e | |||
| 95f45112e9 | |||
| a5ebba7e36 | |||
| a6cfc73cb2 | |||
| 90c3dd300f | |||
| f072f48806 | |||
| 2069430baa | |||
| fc708b396b | |||
| e41c8b6780 | |||
| 646622ccd4 | |||
| c7c4ef9d43 | |||
| cdabc9064b | |||
| 8592f8a2b4 | |||
| 42a7c5d017 | |||
| 5388e6db84 | |||
| 38dbe57797 | |||
| ddb186e61d | |||
| 7b2917b4e1 | |||
| 5a8cd1b118 | |||
| d2d7a5060f | |||
| 16ff0161b3 | |||
| 420b1f89d3 | |||
| ee099b2697 | |||
| 945effcc75 | |||
| 5554de3933 | |||
| 8171ad65cd | |||
| d25648cb6c | |||
| 210c2c9a56 | |||
| 6806a893bd | |||
| 019bc9f6b2 | |||
| c68255f70f | |||
| 247cd92216 | |||
| 3289abe1cc | |||
| 4b95b0df97 | |||
| 3d2e80daed | |||
| d825dff259 | |||
| 9110cfdefb | |||
| f94cb0bdb2 | |||
| 19454e71d8 | |||
| 116989be8e | |||
| 2c791b38e6 | |||
| 52cc25ccbf | |||
| 993dbe49fc | |||
| 65e20f424a | |||
| 02169406be | |||
| bc38d4c81b | |||
| 3394f24728 | |||
| cfb9bcbe42 | |||
| 065867e2c2 | |||
| 08a5cf0b5b | |||
| 8094743f63 | |||
| 4bf53eb935 | |||
| b6b73d9a5a | |||
| c1bad4357a | |||
| ec28d3c439 | |||
| d84a93c987 | |||
| aee3b57c44 | |||
| 49bfd0c461 | |||
| 00213377b1 | |||
| db7abfecdd | |||
| 7f445a59fa | |||
| 3ead4a3494 | |||
| ea4b7226a6 | |||
| bb22d6d8f7 | |||
| ecacb002be | |||
| 922d5187c4 | |||
| 5068279f23 | |||
| 136e8e829f | |||
| 6418a42884 | |||
| e33ffdc555 | |||
| b4fc2e52a2 | |||
| 7331bb9d8d | |||
| f4fe71c1c9 | |||
| 342170fcd3 | |||
| 7361eac10f | |||
| c40e7593f5 | |||
| ea4e4b05e4 | |||
| 7626ca3343 | |||
| 3a6e2922a2 | |||
| 5153d5387a | |||
| b5d21cc1b1 | |||
| 41b1f8d616 | |||
| 12ef74456c | |||
| 5396593b55 | |||
| 7d86a6ff02 | |||
| 61f293e5c9 | |||
| 7f78b17e20 | |||
| 44556dc21a | |||
| a9d8e24e47 | |||
| 74f30c0223 | |||
| 20699e90fa | |||
| 2f1ef3910b | |||
| 60831eabd9 | |||
| 93bc59b62d | |||
| 339dc4f806 | |||
| b462618ed7 | |||
| e8269fe3bc | |||
| d001687ca6 | |||
| cd6dcef5aa | |||
| 0a74d8490a | |||
| af69b48390 | |||
| 440eb840ea | |||
| bfe8816f7c | |||
| acf22336ec | |||
| 9ec26a805a | |||
| d5131805ce | |||
| ad6e20cfde | |||
| e8d2de1f99 | |||
| a170aa16b6 | |||
| 049769a0c9 | |||
| 81a5ecdb18 | |||
| 9edfd88a8a | |||
| 9a07ed53eb | |||
| 06c410ee88 | |||
| ab2677f0a1 | |||
| 5a2b15bf75 | |||
| a1138028a8 | |||
| faaea00069 | |||
| 6c78c2ae38 | |||
| 4aac1ae4b1 | |||
| 59236b7d0f | |||
| e169fdad4f | |||
| 5bef54618a | |||
| a3e68dce56 | |||
| f20f4587e6 | |||
| edd498f6e0 | |||
| 85eeae7aad | |||
| 904584e4ba | |||
| fd7c273fab | |||
| 0949e38263 | |||
| 0ecb6c6647 | |||
| e12ee020e7 | |||
| c8707628f6 | |||
| 271f2e2d78 | |||
| 5a042bdaa1 | |||
| eee302b9b9 | |||
| 12d569e483 | |||
| fc086f93b2 | |||
| f2c26443f8 | |||
| b9f543b29f | |||
| 02547439b1 | |||
| 343d92a092 | |||
| 2c1e119c4a | |||
| 913971417e | |||
| 49c4c329f6 | |||
| 21671d05a3 | |||
| da25a59866 | |||
| 41928dfdda | |||
| 934b2d8842 | |||
| f54ea749a4 | |||
| c6de9657be | |||
| 44c763f9c6 | |||
| cfed6936f3 | |||
| 9f44a44f2f | |||
| 75f23ad494 | |||
| 7a06037c5f | |||
| ed25191ee6 | |||
| d08bd3e062 | |||
| 1b4331397b | |||
| 0aff3ba2ff | |||
| ec50a9b5b9 | |||
| fa647cc0b9 | |||
| bb7d4ec3d3 | |||
| 0c1bb46f0a | |||
| 648bef235e | |||
| f2b76284ed | |||
| b021e09fc0 | |||
| 751cc687bb | |||
| 2f62bae9e3 | |||
| 72a49c2bbc | |||
| faa067f175 | |||
| 3671fd0a97 | |||
| 8acf739b3f | |||
| 8f638e81e9 | |||
| da62e92784 | |||
| d57b12193b | |||
| b805ee653f | |||
| d2c4dbde9e | |||
| 2c4615f3a6 | |||
| a488b86e97 | |||
| 510f71d871 | |||
| 9f81221528 | |||
| eae107d0e9 | |||
| da22def511 | |||
| f23760b1e1 | |||
| 1e983b19df | |||
| ad5a5ef43f | |||
| e02785be83 | |||
| 27a6ef64fd | |||
| 9434603450 | |||
| 703d7aaab6 | |||
| 9beb239634 | |||
| 2cdc7142b0 | |||
| 34abe4a905 | |||
| f6d45b747e | |||
| 1b074b8984 | |||
| 50d2dc3b51 | |||
| d23f9f75ff | |||
| 4356361faf | |||
| 51aa5a5364 | |||
| 25538db150 | |||
| 9bae3992e6 | |||
| 91d8657959 | |||
| d3c166d4d5 | |||
| 0536004d91 | |||
| 57f80c74b6 | |||
| caa11748c6 | |||
| 7866eb03bb | |||
| 4b03e6e776 | |||
| 8f5052a514 | |||
| 0b27c721c9 | |||
| 2a7eff57a8 | |||
| bf380b8584 | |||
| 864841eb9e | |||
| 39a8dba9a6 | |||
| 626f746971 | |||
| 7a06864100 | |||
| 0297448fbc | |||
| aa2844bcf9 | |||
| b57c5a9b54 | |||
| 674122038a | |||
| 126aaeb6d3 | |||
| c7d8b7421c | |||
| 7444963bbb | |||
| 2cb6106523 | |||
| 76a0814142 | |||
| 84bb772003 | |||
| 269d233a94 | |||
| c2f6f2ba7a | |||
| 2e8d6fe9a0 | |||
| eba3bb9d21 | |||
| cfa7b92563 | |||
| 89edbe8aa2 | |||
| b6156e735c | |||
| ab704acab8 | |||
| 722195cf70 | |||
| addc0bf037 | |||
| 086db71e94 | |||
| 7ccbdd4d8d | |||
| 5e5933256b | |||
| da7e9553de | |||
| 6fca1c82fd | |||
| de4746ff69 | |||
| 0eeecde67c | |||
| 479bd50b96 | |||
| d3d0f2f451 | |||
| 34bed1ab41 | |||
| d9df63583f | |||
| 3401676768 | |||
| 02c2b28cd0 | |||
| 66f2ad716b | |||
| 74120c5e3a | |||
| f93d939426 | |||
| 34ce1dd7c7 | |||
| b8751630e2 | |||
| d9205f82b3 | |||
| b99fc70191 | |||
| 260b841dc3 | |||
| 0b7a03bd65 | |||
| 860d73637e | |||
| 8c30ed6d09 | |||
| cc47a6a9c2 | |||
| 403cf6be69 | |||
| 9e726a9250 | |||
| df51eb9bde | |||
| 898aa5fb66 | |||
| ebb64d5bf4 | |||
| 7d257ce7bd | |||
| 707ed72a3c | |||
| 08d5bd36d8 | |||
| 6e81473574 | |||
| c17a59b58e | |||
| 0d2d0844a5 | |||
| 01a57d4c8d | |||
| 1da72c7792 | |||
| 54dc22285b | |||
| 03b3c5800b | |||
| 07934f0e87 | |||
| 72b22fd433 | |||
| 1ed1dd3c89 | |||
| fa3ffff8de | |||
| aab57b7975 | |||
| 497ccfaedc | |||
| 922b0d9933 | |||
| bea6fca9a1 | |||
| fc84822266 | |||
| 29a06ad393 | |||
| e1a196cfd7 | |||
| 0af182baa2 | |||
| d95605cd24 | |||
| b096ec68cd | |||
| 724c19a307 | |||
| cfdec68d5a | |||
| 729545a946 | |||
| cd80471c90 | |||
| dec5680934 | |||
| 6a2084a204 | |||
| dcb91ca4a4 | |||
| 7412f314e4 | |||
| 3c5fb53634 | |||
| 609c11bab3 | |||
| 697a2c0018 | |||
| 3b5690c9e1 | |||
| 2ff39f6fdc | |||
| ae758a236f | |||
| 75e0d16caa | |||
| c413cafdac | |||
| 4c8c5ad1b6 | |||
| 98fb36cb0a | |||
| a02c4686c3 | |||
| 1acd807176 | |||
| f4610e77e2 | |||
| c19ad21ae8 | |||
| 04d9c27120 | |||
| 4cc8ab8a86 | |||
| 2e268abe42 | |||
| 51c787bfc1 | |||
| 1c65b3ee53 | |||
| 19bbdedf00 | |||
| d363b2c7d2 | |||
| 8805233f5e | |||
| 9c5248d101 | |||
| 502f3cef87 | |||
| 29cd40bded | |||
| 5ba49f188b | |||
| 6e2040c955 | |||
| ae93402312 | |||
| 80d74d77d5 | |||
| 5568fcfec1 | |||
| cdce1edf74 | |||
| d1e35a37be | |||
| ad55faaa35 | |||
| 86278f5db2 | |||
| 607ff3489c | |||
| f0c2190ceb | |||
| 956b2bd332 | |||
| ea78f9a2ef | |||
| 4cd6c3e6f1 | |||
| 8cdd86fa25 | |||
| 7083c5bfc8 | |||
| 6125590a7b | |||
| aaaca1cd6d | |||
| 17704271f4 | |||
| e5e9bee1cc | |||
| 0da84c4de8 | |||
| 17b7f0389a | |||
| 27eeb20001 | |||
| 9f39f7c041 | |||
| b7d04d848d | |||
| 39497183a6 | |||
| 8285776603 | |||
| a223006c50 | |||
| 9e7713c150 | |||
| 7d0d2af3fa | |||
| f973274b99 | |||
| de69a5266f | |||
| 2a2a578932 | |||
| b17f031e35 | |||
| ce921e0f26 | |||
| 51ca93981d | |||
| ba2c917842 | |||
| 9ad77ba6d3 | |||
| d5c1f3929c | |||
| 12e58917c0 | |||
| bb32a4a8d7 | |||
| 71d4abcfd4 | |||
| 0a5bc8ec14 | |||
| edb1d5d242 | |||
| 7eff91ff20 | |||
| b45930a0ed | |||
| 4143675b2d | |||
| 4a5f9f5a6d | |||
| aa3adf6c3f | |||
| f6e6913f8f | |||
| e681723a4a | |||
| 578e6c5a57 | |||
| 5bc9f15c6d | |||
| a8c09cd5e4 | |||
| e3e6a11ab8 | |||
| 0a40106cf1 | |||
| d1e40dd244 | |||
| 0f40c8c634 | |||
| 60511976bb | |||
| 2a341c9969 | |||
| 64606aefcf | |||
| de5bf640b7 | |||
| a4c6712a4b | |||
| c6c0771b12 | |||
| eedbe8351c | |||
| 2067115c78 | |||
| d9db1d125e | |||
| bf1c1788ca |
@@ -8,7 +8,17 @@ cd /yuzu
|
||||
ccache -s
|
||||
|
||||
mkdir build || true && cd build
|
||||
cmake .. -DDISPLAY_VERSION=$1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DCMAKE_INSTALL_PREFIX="/usr"
|
||||
cmake .. \
|
||||
-DBoost_USE_STATIC_LIBS=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ \
|
||||
-DCMAKE_C_COMPILER=/usr/lib/ccache/gcc \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DDISPLAY_VERSION=$1 \
|
||||
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
|
||||
-DENABLE_QT_TRANSLATION=ON \
|
||||
-DUSE_DISCORD_PRESENCE=ON \
|
||||
-DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"}
|
||||
|
||||
make -j$(nproc)
|
||||
|
||||
@@ -20,10 +30,10 @@ make install DESTDIR=AppDir
|
||||
rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester
|
||||
|
||||
# Download tools needed to build an AppImage
|
||||
wget -nc https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
|
||||
wget -nc https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
|
||||
wget -nc https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/AppRun-patched-x86_64
|
||||
wget -nc https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/exec-x86_64.so
|
||||
wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/linuxdeploy-x86_64.AppImage
|
||||
wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/linuxdeploy-plugin-qt-x86_64.AppImage
|
||||
wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/AppRun-patched-x86_64
|
||||
wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/exec-x86_64.so
|
||||
# Set executable bit
|
||||
chmod 755 \
|
||||
AppRun-patched-x86_64 \
|
||||
|
||||
@@ -21,7 +21,7 @@ cp build/bin/yuzu "$DIR_NAME"
|
||||
# Build an AppImage
|
||||
cd build
|
||||
|
||||
wget -nc https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/appimagetool-x86_64.AppImage
|
||||
chmod 755 appimagetool-x86_64.AppImage
|
||||
|
||||
if [ "${RELEASE_NAME}" = "mainline" ]; then
|
||||
|
||||
@@ -47,3 +47,6 @@ python3 .ci/scripts/windows/scan_dll.py package/imageformats/*.dll "package/"
|
||||
EXTERNALS_PATH="$(pwd)/build/externals"
|
||||
FFMPEG_DLL_PATH="$(find ${EXTERNALS_PATH} -maxdepth 1 -type d | grep ffmpeg)/bin"
|
||||
find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';'
|
||||
|
||||
# copy libraries from yuzu.exe path
|
||||
find "$(pwd)/build/bin/" -type f -regex ".*\.dll" -exec cp -v {} package/ ';'
|
||||
|
||||
@@ -8,7 +8,7 @@ steps:
|
||||
displayName: 'Install vulkan-sdk'
|
||||
- script: python -m pip install --upgrade pip conan
|
||||
displayName: 'Install conan'
|
||||
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cmake --install . --config Release && cd ..
|
||||
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release .. && cd ..
|
||||
displayName: 'Configure CMake'
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build'
|
||||
|
||||
@@ -40,3 +40,6 @@
|
||||
[submodule "ffmpeg"]
|
||||
path = externals/ffmpeg
|
||||
url = https://git.ffmpeg.org/ffmpeg.git
|
||||
[submodule "SDL"]
|
||||
path = externals/SDL
|
||||
url = https://github.com/libsdl-org/SDL.git
|
||||
|
||||
@@ -11,14 +11,19 @@ project(yuzu)
|
||||
# Set bundled sdl2/qt as dependent options.
|
||||
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
|
||||
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
|
||||
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
|
||||
option(YUZU_ALLOW_SYSTEM_SDL2 "Try using system SDL2 before fallling back to one from externals" OFF)
|
||||
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "ENABLE_QT;MSVC" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
|
||||
|
||||
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled yuzu" ON "WIN32" OFF)
|
||||
option(YUZU_USE_BUNDLED_BOOST "Download bundled Boost" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" ON "WIN32" OFF)
|
||||
|
||||
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
|
||||
|
||||
@@ -166,12 +171,10 @@ macro(yuzu_find_packages)
|
||||
# Cmake Pkg Prefix Version Conan Pkg
|
||||
"Catch2 2.13 catch2/2.13.0"
|
||||
"fmt 7.1 fmt/7.1.2"
|
||||
# can't use until https://github.com/bincrafters/community/issues/1173
|
||||
#"libzip 1.5 libzip/1.5.2@bincrafters/stable"
|
||||
"lz4 1.8 lz4/1.9.2"
|
||||
"nlohmann_json 3.8 nlohmann_json/3.8.0"
|
||||
"ZLIB 1.2 zlib/1.2.11"
|
||||
"zstd 1.4 zstd/1.4.8"
|
||||
"zstd 1.5 zstd/1.5.0"
|
||||
# can't use opus until AVX check is fixed: https://github.com/yuzu-emu/yuzu/pull/4068
|
||||
#"opus 1.3 opus/1.3.1"
|
||||
)
|
||||
@@ -200,7 +203,9 @@ macro(yuzu_find_packages)
|
||||
unset(FN_FORCE_REQUIRED)
|
||||
endmacro()
|
||||
|
||||
find_package(Boost 1.73.0 COMPONENTS context headers QUIET)
|
||||
if (NOT YUZU_USE_BUNDLED_BOOST)
|
||||
find_package(Boost 1.73.0 CONFIG COMPONENTS context headers QUIET)
|
||||
endif()
|
||||
if (Boost_FOUND)
|
||||
set(Boost_LIBRARIES Boost::boost)
|
||||
# Conditionally add Boost::context only if the active version of the Conan or system Boost package provides it
|
||||
@@ -211,6 +216,20 @@ if (Boost_FOUND)
|
||||
if (TARGET Boost::context)
|
||||
list(APPEND Boost_LIBRARIES Boost::context)
|
||||
endif()
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR YUZU_USE_BUNDLED_BOOST)
|
||||
message(STATUS "Boost 1.73.0 or newer not found, falling back to externals")
|
||||
set(YUZU_USE_BUNDLED_BOOST ON CACHE BOOL "Download bundled Boost" FORCE)
|
||||
|
||||
# Use yuzu Boost binaries
|
||||
set(Boost_EXT_NAME "boost_1_75_0")
|
||||
set(Boost_PATH "${CMAKE_BINARY_DIR}/externals/${Boost_EXT_NAME}")
|
||||
download_bundled_external("boost/" ${Boost_EXT_NAME} "")
|
||||
set(Boost_USE_DEBUG_RUNTIME FALSE)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
find_package(Boost 1.75.0 CONFIG REQUIRED COMPONENTS context headers PATHS ${Boost_PATH} NO_DEFAULT_PATH)
|
||||
# Manually set the include dirs since the find_package sets it incorrectly
|
||||
set(Boost_INCLUDE_DIRS ${Boost_PATH}/include CACHE PATH "Path to Boost headers" FORCE)
|
||||
include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
|
||||
else()
|
||||
message(STATUS "Boost 1.73.0 or newer not found, falling back to Conan")
|
||||
list(APPEND CONAN_REQUIRED_LIBS "boost/1.73.0")
|
||||
@@ -221,6 +240,7 @@ yuzu_find_packages()
|
||||
|
||||
# Qt5 requires that we find components, so it doesn't fit our pretty little find package function
|
||||
if(ENABLE_QT)
|
||||
set(QT_VERSION 5.12)
|
||||
# We want to load the generated conan qt config so that we get the QT_ROOT var so that we can use the official
|
||||
# Qt5Config inside the root folder instead of the conan generated one.
|
||||
if(EXISTS ${CMAKE_BINARY_DIR}/qtConfig.cmake)
|
||||
@@ -228,22 +248,40 @@ if(ENABLE_QT)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CONAN_QT_ROOT_RELEASE}")
|
||||
list(APPEND CMAKE_PREFIX_PATH "${CONAN_QT_ROOT_RELEASE}")
|
||||
endif()
|
||||
|
||||
# Check for system Qt on Linux, fallback to bundled Qt
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
if (NOT YUZU_USE_BUNDLED_QT)
|
||||
find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets QUIET)
|
||||
if (NOT Qt5_FOUND)
|
||||
set(YUZU_USE_BUNDLED_QT ON CACHE BOOL "Download bundled Qt" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
if (YUZU_USE_BUNDLED_QT)
|
||||
# Binary package currently does not support Qt webengine, so make sure it's disabled
|
||||
set(YUZU_USE_QT_WEB_ENGINE OFF CACHE BOOL "Use Qt Webengine" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Workaround for an issue where conan tries to build Qt from scratch instead of download prebuilt binaries
|
||||
set(QT_PREFIX_HINT)
|
||||
|
||||
if(YUZU_USE_BUNDLED_QT)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
|
||||
set(QT_VER qt-5.12.8-msvc2017_64)
|
||||
set(QT_BUILD qt-5.12.8-msvc2017_64)
|
||||
elseif ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND NOT MINGW AND ARCHITECTURE_x86_64)
|
||||
set(QT_BUILD qt5_5_15_2)
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.")
|
||||
endif()
|
||||
|
||||
if (DEFINED QT_VER)
|
||||
download_bundled_external("qt/" ${QT_VER} QT_PREFIX)
|
||||
if (DEFINED QT_BUILD)
|
||||
download_bundled_external("qt/" ${QT_BUILD} QT_PREFIX)
|
||||
endif()
|
||||
|
||||
set(QT_PREFIX_HINT HINTS "${QT_PREFIX}")
|
||||
endif()
|
||||
find_package(Qt5 5.9 COMPONENTS Widgets ${QT_PREFIX_HINT})
|
||||
find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets ${QT_PREFIX_HINT} NO_CMAKE_SYSTEM_PATH)
|
||||
if (YUZU_USE_QT_WEB_ENGINE)
|
||||
find_package(Qt5 COMPONENTS WebEngineCore WebEngineWidgets)
|
||||
endif()
|
||||
@@ -251,21 +289,50 @@ if(ENABLE_QT)
|
||||
if (ENABLE_QT_TRANSLATION)
|
||||
find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT})
|
||||
endif()
|
||||
if (NOT Qt5_FOUND)
|
||||
list(APPEND CONAN_REQUIRED_LIBS "qt/5.14.1@bincrafters/stable")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the yuzu_find_package
|
||||
if(ENABLE_SDL2)
|
||||
if(EXISTS ${CMAKE_BINARY_DIR}/sdl2Config.cmake)
|
||||
include(${CMAKE_BINARY_DIR}/sdl2Config.cmake)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CONAN_SDL2_ROOT_RELEASE}")
|
||||
list(APPEND CMAKE_PREFIX_PATH "${CONAN_SDL2_ROOT_RELEASE}")
|
||||
endif()
|
||||
find_package(SDL2)
|
||||
if (NOT SDL2_FOUND)
|
||||
# otherwise add this to the list of libraries to install
|
||||
list(APPEND CONAN_REQUIRED_LIBS "sdl2/2.0.14@bincrafters/stable")
|
||||
if (ENABLE_SDL2)
|
||||
if (YUZU_USE_BUNDLED_SDL2)
|
||||
# Detect toolchain and platform
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
|
||||
set(SDL2_VER "SDL2-2.0.15-prerelease")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
|
||||
endif()
|
||||
|
||||
if (DEFINED SDL2_VER)
|
||||
download_bundled_external("sdl2/" ${SDL2_VER} SDL2_PREFIX)
|
||||
endif()
|
||||
|
||||
set(SDL2_FOUND YES)
|
||||
set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers")
|
||||
set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library")
|
||||
set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll")
|
||||
|
||||
add_library(SDL2 INTERFACE)
|
||||
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
|
||||
target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
|
||||
else()
|
||||
if (YUZU_ALLOW_SYSTEM_SDL2)
|
||||
find_package(SDL2 2.0.15 QUIET)
|
||||
|
||||
if (SDL2_FOUND)
|
||||
# Some installations don't set SDL2_LIBRARIES
|
||||
if("${SDL2_LIBRARIES}" STREQUAL "")
|
||||
message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
|
||||
set(SDL2_LIBRARIES "SDL2::SDL2")
|
||||
endif()
|
||||
|
||||
include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
|
||||
add_library(SDL2 INTERFACE)
|
||||
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
|
||||
else()
|
||||
message(STATUS "SDL2 2.0.15 or newer not found, falling back to externals.")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Using SDL2 from externals.")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -287,9 +354,6 @@ if (CONAN_REQUIRED_LIBS)
|
||||
)
|
||||
|
||||
conan_check(VERSION 1.24.0 REQUIRED)
|
||||
# Add the bincrafters remote
|
||||
conan_add_remote(NAME bincrafters
|
||||
URL https://api.bintray.com/conan/bincrafters/public-conan)
|
||||
|
||||
# Manually add iconv to fix a dep conflict between qt and sdl2
|
||||
# We don't need to add it through find_package or anything since the other two can find it just fine
|
||||
@@ -335,16 +399,11 @@ if (CONAN_REQUIRED_LIBS)
|
||||
if(ENABLE_QT)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CONAN_QT_ROOT_RELEASE}")
|
||||
list(APPEND CMAKE_PREFIX_PATH "${CONAN_QT_ROOT_RELEASE}")
|
||||
find_package(Qt5 5.9 REQUIRED COMPONENTS Widgets)
|
||||
find_package(Qt5 5.12 REQUIRED COMPONENTS Widgets)
|
||||
if (YUZU_USE_QT_WEB_ENGINE)
|
||||
find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets)
|
||||
endif()
|
||||
endif()
|
||||
if(ENABLE_SDL2)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CONAN_SDL2_ROOT_RELEASE}")
|
||||
list(APPEND CMAKE_PREFIX_PATH "${CONAN_SDL2_ROOT_RELEASE}")
|
||||
find_package(SDL2 REQUIRED)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
@@ -360,23 +419,6 @@ elseif (TARGET Boost::boost)
|
||||
add_library(boost ALIAS Boost::boost)
|
||||
endif()
|
||||
|
||||
if (TARGET sdl2::sdl2)
|
||||
# imported from the conan generated sdl2Config.cmake
|
||||
set_target_properties(sdl2::sdl2 PROPERTIES IMPORTED_GLOBAL TRUE)
|
||||
add_library(SDL2 ALIAS sdl2::sdl2)
|
||||
elseif(SDL2_FOUND)
|
||||
# found through the system package manager
|
||||
# Some installations don't set SDL2_LIBRARIES
|
||||
if("${SDL2_LIBRARIES}" STREQUAL "")
|
||||
message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
|
||||
set(SDL2_LIBRARIES "SDL2::SDL2")
|
||||
endif()
|
||||
|
||||
include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
|
||||
add_library(SDL2 INTERFACE)
|
||||
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
# Ensure libusb is properly configured (based on dolphin libusb include)
|
||||
if(NOT APPLE)
|
||||
include(FindPkgConfig)
|
||||
@@ -384,7 +426,7 @@ if(NOT APPLE)
|
||||
endif()
|
||||
if (NOT LIBUSB_FOUND)
|
||||
add_subdirectory(externals/libusb)
|
||||
set(LIBUSB_INCLUDE_DIR "")
|
||||
set(LIBUSB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/externals/libusb/libusb/libusb")
|
||||
set(LIBUSB_LIBRARIES usb)
|
||||
endif()
|
||||
|
||||
@@ -396,7 +438,7 @@ set(FFmpeg_COMPONENTS
|
||||
|
||||
if (NOT YUZU_USE_BUNDLED_FFMPEG)
|
||||
# Use system installed FFmpeg
|
||||
find_package(FFmpeg REQUIRED COMPONENTS ${FFmpeg_COMPONENTS})
|
||||
find_package(FFmpeg QUIET COMPONENTS ${FFmpeg_COMPONENTS})
|
||||
|
||||
if (FFmpeg_FOUND)
|
||||
# Overwrite aggregate defines from FFmpeg module to avoid over-linking libraries.
|
||||
@@ -435,6 +477,7 @@ if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
set(FFmpeg_FOUND YES)
|
||||
endif()
|
||||
|
||||
unset(FFmpeg_LIBRARIES CACHE)
|
||||
foreach(COMPONENT ${FFmpeg_COMPONENTS})
|
||||
set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}")
|
||||
set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a")
|
||||
@@ -447,7 +490,7 @@ if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
endforeach()
|
||||
|
||||
set(FFmpeg_INCLUDE_DIR
|
||||
${FFmpeg_PREFIX}
|
||||
"${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR}"
|
||||
CACHE PATH "Path to FFmpeg headers" FORCE)
|
||||
|
||||
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
|
||||
@@ -494,13 +537,11 @@ if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
|
||||
# ALL makes this custom target build every time
|
||||
# but it won't actually build if the DEPENDS parameter is up to date
|
||||
add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_LIBRARIES})
|
||||
add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE})
|
||||
add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_LIBRARIES} ffmpeg-configure)
|
||||
|
||||
if (FFmpeg_FOUND)
|
||||
message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}")
|
||||
|
||||
add_dependencies(ffmpeg-build ffmpeg-configure)
|
||||
else()
|
||||
message(FATAL_ERROR "FFmpeg not found")
|
||||
endif()
|
||||
|
||||
@@ -1,52 +1,111 @@
|
||||
function(copy_yuzu_Qt5_deps target_dir)
|
||||
include(WindowsCopyFiles)
|
||||
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
|
||||
set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
|
||||
if (MSVC)
|
||||
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
|
||||
set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
|
||||
else()
|
||||
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/")
|
||||
set(Qt5_DLL_DIR "${Qt5_DIR}/../../../lib/")
|
||||
endif()
|
||||
set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/")
|
||||
set(Qt5_PLATFORMTHEMES_DIR "${Qt5_DIR}/../../../plugins/platformthemes/")
|
||||
set(Qt5_PLATFORMINPUTCONTEXTS_DIR "${Qt5_DIR}/../../../plugins/platforminputcontexts/")
|
||||
set(Qt5_XCBGLINTEGRATIONS_DIR "${Qt5_DIR}/../../../plugins/xcbglintegrations/")
|
||||
set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/")
|
||||
set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/")
|
||||
set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/")
|
||||
set(PLATFORMS ${DLL_DEST}plugins/platforms/)
|
||||
set(STYLES ${DLL_DEST}plugins/styles/)
|
||||
set(IMAGEFORMATS ${DLL_DEST}plugins/imageformats/)
|
||||
windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
|
||||
icudt*.dll
|
||||
icuin*.dll
|
||||
icuuc*.dll
|
||||
Qt5Core$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Gui$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Widgets$<$<CONFIG:Debug>:d>.*
|
||||
)
|
||||
|
||||
if (YUZU_USE_QT_WEB_ENGINE)
|
||||
windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
|
||||
Qt5Network$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Positioning$<$<CONFIG:Debug>:d>.*
|
||||
Qt5PrintSupport$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Qml$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Quick$<$<CONFIG:Debug>:d>.*
|
||||
Qt5QuickWidgets$<$<CONFIG:Debug>:d>.*
|
||||
Qt5WebChannel$<$<CONFIG:Debug>:d>.*
|
||||
Qt5WebEngine$<$<CONFIG:Debug>:d>.*
|
||||
Qt5WebEngineCore$<$<CONFIG:Debug>:d>.*
|
||||
Qt5WebEngineWidgets$<$<CONFIG:Debug>:d>.*
|
||||
QtWebEngineProcess$<$<CONFIG:Debug>:d>.*
|
||||
if (MSVC)
|
||||
windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
|
||||
icudt*.dll
|
||||
icuin*.dll
|
||||
icuuc*.dll
|
||||
Qt5Core$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Gui$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Widgets$<$<CONFIG:Debug>:d>.*
|
||||
)
|
||||
|
||||
windows_copy_files(${target_dir} ${Qt5_RESOURCES_DIR} ${DLL_DEST}
|
||||
qtwebengine_resources.pak
|
||||
qtwebengine_devtools_resources.pak
|
||||
qtwebengine_resources_100p.pak
|
||||
qtwebengine_resources_200p.pak
|
||||
icudtl.dat
|
||||
)
|
||||
endif ()
|
||||
windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
|
||||
windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
|
||||
windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS}
|
||||
qjpeg$<$<CONFIG:Debug>:d>.*
|
||||
qgif$<$<CONFIG:Debug>:d>.*
|
||||
)
|
||||
if (YUZU_USE_QT_WEB_ENGINE)
|
||||
windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
|
||||
Qt5Network$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Positioning$<$<CONFIG:Debug>:d>.*
|
||||
Qt5PrintSupport$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Qml$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Quick$<$<CONFIG:Debug>:d>.*
|
||||
Qt5QuickWidgets$<$<CONFIG:Debug>:d>.*
|
||||
Qt5WebChannel$<$<CONFIG:Debug>:d>.*
|
||||
Qt5WebEngine$<$<CONFIG:Debug>:d>.*
|
||||
Qt5WebEngineCore$<$<CONFIG:Debug>:d>.*
|
||||
Qt5WebEngineWidgets$<$<CONFIG:Debug>:d>.*
|
||||
QtWebEngineProcess$<$<CONFIG:Debug>:d>.*
|
||||
)
|
||||
|
||||
windows_copy_files(${target_dir} ${Qt5_RESOURCES_DIR} ${DLL_DEST}
|
||||
qtwebengine_resources.pak
|
||||
qtwebengine_devtools_resources.pak
|
||||
qtwebengine_resources_100p.pak
|
||||
qtwebengine_resources_200p.pak
|
||||
icudtl.dat
|
||||
)
|
||||
endif ()
|
||||
windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
|
||||
windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
|
||||
windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS}
|
||||
qjpeg$<$<CONFIG:Debug>:d>.*
|
||||
qgif$<$<CONFIG:Debug>:d>.*
|
||||
)
|
||||
else()
|
||||
set(Qt5_DLLS
|
||||
"${Qt5_DLL_DIR}libQt5Core.so.5"
|
||||
"${Qt5_DLL_DIR}libQt5DBus.so.5"
|
||||
"${Qt5_DLL_DIR}libQt5Gui.so.5"
|
||||
"${Qt5_DLL_DIR}libQt5Widgets.so.5"
|
||||
"${Qt5_DLL_DIR}libQt5XcbQpa.so.5"
|
||||
"${Qt5_DLL_DIR}libicudata.so.60"
|
||||
"${Qt5_DLL_DIR}libicui18n.so.60"
|
||||
"${Qt5_DLL_DIR}libicuuc.so.60"
|
||||
)
|
||||
set(Qt5_IMAGEFORMAT_DLLS
|
||||
"${Qt5_IMAGEFORMATS_DIR}libqjpeg.so"
|
||||
"${Qt5_IMAGEFORMATS_DIR}libqgif.so"
|
||||
"${Qt5_IMAGEFORMATS_DIR}libqico.so"
|
||||
)
|
||||
set(Qt5_PLATFORMTHEME_DLLS
|
||||
"${Qt5_PLATFORMTHEMES_DIR}libqgtk3.so"
|
||||
"${Qt5_PLATFORMTHEMES_DIR}libqxdgdesktopportal.so"
|
||||
)
|
||||
set(Qt5_PLATFORM_DLLS
|
||||
"${Qt5_PLATFORMS_DIR}libqxcb.so"
|
||||
)
|
||||
set(Qt5_PLATFORMINPUTCONTEXT_DLLS
|
||||
"${Qt5_PLATFORMINPUTCONTEXTS_DIR}libcomposeplatforminputcontextplugin.so"
|
||||
"${Qt5_PLATFORMINPUTCONTEXTS_DIR}libibusplatforminputcontextplugin.so"
|
||||
)
|
||||
set(Qt5_XCBGLINTEGRATION_DLLS
|
||||
"${Qt5_XCBGLINTEGRATIONS_DIR}libqxcb-glx-integration.so"
|
||||
)
|
||||
foreach(LIB ${Qt5_DLLS})
|
||||
file(COPY ${LIB} DESTINATION "${DLL_DEST}/lib" FOLLOW_SYMLINK_CHAIN)
|
||||
endforeach()
|
||||
foreach(LIB ${Qt5_IMAGEFORMAT_DLLS})
|
||||
file(COPY ${LIB} DESTINATION "${DLL_DEST}plugins/imageformats/" FOLLOW_SYMLINK_CHAIN)
|
||||
endforeach()
|
||||
foreach(LIB ${Qt5_PLATFORMTHEME_DLLS})
|
||||
file(COPY ${LIB} DESTINATION "${DLL_DEST}plugins/platformthemes/" FOLLOW_SYMLINK_CHAIN)
|
||||
endforeach()
|
||||
foreach(LIB ${Qt5_PLATFORM_DLLS})
|
||||
file(COPY ${LIB} DESTINATION "${DLL_DEST}plugins/platforms/" FOLLOW_SYMLINK_CHAIN)
|
||||
endforeach()
|
||||
foreach(LIB ${Qt5_PLATFORMINPUTCONTEXT_DLLS})
|
||||
file(COPY ${LIB} DESTINATION "${DLL_DEST}plugins/platforminputcontexts/" FOLLOW_SYMLINK_CHAIN)
|
||||
endforeach()
|
||||
foreach(LIB ${Qt5_XCBGLINTEGRATION_DLLS})
|
||||
file(COPY ${LIB} DESTINATION "${DLL_DEST}plugins/xcbglintegrations/" FOLLOW_SYMLINK_CHAIN)
|
||||
endforeach()
|
||||
|
||||
endif()
|
||||
# Create an empty qt.conf file. Qt will detect that this file exists, and use the folder that its in as the root folder.
|
||||
# This way it'll look for plugins in the root/plugins/ folder
|
||||
add_custom_command(TARGET yuzu POST_BUILD
|
||||
|
||||
@@ -4,15 +4,29 @@
|
||||
# remote_path: path to the file to download, relative to the remote repository root
|
||||
# prefix_var: name of a variable which will be set with the path to the extracted contents
|
||||
function(download_bundled_external remote_path lib_name prefix_var)
|
||||
|
||||
set(package_repo "no_platform")
|
||||
set(package_extension "no_platform")
|
||||
if (WIN32)
|
||||
set(package_repo "ext-windows-bin/raw/master/")
|
||||
set(package_extension ".7z")
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(package_repo "ext-linux-bin/raw/main/")
|
||||
set(package_extension ".tar.xz")
|
||||
else()
|
||||
message(FATAL_ERROR "No package available for this platform")
|
||||
endif()
|
||||
set(package_url "https://github.com/yuzu-emu/${package_repo}")
|
||||
|
||||
set(prefix "${CMAKE_BINARY_DIR}/externals/${lib_name}")
|
||||
if (NOT EXISTS "${prefix}")
|
||||
message(STATUS "Downloading binaries for ${lib_name}...")
|
||||
file(DOWNLOAD
|
||||
https://github.com/yuzu-emu/ext-windows-bin/raw/master/${remote_path}${lib_name}.7z
|
||||
"${CMAKE_BINARY_DIR}/externals/${lib_name}.7z" SHOW_PROGRESS)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${CMAKE_BINARY_DIR}/externals/${lib_name}.7z"
|
||||
${package_url}${remote_path}${lib_name}${package_extension}
|
||||
"${CMAKE_BINARY_DIR}/externals/${lib_name}${package_extension}" SHOW_PROGRESS)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${CMAKE_BINARY_DIR}/externals/${lib_name}${package_extension}"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
|
||||
endif()
|
||||
message(STATUS "Using bundled binaries at ${prefix}")
|
||||
set(${prefix_var} "${prefix}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
endfunction()
|
||||
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 712 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 683 B |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 796 B |
|
After Width: | Height: | Size: 745 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 936 B |
|
After Width: | Height: | Size: 894 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,64 @@
|
||||
<RCC>
|
||||
<qresource prefix="overlay">
|
||||
<file>arrow_left.png</file>
|
||||
<file>arrow_left_dark.png</file>
|
||||
<file>arrow_right.png</file>
|
||||
<file>arrow_right_dark.png</file>
|
||||
<file>button_minus.png</file>
|
||||
<file>button_minus_dark.png</file>
|
||||
<file>button_plus.png</file>
|
||||
<file>button_plus_dark.png</file>
|
||||
<file>button_A.png</file>
|
||||
<file>button_A_dark.png</file>
|
||||
<file>button_B.png</file>
|
||||
<file>button_B_dark.png</file>
|
||||
<file>button_X.png</file>
|
||||
<file>button_X_dark.png</file>
|
||||
<file>button_Y.png</file>
|
||||
<file>button_Y_dark.png</file>
|
||||
<file>button_L.png</file>
|
||||
<file>button_L_dark.png</file>
|
||||
<file>button_R.png</file>
|
||||
<file>button_R_dark.png</file>
|
||||
<file>button_press_stick.png</file>
|
||||
<file>button_press_stick_dark.png</file>
|
||||
<file>osk_button_B.png</file>
|
||||
<file>osk_button_B_disabled.png</file>
|
||||
<file>osk_button_B_dark.png</file>
|
||||
<file>osk_button_B_dark_disabled.png</file>
|
||||
<file>osk_button_Y.png</file>
|
||||
<file>osk_button_Y_disabled.png</file>
|
||||
<file>osk_button_Y_dark.png</file>
|
||||
<file>osk_button_Y_dark_disabled.png</file>
|
||||
<file>osk_button_backspace.png</file>
|
||||
<file>osk_button_backspace_dark.png</file>
|
||||
<file>osk_button_plus.png</file>
|
||||
<file>osk_button_plus_disabled.png</file>
|
||||
<file>osk_button_plus_dark.png</file>
|
||||
<file>osk_button_plus_dark_disabled.png</file>
|
||||
<file>osk_button_shift.png</file>
|
||||
<file>osk_button_shift_dark.png</file>
|
||||
<file>osk_button_shift_on.png</file>
|
||||
<file>osk_button_shift_on_dark.png</file>
|
||||
<file>osk_button_shift_lock_on.png</file>
|
||||
<file>osk_button_shift_lock_off.png</file>
|
||||
<file>controller_dual_joycon.png</file>
|
||||
<file>controller_dual_joycon_dark.png</file>
|
||||
<file>controller_pro.png</file>
|
||||
<file>controller_pro_dark.png</file>
|
||||
<file>controller_handheld.png</file>
|
||||
<file>controller_handheld_dark.png</file>
|
||||
<file>controller_single_joycon_left.png</file>
|
||||
<file>controller_single_joycon_left_dark.png</file>
|
||||
<file>controller_single_joycon_right.png</file>
|
||||
<file>controller_single_joycon_right_dark.png</file>
|
||||
<file>controller_single_joycon_left_a.png</file>
|
||||
<file>controller_single_joycon_left_a_dark.png</file>
|
||||
<file>controller_single_joycon_left_b.png</file>
|
||||
<file>controller_single_joycon_left_b_dark.png</file>
|
||||
<file>controller_single_joycon_left_x.png</file>
|
||||
<file>controller_single_joycon_left_x_dark.png</file>
|
||||
<file>controller_single_joycon_left_y.png</file>
|
||||
<file>controller_single_joycon_left_y_dark.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -281,3 +281,370 @@ QWidget#controllerPlayer7,
|
||||
QWidget#controllerPlayer8 {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog,
|
||||
QStackedWidget#topOSK {
|
||||
background: rgba(51, 51, 51, .9);
|
||||
}
|
||||
|
||||
|
||||
QDialog#OverlayDialog,
|
||||
QStackedWidget#stackedDialog {
|
||||
background: rgba(51, 51, 51, .7);
|
||||
}
|
||||
|
||||
QWidget#boxOSK,
|
||||
QWidget#lineOSK,
|
||||
QWidget#richDialog,
|
||||
QWidget#lineDialog {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QStackedWidget#bottomOSK,
|
||||
QWidget#contentDialog,
|
||||
QWidget#contentRichDialog {
|
||||
background: rgba(240, 240, 240, 1);
|
||||
}
|
||||
|
||||
QWidget#contentDialog,
|
||||
QWidget#contentRichDialog {
|
||||
margin: 5px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
QWidget#buttonsDialog,
|
||||
QWidget#buttonsRichDialog {
|
||||
margin: 5px;
|
||||
border-top: 2px solid rgba(44, 44, 44, 1);
|
||||
}
|
||||
|
||||
QWidget#legendOSKnum {
|
||||
border-top: 1px solid rgba(44, 44, 44, 1);
|
||||
}
|
||||
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar::vertical {
|
||||
background: #cdcdcd;
|
||||
width: 15px;
|
||||
margin: 15px 3px 15px 3px;
|
||||
border: 1px transparent;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar::horizoncal {
|
||||
background: #cdcdcd;
|
||||
height: 15px;
|
||||
margin: 3px 15px 3px 15px;
|
||||
border: 1px transparent;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar::handle {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
min-height: 5px;
|
||||
min-width: 5px;
|
||||
}
|
||||
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line,
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-page,
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-page {
|
||||
background: none;
|
||||
}
|
||||
|
||||
QWidget#inputOSK {
|
||||
border-bottom: 3px solid rgba(255, 255, 255, .9);
|
||||
}
|
||||
|
||||
QWidget#inputOSK QLineEdit {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
QWidget#inputBoxOSK {
|
||||
border: 2px solid rgba(255, 255, 255, .9);
|
||||
}
|
||||
|
||||
QWidget#inputBoxOSK QTextEdit {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
QWidget#richDialog QTextBrowser {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 35px 65px;
|
||||
}
|
||||
|
||||
|
||||
QWidget#lineOSK QLabel#label_header {
|
||||
color: #f0f0f0;
|
||||
}
|
||||
|
||||
QWidget#lineOSK QLabel#label_sub,
|
||||
QWidget#lineOSK QLabel#label_characters,
|
||||
QWidget#boxOSK QLabel#label_characters_box {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
QWidget#contentDialog QLabel#label_title,
|
||||
QWidget#contentRichDialog QLabel#label_title_rich {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
QWidget#contentDialog QLabel#label_dialog {
|
||||
padding: 20px 65px;
|
||||
}
|
||||
|
||||
QWidget#contentDialog QLabel#label_title,
|
||||
QWidget#contentRichDialog QLabel#label_title_rich {
|
||||
padding: 0px 65px;
|
||||
}
|
||||
|
||||
QDialog#OverlayDialog QPushButton {
|
||||
color: rgba(49, 79, 239, 1);
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0px;
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
QDialog#OverlayDialog QPushButton:focus,
|
||||
QDialog#OverlayDialog QPushButton:hover {
|
||||
color: rgba(49, 79, 239, 1);
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border: 5px solid rgba(148, 250, 202, 1);
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QDialog#OverlayDialog QPushButton:pressed {
|
||||
color: rgba(240, 240, 240, 1);
|
||||
background: rgba(150, 150, 150, 1);
|
||||
border: 5px solid rgba(148, 250, 202, 1);
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton {
|
||||
background: rgba(232, 232, 232, 1);
|
||||
border: 2px solid rgba(240, 240, 240, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
|
||||
background: rgba(218, 218, 218, 1);
|
||||
border: 2px solid rgba(240, 240, 240, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
|
||||
color: rgba(240, 240, 240, 1);
|
||||
background: rgba(44, 44, 44, 1);
|
||||
border: 2px solid rgba(240, 240, 240, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
|
||||
color: rgba(240, 240, 240, 1);
|
||||
background: rgba(49, 79, 239, 1);
|
||||
border: 2px solid rgba(240, 240, 240, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
|
||||
color: rgba(0, 0, 0, 1);
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border: 5px solid rgba(148, 250, 202, 1);
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
|
||||
color: rgba(240, 240, 240, 1);
|
||||
background: rgba(150, 150, 150, 1);
|
||||
border: 5px solid rgba(148, 250, 202, 1);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
|
||||
image: url(:/overlay/osk_button_B.png);
|
||||
image-position: right;
|
||||
qproperty-icon: url(:/overlay/osk_button_backspace.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
|
||||
image: url(:/overlay/osk_button_Y.png);
|
||||
image-position: right;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
|
||||
image: url(:/overlay/osk_button_plus.png);
|
||||
image-position: right;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
|
||||
image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image-position: left;
|
||||
qproperty-icon: url(:/overlay/osk_button_shift.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
|
||||
image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image-position: left;
|
||||
qproperty-icon: url(:/overlay/osk_button_shift_on.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
|
||||
background: transparent;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
|
||||
image: url(:/overlay/button_L.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
|
||||
image: url(:/overlay/arrow_left.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
|
||||
image: url(:/overlay/button_R.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
|
||||
image: url(:/overlay/arrow_right.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
|
||||
image: url(:/overlay/button_press_stick.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
|
||||
image: url(:/overlay/button_X.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
|
||||
image: url(:/overlay/button_A.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
|
||||
color: rgba(164, 164, 164, 1);
|
||||
background-color: rgba(218, 218, 218, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
|
||||
color: rgba(164, 164, 164, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
|
||||
image: url(:/overlay/osk_button_plus_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
|
||||
image: url(:/overlay/osk_button_B_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
|
||||
image: url(:/overlay/osk_button_Y_disabled.png);
|
||||
}
|
||||
|
||||
@@ -1560,7 +1560,390 @@ QWidget#controllerPlayer8 {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* touchscreen mapping widget */
|
||||
TouchScreenPreview {
|
||||
qproperty-dotHighlightColor: #3daee9;
|
||||
QDialog#QtSoftwareKeyboardDialog,
|
||||
QStackedWidget#topOSK {
|
||||
background: rgba(41, 41, 41, .9);
|
||||
}
|
||||
|
||||
|
||||
QDialog#OverlayDialog,
|
||||
QStackedWidget#stackedDialog {
|
||||
background: rgba(41, 41, 41, .7);
|
||||
}
|
||||
|
||||
QWidget#boxOSK,
|
||||
QWidget#lineOSK,
|
||||
QWidget#richDialog,
|
||||
QWidget#lineDialog {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QStackedWidget#bottomOSK,
|
||||
QWidget#contentDialog,
|
||||
QWidget#contentRichDialog {
|
||||
background: rgba(71, 69, 71, 1);
|
||||
}
|
||||
|
||||
QWidget#contentDialog,
|
||||
QWidget#contentRichDialog {
|
||||
margin: 5px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
QWidget#buttonsDialog,
|
||||
QWidget#buttonsRichDialog {
|
||||
margin: 5px;
|
||||
border-top: 2px solid rgba(255, 255, 255, .9);
|
||||
}
|
||||
|
||||
QWidget#legendOSKnum {
|
||||
border-top: 1px solid rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
QStackedWidget#stackedDialog QTextBrowser QWidget {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar {
|
||||
background: #2a2929;
|
||||
}
|
||||
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line {
|
||||
border-image: none;
|
||||
}
|
||||
|
||||
QWidget#inputOSK {
|
||||
border-bottom: 3px solid rgba(255, 255, 255, .9);
|
||||
}
|
||||
|
||||
QWidget#inputOSK QLineEdit {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #ccc;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
QWidget#inputBoxOSK {
|
||||
border: 2px solid rgba(255, 255, 255, .9);
|
||||
}
|
||||
|
||||
QWidget#inputBoxOSK QTextEdit {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
QWidget#richDialog QTextBrowser {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #fff;
|
||||
padding: 35px 65px;
|
||||
}
|
||||
|
||||
QWidget#lineOSK QLabel#label_header {
|
||||
color: #f0f0f0;
|
||||
}
|
||||
|
||||
QWidget#lineOSK QLabel#label_sub,
|
||||
QWidget#lineOSK QLabel#label_characters,
|
||||
QWidget#contentDialog QLabel#label_title,
|
||||
QWidget#contentRichDialog QLabel#label_title_rich,
|
||||
QWidget#boxOSK QLabel#label_characters_box {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
QWidget#buttonsDialog,
|
||||
QWidget#buttonsRichDialog,
|
||||
QWidget#mainOSK,
|
||||
QWidget#headerOSK,
|
||||
QWidget#normalOSK,
|
||||
QWidget#shiftOSK,
|
||||
QWidget#numOSK,
|
||||
QWidget#subOSK,
|
||||
QWidget#inputOSK,
|
||||
QWidget#inputBoxOSK,
|
||||
QWidget#charactersOSK,
|
||||
QWidget#charactersBoxOSK,
|
||||
QWidget#legendOSK,
|
||||
QWidget#legendOSK QWidget,
|
||||
QWidget#legendOSKshift,
|
||||
QWidget#legendOSKshift QWidget,
|
||||
QWidget#legendOSKnum,
|
||||
QWidget#legendOSKnum QWidget {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#contentDialog QLabel,
|
||||
QWidget#legendOSK QLabel,
|
||||
QWidget#legendOSKshift QLabel,
|
||||
QWidget#legendOSKnum QLabel {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
QWidget#contentDialog QLabel#label_dialog {
|
||||
padding: 20px 65px;
|
||||
}
|
||||
|
||||
QWidget#contentDialog QLabel#label_title,
|
||||
QWidget#contentRichDialog QLabel#label_title_rich {
|
||||
padding: 0px 65px;
|
||||
}
|
||||
|
||||
QDialog#OverlayDialog QPushButton {
|
||||
color: rgba(1, 253, 201, 1);
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0px;
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
QDialog#OverlayDialog QPushButton:focus,
|
||||
QDialog#OverlayDialog QPushButton:hover {
|
||||
color: rgba(1, 253, 201, 1);
|
||||
background: rgba(58, 61, 66, 1);
|
||||
border: 5px solid rgba(56, 189, 225, 1);
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QDialog#OverlayDialog QPushButton:pressed {
|
||||
color: rgba(240, 240, 240, 1);
|
||||
background: rgba(150, 150, 150, 1);
|
||||
border: 5px solid rgba(56, 189, 225, 1);
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
background: rgba(80, 79, 80, 1);
|
||||
border: 2px solid rgba(71, 69, 71, 1);
|
||||
padding: 0px;
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
|
||||
background: rgba(95, 94, 95, 1);
|
||||
border: 2px solid rgba(71, 69, 71, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
|
||||
color: rgba(240, 240, 240, 1);
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border: 2px solid rgba(71, 69, 71, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
|
||||
color: rgba(0, 0, 0, 1);
|
||||
background: rgba(1, 253, 201, 1);
|
||||
border: 2px solid rgba(71, 69, 71, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
background: rgba(58, 61, 66, 1);
|
||||
border: 5px solid rgba(56, 189, 225, 1);
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
|
||||
color: rgba(240, 240, 240, 1);
|
||||
background: rgba(150, 150, 150, 1);
|
||||
border: 5px solid rgba(56, 189, 225, 1);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
|
||||
image: url(:/overlay/osk_button_B_dark.png);
|
||||
image-position: right;
|
||||
qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
|
||||
image: url(:/overlay/osk_button_Y_dark.png);
|
||||
image-position: right;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
|
||||
color: rgba(44, 44, 44, 1);
|
||||
image: url(:/overlay/osk_button_plus_dark.png);
|
||||
image-position: right;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
|
||||
image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image-position: left;
|
||||
qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
|
||||
image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image-position: left;
|
||||
qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
|
||||
background: transparent;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
|
||||
image: url(:/overlay/button_L_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
|
||||
image: url(:/overlay/arrow_left_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
|
||||
image: url(:/overlay/button_R_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
|
||||
image: url(:/overlay/arrow_right_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
|
||||
image: url(:/overlay/button_press_stick_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
|
||||
image: url(:/overlay/button_X_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
|
||||
image: url(:/overlay/button_A_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
|
||||
color: rgba(144, 144, 144, 1);
|
||||
background-color: rgba(95, 94, 95, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
|
||||
color: rgba(144, 144, 144, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
|
||||
image: url(:/overlay/osk_button_plus_dark_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
|
||||
image: url(:/overlay/osk_button_B_dark_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
|
||||
image: url(:/overlay/osk_button_Y_dark_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QFrame,
|
||||
QDialog#QtSoftwareKeyboardDialog QFrame[frameShape="0"],
|
||||
QDialog#OverlayDialog QFrame,
|
||||
QDialog#OverlayDialog QFrame[frameShape="0"] {
|
||||
border-radius: 0px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Created by the qtsass compiler v0.1.1
|
||||
Created by the qtsass compiler v0.1.1
|
||||
|
||||
The definitions are in the "qdarkstyle.qss._styles.scss" module
|
||||
The definitions are in the "qdarkstyle.qss._styles.scss" module
|
||||
|
||||
WARNING! All changes made in this file will be lost!
|
||||
WARNING! All changes made in this file will be lost!
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
/* QDarkStyleSheet -----------------------------------------------------------
|
||||
@@ -15,34 +15,34 @@ It is based on three selecting colors, three greyish (background) colors
|
||||
plus three whitish (foreground) colors. Each set of widgets of the same
|
||||
type have a header like this:
|
||||
|
||||
------------------
|
||||
GroupName --------
|
||||
------------------
|
||||
------------------
|
||||
GroupName --------
|
||||
------------------
|
||||
|
||||
And each widget is separated with a header like this:
|
||||
|
||||
QWidgetName ------
|
||||
QWidgetName ------
|
||||
|
||||
This makes more easy to find and change some css field. The basic
|
||||
configuration is described bellow.
|
||||
|
||||
BACKGROUND -----------
|
||||
BACKGROUND -----------
|
||||
|
||||
Light (unpressed)
|
||||
Normal (border, disabled, pressed, checked, toolbars, menus)
|
||||
Dark (background)
|
||||
Light (unpressed)
|
||||
Normal (border, disabled, pressed, checked, toolbars, menus)
|
||||
Dark (background)
|
||||
|
||||
FOREGROUND -----------
|
||||
FOREGROUND -----------
|
||||
|
||||
Light (texts/labels)
|
||||
Normal (not used yet)
|
||||
Dark (disabled texts)
|
||||
Light (texts/labels)
|
||||
Normal (not used yet)
|
||||
Dark (disabled texts)
|
||||
|
||||
SELECTION ------------
|
||||
SELECTION ------------
|
||||
|
||||
Light (selection/hover/active)
|
||||
Normal (selected)
|
||||
Dark (selected disabled)
|
||||
Light (selection/hover/active)
|
||||
Normal (selected)
|
||||
Dark (selected disabled)
|
||||
|
||||
If a stranger configuration is required because of a bugfix or anything
|
||||
else, keep the comment on the line above so nobody changes it, including the
|
||||
@@ -2483,3 +2483,394 @@ QWidget#controllerPlayer7,
|
||||
QWidget#controllerPlayer8 {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog,
|
||||
QStackedWidget#topOSK {
|
||||
background: rgba(15, 25, 34, .9);
|
||||
}
|
||||
|
||||
QDialog#OverlayDialog,
|
||||
QStackedWidget#stackedDialog {
|
||||
background: rgba(15, 25, 34, .7);
|
||||
}
|
||||
|
||||
QWidget#boxOSK,
|
||||
QWidget#lineOSK,
|
||||
QWidget#richDialog,
|
||||
QWidget#lineDialog {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QStackedWidget#bottomOSK,
|
||||
QWidget#contentDialog,
|
||||
QWidget#contentRichDialog {
|
||||
background: rgba(31, 41, 51, 1);
|
||||
}
|
||||
|
||||
QWidget#contentDialog,
|
||||
QWidget#contentRichDialog {
|
||||
margin: 5px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
QWidget#buttonsDialog,
|
||||
QWidget#buttonsRichDialog {
|
||||
margin: 5px;
|
||||
border-top: 2px solid rgba(255, 255, 255, .9);
|
||||
}
|
||||
|
||||
QWidget#legendOSKnum {
|
||||
border-top: 1px solid rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
QStackedWidget#stackedDialog QTextBrowser QWidget {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar {
|
||||
background: #19232d;
|
||||
border: none;
|
||||
}
|
||||
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
|
||||
QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line {
|
||||
border-image: none;
|
||||
}
|
||||
|
||||
QWidget#mainOSK QStackedWidget,
|
||||
QDialog#OverlayDialog QStackedWidget {
|
||||
border: none;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
QWidget#inputOSK {
|
||||
border-bottom: 3px solid rgba(255, 255, 255, .9);
|
||||
}
|
||||
|
||||
QWidget#inputOSK QLineEdit {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #ccc;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
QWidget#inputBoxOSK {
|
||||
border: 2px solid rgba(255, 255, 255, .9);
|
||||
}
|
||||
|
||||
QWidget#inputBoxOSK QTextEdit {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
QWidget#richDialog QTextBrowser {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #fff;
|
||||
padding: 35px 65px;
|
||||
}
|
||||
|
||||
QWidget#lineOSK QLabel#label_header {
|
||||
color: #f0f0f0;
|
||||
}
|
||||
|
||||
QWidget#lineOSK QLabel#label_sub,
|
||||
QWidget#lineOSK QLabel#label_characters,
|
||||
QWidget#contentDialog QLabel#label_title,
|
||||
QWidget#contentRichDialog QLabel#label_title_rich,
|
||||
QWidget#boxOSK QLabel#label_characters_box {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
QWidget#buttonsDialog,
|
||||
QWidget#buttonsRichDialog,
|
||||
QWidget#mainOSK,
|
||||
QWidget#headerOSK,
|
||||
QWidget#normalOSK,
|
||||
QWidget#shiftOSK,
|
||||
QWidget#numOSK,
|
||||
QWidget#subOSK,
|
||||
QWidget#inputOSK,
|
||||
QWidget#inputBoxOSK,
|
||||
QWidget#charactersOSK,
|
||||
QWidget#charactersBoxOSK,
|
||||
QWidget#legendOSK,
|
||||
QWidget#legendOSK QWidget,
|
||||
QWidget#legendOSKshift,
|
||||
QWidget#legendOSKshift QWidget,
|
||||
QWidget#legendOSKnum,
|
||||
QWidget#legendOSKnum QWidget {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#contentDialog QLabel,
|
||||
QWidget#legendOSK QLabel,
|
||||
QWidget#legendOSKshift QLabel,
|
||||
QWidget#legendOSKnum QLabel {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
QWidget#contentDialog QLabel#label_dialog {
|
||||
padding: 20px 65px;
|
||||
}
|
||||
|
||||
QWidget#contentDialog QLabel#label_title,
|
||||
QWidget#contentRichDialog QLabel#label_title_rich {
|
||||
padding: 0px 65px;
|
||||
}
|
||||
|
||||
QDialog#OverlayDialog QPushButton {
|
||||
color: rgba(1, 253, 201, 1);
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0px;
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
QDialog#OverlayDialog QPushButton:focus,
|
||||
QDialog#OverlayDialog QPushButton:hover {
|
||||
color: rgba(1, 253, 201, 1);
|
||||
background: rgba(18, 33, 46, 1);
|
||||
border: 5px solid rgba(56, 189, 225, 1);
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QDialog#OverlayDialog QPushButton:pressed {
|
||||
color: rgba(240, 240, 240, 1);
|
||||
background: rgba(110, 122, 130, 1);
|
||||
border: 5px solid rgba(56, 189, 225, 1);
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QLabel {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
background: rgba(40, 51, 60, 1);
|
||||
border: 2px solid rgba(31, 41, 51, 1);
|
||||
border-radius: 0px;
|
||||
padding: 0px;
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
|
||||
background: rgba(55, 66, 75, 1);
|
||||
border: 2px solid rgba(31, 41, 51, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
|
||||
color: rgba(240, 240, 240, 1);
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border: 2px solid rgba(31, 41, 51, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
|
||||
color: rgba(0, 0, 0, 1);
|
||||
background: rgba(1, 253, 201, 1);
|
||||
border: 2px solid rgba(31, 41, 51, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
background: rgba(18, 33, 46, 1);
|
||||
border: 5px solid rgba(56, 189, 225, 1);
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
|
||||
color: rgba(240, 240, 240, 1);
|
||||
background: rgba(110, 122, 130, 1);
|
||||
border: 5px solid rgba(56, 189, 225, 1);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
|
||||
image: url(:/overlay/osk_button_B_dark.png);
|
||||
image-position: right;
|
||||
qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
|
||||
image: url(:/overlay/osk_button_Y_dark.png);
|
||||
image-position: right;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
|
||||
color: rgba(44, 44, 44, 1);
|
||||
image: url(:/overlay/osk_button_plus_dark.png);
|
||||
image-position: right;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
|
||||
image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image-position: left;
|
||||
qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
|
||||
image: url(:/overlay/osk_button_shift_lock_off.png);
|
||||
image-position: left;
|
||||
qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
|
||||
qproperty-iconSize: 36px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
|
||||
background: transparent;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
|
||||
image: url(:/overlay/button_L_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
|
||||
image: url(:/overlay/arrow_left_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
|
||||
image: url(:/overlay/button_R_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
|
||||
image: url(:/overlay/arrow_right_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
|
||||
image: url(:/overlay/button_press_stick_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
|
||||
image: url(:/overlay/button_X_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
|
||||
QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
|
||||
image: url(:/overlay/button_A_dark.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
|
||||
color: rgba(144, 144, 144, 1);
|
||||
background-color: rgba(55, 66, 75, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
|
||||
color: rgba(144, 144, 144, 1);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
|
||||
image: url(:/overlay/osk_button_plus_dark_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
|
||||
image: url(:/overlay/osk_button_B_dark_disabled.png);
|
||||
}
|
||||
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
|
||||
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
|
||||
image: url(:/overlay/osk_button_Y_dark_disabled.png);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,28 @@ target_include_directories(microprofile INTERFACE ./microprofile)
|
||||
add_library(unicorn-headers INTERFACE)
|
||||
target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
|
||||
|
||||
# SDL2
|
||||
if (NOT SDL2_FOUND AND ENABLE_SDL2)
|
||||
if (NOT WIN32)
|
||||
# Yuzu itself needs: Events Joystick Haptic Sensor Timers
|
||||
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
|
||||
set(SDL_UNUSED_SUBSYSTEMS
|
||||
Atomic Audio Render Power Threads
|
||||
File CPUinfo Filesystem Locale)
|
||||
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
|
||||
string(TOUPPER ${_SUB} _OPT)
|
||||
option(SDL_${_OPT} "" OFF)
|
||||
endforeach()
|
||||
|
||||
option(HIDAPI "" ON)
|
||||
endif()
|
||||
set(SDL_STATIC ON)
|
||||
set(SDL_SHARED OFF)
|
||||
|
||||
add_subdirectory(SDL EXCLUDE_FROM_ALL)
|
||||
add_library(SDL2 ALIAS SDL2-static)
|
||||
endif()
|
||||
|
||||
# SoundTouch
|
||||
add_subdirectory(soundtouch)
|
||||
|
||||
|
||||
@@ -1,155 +1,239 @@
|
||||
# Ensure libusb compiles with UTF-8 encoding on MSVC
|
||||
if(MSVC)
|
||||
add_compile_options(/utf-8)
|
||||
endif()
|
||||
if (MINGW)
|
||||
# The MinGW toolchain for some reason doesn't work with this CMakeLists file after updating to
|
||||
# 1.0.24, so we do it the old-fashioned way for now. We may want to move native Linux toolchains
|
||||
# to here, too (TODO lat9nq?).
|
||||
|
||||
add_library(usb STATIC EXCLUDE_FROM_ALL
|
||||
libusb/libusb/core.c
|
||||
libusb/libusb/core.c
|
||||
libusb/libusb/descriptor.c
|
||||
libusb/libusb/hotplug.c
|
||||
libusb/libusb/io.c
|
||||
libusb/libusb/strerror.c
|
||||
libusb/libusb/sync.c
|
||||
)
|
||||
set_target_properties(usb PROPERTIES VERSION 1.0.23)
|
||||
if(WIN32)
|
||||
target_include_directories(usb
|
||||
BEFORE
|
||||
PUBLIC
|
||||
libusb/libusb
|
||||
set(LIBUSB_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/libusb")
|
||||
set(LIBUSB_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libusb")
|
||||
# Workarounds for MSYS/MinGW
|
||||
if (MSYS)
|
||||
# CMake on Windows passes `C:/`, but we need `/C/` or `/c/` to use `configure`
|
||||
string(REPLACE ":/" "/" LIBUSB_SRC_DIR "${LIBUSB_SRC_DIR}")
|
||||
set(LIBUSB_SRC_DIR "/${LIBUSB_SRC_DIR}")
|
||||
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
if (NOT MINGW)
|
||||
target_include_directories(usb BEFORE PRIVATE libusb/msvc)
|
||||
# And now that we are using /C/ for srcdir but everything else is using C:/, we need to
|
||||
# compile everything in the source directory, else `configure` won't think the build
|
||||
# environment is sane.
|
||||
set(LIBUSB_PREFIX "${LIBUSB_SRC_DIR}")
|
||||
endif()
|
||||
|
||||
# Works around other libraries providing their own definition of USB GUIDs (e.g. SDL2)
|
||||
target_compile_definitions(usb PRIVATE "-DGUID_DEVINTERFACE_USB_DEVICE=(GUID){ 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}}")
|
||||
else()
|
||||
target_include_directories(usb
|
||||
# turns out other projects also have "config.h", so make sure the
|
||||
# LibUSB one comes first
|
||||
BEFORE
|
||||
set(LIBUSB_CONFIGURE "${LIBUSB_SRC_DIR}/configure")
|
||||
set(LIBUSB_MAKEFILE "${LIBUSB_PREFIX}/Makefile")
|
||||
set(LIBUSB_LIBRARY "${LIBUSB_PREFIX}/libusb/.libs/libusb-1.0.dll.a")
|
||||
set(LIBUSB_SHARED_LIBRARY "${LIBUSB_PREFIX}/libusb/.libs/libusb-1.0.dll")
|
||||
set(LIBUSB_SHARED_LIBRARY_DEST "${CMAKE_BINARY_DIR}/bin/libusb-1.0.dll")
|
||||
|
||||
PUBLIC
|
||||
libusb/libusb
|
||||
# Causes "externals/libusb/libusb/libusb/os/windows_winusb.c:1427:2: error: conversion to non-scalar type requested", so cannot statically link it for now.
|
||||
# set(LIBUSB_CFLAGS "-DGUID_DEVINTERFACE_USB_DEVICE=\\(GUID\\){0xA5DCBF10,0x6530,0x11D2,{0x90,0x1F,0x00,0xC0,0x4F,0xB9,0x51,0xED}}")
|
||||
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
endif()
|
||||
make_directory("${LIBUSB_PREFIX}")
|
||||
|
||||
if(WIN32 OR CYGWIN)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/threads_windows.c
|
||||
libusb/libusb/os/windows_winusb.c
|
||||
libusb/libusb/os/windows_usbdk.c
|
||||
libusb/libusb/os/windows_nt_common.c
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${LIBUSB_LIBRARY}"
|
||||
COMMAND
|
||||
make
|
||||
WORKING_DIRECTORY
|
||||
"${LIBUSB_PREFIX}"
|
||||
)
|
||||
set(OS_WINDOWS TRUE)
|
||||
elseif(APPLE)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/darwin_usb.c
|
||||
|
||||
# We may use this path for other GNU toolchains, so put all of the MinGW-specific stuff here
|
||||
if (MINGW)
|
||||
set(LIBUSB_CONFIGURE_ARGS --host=x86_64-w64-mingw32 --build=x86_64-windows)
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${LIBUSB_MAKEFILE}"
|
||||
COMMAND
|
||||
# /bin/env
|
||||
# CFLAGS="${LIBUSB_CFLAGS}"
|
||||
/bin/sh "${LIBUSB_CONFIGURE}"
|
||||
${LIBUSB_CONFIGURE_ARGS}
|
||||
--srcdir="${LIBUSB_SRC_DIR}"
|
||||
WORKING_DIRECTORY
|
||||
"${LIBUSB_PREFIX}"
|
||||
)
|
||||
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
|
||||
find_library(IOKIT_LIBRARY IOKit)
|
||||
find_library(OBJC_LIBRARY objc)
|
||||
target_link_libraries(usb PRIVATE
|
||||
${COREFOUNDATION_LIBRARY}
|
||||
${IOKIT_LIBRARY}
|
||||
${OBJC_LIBRARY}
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${LIBUSB_CONFIGURE}"
|
||||
COMMAND
|
||||
/bin/sh "${LIBUSB_SRC_DIR}/bootstrap.sh"
|
||||
WORKING_DIRECTORY
|
||||
"${LIBUSB_SRC_DIR}"
|
||||
)
|
||||
set(OS_DARWIN TRUE)
|
||||
elseif(ANDROID)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_usbfs.c
|
||||
libusb/libusb/os/linux_netlink.c
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${LIBUSB_SHARED_LIBRARY_DEST}"
|
||||
COMMAND
|
||||
/bin/cp "${LIBUSB_SHARED_LIBRARY}" "${LIBUSB_SHARED_LIBRARY_DEST}"
|
||||
)
|
||||
find_library(LOG_LIBRARY log)
|
||||
target_link_libraries(usb PRIVATE ${LOG_LIBRARY})
|
||||
set(OS_LINUX TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_usbfs.c
|
||||
|
||||
add_custom_target(usb-bootstrap ALL DEPENDS "${LIBUSB_CONFIGURE}")
|
||||
add_custom_target(usb-configure ALL DEPENDS "${LIBUSB_MAKEFILE}" usb-bootstrap)
|
||||
add_custom_target(usb-build ALL DEPENDS "${LIBUSB_LIBRARY}" usb-configure)
|
||||
# Workaround since static linking didn't work out -- We need to copy the DLL to the bin directory
|
||||
add_custom_target(usb-copy ALL DEPENDS "${LIBUSB_SHARED_LIBRARY_DEST}" usb-build)
|
||||
|
||||
# Make `usb` alias to LIBUSB_LIBRARY
|
||||
add_library(usb INTERFACE)
|
||||
target_link_libraries(usb INTERFACE "${LIBUSB_LIBRARY}")
|
||||
else() # MINGW
|
||||
# Ensure libusb compiles with UTF-8 encoding on MSVC
|
||||
if(MSVC)
|
||||
add_compile_options(/utf-8)
|
||||
endif()
|
||||
|
||||
add_library(usb STATIC EXCLUDE_FROM_ALL
|
||||
libusb/libusb/core.c
|
||||
libusb/libusb/core.c
|
||||
libusb/libusb/descriptor.c
|
||||
libusb/libusb/hotplug.c
|
||||
libusb/libusb/io.c
|
||||
libusb/libusb/strerror.c
|
||||
libusb/libusb/sync.c
|
||||
)
|
||||
find_package(Libudev)
|
||||
if(LIBUDEV_FOUND)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_udev.c
|
||||
set_target_properties(usb PROPERTIES VERSION 1.0.24)
|
||||
if(WIN32)
|
||||
target_include_directories(usb
|
||||
BEFORE
|
||||
PUBLIC
|
||||
libusb/libusb
|
||||
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
target_link_libraries(usb PRIVATE "${LIBUDEV_LIBRARIES}")
|
||||
target_include_directories(usb PRIVATE "${LIBUDEV_INCLUDE_DIR}")
|
||||
set(HAVE_LIBUDEV TRUE)
|
||||
set(USE_UDEV TRUE)
|
||||
|
||||
if (NOT MINGW)
|
||||
target_include_directories(usb BEFORE PRIVATE libusb/msvc)
|
||||
endif()
|
||||
|
||||
# Works around other libraries providing their own definition of USB GUIDs (e.g. SDL2)
|
||||
target_compile_definitions(usb PRIVATE "-DGUID_DEVINTERFACE_USB_DEVICE=(GUID){ 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}}")
|
||||
else()
|
||||
target_include_directories(usb
|
||||
# turns out other projects also have "config.h", so make sure the
|
||||
# LibUSB one comes first
|
||||
BEFORE
|
||||
|
||||
PUBLIC
|
||||
libusb/libusb
|
||||
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR CYGWIN)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/threads_windows.c
|
||||
libusb/libusb/os/windows_winusb.c
|
||||
libusb/libusb/os/windows_usbdk.c
|
||||
libusb/libusb/os/windows_common.c
|
||||
)
|
||||
set(OS_WINDOWS TRUE)
|
||||
elseif(APPLE)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/darwin_usb.c
|
||||
)
|
||||
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
|
||||
find_library(IOKIT_LIBRARY IOKit)
|
||||
find_library(OBJC_LIBRARY objc)
|
||||
target_link_libraries(usb PRIVATE
|
||||
${COREFOUNDATION_LIBRARY}
|
||||
${IOKIT_LIBRARY}
|
||||
${OBJC_LIBRARY}
|
||||
)
|
||||
set(OS_DARWIN TRUE)
|
||||
elseif(ANDROID)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_usbfs.c
|
||||
libusb/libusb/os/linux_netlink.c
|
||||
)
|
||||
find_library(LOG_LIBRARY log)
|
||||
target_link_libraries(usb PRIVATE ${LOG_LIBRARY})
|
||||
set(OS_LINUX TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_usbfs.c
|
||||
)
|
||||
find_package(Libudev)
|
||||
if(LIBUDEV_FOUND)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_udev.c
|
||||
)
|
||||
target_link_libraries(usb PRIVATE "${LIBUDEV_LIBRARIES}")
|
||||
target_include_directories(usb PRIVATE "${LIBUDEV_INCLUDE_DIR}")
|
||||
set(HAVE_LIBUDEV TRUE)
|
||||
set(USE_UDEV TRUE)
|
||||
else()
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_netlink.c
|
||||
)
|
||||
endif()
|
||||
set(OS_LINUX TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/netbsd_usb.c
|
||||
)
|
||||
set(OS_NETBSD TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/openbsd_usb.c
|
||||
)
|
||||
set(OS_OPENBSD TRUE)
|
||||
endif()
|
||||
set(OS_LINUX TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/netbsd_usb.c
|
||||
)
|
||||
set(OS_NETBSD TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/openbsd_usb.c
|
||||
)
|
||||
set(OS_OPENBSD TRUE)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/poll_posix.c
|
||||
libusb/libusb/os/threads_posix.c
|
||||
)
|
||||
find_package(Threads REQUIRED)
|
||||
if(THREADS_HAVE_PTHREAD_ARG)
|
||||
target_compile_options(usb PUBLIC "-pthread")
|
||||
if(UNIX)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/events_posix.c
|
||||
libusb/libusb/os/threads_posix.c
|
||||
)
|
||||
find_package(Threads REQUIRED)
|
||||
if(THREADS_HAVE_PTHREAD_ARG)
|
||||
target_compile_options(usb PUBLIC "-pthread")
|
||||
endif()
|
||||
if(CMAKE_THREAD_LIBS_INIT)
|
||||
target_link_libraries(usb PRIVATE "${CMAKE_THREAD_LIBS_INIT}")
|
||||
endif()
|
||||
set(THREADS_POSIX TRUE)
|
||||
elseif(WIN32)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/events_windows.c
|
||||
libusb/libusb/os/threads_windows.c
|
||||
)
|
||||
endif()
|
||||
if(CMAKE_THREAD_LIBS_INIT)
|
||||
target_link_libraries(usb PRIVATE "${CMAKE_THREAD_LIBS_INIT}")
|
||||
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckTypeSize)
|
||||
check_include_files(asm/types.h HAVE_ASM_TYPES_H)
|
||||
check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
|
||||
check_include_files(linux/filter.h HAVE_LINUX_FILTER_H)
|
||||
check_include_files(linux/netlink.h HAVE_LINUX_NETLINK_H)
|
||||
check_include_files(poll.h HAVE_POLL_H)
|
||||
check_include_files(signal.h HAVE_SIGNAL_H)
|
||||
check_include_files(strings.h HAVE_STRINGS_H)
|
||||
check_type_size("struct timespec" STRUCT_TIMESPEC)
|
||||
check_function_exists(syslog HAVE_SYSLOG_FUNC)
|
||||
check_include_files(syslog.h HAVE_SYSLOG_H)
|
||||
check_include_files(sys/socket.h HAVE_SYS_SOCKET_H)
|
||||
check_include_files(sys/time.h HAVE_SYS_TIME_H)
|
||||
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
|
||||
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES poll.h)
|
||||
check_type_size("nfds_t" nfds_t)
|
||||
unset(CMAKE_EXTRA_INCLUDE_FILES)
|
||||
if(HAVE_NFDS_T)
|
||||
set(POLL_NFDS_TYPE "nfds_t")
|
||||
else()
|
||||
set(POLL_NFDS_TYPE "unsigned int")
|
||||
endif()
|
||||
set(THREADS_POSIX TRUE)
|
||||
elseif(WIN32)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/poll_windows.c
|
||||
libusb/libusb/os/threads_windows.c
|
||||
)
|
||||
endif()
|
||||
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckTypeSize)
|
||||
check_include_files(asm/types.h HAVE_ASM_TYPES_H)
|
||||
check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
|
||||
check_include_files(linux/filter.h HAVE_LINUX_FILTER_H)
|
||||
check_include_files(linux/netlink.h HAVE_LINUX_NETLINK_H)
|
||||
check_include_files(poll.h HAVE_POLL_H)
|
||||
check_include_files(signal.h HAVE_SIGNAL_H)
|
||||
check_include_files(strings.h HAVE_STRINGS_H)
|
||||
check_type_size("struct timespec" STRUCT_TIMESPEC)
|
||||
check_function_exists(syslog HAVE_SYSLOG_FUNC)
|
||||
check_include_files(syslog.h HAVE_SYSLOG_H)
|
||||
check_include_files(sys/socket.h HAVE_SYS_SOCKET_H)
|
||||
check_include_files(sys/time.h HAVE_SYS_TIME_H)
|
||||
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
|
||||
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES poll.h)
|
||||
check_type_size("nfds_t" nfds_t)
|
||||
unset(CMAKE_EXTRA_INCLUDE_FILES)
|
||||
if(HAVE_NFDS_T)
|
||||
set(POLL_NFDS_TYPE "nfds_t")
|
||||
else()
|
||||
set(POLL_NFDS_TYPE "unsigned int")
|
||||
endif()
|
||||
|
||||
check_include_files(sys/timerfd.h USBI_TIMERFD_AVAILABLE)
|
||||
check_include_files(sys/timerfd.h USBI_TIMERFD_AVAILABLE)
|
||||
|
||||
|
||||
configure_file(config.h.in config.h)
|
||||
configure_file(config.h.in config.h)
|
||||
endif() # MINGW
|
||||
|
||||
@@ -54,6 +54,7 @@ if (MSVC)
|
||||
/we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
|
||||
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
|
||||
/we4555 # Expression has no effect; expected expression with side-effect
|
||||
/we4715 # 'function': not all control paths return a value
|
||||
/we4834 # Discarding return value of function with 'nodiscard' attribute
|
||||
/we5038 # data member 'member1' will be initialized after data member 'member2'
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "audio_core/sink_details.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/settings.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
namespace AudioCore {
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
#include "audio_core/info_updater.h"
|
||||
#include "audio_core/voice_context.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace {
|
||||
[[nodiscard]] static constexpr s16 ClampToS16(s32 value) {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/ring_buffer.h"
|
||||
#include "core/settings.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <objbase.h>
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
#include "audio_core/stream.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace AudioCore {
|
||||
|
||||
|
||||
@@ -109,7 +109,6 @@ add_library(common STATIC
|
||||
cityhash.cpp
|
||||
cityhash.h
|
||||
common_funcs.h
|
||||
common_paths.h
|
||||
common_sizes.h
|
||||
common_types.h
|
||||
concepts.h
|
||||
@@ -118,8 +117,16 @@ add_library(common STATIC
|
||||
dynamic_library.h
|
||||
fiber.cpp
|
||||
fiber.h
|
||||
file_util.cpp
|
||||
file_util.h
|
||||
fs/file.cpp
|
||||
fs/file.h
|
||||
fs/fs.cpp
|
||||
fs/fs.h
|
||||
fs/fs_paths.h
|
||||
fs/fs_types.h
|
||||
fs/fs_util.cpp
|
||||
fs/fs_util.h
|
||||
fs/path_util.cpp
|
||||
fs/path_util.h
|
||||
hash.h
|
||||
hex_util.cpp
|
||||
hex_util.h
|
||||
@@ -147,11 +154,16 @@ add_library(common STATIC
|
||||
param_package.cpp
|
||||
param_package.h
|
||||
parent_of_member.h
|
||||
point.h
|
||||
quaternion.h
|
||||
ring_buffer.h
|
||||
scm_rev.cpp
|
||||
scm_rev.h
|
||||
scope_exit.h
|
||||
settings.cpp
|
||||
settings.h
|
||||
settings_input.cpp
|
||||
settings_input.h
|
||||
spin_lock.cpp
|
||||
spin_lock.h
|
||||
stream.cpp
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/assert.h"
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
#include "common/settings.h"
|
||||
|
||||
void assert_handle_failure() {
|
||||
Crash();
|
||||
if (Settings::values.use_debug_asserts) {
|
||||
Crash();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +108,14 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
} \
|
||||
}
|
||||
|
||||
#define YUZU_NON_COPYABLE(cls) \
|
||||
cls(const cls&) = delete; \
|
||||
cls& operator=(const cls&) = delete
|
||||
|
||||
#define YUZU_NON_MOVEABLE(cls) \
|
||||
cls(cls&&) = delete; \
|
||||
cls& operator=(cls&&) = delete
|
||||
|
||||
#define R_SUCCEEDED(res) (res.IsSuccess())
|
||||
|
||||
/// Evaluates an expression that returns a result, and returns the result if it would fail.
|
||||
@@ -128,4 +136,19 @@ namespace Common {
|
||||
return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24;
|
||||
}
|
||||
|
||||
// std::size() does not support zero-size C arrays. We're fixing that.
|
||||
template <class C>
|
||||
constexpr auto Size(const C& c) -> decltype(c.size()) {
|
||||
return std::size(c);
|
||||
}
|
||||
|
||||
template <class C>
|
||||
constexpr std::size_t Size(const C& c) {
|
||||
if constexpr (sizeof(C) == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return std::size(c);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
// Directory separators, do we need this?
|
||||
#define DIR_SEP "/"
|
||||
#define DIR_SEP_CHR '/'
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 260
|
||||
#endif
|
||||
|
||||
// The user data dir
|
||||
#define ROOT_DIR "."
|
||||
#define USERDATA_DIR "user"
|
||||
#ifdef USER_DIR
|
||||
#define EMU_DATA_DIR USER_DIR
|
||||
#else
|
||||
#define EMU_DATA_DIR "yuzu"
|
||||
#endif
|
||||
|
||||
// Dirs in both User and Sys
|
||||
#define EUR_DIR "EUR"
|
||||
#define USA_DIR "USA"
|
||||
#define JAP_DIR "JAP"
|
||||
|
||||
// Subdirs in the User dir returned by GetUserPath(UserPath::UserDir)
|
||||
#define CONFIG_DIR "config"
|
||||
#define CACHE_DIR "cache"
|
||||
#define SDMC_DIR "sdmc"
|
||||
#define NAND_DIR "nand"
|
||||
#define SYSDATA_DIR "sysdata"
|
||||
#define KEYS_DIR "keys"
|
||||
#define LOAD_DIR "load"
|
||||
#define DUMP_DIR "dump"
|
||||
#define SCREENSHOTS_DIR "screenshots"
|
||||
#define SHADER_DIR "shader"
|
||||
#define LOG_DIR "log"
|
||||
|
||||
// Filenames
|
||||
// Files in the directory returned by GetUserPath(UserPath::ConfigDir)
|
||||
#define EMU_CONFIG "emu.ini"
|
||||
#define DEBUGGER_CONFIG "debugger.ini"
|
||||
#define LOGGER_CONFIG "logger.ini"
|
||||
// Files in the directory returned by GetUserPath(UserPath::LogDir)
|
||||
#define LOG_FILE "yuzu_log.txt"
|
||||
|
||||
// Sys files
|
||||
#define SHARED_FONT "shared_font.bin"
|
||||
#define AES_KEYS "aes_keys.txt"
|
||||
@@ -1,298 +0,0 @@
|
||||
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#ifdef _MSC_VER
|
||||
#include "common/string_util.h"
|
||||
#endif
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
// User paths for GetUserPath
|
||||
enum class UserPath {
|
||||
CacheDir,
|
||||
ConfigDir,
|
||||
KeysDir,
|
||||
LogDir,
|
||||
NANDDir,
|
||||
RootDir,
|
||||
SDMCDir,
|
||||
LoadDir,
|
||||
DumpDir,
|
||||
ScreenshotsDir,
|
||||
ShaderDir,
|
||||
SysDataDir,
|
||||
UserDir,
|
||||
};
|
||||
|
||||
// FileSystem tree node/
|
||||
struct FSTEntry {
|
||||
bool isDirectory;
|
||||
u64 size; // file length or number of entries from children
|
||||
std::string physicalName; // name on disk
|
||||
std::string virtualName; // name in FST names table
|
||||
std::vector<FSTEntry> children;
|
||||
};
|
||||
|
||||
// Returns true if file filename exists
|
||||
[[nodiscard]] bool Exists(const std::string& filename);
|
||||
|
||||
// Returns true if filename is a directory
|
||||
[[nodiscard]] bool IsDirectory(const std::string& filename);
|
||||
|
||||
// Returns the size of filename (64bit)
|
||||
[[nodiscard]] u64 GetSize(const std::string& filename);
|
||||
|
||||
// Overloaded GetSize, accepts file descriptor
|
||||
[[nodiscard]] u64 GetSize(int fd);
|
||||
|
||||
// Overloaded GetSize, accepts FILE*
|
||||
[[nodiscard]] u64 GetSize(FILE* f);
|
||||
|
||||
// Returns true if successful, or path already exists.
|
||||
bool CreateDir(const std::string& filename);
|
||||
|
||||
// Creates the full path of fullPath returns true on success
|
||||
bool CreateFullPath(const std::string& fullPath);
|
||||
|
||||
// Deletes a given filename, return true on success
|
||||
// Doesn't supports deleting a directory
|
||||
bool Delete(const std::string& filename);
|
||||
|
||||
// Deletes a directory filename, returns true on success
|
||||
bool DeleteDir(const std::string& filename);
|
||||
|
||||
// renames file srcFilename to destFilename, returns true on success
|
||||
bool Rename(const std::string& srcFilename, const std::string& destFilename);
|
||||
|
||||
// copies file srcFilename to destFilename, returns true on success
|
||||
bool Copy(const std::string& srcFilename, const std::string& destFilename);
|
||||
|
||||
// creates an empty file filename, returns true on success
|
||||
bool CreateEmptyFile(const std::string& filename);
|
||||
|
||||
/**
|
||||
* @param num_entries_out to be assigned by the callable with the number of iterated directory
|
||||
* entries, never null
|
||||
* @param directory the path to the enclosing directory
|
||||
* @param virtual_name the entry name, without any preceding directory info
|
||||
* @return whether handling the entry succeeded
|
||||
*/
|
||||
using DirectoryEntryCallable = std::function<bool(
|
||||
u64* num_entries_out, const std::string& directory, const std::string& virtual_name)>;
|
||||
|
||||
/**
|
||||
* Scans a directory, calling the callback for each file/directory contained within.
|
||||
* If the callback returns failure, scanning halts and this function returns failure as well
|
||||
* @param num_entries_out assigned by the function with the number of iterated directory entries,
|
||||
* can be null
|
||||
* @param directory the directory to scan
|
||||
* @param callback The callback which will be called for each entry
|
||||
* @return whether scanning the directory succeeded
|
||||
*/
|
||||
bool ForeachDirectoryEntry(u64* num_entries_out, const std::string& directory,
|
||||
DirectoryEntryCallable callback);
|
||||
|
||||
/**
|
||||
* Scans the directory tree, storing the results.
|
||||
* @param directory the parent directory to start scanning from
|
||||
* @param parent_entry FSTEntry where the filesystem tree results will be stored.
|
||||
* @param recursion Number of children directories to read before giving up.
|
||||
* @return the total number of files/directories found
|
||||
*/
|
||||
u64 ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
|
||||
unsigned int recursion = 0);
|
||||
|
||||
// deletes the given directory and anything under it. Returns true on success.
|
||||
bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256);
|
||||
|
||||
// Returns the current directory
|
||||
[[nodiscard]] std::optional<std::string> GetCurrentDir();
|
||||
|
||||
// Create directory and copy contents (does not overwrite existing files)
|
||||
void CopyDir(const std::string& source_path, const std::string& dest_path);
|
||||
|
||||
// Set the current directory to given directory
|
||||
bool SetCurrentDir(const std::string& directory);
|
||||
|
||||
// Returns a pointer to a string with a yuzu data dir in the user's home
|
||||
// directory. To be used in "multi-user" mode (that is, installed).
|
||||
const std::string& GetUserPath(UserPath path, const std::string& new_path = "");
|
||||
|
||||
[[nodiscard]] std::string GetHactoolConfigurationPath();
|
||||
|
||||
[[nodiscard]] std::string GetNANDRegistrationDir(bool system = false);
|
||||
|
||||
// Returns the path to where the sys file are
|
||||
[[nodiscard]] std::string GetSysDirectory();
|
||||
|
||||
#ifdef __APPLE__
|
||||
[[nodiscard]] std::string GetBundleDirectory();
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
[[nodiscard]] const std::string& GetExeDirectory();
|
||||
[[nodiscard]] std::string AppDataRoamingDirectory();
|
||||
#endif
|
||||
|
||||
std::size_t WriteStringToFile(bool text_file, const std::string& filename, std::string_view str);
|
||||
|
||||
std::size_t ReadFileToString(bool text_file, const std::string& filename, std::string& str);
|
||||
|
||||
/**
|
||||
* Splits the filename into 8.3 format
|
||||
* Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename
|
||||
* @param filename The normal filename to use
|
||||
* @param short_name A 9-char array in which the short name will be written
|
||||
* @param extension A 4-char array in which the extension will be written
|
||||
*/
|
||||
void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name,
|
||||
std::array<char, 4>& extension);
|
||||
|
||||
// Splits the path on '/' or '\' and put the components into a vector
|
||||
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
|
||||
[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);
|
||||
|
||||
// Gets all of the text up to the last '/' or '\' in the path.
|
||||
[[nodiscard]] std::string_view GetParentPath(std::string_view path);
|
||||
|
||||
// Gets all of the text after the first '/' or '\' in the path.
|
||||
[[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path);
|
||||
|
||||
// Gets the filename of the path
|
||||
[[nodiscard]] std::string_view GetFilename(std::string_view path);
|
||||
|
||||
// Gets the extension of the filename
|
||||
[[nodiscard]] std::string_view GetExtensionFromFilename(std::string_view name);
|
||||
|
||||
// Removes the final '/' or '\' if one exists
|
||||
[[nodiscard]] std::string_view RemoveTrailingSlash(std::string_view path);
|
||||
|
||||
// Creates a new vector containing indices [first, last) from the original.
|
||||
template <typename T>
|
||||
[[nodiscard]] std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first,
|
||||
std::size_t last) {
|
||||
if (first >= last) {
|
||||
return {};
|
||||
}
|
||||
last = std::min<std::size_t>(last, vector.size());
|
||||
return std::vector<T>(vector.begin() + first, vector.begin() + first + last);
|
||||
}
|
||||
|
||||
enum class DirectorySeparator {
|
||||
ForwardSlash,
|
||||
BackwardSlash,
|
||||
PlatformDefault,
|
||||
};
|
||||
|
||||
// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
|
||||
// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
|
||||
[[nodiscard]] std::string SanitizePath(
|
||||
std::string_view path,
|
||||
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
|
||||
|
||||
// To deal with Windows being dumb at Unicode
|
||||
template <typename T>
|
||||
void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) {
|
||||
#ifdef _MSC_VER
|
||||
fstream.open(Common::UTF8ToUTF16W(filename), openmode);
|
||||
#else
|
||||
fstream.open(filename, openmode);
|
||||
#endif
|
||||
}
|
||||
|
||||
// simple wrapper for cstdlib file functions to
|
||||
// hopefully will make error checking easier
|
||||
// and make forgetting an fclose() harder
|
||||
class IOFile : public NonCopyable {
|
||||
public:
|
||||
IOFile();
|
||||
// flags is used for windows specific file open mode flags, which
|
||||
// allows yuzu to open the logs in shared write mode, so that the file
|
||||
// isn't considered "locked" while yuzu is open and people can open the log file and view it
|
||||
IOFile(const std::string& filename, const char openmode[], int flags = 0);
|
||||
|
||||
~IOFile();
|
||||
|
||||
IOFile(IOFile&& other) noexcept;
|
||||
IOFile& operator=(IOFile&& other) noexcept;
|
||||
|
||||
void Swap(IOFile& other) noexcept;
|
||||
|
||||
bool Open(const std::string& filename, const char openmode[], int flags = 0);
|
||||
bool Close();
|
||||
|
||||
template <typename T>
|
||||
std::size_t ReadArray(T* data, std::size_t length) const {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"Given array does not consist of trivially copyable objects");
|
||||
|
||||
return ReadImpl(data, length, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t WriteArray(const T* data, std::size_t length) {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"Given array does not consist of trivially copyable objects");
|
||||
|
||||
return WriteImpl(data, length, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t ReadBytes(T* data, std::size_t length) const {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
|
||||
return ReadArray(reinterpret_cast<char*>(data), length);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t WriteBytes(const T* data, std::size_t length) {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
|
||||
return WriteArray(reinterpret_cast<const char*>(data), length);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t WriteObject(const T& object) {
|
||||
static_assert(!std::is_pointer_v<T>, "WriteObject arguments must not be a pointer");
|
||||
return WriteArray(&object, 1);
|
||||
}
|
||||
|
||||
std::size_t WriteString(std::string_view str) {
|
||||
return WriteArray(str.data(), str.length());
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsOpen() const {
|
||||
return nullptr != m_file;
|
||||
}
|
||||
|
||||
bool Seek(s64 off, int origin) const;
|
||||
[[nodiscard]] u64 Tell() const;
|
||||
[[nodiscard]] u64 GetSize() const;
|
||||
bool Resize(u64 size);
|
||||
bool Flush();
|
||||
|
||||
// clear error state
|
||||
void Clear() {
|
||||
std::clearerr(m_file);
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t ReadImpl(void* data, std::size_t length, std::size_t data_size) const;
|
||||
std::size_t WriteImpl(const void* data, std::size_t length, std::size_t data_size);
|
||||
|
||||
std::FILE* m_file = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Common::FS
|
||||
@@ -0,0 +1,392 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/fs/file.h"
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <share.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define fileno _fileno
|
||||
#define fseeko _fseeki64
|
||||
#define ftello _ftelli64
|
||||
#endif
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/**
|
||||
* Converts the file access mode and file type enums to a file access mode wide string.
|
||||
*
|
||||
* @param mode File access mode
|
||||
* @param type File type
|
||||
*
|
||||
* @returns A pointer to a wide string representing the file access mode.
|
||||
*/
|
||||
[[nodiscard]] constexpr const wchar_t* AccessModeToWStr(FileAccessMode mode, FileType type) {
|
||||
switch (type) {
|
||||
case FileType::BinaryFile:
|
||||
switch (mode) {
|
||||
case FileAccessMode::Read:
|
||||
return L"rb";
|
||||
case FileAccessMode::Write:
|
||||
return L"wb";
|
||||
case FileAccessMode::Append:
|
||||
return L"ab";
|
||||
case FileAccessMode::ReadWrite:
|
||||
return L"r+b";
|
||||
case FileAccessMode::ReadAppend:
|
||||
return L"a+b";
|
||||
}
|
||||
break;
|
||||
case FileType::TextFile:
|
||||
switch (mode) {
|
||||
case FileAccessMode::Read:
|
||||
return L"r";
|
||||
case FileAccessMode::Write:
|
||||
return L"w";
|
||||
case FileAccessMode::Append:
|
||||
return L"a";
|
||||
case FileAccessMode::ReadWrite:
|
||||
return L"r+";
|
||||
case FileAccessMode::ReadAppend:
|
||||
return L"a+";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return L"";
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the file-share access flag enum to a Windows defined file-share access flag.
|
||||
*
|
||||
* @param flag File-share access flag
|
||||
*
|
||||
* @returns Windows defined file-share access flag.
|
||||
*/
|
||||
[[nodiscard]] constexpr int ToWindowsFileShareFlag(FileShareFlag flag) {
|
||||
switch (flag) {
|
||||
case FileShareFlag::ShareNone:
|
||||
default:
|
||||
return _SH_DENYRW;
|
||||
case FileShareFlag::ShareReadOnly:
|
||||
return _SH_DENYWR;
|
||||
case FileShareFlag::ShareWriteOnly:
|
||||
return _SH_DENYRD;
|
||||
case FileShareFlag::ShareReadWrite:
|
||||
return _SH_DENYNO;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
* Converts the file access mode and file type enums to a file access mode string.
|
||||
*
|
||||
* @param mode File access mode
|
||||
* @param type File type
|
||||
*
|
||||
* @returns A pointer to a string representing the file access mode.
|
||||
*/
|
||||
[[nodiscard]] constexpr const char* AccessModeToStr(FileAccessMode mode, FileType type) {
|
||||
switch (type) {
|
||||
case FileType::BinaryFile:
|
||||
switch (mode) {
|
||||
case FileAccessMode::Read:
|
||||
return "rb";
|
||||
case FileAccessMode::Write:
|
||||
return "wb";
|
||||
case FileAccessMode::Append:
|
||||
return "ab";
|
||||
case FileAccessMode::ReadWrite:
|
||||
return "r+b";
|
||||
case FileAccessMode::ReadAppend:
|
||||
return "a+b";
|
||||
}
|
||||
break;
|
||||
case FileType::TextFile:
|
||||
switch (mode) {
|
||||
case FileAccessMode::Read:
|
||||
return "r";
|
||||
case FileAccessMode::Write:
|
||||
return "w";
|
||||
case FileAccessMode::Append:
|
||||
return "a";
|
||||
case FileAccessMode::ReadWrite:
|
||||
return "r+";
|
||||
case FileAccessMode::ReadAppend:
|
||||
return "a+";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Converts the seek origin enum to a seek origin integer.
|
||||
*
|
||||
* @param origin Seek origin
|
||||
*
|
||||
* @returns Seek origin integer.
|
||||
*/
|
||||
[[nodiscard]] constexpr int ToSeekOrigin(SeekOrigin origin) {
|
||||
switch (origin) {
|
||||
case SeekOrigin::SetOrigin:
|
||||
default:
|
||||
return SEEK_SET;
|
||||
case SeekOrigin::CurrentPosition:
|
||||
return SEEK_CUR;
|
||||
case SeekOrigin::End:
|
||||
return SEEK_END;
|
||||
}
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
std::string ReadStringFromFile(const std::filesystem::path& path, FileType type) {
|
||||
if (!IsFile(path)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
IOFile io_file{path, FileAccessMode::Read, type};
|
||||
|
||||
return io_file.ReadString(io_file.GetSize());
|
||||
}
|
||||
|
||||
size_t WriteStringToFile(const std::filesystem::path& path, FileType type,
|
||||
std::string_view string) {
|
||||
if (!IsFile(path)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IOFile io_file{path, FileAccessMode::Write, type};
|
||||
|
||||
return io_file.WriteString(string);
|
||||
}
|
||||
|
||||
size_t AppendStringToFile(const std::filesystem::path& path, FileType type,
|
||||
std::string_view string) {
|
||||
if (!Exists(path)) {
|
||||
return WriteStringToFile(path, type, string);
|
||||
}
|
||||
|
||||
if (!IsFile(path)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IOFile io_file{path, FileAccessMode::Append, type};
|
||||
|
||||
return io_file.WriteString(string);
|
||||
}
|
||||
|
||||
IOFile::IOFile() = default;
|
||||
|
||||
IOFile::IOFile(const std::string& path, FileAccessMode mode, FileType type, FileShareFlag flag) {
|
||||
Open(path, mode, type, flag);
|
||||
}
|
||||
|
||||
IOFile::IOFile(std::string_view path, FileAccessMode mode, FileType type, FileShareFlag flag) {
|
||||
Open(path, mode, type, flag);
|
||||
}
|
||||
|
||||
IOFile::IOFile(const fs::path& path, FileAccessMode mode, FileType type, FileShareFlag flag) {
|
||||
Open(path, mode, type, flag);
|
||||
}
|
||||
|
||||
IOFile::~IOFile() {
|
||||
Close();
|
||||
}
|
||||
|
||||
IOFile::IOFile(IOFile&& other) noexcept {
|
||||
std::swap(file_path, other.file_path);
|
||||
std::swap(file_access_mode, other.file_access_mode);
|
||||
std::swap(file_type, other.file_type);
|
||||
std::swap(file, other.file);
|
||||
}
|
||||
|
||||
IOFile& IOFile::operator=(IOFile&& other) noexcept {
|
||||
std::swap(file_path, other.file_path);
|
||||
std::swap(file_access_mode, other.file_access_mode);
|
||||
std::swap(file_type, other.file_type);
|
||||
std::swap(file, other.file);
|
||||
return *this;
|
||||
}
|
||||
|
||||
fs::path IOFile::GetPath() const {
|
||||
return file_path;
|
||||
}
|
||||
|
||||
FileAccessMode IOFile::GetAccessMode() const {
|
||||
return file_access_mode;
|
||||
}
|
||||
|
||||
FileType IOFile::GetType() const {
|
||||
return file_type;
|
||||
}
|
||||
|
||||
void IOFile::Open(const fs::path& path, FileAccessMode mode, FileType type, FileShareFlag flag) {
|
||||
Close();
|
||||
|
||||
file_path = path;
|
||||
file_access_mode = mode;
|
||||
file_type = type;
|
||||
|
||||
errno = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (flag != FileShareFlag::ShareNone) {
|
||||
file = _wfsopen(path.c_str(), AccessModeToWStr(mode, type), ToWindowsFileShareFlag(flag));
|
||||
} else {
|
||||
_wfopen_s(&file, path.c_str(), AccessModeToWStr(mode, type));
|
||||
}
|
||||
#else
|
||||
file = std::fopen(path.c_str(), AccessModeToStr(mode, type));
|
||||
#endif
|
||||
|
||||
if (!IsOpen()) {
|
||||
const auto ec = std::error_code{errno, std::generic_category()};
|
||||
LOG_ERROR(Common_Filesystem, "Failed to open the file at path={}, ec_message={}",
|
||||
PathToUTF8String(file_path), ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
void IOFile::Close() {
|
||||
if (!IsOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
const auto close_result = std::fclose(file) == 0;
|
||||
|
||||
if (!close_result) {
|
||||
const auto ec = std::error_code{errno, std::generic_category()};
|
||||
LOG_ERROR(Common_Filesystem, "Failed to close the file at path={}, ec_message={}",
|
||||
PathToUTF8String(file_path), ec.message());
|
||||
}
|
||||
|
||||
file = nullptr;
|
||||
}
|
||||
|
||||
bool IOFile::IsOpen() const {
|
||||
return file != nullptr;
|
||||
}
|
||||
|
||||
std::string IOFile::ReadString(size_t length) const {
|
||||
std::vector<char> string_buffer(length);
|
||||
|
||||
const auto chars_read = ReadSpan<char>(string_buffer);
|
||||
const auto string_size = chars_read != length ? chars_read : length;
|
||||
|
||||
return std::string{string_buffer.data(), string_size};
|
||||
}
|
||||
|
||||
size_t IOFile::WriteString(std::span<const char> string) const {
|
||||
return WriteSpan(string);
|
||||
}
|
||||
|
||||
bool IOFile::Flush() const {
|
||||
if (!IsOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
const auto flush_result = std::fflush(file) == 0;
|
||||
|
||||
if (!flush_result) {
|
||||
const auto ec = std::error_code{errno, std::generic_category()};
|
||||
LOG_ERROR(Common_Filesystem, "Failed to flush the file at path={}, ec_message={}",
|
||||
PathToUTF8String(file_path), ec.message());
|
||||
}
|
||||
|
||||
return flush_result;
|
||||
}
|
||||
|
||||
bool IOFile::SetSize(u64 size) const {
|
||||
if (!IsOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
const auto set_size_result = _chsize_s(fileno(file), static_cast<s64>(size)) == 0;
|
||||
#else
|
||||
const auto set_size_result = ftruncate(fileno(file), static_cast<s64>(size)) == 0;
|
||||
#endif
|
||||
|
||||
if (!set_size_result) {
|
||||
const auto ec = std::error_code{errno, std::generic_category()};
|
||||
LOG_ERROR(Common_Filesystem, "Failed to resize the file at path={}, size={}, ec_message={}",
|
||||
PathToUTF8String(file_path), size, ec.message());
|
||||
}
|
||||
|
||||
return set_size_result;
|
||||
}
|
||||
|
||||
u64 IOFile::GetSize() const {
|
||||
if (!IsOpen()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
const auto file_size = fs::file_size(file_path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}",
|
||||
PathToUTF8String(file_path), ec.message());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return file_size;
|
||||
}
|
||||
|
||||
bool IOFile::Seek(s64 offset, SeekOrigin origin) const {
|
||||
if (!IsOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
const auto seek_result = fseeko(file, offset, ToSeekOrigin(origin)) == 0;
|
||||
|
||||
if (!seek_result) {
|
||||
const auto ec = std::error_code{errno, std::generic_category()};
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to seek the file at path={}, offset={}, origin={}, ec_message={}",
|
||||
PathToUTF8String(file_path), offset, origin, ec.message());
|
||||
}
|
||||
|
||||
return seek_result;
|
||||
}
|
||||
|
||||
s64 IOFile::Tell() const {
|
||||
if (!IsOpen()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
return ftello(file);
|
||||
}
|
||||
|
||||
} // namespace Common::FS
|
||||
@@ -0,0 +1,453 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "common/concepts.h"
|
||||
#include "common/fs/fs_types.h"
|
||||
#include "common/fs/fs_util.h"
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
enum class SeekOrigin {
|
||||
SetOrigin, // Seeks from the start of the file.
|
||||
CurrentPosition, // Seeks from the current file pointer position.
|
||||
End, // Seeks from the end of the file.
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens a file stream at path with the specified open mode.
|
||||
*
|
||||
* @param file_stream Reference to file stream
|
||||
* @param path Filesystem path
|
||||
* @param open_mode File stream open mode
|
||||
*/
|
||||
template <typename FileStream>
|
||||
void OpenFileStream(FileStream& file_stream, const std::filesystem::path& path,
|
||||
std::ios_base::openmode open_mode) {
|
||||
file_stream.open(path, open_mode);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename FileStream, typename Path>
|
||||
void OpenFileStream(FileStream& file_stream, const Path& path, std::ios_base::openmode open_mode) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
file_stream.open(ToU8String(path), open_mode);
|
||||
} else {
|
||||
file_stream.open(std::filesystem::path{path}, open_mode);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Reads an entire file at path and returns a string of the contents read from the file.
|
||||
* If the filesystem object at path is not a file, this function returns an empty string.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
* @param type File type
|
||||
*
|
||||
* @returns A string of the contents read from the file.
|
||||
*/
|
||||
[[nodiscard]] std::string ReadStringFromFile(const std::filesystem::path& path, FileType type);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] std::string ReadStringFromFile(const Path& path, FileType type) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return ReadStringFromFile(ToU8String(path), type);
|
||||
} else {
|
||||
return ReadStringFromFile(std::filesystem::path{path}, type);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Writes a string to a file at path and returns the number of characters successfully written.
|
||||
* If an file already exists at path, its contents will be erased.
|
||||
* If the filesystem object at path is not a file, this function returns 0.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
* @param type File type
|
||||
*
|
||||
* @returns Number of characters successfully written.
|
||||
*/
|
||||
[[nodiscard]] size_t WriteStringToFile(const std::filesystem::path& path, FileType type,
|
||||
std::string_view string);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] size_t WriteStringToFile(const Path& path, FileType type, std::string_view string) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return WriteStringToFile(ToU8String(path), type, string);
|
||||
} else {
|
||||
return WriteStringToFile(std::filesystem::path{path}, type, string);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Appends a string to a file at path and returns the number of characters successfully written.
|
||||
* If a file does not exist at path, WriteStringToFile is called instead.
|
||||
* If the filesystem object at path is not a file, this function returns 0.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
* @param type File type
|
||||
*
|
||||
* @returns Number of characters successfully written.
|
||||
*/
|
||||
[[nodiscard]] size_t AppendStringToFile(const std::filesystem::path& path, FileType type,
|
||||
std::string_view string);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] size_t AppendStringToFile(const Path& path, FileType type, std::string_view string) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return AppendStringToFile(ToU8String(path), type, string);
|
||||
} else {
|
||||
return AppendStringToFile(std::filesystem::path{path}, type, string);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
class IOFile final {
|
||||
public:
|
||||
IOFile();
|
||||
|
||||
explicit IOFile(const std::string& path, FileAccessMode mode,
|
||||
FileType type = FileType::BinaryFile,
|
||||
FileShareFlag flag = FileShareFlag::ShareReadOnly);
|
||||
|
||||
explicit IOFile(std::string_view path, FileAccessMode mode,
|
||||
FileType type = FileType::BinaryFile,
|
||||
FileShareFlag flag = FileShareFlag::ShareReadOnly);
|
||||
|
||||
/**
|
||||
* An IOFile is a lightweight wrapper on C Library file operations.
|
||||
* Automatically closes an open file on the destruction of an IOFile object.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
* @param mode File access mode
|
||||
* @param type File type, default is BinaryFile. Use TextFile to open the file as a text file
|
||||
* @param flag (Windows only) File-share access flag, default is ShareReadOnly
|
||||
*/
|
||||
explicit IOFile(const std::filesystem::path& path, FileAccessMode mode,
|
||||
FileType type = FileType::BinaryFile,
|
||||
FileShareFlag flag = FileShareFlag::ShareReadOnly);
|
||||
|
||||
~IOFile();
|
||||
|
||||
IOFile(const IOFile&) = delete;
|
||||
IOFile& operator=(const IOFile&) = delete;
|
||||
|
||||
IOFile(IOFile&& other) noexcept;
|
||||
IOFile& operator=(IOFile&& other) noexcept;
|
||||
|
||||
/**
|
||||
* Gets the path of the file.
|
||||
*
|
||||
* @returns The path of the file.
|
||||
*/
|
||||
[[nodiscard]] std::filesystem::path GetPath() const;
|
||||
|
||||
/**
|
||||
* Gets the access mode of the file.
|
||||
*
|
||||
* @returns The access mode of the file.
|
||||
*/
|
||||
[[nodiscard]] FileAccessMode GetAccessMode() const;
|
||||
|
||||
/**
|
||||
* Gets the type of the file.
|
||||
*
|
||||
* @returns The type of the file.
|
||||
*/
|
||||
[[nodiscard]] FileType GetType() const;
|
||||
|
||||
/**
|
||||
* Opens a file at path with the specified file access mode.
|
||||
* This function behaves differently depending on the FileAccessMode.
|
||||
* These behaviors are documented in each enum value of FileAccessMode.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
* @param mode File access mode
|
||||
* @param type File type, default is BinaryFile. Use TextFile to open the file as a text file
|
||||
* @param flag (Windows only) File-share access flag, default is ShareReadOnly
|
||||
*/
|
||||
void Open(const std::filesystem::path& path, FileAccessMode mode,
|
||||
FileType type = FileType::BinaryFile,
|
||||
FileShareFlag flag = FileShareFlag::ShareReadOnly);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] void Open(const Path& path, FileAccessMode mode,
|
||||
FileType type = FileType::BinaryFile,
|
||||
FileShareFlag flag = FileShareFlag::ShareReadOnly) {
|
||||
using ValueType = typename Path::value_type;
|
||||
if constexpr (IsChar<ValueType>) {
|
||||
Open(ToU8String(path), mode, type, flag);
|
||||
} else {
|
||||
Open(std::filesystem::path{path}, mode, type, flag);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Closes the file if it is opened.
|
||||
void Close();
|
||||
|
||||
/**
|
||||
* Checks whether the file is open.
|
||||
* Use this to check whether the calls to Open() or Close() succeeded.
|
||||
*
|
||||
* @returns True if the file is open, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool IsOpen() const;
|
||||
|
||||
/**
|
||||
* Helper function which deduces the value type of a contiguous STL container used in ReadSpan.
|
||||
* If T is not a contiguous STL container as defined by the concept IsSTLContainer, this calls
|
||||
* ReadObject and T must be a trivially copyable object.
|
||||
*
|
||||
* See ReadSpan for more details if T is a contiguous container.
|
||||
* See ReadObject for more details if T is a trivially copyable object.
|
||||
*
|
||||
* @tparam T Contiguous container or trivially copyable object
|
||||
*
|
||||
* @param data Container of T::value_type data or reference to object
|
||||
*
|
||||
* @returns Count of T::value_type data or objects successfully read.
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] size_t Read(T& data) const {
|
||||
if constexpr (IsSTLContainer<T>) {
|
||||
using ContiguousType = typename T::value_type;
|
||||
static_assert(std::is_trivially_copyable_v<ContiguousType>,
|
||||
"Data type must be trivially copyable.");
|
||||
return ReadSpan<ContiguousType>(data);
|
||||
} else {
|
||||
return ReadObject(data) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function which deduces the value type of a contiguous STL container used in WriteSpan.
|
||||
* If T is not a contiguous STL container as defined by the concept IsSTLContainer, this calls
|
||||
* WriteObject and T must be a trivially copyable object.
|
||||
*
|
||||
* See WriteSpan for more details if T is a contiguous container.
|
||||
* See WriteObject for more details if T is a trivially copyable object.
|
||||
*
|
||||
* @tparam T Contiguous container or trivially copyable object
|
||||
*
|
||||
* @param data Container of T::value_type data or const reference to object
|
||||
*
|
||||
* @returns Count of T::value_type data or objects successfully written.
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] size_t Write(const T& data) const {
|
||||
if constexpr (IsSTLContainer<T>) {
|
||||
using ContiguousType = typename T::value_type;
|
||||
static_assert(std::is_trivially_copyable_v<ContiguousType>,
|
||||
"Data type must be trivially copyable.");
|
||||
return WriteSpan<ContiguousType>(data);
|
||||
} else {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||
return WriteObject(data) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a span of T data from a file sequentially.
|
||||
* This function reads from the current position of the file pointer and
|
||||
* advances it by the (count of T * sizeof(T)) bytes successfully read.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - The file is not open
|
||||
* - The opened file lacks read permissions
|
||||
* - Attempting to read beyond the end-of-file
|
||||
*
|
||||
* @tparam T Data type
|
||||
*
|
||||
* @param data Span of T data
|
||||
*
|
||||
* @returns Count of T data successfully read.
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] size_t ReadSpan(std::span<T> data) const {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||
|
||||
if (!IsOpen()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return std::fread(data.data(), sizeof(T), data.size(), file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a span of T data to a file sequentially.
|
||||
* This function writes from the current position of the file pointer and
|
||||
* advances it by the (count of T * sizeof(T)) bytes successfully written.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - The file is not open
|
||||
* - The opened file lacks write permissions
|
||||
*
|
||||
* @tparam T Data type
|
||||
*
|
||||
* @param data Span of T data
|
||||
*
|
||||
* @returns Count of T data successfully written.
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] size_t WriteSpan(std::span<const T> data) const {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||
|
||||
if (!IsOpen()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return std::fwrite(data.data(), sizeof(T), data.size(), file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a T object from a file sequentially.
|
||||
* This function reads from the current position of the file pointer and
|
||||
* advances it by the sizeof(T) bytes successfully read.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - The file is not open
|
||||
* - The opened file lacks read permissions
|
||||
* - Attempting to read beyond the end-of-file
|
||||
*
|
||||
* @tparam T Data type
|
||||
*
|
||||
* @param object Reference to object
|
||||
*
|
||||
* @returns True if the object is successfully read from the file, false otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] bool ReadObject(T& object) const {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||
static_assert(!std::is_pointer_v<T>, "T must not be a pointer to an object.");
|
||||
|
||||
if (!IsOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::fread(&object, sizeof(T), 1, file) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a T object to a file sequentially.
|
||||
* This function writes from the current position of the file pointer and
|
||||
* advances it by the sizeof(T) bytes successfully written.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - The file is not open
|
||||
* - The opened file lacks write permissions
|
||||
*
|
||||
* @tparam T Data type
|
||||
*
|
||||
* @param object Const reference to object
|
||||
*
|
||||
* @returns True if the object is successfully written to the file, false otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] bool WriteObject(const T& object) const {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
|
||||
static_assert(!std::is_pointer_v<T>, "T must not be a pointer to an object.");
|
||||
|
||||
if (!IsOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::fwrite(&object, sizeof(T), 1, file) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized function to read a string of a given length from a file sequentially.
|
||||
* This function writes from the current position of the file pointer and
|
||||
* advances it by the number of characters successfully read.
|
||||
* The size of the returned string may not match length if not all bytes are successfully read.
|
||||
*
|
||||
* @param length Length of the string
|
||||
*
|
||||
* @returns A string read from the file.
|
||||
*/
|
||||
[[nodiscard]] std::string ReadString(size_t length) const;
|
||||
|
||||
/**
|
||||
* Specialized function to write a string to a file sequentially.
|
||||
* This function writes from the current position of the file pointer and
|
||||
* advances it by the number of characters successfully written.
|
||||
*
|
||||
* @param string Span of const char backed std::string or std::string_view
|
||||
*
|
||||
* @returns Number of characters successfully written.
|
||||
*/
|
||||
[[nodiscard]] size_t WriteString(std::span<const char> string) const;
|
||||
|
||||
/**
|
||||
* Flushes any unwritten buffered data into the file.
|
||||
*
|
||||
* @returns True if the flush was successful, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool Flush() const;
|
||||
|
||||
/**
|
||||
* Resizes the file to a given size.
|
||||
* If the file is resized to a smaller size, the remainder of the file is discarded.
|
||||
* If the file is resized to a larger size, the new area appears as if zero-filled.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - The file is not open
|
||||
*
|
||||
* @param size File size in bytes
|
||||
*
|
||||
* @returns True if the file resize succeeded, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool SetSize(u64 size) const;
|
||||
|
||||
/**
|
||||
* Gets the size of the file.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - The file is not open
|
||||
*
|
||||
* @returns The file size in bytes of the file. Returns 0 on failure.
|
||||
*/
|
||||
[[nodiscard]] u64 GetSize() const;
|
||||
|
||||
/**
|
||||
* Moves the current position of the file pointer with the specified offset and seek origin.
|
||||
*
|
||||
* @param offset Offset from seek origin
|
||||
* @param origin Seek origin
|
||||
*
|
||||
* @returns True if the file pointer has moved to the specified offset, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool Seek(s64 offset, SeekOrigin origin = SeekOrigin::SetOrigin) const;
|
||||
|
||||
/**
|
||||
* Gets the current position of the file pointer.
|
||||
*
|
||||
* @returns The current position of the file pointer.
|
||||
*/
|
||||
[[nodiscard]] s64 Tell() const;
|
||||
|
||||
private:
|
||||
std::filesystem::path file_path;
|
||||
FileAccessMode file_access_mode{};
|
||||
FileType file_type{};
|
||||
|
||||
std::FILE* file = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Common::FS
|
||||
@@ -0,0 +1,610 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/fs/file.h"
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// File Operations
|
||||
|
||||
bool NewFile(const fs::path& path, u64 size) {
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Exists(path.parent_path())) {
|
||||
LOG_ERROR(Common_Filesystem, "Parent directory of path={} does not exist",
|
||||
PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Exists(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} exists", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
IOFile io_file{path, FileAccessMode::Write};
|
||||
|
||||
if (!io_file.IsOpen()) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to create a file at path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!io_file.SetSize(size)) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to resize the file at path={} to size={}",
|
||||
PathToUTF8String(path), size);
|
||||
return false;
|
||||
}
|
||||
|
||||
io_file.Close();
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Successfully created a file at path={} with size={}",
|
||||
PathToUTF8String(path), size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoveFile(const fs::path& path) {
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Exists(path)) {
|
||||
LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||
PathToUTF8String(path));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!IsFile(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a file",
|
||||
PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
fs::remove(path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to remove the file at path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Successfully removed the file at path={}",
|
||||
PathToUTF8String(path));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenameFile(const fs::path& old_path, const fs::path& new_path) {
|
||||
if (!ValidatePath(old_path) || !ValidatePath(new_path)) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"One or both input path(s) is not valid, old_path={}, new_path={}",
|
||||
PathToUTF8String(old_path), PathToUTF8String(new_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Exists(old_path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at old_path={} does not exist",
|
||||
PathToUTF8String(old_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsFile(old_path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at old_path={} is not a file",
|
||||
PathToUTF8String(old_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Exists(new_path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at new_path={} exists",
|
||||
PathToUTF8String(new_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
fs::rename(old_path, new_path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to rename the file from old_path={} to new_path={}, ec_message={}",
|
||||
PathToUTF8String(old_path), PathToUTF8String(new_path), ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Successfully renamed the file from old_path={} to new_path={}",
|
||||
PathToUTF8String(old_path), PathToUTF8String(new_path));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<IOFile> FileOpen(const fs::path& path, FileAccessMode mode, FileType type,
|
||||
FileShareFlag flag) {
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!IsFile(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a file",
|
||||
PathToUTF8String(path));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto io_file = std::make_shared<IOFile>(path, mode, type, flag);
|
||||
|
||||
if (!io_file->IsOpen()) {
|
||||
io_file.reset();
|
||||
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to open the file at path={} with mode={}, type={}, flag={}",
|
||||
PathToUTF8String(path), mode, type, flag);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem,
|
||||
"Successfully opened the file at path={} with mode={}, type={}, flag={}",
|
||||
PathToUTF8String(path), mode, type, flag);
|
||||
|
||||
return io_file;
|
||||
}
|
||||
|
||||
// Directory Operations
|
||||
|
||||
bool CreateDir(const fs::path& path) {
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Exists(path.parent_path())) {
|
||||
LOG_ERROR(Common_Filesystem, "Parent directory of path={} does not exist",
|
||||
PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsDir(path)) {
|
||||
LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} exists and is a directory",
|
||||
PathToUTF8String(path));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
fs::create_directory(path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to create the directory at path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Successfully created the directory at path={}",
|
||||
PathToUTF8String(path));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateDirs(const fs::path& path) {
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsDir(path)) {
|
||||
LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} exists and is a directory",
|
||||
PathToUTF8String(path));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
fs::create_directories(path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to create the directories at path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Successfully created the directories at path={}",
|
||||
PathToUTF8String(path));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateParentDir(const fs::path& path) {
|
||||
return CreateDir(path.parent_path());
|
||||
}
|
||||
|
||||
bool CreateParentDirs(const fs::path& path) {
|
||||
return CreateDirs(path.parent_path());
|
||||
}
|
||||
|
||||
bool RemoveDir(const fs::path& path) {
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Exists(path)) {
|
||||
LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||
PathToUTF8String(path));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!IsDir(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
|
||||
PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
fs::remove(path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to remove the directory at path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Successfully removed the directory at path={}",
|
||||
PathToUTF8String(path));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoveDirRecursively(const fs::path& path) {
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Exists(path)) {
|
||||
LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||
PathToUTF8String(path));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!IsDir(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
|
||||
PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
fs::remove_all(path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to remove the directory and its contents at path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Successfully removed the directory and its contents at path={}",
|
||||
PathToUTF8String(path));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoveDirContentsRecursively(const fs::path& path) {
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Exists(path)) {
|
||||
LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||
PathToUTF8String(path));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!IsDir(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
|
||||
PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
for (const auto& entry : fs::recursive_directory_iterator(path, ec)) {
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to completely enumerate the directory at path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
break;
|
||||
}
|
||||
|
||||
fs::remove(entry.path(), ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to remove the filesystem object at path={}, ec_message={}",
|
||||
PathToUTF8String(entry.path()), ec.message());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to remove all the contents of the directory at path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem,
|
||||
"Successfully removed all the contents of the directory at path={}",
|
||||
PathToUTF8String(path));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenameDir(const fs::path& old_path, const fs::path& new_path) {
|
||||
if (!ValidatePath(old_path) || !ValidatePath(new_path)) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"One or both input path(s) is not valid, old_path={}, new_path={}",
|
||||
PathToUTF8String(old_path), PathToUTF8String(new_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Exists(old_path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at old_path={} does not exist",
|
||||
PathToUTF8String(old_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsDir(old_path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at old_path={} is not a directory",
|
||||
PathToUTF8String(old_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Exists(new_path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at new_path={} exists",
|
||||
PathToUTF8String(new_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
fs::rename(old_path, new_path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to rename the file from old_path={} to new_path={}, ec_message={}",
|
||||
PathToUTF8String(old_path), PathToUTF8String(new_path), ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Successfully renamed the file from old_path={} to new_path={}",
|
||||
PathToUTF8String(old_path), PathToUTF8String(new_path));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable& callback,
|
||||
DirEntryFilter filter) {
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Exists(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||
PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsDir(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
|
||||
PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
bool callback_error = false;
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
for (const auto& entry : fs::directory_iterator(path, ec)) {
|
||||
if (ec) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (True(filter & DirEntryFilter::File) &&
|
||||
entry.status().type() == fs::file_type::regular) {
|
||||
if (!callback(entry.path())) {
|
||||
callback_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (True(filter & DirEntryFilter::Directory) &&
|
||||
entry.status().type() == fs::file_type::directory) {
|
||||
if (!callback(entry.path())) {
|
||||
callback_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (callback_error || ec) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to visit all the directory entries of path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Successfully visited all the directory entries of path={}",
|
||||
PathToUTF8String(path));
|
||||
}
|
||||
|
||||
void IterateDirEntriesRecursively(const std::filesystem::path& path,
|
||||
const DirEntryCallable& callback, DirEntryFilter filter) {
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Exists(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||
PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsDir(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
|
||||
PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
bool callback_error = false;
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
for (const auto& entry : fs::recursive_directory_iterator(path, ec)) {
|
||||
if (ec) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (True(filter & DirEntryFilter::File) &&
|
||||
entry.status().type() == fs::file_type::regular) {
|
||||
if (!callback(entry.path())) {
|
||||
callback_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (True(filter & DirEntryFilter::Directory) &&
|
||||
entry.status().type() == fs::file_type::directory) {
|
||||
if (!callback(entry.path())) {
|
||||
callback_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (callback_error || ec) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to visit all the directory entries of path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Successfully visited all the directory entries of path={}",
|
||||
PathToUTF8String(path));
|
||||
}
|
||||
|
||||
// Generic Filesystem Operations
|
||||
|
||||
bool Exists(const fs::path& path) {
|
||||
return fs::exists(path);
|
||||
}
|
||||
|
||||
bool IsFile(const fs::path& path) {
|
||||
return fs::is_regular_file(path);
|
||||
}
|
||||
|
||||
bool IsDir(const fs::path& path) {
|
||||
return fs::is_directory(path);
|
||||
}
|
||||
|
||||
fs::path GetCurrentDir() {
|
||||
std::error_code ec;
|
||||
|
||||
const auto current_path = fs::current_path(ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to get the current path, ec_message={}", ec.message());
|
||||
return {};
|
||||
}
|
||||
|
||||
return current_path;
|
||||
}
|
||||
|
||||
bool SetCurrentDir(const fs::path& path) {
|
||||
std::error_code ec;
|
||||
|
||||
fs::current_path(path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to set the current path to path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fs::file_type GetEntryType(const fs::path& path) {
|
||||
std::error_code ec;
|
||||
|
||||
const auto file_status = fs::status(path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to retrieve the entry type of path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return fs::file_type::not_found;
|
||||
}
|
||||
|
||||
return file_status.type();
|
||||
}
|
||||
|
||||
u64 GetSize(const fs::path& path) {
|
||||
std::error_code ec;
|
||||
|
||||
const auto file_size = fs::file_size(path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return file_size;
|
||||
}
|
||||
|
||||
u64 GetFreeSpaceSize(const fs::path& path) {
|
||||
std::error_code ec;
|
||||
|
||||
const auto space_info = fs::space(path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to retrieve the available free space of path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return space_info.free;
|
||||
}
|
||||
|
||||
u64 GetTotalSpaceSize(const fs::path& path) {
|
||||
std::error_code ec;
|
||||
|
||||
const auto space_info = fs::space(path, ec);
|
||||
|
||||
if (ec) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to retrieve the total capacity of path={}, ec_message={}",
|
||||
PathToUTF8String(path), ec.message());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return space_info.capacity;
|
||||
}
|
||||
|
||||
} // namespace Common::FS
|
||||
@@ -0,0 +1,582 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
|
||||
#include "common/fs/fs_types.h"
|
||||
#include "common/fs/fs_util.h"
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
class IOFile;
|
||||
|
||||
// File Operations
|
||||
|
||||
/**
|
||||
* Creates a new file at path with the specified size.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is not valid
|
||||
* - The input path's parent directory does not exist
|
||||
* - Filesystem object at path exists
|
||||
* - Filesystem at path is read only
|
||||
*
|
||||
* @param path Filesystem path
|
||||
* @param size File size
|
||||
*
|
||||
* @returns True if the file creation succeeds, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool NewFile(const std::filesystem::path& path, u64 size = 0);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool NewFile(const Path& path, u64 size = 0) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return NewFile(ToU8String(path), size);
|
||||
} else {
|
||||
return NewFile(std::filesystem::path{path}, size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Removes a file at path.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path is not a file
|
||||
* - Filesystem at path is read only
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if file removal succeeds or file does not exist, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool RemoveFile(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool RemoveFile(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return RemoveFile(ToU8String(path));
|
||||
} else {
|
||||
return RemoveFile(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Renames a file from old_path to new_path.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - One or both input path(s) is not valid
|
||||
* - Filesystem object at old_path does not exist
|
||||
* - Filesystem object at old_path is not a file
|
||||
* - Filesystem object at new_path exists
|
||||
* - Filesystem at either path is read only
|
||||
*
|
||||
* @param old_path Old filesystem path
|
||||
* @param new_path New filesystem path
|
||||
*
|
||||
* @returns True if file rename succeeds, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool RenameFile(const std::filesystem::path& old_path,
|
||||
const std::filesystem::path& new_path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path1, typename Path2>
|
||||
[[nodiscard]] bool RenameFile(const Path1& old_path, const Path2& new_path) {
|
||||
using ValueType1 = typename Path1::value_type;
|
||||
using ValueType2 = typename Path2::value_type;
|
||||
if constexpr (IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||
return RenameFile(ToU8String(old_path), ToU8String(new_path));
|
||||
} else if constexpr (IsChar<ValueType1> && !IsChar<ValueType2>) {
|
||||
return RenameFile(ToU8String(old_path), new_path);
|
||||
} else if constexpr (!IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||
return RenameFile(old_path, ToU8String(new_path));
|
||||
} else {
|
||||
return RenameFile(std::filesystem::path{old_path}, std::filesystem::path{new_path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Opens a file at path with the specified file access mode.
|
||||
* This function behaves differently depending on the FileAccessMode.
|
||||
* These behaviors are documented in each enum value of FileAccessMode.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path is not a file
|
||||
* - The file is not opened
|
||||
*
|
||||
* @param path Filesystem path
|
||||
* @param mode File access mode
|
||||
* @param type File type, default is BinaryFile. Use TextFile to open the file as a text file
|
||||
* @param flag (Windows only) File-share access flag, default is ShareReadOnly
|
||||
*
|
||||
* @returns A shared pointer to the opened file. Returns nullptr on failure.
|
||||
*/
|
||||
[[nodiscard]] std::shared_ptr<IOFile> FileOpen(const std::filesystem::path& path,
|
||||
FileAccessMode mode,
|
||||
FileType type = FileType::BinaryFile,
|
||||
FileShareFlag flag = FileShareFlag::ShareReadOnly);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] std::shared_ptr<IOFile> FileOpen(const Path& path, FileAccessMode mode,
|
||||
FileType type = FileType::BinaryFile,
|
||||
FileShareFlag flag = FileShareFlag::ShareReadOnly) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return FileOpen(ToU8String(path), mode, type, flag);
|
||||
} else {
|
||||
return FileOpen(std::filesystem::path{path}, mode, type, flag);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Directory Operations
|
||||
|
||||
/**
|
||||
* Creates a directory at path.
|
||||
* Note that this function will *always* assume that the input path is a directory. For example,
|
||||
* if the input path is /path/to/directory/file.txt, it will create a directory called "file.txt".
|
||||
* If you intend to create the parent directory of a file, use CreateParentDir instead.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is not valid
|
||||
* - The input path's parent directory does not exist
|
||||
* - Filesystem at path is read only
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if directory creation succeeds or directory already exists, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool CreateDir(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool CreateDir(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return CreateDir(ToU8String(path));
|
||||
} else {
|
||||
return CreateDir(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Recursively creates a directory at path.
|
||||
* Note that this function will *always* assume that the input path is a directory. For example,
|
||||
* if the input path is /path/to/directory/file.txt, it will create a directory called "file.txt".
|
||||
* If you intend to create the parent directory of a file, use CreateParentDirs instead.
|
||||
* Unlike CreateDir, this creates all of input path's parent directories if they do not exist.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is not valid
|
||||
* - Filesystem at path is read only
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if directory creation succeeds or directory already exists, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool CreateDirs(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool CreateDirs(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return CreateDirs(ToU8String(path));
|
||||
} else {
|
||||
return CreateDirs(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates the parent directory of a given path.
|
||||
* This function calls CreateDir(path.parent_path()), see CreateDir for more details.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if directory creation succeeds or directory already exists, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool CreateParentDir(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool CreateParentDir(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return CreateParentDir(ToU8String(path));
|
||||
} else {
|
||||
return CreateParentDir(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Recursively creates the parent directory of a given path.
|
||||
* This function calls CreateDirs(path.parent_path()), see CreateDirs for more details.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if directory creation succeeds or directory already exists, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool CreateParentDirs(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool CreateParentDirs(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return CreateParentDirs(ToU8String(path));
|
||||
} else {
|
||||
return CreateParentDirs(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Removes a directory at path.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path is not a directory
|
||||
* - The given directory is not empty
|
||||
* - Filesystem at path is read only
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if directory removal succeeds or directory does not exist, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool RemoveDir(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool RemoveDir(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return RemoveDir(ToU8String(path));
|
||||
} else {
|
||||
return RemoveDir(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Removes all the contents within the given directory and removes the directory itself.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path is not a directory
|
||||
* - Filesystem at path is read only
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if the directory and all of its contents are removed successfully, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool RemoveDirRecursively(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool RemoveDirRecursively(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return RemoveDirRecursively(ToU8String(path));
|
||||
} else {
|
||||
return RemoveDirRecursively(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Removes all the contents within the given directory without removing the directory itself.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path is not a directory
|
||||
* - Filesystem at path is read only
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if all of the directory's contents are removed successfully, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool RemoveDirContentsRecursively(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool RemoveDirContentsRecursively(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return RemoveDirContentsRecursively(ToU8String(path));
|
||||
} else {
|
||||
return RemoveDirContentsRecursively(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Renames a directory from old_path to new_path.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - One or both input path(s) is not valid
|
||||
* - Filesystem object at old_path does not exist
|
||||
* - Filesystem object at old_path is not a directory
|
||||
* - Filesystem object at new_path exists
|
||||
* - Filesystem at either path is read only
|
||||
*
|
||||
* @param old_path Old filesystem path
|
||||
* @param new_path New filesystem path
|
||||
*
|
||||
* @returns True if directory rename succeeds, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool RenameDir(const std::filesystem::path& old_path,
|
||||
const std::filesystem::path& new_path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path1, typename Path2>
|
||||
[[nodiscard]] bool RenameDir(const Path1& old_path, const Path2& new_path) {
|
||||
using ValueType1 = typename Path1::value_type;
|
||||
using ValueType2 = typename Path2::value_type;
|
||||
if constexpr (IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||
return RenameDir(ToU8String(old_path), ToU8String(new_path));
|
||||
} else if constexpr (IsChar<ValueType1> && !IsChar<ValueType2>) {
|
||||
return RenameDir(ToU8String(old_path), new_path);
|
||||
} else if constexpr (!IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||
return RenameDir(old_path, ToU8String(new_path));
|
||||
} else {
|
||||
return RenameDir(std::filesystem::path{old_path}, std::filesystem::path{new_path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Iterates over the directory entries of a given directory.
|
||||
* This does not iterate over the sub-directories of the given directory.
|
||||
* The DirEntryCallable callback is called for each visited directory entry.
|
||||
* A filter can be set to control which directory entries are visited based on their type.
|
||||
* By default, both files and directories are visited.
|
||||
* If the callback returns false or there is an error, the iteration is immediately halted.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path is not a directory
|
||||
*
|
||||
* @param path Filesystem path
|
||||
* @param callback Callback to be called for each visited directory entry
|
||||
* @param filter Directory entry type filter
|
||||
*/
|
||||
void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable& callback,
|
||||
DirEntryFilter filter = DirEntryFilter::All);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
void IterateDirEntries(const Path& path, const DirEntryCallable& callback,
|
||||
DirEntryFilter filter = DirEntryFilter::All) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
IterateDirEntries(ToU8String(path), callback, filter);
|
||||
} else {
|
||||
IterateDirEntries(std::filesystem::path{path}, callback, filter);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Iterates over the directory entries of a given directory and its sub-directories.
|
||||
* The DirEntryCallable callback is called for each visited directory entry.
|
||||
* A filter can be set to control which directory entries are visited based on their type.
|
||||
* By default, both files and directories are visited.
|
||||
* If the callback returns false or there is an error, the iteration is immediately halted.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path does not exist
|
||||
* - Filesystem object at path is not a directory
|
||||
*
|
||||
* @param path Filesystem path
|
||||
* @param callback Callback to be called for each visited directory entry
|
||||
* @param filter Directory entry type filter
|
||||
*/
|
||||
void IterateDirEntriesRecursively(const std::filesystem::path& path,
|
||||
const DirEntryCallable& callback,
|
||||
DirEntryFilter filter = DirEntryFilter::All);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
void IterateDirEntriesRecursively(const Path& path, const DirEntryCallable& callback,
|
||||
DirEntryFilter filter = DirEntryFilter::All) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
IterateDirEntriesRecursively(ToU8String(path), callback, filter);
|
||||
} else {
|
||||
IterateDirEntriesRecursively(std::filesystem::path{path}, callback, filter);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Generic Filesystem Operations
|
||||
|
||||
/**
|
||||
* Returns whether a filesystem object at path exists.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if a filesystem object at path exists, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool Exists(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool Exists(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return Exists(ToU8String(path));
|
||||
} else {
|
||||
return Exists(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns whether a filesystem object at path is a file.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if a filesystem object at path is a file, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool IsFile(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool IsFile(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return IsFile(ToU8String(path));
|
||||
} else {
|
||||
return IsFile(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns whether a filesystem object at path is a directory.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if a filesystem object at path is a directory, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool IsDir(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool IsDir(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return IsDir(ToU8String(path));
|
||||
} else {
|
||||
return IsDir(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the current working directory.
|
||||
*
|
||||
* @returns The current working directory. Returns an empty path on failure.
|
||||
*/
|
||||
[[nodiscard]] std::filesystem::path GetCurrentDir();
|
||||
|
||||
/**
|
||||
* Sets the current working directory to path.
|
||||
*
|
||||
* @returns True if the current working directory is successfully set, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool SetCurrentDir(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool SetCurrentDir(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return SetCurrentDir(ToU8String(path));
|
||||
} else {
|
||||
return SetCurrentDir(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the entry type of the filesystem object at path.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns The entry type of the filesystem object. Returns file_type::not_found on failure.
|
||||
*/
|
||||
[[nodiscard]] std::filesystem::file_type GetEntryType(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] std::filesystem::file_type GetEntryType(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return GetEntryType(ToU8String(path));
|
||||
} else {
|
||||
return GetEntryType(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the size of the filesystem object at path.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns The size in bytes of the filesystem object. Returns 0 on failure.
|
||||
*/
|
||||
[[nodiscard]] u64 GetSize(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] u64 GetSize(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return GetSize(ToU8String(path));
|
||||
} else {
|
||||
return GetSize(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the free space size of the filesystem at path.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns The free space size in bytes of the filesystem at path. Returns 0 on failure.
|
||||
*/
|
||||
[[nodiscard]] u64 GetFreeSpaceSize(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] u64 GetFreeSpaceSize(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return GetFreeSpaceSize(ToU8String(path));
|
||||
} else {
|
||||
return GetFreeSpaceSize(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the total capacity of the filesystem at path.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns The total capacity in bytes of the filesystem at path. Returns 0 on failure.
|
||||
*/
|
||||
[[nodiscard]] u64 GetTotalSpaceSize(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] u64 GetTotalSpaceSize(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return GetTotalSpaceSize(ToU8String(path));
|
||||
} else {
|
||||
return GetTotalSpaceSize(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace Common::FS
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
// yuzu data directories
|
||||
|
||||
#define YUZU_DIR "yuzu"
|
||||
#define PORTABLE_DIR "user"
|
||||
|
||||
// Sub-directories contained within a yuzu data directory
|
||||
|
||||
#define CACHE_DIR "cache"
|
||||
#define CONFIG_DIR "config"
|
||||
#define DUMP_DIR "dump"
|
||||
#define KEYS_DIR "keys"
|
||||
#define LOAD_DIR "load"
|
||||
#define LOG_DIR "log"
|
||||
#define NAND_DIR "nand"
|
||||
#define SCREENSHOTS_DIR "screenshots"
|
||||
#define SDMC_DIR "sdmc"
|
||||
#define SHADER_DIR "shader"
|
||||
|
||||
// yuzu-specific files
|
||||
|
||||
#define LOG_FILE "yuzu_log.txt"
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
enum class FileAccessMode {
|
||||
/**
|
||||
* If the file at path exists, it opens the file for reading.
|
||||
* If the file at path does not exist, it fails to open the file.
|
||||
*/
|
||||
Read = 1 << 0,
|
||||
/**
|
||||
* If the file at path exists, the existing contents of the file are erased.
|
||||
* The empty file is then opened for writing.
|
||||
* If the file at path does not exist, it creates and opens a new empty file for writing.
|
||||
*/
|
||||
Write = 1 << 1,
|
||||
/**
|
||||
* If the file at path exists, it opens the file for reading and writing.
|
||||
* If the file at path does not exist, it fails to open the file.
|
||||
*/
|
||||
ReadWrite = Read | Write,
|
||||
/**
|
||||
* If the file at path exists, it opens the file for appending.
|
||||
* If the file at path does not exist, it creates and opens a new empty file for appending.
|
||||
*/
|
||||
Append = 1 << 2,
|
||||
/**
|
||||
* If the file at path exists, it opens the file for both reading and appending.
|
||||
* If the file at path does not exist, it creates and opens a new empty file for both
|
||||
* reading and appending.
|
||||
*/
|
||||
ReadAppend = Read | Append,
|
||||
};
|
||||
|
||||
enum class FileType {
|
||||
BinaryFile,
|
||||
TextFile,
|
||||
};
|
||||
|
||||
enum class FileShareFlag {
|
||||
ShareNone, // Provides exclusive access to the file.
|
||||
ShareReadOnly, // Provides read only shared access to the file.
|
||||
ShareWriteOnly, // Provides write only shared access to the file.
|
||||
ShareReadWrite, // Provides read and write shared access to the file.
|
||||
};
|
||||
|
||||
enum class DirEntryFilter {
|
||||
File = 1 << 0,
|
||||
Directory = 1 << 1,
|
||||
All = File | Directory,
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(DirEntryFilter);
|
||||
|
||||
/**
|
||||
* A callback function which takes in the path of a directory entry.
|
||||
*
|
||||
* @param path The path of a directory entry
|
||||
*
|
||||
* @returns A boolean value.
|
||||
* Return true to indicate whether the callback is successful, false otherwise.
|
||||
*/
|
||||
using DirEntryCallable = std::function<bool(const std::filesystem::path& path)>;
|
||||
|
||||
} // namespace Common::FS
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/fs/fs_util.h"
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
std::u8string ToU8String(std::string_view utf8_string) {
|
||||
return std::u8string{utf8_string.begin(), utf8_string.end()};
|
||||
}
|
||||
|
||||
} // namespace Common::FS
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
template <typename T>
|
||||
concept IsChar = std::same_as<T, char>;
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 encoded std::string or std::string_view to a std::u8string.
|
||||
*
|
||||
* @param utf8_string UTF-8 encoded string
|
||||
*
|
||||
* @returns UTF-8 encoded std::u8string.
|
||||
*/
|
||||
[[nodiscard]] std::u8string ToU8String(std::string_view utf8_string);
|
||||
|
||||
} // namespace Common::FS
|
||||
@@ -0,0 +1,432 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/fs_paths.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <shlobj.h> // Used in GetExeDirectory()
|
||||
#else
|
||||
#include <cstdlib> // Used in Get(Home/Data)Directory()
|
||||
#include <pwd.h> // Used in GetHomeDirectory()
|
||||
#include <sys/types.h> // Used in GetHomeDirectory()
|
||||
#include <unistd.h> // Used in GetDataDirectory()
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/param.h> // Used in GetBundleDirectory()
|
||||
|
||||
// CFURL contains __attribute__ directives that gcc does not know how to parse, so we need to just
|
||||
// ignore them if we're not using clang. The macro is only used to prevent linking against
|
||||
// functions that don't exist on older versions of macOS, and the worst case scenario is a linker
|
||||
// error, so this is perfectly safe, just inconvenient.
|
||||
#ifndef __clang__
|
||||
#define availability(...)
|
||||
#endif
|
||||
#include <CoreFoundation/CFBundle.h> // Used in GetBundleDirectory()
|
||||
#include <CoreFoundation/CFString.h> // Used in GetBundleDirectory()
|
||||
#include <CoreFoundation/CFURL.h> // Used in GetBundleDirectory()
|
||||
#ifdef availability
|
||||
#undef availability
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#ifdef _WIN32
|
||||
// This is the maximum number of UTF-16 code units permissible in Windows file paths
|
||||
#define MAX_PATH 260
|
||||
#else
|
||||
// This is the maximum number of UTF-8 code units permissible in all other OSes' file paths
|
||||
#define MAX_PATH 1024
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
/**
|
||||
* The PathManagerImpl is a singleton allowing to manage the mapping of
|
||||
* YuzuPath enums to real filesystem paths.
|
||||
* This class provides 2 functions: GetYuzuPathImpl and SetYuzuPathImpl.
|
||||
* These are used by GetYuzuPath and SetYuzuPath respectively to get or modify
|
||||
* the path mapped by the YuzuPath enum.
|
||||
*/
|
||||
class PathManagerImpl {
|
||||
public:
|
||||
static PathManagerImpl& GetInstance() {
|
||||
static PathManagerImpl path_manager_impl;
|
||||
|
||||
return path_manager_impl;
|
||||
}
|
||||
|
||||
PathManagerImpl(const PathManagerImpl&) = delete;
|
||||
PathManagerImpl& operator=(const PathManagerImpl&) = delete;
|
||||
|
||||
PathManagerImpl(PathManagerImpl&&) = delete;
|
||||
PathManagerImpl& operator=(PathManagerImpl&&) = delete;
|
||||
|
||||
[[nodiscard]] const fs::path& GetYuzuPathImpl(YuzuPath yuzu_path) {
|
||||
return yuzu_paths.at(yuzu_path);
|
||||
}
|
||||
|
||||
void SetYuzuPathImpl(YuzuPath yuzu_path, const fs::path& new_path) {
|
||||
yuzu_paths.insert_or_assign(yuzu_path, new_path);
|
||||
}
|
||||
|
||||
private:
|
||||
PathManagerImpl() {
|
||||
#ifdef _WIN32
|
||||
auto yuzu_path = GetExeDirectory() / PORTABLE_DIR;
|
||||
|
||||
if (!IsDir(yuzu_path)) {
|
||||
yuzu_path = GetAppDataRoamingDirectory() / YUZU_DIR;
|
||||
}
|
||||
|
||||
GenerateYuzuPath(YuzuPath::YuzuDir, yuzu_path);
|
||||
GenerateYuzuPath(YuzuPath::CacheDir, yuzu_path / CACHE_DIR);
|
||||
GenerateYuzuPath(YuzuPath::ConfigDir, yuzu_path / CONFIG_DIR);
|
||||
#else
|
||||
auto yuzu_path = GetCurrentDir() / PORTABLE_DIR;
|
||||
|
||||
if (Exists(yuzu_path) && IsDir(yuzu_path)) {
|
||||
GenerateYuzuPath(YuzuPath::YuzuDir, yuzu_path);
|
||||
GenerateYuzuPath(YuzuPath::CacheDir, yuzu_path / CACHE_DIR);
|
||||
GenerateYuzuPath(YuzuPath::ConfigDir, yuzu_path / CONFIG_DIR);
|
||||
} else {
|
||||
yuzu_path = GetDataDirectory("XDG_DATA_HOME") / YUZU_DIR;
|
||||
|
||||
GenerateYuzuPath(YuzuPath::YuzuDir, yuzu_path);
|
||||
GenerateYuzuPath(YuzuPath::CacheDir, GetDataDirectory("XDG_CACHE_HOME") / YUZU_DIR);
|
||||
GenerateYuzuPath(YuzuPath::ConfigDir, GetDataDirectory("XDG_CONFIG_HOME") / YUZU_DIR);
|
||||
}
|
||||
#endif
|
||||
|
||||
GenerateYuzuPath(YuzuPath::DumpDir, yuzu_path / DUMP_DIR);
|
||||
GenerateYuzuPath(YuzuPath::KeysDir, yuzu_path / KEYS_DIR);
|
||||
GenerateYuzuPath(YuzuPath::LoadDir, yuzu_path / LOAD_DIR);
|
||||
GenerateYuzuPath(YuzuPath::LogDir, yuzu_path / LOG_DIR);
|
||||
GenerateYuzuPath(YuzuPath::NANDDir, yuzu_path / NAND_DIR);
|
||||
GenerateYuzuPath(YuzuPath::ScreenshotsDir, yuzu_path / SCREENSHOTS_DIR);
|
||||
GenerateYuzuPath(YuzuPath::SDMCDir, yuzu_path / SDMC_DIR);
|
||||
GenerateYuzuPath(YuzuPath::ShaderDir, yuzu_path / SHADER_DIR);
|
||||
}
|
||||
|
||||
~PathManagerImpl() = default;
|
||||
|
||||
void GenerateYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) {
|
||||
void(FS::CreateDir(new_path));
|
||||
|
||||
SetYuzuPathImpl(yuzu_path, new_path);
|
||||
}
|
||||
|
||||
std::unordered_map<YuzuPath, fs::path> yuzu_paths;
|
||||
};
|
||||
|
||||
std::string PathToUTF8String(const fs::path& path) {
|
||||
const auto utf8_string = path.u8string();
|
||||
|
||||
return std::string{utf8_string.begin(), utf8_string.end()};
|
||||
}
|
||||
|
||||
bool ValidatePath(const fs::path& path) {
|
||||
if (path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (path.u16string().size() >= MAX_PATH) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is too long, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (path.u8string().size() >= MAX_PATH) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is too long, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fs::path ConcatPath(const fs::path& first, const fs::path& second) {
|
||||
const bool second_has_dir_sep = IsDirSeparator(second.u8string().front());
|
||||
|
||||
if (!second_has_dir_sep) {
|
||||
return (first / second).lexically_normal();
|
||||
}
|
||||
|
||||
fs::path concat_path = first;
|
||||
concat_path += second;
|
||||
|
||||
return concat_path.lexically_normal();
|
||||
}
|
||||
|
||||
fs::path ConcatPathSafe(const fs::path& base, const fs::path& offset) {
|
||||
const auto concatenated_path = ConcatPath(base, offset);
|
||||
|
||||
if (!IsPathSandboxed(base, concatenated_path)) {
|
||||
return base;
|
||||
}
|
||||
|
||||
return concatenated_path;
|
||||
}
|
||||
|
||||
bool IsPathSandboxed(const fs::path& base, const fs::path& path) {
|
||||
const auto base_string = RemoveTrailingSeparators(base.lexically_normal()).u8string();
|
||||
const auto path_string = RemoveTrailingSeparators(path.lexically_normal()).u8string();
|
||||
|
||||
if (path_string.size() < base_string.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return base_string.compare(0, base_string.size(), path_string, 0, base_string.size()) == 0;
|
||||
}
|
||||
|
||||
bool IsDirSeparator(char character) {
|
||||
return character == '/' || character == '\\';
|
||||
}
|
||||
|
||||
bool IsDirSeparator(char8_t character) {
|
||||
return character == u8'/' || character == u8'\\';
|
||||
}
|
||||
|
||||
fs::path RemoveTrailingSeparators(const fs::path& path) {
|
||||
if (path.empty()) {
|
||||
return path;
|
||||
}
|
||||
|
||||
auto string_path = path.u8string();
|
||||
|
||||
while (IsDirSeparator(string_path.back())) {
|
||||
string_path.pop_back();
|
||||
}
|
||||
|
||||
return fs::path{string_path};
|
||||
}
|
||||
|
||||
const fs::path& GetYuzuPath(YuzuPath yuzu_path) {
|
||||
return PathManagerImpl::GetInstance().GetYuzuPathImpl(yuzu_path);
|
||||
}
|
||||
|
||||
std::string GetYuzuPathString(YuzuPath yuzu_path) {
|
||||
return PathToUTF8String(GetYuzuPath(yuzu_path));
|
||||
}
|
||||
|
||||
void SetYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) {
|
||||
if (!FS::IsDir(new_path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Filesystem object at new_path={} is not a directory",
|
||||
PathToUTF8String(new_path));
|
||||
return;
|
||||
}
|
||||
|
||||
PathManagerImpl::GetInstance().SetYuzuPathImpl(yuzu_path, new_path);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
fs::path GetExeDirectory() {
|
||||
wchar_t exe_path[MAX_PATH];
|
||||
|
||||
GetModuleFileNameW(nullptr, exe_path, MAX_PATH);
|
||||
|
||||
if (!exe_path) {
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Failed to get the path to the executable of the current process");
|
||||
}
|
||||
|
||||
return fs::path{exe_path}.parent_path();
|
||||
}
|
||||
|
||||
fs::path GetAppDataRoamingDirectory() {
|
||||
PWSTR appdata_roaming_path = nullptr;
|
||||
|
||||
SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &appdata_roaming_path);
|
||||
|
||||
auto fs_appdata_roaming_path = fs::path{appdata_roaming_path};
|
||||
|
||||
CoTaskMemFree(appdata_roaming_path);
|
||||
|
||||
if (fs_appdata_roaming_path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to get the path to the %APPDATA% directory");
|
||||
}
|
||||
|
||||
return fs_appdata_roaming_path;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
fs::path GetHomeDirectory() {
|
||||
const char* home_env_var = getenv("HOME");
|
||||
|
||||
if (home_env_var) {
|
||||
return fs::path{home_env_var};
|
||||
}
|
||||
|
||||
LOG_INFO(Common_Filesystem,
|
||||
"$HOME is not defined in the environment variables, "
|
||||
"attempting to query passwd to get the home path of the current user");
|
||||
|
||||
const auto* pw = getpwuid(getuid());
|
||||
|
||||
if (!pw) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to get the home path of the current user");
|
||||
return {};
|
||||
}
|
||||
|
||||
return fs::path{pw->pw_dir};
|
||||
}
|
||||
|
||||
fs::path GetDataDirectory(const std::string& env_name) {
|
||||
const char* data_env_var = getenv(env_name.c_str());
|
||||
|
||||
if (data_env_var) {
|
||||
return fs::path{data_env_var};
|
||||
}
|
||||
|
||||
if (env_name == "XDG_DATA_HOME") {
|
||||
return GetHomeDirectory() / ".local/share";
|
||||
} else if (env_name == "XDG_CACHE_HOME") {
|
||||
return GetHomeDirectory() / ".cache";
|
||||
} else if (env_name == "XDG_CONFIG_HOME") {
|
||||
return GetHomeDirectory() / ".config";
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
fs::path GetBundleDirectory() {
|
||||
char app_bundle_path[MAXPATHLEN];
|
||||
|
||||
// Get the main bundle for the app
|
||||
CFURLRef bundle_ref = CFBundleCopyBundleURL(CFBundleGetMainBundle());
|
||||
CFStringRef bundle_path = CFURLCopyFileSystemPath(bundle_ref, kCFURLPOSIXPathStyle);
|
||||
|
||||
CFStringGetFileSystemRepresentation(bundle_path, app_bundle_path, sizeof(app_bundle_path));
|
||||
|
||||
CFRelease(bundle_ref);
|
||||
CFRelease(bundle_path);
|
||||
|
||||
return fs::path{app_bundle_path};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// vvvvvvvvvv Deprecated vvvvvvvvvv //
|
||||
|
||||
std::string_view RemoveTrailingSlash(std::string_view path) {
|
||||
if (path.empty()) {
|
||||
return path;
|
||||
}
|
||||
|
||||
if (path.back() == '\\' || path.back() == '/') {
|
||||
path.remove_suffix(1);
|
||||
return path;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
std::vector<std::string> SplitPathComponents(std::string_view filename) {
|
||||
std::string copy(filename);
|
||||
std::replace(copy.begin(), copy.end(), '\\', '/');
|
||||
std::vector<std::string> out;
|
||||
|
||||
std::stringstream stream(copy);
|
||||
std::string item;
|
||||
while (std::getline(stream, item, '/')) {
|
||||
out.push_back(std::move(item));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) {
|
||||
std::string path(path_);
|
||||
char type1 = directory_separator == DirectorySeparator::BackwardSlash ? '/' : '\\';
|
||||
char type2 = directory_separator == DirectorySeparator::BackwardSlash ? '\\' : '/';
|
||||
|
||||
if (directory_separator == DirectorySeparator::PlatformDefault) {
|
||||
#ifdef _WIN32
|
||||
type1 = '/';
|
||||
type2 = '\\';
|
||||
#endif
|
||||
}
|
||||
|
||||
std::replace(path.begin(), path.end(), type1, type2);
|
||||
|
||||
auto start = path.begin();
|
||||
#ifdef _WIN32
|
||||
// allow network paths which start with a double backslash (e.g. \\server\share)
|
||||
if (start != path.end())
|
||||
++start;
|
||||
#endif
|
||||
path.erase(std::unique(start, path.end(),
|
||||
[type2](char c1, char c2) { return c1 == type2 && c2 == type2; }),
|
||||
path.end());
|
||||
return std::string(RemoveTrailingSlash(path));
|
||||
}
|
||||
|
||||
std::string_view GetParentPath(std::string_view path) {
|
||||
const auto name_bck_index = path.rfind('\\');
|
||||
const auto name_fwd_index = path.rfind('/');
|
||||
std::size_t name_index;
|
||||
|
||||
if (name_bck_index == std::string_view::npos || name_fwd_index == std::string_view::npos) {
|
||||
name_index = std::min(name_bck_index, name_fwd_index);
|
||||
} else {
|
||||
name_index = std::max(name_bck_index, name_fwd_index);
|
||||
}
|
||||
|
||||
return path.substr(0, name_index);
|
||||
}
|
||||
|
||||
std::string_view GetPathWithoutTop(std::string_view path) {
|
||||
if (path.empty()) {
|
||||
return path;
|
||||
}
|
||||
|
||||
while (path[0] == '\\' || path[0] == '/') {
|
||||
path.remove_prefix(1);
|
||||
if (path.empty()) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
const auto name_bck_index = path.find('\\');
|
||||
const auto name_fwd_index = path.find('/');
|
||||
return path.substr(std::min(name_bck_index, name_fwd_index) + 1);
|
||||
}
|
||||
|
||||
std::string_view GetFilename(std::string_view path) {
|
||||
const auto name_index = path.find_last_of("\\/");
|
||||
|
||||
if (name_index == std::string_view::npos) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return path.substr(name_index + 1);
|
||||
}
|
||||
|
||||
std::string_view GetExtensionFromFilename(std::string_view name) {
|
||||
const std::size_t index = name.rfind('.');
|
||||
|
||||
if (index == std::string_view::npos) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return name.substr(index + 1);
|
||||
}
|
||||
|
||||
} // namespace Common::FS
|
||||
@@ -0,0 +1,309 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
#include "common/fs/fs_util.h"
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
enum class YuzuPath {
|
||||
YuzuDir, // Where yuzu stores its data.
|
||||
CacheDir, // Where cached filesystem data is stored.
|
||||
ConfigDir, // Where config files are stored.
|
||||
DumpDir, // Where dumped data is stored.
|
||||
KeysDir, // Where key files are stored.
|
||||
LoadDir, // Where cheat/mod files are stored.
|
||||
LogDir, // Where log files are stored.
|
||||
NANDDir, // Where the emulated NAND is stored.
|
||||
ScreenshotsDir, // Where yuzu screenshots are stored.
|
||||
SDMCDir, // Where the emulated SDMC is stored.
|
||||
ShaderDir, // Where shaders are stored.
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a filesystem path to a UTF-8 encoded std::string.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns UTF-8 encoded std::string.
|
||||
*/
|
||||
[[nodiscard]] std::string PathToUTF8String(const std::filesystem::path& path);
|
||||
|
||||
/**
|
||||
* Validates a given path.
|
||||
*
|
||||
* A given path is valid if it meets these conditions:
|
||||
* - The path is not empty
|
||||
* - The path is not too long
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if the path is valid, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool ValidatePath(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool ValidatePath(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return ValidatePath(ToU8String(path));
|
||||
} else {
|
||||
return ValidatePath(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Concatenates two filesystem paths together.
|
||||
*
|
||||
* This is needed since the following occurs when using std::filesystem::path's operator/:
|
||||
* first: "/first/path"
|
||||
* second: "/second/path" (Note that the second path has a directory separator in the front)
|
||||
* first / second yields "/second/path" when the desired result is first/path/second/path
|
||||
*
|
||||
* @param first First filesystem path
|
||||
* @param second Second filesystem path
|
||||
*
|
||||
* @returns A concatenated filesystem path.
|
||||
*/
|
||||
[[nodiscard]] std::filesystem::path ConcatPath(const std::filesystem::path& first,
|
||||
const std::filesystem::path& second);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path1, typename Path2>
|
||||
[[nodiscard]] std::filesystem::path ConcatPath(const Path1& first, const Path2& second) {
|
||||
using ValueType1 = typename Path1::value_type;
|
||||
using ValueType2 = typename Path2::value_type;
|
||||
if constexpr (IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||
return ConcatPath(ToU8String(first), ToU8String(second));
|
||||
} else if constexpr (IsChar<ValueType1> && !IsChar<ValueType2>) {
|
||||
return ConcatPath(ToU8String(first), second);
|
||||
} else if constexpr (!IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||
return ConcatPath(first, ToU8String(second));
|
||||
} else {
|
||||
return ConcatPath(std::filesystem::path{first}, std::filesystem::path{second});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Safe variant of ConcatPath that takes in a base path and an offset path from the given base path.
|
||||
*
|
||||
* If ConcatPath(base, offset) resolves to a path that is sandboxed within the base path,
|
||||
* this will return the concatenated path. Otherwise this will return the base path.
|
||||
*
|
||||
* @param base Base filesystem path
|
||||
* @param offset Offset filesystem path
|
||||
*
|
||||
* @returns A concatenated filesystem path if it is within the base path,
|
||||
* returns the base path otherwise.
|
||||
*/
|
||||
[[nodiscard]] std::filesystem::path ConcatPathSafe(const std::filesystem::path& base,
|
||||
const std::filesystem::path& offset);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path1, typename Path2>
|
||||
[[nodiscard]] std::filesystem::path ConcatPathSafe(const Path1& base, const Path2& offset) {
|
||||
using ValueType1 = typename Path1::value_type;
|
||||
using ValueType2 = typename Path2::value_type;
|
||||
if constexpr (IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||
return ConcatPathSafe(ToU8String(base), ToU8String(offset));
|
||||
} else if constexpr (IsChar<ValueType1> && !IsChar<ValueType2>) {
|
||||
return ConcatPathSafe(ToU8String(base), offset);
|
||||
} else if constexpr (!IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||
return ConcatPathSafe(base, ToU8String(offset));
|
||||
} else {
|
||||
return ConcatPathSafe(std::filesystem::path{base}, std::filesystem::path{offset});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Checks whether a given path is sandboxed within a given base path.
|
||||
*
|
||||
* @param base Base filesystem path
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if the given path is sandboxed within the given base path, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool IsPathSandboxed(const std::filesystem::path& base,
|
||||
const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path1, typename Path2>
|
||||
[[nodiscard]] bool IsPathSandboxed(const Path1& base, const Path2& path) {
|
||||
using ValueType1 = typename Path1::value_type;
|
||||
using ValueType2 = typename Path2::value_type;
|
||||
if constexpr (IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||
return IsPathSandboxed(ToU8String(base), ToU8String(path));
|
||||
} else if constexpr (IsChar<ValueType1> && !IsChar<ValueType2>) {
|
||||
return IsPathSandboxed(ToU8String(base), path);
|
||||
} else if constexpr (!IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||
return IsPathSandboxed(base, ToU8String(path));
|
||||
} else {
|
||||
return IsPathSandboxed(std::filesystem::path{base}, std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Checks if a character is a directory separator (either a forward slash or backslash).
|
||||
*
|
||||
* @param character Character
|
||||
*
|
||||
* @returns True if the character is a directory separator, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool IsDirSeparator(char character);
|
||||
|
||||
/**
|
||||
* Checks if a character is a directory separator (either a forward slash or backslash).
|
||||
*
|
||||
* @param character Character
|
||||
*
|
||||
* @returns True if the character is a directory separator, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool IsDirSeparator(char8_t character);
|
||||
|
||||
/**
|
||||
* Removes any trailing directory separators if they exist in the given path.
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns The filesystem path without any trailing directory separators.
|
||||
*/
|
||||
[[nodiscard]] std::filesystem::path RemoveTrailingSeparators(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] std::filesystem::path RemoveTrailingSeparators(const Path& path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
return RemoveTrailingSeparators(ToU8String(path));
|
||||
} else {
|
||||
return RemoveTrailingSeparators(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the filesystem path associated with the YuzuPath enum.
|
||||
*
|
||||
* @param yuzu_path YuzuPath enum
|
||||
*
|
||||
* @returns The filesystem path associated with the YuzuPath enum.
|
||||
*/
|
||||
[[nodiscard]] const std::filesystem::path& GetYuzuPath(YuzuPath yuzu_path);
|
||||
|
||||
/**
|
||||
* Gets the filesystem path associated with the YuzuPath enum as a UTF-8 encoded std::string.
|
||||
*
|
||||
* @param yuzu_path YuzuPath enum
|
||||
*
|
||||
* @returns The filesystem path associated with the YuzuPath enum as a UTF-8 encoded std::string.
|
||||
*/
|
||||
[[nodiscard]] std::string GetYuzuPathString(YuzuPath yuzu_path);
|
||||
|
||||
/**
|
||||
* Sets a new filesystem path associated with the YuzuPath enum.
|
||||
* If the filesystem object at new_path is not a directory, this function will not do anything.
|
||||
*
|
||||
* @param yuzu_path YuzuPath enum
|
||||
* @param new_path New filesystem path
|
||||
*/
|
||||
void SetYuzuPath(YuzuPath yuzu_path, const std::filesystem::path& new_path);
|
||||
|
||||
#ifdef _WIN32
|
||||
template <typename Path>
|
||||
[[nodiscard]] void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) {
|
||||
if constexpr (IsChar<typename Path::value_type>) {
|
||||
SetYuzuPath(yuzu_path, ToU8String(new_path));
|
||||
} else {
|
||||
SetYuzuPath(yuzu_path, std::filesystem::path{new_path});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/**
|
||||
* Gets the path of the directory containing the executable of the current process.
|
||||
*
|
||||
* @returns The path of the directory containing the executable of the current process.
|
||||
*/
|
||||
[[nodiscard]] std::filesystem::path GetExeDirectory();
|
||||
|
||||
/**
|
||||
* Gets the path of the current user's %APPDATA% directory (%USERPROFILE%/AppData/Roaming).
|
||||
*
|
||||
* @returns The path of the current user's %APPDATA% directory.
|
||||
*/
|
||||
[[nodiscard]] std::filesystem::path GetAppDataRoamingDirectory();
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
* Gets the path of the directory specified by the #HOME environment variable.
|
||||
* If $HOME is not defined, it will attempt to query the user database in passwd instead.
|
||||
*
|
||||
* @returns The path of the current user's home directory.
|
||||
*/
|
||||
[[nodiscard]] std::filesystem::path GetHomeDirectory();
|
||||
|
||||
/**
|
||||
* Gets the relevant paths for yuzu to store its data based on the given XDG environment variable.
|
||||
* See https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
* Defaults to $HOME/.local/share for main application data,
|
||||
* $HOME/.cache for cached data, and $HOME/.config for configuration files.
|
||||
*
|
||||
* @param env_name XDG environment variable name
|
||||
*
|
||||
* @returns The path where yuzu should store its data.
|
||||
*/
|
||||
[[nodiscard]] std::filesystem::path GetDataDirectory(const std::string& env_name);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
[[nodiscard]] std::filesystem::path GetBundleDirectory();
|
||||
|
||||
#endif
|
||||
|
||||
// vvvvvvvvvv Deprecated vvvvvvvvvv //
|
||||
|
||||
// Removes the final '/' or '\' if one exists
|
||||
[[nodiscard]] std::string_view RemoveTrailingSlash(std::string_view path);
|
||||
|
||||
enum class DirectorySeparator {
|
||||
ForwardSlash,
|
||||
BackwardSlash,
|
||||
PlatformDefault,
|
||||
};
|
||||
|
||||
// Splits the path on '/' or '\' and put the components into a vector
|
||||
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
|
||||
[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);
|
||||
|
||||
// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
|
||||
// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
|
||||
[[nodiscard]] std::string SanitizePath(
|
||||
std::string_view path,
|
||||
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
|
||||
|
||||
// Gets all of the text up to the last '/' or '\' in the path.
|
||||
[[nodiscard]] std::string_view GetParentPath(std::string_view path);
|
||||
|
||||
// Gets all of the text after the first '/' or '\' in the path.
|
||||
[[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path);
|
||||
|
||||
// Gets the filename of the path
|
||||
[[nodiscard]] std::string_view GetFilename(std::string_view path);
|
||||
|
||||
// Gets the extension of the filename
|
||||
[[nodiscard]] std::string_view GetExtensionFromFilename(std::string_view name);
|
||||
|
||||
} // namespace Common::FS
|
||||