mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
Enable nullability everywhere
This commit is contained in:
@@ -2,7 +2,6 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using SabreTools.Core;
|
||||
using SabreTools.DatFiles;
|
||||
using SabreTools.DatItems;
|
||||
@@ -33,16 +32,22 @@ namespace SabreTools.DatTools
|
||||
/// <param name="inputs">List of inputs to use for renaming</param>
|
||||
public static void ApplySuperDAT(DatFile datFile, List<ParentablePath> inputs)
|
||||
{
|
||||
List<string> keys = datFile.Items.Keys.ToList();
|
||||
List<string> keys = [.. datFile.Items.Keys];
|
||||
Parallel.ForEach(keys, Globals.ParallelOptions, key =>
|
||||
{
|
||||
ConcurrentList<DatItem> items = datFile.Items[key];
|
||||
ConcurrentList<DatItem> newItems = new();
|
||||
ConcurrentList<DatItem>? items = datFile.Items[key];
|
||||
if (items == null)
|
||||
return;
|
||||
|
||||
ConcurrentList<DatItem> newItems = [];
|
||||
foreach (DatItem item in items)
|
||||
{
|
||||
DatItem newItem = item;
|
||||
if (newItem.Source == null)
|
||||
continue;
|
||||
|
||||
string filename = inputs[newItem.Source.Index].CurrentPath;
|
||||
string rootpath = inputs[newItem.Source.Index].ParentPath;
|
||||
string? rootpath = inputs[newItem.Source.Index].ParentPath;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(rootpath)
|
||||
&& !rootpath.EndsWith(Path.DirectorySeparatorChar)
|
||||
@@ -51,7 +56,7 @@ namespace SabreTools.DatTools
|
||||
rootpath += Path.DirectorySeparatorChar.ToString();
|
||||
}
|
||||
|
||||
filename = filename.Remove(0, rootpath.Length);
|
||||
filename = filename.Remove(0, rootpath?.Length ?? 0);
|
||||
newItem.Machine.Name = Path.GetDirectoryName(filename) + Path.DirectorySeparatorChar
|
||||
+ Path.GetFileNameWithoutExtension(filename) + Path.DirectorySeparatorChar
|
||||
+ newItem.Machine.Name;
|
||||
@@ -91,12 +96,16 @@ namespace SabreTools.DatTools
|
||||
// Then we do a hashwise comparison against the base DAT
|
||||
Parallel.ForEach(intDat.Items.Keys, Globals.ParallelOptions, key =>
|
||||
{
|
||||
ConcurrentList<DatItem> datItems = intDat.Items[key];
|
||||
ConcurrentList<DatItem> newDatItems = new();
|
||||
ConcurrentList<DatItem>? datItems = intDat.Items[key];
|
||||
if (datItems == null)
|
||||
return;
|
||||
|
||||
ConcurrentList<DatItem> newDatItems = [];
|
||||
foreach (DatItem datItem in datItems)
|
||||
{
|
||||
ConcurrentList<DatItem> dupes = datFile.Items.GetDuplicates(datItem, sorted: true);
|
||||
DatItem newDatItem = datItem.Clone() as DatItem;
|
||||
if (datItem.Clone() is not DatItem newDatItem)
|
||||
continue;
|
||||
|
||||
// Replace fields from the first duplicate, if we have one
|
||||
if (dupes.Count > 0)
|
||||
@@ -121,13 +130,21 @@ namespace SabreTools.DatTools
|
||||
// Then we do a namewise comparison against the base DAT
|
||||
Parallel.ForEach(intDat.Items.Keys, Globals.ParallelOptions, key =>
|
||||
{
|
||||
ConcurrentList<DatItem> datItems = intDat.Items[key];
|
||||
ConcurrentList<DatItem> newDatItems = new();
|
||||
ConcurrentList<DatItem>? datItems = intDat.Items[key];
|
||||
if (datItems == null)
|
||||
return;
|
||||
|
||||
ConcurrentList<DatItem> newDatItems = [];
|
||||
foreach (DatItem datItem in datItems)
|
||||
{
|
||||
DatItem newDatItem = datItem.Clone() as DatItem;
|
||||
if (datFile.Items.ContainsKey(key) && datFile.Items[key].Count > 0)
|
||||
Replacer.ReplaceFields(newDatItem.Machine, datFile.Items[key][0].Machine, machineFields, onlySame);
|
||||
if (datItem.Clone() is not DatItem newDatItem)
|
||||
continue;
|
||||
|
||||
if (!datFile.Items.TryGetValue(key, out var list) || list == null)
|
||||
continue;
|
||||
|
||||
if (datFile.Items.ContainsKey(key) && list.Count > 0)
|
||||
Replacer.ReplaceFields(newDatItem.Machine, list[0].Machine, machineFields, onlySame);
|
||||
|
||||
newDatItems.Add(newDatItem);
|
||||
}
|
||||
@@ -164,26 +181,30 @@ namespace SabreTools.DatTools
|
||||
intDat.Items.BucketBy(ItemKey.CRC, DedupeType.Full);
|
||||
|
||||
// Then we compare against the base DAT
|
||||
List<string> keys = intDat.Items.Keys.ToList();
|
||||
List<string> keys = [.. intDat.Items.Keys];
|
||||
Parallel.ForEach(keys, Globals.ParallelOptions, key =>
|
||||
{
|
||||
// Game Against uses game names
|
||||
if (useGames)
|
||||
{
|
||||
// If the key is null, keep it
|
||||
if (!intDat.Items.TryGetValue(key, out var intList) || intList == null)
|
||||
return;
|
||||
|
||||
// If the base DAT doesn't contain the key, keep it
|
||||
if (!datFile.Items.ContainsKey(key))
|
||||
if (!datFile.Items.TryGetValue(key, out var list) || list == null)
|
||||
return;
|
||||
|
||||
// If the number of items is different, then keep it
|
||||
if (datFile.Items[key].Count != intDat.Items[key].Count)
|
||||
if (list.Count != intList.Count)
|
||||
return;
|
||||
|
||||
// Otherwise, compare by name and hash the remaining files
|
||||
bool exactMatch = true;
|
||||
foreach (DatItem item in intDat.Items[key])
|
||||
foreach (DatItem item in intList)
|
||||
{
|
||||
// TODO: Make this granular to name as well
|
||||
if (!datFile.Items[key].Contains(item))
|
||||
if (!list.Contains(item))
|
||||
{
|
||||
exactMatch = false;
|
||||
break;
|
||||
@@ -198,8 +219,11 @@ namespace SabreTools.DatTools
|
||||
// Standard Against uses hashes
|
||||
else
|
||||
{
|
||||
ConcurrentList<DatItem> datItems = intDat.Items[key];
|
||||
ConcurrentList<DatItem> keepDatItems = new();
|
||||
ConcurrentList<DatItem>? datItems = intDat.Items[key];
|
||||
if (datItems == null)
|
||||
return;
|
||||
|
||||
ConcurrentList<DatItem> keepDatItems = [];
|
||||
foreach (DatItem datItem in datItems)
|
||||
{
|
||||
if (!datFile.Items.HasDuplicates(datItem, true))
|
||||
@@ -224,7 +248,7 @@ namespace SabreTools.DatTools
|
||||
public static List<DatFile> DiffCascade(DatFile datFile, List<DatHeader> datHeaders)
|
||||
{
|
||||
// Create a list of DatData objects representing output files
|
||||
List<DatFile> outDats = new();
|
||||
List<DatFile> outDats = [];
|
||||
|
||||
// Ensure the current DatFile is sorted optimally
|
||||
datFile.Items.BucketBy(ItemKey.CRC, DedupeType.None);
|
||||
@@ -237,12 +261,12 @@ namespace SabreTools.DatTools
|
||||
Parallel.For(0, datHeaders.Count, Globals.ParallelOptions, j =>
|
||||
{
|
||||
DatFile diffData = DatFile.Create(datHeaders[j]);
|
||||
diffData.Items = new ItemDictionary();
|
||||
diffData.Items = [];
|
||||
FillWithSourceIndex(datFile, diffData, j);
|
||||
outDatsArray[j] = diffData;
|
||||
});
|
||||
|
||||
outDats = outDatsArray.ToList();
|
||||
outDats = [.. outDatsArray];
|
||||
watch.Stop();
|
||||
|
||||
return outDats;
|
||||
@@ -283,7 +307,7 @@ namespace SabreTools.DatTools
|
||||
dupeData.Header.FileName += post;
|
||||
dupeData.Header.Name += post;
|
||||
dupeData.Header.Description += post;
|
||||
dupeData.Items = new ItemDictionary();
|
||||
dupeData.Items = [];
|
||||
|
||||
watch.Stop();
|
||||
|
||||
@@ -303,8 +327,11 @@ namespace SabreTools.DatTools
|
||||
{
|
||||
if (item.DupeType.HasFlag(DupeType.External))
|
||||
{
|
||||
DatItem newrom = item.Clone() as DatItem;
|
||||
newrom.Machine.Name += $" ({Path.GetFileNameWithoutExtension(inputs[item.Source.Index].CurrentPath)})";
|
||||
if (item.Clone() is not DatItem newrom)
|
||||
continue;
|
||||
|
||||
if (item.Source != null)
|
||||
newrom.Machine.Name += $" ({Path.GetFileNameWithoutExtension(inputs[item.Source.Index].CurrentPath)})";
|
||||
|
||||
dupeData.Items.Add(key, newrom);
|
||||
}
|
||||
@@ -356,12 +383,12 @@ namespace SabreTools.DatTools
|
||||
diffData.Header.FileName += innerpost;
|
||||
diffData.Header.Name += innerpost;
|
||||
diffData.Header.Description += innerpost;
|
||||
diffData.Items = new ItemDictionary();
|
||||
diffData.Items = [];
|
||||
outDatsArray[j] = diffData;
|
||||
});
|
||||
|
||||
// Create a list of DatData objects representing individual output files
|
||||
List<DatFile> outDats = outDatsArray.ToList();
|
||||
List<DatFile> outDats = [.. outDatsArray];
|
||||
|
||||
watch.Stop();
|
||||
|
||||
@@ -379,6 +406,9 @@ namespace SabreTools.DatTools
|
||||
// Loop through and add the items correctly
|
||||
foreach (DatItem item in items)
|
||||
{
|
||||
if (item.Source == null)
|
||||
continue;
|
||||
|
||||
if (item.DupeType.HasFlag(DupeType.Internal) || item.DupeType == 0x00)
|
||||
outDats[item.Source.Index].Items.Add(key, item);
|
||||
}
|
||||
@@ -386,7 +416,7 @@ namespace SabreTools.DatTools
|
||||
|
||||
watch.Stop();
|
||||
|
||||
return outDats.ToList();
|
||||
return [.. outDats];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -424,7 +454,7 @@ namespace SabreTools.DatTools
|
||||
outerDiffData.Header.FileName += post;
|
||||
outerDiffData.Header.Name += post;
|
||||
outerDiffData.Header.Description += post;
|
||||
outerDiffData.Items = new ItemDictionary();
|
||||
outerDiffData.Items = [];
|
||||
|
||||
watch.Stop();
|
||||
|
||||
@@ -444,8 +474,10 @@ namespace SabreTools.DatTools
|
||||
{
|
||||
if (item.DupeType.HasFlag(DupeType.Internal) || item.DupeType == 0x00)
|
||||
{
|
||||
DatItem newrom = item.Clone() as DatItem;
|
||||
newrom.Machine.Name += $" ({Path.GetFileNameWithoutExtension(inputs[item.Source.Index].CurrentPath)})";
|
||||
if (item.Clone() is not DatItem newrom || newrom.Source == null)
|
||||
continue;
|
||||
|
||||
newrom.Machine.Name += $" ({Path.GetFileNameWithoutExtension(inputs[newrom.Source.Index].CurrentPath)})";
|
||||
outerDiffData.Items.Add(key, newrom);
|
||||
}
|
||||
}
|
||||
@@ -523,7 +555,7 @@ namespace SabreTools.DatTools
|
||||
|
||||
// Now remove the file dictionary from the source DAT
|
||||
if (delete)
|
||||
addFrom.Items = null;
|
||||
addFrom.Items = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -546,7 +578,7 @@ namespace SabreTools.DatTools
|
||||
|
||||
foreach (DatItem item in items)
|
||||
{
|
||||
if (item.Source.Index == index)
|
||||
if (item.Source != null && item.Source.Index == index)
|
||||
indexDat.Items.Add(key, item);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using SabreTools.Core;
|
||||
using SabreTools.DatFiles;
|
||||
using SabreTools.DatItems;
|
||||
@@ -87,7 +86,7 @@ namespace SabreTools.DatTools
|
||||
totalSize = new FileInfo(basePath).Length;
|
||||
logger.User(totalSize, currentSize);
|
||||
|
||||
string parentPath = Path.GetDirectoryName(Path.GetDirectoryName(basePath));
|
||||
string? parentPath = Path.GetDirectoryName(Path.GetDirectoryName(basePath));
|
||||
CheckFileForHashes(datFile, basePath, parentPath, asFiles, skipFileType, addBlanks, hashes);
|
||||
logger.User(totalSize, totalSize, basePath);
|
||||
}
|
||||
@@ -109,7 +108,7 @@ namespace SabreTools.DatTools
|
||||
private static void CheckFileForHashes(
|
||||
DatFile datFile,
|
||||
string item,
|
||||
string basePath,
|
||||
string? basePath,
|
||||
TreatAsFile asFiles,
|
||||
SkipFileType skipFileType,
|
||||
bool addBlanks,
|
||||
@@ -120,7 +119,7 @@ namespace SabreTools.DatTools
|
||||
return;
|
||||
|
||||
// Initialize possible archive variables
|
||||
BaseArchive archive = BaseArchive.Create(item);
|
||||
BaseArchive? archive = BaseArchive.Create(item);
|
||||
|
||||
// Process archives according to flags
|
||||
if (archive != null)
|
||||
@@ -188,7 +187,7 @@ namespace SabreTools.DatTools
|
||||
|
||||
// Check the file as if it were in a depot
|
||||
GZipArchive gzarc = new(item);
|
||||
BaseFile baseFile = gzarc.GetTorrentGZFileInfo();
|
||||
BaseFile? baseFile = gzarc.GetTorrentGZFileInfo();
|
||||
|
||||
// If the rom is valid, add it
|
||||
if (baseFile != null && baseFile.Filename != null)
|
||||
@@ -214,15 +213,18 @@ namespace SabreTools.DatTools
|
||||
/// <param name="item">File to be added</param>
|
||||
/// <param name="basePath">Path the represents the parent directory</param>
|
||||
/// <param name="extracted">List of BaseFiles representing the internal files</param>
|
||||
private static void ProcessArchive(DatFile datFile, string item, string basePath, List<BaseFile> extracted)
|
||||
private static void ProcessArchive(DatFile datFile, string item, string? basePath, List<BaseFile> extracted)
|
||||
{
|
||||
// Get the parent path for all items
|
||||
string parent = (Path.GetDirectoryName(Path.GetFullPath(item)) + Path.DirectorySeparatorChar).Remove(0, basePath.Length) + Path.GetFileNameWithoutExtension(item);
|
||||
string parent = (Path.GetDirectoryName(Path.GetFullPath(item)) + Path.DirectorySeparatorChar).Remove(0, basePath?.Length ?? 0) + Path.GetFileNameWithoutExtension(item);
|
||||
|
||||
// First take care of the found items
|
||||
Parallel.ForEach(extracted, Globals.ParallelOptions, baseFile =>
|
||||
{
|
||||
DatItem datItem = DatItem.Create(baseFile);
|
||||
DatItem? datItem = DatItem.Create(baseFile);
|
||||
if (datItem == null)
|
||||
return;
|
||||
|
||||
ProcessFileHelper(datFile, item, datItem, basePath, parent);
|
||||
});
|
||||
}
|
||||
@@ -234,12 +236,12 @@ namespace SabreTools.DatTools
|
||||
/// <param name="item">File containing the blanks</param>
|
||||
/// <param name="basePath">Path the represents the parent directory</param>
|
||||
/// <param name="archive">BaseArchive to get blanks from</param>
|
||||
private static void ProcessArchiveBlanks(DatFile datFile, string item, string basePath, BaseArchive archive)
|
||||
private static void ProcessArchiveBlanks(DatFile datFile, string item, string? basePath, BaseArchive archive)
|
||||
{
|
||||
List<string> empties = new();
|
||||
List<string> empties = [];
|
||||
|
||||
// Get the parent path for all items
|
||||
string parent = (Path.GetDirectoryName(Path.GetFullPath(item)) + Path.DirectorySeparatorChar).Remove(0, basePath.Length) + Path.GetFileNameWithoutExtension(item);
|
||||
string parent = (Path.GetDirectoryName(Path.GetFullPath(item)) + Path.DirectorySeparatorChar).Remove(0, basePath?.Length ?? 0) + Path.GetFileNameWithoutExtension(item);
|
||||
|
||||
// Now get all blank folders from the archive
|
||||
if (archive != null)
|
||||
@@ -258,13 +260,13 @@ namespace SabreTools.DatTools
|
||||
/// </summary>
|
||||
/// <param name="datFile">Current DatFile object to add to</param>
|
||||
/// <param name="basePath">Path the represents the parent directory</param>
|
||||
private static void ProcessDirectoryBlanks(DatFile datFile, string basePath)
|
||||
private static void ProcessDirectoryBlanks(DatFile datFile, string? basePath)
|
||||
{
|
||||
// If we're in depot mode, we don't process blanks
|
||||
if (datFile.Header.OutputDepot?.IsActive == true)
|
||||
return;
|
||||
|
||||
List<string> empties = basePath.ListEmpty();
|
||||
List<string> empties = basePath.ListEmpty() ?? [];
|
||||
Parallel.ForEach(empties, Globals.ParallelOptions, dir =>
|
||||
{
|
||||
// Get the full path for the directory
|
||||
@@ -277,15 +279,27 @@ namespace SabreTools.DatTools
|
||||
// If we have a SuperDAT, we want anything that's not the base path as the game, and the file as the rom
|
||||
if (datFile.Header.Type == "SuperDAT")
|
||||
{
|
||||
gamename = fulldir.Remove(0, basePath.Length + 1);
|
||||
if (basePath != null)
|
||||
gamename = fulldir.Remove(0, basePath.Length + 1);
|
||||
else
|
||||
gamename = fulldir;
|
||||
|
||||
romname = "_";
|
||||
}
|
||||
|
||||
// Otherwise, we want just the top level folder as the game, and the file as everything else
|
||||
else
|
||||
{
|
||||
gamename = fulldir.Remove(0, basePath.Length + 1).Split(Path.DirectorySeparatorChar)[0];
|
||||
romname = Path.Combine(fulldir.Remove(0, basePath.Length + 1 + gamename.Length), "_");
|
||||
if (basePath != null)
|
||||
{
|
||||
gamename = fulldir.Remove(0, basePath.Length + 1).Split(Path.DirectorySeparatorChar)[0];
|
||||
romname = Path.Combine(fulldir.Remove(0, basePath.Length + 1 + gamename.Length), "_");
|
||||
}
|
||||
else
|
||||
{
|
||||
gamename = fulldir;
|
||||
romname = Path.Combine(fulldir, "_");
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitize the names
|
||||
@@ -293,7 +307,7 @@ namespace SabreTools.DatTools
|
||||
romname = romname.Trim(Path.DirectorySeparatorChar);
|
||||
|
||||
logger.Verbose($"Adding blank empty folder: {gamename}");
|
||||
datFile.Items["null"].Add(new Rom(romname, gamename));
|
||||
datFile.Items["null"]?.Add(new Rom(romname, gamename));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -305,12 +319,13 @@ namespace SabreTools.DatTools
|
||||
/// <param name="basePath">Path the represents the parent directory</param>
|
||||
/// <param name="hashes">Hashes to include in the information</param>
|
||||
/// <param name="asFiles">TreatAsFiles representing CHD and Archive scanning</param>
|
||||
private static void ProcessFile(DatFile datFile, string item, string basePath, Hash hashes, TreatAsFile asFiles)
|
||||
private static void ProcessFile(DatFile datFile, string item, string? basePath, Hash hashes, TreatAsFile asFiles)
|
||||
{
|
||||
logger.Verbose($"'{Path.GetFileName(item)}' treated like a file");
|
||||
BaseFile baseFile = BaseFile.GetInfo(item, header: datFile.Header.HeaderSkipper, hashes: hashes, asFiles: asFiles);
|
||||
DatItem datItem = DatItem.Create(baseFile);
|
||||
ProcessFileHelper(datFile, item, datItem, basePath, string.Empty);
|
||||
BaseFile? baseFile = BaseFile.GetInfo(item, header: datFile.Header.HeaderSkipper, hashes: hashes, asFiles: asFiles);
|
||||
DatItem? datItem = DatItem.Create(baseFile);
|
||||
if (datItem != null)
|
||||
ProcessFileHelper(datFile, item, datItem, basePath, string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -321,17 +336,17 @@ namespace SabreTools.DatTools
|
||||
/// <param name="item">Rom data to be used to write to file</param>
|
||||
/// <param name="basepath">Path the represents the parent directory</param>
|
||||
/// <param name="parent">Parent game to be used</param>
|
||||
private static void ProcessFileHelper(DatFile datFile, string item, DatItem datItem, string basepath, string parent)
|
||||
private static void ProcessFileHelper(DatFile datFile, string item, DatItem datItem, string? basepath, string parent)
|
||||
{
|
||||
// If we didn't get an accepted parsed type somehow, cancel out
|
||||
List<ItemType> parsed = new() { ItemType.Disk, ItemType.File, ItemType.Media, ItemType.Rom };
|
||||
List<ItemType> parsed = [ItemType.Disk, ItemType.File, ItemType.Media, ItemType.Rom];
|
||||
if (!parsed.Contains(datItem.ItemType))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// If the basepath doesn't end with a directory separator, add it
|
||||
if (!basepath.EndsWith(Path.DirectorySeparatorChar.ToString()))
|
||||
if (basepath != null && !basepath.EndsWith(Path.DirectorySeparatorChar.ToString()))
|
||||
basepath += Path.DirectorySeparatorChar.ToString();
|
||||
|
||||
// Make sure we have the full item path
|
||||
@@ -361,10 +376,10 @@ namespace SabreTools.DatTools
|
||||
/// <param name="item">Item name to use</param>
|
||||
/// <param name="parent">Parent name to use</param>
|
||||
/// <param name="basepath">Base path to use</param>
|
||||
private static void SetDatItemInfo(DatFile datFile, DatItem datItem, string item, string parent, string basepath)
|
||||
private static void SetDatItemInfo(DatFile datFile, DatItem datItem, string item, string parent, string? basepath)
|
||||
{
|
||||
// Get the data to be added as game and item names
|
||||
string machineName, itemName;
|
||||
string? machineName, itemName;
|
||||
|
||||
// If the parent is blank, then we have a non-archive file
|
||||
if (string.IsNullOrWhiteSpace(parent))
|
||||
@@ -372,15 +387,18 @@ namespace SabreTools.DatTools
|
||||
// If we have a SuperDAT, we want anything that's not the base path as the game, and the file as the rom
|
||||
if (datFile.Header.Type == "SuperDAT")
|
||||
{
|
||||
machineName = Path.GetDirectoryName(item.Remove(0, basepath.Length));
|
||||
machineName = Path.GetDirectoryName(item.Remove(0, basepath?.Length ?? 0));
|
||||
itemName = Path.GetFileName(item);
|
||||
}
|
||||
|
||||
// Otherwise, we want just the top level folder as the game, and the file as everything else
|
||||
else
|
||||
{
|
||||
machineName = item.Remove(0, basepath.Length).Split(Path.DirectorySeparatorChar)[0];
|
||||
itemName = item.Remove(0, (Path.Combine(basepath, machineName).Length));
|
||||
machineName = item.Remove(0, basepath?.Length ?? 0).Split(Path.DirectorySeparatorChar)[0];
|
||||
if (basepath != null)
|
||||
itemName = item.Remove(0, (Path.Combine(basepath, machineName).Length));
|
||||
else
|
||||
itemName = item.Remove(0, (machineName.Length));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,7 +421,7 @@ namespace SabreTools.DatTools
|
||||
}
|
||||
|
||||
// Sanitize the names
|
||||
machineName = machineName.Trim(Path.DirectorySeparatorChar);
|
||||
machineName = machineName?.Trim(Path.DirectorySeparatorChar);
|
||||
itemName = itemName?.Trim(Path.DirectorySeparatorChar) ?? string.Empty;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(machineName) && string.IsNullOrWhiteSpace(itemName))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using SabreTools.Core.Tools;
|
||||
using SabreTools.DatFiles;
|
||||
using SabreTools.DatItems;
|
||||
@@ -130,7 +129,7 @@ namespace SabreTools.DatTools
|
||||
return 0;
|
||||
|
||||
// Get the extension from the filename
|
||||
string ext = filename.GetNormalizedExtension();
|
||||
string? ext = filename.GetNormalizedExtension();
|
||||
|
||||
// Check if file exists
|
||||
if (!File.Exists(filename))
|
||||
@@ -232,7 +231,7 @@ namespace SabreTools.DatTools
|
||||
else if (first.Contains("doscenter"))
|
||||
return DatFormat.DOSCenter;
|
||||
|
||||
else if (first.Contains("#Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra".ToLowerInvariant()))
|
||||
else if (first.Contains("#Name;Title;Emulator;CloneOf;Year;Manufacturer;Category;Players;Rotation;Control;Status;DisplayCount;DisplayType;AltRomname;AltTitle;Extra", StringComparison.InvariantCultureIgnoreCase))
|
||||
return DatFormat.AttractMode;
|
||||
|
||||
else
|
||||
@@ -251,42 +250,49 @@ namespace SabreTools.DatTools
|
||||
return string.Empty;
|
||||
|
||||
// Find the first line that's not whitespace or an XML comment
|
||||
string line = sr.ReadLine().ToLowerInvariant().Trim();
|
||||
bool inComment = line.StartsWith("<!--");
|
||||
string? line = sr.ReadLine()?.ToLowerInvariant()?.Trim();
|
||||
bool inComment = line?.StartsWith("<!--") ?? false;
|
||||
while ((string.IsNullOrWhiteSpace(line) || inComment) && !sr.EndOfStream)
|
||||
{
|
||||
// Null lines should not happen
|
||||
if (line == null)
|
||||
{
|
||||
line = sr.ReadLine()?.ToLowerInvariant()?.Trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Self-contained comment lines
|
||||
if (line.StartsWith("<!--") && line.EndsWith("-->"))
|
||||
{
|
||||
inComment = false;
|
||||
line = sr.ReadLine().ToLowerInvariant().Trim();
|
||||
line = sr.ReadLine()?.ToLowerInvariant()?.Trim();
|
||||
}
|
||||
|
||||
// Start of block comments
|
||||
else if (line.StartsWith("<!--"))
|
||||
{
|
||||
inComment = true;
|
||||
line = sr.ReadLine().ToLowerInvariant().Trim();
|
||||
line = sr.ReadLine()?.ToLowerInvariant()?.Trim();
|
||||
}
|
||||
|
||||
// End of block comments
|
||||
else if (inComment && line.EndsWith("-->"))
|
||||
{
|
||||
line = sr.ReadLine().ToLowerInvariant().Trim();
|
||||
inComment = line.StartsWith("<!--");
|
||||
line = sr.ReadLine()?.ToLowerInvariant()?.Trim();
|
||||
inComment = line?.StartsWith("<!--") ?? false;
|
||||
}
|
||||
|
||||
// Empty lines are just skipped
|
||||
else if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
line = sr.ReadLine().ToLowerInvariant().Trim();
|
||||
inComment |= line.StartsWith("<!--");
|
||||
line = sr.ReadLine()?.ToLowerInvariant()?.Trim();
|
||||
inComment |= line?.StartsWith("<!--") ?? false;
|
||||
}
|
||||
|
||||
// In-comment lines
|
||||
else if (inComment)
|
||||
{
|
||||
line = sr.ReadLine().ToLowerInvariant().Trim();
|
||||
line = sr.ReadLine()?.ToLowerInvariant()?.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +300,7 @@ namespace SabreTools.DatTools
|
||||
if (inComment)
|
||||
return string.Empty;
|
||||
|
||||
return line;
|
||||
return line ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using SabreTools.Core;
|
||||
using SabreTools.Core.Tools;
|
||||
using SabreTools.DatFiles;
|
||||
@@ -76,7 +75,7 @@ namespace SabreTools.DatTools
|
||||
InternalStopwatch watch = new($"Rebuilding all files to {format}");
|
||||
|
||||
// Now loop through and get only directories from the input paths
|
||||
List<string> directories = new();
|
||||
List<string> directories = [];
|
||||
Parallel.ForEach(inputs, Globals.ParallelOptions, input =>
|
||||
{
|
||||
// Add to the list if the input is a directory
|
||||
@@ -108,10 +107,12 @@ namespace SabreTools.DatTools
|
||||
logger.User($"Checking hash '{hash}'");
|
||||
|
||||
// Get the extension path for the hash
|
||||
string subpath = Utilities.GetDepotPath(hash, datFile.Header.InputDepot.Depth);
|
||||
string? subpath = Utilities.GetDepotPath(hash, datFile.Header.InputDepot?.Depth ?? 0);
|
||||
if (subpath == null)
|
||||
continue;
|
||||
|
||||
// Find the first depot that includes the hash
|
||||
string foundpath = null;
|
||||
string? foundpath = null;
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
if (System.IO.File.Exists(Path.Combine(directory, subpath)))
|
||||
@@ -127,7 +128,7 @@ namespace SabreTools.DatTools
|
||||
|
||||
// If we have a path, we want to try to get the rom information
|
||||
GZipArchive archive = new(foundpath);
|
||||
BaseFile fileinfo = archive.GetTorrentGZFileInfo();
|
||||
BaseFile? fileinfo = archive.GetTorrentGZFileInfo();
|
||||
|
||||
// If the file information is null, then we continue
|
||||
if (fileinfo == null)
|
||||
@@ -137,16 +138,17 @@ namespace SabreTools.DatTools
|
||||
datFile.Items.BucketBy(ItemKey.SHA1, DedupeType.None);
|
||||
|
||||
// If there are no items in the hash, we continue
|
||||
if (datFile.Items[hash] == null || datFile.Items[hash].Count == 0)
|
||||
var items = datFile.Items[hash];
|
||||
if (items == null || items.Count == 0)
|
||||
continue;
|
||||
|
||||
// Otherwise, we rebuild that file to all locations that we need to
|
||||
bool usedInternally;
|
||||
if (datFile.Items[hash][0].ItemType == ItemType.Disk)
|
||||
if (items[0].ItemType == ItemType.Disk)
|
||||
usedInternally = RebuildIndividualFile(datFile, new Disk(fileinfo), foundpath, outDir, date, inverse, outputFormat, isZip: false);
|
||||
else if (datFile.Items[hash][0].ItemType == ItemType.File)
|
||||
else if (items[0].ItemType == ItemType.File)
|
||||
usedInternally = RebuildIndividualFile(datFile, new DatItems.Formats.File(fileinfo), foundpath, outDir, date, inverse, outputFormat, isZip: false);
|
||||
else if (datFile.Items[hash][0].ItemType == ItemType.Media)
|
||||
else if (items[0].ItemType == ItemType.Media)
|
||||
usedInternally = RebuildIndividualFile(datFile, new Media(fileinfo), foundpath, outDir, date, inverse, outputFormat, isZip: false);
|
||||
else
|
||||
usedInternally = RebuildIndividualFile(datFile, new Rom(fileinfo), foundpath, outDir, date, inverse, outputFormat, isZip: false);
|
||||
@@ -284,7 +286,7 @@ namespace SabreTools.DatTools
|
||||
bool usedExternally = false, usedInternally = false;
|
||||
|
||||
// Create an empty list of BaseFile for archive entries
|
||||
List<BaseFile> entries = null;
|
||||
List<BaseFile>? entries = null;
|
||||
|
||||
// Get the TGZ and TXZ status for later
|
||||
GZipArchive tgz = new(file);
|
||||
@@ -292,7 +294,7 @@ namespace SabreTools.DatTools
|
||||
bool isSingleTorrent = tgz.IsTorrent() || txz.IsTorrent();
|
||||
|
||||
// Get the base archive first
|
||||
BaseArchive archive = BaseArchive.Create(file);
|
||||
BaseArchive? archive = BaseArchive.Create(file);
|
||||
|
||||
// Now get all extracted items from the archive
|
||||
if (archive != null)
|
||||
@@ -304,25 +306,31 @@ namespace SabreTools.DatTools
|
||||
// If the entries list is null, we encountered an error or have a file and should scan externally
|
||||
if (entries == null && System.IO.File.Exists(file))
|
||||
{
|
||||
BaseFile internalFileInfo = BaseFile.GetInfo(file, asFiles: asFiles);
|
||||
BaseFile? internalFileInfo = BaseFile.GetInfo(file, asFiles: asFiles);
|
||||
|
||||
// Create the correct DatItem
|
||||
DatItem internalDatItem;
|
||||
if (internalFileInfo.Type == FileType.AaruFormat && !asFiles.HasFlag(TreatAsFile.AaruFormat))
|
||||
DatItem? internalDatItem;
|
||||
if (internalFileInfo == null)
|
||||
internalDatItem = null;
|
||||
else if (internalFileInfo.Type == FileType.AaruFormat && !asFiles.HasFlag(TreatAsFile.AaruFormat))
|
||||
internalDatItem = new Media(internalFileInfo);
|
||||
else if (internalFileInfo.Type == FileType.CHD && !asFiles.HasFlag(TreatAsFile.CHD))
|
||||
internalDatItem = new Disk(internalFileInfo);
|
||||
else
|
||||
internalDatItem = new Rom(internalFileInfo);
|
||||
|
||||
usedExternally = RebuildIndividualFile(datFile, internalDatItem, file, outDir, date, inverse, outputFormat);
|
||||
if (internalDatItem != null)
|
||||
usedExternally = RebuildIndividualFile(datFile, internalDatItem, file, outDir, date, inverse, outputFormat);
|
||||
}
|
||||
// Otherwise, loop through the entries and try to match
|
||||
else
|
||||
else if (entries != null)
|
||||
{
|
||||
foreach (BaseFile entry in entries)
|
||||
{
|
||||
DatItem internalDatItem = DatItem.Create(entry);
|
||||
DatItem? internalDatItem = DatItem.Create(entry);
|
||||
if (internalDatItem == null)
|
||||
continue;
|
||||
|
||||
usedInternally |= RebuildIndividualFile(datFile, internalDatItem, file, outDir, date, inverse, outputFormat, !isSingleTorrent /* isZip */);
|
||||
}
|
||||
}
|
||||
@@ -364,18 +372,18 @@ namespace SabreTools.DatTools
|
||||
}
|
||||
|
||||
// If we have a Disk, File, or Media, change it into a Rom for later use
|
||||
if (datItem.ItemType == ItemType.Disk)
|
||||
datItem = (datItem as Disk).ConvertToRom();
|
||||
else if (datItem.ItemType == ItemType.File)
|
||||
datItem = (datItem as DatItems.Formats.File).ConvertToRom();
|
||||
else if (datItem.ItemType == ItemType.Media)
|
||||
datItem = (datItem as Media).ConvertToRom();
|
||||
if (datItem is Disk disk)
|
||||
datItem = disk.ConvertToRom();
|
||||
else if (datItem is DatItems.Formats.File fileItem)
|
||||
datItem = fileItem.ConvertToRom();
|
||||
else if (datItem is Media media)
|
||||
datItem = media.ConvertToRom();
|
||||
|
||||
// Prepopluate a key string
|
||||
string crc = (datItem as Rom).CRC ?? string.Empty;
|
||||
string crc = (datItem as Rom)!.CRC ?? string.Empty;
|
||||
|
||||
// Try to get the stream for the file
|
||||
if (!GetFileStream(datItem, file, isZip, out Stream fileStream))
|
||||
if (!GetFileStream(datItem, file, isZip, out Stream? fileStream))
|
||||
return false;
|
||||
|
||||
// If either we have duplicates or we're filtering
|
||||
@@ -403,17 +411,22 @@ namespace SabreTools.DatTools
|
||||
// Now loop through the list and rebuild accordingly
|
||||
foreach (DatItem item in dupes)
|
||||
{
|
||||
// If we don't have a proper machine
|
||||
if (item.Machine?.Name == null || !datFile.Items.ContainsKey(item.Machine.Name))
|
||||
continue;
|
||||
|
||||
// If we should check for the items in the machine
|
||||
if (shouldCheck && datFile.Items[item.Machine.Name].Count > 1)
|
||||
var items = datFile.Items[item.Machine.Name];
|
||||
if (shouldCheck && items!.Count > 1)
|
||||
outputFormat = OutputFormat.Folder;
|
||||
else if (shouldCheck && datFile.Items[item.Machine.Name].Count == 1)
|
||||
else if (shouldCheck && items!.Count == 1)
|
||||
outputFormat = OutputFormat.ParentFolder;
|
||||
|
||||
// Get the output archive, if possible
|
||||
Folder outputArchive = GetPreconfiguredFolder(datFile, date, outputFormat);
|
||||
Folder? outputArchive = GetPreconfiguredFolder(datFile, date, outputFormat);
|
||||
|
||||
// Now rebuild to the output file
|
||||
outputArchive.Write(fileStream, outDir, (item as Rom).ConvertToBaseFile());
|
||||
outputArchive!.Write(fileStream, outDir, (item as Rom)!.ConvertToBaseFile());
|
||||
}
|
||||
|
||||
// Close the input stream
|
||||
@@ -451,12 +464,12 @@ namespace SabreTools.DatTools
|
||||
datItem.SetName($"{datItem.GetName()}_{crc}");
|
||||
|
||||
// Get the output archive, if possible
|
||||
Folder outputArchive = GetPreconfiguredFolder(datFile, date, outputFormat);
|
||||
Folder? outputArchive = GetPreconfiguredFolder(datFile, date, outputFormat);
|
||||
|
||||
// Now rebuild to the output file
|
||||
bool eitherSuccess = false;
|
||||
eitherSuccess |= outputArchive.Write(transformStream, outDir, (item as Rom).ConvertToBaseFile());
|
||||
eitherSuccess |= outputArchive.Write(fileStream, outDir, (datItem as Rom).ConvertToBaseFile());
|
||||
eitherSuccess |= outputArchive!.Write(transformStream, outDir, (item as Rom)!.ConvertToBaseFile());
|
||||
eitherSuccess |= outputArchive.Write(fileStream, outDir, (datItem as Rom)!.ConvertToBaseFile());
|
||||
|
||||
// Now add the success of either rebuild
|
||||
rebuilt &= eitherSuccess;
|
||||
@@ -484,7 +497,7 @@ namespace SabreTools.DatTools
|
||||
/// <param name="inverse">True if the DAT should be used as a filter instead of a template, false otherwise</param>
|
||||
/// <param name="dupes">Output list of duplicate items to rebuild to</param>
|
||||
/// <returns>True if the item should be rebuilt, false otherwise</returns>
|
||||
private static bool ShouldRebuild(DatFile datFile, DatItem datItem, Stream stream, bool inverse, out ConcurrentList<DatItem> dupes)
|
||||
private static bool ShouldRebuild(DatFile datFile, DatItem datItem, Stream? stream, bool inverse, out ConcurrentList<DatItem> dupes)
|
||||
{
|
||||
// Find if the file has duplicates in the DAT
|
||||
dupes = datFile.Items.GetDuplicates(datItem);
|
||||
@@ -505,7 +518,7 @@ namespace SabreTools.DatTools
|
||||
// If we have no duplicates and we're filtering
|
||||
else if (!hasDuplicates && inverse)
|
||||
{
|
||||
string machinename = null;
|
||||
string? machinename = null;
|
||||
|
||||
// Get the item from the current file
|
||||
Rom item = new(BaseFile.GetInfo(stream, keepReadOpen: true));
|
||||
@@ -544,20 +557,22 @@ namespace SabreTools.DatTools
|
||||
{
|
||||
// If we have a very specific TGZ->TGZ case, just copy it accordingly
|
||||
GZipArchive tgz = new(file);
|
||||
BaseFile tgzRom = tgz.GetTorrentGZFileInfo();
|
||||
BaseFile? tgzRom = tgz.GetTorrentGZFileInfo();
|
||||
if (isZip == false && tgzRom != null && (outputFormat == OutputFormat.TorrentGzip || outputFormat == OutputFormat.TorrentGzipRomba))
|
||||
{
|
||||
logger.User($"Matches found for '{Path.GetFileName(datItem.GetName() ?? string.Empty)}', rebuilding accordingly...");
|
||||
|
||||
// Get the proper output path
|
||||
string sha1 = (datItem as Rom).SHA1 ?? string.Empty;
|
||||
string sha1 = (datItem as Rom)!.SHA1 ?? string.Empty;
|
||||
if (outputFormat == OutputFormat.TorrentGzipRomba)
|
||||
outDir = Path.Combine(outDir, Utilities.GetDepotPath(sha1, datFile.Header.OutputDepot.Depth));
|
||||
outDir = Path.Combine(outDir, Utilities.GetDepotPath(sha1, datFile.Header.OutputDepot?.Depth ?? 0) ?? string.Empty);
|
||||
else
|
||||
outDir = Path.Combine(outDir, sha1 + ".gz");
|
||||
|
||||
// Make sure the output folder is created
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outDir));
|
||||
string? dir = Path.GetDirectoryName(outDir);
|
||||
if (dir != null)
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
// Now copy the file over
|
||||
try
|
||||
@@ -588,20 +603,22 @@ namespace SabreTools.DatTools
|
||||
{
|
||||
// If we have a very specific TGZ->TGZ case, just copy it accordingly
|
||||
XZArchive txz = new(file);
|
||||
BaseFile txzRom = txz.GetTorrentXZFileInfo();
|
||||
BaseFile? txzRom = txz.GetTorrentXZFileInfo();
|
||||
if (isZip == false && txzRom != null && (outputFormat == OutputFormat.TorrentXZ || outputFormat == OutputFormat.TorrentXZRomba))
|
||||
{
|
||||
logger.User($"Matches found for '{Path.GetFileName(datItem.GetName() ?? string.Empty)}', rebuilding accordingly...");
|
||||
|
||||
// Get the proper output path
|
||||
string sha1 = (datItem as Rom).SHA1 ?? string.Empty;
|
||||
string sha1 = (datItem as Rom)!.SHA1 ?? string.Empty;
|
||||
if (outputFormat == OutputFormat.TorrentXZRomba)
|
||||
outDir = Path.Combine(outDir, Utilities.GetDepotPath(sha1, datFile.Header.OutputDepot.Depth)).Replace(".gz", ".xz");
|
||||
outDir = Path.Combine(outDir, Utilities.GetDepotPath(sha1, datFile.Header.OutputDepot?.Depth ?? 0) ?? string.Empty).Replace(".gz", ".xz");
|
||||
else
|
||||
outDir = Path.Combine(outDir, sha1 + ".xz");
|
||||
|
||||
// Make sure the output folder is created
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outDir));
|
||||
string? dir = Path.GetDirectoryName(outDir);
|
||||
if (dir != null)
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
// Now copy the file over
|
||||
try
|
||||
@@ -626,7 +643,7 @@ namespace SabreTools.DatTools
|
||||
/// <param name="isZip">Non-null if the input file is an archive</param>
|
||||
/// <param name="stream">Output stream representing the opened file</param>
|
||||
/// <returns>True if the stream opening succeeded, false otherwise</returns>
|
||||
private static bool GetFileStream(DatItem datItem, string file, bool? isZip, out Stream stream)
|
||||
private static bool GetFileStream(DatItem datItem, string file, bool? isZip, out Stream? stream)
|
||||
{
|
||||
// Get a generic stream for the file
|
||||
stream = null;
|
||||
@@ -634,7 +651,7 @@ namespace SabreTools.DatTools
|
||||
// If we have a zipfile, extract the stream to memory
|
||||
if (isZip != null)
|
||||
{
|
||||
BaseArchive archive = BaseArchive.Create(file);
|
||||
BaseArchive? archive = BaseArchive.Create(file);
|
||||
if (archive != null)
|
||||
(stream, _) = archive.CopyToStream(datItem.GetName() ?? datItem.ItemType.ToString());
|
||||
}
|
||||
@@ -678,17 +695,17 @@ namespace SabreTools.DatTools
|
||||
/// <param name="date">True if the date from the DAT should be used if available, false otherwise</param>
|
||||
/// <param name="outputFormat">Output format that files should be written to</param>
|
||||
/// <returns>Folder configured with proper flags</returns>
|
||||
private static Folder GetPreconfiguredFolder(DatFile datFile, bool date, OutputFormat outputFormat)
|
||||
private static Folder? GetPreconfiguredFolder(DatFile datFile, bool date, OutputFormat outputFormat)
|
||||
{
|
||||
Folder outputArchive = Folder.Create(outputFormat);
|
||||
Folder? outputArchive = Folder.Create(outputFormat);
|
||||
if (outputArchive is BaseArchive baseArchive && date)
|
||||
baseArchive.UseDates = date;
|
||||
|
||||
// Set the depth fields where appropriate
|
||||
if (outputArchive is GZipArchive gzipArchive)
|
||||
gzipArchive.Depth = datFile.Header.OutputDepot.Depth;
|
||||
gzipArchive.Depth = datFile.Header.OutputDepot?.Depth ?? 0;
|
||||
else if (outputArchive is XZArchive xzArchive)
|
||||
xzArchive.Depth = datFile.Header.OutputDepot.Depth;
|
||||
xzArchive.Depth = datFile.Header.OutputDepot?.Depth ?? 0;
|
||||
|
||||
return outputArchive;
|
||||
}
|
||||
@@ -698,7 +715,7 @@ namespace SabreTools.DatTools
|
||||
/// </summary>
|
||||
/// <param name="itemType">OutputFormat to get value from</param>
|
||||
/// <returns>String value corresponding to the OutputFormat</returns>
|
||||
private static string FromOutputFormat(OutputFormat itemType)
|
||||
private static string? FromOutputFormat(OutputFormat itemType)
|
||||
{
|
||||
return itemType switch
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.IO" Version="1.2.0" />
|
||||
<PackageReference Include="SabreTools.IO" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,14 +4,13 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using NaturalSort;
|
||||
using SabreTools.Core;
|
||||
using SabreTools.DatFiles;
|
||||
using SabreTools.DatItems;
|
||||
using SabreTools.DatItems.Formats;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Logging;
|
||||
using NaturalSort;
|
||||
|
||||
namespace SabreTools.DatTools
|
||||
{
|
||||
@@ -37,7 +36,7 @@ namespace SabreTools.DatTools
|
||||
/// <param name="extA">List of extensions to split on (first DAT)</param>
|
||||
/// <param name="extB">List of extensions to split on (second DAT)</param>
|
||||
/// <returns>Extension Set A and Extension Set B DatFiles</returns>
|
||||
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 (datFile.Items.TotalCount == 0)
|
||||
@@ -66,7 +65,10 @@ namespace SabreTools.DatTools
|
||||
// Now separate the roms accordingly
|
||||
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
|
||||
{
|
||||
ConcurrentList<DatItem> items = datFile.Items[key];
|
||||
ConcurrentList<DatItem>? items = datFile.Items[key];
|
||||
if (items == null)
|
||||
return;
|
||||
|
||||
foreach (DatItem item in items)
|
||||
{
|
||||
if (newExtA.Contains((item.GetName() ?? string.Empty).GetNormalizedExtension()))
|
||||
@@ -101,7 +103,7 @@ namespace SabreTools.DatTools
|
||||
InternalStopwatch watch = new($"Splitting DAT by best available hashes");
|
||||
|
||||
// Create the set of field-to-dat mappings
|
||||
Dictionary<DatItemField, DatFile> fieldDats = new();
|
||||
Dictionary<DatItemField, DatFile> fieldDats = [];
|
||||
|
||||
// TODO: Can this be made into a loop?
|
||||
fieldDats[DatItemField.Status] = DatFile.Create(datFile.Header.CloneStandard());
|
||||
@@ -147,7 +149,10 @@ namespace SabreTools.DatTools
|
||||
// Now populate each of the DAT objects in turn
|
||||
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
|
||||
{
|
||||
ConcurrentList<DatItem> items = datFile.Items[key];
|
||||
ConcurrentList<DatItem>? items = datFile.Items[key];
|
||||
if (items == null)
|
||||
return;
|
||||
|
||||
foreach (DatItem item in items)
|
||||
{
|
||||
// If the file is not a Disk, Media, or Rom, continue
|
||||
@@ -155,49 +160,49 @@ namespace SabreTools.DatTools
|
||||
return;
|
||||
|
||||
// If the file is a nodump
|
||||
if ((item.ItemType == ItemType.Rom && (item as Rom).ItemStatus == ItemStatus.Nodump)
|
||||
|| (item.ItemType == ItemType.Disk && (item as Disk).ItemStatus == ItemStatus.Nodump))
|
||||
if ((item.ItemType == ItemType.Rom && (item as Rom)!.ItemStatus == ItemStatus.Nodump)
|
||||
|| (item.ItemType == ItemType.Disk && (item as Disk)!.ItemStatus == ItemStatus.Nodump))
|
||||
{
|
||||
fieldDats[DatItemField.Status].Items.Add(key, item);
|
||||
}
|
||||
|
||||
// If the file has a SHA-512
|
||||
else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom).SHA512)))
|
||||
else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom)!.SHA512)))
|
||||
{
|
||||
fieldDats[DatItemField.SHA512].Items.Add(key, item);
|
||||
}
|
||||
|
||||
// If the file has a SHA-384
|
||||
else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom).SHA384)))
|
||||
else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom)!.SHA384)))
|
||||
{
|
||||
fieldDats[DatItemField.SHA384].Items.Add(key, item);
|
||||
}
|
||||
|
||||
// If the file has a SHA-256
|
||||
else if ((item.ItemType == ItemType.Media && !string.IsNullOrWhiteSpace((item as Media).SHA256))
|
||||
|| (item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom).SHA256)))
|
||||
else if ((item.ItemType == ItemType.Media && !string.IsNullOrWhiteSpace((item as Media)!.SHA256))
|
||||
|| (item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom)!.SHA256)))
|
||||
{
|
||||
fieldDats[DatItemField.SHA256].Items.Add(key, item);
|
||||
}
|
||||
|
||||
// If the file has a SHA-1
|
||||
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)))
|
||||
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)))
|
||||
{
|
||||
fieldDats[DatItemField.SHA1].Items.Add(key, item);
|
||||
}
|
||||
|
||||
// If the file has an 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)))
|
||||
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)))
|
||||
{
|
||||
fieldDats[DatItemField.MD5].Items.Add(key, item);
|
||||
}
|
||||
|
||||
// If the file has a CRC
|
||||
else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom).CRC)))
|
||||
else if ((item.ItemType == ItemType.Rom && !string.IsNullOrWhiteSpace((item as Rom)!.CRC)))
|
||||
{
|
||||
fieldDats[DatItemField.CRC].Items.Add(key, item);
|
||||
}
|
||||
@@ -233,7 +238,7 @@ namespace SabreTools.DatTools
|
||||
tempDat.Header.Name = null;
|
||||
|
||||
// Sort the input keys
|
||||
List<string> keys = datFile.Items.Keys.ToList();
|
||||
List<string> keys = [.. datFile.Items.Keys];
|
||||
keys.Sort(SplitByLevelSort);
|
||||
|
||||
// Then, we loop over the games
|
||||
@@ -248,7 +253,10 @@ namespace SabreTools.DatTools
|
||||
}
|
||||
|
||||
// Clean the input list and set all games to be pathless
|
||||
ConcurrentList<DatItem> items = datFile.Items[key];
|
||||
ConcurrentList<DatItem>? items = datFile.Items[key];
|
||||
if (items == null)
|
||||
return;
|
||||
|
||||
items.ForEach(item => item.Machine.Name = Path.GetFileName(item.Machine.Name));
|
||||
items.ForEach(item => item.Machine.Description = Path.GetFileName(item.Machine.Description));
|
||||
|
||||
@@ -292,8 +300,8 @@ namespace SabreTools.DatTools
|
||||
private static void SplitByLevelHelper(DatFile datFile, DatFile newDatFile, string outDir, bool shortname, bool restore)
|
||||
{
|
||||
// Get the name from the DAT to use separately
|
||||
string name = newDatFile.Header.Name;
|
||||
string expName = name.Replace("/", " - ").Replace("\\", " - ");
|
||||
string? name = newDatFile.Header.Name;
|
||||
string? expName = name?.Replace("/", " - ")?.Replace("\\", " - ");
|
||||
|
||||
// Now set the new output values
|
||||
newDatFile.Header.FileName = WebUtility.HtmlDecode(string.IsNullOrWhiteSpace(name)
|
||||
@@ -336,7 +344,10 @@ namespace SabreTools.DatTools
|
||||
// Now populate each of the DAT objects in turn
|
||||
Parallel.ForEach(datFile.Items.Keys, Globals.ParallelOptions, key =>
|
||||
{
|
||||
ConcurrentList<DatItem> items = datFile.Items[key];
|
||||
ConcurrentList<DatItem>? items = datFile.Items[key];
|
||||
if (items == null)
|
||||
return;
|
||||
|
||||
foreach (DatItem item in items)
|
||||
{
|
||||
// If the file is not a Rom, it automatically goes in the "lesser" dat
|
||||
@@ -344,15 +355,15 @@ namespace SabreTools.DatTools
|
||||
lessThan.Items.Add(key, item);
|
||||
|
||||
// If the file is a Rom and has no size, put it in the "lesser" dat
|
||||
else if (item.ItemType == ItemType.Rom && (item as Rom).Size == null)
|
||||
else if (item.ItemType == ItemType.Rom && (item as Rom)!.Size == null)
|
||||
lessThan.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 && (item as Rom).Size < radix)
|
||||
else if (item.ItemType == ItemType.Rom && (item as Rom)!.Size < radix)
|
||||
lessThan.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 && (item as Rom).Size >= radix)
|
||||
else if (item.ItemType == ItemType.Rom && (item as Rom)!.Size >= radix)
|
||||
greaterThan.Items.Add(key, item);
|
||||
}
|
||||
});
|
||||
@@ -372,7 +383,7 @@ namespace SabreTools.DatTools
|
||||
{
|
||||
// If the size is invalid, just return
|
||||
if (chunkSize <= 0)
|
||||
return new List<DatFile>();
|
||||
return [];
|
||||
|
||||
// Create each of the respective output DATs
|
||||
InternalStopwatch watch = new($"Splitting DAT by total size");
|
||||
@@ -384,7 +395,7 @@ namespace SabreTools.DatTools
|
||||
var keys = datFile.Items.SortedKeys;
|
||||
|
||||
// Get the output list
|
||||
List<DatFile> datFiles = new();
|
||||
List<DatFile> datFiles = [];
|
||||
|
||||
// Initialize everything
|
||||
long currentSize = 0;
|
||||
@@ -462,16 +473,16 @@ namespace SabreTools.DatTools
|
||||
InternalStopwatch watch = new($"Splitting DAT by item type");
|
||||
|
||||
// Create the set of type-to-dat mappings
|
||||
Dictionary<ItemType, DatFile> typeDats = new();
|
||||
Dictionary<ItemType, DatFile> typeDats = [];
|
||||
|
||||
// We only care about a subset of types
|
||||
List<ItemType> outputTypes = new()
|
||||
{
|
||||
List<ItemType> outputTypes =
|
||||
[
|
||||
ItemType.Disk,
|
||||
ItemType.Media,
|
||||
ItemType.Rom,
|
||||
ItemType.Sample,
|
||||
};
|
||||
];
|
||||
|
||||
// Setup all of the DatFiles
|
||||
foreach (ItemType itemType in outputTypes)
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using SabreTools.Core;
|
||||
using SabreTools.DatFiles;
|
||||
using SabreTools.IO;
|
||||
@@ -16,7 +15,7 @@ namespace SabreTools.DatTools
|
||||
/// <summary>
|
||||
/// Helper methods for dealing with DatFile statistics
|
||||
/// </summary>
|
||||
|
||||
|
||||
public class Statistics
|
||||
{
|
||||
#region Logging
|
||||
@@ -37,7 +36,7 @@ namespace SabreTools.DatTools
|
||||
public static List<DatStatistics> CalculateStatistics(List<string> inputs, bool single, bool throwOnError = false)
|
||||
{
|
||||
// Create the output list
|
||||
List<DatStatistics> stats = new();
|
||||
List<DatStatistics> stats = [];
|
||||
|
||||
// Make sure we have all files and then order them
|
||||
List<ParentablePath> files = PathTool.GetFilesOnly(inputs);
|
||||
@@ -49,17 +48,17 @@ namespace SabreTools.DatTools
|
||||
// Init total
|
||||
DatStatistics totalStats = new()
|
||||
{
|
||||
Statistics = new ItemDictionary(),
|
||||
Statistics = [],
|
||||
DisplayName = "DIR: All DATs",
|
||||
MachineCount = 0,
|
||||
IsDirectory = true,
|
||||
};
|
||||
|
||||
// Init directory-level variables
|
||||
string lastdir = null;
|
||||
string? lastdir = null;
|
||||
DatStatistics dirStats = new()
|
||||
{
|
||||
Statistics = new ItemDictionary(),
|
||||
Statistics = [],
|
||||
MachineCount = 0,
|
||||
IsDirectory = true,
|
||||
};
|
||||
@@ -68,7 +67,7 @@ namespace SabreTools.DatTools
|
||||
foreach (ParentablePath file in files)
|
||||
{
|
||||
// Get the directory for the current file
|
||||
string thisdir = Path.GetDirectoryName(file.CurrentPath);
|
||||
string? thisdir = Path.GetDirectoryName(file.CurrentPath);
|
||||
|
||||
// If we don't have the first file and the directory has changed, show the previous directory stats and reset
|
||||
if (lastdir != null && thisdir != lastdir && single)
|
||||
@@ -78,7 +77,7 @@ namespace SabreTools.DatTools
|
||||
stats.Add(dirStats);
|
||||
dirStats = new DatStatistics
|
||||
{
|
||||
Statistics = new ItemDictionary(),
|
||||
Statistics = [],
|
||||
MachineCount = 0,
|
||||
IsDirectory = true,
|
||||
};
|
||||
@@ -86,7 +85,7 @@ namespace SabreTools.DatTools
|
||||
|
||||
InternalStopwatch watch = new($"Collecting statistics for '{file.CurrentPath}'");
|
||||
|
||||
List<string> machines = new();
|
||||
List<string> machines = [];
|
||||
DatFile datdata = Parser.CreateAndParse(file.CurrentPath, statsOnly: true, throwOnError: throwOnError);
|
||||
|
||||
// Add single DAT stats (if asked)
|
||||
@@ -208,7 +207,7 @@ namespace SabreTools.DatTools
|
||||
/// <returns>Dictionary of output formats mapped to file names</returns>
|
||||
private static Dictionary<StatReportFormat, string> CreateOutStatsNames(string outDir, StatReportFormat statDatFormat, string reportName, bool overwrite = true)
|
||||
{
|
||||
Dictionary<StatReportFormat, string> output = new();
|
||||
Dictionary<StatReportFormat, string> output = [];
|
||||
|
||||
// First try to create the output directory if we need to
|
||||
if (!Directory.Exists(outDir))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using SabreTools.Core;
|
||||
using SabreTools.Core.Tools;
|
||||
using SabreTools.DatFiles;
|
||||
@@ -40,7 +39,7 @@ namespace SabreTools.DatTools
|
||||
InternalStopwatch watch = new("Verifying all from supplied depots");
|
||||
|
||||
// Now loop through and get only directories from the input paths
|
||||
List<string> directories = new();
|
||||
List<string> directories = [];
|
||||
foreach (string input in inputs)
|
||||
{
|
||||
// Add to the list if the input is a directory
|
||||
@@ -69,10 +68,12 @@ namespace SabreTools.DatTools
|
||||
logger.User($"Checking hash '{hash}'");
|
||||
|
||||
// Get the extension path for the hash
|
||||
string subpath = Utilities.GetDepotPath(hash, datFile.Header.InputDepot.Depth);
|
||||
string? subpath = Utilities.GetDepotPath(hash, datFile.Header.InputDepot?.Depth ?? 0);
|
||||
if (subpath == null)
|
||||
continue;
|
||||
|
||||
// Find the first depot that includes the hash
|
||||
string foundpath = null;
|
||||
string? foundpath = null;
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
if (System.IO.File.Exists(Path.Combine(directory, subpath)))
|
||||
@@ -88,7 +89,7 @@ namespace SabreTools.DatTools
|
||||
|
||||
// If we have a path, we want to try to get the rom information
|
||||
GZipArchive tgz = new(foundpath);
|
||||
BaseFile fileinfo = tgz.GetTorrentGZFileInfo();
|
||||
BaseFile? fileinfo = tgz.GetTorrentGZFileInfo();
|
||||
|
||||
// If the file information is null, then we continue
|
||||
if (fileinfo == null)
|
||||
@@ -133,11 +134,14 @@ namespace SabreTools.DatTools
|
||||
var keys = datFile.Items.SortedKeys.ToList();
|
||||
foreach (string key in keys)
|
||||
{
|
||||
ConcurrentList<DatItem> items = datFile.Items[key];
|
||||
ConcurrentList<DatItem>? items = datFile.Items[key];
|
||||
if (items == null)
|
||||
continue;
|
||||
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
// Unmatched items will have a source ID of int.MaxValue, remove all others
|
||||
if (items[i].Source.Index != int.MaxValue)
|
||||
if (items[i].Source?.Index != int.MaxValue)
|
||||
items[i].Remove = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace SabreTools.DatTools
|
||||
|
||||
var statsList = new List<DatStatistics>
|
||||
{
|
||||
new DatStatistics
|
||||
new()
|
||||
{
|
||||
Statistics = datFile.Items,
|
||||
DisplayName = datFile.Header.FileName,
|
||||
@@ -127,7 +127,7 @@ namespace SabreTools.DatTools
|
||||
},
|
||||
};
|
||||
var consoleOutput = BaseReport.Create(StatReportFormat.None, statsList);
|
||||
consoleOutput.WriteToFile(null, true, true);
|
||||
consoleOutput!.WriteToFile(null, true, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user