Migrate DataArea, DiskArea, and Part to property-driven

This commit is contained in:
Matt Nadareski
2026-04-04 11:40:48 -04:00
parent 872fdc2a10
commit eb2f5babd9
20 changed files with 545 additions and 293 deletions

View File

@@ -165,6 +165,8 @@ namespace SabreTools.Data.Extensions
return confSetting.Clone() as ConfSetting;
else if (self is Control control)
return control.Clone() as Control;
else if (self is DataArea dataArea)
return dataArea.Clone() as DataArea;
else if (self is Device device)
return device.Clone() as Device;
else if (self is DeviceRef deviceRef)
@@ -177,15 +179,16 @@ namespace SabreTools.Data.Extensions
return dipValue.Clone() as DipValue;
else if (self is Disk disk)
return disk.Clone() as Disk;
else if (self is DiskArea diskArea)
return diskArea.Clone() as DiskArea;
else if (self is Display display)
return display.Clone() as Display;
else if (self is Driver driver)
return driver.Clone() as Driver;
else if (self is Extension extension)
return extension.Clone() as Extension;
// TODO: Reenable when PartFeature no longer needs nesting
// else if (self is Feature feature)
// return feature.Clone() as Feature;
else if (self is Feature feature)
return feature.Clone() as Feature;
else if (self is Info info)
return info.Clone() as Info;
else if (self is Input input)
@@ -196,6 +199,8 @@ namespace SabreTools.Data.Extensions
return media.Clone() as Media;
else if (self is Original original)
return original.Clone() as Original;
else if (self is Part part)
return part.Clone() as Part;
else if (self is Port port)
return port.Clone() as Port;
else if (self is RamOption ramOption)
@@ -204,6 +209,8 @@ namespace SabreTools.Data.Extensions
return release.Clone() as Release;
else if (self is ReleaseDetails releaseDetails)
return releaseDetails.Clone() as ReleaseDetails;
else if (self is Rom rom)
return rom.Clone() as Rom;
else if (self is Serials serials)
return serials.Clone() as Serials;
else if (self is SharedFeat sharedFeat)
@@ -226,22 +233,7 @@ namespace SabreTools.Data.Extensions
return null;
// Handle individual type properties
if (self is DataArea selfDataArea && clone is DataArea cloneDataArea)
{
cloneDataArea.Endianness = selfDataArea.Endianness;
cloneDataArea.Size = selfDataArea.Size;
cloneDataArea.Width = selfDataArea.Width;
}
else if (self is Feature selfFeature && clone is Feature cloneFeature)
{
// TODO: Remove when PartFeature no longer needs nesting
cloneFeature.FeatureType = selfFeature.FeatureType;
cloneFeature.Name = selfFeature.Name;
cloneFeature.Overall = selfFeature.Overall;
cloneFeature.Status = selfFeature.Status;
cloneFeature.Value = selfFeature.Value;
}
else if (self is Header selfHeader && clone is Header cloneHeader)
if (self is Header selfHeader && clone is Header cloneHeader)
{
cloneHeader.Author = selfHeader.Author;
cloneHeader.BiosMode = selfHeader.BiosMode;
@@ -329,25 +321,6 @@ namespace SabreTools.Data.Extensions
cloneMachine.Url = selfMachine.Url;
cloneMachine.Year = selfMachine.Year;
}
else if (self is Part selfPart && clone is Part clonePart)
{
clonePart.Interface = selfPart.Interface;
}
else if (self is Rom selfRom && clone is Rom cloneRom)
{
cloneRom.Dispose = selfRom.Dispose;
cloneRom.FileCount = selfRom.FileCount;
cloneRom.FileIsAvailable = selfRom.FileIsAvailable;
cloneRom.Inverted = selfRom.Inverted;
cloneRom.LoadFlag = selfRom.LoadFlag;
cloneRom.MIA = selfRom.MIA;
cloneRom.OpenMSXMediaType = selfRom.OpenMSXMediaType;
cloneRom.Optional = selfRom.Optional;
cloneRom.Size = selfRom.Size;
cloneRom.SoundOnly = selfRom.SoundOnly;
cloneRom.Status = selfRom.Status;
cloneRom.Value = selfRom.Value;
}
// Handle known properties
clone.SetName(self.GetName());

View File

@@ -1,10 +1,11 @@
using System;
using System.Xml.Serialization;
using Newtonsoft.Json;
namespace SabreTools.Data.Models.Metadata
{
[JsonObject("dataarea"), XmlRoot("dataarea")]
public class DataArea : DatItem
public class DataArea : DatItem, ICloneable, IEquatable<DataArea>
{
#region Properties
@@ -13,6 +14,8 @@ namespace SabreTools.Data.Models.Metadata
public string? Name { get; set; }
public Rom[]? Rom { get; set; }
public long? Size { get; set; }
/// <remarks>(8|16|32|64) "8"</remarks>
@@ -20,14 +23,49 @@ namespace SabreTools.Data.Models.Metadata
#endregion
#region Keys
/// <remarks>Rom[]</remarks>
[NoFilter]
public const string RomKey = "rom";
#endregion
public DataArea() => ItemType = ItemType.DataArea;
/// <inheritdoc/>
public object Clone()
{
var obj = new DataArea();
obj.Endianness = Endianness;
obj.Name = Name;
if (Rom is not null)
obj.Rom = Array.ConvertAll(Rom, i => (Rom)i.Clone());
obj.Size = Size;
obj.Width = Width;
return obj;
}
/// <inheritdoc/>
public bool Equals(DataArea? other)
{
// Null never matches
if (other is null)
return false;
// Properties
if (Endianness != other.Endianness)
return false;
if ((Name is null) ^ (other.Name is null))
return false;
else if (Name is not null && !Name.Equals(other.Name, StringComparison.OrdinalIgnoreCase))
return false;
if (Size != other.Size)
return false;
if (Width != other.Width)
return false;
// Sub-items
// TODO: Figure out how to properly check arrays
return true;
}
}
}

View File

@@ -1,25 +1,51 @@
using System;
using System.Xml.Serialization;
using Newtonsoft.Json;
namespace SabreTools.Data.Models.Metadata
{
[JsonObject("diskarea"), XmlRoot("diskarea")]
public class DiskArea : DatItem
public class DiskArea : DatItem, ICloneable, IEquatable<DiskArea>
{
#region Properties
public Disk[]? Disk { get; set; }
public string? Name { get; set; }
#endregion
#region Keys
/// <remarks>Disk[]</remarks>
[NoFilter]
public const string DiskKey = "disk";
#endregion
public DiskArea() => ItemType = ItemType.DiskArea;
/// <inheritdoc/>
public object Clone()
{
var obj = new DiskArea();
if (Disk is not null)
obj.Disk = Array.ConvertAll(Disk, i => (Disk)i.Clone());
obj.Name = Name;
return obj;
}
/// <inheritdoc/>
public bool Equals(DiskArea? other)
{
// Null never matches
if (other is null)
return false;
// Properties
if ((Name is null) ^ (other.Name is null))
return false;
else if (Name is not null && !Name.Equals(other.Name, StringComparison.OrdinalIgnoreCase))
return false;
// Sub-items
// TODO: Figure out how to properly check arrays
return true;
}
}
}

View File

