tsunpack-csharp/TSUnpack/Program.cs

116 lines
4.4 KiB
C#

using System;
using System.IO;
using System.Collections.Generic;
using Microsoft.Win32;
using Kaitai;
namespace TSUnpack {
class Program {
private const string USAGE = @"Usage: {0} [-f|--force|/f|/force] [-d|--destination|/d|/destination destination] path [path...]
Unpacks one or more Microsoft Train Simulator Packaged Activity files.
If any of the files do not exist or if any error occurs while parsing one of the files, an error is printed and the file is skipped.
-d, --destination
When unset, the destination directory will be retrieved from the {1} value of the Windows registry key at {2}.
If the destination path does not exist or the registry key is not found, the program will throw an error.
-f, --force
Overwrite existing files when unpacking.
By default, the program stops if a file already exists.";
private const string REGISTRY_KEY = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft Games\Train Simulator\1.0";
private const string REGISTRY_VALUE = "Path";
private static void PrintUsage() {
Console.WriteLine(
USAGE,
Environment.GetCommandLineArgs()[0],
REGISTRY_VALUE,
REGISTRY_KEY);
}
static int Main(string[] args) {
if (args.Length == 0) {
PrintUsage();
return 2;
}
// Poor man's argument parsing because I just can't find something simple for .NET 2.0.
bool overwrite = false;
// Null by default so that we can detect duplicate arguments and handle the default value
string destination = null;
List<string> sourcePaths = new List<string>();
for (int i = 0; i < args.Length; i++) {
string arg = args[i];
if (arg.ToLower() == "-f" || arg.ToLower() == "--force" || arg.ToLower() == "/f" || arg.ToLower() == "/force")
overwrite = true;
else if (arg.ToLower() == "-d" || arg.ToLower() == "--destination" || arg.ToLower() == "/d" || arg.ToLower() == "/destination") {
// Yes, this ++i is blursed. I like it.
if (destination != null || args.Length < ++i) {
PrintUsage();
return 2;
}
destination = args[i];
} else if (arg.ToLower().StartsWith("-d=") || arg.ToLower().StartsWith("--destination=") || arg.ToLower().StartsWith("/d=") || arg.ToLower().StartsWith("/destination=")) {
if (destination != null) {
PrintUsage();
return 2;
}
destination = arg.Split(new char[] { '=' }, 2)[1];
} else
sourcePaths.Add(arg);
}
if (sourcePaths.Count == 0) {
PrintUsage();
return 2;
}
if (destination == null) {
// Try to retrieve the registry key.
destination = (string)Registry.GetValue(REGISTRY_KEY, REGISTRY_VALUE, null);
}
if (destination == null) {
Console.WriteLine(
"No destination path specified and no default Microsoft Train Simulator installation path found in the Windows Registry at {0}.",
REGISTRY_KEY);
return 1;
}
// Resolve as an absolute path
destination = Path.GetFullPath(destination);
if (!Directory.Exists(destination)) {
Console.WriteLine("The destination path {0} does not exist.", destination);
return 1;
}
bool success = false;
foreach (string path in sourcePaths) {
try {
IO.Unpack(path, destination, overwrite);
success = true;
} catch (KaitaiStructError e) {
Console.WriteLine(
"Failed parsing APK file at {0}: {1}",
path,
e.Message);
} catch (IOException e) {
Console.WriteLine(
"Failed unpacking APK file at {0} to {1}: {2}",
path,
destination,
e.Message);
}
}
return success ? 0 : 1;
}
}
}