diff --git a/source/hactool_processor.app_fs.cpp b/source/hactool_processor.app_fs.cpp index e713f0f..9f78d0e 100644 --- a/source/hactool_processor.app_fs.cpp +++ b/source/hactool_processor.app_fs.cpp @@ -366,7 +366,40 @@ namespace ams::hactool { } } - /* TODO: Recursive processing? */ + if (ctx->has_target) { + /* We have a target. Try to find a patch. */ + if (auto patch_prog = ctx->apps.Find(ctx->target_app_id, ctx->target_version, ctx->target_index, ncm::ContentType::Program, ncm::ContentMetaType::Patch); patch_prog != ctx->apps.end()) { + /* Find a base app. */ + if (auto same_app_prog = ctx->apps.Find(ctx->target_app_id, ctx->target_version, ctx->target_index, ncm::ContentType::Program, ncm::ContentMetaType::Application); same_app_prog != ctx->apps.end()) { + if (const auto process_res = this->ProcessAsNca(same_app_prog->GetData().storage, std::addressof(ctx->app_base_nca_ctx)); R_SUCCEEDED(process_res)) { + ctx->app_nca_ctx.base_reader = ctx->app_base_nca_ctx.reader; + } else { + fprintf(stderr, "[Warning]: Failed to process target base program nca: 2%03d-%04d\n", process_res.GetModule(), process_res.GetDescription()); + } + } else if (auto zero_app_prog = ctx->apps.Find(ctx->target_app_id, 0, ctx->target_index, ncm::ContentType::Program, ncm::ContentMetaType::Application); zero_app_prog != ctx->apps.end()) { + if (const auto process_res = this->ProcessAsNca(zero_app_prog->GetData().storage, std::addressof(ctx->app_base_nca_ctx)); R_SUCCEEDED(process_res)) { + ctx->app_nca_ctx.base_reader = ctx->app_base_nca_ctx.reader; + } else { + fprintf(stderr, "[Warning]: Failed to process target base-0 program nca: 2%03d-%04d\n", process_res.GetModule(), process_res.GetDescription()); + } + } + + if (const auto process_res = this->ProcessAsNca(patch_prog->GetData().storage, std::addressof(ctx->app_nca_ctx)); R_FAILED(process_res)) { + fprintf(stderr, "[Warning]: Failed to process target patch program nca: 2%03d-%04d\n", process_res.GetModule(), process_res.GetDescription()); + } + } else { + /* No patch, so we're working with a normal application. */ + auto app_prog = ctx->apps.Find(ctx->target_app_id, ctx->target_version, ctx->target_index, ncm::ContentType::Program, ncm::ContentMetaType::Application); + AMS_ABORT_UNLESS(app_prog != ctx->apps.end()); + + /* Parse the app prog. */ + if (const auto process_res = this->ProcessAsNca(app_prog->GetData().storage, std::addressof(ctx->app_nca_ctx)); R_FAILED(process_res)) { + fprintf(stderr, "[Warning]: Failed to process target program nca: 2%03d-%04d\n", process_res.GetModule(), process_res.GetDescription()); + } + } + + /* TODO: Parse control, etc? */ + } /* Print. */ if (ctx == std::addressof(local_ctx)) { @@ -407,6 +440,10 @@ namespace ams::hactool { } } + if (ctx.has_target) { + this->PrintAsNca(ctx.app_nca_ctx); + } + /* TODO */ AMS_UNUSED(ctx); } diff --git a/source/hactool_processor.hpp b/source/hactool_processor.hpp index 263fe62..d95acc7 100644 --- a/source/hactool_processor.hpp +++ b/source/hactool_processor.hpp @@ -60,6 +60,7 @@ namespace ams::hactool { struct ProcessAsNcaContext { std::shared_ptr storage; std::shared_ptr reader; + std::shared_ptr base_reader; s32 exefs_index = -1; s32 romfs_index = -1; std::array has_sections{}; @@ -88,6 +89,9 @@ namespace ams::hactool { ncm::ApplicationId target_app_id; u32 target_version; u8 target_index; + + ProcessAsNcaContext app_nca_ctx; + ProcessAsNcaContext app_base_nca_ctx; }; struct ProcessAsXciContext { diff --git a/source/hactool_processor.nca.cpp b/source/hactool_processor.nca.cpp index b4e51cd..d67e274 100644 --- a/source/hactool_processor.nca.cpp +++ b/source/hactool_processor.nca.cpp @@ -132,10 +132,22 @@ namespace ams::hactool { for (s32 i = 0; i < fssystem::NcaHeader::FsCountMax; ++i) { ctx->storage_contexts[i].open_raw_storage = true; - const auto res = util::GetReference(g_storage_on_nca_creator).CreateWithContext(std::addressof(ctx->raw_sections[i]), std::addressof(ctx->splitters[i]), std::addressof(ctx->header_readers[i]), std::addressof(ctx->storage_contexts[i]), ctx->reader, i); + + const auto res = [&]() -> Result { + if (ctx->base_reader != nullptr) { + R_RETURN(util::GetReference(g_storage_on_nca_creator).CreateWithPatchWithContext(std::addressof(ctx->raw_sections[i]), std::addressof(ctx->splitters[i]), std::addressof(ctx->header_readers[i]), std::addressof(ctx->storage_contexts[i]), ctx->base_reader, ctx->reader, i)); + } else { + R_RETURN(util::GetReference(g_storage_on_nca_creator).CreateWithContext(std::addressof(ctx->raw_sections[i]), std::addressof(ctx->splitters[i]), std::addressof(ctx->header_readers[i]), std::addressof(ctx->storage_contexts[i]), ctx->reader, i)); + } + }(); + if (R_SUCCEEDED(res)) { ctx->has_sections[i] = true; + if (ctx->header_readers[i].ExistsSparseLayer()) { + continue; + } + /* Try to open the non-raw section. */ const auto real_res = util::GetReference(g_storage_on_nca_creator).CreateByRawStorage(std::addressof(ctx->sections[i]), std::addressof(ctx->splitters[i]), std::addressof(ctx->header_readers[i]), std::shared_ptr(ctx->raw_sections[i]), std::addressof(ctx->storage_contexts[i]), ctx->reader); if (R_SUCCEEDED(real_res)) { diff --git a/source/hactool_processor.xci.cpp b/source/hactool_processor.xci.cpp index 40a52d9..f1fbfe7 100644 --- a/source/hactool_processor.xci.cpp +++ b/source/hactool_processor.xci.cpp @@ -359,26 +359,7 @@ namespace ams::hactool { } if (ctx.secure_partition.fs != nullptr) { - s32 app_idx = -1; - ncm::ApplicationId cur_app_id{}; - const char *field_name = "Programs"; - for (const auto &entry : ctx.app_ctx.apps) { - if (entry.GetType() != ncm::ContentType::Program) { - continue; - } - - if (app_idx == -1 || cur_app_id != entry.GetId()) { - ++app_idx; - cur_app_id = entry.GetId(); - } - - this->PrintFormat(field_name, "{ Idx=%d, ProgramId=%016" PRIX64 ", Version=0x%08" PRIX32 ", IdOffset=%02" PRIX32 ", MetaType=%s }", app_idx, entry.GetId().value, entry.GetVersion(), entry.GetIdOffset(), entry.GetMetaType() == ncm::ContentMetaType::Patch ? "Patch" : "App"); - field_name = ""; - } - - if (ctx.app_ctx.has_target) { - this->PrintFormat("Target", "{ ProgramId=%016" PRIX64 ", Version=0x%08" PRIX32 ", IdOffset=%02" PRIX32 " }", ctx.app_ctx.target_app_id.value, ctx.app_ctx.target_version, ctx.app_ctx.target_index); - } + this->PrintAsApplicationFileSystem(ctx.app_ctx); } AMS_UNUSED(ctx);