diff --git a/rpcs3/Loader/ISO.cpp b/rpcs3/Loader/ISO.cpp index fb74b14f74..12d03f0273 100644 --- a/rpcs3/Loader/ISO.cpp +++ b/rpcs3/Loader/ISO.cpp @@ -38,19 +38,19 @@ bool is_file_iso(const fs::file& file) const int ISO_BLOCK_SIZE = 2048; template -inline T read_both_endian_int(fs::file& file) +inline T retrieve_endian_int(const u8* buf) { - T out; + T out {}; - if (std::endian::little == std::endian::native) + if constexpr (std::endian::little == std::endian::native) { - out = file.read(); - file.seek(sizeof(T), fs::seek_cur); + // first half = little-endian copy + std::memcpy(&out, buf, sizeof(T)); } else { - file.seek(sizeof(T), fs::seek_cur); - out = file.read(); + // second half = big-endian copy + std::memcpy(&out, buf + sizeof(T), sizeof(T)); } return out; @@ -64,41 +64,51 @@ static std::optional iso_read_directory_entry(fs::file& entry, if (entry_length == 0) return std::nullopt; - // Batch this set of file reads. This reduces overall time spent in iso_read_directory_entry by ~38% - constexpr usz read_size = 1 + 4 * sizeof(u32) + 8 + 6 + 1; - const std::array data = entry.read>(); - fs::file file(data.data(), data.size()); + // Batch this set of file reads. This reduces overall time spent in iso_read_directory_entry by ~41% +#pragma pack(push, 1) + struct entry_header + { + u8 padding; + std::array start_sector; + std::array file_size; + u8 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 timezone_value; + u8 flags; + std::array padding2; + u8 file_name_length; + }; +#pragma pack(pop) - file.seek(1, fs::seek_cur); - const u32 start_sector = read_both_endian_int(file); - const u32 file_size = read_both_endian_int(file); + const entry_header header = entry.read(); + + const u32 start_sector = retrieve_endian_int(header.start_sector.data()); + const u32 file_size = retrieve_endian_int(header.file_size.data()); std::tm file_date = {}; - file_date.tm_year = file.read(); - file_date.tm_mon = file.read() - 1; - file_date.tm_mday = file.read(); - file_date.tm_hour = file.read(); - file_date.tm_min = file.read(); - file_date.tm_sec = file.read(); - const s16 timezone_value = file.read(); + file_date.tm_year = header.year; + file_date.tm_mon = header.month - 1; + file_date.tm_mday = header.day; + file_date.tm_hour = header.hour; + file_date.tm_min = header.minute; + file_date.tm_sec = header.second; + const s16 timezone_value = header.timezone_value; const s16 timezone_offset = (timezone_value - 50) * 15 * 60; const std::time_t date_time = std::mktime(&file_date) + timezone_offset; - const u8 flags = file.read(); - // 2nd flag bit indicates whether a given fs node is a directory - const bool is_directory = flags & 0b00000010; - const bool has_more_extents = flags & 0b10000000; - - file.seek(6, fs::seek_cur); - - const u8 file_name_length = file.read(); + const bool is_directory = header.flags & 0b00000010; + const bool has_more_extents = header.flags & 0b10000000; std::string file_name; - entry.read(file_name, file_name_length); + entry.read(file_name, header.file_name_length); - if (file_name_length == 1 && file_name[0] == 0) + if (header.file_name_length == 1 && file_name[0] == 0) { file_name = "."; } @@ -110,7 +120,7 @@ static std::optional iso_read_directory_entry(fs::file& entry, { // characters are stored in big endian format. std::u16string utf16; - utf16.resize(file_name_length / 2); + utf16.resize(header.file_name_length / 2); const u16* raw = reinterpret_cast(file_name.data()); for (size_t i = 0; i < utf16.size(); ++i, raw++) @@ -126,7 +136,7 @@ static std::optional iso_read_directory_entry(fs::file& entry, file_name.erase(file_name.end() - 2, file_name.end()); } - if (file_name_length > 1 && file_name.ends_with(".")) + if (header.file_name_length > 1 && file_name.ends_with(".")) { file_name.pop_back(); }