using System.Collections.Generic; using System.Linq; namespace System.IO.FileFormats { partial class FileFormat { /// /// 文件头标识(幻数) /// public static class MagicNumber { /// /// 对 MagicNumber 进行比较,以确定两个序列是否相等,如果某一个序列为 则返回 /// /// /// /// /// /// static bool SequenceEqual( IReadOnlyList first, IReadOnlyCollection second, Func equatable) { if (first == null || second == null) return false; if (first.Count < second.Count) return false; return !second.Where((t, i) => !equatable(first[i], t)).Any(); } static bool Equals(byte left, byte right) => left.Equals(right); static bool Equals(byte left, byte? right) => !right.HasValue || left.Equals(right); public static bool SequenceEqual(IReadOnlyList first, IReadOnlyCollection second) => SequenceEqual(first, second, Equals); public static bool SequenceEqual(IReadOnlyList first, IReadOnlyCollection second) => SequenceEqual(first, second, Equals); public static bool SequenceEqual(IReadOnlyList first, IEnumerable> seconds) => seconds.Any(second => SequenceEqual(first, second)); public static bool SequenceEqual(IReadOnlyList first, IEnumerable> seconds) => seconds.Any(second => SequenceEqual(first, second)); public static byte[] ReadHeaderBuffer(Stream stream, int length, bool resetPosition = true) { var currentPosition = stream.Position; if (currentPosition != 0) stream.Position = 0; byte[] result; if (stream.Length < length) { var buffer = new byte[stream.Length]; stream.Read(buffer, 0, buffer.Length); result = buffer; } else { var buffer = new byte[length]; stream.Read(buffer, 0, buffer.Length); result = buffer; } if (resetPosition) stream.Position = currentPosition; return result; } public static int GetLength(object magicNumber) { if (magicNumber is IReadOnlyCollection byteArray) { return byteArray.Count; } else if (magicNumber is IReadOnlyCollection byteArrayNullable) { return byteArrayNullable.Count; } else if (magicNumber is IEnumerable> byteArrayArray) { return byteArrayArray.Max(x => x.Count); } else if (magicNumber is IEnumerable> byteArrayArrayNullable) { return byteArrayArrayNullable.Max(x => x.Count); } else { throw new ArgumentOutOfRangeException(nameof(magicNumber), "type mismatch."); } } public static bool Match(object magicNumber, IReadOnlyList? buffer, Stream? stream) { bool result; if (magicNumber is IReadOnlyCollection byteArray) { if (buffer == null) { if (stream == null) goto null_ex; buffer = ReadHeaderBuffer(stream, byteArray.Count); } result = SequenceEqual(buffer, byteArray); } else if (magicNumber is IReadOnlyCollection byteArrayNullable) { if (buffer == null) { if (stream == null) goto null_ex; buffer = ReadHeaderBuffer(stream, byteArrayNullable.Count); } result = SequenceEqual(buffer, byteArrayNullable); } else if (magicNumber is IEnumerable> byteArrayArray) { if (buffer == null) { if (stream == null) goto null_ex; buffer = ReadHeaderBuffer(stream, byteArrayArray.Max(x => x.Count)); } result = SequenceEqual(buffer, byteArrayArray); } else if (magicNumber is IEnumerable> byteArrayArrayNullable) { if (buffer == null) { if (stream == null) goto null_ex; buffer = ReadHeaderBuffer(stream, byteArrayArrayNullable.Max(x => x.Count)); } result = SequenceEqual(buffer, byteArrayArrayNullable); } else { result = false; } return result; null_ex: throw new ArgumentNullException(nameof(stream), "stream or buffer one must be non null."); } } } }