Compare commits

..

19 Commits

Author SHA1 Message Date
Zach Hilman
e8cb6f5c9b registration: Add Data_Unknown5 NCAContentType 2018-08-20 17:34:18 -04:00
Zach Hilman
27da7bc9da filesystem: Add support for loading of system archives 2018-08-18 21:28:23 -04:00
James Rowe
367feaefa0 Merge pull request #838 from FearlessTobi/port-3616
Port #3616 from Citra: "appveyor: set jobs to 4 for mingw"
2018-08-18 11:45:51 -06:00
bunnei
6eba539f4a Merge pull request #1100 from ogniK5377/missing-pred
Added pred-condition GreaterThanWithNan
2018-08-18 10:32:59 -04:00
David Marcec
63dff47e22 Added predcondition GreaterThanWithNan 2018-08-18 17:49:59 +10:00
bunnei
504cff2b7a Merge pull request #1096 from bunnei/supported-blits
gl_rasterizer_cache: Remove asserts for supported blits.
2018-08-17 22:41:53 -04:00
bunnei
804aebf7c7 Merge pull request #1097 from bunnei/gl-critical
renderer_opengl: Treat OpenGL errors as critical.
2018-08-17 10:39:13 -04:00
greggameplayer
2003771789 Implement SetIdleTimeDetectionExtension & GetIdleTimeDetectionExtension (#1059)
* Used by Mario Tennis Aces
2018-08-17 00:23:08 -04:00
bunnei
f246fd778d Merge pull request #1090 from lioncash/ctor-assign
core: Delete System copy/move constructors and assignment operators
2018-08-17 00:19:55 -04:00
bunnei
1db7839f11 Merge pull request #1091 from lioncash/warning
qt/main: Get rid of compilation warnings
2018-08-17 00:19:05 -04:00
bunnei
224be09d66 Merge pull request #1093 from greggameplayer/GetDefaultDisplayResolutionChangeEvent
Implement GetDefaultDisplayResolutionChangeEvent
2018-08-17 00:18:35 -04:00
bunnei
da7226442f renderer_opengl: Treat OpenGL errors as critical. 2018-08-17 00:09:27 -04:00
greggameplayer
cef35e7c9c correct coding style 2018-08-16 23:46:06 +02:00
greggameplayer
928e78dced Implement GetDefaultDisplayResolutionChangeEvent
Require by Toki Tori and Toki Tori 2+
2018-08-16 23:25:54 +02:00
Lioncash
9791f0d590 qt/main: Unindent code in OnMenuInstallToNAND()
We can change this into an early-return if the filename is empty.
There's no need to include all of the code within the if statement.
2018-08-16 10:37:58 -04:00
Lioncash
2a3d7128d1 qt/main: Make installation dialog text within OnMenuInstallToNAND() translatable
This is user-facing text, so it should be marked as translatable by Qt.
2018-08-16 10:36:42 -04:00
Lioncash
aac807fd3a qt/main: Get rid of compilation warnings
Gets rid of truncation warnings about conversion to int. While we're at
it, we can also de-hardcode the buffer size being used.
2018-08-16 10:28:06 -04:00
Lioncash
a0ce6de913 core: Delete System copy/move constructors and assignment operators
Prevents potentially making copies or doing silly things by accident
with the System instance, particularly given our current core is
designed (unfortunately) around one instantiable instance.

This will prevent the accidental case of:

auto instance = System::Instance();

being compiled without warning when it's supposed to be:

auto& instance = System::Instance();
2018-08-16 10:21:14 -04:00
fearlessTobi
ed8b2a0254 Port #3616 from Citra 2018-07-26 15:55:23 +02:00
16 changed files with 238 additions and 112 deletions

View File

@@ -53,7 +53,7 @@ build_script:
# https://www.appveyor.com/docs/build-phase
msbuild msvc_build/yuzu.sln /maxcpucount /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
} else {
C:\msys64\usr\bin\bash.exe -lc 'mingw32-make -C mingw_build/ 2>&1'
C:\msys64\usr\bin\bash.exe -lc 'mingw32-make -j4 -C mingw_build/ 2>&1'
}
after_build:

