mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-09-25 00:05:07 +00:00
Port metadata functionality from ST
This commit is contained in:
346
SabreTools.Metadata.DatItems/DatItem.cs
Normal file
346
SabreTools.Metadata.DatItems/DatItem.cs
Normal file
@@ -0,0 +1,346 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Data.Extensions;
|
||||
using SabreTools.Hashing;
|
||||
using SabreTools.IO.Logging;
|
||||
using SabreTools.Metadata.DatItems.Formats;
|
||||
using SabreTools.Metadata.Filter;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all items included in a set
|
||||
/// </summary>
|
||||
[JsonObject("datitem"), XmlRoot("datitem")]
|
||||
[XmlInclude(typeof(Adjuster))]
|
||||
[XmlInclude(typeof(Analog))]
|
||||
[XmlInclude(typeof(Archive))]
|
||||
[XmlInclude(typeof(BiosSet))]
|
||||
[XmlInclude(typeof(Blank))]
|
||||
[XmlInclude(typeof(Chip))]
|
||||
[XmlInclude(typeof(Condition))]
|
||||
[XmlInclude(typeof(Configuration))]
|
||||
[XmlInclude(typeof(ConfLocation))]
|
||||
[XmlInclude(typeof(ConfSetting))]
|
||||
[XmlInclude(typeof(Control))]
|
||||
[XmlInclude(typeof(DataArea))]
|
||||
[XmlInclude(typeof(Device))]
|
||||
[XmlInclude(typeof(DeviceRef))]
|
||||
[XmlInclude(typeof(DipLocation))]
|
||||
[XmlInclude(typeof(DipSwitch))]
|
||||
[XmlInclude(typeof(DipValue))]
|
||||
[XmlInclude(typeof(Disk))]
|
||||
[XmlInclude(typeof(DiskArea))]
|
||||
[XmlInclude(typeof(Display))]
|
||||
[XmlInclude(typeof(Driver))]
|
||||
[XmlInclude(typeof(Extension))]
|
||||
[XmlInclude(typeof(Feature))]
|
||||
[XmlInclude(typeof(Info))]
|
||||
[XmlInclude(typeof(Input))]
|
||||
[XmlInclude(typeof(Instance))]
|
||||
[XmlInclude(typeof(Media))]
|
||||
[XmlInclude(typeof(Part))]
|
||||
[XmlInclude(typeof(PartFeature))]
|
||||
[XmlInclude(typeof(Port))]
|
||||
[XmlInclude(typeof(RamOption))]
|
||||
[XmlInclude(typeof(Release))]
|
||||
[XmlInclude(typeof(Rom))]
|
||||
[XmlInclude(typeof(Sample))]
|
||||
[XmlInclude(typeof(SharedFeat))]
|
||||
[XmlInclude(typeof(Slot))]
|
||||
[XmlInclude(typeof(SlotOption))]
|
||||
[XmlInclude(typeof(SoftwareList))]
|
||||
[XmlInclude(typeof(Sound))]
|
||||
public abstract class DatItem : ModelBackedItem<Data.Models.Metadata.DatItem>, IEquatable<DatItem>, IComparable<DatItem>, ICloneable
|
||||
{
|
||||
#region Constants
|
||||
|
||||
/// <summary>
|
||||
/// Duplicate type when compared to another item
|
||||
/// </summary>
|
||||
public const string DupeTypeKey = "DUPETYPE";
|
||||
|
||||
/// <summary>
|
||||
/// Machine associated with the item
|
||||
/// </summary>
|
||||
public const string MachineKey = "MACHINE";
|
||||
|
||||
/// <summary>
|
||||
/// Flag if item should be removed
|
||||
/// </summary>
|
||||
public const string RemoveKey = "REMOVE";
|
||||
|
||||
/// <summary>
|
||||
/// Source information
|
||||
/// </summary>
|
||||
public const string SourceKey = "SOURCE";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Item type for the object
|
||||
/// </summary>
|
||||
protected abstract ItemType ItemType { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Logging
|
||||
|
||||
/// <summary>
|
||||
/// Static logger for static methods
|
||||
/// </summary>
|
||||
[JsonIgnore, XmlIgnore]
|
||||
protected static readonly Logger _staticLogger = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Accessors
|
||||
|
||||
/// <summary>
|
||||
/// Get the machine for a DatItem
|
||||
/// </summary>
|
||||
/// <returns>Machine if available, null otherwise</returns>
|
||||
/// <remarks>Relies on <see cref="MachineKey"/></remarks>
|
||||
public Machine? GetMachine() => _internal.Read<Machine>(MachineKey);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name to use for a DatItem
|
||||
/// </summary>
|
||||
/// <returns>Name if available, null otherwise</returns>
|
||||
public virtual string? GetName() => _internal.GetName();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the name to use for a DatItem
|
||||
/// </summary>
|
||||
/// <param name="name">Name to set for the item</param>
|
||||
public virtual void SetName(string? name) => _internal.SetName(name);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <summary>
|
||||
/// Clone the DatItem
|
||||
/// </summary>
|
||||
/// <returns>Clone of the DatItem</returns>
|
||||
public abstract object Clone();
|
||||
|
||||
/// <summary>
|
||||
/// Copy all machine information over in one shot
|
||||
/// </summary>
|
||||
/// <param name="item">Existing item to copy information from</param>
|
||||
public void CopyMachineInformation(DatItem item)
|
||||
{
|
||||
// If there is no machine
|
||||
if (!item._internal.ContainsKey(MachineKey))
|
||||
return;
|
||||
|
||||
var machine = item.GetMachine();
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy all machine information over in one shot
|
||||
/// </summary>
|
||||
/// <param name="machine">Existing machine to copy information from</param>
|
||||
public void CopyMachineInformation(Machine? machine)
|
||||
{
|
||||
if (machine is null)
|
||||
return;
|
||||
|
||||
if (machine.Clone() is Machine cloned)
|
||||
SetFieldValue(MachineKey, cloned);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Comparision Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int CompareTo(DatItem? other)
|
||||
{
|
||||
// If the other item doesn't exist
|
||||
if (other is null)
|
||||
return 1;
|
||||
|
||||
// Get the names to avoid changing values
|
||||
string? selfName = GetName();
|
||||
string? otherName = other.GetName();
|
||||
|
||||
// If the names are equal
|
||||
if (selfName == otherName)
|
||||
return Equals(other) ? 0 : 1;
|
||||
|
||||
// If `otherName` is null, Compare will return > 0
|
||||
// If `selfName` is null, Compare will return < 0
|
||||
return string.Compare(selfName, otherName, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(ModelBackedItem? other)
|
||||
{
|
||||
// If other is null
|
||||
if (other is null)
|
||||
return false;
|
||||
|
||||
// If the type is mismatched
|
||||
if (other is not DatItem otherItem)
|
||||
return false;
|
||||
|
||||
// Compare internal models
|
||||
return _internal.Equals(otherItem);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(ModelBackedItem<Data.Models.Metadata.DatItem>? other)
|
||||
{
|
||||
// If other is null
|
||||
if (other is null)
|
||||
return false;
|
||||
|
||||
// If the type is mismatched
|
||||
if (other is not DatItem otherItem)
|
||||
return false;
|
||||
|
||||
// Compare internal models
|
||||
return _internal.Equals(otherItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if an item is a duplicate using partial matching logic
|
||||
/// </summary>
|
||||
/// <param name="other">DatItem to use as a baseline</param>
|
||||
/// <returns>True if the items are duplicates, false otherwise</returns>
|
||||
public virtual bool Equals(DatItem? other)
|
||||
{
|
||||
// If the other item is null
|
||||
if (other is null)
|
||||
return false;
|
||||
|
||||
// Get the types for comparison
|
||||
ItemType selfType = GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey).AsItemType();
|
||||
ItemType otherType = other.GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey).AsItemType();
|
||||
|
||||
// If we don't have a matched type, return false
|
||||
if (selfType != otherType)
|
||||
return false;
|
||||
|
||||
// Compare the internal models
|
||||
return _internal.EqualTo(other._internal);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Manipulation
|
||||
|
||||
/// <summary>
|
||||
/// Runs a filter and determines if it passes or not
|
||||
/// </summary>
|
||||
/// <param name="filterRunner">Filter runner to use for checking</param>
|
||||
/// <returns>True if the item and its machine passes the filter, false otherwise</returns>
|
||||
public bool PassesFilter(FilterRunner filterRunner)
|
||||
{
|
||||
var machine = GetMachine();
|
||||
if (machine is not null && !machine.PassesFilter(filterRunner))
|
||||
return false;
|
||||
|
||||
return filterRunner.Run(_internal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs a filter and determines if it passes or not
|
||||
/// </summary>
|
||||
/// <param name="filterRunner">Filter runner to use for checking</param>
|
||||
/// <returns>True if the item passes the filter, false otherwise</returns>
|
||||
public bool PassesFilterDB(FilterRunner filterRunner)
|
||||
=> filterRunner.Run(_internal);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sorting and Merging
|
||||
|
||||
/// <summary>
|
||||
/// Get the dictionary key that should be used for a given item and bucketing type
|
||||
/// </summary>
|
||||
/// <param name="bucketedBy">ItemKey value representing what key to get</param>
|
||||
/// <param name="machine">Machine associated with the item for renaming</param>
|
||||
/// <param name="source">Source associated with the item for renaming</param>
|
||||
/// <param name="lower">True if the key should be lowercased (default), false otherwise</param>
|
||||
/// <param name="norename">True if games should only be compared on game and file name, false if system and source are counted</param>
|
||||
/// <returns>String representing the key to be used for the DatItem</returns>
|
||||
public virtual string GetKey(ItemKey bucketedBy, Machine? machine, Source? source, bool lower = true, bool norename = true)
|
||||
{
|
||||
// Set the output key as the default blank string
|
||||
string key = string.Empty;
|
||||
|
||||
string sourceKeyPadded = source?.Index.ToString().PadLeft(10, '0') + '-';
|
||||
string machineName = machine?.GetName() ?? "Default";
|
||||
|
||||
#pragma warning disable IDE0010
|
||||
// Now determine what the key should be based on the bucketedBy value
|
||||
switch (bucketedBy)
|
||||
{
|
||||
case ItemKey.CRC:
|
||||
key = HashType.CRC32.ZeroString;
|
||||
break;
|
||||
|
||||
case ItemKey.Machine:
|
||||
key = (norename ? string.Empty : sourceKeyPadded) + machineName;
|
||||
break;
|
||||
|
||||
case ItemKey.MD2:
|
||||
key = HashType.MD2.ZeroString;
|
||||
break;
|
||||
|
||||
case ItemKey.MD4:
|
||||
key = HashType.MD4.ZeroString;
|
||||
break;
|
||||
|
||||
case ItemKey.MD5:
|
||||
key = HashType.MD5.ZeroString;
|
||||
break;
|
||||
|
||||
case ItemKey.RIPEMD128:
|
||||
key = HashType.RIPEMD128.ZeroString;
|
||||
break;
|
||||
|
||||
case ItemKey.RIPEMD160:
|
||||
key = HashType.RIPEMD160.ZeroString;
|
||||
break;
|
||||
|
||||
case ItemKey.SHA1:
|
||||
key = HashType.SHA1.ZeroString;
|
||||
break;
|
||||
|
||||
case ItemKey.SHA256:
|
||||
key = HashType.SHA256.ZeroString;
|
||||
break;
|
||||
|
||||
case ItemKey.SHA384:
|
||||
key = HashType.SHA384.ZeroString;
|
||||
break;
|
||||
|
||||
case ItemKey.SHA512:
|
||||
key = HashType.SHA512.ZeroString;
|
||||
break;
|
||||
|
||||
case ItemKey.SpamSum:
|
||||
key = HashType.SpamSum.ZeroString;
|
||||
break;
|
||||
}
|
||||
#pragma warning restore IDE0010
|
||||
|
||||
// Double and triple check the key for corner cases
|
||||
key ??= string.Empty;
|
||||
if (lower)
|
||||
key = key.ToLowerInvariant();
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
112
SabreTools.Metadata.DatItems/DatItemT.cs
Normal file
112
SabreTools.Metadata.DatItems/DatItemT.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all items included in a set that are backed by an internal model
|
||||
/// </summary>
|
||||
public abstract class DatItem<T> : DatItem, IEquatable<DatItem<T>>, IComparable<DatItem<T>>, ICloneable where T : Data.Models.Metadata.DatItem
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Create a default, empty object
|
||||
/// </summary>
|
||||
public DatItem()
|
||||
{
|
||||
_internal = Activator.CreateInstance<T>();
|
||||
|
||||
SetName(string.Empty);
|
||||
SetFieldValue(Data.Models.Metadata.DatItem.TypeKey, ItemType);
|
||||
SetFieldValue(MachineKey, new Machine());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an object from the internal model
|
||||
/// </summary>
|
||||
public DatItem(T item)
|
||||
{
|
||||
_internal = item;
|
||||
|
||||
SetFieldValue(Data.Models.Metadata.DatItem.TypeKey, ItemType);
|
||||
SetFieldValue(MachineKey, new Machine());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <summary>
|
||||
/// Clone the DatItem
|
||||
/// </summary>
|
||||
/// <returns>Clone of the DatItem</returns>
|
||||
/// <remarks>
|
||||
/// Throws an exception if there is a DatItem implementation
|
||||
/// that is not a part of this library.
|
||||
/// </remarks>
|
||||
public override object Clone()
|
||||
{
|
||||
var concrete = Array.Find(Assembly.GetExecutingAssembly().GetTypes(),
|
||||
t => !t.IsAbstract && t.IsClass && t.BaseType == typeof(DatItem<T>));
|
||||
|
||||
var clone = Activator.CreateInstance(concrete!);
|
||||
(clone as DatItem<T>)!._internal = _internal?.Clone() as T ?? Activator.CreateInstance<T>();
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a clone of the current internal model
|
||||
/// </summary>
|
||||
public virtual T GetInternalClone() => (_internal.Clone() as T)!;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Comparision Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int CompareTo(DatItem<T>? other)
|
||||
{
|
||||
// If the other item doesn't exist
|
||||
if (other is null)
|
||||
return 1;
|
||||
|
||||
// Get the names to avoid changing values
|
||||
string? selfName = GetName();
|
||||
string? otherName = other.GetName();
|
||||
|
||||
// If the names are equal
|
||||
if (selfName == otherName)
|
||||
return Equals(other) ? 0 : 1;
|
||||
|
||||
// If `otherName` is null, Compare will return > 0
|
||||
// If `selfName` is null, Compare will return < 0
|
||||
return string.Compare(selfName, otherName, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if an item is a duplicate using partial matching logic
|
||||
/// </summary>
|
||||
/// <param name="other">DatItem to use as a baseline</param>
|
||||
/// <returns>True if the items are duplicates, false otherwise</returns>
|
||||
public virtual bool Equals(DatItem<T>? other)
|
||||
{
|
||||
// If the other value is null
|
||||
if (other is null)
|
||||
return false;
|
||||
|
||||
// Get the types for comparison
|
||||
ItemType selfType = GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey).AsItemType();
|
||||
ItemType otherType = other.GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey).AsItemType();
|
||||
|
||||
// If we don't have a matched type, return false
|
||||
if (selfType != otherType)
|
||||
return false;
|
||||
|
||||
// Compare the internal models
|
||||
return _internal.EqualTo(other._internal);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
685
SabreTools.Metadata.DatItems/Enums.cs
Normal file
685
SabreTools.Metadata.DatItems/Enums.cs
Normal file
@@ -0,0 +1,685 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems
|
||||
{
|
||||
/// <summary>
|
||||
/// Determine the chip type
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum ChipType
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("cpu")]
|
||||
CPU = 1 << 0,
|
||||
|
||||
[Mapping("audio")]
|
||||
Audio = 1 << 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the control type
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum ControlType
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("joy")]
|
||||
Joy = 1 << 0,
|
||||
|
||||
[Mapping("stick")]
|
||||
Stick = 1 << 1,
|
||||
|
||||
[Mapping("paddle")]
|
||||
Paddle = 1 << 2,
|
||||
|
||||
[Mapping("pedal")]
|
||||
Pedal = 1 << 3,
|
||||
|
||||
[Mapping("lightgun")]
|
||||
Lightgun = 1 << 4,
|
||||
|
||||
[Mapping("positional")]
|
||||
Positional = 1 << 5,
|
||||
|
||||
[Mapping("dial")]
|
||||
Dial = 1 << 6,
|
||||
|
||||
[Mapping("trackball")]
|
||||
Trackball = 1 << 7,
|
||||
|
||||
[Mapping("mouse")]
|
||||
Mouse = 1 << 8,
|
||||
|
||||
[Mapping("only_buttons")]
|
||||
OnlyButtons = 1 << 9,
|
||||
|
||||
[Mapping("keypad")]
|
||||
Keypad = 1 << 10,
|
||||
|
||||
[Mapping("keyboard")]
|
||||
Keyboard = 1 << 11,
|
||||
|
||||
[Mapping("mahjong")]
|
||||
Mahjong = 1 << 12,
|
||||
|
||||
[Mapping("hanafuda")]
|
||||
Hanafuda = 1 << 13,
|
||||
|
||||
[Mapping("gambling")]
|
||||
Gambling = 1 << 14,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the device type
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum DeviceType
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("unknown")]
|
||||
Unknown = 1 << 0,
|
||||
|
||||
[Mapping("cartridge")]
|
||||
Cartridge = 1 << 1,
|
||||
|
||||
[Mapping("floppydisk")]
|
||||
FloppyDisk = 1 << 2,
|
||||
|
||||
[Mapping("harddisk")]
|
||||
HardDisk = 1 << 3,
|
||||
|
||||
[Mapping("cylinder")]
|
||||
Cylinder = 1 << 4,
|
||||
|
||||
[Mapping("cassette")]
|
||||
Cassette = 1 << 5,
|
||||
|
||||
[Mapping("punchcard")]
|
||||
PunchCard = 1 << 6,
|
||||
|
||||
[Mapping("punchtape")]
|
||||
PunchTape = 1 << 7,
|
||||
|
||||
[Mapping("printout")]
|
||||
Printout = 1 << 8,
|
||||
|
||||
[Mapping("serial")]
|
||||
Serial = 1 << 9,
|
||||
|
||||
[Mapping("parallel")]
|
||||
Parallel = 1 << 10,
|
||||
|
||||
[Mapping("snapshot")]
|
||||
Snapshot = 1 << 11,
|
||||
|
||||
[Mapping("quickload")]
|
||||
QuickLoad = 1 << 12,
|
||||
|
||||
[Mapping("memcard")]
|
||||
MemCard = 1 << 13,
|
||||
|
||||
[Mapping("cdrom")]
|
||||
CDROM = 1 << 14,
|
||||
|
||||
[Mapping("magtape")]
|
||||
MagTape = 1 << 15,
|
||||
|
||||
[Mapping("romimage")]
|
||||
ROMImage = 1 << 16,
|
||||
|
||||
[Mapping("midiin")]
|
||||
MIDIIn = 1 << 17,
|
||||
|
||||
[Mapping("midiout")]
|
||||
MIDIOut = 1 << 18,
|
||||
|
||||
[Mapping("picture")]
|
||||
Picture = 1 << 19,
|
||||
|
||||
[Mapping("vidfile")]
|
||||
VidFile = 1 << 20,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the display type
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum DisplayType
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("raster")]
|
||||
Raster = 1 << 0,
|
||||
|
||||
[Mapping("vector")]
|
||||
Vector = 1 << 1,
|
||||
|
||||
[Mapping("lcd")]
|
||||
LCD = 1 << 2,
|
||||
|
||||
[Mapping("svg")]
|
||||
SVG = 1 << 3,
|
||||
|
||||
[Mapping("unknown")]
|
||||
Unknown = 1 << 4,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines which type of duplicate a file is
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum DupeType
|
||||
{
|
||||
// Type of match
|
||||
Hash = 1 << 0,
|
||||
All = 1 << 1,
|
||||
|
||||
// Location of match
|
||||
Internal = 1 << 2,
|
||||
External = 1 << 3,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the endianness
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum Endianness
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("big")]
|
||||
Big = 1 << 0,
|
||||
|
||||
[Mapping("little")]
|
||||
Little = 1 << 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the emulation status
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum FeatureStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("unemulated")]
|
||||
Unemulated = 1 << 0,
|
||||
|
||||
[Mapping("imperfect")]
|
||||
Imperfect = 1 << 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the feature type
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum FeatureType
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("protection")]
|
||||
Protection = 1 << 0,
|
||||
|
||||
[Mapping("palette")]
|
||||
Palette = 1 << 1,
|
||||
|
||||
[Mapping("graphics")]
|
||||
Graphics = 1 << 2,
|
||||
|
||||
[Mapping("sound")]
|
||||
Sound = 1 << 3,
|
||||
|
||||
[Mapping("controls")]
|
||||
Controls = 1 << 4,
|
||||
|
||||
[Mapping("keyboard")]
|
||||
Keyboard = 1 << 5,
|
||||
|
||||
[Mapping("mouse")]
|
||||
Mouse = 1 << 6,
|
||||
|
||||
[Mapping("microphone")]
|
||||
Microphone = 1 << 7,
|
||||
|
||||
[Mapping("camera")]
|
||||
Camera = 1 << 8,
|
||||
|
||||
[Mapping("disk")]
|
||||
Disk = 1 << 9,
|
||||
|
||||
[Mapping("printer")]
|
||||
Printer = 1 << 10,
|
||||
|
||||
[Mapping("lan")]
|
||||
Lan = 1 << 11,
|
||||
|
||||
[Mapping("wan")]
|
||||
Wan = 1 << 12,
|
||||
|
||||
[Mapping("timing")]
|
||||
Timing = 1 << 13,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A subset of fields that can be used as keys
|
||||
/// </summary>
|
||||
public enum ItemKey
|
||||
{
|
||||
NULL = 0,
|
||||
|
||||
Machine,
|
||||
|
||||
CRC,
|
||||
MD2,
|
||||
MD4,
|
||||
MD5,
|
||||
RIPEMD128,
|
||||
RIPEMD160,
|
||||
SHA1,
|
||||
SHA256,
|
||||
SHA384,
|
||||
SHA512,
|
||||
SpamSum,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the status of the item
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum ItemStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("none", "no")]
|
||||
None = 1 << 0,
|
||||
|
||||
[Mapping("good")]
|
||||
Good = 1 << 1,
|
||||
|
||||
[Mapping("baddump")]
|
||||
BadDump = 1 << 2,
|
||||
|
||||
[Mapping("nodump", "yes")]
|
||||
Nodump = 1 << 3,
|
||||
|
||||
[Mapping("verified")]
|
||||
Verified = 1 << 4,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine what type of file an item is
|
||||
/// </summary>
|
||||
public enum ItemType
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
// "Actionable" item types
|
||||
|
||||
[Mapping("rom")]
|
||||
Rom,
|
||||
|
||||
[Mapping("disk")]
|
||||
Disk,
|
||||
|
||||
[Mapping("file")]
|
||||
File,
|
||||
|
||||
[Mapping("media")]
|
||||
Media,
|
||||
|
||||
// "Auxiliary" item types
|
||||
|
||||
[Mapping("adjuster")]
|
||||
Adjuster,
|
||||
|
||||
[Mapping("analog")]
|
||||
Analog,
|
||||
|
||||
[Mapping("archive")]
|
||||
Archive,
|
||||
|
||||
[Mapping("biosset")]
|
||||
BiosSet,
|
||||
|
||||
[Mapping("chip")]
|
||||
Chip,
|
||||
|
||||
[Mapping("condition")]
|
||||
Condition,
|
||||
|
||||
[Mapping("configuration")]
|
||||
Configuration,
|
||||
|
||||
[Mapping("conflocation")]
|
||||
ConfLocation,
|
||||
|
||||
[Mapping("confsetting")]
|
||||
ConfSetting,
|
||||
|
||||
[Mapping("control")]
|
||||
Control,
|
||||
|
||||
[Mapping("dataarea")]
|
||||
DataArea,
|
||||
|
||||
[Mapping("device")]
|
||||
Device,
|
||||
|
||||
[Mapping("device_ref", "deviceref")]
|
||||
DeviceRef,
|
||||
|
||||
[Mapping("diplocation")]
|
||||
DipLocation,
|
||||
|
||||
[Mapping("dipswitch")]
|
||||
DipSwitch,
|
||||
|
||||
[Mapping("dipvalue")]
|
||||
DipValue,
|
||||
|
||||
[Mapping("diskarea")]
|
||||
DiskArea,
|
||||
|
||||
[Mapping("display")]
|
||||
Display,
|
||||
|
||||
[Mapping("driver")]
|
||||
Driver,
|
||||
|
||||
[Mapping("extension")]
|
||||
Extension,
|
||||
|
||||
[Mapping("feature")]
|
||||
Feature,
|
||||
|
||||
[Mapping("info")]
|
||||
Info,
|
||||
|
||||
[Mapping("input")]
|
||||
Input,
|
||||
|
||||
[Mapping("instance")]
|
||||
Instance,
|
||||
|
||||
[Mapping("original")]
|
||||
Original,
|
||||
|
||||
[Mapping("part")]
|
||||
Part,
|
||||
|
||||
[Mapping("part_feature", "partfeature")]
|
||||
PartFeature,
|
||||
|
||||
[Mapping("port")]
|
||||
Port,
|
||||
|
||||
[Mapping("ramoption", "ram_option")]
|
||||
RamOption,
|
||||
|
||||
[Mapping("release")]
|
||||
Release,
|
||||
|
||||
[Mapping("release_details", "releasedetails")]
|
||||
ReleaseDetails,
|
||||
|
||||
[Mapping("sample")]
|
||||
Sample,
|
||||
|
||||
[Mapping("serials")]
|
||||
Serials,
|
||||
|
||||
[Mapping("sharedfeat", "shared_feat", "sharedfeature", "shared_feature")]
|
||||
SharedFeat,
|
||||
|
||||
[Mapping("slot")]
|
||||
Slot,
|
||||
|
||||
[Mapping("slotoption", "slot_option")]
|
||||
SlotOption,
|
||||
|
||||
[Mapping("softwarelist", "software_list")]
|
||||
SoftwareList,
|
||||
|
||||
[Mapping("sound")]
|
||||
Sound,
|
||||
|
||||
[Mapping("source_details", "sourcedetails")]
|
||||
SourceDetails,
|
||||
|
||||
[Mapping("blank")]
|
||||
Blank = 99, // This is not a real type, only used internally
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the loadflag value
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum LoadFlag
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("load16_byte")]
|
||||
Load16Byte = 1 << 0,
|
||||
|
||||
[Mapping("load16_word")]
|
||||
Load16Word = 1 << 1,
|
||||
|
||||
[Mapping("load16_word_swap")]
|
||||
Load16WordSwap = 1 << 2,
|
||||
|
||||
[Mapping("load32_byte")]
|
||||
Load32Byte = 1 << 3,
|
||||
|
||||
[Mapping("load32_word")]
|
||||
Load32Word = 1 << 4,
|
||||
|
||||
[Mapping("load32_word_swap")]
|
||||
Load32WordSwap = 1 << 5,
|
||||
|
||||
[Mapping("load32_dword")]
|
||||
Load32DWord = 1 << 6,
|
||||
|
||||
[Mapping("load64_word")]
|
||||
Load64Word = 1 << 7,
|
||||
|
||||
[Mapping("load64_word_swap")]
|
||||
Load64WordSwap = 1 << 8,
|
||||
|
||||
[Mapping("reload")]
|
||||
Reload = 1 << 9,
|
||||
|
||||
[Mapping("fill")]
|
||||
Fill = 1 << 10,
|
||||
|
||||
[Mapping("continue")]
|
||||
Continue = 1 << 11,
|
||||
|
||||
[Mapping("reload_plain")]
|
||||
ReloadPlain = 1 << 12,
|
||||
|
||||
[Mapping("ignore")]
|
||||
Ignore = 1 << 13,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine what type of machine it is
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum MachineType
|
||||
{
|
||||
[Mapping("none")]
|
||||
None = 0,
|
||||
|
||||
[Mapping("bios")]
|
||||
Bios = 1 << 0,
|
||||
|
||||
[Mapping("device", "dev")]
|
||||
Device = 1 << 1,
|
||||
|
||||
[Mapping("mechanical", "mech")]
|
||||
Mechanical = 1 << 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine which OpenMSX subtype an item is
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum OpenMSXSubType
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("rom")]
|
||||
Rom = 1 << 0,
|
||||
|
||||
[Mapping("megarom")]
|
||||
MegaRom = 1 << 1,
|
||||
|
||||
[Mapping("sccpluscart")]
|
||||
SCCPlusCart = 1 << 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine relation of value to condition
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum Relation
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("eq")]
|
||||
Equal = 1 << 0,
|
||||
|
||||
[Mapping("ne")]
|
||||
NotEqual = 1 << 1,
|
||||
|
||||
[Mapping("gt")]
|
||||
GreaterThan = 1 << 2,
|
||||
|
||||
[Mapping("le")]
|
||||
LessThanOrEqual = 1 << 3,
|
||||
|
||||
[Mapping("lt")]
|
||||
LessThan = 1 << 4,
|
||||
|
||||
[Mapping("ge")]
|
||||
GreaterThanOrEqual = 1 << 5,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine machine runnable status
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum Runnable
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("no")]
|
||||
No = 1 << 0,
|
||||
|
||||
[Mapping("partial")]
|
||||
Partial = 1 << 1,
|
||||
|
||||
[Mapping("yes")]
|
||||
Yes = 1 << 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine software list status
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum SoftwareListStatus
|
||||
{
|
||||
[Mapping("none")]
|
||||
None = 0,
|
||||
|
||||
[Mapping("original")]
|
||||
Original = 1 << 0,
|
||||
|
||||
[Mapping("compatible")]
|
||||
Compatible = 1 << 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine machine support status
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum Supported
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("no", "unsupported")]
|
||||
No = 1 << 0,
|
||||
|
||||
[Mapping("partial")]
|
||||
Partial = 1 << 1,
|
||||
|
||||
[Mapping("yes", "supported")]
|
||||
Yes = 1 << 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine driver support statuses
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum SupportStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a fake flag that is used for filter only
|
||||
/// </summary>
|
||||
NULL = 0,
|
||||
|
||||
[Mapping("good")]
|
||||
Good = 1 << 0,
|
||||
|
||||
[Mapping("imperfect")]
|
||||
Imperfect = 1 << 1,
|
||||
|
||||
[Mapping("preliminary")]
|
||||
Preliminary = 1 << 2,
|
||||
}
|
||||
}
|
||||
788
SabreTools.Metadata.DatItems/Extensions.cs
Normal file
788
SabreTools.Metadata.DatItems/Extensions.cs
Normal file
@@ -0,0 +1,788 @@
|
||||
using System.Collections.Generic;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
#region Private Maps
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for ChipType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, ChipType> _toChipTypeMap = Converters.GenerateToEnum<ChipType>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for ChipType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<ChipType, string> _fromChipTypeMap = Converters.GenerateToString<ChipType>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for ControlType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, ControlType> _toControlTypeMap = Converters.GenerateToEnum<ControlType>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for ControlType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<ControlType, string> _fromControlTypeMap = Converters.GenerateToString<ControlType>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for DeviceType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, DeviceType> _toDeviceTypeMap = Converters.GenerateToEnum<DeviceType>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for DeviceType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<DeviceType, string> _fromDeviceTypeMap = Converters.GenerateToString<DeviceType>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for DisplayType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, DisplayType> _toDisplayTypeMap = Converters.GenerateToEnum<DisplayType>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for DisplayType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<DisplayType, string> _fromDisplayTypeMap = Converters.GenerateToString<DisplayType>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for Endianness
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, Endianness> _toEndiannessMap = Converters.GenerateToEnum<Endianness>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for Endianness
|
||||
/// </summary>
|
||||
private static readonly Dictionary<Endianness, string> _fromEndiannessMap = Converters.GenerateToString<Endianness>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for FeatureStatus
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, FeatureStatus> _toFeatureStatusMap = Converters.GenerateToEnum<FeatureStatus>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for FeatureStatus
|
||||
/// </summary>
|
||||
private static readonly Dictionary<FeatureStatus, string> _fromFeatureStatusMap = Converters.GenerateToString<FeatureStatus>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for FeatureType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, FeatureType> _toFeatureTypeMap = Converters.GenerateToEnum<FeatureType>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for FeatureType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<FeatureType, string> _fromFeatureTypeMap = Converters.GenerateToString<FeatureType>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for ItemStatus
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, ItemStatus> _toItemStatusMap = Converters.GenerateToEnum<ItemStatus>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for ItemStatus
|
||||
/// </summary>
|
||||
private static readonly Dictionary<ItemStatus, string> _fromItemStatusMap = Converters.GenerateToString<ItemStatus>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for ItemType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, ItemType> _toItemTypeMap = Converters.GenerateToEnum<ItemType>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for ItemType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<ItemType, string> _fromItemTypeMap = Converters.GenerateToString<ItemType>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for LoadFlag
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, LoadFlag> _toLoadFlagMap = Converters.GenerateToEnum<LoadFlag>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for LoadFlag
|
||||
/// </summary>
|
||||
private static readonly Dictionary<LoadFlag, string> _fromLoadFlagMap = Converters.GenerateToString<LoadFlag>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for MachineType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, MachineType> _toMachineTypeMap = Converters.GenerateToEnum<MachineType>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for OpenMSXSubType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, OpenMSXSubType> _toOpenMSXSubTypeMap = Converters.GenerateToEnum<OpenMSXSubType>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for OpenMSXSubType
|
||||
/// </summary>
|
||||
private static readonly Dictionary<OpenMSXSubType, string> _fromOpenMSXSubTypeMap = Converters.GenerateToString<OpenMSXSubType>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for Relation
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, Relation> _toRelationMap = Converters.GenerateToEnum<Relation>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for Relation
|
||||
/// </summary>
|
||||
private static readonly Dictionary<Relation, string> _fromRelationMap = Converters.GenerateToString<Relation>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for Runnable
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, Runnable> _toRunnableMap = Converters.GenerateToEnum<Runnable>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for Runnable
|
||||
/// </summary>
|
||||
private static readonly Dictionary<Runnable, string> _fromRunnableMap = Converters.GenerateToString<Runnable>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for SoftwareListStatus
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, SoftwareListStatus> _toSoftwareListStatusMap = Converters.GenerateToEnum<SoftwareListStatus>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for SoftwareListStatus
|
||||
/// </summary>
|
||||
private static readonly Dictionary<SoftwareListStatus, string> _fromSoftwareListStatusMap = Converters.GenerateToString<SoftwareListStatus>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for Supported
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, Supported> _toSupportedMap = Converters.GenerateToEnum<Supported>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for Supported
|
||||
/// </summary>
|
||||
private static readonly Dictionary<Supported, string> _fromSupportedMap = Converters.GenerateToString<Supported>(useSecond: false);
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for Supported (secondary)
|
||||
/// </summary>
|
||||
private static readonly Dictionary<Supported, string> _fromSupportedSecondaryMap = Converters.GenerateToString<Supported>(useSecond: true);
|
||||
|
||||
/// <summary>
|
||||
/// Set of enum to string mappings for SupportStatus
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, SupportStatus> _toSupportStatusMap = Converters.GenerateToEnum<SupportStatus>();
|
||||
|
||||
/// <summary>
|
||||
/// Set of string to enum mappings for SupportStatus
|
||||
/// </summary>
|
||||
private static readonly Dictionary<SupportStatus, string> _fromSupportStatusMap = Converters.GenerateToString<SupportStatus>(useSecond: false);
|
||||
|
||||
#endregion
|
||||
|
||||
#region String to Enum
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static ChipType AsChipType(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toChipTypeMap.ContainsKey(value))
|
||||
return _toChipTypeMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static ControlType AsControlType(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toControlTypeMap.ContainsKey(value))
|
||||
return _toControlTypeMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static DeviceType AsDeviceType(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toDeviceTypeMap.ContainsKey(value))
|
||||
return _toDeviceTypeMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static DisplayType AsDisplayType(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toDisplayTypeMap.ContainsKey(value))
|
||||
return _toDisplayTypeMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static Endianness AsEndianness(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toEndiannessMap.ContainsKey(value))
|
||||
return _toEndiannessMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static FeatureStatus AsFeatureStatus(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toFeatureStatusMap.ContainsKey(value))
|
||||
return _toFeatureStatusMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static FeatureType AsFeatureType(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toFeatureTypeMap.ContainsKey(value))
|
||||
return _toFeatureTypeMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static ItemStatus AsItemStatus(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toItemStatusMap.ContainsKey(value))
|
||||
return _toItemStatusMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static ItemType AsItemType(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toItemTypeMap.ContainsKey(value))
|
||||
return _toItemTypeMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static LoadFlag AsLoadFlag(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toLoadFlagMap.ContainsKey(value))
|
||||
return _toLoadFlagMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static MachineType AsMachineType(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toMachineTypeMap.ContainsKey(value))
|
||||
return _toMachineTypeMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static OpenMSXSubType AsOpenMSXSubType(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toOpenMSXSubTypeMap.ContainsKey(value))
|
||||
return _toOpenMSXSubTypeMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static Relation AsRelation(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toRelationMap.ContainsKey(value))
|
||||
return _toRelationMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static Runnable AsRunnable(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toRunnableMap.ContainsKey(value))
|
||||
return _toRunnableMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static SoftwareListStatus AsSoftwareListStatus(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toSoftwareListStatusMap.ContainsKey(value))
|
||||
return _toSoftwareListStatusMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static Supported AsSupported(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toSupportedMap.ContainsKey(value))
|
||||
return _toSupportedMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enum value for an input string, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">String value to parse/param>
|
||||
/// <returns>Enum value representing the input, default on error</returns>
|
||||
public static SupportStatus AsSupportStatus(this string? value)
|
||||
{
|
||||
// Normalize the input value
|
||||
value = value?.ToLowerInvariant();
|
||||
if (value is null)
|
||||
return default;
|
||||
|
||||
// Try to get the value from the mappings
|
||||
if (_toSupportStatusMap.ContainsKey(value))
|
||||
return _toSupportStatusMap[value];
|
||||
|
||||
// Otherwise, return the default value for the enum
|
||||
return default;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Enum to String
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this ChipType value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromChipTypeMap.ContainsKey(value))
|
||||
return _fromChipTypeMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this ControlType value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromControlTypeMap.ContainsKey(value))
|
||||
return _fromControlTypeMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this DeviceType value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromDeviceTypeMap.ContainsKey(value))
|
||||
return _fromDeviceTypeMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this DisplayType value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromDisplayTypeMap.ContainsKey(value))
|
||||
return _fromDisplayTypeMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this Endianness value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromEndiannessMap.ContainsKey(value))
|
||||
return _fromEndiannessMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this FeatureStatus value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromFeatureStatusMap.ContainsKey(value))
|
||||
return _fromFeatureStatusMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this FeatureType value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromFeatureTypeMap.ContainsKey(value))
|
||||
return _fromFeatureTypeMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this ItemStatus value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromItemStatusMap.ContainsKey(value))
|
||||
return _fromItemStatusMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this ItemType value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromItemTypeMap.ContainsKey(value))
|
||||
return _fromItemTypeMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this LoadFlag value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromLoadFlagMap.ContainsKey(value))
|
||||
return _fromLoadFlagMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this OpenMSXSubType value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromOpenMSXSubTypeMap.ContainsKey(value))
|
||||
return _fromOpenMSXSubTypeMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this Relation value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromRelationMap.ContainsKey(value))
|
||||
return _fromRelationMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this Runnable value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromRunnableMap.ContainsKey(value))
|
||||
return _fromRunnableMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this SoftwareListStatus value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromSoftwareListStatusMap.ContainsKey(value))
|
||||
return _fromSoftwareListStatusMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this Supported value, bool useSecond = false)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (!useSecond && _fromSupportedMap.ContainsKey(value))
|
||||
return _fromSupportedMap[value];
|
||||
else if (useSecond && _fromSupportedSecondaryMap.ContainsKey(value))
|
||||
return _fromSupportedSecondaryMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an input enum, if possible
|
||||
/// </summary>
|
||||
/// <param name="value">Enum value to parse/param>
|
||||
/// <param name="useSecond">True to use the second mapping option, if it exists</param>
|
||||
/// <returns>String value representing the input, default on error</returns>
|
||||
public static string? AsStringValue(this SupportStatus value)
|
||||
{
|
||||
// Try to get the value from the mappings
|
||||
if (_fromSupportStatusMap.ContainsKey(value))
|
||||
return _fromSupportStatusMap[value];
|
||||
|
||||
// Otherwise, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
70
SabreTools.Metadata.DatItems/Formats/Adjuster.cs
Normal file
70
SabreTools.Metadata.DatItems/Formats/Adjuster.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents which Adjuster(s) is associated with a set
|
||||
/// </summary>
|
||||
[JsonObject("adjuster"), XmlRoot("adjuster")]
|
||||
public sealed class Adjuster : DatItem<Data.Models.Metadata.Adjuster>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Adjuster;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ConditionsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var conditions = GetFieldValue<Condition[]?>(Data.Models.Metadata.Adjuster.ConditionKey);
|
||||
return conditions is not null && conditions.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Adjuster() : base() { }
|
||||
|
||||
public Adjuster(Data.Models.Metadata.Adjuster item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Adjuster.DefaultKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Adjuster.DefaultKey, GetBoolFieldValue(Data.Models.Metadata.Adjuster.DefaultKey).FromYesNo());
|
||||
|
||||
// Handle subitems
|
||||
var condition = item.Read<Data.Models.Metadata.Condition>(Data.Models.Metadata.Adjuster.ConditionKey);
|
||||
if (condition is not null)
|
||||
SetFieldValue(Data.Models.Metadata.Adjuster.ConditionKey, new Condition(condition));
|
||||
}
|
||||
|
||||
public Adjuster(Data.Models.Metadata.Adjuster item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Data.Models.Metadata.Adjuster GetInternalClone()
|
||||
{
|
||||
var adjusterItem = base.GetInternalClone();
|
||||
|
||||
var condition = GetFieldValue<Condition?>(Data.Models.Metadata.Adjuster.ConditionKey);
|
||||
if (condition is not null)
|
||||
adjusterItem[Data.Models.Metadata.Adjuster.ConditionKey] = condition.GetInternalClone();
|
||||
|
||||
return adjusterItem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
33
SabreTools.Metadata.DatItems/Formats/Analog.cs
Normal file
33
SabreTools.Metadata.DatItems/Formats/Analog.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single analog item
|
||||
/// </summary>
|
||||
[JsonObject("analog"), XmlRoot("analog")]
|
||||
public sealed class Analog : DatItem<Data.Models.Metadata.Analog>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Analog;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Analog() : base() { }
|
||||
|
||||
public Analog(Data.Models.Metadata.Analog item) : base(item) { }
|
||||
|
||||
public Analog(Data.Models.Metadata.Analog item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
100
SabreTools.Metadata.DatItems/Formats/Archive.cs
Normal file
100
SabreTools.Metadata.DatItems/Formats/Archive.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents generic archive files to be included in a set
|
||||
/// </summary>
|
||||
[JsonObject("archive"), XmlRoot("archive")]
|
||||
public sealed class Archive : DatItem<Data.Models.Metadata.Archive>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Archive;
|
||||
|
||||
// TODO: None of the following are used or checked
|
||||
|
||||
/// <summary>
|
||||
/// Archive ID number
|
||||
/// </summary>
|
||||
/// <remarks>TODO: No-Intro database export only</remarks>
|
||||
[JsonProperty("number"), XmlElement("number")]
|
||||
public string? Number { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Clone value
|
||||
/// </summary>
|
||||
/// <remarks>TODO: No-Intro database export only</remarks>
|
||||
[JsonProperty("clone"), XmlElement("clone")]
|
||||
public string? CloneValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Regional parent value
|
||||
/// </summary>
|
||||
/// <remarks>TODO: No-Intro database export only</remarks>
|
||||
[JsonProperty("regparent"), XmlElement("regparent")]
|
||||
public string? RegParent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Region value
|
||||
/// </summary>
|
||||
/// <remarks>TODO: No-Intro database export only</remarks>
|
||||
[JsonProperty("region"), XmlElement("region")]
|
||||
public string? Region { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Languages value
|
||||
/// </summary>
|
||||
/// <remarks>TODO: No-Intro database export only</remarks>
|
||||
[JsonProperty("languages"), XmlElement("languages")]
|
||||
public string? Languages { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Development status value
|
||||
/// </summary>
|
||||
/// <remarks>TODO: No-Intro database export only</remarks>
|
||||
[JsonProperty("devstatus"), XmlElement("devstatus")]
|
||||
public string? DevStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Physical value
|
||||
/// </summary>
|
||||
/// <remarks>TODO: No-Intro database export only</remarks>
|
||||
/// <remarks>TODO: Is this numeric or a flag?</remarks>
|
||||
[JsonProperty("physical"), XmlElement("physical")]
|
||||
public string? Physical { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Complete value
|
||||
/// </summary>
|
||||
/// <remarks>TODO: No-Intro database export only</remarks>
|
||||
/// <remarks>TODO: Is this numeric or a flag?</remarks>
|
||||
[JsonProperty("complete"), XmlElement("complete")]
|
||||
public string? Complete { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Categories value
|
||||
/// </summary>
|
||||
/// <remarks>TODO: No-Intro database export only</remarks>
|
||||
[JsonProperty("categories"), XmlElement("categories")]
|
||||
public string? Categories { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Archive() : base() { }
|
||||
|
||||
public Archive(Data.Models.Metadata.Archive item) : base(item) { }
|
||||
|
||||
public Archive(Data.Models.Metadata.Archive item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
39
SabreTools.Metadata.DatItems/Formats/BiosSet.cs
Normal file
39
SabreTools.Metadata.DatItems/Formats/BiosSet.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents which BIOS(es) is associated with a set
|
||||
/// </summary>
|
||||
[JsonObject("biosset"), XmlRoot("biosset")]
|
||||
public sealed class BiosSet : DatItem<Data.Models.Metadata.BiosSet>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.BiosSet;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public BiosSet() : base() { }
|
||||
|
||||
public BiosSet(Data.Models.Metadata.BiosSet item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.BiosSet.DefaultKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.BiosSet.DefaultKey, GetBoolFieldValue(Data.Models.Metadata.BiosSet.DefaultKey).FromYesNo());
|
||||
}
|
||||
|
||||
public BiosSet(Data.Models.Metadata.BiosSet item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
95
SabreTools.Metadata.DatItems/Formats/Blank.cs
Normal file
95
SabreTools.Metadata.DatItems/Formats/Blank.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a blank set from an input DAT
|
||||
/// </summary>
|
||||
[JsonObject("blank"), XmlRoot("blank")]
|
||||
public sealed class Blank : DatItem
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Blank;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Create a default, empty Blank object
|
||||
/// </summary>
|
||||
public Blank()
|
||||
{
|
||||
SetFieldValue(Data.Models.Metadata.DatItem.TypeKey, ItemType);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override object Clone()
|
||||
{
|
||||
var blank = new Blank();
|
||||
blank.SetFieldValue(MachineKey, GetMachine());
|
||||
blank.SetFieldValue(RemoveKey, GetBoolFieldValue(RemoveKey));
|
||||
blank.SetFieldValue<Source?>(SourceKey, GetFieldValue<Source?>(SourceKey));
|
||||
blank.SetFieldValue<string?>(Data.Models.Metadata.DatItem.TypeKey, GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey).AsItemType().AsStringValue());
|
||||
|
||||
return blank;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Comparision Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(ModelBackedItem? other)
|
||||
{
|
||||
// If other is null
|
||||
if (other is null)
|
||||
return false;
|
||||
|
||||
// If the type is mismatched
|
||||
if (other is not DatItem otherItem)
|
||||
return false;
|
||||
|
||||
// Compare internal models
|
||||
return Equals(otherItem);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(ModelBackedItem<Data.Models.Metadata.DatItem>? other)
|
||||
{
|
||||
// If other is null
|
||||
if (other is null)
|
||||
return false;
|
||||
|
||||
// If the type is mismatched
|
||||
if (other is not DatItem otherItem)
|
||||
return false;
|
||||
|
||||
// Compare internal models
|
||||
return Equals(otherItem);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(DatItem? other)
|
||||
{
|
||||
// If we don't have a blank, return false
|
||||
if (GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey) != other?.GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey))
|
||||
return false;
|
||||
|
||||
// Otherwise, treat it as a Blank
|
||||
Blank? newOther = other as Blank;
|
||||
|
||||
// If the machine information matches
|
||||
return GetMachine() == newOther!.GetMachine();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
41
SabreTools.Metadata.DatItems/Formats/Chip.cs
Normal file
41
SabreTools.Metadata.DatItems/Formats/Chip.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents which Chip(s) is associated with a set
|
||||
/// </summary>
|
||||
[JsonObject("chip"), XmlRoot("chip")]
|
||||
public sealed class Chip : DatItem<Data.Models.Metadata.Chip>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Chip;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Chip() : base() { }
|
||||
|
||||
public Chip(Data.Models.Metadata.Chip item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Chip.SoundOnlyKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Chip.SoundOnlyKey, GetBoolFieldValue(Data.Models.Metadata.Chip.SoundOnlyKey).FromYesNo());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Chip.ChipTypeKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Chip.ChipTypeKey, GetStringFieldValue(Data.Models.Metadata.Chip.ChipTypeKey).AsChipType().AsStringValue());
|
||||
}
|
||||
|
||||
public Chip(Data.Models.Metadata.Chip item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
38
SabreTools.Metadata.DatItems/Formats/Condition.cs
Normal file
38
SabreTools.Metadata.DatItems/Formats/Condition.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a condition on a machine or other item
|
||||
/// </summary>
|
||||
[JsonObject("condition"), XmlRoot("condition")]
|
||||
public sealed class Condition : DatItem<Data.Models.Metadata.Condition>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Condition;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Condition() : base() { }
|
||||
|
||||
public Condition(Data.Models.Metadata.Condition item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Condition.RelationKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Condition.RelationKey, GetStringFieldValue(Data.Models.Metadata.Condition.RelationKey).AsRelation().AsStringValue());
|
||||
}
|
||||
|
||||
public Condition(Data.Models.Metadata.Condition item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
39
SabreTools.Metadata.DatItems/Formats/ConfLocation.cs
Normal file
39
SabreTools.Metadata.DatItems/Formats/ConfLocation.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents one conflocation
|
||||
/// </summary>
|
||||
[JsonObject("conflocation"), XmlRoot("conflocation")]
|
||||
public sealed class ConfLocation : DatItem<Data.Models.Metadata.ConfLocation>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.ConfLocation;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ConfLocation() : base() { }
|
||||
|
||||
public ConfLocation(Data.Models.Metadata.ConfLocation item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.ConfLocation.InvertedKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.ConfLocation.InvertedKey, GetBoolFieldValue(Data.Models.Metadata.ConfLocation.InvertedKey).FromYesNo());
|
||||
}
|
||||
|
||||
public ConfLocation(Data.Models.Metadata.ConfLocation item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
71
SabreTools.Metadata.DatItems/Formats/ConfSetting.cs
Normal file
71
SabreTools.Metadata.DatItems/Formats/ConfSetting.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents one ListXML confsetting
|
||||
/// </summary>
|
||||
[JsonObject("confsetting"), XmlRoot("confsetting")]
|
||||
public sealed class ConfSetting : DatItem<Data.Models.Metadata.ConfSetting>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.ConfSetting;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ConditionsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var conditions = GetFieldValue<Condition[]?>(Data.Models.Metadata.ConfSetting.ConditionKey);
|
||||
return conditions is not null && conditions.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ConfSetting() : base() { }
|
||||
|
||||
public ConfSetting(Data.Models.Metadata.ConfSetting item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.ConfSetting.DefaultKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.ConfSetting.DefaultKey, GetBoolFieldValue(Data.Models.Metadata.ConfSetting.DefaultKey).FromYesNo());
|
||||
|
||||
// Handle subitems
|
||||
var condition = GetFieldValue<Data.Models.Metadata.Condition>(Data.Models.Metadata.ConfSetting.ConditionKey);
|
||||
if (condition is not null)
|
||||
SetFieldValue<Condition?>(Data.Models.Metadata.ConfSetting.ConditionKey, new Condition(condition));
|
||||
}
|
||||
|
||||
public ConfSetting(Data.Models.Metadata.ConfSetting item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Data.Models.Metadata.ConfSetting GetInternalClone()
|
||||
{
|
||||
var confSettingItem = base.GetInternalClone();
|
||||
|
||||
// Handle subitems
|
||||
var condition = GetFieldValue<Condition>(Data.Models.Metadata.ConfSetting.ConditionKey);
|
||||
if (condition is not null)
|
||||
confSettingItem[Data.Models.Metadata.ConfSetting.ConditionKey] = condition.GetInternalClone();
|
||||
|
||||
return confSettingItem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
115
SabreTools.Metadata.DatItems/Formats/Configuration.cs
Normal file
115
SabreTools.Metadata.DatItems/Formats/Configuration.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Data.Extensions;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents which Configuration(s) is associated with a set
|
||||
/// </summary>
|
||||
[JsonObject("configuration"), XmlRoot("configuration")]
|
||||
public sealed class Configuration : DatItem<Data.Models.Metadata.Configuration>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Configuration;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ConditionsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var conditions = GetFieldValue<Condition[]?>(Data.Models.Metadata.Configuration.ConditionKey);
|
||||
return conditions is not null && conditions.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool LocationsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var locations = GetFieldValue<ConfLocation[]?>(Data.Models.Metadata.Configuration.ConfLocationKey);
|
||||
return locations is not null && locations.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool SettingsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var settings = GetFieldValue<ConfSetting[]?>(Data.Models.Metadata.Configuration.ConfSettingKey);
|
||||
return settings is not null && settings.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Configuration() : base() { }
|
||||
|
||||
public Configuration(Data.Models.Metadata.Configuration item) : base(item)
|
||||
{
|
||||
// Handle subitems
|
||||
var condition = item.Read<Data.Models.Metadata.Condition>(Data.Models.Metadata.Configuration.ConditionKey);
|
||||
if (condition is not null)
|
||||
SetFieldValue<Condition?>(Data.Models.Metadata.Configuration.ConditionKey, new Condition(condition));
|
||||
|
||||
var confLocations = item.ReadItemArray<Data.Models.Metadata.ConfLocation>(Data.Models.Metadata.Configuration.ConfLocationKey);
|
||||
if (confLocations is not null)
|
||||
{
|
||||
ConfLocation[] confLocationItems = Array.ConvertAll(confLocations, confLocation => new ConfLocation(confLocation));
|
||||
SetFieldValue<ConfLocation[]?>(Data.Models.Metadata.Configuration.ConfLocationKey, confLocationItems);
|
||||
}
|
||||
|
||||
var confSettings = item.ReadItemArray<Data.Models.Metadata.ConfSetting>(Data.Models.Metadata.Configuration.ConfSettingKey);
|
||||
if (confSettings is not null)
|
||||
{
|
||||
ConfSetting[] confSettingItems = Array.ConvertAll(confSettings, confSetting => new ConfSetting(confSetting));
|
||||
SetFieldValue<ConfSetting[]?>(Data.Models.Metadata.Configuration.ConfSettingKey, confSettingItems);
|
||||
}
|
||||
}
|
||||
|
||||
public Configuration(Data.Models.Metadata.Configuration item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Data.Models.Metadata.Configuration GetInternalClone()
|
||||
{
|
||||
var configurationItem = base.GetInternalClone();
|
||||
|
||||
var condition = GetFieldValue<Condition?>(Data.Models.Metadata.Configuration.ConditionKey);
|
||||
if (condition is not null)
|
||||
configurationItem[Data.Models.Metadata.Configuration.ConditionKey] = condition.GetInternalClone();
|
||||
|
||||
var confLocations = GetFieldValue<ConfLocation[]?>(Data.Models.Metadata.Configuration.ConfLocationKey);
|
||||
if (confLocations is not null)
|
||||
{
|
||||
Data.Models.Metadata.ConfLocation[] confLocationItems = Array.ConvertAll(confLocations, confLocation => confLocation.GetInternalClone());
|
||||
configurationItem[Data.Models.Metadata.Configuration.ConfLocationKey] = confLocationItems;
|
||||
}
|
||||
|
||||
var confSettings = GetFieldValue<ConfSetting[]?>(Data.Models.Metadata.Configuration.ConfSettingKey);
|
||||
if (confSettings is not null)
|
||||
{
|
||||
Data.Models.Metadata.ConfSetting[] confSettingItems = Array.ConvertAll(confSettings, confSetting => confSetting.GetInternalClone());
|
||||
configurationItem[Data.Models.Metadata.Configuration.ConfSettingKey] = confSettingItems;
|
||||
}
|
||||
|
||||
return configurationItem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
55
SabreTools.Metadata.DatItems/Formats/Control.cs
Normal file
55
SabreTools.Metadata.DatItems/Formats/Control.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents control for an input
|
||||
/// </summary>
|
||||
[JsonObject("control"), XmlRoot("control")]
|
||||
public sealed class Control : DatItem<Data.Models.Metadata.Control>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Control;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Control() : base() { }
|
||||
|
||||
public Control(Data.Models.Metadata.Control item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Control.ButtonsKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Control.ButtonsKey, GetInt64FieldValue(Data.Models.Metadata.Control.ButtonsKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Control.KeyDeltaKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Control.KeyDeltaKey, GetInt64FieldValue(Data.Models.Metadata.Control.KeyDeltaKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Control.MaximumKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Control.MaximumKey, GetInt64FieldValue(Data.Models.Metadata.Control.MaximumKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Control.MinimumKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Control.MinimumKey, GetInt64FieldValue(Data.Models.Metadata.Control.MinimumKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Control.PlayerKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Control.PlayerKey, GetInt64FieldValue(Data.Models.Metadata.Control.PlayerKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Control.ReqButtonsKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Control.ReqButtonsKey, GetInt64FieldValue(Data.Models.Metadata.Control.ReqButtonsKey).ToString());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Control.ReverseKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Control.ReverseKey, GetBoolFieldValue(Data.Models.Metadata.Control.ReverseKey).FromYesNo());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Control.SensitivityKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Control.SensitivityKey, GetInt64FieldValue(Data.Models.Metadata.Control.SensitivityKey).ToString());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Control.ControlTypeKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Control.ControlTypeKey, GetStringFieldValue(Data.Models.Metadata.Control.ControlTypeKey).AsControlType().AsStringValue());
|
||||
}
|
||||
|
||||
public Control(Data.Models.Metadata.Control item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
43
SabreTools.Metadata.DatItems/Formats/DataArea.cs
Normal file
43
SabreTools.Metadata.DatItems/Formats/DataArea.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// SoftwareList dataarea information
|
||||
/// </summary>
|
||||
/// <remarks>One DataArea can contain multiple Rom items</remarks>
|
||||
[JsonObject("dataarea"), XmlRoot("dataarea")]
|
||||
public sealed class DataArea : DatItem<Data.Models.Metadata.DataArea>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.DataArea;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public DataArea() : base() { }
|
||||
|
||||
public DataArea(Data.Models.Metadata.DataArea item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetStringFieldValue(Data.Models.Metadata.DataArea.EndiannessKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.DataArea.EndiannessKey, GetStringFieldValue(Data.Models.Metadata.DataArea.EndiannessKey).AsEndianness().AsStringValue());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.DataArea.SizeKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.DataArea.SizeKey, GetInt64FieldValue(Data.Models.Metadata.DataArea.SizeKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.DataArea.WidthKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.DataArea.WidthKey, GetInt64FieldValue(Data.Models.Metadata.DataArea.WidthKey).ToString());
|
||||
}
|
||||
|
||||
public DataArea(Data.Models.Metadata.DataArea item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
98
SabreTools.Metadata.DatItems/Formats/Device.cs
Normal file
98
SabreTools.Metadata.DatItems/Formats/Device.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Data.Extensions;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single device on the machine
|
||||
/// </summary>
|
||||
[JsonObject("device"), XmlRoot("device")]
|
||||
public sealed class Device : DatItem<Data.Models.Metadata.Device>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Device;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool InstancesSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var instances = GetFieldValue<Instance[]?>(Data.Models.Metadata.Device.InstanceKey);
|
||||
return instances is not null && instances.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ExtensionsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var extensions = GetFieldValue<Extension[]?>(Data.Models.Metadata.Device.ExtensionKey);
|
||||
return extensions is not null && extensions.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Device() : base() { }
|
||||
|
||||
public Device(Data.Models.Metadata.Device item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Device.MandatoryKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Device.MandatoryKey, GetBoolFieldValue(Data.Models.Metadata.Device.MandatoryKey).FromYesNo());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Device.DeviceTypeKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Device.DeviceTypeKey, GetStringFieldValue(Data.Models.Metadata.Device.DeviceTypeKey).AsDeviceType().AsStringValue());
|
||||
|
||||
// Handle subitems
|
||||
var instance = item.Read<Data.Models.Metadata.Instance>(Data.Models.Metadata.Device.InstanceKey);
|
||||
if (instance is not null)
|
||||
SetFieldValue<Instance?>(Data.Models.Metadata.Device.InstanceKey, new Instance(instance));
|
||||
|
||||
var extensions = item.ReadItemArray<Data.Models.Metadata.Extension>(Data.Models.Metadata.Device.ExtensionKey);
|
||||
if (extensions is not null)
|
||||
{
|
||||
Extension[] extensionItems = Array.ConvertAll(extensions, extension => new Extension(extension));
|
||||
SetFieldValue<Extension[]?>(Data.Models.Metadata.Device.ExtensionKey, extensionItems);
|
||||
}
|
||||
}
|
||||
|
||||
public Device(Data.Models.Metadata.Device item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Data.Models.Metadata.Device GetInternalClone()
|
||||
{
|
||||
var deviceItem = base.GetInternalClone();
|
||||
|
||||
var instance = GetFieldValue<Instance?>(Data.Models.Metadata.Device.InstanceKey);
|
||||
if (instance is not null)
|
||||
deviceItem[Data.Models.Metadata.Device.InstanceKey] = instance.GetInternalClone();
|
||||
|
||||
var extensions = GetFieldValue<Extension[]?>(Data.Models.Metadata.Device.ExtensionKey);
|
||||
if (extensions is not null)
|
||||
{
|
||||
Data.Models.Metadata.Extension[] extensionItems = Array.ConvertAll(extensions, extension => extension.GetInternalClone());
|
||||
deviceItem[Data.Models.Metadata.Device.ExtensionKey] = extensionItems;
|
||||
}
|
||||
|
||||
return deviceItem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
33
SabreTools.Metadata.DatItems/Formats/DeviceRef.cs
Normal file
33
SabreTools.Metadata.DatItems/Formats/DeviceRef.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents which Device Reference(s) is associated with a set
|
||||
/// </summary>
|
||||
[JsonObject("device_ref"), XmlRoot("device_ref")]
|
||||
public sealed class DeviceRef : DatItem<Data.Models.Metadata.DeviceRef>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.DeviceRef;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public DeviceRef() : base() { }
|
||||
|
||||
public DeviceRef(Data.Models.Metadata.DeviceRef item) : base(item) { }
|
||||
|
||||
public DeviceRef(Data.Models.Metadata.DeviceRef item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
39
SabreTools.Metadata.DatItems/Formats/DipLocation.cs
Normal file
39
SabreTools.Metadata.DatItems/Formats/DipLocation.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents one diplocation
|
||||
/// </summary>
|
||||
[JsonObject("diplocation"), XmlRoot("diplocation")]
|
||||
public sealed class DipLocation : DatItem<Data.Models.Metadata.DipLocation>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.DipLocation;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public DipLocation() : base() { }
|
||||
|
||||
public DipLocation(Data.Models.Metadata.DipLocation item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.DipLocation.InvertedKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.DipLocation.InvertedKey, GetBoolFieldValue(Data.Models.Metadata.DipLocation.InvertedKey).FromYesNo());
|
||||
}
|
||||
|
||||
public DipLocation(Data.Models.Metadata.DipLocation item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
141
SabreTools.Metadata.DatItems/Formats/DipSwitch.cs
Normal file
141
SabreTools.Metadata.DatItems/Formats/DipSwitch.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Data.Extensions;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents which DIP Switch(es) is associated with a set
|
||||
/// </summary>
|
||||
[JsonObject("dipswitch"), XmlRoot("dipswitch")]
|
||||
public sealed class DipSwitch : DatItem<Data.Models.Metadata.DipSwitch>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
/// <summary>
|
||||
/// Non-standard key for inverted logic
|
||||
/// </summary>
|
||||
public const string PartKey = "PART";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.DipSwitch;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ConditionsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var conditions = GetFieldValue<Condition[]?>(Data.Models.Metadata.DipSwitch.ConditionKey);
|
||||
return conditions is not null && conditions.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool LocationsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var locations = GetFieldValue<DipLocation[]?>(Data.Models.Metadata.DipSwitch.DipLocationKey);
|
||||
return locations is not null && locations.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ValuesSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var values = GetFieldValue<DipValue[]?>(Data.Models.Metadata.DipSwitch.DipValueKey);
|
||||
return values is not null && values.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool PartSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var part = GetFieldValue<Part?>(PartKey);
|
||||
return part is not null
|
||||
&& (!string.IsNullOrEmpty(part.GetName())
|
||||
|| !string.IsNullOrEmpty(part.GetStringFieldValue(Data.Models.Metadata.Part.InterfaceKey)));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public DipSwitch() : base() { }
|
||||
|
||||
public DipSwitch(Data.Models.Metadata.DipSwitch item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.DipSwitch.DefaultKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.DipSwitch.DefaultKey, GetBoolFieldValue(Data.Models.Metadata.DipSwitch.DefaultKey).FromYesNo());
|
||||
|
||||
// Handle subitems
|
||||
var condition = item.Read<Data.Models.Metadata.Condition>(Data.Models.Metadata.DipSwitch.ConditionKey);
|
||||
if (condition is not null)
|
||||
SetFieldValue<Condition?>(Data.Models.Metadata.DipSwitch.ConditionKey, new Condition(condition));
|
||||
|
||||
var dipLocations = item.ReadItemArray<Data.Models.Metadata.DipLocation>(Data.Models.Metadata.DipSwitch.DipLocationKey);
|
||||
if (dipLocations is not null)
|
||||
{
|
||||
DipLocation[] dipLocationItems = Array.ConvertAll(dipLocations, dipLocation => new DipLocation(dipLocation));
|
||||
SetFieldValue<DipLocation[]?>(Data.Models.Metadata.DipSwitch.DipLocationKey, dipLocationItems);
|
||||
}
|
||||
|
||||
var dipValues = item.ReadItemArray<Data.Models.Metadata.DipValue>(Data.Models.Metadata.DipSwitch.DipValueKey);
|
||||
if (dipValues is not null)
|
||||
{
|
||||
DipValue[] dipValueItems = Array.ConvertAll(dipValues, dipValue => new DipValue(dipValue));
|
||||
SetFieldValue<DipValue[]?>(Data.Models.Metadata.DipSwitch.DipValueKey, dipValueItems);
|
||||
}
|
||||
}
|
||||
|
||||
public DipSwitch(Data.Models.Metadata.DipSwitch item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Data.Models.Metadata.DipSwitch GetInternalClone()
|
||||
{
|
||||
var dipSwitchItem = base.GetInternalClone();
|
||||
|
||||
var condition = GetFieldValue<Condition?>(Data.Models.Metadata.DipSwitch.ConditionKey);
|
||||
if (condition is not null)
|
||||
dipSwitchItem[Data.Models.Metadata.DipSwitch.ConditionKey] = condition.GetInternalClone();
|
||||
|
||||
var dipLocations = GetFieldValue<DipLocation[]?>(Data.Models.Metadata.DipSwitch.DipLocationKey);
|
||||
if (dipLocations is not null)
|
||||
{
|
||||
Data.Models.Metadata.DipLocation[] dipLocationItems = Array.ConvertAll(dipLocations, dipLocation => dipLocation.GetInternalClone());
|
||||
dipSwitchItem[Data.Models.Metadata.DipSwitch.DipLocationKey] = dipLocationItems;
|
||||
}
|
||||
|
||||
var dipValues = GetFieldValue<DipValue[]?>(Data.Models.Metadata.DipSwitch.DipValueKey);
|
||||
if (dipValues is not null)
|
||||
{
|
||||
Data.Models.Metadata.DipValue[] dipValueItems = Array.ConvertAll(dipValues, dipValue => dipValue.GetInternalClone());
|
||||
dipSwitchItem[Data.Models.Metadata.DipSwitch.DipValueKey] = dipValueItems;
|
||||
}
|
||||
|
||||
return dipSwitchItem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
71
SabreTools.Metadata.DatItems/Formats/DipValue.cs
Normal file
71
SabreTools.Metadata.DatItems/Formats/DipValue.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents one ListXML dipvalue
|
||||
/// </summary>
|
||||
[JsonObject("dipvalue"), XmlRoot("dipvalue")]
|
||||
public sealed class DipValue : DatItem<Data.Models.Metadata.DipValue>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.DipValue;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ConditionsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var conditions = GetFieldValue<Condition[]?>(Data.Models.Metadata.DipValue.ConditionKey);
|
||||
return conditions is not null && conditions.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public DipValue() : base() { }
|
||||
|
||||
public DipValue(Data.Models.Metadata.DipValue item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.DipValue.DefaultKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.DipValue.DefaultKey, GetBoolFieldValue(Data.Models.Metadata.DipValue.DefaultKey).FromYesNo());
|
||||
|
||||
// Handle subitems
|
||||
var condition = GetFieldValue<Data.Models.Metadata.Condition>(Data.Models.Metadata.DipValue.ConditionKey);
|
||||
if (condition is not null)
|
||||
SetFieldValue<Condition?>(Data.Models.Metadata.DipValue.ConditionKey, new Condition(condition));
|
||||
}
|
||||
|
||||
public DipValue(Data.Models.Metadata.DipValue item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Data.Models.Metadata.DipValue GetInternalClone()
|
||||
{
|
||||
var dipValueItem = base.GetInternalClone();
|
||||
|
||||
// Handle subitems
|
||||
var subCondition = GetFieldValue<Condition>(Data.Models.Metadata.DipValue.ConditionKey);
|
||||
if (subCondition is not null)
|
||||
dipValueItem[Data.Models.Metadata.DipValue.ConditionKey] = subCondition.GetInternalClone();
|
||||
|
||||
return dipValueItem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
184
SabreTools.Metadata.DatItems/Formats/Disk.cs
Normal file
184
SabreTools.Metadata.DatItems/Formats/Disk.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Data.Extensions;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents Compressed Hunks of Data (CHD) formatted disks which use internal hashes
|
||||
/// </summary>
|
||||
[JsonObject("disk"), XmlRoot("disk")]
|
||||
public sealed class Disk : DatItem<Data.Models.Metadata.Disk>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
/// <summary>
|
||||
/// Non-standard key for inverted logic
|
||||
/// </summary>
|
||||
public const string DiskAreaKey = "DISKAREA";
|
||||
|
||||
/// <summary>
|
||||
/// Non-standard key for inverted logic
|
||||
/// </summary>
|
||||
public const string PartKey = "PART";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Disk;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool DiskAreaSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var diskArea = GetFieldValue<DiskArea?>(DiskAreaKey);
|
||||
return diskArea is not null && !string.IsNullOrEmpty(diskArea.GetName());
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool PartSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var part = GetFieldValue<Part?>(PartKey);
|
||||
return part is not null
|
||||
&& (!string.IsNullOrEmpty(part.GetName())
|
||||
|| !string.IsNullOrEmpty(part.GetStringFieldValue(Data.Models.Metadata.Part.InterfaceKey)));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Disk() : base()
|
||||
{
|
||||
SetFieldValue<DupeType>(DupeTypeKey, 0x00);
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Disk.StatusKey, ItemStatus.None.AsStringValue());
|
||||
}
|
||||
|
||||
public Disk(Data.Models.Metadata.Disk item) : base(item)
|
||||
{
|
||||
SetFieldValue<DupeType>(DupeTypeKey, 0x00);
|
||||
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Disk.OptionalKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Disk.OptionalKey, GetBoolFieldValue(Data.Models.Metadata.Disk.OptionalKey).FromYesNo());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Disk.StatusKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Disk.StatusKey, GetStringFieldValue(Data.Models.Metadata.Disk.StatusKey).AsItemStatus().AsStringValue());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Disk.WritableKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Disk.WritableKey, GetBoolFieldValue(Data.Models.Metadata.Disk.WritableKey).FromYesNo());
|
||||
|
||||
// Process hash values
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Disk.MD5Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Disk.MD5Key, TextHelper.NormalizeMD5(GetStringFieldValue(Data.Models.Metadata.Disk.MD5Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Disk.SHA1Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Disk.SHA1Key, TextHelper.NormalizeSHA1(GetStringFieldValue(Data.Models.Metadata.Disk.SHA1Key)));
|
||||
}
|
||||
|
||||
public Disk(Data.Models.Metadata.Disk item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <summary>
|
||||
/// Convert a disk to the closest Rom approximation
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Rom ConvertToRom()
|
||||
{
|
||||
var rom = new Rom(_internal.ConvertToRom()!);
|
||||
|
||||
// Create a DataArea if there was an existing DiskArea
|
||||
var diskArea = GetFieldValue<DiskArea?>(DiskAreaKey);
|
||||
if (diskArea is not null)
|
||||
{
|
||||
var dataArea = new DataArea();
|
||||
|
||||
string? diskAreaName = diskArea.GetStringFieldValue(Data.Models.Metadata.DiskArea.NameKey);
|
||||
dataArea.SetFieldValue(Data.Models.Metadata.DataArea.NameKey, diskAreaName);
|
||||
|
||||
rom.SetFieldValue<DataArea?>(Rom.DataAreaKey, dataArea);
|
||||
}
|
||||
|
||||
rom.SetFieldValue(DupeTypeKey, GetFieldValue<DupeType>(DupeTypeKey));
|
||||
rom.SetFieldValue(MachineKey, GetMachine()?.Clone() as Machine);
|
||||
rom.SetFieldValue(Rom.PartKey, GetFieldValue<Part>(PartKey)?.Clone() as Part);
|
||||
rom.SetFieldValue(RemoveKey, GetBoolFieldValue(RemoveKey));
|
||||
rom.SetFieldValue<Source?>(SourceKey, GetFieldValue<Source?>(SourceKey)?.Clone() as Source);
|
||||
|
||||
return rom;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Comparision Methods
|
||||
|
||||
/// <summary>
|
||||
/// Fill any missing size and hash information from another Disk
|
||||
/// </summary>
|
||||
/// <param name="other">Disk to fill information from</param>
|
||||
public void FillMissingInformation(Disk other)
|
||||
=> _internal.FillMissingHashes(other._internal);
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the Rom contains any hashes
|
||||
/// </summary>
|
||||
/// <returns>True if any hash exists, false otherwise</returns>
|
||||
public bool HasHashes() => _internal.HasHashes();
|
||||
|
||||
/// <summary>
|
||||
/// Returns if all of the hashes are set to their 0-byte values
|
||||
/// </summary>
|
||||
/// <returns>True if any hash matches the 0-byte value, false otherwise</returns>
|
||||
public bool HasZeroHash() => _internal.HasZeroHash();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sorting and Merging
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GetKey(ItemKey bucketedBy, Machine? machine, Source? source, bool lower = true, bool norename = true)
|
||||
{
|
||||
// Set the output key as the default blank string
|
||||
string? key;
|
||||
|
||||
#pragma warning disable IDE0010
|
||||
// Now determine what the key should be based on the bucketedBy value
|
||||
switch (bucketedBy)
|
||||
{
|
||||
case ItemKey.MD5:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Disk.MD5Key);
|
||||
break;
|
||||
|
||||
case ItemKey.SHA1:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Disk.SHA1Key);
|
||||
break;
|
||||
|
||||
// Let the base handle generic stuff
|
||||
default:
|
||||
return base.GetKey(bucketedBy, machine, source, lower, norename);
|
||||
}
|
||||
#pragma warning restore IDE0010
|
||||
|
||||
// Double and triple check the key for corner cases
|
||||
key ??= string.Empty;
|
||||
if (lower)
|
||||
key = key.ToLowerInvariant();
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
34
SabreTools.Metadata.DatItems/Formats/DiskArea.cs
Normal file
34
SabreTools.Metadata.DatItems/Formats/DiskArea.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// SoftwareList diskarea information
|
||||
/// </summary>
|
||||
/// <remarks>One DiskArea can contain multiple Disk items</remarks>
|
||||
[JsonObject("diskarea"), XmlRoot("diskarea")]
|
||||
public sealed class DiskArea : DatItem<Data.Models.Metadata.DiskArea>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.DiskArea;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public DiskArea() : base() { }
|
||||
|
||||
public DiskArea(Data.Models.Metadata.DiskArea item) : base(item) { }
|
||||
|
||||
public DiskArea(Data.Models.Metadata.DiskArea item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
106
SabreTools.Metadata.DatItems/Formats/Display.cs
Normal file
106
SabreTools.Metadata.DatItems/Formats/Display.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents one machine display
|
||||
/// </summary>
|
||||
[JsonObject("display"), XmlRoot("display")]
|
||||
public sealed class Display : DatItem<Data.Models.Metadata.Display>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Display;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Display() : base() { }
|
||||
|
||||
public Display(Data.Models.Metadata.Display item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Display.FlipXKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.FlipXKey, GetBoolFieldValue(Data.Models.Metadata.Display.FlipXKey).FromYesNo());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Display.HBEndKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.HBEndKey, GetInt64FieldValue(Data.Models.Metadata.Display.HBEndKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Display.HBStartKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.HBStartKey, GetInt64FieldValue(Data.Models.Metadata.Display.HBStartKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Display.HeightKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.HeightKey, GetInt64FieldValue(Data.Models.Metadata.Display.HeightKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Display.HTotalKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.HTotalKey, GetInt64FieldValue(Data.Models.Metadata.Display.HTotalKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Display.PixClockKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.PixClockKey, GetInt64FieldValue(Data.Models.Metadata.Display.PixClockKey).ToString());
|
||||
if (GetDoubleFieldValue(Data.Models.Metadata.Display.RefreshKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.RefreshKey, GetDoubleFieldValue(Data.Models.Metadata.Display.RefreshKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Display.RotateKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.RotateKey, GetInt64FieldValue(Data.Models.Metadata.Display.RotateKey).ToString());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Display.DisplayTypeKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.DisplayTypeKey, GetStringFieldValue(Data.Models.Metadata.Display.DisplayTypeKey).AsDisplayType().AsStringValue());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Display.VBEndKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.VBEndKey, GetInt64FieldValue(Data.Models.Metadata.Display.VBEndKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Display.VBStartKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.VBStartKey, GetInt64FieldValue(Data.Models.Metadata.Display.VBStartKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Display.VTotalKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.VTotalKey, GetInt64FieldValue(Data.Models.Metadata.Display.VTotalKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Display.WidthKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.WidthKey, GetInt64FieldValue(Data.Models.Metadata.Display.WidthKey).ToString());
|
||||
}
|
||||
|
||||
public Display(Data.Models.Metadata.Display item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
public Display(Data.Models.Metadata.Video item) : base()
|
||||
{
|
||||
SetFieldValue(Data.Models.Metadata.Video.AspectXKey, NumberHelper.ConvertToInt64(item.ReadString(Data.Models.Metadata.Video.AspectXKey)));
|
||||
SetFieldValue(Data.Models.Metadata.Video.AspectYKey, NumberHelper.ConvertToInt64(item.ReadString(Data.Models.Metadata.Video.AspectYKey)));
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.DisplayTypeKey, item.ReadString(Data.Models.Metadata.Video.ScreenKey).AsDisplayType().AsStringValue());
|
||||
SetFieldValue(Data.Models.Metadata.Display.HeightKey, NumberHelper.ConvertToInt64(item.ReadString(Data.Models.Metadata.Video.HeightKey)));
|
||||
SetFieldValue(Data.Models.Metadata.Display.RefreshKey, NumberHelper.ConvertToDouble(item.ReadString(Data.Models.Metadata.Video.RefreshKey)));
|
||||
SetFieldValue(Data.Models.Metadata.Display.WidthKey, NumberHelper.ConvertToInt64(item.ReadString(Data.Models.Metadata.Video.WidthKey)));
|
||||
|
||||
switch (item.ReadString(Data.Models.Metadata.Video.OrientationKey))
|
||||
{
|
||||
case "horizontal":
|
||||
SetFieldValue<long?>(Data.Models.Metadata.Display.RotateKey, 0);
|
||||
break;
|
||||
case "vertical":
|
||||
SetFieldValue<long?>(Data.Models.Metadata.Display.RotateKey, 90);
|
||||
break;
|
||||
default:
|
||||
// TODO: Log invalid values
|
||||
break;
|
||||
}
|
||||
|
||||
// Process flag values
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Video.AspectXKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Video.AspectXKey, GetInt64FieldValue(Data.Models.Metadata.Video.AspectXKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Video.AspectYKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Video.AspectYKey, GetInt64FieldValue(Data.Models.Metadata.Video.AspectYKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Video.HeightKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.HeightKey, GetInt64FieldValue(Data.Models.Metadata.Video.HeightKey).ToString());
|
||||
if (GetDoubleFieldValue(Data.Models.Metadata.Video.RefreshKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.RefreshKey, GetDoubleFieldValue(Data.Models.Metadata.Video.RefreshKey).ToString());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Video.ScreenKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.DisplayTypeKey, GetStringFieldValue(Data.Models.Metadata.Video.ScreenKey).AsDisplayType().AsStringValue());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Video.WidthKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Display.WidthKey, GetInt64FieldValue(Data.Models.Metadata.Video.WidthKey).ToString());
|
||||
}
|
||||
|
||||
public Display(Data.Models.Metadata.Video item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
59
SabreTools.Metadata.DatItems/Formats/Driver.cs
Normal file
59
SabreTools.Metadata.DatItems/Formats/Driver.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the a driver of the machine
|
||||
/// </summary>
|
||||
[JsonObject("driver"), XmlRoot("driver")]
|
||||
public sealed class Driver : DatItem<Data.Models.Metadata.Driver>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Driver;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Driver() : base() { }
|
||||
|
||||
public Driver(Data.Models.Metadata.Driver item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Driver.CocktailKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Driver.CocktailKey, GetStringFieldValue(Data.Models.Metadata.Driver.CocktailKey).AsSupportStatus().AsStringValue());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Driver.ColorKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Driver.ColorKey, GetStringFieldValue(Data.Models.Metadata.Driver.ColorKey).AsSupportStatus().AsStringValue());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Driver.EmulationKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Driver.EmulationKey, GetStringFieldValue(Data.Models.Metadata.Driver.EmulationKey).AsSupportStatus().AsStringValue());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Driver.IncompleteKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Driver.IncompleteKey, GetBoolFieldValue(Data.Models.Metadata.Driver.IncompleteKey).FromYesNo());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Driver.NoSoundHardwareKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Driver.NoSoundHardwareKey, GetBoolFieldValue(Data.Models.Metadata.Driver.NoSoundHardwareKey).FromYesNo());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Driver.PaletteSizeKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Driver.PaletteSizeKey, GetInt64FieldValue(Data.Models.Metadata.Driver.PaletteSizeKey).ToString());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Driver.RequiresArtworkKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Driver.RequiresArtworkKey, GetBoolFieldValue(Data.Models.Metadata.Driver.RequiresArtworkKey).FromYesNo());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Driver.SaveStateKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Driver.SaveStateKey, GetStringFieldValue(Data.Models.Metadata.Driver.SaveStateKey).AsSupported().AsStringValue(useSecond: true));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Driver.SoundKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Driver.SoundKey, GetStringFieldValue(Data.Models.Metadata.Driver.SoundKey).AsSupportStatus().AsStringValue());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Driver.StatusKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Driver.StatusKey, GetStringFieldValue(Data.Models.Metadata.Driver.StatusKey).AsSupportStatus().AsStringValue());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Driver.UnofficialKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Driver.UnofficialKey, GetBoolFieldValue(Data.Models.Metadata.Driver.UnofficialKey).FromYesNo());
|
||||
}
|
||||
|
||||
public Driver(Data.Models.Metadata.Driver item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
33
SabreTools.Metadata.DatItems/Formats/Extension.cs
Normal file
33
SabreTools.Metadata.DatItems/Formats/Extension.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a matchable extension
|
||||
/// </summary>
|
||||
[JsonObject("extension"), XmlRoot("extension")]
|
||||
public sealed class Extension : DatItem<Data.Models.Metadata.Extension>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Extension;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Extension() : base() { }
|
||||
|
||||
public Extension(Data.Models.Metadata.Extension item) : base(item) { }
|
||||
|
||||
public Extension(Data.Models.Metadata.Extension item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
42
SabreTools.Metadata.DatItems/Formats/Feature.cs
Normal file
42
SabreTools.Metadata.DatItems/Formats/Feature.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the a feature of the machine
|
||||
/// </summary>
|
||||
[JsonObject("feature"), XmlRoot("feature")]
|
||||
public sealed class Feature : DatItem<Data.Models.Metadata.Feature>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Feature;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Feature() : base() { }
|
||||
|
||||
public Feature(Data.Models.Metadata.Feature item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Feature.OverallKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Feature.OverallKey, GetStringFieldValue(Data.Models.Metadata.Feature.OverallKey).AsFeatureStatus().AsStringValue());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Feature.StatusKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Feature.StatusKey, GetStringFieldValue(Data.Models.Metadata.Feature.StatusKey).AsFeatureStatus().AsStringValue());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Feature.FeatureTypeKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Feature.FeatureTypeKey, GetStringFieldValue(Data.Models.Metadata.Feature.FeatureTypeKey).AsFeatureType().AsStringValue());
|
||||
}
|
||||
|
||||
public Feature(Data.Models.Metadata.Feature item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
323
SabreTools.Metadata.DatItems/Formats/File.cs
Normal file
323
SabreTools.Metadata.DatItems/Formats/File.cs
Normal file
@@ -0,0 +1,323 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Data.Extensions;
|
||||
using SabreTools.Hashing;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
// TODO: Add item mappings for all fields
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single file item
|
||||
/// </summary>
|
||||
[JsonObject("file"), XmlRoot("file")]
|
||||
public sealed class File : DatItem
|
||||
{
|
||||
#region Private instance variables
|
||||
|
||||
private byte[]? _crc; // 8 bytes
|
||||
private byte[]? _md5; // 16 bytes
|
||||
private byte[]? _sha1; // 20 bytes
|
||||
private byte[]? _sha256; // 32 bytes
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.File;
|
||||
|
||||
/// <summary>
|
||||
/// ID value
|
||||
/// </summary>
|
||||
[JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("id")]
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Extension value
|
||||
/// </summary>
|
||||
[JsonProperty("extension", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("extension")]
|
||||
public string? Extension { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Byte size of the rom
|
||||
/// </summary>
|
||||
[JsonProperty("size", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("size")]
|
||||
public long? Size { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// File CRC32 hash
|
||||
/// </summary>
|
||||
[JsonProperty("crc", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("crc")]
|
||||
public string? CRC
|
||||
{
|
||||
get { return _crc.ToHexString(); }
|
||||
set { _crc = value == "null" ? HashType.CRC32.ZeroBytes : TextHelper.NormalizeCRC32(value).FromHexString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// File MD5 hash
|
||||
/// </summary>
|
||||
[JsonProperty("md5", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("md5")]
|
||||
public string? MD5
|
||||
{
|
||||
get { return _md5.ToHexString(); }
|
||||
set { _md5 = TextHelper.NormalizeMD5(value).FromHexString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// File SHA-1 hash
|
||||
/// </summary>
|
||||
[JsonProperty("sha1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("sha1")]
|
||||
public string? SHA1
|
||||
{
|
||||
get { return _sha1.ToHexString(); }
|
||||
set { _sha1 = TextHelper.NormalizeSHA1(value).FromHexString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// File SHA-256 hash
|
||||
/// </summary>
|
||||
[JsonProperty("sha256", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("sha256")]
|
||||
public string? SHA256
|
||||
{
|
||||
get { return _sha256.ToHexString(); }
|
||||
set { _sha256 = TextHelper.NormalizeSHA256(value).FromHexString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Format value
|
||||
/// </summary>
|
||||
[JsonProperty("format", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("format")]
|
||||
public string? Format { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Create a default, empty File object
|
||||
/// </summary>
|
||||
public File()
|
||||
{
|
||||
SetFieldValue(Data.Models.Metadata.DatItem.TypeKey, ItemType);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override object Clone()
|
||||
{
|
||||
var file = new File()
|
||||
{
|
||||
Id = this.Id,
|
||||
Extension = this.Extension,
|
||||
Size = this.Size,
|
||||
_crc = this._crc,
|
||||
_md5 = this._md5,
|
||||
_sha1 = this._sha1,
|
||||
_sha256 = this._sha256,
|
||||
Format = this.Format,
|
||||
};
|
||||
file.SetFieldValue(DupeTypeKey, GetFieldValue<DupeType>(DupeTypeKey));
|
||||
file.SetFieldValue(MachineKey, GetMachine()!.Clone() as Machine ?? new Machine());
|
||||
file.SetFieldValue(RemoveKey, GetBoolFieldValue(RemoveKey));
|
||||
file.SetFieldValue<Source?>(SourceKey, GetFieldValue<Source?>(SourceKey));
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a disk to the closest Rom approximation
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Rom ConvertToRom()
|
||||
{
|
||||
var rom = new Rom();
|
||||
|
||||
rom.SetName($"{Id}.{Extension}");
|
||||
rom.SetFieldValue(Data.Models.Metadata.Rom.SizeKey, Size);
|
||||
rom.SetFieldValue<string?>(Data.Models.Metadata.Rom.CRCKey, CRC);
|
||||
rom.SetFieldValue<string?>(Data.Models.Metadata.Rom.MD5Key, MD5);
|
||||
rom.SetFieldValue<string?>(Data.Models.Metadata.Rom.SHA1Key, SHA1);
|
||||
rom.SetFieldValue<string?>(Data.Models.Metadata.Rom.SHA256Key, SHA256);
|
||||
|
||||
rom.SetFieldValue(DupeTypeKey, GetFieldValue<DupeType>(DupeTypeKey));
|
||||
rom.SetFieldValue(MachineKey, GetMachine()?.Clone() as Machine);
|
||||
rom.SetFieldValue(RemoveKey, GetBoolFieldValue(RemoveKey));
|
||||
rom.SetFieldValue<Source?>(SourceKey, GetFieldValue<Source?>(SourceKey));
|
||||
|
||||
return rom;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Comparision Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(DatItem? other)
|
||||
{
|
||||
bool dupefound = false;
|
||||
|
||||
// If we don't have a file, return false
|
||||
if (GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey) != other?.GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey))
|
||||
return dupefound;
|
||||
|
||||
// Otherwise, treat it as a File
|
||||
File? newOther = other as File;
|
||||
|
||||
// If all hashes are empty, then they're dupes
|
||||
if (!HasHashes() && !newOther!.HasHashes())
|
||||
{
|
||||
dupefound = true;
|
||||
}
|
||||
|
||||
// If we have a file that has no known size, rely on the hashes only
|
||||
else if (Size is null && HashMatch(newOther!))
|
||||
{
|
||||
dupefound = true;
|
||||
}
|
||||
|
||||
// Otherwise if we get a partial match
|
||||
else if (Size == newOther!.Size && HashMatch(newOther))
|
||||
{
|
||||
dupefound = true;
|
||||
}
|
||||
|
||||
return dupefound;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill any missing size and hash information from another Rom
|
||||
/// </summary>
|
||||
/// <param name="other">File to fill information from</param>
|
||||
public void FillMissingInformation(File other)
|
||||
{
|
||||
if (Size is null && other.Size is not null)
|
||||
Size = other.Size;
|
||||
|
||||
if (_crc.IsNullOrEmpty() && !other._crc.IsNullOrEmpty())
|
||||
_crc = other._crc;
|
||||
|
||||
if (_md5.IsNullOrEmpty() && !other._md5.IsNullOrEmpty())
|
||||
_md5 = other._md5;
|
||||
|
||||
if (_sha1.IsNullOrEmpty() && !other._sha1.IsNullOrEmpty())
|
||||
_sha1 = other._sha1;
|
||||
|
||||
if (_sha256.IsNullOrEmpty() && !other._sha256.IsNullOrEmpty())
|
||||
_sha256 = other._sha256;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the File contains any hashes
|
||||
/// </summary>
|
||||
/// <returns>True if any hash exists, false otherwise</returns>
|
||||
public bool HasHashes()
|
||||
{
|
||||
return !_crc.IsNullOrEmpty()
|
||||
|| !_md5.IsNullOrEmpty()
|
||||
|| !_sha1.IsNullOrEmpty()
|
||||
|| !_sha256.IsNullOrEmpty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if all of the hashes are set to their 0-byte values
|
||||
/// </summary>
|
||||
/// <returns>True if any hash matches the 0-byte value, false otherwise</returns>
|
||||
public bool HasZeroHash()
|
||||
{
|
||||
bool crcNull = string.IsNullOrEmpty(CRC) || string.Equals(CRC, HashType.CRC32.ZeroString, StringComparison.OrdinalIgnoreCase);
|
||||
bool md5Null = string.IsNullOrEmpty(MD5) || string.Equals(MD5, HashType.MD5.ZeroString, StringComparison.OrdinalIgnoreCase);
|
||||
bool sha1Null = string.IsNullOrEmpty(SHA1) || string.Equals(SHA1, HashType.SHA1.ZeroString, StringComparison.OrdinalIgnoreCase);
|
||||
bool sha256Null = string.IsNullOrEmpty(SHA256) || string.Equals(SHA256, HashType.SHA256.ZeroString, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
return crcNull && md5Null && sha1Null && sha256Null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if there are no, non-empty hashes in common with another File
|
||||
/// </summary>
|
||||
/// <param name="other">File to compare against</param>
|
||||
/// <returns>True if at least one hash is not mutually exclusive, false otherwise</returns>
|
||||
private bool HasCommonHash(File other)
|
||||
{
|
||||
return !(_crc.IsNullOrEmpty() ^ other._crc.IsNullOrEmpty())
|
||||
|| !(_md5.IsNullOrEmpty() ^ other._md5.IsNullOrEmpty())
|
||||
|| !(_sha1.IsNullOrEmpty() ^ other._sha1.IsNullOrEmpty())
|
||||
|| !(_sha256.IsNullOrEmpty() ^ other._sha256.IsNullOrEmpty());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if any hashes are common with another File
|
||||
/// </summary>
|
||||
/// <param name="other">File to compare against</param>
|
||||
/// <returns>True if any hashes are in common, false otherwise</returns>
|
||||
private bool HashMatch(File other)
|
||||
{
|
||||
// If either have no hashes, we return false, otherwise this would be a false positive
|
||||
if (!HasHashes() || !other.HasHashes())
|
||||
return false;
|
||||
|
||||
// If neither have hashes in common, we return false, otherwise this would be a false positive
|
||||
if (!HasCommonHash(other))
|
||||
return false;
|
||||
|
||||
// Return if all hashes match according to merge rules
|
||||
return MetadataExtensions.ConditionalHashEquals(_crc, other._crc)
|
||||
&& MetadataExtensions.ConditionalHashEquals(_md5, other._md5)
|
||||
&& MetadataExtensions.ConditionalHashEquals(_sha1, other._sha1)
|
||||
&& MetadataExtensions.ConditionalHashEquals(_sha256, other._sha256);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sorting and Merging
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GetKey(ItemKey bucketedBy, Machine? machine, Source? source, bool lower = true, bool norename = true)
|
||||
{
|
||||
// Set the output key as the default blank string
|
||||
string? key;
|
||||
|
||||
#pragma warning disable IDE0010
|
||||
// Now determine what the key should be based on the bucketedBy value
|
||||
switch (bucketedBy)
|
||||
{
|
||||
case ItemKey.CRC:
|
||||
key = CRC;
|
||||
break;
|
||||
|
||||
case ItemKey.MD5:
|
||||
key = MD5;
|
||||
break;
|
||||
|
||||
case ItemKey.SHA1:
|
||||
key = SHA1;
|
||||
break;
|
||||
|
||||
case ItemKey.SHA256:
|
||||
key = SHA256;
|
||||
break;
|
||||
|
||||
// Let the base handle generic stuff
|
||||
default:
|
||||
return base.GetKey(bucketedBy, machine, source, lower, norename);
|
||||
}
|
||||
#pragma warning restore IDE0010
|
||||
|
||||
// Double and triple check the key for corner cases
|
||||
key ??= string.Empty;
|
||||
if (lower)
|
||||
key = key.ToLowerInvariant();
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
33
SabreTools.Metadata.DatItems/Formats/Info.cs
Normal file
33
SabreTools.Metadata.DatItems/Formats/Info.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents special information about a machine
|
||||
/// </summary>
|
||||
[JsonObject("info"), XmlRoot("info")]
|
||||
public sealed class Info : DatItem<Data.Models.Metadata.Info>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Info;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Info() : base() { }
|
||||
|
||||
public Info(Data.Models.Metadata.Info item) : base(item) { }
|
||||
|
||||
public Info(Data.Models.Metadata.Info item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
86
SabreTools.Metadata.DatItems/Formats/Input.cs
Normal file
86
SabreTools.Metadata.DatItems/Formats/Input.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Data.Extensions;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents one ListXML input
|
||||
/// </summary>
|
||||
[JsonObject("input"), XmlRoot("input")]
|
||||
public sealed class Input : DatItem<Data.Models.Metadata.Input>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Input;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ControlsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var controls = GetFieldValue<Control[]?>(Data.Models.Metadata.Input.ControlKey);
|
||||
return controls is not null && controls.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Input() : base() { }
|
||||
|
||||
public Input(Data.Models.Metadata.Input item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Input.ButtonsKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Input.ButtonsKey, GetInt64FieldValue(Data.Models.Metadata.Input.ButtonsKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Input.CoinsKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Input.CoinsKey, GetInt64FieldValue(Data.Models.Metadata.Input.CoinsKey).ToString());
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Input.PlayersKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Input.PlayersKey, GetInt64FieldValue(Data.Models.Metadata.Input.PlayersKey).ToString());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Input.ServiceKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Input.ServiceKey, GetBoolFieldValue(Data.Models.Metadata.Input.ServiceKey).FromYesNo());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Input.TiltKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Input.TiltKey, GetBoolFieldValue(Data.Models.Metadata.Input.TiltKey).FromYesNo());
|
||||
|
||||
// Handle subitems
|
||||
var controls = item.ReadItemArray<Data.Models.Metadata.Control>(Data.Models.Metadata.Input.ControlKey);
|
||||
if (controls is not null)
|
||||
{
|
||||
Control[] controlItems = Array.ConvertAll(controls, control => new Control(control));
|
||||
SetFieldValue<Control[]?>(Data.Models.Metadata.Input.ControlKey, controlItems);
|
||||
}
|
||||
}
|
||||
|
||||
public Input(Data.Models.Metadata.Input item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Data.Models.Metadata.Input GetInternalClone()
|
||||
{
|
||||
var inputItem = base.GetInternalClone();
|
||||
|
||||
var controls = GetFieldValue<Control[]?>(Data.Models.Metadata.Input.ControlKey);
|
||||
if (controls is not null)
|
||||
{
|
||||
Data.Models.Metadata.Control[] controlItems = Array.ConvertAll(controls, control => control.GetInternalClone());
|
||||
inputItem[Data.Models.Metadata.Input.ControlKey] = controlItems;
|
||||
}
|
||||
|
||||
return inputItem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
33
SabreTools.Metadata.DatItems/Formats/Instance.cs
Normal file
33
SabreTools.Metadata.DatItems/Formats/Instance.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single instance of another item
|
||||
/// </summary>
|
||||
[JsonObject("instance"), XmlRoot("instance")]
|
||||
public sealed class Instance : DatItem<Data.Models.Metadata.Instance>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Instance;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Instance() : base() { }
|
||||
|
||||
public Instance(Data.Models.Metadata.Instance item) : base(item) { }
|
||||
|
||||
public Instance(Data.Models.Metadata.Instance item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
136
SabreTools.Metadata.DatItems/Formats/Media.cs
Normal file
136
SabreTools.Metadata.DatItems/Formats/Media.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Data.Extensions;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents Aaruformat images which use internal hashes
|
||||
/// </summary>
|
||||
[JsonObject("media"), XmlRoot("media")]
|
||||
public sealed class Media : DatItem<Data.Models.Metadata.Media>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Media;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Media() : base()
|
||||
{
|
||||
SetFieldValue<DupeType>(DupeTypeKey, 0x00);
|
||||
}
|
||||
|
||||
public Media(Data.Models.Metadata.Media item) : base(item)
|
||||
{
|
||||
SetFieldValue<DupeType>(DupeTypeKey, 0x00);
|
||||
|
||||
// Process hash values
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Media.MD5Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Media.MD5Key, TextHelper.NormalizeMD5(GetStringFieldValue(Data.Models.Metadata.Media.MD5Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Media.SHA1Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Media.SHA1Key, TextHelper.NormalizeSHA1(GetStringFieldValue(Data.Models.Metadata.Media.SHA1Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Media.SHA256Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Media.SHA256Key, TextHelper.NormalizeSHA256(GetStringFieldValue(Data.Models.Metadata.Media.SHA256Key)));
|
||||
}
|
||||
|
||||
public Media(Data.Models.Metadata.Media item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <summary>
|
||||
/// Convert a media to the closest Rom approximation
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Rom ConvertToRom()
|
||||
{
|
||||
var rom = new Rom(_internal.ConvertToRom()!);
|
||||
|
||||
rom.SetFieldValue(DupeTypeKey, GetFieldValue<DupeType>(DupeTypeKey));
|
||||
rom.SetFieldValue(MachineKey, GetMachine());
|
||||
rom.SetFieldValue(RemoveKey, GetBoolFieldValue(RemoveKey));
|
||||
rom.SetFieldValue<Source?>(SourceKey, GetFieldValue<Source?>(SourceKey));
|
||||
|
||||
return rom;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Comparision Methods
|
||||
|
||||
/// <summary>
|
||||
/// Fill any missing size and hash information from another Media
|
||||
/// </summary>
|
||||
/// <param name="other">Media to fill information from</param>
|
||||
public void FillMissingInformation(Media other)
|
||||
=> _internal.FillMissingHashes(other._internal);
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the Rom contains any hashes
|
||||
/// </summary>
|
||||
/// <returns>True if any hash exists, false otherwise</returns>
|
||||
public bool HasHashes() => _internal.HasHashes();
|
||||
|
||||
/// <summary>
|
||||
/// Returns if all of the hashes are set to their 0-byte values
|
||||
/// </summary>
|
||||
/// <returns>True if any hash matches the 0-byte value, false otherwise</returns>
|
||||
public bool HasZeroHash() => _internal.HasZeroHash();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sorting and Merging
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GetKey(ItemKey bucketedBy, Machine? machine, Source? source, bool lower = true, bool norename = true)
|
||||
{
|
||||
// Set the output key as the default blank string
|
||||
string? key;
|
||||
|
||||
#pragma warning disable IDE0010
|
||||
// Now determine what the key should be based on the bucketedBy value
|
||||
switch (bucketedBy)
|
||||
{
|
||||
case ItemKey.MD5:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Media.MD5Key);
|
||||
break;
|
||||
|
||||
case ItemKey.SHA1:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Media.SHA1Key);
|
||||
break;
|
||||
|
||||
case ItemKey.SHA256:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Media.SHA256Key);
|
||||
break;
|
||||
|
||||
case ItemKey.SpamSum:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Media.SpamSumKey);
|
||||
break;
|
||||
|
||||
// Let the base handle generic stuff
|
||||
default:
|
||||
return base.GetKey(bucketedBy, machine, source, lower, norename);
|
||||
}
|
||||
#pragma warning restore IDE0010
|
||||
|
||||
// Double and triple check the key for corner cases
|
||||
key ??= string.Empty;
|
||||
if (lower)
|
||||
key = key.ToLowerInvariant();
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
32
SabreTools.Metadata.DatItems/Formats/Original.cs
Normal file
32
SabreTools.Metadata.DatItems/Formats/Original.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the OpenMSX original value
|
||||
/// </summary>
|
||||
[JsonObject("original"), XmlRoot("original")]
|
||||
public sealed class Original
|
||||
{
|
||||
[JsonProperty("value"), XmlElement("value")]
|
||||
public bool? Value
|
||||
{
|
||||
get => _internal.ReadBool(Data.Models.Metadata.Original.ValueKey);
|
||||
set => _internal[Data.Models.Metadata.Original.ValueKey] = value;
|
||||
}
|
||||
|
||||
[JsonProperty("content"), XmlElement("content")]
|
||||
public string? Content
|
||||
{
|
||||
get => _internal.ReadString(Data.Models.Metadata.Original.ContentKey);
|
||||
set => _internal[Data.Models.Metadata.Original.ContentKey] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal Original model
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
private readonly Data.Models.Metadata.Original _internal = [];
|
||||
}
|
||||
}
|
||||
44
SabreTools.Metadata.DatItems/Formats/Part.cs
Normal file
44
SabreTools.Metadata.DatItems/Formats/Part.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// SoftwareList part information
|
||||
/// </summary>
|
||||
/// <remarks>One Part can contain multiple PartFeature, DataArea, DiskArea, and DipSwitch items</remarks>
|
||||
[JsonObject("part"), XmlRoot("part")]
|
||||
public sealed class Part : DatItem<Data.Models.Metadata.Part>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Part;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool FeaturesSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var features = GetFieldValue<PartFeature[]?>(Data.Models.Metadata.Part.FeatureKey);
|
||||
return features is not null && features.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Part() : base() { }
|
||||
|
||||
public Part(Data.Models.Metadata.Part item) : base(item) { }
|
||||
|
||||
public Part(Data.Models.Metadata.Part item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
51
SabreTools.Metadata.DatItems/Formats/PartFeature.cs
Normal file
51
SabreTools.Metadata.DatItems/Formats/PartFeature.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents one part feature object
|
||||
/// </summary>
|
||||
[JsonObject("part_feature"), XmlRoot("part_feature")]
|
||||
public sealed class PartFeature : DatItem<Data.Models.Metadata.Feature>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
/// <summary>
|
||||
/// Non-standard key for inverted logic
|
||||
/// </summary>
|
||||
public const string PartKey = "PART";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.PartFeature;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public PartFeature() : base() { }
|
||||
|
||||
public PartFeature(Data.Models.Metadata.Feature item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Feature.OverallKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Feature.OverallKey, GetStringFieldValue(Data.Models.Metadata.Feature.OverallKey).AsFeatureStatus().AsStringValue());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Feature.StatusKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Feature.StatusKey, GetStringFieldValue(Data.Models.Metadata.Feature.StatusKey).AsFeatureStatus().AsStringValue());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Feature.FeatureTypeKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Feature.FeatureTypeKey, GetStringFieldValue(Data.Models.Metadata.Feature.FeatureTypeKey).AsFeatureType().AsStringValue());
|
||||
}
|
||||
|
||||
public PartFeature(Data.Models.Metadata.Feature item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
73
SabreTools.Metadata.DatItems/Formats/Port.cs
Normal file
73
SabreTools.Metadata.DatItems/Formats/Port.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Data.Extensions;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single port on a machine
|
||||
/// </summary>
|
||||
[JsonObject("port"), XmlRoot("port")]
|
||||
public sealed class Port : DatItem<Data.Models.Metadata.Port>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Port;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool AnalogsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var analogs = GetFieldValue<Analog[]?>(Data.Models.Metadata.Port.AnalogKey);
|
||||
return analogs is not null && analogs.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Port() : base() { }
|
||||
|
||||
public Port(Data.Models.Metadata.Port item) : base(item)
|
||||
{
|
||||
// Handle subitems
|
||||
var analogs = item.ReadItemArray<Data.Models.Metadata.Analog>(Data.Models.Metadata.Port.AnalogKey);
|
||||
if (analogs is not null)
|
||||
{
|
||||
Analog[] analogItems = Array.ConvertAll(analogs, analog => new Analog(analog));
|
||||
SetFieldValue<Analog[]?>(Data.Models.Metadata.Port.AnalogKey, analogItems);
|
||||
}
|
||||
}
|
||||
|
||||
public Port(Data.Models.Metadata.Port item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Data.Models.Metadata.Port GetInternalClone()
|
||||
{
|
||||
var portItem = base.GetInternalClone();
|
||||
|
||||
var analogs = GetFieldValue<Analog[]?>(Data.Models.Metadata.Port.AnalogKey);
|
||||
if (analogs is not null)
|
||||
{
|
||||
Data.Models.Metadata.Analog[] analogItems = Array.ConvertAll(analogs, analog => analog.GetInternalClone());
|
||||
portItem[Data.Models.Metadata.Port.AnalogKey] = analogItems;
|
||||
}
|
||||
|
||||
return portItem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
39
SabreTools.Metadata.DatItems/Formats/RamOption.cs
Normal file
39
SabreTools.Metadata.DatItems/Formats/RamOption.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents which RAM option(s) is associated with a set
|
||||
/// </summary>
|
||||
[JsonObject("ramoption"), XmlRoot("ramoption")]
|
||||
public sealed class RamOption : DatItem<Data.Models.Metadata.RamOption>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.RamOption;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public RamOption() : base() { }
|
||||
|
||||
public RamOption(Data.Models.Metadata.RamOption item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.RamOption.DefaultKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.RamOption.DefaultKey, GetBoolFieldValue(Data.Models.Metadata.RamOption.DefaultKey).FromYesNo());
|
||||
}
|
||||
|
||||
public RamOption(Data.Models.Metadata.RamOption item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
39
SabreTools.Metadata.DatItems/Formats/Release.cs
Normal file
39
SabreTools.Metadata.DatItems/Formats/Release.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents release information about a set
|
||||
/// </summary>
|
||||
[JsonObject("release"), XmlRoot("release")]
|
||||
public sealed class Release : DatItem<Data.Models.Metadata.Release>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Release;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Release() : base() { }
|
||||
|
||||
public Release(Data.Models.Metadata.Release item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Release.DefaultKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Release.DefaultKey, GetBoolFieldValue(Data.Models.Metadata.Release.DefaultKey).FromYesNo());
|
||||
}
|
||||
|
||||
public Release(Data.Models.Metadata.Release item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
189
SabreTools.Metadata.DatItems/Formats/ReleaseDetails.cs
Normal file
189
SabreTools.Metadata.DatItems/Formats/ReleaseDetails.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
// TODO: Add item mappings for all fields
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single release details item
|
||||
/// </summary>
|
||||
[JsonObject("release_details"), XmlRoot("release_details")]
|
||||
public sealed class ReleaseDetails : DatItem
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.ReleaseDetails;
|
||||
|
||||
/// <summary>
|
||||
/// Id value
|
||||
/// </summary>
|
||||
/// <remarks>TODO: Is this required?</remarks>
|
||||
[JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("id")]
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Directory name value
|
||||
/// </summary>
|
||||
[JsonProperty("dirname", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("dirname")]
|
||||
public string? DirName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Rom info value
|
||||
/// </summary>
|
||||
[JsonProperty("rominfo", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("rominfo")]
|
||||
public string? RomInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Category value
|
||||
/// </summary>
|
||||
[JsonProperty("category", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("category")]
|
||||
public string? Category { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// NFO name value
|
||||
/// </summary>
|
||||
[JsonProperty("nfoname", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("nfoname")]
|
||||
public string? NfoName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// NFO size value
|
||||
/// </summary>
|
||||
[JsonProperty("nfosize", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("nfosize")]
|
||||
public long? NfoSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// NFO CRC value
|
||||
/// </summary>
|
||||
[JsonProperty("nfocrc", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("nfocrc")]
|
||||
public string? NfoCrc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Archive name value
|
||||
/// </summary>
|
||||
[JsonProperty("archivename", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("archivename")]
|
||||
public string? ArchiveName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Original format value
|
||||
/// </summary>
|
||||
[JsonProperty("originalformat", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("originalformat")]
|
||||
public string? OriginalFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Date value
|
||||
/// </summary>
|
||||
[JsonProperty("date", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("date")]
|
||||
public string? Date { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Grpup value
|
||||
/// </summary>
|
||||
[JsonProperty("group", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("group")]
|
||||
public string? Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Comment value
|
||||
/// </summary>
|
||||
[JsonProperty("comment", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tool value
|
||||
/// </summary>
|
||||
[JsonProperty("tool", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("tool")]
|
||||
public string? Tool { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Region value
|
||||
/// </summary>
|
||||
[JsonProperty("region", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("region")]
|
||||
public string? Region { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Origin value
|
||||
/// </summary>
|
||||
[JsonProperty("origin", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("origin")]
|
||||
public string? Origin { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Create a default, empty ReleaseDetails object
|
||||
/// </summary>
|
||||
public ReleaseDetails()
|
||||
{
|
||||
SetFieldValue(Data.Models.Metadata.DatItem.TypeKey, ItemType);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override object Clone()
|
||||
{
|
||||
var releaseDetails = new ReleaseDetails()
|
||||
{
|
||||
Id = this.Id,
|
||||
DirName = this.DirName,
|
||||
RomInfo = this.RomInfo,
|
||||
Category = this.Category,
|
||||
NfoName = this.NfoName,
|
||||
NfoSize = this.NfoSize,
|
||||
NfoCrc = this.NfoCrc,
|
||||
ArchiveName = this.ArchiveName,
|
||||
OriginalFormat = this.OriginalFormat,
|
||||
Date = this.Date,
|
||||
Group = this.Group,
|
||||
Comment = this.Comment,
|
||||
Tool = this.Tool,
|
||||
Region = this.Region,
|
||||
Origin = this.Origin,
|
||||
};
|
||||
releaseDetails.SetFieldValue(DupeTypeKey, GetFieldValue<DupeType>(DupeTypeKey));
|
||||
releaseDetails.SetFieldValue(MachineKey, GetMachine());
|
||||
releaseDetails.SetFieldValue(RemoveKey, GetBoolFieldValue(RemoveKey));
|
||||
releaseDetails.SetFieldValue<Source?>(SourceKey, GetFieldValue<Source?>(SourceKey));
|
||||
releaseDetails.SetFieldValue<string?>(Data.Models.Metadata.DatItem.TypeKey, GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey).AsItemType().AsStringValue());
|
||||
|
||||
return releaseDetails;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Comparision Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(DatItem? other)
|
||||
{
|
||||
// If we don't have a Details, return false
|
||||
if (GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey) != other?.GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey))
|
||||
return false;
|
||||
|
||||
// Otherwise, treat it as a Details
|
||||
ReleaseDetails? newOther = other as ReleaseDetails;
|
||||
|
||||
// If the Details information matches
|
||||
return Id == newOther!.Id
|
||||
&& DirName == newOther.DirName
|
||||
&& RomInfo == newOther.RomInfo
|
||||
&& Category == newOther.Category
|
||||
&& NfoName == newOther.NfoName
|
||||
&& NfoSize == newOther.NfoSize
|
||||
&& NfoCrc == newOther.NfoCrc
|
||||
&& ArchiveName == newOther.ArchiveName
|
||||
&& OriginalFormat == newOther.OriginalFormat
|
||||
&& Date == newOther.Date
|
||||
&& Group == newOther.Group
|
||||
&& Comment == newOther.Comment
|
||||
&& Tool == newOther.Tool
|
||||
&& Region == newOther.Region
|
||||
&& Origin == newOther.Origin;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
312
SabreTools.Metadata.DatItems/Formats/Rom.cs
Normal file
312
SabreTools.Metadata.DatItems/Formats/Rom.cs
Normal file
@@ -0,0 +1,312 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Data.Extensions;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic file within a set
|
||||
/// </summary>
|
||||
[JsonObject("rom"), XmlRoot("rom")]
|
||||
public sealed class Rom : DatItem<Data.Models.Metadata.Rom>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
/// <summary>
|
||||
/// Non-standard key for inverted logic
|
||||
/// </summary>
|
||||
public const string DataAreaKey = "DATAAREA";
|
||||
|
||||
/// <summary>
|
||||
/// Non-standard key for inverted logic
|
||||
/// </summary>
|
||||
public const string PartKey = "PART";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Rom;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool ItemStatusSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var status = GetStringFieldValue(Data.Models.Metadata.Rom.StatusKey).AsItemStatus();
|
||||
return status != ItemStatus.NULL && status != ItemStatus.None;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool OriginalSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var original = GetFieldValue<Original?>("ORIGINAL");
|
||||
return original is not null && original != default;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool DataAreaSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var dataArea = GetFieldValue<DataArea?>(DataAreaKey);
|
||||
return dataArea is not null
|
||||
&& (!string.IsNullOrEmpty(dataArea.GetName())
|
||||
|| dataArea.GetInt64FieldValue(Data.Models.Metadata.DataArea.SizeKey) is not null
|
||||
|| dataArea.GetInt64FieldValue(Data.Models.Metadata.DataArea.WidthKey) is not null
|
||||
|| dataArea.GetStringFieldValue(Data.Models.Metadata.DataArea.EndiannessKey).AsEndianness() != Endianness.NULL);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool PartSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var part = GetFieldValue<Part?>(PartKey);
|
||||
return part is not null
|
||||
&& (!string.IsNullOrEmpty(part.GetName())
|
||||
|| !string.IsNullOrEmpty(part.GetStringFieldValue(Data.Models.Metadata.Part.InterfaceKey)));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Rom() : base()
|
||||
{
|
||||
SetFieldValue<DupeType>(DupeTypeKey, 0x00);
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.StatusKey, ItemStatus.None.AsStringValue());
|
||||
}
|
||||
|
||||
public Rom(Data.Models.Metadata.Dump item, Machine machine, Source source, int index)
|
||||
{
|
||||
// If we don't have rom data, we can't do anything
|
||||
Data.Models.Metadata.Rom? rom = null;
|
||||
OpenMSXSubType subType = OpenMSXSubType.NULL;
|
||||
if (item.Read<Data.Models.Metadata.Rom>(Data.Models.Metadata.Dump.RomKey) is not null)
|
||||
{
|
||||
rom = item.Read<Data.Models.Metadata.Rom>(Data.Models.Metadata.Dump.RomKey);
|
||||
subType = OpenMSXSubType.Rom;
|
||||
}
|
||||
else if (item.Read<Data.Models.Metadata.Rom>(Data.Models.Metadata.Dump.MegaRomKey) is not null)
|
||||
{
|
||||
rom = item.Read<Data.Models.Metadata.Rom>(Data.Models.Metadata.Dump.MegaRomKey);
|
||||
subType = OpenMSXSubType.MegaRom;
|
||||
}
|
||||
else if (item.Read<Data.Models.Metadata.Rom>(Data.Models.Metadata.Dump.SCCPlusCartKey) is not null)
|
||||
{
|
||||
rom = item.Read<Data.Models.Metadata.Rom>(Data.Models.Metadata.Dump.SCCPlusCartKey);
|
||||
subType = OpenMSXSubType.SCCPlusCart;
|
||||
}
|
||||
|
||||
// Just return if nothing valid was found
|
||||
if (rom is null)
|
||||
return;
|
||||
|
||||
string name = $"{machine.GetName()}_{index++}{(!string.IsNullOrEmpty(rom!.ReadString(Data.Models.Metadata.Rom.RemarkKey)) ? $" {rom.ReadString(Data.Models.Metadata.Rom.RemarkKey)}" : string.Empty)}";
|
||||
|
||||
SetName(name);
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.OffsetKey, rom.ReadString(Data.Models.Metadata.Rom.StartKey));
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.OpenMSXMediaType, subType.AsStringValue());
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.OpenMSXType, rom.ReadString(Data.Models.Metadata.Rom.OpenMSXType) ?? rom.ReadString(Data.Models.Metadata.DatItem.TypeKey));
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.RemarkKey, rom.ReadString(Data.Models.Metadata.Rom.RemarkKey));
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.SHA1Key, rom.ReadString(Data.Models.Metadata.Rom.SHA1Key));
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.StartKey, rom.ReadString(Data.Models.Metadata.Rom.StartKey));
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
|
||||
if (item.Read<Data.Models.Metadata.Original>(Data.Models.Metadata.Dump.OriginalKey) is not null)
|
||||
{
|
||||
var original = item.Read<Data.Models.Metadata.Original>(Data.Models.Metadata.Dump.OriginalKey)!;
|
||||
SetFieldValue<Original?>("ORIGINAL", new Original
|
||||
{
|
||||
Value = original.ReadBool(Data.Models.Metadata.Original.ValueKey),
|
||||
Content = original.ReadString(Data.Models.Metadata.Original.ContentKey),
|
||||
});
|
||||
}
|
||||
|
||||
CopyMachineInformation(machine);
|
||||
|
||||
// Process hash values
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Rom.SizeKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.SizeKey, GetInt64FieldValue(Data.Models.Metadata.Rom.SizeKey).ToString());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.CRCKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.CRCKey, TextHelper.NormalizeCRC32(GetStringFieldValue(Data.Models.Metadata.Rom.CRCKey)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.MD2Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.MD2Key, TextHelper.NormalizeMD2(GetStringFieldValue(Data.Models.Metadata.Rom.MD2Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.MD4Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.MD4Key, TextHelper.NormalizeMD5(GetStringFieldValue(Data.Models.Metadata.Rom.MD4Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.MD5Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.MD5Key, TextHelper.NormalizeMD5(GetStringFieldValue(Data.Models.Metadata.Rom.MD5Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.RIPEMD128Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.RIPEMD128Key, TextHelper.NormalizeRIPEMD128(GetStringFieldValue(Data.Models.Metadata.Rom.RIPEMD128Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.RIPEMD160Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.RIPEMD160Key, TextHelper.NormalizeRIPEMD160(GetStringFieldValue(Data.Models.Metadata.Rom.RIPEMD160Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.SHA1Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.SHA1Key, TextHelper.NormalizeSHA1(GetStringFieldValue(Data.Models.Metadata.Rom.SHA1Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.SHA256Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.SHA256Key, TextHelper.NormalizeSHA256(GetStringFieldValue(Data.Models.Metadata.Rom.SHA256Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.SHA384Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.SHA384Key, TextHelper.NormalizeSHA384(GetStringFieldValue(Data.Models.Metadata.Rom.SHA384Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.SHA512Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.SHA512Key, TextHelper.NormalizeSHA512(GetStringFieldValue(Data.Models.Metadata.Rom.SHA512Key)));
|
||||
}
|
||||
|
||||
public Rom(Data.Models.Metadata.Rom item) : base(item)
|
||||
{
|
||||
SetFieldValue<DupeType>(DupeTypeKey, 0x00);
|
||||
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Rom.DisposeKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.DisposeKey, GetBoolFieldValue(Data.Models.Metadata.Rom.DisposeKey).FromYesNo());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Rom.InvertedKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.InvertedKey, GetBoolFieldValue(Data.Models.Metadata.Rom.InvertedKey).FromYesNo());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.LoadFlagKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.LoadFlagKey, GetStringFieldValue(Data.Models.Metadata.Rom.LoadFlagKey).AsLoadFlag().AsStringValue());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.OpenMSXMediaType) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.OpenMSXMediaType, GetStringFieldValue(Data.Models.Metadata.Rom.OpenMSXMediaType).AsOpenMSXSubType().AsStringValue());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Rom.MIAKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.MIAKey, GetBoolFieldValue(Data.Models.Metadata.Rom.MIAKey).FromYesNo());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Rom.OptionalKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.OptionalKey, GetBoolFieldValue(Data.Models.Metadata.Rom.OptionalKey).FromYesNo());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Rom.SoundOnlyKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.SoundOnlyKey, GetBoolFieldValue(Data.Models.Metadata.Rom.SoundOnlyKey).FromYesNo());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.StatusKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.StatusKey, GetStringFieldValue(Data.Models.Metadata.Rom.StatusKey).AsItemStatus().AsStringValue());
|
||||
|
||||
// Process hash values
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Rom.SizeKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.SizeKey, GetInt64FieldValue(Data.Models.Metadata.Rom.SizeKey).ToString());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.CRCKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.CRCKey, TextHelper.NormalizeCRC32(GetStringFieldValue(Data.Models.Metadata.Rom.CRCKey)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.MD2Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.MD2Key, TextHelper.NormalizeMD2(GetStringFieldValue(Data.Models.Metadata.Rom.MD2Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.MD4Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.MD4Key, TextHelper.NormalizeMD4(GetStringFieldValue(Data.Models.Metadata.Rom.MD4Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.MD5Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.MD5Key, TextHelper.NormalizeMD5(GetStringFieldValue(Data.Models.Metadata.Rom.MD5Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.RIPEMD128Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.RIPEMD128Key, TextHelper.NormalizeRIPEMD128(GetStringFieldValue(Data.Models.Metadata.Rom.RIPEMD128Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.RIPEMD160Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.RIPEMD160Key, TextHelper.NormalizeRIPEMD160(GetStringFieldValue(Data.Models.Metadata.Rom.RIPEMD160Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.SHA1Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.SHA1Key, TextHelper.NormalizeSHA1(GetStringFieldValue(Data.Models.Metadata.Rom.SHA1Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.SHA256Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.SHA256Key, TextHelper.NormalizeSHA256(GetStringFieldValue(Data.Models.Metadata.Rom.SHA256Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.SHA384Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.SHA384Key, TextHelper.NormalizeSHA384(GetStringFieldValue(Data.Models.Metadata.Rom.SHA384Key)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Rom.SHA512Key) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Rom.SHA512Key, TextHelper.NormalizeSHA512(GetStringFieldValue(Data.Models.Metadata.Rom.SHA512Key)));
|
||||
}
|
||||
|
||||
public Rom(Data.Models.Metadata.Rom item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Comparision Methods
|
||||
|
||||
/// <summary>
|
||||
/// Fill any missing size and hash information from another Rom
|
||||
/// </summary>
|
||||
/// <param name="other">Rom to fill information from</param>
|
||||
public void FillMissingInformation(Rom other)
|
||||
=> _internal.FillMissingHashes(other._internal);
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the Rom contains any hashes
|
||||
/// </summary>
|
||||
/// <returns>True if any hash exists, false otherwise</returns>
|
||||
public bool HasHashes() => _internal.HasHashes();
|
||||
|
||||
/// <summary>
|
||||
/// Returns if all of the hashes are set to their 0-byte values
|
||||
/// </summary>
|
||||
/// <returns>True if any hash matches the 0-byte value, false otherwise</returns>
|
||||
public bool HasZeroHash() => _internal.HasZeroHash();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sorting and Merging
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GetKey(ItemKey bucketedBy, Machine? machine, Source? source, bool lower = true, bool norename = true)
|
||||
{
|
||||
// Set the output key as the default blank string
|
||||
string? key;
|
||||
|
||||
#pragma warning disable IDE0010
|
||||
// Now determine what the key should be based on the bucketedBy value
|
||||
switch (bucketedBy)
|
||||
{
|
||||
case ItemKey.CRC:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Rom.CRCKey);
|
||||
break;
|
||||
|
||||
case ItemKey.MD2:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Rom.MD2Key);
|
||||
break;
|
||||
|
||||
case ItemKey.MD4:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Rom.MD4Key);
|
||||
break;
|
||||
|
||||
case ItemKey.MD5:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Rom.MD5Key);
|
||||
break;
|
||||
|
||||
case ItemKey.RIPEMD128:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Rom.RIPEMD128Key);
|
||||
break;
|
||||
|
||||
case ItemKey.RIPEMD160:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Rom.RIPEMD160Key);
|
||||
break;
|
||||
|
||||
case ItemKey.SHA1:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Rom.SHA1Key);
|
||||
break;
|
||||
|
||||
case ItemKey.SHA256:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Rom.SHA256Key);
|
||||
break;
|
||||
|
||||
case ItemKey.SHA384:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Rom.SHA384Key);
|
||||
break;
|
||||
|
||||
case ItemKey.SHA512:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Rom.SHA512Key);
|
||||
break;
|
||||
|
||||
case ItemKey.SpamSum:
|
||||
key = GetStringFieldValue(Data.Models.Metadata.Rom.SpamSumKey);
|
||||
break;
|
||||
|
||||
// Let the base handle generic stuff
|
||||
default:
|
||||
return base.GetKey(bucketedBy, machine, source, lower, norename);
|
||||
}
|
||||
#pragma warning restore IDE0010
|
||||
|
||||
// Double and triple check the key for corner cases
|
||||
key ??= string.Empty;
|
||||
if (lower)
|
||||
key = key.ToLowerInvariant();
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
33
SabreTools.Metadata.DatItems/Formats/Sample.cs
Normal file
33
SabreTools.Metadata.DatItems/Formats/Sample.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a (usually WAV-formatted) sample to be included for use in the set
|
||||
/// </summary>
|
||||
[JsonObject("sample"), XmlRoot("sample")]
|
||||
public class Sample : DatItem<Data.Models.Metadata.Sample>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Sample;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Sample() : base() { }
|
||||
|
||||
public Sample(Data.Models.Metadata.Sample item) : base(item) { }
|
||||
|
||||
public Sample(Data.Models.Metadata.Sample item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
180
SabreTools.Metadata.DatItems/Formats/Serials.cs
Normal file
180
SabreTools.Metadata.DatItems/Formats/Serials.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
// TODO: Add item mappings for all fields
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single serials item
|
||||
/// </summary>
|
||||
[JsonObject("serials"), XmlRoot("serials")]
|
||||
public sealed class Serials : DatItem
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Serials;
|
||||
|
||||
/// <summary>
|
||||
/// Digital serial 1 value
|
||||
/// </summary>
|
||||
[JsonProperty("digital_serial1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("digital_serial1")]
|
||||
public string? DigitalSerial1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Digital serial 2 value
|
||||
/// </summary>
|
||||
[JsonProperty("digital_serial2", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("digital_serial2")]
|
||||
public string? DigitalSerial2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Media serial 1 value
|
||||
/// </summary>
|
||||
[JsonProperty("media_serial1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("media_serial1")]
|
||||
public string? MediaSerial1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Media serial 2 value
|
||||
/// </summary>
|
||||
[JsonProperty("media_serial2", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("media_serial2")]
|
||||
public string? MediaSerial2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Media serial 3 value
|
||||
/// </summary>
|
||||
[JsonProperty("media_serial3", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("media_serial3")]
|
||||
public string? MediaSerial3 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// PCB serial value
|
||||
/// </summary>
|
||||
[JsonProperty("pcb_serial", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("pcb_serial")]
|
||||
public string? PcbSerial { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Rom chip serial 1 value
|
||||
/// </summary>
|
||||
[JsonProperty("romchip_serial1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("romchip_serial1")]
|
||||
public string? RomChipSerial1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Rom chip serial 2 value
|
||||
/// </summary>
|
||||
[JsonProperty("romchip_serial2", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("romchip_serial2")]
|
||||
public string? RomChipSerial2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Lockout serial value
|
||||
/// </summary>
|
||||
[JsonProperty("lockout_serial", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("lockout_serial")]
|
||||
public string? LockoutSerial { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Save chip serial value
|
||||
/// </summary>
|
||||
[JsonProperty("savechip_serial", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("savechip_serial")]
|
||||
public string? SaveChipSerial { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Chip serial value
|
||||
/// </summary>
|
||||
[JsonProperty("chip_serial", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("chip_serial")]
|
||||
public string? ChipSerial { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Box serial value
|
||||
/// </summary>
|
||||
[JsonProperty("box_serial", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("box_serial")]
|
||||
public string? BoxSerial { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Media stamp value
|
||||
/// </summary>
|
||||
[JsonProperty("mediastamp", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("mediastamp")]
|
||||
public string? MediaStamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Box barcode value
|
||||
/// </summary>
|
||||
[JsonProperty("box_barcode", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("box_barcode")]
|
||||
public string? BoxBarcode { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Create a default, empty Serials object
|
||||
/// </summary>
|
||||
public Serials()
|
||||
{
|
||||
SetFieldValue(Data.Models.Metadata.DatItem.TypeKey, ItemType);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override object Clone()
|
||||
{
|
||||
var serials = new Serials()
|
||||
{
|
||||
DigitalSerial1 = this.DigitalSerial1,
|
||||
DigitalSerial2 = this.DigitalSerial2,
|
||||
MediaSerial1 = this.MediaSerial1,
|
||||
MediaSerial2 = this.MediaSerial2,
|
||||
MediaSerial3 = this.MediaSerial3,
|
||||
PcbSerial = this.PcbSerial,
|
||||
RomChipSerial1 = this.RomChipSerial1,
|
||||
RomChipSerial2 = this.RomChipSerial2,
|
||||
LockoutSerial = this.LockoutSerial,
|
||||
SaveChipSerial = this.SaveChipSerial,
|
||||
ChipSerial = this.ChipSerial,
|
||||
BoxSerial = this.BoxSerial,
|
||||
MediaStamp = this.MediaStamp,
|
||||
BoxBarcode = this.BoxBarcode,
|
||||
};
|
||||
serials.SetFieldValue(DupeTypeKey, GetFieldValue<DupeType>(DupeTypeKey));
|
||||
serials.SetFieldValue(MachineKey, GetMachine());
|
||||
serials.SetFieldValue(RemoveKey, GetBoolFieldValue(RemoveKey));
|
||||
serials.SetFieldValue<Source?>(SourceKey, GetFieldValue<Source?>(SourceKey));
|
||||
serials.SetFieldValue<string?>(Data.Models.Metadata.DatItem.TypeKey, GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey).AsItemType().AsStringValue());
|
||||
|
||||
return serials;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Comparision Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(DatItem? other)
|
||||
{
|
||||
// If we don't have a Serials, return false
|
||||
if (GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey) != other?.GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey))
|
||||
return false;
|
||||
|
||||
// Otherwise, treat it as a Serials
|
||||
Serials? newOther = other as Serials;
|
||||
|
||||
// If the Serials information matches
|
||||
return DigitalSerial1 == newOther!.DigitalSerial1
|
||||
&& DigitalSerial2 == newOther.DigitalSerial2
|
||||
&& MediaSerial1 == newOther.MediaSerial1
|
||||
&& MediaSerial2 == newOther.MediaSerial2
|
||||
&& MediaSerial3 == newOther.MediaSerial3
|
||||
&& PcbSerial == newOther.PcbSerial
|
||||
&& RomChipSerial1 == newOther.RomChipSerial1
|
||||
&& RomChipSerial2 == newOther.RomChipSerial2
|
||||
&& LockoutSerial == newOther.LockoutSerial
|
||||
&& SaveChipSerial == newOther.SaveChipSerial
|
||||
&& ChipSerial == newOther.ChipSerial
|
||||
&& BoxSerial == newOther.BoxSerial
|
||||
&& MediaStamp == newOther.MediaStamp
|
||||
&& BoxBarcode == newOther.BoxBarcode;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
33
SabreTools.Metadata.DatItems/Formats/SharedFeat.cs
Normal file
33
SabreTools.Metadata.DatItems/Formats/SharedFeat.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents one shared feature object
|
||||
/// </summary>
|
||||
[JsonObject("sharedfeat"), XmlRoot("sharedfeat")]
|
||||
public sealed class SharedFeat : DatItem<Data.Models.Metadata.SharedFeat>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.SharedFeat;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public SharedFeat() : base() { }
|
||||
|
||||
public SharedFeat(Data.Models.Metadata.SharedFeat item) : base(item) { }
|
||||
|
||||
public SharedFeat(Data.Models.Metadata.SharedFeat item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
73
SabreTools.Metadata.DatItems/Formats/Slot.cs
Normal file
73
SabreTools.Metadata.DatItems/Formats/Slot.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Data.Extensions;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents which Slot(s) is associated with a set
|
||||
/// </summary>
|
||||
[JsonObject("slot"), XmlRoot("slot")]
|
||||
public sealed class Slot : DatItem<Data.Models.Metadata.Slot>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Slot;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool SlotOptionsSpecified
|
||||
{
|
||||
get
|
||||
{
|
||||
var slotOptions = GetFieldValue<SlotOption[]?>(Data.Models.Metadata.Slot.SlotOptionKey);
|
||||
return slotOptions is not null && slotOptions.Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Slot() : base() { }
|
||||
|
||||
public Slot(Data.Models.Metadata.Slot item) : base(item)
|
||||
{
|
||||
// Handle subitems
|
||||
var slotOptions = item.ReadItemArray<Data.Models.Metadata.SlotOption>(Data.Models.Metadata.Slot.SlotOptionKey);
|
||||
if (slotOptions is not null)
|
||||
{
|
||||
SlotOption[] slotOptionItems = Array.ConvertAll(slotOptions, slotOption => new SlotOption(slotOption));
|
||||
SetFieldValue<SlotOption[]?>(Data.Models.Metadata.Slot.SlotOptionKey, slotOptionItems);
|
||||
}
|
||||
}
|
||||
|
||||
public Slot(Data.Models.Metadata.Slot item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Data.Models.Metadata.Slot GetInternalClone()
|
||||
{
|
||||
var slotItem = base.GetInternalClone();
|
||||
|
||||
var slotOptions = GetFieldValue<SlotOption[]?>(Data.Models.Metadata.Slot.SlotOptionKey);
|
||||
if (slotOptions is not null)
|
||||
{
|
||||
Data.Models.Metadata.SlotOption[] slotOptionItems = Array.ConvertAll(slotOptions, slotOption => slotOption.GetInternalClone());
|
||||
slotItem[Data.Models.Metadata.Slot.SlotOptionKey] = slotOptionItems;
|
||||
}
|
||||
|
||||
return slotItem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
39
SabreTools.Metadata.DatItems/Formats/SlotOption.cs
Normal file
39
SabreTools.Metadata.DatItems/Formats/SlotOption.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents one ListXML slotoption
|
||||
/// </summary>
|
||||
[JsonObject("slotoption"), XmlRoot("slotoption")]
|
||||
public sealed class SlotOption : DatItem<Data.Models.Metadata.SlotOption>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.SlotOption;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public SlotOption() : base() { }
|
||||
|
||||
public SlotOption(Data.Models.Metadata.SlotOption item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.SlotOption.DefaultKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.SlotOption.DefaultKey, GetBoolFieldValue(Data.Models.Metadata.SlotOption.DefaultKey).FromYesNo());
|
||||
}
|
||||
|
||||
public SlotOption(Data.Models.Metadata.SlotOption item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
41
SabreTools.Metadata.DatItems/Formats/SoftwareList.cs
Normal file
41
SabreTools.Metadata.DatItems/Formats/SoftwareList.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents which SoftwareList(s) is associated with a set
|
||||
/// </summary>
|
||||
[JsonObject("softwarelist"), XmlRoot("softwarelist")]
|
||||
public sealed class SoftwareList : DatItem<Data.Models.Metadata.SoftwareList>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.SoftwareList;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public SoftwareList() : base() { }
|
||||
|
||||
public SoftwareList(Data.Models.Metadata.SoftwareList item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetStringFieldValue(Data.Models.Metadata.SoftwareList.StatusKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.SoftwareList.StatusKey, GetStringFieldValue(Data.Models.Metadata.SoftwareList.StatusKey).AsSoftwareListStatus().AsStringValue());
|
||||
|
||||
// Handle subitems
|
||||
// TODO: Handle the Software subitem
|
||||
}
|
||||
|
||||
public SoftwareList(Data.Models.Metadata.SoftwareList item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
38
SabreTools.Metadata.DatItems/Formats/Sound.cs
Normal file
38
SabreTools.Metadata.DatItems/Formats/Sound.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the sound output for a machine
|
||||
/// </summary>
|
||||
[JsonObject("sound"), XmlRoot("sound")]
|
||||
public sealed class Sound : DatItem<Data.Models.Metadata.Sound>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.Sound;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Sound() : base() { }
|
||||
|
||||
public Sound(Data.Models.Metadata.Sound item) : base(item)
|
||||
{
|
||||
// Process flag values
|
||||
if (GetInt64FieldValue(Data.Models.Metadata.Sound.ChannelsKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Sound.ChannelsKey, GetInt64FieldValue(Data.Models.Metadata.Sound.ChannelsKey).ToString());
|
||||
}
|
||||
|
||||
public Sound(Data.Models.Metadata.Sound item, Machine machine, Source source) : this(item)
|
||||
{
|
||||
SetFieldValue<Source?>(SourceKey, source);
|
||||
CopyMachineInformation(machine);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
230
SabreTools.Metadata.DatItems/Formats/SourceDetails.cs
Normal file
230
SabreTools.Metadata.DatItems/Formats/SourceDetails.cs
Normal file
@@ -0,0 +1,230 @@
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
// TODO: Add item mappings for all fields
|
||||
namespace SabreTools.Metadata.DatItems.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single source details item
|
||||
/// </summary>
|
||||
[JsonObject("source_details"), XmlRoot("source_details")]
|
||||
public sealed class SourceDetails : DatItem
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <inheritdoc>/>
|
||||
protected override ItemType ItemType => ItemType.SourceDetails;
|
||||
|
||||
/// <summary>
|
||||
/// Id value
|
||||
/// </summary>
|
||||
/// <remarks>TODO: Is this required?</remarks>
|
||||
[JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("id")]
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Section value
|
||||
/// </summary>
|
||||
[JsonProperty("section", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("section")]
|
||||
public string? Section { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Rom info value
|
||||
/// </summary>
|
||||
[JsonProperty("rominfo", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("rominfo")]
|
||||
public string? RomInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Dumping date value
|
||||
/// </summary>
|
||||
[JsonProperty("d_date", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("d_date")]
|
||||
public string? DDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Dumping date info value
|
||||
/// </summary>
|
||||
[JsonProperty("d_date_info", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("d_date_info")]
|
||||
public string? DDateInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Release date value
|
||||
/// </summary>
|
||||
[JsonProperty("r_date", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("r_date")]
|
||||
public string? RDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Release date info value
|
||||
/// </summary>
|
||||
[JsonProperty("r_date_info", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("r_date_info")]
|
||||
public string? RDateInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Origin value
|
||||
/// </summary>
|
||||
[JsonProperty("origin", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("origin")]
|
||||
public string? Origin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Region value
|
||||
/// </summary>
|
||||
[JsonProperty("region", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("region")]
|
||||
public string? Region { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Media title value
|
||||
/// </summary>
|
||||
[JsonProperty("media_title", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("media_title")]
|
||||
public string? MediaTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Dumper value
|
||||
/// </summary>
|
||||
[JsonProperty("dumper", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("dumper")]
|
||||
public string? Dumper { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Project value
|
||||
/// </summary>
|
||||
[JsonProperty("project", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("project")]
|
||||
public string? Project { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Original format value
|
||||
/// </summary>
|
||||
[JsonProperty("originalformat", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("originalformat")]
|
||||
public string? OriginalFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Nodump value
|
||||
/// </summary>
|
||||
[JsonProperty("nodump", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("nodump")]
|
||||
public string? Nodump { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tool value
|
||||
/// </summary>
|
||||
[JsonProperty("tool", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("tool")]
|
||||
public string? Tool { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Comment 1 value
|
||||
/// </summary>
|
||||
[JsonProperty("comment1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("comment1")]
|
||||
public string? Comment1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Link 2 value
|
||||
/// </summary>
|
||||
[JsonProperty("comment2", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("comment2")]
|
||||
public string? Comment2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Link 1 value
|
||||
/// </summary>
|
||||
[JsonProperty("link1", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("link1")]
|
||||
public string? Link1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Link 2 value
|
||||
/// </summary>
|
||||
[JsonProperty("link2", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("link2")]
|
||||
public string? Link2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Link 3 value
|
||||
/// </summary>
|
||||
[JsonProperty("link3", DefaultValueHandling = DefaultValueHandling.Ignore), XmlElement("link3")]
|
||||
public string? Link3 { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Create a default, empty SourceDetails object
|
||||
/// </summary>
|
||||
public SourceDetails()
|
||||
{
|
||||
SetFieldValue(Data.Models.Metadata.DatItem.TypeKey, ItemType.SourceDetails);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override object Clone()
|
||||
{
|
||||
var sourceDetails = new SourceDetails()
|
||||
{
|
||||
Id = this.Id,
|
||||
Section = this.Section,
|
||||
RomInfo = this.RomInfo,
|
||||
DDate = this.DDate,
|
||||
DDateInfo = this.DDateInfo,
|
||||
RDate = this.RDate,
|
||||
RDateInfo = this.RDateInfo,
|
||||
Origin = this.Origin,
|
||||
Region = this.Region,
|
||||
MediaTitle = this.MediaTitle,
|
||||
Dumper = this.Dumper,
|
||||
Project = this.Project,
|
||||
OriginalFormat = this.OriginalFormat,
|
||||
Nodump = this.Nodump,
|
||||
Tool = this.Tool,
|
||||
Comment1 = this.Comment1,
|
||||
Comment2 = this.Comment2,
|
||||
Link1 = this.Link1,
|
||||
Link2 = this.Link2,
|
||||
Link3 = this.Link3,
|
||||
};
|
||||
sourceDetails.SetFieldValue(DupeTypeKey, GetFieldValue<DupeType>(DupeTypeKey));
|
||||
sourceDetails.SetFieldValue(MachineKey, GetMachine());
|
||||
sourceDetails.SetFieldValue(RemoveKey, GetBoolFieldValue(RemoveKey));
|
||||
sourceDetails.SetFieldValue<Source?>(SourceKey, GetFieldValue<Source?>(SourceKey));
|
||||
sourceDetails.SetFieldValue<string?>(Data.Models.Metadata.DatItem.TypeKey, GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey).AsItemType().AsStringValue());
|
||||
|
||||
return sourceDetails;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Comparision Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(DatItem? other)
|
||||
{
|
||||
// If we don't have a SourceDetails, return false
|
||||
if (GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey) != other?.GetStringFieldValue(Data.Models.Metadata.DatItem.TypeKey))
|
||||
return false;
|
||||
|
||||
// Otherwise, treat it as a SourceDetails
|
||||
SourceDetails? newOther = other as SourceDetails;
|
||||
|
||||
// If the Details information matches
|
||||
return Id == newOther!.Id
|
||||
&& Section == newOther.Section
|
||||
&& RomInfo == newOther.RomInfo
|
||||
&& DDate == newOther.DDate
|
||||
&& DDateInfo == newOther.DDateInfo
|
||||
&& RomInfo == newOther.RomInfo
|
||||
&& RDate == newOther.RDate
|
||||
&& RDateInfo == newOther.RDateInfo
|
||||
&& Origin == newOther.Origin
|
||||
&& Region == newOther.Region
|
||||
&& MediaTitle == newOther.MediaTitle
|
||||
&& Dumper == newOther.Dumper
|
||||
&& Project == newOther.Project
|
||||
&& OriginalFormat == newOther.OriginalFormat
|
||||
&& Nodump == newOther.Nodump
|
||||
&& Tool == newOther.Tool
|
||||
&& Comment1 == newOther.Comment1
|
||||
&& Comment2 == newOther.Comment2
|
||||
&& Link1 == newOther.Link1
|
||||
&& Link2 == newOther.Link2
|
||||
&& Link3 == newOther.Link3;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
156
SabreTools.Metadata.DatItems/Machine.cs
Normal file
156
SabreTools.Metadata.DatItems/Machine.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Data.Extensions;
|
||||
using SabreTools.Metadata.Filter;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the information specific to a set/game/machine
|
||||
/// </summary>
|
||||
[JsonObject("machine"), XmlRoot("machine")]
|
||||
public sealed class Machine : ModelBackedItem<Data.Models.Metadata.Machine>, ICloneable, IEquatable<Machine>
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public Machine()
|
||||
{
|
||||
_internal = [];
|
||||
}
|
||||
|
||||
public Machine(Data.Models.Metadata.Machine machine)
|
||||
{
|
||||
// Get all fields to automatically copy without processing
|
||||
var nonItemFields = TypeHelper.GetConstants(typeof(Data.Models.Metadata.Machine));
|
||||
if (nonItemFields is null)
|
||||
return;
|
||||
|
||||
// Populate the internal machine from non-filter fields
|
||||
_internal = [];
|
||||
foreach (string fieldName in nonItemFields)
|
||||
{
|
||||
if (machine.TryGetValue(fieldName, out var value))
|
||||
_internal[fieldName] = value;
|
||||
}
|
||||
|
||||
// Process flag values
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Machine.Im1CRCKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Machine.Im1CRCKey, TextHelper.NormalizeCRC32(GetStringFieldValue(Data.Models.Metadata.Machine.Im1CRCKey)));
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Machine.Im2CRCKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Machine.Im2CRCKey, TextHelper.NormalizeCRC32(GetStringFieldValue(Data.Models.Metadata.Machine.Im2CRCKey)));
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Machine.IsBiosKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Machine.IsBiosKey, GetBoolFieldValue(Data.Models.Metadata.Machine.IsBiosKey).FromYesNo());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Machine.IsDeviceKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Machine.IsDeviceKey, GetBoolFieldValue(Data.Models.Metadata.Machine.IsDeviceKey).FromYesNo());
|
||||
if (GetBoolFieldValue(Data.Models.Metadata.Machine.IsMechanicalKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Machine.IsMechanicalKey, GetBoolFieldValue(Data.Models.Metadata.Machine.IsMechanicalKey).FromYesNo());
|
||||
if (GetStringFieldValue(Data.Models.Metadata.Machine.SupportedKey) is not null)
|
||||
SetFieldValue<string?>(Data.Models.Metadata.Machine.SupportedKey, GetStringFieldValue(Data.Models.Metadata.Machine.SupportedKey).AsSupported().AsStringValue());
|
||||
|
||||
// Handle Trurip object, if it exists
|
||||
if (machine.ContainsKey(Data.Models.Metadata.Machine.TruripKey))
|
||||
{
|
||||
var truripItem = machine.Read<Data.Models.Logiqx.Trurip>(Data.Models.Metadata.Machine.TruripKey);
|
||||
if (truripItem is not null)
|
||||
SetFieldValue(Data.Models.Metadata.Machine.TruripKey, new Trurip(truripItem));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Accessors
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name to use for a Machine
|
||||
/// </summary>
|
||||
/// <returns>Name if available, null otherwise</returns>
|
||||
public string? GetName() => _internal.GetName();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the name to use for a Machine
|
||||
/// </summary>
|
||||
/// <param name="name">Name to set for the item</param>
|
||||
public void SetName(string? name) => _internal.SetName(name);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning methods
|
||||
|
||||
/// <summary>
|
||||
/// Create a clone of the current machine
|
||||
/// </summary>
|
||||
/// <returns>New machine with the same values as the current one</returns>
|
||||
public object Clone()
|
||||
{
|
||||
return new Machine()
|
||||
{
|
||||
_internal = _internal.Clone() as Data.Models.Metadata.Machine ?? [],
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a clone of the current internal model
|
||||
/// </summary>
|
||||
public Data.Models.Metadata.Machine GetInternalClone() => (_internal.Clone() as Data.Models.Metadata.Machine)!;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Comparision Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(ModelBackedItem? other)
|
||||
{
|
||||
// If other is null
|
||||
if (other is null)
|
||||
return false;
|
||||
|
||||
// If the type is mismatched
|
||||
if (other is not Machine otherItem)
|
||||
return false;
|
||||
|
||||
// Compare internal models
|
||||
return _internal.EqualTo(otherItem._internal);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(ModelBackedItem<Data.Models.Metadata.Machine>? other)
|
||||
{
|
||||
// If other is null
|
||||
if (other is null)
|
||||
return false;
|
||||
|
||||
// If the type is mismatched
|
||||
if (other is not Machine otherItem)
|
||||
return false;
|
||||
|
||||
// Compare internal models
|
||||
return _internal.EqualTo(otherItem._internal);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(Machine? other)
|
||||
{
|
||||
// If other is null
|
||||
if (other is null)
|
||||
return false;
|
||||
|
||||
// Compare internal models
|
||||
return _internal.EqualTo(other._internal);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Manipulation
|
||||
|
||||
/// <summary>
|
||||
/// Runs a filter and determines if it passes or not
|
||||
/// </summary>
|
||||
/// <param name="filterRunner">Filter runner to use for checking</param>
|
||||
/// <returns>True if the Machine passes the filter, false otherwise</returns>
|
||||
public bool PassesFilter(FilterRunner filterRunner) => filterRunner.Run(_internal);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>2.3.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
<Description>DatItem specific functionality for metadata file processing</Description>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2016-2026</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/SabreTools/SabreTools.Serialization</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>metadata dat datfile</PackageTags>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="README.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="[2.0.0]" />
|
||||
<PackageReference Include="SabreTools.IO" Version="[2.0.0]" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SabreTools.Data.Extensions\SabreTools.Data.Extensions.csproj" />
|
||||
<ProjectReference Include="..\SabreTools.Metadata\SabreTools.Metadata.csproj" />
|
||||
<ProjectReference Include="..\SabreTools.Metadata.Filter\SabreTools.Metadata.Filter.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
41
SabreTools.Metadata.DatItems/Source.cs
Normal file
41
SabreTools.Metadata.DatItems/Source.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
|
||||
#pragma warning disable IDE0290 // Use primary constructor
|
||||
namespace SabreTools.Metadata.DatItems
|
||||
{
|
||||
/// <summary>
|
||||
/// Source information wrapper
|
||||
/// </summary>
|
||||
public class Source : ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// Source index
|
||||
/// </summary>
|
||||
public readonly int Index;
|
||||
|
||||
/// <summary>
|
||||
/// Source name
|
||||
/// </summary>
|
||||
public readonly string? Name;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="id">Source ID</param>
|
||||
/// <param name="source">Source name, optional</param>
|
||||
public Source(int id, string? source = null)
|
||||
{
|
||||
Index = id;
|
||||
Name = source;
|
||||
}
|
||||
|
||||
#region Cloning
|
||||
|
||||
/// <summary>
|
||||
/// Clone the current object
|
||||
/// </summary>
|
||||
public object Clone() => new Source(Index, Name);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
146
SabreTools.Metadata.DatItems/Trurip.cs
Normal file
146
SabreTools.Metadata.DatItems/Trurip.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using SabreTools.Metadata.Tools;
|
||||
|
||||
namespace SabreTools.Metadata.DatItems
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents TruRip/EmuArc-specific values on a machine
|
||||
/// </summary>
|
||||
[JsonObject("trurip"), XmlRoot("trurip")]
|
||||
public sealed class Trurip : ICloneable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Title ID
|
||||
/// </summary>
|
||||
[JsonProperty("titleid", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
[XmlElement("titleid")]
|
||||
public string? TitleID { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Machine developer
|
||||
/// </summary>
|
||||
[JsonProperty("developer", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
[XmlElement("developer")]
|
||||
public string? Developer { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Game genre
|
||||
/// </summary>
|
||||
[JsonProperty("genre", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
[XmlElement("genre")]
|
||||
public string? Genre { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Game subgenre
|
||||
/// </summary>
|
||||
[JsonProperty("subgenre", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
[XmlElement("subgenre")]
|
||||
public string? Subgenre { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Game ratings
|
||||
/// </summary>
|
||||
[JsonProperty("ratings", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
[XmlElement("ratings")]
|
||||
public string? Ratings { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Game score
|
||||
/// </summary>
|
||||
[JsonProperty("score", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
[XmlElement("score")]
|
||||
public string? Score { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Is the machine enabled
|
||||
/// </summary>
|
||||
[JsonProperty("enabled", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
[XmlElement("enabled")]
|
||||
public string? Enabled { get; set; } = null; // bool?
|
||||
|
||||
/// <summary>
|
||||
/// Does the game have a CRC check
|
||||
/// </summary>
|
||||
[JsonProperty("hascrc", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
[XmlElement("hascrc")]
|
||||
public bool? Crc { get; set; } = null;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool CrcSpecified { get { return Crc is not null; } }
|
||||
|
||||
/// <summary>
|
||||
/// Machine relations
|
||||
/// </summary>
|
||||
[JsonProperty("relatedto", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
[XmlElement("relatedto")]
|
||||
public string? RelatedTo { get; set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Trurip() { }
|
||||
|
||||
public Trurip(Data.Models.Logiqx.Trurip trurip)
|
||||
{
|
||||
TitleID = trurip.TitleID;
|
||||
Developer = trurip.Developer;
|
||||
Genre = trurip.Genre;
|
||||
Subgenre = trurip.Subgenre;
|
||||
Ratings = trurip.Ratings;
|
||||
Score = trurip.Score;
|
||||
Enabled = trurip.Enabled;
|
||||
Crc = trurip.CRC.AsYesNo();
|
||||
RelatedTo = trurip.RelatedTo;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cloning methods
|
||||
|
||||
/// <summary>
|
||||
/// Create a clone of the current object
|
||||
/// </summary>
|
||||
/// <returns>New object with the same values as the current one</returns>
|
||||
public object Clone()
|
||||
{
|
||||
return new Trurip()
|
||||
{
|
||||
TitleID = this.TitleID,
|
||||
Developer = this.Developer,
|
||||
Genre = this.Genre,
|
||||
Subgenre = this.Subgenre,
|
||||
Ratings = this.Ratings,
|
||||
Score = this.Score,
|
||||
Enabled = this.Enabled,
|
||||
Crc = this.Crc,
|
||||
RelatedTo = this.RelatedTo,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert to the internal Logiqx model
|
||||
/// </summary>
|
||||
public Data.Models.Logiqx.Trurip ConvertToLogiqx()
|
||||
{
|
||||
return new Data.Models.Logiqx.Trurip()
|
||||
{
|
||||
TitleID = this.TitleID,
|
||||
Developer = this.Developer,
|
||||
Genre = this.Genre,
|
||||
Subgenre = this.Subgenre,
|
||||
Ratings = this.Ratings,
|
||||
Score = this.Score,
|
||||
Enabled = this.Enabled,
|
||||
CRC = this.Crc.FromYesNo(),
|
||||
RelatedTo = this.RelatedTo,
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user