fixed missing DLC, macOS crash, crashes when editing photos

This commit is contained in:
mchughalex 2026-06-11 07:56:33 +01:00
parent 4329f6d049
commit 5d932d1cc8
4 changed files with 37 additions and 14 deletions

View file

@ -77,7 +77,7 @@ class StfsContainerDevice : public Device {
if (header_.metadata.volume_type == XContentVolumeType::kStfs) {
return header_.metadata.volume_descriptor.stfs.total_block_count * kBlockSize;
}
return files_total_size_ - rex::round_up(header_.header.header_size, kBlockSize);
return files_total_size_ - StfsBaseOffset();
}
return files_total_size_ - sizeof(StfsHeader);
}
@ -116,6 +116,7 @@ class StfsContainerDevice : public Device {
void BlockToOffsetSVOD(size_t sector, size_t* address, size_t* file_index);
Error ReadSTFS();
size_t StfsBaseOffset() const;
size_t BlockToOffsetSTFS(uint64_t block_index) const;
uint32_t BlockToHashBlockNumberSTFS(uint32_t block_index, uint32_t hash_level) const;
size_t BlockToHashBlockOffsetSTFS(uint32_t block_index, uint32_t hash_level) const;

View file

@ -111,7 +111,7 @@ extern PPCFuncMapping {{ project }}_PPCFuncMappings[];
// Memory Access
//=============================================================================
#if REX_PLATFORM_WIN32
#if REX_PLATFORM_WIN32 || (REX_PLATFORM_MAC && REX_ARCH_ARM64)
#define REX_PHYS_HOST_OFFSET(addr) (((u32)(addr) >= 0xE0000000u) ? 0x1000u : 0u)
#else
#define REX_PHYS_HOST_OFFSET(addr) 0u

View file

@ -69,7 +69,7 @@
#endif
#endif
#if REX_PLATFORM_WIN32
#if REX_PLATFORM_WIN32 || (REX_PLATFORM_MAC && REX_ARCH_ARM64)
#define REX_PHYS_HOST_OFFSET(addr) (((u32)(addr) >= 0xE0000000u) ? 0x1000u : 0u)
#else
#define REX_PHYS_HOST_OFFSET(addr) 0u

View file

@ -568,15 +568,20 @@ StfsContainerDevice::Error StfsContainerDevice::ReadSTFS() {
break;
}
std::string name(reinterpret_cast<const char*>(dir_entry.name),
dir_entry.flags.name_length & 0x3F);
StfsContainerEntry* parent_entry = nullptr;
if (dir_entry.directory_index == 0xFFFF) {
parent_entry = root_entry;
} else {
if (dir_entry.directory_index >= all_entries.size()) {
REXFS_ERROR("STFS directory entry {} has invalid parent index {}", name,
dir_entry.directory_index.get());
return Error::kErrorDamagedFile;
}
parent_entry = all_entries[dir_entry.directory_index];
}
std::string name(reinterpret_cast<const char*>(dir_entry.name),
dir_entry.flags.name_length & 0x3F);
auto entry = StfsContainerEntry::Create(this, parent_entry, name, &files_);
if (dir_entry.flags.directory) {
@ -609,27 +614,32 @@ StfsContainerDevice::Error StfsContainerDevice::ReadSTFS() {
entry->block_list_.push_back({0, offset, block_size});
remaining_size -= block_size;
auto block_hash = GetBlockHash(block_index);
if (!block_hash) {
REXFS_ERROR("STFS failed to read block hash for entry {} block {}", name,
block_index);
return Error::kErrorReadError;
}
block_index = block_hash->level0_next_block();
}
if (remaining_size) {
// Loop above must have exited prematurely, bad hash tables?
REXFS_WARN(
REXFS_ERROR(
"STFS file {} only found {} bytes for file, expected {} ({} "
"bytes missing)",
name, dir_entry.length.get() - remaining_size, dir_entry.length.get(),
remaining_size);
assert_always();
return Error::kErrorDamagedFile;
}
// Check that the number of blocks retrieved from hash entries matches
// the block count read from the file entry
if (entry->block_list_.size() != dir_entry.allocated_data_blocks()) {
REXFS_WARN(
REXFS_ERROR(
"STFS failed to read correct block-chain for entry {}, read {} "
"blocks, expected {}",
entry->name_, entry->block_list_.size(), dir_entry.allocated_data_blocks());
assert_always();
return Error::kErrorDamagedFile;
}
}
@ -637,6 +647,10 @@ StfsContainerDevice::Error StfsContainerDevice::ReadSTFS() {
}
auto block_hash = GetBlockHash(table_block_index);
if (!block_hash) {
REXFS_ERROR("STFS failed to read file table block hash for block {}", table_block_index);
return Error::kErrorReadError;
}
table_block_index = block_hash->level0_next_block();
if (table_block_index == kEndOfChain) {
break;
@ -644,14 +658,22 @@ StfsContainerDevice::Error StfsContainerDevice::ReadSTFS() {
}
if (n + 1 != descriptor.file_table_block_count) {
REXFS_WARN("STFS read {} file table blocks, but STFS headers expected {}!", n + 1,
REXFS_ERROR("STFS read {} file table blocks, but STFS headers expected {}!", n + 1,
descriptor.file_table_block_count);
assert_always();
return Error::kErrorDamagedFile;
}
return Error::kSuccess;
}
size_t StfsContainerDevice::StfsBaseOffset() const {
// STFS packages with CON headers can report a metadata header size that
// rounds to 0xA000, but the hash tables still begin at the standard 0xB000
// backing offset. Using the smaller value makes the directory reader consume
// hash bytes as file-table entries.
return std::max<size_t>(0xB000, rex::round_up(header_.header.header_size, kBlockSize));
}
size_t StfsContainerDevice::BlockToOffsetSTFS(uint64_t block_index) const {
// For every level there is a hash table
// Level 0: hash table of next 170 blocks
@ -669,7 +691,7 @@ size_t StfsContainerDevice::BlockToOffsetSTFS(uint64_t block_index) const {
base *= kBlocksPerHashLevel[0];
}
return rex::round_up(header_.header.header_size, kBlockSize) + (block << 12);
return StfsBaseOffset() + (block << 12);
}
uint32_t StfsContainerDevice::BlockToHashBlockNumberSTFS(uint32_t block_index,
@ -706,7 +728,7 @@ uint32_t StfsContainerDevice::BlockToHashBlockNumberSTFS(uint32_t block_index,
size_t StfsContainerDevice::BlockToHashBlockOffsetSTFS(uint32_t block_index,
uint32_t hash_level) const {
uint64_t block = BlockToHashBlockNumberSTFS(block_index, hash_level);
return rex::round_up(header_.header.header_size, kBlockSize) + (block << 12);
return StfsBaseOffset() + (block << 12);
}
const StfsHashEntry* StfsContainerDevice::GetBlockHash(uint32_t block_index) {