TextBinaryFileId.cs

Determine Byte Array Binary or Text

Updated: March-5, 2022

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
public class TextBinaryFileId
{
    private readonly BoyerMooreByte             _boyerMoore4Null = new(new byte[] { 0, 0, 0, 0 });
    public           Dictionary<string, string> BinaryFiles      = new();
    public           Dictionary<string, string> EncodingFiles    = new();
    public           Dictionary<string, double> TextFiles        = new();
    public bool IsBlockText(byte[] BinData, double ConfidenceThreshold = 25)
    {
        if (BinData.Length == 0)
            return false;
        if (_boyerMoore4Null.Search(BinData) != -1)
            return false;
        var enc     = GetEncoding(BinData);
        var CcCount = BinData.AsParallel().Count(b => !IsValidTextByte(b, !(enc == Encoding.Unicode || enc == Encoding.UTF8 || enc == Encoding.UTF7 || enc == Encoding.ASCII)));
        var asp     = (double)CcCount / BinData.Length * 100d;
        return !(asp > ConfidenceThreshold);
    }
    public byte[] ReadBytes(string path)
    {
        try
        {
            var ba  = File.ReadAllBytes(path);
            var enc = GetEncoding(ba);
            EncodingFiles.Add(path, enc.EncodingName);
            if (Equals(enc, Encoding.UTF7) || Equals(enc, Encoding.UTF8) || Equals(enc, Encoding.ASCII)) return ba;
            if (Equals(enc, Encoding.Unicode))
            {
                var len  = ba.Length - 2;
                var blen = len / 2;
                if (blen * 2 < len) blen++;
                var b = new byte[blen];
                for (int i = 2, j = 0; i < ba.Length && j < blen; i += 2, ++j)
                    b[j] = ba[i];
                return b;
            }
            if (Equals(enc, Encoding.UTF32))
            {
                var len1  = ba.Length - 4;
                var blen1 = len1 / 4;
                if (blen1 * 4 < len1)
                    blen1++;
                var b1 = new byte[blen1];
                for (int i = 4, j = 0; i < ba.Length && j < blen1; i += 4, ++j)
                    b1[j] = ba[i];
                return b1;
            }
            return ba;
        }
        catch (Exception ex)
        {
            ExceptionLog.ExLog(ex, "ReadBytes", "ReadBytes");
        }
        return null;
    }
    public bool IsTextQik(string path, bool TestEntireFile = false)
    {
        var    isText = true;
        double asp    = 0;
        using (var fileStream = File.OpenRead(path))
        {
            var WindowSize = 0l;
            if (TestEntireFile)
            {
                WindowSize = fileStream.Length;
            }
            else
            {
                WindowSize = 512;
                if (WindowSize > fileStream.Length)
                    WindowSize = fileStream.Length;
            }
            if (fileStream.Length == 0)
                return false;
            var BinData = new byte[WindowSize];
            fileStream.Read(BinData, 0, BinData.Length);
            if (fileStream.Length < 4)
            {
                foreach (var b in BinData)
                    if (!IsValidTextByte(b))
                        return false;
                return true;
            }
            if (_boyerMoore4Null.Search(BinData) != -1)
                isText = false;
            if (!ComfirmIsText(BinData))
                isText = false;
        }
        return isText;
    }
    public bool IsTextQik(byte[] buffer, bool TestEntireFile = false)
    {
        var    isText = true;
        double asp    = 0;
        if (buffer.Length == 0)
            return false;
        var WindowSize = 0;
        if (TestEntireFile)
        {
            WindowSize = buffer.Length;
        }
        else
        {
            WindowSize = 512;
            if (WindowSize > buffer.Length)
                WindowSize = buffer.Length;
        }
        var BinData = buffer.SubArray(0, WindowSize);
        if (BinData.Count(b => !IsValidTextByte(b)) > 0)
            return false;
        if (_boyerMoore4Null.Search(BinData) != -1)
            return false;
        return true;
    }
    public bool IsText(string path, bool TestEntireFile = false, double ConfidenceThreshold = 100, bool TestEncoding = true)
    {
        var    Reason = "None";
        var    isText = true;
        double asp    = 0;
        using (var fileStream = File.OpenRead(path))
        {
            var WindowSize = 0l;
            if (TestEntireFile)
            {
                WindowSize = fileStream.Length;
            }
            else
            {
                WindowSize = 512;
                if (WindowSize > fileStream.Length)
                    WindowSize = fileStream.Length;
            }
            if (fileStream.Length == 0)
            {
                BinaryFiles.Add(path, "Zero Length File.");
                return false;
            }
            var BinData       = new byte[WindowSize];
            var BinDataLength = fileStream.Read(BinData, 0, BinData.Length);
            fileStream.Seek(0, SeekOrigin.Begin);
            if (fileStream.Length < 4)
            {
                var r = BinData.All(b => IsValidTextByte(b));
                if (!r)
                    BinaryFiles.Add(path, "Length 4 file Contains invalid Characters.");
                return r;
            }
            if (_boyerMoore4Null.Search(BinData) != -1)
            {
                Reason = "4 Sequential Nulls Found within File.";
                isText = false;
            }
            if (isText)
            {
                var enc = GetEncoding(BinData);
                if (TestEncoding)
                {
                    var TextData = new char[WindowSize];
                    var eMatches = 0;
                    using (var streamReader = new StreamReader(fileStream))
                    {
                        streamReader.Read(TextData, 0, TextData.Length);
                    }
                    using (var memoryStream = new MemoryStream())
                    {
                        using (var streamWriter = new StreamWriter(memoryStream, enc))
                        {
                            streamWriter.Write(TextData);
                            streamWriter.Flush();
                            var memoryBuffer = memoryStream.GetBuffer();
                            for (var i = 0; i < BinDataLength; i++)
                                if (BinData[i] == memoryBuffer[i])
                                    eMatches++;
                            var er = (double)eMatches / BinDataLength * 100d;
                            if ((int)er < 99)
                            {
                                isText = false;
                                Reason = $"Encoding Mismatch: {er:0.0}";
                            }
                        }
                    }
                }
                if (isText)
                {
                    double CcCount = BinData.AsParallel().Count(b =>
                        !IsValidTextByte(b, !(enc == Encoding.Unicode || enc == Encoding.UTF8 || enc == Encoding.UTF7 || enc == Encoding.ASCII)));
                    asp = CcCount / BinData.Length * 100d;
                    if (asp > ConfidenceThreshold)
                    {
                        Reason = $"Confidence threshold {ConfidenceThreshold:0.0} Exceeded: {asp:0.0}";
                        isText = false;
                    }
                }
            }
        }
        if (isText)
            TextFiles.Add(path, asp.TruncateToDecimalPlace(1));
        else
            BinaryFiles.Add(path, Reason);
        return isText;
    }
    public static Encoding GetEncoding(byte[] Data)
    {
        if (Data == null)
            throw new Exception("Array cannot be null.");
        if (Data.Length < 2)
            return Encoding.Default;
        if (Data[0] == 0xff && Data[1] == 0xfe)
            return Encoding.Unicode;
        if (Data[0] == 0xfe && Data[1] == 0xff)
            return Encoding.BigEndianUnicode;
        if (Data.Length < 3)
            return Encoding.Default;
        if (Data[0] == 0xef && Data[1] == 0xbb && Data[2] == 0xbf)
            return Encoding.UTF8;
        if (Data[0] == 0x2b && Data[1] == 0x2f && Data[2] == 0x76)
            return Encoding.UTF7;
        if (Data.Length < 4)
            return Encoding.Default;
        if (Data[0] == 0xff && Data[1] == 0xfe && Data[2] == 0 && Data[3] == 0)
            return Encoding.UTF32;
        return Encoding.Default;
    }
    public static bool ComfirmIsText(byte[] Data)
    {
        if (Data == null)
            throw new Exception("Array cannot be null.");
        if (Data.Length < 2)
            return false;
        if (Data[0] == 0xff && Data[1] == 0xfe)
            return true;
        if (Data[0] == 0xfe && Data[1] == 0xff)
            return true;
        if (Data.Length < 3)
            return false;
        if (Data[0] == 0xef && Data[1] == 0xbb && Data[2] == 0xbf)
            return true;
        if (Data[0] == 0x2b && Data[1] == 0x2f && Data[2] == 0x76)
            return true;
        if (Data.Length < 4)
            return false;
        if (Data[0] == 0xff && Data[1] == 0xfe && Data[2] == 0 && Data[3] == 0)
            return true;
        var ld = Data.SubArray(0, Data.Length >= 6 ? 6 : Data.Length);
        foreach (var b in ld)
            if (!IsValidTextByte(b))
                return false;
        return true;
        ;
    }
    private static bool IsValidTextByte(byte _byte, bool IncludeNull = false)
    {
        if (IncludeNull)
            if (_byte == 0x00)
                return true;
        if (_byte == 0x0A || _byte == 0x0D || _byte == 0x09 || (_byte >= 0x20 && _byte <= 0x2F) || (_byte >= 0x30 && _byte <= 0x39) || (_byte >= 0x3A && _byte <= 0x40) ||
            (_byte >= 0x41 && _byte <= 0x5A) || (_byte >= 0x5B && _byte <= 0x60) || (_byte >= 0x61 && _byte <= 0x7A) || (_byte >= 0x7B && _byte <= 0x7E))
            return true;
        return false;
    }
}

