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) { if (header_.metadata.volume_type == XContentVolumeType::kStfs) {
return header_.metadata.volume_descriptor.stfs.total_block_count * kBlockSize; 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); 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); void BlockToOffsetSVOD(size_t sector, size_t* address, size_t* file_index);
Error ReadSTFS(); Error ReadSTFS();
size_t StfsBaseOffset() const;
size_t BlockToOffsetSTFS(uint64_t block_index) const; size_t BlockToOffsetSTFS(uint64_t block_index) const;
uint32_t BlockToHashBlockNumberSTFS(uint32_t block_index, uint32_t hash_level) 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; size_t BlockToHashBlockOffsetSTFS(uint32_t block_index, uint32_t hash_level) const;

View file

@ -111,7 +111,7 @@ extern PPCFuncMapping {{ project }}_PPCFuncMappings[];
// Memory Access // 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) #define REX_PHYS_HOST_OFFSET(addr) (((u32)(addr) >= 0xE0000000u) ? 0x1000u : 0u)
#else #else
#define REX_PHYS_HOST_OFFSET(addr) 0u #define REX_PHYS_HOST_OFFSET(addr) 0u

View file

@ -69,7 +69,7 @@
#endif #endif
#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) #define REX_PHYS_HOST_OFFSET(addr) (((u32)(addr) >= 0xE0000000u) ? 0x1000u : 0u)
#else #else
#define REX_PHYS_HOST_OFFSET(addr) 0u #define REX_PHYS_HOST_OFFSET(addr) 0u

View file

@ -568,15 +568,20 @@ StfsContainerDevice::Error StfsContainerDevice::ReadSTFS() {
break; break;
} }
std::string name(reinterpret_cast<const char*>(dir_entry.name),
dir_entry.flags.name_length & 0x3F);
StfsContainerEntry* parent_entry = nullptr; StfsContainerEntry* parent_entry = nullptr;
if (dir_entry.directory_index == 0xFFFF) { if (dir_entry.directory_index == 0xFFFF) {
parent_entry = root_entry; parent_entry = root_entry;
} else { } 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]; 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_); auto entry = StfsContainerEntry::Create(this, parent_entry, name, &files_);
if (dir_entry.flags.directory) { if (dir_entry.flags.directory) {
@ -609,27 +614,32 @@ StfsContainerDevice::Error StfsContainerDevice::ReadSTFS() {
entry->block_list_.push_back({0, offset, block_size}); entry->block_list_.push_back({0, offset, block_size});
remaining_size -= block_size; remaining_size -= block_size;
auto block_hash = GetBlockHash(block_index); 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(); block_index = block_hash->level0_next_block();
} }
if (remaining_size) { if (remaining_size) {
// Loop above must have exited prematurely, bad hash tables? // Loop above must have exited prematurely, bad hash tables?
REXFS_WARN( REXFS_ERROR(
"STFS file {} only found {} bytes for file, expected {} ({} " "STFS file {} only found {} bytes for file, expected {} ({} "
"bytes missing)", "bytes missing)",
name, dir_entry.length.get() - remaining_size, dir_entry.length.get(), name, dir_entry.length.get() - remaining_size, dir_entry.length.get(),
remaining_size); remaining_size);
assert_always(); return Error::kErrorDamagedFile;
} }
// Check that the number of blocks retrieved from hash entries matches // Check that the number of blocks retrieved from hash entries matches
// the block count read from the file entry // the block count read from the file entry
if (entry->block_list_.size() != dir_entry.allocated_data_blocks()) { if (entry->block_list_.size() != dir_entry.allocated_data_blocks()) {
REXFS_WARN( REXFS_ERROR(
"STFS failed to read correct block-chain for entry {}, read {} " "STFS failed to read correct block-chain for entry {}, read {} "
"blocks, expected {}", "blocks, expected {}",
entry->name_, entry->block_list_.size(), dir_entry.allocated_data_blocks()); 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); 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(); table_block_index = block_hash->level0_next_block();
if (table_block_index == kEndOfChain) { if (table_block_index == kEndOfChain) {
break; break;
@ -644,14 +658,22 @@ StfsContainerDevice::Error StfsContainerDevice::ReadSTFS() {
} }
if (n + 1 != descriptor.file_table_block_count) { 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); descriptor.file_table_block_count);
assert_always(); return Error::kErrorDamagedFile;
} }
return Error::kSuccess; 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 { size_t StfsContainerDevice::BlockToOffsetSTFS(uint64_t block_index) const {
// For every level there is a hash table // For every level there is a hash table
// Level 0: hash table of next 170 blocks // Level 0: hash table of next 170 blocks
@ -669,7 +691,7 @@ size_t StfsContainerDevice::BlockToOffsetSTFS(uint64_t block_index) const {
base *= kBlocksPerHashLevel[0]; 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, 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, size_t StfsContainerDevice::BlockToHashBlockOffsetSTFS(uint32_t block_index,
uint32_t hash_level) const { uint32_t hash_level) const {
uint64_t block = BlockToHashBlockNumberSTFS(block_index, hash_level); 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) { const StfsHashEntry* StfsContainerDevice::GetBlockHash(uint32_t block_index) {