BTar files are integrated into the extractor code

This commit is contained in:
Timothy Baldridge 2022-02-11 17:47:02 -07:00
parent 30b29d890d
commit 379337d0b6
6 changed files with 1255 additions and 1258 deletions

View File

@ -69,6 +69,7 @@ internal class Program
services.AddSingleton<IVerb, SteamDownloadFile>();
services.AddSingleton<IVerb, UploadToNexus>();
services.AddSingleton<IVerb, ListCreationClubContent>();
services.AddSingleton<IVerb, Extract>();
services.AddSingleton<IUserInterventionHandler, UserInterventionHandler>();
}).Build();

View File

@ -0,0 +1,49 @@
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Wabbajack.Common;
using Wabbajack.Downloaders;
using Wabbajack.DTOs;
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
namespace Wabbajack.CLI.Verbs;
public class Extract : IVerb
{
private readonly ILogger<DownloadUrl> _logger;
private readonly FileExtractor.FileExtractor _extractor;
public Extract(ILogger<DownloadUrl> logger, FileExtractor.FileExtractor extractor)
{
_logger = logger;
_extractor = extractor;
}
public Command MakeCommand()
{
var command = new Command("extract");
command.Add(new Option<AbsolutePath>(new[] {"-i", "-input"}, "Input Archive"));
command.Add(new Option<AbsolutePath>(new[] {"-o", "-output"}, "Output folder"));
command.Description = "Extracts the contents of an archive into a folder";
command.Handler = CommandHandler.Create(Run);
return command;
}
private async Task<int> Run(AbsolutePath input, AbsolutePath output, CancellationToken token)
{
if (!output.DirectoryExists())
output.Parent.CreateDirectory();
await _extractor.ExtractAll(input, output, token, f =>
{
Console.WriteLine($" - {f}");
return true;
});
return 0;
}
}

View File

@ -5,3 +5,4 @@ Relaxed RAR format,52 61 72 21,RAR
RAR5 or newer, 52 61 72 21 1A 07 01 00,RAR_NEW
RAR4 or older, 52 61 72 21 1A 07 00,RAR_OLD
DDS, 44 44 53 20,DDS
Bethesda Tar, 42 54 41 52, BTAR

View File

@ -1,7 +1,7 @@
namespace Wabbajack.Common.FileSignatures;

