Compare commits
26 Commits
macros
...
gl-present
Author | SHA1 | Date | |
---|---|---|---|
208e1a0aaf | |||
1247bff174 | |||
6cbdc73f53 | |||
81ee7ad893 | |||
2ce0a9e899 | |||
015e42be05 | |||
57696b2c11 | |||
c8c2beaeff | |||
6069fac76d | |||
7bacb78ce3 | |||
0165012ba4 | |||
96aa1b3a08 | |||
b2c740ee0e | |||
bc352e8168 | |||
4f00eb20db | |||
8b6a9b0dd8 | |||
62409f8139 | |||
0df72f3873 | |||
f2ee9baec7 | |||
8e2037b3ff | |||
c6bcbc02de | |||
36db566428 | |||
9b147d3f9c | |||
7dd9174d31 | |||
5a7f615da1 | |||
811303ea54 |
@ -121,7 +121,7 @@ function(download_moltenvk)
|
|||||||
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
|
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
|
||||||
if (NOT EXISTS ${MOLTENVK_DIR})
|
if (NOT EXISTS ${MOLTENVK_DIR})
|
||||||
if (NOT EXISTS ${MOLTENVK_TAR})
|
if (NOT EXISTS ${MOLTENVK_TAR})
|
||||||
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/latest/download/MoltenVK-all.tar
|
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/download/v1.2.7-rc1/MoltenVK-all.tar
|
||||||
${MOLTENVK_TAR} SHOW_PROGRESS)
|
${MOLTENVK_TAR} SHOW_PROGRESS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
32
dist/apple/Info.plist.in
vendored
32
dist/apple/Info.plist.in
vendored
@ -26,6 +26,38 @@
|
|||||||
<!-- Fixed -->
|
<!-- Fixed -->
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.games</string>
|
<string>public.app-category.games</string>
|
||||||
|
<key>CFBundleDocumentTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeExtensions</key>
|
||||||
|
<array>
|
||||||
|
<string>3ds</string>
|
||||||
|
<string>3dsx</string>
|
||||||
|
<string>cci</string>
|
||||||
|
<string>cxi</string>
|
||||||
|
<string>cia</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleTypeName</key>
|
||||||
|
<string>Nintendo 3DS File</string>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Viewer</string>
|
||||||
|
<key>LSHandlerRank</key>
|
||||||
|
<string>Default</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeExtensions</key>
|
||||||
|
<array>
|
||||||
|
<string>elf</string>
|
||||||
|
<string>axf</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleTypeName</key>
|
||||||
|
<string>Unix Executable and Linkable Format</string>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Viewer</string>
|
||||||
|
<key>LSHandlerRank</key>
|
||||||
|
<string>Alternate</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>This app requires camera access to emulate the 3DS's cameras.</string>
|
<string>This app requires camera access to emulate the 3DS's cameras.</string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
|
13
dist/qt_themes/default/style.qss
vendored
13
dist/qt_themes/default/style.qss
vendored
@ -12,18 +12,19 @@ QPushButton#GraphicsAPIStatusBarButton:hover {
|
|||||||
border: 1px solid #76797C;
|
border: 1px solid #76797C;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton#3DOptionStatusBarButton {
|
QPushButton#TogglableStatusBarButton {
|
||||||
color: #A5A5A5;
|
color: #959595;
|
||||||
font-weight: bold;
|
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
padding: 0px 3px 0px 3px;
|
padding: 0px 3px 0px 3px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
min-width: 60px;
|
|
||||||
min-height: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton#3DOptionStatusBarButton:hover {
|
QPushButton#TogglableStatusBarButton:checked {
|
||||||
|
color: #00FF00;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#TogglableStatusBarButton:hover {
|
||||||
border: 1px solid #76797C;
|
border: 1px solid #76797C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
dist/qt_themes/qdarkstyle/style.qss
vendored
33
dist/qt_themes/qdarkstyle/style.qss
vendored
@ -1,19 +1,3 @@
|
|||||||
QPushButton#TogglableStatusBarButton {
|
|
||||||
color: #959595;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 0px 3px 0px 3px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton#TogglableStatusBarButton:checked {
|
|
||||||
color: palette(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton#TogglableStatusBarButton:hover {
|
|
||||||
border: 1px solid #76797C;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton#GraphicsAPIStatusBarButton {
|
QPushButton#GraphicsAPIStatusBarButton {
|
||||||
color: #656565;
|
color: #656565;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
@ -26,6 +10,23 @@ QPushButton#GraphicsAPIStatusBarButton:hover {
|
|||||||
border: 1px solid #76797C;
|
border: 1px solid #76797C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton#TogglableStatusBarButton {
|
||||||
|
min-width: 0px;
|
||||||
|
color: #656565;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 0px 3px 0px 3px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#TogglableStatusBarButton:checked {
|
||||||
|
color: #00FF00;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#TogglableStatusBarButton:hover {
|
||||||
|
border: 1px solid #76797C;
|
||||||
|
}
|
||||||
|
|
||||||
QToolTip {
|
QToolTip {
|
||||||
border: 1px solid #76797C;
|
border: 1px solid #76797C;
|
||||||
background-color: #5A7566;
|
background-color: #5A7566;
|
||||||
|
3
externals/CMakeLists.txt
vendored
3
externals/CMakeLists.txt
vendored
@ -395,9 +395,6 @@ if(USE_SYSTEM_VULKAN_HEADERS)
|
|||||||
else()
|
else()
|
||||||
target_include_directories(vulkan-headers SYSTEM INTERFACE ./vulkan-headers/include)
|
target_include_directories(vulkan-headers SYSTEM INTERFACE ./vulkan-headers/include)
|
||||||
endif()
|
endif()
|
||||||
if (APPLE)
|
|
||||||
target_include_directories(vulkan-headers SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# adrenotools
|
# adrenotools
|
||||||
if (ANDROID AND "arm64" IN_LIST ARCHITECTURE)
|
if (ANDROID AND "arm64" IN_LIST ARCHITECTURE)
|
||||||
|
1071
externals/moltenvk/mvk_config.h
vendored
1071
externals/moltenvk/mvk_config.h
vendored
File diff suppressed because it is too large
Load Diff
2
externals/vulkan-headers
vendored
2
externals/vulkan-headers
vendored
Submodule externals/vulkan-headers updated: 85c2334e92...217e93c664
@ -7,25 +7,13 @@ package org.citra.citra_emu.features.cheats.model
|
|||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
class CheatEngine(titleId: Long) {
|
object CheatEngine {
|
||||||
@Keep
|
external fun loadCheatFile(titleId: Long)
|
||||||
private val mPointer: Long
|
external fun saveCheatFile(titleId: Long)
|
||||||
|
|
||||||
init {
|
|
||||||
mPointer = initialize(titleId)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected external fun finalize()
|
|
||||||
|
|
||||||
external fun getCheats(): Array<Cheat>
|
external fun getCheats(): Array<Cheat>
|
||||||
|
|
||||||
external fun addCheat(cheat: Cheat?)
|
external fun addCheat(cheat: Cheat?)
|
||||||
external fun removeCheat(index: Int)
|
external fun removeCheat(index: Int)
|
||||||
external fun updateCheat(index: Int, newCheat: Cheat?)
|
external fun updateCheat(index: Int, newCheat: Cheat?)
|
||||||
external fun saveCheatFile()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
|
||||||
private external fun initialize(titleId: Long): Long
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -47,18 +47,19 @@ class CheatsViewModel : ViewModel() {
|
|||||||
val detailsViewFocusChange get() = _detailsViewFocusChange.asStateFlow()
|
val detailsViewFocusChange get() = _detailsViewFocusChange.asStateFlow()
|
||||||
private val _detailsViewFocusChange = MutableStateFlow(false)
|
private val _detailsViewFocusChange = MutableStateFlow(false)
|
||||||
|
|
||||||
private var cheatEngine: CheatEngine? = null
|
private var titleId: Long = 0
|
||||||
lateinit var cheats: Array<Cheat>
|
lateinit var cheats: Array<Cheat>
|
||||||
private var cheatsNeedSaving = false
|
private var cheatsNeedSaving = false
|
||||||
private var selectedCheatPosition = -1
|
private var selectedCheatPosition = -1
|
||||||
|
|
||||||
fun initialize(titleId: Long) {
|
fun initialize(titleId_: Long) {
|
||||||
cheatEngine = CheatEngine(titleId)
|
titleId = titleId_;
|
||||||
load()
|
load()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun load() {
|
private fun load() {
|
||||||
cheats = cheatEngine!!.getCheats()
|
CheatEngine.loadCheatFile(titleId)
|
||||||
|
cheats = CheatEngine.getCheats()
|
||||||
for (i in cheats.indices) {
|
for (i in cheats.indices) {
|
||||||
cheats[i].setEnabledChangedCallback {
|
cheats[i].setEnabledChangedCallback {
|
||||||
cheatsNeedSaving = true
|
cheatsNeedSaving = true
|
||||||
@ -69,7 +70,7 @@ class CheatsViewModel : ViewModel() {
|
|||||||
|
|
||||||
fun saveIfNeeded() {
|
fun saveIfNeeded() {
|
||||||
if (cheatsNeedSaving) {
|
if (cheatsNeedSaving) {
|
||||||
cheatEngine!!.saveCheatFile()
|
CheatEngine.saveCheatFile(titleId)
|
||||||
cheatsNeedSaving = false
|
cheatsNeedSaving = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,7 +108,7 @@ class CheatsViewModel : ViewModel() {
|
|||||||
_isAdding.value = false
|
_isAdding.value = false
|
||||||
_isEditing.value = false
|
_isEditing.value = false
|
||||||
val position = cheats.size
|
val position = cheats.size
|
||||||
cheatEngine!!.addCheat(cheat)
|
CheatEngine.addCheat(cheat)
|
||||||
cheatsNeedSaving = true
|
cheatsNeedSaving = true
|
||||||
load()
|
load()
|
||||||
notifyCheatAdded(position)
|
notifyCheatAdded(position)
|
||||||
@ -123,7 +124,7 @@ class CheatsViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun updateSelectedCheat(newCheat: Cheat?) {
|
fun updateSelectedCheat(newCheat: Cheat?) {
|
||||||
cheatEngine!!.updateCheat(selectedCheatPosition, newCheat)
|
CheatEngine.updateCheat(selectedCheatPosition, newCheat)
|
||||||
cheatsNeedSaving = true
|
cheatsNeedSaving = true
|
||||||
load()
|
load()
|
||||||
notifyCheatUpdated(selectedCheatPosition)
|
notifyCheatUpdated(selectedCheatPosition)
|
||||||
@ -141,7 +142,7 @@ class CheatsViewModel : ViewModel() {
|
|||||||
fun deleteSelectedCheat() {
|
fun deleteSelectedCheat() {
|
||||||
val position = selectedCheatPosition
|
val position = selectedCheatPosition
|
||||||
setSelectedCheat(null, -1)
|
setSelectedCheat(null, -1)
|
||||||
cheatEngine!!.removeCheat(position)
|
CheatEngine.removeCheat(position)
|
||||||
cheatsNeedSaving = true
|
cheatsNeedSaving = true
|
||||||
load()
|
load()
|
||||||
notifyCheatDeleted(position)
|
notifyCheatDeleted(position)
|
||||||
|
@ -15,24 +15,24 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static Cheats::CheatEngine* GetPointer(JNIEnv* env, jobject obj) {
|
static Cheats::CheatEngine& GetEngine() {
|
||||||
return reinterpret_cast<Cheats::CheatEngine*>(
|
Core::System& system{Core::System::GetInstance()};
|
||||||
env->GetLongField(obj, IDCache::GetCheatEnginePointer()));
|
return system.CheatEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_initialize(
|
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_loadCheatFile(
|
||||||
JNIEnv* env, jclass, jlong title_id) {
|
JNIEnv* env, jclass, jlong title_id) {
|
||||||
return reinterpret_cast<jlong>(new Cheats::CheatEngine(title_id, Core::System::GetInstance()));
|
GetEngine().LoadCheatFile(title_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_saveCheatFile(
|
||||||
Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_finalize(JNIEnv* env, jobject obj) {
|
JNIEnv* env, jclass, jlong title_id) {
|
||||||
delete GetPointer(env, obj);
|
GetEngine().SaveCheatFile(title_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jobjectArray JNICALL
|
JNIEXPORT jobjectArray JNICALL
|
||||||
Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_getCheats(JNIEnv* env, jobject obj) {
|
Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_getCheats(JNIEnv* env, jclass) {
|
||||||
auto cheats = GetPointer(env, obj)->GetCheats();
|
auto cheats = GetEngine().GetCheats();
|
||||||
|
|
||||||
const jobjectArray array =
|
const jobjectArray array =
|
||||||
env->NewObjectArray(static_cast<jsize>(cheats.size()), IDCache::GetCheatClass(), nullptr);
|
env->NewObjectArray(static_cast<jsize>(cheats.size()), IDCache::GetCheatClass(), nullptr);
|
||||||
@ -45,22 +45,19 @@ Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_getCheats(JNIEnv* en
|
|||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_addCheat(
|
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_addCheat(
|
||||||
JNIEnv* env, jobject obj, jobject j_cheat) {
|
JNIEnv* env, jclass, jobject j_cheat) {
|
||||||
GetPointer(env, obj)->AddCheat(*CheatFromJava(env, j_cheat));
|
auto cheat = *CheatFromJava(env, j_cheat);
|
||||||
|
GetEngine().AddCheat(std::move(cheat));
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_removeCheat(
|
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_removeCheat(
|
||||||
JNIEnv* env, jobject obj, jint index) {
|
JNIEnv* env, jclass, jint index) {
|
||||||
GetPointer(env, obj)->RemoveCheat(index);
|
GetEngine().RemoveCheat(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_updateCheat(
|
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_updateCheat(
|
||||||
JNIEnv* env, jobject obj, jint index, jobject j_new_cheat) {
|
JNIEnv* env, jclass, jint index, jobject j_new_cheat) {
|
||||||
GetPointer(env, obj)->UpdateCheat(index, *CheatFromJava(env, j_new_cheat));
|
auto cheat = *CheatFromJava(env, j_new_cheat);
|
||||||
}
|
GetEngine().UpdateCheat(index, std::move(cheat));
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_saveCheatFile(
|
|
||||||
JNIEnv* env, jobject obj) {
|
|
||||||
GetPointer(env, obj)->SaveCheatFile();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,6 +146,7 @@ void Config::ReadValues() {
|
|||||||
ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
|
ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
|
||||||
ReadSetting("Renderer", Settings::values.use_vsync_new);
|
ReadSetting("Renderer", Settings::values.use_vsync_new);
|
||||||
ReadSetting("Renderer", Settings::values.texture_filter);
|
ReadSetting("Renderer", Settings::values.texture_filter);
|
||||||
|
ReadSetting("Renderer", Settings::values.texture_sampling);
|
||||||
|
|
||||||
// Work around to map Android setting for enabling the frame limiter to the format Citra expects
|
// Work around to map Android setting for enabling the frame limiter to the format Citra expects
|
||||||
if (sdl2_config->GetBoolean("Renderer", "use_frame_limit", true)) {
|
if (sdl2_config->GetBoolean("Renderer", "use_frame_limit", true)) {
|
||||||
@ -214,6 +215,8 @@ void Config::ReadValues() {
|
|||||||
} catch (...) {
|
} catch (...) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ReadSetting("System", Settings::values.init_ticks_type);
|
||||||
|
ReadSetting("System", Settings::values.init_ticks_override);
|
||||||
ReadSetting("System", Settings::values.plugin_loader_enabled);
|
ReadSetting("System", Settings::values.plugin_loader_enabled);
|
||||||
ReadSetting("System", Settings::values.allow_plugin_loader);
|
ReadSetting("System", Settings::values.allow_plugin_loader);
|
||||||
|
|
||||||
|
@ -288,6 +288,14 @@ init_clock =
|
|||||||
# Note: 3DS can only handle times later then Jan 1 2000
|
# Note: 3DS can only handle times later then Jan 1 2000
|
||||||
init_time =
|
init_time =
|
||||||
|
|
||||||
|
# The system ticks count to use when citra starts
|
||||||
|
# 0: Random (default), 1: Fixed
|
||||||
|
init_ticks_type =
|
||||||
|
|
||||||
|
# Tick count to use when init_ticks_type is set to Fixed.
|
||||||
|
# Defaults to 0.
|
||||||
|
init_ticks_override =
|
||||||
|
|
||||||
# Plugin loader state, if enabled plugins will be loaded from the SD card.
|
# Plugin loader state, if enabled plugins will be loaded from the SD card.
|
||||||
# You can also set if homebrew apps are allowed to enable the plugin loader
|
# You can also set if homebrew apps are allowed to enable the plugin loader
|
||||||
plugin_loader =
|
plugin_loader =
|
||||||
|
@ -81,8 +81,8 @@ jstring Java_org_citra_citra_1emu_model_GameInfo_getTitle(JNIEnv* env, jobject o
|
|||||||
Loader::SMDH::TitleLanguage language = Loader::SMDH::TitleLanguage::English;
|
Loader::SMDH::TitleLanguage language = Loader::SMDH::TitleLanguage::English;
|
||||||
|
|
||||||
// Get the title from SMDH in UTF-16 format
|
// Get the title from SMDH in UTF-16 format
|
||||||
std::u16string title{
|
std::u16string title{reinterpret_cast<char16_t*>(
|
||||||
reinterpret_cast<char16_t*>(smdh->titles[static_cast<size_t>(language)].long_title.data())};
|
smdh->titles[static_cast<std::size_t>(language)].long_title.data())};
|
||||||
|
|
||||||
return ToJString(env, Common::UTF16ToUTF8(title).data());
|
return ToJString(env, Common::UTF16ToUTF8(title).data());
|
||||||
}
|
}
|
||||||
@ -93,8 +93,8 @@ jstring Java_org_citra_citra_1emu_model_GameInfo_getCompany(JNIEnv* env, jobject
|
|||||||
|
|
||||||
// Get the Publisher's name from SMDH in UTF-16 format
|
// Get the Publisher's name from SMDH in UTF-16 format
|
||||||
char16_t* publisher;
|
char16_t* publisher;
|
||||||
publisher =
|
publisher = reinterpret_cast<char16_t*>(
|
||||||
reinterpret_cast<char16_t*>(smdh->titles[static_cast<size_t>(language)].publisher.data());
|
smdh->titles[static_cast<std::size_t>(language)].publisher.data());
|
||||||
|
|
||||||
return ToJString(env, Common::UTF16ToUTF8(publisher).data());
|
return ToJString(env, Common::UTF16ToUTF8(publisher).data());
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,6 @@ static jclass s_cheat_class;
|
|||||||
static jfieldID s_cheat_pointer;
|
static jfieldID s_cheat_pointer;
|
||||||
static jmethodID s_cheat_constructor;
|
static jmethodID s_cheat_constructor;
|
||||||
|
|
||||||
static jfieldID s_cheat_engine_pointer;
|
|
||||||
|
|
||||||
static jfieldID s_game_info_pointer;
|
static jfieldID s_game_info_pointer;
|
||||||
|
|
||||||
static jclass s_disk_cache_progress_class;
|
static jclass s_disk_cache_progress_class;
|
||||||
@ -116,10 +114,6 @@ jmethodID GetCheatConstructor() {
|
|||||||
return s_cheat_constructor;
|
return s_cheat_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID GetCheatEnginePointer() {
|
|
||||||
return s_cheat_engine_pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
jfieldID GetGameInfoPointer() {
|
jfieldID GetGameInfoPointer() {
|
||||||
return s_game_info_pointer;
|
return s_game_info_pointer;
|
||||||
}
|
}
|
||||||
@ -195,12 +189,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|||||||
s_cheat_constructor = env->GetMethodID(cheat_class, "<init>", "(J)V");
|
s_cheat_constructor = env->GetMethodID(cheat_class, "<init>", "(J)V");
|
||||||
env->DeleteLocalRef(cheat_class);
|
env->DeleteLocalRef(cheat_class);
|
||||||
|
|
||||||
// Initialize CheatEngine
|
|
||||||
const jclass cheat_engine_class =
|
|
||||||
env->FindClass("org/citra/citra_emu/features/cheats/model/CheatEngine");
|
|
||||||
s_cheat_engine_pointer = env->GetFieldID(cheat_engine_class, "mPointer", "J");
|
|
||||||
env->DeleteLocalRef(cheat_engine_class);
|
|
||||||
|
|
||||||
// Initialize GameInfo
|
// Initialize GameInfo
|
||||||
const jclass game_info_class = env->FindClass("org/citra/citra_emu/model/GameInfo");
|
const jclass game_info_class = env->FindClass("org/citra/citra_emu/model/GameInfo");
|
||||||
s_game_info_pointer = env->GetFieldID(game_info_class, "pointer", "J");
|
s_game_info_pointer = env->GetFieldID(game_info_class, "pointer", "J");
|
||||||
|
@ -35,8 +35,6 @@ jclass GetCheatClass();
|
|||||||
jfieldID GetCheatPointer();
|
jfieldID GetCheatPointer();
|
||||||
jmethodID GetCheatConstructor();
|
jmethodID GetCheatConstructor();
|
||||||
|
|
||||||
jfieldID GetCheatEnginePointer();
|
|
||||||
|
|
||||||
jfieldID GetGameInfoPointer();
|
jfieldID GetGameInfoPointer();
|
||||||
|
|
||||||
jclass GetDiskCacheProgressClass();
|
jclass GetDiskCacheProgressClass();
|
||||||
|
@ -661,8 +661,8 @@ void Java_org_citra_citra_1emu_NativeLibrary_removeAmiibo([[maybe_unused]] JNIEn
|
|||||||
JNIEXPORT jobject JNICALL Java_org_citra_citra_1emu_utils_CiaInstallWorker_installCIA(
|
JNIEXPORT jobject JNICALL Java_org_citra_citra_1emu_utils_CiaInstallWorker_installCIA(
|
||||||
JNIEnv* env, jobject jobj, jstring jpath) {
|
JNIEnv* env, jobject jobj, jstring jpath) {
|
||||||
std::string path = GetJString(env, jpath);
|
std::string path = GetJString(env, jpath);
|
||||||
Service::AM::InstallStatus res =
|
Service::AM::InstallStatus res = Service::AM::InstallCIA(
|
||||||
Service::AM::InstallCIA(path, [env, jobj](size_t total_bytes_read, size_t file_size) {
|
path, [env, jobj](std::size_t total_bytes_read, std::size_t file_size) {
|
||||||
env->CallVoidMethod(jobj, IDCache::GetCiaInstallHelperSetProgress(),
|
env->CallVoidMethod(jobj, IDCache::GetCiaInstallHelperSetProgress(),
|
||||||
static_cast<jint>(file_size), static_cast<jint>(total_bytes_read));
|
static_cast<jint>(file_size), static_cast<jint>(total_bytes_read));
|
||||||
});
|
});
|
||||||
|
@ -4,11 +4,11 @@ add_library(audio_core STATIC
|
|||||||
codec.h
|
codec.h
|
||||||
dsp_interface.cpp
|
dsp_interface.cpp
|
||||||
dsp_interface.h
|
dsp_interface.h
|
||||||
|
hle/aac_decoder.cpp
|
||||||
|
hle/aac_decoder.h
|
||||||
hle/common.h
|
hle/common.h
|
||||||
hle/decoder.cpp
|
hle/decoder.cpp
|
||||||
hle/decoder.h
|
hle/decoder.h
|
||||||
hle/faad2_decoder.cpp
|
|
||||||
hle/faad2_decoder.h
|
|
||||||
hle/filter.cpp
|
hle/filter.cpp
|
||||||
hle/filter.h
|
hle/filter.h
|
||||||
hle/hle.cpp
|
hle/hle.cpp
|
||||||
|
@ -3,30 +3,11 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <neaacdec.h>
|
#include <neaacdec.h>
|
||||||
#include "audio_core/hle/faad2_decoder.h"
|
#include "audio_core/hle/aac_decoder.h"
|
||||||
|
|
||||||
namespace AudioCore::HLE {
|
namespace AudioCore::HLE {
|
||||||
|
|
||||||
class FAAD2Decoder::Impl {
|
AACDecoder::AACDecoder(Memory::MemorySystem& memory) : memory(memory) {
|
||||||
public:
|
|
||||||
explicit Impl(Memory::MemorySystem& memory);
|
|
||||||
~Impl();
|
|
||||||
std::optional<BinaryMessage> ProcessRequest(const BinaryMessage& request);
|
|
||||||
bool IsValid() const {
|
|
||||||
return decoder != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::optional<BinaryMessage> Initalize(const BinaryMessage& request);
|
|
||||||
|
|
||||||
std::optional<BinaryMessage> Decode(const BinaryMessage& request);
|
|
||||||
|
|
||||||
Memory::MemorySystem& memory;
|
|
||||||
|
|
||||||
NeAACDecHandle decoder = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
FAAD2Decoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) {
|
|
||||||
decoder = NeAACDecOpen();
|
decoder = NeAACDecOpen();
|
||||||
if (decoder == nullptr) {
|
if (decoder == nullptr) {
|
||||||
LOG_CRITICAL(Audio_DSP, "Could not open FAAD2 decoder.");
|
LOG_CRITICAL(Audio_DSP, "Could not open FAAD2 decoder.");
|
||||||
@ -46,7 +27,7 @@ FAAD2Decoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) {
|
|||||||
LOG_INFO(Audio_DSP, "Created FAAD2 AAC decoder.");
|
LOG_INFO(Audio_DSP, "Created FAAD2 AAC decoder.");
|
||||||
}
|
}
|
||||||
|
|
||||||
FAAD2Decoder::Impl::~Impl() {
|
AACDecoder::~AACDecoder() {
|
||||||
if (decoder) {
|
if (decoder) {
|
||||||
NeAACDecClose(decoder);
|
NeAACDecClose(decoder);
|
||||||
decoder = nullptr;
|
decoder = nullptr;
|
||||||
@ -55,16 +36,23 @@ FAAD2Decoder::Impl::~Impl() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<BinaryMessage> FAAD2Decoder::Impl::ProcessRequest(const BinaryMessage& request) {
|
BinaryMessage AACDecoder::ProcessRequest(const BinaryMessage& request) {
|
||||||
if (request.header.codec != DecoderCodec::DecodeAAC) {
|
if (request.header.codec != DecoderCodec::DecodeAAC) {
|
||||||
LOG_ERROR(Audio_DSP, "FAAD2 AAC Decoder cannot handle such codec: {}",
|
LOG_ERROR(Audio_DSP, "AAC decoder received unsupported codec: {}",
|
||||||
static_cast<u16>(request.header.codec));
|
static_cast<u16>(request.header.codec));
|
||||||
return {};
|
return {
|
||||||
|
.header =
|
||||||
|
{
|
||||||
|
.result = ResultStatus::Error,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (request.header.cmd) {
|
switch (request.header.cmd) {
|
||||||
case DecoderCommand::Init: {
|
case DecoderCommand::Init: {
|
||||||
return Initalize(request);
|
BinaryMessage response = request;
|
||||||
|
response.header.result = ResultStatus::Success;
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
case DecoderCommand::EncodeDecode: {
|
case DecoderCommand::EncodeDecode: {
|
||||||
return Decode(request);
|
return Decode(request);
|
||||||
@ -72,26 +60,25 @@ std::optional<BinaryMessage> FAAD2Decoder::Impl::ProcessRequest(const BinaryMess
|
|||||||
case DecoderCommand::Shutdown:
|
case DecoderCommand::Shutdown:
|
||||||
case DecoderCommand::SaveState:
|
case DecoderCommand::SaveState:
|
||||||
case DecoderCommand::LoadState: {
|
case DecoderCommand::LoadState: {
|
||||||
LOG_WARNING(Audio_DSP, "Got unimplemented binary request: {}",
|
LOG_WARNING(Audio_DSP, "Got unimplemented AAC binary request: {}",
|
||||||
static_cast<u16>(request.header.cmd));
|
static_cast<u16>(request.header.cmd));
|
||||||
BinaryMessage response = request;
|
BinaryMessage response = request;
|
||||||
response.header.result = ResultStatus::Success;
|
response.header.result = ResultStatus::Success;
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
LOG_ERROR(Audio_DSP, "Got unknown binary request: {}",
|
LOG_ERROR(Audio_DSP, "Got unknown AAC binary request: {}",
|
||||||
static_cast<u16>(request.header.cmd));
|
static_cast<u16>(request.header.cmd));
|
||||||
return {};
|
return {
|
||||||
|
.header =
|
||||||
|
{
|
||||||
|
.result = ResultStatus::Error,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<BinaryMessage> FAAD2Decoder::Impl::Initalize(const BinaryMessage& request) {
|
BinaryMessage AACDecoder::Decode(const BinaryMessage& request) {
|
||||||
BinaryMessage response = request;
|
|
||||||
response.header.result = ResultStatus::Success;
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<BinaryMessage> FAAD2Decoder::Impl::Decode(const BinaryMessage& request) {
|
|
||||||
BinaryMessage response{};
|
BinaryMessage response{};
|
||||||
response.header.codec = request.header.codec;
|
response.header.codec = request.header.codec;
|
||||||
response.header.cmd = request.header.cmd;
|
response.header.cmd = request.header.cmd;
|
||||||
@ -101,6 +88,10 @@ std::optional<BinaryMessage> FAAD2Decoder::Impl::Decode(const BinaryMessage& req
|
|||||||
response.decode_aac_response.num_channels = 2;
|
response.decode_aac_response.num_channels = 2;
|
||||||
response.decode_aac_response.num_samples = 1024;
|
response.decode_aac_response.num_samples = 1024;
|
||||||
|
|
||||||
|
if (decoder == nullptr) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
if (request.decode_aac_request.src_addr < Memory::FCRAM_PADDR ||
|
if (request.decode_aac_request.src_addr < Memory::FCRAM_PADDR ||
|
||||||
request.decode_aac_request.src_addr + request.decode_aac_request.size >
|
request.decode_aac_request.src_addr + request.decode_aac_request.size >
|
||||||
Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) {
|
Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) {
|
||||||
@ -171,16 +162,4 @@ std::optional<BinaryMessage> FAAD2Decoder::Impl::Decode(const BinaryMessage& req
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
FAAD2Decoder::FAAD2Decoder(Memory::MemorySystem& memory) : impl(std::make_unique<Impl>(memory)) {}
|
|
||||||
|
|
||||||
FAAD2Decoder::~FAAD2Decoder() = default;
|
|
||||||
|
|
||||||
std::optional<BinaryMessage> FAAD2Decoder::ProcessRequest(const BinaryMessage& request) {
|
|
||||||
return impl->ProcessRequest(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FAAD2Decoder::IsValid() const {
|
|
||||||
return impl->IsValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace AudioCore::HLE
|
} // namespace AudioCore::HLE
|
26
src/audio_core/hle/aac_decoder.h
Normal file
26
src/audio_core/hle/aac_decoder.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2023 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "audio_core/hle/decoder.h"
|
||||||
|
|
||||||
|
namespace AudioCore::HLE {
|
||||||
|
|
||||||
|
using NeAACDecHandle = void*;
|
||||||
|
|
||||||
|
class AACDecoder final : public DecoderBase {
|
||||||
|
public:
|
||||||
|
explicit AACDecoder(Memory::MemorySystem& memory);
|
||||||
|
~AACDecoder() override;
|
||||||
|
BinaryMessage ProcessRequest(const BinaryMessage& request) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BinaryMessage Decode(const BinaryMessage& request);
|
||||||
|
|
||||||
|
Memory::MemorySystem& memory;
|
||||||
|
NeAACDecHandle decoder = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace AudioCore::HLE
|
@ -32,34 +32,4 @@ DecoderSampleRate GetSampleRateEnum(u32 sample_rate) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DecoderBase::~DecoderBase(){};
|
|
||||||
|
|
||||||
NullDecoder::NullDecoder() = default;
|
|
||||||
|
|
||||||
NullDecoder::~NullDecoder() = default;
|
|
||||||
|
|
||||||
std::optional<BinaryMessage> NullDecoder::ProcessRequest(const BinaryMessage& request) {
|
|
||||||
BinaryMessage response{};
|
|
||||||
switch (request.header.cmd) {
|
|
||||||
case DecoderCommand::Init:
|
|
||||||
case DecoderCommand::Shutdown:
|
|
||||||
case DecoderCommand::SaveState:
|
|
||||||
case DecoderCommand::LoadState:
|
|
||||||
response = request;
|
|
||||||
response.header.result = ResultStatus::Success;
|
|
||||||
return response;
|
|
||||||
case DecoderCommand::EncodeDecode:
|
|
||||||
response.header.codec = request.header.codec;
|
|
||||||
response.header.cmd = request.header.cmd;
|
|
||||||
response.header.result = ResultStatus::Success;
|
|
||||||
response.decode_aac_response.num_channels = 2; // Just assume stereo here
|
|
||||||
response.decode_aac_response.size = request.decode_aac_request.size;
|
|
||||||
response.decode_aac_response.num_samples = 1024; // Just assume 1024 here
|
|
||||||
return response;
|
|
||||||
default:
|
|
||||||
LOG_ERROR(Audio_DSP, "Got unknown binary request: {}",
|
|
||||||
static_cast<u16>(request.header.cmd));
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace AudioCore::HLE
|
} // namespace AudioCore::HLE
|
||||||
|
@ -135,21 +135,8 @@ enum_le<DecoderSampleRate> GetSampleRateEnum(u32 sample_rate);
|
|||||||
|
|
||||||
class DecoderBase {
|
class DecoderBase {
|
||||||
public:
|
public:
|
||||||
virtual ~DecoderBase();
|
virtual ~DecoderBase() = default;
|
||||||
virtual std::optional<BinaryMessage> ProcessRequest(const BinaryMessage& request) = 0;
|
virtual BinaryMessage ProcessRequest(const BinaryMessage& request) = 0;
|
||||||
/// Return true if this Decoder can be loaded. Return false if the system cannot create the
|
|
||||||
/// decoder
|
|
||||||
virtual bool IsValid() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NullDecoder final : public DecoderBase {
|
|
||||||
public:
|
|
||||||
NullDecoder();
|
|
||||||
~NullDecoder() override;
|
|
||||||
std::optional<BinaryMessage> ProcessRequest(const BinaryMessage& request) override;
|
|
||||||
bool IsValid() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace AudioCore::HLE
|
} // namespace AudioCore::HLE
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
// Copyright 2023 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "audio_core/hle/decoder.h"
|
|
||||||
|
|
||||||
namespace AudioCore::HLE {
|
|
||||||
|
|
||||||
class FAAD2Decoder final : public DecoderBase {
|
|
||||||
public:
|
|
||||||
explicit FAAD2Decoder(Memory::MemorySystem& memory);
|
|
||||||
~FAAD2Decoder() override;
|
|
||||||
std::optional<BinaryMessage> ProcessRequest(const BinaryMessage& request) override;
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
class Impl;
|
|
||||||
std::unique_ptr<Impl> impl;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace AudioCore::HLE
|
|
@ -8,9 +8,9 @@
|
|||||||
#include <boost/serialization/vector.hpp>
|
#include <boost/serialization/vector.hpp>
|
||||||
#include <boost/serialization/weak_ptr.hpp>
|
#include <boost/serialization/weak_ptr.hpp>
|
||||||
#include "audio_core/audio_types.h"
|
#include "audio_core/audio_types.h"
|
||||||
|
#include "audio_core/hle/aac_decoder.h"
|
||||||
#include "audio_core/hle/common.h"
|
#include "audio_core/hle/common.h"
|
||||||
#include "audio_core/hle/decoder.h"
|
#include "audio_core/hle/decoder.h"
|
||||||
#include "audio_core/hle/faad2_decoder.h"
|
|
||||||
#include "audio_core/hle/hle.h"
|
#include "audio_core/hle/hle.h"
|
||||||
#include "audio_core/hle/mixers.h"
|
#include "audio_core/hle/mixers.h"
|
||||||
#include "audio_core/hle/shared_memory.h"
|
#include "audio_core/hle/shared_memory.h"
|
||||||
@ -24,16 +24,10 @@
|
|||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
|
|
||||||
SERIALIZE_EXPORT_IMPL(AudioCore::DspHle)
|
|
||||||
|
|
||||||
using InterruptType = Service::DSP::InterruptType;
|
using InterruptType = Service::DSP::InterruptType;
|
||||||
|
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
|
|
||||||
DspHle::DspHle()
|
|
||||||
: DspHle(Core::System::GetInstance(), Core::System::GetInstance().Memory(),
|
|
||||||
Core::System::GetInstance().CoreTiming()) {}
|
|
||||||
|
|
||||||
DspHle::DspHle(Core::System& system) : DspHle(system, system.Memory(), system.CoreTiming()) {}
|
DspHle::DspHle(Core::System& system) : DspHle(system, system.Memory(), system.CoreTiming()) {}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
@ -98,7 +92,7 @@ private:
|
|||||||
Core::Timing& core_timing;
|
Core::Timing& core_timing;
|
||||||
Core::TimingEventType* tick_event{};
|
Core::TimingEventType* tick_event{};
|
||||||
|
|
||||||
std::unique_ptr<HLE::DecoderBase> decoder{};
|
std::unique_ptr<HLE::DecoderBase> aac_decoder{};
|
||||||
|
|
||||||
std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> interrupt_handler{};
|
std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> interrupt_handler{};
|
||||||
|
|
||||||
@ -114,13 +108,6 @@ private:
|
|||||||
friend class boost::serialization::access;
|
friend class boost::serialization::access;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<std::function<std::unique_ptr<HLE::DecoderBase>(Memory::MemorySystem&)>>
|
|
||||||
decoder_backends = {
|
|
||||||
[](Memory::MemorySystem& memory) -> std::unique_ptr<HLE::DecoderBase> {
|
|
||||||
return std::make_unique<HLE::FAAD2Decoder>(memory);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory, Core::Timing& timing)
|
DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory, Core::Timing& timing)
|
||||||
: parent(parent_), core_timing(timing) {
|
: parent(parent_), core_timing(timing) {
|
||||||
dsp_memory.raw_memory.fill(0);
|
dsp_memory.raw_memory.fill(0);
|
||||||
@ -129,19 +116,7 @@ DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory, Core::Timing&
|
|||||||
source.SetMemory(memory);
|
source.SetMemory(memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& factory : decoder_backends) {
|
aac_decoder = std::make_unique<HLE::AACDecoder>(memory);
|
||||||
decoder = factory(memory);
|
|
||||||
if (decoder && decoder->IsValid()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!decoder || !decoder->IsValid()) {
|
|
||||||
LOG_WARNING(Audio_DSP,
|
|
||||||
"Unable to load any decoders, this could cause missing audio in some games");
|
|
||||||
decoder = std::make_unique<HLE::NullDecoder>();
|
|
||||||
}
|
|
||||||
|
|
||||||
tick_event =
|
tick_event =
|
||||||
core_timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) {
|
core_timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) {
|
||||||
this->AudioTickCallback(cycles_late);
|
this->AudioTickCallback(cycles_late);
|
||||||
@ -291,12 +266,9 @@ void DspHle::Impl::PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) {
|
|||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::optional<HLE::BinaryMessage> response = decoder->ProcessRequest(request);
|
const HLE::BinaryMessage response = aac_decoder->ProcessRequest(request);
|
||||||
if (response) {
|
pipe_data[static_cast<u32>(pipe_number)].resize(sizeof(response));
|
||||||
const HLE::BinaryMessage& value = *response;
|
std::memcpy(pipe_data[static_cast<u32>(pipe_number)].data(), &response, sizeof(response));
|
||||||
pipe_data[static_cast<u32>(pipe_number)].resize(sizeof(value));
|
|
||||||
std::memcpy(pipe_data[static_cast<u32>(pipe_number)].data(), &value, sizeof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
interrupt_handler(InterruptType::Pipe, DspPipe::Binary);
|
interrupt_handler(InterruptType::Pipe, DspPipe::Binary);
|
||||||
break;
|
break;
|
||||||
|
@ -50,13 +50,9 @@ private:
|
|||||||
friend struct Impl;
|
friend struct Impl;
|
||||||
std::unique_ptr<Impl> impl;
|
std::unique_ptr<Impl> impl;
|
||||||
|
|
||||||
DspHle();
|
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
void serialize(Archive& ar, const unsigned int);
|
void serialize(Archive& ar, const unsigned int);
|
||||||
friend class boost::serialization::access;
|
friend class boost::serialization::access;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace AudioCore
|
} // namespace AudioCore
|
||||||
|
|
||||||
BOOST_CLASS_EXPORT_KEY(AudioCore::DspHle)
|
|
||||||
|
@ -24,8 +24,8 @@ namespace {
|
|||||||
constexpr std::array input_details = {
|
constexpr std::array input_details = {
|
||||||
#ifdef HAVE_CUBEB
|
#ifdef HAVE_CUBEB
|
||||||
InputDetails{InputType::Cubeb, "Real Device (Cubeb)", true,
|
InputDetails{InputType::Cubeb, "Real Device (Cubeb)", true,
|
||||||
[](std::string_view device_id) -> std::unique_ptr<Input> {
|
[](Core::System& system, std::string_view device_id) -> std::unique_ptr<Input> {
|
||||||
if (!Core::System::GetInstance().HasMicPermission()) {
|
if (!system.HasMicPermission()) {
|
||||||
LOG_WARNING(Audio,
|
LOG_WARNING(Audio,
|
||||||
"Microphone permission denied, falling back to null input.");
|
"Microphone permission denied, falling back to null input.");
|
||||||
return std::make_unique<NullInput>();
|
return std::make_unique<NullInput>();
|
||||||
@ -36,8 +36,8 @@ constexpr std::array input_details = {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_OPENAL
|
#ifdef HAVE_OPENAL
|
||||||
InputDetails{InputType::OpenAL, "Real Device (OpenAL)", true,
|
InputDetails{InputType::OpenAL, "Real Device (OpenAL)", true,
|
||||||
[](std::string_view device_id) -> std::unique_ptr<Input> {
|
[](Core::System& system, std::string_view device_id) -> std::unique_ptr<Input> {
|
||||||
if (!Core::System::GetInstance().HasMicPermission()) {
|
if (!system.HasMicPermission()) {
|
||||||
LOG_WARNING(Audio,
|
LOG_WARNING(Audio,
|
||||||
"Microphone permission denied, falling back to null input.");
|
"Microphone permission denied, falling back to null input.");
|
||||||
return std::make_unique<NullInput>();
|
return std::make_unique<NullInput>();
|
||||||
@ -47,12 +47,12 @@ constexpr std::array input_details = {
|
|||||||
&ListOpenALInputDevices},
|
&ListOpenALInputDevices},
|
||||||
#endif
|
#endif
|
||||||
InputDetails{InputType::Static, "Static Noise", false,
|
InputDetails{InputType::Static, "Static Noise", false,
|
||||||
[](std::string_view device_id) -> std::unique_ptr<Input> {
|
[](Core::System& system, std::string_view device_id) -> std::unique_ptr<Input> {
|
||||||
return std::make_unique<StaticInput>();
|
return std::make_unique<StaticInput>();
|
||||||
},
|
},
|
||||||
[] { return std::vector<std::string>{"Static Noise"}; }},
|
[] { return std::vector<std::string>{"Static Noise"}; }},
|
||||||
InputDetails{InputType::Null, "None", false,
|
InputDetails{InputType::Null, "None", false,
|
||||||
[](std::string_view device_id) -> std::unique_ptr<Input> {
|
[](Core::System& system, std::string_view device_id) -> std::unique_ptr<Input> {
|
||||||
return std::make_unique<NullInput>();
|
return std::make_unique<NullInput>();
|
||||||
},
|
},
|
||||||
[] { return std::vector<std::string>{"None"}; }},
|
[] { return std::vector<std::string>{"None"}; }},
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
|
|
||||||
class Input;
|
class Input;
|
||||||
@ -23,7 +27,7 @@ enum class InputType : u32 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct InputDetails {
|
struct InputDetails {
|
||||||
using FactoryFn = std::unique_ptr<Input> (*)(std::string_view device_id);
|
using FactoryFn = std::unique_ptr<Input> (*)(Core::System& system, std::string_view device_id);
|
||||||
using ListDevicesFn = std::vector<std::string> (*)();
|
using ListDevicesFn = std::vector<std::string> (*)();
|
||||||
|
|
||||||
/// Type of this input.
|
/// Type of this input.
|
||||||
|
@ -148,7 +148,7 @@ ALsizei OpenALSink::Impl::Callback(void* impl_, void* buffer, ALsizei buffer_siz
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t num_frames = buffer_size_in_bytes / (2 * sizeof(s16));
|
const std::size_t num_frames = buffer_size_in_bytes / (2 * sizeof(s16));
|
||||||
impl->cb(reinterpret_cast<s16*>(buffer), num_frames);
|
impl->cb(reinterpret_cast<s16*>(buffer), num_frames);
|
||||||
|
|
||||||
return buffer_size_in_bytes;
|
return buffer_size_in_bytes;
|
||||||
|
@ -83,7 +83,7 @@ void SDL2Sink::Impl::Callback(void* impl_, u8* buffer, int buffer_size_in_bytes)
|
|||||||
if (!impl || !impl->cb)
|
if (!impl || !impl->cb)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const size_t num_frames = buffer_size_in_bytes / (2 * sizeof(s16));
|
const std::size_t num_frames = buffer_size_in_bytes / (2 * sizeof(s16));
|
||||||
|
|
||||||
impl->cb(reinterpret_cast<s16*>(buffer), num_frames);
|
impl->cb(reinterpret_cast<s16*>(buffer), num_frames);
|
||||||
}
|
}
|
||||||
|
@ -146,6 +146,7 @@ void Config::ReadValues() {
|
|||||||
ReadSetting("Renderer", Settings::values.frame_limit);
|
ReadSetting("Renderer", Settings::values.frame_limit);
|
||||||
ReadSetting("Renderer", Settings::values.use_vsync_new);
|
ReadSetting("Renderer", Settings::values.use_vsync_new);
|
||||||
ReadSetting("Renderer", Settings::values.texture_filter);
|
ReadSetting("Renderer", Settings::values.texture_filter);
|
||||||
|
ReadSetting("Renderer", Settings::values.texture_sampling);
|
||||||
|
|
||||||
ReadSetting("Renderer", Settings::values.mono_render_option);
|
ReadSetting("Renderer", Settings::values.mono_render_option);
|
||||||
ReadSetting("Renderer", Settings::values.render_3d);
|
ReadSetting("Renderer", Settings::values.render_3d);
|
||||||
@ -224,6 +225,8 @@ void Config::ReadValues() {
|
|||||||
std::chrono::system_clock::from_time_t(std::mktime(&t)).time_since_epoch())
|
std::chrono::system_clock::from_time_t(std::mktime(&t)).time_since_epoch())
|
||||||
.count();
|
.count();
|
||||||
}
|
}
|
||||||
|
ReadSetting("System", Settings::values.init_ticks_type);
|
||||||
|
ReadSetting("System", Settings::values.init_ticks_override);
|
||||||
ReadSetting("System", Settings::values.plugin_loader_enabled);
|
ReadSetting("System", Settings::values.plugin_loader_enabled);
|
||||||
ReadSetting("System", Settings::values.allow_plugin_loader);
|
ReadSetting("System", Settings::values.allow_plugin_loader);
|
||||||
|
|
||||||
@ -233,7 +236,7 @@ void Config::ReadValues() {
|
|||||||
std::string offset_string =
|
std::string offset_string =
|
||||||
sdl2_config->GetString("System", "init_time_offset", default_init_time_offset);
|
sdl2_config->GetString("System", "init_time_offset", default_init_time_offset);
|
||||||
|
|
||||||
size_t sep_index = offset_string.find(' ');
|
std::size_t sep_index = offset_string.find(' ');
|
||||||
|
|
||||||
if (sep_index == std::string::npos) {
|
if (sep_index == std::string::npos) {
|
||||||
LOG_ERROR(Config, "Failed to parse init_time_offset. Using 0 00:00:00");
|
LOG_ERROR(Config, "Failed to parse init_time_offset. Using 0 00:00:00");
|
||||||
|
@ -307,6 +307,14 @@ init_clock =
|
|||||||
# Note: 3DS can only handle times later then Jan 1 2000
|
# Note: 3DS can only handle times later then Jan 1 2000
|
||||||
init_time =
|
init_time =
|
||||||
|
|
||||||
|
# The system ticks count to use when citra starts
|
||||||
|
# 0: Random (default), 1: Fixed
|
||||||
|
init_ticks_type =
|
||||||
|
|
||||||
|
# Tick count to use when init_ticks_type is set to Fixed.
|
||||||
|
# Defaults to 0.
|
||||||
|
init_ticks_override =
|
||||||
|
|
||||||
[Camera]
|
[Camera]
|
||||||
# Which camera engine to use for the right outer camera
|
# Which camera engine to use for the right outer camera
|
||||||
# blank (default): a dummy camera that always returns black image
|
# blank (default): a dummy camera that always returns black image
|
||||||
|
@ -54,8 +54,11 @@ const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config:
|
|||||||
// This must be in alphabetical order according to action name as it must have the same order as
|
// This must be in alphabetical order according to action name as it must have the same order as
|
||||||
// UISetting::values.shortcuts, which is alphabetically ordered.
|
// UISetting::values.shortcuts, which is alphabetically ordered.
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const std::array<UISettings::Shortcut, 28> Config::default_hotkeys {{
|
const std::array<UISettings::Shortcut, 30> Config::default_hotkeys {{
|
||||||
{QStringLiteral("Advance Frame"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::ApplicationShortcut}},
|
{QStringLiteral("Advance Frame"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::ApplicationShortcut}},
|
||||||
|
{QStringLiteral("Audio Mute/Unmute"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), Qt::WindowShortcut}},
|
||||||
|
{QStringLiteral("Audio Volume Down"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WindowShortcut}},
|
||||||
|
{QStringLiteral("Audio Volume Up"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WindowShortcut}},
|
||||||
{QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::WidgetWithChildrenShortcut}},
|
{QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::WidgetWithChildrenShortcut}},
|
||||||
{QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}},
|
{QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}},
|
||||||
{QStringLiteral("Decrease 3D Factor"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+-"), Qt::ApplicationShortcut}},
|
{QStringLiteral("Decrease 3D Factor"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+-"), Qt::ApplicationShortcut}},
|
||||||
@ -68,7 +71,6 @@ const std::array<UISettings::Shortcut, 28> Config::default_hotkeys {{
|
|||||||
{QStringLiteral("Load Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), Qt::WidgetWithChildrenShortcut}},
|
{QStringLiteral("Load Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), Qt::WidgetWithChildrenShortcut}},
|
||||||
{QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), Qt::WidgetWithChildrenShortcut}},
|
{QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), Qt::WidgetWithChildrenShortcut}},
|
||||||
{QStringLiteral("Load from Newest Slot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+V"), Qt::WindowShortcut}},
|
{QStringLiteral("Load from Newest Slot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+V"), Qt::WindowShortcut}},
|
||||||
{QStringLiteral("Mute Audio"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), Qt::WindowShortcut}},
|
|
||||||
{QStringLiteral("Remove Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F3"), Qt::ApplicationShortcut}},
|
{QStringLiteral("Remove Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F3"), Qt::ApplicationShortcut}},
|
||||||
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}},
|
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}},
|
||||||
{QStringLiteral("Rotate Screens Upright"), QStringLiteral("Main Window"), {QStringLiteral("F8"), Qt::WindowShortcut}},
|
{QStringLiteral("Rotate Screens Upright"), QStringLiteral("Main Window"), {QStringLiteral("F8"), Qt::WindowShortcut}},
|
||||||
@ -645,6 +647,7 @@ void Config::ReadRendererValues() {
|
|||||||
ReadGlobalSetting(Settings::values.bg_blue);
|
ReadGlobalSetting(Settings::values.bg_blue);
|
||||||
|
|
||||||
ReadGlobalSetting(Settings::values.texture_filter);
|
ReadGlobalSetting(Settings::values.texture_filter);
|
||||||
|
ReadGlobalSetting(Settings::values.texture_sampling);
|
||||||
|
|
||||||
if (global) {
|
if (global) {
|
||||||
ReadBasicSetting(Settings::values.use_shader_jit);
|
ReadBasicSetting(Settings::values.use_shader_jit);
|
||||||
@ -684,6 +687,8 @@ void Config::ReadSystemValues() {
|
|||||||
ReadBasicSetting(Settings::values.init_clock);
|
ReadBasicSetting(Settings::values.init_clock);
|
||||||
ReadBasicSetting(Settings::values.init_time);
|
ReadBasicSetting(Settings::values.init_time);
|
||||||
ReadBasicSetting(Settings::values.init_time_offset);
|
ReadBasicSetting(Settings::values.init_time_offset);
|
||||||
|
ReadBasicSetting(Settings::values.init_ticks_type);
|
||||||
|
ReadBasicSetting(Settings::values.init_ticks_override);
|
||||||
ReadBasicSetting(Settings::values.plugin_loader_enabled);
|
ReadBasicSetting(Settings::values.plugin_loader_enabled);
|
||||||
ReadBasicSetting(Settings::values.allow_plugin_loader);
|
ReadBasicSetting(Settings::values.allow_plugin_loader);
|
||||||
}
|
}
|
||||||
@ -763,6 +768,7 @@ void Config::ReadUIValues() {
|
|||||||
ReadBasicSetting(UISettings::values.callout_flags);
|
ReadBasicSetting(UISettings::values.callout_flags);
|
||||||
ReadBasicSetting(UISettings::values.show_console);
|
ReadBasicSetting(UISettings::values.show_console);
|
||||||
ReadBasicSetting(UISettings::values.pause_when_in_background);
|
ReadBasicSetting(UISettings::values.pause_when_in_background);
|
||||||
|
ReadBasicSetting(UISettings::values.mute_when_in_background);
|
||||||
ReadBasicSetting(UISettings::values.hide_mouse);
|
ReadBasicSetting(UISettings::values.hide_mouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1130,6 +1136,7 @@ void Config::SaveRendererValues() {
|
|||||||
WriteGlobalSetting(Settings::values.bg_blue);
|
WriteGlobalSetting(Settings::values.bg_blue);
|
||||||
|
|
||||||
WriteGlobalSetting(Settings::values.texture_filter);
|
WriteGlobalSetting(Settings::values.texture_filter);
|
||||||
|
WriteGlobalSetting(Settings::values.texture_sampling);
|
||||||
|
|
||||||
if (global) {
|
if (global) {
|
||||||
WriteSetting(QStringLiteral("use_shader_jit"), Settings::values.use_shader_jit.GetValue(),
|
WriteSetting(QStringLiteral("use_shader_jit"), Settings::values.use_shader_jit.GetValue(),
|
||||||
@ -1169,6 +1176,8 @@ void Config::SaveSystemValues() {
|
|||||||
WriteBasicSetting(Settings::values.init_clock);
|
WriteBasicSetting(Settings::values.init_clock);
|
||||||
WriteBasicSetting(Settings::values.init_time);
|
WriteBasicSetting(Settings::values.init_time);
|
||||||
WriteBasicSetting(Settings::values.init_time_offset);
|
WriteBasicSetting(Settings::values.init_time_offset);
|
||||||
|
WriteBasicSetting(Settings::values.init_ticks_type);
|
||||||
|
WriteBasicSetting(Settings::values.init_ticks_override);
|
||||||
WriteBasicSetting(Settings::values.plugin_loader_enabled);
|
WriteBasicSetting(Settings::values.plugin_loader_enabled);
|
||||||
WriteBasicSetting(Settings::values.allow_plugin_loader);
|
WriteBasicSetting(Settings::values.allow_plugin_loader);
|
||||||
}
|
}
|
||||||
@ -1231,6 +1240,7 @@ void Config::SaveUIValues() {
|
|||||||
WriteBasicSetting(UISettings::values.callout_flags);
|
WriteBasicSetting(UISettings::values.callout_flags);
|
||||||
WriteBasicSetting(UISettings::values.show_console);
|
WriteBasicSetting(UISettings::values.show_console);
|
||||||
WriteBasicSetting(UISettings::values.pause_when_in_background);
|
WriteBasicSetting(UISettings::values.pause_when_in_background);
|
||||||
|
WriteBasicSetting(UISettings::values.mute_when_in_background);
|
||||||
WriteBasicSetting(UISettings::values.hide_mouse);
|
WriteBasicSetting(UISettings::values.hide_mouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ public:
|
|||||||
|
|
||||||
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
|
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
|
||||||
static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs;
|
static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs;
|
||||||
static const std::array<UISettings::Shortcut, 28> default_hotkeys;
|
static const std::array<UISettings::Shortcut, 30> default_hotkeys;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Initialize(const std::string& config_name);
|
void Initialize(const std::string& config_name);
|
||||||
|
@ -11,8 +11,10 @@
|
|||||||
#include "core/cheats/gateway_cheat.h"
|
#include "core/cheats/gateway_cheat.h"
|
||||||
#include "ui_configure_cheats.h"
|
#include "ui_configure_cheats.h"
|
||||||
|
|
||||||
ConfigureCheats::ConfigureCheats(Core::System& system, u64 title_id_, QWidget* parent)
|
ConfigureCheats::ConfigureCheats(Cheats::CheatEngine& cheat_engine_, u64 title_id_, QWidget* parent)
|
||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureCheats>()), title_id{title_id_} {
|
: QWidget(parent),
|
||||||
|
ui(std::make_unique<Ui::ConfigureCheats>()), cheat_engine{cheat_engine_}, title_id{
|
||||||
|
title_id_} {
|
||||||
// Setup gui control settings
|
// Setup gui control settings
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->tableCheats->setColumnWidth(0, 30);
|
ui->tableCheats->setColumnWidth(0, 30);
|
||||||
@ -34,15 +36,14 @@ ConfigureCheats::ConfigureCheats(Core::System& system, u64 title_id_, QWidget* p
|
|||||||
[this] { SaveCheat(ui->tableCheats->currentRow()); });
|
[this] { SaveCheat(ui->tableCheats->currentRow()); });
|
||||||
connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureCheats::OnDeleteCheat);
|
connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureCheats::OnDeleteCheat);
|
||||||
|
|
||||||
cheat_engine = std::make_unique<Cheats::CheatEngine>(title_id, system);
|
cheat_engine.LoadCheatFile(title_id);
|
||||||
|
|
||||||
LoadCheats();
|
LoadCheats();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigureCheats::~ConfigureCheats() = default;
|
ConfigureCheats::~ConfigureCheats() = default;
|
||||||
|
|
||||||
void ConfigureCheats::LoadCheats() {
|
void ConfigureCheats::LoadCheats() {
|
||||||
cheats = cheat_engine->GetCheats();
|
cheats = cheat_engine.GetCheats();
|
||||||
const int cheats_count = static_cast<int>(cheats.size());
|
const int cheats_count = static_cast<int>(cheats.size());
|
||||||
|
|
||||||
ui->tableCheats->setRowCount(cheats_count);
|
ui->tableCheats->setRowCount(cheats_count);
|
||||||
@ -106,12 +107,12 @@ bool ConfigureCheats::SaveCheat(int row) {
|
|||||||
ui->textNotes->toPlainText().toStdString());
|
ui->textNotes->toPlainText().toStdString());
|
||||||
|
|
||||||
if (newly_created) {
|
if (newly_created) {
|
||||||
cheat_engine->AddCheat(cheat);
|
cheat_engine.AddCheat(std::move(cheat));
|
||||||
newly_created = false;
|
newly_created = false;
|
||||||
} else {
|
} else {
|
||||||
cheat_engine->UpdateCheat(row, cheat);
|
cheat_engine.UpdateCheat(row, std::move(cheat));
|
||||||
}
|
}
|
||||||
cheat_engine->SaveCheatFile();
|
cheat_engine.SaveCheatFile(title_id);
|
||||||
|
|
||||||
int previous_row = ui->tableCheats->currentRow();
|
int previous_row = ui->tableCheats->currentRow();
|
||||||
int previous_col = ui->tableCheats->currentColumn();
|
int previous_col = ui->tableCheats->currentColumn();
|
||||||
@ -161,7 +162,7 @@ void ConfigureCheats::OnCheckChanged(int state) {
|
|||||||
const QCheckBox* checkbox = qobject_cast<QCheckBox*>(sender());
|
const QCheckBox* checkbox = qobject_cast<QCheckBox*>(sender());
|
||||||
int row = static_cast<int>(checkbox->property("row").toInt());
|
int row = static_cast<int>(checkbox->property("row").toInt());
|
||||||
cheats[row]->SetEnabled(state);
|
cheats[row]->SetEnabled(state);
|
||||||
cheat_engine->SaveCheatFile();
|
cheat_engine.SaveCheatFile(title_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureCheats::OnTextEdited() {
|
void ConfigureCheats::OnTextEdited() {
|
||||||
@ -173,8 +174,8 @@ void ConfigureCheats::OnDeleteCheat() {
|
|||||||
if (newly_created) {
|
if (newly_created) {
|
||||||
newly_created = false;
|
newly_created = false;
|
||||||
} else {
|
} else {
|
||||||
cheat_engine->RemoveCheat(ui->tableCheats->currentRow());
|
cheat_engine.RemoveCheat(ui->tableCheats->currentRow());
|
||||||
cheat_engine->SaveCheatFile();
|
cheat_engine.SaveCheatFile(title_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadCheats();
|
LoadCheats();
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
@ -25,7 +26,8 @@ class ConfigureCheats : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigureCheats(Core::System& system, u64 title_id, QWidget* parent = nullptr);
|
explicit ConfigureCheats(Cheats::CheatEngine& cheat_engine, u64 title_id_,
|
||||||
|
QWidget* parent = nullptr);
|
||||||
~ConfigureCheats();
|
~ConfigureCheats();
|
||||||
bool ApplyConfiguration();
|
bool ApplyConfiguration();
|
||||||
|
|
||||||
@ -58,9 +60,9 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::ConfigureCheats> ui;
|
std::unique_ptr<Ui::ConfigureCheats> ui;
|
||||||
std::vector<std::shared_ptr<Cheats::CheatBase>> cheats;
|
Cheats::CheatEngine& cheat_engine;
|
||||||
|
std::span<const std::shared_ptr<Cheats::CheatBase>> cheats;
|
||||||
bool edited = false, newly_created = false;
|
bool edited = false, newly_created = false;
|
||||||
int last_row = -1, last_col = -1;
|
int last_row = -1, last_col = -1;
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
std::unique_ptr<Cheats::CheatEngine> cheat_engine;
|
|
||||||
};
|
};
|
||||||
|
@ -74,6 +74,8 @@ void ConfigureGeneral::SetConfiguration() {
|
|||||||
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
|
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
|
||||||
ui->toggle_background_pause->setChecked(
|
ui->toggle_background_pause->setChecked(
|
||||||
UISettings::values.pause_when_in_background.GetValue());
|
UISettings::values.pause_when_in_background.GetValue());
|
||||||
|
ui->toggle_background_mute->setChecked(
|
||||||
|
UISettings::values.mute_when_in_background.GetValue());
|
||||||
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
|
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
|
||||||
|
|
||||||
ui->toggle_update_check->setChecked(
|
ui->toggle_update_check->setChecked(
|
||||||
@ -174,6 +176,7 @@ void ConfigureGeneral::ApplyConfiguration() {
|
|||||||
if (Settings::IsConfiguringGlobal()) {
|
if (Settings::IsConfiguringGlobal()) {
|
||||||
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
|
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
|
||||||
UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
|
UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
|
||||||
|
UISettings::values.mute_when_in_background = ui->toggle_background_mute->isChecked();
|
||||||
UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
|
UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
|
||||||
|
|
||||||
UISettings::values.check_for_update_on_start = ui->toggle_update_check->isChecked();
|
UISettings::values.check_for_update_on_start = ui->toggle_update_check->isChecked();
|
||||||
|
@ -36,6 +36,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="toggle_background_mute">
|
||||||
|
<property name="text">
|
||||||
|
<string>Mute audio when in background</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="toggle_hide_mouse">
|
<widget class="QCheckBox" name="toggle_hide_mouse">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -38,7 +38,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString
|
|||||||
graphics_tab = std::make_unique<ConfigureGraphics>(physical_devices, is_powered_on, this);
|
graphics_tab = std::make_unique<ConfigureGraphics>(physical_devices, is_powered_on, this);
|
||||||
system_tab = std::make_unique<ConfigureSystem>(system, this);
|
system_tab = std::make_unique<ConfigureSystem>(system, this);
|
||||||
debug_tab = std::make_unique<ConfigureDebug>(is_powered_on, this);
|
debug_tab = std::make_unique<ConfigureDebug>(is_powered_on, this);
|
||||||
cheat_tab = std::make_unique<ConfigureCheats>(system, title_id, this);
|
cheat_tab = std::make_unique<ConfigureCheats>(system.CheatEngine(), title_id, this);
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
@ -230,6 +230,8 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
|
|||||||
&ConfigureSystem::UpdateBirthdayComboBox);
|
&ConfigureSystem::UpdateBirthdayComboBox);
|
||||||
connect(ui->combo_init_clock, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
connect(ui->combo_init_clock, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
&ConfigureSystem::UpdateInitTime);
|
&ConfigureSystem::UpdateInitTime);
|
||||||
|
connect(ui->combo_init_ticks_type, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
|
&ConfigureSystem::UpdateInitTicks);
|
||||||
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
|
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
|
||||||
&ConfigureSystem::RefreshConsoleID);
|
&ConfigureSystem::RefreshConsoleID);
|
||||||
connect(ui->button_start_download, &QPushButton::clicked, this,
|
connect(ui->button_start_download, &QPushButton::clicked, this,
|
||||||
@ -293,6 +295,11 @@ void ConfigureSystem::SetConfiguration() {
|
|||||||
QTime time = QTime::fromMSecsSinceStartOfDay(static_cast<int>(time_offset * 1000));
|
QTime time = QTime::fromMSecsSinceStartOfDay(static_cast<int>(time_offset * 1000));
|
||||||
ui->edit_init_time_offset_time->setTime(time);
|
ui->edit_init_time_offset_time->setTime(time);
|
||||||
|
|
||||||
|
ui->combo_init_ticks_type->setCurrentIndex(
|
||||||
|
static_cast<u8>(Settings::values.init_ticks_type.GetValue()));
|
||||||
|
ui->edit_init_ticks_value->setText(
|
||||||
|
QString::number(Settings::values.init_ticks_override.GetValue()));
|
||||||
|
|
||||||
cfg = Service::CFG::GetModule(system);
|
cfg = Service::CFG::GetModule(system);
|
||||||
ReadSystemSettings();
|
ReadSystemSettings();
|
||||||
|
|
||||||
@ -413,6 +420,11 @@ void ConfigureSystem::ApplyConfiguration() {
|
|||||||
static_cast<Settings::InitClock>(ui->combo_init_clock->currentIndex());
|
static_cast<Settings::InitClock>(ui->combo_init_clock->currentIndex());
|
||||||
Settings::values.init_time = ui->edit_init_time->dateTime().toSecsSinceEpoch();
|
Settings::values.init_time = ui->edit_init_time->dateTime().toSecsSinceEpoch();
|
||||||
|
|
||||||
|
Settings::values.init_ticks_type =
|
||||||
|
static_cast<Settings::InitTicks>(ui->combo_init_ticks_type->currentIndex());
|
||||||
|
Settings::values.init_ticks_override =
|
||||||
|
static_cast<s64>(ui->edit_init_ticks_value->text().toLongLong());
|
||||||
|
|
||||||
s64 time_offset_time = ui->edit_init_time_offset_time->time().msecsSinceStartOfDay() / 1000;
|
s64 time_offset_time = ui->edit_init_time_offset_time->time().msecsSinceStartOfDay() / 1000;
|
||||||
s64 time_offset_days = ui->edit_init_time_offset_days->value() * 86400;
|
s64 time_offset_days = ui->edit_init_time_offset_days->value() * 86400;
|
||||||
|
|
||||||
@ -462,6 +474,7 @@ void ConfigureSystem::ConfigureTime() {
|
|||||||
SetConfiguration();
|
SetConfiguration();
|
||||||
|
|
||||||
UpdateInitTime(ui->combo_init_clock->currentIndex());
|
UpdateInitTime(ui->combo_init_clock->currentIndex());
|
||||||
|
UpdateInitTicks(ui->combo_init_ticks_type->currentIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureSystem::UpdateInitTime(int init_clock) {
|
void ConfigureSystem::UpdateInitTime(int init_clock) {
|
||||||
@ -477,6 +490,15 @@ void ConfigureSystem::UpdateInitTime(int init_clock) {
|
|||||||
ui->edit_init_time_offset_time->setVisible(!is_fixed_time && is_global);
|
ui->edit_init_time_offset_time->setVisible(!is_fixed_time && is_global);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigureSystem::UpdateInitTicks(int init_ticks_type) {
|
||||||
|
const bool is_global = Settings::IsConfiguringGlobal();
|
||||||
|
const bool is_fixed =
|
||||||
|
static_cast<Settings::InitTicks>(init_ticks_type) == Settings::InitTicks::Fixed;
|
||||||
|
|
||||||
|
ui->label_init_ticks_value->setVisible(is_fixed && is_global);
|
||||||
|
ui->edit_init_ticks_value->setVisible(is_fixed && is_global);
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigureSystem::RefreshConsoleID() {
|
void ConfigureSystem::RefreshConsoleID() {
|
||||||
QMessageBox::StandardButton reply;
|
QMessageBox::StandardButton reply;
|
||||||
QString warning_text = tr("This will replace your current virtual 3DS with a new one. "
|
QString warning_text = tr("This will replace your current virtual 3DS with a new one. "
|
||||||
@ -512,6 +534,8 @@ void ConfigureSystem::SetupPerGameUI() {
|
|||||||
ui->label_birthday->setVisible(false);
|
ui->label_birthday->setVisible(false);
|
||||||
ui->label_init_clock->setVisible(false);
|
ui->label_init_clock->setVisible(false);
|
||||||
ui->label_init_time->setVisible(false);
|
ui->label_init_time->setVisible(false);
|
||||||
|
ui->label_init_ticks_type->setVisible(false);
|
||||||
|
ui->label_init_ticks_value->setVisible(false);
|
||||||
ui->label_console_id->setVisible(false);
|
ui->label_console_id->setVisible(false);
|
||||||
ui->label_sound->setVisible(false);
|
ui->label_sound->setVisible(false);
|
||||||
ui->label_language->setVisible(false);
|
ui->label_language->setVisible(false);
|
||||||
@ -522,12 +546,14 @@ void ConfigureSystem::SetupPerGameUI() {
|
|||||||
ui->combo_birthday->setVisible(false);
|
ui->combo_birthday->setVisible(false);
|
||||||
ui->combo_birthmonth->setVisible(false);
|
ui->combo_birthmonth->setVisible(false);
|
||||||
ui->combo_init_clock->setVisible(false);
|
ui->combo_init_clock->setVisible(false);
|
||||||
|
ui->combo_init_ticks_type->setVisible(false);
|
||||||
ui->combo_sound->setVisible(false);
|
ui->combo_sound->setVisible(false);
|
||||||
ui->combo_language->setVisible(false);
|
ui->combo_language->setVisible(false);
|
||||||
ui->combo_country->setVisible(false);
|
ui->combo_country->setVisible(false);
|
||||||
ui->label_init_time_offset->setVisible(false);
|
ui->label_init_time_offset->setVisible(false);
|
||||||
ui->edit_init_time_offset_days->setVisible(false);
|
ui->edit_init_time_offset_days->setVisible(false);
|
||||||
ui->edit_init_time_offset_time->setVisible(false);
|
ui->edit_init_time_offset_time->setVisible(false);
|
||||||
|
ui->edit_init_ticks_value->setVisible(false);
|
||||||
ui->toggle_system_setup->setVisible(false);
|
ui->toggle_system_setup->setVisible(false);
|
||||||
ui->button_regenerate_console_id->setVisible(false);
|
ui->button_regenerate_console_id->setVisible(false);
|
||||||
// Apps can change the state of the plugin loader, so plugins load
|
// Apps can change the state of the plugin loader, so plugins load
|
||||||
|
@ -43,6 +43,7 @@ private:
|
|||||||
|
|
||||||
void UpdateBirthdayComboBox(int birthmonth_index);
|
void UpdateBirthdayComboBox(int birthmonth_index);
|
||||||
void UpdateInitTime(int init_clock);
|
void UpdateInitTime(int init_clock);
|
||||||
|
void UpdateInitTicks(int init_ticks_type);
|
||||||
void RefreshConsoleID();
|
void RefreshConsoleID();
|
||||||
|
|
||||||
void SetupPerGameUI();
|
void SetupPerGameUI();
|
||||||
|
@ -304,34 +304,75 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="0">
|
<item row="9" column="0">
|
||||||
|
<widget class="QLabel" name="label_init_ticks_type">
|
||||||
|
<property name="text">
|
||||||
|
<string>Initial System Ticks</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="1">
|
||||||
|
<widget class="QComboBox" name="combo_init_ticks_type">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Random</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Fixed</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="0">
|
||||||
|
<widget class="QLabel" name="label_init_ticks_value">
|
||||||
|
<property name="text">
|
||||||
|
<string>Initial System Ticks Override</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="1">
|
||||||
|
<widget class="QLineEdit" name="edit_init_ticks_value">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maxLength">
|
||||||
|
<number>20</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="0">
|
||||||
<widget class="QLabel" name="label_play_coins">
|
<widget class="QLabel" name="label_play_coins">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Play Coins:</string>
|
<string>Play Coins:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="1">
|
<item row="11" column="1">
|
||||||
<widget class="QSpinBox" name="spinBox_play_coins">
|
<widget class="QSpinBox" name="spinBox_play_coins">
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>300</number>
|
<number>300</number>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="10" column="1">
|
<item row="12" column="1">
|
||||||
<widget class="QCheckBox" name="toggle_system_setup">
|
<widget class="QCheckBox" name="toggle_system_setup">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Run System Setup when Home Menu is launched</string>
|
<string>Run System Setup when Home Menu is launched</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="11" column="0">
|
<item row="13" column="0">
|
||||||
<widget class="QLabel" name="label_console_id">
|
<widget class="QLabel" name="label_console_id">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Console ID:</string>
|
<string>Console ID:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="11" column="1">
|
<item row="13" column="1">
|
||||||
<widget class="QPushButton" name="button_regenerate_console_id">
|
<widget class="QPushButton" name="button_regenerate_console_id">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
@ -347,35 +388,35 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="12" column="0">
|
<item row="14" column="0">
|
||||||
<widget class="QLabel" name="label_plugin_loader">
|
<widget class="QLabel" name="label_plugin_loader">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>3GX Plugin Loader:</string>
|
<string>3GX Plugin Loader:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="12" column="1">
|
<item row="14" column="1">
|
||||||
<widget class="QCheckBox" name="plugin_loader">
|
<widget class="QCheckBox" name="plugin_loader">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Enable 3GX plugin loader</string>
|
<string>Enable 3GX plugin loader</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="13" column="1">
|
<item row="15" column="1">
|
||||||
<widget class="QCheckBox" name="allow_plugin_loader">
|
<widget class="QCheckBox" name="allow_plugin_loader">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Allow games to change plugin loader state</string>
|
<string>Allow games to change plugin loader state</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="14" column="0">
|
<item row="16" column="0">
|
||||||
<widget class="QLabel" name="label_nus_download">
|
<widget class="QLabel" name="label_nus_download">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Download System Files from Nitendo servers</string>
|
<string>Download System Files from Nitendo servers</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="14" column="1">
|
<item row="16" column="1">
|
||||||
<widget class="QWidget" name="body_nus_download">
|
<widget class="QWidget" name="body_nus_download">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_nus_download">
|
<layout class="QHBoxLayout" name="horizontalLayout_nus_download">
|
||||||
<item>
|
<item>
|
||||||
|
@ -49,7 +49,7 @@ QString IPCRecorderWidget::GetStatusStr(const IPCDebugger::RequestRecord& record
|
|||||||
case IPCDebugger::RequestStatus::Handling:
|
case IPCDebugger::RequestStatus::Handling:
|
||||||
return tr("Handling");
|
return tr("Handling");
|
||||||
case IPCDebugger::RequestStatus::Handled:
|
case IPCDebugger::RequestStatus::Handled:
|
||||||
if (record.translated_reply_cmdbuf[1] == RESULT_SUCCESS.raw) {
|
if (record.translated_reply_cmdbuf[1] == ResultSuccess.raw) {
|
||||||
return tr("Success");
|
return tr("Success");
|
||||||
}
|
}
|
||||||
return tr("Error");
|
return tr("Error");
|
||||||
@ -88,7 +88,7 @@ void IPCRecorderWidget::OnEntryUpdated(IPCDebugger::RequestRecord record) {
|
|||||||
|
|
||||||
if (record.status == IPCDebugger::RequestStatus::HLEUnimplemented ||
|
if (record.status == IPCDebugger::RequestStatus::HLEUnimplemented ||
|
||||||
(record.status == IPCDebugger::RequestStatus::Handled &&
|
(record.status == IPCDebugger::RequestStatus::Handled &&
|
||||||
record.translated_reply_cmdbuf[1] != RESULT_SUCCESS.raw)) { // Unimplemented / Error
|
record.translated_reply_cmdbuf[1] != ResultSuccess.raw)) { // Unimplemented / Error
|
||||||
|
|
||||||
auto item = ui->main->invisibleRootItem()->child(row_id);
|
auto item = ui->main->invisibleRootItem()->child(row_id);
|
||||||
for (int column = 0; column < item->columnCount(); ++column) {
|
for (int column = 0; column < item->columnCount(); ++column) {
|
||||||
|
@ -229,6 +229,7 @@ GMainWindow::GMainWindow(Core::System& system_)
|
|||||||
SetDefaultUIGeometry();
|
SetDefaultUIGeometry();
|
||||||
RestoreUIState();
|
RestoreUIState();
|
||||||
|
|
||||||
|
ConnectAppEvents();
|
||||||
ConnectMenuEvents();
|
ConnectMenuEvents();
|
||||||
ConnectWidgetEvents();
|
ConnectWidgetEvents();
|
||||||
|
|
||||||
@ -419,6 +420,38 @@ void GMainWindow::InitializeWidgets() {
|
|||||||
|
|
||||||
statusBar()->insertPermanentWidget(0, graphics_api_button);
|
statusBar()->insertPermanentWidget(0, graphics_api_button);
|
||||||
|
|
||||||
|
volume_popup = new QWidget(this);
|
||||||
|
volume_popup->setWindowFlags(Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint | Qt::Popup);
|
||||||
|
volume_popup->setLayout(new QVBoxLayout());
|
||||||
|
volume_popup->setMinimumWidth(200);
|
||||||
|
|
||||||
|
volume_slider = new QSlider(Qt::Horizontal);
|
||||||
|
volume_slider->setObjectName(QStringLiteral("volume_slider"));
|
||||||
|
volume_slider->setMaximum(100);
|
||||||
|
volume_slider->setPageStep(5);
|
||||||
|
connect(volume_slider, &QSlider::valueChanged, this, [this](int percentage) {
|
||||||
|
Settings::values.audio_muted = false;
|
||||||
|
const auto value = static_cast<float>(percentage) / volume_slider->maximum();
|
||||||
|
Settings::values.volume.SetValue(value);
|
||||||
|
UpdateVolumeUI();
|
||||||
|
});
|
||||||
|
volume_popup->layout()->addWidget(volume_slider);
|
||||||
|
|
||||||
|
volume_button = new QPushButton();
|
||||||
|
volume_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
|
||||||
|
volume_button->setFocusPolicy(Qt::NoFocus);
|
||||||
|
volume_button->setCheckable(true);
|
||||||
|
UpdateVolumeUI();
|
||||||
|
connect(volume_button, &QPushButton::clicked, this, [&] {
|
||||||
|
UpdateVolumeUI();
|
||||||
|
volume_popup->setVisible(!volume_popup->isVisible());
|
||||||
|
QRect rect = volume_button->geometry();
|
||||||
|
QPoint bottomLeft = statusBar()->mapToGlobal(rect.topLeft());
|
||||||
|
bottomLeft.setY(bottomLeft.y() - volume_popup->geometry().height());
|
||||||
|
volume_popup->setGeometry(QRect(bottomLeft, QSize(rect.width(), rect.height())));
|
||||||
|
});
|
||||||
|
statusBar()->insertPermanentWidget(1, volume_button);
|
||||||
|
|
||||||
statusBar()->addPermanentWidget(multiplayer_state->GetStatusText());
|
statusBar()->addPermanentWidget(multiplayer_state->GetStatusText());
|
||||||
statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon());
|
statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon());
|
||||||
|
|
||||||
@ -671,8 +704,10 @@ void GMainWindow::InitializeHotkeys() {
|
|||||||
}
|
}
|
||||||
UpdateStatusBar();
|
UpdateStatusBar();
|
||||||
});
|
});
|
||||||
connect_shortcut(QStringLiteral("Mute Audio"),
|
|
||||||
[] { Settings::values.audio_muted = !Settings::values.audio_muted; });
|
connect_shortcut(QStringLiteral("Audio Mute/Unmute"), &GMainWindow::OnMute);
|
||||||
|
connect_shortcut(QStringLiteral("Audio Volume Down"), &GMainWindow::OnDecreaseVolume);
|
||||||
|
connect_shortcut(QStringLiteral("Audio Volume Up"), &GMainWindow::OnIncreaseVolume);
|
||||||
|
|
||||||
// We use "static" here in order to avoid capturing by lambda due to a MSVC bug, which makes the
|
// We use "static" here in order to avoid capturing by lambda due to a MSVC bug, which makes the
|
||||||
// variable hold a garbage value after this function exits
|
// variable hold a garbage value after this function exits
|
||||||
@ -743,22 +778,49 @@ void GMainWindow::RestoreUIState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
|
void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
|
||||||
if (!UISettings::values.pause_when_in_background) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (state != Qt::ApplicationHidden && state != Qt::ApplicationInactive &&
|
if (state != Qt::ApplicationHidden && state != Qt::ApplicationInactive &&
|
||||||
state != Qt::ApplicationActive) {
|
state != Qt::ApplicationActive) {
|
||||||
LOG_DEBUG(Frontend, "ApplicationState unusual flag: {} ", state);
|
LOG_DEBUG(Frontend, "ApplicationState unusual flag: {} ", state);
|
||||||
}
|
}
|
||||||
if (ui->action_Pause->isEnabled() &&
|
if (!emulation_running) {
|
||||||
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
|
return;
|
||||||
auto_paused = true;
|
|
||||||
OnPauseGame();
|
|
||||||
} else if (emulation_running && !emu_thread->IsRunning() && auto_paused &&
|
|
||||||
state == Qt::ApplicationActive) {
|
|
||||||
auto_paused = false;
|
|
||||||
OnStartGame();
|
|
||||||
}
|
}
|
||||||
|
if (UISettings::values.pause_when_in_background) {
|
||||||
|
if (emu_thread->IsRunning() &&
|
||||||
|
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
|
||||||
|
auto_paused = true;
|
||||||
|
OnPauseGame();
|
||||||
|
} else if (!emu_thread->IsRunning() && auto_paused && state == Qt::ApplicationActive) {
|
||||||
|
auto_paused = false;
|
||||||
|
OnStartGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (UISettings::values.mute_when_in_background) {
|
||||||
|
if (!Settings::values.audio_muted &&
|
||||||
|
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
|
||||||
|
Settings::values.audio_muted = true;
|
||||||
|
auto_muted = true;
|
||||||
|
} else if (auto_muted && state == Qt::ApplicationActive) {
|
||||||
|
Settings::values.audio_muted = false;
|
||||||
|
auto_muted = false;
|
||||||
|
}
|
||||||
|
UpdateVolumeUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GApplicationEventFilter::eventFilter(QObject* object, QEvent* event) {
|
||||||
|
if (event->type() == QEvent::FileOpen) {
|
||||||
|
emit FileOpen(static_cast<QFileOpenEvent*>(event));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMainWindow::ConnectAppEvents() {
|
||||||
|
const auto filter = new GApplicationEventFilter();
|
||||||
|
QGuiApplication::instance()->installEventFilter(filter);
|
||||||
|
|
||||||
|
connect(filter, &GApplicationEventFilter::FileOpen, this, &GMainWindow::OnFileOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::ConnectWidgetEvents() {
|
void GMainWindow::ConnectWidgetEvents() {
|
||||||
@ -1858,7 +1920,7 @@ void GMainWindow::OnStartGame() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
UpdateSaveStates();
|
UpdateSaveStates();
|
||||||
UpdateAPIIndicator();
|
UpdateStatusButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::OnRestartGame() {
|
void GMainWindow::OnRestartGame() {
|
||||||
@ -1895,7 +1957,7 @@ void GMainWindow::OnStopGame() {
|
|||||||
ShutdownGame();
|
ShutdownGame();
|
||||||
graphics_api_button->setEnabled(true);
|
graphics_api_button->setEnabled(true);
|
||||||
Settings::RestoreGlobalState(false);
|
Settings::RestoreGlobalState(false);
|
||||||
UpdateAPIIndicator();
|
UpdateStatusButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::OnLoadComplete() {
|
void GMainWindow::OnLoadComplete() {
|
||||||
@ -2136,7 +2198,7 @@ void GMainWindow::OnConfigure() {
|
|||||||
}
|
}
|
||||||
UpdateSecondaryWindowVisibility();
|
UpdateSecondaryWindowVisibility();
|
||||||
UpdateBootHomeMenuState();
|
UpdateBootHomeMenuState();
|
||||||
UpdateAPIIndicator();
|
UpdateStatusButtons();
|
||||||
} else {
|
} else {
|
||||||
Settings::values.input_profiles = old_input_profiles;
|
Settings::values.input_profiles = old_input_profiles;
|
||||||
Settings::values.touch_from_button_maps = old_touch_from_button_maps;
|
Settings::values.touch_from_button_maps = old_touch_from_button_maps;
|
||||||
@ -2566,6 +2628,57 @@ void GMainWindow::ShowMouseCursor() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GMainWindow::OnMute() {
|
||||||
|
Settings::values.audio_muted = !Settings::values.audio_muted;
|
||||||
|
UpdateVolumeUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMainWindow::OnDecreaseVolume() {
|
||||||
|
Settings::values.audio_muted = false;
|
||||||
|
const auto current_volume =
|
||||||
|
static_cast<s32>(Settings::values.volume.GetValue() * volume_slider->maximum());
|
||||||
|
int step = 5;
|
||||||
|
if (current_volume <= 30) {
|
||||||
|
step = 2;
|
||||||
|
}
|
||||||
|
if (current_volume <= 6) {
|
||||||
|
step = 1;
|
||||||
|
}
|
||||||
|
const auto value =
|
||||||
|
static_cast<float>(std::max(current_volume - step, 0)) / volume_slider->maximum();
|
||||||
|
Settings::values.volume.SetValue(value);
|
||||||
|
UpdateVolumeUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMainWindow::OnIncreaseVolume() {
|
||||||
|
Settings::values.audio_muted = false;
|
||||||
|
const auto current_volume =
|
||||||
|
static_cast<s32>(Settings::values.volume.GetValue() * volume_slider->maximum());
|
||||||
|
int step = 5;
|
||||||
|
if (current_volume < 30) {
|
||||||
|
step = 2;
|
||||||
|
}
|
||||||
|
if (current_volume < 6) {
|
||||||
|
step = 1;
|
||||||
|
}
|
||||||
|
const auto value = static_cast<float>(current_volume + step) / volume_slider->maximum();
|
||||||
|
Settings::values.volume.SetValue(value);
|
||||||
|
UpdateVolumeUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMainWindow::UpdateVolumeUI() {
|
||||||
|
const auto volume_value =
|
||||||
|
static_cast<int>(Settings::values.volume.GetValue() * volume_slider->maximum());
|
||||||
|
volume_slider->setValue(volume_value);
|
||||||
|
if (Settings::values.audio_muted) {
|
||||||
|
volume_button->setChecked(false);
|
||||||
|
volume_button->setText(tr("VOLUME: MUTE"));
|
||||||
|
} else {
|
||||||
|
volume_button->setChecked(true);
|
||||||
|
volume_button->setText(tr("VOLUME: %1%", "Volume percentage (e.g. 50%)").arg(volume_value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GMainWindow::UpdateAPIIndicator(bool update) {
|
void GMainWindow::UpdateAPIIndicator(bool update) {
|
||||||
static std::array graphics_apis = {QStringLiteral("SOFTWARE"), QStringLiteral("OPENGL"),
|
static std::array graphics_apis = {QStringLiteral("SOFTWARE"), QStringLiteral("OPENGL"),
|
||||||
QStringLiteral("VULKAN")};
|
QStringLiteral("VULKAN")};
|
||||||
@ -2586,6 +2699,11 @@ void GMainWindow::UpdateAPIIndicator(bool update) {
|
|||||||
graphics_api_button->setStyleSheet(style_sheet);
|
graphics_api_button->setStyleSheet(style_sheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GMainWindow::UpdateStatusButtons() {
|
||||||
|
UpdateAPIIndicator();
|
||||||
|
UpdateVolumeUI();
|
||||||
|
}
|
||||||
|
|
||||||
void GMainWindow::OnMouseActivity() {
|
void GMainWindow::OnMouseActivity() {
|
||||||
ShowMouseCursor();
|
ShowMouseCursor();
|
||||||
}
|
}
|
||||||
@ -2752,6 +2870,10 @@ bool GMainWindow::DropAction(QDropEvent* event) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GMainWindow::OnFileOpen(const QFileOpenEvent* event) {
|
||||||
|
BootGame(event->file());
|
||||||
|
}
|
||||||
|
|
||||||
void GMainWindow::dropEvent(QDropEvent* event) {
|
void GMainWindow::dropEvent(QDropEvent* event) {
|
||||||
DropAction(event);
|
DropAction(event);
|
||||||
}
|
}
|
||||||
@ -2883,6 +3005,8 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const QString& file_nam
|
|||||||
if (!is_powered_on) {
|
if (!is_powered_on) {
|
||||||
config->Save();
|
config->Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateStatusButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::OnMoviePlaybackCompleted() {
|
void GMainWindow::OnMoviePlaybackCompleted() {
|
||||||
|
@ -41,6 +41,7 @@ class LoadingScreen;
|
|||||||
class MicroProfileDialog;
|
class MicroProfileDialog;
|
||||||
class MultiplayerState;
|
class MultiplayerState;
|
||||||
class ProfilerWidget;
|
class ProfilerWidget;
|
||||||
|
class QFileOpenEvent;
|
||||||
template <typename>
|
template <typename>
|
||||||
class QFutureWatcher;
|
class QFutureWatcher;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
@ -96,6 +97,8 @@ public:
|
|||||||
bool DropAction(QDropEvent* event);
|
bool DropAction(QDropEvent* event);
|
||||||
void AcceptDropEvent(QDropEvent* event);
|
void AcceptDropEvent(QDropEvent* event);
|
||||||
|
|
||||||
|
void OnFileOpen(const QFileOpenEvent* event);
|
||||||
|
|
||||||
void UninstallTitles(
|
void UninstallTitles(
|
||||||
const std::vector<std::tuple<Service::FS::MediaType, u64, QString>>& titles);
|
const std::vector<std::tuple<Service::FS::MediaType, u64, QString>>& titles);
|
||||||
|
|
||||||
@ -137,6 +140,7 @@ private:
|
|||||||
void SyncMenuUISettings();
|
void SyncMenuUISettings();
|
||||||
void RestoreUIState();
|
void RestoreUIState();
|
||||||
|
|
||||||
|
void ConnectAppEvents();
|
||||||
void ConnectWidgetEvents();
|
void ConnectWidgetEvents();
|
||||||
void ConnectMenuEvents();
|
void ConnectMenuEvents();
|
||||||
void UpdateMenuState();
|
void UpdateMenuState();
|
||||||
@ -263,6 +267,10 @@ private slots:
|
|||||||
void OnLanguageChanged(const QString& locale);
|
void OnLanguageChanged(const QString& locale);
|
||||||
void OnMouseActivity();
|
void OnMouseActivity();
|
||||||
|
|
||||||
|
void OnDecreaseVolume();
|
||||||
|
void OnIncreaseVolume();
|
||||||
|
void OnMute();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_INVOKABLE void OnMoviePlaybackCompleted();
|
Q_INVOKABLE void OnMoviePlaybackCompleted();
|
||||||
void UpdateStatusBar();
|
void UpdateStatusBar();
|
||||||
@ -275,7 +283,9 @@ private:
|
|||||||
void HideMouseCursor();
|
void HideMouseCursor();
|
||||||
void ShowMouseCursor();
|
void ShowMouseCursor();
|
||||||
void OpenPerGameConfiguration(u64 title_id, const QString& file_name);
|
void OpenPerGameConfiguration(u64 title_id, const QString& file_name);
|
||||||
|
void UpdateVolumeUI();
|
||||||
void UpdateAPIIndicator(bool update = false);
|
void UpdateAPIIndicator(bool update = false);
|
||||||
|
void UpdateStatusButtons();
|
||||||
#ifdef __unix__
|
#ifdef __unix__
|
||||||
void SetGamemodeEnabled(bool state);
|
void SetGamemodeEnabled(bool state);
|
||||||
#endif
|
#endif
|
||||||
@ -297,6 +307,9 @@ private:
|
|||||||
QLabel* game_fps_label = nullptr;
|
QLabel* game_fps_label = nullptr;
|
||||||
QLabel* emu_frametime_label = nullptr;
|
QLabel* emu_frametime_label = nullptr;
|
||||||
QPushButton* graphics_api_button = nullptr;
|
QPushButton* graphics_api_button = nullptr;
|
||||||
|
QPushButton* volume_button = nullptr;
|
||||||
|
QWidget* volume_popup = nullptr;
|
||||||
|
QSlider* volume_slider = nullptr;
|
||||||
QTimer status_bar_update_timer;
|
QTimer status_bar_update_timer;
|
||||||
bool message_label_used_for_movie = false;
|
bool message_label_used_for_movie = false;
|
||||||
|
|
||||||
@ -312,6 +325,7 @@ private:
|
|||||||
QString game_path;
|
QString game_path;
|
||||||
|
|
||||||
bool auto_paused = false;
|
bool auto_paused = false;
|
||||||
|
bool auto_muted = false;
|
||||||
QTimer mouse_hide_timer;
|
QTimer mouse_hide_timer;
|
||||||
|
|
||||||
// Movie
|
// Movie
|
||||||
@ -382,5 +396,15 @@ protected:
|
|||||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GApplicationEventFilter : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void FileOpen(const QFileOpenEvent* event);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject* object, QEvent* event) override;
|
||||||
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(std::size_t);
|
Q_DECLARE_METATYPE(std::size_t);
|
||||||
Q_DECLARE_METATYPE(Service::AM::InstallStatus);
|
Q_DECLARE_METATYPE(Service::AM::InstallStatus);
|
||||||
|
@ -25,7 +25,7 @@ bool QtImageInterface::DecodePNG(std::vector<u8>& dst, u32& width, u32& height,
|
|||||||
image = image.convertToFormat(QImage::Format_RGBA8888);
|
image = image.convertToFormat(QImage::Format_RGBA8888);
|
||||||
|
|
||||||
// Write RGBA8 to vector
|
// Write RGBA8 to vector
|
||||||
const size_t image_size = width * height * 4;
|
const std::size_t image_size = width * height * 4;
|
||||||
dst.resize(image_size);
|
dst.resize(image_size);
|
||||||
std::memcpy(dst.data(), image.constBits(), image_size);
|
std::memcpy(dst.data(), image.constBits(), image_size);
|
||||||
|
|
||||||
|
@ -80,6 +80,7 @@ struct Values {
|
|||||||
Settings::Setting<bool> save_state_warning{true, "saveStateWarning"};
|
Settings::Setting<bool> save_state_warning{true, "saveStateWarning"};
|
||||||
Settings::Setting<bool> first_start{true, "firstStart"};
|
Settings::Setting<bool> first_start{true, "firstStart"};
|
||||||
Settings::Setting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
|
Settings::Setting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
|
||||||
|
Settings::Setting<bool> mute_when_in_background{false, "muteWhenInBackground"};
|
||||||
Settings::Setting<bool> hide_mouse{false, "hideInactiveMouse"};
|
Settings::Setting<bool> hide_mouse{false, "hideInactiveMouse"};
|
||||||
|
|
||||||
bool updater_found;
|
bool updater_found;
|
||||||
|
@ -30,7 +30,7 @@ namespace Common {
|
|||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
static std::string GetCPUString() {
|
static std::string GetCPUString() {
|
||||||
char buf[128];
|
char buf[128];
|
||||||
size_t buf_len = sizeof(buf);
|
std::size_t buf_len = sizeof(buf);
|
||||||
if (sysctlbyname("machdep.cpu.brand_string", &buf, &buf_len, NULL, 0) == -1) {
|
if (sysctlbyname("machdep.cpu.brand_string", &buf, &buf_len, NULL, 0) == -1) {
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
@ -63,15 +63,15 @@ struct ABIFrameInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
inline ABIFrameInfo ABI_CalculateFrameSize(std::bitset<64> regs, std::size_t frame_size) {
|
inline ABIFrameInfo ABI_CalculateFrameSize(std::bitset<64> regs, std::size_t frame_size) {
|
||||||
const size_t gprs_count = (regs & ABI_ALL_GPRS).count();
|
const std::size_t gprs_count = (regs & ABI_ALL_GPRS).count();
|
||||||
const size_t fprs_count = (regs & ABI_ALL_FPRS).count();
|
const std::size_t fprs_count = (regs & ABI_ALL_FPRS).count();
|
||||||
|
|
||||||
const size_t gprs_size = (gprs_count + 1) / 2 * 16;
|
const std::size_t gprs_size = (gprs_count + 1) / 2 * 16;
|
||||||
const size_t fprs_size = fprs_count * 16;
|
const std::size_t fprs_size = fprs_count * 16;
|
||||||
|
|
||||||
size_t total_size = 0;
|
std::size_t total_size = 0;
|
||||||
total_size += gprs_size;
|
total_size += gprs_size;
|
||||||
const size_t fprs_base_subtraction = total_size;
|
const std::size_t fprs_base_subtraction = total_size;
|
||||||
total_size += fprs_size;
|
total_size += fprs_size;
|
||||||
total_size += frame_size;
|
total_size += frame_size;
|
||||||
|
|
||||||
@ -100,11 +100,11 @@ inline void ABI_PushRegisters(oaknut::CodeGenerator& code, std::bitset<64> regs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!gprs.empty()) {
|
if (!gprs.empty()) {
|
||||||
for (size_t i = 0; i < gprs.size() - 1; i += 2) {
|
for (std::size_t i = 0; i < gprs.size() - 1; i += 2) {
|
||||||
code.STP(gprs[i], gprs[i + 1], SP, i * sizeof(u64));
|
code.STP(gprs[i], gprs[i + 1], SP, i * sizeof(u64));
|
||||||
}
|
}
|
||||||
if (gprs.size() % 2 == 1) {
|
if (gprs.size() % 2 == 1) {
|
||||||
const size_t i = gprs.size() - 1;
|
const std::size_t i = gprs.size() - 1;
|
||||||
code.STR(gprs[i], SP, i * sizeof(u64));
|
code.STR(gprs[i], SP, i * sizeof(u64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,11 +121,11 @@ inline void ABI_PushRegisters(oaknut::CodeGenerator& code, std::bitset<64> regs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!fprs.empty()) {
|
if (!fprs.empty()) {
|
||||||
for (size_t i = 0; i < fprs.size() - 1; i += 2) {
|
for (std::size_t i = 0; i < fprs.size() - 1; i += 2) {
|
||||||
code.STP(fprs[i], fprs[i + 1], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
|
code.STP(fprs[i], fprs[i + 1], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
|
||||||
}
|
}
|
||||||
if (fprs.size() % 2 == 1) {
|
if (fprs.size() % 2 == 1) {
|
||||||
const size_t i = fprs.size() - 1;
|
const std::size_t i = fprs.size() - 1;
|
||||||
code.STR(fprs[i], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
|
code.STR(fprs[i], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,11 +159,11 @@ inline void ABI_PopRegisters(oaknut::CodeGenerator& code, std::bitset<64> regs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!gprs.empty()) {
|
if (!gprs.empty()) {
|
||||||
for (size_t i = 0; i < gprs.size() - 1; i += 2) {
|
for (std::size_t i = 0; i < gprs.size() - 1; i += 2) {
|
||||||
code.LDP(gprs[i], gprs[i + 1], SP, i * sizeof(u64));
|
code.LDP(gprs[i], gprs[i + 1], SP, i * sizeof(u64));
|
||||||
}
|
}
|
||||||
if (gprs.size() % 2 == 1) {
|
if (gprs.size() % 2 == 1) {
|
||||||
const size_t i = gprs.size() - 1;
|
const std::size_t i = gprs.size() - 1;
|
||||||
code.LDR(gprs[i], SP, i * sizeof(u64));
|
code.LDR(gprs[i], SP, i * sizeof(u64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,11 +180,11 @@ inline void ABI_PopRegisters(oaknut::CodeGenerator& code, std::bitset<64> regs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!fprs.empty()) {
|
if (!fprs.empty()) {
|
||||||
for (size_t i = 0; i < fprs.size() - 1; i += 2) {
|
for (std::size_t i = 0; i < fprs.size() - 1; i += 2) {
|
||||||
code.LDP(fprs[i], fprs[i + 1], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
|
code.LDP(fprs[i], fprs[i + 1], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
|
||||||
}
|
}
|
||||||
if (fprs.size() % 2 == 1) {
|
if (fprs.size() % 2 == 1) {
|
||||||
const size_t i = fprs.size() - 1;
|
const std::size_t i = fprs.size() - 1;
|
||||||
code.LDR(fprs[i], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
|
code.LDR(fprs[i], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@
|
|||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
constexpr size_t DefaultCapacity = 0x1000;
|
constexpr std::size_t DefaultCapacity = 0x1000;
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <typename T, size_t Capacity = detail::DefaultCapacity>
|
template <typename T, std::size_t Capacity = detail::DefaultCapacity>
|
||||||
class SPSCQueue {
|
class SPSCQueue {
|
||||||
static_assert((Capacity & (Capacity - 1)) == 0, "Capacity must be a power of two.");
|
static_assert((Capacity & (Capacity - 1)) == 0, "Capacity must be a power of two.");
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ private:
|
|||||||
|
|
||||||
template <PushMode Mode, typename... Args>
|
template <PushMode Mode, typename... Args>
|
||||||
bool Emplace(Args&&... args) {
|
bool Emplace(Args&&... args) {
|
||||||
const size_t write_index = m_write_index.load(std::memory_order::relaxed);
|
const std::size_t write_index = m_write_index.load(std::memory_order::relaxed);
|
||||||
|
|
||||||
if constexpr (Mode == PushMode::Try) {
|
if constexpr (Mode == PushMode::Try) {
|
||||||
// Check if we have free slots to write to.
|
// Check if we have free slots to write to.
|
||||||
@ -92,7 +92,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine the position to write to.
|
// Determine the position to write to.
|
||||||
const size_t pos = write_index % Capacity;
|
const std::size_t pos = write_index % Capacity;
|
||||||
|
|
||||||
// Emplace into the queue.
|
// Emplace into the queue.
|
||||||
new (std::addressof(m_data[pos])) T(std::forward<Args>(args)...);
|
new (std::addressof(m_data[pos])) T(std::forward<Args>(args)...);
|
||||||
@ -109,7 +109,7 @@ private:
|
|||||||
|
|
||||||
template <PopMode Mode>
|
template <PopMode Mode>
|
||||||
bool Pop(T& t, [[maybe_unused]] std::stop_token stop_token = {}) {
|
bool Pop(T& t, [[maybe_unused]] std::stop_token stop_token = {}) {
|
||||||
const size_t read_index = m_read_index.load(std::memory_order::relaxed);
|
const std::size_t read_index = m_read_index.load(std::memory_order::relaxed);
|
||||||
|
|
||||||
if constexpr (Mode == PopMode::Try) {
|
if constexpr (Mode == PopMode::Try) {
|
||||||
// Check if the queue is empty.
|
// Check if the queue is empty.
|
||||||
@ -136,7 +136,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine the position to read from.
|
// Determine the position to read from.
|
||||||
const size_t pos = read_index % Capacity;
|
const std::size_t pos = read_index % Capacity;
|
||||||
|
|
||||||
// Pop the data off the queue, moving it.
|
// Pop the data off the queue, moving it.
|
||||||
t = std::move(m_data[pos]);
|
t = std::move(m_data[pos]);
|
||||||
@ -162,7 +162,7 @@ private:
|
|||||||
std::mutex consumer_cv_mutex;
|
std::mutex consumer_cv_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, size_t Capacity = detail::DefaultCapacity>
|
template <typename T, std::size_t Capacity = detail::DefaultCapacity>
|
||||||
class MPSCQueue {
|
class MPSCQueue {
|
||||||
public:
|
public:
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
@ -202,7 +202,7 @@ private:
|
|||||||
std::mutex write_mutex;
|
std::mutex write_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, size_t Capacity = detail::DefaultCapacity>
|
template <typename T, std::size_t Capacity = detail::DefaultCapacity>
|
||||||
class MPMCQueue {
|
class MPMCQueue {
|
||||||
public:
|
public:
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
|
@ -40,11 +40,9 @@
|
|||||||
#define WORDS_BIGENDIAN 1
|
#define WORDS_BIGENDIAN 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
typedef std::uint8_t uint8;
|
||||||
|
typedef std::uint32_t uint32;
|
||||||
typedef uint8_t uint8;
|
typedef std::uint64_t uint64;
|
||||||
typedef uint32_t uint32;
|
|
||||||
typedef uint64_t uint64;
|
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
@ -152,19 +150,19 @@ static uint64 HashLen17to32(const char* s, std::size_t len) {
|
|||||||
|
|
||||||
// Return a 16-byte hash for 48 bytes. Quick and dirty.
|
// Return a 16-byte hash for 48 bytes. Quick and dirty.
|
||||||
// Callers do best to use "random-looking" values for a and b.
|
// Callers do best to use "random-looking" values for a and b.
|
||||||
static pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w, uint64 x, uint64 y, uint64 z, uint64 a,
|
static std::pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w, uint64 x, uint64 y, uint64 z,
|
||||||
uint64 b) {
|
uint64 a, uint64 b) {
|
||||||
a += w;
|
a += w;
|
||||||
b = Rotate(b + a + z, 21);
|
b = Rotate(b + a + z, 21);
|
||||||
uint64 c = a;
|
uint64 c = a;
|
||||||
a += x;
|
a += x;
|
||||||
a += y;
|
a += y;
|
||||||
b += Rotate(a, 44);
|
b += Rotate(a, 44);
|
||||||
return make_pair(a + z, b + c);
|
return std::make_pair(a + z, b + c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
|
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
|
||||||
static pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s, uint64 a, uint64 b) {
|
static std::pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s, uint64 a, uint64 b) {
|
||||||
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a,
|
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a,
|
||||||
b);
|
b);
|
||||||
}
|
}
|
||||||
@ -207,8 +205,8 @@ uint64 CityHash64(const char* s, std::size_t len) {
|
|||||||
uint64 x = Fetch64(s + len - 40);
|
uint64 x = Fetch64(s + len - 40);
|
||||||
uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
|
uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
|
||||||
uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
|
uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
|
||||||
pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
|
std::pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
|
||||||
pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
|
std::pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
|
||||||
x = x * k1 + Fetch64(s);
|
x = x * k1 + Fetch64(s);
|
||||||
|
|
||||||
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
|
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
|
||||||
@ -276,7 +274,7 @@ uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed) {
|
|||||||
|
|
||||||
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
|
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
|
||||||
// v, w, x, y, and z.
|
// v, w, x, y, and z.
|
||||||
pair<uint64, uint64> v, w;
|
std::pair<uint64, uint64> v, w;
|
||||||
uint64 x = Uint128Low64(seed);
|
uint64 x = Uint128Low64(seed);
|
||||||
uint64 y = Uint128High64(seed);
|
uint64 y = Uint128High64(seed);
|
||||||
uint64 z = len * k1;
|
uint64 z = len * k1;
|
||||||
|
@ -38,7 +38,7 @@ bool DynamicLibrary::Load(std::string_view filename) {
|
|||||||
if (!handle) {
|
if (!handle) {
|
||||||
DWORD error_message_id = GetLastError();
|
DWORD error_message_id = GetLastError();
|
||||||
LPSTR message_buffer = nullptr;
|
LPSTR message_buffer = nullptr;
|
||||||
size_t size =
|
std::size_t size =
|
||||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
nullptr, error_message_id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
nullptr, error_message_id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
@ -1159,7 +1159,7 @@ std::size_t IOFile::ReadImpl(void* data, std::size_t length, std::size_t data_si
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static std::size_t pread(int fd, void* buf, size_t count, uint64_t offset) {
|
static std::size_t pread(int fd, void* buf, std::size_t count, uint64_t offset) {
|
||||||
long unsigned int read_bytes = 0;
|
long unsigned int read_bytes = 0;
|
||||||
OVERLAPPED overlapped = {0};
|
OVERLAPPED overlapped = {0};
|
||||||
HANDLE file = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
|
HANDLE file = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
|
||||||
|
@ -37,7 +37,7 @@ static inline u64 ComputeStructHash64(const T& data) noexcept {
|
|||||||
* Combines the seed parameter with the provided hash, producing a new unique hash
|
* Combines the seed parameter with the provided hash, producing a new unique hash
|
||||||
* Implementation from: http://boost.sourceforge.net/doc/html/boost/hash_combine.html
|
* Implementation from: http://boost.sourceforge.net/doc/html/boost/hash_combine.html
|
||||||
*/
|
*/
|
||||||
inline u64 HashCombine(const u64 seed, const u64 hash) {
|
[[nodiscard]] inline u64 HashCombine(const u64 seed, const u64 hash) {
|
||||||
return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2));
|
return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred&& pred) {
|
|||||||
namespace std {
|
namespace std {
|
||||||
namespace polyfill {
|
namespace polyfill {
|
||||||
|
|
||||||
using stop_state_callback = size_t;
|
using stop_state_callback = std::size_t;
|
||||||
|
|
||||||
class stop_state {
|
class stop_state {
|
||||||
public:
|
public:
|
||||||
|
@ -28,6 +28,11 @@ enum class InitClock : u32 {
|
|||||||
FixedTime = 1,
|
FixedTime = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class InitTicks : u32 {
|
||||||
|
Random = 0,
|
||||||
|
Fixed = 1,
|
||||||
|
};
|
||||||
|
|
||||||
enum class LayoutOption : u32 {
|
enum class LayoutOption : u32 {
|
||||||
Default,
|
Default,
|
||||||
SingleScreen,
|
SingleScreen,
|
||||||
@ -437,6 +442,8 @@ struct Values {
|
|||||||
Setting<InitClock> init_clock{InitClock::SystemTime, "init_clock"};
|
Setting<InitClock> init_clock{InitClock::SystemTime, "init_clock"};
|
||||||
Setting<u64> init_time{946681277ULL, "init_time"};
|
Setting<u64> init_time{946681277ULL, "init_time"};
|
||||||
Setting<s64> init_time_offset{0, "init_time_offset"};
|
Setting<s64> init_time_offset{0, "init_time_offset"};
|
||||||
|
Setting<InitTicks> init_ticks_type{InitTicks::Random, "init_ticks_type"};
|
||||||
|
Setting<s64> init_ticks_override{0, "init_ticks_override"};
|
||||||
Setting<bool> plugin_loader_enabled{false, "plugin_loader"};
|
Setting<bool> plugin_loader_enabled{false, "plugin_loader"};
|
||||||
Setting<bool> allow_plugin_loader{true, "allow_plugin_loader"};
|
Setting<bool> allow_plugin_loader{true, "allow_plugin_loader"};
|
||||||
|
|
||||||
|
@ -31,9 +31,9 @@ template <class T>
|
|||||||
class SlotVector {
|
class SlotVector {
|
||||||
public:
|
public:
|
||||||
~SlotVector() noexcept {
|
~SlotVector() noexcept {
|
||||||
size_t index = 0;
|
std::size_t index = 0;
|
||||||
for (u64 bits : stored_bitset) {
|
for (u64 bits : stored_bitset) {
|
||||||
for (size_t bit = 0; bits; ++bit, bits >>= 1) {
|
for (std::size_t bit = 0; bits; ++bit, bits >>= 1) {
|
||||||
if ((bits & 1) != 0) {
|
if ((bits & 1) != 0) {
|
||||||
values[index + bit].object.~T();
|
values[index + bit].object.~T();
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ public:
|
|||||||
ResetStorageBit(id.index);
|
ResetStorageBit(id.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const noexcept {
|
std::size_t size() const noexcept {
|
||||||
return values_capacity - free_list.size();
|
return values_capacity - free_list.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,12 +126,12 @@ private:
|
|||||||
return free_index;
|
return free_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reserve(size_t new_capacity) noexcept {
|
void Reserve(std::size_t new_capacity) noexcept {
|
||||||
Entry* const new_values = new Entry[new_capacity];
|
Entry* const new_values = new Entry[new_capacity];
|
||||||
size_t index = 0;
|
std::size_t index = 0;
|
||||||
for (u64 bits : stored_bitset) {
|
for (u64 bits : stored_bitset) {
|
||||||
for (size_t bit = 0; bits; ++bit, bits >>= 1) {
|
for (std::size_t bit = 0; bits; ++bit, bits >>= 1) {
|
||||||
const size_t i = index + bit;
|
const std::size_t i = index + bit;
|
||||||
if ((bits & 1) == 0) {
|
if ((bits & 1) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ private:
|
|||||||
|
|
||||||
stored_bitset.resize((new_capacity + 63) / 64);
|
stored_bitset.resize((new_capacity + 63) / 64);
|
||||||
|
|
||||||
const size_t old_free_size = free_list.size();
|
const std::size_t old_free_size = free_list.size();
|
||||||
free_list.resize(old_free_size + (new_capacity - values_capacity));
|
free_list.resize(old_free_size + (new_capacity - values_capacity));
|
||||||
std::iota(free_list.begin() + old_free_size, free_list.end(),
|
std::iota(free_list.begin() + old_free_size, free_list.end(),
|
||||||
static_cast<u32>(values_capacity));
|
static_cast<u32>(values_capacity));
|
||||||
@ -155,7 +155,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Entry* values = nullptr;
|
Entry* values = nullptr;
|
||||||
size_t values_capacity = 0;
|
std::size_t values_capacity = 0;
|
||||||
|
|
||||||
std::vector<u64> stored_bitset;
|
std::vector<u64> stored_bitset;
|
||||||
std::vector<u32> free_list;
|
std::vector<u32> free_list;
|
||||||
@ -165,7 +165,7 @@ private:
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct std::hash<Common::SlotId> {
|
struct std::hash<Common::SlotId> {
|
||||||
size_t operator()(const Common::SlotId& id) const noexcept {
|
std::size_t operator()(const Common::SlotId& id) const noexcept {
|
||||||
return std::hash<u32>{}(id.index);
|
return std::hash<u32>{}(id.index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -23,23 +23,23 @@ namespace Common {
|
|||||||
|
|
||||||
// a cache which evicts the least recently used item when it is full
|
// a cache which evicts the least recently used item when it is full
|
||||||
// the cache elements are statically allocated.
|
// the cache elements are statically allocated.
|
||||||
template <class Key, class Value, size_t Size>
|
template <class Key, class Value, std::size_t Size>
|
||||||
class StaticLRUCache {
|
class StaticLRUCache {
|
||||||
public:
|
public:
|
||||||
using key_type = Key;
|
using key_type = Key;
|
||||||
using value_type = Value;
|
using value_type = Value;
|
||||||
using list_type = std::list<std::pair<Key, size_t>>;
|
using list_type = std::list<std::pair<Key, std::size_t>>;
|
||||||
using array_type = std::array<Value, Size>;
|
using array_type = std::array<Value, Size>;
|
||||||
|
|
||||||
StaticLRUCache() = default;
|
StaticLRUCache() = default;
|
||||||
|
|
||||||
~StaticLRUCache() = default;
|
~StaticLRUCache() = default;
|
||||||
|
|
||||||
size_t size() const {
|
std::size_t size() const {
|
||||||
return m_list.size();
|
return m_list.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr size_t capacity() const {
|
constexpr std::size_t capacity() const {
|
||||||
return m_array.size();
|
return m_array.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ public:
|
|||||||
// lookup value in the cache
|
// lookup value in the cache
|
||||||
auto i = find(key);
|
auto i = find(key);
|
||||||
if (i == m_list.cend()) {
|
if (i == m_list.cend()) {
|
||||||
size_t next_index = size();
|
std::size_t next_index = size();
|
||||||
// insert item into the cache, but first check if it is full
|
// insert item into the cache, but first check if it is full
|
||||||
if (next_index >= capacity()) {
|
if (next_index >= capacity()) {
|
||||||
// cache is full, evict the least recently used item
|
// cache is full, evict the least recently used item
|
||||||
@ -97,10 +97,10 @@ private:
|
|||||||
[&key](const auto& el) { return el.first == key; });
|
[&key](const auto& el) { return el.first == key; });
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t evict() {
|
std::size_t evict() {
|
||||||
// evict item from the end of most recently used list
|
// evict item from the end of most recently used list
|
||||||
typename list_type::iterator i = --m_list.end();
|
typename list_type::iterator i = --m_list.end();
|
||||||
size_t evicted_index = i->second;
|
std::size_t evicted_index = i->second;
|
||||||
m_list.erase(i);
|
m_list.erase(i);
|
||||||
return evicted_index;
|
return evicted_index;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
template <size_t N>
|
template <std::size_t N>
|
||||||
struct StringLiteral {
|
struct StringLiteral {
|
||||||
constexpr StringLiteral(const char (&str)[N]) {
|
constexpr StringLiteral(const char (&str)[N]) {
|
||||||
std::copy_n(str, N, value);
|
std::copy_n(str, N, value);
|
||||||
|
@ -101,7 +101,7 @@ void SetCurrentThreadName(const char* name) {
|
|||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
// Linux limits thread names to 15 characters and will outright reject any
|
// Linux limits thread names to 15 characters and will outright reject any
|
||||||
// attempt to set a longer name with ERANGE.
|
// attempt to set a longer name with ERANGE.
|
||||||
std::string truncated(name, std::min(strlen(name), static_cast<size_t>(15)));
|
std::string truncated(name, std::min(strlen(name), static_cast<std::size_t>(15)));
|
||||||
if (int e = pthread_setname_np(pthread_self(), truncated.c_str())) {
|
if (int e = pthread_setname_np(pthread_self(), truncated.c_str())) {
|
||||||
errno = e;
|
errno = e;
|
||||||
LOG_ERROR(Common, "Failed to set thread name to '{}': {}", truncated, GetLastErrorMsg());
|
LOG_ERROR(Common, "Failed to set thread name to '{}': {}", truncated, GetLastErrorMsg());
|
||||||
|
@ -25,7 +25,7 @@ class StatefulThreadWorker {
|
|||||||
static constexpr bool with_state = !std::is_same_v<StateType, void>;
|
static constexpr bool with_state = !std::is_same_v<StateType, void>;
|
||||||
|
|
||||||
struct DummyCallable {
|
struct DummyCallable {
|
||||||
int operator()(size_t) const noexcept {
|
int operator()(std::size_t) const noexcept {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -33,12 +33,13 @@ class StatefulThreadWorker {
|
|||||||
using Task =
|
using Task =
|
||||||
std::conditional_t<with_state, UniqueFunction<void, StateType*>, UniqueFunction<void>>;
|
std::conditional_t<with_state, UniqueFunction<void, StateType*>, UniqueFunction<void>>;
|
||||||
using StateMaker =
|
using StateMaker =
|
||||||
std::conditional_t<with_state, std::function<StateType(size_t)>, DummyCallable>;
|
std::conditional_t<with_state, std::function<StateType(std::size_t)>, DummyCallable>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit StatefulThreadWorker(size_t num_workers, std::string_view name, StateMaker func = {})
|
explicit StatefulThreadWorker(std::size_t num_workers, std::string_view name,
|
||||||
|
StateMaker func = {})
|
||||||
: workers_queued{num_workers}, thread_name{name} {
|
: workers_queued{num_workers}, thread_name{name} {
|
||||||
const auto lambda = [this, func](std::stop_token stop_token, size_t index) {
|
const auto lambda = [this, func](std::stop_token stop_token, std::size_t index) {
|
||||||
Common::SetCurrentThreadName(thread_name.data());
|
Common::SetCurrentThreadName(thread_name.data());
|
||||||
{
|
{
|
||||||
[[maybe_unused]] std::conditional_t<with_state, StateType, int> state{func(index)};
|
[[maybe_unused]] std::conditional_t<with_state, StateType, int> state{func(index)};
|
||||||
@ -69,7 +70,7 @@ public:
|
|||||||
wait_condition.notify_all();
|
wait_condition.notify_all();
|
||||||
};
|
};
|
||||||
threads.reserve(num_workers);
|
threads.reserve(num_workers);
|
||||||
for (size_t i = 0; i < num_workers; ++i) {
|
for (std::size_t i = 0; i < num_workers; ++i) {
|
||||||
threads.emplace_back(lambda, i);
|
threads.emplace_back(lambda, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,10 +111,10 @@ private:
|
|||||||
std::mutex queue_mutex;
|
std::mutex queue_mutex;
|
||||||
std::condition_variable_any condition;
|
std::condition_variable_any condition;
|
||||||
std::condition_variable wait_condition;
|
std::condition_variable wait_condition;
|
||||||
std::atomic<size_t> work_scheduled{};
|
std::atomic<std::size_t> work_scheduled{};
|
||||||
std::atomic<size_t> work_done{};
|
std::atomic<std::size_t> work_done{};
|
||||||
std::atomic<size_t> workers_stopped{};
|
std::atomic<std::size_t> workers_stopped{};
|
||||||
std::atomic<size_t> workers_queued{};
|
std::atomic<std::size_t> workers_queued{};
|
||||||
std::string_view thread_name;
|
std::string_view thread_name;
|
||||||
std::vector<std::jthread> threads;
|
std::vector<std::jthread> threads;
|
||||||
};
|
};
|
||||||
|
@ -13,8 +13,8 @@ namespace {
|
|||||||
template <Common::StringLiteral haystack, Common::StringLiteral needle>
|
template <Common::StringLiteral haystack, Common::StringLiteral needle>
|
||||||
constexpr u32 GetMatchingBitsFromStringLiteral() {
|
constexpr u32 GetMatchingBitsFromStringLiteral() {
|
||||||
u32 result = 0;
|
u32 result = 0;
|
||||||
for (size_t i = 0; i < haystack.strlen; i++) {
|
for (std::size_t i = 0; i < haystack.strlen; i++) {
|
||||||
for (size_t a = 0; a < needle.strlen; a++) {
|
for (std::size_t a = 0; a < needle.strlen; a++) {
|
||||||
if (haystack.value[i] == needle.value[a]) {
|
if (haystack.value[i] == needle.value[a]) {
|
||||||
result |= 1 << (haystack.strlen - 1 - i);
|
result |= 1 << (haystack.strlen - 1 - i);
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#include "core/cheats/gateway_cheat.h"
|
#include "core/cheats/gateway_cheat.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/process.h"
|
|
||||||
|
|
||||||
namespace Cheats {
|
namespace Cheats {
|
||||||
|
|
||||||
@ -18,11 +17,11 @@ namespace Cheats {
|
|||||||
// we use the same value
|
// we use the same value
|
||||||
constexpr u64 run_interval_ticks = 50'000'000;
|
constexpr u64 run_interval_ticks = 50'000'000;
|
||||||
|
|
||||||
CheatEngine::CheatEngine(u64 title_id_, Core::System& system_)
|
CheatEngine::CheatEngine(Core::System& system_) : system{system_} {}
|
||||||
: system(system_), title_id{title_id_} {
|
|
||||||
LoadCheatFile();
|
CheatEngine::~CheatEngine() {
|
||||||
if (system.IsPoweredOn()) {
|
if (system.IsPoweredOn()) {
|
||||||
Connect();
|
system.CoreTiming().UnscheduleEvent(event, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,24 +32,18 @@ void CheatEngine::Connect() {
|
|||||||
system.CoreTiming().ScheduleEvent(run_interval_ticks, event);
|
system.CoreTiming().ScheduleEvent(run_interval_ticks, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
CheatEngine::~CheatEngine() {
|
std::span<const std::shared_ptr<CheatBase>> CheatEngine::GetCheats() const {
|
||||||
if (system.IsPoweredOn()) {
|
std::shared_lock lock{cheats_list_mutex};
|
||||||
system.CoreTiming().UnscheduleEvent(event, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<CheatBase>> CheatEngine::GetCheats() const {
|
|
||||||
std::shared_lock<std::shared_mutex> lock(cheats_list_mutex);
|
|
||||||
return cheats_list;
|
return cheats_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEngine::AddCheat(const std::shared_ptr<CheatBase>& cheat) {
|
void CheatEngine::AddCheat(std::shared_ptr<CheatBase>&& cheat) {
|
||||||
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
|
std::unique_lock lock{cheats_list_mutex};
|
||||||
cheats_list.push_back(cheat);
|
cheats_list.push_back(std::move(cheat));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEngine::RemoveCheat(std::size_t index) {
|
void CheatEngine::RemoveCheat(std::size_t index) {
|
||||||
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
|
std::unique_lock lock{cheats_list_mutex};
|
||||||
if (index < 0 || index >= cheats_list.size()) {
|
if (index < 0 || index >= cheats_list.size()) {
|
||||||
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
|
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
|
||||||
return;
|
return;
|
||||||
@ -58,16 +51,16 @@ void CheatEngine::RemoveCheat(std::size_t index) {
|
|||||||
cheats_list.erase(cheats_list.begin() + index);
|
cheats_list.erase(cheats_list.begin() + index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEngine::UpdateCheat(std::size_t index, const std::shared_ptr<CheatBase>& new_cheat) {
|
void CheatEngine::UpdateCheat(std::size_t index, std::shared_ptr<CheatBase>&& new_cheat) {
|
||||||
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
|
std::unique_lock lock{cheats_list_mutex};
|
||||||
if (index < 0 || index >= cheats_list.size()) {
|
if (index < 0 || index >= cheats_list.size()) {
|
||||||
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
|
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cheats_list[index] = new_cheat;
|
cheats_list[index] = std::move(new_cheat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEngine::SaveCheatFile() const {
|
void CheatEngine::SaveCheatFile(u64 title_id) const {
|
||||||
const std::string cheat_dir = FileUtil::GetUserPath(FileUtil::UserPath::CheatsDir);
|
const std::string cheat_dir = FileUtil::GetUserPath(FileUtil::UserPath::CheatsDir);
|
||||||
const std::string filepath = fmt::format("{}{:016X}.txt", cheat_dir, title_id);
|
const std::string filepath = fmt::format("{}{:016X}.txt", cheat_dir, title_id);
|
||||||
|
|
||||||
@ -82,7 +75,14 @@ void CheatEngine::SaveCheatFile() const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEngine::LoadCheatFile() {
|
void CheatEngine::LoadCheatFile(u64 title_id) {
|
||||||
|
{
|
||||||
|
std::unique_lock lock{cheats_list_mutex};
|
||||||
|
if (loaded_title_id.has_value() && loaded_title_id == title_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const std::string cheat_dir = FileUtil::GetUserPath(FileUtil::UserPath::CheatsDir);
|
const std::string cheat_dir = FileUtil::GetUserPath(FileUtil::UserPath::CheatsDir);
|
||||||
const std::string filepath = fmt::format("{}{:016X}.txt", cheat_dir, title_id);
|
const std::string filepath = fmt::format("{}{:016X}.txt", cheat_dir, title_id);
|
||||||
|
|
||||||
@ -90,20 +90,22 @@ void CheatEngine::LoadCheatFile() {
|
|||||||
FileUtil::CreateDir(cheat_dir);
|
FileUtil::CreateDir(cheat_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FileUtil::Exists(filepath))
|
if (!FileUtil::Exists(filepath)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto gateway_cheats = GatewayCheat::LoadFile(filepath);
|
auto gateway_cheats = GatewayCheat::LoadFile(filepath);
|
||||||
{
|
{
|
||||||
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
|
std::unique_lock lock{cheats_list_mutex};
|
||||||
std::move(gateway_cheats.begin(), gateway_cheats.end(), std::back_inserter(cheats_list));
|
loaded_title_id = title_id;
|
||||||
|
cheats_list = std::move(gateway_cheats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEngine::RunCallback([[maybe_unused]] std::uintptr_t user_data, s64 cycles_late) {
|
void CheatEngine::RunCallback([[maybe_unused]] std::uintptr_t user_data, s64 cycles_late) {
|
||||||
{
|
{
|
||||||
std::shared_lock<std::shared_mutex> lock(cheats_list_mutex);
|
std::shared_lock lock{cheats_list_mutex};
|
||||||
for (auto& cheat : cheats_list) {
|
for (const auto& cheat : cheats_list) {
|
||||||
if (cheat->IsEnabled()) {
|
if (cheat->IsEnabled()) {
|
||||||
cheat->Execute(system);
|
cheat->Execute(system);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
@ -24,22 +26,39 @@ class CheatBase;
|
|||||||
|
|
||||||
class CheatEngine {
|
class CheatEngine {
|
||||||
public:
|
public:
|
||||||
explicit CheatEngine(u64 title_id_, Core::System& system);
|
explicit CheatEngine(Core::System& system);
|
||||||
~CheatEngine();
|
~CheatEngine();
|
||||||
|
|
||||||
|
/// Registers the cheat execution callback.
|
||||||
void Connect();
|
void Connect();
|
||||||
std::vector<std::shared_ptr<CheatBase>> GetCheats() const;
|
|
||||||
void AddCheat(const std::shared_ptr<CheatBase>& cheat);
|
/// Returns a span of the currently active cheats.
|
||||||
|
std::span<const std::shared_ptr<CheatBase>> GetCheats() const;
|
||||||
|
|
||||||
|
/// Adds a cheat to the cheat engine.
|
||||||
|
void AddCheat(std::shared_ptr<CheatBase>&& cheat);
|
||||||
|
|
||||||
|
/// Removes a cheat at the specified index in the cheats list.
|
||||||
void RemoveCheat(std::size_t index);
|
void RemoveCheat(std::size_t index);
|
||||||
void UpdateCheat(std::size_t index, const std::shared_ptr<CheatBase>& new_cheat);
|
|
||||||
void SaveCheatFile() const;
|
/// Updates a cheat at the specified index in the cheats list.
|
||||||
|
void UpdateCheat(std::size_t index, std::shared_ptr<CheatBase>&& new_cheat);
|
||||||
|
|
||||||
|
/// Loads the cheat file from disk for the specified title id.
|
||||||
|
void LoadCheatFile(u64 title_id);
|
||||||
|
|
||||||
|
/// Saves currently active cheats to file for the specified title id.
|
||||||
|
void SaveCheatFile(u64 title_id) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void LoadCheatFile();
|
/// The cheat execution callback.
|
||||||
void RunCallback(std::uintptr_t user_data, s64 cycles_late);
|
void RunCallback(std::uintptr_t user_data, s64 cycles_late);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Core::System& system;
|
||||||
|
Core::TimingEventType* event;
|
||||||
|
std::optional<u64> loaded_title_id;
|
||||||
std::vector<std::shared_ptr<CheatBase>> cheats_list;
|
std::vector<std::shared_ptr<CheatBase>> cheats_list;
|
||||||
mutable std::shared_mutex cheats_list_mutex;
|
mutable std::shared_mutex cheats_list_mutex;
|
||||||
Core::TimingEventType* event;
|
|
||||||
Core::System& system;
|
|
||||||
u64 title_id;
|
|
||||||
};
|
};
|
||||||
} // namespace Cheats
|
} // namespace Cheats
|
||||||
|
@ -472,8 +472,8 @@ std::string GatewayCheat::ToString() const {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string& filepath) {
|
std::vector<std::shared_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string& filepath) {
|
||||||
std::vector<std::unique_ptr<CheatBase>> cheats;
|
std::vector<std::shared_ptr<CheatBase>> cheats;
|
||||||
|
|
||||||
boost::iostreams::stream<boost::iostreams::file_descriptor_source> file;
|
boost::iostreams::stream<boost::iostreams::file_descriptor_source> file;
|
||||||
FileUtil::OpenFStream<std::ios_base::in>(file, filepath);
|
FileUtil::OpenFStream<std::ios_base::in>(file, filepath);
|
||||||
@ -493,7 +493,7 @@ std::vector<std::unique_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string
|
|||||||
line = Common::StripSpaces(line); // remove spaces at front and end
|
line = Common::StripSpaces(line); // remove spaces at front and end
|
||||||
if (line.length() >= 2 && line.front() == '[') {
|
if (line.length() >= 2 && line.front() == '[') {
|
||||||
if (!cheat_lines.empty()) {
|
if (!cheat_lines.empty()) {
|
||||||
cheats.push_back(std::make_unique<GatewayCheat>(name, cheat_lines, comments));
|
cheats.push_back(std::make_shared<GatewayCheat>(name, cheat_lines, comments));
|
||||||
cheats.back()->SetEnabled(enabled);
|
cheats.back()->SetEnabled(enabled);
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
@ -511,7 +511,7 @@ std::vector<std::unique_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cheat_lines.empty()) {
|
if (!cheat_lines.empty()) {
|
||||||
cheats.push_back(std::make_unique<GatewayCheat>(name, cheat_lines, comments));
|
cheats.push_back(std::make_shared<GatewayCheat>(name, cheat_lines, comments));
|
||||||
cheats.back()->SetEnabled(enabled);
|
cheats.back()->SetEnabled(enabled);
|
||||||
}
|
}
|
||||||
return cheats;
|
return cheats;
|
||||||
|
@ -77,7 +77,7 @@ public:
|
|||||||
/// (there might be multiple lines of those hex numbers)
|
/// (there might be multiple lines of those hex numbers)
|
||||||
/// Comment lines start with a '*'
|
/// Comment lines start with a '*'
|
||||||
/// This function will pares the file for such structures
|
/// This function will pares the file for such structures
|
||||||
static std::vector<std::unique_ptr<CheatBase>> LoadFile(const std::string& filepath);
|
static std::vector<std::shared_ptr<CheatBase>> LoadFile(const std::string& filepath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<bool> enabled = false;
|
std::atomic<bool> enabled = false;
|
||||||
|
@ -72,7 +72,7 @@ Core::Timing& Global() {
|
|||||||
return System::GetInstance().CoreTiming();
|
return System::GetInstance().CoreTiming();
|
||||||
}
|
}
|
||||||
|
|
||||||
System::System() : movie{*this} {}
|
System::System() : movie{*this}, cheat_engine{*this} {}
|
||||||
|
|
||||||
System::~System() = default;
|
System::~System() = default;
|
||||||
|
|
||||||
@ -296,6 +296,20 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
|
|||||||
return init_result;
|
return init_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore any parameters that should be carried through a reset.
|
||||||
|
if (restore_deliver_arg.has_value()) {
|
||||||
|
if (auto apt = Service::APT::GetModule(*this)) {
|
||||||
|
apt->GetAppletManager()->SetDeliverArg(restore_deliver_arg);
|
||||||
|
}
|
||||||
|
restore_deliver_arg.reset();
|
||||||
|
}
|
||||||
|
if (restore_plugin_context.has_value()) {
|
||||||
|
if (auto plg_ldr = Service::PLGLDR::GetService(*this)) {
|
||||||
|
plg_ldr->SetPluginLoaderContext(restore_plugin_context.value());
|
||||||
|
}
|
||||||
|
restore_plugin_context.reset();
|
||||||
|
}
|
||||||
|
|
||||||
telemetry_session->AddInitialInfo(*app_loader);
|
telemetry_session->AddInitialInfo(*app_loader);
|
||||||
std::shared_ptr<Kernel::Process> process;
|
std::shared_ptr<Kernel::Process> process;
|
||||||
const Loader::ResultStatus load_result{app_loader->Load(process)};
|
const Loader::ResultStatus load_result{app_loader->Load(process)};
|
||||||
@ -320,7 +334,10 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
|
|||||||
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
|
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
|
||||||
static_cast<u32>(load_result));
|
static_cast<u32>(load_result));
|
||||||
}
|
}
|
||||||
cheat_engine = std::make_unique<Cheats::CheatEngine>(title_id, *this);
|
|
||||||
|
cheat_engine.LoadCheatFile(title_id);
|
||||||
|
cheat_engine.Connect();
|
||||||
|
|
||||||
perf_stats = std::make_unique<PerfStats>(title_id);
|
perf_stats = std::make_unique<PerfStats>(title_id);
|
||||||
|
|
||||||
if (Settings::values.dump_textures) {
|
if (Settings::values.dump_textures) {
|
||||||
@ -376,7 +393,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
|
|||||||
|
|
||||||
memory = std::make_unique<Memory::MemorySystem>(*this);
|
memory = std::make_unique<Memory::MemorySystem>(*this);
|
||||||
|
|
||||||
timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage.GetValue());
|
timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage.GetValue(),
|
||||||
|
movie.GetOverrideBaseTicks());
|
||||||
|
|
||||||
kernel = std::make_unique<Kernel::KernelSystem>(
|
kernel = std::make_unique<Kernel::KernelSystem>(
|
||||||
*memory, *timing, [this] { PrepareReschedule(); }, memory_mode, num_cores, n3ds_hw_caps,
|
*memory, *timing, [this] { PrepareReschedule(); }, memory_mode, num_cores, n3ds_hw_caps,
|
||||||
@ -446,6 +464,12 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
|
|||||||
gpu->SetInterruptHandler(
|
gpu->SetInterruptHandler(
|
||||||
[gsp](Service::GSP::InterruptId interrupt_id) { gsp->SignalInterrupt(interrupt_id); });
|
[gsp](Service::GSP::InterruptId interrupt_id) { gsp->SignalInterrupt(interrupt_id); });
|
||||||
|
|
||||||
|
auto plg_ldr = Service::PLGLDR::GetService(*this);
|
||||||
|
if (plg_ldr) {
|
||||||
|
plg_ldr->SetEnabled(Settings::values.plugin_loader_enabled.GetValue());
|
||||||
|
plg_ldr->SetAllowGameChangeState(Settings::values.allow_plugin_loader.GetValue());
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG(Core, "Initialized OK");
|
LOG_DEBUG(Core, "Initialized OK");
|
||||||
|
|
||||||
is_powered_on = true;
|
is_powered_on = true;
|
||||||
@ -502,11 +526,11 @@ const Memory::MemorySystem& System::Memory() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Cheats::CheatEngine& System::CheatEngine() {
|
Cheats::CheatEngine& System::CheatEngine() {
|
||||||
return *cheat_engine;
|
return cheat_engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Cheats::CheatEngine& System::CheatEngine() const {
|
const Cheats::CheatEngine& System::CheatEngine() const {
|
||||||
return *cheat_engine;
|
return cheat_engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::RegisterVideoDumper(std::shared_ptr<VideoDumper::Backend> dumper) {
|
void System::RegisterVideoDumper(std::shared_ptr<VideoDumper::Backend> dumper) {
|
||||||
@ -560,7 +584,6 @@ void System::Shutdown(bool is_deserializing) {
|
|||||||
if (!is_deserializing) {
|
if (!is_deserializing) {
|
||||||
GDBStub::Shutdown();
|
GDBStub::Shutdown();
|
||||||
perf_stats.reset();
|
perf_stats.reset();
|
||||||
cheat_engine.reset();
|
|
||||||
app_loader.reset();
|
app_loader.reset();
|
||||||
}
|
}
|
||||||
custom_tex_manager.reset();
|
custom_tex_manager.reset();
|
||||||
@ -599,10 +622,13 @@ void System::Reset() {
|
|||||||
// reloading.
|
// reloading.
|
||||||
// TODO: Properly implement the reset
|
// TODO: Properly implement the reset
|
||||||
|
|
||||||
// Since the system is completely reinitialized, we'll have to store the deliver arg manually.
|
// Save the APT deliver arg and plugin loader context across resets.
|
||||||
boost::optional<Service::APT::DeliverArg> deliver_arg;
|
// This is needed as we don't currently support proper app jumping.
|
||||||
if (auto apt = Service::APT::GetModule(*this)) {
|
if (auto apt = Service::APT::GetModule(*this)) {
|
||||||
deliver_arg = apt->GetAppletManager()->ReceiveDeliverArg();
|
restore_deliver_arg = apt->GetAppletManager()->ReceiveDeliverArg();
|
||||||
|
}
|
||||||
|
if (auto plg_ldr = Service::PLGLDR::GetService(*this)) {
|
||||||
|
restore_plugin_context = plg_ldr->GetPluginLoaderContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
Shutdown();
|
Shutdown();
|
||||||
@ -615,11 +641,6 @@ void System::Reset() {
|
|||||||
// Reload the system with the same setting
|
// Reload the system with the same setting
|
||||||
[[maybe_unused]] const System::ResultStatus result =
|
[[maybe_unused]] const System::ResultStatus result =
|
||||||
Load(*m_emu_window, m_filepath, m_secondary_window);
|
Load(*m_emu_window, m_filepath, m_secondary_window);
|
||||||
|
|
||||||
// Restore the deliver arg.
|
|
||||||
if (auto apt = Service::APT::GetModule(*this)) {
|
|
||||||
apt->GetAppletManager()->SetDeliverArg(std::move(deliver_arg));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::ApplySettings() {
|
void System::ApplySettings() {
|
||||||
@ -664,9 +685,11 @@ void System::ApplySettings() {
|
|||||||
Service::MIC::ReloadMic(*this);
|
Service::MIC::ReloadMic(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::PLGLDR::PLG_LDR::SetEnabled(Settings::values.plugin_loader_enabled.GetValue());
|
auto plg_ldr = Service::PLGLDR::GetService(*this);
|
||||||
Service::PLGLDR::PLG_LDR::SetAllowGameChangeState(
|
if (plg_ldr) {
|
||||||
Settings::values.allow_plugin_loader.GetValue());
|
plg_ldr->SetEnabled(Settings::values.plugin_loader_enabled.GetValue());
|
||||||
|
plg_ldr->SetAllowGameChangeState(Settings::values.allow_plugin_loader.GetValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
@ -718,7 +741,7 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
|
|||||||
if (Archive::is_loading::value) {
|
if (Archive::is_loading::value) {
|
||||||
timing->UnlockEventQueue();
|
timing->UnlockEventQueue();
|
||||||
memory->SetDSP(*dsp_core);
|
memory->SetDSP(*dsp_core);
|
||||||
cheat_engine->Connect();
|
cheat_engine.Connect();
|
||||||
gpu->Sync();
|
gpu->Sync();
|
||||||
|
|
||||||
// Re-register gpu callback, because gsp service changed after service_manager got
|
// Re-register gpu callback, because gsp service changed after service_manager got
|
||||||
|
@ -8,9 +8,13 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
#include <boost/serialization/version.hpp>
|
#include <boost/serialization/version.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
|
#include "core/cheats/cheats.h"
|
||||||
|
#include "core/hle/service/apt/applet_manager.h"
|
||||||
|
#include "core/hle/service/plgldr/plgldr.h"
|
||||||
#include "core/movie.h"
|
#include "core/movie.h"
|
||||||
#include "core/perf_stats.h"
|
#include "core/perf_stats.h"
|
||||||
|
|
||||||
@ -48,10 +52,6 @@ struct New3dsHwCapabilities;
|
|||||||
enum class MemoryMode : u8;
|
enum class MemoryMode : u8;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
namespace Cheats {
|
|
||||||
class CheatEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace VideoDumper {
|
namespace VideoDumper {
|
||||||
class Backend;
|
class Backend;
|
||||||
}
|
}
|
||||||
@ -401,7 +401,7 @@ private:
|
|||||||
Core::Movie movie;
|
Core::Movie movie;
|
||||||
|
|
||||||
/// Cheats manager
|
/// Cheats manager
|
||||||
std::unique_ptr<Cheats::CheatEngine> cheat_engine;
|
Cheats::CheatEngine cheat_engine;
|
||||||
|
|
||||||
/// Video dumper backend
|
/// Video dumper backend
|
||||||
std::shared_ptr<VideoDumper::Backend> video_dumper;
|
std::shared_ptr<VideoDumper::Backend> video_dumper;
|
||||||
@ -447,6 +447,9 @@ private:
|
|||||||
std::function<bool()> mic_permission_func;
|
std::function<bool()> mic_permission_func;
|
||||||
bool mic_permission_granted = false;
|
bool mic_permission_granted = false;
|
||||||
|
|
||||||
|
boost::optional<Service::APT::DeliverArg> restore_deliver_arg;
|
||||||
|
boost::optional<Service::PLGLDR::PLG_LDR::PluginLoaderContext> restore_plugin_context;
|
||||||
|
|
||||||
friend class boost::serialization::access;
|
friend class boost::serialization::access;
|
||||||
template <typename Archive>
|
template <typename Archive>
|
||||||
void serialize(Archive& ar, const unsigned int file_version);
|
void serialize(Archive& ar, const unsigned int file_version);
|
||||||
|
@ -3,9 +3,11 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/settings.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@ -19,15 +21,28 @@ bool Timing::Event::operator<(const Timing::Event& right) const {
|
|||||||
return std::tie(time, fifo_order) < std::tie(right.time, right.fifo_order);
|
return std::tie(time, fifo_order) < std::tie(right.time, right.fifo_order);
|
||||||
}
|
}
|
||||||
|
|
||||||
Timing::Timing(std::size_t num_cores, u32 cpu_clock_percentage) {
|
Timing::Timing(std::size_t num_cores, u32 cpu_clock_percentage, s64 override_base_ticks) {
|
||||||
|
// Generate non-zero base tick count to simulate time the system ran before launching the game.
|
||||||
|
// This accounts for games that rely on the system tick to seed randomness.
|
||||||
|
const auto base_ticks = override_base_ticks >= 0 ? override_base_ticks : GenerateBaseTicks();
|
||||||
|
|
||||||
timers.resize(num_cores);
|
timers.resize(num_cores);
|
||||||
for (std::size_t i = 0; i < num_cores; ++i) {
|
for (std::size_t i = 0; i < num_cores; ++i) {
|
||||||
timers[i] = std::make_shared<Timer>();
|
timers[i] = std::make_shared<Timer>(base_ticks);
|
||||||
}
|
}
|
||||||
UpdateClockSpeed(cpu_clock_percentage);
|
UpdateClockSpeed(cpu_clock_percentage);
|
||||||
current_timer = timers[0].get();
|
current_timer = timers[0].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s64 Timing::GenerateBaseTicks() {
|
||||||
|
if (Settings::values.init_ticks_type.GetValue() == Settings::InitTicks::Fixed) {
|
||||||
|
return Settings::values.init_ticks_override.GetValue();
|
||||||
|
}
|
||||||
|
// Bounded to 32 bits to make sure we don't generate too high of a counter and risk overflowing.
|
||||||
|
std::mt19937 random_gen(std::random_device{}());
|
||||||
|
return random_gen();
|
||||||
|
}
|
||||||
|
|
||||||
void Timing::UpdateClockSpeed(u32 cpu_clock_percentage) {
|
void Timing::UpdateClockSpeed(u32 cpu_clock_percentage) {
|
||||||
for (auto& timer : timers) {
|
for (auto& timer : timers) {
|
||||||
timer->cpu_clock_scale = 100.0 / cpu_clock_percentage;
|
timer->cpu_clock_scale = 100.0 / cpu_clock_percentage;
|
||||||
@ -146,7 +161,7 @@ std::shared_ptr<Timing::Timer> Timing::GetTimer(std::size_t cpu_id) {
|
|||||||
return timers[cpu_id];
|
return timers[cpu_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
Timing::Timer::Timer() = default;
|
Timing::Timer::Timer(s64 base_ticks) : executed_ticks(base_ticks) {}
|
||||||
|
|
||||||
Timing::Timer::~Timer() {
|
Timing::Timer::~Timer() {
|
||||||
MoveEvents();
|
MoveEvents();
|
||||||
|
@ -185,7 +185,7 @@ public:
|
|||||||
|
|
||||||
class Timer {
|
class Timer {
|
||||||
public:
|
public:
|
||||||
Timer();
|
Timer(s64 base_ticks = 0);
|
||||||
~Timer();
|
~Timer();
|
||||||
|
|
||||||
s64 GetMaxSliceLength() const;
|
s64 GetMaxSliceLength() const;
|
||||||
@ -249,7 +249,7 @@ public:
|
|||||||
friend class boost::serialization::access;
|
friend class boost::serialization::access;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Timing(std::size_t num_cores, u32 cpu_clock_percentage);
|
explicit Timing(std::size_t num_cores, u32 cpu_clock_percentage, s64 override_base_ticks = -1);
|
||||||
|
|
||||||
~Timing(){};
|
~Timing(){};
|
||||||
|
|
||||||
@ -290,6 +290,9 @@ public:
|
|||||||
event_queue_locked = false;
|
event_queue_locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates a random tick count to seed the system tick timer with.
|
||||||
|
static s64 GenerateBaseTicks();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// unordered_map stores each element separately as a linked list node so pointers to
|
// unordered_map stores each element separately as a linked list node so pointers to
|
||||||
// elements remain stable regardless of rehashes/resizing.
|
// elements remain stable regardless of rehashes/resizing.
|
||||||
|
@ -1073,7 +1073,7 @@ std::vector<FormatInfo> ListFormats() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
out.push_back({current->name, ToStdString(current->long_name), std::move(extensions),
|
out.push_back({current->name, ToStdString(current->long_name), extensions,
|
||||||
std::move(supported_video_codecs), std::move(supported_audio_codecs),
|
std::move(supported_video_codecs), std::move(supported_audio_codecs),
|
||||||
GetOptionList(current->priv_class, true)});
|
GetOptionList(current->priv_class, true)});
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ public:
|
|||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
* @return Result of the operation
|
* @return Result of the operation
|
||||||
*/
|
*/
|
||||||
virtual ResultCode DeleteFile(const Path& path) const = 0;
|
virtual Result DeleteFile(const Path& path) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rename a File specified by its path
|
* Rename a File specified by its path
|
||||||
@ -135,21 +135,21 @@ public:
|
|||||||
* @param dest_path Destination path relative to the archive
|
* @param dest_path Destination path relative to the archive
|
||||||
* @return Result of the operation
|
* @return Result of the operation
|
||||||
*/
|
*/
|
||||||
virtual ResultCode RenameFile(const Path& src_path, const Path& dest_path) const = 0;
|
virtual Result RenameFile(const Path& src_path, const Path& dest_path) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a directory specified by its path
|
* Delete a directory specified by its path
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
* @return Result of the operation
|
* @return Result of the operation
|
||||||
*/
|
*/
|
||||||
virtual ResultCode DeleteDirectory(const Path& path) const = 0;
|
virtual Result DeleteDirectory(const Path& path) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a directory specified by its path and anything under it
|
* Delete a directory specified by its path and anything under it
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
* @return Result of the operation
|
* @return Result of the operation
|
||||||
*/
|
*/
|
||||||
virtual ResultCode DeleteDirectoryRecursively(const Path& path) const = 0;
|
virtual Result DeleteDirectoryRecursively(const Path& path) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a file specified by its path
|
* Create a file specified by its path
|
||||||
@ -157,14 +157,14 @@ public:
|
|||||||
* @param size The size of the new file, filled with zeroes
|
* @param size The size of the new file, filled with zeroes
|
||||||
* @return Result of the operation
|
* @return Result of the operation
|
||||||
*/
|
*/
|
||||||
virtual ResultCode CreateFile(const Path& path, u64 size) const = 0;
|
virtual Result CreateFile(const Path& path, u64 size) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a directory specified by its path
|
* Create a directory specified by its path
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
* @return Result of the operation
|
* @return Result of the operation
|
||||||
*/
|
*/
|
||||||
virtual ResultCode CreateDirectory(const Path& path) const = 0;
|
virtual Result CreateDirectory(const Path& path) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rename a Directory specified by its path
|
* Rename a Directory specified by its path
|
||||||
@ -172,7 +172,7 @@ public:
|
|||||||
* @param dest_path Destination path relative to the archive
|
* @param dest_path Destination path relative to the archive
|
||||||
* @return Result of the operation
|
* @return Result of the operation
|
||||||
*/
|
*/
|
||||||
virtual ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const = 0;
|
virtual Result RenameDirectory(const Path& src_path, const Path& dest_path) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a directory specified by its path
|
* Open a directory specified by its path
|
||||||
@ -229,10 +229,10 @@ public:
|
|||||||
* @param path Path to the archive
|
* @param path Path to the archive
|
||||||
* @param format_info Format information for the new archive
|
* @param format_info Format information for the new archive
|
||||||
* @param program_id the program ID of the client that requests the operation
|
* @param program_id the program ID of the client that requests the operation
|
||||||
* @return ResultCode of the operation, 0 on success
|
* @return Result of the operation, 0 on success
|
||||||
*/
|
*/
|
||||||
virtual ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
virtual Result Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) = 0;
|
u64 program_id) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the format info about the archive with the specified path
|
* Retrieves the format info about the archive with the specified path
|
||||||
|
@ -40,7 +40,7 @@ public:
|
|||||||
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush,
|
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush,
|
||||||
const u8* buffer) override {
|
const u8* buffer) override {
|
||||||
if (offset > size) {
|
if (offset > size) {
|
||||||
return ERR_WRITE_BEYOND_END;
|
return ResultWriteBeyondEnd;
|
||||||
} else if (offset == size) {
|
} else if (offset == size) {
|
||||||
return 0ULL;
|
return 0ULL;
|
||||||
}
|
}
|
||||||
@ -108,17 +108,17 @@ public:
|
|||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode.hex == 0) {
|
if (mode.hex == 0) {
|
||||||
LOG_ERROR(Service_FS, "Empty open mode");
|
LOG_ERROR(Service_FS, "Empty open mode");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode.create_flag) {
|
if (mode.create_flag) {
|
||||||
LOG_ERROR(Service_FS, "Create flag is not supported");
|
LOG_ERROR(Service_FS, "Create flag is not supported");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
@ -126,17 +126,17 @@ public:
|
|||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ResultFileNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
||||||
return ERROR_PATH_NOT_FOUND;
|
return ResultPathNotFound;
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
LOG_ERROR(Service_FS, "Unexpected file or directory in {}", full_path);
|
LOG_ERROR(Service_FS, "Unexpected file or directory in {}", full_path);
|
||||||
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
|
return ResultUnexpectedFileOrDirectory;
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
LOG_ERROR(Service_FS, "{} not found", full_path);
|
LOG_ERROR(Service_FS, "{} not found", full_path);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ResultFileNotFound;
|
||||||
case PathParser::FileFound:
|
case PathParser::FileFound:
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ public:
|
|||||||
FileUtil::IOFile file(full_path, "r+b");
|
FileUtil::IOFile file(full_path, "r+b");
|
||||||
if (!file.IsOpen()) {
|
if (!file.IsOpen()) {
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening {}", full_path);
|
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening {}", full_path);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ResultFileNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mode rwmode;
|
Mode rwmode;
|
||||||
@ -155,10 +155,10 @@ public:
|
|||||||
std::move(delay_generator));
|
std::move(delay_generator));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode CreateFile(const Path& path, u64 size) const override {
|
Result CreateFile(const Path& path, u64 size) const override {
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
LOG_ERROR(Service_FS, "Zero-size file is not supported");
|
LOG_ERROR(Service_FS, "Zero-size file is not supported");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
return SaveDataArchive::CreateFile(path, size);
|
return SaveDataArchive::CreateFile(path, size);
|
||||||
}
|
}
|
||||||
@ -250,18 +250,18 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(cons
|
|||||||
// TODO(Subv): Verify the archive behavior of SharedExtSaveData compared to ExtSaveData.
|
// TODO(Subv): Verify the archive behavior of SharedExtSaveData compared to ExtSaveData.
|
||||||
// ExtSaveData seems to return FS_NotFound (120) when the archive doesn't exist.
|
// ExtSaveData seems to return FS_NotFound (120) when the archive doesn't exist.
|
||||||
if (type != ExtSaveDataType::Shared) {
|
if (type != ExtSaveDataType::Shared) {
|
||||||
return ERR_NOT_FOUND_INVALID_STATE;
|
return ResultNotFoundInvalidState;
|
||||||
} else {
|
} else {
|
||||||
return ERR_NOT_FORMATTED;
|
return ResultNotFormatted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<ExtSaveDataDelayGenerator>();
|
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<ExtSaveDataDelayGenerator>();
|
||||||
return std::make_unique<ExtSaveDataArchive>(fullpath, std::move(delay_generator));
|
return std::make_unique<ExtSaveDataArchive>(fullpath, std::move(delay_generator));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path,
|
Result ArchiveFactory_ExtSaveData::Format(const Path& path,
|
||||||
const FileSys::ArchiveFormatInfo& format_info,
|
const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) {
|
u64 program_id) {
|
||||||
auto corrected_path = GetCorrectedPath(path);
|
auto corrected_path = GetCorrectedPath(path);
|
||||||
|
|
||||||
// These folders are always created with the ExtSaveData
|
// These folders are always created with the ExtSaveData
|
||||||
@ -276,11 +276,11 @@ ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path,
|
|||||||
|
|
||||||
if (!file.IsOpen()) {
|
if (!file.IsOpen()) {
|
||||||
// TODO(Subv): Find the correct error code
|
// TODO(Subv): Find the correct error code
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.WriteBytes(&format_info, sizeof(format_info));
|
file.WriteBytes(&format_info, sizeof(format_info));
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Path& path,
|
ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Path& path,
|
||||||
@ -291,7 +291,7 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Pat
|
|||||||
if (!file.IsOpen()) {
|
if (!file.IsOpen()) {
|
||||||
LOG_ERROR(Service_FS, "Could not open metadata information for archive");
|
LOG_ERROR(Service_FS, "Could not open metadata information for archive");
|
||||||
// TODO(Subv): Verify error code
|
// TODO(Subv): Verify error code
|
||||||
return ERR_NOT_FORMATTED;
|
return ResultNotFormatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArchiveFormatInfo info = {};
|
ArchiveFormatInfo info = {};
|
||||||
|
@ -31,8 +31,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
||||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
Result Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) override;
|
u64 program_id) override;
|
||||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||||
|
|
||||||
const std::string& GetMountPoint() const {
|
const std::string& GetMountPoint() const {
|
||||||
|
@ -73,13 +73,13 @@ ResultVal<std::unique_ptr<FileBackend>> NCCHArchive::OpenFile(const Path& path,
|
|||||||
const Mode& mode) const {
|
const Mode& mode) const {
|
||||||
if (path.GetType() != LowPathType::Binary) {
|
if (path.GetType() != LowPathType::Binary) {
|
||||||
LOG_ERROR(Service_FS, "Path need to be Binary");
|
LOG_ERROR(Service_FS, "Path need to be Binary");
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> binary = path.AsBinary();
|
std::vector<u8> binary = path.AsBinary();
|
||||||
if (binary.size() != sizeof(NCCHFilePath)) {
|
if (binary.size() != sizeof(NCCHFilePath)) {
|
||||||
LOG_ERROR(Service_FS, "Wrong path size {}", binary.size());
|
LOG_ERROR(Service_FS, "Wrong path size {}", binary.size());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
NCCHFilePath openfile_path;
|
NCCHFilePath openfile_path;
|
||||||
@ -174,63 +174,63 @@ ResultVal<std::unique_ptr<FileBackend>> NCCHArchive::OpenFile(const Path& path,
|
|||||||
return std::make_unique<IVFCFileInMemory>(std::move(archive_data), romfs_offset,
|
return std::make_unique<IVFCFileInMemory>(std::move(archive_data), romfs_offset,
|
||||||
romfs_size, std::move(delay_generator));
|
romfs_size, std::move(delay_generator));
|
||||||
}
|
}
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NCCHArchive::DeleteFile(const Path& path) const {
|
Result NCCHArchive::DeleteFile(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a file from an NCCH archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to delete a file from an NCCH archive ({}).", GetName());
|
||||||
// TODO(Subv): Verify error code
|
// TODO(Subv): Verify error code
|
||||||
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled,
|
return Result(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled,
|
||||||
ErrorLevel::Status);
|
ErrorLevel::Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NCCHArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
Result NCCHArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an NCCH archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an NCCH archive ({}).", GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NCCHArchive::DeleteDirectory(const Path& path) const {
|
Result NCCHArchive::DeleteDirectory(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an NCCH archive ({}).",
|
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an NCCH archive ({}).",
|
||||||
GetName());
|
GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NCCHArchive::DeleteDirectoryRecursively(const Path& path) const {
|
Result NCCHArchive::DeleteDirectoryRecursively(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an NCCH archive ({}).",
|
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an NCCH archive ({}).",
|
||||||
GetName());
|
GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NCCHArchive::CreateFile(const Path& path, u64 size) const {
|
Result NCCHArchive::CreateFile(const Path& path, u64 size) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to create a file in an NCCH archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to create a file in an NCCH archive ({}).", GetName());
|
||||||
// TODO: Verify error code
|
// TODO: Verify error code
|
||||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported,
|
return Result(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported,
|
||||||
ErrorLevel::Permanent);
|
ErrorLevel::Permanent);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NCCHArchive::CreateDirectory(const Path& path) const {
|
Result NCCHArchive::CreateDirectory(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an NCCH archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an NCCH archive ({}).", GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NCCHArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
Result NCCHArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an NCCH archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an NCCH archive ({}).", GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<DirectoryBackend>> NCCHArchive::OpenDirectory(const Path& path) const {
|
ResultVal<std::unique_ptr<DirectoryBackend>> NCCHArchive::OpenDirectory(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to open a directory within an NCCH archive ({}).",
|
LOG_CRITICAL(Service_FS, "Attempted to open a directory within an NCCH archive ({}).",
|
||||||
GetName().c_str());
|
GetName().c_str());
|
||||||
// TODO(shinyquagsire23): Use correct error code
|
// TODO(shinyquagsire23): Use correct error code
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 NCCHArchive::GetFreeBytes() const {
|
u64 NCCHArchive::GetFreeBytes() const {
|
||||||
@ -276,13 +276,13 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_NCCH::Open(const Path&
|
|||||||
u64 program_id) {
|
u64 program_id) {
|
||||||
if (path.GetType() != LowPathType::Binary) {
|
if (path.GetType() != LowPathType::Binary) {
|
||||||
LOG_ERROR(Service_FS, "Path need to be Binary");
|
LOG_ERROR(Service_FS, "Path need to be Binary");
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> binary = path.AsBinary();
|
std::vector<u8> binary = path.AsBinary();
|
||||||
if (binary.size() != sizeof(NCCHArchivePath)) {
|
if (binary.size() != sizeof(NCCHArchivePath)) {
|
||||||
LOG_ERROR(Service_FS, "Wrong path size {}", binary.size());
|
LOG_ERROR(Service_FS, "Wrong path size {}", binary.size());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
NCCHArchivePath open_path;
|
NCCHArchivePath open_path;
|
||||||
@ -292,20 +292,19 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_NCCH::Open(const Path&
|
|||||||
open_path.tid, static_cast<Service::FS::MediaType>(open_path.media_type & 0xFF));
|
open_path.tid, static_cast<Service::FS::MediaType>(open_path.media_type & 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_NCCH::Format(const Path& path,
|
Result ArchiveFactory_NCCH::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||||
const FileSys::ArchiveFormatInfo& format_info,
|
u64 program_id) {
|
||||||
u64 program_id) {
|
|
||||||
LOG_ERROR(Service_FS, "Attempted to format a NCCH archive.");
|
LOG_ERROR(Service_FS, "Attempted to format a NCCH archive.");
|
||||||
// TODO: Verify error code
|
// TODO: Verify error code
|
||||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported,
|
return Result(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported,
|
||||||
ErrorLevel::Permanent);
|
ErrorLevel::Permanent);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<ArchiveFormatInfo> ArchiveFactory_NCCH::GetFormatInfo(const Path& path,
|
ResultVal<ArchiveFormatInfo> ArchiveFactory_NCCH::GetFormatInfo(const Path& path,
|
||||||
u64 program_id) const {
|
u64 program_id) const {
|
||||||
// TODO(Subv): Implement
|
// TODO(Subv): Implement
|
||||||
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
@ -50,13 +50,13 @@ public:
|
|||||||
|
|
||||||
ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
|
ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
|
||||||
const Mode& mode) const override;
|
const Mode& mode) const override;
|
||||||
ResultCode DeleteFile(const Path& path) const override;
|
Result DeleteFile(const Path& path) const override;
|
||||||
ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override;
|
Result RenameFile(const Path& src_path, const Path& dest_path) const override;
|
||||||
ResultCode DeleteDirectory(const Path& path) const override;
|
Result DeleteDirectory(const Path& path) const override;
|
||||||
ResultCode DeleteDirectoryRecursively(const Path& path) const override;
|
Result DeleteDirectoryRecursively(const Path& path) const override;
|
||||||
ResultCode CreateFile(const Path& path, u64 size) const override;
|
Result CreateFile(const Path& path, u64 size) const override;
|
||||||
ResultCode CreateDirectory(const Path& path) const override;
|
Result CreateDirectory(const Path& path) const override;
|
||||||
ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
|
Result RenameDirectory(const Path& src_path, const Path& dest_path) const override;
|
||||||
ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
|
ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
|
||||||
u64 GetFreeBytes() const override;
|
u64 GetFreeBytes() const override;
|
||||||
|
|
||||||
@ -114,8 +114,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
||||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
Result Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) override;
|
u64 program_id) override;
|
||||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -25,14 +25,14 @@ template <typename T>
|
|||||||
ResultVal<std::tuple<MediaType, u64>> ParsePath(const Path& path, T program_id_reader) {
|
ResultVal<std::tuple<MediaType, u64>> ParsePath(const Path& path, T program_id_reader) {
|
||||||
if (path.GetType() != LowPathType::Binary) {
|
if (path.GetType() != LowPathType::Binary) {
|
||||||
LOG_ERROR(Service_FS, "Wrong path type {}", path.GetType());
|
LOG_ERROR(Service_FS, "Wrong path type {}", path.GetType());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> vec_data = path.AsBinary();
|
std::vector<u8> vec_data = path.AsBinary();
|
||||||
|
|
||||||
if (vec_data.size() != 12) {
|
if (vec_data.size() != 12) {
|
||||||
LOG_ERROR(Service_FS, "Wrong path length {}", vec_data.size());
|
LOG_ERROR(Service_FS, "Wrong path length {}", vec_data.size());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32* data = reinterpret_cast<const u32*>(vec_data.data());
|
const u32* data = reinterpret_cast<const u32*>(vec_data.data());
|
||||||
@ -42,7 +42,7 @@ ResultVal<std::tuple<MediaType, u64>> ParsePath(const Path& path, T program_id_r
|
|||||||
LOG_ERROR(Service_FS, "Unsupported media type {}", media_type);
|
LOG_ERROR(Service_FS, "Unsupported media type {}", media_type);
|
||||||
|
|
||||||
// Note: this is strange, but the error code was verified with a real 3DS
|
// Note: this is strange, but the error code was verified with a real 3DS
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_tuple(media_type, program_id_reader(data));
|
return std::make_tuple(media_type, program_id_reader(data));
|
||||||
@ -72,16 +72,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_OtherSaveDataPermitted
|
|||||||
|
|
||||||
if (media_type == MediaType::GameCard) {
|
if (media_type == MediaType::GameCard) {
|
||||||
LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
|
LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
|
||||||
return ERROR_GAMECARD_NOT_INSERTED;
|
return ResultGamecardNotInserted;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd_savedata_source->Open(program_id);
|
return sd_savedata_source->Open(program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_OtherSaveDataPermitted::Format(
|
Result ArchiveFactory_OtherSaveDataPermitted::Format(const Path& path,
|
||||||
const Path& path, const FileSys::ArchiveFormatInfo& format_info, u64 program_id) {
|
const FileSys::ArchiveFormatInfo& format_info,
|
||||||
|
u64 program_id) {
|
||||||
LOG_ERROR(Service_FS, "Attempted to format a OtherSaveDataPermitted archive.");
|
LOG_ERROR(Service_FS, "Attempted to format a OtherSaveDataPermitted archive.");
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<ArchiveFormatInfo> ArchiveFactory_OtherSaveDataPermitted::GetFormatInfo(
|
ResultVal<ArchiveFormatInfo> ArchiveFactory_OtherSaveDataPermitted::GetFormatInfo(
|
||||||
@ -92,7 +93,7 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_OtherSaveDataPermitted::GetFormatInf
|
|||||||
|
|
||||||
if (media_type == MediaType::GameCard) {
|
if (media_type == MediaType::GameCard) {
|
||||||
LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
|
LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
|
||||||
return ERROR_GAMECARD_NOT_INSERTED;
|
return ResultGamecardNotInserted;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd_savedata_source->GetFormatInfo(program_id);
|
return sd_savedata_source->GetFormatInfo(program_id);
|
||||||
@ -110,21 +111,22 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_OtherSaveDataGeneral::
|
|||||||
|
|
||||||
if (media_type == MediaType::GameCard) {
|
if (media_type == MediaType::GameCard) {
|
||||||
LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
|
LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
|
||||||
return ERROR_GAMECARD_NOT_INSERTED;
|
return ResultGamecardNotInserted;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd_savedata_source->Open(program_id);
|
return sd_savedata_source->Open(program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_OtherSaveDataGeneral::Format(
|
Result ArchiveFactory_OtherSaveDataGeneral::Format(const Path& path,
|
||||||
const Path& path, const FileSys::ArchiveFormatInfo& format_info, u64 /*client_program_id*/) {
|
const FileSys::ArchiveFormatInfo& format_info,
|
||||||
|
u64 /*client_program_id*/) {
|
||||||
MediaType media_type;
|
MediaType media_type;
|
||||||
u64 program_id;
|
u64 program_id;
|
||||||
CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path));
|
CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path));
|
||||||
|
|
||||||
if (media_type == MediaType::GameCard) {
|
if (media_type == MediaType::GameCard) {
|
||||||
LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
|
LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
|
||||||
return ERROR_GAMECARD_NOT_INSERTED;
|
return ResultGamecardNotInserted;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd_savedata_source->Format(program_id, format_info);
|
return sd_savedata_source->Format(program_id, format_info);
|
||||||
@ -138,7 +140,7 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_OtherSaveDataGeneral::GetFormatInfo(
|
|||||||
|
|
||||||
if (media_type == MediaType::GameCard) {
|
if (media_type == MediaType::GameCard) {
|
||||||
LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
|
LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
|
||||||
return ERROR_GAMECARD_NOT_INSERTED;
|
return ResultGamecardNotInserted;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd_savedata_source->GetFormatInfo(program_id);
|
return sd_savedata_source->GetFormatInfo(program_id);
|
||||||
|
@ -22,8 +22,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
||||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
Result Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) override;
|
u64 program_id) override;
|
||||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -49,8 +49,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
||||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
Result Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) override;
|
u64 program_id) override;
|
||||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -21,9 +21,9 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const P
|
|||||||
return sd_savedata_source->Open(program_id);
|
return sd_savedata_source->Open(program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_SaveData::Format(const Path& path,
|
Result ArchiveFactory_SaveData::Format(const Path& path,
|
||||||
const FileSys::ArchiveFormatInfo& format_info,
|
const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) {
|
u64 program_id) {
|
||||||
return sd_savedata_source->Format(program_id, format_info);
|
return sd_savedata_source->Format(program_id, format_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,8 +20,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
||||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
Result Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) override;
|
u64 program_id) override;
|
||||||
|
|
||||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||||
|
|
||||||
|
@ -62,17 +62,17 @@ ResultVal<std::unique_ptr<FileBackend>> SDMCArchive::OpenFileBase(const Path& pa
|
|||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode.hex == 0) {
|
if (mode.hex == 0) {
|
||||||
LOG_ERROR(Service_FS, "Empty open mode");
|
LOG_ERROR(Service_FS, "Empty open mode");
|
||||||
return ERROR_INVALID_OPEN_FLAGS;
|
return ResultInvalidOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode.create_flag && !mode.write_flag) {
|
if (mode.create_flag && !mode.write_flag) {
|
||||||
LOG_ERROR(Service_FS, "Create flag set but write flag not set");
|
LOG_ERROR(Service_FS, "Create flag set but write flag not set");
|
||||||
return ERROR_INVALID_OPEN_FLAGS;
|
return ResultInvalidOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
@ -80,19 +80,19 @@ ResultVal<std::unique_ptr<FileBackend>> SDMCArchive::OpenFileBase(const Path& pa
|
|||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
LOG_ERROR(Service_FS, "{} is not a file", full_path);
|
LOG_ERROR(Service_FS, "{} is not a file", full_path);
|
||||||
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC;
|
return ResultUnexpectedFileOrDirectorySdmc;
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
if (!mode.create_flag) {
|
if (!mode.create_flag) {
|
||||||
LOG_ERROR(Service_FS, "Non-existing file {} can't be open without mode create.",
|
LOG_ERROR(Service_FS, "Non-existing file {} can't be open without mode create.",
|
||||||
full_path);
|
full_path);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
} else {
|
} else {
|
||||||
// Create the file
|
// Create the file
|
||||||
FileUtil::CreateEmptyFile(full_path);
|
FileUtil::CreateEmptyFile(full_path);
|
||||||
@ -105,19 +105,19 @@ ResultVal<std::unique_ptr<FileBackend>> SDMCArchive::OpenFileBase(const Path& pa
|
|||||||
FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb");
|
FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb");
|
||||||
if (!file.IsOpen()) {
|
if (!file.IsOpen()) {
|
||||||
LOG_CRITICAL(Service_FS, "Error opening {}: {}", full_path, Common::GetLastErrorMsg());
|
LOG_CRITICAL(Service_FS, "Error opening {}: {}", full_path, Common::GetLastErrorMsg());
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<SDMCDelayGenerator>();
|
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<SDMCDelayGenerator>();
|
||||||
return std::make_unique<DiskFile>(std::move(file), mode, std::move(delay_generator));
|
return std::make_unique<DiskFile>(std::move(file), mode, std::move(delay_generator));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SDMCArchive::DeleteFile(const Path& path) const {
|
Result SDMCArchive::DeleteFile(const Path& path) const {
|
||||||
const PathParser path_parser(path);
|
const PathParser path_parser(path);
|
||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
@ -125,110 +125,109 @@ ResultCode SDMCArchive::DeleteFile(const Path& path) const {
|
|||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
LOG_DEBUG(Service_FS, "{} not found", full_path);
|
LOG_DEBUG(Service_FS, "{} not found", full_path);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
LOG_ERROR(Service_FS, "{} is not a file", full_path);
|
LOG_ERROR(Service_FS, "{} is not a file", full_path);
|
||||||
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC;
|
return ResultUnexpectedFileOrDirectorySdmc;
|
||||||
case PathParser::FileFound:
|
case PathParser::FileFound:
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FileUtil::Delete(full_path)) {
|
if (FileUtil::Delete(full_path)) {
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting {}", full_path);
|
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting {}", full_path);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SDMCArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
Result SDMCArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
||||||
const PathParser path_parser_src(src_path);
|
const PathParser path_parser_src(src_path);
|
||||||
|
|
||||||
// TODO: Verify these return codes with HW
|
// TODO: Verify these return codes with HW
|
||||||
if (!path_parser_src.IsValid()) {
|
if (!path_parser_src.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid src path {}", src_path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid src path {}", src_path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathParser path_parser_dest(dest_path);
|
const PathParser path_parser_dest(dest_path);
|
||||||
|
|
||||||
if (!path_parser_dest.IsValid()) {
|
if (!path_parser_dest.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid dest path {}", dest_path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid dest path {}", dest_path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto src_path_full = path_parser_src.BuildHostPath(mount_point);
|
const auto src_path_full = path_parser_src.BuildHostPath(mount_point);
|
||||||
const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point);
|
const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point);
|
||||||
|
|
||||||
if (FileUtil::Rename(src_path_full, dest_path_full)) {
|
if (FileUtil::Rename(src_path_full, dest_path_full)) {
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
|
// TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
|
||||||
// exist or similar. Verify.
|
// exist or similar. Verify.
|
||||||
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
return Result(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
||||||
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static ResultCode DeleteDirectoryHelper(const Path& path, const std::string& mount_point,
|
static Result DeleteDirectoryHelper(const Path& path, const std::string& mount_point, T deleter) {
|
||||||
T deleter) {
|
|
||||||
const PathParser path_parser(path);
|
const PathParser path_parser(path);
|
||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path_parser.IsRootDirectory())
|
if (path_parser.IsRootDirectory())
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
|
|
||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
case PathParser::FileFound:
|
case PathParser::FileFound:
|
||||||
LOG_ERROR(Service_FS, "Unexpected file in path {}", full_path);
|
LOG_ERROR(Service_FS, "Unexpected file in path {}", full_path);
|
||||||
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC;
|
return ResultUnexpectedFileOrDirectorySdmc;
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleter(full_path)) {
|
if (deleter(full_path)) {
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_ERROR(Service_FS, "Directory not empty {}", full_path);
|
LOG_ERROR(Service_FS, "Directory not empty {}", full_path);
|
||||||
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC;
|
return ResultUnexpectedFileOrDirectorySdmc;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SDMCArchive::DeleteDirectory(const Path& path) const {
|
Result SDMCArchive::DeleteDirectory(const Path& path) const {
|
||||||
return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir);
|
return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SDMCArchive::DeleteDirectoryRecursively(const Path& path) const {
|
Result SDMCArchive::DeleteDirectoryRecursively(const Path& path) const {
|
||||||
return DeleteDirectoryHelper(
|
return DeleteDirectoryHelper(
|
||||||
path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); });
|
path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); });
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SDMCArchive::CreateFile(const FileSys::Path& path, u64 size) const {
|
Result SDMCArchive::CreateFile(const FileSys::Path& path, u64 size) const {
|
||||||
const PathParser path_parser(path);
|
const PathParser path_parser(path);
|
||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
@ -236,44 +235,44 @@ ResultCode SDMCArchive::CreateFile(const FileSys::Path& path, u64 size) const {
|
|||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
LOG_ERROR(Service_FS, "{} already exists", full_path);
|
LOG_ERROR(Service_FS, "{} already exists", full_path);
|
||||||
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC;
|
return ResultUnexpectedFileOrDirectorySdmc;
|
||||||
case PathParser::FileFound:
|
case PathParser::FileFound:
|
||||||
LOG_ERROR(Service_FS, "{} already exists", full_path);
|
LOG_ERROR(Service_FS, "{} already exists", full_path);
|
||||||
return ERROR_ALREADY_EXISTS;
|
return ResultAlreadyExists;
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
FileUtil::CreateEmptyFile(full_path);
|
FileUtil::CreateEmptyFile(full_path);
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileUtil::IOFile file(full_path, "wb");
|
FileUtil::IOFile file(full_path, "wb");
|
||||||
// Creates a sparse file (or a normal file on filesystems without the concept of sparse files)
|
// Creates a sparse file (or a normal file on filesystems without the concept of sparse files)
|
||||||
// We do this by seeking to the right size, then writing a single null byte.
|
// We do this by seeking to the right size, then writing a single null byte.
|
||||||
if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) {
|
if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) {
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_ERROR(Service_FS, "Too large file");
|
LOG_ERROR(Service_FS, "Too large file");
|
||||||
return ResultCode(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource,
|
return Result(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource,
|
||||||
ErrorLevel::Info);
|
ErrorLevel::Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SDMCArchive::CreateDirectory(const Path& path) const {
|
Result SDMCArchive::CreateDirectory(const Path& path) const {
|
||||||
const PathParser path_parser(path);
|
const PathParser path_parser(path);
|
||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
@ -281,55 +280,55 @@ ResultCode SDMCArchive::CreateDirectory(const Path& path) const {
|
|||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
case PathParser::FileFound:
|
case PathParser::FileFound:
|
||||||
LOG_DEBUG(Service_FS, "{} already exists", full_path);
|
LOG_DEBUG(Service_FS, "{} already exists", full_path);
|
||||||
return ERROR_ALREADY_EXISTS;
|
return ResultAlreadyExists;
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FileUtil::CreateDir(mount_point + path.AsString())) {
|
if (FileUtil::CreateDir(mount_point + path.AsString())) {
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating {}", mount_point);
|
||||||
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled,
|
return Result(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled,
|
||||||
ErrorLevel::Status);
|
ErrorLevel::Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SDMCArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
Result SDMCArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
||||||
const PathParser path_parser_src(src_path);
|
const PathParser path_parser_src(src_path);
|
||||||
|
|
||||||
// TODO: Verify these return codes with HW
|
// TODO: Verify these return codes with HW
|
||||||
if (!path_parser_src.IsValid()) {
|
if (!path_parser_src.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid src path {}", src_path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid src path {}", src_path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathParser path_parser_dest(dest_path);
|
const PathParser path_parser_dest(dest_path);
|
||||||
|
|
||||||
if (!path_parser_dest.IsValid()) {
|
if (!path_parser_dest.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid dest path {}", dest_path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid dest path {}", dest_path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto src_path_full = path_parser_src.BuildHostPath(mount_point);
|
const auto src_path_full = path_parser_src.BuildHostPath(mount_point);
|
||||||
const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point);
|
const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point);
|
||||||
|
|
||||||
if (FileUtil::Rename(src_path_full, dest_path_full)) {
|
if (FileUtil::Rename(src_path_full, dest_path_full)) {
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
|
// TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
|
||||||
// exist or similar. Verify.
|
// exist or similar. Verify.
|
||||||
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
return Result(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
||||||
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<DirectoryBackend>> SDMCArchive::OpenDirectory(const Path& path) const {
|
ResultVal<std::unique_ptr<DirectoryBackend>> SDMCArchive::OpenDirectory(const Path& path) const {
|
||||||
@ -337,7 +336,7 @@ ResultVal<std::unique_ptr<DirectoryBackend>> SDMCArchive::OpenDirectory(const Pa
|
|||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
@ -345,15 +344,15 @@ ResultVal<std::unique_ptr<DirectoryBackend>> SDMCArchive::OpenDirectory(const Pa
|
|||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
case PathParser::FileFound:
|
case PathParser::FileFound:
|
||||||
LOG_ERROR(Service_FS, "{} not found", full_path);
|
LOG_ERROR(Service_FS, "{} not found", full_path);
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
LOG_ERROR(Service_FS, "Unexpected file in path {}", full_path);
|
LOG_ERROR(Service_FS, "Unexpected file in path {}", full_path);
|
||||||
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC;
|
return ResultUnexpectedFileOrDirectorySdmc;
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
@ -392,18 +391,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path&
|
|||||||
return std::make_unique<SDMCArchive>(sdmc_directory, std::move(delay_generator));
|
return std::make_unique<SDMCArchive>(sdmc_directory, std::move(delay_generator));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_SDMC::Format(const Path& path,
|
Result ArchiveFactory_SDMC::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||||
const FileSys::ArchiveFormatInfo& format_info,
|
u64 program_id) {
|
||||||
u64 program_id) {
|
|
||||||
// This is kind of an undesirable operation, so let's just ignore it. :)
|
// This is kind of an undesirable operation, so let's just ignore it. :)
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMC::GetFormatInfo(const Path& path,
|
ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMC::GetFormatInfo(const Path& path,
|
||||||
u64 program_id) const {
|
u64 program_id) const {
|
||||||
// TODO(Subv): Implement
|
// TODO(Subv): Implement
|
||||||
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
||||||
|
@ -29,13 +29,13 @@ public:
|
|||||||
|
|
||||||
ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
|
ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
|
||||||
const Mode& mode) const override;
|
const Mode& mode) const override;
|
||||||
ResultCode DeleteFile(const Path& path) const override;
|
Result DeleteFile(const Path& path) const override;
|
||||||
ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override;
|
Result RenameFile(const Path& src_path, const Path& dest_path) const override;
|
||||||
ResultCode DeleteDirectory(const Path& path) const override;
|
Result DeleteDirectory(const Path& path) const override;
|
||||||
ResultCode DeleteDirectoryRecursively(const Path& path) const override;
|
Result DeleteDirectoryRecursively(const Path& path) const override;
|
||||||
ResultCode CreateFile(const Path& path, u64 size) const override;
|
Result CreateFile(const Path& path, u64 size) const override;
|
||||||
ResultCode CreateDirectory(const Path& path) const override;
|
Result CreateDirectory(const Path& path) const override;
|
||||||
ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
|
Result RenameDirectory(const Path& src_path, const Path& dest_path) const override;
|
||||||
ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
|
ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
|
||||||
u64 GetFreeBytes() const override;
|
u64 GetFreeBytes() const override;
|
||||||
|
|
||||||
@ -68,8 +68,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
||||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
Result Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) override;
|
u64 program_id) override;
|
||||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -44,7 +44,7 @@ ResultVal<std::unique_ptr<FileBackend>> SDMCWriteOnlyArchive::OpenFile(const Pat
|
|||||||
const Mode& mode) const {
|
const Mode& mode) const {
|
||||||
if (mode.read_flag) {
|
if (mode.read_flag) {
|
||||||
LOG_ERROR(Service_FS, "Read flag is not supported");
|
LOG_ERROR(Service_FS, "Read flag is not supported");
|
||||||
return ERROR_INVALID_READ_FLAG;
|
return ResultInvalidReadFlag;
|
||||||
}
|
}
|
||||||
return SDMCArchive::OpenFileBase(path, mode);
|
return SDMCArchive::OpenFileBase(path, mode);
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ ResultVal<std::unique_ptr<FileBackend>> SDMCWriteOnlyArchive::OpenFile(const Pat
|
|||||||
ResultVal<std::unique_ptr<DirectoryBackend>> SDMCWriteOnlyArchive::OpenDirectory(
|
ResultVal<std::unique_ptr<DirectoryBackend>> SDMCWriteOnlyArchive::OpenDirectory(
|
||||||
const Path& path) const {
|
const Path& path) const {
|
||||||
LOG_ERROR(Service_FS, "Not supported");
|
LOG_ERROR(Service_FS, "Not supported");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArchiveFactory_SDMCWriteOnly::ArchiveFactory_SDMCWriteOnly(const std::string& mount_point)
|
ArchiveFactory_SDMCWriteOnly::ArchiveFactory_SDMCWriteOnly(const std::string& mount_point)
|
||||||
@ -81,19 +81,19 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMCWriteOnly::Open(co
|
|||||||
return std::make_unique<SDMCWriteOnlyArchive>(sdmc_directory, std::move(delay_generator));
|
return std::make_unique<SDMCWriteOnlyArchive>(sdmc_directory, std::move(delay_generator));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_SDMCWriteOnly::Format(const Path& path,
|
Result ArchiveFactory_SDMCWriteOnly::Format(const Path& path,
|
||||||
const FileSys::ArchiveFormatInfo& format_info,
|
const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) {
|
u64 program_id) {
|
||||||
// TODO(wwylele): hwtest this
|
// TODO(wwylele): hwtest this
|
||||||
LOG_ERROR(Service_FS, "Attempted to format a SDMC write-only archive.");
|
LOG_ERROR(Service_FS, "Attempted to format a SDMC write-only archive.");
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMCWriteOnly::GetFormatInfo(const Path& path,
|
ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMCWriteOnly::GetFormatInfo(const Path& path,
|
||||||
u64 program_id) const {
|
u64 program_id) const {
|
||||||
// TODO(Subv): Implement
|
// TODO(Subv): Implement
|
||||||
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
@ -54,8 +54,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
||||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
Result Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) override;
|
u64 program_id) override;
|
||||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -39,12 +39,12 @@ public:
|
|||||||
ResultVal<std::size_t> Read(u64 offset, std::size_t length, u8* buffer) const override {
|
ResultVal<std::size_t> Read(u64 offset, std::size_t length, u8* buffer) const override {
|
||||||
if (offset != 0) {
|
if (offset != 0) {
|
||||||
LOG_ERROR(Service_FS, "offset must be zero!");
|
LOG_ERROR(Service_FS, "offset must be zero!");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length != data->size()) {
|
if (length != data->size()) {
|
||||||
LOG_ERROR(Service_FS, "size must match the file size!");
|
LOG_ERROR(Service_FS, "size must match the file size!");
|
||||||
return ERROR_INCORRECT_EXEFS_READ_SIZE;
|
return ResultIncorrectExefsReadSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(buffer, data->data(), data->size());
|
std::memcpy(buffer, data->data(), data->size());
|
||||||
@ -54,7 +54,7 @@ public:
|
|||||||
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush,
|
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush,
|
||||||
const u8* buffer) override {
|
const u8* buffer) override {
|
||||||
LOG_ERROR(Service_FS, "The file is read-only!");
|
LOG_ERROR(Service_FS, "The file is read-only!");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetSize() const override {
|
u64 GetSize() const override {
|
||||||
@ -99,13 +99,13 @@ public:
|
|||||||
|
|
||||||
if (path.GetType() != LowPathType::Binary) {
|
if (path.GetType() != LowPathType::Binary) {
|
||||||
LOG_ERROR(Service_FS, "Path need to be Binary");
|
LOG_ERROR(Service_FS, "Path need to be Binary");
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> binary = path.AsBinary();
|
std::vector<u8> binary = path.AsBinary();
|
||||||
if (binary.size() != sizeof(SelfNCCHFilePath)) {
|
if (binary.size() != sizeof(SelfNCCHFilePath)) {
|
||||||
LOG_ERROR(Service_FS, "Wrong path size {}", binary.size());
|
LOG_ERROR(Service_FS, "Wrong path size {}", binary.size());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
SelfNCCHFilePath file_path;
|
SelfNCCHFilePath file_path;
|
||||||
@ -120,7 +120,7 @@ public:
|
|||||||
|
|
||||||
case SelfNCCHFilePathType::Code:
|
case SelfNCCHFilePathType::Code:
|
||||||
LOG_ERROR(Service_FS, "Reading the code section is not supported!");
|
LOG_ERROR(Service_FS, "Reading the code section is not supported!");
|
||||||
return ERROR_COMMAND_NOT_ALLOWED;
|
return ResultCommandNotAllowed;
|
||||||
|
|
||||||
case SelfNCCHFilePathType::ExeFS: {
|
case SelfNCCHFilePathType::ExeFS: {
|
||||||
const auto& raw = file_path.exefs_filename;
|
const auto& raw = file_path.exefs_filename;
|
||||||
@ -130,48 +130,48 @@ public:
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
LOG_ERROR(Service_FS, "Unknown file type {}!", file_path.type);
|
LOG_ERROR(Service_FS, "Unknown file type {}!", file_path.type);
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode DeleteFile(const Path& path) const override {
|
Result DeleteFile(const Path& path) const override {
|
||||||
LOG_ERROR(Service_FS, "Unsupported");
|
LOG_ERROR(Service_FS, "Unsupported");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override {
|
Result RenameFile(const Path& src_path, const Path& dest_path) const override {
|
||||||
LOG_ERROR(Service_FS, "Unsupported");
|
LOG_ERROR(Service_FS, "Unsupported");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode DeleteDirectory(const Path& path) const override {
|
Result DeleteDirectory(const Path& path) const override {
|
||||||
LOG_ERROR(Service_FS, "Unsupported");
|
LOG_ERROR(Service_FS, "Unsupported");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode DeleteDirectoryRecursively(const Path& path) const override {
|
Result DeleteDirectoryRecursively(const Path& path) const override {
|
||||||
LOG_ERROR(Service_FS, "Unsupported");
|
LOG_ERROR(Service_FS, "Unsupported");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode CreateFile(const Path& path, u64 size) const override {
|
Result CreateFile(const Path& path, u64 size) const override {
|
||||||
LOG_ERROR(Service_FS, "Unsupported");
|
LOG_ERROR(Service_FS, "Unsupported");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode CreateDirectory(const Path& path) const override {
|
Result CreateDirectory(const Path& path) const override {
|
||||||
LOG_ERROR(Service_FS, "Unsupported");
|
LOG_ERROR(Service_FS, "Unsupported");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override {
|
Result RenameDirectory(const Path& src_path, const Path& dest_path) const override {
|
||||||
LOG_ERROR(Service_FS, "Unsupported");
|
LOG_ERROR(Service_FS, "Unsupported");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override {
|
ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override {
|
||||||
LOG_ERROR(Service_FS, "Unsupported");
|
LOG_ERROR(Service_FS, "Unsupported");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetFreeBytes() const override {
|
u64 GetFreeBytes() const override {
|
||||||
@ -186,7 +186,7 @@ private:
|
|||||||
return std::make_unique<IVFCFile>(ncch_data.romfs_file, std::move(delay_generator));
|
return std::make_unique<IVFCFile>(ncch_data.romfs_file, std::move(delay_generator));
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO(Service_FS, "Unable to read RomFS");
|
LOG_INFO(Service_FS, "Unable to read RomFS");
|
||||||
return ERROR_ROMFS_NOT_FOUND;
|
return ResultRomfsNotFound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +198,7 @@ private:
|
|||||||
std::move(delay_generator));
|
std::move(delay_generator));
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO(Service_FS, "Unable to read update RomFS");
|
LOG_INFO(Service_FS, "Unable to read update RomFS");
|
||||||
return ERROR_ROMFS_NOT_FOUND;
|
return ResultRomfsNotFound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +209,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_WARNING(Service_FS, "Unable to read icon");
|
LOG_WARNING(Service_FS, "Unable to read icon");
|
||||||
return ERROR_EXEFS_SECTION_NOT_FOUND;
|
return ResultExefsSectionNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filename == "logo") {
|
if (filename == "logo") {
|
||||||
@ -218,7 +218,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_WARNING(Service_FS, "Unable to read logo");
|
LOG_WARNING(Service_FS, "Unable to read logo");
|
||||||
return ERROR_EXEFS_SECTION_NOT_FOUND;
|
return ResultExefsSectionNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filename == "banner") {
|
if (filename == "banner") {
|
||||||
@ -227,11 +227,11 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_WARNING(Service_FS, "Unable to read banner");
|
LOG_WARNING(Service_FS, "Unable to read banner");
|
||||||
return ERROR_EXEFS_SECTION_NOT_FOUND;
|
return ResultExefsSectionNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_ERROR(Service_FS, "Unknown ExeFS section {}!", filename);
|
LOG_ERROR(Service_FS, "Unknown ExeFS section {}!", filename);
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
NCCHData ncch_data;
|
NCCHData ncch_data;
|
||||||
@ -296,16 +296,16 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const P
|
|||||||
return std::make_unique<SelfNCCHArchive>(ncch_data[program_id]);
|
return std::make_unique<SelfNCCHArchive>(ncch_data[program_id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_SelfNCCH::Format(const Path&, const FileSys::ArchiveFormatInfo&,
|
Result ArchiveFactory_SelfNCCH::Format(const Path&, const FileSys::ArchiveFormatInfo&,
|
||||||
u64 program_id) {
|
u64 program_id) {
|
||||||
LOG_ERROR(Service_FS, "Attempted to format a SelfNCCH archive.");
|
LOG_ERROR(Service_FS, "Attempted to format a SelfNCCH archive.");
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<ArchiveFormatInfo> ArchiveFactory_SelfNCCH::GetFormatInfo(const Path&,
|
ResultVal<ArchiveFormatInfo> ArchiveFactory_SelfNCCH::GetFormatInfo(const Path&,
|
||||||
u64 program_id) const {
|
u64 program_id) const {
|
||||||
LOG_ERROR(Service_FS, "Attempted to get format info of a SelfNCCH archive");
|
LOG_ERROR(Service_FS, "Attempted to get format info of a SelfNCCH archive");
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
@ -50,8 +50,8 @@ public:
|
|||||||
return "SelfNCCH";
|
return "SelfNCCH";
|
||||||
}
|
}
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
||||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
Result Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) override;
|
u64 program_id) override;
|
||||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -47,14 +47,14 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveSource_SDSaveData::Open(u64 pr
|
|||||||
// save file/directory structure expected by the game has not yet been initialized.
|
// save file/directory structure expected by the game has not yet been initialized.
|
||||||
// Returning the NotFormatted error code will signal the game to provision the SaveData
|
// Returning the NotFormatted error code will signal the game to provision the SaveData
|
||||||
// archive with the files and folders that it expects.
|
// archive with the files and folders that it expects.
|
||||||
return ERR_NOT_FORMATTED;
|
return ResultNotFormatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<SaveDataArchive>(std::move(concrete_mount_point));
|
return std::make_unique<SaveDataArchive>(std::move(concrete_mount_point));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveSource_SDSaveData::Format(u64 program_id,
|
Result ArchiveSource_SDSaveData::Format(u64 program_id,
|
||||||
const FileSys::ArchiveFormatInfo& format_info) {
|
const FileSys::ArchiveFormatInfo& format_info) {
|
||||||
std::string concrete_mount_point = GetSaveDataPath(mount_point, program_id);
|
std::string concrete_mount_point = GetSaveDataPath(mount_point, program_id);
|
||||||
FileUtil::DeleteDirRecursively(concrete_mount_point);
|
FileUtil::DeleteDirRecursively(concrete_mount_point);
|
||||||
FileUtil::CreateFullPath(concrete_mount_point);
|
FileUtil::CreateFullPath(concrete_mount_point);
|
||||||
@ -65,9 +65,9 @@ ResultCode ArchiveSource_SDSaveData::Format(u64 program_id,
|
|||||||
|
|
||||||
if (file.IsOpen()) {
|
if (file.IsOpen()) {
|
||||||
file.WriteBytes(&format_info, sizeof(format_info));
|
file.WriteBytes(&format_info, sizeof(format_info));
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<ArchiveFormatInfo> ArchiveSource_SDSaveData::GetFormatInfo(u64 program_id) const {
|
ResultVal<ArchiveFormatInfo> ArchiveSource_SDSaveData::GetFormatInfo(u64 program_id) const {
|
||||||
@ -77,7 +77,7 @@ ResultVal<ArchiveFormatInfo> ArchiveSource_SDSaveData::GetFormatInfo(u64 program
|
|||||||
if (!file.IsOpen()) {
|
if (!file.IsOpen()) {
|
||||||
LOG_ERROR(Service_FS, "Could not open metadata information for archive");
|
LOG_ERROR(Service_FS, "Could not open metadata information for archive");
|
||||||
// TODO(Subv): Verify error code
|
// TODO(Subv): Verify error code
|
||||||
return ERR_NOT_FORMATTED;
|
return ResultNotFormatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArchiveFormatInfo info = {};
|
ArchiveFormatInfo info = {};
|
||||||
|
@ -19,7 +19,7 @@ public:
|
|||||||
explicit ArchiveSource_SDSaveData(const std::string& mount_point);
|
explicit ArchiveSource_SDSaveData(const std::string& mount_point);
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(u64 program_id);
|
ResultVal<std::unique_ptr<ArchiveBackend>> Open(u64 program_id);
|
||||||
ResultCode Format(u64 program_id, const FileSys::ArchiveFormatInfo& format_info);
|
Result Format(u64 program_id, const FileSys::ArchiveFormatInfo& format_info);
|
||||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(u64 program_id) const;
|
ResultVal<ArchiveFormatInfo> GetFormatInfo(u64 program_id) const;
|
||||||
|
|
||||||
static std::string GetSaveDataPathFor(const std::string& mount_point, u64 program_id);
|
static std::string GetSaveDataPathFor(const std::string& mount_point, u64 program_id);
|
||||||
|
@ -57,25 +57,25 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(c
|
|||||||
std::string fullpath = GetSystemSaveDataPath(base_path, path);
|
std::string fullpath = GetSystemSaveDataPath(base_path, path);
|
||||||
if (!FileUtil::Exists(fullpath)) {
|
if (!FileUtil::Exists(fullpath)) {
|
||||||
// TODO(Subv): Check error code, this one is probably wrong
|
// TODO(Subv): Check error code, this one is probably wrong
|
||||||
return ERROR_NOT_FOUND;
|
return ResultNotFound;
|
||||||
}
|
}
|
||||||
return std::make_unique<SaveDataArchive>(fullpath);
|
return std::make_unique<SaveDataArchive>(fullpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path,
|
Result ArchiveFactory_SystemSaveData::Format(const Path& path,
|
||||||
const FileSys::ArchiveFormatInfo& format_info,
|
const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) {
|
u64 program_id) {
|
||||||
std::string fullpath = GetSystemSaveDataPath(base_path, path);
|
std::string fullpath = GetSystemSaveDataPath(base_path, path);
|
||||||
FileUtil::DeleteDirRecursively(fullpath);
|
FileUtil::DeleteDirRecursively(fullpath);
|
||||||
FileUtil::CreateFullPath(fullpath);
|
FileUtil::CreateFullPath(fullpath);
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<ArchiveFormatInfo> ArchiveFactory_SystemSaveData::GetFormatInfo(const Path& path,
|
ResultVal<ArchiveFormatInfo> ArchiveFactory_SystemSaveData::GetFormatInfo(const Path& path,
|
||||||
u64 program_id) const {
|
u64 program_id) const {
|
||||||
// TODO(Subv): Implement
|
// TODO(Subv): Implement
|
||||||
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
@ -20,8 +20,8 @@ public:
|
|||||||
explicit ArchiveFactory_SystemSaveData(const std::string& mount_point);
|
explicit ArchiveFactory_SystemSaveData(const std::string& mount_point);
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override;
|
||||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
Result Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) override;
|
u64 program_id) override;
|
||||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||||
|
|
||||||
std::string GetName() const override {
|
std::string GetName() const override {
|
||||||
|
@ -19,7 +19,7 @@ namespace FileSys {
|
|||||||
ResultVal<std::size_t> DiskFile::Read(const u64 offset, const std::size_t length,
|
ResultVal<std::size_t> DiskFile::Read(const u64 offset, const std::size_t length,
|
||||||
u8* buffer) const {
|
u8* buffer) const {
|
||||||
if (!mode.read_flag)
|
if (!mode.read_flag)
|
||||||
return ERROR_INVALID_OPEN_FLAGS;
|
return ResultInvalidOpenFlags;
|
||||||
|
|
||||||
file->Seek(offset, SEEK_SET);
|
file->Seek(offset, SEEK_SET);
|
||||||
return file->ReadBytes(buffer, length);
|
return file->ReadBytes(buffer, length);
|
||||||
@ -28,7 +28,7 @@ ResultVal<std::size_t> DiskFile::Read(const u64 offset, const std::size_t length
|
|||||||
ResultVal<std::size_t> DiskFile::Write(const u64 offset, const std::size_t length, const bool flush,
|
ResultVal<std::size_t> DiskFile::Write(const u64 offset, const std::size_t length, const bool flush,
|
||||||
const u8* buffer) {
|
const u8* buffer) {
|
||||||
if (!mode.write_flag)
|
if (!mode.write_flag)
|
||||||
return ERROR_INVALID_OPEN_FLAGS;
|
return ResultInvalidOpenFlags;
|
||||||
|
|
||||||
file->Seek(offset, SEEK_SET);
|
file->Seek(offset, SEEK_SET);
|
||||||
std::size_t written = file->WriteBytes(buffer, length);
|
std::size_t written = file->WriteBytes(buffer, length);
|
||||||
|
@ -35,63 +35,60 @@ enum {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ResultCode ERROR_INVALID_PATH(ErrCodes::InvalidPath, ErrorModule::FS,
|
constexpr Result ResultInvalidPath(ErrCodes::InvalidPath, ErrorModule::FS,
|
||||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||||
constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ErrCodes::UnsupportedOpenFlags, ErrorModule::FS,
|
constexpr Result ResultUnsupportedOpenFlags(ErrCodes::UnsupportedOpenFlags, ErrorModule::FS,
|
||||||
ErrorSummary::NotSupported, ErrorLevel::Usage);
|
ErrorSummary::NotSupported, ErrorLevel::Usage);
|
||||||
constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(ErrCodes::InvalidOpenFlags, ErrorModule::FS,
|
constexpr Result ResultInvalidOpenFlags(ErrCodes::InvalidOpenFlags, ErrorModule::FS,
|
||||||
ErrorSummary::Canceled, ErrorLevel::Status);
|
ErrorSummary::Canceled, ErrorLevel::Status);
|
||||||
constexpr ResultCode ERROR_INVALID_READ_FLAG(ErrCodes::InvalidReadFlag, ErrorModule::FS,
|
constexpr Result ResultInvalidReadFlag(ErrCodes::InvalidReadFlag, ErrorModule::FS,
|
||||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||||
constexpr ResultCode ERROR_FILE_NOT_FOUND(ErrCodes::FileNotFound, ErrorModule::FS,
|
constexpr Result ResultFileNotFound(ErrCodes::FileNotFound, ErrorModule::FS, ErrorSummary::NotFound,
|
||||||
ErrorSummary::NotFound, ErrorLevel::Status);
|
ErrorLevel::Status);
|
||||||
constexpr ResultCode ERROR_PATH_NOT_FOUND(ErrCodes::PathNotFound, ErrorModule::FS,
|
constexpr Result ResultPathNotFound(ErrCodes::PathNotFound, ErrorModule::FS, ErrorSummary::NotFound,
|
||||||
ErrorSummary::NotFound, ErrorLevel::Status);
|
ErrorLevel::Status);
|
||||||
constexpr ResultCode ERROR_NOT_FOUND(ErrCodes::NotFound, ErrorModule::FS, ErrorSummary::NotFound,
|
constexpr Result ResultNotFound(ErrCodes::NotFound, ErrorModule::FS, ErrorSummary::NotFound,
|
||||||
ErrorLevel::Status);
|
ErrorLevel::Status);
|
||||||
constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ErrCodes::UnexpectedFileOrDirectory,
|
constexpr Result ResultUnexpectedFileOrDirectory(ErrCodes::UnexpectedFileOrDirectory,
|
||||||
ErrorModule::FS, ErrorSummary::NotSupported,
|
ErrorModule::FS, ErrorSummary::NotSupported,
|
||||||
ErrorLevel::Usage);
|
ErrorLevel::Usage);
|
||||||
constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC(ErrCodes::NotAFile, ErrorModule::FS,
|
constexpr Result ResultUnexpectedFileOrDirectorySdmc(ErrCodes::NotAFile, ErrorModule::FS,
|
||||||
ErrorSummary::Canceled,
|
ErrorSummary::Canceled, ErrorLevel::Status);
|
||||||
ErrorLevel::Status);
|
constexpr Result ResultDirectoryAlreadyExists(ErrCodes::DirectoryAlreadyExists, ErrorModule::FS,
|
||||||
constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ErrCodes::DirectoryAlreadyExists,
|
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
||||||
ErrorModule::FS, ErrorSummary::NothingHappened,
|
constexpr Result ResultFileAlreadyExists(ErrCodes::FileAlreadyExists, ErrorModule::FS,
|
||||||
ErrorLevel::Status);
|
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
||||||
constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(ErrCodes::FileAlreadyExists, ErrorModule::FS,
|
constexpr Result ResultAlreadyExists(ErrCodes::AlreadyExists, ErrorModule::FS,
|
||||||
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
||||||
constexpr ResultCode ERROR_ALREADY_EXISTS(ErrCodes::AlreadyExists, ErrorModule::FS,
|
constexpr Result ResultDirectoryNotEmpty(ErrCodes::DirectoryNotEmpty, ErrorModule::FS,
|
||||||
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
ErrorSummary::Canceled, ErrorLevel::Status);
|
||||||
constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(ErrCodes::DirectoryNotEmpty, ErrorModule::FS,
|
constexpr Result ResultGamecardNotInserted(ErrCodes::GameCardNotInserted, ErrorModule::FS,
|
||||||
ErrorSummary::Canceled, ErrorLevel::Status);
|
|
||||||
constexpr ResultCode ERROR_GAMECARD_NOT_INSERTED(ErrCodes::GameCardNotInserted, ErrorModule::FS,
|
|
||||||
ErrorSummary::NotFound, ErrorLevel::Status);
|
|
||||||
constexpr ResultCode ERROR_INCORRECT_EXEFS_READ_SIZE(ErrCodes::IncorrectExeFSReadSize,
|
|
||||||
ErrorModule::FS, ErrorSummary::NotSupported,
|
|
||||||
ErrorLevel::Usage);
|
|
||||||
constexpr ResultCode ERROR_ROMFS_NOT_FOUND(ErrCodes::RomFSNotFound, ErrorModule::FS,
|
|
||||||
ErrorSummary::NotFound, ErrorLevel::Status);
|
ErrorSummary::NotFound, ErrorLevel::Status);
|
||||||
constexpr ResultCode ERROR_COMMAND_NOT_ALLOWED(ErrCodes::CommandNotAllowed, ErrorModule::FS,
|
constexpr Result ResultIncorrectExefsReadSize(ErrCodes::IncorrectExeFSReadSize, ErrorModule::FS,
|
||||||
ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
ErrorSummary::NotSupported, ErrorLevel::Usage);
|
||||||
constexpr ResultCode ERROR_EXEFS_SECTION_NOT_FOUND(ErrCodes::ExeFSSectionNotFound, ErrorModule::FS,
|
constexpr Result ResultRomfsNotFound(ErrCodes::RomFSNotFound, ErrorModule::FS,
|
||||||
ErrorSummary::NotFound, ErrorLevel::Status);
|
ErrorSummary::NotFound, ErrorLevel::Status);
|
||||||
constexpr ResultCode ERROR_INSUFFICIENT_SPACE(ErrCodes::InsufficientSpace, ErrorModule::FS,
|
constexpr Result ResultCommandNotAllowed(ErrCodes::CommandNotAllowed, ErrorModule::FS,
|
||||||
ErrorSummary::OutOfResource, ErrorLevel::Status);
|
ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||||
|
constexpr Result ResultExefsSectionNotFound(ErrCodes::ExeFSSectionNotFound, ErrorModule::FS,
|
||||||
|
ErrorSummary::NotFound, ErrorLevel::Status);
|
||||||
|
constexpr Result ResultInsufficientSpace(ErrCodes::InsufficientSpace, ErrorModule::FS,
|
||||||
|
ErrorSummary::OutOfResource, ErrorLevel::Status);
|
||||||
|
|
||||||
/// Returned when a function is passed an invalid archive handle.
|
/// Returned when a function is passed an invalid archive handle.
|
||||||
constexpr ResultCode ERR_INVALID_ARCHIVE_HANDLE(ErrCodes::ArchiveNotMounted, ErrorModule::FS,
|
constexpr Result ResultInvalidArchiveHandle(ErrCodes::ArchiveNotMounted, ErrorModule::FS,
|
||||||
ErrorSummary::NotFound,
|
ErrorSummary::NotFound,
|
||||||
ErrorLevel::Status); // 0xC8804465
|
ErrorLevel::Status); // 0xC8804465
|
||||||
constexpr ResultCode ERR_WRITE_BEYOND_END(ErrCodes::WriteBeyondEnd, ErrorModule::FS,
|
constexpr Result ResultWriteBeyondEnd(ErrCodes::WriteBeyondEnd, ErrorModule::FS,
|
||||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Variant of ERROR_NOT_FOUND returned in some places in the code. Unknown if these usages are
|
* Variant of ResultNotFound returned in some places in the code. Unknown if these usages are
|
||||||
* correct or a bug.
|
* correct or a bug.
|
||||||
*/
|
*/
|
||||||
constexpr ResultCode ERR_NOT_FOUND_INVALID_STATE(ErrCodes::NotFound, ErrorModule::FS,
|
constexpr Result ResultNotFoundInvalidState(ErrCodes::NotFound, ErrorModule::FS,
|
||||||
ErrorSummary::InvalidState, ErrorLevel::Status);
|
ErrorSummary::InvalidState, ErrorLevel::Status);
|
||||||
constexpr ResultCode ERR_NOT_FORMATTED(ErrCodes::NotFormatted, ErrorModule::FS,
|
constexpr Result ResultNotFormatted(ErrCodes::NotFormatted, ErrorModule::FS,
|
||||||
ErrorSummary::InvalidState, ErrorLevel::Status);
|
ErrorSummary::InvalidState, ErrorLevel::Status);
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
@ -34,50 +34,50 @@ ResultVal<std::unique_ptr<FileBackend>> IVFCArchive::OpenFile(const Path& path,
|
|||||||
return std::make_unique<IVFCFile>(romfs_file, std::move(delay_generator));
|
return std::make_unique<IVFCFile>(romfs_file, std::move(delay_generator));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode IVFCArchive::DeleteFile(const Path& path) const {
|
Result IVFCArchive::DeleteFile(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a file from an IVFC archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to delete a file from an IVFC archive ({}).", GetName());
|
||||||
// TODO(Subv): Verify error code
|
// TODO(Subv): Verify error code
|
||||||
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled,
|
return Result(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled,
|
||||||
ErrorLevel::Status);
|
ErrorLevel::Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode IVFCArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
Result IVFCArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive ({}).", GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode IVFCArchive::DeleteDirectory(const Path& path) const {
|
Result IVFCArchive::DeleteDirectory(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive ({}).",
|
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive ({}).",
|
||||||
GetName());
|
GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode IVFCArchive::DeleteDirectoryRecursively(const Path& path) const {
|
Result IVFCArchive::DeleteDirectoryRecursively(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive ({}).",
|
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive ({}).",
|
||||||
GetName());
|
GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode IVFCArchive::CreateFile(const Path& path, u64 size) const {
|
Result IVFCArchive::CreateFile(const Path& path, u64 size) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to create a file in an IVFC archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to create a file in an IVFC archive ({}).", GetName());
|
||||||
// TODO: Verify error code
|
// TODO: Verify error code
|
||||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported,
|
return Result(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported,
|
||||||
ErrorLevel::Permanent);
|
ErrorLevel::Permanent);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode IVFCArchive::CreateDirectory(const Path& path) const {
|
Result IVFCArchive::CreateDirectory(const Path& path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an IVFC archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an IVFC archive ({}).", GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode IVFCArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
Result IVFCArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive ({}).", GetName());
|
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive ({}).", GetName());
|
||||||
// TODO(wwylele): Use correct error code
|
// TODO(wwylele): Use correct error code
|
||||||
return RESULT_UNKNOWN;
|
return ResultUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<DirectoryBackend>> IVFCArchive::OpenDirectory(const Path& path) const {
|
ResultVal<std::unique_ptr<DirectoryBackend>> IVFCArchive::OpenDirectory(const Path& path) const {
|
||||||
|
@ -103,13 +103,13 @@ public:
|
|||||||
|
|
||||||
ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
|
ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
|
||||||
const Mode& mode) const override;
|
const Mode& mode) const override;
|
||||||
ResultCode DeleteFile(const Path& path) const override;
|
Result DeleteFile(const Path& path) const override;
|
||||||
ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override;
|
Result RenameFile(const Path& src_path, const Path& dest_path) const override;
|
||||||
ResultCode DeleteDirectory(const Path& path) const override;
|
Result DeleteDirectory(const Path& path) const override;
|
||||||
ResultCode DeleteDirectoryRecursively(const Path& path) const override;
|
Result DeleteDirectoryRecursively(const Path& path) const override;
|
||||||
ResultCode CreateFile(const Path& path, u64 size) const override;
|
Result CreateFile(const Path& path, u64 size) const override;
|
||||||
ResultCode CreateDirectory(const Path& path) const override;
|
Result CreateDirectory(const Path& path) const override;
|
||||||
ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
|
Result RenameDirectory(const Path& src_path, const Path& dest_path) const override;
|
||||||
ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
|
ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
|
||||||
u64 GetFreeBytes() const override;
|
u64 GetFreeBytes() const override;
|
||||||
|
|
||||||
|
@ -57,9 +57,9 @@ static bool LZSS_Decompress(std::span<const u8> compressed, std::span<u8> decomp
|
|||||||
u32 buffer_top_and_bottom;
|
u32 buffer_top_and_bottom;
|
||||||
std::memcpy(&buffer_top_and_bottom, footer, sizeof(u32));
|
std::memcpy(&buffer_top_and_bottom, footer, sizeof(u32));
|
||||||
|
|
||||||
size_t out = decompressed.size();
|
std::size_t out = decompressed.size();
|
||||||
size_t index = compressed.size() - ((buffer_top_and_bottom >> 24) & 0xFF);
|
std::size_t index = compressed.size() - ((buffer_top_and_bottom >> 24) & 0xFF);
|
||||||
size_t stop_index = compressed.size() - (buffer_top_and_bottom & 0xFFFFFF);
|
std::size_t stop_index = compressed.size() - (buffer_top_and_bottom & 0xFFFFFF);
|
||||||
|
|
||||||
std::memset(decompressed.data(), 0, decompressed.size());
|
std::memset(decompressed.data(), 0, decompressed.size());
|
||||||
std::memcpy(decompressed.data(), compressed.data(), compressed.size());
|
std::memcpy(decompressed.data(), compressed.data(), compressed.size());
|
||||||
|
@ -131,7 +131,7 @@ public:
|
|||||||
return m_offset;
|
return m_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Seek(size_t offset) {
|
bool Seek(std::size_t offset) {
|
||||||
if (offset > m_size)
|
if (offset > m_size)
|
||||||
return false;
|
return false;
|
||||||
m_offset = offset;
|
m_offset = offset;
|
||||||
@ -242,7 +242,7 @@ private:
|
|||||||
if (m_target_relative_offset + length > m_target.size())
|
if (m_target_relative_offset + length > m_target.size())
|
||||||
return false;
|
return false;
|
||||||
// Byte by byte copy.
|
// Byte by byte copy.
|
||||||
for (size_t i = 0; i < length; ++i)
|
for (std::size_t i = 0; i < length; ++i)
|
||||||
m_target.data()[m_target.Tell() + i] = m_target.data()[m_target_relative_offset++];
|
m_target.data()[m_target.Tell() + i] = m_target.data()[m_target_relative_offset++];
|
||||||
m_target.Seek(m_target.Tell() + length);
|
m_target.Seek(m_target.Tell() + length);
|
||||||
return true;
|
return true;
|
||||||
|
@ -65,7 +65,7 @@ static bool ReadSection(std::vector<u8>& data_out, FileUtil::IOFile& file, std::
|
|||||||
|
|
||||||
Loader::ResultStatus FileSys::Plugin3GXLoader::Load(
|
Loader::ResultStatus FileSys::Plugin3GXLoader::Load(
|
||||||
Service::PLGLDR::PLG_LDR::PluginLoaderContext& plg_context, Kernel::Process& process,
|
Service::PLGLDR::PLG_LDR::PluginLoaderContext& plg_context, Kernel::Process& process,
|
||||||
Kernel::KernelSystem& kernel) {
|
Kernel::KernelSystem& kernel, Service::PLGLDR::PLG_LDR& plg_ldr) {
|
||||||
FileUtil::IOFile file(plg_context.plugin_path, "rb");
|
FileUtil::IOFile file(plg_context.plugin_path, "rb");
|
||||||
if (!file.IsOpen()) {
|
if (!file.IsOpen()) {
|
||||||
LOG_ERROR(Service_PLGLDR, "Failed to load 3GX plugin. Not found: {}",
|
LOG_ERROR(Service_PLGLDR, "Failed to load 3GX plugin. Not found: {}",
|
||||||
@ -158,12 +158,12 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Load(
|
|||||||
return Loader::ResultStatus::Error;
|
return Loader::ResultStatus::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Map(plg_context, process, kernel);
|
return Map(plg_context, process, kernel, plg_ldr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader::ResultStatus FileSys::Plugin3GXLoader::Map(
|
Loader::ResultStatus FileSys::Plugin3GXLoader::Map(
|
||||||
Service::PLGLDR::PLG_LDR::PluginLoaderContext& plg_context, Kernel::Process& process,
|
Service::PLGLDR::PLG_LDR::PluginLoaderContext& plg_context, Kernel::Process& process,
|
||||||
Kernel::KernelSystem& kernel) {
|
Kernel::KernelSystem& kernel, Service::PLGLDR::PLG_LDR& plg_ldr) {
|
||||||
|
|
||||||
// Verify exe load checksum function is available
|
// Verify exe load checksum function is available
|
||||||
if (exe_load_func.empty() && plg_context.load_exe_func.empty()) {
|
if (exe_load_func.empty() && plg_context.load_exe_func.empty()) {
|
||||||
@ -195,7 +195,7 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map(
|
|||||||
return Loader::ResultStatus::ErrorMemoryAllocationFailed;
|
return Loader::ResultStatus::ErrorMemoryAllocationFailed;
|
||||||
}
|
}
|
||||||
auto backing_memory_fb = kernel.memory.GetFCRAMRef(*offset_fb);
|
auto backing_memory_fb = kernel.memory.GetFCRAMRef(*offset_fb);
|
||||||
Service::PLGLDR::PLG_LDR::SetPluginFBAddr(Memory::FCRAM_PADDR + *offset_fb);
|
plg_ldr.SetPluginFBAddr(Memory::FCRAM_PADDR + *offset_fb);
|
||||||
std::fill(backing_memory_fb.GetPtr(), backing_memory_fb.GetPtr() + _3GX_fb_size, 0);
|
std::fill(backing_memory_fb.GetPtr(), backing_memory_fb.GetPtr() + _3GX_fb_size, 0);
|
||||||
|
|
||||||
auto vma_heap_fb = process.vm_manager.MapBackingMemory(
|
auto vma_heap_fb = process.vm_manager.MapBackingMemory(
|
||||||
@ -357,7 +357,7 @@ void FileSys::Plugin3GXLoader::MapBootloader(Kernel::Process& process, Kernel::K
|
|||||||
// Write bootloader
|
// Write bootloader
|
||||||
kernel.memory.WriteBlock(
|
kernel.memory.WriteBlock(
|
||||||
process, _3GX_exe_load_addr - bootloader_memory_size, bootloader.data(),
|
process, _3GX_exe_load_addr - bootloader_memory_size, bootloader.data(),
|
||||||
std::min<size_t>(bootloader.size() * sizeof(u32), bootloader_memory_size));
|
std::min<std::size_t>(bootloader.size() * sizeof(u32), bootloader_memory_size));
|
||||||
|
|
||||||
game_instructions[0] = 0xE51FF004; // ldr pc, [pc, #-4]
|
game_instructions[0] = 0xE51FF004; // ldr pc, [pc, #-4]
|
||||||
game_instructions[1] = _3GX_exe_load_addr - bootloader_memory_size;
|
game_instructions[1] = _3GX_exe_load_addr - bootloader_memory_size;
|
||||||
|
@ -43,7 +43,8 @@ class FileBackend;
|
|||||||
class Plugin3GXLoader {
|
class Plugin3GXLoader {
|
||||||
public:
|
public:
|
||||||
Loader::ResultStatus Load(Service::PLGLDR::PLG_LDR::PluginLoaderContext& plg_context,
|
Loader::ResultStatus Load(Service::PLGLDR::PLG_LDR::PluginLoaderContext& plg_context,
|
||||||
Kernel::Process& process, Kernel::KernelSystem& kernel);
|
Kernel::Process& process, Kernel::KernelSystem& kernel,
|
||||||
|
Service::PLGLDR::PLG_LDR& plg_ldr);
|
||||||
|
|
||||||
struct PluginHeader {
|
struct PluginHeader {
|
||||||
u32_le magic;
|
u32_le magic;
|
||||||
@ -68,9 +69,10 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Loader::ResultStatus Map(Service::PLGLDR::PLG_LDR::PluginLoaderContext& plg_context,
|
Loader::ResultStatus Map(Service::PLGLDR::PLG_LDR::PluginLoaderContext& plg_context,
|
||||||
Kernel::Process& process, Kernel::KernelSystem& kernel);
|
Kernel::Process& process, Kernel::KernelSystem& kernel,
|
||||||
|
Service::PLGLDR::PLG_LDR& plg_ldr);
|
||||||
|
|
||||||
static constexpr size_t bootloader_memory_size = 0x1000;
|
static constexpr std::size_t bootloader_memory_size = 0x1000;
|
||||||
static void MapBootloader(Kernel::Process& process, Kernel::KernelSystem& kernel,
|
static void MapBootloader(Kernel::Process& process, Kernel::KernelSystem& kernel,
|
||||||
u32 memory_offset, std::span<const u32> exe_load_func,
|
u32 memory_offset, std::span<const u32> exe_load_func,
|
||||||
const u32_le* exe_load_args, u32 checksum_size, u32 exe_checksum,
|
const u32_le* exe_load_args, u32 checksum_size, u32 exe_checksum,
|
||||||
|
@ -16,7 +16,7 @@ std::size_t DirectRomFSReader::ReadFile(std::size_t offset, std::size_t length,
|
|||||||
return 0; // Crypto++ does not like zero size buffer
|
return 0; // Crypto++ does not like zero size buffer
|
||||||
|
|
||||||
const auto segments = BreakupRead(offset, length);
|
const auto segments = BreakupRead(offset, length);
|
||||||
size_t read_progress = 0;
|
std::size_t read_progress = 0;
|
||||||
|
|
||||||
// Skip cache if the read is too big
|
// Skip cache if the read is too big
|
||||||
if (segments.size() == 1 && segments[0].second > cache_line_size) {
|
if (segments.size() == 1 && segments[0].second > cache_line_size) {
|
||||||
@ -33,8 +33,8 @@ std::size_t DirectRomFSReader::ReadFile(std::size_t offset, std::size_t length,
|
|||||||
// TODO(PabloMK7): Make cache thread safe, read the comment in CacheReady function.
|
// TODO(PabloMK7): Make cache thread safe, read the comment in CacheReady function.
|
||||||
// std::unique_lock<std::shared_mutex> read_guard(cache_mutex);
|
// std::unique_lock<std::shared_mutex> read_guard(cache_mutex);
|
||||||
for (const auto& seg : segments) {
|
for (const auto& seg : segments) {
|
||||||
size_t read_size = cache_line_size;
|
std::size_t read_size = cache_line_size;
|
||||||
size_t page = OffsetToPage(seg.first);
|
std::size_t page = OffsetToPage(seg.first);
|
||||||
// Check if segment is in cache
|
// Check if segment is in cache
|
||||||
auto cache_entry = cache.request(page);
|
auto cache_entry = cache.request(page);
|
||||||
if (!cache_entry.first) {
|
if (!cache_entry.first) {
|
||||||
@ -51,7 +51,7 @@ std::size_t DirectRomFSReader::ReadFile(std::size_t offset, std::size_t length,
|
|||||||
LOG_TRACE(Service_FS, "RomFS Cache HIT: page={}, length={}, into={}", page, seg.second,
|
LOG_TRACE(Service_FS, "RomFS Cache HIT: page={}, length={}, into={}", page, seg.second,
|
||||||
(seg.first - page));
|
(seg.first - page));
|
||||||
}
|
}
|
||||||
size_t copy_amount =
|
std::size_t copy_amount =
|
||||||
(read_size > (seg.first - page))
|
(read_size > (seg.first - page))
|
||||||
? std::min((seg.first - page) + seg.second, read_size) - (seg.first - page)
|
? std::min((seg.first - page) + seg.second, read_size) - (seg.first - page)
|
||||||
: 0;
|
: 0;
|
||||||
@ -98,10 +98,10 @@ std::vector<std::pair<std::size_t, std::size_t>> DirectRomFSReader::BreakupRead(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t curr_offset = offset;
|
std::size_t curr_offset = offset;
|
||||||
while (length) {
|
while (length) {
|
||||||
size_t next_page = OffsetToPage(curr_offset + cache_line_size);
|
std::size_t next_page = OffsetToPage(curr_offset + cache_line_size);
|
||||||
size_t curr_page_len = std::min(length, next_page - curr_offset);
|
std::size_t curr_page_len = std::min(length, next_page - curr_offset);
|
||||||
ret.push_back(std::make_pair(curr_offset, curr_page_len));
|
ret.push_back(std::make_pair(curr_offset, curr_page_len));
|
||||||
curr_offset = next_page;
|
curr_offset = next_page;
|
||||||
length -= curr_page_len;
|
length -= curr_page_len;
|
||||||
|
@ -67,8 +67,8 @@ private:
|
|||||||
u64 data_size;
|
u64 data_size;
|
||||||
|
|
||||||
// Total cache size: 128KB
|
// Total cache size: 128KB
|
||||||
static constexpr size_t cache_line_size = (1 << 13); // About 8KB
|
static constexpr std::size_t cache_line_size = (1 << 13); // About 8KB
|
||||||
static constexpr size_t cache_line_count = 16;
|
static constexpr std::size_t cache_line_count = 16;
|
||||||
|
|
||||||
Common::StaticLRUCache<std::size_t, std::array<u8, cache_line_size>, cache_line_count> cache;
|
Common::StaticLRUCache<std::size_t, std::array<u8, cache_line_size>, cache_line_count> cache;
|
||||||
// TODO(PabloMK7): Make cache thread safe, read the comment in CacheReady function.
|
// TODO(PabloMK7): Make cache thread safe, read the comment in CacheReady function.
|
||||||
|
@ -43,17 +43,17 @@ ResultVal<std::unique_ptr<FileBackend>> SaveDataArchive::OpenFile(const Path& pa
|
|||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode.hex == 0) {
|
if (mode.hex == 0) {
|
||||||
LOG_ERROR(Service_FS, "Empty open mode");
|
LOG_ERROR(Service_FS, "Empty open mode");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode.create_flag && !mode.write_flag) {
|
if (mode.create_flag && !mode.write_flag) {
|
||||||
LOG_ERROR(Service_FS, "Create flag set but write flag not set");
|
LOG_ERROR(Service_FS, "Create flag set but write flag not set");
|
||||||
return ERROR_UNSUPPORTED_OPEN_FLAGS;
|
return ResultUnsupportedOpenFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
@ -61,19 +61,19 @@ ResultVal<std::unique_ptr<FileBackend>> SaveDataArchive::OpenFile(const Path& pa
|
|||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ResultFileNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
||||||
return ERROR_PATH_NOT_FOUND;
|
return ResultPathNotFound;
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
LOG_ERROR(Service_FS, "Unexpected file or directory in {}", full_path);
|
LOG_ERROR(Service_FS, "Unexpected file or directory in {}", full_path);
|
||||||
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
|
return ResultUnexpectedFileOrDirectory;
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
if (!mode.create_flag) {
|
if (!mode.create_flag) {
|
||||||
LOG_ERROR(Service_FS, "Non-existing file {} can't be open without mode create.",
|
LOG_ERROR(Service_FS, "Non-existing file {} can't be open without mode create.",
|
||||||
full_path);
|
full_path);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ResultFileNotFound;
|
||||||
} else {
|
} else {
|
||||||
// Create the file
|
// Create the file
|
||||||
FileUtil::CreateEmptyFile(full_path);
|
FileUtil::CreateEmptyFile(full_path);
|
||||||
@ -86,19 +86,19 @@ ResultVal<std::unique_ptr<FileBackend>> SaveDataArchive::OpenFile(const Path& pa
|
|||||||
FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb");
|
FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb");
|
||||||
if (!file.IsOpen()) {
|
if (!file.IsOpen()) {
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening {}", full_path);
|
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening {}", full_path);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ResultFileNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<SaveDataDelayGenerator>();
|
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<SaveDataDelayGenerator>();
|
||||||
return std::make_unique<DiskFile>(std::move(file), mode, std::move(delay_generator));
|
return std::make_unique<DiskFile>(std::move(file), mode, std::move(delay_generator));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SaveDataArchive::DeleteFile(const Path& path) const {
|
Result SaveDataArchive::DeleteFile(const Path& path) const {
|
||||||
const PathParser path_parser(path);
|
const PathParser path_parser(path);
|
||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
@ -106,110 +106,109 @@ ResultCode SaveDataArchive::DeleteFile(const Path& path) const {
|
|||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ResultFileNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
||||||
return ERROR_PATH_NOT_FOUND;
|
return ResultPathNotFound;
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
LOG_ERROR(Service_FS, "File not found {}", full_path);
|
LOG_ERROR(Service_FS, "File not found {}", full_path);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ResultFileNotFound;
|
||||||
case PathParser::FileFound:
|
case PathParser::FileFound:
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FileUtil::Delete(full_path)) {
|
if (FileUtil::Delete(full_path)) {
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting {}", full_path);
|
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting {}", full_path);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ResultFileNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SaveDataArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
Result SaveDataArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
||||||
const PathParser path_parser_src(src_path);
|
const PathParser path_parser_src(src_path);
|
||||||
|
|
||||||
// TODO: Verify these return codes with HW
|
// TODO: Verify these return codes with HW
|
||||||
if (!path_parser_src.IsValid()) {
|
if (!path_parser_src.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid src path {}", src_path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid src path {}", src_path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathParser path_parser_dest(dest_path);
|
const PathParser path_parser_dest(dest_path);
|
||||||
|
|
||||||
if (!path_parser_dest.IsValid()) {
|
if (!path_parser_dest.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid dest path {}", dest_path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid dest path {}", dest_path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto src_path_full = path_parser_src.BuildHostPath(mount_point);
|
const auto src_path_full = path_parser_src.BuildHostPath(mount_point);
|
||||||
const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point);
|
const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point);
|
||||||
|
|
||||||
if (FileUtil::Rename(src_path_full, dest_path_full)) {
|
if (FileUtil::Rename(src_path_full, dest_path_full)) {
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
|
// TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
|
||||||
// exist or similar. Verify.
|
// exist or similar. Verify.
|
||||||
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
return Result(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
||||||
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static ResultCode DeleteDirectoryHelper(const Path& path, const std::string& mount_point,
|
static Result DeleteDirectoryHelper(const Path& path, const std::string& mount_point, T deleter) {
|
||||||
T deleter) {
|
|
||||||
const PathParser path_parser(path);
|
const PathParser path_parser(path);
|
||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path_parser.IsRootDirectory())
|
if (path_parser.IsRootDirectory())
|
||||||
return ERROR_DIRECTORY_NOT_EMPTY;
|
return ResultDirectoryNotEmpty;
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
|
|
||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_PATH_NOT_FOUND;
|
return ResultPathNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
||||||
return ERROR_PATH_NOT_FOUND;
|
return ResultPathNotFound;
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
case PathParser::FileFound:
|
case PathParser::FileFound:
|
||||||
LOG_ERROR(Service_FS, "Unexpected file or directory {}", full_path);
|
LOG_ERROR(Service_FS, "Unexpected file or directory {}", full_path);
|
||||||
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
|
return ResultUnexpectedFileOrDirectory;
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleter(full_path)) {
|
if (deleter(full_path)) {
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_ERROR(Service_FS, "Directory not empty {}", full_path);
|
LOG_ERROR(Service_FS, "Directory not empty {}", full_path);
|
||||||
return ERROR_DIRECTORY_NOT_EMPTY;
|
return ResultDirectoryNotEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SaveDataArchive::DeleteDirectory(const Path& path) const {
|
Result SaveDataArchive::DeleteDirectory(const Path& path) const {
|
||||||
return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir);
|
return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SaveDataArchive::DeleteDirectoryRecursively(const Path& path) const {
|
Result SaveDataArchive::DeleteDirectoryRecursively(const Path& path) const {
|
||||||
return DeleteDirectoryHelper(
|
return DeleteDirectoryHelper(
|
||||||
path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); });
|
path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); });
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SaveDataArchive::CreateFile(const FileSys::Path& path, u64 size) const {
|
Result SaveDataArchive::CreateFile(const FileSys::Path& path, u64 size) const {
|
||||||
const PathParser path_parser(path);
|
const PathParser path_parser(path);
|
||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
@ -217,44 +216,44 @@ ResultCode SaveDataArchive::CreateFile(const FileSys::Path& path, u64 size) cons
|
|||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ResultFileNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
||||||
return ERROR_PATH_NOT_FOUND;
|
return ResultPathNotFound;
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
LOG_ERROR(Service_FS, "Unexpected file in path {}", full_path);
|
LOG_ERROR(Service_FS, "Unexpected file in path {}", full_path);
|
||||||
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
|
return ResultUnexpectedFileOrDirectory;
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
case PathParser::FileFound:
|
case PathParser::FileFound:
|
||||||
LOG_ERROR(Service_FS, "{} already exists", full_path);
|
LOG_ERROR(Service_FS, "{} already exists", full_path);
|
||||||
return ERROR_FILE_ALREADY_EXISTS;
|
return ResultFileAlreadyExists;
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
FileUtil::CreateEmptyFile(full_path);
|
FileUtil::CreateEmptyFile(full_path);
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileUtil::IOFile file(full_path, "wb");
|
FileUtil::IOFile file(full_path, "wb");
|
||||||
// Creates a sparse file (or a normal file on filesystems without the concept of sparse files)
|
// Creates a sparse file (or a normal file on filesystems without the concept of sparse files)
|
||||||
// We do this by seeking to the right size, then writing a single null byte.
|
// We do this by seeking to the right size, then writing a single null byte.
|
||||||
if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) {
|
if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) {
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_ERROR(Service_FS, "Too large file");
|
LOG_ERROR(Service_FS, "Too large file");
|
||||||
return ResultCode(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource,
|
return Result(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource,
|
||||||
ErrorLevel::Info);
|
ErrorLevel::Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SaveDataArchive::CreateDirectory(const Path& path) const {
|
Result SaveDataArchive::CreateDirectory(const Path& path) const {
|
||||||
const PathParser path_parser(path);
|
const PathParser path_parser(path);
|
||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
@ -262,57 +261,57 @@ ResultCode SaveDataArchive::CreateDirectory(const Path& path) const {
|
|||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ResultFileNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
||||||
return ERROR_PATH_NOT_FOUND;
|
return ResultPathNotFound;
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
LOG_ERROR(Service_FS, "Unexpected file in path {}", full_path);
|
LOG_ERROR(Service_FS, "Unexpected file in path {}", full_path);
|
||||||
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
|
return ResultUnexpectedFileOrDirectory;
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
case PathParser::FileFound:
|
case PathParser::FileFound:
|
||||||
LOG_ERROR(Service_FS, "{} already exists", full_path);
|
LOG_ERROR(Service_FS, "{} already exists", full_path);
|
||||||
return ERROR_DIRECTORY_ALREADY_EXISTS;
|
return ResultDirectoryAlreadyExists;
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FileUtil::CreateDir(mount_point + path.AsString())) {
|
if (FileUtil::CreateDir(mount_point + path.AsString())) {
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating {}", mount_point);
|
||||||
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled,
|
return Result(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled,
|
||||||
ErrorLevel::Status);
|
ErrorLevel::Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SaveDataArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
Result SaveDataArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
||||||
const PathParser path_parser_src(src_path);
|
const PathParser path_parser_src(src_path);
|
||||||
|
|
||||||
// TODO: Verify these return codes with HW
|
// TODO: Verify these return codes with HW
|
||||||
if (!path_parser_src.IsValid()) {
|
if (!path_parser_src.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid src path {}", src_path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid src path {}", src_path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathParser path_parser_dest(dest_path);
|
const PathParser path_parser_dest(dest_path);
|
||||||
|
|
||||||
if (!path_parser_dest.IsValid()) {
|
if (!path_parser_dest.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid dest path {}", dest_path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid dest path {}", dest_path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto src_path_full = path_parser_src.BuildHostPath(mount_point);
|
const auto src_path_full = path_parser_src.BuildHostPath(mount_point);
|
||||||
const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point);
|
const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point);
|
||||||
|
|
||||||
if (FileUtil::Rename(src_path_full, dest_path_full)) {
|
if (FileUtil::Rename(src_path_full, dest_path_full)) {
|
||||||
return RESULT_SUCCESS;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
|
// TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
|
||||||
// exist or similar. Verify.
|
// exist or similar. Verify.
|
||||||
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
return Result(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
||||||
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<DirectoryBackend>> SaveDataArchive::OpenDirectory(
|
ResultVal<std::unique_ptr<DirectoryBackend>> SaveDataArchive::OpenDirectory(
|
||||||
@ -321,7 +320,7 @@ ResultVal<std::unique_ptr<DirectoryBackend>> SaveDataArchive::OpenDirectory(
|
|||||||
|
|
||||||
if (!path_parser.IsValid()) {
|
if (!path_parser.IsValid()) {
|
||||||
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
|
||||||
return ERROR_INVALID_PATH;
|
return ResultInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto full_path = path_parser.BuildHostPath(mount_point);
|
const auto full_path = path_parser.BuildHostPath(mount_point);
|
||||||
@ -329,15 +328,15 @@ ResultVal<std::unique_ptr<DirectoryBackend>> SaveDataArchive::OpenDirectory(
|
|||||||
switch (path_parser.GetHostStatus(mount_point)) {
|
switch (path_parser.GetHostStatus(mount_point)) {
|
||||||
case PathParser::InvalidMountPoint:
|
case PathParser::InvalidMountPoint:
|
||||||
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ResultFileNotFound;
|
||||||
case PathParser::PathNotFound:
|
case PathParser::PathNotFound:
|
||||||
case PathParser::NotFound:
|
case PathParser::NotFound:
|
||||||
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
LOG_ERROR(Service_FS, "Path not found {}", full_path);
|
||||||
return ERROR_PATH_NOT_FOUND;
|
return ResultPathNotFound;
|
||||||
case PathParser::FileInPath:
|
case PathParser::FileInPath:
|
||||||
case PathParser::FileFound:
|
case PathParser::FileFound:
|
||||||
LOG_ERROR(Service_FS, "Unexpected file in path {}", full_path);
|
LOG_ERROR(Service_FS, "Unexpected file in path {}", full_path);
|
||||||
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
|
return ResultUnexpectedFileOrDirectory;
|
||||||
case PathParser::DirectoryFound:
|
case PathParser::DirectoryFound:
|
||||||
break; // Expected 'success' case
|
break; // Expected 'success' case
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user