View File

@@ -40,6 +40,12 @@ namespace Core {
class System {
public:
System(const System&) = delete;
System& operator=(const System&) = delete;
System(System&&) = delete;
System& operator=(System&&) = delete;
~System();
/**

View File

@@ -27,6 +27,7 @@ enum class NCAContentType : u8 {
Control = 2,
Manual = 3,
Data = 4,
Data_Unknown5 = 5, ///< Seems to be used on some system archives
};
enum class NCASectionCryptoType : u8 {

View File

@@ -77,12 +77,13 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
case NCAContentType::Control:
return ContentRecordType::Control;
case NCAContentType::Data:
case NCAContentType::Data_Unknown5:
return ContentRecordType::Data;
case NCAContentType::Manual:
// TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal.
return ContentRecordType::Manual;
default:
UNREACHABLE();
UNREACHABLE_MSG("Invalid NCAContentType={:02X}", static_cast<u8>(type));
}
}

View File

@@ -6,7 +6,9 @@
#include <memory>
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/kernel/process.h"
namespace FileSys {
@@ -17,9 +19,41 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
}
}
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id) {
// TODO(DarkLordZach): Use title id.
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
return MakeResult<VirtualFile>(file);
}
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) {
switch (storage) {
case StorageId::NandSystem: {
const auto res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);
if (res == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return ResultCode(-1);
}
const auto romfs = res->GetRomFS();
if (romfs == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return ResultCode(-1);
}
return MakeResult<VirtualFile>(romfs);
}
case StorageId::NandUser: {
const auto res = Service::FileSystem::GetUserNANDContents()->GetEntry(title_id, type);
if (res == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return ResultCode(-1);
}
const auto romfs = res->GetRomFS();
if (romfs == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return ResultCode(-1);
}
return MakeResult<VirtualFile>(romfs);
}
default:
UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage));
}
}
} // namespace FileSys

View File

@@ -11,12 +11,22 @@
namespace FileSys {
enum class StorageId : u8 {
None = 0,
Host = 1,
GameCard = 2,
NandSystem = 3,
NandUser = 4,
SdCard = 5,
};
/// File system interface to the RomFS archive
class RomFSFactory {
public:
explicit RomFSFactory(Loader::AppLoader& app_loader);
ResultVal<VirtualFile> Open(u64 title_id);
ResultVal<VirtualFile> OpenCurrentProcess();
ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type);
private:
VirtualFile file;

View File

@@ -145,8 +145,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
{51, nullptr, "ApproveToDisplay"},
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
{61, nullptr, "SetMediaPlaybackState"},
{62, nullptr, "SetIdleTimeDetectionExtension"},
{63, nullptr, "GetIdleTimeDetectionExtension"},
{62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
{63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"},
{64, nullptr, "SetInputDetectionSourceSet"},
{65, nullptr, "ReportUserIsActive"},
{66, nullptr, "GetCurrentIlluminance"},
@@ -281,6 +281,23 @@ void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx)
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
idle_time_detection_extension = rp.Pop<u32>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(idle_time_detection_extension);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") {
static const FunctionInfo functions[] = {
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
@@ -306,7 +323,8 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter"
{52, nullptr, "SwitchLcdBacklight"},
{55, nullptr, "IsInControllerFirmwareUpdateSection"},
{60, nullptr, "GetDefaultDisplayResolution"},
{61, nullptr, "GetDefaultDisplayResolutionChangeEvent"},
{61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent,
"GetDefaultDisplayResolutionChangeEvent"},
{62, nullptr, "GetHdcpAuthenticationState"},
{63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
};
@@ -341,6 +359,16 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
event->Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(event);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
const bool use_docked_mode{Settings::values.use_docked_mode};
IPC::ResponseBuilder rb{ctx, 3};

View File

@@ -87,9 +87,12 @@ private:
void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx);
void SetScreenShotPermission(Kernel::HLERequestContext& ctx);
void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);
void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
Kernel::SharedPtr<Kernel::Event> launchable_event;
u32 idle_time_detection_extension = 0;
};
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
@@ -110,6 +113,7 @@ private:
void GetEventHandle(Kernel::HLERequestContext& ctx);
void ReceiveMessage(Kernel::HLERequestContext& ctx);
void GetCurrentFocusState(Kernel::HLERequestContext& ctx);
void GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx);
void GetOperationMode(Kernel::HLERequestContext& ctx);
void GetPerformanceMode(Kernel::HLERequestContext& ctx);

View File

@@ -256,15 +256,28 @@ ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
return RESULT_SUCCESS;
}
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id) {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}", title_id);
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
LOG_TRACE(Service_FS, "Opening RomFS for current process");
if (romfs_factory == nullptr) {
// TODO(bunnei): Find a better error code for this
return ResultCode(-1);
}
return romfs_factory->Open(title_id);
return romfs_factory->OpenCurrentProcess();
}
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type) {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
title_id, static_cast<u8>(storage_id), static_cast<u8>(type));
if (romfs_factory == nullptr) {
// TODO(bunnei): Find a better error code for this
return ResultCode(-1);
}
return romfs_factory->Open(title_id, storage_id, type);
}
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,

View File

@@ -27,7 +27,9 @@ ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory)
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id);
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess();
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type);
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
FileSys::SaveDataDescriptor save_struct);
ResultVal<FileSys::VirtualDir> OpenSDMC();

View File

@@ -23,15 +23,6 @@
namespace Service::FileSystem {
enum class StorageId : u8 {
None = 0,
Host = 1,
GameCard = 2,
NandSystem = 3,
NandUser = 4,
SdCard = 5,
};
class IStorage final : public ServiceFramework<IStorage> {
public:
explicit IStorage(FileSys::VirtualFile backend_)
@@ -467,7 +458,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
{110, nullptr, "OpenContentStorageFileSystem"},
{200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"},
{201, nullptr, "OpenDataStorageByProgramId"},
{202, nullptr, "OpenDataStorageByDataId"},
{202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"},
{203, &FSP_SRV::OpenRomStorage, "OpenRomStorage"},
{400, nullptr, "OpenDeviceOperator"},
{500, nullptr, "OpenSdCardDetectionEventNotifier"},
@@ -580,7 +571,7 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
auto romfs = OpenRomFS(Core::System::GetInstance().CurrentProcess()->program_id);
auto romfs = OpenRomFSCurrentProcess();
if (romfs.Failed()) {
// TODO (bunnei): Find the right error code to use here
LOG_CRITICAL(Service_FS, "no file system interface available!");
@@ -596,10 +587,37 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IStorage>(std::move(storage));
}
void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage_id = rp.PopRaw<FileSys::StorageId>();
const auto unknown = rp.PopRaw<u32>();
const auto title_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
static_cast<u8>(storage_id), unknown, title_id);
auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
if (data.Failed()) {
// TODO(DarkLordZach): Find the right error code to use here
LOG_ERROR(Service_FS,
"could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
static_cast<u8>(storage_id));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultCode(-1));
return;
}
IStorage storage(std::move(data.Unwrap()));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IStorage>(std::move(storage));
}
void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto storage_id = rp.PopRaw<StorageId>();
auto storage_id = rp.PopRaw<FileSys::StorageId>();
auto title_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}",

View File

@@ -25,6 +25,7 @@ private:
void MountSaveData(Kernel::HLERequestContext& ctx);
void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
void OpenRomStorage(Kernel::HLERequestContext& ctx);
FileSys::VirtualFile romfs;

View File

@@ -141,6 +141,7 @@ enum class PredCondition : u64 {
NotEqual = 5,
GreaterEqual = 6,
LessThanWithNan = 9,
GreaterThanWithNan = 12,
NotEqualWithNan = 13,
// TODO(Subv): Other condition types
};

View File

@@ -703,10 +703,11 @@ private:
const std::string& op_a, const std::string& op_b) const {
using Tegra::Shader::PredCondition;
static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = {
{PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="},
{PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"},
{PredCondition::NotEqual, "!="}, {PredCondition::GreaterEqual, ">="},
{PredCondition::LessThanWithNan, "<"}, {PredCondition::NotEqualWithNan, "!="},
{PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="},
{PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"},
{PredCondition::NotEqual, "!="}, {PredCondition::GreaterEqual, ">="},
{PredCondition::LessThanWithNan, "<"}, {PredCondition::NotEqualWithNan, "!="},
{PredCondition::GreaterThanWithNan, ">"},
};
const auto& comparison{PredicateComparisonStrings.find(condition)};
@@ -715,7 +716,8 @@ private:
std::string predicate{'(' + op_a + ") " + comparison->second + " (" + op_b + ')'};
if (condition == PredCondition::LessThanWithNan ||
condition == PredCondition::NotEqualWithNan) {
condition == PredCondition::NotEqualWithNan ||
condition == PredCondition::GreaterThanWithNan) {
predicate += " || isnan(" + op_a + ") || isnan(" + op_b + ')';
}

View File

@@ -425,7 +425,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH:
LOG_ERROR(Render_OpenGL, format, str_source, str_type, id, message);
LOG_CRITICAL(Render_OpenGL, format, str_source, str_type, id, message);
break;
case GL_DEBUG_SEVERITY_MEDIUM:
LOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message);

View File

@@ -628,24 +628,33 @@ void GMainWindow::OnMenuInstallToNAND() {
QString filename = QFileDialog::getOpenFileName(this, tr("Install File"),
UISettings::values.roms_path, file_filter);
if (filename.isEmpty()) {
return;
}
const auto qt_raw_copy = [this](FileSys::VirtualFile src, FileSys::VirtualFile dest) {
if (src == nullptr || dest == nullptr)
return false;
if (!dest->Resize(src->GetSize()))
return false;
QProgressDialog progress(fmt::format("Installing file \"{}\"...", src->GetName()).c_str(),
"Cancel", 0, src->GetSize() / 0x1000, this);
std::array<u8, 0x1000> buffer{};
const int progress_maximum = static_cast<int>(src->GetSize() / buffer.size());
QProgressDialog progress(
tr("Installing file \"%1\"...").arg(QString::fromStdString(src->GetName())),
tr("Cancel"), 0, progress_maximum, this);
progress.setWindowModality(Qt::WindowModal);
std::array<u8, 0x1000> buffer{};
for (size_t i = 0; i < src->GetSize(); i += 0x1000) {
for (size_t i = 0; i < src->GetSize(); i += buffer.size()) {
if (progress.wasCanceled()) {
dest->Resize(0);
return false;
}
progress.setValue(i / 0x1000);
const int progress_value = static_cast<int>(i / buffer.size());
progress.setValue(progress_value);
const auto read = src->Read(buffer.data(), buffer.size(), i);
dest->Write(buffer.data(), read, i);
}
@@ -668,92 +677,88 @@ void GMainWindow::OnMenuInstallToNAND() {
};
const auto overwrite = [this]() {
return QMessageBox::question(this, "Failed to Install",
"The file you are attempting to install already exists "
"in the cache. Would you like to overwrite it?") ==
return QMessageBox::question(this, tr("Failed to Install"),
tr("The file you are attempting to install already exists "
"in the cache. Would you like to overwrite it?")) ==
QMessageBox::Yes;
};
if (!filename.isEmpty()) {
if (filename.endsWith("xci", Qt::CaseInsensitive)) {
const auto xci = std::make_shared<FileSys::XCI>(
vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
if (xci->GetStatus() != Loader::ResultStatus::Success) {
failed();
return;
}
const auto res =
Service::FileSystem::GetUserNANDContents()->InstallEntry(xci, false, qt_raw_copy);
if (res == FileSys::InstallResult::Success) {
success();
} else {
if (res == FileSys::InstallResult::ErrorAlreadyExists) {
if (overwrite()) {
const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry(
xci, true, qt_raw_copy);
if (res2 == FileSys::InstallResult::Success) {
success();
} else {
failed();
}
if (filename.endsWith("xci", Qt::CaseInsensitive)) {
const auto xci = std::make_shared<FileSys::XCI>(
vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
if (xci->GetStatus() != Loader::ResultStatus::Success) {
failed();
return;
}
const auto res =
Service::FileSystem::GetUserNANDContents()->InstallEntry(xci, false, qt_raw_copy);
if (res == FileSys::InstallResult::Success) {
success();
} else {
if (res == FileSys::InstallResult::ErrorAlreadyExists) {
if (overwrite()) {
const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry(
xci, true, qt_raw_copy);
if (res2 == FileSys::InstallResult::Success) {
success();
} else {
failed();
}
}
} else {
failed();
}
}
} else {
const auto nca = std::make_shared<FileSys::NCA>(
vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
if (nca->GetStatus() != Loader::ResultStatus::Success) {
failed();
return;
}
const QStringList tt_options{tr("System Application"),
tr("System Archive"),
tr("System Application Update"),
tr("Firmware Package (Type A)"),
tr("Firmware Package (Type B)"),
tr("Game"),
tr("Game Update"),
tr("Game DLC"),
tr("Delta Title")};
bool ok;
const auto item = QInputDialog::getItem(
this, tr("Select NCA Install Type..."),
tr("Please select the type of title you would like to install this NCA as:\n(In "
"most instances, the default 'Game' is fine.)"),
tt_options, 5, false, &ok);
auto index = tt_options.indexOf(item);
if (!ok || index == -1) {
QMessageBox::warning(this, tr("Failed to Install"),
tr("The title type you selected for the NCA is invalid."));
return;
}
if (index >= 5)
index += 0x7B;
const auto res = Service::FileSystem::GetUserNANDContents()->InstallEntry(
nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy);
if (res == FileSys::InstallResult::Success) {
success();
} else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
if (overwrite()) {
const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry(
nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
if (res2 == FileSys::InstallResult::Success) {
success();
} else {
failed();
}
}
} else {
const auto nca = std::make_shared<FileSys::NCA>(
vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
if (nca->GetStatus() != Loader::ResultStatus::Success) {
failed();
return;
}
static const QStringList tt_options{"System Application",
"System Archive",
"System Application Update",
"Firmware Package (Type A)",
"Firmware Package (Type B)",
"Game",
"Game Update",
"Game DLC",
"Delta Title"};
bool ok;
const auto item = QInputDialog::getItem(
this, tr("Select NCA Install Type..."),
tr("Please select the type of title you would like to install this NCA as:\n(In "
"most instances, the default 'Game' is fine.)"),
tt_options, 5, false, &ok);
auto index = tt_options.indexOf(item);
if (!ok || index == -1) {
QMessageBox::warning(this, tr("Failed to Install"),
tr("The title type you selected for the NCA is invalid."));
return;
}
if (index >= 5)
index += 0x7B;
const auto res = Service::FileSystem::GetUserNANDContents()->InstallEntry(
nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy);
if (res == FileSys::InstallResult::Success) {
success();
} else {
if (res == FileSys::InstallResult::ErrorAlreadyExists) {
if (overwrite()) {
const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry(
nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
if (res2 == FileSys::InstallResult::Success) {
success();
} else {
failed();
}
}
} else {
failed();
}
}
failed();
}
}
}