mirror of
https://github.com/Dark98/threeSD.git
synced 2026-07-03 00:38:58 +00:00
Use GodMode9 naming scheme
This commit is contained in:
+72
-4
@@ -561,8 +561,53 @@ TitleData LoadTitleData(NCCHContainer& ncch) {
|
|||||||
encryption, seed_crypto, smdh.GetIcon(false)};
|
encryption, seed_crypto, smdh.GetIcon(false)};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDMCImporter::DumpCXI(const ContentSpecifier& specifier, const std::string& destination,
|
static std::string NormalizeFilename(std::string filename) {
|
||||||
const Common::ProgressCallback& callback) {
|
static constexpr std::array<char, 8> IllegalCharacters{
|
||||||
|
{':', '/', '\\', '"', '*', '?', '\n', '\r'}};
|
||||||
|
|
||||||
|
const auto pred = [](char c) {
|
||||||
|
return std::ranges::find(IllegalCharacters, c) != IllegalCharacters.end();
|
||||||
|
};
|
||||||
|
std::ranges::replace_if(filename, pred, ' ');
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
for (std::size_t i = 0; i < filename.size(); ++i) {
|
||||||
|
if (i < filename.size() - 1 && filename[i] == ' ' && filename[i + 1] == ' ') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.push_back(filename[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string GetTitleFileName(NCCHContainer& ncch) {
|
||||||
|
std::string codeset_name;
|
||||||
|
ncch.ReadCodesetName(codeset_name);
|
||||||
|
|
||||||
|
std::string product_code;
|
||||||
|
ncch.ReadProductCode(product_code);
|
||||||
|
|
||||||
|
u64 program_id{};
|
||||||
|
ncch.ReadProgramId(program_id);
|
||||||
|
|
||||||
|
std::vector<u8> smdh_buffer;
|
||||||
|
if (ncch.LoadSectionExeFS("icon", smdh_buffer) != ResultStatus::Success ||
|
||||||
|
smdh_buffer.size() != sizeof(SMDH)) {
|
||||||
|
LOG_WARNING(Core, "Failed to load icon in ExeFS or size incorrect");
|
||||||
|
return NormalizeFilename(
|
||||||
|
fmt::format("{:016x} {} ({})", program_id, codeset_name, product_code));
|
||||||
|
} else {
|
||||||
|
SMDH smdh;
|
||||||
|
std::memcpy(&smdh, smdh_buffer.data(), smdh_buffer.size());
|
||||||
|
const auto short_title =
|
||||||
|
Common::UTF16BufferToUTF8(smdh.GetShortTitle(SMDH::TitleLanguage::English));
|
||||||
|
return NormalizeFilename(fmt::format("{:016x} {} ({}) ({})", program_id, short_title,
|
||||||
|
product_code, smdh.GetRegionString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDMCImporter::DumpCXI(const ContentSpecifier& specifier, std::string destination,
|
||||||
|
const Common::ProgressCallback& callback, bool auto_filename) {
|
||||||
|
|
||||||
if (specifier.type != ContentType::Application) {
|
if (specifier.type != ContentType::Application) {
|
||||||
LOG_ERROR(Core, "Unsupported specifier type {}", static_cast<int>(specifier.type));
|
LOG_ERROR(Core, "Unsupported specifier type {}", static_cast<int>(specifier.type));
|
||||||
@@ -580,6 +625,13 @@ bool SDMCImporter::DumpCXI(const ContentSpecifier& specifier, const std::string&
|
|||||||
dump_cxi_ncch = std::make_unique<NCCHContainer>(
|
dump_cxi_ncch = std::make_unique<NCCHContainer>(
|
||||||
std::make_shared<SDMCFile>(config.sdmc_path, boot_content_path, "rb"));
|
std::make_shared<SDMCFile>(config.sdmc_path, boot_content_path, "rb"));
|
||||||
|
|
||||||
|
if (auto_filename) {
|
||||||
|
if (destination.back() != '/' && destination.back() != '\\') {
|
||||||
|
destination.push_back('/');
|
||||||
|
}
|
||||||
|
destination.append(GetTitleFileName(*dump_cxi_ncch)).append(".cxi");
|
||||||
|
}
|
||||||
|
|
||||||
if (!FileUtil::CreateFullPath(destination)) {
|
if (!FileUtil::CreateFullPath(destination)) {
|
||||||
LOG_ERROR(Core, "Failed to create path {}", destination);
|
LOG_ERROR(Core, "Failed to create path {}", destination);
|
||||||
return false;
|
return false;
|
||||||
@@ -593,8 +645,8 @@ void SDMCImporter::AbortDumpCXI() {
|
|||||||
dump_cxi_ncch->AbortDecryptToFile();
|
dump_cxi_ncch->AbortDecryptToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDMCImporter::BuildCIA(const ContentSpecifier& specifier, const std::string& destination,
|
bool SDMCImporter::BuildCIA(const ContentSpecifier& specifier, std::string destination,
|
||||||
const Common::ProgressCallback& callback) {
|
const Common::ProgressCallback& callback, bool auto_filename) {
|
||||||
|
|
||||||
if (config.certs_db_path.empty()) {
|
if (config.certs_db_path.empty()) {
|
||||||
LOG_ERROR(Core, "Missing certs.db");
|
LOG_ERROR(Core, "Missing certs.db");
|
||||||
@@ -621,6 +673,22 @@ bool SDMCImporter::BuildCIA(const ContentSpecifier& specifier, const std::string
|
|||||||
: fmt::format("{}title/{:08x}/{:08x}/content/", config.sdmc_path,
|
: fmt::format("{}title/{:08x}/{:08x}/content/", config.sdmc_path,
|
||||||
(specifier.id >> 32), (specifier.id & 0xFFFFFFFF));
|
(specifier.id >> 32), (specifier.id & 0xFFFFFFFF));
|
||||||
|
|
||||||
|
if (auto_filename) {
|
||||||
|
if (destination.back() != '/' && destination.back() != '\\') {
|
||||||
|
destination.push_back('/');
|
||||||
|
}
|
||||||
|
const auto boot_content_path =
|
||||||
|
fmt::format("{}{:08x}.app", physical_path, tmd.GetBootContentID());
|
||||||
|
if (is_nand) {
|
||||||
|
NCCHContainer ncch(std::make_shared<FileUtil::IOFile>(boot_content_path, "rb"));
|
||||||
|
destination.append(GetTitleFileName(ncch)).append(".cia");
|
||||||
|
} else {
|
||||||
|
const auto relative_path = boot_content_path.substr(config.sdmc_path.size() - 1);
|
||||||
|
NCCHContainer ncch(std::make_shared<SDMCFile>(config.sdmc_path, relative_path, "rb"));
|
||||||
|
destination.append(GetTitleFileName(ncch)).append(".cia");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ret = cia_builder->Init(destination, tmd, config.certs_db_path,
|
bool ret = cia_builder->Init(destination, tmd, config.certs_db_path,
|
||||||
FileUtil::GetDirectoryTreeSize(physical_path), callback);
|
FileUtil::GetDirectoryTreeSize(physical_path), callback);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
|||||||
+4
-6
@@ -127,9 +127,8 @@ public:
|
|||||||
* 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(
|
bool DumpCXI(const ContentSpecifier& specifier, std::string destination,
|
||||||
const ContentSpecifier& specifier, const std::string& destination,
|
const Common::ProgressCallback& callback, bool auto_filename = false);
|
||||||
const Common::ProgressCallback& callback = [](std::size_t, std::size_t) {});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aborts current CXI dumping.
|
* Aborts current CXI dumping.
|
||||||
@@ -141,9 +140,8 @@ public:
|
|||||||
* 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(
|
bool BuildCIA(const ContentSpecifier& specifier, std::string destination,
|
||||||
const ContentSpecifier& specifier, const std::string& destination,
|
const Common::ProgressCallback& callback, bool auto_filename = false);
|
||||||
const Common::ProgressCallback& callback = [](std::size_t, std::size_t) {});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aborts current CIA building
|
* Aborts current CIA building
|
||||||
|
|||||||
@@ -371,6 +371,17 @@ ResultStatus NCCHContainer::ReadCodesetName(std::string& name) {
|
|||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultStatus NCCHContainer::ReadProductCode(std::string& product_code) {
|
||||||
|
ResultStatus result = Load();
|
||||||
|
if (result != ResultStatus::Success)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
std::array<char, 17> data{};
|
||||||
|
std::memcpy(data.data(), ncch_header.product_code, 16);
|
||||||
|
product_code = data.data();
|
||||||
|
return ResultStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
ResultStatus NCCHContainer::ReadEncryptionType(EncryptionType& encryption) {
|
ResultStatus NCCHContainer::ReadEncryptionType(EncryptionType& encryption) {
|
||||||
ResultStatus result = Load();
|
ResultStatus result = Load();
|
||||||
if (result != ResultStatus::Success)
|
if (result != ResultStatus::Success)
|
||||||
|
|||||||
@@ -257,6 +257,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
ResultStatus ReadCodesetName(std::string& name);
|
ResultStatus ReadCodesetName(std::string& name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the product code.
|
||||||
|
* @return ResultStatus result of function.
|
||||||
|
*/
|
||||||
|
ResultStatus ReadProductCode(std::string& name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets encryption type (which key is used).
|
* Gets encryption type (which key is used).
|
||||||
* @return ResultStatus result of function.
|
* @return ResultStatus result of function.
|
||||||
|
|||||||
+13
-8
@@ -88,20 +88,25 @@ std::array<u16, 0x40> SMDH::GetShortTitle(Core::SMDH::TitleLanguage language) co
|
|||||||
return titles[static_cast<int>(language)].short_title;
|
return titles[static_cast<int>(language)].short_title;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SMDH::GameRegion> SMDH::GetRegions() const {
|
std::string SMDH::GetRegionString() const {
|
||||||
if (region_lockout == 0x7fffffff) {
|
|
||||||
return std::vector<GameRegion>{GameRegion::RegionFree};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 REGION_COUNT = 7;
|
constexpr u32 REGION_COUNT = 7;
|
||||||
std::vector<GameRegion> result;
|
|
||||||
|
// JPN/USA/EUR/Australia/CHN/KOR/TWN
|
||||||
|
// Australia does not have a symbol because it's practically the same as Europe
|
||||||
|
static const std::array<std::string, REGION_COUNT> RegionSymbols{
|
||||||
|
{"J", "U", "E", "", "C", "K", "T"}};
|
||||||
|
|
||||||
|
std::string region_string;
|
||||||
for (u32 region = 0; region < REGION_COUNT; ++region) {
|
for (u32 region = 0; region < REGION_COUNT; ++region) {
|
||||||
if (region_lockout & (1 << region)) {
|
if (region_lockout & (1 << region)) {
|
||||||
result.push_back(static_cast<GameRegion>(region));
|
region_string.append(RegionSymbols[region]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
if (region_string == "JUECKT") {
|
||||||
|
return "W";
|
||||||
|
}
|
||||||
|
return region_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|||||||
+2
-12
@@ -62,17 +62,6 @@ struct SMDH {
|
|||||||
TraditionalChinese = 11
|
TraditionalChinese = 11
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class GameRegion {
|
|
||||||
Japan = 0,
|
|
||||||
NorthAmerica = 1,
|
|
||||||
Europe = 2,
|
|
||||||
Australia = 3,
|
|
||||||
China = 4,
|
|
||||||
Korea = 5,
|
|
||||||
Taiwan = 6,
|
|
||||||
RegionFree = 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets game icon from SMDH
|
* Gets game icon from SMDH
|
||||||
* @param large If true, returns large icon (48x48), otherwise returns small icon (24x24)
|
* @param large If true, returns large icon (48x48), otherwise returns small icon (24x24)
|
||||||
@@ -87,7 +76,8 @@ struct SMDH {
|
|||||||
*/
|
*/
|
||||||
std::array<u16, 0x40> GetShortTitle(Core::SMDH::TitleLanguage language) const;
|
std::array<u16, 0x40> GetShortTitle(Core::SMDH::TitleLanguage language) const;
|
||||||
|
|
||||||
std::vector<GameRegion> GetRegions() const;
|
/// Gets a string representing the supported regions.
|
||||||
|
std::string GetRegionString() const;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(SMDH) == 0x36C0, "SMDH structure size is wrong");
|
static_assert(sizeof(SMDH) == 0x36C0, "SMDH structure size is wrong");
|
||||||
|
|
||||||
|
|||||||
@@ -738,13 +738,6 @@ void ImportDialog::StartDumpingCXISingle(const Core::ContentSpecifier& specifier
|
|||||||
RunSimpleJob(job);
|
RunSimpleJob(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetCXIFileName(const Core::ContentSpecifier& specifier) {
|
|
||||||
return QStringLiteral("%1 (%2).cxi")
|
|
||||||
.arg(QString::fromStdString(specifier.name))
|
|
||||||
.arg(specifier.id, 16, 16, QLatin1Char('0'))
|
|
||||||
.toStdString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImportDialog::StartBatchDumpingCXI() {
|
void ImportDialog::StartBatchDumpingCXI() {
|
||||||
auto to_import = GetSelectedContentList();
|
auto to_import = GetSelectedContentList();
|
||||||
if (to_import.empty()) {
|
if (to_import.empty()) {
|
||||||
@@ -791,11 +784,10 @@ void ImportDialog::StartBatchDumpingCXI() {
|
|||||||
this, importer, std::move(to_import),
|
this, importer, std::move(to_import),
|
||||||
[path](Core::SDMCImporter& importer, const Core::ContentSpecifier& specifier,
|
[path](Core::SDMCImporter& importer, const Core::ContentSpecifier& specifier,
|
||||||
const Common::ProgressCallback& callback) {
|
const Common::ProgressCallback& callback) {
|
||||||
return importer.DumpCXI(specifier, path.toStdString() + GetCXIFileName(specifier),
|
return importer.DumpCXI(specifier, path.toStdString(), callback, true);
|
||||||
callback);
|
|
||||||
},
|
},
|
||||||
[path](Core::SDMCImporter& /*importer*/, const Core::ContentSpecifier& specifier) {
|
[path](Core::SDMCImporter& /*importer*/, const Core::ContentSpecifier& specifier) {
|
||||||
FileUtil::Delete(path.toStdString() + GetCXIFileName(specifier));
|
// TODO: FileUtil::Delete(path.toStdString() + GetCXIFileName(specifier));
|
||||||
},
|
},
|
||||||
&Core::SDMCImporter::AbortDumpCXI);
|
&Core::SDMCImporter::AbortDumpCXI);
|
||||||
RunMultiJob(job, total_count, total_size);
|
RunMultiJob(job, total_count, total_size);
|
||||||
@@ -824,13 +816,6 @@ void ImportDialog::StartBuildingCIASingle(const Core::ContentSpecifier& specifie
|
|||||||
RunSimpleJob(job);
|
RunSimpleJob(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetCIAFileName(const Core::ContentSpecifier& specifier) {
|
|
||||||
return QStringLiteral("%1 (%2).cia")
|
|
||||||
.arg(QString::fromStdString(specifier.name))
|
|
||||||
.arg(specifier.id, 16, 16, QLatin1Char('0'))
|
|
||||||
.toStdString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImportDialog::StartBatchBuildingCIA() {
|
void ImportDialog::StartBatchBuildingCIA() {
|
||||||
auto to_import = GetSelectedContentList();
|
auto to_import = GetSelectedContentList();
|
||||||
if (to_import.empty()) {
|
if (to_import.empty()) {
|
||||||
@@ -881,11 +866,10 @@ void ImportDialog::StartBatchBuildingCIA() {
|
|||||||
this, importer, std::move(to_import),
|
this, importer, std::move(to_import),
|
||||||
[path](Core::SDMCImporter& importer, const Core::ContentSpecifier& specifier,
|
[path](Core::SDMCImporter& importer, const Core::ContentSpecifier& specifier,
|
||||||
const Common::ProgressCallback& callback) {
|
const Common::ProgressCallback& callback) {
|
||||||
return importer.BuildCIA(specifier, path.toStdString() + GetCIAFileName(specifier),
|
return importer.BuildCIA(specifier, path.toStdString(), callback, true);
|
||||||
callback);
|
|
||||||
},
|
},
|
||||||
[path](Core::SDMCImporter& /*importer*/, const Core::ContentSpecifier& specifier) {
|
[path](Core::SDMCImporter& /*importer*/, const Core::ContentSpecifier& specifier) {
|
||||||
FileUtil::Delete(path.toStdString() + GetCIAFileName(specifier));
|
// TODO: FileUtil::Delete(path.toStdString() + GetCIAFileName(specifier));
|
||||||
},
|
},
|
||||||
&Core::SDMCImporter::AbortBuildCIA);
|
&Core::SDMCImporter::AbortBuildCIA);
|
||||||
RunMultiJob(job, total_count, total_size);
|
RunMultiJob(job, total_count, total_size);
|
||||||
|
|||||||
Reference in New Issue
Block a user