Writer.cs

Simplified Binary Writer

Example Code:

using System;
using System.IO;
using System.Numerics;
using System.Text;
/// <inheritdoc />
/// <summary>
///     Alternate Binary Writer created to enhance usability and ease coding complexity.
/// </summary>
public class Writer : IDisposable
{
    /// <inheritdoc />
    /// <summary>
    ///     Initializes a new instance of the Writer class based on a specified path name, a default FileMode of Create, and
    ///     defaulting to UTF-8 encoding.
    /// </summary>
    public Writer(string path) : this(path, FileMode.Create, new UTF8Encoding(false, true))
    {
    }
    /// <inheritdoc />
    /// <summary>
    ///     Initializes a new instance of the Writer class based on a specified path name, a specified FileMode and defaulting
    ///     to UTF-8 encoding.
    /// </summary>
    public Writer(string path, FileMode fm) : this(path, fm, new UTF8Encoding(false, true))
    {
    }
    /// <summary>
    ///     Initializes a new instance of the Writer class based on a specified path name, a specified FileMode and a specified
    ///     encoding.
    /// </summary>
    public Writer(string path, FileMode fm, Encoding encoding)
    {
        if (string.IsNullOrEmpty(path))
            throw new Exception($"Path {path} cannot be null or empty.");
        BaseMode = fm;
        try
        {
            if (File.Exists(path))
                File.SetAttributes(path, File.GetAttributes(path) | FileAttributes.Normal);
            BaseStream = new FileStream(path, BaseMode, FileAccess.Write);
            if (BaseStream?.CanWrite == true)
                BaseWriter = new BinaryWriter(BaseStream, encoding, true);
            else throw new Exception($"The FileStream for path:{path} is null.");
        }
        catch (Exception e)
        {
            throw new Exception($"Error: {e.Message}");
        }
    }
    public Writer(Stream stream) : this(stream, new UTF8Encoding(false, true))
    {
    }
    public Writer(Stream strm, Encoding encoding)
    {
        try
        {
            if (strm?.CanWrite == true)
                BaseWriter = new BinaryWriter(strm, encoding, true);
            else throw new Exception("The Stream is null.");
        }
        catch (Exception e)
        {
            throw new Exception($"Error: {e.Message}");
        }
    }
    /// <summary>
    ///     Expose the underlying BinaryWriter
    /// </summary>
    public BinaryWriter BaseWriter { get; }
    /// <summary>
    ///     Expose the underlying FileMode
    /// </summary>
    public FileMode BaseMode { get; }
    /// <summary>
    ///     Expose the underlying FileStream
    /// </summary>
    public FileStream BaseStream { get; }
    /// <summary>
    ///     Each time a primitive is written there is one additional integer written to signify its type.
    ///     This can be used to compute the final size of the stream bytes needed.
    /// </summary>
    public static int PrimitiveOverHead => sizeof(int);
    /// <summary>
    ///     Each time a array is written there are two additional integers written one to signify its type and the other its
    ///     size.
    ///     This can be used to compute the final size of the stream bytes needed.
    /// </summary>
    public static int ArrayOverHead => sizeof(int) * 2;
    public void Dispose()
    {
        if (BaseStream == null) return;
        BaseStream.Flush();
        BaseStream.Dispose();
    }
    /// <summary>
    ///     Sets the position to offset relative to origin within the stream.
    /// </summary>
    public long Seek(int offset, SeekOrigin origin)
    {
        return BaseStream.Seek(offset, origin);
    }
    public void WriteBool(bool value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.Boolean);
        BaseWriter.Write(value);
    }
    public void WriteChar(char value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.Character);
        BaseWriter.Write(value);
    }
    public void WriteByte(byte value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.Byte);
        BaseWriter.Write(value);
    }
    public void WriteSByte(sbyte value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.ShortByte);
        BaseWriter.Write(value);
    }
    public void WriteShort(short value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.Short);
        BaseWriter.Write(value);
    }
    public void WriteUShort(ushort value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.UnsignedShort);
        BaseWriter.Write(value);
    }
    public void WriteInt(int value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.Integer);
        BaseWriter.Write(value);
    }
    public void WriteUInt(uint value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.UnsignedInteger);
        BaseWriter.Write(value);
    }
    public void WriteLOng(long value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.Long);
        BaseWriter.Write(value);
    }
    public void WriteULong(ulong value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.UnsignedLong);
        BaseWriter.Write(value);
    }
    public void WriteString(string value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.String);
        BaseWriter.Write(value);
    }
    public void WriteFloat(float value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.Float);
        BaseWriter.Write(value);
    }
    public void WriteDouble(double value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.Double);
        BaseWriter.Write(value);
    }
    public void WriteDecimal(decimal value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.Decimal);
        BaseWriter.Write(value);
    }
    public void WriteBigInteger(BigInteger value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.BigInteger);
        WriteBytes(value.ToByteArray());
    }
    public void WriteBigRational(BigRational value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.BigRational);
        var Num = value.Numerator.ToByteArray();
        var Den = value.Denominator.ToByteArray();
        WriteBytes(Num);
        WriteBytes(Den);
    }
    public void WriteBools(bool[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.BooleanArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteChars(char[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.CharacterArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteBytes(byte[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.ByteArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteSBytes(sbyte[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.ShortByteArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteShorts(short[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.ShortArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteUShorts(ushort[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.UnsignedShortArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteInts(int[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.IntegerArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteUInts(uint[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.UnsignedIntegerArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteLongs(long[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.LongArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteULongs(ulong[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.UnsignedLongArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteStrings(string[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.StringArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteFloats(float[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.FloatArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteDoubles(double[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.DoubleArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteDecimals(decimal[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.DecimalArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            BaseWriter.Write(v);
    }
    public void WriteBigIntegers(BigInteger[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.BigIntegerArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            WriteBigInteger(v);
    }
    public void WriteBigRationals(BigRational[] value)
    {
        BaseWriter.Write((int) Rwtypes.Readerwritertypes.BigRationalArray);
        var len = value.Length;
        BaseWriter.Write(len);
        foreach (var v in value)
            WriteBigRational(v);
    }
}

Reader.cs

Simplified Binary Reader

Example Code:

using System;
using System.IO;
using System.Numerics;
using System.Text;
/// <inheritdoc />
/// <summary>
///     Alternate Binary Reader created to ease usability and complexity of coding.
/// </summary>
public class Reader : IDisposable
{
    /// <inheritdoc />
    /// <summary>
    ///     Initializes a new instance of the Reader class based on a specified path name, and defaulting to UTF-8 encoding.
    /// </summary>
    public Reader(string path) : this(path, new UTF8Encoding(false, true))
    {
    }
    /// <summary>
    ///     Initializes a new instance of the Reader class based on a specified path name, a specified encoding.
    /// </summary>
    public Reader(string path, Encoding encoding)
    {
        if (string.IsNullOrEmpty(path))
            throw new Exception($"Path {path} cannot be null or empty.");
        try
        {
            File.SetAttributes(path, File.GetAttributes(path) | FileAttributes.Normal);
            BaseStream = new FileStream(path, FileMode.Open, FileAccess.Read);
            if (BaseStream?.CanRead == true)
                BaseReader = new BinaryReader(BaseStream, encoding);
            else throw new Exception($"The FileStream for path:{path} is null.");
        }
        catch (Exception e)
        {
            throw new Exception($"Error: {e.Message}");
        }
    }
    public Reader(Stream strm) : this(strm, new UTF8Encoding(false, true))
    {
    }
    public Reader(Stream strm, Encoding encoding)
    {
        try
        {
            if (strm?.CanRead == true)
                BaseReader = new BinaryReader(strm, encoding);
            else throw new Exception("The Stream is null.");
        }
        catch (Exception e)
        {
            throw new Exception($"Error: {e.Message}");
        }
    }
    /// <summary>
    ///     Expose the underlying BinaryReader
    /// </summary>
    public BinaryReader BaseReader { get; }
    /// <summary>
    ///     Expose the underlying FileStream
    /// </summary>
    public FileStream BaseStream { get; }
    /// <summary>
    ///     Each time a primitive is written there is one additional integer written to signify its type.
    ///     This can be used to compute the final size of the stream bytes needed.
    /// </summary>
    public static int PrimitiveOverHead => sizeof(int);
    /// <summary>
    ///     Each time a array is written there are two additional integers written one to signify its type and the other its
    ///     size.
    ///     This can be used to compute the final size of the stream bytes needed.
    /// </summary>
    public static int ArrayOverHead => sizeof(int) * 2;
    public void Dispose()
    {
        BaseStream?.Dispose();
    }
    /// <summary>
    ///     Sets the position to offset relative to origin within the stream.
    /// </summary>
    public long Seek(int offset, SeekOrigin origin)
    {
        return BaseStream.Seek(offset, origin);
    }
    /// <summary>
    ///     A wrapper for PeekChar of BinaryReader underling class.
    /// </summary>
    public int PeekChar()
    {
        return BaseReader.PeekChar();
    }
    public bool ReadBool()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary boolean value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.Boolean)
            throw new Exception($"Boolean value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadBoolean();
    }
    public char ReadChar()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary Char value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.Character)
            throw new Exception($"Character value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadChar();
    }
    public byte ReadByte()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary Byte value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.Byte)
            throw new Exception($"Byte value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadByte();
    }
    public sbyte ReadSByte()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary short byte value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.ShortByte)
            throw new Exception($"Short Byte value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadSByte();
    }
    public short ReadShort()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary Short value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.Short)
            throw new Exception($"Short value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadInt16();
    }
    public ushort ReadUShort()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary Unsigned Short value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.UnsignedShort)
            throw new Exception($"Unsigned Short value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadUInt16();
    }
    public int ReadInt()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary Integer value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.Integer)
            throw new Exception($"Integer value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadInt32();
    }
    public uint ReadUInt()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary Unsigned Integer value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.UnsignedInteger)
            throw new Exception($"Unsigned Integer value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadUInt32();
    }
    public long ReadLong()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary Long value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.Long)
            throw new Exception($"Long value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadInt64();
    }
    public ulong ReadULong()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary Unsigned Long value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.UnsignedLong)
            throw new Exception($"Unsigned Long value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadUInt64();
    }
    public string ReadString()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary String value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.String)
            throw new Exception($"String value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadString();
    }
    public float ReadFloat()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary Float value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.Float)
            throw new Exception($"Float value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadSingle();
    }
    public double ReadDouble()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary Double value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.Double)
            throw new Exception($"Double value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadDouble();
    }
    public decimal ReadDecimal()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary Decimal value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.Decimal)
            throw new Exception($"Decimal value read requested '{Rwtypes.GetType(t)}' value found.");
        return BaseReader.ReadDecimal();
    }
    public BigInteger ReadBigInteger()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary BigInteger value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.BigInteger)
            throw new Exception($"BigInteger value read requested '{Rwtypes.GetType(t)}' value found.");
        return new BigInteger(ReadBytes());
    }
    public BigRational ReadBigRational()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary BigRational value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.BigRational)
            throw new Exception($"BigRational value read requested '{Rwtypes.GetType(t)}' value found.");
        var Num = new BigInteger(ReadBytes());
        var Den = new BigInteger(ReadBytes());
        return new BigRational(Num, Den);
    }
    public bool[] ReadBools()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary boolean array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.BooleanArray)
            throw new Exception($"Boolean Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new bool[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadBoolean();
        return arr;
    }
    public char[] ReadChars()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary char array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.CharacterArray)
            throw new Exception($"Character array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new char[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadChar();
        return arr;
    }
    public byte[] ReadBytes()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary byte array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.ByteArray)
            throw new Exception($"Byte Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new byte[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadByte();
        return arr;
    }
    public sbyte[] ReadSBytes()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary sbyte array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.ShortByteArray)
            throw new Exception($"Short Byte Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new sbyte[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadSByte();
        return arr;
    }
    public short[] ReadShorts()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary short array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.ShortArray)
            throw new Exception($"Short Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new short[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadInt16();
        return arr;
    }
    public ushort[] ReadUShorts()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary unsigned short array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.UnsignedShortArray)
            throw new Exception($"Unsigned Short Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new ushort[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadUInt16();
        return arr;
    }
    public int[] ReadInts()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary integer array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.IntegerArray)
            throw new Exception($"Integer Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new int[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadInt32();
        return arr;
    }
    public uint[] ReadUInts()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary unsigned integer array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.UnsignedInteger)
            throw new Exception($"Unsigned Integer Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new uint[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadUInt32();
        return arr;
    }
    public long[] ReadLongs()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary long array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.LongArray)
            throw new Exception($"Long Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new long[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadInt64();
        return arr;
    }
    public ulong[] ReadULongs()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary unsigned long array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.UnsignedLongArray)
            throw new Exception($"Unsigned Long Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new ulong[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadUInt64();
        return arr;
    }
    public string[] ReadStrings()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary string array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.StringArray)
            throw new Exception($"String Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new string[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadString();
        return arr;
    }
    public float[] ReadFloats()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary float array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.FloatArray)
            throw new Exception($"Float Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new float[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadSingle();
        return arr;
    }
    public double[] ReadDoubles()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary double array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.DoubleArray)
            throw new Exception($"Double Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new double[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadDouble();
        return arr;
    }
    public decimal[] ReadDecimals()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary decimal array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.DecimalArray)
            throw new Exception($"Decimal Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new decimal[len];
        for (var i = 0; i < len; ++i)
            arr[i] = BaseReader.ReadDecimal();
        return arr;
    }
    public BigInteger[] ReadBigIntegers()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary BigInteger array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.BigIntegerArray)
            throw new Exception($"BigInteger Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new BigInteger[len];
        for (var i = 0; i < len; ++i)
            arr[i] = ReadBigInteger();
        return arr;
    }
    public BigRational[] ReadBigRationals()
    {
        if (BaseReader.PeekChar() == -1)
            throw new Exception("Primary BigRational array value does not exist or can not be read.");
        var t = BaseReader.ReadInt32();
        if (t != (int) Rwtypes.Readerwritertypes.BigRationalArray)
            throw new Exception($"BigRational Array value read requested '{Rwtypes.GetType(t)}' value found.");
        var len = BaseReader.ReadInt32();
        var arr = new BigRational[len];
        for (var i = 0; i < len; ++i)
            arr[i] = ReadBigRational();
        return arr;
    }
}

