|
@@ -6,27 +6,36 @@ using System.Linq;
|
|
using System.Text;
|
|
using System.Text;
|
|
using CommandLine;
|
|
using CommandLine;
|
|
using COM3D2.Toolkit.Arc;
|
|
using COM3D2.Toolkit.Arc;
|
|
|
|
+using COM3D2.Toolkit.Arc.Files;
|
|
using Ganss.IO;
|
|
using Ganss.IO;
|
|
|
|
|
|
namespace ArcToolkitCLI
|
|
namespace ArcToolkitCLI
|
|
{
|
|
{
|
|
- internal interface IOptions
|
|
|
|
|
|
+ interface IOptions
|
|
{
|
|
{
|
|
[Value(0, MetaName = "input", HelpText = "Input ARC files")]
|
|
[Value(0, MetaName = "input", HelpText = "Input ARC files")]
|
|
IEnumerable<string> Input { get; set; }
|
|
IEnumerable<string> Input { get; set; }
|
|
}
|
|
}
|
|
|
|
|
|
- internal interface IDecryptionOptions
|
|
|
|
|
|
+ interface IOutputOptions
|
|
{
|
|
{
|
|
- [Option("arc-search-dir", Required = false, HelpText = "Directory where to search ARC file to decrypt the WARP file")]
|
|
|
|
|
|
+ [Option('o', "output", HelpText = "Output directory", Default = ".")]
|
|
|
|
+ string Output { get; set; }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ interface IDecryptionOptions
|
|
|
|
+ {
|
|
|
|
+ [Option("arc-search-dir", Required = false,
|
|
|
|
+ HelpText = "Directory where to search ARC file to decrypt the WARP file")]
|
|
string ArcDirectory { get; set; }
|
|
string ArcDirectory { get; set; }
|
|
|
|
|
|
[Option('k', "key", HelpText = "Decryption key as a base64 string (applied to all inputs)", Required = false)]
|
|
[Option('k', "key", HelpText = "Decryption key as a base64 string (applied to all inputs)", Required = false)]
|
|
string DecryptionKey { get; set; }
|
|
string DecryptionKey { get; set; }
|
|
|
|
|
|
[Option("key-file",
|
|
[Option("key-file",
|
|
- HelpText = "A file with decryption keys on each line. Format of the file is <decryption arc name>:<key in base64>.",
|
|
|
|
- Required = false)]
|
|
|
|
|
|
+ HelpText =
|
|
|
|
+ "A file with decryption keys on each line. Format of the file is <decryption arc name>:<key in base64>.",
|
|
|
|
+ Required = false)]
|
|
string KeyFile { get; set; }
|
|
string KeyFile { get; set; }
|
|
|
|
|
|
[Option("warc", Required = false, HelpText = "WARC file to use for decryption")]
|
|
[Option("warc", Required = false, HelpText = "WARC file to use for decryption")]
|
|
@@ -34,44 +43,40 @@ namespace ArcToolkitCLI
|
|
}
|
|
}
|
|
|
|
|
|
[Verb("extract", HelpText = "Extract the contents of the given ARC files")]
|
|
[Verb("extract", HelpText = "Extract the contents of the given ARC files")]
|
|
- internal class ExtractOptions : IOptions, IDecryptionOptions
|
|
|
|
|
|
+ class ExtractOptions : IOptions, IDecryptionOptions, IOutputOptions
|
|
{
|
|
{
|
|
- [Option('o', "output", HelpText = "Output directory", Required = true)]
|
|
|
|
- public string Output { get; set; }
|
|
|
|
-
|
|
|
|
public string ArcDirectory { get; set; }
|
|
public string ArcDirectory { get; set; }
|
|
public string DecryptionKey { get; set; }
|
|
public string DecryptionKey { get; set; }
|
|
public string KeyFile { get; set; }
|
|
public string KeyFile { get; set; }
|
|
|
|
|
|
public string WarcFile { get; set; }
|
|
public string WarcFile { get; set; }
|
|
public IEnumerable<string> Input { get; set; }
|
|
public IEnumerable<string> Input { get; set; }
|
|
|
|
+ public string Output { get; set; }
|
|
}
|
|
}
|
|
|
|
|
|
[Verb("info", HelpText = "Display information about the given ARC files")]
|
|
[Verb("info", HelpText = "Display information about the given ARC files")]
|
|
- internal class InfoOptions : IOptions
|
|
|
|
|
|
+ class InfoOptions : IOptions
|
|
{
|
|
{
|
|
[Option("only-key",
|
|
[Option("only-key",
|
|
- HelpText = "If the archive is a WARC file, output only the decryption key as a base64 string",
|
|
|
|
- Required = false)]
|
|
|
|
|
|
+ HelpText = "If the archive is a WARC file, output only the decryption key as a base64 string",
|
|
|
|
+ Required = false)]
|
|
public bool OnlyKey { get; set; }
|
|
public bool OnlyKey { get; set; }
|
|
|
|
|
|
public IEnumerable<string> Input { get; set; }
|
|
public IEnumerable<string> Input { get; set; }
|
|
}
|
|
}
|
|
|
|
|
|
[Verb("decrypt", HelpText = "Decrypts the provided WARP files")]
|
|
[Verb("decrypt", HelpText = "Decrypts the provided WARP files")]
|
|
- internal class DecryptOptions : IOptions, IDecryptionOptions
|
|
|
|
|
|
+ class DecryptOptions : IOptions, IDecryptionOptions, IOutputOptions
|
|
{
|
|
{
|
|
- [Option('o', "output", HelpText = "Output directory", Default = ".")]
|
|
|
|
- public string Output { get; set; }
|
|
|
|
-
|
|
|
|
public string ArcDirectory { get; set; }
|
|
public string ArcDirectory { get; set; }
|
|
public string DecryptionKey { get; set; }
|
|
public string DecryptionKey { get; set; }
|
|
public string KeyFile { get; set; }
|
|
public string KeyFile { get; set; }
|
|
public string WarcFile { get; set; }
|
|
public string WarcFile { get; set; }
|
|
public IEnumerable<string> Input { get; set; }
|
|
public IEnumerable<string> Input { get; set; }
|
|
|
|
+ public string Output { get; set; }
|
|
}
|
|
}
|
|
|
|
|
|
- internal static class Errors
|
|
|
|
|
|
+ static class Errors
|
|
{
|
|
{
|
|
public enum ErrorCodes
|
|
public enum ErrorCodes
|
|
{
|
|
{
|
|
@@ -84,11 +89,11 @@ namespace ArcToolkitCLI
|
|
|
|
|
|
public static readonly string[] ErrorMessages =
|
|
public static readonly string[] ErrorMessages =
|
|
{
|
|
{
|
|
- "{0} is not a file",
|
|
|
|
- "{0} is not a known ARC file",
|
|
|
|
- "No key specified or the key file does not exist",
|
|
|
|
- "The provided keyfile is not valid",
|
|
|
|
- "The ARC {0} needs a key from {1}"
|
|
|
|
|
|
+ "{0} is not a file",
|
|
|
|
+ "{0} is not a known ARC file",
|
|
|
|
+ "No key specified or the key file does not exist",
|
|
|
|
+ "The provided keyfile is not valid",
|
|
|
|
+ "The ARC {0} needs a key from {1}"
|
|
};
|
|
};
|
|
|
|
|
|
public static int Error(ErrorCodes code, params object[] args)
|
|
public static int Error(ErrorCodes code, params object[] args)
|
|
@@ -98,13 +103,13 @@ namespace ArcToolkitCLI
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- internal static class Util
|
|
|
|
|
|
+ static class Util
|
|
{
|
|
{
|
|
- private static readonly char[] GlobCharacters = {'*', '{', '}', '[', ']', '?'};
|
|
|
|
|
|
+ static readonly char[] GlobCharacters = {'*', '{', '}', '[', ']', '?'};
|
|
|
|
|
|
public static IEnumerable<FileSystemInfoBase> EnumerateFiles(IEnumerable<string> patterns)
|
|
public static IEnumerable<FileSystemInfoBase> EnumerateFiles(IEnumerable<string> patterns)
|
|
{
|
|
{
|
|
- foreach (string pattern in patterns)
|
|
|
|
|
|
+ foreach (var pattern in patterns)
|
|
if (IsGlob(pattern))
|
|
if (IsGlob(pattern))
|
|
foreach (var fileSystemInfoBase in Glob.Expand(pattern))
|
|
foreach (var fileSystemInfoBase in Glob.Expand(pattern))
|
|
yield return fileSystemInfoBase;
|
|
yield return fileSystemInfoBase;
|
|
@@ -112,26 +117,69 @@ namespace ArcToolkitCLI
|
|
yield return new FileInfoWrapper(new FileSystem(), new FileInfo(pattern));
|
|
yield return new FileInfoWrapper(new FileSystem(), new FileInfo(pattern));
|
|
}
|
|
}
|
|
|
|
|
|
- private static bool IsGlob(string path)
|
|
|
|
- {
|
|
|
|
- return path.IndexOfAny(GlobCharacters) >= 0;
|
|
|
|
- }
|
|
|
|
|
|
+ static bool IsGlob(string path) { return path.IndexOfAny(GlobCharacters) >= 0; }
|
|
}
|
|
}
|
|
|
|
|
|
- internal class Program
|
|
|
|
|
|
+ class Program
|
|
{
|
|
{
|
|
- private static int Main(string[] args)
|
|
|
|
|
|
+ static int Decrypt(DecryptOptions opts)
|
|
{
|
|
{
|
|
- return Parser.Default.ParseArguments<InfoOptions, ExtractOptions, DecryptOptions>(args)
|
|
|
|
- .MapResult((InfoOptions opts) => DisplayInfo(opts),
|
|
|
|
- (ExtractOptions opts) => Extract(opts),
|
|
|
|
- (DecryptOptions opts) => Decrypt(opts),
|
|
|
|
- errs => 1);
|
|
|
|
|
|
+ var errCode = GetDecryptionKeys(opts, out var keysDict);
|
|
|
|
+ if (errCode != 0)
|
|
|
|
+ return errCode;
|
|
|
|
+
|
|
|
|
+ Directory.CreateDirectory(opts.Output);
|
|
|
|
+
|
|
|
|
+ foreach (var file in Util.EnumerateFiles(opts.Input))
|
|
|
|
+ {
|
|
|
|
+ if (!file.Exists)
|
|
|
|
+ return Errors.Error(Errors.ErrorCodes.NotAFile, file.Name);
|
|
|
|
+
|
|
|
|
+ using (var stream = File.OpenRead(file.FullName))
|
|
|
|
+ {
|
|
|
|
+ var header = new byte[4];
|
|
|
|
+ stream.Read(header, 0, header.Length);
|
|
|
|
+ var headerString = Encoding.ASCII.GetString(header);
|
|
|
|
+ stream.Position = 0;
|
|
|
|
+ if (headerString == "warc")
|
|
|
|
+ Console.WriteLine($"{file.Name} is a WARC file, skipping...");
|
|
|
|
+ else if (headerString == "warp")
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ var arcStream = WarpArc.DecryptWarp(stream, requestedFile =>
|
|
|
|
+ {
|
|
|
|
+ if (keysDict.TryGetValue("*", out var key))
|
|
|
|
+ return key;
|
|
|
|
+ if (keysDict.TryGetValue(requestedFile, out key))
|
|
|
|
+ return key;
|
|
|
|
+ if (Directory.Exists(opts.ArcDirectory) &&
|
|
|
|
+ File.Exists(Path.Combine(opts.ArcDirectory, requestedFile)))
|
|
|
|
+ return ReadKeyFromFile(Path.Combine(opts.ArcDirectory, requestedFile));
|
|
|
|
+ if (File.Exists(opts.WarcFile))
|
|
|
|
+ return ReadKeyFromFile(opts.WarcFile);
|
|
|
|
+ throw new FileNotFoundException("No key found for the requested ARC", requestedFile);
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ Console.WriteLine(
|
|
|
|
+ $"Writing {Path.Combine(opts.Output, file.Name)} with length {arcStream.Length}");
|
|
|
|
+ using (var output = File.Create(Path.Combine(opts.Output, file.Name)))
|
|
|
|
+ arcStream.CopyTo(output);
|
|
|
|
+ }
|
|
|
|
+ catch (FileNotFoundException fe)
|
|
|
|
+ {
|
|
|
|
+ return Errors.Error(Errors.ErrorCodes.NoCorrectKey, file.Name, fe.FileName);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ return Errors.Error(Errors.ErrorCodes.UnknownArcType, file.Name);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- private static int DisplayInfo(InfoOptions opts)
|
|
|
|
|
|
+ static int DisplayInfo(InfoOptions opts)
|
|
{
|
|
{
|
|
- bool first = true;
|
|
|
|
|
|
+ var first = true;
|
|
foreach (var file in Util.EnumerateFiles(opts.Input))
|
|
foreach (var file in Util.EnumerateFiles(opts.Input))
|
|
{
|
|
{
|
|
if (!file.Exists)
|
|
if (!file.Exists)
|
|
@@ -145,14 +193,14 @@ namespace ArcToolkitCLI
|
|
{
|
|
{
|
|
var header = new byte[4];
|
|
var header = new byte[4];
|
|
stream.Read(header, 0, header.Length);
|
|
stream.Read(header, 0, header.Length);
|
|
- string headerString = Encoding.ASCII.GetString(header);
|
|
|
|
|
|
+ var headerString = Encoding.ASCII.GetString(header);
|
|
stream.Position = 0;
|
|
stream.Position = 0;
|
|
|
|
|
|
if (headerString == "warc")
|
|
if (headerString == "warc")
|
|
{
|
|
{
|
|
var key = new byte[2048];
|
|
var key = new byte[2048];
|
|
stream.Read(key, 0, key.Length);
|
|
stream.Read(key, 0, key.Length);
|
|
- string keyBase64 = Convert.ToBase64String(key);
|
|
|
|
|
|
+ var keyBase64 = Convert.ToBase64String(key);
|
|
if (opts.OnlyKey)
|
|
if (opts.OnlyKey)
|
|
{
|
|
{
|
|
Console.WriteLine($"{Path.GetFileName(file.FullName)}:{keyBase64}");
|
|
Console.WriteLine($"{Path.GetFileName(file.FullName)}:{keyBase64}");
|
|
@@ -177,108 +225,135 @@ namespace ArcToolkitCLI
|
|
Console.WriteLine($"File name: {file.Name}");
|
|
Console.WriteLine($"File name: {file.Name}");
|
|
Console.WriteLine("ARC type: WARP");
|
|
Console.WriteLine("ARC type: WARP");
|
|
using (var br = new BinaryReader(stream))
|
|
using (var br = new BinaryReader(stream))
|
|
- Console.WriteLine($"Needs a decryption key from the following ARC: {WarpArc.GetKeyWarpName(br)}");
|
|
|
|
|
|
+ Console.WriteLine(
|
|
|
|
+ $"Needs a decryption key from the following ARC: {WarpArc.GetKeyWarpName(br)}");
|
|
}
|
|
}
|
|
else
|
|
else
|
|
- {
|
|
|
|
return Errors.Error(Errors.ErrorCodes.UnknownArcType, file.Name);
|
|
return Errors.Error(Errors.ErrorCodes.UnknownArcType, file.Name);
|
|
- }
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- private static int Extract(ExtractOptions opts)
|
|
|
|
|
|
+ static int Extract(ExtractOptions opts)
|
|
{
|
|
{
|
|
|
|
+ Dictionary<string, byte[]> keys = null;
|
|
|
|
+
|
|
|
|
+ Directory.CreateDirectory(opts.Output);
|
|
|
|
+
|
|
|
|
+ foreach (var file in Util.EnumerateFiles(opts.Input))
|
|
|
|
+ {
|
|
|
|
+ if (!file.Exists)
|
|
|
|
+ return Errors.Error(Errors.ErrorCodes.NotAFile, file.Name);
|
|
|
|
+
|
|
|
|
+ using (var stream = File.OpenRead(file.FullName))
|
|
|
|
+ {
|
|
|
|
+ var header = new byte[4];
|
|
|
|
+ stream.Read(header, 0, header.Length);
|
|
|
|
+ var headerString = Encoding.ASCII.GetString(header);
|
|
|
|
+ stream.Position = 0;
|
|
|
|
+ WarcArc arc = null;
|
|
|
|
+
|
|
|
|
+ if (headerString == "warp")
|
|
|
|
+ {
|
|
|
|
+ if (keys == null)
|
|
|
|
+ {
|
|
|
|
+ var err = GetDecryptionKeys(opts, out keys);
|
|
|
|
+ if (err != 0)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ arc = new WarpArc(stream, requestedFile =>
|
|
|
|
+ {
|
|
|
|
+ if (keys.TryGetValue("*", out var key))
|
|
|
|
+ return key;
|
|
|
|
+ if (keys.TryGetValue(requestedFile, out key))
|
|
|
|
+ return key;
|
|
|
|
+ if (Directory.Exists(opts.ArcDirectory) &&
|
|
|
|
+ File.Exists(Path.Combine(opts.ArcDirectory, requestedFile)))
|
|
|
|
+ return ReadKeyFromFile(Path.Combine(opts.ArcDirectory, requestedFile));
|
|
|
|
+ if (File.Exists(opts.WarcFile))
|
|
|
|
+ return ReadKeyFromFile(opts.WarcFile);
|
|
|
|
+ throw new FileNotFoundException("No key found for the requested ARC", requestedFile);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else if (headerString == "warc")
|
|
|
|
+ arc = new WarcArc(stream);
|
|
|
|
+
|
|
|
|
+ if (arc == null)
|
|
|
|
+ return Errors.Error(Errors.ErrorCodes.UnknownArcType, file.Name);
|
|
|
|
+
|
|
|
|
+ Console.WriteLine($"Extracting {arc.Name}:");
|
|
|
|
+ var arcDir = Path.Combine(opts.Output, Path.GetFileNameWithoutExtension(arc.Name));
|
|
|
|
+
|
|
|
|
+ Directory.CreateDirectory(arcDir);
|
|
|
|
+ foreach (var arcEntry in arc.Entries)
|
|
|
|
+ ExtractArchive(arcEntry, arcDir);
|
|
|
|
+
|
|
|
|
+ arc.Dispose();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- private static byte[] ReadKeyFromFile(string filename)
|
|
|
|
|
|
+ static void ExtractArchive(ArcEntry entry, string path)
|
|
{
|
|
{
|
|
- using (var br = new BinaryReader(File.OpenRead(filename)))
|
|
|
|
- return br.ReadBytes(2048);
|
|
|
|
|
|
+ switch (entry)
|
|
|
|
+ {
|
|
|
|
+ case ArcFileEntry fe:
|
|
|
|
+ var fullName = Path.Combine(path, fe.Name);
|
|
|
|
+ Console.WriteLine(fullName);
|
|
|
|
+ using (var file = File.Create(fullName))
|
|
|
|
+ using (var data = fe.GetDataStream())
|
|
|
|
+ data.CopyTo(file);
|
|
|
|
+ break;
|
|
|
|
+ case ArcDirectoryEntry de:
|
|
|
|
+ var subfolderPath = Path.Combine(path, de.Name);
|
|
|
|
+ Directory.CreateDirectory(subfolderPath);
|
|
|
|
+ foreach (var arcEntry in de.Children)
|
|
|
|
+ ExtractArchive(arcEntry, subfolderPath);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- private static int Decrypt(DecryptOptions opts)
|
|
|
|
|
|
+ static int GetDecryptionKeys(IDecryptionOptions opts, out Dictionary<string, byte[]> keys)
|
|
{
|
|
{
|
|
- var keysDict = new Dictionary<string, byte[]>(StringComparer.InvariantCultureIgnoreCase);
|
|
|
|
|
|
+ keys = new Dictionary<string, byte[]>(StringComparer.InvariantCultureIgnoreCase);
|
|
if (!string.IsNullOrWhiteSpace(opts.KeyFile))
|
|
if (!string.IsNullOrWhiteSpace(opts.KeyFile))
|
|
{
|
|
{
|
|
if (!File.Exists(opts.KeyFile))
|
|
if (!File.Exists(opts.KeyFile))
|
|
return Errors.Error(Errors.ErrorCodes.KeyNotFound);
|
|
return Errors.Error(Errors.ErrorCodes.KeyNotFound);
|
|
|
|
|
|
- foreach (string line in File.ReadAllLines(opts.KeyFile))
|
|
|
|
|
|
+ foreach (var line in File.ReadAllLines(opts.KeyFile))
|
|
{
|
|
{
|
|
var parts = line.Split(':');
|
|
var parts = line.Split(':');
|
|
if (parts.Length != 2)
|
|
if (parts.Length != 2)
|
|
return Errors.Error(Errors.ErrorCodes.InvalidKeyFile);
|
|
return Errors.Error(Errors.ErrorCodes.InvalidKeyFile);
|
|
- keysDict[parts[0].Trim()] = Convert.FromBase64String(parts[1].Trim());
|
|
|
|
|
|
+ keys[parts[0].Trim()] = Convert.FromBase64String(parts[1].Trim());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (!string.IsNullOrWhiteSpace(opts.DecryptionKey))
|
|
else if (!string.IsNullOrWhiteSpace(opts.DecryptionKey))
|
|
- {
|
|
|
|
- keysDict["*"] = Convert.FromBase64String(opts.DecryptionKey);
|
|
|
|
- }
|
|
|
|
|
|
+ keys["*"] = Convert.FromBase64String(opts.DecryptionKey);
|
|
else if (string.IsNullOrWhiteSpace(opts.ArcDirectory) && string.IsNullOrWhiteSpace(opts.WarcFile))
|
|
else if (string.IsNullOrWhiteSpace(opts.ArcDirectory) && string.IsNullOrWhiteSpace(opts.WarcFile))
|
|
- {
|
|
|
|
return Errors.Error(Errors.ErrorCodes.KeyNotFound);
|
|
return Errors.Error(Errors.ErrorCodes.KeyNotFound);
|
|
- }
|
|
|
|
|
|
|
|
- Directory.CreateDirectory(opts.Output);
|
|
|
|
-
|
|
|
|
- foreach (var file in Util.EnumerateFiles(opts.Input))
|
|
|
|
- {
|
|
|
|
- if (!file.Exists)
|
|
|
|
- return Errors.Error(Errors.ErrorCodes.NotAFile, file.Name);
|
|
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
|
|
- using (var stream = File.OpenRead(file.FullName))
|
|
|
|
- {
|
|
|
|
- var header = new byte[4];
|
|
|
|
- stream.Read(header, 0, header.Length);
|
|
|
|
- string headerString = Encoding.ASCII.GetString(header);
|
|
|
|
- stream.Position = 0;
|
|
|
|
- if (headerString == "warc")
|
|
|
|
- {
|
|
|
|
- Console.WriteLine($"{file.Name} is a WARC file, skipping...");
|
|
|
|
- }
|
|
|
|
- else if (headerString == "warp")
|
|
|
|
- {
|
|
|
|
- try
|
|
|
|
- {
|
|
|
|
- var arcStream = WarpArc.DecryptWarp(stream,
|
|
|
|
- requestedFile =>
|
|
|
|
- {
|
|
|
|
- if (keysDict.TryGetValue("*", out var key))
|
|
|
|
- return key;
|
|
|
|
- if (keysDict.TryGetValue(requestedFile, out key))
|
|
|
|
- return key;
|
|
|
|
- if (Directory.Exists(opts.ArcDirectory)
|
|
|
|
- && File.Exists(Path.Combine(opts.ArcDirectory, requestedFile)))
|
|
|
|
- return ReadKeyFromFile(Path.Combine(opts.ArcDirectory, requestedFile));
|
|
|
|
- if (File.Exists(opts.WarcFile))
|
|
|
|
- return ReadKeyFromFile(opts.WarcFile);
|
|
|
|
- throw new FileNotFoundException("No key found for the requested ARC",
|
|
|
|
- requestedFile);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- using (var output =
|
|
|
|
- File.Create(Path.Combine(Path.GetDirectoryName(opts.Output), Path.GetFileNameWithoutExtension(file.Name))))
|
|
|
|
- arcStream.CopyTo(output);
|
|
|
|
- }
|
|
|
|
- catch (FileNotFoundException fe)
|
|
|
|
- {
|
|
|
|
- return Errors.Error(Errors.ErrorCodes.NoCorrectKey, file.Name, fe.FileName);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- return Errors.Error(Errors.ErrorCodes.UnknownArcType, file.Name);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ static int Main(string[] args)
|
|
|
|
+ {
|
|
|
|
+ return Parser.Default.ParseArguments<InfoOptions, ExtractOptions, DecryptOptions>(args).MapResult(
|
|
|
|
+ (InfoOptions opts) => DisplayInfo(opts), (ExtractOptions opts) => Extract(opts),
|
|
|
|
+ (DecryptOptions opts) => Decrypt(opts), errs => 1);
|
|
|
|
+ }
|
|
|
|
|
|
- return 0;
|
|
|
|
|
|
+ static byte[] ReadKeyFromFile(string filename)
|
|
|
|
+ {
|
|
|
|
+ using (var br = new BinaryReader(File.OpenRead(filename)))
|
|
|
|
+ return br.ReadBytes(2048);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|