namespace Wabbajack.Common.FileSignatures {
public enum FileType
{
public enum FileType { BTAR,
_123,
_386,
_3G2,
@ -431,13 +431,13 @@ public enum FileType
XZ,
ZAP,
ZIP,
ZOO
ZOO,
}
public static class Definitions
{
public static (FileType, byte[])[] Signatures =
{
public static class Definitions {
public static (FileType, byte[])[] Signatures = {
// Morrowind BSA
(FileType.TES3, new byte[] {0x00, 0x01, 0x00, 0x00}),
@ -459,6 +459,9 @@ public static class Definitions
// DDS
(FileType.DDS, new byte[] {0x44, 0x44, 0x53, 0x20}),
// Bethesda Tar
(FileType. BTAR, new byte[] {0x42, 0x54, 0x41, 0x52}),
// JPEG2000 image files
(FileType.JP2, new byte[] {0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20}),
@ -481,12 +484,7 @@ public static class Definitions
(FileType.TBI, new byte[] {0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00}),
// Bitcoin Core wallet.dat file
(FileType.DAT,
new byte[]
{
0x00, 0x00, 0x00, 0x00, 0x62, 0x31, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}),
(FileType.DAT, new byte[] {0x00, 0x00, 0x00, 0x00, 0x62, 0x31, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
// MPEG-4 video_1
(FileType._3GP5, new byte[] {0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70}),
@ -534,11 +532,7 @@ public static class Definitions
(FileType.CUR, new byte[] {0x00, 0x00, 0x02, 0x00}),
// Compucon-Singer embroidery design file
(FileType.XXX,
new byte[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}),
(FileType.XXX, new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
// QuattroPro spreadsheet
(FileType.WB2, new byte[] {0x00, 0x00, 0x02, 0x00}),
@ -574,28 +568,13 @@ public static class Definitions
(FileType.TTF, new byte[] {0x00, 0x01, 0x00, 0x00, 0x00}),
// Microsoft Money file
(FileType.MNY,
new byte[]
{
0x00, 0x01, 0x00, 0x00, 0x4D, 0x53, 0x49, 0x53, 0x41, 0x4D, 0x20, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61,
0x73, 0x65
}),
(FileType.MNY, new byte[] {0x00, 0x01, 0x00, 0x00, 0x4D, 0x53, 0x49, 0x53, 0x41, 0x4D, 0x20, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65}),
// Microsoft Access 2007
(FileType.ACCDB,
new byte[]
{
0x00, 0x01, 0x00, 0x00, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x41, 0x43, 0x45, 0x20,
0x44, 0x42
}),
(FileType.ACCDB, new byte[] {0x00, 0x01, 0x00, 0x00, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x41, 0x43, 0x45, 0x20, 0x44, 0x42}),
// Microsoft Access
(FileType.MDB,
new byte[]
{
0x00, 0x01, 0x00, 0x00, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x4A, 0x65, 0x74, 0x20,
0x44, 0x42
}),
(FileType.MDB, new byte[] {0x00, 0x01, 0x00, 0x00, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x4A, 0x65, 0x74, 0x20, 0x44, 0x42}),
// Palm Address Book Archive
(FileType.ABA, new byte[] {0x00, 0x01, 0x42, 0x41}),
@ -604,11 +583,7 @@ public static class Definitions
(FileType.DBA, new byte[] {0x00, 0x01, 0x42, 0x44}),
// Netscape Navigator (v4) database
(FileType.DB,
new byte[]
{
0x00, 0x06, 0x15, 0x61, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0xD2, 0x00, 0x00, 0x10, 0x00
}),
(FileType.DB, new byte[] {0x00, 0x06, 0x15, 0x61, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0xD2, 0x00, 0x00, 0x10, 0x00}),
// FLIC animation
(FileType.FLI, new byte[] {0x00, 0x11}),
@ -662,11 +637,7 @@ public static class Definitions
(FileType.DB4, new byte[] {0x04}),
// Adobe InDesign
(FileType.INDD,
new byte[]
{
0x06, 0x06, 0xED, 0xF5, 0xD8, 0x1D, 0x46, 0xE5, 0xBD, 0x31, 0xEF, 0xE7, 0xFE, 0x74, 0xB7, 0x1D
}),
(FileType.INDD, new byte[] {0x06, 0x06, 0xED, 0xF5, 0xD8, 0x1D, 0x46, 0xE5, 0xBD, 0x31, 0xEF, 0xE7, 0xFE, 0x74, 0xB7, 0x1D}),
// Material Exchange Format
(FileType.MXF, new byte[] {0x06, 0x0E, 0x2B, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0D, 0x01, 0x02, 0x01, 0x01, 0x02}),
@ -696,11 +667,7 @@ public static class Definitions
(FileType.PCX, new byte[] {0x0A, 0x05, 0x01, 0x01}),
// MultiBit Bitcoin wallet file
(FileType.WALLET,
new byte[]
{
0x0A, 0x16, 0x6F, 0x72, 0x67, 0x2E, 0x62, 0x69, 0x74, 0x63, 0x6F, 0x69, 0x6E, 0x2E, 0x70, 0x72
}),
(FileType.WALLET, new byte[] {0x0A, 0x16, 0x6F, 0x72, 0x67, 0x2E, 0x62, 0x69, 0x74, 0x63, 0x6F, 0x69, 0x6E, 0x2E, 0x70, 0x72}),
// Monochrome Picture TIFF bitmap
(FileType.MP, new byte[] {0x0C, 0xED}),
@ -865,12 +832,7 @@ public static class Definitions
(FileType.AU, new byte[] {0x2E, 0x73, 0x6E, 0x64}),
// Thunderbird-Mozilla Mail Summary File
(FileType.MSF,
new byte[]
{
0x2F, 0x2F, 0x20, 0x3C, 0x21, 0x2D, 0x2D, 0x20, 0x3C, 0x6D, 0x64, 0x62, 0x3A, 0x6D, 0x6F, 0x72, 0x6B,
0x3A, 0x7A
}),
(FileType.MSF, new byte[] {0x2F, 0x2F, 0x20, 0x3C, 0x21, 0x2D, 0x2D, 0x20, 0x3C, 0x6D, 0x64, 0x62, 0x3A, 0x6D, 0x6F, 0x72, 0x6B, 0x3A, 0x7A}),
// MS security catalog file
(FileType.CAT, new byte[] {0x30}),
@ -900,11 +862,7 @@ public static class Definitions
(FileType.WRI, new byte[] {0x32, 0xBE}),
// Pfaff Home Embroidery
(FileType.PCS,
new byte[]
{
0x32, 0x03, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xFF, 0x00
}),
(FileType.PCS, new byte[] {0x32, 0x03, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xFF, 0x00}),
// 7-Zip compressed file
(FileType._7Z, new byte[] {0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C}),
@ -928,40 +886,19 @@ public static class Definitions
(FileType.WSC, new byte[] {0x3C, 0x3F}),
// Windows Visual Stylesheet
(FileType.MANIFEST,
new byte[] {0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D}),
(FileType.MANIFEST, new byte[] {0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D}),
// User Interface Language
(FileType.XML,
new byte[]
{
0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E,
0x30, 0x22, 0x3F, 0x3E
}),
(FileType.XML, new byte[] {0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E, 0x30, 0x22, 0x3F, 0x3E}),
// MMC Snap-in Control file
(FileType.MSC,
new byte[]
{
0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E,
0x30, 0x22, 0x3F, 0x3E, 0x0D, 0x0A, 0x3C, 0x4D, 0x4D, 0x43, 0x5F, 0x43, 0x6F, 0x6E, 0x73, 0x6F, 0x6C,
0x65, 0x46, 0x69, 0x6C, 0x65, 0x20, 0x43, 0x6F, 0x6E, 0x73, 0x6F, 0x6C, 0x65, 0x56, 0x65, 0x72, 0x73,
0x69, 0x6F, 0x6E, 0x3D, 0x22
}),
(FileType.MSC, new byte[] {0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E, 0x30, 0x22, 0x3F, 0x3E, 0x0D, 0x0A, 0x3C, 0x4D, 0x4D, 0x43, 0x5F, 0x43, 0x6F, 0x6E, 0x73, 0x6F, 0x6C, 0x65, 0x46, 0x69, 0x6C, 0x65, 0x20, 0x43, 0x6F, 0x6E, 0x73, 0x6F, 0x6C, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22}),
// Picasa movie project file
(FileType.MXF,
new byte[]
{
0x3C, 0x43, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x54, 0x69, 0x6D, 0x65, 0x6C, 0x69, 0x6E, 0x65, 0x3E
}),
(FileType.MXF, new byte[] {0x3C, 0x43, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x54, 0x69, 0x6D, 0x65, 0x6C, 0x69, 0x6E, 0x65, 0x3E}),
// Csound music
(FileType.CSD,
new byte[]
{
0x3C, 0x43, 0x73, 0x6F, 0x75, 0x6E, 0x64, 0x53, 0x79, 0x6E, 0x74, 0x68, 0x65, 0x73, 0x69, 0x7A
}),
(FileType.CSD, new byte[] {0x3C, 0x43, 0x73, 0x6F, 0x75, 0x6E, 0x64, 0x53, 0x79, 0x6E, 0x74, 0x68, 0x65, 0x73, 0x69, 0x7A}),
// Adobe FrameMaker
(FileType.FM, new byte[] {0x3C, 0x4D, 0x61, 0x6B, 0x65, 0x72, 0x46, 0x69}),
@ -970,11 +907,7 @@ public static class Definitions
(FileType.MIF, new byte[] {0x3C, 0x4D, 0x61, 0x6B, 0x65, 0x72, 0x46, 0x69}),
// GPS Exchange (v1.1)
(FileType.GPX,
new byte[]
{
0x3C, 0x67, 0x70, 0x78, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E
}),
(FileType.GPX, new byte[] {0x3C, 0x67, 0x70, 0x78, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E}),
// BASE85 file
(FileType.B85, new byte[] {0x3C, 0x7E, 0x36, 0x3C, 0x5C, 0x25, 0x5F, 0x30, 0x67, 0x53, 0x71, 0x68, 0x3B}),
@ -1142,11 +1075,7 @@ public static class Definitions
(FileType.SWF, new byte[] {0x43, 0x57, 0x53}),
// Calculux Indoor lighting project file
(FileType.CIN,
new byte[]
{
0x43, 0x61, 0x6C, 0x63, 0x75, 0x6C, 0x75, 0x78, 0x20, 0x49, 0x6E, 0x64, 0x6F, 0x6F, 0x72, 0x20
}),
(FileType.CIN, new byte[] {0x43, 0x61, 0x6C, 0x63, 0x75, 0x6C, 0x75, 0x78, 0x20, 0x49, 0x6E, 0x64, 0x6F, 0x6F, 0x72, 0x20}),
// WhereIsIt Catalog
(FileType.CTF, new byte[] {0x43, 0x61, 0x74, 0x61, 0x6C, 0x6F, 0x67, 0x20}),
@ -1158,11 +1087,7 @@ public static class Definitions
(FileType.CRX, new byte[] {0x43, 0x72, 0x32, 0x34}),
// Creative Voice
(FileType.VOC,
new byte[]
{
0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x56, 0x6F, 0x69, 0x63, 0x65, 0x20, 0x46
}),
(FileType.VOC, new byte[] {0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x56, 0x6F, 0x69, 0x63, 0x65, 0x20, 0x46}),
// PowerISO Direct-Access-Archive image
(FileType.DAA, new byte[] {0x44, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00}),
@ -1258,18 +1183,10 @@ public static class Definitions
(FileType.GX2, new byte[] {0x47, 0x58, 0x32}),
// Genetec video archive
(FileType.G64,
new byte[]
{
0x47, 0x65, 0x6E, 0x65, 0x74, 0x65, 0x63, 0x20, 0x4F, 0x6D, 0x6E, 0x69, 0x63, 0x61, 0x73, 0x74
}),
(FileType.G64, new byte[] {0x47, 0x65, 0x6E, 0x65, 0x74, 0x65, 0x63, 0x20, 0x4F, 0x6D, 0x6E, 0x69, 0x63, 0x61, 0x73, 0x74}),
// SAS Transport dataset
(FileType.XPT,
new byte[]
{
0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20, 0x52, 0x45, 0x43, 0x4F, 0x52, 0x44, 0x2A, 0x2A, 0x2A
}),
(FileType.XPT, new byte[] {0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20, 0x52, 0x45, 0x43, 0x4F, 0x52, 0x44, 0x2A, 0x2A, 0x2A}),
// Harvard Graphics presentation file
(FileType.SH3, new byte[] {0x48, 0x48, 0x47, 0x42, 0x31}),
@ -1317,11 +1234,7 @@ public static class Definitions
(FileType.DAT, new byte[] {0x49, 0x6E, 0x6E, 0x6F, 0x20, 0x53, 0x65, 0x74}),
// Inter@ctive Pager Backup (BlackBerry file
(FileType.IPD,
new byte[]
{
0x49, 0x6E, 0x74, 0x65, 0x72, 0x40, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x50, 0x61, 0x67, 0x65
}),
(FileType.IPD, new byte[] {0x49, 0x6E, 0x74, 0x65, 0x72, 0x40, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x50, 0x61, 0x67, 0x65}),
// JARCS compressed archive
(FileType.JAR, new byte[] {0x4A, 0x41, 0x52, 0x43, 0x53, 0x00}),
@ -1375,22 +1288,13 @@ public static class Definitions
(FileType.MAR, new byte[] {0x4D, 0x41, 0x52, 0x43}),
// MATLAB v5 workspace
(FileType.MAT,
new byte[]
{
0x4D, 0x41, 0x54, 0x4C, 0x41, 0x42, 0x20, 0x35, 0x2E, 0x30, 0x20, 0x4D, 0x41, 0x54, 0x2D, 0x66, 0x69,
0x6C, 0x65
}),
(FileType.MAT, new byte[] {0x4D, 0x41, 0x54, 0x4C, 0x41, 0x42, 0x20, 0x35, 0x2E, 0x30, 0x20, 0x4D, 0x41, 0x54, 0x2D, 0x66, 0x69, 0x6C, 0x65}),
// MAr compressed archive
(FileType.MAR, new byte[] {0x4D, 0x41, 0x72, 0x30, 0x00}),
// TargetExpress target file
(FileType.MTE,
new byte[]
{
0x4D, 0x43, 0x57, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6E, 0x6F, 0x67, 0x6F, 0x6C, 0x69, 0x65, 0x73
}),
(FileType.MTE, new byte[] {0x4D, 0x43, 0x57, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6E, 0x6F, 0x67, 0x6F, 0x6C, 0x69, 0x65, 0x73}),
// Windows dump file
(FileType.DMP, new byte[] {0x4D, 0x44, 0x4D, 0x50, 0x93, 0xA7}),
@ -1534,26 +1438,13 @@ public static class Definitions
(FileType.ZAP, new byte[] {0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF}),
// MS C++ debugging symbols file
(FileType.PDB,
new byte[]
{
0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x43, 0x2F, 0x43, 0x2B, 0x2B, 0x20
}),
(FileType.PDB, new byte[] {0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x43, 0x2F, 0x43, 0x2B, 0x2B, 0x20}),
// Visual Studio .NET file
(FileType.SLN,
new byte[]
{
0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x56, 0x69, 0x73, 0x75, 0x61, 0x6C
}),
(FileType.SLN, new byte[] {0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x56, 0x69, 0x73, 0x75, 0x61, 0x6C}),
// Windows Media Player playlist
(FileType.WPL,
new byte[]
{
0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73,
0x20, 0x4D, 0x65, 0x64, 0x69, 0x61, 0x20, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x20, 0x2D, 0x2D, 0x20
}),
(FileType.WPL, new byte[] {0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x4D, 0x65, 0x64, 0x69, 0x61, 0x20, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x20, 0x2D, 0x2D, 0x20}),
// VMapSource GPS Waypoint Database
(FileType.GDB, new byte[] {0x4D, 0x73, 0x52, 0x63, 0x66}),
@ -1751,12 +1642,7 @@ public static class Definitions
(FileType.QSD, new byte[] {0x51, 0x57, 0x20, 0x56, 0x65, 0x72, 0x2E, 0x20}),
// Outlook-Exchange message subheader
(FileType.MSG,
new byte[]
{
0x52, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x74, 0x00, 0x20, 0x00, 0x45, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x72,
0x00, 0x79, 0x00
}),
(FileType.MSG, new byte[] {0x52, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x74, 0x00, 0x20, 0x00, 0x45, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x72, 0x00, 0x79, 0x00}),
// Shareaza (P2P) thumbnail
(FileType.DAT, new byte[] {0x52, 0x41, 0x5A, 0x41, 0x54, 0x44, 0x42, 0x31}),
@ -1840,12 +1726,7 @@ public static class Definitions
(FileType.CPI, new byte[] {0x53, 0x49, 0x45, 0x54, 0x52, 0x4F, 0x4E, 0x49}),
// Flexible Image Transport System (FITS) file
(FileType.FITS,
new byte[]
{
0x53, 0x49, 0x4D, 0x50, 0x4C, 0x45, 0x20, 0x20, 0x3D, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54
}),
(FileType.FITS, new byte[] {0x53, 0x49, 0x4D, 0x50, 0x4C, 0x45, 0x20, 0x20, 0x3D, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54}),
// StuffIt archive
(FileType.SIT, new byte[] {0x53, 0x49, 0x54, 0x21, 0x00}),
@ -1860,11 +1741,7 @@ public static class Definitions
(FileType.SPVB, new byte[] {0x53, 0x50, 0x56, 0x42}),
// SQLite database file
(FileType.DB,
new byte[]
{
0x53, 0x51, 0x4C, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x20, 0x33, 0x00
}),
(FileType.DB, new byte[] {0x53, 0x51, 0x4C, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x20, 0x33, 0x00}),
// DB2 conversion file
(FileType.CNV, new byte[] {0x53, 0x51, 0x4C, 0x4F, 0x43, 0x4F, 0x4E, 0x56}),
@ -1900,11 +1777,7 @@ public static class Definitions
(FileType.MIF, new byte[] {0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20}),
// SPSS template
(FileType.SCT,
new byte[]
{
0x57, 0x04, 0x00, 0x00, 0x53, 0x50, 0x53, 0x53, 0x20, 0x74, 0x65, 0x6D, 0x70, 0x6C, 0x61, 0x74
}),
(FileType.SCT, new byte[] {0x57, 0x04, 0x00, 0x00, 0x53, 0x50, 0x53, 0x53, 0x20, 0x74, 0x65, 0x6D, 0x70, 0x6C, 0x61, 0x74}),
// RIFF Windows Audio
(FileType.WAV, new byte[] {0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20}),
@ -2153,12 +2026,7 @@ public static class Definitions
(FileType.PSP, new byte[] {0x7E, 0x42, 0x4B, 0x00}),
// Easy Street Draw diagram file
(FileType.ESD,
new byte[]
{
0x7E, 0x45, 0x53, 0x44, 0x77, 0xF6, 0x85, 0x3E, 0xBF, 0x6A, 0xD2, 0x11, 0x45, 0x61, 0x73, 0x79, 0x20,
0x53, 0x74, 0x72, 0x65, 0x65, 0x74, 0x20, 0x44, 0x72, 0x61, 0x77
}),
(FileType.ESD, new byte[] {0x7E, 0x45, 0x53, 0x44, 0x77, 0xF6, 0x85, 0x3E, 0xBF, 0x6A, 0xD2, 0x11, 0x45, 0x61, 0x73, 0x79, 0x20, 0x53, 0x74, 0x72, 0x65, 0x65, 0x74, 0x20, 0x44, 0x72, 0x61, 0x77}),
// Digital Watchdog DW-TP-500G audio
(FileType.IMG, new byte[] {0x7E, 0x74, 0x2C, 0x01, 0x50, 0x70, 0x02, 0x4D, 0x52}),
@ -2236,11 +2104,7 @@ public static class Definitions
(FileType.WRI, new byte[] {0xBE, 0x00, 0x00, 0x00, 0xAB}),
// Palm Desktop DateBook
(FileType.DAT,
new byte[]
{
0xBE, 0xBA, 0xFE, 0xCA, 0x0F, 0x50, 0x61, 0x6C, 0x6D, 0x53, 0x47, 0x20, 0x44, 0x61, 0x74, 0x61
}),
(FileType.DAT, new byte[] {0xBE, 0xBA, 0xFE, 0xCA, 0x0F, 0x50, 0x61, 0x6C, 0x6D, 0x53, 0x47, 0x20, 0x44, 0x61, 0x74, 0x61}),
// MS Agent Character file
(FileType.ACS, new byte[] {0xC3, 0xAB, 0xCD, 0xAB}),
@ -2510,6 +2374,7 @@ public static class Definitions
(FileType.MOF, new byte[] {0xFF, 0xFE, 0x23, 0x00, 0x6C, 0x00, 0x69, 0x00}),
// DOS system driver
(FileType.SYS, new byte[] {0xFF, 0xFF, 0xFF, 0xFF})
};
}
(FileType.SYS, new byte[] {0xFF, 0xFF, 0xFF, 0xFF}),
};}}

View File

@ -1,5 +1,8 @@
<#@ template language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#
byte[] StringToByteArray(string hex)

View File

@ -1,9 +1,11 @@
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@ -11,8 +13,10 @@ using OMODFramework;
using Wabbajack.Common;
using Wabbajack.Common.FileSignatures;
using Wabbajack.Compression.BSA;
using Wabbajack.Compression.BSA.FO4Archive;
using Wabbajack.DTOs.Streams;
using Wabbajack.FileExtractor.ExtractedFiles;
using Wabbajack.IO.Async;
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
using Wabbajack.RateLimiter;
@ -24,6 +28,7 @@ public class FileExtractor
public static readonly SignatureChecker ArchiveSigs = new(FileType.TES3,
FileType.BSA,
FileType.BA2,
FileType.BTAR,
FileType.ZIP,
//FileType.EXE,
FileType.RAR_OLD,
@ -43,6 +48,7 @@ public class FileExtractor
new Extension(".7zip"),
new Extension(".rar"),
new Extension(".zip"),
new Extension(".btar"),
OMODExtension,
FOMODExtension
};
@ -98,6 +104,9 @@ public class FileExtractor
break;
}
case FileType.BTAR:
results = await GatheringExtractWithBTAR(sFn, shouldExtract, mapfn, token);
break;
case FileType.BSA:
case FileType.BA2:
@ -120,6 +129,75 @@ public class FileExtractor
return results;
}
private async Task<IDictionary<RelativePath,T>> GatheringExtractWithBTAR<T>
(IStreamFactory sFn, Predicate<RelativePath> shouldExtract, Func<RelativePath,IExtractedFile,ValueTask<T>> mapfn, CancellationToken token)
{
await using var strm = await sFn.GetStream();
var astrm = new AsyncBinaryReader(strm);
var magic = BinaryPrimitives.ReadUInt32BigEndian(await astrm.ReadBytes(4));
// BTAR Magic
if (magic != 0x42544152) throw new Exception("Not a valid BTAR file");
if (await astrm.ReadUInt16() != 1) throw new Exception("Invalid BTAR major version, should be 1");
var minorVersion = await astrm.ReadUInt16();
if (minorVersion is < 2 or > 4) throw new Exception("Invalid BTAR minor version");
var results = new Dictionary<RelativePath, T>();
while (astrm.Position < astrm.Length)
{
var nameLength = await astrm.ReadUInt16();
var name = Encoding.UTF8.GetString(await astrm.ReadBytes(nameLength)).ToRelativePath();
var dataLength = await astrm.ReadUInt64();
var newPos = astrm.Position + (long)dataLength;
if (!shouldExtract(name))
{
astrm.Position += (long)dataLength;
continue;
}
var result = await mapfn(name, new BTARExtractedFile(sFn, name, astrm, astrm.Position, (long) dataLength));
results.Add(name, result);
astrm.Position = newPos;
}
return results;
}
private class BTARExtractedFile : IExtractedFile
{
private readonly IStreamFactory _parent;
private readonly AsyncBinaryReader _rdr;
private readonly long _start;
private readonly long _length;
private readonly RelativePath _name;
public BTARExtractedFile(IStreamFactory parent, RelativePath name, AsyncBinaryReader rdr, long startingPosition, long length)
{
_name = name;
_parent = parent;
_rdr = rdr;
_start = startingPosition;
_length = length;
}
public DateTime LastModifiedUtc => _parent.LastModifiedUtc;
public IPath Name => _name;
public async ValueTask<Stream> GetStream()
{
_rdr.Position = _start;
var data = await _rdr.ReadBytes((int) _length);
return new MemoryStream(data);
}
public bool CanMove { get; set; } = true;
public async ValueTask Move(AbsolutePath newPath, CancellationToken token)
{
await using var output = newPath.Open(FileMode.Create, FileAccess.Read, FileShare.Read);
_rdr.Position = _start;
await _rdr.BaseStream.CopyToLimitAsync(output, (int)_length, token);
}
}
private async Task<Dictionary<RelativePath, T>> GatheringExtractWithOMOD<T>
(Stream archive, Predicate<RelativePath> shouldExtract, Func<RelativePath, IExtractedFile, ValueTask<T>> mapfn,
CancellationToken token)