Some fixes (#18686)

### FIXES + MINOR IMPROVEMENTS:
- Fixed issue18685: Not a real issue. PR18648 added some logging that made
evident a missing check on the validity of the paths in `games.yml`
before trying to manage the path as a possible ISO file. That missing
check was already present but simply invisible due to missing log
- Fixed `bytes_to_hex()` function used to store file hash hex string: In
some cases the integrity check wrongly reported the check as failed
- Optimized `fs::get_optical_raw_device()` function: Moved under
`_WIN32` block a check valid only on `Windows` and simplified the logic
to detect a CDROM / BD as raw device
- Used `iso_file` objects instead of `fs:file` in `ISO.cpp`: It allows
to use proper `bool()` operator on some checks
This commit is contained in:
Antonino Di Guardo
2026-05-07 05:38:57 +02:00
committed by GitHub
parent 4f47fee360
commit 026297334f
5 changed files with 39 additions and 48 deletions
+12 -30
View File
@@ -1125,13 +1125,6 @@ bool fs::is_optical_raw_device([[maybe_unused]] const std::string& path)
bool fs::get_optical_raw_device(const std::string& path, std::string* raw_device) bool fs::get_optical_raw_device(const std::string& path, std::string* raw_device)
{ {
// Skip a useless check to detect an optical raw device if navigating on subfolders (e.g. C:/subfolder_1/subfolder_2/), it means we are on a hdd/ssd.
// A path for an optical drive should include only the drive letter (e.g. E:/)
if (path.find_first_of(":") != path.find_last_not_of(delim))
{
return false;
}
if (fs::is_optical_raw_device(path)) if (fs::is_optical_raw_device(path))
{ {
if (raw_device) if (raw_device)
@@ -1143,38 +1136,27 @@ bool fs::get_optical_raw_device(const std::string& path, std::string* raw_device
} }
#ifdef _WIN32 #ifdef _WIN32
constexpr u32 BUF_SIZE = 1000; // Skip a useless check to detect an optical raw device if navigating on subfolders (e.g. C:\subfolder_1\subfolder_2\),
WCHAR drive_list[BUF_SIZE] = {0}; // it means we are on a HDD/SSD. A path for an optical drive should include only the drive letter (e.g. E:\)
const size_t drive_delim_pos = path.find_first_of(":");
// GetLogicalDriveStrings() returns a double-null terminated list of null-terminated strings. if (drive_delim_pos != 1 || drive_delim_pos != path.find_last_not_of(delim))
// E.g. A:\<nul>B:\<nul>C:\<nul><nul>
const DWORD copied = GetLogicalDriveStrings(BUF_SIZE, drive_list);
if (copied == 0 || copied > BUF_SIZE)
{ {
return false; return false;
} }
for (const WCHAR* drive = drive_list; drive && *drive; drive += wcslen(drive) + 1) const std::string drive_letter = path.substr(0, drive_delim_pos + 1); // e.g. "E:"
const std::string drive_path = drive_letter + "\\"; // e.g. "E:\"
if (GetDriveTypeA(drive_path.c_str()) == DRIVE_CDROM)
{ {
if (GetDriveType(drive) == DRIVE_CDROM) if (raw_device)
{ {
const std::wstring ws(drive); *raw_device = "\\\\.\\" + drive_letter;
const std::string s = std::string(ws.begin(), ws.end() - 1);
if (path.starts_with(s))
{
if (raw_device)
{
*raw_device = "\\\\.\\" + s;
}
return true;
}
} }
}
return false; return true;
}
#endif #endif
return false; return false;
} }
+8
View File
@@ -37,6 +37,14 @@ void bytes_to_hex(std::string& hex_str, const unsigned char* data, unsigned int
{ {
fmt::throw_exception("Failed to read bytes: %s", std::make_error_code(err).message()); fmt::throw_exception("Failed to read bytes: %s", std::make_error_code(err).message());
} }
// Padding handling for values < 0x10 (e.g. 0x05 becomes "5" instead of "05")
// If to_chars only writes 1 character, we move to the right and put '0'
if (ptr == &hex_str[i] + 1)
{
hex_str[i + 1] = hex_str[i];
hex_str[i] = '0';
}
} }
} }
+15 -14
View File
@@ -54,7 +54,7 @@ static void* get_aligned_buf()
return s_aligned_buf.buf; return s_aligned_buf.buf;
} }
static bool is_iso_file(const fs::file& file, u64* size = nullptr) static bool is_iso_file(iso_file& file, u64* size = nullptr)
{ {
if (!file || file.size() < 32768ULL + 6) if (!file || file.size() < 32768ULL + 6)
{ {
@@ -87,7 +87,7 @@ bool is_iso_file(const std::string& path, u64* size, bool* is_raw_device)
// "new_path" is updated with the raw device path in case "path" points to a BD drive // "new_path" is updated with the raw device path in case "path" points to a BD drive
const bool raw_device = fs::get_optical_raw_device(path, &new_path); const bool raw_device = fs::get_optical_raw_device(path, &new_path);
if (!raw_device && fs::is_dir(path)) if (!raw_device && !fs::is_file(path))
{ {
return false; return false;
} }
@@ -97,7 +97,7 @@ bool is_iso_file(const std::string& path, u64* size, bool* is_raw_device)
*is_raw_device = raw_device; *is_raw_device = raw_device;
} }
fs::file file(std::make_unique<iso_file>(new_path, fs::read)); iso_file file(new_path);
return is_iso_file(file, size); return is_iso_file(file, size);
} }
@@ -337,7 +337,7 @@ iso_type_status iso_file_decryption::retrieve_key(iso_archive& archive, std::str
return iso_type_status::ERROR_OPENING_KEY; return iso_type_status::ERROR_OPENING_KEY;
} }
iso_type_status iso_file_decryption::check_type(const std::string& path, std::string& key_path, aes_context* aes_ctx) iso_type_status iso_file_decryption::check_type(const std::string& path, std::string* key_path, aes_context* aes_ctx)
{ {
if (!is_iso_file(path)) if (!is_iso_file(path))
{ {
@@ -363,8 +363,12 @@ iso_type_status iso_file_decryption::check_type(const std::string& path, std::st
{ {
if (fs::is_file(path)) if (fs::is_file(path))
{ {
key_path = path; if (key_path)
return get_key(key_path, aes_ctx); {
*key_path = path;
}
return get_key(path, aes_ctx);
} }
} }
@@ -381,7 +385,7 @@ bool iso_file_decryption::init(const std::string& path, iso_archive* archive)
// Store the ISO region information (needed by both the "Redump" type (only on "decrypt()" method) and "3k3y" type) // Store the ISO region information (needed by both the "Redump" type (only on "decrypt()" method) and "3k3y" type)
// //
fs::file iso_file(std::make_unique<iso_file>(path, fs::read)); iso_file iso_file(path);
if (!is_iso_file(iso_file)) if (!is_iso_file(iso_file))
{ {
@@ -390,7 +394,7 @@ bool iso_file_decryption::init(const std::string& path, iso_archive* archive)
} }
// Reset the file position after it was changed by is_iso_file() // Reset the file position after it was changed by is_iso_file()
iso_file.seek(0); iso_file.seek(0, fs::seek_set);
std::array<u8, ISO_SECTOR_SIZE * 2> sec0_sec1; std::array<u8, ISO_SECTOR_SIZE * 2> sec0_sec1;
@@ -447,7 +451,7 @@ bool iso_file_decryption::init(const std::string& path, iso_archive* archive)
else else
{ {
// Try to detect the Redump type. If so, the decryption context is set into "m_aes_dec" // Try to detect the Redump type. If so, the decryption context is set into "m_aes_dec"
status = check_type(path, key_path, &m_aes_dec); status = check_type(path, &key_path, &m_aes_dec);
} }
switch (status) switch (status)
@@ -968,17 +972,14 @@ iso_archive::iso_archive(const std::string& path)
// "m_path" is updated with the raw device path in case "path" points to a BD drive // "m_path" is updated with the raw device path in case "path" points to a BD drive
fs::get_optical_raw_device(path, &m_path); fs::get_optical_raw_device(path, &m_path);
fs::file iso_file(std::make_unique<iso_file>(m_path, fs::read)); if (!is_iso_file(m_path))
if (!iso_file || !is_iso_file(iso_file))
{ {
// Not ISO... TODO: throw something? // Not ISO... TODO: throw something?
iso_log.error("iso_archive: Failed to recognize ISO file: '%s'", path); iso_log.error("iso_archive: Failed to recognize ISO file: '%s'", path);
return; return;
} }
// Reset the file position after it was changed by is_iso_file() fs::file iso_file(std::make_unique<iso_file>(m_path));
iso_file.seek(0);
u8 descriptor_type = -2; u8 descriptor_type = -2;
bool use_ucs2_decoding = false; bool use_ucs2_decoding = false;
+3 -2
View File
@@ -71,7 +71,7 @@ private:
static iso_type_status retrieve_key(iso_archive& archive, std::string& key_path, aes_context& aes_ctx); static iso_type_status retrieve_key(iso_archive& archive, std::string& key_path, aes_context& aes_ctx);
public: public:
static iso_type_status check_type(const std::string& path, std::string& key_path, aes_context* aes_ctx = nullptr); static iso_type_status check_type(const std::string& path, std::string* key_path = nullptr, aes_context* aes_ctx = nullptr);
iso_encryption_type get_enc_type() const { return m_enc_type; } iso_encryption_type get_enc_type() const { return m_enc_type; }
@@ -116,7 +116,7 @@ protected:
u64 file_offset(u64 pos) const; u64 file_offset(u64 pos) const;
public: public:
iso_file(const std::string& path, bs_t<fs::open_mode> mode); iso_file(const std::string& path, bs_t<fs::open_mode> mode = fs::read);
iso_file(const std::string& path, bs_t<fs::open_mode> mode, const iso_fs_node& node); iso_file(const std::string& path, bs_t<fs::open_mode> mode, const iso_fs_node& node);
explicit operator bool() const { return m_file.operator bool(); } explicit operator bool() const { return m_file.operator bool(); }
@@ -173,6 +173,7 @@ public:
const std::string& path() const { return m_path; } const std::string& path() const { return m_path; }
const iso_fs_node& root() const { return m_root; } const iso_fs_node& root() const { return m_root; }
iso_fs_node* retrieve(const std::string& path); iso_fs_node* retrieve(const std::string& path);
bool exists(const std::string& path); bool exists(const std::string& path);
bool is_file(const std::string& path); bool is_file(const std::string& path);
+1 -2
View File
@@ -605,8 +605,7 @@ void game_list_context_menu::show_single_selection_context_menu(const game_info&
// Check integrity // Check integrity
if (QString::fromStdString(current_game.category) == cat::cat_disc_game) if (QString::fromStdString(current_game.category) == cat::cat_disc_game)
{ {
std::string key_path; const iso_type_status iso_type = iso_file_decryption::check_type(current_game.path);
const iso_type_status iso_type = iso_file_decryption::check_type(current_game.path, key_path);
// If it's an ISO file (e.g. even a decrypted ISO), always provide the entry on the context menu but disable // If it's an ISO file (e.g. even a decrypted ISO), always provide the entry on the context menu but disable
// it if the ISO does not support integrity check (e.g. non Redump ISO) or no integrity DB is found. // it if the ISO does not support integrity check (e.g. non Redump ISO) or no integrity DB is found.