BizHawk/ExternalToolProjects/DATParser/NOINTROParser.cs

320 lines
7.5 KiB
C#

#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Windows.Forms;
namespace BizHawk.DATTool
{
public class NOINTROParser : DATParser
{
/// <summary>
/// Required to generate a GameDB file
/// </summary>
public override SystemType SysType { get; set; }
private List<XDocument> xmls = new List<XDocument>();
public NOINTROParser(SystemType type)
{
SysType = type;
}
/// <summary>
/// Parses multiple DAT files and returns a single GamesDB format csv string
/// </summary>
public override string ParseDAT(string[] filePath)
{
foreach (var s in filePath)
{
try
{
xmls.Add(XDocument.Load(s));
}
catch
{
var res = MessageBox.Show("Could not parse document as valid XML:\n\n" + s + "\n\nDo you wish to continue any other processing?", "Parsing Error", MessageBoxButtons.YesNo);
if (res != DialogResult.Yes)
return "";
}
}
int startIndex = 0;
// actual tosec parsing
foreach (var obj in xmls)
{
startIndex = Data.Count > 0 ? Data.Count - 1 : 0;
// get header info
var header = obj.Root.Descendants("header").First();
var name = header.Element("name").Value;
var version = header.Element("version").Value;
var description = header.Element("description").Value + " - " + version;
// start comment block
List<string> comments = new List<string>
{
"Type:\tNO-INTRO",
$"Source:\t{description}",
$"FileGen:\t{DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} (UTC)",
};
AddCommentBlock(comments.ToArray());
// process each entry
var query = obj.Root.Descendants("game");
foreach (var g in query)
{
GameDB item = new GameDB();
item.Name = g.Value;
item.SHA1 = g.Elements("rom").First().Attribute("sha1").Value.ToUpper();
item.MD5 = g.Elements("rom").First().Attribute("md5").Value.ToUpper();
item.CRC32 = g.Elements("rom").First().Attribute("crc").Value.ToUpper();
item.System = GameDB.GetSystemCode(SysType);
ParseNOINTROFlags(item);
Data.Add(item);
}
// add this file's data to the stringbuilder
// first we will sort into various ROMSTATUS groups
var working = Data.Skip(startIndex).ToList();
var baddump = working.Where(st => st.Status == "B").OrderBy(na => na.Name).ToList();
AddCommentBlock("Bad Dumps");
AppendCSVData(baddump);
var hack = working.Where(st => st.Status == "H").OrderBy(na => na.Name).ToList();
AddCommentBlock("Hacks");
AppendCSVData(hack);
var over = working.Where(st => st.Status == "O").OrderBy(na => na.Name).ToList();
AddCommentBlock("Over Dumps");
AppendCSVData(over);
var trans = working.Where(st => st.Status == "T").OrderBy(na => na.Name).ToList();
AddCommentBlock("Translated");
AppendCSVData(trans);
var good = working.Where(st => st.Status == "" || st.Status == null).OrderBy(na => na.Name).ToList();
AddCommentBlock("Believed Good");
AppendCSVData(good);
}
string result = sb.ToString();
return sb.ToString();
}
/// <summary>
/// Parses all the weird TOSEC flags within the game field
/// Detailed info here: https://www.tosecdev.org/tosec-naming-convention
/// Guts of this has been reused from here: https://github.com/Asnivor/MedLaunch/blob/master/MedLaunch/_Debug/DATDB/Platforms/TOSEC/StringConverterToSec.cs
/// </summary>
private void ParseNOINTROFlags(GameDB g)
{
string nameString = g.Name;
// remove uninteresting options
string a = RemoveUnneededOptions(nameString);
// process data contained in ()
string[] d = a.ToString().Split('(', ')');
if (d.Length > 0)
{
// name field
}
if (d.Length > 1)
{
if (d[1].Length >= 3)
{
// country
g.Region = d[1].Trim();
}
}
if (d.Length > 2)
{
// parse all other () fields
// because these are not mandatory this can be a confusing process
for (int i = 4; i < d.Length; i++)
{
string f = d[i].Trim();
// check for language
if (IsLanguageFlag(f) == true)
{
g.Notes = f;
continue;
}
// version - ignore
// check development status (not currently implemented)
if (IsDevelopmenttStatus(f) == true)
{
continue;
}
// check copyright status (not currently implemented)
if (IsCopyrightStatus(f) == true)
{
continue;
}
// country flag(s)
if (IsCountryFlag(f) == true)
{
g.Region = f;
continue;
}
// language - if present add to notes
if (IsLanguageFlag(f) == true)
{
g.Notes = f;
continue;
}
// Media Type - ignore for now
// Media Label - ignore for now
}
// process dump info flags and other info contained in []
if (nameString.Contains("[") && nameString.Contains("]"))
{
var e = nameString.Split('[', ']')
.Skip(1) // remove first entry (this is the bit before the [] entries start)
.Where(s => !string.IsNullOrWhiteSpace(s)) // remove empty entries
.Distinct()
.ToList();
if (e.Count > 0)
{
// bizhawk currently only has a few different RomStatus values (not as many as TOSEC anyway)
// Parsing priority will be:
// RomStatus.BadDump
// RomStatus.Hack
// RomStatus.Overdump
// RomStatus.GoodDump
// RomStatus.TranslatedRom
// everything else
// all tosec cr, h, t etc.. will fall under RomStatus.Hack
if (e.Where(str =>
// bad dump
str == "b" || str.StartsWith("b ")).ToList().Count > 0)
{
// RomStatus.BadDump
g.Status = "B";
}
else if (e.Where(str =>
// BIOS
str == "BIOS" || str.StartsWith("BIOS ")).ToList().Count > 0)
{
// RomStatus.BIOS
g.Status = "I";
}
else
{
g.Status = "";
}
}
}
}
}
public static bool IsDevelopmenttStatus(string s)
{
List<string> DS = new List<string>
{
"alpha", "beta", "preview", "pre-release", "proto"
};
bool b = DS.Any(s.Contains);
return b;
}
public static bool IsCopyrightStatus(string s)
{
List<string> CS = new List<string>
{
"CW", "CW-R", "FW", "GW", "GW-R", "LW", "PD", "SW", "SW-R"
};
bool b = CS.Any(s.Contains);
return b;
}
public static bool IsLanguageFlag(string s)
{
List<string> LC = new List<string>
{
"En", "Ja", "Fr", "De", "Es", "It", "Nl", "Pt", "Sv", "No", "Da", "Fi", "Zh", "Ko", "Pl"
};
bool b = false;
if (!s.Contains("[") && !s.Contains("]"))
{
foreach (var x in LC)
{
if (s == x || s.StartsWith(x + ",") || s.EndsWith("," + x))
{
b = true;
break;
}
}
//b = LC.Any(s.Contains);
}
return b;
}
public static bool IsCountryFlag(string s)
{
List<string> CC = new List<string>
{
"World", "Australia", "Brazil", "Canada", "China", "France", "Germany", "Hong Kong", "Italy",
"Japan", "Korea", "Netherlands", "Spain", "Sweden", "USA", "Europe", "Asia"
};
bool b = false;
if (!s.Contains("[") && !s.Contains("]"))
{
foreach (var x in CC)
{
if (s == x || s.StartsWith(x) || s.EndsWith(x))
{
b = true;
break;
}
}
//b = CC.Any(s.Contains);
}
return b;
}
public static string RemoveUnneededOptions(string nameString)
{
// Remove unneeded entries
string n = nameString
.Replace(" (demo) ", " ")
.Replace(" (demo-kiosk) ", " ")
.Replace(" (demo-playable) ", " ")
.Replace(" (demo-rolling) ", " ")
.Replace(" (demo-slideshow) ", " ");
return n;
}
}
}