diff --git a/src/xenia/apu/audio_media_player.cc b/src/xenia/apu/audio_media_player.cc index 109862f7a..db835ac23 100644 --- a/src/xenia/apu/audio_media_player.cc +++ b/src/xenia/apu/audio_media_player.cc @@ -412,8 +412,9 @@ bool AudioMediaPlayer::LoadSongToMemory(std::vector* buffer) { buffer->resize(vfs_file->entry()->size()); size_t bytes_read = 0; - result = vfs_file->ReadSync(buffer->data(), vfs_file->entry()->size(), 0, - &bytes_read); + result = vfs_file->ReadSync( + std::span(buffer->data(), vfs_file->entry()->size()), 0, + &bytes_read); return !result; } diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 528429aa2..6b31db859 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -157,8 +157,8 @@ bool KernelState::UpdateSpaData(vfs::Entry* spa_file_update) { std::vector data(spa_file_update->size()); size_t read_bytes = 0; - if (file->ReadSync(data.data(), spa_file_update->size(), 0, &read_bytes) != - X_STATUS_SUCCESS) { + if (file->ReadSync(std::span(data.data(), spa_file_update->size()), + 0, &read_bytes) != X_STATUS_SUCCESS) { return false; } diff --git a/src/xenia/kernel/user_module.cc b/src/xenia/kernel/user_module.cc index b6a061182..c0558345f 100644 --- a/src/xenia/kernel/user_module.cc +++ b/src/xenia/kernel/user_module.cc @@ -102,7 +102,8 @@ X_STATUS UserModule::LoadFromFile(const std::string_view path) { // Read entire file into memory. // Ugh. size_t bytes_read = 0; - result = file->ReadSync(buffer.data(), buffer.size(), 0, &bytes_read); + result = file->ReadSync(std::span(buffer.data(), buffer.size()), 0, + &bytes_read); if (XFAILED(result)) { return result; } diff --git a/src/xenia/kernel/util/xex2_info.h b/src/xenia/kernel/util/xex2_info.h index 52df96ad4..33efc360c 100644 --- a/src/xenia/kernel/util/xex2_info.h +++ b/src/xenia/kernel/util/xex2_info.h @@ -11,6 +11,7 @@ #define XENIA_KERNEL_UTIL_XEX2_INFO_H_ #include +#include #include #include "xenia/base/byte_order.h" diff --git a/src/xenia/kernel/xam/profile_manager.cc b/src/xenia/kernel/xam/profile_manager.cc index d6c1a1ab1..154983f77 100644 --- a/src/xenia/kernel/xam/profile_manager.cc +++ b/src/xenia/kernel/xam/profile_manager.cc @@ -202,8 +202,9 @@ bool ProfileManager::LoadAccount(const uint64_t xuid) { file_data.resize(output_file->entry()->size()); size_t bytes_read = 0; - output_file->ReadSync(file_data.data(), output_file->entry()->size(), 0, - &bytes_read); + output_file->ReadSync( + std::span(file_data.data(), output_file->entry()->size()), 0, + &bytes_read); output_file->Destroy(); if (bytes_read < sizeof(X_XAMACCOUNTINFO)) { @@ -562,8 +563,9 @@ bool ProfileManager::UpdateAccount(const uint64_t xuid, EncryptAccountFile(account, encrypted_data.data()); size_t written_bytes = 0; - output_file->WriteSync(encrypted_data.data(), encrypted_data.size(), 0, - &written_bytes); + output_file->WriteSync( + std::span(encrypted_data.data(), encrypted_data.size()), 0, + &written_bytes); output_file->Destroy(); return true; } diff --git a/src/xenia/kernel/xam/user_profile.cc b/src/xenia/kernel/xam/user_profile.cc index 1dc8dcd55..64a0eb0a1 100644 --- a/src/xenia/kernel/xam/user_profile.cc +++ b/src/xenia/kernel/xam/user_profile.cc @@ -89,7 +89,8 @@ void UserProfile::LoadProfileIcon(XTileType tile_type) { std::vector data(file->entry()->size()); size_t written_bytes = 0; - file->ReadSync(data.data(), file->entry()->size(), 0, &written_bytes); + file->ReadSync(std::span(data.data(), file->entry()->size()), 0, + &written_bytes); file->Destroy(); profile_images_.insert({tile_type, data}); @@ -114,7 +115,8 @@ std::vector UserProfile::LoadGpd(const uint32_t title_id) { std::vector data(entry->size()); size_t read_size = 0; - result = file->ReadSync(data.data(), entry->size(), 0, &read_size); + result = file->ReadSync(std::span(data.data(), entry->size()), 0, + &read_size); if (result != X_STATUS_SUCCESS || read_size != entry->size()) { XELOGW( "User {} (XUID: {:016X}) cannot read profile GPD! Status: {:08X} read: " @@ -150,7 +152,8 @@ bool UserProfile::WriteGpd(const uint32_t title_id) { } size_t written_bytes = 0; - file->WriteSync(data.data(), data.size(), 0, &written_bytes); + file->WriteSync(std::span(data.data(), data.size()), 0, + &written_bytes); file->Destroy(); return true; } diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc index 656089dad..a0c88beea 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc @@ -277,7 +277,9 @@ dword_result_t XexLoadImageHeaders_entry(pointer_t path, size_t bytes_read = 0; X_STATUS result_status = vfs_file->ReadSync( - reinterpret_cast(header.host_address()), 2048, 0, &bytes_read); + std::span(reinterpret_cast(header.host_address()), + 2048), + 0, &bytes_read); if (result_status < 0) { vfs_file->Destroy(); @@ -298,8 +300,10 @@ dword_result_t XexLoadImageHeaders_entry(pointer_t path, result_status = X_STATUS_SUCCESS; } else { result_status = vfs_file->ReadSync( - reinterpret_cast(header.host_address() + 2048), - header_size - 2048, 2048, &bytes_read); + std::span( + reinterpret_cast(header.host_address() + 2048), + header_size - 2048), + 2048, &bytes_read); if (result_status >= X_STATUS_SUCCESS) { result_status = X_STATUS_SUCCESS; } diff --git a/src/xenia/kernel/xfile.cc b/src/xenia/kernel/xfile.cc index a1c9257d2..935cf5492 100644 --- a/src/xenia/kernel/xfile.cc +++ b/src/xenia/kernel/xfile.cc @@ -143,12 +143,14 @@ X_STATUS XFile::Read(uint32_t buffer_guest_address, uint32_t buffer_length, result = X_STATUS_ACCESS_VIOLATION; } else { result = file_->ReadSync( - buffer_physical_heap - ? memory()->TranslatePhysical( - buffer_physical_heap->GetPhysicalAddress( - buffer_guest_address)) - : memory()->TranslateVirtual(buffer_guest_address), - buffer_length, size_t(byte_offset), &bytes_read); + std::span( + buffer_physical_heap + ? memory()->TranslatePhysical( + buffer_physical_heap->GetPhysicalAddress( + buffer_guest_address)) + : memory()->TranslateVirtual(buffer_guest_address), + buffer_length), + size_t(byte_offset), &bytes_read); if (XSUCCEEDED(result)) { if (buffer_physical_heap) { buffer_physical_heap->TriggerCallbacks( @@ -245,9 +247,10 @@ X_STATUS XFile::Write(uint32_t buffer_guest_address, uint32_t buffer_length, } size_t bytes_written = 0; - X_STATUS result = - file_->WriteSync(memory()->TranslateVirtual(buffer_guest_address), - buffer_length, size_t(byte_offset), &bytes_written); + X_STATUS result = file_->WriteSync( + std::span(memory()->TranslateVirtual(buffer_guest_address), + buffer_length), + size_t(byte_offset), &bytes_written); if (XSUCCEEDED(result)) { position_ += bytes_written; } diff --git a/src/xenia/vfs/devices/disc_image_file.cc b/src/xenia/vfs/devices/disc_image_file.cc index dab4f9e08..f5594a1ac 100644 --- a/src/xenia/vfs/devices/disc_image_file.cc +++ b/src/xenia/vfs/devices/disc_image_file.cc @@ -23,8 +23,8 @@ DiscImageFile::~DiscImageFile() = default; void DiscImageFile::Destroy() { delete this; } -X_STATUS DiscImageFile::ReadSync(void* buffer, size_t buffer_length, - size_t byte_offset, size_t* out_bytes_read) { +X_STATUS DiscImageFile::ReadSync(std::span buffer, size_t byte_offset, + size_t* out_bytes_read) { if (byte_offset >= entry_->size()) { return X_STATUS_END_OF_FILE; } @@ -36,8 +36,8 @@ X_STATUS DiscImageFile::ReadSync(void* buffer, size_t buffer_length, size_t real_offset = entry_->data_offset() + byte_offset; size_t real_length = - std::min(buffer_length, entry_->data_size() - byte_offset); - std::memcpy(buffer, entry_->mmap()->data() + real_offset, real_length); + std::min(buffer.size(), entry_->data_size() - byte_offset); + std::memcpy(buffer.data(), entry_->mmap()->data() + real_offset, real_length); *out_bytes_read = real_length; return X_STATUS_SUCCESS; } diff --git a/src/xenia/vfs/devices/disc_image_file.h b/src/xenia/vfs/devices/disc_image_file.h index d4b996c3e..b2c0cf99f 100644 --- a/src/xenia/vfs/devices/disc_image_file.h +++ b/src/xenia/vfs/devices/disc_image_file.h @@ -24,10 +24,10 @@ class DiscImageFile : public File { void Destroy() override; - X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset, + X_STATUS ReadSync(std::span buffer, size_t byte_offset, size_t* out_bytes_read) override; - X_STATUS WriteSync(const void* buffer, size_t buffer_length, - size_t byte_offset, size_t* out_bytes_written) override { + X_STATUS WriteSync(std::span buffer, size_t byte_offset, + size_t* out_bytes_written) override { return X_STATUS_ACCESS_DENIED; } X_STATUS SetLength(size_t length) override { return X_STATUS_ACCESS_DENIED; } diff --git a/src/xenia/vfs/devices/disc_zarchive_file.cc b/src/xenia/vfs/devices/disc_zarchive_file.cc index 1a925156b..99c2f7833 100644 --- a/src/xenia/vfs/devices/disc_zarchive_file.cc +++ b/src/xenia/vfs/devices/disc_zarchive_file.cc @@ -25,19 +25,23 @@ DiscZarchiveFile::~DiscZarchiveFile() = default; void DiscZarchiveFile::Destroy() { delete this; } -X_STATUS DiscZarchiveFile::ReadSync(void* buffer, size_t buffer_length, +X_STATUS DiscZarchiveFile::ReadSync(std::span buffer, size_t byte_offset, size_t* out_bytes_read) { if (byte_offset >= entry_->size()) { return X_STATUS_END_OF_FILE; } - const uint64_t bytes_read = - ((DiscZarchiveDevice*)entry_->device_) - ->reader() - ->ReadFromFile(entry_->handle_, byte_offset, buffer_length, buffer); - const size_t real_length = - std::min(buffer_length, entry_->data_size() - byte_offset); - *out_bytes_read = real_length; + + DiscZarchiveDevice* zArchDev = + dynamic_cast(entry_->device_); + + if (!zArchDev) { + return X_STATUS_UNSUCCESSFUL; + } + + const uint64_t bytes_read = zArchDev->reader()->ReadFromFile( + entry_->handle_, byte_offset, buffer.size(), buffer.data()); + *out_bytes_read = bytes_read; return X_STATUS_SUCCESS; } diff --git a/src/xenia/vfs/devices/disc_zarchive_file.h b/src/xenia/vfs/devices/disc_zarchive_file.h index e73df76b5..8d6d91960 100644 --- a/src/xenia/vfs/devices/disc_zarchive_file.h +++ b/src/xenia/vfs/devices/disc_zarchive_file.h @@ -24,10 +24,10 @@ class DiscZarchiveFile : public File { void Destroy() override; - X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset, + X_STATUS ReadSync(std::span buffer, size_t byte_offset, size_t* out_bytes_read) override; - X_STATUS WriteSync(const void* buffer, size_t buffer_length, - size_t byte_offset, size_t* out_bytes_written) override { + X_STATUS WriteSync(std::span buffer, size_t byte_offset, + size_t* out_bytes_written) override { return X_STATUS_ACCESS_DENIED; } X_STATUS SetLength(size_t length) override { return X_STATUS_ACCESS_DENIED; } diff --git a/src/xenia/vfs/devices/host_path_file.cc b/src/xenia/vfs/devices/host_path_file.cc index b037d511f..48ab1a620 100644 --- a/src/xenia/vfs/devices/host_path_file.cc +++ b/src/xenia/vfs/devices/host_path_file.cc @@ -28,21 +28,22 @@ void HostPathFile::Destroy() { delete this; } -X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length, - size_t byte_offset, size_t* out_bytes_read) { +X_STATUS HostPathFile::ReadSync(std::span buffer, size_t byte_offset, + size_t* out_bytes_read) { if (!(file_access_ & (FileAccess::kGenericRead | FileAccess::kFileReadData))) { return X_STATUS_ACCESS_DENIED; } - if (file_handle_->Read(byte_offset, buffer, buffer_length, out_bytes_read)) { + if (file_handle_->Read(byte_offset, buffer.data(), buffer.size(), + out_bytes_read)) { return X_STATUS_SUCCESS; } else { return X_STATUS_END_OF_FILE; } } -X_STATUS HostPathFile::WriteSync(const void* buffer, size_t buffer_length, +X_STATUS HostPathFile::WriteSync(std::span buffer, size_t byte_offset, size_t* out_bytes_written) { if (!(file_access_ & (FileAccess::kGenericWrite | FileAccess::kFileWriteData | @@ -50,7 +51,7 @@ X_STATUS HostPathFile::WriteSync(const void* buffer, size_t buffer_length, return X_STATUS_ACCESS_DENIED; } - if (file_handle_->Write(byte_offset, buffer, buffer_length, + if (file_handle_->Write(byte_offset, buffer.data(), buffer.size(), out_bytes_written)) { return X_STATUS_SUCCESS; } else { diff --git a/src/xenia/vfs/devices/host_path_file.h b/src/xenia/vfs/devices/host_path_file.h index 2d896e11a..3f0b50b23 100644 --- a/src/xenia/vfs/devices/host_path_file.h +++ b/src/xenia/vfs/devices/host_path_file.h @@ -28,10 +28,10 @@ class HostPathFile : public File { void Destroy() override; - X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset, + X_STATUS ReadSync(std::span buffer, size_t byte_offset, size_t* out_bytes_read) override; - X_STATUS WriteSync(const void* buffer, size_t buffer_length, - size_t byte_offset, size_t* out_bytes_written) override; + X_STATUS WriteSync(std::span buffer, size_t byte_offset, + size_t* out_bytes_written) override; X_STATUS SetLength(size_t length) override; private: diff --git a/src/xenia/vfs/devices/null_file.cc b/src/xenia/vfs/devices/null_file.cc index e04fd8397..b54e5e13e 100644 --- a/src/xenia/vfs/devices/null_file.cc +++ b/src/xenia/vfs/devices/null_file.cc @@ -21,8 +21,8 @@ NullFile::~NullFile() = default; void NullFile::Destroy() { delete this; } -X_STATUS NullFile::ReadSync(void* buffer, size_t buffer_length, - size_t byte_offset, size_t* out_bytes_read) { +X_STATUS NullFile::ReadSync(std::span buffer, size_t byte_offset, + size_t* out_bytes_read) { if (!(file_access_ & FileAccess::kFileReadData)) { return X_STATUS_ACCESS_DENIED; } @@ -30,7 +30,7 @@ X_STATUS NullFile::ReadSync(void* buffer, size_t buffer_length, return X_STATUS_SUCCESS; } -X_STATUS NullFile::WriteSync(const void* buffer, size_t buffer_length, +X_STATUS NullFile::WriteSync(std::span buffer, size_t byte_offset, size_t* out_bytes_written) { if (!(file_access_ & (FileAccess::kFileWriteData | FileAccess::kFileAppendData))) { diff --git a/src/xenia/vfs/devices/null_file.h b/src/xenia/vfs/devices/null_file.h index 32a6be25c..7e04b2977 100644 --- a/src/xenia/vfs/devices/null_file.h +++ b/src/xenia/vfs/devices/null_file.h @@ -27,10 +27,10 @@ class NullFile : public File { void Destroy() override; - X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset, + X_STATUS ReadSync(std::span buffer, size_t byte_offset, size_t* out_bytes_read) override; - X_STATUS WriteSync(const void* buffer, size_t buffer_length, - size_t byte_offset, size_t* out_bytes_written) override; + X_STATUS WriteSync(std::span buffer, size_t byte_offset, + size_t* out_bytes_written) override; X_STATUS SetLength(size_t length) override; }; diff --git a/src/xenia/vfs/devices/xcontent_container_device.cc b/src/xenia/vfs/devices/xcontent_container_device.cc index eb95bc45f..3160eb283 100644 --- a/src/xenia/vfs/devices/xcontent_container_device.cc +++ b/src/xenia/vfs/devices/xcontent_container_device.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2023 Ben Vanik. All rights reserved. * + * Copyright 2025 Xenia Canary. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -100,7 +100,7 @@ bool XContentContainerDevice::Initialize() { SetupContainer(); - if (LoadHostFiles(header_file) != Result::kSuccess) { + if (LoadHostFiles() != Result::kSuccess) { XELOGE("Error loading XContent host files."); return false; } @@ -152,14 +152,6 @@ void XContentContainerDevice::Dump(StringBuffer* string_buffer) { root_entry_->Dump(string_buffer, 0); } -void XContentContainerDevice::CloseFiles() { - for (auto& file : files_) { - fclose(file.second); - } - files_.clear(); - files_total_size_ = 0; -} - kernel::xam::XCONTENT_AGGREGATE_DATA XContentContainerDevice::content_header() const { kernel::xam::XCONTENT_AGGREGATE_DATA data; diff --git a/src/xenia/vfs/devices/xcontent_container_device.h b/src/xenia/vfs/devices/xcontent_container_device.h index f1a738687..4c3d3a573 100644 --- a/src/xenia/vfs/devices/xcontent_container_device.h +++ b/src/xenia/vfs/devices/xcontent_container_device.h @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2023 Ben Vanik. All rights reserved. * + * Copyright 2025 Xenia Canary. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -14,8 +14,6 @@ #include #include -#include "xenia/base/math.h" -#include "xenia/kernel/util/xex2_info.h" #include "xenia/kernel/xam/content_manager.h" #include "xenia/vfs/device.h" #include "xenia/vfs/devices/stfs_xbox.h" @@ -66,7 +64,7 @@ class XContentContainerDevice : public Device { } uint32_t content_type() const { - return (uint32_t)header_->content_metadata.content_type.get(); + return static_cast(header_->content_metadata.content_type.get()); } kernel::xam::XCONTENT_AGGREGATE_DATA content_header() const; @@ -99,12 +97,11 @@ class XContentContainerDevice : public Device { virtual Result Read() = 0; // Load all host files. Usually STFS is only 1 file, meanwhile SVOD is usually // multiple file. - virtual Result LoadHostFiles(FILE* header_file) = 0; - // Initialize any container specific fields. + virtual Result LoadHostFiles() = 0; + // Initialize container specific fields. virtual void SetupContainer() {}; Entry* ResolvePath(const std::string_view path) override; - void CloseFiles(); void Dump(StringBuffer* string_buffer) override; Result ReadHeaderAndVerify(FILE* header_file); @@ -119,7 +116,6 @@ class XContentContainerDevice : public Device { std::string name_; std::filesystem::path host_path_; - std::map files_; size_t files_total_size_; std::unique_ptr root_entry_; std::unique_ptr header_; diff --git a/src/xenia/vfs/devices/xcontent_container_entry.cc b/src/xenia/vfs/devices/xcontent_container_entry.cc index c3c0f9a09..87d76a931 100644 --- a/src/xenia/vfs/devices/xcontent_container_entry.cc +++ b/src/xenia/vfs/devices/xcontent_container_entry.cc @@ -2,46 +2,22 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2023 Ben Vanik. All rights reserved. * + * Copyright 2025 Xenia Canary. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include "xenia/vfs/devices/xcontent_container_entry.h" -#include "xenia/vfs/devices/xcontent_container_file.h" - -#include namespace xe { namespace vfs { XContentContainerEntry::XContentContainerEntry(Device* device, Entry* parent, - const std::string_view path, - MultiFileHandles* files) - : Entry(device, parent, path), - files_(files), - data_offset_(0), - data_size_(0), - block_(0) {} + const std::string_view path) + : Entry(device, parent, path), data_offset_(0), data_size_(0), block_(0) {} XContentContainerEntry::~XContentContainerEntry() = default; -std::unique_ptr XContentContainerEntry::Create( - Device* device, Entry* parent, const std::string_view name, - MultiFileHandles* files) { - auto path = xe::utf8::join_guest_paths(parent->path(), name); - auto entry = - std::make_unique(device, parent, path, files); - - return std::move(entry); -} - -X_STATUS XContentContainerEntry::Open(uint32_t desired_access, - File** out_file) { - *out_file = new XContentContainerFile(desired_access, this); - return X_STATUS_SUCCESS; -} - bool XContentContainerEntry::DeleteEntryInternal(Entry* entry) { return false; } } // namespace vfs diff --git a/src/xenia/vfs/devices/xcontent_container_entry.h b/src/xenia/vfs/devices/xcontent_container_entry.h index 563d02b4e..a9dbdeb08 100644 --- a/src/xenia/vfs/devices/xcontent_container_entry.h +++ b/src/xenia/vfs/devices/xcontent_container_entry.h @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2023 Ben Vanik. All rights reserved. * + * Copyright 2025 Xenia Canary. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -10,8 +10,6 @@ #ifndef XENIA_VFS_DEVICES_XCONTENT_CONTAINER_ENTRY_H_ #define XENIA_VFS_DEVICES_XCONTENT_CONTAINER_ENTRY_H_ -#include -#include #include #include "xenia/vfs/entry.h" @@ -19,26 +17,18 @@ namespace xe { namespace vfs { -typedef std::map MultiFileHandles; - -class XContentContainerDevice; class XContentContainerEntry : public Entry { public: XContentContainerEntry(Device* device, Entry* parent, - const std::string_view path, MultiFileHandles* files); + const std::string_view path); ~XContentContainerEntry() override; - static std::unique_ptr Create( - Device* device, Entry* parent, const std::string_view name, - MultiFileHandles* files); - - MultiFileHandles* files() const { return files_; } size_t data_offset() const { return data_offset_; } size_t data_size() const { return data_size_; } size_t block() const { return block_; } - X_STATUS Open(uint32_t desired_access, File** out_file) override; + X_STATUS Open(uint32_t desired_access, File** out_file) override = 0; struct BlockRecord { size_t file; @@ -53,7 +43,6 @@ class XContentContainerEntry : public Entry { bool DeleteEntryInternal(Entry* entry) override; - MultiFileHandles* files_; size_t data_offset_; size_t data_size_; size_t block_; diff --git a/src/xenia/vfs/devices/xcontent_container_file.cc b/src/xenia/vfs/devices/xcontent_container_file.cc index 65706534d..43237d168 100644 --- a/src/xenia/vfs/devices/xcontent_container_file.cc +++ b/src/xenia/vfs/devices/xcontent_container_file.cc @@ -2,17 +2,13 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2023 Ben Vanik. All rights reserved. * + * Copyright 2025 Xenia Canary. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ -#include -#include - -#include "xenia/base/math.h" -#include "xenia/vfs/devices/xcontent_container_entry.h" #include "xenia/vfs/devices/xcontent_container_file.h" +#include "xenia/vfs/devices/xcontent_container_entry.h" namespace xe { namespace vfs { @@ -25,7 +21,7 @@ XContentContainerFile::~XContentContainerFile() = default; void XContentContainerFile::Destroy() { delete this; } -X_STATUS XContentContainerFile::ReadSync(void* buffer, size_t buffer_length, +X_STATUS XContentContainerFile::ReadSync(std::span buffer, size_t byte_offset, size_t* out_bytes_read) { if (byte_offset >= entry_->size()) { @@ -33,9 +29,9 @@ X_STATUS XContentContainerFile::ReadSync(void* buffer, size_t buffer_length, } size_t src_offset = 0; - uint8_t* p = reinterpret_cast(buffer); + uint8_t* p = buffer.data(); size_t remaining_length = - std::min(buffer_length, entry_->size() - byte_offset); + std::min(buffer.size(), entry_->size() - byte_offset); *out_bytes_read = 0; for (size_t i = 0; i < entry_->block_list().size(); i++) { @@ -51,9 +47,8 @@ X_STATUS XContentContainerFile::ReadSync(void* buffer, size_t buffer_length, size_t read_length = std::min(record.length - read_offset, remaining_length); - auto& file = entry_->files()->at(record.file); - xe::filesystem::Seek(file, record.offset + read_offset, SEEK_SET); - auto num_read = fread(p, 1, read_length, file); + auto num_read = Read(std::span(p, read_length), + record.offset + read_offset, record.file); *out_bytes_read += num_read; p += num_read; diff --git a/src/xenia/vfs/devices/xcontent_container_file.h b/src/xenia/vfs/devices/xcontent_container_file.h index e2b46bb7a..2e129e2a2 100644 --- a/src/xenia/vfs/devices/xcontent_container_file.h +++ b/src/xenia/vfs/devices/xcontent_container_file.h @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2023 Ben Vanik. All rights reserved. * + * Copyright 2025 Xenia Canary. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -26,15 +26,18 @@ class XContentContainerFile : public File { void Destroy() override; - X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset, + X_STATUS ReadSync(std::span buffer, size_t byte_offset, size_t* out_bytes_read) override; - X_STATUS WriteSync(const void* buffer, size_t buffer_length, - size_t byte_offset, size_t* out_bytes_written) override { + X_STATUS WriteSync(std::span buffer, size_t byte_offset, + size_t* out_bytes_written) override { return X_STATUS_ACCESS_DENIED; } X_STATUS SetLength(size_t length) override { return X_STATUS_ACCESS_DENIED; } private: + virtual size_t Read(std::span buffer, size_t offset, + size_t record_file) = 0; + XContentContainerEntry* entry_; }; diff --git a/src/xenia/vfs/devices/xcontent_devices/stfs_container_device.cc b/src/xenia/vfs/devices/xcontent_devices/stfs_container_device.cc index 7273a7b4d..af35cefe6 100644 --- a/src/xenia/vfs/devices/xcontent_devices/stfs_container_device.cc +++ b/src/xenia/vfs/devices/xcontent_devices/stfs_container_device.cc @@ -7,13 +7,10 @@ ****************************************************************************** */ -#include -#include - +#include "xenia/vfs/devices/xcontent_devices/stfs_container_device.h" #include "xenia/base/logging.h" #include "xenia/kernel/xam/content_manager.h" -#include "xenia/vfs/devices/xcontent_container_entry.h" -#include "xenia/vfs/devices/xcontent_devices/stfs_container_device.h" +#include "xenia/vfs/devices/xcontent_devices/stfs_container_entry.h" namespace xe { namespace vfs { @@ -26,7 +23,7 @@ StfsContainerDevice::StfsContainerDevice(const std::string_view mount_path, SetName("STFS"); } -StfsContainerDevice::~StfsContainerDevice() { CloseFiles(); } +StfsContainerDevice::~StfsContainerDevice() {} void StfsContainerDevice::SetupContainer() { // Additional part specific to STFS container. @@ -38,26 +35,27 @@ void StfsContainerDevice::SetupContainer() { ((kBlocksPerHashLevel[0] + 1) * blocks_per_hash_table_); } -XContentContainerDevice::Result StfsContainerDevice::LoadHostFiles( - FILE* header_file) { +XContentContainerDevice::Result StfsContainerDevice::LoadHostFiles() { const XContentContainerHeader* header = GetContainerHeader(); if (header->content_metadata.data_file_count > 0) { XELOGW("STFS container is not a single file. Loading might fail!"); } - files_.emplace(std::make_pair(0, header_file)); + data_ = MappedMemory::Open(host_path_, MappedMemory::Mode::kRead); + if (!data_) { + return Result::kOutOfMemory; + } + return Result::kSuccess; } StfsContainerDevice::Result StfsContainerDevice::Read() { - auto& file = files_.at(0); - - auto root_entry = new XContentContainerEntry(this, nullptr, "", &files_); + auto root_entry = new StfsContainerEntry(this, nullptr, "", data_.get()); root_entry->attributes_ = kFileAttributeDirectory; root_entry_ = std::unique_ptr(root_entry); - std::vector all_entries; + std::vector all_entries; // Load all listings. StfsDirectoryBlock directory; @@ -68,12 +66,7 @@ StfsContainerDevice::Result StfsContainerDevice::Read() { size_t n = 0; for (n = 0; n < descriptor.file_table_block_count; n++) { const size_t offset = BlockToOffset(table_block_index); - xe::filesystem::Seek(file, offset, SEEK_SET); - - if (fread(&directory, sizeof(StfsDirectoryBlock), 1, file) != 1) { - XELOGE("ReadSTFS failed to read directory block at 0x{X}", offset); - return Result::kReadError; - } + directory = *reinterpret_cast(data_->data() + offset); for (size_t m = 0; m < kEntriesPerDirectoryBlock; m++) { const StfsDirectoryEntry& dir_entry = directory.entries[m]; @@ -83,13 +76,13 @@ StfsContainerDevice::Result StfsContainerDevice::Read() { break; } - XContentContainerEntry* parent_entry = + StfsContainerEntry* parent_entry = dir_entry.directory_index == 0xFFFF ? root_entry : all_entries[dir_entry.directory_index]; - std::unique_ptr entry = - ReadEntry(parent_entry, &files_, &dir_entry); + std::unique_ptr entry = + ReadEntry(parent_entry, &dir_entry); all_entries.push_back(entry.get()); parent_entry->children_.emplace_back(std::move(entry)); } @@ -110,9 +103,8 @@ StfsContainerDevice::Result StfsContainerDevice::Read() { return Result::kSuccess; } -std::unique_ptr StfsContainerDevice::ReadEntry( - Entry* parent, MultiFileHandles* files, - const StfsDirectoryEntry* dir_entry) { +std::unique_ptr StfsContainerDevice::ReadEntry( + Entry* parent, const StfsDirectoryEntry* dir_entry) { // Filename is stored as Windows-1252, convert it to UTF-8. std::string ansi_name(reinterpret_cast(dir_entry->name), dir_entry->flags.name_length & 0x3F); @@ -123,7 +115,7 @@ std::unique_ptr StfsContainerDevice::ReadEntry( name = ansi_name; } - auto entry = XContentContainerEntry::Create(this, parent, name, &files_); + auto entry = StfsContainerEntry::Create(this, parent, name, data_.get()); if (dir_entry->flags.directory) { entry->attributes_ = kFileAttributeDirectory; @@ -253,15 +245,8 @@ void StfsContainerDevice::UpdateCachedHashTable( const size_t hash_offset = BlockToHashBlockOffset(block_index, hash_level); // Do nothing. It's already there. if (!cached_hash_tables_.count(hash_offset)) { - auto& file = files_.at(0); - xe::filesystem::Seek(file, hash_offset + secondary_table_offset, SEEK_SET); - StfsHashTable table; - if (fread(&table, sizeof(StfsHashTable), 1, file) != 1) { - XELOGE("GetBlockHash failed to read level{} hash table at 0x{:08X}", - hash_level, hash_offset + secondary_table_offset); - return; - } - cached_hash_tables_[hash_offset] = table; + cached_hash_tables_[hash_offset] = *reinterpret_cast( + data_->data() + hash_offset + secondary_table_offset); } uint32_t record = block_index % kBlocksPerHashLevel[0]; @@ -283,8 +268,6 @@ void StfsContainerDevice::UpdateCachedHashTables( } const StfsHashEntry* StfsContainerDevice::GetBlockHash(uint32_t block_index) { - auto& file = files_.at(0); - const StfsVolumeDescriptor& descriptor = header_->content_metadata.volume_descriptor.stfs; diff --git a/src/xenia/vfs/devices/xcontent_devices/stfs_container_device.h b/src/xenia/vfs/devices/xcontent_devices/stfs_container_device.h index 828e00921..3e94f0c09 100644 --- a/src/xenia/vfs/devices/xcontent_devices/stfs_container_device.h +++ b/src/xenia/vfs/devices/xcontent_devices/stfs_container_device.h @@ -10,15 +10,12 @@ #ifndef XENIA_VFS_DEVICES_XCONTENT_DEVICES_STFS_CONTAINER_DEVICE_H_ #define XENIA_VFS_DEVICES_XCONTENT_DEVICES_STFS_CONTAINER_DEVICE_H_ -#include #include -#include "xenia/base/string_util.h" #include "xenia/kernel/util/xex2_info.h" -#include "xenia/vfs/device.h" #include "xenia/vfs/devices/stfs_xbox.h" #include "xenia/vfs/devices/xcontent_container_device.h" -#include "xenia/vfs/devices/xcontent_container_entry.h" +#include "xenia/vfs/devices/xcontent_devices/stfs_container_entry.h" namespace xe { namespace vfs { @@ -61,12 +58,11 @@ class StfsContainerDevice : public XContentContainerDevice { kBlockSize / sizeof(StfsDirectoryEntry); void SetupContainer() override; - Result LoadHostFiles(FILE* header_file) override; + Result LoadHostFiles() override; Result Read() override; - std::unique_ptr ReadEntry( - Entry* parent, MultiFileHandles* files, - const StfsDirectoryEntry* dir_entry); + std::unique_ptr ReadEntry( + Entry* parent, const StfsDirectoryEntry* dir_entry); size_t BlockToOffset(uint64_t block_index) const; uint32_t BlockToHashBlockNumber(uint32_t block_index, @@ -87,6 +83,7 @@ class StfsContainerDevice : public XContentContainerDevice { uint32_t block_step_[2]; std::unordered_map cached_hash_tables_; + std::unique_ptr data_; }; } // namespace vfs diff --git a/src/xenia/vfs/devices/xcontent_devices/stfs_container_entry.cc b/src/xenia/vfs/devices/xcontent_devices/stfs_container_entry.cc new file mode 100644 index 000000000..7e90d7ef3 --- /dev/null +++ b/src/xenia/vfs/devices/xcontent_devices/stfs_container_entry.cc @@ -0,0 +1,40 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2025 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/vfs/devices/xcontent_devices/stfs_container_entry.h" +#include "xenia/vfs/devices/xcontent_devices/stfs_container_file.h" + +namespace xe { +namespace vfs { + +StfsContainerEntry::StfsContainerEntry(Device* device, Entry* parent, + const std::string_view path, + MappedMemory* data) + : XContentContainerEntry(device, parent, path), data_(data) {} + +StfsContainerEntry::~StfsContainerEntry() = default; + +std::unique_ptr StfsContainerEntry::Create( + Device* device, Entry* parent, const std::string_view name, + MappedMemory* data) { + auto path = xe::utf8::join_guest_paths(parent->path(), name); + auto entry = std::make_unique(device, parent, path, data); + + return std::move(entry); +} + +X_STATUS StfsContainerEntry::Open(uint32_t desired_access, File** out_file) { + *out_file = new StfsContainerFile(desired_access, this); + return X_STATUS_SUCCESS; +} + +bool StfsContainerEntry::DeleteEntryInternal(Entry* entry) { return false; } + +} // namespace vfs +} // namespace xe \ No newline at end of file diff --git a/src/xenia/vfs/devices/xcontent_devices/stfs_container_entry.h b/src/xenia/vfs/devices/xcontent_devices/stfs_container_entry.h new file mode 100644 index 000000000..5c6d32571 --- /dev/null +++ b/src/xenia/vfs/devices/xcontent_devices/stfs_container_entry.h @@ -0,0 +1,42 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2025 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_VFS_DEVICES_XCONTENT_STFS_CONTAINER_ENTRY_H_ +#define XENIA_VFS_DEVICES_XCONTENT_STFS_CONTAINER_ENTRY_H_ + +#include "xenia/vfs/devices/xcontent_container_entry.h" + +namespace xe { +namespace vfs { + +class StfsContainerEntry : public XContentContainerEntry { + public: + StfsContainerEntry(Device* device, Entry* parent, const std::string_view path, + MappedMemory* data); + ~StfsContainerEntry() override; + + static std::unique_ptr Create(Device* device, + Entry* parent, + const std::string_view name, + MappedMemory* data); + + MappedMemory* data() const { return data_; } + + X_STATUS Open(uint32_t desired_access, File** out_file) override; + + private: + bool DeleteEntryInternal(Entry* entry) override; + + MappedMemory* data_; +}; + +} // namespace vfs +} // namespace xe + +#endif // XENIA_VFS_DEVICES_XCONTENT_CONTAINER_ENTRY_H_ \ No newline at end of file diff --git a/src/xenia/vfs/devices/xcontent_devices/stfs_container_file.cc b/src/xenia/vfs/devices/xcontent_devices/stfs_container_file.cc new file mode 100644 index 000000000..fa31b3377 --- /dev/null +++ b/src/xenia/vfs/devices/xcontent_devices/stfs_container_file.cc @@ -0,0 +1,31 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2025 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/vfs/devices/xcontent_devices/stfs_container_file.h" +#include "xenia/vfs/devices/xcontent_devices/stfs_container_entry.h" + +namespace xe { +namespace vfs { + +StfsContainerFile::StfsContainerFile(uint32_t file_access, + StfsContainerEntry* entry) + : XContentContainerFile(file_access, entry), entry_(entry) {} + +StfsContainerFile::~StfsContainerFile() = default; + +void StfsContainerFile::Destroy() { delete this; } + +size_t StfsContainerFile::Read(std::span buffer, size_t offset, + size_t record_file) { + std::memcpy(buffer.data(), entry_->data()->data() + offset, buffer.size()); + return buffer.size(); +} + +} // namespace vfs +} // namespace xe \ No newline at end of file diff --git a/src/xenia/vfs/devices/xcontent_devices/stfs_container_file.h b/src/xenia/vfs/devices/xcontent_devices/stfs_container_file.h new file mode 100644 index 000000000..637355e81 --- /dev/null +++ b/src/xenia/vfs/devices/xcontent_devices/stfs_container_file.h @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2025 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_VFS_DEVICES_XCONTENT_STFS_CONTAINER_FILE_H_ +#define XENIA_VFS_DEVICES_XCONTENT_STFS_CONTAINER_FILE_H_ + +#include + +#include "xenia/vfs/devices/xcontent_container_file.h" +#include "xenia/vfs/file.h" + +#include "xenia/xbox.h" + +namespace xe { +namespace vfs { + +class StfsContainerEntry; + +class StfsContainerFile : public XContentContainerFile { + public: + StfsContainerFile(uint32_t file_access, StfsContainerEntry* entry); + ~StfsContainerFile() override; + + void Destroy() override; + + X_STATUS WriteSync(std::span buffer, size_t byte_offset, + size_t* out_bytes_written) override { + return X_STATUS_ACCESS_DENIED; + } + X_STATUS SetLength(size_t length) override { return X_STATUS_ACCESS_DENIED; } + + private: + size_t Read(std::span buffer, size_t offset, + size_t record_file) override; + + StfsContainerEntry* entry_; +}; + +} // namespace vfs +} // namespace xe + +#endif // XENIA_VFS_DEVICES_XCONTENT_CONTAINER_FILE_H_ diff --git a/src/xenia/vfs/devices/xcontent_devices/svod_container_device.cc b/src/xenia/vfs/devices/xcontent_devices/svod_container_device.cc index bf88cd31f..97a03bc65 100644 --- a/src/xenia/vfs/devices/xcontent_devices/svod_container_device.cc +++ b/src/xenia/vfs/devices/xcontent_devices/svod_container_device.cc @@ -7,13 +7,9 @@ ****************************************************************************** */ -#include -#include - -#include "xenia/base/logging.h" -#include "xenia/vfs/devices/xcontent_container_device.h" -#include "xenia/vfs/devices/xcontent_container_entry.h" #include "xenia/vfs/devices/xcontent_devices/svod_container_device.h" +#include "xenia/base/logging.h" +#include "xenia/vfs/devices/xcontent_devices/svod_container_entry.h" namespace xe { namespace vfs { @@ -26,10 +22,15 @@ SvodContainerDevice::SvodContainerDevice(const std::string_view mount_path, SetName("FATX"); } -SvodContainerDevice::~SvodContainerDevice() { CloseFiles(); } +SvodContainerDevice::~SvodContainerDevice() { + for (auto& file : files_) { + fclose(file.second); + } + files_.clear(); + files_total_size_ = 0; +} -SvodContainerDevice::Result SvodContainerDevice::LoadHostFiles( - FILE* header_file) { +SvodContainerDevice::Result SvodContainerDevice::LoadHostFiles() { std::filesystem::path data_fragment_path = host_path_; data_fragment_path += ".data"; if (!std::filesystem::exists(data_fragment_path)) { @@ -58,7 +59,7 @@ SvodContainerDevice::Result SvodContainerDevice::LoadHostFiles( auto file = xe::filesystem::OpenFile(path, "rb"); if (!file) { XELOGI("Failed to map SVOD file {}.", path); - CloseFiles(); + // CloseFiles(); return Result::kReadError; } @@ -100,7 +101,7 @@ XContentContainerDevice::Result SvodContainerDevice::Read() { const uint64_t root_creation_timestamp = decode_fat_timestamp(root_data.creation_date, root_data.creation_time); - auto root_entry = new XContentContainerEntry(this, nullptr, "", &files_); + auto root_entry = new SvodContainerEntry(this, nullptr, "", &files_); root_entry->attributes_ = kFileAttributeDirectory; root_entry->access_timestamp_ = root_creation_timestamp; root_entry->create_timestamp_ = root_creation_timestamp; @@ -112,7 +113,7 @@ XContentContainerDevice::Result SvodContainerDevice::Read() { } SvodContainerDevice::Result SvodContainerDevice::ReadEntry( - uint32_t block, uint32_t ordinal, XContentContainerEntry* parent) { + uint32_t block, uint32_t ordinal, SvodContainerEntry* parent) { // For games with a large amount of files, the ordinal offset can overrun // the current block and potentially hit a hash block. size_t ordinal_offset = ordinal * 0x4; @@ -184,7 +185,7 @@ SvodContainerDevice::Result SvodContainerDevice::ReadEntry( // NOTE: SVOD entries don't have timestamps for individual files, which can // cause issues when decrypting games. Using the root entry's timestamp // solves this issues. - auto entry = XContentContainerEntry::Create(this, parent, name, &files_); + auto entry = SvodContainerEntry::Create(this, parent, name, &files_); if (dir_entry.attributes & kFileAttributeDirectory) { // Entry is a directory entry->attributes_ = kFileAttributeDirectory | kFileAttributeReadOnly; diff --git a/src/xenia/vfs/devices/xcontent_devices/svod_container_device.h b/src/xenia/vfs/devices/xcontent_devices/svod_container_device.h index 41d236eca..a1b805f85 100644 --- a/src/xenia/vfs/devices/xcontent_devices/svod_container_device.h +++ b/src/xenia/vfs/devices/xcontent_devices/svod_container_device.h @@ -11,19 +11,14 @@ #define XENIA_VFS_DEVICES_XCONTENT_DEVICES_SVOD_CONTAINER_DEVICE_H_ #include -#include -#include -#include -#include "xenia/base/string_util.h" -#include "xenia/kernel/util/xex2_info.h" -#include "xenia/vfs/device.h" #include "xenia/vfs/devices/stfs_xbox.h" #include "xenia/vfs/devices/xcontent_container_device.h" -#include "xenia/vfs/devices/xcontent_container_entry.h" +#include "xenia/vfs/devices/xcontent_devices/svod_container_entry.h" namespace xe { namespace vfs { + class SvodContainerDevice : public XContentContainerDevice { public: SvodContainerDevice(const std::string_view mount_path, @@ -49,11 +44,11 @@ class SvodContainerDevice : public XContentContainerDevice { }; const char* MEDIA_MAGIC = "MICROSOFT*XBOX*MEDIA"; - Result LoadHostFiles(FILE* header_file) override; + Result LoadHostFiles() override; Result Read() override; Result ReadEntry(uint32_t sector, uint32_t ordinal, - XContentContainerEntry* parent); + SvodContainerEntry* parent); void BlockToOffset(size_t sector, size_t* address, size_t* file_index) const; Result SetLayout(FILE* header, size_t& magic_offset); @@ -69,6 +64,7 @@ class SvodContainerDevice : public XContentContainerDevice { size_t svod_base_offset_; SvodLayoutType svod_layout_; + MultiFileHandles files_; }; } // namespace vfs diff --git a/src/xenia/vfs/devices/xcontent_devices/svod_container_entry.cc b/src/xenia/vfs/devices/xcontent_devices/svod_container_entry.cc new file mode 100644 index 000000000..c9203dca6 --- /dev/null +++ b/src/xenia/vfs/devices/xcontent_devices/svod_container_entry.cc @@ -0,0 +1,41 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2025 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/vfs/devices/xcontent_devices/svod_container_entry.h" +#include "xenia/vfs/devices/xcontent_devices/svod_container_file.h" + +namespace xe { +namespace vfs { + +SvodContainerEntry::SvodContainerEntry(Device* device, Entry* parent, + const std::string_view path, + MultiFileHandles* files) + : XContentContainerEntry(device, parent, path), files_(files) {} + +SvodContainerEntry::~SvodContainerEntry() = default; + +std::unique_ptr SvodContainerEntry::Create( + Device* device, Entry* parent, const std::string_view name, + MultiFileHandles* files) { + auto path = xe::utf8::join_guest_paths(parent->path(), name); + auto entry = + std::make_unique(device, parent, path, files); + + return std::move(entry); +} + +X_STATUS SvodContainerEntry::Open(uint32_t desired_access, File** out_file) { + *out_file = new SvodContainerFile(desired_access, this); + return X_STATUS_SUCCESS; +} + +bool SvodContainerEntry::DeleteEntryInternal(Entry* entry) { return false; } + +} // namespace vfs +} // namespace xe \ No newline at end of file diff --git a/src/xenia/vfs/devices/xcontent_devices/svod_container_entry.h b/src/xenia/vfs/devices/xcontent_devices/svod_container_entry.h new file mode 100644 index 000000000..ff0b939a6 --- /dev/null +++ b/src/xenia/vfs/devices/xcontent_devices/svod_container_entry.h @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2025 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_VFS_DEVICES_XCONTENT_SVOD_CONTAINER_ENTRY_H_ +#define XENIA_VFS_DEVICES_XCONTENT_SVOD_CONTAINER_ENTRY_H_ + +#include + +#include "xenia/vfs/devices/xcontent_container_entry.h" +#include "xenia/vfs/file.h" + +namespace xe { +namespace vfs { +typedef std::map MultiFileHandles; + +class XContentContainerDevice; + +class SvodContainerEntry : public XContentContainerEntry { + public: + SvodContainerEntry(Device* device, Entry* parent, const std::string_view path, + MultiFileHandles* files); + ~SvodContainerEntry() override; + + static std::unique_ptr Create(Device* device, + Entry* parent, + const std::string_view name, + MultiFileHandles* files); + + MultiFileHandles* files() const { return files_; } + + X_STATUS Open(uint32_t desired_access, File** out_file) override; + + private: + bool DeleteEntryInternal(Entry* entry) override; + + MultiFileHandles* files_; +}; + +} // namespace vfs +} // namespace xe + +#endif // XENIA_VFS_DEVICES_XCONTENT_SVOD_CONTAINER_ENTRY_H_ \ No newline at end of file diff --git a/src/xenia/vfs/devices/xcontent_devices/svod_container_file.cc b/src/xenia/vfs/devices/xcontent_devices/svod_container_file.cc new file mode 100644 index 000000000..65e40a000 --- /dev/null +++ b/src/xenia/vfs/devices/xcontent_devices/svod_container_file.cc @@ -0,0 +1,32 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2025 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/vfs/devices/xcontent_devices/svod_container_file.h" +#include "xenia/vfs/devices/xcontent_devices/svod_container_entry.h" + +namespace xe { +namespace vfs { + +SvodContainerFile::SvodContainerFile(uint32_t file_access, + SvodContainerEntry* entry) + : XContentContainerFile(file_access, entry), entry_(entry) {} + +SvodContainerFile::~SvodContainerFile() = default; + +void SvodContainerFile::Destroy() { delete this; } + +size_t SvodContainerFile::Read(std::span buffer, size_t offset, + size_t record_file) { + auto& file = entry_->files()->at(record_file); + xe::filesystem::Seek(file, offset, SEEK_SET); + return fread(buffer.data(), 1, buffer.size(), file); +} + +} // namespace vfs +} // namespace xe \ No newline at end of file diff --git a/src/xenia/vfs/devices/xcontent_devices/svod_container_file.h b/src/xenia/vfs/devices/xcontent_devices/svod_container_file.h new file mode 100644 index 000000000..23e0d7825 --- /dev/null +++ b/src/xenia/vfs/devices/xcontent_devices/svod_container_file.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2025 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_VFS_DEVICES_XCONTENT_SVOD_CONTAINER_FILE_H_ +#define XENIA_VFS_DEVICES_XCONTENT_SVOD_CONTAINER_FILE_H_ + +#include "xenia/vfs/devices/xcontent_container_file.h" + +namespace xe { +namespace vfs { + +class SvodContainerEntry; + +class SvodContainerFile : public XContentContainerFile { + public: + SvodContainerFile(uint32_t file_access, SvodContainerEntry* entry); + ~SvodContainerFile() override; + + void Destroy() override; + + X_STATUS WriteSync(std::span buffer, size_t byte_offset, + size_t* out_bytes_written) override { + return X_STATUS_ACCESS_DENIED; + } + X_STATUS SetLength(size_t length) override { return X_STATUS_ACCESS_DENIED; } + + private: + size_t Read(std::span buffer, size_t offset, + size_t record_file) override; + + SvodContainerEntry* entry_; +}; + +} // namespace vfs +} // namespace xe + +#endif // XENIA_VFS_DEVICES_XCONTENT_SVOD_CONTAINER_FILE_H_ diff --git a/src/xenia/vfs/file.h b/src/xenia/vfs/file.h index 841a9ed6f..2bbe70fc0 100644 --- a/src/xenia/vfs/file.h +++ b/src/xenia/vfs/file.h @@ -11,6 +11,7 @@ #define XENIA_VFS_FILE_H_ #include +#include #include "xenia/xbox.h" @@ -27,20 +28,20 @@ class File { virtual void Destroy() = 0; - virtual X_STATUS ReadSync(void* buffer, size_t buffer_length, - size_t byte_offset, size_t* out_bytes_read) = 0; - virtual X_STATUS WriteSync(const void* buffer, size_t buffer_length, + virtual X_STATUS ReadSync(std::span buffer, size_t byte_offset, + size_t* out_bytes_read) = 0; + virtual X_STATUS WriteSync(std::span buffer, size_t byte_offset, size_t* out_bytes_written) = 0; // TODO: Parameters - virtual X_STATUS ReadAsync(void* buffer, size_t buffer_length, - size_t byte_offset, size_t* out_bytes_read) { + virtual X_STATUS ReadAsync(std::span buffer, size_t byte_offset, + size_t* out_bytes_read) { return X_STATUS_NOT_IMPLEMENTED; } // TODO: Parameters - virtual X_STATUS WriteAsync(const void* buffer, size_t buffer_length, - size_t byte_offset, size_t* out_bytes_written) { + virtual X_STATUS WriteAsync(std::span buffer, size_t byte_offset, + size_t* out_bytes_written) { return X_STATUS_NOT_IMPLEMENTED; } diff --git a/src/xenia/vfs/virtual_file_system.cc b/src/xenia/vfs/virtual_file_system.cc index b3b6b00cf..70a1d2771 100644 --- a/src/xenia/vfs/virtual_file_system.cc +++ b/src/xenia/vfs/virtual_file_system.cc @@ -391,7 +391,8 @@ X_STATUS VirtualFileSystem::ExtractContentFile(Entry* entry, while (remaining_size > 0) { size_t bytes_read = 0; - in_file->ReadSync(buffer, write_buffer_size, offset, &bytes_read); + in_file->ReadSync(std::span(buffer, write_buffer_size), offset, + &bytes_read); fwrite(buffer, bytes_read, 1, file); offset += bytes_read; remaining_size -= bytes_read;