Files
annotations/Azaion.Common/Services/HashExtensions.cs
T
Oleksandr Bezdieniezhnykh fd95d2ba2c add MediaHash. Step1
2025-11-17 07:46:05 +02:00

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];
}
}