diff options
| author | Djihads <76681596+Djihads80@users.noreply.github.com> | 2026-10-29 02:25:36 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-10-29 02:25:36 +0100 |
| commit | 0bb5055b6541c74f47603a8dff0569a509cbaf18 (patch) | |
| tree | da827ff9c4f2f9a5309ee2804ee689f608c0ac2f /src/core/file_sys/program_metadata.cpp | |
| parent | 1af7fe72927af9fc64aa4af117bc9b30043c4dc7 (diff) | |
| parent | 535b6769709eb22333af26269f1b16f37adce4db (diff) | |
Merge pull request #1 from Djihads80/yumekiru/ns2-progress-v2
Experimental NS2 support and accumulated GPU fixes
Diffstat (limited to 'src/core/file_sys/program_metadata.cpp')
| -rw-r--r-- | src/core/file_sys/program_metadata.cpp | 55 |
1 files changed, 51 insertions, 4 deletions
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 63ca9d3fe3..b528523e67 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp @@ -20,6 +20,10 @@ ProgramMetadata::ProgramMetadata() = default; ProgramMetadata::~ProgramMetadata() = default; Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { + uses_extended_acid = false; + if (!file) { + return Loader::ResultStatus::ErrorBadNPDMHeader; + } const std::size_t total_size = file->GetSize(); if (total_size < sizeof(Header)) { return Loader::ResultStatus::ErrorBadNPDMHeader; @@ -29,17 +33,55 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { return Loader::ResultStatus::ErrorBadNPDMHeader; } - if (sizeof(AcidHeader) != file->ReadObject(&acid_header, npdm_header.acid_offset)) { + if (npdm_header.magic != std::array{'M', 'E', 'T', 'A'}) { + return Loader::ResultStatus::ErrorBadNPDMHeader; + } + + const auto contains = [](u64 offset, u64 size, u64 limit) { + return offset <= limit && size <= limit - offset; + }; + const u64 acid_offset = npdm_header.acid_offset; + const u64 acid_size = npdm_header.acid_size; + const u64 aci_offset = npdm_header.aci_offset; + const u64 aci_size = npdm_header.aci_size; + if (acid_offset < sizeof(Header) || !contains(acid_offset, acid_size, total_size)) { return Loader::ResultStatus::ErrorBadACIDHeader; } - if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset)) { + const auto read_acid = [&](u64 body_offset) { + return contains(body_offset, sizeof(AcidHeader), acid_size) && + file->ReadObject(&acid_header, acid_offset + body_offset) == sizeof(AcidHeader) && + acid_header.magic == std::array{'A', 'C', 'I', 'D'}; + }; + if (!read_acid(0x200)) { + if (!read_acid(0x300)) { + return Loader::ResultStatus::ErrorBadACIDHeader; + } + uses_extended_acid = true; + } + + if (aci_offset < sizeof(Header) || !contains(aci_offset, aci_size, total_size) || + aci_size < sizeof(AciHeader) || + sizeof(AciHeader) != file->ReadObject(&aci_header, aci_offset) || + aci_header.magic != std::array{'A', 'C', 'I', '0'}) { return Loader::ResultStatus::ErrorBadACIHeader; } + constexpr u64 fac_read_size = 4 + sizeof(FileAccessControl::permissions) + + sizeof(FileAccessControl::unknown); + if (acid_header.fac_size < fac_read_size || + !contains(acid_header.fac_offset, acid_header.fac_size, acid_size)) { + return Loader::ResultStatus::ErrorBadFileAccessControl; + } + constexpr u64 fah_read_size = 4 + sizeof(FileAccessHeader::permissions) + 4 * sizeof(u32); + if (aci_header.fah_size < fah_read_size || + !contains(aci_header.fah_offset, aci_header.fah_size, aci_size)) { + return Loader::ResultStatus::ErrorBadFileAccessHeader; + } + // Load acid_file_access per-component instead of the entire struct, since this struct does not // reflect the layout of the real data. - std::size_t current_offset = acid_header.fac_offset; + std::size_t current_offset = acid_offset + acid_header.fac_offset; if (sizeof(FileAccessControl::version) != file->ReadBytes(&acid_file_access.version, sizeof(FileAccessControl::version), current_offset)) { @@ -57,7 +99,7 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { } // Load aci_file_access per-component instead of the entire struct, same as acid_file_access - current_offset = aci_header.fah_offset; + current_offset = aci_offset + aci_header.fah_offset; if (sizeof(FileAccessHeader::version) != file->ReadBytes(&aci_file_access.version, sizeof(FileAccessHeader::version), current_offset)) { @@ -89,6 +131,10 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { return Loader::ResultStatus::ErrorBadFileAccessHeader; } + if (aci_header.kac_size % sizeof(u32) != 0 || + !contains(aci_header.kac_offset, aci_header.kac_size, aci_size)) { + return Loader::ResultStatus::ErrorBadKernelCapabilityDescriptors; + } aci_kernel_capabilities.resize(aci_header.kac_size / sizeof(u32)); const u64 read_size = aci_header.kac_size; const u64 read_offset = npdm_header.aci_offset + aci_header.kac_offset; @@ -128,6 +174,7 @@ void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address u32 main_thread_stack_size, u64 title_id, u64 filesystem_permissions, u32 system_resource_size, KernelCapabilityDescriptors capabilities) { + uses_extended_acid = false; npdm_header.has_64_bit_instructions.Assign(is_64_bit); npdm_header.address_space_type.Assign(address_space); npdm_header.main_thread_priority = static_cast<u8>(main_thread_prio); |
