mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
Add split by total size
This commit is contained in:
@@ -721,6 +721,15 @@ Features and Options:
|
||||
first DAT, and everything greater than or equal goes in the
|
||||
second.
|
||||
|
||||
-tis, --total-size Split DAT(s) or folder by total game sizes
|
||||
For a DAT, or set of DATs, allow for splitting based on the combined
|
||||
sizes of the games, splitting into individual chunks.
|
||||
|
||||
-cs=, --chunk-size= Set a chunk size to output
|
||||
Set the total game size to cut off at for each chunked DAT. It is
|
||||
recommended to use a sufficiently large size such as 1GB or else
|
||||
you may run into issues.
|
||||
|
||||
-ts, --type Split DAT(s) or folder by file types (rom/disk)
|
||||
For a DAT, or set of DATs, allow for splitting based on the types of
|
||||
the files, specifically if the type is a rom or a disk.
|
||||
|
||||
@@ -353,6 +353,79 @@ namespace SabreTools.DatTools
|
||||
return (lessThan, greaterThan);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Split a DAT by size of Rom
|
||||
/// </summary>
|
||||
/// <param name="datFile">Current DatFile object to split</param>
|
||||
/// <param name="chunkSize">Long value representing the total size to split at</param>
|
||||
/// <returns>Less Than and Greater Than DatFiles</returns>
|
||||
public static List<DatFile> SplitByTotalSize(DatFile datFile, long chunkSize)
|
||||
{
|
||||
// If the size is invalid, just return
|
||||
if (chunkSize <= 0)
|
||||
return new List<DatFile>();
|
||||
|
||||
// Create each of the respective output DATs
|
||||
InternalStopwatch watch = new InternalStopwatch($"Splitting DAT by total size");
|
||||
|
||||
// Sort the DatFile by machine name
|
||||
datFile.Items.BucketBy(ItemKey.Machine, DedupeType.None);
|
||||
|
||||
// Get the keys in a known order for easier sorting
|
||||
var keys = datFile.Items.SortedKeys;
|
||||
|
||||
// Get the output list
|
||||
List<DatFile> datFiles = new List<DatFile>();
|
||||
|
||||
// Initialize everything
|
||||
long currentSize = 0;
|
||||
long currentIndex = 0;
|
||||
DatFile currentDat = DatFile.Create(datFile.Header.CloneStandard());
|
||||
currentDat.Header.FileName += $"_{currentIndex}";
|
||||
currentDat.Header.Name += $"_{currentIndex}";
|
||||
currentDat.Header.Description += $"_{currentIndex}";
|
||||
|
||||
// Loop through each machine
|
||||
foreach (string machine in keys)
|
||||
{
|
||||
// Get the current machine
|
||||
var items = datFile.Items[machine];
|
||||
if (items == null || !items.Any())
|
||||
continue;
|
||||
|
||||
// Get the total size of the current machine
|
||||
long machineSize = 0;
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item is Rom rom)
|
||||
machineSize += rom.Size ?? 0;
|
||||
}
|
||||
|
||||
// If the current machine size makes the current DatFile too big, split
|
||||
if (currentSize + machineSize > chunkSize)
|
||||
{
|
||||
datFiles.Add(currentDat);
|
||||
currentSize = 0;
|
||||
currentIndex++;
|
||||
currentDat = DatFile.Create(datFile.Header.CloneStandard());
|
||||
currentDat.Header.FileName += $"_{currentIndex}";
|
||||
currentDat.Header.Name += $"_{currentIndex}";
|
||||
currentDat.Header.Description += $"_{currentIndex}";
|
||||
}
|
||||
|
||||
// Add the current machine to the current DatFile
|
||||
currentDat.Items[machine] = items;
|
||||
currentSize += machineSize;
|
||||
}
|
||||
|
||||
// Add the final DatFile to the list
|
||||
datFiles.Add(currentDat);
|
||||
|
||||
// Then return the list
|
||||
watch.Stop();
|
||||
return datFiles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Split a DAT by type of DatItem
|
||||
/// </summary>
|
||||
|
||||
@@ -38,10 +38,11 @@ namespace SabreTools.Features
|
||||
None = 0x00,
|
||||
|
||||
Extension = 1 << 0,
|
||||
Hash = 1 << 2,
|
||||
Level = 1 << 3,
|
||||
Type = 1 << 4,
|
||||
Size = 1 << 5,
|
||||
Hash = 1 << 1,
|
||||
Level = 1 << 2,
|
||||
Type = 1 << 3,
|
||||
Size = 1 << 4,
|
||||
TotalSize = 1 << 5,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1080,6 +1081,20 @@ namespace SabreTools.Features
|
||||
}
|
||||
}
|
||||
|
||||
internal const string TotalSizeValue = "total-size";
|
||||
internal static Feature TotalSizeFlag
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Feature(
|
||||
TotalSizeValue,
|
||||
new List<string>() { "-tis", "--total-size" },
|
||||
"Split DAT(s) or folder by total game sizes",
|
||||
ParameterType.Flag,
|
||||
longDescription: "For a DAT, or set of DATs, allow for splitting based on the combined sizes of the games, splitting into individual chunks.");
|
||||
}
|
||||
}
|
||||
|
||||
internal const string TrimValue = "trim";
|
||||
internal static Feature TrimFlag
|
||||
{
|
||||
@@ -1172,6 +1187,20 @@ namespace SabreTools.Features
|
||||
|
||||
#region Int64 features
|
||||
|
||||
internal const string ChunkSizeInt64Value = "chunk-size";
|
||||
internal static Feature ChunkSizeInt64Input
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Feature(
|
||||
ChunkSizeInt64Value,
|
||||
new List<string>() { "-cs", "--chunk-size" },
|
||||
"Set a chunk size to output",
|
||||
ParameterType.Int64,
|
||||
longDescription: "Set the total game size to cut off at for each chunked DAT. It is recommended to use a sufficiently large size such as 1GB or else you may run into issues.");
|
||||
}
|
||||
}
|
||||
|
||||
internal const string RadixInt64Value = "radix";
|
||||
internal static Feature RadixInt64Input
|
||||
{
|
||||
@@ -1958,6 +1987,8 @@ Some special strings that can be used:
|
||||
splittingMode |= SplittingMode.Level;
|
||||
if (GetBoolean(features, SizeValue))
|
||||
splittingMode |= SplittingMode.Size;
|
||||
if (GetBoolean(features, TotalSizeValue))
|
||||
splittingMode |= SplittingMode.TotalSize;
|
||||
if (GetBoolean(features, TypeValue))
|
||||
splittingMode |= SplittingMode.Type;
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace SabreTools.Features
|
||||
this[LevelFlag].AddFeature(BaseFlag);
|
||||
AddFeature(SizeFlag);
|
||||
this[SizeFlag].AddFeature(RadixInt64Input);
|
||||
AddFeature(TotalSizeFlag);
|
||||
this[TotalSizeFlag].AddFeature(ChunkSizeInt64Input);
|
||||
AddFeature(TypeFlag);
|
||||
}
|
||||
|
||||
@@ -120,6 +122,23 @@ namespace SabreTools.Features
|
||||
watch.Stop();
|
||||
}
|
||||
|
||||
// Total Size splitting
|
||||
if (splittingMode.HasFlag(SplittingMode.TotalSize))
|
||||
{
|
||||
logger.Warning("This feature is not implemented: level-split");
|
||||
List<DatFile> sizedDats = DatTools.Splitter.SplitByTotalSize(internalDat, GetInt64(features, ChunkSizeInt64Value));
|
||||
|
||||
InternalStopwatch watch = new InternalStopwatch("Outputting total-size-split DATs");
|
||||
|
||||
// Loop through each type DatFile
|
||||
Parallel.ForEach(sizedDats, Globals.ParallelOptions, sizedDat =>
|
||||
{
|
||||
Writer.Write(sizedDat, OutputDir);
|
||||
});
|
||||
|
||||
watch.Stop();
|
||||
}
|
||||
|
||||
// Type splitting
|
||||
if (splittingMode.HasFlag(SplittingMode.Type))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user