You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
3.1 KiB
93 lines
3.1 KiB
using System.Buffers; |
|
using System.Security.Cryptography; |
|
using Blake3; |
|
using StabilityMatrix.Core.Models.Progress; |
|
|
|
namespace StabilityMatrix.Core.Helper; |
|
|
|
public static class FileHash |
|
{ |
|
public static async Task<string> GetHashAsync(HashAlgorithm hashAlgorithm, Stream stream, byte[] buffer, Action<ulong>? progress = default) |
|
{ |
|
ulong totalBytesRead = 0; |
|
|
|
using (hashAlgorithm) |
|
{ |
|
int bytesRead; |
|
while ((bytesRead = await stream.ReadAsync(buffer)) != 0) |
|
{ |
|
totalBytesRead += (ulong) bytesRead; |
|
hashAlgorithm.TransformBlock(buffer, 0, bytesRead, null, 0); |
|
progress?.Invoke(totalBytesRead); |
|
} |
|
hashAlgorithm.TransformFinalBlock(buffer, 0, 0); |
|
var hash = hashAlgorithm.Hash; |
|
if (hash == null || hash.Length == 0) |
|
{ |
|
throw new InvalidOperationException("Hash algorithm did not produce a hash."); |
|
} |
|
return BitConverter.ToString(hash).Replace("-", string.Empty).ToLowerInvariant(); |
|
} |
|
} |
|
|
|
public static async Task<string> GetSha256Async(string filePath, IProgress<ProgressReport>? progress = default) |
|
{ |
|
if (!File.Exists(filePath)) |
|
{ |
|
throw new FileNotFoundException($"Could not find file: {filePath}"); |
|
} |
|
|
|
var totalBytes = Convert.ToUInt64(new FileInfo(filePath).Length); |
|
var shared = ArrayPool<byte>.Shared; |
|
var buffer = shared.Rent((int) FileTransfers.GetBufferSize(totalBytes)); |
|
try |
|
{ |
|
await using var stream = File.OpenRead(filePath); |
|
|
|
var hash = await GetHashAsync(SHA256.Create(), stream, buffer, totalBytesRead => |
|
{ |
|
progress?.Report(new ProgressReport(totalBytesRead, totalBytes, type: ProgressType.Hashing)); |
|
}).ConfigureAwait(false); |
|
return hash; |
|
} |
|
finally |
|
{ |
|
shared.Return(buffer); |
|
} |
|
|
|
} |
|
|
|
public static async Task<string> GetBlake3Async(string filePath, IProgress<ProgressReport>? progress = default) |
|
{ |
|
if (!File.Exists(filePath)) |
|
{ |
|
throw new FileNotFoundException($"Could not find file: {filePath}"); |
|
} |
|
|
|
var totalBytes = Convert.ToUInt64(new FileInfo(filePath).Length); |
|
var readBytes = 0ul; |
|
var shared = ArrayPool<byte>.Shared; |
|
var buffer = shared.Rent((int) FileTransfers.GetBufferSize(totalBytes)); |
|
try |
|
{ |
|
await using var stream = File.OpenRead(filePath); |
|
using var hasher = Hasher.New(); |
|
while (true) |
|
{ |
|
var bytesRead = await stream.ReadAsync(buffer); |
|
if (bytesRead == 0) |
|
{ |
|
break; |
|
} |
|
readBytes += (ulong) bytesRead; |
|
hasher.Update(buffer.AsSpan(0, bytesRead)); |
|
progress?.Report(new ProgressReport(readBytes, totalBytes)); |
|
} |
|
return hasher.Finalize().ToString(); |
|
} |
|
finally |
|
{ |
|
shared.Return(buffer); |
|
} |
|
} |
|
}
|
|
|