Skip to content

Commit

Permalink
🔖 v1.23.10817.11409
Browse files Browse the repository at this point in the history
  • Loading branch information
AigioL committed Aug 17, 2023
1 parent 702e26f commit 1d46061
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 6 deletions.
2 changes: 1 addition & 1 deletion ref/DirectoryPackages
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace System.Collections.Generic;

/// <summary>
/// 适用于 UTF8String 忽略大小写的字符串比较
/// </summary>
public sealed class Utf8StringComparerOrdinalIgnoreCase : IEqualityComparer<byte>
{
public Utf8StringComparerOrdinalIgnoreCase() { }

// https://www.geeksforgeeks.org/lower-case-upper-case-interesting-fact/

static byte Convert(byte b)
{
int i = b;
i &= ~32;
return (byte)i;
}

bool IEqualityComparer<byte>.Equals(byte x, byte y)
=> Convert(x) == Convert(y);

int IEqualityComparer<byte>.GetHashCode(byte obj)
=> EqualityComparer<byte>.Default.GetHashCode(Convert(obj));
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ public static bool IsImage(this ImageFormat imageFormat, IReadOnlyList<byte> buf
return FileFormat.MagicNumber.Match(magicNumber, buffer, null);
}

/// <summary>
/// 检查 二进制数据 是否为指定的图片格式
/// </summary>
/// <param name="imageFormat"></param>
/// <param name="buffer"></param>
/// <returns></returns>
public static bool IsImage(this ImageFormat imageFormat, ReadOnlyMemory<byte> buffer)
{
var magicNumber = imageFormat.GetMagicNumber();
return FileFormat.MagicNumber.Match(magicNumber, buffer, null);
}

/// <summary>
/// 检查 流中的数据 是否为指定的图片格式
/// </summary>
Expand All @@ -120,6 +132,7 @@ public static bool IsImage(this ImageFormat imageFormat, IReadOnlyList<byte> buf
public static bool IsImage(this ImageFormat imageFormat, Stream stream)
{
var magicNumber = imageFormat.GetMagicNumber();
return FileFormat.MagicNumber.Match(magicNumber, null, stream);
return FileFormat.MagicNumber.Match(magicNumber,
(IReadOnlyList<byte>?)null, stream);
}
}
74 changes: 74 additions & 0 deletions src/BD.Common/IO/FileFormats/FileFormat.AnalyzeFileType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
namespace System.IO.FileFormats;

partial class FileFormat
{
public readonly record struct AnalyzeFileTypeResult
{
AnalyzeFileTypeResult(string fileEx)
{
FileEx = fileEx;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator AnalyzeFileTypeResult(string fileEx)
=> new(fileEx);

AnalyzeFileTypeResult(ImageFormat imageFormat)
{
ImageFormat = imageFormat;
FileEx = imageFormat.GetExtension();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator AnalyzeFileTypeResult(ImageFormat imageFormat)
=> new(imageFormat);

public string FileEx { get; init; }

public ImageFormat? ImageFormat { get; init; }
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AnalyzeFileTypeResult AnalyzeFileType(ReadOnlyMemory<byte> buffer)
{
if (IsImage(buffer, out var imageFormat))
{
return imageFormat;
}

if (IsSQLite3(buffer))
{
return FileEx.SQLite;
}

Utf8StringComparerOrdinalIgnoreCase comparer = new();
// 根据文件头识别一些文件类型使用正确的文件扩展名
var magicNumber = "<html"u8;
if (magicNumber.SequenceEqual(buffer.Span[..magicNumber.Length], comparer))
{
return FileEx.HTML;
}
magicNumber = "<body"u8;
if (magicNumber.SequenceEqual(buffer.Span[..magicNumber.Length], comparer))
{
return FileEx.HTML;
}
magicNumber = "<!DOCTYPE"u8;
if (magicNumber.SequenceEqual(buffer.Span[..magicNumber.Length], comparer))
{
return FileEx.HTML;
}
magicNumber = "<?xml"u8;
if (magicNumber.SequenceEqual(buffer.Span[..magicNumber.Length], comparer))
{
return FileEx.XML;
}
magicNumber = "{"u8;
if (magicNumber.SequenceEqual(buffer.Span[..magicNumber.Length], comparer))
{
return FileEx.JSON;
}

return FileEx.BIN;
}
}
67 changes: 67 additions & 0 deletions src/BD.Common/IO/FileFormats/FileFormat.MagicNumber.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ static bool SequenceEqual<T>(
return !second.Where((t, i) => !equatable(first[i], t)).Any();
}

static bool SequenceEqual<T>(
ReadOnlyMemory<byte> first,
IReadOnlyCollection<T> second,
Func<byte, T, bool> equatable)
{
if (second == null) return false;
if (first.Length < second.Count) return false;
return !second.Where((t, i) => !equatable(first.Span[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);
Expand All @@ -39,6 +49,16 @@ public static bool SequenceEqual(IReadOnlyList<byte> first, IEnumerable<IReadOnl
public static bool SequenceEqual(IReadOnlyList<byte> first, IEnumerable<IReadOnlyCollection<byte?>> seconds)
=> seconds.Any(second => SequenceEqual(first, second));

public static bool SequenceEqual(ReadOnlyMemory<byte> first, IReadOnlyCollection<byte?> second) => SequenceEqual(first, second, Equals);

public static bool SequenceEqual(ReadOnlyMemory<byte> first, IReadOnlyCollection<byte> second) => SequenceEqual(first, second, Equals);

public static bool SequenceEqual(ReadOnlyMemory<byte> first, IEnumerable<IReadOnlyCollection<byte>> seconds)
=> seconds.Any(second => SequenceEqual(first, second));

public static bool SequenceEqual(ReadOnlyMemory<byte> first, IEnumerable<IReadOnlyCollection<byte?>> seconds)
=> seconds.Any(second => SequenceEqual(first, second));

public static byte[] ReadHeaderBuffer(Stream stream, int length, bool resetPosition = true)
{
var currentPosition = stream.Position;
Expand Down Expand Up @@ -130,5 +150,52 @@ public static bool Match(object magicNumber, IReadOnlyList<byte>? buffer, Stream
return result;
null_ex: throw new ArgumentNullException(nameof(stream), "stream or buffer one must be non null.");
}

public static bool Match(object magicNumber, ReadOnlyMemory<byte>? buffer, Stream? stream)
{
bool result;
if (magicNumber is IReadOnlyCollection<byte> byteArray)
{
if (!buffer.HasValue)
{
if (stream == null) goto null_ex;
buffer = ReadHeaderBuffer(stream, byteArray.Count);
}
result = SequenceEqual(buffer.Value, byteArray);
}
else if (magicNumber is IReadOnlyCollection<byte?> byteArrayNullable)
{
if (!buffer.HasValue)
{
if (stream == null) goto null_ex;
buffer = ReadHeaderBuffer(stream, byteArrayNullable.Count);
}
result = SequenceEqual(buffer.Value, byteArrayNullable);
}
else if (magicNumber is IEnumerable<IReadOnlyCollection<byte>> byteArrayArray)
{
if (!buffer.HasValue)
{
if (stream == null) goto null_ex;
buffer = ReadHeaderBuffer(stream, byteArrayArray.Max(x => x.Count));
}
result = SequenceEqual(buffer.Value, byteArrayArray);
}
else if (magicNumber is IEnumerable<IReadOnlyCollection<byte?>> byteArrayArrayNullable)
{
if (!buffer.HasValue)
{
if (stream == null) goto null_ex;
buffer = ReadHeaderBuffer(stream, byteArrayArrayNullable.Max(x => x.Count));
}
result = SequenceEqual(buffer.Value, byteArrayArrayNullable);
}
else
{
result = false;
}
return result;
null_ex: throw new ArgumentNullException(nameof(stream), "stream or buffer one must be non null.");
}
}
}
46 changes: 44 additions & 2 deletions src/BD.Common/IO/FileFormats/FileFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,26 @@ public static bool IsImage(IReadOnlyList<byte> buffer, out ImageFormat format)
return false;
}

/// <summary>
/// 检查 二进制数据 是否为图片格式
/// </summary>
/// <param name="buffer"></param>
/// <param name="format"></param>
/// <returns></returns>
public static bool IsImage(ReadOnlyMemory<byte> buffer, out ImageFormat format)
{
foreach (var item in ImageFormats)
{
if (item.IsImage(buffer))
{
format = item;
return true;
}
}
format = 0;
return false;
}

/// <summary>
/// 检查 二进制数据 是否为图片格式
/// </summary>
Expand All @@ -66,6 +86,17 @@ public static (bool isImage, ImageFormat format) IsImage(IReadOnlyList<byte> buf
return (isImage, format);
}

/// <summary>
/// 检查 二进制数据 是否为图片格式
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
public static (bool isImage, ImageFormat format) IsImage(ReadOnlyMemory<byte> buffer)
{
var isImage = IsImage(buffer, out var format);
return (isImage, format);
}

/// <summary>
/// 检查 流中的数据 是否为图片格式
/// </summary>
Expand All @@ -75,7 +106,7 @@ public static (bool isImage, ImageFormat format) IsImage(IReadOnlyList<byte> buf
public static bool IsImage(Stream stream, out ImageFormat format)
{
var length = imgFileMagicNums.Values.Max(MagicNumber.GetLength);
var buffer = MagicNumber.ReadHeaderBuffer(stream, length);
IReadOnlyList<byte> buffer = MagicNumber.ReadHeaderBuffer(stream, length);
foreach (var item in imgFileMagicNums)
{
if (MagicNumber.Match(item.Value, buffer, null))
Expand Down Expand Up @@ -107,11 +138,22 @@ public static (bool isImage, ImageFormat format) IsImage(Stream stream)
public static bool IsSQLite3(IReadOnlyList<byte> buffer)
=> MagicNumber.SequenceEqual(buffer, DataBaseFileFormat.SQLite3.MagicNumber);

/// <summary>
/// 检查 二进制数据 是否为 SQLite3 数据库文件
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
public static bool IsSQLite3(ReadOnlyMemory<byte> buffer)
=> MagicNumber.SequenceEqual(buffer, DataBaseFileFormat.SQLite3.MagicNumber);

/// <summary>
/// 检查 流中的数据 是否为 SQLite3 数据库文件
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
public static bool IsSQLite3(Stream stream)
=> IsSQLite3(MagicNumber.ReadHeaderBuffer(stream, DataBaseFileFormat.SQLite3.MagicNumber.Length));
{
IReadOnlyList<byte> buffer = MagicNumber.ReadHeaderBuffer(stream, DataBaseFileFormat.SQLite3.MagicNumber.Length);
return IsSQLite3(buffer);
}
}
4 changes: 4 additions & 0 deletions src/BD.Common/IO/_/FileEx/FileEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ public static partial class FileEx
/// </summary>
public const string Reg = ".reg";

public const string SQLite = ".sqlite";

public const string Database = ".db";

/// <summary>
/// 是否支持使用文本阅读器打开的扩展名
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
<ImplicitUsings>enable</ImplicitUsings>
<IsTrimmable>true</IsTrimmable>
<!--<Version>1.yy.1MMdd.1hhmm</Version>-->
<Version>1.23.10801.11742</Version>
<Version>1.23.10817.11409</Version>
<PackageIconUrl>https://avatars.githubusercontent.com/u/79355691?s=200&amp;v=4</PackageIconUrl>
<Company>长沙次元超越科技有限公司</Company>
<Company>江苏蒸汽凡星科技有限公司</Company>
<Copyright>©️ $(Company). All rights reserved.</Copyright>
<Authors>$(Company)</Authors>
<FileVersion>$(Version)</FileVersion>
Expand Down

0 comments on commit 1d46061

Please sign in to comment.