diff --git a/src/core/importer.cpp b/src/core/importer.cpp index 3fde228..e934363 100644 --- a/src/core/importer.cpp +++ b/src/core/importer.cpp @@ -526,12 +526,17 @@ bool SDMCImporter::BuildCIA(const ContentSpecifier& specifier, const std::string return false; } - ret = FileUtil::ForeachDirectoryEntry( - nullptr, physical_path, - [this, path](u64* /*num_entries_out*/, const std::string& directory, - const std::string& virtual_name) { + const FileUtil::DirectoryEntryCallable DirectoryEntryCallback = + [this, specifier, path, &DirectoryEntryCallback](u64* /*num_entries_out*/, + const std::string& directory, + const std::string& virtual_name) { if (FileUtil::IsDirectory(directory + virtual_name + "/")) { - return true; + if (virtual_name == "cmd") { + return true; // Skip cmd (not used in Citra) + } + // Recursive call (necessary for DLCs) + return FileUtil::ForeachDirectoryEntry(nullptr, directory + virtual_name + "/", + DirectoryEntryCallback); } static const std::regex app_regex{"([0-9a-f]{8})\\.app"}; @@ -543,11 +548,12 @@ bool SDMCImporter::BuildCIA(const ContentSpecifier& specifier, const std::string ASSERT(match.size() >= 2); const u32 id = static_cast(std::stoul(match[1], nullptr, 16)); - NCCHContainer ncch( - std::make_shared(config.sdmc_path, path + virtual_name, "rb")); + const auto relative_path = directory.substr(config.sdmc_path.size() - 1) + virtual_name; + NCCHContainer ncch(std::make_shared(config.sdmc_path, relative_path, "rb")); return cia_builder->AddContent(id, ncch); - }); - if (!ret) { + }; + + if (!FileUtil::ForeachDirectoryEntry(nullptr, physical_path, DirectoryEntryCallback)) { return false; } diff --git a/src/core/ncch/cia_builder.cpp b/src/core/ncch/cia_builder.cpp index ab20d85..4001471 100644 --- a/src/core/ncch/cia_builder.cpp +++ b/src/core/ncch/cia_builder.cpp @@ -47,6 +47,9 @@ bool CIABuilder::Init(const std::string& destination, TitleMetadata tmd_, const std::string& certs_db_path, std::size_t total_size_, const ProgressCallback& callback_) { + header = {}; + meta = {}; + file = std::make_shared(destination, "wb"); if (!*file) { LOG_ERROR(Core, "Could not open file {}", destination); @@ -165,13 +168,14 @@ bool CIABuilder::AddContent(u16 content_id, NCCHContainer& ncch) { written = Common::AlignUp(file->Tell(), CIA_ALIGNMENT); header.content_size = written - content_offset; - header.SetContentPresent(content_id); auto& tmd_chunk = tmd.GetContentChunkByID(content_id); + header.SetContentPresent(tmd_chunk.index); file->GetHash(tmd_chunk.hash.data()); file->SetHashEnabled(false); - if (tmd_chunk.index != TMDContentIndex::Main) { + // DLCs do not have a meta + if (tmd_chunk.index != TMDContentIndex::Main || (tmd.GetTitleID() & 0x0004008c'00000000)) { return true; } diff --git a/src/core/ncch/cia_builder.h b/src/core/ncch/cia_builder.h index 6d654ef..42c253a 100644 --- a/src/core/ncch/cia_builder.h +++ b/src/core/ncch/cia_builder.h @@ -97,7 +97,6 @@ private: std::size_t ticket_offset{}; std::size_t tmd_offset{}; std::size_t content_offset{}; - std::size_t metadata_offset{}; std::shared_ptr file; std::size_t written{}; // size written (with alignment) diff --git a/src/core/ncch/ticket.cpp b/src/core/ncch/ticket.cpp index ae52f31..0a7e18d 100644 --- a/src/core/ncch/ticket.cpp +++ b/src/core/ncch/ticket.cpp @@ -31,8 +31,9 @@ Ticket BuildFakeTicket(u64 title_id) { ticket.title_id = title_id; ticket.common_key_index = 0x00; ticket.audit = 0x01; - std::memset(ticket.content_index.data(), 0xFF, ticket.content_index.size()); std::memcpy(ticket.content_index.data(), TicketContentIndex.data(), TicketContentIndex.size()); + // GodMode9 by default sets all remaining 0x80 bytes to 0xFF, but legit tickets only set 0x20 + std::memset(ticket.content_index.data() + TicketContentIndex.size(), 0xFF, 0x20); return ticket; }