KeccakSpongeManaged.cs

Keccak Sponge (Sha3) Checked

using System;
using System.Runtime.CompilerServices;
[Serializable]
public class SHA3Managed : HashAlgorithmEx
{
    private readonly KeccakSpongeManaged ksm;
    public SHA3Managed(int size, ulong[] seed = null) : this(size, 24, seed)
    {
    }
    public SHA3Managed(int size) : this(size, 24)
    {
    }
    public SHA3Managed() : this(512, 24)
    {
    }
    public SHA3Managed(int size, int rounds = 24, ulong[] seed = null)
    {
        if (rounds > 24)
            throw new Exception($"Maximum rounds allowed is {24}");
        var MaxBR     = (64 >> 3) * 25;
        var sizeBytes = size >> 3;
        var rateBytes = MaxBR - (sizeBytes << 1);
        var MaxSize   = ((MaxBR - 8)       >> 1) << 3;
        if (rateBytes < 8)
            throw new Exception($"Maximum size allowed is {MaxSize} Bits with {64} bit Width specified. Specified Size is {size} Bits.");
        var outputLength = size >> 3;
        ksm           = new KeccakSpongeManaged(rateBytes, 200 - rateBytes, KeccakSpongeManaged.KeccakDelimiter, outputLength, seed);
        ksm.Rounds    = rounds;
        HashSizeValue = size;
    }
    public int HashLength => ksm.HashLength;
    public override void Initialize()
    {
        ksm.Initialize();
    }
    protected override void HashCore(byte[] array, int ibStart, int cbSize)
    {
        Initialize();
        ksm.Absorb(array, ibStart, cbSize);
    }
    protected override byte[] HashFinal()
    {
        return ksm.Squeeze();
    }
}
[Serializable]
public class KeccakSpongeManaged
{
    public const     int KeccakDelimiter = 6;
    public const     int ShakeDelimiter  = 31;
    private readonly int _delimiter;
    private readonly int _outputLength;
    private readonly int _rateBytes;
    private readonly ulong[] _roundConstants =
    {
        0x0000000000000001,
        0x0000000000008082,
        0x800000000000808A,
        0x8000000080008000,
        0x000000000000808B,
        0x0000000080000001,
        0x8000000080008081,
        0x8000000000008009,
        0x000000000000008A,
        0x0000000000000088,
        0x0000000080008009,
        0x000000008000000A,
        0x000000008000808B,
        0x800000000000008B,
        0x8000000000008089,
        0x8000000000008003,
        0x8000000000008002,
        0x8000000000000080,
        0x000000000000800A,
        0x800000008000000A,
        0x8000000080008081,
        0x8000000000008080,
        0x0000000080000001,
        0x8000000080008008
    };
    private readonly ulong[] _seed;
    private          int     _blockSize;
    private          int     _input;
    private          int     _output;
    private          byte[]  _result;
    private          ulong[] _state;
    public           int     HashLength;
    public           int     Rounds = 24;
    public KeccakSpongeManaged(int rateBytes, int capacityBytes, int delimiter, int outputLength, ulong[] seed)
    {
        if (rateBytes + capacityBytes != 200 || (uint) (rateBytes % 8) > 0U)
            throw new ArgumentException($"rateBytes {rateBytes} + capacityBytes {capacityBytes}={rateBytes + capacityBytes} must be 200 or {rateBytes} must be a multiple of 8");
        _rateBytes    = rateBytes;
        _delimiter    = delimiter;
        _outputLength = outputLength;
        HashLength    = outputLength;
        _seed         = seed;
    }
    public void Initialize()
    {
        _blockSize = 0;
        _input     = 0;
        _output    = 0;
        _state     = new ulong[25];
        _result    = new byte[_outputLength];
        if (_seed != null && _seed[0] != 0)
        {
            for (var i = 0; i < _seed.Length && i < _state.Length; ++i)
                _state[i] = _seed[i];
            Permute(_state);
        }
    }
    public void Absorb(byte[] array, int start, int size)
    {
        while (size > 0)
        {
            _blockSize = Math.Min(size, _rateBytes);
            for (var index = start; index < _blockSize; ++index)
            {
                var num = Convert.ToByte(Buffer.GetByte(_state, index) ^ array[index + _input]);
                Buffer.SetByte(_state, index, num);
            }
            _input += _blockSize;
            size   -= _blockSize;
            if (_blockSize == _rateBytes)
            {
                Permute(_state);
                _blockSize = 0;
            }
        }
    }
    public byte[] Squeeze()
    {
        Buffer.SetByte(_state, _blockSize, Convert.ToByte(Buffer.GetByte(_state, _blockSize) ^ _delimiter));
        if ((_delimiter & 128) != 0 && _blockSize == _rateBytes - 1)
            Permute(_state);
        Buffer.SetByte(_state, _rateBytes - 1, Convert.ToByte(Buffer.GetByte(_state, _rateBytes - 1) ^ 128));
        Permute(_state);
        var outputLength = _outputLength;
        while (outputLength > 0)
        {
            _blockSize = Math.Min(outputLength, _rateBytes);
            Buffer.BlockCopy(_state, 0, _result, _output, _blockSize);
            _output      += _blockSize;
            outputLength -= _blockSize;
            if (outputLength > 0)
                Permute(_state);
        }
        return _result;
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void Permute(ulong[] state)
    {
        for (var round = 0; round < Rounds; ++round)
        {
            Theta(out var C0, state, out var C1, out var C2, out var C3, out var C4);
            RhoPi(state);
            Chi(ref C0, state, ref C1, ref C2, ref C3, ref C4);
            Iota(round, state);
        }
    }
    private static void Theta(out ulong C0, ulong[] state, out ulong C1, out ulong C2, out ulong C3, out ulong C4)
    {
        C0 = state[0] ^ state[5] ^ state[10] ^ state[15] ^ state[20];
        C1 = state[1] ^ state[6] ^ state[11] ^ state[16] ^ state[21];
        C2 = state[2] ^ state[7] ^ state[12] ^ state[17] ^ state[22];
        C3 = state[3] ^ state[8] ^ state[13] ^ state[18] ^ state[23];
        C4 = state[4] ^ state[9] ^ state[14] ^ state[19] ^ state[24];
        var D0 = Rol(C1, 1) ^ C4;
        var D1 = Rol(C2, 1) ^ C0;
        var D2 = Rol(C3, 1) ^ C1;
        var D3 = Rol(C4, 1) ^ C2;
        var D4 = Rol(C0, 1) ^ C3;
        state[0]  ^= D0;
        state[5]  ^= D0;
        state[10] ^= D0;
        state[15] ^= D0;
        state[20] ^= D0;
        state[1]  ^= D1;
        state[6]  ^= D1;
        state[11] ^= D1;
        state[16] ^= D1;
        state[21] ^= D1;
        state[2]  ^= D2;
        state[7]  ^= D2;
        state[12] ^= D2;
        state[17] ^= D2;
        state[22] ^= D2;
        state[3]  ^= D3;
        state[8]  ^= D3;
        state[13] ^= D3;
        state[18] ^= D3;
        state[23] ^= D3;
        state[4]  ^= D4;
        state[9]  ^= D4;
        state[14] ^= D4;
        state[19] ^= D4;
        state[24] ^= D4;
    }
    private static void RhoPi(ulong[] state)
    {
        var a = Rol(state[1], 1);
        state[1]  = Rol(state[6],  44);
        state[6]  = Rol(state[9],  20);
        state[9]  = Rol(state[22], 61);
        state[22] = Rol(state[14], 39);
        state[14] = Rol(state[20], 18);
        state[20] = Rol(state[2],  62);
        state[2]  = Rol(state[12], 43);
        state[12] = Rol(state[13], 25);
        state[13] = Rol(state[19], 8);
        state[19] = Rol(state[23], 56);
        state[23] = Rol(state[15], 41);
        state[15] = Rol(state[4],  27);
        state[4]  = Rol(state[24], 14);
        state[24] = Rol(state[21], 2);
        state[21] = Rol(state[8],  55);
        state[8]  = Rol(state[16], 45);
        state[16] = Rol(state[5],  36);
        state[5]  = Rol(state[3],  28);
        state[3]  = Rol(state[18], 21);
        state[18] = Rol(state[17], 15);
        state[17] = Rol(state[11], 10);
        state[11] = Rol(state[7],  6);
        state[7]  = Rol(state[10], 3);
        state[10] = a;
    }
    private void Iota(int round, ulong[] state)
    {
        state[0] ^= _roundConstants[round];
    }
    private static void Chi(ref ulong C0, ulong[] state, ref ulong C1, ref ulong C2, ref ulong C3, ref ulong C4)
    {
        for (var index = 0; index < 25; index += 5)
        {
            C0               = state[index]     ^ (~state[1 + index] & state[2 + index]);
            C1               = state[1 + index] ^ (~state[2 + index] & state[3 + index]);
            C2               = state[2 + index] ^ (~state[3 + index] & state[4 + index]);
            C3               = state[3 + index] ^ (~state[4 + index] & state[index]);
            C4               = state[4 + index] ^ (~state[index]     & state[1 + index]);
            state[index]     = C0;
            state[1 + index] = C1;
            state[2 + index] = C2;
            state[3 + index] = C3;
            state[4 + index] = C4;
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static ulong Rol(ulong x, byte y)
    {
        return (x << y) | (x >> (64 - y));
    }
}

BMPartialPatternSearch.cs

Boyer Moore Partial Pattern Search

using System;
using System.Collections.Generic;
public class BMPartialPatternSearch
{
    public int MinimumSearchLength;
    public BMPartialPatternSearch(int min = 5)
    {
        MinimumSearchLength = min;
    }
    public (byte[] partialPattern, int idx) SearchPartial(byte[] pattern, byte[] searchArray)
    {
        var bm   = new BoyerMoore(pattern);
        var len  = pattern.Length;
        var tree = new List<byte[]>();
        if (len < MinimumSearchLength)
            throw new Exception("Search Pattern less than minimum search length.");
        var offset = 0;
        var wl     = MinimumSearchLength;
        do
        {
            var tpat = new byte[wl];
            Array.Copy(pattern, offset, tpat, 0, wl);
            tree.Add(tpat);
            bm.SetPattern(tpat);
            var idx = bm.Search(searchArray);
            if (idx != -1)
                return (tpat, idx);
            if (offset + wl >= len)
            {
                offset = 0;
                wl++;
                continue;
            }
            offset++;
        } while (wl != len + 1);
        return (pattern, -1);
    }
    public List<(byte[] partialPattern, int idx)> SearchPartialFirst(byte[] pattern, byte[] searchArray)
    {
        var bm   = new BoyerMoore(pattern);
        var len  = pattern.Length;
        var lst  = new List<(byte[] partialPattern, int idx)>();
        var tree = new List<byte[]>();
        if (len < MinimumSearchLength)
            throw new Exception("Search Pattern less than minimum search length.");
        var offset = 0;
        var wl     = MinimumSearchLength;
        do
        {
            var tpat = new byte[wl];
            Array.Copy(pattern, offset, tpat, 0, wl);
            tree.Add(tpat);
            bm.SetPattern(tpat);
            var idx = bm.Search(searchArray);
            if (idx != -1)
                lst.Add((tpat, idx));
            if (offset + wl >= len)
            {
                offset = 0;
                wl++;
                continue;
            }
            offset++;
        } while (wl != len + 1);
        return new List<(byte[] partialPattern, int idx)> {(pattern, -1)};
    }
    public List<(byte[] partialPattern, int idx)> SearchPartialAll(byte[] pattern, byte[] searchArray)
    {
        var bm   = new BoyerMoore(pattern);
        var len  = pattern.Length;
        var lst  = new List<(byte[] partialPattern, int idx)>();
        var tree = new List<byte[]>();
        if (len < MinimumSearchLength)
            throw new Exception("Search Pattern less than minimum search length.");
        var offset = 0;
        var wl     = MinimumSearchLength;
        do
        {
            var tpat = new byte[wl];
            Array.Copy(pattern, offset, tpat, 0, wl);
            tree.Add(tpat);
            bm.SetPattern(tpat);
            var idxl = bm.SearchAll(searchArray);
            if (idxl.Item1.Count > 0)
                foreach (var idx in idxl.Item1)
                    lst.Add((tpat, idx));
            if (offset + wl >= len)
            {
                offset = 0;
                wl++;
                continue;
            }
            offset++;
        } while (wl != len + 1);
        return lst;
    }
    public static Dictionary<string, int> SearchPartialSubSet(byte[] searchArray, int startLength, int endLength)
    {
        var pattern = (byte[]) searchArray.Clone();
        var bm      = new BoyerMoore(pattern);
        var pLen    = pattern.Length;
        var lst     = new Dictionary<string, int>();
        var tree    = new List<byte[]>();
        if (pLen < endLength)
            throw new Exception("Search Pattern less than minimum search length.");
        var offset = 0;
        var wl     = startLength;
        do
        {
            var tpat = new byte[wl];
            Array.Copy(pattern, offset, tpat, 0, wl);
            tree.Add(tpat);
            bm.SetPattern(tpat);
            var idxl = bm.SearchAll(searchArray);
            if (idxl.Item1.Count > 1)
            {
                var sapat = tpat.ToHexString();
                if (!lst.ContainsKey(sapat))
                    lst.Add(sapat, idxl.Item1.Count);
            }
            if (offset + wl >= pLen)
            {
                offset = 0;
                wl++;
                if (wl > endLength)
                    break;
                continue;
            }
            offset++;
        } while (wl != pLen + 1);
        return lst;
    }
    public static Dictionary<string, int> SearchPartialSubSet(byte[] searchArray1, byte[] searchArray2, int startLength, int endLength)
    {
        var bm   = new BoyerMoore(searchArray2);
        var pLen = searchArray2.Length;
        var lst  = new Dictionary<string, int>();
        var tree = new List<byte[]>();
        if (pLen < endLength)
            throw new Exception("Search Pattern less than minimum search length.");
        var offset = 0;
        var wl     = startLength;
        do
        {
            var tpat = new byte[wl];
            Array.Copy(searchArray2, offset, tpat, 0, wl);
            tree.Add(tpat);
            bm.SetPattern(tpat);
            var idxl = bm.SearchAll(searchArray1);
            if (idxl.Item1.Count > 1)
            {
                var sapat = tpat.ToHexString();
                if (!lst.ContainsKey(sapat))
                    lst.Add(sapat, idxl.Item1.Count);
            }
            if (offset + wl >= pLen)
            {
                offset = 0;
                wl++;
                if (wl > endLength)
                    break;
                continue;
            }
            offset++;
        } while (wl != pLen + 1);
        return lst;
    }
}

BoyerMoore.cs

Boyer Moore Search Algorithm

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class BoyerMoore
{
    private int[]  _jumpTable;
    private byte[] _pattern;
    private int    _patternLength;
    public BoyerMoore()
    {
    }
    public BoyerMoore(byte[] pattern)
    {
        SetPattern(pattern);
    }
    public void SetPattern(byte[] pattern)
    {
        _pattern       = pattern;
        _jumpTable     = new int[256];
        _patternLength = _pattern.Length;
        for (var index = 0; index < 256; index++)
            _jumpTable[index] = _patternLength;
        for (var index = 0; index < _patternLength - 1; index++)
            _jumpTable[_pattern[index]] = _patternLength - index - 1;
    }
    public unsafe int Search(byte[] searchArray, int startIndex = 0)
    {
        if (_pattern == null)
            throw new Exception("Pattern has not been set.");
        if (_patternLength > searchArray.Length)
            throw new Exception("Search Pattern length exceeds search array length.");
        var index                 = startIndex;
        var limit                 = searchArray.Length - _patternLength;
        var patternLengthMinusOne = _patternLength     - 1;
        var Moves                 = 0;
        fixed (byte* pointerToByteArray = searchArray)
        {
            var pointerToByteArrayStartingIndex = pointerToByteArray + startIndex;
            fixed (byte* pointerToPattern = _pattern)
            {
                while (index <= limit)
                {
                    var j = patternLengthMinusOne;
                    while (j >= 0 && pointerToPattern[j] == pointerToByteArrayStartingIndex[index + j])
                        j--;
                    if (j < 0)
                        return index;
                    index += Math.Max(_jumpTable[pointerToByteArrayStartingIndex[index + j]] - _patternLength + 1 + j,
                        1);
                    Moves++;
                }
            }
        }
        return -1;
    }
    public unsafe (List<int>, int) SearchAll(byte[] searchArray, int startIndex = 0)
    {
        if (_pattern == null)
            throw new Exception("Pattern has not been set.");
        if (_patternLength > searchArray.Length)
            throw new Exception("Search Pattern length exceeds search array length.");
        var index                 = startIndex;
        var limit                 = searchArray.Length - _patternLength;
        var patternLengthMinusOne = _patternLength     - 1;
        var list                  = new List<int>();
        var Moves                 = 0;
        fixed (byte* pointerToByteArray = searchArray)
        {
            var pointerToByteArrayStartingIndex = pointerToByteArray + startIndex;
            fixed (byte* pointerToPattern = _pattern)
            {
                while (index <= limit)
                {
                    var j = patternLengthMinusOne;
                    while (j >= 0 && pointerToPattern[j] == pointerToByteArrayStartingIndex[index + j])
                        j--;
                    if (j < 0)
                        list.Add(index);
                    index += Math.Max(_jumpTable[pointerToByteArrayStartingIndex[index + j]] - _patternLength + 1 + j,
                        1);
                    Moves++;
                }
            }
        }
        return (list, Moves);
    }
    public int SuperSearch(byte[] searchArray, int nth, int start = 0)
    {
        var e = start;
        var c = 0;
        do
        {
            e = Search(searchArray, e);
            if (e == -1)
                return -1;
            c++;
            e++;
        } while (c < nth);
        return e - 1;
    }
    public static bool ContainsAny(byte[] sPattern, params byte[][] list)
    {
        return list.Select(v => new BoyerMoore(v)).Any(bm => bm.Search(sPattern) != -1);
    }
    public static bool ContainsAny(string sPattern, params string[] list)
    {
        return list.Select(s => new BoyerMoore(s.ToLower().GetBytes(Encoding.ASCII)))
            .Any(bm => bm.Search(sPattern.ToLower().GetBytes(Encoding.ASCII)) != -1);
    }
    }

MemoryBitmap.cs

Direct Access Pixel Data, GetPixel, SetPixel

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
public unsafe class MemoryBitmap : IDisposable
{
    private readonly BitmapData _bmpData;
    private readonly int        _depth;
    private readonly byte*      _pfp;
    private readonly int        _stride;
    private          Bitmap     _memoryBitmap;
    public MemoryBitmap(string path)
    {
        if (path.IsNullOrEmpty())
            throw new Exception("Path cannot be null or empty.");
        if (!File.Exists(path))
            throw new Exception($"Path {path} does not exist.");
        var bitmap = new Bitmap(path);
        _memoryBitmap = bitmap;
        if (_memoryBitmap.PixelFormat != PixelFormat.Format32bppArgb && _memoryBitmap.PixelFormat != PixelFormat.Format24bppRgb && _memoryBitmap.PixelFormat != PixelFormat.Format8bppIndexed)
        {
            var clone = new Bitmap(_memoryBitmap.Width, _memoryBitmap.Height, PixelFormat.Format32bppArgb);
            using (var gr = Graphics.FromImage(clone))
            {
                gr.DrawImage(_memoryBitmap, new Rectangle(0, 0, clone.Width, clone.Height));
                _memoryBitmap = clone;
            }
        }
        Width  = _memoryBitmap.Width;
        Height = _memoryBitmap.Height;
        var rect = new Rectangle(0, 0, _memoryBitmap.Width, _memoryBitmap.Height);
        try
        {
            _bmpData = _memoryBitmap.LockBits(rect, ImageLockMode.ReadWrite, _memoryBitmap.PixelFormat);
        }
        catch (Exception ex)
        {
            throw new Exception("Could not lock bitmap", ex.InnerException);
        }
        _depth  = Image.GetPixelFormatSize(_bmpData.PixelFormat) / 8;
        _pfp    = (byte*) _bmpData.Scan0.ToPointer();
        _stride = _bmpData.Stride;
    }
    public MemoryBitmap(Bitmap bitmap)
    {
        _memoryBitmap = bitmap ?? throw new Exception("Bitmap cannot be null");
        if (_memoryBitmap.PixelFormat != PixelFormat.Format32bppArgb && _memoryBitmap.PixelFormat != PixelFormat.Format24bppRgb && _memoryBitmap.PixelFormat != PixelFormat.Format8bppIndexed)
        {
            var clone = new Bitmap(_memoryBitmap.Width, _memoryBitmap.Height, PixelFormat.Format32bppArgb);
            using (var gr = Graphics.FromImage(clone))
            {
                gr.DrawImage(_memoryBitmap, new Rectangle(0, 0, clone.Width, clone.Height));
                _memoryBitmap = clone;
            }
        }
        Width  = _memoryBitmap.Width;
        Height = _memoryBitmap.Height;
        var rect = new Rectangle(0, 0, _memoryBitmap.Width, _memoryBitmap.Height);
        try
        {
            _bmpData = _memoryBitmap.LockBits(rect, ImageLockMode.ReadWrite, _memoryBitmap.PixelFormat);
        }
        catch (Exception ex)
        {
            throw new Exception("Could not lock bitmap", ex.InnerException);
        }
        _depth  = Image.GetPixelFormatSize(_bmpData.PixelFormat) / 8;
        _pfp    = (byte*) _bmpData.Scan0.ToPointer();
        _stride = _bmpData.Stride;
    }
    public int Width
    {
        get;
    }
    public int Height
    {
        get;
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    public void ConvertFormat(PixelFormat newPf)
    {
        var clone = new Bitmap(_memoryBitmap.Width, _memoryBitmap.Height, newPf);
        using (var gr = Graphics.FromImage(clone))
        {
            gr.DrawImage(_memoryBitmap, new Rectangle(0, 0, clone.Width, clone.Height));
            _memoryBitmap = clone;
        }
    }
    public void Save(string path)
    {
        _memoryBitmap.Save(path);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!disposing)
            return;
        if (_memoryBitmap != null)
            _memoryBitmap.UnlockBits(_bmpData);
    }
    private byte* PixelPointer(int x, int y)
    {
        return _pfp + y * _stride + x * _depth;
    }
    public Color GetPixel(int x, int y)
    {
        if (x < 0 || y < 0 || x >= Width || y >= Height)
            throw new Exception("Coordinates out of range");
        int a, r, g, b;
        var p = PixelPointer(x, y);
        if (_memoryBitmap.PixelFormat == PixelFormat.Format32bppArgb)
        {
            b = *p++;
            g = *p++;
            r = *p++;
            a = *p;
            return Color.FromArgb(a, r, g, b);
        }
        if (_memoryBitmap.PixelFormat == PixelFormat.Format24bppRgb)
        {
            b = *p++;
            g = *p++;
            r = *p;
            return Color.FromArgb(r, g, b);
        }
        if (_memoryBitmap.PixelFormat == PixelFormat.Format8bppIndexed)
        {
            a = *p;
            return Color.FromArgb(a, a, a);
        }
        return default;
    }
    public void SetPixel(int x, int y, Color col)
    {
        if (x < 0 || y < 0 || x >= Width || y >= Height)
            throw new Exception("Coordinates out of range");
        var p = PixelPointer(x, y);
        if (_memoryBitmap.PixelFormat == PixelFormat.Format32bppArgb)
        {
            *p++ = col.B;
            *p++ = col.G;
            *p++ = col.R;
            *p   = col.A;
            return;
        }
        if (_memoryBitmap.PixelFormat == PixelFormat.Format24bppRgb)
        {
            *p++ = col.B;
            *p++ = col.G;
            *p   = col.R;
            return;
        }
        if (_memoryBitmap.PixelFormat == PixelFormat.Format8bppIndexed)
            *p = col.B;
    }
}

Lz77.cs

LZ77 Compression Algorithm

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public static class Lz77
{
    private const           int      RingBufferSize   = 1024 * 4;
    private const           int      UpperMatchLength = 18;
    private const           int      LowerMatchLength = 3;
    private const           int      None             = RingBufferSize;
    private static readonly int[]    Parent           = new int[RingBufferSize                       + 1];
    private static readonly int[]    LeftChild        = new int[RingBufferSize                       + 1];
    private static readonly int[]    RightChild       = new int[RingBufferSize                       + 257];
    private static readonly ushort[] Buffer           = new ushort[RingBufferSize + UpperMatchLength - 1];
    private static          int      matchPosition, matchLength;
    /// <summary>
    ///     Size of the compressed code during and after compression
    /// </summary>
    public static int CompressedSize
    {
        get;
        set;
    }
    /// <summary>
    ///     Size of the original code packet while decompressing
    /// </summary>
    public static int DeCompressedSize
    {
        get;
        set;
    }
    public static double Ratio => (double) CompressedSize / DeCompressedSize * 100.0;
    public static byte[] Lz77Decompress(this byte[] ins)
    {
        if (ins == null)
            throw new Exception("Input buffer is null.");
        if (ins.Length == 0)
            throw new Exception("Input buffer is empty.");
        var outa = new GArray<byte>();
        var ina  = new GArray<byte>(ins);
        CompressedSize   = 0;
        DeCompressedSize = ina.Read(4).ToInt();
        for (var i = 0; i < RingBufferSize - UpperMatchLength; i++)
            Buffer[i] = 0;
        var  r     = RingBufferSize - UpperMatchLength;
        uint flags = 7;
        var  z     = 7;
        while (true)
        {
            flags <<= 1;
            z++;
            if (z == 8)
            {
                if (ina.ReadEnd)
                    break;
                flags = ina.Read();
                z     = 0;
            }
            if ((flags & 0x80) == 0)
            {
                if (ina.ReadEnd)
                    break;
                var c = ina.Read();
                if (CompressedSize < DeCompressedSize)
                    outa.Write(c);
                Buffer[r++] =  c;
                r           &= RingBufferSize - 1;
                CompressedSize++;
            }
            else
            {
                if (ina.ReadEnd)
                    break;
                int i = ina.Read();
                if (ina.ReadEnd)
                    break;
                int j = ina.Read();
                j = j | ((i << 8) & 0xF00);
                i = ((i     >> 4) & 0xF) + LowerMatchLength;
                for (var k = 0; k <= i; k++)
                {
                    var c = Buffer[(r - j - 1) & (RingBufferSize - 1)];
                    if (CompressedSize < DeCompressedSize)
                        outa.Write((byte) c);
                    Buffer[r++] =  (byte) c;
                    r           &= RingBufferSize - 1;
                    CompressedSize++;
                }
            }
        }
        return outa.ToArray();
    }
    /// <summary>
    ///     E:12.5, R:17.3 E:25.0, R:35.9 E:32.3, R:47.7 E:37.5, R:56.5 E:41.5, R:63.0 E:44.8, R:67.6 E:47.6, R:71.7 E:50.0,
    ///     R:75.8 E:52.1, R:79.9 E:54.0, R:83.9 E:55.7, R:87.7
    ///     E:57.3, R:91.0 E:58.8, R:93.9 E:60.1, R:96.6 E:61.3, R:98.8 E:62.5, R:100.6 E:63.6, R:102.1 E:64.6, R:103.5 E:65.6,
    ///     R:104.7 E:66.5, R:105.6 E:67.4, R:106.5
    ///     E:68.2, R:107.2 E:69.0, R:107.8 E:69.8, R:108.3 E:70.5, R:108.7
    /// </summary>
    public static byte[] Lz77Compress(this byte[] ins, bool TestForCompressibility = false)
    {
        if (ins == null)
            throw new Exception("Input buffer is null.");
        if (ins.Length == 0)
            throw new Exception("Input buffer is empty.");
        if (TestForCompressibility)
            if ((int) Entropy(ins) > 61)
                throw new Exception("Input buffer Cannot be compressed.");
        matchLength      = 0;
        matchPosition    = 0;
        CompressedSize   = 0;
        DeCompressedSize = ins.Length;
        int length;
        var codeBuffer = new int[UpperMatchLength - 1];
        var outa       = new GArray<byte>();
        var ina        = new GArray<byte>(ins);
        outa.Write(DeCompressedSize.GetBytes(0, 4));
        InitTree();
        codeBuffer[0] = 0;
        var codeBufferPointer = 1;
        var mask              = 0x80;
        var s                 = 0;
        var r                 = RingBufferSize - UpperMatchLength;
        for (var i = s; i < r; i++)
            Buffer[i] = 0xFFFF;
        for (length = 0; length < UpperMatchLength && !ina.ReadEnd; length++)
            Buffer[r + length] = ina.Read();
        if (length == 0)
            throw new Exception("No Data to Compress.");
        for (var i = 1; i <= UpperMatchLength; i++)
            InsertNode(r - i);
        InsertNode(r);
        do
        {
            if (matchLength > length)
                matchLength = length;
            if (matchLength <= LowerMatchLength)
            {
                matchLength                     = 1;
                codeBuffer[codeBufferPointer++] = Buffer[r];
            }
            else
            {
                codeBuffer[0]                   |= mask;
                codeBuffer[codeBufferPointer++] =  (byte) (((r - matchPosition - 1) >> 8) & 0xF) | ((matchLength - (LowerMatchLength + 1)) << 4);
                codeBuffer[codeBufferPointer++] =  (byte) ((r - matchPosition                                    - 1) & 0xFF);
            }
            if ((mask >>= 1) == 0)
            {
                for (var i = 0; i < codeBufferPointer; i++)
                    outa.Write((byte) codeBuffer[i]);
                CompressedSize    += codeBufferPointer;
                codeBuffer[0]     =  0;
                codeBufferPointer =  1;
                mask              =  0x80;
            }
            var lastMatchLength = matchLength;
            var ii              = 0;
            for (ii = 0; ii < lastMatchLength && !ina.ReadEnd; ii++)
            {
                DeleteNode(s);
                var c = ina.Read();
                Buffer[s] = c;
                if (s < UpperMatchLength - 1)
                    Buffer[s + RingBufferSize] = c;
                s = (s + 1) & (RingBufferSize - 1);
                r = (r + 1) & (RingBufferSize - 1);
                InsertNode(r);
            }
            while (ii++ < lastMatchLength)
            {
                DeleteNode(s);
                s = (s + 1) & (RingBufferSize - 1);
                r = (r + 1) & (RingBufferSize - 1);
                if (--length != 0)
                    InsertNode(r);
            }
        } while (length > 0);
        if (codeBufferPointer > 1)
        {
            for (var i = 0; i < codeBufferPointer; i++)
                outa.Write((byte) codeBuffer[i]);
            CompressedSize += codeBufferPointer;
        }
        if (CompressedSize % 4 != 0)
            for (var i = 0; i < 4 - CompressedSize % 4; i++)
                outa.Write(0);
        return outa.ToArray();
    }
    private static void InitTree()
    {
        for (var i = RingBufferSize + 1; i <= RingBufferSize + 256; i++)
            RightChild[i] = None;
        for (var i = 0; i < RingBufferSize; i++)
            Parent[i] = None;
    }
    private static void InsertNode(int r)
    {
        var cmp                      = 1;
        var p                        = RingBufferSize + 1 + (Buffer[r] == 0xFFFF ? 0 : Buffer[r]);
        RightChild[r] = LeftChild[r] = None;
        matchLength   = 0;
        while (true)
        {
            if (cmp >= 0)
            {
                if (RightChild[p] != None)
                {
                    p = RightChild[p];
                }
                else
                {
                    RightChild[p] = r;
                    Parent[r]     = p;
                    return;
                }
            }
            else
            {
                if (LeftChild[p] != None)
                {
                    p = LeftChild[p];
                }
                else
                {
                    LeftChild[p] = r;
                    Parent[r]    = p;
                    return;
                }
            }
            int i;
            for (i = 1; i < UpperMatchLength; i++)
                if ((cmp = Buffer[r + i] - Buffer[p + i]) != 0)
                    break;
            if (i > matchLength)
            {
                matchPosition = p;
                if ((matchLength = i) >= UpperMatchLength)
                    break;
            }
        }
        Parent[r]             = Parent[p];
        LeftChild[r]          = LeftChild[p];
        RightChild[r]         = RightChild[p];
        Parent[LeftChild[p]]  = r;
        Parent[RightChild[p]] = r;
        if (RightChild[Parent[p]] == p)
            RightChild[Parent[p]] = r;
        else LeftChild[Parent[p]] = r;
        Parent[p] = None;
    }
    private static void DeleteNode(int p)
    {
        int q;
        if (Parent[p] == None)
            return;
        if (RightChild[p] == None)
        {
            q = LeftChild[p];
        }
        else if (LeftChild[p] == None)
        {
            q = RightChild[p];
        }
        else
        {
            q = LeftChild[p];
            if (RightChild[q] != None)
            {
                do
                {
                    q = RightChild[q];
                } while (RightChild[q] != None);
                RightChild[Parent[q]] = LeftChild[q];
                Parent[LeftChild[q]]  = Parent[q];
                LeftChild[q]          = LeftChild[p];
                Parent[LeftChild[p]]  = q;
            }
            RightChild[q]         = RightChild[p];
            Parent[RightChild[p]] = q;
        }
        Parent[q] = Parent[p];
        if (RightChild[Parent[p]] == p)
            RightChild[Parent[p]] = q;
        else LeftChild[Parent[p]] = q;
        Parent[p] = None;
    }
    private static double Entropy(byte[] ba)
    {
        var map = new Dictionary<byte, int>();
        foreach (var c in ba)
            if (!map.ContainsKey(c))
                map.Add(c, 1);
            else
                map[c]++;
        double Len = ba.Length;
        var    re  = map.Select(item => item.Value / Len).Aggregate(0.0, (current, frequency) => current - frequency * (Math.Log(frequency) / Math.Log(2)));
        return re / 8.00D * 100D;
    }
}

FixedBigIntegerRandomNumberGenerator.cs

Fixed BigInteger Random Number Generator

using System;
using System.Security.Cryptography;
public class FixedBigIntegerRandomNumberGenerator : RandomNumberGenerator
{
    private readonly int             _bitWidthHold;
    private readonly byte[]          _buffer;
    private readonly JitterCacheRng  _crng;
    private readonly BigDecimal      _dBi;
    private readonly FixedBigInteger _maxValueHold = new FixedBigInteger(0, 0);
    public FixedBigIntegerRandomNumberGenerator(int bitWidth)
    {
        if (bitWidth < 32)
            bitWidth = 32;
        var maxValue = GetMaxValue(bitWidth);
        var vdp      = maxValue.GetDecimalPlaces();
        if (vdp > BigDecimal.MaxPrecision)
            BigDecimal.MaxPrecision = vdp;
        _bitWidthHold = bitWidth;
        if (_bitWidthHold < 32)
            _bitWidthHold = 32;
        _maxValueHold = maxValue;
        _dBi          = BigDecimal.One / (BigDecimal) maxValue;
        _buffer       = new byte[_bitWidthHold >> 3];
        _crng         = new JitterCacheRng(1000000);
    }
    public FixedBigIntegerRandomNumberGenerator(int bitWidth, int cacheSize)
    {
        if (bitWidth < 32)
            bitWidth = 32;
        var maxValue = GetMaxValue(bitWidth);
        var vdp      = maxValue.GetDecimalPlaces();
        if (vdp > BigDecimal.MaxPrecision)
            BigDecimal.MaxPrecision = vdp;
        _bitWidthHold = bitWidth;
        if (_bitWidthHold < 32)
            _bitWidthHold = 32;
        _maxValueHold = maxValue;
        _dBi          = BigDecimal.One / (BigDecimal) maxValue;
        _buffer       = new byte[_bitWidthHold >> 3];
        _crng         = new JitterCacheRng(cacheSize);
    }
    public bool OddsOnly
    {
        get;
        set;
    }
    public bool Unsigned
    {
        get;
        set;
    }
    protected override void Dispose(bool disposing)
    {
        _crng.Dispose();
    }
    private FixedBigInteger GetMaxValue(int bitWidth)
    {
        var r = new FixedBigInteger(0, bitWidth);
        for (var i = 0; i < r.Data.Length; ++i)
            r.Data[i] = uint.MaxValue;
        r.Data[r.Data.Length - 1] = int.MaxValue;
        return r;
    }
    private FixedBigInteger GetMaxValue()
    {
        var r = new FixedBigInteger(0, _bitWidthHold);
        for (var i = 0; i < r.Data.Length; ++i)
            r.Data[i] = uint.MaxValue;
        r.Data[r.Data.Length - 1] = int.MaxValue;
        return r;
    }
    private BigDecimal Sample()
    {
        FixedBigInteger Internal()
        {
            _crng.GetBytes(_buffer);
            var n = new FixedBigInteger(_buffer, _bitWidthHold);
            return !OddsOnly ? n : n | 1;
        }
        var s = (BigDecimal) Internal() * _dBi;
        if (s.Sign == -1)
            s = s * -1;
        if (s.IsZero)
            throw new Exception("Sample is zero. SEE: MaxPrecision in BigDecimal.cs. Default value is 308.");
        return s;
    }
    public FixedBigInteger Next(FixedBigInteger minValue, FixedBigInteger maxValue)
    {
        var sa = Sample();
        var fi = (BigDecimal) (maxValue - minValue + minValue);
        var n  = new FixedBigInteger(sa * fi, 0);
        n = !OddsOnly ? n : n | 1;
        if (Unsigned)
            return n.Sign < 0 ? new FixedBigInteger(1, n.Data, 0) : n;
        var buffer = new byte[1];
        _crng.GetBytes(buffer);
        if (buffer[0] > 127)
            return n.Sign < 0 ? n : new FixedBigInteger(-1, n.Data, 0);
        return n.Sign < 0 ? new FixedBigInteger(1, n.Data, 0) : n;
    }
    public FixedBigInteger Next(FixedBigInteger maxValue)
    {
        return Next(0, maxValue);
    }
    public FixedBigInteger Next()
    {
        return Next(0, _maxValueHold);
    }
    public override void GetBytes(byte[] data)
    {
        if (data == null)
            throw new ArgumentException("The buffer cannot be null.");
        _crng.GetBytes(data);
    }
    public void NextBytes(byte[] buffer)
    {
        if (buffer == null)
            throw new ArgumentNullException("The buffer cannot be null.");
        for (var index = 0; index < buffer.Length; ++index)
            buffer[index] = (byte) (Sample() * byte.MaxValue);
    }
    public FixedBigInteger[] Next(FixedBigInteger minValue, FixedBigInteger maxValue, int arraySize)
    {
        var array = new FixedBigInteger[arraySize];
        for (var i = 0; i < arraySize; ++i)
            array[i] = Next(minValue, maxValue);
        return array;
    }
    public char[] GetNextCharArray(int size)
    {
        var ca  = new char[size];
        var ptr = 0;
        do
        {
            ca[ptr++] = (char) Next(32, 128);
        } while (ptr < size);
        return ca;
    }
    public byte[] GetNextByteArray(int size)
    {
        var ba = new byte[size];
        _crng.GetBytes(ba);
        return ba;
    }
    public string GetRandomString(int minLen, int maxLen)
    {
        if (minLen == maxLen)
            return new string(GetNextCharArray(minLen));
        return new string(GetNextCharArray((int) Next((uint) minLen, (uint) maxLen)));
    }
}

ChiSquaredImageComparison.cs

Chi Squared Image Comparison (Work In Progress)

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
public class ChiSquaredImageComparison
{
    private readonly int[]                               _expectedHistogram  = new int[256];
    private readonly ConcurrentDictionary<string, float> _finalDistList      = new ConcurrentDictionary<string, float>();
    private          ConcurrentDictionary<string, int[]> _observedHistograms = new ConcurrentDictionary<string, int[]>();
    private volatile float                               c, p, t, s1, s2;
    private volatile int                                 ExpectedLength;
    private volatile int                                 ExpectedMetric;
    private volatile int                                 XYExpectedLength;
    public void SetExpectedHistogram(string path)
    {
        try
        {
            using (var org = new Bitmap(path))
            {
                using (var img = new MemoryBitmap(org))
                {
                    XYExpectedLength = img.Height * img.Width;
                    for (var y = 0; y < img.Height; y++)
                    for (var x = 0; x < img.Width; x++)
                    {
                        var pixel = img.GetPixel(x, y);
                        _expectedHistogram[(pixel.R + pixel.G + pixel.B) / 3]++;
                    }
                }
            }
        }
        catch
        {
        }
        ExpectedLength = _expectedHistogram.Sum(e => e);
        ExpectedMetric = _expectedHistogram.Count(e => e > 0);
    }
    public void BuildHistograms(EnumBase.IEnumBase[] paths)
    {
        if (File.Exists(LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin"))
        {
            var file = LoadFromFile(LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin");
            _observedHistograms = new ConcurrentDictionary<string, int[]>(file);
            var list1 = paths.Select(e => e.PathString).ToList();
            var list2 = file.Select(e => e.Key).ToList();
            var list3 = list1.Except(list2).ToArray();
            foreach (var e in list3)
                try
                {
                    using (var org = new Bitmap(e))
                    {
                        var observedHistogram = new int[256];
                        using (var img = new MemoryBitmap(org))
                        {
                            c++;
                            p = c / t * 100f;
                            for (var y = 0; y < img.Height; y++)
                            for (var x = 0; x < img.Width; x++)
                            {
                                var pixel = img.GetPixel(x, y);
                                observedHistogram[(pixel.R + pixel.G + pixel.B) / 3]++;
                            }
                            if (!_observedHistograms.ContainsKey(e))
                                _observedHistograms.TryAdd(e, observedHistogram);
                        }
                    }
                }
                catch
                {
                }
        }
        else
        {
            t = paths.Length;
            paths.AsParallel().WithDegreeOfParallelism(8).ForAll(i =>
            {
                try
                {
                    using (var org = new Bitmap(i.PathString))
                    {
                        var observedHistogram = new int[256];
                        using (var img = new MemoryBitmap(org))
                        {
                            c++;
                            p = c / t * 100f;
                            for (var y = 0; y < img.Height; y++)
                            for (var x = 0; x < img.Width; x++)
                            {
                                var pixel = img.GetPixel(x, y);
                                observedHistogram[(pixel.R + pixel.G + pixel.B) / 3]++;
                            }
                            _observedHistograms.TryAdd(i.PathString, observedHistogram);
                        }
                    }
                }
                catch
                {
                }
            });
        }
        var kpa = _observedHistograms.ToArray();
        SaveToFile(kpa, LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin");
    }
    public void SaveToFile(KeyValuePair<string, int[]>[] kpa, string path)
    {
        using (var wrtr = new Writer(path))
        {
            foreach (var i in kpa)
            {
                var k = i.Key;
                var v = i.Value;
                wrtr.WriteString(k);
                wrtr.WriteInts(v);
            }
        }
    }
    public KeyValuePair<string, int[]>[] LoadFromFile(string path)
    {
        var kpd = new Dictionary<string, int[]>();
        using (var reader = new Reader(path))
        {
            while (true)
                try
                {
                    var k = reader.ReadString();
                    var v = reader.ReadInts();
                    kpd.Add(k, v);
                }
                catch
                {
                    return kpd.ToArray();
                }
        }
        return kpd.ToArray();
    }
    public ConcurrentDictionary<string, float> HistogramChiSquared(EnumBase.IEnumBase[] paths)
    {
        t = paths.Length;
        paths.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 2).ForAll(i =>
        {
            try
            {
                using (var org = new Bitmap(i.PathString))
                {
                    var observedHistogram = new int[256];
                    using (var img = new MemoryBitmap(org))
                    {
                        c++;
                        p = c / t * 100f;
                        var XYObservedLength = img.Height * img.Width;
                        if (XYObservedLength != XYExpectedLength)
                        {
                            s1++;
                            return;
                        }
                        for (var y = 0; y < img.Height; y++)
                        for (var x = 0; x < img.Width; x++)
                        {
                            var pixel = img.GetPixel(x, y);
                            observedHistogram[(pixel.R + pixel.G + pixel.B) / 3]++;
                        }
                        var observedLength = observedHistogram.Sum(e => e);
                        if (observedLength > ExpectedLength)
                        {
                            s2++;
                            return;
                        }
                        var ChiSqrd = 0.0f;
                        for (var j = 0; j < 256; j++)
                            if (_expectedHistogram[j] + observedHistogram[j] != 0)
                                ChiSqrd += (float) Math.Pow(_expectedHistogram[j] - observedHistogram[j], 2) / (_expectedHistogram[j] + observedHistogram[j]);
                        var fp = Math.Abs(ChiSqrd / ExpectedLength * 100f);
                        if (fp >= 0 && fp < 15)
                            _finalDistList.TryAdd(i.PathString, fp);
                    }
                }
            }
            catch
            {
            }
        });
        return _finalDistList;
    }
    public ConcurrentDictionary<string, float> LoadedHistogramChiSquared()
    {
        var file = LoadFromFile(LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin");
        t = file.Length;
        file.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 2).ForAll(i =>
        {
            try
            {
                c++;
                p = c / t * 100f;
                var d = 0.0f;
                for (var j = 0; j < 256; j++)
                {
                    var e = _expectedHistogram[j];
                    var o = i.Value[j];
                    if (e + o != 0)
                        d += (float) Math.Pow(e - o, 2) / (e + o);
                }
                var dd = d / 100;
                if (dd >= 0 && dd < 500)
                    _finalDistList.TryAdd(i.Key, dd);
            }
            catch
            {
            }
        });
        var srt = _finalDistList.OrderBy(x => x.Value);
        return _finalDistList;
    }
    public ConcurrentDictionary<string, float> LoadedHistogramIntersection()
    {
        var file = LoadFromFile(LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin");
        t = file.Length;
        file.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 2).ForAll(i =>
        {
            try
            {
                c++;
                p = c / t * 100f;
                var d = 0.0f;
                for (var j = 0; j < 256; j++)
                {
                    var e = _expectedHistogram[j];
                    var o = i.Value[j];
                    d += e + o - Math.Abs(e - o);
                }
                var observedLength = i.Value.Sum(e => e);
                var dd             = 0.5f * d / Math.Max(ExpectedLength, observedLength);
                if (d >= 0 && d < 5)
                    _finalDistList.TryAdd(i.Key, d);
            }
            catch
            {
            }
        });
        var srt = _finalDistList.OrderBy(x => x.Value);
        return _finalDistList;
    }
}