diff --git a/src/xenia/vfs/devices/stfs_container_device.cc b/src/xenia/vfs/devices/stfs_container_device.cc index c8bb33fb4..caa01877c 100644 --- a/src/xenia/vfs/devices/stfs_container_device.cc +++ b/src/xenia/vfs/devices/stfs_container_device.cc @@ -542,16 +542,16 @@ StfsContainerDevice::Error StfsContainerDevice::ReadSTFS() { if (entry->attributes() & X_FILE_ATTRIBUTE_NORMAL) { uint32_t block_index = start_block_index; size_t remaining_size = file_size; - uint32_t info = 0x80; while (remaining_size && block_index) { + assert_true(block_index != 0xffffff); + size_t block_size = std::min(static_cast(0x1000), remaining_size); size_t offset = STFSDataBlockToOffset(block_index); entry->block_list_.push_back({0, offset, block_size}); remaining_size -= block_size; auto block_hash = STFSGetLevel0HashEntry(data, block_index); - block_index = block_hash.next_block_index; - info = block_hash.info; + block_index = block_hash.level0_next_block(); } } @@ -559,7 +559,7 @@ StfsContainerDevice::Error StfsContainerDevice::ReadSTFS() { } auto block_hash = STFSGetLevel0HashEntry(data, table_block_index); - table_block_index = block_hash.next_block_index; + table_block_index = block_hash.level0_next_block(); } if (all_entries.size() > 0) { @@ -634,7 +634,7 @@ size_t StfsContainerDevice::STFSDataBlockToBackingHashBlockOffset( STFSDataBlockToBackingHashBlock(block, level)); } -StfsContainerDevice::BlockHash StfsContainerDevice::STFSGetLevelNHashEntry( +StfsHashEntry StfsContainerDevice::STFSGetLevelNHashEntry( const uint8_t* map_ptr, uint32_t block_index, uint32_t level, bool secondary_block) { uint32_t record = block_index; @@ -652,13 +652,11 @@ StfsContainerDevice::BlockHash StfsContainerDevice::STFSGetLevelNHashEntry( const uint8_t* hash_data = map_ptr + hash_offset; - const uint8_t* record_data = hash_data + record * 0x18; - uint32_t info = xe::load_and_swap(record_data + 0x14); - uint32_t next_block_index = load_uint24_be(record_data + 0x15); - return {next_block_index, info}; + auto* entry = (StfsHashEntry*)(hash_data + record * 0x18); + return *entry; } -StfsContainerDevice::BlockHash StfsContainerDevice::STFSGetLevel0HashEntry( +StfsHashEntry StfsContainerDevice::STFSGetLevel0HashEntry( const uint8_t* map_ptr, uint32_t block_index) { bool use_secondary_block = false; // Use secondary block for root table if RootActiveIndex flag is set @@ -679,7 +677,7 @@ StfsContainerDevice::BlockHash StfsContainerDevice::STFSGetLevel0HashEntry( auto l2_entry = STFSGetLevelNHashEntry(map_ptr, block_index, 2, use_secondary_block); use_secondary_block = false; - if (l2_entry.info & 0x40) { // ActiveIndex flag + if (l2_entry.levelN_activeindex()) { use_secondary_block = true; } } @@ -689,7 +687,7 @@ StfsContainerDevice::BlockHash StfsContainerDevice::STFSGetLevel0HashEntry( auto l1_entry = STFSGetLevelNHashEntry(map_ptr, block_index, 1, use_secondary_block); use_secondary_block = false; - if (l1_entry.info & 0x40) { // ActiveIndex flag + if (l1_entry.levelN_activeindex()) { use_secondary_block = true; } } diff --git a/src/xenia/vfs/devices/stfs_container_device.h b/src/xenia/vfs/devices/stfs_container_device.h index 343dc5e08..2d833ce50 100644 --- a/src/xenia/vfs/devices/stfs_container_device.h +++ b/src/xenia/vfs/devices/stfs_container_device.h @@ -59,6 +59,26 @@ struct StfsVolumeDescriptor { }; static_assert_size(StfsVolumeDescriptor, 0x24); +struct StfsHashEntry { + uint8_t sha1[0x14]; + + uint8_t info0; // usually contains flags + + uint8_t info1; + uint8_t info2; + uint8_t info3; + + // If this is a level0 entry, this points to the next block in the chain + uint32_t level0_next_block() { return info3 | (info2 << 8) | (info1 << 16); } + + // If this is level 1 or 2, this says whether the hash table this entry refers + // to is using the secondary block or not + bool levelN_activeindex() { return info0 & 0x40; } + + bool levelN_writeable() { return info0 & 0x80; } +}; +static_assert_size(StfsHashEntry, 0x18); + /* SVOD */ struct SvodDeviceDescriptor { uint8_t descriptor_length; @@ -385,13 +405,16 @@ struct StfsHeader { XContentInstaller installer; uint8_t padding[0x2F2]; + bool has_installer() { + return header.header_size == 0xAD0E && installer.type != 0; + } + void set_defaults() { memset(this, 0, sizeof(StfsHeader)); header.magic = xe::vfs::XContentPackageType::kPackageTypeCon; - header.licenses[0].licensee_id = - -1; // X360 gamesaves seem to set licenses like this - header.header_size = 0x971A; + header.licenses[0].licensee_id = -1; // gamesaves set licenses like this ? + header.header_size = 0x971A; // no installer section in header metadata.metadata_version = 2; memcpy(metadata.console_id, "XENIA", 5); @@ -441,11 +464,6 @@ class StfsContainerDevice : public Device { kSingleFile = 0x4, }; - struct BlockHash { - uint32_t next_block_index; - uint32_t info; - }; - const uint32_t kSTFSDataBlocksPerHashLevel[3] = {0xAA, 0x70E4, 0x4AF768}; uint32_t ReadMagic(const std::wstring& path); @@ -469,12 +487,12 @@ class StfsContainerDevice : public Device { size_t STFSDataBlockToBackingHashBlockOffset(uint64_t block, uint32_t level = 0); - BlockHash STFSGetLevelNHashEntry(const uint8_t* map_ptr, uint32_t block_index, - uint32_t level, - bool secondary_block = false); + StfsHashEntry STFSGetLevelNHashEntry(const uint8_t* map_ptr, + uint32_t block_index, uint32_t level, + bool secondary_block = false); - BlockHash STFSGetLevel0HashEntry(const uint8_t* map_ptr, - uint32_t block_index); + StfsHashEntry STFSGetLevel0HashEntry(const uint8_t* map_ptr, + uint32_t block_index); std::wstring local_path_; std::map> mmap_;