/// <summary>
        /// Get what type of DAT the input file is
        /// </summary>
        /// <param name="filename">Name of the file to be parsed</param>
        /// <returns>The DatFormat corresponding to the DAT</returns>
        public static DatFormat GetDatFormat(this string filename)
        {
            // Limit the output formats based on extension
            if (!PathExtensions.HasValidDatExtension(filename))
                return 0;

            // Get the extension from the filename
            string ext = PathExtensions.GetNormalizedExtension(filename);

            // Read the input file, if possible
            logger.Verbose($"Attempting to read file to get format: {filename}");

            // Check if file exists
            if (!File.Exists(filename))
            {
                logger.Warning($"File '{filename}' could not read from!");
                return 0;
            }

            // Some formats should only require the extension to know
            switch (ext)
            {
                case "csv":
                    return DatFormat.CSV;
                case "json":
                    return DatFormat.SabreJSON;
                case "md5":
                    return DatFormat.RedumpMD5;
#if NET_FRAMEWORK
                case "ripemd160":
                    return DatFormat.RedumpRIPEMD160;
#endif
                case "sfv":
                    return DatFormat.RedumpSFV;
                case "sha1":
                    return DatFormat.RedumpSHA1;
                case "sha256":
                    return DatFormat.RedumpSHA256;
                case "sha384":
                    return DatFormat.RedumpSHA384;
                case "sha512":
                    return DatFormat.RedumpSHA512;
                case "spamsum":
                    return DatFormat.RedumpSpamSum;
                case "ssv":
                    return DatFormat.SSV;
                case "tsv":
                    return DatFormat.TSV;
            }

            // For everything else, we need to read it
            try
            {
                // Get the first two non-whitespace, non-comment lines to check, if possible
                string first = string.Empty, second = string.Empty;

                try
                {
                    using (StreamReader sr = File.OpenText(filename))
                    {
                        first = sr.ReadLine().ToLowerInvariant();
                        while ((string.IsNullOrWhiteSpace(first) || first.StartsWith("<!--"))
                            && !sr.EndOfStream)
                        {
                            first = sr.ReadLine().ToLowerInvariant();
                        }

                        if (!sr.EndOfStream)
                        {
                            second = sr.ReadLine().ToLowerInvariant();
                            while (string.IsNullOrWhiteSpace(second) || second.StartsWith("<!--")
                                && !sr.EndOfStream)
                            {
                                second = sr.ReadLine().ToLowerInvariant();
                            }
                        }
                    }
                }
                catch { }

                // If we have an XML-based DAT
                if (first.Contains("<?xml") && first.Contains("?>"))
                {
                    if (second.StartsWith("<!doctype datafile"))
                        return DatFormat.Logiqx;

                    else if (second.StartsWith("<!doctype mame")
                        || second.StartsWith("<!doctype m1")
                        || second.StartsWith("<mame")
                        || second.StartsWith("<m1"))
                        return DatFormat.Listxml;

                    else if (second.StartsWith("<!doctype softwaredb"))
                        return DatFormat.OpenMSX;

                    else if (second.StartsWith("<!doctype softwarelist"))
                        return DatFormat.SoftwareList;

                    else if (second.StartsWith("<!doctype sabredat"))
                        return DatFormat.SabreXML;

                    else if ((second.StartsWith("<dat") && !second.StartsWith("<datafile"))
                        || second.StartsWith("<?xml-stylesheet"))
                        return DatFormat.OfflineList;

                    // Older and non-compliant DATs
                    else
                        return DatFormat.Logiqx;
                }

                // If we have an SMDB (SHA-256, Filename, SHA-1, MD5, CRC32)
                else if (Regex.IsMatch(first, @"[0-9a-f]{64}\t.*?\t[0-9a-f]{40}\t[0-9a-f]{32}\t[0-9a-f]{8}"))
                    return DatFormat.EverdriveSMDB;

                // If we have an INI-based DAT
                else if (first.Contains("[") && first.Contains("]"))
                    return DatFormat.RomCenter;

                // If we have a listroms DAT
                else if (first.StartsWith("roms required for driver"))
                    return DatFormat.Listrom;

                // If we have a CMP-based DAT
                else if (first.Contains("clrmamepro"))
                    return DatFormat.ClrMamePro;

                else if (first.Contains("romvault"))
                    return DatFormat.ClrMamePro;

                else if (first.Contains("doscenter"))
                    return DatFormat.DOSCenter;

                else if (first.Contains("#Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra"))
                    return DatFormat.AttractMode;

                else
                    return DatFormat.ClrMamePro;
            }
            catch (Exception ex)
            {
                logger.Warning(ex, $"An exception occurred trying to figure out the format of '{filename}'");
                return 0;
            }
        }
        /// <summary>
        /// Returns the file type of an input file
        /// </summary>
        /// <param name="input">Input file to check</param>
        /// <returns>FileType of inputted file (null on error)</returns>
        public static FileType? GetFileType(this string input)
        {
            FileType? outFileType = null;

            // If the file is null, then we have no archive type
            if (input == null)
                return outFileType;

            // First line of defense is going to be the extension, for better or worse
            if (!PathExtensions.HasValidArchiveExtension(input))
                return outFileType;

            // Read the first bytes of the file and get the magic number
            try
            {
                byte[] magic = new byte[8];
                BinaryReader br = new BinaryReader(TryOpenRead(input));
                magic = br.ReadBytes(8);
                br.Dispose();

                // Now try to match it to a known signature
                if (magic.StartsWith(Constants.SevenZipSignature))
                {
                    outFileType = FileType.SevenZipArchive;
                }
                else if (magic.StartsWith(Constants.AaruFormatSignature))
                {
                    outFileType = FileType.AaruFormat;
                }
                else if (magic.StartsWith(Constants.CHDSignature))
                {
                    outFileType = FileType.CHD;
                }
                else if (magic.StartsWith(Constants.GzSignature))
                {
                    outFileType = FileType.GZipArchive;
                }
                else if (magic.StartsWith(Constants.LRZipSignature))
                {
                    outFileType = FileType.LRZipArchive;
                }
                else if (magic.StartsWith(Constants.LZ4Signature)
                    || magic.StartsWith(Constants.LZ4SkippableMinSignature)
                    || magic.StartsWith(Constants.LZ4SkippableMaxSignature))
                {
                    outFileType = FileType.LZ4Archive;
                }
                else if (magic.StartsWith(Constants.RarSignature)
                    || magic.StartsWith(Constants.RarFiveSignature))
                {
                    outFileType = FileType.RarArchive;
                }
                else if (magic.StartsWith(Constants.TarSignature)
                    || magic.StartsWith(Constants.TarZeroSignature))
                {
                    outFileType = FileType.TapeArchive;
                }
                else if (magic.StartsWith(Constants.XZSignature))
                {
                    outFileType = FileType.XZArchive;
                }
                else if (magic.StartsWith(Constants.ZipSignature)
                    || magic.StartsWith(Constants.ZipSignatureEmpty)
                    || magic.StartsWith(Constants.ZipSignatureSpanned))
                {
                    outFileType = FileType.ZipArchive;
                }
                else if (magic.StartsWith(Constants.ZPAQSignature))
                {
                    outFileType = FileType.ZPAQArchive;
                }
                else if (magic.StartsWith(Constants.ZstdSignature))
                {
                    outFileType = FileType.ZstdArchive;
                }
            }
            catch (Exception ex)
            {
                logger.Warning(ex, $"An exception occurred determining file type of '{input}'");
            }

            return outFileType;
        }