Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions FileTypeChecker.Tests/FileTypeChecker.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,14 @@
<None Update="files\file_example_WAV_1MG.wav">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="files\test.m4a">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="files\test.flac">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="files\test.ogg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
6 changes: 6 additions & 0 deletions FileTypeChecker.Tests/FileTypeValidatorAsyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ public async Task IsTypeRecognizableAsync_ShouldReturnFalseIfFormatIsUnknown()
[TestCase("test.mp4")]
[TestCase("file_example_AVI_480_750kB.avi")]
[TestCase("file_example_WAV_1MG.wav")]
[TestCase("test.m4a")]
[TestCase("test.flac")]
[TestCase("test.ogg")]
public async Task IsTypeRecognizableAsync_ShouldReturnTrueIfFileIsRecognized(string fileName)
{
await using var fileStream = File.OpenRead(Path.Combine(FilesPath, fileName));
Expand Down Expand Up @@ -104,6 +107,9 @@ public void GetFileTypeAsync_ShouldThrowTypeNotFoundExceptionWhenTypeIsNotRegist
[TestCase("test-issue-41.xlsx", typeof(MicrosoftOffice365Document))]
[TestCase("file_example_AVI_480_750kB.avi", typeof(AudioVideoInterleaveVideoFormat))]
[TestCase("file_example_WAV_1MG.wav", typeof(WaveformAudioFileFormat))]
[TestCase("test.m4a", typeof(M4a))]
[TestCase("test.flac", typeof(Flac))]
[TestCase("test.ogg", typeof(Ogg))]
public async Task GetFileTypeAsync_ShouldReturnAccurateType(string fileName, Type expectedType)
{
await using var fileStream = File.OpenRead(Path.Combine(FilesPath, fileName));
Expand Down
21 changes: 21 additions & 0 deletions FileTypeChecker.Tests/FileTypeValidatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ public void IsTypeRecognizable_ShouldReturnFalseIfFormatIsUnknown()
[TestCase("test.mp4")]
[TestCase("file_example_AVI_480_750kB.avi")]
[TestCase("file_example_WAV_1MG.wav")]
[TestCase("test.m4a")]
[TestCase("test.flac")]
[TestCase("test.ogg")]
public void IsTypeRecognizable_ShouldReturnTrueIfFileIsRecognized(string filePath)
{
using var fileStream = File.OpenRead(Path.Combine(FilesPath, filePath));
Expand Down Expand Up @@ -95,6 +98,9 @@ public void IsTypeRecognizable_ShouldReturnTrueIfFileIsRecognized(string filePat
[TestCase("FileTypeCheckerLogo-150.heic", HighEfficiencyImageFile.TypeMimeType)]
[TestCase("file_example_AVI_480_750kB.avi", AudioVideoInterleaveVideoFormat.TypeMimeType)]
[TestCase("file_example_WAV_1MG.wav", WaveformAudioFileFormat.TypeMimeType)]
[TestCase("test.m4a", M4a.TypeMimeType)]
[TestCase("test.flac", Flac.TypeMimeType)]
[TestCase("test.ogg", Ogg.TypeMimeType)]
public void GetFileType_ShouldReturnFileMimeType(string filePath, string expectedFileExtension)
{
using var fileStream = File.OpenRead(Path.Combine(FilesPath, filePath));
Expand Down Expand Up @@ -128,6 +134,9 @@ public void GetFileType_ShouldReturnFileMimeType(string filePath, string expecte
[TestCase("FileTypeCheckerLogo-150.heic", HighEfficiencyImageFile.TypeMimeType)]
[TestCase("file_example_AVI_480_750kB.avi", AudioVideoInterleaveVideoFormat.TypeMimeType)]
[TestCase("file_example_WAV_1MG.wav", WaveformAudioFileFormat.TypeMimeType)]
[TestCase("test.m4a", M4a.TypeMimeType)]
[TestCase("test.flac", Flac.TypeMimeType)]
[TestCase("test.ogg", Ogg.TypeMimeType)]
public void TryGetFileType_ShouldReturnFileMimeType(string filePath, string expectedFileExtension)
{
using var fileStream = File.OpenRead(Path.Combine(FilesPath, filePath));
Expand Down Expand Up @@ -160,6 +169,9 @@ public void TryGetFileType_ShouldReturnFileMimeType(string filePath, string expe
[TestCase("FileTypeCheckerLogo-150.heic", HighEfficiencyImageFile.TypeExtension)]
[TestCase("file_example_AVI_480_750kB.avi", AudioVideoInterleaveVideoFormat.TypeExtension)]
[TestCase("file_example_WAV_1MG.wav", WaveformAudioFileFormat.TypeExtension)]
[TestCase("test.m4a", M4a.TypeExtension)]
[TestCase("test.flac", Flac.TypeExtension)]
[TestCase("test.ogg", Ogg.TypeExtension)]
public void GetFileType_ShouldReturnFileExtension(string filePath, string expectedFileExtension)
{
using var fileStream = File.OpenRead(Path.Combine(FilesPath, filePath));
Expand Down Expand Up @@ -194,6 +206,9 @@ public void GetFileType_ShouldReturnFileExtension(string filePath, string expect
[TestCase("test-offset.mp4", M4V.TypeExtension)]
[TestCase("file_example_AVI_480_750kB.avi", AudioVideoInterleaveVideoFormat.TypeExtension)]
[TestCase("file_example_WAV_1MG.wav", WaveformAudioFileFormat.TypeExtension)]
[TestCase("test.m4a", M4a.TypeExtension)]
[TestCase("test.flac", Flac.TypeExtension)]
[TestCase("test.ogg", Ogg.TypeExtension)]
public void TryGetFileType_ShouldReturnFileExtension(string filePath, string expectedFileExtension)
{
using var fileStream = File.OpenRead(Path.Combine(FilesPath, filePath));
Expand Down Expand Up @@ -274,6 +289,9 @@ public void TryGetFileType_TypeShouldBeNullWhenNotMatching()
[TestCase("FileTypeCheckerLogo-150.heic", HighEfficiencyImageFile.TypeName)]
[TestCase("file_example_AVI_480_750kB.avi", AudioVideoInterleaveVideoFormat.TypeName)]
[TestCase("file_example_WAV_1MG.wav", WaveformAudioFileFormat.TypeName)]
[TestCase("test.m4a", M4a.TypeName)]
[TestCase("test.flac", Flac.TypeName)]
[TestCase("test.ogg", Ogg.TypeName)]
public void GetFileType_ShouldReturnFileName(string filePath, string expectedFileTypeName)
{
using var fileStream = File.OpenRead(Path.Combine(FilesPath, filePath));
Expand Down Expand Up @@ -342,6 +360,9 @@ public void Is_ShouldReturnFalseIfTypesDidNotMatch()
[TestCase("test-issue-41.xlsx", typeof(MicrosoftOffice365Document))]
[TestCase("file_example_AVI_480_750kB.avi", typeof(AudioVideoInterleaveVideoFormat))]
[TestCase("file_example_WAV_1MG.wav", typeof(WaveformAudioFileFormat))]
[TestCase("test.m4a", typeof(M4a))]
[TestCase("test.flac", typeof(Flac))]
[TestCase("test.ogg", typeof(Ogg))]
public void GetFileType_ShouldReturnAccurateTypeWhenUsingBytes(string fileName, Type expectedType)
{
var buffer = GetFileBytes(fileName);
Expand Down
Binary file added FileTypeChecker.Tests/files/test.flac
Binary file not shown.
Binary file added FileTypeChecker.Tests/files/test.m4a
Binary file not shown.
Binary file added FileTypeChecker.Tests/files/test.ogg
Binary file not shown.
29 changes: 29 additions & 0 deletions FileTypeChecker/Extensions/ByteExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ public static bool IsArchive(this byte[] content)
|| content.Is<LZipFile>()
|| content.Is<XzFile>();

/// <summary>
/// Validates that the current file is an audio file.
/// </summary>
/// <param name="content">File content as byte array.</param>
/// <returns>Returns true if the provided file is an audio file otherwise returns false. Supported audio types are: MP3, WAV, FLAC, OGG, M4A, and WMA.</returns>
public static bool IsAudio(this byte[] content)
=> content.Is<Mp3>()
|| content.Is<MpegAudio>()
|| content.Is<WaveformAudioFileFormat>()
|| content.Is<Flac>()
|| content.Is<Ogg>()
|| content.Is<M4a>()
|| content.Is<WindowsAudio>();

/// <summary>
/// Validates that the current file is executable or executable and linkable.
/// </summary>
Expand Down Expand Up @@ -173,6 +187,21 @@ public static bool IsArchive(this ReadOnlySpan<byte> content)
|| content.Is<LZipFile>()
|| content.Is<XzFile>();

/// <summary>
/// Validates that the current file is an audio file using high-performance ReadOnlySpan.
/// This overload avoids memory allocations and provides optimal performance.
/// </summary>
/// <param name="content">File content as ReadOnlySpan of bytes.</param>
/// <returns>Returns true if the provided file is an audio file otherwise returns false. Supported audio types are: MP3, WAV, FLAC, OGG, M4A, and WMA.</returns>
public static bool IsAudio(this ReadOnlySpan<byte> content)
=> content.Is<Mp3>()
|| content.Is<MpegAudio>()
|| content.Is<WaveformAudioFileFormat>()
|| content.Is<Flac>()
|| content.Is<Ogg>()
|| content.Is<M4a>()
|| content.Is<WindowsAudio>();

/// <summary>
/// Validates that the current file is executable or executable and linkable using high-performance ReadOnlySpan.
/// This overload avoids memory allocations and provides optimal performance.
Expand Down
31 changes: 31 additions & 0 deletions FileTypeChecker/Extensions/StreamExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ public static bool IsArchive(this Stream fileContent)
|| fileContent.Is<LZipFile>()
|| fileContent.Is<XzFile>();

/// <summary>
/// Validates that the current file is an audio file.
/// </summary>
/// <param name="fileContent">File to check as a stream.</param>
/// <returns>True if the provided file is an audio file; otherwise, false. Supported audio types include: MP3, WAV, FLAC, OGG, M4A, and WMA.</returns>
public static bool IsAudio(this Stream fileContent)
=> fileContent.Is<Mp3>()
|| fileContent.Is<MpegAudio>()
|| fileContent.Is<WaveformAudioFileFormat>()
|| fileContent.Is<Flac>()
|| fileContent.Is<Ogg>()
|| fileContent.Is<M4a>()
|| fileContent.Is<WindowsAudio>();

/// <summary>
/// Validates that the current file is an executable.
/// </summary>
Expand Down Expand Up @@ -139,6 +153,23 @@ public static async Task<bool> IsArchiveAsync(this Stream fileContent, Cancellat
|| await fileContent.IsAsync<XzFile>(cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// Asynchronously validates that the current file is an audio file.
/// </summary>
/// <param name="fileContent">File to check as a stream.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains true if the provided file is an audio file; otherwise, false. Supported audio types include: MP3, WAV, FLAC, OGG, M4A, and WMA.</returns>
public static async Task<bool> IsAudioAsync(this Stream fileContent, CancellationToken cancellationToken = default)
{
return await fileContent.IsAsync<Mp3>(cancellationToken).ConfigureAwait(false)
|| await fileContent.IsAsync<MpegAudio>(cancellationToken).ConfigureAwait(false)
|| await fileContent.IsAsync<WaveformAudioFileFormat>(cancellationToken).ConfigureAwait(false)
|| await fileContent.IsAsync<Flac>(cancellationToken).ConfigureAwait(false)
|| await fileContent.IsAsync<Ogg>(cancellationToken).ConfigureAwait(false)
|| await fileContent.IsAsync<M4a>(cancellationToken).ConfigureAwait(false)
|| await fileContent.IsAsync<WindowsAudio>(cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// Asynchronously validates that the current file is an executable.
/// </summary>
Expand Down
34 changes: 34 additions & 0 deletions FileTypeChecker/FileTypeValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ public static void RegisterCustomTypes(params Assembly[] assemblies)
public static bool Is<T>(Stream fileContent) where T : FileType, IFileType, new()
=> fileContent.Is<T>();

/// <summary>
/// Validates that the current file is an audio file.
/// </summary>
/// <param name="fileContent">File to check as a stream.</param>
/// <returns>Returns true if the provided file is an audio file otherwise returns false. Supported audio types are: MP3, WAV, FLAC, OGG, M4A, and WMA.</returns>
public static bool IsAudio(Stream fileContent)
=> fileContent.IsAudio();

/// <summary>
/// Validates that the current file is an image.
/// </summary>
Expand All @@ -181,6 +189,14 @@ public static bool IsArchive(Stream fileContent)
public static bool Is<T>(byte[] fileContent) where T : FileType, IFileType, new()
=> fileContent.Is<T>();

/// <summary>
/// Validates that the current file is an audio file.
/// </summary>
/// <param name="fileContent">File bytes.</param>
/// <returns>Returns true if the provided file is an audio file otherwise returns false. Supported audio types are: MP3, WAV, FLAC, OGG, M4A, and WMA.</returns>
public static bool IsAudio(byte[] fileContent)
=> fileContent.IsAudio();

/// <summary>
/// Validates that the current file is an image.
/// </summary>
Expand Down Expand Up @@ -274,6 +290,15 @@ public static async Task<MatchResult> TryGetFileTypeAsync(Stream fileContent, Ca
public static async Task<bool> IsAsync<T>(Stream fileContent, CancellationToken cancellationToken = default) where T : FileType, IFileType, new()
=> await fileContent.IsAsync<T>(cancellationToken).ConfigureAwait(false);

/// <summary>
/// Asynchronously validates that the current file is an audio file.
/// </summary>
/// <param name="fileContent">File to check as a stream.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains true if the provided file is an audio file; otherwise, false. Supported audio types include: MP3, WAV, FLAC, OGG, M4A, and WMA.</returns>
public static async Task<bool> IsAudioAsync(Stream fileContent, CancellationToken cancellationToken = default)
=> await fileContent.IsAudioAsync(cancellationToken).ConfigureAwait(false);

/// <summary>
/// Asynchronously validates that the current file is an image.
/// </summary>
Expand Down Expand Up @@ -362,6 +387,15 @@ public static MatchResult TryGetFileType(ReadOnlySpan<byte> fileContent)
public static bool Is<T>(ReadOnlySpan<byte> fileContent) where T : FileType, IFileType, new()
=> fileContent.Is<T>();

/// <summary>
/// Validates that the current file is an audio file using high-performance ReadOnlySpan.
/// This overload avoids memory allocations and provides optimal performance.
/// </summary>
/// <param name="fileContent">File content as ReadOnlySpan of bytes.</param>
/// <returns>True if the provided file is an audio file; otherwise, false. Supported audio types include: MP3, WAV, FLAC, OGG, M4A, and WMA.</returns>
public static bool IsAudio(ReadOnlySpan<byte> fileContent)
=> fileContent.IsAudio();

/// <summary>
/// Validates that the current file is an image using high-performance ReadOnlySpan.
/// This overload avoids memory allocations and provides optimal performance.
Expand Down
19 changes: 19 additions & 0 deletions FileTypeChecker/Types/Flac.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace FileTypeChecker.Types
{
using Abstracts;

/// <summary>
/// Free Lossless Audio Codec file. Identified by the fLaC magic marker.
/// </summary>
public class Flac : FileType, IFileType
{
public const string TypeName = "FLAC audio file";
public const string TypeMimeType = "audio/flac";
public const string TypeExtension = "flac";
private static readonly byte[] MagicBytes = { 0x66, 0x4C, 0x61, 0x43 }; // fLaC

public Flac() : base(TypeName, TypeMimeType, TypeExtension, MagicBytes)
{
}
}
}
23 changes: 23 additions & 0 deletions FileTypeChecker/Types/M4a.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using FileTypeChecker.Abstracts;

namespace FileTypeChecker.Types
{
/// <summary>
/// MPEG-4 audio file (AAC). Identified by ftyp box with M4A or M4B brand.
/// </summary>
public class M4a : FileType, IFileType
{
public const string TypeName = "MPEG-4 audio file";
public const string TypeMimeType = "audio/mp4";
public const string TypeExtension = "m4a";
private static readonly MagicSequence[] MagicBytesSequence =
{
new(new byte[] { 0x66, 0x74, 0x79, 0x70, 0x4D, 0x34, 0x41, 0x20 }, 4), // ftypM4A
new(new byte[] { 0x66, 0x74, 0x79, 0x70, 0x4D, 0x34, 0x42, 0x20 }, 4), // ftypM4B
};

public M4a() : base(TypeName, TypeMimeType, TypeExtension, MagicBytesSequence)
{
}
}
}
19 changes: 19 additions & 0 deletions FileTypeChecker/Types/Ogg.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace FileTypeChecker.Types
{
using Abstracts;

/// <summary>
/// Ogg container file (Vorbis, Opus, FLAC). Identified by the OggS capture pattern.
/// </summary>
public class Ogg : FileType, IFileType
{
public const string TypeName = "Ogg audio file";
public const string TypeMimeType = "audio/ogg";
public const string TypeExtension = "ogg";
private static readonly byte[] MagicBytes = { 0x4F, 0x67, 0x67, 0x53 }; // OggS

public Ogg() : base(TypeName, TypeMimeType, TypeExtension, MagicBytes)
{
}
}
}