using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Masuit.Tools.Mime;
namespace Masuit.Tools.Files.FileDetector;
[StructLayout(LayoutKind.Sequential)]
public struct SignatureInformation
{
///
///
///
public int Position;
///
///
///
public byte[] Signature;
///
///
///
public byte[] Presignature;
}
public abstract class AbstractSignatureDetector : IDetector
{
public abstract string Extension { get; }
public virtual string Precondition => null;
protected abstract SignatureInformation[] SignatureInformations { get; }
public virtual string MimeType => new MimeMapper().GetMimeFromExtension("." + Extension);
public virtual List FormatCategories => GetType().GetCustomAttributes().Select(a => a.Category).ToList();
private int _cachedLongestLength = -1;
public virtual bool Detect(Stream stream)
{
if (_cachedLongestLength == -1)
{
foreach (var sig in SignatureInformations)
{
_cachedLongestLength = _cachedLongestLength < sig.Signature.Length ? sig.Signature.Length : _cachedLongestLength;
}
}
byte[] buffer = new byte[_cachedLongestLength];
byte[] preSignature = null;
bool correct = false;
while (true)
{
bool found = false;
foreach (var siginfo in SignatureInformations.Where(si => CompareArray(si.Presignature, preSignature)).OrderBy(si => si.Position))
{
correct = false;
stream.Position = siginfo.Position;
stream.Read(buffer, 0, _cachedLongestLength);
if (CompareArray(siginfo.Signature, buffer))
{
preSignature = siginfo.Signature;
correct = true;
found = true;
break;
}
}
if (!found)
{
break;
}
}
return correct;
}
private bool CompareArray(byte[] a1, byte[] a2)
{
if (a1 == null && a2 == null) return true;
if (a1 == null || a2 == null) return false;
bool failed = false;
int min = a1.Length > a2.Length ? a2.Length : a1.Length;
for (int i = 0; i < min; ++i)
{
if (a1[i] != a2[i])
{
failed = true;
break;
}
}
return !failed;
}
}