mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-27 16:15:41 +00:00
116 lines
3.5 KiB
C++
116 lines
3.5 KiB
C++
#include "cd_image_hasher.h"
|
|
#include "cd_image.h"
|
|
#include "md5_digest.h"
|
|
#include "string_util.h"
|
|
|
|
namespace CDImageHasher {
|
|
|
|
static bool ReadIndex(CDImage* image, u8 track, u8 index, MD5Digest* digest, ProgressCallback* progress_callback)
|
|
{
|
|
const CDImage::LBA index_start = image->GetTrackIndexPosition(track, index);
|
|
const u32 index_length = image->GetTrackIndexLength(track, index);
|
|
const u32 update_interval = std::max<u32>(index_length / 100u, 1u);
|
|
|
|
progress_callback->SetFormattedStatusText("Computing hash for track %u/index %u...", track, index);
|
|
progress_callback->SetProgressRange(index_length);
|
|
|
|
if (!image->Seek(index_start))
|
|
{
|
|
progress_callback->DisplayFormattedModalError("Failed to seek to sector %u for track %u index %u", index_start,
|
|
track, index);
|
|
return false;
|
|
}
|
|
|
|
std::array<u8, CDImage::RAW_SECTOR_SIZE> sector;
|
|
for (u32 lba = 0; lba < index_length; lba++)
|
|
{
|
|
if ((lba % update_interval) == 0)
|
|
progress_callback->SetProgressValue(lba);
|
|
|
|
if (!image->ReadRawSector(sector.data()))
|
|
{
|
|
progress_callback->DisplayFormattedModalError("Failed to read sector %u from image", image->GetPositionOnDisc());
|
|
return false;
|
|
}
|
|
|
|
digest->Update(sector.data(), static_cast<u32>(sector.size()));
|
|
}
|
|
|
|
progress_callback->SetProgressValue(index_length);
|
|
return true;
|
|
}
|
|
|
|
static bool ReadTrack(CDImage* image, u8 track, MD5Digest* digest, ProgressCallback* progress_callback)
|
|
{
|
|
static constexpr u8 INDICES_TO_READ = 2;
|
|
|
|
progress_callback->PushState();
|
|
|
|
progress_callback->SetProgressRange(2);
|
|
for (u8 index = 0; index < INDICES_TO_READ; index++)
|
|
{
|
|
progress_callback->SetProgressValue(index);
|
|
|
|
// skip index 0 if data track
|
|
if (index == 0 && image->GetTrackMode(track) != CDImage::TrackMode::Audio)
|
|
continue;
|
|
|
|
progress_callback->PushState();
|
|
if (!ReadIndex(image, track, index, digest, progress_callback))
|
|
{
|
|
progress_callback->PopState();
|
|
progress_callback->PopState();
|
|
return false;
|
|
}
|
|
|
|
progress_callback->PopState();
|
|
}
|
|
|
|
progress_callback->SetProgressValue(INDICES_TO_READ);
|
|
progress_callback->PopState();
|
|
return true;
|
|
}
|
|
|
|
std::string HashToString(const Hash& hash)
|
|
{
|
|
return StringUtil::StdStringFromFormat("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", hash[0],
|
|
hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8],
|
|
hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]);
|
|
}
|
|
|
|
bool GetImageHash(CDImage* image, Hash* out_hash,
|
|
ProgressCallback* progress_callback /*= ProgressCallback::NullProgressCallback*/)
|
|
{
|
|
MD5Digest digest;
|
|
|
|
progress_callback->SetProgressRange(image->GetTrackCount());
|
|
progress_callback->SetProgressValue(0);
|
|
progress_callback->PushState();
|
|
|
|
for (u32 i = 1; i <= image->GetTrackCount(); i++)
|
|
{
|
|
progress_callback->SetProgressValue(i - 1);
|
|
if (!ReadTrack(image, i, &digest, progress_callback))
|
|
{
|
|
progress_callback->PopState();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
progress_callback->SetProgressValue(image->GetTrackCount());
|
|
digest.Final(out_hash->data());
|
|
return true;
|
|
}
|
|
|
|
bool GetTrackHash(CDImage* image, u8 track, Hash* out_hash,
|
|
ProgressCallback* progress_callback /*= ProgressCallback::NullProgressCallback*/)
|
|
{
|
|
MD5Digest digest;
|
|
if (!ReadTrack(image, track, &digest, progress_callback))
|
|
return false;
|
|
|
|
digest.Final(out_hash->data());
|
|
return true;
|
|
}
|
|
|
|
} // namespace CDImageHasher
|