mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 12:06:31 +00:00
63 lines
2.0 KiB
C#
63 lines
2.0 KiB
C#
using System.IO;
|
|
using System.IO.Hashing;
|
|
using System.Text;
|
|
|
|
namespace Azaion.Common.Services;
|
|
|
|
public static class HashExtensions
|
|
{
|
|
private const int SampleSize = 1024;
|
|
private const int HashLength = 9;
|
|
private const string VirtualHashPrefix = "V";
|
|
|
|
public static string CalcHash(this FileInfo file)
|
|
{
|
|
if (!file.Exists)
|
|
return CalcVirtualHash(file.Name);
|
|
|
|
var fileSize = file.Length;
|
|
if (fileSize < SampleSize * 8)
|
|
return CalcHashInner(File.ReadAllBytes(file.FullName));
|
|
|
|
var combinedData = new byte[8 + SampleSize * 3];
|
|
var offset = 0;
|
|
|
|
var fileSizeBytes = BitConverter.GetBytes(fileSize);
|
|
Array.Copy(fileSizeBytes, 0, combinedData, offset, 8);
|
|
offset += 8;
|
|
|
|
using var stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
|
|
|
stream.ReadExactly(combinedData, offset, SampleSize);
|
|
offset += SampleSize;
|
|
|
|
stream.Position = (fileSize - SampleSize) / 2;
|
|
stream.ReadExactly(combinedData, offset, SampleSize);
|
|
offset += SampleSize;
|
|
|
|
stream.Position = fileSize - SampleSize;
|
|
stream.ReadExactly(combinedData, offset, SampleSize);
|
|
|
|
return CalcHashInner(combinedData);
|
|
}
|
|
|
|
public static string CalcVirtualHash(string filename)
|
|
{
|
|
var bytes = Encoding.UTF8.GetBytes($"VIRTUAL:{filename}");
|
|
var hash = XxHash64.HashToUInt64(bytes);
|
|
var hashBytes = BitConverter.GetBytes(hash);
|
|
var base64 = Convert.ToBase64String(hashBytes);
|
|
return VirtualHashPrefix + base64[..HashLength];
|
|
}
|
|
|
|
public static bool IsVirtualHash(this string? hash) =>
|
|
!string.IsNullOrEmpty(hash) && hash.StartsWith(VirtualHashPrefix);
|
|
|
|
private static string CalcHashInner(byte[] data)
|
|
{
|
|
var hash = XxHash64.HashToUInt64(data);
|
|
var hashBytes = BitConverter.GetBytes(hash);
|
|
var base64 = Convert.ToBase64String(hashBytes);
|
|
return base64[..HashLength];
|
|
}
|
|
} |