diff --git a/SabreTools.Library/DatFiles/ItemDictionary.cs b/SabreTools.Library/DatFiles/ItemDictionary.cs index ecf66b62..0da179d9 100644 --- a/SabreTools.Library/DatFiles/ItemDictionary.cs +++ b/SabreTools.Library/DatFiles/ItemDictionary.cs @@ -161,6 +161,12 @@ namespace SabreTools.Library.DatFiles [JsonIgnore] public long FeatureCount { get; private set; } = 0; + /// + /// Number of Info items + /// + [JsonIgnore] + public long InfoCount { get; private set; } = 0; + /// /// Number of Input items /// @@ -599,6 +605,9 @@ namespace SabreTools.Library.DatFiles case ItemType.Feature: FeatureCount++; break; + case ItemType.Info: + InfoCount++; + break; case ItemType.Input: InputCount++; break; @@ -776,6 +785,9 @@ namespace SabreTools.Library.DatFiles case ItemType.Feature: FeatureCount--; break; + case ItemType.Info: + InfoCount--; + break; case ItemType.Input: InputCount--; break; diff --git a/SabreTools.Library/DatFiles/Json.cs b/SabreTools.Library/DatFiles/Json.cs index dd0ba1e9..67653989 100644 --- a/SabreTools.Library/DatFiles/Json.cs +++ b/SabreTools.Library/DatFiles/Json.cs @@ -259,6 +259,9 @@ namespace SabreTools.Library.DatFiles case ItemType.Feature: datItem = datItemObj.ToObject(); break; + case ItemType.Info: + datItem = datItemObj.ToObject(); + break; case ItemType.Input: datItem = datItemObj.ToObject(); break; diff --git a/SabreTools.Library/DatFiles/SabreDat.cs b/SabreTools.Library/DatFiles/SabreDat.cs index e5c0eccf..aa5b281a 100644 --- a/SabreTools.Library/DatFiles/SabreDat.cs +++ b/SabreTools.Library/DatFiles/SabreDat.cs @@ -1473,6 +1473,15 @@ namespace SabreTools.Library.DatFiles xtw.WriteEndElement(); break; + case ItemType.Info: + var info = datItem as Info; + xtw.WriteStartElement("file"); + xtw.WriteAttributeString("type", "info"); + xtw.WriteRequiredAttributeString("name", info.Name); + xtw.WriteRequiredAttributeString("value", info.InfoValue); + xtw.WriteEndElement(); + break; + case ItemType.Input: var input = datItem as Input; xtw.WriteStartElement("file"); diff --git a/SabreTools.Library/DatFiles/SoftwareList.cs b/SabreTools.Library/DatFiles/SoftwareList.cs index e47098a8..b7205504 100644 --- a/SabreTools.Library/DatFiles/SoftwareList.cs +++ b/SabreTools.Library/DatFiles/SoftwareList.cs @@ -164,23 +164,27 @@ namespace SabreTools.Library.DatFiles break; case "info": - var info = new Info(); - info.Name = reader.GetAttribute("name"); - info.Value = reader.GetAttribute("value"); + ParseAddHelper(new Info + { + Name = reader.GetAttribute("name"), + InfoValue = reader.GetAttribute("value"), - // Ensure the list exists - if (machine.Infos == null) - machine.Infos = new List(); - - machine.Infos.Add(info); + Source = new Source + { + Index = indexId, + Name = filename, + }, + }); reader.Read(); break; case "sharedfeat": - var sharedFeature = new SharedFeature(); - sharedFeature.Name = reader.GetAttribute("name"); - sharedFeature.Value = reader.GetAttribute("value"); + var sharedFeature = new SharedFeature + { + Name = reader.GetAttribute("name"), + Value = reader.GetAttribute("value"), + }; // Ensure the list exists if (machine.SharedFeatures == null) @@ -699,17 +703,6 @@ namespace SabreTools.Library.DatFiles xtw.WriteOptionalElementString("publisher", datItem.Machine.Publisher); xtw.WriteOptionalElementString("category", datItem.Machine.Category); - if (datItem.Machine.Infos != null && datItem.Machine.Infos.Count > 0) - { - foreach (Info kvp in datItem.Machine.Infos) - { - xtw.WriteStartElement("info"); - xtw.WriteRequiredAttributeString("name", kvp.Name); - xtw.WriteRequiredAttributeString("value", kvp.Value); - xtw.WriteEndElement(); - } - } - if (datItem.Machine.SharedFeatures != null && datItem.Machine.SharedFeatures.Count > 0) { foreach (SharedFeature kvp in datItem.Machine.SharedFeatures) @@ -828,6 +821,14 @@ namespace SabreTools.Library.DatFiles xtw.WriteEndElement(); break; + case ItemType.Info: + var info = datItem as Info; + xtw.WriteStartElement("info"); + xtw.WriteRequiredAttributeString("name", info.Name); + xtw.WriteRequiredAttributeString("value", info.InfoValue); + xtw.WriteEndElement(); + break; + case ItemType.Rom: var rom = datItem as Rom; if (string.IsNullOrWhiteSpace(areaName)) diff --git a/SabreTools.Library/DatItems/Auxiliary.cs b/SabreTools.Library/DatItems/Auxiliary.cs index b0a510a7..da3611ef 100644 --- a/SabreTools.Library/DatItems/Auxiliary.cs +++ b/SabreTools.Library/DatItems/Auxiliary.cs @@ -15,38 +15,8 @@ namespace SabreTools.Library.DatItems { #region Machine - #region OpenMSX - - /// - /// Represents the OpenMSX original value - /// - [JsonObject("original")] - public class Original - { - [JsonProperty("value")] - public bool? Value { get; set; } - - [JsonProperty("content")] - public string Content { get; set; } - } - - #endregion - #region SoftwareList - /// - /// Represents one SoftwareList info - /// - [JsonObject("info")] - public class Info - { - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("value")] - public string Value { get; set; } - } - /// /// Represents one SoftwareList shared feature object /// @@ -66,6 +36,23 @@ namespace SabreTools.Library.DatItems #region DatItem + #region OpenMSX + + /// + /// Represents the OpenMSX original value + /// + [JsonObject("original")] + public class Original + { + [JsonProperty("value")] + public bool? Value { get; set; } + + [JsonProperty("content")] + public string Content { get; set; } + } + + #endregion + #region SoftwareList /// diff --git a/SabreTools.Library/DatItems/DatItem.cs b/SabreTools.Library/DatItems/DatItem.cs index 42967ac7..6537ab8c 100644 --- a/SabreTools.Library/DatItems/DatItem.cs +++ b/SabreTools.Library/DatItems/DatItem.cs @@ -326,7 +326,6 @@ namespace SabreTools.Library.DatItems // ListXML Field.Machine_SourceFile, Field.Machine_Runnable, - Field.Machine_Infos, // Logiqx Field.Machine_Board, @@ -506,6 +505,9 @@ namespace SabreTools.Library.DatItems case ItemType.Feature: return new Feature(); + case ItemType.Info: + return new Info(); + case ItemType.Input: return new Input(); @@ -570,6 +572,7 @@ namespace SabreTools.Library.DatItems ItemType.Driver => new Driver(), ItemType.Extension => new Extension(), ItemType.Feature => new Feature(), + ItemType.Info => new Info(), ItemType.Instance => new Instance(), ItemType.Location => new Location(), ItemType.Media => new Media(), diff --git a/SabreTools.Library/DatItems/Enums.cs b/SabreTools.Library/DatItems/Enums.cs index b08207cf..6403bcf2 100644 --- a/SabreTools.Library/DatItems/Enums.cs +++ b/SabreTools.Library/DatItems/Enums.cs @@ -221,11 +221,6 @@ namespace SabreTools.Library.DatItems Machine_Supported, - // Infos - Machine_Infos, // TODO: Fix usage of Infos - Machine_Info_Name, - Machine_Info_Value, - // SharedFeatures Machine_SharedFeatures, // TODO: Fix usage of SharedFeatures Machine_SharedFeature_Name, @@ -396,6 +391,9 @@ namespace SabreTools.Library.DatItems DatItem_FeatureStatus, DatItem_FeatureOverall, + // Info + DatItem_InfoValue, + // Inputs DatItem_Service, DatItem_Tilt, @@ -491,6 +489,7 @@ namespace SabreTools.Library.DatItems Driver, Extension, Feature, + Info, Input, Instance, Location, diff --git a/SabreTools.Library/DatItems/Info.cs b/SabreTools.Library/DatItems/Info.cs new file mode 100644 index 00000000..0ab7bca1 --- /dev/null +++ b/SabreTools.Library/DatItems/Info.cs @@ -0,0 +1,243 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SabreTools.Library.Filtering; +using Newtonsoft.Json; +using SabreTools.Library.Tools; + +namespace SabreTools.Library.DatItems +{ + /// + /// Represents special information about a machine + /// + [JsonObject("info")] + public class Info : DatItem + { + #region Fields + + /// + /// Name of the item + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Information value + /// + [JsonProperty("value")] + public string InfoValue { get; set; } + + #endregion + + #region Accessors + + /// + /// Gets the name to use for a DatItem + /// + /// Name if available, null otherwise + public override string GetName() + { + return Name; + } + + /// + /// Set fields with given values + /// + /// Mappings dictionary + public override void SetFields(Dictionary mappings) + { + // Set base fields + base.SetFields(mappings); + + // Handle Info-specific fields + if (mappings.Keys.Contains(Field.DatItem_Name)) + Name = mappings[Field.DatItem_Name]; + + if (mappings.Keys.Contains(Field.DatItem_InfoValue)) + InfoValue = mappings[Field.DatItem_InfoValue]; + } + + #endregion + + #region Constructors + + /// + /// Create a default, empty Info object + /// + public Info() + { + Name = string.Empty; + ItemType = ItemType.Info; + } + + #endregion + + #region Cloning Methods + + public override object Clone() + { + return new Info() + { + Name = this.Name, + ItemType = this.ItemType, + DupeType = this.DupeType, + + AltName = this.AltName, + AltTitle = this.AltTitle, + + Original = this.Original, + OpenMSXSubType = this.OpenMSXSubType, + OpenMSXType = this.OpenMSXType, + Remark = this.Remark, + Boot = this.Boot, + + Part = this.Part, + Features = this.Features, + AreaName = this.AreaName, + AreaSize = this.AreaSize, + AreaWidth = this.AreaWidth, + AreaEndianness = this.AreaEndianness, + Value = this.Value, + LoadFlag = this.LoadFlag, + + Machine = this.Machine.Clone() as Machine, + Source = this.Source.Clone() as Source, + Remove = this.Remove, + + InfoValue = this.InfoValue, + }; + } + + #endregion + + #region Comparision Methods + + public override bool Equals(DatItem other) + { + // If we don't have a sample, return false + if (ItemType != other.ItemType) + return false; + + // Otherwise, treat it as a Info + Info newOther = other as Info; + + // If the archive information matches + return (Name == newOther.Name && InfoValue == newOther.InfoValue); + } + + #endregion + + #region Filtering + + /// + /// Clean a DatItem according to the cleaner + /// + /// Cleaner to implement + public override void Clean(Cleaner cleaner) + { + // Clean common items first + base.Clean(cleaner); + + // If we're stripping unicode characters, strip item name + if (cleaner?.RemoveUnicode == true) + Name = Sanitizer.RemoveUnicodeCharacters(Name); + + // If we are in NTFS trim mode, trim the game name + if (cleaner?.Trim == true) + { + // Windows max name length is 260 + int usableLength = 260 - Machine.Name.Length - (cleaner.Root?.Length ?? 0); + if (Name.Length > usableLength) + { + string ext = Path.GetExtension(Name); + Name = Name.Substring(0, usableLength - ext.Length); + Name += ext; + } + } + } + + /// + /// Check to see if a DatItem passes the filter + /// + /// Filter to check against + /// True if the item passed the filter, false otherwise + public override bool PassesFilter(Filter filter) + { + // Check common fields first + if (!base.PassesFilter(filter)) + return false; + + // Filter on item name + if (filter.DatItem_Name.MatchesPositiveSet(Name) == false) + return false; + if (filter.DatItem_Name.MatchesNegativeSet(Name) == true) + return false; + + // Filter on info value + if (filter.DatItem_InfoValue.MatchesPositiveSet(InfoValue) == false) + return false; + if (filter.DatItem_InfoValue.MatchesNegativeSet(InfoValue) == true) + return false; + + return true; + } + + /// + /// Remove fields from the DatItem + /// + /// List of Fields to remove + public override void RemoveFields(List fields) + { + // Remove common fields first + base.RemoveFields(fields); + + // Remove the fields + if (fields.Contains(Field.DatItem_Name)) + Name = null; + + if (fields.Contains(Field.DatItem_InfoValue)) + InfoValue = null; + } + + /// + /// Set internal names to match One Rom Per Game (ORPG) logic + /// + public override void SetOneRomPerGame() + { + string[] splitname = Name.Split('.'); + Machine.Name += $"/{string.Join(".", splitname.Take(splitname.Length > 1 ? splitname.Length - 1 : 1))}"; + Name = Path.GetFileName(Name); + } + + #endregion + + #region Sorting and Merging + + /// + /// Replace fields from another item + /// + /// DatItem to pull new information from + /// List of Fields representing what should be updated + public override void ReplaceFields(DatItem item, List fields) + { + // Replace common fields first + base.ReplaceFields(item, fields); + + // If we don't have a Info to replace from, ignore specific fields + if (item.ItemType != ItemType.Info) + return; + + // Cast for easier access + Info newItem = item as Info; + + // Replace the fields + if (fields.Contains(Field.DatItem_Name)) + Name = newItem.Name; + + if (fields.Contains(Field.DatItem_InfoValue)) + InfoValue = newItem.InfoValue; + } + + #endregion + } +} diff --git a/SabreTools.Library/DatItems/Machine.cs b/SabreTools.Library/DatItems/Machine.cs index c14cde18..6becc6cf 100644 --- a/SabreTools.Library/DatItems/Machine.cs +++ b/SabreTools.Library/DatItems/Machine.cs @@ -259,13 +259,6 @@ namespace SabreTools.Library.DatItems [JsonProperty("supported", DefaultValueHandling = DefaultValueHandling.Ignore)] public Supported Supported { get; set; } = Supported.NULL; - /// - /// List of info items - /// - /// Also in SoftwareList - [JsonProperty("infos", DefaultValueHandling = DefaultValueHandling.Ignore)] - public List Infos { get; set; } = null; - /// /// List of shared feature items /// @@ -522,7 +515,6 @@ namespace SabreTools.Library.DatItems #region SoftwareList Supported = this.Supported, - Infos = this.Infos, SharedFeatures = this.SharedFeatures, #endregion @@ -790,54 +782,6 @@ namespace SabreTools.Library.DatItems if (filter.Machine_Supported.MatchesNegative(Supported.NULL, Supported) == true) return false; - #region Infos - - // Machine_Infos - if (filter.Machine_Infos.MatchesNeutral(null, Infos?.Any() ?? null) == false) - return false; - - // Machine_Info_Name - if (Infos?.Any() == true) - { - bool anyPositive = false; - bool anyNegative = false; - - foreach (var info in Infos) - { - if (filter.Machine_Info_Name.MatchesPositiveSet(info?.Name) != false) - anyPositive = true; - if (filter.Machine_Info_Name.MatchesNegativeSet(info?.Name) == true) - anyNegative = true; - } - - if (!anyPositive) - return false; - if (anyNegative) - return false; - } - - // Machine_Info_Value - if (Infos?.Any() == true) - { - bool anyPositive = false; - bool anyNegative = false; - - foreach (var info in Infos) - { - if (filter.Machine_Info_Value.MatchesPositiveSet(info?.Value) != false) - anyPositive = true; - if (filter.Machine_Info_Value.MatchesNegativeSet(info?.Value) == true) - anyNegative = true; - } - - if (!anyPositive) - return false; - if (anyNegative) - return false; - } - - #endregion - #region SharedFeatures // Machine_SharedFeatures @@ -968,9 +912,6 @@ namespace SabreTools.Library.DatItems if (fields.Contains(Field.Machine_Runnable)) Runnable = Runnable.NULL; - if (fields.Contains(Field.Machine_Infos)) - Infos = null; - #endregion #region Logiqx @@ -1124,9 +1065,6 @@ namespace SabreTools.Library.DatItems if (fields.Contains(Field.Machine_Runnable)) Runnable = machine.Runnable; - if (fields.Contains(Field.Machine_Infos)) - Infos = machine.Infos; - #endregion #region Logiqx diff --git a/SabreTools.Library/Filtering/Filter.cs b/SabreTools.Library/Filtering/Filter.cs index 9a455209..2c8db4a4 100644 --- a/SabreTools.Library/Filtering/Filter.cs +++ b/SabreTools.Library/Filtering/Filter.cs @@ -86,11 +86,6 @@ namespace SabreTools.Library.Filtering public FilterItem Machine_Supported { get; private set; } = new FilterItem() { Positive = Supported.NULL, Negative = Supported.NULL }; - // Infos - public FilterItem Machine_Infos { get; private set; } = new FilterItem() { Neutral = null }; - public FilterItem Machine_Info_Name { get; private set; } = new FilterItem(); - public FilterItem Machine_Info_Value { get; private set; } = new FilterItem(); - // SharedFeatures public FilterItem Machine_SharedFeatures { get; private set; } = new FilterItem() { Neutral = null }; public FilterItem Machine_SharedFeature_Name { get; private set; } = new FilterItem(); @@ -261,6 +256,9 @@ namespace SabreTools.Library.Filtering public FilterItem DatItem_FeatureStatus { get; private set; } = new FilterItem() { Positive = FeatureStatus.NULL, Negative = FeatureStatus.NULL }; public FilterItem DatItem_FeatureOverall { get; private set; } = new FilterItem() { Positive = FeatureStatus.NULL, Negative = FeatureStatus.NULL }; + // Info + public FilterItem DatItem_InfoValue { get; private set; } = new FilterItem(); + // Input public FilterItem DatItem_Service { get; private set; } = new FilterItem() { Neutral = null }; public FilterItem DatItem_Tilt { get; private set; } = new FilterItem() { Neutral = null }; @@ -653,28 +651,6 @@ namespace SabreTools.Library.Filtering Machine_Supported.Positive |= value.AsSupported(); break; - // Infos - case Field.Machine_Infos: - if (negate || value.Equals("false", StringComparison.OrdinalIgnoreCase)) - Machine_Infos.Neutral = false; - else - Machine_Infos.Neutral = true; - break; - - case Field.Machine_Info_Name: - if (negate) - Machine_Info_Name.NegativeSet.Add(value); - else - Machine_Info_Name.PositiveSet.Add(value); - break; - - case Field.Machine_Info_Value: - if (negate) - Machine_Info_Value.NegativeSet.Add(value); - else - Machine_Info_Value.PositiveSet.Add(value); - break; - // SharedFeatures case Field.Machine_SharedFeatures: if (negate || value.Equals("false", StringComparison.OrdinalIgnoreCase)) @@ -1491,6 +1467,14 @@ namespace SabreTools.Library.Filtering DatItem_FeatureOverall.Positive |= value.AsFeatureStatus(); break; + // Info + case Field.DatItem_InfoValue: + if (negate) + DatItem_InfoValue.NegativeSet.Add(value); + else + DatItem_InfoValue.PositiveSet.Add(value); + break; + // Input case Field.DatItem_Service: if (negate || value.Equals("false", StringComparison.OrdinalIgnoreCase)) diff --git a/SabreTools.Library/Tools/Converters.cs b/SabreTools.Library/Tools/Converters.cs index 0e9e840d..21b09fe7 100644 --- a/SabreTools.Library/Tools/Converters.cs +++ b/SabreTools.Library/Tools/Converters.cs @@ -644,15 +644,6 @@ namespace SabreTools.Library.Tools case "supported": return Field.Machine_Supported; - case "infos": - return Field.Machine_Infos; - - case "info_name": - return Field.Machine_Info_Name; - - case "info_value": - return Field.Machine_Info_Value; - case "sharedfeatures": return Field.Machine_SharedFeatures; @@ -1044,6 +1035,10 @@ namespace SabreTools.Library.Tools case "featureoverall": return Field.DatItem_FeatureOverall; + // Info + case "infovalue": + return Field.DatItem_InfoValue; + // Input case "service": return Field.DatItem_Service; @@ -1136,9 +1131,9 @@ namespace SabreTools.Library.Tools case "channels": return Field.DatItem_Channels; - #endregion + #endregion - #endregion // Item-Specific + #endregion // Item-Specific } } @@ -1255,9 +1250,6 @@ namespace SabreTools.Library.Tools case "runnable": return Field.Machine_Runnable; - case "infos": - return Field.Machine_Infos; - #endregion #region Logiqx @@ -1673,6 +1665,8 @@ namespace SabreTools.Library.Tools return ItemType.Extension; case "feature": return ItemType.Feature; + case "info": + return ItemType.Info; case "input": return ItemType.Input; case "instance": @@ -1724,6 +1718,7 @@ namespace SabreTools.Library.Tools "driver" => ItemType.Driver, "extension" => ItemType.Extension, "feature" => ItemType.Feature, + "info" => ItemType.Info, "input" => ItemType.Input, "instance" => ItemType.Instance, "location" => ItemType.Location, @@ -2314,6 +2309,8 @@ namespace SabreTools.Library.Tools return "extension"; case ItemType.Feature: return "feature"; + case ItemType.Info: + return "info"; case ItemType.Input: return "input"; case ItemType.Instance: @@ -2365,6 +2362,7 @@ namespace SabreTools.Library.Tools ItemType.Driver => "driver", ItemType.Extension => "extension", ItemType.Feature => "feature", + ItemType.Info => "info", ItemType.Input => "input", ItemType.Instance => "instance", ItemType.Location => "location",