mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-10-07 23:28:52 +02:00
Add ability to trim and untrim XCI files from the application context menu AND in Bulk
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
// Uncomment the line below to ensure XCIFileTrimmer does not modify files
|
||||
//#define XCI_TRIMMER_READ_ONLY_MODE
|
||||
|
||||
using Gommon;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
@@ -91,6 +95,7 @@ namespace Ryujinx.Common.Utilities
|
||||
|
||||
public enum OperationOutcome
|
||||
{
|
||||
Undetermined,
|
||||
InvalidXCIFile,
|
||||
NoTrimNecessary,
|
||||
NoUntrimPossible,
|
||||
@@ -98,7 +103,8 @@ namespace Ryujinx.Common.Utilities
|
||||
FileIOWriteError,
|
||||
ReadOnlyFileCannotFix,
|
||||
FileSizeChanged,
|
||||
Successful
|
||||
Successful,
|
||||
Cancelled
|
||||
}
|
||||
|
||||
public enum LogType
|
||||
@@ -159,7 +165,7 @@ namespace Ryujinx.Common.Utilities
|
||||
ReadHeader();
|
||||
}
|
||||
|
||||
public void CheckFreeSpace()
|
||||
public void CheckFreeSpace(CancellationToken? cancelToken = null)
|
||||
{
|
||||
if (FreeSpaceChecked)
|
||||
return;
|
||||
@@ -178,14 +184,14 @@ namespace Ryujinx.Common.Utilities
|
||||
bool freeSpaceValid = true;
|
||||
long readSizeB = FileSizeB - TrimmedFileSizeB;
|
||||
|
||||
TimeSpan time = Performance.Measure(() =>
|
||||
Stopwatch timedSw = Lambda.Timed(() =>
|
||||
{
|
||||
freeSpaceValid = CheckPadding(readSizeB);
|
||||
freeSpaceValid = CheckPadding(readSizeB, cancelToken);
|
||||
});
|
||||
|
||||
if (time.TotalSeconds > 0)
|
||||
if (timedSw.Elapsed.TotalSeconds > 0)
|
||||
{
|
||||
Log?.Write(LogType.Info, $"Checked at {readSizeB / (double)XCIFileTrimmer.BytesInAMegabyte / time.TotalSeconds:N} Mb/sec");
|
||||
Log?.Write(LogType.Info, $"Checked at {readSizeB / (double)XCIFileTrimmer.BytesInAMegabyte / timedSw.Elapsed.TotalSeconds:N} Mb/sec");
|
||||
}
|
||||
|
||||
if (freeSpaceValid)
|
||||
@@ -211,7 +217,7 @@ namespace Ryujinx.Common.Utilities
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckPadding(long readSizeB)
|
||||
private bool CheckPadding(long readSizeB, CancellationToken? cancelToken = null)
|
||||
{
|
||||
long maxReads = readSizeB / XCIFileTrimmer.BufferSize;
|
||||
long read = 0;
|
||||
@@ -219,6 +225,11 @@ namespace Ryujinx.Common.Utilities
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int bytes = _fileStream.Read(buffer, 0, XCIFileTrimmer.BufferSize);
|
||||
if (bytes == 0)
|
||||
break;
|
||||
@@ -243,7 +254,7 @@ namespace Ryujinx.Common.Utilities
|
||||
ReadHeader();
|
||||
}
|
||||
|
||||
public OperationOutcome Trim()
|
||||
public OperationOutcome Trim(CancellationToken? cancelToken = null)
|
||||
{
|
||||
if (!FileOK)
|
||||
{
|
||||
@@ -257,12 +268,19 @@ namespace Ryujinx.Common.Utilities
|
||||
|
||||
if (!FreeSpaceChecked)
|
||||
{
|
||||
CheckFreeSpace();
|
||||
CheckFreeSpace(cancelToken);
|
||||
}
|
||||
|
||||
if (!FreeSpaceValid)
|
||||
{
|
||||
return OperationOutcome.FreeSpaceCheckFailed;
|
||||
if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested)
|
||||
{
|
||||
return OperationOutcome.Cancelled;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OperationOutcome.FreeSpaceCheckFailed;
|
||||
}
|
||||
}
|
||||
|
||||
Log?.Write(LogType.Info, "Trimming...");
|
||||
@@ -294,7 +312,10 @@ namespace Ryujinx.Common.Utilities
|
||||
|
||||
try
|
||||
{
|
||||
outfileStream.SetLength(TrimmedFileSizeB);
|
||||
|
||||
#if !XCI_TRIMMER_READ_ONLY_MODE
|
||||
outfileStream.SetLength(TrimmedFileSizeB);
|
||||
#endif
|
||||
return OperationOutcome.Successful;
|
||||
}
|
||||
finally
|
||||
@@ -310,7 +331,7 @@ namespace Ryujinx.Common.Utilities
|
||||
}
|
||||
}
|
||||
|
||||
public OperationOutcome Untrim()
|
||||
public OperationOutcome Untrim(CancellationToken? cancelToken = null)
|
||||
{
|
||||
if (!FileOK)
|
||||
{
|
||||
@@ -352,17 +373,24 @@ namespace Ryujinx.Common.Utilities
|
||||
|
||||
try
|
||||
{
|
||||
TimeSpan time = Performance.Measure(() =>
|
||||
Stopwatch timedSw = Lambda.Timed(() =>
|
||||
{
|
||||
WritePadding(outfileStream, bytesToWriteB);
|
||||
WritePadding(outfileStream, bytesToWriteB, cancelToken);
|
||||
});
|
||||
|
||||
if (time.TotalSeconds > 0)
|
||||
if (timedSw.Elapsed.TotalSeconds > 0)
|
||||
{
|
||||
Log?.Write(LogType.Info, $"Wrote at {bytesToWriteB / (double)XCIFileTrimmer.BytesInAMegabyte / time.TotalSeconds:N} Mb/sec");
|
||||
Log?.Write(LogType.Info, $"Wrote at {bytesToWriteB / (double)XCIFileTrimmer.BytesInAMegabyte / timedSw.Elapsed.TotalSeconds:N} Mb/sec");
|
||||
}
|
||||
|
||||
return OperationOutcome.Successful;
|
||||
if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested)
|
||||
{
|
||||
return OperationOutcome.Cancelled;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OperationOutcome.Successful;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -377,7 +405,7 @@ namespace Ryujinx.Common.Utilities
|
||||
}
|
||||
}
|
||||
|
||||
private void WritePadding(FileStream outfileStream, long bytesToWriteB)
|
||||
private void WritePadding(FileStream outfileStream, long bytesToWriteB, CancellationToken? cancelToken = null)
|
||||
{
|
||||
long bytesLeftToWriteB = bytesToWriteB;
|
||||
long writes = bytesLeftToWriteB / XCIFileTrimmer.BufferSize;
|
||||
@@ -390,8 +418,17 @@ namespace Ryujinx.Common.Utilities
|
||||
|
||||
while (bytesLeftToWriteB > 0)
|
||||
{
|
||||
if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long bytesToWrite = Math.Min(XCIFileTrimmer.BufferSize, bytesLeftToWriteB);
|
||||
outfileStream.Write(buffer, 0, (int)bytesToWrite);
|
||||
|
||||
#if !XCI_TRIMMER_READ_ONLY_MODE
|
||||
outfileStream.Write(buffer, 0, (int)bytesToWrite);
|
||||
#endif
|
||||
|
||||
bytesLeftToWriteB -= bytesToWrite;
|
||||
Log?.Progress(write, writes, "Writing padding data...", false);
|
||||
write++;
|
||||
|
||||
Reference in New Issue
Block a user