Qt: ISO clean up
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.7, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.7, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.7, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.7, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang (win64, clang, clang64) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run

Should fix some potential Qt bugs as well
This commit is contained in:
Megamouse 2025-12-16 21:08:08 +01:00
parent be77083a2b
commit 19129eddd7
14 changed files with 191 additions and 196 deletions

View file

@ -1296,6 +1296,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
m_path_old = m_path;
resolve_path_as_vfs_path = true;
if (launching_from_disc_archive)
{
load_iso(disc_info);
@ -1636,13 +1637,13 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
}
// ISO PKG INSTALL HACK!
if (fs::is_dir(m_path) && launching_from_disc_archive)
if (launching_from_disc_archive && fs::is_dir(m_path))
{
bdvd_dir = m_path;
}
// Special boot mode (directory scan)
if (fs::is_dir(m_path) && !launching_from_disc_archive)
if (!launching_from_disc_archive && fs::is_dir(m_path))
{
m_state = system_state::ready;
GetCallbacks().on_ready();
@ -2142,7 +2143,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
// ISO has no USRDIR/EBOOT.BIN, and we've examined its PKGDIR and extras.
// time to wrap up
if (fs::is_dir(m_path) && launching_from_disc_archive)
if (launching_from_disc_archive && fs::is_dir(m_path))
{
return game_boot_result::nothing_to_boot;
}
@ -2255,8 +2256,8 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
// Check game updates
if (const std::string hdd0_boot = hdd0_game + m_title_id + "/USRDIR/EBOOT.BIN"; !m_ar
&& recursion_count == 0 && disc.empty() && !bdvd_dir.empty() && !m_title_id.empty()
&& (resolved_path == GetCallbacks().resolve_path(vfs::get("/dev_bdvd/PS3_GAME/USRDIR/EBOOT.BIN"))
|| launching_from_disc_archive)
&& (launching_from_disc_archive ||
resolved_path == GetCallbacks().resolve_path(vfs::get("/dev_bdvd/PS3_GAME/USRDIR/EBOOT.BIN")))
&& resolved_path != GetCallbacks().resolve_path(hdd0_boot) && fs::is_file(hdd0_boot)
&& ppu_exec == elf_error::ok)
{
@ -2367,7 +2368,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
else if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
{
// Disc games are on /dev_bdvd/
std::string disc_path = !launching_from_disc_archive ? resolved_path : m_path;
const std::string& disc_path = !launching_from_disc_archive ? resolved_path : m_path;
const usz pos = disc_path.rfind(m_game_dir);
argv[0] = "/dev_bdvd/PS3_GAME/" + unescape(disc_path.substr(pos + m_game_dir.size() + 1));
m_dir = "/dev_bdvd/PS3_GAME/";
@ -3622,13 +3623,13 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
// Game mounted from archive
if (m_path.starts_with(iso_device::virtual_device_name + "/"))
{
auto device = fs::get_virtual_device(iso_device::virtual_device_name + "/");
const auto device = fs::get_virtual_device(iso_device::virtual_device_name + "/");
ensure(device);
auto iso_device = dynamic_cast<class iso_device*>(device.get());
const auto iso_dev = dynamic_cast<const iso_device*>(device.get());
ar(m_path.substr(iso_device::virtual_device_name.size() + 1));
ar(iso_device->get_loaded_iso());
ar(iso_dev->get_loaded_iso());
}
else if (auto dir = vfs::get("/dev_bdvd/PS3_GAME"); fs::is_dir(dir) && !fs::is_file(fs::get_parent_dir(dir) + "/PS3_DISC.SFB"))
{
@ -4245,9 +4246,9 @@ game_boot_result Emulator::AddGameToYml(const std::string& path)
// Load PARAM.SFO
const std::string elf_dir = fs::get_parent_dir(path);
std::string sfo_dir = !archive ? rpcs3::utils::get_sfo_dir_from_game_path(fs::get_parent_dir(elf_dir)) : "PS3_GAME";
std::string sfo_dir = archive ? "PS3_GAME" : rpcs3::utils::get_sfo_dir_from_game_path(fs::get_parent_dir(elf_dir));
const std::string sfo_path = sfo_dir + "/PARAM.SFO";
const psf::registry _psf = !archive ? psf::load_object(sfo_path) : archive->open_psf(sfo_path);
const psf::registry _psf = archive ? archive->open_psf(sfo_path) : psf::load_object(sfo_path);
const std::string title_id = std::string(psf::get_string(_psf, "TITLE_ID"));
const std::string cat = std::string(psf::get_string(_psf, "CATEGORY"));

View file

@ -48,11 +48,11 @@ games_config::result games_config::add_game(const std::string& key, const std::s
{
if (path == iso_device::virtual_device_name + "/")
{
auto device = fs::get_virtual_device(iso_device::virtual_device_name + "/");
const auto device = fs::get_virtual_device(iso_device::virtual_device_name + "/");
if (!device) return result::failure;
auto iso_device = dynamic_cast<class iso_device*>(device.get());
return add_game(key, iso_device->get_loaded_iso());
const auto iso_dev = dynamic_cast<const iso_device*>(device.get());
return add_game(key, iso_dev->get_loaded_iso());
}
std::lock_guard lock(m_mutex);

View file

@ -11,6 +11,7 @@
bool is_file_iso(const std::string& path)
{
if (path.empty()) return false;
if (fs::is_dir(path)) return false;
return is_file_iso(fs::file(path));
@ -55,14 +56,14 @@ inline T read_both_endian_int(fs::file& file)
// assumed that directory_entry is at file head
std::optional<iso_fs_metadata> iso_read_directory_entry(fs::file& file, bool names_in_ucs2 = false)
{
auto start_pos = file.pos();
u8 entry_length = file.read<u8>();
const auto start_pos = file.pos();
const u8 entry_length = file.read<u8>();
if (entry_length == 0) return std::nullopt;
file.seek(1, fs::seek_cur);
u32 start_sector = read_both_endian_int<u32>(file);
u32 file_size = read_both_endian_int<u32>(file);
const u32 start_sector = read_both_endian_int<u32>(file);
const u32 file_size = read_both_endian_int<u32>(file);
std::tm file_date = {};
file_date.tm_year = file.read<u8>();
@ -71,20 +72,20 @@ std::optional<iso_fs_metadata> iso_read_directory_entry(fs::file& file, bool nam
file_date.tm_hour = file.read<u8>();
file_date.tm_min = file.read<u8>();
file_date.tm_sec = file.read<u8>();
s16 timezone_value = file.read<u8>();
s16 timezone_offset = (timezone_value - 50) * 15 * 60;
const s16 timezone_value = file.read<u8>();
const s16 timezone_offset = (timezone_value - 50) * 15 * 60;
std::time_t date_time = std::mktime(&file_date) + timezone_offset;
const std::time_t date_time = std::mktime(&file_date) + timezone_offset;
u8 flags = file.read<u8>();
const u8 flags = file.read<u8>();
// 2nd flag bit indicates whether a given fs node is a directory
bool is_directory = flags & 0b00000010;
bool has_more_extents = flags & 0b10000000;
const bool is_directory = flags & 0b00000010;
const bool has_more_extents = flags & 0b10000000;
file.seek(6, fs::seek_cur);
u8 file_name_length = file.read<u8>();
const u8 file_name_length = file.read<u8>();
std::string file_name;
file.read(file_name, file_name_length);
@ -99,10 +100,10 @@ std::optional<iso_fs_metadata> iso_read_directory_entry(fs::file& file, bool nam
}
else if (names_in_ucs2) // for strings in joliet descriptor
{
std::string new_file_name = "";
std::string new_file_name;
int read = 0;
const u8* raw_str = reinterpret_cast<const u8*>(file_name.c_str());
while(read < file_name_length)
while (read < file_name_length)
{
// characters are stored in big endian format.
const u16 upper = raw_str[read];
@ -134,7 +135,7 @@ std::optional<iso_fs_metadata> iso_read_directory_entry(fs::file& file, bool nam
return iso_fs_metadata
{
.name = file_name,
.name = std::move(file_name),
.time = date_time,
.is_directory = is_directory,
.has_multiple_extents = has_more_extents,
@ -149,26 +150,25 @@ std::optional<iso_fs_metadata> iso_read_directory_entry(fs::file& file, bool nam
};
}
void iso_form_hierarchy(fs::file& file, iso_fs_node& node,
bool use_ucs2_decoding = false, std::string parent_path = "")
void iso_form_hierarchy(fs::file& file, iso_fs_node& node, bool use_ucs2_decoding = false, const std::string& parent_path = "")
{
if (!node.metadata.is_directory) return;
std::vector<int> multi_extent_node_indices;
std::vector<usz> multi_extent_node_indices;
// assuming the directory spans a single extent
const auto& directory_extent = node.metadata.extents[0];
file.seek(directory_extent.start * ISO_BLOCK_SIZE);
u64 end_pos = directory_extent.size + (directory_extent.start * ISO_BLOCK_SIZE);
const u64 end_pos = directory_extent.size + (directory_extent.start * ISO_BLOCK_SIZE);
while(file.pos() < end_pos)
{
auto entry = iso_read_directory_entry(file, use_ucs2_decoding);
if (!entry)
{
u64 new_sector = (file.pos() / ISO_BLOCK_SIZE) + 1;
const u64 new_sector = (file.pos() / ISO_BLOCK_SIZE) + 1;
file.seek(new_sector * ISO_BLOCK_SIZE);
continue;
}
@ -176,10 +176,10 @@ void iso_form_hierarchy(fs::file& file, iso_fs_node& node,
bool extent_added = false;
// find previous extent and merge into it, otherwise we push this node's index
for (int index : multi_extent_node_indices)
for (usz index : multi_extent_node_indices)
{
auto& selected_node = node.children.at(index);
if (selected_node->metadata.name.compare(entry->name) == 0)
auto& selected_node = ::at32(node.children, index);
if (selected_node->metadata.name == entry->name)
{
// merge into selected_node
selected_node->metadata.extents.push_back(entry->extents[0]);
@ -197,7 +197,7 @@ void iso_form_hierarchy(fs::file& file, iso_fs_node& node,
}
node.children.push_back(std::make_unique<iso_fs_node>(iso_fs_node{
.metadata = *entry
.metadata = std::move(*entry)
}));
}
@ -237,7 +237,7 @@ iso_archive::iso_archive(const std::string& path)
do
{
auto descriptor_start = m_file.pos();
const auto descriptor_start = m_file.pos();
descriptor_type = m_file.read<u8>();
@ -257,7 +257,7 @@ iso_archive::iso_archive(const std::string& path)
m_file.seek(descriptor_start + ISO_BLOCK_SIZE);
}
while(descriptor_type != 255);
while (descriptor_type != 255);
iso_form_hierarchy(m_file, m_root, use_ucs2_decoding);
}
@ -266,7 +266,7 @@ iso_fs_node* iso_archive::retrieve(const std::string& passed_path)
{
if (passed_path.empty()) return nullptr;
std::string path = std::filesystem::path(passed_path).string();
const std::string path = std::filesystem::path(passed_path).string();
size_t start = 0;
size_t end = path.find_first_of(fs::delim);
@ -277,14 +277,14 @@ iso_fs_node* iso_archive::retrieve(const std::string& passed_path)
do
{
if (search_stack.empty()) return nullptr;
auto* top_entry = search_stack.top();
const auto* top_entry = search_stack.top();
if (end == std::string::npos)
if (end == umax)
{
end = path.size();
}
auto path_component = path.substr(start, end-start);
const auto path_component = path.substr(start, end-start);
bool found = false;
@ -301,7 +301,7 @@ iso_fs_node* iso_archive::retrieve(const std::string& passed_path)
{
for (const auto& entry : top_entry->children)
{
if (entry->metadata.name.compare(path_component) == 0)
if (entry->metadata.name == path_component)
{
search_stack.push(entry.get());
@ -316,7 +316,7 @@ iso_fs_node* iso_archive::retrieve(const std::string& passed_path)
start = end + 1;
end = path.find_first_of(fs::delim, start);
}
while(start < path.size());
while (start < path.size());
if (search_stack.empty()) return nullptr;
@ -330,7 +330,7 @@ bool iso_archive::exists(const std::string& path)
bool iso_archive::is_file(const std::string& path)
{
auto file_node = retrieve(path);
const auto file_node = retrieve(path);
if (!file_node) return false;
return !file_node->metadata.is_directory;
@ -338,7 +338,7 @@ bool iso_archive::is_file(const std::string& path)
iso_file iso_archive::open(const std::string& path)
{
return iso_file(fs::file(m_path), *retrieve(path));
return iso_file(fs::file(m_path), *ensure(retrieve(path)));
}
psf::registry iso_archive::open_psf(const std::string& path)
@ -355,7 +355,7 @@ psf::registry iso_archive::open_psf(const std::string& path)
}
iso_file::iso_file(fs::file&& iso_handle, const iso_fs_node& node)
: m_file(std::move(iso_handle)), m_meta(node.metadata), m_pos(0)
: m_file(std::move(iso_handle)), m_meta(node.metadata)
{
m_file.seek(ISO_BLOCK_SIZE * node.metadata.extents[0].start);
}
@ -374,7 +374,7 @@ fs::stat_t iso_file::get_stat()
};
}
bool iso_file::trunc(u64)
bool iso_file::trunc(u64 /*length*/)
{
fs::g_tls_error = fs::error::readonly;
return false;
@ -382,9 +382,11 @@ bool iso_file::trunc(u64)
std::pair<u64, iso_extent_info> iso_file::get_extent_pos(u64 pos) const
{
ensure(!m_meta.extents.empty());
auto it = m_meta.extents.begin();
while(pos >= it->size && it != m_meta.extents.end() - 1)
while (pos >= it->size && it != m_meta.extents.end() - 1)
{
pos -= it->size;
@ -397,14 +399,14 @@ std::pair<u64, iso_extent_info> iso_file::get_extent_pos(u64 pos) const
// assumed valid and in bounds.
u64 iso_file::file_offset(u64 pos) const
{
auto [local_pos, extent] = get_extent_pos(pos);
const auto [local_pos, extent] = get_extent_pos(pos);
return (extent.start * ISO_BLOCK_SIZE) + local_pos;
}
u64 iso_file::local_extent_remaining(u64 pos) const
{
auto [local_pos, extent] = get_extent_pos(pos);
const auto [local_pos, extent] = get_extent_pos(pos);
return extent.size - local_pos;
}
@ -416,25 +418,22 @@ u64 iso_file::local_extent_size(u64 pos) const
u64 iso_file::read(void* buffer, u64 size)
{
auto r = read_at(m_pos, buffer, size);
const auto r = read_at(m_pos, buffer, size);
m_pos += r;
return r;
}
u64 iso_file::read_at(u64 offset, void* buffer, u64 size)
{
u64 local_remaining = local_extent_remaining(offset);
const u64 local_remaining = local_extent_remaining(offset);
u64 total_read = m_file.read_at(file_offset(offset), buffer, std::min(size, local_remaining));
const u64 total_read = m_file.read_at(file_offset(offset), buffer, std::min(size, local_remaining));
auto total_size = this->size();
const auto total_size = this->size();
if (size > total_read && (offset + total_read) < total_size)
{
u64 second_total_read = read_at(offset + total_read,
reinterpret_cast<u8*>(buffer) + total_read,
size - total_read
);
const u64 second_total_read = read_at(offset + total_read, reinterpret_cast<u8*>(buffer) + total_read, size - total_read);
return total_read + second_total_read;
}
@ -442,7 +441,7 @@ u64 iso_file::read_at(u64 offset, void* buffer, u64 size)
return total_read;
}
u64 iso_file::write(const void*, u64)
u64 iso_file::write(const void* /*buffer*/, u64 /*size*/)
{
fs::g_tls_error = fs::error::readonly;
return 0;
@ -462,10 +461,8 @@ u64 iso_file::seek(s64 offset, fs::seek_mode whence)
return -1;
}
const u64 bad_res = -1;
u64 result = m_file.seek(file_offset(m_pos));
if (result == bad_res) return -1;
const u64 result = m_file.seek(file_offset(m_pos));
if (result == umax) return umax;
m_pos = new_pos;
return m_pos;
@ -491,8 +488,7 @@ bool iso_dir::read(fs::dir_entry& entry)
{
if (m_pos < m_node.children.size())
{
auto& selected = m_node.children[m_pos].get()->metadata;
u64 size = selected.size();
const auto& selected = m_node.children[m_pos].get()->metadata;
entry.name = selected.name;
entry.atime = selected.time;
@ -501,7 +497,7 @@ bool iso_dir::read(fs::dir_entry& entry)
entry.is_directory = selected.is_directory;
entry.is_symlink = false;
entry.is_writable = false;
entry.size = size;
entry.size = selected.size();
m_pos++;
@ -513,25 +509,23 @@ bool iso_dir::read(fs::dir_entry& entry)
bool iso_device::stat(const std::string& path, fs::stat_t& info)
{
auto relative_path = std::filesystem::relative(std::filesystem::path(path),
std::filesystem::path(fs_prefix)).string();
const auto relative_path = std::filesystem::relative(std::filesystem::path(path), std::filesystem::path(fs_prefix)).string();
auto node = m_archive.retrieve(relative_path);
const auto node = m_archive.retrieve(relative_path);
if (!node)
{
fs::g_tls_error = fs::error::noent;
return false;
}
auto& meta = node->metadata;
u64 size = meta.size();
const auto& meta = node->metadata;
info = fs::stat_t
{
.is_directory = meta.is_directory,
.is_symlink = false,
.is_writable = false,
.size = size,
.size = meta.size(),
.atime = meta.time,
.mtime = meta.time,
.ctime = meta.time
@ -542,25 +536,24 @@ bool iso_device::stat(const std::string& path, fs::stat_t& info)
bool iso_device::statfs(const std::string& path, fs::device_stat& info)
{
auto relative_path = std::filesystem::relative(std::filesystem::path(path),
std::filesystem::path(fs_prefix)).string();
const auto relative_path = std::filesystem::relative(std::filesystem::path(path), std::filesystem::path(fs_prefix)).string();
auto node = m_archive.retrieve(relative_path);
const auto node = m_archive.retrieve(relative_path);
if (!node)
{
fs::g_tls_error = fs::error::noent;
return false;
}
auto& meta = node->metadata;
u64 size = meta.size();
const auto& meta = node->metadata;
const u64 size = meta.size();
info = fs::device_stat
{
.block_size=size,
.total_size=size,
.total_free=0,
.avail_free=0
.block_size = size,
.total_size = size,
.total_free = 0,
.avail_free = 0
};
return false;
@ -568,10 +561,9 @@ bool iso_device::statfs(const std::string& path, fs::device_stat& info)
std::unique_ptr<fs::file_base> iso_device::open(const std::string& path, bs_t<fs::open_mode> mode)
{
auto relative_path = std::filesystem::relative(std::filesystem::path(path),
std::filesystem::path(fs_prefix)).string();
const auto relative_path = std::filesystem::relative(std::filesystem::path(path), std::filesystem::path(fs_prefix)).string();
auto node = m_archive.retrieve(relative_path);
const auto node = m_archive.retrieve(relative_path);
if (!node)
{
fs::g_tls_error = fs::error::noent;
@ -589,10 +581,9 @@ std::unique_ptr<fs::file_base> iso_device::open(const std::string& path, bs_t<fs
std::unique_ptr<fs::dir_base> iso_device::open_dir(const std::string& path)
{
auto relative_path = std::filesystem::relative(std::filesystem::path(path),
std::filesystem::path(fs_prefix)).string();
const auto relative_path = std::filesystem::relative(std::filesystem::path(path), std::filesystem::path(fs_prefix)).string();
auto node = m_archive.retrieve(relative_path);
const auto node = m_archive.retrieve(relative_path);
if (!node)
{
fs::g_tls_error = fs::error::noent;
@ -618,14 +609,12 @@ void iso_dir::rewind()
void load_iso(const std::string& path)
{
fs::set_virtual_device("iso_overlay_fs_dev",
stx::make_shared<iso_device>(path));
fs::set_virtual_device("iso_overlay_fs_dev", stx::make_shared<iso_device>(path));
vfs::mount("/dev_bdvd/"sv, iso_device::virtual_device_name + "/");
}
void unload_iso()
{
fs::set_virtual_device("iso_overlay_fs_dev",
stx::shared_ptr<iso_device>());
fs::set_virtual_device("iso_overlay_fs_dev", stx::shared_ptr<iso_device>());
}

View file

@ -36,82 +36,86 @@ struct iso_fs_node
class iso_file : public fs::file_base
{
private:
fs::file m_file;
iso_fs_metadata m_meta;
u64 m_pos;
u64 m_pos = 0;
std::pair<u64, iso_extent_info> get_extent_pos(u64 pos) const;
u64 file_offset(u64 pos) const;
u64 local_extent_remaining(u64 pos) const;
u64 local_extent_size(u64 pos) const;
public:
iso_file(fs::file&& iso_handle, const iso_fs_node& node);
public:
iso_file(fs::file&& iso_handle, const iso_fs_node& node);
fs::stat_t get_stat() override;
bool trunc(u64 length) override;
u64 read(void* buffer, u64 size) override;
u64 read_at(u64 offset, void* buffer, u64 size) override;
u64 write(const void* buffer, u64 size) override;
u64 seek(s64 offset, fs::seek_mode whence) override;
u64 size() override;
fs::stat_t get_stat() override;
bool trunc(u64 length) override;
u64 read(void* buffer, u64 size) override;
u64 read_at(u64 offset, void* buffer, u64 size) override;
u64 write(const void* buffer, u64 size) override;
u64 seek(s64 offset, fs::seek_mode whence) override;
u64 size() override;
void release() override;
void release() override;
};
class iso_dir : public fs::dir_base
{
private:
const iso_fs_node& m_node;
u64 m_pos;
u64 m_pos = 0;
public:
iso_dir(const iso_fs_node& node)
: m_node(node), m_pos(0)
{}
public:
iso_dir(const iso_fs_node& node)
: m_node(node)
{}
bool read(fs::dir_entry&) override;
void rewind() override;
bool read(fs::dir_entry&) override;
void rewind() override;
};
// represents the .iso file itself.
class iso_archive
{
private:
std::string m_path;
iso_fs_node m_root;
fs::file m_file;
public:
iso_archive(const std::string& path);
public:
iso_archive(const std::string& path);
iso_fs_node* retrieve(const std::string& path);
bool exists(const std::string& path);
bool is_file(const std::string& path);
iso_fs_node* retrieve(const std::string& path);
bool exists(const std::string& path);
bool is_file(const std::string& path);
iso_file open(const std::string& path);
iso_file open(const std::string& path);
psf::registry open_psf(const std::string& path);
psf::registry open_psf(const std::string& path);
};
class iso_device : public fs::device_base
{
private:
iso_archive m_archive;
std::string iso_path;
public:
inline static std::string virtual_device_name = "/vfsv0_virtual_iso_overlay_fs_dev";
public:
inline static std::string virtual_device_name = "/vfsv0_virtual_iso_overlay_fs_dev";
iso_device(const std::string& iso_path, const std::string& device_name = virtual_device_name)
: m_archive(iso_path), iso_path(iso_path)
{
fs_prefix = device_name;
}
~iso_device() override = default;
iso_device(const std::string& iso_path, const std::string& device_name = virtual_device_name)
: m_archive(iso_path), iso_path(iso_path)
{
fs_prefix = device_name;
}
~iso_device() override = default;
const std::string& get_loaded_iso() const { return iso_path; }
const std::string& get_loaded_iso() const { return iso_path; }
bool stat(const std::string& path, fs::stat_t& info) override;
bool statfs(const std::string& path, fs::device_stat& info) override;
bool stat(const std::string& path, fs::stat_t& info) override;
bool statfs(const std::string& path, fs::device_stat& info) override;
std::unique_ptr<fs::file_base> open(const std::string& path, bs_t<fs::open_mode> mode) override;
std::unique_ptr<fs::dir_base> open_dir(const std::string& path) override;
std::unique_ptr<fs::file_base> open(const std::string& path, bs_t<fs::open_mode> mode) override;
std::unique_ptr<fs::dir_base> open_dir(const std::string& path) override;
};

View file

@ -49,14 +49,9 @@ void game_list_base::IconLoadFunction(game_info game, qreal device_pixel_ratio,
static std::unordered_set<std::string> warn_once_list;
static shared_mutex s_mtx;
if (game->icon.isNull() && (game->info.icon_path.empty() || !game->icon.load(QString::fromStdString(game->info.icon_path))))
if (game->icon.isNull() && !gui::utils::load_icon(game->icon, game->info.icon_path, game->icon_in_archive ? game->info.path : ""))
{
if (game->icon_in_archive)
{
game->icon_in_archive = gui::utils::load_icon(game->icon, game->info.icon_path, game->info.path);
}
if (!game->icon_in_archive && game_list_log.warning)
if (game_list_log.warning)
{
bool logged = false;
{

View file

@ -531,8 +531,7 @@ void game_list_frame::OnParsingFinished()
const auto file_exists = [&archive](const std::string& path)
{
if (!archive) return fs::is_file(path);
return archive->is_file(path);
return archive ? archive->is_file(path) : fs::is_file(path);
};
gui_game_info game{};
@ -540,10 +539,10 @@ void game_list_frame::OnParsingFinished()
const Localized thread_localized;
const std::string sfo_dir = !archive ? rpcs3::utils::get_sfo_dir_from_game_path(dir_or_elf) : "PS3_GAME";
const std::string sfo_dir = archive ? "PS3_GAME" : rpcs3::utils::get_sfo_dir_from_game_path(dir_or_elf);
const std::string sfo_path = sfo_dir + "/PARAM.SFO";
const psf::registry psf = !archive ? psf::load_object(sfo_path) : archive->open_psf(sfo_path);
const psf::registry psf = archive ? archive->open_psf(sfo_path) : psf::load_object(sfo_path);
const std::string_view title_id = psf::get_string(psf, "TITLE_ID", "");
if (title_id.empty())

View file

@ -4,6 +4,8 @@
#include "gui_settings.h"
#include "qt_utils.h"
#include "Loader/ISO.h"
#include <QApplication>
game_list_grid::game_list_grid()
@ -110,6 +112,11 @@ void game_list_grid::populate(
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam))
{
item->set_video_path(game->info.movie_path);
if (!fs::exists(game->info.movie_path) && is_file_iso(game->info.path))
{
item->set_iso_path(game->info.path);
}
}
if (selected_item_ids.contains(game->info.path + game->info.icon_path))

View file

@ -244,12 +244,6 @@ void game_list_table::populate(
custom_table_widget_item* icon_item = new custom_table_widget_item;
game->item = icon_item;
if (is_file_iso(game->info.path) && !game->info.movie_path.empty()
&& !fs::exists(game->info.movie_path))
{
icon_item->set_source_path(game->info.path);
}
icon_item->set_image_change_callback([this, icon_item, game](const QVideoFrame& frame)
{
if (!icon_item || !game)
@ -285,7 +279,7 @@ void game_list_table::populate(
// Do not report size of apps inside /dev_flash (it does not make sense to do so)
game->info.size_on_disk = 0;
}
else if(is_file_iso(game->info.path))
else if (is_file_iso(game->info.path))
{
fs::stat_t iso_stat;
fs::get_stat(game->info.path, iso_stat);
@ -308,6 +302,11 @@ void game_list_table::populate(
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam))
{
icon_item->set_video_path(game->info.movie_path);
if (!fs::exists(game->info.movie_path) && is_file_iso(game->info.path))
{
icon_item->set_iso_path(game->info.path);
}
}
icon_item->setData(Qt::UserRole, index, true);

View file

@ -546,9 +546,9 @@ void main_window::Boot(const std::string& path, const std::string& title_id, boo
std::string game_path = Emu.GetBoot();
if (game_path.starts_with(iso_device::virtual_device_name))
{
auto device = fs::get_virtual_device(iso_device::virtual_device_name + "/");
auto iso_device = dynamic_cast<class iso_device*>(device.get());
game_path = iso_device->get_loaded_iso();
const auto device = fs::get_virtual_device(iso_device::virtual_device_name + "/");
const auto iso_dev = ensure(dynamic_cast<const iso_device*>(device.get()));
game_path = iso_dev->get_loaded_iso();
}
gui_log.success("Boot successful.");

View file

@ -683,27 +683,28 @@ namespace gui
return QString("%1 days ago %2").arg(current_date - exctrated_date).arg(date.toString(fmt_relative));
}
bool load_icon(QPixmap& icon, const std::string& icon_path,
const std::string& archive_path)
bool load_icon(QPixmap& icon, const std::string& icon_path, const std::string& archive_path)
{
if (icon_path.empty()) return false;
if (archive_path.empty())
{
return icon.load(QString::fromStdString(icon_path));
}
if (!is_file_iso(archive_path)) return false;
iso_archive archive(archive_path);
if (!archive.exists(icon_path)) return false;
auto icon_file = archive.open(icon_path);
auto icon_size = icon_file.size();
const auto icon_size = icon_file.size();
if (icon_size == 0) return false;
QByteArray data(icon_size, 0);
icon_file.read(data.data(), icon_size);
QImage iconImage;
if (iconImage.loadFromData(data))
{
icon = QPixmap::fromImage(iconImage);
}
return true;
return icon.loadFromData(data);
}
QString format_timestamp(s64 time, const QString& fmt)

View file

@ -21,9 +21,9 @@ void qt_video_source::set_video_path(const std::string& video_path)
m_video_path = QString::fromStdString(video_path);
}
void qt_video_source::set_source_path(const std::string& source_path)
void qt_video_source::set_iso_path(const std::string& iso_path)
{
m_source_path = QString::fromStdString(source_path);
m_iso_path = iso_path;
}
void qt_video_source::set_active(bool active)
@ -62,7 +62,7 @@ void qt_video_source::init_movie()
return;
}
if (!m_image_change_callback || m_video_path.isEmpty() || (!QFile::exists(m_video_path) && m_source_path.isEmpty()))
if (!m_image_change_callback || m_video_path.isEmpty() || (m_iso_path.empty() && !QFile::exists(m_video_path)))
{
m_video_path.clear();
return;
@ -72,24 +72,24 @@ void qt_video_source::init_movie()
if (lower.endsWith(".gif"))
{
if (m_source_path.isEmpty())
if (m_iso_path.empty())
{
m_movie = std::make_unique<QMovie>(m_video_path);
m_video_path.clear();
}
else
{
iso_archive archive(m_source_path.toStdString());
iso_archive archive(m_iso_path);
auto movie_file = archive.open(m_video_path.toStdString());
auto movie_size = movie_file.size();
const auto movie_size = movie_file.size();
if (movie_size == 0) return;
m_video_data = QByteArray(movie_size, 0);
movie_file.read(m_video_data.data(), movie_size);
QBuffer buffer(&m_video_data);
buffer.open(QIODevice::ReadOnly);
m_movie = std::make_unique<QMovie>(&buffer);
m_video_buffer = std::make_unique<QBuffer>(&m_video_data);
m_video_buffer->open(QIODevice::ReadOnly);
m_movie = std::make_unique<QMovie>(m_video_buffer.get());
m_video_path.clear();
}
if (!m_movie->isValid())
@ -109,7 +109,7 @@ void qt_video_source::init_movie()
if (lower.endsWith(".pam"))
{
// We can't set PAM files as source of the video player, so we have to feed them as raw data.
if (m_source_path.isEmpty())
if (m_iso_path.empty())
{
QFile file(m_video_path);
if (!file.open(QFile::OpenModeFlag::ReadOnly))
@ -119,22 +119,26 @@ void qt_video_source::init_movie()
// TODO: Decode the pam properly before pushing it to the player
m_video_data = file.readAll();
if (m_video_data.isEmpty())
{
return;
}
}
else
{
auto source_path = m_source_path.toStdString();
auto video_path = m_video_path.toStdString();
iso_archive archive(source_path.c_str());
auto movie_file = archive.open(video_path);
auto movie_size = movie_file.size();
iso_archive archive(m_iso_path);
auto movie_file = archive.open(m_video_path.toStdString());
const auto movie_size = movie_file.size();
if (movie_size == 0)
{
return;
}
m_video_data = QByteArray(movie_size, 0);
movie_file.read(m_video_data.data(), movie_size);
}
if (m_video_data.isEmpty())
{
return;
}
m_video_buffer = std::make_unique<QBuffer>(&m_video_data);
m_video_buffer->open(QIODevice::ReadOnly);
}
@ -185,6 +189,7 @@ void qt_video_source::stop_movie()
if (m_movie)
{
m_movie->stop();
m_movie.reset();
}
m_video_sink.reset();

View file

@ -17,7 +17,7 @@ public:
qt_video_source();
virtual ~qt_video_source();
void set_source_path(const std::string& source_path);
void set_iso_path(const std::string& iso_path);
void set_video_path(const std::string& video_path) override;
const QString& video_path() const { return m_video_path; }
@ -44,7 +44,7 @@ protected:
atomic_t<bool> m_has_new = false;
QString m_video_path;
QString m_source_path; // path of the source archive
std::string m_iso_path; // path of the source archive
QByteArray m_video_data{};
QImage m_image{};
std::vector<u8> m_image_path;

View file

@ -418,10 +418,10 @@ void savestate_manager_dialog::ResizeGameIcons()
{
const qreal dpr = devicePixelRatioF();
const int savestate_index = item->data(GameUserRole::GameIndex).toInt();
const std::string icon_path = m_savestate_db[savestate_index]->game_icon_path;
const std::string archive_path = m_savestate_db[savestate_index]->archive_path;
std::string game_icon_path = m_savestate_db[savestate_index]->game_icon_path;
std::string game_archive_path = m_savestate_db[savestate_index]->archive_path;
item->set_icon_load_func([this, icon_path, archive_path, savestate_index, cancel = item->icon_loading_aborted(), dpr](int index)
item->set_icon_load_func([this, icon_path = std::move(game_icon_path), archive_path = std::move(game_archive_path), savestate_index, cancel = item->icon_loading_aborted(), dpr](int index)
{
if (cancel && cancel->load())
{
@ -434,13 +434,8 @@ void savestate_manager_dialog::ResizeGameIcons()
{
if (!item->data(GameUserRole::GamePixmapLoaded).toBool())
{
if (!archive_path.empty())
{
gui::utils::load_icon(icon, icon_path, archive_path);
}
// Load game icon
if (!icon.load(QString::fromStdString(icon_path)))
if (!gui::utils::load_icon(icon, icon_path, archive_path))
{
gui_log.warning("Could not load savestate game icon from path %s", icon_path);
}

View file

@ -649,9 +649,9 @@ void trophy_manager_dialog::ResizeGameIcons()
{
const qreal dpr = devicePixelRatioF();
const int trophy_index = item->data(GameUserRole::GameIndex).toInt();
const QString icon_path = QString::fromStdString(m_trophies_db[trophy_index]->path);
QString trophy_icon_path = QString::fromStdString(m_trophies_db[trophy_index]->path);
item->set_icon_load_func([this, icon_path, localized_icon, trophy_index, cancel = item->icon_loading_aborted(), dpr](int index)
item->set_icon_load_func([this, icon_path = std::move(trophy_icon_path), localized_icon, trophy_index, cancel = item->icon_loading_aborted(), dpr](int index)
{
if (cancel && cancel->load())
{