Files
SabreTools/SabreTools.DatFiles/Formats/Hashfile.Writer.cs

622 lines
23 KiB
C#
Raw Normal View History

2023-07-28 21:34:34 -04:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SabreTools.Core;
using SabreTools.DatItems;
using SabreTools.DatItems.Formats;
namespace SabreTools.DatFiles.Formats
{
/// <summary>
/// Represents writing a hashfile such as an SFV, MD5, or SHA-1 file
/// </summary>
internal partial class Hashfile : DatFile
{
/// <inheritdoc/>
protected override ItemType[] GetSupportedTypes()
{
2024-02-28 19:19:50 -05:00
return
[
2023-07-28 21:34:34 -04:00
ItemType.Disk,
ItemType.Media,
ItemType.Rom
2024-02-28 19:19:50 -05:00
];
2023-07-28 21:34:34 -04:00
}
/// <inheritdoc/>
2024-03-05 23:41:00 -05:00
protected override List<string>? GetMissingRequiredFields(DatItem datItem)
2023-07-28 21:34:34 -04:00
{
2024-03-05 23:41:00 -05:00
var missingFields = new List<string>();
2023-07-28 21:34:34 -04:00
// Check item name
2024-02-28 22:54:56 -05:00
if (string.IsNullOrEmpty(datItem.GetName()))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.NameKey);
2023-07-28 21:34:34 -04:00
// Check hash linked to specific Hashfile type
switch (_hash)
{
2023-09-11 10:27:17 -04:00
case Serialization.Hash.CRC:
2023-07-28 21:34:34 -04:00
switch (datItem.ItemType)
{
case ItemType.Rom:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Rom)?.CRC))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.CRCKey);
2023-07-28 21:34:34 -04:00
break;
default:
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.CRCKey);
2023-07-28 21:34:34 -04:00
break;
}
break;
2023-09-11 10:27:17 -04:00
case Serialization.Hash.MD5:
2023-07-28 21:34:34 -04:00
switch (datItem.ItemType)
{
case ItemType.Disk:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Disk)?.MD5))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Disk.MD5Key);
2023-07-28 21:34:34 -04:00
break;
case ItemType.Media:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Media)?.MD5))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Media.MD5Key);
2023-07-28 21:34:34 -04:00
break;
case ItemType.Rom:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Rom)?.MD5))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.MD5Key);
2023-07-28 21:34:34 -04:00
break;
default:
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.MD5Key);
2023-07-28 21:34:34 -04:00
break;
}
break;
2023-09-11 10:27:17 -04:00
case Serialization.Hash.SHA1:
2023-07-28 21:34:34 -04:00
switch (datItem.ItemType)
{
case ItemType.Disk:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Disk)?.SHA1))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Disk.SHA1Key);
2023-07-28 21:34:34 -04:00
break;
case ItemType.Media:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Media)?.SHA1))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Media.SHA1Key);
2023-07-28 21:34:34 -04:00
break;
case ItemType.Rom:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Rom)?.SHA1))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.SHA1Key);
2023-07-28 21:34:34 -04:00
break;
default:
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.SHA1Key);
2023-07-28 21:34:34 -04:00
break;
}
break;
2023-09-11 10:27:17 -04:00
case Serialization.Hash.SHA256:
2023-07-28 21:34:34 -04:00
switch (datItem.ItemType)
{
case ItemType.Media:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Media)?.SHA256))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Media.SHA256Key);
2023-07-28 21:34:34 -04:00
break;
case ItemType.Rom:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Rom)?.SHA256))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.SHA256Key);
2023-07-28 21:34:34 -04:00
break;
default:
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.SHA256Key);
2023-07-28 21:34:34 -04:00
break;
}
break;
2023-09-11 10:27:17 -04:00
case Serialization.Hash.SHA384:
2023-07-28 21:34:34 -04:00
switch (datItem.ItemType)
{
case ItemType.Rom:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Rom)?.SHA384))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.SHA384Key);
2023-07-28 21:34:34 -04:00
break;
default:
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.SHA384Key);
2023-07-28 21:34:34 -04:00
break;
}
break;
2023-09-11 10:27:17 -04:00
case Serialization.Hash.SHA512:
2023-07-28 21:34:34 -04:00
switch (datItem.ItemType)
{
case ItemType.Rom:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Rom)?.SHA512))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.SHA512Key);
2023-07-28 21:34:34 -04:00
break;
default:
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.SHA512Key);
2023-07-28 21:34:34 -04:00
break;
}
break;
2023-09-11 10:27:17 -04:00
case Serialization.Hash.SpamSum:
2023-07-28 21:34:34 -04:00
switch (datItem.ItemType)
{
case ItemType.Media:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Media)?.SpamSum))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Media.SpamSumKey);
2023-07-28 21:34:34 -04:00
break;
case ItemType.Rom:
2023-07-28 22:50:17 -04:00
if (string.IsNullOrEmpty((datItem as Rom)?.SpamSum))
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.SpamSumKey);
2023-07-28 21:34:34 -04:00
break;
default:
2024-03-05 23:41:00 -05:00
missingFields.Add(Models.Metadata.Rom.SpamSumKey);
2023-07-28 21:34:34 -04:00
break;
}
break;
}
return missingFields;
}
/// <inheritdoc/>
public override bool WriteToFile(string outfile, bool ignoreblanks = false, bool throwOnError = false)
{
try
{
logger.User($"Writing to '{outfile}'...");
2023-07-28 22:50:17 -04:00
var hashfile = CreateHashFile(ignoreblanks);
2023-09-11 01:20:21 -04:00
if (!(new Serialization.Files.Hashfile().Serialize(hashfile, outfile, _hash)))
2023-07-28 21:34:34 -04:00
{
logger.Warning($"File '{outfile}' could not be written! See the log for more details.");
return false;
}
}
catch (Exception ex) when (!throwOnError)
{
logger.Error(ex);
return false;
}
2023-07-31 11:33:03 -04:00
logger.User($"'{outfile}' written!{Environment.NewLine}");
2023-07-28 21:34:34 -04:00
return true;
}
2023-07-28 22:58:53 -04:00
#region Converters
2023-07-28 21:34:34 -04:00
/// <summary>
/// Create a Hashfile from the current internal information
/// <summary>
2023-07-28 22:50:17 -04:00
/// <param name="ignoreblanks">True if blank roms should be skipped on output, false otherwise</param>
private Models.Hashfile.Hashfile CreateHashFile(bool ignoreblanks)
2023-07-28 21:34:34 -04:00
{
var hashfile = new Models.Hashfile.Hashfile();
switch (_hash)
{
2023-09-11 10:27:17 -04:00
case Serialization.Hash.CRC:
2023-07-28 22:50:17 -04:00
hashfile.SFV = CreateSFV(ignoreblanks);
2023-07-28 21:34:34 -04:00
break;
2023-09-11 10:27:17 -04:00
case Serialization.Hash.MD5:
2023-07-28 22:50:17 -04:00
hashfile.MD5 = CreateMD5(ignoreblanks);
2023-07-28 21:34:34 -04:00
break;
2023-09-11 10:27:17 -04:00
case Serialization.Hash.SHA1:
2023-07-28 22:50:17 -04:00
hashfile.SHA1 = CreateSHA1(ignoreblanks);
2023-07-28 21:34:34 -04:00
break;
2023-09-11 10:27:17 -04:00
case Serialization.Hash.SHA256:
2023-07-28 22:50:17 -04:00
hashfile.SHA256 = CreateSHA256(ignoreblanks);
2023-07-28 21:34:34 -04:00
break;
2023-09-11 10:27:17 -04:00
case Serialization.Hash.SHA384:
2023-07-28 22:50:17 -04:00
hashfile.SHA384 = CreateSHA384(ignoreblanks);
2023-07-28 21:34:34 -04:00
break;
2023-09-11 10:27:17 -04:00
case Serialization.Hash.SHA512:
2023-07-28 22:50:17 -04:00
hashfile.SHA512 = CreateSHA512(ignoreblanks);
2023-07-28 21:34:34 -04:00
break;
2023-09-11 10:27:17 -04:00
case Serialization.Hash.SpamSum:
2023-07-28 22:50:17 -04:00
hashfile.SpamSum = CreateSpamSum(ignoreblanks);
2023-07-28 21:34:34 -04:00
break;
}
return hashfile;
}
/// <summary>
/// Create an array of SFV
/// <summary>
2023-07-28 22:50:17 -04:00
/// <param name="ignoreblanks">True if blank roms should be skipped on output, false otherwise</param>
private Models.Hashfile.SFV[]? CreateSFV(bool ignoreblanks)
2023-07-28 21:34:34 -04:00
{
// Create a list of hold the SFVs
var sfvs = new List<Models.Hashfile.SFV>();
// Loop through the sorted items and create items for them
foreach (string key in Items.SortedKeys)
{
var items = Items.FilteredItems(key);
if (items == null || !items.Any())
continue;
// Loop through and convert the items to respective lists
for (int index = 0; index < items.Count; index++)
2023-07-28 21:34:34 -04:00
{
// Get the item
var item = items[index];
if (item == null)
continue;
// Check for a "null" item
item = ProcessNullifiedItem(item);
2023-07-28 22:50:17 -04:00
// Skip if we're ignoring the item
if (ShouldIgnore(item, ignoreblanks))
continue;
2023-07-28 21:34:34 -04:00
string name = string.Empty;
if (Header.GameName && item.Machine != null)
2023-07-28 21:34:34 -04:00
name = $"{item.Machine.Name}{Path.DirectorySeparatorChar}";
switch (item)
{
case Rom rom:
sfvs.Add(new Models.Hashfile.SFV
{
File = name + rom.Name,
Hash = rom.CRC,
});
break;
}
}
}
2024-02-28 19:19:50 -05:00
return [.. sfvs];
2023-07-28 21:34:34 -04:00
}
/// <summary>
/// Create an array of MD5
/// <summary>
2023-07-28 22:50:17 -04:00
/// <param name="ignoreblanks">True if blank roms should be skipped on output, false otherwise</param>
private Models.Hashfile.MD5[]? CreateMD5(bool ignoreblanks)
2023-07-28 21:34:34 -04:00
{
// Create a list of hold the MD5s
var md5s = new List<Models.Hashfile.MD5>();
// Loop through the sorted items and create items for them
foreach (string key in Items.SortedKeys)
{
var items = Items.FilteredItems(key);
if (items == null || !items.Any())
continue;
// Loop through and convert the items to respective lists
for (int index = 0; index < items.Count; index++)
2023-07-28 21:34:34 -04:00
{
// Get the item
var item = items[index];
if (item == null)
continue;
// Check for a "null" item
item = ProcessNullifiedItem(item);
2023-07-28 22:50:17 -04:00
// Skip if we're ignoring the item
if (ShouldIgnore(item, ignoreblanks))
continue;
2023-07-28 21:34:34 -04:00
string name = string.Empty;
if (Header.GameName && item.Machine != null)
2023-07-28 21:34:34 -04:00
name = $"{item.Machine.Name}{Path.DirectorySeparatorChar}";
switch (item)
{
case Disk disk:
md5s.Add(new Models.Hashfile.MD5
{
Hash = disk.MD5,
File = name + disk.Name,
});
break;
case Media media:
md5s.Add(new Models.Hashfile.MD5
{
Hash = media.MD5,
File = name + media.Name,
});
break;
case Rom rom:
md5s.Add(new Models.Hashfile.MD5
{
Hash = rom.MD5,
File = name + rom.Name,
});
break;
}
}
}
2024-02-28 19:19:50 -05:00
return [.. md5s];
2023-07-28 21:34:34 -04:00
}
/// <summary>
/// Create an array of SHA1
/// <summary>
2023-07-28 22:50:17 -04:00
/// <param name="ignoreblanks">True if blank roms should be skipped on output, false otherwise</param>
private Models.Hashfile.SHA1[]? CreateSHA1(bool ignoreblanks)
2023-07-28 21:34:34 -04:00
{
// Create a list of hold the SHA1s
var sha1s = new List<Models.Hashfile.SHA1>();
// Loop through the sorted items and create items for them
foreach (string key in Items.SortedKeys)
{
var items = Items.FilteredItems(key);
if (items == null || !items.Any())
continue;
// Loop through and convert the items to respective lists
for (int index = 0; index < items.Count; index++)
2023-07-28 21:34:34 -04:00
{
// Get the item
var item = items[index];
if (item == null)
continue;
// Check for a "null" item
item = ProcessNullifiedItem(item);
2023-07-28 22:50:17 -04:00
// Skip if we're ignoring the item
if (ShouldIgnore(item, ignoreblanks))
continue;
2023-07-28 21:34:34 -04:00
string name = string.Empty;
if (Header.GameName && item.Machine != null)
2023-07-28 21:34:34 -04:00
name = $"{item.Machine.Name}{Path.DirectorySeparatorChar}";
switch (item)
{
case Disk disk:
sha1s.Add(new Models.Hashfile.SHA1
{
Hash = disk.SHA1,
File = name + disk.Name,
});
break;
case Media media:
sha1s.Add(new Models.Hashfile.SHA1
{
Hash = media.SHA1,
File = name + media.Name,
});
break;
case Rom rom:
sha1s.Add(new Models.Hashfile.SHA1
{
Hash = rom.SHA1,
File = name + rom.Name,
});
break;
}
}
}
2024-02-28 19:19:50 -05:00
return [.. sha1s];
2023-07-28 21:34:34 -04:00
}
/// <summary>
/// Create an array of SHA256
/// <summary>
2023-07-28 22:50:17 -04:00
/// <param name="ignoreblanks">True if blank roms should be skipped on output, false otherwise</param>
private Models.Hashfile.SHA256[]? CreateSHA256(bool ignoreblanks)
2023-07-28 21:34:34 -04:00
{
// Create a list of hold the SHA256s
var sha256s = new List<Models.Hashfile.SHA256>();
// Loop through the sorted items and create items for them
foreach (string key in Items.SortedKeys)
{
var items = Items.FilteredItems(key);
if (items == null || !items.Any())
continue;
// Loop through and convert the items to respective lists
for (int index = 0; index < items.Count; index++)
2023-07-28 21:34:34 -04:00
{
// Get the item
var item = items[index];
if (item == null)
continue;
// Check for a "null" item
item = ProcessNullifiedItem(item);
2023-07-28 22:50:17 -04:00
// Skip if we're ignoring the item
if (ShouldIgnore(item, ignoreblanks))
continue;
2023-07-28 21:34:34 -04:00
string name = string.Empty;
if (Header.GameName && item.Machine != null)
2023-07-28 22:50:17 -04:00
name = $"{item.Machine.Name}{Path.DirectorySeparatorChar}";
2023-07-28 21:34:34 -04:00
switch (item)
{
case Media media:
sha256s.Add(new Models.Hashfile.SHA256
{
Hash = media.SHA256,
File = name + media.Name,
});
break;
case Rom rom:
sha256s.Add(new Models.Hashfile.SHA256
{
Hash = rom.SHA256,
File = name + rom.Name,
});
break;
}
}
}
2024-02-28 19:19:50 -05:00
return [.. sha256s];
2023-07-28 21:34:34 -04:00
}
/// <summary>
/// Create an array of SHA384
/// <summary>
2023-07-28 22:50:17 -04:00
/// <param name="ignoreblanks">True if blank roms should be skipped on output, false otherwise</param>
private Models.Hashfile.SHA384[]? CreateSHA384(bool ignoreblanks)
2023-07-28 21:34:34 -04:00
{
// Create a list of hold the SHA384s
var sha384s = new List<Models.Hashfile.SHA384>();
// Loop through the sorted items and create items for them
foreach (string key in Items.SortedKeys)
{
var items = Items.FilteredItems(key);
if (items == null || !items.Any())
continue;
// Loop through and convert the items to respective lists
for (int index = 0; index < items.Count; index++)
2023-07-28 21:34:34 -04:00
{
// Get the item
var item = items[index];
if (item == null)
continue;
// Check for a "null" item
item = ProcessNullifiedItem(item);
2023-07-28 22:50:17 -04:00
// Skip if we're ignoring the item
if (ShouldIgnore(item, ignoreblanks))
continue;
2023-07-28 21:34:34 -04:00
string name = string.Empty;
if (Header.GameName && item.Machine != null)
2023-07-28 22:50:17 -04:00
name = $"{item.Machine.Name}{Path.DirectorySeparatorChar}";
2023-07-28 21:34:34 -04:00
switch (item)
{
case Rom rom:
sha384s.Add(new Models.Hashfile.SHA384
{
Hash = rom.SHA384,
File = name + rom.Name,
});
break;
}
}
}
2024-02-28 19:19:50 -05:00
return [.. sha384s];
2023-07-28 21:34:34 -04:00
}
/// <summary>
/// Create an array of SHA512
/// <summary>
2023-07-28 22:50:17 -04:00
/// <param name="ignoreblanks">True if blank roms should be skipped on output, false otherwise</param>
private Models.Hashfile.SHA512[]? CreateSHA512(bool ignoreblanks)
2023-07-28 21:34:34 -04:00
{
// Create a list of hold the SHA512s
var sha512s = new List<Models.Hashfile.SHA512>();
// Loop through the sorted items and create items for them
foreach (string key in Items.SortedKeys)
{
var items = Items.FilteredItems(key);
if (items == null || !items.Any())
continue;
// Loop through and convert the items to respective lists
for (int index = 0; index < items.Count; index++)
2023-07-28 21:34:34 -04:00
{
// Get the item
var item = items[index];
if (item == null)
continue;
// Check for a "null" item
item = ProcessNullifiedItem(item);
2023-07-28 22:50:17 -04:00
// Skip if we're ignoring the item
if (ShouldIgnore(item, ignoreblanks))
continue;
2023-07-28 21:34:34 -04:00
string name = string.Empty;
if (Header.GameName && item.Machine != null)
2023-07-28 22:50:17 -04:00
name = $"{item.Machine.Name}{Path.DirectorySeparatorChar}";
2023-07-28 21:34:34 -04:00
switch (item)
{
case Rom rom:
sha512s.Add(new Models.Hashfile.SHA512
{
Hash = rom.SHA512,
File = name + rom.Name,
});
break;
}
}
}
2024-02-28 19:19:50 -05:00
return [.. sha512s];
2023-07-28 21:34:34 -04:00
}
/// <summary>
/// Create an array of SpamSum
/// <summary>
2023-07-28 22:50:17 -04:00
/// <param name="ignoreblanks">True if blank roms should be skipped on output, false otherwise</param>
private Models.Hashfile.SpamSum[]? CreateSpamSum(bool ignoreblanks)
2023-07-28 21:34:34 -04:00
{
// Create a list of hold the SpamSums
var spamsums = new List<Models.Hashfile.SpamSum>();
// Loop through the sorted items and create items for them
foreach (string key in Items.SortedKeys)
{
var items = Items.FilteredItems(key);
if (items == null || !items.Any())
continue;
// Loop through and convert the items to respective lists
for (int index = 0; index < items.Count; index++)
2023-07-28 21:34:34 -04:00
{
// Get the item
var item = items[index];
if (item == null)
continue;
// Check for a "null" item
item = ProcessNullifiedItem(item);
2023-07-28 22:50:17 -04:00
// Skip if we're ignoring the item
if (ShouldIgnore(item, ignoreblanks))
continue;
2023-07-28 21:34:34 -04:00
string name = string.Empty;
if (Header.GameName && item.Machine != null)
2023-07-28 22:50:17 -04:00
name = $"{item.Machine.Name}{Path.DirectorySeparatorChar}";
2023-07-28 21:34:34 -04:00
switch (item)
{
case Media media:
spamsums.Add(new Models.Hashfile.SpamSum
{
Hash = media.SpamSum,
File = name + media.Name,
});
break;
case Rom rom:
spamsums.Add(new Models.Hashfile.SpamSum
{
Hash = rom.SpamSum,
File = name + rom.Name,
});
break;
}
}
}
2024-02-28 19:19:50 -05:00
return [.. spamsums];
2023-07-28 21:34:34 -04:00
}
2023-07-28 22:58:53 -04:00
#endregion
2023-07-28 21:34:34 -04:00
}
}