AbstractSignatureDetector.cs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. using System.Reflection;
  2. using System.Runtime.InteropServices;
  3. using Masuit.Tools.Mime;
  4. namespace Masuit.Tools.Files.FileDetector;
  5. [StructLayout(LayoutKind.Sequential)]
  6. public record struct SignatureInformation : IEquatable<SignatureInformation>
  7. {
  8. /// <summary>
  9. ///
  10. /// </summary>
  11. public int Position{get;set;}
  12. /// <summary>
  13. ///
  14. /// </summary>
  15. public byte[] Signature{get;set;}
  16. /// <summary>
  17. ///
  18. /// </summary>
  19. public byte[] Presignature{get;set;}
  20. /// <summary>指示当前对象是否等于同一类型的另一个对象。</summary>
  21. /// <param name="other">一个与此对象进行比较的对象。</param>
  22. /// <returns>如果当前对象等于 <paramref name="other" /> 参数,则为 true;否则为 false。</returns>
  23. public bool Equals(SignatureInformation other)
  24. {
  25. return Position == other.Position && Signature.SequenceEqual(other.Signature) && Presignature.SequenceEqual(other.Presignature);
  26. }
  27. /// <summary>返回此实例的哈希代码。</summary>
  28. /// <returns>一个 32 位带符号整数,它是此实例的哈希代码。</returns>
  29. public override int GetHashCode()
  30. {
  31. unchecked
  32. {
  33. var hashCode = Position;
  34. hashCode = (hashCode * 397) ^ (Signature != null ? Signature.GetHashCode() : 0);
  35. hashCode = (hashCode * 397) ^ (Presignature != null ? Presignature.GetHashCode() : 0);
  36. return hashCode;
  37. }
  38. }
  39. }
  40. public abstract class AbstractSignatureDetector : IDetector
  41. {
  42. public abstract string Extension { get; }
  43. public virtual string Precondition => null;
  44. protected abstract SignatureInformation[] SignatureInformations { get; }
  45. public virtual string MimeType => new MimeMapper().GetMimeFromExtension("." + Extension);
  46. public virtual List<FormatCategory> FormatCategories => GetType().GetCustomAttributes<FormatCategoryAttribute>().Select(a => a.Category).ToList();
  47. private int _cachedLongestLength = -1;
  48. public virtual bool Detect(Stream stream)
  49. {
  50. if (_cachedLongestLength == -1)
  51. {
  52. foreach (var sig in SignatureInformations)
  53. {
  54. _cachedLongestLength = _cachedLongestLength < sig.Signature.Length ? sig.Signature.Length : _cachedLongestLength;
  55. }
  56. }
  57. byte[] buffer = new byte[_cachedLongestLength];
  58. byte[] preSignature = null;
  59. foreach (var siginfo in SignatureInformations.Where(si => CompareArray(si.Presignature, preSignature)).OrderBy(si => si.Position))
  60. {
  61. stream.Position = siginfo.Position;
  62. _ = stream.Read(buffer, 0, _cachedLongestLength);
  63. if (CompareArray(siginfo.Signature, buffer))
  64. {
  65. preSignature = siginfo.Signature;
  66. return true;
  67. }
  68. }
  69. return false;
  70. }
  71. private static bool CompareArray(byte[] a1, byte[] a2)
  72. {
  73. if (a1 == null && a2 == null)
  74. {
  75. return true;
  76. }
  77. if (a1 == null || a2 == null)
  78. {
  79. return false;
  80. }
  81. return a1.Zip(a2,(x, y) => (x,y)).All(t => t.x==t.y);
  82. }
  83. }