@@ -1,39 +1,71 @@
using System;
using System.Xml.Serialization;
using Newtonsoft.Json;
namespace SabreTools.Data.Models.Metadata
{
[JsonObject("part"), XmlRoot("part")]
public class Part : DatItem
public class Part : DatItem, ICloneable, IEquatable<Part>
{
#region Properties
public DataArea[]? DataArea { get; set; }
public DiskArea[]? DiskArea { get; set; }
public DipSwitch[]? DipSwitch { get; set; }
public Feature[]? Feature { get; set; }
public string? Interface { get; set; }
public string? Name { get; set; }
#endregion
#region Keys
/// <remarks>DataArea[]</remarks>
[NoFilter]
public const string DataAreaKey = "dataarea";
/// <remarks>DiskArea[]</remarks>
[NoFilter]
public const string DiskAreaKey = "diskarea";
/// <remarks>DipSwitch[]</remarks>
[NoFilter]
public const string DipSwitchKey = "dipswitch";
/// <remarks>Feature[]</remarks>
[NoFilter]
public const string FeatureKey = "feature";
#endregion
public Part() => ItemType = ItemType.Part;
/// <inheritdoc/>
public object Clone()
{
var obj = new Part();
if (DataArea is not null)
obj.DataArea = Array.ConvertAll(DataArea, i => (DataArea)i.Clone());
if (DiskArea is not null)
obj.DiskArea = Array.ConvertAll(DiskArea, i => (DiskArea)i.Clone());
if (DipSwitch is not null)
obj.DipSwitch = Array.ConvertAll(DipSwitch, i => (DipSwitch)i.Clone());
if (Feature is not null)
obj.Feature = Array.ConvertAll(Feature, i => (Feature)i.Clone());
obj.Interface = Interface;
obj.Name = Name;
return obj;
}
/// <inheritdoc/>
public bool Equals(Part? other)
{
// Null never matches
if (other is null)
return false;
// Properties
if ((Interface is null) ^ (other.Interface is null))
return false;
else if (Interface is not null && !Interface.Equals(other.Interface, StringComparison.OrdinalIgnoreCase))
return false;
if ((Name is null) ^ (other.Name is null))
return false;
else if (Name is not null && !Name.Equals(other.Name, StringComparison.OrdinalIgnoreCase))
return false;
// Sub-items
// TODO: Figure out how to properly check arrays
return true;
}
}
}

View File

@@ -1,10 +1,12 @@
using System;
using System.Xml.Serialization;
using Newtonsoft.Json;
namespace SabreTools.Data.Models.Metadata
{
// TODO: IEquatable<Rom>
[JsonObject("rom"), XmlRoot("rom")]
public class Rom : DatItem
public class Rom : DatItem, ICloneable
{
#region Properties
@@ -300,5 +302,195 @@ namespace SabreTools.Data.Models.Metadata
#endregion
public Rom() => ItemType = ItemType.Rom;
/// <inheritdoc/>
public object Clone()
{
var obj = new Rom();
obj.Dispose = Dispose;
obj.FileCount = FileCount;
obj.FileIsAvailable = FileIsAvailable;
obj.Inverted = Inverted;
obj.LoadFlag = LoadFlag;
obj.MIA = MIA;
obj.Name = Name;
obj.OpenMSXMediaType = OpenMSXMediaType;
obj.Optional = Optional;
obj.Size = Size;
obj.SoundOnly = SoundOnly;
obj.Status = Status;
obj.Value = Value;
// TODO: Replace these when moving away from keys
if (TryGetValue(AlbumKey, out var Album))
obj[AlbumKey] = Album;
if (TryGetValue(AltRomnameKey, out var AltRomname))
obj[AltRomnameKey] = AltRomname;
if (TryGetValue(AltTitleKey, out var AltTitle))
obj[AltTitleKey] = AltTitle;
if (TryGetValue(ArtistKey, out var Artist))
obj[ArtistKey] = Artist;
if (TryGetValue(ASRDetectedLangKey, out var ASRDetectedLang))
obj[ASRDetectedLangKey] = ASRDetectedLang;
if (TryGetValue(ASRDetectedLangConfKey, out var ASRDetectedLangConf))
obj[ASRDetectedLangConfKey] = ASRDetectedLangConf;
if (TryGetValue(ASRTranscribedLangKey, out var ASRTranscribedLang))
obj[ASRTranscribedLangKey] = ASRTranscribedLang;
if (TryGetValue(BiosKey, out var Bios))
obj[BiosKey] = Bios;
if (TryGetValue(BitrateKey, out var Bitrate))
obj[BitrateKey] = Bitrate;
if (TryGetValue(BitTorrentMagnetHashKey, out var BitTorrentMagnetHash))
obj[BitTorrentMagnetHashKey] = BitTorrentMagnetHash;
if (TryGetValue(ClothCoverDetectionModuleVersionKey, out var ClothCoverDetectionModuleVersion))
obj[ClothCoverDetectionModuleVersionKey] = ClothCoverDetectionModuleVersion;
if (TryGetValue(CollectionCatalogNumberKey, out var CollectionCatalogNumber))
obj[CollectionCatalogNumberKey] = CollectionCatalogNumber;
if (TryGetValue(CommentKey, out var Comment))
obj[CommentKey] = Comment;
if (TryGetValue(CRCKey, out var CRC))
obj[CRCKey] = CRC;
if (TryGetValue(CRC16Key, out var CRC16))
obj[CRC16Key] = CRC16;
if (TryGetValue(CRC64Key, out var CRC64))
obj[CRC64Key] = CRC64;
if (TryGetValue(CreatorKey, out var Creator))
obj[CreatorKey] = Creator;
if (TryGetValue(DateKey, out var Date))
obj[DateKey] = Date;
if (TryGetValue(ExtensionKey, out var Extension))
obj[ExtensionKey] = Extension;
if (TryGetValue(FlagsKey, out var Flags))
obj[FlagsKey] = Flags;
if (TryGetValue(FormatKey, out var Format))
obj[FormatKey] = Format;
if (TryGetValue(HeaderKey, out var Header))
obj[HeaderKey] = Header;
if (TryGetValue(HeightKey, out var Height))
obj[HeightKey] = Height;
if (TryGetValue(hOCRCharToWordhOCRVersionKey, out var hOCRCharToWordhOCRVersion))
obj[hOCRCharToWordhOCRVersionKey] = hOCRCharToWordhOCRVersion;
if (TryGetValue(hOCRCharToWordModuleVersionKey, out var hOCRCharToWordModuleVersion))
obj[hOCRCharToWordModuleVersionKey] = hOCRCharToWordModuleVersion;
if (TryGetValue(hOCRFtsTexthOCRVersionKey, out var hOCRFtsTexthOCRVersion))
obj[hOCRFtsTexthOCRVersionKey] = hOCRFtsTexthOCRVersion;
if (TryGetValue(hOCRFtsTextModuleVersionKey, out var hOCRFtsTextModuleVersion))
obj[hOCRFtsTextModuleVersionKey] = hOCRFtsTextModuleVersion;
if (TryGetValue(hOCRPageIndexhOCRVersionKey, out var hOCRPageIndexhOCRVersion))
obj[hOCRPageIndexhOCRVersionKey] = hOCRPageIndexhOCRVersion;
if (TryGetValue(hOCRPageIndexModuleVersionKey, out var hOCRPageIndexModuleVersion))
obj[hOCRPageIndexModuleVersionKey] = hOCRPageIndexModuleVersion;
if (TryGetValue(LastModifiedTimeKey, out var LastModifiedTime))
obj[LastModifiedTimeKey] = LastModifiedTime;
if (TryGetValue(LengthKey, out var Length))
obj[LengthKey] = Length;
if (TryGetValue(MatrixNumberKey, out var MatrixNumber))
obj[MatrixNumberKey] = MatrixNumber;
if (TryGetValue(MD2Key, out var MD2))
obj[MD2Key] = MD2;
if (TryGetValue(MD4Key, out var MD4))
obj[MD4Key] = MD4;
if (TryGetValue(MD5Key, out var MD5))
obj[MD5Key] = MD5;
if (TryGetValue(MergeKey, out var Merge))
obj[MergeKey] = Merge;
if (TryGetValue(TesseractOCRKey, out var TesseractOCR))
obj[TesseractOCRKey] = TesseractOCR;
if (TryGetValue(TesseractOCRConvertedKey, out var TesseractOCRConverted))
obj[TesseractOCRConvertedKey] = TesseractOCRConverted;
if (TryGetValue(TesseractOCRDetectedLangKey, out var TesseractOCRDetectedLang))
obj[TesseractOCRDetectedLangKey] = TesseractOCRDetectedLang;
if (TryGetValue(TesseractOCRDetectedLangConfKey, out var TesseractOCRDetectedLangConf))
obj[TesseractOCRDetectedLangConfKey] = TesseractOCRDetectedLangConf;
if (TryGetValue(TesseractOCRDetectedScriptKey, out var TesseractOCRDetectedScript))
obj[TesseractOCRDetectedScriptKey] = TesseractOCRDetectedScript;
if (TryGetValue(TesseractOCRDetectedScriptConfKey, out var TesseractOCRDetectedScriptConf))
obj[TesseractOCRDetectedScriptConfKey] = TesseractOCRDetectedScriptConf;
if (TryGetValue(TesseractOCRModuleVersionKey, out var TesseractOCRModuleVersion))
obj[TesseractOCRModuleVersionKey] = TesseractOCRModuleVersion;
if (TryGetValue(TesseractOCRParametersKey, out var TesseractOCRParameters))
obj[TesseractOCRParametersKey] = TesseractOCRParameters;
if (TryGetValue(OffsetKey, out var Offset))
obj[OffsetKey] = Offset;
if (TryGetValue(OriginalKey, out var Original))
obj[OriginalKey] = Original;
if (TryGetValue(PDFModuleVersionKey, out var PDFModuleVersion))
obj[PDFModuleVersionKey] = PDFModuleVersion;
if (TryGetValue(PreviewImageKey, out var PreviewImage))
obj[PreviewImageKey] = PreviewImage;
if (TryGetValue(PublisherKey, out var Publisher))
obj[PublisherKey] = Publisher;
if (TryGetValue(RegionKey, out var Region))
obj[RegionKey] = Region;
if (TryGetValue(RemarkKey, out var Remark))
obj[RemarkKey] = Remark;
if (TryGetValue(RIPEMD128Key, out var RIPEMD128))
obj[RIPEMD128Key] = RIPEMD128;
if (TryGetValue(RIPEMD160Key, out var RIPEMD160))
obj[RIPEMD160Key] = RIPEMD160;
if (TryGetValue(RotationKey, out var Rotation))
obj[RotationKey] = Rotation;
if (TryGetValue(SerialKey, out var Serial))
obj[SerialKey] = Serial;
if (TryGetValue(SHA1Key, out var SHA1))
obj[SHA1Key] = SHA1;
if (TryGetValue(SHA256Key, out var SHA256))
obj[SHA256Key] = SHA256;
if (TryGetValue(SHA384Key, out var SHA384))
obj[SHA384Key] = SHA384;
if (TryGetValue(SHA512Key, out var SHA512))
obj[SHA512Key] = SHA512;
if (TryGetValue(SourceKey, out var Source))
obj[SourceKey] = Source;
if (TryGetValue(SpamSumKey, out var SpamSum))
obj[SpamSumKey] = SpamSum;
if (TryGetValue(StartKey, out var Start))
obj[StartKey] = Start;
if (TryGetValue(SummationKey, out var Summation))
obj[SummationKey] = Summation;
if (TryGetValue(TitleKey, out var Title))
obj[TitleKey] = Title;
if (TryGetValue(TrackKey, out var Track))
obj[TrackKey] = Track;
if (TryGetValue(OpenMSXType, out var OpenMSXTypeValue))
obj[OpenMSXType] = OpenMSXTypeValue;
if (TryGetValue(WhisperASRModuleVersionKey, out var WhisperASRModuleVersion))
obj[WhisperASRModuleVersionKey] = WhisperASRModuleVersion;
if (TryGetValue(WhisperModelHashKey, out var WhisperModelHash))
obj[WhisperModelHashKey] = WhisperModelHash;
if (TryGetValue(WhisperModelNameKey, out var WhisperModelName))
obj[WhisperModelNameKey] = WhisperModelName;
if (TryGetValue(WhisperVersionKey, out var WhisperVersion))
obj[WhisperVersionKey] = WhisperVersion;
if (TryGetValue(WidthKey, out var Width))
obj[WidthKey] = Width;
if (TryGetValue(WordConfidenceInterval0To10Key, out var WordConfidenceInterval0To10))
obj[WordConfidenceInterval0To10Key] = WordConfidenceInterval0To10;
if (TryGetValue(WordConfidenceInterval11To20Key, out var WordConfidenceInterval11To20))
obj[WordConfidenceInterval11To20Key] = WordConfidenceInterval11To20;
if (TryGetValue(WordConfidenceInterval21To30Key, out var WordConfidenceInterval21To30))
obj[WordConfidenceInterval21To30Key] = WordConfidenceInterval21To30;
if (TryGetValue(WordConfidenceInterval31To40Key, out var WordConfidenceInterval31To40))
obj[WordConfidenceInterval31To40Key] = WordConfidenceInterval31To40;
if (TryGetValue(WordConfidenceInterval41To50Key, out var WordConfidenceInterval41To50))
obj[WordConfidenceInterval41To50Key] = WordConfidenceInterval41To50;
if (TryGetValue(WordConfidenceInterval51To60Key, out var WordConfidenceInterval51To60))
obj[WordConfidenceInterval51To60Key] = WordConfidenceInterval51To60;
if (TryGetValue(WordConfidenceInterval61To70Key, out var WordConfidenceInterval61To70))
obj[WordConfidenceInterval61To70Key] = WordConfidenceInterval61To70;
if (TryGetValue(WordConfidenceInterval71To80Key, out var WordConfidenceInterval71To80))
obj[WordConfidenceInterval71To80Key] = WordConfidenceInterval71To80;
if (TryGetValue(WordConfidenceInterval81To90Key, out var WordConfidenceInterval81To90))
obj[WordConfidenceInterval81To90Key] = WordConfidenceInterval81To90;
if (TryGetValue(WordConfidenceInterval91To100Key, out var WordConfidenceInterval91To100))
obj[WordConfidenceInterval91To100Key] = WordConfidenceInterval91To100;
if (TryGetValue(xxHash364Key, out var xxHash364))
obj[xxHash364Key] = xxHash364;
if (TryGetValue(xxHash3128Key, out var xxHash3128))
obj[xxHash3128Key] = xxHash3128;
return obj;
}
}
}

