Consolidate statistics into a single place again

This commit is contained in:
Matt Nadareski
2024-03-13 01:22:59 -04:00
parent 5a70802cd8
commit 3f48f5c42c
15 changed files with 519 additions and 884 deletions

View File

@@ -296,7 +296,7 @@ namespace SabreTools.DatFiles
if (statsOnly) if (statsOnly)
{ {
Items.EnsureKey(key); Items.EnsureKey(key);
Items.AddItemStatistics(item); Items.DatStatistics.AddItemStatistics(item);
} }
else else
{ {

View File

@@ -0,0 +1,411 @@
using System.Collections.Generic;
using SabreTools.Core.Tools;
using SabreTools.DatItems;
using SabreTools.DatItems.Formats;
using SabreTools.Hashing;
namespace SabreTools.DatFiles
{
/// <summary>
/// Statistics wrapper for outputting
/// </summary>
public class DatStatistics
{
#region Private instance variables
/// <summary>
/// Lock for statistics calculation
/// </summary>
private readonly object statsLock = new();
#endregion
#region Fields
/// <summary>
/// Overall item count
/// </summary>
public long TotalCount { get; private set; } = 0;
/// <summary>
/// Number of items for each item type
/// </summary>
public Dictionary<ItemType, long> ItemCounts { get; private set; } = [];
/// <summary>
/// Number of machines
/// </summary>
/// <remarks>Special count only used by statistics output</remarks>
public long GameCount { get; set; } = 0;
/// <summary>
/// Total uncompressed size
/// </summary>
public long TotalSize { get; private set; } = 0;
/// <summary>
/// Number of items for each hash type
/// </summary>
public Dictionary<HashType, long> HashCounts { get; private set; } = [];
/// <summary>
/// Number of items for each item status
/// </summary>
public Dictionary<ItemStatus, long> StatusCounts { get; private set; } = [];
/// <summary>
/// Number of items with the remove flag
/// </summary>
public long RemovedCount { get; private set; } = 0;
/// <summary>
/// Name to display on output
/// </summary>
public string? DisplayName { get; set; }
/// <summary>
/// Total machine count to use on output
/// </summary>
public long MachineCount { get; set; } = 0;
/// <summary>
/// Determines if statistics are for a directory or not
/// </summary>
public bool IsDirectory { get; set; } = false;
#endregion
#region Accessors
/// <summary>
/// Add to the statistics given a DatItem
/// </summary>
/// <param name="item">Item to add info from</param>
public void AddItemStatistics(DatItem item)
{
lock (statsLock)
{
// No matter what the item is, we increment the count
TotalCount++;
// Increment removal count
if (item.GetBoolFieldValue(DatItem.RemoveKey) == true)
RemovedCount++;
// Increment the item count for the type
AddItemCount(item.GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsEnumValue<ItemType>());
// Some item types require special processing
switch (item)
{
case Disk disk:
if (disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() != ItemStatus.Nodump)
{
AddHashCount(HashType.MD5, string.IsNullOrEmpty(disk.GetStringFieldValue(Models.Metadata.Disk.MD5Key)) ? 0 : 1);
AddHashCount(HashType.SHA1, string.IsNullOrEmpty(disk.GetStringFieldValue(Models.Metadata.Disk.SHA1Key)) ? 0 : 1);
}
AddStatusCount(ItemStatus.BadDump, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.BadDump ? 1 : 0);
AddStatusCount(ItemStatus.Good, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Good ? 1 : 0);
AddStatusCount(ItemStatus.Nodump, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Nodump ? 1 : 0);
AddStatusCount(ItemStatus.Verified, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Verified ? 1 : 0);
break;
case Media media:
AddHashCount(HashType.MD5, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.MD5Key)) ? 0 : 1);
AddHashCount(HashType.SHA1, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SHA1Key)) ? 0 : 1);
AddHashCount(HashType.SHA256, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SHA256Key)) ? 0 : 1);
AddHashCount(HashType.SpamSum, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SpamSumKey)) ? 0 : 1);
break;
case Rom rom:
if (rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() != ItemStatus.Nodump)
{
TotalSize += rom.GetInt64FieldValue(Models.Metadata.Rom.SizeKey) ?? 0;
AddHashCount(HashType.CRC32, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.CRCKey)) ? 0 : 1);
AddHashCount(HashType.MD5, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.MD5Key)) ? 0 : 1);
AddHashCount(HashType.SHA1, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA1Key)) ? 0 : 1);
AddHashCount(HashType.SHA256, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA256Key)) ? 0 : 1);
AddHashCount(HashType.SHA384, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA384Key)) ? 0 : 1);
AddHashCount(HashType.SHA512, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA512Key)) ? 0 : 1);
AddHashCount(HashType.SpamSum, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SpamSumKey)) ? 0 : 1);
}
AddStatusCount(ItemStatus.BadDump, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.BadDump ? 1 : 0);
AddStatusCount(ItemStatus.Good, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Good ? 1 : 0);
AddStatusCount(ItemStatus.Nodump, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Nodump ? 1 : 0);
AddStatusCount(ItemStatus.Verified, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Verified ? 1 : 0);
break;
}
}
}
/// <summary>
/// Add statistics from another DatStatistics object
/// </summary>
/// <param name="stats">DatStatistics object to add from</param>
public void AddStatistics(DatStatistics stats)
{
TotalCount += stats.TotalCount;
// Loop through and add stats for all items
foreach (var itemCountKvp in stats.ItemCounts)
{
AddItemCount(itemCountKvp.Key, itemCountKvp.Value);
}
GameCount += stats.GameCount;
TotalSize += stats.TotalSize;
// Individual hash counts
foreach (var hashCountKvp in stats.HashCounts)
{
AddHashCount(hashCountKvp.Key, hashCountKvp.Value);
}
// Individual status counts
foreach (var statusCountKvp in stats.StatusCounts)
{
AddStatusCount(statusCountKvp.Key, statusCountKvp.Value);
}
RemovedCount += stats.RemovedCount;
}
/// <summary>
/// Get the item count for a given hash type, defaulting to 0 if it does not exist
/// </summary>
/// <param name="hashType">Hash type to retrieve</param>
/// <returns>The number of items with that hash, if it exists</returns>
public long GetHashCount(HashType hashType)
{
lock (HashCounts)
{
if (!HashCounts.ContainsKey(hashType))
return 0;
return HashCounts[hashType];
}
}
/// <summary>
/// Get the item count for a given item type, defaulting to 0 if it does not exist
/// </summary>
/// <param name="itemType">Item type to retrieve</param>
/// <returns>The number of items of that type, if it exists</returns>
public long GetItemCount(ItemType itemType)
{
lock (ItemCounts)
{
if (!ItemCounts.ContainsKey(itemType))
return 0;
return ItemCounts[itemType];
}
}
/// <summary>
/// Get the item count for a given item status, defaulting to 0 if it does not exist
/// </summary>
/// <param name="itemStatus">Item status to retrieve</param>
/// <returns>The number of items of that type, if it exists</returns>
public long GetStatusCount(ItemStatus itemStatus)
{
lock (StatusCounts)
{
if (!StatusCounts.ContainsKey(itemStatus))
return 0;
return StatusCounts[itemStatus];
}
}
/// <summary>
/// Increment the hash count for a given hash type
/// </summary>
/// <param name="hashType">Hash type to increment</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void AddHashCount(HashType hashType, long interval = 1)
{
lock (HashCounts)
{
if (!HashCounts.ContainsKey(hashType))
HashCounts[hashType] = 0;
HashCounts[hashType] += interval;
if (HashCounts[hashType] < 0)
HashCounts[hashType] = 0;
}
}
/// <summary>
/// Increment the item count for a given item type
/// </summary>
/// <param name="itemType">Item type to increment</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void AddItemCount(ItemType itemType, long interval = 1)
{
lock (ItemCounts)
{
if (!ItemCounts.ContainsKey(itemType))
ItemCounts[itemType] = 0;
ItemCounts[itemType] += interval;
if (ItemCounts[itemType] < 0)
ItemCounts[itemType] = 0;
}
}
/// <summary>
/// Increment the item count for a given item status
/// </summary>
/// <param name="itemStatus">Item type to increment</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void AddStatusCount(ItemStatus itemStatus, long interval = 1)
{
lock (StatusCounts)
{
if (!StatusCounts.ContainsKey(itemStatus))
StatusCounts[itemStatus] = 0;
StatusCounts[itemStatus] += interval;
if (StatusCounts[itemStatus] < 0)
StatusCounts[itemStatus] = 0;
}
}
/// <summary>
/// Remove from the statistics given a DatItem
/// </summary>
/// <param name="item">Item to remove info for</param>
public void RemoveItemStatistics(DatItem item)
{
// If we have a null item, we can't do anything
if (item == null)
return;
lock (statsLock)
{
// No matter what the item is, we decrease the count
TotalCount--;
// Decrement removal count
if (item.GetBoolFieldValue(DatItem.RemoveKey) == true)
RemovedCount--;
// Decrement the item count for the type
RemoveItemCount(item.GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsEnumValue<ItemType>());
// Some item types require special processing
switch (item)
{
case Disk disk:
if (disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() != ItemStatus.Nodump)
{
RemoveHashCount(HashType.MD5, string.IsNullOrEmpty(disk.GetStringFieldValue(Models.Metadata.Disk.MD5Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA1, string.IsNullOrEmpty(disk.GetStringFieldValue(Models.Metadata.Disk.SHA1Key)) ? 0 : 1);
}
RemoveStatusCount(ItemStatus.BadDump, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.BadDump ? 1 : 0);
RemoveStatusCount(ItemStatus.Good, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Good ? 1 : 0);
RemoveStatusCount(ItemStatus.Nodump, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Nodump ? 1 : 0);
RemoveStatusCount(ItemStatus.Verified, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Verified ? 1 : 0);
break;
case Media media:
RemoveHashCount(HashType.MD5, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.MD5Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA1, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SHA1Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA256, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SHA256Key)) ? 0 : 1);
RemoveHashCount(HashType.SpamSum, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SpamSumKey)) ? 0 : 1);
break;
case Rom rom:
if (rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() != ItemStatus.Nodump)
{
TotalSize -= rom.GetInt64FieldValue(Models.Metadata.Rom.SizeKey) ?? 0;
RemoveHashCount(HashType.CRC32, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.CRCKey)) ? 0 : 1);
RemoveHashCount(HashType.MD5, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.MD5Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA1, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA1Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA256, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA256Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA384, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA384Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA512, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA512Key)) ? 0 : 1);
RemoveHashCount(HashType.SpamSum, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SpamSumKey)) ? 0 : 1);
}
RemoveStatusCount(ItemStatus.BadDump, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.BadDump ? 1 : 0);
RemoveStatusCount(ItemStatus.Good, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Good ? 1 : 0);
RemoveStatusCount(ItemStatus.Nodump, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Nodump ? 1 : 0);
RemoveStatusCount(ItemStatus.Verified, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Verified ? 1 : 0);
break;
}
}
}
/// <summary>
/// Reset all statistics
/// </summary>
public void ResetStatistics()
{
TotalCount = 0;
ItemCounts = [];
GameCount = 0;
TotalSize = 0;
HashCounts = [];
StatusCounts = [];
RemovedCount = 0;
}
/// <summary>
/// Decrement the hash count for a given hash type
/// </summary>
/// <param name="hashType">Hash type to increment</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void RemoveHashCount(HashType hashType, long interval = 1)
{
lock (HashCounts)
{
if (!HashCounts.ContainsKey(hashType))
return;
HashCounts[hashType] -= interval;
if (HashCounts[hashType] < 0)
HashCounts[hashType] = 0;
}
}
/// <summary>
/// Decrement the item count for a given item type
/// </summary>
/// <param name="itemType">Item type to decrement</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void RemoveItemCount(ItemType itemType, long interval = 1)
{
lock (ItemCounts)
{
if (!ItemCounts.ContainsKey(itemType))
return;
ItemCounts[itemType] -= interval;
if (ItemCounts[itemType] < 0)
ItemCounts[itemType] = 0;
}
}
/// <summary>
/// Decrement the item count for a given item status
/// </summary>
/// <param name="itemStatus">Item type to decrement</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void RemoveStatusCount(ItemStatus itemStatus, long interval = 1)
{
lock (StatusCounts)
{
if (!StatusCounts.ContainsKey(itemStatus))
return;
StatusCounts[itemStatus] -= interval;
if (StatusCounts[itemStatus] < 0)
StatusCounts[itemStatus] = 0;
}
}
#endregion
}
}

