Files

242 lines
11 KiB
C#
Raw Permalink Normal View History

2025-12-19 15:58:45 -07:00
using Mono.Options;
2025-04-13 15:18:03 -06:00
using Repackinator.Core.Helpers;
2025-12-19 15:25:06 -07:00
using XboxToolkit;
using XboxToolkit.Interface;
2025-04-13 15:18:03 -06:00
using Repackinator.Core.Models;
2023-01-04 21:08:49 -08:00
2025-12-19 15:58:45 -07:00
namespace Repackinator.Shell.Console
2023-01-04 21:08:49 -08:00
{
2025-04-13 15:18:03 -06:00
public static class ConsoleConvert
2023-01-04 21:08:49 -08:00
{
2023-01-11 20:44:58 +01:00
public const string Action = "Convert";
2023-01-04 21:08:49 -08:00
public static string Input { get; set; } = string.Empty;
2025-12-19 16:23:18 -07:00
public static string Output { get; set; } = string.Empty;
2025-11-22 17:30:18 -08:00
public static bool Scrub { get; set; } = false;
public static bool TrimScrub { get; set; } = false;
public static bool Compress { get; set; } = false;
2024-10-08 17:21:55 -06:00
public static bool NoSplit { get; set; } = false;
2023-01-04 21:08:49 -08:00
public static bool ShowHelp { get; set; } = false;
public static bool Wait { get; set; } = false;
public static bool Quiet { get; set; } = false;
2023-01-04 21:08:49 -08:00
public static OptionSet GetOptions()
{
return new OptionSet {
{ "i|input=", "Input file", i => Input = i },
2025-12-19 16:23:18 -07:00
{ "o|output=", "Output file or directory (optional, defaults to 'Converted' subfolder)", o => Output = o },
2025-11-22 17:30:18 -08:00
{ "c|compress", "Compress (CCI)", c => Compress = c != null },
{ "s|scrub", "Scrub", s => Scrub = s != null },
{ "t|trim", "TrimScrub", t => TrimScrub = t != null },
2024-10-08 17:21:55 -06:00
{ "n|nosplit", "No Split of output file", n => NoSplit = n != null },
2023-01-04 21:08:49 -08:00
{ "h|help", "show help", h => ShowHelp = h != null },
{ "w|wait", "Wait on exit", w => Wait = w != null },
{ "q|quiet", "Suppress status output", q => Quiet = q != null }
2023-01-04 21:08:49 -08:00
};
}
public static void ShowOptionDescription()
{
2023-01-11 20:44:58 +01:00
System.Console.WriteLine();
System.Console.WriteLine("Convert Action...");
System.Console.WriteLine();
System.Console.WriteLine("This action is used to convert one xbox disk image format to another.");
System.Console.WriteLine();
GetOptions().WriteOptionDescriptions(System.Console.Out);
2023-01-04 21:08:49 -08:00
}
public static void Process(string version, string[] args)
{
try
{
var options = GetOptions();
options.Parse(args);
if (ShowHelp)
{
2023-01-11 20:44:58 +01:00
ConsoleUtil.ShowHelpHeaderForAction(version, Action, options);
2023-01-04 21:08:49 -08:00
ConsoleUtil.ProcessWait(Wait);
return;
}
2025-12-19 17:31:03 -07:00
if (string.IsNullOrEmpty(Input))
{
throw new OptionException("Input file not specified.", "input");
}
2023-01-04 21:08:49 -08:00
var input = Path.GetFullPath(Input);
if (!File.Exists(input))
{
2025-12-19 17:31:03 -07:00
throw new OptionException("Input file does not exist.", "input");
2023-01-04 21:08:49 -08:00
}
var outputNameWithoutExtension = Path.GetFileNameWithoutExtension(input);
var subExtension = Path.GetExtension(outputNameWithoutExtension);
if (subExtension.Equals(".1") || subExtension.Equals(".2"))
{
outputNameWithoutExtension = Path.GetFileNameWithoutExtension(outputNameWithoutExtension);
}
2025-12-19 18:53:39 -07:00
string? outputPath;
2025-12-19 16:23:18 -07:00
string outputFile;
if (!string.IsNullOrEmpty(Output))
2023-01-04 21:08:49 -08:00
{
2025-12-19 16:23:18 -07:00
var outputFullPath = Path.GetFullPath(Output);
if (Directory.Exists(outputFullPath) || outputFullPath.EndsWith(Path.DirectorySeparatorChar) || outputFullPath.EndsWith(Path.AltDirectorySeparatorChar))
{
// Output is a directory
outputPath = outputFullPath;
Directory.CreateDirectory(outputPath);
var extension = Compress ? ".cci" : ".iso";
outputFile = Path.Combine(outputPath, $"{outputNameWithoutExtension}{extension}");
}
else
{
// Output is a file path
outputPath = Path.GetDirectoryName(outputFullPath) ?? Path.GetDirectoryName(input) ?? "";
if (!string.IsNullOrEmpty(outputPath) && !Directory.Exists(outputPath))
{
Directory.CreateDirectory(outputPath);
}
outputFile = outputFullPath;
// Ensure correct extension
if (Compress && !outputFile.EndsWith(".cci", StringComparison.OrdinalIgnoreCase))
{
outputFile = Path.ChangeExtension(outputFile, ".cci");
}
else if (!Compress && !outputFile.EndsWith(".iso", StringComparison.OrdinalIgnoreCase))
{
outputFile = Path.ChangeExtension(outputFile, ".iso");
}
}
}
else
{
// Default behavior: use Converted subfolder
outputPath = Path.GetDirectoryName(input);
if (outputPath == null)
{
throw new OptionException("Unable to get directory from input.", "input");
}
outputPath = Path.Combine(outputPath, $"Converted");
Directory.CreateDirectory(outputPath);
var extension = Compress ? ".cci" : ".iso";
outputFile = Path.Combine(outputPath, $"{outputNameWithoutExtension}{extension}");
2023-01-04 21:08:49 -08:00
}
2025-12-19 16:23:18 -07:00
if (!Quiet)
{
System.Console.WriteLine("Converting:");
var slices = ContainerUtility.GetSlicesFromFile(input);
foreach (var slice in slices)
{
System.Console.WriteLine(Path.GetFileName(slice));
}
System.Console.WriteLine($"To: {outputFile}");
System.Console.WriteLine();
}
2023-01-19 14:35:20 -08:00
2023-01-04 21:08:49 -08:00
var previousProgress = -1.0f;
if (outputPath != null)
{
2025-12-19 15:25:06 -07:00
if (!ContainerUtility.TryAutoDetectContainerType(input, out var containerReader) || containerReader == null)
2023-01-04 21:08:49 -08:00
{
2025-12-19 15:25:06 -07:00
throw new Exception("Unable to detect container type.");
}
using (containerReader)
2023-01-04 21:08:49 -08:00
{
2025-12-19 15:25:06 -07:00
if (!containerReader.TryMount())
2023-01-04 21:08:49 -08:00
{
2025-12-19 15:25:06 -07:00
throw new Exception("Unable to mount container.");
}
try
{
var processingOptions = ProcessingOptions.OneToOneCopy;
if (Scrub || TrimScrub) processingOptions |= ProcessingOptions.ScrubSectors;
if (TrimScrub) processingOptions |= ProcessingOptions.TrimSectors;
if (Compress)
2023-01-04 21:08:49 -08:00
{
2025-12-19 15:25:06 -07:00
var progress = new Action<float>((p) =>
2025-11-22 17:30:18 -08:00
{
2025-12-19 15:25:06 -07:00
var amount = (float)Math.Round(p * 100);
if (!Quiet && amount != previousProgress)
{
if (amount < 10)
{
System.Console.Write($"Progress {amount}%");
}
else if (amount < 100)
{
System.Console.Write($"Progress {amount}%");
}
else
{
System.Console.Write($"Progress {amount}%");
}
System.Console.CursorLeft = 0;
previousProgress = amount;
}
});
if (!ContainerUtility.ConvertContainerToCCI(containerReader, processingOptions, outputFile, 0, progress))
2025-11-22 17:30:18 -08:00
{
2025-12-19 15:25:06 -07:00
throw new Exception("Unable to convert to CCI.");
2025-11-22 17:30:18 -08:00
}
2025-12-19 15:25:06 -07:00
}
else
{
var splitPoint = NoSplit ? 0L : 4L * 1024 * 1024 * 1024; // 4GB
var progress = new Action<float>((p) =>
2025-11-22 17:30:18 -08:00
{
2025-12-19 15:25:06 -07:00
var amount = (float)Math.Round(p * 100);
if (!Quiet && amount != previousProgress)
{
if (amount < 10)
{
System.Console.Write($"Progress {amount}%");
}
else if (amount < 100)
{
System.Console.Write($"Progress {amount}%");
}
else
{
System.Console.Write($"Progress {amount}%");
}
System.Console.CursorLeft = 0;
previousProgress = amount;
}
});
if (!ContainerUtility.ConvertContainerToISO(containerReader, processingOptions, outputFile, splitPoint, progress))
{
throw new Exception("Unable to convert to ISO.");
2025-11-22 17:30:18 -08:00
}
2023-01-04 21:08:49 -08:00
}
2025-12-19 15:25:06 -07:00
}
finally
{
containerReader.Dismount();
}
2023-01-04 21:08:49 -08:00
}
}
if (!Quiet)
{
System.Console.WriteLine();
2025-11-22 17:30:18 -08:00
System.Console.WriteLine("Conversion completed.");
}
2023-01-04 21:08:49 -08:00
}
catch (OptionException e)
{
2025-12-19 16:19:12 -07:00
ConsoleUtil.ShowOptionException(e, Action, version);
2023-01-04 21:08:49 -08:00
}
2025-12-20 19:58:42 -07:00
ConsoleUtil.ProcessWait(Wait);
2023-01-04 21:08:49 -08:00
}
}
}
2025-12-19 15:58:45 -07:00