diff --git a/README.MD b/README.MD index 656305e0..7657adde 100644 --- a/README.MD +++ b/README.MD @@ -18,7 +18,7 @@ As the core of the SabreTools suite, the C# library provides nearly all of the f * **Dir2DAT / DATFromDir** - Create a DAT from a file, folder, or mix of both * Archives and files can be filtered selectively - * Archives and CHDs can be treated like files, that is, it will get an external hash only + * Aaruformat, Archives, and CHDs can be treated like files, that is, it will get an external hash only * Multiple input archive formats are supported: 7zip, GZip, RAR, TAR, and ZIP/ZIP64 * Multiple hashing algorithms available, up to SHA-512 * Created DATs can be output in multiple formats at once, including ClrMamePro, Logiqx XML, and RomCenter @@ -56,13 +56,13 @@ As the core of the SabreTools suite, the C# library provides nearly all of the f * Can rebuild from multiple DATs at the same time * Cross-check with multiple hashing algorithms, up to SHA-512 * Can output a fixdat based on the rebuilt files - * CHDs can be rebuilt either to folders or to TorrentGZ archives + * Aaruformat and CHDs can be rebuilt either to folders or to TorrentGZ archives * **Verify From DAT** - Act as a simple verifier for files * Two options for verification target: standard folder and Romba depot * Exact verification and hash-only verification both available * Can verify from multiple DATs at the same time * Cross-check with mutliple hashing algorithms, up to SHA-512 - * CHDs can be treated like files + * Aaruformat and CHDs can be treated like files This tool has a comprehensive list of command line parameters that can be used to do the above and much more. diff --git a/RombaSharp/Features/Archive.cs b/RombaSharp/Features/Archive.cs index 9feee70b..ab2bc023 100644 --- a/RombaSharp/Features/Archive.cs +++ b/RombaSharp/Features/Archive.cs @@ -65,8 +65,8 @@ have a current entry in the DAT index."; DatFile df = DatFile.Create(); foreach (string dir in onlyDirs) { - df.PopulateFromDir(dir, asFiles: TreatAsFiles.CHDs); - df.PopulateFromDir(dir, asFiles: TreatAsFiles.Archives | TreatAsFiles.CHDs); + df.PopulateFromDir(dir, asFiles: TreatAsFiles.AaruFormats | TreatAsFiles.CHDs); + df.PopulateFromDir(dir, asFiles: TreatAsFiles.AaruFormats | TreatAsFiles.Archives | TreatAsFiles.CHDs); } // Create an empty Dat for files that need to be rebuilt @@ -194,7 +194,7 @@ have a current entry in the DAT index."; outDir: _depots.Keys.ToList()[0], outputFormat: OutputFormat.TorrentGzipRomba, updateDat: false, - asFiles: TreatAsFiles.CHDs); + asFiles: TreatAsFiles.AaruFormats | TreatAsFiles.CHDs); } } } diff --git a/RombaSharp/Features/BaseFeature.cs b/RombaSharp/Features/BaseFeature.cs index eab7c9fb..25d975e8 100644 --- a/RombaSharp/Features/BaseFeature.cs +++ b/RombaSharp/Features/BaseFeature.cs @@ -629,7 +629,39 @@ namespace RombaSharp.Features { Globals.Logger.Verbose($"Checking and adding file '{datItem.Name}'"); - if (datItem.ItemType == ItemType.Rom) + if (datItem.ItemType == ItemType.Disk) + { + Disk disk = (Disk)datItem; + hasItems = true; + + if (!string.IsNullOrWhiteSpace(disk.MD5)) + md5query += $" (\"{disk.MD5}\"),"; + + if (!string.IsNullOrWhiteSpace(disk.SHA1)) + { + sha1query += $" (\"{disk.SHA1}\"),"; + + if (!string.IsNullOrWhiteSpace(disk.MD5)) + md5sha1query += $" (\"{disk.MD5}\", \"{disk.SHA1}\"),"; + } + } + else if (datItem.ItemType == ItemType.Media) + { + Media media = (Media)datItem; + hasItems = true; + + if (!string.IsNullOrWhiteSpace(media.MD5)) + md5query += $" (\"{media.MD5}\"),"; + + if (!string.IsNullOrWhiteSpace(media.SHA1)) + { + sha1query += $" (\"{media.SHA1}\"),"; + + if (!string.IsNullOrWhiteSpace(media.MD5)) + md5sha1query += $" (\"{media.MD5}\", \"{media.SHA1}\"),"; + } + } + else if (datItem.ItemType == ItemType.Rom) { Rom rom = (Rom)datItem; hasItems = true; @@ -651,22 +683,6 @@ namespace RombaSharp.Features md5sha1query += $" (\"{rom.MD5}\", \"{rom.SHA1}\"),"; } } - else if (datItem.ItemType == ItemType.Disk) - { - Disk disk = (Disk)datItem; - hasItems = true; - - if (!string.IsNullOrWhiteSpace(disk.MD5)) - md5query += $" (\"{disk.MD5}\"),"; - - if (!string.IsNullOrWhiteSpace(disk.SHA1)) - { - sha1query += $" (\"{disk.SHA1}\"),"; - - if (!string.IsNullOrWhiteSpace(disk.MD5)) - md5sha1query += $" (\"{disk.MD5}\", \"{disk.SHA1}\"),"; - } - } } } diff --git a/RombaSharp/Features/Dir2Dat.cs b/RombaSharp/Features/Dir2Dat.cs index 80fdc0d9..10116c9c 100644 --- a/RombaSharp/Features/Dir2Dat.cs +++ b/RombaSharp/Features/Dir2Dat.cs @@ -51,7 +51,7 @@ namespace RombaSharp.Features DatFile datfile = DatFile.Create(); datfile.Header.Name = string.IsNullOrWhiteSpace(name) ? "untitled" : name; datfile.Header.Description = description; - datfile.PopulateFromDir(source, bare: true, asFiles: TreatAsFiles.CHDs); + datfile.PopulateFromDir(source, bare: true, asFiles: TreatAsFiles.AaruFormats | TreatAsFiles.CHDs); datfile.Write(outDir: outdat); } } diff --git a/RombaSharp/Features/RefreshDats.cs b/RombaSharp/Features/RefreshDats.cs index 4119713d..0de46b8a 100644 --- a/RombaSharp/Features/RefreshDats.cs +++ b/RombaSharp/Features/RefreshDats.cs @@ -62,7 +62,7 @@ contents of any changed dats."; // First get a list of SHA-1's from the input DATs DatFile datroot = DatFile.Create(); datroot.Header.Type = "SuperDAT"; - datroot.PopulateFromDir(_dats, asFiles: TreatAsFiles.CHDs); + datroot.PopulateFromDir(_dats, asFiles: TreatAsFiles.AaruFormats | TreatAsFiles.CHDs); datroot.Items.BucketBy(Field.DatItem_SHA1, DedupeType.None); // Create a List of dat hashes in the database (SHA-1) diff --git a/RombaSharp/Features/RescanDepots.cs b/RombaSharp/Features/RescanDepots.cs index 4571091c..bcba7896 100644 --- a/RombaSharp/Features/RescanDepots.cs +++ b/RombaSharp/Features/RescanDepots.cs @@ -64,7 +64,7 @@ namespace RombaSharp.Features // Now rescan the depot itself DatFile depot = DatFile.Create(); - depot.PopulateFromDir(depotname, asFiles: TreatAsFiles.CHDs); + depot.PopulateFromDir(depotname, asFiles: TreatAsFiles.AaruFormats | TreatAsFiles.CHDs); depot.Items.BucketBy(Field.DatItem_SHA1, DedupeType.None); // Set the base queries to use diff --git a/SabreTools.Library/DatFiles/AttractMode.cs b/SabreTools.Library/DatFiles/AttractMode.cs index 08a92487..657a65e7 100644 --- a/SabreTools.Library/DatFiles/AttractMode.cs +++ b/SabreTools.Library/DatFiles/AttractMode.cs @@ -175,13 +175,13 @@ namespace SabreTools.Library.DatFiles // If we have a "null" game (created by DATFromDir or something similar), log it to file if (item.ItemType == ItemType.Rom - && ((Rom)item).Size == -1 - && ((Rom)item).CRC == "null") + && (item as Rom).Size == -1 + && (item as Rom).CRC == "null") { Globals.Logger.Verbose($"Empty folder found: {item.Machine.Name}"); item.Name = (item.Name == "null" ? "-" : item.Name); - ((Rom)item).Size = Constants.SizeZero; + (item as Rom).Size = Constants.SizeZero; } // Set the new data to compare against @@ -255,7 +255,7 @@ namespace SabreTools.Library.DatFiles private bool WriteDatItem(SeparatedValueWriter svw, DatItem datItem, bool ignoreblanks = false) { // If we are in ignore blanks mode AND we have a blank (0-size) rom, skip - if (ignoreblanks && (datItem.ItemType == ItemType.Rom && (((Rom)datItem).Size == 0 || ((Rom)datItem).Size == -1))) + if (ignoreblanks && (datItem.ItemType == ItemType.Rom && ((datItem as Rom).Size == 0 || (datItem as Rom).Size == -1))) return true; try diff --git a/SabreTools.Library/DatFiles/ClrMamePro.cs b/SabreTools.Library/DatFiles/ClrMamePro.cs index 4c8ad353..006f19f4 100644 --- a/SabreTools.Library/DatFiles/ClrMamePro.cs +++ b/SabreTools.Library/DatFiles/ClrMamePro.cs @@ -262,33 +262,8 @@ namespace SabreTools.Library.DatFiles containsItems = true; string itemKey = cmpr.InternalName; - ItemType itemType = ItemType.Rom; - switch (itemKey) - { - case "archive": - itemType = ItemType.Archive; - break; - case "biosset": - itemType = ItemType.BiosSet; - break; - case "chip": - itemType = ItemType.Chip; - break; - case "disk": - itemType = ItemType.Disk; - break; - case "release": - itemType = ItemType.Release; - break; - case "rom": - itemType = ItemType.Rom; - break; - case "sample": - itemType = ItemType.Sample; - break; - } - // Create the proper DatItem based on the type + ItemType itemType = itemKey.AsItemType() ?? ItemType.Rom; DatItem item = DatItem.Create(itemType); // Then populate it with information @@ -318,9 +293,9 @@ namespace SabreTools.Library.DatFiles if (item.ItemType == ItemType.Rom) { if (Int64.TryParse(attrVal, out long size)) - ((Rom)item).Size = size; + (item as Rom).Size = size; else - ((Rom)item).Size = -1; + (item as Rom).Size = -1; } break; @@ -330,99 +305,97 @@ namespace SabreTools.Library.DatFiles break; case "md5": - if (item.ItemType == ItemType.Rom) + if (item.ItemType == ItemType.Disk) + (item as Disk).MD5 = attrVal; + else if (item.ItemType == ItemType.Media) + (item as Media).MD5 = attrVal; + else if (item.ItemType == ItemType.Rom) (item as Rom).MD5 = attrVal; - else if (item.ItemType == ItemType.Disk) - ((Disk)item).MD5 = attrVal; break; #if NET_FRAMEWORK case "ripemd160": if (item.ItemType == ItemType.Rom) (item as Rom).RIPEMD160 = attrVal; - else if (item.ItemType == ItemType.Disk) - ((Disk)item).RIPEMD160 = attrVal; break; #endif case "sha1": - if (item.ItemType == ItemType.Rom) + if (item.ItemType == ItemType.Disk) + (item as Disk).SHA1 = attrVal; + else if (item.ItemType == ItemType.Media) + (item as Media).SHA1 = attrVal; + else if (item.ItemType == ItemType.Rom) (item as Rom).SHA1 = attrVal; - else if (item.ItemType == ItemType.Disk) - ((Disk)item).SHA1 = attrVal; break; case "sha256": - if (item.ItemType == ItemType.Rom) - ((Rom)item).SHA256 = attrVal; - else if (item.ItemType == ItemType.Disk) - ((Disk)item).SHA256 = attrVal; - + if (item.ItemType == ItemType.Media) + (item as Media).SHA256 = attrVal; + else if (item.ItemType == ItemType.Rom) + (item as Rom).SHA256 = attrVal; + break; case "sha384": if (item.ItemType == ItemType.Rom) - ((Rom)item).SHA384 = attrVal; - else if (item.ItemType == ItemType.Disk) - ((Disk)item).SHA384 = attrVal; + (item as Rom).SHA384 = attrVal; break; case "sha512": if (item.ItemType == ItemType.Rom) - ((Rom)item).SHA512 = attrVal; - else if (item.ItemType == ItemType.Disk) - ((Disk)item).SHA512 = attrVal; + (item as Rom).SHA512 = attrVal; break; case "status": ItemStatus tempFlagStatus = attrVal.AsItemStatus(); - if (item.ItemType == ItemType.Rom) - ((Rom)item).ItemStatus = tempFlagStatus; - else if (item.ItemType == ItemType.Disk) - ((Disk)item).ItemStatus = tempFlagStatus; + if (item.ItemType == ItemType.Disk) + (item as Disk).ItemStatus = tempFlagStatus; + else if (item.ItemType == ItemType.Rom) + (item as Rom).ItemStatus = tempFlagStatus; break; case "date": - if (item.ItemType == ItemType.Rom) - ((Rom)item).Date = attrVal; - else if (item.ItemType == ItemType.Release) - ((Release)item).Date = attrVal; + if (item.ItemType == ItemType.Release) + (item as Release).Date = attrVal; + else if (item.ItemType == ItemType.Rom) + (item as Rom).Date = attrVal; break; case "default": if (item.ItemType == ItemType.BiosSet) - ((BiosSet)item).Default = attrVal.AsYesNo(); + (item as BiosSet).Default = attrVal.AsYesNo(); else if (item.ItemType == ItemType.Release) - ((Release)item).Default = attrVal.AsYesNo(); + (item as Release).Default = attrVal.AsYesNo(); break; case "description": if (item.ItemType == ItemType.BiosSet) - ((BiosSet)item).Description = attrVal; + (item as BiosSet).Description = attrVal; break; case "region": if (item.ItemType == ItemType.Release) - ((Release)item).Region = attrVal; + (item as Release).Region = attrVal; break; case "language": if (item.ItemType == ItemType.Release) - ((Release)item).Language = attrVal; + (item as Release).Language = attrVal; break; case "tag": if (item.ItemType == ItemType.Chip) - ((Chip)item).Tag = attrVal; + (item as Chip).Tag = attrVal; break; case "type": if (item.ItemType == ItemType.Chip) - ((Chip)item).ChipType = attrVal; + (item as Chip).ChipType = attrVal; break; case "clock": if (item.ItemType == ItemType.Chip) - ((Chip)item).Clock = attrVal; + (item as Chip).Clock = attrVal; break; } @@ -707,17 +680,21 @@ namespace SabreTools.Library.DatFiles cmpw.WriteStartElement("disk"); cmpw.WriteRequiredAttributeString("name", disk.Name); cmpw.WriteOptionalAttributeString("md5", disk.MD5?.ToLowerInvariant()); -#if NET_FRAMEWORK - cmpw.WriteOptionalAttributeString("ripemd160", disk.RIPEMD160?.ToLowerInvariant()); -#endif cmpw.WriteOptionalAttributeString("sha1", disk.SHA1?.ToLowerInvariant()); - cmpw.WriteOptionalAttributeString("sha256", disk.SHA256?.ToLowerInvariant()); - cmpw.WriteOptionalAttributeString("sha384", disk.SHA384?.ToLowerInvariant()); - cmpw.WriteOptionalAttributeString("sha512", disk.SHA512?.ToLowerInvariant()); cmpw.WriteOptionalAttributeString("flags", disk.ItemStatus.FromItemStatus(false)); cmpw.WriteEndElement(); break; + case ItemType.Media: + var media = datItem as Media; + cmpw.WriteStartElement("media"); + cmpw.WriteRequiredAttributeString("name", media.Name); + cmpw.WriteOptionalAttributeString("md5", media.MD5?.ToLowerInvariant()); + cmpw.WriteOptionalAttributeString("sha1", media.SHA1?.ToLowerInvariant()); + cmpw.WriteOptionalAttributeString("sha256", media.SHA256?.ToLowerInvariant()); + cmpw.WriteEndElement(); + break; + case ItemType.Release: var release = datItem as Release; cmpw.WriteStartElement("release"); diff --git a/SabreTools.Library/DatFiles/DatFile.cs b/SabreTools.Library/DatFiles/DatFile.cs index 8819ca36..8a12e67e 100644 --- a/SabreTools.Library/DatFiles/DatFile.cs +++ b/SabreTools.Library/DatFiles/DatFile.cs @@ -1986,100 +1986,92 @@ namespace SabreTools.Library.DatFiles return key; } - // If we have a Rom or a Disk, clean the hash data - if (item.ItemType == ItemType.Rom) + // If we have a Disk, Media, or Rom, clean the hash data + if (item.ItemType == ItemType.Disk) { - Rom itemRom = (Rom)item; + Disk disk = item as Disk; + + // If the file has aboslutely no hashes, skip and log + if (disk.ItemStatus != ItemStatus.Nodump + && string.IsNullOrWhiteSpace(disk.MD5) + && string.IsNullOrWhiteSpace(disk.SHA1)) + { + Globals.Logger.Verbose($"Incomplete entry for '{disk.Name}' will be output as nodump"); + disk.ItemStatus = ItemStatus.Nodump; + } + + item = disk; + } + else if (item.ItemType == ItemType.Rom) + { + Rom rom = item as Rom; // If we have the case where there is SHA-1 and nothing else, we don't fill in any other part of the data - if (itemRom.Size == -1 - && string.IsNullOrWhiteSpace(itemRom.CRC) - && string.IsNullOrWhiteSpace(itemRom.MD5) + if (rom.Size == -1 + && string.IsNullOrWhiteSpace(rom.CRC) + && string.IsNullOrWhiteSpace(rom.MD5) #if NET_FRAMEWORK - && string.IsNullOrWhiteSpace(itemRom.RIPEMD160) + && string.IsNullOrWhiteSpace(rom.RIPEMD160) #endif - && !string.IsNullOrWhiteSpace(itemRom.SHA1) - && string.IsNullOrWhiteSpace(itemRom.SHA256) - && string.IsNullOrWhiteSpace(itemRom.SHA384) - && string.IsNullOrWhiteSpace(itemRom.SHA512)) + && !string.IsNullOrWhiteSpace(rom.SHA1) + && string.IsNullOrWhiteSpace(rom.SHA256) + && string.IsNullOrWhiteSpace(rom.SHA384) + && string.IsNullOrWhiteSpace(rom.SHA512)) { // No-op, just catch it so it doesn't go further - Globals.Logger.Verbose($"{Header.FileName}: Entry with only SHA-1 found - '{itemRom.Name}'"); + Globals.Logger.Verbose($"{Header.FileName}: Entry with only SHA-1 found - '{rom.Name}'"); } // If we have a rom and it's missing size AND the hashes match a 0-byte file, fill in the rest of the info - else if ((itemRom.Size == 0 || itemRom.Size == -1) - && ((itemRom.CRC == Constants.CRCZero || string.IsNullOrWhiteSpace(itemRom.CRC)) - || itemRom.MD5 == Constants.MD5Zero + else if ((rom.Size == 0 || rom.Size == -1) + && ((rom.CRC == Constants.CRCZero || string.IsNullOrWhiteSpace(rom.CRC)) + || rom.MD5 == Constants.MD5Zero #if NET_FRAMEWORK - || itemRom.RIPEMD160 == Constants.RIPEMD160Zero + || rom.RIPEMD160 == Constants.RIPEMD160Zero #endif - || itemRom.SHA1 == Constants.SHA1Zero - || itemRom.SHA256 == Constants.SHA256Zero - || itemRom.SHA384 == Constants.SHA384Zero - || itemRom.SHA512 == Constants.SHA512Zero)) + || rom.SHA1 == Constants.SHA1Zero + || rom.SHA256 == Constants.SHA256Zero + || rom.SHA384 == Constants.SHA384Zero + || rom.SHA512 == Constants.SHA512Zero)) { // TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually - itemRom.Size = Constants.SizeZero; - itemRom.CRC = Constants.CRCZero; - itemRom.MD5 = Constants.MD5Zero; + rom.Size = Constants.SizeZero; + rom.CRC = Constants.CRCZero; + rom.MD5 = Constants.MD5Zero; #if NET_FRAMEWORK - itemRom.RIPEMD160 = null; - //itemRom.RIPEMD160 = Constants.RIPEMD160Zero; + rom.RIPEMD160 = null; // Constants.RIPEMD160Zero; #endif - itemRom.SHA1 = Constants.SHA1Zero; - itemRom.SHA256 = null; - //itemRom.SHA256 = Constants.SHA256Zero; - itemRom.SHA384 = null; - //itemRom.SHA384 = Constants.SHA384Zero; - itemRom.SHA512 = null; - //itemRom.SHA512 = Constants.SHA512Zero; + rom.SHA1 = Constants.SHA1Zero; + rom.SHA256 = null; // Constants.SHA256Zero; + rom.SHA384 = null; // Constants.SHA384Zero; + rom.SHA512 = null; // Constants.SHA512Zero; } + // If the file has no size and it's not the above case, skip and log - else if (itemRom.ItemStatus != ItemStatus.Nodump && (itemRom.Size == 0 || itemRom.Size == -1)) + else if (rom.ItemStatus != ItemStatus.Nodump && (rom.Size == 0 || rom.Size == -1)) { - Globals.Logger.Verbose($"{Header.FileName}: Incomplete entry for '{itemRom.Name}' will be output as nodump"); - itemRom.ItemStatus = ItemStatus.Nodump; + Globals.Logger.Verbose($"{Header.FileName}: Incomplete entry for '{rom.Name}' will be output as nodump"); + rom.ItemStatus = ItemStatus.Nodump; } + // If the file has a size but aboslutely no hashes, skip and log - else if (itemRom.ItemStatus != ItemStatus.Nodump - && itemRom.Size > 0 - && string.IsNullOrWhiteSpace(itemRom.CRC) - && string.IsNullOrWhiteSpace(itemRom.MD5) + else if (rom.ItemStatus != ItemStatus.Nodump + && rom.Size > 0 + && string.IsNullOrWhiteSpace(rom.CRC) + && string.IsNullOrWhiteSpace(rom.MD5) #if NET_FRAMEWORK - && string.IsNullOrWhiteSpace(itemRom.RIPEMD160) + && string.IsNullOrWhiteSpace(rom.RIPEMD160) #endif - && string.IsNullOrWhiteSpace(itemRom.SHA1) - && string.IsNullOrWhiteSpace(itemRom.SHA256) - && string.IsNullOrWhiteSpace(itemRom.SHA384) - && string.IsNullOrWhiteSpace(itemRom.SHA512)) + && string.IsNullOrWhiteSpace(rom.SHA1) + && string.IsNullOrWhiteSpace(rom.SHA256) + && string.IsNullOrWhiteSpace(rom.SHA384) + && string.IsNullOrWhiteSpace(rom.SHA512)) { - Globals.Logger.Verbose($"{Header.FileName}: Incomplete entry for '{itemRom.Name}' will be output as nodump"); - itemRom.ItemStatus = ItemStatus.Nodump; + Globals.Logger.Verbose($"{Header.FileName}: Incomplete entry for '{rom.Name}' will be output as nodump"); + rom.ItemStatus = ItemStatus.Nodump; } - item = itemRom; - } - else if (item.ItemType == ItemType.Disk) - { - Disk itemDisk = (Disk)item; - - // If the file has aboslutely no hashes, skip and log - if (itemDisk.ItemStatus != ItemStatus.Nodump - && string.IsNullOrWhiteSpace(itemDisk.MD5) -#if NET_FRAMEWORK - && string.IsNullOrWhiteSpace(itemDisk.RIPEMD160) -#endif - && string.IsNullOrWhiteSpace(itemDisk.SHA1) - && string.IsNullOrWhiteSpace(itemDisk.SHA256) - && string.IsNullOrWhiteSpace(itemDisk.SHA384) - && string.IsNullOrWhiteSpace(itemDisk.SHA512)) - { - Globals.Logger.Verbose($"Incomplete entry for '{itemDisk.Name}' will be output as nodump"); - itemDisk.ItemStatus = ItemStatus.Nodump; - } - - item = itemDisk; + item = rom; } // Get the key and add the file @@ -2349,7 +2341,13 @@ namespace SabreTools.Library.DatFiles private void ProcessFile(string item, string basePath, Hash omitFromScan, bool addDate, TreatAsFiles asFiles) { Globals.Logger.Verbose($"'{Path.GetFileName(item)}' treated like a file"); - BaseFile baseFile = FileExtensions.GetInfo(item, omitFromScan: omitFromScan, date: addDate, header: Header.HeaderSkipper, chdsAsFiles: asFiles.HasFlag(TreatAsFiles.CHDs)); + BaseFile baseFile = FileExtensions.GetInfo( + item, + omitFromScan: omitFromScan, + date: addDate, + header: Header.HeaderSkipper, + aaruFormatAsFiles: asFiles.HasFlag(TreatAsFiles.AaruFormats), + chdsAsFiles: asFiles.HasFlag(TreatAsFiles.CHDs)); ProcessFileHelper(item, DatItem.Create(baseFile), basePath, string.Empty); } @@ -2362,8 +2360,9 @@ namespace SabreTools.Library.DatFiles /// Parent game to be used private void ProcessFileHelper(string item, DatItem datItem, string basepath, string parent) { - // If we somehow got something other than a Rom or Disk, cancel out - if (datItem.ItemType != ItemType.Rom && datItem.ItemType != ItemType.Disk) + // If we didn't get an accepted parsed type somehow, cancel out + List parsed = new List { ItemType.Disk, ItemType.Media, ItemType.Rom }; + if (!parsed.Contains(datItem.ItemType)) return; try @@ -2401,7 +2400,7 @@ namespace SabreTools.Library.DatFiles private void SetDatItemInfo(DatItem datItem, string item, string parent, string basepath) { // Get the data to be added as game and item names - string gamename, romname; + string machineName, itemName; // If the parent is blank, then we have a non-archive file if (string.IsNullOrWhiteSpace(parent)) @@ -2409,15 +2408,15 @@ namespace SabreTools.Library.DatFiles // If we have a SuperDAT, we want anything that's not the base path as the game, and the file as the rom if (Header.Type == "SuperDAT") { - gamename = Path.GetDirectoryName(item.Remove(0, basepath.Length)); - romname = Path.GetFileName(item); + machineName = Path.GetDirectoryName(item.Remove(0, basepath.Length)); + itemName = Path.GetFileName(item); } // Otherwise, we want just the top level folder as the game, and the file as everything else else { - gamename = item.Remove(0, basepath.Length).Split(Path.DirectorySeparatorChar)[0]; - romname = item.Remove(0, (Path.Combine(basepath, gamename).Length)); + machineName = item.Remove(0, basepath.Length).Split(Path.DirectorySeparatorChar)[0]; + itemName = item.Remove(0, (Path.Combine(basepath, machineName).Length)); } } @@ -2427,36 +2426,58 @@ namespace SabreTools.Library.DatFiles // If we have a SuperDAT, we want the archive name as the game, and the file as everything else (?) if (Header.Type == "SuperDAT") { - gamename = parent; - romname = datItem.Name; + machineName = parent; + itemName = datItem.Name; } // Otherwise, we want the archive name as the game, and the file as everything else else { - gamename = parent; - romname = datItem.Name; + machineName = parent; + itemName = datItem.Name; } } // Sanitize the names - gamename = gamename.Trim(Path.DirectorySeparatorChar); - romname = romname?.Trim(Path.DirectorySeparatorChar) ?? string.Empty; + machineName = machineName.Trim(Path.DirectorySeparatorChar); + itemName = itemName?.Trim(Path.DirectorySeparatorChar) ?? string.Empty; - if (!string.IsNullOrWhiteSpace(gamename) && string.IsNullOrWhiteSpace(romname)) + if (!string.IsNullOrWhiteSpace(machineName) && string.IsNullOrWhiteSpace(itemName)) { - romname = gamename; - gamename = "Default"; + itemName = machineName; + machineName = "Default"; } - // Update rom information - datItem.Name = romname; - datItem.Machine.Name = gamename; - datItem.Machine.Description = gamename; + // Update machine information + datItem.Machine.Name = machineName; + datItem.Machine.Description = machineName; // If we have a Disk, then the ".chd" extension needs to be removed - if (datItem.ItemType == ItemType.Disk) - datItem.Name = datItem.Name.Replace(".chd", string.Empty); + if (datItem.ItemType == ItemType.Disk && datItem.Name.EndsWith(".chd")) + { + datItem.Name = itemName.Substring(0, itemName.Length - 4); + } + + // If we have a Media, then the extension needs to be removed + else if (datItem.ItemType == ItemType.Media) + { + if (datItem.Name.EndsWith(".dicf")) + datItem.Name = itemName.Substring(0, itemName.Length - 5); + else if (datItem.Name.EndsWith(".aaru")) + datItem.Name = itemName.Substring(0, itemName.Length - 5); + else if (datItem.Name.EndsWith(".aaruformat")) + datItem.Name = itemName.Substring(0, itemName.Length - 11); + else if (datItem.Name.EndsWith(".aaruf")) + datItem.Name = itemName.Substring(0, itemName.Length - 6); + else if (datItem.Name.EndsWith(".aif")) + datItem.Name = itemName.Substring(0, itemName.Length - 3); + } + + // All others leave the extension alone + else + { + datItem.Name = itemName; + } } #endregion @@ -2617,6 +2638,8 @@ namespace SabreTools.Library.DatFiles bool usedInternally; if (Items[hash][0].ItemType == ItemType.Disk) usedInternally = RebuildIndividualFile(new Disk(fileinfo), foundpath, outDir, date, inverse, outputFormat, updateDat, false /* isZip */); + else if (Items[hash][0].ItemType == ItemType.Media) + usedInternally = RebuildIndividualFile(new Media(fileinfo), foundpath, outDir, date, inverse, outputFormat, updateDat, false /* isZip */); else usedInternally = RebuildIndividualFile(new Rom(fileinfo), foundpath, outDir, date, inverse, outputFormat, updateDat, false /* isZip */); @@ -2810,11 +2833,17 @@ namespace SabreTools.Library.DatFiles // Scan the file externally // TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually - BaseFile externalFileInfo = FileExtensions.GetInfo(file, omitFromScan: (quickScan ? Hash.SecureHashes : Hash.DeepHashes), - header: Header.HeaderSkipper, chdsAsFiles: asFiles.HasFlag(TreatAsFiles.CHDs)); + BaseFile externalFileInfo = FileExtensions.GetInfo( + file, + omitFromScan: (quickScan ? Hash.SecureHashes : Hash.DeepHashes), + header: Header.HeaderSkipper, + aaruFormatAsFiles: asFiles.HasFlag(TreatAsFiles.AaruFormats), + chdsAsFiles: asFiles.HasFlag(TreatAsFiles.CHDs)); DatItem externalDatItem = null; - if (externalFileInfo.Type == FileType.CHD) + if (externalFileInfo.Type == FileType.AaruFormat) + externalDatItem = new Media(externalFileInfo); + else if (externalFileInfo.Type == FileType.CHD) externalDatItem = new Disk(externalFileInfo); else if (externalFileInfo.Type == FileType.None) externalDatItem = new Rom(externalFileInfo); @@ -2844,10 +2873,16 @@ namespace SabreTools.Library.DatFiles if (entries == null && File.Exists(file)) { // TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually - BaseFile internalFileInfo = FileExtensions.GetInfo(file, omitFromScan: (quickScan ? Hash.SecureHashes : Hash.DeepHashes), chdsAsFiles: asFiles.HasFlag(TreatAsFiles.CHDs)); + BaseFile internalFileInfo = FileExtensions.GetInfo( + file, + omitFromScan: (quickScan ? Hash.SecureHashes : Hash.DeepHashes), + aaruFormatAsFiles: asFiles.HasFlag(TreatAsFiles.AaruFormats), + chdsAsFiles: asFiles.HasFlag(TreatAsFiles.CHDs)); DatItem internalDatItem = null; - if (internalFileInfo.Type == FileType.CHD) + if (internalFileInfo.Type == FileType.AaruFormat) + internalDatItem = new Media(internalFileInfo); + else if (internalFileInfo.Type == FileType.CHD) internalDatItem = new Disk(internalFileInfo); else if (internalFileInfo.Type == FileType.None) internalDatItem = new Rom(internalFileInfo); @@ -2894,21 +2929,23 @@ namespace SabreTools.Library.DatFiles // Set the initial output value bool rebuilt = false; - // If the DatItem is a Disk, force rebuilding to a folder except if TGZ or TXZ - if (datItem.ItemType == ItemType.Disk + // If the DatItem is a Disk or Media, force rebuilding to a folder except if TGZ or TXZ + if ((datItem.ItemType == ItemType.Disk || datItem.ItemType == ItemType.Media) && !(outputFormat == OutputFormat.TorrentGzip || outputFormat == OutputFormat.TorrentGzipRomba) && !(outputFormat == OutputFormat.TorrentXZ || outputFormat == OutputFormat.TorrentXZRomba)) { outputFormat = OutputFormat.Folder; } - // If we have a disk, change it into a Rom for later use + // If we have a disk or media, change it into a Rom for later use if (datItem.ItemType == ItemType.Disk) - datItem = ((Disk)datItem).ConvertToRom(); + datItem = (datItem as Disk).ConvertToRom(); + if (datItem.ItemType == ItemType.Media) + datItem = (datItem as Media).ConvertToRom(); // Prepopluate a few key strings - string crc = ((Rom)datItem).CRC ?? string.Empty; - string sha1 = ((Rom)datItem).SHA1 ?? string.Empty; + string crc = (datItem as Rom).CRC ?? string.Empty; + string sha1 = (datItem as Rom).SHA1 ?? string.Empty; // Find if the file has duplicates in the DAT List dupes = Items.GetDuplicates(datItem, remove: updateDat); @@ -3027,7 +3064,7 @@ namespace SabreTools.Library.DatFiles Folder outputArchive = Folder.Create(outputFormat); // Now rebuild to the output file - outputArchive.Write(fileStream, outDir, (Rom)item, date: date, depth: Header.OutputDepot.Depth); + outputArchive.Write(fileStream, outDir, item as Rom, date: date, depth: Header.OutputDepot.Depth); } // Close the input stream @@ -3094,8 +3131,8 @@ namespace SabreTools.Library.DatFiles Folder outputArchive = Folder.Create(outputFormat); // Now rebuild to the output file - eitherSuccess |= outputArchive.Write(transformStream, outDir, (Rom)item, date: date, depth: Header.OutputDepot.Depth); - eitherSuccess |= outputArchive.Write(fileStream, outDir, (Rom)datItem, date: date, depth: Header.OutputDepot.Depth); + eitherSuccess |= outputArchive.Write(transformStream, outDir, item as Rom, date: date, depth: Header.OutputDepot.Depth); + eitherSuccess |= outputArchive.Write(fileStream, outDir, datItem as Rom, date: date, depth: Header.OutputDepot.Depth); // Now add the success of either rebuild rebuilt &= eitherSuccess; @@ -3253,13 +3290,17 @@ namespace SabreTools.Library.DatFiles var keys = Items.SortedKeys.ToList(); foreach (string key in keys) { - List roms = Items[key]; - foreach (DatItem rom in roms) + List items = Items[key]; + foreach (DatItem datItem in items) { - if (rom.Source.Index == 99) + if (datItem.Source.Index == 99) { - if (rom.ItemType == ItemType.Disk || rom.ItemType == ItemType.Rom) - matched.Items.Add(((Disk)rom).SHA1, rom); + if (datItem.ItemType == ItemType.Disk) + matched.Items.Add((datItem as Disk).SHA1, datItem); + else if (datItem.ItemType == ItemType.Media) + matched.Items.Add((datItem as Media).SHA1, datItem); + else if (datItem.ItemType == ItemType.Rom) + matched.Items.Add((datItem as Rom).SHA1, datItem); } } } @@ -3269,9 +3310,9 @@ namespace SabreTools.Library.DatFiles { foreach (string key in Items.Keys) { - List roms = Items[key]; - List newroms = DatItem.Merge(roms); - foreach (Rom rom in newroms) + List items = Items[key]; + List newItems = DatItem.Merge(items); + foreach (Rom rom in newItems) { if (rom.Source.Index == 99) matched.Items.Add($"{rom.Size}-{rom.CRC}", rom); @@ -3414,59 +3455,61 @@ namespace SabreTools.Library.DatFiles List items = Items[key]; foreach (DatItem item in items) { - // If the file is not a Rom or Disk, continue - if (item.ItemType != ItemType.Disk && item.ItemType != ItemType.Rom) + // If the file is not a Disk, Media, or Rom, continue + if (item.ItemType != ItemType.Disk && item.ItemType != ItemType.Media && item.ItemType != ItemType.Rom) return; // If the file is a nodump - if ((item.ItemType == ItemType.Rom && ((Rom)item).ItemStatus == ItemStatus.Nodump) - || (item.ItemType == ItemType.Disk && ((Disk)item).ItemStatus == ItemStatus.Nodump)) + if ((item.ItemType == ItemType.Rom && (item as Rom).ItemStatus == ItemStatus.Nodump) + || (item.ItemType == ItemType.Disk && (item as Disk).ItemStatus == ItemStatus.Nodump)) { nodump.Items.Add(key, item); } // If the file has a SHA-512 - else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace(((Rom)item).SHA512)) - || (item.ItemType == ItemType.Disk && !string.IsNullOrWhiteSpace(((Disk)item).SHA512))) + else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom).SHA512))) { sha512.Items.Add(key, item); } // If the file has a SHA-384 - else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace(((Rom)item).SHA384)) - || (item.ItemType == ItemType.Disk && !string.IsNullOrWhiteSpace(((Disk)item).SHA384))) + else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom).SHA384))) { sha384.Items.Add(key, item); } // If the file has a SHA-256 - else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace(((Rom)item).SHA256)) - || (item.ItemType == ItemType.Disk && !string.IsNullOrWhiteSpace(((Disk)item).SHA256))) + else if ((item.ItemType == ItemType.Media && !string.IsNullOrWhiteSpace((item as Media).SHA256)) + || (item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom).SHA256))) { sha256.Items.Add(key, item); } // If the file has a SHA-1 - else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace(((Rom)item).SHA1)) - || (item.ItemType == ItemType.Disk && !string.IsNullOrWhiteSpace(((Disk)item).SHA1))) + else if ((item.ItemType == ItemType.Disk && !string.IsNullOrWhiteSpace((item as Disk).SHA1)) + || (item.ItemType == ItemType.Media && !string.IsNullOrWhiteSpace((item as Media).SHA1)) + || (item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom).SHA1))) { sha1.Items.Add(key, item); } #if NET_FRAMEWORK // If the file has a RIPEMD160 - else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace(((Rom)item).RIPEMD160)) - || (item.ItemType == ItemType.Disk && !string.IsNullOrWhiteSpace(((Disk)item).RIPEMD160))) + else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom).RIPEMD160))) { ripemd160.Items.Add(key, item); } #endif // If the file has an MD5 - else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace(((Rom)item).MD5)) - || (item.ItemType == ItemType.Disk && !string.IsNullOrWhiteSpace(((Disk)item).MD5))) + else if ((item.ItemType == ItemType.Disk && !string.IsNullOrWhiteSpace((item as Disk).MD5)) + || (item.ItemType == ItemType.Media && !string.IsNullOrWhiteSpace((item as Media).MD5) + || (item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom).MD5))) + ) { md5.Items.Add(key, item); } + // If the file has a CRC - else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace(((Rom)item).CRC))) + else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom).CRC))) { crc.Items.Add(key, item); } + else { other.Items.Add(key, item); @@ -3617,11 +3660,11 @@ namespace SabreTools.Library.DatFiles lessDat.Items.Add(key, item); // If the file is a Rom and less than the radix, put it in the "lesser" dat - else if (item.ItemType == ItemType.Rom && ((Rom)item).Size < radix) + else if (item.ItemType == ItemType.Rom && (item as Rom).Size < radix) lessDat.Items.Add(key, item); // If the file is a Rom and greater than or equal to the radix, put it in the "greater" dat - else if (item.ItemType == ItemType.Rom && ((Rom)item).Size >= radix) + else if (item.ItemType == ItemType.Rom && (item as Rom).Size >= radix) greaterEqualDat.Items.Add(key, item); } }); @@ -3645,16 +3688,21 @@ namespace SabreTools.Library.DatFiles // Create each of the respective output DATs Globals.Logger.User("Creating and populating new DATs"); - DatFile romdat = Create(Header.CloneStandard()); - romdat.Header.FileName += " (ROM)"; - romdat.Header.Name += " (ROM)"; - romdat.Header.Description += " (ROM)"; - DatFile diskdat = Create(Header.CloneStandard()); diskdat.Header.FileName += " (Disk)"; diskdat.Header.Name += " (Disk)"; diskdat.Header.Description += " (Disk)"; + DatFile mediadat = Create(Header.CloneStandard()); + mediadat.Header.FileName += " (Media)"; + mediadat.Header.Name += " (Media)"; + mediadat.Header.Description += " (Media)"; + + DatFile romdat = Create(Header.CloneStandard()); + romdat.Header.FileName += " (Rom)"; + romdat.Header.Name += " (Rom)"; + romdat.Header.Description += " (Rom)"; + DatFile sampledat = Create(Header.CloneStandard()); sampledat.Header.FileName += " (Sample)"; sampledat.Header.Name += " (Sample)"; @@ -3666,14 +3714,18 @@ namespace SabreTools.Library.DatFiles List items = Items[key]; foreach (DatItem item in items) { - // If the file is a Rom - if (item.ItemType == ItemType.Rom) - romdat.Items.Add(key, item); - // If the file is a Disk - else if (item.ItemType == ItemType.Disk) + if (item.ItemType == ItemType.Disk) diskdat.Items.Add(key, item); + // If the file is a Media + else if (item.ItemType == ItemType.Media) + mediadat.Items.Add(key, item); + + // If the file is a Rom + else if (item.ItemType == ItemType.Rom) + romdat.Items.Add(key, item); + // If the file is a Sample else if (item.ItemType == ItemType.Sample) sampledat.Items.Add(key, item); @@ -3683,8 +3735,9 @@ namespace SabreTools.Library.DatFiles // Now, output all of the files to the output directory Globals.Logger.User("DAT information created, outputting new files"); bool success = true; - success &= romdat.Write(outDir); success &= diskdat.Write(outDir); + success &= mediadat.Write(outDir); + success &= romdat.Write(outDir); success &= sampledat.Write(outDir); return success; @@ -3843,28 +3896,40 @@ namespace SabreTools.Library.DatFiles // If we're in Depot mode, take care of that instead if (Header.OutputDepot?.IsActive ?? false) { - if (item.ItemType == ItemType.Rom) + if (item.ItemType == ItemType.Disk) { - Rom romItem = item as Rom; + Disk disk = item as Disk; // We can only write out if there's a SHA-1 - if (!string.IsNullOrWhiteSpace(romItem.SHA1)) + if (!string.IsNullOrWhiteSpace(disk.SHA1)) { - name = PathExtensions.GetDepotPath(romItem.SHA1, Header.OutputDepot.Depth).Replace('\\', '/'); - item.Name = $"{pre}{name}{post}"; - } - } - else if (item.ItemType == ItemType.Disk) - { - Disk diskItem = item as Disk; - - // We can only write out if there's a SHA-1 - if (!string.IsNullOrWhiteSpace(diskItem.SHA1)) - { - name = PathExtensions.GetDepotPath(diskItem.SHA1, Header.OutputDepot.Depth).Replace('\\', '/'); + name = PathExtensions.GetDepotPath(disk.SHA1, Header.OutputDepot.Depth).Replace('\\', '/'); item.Name = pre + name + post; } } + else if (item.ItemType == ItemType.Media) + { + Media media = item as Media; + + // We can only write out if there's a SHA-1 + if (!string.IsNullOrWhiteSpace(media.SHA1)) + { + name = PathExtensions.GetDepotPath(media.SHA1, Header.OutputDepot.Depth).Replace('\\', '/'); + item.Name = pre + name + post; + } + } + else if (item.ItemType == ItemType.Rom) + { + Rom rom = item as Rom; + + // We can only write out if there's a SHA-1 + if (!string.IsNullOrWhiteSpace(rom.SHA1)) + { + name = PathExtensions.GetDepotPath(rom.SHA1, Header.OutputDepot.Depth).Replace('\\', '/'); + item.Name = $"{pre}{name}{post}"; + } + } + return; } @@ -3926,29 +3991,29 @@ namespace SabreTools.Library.DatFiles fix = (Header.Quotes ? "\"" : string.Empty) + Header.Postfix; // Ensure we have the proper values for replacement - if (item.ItemType == ItemType.Rom) + if (item.ItemType == ItemType.Disk) { - crc = ((Rom)item).CRC ?? string.Empty; - md5 = ((Rom)item).MD5 ?? string.Empty; -#if NET_FRAMEWORK - ripemd160 = ((Rom)item).RIPEMD160 ?? string.Empty; -#endif - sha1 = ((Rom)item).SHA1 ?? string.Empty; - sha256 = ((Rom)item).SHA256 ?? string.Empty; - sha384 = ((Rom)item).SHA384 ?? string.Empty; - sha512 = ((Rom)item).SHA512 ?? string.Empty; - size = ((Rom)item).Size.ToString(); + md5 = (item as Disk).MD5 ?? string.Empty; + sha1 = (item as Disk).SHA1 ?? string.Empty; } - else if (item.ItemType == ItemType.Disk) + else if (item.ItemType == ItemType.Media) { - md5 = ((Disk)item).MD5 ?? string.Empty; + md5 = (item as Media).MD5 ?? string.Empty; + sha1 = (item as Media).SHA1 ?? string.Empty; + sha256 = (item as Media).SHA256 ?? string.Empty; + } + else if (item.ItemType == ItemType.Rom) + { + crc = (item as Rom).CRC ?? string.Empty; + md5 = (item as Rom).MD5 ?? string.Empty; #if NET_FRAMEWORK - ripemd160 = ((Disk)item).RIPEMD160 ?? string.Empty; + ripemd160 = (item as Rom).RIPEMD160 ?? string.Empty; #endif - sha1 = ((Disk)item).SHA1 ?? string.Empty; - sha256 = ((Disk)item).SHA256 ?? string.Empty; - sha384 = ((Disk)item).SHA384 ?? string.Empty; - sha512 = ((Disk)item).SHA512 ?? string.Empty; + sha1 = (item as Rom).SHA1 ?? string.Empty; + sha256 = (item as Rom).SHA256 ?? string.Empty; + sha384 = (item as Rom).SHA384 ?? string.Empty; + sha512 = (item as Rom).SHA512 ?? string.Empty; + size = (item as Rom).Size.ToString(); } // Now do bulk replacement where possible diff --git a/SabreTools.Library/DatFiles/DosCenter.cs b/SabreTools.Library/DatFiles/DosCenter.cs index 7beff913..79331f8f 100644 --- a/SabreTools.Library/DatFiles/DosCenter.cs +++ b/SabreTools.Library/DatFiles/DosCenter.cs @@ -7,7 +7,6 @@ using System.Text; using SabreTools.Library.Data; using SabreTools.Library.DatItems; using SabreTools.Library.IO; -using SabreTools.Library.Tools; namespace SabreTools.Library.DatFiles { @@ -324,22 +323,22 @@ namespace SabreTools.Library.DatFiles // If we have a "null" game (created by DATFromDir or something similar), log it to file if (rom.ItemType == ItemType.Rom - && ((Rom)rom).Size == -1 - && ((Rom)rom).CRC == "null") + && (rom as Rom).Size == -1 + && (rom as Rom).CRC == "null") { Globals.Logger.Verbose($"Empty folder found: {rom.Machine.Name}"); rom.Name = (rom.Name == "null" ? "-" : rom.Name); - ((Rom)rom).Size = Constants.SizeZero; - ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null; - ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null; + (rom as Rom).Size = Constants.SizeZero; + (rom as Rom).CRC = (rom as Rom).CRC == "null" ? Constants.CRCZero : null; + (rom as Rom).MD5 = (rom as Rom).MD5 == "null" ? Constants.MD5Zero : null; #if NET_FRAMEWORK - ((Rom)rom).RIPEMD160 = ((Rom)rom).RIPEMD160 == "null" ? Constants.RIPEMD160Zero : null; + (rom as Rom).RIPEMD160 = (rom as Rom).RIPEMD160 == "null" ? Constants.RIPEMD160Zero : null; #endif - ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null; - ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null; - ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null; - ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null; + (rom as Rom).SHA1 = (rom as Rom).SHA1 == "null" ? Constants.SHA1Zero : null; + (rom as Rom).SHA256 = (rom as Rom).SHA256 == "null" ? Constants.SHA256Zero : null; + (rom as Rom).SHA384 = (rom as Rom).SHA384 == "null" ? Constants.SHA384Zero : null; + (rom as Rom).SHA512 = (rom as Rom).SHA512 == "null" ? Constants.SHA512Zero : null; } // Now, output the rom data diff --git a/SabreTools.Library/DatFiles/Enums.cs b/SabreTools.Library/DatFiles/Enums.cs index 60111ec5..6896e965 100644 --- a/SabreTools.Library/DatFiles/Enums.cs +++ b/SabreTools.Library/DatFiles/Enums.cs @@ -255,5 +255,6 @@ namespace SabreTools.Library.DatFiles { CHDs = 1 << 0, Archives = 1 << 1, + AaruFormats = 1 << 2, } } diff --git a/SabreTools.Library/DatFiles/Hashfile.cs b/SabreTools.Library/DatFiles/Hashfile.cs index 1c100613..204f51e2 100644 --- a/SabreTools.Library/DatFiles/Hashfile.cs +++ b/SabreTools.Library/DatFiles/Hashfile.cs @@ -6,7 +6,6 @@ using System.Text; using SabreTools.Library.Data; using SabreTools.Library.DatItems; using SabreTools.Library.IO; -using SabreTools.Library.Tools; namespace SabreTools.Library.DatFiles { @@ -205,6 +204,14 @@ namespace SabreTools.Library.DatFiles name += disk.Name; break; + case ItemType.Media: + var media = datItem as Media; + if (Header.GameName) + name = $"{media.Machine.Name}{Path.DirectorySeparatorChar}"; + + name += media.Name; + break; + case ItemType.Rom: var rom = datItem as Rom; if (Header.GameName) @@ -239,6 +246,12 @@ namespace SabreTools.Library.DatFiles fields[1] = name; break; + case ItemType.Media: + var media = datItem as Media; + fields[0] = media.MD5; + fields[1] = name; + break; + case ItemType.Rom: var rom = datItem as Rom; fields[0] = rom.MD5; @@ -252,12 +265,6 @@ namespace SabreTools.Library.DatFiles case Hash.RIPEMD160: switch (datItem.ItemType) { - case ItemType.Disk: - var disk = datItem as Disk; - fields[0] = disk.RIPEMD160; - fields[1] = name; - break; - case ItemType.Rom: var rom = datItem as Rom; fields[0] = rom.RIPEMD160; @@ -276,6 +283,12 @@ namespace SabreTools.Library.DatFiles fields[1] = name; break; + case ItemType.Media: + var media = datItem as Media; + fields[0] = media.SHA1; + fields[1] = name; + break; + case ItemType.Rom: var rom = datItem as Rom; fields[0] = rom.SHA1; @@ -288,9 +301,9 @@ namespace SabreTools.Library.DatFiles case Hash.SHA256: switch (datItem.ItemType) { - case ItemType.Disk: - var disk = datItem as Disk; - fields[0] = disk.SHA256; + case ItemType.Media: + var media = datItem as Media; + fields[0] = media.SHA256; fields[1] = name; break; @@ -306,12 +319,6 @@ namespace SabreTools.Library.DatFiles case Hash.SHA384: switch (datItem.ItemType) { - case ItemType.Disk: - var disk = datItem as Disk; - fields[0] = disk.SHA384; - fields[1] = name; - break; - case ItemType.Rom: var rom = datItem as Rom; fields[0] = rom.SHA384; @@ -324,12 +331,6 @@ namespace SabreTools.Library.DatFiles case Hash.SHA512: switch (datItem.ItemType) { - case ItemType.Disk: - var disk = datItem as Disk; - fields[0] = disk.SHA512; - fields[1] = name; - break; - case ItemType.Rom: var rom = datItem as Rom; fields[0] = rom.SHA512; diff --git a/SabreTools.Library/DatFiles/ItemDictionary.cs b/SabreTools.Library/DatFiles/ItemDictionary.cs index d4a90d92..cb919091 100644 --- a/SabreTools.Library/DatFiles/ItemDictionary.cs +++ b/SabreTools.Library/DatFiles/ItemDictionary.cs @@ -100,6 +100,12 @@ namespace SabreTools.Library.DatFiles [JsonIgnore] public long DiskCount { get; private set; } = 0; + /// + /// Number of Media items + /// + [JsonIgnore] + public long MediaCount { get; private set; } = 0; + /// /// Number of Release items /// @@ -399,46 +405,46 @@ namespace SabreTools.Library.DatFiles break; case ItemType.Disk: DiskCount += 1; - if (((Disk)item).ItemStatus != ItemStatus.Nodump) + if ((item as Disk).ItemStatus != ItemStatus.Nodump) { - MD5Count += (string.IsNullOrWhiteSpace(((Disk)item).MD5) ? 0 : 1); -#if NET_FRAMEWORK - RIPEMD160Count += (string.IsNullOrWhiteSpace(((Disk)item).RIPEMD160) ? 0 : 1); -#endif - SHA1Count += (string.IsNullOrWhiteSpace(((Disk)item).SHA1) ? 0 : 1); - SHA256Count += (string.IsNullOrWhiteSpace(((Disk)item).SHA256) ? 0 : 1); - SHA384Count += (string.IsNullOrWhiteSpace(((Disk)item).SHA384) ? 0 : 1); - SHA512Count += (string.IsNullOrWhiteSpace(((Disk)item).SHA512) ? 0 : 1); + MD5Count += (string.IsNullOrWhiteSpace((item as Disk).MD5) ? 0 : 1); + SHA1Count += (string.IsNullOrWhiteSpace((item as Disk).SHA1) ? 0 : 1); } - BaddumpCount += (((Disk)item).ItemStatus == ItemStatus.BadDump ? 1 : 0); - GoodCount += (((Disk)item).ItemStatus == ItemStatus.Good ? 1 : 0); - NodumpCount += (((Disk)item).ItemStatus == ItemStatus.Nodump ? 1 : 0); - VerifiedCount += (((Disk)item).ItemStatus == ItemStatus.Verified ? 1 : 0); + BaddumpCount += ((item as Disk).ItemStatus == ItemStatus.BadDump ? 1 : 0); + GoodCount += ((item as Disk).ItemStatus == ItemStatus.Good ? 1 : 0); + NodumpCount += ((item as Disk).ItemStatus == ItemStatus.Nodump ? 1 : 0); + VerifiedCount += ((item as Disk).ItemStatus == ItemStatus.Verified ? 1 : 0); + break; + case ItemType.Media: + MediaCount += 1; + MD5Count += (string.IsNullOrWhiteSpace((item as Media).MD5) ? 0 : 1); + SHA1Count += (string.IsNullOrWhiteSpace((item as Media).SHA1) ? 0 : 1); + SHA256Count += (string.IsNullOrWhiteSpace((item as Media).SHA256) ? 0 : 1); break; case ItemType.Release: ReleaseCount += 1; break; case ItemType.Rom: RomCount += 1; - if (((Rom)item).ItemStatus != ItemStatus.Nodump) + if ((item as Rom).ItemStatus != ItemStatus.Nodump) { - TotalSize += ((Rom)item).Size; - CRCCount += (string.IsNullOrWhiteSpace(((Rom)item).CRC) ? 0 : 1); - MD5Count += (string.IsNullOrWhiteSpace(((Rom)item).MD5) ? 0 : 1); + TotalSize += (item as Rom).Size; + CRCCount += (string.IsNullOrWhiteSpace((item as Rom).CRC) ? 0 : 1); + MD5Count += (string.IsNullOrWhiteSpace((item as Rom).MD5) ? 0 : 1); #if NET_FRAMEWORK - RIPEMD160Count += (string.IsNullOrWhiteSpace(((Rom)item).RIPEMD160) ? 0 : 1); + RIPEMD160Count += (string.IsNullOrWhiteSpace((item as Rom).RIPEMD160) ? 0 : 1); #endif - SHA1Count += (string.IsNullOrWhiteSpace(((Rom)item).SHA1) ? 0 : 1); - SHA256Count += (string.IsNullOrWhiteSpace(((Rom)item).SHA256) ? 0 : 1); - SHA384Count += (string.IsNullOrWhiteSpace(((Rom)item).SHA384) ? 0 : 1); - SHA512Count += (string.IsNullOrWhiteSpace(((Rom)item).SHA512) ? 0 : 1); + SHA1Count += (string.IsNullOrWhiteSpace((item as Rom).SHA1) ? 0 : 1); + SHA256Count += (string.IsNullOrWhiteSpace((item as Rom).SHA256) ? 0 : 1); + SHA384Count += (string.IsNullOrWhiteSpace((item as Rom).SHA384) ? 0 : 1); + SHA512Count += (string.IsNullOrWhiteSpace((item as Rom).SHA512) ? 0 : 1); } - BaddumpCount += (((Rom)item).ItemStatus == ItemStatus.BadDump ? 1 : 0); - GoodCount += (((Rom)item).ItemStatus == ItemStatus.Good ? 1 : 0); - NodumpCount += (((Rom)item).ItemStatus == ItemStatus.Nodump ? 1 : 0); - VerifiedCount += (((Rom)item).ItemStatus == ItemStatus.Verified ? 1 : 0); + BaddumpCount += ((item as Rom).ItemStatus == ItemStatus.BadDump ? 1 : 0); + GoodCount += ((item as Rom).ItemStatus == ItemStatus.Good ? 1 : 0); + NodumpCount += ((item as Rom).ItemStatus == ItemStatus.Nodump ? 1 : 0); + VerifiedCount += ((item as Rom).ItemStatus == ItemStatus.Verified ? 1 : 0); break; case ItemType.Sample: SampleCount += 1; @@ -456,7 +462,9 @@ namespace SabreTools.Library.DatFiles ArchiveCount += stats.ArchiveCount; BiosSetCount += stats.BiosSetCount; + ChipCount += stats.ChipCount; DiskCount += stats.DiskCount; + MediaCount += stats.MediaCount; ReleaseCount += stats.ReleaseCount; RomCount += stats.RomCount; SampleCount += stats.SampleCount; @@ -522,46 +530,46 @@ namespace SabreTools.Library.DatFiles break; case ItemType.Disk: DiskCount -= 1; - if (((Disk)item).ItemStatus != ItemStatus.Nodump) + if ((item as Disk).ItemStatus != ItemStatus.Nodump) { - MD5Count -= (string.IsNullOrWhiteSpace(((Disk)item).MD5) ? 0 : 1); -#if NET_FRAMEWORK - RIPEMD160Count -= (string.IsNullOrWhiteSpace(((Disk)item).RIPEMD160) ? 0 : 1); -#endif - SHA1Count -= (string.IsNullOrWhiteSpace(((Disk)item).SHA1) ? 0 : 1); - SHA256Count -= (string.IsNullOrWhiteSpace(((Disk)item).SHA256) ? 0 : 1); - SHA384Count -= (string.IsNullOrWhiteSpace(((Disk)item).SHA384) ? 0 : 1); - SHA512Count -= (string.IsNullOrWhiteSpace(((Disk)item).SHA512) ? 0 : 1); + MD5Count -= (string.IsNullOrWhiteSpace((item as Disk).MD5) ? 0 : 1); + SHA1Count -= (string.IsNullOrWhiteSpace((item as Disk).SHA1) ? 0 : 1); } - BaddumpCount -= (((Disk)item).ItemStatus == ItemStatus.BadDump ? 1 : 0); - GoodCount -= (((Disk)item).ItemStatus == ItemStatus.Good ? 1 : 0); - NodumpCount -= (((Disk)item).ItemStatus == ItemStatus.Nodump ? 1 : 0); - VerifiedCount -= (((Disk)item).ItemStatus == ItemStatus.Verified ? 1 : 0); + BaddumpCount -= ((item as Disk).ItemStatus == ItemStatus.BadDump ? 1 : 0); + GoodCount -= ((item as Disk).ItemStatus == ItemStatus.Good ? 1 : 0); + NodumpCount -= ((item as Disk).ItemStatus == ItemStatus.Nodump ? 1 : 0); + VerifiedCount -= ((item as Disk).ItemStatus == ItemStatus.Verified ? 1 : 0); + break; + case ItemType.Media: + MediaCount -= 1; + MD5Count -= (string.IsNullOrWhiteSpace((item as Media).MD5) ? 0 : 1); + SHA1Count -= (string.IsNullOrWhiteSpace((item as Media).SHA1) ? 0 : 1); + SHA256Count -= (string.IsNullOrWhiteSpace((item as Media).SHA256) ? 0 : 1); break; case ItemType.Release: ReleaseCount -= 1; break; case ItemType.Rom: RomCount -= 1; - if (((Rom)item).ItemStatus != ItemStatus.Nodump) + if ((item as Rom).ItemStatus != ItemStatus.Nodump) { - TotalSize -= ((Rom)item).Size; - CRCCount -= (string.IsNullOrWhiteSpace(((Rom)item).CRC) ? 0 : 1); - MD5Count -= (string.IsNullOrWhiteSpace(((Rom)item).MD5) ? 0 : 1); + TotalSize -= (item as Rom).Size; + CRCCount -= (string.IsNullOrWhiteSpace((item as Rom).CRC) ? 0 : 1); + MD5Count -= (string.IsNullOrWhiteSpace((item as Rom).MD5) ? 0 : 1); #if NET_FRAMEWORK - RIPEMD160Count -= (string.IsNullOrWhiteSpace(((Rom)item).RIPEMD160) ? 0 : 1); + RIPEMD160Count -= (string.IsNullOrWhiteSpace((item as Rom).RIPEMD160) ? 0 : 1); #endif - SHA1Count -= (string.IsNullOrWhiteSpace(((Rom)item).SHA1) ? 0 : 1); - SHA256Count -= (string.IsNullOrWhiteSpace(((Rom)item).SHA256) ? 0 : 1); - SHA384Count -= (string.IsNullOrWhiteSpace(((Rom)item).SHA384) ? 0 : 1); - SHA512Count -= (string.IsNullOrWhiteSpace(((Rom)item).SHA512) ? 0 : 1); + SHA1Count -= (string.IsNullOrWhiteSpace((item as Rom).SHA1) ? 0 : 1); + SHA256Count -= (string.IsNullOrWhiteSpace((item as Rom).SHA256) ? 0 : 1); + SHA384Count -= (string.IsNullOrWhiteSpace((item as Rom).SHA384) ? 0 : 1); + SHA512Count -= (string.IsNullOrWhiteSpace((item as Rom).SHA512) ? 0 : 1); } - BaddumpCount -= (((Rom)item).ItemStatus == ItemStatus.BadDump ? 1 : 0); - GoodCount -= (((Rom)item).ItemStatus == ItemStatus.Good ? 1 : 0); - NodumpCount -= (((Rom)item).ItemStatus == ItemStatus.Nodump ? 1 : 0); - VerifiedCount -= (((Rom)item).ItemStatus == ItemStatus.Verified ? 1 : 0); + BaddumpCount -= ((item as Rom).ItemStatus == ItemStatus.BadDump ? 1 : 0); + GoodCount -= ((item as Rom).ItemStatus == ItemStatus.Good ? 1 : 0); + NodumpCount -= ((item as Rom).ItemStatus == ItemStatus.Nodump ? 1 : 0); + VerifiedCount -= ((item as Rom).ItemStatus == ItemStatus.Verified ? 1 : 0); break; case ItemType.Sample: SampleCount -= 1; @@ -817,29 +825,29 @@ namespace SabreTools.Library.DatFiles private Field GetBestAvailable() { // If all items are supposed to have a SHA-512, we bucket by that - if (RomCount + DiskCount - NodumpCount == SHA512Count) + if (DiskCount + MediaCount + RomCount - NodumpCount == SHA512Count) return Field.DatItem_SHA512; // If all items are supposed to have a SHA-384, we bucket by that - else if (RomCount + DiskCount - NodumpCount == SHA384Count) + else if (DiskCount + MediaCount + RomCount - NodumpCount == SHA384Count) return Field.DatItem_SHA384; // If all items are supposed to have a SHA-256, we bucket by that - else if (RomCount + DiskCount - NodumpCount == SHA256Count) + else if (DiskCount + MediaCount + RomCount - NodumpCount == SHA256Count) return Field.DatItem_SHA256; // If all items are supposed to have a SHA-1, we bucket by that - else if (RomCount + DiskCount - NodumpCount == SHA1Count) + else if (DiskCount + MediaCount + RomCount - NodumpCount == SHA1Count) return Field.DatItem_SHA1; #if NET_FRAMEWORK // If all items are supposed to have a RIPEMD160, we bucket by that - else if (RomCount + DiskCount - NodumpCount == RIPEMD160Count) + else if (DiskCount + MediaCount + RomCount - NodumpCount == RIPEMD160Count) return Field.DatItem_RIPEMD160; #endif // If all items are supposed to have a MD5, we bucket by that - else if (RomCount + DiskCount - NodumpCount == MD5Count) + else if (DiskCount + MediaCount + RomCount - NodumpCount == MD5Count) return Field.DatItem_MD5; // Otherwise, we bucket by CRC @@ -856,7 +864,9 @@ namespace SabreTools.Library.DatFiles ArchiveCount = 0; BiosSetCount = 0; + ChipCount = 0; DiskCount = 0; + MediaCount = 0; ReleaseCount = 0; RomCount = 0; SampleCount = 0; diff --git a/SabreTools.Library/DatFiles/Json.cs b/SabreTools.Library/DatFiles/Json.cs index 014f4ad5..d67237a1 100644 --- a/SabreTools.Library/DatFiles/Json.cs +++ b/SabreTools.Library/DatFiles/Json.cs @@ -238,6 +238,9 @@ namespace SabreTools.Library.DatFiles case ItemType.Disk: datItem = datItemObj.ToObject(); break; + case ItemType.Media: + datItem = datItemObj.ToObject(); + break; case ItemType.Release: datItem = datItemObj.ToObject(); break; @@ -322,22 +325,22 @@ namespace SabreTools.Library.DatFiles // If we have a "null" game (created by DATFromDir or something similar), log it to file if (rom.ItemType == ItemType.Rom - && ((Rom)rom).Size == -1 - && ((Rom)rom).CRC == "null") + && (rom as Rom).Size == -1 + && (rom as Rom).CRC == "null") { Globals.Logger.Verbose($"Empty folder found: {rom.Machine.Name}"); rom.Name = (rom.Name == "null" ? "-" : rom.Name); - ((Rom)rom).Size = Constants.SizeZero; - ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null; - ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null; + (rom as Rom).Size = Constants.SizeZero; + (rom as Rom).CRC = (rom as Rom).CRC == "null" ? Constants.CRCZero : null; + (rom as Rom).MD5 = (rom as Rom).MD5 == "null" ? Constants.MD5Zero : null; #if NET_FRAMEWORK - ((Rom)rom).RIPEMD160 = ((Rom)rom).RIPEMD160 == "null" ? Constants.RIPEMD160Zero : null; + (rom as Rom).RIPEMD160 = (rom as Rom).RIPEMD160 == "null" ? Constants.RIPEMD160Zero : null; #endif - ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null; - ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null; - ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null; - ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null; + (rom as Rom).SHA1 = (rom as Rom).SHA1 == "null" ? Constants.SHA1Zero : null; + (rom as Rom).SHA256 = (rom as Rom).SHA256 == "null" ? Constants.SHA256Zero : null; + (rom as Rom).SHA384 = (rom as Rom).SHA384 == "null" ? Constants.SHA384Zero : null; + (rom as Rom).SHA512 = (rom as Rom).SHA512 == "null" ? Constants.SHA512Zero : null; } // Now, output the rom data diff --git a/SabreTools.Library/DatFiles/Listrom.cs b/SabreTools.Library/DatFiles/Listrom.cs index 6b2d832a..5828947d 100644 --- a/SabreTools.Library/DatFiles/Listrom.cs +++ b/SabreTools.Library/DatFiles/Listrom.cs @@ -318,19 +318,19 @@ namespace SabreTools.Library.DatFiles // If we have a "null" game (created by DATFromDir or something similar), log it to file if (rom.ItemType == ItemType.Rom - && ((Rom)rom).Size == -1 - && ((Rom)rom).CRC == "null") + && (rom as Rom).Size == -1 + && (rom as Rom).CRC == "null") { Globals.Logger.Verbose($"Empty folder found: {rom.Machine.Name}"); rom.Name = (rom.Name == "null" ? "-" : rom.Name); - ((Rom)rom).Size = Constants.SizeZero; - ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null; - ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null; - ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null; - ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null; - ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null; - ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null; + (rom as Rom).Size = Constants.SizeZero; + (rom as Rom).CRC = (rom as Rom).CRC == "null" ? Constants.CRCZero : null; + (rom as Rom).MD5 = (rom as Rom).MD5 == "null" ? Constants.MD5Zero : null; + (rom as Rom).SHA1 = (rom as Rom).SHA1 == "null" ? Constants.SHA1Zero : null; + (rom as Rom).SHA256 = (rom as Rom).SHA256 == "null" ? Constants.SHA256Zero : null; + (rom as Rom).SHA384 = (rom as Rom).SHA384 == "null" ? Constants.SHA384Zero : null; + (rom as Rom).SHA512 = (rom as Rom).SHA512 == "null" ? Constants.SHA512Zero : null; } // Now, output the rom data diff --git a/SabreTools.Library/DatFiles/Listxml.cs b/SabreTools.Library/DatFiles/Listxml.cs index 9302fc8a..6e264fa7 100644 --- a/SabreTools.Library/DatFiles/Listxml.cs +++ b/SabreTools.Library/DatFiles/Listxml.cs @@ -230,13 +230,7 @@ namespace SabreTools.Library.DatFiles { Name = reader.GetAttribute("name"), MD5 = reader.GetAttribute("md5"), -#if NET_FRAMEWORK - RIPEMD160 = reader.GetAttribute("ripemd160"), -#endif SHA1 = reader.GetAttribute("sha1"), - SHA256 = reader.GetAttribute("sha256"), - SHA384 = reader.GetAttribute("sha384"), - SHA512 = reader.GetAttribute("sha512"), MergeTag = reader.GetAttribute("merge"), Region = reader.GetAttribute("region"), Index = reader.GetAttribute("index"), @@ -1560,13 +1554,7 @@ namespace SabreTools.Library.DatFiles xtw.WriteStartElement("disk"); xtw.WriteRequiredAttributeString("name", disk.Name); xtw.WriteOptionalAttributeString("md5", disk.MD5?.ToLowerInvariant()); -#if NET_FRAMEWORK - xtw.WriteOptionalAttributeString("ripemd160", disk.RIPEMD160?.ToLowerInvariant()); -#endif xtw.WriteOptionalAttributeString("sha1", disk.SHA1?.ToLowerInvariant()); - xtw.WriteOptionalAttributeString("sha256", disk.SHA256?.ToLowerInvariant()); - xtw.WriteOptionalAttributeString("sha384", disk.SHA384?.ToLowerInvariant()); - xtw.WriteOptionalAttributeString("sha512", disk.SHA512?.ToLowerInvariant()); xtw.WriteOptionalAttributeString("merge", disk.MergeTag); xtw.WriteOptionalAttributeString("region", disk.Region); xtw.WriteOptionalAttributeString("index", disk.Index); diff --git a/SabreTools.Library/DatFiles/Logiqx.cs b/SabreTools.Library/DatFiles/Logiqx.cs index 8000f399..b7366ab1 100644 --- a/SabreTools.Library/DatFiles/Logiqx.cs +++ b/SabreTools.Library/DatFiles/Logiqx.cs @@ -237,13 +237,13 @@ namespace SabreTools.Library.DatFiles if (Header.System == null) Header.System = reader.GetAttribute("plugin"); - if (Header.RomMode == null) + if (Header.RomMode == MergingFlag.None) Header.RomMode = reader.GetAttribute("rommode").AsMergingFlag(); - if (Header.BiosMode == null) + if (Header.BiosMode == MergingFlag.None) Header.BiosMode = reader.GetAttribute("biosmode").AsMergingFlag(); - if (Header.SampleMode == null) + if (Header.SampleMode == MergingFlag.None) Header.SampleMode = reader.GetAttribute("samplemode").AsMergingFlag(); if (Header.LockRomMode == null) @@ -372,6 +372,128 @@ namespace SabreTools.Library.DatFiles reader.Skip(); break; + case "archive": + containsItems = true; + + DatItem archive = new Archive + { + Name = reader.GetAttribute("name"), + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + archive.CopyMachineInformation(machine); + + // Now process and add the archive + key = ParseAddHelper(archive); + + reader.Read(); + break; + + case "biosset": + containsItems = true; + + DatItem biosSet = new BiosSet + { + Name = reader.GetAttribute("name"), + Description = reader.GetAttribute("description"), + Default = reader.GetAttribute("default").AsYesNo(), + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + biosSet.CopyMachineInformation(machine); + + // Now process and add the biosSet + key = ParseAddHelper(biosSet); + + reader.Read(); + break; + + case "chip": + containsItems = true; + + DatItem chip = new Chip + { + Name = reader.GetAttribute("name"), + Tag = reader.GetAttribute("tag"), + ChipType = reader.GetAttribute("type"), + Clock = reader.GetAttribute("clock"), + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + chip.CopyMachineInformation(machine); + + // Now process and add the chip + key = ParseAddHelper(chip); + + reader.Read(); + break; + + case "disk": + containsItems = true; + + DatItem disk = new Disk + { + Name = reader.GetAttribute("name"), + MD5 = reader.GetAttribute("md5"), + SHA1 = reader.GetAttribute("sha1"), + MergeTag = reader.GetAttribute("merge"), + ItemStatus = reader.GetAttribute("status").AsItemStatus(), + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + disk.CopyMachineInformation(machine); + + // Now process and add the disk + key = ParseAddHelper(disk); + + reader.Read(); + break; + + case "media": + containsItems = true; + + DatItem media = new Media + { + Name = reader.GetAttribute("name"), + MD5 = reader.GetAttribute("md5"), + SHA1 = reader.GetAttribute("sha1"), + SHA256 = reader.GetAttribute("sha256"), + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + + media.CopyMachineInformation(machine); + + // Now process and add the media + key = ParseAddHelper(media); + + reader.Read(); + break; + case "release": containsItems = true; @@ -386,36 +508,12 @@ namespace SabreTools.Library.DatFiles release.CopyMachineInformation(machine); - // Now process and add the rom + // Now process and add the release key = ParseAddHelper(release); reader.Read(); break; - case "biosset": - containsItems = true; - - DatItem biosset = new BiosSet - { - Name = reader.GetAttribute("name"), - Description = reader.GetAttribute("description"), - Default = reader.GetAttribute("default").AsYesNo(), - - Source = new Source - { - Index = indexId, - Name = filename, - }, - }; - - biosset.CopyMachineInformation(machine); - - // Now process and add the rom - key = ParseAddHelper(biosset); - - reader.Read(); - break; - case "rom": containsItems = true; @@ -452,42 +550,10 @@ namespace SabreTools.Library.DatFiles reader.Read(); break; - case "disk": - containsItems = true; - - DatItem disk = new Disk - { - Name = reader.GetAttribute("name"), - MD5 = reader.GetAttribute("md5"), -#if NET_FRAMEWORK - RIPEMD160 = reader.GetAttribute("ripemd160"), -#endif - SHA1 = reader.GetAttribute("sha1"), - SHA256 = reader.GetAttribute("sha256"), - SHA384 = reader.GetAttribute("sha384"), - SHA512 = reader.GetAttribute("sha512"), - MergeTag = reader.GetAttribute("merge"), - ItemStatus = reader.GetAttribute("status").AsItemStatus(), - - Source = new Source - { - Index = indexId, - Name = filename, - }, - }; - - disk.CopyMachineInformation(machine); - - // Now process and add the rom - key = ParseAddHelper(disk); - - reader.Read(); - break; - case "sample": containsItems = true; - DatItem samplerom = new Sample + DatItem sample = new Sample { Name = reader.GetAttribute("name"), @@ -498,57 +564,10 @@ namespace SabreTools.Library.DatFiles }, }; - samplerom.CopyMachineInformation(machine); + sample.CopyMachineInformation(machine); - // Now process and add the rom - key = ParseAddHelper(samplerom); - - reader.Read(); - break; - - case "archive": - containsItems = true; - - DatItem archiverom = new Archive - { - Name = reader.GetAttribute("name"), - - Source = new Source - { - Index = indexId, - Name = filename, - }, - }; - - archiverom.CopyMachineInformation(machine); - - // Now process and add the rom - key = ParseAddHelper(archiverom); - - reader.Read(); - break; - - case "chip": - containsItems = true; - - DatItem chiprom = new Chip - { - Name = reader.GetAttribute("name"), - Tag = reader.GetAttribute("tag"), - ChipType = reader.GetAttribute("type"), - Clock = reader.GetAttribute("clock"), - - Source = new Source - { - Index = indexId, - Name = filename, - }, - }; - - chiprom.CopyMachineInformation(machine); - - // Now process and add the rom - key = ParseAddHelper(chiprom); + // Now process and add the sample + key = ParseAddHelper(sample); reader.Read(); break; @@ -729,22 +748,22 @@ namespace SabreTools.Library.DatFiles // If we have a "null" game (created by DATFromDir or something similar), log it to file if (rom.ItemType == ItemType.Rom - && ((Rom)rom).Size == -1 - && ((Rom)rom).CRC == "null") + && (rom as Rom).Size == -1 + && (rom as Rom).CRC == "null") { Globals.Logger.Verbose($"Empty folder found: {rom.Machine.Name}"); rom.Name = (rom.Name == "null" ? "-" : rom.Name); - ((Rom)rom).Size = Constants.SizeZero; - ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null; - ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null; + (rom as Rom).Size = Constants.SizeZero; + (rom as Rom).CRC = (rom as Rom).CRC == "null" ? Constants.CRCZero : null; + (rom as Rom).MD5 = (rom as Rom).MD5 == "null" ? Constants.MD5Zero : null; #if NET_FRAMEWORK - ((Rom)rom).RIPEMD160 = ((Rom)rom).RIPEMD160 == "null" ? Constants.RIPEMD160Zero : null; + (rom as Rom).RIPEMD160 = (rom as Rom).RIPEMD160 == "null" ? Constants.RIPEMD160Zero : null; #endif - ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null; - ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null; - ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null; - ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null; + (rom as Rom).SHA1 = (rom as Rom).SHA1 == "null" ? Constants.SHA1Zero : null; + (rom as Rom).SHA256 = (rom as Rom).SHA256 == "null" ? Constants.SHA256Zero : null; + (rom as Rom).SHA384 = (rom as Rom).SHA384 == "null" ? Constants.SHA384Zero : null; + (rom as Rom).SHA512 = (rom as Rom).SHA512 == "null" ? Constants.SHA512Zero : null; } // Now, output the rom data @@ -1008,17 +1027,21 @@ namespace SabreTools.Library.DatFiles xtw.WriteStartElement("disk"); xtw.WriteRequiredAttributeString("name", disk.Name); xtw.WriteOptionalAttributeString("md5", disk.MD5?.ToLowerInvariant()); -#if NET_FRAMEWORK - xtw.WriteOptionalAttributeString("ripemd160", disk.RIPEMD160?.ToLowerInvariant()); -#endif xtw.WriteOptionalAttributeString("sha1", disk.SHA1?.ToLowerInvariant()); - xtw.WriteOptionalAttributeString("sha256", disk.SHA256?.ToLowerInvariant()); - xtw.WriteOptionalAttributeString("sha384", disk.SHA384?.ToLowerInvariant()); - xtw.WriteOptionalAttributeString("sha512", disk.SHA512?.ToLowerInvariant()); xtw.WriteOptionalAttributeString("status", disk.ItemStatus.FromItemStatus(false)); xtw.WriteEndElement(); break; + case ItemType.Media: + var media = datItem as Media; + xtw.WriteStartElement("media"); + xtw.WriteRequiredAttributeString("name", media.Name); + xtw.WriteOptionalAttributeString("md5", media.MD5?.ToLowerInvariant()); + xtw.WriteOptionalAttributeString("sha1", media.SHA1?.ToLowerInvariant()); + xtw.WriteOptionalAttributeString("sha256", media.SHA256?.ToLowerInvariant()); + xtw.WriteEndElement(); + break; + case ItemType.Release: var release = datItem as Release; xtw.WriteStartElement("release"); diff --git a/SabreTools.Library/DatFiles/Missfile.cs b/SabreTools.Library/DatFiles/Missfile.cs index 6d06ae65..6ef017c3 100644 --- a/SabreTools.Library/DatFiles/Missfile.cs +++ b/SabreTools.Library/DatFiles/Missfile.cs @@ -87,8 +87,8 @@ namespace SabreTools.Library.DatFiles // If we have a "null" game (created by DATFromDir or something similar), log it to file if (rom.ItemType == ItemType.Rom - && ((Rom)rom).Size == -1 - && ((Rom)rom).CRC == "null") + && (rom as Rom).Size == -1 + && (rom as Rom).CRC == "null") { Globals.Logger.Verbose($"Empty folder found: {rom.Machine.Name}"); lastgame = rom.Machine.Name; diff --git a/SabreTools.Library/DatFiles/OfflineList.cs b/SabreTools.Library/DatFiles/OfflineList.cs index f91579bc..d6012cd8 100644 --- a/SabreTools.Library/DatFiles/OfflineList.cs +++ b/SabreTools.Library/DatFiles/OfflineList.cs @@ -644,8 +644,6 @@ namespace SabreTools.Library.DatFiles reader.ReadElementContentAsString().ToLowerInvariant())); break; - // TODO: Should I support the "custom" romMD5 and romSHA1 tags I write out? - default: reader.Read(); break; @@ -727,22 +725,22 @@ namespace SabreTools.Library.DatFiles // If we have a "null" game (created by DATFromDir or something similar), log it to file if (rom.ItemType == ItemType.Rom - && ((Rom)rom).Size == -1 - && ((Rom)rom).CRC == "null") + && (rom as Rom).Size == -1 + && (rom as Rom).CRC == "null") { Globals.Logger.Verbose($"Empty folder found: {rom.Machine.Name}"); rom.Name = (rom.Name == "null" ? "-" : rom.Name); - ((Rom)rom).Size = Constants.SizeZero; - ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null; - ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null; + (rom as Rom).Size = Constants.SizeZero; + (rom as Rom).CRC = (rom as Rom).CRC == "null" ? Constants.CRCZero : null; + (rom as Rom).MD5 = (rom as Rom).MD5 == "null" ? Constants.MD5Zero : null; #if NET_FRAMEWORK - ((Rom)rom).RIPEMD160 = ((Rom)rom).RIPEMD160 == "null" ? Constants.RIPEMD160Zero : null; + (rom as Rom).RIPEMD160 = (rom as Rom).RIPEMD160 == "null" ? Constants.RIPEMD160Zero : null; #endif - ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null; - ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null; - ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null; - ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null; + (rom as Rom).SHA1 = (rom as Rom).SHA1 == "null" ? Constants.SHA1Zero : null; + (rom as Rom).SHA256 = (rom as Rom).SHA256 == "null" ? Constants.SHA256Zero : null; + (rom as Rom).SHA384 = (rom as Rom).SHA384 == "null" ? Constants.SHA384Zero : null; + (rom as Rom).SHA512 = (rom as Rom).SHA512 == "null" ? Constants.SHA512Zero : null; } // Now, output the rom data @@ -929,29 +927,7 @@ namespace SabreTools.Library.DatFiles xtw.WriteElementString("sourceRom", "None"); xtw.WriteElementString("language", "0"); - if (datItem.ItemType == ItemType.Disk) - { - var disk = datItem as Disk; - xtw.WriteStartElement("files"); - if (!string.IsNullOrWhiteSpace(disk.MD5)) - { - xtw.WriteStartElement("romMD5"); - xtw.WriteAttributeString("extension", ".chd"); - xtw.WriteString(disk.MD5?.ToUpperInvariant()); - xtw.WriteEndElement(); - } - else if (!string.IsNullOrWhiteSpace(disk.SHA1)) - { - xtw.WriteStartElement("romSHA1"); - xtw.WriteAttributeString("extension", ".chd"); - xtw.WriteString(disk.SHA1?.ToUpperInvariant()); - xtw.WriteEndElement(); - } - - // End files - xtw.WriteEndElement(); - } - else if (datItem.ItemType == ItemType.Rom) + if (datItem.ItemType == ItemType.Rom) { var rom = datItem as Rom; string tempext = "." + PathExtensions.GetNormalizedExtension(rom.Name); @@ -964,20 +940,6 @@ namespace SabreTools.Library.DatFiles xtw.WriteString(rom.CRC?.ToUpperInvariant()); xtw.WriteEndElement(); } - else if (!string.IsNullOrWhiteSpace(rom.MD5)) - { - xtw.WriteStartElement("romMD5"); - xtw.WriteRequiredAttributeString("extension", tempext); - xtw.WriteString(rom.MD5?.ToUpperInvariant()); - xtw.WriteEndElement(); - } - else if (!string.IsNullOrWhiteSpace(rom.SHA1)) - { - xtw.WriteStartElement("romSHA1"); - xtw.WriteRequiredAttributeString("extension", tempext); - xtw.WriteString(rom.SHA1?.ToUpperInvariant()); - xtw.WriteEndElement(); - } // End files xtw.WriteEndElement(); diff --git a/SabreTools.Library/DatFiles/OpenMSX.cs b/SabreTools.Library/DatFiles/OpenMSX.cs index 25620f4f..5296a9c8 100644 --- a/SabreTools.Library/DatFiles/OpenMSX.cs +++ b/SabreTools.Library/DatFiles/OpenMSX.cs @@ -572,8 +572,8 @@ namespace SabreTools.Library.DatFiles // If we have a "null" game (created by DATFromDir or something similar), log it to file if (rom.ItemType == ItemType.Rom - && ((Rom)rom).Size == -1 - && ((Rom)rom).CRC == "null") + && (rom as Rom).Size == -1 + && (rom as Rom).CRC == "null") { Globals.Logger.Verbose($"Empty folder found: {rom.Machine.Name}"); diff --git a/SabreTools.Library/DatFiles/RomCenter.cs b/SabreTools.Library/DatFiles/RomCenter.cs index df3a400e..02326f54 100644 --- a/SabreTools.Library/DatFiles/RomCenter.cs +++ b/SabreTools.Library/DatFiles/RomCenter.cs @@ -419,22 +419,22 @@ namespace SabreTools.Library.DatFiles // If we have a "null" game (created by DATFromDir or something similar), log it to file if (rom.ItemType == ItemType.Rom - && ((Rom)rom).Size == -1 - && ((Rom)rom).CRC == "null") + && (rom as Rom).Size == -1 + && (rom as Rom).CRC == "null") { Globals.Logger.Verbose($"Empty folder found: {rom.Machine.Name}"); rom.Name = (rom.Name == "null" ? "-" : rom.Name); - ((Rom)rom).Size = Constants.SizeZero; - ((Rom)rom).CRC = ((Rom)rom).CRC == "null" ? Constants.CRCZero : null; - ((Rom)rom).MD5 = ((Rom)rom).MD5 == "null" ? Constants.MD5Zero : null; + (rom as Rom).Size = Constants.SizeZero; + (rom as Rom).CRC = (rom as Rom).CRC == "null" ? Constants.CRCZero : null; + (rom as Rom).MD5 = (rom as Rom).MD5 == "null" ? Constants.MD5Zero : null; #if NET_FRAMEWORK - ((Rom)rom).RIPEMD160 = ((Rom)rom).RIPEMD160 == "null" ? Constants.RIPEMD160Zero : null; + (rom as Rom).RIPEMD160 = (rom as Rom).RIPEMD160 == "null" ? Constants.RIPEMD160Zero : null; #endif - ((Rom)rom).SHA1 = ((Rom)rom).SHA1 == "null" ? Constants.SHA1Zero : null; - ((Rom)rom).SHA256 = ((Rom)rom).SHA256 == "null" ? Constants.SHA256Zero : null; - ((Rom)rom).SHA384 = ((Rom)rom).SHA384 == "null" ? Constants.SHA384Zero : null; - ((Rom)rom).SHA512 = ((Rom)rom).SHA512 == "null" ? Constants.SHA512Zero : null; + (rom as Rom).SHA1 = (rom as Rom).SHA1 == "null" ? Constants.SHA1Zero : null; + (rom as Rom).SHA256 = (rom as Rom).SHA256 == "null" ? Constants.SHA256Zero : null; + (rom as Rom).SHA384 = (rom as Rom).SHA384 == "null" ? Constants.SHA384Zero : null; + (rom as Rom).SHA512 = (rom as Rom).SHA512 == "null" ? Constants.SHA512Zero : null; } // Now, output the rom data diff --git a/SabreTools.Library/DatFiles/SabreDat.cs b/SabreTools.Library/DatFiles/SabreDat.cs index e284fccc..7ee6e46d 100644 --- a/SabreTools.Library/DatFiles/SabreDat.cs +++ b/SabreTools.Library/DatFiles/SabreDat.cs @@ -404,14 +404,24 @@ namespace SabreTools.Library.DatFiles { Name = reader.GetAttribute("name"), MD5 = reader.GetAttribute("md5"), -#if NET_FRAMEWORK - RIPEMD160 = reader.GetAttribute("ripemd160"), -#endif + SHA1 = reader.GetAttribute("sha1"), + ItemStatus = its, + + Source = new Source + { + Index = indexId, + Name = filename, + }, + }; + break; + + case "media": + datItem = new Media + { + Name = reader.GetAttribute("name"), + MD5 = reader.GetAttribute("md5"), SHA1 = reader.GetAttribute("sha1"), SHA256 = reader.GetAttribute("sha256"), - SHA384 =reader.GetAttribute("sha384"), - SHA512 = reader.GetAttribute("sha512"), - ItemStatus = its, Source = new Source { @@ -628,8 +638,8 @@ namespace SabreTools.Library.DatFiles // If we have a "null" game (created by DATFromDir or something similar), log it to file if (rom.ItemType == ItemType.Rom - && ((Rom)rom).Size == -1 - && ((Rom)rom).CRC == "null") + && (rom as Rom).Size == -1 + && (rom as Rom).CRC == "null") { Globals.Logger.Verbose($"Empty folder found: {rom.Machine.Name}"); @@ -888,13 +898,7 @@ namespace SabreTools.Library.DatFiles xtw.WriteAttributeString("type", "disk"); xtw.WriteRequiredAttributeString("name", disk.Name); xtw.WriteOptionalAttributeString("md5", disk.MD5?.ToLowerInvariant()); -#if NET_FRAMEWORK - xtw.WriteOptionalAttributeString("ripemd160", disk.RIPEMD160?.ToLowerInvariant()); -#endif xtw.WriteOptionalAttributeString("sha1", disk.SHA1?.ToLowerInvariant()); - xtw.WriteOptionalAttributeString("sha256", disk.SHA256?.ToLowerInvariant()); - xtw.WriteOptionalAttributeString("sha384", disk.SHA384?.ToLowerInvariant()); - xtw.WriteOptionalAttributeString("sha512", disk.SHA512?.ToLowerInvariant()); if (disk.ItemStatus != ItemStatus.None) { xtw.WriteStartElement("flags"); @@ -910,6 +914,17 @@ namespace SabreTools.Library.DatFiles xtw.WriteEndElement(); break; + case ItemType.Media: + var media = datItem as Media; + xtw.WriteStartElement("file"); + xtw.WriteAttributeString("type", "media"); + xtw.WriteRequiredAttributeString("name", media.Name); + xtw.WriteOptionalAttributeString("md5", media.MD5?.ToLowerInvariant()); + xtw.WriteOptionalAttributeString("sha1", media.SHA1?.ToLowerInvariant()); + xtw.WriteOptionalAttributeString("sha256", media.SHA256?.ToLowerInvariant()); + xtw.WriteEndElement(); + break; + case ItemType.Release: var release = datItem as Release; xtw.WriteStartElement("file"); diff --git a/SabreTools.Library/DatFiles/SeparatedValue.cs b/SabreTools.Library/DatFiles/SeparatedValue.cs index a5874042..3b33b5ab 100644 --- a/SabreTools.Library/DatFiles/SeparatedValue.cs +++ b/SabreTools.Library/DatFiles/SeparatedValue.cs @@ -152,8 +152,8 @@ namespace SabreTools.Library.DatFiles // If we have a "null" game (created by DATFromDir or something similar), log it to file if (rom.ItemType == ItemType.Rom - && ((Rom)rom).Size == -1 - && ((Rom)rom).CRC == "null") + && (rom as Rom).Size == -1 + && (rom as Rom).CRC == "null") { Globals.Logger.Verbose($"Empty folder found: {rom.Machine.Name}"); } @@ -257,14 +257,30 @@ namespace SabreTools.Library.DatFiles fields[8] = string.Empty; fields[9] = string.Empty; fields[10] = disk.MD5.ToLowerInvariant(); - //fields[11] = disk.RIPEMD160?.ToLowerInvariant(); + //fields[11] = string.Empty; fields[11] = disk.SHA1.ToLowerInvariant(); - fields[12] = disk.SHA256.ToLowerInvariant(); - //fields[13] = disk.SHA384?.ToLowerInvariant(); - //fields[14] = disk.SHA512?.ToLowerInvariant(); + fields[12] = string.Empty; + //fields[13] = string.Empty; + //fields[14] = string.Empty; fields[13] = disk.ItemStatus.ToString(); break; + case ItemType.Media: + var media = datItem as Media; + fields[5] = "media"; + fields[6] = string.Empty; + fields[7] = media.Name; + fields[8] = string.Empty; + fields[9] = string.Empty; + fields[10] = media.MD5.ToLowerInvariant(); + //fields[11] = string.Empty; + fields[11] = media.SHA1.ToLowerInvariant(); + fields[12] = media.SHA256?.ToLowerInvariant(); + //fields[13] = string.Empty; + //fields[14] = string.Empty; + fields[13] = string.Empty; + break; + case ItemType.Rom: var rom = datItem as Rom; fields[5] = "rom"; diff --git a/SabreTools.Library/DatFiles/SoftwareList.cs b/SabreTools.Library/DatFiles/SoftwareList.cs index 72d6a176..d9676ad6 100644 --- a/SabreTools.Library/DatFiles/SoftwareList.cs +++ b/SabreTools.Library/DatFiles/SoftwareList.cs @@ -516,13 +516,7 @@ namespace SabreTools.Library.DatFiles { Name = reader.GetAttribute("name"), MD5 = reader.GetAttribute("md5"), -#if NET_FRAMEWORK - RIPEMD160 = reader.GetAttribute("ripemd160"), -#endif SHA1 = reader.GetAttribute("sha1"), - SHA256 = reader.GetAttribute("sha256"), - SHA384 = reader.GetAttribute("sha384"), - SHA512 = reader.GetAttribute("sha512"), ItemStatus = reader.GetAttribute("status").AsItemStatus(), Writable = reader.GetAttribute("writable").AsYesNo(), @@ -652,8 +646,8 @@ namespace SabreTools.Library.DatFiles // If we have a "null" game (created by DATFromDir or something similar), log it to file if (rom.ItemType == ItemType.Rom - && ((Rom)rom).Size == -1 - && ((Rom)rom).CRC == "null") + && (rom as Rom).Size == -1 + && (rom as Rom).CRC == "null") { Globals.Logger.Verbose($"Empty folder found: {rom.Machine.Name}"); @@ -870,13 +864,7 @@ namespace SabreTools.Library.DatFiles xtw.WriteStartElement("disk"); xtw.WriteRequiredAttributeString("name", disk.Name); xtw.WriteOptionalAttributeString("md5", disk.MD5?.ToLowerInvariant()); -#if NET_FRAMEWORK - xtw.WriteOptionalAttributeString("ripemd160", disk.RIPEMD160?.ToLowerInvariant()); -#endif xtw.WriteOptionalAttributeString("sha1", disk.SHA1?.ToLowerInvariant()); - xtw.WriteOptionalAttributeString("sha256", disk.SHA256?.ToLowerInvariant()); - xtw.WriteOptionalAttributeString("sha384", disk.SHA384?.ToLowerInvariant()); - xtw.WriteOptionalAttributeString("sha512", disk.SHA512?.ToLowerInvariant()); xtw.WriteOptionalAttributeString("status", disk.ItemStatus.FromItemStatus(false)); xtw.WriteOptionalAttributeString("writable", disk.Writable.FromYesNo()); xtw.WriteEndElement(); diff --git a/SabreTools.Library/DatItems/DatItem.cs b/SabreTools.Library/DatItems/DatItem.cs index cfef11ce..1194df64 100644 --- a/SabreTools.Library/DatItems/DatItem.cs +++ b/SabreTools.Library/DatItems/DatItem.cs @@ -245,13 +245,7 @@ namespace SabreTools.Library.DatItems // Disk Field.DatItem_MD5, -#if NET_FRAMEWORK - Field.DatItem_RIPEMD160, -#endif Field.DatItem_SHA1, - Field.DatItem_SHA256, - Field.DatItem_SHA384, - Field.DatItem_SHA512, Field.DatItem_Merge, Field.DatItem_Region, Field.DatItem_Index, @@ -259,6 +253,9 @@ namespace SabreTools.Library.DatItems Field.DatItem_Status, Field.DatItem_Optional, + // Media + Field.DatItem_SHA256, + // Release Field.DatItem_Language, Field.DatItem_Date, @@ -267,6 +264,11 @@ namespace SabreTools.Library.DatItems Field.DatItem_Bios, Field.DatItem_Size, Field.DatItem_CRC, +#if NET_FRAMEWORK + Field.DatItem_RIPEMD160, +#endif + Field.DatItem_SHA384, + Field.DatItem_SHA512, Field.DatItem_Offset, Field.DatItem_Inverted, @@ -448,6 +450,9 @@ namespace SabreTools.Library.DatItems case ItemType.Disk: return new Disk(); + case ItemType.Media: + return new Media(); + case ItemType.Release: return new Release(); @@ -484,6 +489,9 @@ namespace SabreTools.Library.DatItems { switch (baseFile.Type) { + case FileType.AaruFormat: + return new Media(baseFile); + case FileType.CHD: return new Disk(baseFile); @@ -1016,8 +1024,8 @@ namespace SabreTools.Library.DatItems { DatItem file = infiles[f]; - // If we don't have a Rom or a Disk, we skip checking for duplicates - if (file.ItemType != ItemType.Rom && file.ItemType != ItemType.Disk) + // If we don't have a Dis, Media, or Rom, we skip checking for duplicates + if (file.ItemType != ItemType.Disk && file.ItemType != ItemType.Media && file.ItemType != ItemType.Rom) continue; // If it's a nodump, add and skip @@ -1057,9 +1065,11 @@ namespace SabreTools.Library.DatItems saveditem = lastrom; pos = i; - // Disks and Roms have more information to fill + // Disks, Media, and Roms have more information to fill if (file.ItemType == ItemType.Disk) (saveditem as Disk).FillMissingInformation(file as Disk); + else if (file.ItemType == ItemType.Media) + (saveditem as Media).FillMissingInformation(file as Media); else if (file.ItemType == ItemType.Rom) (saveditem as Rom).FillMissingInformation(file as Rom); @@ -1142,7 +1152,7 @@ namespace SabreTools.Library.DatItems { Globals.Logger.Verbose($"Name duplicate found for '{datItem.Name}'"); - if (datItem.ItemType == ItemType.Disk || datItem.ItemType == ItemType.Rom) + if (datItem.ItemType == ItemType.Disk || datItem.ItemType == ItemType.Media || datItem.ItemType == ItemType.Rom) { datItem.Name += GetDuplicateSuffix(datItem); #if NET_FRAMEWORK @@ -1192,6 +1202,8 @@ namespace SabreTools.Library.DatItems { if (datItem.ItemType == ItemType.Disk) return (datItem as Disk).GetDuplicateSuffix(); + else if (datItem.ItemType == ItemType.Media) + return (datItem as Media).GetDuplicateSuffix(); else if (datItem.ItemType == ItemType.Rom) return (datItem as Rom).GetDuplicateSuffix(); @@ -1215,10 +1227,11 @@ namespace SabreTools.Library.DatItems { if (x.Machine.Name == y.Machine.Name) { - // Special case for comparing a Disk or Rom to another item type - if ((x.ItemType == ItemType.Disk || x.ItemType == ItemType.Rom) ^ (y.ItemType == ItemType.Disk || y.ItemType == ItemType.Rom)) + // Special case for comparing a Disk, Media, or Rom to another item type + if ((x.ItemType == ItemType.Disk || x.ItemType == ItemType.Media || x.ItemType == ItemType.Rom) + ^ (y.ItemType == ItemType.Disk || y.ItemType == ItemType.Media || x.ItemType == ItemType.Rom)) { - if (x.ItemType == ItemType.Disk || x.ItemType == ItemType.Rom) + if (x.ItemType == ItemType.Disk || x.ItemType == ItemType.Media || x.ItemType == ItemType.Rom) return -1; else return 1; diff --git a/SabreTools.Library/DatItems/Disk.cs b/SabreTools.Library/DatItems/Disk.cs index 85091676..8b8fa7bc 100644 --- a/SabreTools.Library/DatItems/Disk.cs +++ b/SabreTools.Library/DatItems/Disk.cs @@ -18,13 +18,7 @@ namespace SabreTools.Library.DatItems #region Private instance variables private byte[] _md5; // 16 bytes -#if NET_FRAMEWORK - private byte[] _ripemd160; // 20 bytes -#endif private byte[] _sha1; // 20 bytes - private byte[] _sha256; // 32 bytes - private byte[] _sha384; // 48 bytes - private byte[] _sha512; // 64 bytes #endregion @@ -40,18 +34,6 @@ namespace SabreTools.Library.DatItems set { _md5 = Utilities.StringToByteArray(Sanitizer.CleanMD5(value)); } } -#if NET_FRAMEWORK - /// - /// Data RIPEMD160 hash - /// - [JsonProperty("ripemd160", DefaultValueHandling = DefaultValueHandling.Ignore)] - public string RIPEMD160 - { - get { return _ripemd160.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_ripemd160); } - set { _ripemd160 = Utilities.StringToByteArray(Sanitizer.CleanRIPEMD160(value)); } - } -#endif - /// /// Data SHA-1 hash /// @@ -62,36 +44,6 @@ namespace SabreTools.Library.DatItems set { _sha1 = Utilities.StringToByteArray(Sanitizer.CleanSHA1(value)); } } - /// - /// Data SHA-256 hash - /// - [JsonProperty("sha256", DefaultValueHandling = DefaultValueHandling.Ignore)] - public string SHA256 - { - get { return _sha256.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha256); } - set { _sha256 = Utilities.StringToByteArray(Sanitizer.CleanSHA256(value)); } - } - - /// - /// Data SHA-384 hash - /// - [JsonProperty("sha384", DefaultValueHandling = DefaultValueHandling.Ignore)] - public string SHA384 - { - get { return _sha384.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha384); } - set { _sha384 = Utilities.StringToByteArray(Sanitizer.CleanSHA384(value)); } - } - - /// - /// Data SHA-512 hash - /// - [JsonProperty("sha512", DefaultValueHandling = DefaultValueHandling.Ignore)] - public string SHA512 - { - get { return _sha512.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha512); } - set { _sha512 = Utilities.StringToByteArray(Sanitizer.CleanSHA512(value)); } - } - /// /// Disk name to merge from parent /// @@ -146,23 +98,9 @@ namespace SabreTools.Library.DatItems if (mappings.Keys.Contains(Field.DatItem_MD5)) MD5 = mappings[Field.DatItem_MD5]; -#if NET_FRAMEWORK - if (mappings.Keys.Contains(Field.DatItem_RIPEMD160)) - RIPEMD160 = mappings[Field.DatItem_RIPEMD160]; -#endif - if (mappings.Keys.Contains(Field.DatItem_SHA1)) SHA1 = mappings[Field.DatItem_SHA1]; - if (mappings.Keys.Contains(Field.DatItem_SHA256)) - SHA256 = mappings[Field.DatItem_SHA256]; - - if (mappings.Keys.Contains(Field.DatItem_SHA384)) - SHA384 = mappings[Field.DatItem_SHA384]; - - if (mappings.Keys.Contains(Field.DatItem_SHA512)) - SHA512 = mappings[Field.DatItem_SHA512]; - if (mappings.Keys.Contains(Field.DatItem_Merge)) MergeTag = mappings[Field.DatItem_Merge]; @@ -198,20 +136,14 @@ namespace SabreTools.Library.DatItems } /// - /// Create a Rom object from a BaseFile + /// Create a Disk object from a BaseFile /// /// public Disk(BaseFile baseFile) { Name = baseFile.Filename; _md5 = baseFile.MD5; -#if NET_FRAMEWORK - _ripemd160 = baseFile.RIPEMD160; -#endif _sha1 = baseFile.SHA1; - _sha256 = baseFile.SHA256; - _sha384 = baseFile.SHA384; - _sha512 = baseFile.SHA512; ItemType = ItemType.Disk; DupeType = 0x00; @@ -253,13 +185,7 @@ namespace SabreTools.Library.DatItems Remove = this.Remove, _md5 = this._md5, -#if NET_FRAMEWORK - _ripemd160 = this._ripemd160, -#endif _sha1 = this._sha1, - _sha256 = this._sha256, - _sha384 = this._sha384, - _sha512 = this._sha512, MergeTag = this.MergeTag, Region = this.Region, Index = this.Index, @@ -277,7 +203,7 @@ namespace SabreTools.Library.DatItems { var rom = new Rom() { - Name = this.Name, + Name = this.Name + ".chd", ItemType = ItemType.Rom, DupeType = this.DupeType, @@ -308,15 +234,8 @@ namespace SabreTools.Library.DatItems ItemStatus = this.ItemStatus, Optional = this.Optional, - CRC = null, MD5 = this.MD5, -#if NET_FRAMEWORK - RIPEMD160 = this.RIPEMD160, -#endif SHA1 = this.SHA1, - SHA256 = this.SHA256, - SHA384 = this.SHA384, - SHA512 = this.SHA512, }; return rom; @@ -363,22 +282,8 @@ namespace SabreTools.Library.DatItems if (_md5.IsNullOrEmpty() && !other._md5.IsNullOrEmpty()) _md5 = other._md5; -#if NET_FRAMEWORK - if (_ripemd160.IsNullOrEmpty() && !other._ripemd160.IsNullOrEmpty()) - _ripemd160 = other._ripemd160; -#endif - if (_sha1.IsNullOrEmpty() && !other._sha1.IsNullOrEmpty()) _sha1 = other._sha1; - - if (_sha256.IsNullOrEmpty() && !other._sha256.IsNullOrEmpty()) - _sha256 = other._sha256; - - if (_sha384.IsNullOrEmpty() && !other._sha384.IsNullOrEmpty()) - _sha384 = other._sha384; - - if (_sha512.IsNullOrEmpty() && !other._sha512.IsNullOrEmpty()) - _sha512 = other._sha512; } /// @@ -391,12 +296,6 @@ namespace SabreTools.Library.DatItems return $"_{MD5}"; else if (!_sha1.IsNullOrEmpty()) return $"_{SHA1}"; - else if (!_sha256.IsNullOrEmpty()) - return $"_{SHA256}"; - else if (!_sha384.IsNullOrEmpty()) - return $"_{SHA384}"; - else if (!_sha512.IsNullOrEmpty()) - return $"_{SHA512}"; else return "_1"; } @@ -409,13 +308,7 @@ namespace SabreTools.Library.DatItems private bool HasCommonHash(Disk other) { return !(_md5.IsNullOrEmpty() ^ other._md5.IsNullOrEmpty()) -#if NET_FRAMEWORK - || !(_ripemd160.IsNullOrEmpty() || other._ripemd160.IsNullOrEmpty()) -#endif - || !(_sha1.IsNullOrEmpty() ^ other._sha1.IsNullOrEmpty()) - || !(_sha256.IsNullOrEmpty() ^ other._sha256.IsNullOrEmpty()) - || !(_sha384.IsNullOrEmpty() ^ other._sha384.IsNullOrEmpty()) - || !(_sha512.IsNullOrEmpty() ^ other._sha512.IsNullOrEmpty()); + || !(_sha1.IsNullOrEmpty() ^ other._sha1.IsNullOrEmpty()); } /// @@ -425,13 +318,7 @@ namespace SabreTools.Library.DatItems private bool HasHashes() { return !_md5.IsNullOrEmpty() -#if NET_FRAMEWORK - || !_ripemd160.IsNullOrEmpty() -#endif - || !_sha1.IsNullOrEmpty() - || !_sha256.IsNullOrEmpty() - || !_sha384.IsNullOrEmpty() - || !_sha512.IsNullOrEmpty(); + || !_sha1.IsNullOrEmpty(); } /// @@ -451,13 +338,7 @@ namespace SabreTools.Library.DatItems // Return if all hashes match according to merge rules return ConditionalHashEquals(_md5, other._md5) -#if NET_FRAMEWORK - && ConditionalHashEquals(_ripemd160, other._ripemd160) -#endif - && ConditionalHashEquals(_sha1, other._sha1) - && ConditionalHashEquals(_sha256, other._sha256) - && ConditionalHashEquals(_sha384, other._sha384) - && ConditionalHashEquals(_sha512, other._sha512); + && ConditionalHashEquals(_sha1, other._sha1); } #endregion @@ -481,38 +362,12 @@ namespace SabreTools.Library.DatItems if (filter.DatItem_MD5.MatchesNegativeSet(MD5) == true) return false; -#if NET_FRAMEWORK - // Filter on RIPEMD160 - if (filter.DatItem_RIPEMD160.MatchesPositiveSet(RIPEMD160) == false) - return false; - if (filter.DatItem_RIPEMD160.MatchesNegativeSet(RIPEMD160) == true) - return false; -#endif - // Filter on SHA-1 if (filter.DatItem_SHA1.MatchesPositiveSet(SHA1) == false) return false; if (filter.DatItem_SHA1.MatchesNegativeSet(SHA1) == true) return false; - // Filter on SHA-256 - if (filter.DatItem_SHA256.MatchesPositiveSet(SHA256) == false) - return false; - if (filter.DatItem_SHA256.MatchesNegativeSet(SHA256) == true) - return false; - - // Filter on SHA-384 - if (filter.DatItem_SHA384.MatchesPositiveSet(SHA384) == false) - return false; - if (filter.DatItem_SHA384.MatchesNegativeSet(SHA384) == true) - return false; - - // Filter on SHA-512 - if (filter.DatItem_SHA512.MatchesPositiveSet(SHA512) == false) - return false; - if (filter.DatItem_SHA512.MatchesNegativeSet(SHA512) == true) - return false; - // Filter on merge tag if (filter.DatItem_Merge.MatchesPositiveSet(MergeTag) == false) return false; @@ -561,23 +416,9 @@ namespace SabreTools.Library.DatItems if (fields.Contains(Field.DatItem_MD5)) MD5 = null; -#if NET_FRAMEWORK - if (fields.Contains(Field.DatItem_RIPEMD160)) - RIPEMD160 = null; -#endif - if (fields.Contains(Field.DatItem_SHA1)) SHA1 = null; - if (fields.Contains(Field.DatItem_SHA256)) - SHA256 = null; - - if (fields.Contains(Field.DatItem_SHA384)) - SHA384 = null; - - if (fields.Contains(Field.DatItem_SHA512)) - SHA512 = null; - if (fields.Contains(Field.DatItem_Merge)) MergeTag = null; @@ -620,28 +461,10 @@ namespace SabreTools.Library.DatItems key = MD5; break; -#if NET_FRAMEWORK - case Field.DatItem_RIPEMD160: - key = RIPEMD160; - break; -#endif - case Field.DatItem_SHA1: key = SHA1; break; - case Field.DatItem_SHA256: - key = SHA256; - break; - - case Field.DatItem_SHA384: - key = SHA384; - break; - - case Field.DatItem_SHA512: - key = SHA512; - break; - // Let the base handle generic stuff default: return base.GetKey(bucketedBy, lower, norename); @@ -678,38 +501,12 @@ namespace SabreTools.Library.DatItems MD5 = newItem.MD5; } -#if NET_FRAMEWORK - if (fields.Contains(Field.DatItem_RIPEMD160)) - { - if (string.IsNullOrEmpty(RIPEMD160) && !string.IsNullOrEmpty(newItem.RIPEMD160)) - RIPEMD160 = newItem.RIPEMD160; - } -#endif - if (fields.Contains(Field.DatItem_SHA1)) { if (string.IsNullOrEmpty(SHA1) && !string.IsNullOrEmpty(newItem.SHA1)) SHA1 = newItem.SHA1; } - if (fields.Contains(Field.DatItem_SHA256)) - { - if (string.IsNullOrEmpty(SHA256) && !string.IsNullOrEmpty(newItem.SHA256)) - SHA256 = newItem.SHA256; - } - - if (fields.Contains(Field.DatItem_SHA384)) - { - if (string.IsNullOrEmpty(SHA384) && !string.IsNullOrEmpty(newItem.SHA384)) - SHA384 = newItem.SHA384; - } - - if (fields.Contains(Field.DatItem_SHA512)) - { - if (string.IsNullOrEmpty(SHA512) && !string.IsNullOrEmpty(newItem.SHA512)) - SHA512 = newItem.SHA512; - } - if (fields.Contains(Field.DatItem_Merge)) MergeTag = newItem.MergeTag; diff --git a/SabreTools.Library/DatItems/Enums.cs b/SabreTools.Library/DatItems/Enums.cs index a77207d8..7fd7ecfb 100644 --- a/SabreTools.Library/DatItems/Enums.cs +++ b/SabreTools.Library/DatItems/Enums.cs @@ -398,13 +398,7 @@ namespace SabreTools.Library.DatItems // Disk DatItem_MD5, -#if NET_FRAMEWORK - DatItem_RIPEMD160, -#endif DatItem_SHA1, - DatItem_SHA256, - DatItem_SHA384, - DatItem_SHA512, DatItem_Merge, DatItem_Region, DatItem_Index, @@ -412,6 +406,9 @@ namespace SabreTools.Library.DatItems DatItem_Status, DatItem_Optional, + // Media + DatItem_SHA256, + // Release DatItem_Language, DatItem_Date, @@ -420,6 +417,11 @@ namespace SabreTools.Library.DatItems DatItem_Bios, DatItem_Size, DatItem_CRC, +#if NET_FRAMEWORK + DatItem_RIPEMD160, +#endif + DatItem_SHA384, + DatItem_SHA512, DatItem_Offset, DatItem_Inverted, @@ -458,6 +460,7 @@ namespace SabreTools.Library.DatItems BiosSet = 4, Archive = 5, Chip = 6, + Media = 7, Blank = 99, // This is not a real type, only used internally } diff --git a/SabreTools.Library/DatItems/Media.cs b/SabreTools.Library/DatItems/Media.cs new file mode 100644 index 00000000..a177cda9 --- /dev/null +++ b/SabreTools.Library/DatItems/Media.cs @@ -0,0 +1,431 @@ +using System.Collections.Generic; +using System.Linq; + +using SabreTools.Library.Data; +using SabreTools.Library.FileTypes; +using SabreTools.Library.Filtering; +using SabreTools.Library.Tools; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace SabreTools.Library.DatItems +{ + /// + /// Represents Aaruformat images which use internal hashes + /// + [JsonObject("media")] + public class Media : DatItem + { + #region Private instance variables + + private byte[] _md5; // 16 bytes + private byte[] _sha1; // 20 bytes + private byte[] _sha256; // 32 bytes + // TODO: Implement SpamSum + + #endregion + + #region Fields + + /// + /// Data MD5 hash + /// + [JsonProperty("md5", DefaultValueHandling = DefaultValueHandling.Ignore)] + public string MD5 + { + get { return _md5.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_md5); } + set { _md5 = Utilities.StringToByteArray(Sanitizer.CleanMD5(value)); } + } + + /// + /// Data SHA-1 hash + /// + [JsonProperty("sha1", DefaultValueHandling = DefaultValueHandling.Ignore)] + public string SHA1 + { + get { return _sha1.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha1); } + set { _sha1 = Utilities.StringToByteArray(Sanitizer.CleanSHA1(value)); } + } + + /// + /// Data SHA-256 hash + /// + [JsonProperty("sha256", DefaultValueHandling = DefaultValueHandling.Ignore)] + public string SHA256 + { + get { return _sha256.IsNullOrEmpty() ? null : Utilities.ByteArrayToString(_sha256); } + set { _sha256 = Utilities.StringToByteArray(Sanitizer.CleanSHA256(value)); } + } + + #endregion + + #region Accessors + + /// + /// Set fields with given values + /// + /// Mappings dictionary + public override void SetFields(Dictionary mappings) + { + // Set base fields + base.SetFields(mappings); + + // Handle Media-specific fields + if (mappings.Keys.Contains(Field.DatItem_MD5)) + MD5 = mappings[Field.DatItem_MD5]; + + if (mappings.Keys.Contains(Field.DatItem_SHA1)) + SHA1 = mappings[Field.DatItem_SHA1]; + + if (mappings.Keys.Contains(Field.DatItem_SHA256)) + SHA256 = mappings[Field.DatItem_SHA256]; + } + + #endregion + + #region Constructors + + /// + /// Create a default, empty Media object + /// + public Media() + { + Name = string.Empty; + ItemType = ItemType.Media; + DupeType = 0x00; + } + + /// + /// Create a Media object from a BaseFile + /// + /// + public Media(BaseFile baseFile) + { + Name = baseFile.Filename; + _md5 = baseFile.MD5; + _sha1 = baseFile.SHA1; + _sha256 = baseFile.SHA256; + + ItemType = ItemType.Media; + DupeType = 0x00; + } + + #endregion + + #region Cloning Methods + + public override object Clone() + { + return new Media() + { + Name = this.Name, + ItemType = this.ItemType, + DupeType = this.DupeType, + + AltName = this.AltName, + AltTitle = this.AltTitle, + + Original = this.Original, + OpenMSXSubType = this.OpenMSXSubType, + OpenMSXType = this.OpenMSXType, + Remark = this.Remark, + Boot = this.Boot, + + Part = this.Part, + Features = this.Features, + AreaName = this.AreaName, + AreaSize = this.AreaSize, + AreaWidth = this.AreaWidth, + AreaEndianness = this.AreaEndianness, + Value = this.Value, + LoadFlag = this.LoadFlag, + + Machine = this.Machine.Clone() as Machine, + Source = this.Source.Clone() as Source, + Remove = this.Remove, + + _md5 = this._md5, + _sha1 = this._sha1, + _sha256 = this._sha256, + }; + } + + /// + /// Convert a disk to the closest Rom approximation + /// + /// + public Rom ConvertToRom() + { + var rom = new Rom() + { + Name = this.Name + ".aif", + ItemType = ItemType.Rom, + DupeType = this.DupeType, + + AltName = this.AltName, + AltTitle = this.AltTitle, + + Original = this.Original, + OpenMSXSubType = this.OpenMSXSubType, + OpenMSXType = this.OpenMSXType, + Remark = this.Remark, + Boot = this.Boot, + + Part = this.Part, + Features = this.Features, + AreaName = this.AreaName, + AreaSize = this.AreaSize, + AreaWidth = this.AreaWidth, + AreaEndianness = this.AreaEndianness, + Value = this.Value, + LoadFlag = this.LoadFlag, + + Machine = this.Machine.Clone() as Machine, + Source = this.Source.Clone() as Source, + Remove = this.Remove, + + MD5 = this.MD5, + SHA1 = this.SHA1, + SHA256 = this.SHA256, + }; + + return rom; + } + + #endregion + + #region Comparision Methods + + public override bool Equals(DatItem other) + { + bool dupefound = false; + + // If we don't have a Media, return false + if (ItemType != other.ItemType) + return dupefound; + + // Otherwise, treat it as a Media + Media newOther = other as Media; + + // If we get a partial match + if (HashMatch(newOther)) + dupefound = true; + + return dupefound; + } + + /// + /// Fill any missing size and hash information from another Media + /// + /// Media to fill information from + public void FillMissingInformation(Media other) + { + 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; + } + + /// + /// Get unique duplicate suffix on name collision + /// + /// String representing the suffix + public string GetDuplicateSuffix() + { + if (!_md5.IsNullOrEmpty()) + return $"_{MD5}"; + else if (!_sha1.IsNullOrEmpty()) + return $"_{SHA1}"; + else if (!_sha256.IsNullOrEmpty()) + return $"_{SHA256}"; + else + return "_1"; + } + + /// + /// Returns if there are no, non-empty hashes in common with another Media + /// + /// Media to compare against + /// True if at least one hash is not mutually exclusive, false otherwise + private bool HasCommonHash(Media other) + { + return !(_md5.IsNullOrEmpty() ^ other._md5.IsNullOrEmpty()) + || !(_sha1.IsNullOrEmpty() ^ other._sha1.IsNullOrEmpty()) + || !(_sha256.IsNullOrEmpty() ^ other._sha256.IsNullOrEmpty()); + } + + /// + /// Returns if the Media contains any hashes + /// + /// True if any hash exists, false otherwise + private bool HasHashes() + { + return !_md5.IsNullOrEmpty() + || !_sha1.IsNullOrEmpty() + || !_sha256.IsNullOrEmpty(); + } + + /// + /// Returns if any hashes are common with another Media + /// + /// Media to compare against + /// True if any hashes are in common, false otherwise + private bool HashMatch(Media 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 ConditionalHashEquals(_md5, other._md5) + && ConditionalHashEquals(_sha1, other._sha1) + && ConditionalHashEquals(_sha256, other._sha256); + } + + #endregion + + #region Filtering + + /// + /// Check to see if a DatItem passes the filter + /// + /// Filter to check against + /// True if the item passed the filter, false otherwise + public override bool PassesFilter(Filter filter) + { + // Check common fields first + if (!base.PassesFilter(filter)) + return false; + + // Filter on MD5 + if (filter.DatItem_MD5.MatchesPositiveSet(MD5) == false) + return false; + if (filter.DatItem_MD5.MatchesNegativeSet(MD5) == true) + return false; + + // Filter on SHA-1 + if (filter.DatItem_SHA1.MatchesPositiveSet(SHA1) == false) + return false; + if (filter.DatItem_SHA1.MatchesNegativeSet(SHA1) == true) + return false; + + // Filter on SHA-256 + if (filter.DatItem_SHA256.MatchesPositiveSet(SHA256) == false) + return false; + if (filter.DatItem_SHA256.MatchesNegativeSet(SHA256) == true) + return false; + + return true; + } + + /// + /// Remove fields from the DatItem + /// + /// List of Fields to remove + public override void RemoveFields(List fields) + { + // Remove common fields first + base.RemoveFields(fields); + + // Remove the fields + if (fields.Contains(Field.DatItem_MD5)) + MD5 = null; + + if (fields.Contains(Field.DatItem_SHA1)) + SHA1 = null; + + if (fields.Contains(Field.DatItem_SHA256)) + SHA256 = null; + } + + #endregion + + #region Sorting and Merging + + /// + /// Get the dictionary key that should be used for a given item and bucketing type + /// + /// Field enum representing what key to get + /// True if the key should be lowercased (default), false otherwise + /// True if games should only be compared on game and file name, false if system and source are counted + /// String representing the key to be used for the DatItem + public override string GetKey(Field bucketedBy, bool lower = true, bool norename = true) + { + // Set the output key as the default blank string + string key = string.Empty; + + // Now determine what the key should be based on the bucketedBy value + switch (bucketedBy) + { + case Field.DatItem_MD5: + key = MD5; + break; + + case Field.DatItem_SHA1: + key = SHA1; + break; + + case Field.DatItem_SHA256: + key = SHA256; + break; + + // Let the base handle generic stuff + default: + return base.GetKey(bucketedBy, lower, norename); + } + + // Double and triple check the key for corner cases + if (key == null) + key = string.Empty; + + return key; + } + + /// + /// Replace fields from another item + /// + /// DatItem to pull new information from + /// List of Fields representing what should be updated + public override void ReplaceFields(DatItem item, List fields) + { + // Replace common fields first + base.ReplaceFields(item, fields); + + // If we don't have a Media to replace from, ignore specific fields + if (item.ItemType != ItemType.Media) + return; + + // Cast for easier access + Media newItem = item as Media; + + // Replace the fields + if (fields.Contains(Field.DatItem_MD5)) + { + if (string.IsNullOrEmpty(MD5) && !string.IsNullOrEmpty(newItem.MD5)) + MD5 = newItem.MD5; + } + + if (fields.Contains(Field.DatItem_SHA1)) + { + if (string.IsNullOrEmpty(SHA1) && !string.IsNullOrEmpty(newItem.SHA1)) + SHA1 = newItem.SHA1; + } + + if (fields.Contains(Field.DatItem_SHA256)) + { + if (string.IsNullOrEmpty(SHA256) && !string.IsNullOrEmpty(newItem.SHA256)) + SHA256 = newItem.SHA256; + } + } + + #endregion + } +} diff --git a/SabreTools.Library/Data/Constants.cs b/SabreTools.Library/Data/Constants.cs index 3d14ad35..46d9d17e 100644 --- a/SabreTools.Library/Data/Constants.cs +++ b/SabreTools.Library/Data/Constants.cs @@ -478,6 +478,7 @@ namespace SabreTools.Library.Data public static readonly byte[] A7800SignatureV1 = { 0x41, 0x54, 0x41, 0x52, 0x49, 0x37, 0x38, 0x30, 0x30 }; // Offset 0x01 public static readonly byte[] A7800SignatureV2 = { 0x41, 0x43, 0x54, 0x55, 0x41, 0x4c, 0x20, 0x43, 0x41, 0x52, 0x54, 0x20, 0x44, 0x41, 0x54, 0x41, 0x20, 0x53, 0x54, 0x41, 0x52, 0x54, 0x53, 0x20, 0x48, 0x45, 0x52, 0x45 }; // Offset 0x64 + public static readonly byte[] AaruFormatSignature = { 0x41, 0x41, 0x52, 0x55, 0x46, 0x52, 0x4d, 0x54 }; public static readonly byte[] BZ2Signature = { 0x42, 0x5a, 0x68 }; public static readonly byte[] CabinetSignature = { 0x4d, 0x53, 0x43, 0x46 }; public static readonly byte[] CHDSignature = { 0x4d, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x48, 0x44 }; diff --git a/SabreTools.Library/FileTypes/Aaru/ChecksumEntry.cs b/SabreTools.Library/FileTypes/Aaru/ChecksumEntry.cs new file mode 100644 index 00000000..2d7c34a1 --- /dev/null +++ b/SabreTools.Library/FileTypes/Aaru/ChecksumEntry.cs @@ -0,0 +1,41 @@ +using System.IO; +using System.Text; + +namespace SabreTools.Library.FileTypes.Aaru +{ + /// + /// Checksum entry, followed by checksum data itself + /// + /// + public class ChecksumEntry + { + /// Checksum algorithm + public AaruChecksumAlgorithm type; + /// Length in bytes of checksum that follows this structure + public uint length; + /// Checksum that follows this structure + public byte[] checksum; + + /// + /// Read a stream as an v + /// + /// ChecksumEntry as a stream + /// Populated ChecksumEntry, null on failure + public static ChecksumEntry Deserialize(Stream stream) + { + ChecksumEntry checksumEntry = new ChecksumEntry(); + + using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true)) + { + checksumEntry.type = (AaruChecksumAlgorithm)br.ReadByte(); + checksumEntry.length = br.ReadUInt32(); + if (checksumEntry.length == 0) + return null; + + checksumEntry.checksum = br.ReadBytes((int)checksumEntry.length); + } + + return checksumEntry; + } + } +} diff --git a/SabreTools.Library/FileTypes/Aaru/ChecksumHeader.cs b/SabreTools.Library/FileTypes/Aaru/ChecksumHeader.cs new file mode 100644 index 00000000..5527ef11 --- /dev/null +++ b/SabreTools.Library/FileTypes/Aaru/ChecksumHeader.cs @@ -0,0 +1,39 @@ +using System.IO; +using System.Text; + +namespace SabreTools.Library.FileTypes.Aaru +{ + /// + /// Checksum block, contains a checksum of all user data sectors + /// (except for optical discs that is 2352 bytes raw sector if available + /// + /// + public class ChecksumHeader + { + /// Identifier, + public AaruBlockType identifier; + /// Length in bytes of the block + public uint length; + /// How many checksums follow + public byte entries; + + /// + /// Read a stream as an ChecksumHeader + /// + /// ChecksumHeader as a stream + /// Populated ChecksumHeader, null on failure + public static ChecksumHeader Deserialize(Stream stream) + { + ChecksumHeader checksumHeader = new ChecksumHeader(); + + using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true)) + { + checksumHeader.identifier = (AaruBlockType)br.ReadUInt32(); + checksumHeader.length = br.ReadUInt32(); + checksumHeader.entries = br.ReadByte(); + } + + return checksumHeader; + } + } +} diff --git a/SabreTools.Library/FileTypes/Aaru/IndexEntry.cs b/SabreTools.Library/FileTypes/Aaru/IndexEntry.cs new file mode 100644 index 00000000..5e8b6bc6 --- /dev/null +++ b/SabreTools.Library/FileTypes/Aaru/IndexEntry.cs @@ -0,0 +1,38 @@ +using System.IO; +using System.Text; + +namespace SabreTools.Library.FileTypes.Aaru +{ + /// + /// Index entry + /// + /// + public class IndexEntry + { + /// Type of item pointed by this entry + public AaruBlockType blockType; + /// Type of data contained by the block pointed by this entry + public AaruDataType dataType; + /// Offset in file where item is stored + public ulong offset; + + /// + /// Read a stream as an IndexHeader + /// + /// IndexHeader as a stream + /// Populated IndexHeader, null on failure + public static IndexEntry Deserialize(Stream stream) + { + IndexEntry indexEntry = new IndexEntry(); + + using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true)) + { + indexEntry.blockType = (AaruBlockType)br.ReadUInt32(); + indexEntry.dataType = (AaruDataType)br.ReadUInt16(); + indexEntry.offset = br.ReadUInt64(); + } + + return indexEntry; + } + } +} diff --git a/SabreTools.Library/FileTypes/Aaru/IndexHeader.cs b/SabreTools.Library/FileTypes/Aaru/IndexHeader.cs new file mode 100644 index 00000000..1c3fd06b --- /dev/null +++ b/SabreTools.Library/FileTypes/Aaru/IndexHeader.cs @@ -0,0 +1,38 @@ +using System.IO; +using System.Text; + +namespace SabreTools.Library.FileTypes.Aaru +{ + /// + /// Header for the index, followed by entries + /// + /// + public class IndexHeader + { + /// Identifier, + public AaruBlockType identifier; + /// How many entries follow this header + public ushort entries; + /// CRC64-ECMA of the index + public ulong crc64; + + /// + /// Read a stream as an IndexHeader + /// + /// IndexHeader as a stream + /// Populated IndexHeader, null on failure + public static IndexHeader Deserialize(Stream stream) + { + IndexHeader indexHeader = new IndexHeader(); + + using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true)) + { + indexHeader.identifier = (AaruBlockType)br.ReadUInt32(); + indexHeader.entries = br.ReadUInt16(); + indexHeader.crc64 = br.ReadUInt64(); + } + + return indexHeader; + } + } +} diff --git a/SabreTools.Library/FileTypes/AaruFormat.cs b/SabreTools.Library/FileTypes/AaruFormat.cs new file mode 100644 index 00000000..9e68d724 --- /dev/null +++ b/SabreTools.Library/FileTypes/AaruFormat.cs @@ -0,0 +1,229 @@ +using System; +using System.IO; +using System.Text; + +using SabreTools.Library.Data; +using SabreTools.Library.FileTypes.Aaru; +using SabreTools.Library.IO; + +namespace SabreTools.Library.FileTypes +{ + /// + /// AaruFormat code is based on the Aaru project + /// See https://github.com/aaru-dps/Aaru/tree/master/Aaru.Images/AaruFormat + /// + public class AaruFormat : BaseFile + { + #region Private instance variables + + #region Header + + protected ulong Identifier; // 'AARUFRMT' (0x544D524655524141) + protected string Application; // Name of application that created image + protected byte ImageMajorVersion; // Image format major version + protected byte ImageMinorVersion; // Image format minor version + protected byte ApplicationMajorVersion; // Major version of application that created image + protected byte ApplicationMinorVersion; // Minor version of application that created image + protected AaruMediaType MediaType; // Media type contained in image + protected ulong IndexOffset; // Offset to index + protected long CreationTime; // Windows filetime of creation time + protected long LastWrittenTime; // Windows filetime of last written time + + #endregion + + #region Internal Values + + protected IndexHeader IndexHeader; + protected IndexEntry[] IndexEntries; + + #endregion + + #region Hashes + + // TODO: Support SpamSum + + #endregion + + #endregion // Private instance variables + + #region Constructors + + /// + /// Create a new AaruFormat from an input file + /// + /// Filename respresenting the AaruFormat file + public static AaruFormat Create(string filename) + { + using (FileStream fs = FileExtensions.TryOpenRead(filename)) + { + return Create(fs); + } + } + + /// + /// Create a new AaruFormat from an input stream + /// + /// Stream representing the AaruFormat file + public static AaruFormat Create(Stream aarustream) + { + try + { + // Validate that this is actually a valid AaruFormat (by magic string alone) + bool validated = ValidateHeader(aarustream); + aarustream.Seek(-8, SeekOrigin.Current); // Seek back to start + if (!validated) + return null; + + // Read and retrun the current AaruFormat + AaruFormat generated = Deserialize(aarustream); + if (generated != null) + generated.Type = FileType.AaruFormat; + + return generated; + } + catch + { + return null; + } + } + + #endregion + + #region Header Parsing + + /// + /// Validate we start with the right magic number + /// + public static bool ValidateHeader(Stream aarustream) + { + // Read the magic string + byte[] magicBytes = new byte[8]; + int read = aarustream.Read(magicBytes, 0, 8); + + // If we didn't read the magic fully, we don't have an AaruFormat + if (read < 8) + return false; + + // If the bytes don't match, we don't have an AaruFormat + if (!magicBytes.StartsWith(Constants.AaruFormatSignature)) + return false; + + return true; + } + + /// + /// Read a stream as an AaruFormat + /// + /// AaruFormat file as a stream + /// Populated AaruFormat file, null on failure + public static AaruFormat Deserialize(Stream stream) + { + try + { + AaruFormat aif = new AaruFormat(); + + using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true)) + { + aif.Identifier = br.ReadUInt64(); + aif.Application = Encoding.Unicode.GetString(br.ReadBytes(64), 0, 64); + aif.ImageMajorVersion = br.ReadByte(); + aif.ImageMinorVersion = br.ReadByte(); + aif.ApplicationMajorVersion = br.ReadByte(); + aif.ApplicationMinorVersion = br.ReadByte(); + aif.MediaType = (AaruMediaType)br.ReadUInt32(); + aif.IndexOffset = br.ReadUInt64(); + aif.CreationTime = br.ReadInt64(); + aif.LastWrittenTime = br.ReadInt64(); + + // If the offset is bigger than the stream, we can't read it + if (aif.IndexOffset > (ulong)stream.Length) + return null; + + // Otherwise, we read in the index header + stream.Seek((long)aif.IndexOffset, SeekOrigin.Begin); + aif.IndexHeader = IndexHeader.Deserialize(stream); + if (aif.IndexHeader.entries == 0) + return null; + + // Get the list of entries + aif.IndexEntries = new IndexEntry[aif.IndexHeader.entries]; + for (ushort index = 0; index < aif.IndexHeader.entries; index++) + { + aif.IndexEntries[index] = IndexEntry.Deserialize(stream); + switch (aif.IndexEntries[index].blockType) + { + // We don't do anything with these block types currently + case AaruBlockType.DataBlock: + case AaruBlockType.DeDuplicationTable: + case AaruBlockType.Index: + case AaruBlockType.Index2: + case AaruBlockType.GeometryBlock: + case AaruBlockType.MetadataBlock: + case AaruBlockType.TracksBlock: + case AaruBlockType.CicmBlock: + case AaruBlockType.DataPositionMeasurementBlock: + case AaruBlockType.SnapshotBlock: + case AaruBlockType.ParentBlock: + case AaruBlockType.DumpHardwareBlock: + case AaruBlockType.TapeFileBlock: + case AaruBlockType.TapePartitionBlock: + case AaruBlockType.CompactDiscIndexesBlock: + // No-op + break; + + // Read in all available hashes + case AaruBlockType.ChecksumBlock: + // If the offset is bigger than the stream, we can't read it + if (aif.IndexEntries[index].offset > (ulong)stream.Length) + return null; + + // Otherwise, we read in the block + stream.Seek((long)aif.IndexEntries[index].offset, SeekOrigin.Begin); + ChecksumHeader checksumHeader = ChecksumHeader.Deserialize(stream); + if (checksumHeader.entries == 0) + return null; + + // Read through each and pick out the ones we care about + for (byte entry = 0; entry < checksumHeader.entries; entry++) + { + ChecksumEntry checksumEntry = ChecksumEntry.Deserialize(stream); + if (checksumEntry == null) + continue; + + switch (checksumEntry.type) + { + case AaruChecksumAlgorithm.Invalid: + break; + case AaruChecksumAlgorithm.Md5: + aif.MD5 = checksumEntry.checksum; + break; + case AaruChecksumAlgorithm.Sha1: + aif.SHA1 = checksumEntry.checksum; + break; + case AaruChecksumAlgorithm.Sha256: + aif.SHA256 = checksumEntry.checksum; + break; + case AaruChecksumAlgorithm.SpamSum: + // TODO: Support SpamSum + break; + } + } + + // Once we got hashes, we return early + return aif; + } + } + } + + return aif; + } + catch + { + // We don't care what the error was at this point + return null; + } + } + + #endregion + } +} diff --git a/SabreTools.Library/FileTypes/Enums.cs b/SabreTools.Library/FileTypes/Enums.cs index 96b064b1..764f63c2 100644 --- a/SabreTools.Library/FileTypes/Enums.cs +++ b/SabreTools.Library/FileTypes/Enums.cs @@ -1,5 +1,1178 @@ -namespace SabreTools.Library.FileTypes +using System; + +namespace SabreTools.Library.FileTypes { + /// + /// List of known blocks types + /// + /// + public enum AaruBlockType : uint + { + /// Block containing data + DataBlock = 0x4B4C4244, + /// Block containing a deduplication table + DeDuplicationTable = 0x2A544444, + /// Block containing the index + Index = 0x58444E49, + /// Block containing the index + Index2 = 0x32584449, + /// Block containing logical geometry + GeometryBlock = 0x4D4F4547, + /// Block containing metadata + MetadataBlock = 0x4154454D, + /// Block containing optical disc tracks + TracksBlock = 0x534B5254, + /// Block containing CICM XML metadata + CicmBlock = 0x4D434943, + /// Block containing contents checksums + ChecksumBlock = 0x4D534B43, + /// TODO: Block containing data position measurements + DataPositionMeasurementBlock = 0x2A4D5044, + /// TODO: Block containing a snapshot index + SnapshotBlock = 0x50414E53, + /// TODO: Block containing how to locate the parent image + ParentBlock = 0x50524E54, + /// Block containing an array of hardware used to create the image + DumpHardwareBlock = 0x2A504D44, + /// Block containing list of files for a tape image + TapeFileBlock = 0x454C4654, + /// Block containing list of partitions for a tape image + TapePartitionBlock = 0x54425054, + /// Block containing list of indexes for Compact Disc tracks + CompactDiscIndexesBlock = 0x58494443 + } + + /// + public enum AaruChecksumAlgorithm : byte + { + Invalid = 0, Md5 = 1, Sha1 = 2, + Sha256 = 3, SpamSum = 4 + } + + /// + /// List of known data types + /// + /// + public enum AaruDataType : ushort + { + /// No data + NoData = 0, + /// User data + UserData = 1, + /// CompactDisc partial Table of Contents + CompactDiscPartialToc = 2, + /// CompactDisc session information + CompactDiscSessionInfo = 3, + /// CompactDisc Table of Contents + CompactDiscToc = 4, + /// CompactDisc Power Management Area + CompactDiscPma = 5, + /// CompactDisc Absolute Time In Pregroove + CompactDiscAtip = 6, + /// CompactDisc Lead-in's CD-Text + CompactDiscLeadInCdText = 7, + /// DVD Physical Format Information + DvdPfi = 8, + /// DVD Lead-in's Copyright Management Information + DvdLeadInCmi = 9, + /// DVD Disc Key + DvdDiscKey = 10, + /// DVD Burst Cutting Area + DvdBca = 11, + /// DVD DMI + DvdDmi = 12, + /// DVD Media Identifier + DvdMediaIdentifier = 13, + /// DVD Media Key Block + DvdMediaKeyBlock = 14, + /// DVD-RAM Disc Definition Structure + DvdRamDds = 15, + /// DVD-RAM Medium Status + DvdRamMediumStatus = 16, + /// DVD-RAM Spare Area Information + DvdRamSpareArea = 17, + /// DVD-R RMD + DvdRRmd = 18, + /// DVD-R Pre-recorded Information + DvdRPrerecordedInfo = 19, + /// DVD-R Media Identifier + DvdRMediaIdentifier = 20, + /// DVD-R Physical Format Information + DvdRPfi = 21, + /// DVD ADress In Pregroove + DvdAdip = 22, + /// HD DVD Copy Protection Information + HdDvdCpi = 23, + /// HD DVD Medium Status + HdDvdMediumStatus = 24, + /// DVD DL Layer Capacity + DvdDlLayerCapacity = 25, + /// DVD DL Middle Zone Address + DvdDlMiddleZoneAddress = 26, + /// DVD DL Jump Interval Size + DvdDlJumpIntervalSize = 27, + /// DVD DL Manual Layer Jump LBA + DvdDlManualLayerJumpLba = 28, + /// Bluray Disc Information + BlurayDi = 29, + /// Bluray Burst Cutting Area + BlurayBca = 30, + /// Bluray Disc Definition Structure + BlurayDds = 31, + /// Bluray Cartridge Status + BlurayCartridgeStatus = 32, + /// Bluray Spare Area Information + BluraySpareArea = 33, + /// AACS Volume Identifier + AacsVolumeIdentifier = 34, + /// AACS Serial Number + AacsSerialNumber = 35, + /// AACS Media Identifier + AacsMediaIdentifier = 36, + /// AACS Media Key Block + AacsMediaKeyBlock = 37, + /// AACS Data Keys + AacsDataKeys = 38, + /// AACS LBA Extents + AacsLbaExtents = 39, + /// CPRM Media Key Block + CprmMediaKeyBlock = 40, + /// Recognized Layers + HybridRecognizedLayers = 41, + /// MMC Write Protection + ScsiMmcWriteProtection = 42, + /// MMC Disc Information + ScsiMmcDiscInformation = 43, + /// MMC Track Resources Information + ScsiMmcTrackResourcesInformation = 44, + /// MMC POW Resources Information + ScsiMmcPowResourcesInformation = 45, + /// SCSI INQUIRY RESPONSE + ScsiInquiry = 46, + /// SCSI MODE PAGE 2Ah + ScsiModePage2A = 47, + /// ATA IDENTIFY response + AtaIdentify = 48, + /// ATAPI IDENTIFY response + AtapiIdentify = 49, + /// PCMCIA CIS + PcmciaCis = 50, + /// SecureDigital CID + SecureDigitalCid = 51, + /// SecureDigital CSD + SecureDigitalCsd = 52, + /// SecureDigital SCR + SecureDigitalScr = 53, + /// SecureDigital OCR + SecureDigitalOcr = 54, + /// MultiMediaCard CID + MultiMediaCardCid = 55, + /// MultiMediaCard CSD + MultiMediaCardCsd = 56, + /// MultiMediaCard OCR + MultiMediaCardOcr = 57, + /// MultiMediaCard Extended CSD + MultiMediaCardExtendedCsd = 58, + /// Xbox Security Sector + XboxSecuritySector = 59, + /// Floppy Lead-out + FloppyLeadOut = 60, + /// Dvd Disc Control Block + DvdDiscControlBlock = 61, + /// CompactDisc First track pregap + CompactDiscFirstTrackPregap = 62, + /// CompactDisc Lead-out + CompactDiscLeadOut = 63, + /// SCSI MODE SENSE (6) response + ScsiModeSense6 = 64, + /// SCSI MODE SENSE (10) response + ScsiModeSense10 = 65, + /// USB descriptors + UsbDescriptors = 66, + /// Xbox DMI + XboxDmi = 67, + /// Xbox Physical Format Information + XboxPfi = 68, + /// CompactDisc sector prefix (sync, header + CdSectorPrefix = 69, + /// CompactDisc sector suffix (edc, ecc p, ecc q) + CdSectorSuffix = 70, + /// CompactDisc subchannel + CdSectorSubchannel = 71, + /// Apple Profile (20 byte) tag + AppleProfileTag = 72, + /// Apple Sony (12 byte) tag + AppleSonyTag = 73, + /// Priam Data Tower (24 byte) tag + PriamDataTowerTag = 74, + /// CompactDisc Media Catalogue Number (as in Lead-in), 13 bytes, ASCII + CompactDiscMediaCatalogueNumber = 75, + /// CompactDisc sector prefix (sync, header), only incorrect stored + CdSectorPrefixCorrected = 76, + /// CompactDisc sector suffix (edc, ecc p, ecc q), only incorrect stored + CdSectorSuffixCorrected = 77, + /// CompactDisc MODE 2 subheader + CompactDiscMode2Subheader = 78, + /// CompactDisc Lead-in + CompactDiscLeadIn = 79 + } + + /// + /// Internal media format for AaruFormat + /// + /// + public enum AaruMediaType : uint + { + #region Generics, types 0 to 9 + /// Unknown disk type + Unknown = 0, + /// Unknown magneto-optical + UnknownMO = 1, + /// Generic hard disk + GENERIC_HDD = 2, + /// Microdrive type hard disk + Microdrive = 3, + /// Zoned hard disk + Zone_HDD = 4, + /// USB flash drives + FlashDrive = 5, + /// USB flash drives + UnknownTape = 4, + #endregion Generics, types 0 to 9 + + #region Somewhat standard Compact Disc formats, types 10 to 39 + /// Any unknown or standard violating CD + CD = 10, + /// CD Digital Audio (Red Book) + CDDA = 11, + /// CD+G (Red Book) + CDG = 12, + /// CD+EG (Red Book) + CDEG = 13, + /// CD-i (Green Book) + CDI = 14, + /// CD-ROM (Yellow Book) + CDROM = 15, + /// CD-ROM XA (Yellow Book) + CDROMXA = 16, + /// CD+ (Blue Book) + CDPLUS = 17, + /// CD-MO (Orange Book) + CDMO = 18, + /// CD-Recordable (Orange Book) + CDR = 19, + /// CD-ReWritable (Orange Book) + CDRW = 20, + /// Mount-Rainier CD-RW + CDMRW = 21, + /// Video CD (White Book) + VCD = 22, + /// Super Video CD (White Book) + SVCD = 23, + /// Photo CD (Beige Book) + PCD = 24, + /// Super Audio CD (Scarlet Book) + SACD = 25, + /// Double-Density CD-ROM (Purple Book) + DDCD = 26, + /// DD CD-R (Purple Book) + DDCDR = 27, + /// DD CD-RW (Purple Book) + DDCDRW = 28, + /// DTS audio CD (non-standard) + DTSCD = 29, + /// CD-MIDI (Red Book) + CDMIDI = 30, + /// CD-Video (ISO/IEC 61104) + CDV = 31, + /// 120mm, Phase-Change, 1298496 sectors, 512 bytes/sector, PD650, ECMA-240, ISO 15485 + PD650 = 32, + /// 120mm, Write-Once, 1281856 sectors, 512 bytes/sector, PD650, ECMA-240, ISO 15485 + PD650_WORM = 33, + /// + /// CD-i Ready, contains a track before the first TOC track, in mode 2, and all TOC tracks are Audio. Subchannel + /// marks track as audio pause. + /// + CDIREADY = 34, FMTOWNS = 35, + #endregion Somewhat standard Compact Disc formats, types 10 to 39 + + #region Standard DVD formats, types 40 to 50 + /// DVD-ROM (applies to DVD Video and DVD Audio) + DVDROM = 40, + /// DVD-R + DVDR = 41, + /// DVD-RW + DVDRW = 42, + /// DVD+R + DVDPR = 43, + /// DVD+RW + DVDPRW = 44, + /// DVD+RW DL + DVDPRWDL = 45, + /// DVD-R DL + DVDRDL = 46, + /// DVD+R DL + DVDPRDL = 47, + /// DVD-RAM + DVDRAM = 48, + /// DVD-RW DL + DVDRWDL = 49, + /// DVD-Download + DVDDownload = 50, + #endregion Standard DVD formats, types 40 to 50 + + #region Standard HD-DVD formats, types 51 to 59 + /// HD DVD-ROM (applies to HD DVD Video) + HDDVDROM = 51, + /// HD DVD-RAM + HDDVDRAM = 52, + /// HD DVD-R + HDDVDR = 53, + /// HD DVD-RW + HDDVDRW = 54, + /// HD DVD-R DL + HDDVDRDL = 55, + /// HD DVD-RW DL + HDDVDRWDL = 56, + #endregion Standard HD-DVD formats, types 51 to 59 + + #region Standard Blu-ray formats, types 60 to 69 + /// BD-ROM (and BD Video) + BDROM = 60, + /// BD-R + BDR = 61, + /// BD-RE + BDRE = 62, + /// BD-R XL + BDRXL = 63, + /// BD-RE XL + BDREXL = 64, + #endregion Standard Blu-ray formats, types 60 to 69 + + #region Rare or uncommon optical standards, types 70 to 79 + /// Enhanced Versatile Disc + EVD = 70, + /// Forward Versatile Disc + FVD = 71, + /// Holographic Versatile Disc + HVD = 72, + /// China Blue High Definition + CBHD = 73, + /// High Definition Versatile Multilayer Disc + HDVMD = 74, + /// Versatile Compact Disc High Density + VCDHD = 75, + /// Stacked Volumetric Optical Disc + SVOD = 76, + /// Five Dimensional disc + FDDVD = 77, + /// China Video Disc + CVD = 78, + #endregion Rare or uncommon optical standards, types 70 to 79 + + #region LaserDisc based, types 80 to 89 + /// Pioneer LaserDisc + LD = 80, + /// Pioneer LaserDisc data + LDROM = 81, LDROM2 = 82, LVROM = 83, MegaLD = 84, + #endregion LaserDisc based, types 80 to 89 + + #region MiniDisc based, types 90 to 99 + /// Sony Hi-MD + HiMD = 90, + /// Sony MiniDisc + MD = 91, + /// Sony MD-Data + MDData = 92, + /// Sony MD-Data2 + MDData2 = 93, + /// Sony MiniDisc, 60 minutes, formatted with Hi-MD format + MD60 = 94, + /// Sony MiniDisc, 74 minutes, formatted with Hi-MD format + MD74 = 95, + /// Sony MiniDisc, 80 minutes, formatted with Hi-MD format + MD80 = 96, + #endregion MiniDisc based, types 90 to 99 + + #region Plasmon UDO, types 100 to 109 + /// 5.25", Phase-Change, 1834348 sectors, 8192 bytes/sector, Ultra Density Optical, ECMA-350, ISO 17345 + UDO = 100, + /// 5.25", Phase-Change, 3669724 sectors, 8192 bytes/sector, Ultra Density Optical 2, ECMA-380, ISO 11976 + UDO2 = 101, + /// 5.25", Write-Once, 3668759 sectors, 8192 bytes/sector, Ultra Density Optical 2, ECMA-380, ISO 11976 + UDO2_WORM = 102, + #endregion Plasmon UDO, types 100 to 109 + + #region Sony game media, types 110 to 129 + PlayStationMemoryCard = 110, PlayStationMemoryCard2 = 111, + /// Sony PlayStation game CD + PS1CD = 112, + /// Sony PlayStation 2 game CD + PS2CD = 113, + /// Sony PlayStation 2 game DVD + PS2DVD = 114, + /// Sony PlayStation 3 game DVD + PS3DVD = 115, + /// Sony PlayStation 3 game Blu-ray + PS3BD = 116, + /// Sony PlayStation 4 game Blu-ray + PS4BD = 117, + /// Sony PlayStation Portable Universal Media Disc (ECMA-365) + UMD = 118, PlayStationVitaGameCard = 119, + #endregion Sony game media, types 110 to 129 + + #region Microsoft game media, types 130 to 149 + /// Microsoft X-box Game Disc + XGD = 130, + /// Microsoft X-box 360 Game Disc + XGD2 = 131, + /// Microsoft X-box 360 Game Disc + XGD3 = 132, + /// Microsoft X-box One Game Disc + XGD4 = 133, + #endregion Microsoft game media, types 130 to 149 + + #region Sega game media, types 150 to 169 + /// Sega MegaCD + MEGACD = 150, + /// Sega Saturn disc + SATURNCD = 151, + /// Sega/Yamaha Gigabyte Disc + GDROM = 152, + /// Sega/Yamaha recordable Gigabyte Disc + GDR = 153, SegaCard = 154, MilCD = 155, + #endregion Sega game media, types 150 to 169 + + #region Other game media, types 170 to 179 + /// PC-Engine / TurboGrafx cartridge + HuCard = 170, + /// PC-Engine / TurboGrafx CD + SuperCDROM2 = 171, + /// Atari Jaguar CD + JaguarCD = 172, + /// 3DO CD + ThreeDO = 173, + /// NEC PC-FX + PCFX = 174, + /// NEO-GEO CD + NeoGeoCD = 175, + /// Commodore CDTV + CDTV = 176, + /// Amiga CD32 + CD32 = 177, + /// Nuon (DVD based videogame console) + Nuon = 178, + /// Bandai Playdia + Playdia = 179, + #endregion Other game media, types 170 to 179 + + #region Apple standard floppy format, types 180 to 189 + /// 5.25", SS, DD, 35 tracks, 13 spt, 256 bytes/sector, GCR + Apple32SS = 180, + /// 5.25", DS, DD, 35 tracks, 13 spt, 256 bytes/sector, GCR + Apple32DS = 181, + /// 5.25", SS, DD, 35 tracks, 16 spt, 256 bytes/sector, GCR + Apple33SS = 182, + /// 5.25", DS, DD, 35 tracks, 16 spt, 256 bytes/sector, GCR + Apple33DS = 183, + /// 3.5", SS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR + AppleSonySS = 184, + /// 3.5", DS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR + AppleSonyDS = 185, + /// 5.25", DS, ?D, ?? tracks, ?? spt, 512 bytes/sector, GCR, opposite side heads, aka Twiggy + AppleFileWare = 186, + #endregion Apple standard floppy format + + #region IBM/Microsoft PC floppy formats, types 190 to 209 + /// 5.25", SS, DD, 40 tracks, 8 spt, 512 bytes/sector, MFM + DOS_525_SS_DD_8 = 190, + /// 5.25", SS, DD, 40 tracks, 9 spt, 512 bytes/sector, MFM + DOS_525_SS_DD_9 = 191, + /// 5.25", DS, DD, 40 tracks, 8 spt, 512 bytes/sector, MFM + DOS_525_DS_DD_8 = 192, + /// 5.25", DS, DD, 40 tracks, 9 spt, 512 bytes/sector, MFM + DOS_525_DS_DD_9 = 193, + /// 5.25", DS, HD, 80 tracks, 15 spt, 512 bytes/sector, MFM + DOS_525_HD = 194, + /// 3.5", SS, DD, 80 tracks, 8 spt, 512 bytes/sector, MFM + DOS_35_SS_DD_8 = 195, + /// 3.5", SS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM + DOS_35_SS_DD_9 = 196, + /// 3.5", DS, DD, 80 tracks, 8 spt, 512 bytes/sector, MFM + DOS_35_DS_DD_8 = 197, + /// 3.5", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM + DOS_35_DS_DD_9 = 198, + /// 3.5", DS, HD, 80 tracks, 18 spt, 512 bytes/sector, MFM + DOS_35_HD = 199, + /// 3.5", DS, ED, 80 tracks, 36 spt, 512 bytes/sector, MFM + DOS_35_ED = 200, + /// 3.5", DS, HD, 80 tracks, 21 spt, 512 bytes/sector, MFM + DMF = 201, + /// 3.5", DS, HD, 82 tracks, 21 spt, 512 bytes/sector, MFM + DMF_82 = 202, + /// + /// 5.25", DS, HD, 80 tracks, ? spt, ??? + ??? + ??? bytes/sector, MFM track 0 = ??15 sectors, 512 bytes/sector, + /// falsified to DOS as 19 spt, 512 bps + /// + XDF_525 = 203, + /// + /// 3.5", DS, HD, 80 tracks, 4 spt, 8192 + 2048 + 1024 + 512 bytes/sector, MFM track 0 = 19 sectors, 512 + /// bytes/sector, falsified to DOS as 23 spt, 512 bps + /// + XDF_35 = 204, + #endregion IBM/Microsoft PC standard floppy formats, types 190 to 209 + + #region IBM standard floppy formats, types 210 to 219 + /// 8", SS, SD, 32 tracks, 8 spt, 319 bytes/sector, FM + IBM23FD = 210, + /// 8", SS, SD, 73 tracks, 26 spt, 128 bytes/sector, FM + IBM33FD_128 = 211, + /// 8", SS, SD, 74 tracks, 15 spt, 256 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector + IBM33FD_256 = 212, + /// 8", SS, SD, 74 tracks, 8 spt, 512 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector + IBM33FD_512 = 213, + /// 8", DS, SD, 74 tracks, 26 spt, 128 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector + IBM43FD_128 = 214, + /// 8", DS, SD, 74 tracks, 26 spt, 256 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector + IBM43FD_256 = 215, + /// + /// 8", DS, DD, 74 tracks, 26 spt, 256 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 + /// side 1 = 26 sectors, 256 bytes/sector + /// + IBM53FD_256 = 216, + /// + /// 8", DS, DD, 74 tracks, 15 spt, 512 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 + /// side 1 = 26 sectors, 256 bytes/sector + /// + IBM53FD_512 = 217, + /// + /// 8", DS, DD, 74 tracks, 8 spt, 1024 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 + /// side 1 = 26 sectors, 256 bytes/sector + /// + IBM53FD_1024 = 218, + #endregion IBM standard floppy formats, types 210 to 219 + + #region DEC standard floppy formats, types 220 to 229 + /// 8", SS, DD, 77 tracks, 26 spt, 128 bytes/sector, FM + RX01 = 220, + /// 8", SS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM/MFM + RX02 = 221, + /// 8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM/MFM + RX03 = 222, + /// 5.25", SS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM + RX50 = 223, + #endregion DEC standard floppy formats, types 220 to 229 + + #region Acorn standard floppy formats, types 230 to 239 + /// 5,25", SS, SD, 40 tracks, 10 spt, 256 bytes/sector, FM + ACORN_525_SS_SD_40 = 230, + /// 5,25", SS, SD, 80 tracks, 10 spt, 256 bytes/sector, FM + ACORN_525_SS_SD_80 = 231, + /// 5,25", SS, DD, 40 tracks, 16 spt, 256 bytes/sector, MFM + ACORN_525_SS_DD_40 = 232, + /// 5,25", SS, DD, 80 tracks, 16 spt, 256 bytes/sector, MFM + ACORN_525_SS_DD_80 = 233, + /// 5,25", DS, DD, 80 tracks, 16 spt, 256 bytes/sector, MFM + ACORN_525_DS_DD = 234, + /// 3,5", DS, DD, 80 tracks, 5 spt, 1024 bytes/sector, MFM + ACORN_35_DS_DD = 235, + /// 3,5", DS, HD, 80 tracks, 10 spt, 1024 bytes/sector, MFM + ACORN_35_DS_HD = 236, + #endregion Acorn standard floppy formats, types 230 to 239 + + #region Atari standard floppy formats, types 240 to 249 + /// 5,25", SS, SD, 40 tracks, 18 spt, 128 bytes/sector, FM + ATARI_525_SD = 240, + /// 5,25", SS, ED, 40 tracks, 26 spt, 128 bytes/sector, MFM + ATARI_525_ED = 241, + /// 5,25", SS, DD, 40 tracks, 18 spt, 256 bytes/sector, MFM + ATARI_525_DD = 242, + /// 3,5", SS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM + ATARI_35_SS_DD = 243, + /// 3,5", DS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM + ATARI_35_DS_DD = 244, + /// 3,5", SS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM + ATARI_35_SS_DD_11 = 245, + /// 3,5", DS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM + ATARI_35_DS_DD_11 = 246, + #endregion Atari standard floppy formats, types 240 to 249 + + #region Commodore standard floppy formats, types 250 to 259 + /// 3,5", DS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM (1581) + CBM_35_DD = 250, + /// 3,5", DS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM (Amiga) + CBM_AMIGA_35_DD = 251, + /// 3,5", DS, HD, 80 tracks, 22 spt, 512 bytes/sector, MFM (Amiga) + CBM_AMIGA_35_HD = 252, + /// 5,25", SS, DD, 35 tracks, GCR + CBM_1540 = 253, + /// 5,25", SS, DD, 40 tracks, GCR + CBM_1540_Ext = 254, + /// 5,25", DS, DD, 35 tracks, GCR + CBM_1571 = 255, + #endregion Commodore standard floppy formats, types 250 to 259 + + #region NEC/SHARP standard floppy formats, types 260 to 269 + /// 8", DS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM + NEC_8_SD = 260, + /// 8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, MFM + NEC_8_DD = 261, + /// 5.25", SS, SD, 80 tracks, 16 spt, 256 bytes/sector, FM + NEC_525_SS = 262, + /// 5.25", DS, SD, 80 tracks, 16 spt, 256 bytes/sector, MFM + NEC_525_DS = 263, + /// 5,25", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM + NEC_525_HD = 264, + /// 3,5", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM, aka mode 3 + NEC_35_HD_8 = 265, + /// 3,5", DS, HD, 80 tracks, 15 spt, 512 bytes/sector, MFM + NEC_35_HD_15 = 266, + /// 3,5", DS, TD, 240 tracks, 38 spt, 512 bytes/sector, MFM + NEC_35_TD = 267, + /// 5,25", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM + SHARP_525 = NEC_525_HD, + /// 3,5", DS, HD, 80 tracks, 9 spt, 1024 bytes/sector, MFM + SHARP_525_9 = 268, + /// 3,5", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM + SHARP_35 = NEC_35_HD_8, + /// 3,5", DS, HD, 80 tracks, 9 spt, 1024 bytes/sector, MFM + SHARP_35_9 = 269, + #endregion NEC/SHARP standard floppy formats, types 260 to 269 + + #region ECMA floppy standards, types 270 to 289 + /// + /// 5,25", DS, DD, 80 tracks, 8 spt, 1024 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track + /// 0 side 1 = 26 sectors, 256 bytes/sector + /// + ECMA_99_8 = 270, + /// + /// 5,25", DS, DD, 77 tracks, 15 spt, 512 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track + /// 0 side 1 = 26 sectors, 256 bytes/sector + /// + ECMA_99_15 = 271, + /// + /// 5,25", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track + /// 0 side 1 = 26 sectors, 256 bytes/sector + /// + ECMA_99_26 = 272, + /// 3,5", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM + ECMA_100 = DOS_35_DS_DD_9, + /// 3,5", DS, HD, 80 tracks, 18 spt, 512 bytes/sector, MFM + ECMA_125 = DOS_35_HD, + /// 3,5", DS, ED, 80 tracks, 36 spt, 512 bytes/sector, MFM + ECMA_147 = DOS_35_ED, + /// 8", SS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM + ECMA_54 = 273, + /// 8", DS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM + ECMA_59 = 274, + /// 5,25", SS, DD, 35 tracks, 9 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector + ECMA_66 = 275, + /// + /// 8", DS, DD, 77 tracks, 8 spt, 1024 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 + /// side 1 = 26 sectors, 256 bytes/sector + /// + ECMA_69_8 = 276, + /// + /// 8", DS, DD, 77 tracks, 15 spt, 512 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 + /// side 1 = 26 sectors, 256 bytes/sector + /// + ECMA_69_15 = 277, + /// + /// 8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 + /// side 1 = 26 sectors, 256 bytes/sector + /// + ECMA_69_26 = 278, + /// + /// 5,25", DS, DD, 40 tracks, 16 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector, track 0 + /// side 1 = 16 sectors, 256 bytes/sector + /// + ECMA_70 = 279, + /// + /// 5,25", DS, DD, 80 tracks, 16 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector, track 0 + /// side 1 = 16 sectors, 256 bytes/sector + /// + ECMA_78 = 280, + /// 5,25", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, FM + ECMA_78_2 = 281, + #endregion ECMA floppy standards, types 270 to 289 + + #region Non-standard PC formats (FDFORMAT, 2M, etc), types 290 to 308 + /// 5,25", DS, DD, 82 tracks, 10 spt, 512 bytes/sector, MFM + FDFORMAT_525_DD = 290, + /// 5,25", DS, HD, 82 tracks, 17 spt, 512 bytes/sector, MFM + FDFORMAT_525_HD = 291, + /// 3,5", DS, DD, 82 tracks, 10 spt, 512 bytes/sector, MFM + FDFORMAT_35_DD = 292, + /// 3,5", DS, HD, 82 tracks, 21 spt, 512 bytes/sector, MFM + FDFORMAT_35_HD = 293, + #endregion Non-standard PC formats (FDFORMAT, 2M, etc), types 290 to 308 + + #region Apricot ACT standard floppy formats, type 309 + /// 3.5", DS, DD, 70 tracks, 9 spt, 512 bytes/sector, MFM + Apricot_35 = 309, + #endregion Apricot ACT standard floppy formats, type 309 + + #region OnStream ADR, types 310 to 319 + ADR2120 = 310, ADR260 = 311, ADR30 = 312, + ADR50 = 313, + #endregion OnStream ADR, types 310 to 319 + + #region Advanced Intelligent Tape, types 320 to 339 + AIT1 = 320, AIT1Turbo = 321, AIT2 = 322, + AIT2Turbo = 323, AIT3 = 324, AIT3Ex = 325, + AIT3Turbo = 326, AIT4 = 327, AIT5 = 328, + AITETurbo = 329, SAIT1 = 330, SAIT2 = 331, + #endregion Advanced Intelligent Tape, types 320 to 339 + + #region Iomega, types 340 to 359 + /// Obsolete type for 8"x11" Bernoulli Box disk + [Obsolete] + Bernoulli = 340, + /// Obsolete type for 5⅓" Bernoulli Box II disks + [Obsolete] + Bernoulli2 = 341, Ditto = 342, DittoMax = 343, Jaz = 344, + Jaz2 = 345, PocketZip = 346, REV120 = 347, + REV35 = 348, REV70 = 349, ZIP100 = 350, + ZIP250 = 351, ZIP750 = 352, + /// 5⅓" Bernoulli Box II disk with 35Mb capacity + Bernoulli35 = 353, + /// 5⅓" Bernoulli Box II disk with 44Mb capacity + Bernoulli44 = 354, + /// 5⅓" Bernoulli Box II disk with 65Mb capacity + Bernoulli65 = 355, + /// 5⅓" Bernoulli Box II disk with 90Mb capacity + Bernoulli90 = 356, + /// 5⅓" Bernoulli Box II disk with 105Mb capacity + Bernoulli105 = 357, + /// 5⅓" Bernoulli Box II disk with 150Mb capacity + Bernoulli150 = 358, + /// 5⅓" Bernoulli Box II disk with 230Mb capacity + Bernoulli230 = 359, + #endregion Iomega, types 340 to 359 + + #region Audio or video media, types 360 to 369 + CompactCassette = 360, Data8 = 361, MiniDV = 362, + /// D/CAS-25: Digital data on Compact Cassette form factor, special magnetic media, 9-track + Dcas25 = 363, + /// D/CAS-85: Digital data on Compact Cassette form factor, special magnetic media, 17-track + Dcas85 = 364, + /// D/CAS-103: Digital data on Compact Cassette form factor, special magnetic media, 21-track + Dcas103 = 365, + #endregion Audio media, types 360 to 369 + + #region CompactFlash Association, types 370 to 379 + CFast = 370, CompactFlash = 371, CompactFlashType2 = 372, + #endregion CompactFlash Association, types 370 to 379 + + #region Digital Audio Tape / Digital Data Storage, types 380 to 389 + DigitalAudioTape = 380, DAT160 = 381, DAT320 = 382, + DAT72 = 383, DDS1 = 384, DDS2 = 385, + DDS3 = 386, DDS4 = 387, + #endregion Digital Audio Tape / Digital Data Storage, types 380 to 389 + + #region DEC, types 390 to 399 + CompactTapeI = 390, CompactTapeII = 391, DECtapeII = 392, + DLTtapeIII = 393, DLTtapeIIIxt = 394, DLTtapeIV = 395, + DLTtapeS4 = 396, SDLT1 = 397, SDLT2 = 398, + VStapeI = 399, + #endregion DEC, types 390 to 399 + + #region Exatape, types 400 to 419 + Exatape15m = 400, Exatape22m = 401, Exatape22mAME = 402, + Exatape28m = 403, Exatape40m = 404, Exatape45m = 405, + Exatape54m = 406, Exatape75m = 407, Exatape76m = 408, + Exatape80m = 409, Exatape106m = 410, Exatape160mXL = 411, + Exatape112m = 412, Exatape125m = 413, Exatape150m = 414, + Exatape170m = 415, Exatape225m = 416, + #endregion Exatape, types 400 to 419 + + #region PCMCIA / ExpressCard, types 420 to 429 + ExpressCard34 = 420, ExpressCard54 = 421, PCCardTypeI = 422, + PCCardTypeII = 423, PCCardTypeIII = 424, PCCardTypeIV = 425, + #endregion PCMCIA / ExpressCard, types 420 to 429 + + #region SyQuest, types 430 to 449 + /// SyQuest 135Mb cartridge for use in EZ135 and EZFlyer drives + EZ135 = 430, + /// SyQuest EZFlyer 230Mb cartridge for use in EZFlyer drive + EZ230 = 431, + /// SyQuest 4.7Gb for use in Quest drive + Quest = 432, + /// SyQuest SparQ 1Gb cartridge + SparQ = 433, + /// SyQuest 5Mb cartridge for SQ306RD drive + SQ100 = 434, + /// SyQuest 10Mb cartridge for SQ312RD drive + SQ200 = 435, + /// SyQuest 15Mb cartridge for SQ319RD drive + SQ300 = 436, + /// SyQuest 105Mb cartridge for SQ3105 and SQ3270 drives + SQ310 = 437, + /// SyQuest 270Mb cartridge for SQ3270 drive + SQ327 = 438, + /// SyQuest 44Mb cartridge for SQ555, SQ5110 and SQ5200C/SQ200 drives + SQ400 = 439, + /// SyQuest 88Mb cartridge for SQ5110 and SQ5200C/SQ200 drives + SQ800 = 440, + /// SyQuest 1.5Gb cartridge for SyJet drive + [Obsolete] + SQ1500 = 441, + /// SyQuest 200Mb cartridge for use in SQ5200C drive + SQ2000 = 442, + /// SyQuest 1.5Gb cartridge for SyJet drive + SyJet = 443, + #endregion SyQuest, types 430 to 449 + + #region Nintendo, types 450 to 469 + FamicomGamePak = 450, GameBoyAdvanceGamePak = 451, GameBoyGamePak = 452, + /// Nintendo GameCube Optical Disc + GOD = 453, N64DD = 454, N64GamePak = 455, NESGamePak = 456, + Nintendo3DSGameCard = 457, NintendoDiskCard = 458, NintendoDSGameCard = 459, + NintendoDSiGameCard = 460, SNESGamePak = 461, SNESGamePakUS = 462, + /// Nintendo Wii Optical Disc + WOD = 463, + /// Nintendo Wii U Optical Disc + WUOD = 464, SwitchGameCard = 465, + #endregion Nintendo, types 450 to 469 + + #region IBM Tapes, types 470 to 479 + IBM3470 = 470, IBM3480 = 471, IBM3490 = 472, + IBM3490E = 473, IBM3592 = 474, + #endregion IBM Tapes, types 470 to 479 + + #region LTO Ultrium, types 480 to 509 + LTO = 480, LTO2 = 481, LTO3 = 482, + LTO3WORM = 483, LTO4 = 484, LTO4WORM = 485, + LTO5 = 486, LTO5WORM = 487, LTO6 = 488, + LTO6WORM = 489, LTO7 = 490, LTO7WORM = 491, + #endregion LTO Ultrium, types 480 to 509 + + #region MemoryStick, types 510 to 519 + MemoryStick = 510, MemoryStickDuo = 511, MemoryStickMicro = 512, + MemoryStickPro = 513, MemoryStickProDuo = 514, + #endregion MemoryStick, types 510 to 519 + + #region SecureDigital, types 520 to 529 + microSD = 520, miniSD = 521, SecureDigital = 522, + #endregion SecureDigital, types 520 to 529 + + #region MultiMediaCard, types 530 to 539 + MMC = 530, MMCmicro = 531, RSMMC = 532, + MMCplus = 533, MMCmobile = 534, + #endregion MultiMediaCard, types 530 to 539 + + #region SLR, types 540 to 569 + MLR1 = 540, MLR1SL = 541, MLR3 = 542, + SLR1 = 543, SLR2 = 544, SLR3 = 545, + SLR32 = 546, SLR32SL = 547, SLR4 = 548, + SLR5 = 549, SLR5SL = 550, SLR6 = 551, + SLRtape7 = 552, SLRtape7SL = 553, SLRtape24 = 554, + SLRtape24SL = 555, SLRtape40 = 556, SLRtape50 = 557, + SLRtape60 = 558, SLRtape75 = 559, SLRtape100 = 560, + SLRtape140 = 561, + #endregion SLR, types 540 to 569 + + #region QIC, types 570 to 589 + QIC11 = 570, QIC120 = 571, QIC1350 = 572, + QIC150 = 573, QIC24 = 574, QIC3010 = 575, + QIC3020 = 576, QIC3080 = 577, QIC3095 = 578, + QIC320 = 579, QIC40 = 580, QIC525 = 581, + QIC80 = 582, + #endregion QIC, types 570 to 589 + + #region StorageTek tapes, types 590 to 609 + STK4480 = 590, STK4490 = 591, STK9490 = 592, + T9840A = 593, T9840B = 594, T9840C = 595, + T9840D = 596, T9940A = 597, T9940B = 598, + T10000A = 599, T10000B = 600, T10000C = 601, + T10000D = 602, + #endregion StorageTek tapes, types 590 to 609 + + #region Travan, types 610 to 619 + Travan = 610, Travan1Ex = 611, Travan3 = 612, + Travan3Ex = 613, Travan4 = 614, Travan5 = 615, + Travan7 = 616, + #endregion Travan, types 610 to 619 + + #region VXA, types 620 to 629 + VXA1 = 620, VXA2 = 621, VXA3 = 622, + #endregion VXA, types 620 to 629 + + #region Magneto-optical, types 630 to 659 + /// 5,25", M.O., WORM, 650Mb, 318750 sectors, 1024 bytes/sector, ECMA-153, ISO 11560 + ECMA_153 = 630, + /// 5,25", M.O., WORM, 600Mb, 581250 sectors, 512 bytes/sector, ECMA-153, ISO 11560 + ECMA_153_512 = 631, + /// 3,5", M.O., RW, 128Mb, 248826 sectors, 512 bytes/sector, ECMA-154, ISO 10090 + ECMA_154 = 632, + /// 5,25", M.O., RW/WORM, 1Gb, 904995 sectors, 512 bytes/sector, ECMA-183, ISO 13481 + ECMA_183_512 = 633, + /// 5,25", M.O., RW/WORM, 1Gb, 498526 sectors, 1024 bytes/sector, ECMA-183, ISO 13481 + ECMA_183 = 634, + /// 5,25", M.O., RW/WORM, 1.2Gb, 1165600 sectors, 512 bytes/sector, ECMA-184, ISO 13549 + ECMA_184_512 = 635, + /// 5,25", M.O., RW/WORM, 1.3Gb, 639200 sectors, 1024 bytes/sector, ECMA-184, ISO 13549 + ECMA_184 = 636, + /// 300mm, M.O., WORM, ??? sectors, 1024 bytes/sector, ECMA-189, ISO 13614 + ECMA_189 = 637, + /// 300mm, M.O., WORM, ??? sectors, 1024 bytes/sector, ECMA-190, ISO 13403 + ECMA_190 = 638, + /// 5,25", M.O., RW/WORM, 936921 or 948770 sectors, 1024 bytes/sector, ECMA-195, ISO 13842 + ECMA_195 = 639, + /// 5,25", M.O., RW/WORM, 1644581 or 1647371 sectors, 512 bytes/sector, ECMA-195, ISO 13842 + ECMA_195_512 = 640, + /// 3,5", M.O., 446325 sectors, 512 bytes/sector, ECMA-201, ISO 13963 + ECMA_201 = 641, + /// 3,5", M.O., 429975 sectors, 512 bytes/sector, embossed, ISO 13963 + ECMA_201_ROM = 642, + /// 3,5", M.O., 371371 sectors, 1024 bytes/sector, ECMA-223 + ECMA_223 = 643, + /// 3,5", M.O., 694929 sectors, 512 bytes/sector, ECMA-223 + ECMA_223_512 = 644, + /// 5,25", M.O., 1244621 sectors, 1024 bytes/sector, ECMA-238, ISO 15486 + ECMA_238 = 645, + /// 3,5", M.O., 310352, 320332 or 321100 sectors, 2048 bytes/sector, ECMA-239, ISO 15498 + ECMA_239 = 646, + /// 356mm, M.O., 14476734 sectors, 1024 bytes/sector, ECMA-260, ISO 15898 + ECMA_260 = 647, + /// 356mm, M.O., 24445990 sectors, 1024 bytes/sector, ECMA-260, ISO 15898 + ECMA_260_Double = 648, + /// 5,25", M.O., 1128134 sectors, 2048 bytes/sector, ECMA-280, ISO 18093 + ECMA_280 = 649, + /// 300mm, M.O., 7355716 sectors, 2048 bytes/sector, ECMA-317, ISO 20162 + ECMA_317 = 650, + /// 5,25", M.O., 1095840 sectors, 4096 bytes/sector, ECMA-322, ISO 22092 + ECMA_322 = 651, + /// 5,25", M.O., 2043664 sectors, 2048 bytes/sector, ECMA-322, ISO 22092 + ECMA_322_2k = 652, + /// 3,5", M.O., 605846 sectors, 2048 bytes/sector, Cherry Book, GigaMo, ECMA-351, ISO 17346 + GigaMo = 653, + /// 3,5", M.O., 1063146 sectors, 2048 bytes/sector, Cherry Book 2, GigaMo 2, ECMA-353, ISO 22533 + GigaMo2 = 654, + #endregion Magneto-optical, types 630 to 659 + + #region Other floppy standards, types 660 to 689 + CompactFloppy = 660, DemiDiskette = 661, + /// 3.5", 652 tracks, 2 sides, 512 bytes/sector, Floptical, ECMA-207, ISO 14169 + Floptical = 662, HiFD = 663, QuickDisk = 664, UHD144 = 665, + VideoFloppy = 666, Wafer = 667, ZXMicrodrive = 668, + #endregion Other floppy standards, types 660 to 669 + + #region Miscellaneous, types 670 to 689 + BeeCard = 670, Borsu = 671, DataStore = 672, + DIR = 673, DST = 674, DTF = 675, + DTF2 = 676, Flextra3020 = 677, Flextra3225 = 678, + HiTC1 = 679, HiTC2 = 680, LT1 = 681, + MiniCard = 872, Orb = 683, Orb5 = 684, + SmartMedia = 685, xD = 686, XQD = 687, + DataPlay = 688, + #endregion Miscellaneous, types 670 to 689 + + #region Apple specific media, types 690 to 699 + AppleProfile = 690, AppleWidget = 691, AppleHD20 = 692, + PriamDataTower = 693, Pippin = 694, + #endregion Apple specific media, types 690 to 699 + + #region DEC hard disks, types 700 to 729 + /// + /// 2382 cylinders, 4 tracks/cylinder, 42 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 204890112 bytes + /// + RA60 = 700, + /// + /// 546 cylinders, 14 tracks/cylinder, 31 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 121325568 bytes + /// + RA80 = 701, + /// + /// 1248 cylinders, 14 tracks/cylinder, 51 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 456228864 bytes + /// + RA81 = 702, + /// + /// 302 cylinders, 4 tracks/cylinder, 42 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 25976832 + /// bytes + /// + RC25 = 703, + /// + /// 615 cylinders, 4 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 21411840 + /// bytes + /// + RD31 = 704, + /// + /// 820 cylinders, 6 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 42823680 + /// bytes + /// + RD32 = 705, + /// + /// 306 cylinders, 4 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 10653696 + /// bytes + /// + RD51 = 706, + /// + /// 480 cylinders, 7 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 30965760 + /// bytes + /// + RD52 = 707, + /// + /// 1024 cylinders, 7 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 75497472 bytes + /// + RD53 = 708, + /// + /// 1225 cylinders, 8 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 159936000 bytes + /// + RD54 = 709, + /// + /// 411 cylinders, 3 tracks/cylinder, 22 sectors/track, 256 words/sector, 16 bits/word, 512 bytes/sector, 13888512 + /// bytes + /// + RK06 = 710, + /// + /// 411 cylinders, 3 tracks/cylinder, 20 sectors/track, 256 words/sector, 18 bits/word, 576 bytes/sector, 14204160 + /// bytes + /// + RK06_18 = 711, + /// + /// 815 cylinders, 3 tracks/cylinder, 22 sectors/track, 256 words/sector, 16 bits/word, 512 bytes/sector, 27540480 + /// bytes + /// + RK07 = 712, + /// + /// 815 cylinders, 3 tracks/cylinder, 20 sectors/track, 256 words/sector, 18 bits/word, 576 bytes/sector, 28166400 + /// bytes + /// + RK07_18 = 713, + /// + /// 823 cylinders, 5 tracks/cylinder, 32 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 67420160 + /// bytes + /// + RM02 = 714, + /// + /// 823 cylinders, 5 tracks/cylinder, 32 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, 67420160 + /// bytes + /// + RM03 = 715, + /// + /// 823 cylinders, 19 tracks/cylinder, 32 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 256196608 bytes + /// + RM05 = 716, + /// + /// 203 cylinders, 10 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 22865920 bytes + /// + RP02 = 717, + /// + /// 203 cylinders, 10 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, + /// 23385600 bytes + /// + RP02_18 = 718, + /// + /// 400 cylinders, 10 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 45056000 bytes + /// + RP03 = 719, + /// + /// 400 cylinders, 10 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, + /// 46080000 bytes + /// + RP03_18 = 720, + /// + /// 411 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 87960576 bytes + /// + RP04 = 721, + /// + /// 411 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, + /// 89959680 bytes + /// + RP04_18 = 722, + /// + /// 411 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 87960576 bytes + /// + RP05 = 723, + /// + /// 411 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, + /// 89959680 bytes + /// + RP05_18 = 724, + /// + /// 815 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, + /// 174423040 bytes + /// + RP06 = 725, + /// + /// 815 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 bytes/sector, + /// 178387200 bytes + /// + RP06_18 = 726, + #endregion DEC hard disks, types 700 to 729 + + #region Imation, types 730 to 739 + LS120 = 730, LS240 = 731, FD32MB = 732, + RDX = 733, + /// Imation 320Gb RDX + RDX320 = 734, + #endregion Imation, types 730 to 739 + + #region VideoNow, types 740 to 749 + VideoNow = 740, VideoNowColor = 741, VideoNowXp = 742, + #endregion + + #region Iomega, types 750 to 759 + /// 8"x11" Bernoulli Box disk with 10Mb capacity + Bernoulli10 = 750, + /// 8"x11" Bernoulli Box disk with 20Mb capacity + Bernoulli20 = 751, + /// 5⅓" Bernoulli Box II disk with 20Mb capacity + BernoulliBox2_20 = 752, + #endregion Iomega, types 750 to 759 + + #region Kodak, types 760 to 769 + KodakVerbatim3 = 760, KodakVerbatim6 = 761, KodakVerbatim12 = 762, + #endregion Kodak, types 760 to 769 + + #region Sony and Panasonic Blu-ray derived, types 770 to 799 + /// Professional Disc for video, single layer, rewritable, 23Gb + ProfessionalDisc = 770, + /// Professional Disc for video, dual layer, rewritable, 50Gb + ProfessionalDiscDual = 771, + /// Professional Disc for video, triple layer, rewritable, 100Gb + ProfessionalDiscTriple = 772, + /// Professional Disc for video, quad layer, write once, 128Gb + ProfessionalDiscQuad = 773, + /// Professional Disc for DATA, single layer, rewritable, 23Gb + PDD = 774, + /// Professional Disc for DATA, single layer, write once, 23Gb + PDD_WORM = 775, + /// Archival Disc, 1st gen., 300Gb + ArchivalDisc = 776, + /// Archival Disc, 2nd gen., 500Gb + ArchivalDisc2 = 777, + /// Archival Disc, 3rd gen., 1Tb + ArchivalDisc3 = 778, + /// Optical Disc archive, 1st gen., write once, 300Gb + ODC300R = 779, + /// Optical Disc archive, 1st gen., rewritable, 300Gb + ODC300RE = 780, + /// Optical Disc archive, 2nd gen., write once, 600Gb + ODC600R = 781, + /// Optical Disc archive, 2nd gen., rewritable, 600Gb + ODC600RE = 782, + /// Optical Disc archive, 3rd gen., rewritable, 1200Gb + ODC1200RE = 783, + /// Optical Disc archive, 3rd gen., write once, 1500Gb + ODC1500R = 784, + /// Optical Disc archive, 4th gen., write once, 3300Gb + ODC3300R = 785, + /// Optical Disc archive, 5th gen., write once, 5500Gb + ODC5500R = 786 + #endregion Sony and Panasonic Blu-ray derived, types 770 to 799 + } + /// /// Compression being used in CHD /// @@ -86,6 +1259,7 @@ { // Singleton None = 0, + AaruFormat, CHD, // Can contain children diff --git a/SabreTools.Library/FileTypes/Folder.cs b/SabreTools.Library/FileTypes/Folder.cs index 9eae283b..e6bd975d 100644 --- a/SabreTools.Library/FileTypes/Folder.cs +++ b/SabreTools.Library/FileTypes/Folder.cs @@ -362,9 +362,9 @@ namespace SabreTools.Library.FileTypes if (rom.ItemType == ItemType.Rom) { - if (date && !string.IsNullOrWhiteSpace(((Rom)rom).Date)) + if (date && !string.IsNullOrWhiteSpace((rom as Rom).Date)) { - File.SetCreationTime(fileName, DateTime.Parse(((Rom)rom).Date)); + File.SetCreationTime(fileName, DateTime.Parse((rom as Rom).Date)); } } diff --git a/SabreTools.Library/FileTypes/RarArchive.cs b/SabreTools.Library/FileTypes/RarArchive.cs index 1c33dc15..f16c6f45 100644 --- a/SabreTools.Library/FileTypes/RarArchive.cs +++ b/SabreTools.Library/FileTypes/RarArchive.cs @@ -204,7 +204,7 @@ namespace SabreTools.Library.FileTypes else { Stream entryStream = entry.OpenEntryStream(); - BaseFile rarEntryRom = entryStream.GetInfo(entry.Size, omitFromScan); + BaseFile rarEntryRom = entryStream.GetInfo(size: entry.Size, omitFromScan: omitFromScan); rarEntryRom.Filename = entry.Key; rarEntryRom.Parent = gamename; rarEntryRom.Date = entry.LastModifiedTime?.ToString("yyyy/MM/dd hh:mm:ss"); diff --git a/SabreTools.Library/FileTypes/SevenZipArchive.cs b/SabreTools.Library/FileTypes/SevenZipArchive.cs index 13bcb6e1..2e41a20f 100644 --- a/SabreTools.Library/FileTypes/SevenZipArchive.cs +++ b/SabreTools.Library/FileTypes/SevenZipArchive.cs @@ -316,7 +316,7 @@ namespace SabreTools.Library.FileTypes // Otherwise, use the stream directly else { - BaseFile zipEntryRom = readStream.GetInfo((long)zf.UncompressedSize(i), omitFromScan, true); + BaseFile zipEntryRom = readStream.GetInfo(size: (long)zf.UncompressedSize(i), omitFromScan: omitFromScan, keepReadOpen: true); zipEntryRom.Filename = zf.Filename(i); zipEntryRom.Parent = gamename; found.Add(zipEntryRom); diff --git a/SabreTools.Library/FileTypes/TapeArchive.cs b/SabreTools.Library/FileTypes/TapeArchive.cs index cd88ea4a..2bdbc3cb 100644 --- a/SabreTools.Library/FileTypes/TapeArchive.cs +++ b/SabreTools.Library/FileTypes/TapeArchive.cs @@ -209,7 +209,7 @@ namespace SabreTools.Library.FileTypes else { Stream entryStream = entry.OpenEntryStream(); - BaseFile tarEntryRom = entryStream.GetInfo(entry.Size, omitFromScan); + BaseFile tarEntryRom = entryStream.GetInfo(size: entry.Size, omitFromScan: omitFromScan); tarEntryRom.Filename = entry.Key; tarEntryRom.Parent = gamename; tarEntryRom.Date = entry.LastModifiedTime?.ToString("yyyy/MM/dd hh:mm:ss"); diff --git a/SabreTools.Library/FileTypes/ZipArchive.cs b/SabreTools.Library/FileTypes/ZipArchive.cs index 366c2a30..3f39ac44 100644 --- a/SabreTools.Library/FileTypes/ZipArchive.cs +++ b/SabreTools.Library/FileTypes/ZipArchive.cs @@ -319,7 +319,7 @@ namespace SabreTools.Library.FileTypes // Otherwise, use the stream directly else { - BaseFile zipEntryRom = readStream.GetInfo((long)zf.UncompressedSize(i), omitFromScan, true); + BaseFile zipEntryRom = readStream.GetInfo(size: (long)zf.UncompressedSize(i), omitFromScan: omitFromScan, keepReadOpen: true); zipEntryRom.Filename = zf.Filename(i); zipEntryRom.Parent = gamename; string convertedDate = zf.LastModified(i).ToString("yyyy/MM/dd hh:mm:ss"); diff --git a/SabreTools.Library/Filtering/Filter.cs b/SabreTools.Library/Filtering/Filter.cs index 9f1b59ad..ffbb75be 100644 --- a/SabreTools.Library/Filtering/Filter.cs +++ b/SabreTools.Library/Filtering/Filter.cs @@ -321,13 +321,7 @@ namespace SabreTools.Library.Filtering // Disk public FilterItem DatItem_MD5 { get; private set; } = new FilterItem(); -#if NET_FRAMEWORK - public FilterItem DatItem_RIPEMD160 { get; private set; } = new FilterItem(); -#endif public FilterItem DatItem_SHA1 { get; private set; } = new FilterItem(); - public FilterItem DatItem_SHA256 { get; private set; } = new FilterItem(); - public FilterItem DatItem_SHA384 { get; private set; } = new FilterItem(); - public FilterItem DatItem_SHA512 { get; private set; } = new FilterItem(); public FilterItem DatItem_Merge { get; private set; } = new FilterItem(); public FilterItem DatItem_Region { get; private set; } = new FilterItem(); public FilterItem DatItem_Index { get; private set; } = new FilterItem(); @@ -335,6 +329,9 @@ namespace SabreTools.Library.Filtering public FilterItem DatItem_Optional { get; private set; } = new FilterItem() { Neutral = null }; public FilterItem DatItem_Status { get; private set; } = new FilterItem() { Positive = ItemStatus.NULL, Negative = ItemStatus.NULL }; + // Media + public FilterItem DatItem_SHA256 { get; private set; } = new FilterItem(); + // Release public FilterItem DatItem_Language { get; private set; } = new FilterItem(); public FilterItem DatItem_Date { get; private set; } = new FilterItem(); @@ -343,6 +340,11 @@ namespace SabreTools.Library.Filtering public FilterItem DatItem_Bios { get; private set; } = new FilterItem(); public FilterItem DatItem_Size { get; private set; } = new FilterItem() { Positive = -1, Negative = -1, Neutral = -1 }; public FilterItem DatItem_CRC { get; private set; } = new FilterItem(); +#if NET_FRAMEWORK + public FilterItem DatItem_RIPEMD160 { get; private set; } = new FilterItem(); +#endif + public FilterItem DatItem_SHA384 { get; private set; } = new FilterItem(); + public FilterItem DatItem_SHA512 { get; private set; } = new FilterItem(); public FilterItem DatItem_Offset { get; private set; } = new FilterItem(); public FilterItem DatItem_Inverted { get; private set; } = new FilterItem(); @@ -1832,15 +1834,6 @@ namespace SabreTools.Library.Filtering DatItem_MD5.PositiveSet.Add(value); break; -#if NET_FRAMEWORK - case Field.DatItem_RIPEMD160: - if (negate) - DatItem_RIPEMD160.NegativeSet.Add(value); - else - DatItem_RIPEMD160.PositiveSet.Add(value); - break; -#endif - case Field.DatItem_SHA1: if (negate) DatItem_SHA1.NegativeSet.Add(value); @@ -1848,27 +1841,6 @@ namespace SabreTools.Library.Filtering DatItem_SHA1.PositiveSet.Add(value); break; - case Field.DatItem_SHA256: - if (negate) - DatItem_SHA256.NegativeSet.Add(value); - else - DatItem_SHA256.PositiveSet.Add(value); - break; - - case Field.DatItem_SHA384: - if (negate) - DatItem_SHA384.NegativeSet.Add(value); - else - DatItem_SHA384.PositiveSet.Add(value); - break; - - case Field.DatItem_SHA512: - if (negate) - DatItem_SHA512.NegativeSet.Add(value); - else - DatItem_SHA512.PositiveSet.Add(value); - break; - case Field.DatItem_Merge: if (negate) DatItem_Merge.NegativeSet.Add(value); @@ -1911,6 +1883,14 @@ namespace SabreTools.Library.Filtering DatItem_Status.Positive |= value.AsItemStatus(); break; + // Media + case Field.DatItem_SHA256: + if (negate) + DatItem_SHA256.NegativeSet.Add(value); + else + DatItem_SHA256.PositiveSet.Add(value); + break; + // Release case Field.DatItem_Language: if (negate) @@ -1993,6 +1973,29 @@ namespace SabreTools.Library.Filtering DatItem_CRC.PositiveSet.Add(value); break; +#if NET_FRAMEWORK + case Field.DatItem_RIPEMD160: + if (negate) + DatItem_RIPEMD160.NegativeSet.Add(value); + else + DatItem_RIPEMD160.PositiveSet.Add(value); + break; +#endif + + case Field.DatItem_SHA384: + if (negate) + DatItem_SHA384.NegativeSet.Add(value); + else + DatItem_SHA384.PositiveSet.Add(value); + break; + + case Field.DatItem_SHA512: + if (negate) + DatItem_SHA512.NegativeSet.Add(value); + else + DatItem_SHA512.PositiveSet.Add(value); + break; + case Field.DatItem_Offset: if (negate) DatItem_Offset.NegativeSet.Add(value); diff --git a/SabreTools.Library/IO/FileExtensions.cs b/SabreTools.Library/IO/FileExtensions.cs index 7e244373..051b9357 100644 --- a/SabreTools.Library/IO/FileExtensions.cs +++ b/SabreTools.Library/IO/FileExtensions.cs @@ -245,6 +245,10 @@ namespace SabreTools.Library.IO { outFileType = FileType.SevenZipArchive; } + else if (magic.StartsWith(Constants.AaruFormatSignature)) + { + outFileType = FileType.AaruFormat; + } else if (magic.StartsWith(Constants.CHDSignature)) { outFileType = FileType.CHD; @@ -307,7 +311,7 @@ namespace SabreTools.Library.IO /// Second byte array to compare /// True if the input arrays should match exactly, false otherwise (default) /// True if the first byte array starts with the second, false otherwise - private static bool StartsWith(this byte[] arr1, byte[] arr2, bool exact = false) + public static bool StartsWith(this byte[] arr1, byte[] arr2, bool exact = false) { // If we have any invalid inputs, we return false if (arr1 == null || arr2 == null @@ -335,9 +339,10 @@ namespace SabreTools.Library.IO /// Hash flag saying what hashes should not be calculated (defaults to none) /// True if the file Date should be included, false otherwise (default) /// Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise + /// True if AaruFormats should be treated like regular files, false otherwise /// True if CHDs should be treated like regular files, false otherwise /// Populated BaseFile object if success, empty one on error - public static BaseFile GetInfo(string input, Hash omitFromScan = 0x0, bool date = false, string header = null, bool chdsAsFiles = true) + public static BaseFile GetInfo(string input, Hash omitFromScan = 0x0, bool date = false, string header = null, bool aaruFormatAsFiles = true, bool chdsAsFiles = true) { // Add safeguard if file doesn't exist if (!File.Exists(input)) @@ -358,7 +363,7 @@ namespace SabreTools.Library.IO // Transform the stream and get the information from it rule.TransformStream(inputStream, outputStream, keepReadOpen: false, keepWriteOpen: true); - baseFile = outputStream.GetInfo(omitFromScan: omitFromScan, keepReadOpen: false, chdsAsFiles: chdsAsFiles); + baseFile = outputStream.GetInfo(omitFromScan: omitFromScan, keepReadOpen: false, aaruFormatAsFiles: aaruFormatAsFiles, chdsAsFiles: chdsAsFiles); // Dispose of the streams outputStream.Dispose(); @@ -367,12 +372,12 @@ namespace SabreTools.Library.IO // Otherwise, just get the info else { - baseFile = TryOpenRead(input).GetInfo(omitFromScan: omitFromScan, keepReadOpen: false, chdsAsFiles: chdsAsFiles); + baseFile = TryOpenRead(input).GetInfo(omitFromScan: omitFromScan, keepReadOpen: false, aaruFormatAsFiles: aaruFormatAsFiles, chdsAsFiles: chdsAsFiles); } } else { - baseFile = TryOpenRead(input).GetInfo(omitFromScan: omitFromScan, keepReadOpen: false, chdsAsFiles: chdsAsFiles); + baseFile = TryOpenRead(input).GetInfo(omitFromScan: omitFromScan, keepReadOpen: false, aaruFormatAsFiles: aaruFormatAsFiles, chdsAsFiles: chdsAsFiles); } // Add unique data from the file diff --git a/SabreTools.Library/IO/PathExtensions.cs b/SabreTools.Library/IO/PathExtensions.cs index 69779257..45557bb8 100644 --- a/SabreTools.Library/IO/PathExtensions.cs +++ b/SabreTools.Library/IO/PathExtensions.cs @@ -76,6 +76,14 @@ namespace SabreTools.Library.IO // Check against the list of known archive extensions switch (ext) { + // Aaruformat + case "aaru": + case "aaruf": + case "aaruformat": + case "aif": + case "dicf": + + // Archives case "7z": case "gz": case "lzma": @@ -88,6 +96,9 @@ namespace SabreTools.Library.IO case "tlz": case "zip": case "zipx": + + // CHD + case "chd": return true; default: return false; diff --git a/SabreTools.Library/IO/StreamExtensions.cs b/SabreTools.Library/IO/StreamExtensions.cs index 30fb1068..bf99e42a 100644 --- a/SabreTools.Library/IO/StreamExtensions.cs +++ b/SabreTools.Library/IO/StreamExtensions.cs @@ -45,11 +45,12 @@ namespace SabreTools.Library.IO /// Size of the input stream /// Hash flag saying what hashes should not be calculated (defaults to none) /// True if the underlying read stream should be kept open, false otherwise + /// True if AaruFormats should be treated like regular files, false otherwise /// True if CHDs should be treated like regular files, false otherwise /// Populated BaseFile object if success, empty one on error - public static BaseFile GetInfo(this Stream input, long size = -1, Hash omitFromScan = 0x0, bool keepReadOpen = false, bool chdsAsFiles = true) + public static BaseFile GetInfo(this Stream input, long size = -1, Hash omitFromScan = 0x0, bool keepReadOpen = false, bool aaruFormatAsFiles = true, bool chdsAsFiles = true) { - return GetInfoAsync(input, size, omitFromScan, keepReadOpen, chdsAsFiles).ConfigureAwait(false).GetAwaiter().GetResult(); + return GetInfoAsync(input, size, omitFromScan, keepReadOpen, aaruFormatAsFiles, chdsAsFiles).ConfigureAwait(false).GetAwaiter().GetResult(); } /// @@ -59,15 +60,32 @@ namespace SabreTools.Library.IO /// Size of the input stream /// Hash flag saying what hashes should not be calculated (defaults to none) /// True if the underlying read stream should be kept open, false otherwise + /// True if AaruFormats should be treated like regular files, false otherwise /// True if CHDs should be treated like regular files, false otherwise /// Populated BaseFile object if success, empty one on error - public static async Task GetInfoAsync(Stream input, long size = -1, Hash omitFromScan = 0x0, bool keepReadOpen = false, bool chdsAsFiles = true) + public static async Task GetInfoAsync(Stream input, long size = -1, Hash omitFromScan = 0x0, bool keepReadOpen = false, bool aaruFormatAsFiles = true, bool chdsAsFiles = true) { // If we want to automatically set the size if (size == -1) size = input.Length; - // We first check to see if it's a CHD if we have to + // We first check to see if it's an AaruFormat if we have to + if (!aaruFormatAsFiles) + { + var aaruFormat = AaruFormat.Create(input); + input.SeekIfPossible(); + + // If we found a valid AaruFormat + if (aaruFormat != null) + { + if (!keepReadOpen) + input.Dispose(); + + return aaruFormat; + } + } + + // Then, we first check to see if it's a CHD if we have to if (!chdsAsFiles) { var chd = CHDFile.Create(input); diff --git a/SabreTools.Library/README.1ST b/SabreTools.Library/README.1ST index 45fb492b..1c69b387 100644 --- a/SabreTools.Library/README.1ST +++ b/SabreTools.Library/README.1ST @@ -233,11 +233,21 @@ Options: Normally, the DAT will be created with the date in the file name in brackets. This flag removes that instead of the default. + -caf, --aaruformats-as-files Treat AaruFormats as regular files + Normally, AaruFormats would be processed using their internal hash to + compare against the input DATs. This flag forces all AaruFormats to be + treated like regular files. + -aaf, --archives-as-files Treat archives as files Instead of trying to enumerate the files within archives, treat the archives as files themselves. This is good for uncompressed sets that include archives that should be read as-is. + -ic, --chds-as-files Treat CHDs as regular files + Normally, CHDs would be processed using their internal hash to + compare against the input DATs. This flag forces all CHDs to be + treated like regular files. + -ot=, --output-type= Output DATs to a specified format Add outputting the created DAT to known format. Multiple instances of this flag are allowed. @@ -387,11 +397,6 @@ Options: or specific copier headers by name (such as "fds.xml") to determine if a file matches or not. - -ic, --chds-as-files Treat CHDs as regular files - Normally, CHDs would be processed using their internal hash to - compare against the input DATs. This flag forces all CHDs to be - treated like regular files. - -ini=, --extra-ini= Apply a MAME INI for given field(s) Apply any valid MAME INI for any valid field in the DatFile. Inputs are of the form 'Field:path\to\ini'. Multiple instances of this flag are @@ -687,6 +692,11 @@ Options: can only get the CRC and size from most archive formats, leading to possible issues. + -caf, --aaruformats-as-files Treat AaruFormats as regular files + Normally, AaruFormats would be processed using their internal hash to + compare against the input DATs. This flag forces all AaruFormats to be + treated like regular files. + -ic, --chds-as-files Treat CHDs as regular files Normally, CHDs would be processed using their internal hash to compare against the input DATs. This flag forces all CHDs to be @@ -1606,6 +1616,11 @@ Options: or specific copier headers by name (such as "fds.xml") to determine if a file matches or not. + -caf, --aaruformats-as-files Treat AaruFormats as regular files + Normally, AaruFormats would be processed using their internal hash to + compare against the input DATs. This flag forces all AaruFormats to be + treated like regular files. + -ic, --chds-as-files Treat CHDs as regular files Normally, CHDs would be processed using their internal hash to compare against the input DATs. This flag forces all CHDs to be diff --git a/SabreTools.Library/Skippers/Transform.cs b/SabreTools.Library/Skippers/Transform.cs index ac65f649..67c0160d 100644 --- a/SabreTools.Library/Skippers/Transform.cs +++ b/SabreTools.Library/Skippers/Transform.cs @@ -118,7 +118,7 @@ namespace SabreTools.Library.Skippers // Now add the information to the database if it's not already there if (!nostore) { - BaseFile baseFile = FileExtensions.GetInfo(newfile, chdsAsFiles: true); + BaseFile baseFile = FileExtensions.GetInfo(newfile, aaruFormatAsFiles: true, chdsAsFiles: true); DatabaseTools.AddHeaderToDatabase(hstr, Utilities.ByteArrayToString(baseFile.SHA1), rule.SourceFile); } @@ -138,7 +138,7 @@ namespace SabreTools.Library.Skippers Directory.CreateDirectory(outDir); // First, get the SHA-1 hash of the file - BaseFile baseFile = FileExtensions.GetInfo(file, chdsAsFiles: true); + BaseFile baseFile = FileExtensions.GetInfo(file, aaruFormatAsFiles: true, chdsAsFiles: true); // Retrieve a list of all related headers from the database List headers = DatabaseTools.RetrieveHeadersFromDatabase(Utilities.ByteArrayToString(baseFile.SHA1)); diff --git a/SabreTools.Library/Tools/Converters.cs b/SabreTools.Library/Tools/Converters.cs index 265d8cfb..5b8ace98 100644 --- a/SabreTools.Library/Tools/Converters.cs +++ b/SabreTools.Library/Tools/Converters.cs @@ -1528,6 +1528,8 @@ namespace SabreTools.Library.Tools return ItemType.Chip; case "disk": return ItemType.Disk; + case "media": + return ItemType.Media; case "release": return ItemType.Release; case "rom": @@ -1545,6 +1547,7 @@ namespace SabreTools.Library.Tools "blank" => ItemType.Blank, "chip" => ItemType.Chip, "disk" => ItemType.Disk, + "media" => ItemType.Media, "release" => ItemType.Release, "rom" => ItemType.Rom, "sample" => ItemType.Sample, @@ -1914,6 +1917,8 @@ namespace SabreTools.Library.Tools return "chip"; case ItemType.Disk: return "disk"; + case ItemType.Media: + return "media"; case ItemType.Release: return "release"; case ItemType.Rom: @@ -1931,6 +1936,7 @@ namespace SabreTools.Library.Tools ItemType.Blank => "blank", ItemType.Chip => "chip", ItemType.Disk => "disk", + ItemType.Media => "media", ItemType.Release => "release", ItemType.Rom => "rom", ItemType.Sample => "sample", diff --git a/SabreTools/Features/BaseFeature.cs b/SabreTools/Features/BaseFeature.cs index e6621794..e659e693 100644 --- a/SabreTools/Features/BaseFeature.cs +++ b/SabreTools/Features/BaseFeature.cs @@ -66,6 +66,20 @@ namespace SabreTools.Features #region Flag features + internal const string AaruFormatsAsFilesValue = "aaruformats-as-files"; + internal static Feature AaruFormatsAsFilesFlag + { + get + { + return new Feature( + AaruFormatsAsFilesValue, + new List() { "-caf", "--aaruformats-as-files" }, + "Treat AaruFormats as files", + FeatureType.Flag, + longDescription: "Normally, AaruFormats would be processed using their internal hash to compare against the input DATs. This flag forces all AaruFormats to be treated like regular files."); + } + } + internal const string AddBlankFilesValue = "add-blank-files"; internal static Feature AddBlankFilesFlag { @@ -2530,6 +2544,8 @@ Some special strings that can be used: protected TreatAsFiles GetTreatAsFiles(Dictionary features) { TreatAsFiles asFiles = 0x00; + if (GetBoolean(features, AaruFormatsAsFilesValue)) + asFiles |= TreatAsFiles.AaruFormats; if (GetBoolean(features, ArchivesAsFilesValue)) asFiles |= TreatAsFiles.Archives; if (GetBoolean(features, ChdsAsFilesValue)) diff --git a/SabreTools/Features/DatFromDir.cs b/SabreTools/Features/DatFromDir.cs index a3418f07..c52b7be8 100644 --- a/SabreTools/Features/DatFromDir.cs +++ b/SabreTools/Features/DatFromDir.cs @@ -31,7 +31,9 @@ namespace SabreTools.Features AddFeature(SkipSha512Flag); AddFeature(NoAutomaticDateFlag); + AddFeature(AaruFormatsAsFilesFlag); AddFeature(ArchivesAsFilesFlag); + AddFeature(ChdsAsFilesFlag); AddFeature(OutputTypeListInput); this[OutputTypeListInput].AddFeature(DeprecatedFlag); AddFeature(RombaFlag); @@ -43,7 +45,6 @@ namespace SabreTools.Features AddFeature(AddDateFlag); AddFeature(CopyFilesFlag); AddFeature(HeaderStringInput); - AddFeature(ChdsAsFilesFlag); AddFeature(ExtraIniListInput); AddFilteringFeatures(); AddFeature(TempStringInput); diff --git a/SabreTools/Features/Sort.cs b/SabreTools/Features/Sort.cs index 1464c834..56ad0ae1 100644 --- a/SabreTools/Features/Sort.cs +++ b/SabreTools/Features/Sort.cs @@ -29,6 +29,7 @@ namespace SabreTools.Features AddFeature(DeleteFlag); AddFeature(InverseFlag); AddFeature(QuickFlag); + AddFeature(AaruFormatsAsFilesFlag); AddFeature(ChdsAsFilesFlag); AddFeature(AddDateFlag); AddFeature(IndividualFlag); diff --git a/SabreTools/Features/Verify.cs b/SabreTools/Features/Verify.cs index 682a3252..ac3fa0bd 100644 --- a/SabreTools/Features/Verify.cs +++ b/SabreTools/Features/Verify.cs @@ -28,6 +28,7 @@ namespace SabreTools.Features AddFeature(HashOnlyFlag); AddFeature(QuickFlag); AddFeature(HeaderStringInput); + AddFeature(AaruFormatsAsFilesFlag); AddFeature(ChdsAsFilesFlag); AddFeature(IndividualFlag); AddInternalSplitFeatures();