View File

@@ -10,7 +10,6 @@ using System.Threading.Tasks;
using System.Xml.Serialization; using System.Xml.Serialization;
using Newtonsoft.Json; using Newtonsoft.Json;
using SabreTools.Core; using SabreTools.Core;
using SabreTools.Core.Tools;
using SabreTools.DatItems; using SabreTools.DatItems;
using SabreTools.DatItems.Formats; using SabreTools.DatItems.Formats;
using SabreTools.Hashing; using SabreTools.Hashing;
@@ -50,11 +49,6 @@ namespace SabreTools.DatFiles
private readonly Dictionary<string, ConcurrentList<DatItem>?> items; private readonly Dictionary<string, ConcurrentList<DatItem>?> items;
#endif #endif
/// <summary>
/// Lock for statistics calculation
/// </summary>
private readonly object statsLock = new();
/// <summary> /// <summary>
/// Logging object /// Logging object
/// </summary> /// </summary>
@@ -96,47 +90,10 @@ namespace SabreTools.DatFiles
#region Statistics #region Statistics
/// <summary> /// <summary>
/// Overall item count /// DAT statistics
/// </summary> /// </summary>
[JsonIgnore, XmlIgnore] [JsonIgnore, XmlIgnore]
public long TotalCount { get; private set; } = 0; public DatStatistics DatStatistics { get; } = new DatStatistics();
/// <summary>
/// Number of items for each item type
/// </summary>
[JsonIgnore, XmlIgnore]
public Dictionary<ItemType, long> ItemCounts { get; private set; } = [];
/// <summary>
/// Number of machines
/// </summary>
/// <remarks>Special count only used by statistics output</remarks>
[JsonIgnore, XmlIgnore]
public long GameCount { get; set; } = 0;
/// <summary>
/// Total uncompressed size
/// </summary>
[JsonIgnore, XmlIgnore]
public long TotalSize { get; private set; } = 0;
/// <summary>
/// Number of items for each hash type
/// </summary>
[JsonIgnore, XmlIgnore]
public Dictionary<HashType, long> HashCounts { get; private set; } = [];
/// <summary>
/// Number of items for each item status
/// </summary>
[JsonIgnore, XmlIgnore]
public Dictionary<ItemStatus, long> StatusCounts { get; private set; } = [];
/// <summary>
/// Number of items with the remove flag
/// </summary>
[JsonIgnore, XmlIgnore]
public long RemovedCount { get; private set; } = 0;
#endregion #endregion
@@ -193,7 +150,7 @@ namespace SabreTools.DatFiles
items[key]!.Add(value); items[key]!.Add(value);
// Now update the statistics // Now update the statistics
AddItemStatistics(value); DatStatistics.AddItemStatistics(value);
} }
} }
@@ -207,67 +164,6 @@ namespace SabreTools.DatFiles
AddRange(key, value); AddRange(key, value);
} }
/// <summary>
/// Add to the statistics given a DatItem
/// </summary>
/// <param name="item">Item to add info from</param>
public void AddItemStatistics(DatItem item)
{
lock (statsLock)
{
// No matter what the item is, we increment the count
TotalCount++;
// Increment removal count
if (item.GetBoolFieldValue(DatItem.RemoveKey) == true)
RemovedCount++;
// Increment the item count for the type
AddItemCount(item.GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsEnumValue<ItemType>());
// Some item types require special processing
switch (item)
{
case Disk disk:
if (disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() != ItemStatus.Nodump)
{
AddHashCount(HashType.MD5, string.IsNullOrEmpty(disk.GetStringFieldValue(Models.Metadata.Disk.MD5Key)) ? 0 : 1);
AddHashCount(HashType.SHA1, string.IsNullOrEmpty(disk.GetStringFieldValue(Models.Metadata.Disk.SHA1Key)) ? 0 : 1);
}
AddStatusCount(ItemStatus.BadDump, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.BadDump ? 1 : 0);
AddStatusCount(ItemStatus.Good, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Good ? 1 : 0);
AddStatusCount(ItemStatus.Nodump, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Nodump ? 1 : 0);
AddStatusCount(ItemStatus.Verified, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Verified ? 1 : 0);
break;
case Media media:
AddHashCount(HashType.MD5, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.MD5Key)) ? 0 : 1);
AddHashCount(HashType.SHA1, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SHA1Key)) ? 0 : 1);
AddHashCount(HashType.SHA256, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SHA256Key)) ? 0 : 1);
AddHashCount(HashType.SpamSum, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SpamSumKey)) ? 0 : 1);
break;
case Rom rom:
if (rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() != ItemStatus.Nodump)
{
TotalSize += rom.GetInt64FieldValue(Models.Metadata.Rom.SizeKey) ?? 0;
AddHashCount(HashType.CRC32, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.CRCKey)) ? 0 : 1);
AddHashCount(HashType.MD5, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.MD5Key)) ? 0 : 1);
AddHashCount(HashType.SHA1, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA1Key)) ? 0 : 1);
AddHashCount(HashType.SHA256, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA256Key)) ? 0 : 1);
AddHashCount(HashType.SHA384, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA384Key)) ? 0 : 1);
AddHashCount(HashType.SHA512, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA512Key)) ? 0 : 1);
AddHashCount(HashType.SpamSum, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SpamSumKey)) ? 0 : 1);
}
AddStatusCount(ItemStatus.BadDump, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.BadDump ? 1 : 0);
AddStatusCount(ItemStatus.Good, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Good ? 1 : 0);
AddStatusCount(ItemStatus.Nodump, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Nodump ? 1 : 0);
AddStatusCount(ItemStatus.Verified, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Verified ? 1 : 0);
break;
}
}
}
/// <summary> /// <summary>
/// Add a range of values to the file dictionary /// Add a range of values to the file dictionary
/// </summary> /// </summary>
@@ -291,44 +187,11 @@ namespace SabreTools.DatFiles
// Now update the statistics // Now update the statistics
foreach (DatItem item in value) foreach (DatItem item in value)
{ {
AddItemStatistics(item); DatStatistics.AddItemStatistics(item);
} }
} }
} }
/// <summary>
/// Add statistics from another DatStats object
/// </summary>
/// <param name="stats">DatStats object to add from</param>
public void AddStatistics(ItemDictionary stats)
{
TotalCount += stats.Count;
// Loop through and add stats for all items
foreach (var itemCountKvp in stats.ItemCounts)
{
AddItemCount(itemCountKvp.Key, itemCountKvp.Value);
}
GameCount += stats.GameCount;
TotalSize += stats.TotalSize;
// Individual hash counts
foreach (var hashCountKvp in stats.HashCounts)
{
AddHashCount(hashCountKvp.Key, hashCountKvp.Value);
}
// Individual status counts
foreach (var statusCountKvp in stats.StatusCounts)
{
AddStatusCount(statusCountKvp.Key, statusCountKvp.Value);
}
RemovedCount += stats.RemovedCount;
}
/// <summary> /// <summary>
/// Get if the file dictionary contains the key /// Get if the file dictionary contains the key
/// </summary> /// </summary>
@@ -421,7 +284,7 @@ namespace SabreTools.DatFiles
// Remove the statistics first // Remove the statistics first
foreach (DatItem item in items[key]!) foreach (DatItem item in items[key]!)
{ {
RemoveItemStatistics(item); DatStatistics.RemoveItemStatistics(item);
} }
// Remove the key from the dictionary // Remove the key from the dictionary
@@ -448,7 +311,7 @@ namespace SabreTools.DatFiles
return false; return false;
// Remove the statistics first // Remove the statistics first
RemoveItemStatistics(value); DatStatistics.RemoveItemStatistics(value);
return items[key]!.Remove(value); return items[key]!.Remove(value);
} }
@@ -467,7 +330,7 @@ namespace SabreTools.DatFiles
// Remove the statistics first // Remove the statistics first
foreach (DatItem item in items[key]!) foreach (DatItem item in items[key]!)
{ {
RemoveItemStatistics(item); DatStatistics.RemoveItemStatistics(item);
} }
// Remove the key from the dictionary // Remove the key from the dictionary
@@ -484,227 +347,6 @@ namespace SabreTools.DatFiles
bucketedBy = newBucket; bucketedBy = newBucket;
} }
/// <summary>
/// Remove from the statistics given a DatItem
/// </summary>
/// <param name="item">Item to remove info for</param>
public void RemoveItemStatistics(DatItem item)
{
// If we have a null item, we can't do anything
if (item == null)
return;
lock (statsLock)
{
// No matter what the item is, we decrease the count
TotalCount--;
// Decrement removal count
if (item.GetBoolFieldValue(DatItem.RemoveKey) == true)
RemovedCount--;
// Decrement the item count for the type
RemoveItemCount(item.GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsEnumValue<ItemType>());
// Some item types require special processing
switch (item)
{
case Disk disk:
if (disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() != ItemStatus.Nodump)
{
RemoveHashCount(HashType.MD5, string.IsNullOrEmpty(disk.GetStringFieldValue(Models.Metadata.Disk.MD5Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA1, string.IsNullOrEmpty(disk.GetStringFieldValue(Models.Metadata.Disk.SHA1Key)) ? 0 : 1);
}
RemoveStatusCount(ItemStatus.BadDump, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.BadDump ? 1 : 0);
RemoveStatusCount(ItemStatus.Good, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Good ? 1 : 0);
RemoveStatusCount(ItemStatus.Nodump, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Nodump ? 1 : 0);
RemoveStatusCount(ItemStatus.Verified, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Verified ? 1 : 0);
break;
case Media media:
RemoveHashCount(HashType.MD5, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.MD5Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA1, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SHA1Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA256, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SHA256Key)) ? 0 : 1);
RemoveHashCount(HashType.SpamSum, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SpamSumKey)) ? 0 : 1);
break;
case Rom rom:
if (rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() != ItemStatus.Nodump)
{
TotalSize -= rom.GetInt64FieldValue(Models.Metadata.Rom.SizeKey) ?? 0;
RemoveHashCount(HashType.CRC32, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.CRCKey)) ? 0 : 1);
RemoveHashCount(HashType.MD5, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.MD5Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA1, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA1Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA256, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA256Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA384, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA384Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA512, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA512Key)) ? 0 : 1);
RemoveHashCount(HashType.SpamSum, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SpamSumKey)) ? 0 : 1);
}
RemoveStatusCount(ItemStatus.BadDump, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.BadDump ? 1 : 0);
RemoveStatusCount(ItemStatus.Good, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Good ? 1 : 0);
RemoveStatusCount(ItemStatus.Nodump, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Nodump ? 1 : 0);
RemoveStatusCount(ItemStatus.Verified, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Verified ? 1 : 0);
break;
}
}
}
/// <summary>
/// Get the item count for a given hash type, defaulting to 0 if it does not exist
/// </summary>
/// <param name="hashType">Hash type to retrieve</param>
/// <returns>The number of items with that hash, if it exists</returns>
public long GetHashCount(HashType hashType)
{
lock (HashCounts)
{
if (!HashCounts.ContainsKey(hashType))
return 0;
return HashCounts[hashType];
}
}
/// <summary>
/// Get the item count for a given item type, defaulting to 0 if it does not exist
/// </summary>
/// <param name="itemType">Item type to retrieve</param>
/// <returns>The number of items of that type, if it exists</returns>
public long GetItemCount(ItemType itemType)
{
lock (ItemCounts)
{
if (!ItemCounts.ContainsKey(itemType))
return 0;
return ItemCounts[itemType];
}
}
/// <summary>
/// Get the item count for a given item status, defaulting to 0 if it does not exist
/// </summary>
/// <param name="itemStatus">Item status to retrieve</param>
/// <returns>The number of items of that type, if it exists</returns>
public long GetStatusCount(ItemStatus itemStatus)
{
lock (StatusCounts)
{
if (!StatusCounts.ContainsKey(itemStatus))
return 0;
return StatusCounts[itemStatus];
}
}
/// <summary>
/// Increment the hash count for a given hash type
/// </summary>
/// <param name="hashType">Hash type to increment</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void AddHashCount(HashType hashType, long interval = 1)
{
lock (HashCounts)
{
if (!HashCounts.ContainsKey(hashType))
HashCounts[hashType] = 0;
HashCounts[hashType] += interval;
if (HashCounts[hashType] < 0)
HashCounts[hashType] = 0;
}
}
/// <summary>
/// Decrement the hash count for a given hash type
/// </summary>
/// <param name="hashType">Hash type to increment</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void RemoveHashCount(HashType hashType, long interval = 1)
{
lock (HashCounts)
{
if (!HashCounts.ContainsKey(hashType))
return;
HashCounts[hashType] -= interval;
if (HashCounts[hashType] < 0)
HashCounts[hashType] = 0;
}
}
/// <summary>
/// Increment the item count for a given item type
/// </summary>
/// <param name="itemType">Item type to increment</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void AddItemCount(ItemType itemType, long interval = 1)
{
lock (ItemCounts)
{
if (!ItemCounts.ContainsKey(itemType))
ItemCounts[itemType] = 0;
ItemCounts[itemType] += interval;
if (ItemCounts[itemType] < 0)
ItemCounts[itemType] = 0;
}
}
/// <summary>
/// Decrement the item count for a given item type
/// </summary>
/// <param name="itemType">Item type to decrement</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void RemoveItemCount(ItemType itemType, long interval = 1)
{
lock (ItemCounts)
{
if (!ItemCounts.ContainsKey(itemType))
return;
ItemCounts[itemType] -= interval;
if (ItemCounts[itemType] < 0)
ItemCounts[itemType] = 0;
}
}
/// <summary>
/// Increment the item count for a given item status
/// </summary>
/// <param name="itemStatus">Item type to increment</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void AddStatusCount(ItemStatus itemStatus, long interval = 1)
{
lock (StatusCounts)
{
if (!StatusCounts.ContainsKey(itemStatus))
StatusCounts[itemStatus] = 0;
StatusCounts[itemStatus] += interval;
if (StatusCounts[itemStatus] < 0)
StatusCounts[itemStatus] = 0;
}
}
/// <summary>
/// Decrement the item count for a given item status
/// </summary>
/// <param name="itemStatus">Item type to decrement</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void RemoveStatusCount(ItemStatus itemStatus, long interval = 1)
{
lock (StatusCounts)
{
if (!StatusCounts.ContainsKey(itemStatus))
return;
StatusCounts[itemStatus] -= interval;
if (StatusCounts[itemStatus] < 0)
StatusCounts[itemStatus] = 0;
}
}
#endregion #endregion
#region Constructors #region Constructors
@@ -925,7 +567,7 @@ namespace SabreTools.DatFiles
ConcurrentList<DatItem> output = []; ConcurrentList<DatItem> output = [];
// Check for an empty rom list first // Check for an empty rom list first
if (TotalCount == 0) if (DatStatistics.TotalCount == 0)
return output; return output;
// We want to get the proper key for the DatItem // We want to get the proper key for the DatItem
@@ -975,7 +617,7 @@ namespace SabreTools.DatFiles
public bool HasDuplicates(DatItem datItem, bool sorted = false) public bool HasDuplicates(DatItem datItem, bool sorted = false)
{ {
// Check for an empty rom list first // Check for an empty rom list first
if (TotalCount == 0) if (DatStatistics.TotalCount == 0)
return false; return false;
// We want to get the proper key for the DatItem // We want to get the proper key for the DatItem
@@ -996,7 +638,7 @@ namespace SabreTools.DatFiles
public void RecalculateStats() public void RecalculateStats()
{ {
// Wipe out any stats already there // Wipe out any stats already there
ResetStatistics(); DatStatistics.ResetStatistics();
// If we have a blank Dat in any way, return // If we have a blank Dat in any way, return
if (items == null) if (items == null)
@@ -1011,54 +653,40 @@ namespace SabreTools.DatFiles
foreach (DatItem item in datItems) foreach (DatItem item in datItems)
{ {
AddItemStatistics(item); DatStatistics.AddItemStatistics(item);
} }
} }
} }
/// <summary>
/// Reset all statistics
/// </summary>
public void ResetStatistics()
{
TotalCount = 0;
ItemCounts = [];
GameCount = 0;
TotalSize = 0;
HashCounts = [];
StatusCounts = [];
RemovedCount = 0;
}
/// <summary> /// <summary>
/// Get the highest-order Field value that represents the statistics /// Get the highest-order Field value that represents the statistics
/// </summary> /// </summary>
private ItemKey GetBestAvailable() private ItemKey GetBestAvailable()
{ {
// Get the required counts // Get the required counts
long diskCount = GetItemCount(ItemType.Disk); long diskCount = DatStatistics.GetItemCount(ItemType.Disk);
long mediaCount = GetItemCount(ItemType.Media); long mediaCount = DatStatistics.GetItemCount(ItemType.Media);
long romCount = GetItemCount(ItemType.Rom); long romCount = DatStatistics.GetItemCount(ItemType.Rom);
long nodumpCount = GetStatusCount(ItemStatus.Nodump); long nodumpCount = DatStatistics.GetStatusCount(ItemStatus.Nodump);
// If all items are supposed to have a SHA-512, we bucket by that // If all items are supposed to have a SHA-512, we bucket by that
if (diskCount + mediaCount + romCount - nodumpCount == GetHashCount(HashType.SHA512)) if (diskCount + mediaCount + romCount - nodumpCount == DatStatistics.GetHashCount(HashType.SHA512))
return ItemKey.SHA512; return ItemKey.SHA512;
// If all items are supposed to have a SHA-384, we bucket by that // If all items are supposed to have a SHA-384, we bucket by that
else if (diskCount + mediaCount + romCount - nodumpCount == GetHashCount(HashType.SHA384)) else if (diskCount + mediaCount + romCount - nodumpCount == DatStatistics.GetHashCount(HashType.SHA384))
return ItemKey.SHA384; return ItemKey.SHA384;
// If all items are supposed to have a SHA-256, we bucket by that // If all items are supposed to have a SHA-256, we bucket by that
else if (diskCount + mediaCount + romCount - nodumpCount == GetHashCount(HashType.SHA256)) else if (diskCount + mediaCount + romCount - nodumpCount == DatStatistics.GetHashCount(HashType.SHA256))
return ItemKey.SHA256; return ItemKey.SHA256;
// If all items are supposed to have a SHA-1, we bucket by that // If all items are supposed to have a SHA-1, we bucket by that
else if (diskCount + mediaCount + romCount - nodumpCount == GetHashCount(HashType.SHA1)) else if (diskCount + mediaCount + romCount - nodumpCount == DatStatistics.GetHashCount(HashType.SHA1))
return ItemKey.SHA1; return ItemKey.SHA1;
// If all items are supposed to have a MD5, we bucket by that // If all items are supposed to have a MD5, we bucket by that
else if (diskCount + mediaCount + romCount - nodumpCount == GetHashCount(HashType.MD5)) else if (diskCount + mediaCount + romCount - nodumpCount == DatStatistics.GetHashCount(HashType.MD5))
return ItemKey.MD5; return ItemKey.MD5;
// Otherwise, we bucket by CRC // Otherwise, we bucket by CRC

View File

@@ -10,7 +10,6 @@ using System.Threading.Tasks;
using System.Xml.Serialization; using System.Xml.Serialization;
using Newtonsoft.Json; using Newtonsoft.Json;
using SabreTools.Core; using SabreTools.Core;
using SabreTools.Core.Tools;
using SabreTools.DatItems; using SabreTools.DatItems;
using SabreTools.DatItems.Formats; using SabreTools.DatItems.Formats;
using SabreTools.Hashing; using SabreTools.Hashing;
@@ -55,11 +54,6 @@ namespace SabreTools.DatFiles
private readonly Dictionary<string, Machine> machines; private readonly Dictionary<string, Machine> machines;
#endif #endif
/// <summary>
/// Lock for statistics calculation
/// </summary>
private readonly object statsLock = new();
/// <summary> /// <summary>
/// Logging object /// Logging object
/// </summary> /// </summary>
@@ -101,47 +95,10 @@ namespace SabreTools.DatFiles
#region Statistics #region Statistics
/// <summary> /// <summary>
/// Overall item count /// DAT statistics
/// </summary> /// </summary>
[JsonIgnore, XmlIgnore] [JsonIgnore, XmlIgnore]
public long TotalCount { get; private set; } = 0; public DatStatistics DatStatistics { get; } = new DatStatistics();
/// <summary>
/// Number of items for each item type
/// </summary>
[JsonIgnore, XmlIgnore]
public Dictionary<ItemType, long> ItemCounts { get; private set; } = [];
/// <summary>
/// Number of machines
/// </summary>
/// <remarks>Special count only used by statistics output</remarks>
[JsonIgnore, XmlIgnore]
public long GameCount { get; set; } = 0;
/// <summary>
/// Total uncompressed size
/// </summary>
[JsonIgnore, XmlIgnore]
public long TotalSize { get; private set; } = 0;
/// <summary>
/// Number of items for each hash type
/// </summary>
[JsonIgnore, XmlIgnore]
public Dictionary<HashType, long> HashCounts { get; private set; } = [];
/// <summary>
/// Number of items for each item status
/// </summary>
[JsonIgnore, XmlIgnore]
public Dictionary<ItemStatus, long> StatusCounts { get; private set; } = [];
/// <summary>
/// Number of items with the remove flag
/// </summary>
[JsonIgnore, XmlIgnore]
public long RemovedCount { get; private set; } = 0;
#endregion #endregion
@@ -198,7 +155,7 @@ namespace SabreTools.DatFiles
items[key]!.Add(value); items[key]!.Add(value);
// Now update the statistics // Now update the statistics
AddItemStatistics(value); DatStatistics.AddItemStatistics(value);
} }
} }
@@ -212,67 +169,6 @@ namespace SabreTools.DatFiles
AddRange(key, value); AddRange(key, value);
} }
/// <summary>
/// Add to the statistics given a DatItem
/// </summary>
/// <param name="item">Item to add info from</param>
public void AddItemStatistics(DatItem item)
{
lock (statsLock)
{
// No matter what the item is, we increment the count
TotalCount++;
// Increment removal count
if (item.GetBoolFieldValue(DatItem.RemoveKey) == true)
RemovedCount++;
// Increment the item count for the type
AddItemCount(item.GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsEnumValue<ItemType>());
// Some item types require special processing
switch (item)
{
case Disk disk:
if (disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() != ItemStatus.Nodump)
{
AddHashCount(HashType.MD5, string.IsNullOrEmpty(disk.GetStringFieldValue(Models.Metadata.Disk.MD5Key)) ? 0 : 1);
AddHashCount(HashType.SHA1, string.IsNullOrEmpty(disk.GetStringFieldValue(Models.Metadata.Disk.SHA1Key)) ? 0 : 1);
}
AddStatusCount(ItemStatus.BadDump, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.BadDump ? 1 : 0);
AddStatusCount(ItemStatus.Good, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Good ? 1 : 0);
AddStatusCount(ItemStatus.Nodump, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Nodump ? 1 : 0);
AddStatusCount(ItemStatus.Verified, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Verified ? 1 : 0);
break;
case Media media:
AddHashCount(HashType.MD5, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.MD5Key)) ? 0 : 1);
AddHashCount(HashType.SHA1, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SHA1Key)) ? 0 : 1);
AddHashCount(HashType.SHA256, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SHA256Key)) ? 0 : 1);
AddHashCount(HashType.SpamSum, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SpamSumKey)) ? 0 : 1);
break;
case Rom rom:
if (rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() != ItemStatus.Nodump)
{
TotalSize += rom.GetInt64FieldValue(Models.Metadata.Rom.SizeKey) ?? 0;
AddHashCount(HashType.CRC32, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.CRCKey)) ? 0 : 1);
AddHashCount(HashType.MD5, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.MD5Key)) ? 0 : 1);
AddHashCount(HashType.SHA1, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA1Key)) ? 0 : 1);
AddHashCount(HashType.SHA256, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA256Key)) ? 0 : 1);
AddHashCount(HashType.SHA384, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA384Key)) ? 0 : 1);
AddHashCount(HashType.SHA512, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA512Key)) ? 0 : 1);
AddHashCount(HashType.SpamSum, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SpamSumKey)) ? 0 : 1);
}
AddStatusCount(ItemStatus.BadDump, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.BadDump ? 1 : 0);
AddStatusCount(ItemStatus.Good, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Good ? 1 : 0);
AddStatusCount(ItemStatus.Nodump, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Nodump ? 1 : 0);
AddStatusCount(ItemStatus.Verified, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Verified ? 1 : 0);
break;
}
}
}
/// <summary> /// <summary>
/// Add a range of values to the file dictionary /// Add a range of values to the file dictionary
/// </summary> /// </summary>
@@ -296,44 +192,11 @@ namespace SabreTools.DatFiles
// Now update the statistics // Now update the statistics
foreach (DatItem item in value) foreach (DatItem item in value)
{ {
AddItemStatistics(item); DatStatistics.AddItemStatistics(item);
} }
} }
} }
/// <summary>
/// Add statistics from another DatStats object
/// </summary>
/// <param name="stats">DatStats object to add from</param>
public void AddStatistics(ItemDictionary stats)
{
TotalCount += stats.Count;
// Loop through and add stats for all items
foreach (var itemCountKvp in stats.ItemCounts)
{
AddItemCount(itemCountKvp.Key, itemCountKvp.Value);
}
GameCount += stats.GameCount;
TotalSize += stats.TotalSize;
// Individual hash counts
foreach (var hashCountKvp in stats.HashCounts)
{
AddHashCount(hashCountKvp.Key, hashCountKvp.Value);
}
// Individual status counts
foreach (var statusCountKvp in stats.StatusCounts)
{
AddStatusCount(statusCountKvp.Key, statusCountKvp.Value);
}
RemovedCount += stats.RemovedCount;
}
/// <summary> /// <summary>
/// Get if the file dictionary contains the key /// Get if the file dictionary contains the key
/// </summary> /// </summary>
@@ -426,7 +289,7 @@ namespace SabreTools.DatFiles
// Remove the statistics first // Remove the statistics first
foreach (DatItem item in items[key]!) foreach (DatItem item in items[key]!)
{ {
RemoveItemStatistics(item); DatStatistics.RemoveItemStatistics(item);
} }
// Remove the key from the dictionary // Remove the key from the dictionary
@@ -453,7 +316,7 @@ namespace SabreTools.DatFiles
return false; return false;
// Remove the statistics first // Remove the statistics first
RemoveItemStatistics(value); DatStatistics.RemoveItemStatistics(value);
return items[key]!.Remove(value); return items[key]!.Remove(value);
} }
@@ -472,7 +335,7 @@ namespace SabreTools.DatFiles
// Remove the statistics first // Remove the statistics first
foreach (DatItem item in items[key]!) foreach (DatItem item in items[key]!)
{ {
RemoveItemStatistics(item); DatStatistics.RemoveItemStatistics(item);
} }
// Remove the key from the dictionary // Remove the key from the dictionary
@@ -489,227 +352,6 @@ namespace SabreTools.DatFiles
bucketedBy = newBucket; bucketedBy = newBucket;
} }
/// <summary>
/// Remove from the statistics given a DatItem
/// </summary>
/// <param name="item">Item to remove info for</param>
public void RemoveItemStatistics(DatItem item)
{
// If we have a null item, we can't do anything
if (item == null)
return;
lock (statsLock)
{
// No matter what the item is, we decrease the count
TotalCount--;
// Decrement removal count
if (item.GetBoolFieldValue(DatItem.RemoveKey) == true)
RemovedCount--;
// Decrement the item count for the type
RemoveItemCount(item.GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsEnumValue<ItemType>());
// Some item types require special processing
switch (item)
{
case Disk disk:
if (disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() != ItemStatus.Nodump)
{
RemoveHashCount(HashType.MD5, string.IsNullOrEmpty(disk.GetStringFieldValue(Models.Metadata.Disk.MD5Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA1, string.IsNullOrEmpty(disk.GetStringFieldValue(Models.Metadata.Disk.SHA1Key)) ? 0 : 1);
}
RemoveStatusCount(ItemStatus.BadDump, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.BadDump ? 1 : 0);
RemoveStatusCount(ItemStatus.Good, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Good ? 1 : 0);
RemoveStatusCount(ItemStatus.Nodump, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Nodump ? 1 : 0);
RemoveStatusCount(ItemStatus.Verified, disk.GetStringFieldValue(Models.Metadata.Disk.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Verified ? 1 : 0);
break;
case Media media:
RemoveHashCount(HashType.MD5, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.MD5Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA1, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SHA1Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA256, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SHA256Key)) ? 0 : 1);
RemoveHashCount(HashType.SpamSum, string.IsNullOrEmpty(media.GetStringFieldValue(Models.Metadata.Media.SpamSumKey)) ? 0 : 1);
break;
case Rom rom:
if (rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() != ItemStatus.Nodump)
{
TotalSize -= rom.GetInt64FieldValue(Models.Metadata.Rom.SizeKey) ?? 0;
RemoveHashCount(HashType.CRC32, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.CRCKey)) ? 0 : 1);
RemoveHashCount(HashType.MD5, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.MD5Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA1, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA1Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA256, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA256Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA384, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA384Key)) ? 0 : 1);
RemoveHashCount(HashType.SHA512, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SHA512Key)) ? 0 : 1);
RemoveHashCount(HashType.SpamSum, string.IsNullOrEmpty(rom.GetStringFieldValue(Models.Metadata.Rom.SpamSumKey)) ? 0 : 1);
}
RemoveStatusCount(ItemStatus.BadDump, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.BadDump ? 1 : 0);
RemoveStatusCount(ItemStatus.Good, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Good ? 1 : 0);
RemoveStatusCount(ItemStatus.Nodump, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Nodump ? 1 : 0);
RemoveStatusCount(ItemStatus.Verified, rom.GetStringFieldValue(Models.Metadata.Rom.StatusKey).AsEnumValue<ItemStatus>() == ItemStatus.Verified ? 1 : 0);
break;
}
}
}
/// <summary>
/// Get the item count for a given hash type, defaulting to 0 if it does not exist
/// </summary>
/// <param name="hashType">Hash type to retrieve</param>
/// <returns>The number of items with that hash, if it exists</returns>
public long GetHashCount(HashType hashType)
{
lock (HashCounts)
{
if (!HashCounts.ContainsKey(hashType))
return 0;
return HashCounts[hashType];
}
}
/// <summary>
/// Get the item count for a given item type, defaulting to 0 if it does not exist
/// </summary>
/// <param name="itemType">Item type to retrieve</param>
/// <returns>The number of items of that type, if it exists</returns>
public long GetItemCount(ItemType itemType)
{
lock (ItemCounts)
{
if (!ItemCounts.ContainsKey(itemType))
return 0;
return ItemCounts[itemType];
}
}
/// <summary>
/// Get the item count for a given item status, defaulting to 0 if it does not exist
/// </summary>
/// <param name="itemStatus">Item status to retrieve</param>
/// <returns>The number of items of that type, if it exists</returns>
public long GetStatusCount(ItemStatus itemStatus)
{
lock (StatusCounts)
{
if (!StatusCounts.ContainsKey(itemStatus))
return 0;
return StatusCounts[itemStatus];
}
}
/// <summary>
/// Increment the hash count for a given hash type
/// </summary>
/// <param name="hashType">Hash type to increment</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void AddHashCount(HashType hashType, long interval = 1)
{
lock (HashCounts)
{
if (!HashCounts.ContainsKey(hashType))
HashCounts[hashType] = 0;
HashCounts[hashType] += interval;
if (HashCounts[hashType] < 0)
HashCounts[hashType] = 0;
}
}
/// <summary>
/// Decrement the hash count for a given hash type
/// </summary>
/// <param name="hashType">Hash type to increment</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void RemoveHashCount(HashType hashType, long interval = 1)
{
lock (HashCounts)
{
if (!HashCounts.ContainsKey(hashType))
return;
HashCounts[hashType] -= interval;
if (HashCounts[hashType] < 0)
HashCounts[hashType] = 0;
}
}
/// <summary>
/// Increment the item count for a given item type
/// </summary>
/// <param name="itemType">Item type to increment</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void AddItemCount(ItemType itemType, long interval = 1)
{
lock (ItemCounts)
{
if (!ItemCounts.ContainsKey(itemType))
ItemCounts[itemType] = 0;
ItemCounts[itemType] += interval;
if (ItemCounts[itemType] < 0)
ItemCounts[itemType] = 0;
}
}
/// <summary>
/// Decrement the item count for a given item type
/// </summary>
/// <param name="itemType">Item type to decrement</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void RemoveItemCount(ItemType itemType, long interval = 1)
{
lock (ItemCounts)
{
if (!ItemCounts.ContainsKey(itemType))
return;
ItemCounts[itemType] -= interval;
if (ItemCounts[itemType] < 0)
ItemCounts[itemType] = 0;
}
}
/// <summary>
/// Increment the item count for a given item status
/// </summary>
/// <param name="itemStatus">Item type to increment</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void AddStatusCount(ItemStatus itemStatus, long interval = 1)
{
lock (StatusCounts)
{
if (!StatusCounts.ContainsKey(itemStatus))
StatusCounts[itemStatus] = 0;
StatusCounts[itemStatus] += interval;
if (StatusCounts[itemStatus] < 0)
StatusCounts[itemStatus] = 0;
}
}
/// <summary>
/// Decrement the item count for a given item status
/// </summary>
/// <param name="itemStatus">Item type to decrement</param>
/// <param name="interval">Amount to increment by, defaults to 1</param>
private void RemoveStatusCount(ItemStatus itemStatus, long interval = 1)
{
lock (StatusCounts)
{
if (!StatusCounts.ContainsKey(itemStatus))
return;
StatusCounts[itemStatus] -= interval;
if (StatusCounts[itemStatus] < 0)
StatusCounts[itemStatus] = 0;
}
}
#endregion #endregion
#region Constructors #region Constructors
@@ -932,7 +574,7 @@ namespace SabreTools.DatFiles
ConcurrentList<DatItem> output = []; ConcurrentList<DatItem> output = [];
// Check for an empty rom list first // Check for an empty rom list first
if (TotalCount == 0) if (DatStatistics.TotalCount == 0)
return output; return output;
// We want to get the proper key for the DatItem // We want to get the proper key for the DatItem
@@ -982,7 +624,7 @@ namespace SabreTools.DatFiles
public bool HasDuplicates(DatItem datItem, bool sorted = false) public bool HasDuplicates(DatItem datItem, bool sorted = false)
{ {
// Check for an empty rom list first // Check for an empty rom list first
if (TotalCount == 0) if (DatStatistics.TotalCount == 0)
return false; return false;
// We want to get the proper key for the DatItem // We want to get the proper key for the DatItem
@@ -1003,7 +645,7 @@ namespace SabreTools.DatFiles
public void RecalculateStats() public void RecalculateStats()
{ {
// Wipe out any stats already there // Wipe out any stats already there
ResetStatistics(); DatStatistics.ResetStatistics();
// If we have a blank Dat in any way, return // If we have a blank Dat in any way, return
if (items == null) if (items == null)
@@ -1018,54 +660,40 @@ namespace SabreTools.DatFiles
foreach (DatItem item in datItems) foreach (DatItem item in datItems)
{ {
AddItemStatistics(item); DatStatistics.AddItemStatistics(item);
} }
} }
} }
/// <summary>
/// Reset all statistics
/// </summary>
public void ResetStatistics()
{
TotalCount = 0;
ItemCounts = [];
GameCount = 0;
TotalSize = 0;
HashCounts = [];
StatusCounts = [];
RemovedCount = 0;
}
/// <summary> /// <summary>
/// Get the highest-order Field value that represents the statistics /// Get the highest-order Field value that represents the statistics
/// </summary> /// </summary>
private ItemKey GetBestAvailable() private ItemKey GetBestAvailable()
{ {
// Get the required counts // Get the required counts
long diskCount = GetItemCount(ItemType.Disk); long diskCount = DatStatistics.GetItemCount(ItemType.Disk);
long mediaCount = GetItemCount(ItemType.Media); long mediaCount = DatStatistics.GetItemCount(ItemType.Media);
long romCount = GetItemCount(ItemType.Rom); long romCount = DatStatistics.GetItemCount(ItemType.Rom);
long nodumpCount = GetStatusCount(ItemStatus.Nodump); long nodumpCount = DatStatistics.GetStatusCount(ItemStatus.Nodump);
// If all items are supposed to have a SHA-512, we bucket by that // If all items are supposed to have a SHA-512, we bucket by that
if (diskCount + mediaCount + romCount - nodumpCount == GetHashCount(HashType.SHA512)) if (diskCount + mediaCount + romCount - nodumpCount == DatStatistics.GetHashCount(HashType.SHA512))
return ItemKey.SHA512; return ItemKey.SHA512;
// If all items are supposed to have a SHA-384, we bucket by that // If all items are supposed to have a SHA-384, we bucket by that
else if (diskCount + mediaCount + romCount - nodumpCount == GetHashCount(HashType.SHA384)) else if (diskCount + mediaCount + romCount - nodumpCount == DatStatistics.GetHashCount(HashType.SHA384))
return ItemKey.SHA384; return ItemKey.SHA384;
// If all items are supposed to have a SHA-256, we bucket by that // If all items are supposed to have a SHA-256, we bucket by that
else if (diskCount + mediaCount + romCount - nodumpCount == GetHashCount(HashType.SHA256)) else if (diskCount + mediaCount + romCount - nodumpCount == DatStatistics.GetHashCount(HashType.SHA256))
return ItemKey.SHA256; return ItemKey.SHA256;
// If all items are supposed to have a SHA-1, we bucket by that // If all items are supposed to have a SHA-1, we bucket by that
else if (diskCount + mediaCount + romCount - nodumpCount == GetHashCount(HashType.SHA1)) else if (diskCount + mediaCount + romCount - nodumpCount == DatStatistics.GetHashCount(HashType.SHA1))
return ItemKey.SHA1; return ItemKey.SHA1;
// If all items are supposed to have a MD5, we bucket by that // If all items are supposed to have a MD5, we bucket by that
else if (diskCount + mediaCount + romCount - nodumpCount == GetHashCount(HashType.MD5)) else if (diskCount + mediaCount + romCount - nodumpCount == DatStatistics.GetHashCount(HashType.MD5))
return ItemKey.MD5; return ItemKey.MD5;
// Otherwise, we bucket by CRC // Otherwise, we bucket by CRC

View File

@@ -55,7 +55,7 @@ namespace SabreTools.DatTools
#region Perform setup #region Perform setup
// If the DAT is not populated and inverse is not set, inform the user and quit // If the DAT is not populated and inverse is not set, inform the user and quit
if (datFile.Items.TotalCount == 0 && !inverse) if (datFile.Items.DatStatistics.TotalCount == 0 && !inverse)
{ {
logger.User("No entries were found to rebuild, exiting..."); logger.User("No entries were found to rebuild, exiting...");
return false; return false;
@@ -205,7 +205,7 @@ namespace SabreTools.DatTools
#region Perform setup #region Perform setup
// If the DAT is not populated and inverse is not set, inform the user and quit // If the DAT is not populated and inverse is not set, inform the user and quit
if (datFile.Items.TotalCount == 0 && !inverse) if (datFile.Items.DatStatistics.TotalCount == 0 && !inverse)
{ {
logger.User("No entries were found to rebuild, exiting..."); logger.User("No entries were found to rebuild, exiting...");
return false; return false;

View File

@@ -42,7 +42,7 @@ namespace SabreTools.DatTools
public static (DatFile? extADat, DatFile? extBDat) SplitByExtension(DatFile datFile, List<string> extA, List<string> extB) public static (DatFile? extADat, DatFile? extBDat) SplitByExtension(DatFile datFile, List<string> extA, List<string> extB)
{ {
// If roms is empty, return false // If roms is empty, return false
if (datFile.Items.TotalCount == 0) if (datFile.Items.DatStatistics.TotalCount == 0)
return (null, null); return (null, null);
InternalStopwatch watch = new($"Splitting DAT by extension"); InternalStopwatch watch = new($"Splitting DAT by extension");

View File

@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Runtime.InteropServices.ComTypes;
#if NET40_OR_GREATER || NETCOREAPP #if NET40_OR_GREATER || NETCOREAPP
using System.Threading.Tasks; using System.Threading.Tasks;
#endif #endif
@@ -50,7 +52,6 @@ namespace SabreTools.DatTools
// Init total // Init total
DatStatistics totalStats = new() DatStatistics totalStats = new()
{ {
Statistics = [],
DisplayName = "DIR: All DATs", DisplayName = "DIR: All DATs",
MachineCount = 0, MachineCount = 0,
IsDirectory = true, IsDirectory = true,
@@ -60,7 +61,6 @@ namespace SabreTools.DatTools
string? lastdir = null; string? lastdir = null;
DatStatistics dirStats = new() DatStatistics dirStats = new()
{ {
Statistics = [],
MachineCount = 0, MachineCount = 0,
IsDirectory = true, IsDirectory = true,
}; };
@@ -79,11 +79,10 @@ namespace SabreTools.DatTools
#else #else
dirStats.DisplayName = $"DIR: {WebUtility.HtmlEncode(lastdir)}"; dirStats.DisplayName = $"DIR: {WebUtility.HtmlEncode(lastdir)}";
#endif #endif
dirStats.MachineCount = dirStats.Statistics.GameCount; dirStats.MachineCount = dirStats.GameCount;
stats.Add(dirStats); stats.Add(dirStats);
dirStats = new DatStatistics dirStats = new DatStatistics
{ {
Statistics = [],
MachineCount = 0, MachineCount = 0,
IsDirectory = true, IsDirectory = true,
}; };
@@ -97,23 +96,20 @@ namespace SabreTools.DatTools
// Add single DAT stats (if asked) // Add single DAT stats (if asked)
if (single) if (single)
{ {
DatStatistics individualStats = new() DatStatistics individualStats = datdata.Items.DatStatistics;
{ individualStats.DisplayName = datdata.Header.GetStringFieldValue(DatHeader.FileNameKey);
Statistics = datdata.Items, individualStats.MachineCount = datdata.Items.Keys.Count;
DisplayName = datdata.Header.GetStringFieldValue(DatHeader.FileNameKey), individualStats.IsDirectory = false;
MachineCount = datdata.Items.Keys.Count,
IsDirectory = false,
};
stats.Add(individualStats); stats.Add(individualStats);
} }
// Add single DAT stats to dir // Add single DAT stats to dir
dirStats.Statistics.AddStatistics(datdata.Items); dirStats.AddStatistics(datdata.Items.DatStatistics);
dirStats.Statistics.GameCount += datdata.Items.Keys.Count; dirStats.GameCount += datdata.Items.Keys.Count;
// Add single DAT stats to totals // Add single DAT stats to totals
totalStats.Statistics.AddStatistics(datdata.Items); totalStats.AddStatistics(datdata.Items.DatStatistics);
totalStats.Statistics.GameCount += datdata.Items.Keys.Count; totalStats.GameCount += datdata.Items.Keys.Count;
// Make sure to assign the new directory // Make sure to assign the new directory
lastdir = thisdir; lastdir = thisdir;
@@ -129,12 +125,12 @@ namespace SabreTools.DatTools
#else #else
dirStats.DisplayName = $"DIR: {WebUtility.HtmlEncode(lastdir)}"; dirStats.DisplayName = $"DIR: {WebUtility.HtmlEncode(lastdir)}";
#endif #endif
dirStats.MachineCount = dirStats.Statistics.GameCount; dirStats.MachineCount = dirStats.GameCount;
stats.Add(dirStats); stats.Add(dirStats);
} }
// Add total DAT stats // Add total DAT stats
totalStats.MachineCount = totalStats.Statistics.GameCount; totalStats.MachineCount = totalStats.GameCount;
stats.Add(totalStats); stats.Add(totalStats);
return stats; return stats;

View File

@@ -71,7 +71,7 @@ namespace SabreTools.DatTools
datFile.Items.BucketBy(ItemKey.Machine, DedupeType.None); datFile.Items.BucketBy(ItemKey.Machine, DedupeType.None);
// Output the number of items we're going to be writing // Output the number of items we're going to be writing
logger.User($"A total of {datFile.Items.TotalCount - datFile.Items.RemovedCount} items will be written out to '{datFile.Header.GetStringFieldValue(DatHeader.FileNameKey)}'"); logger.User($"A total of {datFile.Items.DatStatistics.TotalCount - datFile.Items.DatStatistics.RemovedCount} items will be written out to '{datFile.Header.GetStringFieldValue(DatHeader.FileNameKey)}'");
// Get the outfile names // Get the outfile names
Dictionary<DatFormat, string> outfiles = datFile.Header.CreateOutFileNames(outDir!, overwrite); Dictionary<DatFormat, string> outfiles = datFile.Header.CreateOutFileNames(outDir!, overwrite);
@@ -121,24 +121,22 @@ namespace SabreTools.DatTools
/// <param name="datFile">Current DatFile object to write from</param> /// <param name="datFile">Current DatFile object to write from</param>
public static void WriteStatsToConsole(DatFile datFile) public static void WriteStatsToConsole(DatFile datFile)
{ {
long diskCount = datFile.Items.GetItemCount(ItemType.Disk); long diskCount = datFile.Items.DatStatistics.GetItemCount(ItemType.Disk);
long mediaCount = datFile.Items.GetItemCount(ItemType.Media); long mediaCount = datFile.Items.DatStatistics.GetItemCount(ItemType.Media);
long romCount = datFile.Items.GetItemCount(ItemType.Rom); long romCount = datFile.Items.DatStatistics.GetItemCount(ItemType.Rom);
if (diskCount + mediaCount + romCount == 0) if (diskCount + mediaCount + romCount == 0)
datFile.Items.RecalculateStats(); datFile.Items.RecalculateStats();
datFile.Items.BucketBy(ItemKey.Machine, DedupeType.None, norename: true); datFile.Items.BucketBy(ItemKey.Machine, DedupeType.None, norename: true);
datFile.Items.DatStatistics.DisplayName = datFile.Header.GetStringFieldValue(DatHeader.FileNameKey);
datFile.Items.DatStatistics.MachineCount = datFile.Items.Keys.Count;
datFile.Items.DatStatistics.IsDirectory = false;
var statsList = new List<DatStatistics> var statsList = new List<DatStatistics>
{ {
new() datFile.Items.DatStatistics,
{
Statistics = datFile.Items,
DisplayName = datFile.Header.GetStringFieldValue(DatHeader.FileNameKey),
MachineCount = datFile.Items.Keys.Count,
IsDirectory = false,
},
}; };
var consoleOutput = BaseReport.Create(StatReportFormat.None, statsList); var consoleOutput = BaseReport.Create(StatReportFormat.None, statsList);
consoleOutput!.WriteToFile(null, true, true); consoleOutput!.WriteToFile(null, true, true);
@@ -210,11 +208,11 @@ namespace SabreTools.DatTools
datFile.Items.RecalculateStats(); datFile.Items.RecalculateStats();
// If there's nothing there, abort // If there's nothing there, abort
if (datFile.Items.TotalCount == 0) if (datFile.Items.DatStatistics.TotalCount == 0)
return false; return false;
// If every item is removed, abort // If every item is removed, abort
if (datFile.Items.TotalCount == datFile.Items.RemovedCount) if (datFile.Items.DatStatistics.TotalCount == datFile.Items.DatStatistics.RemovedCount)
return false; return false;
return true; return true;

View File

@@ -1,5 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using SabreTools.DatFiles;
using SabreTools.Logging; using SabreTools.Logging;
using SabreTools.Reports.Formats; using SabreTools.Reports.Formats;

View File

@@ -1,30 +0,0 @@
using SabreTools.DatFiles;
namespace SabreTools.Reports
{
/// <summary>
/// Statistics wrapper for outputting
/// </summary>
public class DatStatistics
{
/// <summary>
/// ItemDictionary representing the statistics
/// </summary>
public ItemDictionary? Statistics { get; set; }
/// <summary>
/// Name to display on output
/// </summary>
public string? DisplayName { get; set; }
/// <summary>
/// Total machine count to use on output
/// </summary>
public long MachineCount { get; set; }
/// <summary>
/// Determines if statistics are for a directory or not
/// </summary>
public bool IsDirectory { get; set; } = false;
}
}

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Xml; using System.Xml;
using SabreTools.DatFiles;
using SabreTools.DatItems; using SabreTools.DatItems;
using SabreTools.Hashing; using SabreTools.Hashing;
using SabreTools.Logging; using SabreTools.Logging;
@@ -228,7 +229,7 @@ body {
xtw.WriteStartElement("td"); xtw.WriteStartElement("td");
xtw.WriteAttributeString("align", "right"); xtw.WriteAttributeString("align", "right");
xtw.WriteString(GetBytesReadable(stat.Statistics!.TotalSize)); xtw.WriteString(GetBytesReadable(stat.TotalSize));
xtw.WriteEndElement(); // td xtw.WriteEndElement(); // td
xtw.WriteStartElement("td"); xtw.WriteStartElement("td");
@@ -238,39 +239,39 @@ body {
xtw.WriteStartElement("td"); xtw.WriteStartElement("td");
xtw.WriteAttributeString("align", "right"); xtw.WriteAttributeString("align", "right");
xtw.WriteString(stat.Statistics.GetItemCount(ItemType.Rom).ToString()); xtw.WriteString(stat.GetItemCount(ItemType.Rom).ToString());
xtw.WriteEndElement(); // td xtw.WriteEndElement(); // td
xtw.WriteStartElement("td"); xtw.WriteStartElement("td");
xtw.WriteAttributeString("align", "right"); xtw.WriteAttributeString("align", "right");
xtw.WriteString(stat.Statistics.GetItemCount(ItemType.Disk).ToString()); xtw.WriteString(stat.GetItemCount(ItemType.Disk).ToString());
xtw.WriteEndElement(); // td xtw.WriteEndElement(); // td
xtw.WriteStartElement("td"); xtw.WriteStartElement("td");
xtw.WriteAttributeString("align", "right"); xtw.WriteAttributeString("align", "right");
xtw.WriteString(stat.Statistics.GetHashCount(HashType.CRC32).ToString()); xtw.WriteString(stat.GetHashCount(HashType.CRC32).ToString());
xtw.WriteEndElement(); // td xtw.WriteEndElement(); // td
xtw.WriteStartElement("td"); xtw.WriteStartElement("td");
xtw.WriteAttributeString("align", "right"); xtw.WriteAttributeString("align", "right");
xtw.WriteString(stat.Statistics.GetHashCount(HashType.MD5).ToString()); xtw.WriteString(stat.GetHashCount(HashType.MD5).ToString());
xtw.WriteEndElement(); // td xtw.WriteEndElement(); // td
xtw.WriteStartElement("td"); xtw.WriteStartElement("td");
xtw.WriteAttributeString("align", "right"); xtw.WriteAttributeString("align", "right");
xtw.WriteString(stat.Statistics.GetHashCount(HashType.SHA1).ToString()); xtw.WriteString(stat.GetHashCount(HashType.SHA1).ToString());
xtw.WriteEndElement(); // td xtw.WriteEndElement(); // td
xtw.WriteStartElement("td"); xtw.WriteStartElement("td");
xtw.WriteAttributeString("align", "right"); xtw.WriteAttributeString("align", "right");
xtw.WriteString(stat.Statistics.GetHashCount(HashType.SHA256).ToString()); xtw.WriteString(stat.GetHashCount(HashType.SHA256).ToString());
xtw.WriteEndElement(); // td xtw.WriteEndElement(); // td
if (baddumpCol) if (baddumpCol)
{ {
xtw.WriteStartElement("td"); xtw.WriteStartElement("td");
xtw.WriteAttributeString("align", "right"); xtw.WriteAttributeString("align", "right");
xtw.WriteString(stat.Statistics.GetStatusCount(ItemStatus.BadDump).ToString()); xtw.WriteString(stat.GetStatusCount(ItemStatus.BadDump).ToString());
xtw.WriteEndElement(); // td xtw.WriteEndElement(); // td
} }
@@ -278,7 +279,7 @@ body {
{ {
xtw.WriteStartElement("td"); xtw.WriteStartElement("td");
xtw.WriteAttributeString("align", "right"); xtw.WriteAttributeString("align", "right");
xtw.WriteString(stat.Statistics.GetStatusCount(ItemStatus.Nodump).ToString()); xtw.WriteString(stat.GetStatusCount(ItemStatus.Nodump).ToString());
xtw.WriteEndElement(); // td xtw.WriteEndElement(); // td
} }

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using SabreTools.DatFiles;
using SabreTools.DatItems; using SabreTools.DatItems;
using SabreTools.Hashing; using SabreTools.Hashing;
using SabreTools.IO.Writers; using SabreTools.IO.Writers;
@@ -130,18 +131,18 @@ namespace SabreTools.Reports.Formats
string[] values = string[] values =
[ [
stat.DisplayName!, stat.DisplayName!,
stat.Statistics!.TotalSize.ToString(), stat.TotalSize.ToString(),
stat.MachineCount.ToString(), stat.MachineCount.ToString(),
stat.Statistics.GetItemCount(ItemType.Rom).ToString(), stat.GetItemCount(ItemType.Rom).ToString(),
stat.Statistics.GetItemCount(ItemType.Disk).ToString(), stat.GetItemCount(ItemType.Disk).ToString(),
stat.Statistics.GetHashCount(HashType.CRC32).ToString(), stat.GetHashCount(HashType.CRC32).ToString(),
stat.Statistics.GetHashCount(HashType.MD5).ToString(), stat.GetHashCount(HashType.MD5).ToString(),
stat.Statistics.GetHashCount(HashType.SHA1).ToString(), stat.GetHashCount(HashType.SHA1).ToString(),
stat.Statistics.GetHashCount(HashType.SHA256).ToString(), stat.GetHashCount(HashType.SHA256).ToString(),
stat.Statistics.GetHashCount(HashType.SHA384).ToString(), stat.GetHashCount(HashType.SHA384).ToString(),
stat.Statistics.GetHashCount(HashType.SHA512).ToString(), stat.GetHashCount(HashType.SHA512).ToString(),
baddumpCol ? stat.Statistics.GetStatusCount(ItemStatus.BadDump).ToString() : string.Empty, baddumpCol ? stat.GetStatusCount(ItemStatus.BadDump).ToString() : string.Empty,
nodumpCol ? stat.Statistics.GetStatusCount(ItemStatus.Nodump).ToString() : string.Empty, nodumpCol ? stat.GetStatusCount(ItemStatus.Nodump).ToString() : string.Empty,
]; ];
svw.WriteValues(values); svw.WriteValues(values);
svw.Flush(); svw.Flush();

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using SabreTools.DatFiles;
using SabreTools.DatItems; using SabreTools.DatItems;
using SabreTools.Hashing; using SabreTools.Hashing;
using SabreTools.Logging; using SabreTools.Logging;
@@ -92,22 +93,22 @@ namespace SabreTools.Reports.Formats
{ {
string line = @"'" + stat.DisplayName + @"': string line = @"'" + stat.DisplayName + @"':
-------------------------------------------------- --------------------------------------------------
Uncompressed size: " + GetBytesReadable(stat.Statistics!.TotalSize) + @" Uncompressed size: " + GetBytesReadable(stat!.TotalSize) + @"
Games found: " + stat.MachineCount + @" Games found: " + stat.MachineCount + @"
Roms found: " + stat.Statistics.GetItemCount(ItemType.Rom) + @" Roms found: " + stat.GetItemCount(ItemType.Rom) + @"
Disks found: " + stat.Statistics.GetItemCount(ItemType.Disk) + @" Disks found: " + stat.GetItemCount(ItemType.Disk) + @"
Roms with CRC: " + stat.Statistics.GetHashCount(HashType.CRC32) + @" Roms with CRC: " + stat.GetHashCount(HashType.CRC32) + @"
Roms with MD5: " + stat.Statistics.GetHashCount(HashType.MD5) + @" Roms with MD5: " + stat.GetHashCount(HashType.MD5) + @"
Roms with SHA-1: " + stat.Statistics.GetHashCount(HashType.SHA1) + @" Roms with SHA-1: " + stat.GetHashCount(HashType.SHA1) + @"
Roms with SHA-256: " + stat.Statistics.GetHashCount(HashType.SHA256) + @" Roms with SHA-256: " + stat.GetHashCount(HashType.SHA256) + @"
Roms with SHA-384: " + stat.Statistics.GetHashCount(HashType.SHA384) + @" Roms with SHA-384: " + stat.GetHashCount(HashType.SHA384) + @"
Roms with SHA-512: " + stat.Statistics.GetHashCount(HashType.SHA512) + "\n"; Roms with SHA-512: " + stat.GetHashCount(HashType.SHA512) + "\n";
if (baddumpCol) if (baddumpCol)
line += " Roms with BadDump status: " + stat.Statistics.GetStatusCount(ItemStatus.BadDump) + "\n"; line += " Roms with BadDump status: " + stat.GetStatusCount(ItemStatus.BadDump) + "\n";
if (nodumpCol) if (nodumpCol)
line += " Roms with Nodump status: " + stat.Statistics.GetStatusCount(ItemStatus.Nodump) + "\n"; line += " Roms with Nodump status: " + stat.GetStatusCount(ItemStatus.Nodump) + "\n";
// For spacing between DATs // For spacing between DATs
line += "\n\n"; line += "\n\n";

View File

@@ -189,9 +189,10 @@ namespace SabreTools.Test.DatFiles
[Fact] [Fact]
public void ResetStatisticsTest() public void ResetStatisticsTest()
{ {
var dict = new ItemDictionary { GameCount = 1 }; var dict = new ItemDictionary();
dict.ResetStatistics(); dict.DatStatistics.GameCount = 1;
Assert.Equal(0, dict.GameCount); dict.DatStatistics.ResetStatistics();
Assert.Equal(0, dict.DatStatistics.GameCount);
} }
} }
} }

View File

@@ -43,7 +43,7 @@ namespace SabreTools.Test.DatTools
var datFile = SabreTools.DatTools.Parser.CreateAndParse(filename, throwOnError: true); var datFile = SabreTools.DatTools.Parser.CreateAndParse(filename, throwOnError: true);
Assert.Equal(datFormat, datFile.Header.GetFieldValue<DatFormat>(DatHeader.DatFormatKey)); Assert.Equal(datFormat, datFile.Header.GetFieldValue<DatFormat>(DatHeader.DatFormatKey));
Assert.Equal(totalCount, datFile.Items.TotalCount); Assert.Equal(totalCount, datFile.Items.DatStatistics.TotalCount);
} }
} }
} }