mirror of
https://github.com/Dark98/threeSD.git
synced 2026-07-03 08:39:04 +00:00
Add CIA building
Quite a lot of code, yeah. The built CIA is almost identical to GM9, with the following differences: 1. Paddings are zeroed out 2. Title key is not written (GM9 gets it from support data/ticket db) 3. Ticket content index is slightly different (GM9 likely takes it from the legit ticket, while we are building a fake one) The 2, 3 points can be fixed probably.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include "core/importer.h"
|
||||
#include "core/inner_fat.h"
|
||||
#include "core/key/key.h"
|
||||
#include "core/ncch/cia_builder.h"
|
||||
#include "core/ncch/ncch_container.h"
|
||||
#include "core/ncch/seed_db.h"
|
||||
#include "core/ncch/smdh.h"
|
||||
@@ -53,6 +54,7 @@ bool SDMCImporter::Init() {
|
||||
}
|
||||
|
||||
decryptor = std::make_unique<SDMCDecryptor>(config.sdmc_path);
|
||||
cia_builder = std::make_unique<CIABuilder>();
|
||||
|
||||
FileUtil::SetUserPath(config.user_path);
|
||||
return true;
|
||||
@@ -493,6 +495,69 @@ void SDMCImporter::AbortDumpCXI() {
|
||||
dump_cxi_ncch->AbortDecryptToFile();
|
||||
}
|
||||
|
||||
bool SDMCImporter::BuildCIA(const ContentSpecifier& specifier, const std::string& destination,
|
||||
const ProgressCallback& callback) {
|
||||
|
||||
if (config.certs_db_path.empty()) {
|
||||
LOG_ERROR(Core, "Missing certs.db");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (specifier.type != ContentType::Application && specifier.type != ContentType::Update &&
|
||||
specifier.type != ContentType::DLC) {
|
||||
|
||||
LOG_ERROR(Core, "Unsupported specifier type {}", static_cast<int>(specifier.type));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load TMD
|
||||
const auto path = fmt::format("/title/{:08x}/{:08x}/content/", (specifier.id >> 32),
|
||||
(specifier.id & 0xFFFFFFFF));
|
||||
TitleMetadata tmd;
|
||||
if (!LoadTMD(config.sdmc_path, path, *decryptor, tmd)) {
|
||||
LOG_ERROR(Core, "Failed to load TMD from {}", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto physical_path = config.sdmc_path + path.substr(1);
|
||||
bool ret = cia_builder->Init(destination, std::move(tmd), config.certs_db_path,
|
||||
FileUtil::GetDirectoryTreeSize(physical_path), callback);
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = FileUtil::ForeachDirectoryEntry(
|
||||
nullptr, physical_path,
|
||||
[this, path](u64* /*num_entries_out*/, const std::string& directory,
|
||||
const std::string& virtual_name) {
|
||||
if (FileUtil::IsDirectory(directory + virtual_name + "/")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static const std::regex app_regex{"([0-9a-f]{8})\\.app"};
|
||||
|
||||
std::smatch match;
|
||||
if (!std::regex_match(virtual_name, match, app_regex)) {
|
||||
return true;
|
||||
}
|
||||
ASSERT(match.size() >= 2);
|
||||
|
||||
const u32 id = static_cast<u32>(std::stoul(match[1], nullptr, 16));
|
||||
NCCHContainer ncch(
|
||||
std::make_shared<SDMCFile>(config.sdmc_path, path + virtual_name, "rb"));
|
||||
return cia_builder->AddContent(id, ncch);
|
||||
});
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return cia_builder->Finalize();
|
||||
}
|
||||
|
||||
void SDMCImporter::AbortBuildCIA() {
|
||||
cia_builder->Abort();
|
||||
}
|
||||
|
||||
void SDMCImporter::ListTitle(std::vector<ContentSpecifier>& out) const {
|
||||
const auto ProcessDirectory = [this, &out, &sdmc_path = config.sdmc_path](ContentType type,
|
||||
u64 high_id) {
|
||||
|
||||
Reference in New Issue
Block a user