mirror of
https://git.suyu.dev/suyu/suyu
synced 2025-12-08 22:02:07 -06:00
Compare commits
3 Commits
v0.0.3
...
qlaunch-wo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fed0ec70e0 | ||
|
|
097e340d40 | ||
|
|
aebf13752e |
@@ -6,7 +6,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
**Note**: We do not support or condone piracy in any form. In order to use suyu, you'll need keys from your real Switch system, and games which you have legally obtained and paid for. We do not intend to make money or profit from this project.
|
||||
|
||||
We're in need of developers. Please join our Matrix below if you want to contribute!
|
||||
We're in need of developers. Please join our Discord server below if you want to contribute!
|
||||
This repo is based on Yuzu EA 4176.
|
||||
|
||||
<hr />
|
||||
@@ -25,7 +25,7 @@ It is written in C++ with portability in mind, and we're actively working on bui
|
||||
</h4>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://chat.suyu.dev">Matrix</a> |
|
||||
<a href="https://discord.gg/suyu">Discord</a> |
|
||||
<a href="#status">Status</a> |
|
||||
<a href="#development">Development</a> |
|
||||
<a href="#downloads">Downloads</a> |
|
||||
@@ -48,7 +48,7 @@ We currently have builds over at the [Releases](https://git.suyu.dev/suyu/suyu/r
|
||||
|
||||
This project is completely free and open source, and anyone can contribute to help improve suyu.
|
||||
|
||||
Most of the development happens on GitLab. For development discussion, please join us on [Matrix](https://chat.suyu.dev).
|
||||
Most of the development happens on GitLab. For development discussion, please join us on [Discord](https://discord.gg/suyu).
|
||||
|
||||
If you want to contribute, please take a look at the [Contributor's Guide](https://git.suyu.dev/suyu/suyu/wiki/Contributing) and [Developer Information](https://git.suyu.dev/suyu/suyu/wiki/Developer-Information).
|
||||
You can also contact any of the developers on Discord to learn more about the current state of suyu.
|
||||
@@ -77,7 +77,7 @@ We have official builds [here.](https://git.suyu.dev/suyu/suyu/releases) If any
|
||||
|
||||
## Support
|
||||
|
||||
If you have any questions, don't hesitate to ask us on [Matrix](https://chat.suyu.dev). We don't bite!
|
||||
If you have any questions, don't hesitate to ask us on [Discord](https://discord.gg/suyu). We don't bite!
|
||||
|
||||
|
||||
## License
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Modified by palfaiate on <2024/03/07>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -172,6 +172,7 @@ Result KPageTableBase::InitializeForKernel(bool is_64_bit, KVirtualAddress start
|
||||
m_mapped_unsafe_physical_memory = 0;
|
||||
m_mapped_insecure_memory = 0;
|
||||
m_mapped_ipc_server_memory = 0;
|
||||
m_alias_region_extra_size = 0;
|
||||
|
||||
m_memory_block_slab_manager =
|
||||
m_kernel.GetSystemSystemResource().GetMemoryBlockSlabManagerPointer();
|
||||
@@ -269,6 +270,12 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
|
||||
process_code_end = m_code_region_end;
|
||||
}
|
||||
|
||||
m_alias_region_extra_size = 0;
|
||||
if (as_type == Svc::CreateProcessFlag::EnableReservedRegionExtraSize) {
|
||||
m_alias_region_extra_size = GetAddressSpaceSize() / 8;
|
||||
alias_region_size += m_alias_region_extra_size;
|
||||
}
|
||||
|
||||
// Set other basic fields.
|
||||
m_enable_aslr = enable_aslr;
|
||||
m_enable_device_address_space_merge = enable_das_merge;
|
||||
|
||||
@@ -208,6 +208,7 @@ private:
|
||||
size_t m_mapped_unsafe_physical_memory{};
|
||||
size_t m_mapped_insecure_memory{};
|
||||
size_t m_mapped_ipc_server_memory{};
|
||||
size_t m_alias_region_extra_size{};
|
||||
mutable KLightLock m_general_lock;
|
||||
mutable KLightLock m_map_physical_memory_lock;
|
||||
KLightLock m_device_map_lock;
|
||||
@@ -682,6 +683,9 @@ public:
|
||||
size_t GetAliasRegionSize() const {
|
||||
return m_alias_region_end - m_alias_region_start;
|
||||
}
|
||||
size_t GetReservedRegionExtraSize() const {
|
||||
return m_alias_region_extra_size;
|
||||
}
|
||||
size_t GetStackRegionSize() const {
|
||||
return m_stack_region_end - m_stack_region_start;
|
||||
}
|
||||
|
||||
@@ -410,6 +410,9 @@ public:
|
||||
size_t GetAliasRegionSize() const {
|
||||
return m_page_table.GetAliasRegionSize();
|
||||
}
|
||||
size_t GetReservedRegionExtraSize() const {
|
||||
return m_page_table.GetReservedRegionExtraSize();
|
||||
}
|
||||
size_t GetStackRegionSize() const {
|
||||
return m_page_table.GetStackRegionSize();
|
||||
}
|
||||
|
||||
@@ -37,7 +37,8 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
|
||||
case InfoType::TotalNonSystemMemorySize:
|
||||
case InfoType::UsedNonSystemMemorySize:
|
||||
case InfoType::IsApplication:
|
||||
case InfoType::FreeThreadCount: {
|
||||
case InfoType::FreeThreadCount:
|
||||
case InfoType::ReservedRegionExtraSize: {
|
||||
R_UNLESS(info_sub_id == 0, ResultInvalidEnumValue);
|
||||
|
||||
const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
|
||||
@@ -134,6 +135,10 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
|
||||
}
|
||||
R_SUCCEED();
|
||||
|
||||
case InfoType::ReservedRegionExtraSize:
|
||||
*result = process->GetPageTable().GetReservedRegionExtraSize();
|
||||
R_SUCCEED();
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -153,6 +153,7 @@ enum class InfoType : u32 {
|
||||
ThreadTickCount = 25,
|
||||
IsSvcPermitted = 26,
|
||||
IoRegionHint = 27,
|
||||
ReservedRegionExtraSize = 28,
|
||||
|
||||
MesosphereMeta = 65000,
|
||||
MesosphereCurrentProcess = 65001,
|
||||
@@ -642,9 +643,12 @@ enum class CreateProcessFlag : u32 {
|
||||
// 11.x+ DisableDeviceAddressSpaceMerge.
|
||||
DisableDeviceAddressSpaceMerge = (1 << 12),
|
||||
|
||||
EnableReservedRegionExtraSize = (1 << 13),
|
||||
|
||||
// Mask of all flags.
|
||||
All = Is64Bit | AddressSpaceMask | EnableDebug | EnableAslr | IsApplication |
|
||||
PoolPartitionMask | OptimizeMemoryAllocation | DisableDeviceAddressSpaceMerge,
|
||||
PoolPartitionMask | OptimizeMemoryAllocation | DisableDeviceAddressSpaceMerge |
|
||||
EnableReservedRegionExtraSize,
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(CreateProcessFlag);
|
||||
|
||||
|
||||
@@ -323,7 +323,7 @@ public:
|
||||
{11, &IProfileCommon::LoadImage, "LoadImage"},
|
||||
{20, &IProfileCommon::GetImageSize, "GetLargeImageSize"}, // 18.0.0+
|
||||
{21, &IProfileCommon::LoadImage, "LoadLargeImage"}, // 18.0.0+
|
||||
{30, nullptr, "GetImageId"}, // 18.0.0+
|
||||
{30, &IProfileCommon::Unknown, "GetImageId"}, // 18.0.0+
|
||||
};
|
||||
|
||||
RegisterHandlers(functions);
|
||||
@@ -494,6 +494,13 @@ protected:
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void Unknown(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(0);
|
||||
}
|
||||
|
||||
ProfileManager& profile_manager;
|
||||
Common::UUID user_id{}; ///< The user id this profile refers to.
|
||||
};
|
||||
@@ -509,7 +516,15 @@ class IProfileEditor final : public IProfileCommon {
|
||||
public:
|
||||
explicit IProfileEditor(Core::System& system_, Common::UUID user_id_,
|
||||
ProfileManager& profile_manager_)
|
||||
: IProfileCommon{system_, "IProfileEditor", true, user_id_, profile_manager_} {}
|
||||
: IProfileCommon{system_, "IProfileEditor", true, user_id_, profile_manager_} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{30, &IProfileEditor::Unknown, "Unknown"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class ISessionObject final : public ServiceFramework<ISessionObject> {
|
||||
|
||||
@@ -14,6 +14,7 @@ IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u
|
||||
: ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
|
||||
impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
|
||||
event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IAudioDevice::ListAudioDeviceName>, "ListAudioDeviceName"},
|
||||
{1, D<&IAudioDevice::SetAudioDeviceOutputVolume>, "SetAudioDeviceOutputVolume"},
|
||||
@@ -37,6 +38,7 @@ IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u
|
||||
{19, nullptr, "SetAudioDeviceOutputVolumeAutoTuneEnabled"}, // 18.0.0+
|
||||
{20, nullptr, "IsAudioDeviceOutputVolumeAutoTuneEnabled"} // 18.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
|
||||
event->Signal();
|
||||
|
||||
@@ -105,7 +105,7 @@ IParentalControlService::IParentalControlService(Core::System& system_, Capabili
|
||||
{1954, nullptr, "IsBedtimeAlarmEnabled"}, // 18.0.0+
|
||||
{1955, nullptr, "GetBedtimeAlarmTime"}, // 18.0.0+
|
||||
{1956, nullptr, "GetBedtimeAlarmTimeHour"}, // 18.0.0+
|
||||
{1967, nullptr, "GetBedtimeAlarmMinute"}, // 18.0.0+
|
||||
{1967, nullptr, "GetBedtimeAlarmTimeMinute"}, // 18.0.0+
|
||||
{2001, nullptr, "RequestPairingAsync"},
|
||||
{2002, nullptr, "FinishRequestPairing"},
|
||||
{2003, nullptr, "AuthorizePairingAsync"},
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Modified by palfaiate on <2024/03/07>
|
||||
// Reverted palfaiate's changes on <2024/03/25> -Nine-Ball
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
@@ -581,9 +580,6 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
|
||||
remove_menu->addSeparator();
|
||||
QAction* remove_shader_cache = remove_menu->addAction(tr("Remove All Pipeline Caches"));
|
||||
QAction* remove_all_content = remove_menu->addAction(tr("Remove All Installed Contents"));
|
||||
QMenu* dump_romfs_menu = context_menu.addMenu(tr("Dump RomFS"));
|
||||
QAction* dump_romfs = dump_romfs_menu->addAction(tr("Dump RomFS"));
|
||||
QAction* dump_romfs_sdmc = dump_romfs_menu->addAction(tr("Dump RomFS to SDMC"));
|
||||
QAction* verify_integrity = context_menu.addAction(tr("Verify Integrity"));
|
||||
QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard"));
|
||||
QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry"));
|
||||
@@ -651,12 +647,6 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
|
||||
connect(remove_cache_storage, &QAction::triggered, [this, program_id, path] {
|
||||
emit RemoveFileRequested(program_id, GameListRemoveTarget::CacheStorage, path);
|
||||
});
|
||||
connect(dump_romfs, &QAction::triggered, [this, program_id, path]() {
|
||||
emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::Normal);
|
||||
});
|
||||
connect(dump_romfs_sdmc, &QAction::triggered, [this, program_id, path]() {
|
||||
emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::SDMC);
|
||||
});
|
||||
connect(verify_integrity, &QAction::triggered,
|
||||
[this, path]() { emit VerifyIntegrityRequested(path); });
|
||||
connect(copy_tid, &QAction::triggered,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Modified by palfaiate on <2024/03/07>
|
||||
// Reverted palfaiate's changes on <2024/03/25> -Nine-Ball
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -53,11 +52,6 @@ enum class GameListRemoveTarget {
|
||||
CacheStorage,
|
||||
};
|
||||
|
||||
enum class DumpRomFSTarget {
|
||||
Normal,
|
||||
SDMC,
|
||||
};
|
||||
|
||||
enum class GameListShortcutTarget {
|
||||
Desktop,
|
||||
Applications,
|
||||
@@ -119,7 +113,6 @@ signals:
|
||||
void RemoveFileRequested(u64 program_id, GameListRemoveTarget target,
|
||||
const std::string& game_path);
|
||||
void RemovePlayTimeRequested(u64 program_id);
|
||||
void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target);
|
||||
void VerifyIntegrityRequested(const std::string& game_path);
|
||||
void CopyTIDRequested(u64 program_id);
|
||||
void CreateShortcut(u64 program_id, const std::string& game_path,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Modified by palfaiate on <2024/03/07>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <clocale>
|
||||
#include <cmath>
|
||||
@@ -53,18 +55,6 @@
|
||||
#include "suyu/multiplayer/state.h"
|
||||
#include "suyu/util/controller_navigation.h"
|
||||
|
||||
// These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
|
||||
static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper(
|
||||
const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::OpenMode mode) {
|
||||
return vfs->CreateDirectory(path, mode);
|
||||
}
|
||||
|
||||
// Overloaded function, also removed by palafiate
|
||||
static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::VirtualDir& dir,
|
||||
const std::string& path) {
|
||||
return dir->CreateFile(path);
|
||||
}
|
||||
|
||||
#include <fmt/ostream.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
@@ -1475,7 +1465,6 @@ void GMainWindow::ConnectWidgetEvents() {
|
||||
connect(game_list, &GameList::RemoveFileRequested, this, &GMainWindow::OnGameListRemoveFile);
|
||||
connect(game_list, &GameList::RemovePlayTimeRequested, this,
|
||||
&GMainWindow::OnGameListRemovePlayTimeData);
|
||||
connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS);
|
||||
connect(game_list, &GameList::VerifyIntegrityRequested, this,
|
||||
&GMainWindow::OnGameListVerifyIntegrity);
|
||||
connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);
|
||||
@@ -2380,68 +2369,6 @@ void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path));
|
||||
}
|
||||
|
||||
static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& dialog,
|
||||
const FileSys::VirtualDir& src, const FileSys::VirtualDir& dest,
|
||||
bool full) {
|
||||
if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
|
||||
return false;
|
||||
if (dialog.wasCanceled())
|
||||
return false;
|
||||
|
||||
std::vector<u8> buffer(CopyBufferSize);
|
||||
auto last_timestamp = std::chrono::steady_clock::now();
|
||||
|
||||
const auto QtRawCopy = [&](const FileSys::VirtualFile& src_file,
|
||||
const FileSys::VirtualFile& dest_file) {
|
||||
if (src_file == nullptr || dest_file == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (!dest_file->Resize(src_file->GetSize())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < src_file->GetSize(); i += buffer.size()) {
|
||||
if (dialog.wasCanceled()) {
|
||||
dest_file->Resize(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
using namespace std::literals::chrono_literals;
|
||||
const auto new_timestamp = std::chrono::steady_clock::now();
|
||||
|
||||
if ((new_timestamp - last_timestamp) > 33ms) {
|
||||
last_timestamp = new_timestamp;
|
||||
dialog.setValue(
|
||||
static_cast<int>(std::min(read_size, total_size) * 100 / total_size));
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
const auto read = src_file->Read(buffer.data(), buffer.size(), i);
|
||||
dest_file->Write(buffer.data(), read, i);
|
||||
|
||||
read_size += read;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (full) {
|
||||
for (const auto& file : src->GetFiles()) {
|
||||
const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName());
|
||||
if (!QtRawCopy(file, out))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& dir : src->GetSubdirectories()) {
|
||||
const auto out = dest->CreateSubdirectory(dir->GetName());
|
||||
if (!RomFSRawCopy(total_size, read_size, dialog, dir, out, full))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const {
|
||||
switch (type) {
|
||||
case InstalledEntryType::Game:
|
||||
@@ -2683,121 +2610,6 @@ void GMainWindow::RemoveCacheStorage(u64 program_id) {
|
||||
Common::FS::RemoveDirRecursively(path);
|
||||
}
|
||||
|
||||
void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path,
|
||||
DumpRomFSTarget target) {
|
||||
const auto failed = [this] {
|
||||
QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
|
||||
tr("There was an error copying the RomFS files or the user "
|
||||
"cancelled the operation."));
|
||||
};
|
||||
|
||||
const auto loader =
|
||||
Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read));
|
||||
if (loader == nullptr) {
|
||||
failed();
|
||||
return;
|
||||
}
|
||||
|
||||
FileSys::VirtualFile packed_update_raw{};
|
||||
loader->ReadUpdateRaw(packed_update_raw);
|
||||
|
||||
const auto& installed = system->GetContentProvider();
|
||||
|
||||
u64 title_id{};
|
||||
u8 raw_type{};
|
||||
if (!SelectRomFSDumpTarget(installed, program_id, &title_id, &raw_type)) {
|
||||
failed();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto type = static_cast<FileSys::ContentRecordType>(raw_type);
|
||||
const auto base_nca = installed.GetEntry(title_id, type);
|
||||
if (!base_nca) {
|
||||
failed();
|
||||
return;
|
||||
}
|
||||
|
||||
const FileSys::NCA update_nca{packed_update_raw, nullptr};
|
||||
if (type != FileSys::ContentRecordType::Program ||
|
||||
update_nca.GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS ||
|
||||
update_nca.GetTitleId() != FileSys::GetUpdateTitleID(title_id)) {
|
||||
packed_update_raw = {};
|
||||
}
|
||||
|
||||
const auto base_romfs = base_nca->GetRomFS();
|
||||
const auto dump_dir =
|
||||
target == DumpRomFSTarget::Normal
|
||||
? Common::FS::GetSuyuPath(Common::FS::SuyuPath::DumpDir)
|
||||
: Common::FS::GetSuyuPath(Common::FS::SuyuPath::SDMCDir) / "atmosphere" / "contents";
|
||||
const auto romfs_dir = fmt::format("{:016X}/romfs", title_id);
|
||||
|
||||
const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir);
|
||||
|
||||
const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), installed};
|
||||
auto romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, packed_update_raw, false);
|
||||
|
||||
const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::OpenMode::ReadWrite);
|
||||
|
||||
if (out == nullptr) {
|
||||
failed();
|
||||
vfs->DeleteDirectory(path);
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
const QStringList selections{tr("Full"), tr("Skeleton")};
|
||||
const auto res = QInputDialog::getItem(
|
||||
this, tr("Select RomFS Dump Mode"),
|
||||
tr("Please select the how you would like the RomFS dumped.<br>Full will copy all of the "
|
||||
"files into the new directory while <br>skeleton will only create the directory "
|
||||
"structure."),
|
||||
selections, 0, false, &ok);
|
||||
if (!ok) {
|
||||
failed();
|
||||
vfs->DeleteDirectory(path);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto extracted = FileSys::ExtractRomFS(romfs);
|
||||
if (extracted == nullptr) {
|
||||
failed();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto full = res == selections.constFirst();
|
||||
|
||||
// The expected required space is the size of the RomFS + 1 GiB
|
||||
const auto minimum_free_space = romfs->GetSize() + 0x40000000;
|
||||
|
||||
if (full && Common::FS::GetFreeSpaceSize(path) < minimum_free_space) {
|
||||
QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
|
||||
tr("There is not enough free space at %1 to extract the RomFS. Please "
|
||||
"free up space or select a different dump directory at "
|
||||
"Emulation > Configure > System > Filesystem > Dump Root")
|
||||
.arg(QString::fromStdString(path)));
|
||||
return;
|
||||
}
|
||||
|
||||
QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, 100, this);
|
||||
progress.setWindowModality(Qt::WindowModal);
|
||||
progress.setMinimumDuration(100);
|
||||
progress.setAutoClose(false);
|
||||
progress.setAutoReset(false);
|
||||
|
||||
size_t read_size = 0;
|
||||
|
||||
if (RomFSRawCopy(romfs->GetSize(), read_size, progress, extracted, out, full)) {
|
||||
progress.close();
|
||||
QMessageBox::information(this, tr("RomFS Extraction Succeeded!"),
|
||||
tr("The operation completed successfully."));
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(path)));
|
||||
} else {
|
||||
progress.close();
|
||||
failed();
|
||||
vfs->DeleteDirectory(path);
|
||||
}
|
||||
}
|
||||
|
||||
void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) {
|
||||
const auto NotImplemented = [this] {
|
||||
QMessageBox::warning(this, tr("Integrity verification couldn't be performed!"),
|
||||
@@ -4868,66 +4680,6 @@ void GMainWindow::SetFirmwareVersion() {
|
||||
firmware_label->setToolTip(QString::fromStdString(display_title));
|
||||
}
|
||||
|
||||
bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, u64 program_id,
|
||||
u64* selected_title_id, u8* selected_content_record_type) {
|
||||
using ContentInfo = std::tuple<u64, FileSys::TitleType, FileSys::ContentRecordType>;
|
||||
boost::container::flat_set<ContentInfo> available_title_ids;
|
||||
|
||||
const auto RetrieveEntries = [&](FileSys::TitleType title_type,
|
||||
FileSys::ContentRecordType record_type) {
|
||||
const auto entries = installed.ListEntriesFilter(title_type, record_type);
|
||||
for (const auto& entry : entries) {
|
||||
if (FileSys::GetBaseTitleID(entry.title_id) == program_id &&
|
||||
installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success) {
|
||||
available_title_ids.insert({entry.title_id, title_type, record_type});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::Program);
|
||||
RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::HtmlDocument);
|
||||
RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::LegalInformation);
|
||||
RetrieveEntries(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
|
||||
|
||||
if (available_title_ids.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t title_index = 0;
|
||||
|
||||
if (available_title_ids.size() > 1) {
|
||||
QStringList list;
|
||||
for (auto& [title_id, title_type, record_type] : available_title_ids) {
|
||||
const auto hex_title_id = QString::fromStdString(fmt::format("{:X}", title_id));
|
||||
if (record_type == FileSys::ContentRecordType::Program) {
|
||||
list.push_back(QStringLiteral("Program [%1]").arg(hex_title_id));
|
||||
} else if (record_type == FileSys::ContentRecordType::HtmlDocument) {
|
||||
list.push_back(QStringLiteral("HTML document [%1]").arg(hex_title_id));
|
||||
} else if (record_type == FileSys::ContentRecordType::LegalInformation) {
|
||||
list.push_back(QStringLiteral("Legal information [%1]").arg(hex_title_id));
|
||||
} else {
|
||||
list.push_back(
|
||||
QStringLiteral("DLC %1 [%2]").arg(title_id & 0x7FF).arg(hex_title_id));
|
||||
}
|
||||
}
|
||||
|
||||
bool ok;
|
||||
const auto res = QInputDialog::getItem(
|
||||
this, tr("Select RomFS Dump Target"),
|
||||
tr("Please select which RomFS you would like to dump."), list, 0, false, &ok);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
title_index = list.indexOf(res);
|
||||
}
|
||||
|
||||
const auto& [title_id, title_type, record_type] = *available_title_ids.nth(title_index);
|
||||
*selected_title_id = title_id;
|
||||
*selected_content_record_type = static_cast<u8>(record_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GMainWindow::ConfirmClose() {
|
||||
if (emu_thread == nullptr ||
|
||||
UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Never) {
|
||||
|
||||
@@ -51,7 +51,6 @@ class WaitTreeWidget;
|
||||
enum class GameListOpenTarget;
|
||||
enum class GameListRemoveTarget;
|
||||
enum class GameListShortcutTarget;
|
||||
enum class DumpRomFSTarget;
|
||||
enum class InstalledEntryType;
|
||||
class GameListPlaceholder;
|
||||
|
||||
@@ -348,7 +347,6 @@ private slots:
|
||||
void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target,
|
||||
const std::string& game_path);
|
||||
void OnGameListRemovePlayTimeData(u64 program_id);
|
||||
void OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target);
|
||||
void OnGameListVerifyIntegrity(const std::string& game_path);
|
||||
void OnGameListCopyTID(u64 program_id);
|
||||
void OnGameListNavigateToGamedbEntry(u64 program_id,
|
||||
|
||||
Reference in New Issue
Block a user