Skip to content

Commit

Permalink
Introducing functionality to find best match if the input has two or …
Browse files Browse the repository at this point in the history
…more matches.
  • Loading branch information
AJMitev committed Oct 29, 2021
1 parent 52cdab8 commit 0fcfcc4
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 6 deletions.
34 changes: 29 additions & 5 deletions FileTypeChecker/Abstracts/FileType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
public abstract class FileType : IFileType
{
private const string FileContentMustBeReadableErrorMessage = "File contents must be a readable stream";

private const int ByfferDefaultSize = 20;
private string name;
private string extension;
private byte[][] bytes;
Expand Down Expand Up @@ -57,7 +57,7 @@ private set
}


private byte[][] Bytes
internal byte[][] Bytes
{
get => this.bytes;
set
Expand All @@ -83,21 +83,45 @@ public bool DoesMatchWith(Stream stream, bool resetPosition = true)
stream.Position = 0;
}

var buffer = new byte[20];
var buffer = new byte[ByfferDefaultSize];
stream.Read(buffer, 0, buffer.Length);
return DoesMatchWith(buffer);
}

public bool DoesMatchWith(byte[] buffer)
{
foreach (var x in this.Bytes)
foreach (var bytesArr in this.Bytes)
{
if (buffer.Skip(SkipBytes).Take(x.Length).SequenceEqual(x))
if (buffer.Skip(SkipBytes).Take(bytesArr.Length).SequenceEqual(bytesArr))
{
return true;
}
}
return false;
}

public int GetMatchingNumber(Stream stream)
{
stream.Position = 0;

int counter = 0;
var buffer = new byte[ByfferDefaultSize];
stream.Read(buffer, 0, buffer.Length);

foreach (var bytesArr in this.Bytes)
{
var shrinkedBuffer = buffer.Skip(SkipBytes).Take(bytesArr.Length);

for (int i = counter; i < bytesArr.Length; i++)
{
if (!bytesArr[i].Equals(buffer[i]))
break;

counter++;
}
}

return counter == 0 ? -1 : counter;
}
}
}
7 changes: 7 additions & 0 deletions FileTypeChecker/Abstracts/IFileType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,12 @@ public interface IFileType
/// <exception cref="System.NotSupportedException"></exception>
/// <exception cref="System.ObjectDisposedException"></exception>
bool DoesMatchWith(Stream stream, bool resetPosition = true);

/// <summary>
/// Returns an integer that represents how much that filetype matches the input. The bigger the number the best it match.
/// </summary>
/// <param name="stream">File as stream.</param>
/// <returns>Integer</returns>
int GetMatchingNumber(Stream stream);
}
}
41 changes: 40 additions & 1 deletion FileTypeChecker/FileTypeValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
/// </summary>
public static class FileTypeValidator
{
private const string EmptyCollectionErrorMessage = "Can't search in collection with no items!";
private static readonly List<Assembly> typesAssemblies = new List<Assembly>
{
typeof(FileType).Assembly
Expand Down Expand Up @@ -75,7 +76,9 @@ public static IFileType GetFileType(Stream fileContent)
{
DataValidator.ThrowIfNull(fileContent, nameof(Stream));

return FileTypes.SingleOrDefault(fileType => fileType.DoesMatchWith(fileContent));
var matches = FileTypes.Where(fileType => fileType.DoesMatchWith(fileContent));

return matches.Count() == 1 ? matches.First() : FindBestMatch(fileContent, matches); ;
}

/// <summary>
Expand Down Expand Up @@ -134,5 +137,41 @@ private static void RegisterTypes(IEnumerable<Assembly> assemblies)
}
}
}

private static IFileType FindBestMatch(Stream fileContent, IEnumerable<IFileType> result)
{
var scoreboard = new Dictionary<IFileType, int>();

for (int typeIndex = 0; typeIndex < result.Count(); typeIndex++)
{
var currentType = result.ElementAt(typeIndex) as FileType;

if (!scoreboard.ContainsKey(currentType))
scoreboard.Add(currentType, currentType.GetMatchingNumber(fileContent));

}

return FindMaxScore(scoreboard);
}

private static IFileType FindMaxScore(IDictionary<IFileType, int> dictinalry)
{
if (dictinalry.Count == 0)
throw new InvalidOperationException(EmptyCollectionErrorMessage);

int maxAge = int.MinValue;
IFileType element = null;

foreach (var type in dictinalry)
{
if (!(type.Value > maxAge))
continue;

maxAge = type.Value;
element = type.Key;
}

return element;
}
}
}

0 comments on commit 0fcfcc4

Please sign in to comment.