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.");
}
}
}
}