Separate out CMP and DC reading

This commit is contained in:
Matt Nadareski
2020-06-12 13:48:49 -07:00
parent 6ee376d6ec
commit daa63a5e8a
2 changed files with 223 additions and 130 deletions

View File

@@ -66,8 +66,7 @@ namespace SabreTools.Library.DatFiles
// If we have a known header // If we have a known header
if (normalizedValue == "clrmamepro" if (normalizedValue == "clrmamepro"
|| normalizedValue == "romvault" || normalizedValue == "romvault")
|| normalizedValue == "doscenter")
{ {
ReadHeader(sr, keep); ReadHeader(sr, keep);
} }
@@ -116,22 +115,9 @@ namespace SabreTools.Library.DatFiles
GroupCollection gc = Regex.Match(line, Constants.ItemPatternCMP).Groups; GroupCollection gc = Regex.Match(line, Constants.ItemPatternCMP).Groups;
string itemval = gc[2].Value.Replace("\"", string.Empty); string itemval = gc[2].Value.Replace("\"", string.Empty);
if (line.Trim().StartsWith("Name:"))
{
Name = (string.IsNullOrWhiteSpace(Name) ? line.Substring(6) : Name);
superdat = superdat || itemval.Contains(" - SuperDAT");
if (keep && superdat)
Type = (string.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
line = reader.ReadLine();
continue;
}
switch (gc[1].Value) switch (gc[1].Value)
{ {
case "name": case "name":
case "Name:":
Name = (string.IsNullOrWhiteSpace(Name) ? itemval : Name); Name = (string.IsNullOrWhiteSpace(Name) ? itemval : Name);
superdat = superdat || itemval.Contains(" - SuperDAT"); superdat = superdat || itemval.Contains(" - SuperDAT");
@@ -140,51 +126,39 @@ namespace SabreTools.Library.DatFiles
break; break;
case "description": case "description":
case "Description:":
Description = (string.IsNullOrWhiteSpace(Description) ? itemval : Description); Description = (string.IsNullOrWhiteSpace(Description) ? itemval : Description);
break; break;
case "rootdir": case "rootdir":
case "Rootdir:":
RootDir = (string.IsNullOrWhiteSpace(RootDir) ? itemval : RootDir); RootDir = (string.IsNullOrWhiteSpace(RootDir) ? itemval : RootDir);
break; break;
case "category": case "category":
case "Category:":
Category = (string.IsNullOrWhiteSpace(Category) ? itemval : Category); Category = (string.IsNullOrWhiteSpace(Category) ? itemval : Category);
break; break;
case "version": case "version":
case "Version:":
Version = (string.IsNullOrWhiteSpace(Version) ? itemval : Version); Version = (string.IsNullOrWhiteSpace(Version) ? itemval : Version);
break; break;
case "date": case "date":
case "Date:":
Date = (string.IsNullOrWhiteSpace(Date) ? itemval : Date); Date = (string.IsNullOrWhiteSpace(Date) ? itemval : Date);
break; break;
case "author": case "author":
case "Author:":
Author = (string.IsNullOrWhiteSpace(Author) ? itemval : Author); Author = (string.IsNullOrWhiteSpace(Author) ? itemval : Author);
break; break;
case "email": case "email":
case "Email:":
Email = (string.IsNullOrWhiteSpace(Email) ? itemval : Email); Email = (string.IsNullOrWhiteSpace(Email) ? itemval : Email);
break; break;
case "homepage": case "homepage":
case "Homepage:":
Homepage = (string.IsNullOrWhiteSpace(Homepage) ? itemval : Homepage); Homepage = (string.IsNullOrWhiteSpace(Homepage) ? itemval : Homepage);
break; break;
case "url": case "url":
case "Url:":
Url = (string.IsNullOrWhiteSpace(Url) ? itemval : Url); Url = (string.IsNullOrWhiteSpace(Url) ? itemval : Url);
break; break;
case "comment": case "comment":
case "Comment:":
Comment = (string.IsNullOrWhiteSpace(Comment) ? itemval : Comment); Comment = (string.IsNullOrWhiteSpace(Comment) ? itemval : Comment);
break; break;
case "header": case "header":
case "Header:":
Header = (string.IsNullOrWhiteSpace(Header) ? itemval : Header); Header = (string.IsNullOrWhiteSpace(Header) ? itemval : Header);
break; break;
case "type": case "type":
case "Type:":
Type = (string.IsNullOrWhiteSpace(Type) ? itemval : Type); Type = (string.IsNullOrWhiteSpace(Type) ? itemval : Type);
superdat = superdat || itemval.Contains("SuperDAT"); superdat = superdat || itemval.Contains("SuperDAT");
break; break;
@@ -259,7 +233,6 @@ namespace SabreTools.Library.DatFiles
if (trimmedline.StartsWith("archive (") if (trimmedline.StartsWith("archive (")
|| trimmedline.StartsWith("biosset (") || trimmedline.StartsWith("biosset (")
|| trimmedline.StartsWith("disk (") || trimmedline.StartsWith("disk (")
|| trimmedline.StartsWith("file (") // This is a DOSCenter file, not a SabreDAT file
|| trimmedline.StartsWith("release (") || trimmedline.StartsWith("release (")
|| trimmedline.StartsWith("rom (") || trimmedline.StartsWith("rom (")
|| (trimmedline.StartsWith("sample") && !trimmedline.StartsWith("sampleof"))) || (trimmedline.StartsWith("sample") && !trimmedline.StartsWith("sampleof")))
@@ -270,8 +243,6 @@ namespace SabreTools.Library.DatFiles
temptype = ItemType.Rom; temptype = ItemType.Rom;
else if (line.Trim().StartsWith("disk (")) else if (line.Trim().StartsWith("disk ("))
temptype = ItemType.Disk; temptype = ItemType.Disk;
else if (line.Trim().StartsWith("file ("))
temptype = ItemType.Rom;
else if (line.Trim().StartsWith("sample")) else if (line.Trim().StartsWith("sample"))
temptype = ItemType.Sample; temptype = ItemType.Sample;
@@ -300,99 +271,6 @@ namespace SabreTools.Library.DatFiles
// Get the line split by spaces and quotes // Get the line split by spaces and quotes
string[] linegc = Utilities.SplitLineAsCMP(line); string[] linegc = Utilities.SplitLineAsCMP(line);
// Special cases for DOSCenter DATs only because of how the lines are arranged
if (line.Trim().StartsWith("file ("))
{
// Loop over the specifics
for (int i = 0; i < linegc.Length; i++)
{
// Names are not quoted, for some stupid reason
if (linegc[i] == "name")
{
// Get the name in order until we find the next flag
while (++i < linegc.Length && linegc[i] != "size"
&& linegc[i] != "date"
&& linegc[i] != "crc"
&& linegc[i] != "md5"
&& linegc[i] != "ripemd160"
&& linegc[i] != "sha1"
&& linegc[i] != "sha256"
&& linegc[i] != "sha384"
&& linegc[i] != "sha512")
{
item.Name += $" {linegc[i]}";
}
// Perform correction
item.Name = item.Name.TrimStart();
i--;
}
// Get the size from the next part
else if (linegc[i] == "size")
{
long tempsize = -1;
if (!Int64.TryParse(linegc[++i], out tempsize))
tempsize = 0;
((Rom)item).Size = tempsize;
}
// Get the date from the next part
else if (linegc[i] == "date")
{
((Rom)item).Date = $"{linegc[++i].Replace("\"", string.Empty)} {linegc[++i].Replace("\"", string.Empty)}";
}
// Get the CRC from the next part
else if (linegc[i] == "crc")
{
((Rom)item).CRC = linegc[++i].Replace("\"", string.Empty).ToLowerInvariant();
}
// Get the MD5 from the next part
else if (linegc[i] == "md5")
{
((Rom)item).MD5 = linegc[++i].Replace("\"", string.Empty).ToLowerInvariant();
}
// Get the RIPEMD160 from the next part
else if (linegc[i] == "ripemd160")
{
((Rom)item).RIPEMD160 = linegc[++i].Replace("\"", string.Empty).ToLowerInvariant();
}
// Get the SHA1 from the next part
else if (linegc[i] == "sha1")
{
((Rom)item).SHA1 = linegc[++i].Replace("\"", string.Empty).ToLowerInvariant();
}
// Get the SHA256 from the next part
else if (linegc[i] == "sha256")
{
((Rom)item).SHA256 = linegc[++i].Replace("\"", string.Empty).ToLowerInvariant();
}
// Get the SHA384 from the next part
else if (linegc[i] == "sha384")
{
((Rom)item).SHA384 = linegc[++i].Replace("\"", string.Empty).ToLowerInvariant();
}
// Get the SHA512 from the next part
else if (linegc[i] == "sha512")
{
((Rom)item).SHA512 = linegc[++i].Replace("\"", string.Empty).ToLowerInvariant();
}
}
// Now process and add the rom
ParseAddHelper(item, clean, remUnicode);
line = reader.ReadLine();
continue;
}
// Loop over all attributes normally and add them if possible // Loop over all attributes normally and add them if possible
for (int i = 0; i < linegc.Length; i++) for (int i = 0; i < linegc.Length; i++)
{ {

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using SabreTools.Library.Data; using SabreTools.Library.Data;
using SabreTools.Library.DatItems; using SabreTools.Library.DatItems;
@@ -26,7 +27,7 @@ namespace SabreTools.Library.DatFiles
} }
/// <summary> /// <summary>
/// Parse a DosCenter DAT and return all found games and roms within /// Parse a DOSCenter DAT and return all found games and roms within
/// </summary> /// </summary>
/// <param name="filename">Name of the file to be parsed</param> /// <param name="filename">Name of the file to be parsed</param>
/// <param name="sysid">System ID for the DAT</param> /// <param name="sysid">System ID for the DAT</param>
@@ -34,7 +35,6 @@ namespace SabreTools.Library.DatFiles
/// <param name="keep">True if full pathnames are to be kept, false otherwise (default)</param> /// <param name="keep">True if full pathnames are to be kept, false otherwise (default)</param>
/// <param name="clean">True if game names are sanitized, false otherwise (default)</param> /// <param name="clean">True if game names are sanitized, false otherwise (default)</param>
/// <param name="remUnicode">True if we should remove non-ASCII characters from output, false otherwise (default)</param> /// <param name="remUnicode">True if we should remove non-ASCII characters from output, false otherwise (default)</param>
/// TODO: Pull parsing into this file instead of relying on CMP
public override void ParseFile( public override void ParseFile(
// Standard Dat parsing // Standard Dat parsing
string filename, string filename,
@@ -46,8 +46,224 @@ namespace SabreTools.Library.DatFiles
bool clean, bool clean,
bool remUnicode) bool remUnicode)
{ {
// ClrMamePro and DosCenter parsing are identical so it just calls one implementation // Open a file reader
new ClrMamePro(this).ParseFile(filename, sysid, srcid, keep, clean, remUnicode); Encoding enc = Utilities.GetEncoding(filename);
StreamReader sr = new StreamReader(Utilities.TryOpenRead(filename), enc);
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
// If the line is the header or a game
if (Regex.IsMatch(line, Constants.HeaderPatternCMP))
{
GroupCollection gc = Regex.Match(line, Constants.HeaderPatternCMP).Groups;
string normalizedValue = gc[1].Value.ToLowerInvariant();
// If we have a known header
if (normalizedValue == "doscenter")
ReadHeader(sr, keep);
// If we have a known set type
else if (normalizedValue == "game" )
ReadGame(sr, filename, sysid, srcid, clean, remUnicode);
}
}
sr.Dispose();
}
/// <summary>
/// Read header information
/// </summary>
/// <param name="reader">StreamReader to use to parse the header</param>
/// <param name="keep">True if full pathnames are to be kept, false otherwise (default)</param>
private void ReadHeader(StreamReader reader, bool keep)
{
bool superdat = false;
// If there's no subtree to the header, skip it
if (reader == null || reader.EndOfStream)
return;
// Otherwise, add what is possible
string line = reader.ReadLine();
while (!Regex.IsMatch(line, Constants.EndPatternCMP))
{
// Get all header items (ONLY OVERWRITE IF THERE'S NO DATA)
GroupCollection gc = Regex.Match(line, Constants.ItemPatternCMP).Groups;
string itemval = gc[2].Value.Replace("\"", string.Empty);
// Some dats don't have the space between "Name:" and the dat name
if (line.Trim().StartsWith("Name:"))
{
Name = (string.IsNullOrWhiteSpace(Name) ? line.Substring(6) : Name);
superdat = superdat || itemval.Contains(" - SuperDAT");
if (keep && superdat)
Type = (string.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
line = reader.ReadLine();
continue;
}
switch (gc[1].Value)
{
case "Name:":
Name = (string.IsNullOrWhiteSpace(Name) ? itemval : Name);
superdat = superdat || itemval.Contains(" - SuperDAT");
if (keep && superdat)
Type = (string.IsNullOrWhiteSpace(Type) ? "SuperDAT" : Type);
break;
case "Description:":
Description = (string.IsNullOrWhiteSpace(Description) ? itemval : Description);
break;
case "Version:":
Version = (string.IsNullOrWhiteSpace(Version) ? itemval : Version);
break;
case "Date:":
Date = (string.IsNullOrWhiteSpace(Date) ? itemval : Date);
break;
case "Author:":
Author = (string.IsNullOrWhiteSpace(Author) ? itemval : Author);
break;
case "Homepage:":
Homepage = (string.IsNullOrWhiteSpace(Homepage) ? itemval : Homepage);
break;
case "Comment:":
Comment = (string.IsNullOrWhiteSpace(Comment) ? itemval : Comment);
break;
}
line = reader.ReadLine();
}
}
/// <summary>
/// Read set information
/// </summary>
/// <param name="reader">StreamReader to use to parse the header</param>
/// <param name="filename">Name of the file to be parsed</param>
/// <param name="sysid">System ID for the DAT</param>
/// <param name="srcid">Source ID for the DAT</param>
/// <param name="clean">True if game names are sanitized, false otherwise (default)</param>
/// <param name="remUnicode">True if we should remove non-ASCII characters from output, false otherwise (default)</param>
private void ReadGame(
StreamReader reader,
// Standard Dat parsing
string filename,
int sysid,
int srcid,
// Miscellaneous
bool clean,
bool remUnicode)
{
// Prepare all internal variables
bool containsItems = false;
Machine machine = new Machine()
{
MachineType = MachineType.None,
};
// If there's no subtree to the header, skip it
if (reader == null || reader.EndOfStream)
return;
// Otherwise, add what is possible
string line = reader.ReadLine();
while (!Regex.IsMatch(line, Constants.EndPatternCMP))
{
// Item-specific lines have a known pattern
string trimmedline = line.Trim();
if (trimmedline.StartsWith("file ("))
{
containsItems = true;
ItemType temptype = ItemType.Rom;
// Create the proper DatItem based on the type
DatItem item = Utilities.GetDatItem(temptype);
// Then populate it with information
item.CopyMachineInformation(machine);
item.SystemID = sysid;
item.System = filename;
item.SourceID = srcid;
// Get the line split by spaces and quotes
string[] linegc = Utilities.SplitLineAsCMP(line);
// Loop over the specifics
for (int i = 0; i < linegc.Length; i++)
{
// Names are not quoted, for some stupid reason
if (linegc[i] == "name")
{
// Get the name in order until we find the next flag
while (++i < linegc.Length
&& linegc[i] != "size"
&& linegc[i] != "date"
&& linegc[i] != "crc")
{
item.Name += $" {linegc[i]}";
}
// Perform correction
item.Name = item.Name.TrimStart();
i--;
}
// Get the size from the next part
else if (linegc[i] == "size")
{
if (!Int64.TryParse(linegc[++i], out long tempsize))
tempsize = 0;
((Rom)item).Size = tempsize;
}
// Get the date from the next part
else if (linegc[i] == "date")
{
((Rom)item).Date = $"{linegc[++i].Replace("\"", string.Empty)} {linegc[++i].Replace("\"", string.Empty)}";
}
// Get the CRC from the next part
else if (linegc[i] == "crc")
{
((Rom)item).CRC = linegc[++i].Replace("\"", string.Empty).ToLowerInvariant();
}
}
// Now process and add the rom
ParseAddHelper(item, clean, remUnicode);
line = reader.ReadLine();
continue;
}
line = reader.ReadLine();
}
// If no items were found for this machine, add a Blank placeholder
if (!containsItems)
{
Blank blank = new Blank()
{
SystemID = sysid,
System = filename,
SourceID = srcid,
};
blank.CopyMachineInformation(machine);
// Now process and add the rom
ParseAddHelper(blank, clean, remUnicode);
}
} }
@@ -198,7 +414,7 @@ namespace SabreTools.Library.DatFiles
// Build the state based on excluded fields // Build the state based on excluded fields
sw.Write("game (\n"); sw.Write("game (\n");
sw.Write($"\tname \"{datItem.GetField(Field.MachineName, ExcludeFields)}.zip\n"); sw.Write($"\tname \"{datItem.GetField(Field.MachineName, ExcludeFields)}.zip\"\n");
sw.Flush(); sw.Flush();
} }
@@ -265,7 +481,7 @@ namespace SabreTools.Library.DatFiles
case ItemType.Rom: case ItemType.Rom:
var rom = datItem as Rom; var rom = datItem as Rom;
sw.Write("\tfile ("); sw.Write("\tfile (");
sw.Write($" name \"{datItem.GetField(Field.Name, ExcludeFields)}\""); sw.Write($" name {datItem.GetField(Field.Name, ExcludeFields)}");
if (!ExcludeFields[(int)Field.Size] && rom.Size != -1) if (!ExcludeFields[(int)Field.Size] && rom.Size != -1)
sw.Write($" size \"{rom.Size}\""); sw.Write($" size \"{rom.Size}\"");
if (!string.IsNullOrWhiteSpace(datItem.GetField(Field.Date, ExcludeFields))) if (!string.IsNullOrWhiteSpace(datItem.GetField(Field.Date, ExcludeFields)))
@@ -300,7 +516,6 @@ namespace SabreTools.Library.DatFiles
// End game // End game
sw.Write(")\n"); sw.Write(")\n");
// Write the footer out
sw.Flush(); sw.Flush();
} }
catch (Exception ex) catch (Exception ex)