View File

@@ -142,9 +142,9 @@ namespace SabreTools.Metadata.DatFiles.Test
// All other fields are tested separately
Rom? partRom = Array.Find(datItems, item => item is Rom rom && rom.DataAreaSpecified && rom.PartSpecified) as Rom;
Assert.NotNull(partRom);
DataArea? romDataArea = partRom.Read<DataArea>(Rom.DataAreaKey);
DataArea? romDataArea = partRom.DataArea;
ValidateDataArea(romDataArea);
Part? romPart = partRom.Read<Part>(Rom.PartKey);
Part? romPart = partRom.Part;
ValidatePart(romPart);
Port? port = Array.Find(datItems, item => item is Port) as Port;
@@ -539,7 +539,7 @@ namespace SabreTools.Metadata.DatFiles.Test
{
Endianness = Data.Models.Metadata.Endianness.Big,
Name = "name",
[Data.Models.Metadata.DataArea.RomKey] = new Data.Models.Metadata.Rom[] { [] },
Rom = [[]],
Size = 12345,
Width = Data.Models.Metadata.Width.Long,
};
@@ -565,7 +565,7 @@ namespace SabreTools.Metadata.DatFiles.Test
{
return new Data.Models.Metadata.DiskArea
{
[Data.Models.Metadata.DiskArea.DiskKey] = new Data.Models.Metadata.Disk[] { [] },
Disk = [[]],
Name = "name",
};
}
@@ -704,10 +704,10 @@ namespace SabreTools.Metadata.DatFiles.Test
{
return new Data.Models.Metadata.Part
{
[Data.Models.Metadata.Part.DataAreaKey] = new Data.Models.Metadata.DataArea[] { CreateMetadataDataArea() },
[Data.Models.Metadata.Part.DiskAreaKey] = new Data.Models.Metadata.DiskArea[] { CreateMetadataDiskArea() },
[Data.Models.Metadata.Part.DipSwitchKey] = new Data.Models.Metadata.DipSwitch[] { [] },
[Data.Models.Metadata.Part.FeatureKey] = new Data.Models.Metadata.Feature[] { CreateMetadataFeature() },
DataArea = [CreateMetadataDataArea()],
DiskArea = [CreateMetadataDiskArea()],
DipSwitch = [[]],
Feature = [CreateMetadataFeature()],
Interface = "interface",
Name = "name",
};
@@ -1432,7 +1432,7 @@ namespace SabreTools.Metadata.DatFiles.Test
Assert.Equal(Data.Models.Metadata.FeatureType.Protection, partFeature.FeatureType);
Assert.Equal("value", partFeature.Value);
Part? part = partFeature.Read<Part>(PartFeature.PartKey);
Part? part = partFeature.Part;
ValidatePart(part);
}

