ExtractCommand.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Text;
  5. using ArcToolkitCLI.Commands.Options;
  6. using ArcToolkitCLI.Util;
  7. using COM3D2.Toolkit.Arc;
  8. using COM3D2.Toolkit.Arc.Files;
  9. using CommandLine;
  10. namespace ArcToolkitCLI.Commands
  11. {
  12. [Verb("extract", HelpText = "Extract the contents of the given ARC files")]
  13. public class ExtractCommand : ICommand, IInputOptions, IDecryptionOptions, IOutputOptions
  14. {
  15. public int Run()
  16. {
  17. Dictionary<string, byte[]> keys = null;
  18. Directory.CreateDirectory(Output);
  19. foreach (var file in Glob.EnumerateFiles(Input))
  20. {
  21. if (!file.Exists)
  22. return Errors.Error(Errors.ErrorCodes.NotAFile, file.Name);
  23. using (var stream = File.OpenRead(file.FullName))
  24. {
  25. var header = new byte[4];
  26. stream.Read(header, 0, header.Length);
  27. var headerString = Encoding.ASCII.GetString(header);
  28. stream.Position = 0;
  29. WarcArc arc = null;
  30. if (headerString == "warp")
  31. {
  32. if (keys == null)
  33. {
  34. var err = Encryption.GetDecryptionKeys(this, out keys);
  35. if (err != 0)
  36. return err;
  37. arc = new WarpArc(stream, requestedFile =>
  38. {
  39. if (keys.TryGetValue("*", out var key))
  40. return key;
  41. if (keys.TryGetValue(requestedFile, out key))
  42. return key;
  43. if (Directory.Exists(ArcDirectory) &&
  44. File.Exists(Path.Combine(ArcDirectory, requestedFile)))
  45. return Encryption.ReadKeyFromFile(Path.Combine(ArcDirectory, requestedFile));
  46. if (File.Exists(WarcFile))
  47. return Encryption.ReadKeyFromFile(WarcFile);
  48. throw new FileNotFoundException("No key found for the requested ARC", requestedFile);
  49. });
  50. }
  51. }
  52. else if (headerString == "warc")
  53. {
  54. arc = new WarcArc(stream);
  55. }
  56. if (arc == null)
  57. return Errors.Error(Errors.ErrorCodes.UnknownArcType, file.Name);
  58. Console.WriteLine($"Extracting {arc.Name}:");
  59. var arcDir = Path.Combine(Output, Path.GetFileNameWithoutExtension(arc.Name));
  60. Directory.CreateDirectory(arcDir);
  61. foreach (var arcEntry in arc.Entries)
  62. ExtractArchive(arcEntry, arcDir);
  63. arc.Dispose();
  64. }
  65. }
  66. return 0;
  67. }
  68. public string ArcDirectory { get; set; }
  69. public string DecryptionKey { get; set; }
  70. public string KeyFile { get; set; }
  71. public string WarcFile { get; set; }
  72. public IEnumerable<string> Input { get; set; }
  73. public string Output { get; set; }
  74. private void ExtractArchive(ArcEntry entry, string path)
  75. {
  76. switch (entry)
  77. {
  78. case ArcFileEntry fe:
  79. var fullName = Path.Combine(path, fe.Name);
  80. Console.WriteLine(fullName);
  81. using (var file = File.Create(fullName))
  82. using (var data = fe.GetDataStream())
  83. {
  84. data.CopyTo(file);
  85. }
  86. break;
  87. case ArcDirectoryEntry de:
  88. var subfolderPath = Path.Combine(path, de.Name);
  89. Directory.CreateDirectory(subfolderPath);
  90. foreach (var arcEntry in de.Children)
  91. ExtractArchive(arcEntry, subfolderPath);
  92. break;
  93. }
  94. }
  95. }
  96. }