2025-02-19 14:42:41 -05:00
|
|
|
using System;
|
2020-12-09 21:52:38 -08:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
2024-03-05 03:04:47 -05:00
|
|
|
#if NET40_OR_GREATER || NETCOREAPP
|
2020-12-09 21:52:38 -08:00
|
|
|
using System.Threading.Tasks;
|
2024-03-05 03:04:47 -05:00
|
|
|
#endif
|
2024-03-11 16:26:28 -04:00
|
|
|
using SabreTools.Core.Tools;
|
2020-12-10 23:24:09 -08:00
|
|
|
using SabreTools.DatFiles;
|
2020-12-09 21:52:38 -08:00
|
|
|
using SabreTools.DatItems;
|
2021-02-02 10:23:43 -08:00
|
|
|
using SabreTools.DatItems.Formats;
|
2020-12-09 21:52:38 -08:00
|
|
|
using SabreTools.FileTypes;
|
2020-12-10 22:31:23 -08:00
|
|
|
using SabreTools.FileTypes.Archives;
|
2024-03-04 23:56:05 -05:00
|
|
|
using SabreTools.Hashing;
|
2024-04-24 13:45:38 -04:00
|
|
|
using SabreTools.IO.Extensions;
|
2024-10-24 00:36:44 -04:00
|
|
|
using SabreTools.IO.Logging;
|
2020-12-09 21:52:38 -08:00
|
|
|
|
2020-12-10 23:24:09 -08:00
|
|
|
namespace SabreTools.DatTools
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
2020-12-10 14:11:35 -08:00
|
|
|
/// <summary>
|
|
|
|
|
/// This file represents all methods related to populating a DatFile
|
|
|
|
|
/// from a set of files and directories
|
|
|
|
|
/// </summary>
|
2020-12-10 15:42:39 -08:00
|
|
|
public class DatFromDir
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
2024-10-24 05:52:48 -04:00
|
|
|
#region Fields
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Hashes to include in the information
|
|
|
|
|
/// </summary>
|
|
|
|
|
private readonly HashType[] _hashes;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Type of files that should be skipped
|
|
|
|
|
/// </summary>
|
|
|
|
|
private readonly SkipFileType _skipFileType;
|
|
|
|
|
|
2025-02-19 22:24:00 -05:00
|
|
|
/// <summary>
|
|
|
|
|
/// TreatAsFile representing CHD and Archive scanning</param>
|
|
|
|
|
/// </summary>
|
|
|
|
|
private readonly TreatAsFile _treatAsFile;
|
|
|
|
|
|
2024-10-24 05:52:48 -04:00
|
|
|
/// <summary>
|
|
|
|
|
/// Indicates if blank items should be created for empty folders
|
|
|
|
|
/// </summary>
|
|
|
|
|
private readonly bool _addBlanks;
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2020-12-10 13:30:08 -08:00
|
|
|
#region Logging
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Logging object
|
|
|
|
|
/// </summary>
|
2025-01-08 16:59:44 -05:00
|
|
|
private static readonly Logger _staticLogger = new();
|
2020-12-10 13:30:08 -08:00
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2024-10-24 05:52:48 -04:00
|
|
|
#region Constructors
|
|
|
|
|
|
2025-02-19 22:24:00 -05:00
|
|
|
public DatFromDir(HashType[] hashes, SkipFileType skipFileType, TreatAsFile treatAsFile, bool addBlanks)
|
2024-10-24 05:52:48 -04:00
|
|
|
{
|
2025-02-19 14:42:41 -05:00
|
|
|
if (hashes.Length == 0)
|
|
|
|
|
throw new ArgumentException($"{nameof(hashes)} must contain at least one valid HashType");
|
|
|
|
|
|
2025-02-19 14:41:12 -05:00
|
|
|
_hashes = hashes;
|
2024-10-24 05:52:48 -04:00
|
|
|
_skipFileType = skipFileType;
|
2025-02-19 22:24:00 -05:00
|
|
|
_treatAsFile = treatAsFile;
|
2024-10-24 05:52:48 -04:00
|
|
|
_addBlanks = addBlanks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2020-12-09 21:52:38 -08:00
|
|
|
/// <summary>
|
|
|
|
|
/// Create a new Dat from a directory
|
|
|
|
|
/// </summary>
|
2020-12-10 10:39:39 -08:00
|
|
|
/// <param name="datFile">Current DatFile object to add to</param>
|
2020-12-09 21:52:38 -08:00
|
|
|
/// <param name="basePath">Base folder to be used in creating the DAT</param>
|
2025-02-19 22:24:00 -05:00
|
|
|
public bool PopulateFromDir(DatFile datFile, string basePath)
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
2023-04-19 16:39:58 -04:00
|
|
|
InternalStopwatch watch = new($"Populating DAT from {basePath}");
|
2021-02-02 14:09:49 -08:00
|
|
|
|
2020-12-09 21:52:38 -08:00
|
|
|
// Process the input
|
|
|
|
|
if (Directory.Exists(basePath))
|
|
|
|
|
{
|
2025-01-08 16:59:44 -05:00
|
|
|
_staticLogger.Verbose($"Folder found: {basePath}");
|
2020-12-09 21:52:38 -08:00
|
|
|
|
|
|
|
|
// Get a list of all files to process
|
2025-02-19 14:44:46 -05:00
|
|
|
string[] files = IOExtensions.SafeGetFiles(basePath, "*", SearchOption.AllDirectories);
|
2020-12-09 21:52:38 -08:00
|
|
|
|
2025-02-19 15:00:11 -05:00
|
|
|
// Set intiial progress values
|
|
|
|
|
long totalCount = files.Length;
|
|
|
|
|
long currentCount = 0;
|
|
|
|
|
_staticLogger.User(totalCount, currentCount);
|
2020-12-09 21:52:38 -08:00
|
|
|
|
|
|
|
|
// Process the files in the main folder or any subfolder
|
|
|
|
|
foreach (string item in files)
|
|
|
|
|
{
|
2025-02-19 15:00:11 -05:00
|
|
|
currentCount++;
|
2025-02-19 22:24:00 -05:00
|
|
|
CheckFileForHashes(datFile, item, basePath);
|
2025-02-19 15:00:11 -05:00
|
|
|
|
|
|
|
|
_staticLogger.User(totalCount, currentCount, item);
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now find all folders that are empty, if we are supposed to
|
2024-10-24 05:52:48 -04:00
|
|
|
if (_addBlanks)
|
2020-12-10 10:39:39 -08:00
|
|
|
ProcessDirectoryBlanks(datFile, basePath);
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
2023-04-17 13:22:35 -04:00
|
|
|
else if (System.IO.File.Exists(basePath))
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
2025-01-08 16:59:44 -05:00
|
|
|
_staticLogger.Verbose($"File found: {basePath}");
|
2020-12-09 21:52:38 -08:00
|
|
|
|
2025-02-19 15:00:11 -05:00
|
|
|
// Set intiial progress values
|
|
|
|
|
long totalCount = 1;
|
|
|
|
|
_staticLogger.User(totalCount, 0);
|
2020-12-09 21:52:38 -08:00
|
|
|
|
2025-02-19 15:01:06 -05:00
|
|
|
// Process the input file
|
2024-02-28 19:19:50 -05:00
|
|
|
string? parentPath = Path.GetDirectoryName(Path.GetDirectoryName(basePath));
|
2025-02-19 22:24:00 -05:00
|
|
|
CheckFileForHashes(datFile, basePath, parentPath);
|
2025-02-19 15:00:11 -05:00
|
|
|
|
|
|
|
|
_staticLogger.User(totalCount, totalCount, basePath);
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
2025-02-19 15:19:35 -05:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_staticLogger.Verbose($"Invalid path found: {basePath}");
|
|
|
|
|
}
|
2020-12-09 21:52:38 -08:00
|
|
|
|
2021-02-02 14:09:49 -08:00
|
|
|
watch.Stop();
|
2020-12-09 21:52:38 -08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Check a given file for hashes, based on current settings
|
|
|
|
|
/// </summary>
|
2020-12-10 10:39:39 -08:00
|
|
|
/// <param name="datFile">Current DatFile object to add to</param>
|
2020-12-09 21:52:38 -08:00
|
|
|
/// <param name="item">Filename of the item to be checked</param>
|
|
|
|
|
/// <param name="basePath">Base folder to be used in creating the DAT</param>
|
2025-01-05 21:51:35 -05:00
|
|
|
/// <param name="asFile">TreatAsFile representing CHD and Archive scanning</param>
|
2025-02-19 22:24:00 -05:00
|
|
|
private void CheckFileForHashes(DatFile datFile, string item, string? basePath)
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
// If we're in depot mode, process it separately
|
2020-12-10 10:39:39 -08:00
|
|
|
if (CheckDepotFile(datFile, item))
|
2020-12-09 21:52:38 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Initialize possible archive variables
|
2025-01-04 21:17:02 -05:00
|
|
|
BaseArchive? archive = FileTypeTool.CreateArchiveType(item);
|
2020-12-09 21:52:38 -08:00
|
|
|
|
|
|
|
|
// Process archives according to flags
|
|
|
|
|
if (archive != null)
|
|
|
|
|
{
|
|
|
|
|
// Set the archive flags
|
2025-01-04 21:17:02 -05:00
|
|
|
archive.SetHashTypes(_hashes);
|
2020-12-09 21:52:38 -08:00
|
|
|
|
|
|
|
|
// Skip if we're treating archives as files and skipping files
|
2024-12-28 20:15:32 -05:00
|
|
|
#if NET20 || NET35
|
2025-02-19 22:24:00 -05:00
|
|
|
if ((_treatAsFile & TreatAsFile.Archive) != 0 && _skipFileType == SkipFileType.File)
|
2024-02-28 22:54:56 -05:00
|
|
|
#else
|
2025-02-19 22:24:00 -05:00
|
|
|
if (_treatAsFile.HasFlag(TreatAsFile.Archive) && _skipFileType == SkipFileType.File)
|
2024-02-28 22:54:56 -05:00
|
|
|
#endif
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skip if we're skipping archives
|
2024-10-24 05:52:48 -04:00
|
|
|
else if (_skipFileType == SkipFileType.Archive)
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Process as archive if we're not treating archives as files
|
2024-12-28 20:15:32 -05:00
|
|
|
#if NET20 || NET35
|
2025-02-19 22:24:00 -05:00
|
|
|
else if ((_treatAsFile & TreatAsFile.Archive) == 0)
|
2024-02-28 22:54:56 -05:00
|
|
|
#else
|
2025-02-19 22:24:00 -05:00
|
|
|
else if (!_treatAsFile.HasFlag(TreatAsFile.Archive))
|
2024-02-28 22:54:56 -05:00
|
|
|
#endif
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
var extracted = archive.GetChildren();
|
|
|
|
|
|
|
|
|
|
// If we have internal items to process, do so
|
|
|
|
|
if (extracted != null)
|
2020-12-10 10:39:39 -08:00
|
|
|
ProcessArchive(datFile, item, basePath, extracted);
|
2020-12-09 21:52:38 -08:00
|
|
|
|
|
|
|
|
// Now find all folders that are empty, if we are supposed to
|
2024-10-24 05:52:48 -04:00
|
|
|
if (_addBlanks)
|
2020-12-10 10:39:39 -08:00
|
|
|
ProcessArchiveBlanks(datFile, item, basePath, archive);
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Process as file if we're treating archives as files
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-02-19 22:24:00 -05:00
|
|
|
ProcessFile(datFile, item, basePath);
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Process non-archives according to flags
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Skip if we're skipping files
|
2024-10-24 05:52:48 -04:00
|
|
|
if (_skipFileType == SkipFileType.File)
|
2020-12-09 21:52:38 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Process as file
|
|
|
|
|
else
|
2025-02-19 22:24:00 -05:00
|
|
|
ProcessFile(datFile, item, basePath);
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Check an item as if it's supposed to be in a depot
|
|
|
|
|
/// </summary>
|
2020-12-10 10:39:39 -08:00
|
|
|
/// <param name="datFile">Current DatFile object to add to</param>
|
2020-12-09 21:52:38 -08:00
|
|
|
/// <param name="item">Filename of the item to be checked</param>
|
|
|
|
|
/// <returns>True if we checked a depot file, false otherwise</returns>
|
2020-12-10 11:58:46 -08:00
|
|
|
private static bool CheckDepotFile(DatFile datFile, string item)
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
// If we're not in Depot mode, return false
|
2025-01-29 22:51:30 -05:00
|
|
|
if (datFile.Modifiers.OutputDepot?.IsActive != true)
|
2020-12-09 21:52:38 -08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Check the file as if it were in a depot
|
2023-04-19 16:39:58 -04:00
|
|
|
GZipArchive gzarc = new(item);
|
2024-02-28 19:19:50 -05:00
|
|
|
BaseFile? baseFile = gzarc.GetTorrentGZFileInfo();
|
2020-12-09 21:52:38 -08:00
|
|
|
|
|
|
|
|
// If the rom is valid, add it
|
|
|
|
|
if (baseFile != null && baseFile.Filename != null)
|
|
|
|
|
{
|
|
|
|
|
// Add the list if it doesn't exist already
|
2025-01-06 11:18:04 -05:00
|
|
|
Rom rom = baseFile.ConvertToRom();
|
2025-01-14 15:32:14 -05:00
|
|
|
datFile.AddItem(rom, statsOnly: false);
|
2025-01-08 16:59:44 -05:00
|
|
|
_staticLogger.Verbose($"File added: {Path.GetFileNameWithoutExtension(item)}");
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-01-08 16:59:44 -05:00
|
|
|
_staticLogger.Verbose($"File not added: {Path.GetFileNameWithoutExtension(item)}");
|
2020-12-09 21:52:38 -08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Process a single file as an archive
|
|
|
|
|
/// </summary>
|
2020-12-10 10:39:39 -08:00
|
|
|
/// <param name="datFile">Current DatFile object to add to</param>
|
2020-12-09 21:52:38 -08:00
|
|
|
/// <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>
|
2024-02-28 19:19:50 -05:00
|
|
|
private static void ProcessArchive(DatFile datFile, string item, string? basePath, List<BaseFile> extracted)
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
// Get the parent path for all items
|
2024-02-28 19:19:50 -05:00
|
|
|
string parent = (Path.GetDirectoryName(Path.GetFullPath(item)) + Path.DirectorySeparatorChar).Remove(0, basePath?.Length ?? 0) + Path.GetFileNameWithoutExtension(item);
|
2020-12-09 21:52:38 -08:00
|
|
|
|
|
|
|
|
// First take care of the found items
|
2024-02-28 22:54:56 -05:00
|
|
|
#if NET452_OR_GREATER || NETCOREAPP
|
2024-10-24 05:52:48 -04:00
|
|
|
Parallel.ForEach(extracted, Core.Globals.ParallelOptions, baseFile =>
|
2024-02-28 22:54:56 -05:00
|
|
|
#elif NET40_OR_GREATER
|
|
|
|
|
Parallel.ForEach(extracted, baseFile =>
|
|
|
|
|
#else
|
|
|
|
|
foreach (var baseFile in extracted)
|
|
|
|
|
#endif
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
2025-01-05 22:16:44 -05:00
|
|
|
DatItem? datItem = DatItemTool.CreateDatItem(baseFile);
|
2024-02-28 19:19:50 -05:00
|
|
|
if (datItem == null)
|
2024-03-05 02:52:53 -05:00
|
|
|
#if NET40_OR_GREATER || NETCOREAPP
|
2024-02-28 19:19:50 -05:00
|
|
|
return;
|
2024-03-05 02:52:53 -05:00
|
|
|
#else
|
|
|
|
|
continue;
|
|
|
|
|
#endif
|
2024-02-28 19:19:50 -05:00
|
|
|
|
2020-12-10 10:39:39 -08:00
|
|
|
ProcessFileHelper(datFile, item, datItem, basePath, parent);
|
2024-02-28 21:59:13 -05:00
|
|
|
#if NET40_OR_GREATER || NETCOREAPP
|
2020-12-09 21:52:38 -08:00
|
|
|
});
|
2024-02-28 21:59:13 -05:00
|
|
|
#else
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Process blank folders in an archive
|
|
|
|
|
/// </summary>
|
2020-12-10 10:39:39 -08:00
|
|
|
/// <param name="datFile">Current DatFile object to add to</param>
|
2020-12-09 21:52:38 -08:00
|
|
|
/// <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>
|
2024-02-28 19:19:50 -05:00
|
|
|
private static void ProcessArchiveBlanks(DatFile datFile, string item, string? basePath, BaseArchive archive)
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
2024-02-28 19:19:50 -05:00
|
|
|
List<string> empties = [];
|
2020-12-09 21:52:38 -08:00
|
|
|
|
|
|
|
|
// Get the parent path for all items
|
2024-02-28 19:19:50 -05:00
|
|
|
string parent = (Path.GetDirectoryName(Path.GetFullPath(item)) + Path.DirectorySeparatorChar).Remove(0, basePath?.Length ?? 0) + Path.GetFileNameWithoutExtension(item);
|
2020-12-09 21:52:38 -08:00
|
|
|
|
|
|
|
|
// Now get all blank folders from the archive
|
|
|
|
|
if (archive != null)
|
|
|
|
|
empties = archive.GetEmptyFolders();
|
|
|
|
|
|
|
|
|
|
// Add add all of the found empties to the DAT
|
2024-02-28 22:54:56 -05:00
|
|
|
#if NET452_OR_GREATER || NETCOREAPP
|
2024-10-24 05:52:48 -04:00
|
|
|
Parallel.ForEach(empties, Core.Globals.ParallelOptions, empty =>
|
2024-02-28 22:54:56 -05:00
|
|
|
#elif NET40_OR_GREATER
|
|
|
|
|
Parallel.ForEach(empties, empty =>
|
|
|
|
|
#else
|
|
|
|
|
foreach (var empty in empties)
|
|
|
|
|
#endif
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
2024-03-10 21:08:34 -04:00
|
|
|
var emptyMachine = new Machine();
|
2025-05-02 16:05:08 -04:00
|
|
|
emptyMachine.SetName(item);
|
2024-03-10 21:08:34 -04:00
|
|
|
|
|
|
|
|
var emptyRom = new Rom();
|
|
|
|
|
emptyRom.SetName(Path.Combine(empty, "_"));
|
|
|
|
|
emptyRom.SetFieldValue<Machine?>(DatItem.MachineKey, emptyMachine);
|
|
|
|
|
|
2020-12-10 10:39:39 -08:00
|
|
|
ProcessFileHelper(datFile, item, emptyRom, basePath, parent);
|
2024-02-28 21:59:13 -05:00
|
|
|
#if NET40_OR_GREATER || NETCOREAPP
|
2020-12-09 21:52:38 -08:00
|
|
|
});
|
2024-02-28 21:59:13 -05:00
|
|
|
#else
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Process blank folders in a directory
|
|
|
|
|
/// </summary>
|
2020-12-10 10:39:39 -08:00
|
|
|
/// <param name="datFile">Current DatFile object to add to</param>
|
2020-12-09 21:52:38 -08:00
|
|
|
/// <param name="basePath">Path the represents the parent directory</param>
|
2024-02-28 19:19:50 -05:00
|
|
|
private static void ProcessDirectoryBlanks(DatFile datFile, string? basePath)
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
// If we're in depot mode, we don't process blanks
|
2025-01-29 22:51:30 -05:00
|
|
|
if (datFile.Modifiers.OutputDepot?.IsActive == true)
|
2020-12-09 21:52:38 -08:00
|
|
|
return;
|
|
|
|
|
|
2024-02-28 19:19:50 -05:00
|
|
|
List<string> empties = basePath.ListEmpty() ?? [];
|
2024-02-28 22:54:56 -05:00
|
|
|
#if NET452_OR_GREATER || NETCOREAPP
|
2024-10-24 05:52:48 -04:00
|
|
|
Parallel.ForEach(empties, Core.Globals.ParallelOptions, dir =>
|
2024-02-28 22:54:56 -05:00
|
|
|
#elif NET40_OR_GREATER
|
|
|
|
|
Parallel.ForEach(empties, dir =>
|
|
|
|
|
#else
|
|
|
|
|
foreach (var dir in empties)
|
|
|
|
|
#endif
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
// Get the full path for the directory
|
|
|
|
|
string fulldir = Path.GetFullPath(dir);
|
|
|
|
|
|
|
|
|
|
// Set the temporary variables
|
|
|
|
|
string gamename = string.Empty;
|
|
|
|
|
string romname = string.Empty;
|
|
|
|
|
|
|
|
|
|
// If we have a SuperDAT, we want anything that's not the base path as the game, and the file as the rom
|
2024-03-11 15:46:44 -04:00
|
|
|
if (datFile.Header.GetStringFieldValue(Models.Metadata.Header.TypeKey) == "SuperDAT")
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
2024-02-28 19:19:50 -05:00
|
|
|
if (basePath != null)
|
|
|
|
|
gamename = fulldir.Remove(0, basePath.Length + 1);
|
|
|
|
|
else
|
|
|
|
|
gamename = fulldir;
|
|
|
|
|
|
2020-12-09 21:52:38 -08:00
|
|
|
romname = "_";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise, we want just the top level folder as the game, and the file as everything else
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-02-28 19:19:50 -05:00
|
|
|
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, "_");
|
|
|
|
|
}
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sanitize the names
|
|
|
|
|
gamename = gamename.Trim(Path.DirectorySeparatorChar);
|
|
|
|
|
romname = romname.Trim(Path.DirectorySeparatorChar);
|
|
|
|
|
|
2025-01-08 16:59:44 -05:00
|
|
|
_staticLogger.Verbose($"Adding blank empty folder: {gamename}");
|
2024-03-10 21:08:34 -04:00
|
|
|
|
|
|
|
|
var blankMachine = new Machine();
|
2025-05-02 16:05:08 -04:00
|
|
|
blankMachine.SetName(gamename);
|
2024-03-10 21:08:34 -04:00
|
|
|
|
2024-10-22 13:05:51 -04:00
|
|
|
var blankRom = new Blank();
|
2024-03-10 21:08:34 -04:00
|
|
|
blankRom.SetName(romname);
|
|
|
|
|
blankRom.SetFieldValue<Machine?>(DatItem.MachineKey, blankMachine);
|
|
|
|
|
|
2025-01-14 15:32:14 -05:00
|
|
|
datFile.AddItem(blankRom, statsOnly: false);
|
2024-02-28 21:59:13 -05:00
|
|
|
#if NET40_OR_GREATER || NETCOREAPP
|
2020-12-09 21:52:38 -08:00
|
|
|
});
|
2024-02-28 21:59:13 -05:00
|
|
|
#else
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Process a single file as a file
|
|
|
|
|
/// </summary>
|
2020-12-10 10:39:39 -08:00
|
|
|
/// <param name="datFile">Current DatFile object to add to</param>
|
2020-12-09 21:52:38 -08:00
|
|
|
/// <param name="item">File to be added</param>
|
|
|
|
|
/// <param name="basePath">Path the represents the parent directory</param>
|
2025-01-05 21:51:35 -05:00
|
|
|
/// <param name="asFile">TreatAsFile representing CHD and Archive scanning</param>
|
2025-02-19 22:24:00 -05:00
|
|
|
private void ProcessFile(DatFile datFile, string item, string? basePath)
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
2025-01-08 16:59:44 -05:00
|
|
|
_staticLogger.Verbose($"'{Path.GetFileName(item)}' treated like a file");
|
2024-10-24 05:52:48 -04:00
|
|
|
var header = datFile.Header.GetStringFieldValue(Models.Metadata.Header.HeaderKey);
|
2025-01-05 22:19:42 -05:00
|
|
|
BaseFile? baseFile = FileTypeTool.GetInfo(item, _hashes, header);
|
2025-02-19 22:24:00 -05:00
|
|
|
DatItem? datItem = DatItemTool.CreateDatItem(baseFile, _treatAsFile);
|
2024-02-28 19:19:50 -05:00
|
|
|
if (datItem != null)
|
|
|
|
|
ProcessFileHelper(datFile, item, datItem, basePath, string.Empty);
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Process a single file as a file (with found Rom data)
|
|
|
|
|
/// </summary>
|
2020-12-10 10:39:39 -08:00
|
|
|
/// <param name="datFile">Current DatFile object to add to</param>
|
2020-12-09 21:52:38 -08:00
|
|
|
/// <param name="item">File to be added</param>
|
|
|
|
|
/// <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>
|
2024-02-28 19:19:50 -05:00
|
|
|
private static void ProcessFileHelper(DatFile datFile, string item, DatItem datItem, string? basepath, string parent)
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
// If we didn't get an accepted parsed type somehow, cancel out
|
2024-02-28 19:19:50 -05:00
|
|
|
List<ItemType> parsed = [ItemType.Disk, ItemType.File, ItemType.Media, ItemType.Rom];
|
2025-05-11 22:55:38 -04:00
|
|
|
if (!parsed.Contains(datItem.GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsItemType()))
|
2020-12-09 21:52:38 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// If the basepath doesn't end with a directory separator, add it
|
2024-02-28 19:19:50 -05:00
|
|
|
if (basepath != null && !basepath.EndsWith(Path.DirectorySeparatorChar.ToString()))
|
2020-12-09 21:52:38 -08:00
|
|
|
basepath += Path.DirectorySeparatorChar.ToString();
|
|
|
|
|
|
|
|
|
|
// Make sure we have the full item path
|
|
|
|
|
item = Path.GetFullPath(item);
|
|
|
|
|
|
|
|
|
|
// Process the item to sanitize names based on input
|
2020-12-10 10:39:39 -08:00
|
|
|
SetDatItemInfo(datFile, datItem, item, parent, basepath);
|
2020-12-09 21:52:38 -08:00
|
|
|
|
|
|
|
|
// Add the file information to the DAT
|
2025-01-14 15:32:14 -05:00
|
|
|
datFile.AddItem(datItem, statsOnly: false);
|
2020-12-09 21:52:38 -08:00
|
|
|
|
2025-01-08 16:59:44 -05:00
|
|
|
_staticLogger.Verbose($"File added: {datItem.GetName() ?? string.Empty}");
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
catch (IOException ex)
|
|
|
|
|
{
|
2025-01-08 16:59:44 -05:00
|
|
|
_staticLogger.Error(ex);
|
2020-12-09 21:52:38 -08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set proper Game and Rom names from user inputs
|
|
|
|
|
/// </summary>
|
2020-12-10 10:39:39 -08:00
|
|
|
/// <param name="datFile">Current DatFile object to add to</param>
|
2020-12-09 21:52:38 -08:00
|
|
|
/// <param name="datItem">DatItem representing the input file</param>
|
|
|
|
|
/// <param name="item">Item name to use</param>
|
|
|
|
|
/// <param name="parent">Parent name to use</param>
|
|
|
|
|
/// <param name="basepath">Base path to use</param>
|
2024-02-28 19:19:50 -05:00
|
|
|
private static void SetDatItemInfo(DatFile datFile, DatItem datItem, string item, string parent, string? basepath)
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
// Get the data to be added as game and item names
|
2024-02-28 19:19:50 -05:00
|
|
|
string? machineName, itemName;
|
2020-12-09 21:52:38 -08:00
|
|
|
|
|
|
|
|
// If the parent is blank, then we have a non-archive file
|
2024-02-29 00:14:16 -05:00
|
|
|
if (string.IsNullOrEmpty(parent))
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
// If we have a SuperDAT, we want anything that's not the base path as the game, and the file as the rom
|
2024-03-11 15:46:44 -04:00
|
|
|
if (datFile.Header.GetStringFieldValue(Models.Metadata.Header.TypeKey) == "SuperDAT")
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
2024-02-28 19:19:50 -05:00
|
|
|
machineName = Path.GetDirectoryName(item.Remove(0, basepath?.Length ?? 0));
|
2020-12-09 21:52:38 -08:00
|
|
|
itemName = Path.GetFileName(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise, we want just the top level folder as the game, and the file as everything else
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-02-28 19:19:50 -05:00
|
|
|
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));
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise, we assume that we have an archive
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// If we have a SuperDAT, we want the archive name as the game, and the file as everything else (?)
|
2024-03-11 15:46:44 -04:00
|
|
|
if (datFile.Header.GetStringFieldValue(Models.Metadata.Header.TypeKey) == "SuperDAT")
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
machineName = parent;
|
|
|
|
|
itemName = datItem.GetName();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise, we want the archive name as the game, and the file as everything else
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
machineName = parent;
|
|
|
|
|
itemName = datItem.GetName();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sanitize the names
|
2024-02-28 19:19:50 -05:00
|
|
|
machineName = machineName?.Trim(Path.DirectorySeparatorChar);
|
2020-12-09 21:52:38 -08:00
|
|
|
itemName = itemName?.Trim(Path.DirectorySeparatorChar) ?? string.Empty;
|
|
|
|
|
|
2024-02-29 00:14:16 -05:00
|
|
|
if (!string.IsNullOrEmpty(machineName) && string.IsNullOrEmpty(itemName))
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
|
|
|
|
itemName = machineName;
|
|
|
|
|
machineName = "Default";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update machine information
|
2025-05-02 16:46:20 -04:00
|
|
|
datItem.GetMachine()!.SetFieldValue<string?>(Models.Metadata.Machine.DescriptionKey, machineName);
|
|
|
|
|
datItem.GetMachine()!.SetName(machineName);
|
2020-12-09 21:52:38 -08:00
|
|
|
|
|
|
|
|
// If we have a Disk, then the ".chd" extension needs to be removed
|
2024-03-10 16:49:07 -04:00
|
|
|
if (datItem is Disk && itemName!.EndsWith(".chd"))
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
2024-02-29 00:14:16 -05:00
|
|
|
itemName = itemName.Substring(0, itemName.Length - 4);
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we have a Media, then the extension needs to be removed
|
2024-03-10 16:49:07 -04:00
|
|
|
else if (datItem is Media)
|
2020-12-09 21:52:38 -08:00
|
|
|
{
|
2024-02-29 00:14:16 -05:00
|
|
|
if (itemName!.EndsWith(".dicf"))
|
|
|
|
|
itemName = itemName.Substring(0, itemName.Length - 5);
|
2020-12-09 21:52:38 -08:00
|
|
|
else if (itemName.EndsWith(".aaru"))
|
2024-02-29 00:14:16 -05:00
|
|
|
itemName = itemName.Substring(0, itemName.Length - 5);
|
2020-12-09 21:52:38 -08:00
|
|
|
else if (itemName.EndsWith(".aaruformat"))
|
2024-02-29 00:14:16 -05:00
|
|
|
itemName = itemName.Substring(0, itemName.Length - 11);
|
2020-12-09 21:52:38 -08:00
|
|
|
else if (itemName.EndsWith(".aaruf"))
|
2024-02-29 00:14:16 -05:00
|
|
|
itemName = itemName.Substring(0, itemName.Length - 6);
|
2020-12-09 21:52:38 -08:00
|
|
|
else if (itemName.EndsWith(".aif"))
|
2024-02-29 00:14:16 -05:00
|
|
|
itemName = itemName.Substring(0, itemName.Length - 4);
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set the item name back
|
2020-12-14 10:58:43 -08:00
|
|
|
datItem.SetName(itemName);
|
2020-12-09 21:52:38 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|