View File

@@ -261,7 +261,7 @@ namespace SabreTools.Metadata.DatFiles.Test
{
PartFeature item = new PartFeature(CreateMetadataFeature());
item.CopyMachineInformation(machine);
item.Write(PartFeature.PartKey, CreatePart(machine));
item.Part = CreatePart(machine);
return item;
}
@@ -298,8 +298,8 @@ namespace SabreTools.Metadata.DatFiles.Test
{
Rom item = new Rom(CreateMetadataRom());
item.CopyMachineInformation(machine);
item.Write(Rom.DataAreaKey, CreateDataArea(machine));
item.Write(Rom.PartKey, CreatePart(machine));
item.DataArea = CreateDataArea(machine);
item.Part = CreatePart(machine);
return item;
}
@@ -761,7 +761,7 @@ namespace SabreTools.Metadata.DatFiles.Test
Assert.Equal(12345, dataArea.Size);
Assert.Equal(Data.Models.Metadata.Width.Long, dataArea.Width);
Data.Models.Metadata.Rom[]? roms = dataArea.ReadArray<Data.Models.Metadata.Rom>(Data.Models.Metadata.DataArea.RomKey);
Data.Models.Metadata.Rom[]? roms = dataArea.Rom;
Assert.NotNull(roms);
Data.Models.Metadata.Rom? rom = Assert.Single(roms);
ValidateMetadataRom(rom);
@@ -853,7 +853,7 @@ namespace SabreTools.Metadata.DatFiles.Test
Assert.NotNull(diskArea);
Assert.Equal("name", diskArea.Name);
Data.Models.Metadata.Disk[]? disks = diskArea.ReadArray<Data.Models.Metadata.Disk>(Data.Models.Metadata.DiskArea.DiskKey);
Data.Models.Metadata.Disk[]? disks = diskArea.Disk;
Assert.NotNull(disks);
Data.Models.Metadata.Disk? disk = Assert.Single(disks);
ValidateMetadataDisk(disk);
@@ -959,22 +959,22 @@ namespace SabreTools.Metadata.DatFiles.Test
Assert.Equal("interface", part.Interface);
Assert.Equal("name", part.Name);
Data.Models.Metadata.DataArea[]? dataAreas = part.ReadArray<Data.Models.Metadata.DataArea>(Data.Models.Metadata.Part.DataAreaKey);
Data.Models.Metadata.DataArea[]? dataAreas = part.DataArea;
Assert.NotNull(dataAreas);
Data.Models.Metadata.DataArea? dataArea = Assert.Single(dataAreas);
ValidateMetadataDataArea(dataArea);
Data.Models.Metadata.DiskArea[]? diskAreas = part.ReadArray<Data.Models.Metadata.DiskArea>(Data.Models.Metadata.Part.DiskAreaKey);
Data.Models.Metadata.DiskArea[]? diskAreas = part.DiskArea;
Assert.NotNull(diskAreas);
Data.Models.Metadata.DiskArea? diskArea = Assert.Single(diskAreas);
ValidateMetadataDiskArea(diskArea);
Data.Models.Metadata.DipSwitch[]? dipSwitches = part.ReadArray<Data.Models.Metadata.DipSwitch>(Data.Models.Metadata.Part.DipSwitchKey);
Data.Models.Metadata.DipSwitch[]? dipSwitches = part.DipSwitch;
Assert.NotNull(dipSwitches);
Data.Models.Metadata.DipSwitch? dipSwitch = Assert.Single(dipSwitches);
ValidateMetadataDipSwitch(dipSwitch);
Data.Models.Metadata.Feature[]? features = part.ReadArray<Data.Models.Metadata.Feature>(Data.Models.Metadata.Part.FeatureKey);
Data.Models.Metadata.Feature[]? features = part.Feature;
Assert.NotNull(features);
Data.Models.Metadata.Feature? feature = Assert.Single(features);
ValidateMetadataFeature(feature);

View File

