AbstractSignatureDetector.cs 3.6 KB

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