diff --git a/SabreTools.Library/DatFiles/AttractMode.cs b/SabreTools.Library/DatFiles/AttractMode.cs index 6410aaf8..b64d920b 100644 --- a/SabreTools.Library/DatFiles/AttractMode.cs +++ b/SabreTools.Library/DatFiles/AttractMode.cs @@ -59,53 +59,57 @@ namespace SabreTools.Library.DatFiles { // Get the current line, split and parse svr.ReadNextLine(); - } - catch (InvalidDataException ex) - { - Globals.Logger.Error(ex, $"Malformed line found in '{filename}' at line {svr.LineNumber}"); - if (throwOnError) throw ex; - continue; - } - Rom rom = new Rom - { - Name = "-", - Size = Constants.SizeZero, - CRC = Constants.CRCZero, - MD5 = Constants.MD5Zero, - SHA1 = Constants.SHA1Zero, - ItemStatus = ItemStatus.None, - - Machine = new Machine + Rom rom = new Rom { - Name = svr.Line[0], // #Name - Description = svr.Line[1], // Title - CloneOf = svr.Line[3], // CloneOf - Year = svr.Line[4], // Year - Manufacturer = svr.Line[5], // Manufacturer - Category = svr.Line[6], // Category - Players = svr.Line[7], // Players - Rotation = svr.Line[8], // Rotation - Control = svr.Line[9], // Control - Status = svr.Line[10], // Status - DisplayCount = svr.Line[11], // DisplayCount - DisplayType = svr.Line[12], // DisplayType - Comment = svr.Line[15], // Extra - Buttons = svr.Line[16], // Buttons - }, + Name = "-", + Size = Constants.SizeZero, + CRC = Constants.CRCZero, + MD5 = Constants.MD5Zero, + SHA1 = Constants.SHA1Zero, + ItemStatus = ItemStatus.None, - AltName = svr.Line[13], // AltRomname - AltTitle = svr.Line[14], // AltTitle + Machine = new Machine + { + Name = svr.Line[0], // #Name + Description = svr.Line[1], // Title + CloneOf = svr.Line[3], // CloneOf + Year = svr.Line[4], // Year + Manufacturer = svr.Line[5], // Manufacturer + Category = svr.Line[6], // Category + Players = svr.Line[7], // Players + Rotation = svr.Line[8], // Rotation + Control = svr.Line[9], // Control + Status = svr.Line[10], // Status + DisplayCount = svr.Line[11], // DisplayCount + DisplayType = svr.Line[12], // DisplayType + Comment = svr.Line[15], // Extra + Buttons = svr.Line[16], // Buttons + }, - Source = new Source + AltName = svr.Line[13], // AltRomname + AltTitle = svr.Line[14], // AltTitle + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + // Now process and add the rom + ParseAddHelper(rom); + } + catch (Exception ex) + { + string message = $"'{filename}' - There was an error parsing line {svr.LineNumber} '{svr.CurrentLine}'"; + Globals.Logger.Error(ex, message); + if (throwOnError) { - Index = indexId, - Name = filename, - }, - }; - - // Now process and add the rom - ParseAddHelper(rom); + svr.Dispose(); + throw new Exception(message, ex); + } + } } svr.Dispose(); diff --git a/SabreTools.Library/DatFiles/ClrMamePro.cs b/SabreTools.Library/DatFiles/ClrMamePro.cs index 1fe4c21c..992e6fb5 100644 --- a/SabreTools.Library/DatFiles/ClrMamePro.cs +++ b/SabreTools.Library/DatFiles/ClrMamePro.cs @@ -54,33 +54,46 @@ namespace SabreTools.Library.DatFiles while (!cmpr.EndOfStream) { - cmpr.ReadNextLine(); - - // Ignore everything not top-level - if (cmpr.RowType != CmpRowType.TopLevel) - continue; - - // Switch on the top-level name - switch (cmpr.TopLevel.ToLowerInvariant()) + try { - // Header values - case "clrmamepro": - case "romvault": - ReadHeader(cmpr, keep); - break; + cmpr.ReadNextLine(); - // Sets - case "set": // Used by the most ancient DATs - case "game": // Used by most CMP DATs - case "machine": // Possibly used by MAME CMP DATs - ReadSet(cmpr, false, filename, indexId); - break; - case "resource": // Used by some other DATs to denote a BIOS set - ReadSet(cmpr, true, filename, indexId); - break; + // Ignore everything not top-level + if (cmpr.RowType != CmpRowType.TopLevel) + continue; - default: - break; + // Switch on the top-level name + switch (cmpr.TopLevel.ToLowerInvariant()) + { + // Header values + case "clrmamepro": + case "romvault": + ReadHeader(cmpr, keep); + break; + + // Sets + case "set": // Used by the most ancient DATs + case "game": // Used by most CMP DATs + case "machine": // Possibly used by MAME CMP DATs + ReadSet(cmpr, false, filename, indexId); + break; + case "resource": // Used by some other DATs to denote a BIOS set + ReadSet(cmpr, true, filename, indexId); + break; + + default: + break; + } + } + catch (Exception ex) + { + string message = $"'{filename}' - There was an error parsing line {cmpr.LineNumber} '{cmpr.CurrentLine}'"; + Globals.Logger.Error(ex, message); + if (throwOnError) + { + cmpr.Dispose(); + throw new Exception(message, ex); + } } } diff --git a/SabreTools.Library/DatFiles/DatFile.cs b/SabreTools.Library/DatFiles/DatFile.cs index c4539b9a..324d4646 100644 --- a/SabreTools.Library/DatFiles/DatFile.cs +++ b/SabreTools.Library/DatFiles/DatFile.cs @@ -1802,10 +1802,11 @@ namespace SabreTools.Library.DatFiles /// Create a DatFile and parse a file into it /// /// Name of the file to be parsed - public static DatFile CreateAndParse(string filename) + /// 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 = Create(); - datFile.Parse(new ParentablePath(filename)); + datFile.Parse(new ParentablePath(filename), throwOnError: throwOnError); return datFile; } @@ -1833,22 +1834,22 @@ namespace SabreTools.Library.DatFiles /// /// Parse a DAT and return all found games and roms within /// - /// Name of the file to be parsed + /// 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 void Parse( - ParentablePath filename, + ParentablePath input, int indexId = 0, bool keep = false, bool keepext = false, bool quotes = true, - bool throwOnError = false) + bool throwOnError = true) { // Get the current path from the filename - string currentPath = filename.CurrentPath; + string currentPath = input.CurrentPath; // Check the file extension first as a safeguard if (!PathExtensions.HasValidDatExtension(currentPath)) @@ -1868,7 +1869,7 @@ namespace SabreTools.Library.DatFiles } catch (Exception ex) { - Globals.Logger.Error(ex, $"Error with file '{filename}'"); + Globals.Logger.Error(ex, $"Error with file '{currentPath}'"); if (throwOnError) throw ex; } } diff --git a/SabreTools.Library/DatFiles/DosCenter.cs b/SabreTools.Library/DatFiles/DosCenter.cs index e55b5792..88396458 100644 --- a/SabreTools.Library/DatFiles/DosCenter.cs +++ b/SabreTools.Library/DatFiles/DosCenter.cs @@ -43,27 +43,40 @@ namespace SabreTools.Library.DatFiles while (!cmpr.EndOfStream) { - cmpr.ReadNextLine(); - - // Ignore everything not top-level - if (cmpr.RowType != CmpRowType.TopLevel) - continue; - - // Switch on the top-level name - switch (cmpr.TopLevel.ToLowerInvariant()) + try { - // Header values - case "doscenter": - ReadHeader(cmpr); - break; + cmpr.ReadNextLine(); - // Sets - case "game": - ReadGame(cmpr, filename, indexId); - break; + // Ignore everything not top-level + if (cmpr.RowType != CmpRowType.TopLevel) + continue; - default: - break; + // Switch on the top-level name + switch (cmpr.TopLevel.ToLowerInvariant()) + { + // Header values + case "doscenter": + ReadHeader(cmpr); + break; + + // Sets + case "game": + ReadGame(cmpr, filename, indexId); + break; + + default: + break; + } + } + catch (Exception ex) + { + string message = $"'{filename}' - There was an error parsing line {cmpr.LineNumber} '{cmpr.CurrentLine}'"; + Globals.Logger.Error(ex, message); + if (throwOnError) + { + cmpr.Dispose(); + throw new Exception(message, ex); + } } } diff --git a/SabreTools.Library/DatFiles/EverdriveSmdb.cs b/SabreTools.Library/DatFiles/EverdriveSmdb.cs index 2d583629..07a0f0e9 100644 --- a/SabreTools.Library/DatFiles/EverdriveSmdb.cs +++ b/SabreTools.Library/DatFiles/EverdriveSmdb.cs @@ -33,51 +33,65 @@ namespace SabreTools.Library.DatFiles /// True if the error that is thrown should be thrown back to the caller, false otherwise protected override void ParseFile(string filename, int indexId, bool keep, bool throwOnError = false) { + // TODO: Use SeparatedValueReader // Open a file reader Encoding enc = FileExtensions.GetEncoding(filename); StreamReader sr = new StreamReader(FileExtensions.TryOpenRead(filename), enc); while (!sr.EndOfStream) { - string line = sr.ReadLine(); - - /* - The gameinfo order is as follows - 0 - SHA-256 - 1 - Machine Name/Filename - 2 - SHA-1 - 3 - MD5 - 4 - CRC32 - */ - - string[] gameinfo = line.Split('\t'); - string[] fullname = gameinfo[1].Split('/'); - - Rom rom = new Rom + try { - Name = gameinfo[1].Substring(fullname[0].Length + 1), - Size = null, // No size provided, but we don't want the size being 0 - CRC = gameinfo[4], - MD5 = gameinfo[3], - SHA1 = gameinfo[2], - SHA256 = gameinfo[0], - ItemStatus = ItemStatus.None, + string line = sr.ReadLine(); - Machine = new Machine + /* + The gameinfo order is as follows + 0 - SHA-256 + 1 - Machine Name/Filename + 2 - SHA-1 + 3 - MD5 + 4 - CRC32 + */ + + string[] gameinfo = line.Split('\t'); + string[] fullname = gameinfo[1].Split('/'); + + Rom rom = new Rom { - Name = fullname[0], - Description = fullname[0], - }, + Name = gameinfo[1].Substring(fullname[0].Length + 1), + Size = null, // No size provided, but we don't want the size being 0 + CRC = gameinfo[4], + MD5 = gameinfo[3], + SHA1 = gameinfo[2], + SHA256 = gameinfo[0], + ItemStatus = ItemStatus.None, - Source = new Source + Machine = new Machine + { + Name = fullname[0], + Description = fullname[0], + }, + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + // Now process and add the rom + ParseAddHelper(rom); + } + catch (Exception ex) + { + string message = $"'{filename}' - There was an error parsing at position {sr.BaseStream.Position}"; + Globals.Logger.Error(ex, message); + if (throwOnError) { - Index = indexId, - Name = filename, - }, - }; - - // Now process and add the rom - ParseAddHelper(rom); + sr.Dispose(); + throw new Exception(message, ex); + } + } } sr.Dispose(); diff --git a/SabreTools.Library/DatFiles/Hashfile.cs b/SabreTools.Library/DatFiles/Hashfile.cs index ce6e5437..63265042 100644 --- a/SabreTools.Library/DatFiles/Hashfile.cs +++ b/SabreTools.Library/DatFiles/Hashfile.cs @@ -43,56 +43,69 @@ namespace SabreTools.Library.DatFiles while (!sr.EndOfStream) { - string line = sr.ReadLine(); - - // Split the line and get the name and hash - string[] split = line.Split(' '); - string name = string.Empty; - string hash = string.Empty; - - // If we have CRC, then it's an SFV file and the name is first are - if (_hash.HasFlag(Hash.CRC)) + try { - name = split[0].Replace("*", String.Empty); - hash = split[1]; - } - // Otherwise, the name is second - else - { - name = split[1].Replace("*", String.Empty); - hash = split[0]; - } + string line = sr.ReadLine(); - Rom rom = new Rom - { - Name = name, - Size = null, - CRC = (_hash.HasFlag(Hash.CRC) ? hash : null), - MD5 = (_hash.HasFlag(Hash.MD5) ? hash : null), + // Split the line and get the name and hash + string[] split = line.Split(' '); + string name = string.Empty; + string hash = string.Empty; + + // If we have CRC, then it's an SFV file and the name is first are + if (_hash.HasFlag(Hash.CRC)) + { + name = split[0].Replace("*", String.Empty); + hash = split[1]; + } + // Otherwise, the name is second + else + { + name = split[1].Replace("*", String.Empty); + hash = split[0]; + } + + Rom rom = new Rom + { + Name = name, + Size = null, + CRC = (_hash.HasFlag(Hash.CRC) ? hash : null), + MD5 = (_hash.HasFlag(Hash.MD5) ? hash : null), #if NET_FRAMEWORK - RIPEMD160 = (_hash.HasFlag(Hash.RIPEMD160) ? hash : null), + RIPEMD160 = (_hash.HasFlag(Hash.RIPEMD160) ? hash : null), #endif - SHA1 = (_hash.HasFlag(Hash.SHA1) ? hash : null), - SHA256 = (_hash.HasFlag(Hash.SHA256) ? hash : null), - SHA384 = (_hash.HasFlag(Hash.SHA384) ? hash : null), - SHA512 = (_hash.HasFlag(Hash.SHA512) ? hash : null), - SpamSum = (_hash.HasFlag(Hash.SpamSum) ? hash : null), - ItemStatus = ItemStatus.None, + SHA1 = (_hash.HasFlag(Hash.SHA1) ? hash : null), + SHA256 = (_hash.HasFlag(Hash.SHA256) ? hash : null), + SHA384 = (_hash.HasFlag(Hash.SHA384) ? hash : null), + SHA512 = (_hash.HasFlag(Hash.SHA512) ? hash : null), + SpamSum = (_hash.HasFlag(Hash.SpamSum) ? hash : null), + ItemStatus = ItemStatus.None, - Machine = new Machine + Machine = new Machine + { + Name = Path.GetFileNameWithoutExtension(filename), + }, + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + // Now process and add the rom + ParseAddHelper(rom); + } + catch (Exception ex) + { + string message = $"'{filename}' - There was an error parsing at position {sr.BaseStream.Position}"; + Globals.Logger.Error(ex, message); + if (throwOnError) { - Name = Path.GetFileNameWithoutExtension(filename), - }, - - Source = new Source - { - Index = indexId, - Name = filename, - }, - }; - - // Now process and add the rom - ParseAddHelper(rom); + sr.Dispose(); + throw new Exception(message, ex); + } + } } sr.Dispose(); diff --git a/SabreTools.Library/DatFiles/ItemDictionary.cs b/SabreTools.Library/DatFiles/ItemDictionary.cs index 4522cdbe..3710b01e 100644 --- a/SabreTools.Library/DatFiles/ItemDictionary.cs +++ b/SabreTools.Library/DatFiles/ItemDictionary.cs @@ -1410,13 +1410,13 @@ namespace SabreTools.Library.DatFiles dirStats.ResetStatistics(); } - Globals.Logger.Verbose($"Beginning stat collection for '{file}'", false); + Globals.Logger.Verbose($"Beginning stat collection for '{file.CurrentPath}'", false); List games = new List(); DatFile datdata = DatFile.CreateAndParse(file.CurrentPath); datdata.Items.BucketBy(Field.Machine_Name, DedupeType.None, norename: true); // Output single DAT stats (if asked) - Globals.Logger.User($"Adding stats for file '{file}'\n", false); + Globals.Logger.User($"Adding stats for file '{file.CurrentPath}'\n", false); if (single) { reports.ForEach(report => report.ReplaceStatistics(datdata.Header.FileName, datdata.Items.Keys.Count, datdata.Items)); diff --git a/SabreTools.Library/DatFiles/Listrom.cs b/SabreTools.Library/DatFiles/Listrom.cs index 8bd57f7a..a199d9c1 100644 --- a/SabreTools.Library/DatFiles/Listrom.cs +++ b/SabreTools.Library/DatFiles/Listrom.cs @@ -50,201 +50,214 @@ namespace SabreTools.Library.DatFiles string gamename = string.Empty; while (!sr.EndOfStream) { - string line = sr.ReadLine().Trim(); - - // If we have a blank line, we just skip it - if (string.IsNullOrWhiteSpace(line)) + try { - continue; - } + string line = sr.ReadLine().Trim(); - // If we have the descriptor line, ignore it - else if (line == "Name Size Checksum") - { - continue; - } - - // If we have the beginning of a game, set the name of the game - else if (line.StartsWith("ROMs required for")) - { - gamename = Regex.Match(line, @"^ROMs required for \S*? string.Empty(.*?)string.Empty\.").Groups[1].Value; - } - - // If we have a machine with no required roms (usually internal devices), skip it - else if (line.StartsWith("No ROMs required for")) - { - continue; - } - - // Otherwise, we assume we have a rom that we need to add - else - { - // First, we preprocess the line so that the rom name is consistently correct - string[] split = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); - - // If the line doesn't have the 4 spaces of padding, check for 3 - if (split.Length == 1) - split = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); - - // If the split is still unsuccessful, log it and skip - if (split.Length == 1) - Globals.Logger.Warning($"Possibly malformed line: '{line}'"); - - string romname = split[0]; - line = line.Substring(romname.Length); - - // Next we separate the ROM into pieces - split = line.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); - - // Standard Disks have 2 pieces (name, sha1) - if (split.Length == 1) + // If we have a blank line, we just skip it + if (string.IsNullOrWhiteSpace(line)) { - Disk disk = new Disk() - { - Name = romname, - SHA1 = Sanitizer.CleanListromHashData(split[0]), - - Machine = new Machine - { - Name = gamename, - }, - - Source = new Source - { - Index = indexId, - Name = filename, - }, - }; - - ParseAddHelper(disk); + continue; } - // Baddump Disks have 4 pieces (name, BAD, sha1, BAD_DUMP) - else if (split.Length == 3 && line.EndsWith("BAD_DUMP")) + // If we have the descriptor line, ignore it + else if (line == "Name Size Checksum") { - Disk disk = new Disk() - { - Name = romname, - SHA1 = Sanitizer.CleanListromHashData(split[1]), - ItemStatus = ItemStatus.BadDump, - - Machine = new Machine - { - Name = gamename, - }, - - Source = new Source - { - Index = indexId, - Name = filename, - }, - }; - - ParseAddHelper(disk); + continue; } - // Standard ROMs have 4 pieces (name, size, crc, sha1) - else if (split.Length == 3) + // If we have the beginning of a game, set the name of the game + else if (line.StartsWith("ROMs required for")) { - Rom rom = new Rom() - { - Name = romname, - Size = Sanitizer.CleanLong(split[0]), - CRC = Sanitizer.CleanListromHashData(split[1]), - SHA1 = Sanitizer.CleanListromHashData(split[2]), - - Machine = new Machine - { - Name = gamename, - }, - - Source = new Source - { - Index = indexId, - Name = filename, - }, - }; - - ParseAddHelper(rom); + gamename = Regex.Match(line, @"^ROMs required for \S*? string.Empty(.*?)string.Empty\.").Groups[1].Value; } - // Nodump Disks have 5 pieces (name, NO, GOOD, DUMP, KNOWN) - else if (split.Length == 4 && line.EndsWith("NO GOOD DUMP KNOWN")) + // If we have a machine with no required roms (usually internal devices), skip it + else if (line.StartsWith("No ROMs required for")) { - Disk disk = new Disk() - { - Name = romname, - ItemStatus = ItemStatus.Nodump, - - Machine = new Machine - { - Name = gamename, - }, - - Source = new Source - { - Index = indexId, - Name = filename, - }, - }; - - ParseAddHelper(disk); + continue; } - // Baddump ROMs have 6 pieces (name, size, BAD, crc, sha1, BAD_DUMP) - else if (split.Length == 5 && line.EndsWith("BAD_DUMP")) - { - Rom rom = new Rom() - { - Name = romname, - Size = Sanitizer.CleanLong(split[0]), - CRC = Sanitizer.CleanListromHashData(split[2]), - SHA1 = Sanitizer.CleanListromHashData(split[3]), - ItemStatus = ItemStatus.BadDump, - - Machine = new Machine - { - Name = gamename, - }, - - Source = new Source - { - Index = indexId, - Name = filename, - }, - }; - - ParseAddHelper(rom); - } - - // Nodump ROMs have 6 pieces (name, size, NO, GOOD, DUMP, KNOWN) - else if (split.Length == 5 && line.EndsWith("NO GOOD DUMP KNOWN")) - { - Rom rom = new Rom() - { - Name = romname, - Size = Sanitizer.CleanLong(split[0]), - ItemStatus = ItemStatus.Nodump, - - Machine = new Machine - { - Name = gamename, - }, - - Source = new Source - { - Index = indexId, - Name = filename, - }, - }; - - ParseAddHelper(rom); - } - - // If we have something else, it's invalid + // Otherwise, we assume we have a rom that we need to add else { - Globals.Logger.Warning($"Invalid line detected: '{romname} {line}'"); + // First, we preprocess the line so that the rom name is consistently correct + string[] split = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); + + // If the line doesn't have the 4 spaces of padding, check for 3 + if (split.Length == 1) + split = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); + + // If the split is still unsuccessful, log it and skip + if (split.Length == 1) + Globals.Logger.Warning($"Possibly malformed line: '{line}'"); + + string romname = split[0]; + line = line.Substring(romname.Length); + + // Next we separate the ROM into pieces + split = line.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); + + // Standard Disks have 2 pieces (name, sha1) + if (split.Length == 1) + { + Disk disk = new Disk() + { + Name = romname, + SHA1 = Sanitizer.CleanListromHashData(split[0]), + + Machine = new Machine + { + Name = gamename, + }, + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + ParseAddHelper(disk); + } + + // Baddump Disks have 4 pieces (name, BAD, sha1, BAD_DUMP) + else if (split.Length == 3 && line.EndsWith("BAD_DUMP")) + { + Disk disk = new Disk() + { + Name = romname, + SHA1 = Sanitizer.CleanListromHashData(split[1]), + ItemStatus = ItemStatus.BadDump, + + Machine = new Machine + { + Name = gamename, + }, + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + ParseAddHelper(disk); + } + + // Standard ROMs have 4 pieces (name, size, crc, sha1) + else if (split.Length == 3) + { + Rom rom = new Rom() + { + Name = romname, + Size = Sanitizer.CleanLong(split[0]), + CRC = Sanitizer.CleanListromHashData(split[1]), + SHA1 = Sanitizer.CleanListromHashData(split[2]), + + Machine = new Machine + { + Name = gamename, + }, + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + ParseAddHelper(rom); + } + + // Nodump Disks have 5 pieces (name, NO, GOOD, DUMP, KNOWN) + else if (split.Length == 4 && line.EndsWith("NO GOOD DUMP KNOWN")) + { + Disk disk = new Disk() + { + Name = romname, + ItemStatus = ItemStatus.Nodump, + + Machine = new Machine + { + Name = gamename, + }, + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + ParseAddHelper(disk); + } + + // Baddump ROMs have 6 pieces (name, size, BAD, crc, sha1, BAD_DUMP) + else if (split.Length == 5 && line.EndsWith("BAD_DUMP")) + { + Rom rom = new Rom() + { + Name = romname, + Size = Sanitizer.CleanLong(split[0]), + CRC = Sanitizer.CleanListromHashData(split[2]), + SHA1 = Sanitizer.CleanListromHashData(split[3]), + ItemStatus = ItemStatus.BadDump, + + Machine = new Machine + { + Name = gamename, + }, + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + ParseAddHelper(rom); + } + + // Nodump ROMs have 6 pieces (name, size, NO, GOOD, DUMP, KNOWN) + else if (split.Length == 5 && line.EndsWith("NO GOOD DUMP KNOWN")) + { + Rom rom = new Rom() + { + Name = romname, + Size = Sanitizer.CleanLong(split[0]), + ItemStatus = ItemStatus.Nodump, + + Machine = new Machine + { + Name = gamename, + }, + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + ParseAddHelper(rom); + } + + // If we have something else, it's invalid + else + { + Globals.Logger.Warning($"Invalid line detected: '{romname} {line}'"); + } + } + } + catch (Exception ex) + { + string message = $"'{filename}' - There was an error parsing at position {sr.BaseStream.Position}"; + Globals.Logger.Error(ex, message); + if (throwOnError) + { + sr.Dispose(); + throw new Exception(message, ex); } } } diff --git a/SabreTools.Library/DatFiles/Listxml.cs b/SabreTools.Library/DatFiles/Listxml.cs index 1a6c5cff..705b0218 100644 --- a/SabreTools.Library/DatFiles/Listxml.cs +++ b/SabreTools.Library/DatFiles/Listxml.cs @@ -90,8 +90,12 @@ namespace SabreTools.Library.DatFiles } catch (Exception ex) { - Globals.Logger.Warning($"Exception found while parsing '{filename}': {ex}"); - if (throwOnError) throw ex; + Globals.Logger.Warning(ex, $"Exception found while parsing '{filename}'"); + if (throwOnError) + { + xtr.Dispose(); + throw ex; + } // For XML errors, just skip the affected node xtr?.Read(); diff --git a/SabreTools.Library/DatFiles/Logiqx.cs b/SabreTools.Library/DatFiles/Logiqx.cs index 9106277a..0494c268 100644 --- a/SabreTools.Library/DatFiles/Logiqx.cs +++ b/SabreTools.Library/DatFiles/Logiqx.cs @@ -107,8 +107,12 @@ namespace SabreTools.Library.DatFiles } catch (Exception ex) { - Globals.Logger.Warning($"Exception found while parsing '{filename}': {ex}"); - if (throwOnError) throw ex; + Globals.Logger.Warning(ex, $"Exception found while parsing '{filename}'"); + if (throwOnError) + { + xtr.Dispose(); + throw ex; + } // For XML errors, just skip the affected node xtr?.Read(); diff --git a/SabreTools.Library/DatFiles/OfflineList.cs b/SabreTools.Library/DatFiles/OfflineList.cs index cbf4b632..9b35f842 100644 --- a/SabreTools.Library/DatFiles/OfflineList.cs +++ b/SabreTools.Library/DatFiles/OfflineList.cs @@ -78,8 +78,12 @@ namespace SabreTools.Library.DatFiles } catch (Exception ex) { - Globals.Logger.Warning($"Exception found while parsing '{filename}': {ex}"); - if (throwOnError) throw ex; + Globals.Logger.Warning(ex, $"Exception found while parsing '{filename}'"); + if (throwOnError) + { + xtr.Dispose(); + throw ex; + } // For XML errors, just skip the affected node xtr?.Read(); diff --git a/SabreTools.Library/DatFiles/OpenMSX.cs b/SabreTools.Library/DatFiles/OpenMSX.cs index 08ca3de5..3b696081 100644 --- a/SabreTools.Library/DatFiles/OpenMSX.cs +++ b/SabreTools.Library/DatFiles/OpenMSX.cs @@ -80,8 +80,12 @@ namespace SabreTools.Library.DatFiles } catch (Exception ex) { - Globals.Logger.Warning($"Exception found while parsing '{filename}': {ex}"); - if (throwOnError) throw ex; + Globals.Logger.Warning(ex, $"Exception found while parsing '{filename}'"); + if (throwOnError) + { + xtr.Dispose(); + throw ex; + } // For XML errors, just skip the affected node xtr?.Read(); diff --git a/SabreTools.Library/DatFiles/RomCenter.cs b/SabreTools.Library/DatFiles/RomCenter.cs index 0b562dbe..9149beca 100644 --- a/SabreTools.Library/DatFiles/RomCenter.cs +++ b/SabreTools.Library/DatFiles/RomCenter.cs @@ -84,8 +84,13 @@ namespace SabreTools.Library.DatFiles } catch (Exception ex) { - Globals.Logger.Warning($"Exception found while parsing '{filename}': {ex}"); - if (throwOnError) throw ex; + string message = $"'{filename}' - There was an error parsing line {ir.LineNumber} '{ir.CurrentLine}'"; + Globals.Logger.Error(ex, message); + if (throwOnError) + { + ir.Dispose(); + throw new Exception(message, ex); + } } ir.Dispose(); @@ -304,7 +309,7 @@ namespace SabreTools.Library.DatFiles } // Roms are not valid row formats, usually - string line = reader.Line; + string line = reader.CurrentLine; // If we don't have a valid game, keep reading if (!line.StartsWith("¬")) diff --git a/SabreTools.Library/DatFiles/SabreXML.cs b/SabreTools.Library/DatFiles/SabreXML.cs index 52bdf740..76c7454b 100644 --- a/SabreTools.Library/DatFiles/SabreXML.cs +++ b/SabreTools.Library/DatFiles/SabreXML.cs @@ -77,8 +77,12 @@ namespace SabreTools.Library.DatFiles } catch (Exception ex) { - Globals.Logger.Warning($"Exception found while parsing '{filename}': {ex}"); - if (throwOnError) throw ex; + Globals.Logger.Warning(ex, $"Exception found while parsing '{filename}'"); + if (throwOnError) + { + xtr.Dispose(); + throw ex; + } // For XML errors, just skip the affected node xtr?.Read(); diff --git a/SabreTools.Library/DatFiles/SeparatedValue.cs b/SabreTools.Library/DatFiles/SeparatedValue.cs index 4b50af37..8c9c2794 100644 --- a/SabreTools.Library/DatFiles/SeparatedValue.cs +++ b/SabreTools.Library/DatFiles/SeparatedValue.cs @@ -65,8 +65,14 @@ namespace SabreTools.Library.DatFiles } catch (InvalidDataException ex) { - Globals.Logger.Warning($"Malformed line found in '{filename}' at line {svr.LineNumber}"); - if (throwOnError) throw ex; + string message = $"'{filename}' - There was an error parsing line {svr.LineNumber} '{svr.CurrentLine}'"; + Globals.Logger.Error(ex, message); + if (throwOnError) + { + svr.Dispose(); + throw new Exception(message, ex); + } + continue; } diff --git a/SabreTools.Library/DatFiles/SoftwareList.cs b/SabreTools.Library/DatFiles/SoftwareList.cs index 294a9d7d..44f86b33 100644 --- a/SabreTools.Library/DatFiles/SoftwareList.cs +++ b/SabreTools.Library/DatFiles/SoftwareList.cs @@ -81,8 +81,12 @@ namespace SabreTools.Library.DatFiles } catch (Exception ex) { - Globals.Logger.Warning($"Exception found while parsing '{filename}': {ex}"); - if (throwOnError) throw ex; + Globals.Logger.Warning(ex, $"Exception found while parsing '{filename}'"); + if (throwOnError) + { + xtr.Dispose(); + throw ex; + } // For XML errors, just skip the affected node xtr?.Read(); diff --git a/SabreTools.Library/Filtering/ExtraIniItem.cs b/SabreTools.Library/Filtering/ExtraIniItem.cs index 6705257a..832e305c 100644 --- a/SabreTools.Library/Filtering/ExtraIniItem.cs +++ b/SabreTools.Library/Filtering/ExtraIniItem.cs @@ -74,7 +74,7 @@ namespace SabreTools.Library.Filtering { // Get the key and value string key = ir.Section; - string value = ir.Line.Trim(); + string value = ir.CurrentLine.Trim(); // If the section is "ROOT_FOLDER", then we use the value "true" instead. // This is done because some INI files use the name of the file as the diff --git a/SabreTools.Library/IO/ClrMameProReader.cs b/SabreTools.Library/IO/ClrMameProReader.cs index 86e1b6aa..124c7654 100644 --- a/SabreTools.Library/IO/ClrMameProReader.cs +++ b/SabreTools.Library/IO/ClrMameProReader.cs @@ -16,6 +16,16 @@ namespace SabreTools.Library.IO /// private StreamReader sr; + /// + /// Contents of the current line, unprocessed + /// + public string CurrentLine { get; private set; } = string.Empty; + + /// + /// Get the current line number + /// + public long LineNumber { get; private set; } = 0; + /// /// Get if at end of stream /// @@ -74,7 +84,6 @@ namespace SabreTools.Library.IO public ClrMameProReader(string filename) { sr = new StreamReader(filename); - DosCenter = true; } /// @@ -83,7 +92,6 @@ namespace SabreTools.Library.IO public ClrMameProReader(Stream stream, Encoding encoding) { sr = new StreamReader(stream, encoding); - DosCenter = true; } /// @@ -94,8 +102,11 @@ namespace SabreTools.Library.IO if (!(sr.BaseStream?.CanRead ?? false) || sr.EndOfStream) return false; - string line = sr.ReadLine().Trim(); - ProcessLine(line); + CurrentLine = sr.ReadLine().Trim(); + LineNumber++; + + // TODO: Act like IniReader here + ProcessLine(CurrentLine); return true; } diff --git a/SabreTools.Library/IO/IniReader.cs b/SabreTools.Library/IO/IniReader.cs index 53527cfa..d946cb28 100644 --- a/SabreTools.Library/IO/IniReader.cs +++ b/SabreTools.Library/IO/IniReader.cs @@ -30,9 +30,14 @@ namespace SabreTools.Library.IO public KeyValuePair? KeyValuePair { get; private set; } = null; /// - /// Contents of the currently read line + /// Contents of the current line, unprocessed /// - public string Line { get; private set; } = string.Empty; + public string CurrentLine { get; private set; } = string.Empty; + + /// + /// Get the current line number + /// + public long LineNumber { get; private set; } = 0; /// /// Current row type @@ -73,7 +78,8 @@ namespace SabreTools.Library.IO if (!(sr.BaseStream?.CanRead ?? false) || sr.EndOfStream) return false; - Line = sr.ReadLine().Trim(); + CurrentLine = sr.ReadLine().Trim(); + LineNumber++; ProcessLine(); return true; } @@ -84,25 +90,25 @@ namespace SabreTools.Library.IO private void ProcessLine() { // Comment - if (Line.StartsWith(";")) + if (CurrentLine.StartsWith(";")) { KeyValuePair = null; RowType = IniRowType.Comment; } // Section - else if (Line.StartsWith("[") && Line.EndsWith("]")) + else if (CurrentLine.StartsWith("[") && CurrentLine.EndsWith("]")) { KeyValuePair = null; RowType = IniRowType.SectionHeader; - Section = Line.TrimStart('[').TrimEnd(']'); + Section = CurrentLine.TrimStart('[').TrimEnd(']'); } // KeyValuePair - else if (Line.Contains("=")) + else if (CurrentLine.Contains("=")) { // Split the line by '=' for key-value pairs - string[] data = Line.Split('='); + string[] data = CurrentLine.Split('='); // If the value field contains an '=', we need to put them back in string key = data[0].Trim(); @@ -113,10 +119,10 @@ namespace SabreTools.Library.IO } // Empty - else if (string.IsNullOrEmpty(Line)) + else if (string.IsNullOrEmpty(CurrentLine)) { KeyValuePair = null; - Line = string.Empty; + CurrentLine = string.Empty; RowType = IniRowType.None; } @@ -127,7 +133,7 @@ namespace SabreTools.Library.IO RowType = IniRowType.Invalid; if (ValidateRows) - throw new InvalidDataException($"Invalid INI row found, cannot continue: {Line}"); + throw new InvalidDataException($"Invalid INI row found, cannot continue: {CurrentLine}"); } } diff --git a/SabreTools.Library/IO/SeparatedValueReader.cs b/SabreTools.Library/IO/SeparatedValueReader.cs index 178998d0..cfe0941a 100644 --- a/SabreTools.Library/IO/SeparatedValueReader.cs +++ b/SabreTools.Library/IO/SeparatedValueReader.cs @@ -30,6 +30,16 @@ namespace SabreTools.Library.IO } } + /// + /// Contents of the current line, unprocessed + /// + public string CurrentLine { get; private set; } = string.Empty; + + /// + /// Get the current line number + /// + public long LineNumber { get; private set; } = 0; + /// /// Assume the first row is a header /// @@ -45,11 +55,6 @@ namespace SabreTools.Library.IO /// public List Line { get; private set; } = null; - /// - /// Get the current line number - /// - public long LineNumber { get; private set; } = -1; - /// /// Assume that values are wrapped in quotes /// @@ -104,6 +109,7 @@ namespace SabreTools.Library.IO return false; string fullLine = sr.ReadLine(); + CurrentLine = fullLine; LineNumber++; // If we have quotes, we need to split specially