@@ -589,13 +589,13 @@ namespace SabreTools.Metadata.DatFiles
var partItem = new Part(item, machine, source);
// Handle subitems
var dataAreas = item.ReadArray<Data.Models.Metadata.DataArea>(Data.Models.Metadata.Part.DataAreaKey);
var dataAreas = item.DataArea;
if (dataAreas is not null)
{
foreach (var dataArea in dataAreas)
{
var dataAreaItem = new DataArea(dataArea, machine, source);
var roms = dataArea.ReadArray<Data.Models.Metadata.Rom>(Data.Models.Metadata.DataArea.RomKey);
var roms = dataArea.Rom;
if (roms is null)
continue;
@@ -623,8 +623,8 @@ namespace SabreTools.Metadata.DatFiles
continue;
}
romItem.Write<DataArea?>(Rom.DataAreaKey, dataAreaItem);
romItem.Write<Part?>(Rom.PartKey, partItem);
romItem.DataArea = dataAreaItem;
romItem.Part = partItem;
addRoms.Add(romItem);
}
@@ -638,13 +638,13 @@ namespace SabreTools.Metadata.DatFiles
}
}
var diskAreas = item.ReadArray<Data.Models.Metadata.DiskArea>(Data.Models.Metadata.Part.DiskAreaKey);
var diskAreas = item.DiskArea;
if (diskAreas is not null)
{
foreach (var diskArea in diskAreas)
{
var diskAreaitem = new DiskArea(diskArea, machine, source);
var disks = diskArea.ReadArray<Data.Models.Metadata.Disk>(Data.Models.Metadata.DiskArea.DiskKey);
var disks = diskArea.Disk;
if (disks is null)
continue;
@@ -666,7 +666,7 @@ namespace SabreTools.Metadata.DatFiles
}
}
var dipSwitches = item.ReadArray<Data.Models.Metadata.DipSwitch>(Data.Models.Metadata.Part.DipSwitchKey);
var dipSwitches = item.DipSwitch;
if (dipSwitches is not null)
{
foreach (var dipSwitch in dipSwitches)
@@ -682,7 +682,7 @@ namespace SabreTools.Metadata.DatFiles
}
}
var partFeatures = item.ReadArray<Data.Models.Metadata.Feature>(Data.Models.Metadata.Part.FeatureKey);
var partFeatures = item.Feature;
if (partFeatures is not null)
{
foreach (var partFeature in partFeatures)
@@ -691,9 +691,11 @@ namespace SabreTools.Metadata.DatFiles
if (filterRunner is not null && !filterRunner.Run(partFeature))
continue;
var partFeatureItem = new PartFeature(partFeature);
partFeatureItem.Write<Part?>(PartFeature.PartKey, partItem);
partFeatureItem.Source = source;
var partFeatureItem = new PartFeature(partFeature)
{
Part = partItem,
Source = source,
};
partFeatureItem.CopyMachineInformation(machine);
AddItem(partFeatureItem, statsOnly);

View File

@@ -164,20 +164,11 @@ namespace SabreTools.Metadata.DatFiles
AppendToMachineKey(machine, Data.Models.Metadata.Machine.DiskKey, diskItem);
// Add Part and DiskArea mappings
bool diskContainsPart = disk.Part is not null;
bool diskContainsDiskArea = disk.DiskArea is not null;
if (diskContainsPart && diskContainsDiskArea)
if (disk.Part is not null && disk.DiskArea is not null)
{
var partItem = disk.Part;
if (partItem is not null)
{
var partItemInternal = partItem.GetInternalClone();
partMappings[partItemInternal] = diskItem;
var diskAreaItem = disk.DiskArea;
if (diskAreaItem is not null)
diskAreaMappings[partItemInternal] = (diskAreaItem.GetInternalClone(), diskItem);
}
var partItemInternal = disk.Part.GetInternalClone();
partMappings[partItemInternal] = diskItem;
diskAreaMappings[partItemInternal] = (disk.DiskArea.GetInternalClone(), diskItem);
}
break;
@@ -217,13 +208,8 @@ namespace SabreTools.Metadata.DatFiles
AppendToMachineKey(machine, Data.Models.Metadata.Machine.FeatureKey, partFeatureItem);
// Add Part mapping
bool partFeatureContainsPart = partFeatureItem.ContainsKey(DatItems.Formats.PartFeature.PartKey);
if (partFeatureContainsPart)
{
var partItem = partFeatureItem.Read<DatItems.Formats.Part>(DatItems.Formats.PartFeature.PartKey);
if (partItem is not null)
partMappings[partItem.GetInternalClone()] = partFeatureItem;
}
if (partFeature.Part is not null)
partMappings[partFeature.Part.GetInternalClone()] = partFeatureItem;
break;
case DatItems.Formats.Port port:
@@ -247,20 +233,11 @@ namespace SabreTools.Metadata.DatFiles
AppendToMachineKey(machine, Data.Models.Metadata.Machine.RomKey, romItem);
// Add Part and DataArea mappings
bool romContainsPart = romItem.ContainsKey(DatItems.Formats.Rom.PartKey);
bool romContainsDataArea = romItem.ContainsKey(DatItems.Formats.Rom.DataAreaKey);
if (romContainsPart && romContainsDataArea)
if (rom.Part is not null && rom.DataArea is not null)
{
var partItem = romItem.Read<DatItems.Formats.Part>(DatItems.Formats.Rom.PartKey);
if (partItem is not null)
{
var partItemInternal = partItem.GetInternalClone();
partMappings[partItemInternal] = romItem;
var dataAreaItem = romItem.Read<DatItems.Formats.DataArea>(DatItems.Formats.Rom.DataAreaKey);
if (dataAreaItem is not null)
dataAreaMappings[partItemInternal] = (dataAreaItem.GetInternalClone(), romItem);
}
var partItemInternal = rom.Part.GetInternalClone();
partMappings[partItemInternal] = romItem;
dataAreaMappings[partItemInternal] = (rom.DataArea.GetInternalClone(), romItem);
}
break;
@@ -339,7 +316,7 @@ namespace SabreTools.Metadata.DatFiles
if (dataAreaName is not null)
{
// Get existing data areas as a list
var dataAreasArr = partItems[partName].Read<Data.Models.Metadata.DataArea[]>(Data.Models.Metadata.Part.DataAreaKey) ?? [];
var dataAreasArr = partItems[partName].DataArea ?? [];
List<Data.Models.Metadata.DataArea> dataAreas = [.. dataAreasArr];
// Find the existing disk area to append to, otherwise create a new disk area
@@ -362,14 +339,14 @@ namespace SabreTools.Metadata.DatFiles
ClearEmptyKeys(aggregateDataArea);
// Get existing roms as a list
var romsArr = aggregateDataArea.Read<Data.Models.Metadata.Rom[]>(Data.Models.Metadata.DataArea.RomKey) ?? [];
var romsArr = aggregateDataArea.Rom ?? [];
List<Data.Models.Metadata.Rom> roms = [.. romsArr];
// Add the rom to the data area
roms.Add(romItem);
// Assign back the roms
aggregateDataArea[Data.Models.Metadata.DataArea.RomKey] = roms.ToArray();
aggregateDataArea.Rom = roms.ToArray();
// Assign back the data area
if (dataAreaIndex > -1)
@@ -378,7 +355,7 @@ namespace SabreTools.Metadata.DatFiles
dataAreas.Add(aggregateDataArea);
// Assign back the data areas array
partItems[partName][Data.Models.Metadata.Part.DataAreaKey] = dataAreas.ToArray();
partItems[partName].DataArea = dataAreas.ToArray();
}
}
@@ -396,7 +373,7 @@ namespace SabreTools.Metadata.DatFiles
if (diskAreaName is not null)
{
// Get existing disk areas as a list
var diskAreasArr = partItems[partName].Read<Data.Models.Metadata.DiskArea[]>(Data.Models.Metadata.Part.DiskAreaKey) ?? [];
var diskAreasArr = partItems[partName].DiskArea ?? [];
List<Data.Models.Metadata.DiskArea> diskAreas = [.. diskAreasArr];
// Find the existing disk area to append to, otherwise create a new disk area
@@ -416,14 +393,14 @@ namespace SabreTools.Metadata.DatFiles
ClearEmptyKeys(aggregateDiskArea);
// Get existing disks as a list
var disksArr = aggregateDiskArea.Read<Data.Models.Metadata.Disk[]>(Data.Models.Metadata.DiskArea.DiskKey) ?? [];
var disksArr = aggregateDiskArea.Disk ?? [];
List<Data.Models.Metadata.Disk> disks = [.. disksArr];
// Add the disk to the data area
disks.Add(diskItem);
// Assign back the disks
aggregateDiskArea[Data.Models.Metadata.DiskArea.DiskKey] = disks.ToArray();
aggregateDiskArea.Disk = disks.ToArray();
// Assign back the disk area
if (diskAreaIndex > -1)
@@ -432,7 +409,7 @@ namespace SabreTools.Metadata.DatFiles
diskAreas.Add(aggregateDiskArea);
// Assign back the disk areas array
partItems[partName][Data.Models.Metadata.Part.DiskAreaKey] = diskAreas.ToArray();
partItems[partName].DiskArea = diskAreas.ToArray();
}
}
@@ -440,7 +417,7 @@ namespace SabreTools.Metadata.DatFiles
if (datItem is Data.Models.Metadata.DipSwitch dipSwitchItem)
{
// Get existing dipswitches as a list
var dipSwitchesArr = partItems[partName].Read<Data.Models.Metadata.DipSwitch[]>(Data.Models.Metadata.Part.DipSwitchKey) ?? [];
var dipSwitchesArr = partItems[partName].DipSwitch ?? [];
List<Data.Models.Metadata.DipSwitch> dipSwitches = [.. dipSwitchesArr];
// Clear any empty fields
@@ -450,14 +427,14 @@ namespace SabreTools.Metadata.DatFiles
dipSwitches.Add(dipSwitchItem);
// Assign back the dipswitches
partItems[partName][Data.Models.Metadata.Part.DipSwitchKey] = dipSwitches.ToArray();
partItems[partName].DipSwitch = dipSwitches.ToArray();
}
// If the item is a Feature
else if (datItem is Data.Models.Metadata.Feature featureItem)
{
// Get existing features as a list
var featuresArr = partItems[partName].Read<Data.Models.Metadata.Feature[]>(Data.Models.Metadata.Part.FeatureKey) ?? [];
var featuresArr = partItems[partName].Feature ?? [];
List<Data.Models.Metadata.Feature> features = [.. featuresArr];
// Clear any empty fields
@@ -467,7 +444,7 @@ namespace SabreTools.Metadata.DatFiles
features.Add(featureItem);
// Assign back the features
partItems[partName][Data.Models.Metadata.Part.FeatureKey] = features.ToArray();
partItems[partName].Feature = features.ToArray();
}
}
@@ -585,20 +562,11 @@ namespace SabreTools.Metadata.DatFiles
AppendToMachineKey(machine, Data.Models.Metadata.Machine.DiskKey, diskItem);
// Add Part and DiskArea mappings
bool diskContainsPart = disk.Part is not null;
bool diskContainsDiskArea = disk.DiskArea is not null;
if (diskContainsPart && diskContainsDiskArea)
if (disk.Part is not null && disk.DiskArea is not null)
{
var partItem = disk.Part;
if (partItem is not null)
{
var partItemInternal = partItem.GetInternalClone();
partMappings[partItemInternal] = diskItem;
var diskAreaItem = disk.DiskArea;
if (diskAreaItem is not null)
diskAreaMappings[partItemInternal] = (diskAreaItem.GetInternalClone(), diskItem);
}
var partItemInternal = disk.Part.GetInternalClone();
partMappings[partItemInternal] = diskItem;
diskAreaMappings[partItemInternal] = (disk.DiskArea.GetInternalClone(), diskItem);
}
break;
@@ -638,13 +606,8 @@ namespace SabreTools.Metadata.DatFiles
AppendToMachineKey(machine, Data.Models.Metadata.Machine.FeatureKey, partFeatureItem);
// Add Part mapping
bool partFeatureContainsPart = partFeatureItem.ContainsKey(DatItems.Formats.PartFeature.PartKey);
if (partFeatureContainsPart)
{
var partItem = partFeatureItem.Read<DatItems.Formats.Part>(DatItems.Formats.PartFeature.PartKey);
if (partItem is not null)
partMappings[partItem.GetInternalClone()] = partFeatureItem;
}
if (partFeature.Part is not null)
partMappings[partFeature.Part.GetInternalClone()] = partFeatureItem;
break;
case DatItems.Formats.Port port:
@@ -668,20 +631,11 @@ namespace SabreTools.Metadata.DatFiles
AppendToMachineKey(machine, Data.Models.Metadata.Machine.RomKey, romItem);
// Add Part and DataArea mappings
bool romContainsPart = romItem.ContainsKey(DatItems.Formats.Rom.PartKey);
bool romContainsDataArea = romItem.ContainsKey(DatItems.Formats.Rom.DataAreaKey);
if (romContainsPart && romContainsDataArea)
if (rom.Part is not null && rom.DataArea is not null)
{
var partItem = romItem.Read<DatItems.Formats.Part>(DatItems.Formats.Rom.PartKey);
if (partItem is not null)
{
var partItemInternal = partItem.GetInternalClone();
partMappings[partItemInternal] = romItem;
var dataAreaItem = romItem.Read<DatItems.Formats.DataArea>(DatItems.Formats.Rom.DataAreaKey);
if (dataAreaItem is not null)
dataAreaMappings[partItemInternal] = (dataAreaItem.GetInternalClone(), romItem);
}
var partItemInternal = rom.Part.GetInternalClone();
partMappings[partItemInternal] = romItem;
dataAreaMappings[partItemInternal] = (rom.DataArea.GetInternalClone(), romItem);
}
break;
@@ -760,7 +714,7 @@ namespace SabreTools.Metadata.DatFiles
if (dataAreaName is not null)
{
// Get existing data areas as a list
var dataAreasArr = partItems[partName].Read<Data.Models.Metadata.DataArea[]>(Data.Models.Metadata.Part.DataAreaKey) ?? [];
var dataAreasArr = partItems[partName].DataArea ?? [];
List<Data.Models.Metadata.DataArea> dataAreas = [.. dataAreasArr];
// Find the existing disk area to append to, otherwise create a new disk area
@@ -783,14 +737,14 @@ namespace SabreTools.Metadata.DatFiles
ClearEmptyKeys(aggregateDataArea);
// Get existing roms as a list
var romsArr = aggregateDataArea.Read<Data.Models.Metadata.Rom[]>(Data.Models.Metadata.DataArea.RomKey) ?? [];
var romsArr = aggregateDataArea.Rom ?? [];
List<Data.Models.Metadata.Rom> roms = [.. romsArr];
// Add the rom to the data area
roms.Add(romItem);
// Assign back the roms
aggregateDataArea[Data.Models.Metadata.DataArea.RomKey] = roms.ToArray();
aggregateDataArea.Rom = roms.ToArray();
// Assign back the data area
if (dataAreaIndex > -1)
@@ -799,7 +753,7 @@ namespace SabreTools.Metadata.DatFiles
dataAreas.Add(aggregateDataArea);
// Assign back the data areas array
partItems[partName][Data.Models.Metadata.Part.DataAreaKey] = dataAreas.ToArray();
partItems[partName].DataArea = dataAreas.ToArray();
}
}
@@ -817,7 +771,7 @@ namespace SabreTools.Metadata.DatFiles
if (diskAreaName is not null)
{
// Get existing disk areas as a list
var diskAreasArr = partItems[partName].Read<Data.Models.Metadata.DiskArea[]>(Data.Models.Metadata.Part.DiskAreaKey) ?? [];
var diskAreasArr = partItems[partName].DiskArea ?? [];
List<Data.Models.Metadata.DiskArea> diskAreas = [.. diskAreasArr];
// Find the existing disk area to append to, otherwise create a new disk area
@@ -837,14 +791,14 @@ namespace SabreTools.Metadata.DatFiles
ClearEmptyKeys(aggregateDiskArea);
// Get existing disks as a list
var disksArr = aggregateDiskArea.Read<Data.Models.Metadata.Disk[]>(Data.Models.Metadata.DiskArea.DiskKey) ?? [];
var disksArr = aggregateDiskArea.Disk ?? [];
List<Data.Models.Metadata.Disk> disks = [.. disksArr];
// Add the disk to the data area
disks.Add(diskItem);
// Assign back the disks
aggregateDiskArea[Data.Models.Metadata.DiskArea.DiskKey] = disks.ToArray();
aggregateDiskArea.Disk = disks.ToArray();
// Assign back the disk area
if (diskAreaIndex > -1)
@@ -853,7 +807,7 @@ namespace SabreTools.Metadata.DatFiles
diskAreas.Add(aggregateDiskArea);
// Assign back the disk areas array
partItems[partName][Data.Models.Metadata.Part.DiskAreaKey] = diskAreas.ToArray();
partItems[partName].DiskArea = diskAreas.ToArray();
}
}
@@ -861,7 +815,7 @@ namespace SabreTools.Metadata.DatFiles
if (datItem is Data.Models.Metadata.DipSwitch dipSwitchItem)
{
// Get existing dipswitches as a list
var dipSwitchesArr = partItems[partName].Read<Data.Models.Metadata.DipSwitch[]>(Data.Models.Metadata.Part.DipSwitchKey) ?? [];
var dipSwitchesArr = partItems[partName].DipSwitch ?? [];
List<Data.Models.Metadata.DipSwitch> dipSwitches = [.. dipSwitchesArr];
// Clear any empty fields
@@ -871,14 +825,14 @@ namespace SabreTools.Metadata.DatFiles
dipSwitches.Add(dipSwitchItem);
// Assign back the dipswitches
partItems[partName][Data.Models.Metadata.Part.DipSwitchKey] = dipSwitches.ToArray();
partItems[partName].DipSwitch = dipSwitches.ToArray();
}
// If the item is a Feature
else if (datItem is Data.Models.Metadata.Feature featureItem)
{
// Get existing features as a list
var featuresArr = partItems[partName].Read<Data.Models.Metadata.Feature[]>(Data.Models.Metadata.Part.FeatureKey) ?? [];
var featuresArr = partItems[partName].Feature ?? [];
List<Data.Models.Metadata.Feature> features = [.. featuresArr];
// Clear any empty fields
@@ -888,7 +842,7 @@ namespace SabreTools.Metadata.DatFiles
features.Add(featureItem);
// Assign back the features
partItems[partName][Data.Models.Metadata.Part.FeatureKey] = features.ToArray();
partItems[partName].Feature = features.ToArray();
}
}

