mirror of
https://github.com/Atmosphere-NX/hac2l.git
synced 2025-06-21 19:22:39 +02:00
hac2l: add basenca, basexci, basepfs/basensp, baseappfs support
This commit is contained in:
parent
161c292397
commit
f2166ab374
@ -163,6 +163,11 @@ namespace ams::hactool {
|
|||||||
MakeOptionHandler("normaldir", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.normal_partition_out_dir), arg); }),
|
MakeOptionHandler("normaldir", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.normal_partition_out_dir), arg); }),
|
||||||
MakeOptionHandler("updatedir", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.update_partition_out_dir), arg); }),
|
MakeOptionHandler("updatedir", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.update_partition_out_dir), arg); }),
|
||||||
MakeOptionHandler("logodir", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.logo_partition_out_dir), arg); }),
|
MakeOptionHandler("logodir", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.logo_partition_out_dir), arg); }),
|
||||||
|
MakeOptionHandler("basenca", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.base_nca_path), arg); }),
|
||||||
|
MakeOptionHandler("basexci", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.base_xci_path), arg); }),
|
||||||
|
MakeOptionHandler("basepfs", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.base_pfs_path), arg); }),
|
||||||
|
MakeOptionHandler("basensp", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.base_pfs_path), arg); }),
|
||||||
|
MakeOptionHandler("baseappfs", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.base_appfs_path), arg); }),
|
||||||
MakeOptionHandler("listromfs", [] (Options &options) { options.list_romfs = true; }),
|
MakeOptionHandler("listromfs", [] (Options &options) { options.list_romfs = true; }),
|
||||||
MakeOptionHandler("listupdate", [] (Options &options) { options.list_update = true; }),
|
MakeOptionHandler("listupdate", [] (Options &options) { options.list_update = true; }),
|
||||||
MakeOptionHandler("appindex", [] (Options &options, const char *arg) { return ParseIntegerArgument(std::addressof(options.preferred_app_index), arg); }),
|
MakeOptionHandler("appindex", [] (Options &options, const char *arg) { return ParseIntegerArgument(std::addressof(options.preferred_app_index), arg); }),
|
||||||
|
@ -36,6 +36,10 @@ namespace ams::hactool {
|
|||||||
struct Options {
|
struct Options {
|
||||||
const char *in_file_path = nullptr;
|
const char *in_file_path = nullptr;
|
||||||
FileType file_type = FileType::Nca;
|
FileType file_type = FileType::Nca;
|
||||||
|
const char *base_nca_path = nullptr;
|
||||||
|
const char *base_xci_path = nullptr;
|
||||||
|
const char *base_pfs_path = nullptr;
|
||||||
|
const char *base_appfs_path = nullptr;
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
bool raw = false;
|
bool raw = false;
|
||||||
bool verify = false;
|
bool verify = false;
|
||||||
|
@ -140,6 +140,15 @@ namespace ams::hactool {
|
|||||||
fssrv::impl::ExternalKeyManager m_external_nca_key_manager;
|
fssrv::impl::ExternalKeyManager m_external_nca_key_manager;
|
||||||
std::shared_ptr<fs::fsa::IFileSystem> m_local_fs;
|
std::shared_ptr<fs::fsa::IFileSystem> m_local_fs;
|
||||||
|
|
||||||
|
bool m_has_base_nca;
|
||||||
|
bool m_has_base_xci;
|
||||||
|
bool m_has_base_pfs;
|
||||||
|
bool m_has_base_appfs;
|
||||||
|
ProcessAsNcaContext m_base_nca_ctx;
|
||||||
|
ProcessAsXciContext m_base_xci_ctx;
|
||||||
|
ProcessAsPfsContext m_base_pfs_ctx;
|
||||||
|
ProcessAsApplicationFileSystemContext m_base_appfs_ctx;
|
||||||
|
|
||||||
os::SdkMutex m_print_lock;
|
os::SdkMutex m_print_lock;
|
||||||
char m_indent_buffer[1_KB];
|
char m_indent_buffer[1_KB];
|
||||||
public:
|
public:
|
||||||
|
@ -19,7 +19,13 @@
|
|||||||
|
|
||||||
namespace ams::hactool {
|
namespace ams::hactool {
|
||||||
|
|
||||||
Processor::Processor(const Options &options) : m_options(options) {
|
Processor::Processor(const Options &options) : m_options(options), m_base_nca_ctx{}, m_base_xci_ctx{}, m_base_pfs_ctx{}, m_base_appfs_ctx{} {
|
||||||
|
/* Default to no bases. */
|
||||||
|
m_has_base_nca = false;
|
||||||
|
m_has_base_xci = false;
|
||||||
|
m_has_base_pfs = false;
|
||||||
|
m_has_base_appfs = false;
|
||||||
|
|
||||||
/* Create local file system for host root. */
|
/* Create local file system for host root. */
|
||||||
fssrv::fscreator::LocalFileSystemCreator local_fs_creator(true);
|
fssrv::fscreator::LocalFileSystemCreator local_fs_creator(true);
|
||||||
fs::Path normalized_path;
|
fs::Path normalized_path;
|
||||||
@ -33,6 +39,61 @@ namespace ams::hactool {
|
|||||||
/* Setup our internal keys. */
|
/* Setup our internal keys. */
|
||||||
this->PresetInternalKeys();
|
this->PresetInternalKeys();
|
||||||
|
|
||||||
|
/* Open any bases we've been provided. */
|
||||||
|
{
|
||||||
|
if (m_options.base_nca_path != nullptr) {
|
||||||
|
std::shared_ptr<fs::IStorage> storage = nullptr;
|
||||||
|
if (const auto open_res = OpenFileStorage(std::addressof(storage), m_local_fs, m_options.base_nca_path); R_SUCCEEDED(open_res)) {
|
||||||
|
if (const auto proc_res = this->ProcessAsNca(std::move(storage), std::addressof(m_base_nca_ctx)); R_SUCCEEDED(proc_res)) {
|
||||||
|
m_has_base_nca = true;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Failed to process base nca (%s): 2%03d-%04d\n", m_options.base_nca_path, proc_res.GetModule(), proc_res.GetDescription());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Failed to open base nca (%s): 2%03d-%04d\n", m_options.base_nca_path, open_res.GetModule(), open_res.GetDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_options.base_xci_path != nullptr) {
|
||||||
|
std::shared_ptr<fs::IStorage> storage = nullptr;
|
||||||
|
if (const auto open_res = OpenFileStorage(std::addressof(storage), m_local_fs, m_options.base_xci_path); R_SUCCEEDED(open_res)) {
|
||||||
|
if (const auto proc_res = this->ProcessAsXci(std::move(storage), std::addressof(m_base_xci_ctx)); R_SUCCEEDED(proc_res)) {
|
||||||
|
m_has_base_xci = true;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Failed to process base xci (%s): 2%03d-%04d\n", m_options.base_xci_path, proc_res.GetModule(), proc_res.GetDescription());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Failed to open base xci (%s): 2%03d-%04d\n", m_options.base_xci_path, open_res.GetModule(), open_res.GetDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_options.base_pfs_path != nullptr) {
|
||||||
|
std::shared_ptr<fs::IStorage> storage = nullptr;
|
||||||
|
if (const auto open_res = OpenFileStorage(std::addressof(storage), m_local_fs, m_options.base_pfs_path); R_SUCCEEDED(open_res)) {
|
||||||
|
if (const auto proc_res = this->ProcessAsPfs(std::move(storage), std::addressof(m_base_pfs_ctx)); R_SUCCEEDED(proc_res)) {
|
||||||
|
m_has_base_pfs = true;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Failed to process base pfs (%s): 2%03d-%04d\n", m_options.base_pfs_path, proc_res.GetModule(), proc_res.GetDescription());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Failed to open base pfs (%s): 2%03d-%04d\n", m_options.base_pfs_path, open_res.GetModule(), open_res.GetDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_options.base_appfs_path != nullptr) {
|
||||||
|
std::shared_ptr<fs::fsa::IFileSystem> fs = nullptr;
|
||||||
|
if (const auto open_res = OpenSubDirectoryFileSystem(std::addressof(fs), m_local_fs, m_options.base_appfs_path); R_SUCCEEDED(open_res)) {
|
||||||
|
if (const auto proc_res = this->ProcessAsApplicationFileSystem(std::move(fs), std::addressof(m_base_appfs_ctx)); R_SUCCEEDED(proc_res)) {
|
||||||
|
m_has_base_appfs = true;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Failed to process base app fs (%s): 2%03d-%04d\n", m_options.base_appfs_path, proc_res.GetModule(), proc_res.GetDescription());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Failed to open base app fs (%s): 2%03d-%04d\n", m_options.base_appfs_path, open_res.GetModule(), open_res.GetDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_options.file_type == FileType::AppFs) {
|
if (m_options.file_type == FileType::AppFs) {
|
||||||
/* Open the filesystem. */
|
/* Open the filesystem. */
|
||||||
std::shared_ptr<fs::fsa::IFileSystem> input = nullptr;
|
std::shared_ptr<fs::fsa::IFileSystem> input = nullptr;
|
||||||
|
@ -127,6 +127,47 @@ namespace ams::hactool {
|
|||||||
/* Create an NCA reader for the input file. */
|
/* Create an NCA reader for the input file. */
|
||||||
R_TRY(ParseNca(std::addressof(ctx->reader), ctx->storage, m_external_nca_key_manager));
|
R_TRY(ParseNca(std::addressof(ctx->reader), ctx->storage, m_external_nca_key_manager));
|
||||||
|
|
||||||
|
/* Decide on a base, if one isn't already set. */
|
||||||
|
{
|
||||||
|
/* First see if we explicitly have a viable base nca. */
|
||||||
|
if (ctx->base_reader == nullptr && m_has_base_nca && m_base_nca_ctx.reader != nullptr && m_base_nca_ctx.reader->GetProgramId() == ctx->reader->GetProgramId()) {
|
||||||
|
ctx->base_reader = m_base_nca_ctx.reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next, we'll try looking for a match in the appfs of a base xci, pfs, or appfs. */
|
||||||
|
auto GetBaseFromAppFs = [&](ProcessAsApplicationFileSystemContext &app_ctx, const char *src) {
|
||||||
|
if (ctx->base_reader == nullptr) {
|
||||||
|
if (auto app_prog = app_ctx.apps.Find(ncm::ApplicationId{ctx->reader->GetProgramId() & ~static_cast<u64>(0xFF)}, 0, ctx->reader->GetProgramId() & 0xFF, ncm::ContentType::Program, ncm::ContentMetaType::Application); app_prog != app_ctx.apps.end()) {
|
||||||
|
ProcessAsNcaContext tmp_ctx{};
|
||||||
|
if (const auto process_res = this->ProcessAsNca(app_prog->GetData().storage, std::addressof(tmp_ctx)); R_SUCCEEDED(process_res)) {
|
||||||
|
if (ctx->reader->GetProgramId() )
|
||||||
|
ctx->base_reader = tmp_ctx.reader;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "[Warning]: Failed to process base program nca from %s: 2%03d-%04d\n", src, process_res.GetModule(), process_res.GetDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (m_has_base_xci && m_base_xci_ctx.secure_partition.fs != nullptr) {
|
||||||
|
m_has_base_xci = false;
|
||||||
|
GetBaseFromAppFs(m_base_xci_ctx.app_ctx, "basexci");
|
||||||
|
m_has_base_xci = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_has_base_pfs && !m_base_pfs_ctx.is_exefs) {
|
||||||
|
m_has_base_xci = false;
|
||||||
|
GetBaseFromAppFs(m_base_pfs_ctx.app_ctx, "basepfs");
|
||||||
|
m_has_base_pfs = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_has_base_appfs) {
|
||||||
|
m_has_base_appfs = false;
|
||||||
|
GetBaseFromAppFs(m_base_appfs_ctx, "baseappfs");
|
||||||
|
m_has_base_appfs = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Open storages for each section. */
|
/* Open storages for each section. */
|
||||||
std::shared_ptr<fs::IStorage> npdm_storage;
|
std::shared_ptr<fs::IStorage> npdm_storage;
|
||||||
|
|
||||||
@ -279,6 +320,8 @@ namespace ams::hactool {
|
|||||||
addon.v32 = util::ConvertToBigEndian<u32>(ctx.reader->GetSdkAddonVersion());
|
addon.v32 = util::ConvertToBigEndian<u32>(ctx.reader->GetSdkAddonVersion());
|
||||||
this->PrintFormat("SDK Version", "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8, addon.v8[0], addon.v8[1], addon.v8[2], addon.v8[3]);
|
this->PrintFormat("SDK Version", "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8, addon.v8[0], addon.v8[1], addon.v8[2], addon.v8[3]);
|
||||||
|
|
||||||
|
this->PrintId64("Program Id", ctx.reader->GetProgramId());
|
||||||
|
|
||||||
this->PrintString("Distribution Type", fs::impl::IdString().ToString(ctx.reader->GetDistributionType()));
|
this->PrintString("Distribution Type", fs::impl::IdString().ToString(ctx.reader->GetDistributionType()));
|
||||||
this->PrintString("Content Type", fs::impl::IdString().ToString(ctx.reader->GetContentType()));
|
this->PrintString("Content Type", fs::impl::IdString().ToString(ctx.reader->GetContentType()));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user