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
|
first DAT, and everything greater than or equal goes in the
|
||||||
second.
|
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)
|
-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
|
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.
|
the files, specifically if the type is a rom or a disk.
|
||||||
|
|||||||
@@ -353,6 +353,79 @@ namespace SabreTools.DatTools
|
|||||||
return (lessThan, greaterThan);
|
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>
|
/// <summary>
|
||||||
/// Split a DAT by type of DatItem
|
/// Split a DAT by type of DatItem
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -38,10 +38,11 @@ namespace SabreTools.Features
|
|||||||
None = 0x00,
|
None = 0x00,
|
||||||
|
|
||||||
Extension = 1 << 0,
|
Extension = 1 << 0,
|
||||||
Hash = 1 << 2,
|
Hash = 1 << 1,
|
||||||
Level = 1 << 3,
|
Level = 1 << 2,
|
||||||
Type = 1 << 4,
|
Type = 1 << 3,
|
||||||
Size = 1 << 5,
|
Size = 1 << 4,
|
||||||
|
TotalSize = 1 << 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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 const string TrimValue = "trim";
|
||||||
internal static Feature TrimFlag
|
internal static Feature TrimFlag
|
||||||
{
|
{
|
||||||
@@ -1172,6 +1187,20 @@ namespace SabreTools.Features
|
|||||||
|
|
||||||
#region Int64 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 const string RadixInt64Value = "radix";
|
||||||
internal static Feature RadixInt64Input
|
internal static Feature RadixInt64Input
|
||||||
{
|
{
|
||||||
@@ -1958,6 +1987,8 @@ Some special strings that can be used:
|
|||||||
splittingMode |= SplittingMode.Level;
|
splittingMode |= SplittingMode.Level;
|
||||||
if (GetBoolean(features, SizeValue))
|
if (GetBoolean(features, SizeValue))
|
||||||
splittingMode |= SplittingMode.Size;
|
splittingMode |= SplittingMode.Size;
|
||||||
|
if (GetBoolean(features, TotalSizeValue))
|
||||||
|
splittingMode |= SplittingMode.TotalSize;
|
||||||
if (GetBoolean(features, TypeValue))
|
if (GetBoolean(features, TypeValue))
|
||||||
splittingMode |= SplittingMode.Type;
|
splittingMode |= SplittingMode.Type;
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ namespace SabreTools.Features
|
|||||||
this[LevelFlag].AddFeature(BaseFlag);
|
this[LevelFlag].AddFeature(BaseFlag);
|
||||||
AddFeature(SizeFlag);
|
AddFeature(SizeFlag);
|
||||||
this[SizeFlag].AddFeature(RadixInt64Input);
|
this[SizeFlag].AddFeature(RadixInt64Input);
|
||||||
|
AddFeature(TotalSizeFlag);
|
||||||
|
this[TotalSizeFlag].AddFeature(ChunkSizeInt64Input);
|
||||||
AddFeature(TypeFlag);
|
AddFeature(TypeFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +122,23 @@ namespace SabreTools.Features
|
|||||||
watch.Stop();
|
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
|
// Type splitting
|
||||||
if (splittingMode.HasFlag(SplittingMode.Type))
|
if (splittingMode.HasFlag(SplittingMode.Type))
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user