View File

@@ -178,9 +178,9 @@ namespace SabreTools.Metadata.DatFiles.Formats
}
else
{
if (string.IsNullOrEmpty(rom.Read<Part?>(Rom.PartKey)!.Name))
if (string.IsNullOrEmpty(rom.Part!.Name))
missingFields.Add(nameof(Data.Models.Metadata.Part.Name));
if (string.IsNullOrEmpty(rom.Read<Part?>(Rom.PartKey)!.Interface))
if (string.IsNullOrEmpty(rom.Part!.Interface))
missingFields.Add(nameof(Data.Models.Metadata.Part.Interface));
}
@@ -191,9 +191,9 @@ namespace SabreTools.Metadata.DatFiles.Formats
}
else
{
if (string.IsNullOrEmpty(rom.Read<DataArea?>(Rom.DataAreaKey)!.Name))
if (string.IsNullOrEmpty(rom.DataArea!.Name))
missingFields.Add(nameof(Data.Models.Metadata.DataArea.Name));
if (rom.Read<DataArea?>(Rom.DataAreaKey)!.Size is null)
if (rom.DataArea!.Size is null)
missingFields.Add(nameof(Data.Models.Metadata.DataArea.Size));
}

View File

@@ -46,7 +46,7 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
Assert.Equal(HashType.SHA1.ZeroString, actual.ReadString(Data.Models.Metadata.Rom.SHA1Key));
Assert.Equal(DupeType.All | DupeType.External, actual.DupeType);
DataArea? actualDataArea = actual.Read<DataArea?>(Rom.DataAreaKey);
DataArea? actualDataArea = actual.DataArea;
Assert.NotNull(actualDataArea);
Assert.Equal("name", actualDataArea.Name);
@@ -56,7 +56,7 @@ namespace SabreTools.Metadata.DatItems.Formats.Test
Assert.False(actual.RemoveFlag);
Part? actualPart = actual.Read<Part?>(Rom.PartKey);
Part? actualPart = actual.Part;
Assert.NotNull(actualPart);
Assert.Equal("name", actualPart.Name);

