using System; using System.IO; using System.Text.RegularExpressions; using SabreTools.Core; using SabreTools.IO; // This file represents all methods related to parsing from a file namespace SabreTools.DatFiles { public partial class DatTool { /// /// Create a DatFile and parse a file into it /// /// Name of the file to be parsed /// True if the error that is thrown should be thrown back to the caller, false otherwise public static DatFile CreateAndParse(string filename, bool throwOnError = false) { DatFile datFile = DatFile.Create(); ParseInto(datFile, new ParentablePath(filename), throwOnError: throwOnError); return datFile; } /// /// Parse a DAT and return all found games and roms within /// /// Current DatFile object to add to /// Name of the file to be parsed /// Index ID for the DAT /// True if full pathnames are to be kept, false otherwise (default) /// True if original extension should be kept, false otherwise (default) /// True if quotes are assumed in supported types (default), false otherwise /// True if the error that is thrown should be thrown back to the caller, false otherwise public static void ParseInto( DatFile datFile, string filename, int indexId = 0, bool keep = false, bool keepext = false, bool quotes = true, bool throwOnError = false) { ParentablePath path = new ParentablePath(filename.Trim('"')); ParseInto(datFile, path, indexId, keep, keepext, quotes, throwOnError); } /// /// Parse a DAT and return all found games and roms within /// /// Current DatFile object to add to /// Name of the file to be parsed /// Index ID for the DAT /// True if full pathnames are to be kept, false otherwise (default) /// True if original extension should be kept, false otherwise (default) /// True if quotes are assumed in supported types (default), false otherwise /// True if the error that is thrown should be thrown back to the caller, false otherwise public static void ParseInto( DatFile datFile, ParentablePath input, int indexId = 0, bool keep = false, bool keepext = false, bool quotes = true, bool throwOnError = true) { // Get the current path from the filename string currentPath = input.CurrentPath; // Check the file extension first as a safeguard if (!PathExtensions.HasValidDatExtension(currentPath)) return; // If the output filename isn't set already, get the internal filename datFile.Header.FileName = string.IsNullOrWhiteSpace(datFile.Header.FileName) ? (keepext ? Path.GetFileName(currentPath) : Path.GetFileNameWithoutExtension(currentPath)) : datFile.Header.FileName; // If the output type isn't set already, get the internal output type DatFormat currentPathFormat = GetDatFormat(currentPath); datFile.Header.DatFormat = datFile.Header.DatFormat == 0 ? currentPathFormat : datFile.Header.DatFormat; datFile.Items.SetBucketedBy(Field.DatItem_CRC); // Setting this because it can reduce issues later // Now parse the correct type of DAT try { DatFile.Create(currentPathFormat, datFile, quotes)?.ParseFile(currentPath, indexId, keep, throwOnError); } catch (Exception ex) { logger.Error(ex, $"Error with file '{currentPath}'"); if (throwOnError) throw ex; } } /// /// Get what type of DAT the input file is /// /// Name of the file to be parsed /// The DatFormat corresponding to the DAT private static DatFormat GetDatFormat(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); // Check if file exists if (!File.Exists(filename)) 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 // 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("