2026-03-24 18:03:01 -04:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Xml.Serialization;
|
|
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
|
using SabreTools.Metadata.Filter;
|
2026-03-26 22:51:14 -04:00
|
|
|
|
using MergingFlag = SabreTools.Data.Models.Metadata.MergingFlag;
|
|
|
|
|
|
using NodumpFlag = SabreTools.Data.Models.Metadata.NodumpFlag;
|
|
|
|
|
|
using PackingFlag = SabreTools.Data.Models.Metadata.PackingFlag;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
|
|
|
|
|
|
namespace SabreTools.Metadata.DatFiles
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Represents all possible DAT header information
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[JsonObject("header"), XmlRoot("header")]
|
2026-04-05 01:19:46 -04:00
|
|
|
|
public sealed class DatHeader : ICloneable, IEquatable<DatHeader>
|
2026-03-24 18:03:01 -04:00
|
|
|
|
{
|
2026-04-04 16:07:37 -04:00
|
|
|
|
#region Properties
|
2026-03-24 18:03:01 -04:00
|
|
|
|
|
2026-04-02 22:01:42 -04:00
|
|
|
|
public string? Author
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Author;
|
|
|
|
|
|
set => _internal.Author = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 02:18:08 -04:00
|
|
|
|
public MergingFlag BiosMode
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.BiosMode;
|
|
|
|
|
|
set => _internal.BiosMode = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 22:01:42 -04:00
|
|
|
|
public string? Build
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Build;
|
|
|
|
|
|
set => _internal.Build = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 18:24:58 -04:00
|
|
|
|
public Data.Models.OfflineList.CanOpen? CanOpen
|
2026-03-24 18:03:01 -04:00
|
|
|
|
{
|
2026-04-04 18:24:58 -04:00
|
|
|
|
get => _internal.CanOpen;
|
|
|
|
|
|
set => _internal.CanOpen = value;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 18:24:58 -04:00
|
|
|
|
[JsonIgnore]
|
|
|
|
|
|
public bool CanOpenSpecified => CanOpen is not null;
|
|
|
|
|
|
|
2026-04-02 22:01:42 -04:00
|
|
|
|
public string? Category
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Category;
|
|
|
|
|
|
set => _internal.Category = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? Comment
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Comment;
|
|
|
|
|
|
set => _internal.Comment = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? Date
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Date;
|
|
|
|
|
|
set => _internal.Date = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 22:16:04 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Read or write format
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public DatFormat? DatFormat { get; set; }
|
|
|
|
|
|
|
2026-04-02 22:01:42 -04:00
|
|
|
|
public string? DatVersion
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.DatVersion;
|
|
|
|
|
|
set => _internal.DatVersion = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-01 21:59:16 -04:00
|
|
|
|
public bool? Debug
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Debug;
|
|
|
|
|
|
set => _internal.Debug = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 11:18:49 -04:00
|
|
|
|
public string? Description
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Description;
|
|
|
|
|
|
set => _internal.Description = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 22:01:42 -04:00
|
|
|
|
public string? Email
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Email;
|
|
|
|
|
|
set => _internal.Email = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? EmulatorVersion
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.EmulatorVersion;
|
|
|
|
|
|
set => _internal.EmulatorVersion = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 23:13:36 -04:00
|
|
|
|
public string? FileName
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.FileName;
|
|
|
|
|
|
set => _internal.FileName = value;
|
|
|
|
|
|
}
|
2026-04-02 22:17:39 -04:00
|
|
|
|
|
2026-04-02 02:18:08 -04:00
|
|
|
|
public MergingFlag ForceMerging
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.ForceMerging;
|
|
|
|
|
|
set => _internal.ForceMerging = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public NodumpFlag ForceNodump
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.ForceNodump;
|
|
|
|
|
|
set => _internal.ForceNodump = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public PackingFlag ForcePacking
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.ForcePacking;
|
|
|
|
|
|
set => _internal.ForcePacking = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-01 21:59:16 -04:00
|
|
|
|
public bool? ForceZipping
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.ForceZipping;
|
|
|
|
|
|
set => _internal.ForceZipping = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 17:58:09 -04:00
|
|
|
|
public string[]? HeaderRow
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.HeaderRow;
|
|
|
|
|
|
set => _internal.HeaderRow = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? HeaderSkipper
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.HeaderSkipper;
|
|
|
|
|
|
set => _internal.HeaderSkipper = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 22:01:42 -04:00
|
|
|
|
public string? Homepage
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Homepage;
|
|
|
|
|
|
set => _internal.Homepage = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? Id
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Id;
|
|
|
|
|
|
set => _internal.Id = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 18:24:58 -04:00
|
|
|
|
public Data.Models.OfflineList.Images? Images
|
2026-03-24 18:03:01 -04:00
|
|
|
|
{
|
2026-04-04 18:24:58 -04:00
|
|
|
|
get => _internal.Images;
|
|
|
|
|
|
set => _internal.Images = value;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[JsonIgnore]
|
2026-04-04 18:24:58 -04:00
|
|
|
|
public bool ImagesSpecified => Images is not null;
|
|
|
|
|
|
|
|
|
|
|
|
public string? ImFolder
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.ImFolder;
|
|
|
|
|
|
set => _internal.ImFolder = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Data.Models.OfflineList.Infos? Infos
|
2026-03-24 18:03:01 -04:00
|
|
|
|
{
|
2026-04-04 18:24:58 -04:00
|
|
|
|
get => _internal.Infos;
|
|
|
|
|
|
set => _internal.Infos = value;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 18:24:58 -04:00
|
|
|
|
[JsonIgnore]
|
|
|
|
|
|
public bool InfosSpecified => Infos is not null;
|
|
|
|
|
|
|
2026-04-01 21:59:16 -04:00
|
|
|
|
public bool? LockBiosMode
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.LockBiosMode;
|
|
|
|
|
|
set => _internal.LockBiosMode = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool? LockRomMode
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.LockRomMode;
|
|
|
|
|
|
set => _internal.LockRomMode = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool? LockSampleMode
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.LockSampleMode;
|
|
|
|
|
|
set => _internal.LockSampleMode = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 22:01:42 -04:00
|
|
|
|
public string? MameConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.MameConfig;
|
|
|
|
|
|
set => _internal.MameConfig = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 11:18:49 -04:00
|
|
|
|
public string? Name
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Name;
|
|
|
|
|
|
set => _internal.Name = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 18:24:58 -04:00
|
|
|
|
public Data.Models.OfflineList.NewDat? NewDat
|
2026-03-24 18:03:01 -04:00
|
|
|
|
{
|
2026-04-04 18:24:58 -04:00
|
|
|
|
get => _internal.NewDat;
|
|
|
|
|
|
set => _internal.NewDat = value;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 18:24:58 -04:00
|
|
|
|
[JsonIgnore]
|
|
|
|
|
|
public bool NewDatSpecified => NewDat is not null;
|
|
|
|
|
|
|
2026-04-02 22:01:42 -04:00
|
|
|
|
public string? Notes
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Notes;
|
|
|
|
|
|
set => _internal.Notes = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? Plugin
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Plugin;
|
|
|
|
|
|
set => _internal.Plugin = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? RefName
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.RefName;
|
|
|
|
|
|
set => _internal.RefName = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 02:18:08 -04:00
|
|
|
|
public MergingFlag RomMode
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.RomMode;
|
|
|
|
|
|
set => _internal.RomMode = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 22:01:42 -04:00
|
|
|
|
public string? RomTitle
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.RomTitle;
|
|
|
|
|
|
set => _internal.RomTitle = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? RootDir
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.RootDir;
|
|
|
|
|
|
set => _internal.RootDir = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 02:18:08 -04:00
|
|
|
|
public MergingFlag SampleMode
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.SampleMode;
|
|
|
|
|
|
set => _internal.SampleMode = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 18:46:35 -04:00
|
|
|
|
public string? SchemaLocation
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.SchemaLocation;
|
|
|
|
|
|
set => _internal.SchemaLocation = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 16:34:13 -04:00
|
|
|
|
public string? ScreenshotsHeight
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.ScreenshotsHeight;
|
|
|
|
|
|
set => _internal.ScreenshotsHeight = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? ScreenshotsWidth
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.ScreenshotsWidth;
|
|
|
|
|
|
set => _internal.ScreenshotsWidth = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 18:24:58 -04:00
|
|
|
|
public Data.Models.OfflineList.Search? Search
|
2026-03-24 18:03:01 -04:00
|
|
|
|
{
|
2026-04-04 18:24:58 -04:00
|
|
|
|
get => _internal.Search;
|
|
|
|
|
|
set => _internal.Search = value;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-04 18:24:58 -04:00
|
|
|
|
[JsonIgnore]
|
|
|
|
|
|
public bool SearchSpecified => Search is not null;
|
|
|
|
|
|
|
2026-04-02 22:01:42 -04:00
|
|
|
|
public string? System
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.System;
|
|
|
|
|
|
set => _internal.System = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? Timestamp
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Timestamp;
|
|
|
|
|
|
set => _internal.Timestamp = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? Type
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Type;
|
|
|
|
|
|
set => _internal.Type = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? Url
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Url;
|
|
|
|
|
|
set => _internal.Url = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string? Version
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _internal.Version;
|
|
|
|
|
|
set => _internal.Version = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-24 18:03:01 -04:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2026-04-05 01:19:46 -04:00
|
|
|
|
#region Private Fields
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Internal model
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private readonly Data.Models.Metadata.Header _internal;
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2026-03-24 18:03:01 -04:00
|
|
|
|
#region Constructors
|
|
|
|
|
|
|
2026-04-05 01:19:46 -04:00
|
|
|
|
public DatHeader()
|
|
|
|
|
|
{
|
|
|
|
|
|
_internal = new();
|
|
|
|
|
|
}
|
2026-03-24 18:03:01 -04:00
|
|
|
|
|
|
|
|
|
|
public DatHeader(Data.Models.Metadata.Header header)
|
|
|
|
|
|
{
|
2026-03-26 23:59:53 -04:00
|
|
|
|
_internal = header;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Cloning Methods
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Clone the current header
|
|
|
|
|
|
/// </summary>
|
2026-04-02 22:17:39 -04:00
|
|
|
|
public object Clone() => new DatHeader(GetInternalClone())
|
|
|
|
|
|
{
|
|
|
|
|
|
DatFormat = DatFormat,
|
|
|
|
|
|
};
|
2026-03-24 18:03:01 -04:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Clone just the format from the current header
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public DatHeader CloneFormat()
|
|
|
|
|
|
{
|
|
|
|
|
|
var header = new DatHeader();
|
|
|
|
|
|
|
2026-04-02 22:16:04 -04:00
|
|
|
|
header.DatFormat = DatFormat;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
|
|
|
|
|
|
return header;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Get a clone of the current internal model
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public Data.Models.Metadata.Header GetInternalClone()
|
|
|
|
|
|
{
|
2026-04-04 18:46:35 -04:00
|
|
|
|
var header = (_internal.Clone() as Data.Models.Metadata.Header)!;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
|
|
|
|
|
|
// Convert subheader values
|
|
|
|
|
|
if (CanOpenSpecified)
|
2026-04-04 18:24:58 -04:00
|
|
|
|
header.CanOpen = CanOpen;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
if (ImagesSpecified)
|
2026-04-04 18:24:58 -04:00
|
|
|
|
header.Images = Images;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
if (InfosSpecified)
|
2026-04-04 18:24:58 -04:00
|
|
|
|
header.Infos = Infos;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
if (NewDatSpecified)
|
2026-04-04 18:24:58 -04:00
|
|
|
|
header.NewDat = NewDat;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
if (SearchSpecified)
|
2026-04-04 18:24:58 -04:00
|
|
|
|
header.Search = Search;
|
2026-03-24 18:03:01 -04:00
|
|
|
|
|
|
|
|
|
|
return header;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Comparision Methods
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc/>
|
2026-04-05 01:08:41 -04:00
|
|
|
|
public bool Equals(DatHeader? other)
|
2026-03-24 18:03:01 -04:00
|
|
|
|
{
|
|
|
|
|
|
// If other is null
|
|
|
|
|
|
if (other is null)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
// Compare internal models
|
2026-04-05 01:08:41 -04:00
|
|
|
|
return _internal.Equals(other._internal);
|
2026-03-24 18:03:01 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|