mirror of
https://github.com/Dark98/threeSD.git
synced 2026-07-03 00:38:58 +00:00
Preliminary work for a title info dialog
pending DRY fixes, etc
This commit is contained in:
@@ -521,6 +521,10 @@ bool SDMCImporter::LoadTMD(ContentType type, u64 id, TitleMetadata& out) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SDMCImporter::LoadTMD(const ContentSpecifier& specifier, TitleMetadata& out) const {
|
||||||
|
return LoadTMD(specifier.type, specifier.id, out);
|
||||||
|
}
|
||||||
|
|
||||||
// English short title name, extdata id, encryption, seed, icon
|
// English short title name, extdata id, encryption, seed, icon
|
||||||
using TitleData = std::tuple<std::string, u64, EncryptionType, bool, std::vector<u16>>;
|
using TitleData = std::tuple<std::string, u64, EncryptionType, bool, std::vector<u16>>;
|
||||||
|
|
||||||
@@ -659,7 +663,7 @@ void SDMCImporter::AbortDumpCXI() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool SDMCImporter::CanBuildLegitCIA(const ContentSpecifier& specifier) const {
|
bool SDMCImporter::CanBuildLegitCIA(const ContentSpecifier& specifier) const {
|
||||||
if (!CanBuildCIA(specifier.type)) {
|
if (!IsTitle(specifier.type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,7 +687,7 @@ bool SDMCImporter::BuildCIA(CIABuildType build_type, const ContentSpecifier& spe
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CanBuildCIA(specifier.type)) {
|
if (!IsTitle(specifier.type)) {
|
||||||
LOG_ERROR(Core, "Unsupported specifier type {}", static_cast<int>(specifier.type));
|
LOG_ERROR(Core, "Unsupported specifier type {}", static_cast<int>(specifier.type));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+233
-232
@@ -1,232 +1,233 @@
|
|||||||
// Copyright 2019 threeSD Project
|
// Copyright 2019 threeSD Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/progress_callback.h"
|
#include "common/progress_callback.h"
|
||||||
#include "core/file_sys/cia_common.h"
|
#include "core/file_sys/cia_common.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
class CIABuilder;
|
class CIABuilder;
|
||||||
class SDMCDecryptor;
|
class SDMCDecryptor;
|
||||||
class TicketDB;
|
class TicketDB;
|
||||||
class TitleDB;
|
class TitleDB;
|
||||||
class TitleMetadata;
|
class TitleMetadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of an importable content.
|
* Type of an importable content.
|
||||||
* Applications, updates and DLCs are all considered titles.
|
* Applications, updates and DLCs are all considered titles.
|
||||||
*/
|
*/
|
||||||
enum class ContentType {
|
enum class ContentType {
|
||||||
Application,
|
Application,
|
||||||
Update,
|
Update,
|
||||||
DLC,
|
DLC,
|
||||||
Savegame,
|
Savegame,
|
||||||
Extdata,
|
Extdata,
|
||||||
SystemArchive,
|
SystemArchive,
|
||||||
Sysdata,
|
Sysdata,
|
||||||
SystemTitle,
|
SystemTitle,
|
||||||
SystemApplet, // This should belong to System Title, but they cause problems so a new category.
|
SystemApplet, // This should belong to System Title, but they cause problems so a new category.
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr bool CanBuildCIA(ContentType type) {
|
constexpr bool IsTitle(ContentType type) {
|
||||||
return type == ContentType::Application || type == ContentType::Update ||
|
return type == ContentType::Application || type == ContentType::Update ||
|
||||||
type == ContentType::DLC || type == ContentType::SystemTitle ||
|
type == ContentType::DLC || type == ContentType::SystemTitle ||
|
||||||
type == ContentType::SystemApplet;
|
type == ContentType::SystemApplet;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encryption type of an importable content.
|
* Encryption type of an importable content.
|
||||||
*/
|
*/
|
||||||
enum class EncryptionType {
|
enum class EncryptionType {
|
||||||
None,
|
None,
|
||||||
FixedKey,
|
FixedKey,
|
||||||
NCCHSecure1,
|
NCCHSecure1,
|
||||||
NCCHSecure2,
|
NCCHSecure2,
|
||||||
NCCHSecure3,
|
NCCHSecure3,
|
||||||
NCCHSecure4,
|
NCCHSecure4,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Struct that specifies an importable content.
|
* Struct that specifies an importable content.
|
||||||
*/
|
*/
|
||||||
struct ContentSpecifier {
|
struct ContentSpecifier {
|
||||||
ContentType type;
|
ContentType type;
|
||||||
u64 id;
|
u64 id;
|
||||||
bool already_exists; ///< Tells whether a file already exists in target path.
|
bool already_exists; ///< Tells whether a file already exists in target path.
|
||||||
u64 maximum_size; ///< The maximum size of the content. May be slightly bigger than real size.
|
u64 maximum_size; ///< The maximum size of the content. May be slightly bigger than real size.
|
||||||
std::string name; ///< Optional. The content's preferred display name.
|
std::string name; ///< Optional. The content's preferred display name.
|
||||||
u64 extdata_id; ///< Extdata ID for Applications.
|
u64 extdata_id; ///< Extdata ID for Applications.
|
||||||
EncryptionType encryption = EncryptionType::None; ///< Only for NCCHs. Encryption scheme.
|
EncryptionType encryption = EncryptionType::None; ///< Only for NCCHs. Encryption scheme.
|
||||||
bool seed_crypto = false; ///< Only for NCCHs. Whether seed crypto is used.
|
bool seed_crypto = false; ///< Only for NCCHs. Whether seed crypto is used.
|
||||||
std::vector<u16> icon; ///< Optional. The content's icon.
|
std::vector<u16> icon; ///< Optional. The content's icon.
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A set of values that are used to initialize the importer.
|
* A set of values that are used to initialize the importer.
|
||||||
* All paths to directories shall end with a '/' (will be automatically added when not present)
|
* All paths to directories shall end with a '/' (will be automatically added when not present)
|
||||||
*/
|
*/
|
||||||
struct Config {
|
struct Config {
|
||||||
std::string sdmc_path; ///< SDMC root path ("Nintendo 3DS/<ID0>/<ID1>")
|
std::string sdmc_path; ///< SDMC root path ("Nintendo 3DS/<ID0>/<ID1>")
|
||||||
std::string user_path; ///< Target user path of Citra
|
std::string user_path; ///< Target user path of Citra
|
||||||
|
|
||||||
// Necessary system files keys are loaded from.
|
// Necessary system files keys are loaded from.
|
||||||
std::string movable_sed_path; ///< Path to movable.sed
|
std::string movable_sed_path; ///< Path to movable.sed
|
||||||
std::string bootrom_path; ///< Path to bootrom (boot9.bin) (Sysdata 0)
|
std::string bootrom_path; ///< Path to bootrom (boot9.bin) (Sysdata 0)
|
||||||
std::string certs_db_path; ///< Path to certs.db. Used while building CIA.
|
std::string certs_db_path; ///< Path to certs.db. Used while building CIA.
|
||||||
|
|
||||||
// Optional, used while building CIA, but usually missing these files won't hinder CIA building.
|
// Optional, used while building CIA, but usually missing these files won't hinder CIA building.
|
||||||
std::string nand_title_db_path; ///< Path to NAND title.db. Entirely optional.
|
std::string nand_title_db_path; ///< Path to NAND title.db. Entirely optional.
|
||||||
std::string ticket_db_path; ///< Path to ticket.db. Entirely optional.
|
std::string ticket_db_path; ///< Path to ticket.db. Entirely optional.
|
||||||
std::string enc_title_keys_bin_path; ///< Path to encTitleKeys.bin. Entireley optional.
|
std::string enc_title_keys_bin_path; ///< Path to encTitleKeys.bin. Entireley optional.
|
||||||
|
|
||||||
// The following system files are optional for importing and are only copied so that Citra
|
// The following system files are optional for importing and are only copied so that Citra
|
||||||
// will be able to decrypt imported encrypted ROMs.
|
// will be able to decrypt imported encrypted ROMs.
|
||||||
|
|
||||||
std::string safe_mode_firm_path; ///< Path to safe mode firm (A folder) (Sysdata 1)
|
std::string safe_mode_firm_path; ///< Path to safe mode firm (A folder) (Sysdata 1)
|
||||||
std::string seed_db_path; ///< Path to seeddb.bin (Sysdata 2)
|
std::string seed_db_path; ///< Path to seeddb.bin (Sysdata 2)
|
||||||
std::string secret_sector_path; ///< Path to secret sector (New3DS only) (Sysdata 3)
|
std::string secret_sector_path; ///< Path to secret sector (New3DS only) (Sysdata 3)
|
||||||
// Note: Sysdata 4 is aes_keys.txt (slot0x25KeyX)
|
// Note: Sysdata 4 is aes_keys.txt (slot0x25KeyX)
|
||||||
std::string config_savegame_path; ///< Path to config savegame (Sysdata 5)
|
std::string config_savegame_path; ///< Path to config savegame (Sysdata 5)
|
||||||
|
|
||||||
std::string system_archives_path; ///< Path to system archives.
|
std::string system_archives_path; ///< Path to system archives.
|
||||||
std::string system_titles_path; ///< Path to system titles.
|
std::string system_titles_path; ///< Path to system titles.
|
||||||
std::string nand_data_path; ///< Path to NAND data. (Extdata and savedata)
|
std::string nand_data_path; ///< Path to NAND data. (Extdata and savedata)
|
||||||
|
|
||||||
int version = 0; ///< Version of the dumper used.
|
int version = 0; ///< Version of the dumper used.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Version of the current dumper.
|
// Version of the current dumper.
|
||||||
constexpr int CurrentDumperVersion = 4;
|
constexpr int CurrentDumperVersion = 4;
|
||||||
|
|
||||||
class SDMCFile;
|
class SDMCFile;
|
||||||
class NCCHContainer;
|
class NCCHContainer;
|
||||||
|
|
||||||
class SDMCImporter {
|
class SDMCImporter {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Initializes the importer.
|
* Initializes the importer.
|
||||||
* @param root_folder Path to the "Nintendo 3DS/<ID0>/<ID1>" folder.
|
* @param root_folder Path to the "Nintendo 3DS/<ID0>/<ID1>" folder.
|
||||||
*/
|
*/
|
||||||
explicit SDMCImporter(const Config& config);
|
explicit SDMCImporter(const Config& config);
|
||||||
|
|
||||||
~SDMCImporter();
|
~SDMCImporter();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Imports a specific content by its specifier, deleting it when failed.
|
* Imports a specific content by its specifier, deleting it when failed.
|
||||||
* Blocks, but can be aborted on another thread if needed.
|
* Blocks, but can be aborted on another thread if needed.
|
||||||
* @return true on success, false otherwise
|
* @return true on success, false otherwise
|
||||||
*/
|
*/
|
||||||
bool ImportContent(
|
bool ImportContent(
|
||||||
const ContentSpecifier& specifier,
|
const ContentSpecifier& specifier,
|
||||||
const Common::ProgressCallback& callback = [](u64, u64) {});
|
const Common::ProgressCallback& callback = [](u64, u64) {});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aborts current importing.
|
* Aborts current importing.
|
||||||
*/
|
*/
|
||||||
void AbortImporting();
|
void AbortImporting();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dumps a content to CXI.
|
* Dumps a content to CXI.
|
||||||
* Blocks, but can be aborted on another thread.
|
* Blocks, but can be aborted on another thread.
|
||||||
* @return true on success, false otherwise
|
* @return true on success, false otherwise
|
||||||
*/
|
*/
|
||||||
bool DumpCXI(const ContentSpecifier& specifier, std::string destination,
|
bool DumpCXI(const ContentSpecifier& specifier, std::string destination,
|
||||||
const Common::ProgressCallback& callback, bool auto_filename = false);
|
const Common::ProgressCallback& callback, bool auto_filename = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aborts current CXI dumping.
|
* Aborts current CXI dumping.
|
||||||
*/
|
*/
|
||||||
void AbortDumpCXI();
|
void AbortDumpCXI();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a CIA from a content.
|
* Builds a CIA from a content.
|
||||||
* Blocks, but can be aborted on another thread.
|
* Blocks, but can be aborted on another thread.
|
||||||
* @return true on success, false otherwise
|
* @return true on success, false otherwise
|
||||||
*/
|
*/
|
||||||
bool BuildCIA(CIABuildType build_type, const ContentSpecifier& specifier,
|
bool BuildCIA(CIABuildType build_type, const ContentSpecifier& specifier,
|
||||||
std::string destination, const Common::ProgressCallback& callback,
|
std::string destination, const Common::ProgressCallback& callback,
|
||||||
bool auto_filename = false);
|
bool auto_filename = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a content can be built as a legit CIA.
|
* Checks if a content can be built as a legit CIA.
|
||||||
*/
|
*/
|
||||||
bool CanBuildLegitCIA(const ContentSpecifier& specifier) const;
|
bool CanBuildLegitCIA(const ContentSpecifier& specifier) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aborts current CIA building
|
* Aborts current CIA building
|
||||||
*/
|
*/
|
||||||
void AbortBuildCIA();
|
void AbortBuildCIA();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a list of dumpable content specifiers.
|
* Gets a list of dumpable content specifiers.
|
||||||
*/
|
*/
|
||||||
std::vector<ContentSpecifier> ListContent() const;
|
std::vector<ContentSpecifier> ListContent() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the importer is in good state.
|
* Returns whether the importer is in good state.
|
||||||
*/
|
*/
|
||||||
bool IsGood() const;
|
bool IsGood() const;
|
||||||
|
|
||||||
private:
|
bool LoadTMD(ContentType type, u64 id, TitleMetadata& out) const;
|
||||||
bool Init();
|
bool LoadTMD(const ContentSpecifier& specifier, TitleMetadata& out) const;
|
||||||
|
|
||||||
// Impl of ImportContent without deleting mechanism.
|
private:
|
||||||
bool ImportContentImpl(
|
bool Init();
|
||||||
const ContentSpecifier& specifier,
|
|
||||||
const Common::ProgressCallback& callback = [](u64, u64) {});
|
// Impl of ImportContent without deleting mechanism.
|
||||||
bool ImportTitle(const ContentSpecifier& specifier, const Common::ProgressCallback& callback);
|
bool ImportContentImpl(
|
||||||
bool ImportNandTitle(const ContentSpecifier& specifier,
|
const ContentSpecifier& specifier,
|
||||||
const Common::ProgressCallback& callback);
|
const Common::ProgressCallback& callback = [](u64, u64) {});
|
||||||
bool ImportSavegame(u64 id, const Common::ProgressCallback& callback);
|
bool ImportTitle(const ContentSpecifier& specifier, const Common::ProgressCallback& callback);
|
||||||
bool ImportNandSavegame(u64 id, const Common::ProgressCallback& callback);
|
bool ImportNandTitle(const ContentSpecifier& specifier,
|
||||||
bool ImportExtdata(u64 id, const Common::ProgressCallback& callback);
|
const Common::ProgressCallback& callback);
|
||||||
bool ImportNandExtdata(u64 id, const Common::ProgressCallback& callback);
|
bool ImportSavegame(u64 id, const Common::ProgressCallback& callback);
|
||||||
bool ImportSystemArchive(u64 id, const Common::ProgressCallback& callback);
|
bool ImportNandSavegame(u64 id, const Common::ProgressCallback& callback);
|
||||||
bool ImportSysdata(u64 id, const Common::ProgressCallback& callback);
|
bool ImportExtdata(u64 id, const Common::ProgressCallback& callback);
|
||||||
|
bool ImportNandExtdata(u64 id, const Common::ProgressCallback& callback);
|
||||||
void ListTitle(std::vector<ContentSpecifier>& out) const;
|
bool ImportSystemArchive(u64 id, const Common::ProgressCallback& callback);
|
||||||
void ListNandTitle(std::vector<ContentSpecifier>& out) const;
|
bool ImportSysdata(u64 id, const Common::ProgressCallback& callback);
|
||||||
void ListNandSavegame(std::vector<ContentSpecifier>& out) const;
|
|
||||||
void ListExtdata(std::vector<ContentSpecifier>& out) const;
|
void ListTitle(std::vector<ContentSpecifier>& out) const;
|
||||||
void ListSystemArchive(std::vector<ContentSpecifier>& out) const;
|
void ListNandTitle(std::vector<ContentSpecifier>& out) const;
|
||||||
void ListSysdata(std::vector<ContentSpecifier>& out) const;
|
void ListNandSavegame(std::vector<ContentSpecifier>& out) const;
|
||||||
|
void ListExtdata(std::vector<ContentSpecifier>& out) const;
|
||||||
void DeleteContent(const ContentSpecifier& specifier) const;
|
void ListSystemArchive(std::vector<ContentSpecifier>& out) const;
|
||||||
void DeleteTitle(u64 id) const;
|
void ListSysdata(std::vector<ContentSpecifier>& out) const;
|
||||||
void DeleteNandTitle(u64 id) const;
|
|
||||||
void DeleteSavegame(u64 id) const;
|
void DeleteContent(const ContentSpecifier& specifier) const;
|
||||||
void DeleteExtdata(u64 id) const;
|
void DeleteTitle(u64 id) const;
|
||||||
void DeleteSystemArchive(u64 id) const;
|
void DeleteNandTitle(u64 id) const;
|
||||||
void DeleteSysdata(u64 id) const;
|
void DeleteSavegame(u64 id) const;
|
||||||
|
void DeleteExtdata(u64 id) const;
|
||||||
bool LoadTMD(ContentType type, u64 id, TitleMetadata& out) const;
|
void DeleteSystemArchive(u64 id) const;
|
||||||
|
void DeleteSysdata(u64 id) const;
|
||||||
bool is_good{};
|
|
||||||
Config config;
|
bool is_good{};
|
||||||
std::unique_ptr<SDMCDecryptor> sdmc_decryptor;
|
Config config;
|
||||||
|
std::unique_ptr<SDMCDecryptor> sdmc_decryptor;
|
||||||
// Used for CIA building
|
|
||||||
std::unique_ptr<CIABuilder> cia_builder;
|
// Used for CIA building
|
||||||
|
std::unique_ptr<CIABuilder> cia_builder;
|
||||||
// The NCCH used to dump CXIs.
|
|
||||||
std::unique_ptr<NCCHContainer> dump_cxi_ncch;
|
// The NCCH used to dump CXIs.
|
||||||
|
std::unique_ptr<NCCHContainer> dump_cxi_ncch;
|
||||||
std::unique_ptr<TitleDB> sdmc_title_db{};
|
|
||||||
std::unique_ptr<TitleDB> nand_title_db{};
|
std::unique_ptr<TitleDB> sdmc_title_db{};
|
||||||
};
|
std::unique_ptr<TitleDB> nand_title_db{};
|
||||||
|
};
|
||||||
/**
|
|
||||||
* Look for and load preset config for a SD card mounted at mount_point.
|
/**
|
||||||
* @return a list of preset config available. can be empty
|
* Look for and load preset config for a SD card mounted at mount_point.
|
||||||
*/
|
* @return a list of preset config available. can be empty
|
||||||
std::vector<Config> LoadPresetConfig(std::string mount_point);
|
*/
|
||||||
|
std::vector<Config> LoadPresetConfig(std::string mount_point);
|
||||||
} // namespace Core
|
|
||||||
|
} // namespace Core
|
||||||
|
|||||||
+82
-79
@@ -1,79 +1,82 @@
|
|||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
if (POLICY CMP0071)
|
if (POLICY CMP0071)
|
||||||
cmake_policy(SET CMP0071 NEW)
|
cmake_policy(SET CMP0071 NEW)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/themes/*)
|
file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/themes/*)
|
||||||
|
|
||||||
add_executable(threeSD
|
add_executable(threeSD
|
||||||
helpers/multi_job.cpp
|
helpers/multi_job.cpp
|
||||||
helpers/multi_job.h
|
helpers/multi_job.h
|
||||||
helpers/simple_job.cpp
|
helpers/simple_job.cpp
|
||||||
helpers/simple_job.h
|
helpers/simple_job.h
|
||||||
cia_build_dialog.cpp
|
cia_build_dialog.cpp
|
||||||
cia_build_dialog.h
|
cia_build_dialog.h
|
||||||
cia_build_dialog.ui
|
cia_build_dialog.ui
|
||||||
import_dialog.cpp
|
import_dialog.cpp
|
||||||
import_dialog.h
|
import_dialog.h
|
||||||
import_dialog.ui
|
import_dialog.ui
|
||||||
main.cpp
|
main.cpp
|
||||||
main.h
|
main.h
|
||||||
main.ui
|
main.ui
|
||||||
select_files_dialog.cpp
|
select_files_dialog.cpp
|
||||||
select_files_dialog.h
|
select_files_dialog.h
|
||||||
select_files_dialog.ui
|
select_files_dialog.ui
|
||||||
utilities.cpp
|
title_info_dialog.cpp
|
||||||
utilities.h
|
title_info_dialog.h
|
||||||
utilities.ui
|
title_info_dialog.ui
|
||||||
${THEMES}
|
utilities.cpp
|
||||||
)
|
utilities.h
|
||||||
|
utilities.ui
|
||||||
target_link_libraries(threeSD PRIVATE common core)
|
${THEMES}
|
||||||
target_link_libraries(threeSD PRIVATE Qt5::Widgets)
|
)
|
||||||
target_link_libraries(threeSD PRIVATE qdevicewatcher)
|
|
||||||
target_link_libraries(threeSD PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
target_link_libraries(threeSD PRIVATE common core)
|
||||||
|
target_link_libraries(threeSD PRIVATE Qt5::Widgets)
|
||||||
if (APPLE)
|
target_link_libraries(threeSD PRIVATE qdevicewatcher)
|
||||||
# set(MACOSX_ICON "../../dist/citra.icns")
|
target_link_libraries(threeSD PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||||
# set_source_files_properties(${MACOSX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
|
||||||
# target_sources(threeSD PRIVATE ${MACOSX_ICON})
|
if (APPLE)
|
||||||
set_target_properties(threeSD PROPERTIES MACOSX_BUNDLE TRUE)
|
# set(MACOSX_ICON "../../dist/citra.icns")
|
||||||
set_target_properties(threeSD PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
|
# set_source_files_properties(${MACOSX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||||
elseif(WIN32)
|
# target_sources(threeSD PRIVATE ${MACOSX_ICON})
|
||||||
# compile as a win32 gui application instead of a console application
|
set_target_properties(threeSD PROPERTIES MACOSX_BUNDLE TRUE)
|
||||||
target_link_libraries(threeSD PRIVATE Qt5::WinMain)
|
set_target_properties(threeSD PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
|
||||||
if(MSVC)
|
elseif(WIN32)
|
||||||
set_target_properties(threeSD PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
|
# compile as a win32 gui application instead of a console application
|
||||||
elseif(MINGW)
|
target_link_libraries(threeSD PRIVATE Qt5::WinMain)
|
||||||
set_target_properties(threeSD PROPERTIES LINK_FLAGS_RELEASE "-mwindows")
|
if(MSVC)
|
||||||
endif()
|
set_target_properties(threeSD PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
|
||||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
elseif(MINGW)
|
||||||
# In Ubuntu, the executable would be recognized as a shared library otherwise.
|
set_target_properties(threeSD PROPERTIES LINK_FLAGS_RELEASE "-mwindows")
|
||||||
set_target_properties(threeSD PROPERTIES LINK_FLAGS "-no-pie")
|
endif()
|
||||||
endif()
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
# In Ubuntu, the executable would be recognized as a shared library otherwise.
|
||||||
target_compile_definitions(threeSD PRIVATE
|
set_target_properties(threeSD PROPERTIES LINK_FLAGS "-no-pie")
|
||||||
# Use QStringBuilder for string concatenation to reduce
|
endif()
|
||||||
# the overall number of temporary strings created.
|
|
||||||
-DQT_USE_QSTRINGBUILDER
|
target_compile_definitions(threeSD PRIVATE
|
||||||
|
# Use QStringBuilder for string concatenation to reduce
|
||||||
# Disable implicit type narrowing in signal/slot connect() calls.
|
# the overall number of temporary strings created.
|
||||||
-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT
|
-DQT_USE_QSTRINGBUILDER
|
||||||
|
|
||||||
# Disable unsafe overloads of QProcess' start() function.
|
# Disable implicit type narrowing in signal/slot connect() calls.
|
||||||
-DQT_NO_PROCESS_COMBINED_ARGUMENT_START
|
-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT
|
||||||
|
|
||||||
# Disable implicit QString->QUrl conversions to enforce use of proper resolving functions.
|
# Disable unsafe overloads of QProcess' start() function.
|
||||||
-DQT_NO_URL_CAST_FROM_STRING
|
-DQT_NO_PROCESS_COMBINED_ARGUMENT_START
|
||||||
|
|
||||||
# Disable automatic conversions from 8-bit strings (char *) to unicode QStrings
|
# Disable implicit QString->QUrl conversions to enforce use of proper resolving functions.
|
||||||
-DQT_NO_CAST_FROM_ASCII
|
-DQT_NO_URL_CAST_FROM_STRING
|
||||||
)
|
|
||||||
|
# Disable automatic conversions from 8-bit strings (char *) to unicode QStrings
|
||||||
if (MSVC)
|
-DQT_NO_CAST_FROM_ASCII
|
||||||
include(CopyQt5Deps)
|
)
|
||||||
copy_Qt5_deps(threeSD)
|
|
||||||
endif()
|
if (MSVC)
|
||||||
|
include(CopyQt5Deps)
|
||||||
|
copy_Qt5_deps(threeSD)
|
||||||
|
endif()
|
||||||
|
|||||||
+125
-125
@@ -1,125 +1,125 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>CIABuildDialog</class>
|
<class>CIABuildDialog</class>
|
||||||
<widget class="QDialog" name="CIABuildDialog">
|
<widget class="QDialog" name="CIABuildDialog">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>510</width>
|
<width>510</width>
|
||||||
<height>260</height>
|
<height>260</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Build CIA</string>
|
<string>Build CIA</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout">
|
<layout class="QVBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel">
|
<widget class="QLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Destination:</string>
|
<string>Destination:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="destination"/>
|
<widget class="QLineEdit" name="destination"/>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QToolButton" name="destinationExplore">
|
<widget class="QToolButton" name="destinationExplore">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>...</string>
|
<string>...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox">
|
<widget class="QGroupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Build Type</string>
|
<string>Build Type</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout">
|
<layout class="QVBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="standardButton">
|
<widget class="QRadioButton" name="standardButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Standard</string>
|
<string>Standard</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="checked">
|
<property name="checked">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel">
|
<widget class="QLabel">
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Recommended for general use.<br>Decrypted CIA with decrypted contents and standard ticket.</string>
|
<string>Recommended for general use.<br>Decrypted CIA with decrypted contents and standard ticket.</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="pirateLegitButton">
|
<widget class="QRadioButton" name="pirateLegitButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Legit with standard ticket ("pirate legit")</string>
|
<string>Legit with standard ticket ("pirate legit")</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="pirateLegitLabel">
|
<widget class="QLabel" name="pirateLegitLabel">
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Encrypted CIA with legit TMD, encrypted contents and standard ticket.</string>
|
<string>Encrypted CIA with legit TMD, encrypted contents and standard ticket.</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="legitButton">
|
<widget class="QRadioButton" name="legitButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Legit</string>
|
<string>Legit</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="legitLabel">
|
<widget class="QLabel" name="legitLabel">
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Encrypted CIA with legit TMD, encrypted contents and legit ticket.<br>WARNING: Legit ticket may include console identifying information!</string>
|
<string>Encrypted CIA with legit TMD, encrypted contents and legit ticket.<br>WARNING: Legit ticket may include console identifying information!</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer>
|
<spacer>
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="standardButtons">
|
<property name="standardButtons">
|
||||||
<set>QDialogButtonBox::Ok|QDialogButtonBox::Cancel</set>
|
<set>QDialogButtonBox::Ok|QDialogButtonBox::Cancel</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "frontend/helpers/multi_job.h"
|
#include "frontend/helpers/multi_job.h"
|
||||||
#include "frontend/helpers/simple_job.h"
|
#include "frontend/helpers/simple_job.h"
|
||||||
#include "frontend/import_dialog.h"
|
#include "frontend/import_dialog.h"
|
||||||
|
#include "frontend/title_info_dialog.h"
|
||||||
#include "ui_import_dialog.h"
|
#include "ui_import_dialog.h"
|
||||||
|
|
||||||
static QString ReadableByteSize(qulonglong size) {
|
static QString ReadableByteSize(qulonglong size) {
|
||||||
@@ -519,10 +520,15 @@ void ImportDialog::OnContextMenu(const QPoint& point) {
|
|||||||
connect(dump_cxi, &QAction::triggered,
|
connect(dump_cxi, &QAction::triggered,
|
||||||
[this, specifier] { StartDumpingCXISingle(specifier); });
|
[this, specifier] { StartDumpingCXISingle(specifier); });
|
||||||
}
|
}
|
||||||
if (Core::CanBuildCIA(specifier.type)) {
|
if (Core::IsTitle(specifier.type)) {
|
||||||
QAction* build_cia = context_menu.addAction(tr("Build CIA..."));
|
QAction* build_cia = context_menu.addAction(tr("Build CIA..."));
|
||||||
connect(build_cia, &QAction::triggered,
|
connect(build_cia, &QAction::triggered,
|
||||||
[this, specifier] { StartBuildingCIASingle(specifier); });
|
[this, specifier] { StartBuildingCIASingle(specifier); });
|
||||||
|
QAction* show_title_info = context_menu.addAction(tr("Show Title Info"));
|
||||||
|
connect(show_title_info, &QAction::triggered, [this, specifier] {
|
||||||
|
TitleInfoDialog dialog(this, config, *importer, specifier);
|
||||||
|
dialog.exec();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else { // Top level
|
} else { // Top level
|
||||||
if (!title_view) {
|
if (!title_view) {
|
||||||
@@ -837,7 +843,7 @@ void ImportDialog::StartBatchBuildingCIA() {
|
|||||||
|
|
||||||
const auto removed_iter = std::remove_if(
|
const auto removed_iter = std::remove_if(
|
||||||
to_import.begin(), to_import.end(),
|
to_import.begin(), to_import.end(),
|
||||||
[](const Core::ContentSpecifier& specifier) { return !Core::CanBuildCIA(specifier.type); });
|
[](const Core::ContentSpecifier& specifier) { return !Core::IsTitle(specifier.type); });
|
||||||
if (removed_iter == to_import.begin()) { // No Titles selected
|
if (removed_iter == to_import.begin()) { // No Titles selected
|
||||||
QMessageBox::critical(this, tr("threeSD"),
|
QMessageBox::critical(this, tr("threeSD"),
|
||||||
tr("The contents selected are not supported.<br>You can only build "
|
tr("The contents selected are not supported.<br>You can only build "
|
||||||
|
|||||||
@@ -1,57 +1,57 @@
|
|||||||
// Copyright 2020 threeSD Project
|
// Copyright 2020 threeSD Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <QDesktopWidget>
|
#include <QDesktopWidget>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include "frontend/select_files_dialog.h"
|
#include "frontend/select_files_dialog.h"
|
||||||
#include "ui_select_files_dialog.h"
|
#include "ui_select_files_dialog.h"
|
||||||
|
|
||||||
SelectFilesDialog::SelectFilesDialog(QWidget* parent, bool source_is_dir_, bool destination_is_dir_)
|
SelectFilesDialog::SelectFilesDialog(QWidget* parent, bool source_is_dir_, bool destination_is_dir_)
|
||||||
: QDialog(parent), ui(std::make_unique<Ui::SelectFilesDialog>()), source_is_dir(source_is_dir_),
|
: QDialog(parent), ui(std::make_unique<Ui::SelectFilesDialog>()), source_is_dir(source_is_dir_),
|
||||||
destination_is_dir(destination_is_dir_) {
|
destination_is_dir(destination_is_dir_) {
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
const double scale = qApp->desktop()->logicalDpiX() / 96.0;
|
const double scale = qApp->desktop()->logicalDpiX() / 96.0;
|
||||||
resize(static_cast<int>(width() * scale), static_cast<int>(height() * scale));
|
resize(static_cast<int>(width() * scale), static_cast<int>(height() * scale));
|
||||||
|
|
||||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, [this] {
|
connect(ui->buttonBox, &QDialogButtonBox::accepted, [this] {
|
||||||
if (ui->source->text().isEmpty() || ui->destination->text().isEmpty()) {
|
if (ui->source->text().isEmpty() || ui->destination->text().isEmpty()) {
|
||||||
QMessageBox::warning(this, tr("Warning"), tr("Please fill in all the fields."));
|
QMessageBox::warning(this, tr("Warning"), tr("Please fill in all the fields."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
accept();
|
accept();
|
||||||
});
|
});
|
||||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &SelectFilesDialog::reject);
|
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &SelectFilesDialog::reject);
|
||||||
|
|
||||||
connect(ui->sourceExplore, &QToolButton::clicked, [this] {
|
connect(ui->sourceExplore, &QToolButton::clicked, [this] {
|
||||||
QString path;
|
QString path;
|
||||||
if (source_is_dir) {
|
if (source_is_dir) {
|
||||||
path = QFileDialog::getExistingDirectory(this, tr("Select Directory"));
|
path = QFileDialog::getExistingDirectory(this, tr("Select Directory"));
|
||||||
} else {
|
} else {
|
||||||
path = QFileDialog::getOpenFileName(this, tr("Select File"));
|
path = QFileDialog::getOpenFileName(this, tr("Select File"));
|
||||||
}
|
}
|
||||||
if (!path.isEmpty()) {
|
if (!path.isEmpty()) {
|
||||||
ui->source->setText(path);
|
ui->source->setText(path);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(ui->destinationExplore, &QToolButton::clicked, [this] {
|
connect(ui->destinationExplore, &QToolButton::clicked, [this] {
|
||||||
QString path;
|
QString path;
|
||||||
if (destination_is_dir) {
|
if (destination_is_dir) {
|
||||||
path = QFileDialog::getExistingDirectory(this, tr("Select Directory"));
|
path = QFileDialog::getExistingDirectory(this, tr("Select Directory"));
|
||||||
} else {
|
} else {
|
||||||
path = QFileDialog::getSaveFileName(this, tr("Select File"));
|
path = QFileDialog::getSaveFileName(this, tr("Select File"));
|
||||||
}
|
}
|
||||||
if (!path.isEmpty()) {
|
if (!path.isEmpty()) {
|
||||||
ui->destination->setText(path);
|
ui->destination->setText(path);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectFilesDialog::~SelectFilesDialog() = default;
|
SelectFilesDialog::~SelectFilesDialog() = default;
|
||||||
|
|
||||||
std::pair<QString, QString> SelectFilesDialog::GetResults() const {
|
std::pair<QString, QString> SelectFilesDialog::GetResults() const {
|
||||||
return {ui->source->text(), ui->destination->text()};
|
return {ui->source->text(), ui->destination->text()};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
// Copyright 2021 threeSD Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include "common/string_util.h"
|
||||||
|
#include "core/file_sys/ncch_container.h"
|
||||||
|
#include "core/file_sys/title_metadata.h"
|
||||||
|
#include "core/importer.h"
|
||||||
|
#include "frontend/title_info_dialog.h"
|
||||||
|
#include "ui_title_info_dialog.h"
|
||||||
|
|
||||||
|
TitleInfoDialog::TitleInfoDialog(QWidget* parent, const Core::Config& config,
|
||||||
|
Core::SDMCImporter& importer,
|
||||||
|
const Core::ContentSpecifier& specifier)
|
||||||
|
: QDialog(parent), ui(std::make_unique<Ui::TitleInfoDialog>()) {
|
||||||
|
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
const double scale = qApp->desktop()->logicalDpiX() / 96.0;
|
||||||
|
resize(static_cast<int>(width() * scale), static_cast<int>(height() * scale));
|
||||||
|
|
||||||
|
InitializeInfo(config, importer, specifier);
|
||||||
|
InitializeLanguageComboBox();
|
||||||
|
|
||||||
|
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &TitleInfoDialog::accept);
|
||||||
|
}
|
||||||
|
|
||||||
|
TitleInfoDialog::~TitleInfoDialog() = default;
|
||||||
|
|
||||||
|
void TitleInfoDialog::InitializeInfo(const Core::Config& config, Core::SDMCImporter& importer,
|
||||||
|
const Core::ContentSpecifier& specifier) {
|
||||||
|
Core::TitleMetadata tmd;
|
||||||
|
if (!importer.LoadTMD(specifier, tmd)) {
|
||||||
|
QMessageBox::warning(this, tr("threeSD"), tr("Could not load title information."));
|
||||||
|
reject();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ui->versionLineEdit->setText(QString::fromStdString(tmd.GetTitleVersionString()));
|
||||||
|
ui->titleIDLineEdit->setText(QStringLiteral("%1").arg(specifier.id, 16, 16, QLatin1Char{'0'}));
|
||||||
|
|
||||||
|
const bool is_nand = specifier.type == Core::ContentType::SystemTitle ||
|
||||||
|
specifier.type == Core::ContentType::SystemApplet;
|
||||||
|
const auto physical_path =
|
||||||
|
is_nand ? fmt::format("{}{:08x}/{:08x}/content/", config.system_titles_path,
|
||||||
|
(specifier.id >> 32), (specifier.id & 0xFFFFFFFF))
|
||||||
|
: fmt::format("{}title/{:08x}/{:08x}/content/", config.sdmc_path,
|
||||||
|
(specifier.id >> 32), (specifier.id & 0xFFFFFFFF));
|
||||||
|
const auto boot_content_path =
|
||||||
|
fmt::format("{}{:08x}.app", physical_path, tmd.GetBootContentID());
|
||||||
|
Core::NCCHContainer ncch;
|
||||||
|
if (is_nand) {
|
||||||
|
ncch.OpenFile(std::make_shared<FileUtil::IOFile>(boot_content_path, "rb"));
|
||||||
|
} else {
|
||||||
|
const auto relative_path = boot_content_path.substr(config.sdmc_path.size() - 1);
|
||||||
|
ncch.OpenFile(std::make_shared<Core::SDMCFile>(config.sdmc_path, relative_path, "rb"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const std::unordered_map<Core::EncryptionType, const char*> EncryptionTypeMap{{
|
||||||
|
{Core::EncryptionType::None, QT_TR_NOOP("None")},
|
||||||
|
{Core::EncryptionType::FixedKey, QT_TR_NOOP("FixedKey")},
|
||||||
|
{Core::EncryptionType::NCCHSecure1, QT_TR_NOOP("Secure1")},
|
||||||
|
{Core::EncryptionType::NCCHSecure2, QT_TR_NOOP("Secure2")},
|
||||||
|
{Core::EncryptionType::NCCHSecure3, QT_TR_NOOP("Secure3")},
|
||||||
|
{Core::EncryptionType::NCCHSecure4, QT_TR_NOOP("Secure4")},
|
||||||
|
}};
|
||||||
|
|
||||||
|
Core::EncryptionType encryption = Core::EncryptionType::None;
|
||||||
|
ncch.ReadEncryptionType(encryption);
|
||||||
|
|
||||||
|
bool seed_crypto = false;
|
||||||
|
ncch.ReadSeedCrypto(seed_crypto);
|
||||||
|
|
||||||
|
QString encryption_text = tr(EncryptionTypeMap.at(encryption));
|
||||||
|
if (seed_crypto) {
|
||||||
|
encryption_text.append(tr(" (Seed)"));
|
||||||
|
}
|
||||||
|
ui->encryptionLineEdit->setText(encryption_text);
|
||||||
|
|
||||||
|
// Load SMDH
|
||||||
|
std::vector<u8> smdh_buffer;
|
||||||
|
if (!ncch.LoadSectionExeFS("icon", smdh_buffer) || smdh_buffer.size() != sizeof(Core::SMDH) ||
|
||||||
|
!Core::IsValidSMDH(smdh_buffer)) {
|
||||||
|
|
||||||
|
LOG_WARNING(Core, "Failed to load SMDH");
|
||||||
|
ui->namesGroupBox->setEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(&smdh, smdh_buffer.data(), smdh_buffer.size());
|
||||||
|
// Load icon
|
||||||
|
ui->iconLargeLabel->setPixmap(
|
||||||
|
QPixmap::fromImage(QImage(reinterpret_cast<const uchar*>(smdh.GetIcon(true).data()), 48, 48,
|
||||||
|
QImage::Format::Format_RGB16)));
|
||||||
|
ui->iconSmallLabel->setPixmap(
|
||||||
|
QPixmap::fromImage(QImage(reinterpret_cast<const uchar*>(smdh.GetIcon(false).data()), 24,
|
||||||
|
24, QImage::Format::Format_RGB16)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleInfoDialog::InitializeLanguageComboBox() {
|
||||||
|
if (!ui->namesGroupBox->isEnabled()) { // SMDH not available
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Corresponds to the indices of the languages defined in SMDH
|
||||||
|
static constexpr std::array<const char*, 12> LanguageNames{{
|
||||||
|
QT_TR_NOOP("Japanese"),
|
||||||
|
QT_TR_NOOP("English"),
|
||||||
|
QT_TR_NOOP("French"),
|
||||||
|
QT_TR_NOOP("German"),
|
||||||
|
QT_TR_NOOP("Italian"),
|
||||||
|
QT_TR_NOOP("Spanish"),
|
||||||
|
QT_TR_NOOP("Chinese (Simplified)"),
|
||||||
|
QT_TR_NOOP("Korean"),
|
||||||
|
QT_TR_NOOP("Dutch"),
|
||||||
|
QT_TR_NOOP("Portuguese"),
|
||||||
|
QT_TR_NOOP("Russian"),
|
||||||
|
QT_TR_NOOP("Chinese (Traditional)"),
|
||||||
|
}};
|
||||||
|
for (std::size_t i = 0; i < LanguageNames.size(); ++i) {
|
||||||
|
const auto& title = smdh.titles.at(i);
|
||||||
|
if (Common::UTF16BufferToUTF8(title.short_title).empty() &&
|
||||||
|
Common::UTF16BufferToUTF8(title.long_title).empty() &&
|
||||||
|
Common::UTF16BufferToUTF8(title.publisher).empty()) {
|
||||||
|
// All empty, ignore this language
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->languageComboBox->addItem(tr(LanguageNames.at(i)), static_cast<int>(i));
|
||||||
|
if (i == 1) { // English
|
||||||
|
ui->languageComboBox->setCurrentIndex(ui->languageComboBox->count() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connect(ui->languageComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
|
&TitleInfoDialog::UpdateNames);
|
||||||
|
UpdateNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleInfoDialog::UpdateNames() {
|
||||||
|
const auto& title = smdh.titles.at(ui->languageComboBox->currentData().toInt());
|
||||||
|
ui->shortTitleLineEdit->setText(
|
||||||
|
QString::fromStdString(Common::UTF16BufferToUTF8(title.short_title)));
|
||||||
|
ui->longTitleLineEdit->setText(
|
||||||
|
QString::fromStdString(Common::UTF16BufferToUTF8(title.long_title)));
|
||||||
|
ui->publisherLineEdit->setText(
|
||||||
|
QString::fromStdString(Common::UTF16BufferToUTF8(title.publisher)));
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2021 threeSD Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <QDialog>
|
||||||
|
#include "core/file_sys/smdh.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class Config;
|
||||||
|
class ContentSpecifier;
|
||||||
|
class SDMCImporter;
|
||||||
|
} // namespace Core
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class TitleInfoDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TitleInfoDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TitleInfoDialog(QWidget* parent, const Core::Config& config,
|
||||||
|
Core::SDMCImporter& importer, const Core::ContentSpecifier& specifier);
|
||||||
|
~TitleInfoDialog();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitializeInfo(const Core::Config& config, Core::SDMCImporter& importer,
|
||||||
|
const Core::ContentSpecifier& specifier);
|
||||||
|
void InitializeLanguageComboBox();
|
||||||
|
void UpdateNames();
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::TitleInfoDialog> ui;
|
||||||
|
Core::SMDH smdh{};
|
||||||
|
};
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>TitleInfoDialog</class>
|
||||||
|
<widget class="QDialog" name="TitleInfoDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>500</width>
|
||||||
|
<height>360</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Title Info</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Info</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Version:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="versionLineEdit"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2" rowspan="2">
|
||||||
|
<widget class="QLabel" name="iconLargeLabel">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>48</width>
|
||||||
|
<height>48</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3" rowspan="2">
|
||||||
|
<widget class="QLabel" name="iconSmallLabel">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Encryption:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="encryptionLineEdit"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Title ID:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1" colspan="3">
|
||||||
|
<widget class="QLineEdit" name="titleIDLineEdit"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="namesGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Names</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" columnstretch="0,20,10">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Short Title:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="shortTitleLineEdit"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QComboBox" name="languageComboBox"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Long Title:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1" colspan="2">
|
||||||
|
<widget class="QLineEdit" name="longTitleLineEdit"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Publisher:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1" colspan="2">
|
||||||
|
<widget class="QLineEdit" name="publisherLineEdit"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Checks</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TMD:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="tmdCheckLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Legit</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Ticket:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="ticketCheckLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Legit</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Contents:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QPushButton" name="contentsCheckButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Check</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="contentsCheckLabel">
|
||||||
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Legit</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</ui>
|
||||||
Reference in New Issue
Block a user