View File

@@ -1,4 +1,5 @@
using System.Xml.Serialization;
using System;
using System.Xml.Serialization;
using Newtonsoft.Json;
using SabreTools.Data.Extensions;
@@ -29,6 +30,11 @@ namespace SabreTools.Metadata.DatItems.Formats
set => (_internal as Data.Models.Metadata.DataArea)?.Name = value;
}
public Rom[]? Rom { get; set; }
[JsonIgnore]
public bool RomSpecified => Rom is not null && Rom.Length > 0;
public long? Size
{
get => (_internal as Data.Models.Metadata.DataArea)?.Size;
@@ -47,7 +53,12 @@ namespace SabreTools.Metadata.DatItems.Formats
public DataArea() : base() { }
public DataArea(Data.Models.Metadata.DataArea item) : base(item) { }
public DataArea(Data.Models.Metadata.DataArea item) : base(item)
{
// Handle subitems
if (item.Rom is not null)
Rom = Array.ConvertAll(item.Rom, rom => new Rom(rom));
}
public DataArea(Data.Models.Metadata.DataArea item, Machine machine, Source source) : this(item)
{
@@ -72,6 +83,16 @@ namespace SabreTools.Metadata.DatItems.Formats
/// <inheritdoc/>
public override object Clone() => new DataArea(_internal.DeepClone() as Data.Models.Metadata.DataArea ?? []);
public override Data.Models.Metadata.DataArea GetInternalClone()
{
var partItem = base.GetInternalClone();
if (Rom is not null)
partItem.Rom = Array.ConvertAll(Rom, rom => rom.GetInternalClone());
return partItem;
}
#endregion
}
}

View File

@@ -153,12 +153,12 @@ namespace SabreTools.Metadata.DatItems.Formats
if (DiskArea is not null)
{
var dataArea = new DataArea { Name = DiskArea.Name };
rom.Write<DataArea?>(Rom.DataAreaKey, dataArea);
rom.DataArea = dataArea;
}
rom.DupeType = DupeType;
rom.Machine = Machine?.Clone() as Machine;
rom.Write(Rom.PartKey, Part?.Clone() as Part);
rom.Part = Part?.Clone() as Part;
rom.RemoveFlag = RemoveFlag;
rom.Source = Source?.Clone() as Source;

View File

@@ -1,4 +1,5 @@
using System.Xml.Serialization;
using System;
using System.Xml.Serialization;
using Newtonsoft.Json;
using SabreTools.Data.Extensions;
@@ -13,6 +14,11 @@ namespace SabreTools.Metadata.DatItems.Formats
{
#region Fields
public Disk[]? Disk { get; set; }
[JsonIgnore]
public bool DiskSpecified => Disk is not null && Disk.Length > 0;
/// <inheritdoc>/>
public override Data.Models.Metadata.ItemType ItemType
=> Data.Models.Metadata.ItemType.DiskArea;
@@ -29,7 +35,12 @@ namespace SabreTools.Metadata.DatItems.Formats
public DiskArea() : base() { }
public DiskArea(Data.Models.Metadata.DiskArea item) : base(item) { }
public DiskArea(Data.Models.Metadata.DiskArea item) : base(item)
{
// Handle subitems
if (item.Disk is not null)
Disk = Array.ConvertAll(item.Disk, rom => new Disk(rom));
}
public DiskArea(Data.Models.Metadata.DiskArea item, Machine machine, Source source) : this(item)
{
@@ -54,6 +65,16 @@ namespace SabreTools.Metadata.DatItems.Formats
/// <inheritdoc/>
public override object Clone() => new DiskArea(_internal.DeepClone() as Data.Models.Metadata.DiskArea ?? []);
public override Data.Models.Metadata.DiskArea GetInternalClone()
{
var partItem = base.GetInternalClone();
if (Disk is not null)
partItem.Disk = Array.ConvertAll(Disk, rom => rom.GetInternalClone());
return partItem;
}
#endregion
}
}

View File

@@ -14,15 +14,25 @@ namespace SabreTools.Metadata.DatItems.Formats
{
#region Fields
public DataArea[]? DataArea { get; set; }
[JsonIgnore]
public bool FeaturesSpecified
{
get
{
var features = Read<PartFeature[]?>(Data.Models.Metadata.Part.FeatureKey);
return features is not null && features.Length > 0;
}
}
public bool DataAreaSpecified => DataArea is not null && DataArea.Length > 0;
public DiskArea[]? DiskArea { get; set; }
[JsonIgnore]
public bool DiskAreaSpecified => DiskArea is not null && DiskArea.Length > 0;
public DipSwitch[]? DipSwitch { get; set; }
[JsonIgnore]
public bool DipSwitchSpecified => DipSwitch is not null && DipSwitch.Length > 0;
public PartFeature[]? Feature { get; set; }
[JsonIgnore]
public bool FeatureSpecified => Feature is not null && Feature.Length > 0;
public string? Interface
{
@@ -46,7 +56,21 @@ namespace SabreTools.Metadata.DatItems.Formats
public Part() : base() { }
public Part(Data.Models.Metadata.Part item) : base(item) { }
public Part(Data.Models.Metadata.Part item) : base(item)
{
// Handle subitems
if (item.DataArea is not null)
DataArea = Array.ConvertAll(item.DataArea, dataArea => new DataArea(dataArea));
if (item.DiskArea is not null)
DiskArea = Array.ConvertAll(item.DiskArea, diskArea => new DiskArea(diskArea));
if (item.DipSwitch is not null)
DipSwitch = Array.ConvertAll(item.DipSwitch, dipSwitch => new DipSwitch(dipSwitch));
if (item.Feature is not null)
Feature = Array.ConvertAll(item.Feature, feature => new PartFeature(feature));
}
public Part(Data.Models.Metadata.Part item, Machine machine, Source source) : this(item)
{
@@ -76,33 +100,17 @@ namespace SabreTools.Metadata.DatItems.Formats
{
var partItem = base.GetInternalClone();
var dataAreas = Read<DataArea[]?>(Data.Models.Metadata.Part.DataAreaKey);
if (dataAreas is not null)
{
Data.Models.Metadata.DataArea[] dataAreaItems = Array.ConvertAll(dataAreas, dataArea => dataArea.GetInternalClone());
partItem[Data.Models.Metadata.Part.DataAreaKey] = dataAreaItems;
}
if (DataArea is not null)
partItem.DataArea = Array.ConvertAll(DataArea, dataArea => dataArea.GetInternalClone());
var diskAreas = Read<DiskArea[]?>(Data.Models.Metadata.Part.DiskAreaKey);
if (diskAreas is not null)
{
Data.Models.Metadata.DiskArea[] diskAreaItems = Array.ConvertAll(diskAreas, diskArea => diskArea.GetInternalClone());
partItem[Data.Models.Metadata.Part.DiskAreaKey] = diskAreaItems;
}
if (DiskArea is not null)
partItem.DiskArea = Array.ConvertAll(DiskArea, diskArea => diskArea.GetInternalClone());
var dipSwitches = Read<DipSwitch[]?>(Data.Models.Metadata.Part.DipSwitchKey);
if (dipSwitches is not null)
{
Data.Models.Metadata.DipSwitch[] dipSwitchItems = Array.ConvertAll(dipSwitches, dipSwitch => dipSwitch.GetInternalClone());
partItem[Data.Models.Metadata.Part.DipSwitchKey] = dipSwitchItems;
}
if (DipSwitch is not null)
partItem.DipSwitch = Array.ConvertAll(DipSwitch, dipSwitch => dipSwitch.GetInternalClone());
var features = Read<Feature[]?>(Data.Models.Metadata.Part.FeatureKey);
if (features is not null)
{
Data.Models.Metadata.Feature[] featureItems = Array.ConvertAll(features, feature => feature.GetInternalClone());
partItem[Data.Models.Metadata.Part.FeatureKey] = featureItems;
}
if (Feature is not null)
partItem.Feature = Array.ConvertAll(Feature, feature => feature.GetInternalClone());
return partItem;
}

View File

@@ -10,15 +10,6 @@ namespace SabreTools.Metadata.DatItems.Formats
[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
public Data.Models.Metadata.FeatureType? FeatureType
@@ -43,6 +34,11 @@ namespace SabreTools.Metadata.DatItems.Formats
set => (_internal as Data.Models.Metadata.Feature)?.Overall = value;
}
public Part? Part { get; set; }
[JsonIgnore]
public bool PartSpecified => Part is not null;
public Data.Models.Metadata.FeatureStatus? Status
{
get => (_internal as Data.Models.Metadata.Feature)?.Status;

View File

@@ -12,33 +12,20 @@ namespace SabreTools.Metadata.DatItems.Formats
[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
public DataArea? DataArea { get; set; }
[JsonIgnore]
public bool DataAreaSpecified
{
get
{
var dataArea = Read<DataArea?>(DataAreaKey);
return dataArea is not null
&& (!string.IsNullOrEmpty(dataArea.Name)
|| dataArea.Size is not null
|| dataArea.Width is not null
|| dataArea.Endianness is not null);
return DataArea is not null
&& (!string.IsNullOrEmpty(DataArea.Name)
|| DataArea.Size is not null
|| DataArea.Width is not null
|| DataArea.Endianness is not null);
}
}
@@ -109,15 +96,16 @@ namespace SabreTools.Metadata.DatItems.Formats
}
}
public Part? Part { get; set; }
[JsonIgnore]
public bool PartSpecified
{
get
{
var part = Read<Part?>(PartKey);
return part is not null
&& (!string.IsNullOrEmpty(part.Name)
|| !string.IsNullOrEmpty(part.Interface));
return Part is not null
&& (!string.IsNullOrEmpty(Part.Name)
|| !string.IsNullOrEmpty(Part.Interface));
}
}

View File

@@ -114,11 +114,7 @@ namespace SabreTools.Metadata
}
else if (self is DataArea selfDataArea && other is DataArea otherDataArea)
{
if (selfDataArea.Endianness != otherDataArea.Endianness)
return false;
if (selfDataArea.Size != otherDataArea.Size)
return false;
if (selfDataArea.Width != otherDataArea.Width)
if (!selfDataArea.Equals(otherDataArea))
return false;
}
else if (self is Device selfDevice && other is Device otherDevice)
@@ -145,6 +141,11 @@ namespace SabreTools.Metadata
{
// Intentionally skipped here
}
else if (self is DiskArea selfDiskArea && other is DiskArea otherDiskArea)
{
if (!selfDiskArea.Equals(otherDiskArea))
return false;
}
else if (self is Display selfDisplay && other is Display otherDisplay)
{
if (!selfDisplay.Equals(otherDisplay))
@@ -356,7 +357,7 @@ namespace SabreTools.Metadata
}
else if (self is Part selfPart && other is Part otherPart)
{
if (selfPart.Interface != otherPart.Interface)
if (!selfPart.Equals(otherPart))
return false;
}
else if (self is Port selfPort && other is Port otherPort)

View File

@@ -79,7 +79,7 @@ namespace SabreTools.Serialization.CrossModel
Endianness = item.Endianness,
};
var roms = item.Read<Data.Models.Metadata.Rom[]>(Data.Models.Metadata.DataArea.RomKey);
var roms = item.Rom;
if (roms is not null && roms.Length > 0)
dataArea.Rom = Array.ConvertAll(roms, ConvertFromInternalModel);
@@ -145,7 +145,7 @@ namespace SabreTools.Serialization.CrossModel
Name = item.Name,
};
var disks = item.Read<Data.Models.Metadata.Disk[]>(Data.Models.Metadata.DiskArea.DiskKey);
var disks = item.Disk;
if (disks is not null && disks.Length > 0)
diskArea.Disk = Array.ConvertAll(disks, ConvertFromInternalModel);
@@ -189,19 +189,19 @@ namespace SabreTools.Serialization.CrossModel
Interface = item.Interface,
};
var features = item.Read<Data.Models.Metadata.Feature[]>(Data.Models.Metadata.Part.FeatureKey);
var features = item.Feature;
if (features is not null && features.Length > 0)
part.Feature = Array.ConvertAll(features, ConvertFromInternalModel);
var dataAreas = item.Read<Data.Models.Metadata.DataArea[]>(Data.Models.Metadata.Part.DataAreaKey);
var dataAreas = item.DataArea;
if (dataAreas is not null && dataAreas.Length > 0)
part.DataArea = Array.ConvertAll(dataAreas, ConvertFromInternalModel);
var diskAreas = item.Read<Data.Models.Metadata.DiskArea[]>(Data.Models.Metadata.Part.DiskAreaKey);
var diskAreas = item.DiskArea;
if (diskAreas is not null && diskAreas.Length > 0)
part.DiskArea = Array.ConvertAll(diskAreas, ConvertFromInternalModel);
var dipSwitches = item.Read<Data.Models.Metadata.DipSwitch[]>(Data.Models.Metadata.Part.DipSwitchKey);
var dipSwitches = item.DipSwitch;
if (dipSwitches is not null && dipSwitches.Length > 0)
part.DipSwitch = Array.ConvertAll(dipSwitches, ConvertFromInternalModel);

View File

@@ -81,7 +81,7 @@ namespace SabreTools.Serialization.CrossModel
};
if (item.Rom is not null && item.Rom.Length > 0)
dataArea[Data.Models.Metadata.DataArea.RomKey] = Array.ConvertAll(item.Rom, ConvertToInternalModel);
dataArea.Rom = Array.ConvertAll(item.Rom, ConvertToInternalModel);
return dataArea;
}
@@ -145,7 +145,7 @@ namespace SabreTools.Serialization.CrossModel
};
if (item.Disk is not null && item.Disk.Length > 0)
diskArea[Data.Models.Metadata.DiskArea.DiskKey] = Array.ConvertAll(item.Disk, ConvertToInternalModel);
diskArea.Disk = Array.ConvertAll(item.Disk, ConvertToInternalModel);
return diskArea;
}
@@ -188,16 +188,16 @@ namespace SabreTools.Serialization.CrossModel
};
if (item.Feature is not null && item.Feature.Length > 0)
part[Data.Models.Metadata.Part.FeatureKey] = Array.ConvertAll(item.Feature, ConvertToInternalModel);
part.Feature = Array.ConvertAll(item.Feature, ConvertToInternalModel);
if (item.DataArea is not null && item.DataArea.Length > 0)
part[Data.Models.Metadata.Part.DataAreaKey] = Array.ConvertAll(item.DataArea, ConvertToInternalModel);
part.DataArea = Array.ConvertAll(item.DataArea, ConvertToInternalModel);
if (item.DiskArea is not null && item.DiskArea.Length > 0)
part[Data.Models.Metadata.Part.DiskAreaKey] = Array.ConvertAll(item.DiskArea, ConvertToInternalModel);
part.DiskArea = Array.ConvertAll(item.DiskArea, ConvertToInternalModel);
if (item.DipSwitch is not null && item.DipSwitch.Length > 0)
part[Data.Models.Metadata.Part.DipSwitchKey] = Array.ConvertAll(item.DipSwitch, ConvertToInternalModel);
part.DipSwitch = Array.ConvertAll(item.DipSwitch, ConvertToInternalModel);
return part;
}