implement new BSA framework for old BSA routines

This commit is contained in:
Timothy Baldridge 2019-10-08 15:20:43 -06:00
parent ce4a3e17dd
commit 88fa091d07
4 changed files with 104 additions and 21 deletions

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -9,17 +10,24 @@ namespace Compression.BSA.Test
{
internal class Program
{
private const string TestDir = @"D:\MO2 Instances\F4EE";
//private const string TestDirBSA = @"D:\MO2 Instances\F4EE";
//private const string TestDirBA2 = @"D:\MO2 Instances\F4EE";
private const string TestDir = @"D:\MO2 Instances";
//private const string TestDir = @"D:\Steam\steamapps\common\Fallout 4";
private const string TempDir = @"c:\tmp\out\f4ee";
private const string ArchiveTempDir = @"c:\tmp\out\archive";
//private const string Archive2Location = @"D:\Steam\steamapps\common\Fallout 4\Tools\Archive2\Archive2.exe";
private static void Main(string[] args)
{
foreach (var bsa in Directory.EnumerateFiles(TestDir, "*.ba2", SearchOption.AllDirectories).Skip(0))
foreach (var bsa in Directory.EnumerateFiles(TestDir, "*.ba2", SearchOption.AllDirectories)
.Concat(Directory.EnumerateFiles(TestDir, "*.bsa", SearchOption.AllDirectories)).Skip(200))
{
Console.WriteLine($"From {bsa}");
Console.WriteLine("Cleaning Output Dir");
if (Directory.Exists(TempDir)) Directory.Delete(TempDir, true);
if (Directory.Exists(ArchiveTempDir)) Directory.Delete(ArchiveTempDir, true);
Directory.CreateDirectory(TempDir);
Console.WriteLine($"Reading {bsa}");
@ -28,6 +36,7 @@ namespace Compression.BSA.Test
Parallel.ForEach(a.Files, file =>
{
var abs_name = Path.Combine(TempDir, file.Path);
ViaJson(file.State);
if (!Directory.Exists(Path.GetDirectoryName(abs_name)))
Directory.CreateDirectory(Path.GetDirectoryName(abs_name));
@ -43,6 +52,22 @@ namespace Compression.BSA.Test
});
/*
Console.WriteLine("Extracting via Archive.exe");
if (bsa.ToLower().EndsWith(".ba2"))
{
var p = Process.Start(Archive2Location, $"\"{bsa}\" -e=\"{ArchiveTempDir}\"");
p.WaitForExit();
foreach (var file in a.Files)
{
var a_path = Path.Combine(TempDir, file.Path);
var b_path = Path.Combine(ArchiveTempDir, file.Path);
Equal(new FileInfo(a_path).Length, new FileInfo(b_path).Length);
Equal(File.ReadAllBytes(a_path), File.ReadAllBytes(b_path));
}
}*/
Console.WriteLine($"Building {bsa}");
@ -59,9 +84,6 @@ namespace Compression.BSA.Test
});
w.Build("c:\\tmp\\tmp.bsa");
}
Console.WriteLine($"Verifying {bsa}");
@ -163,7 +185,7 @@ namespace Compression.BSA.Test
for (var idx = 0; idx < a.Length; idx++)
if (a[idx] != b[idx])
throw new InvalidDataException($"Byte array contents not equal at {idx}");
throw new InvalidDataException($"Byte array contents not equal at {idx} - {a[idx]} vs {b[idx]}");
}
}
}

View File

@ -250,6 +250,7 @@ namespace Compression.BSA
ddsHeader.dwWidth = _width;
ddsHeader.dwMipMapCount = _numMips;
ddsHeader.PixelFormat.dwSize = ddsHeader.PixelFormat.GetSize();
ddsHeader.dwDepth = 1;
ddsHeader.dwSurfaceFlags = DDS.DDS_SURFACE_FLAGS_TEXTURE | DDS.DDS_SURFACE_FLAGS_MIPMAP;
switch ((DXGI_FORMAT)_format)
@ -274,7 +275,7 @@ namespace Compression.BSA
if (_bsa.UseATIFourCC)
ddsHeader.PixelFormat.dwFourCC = DDS.MAKEFOURCC('A', 'T', 'I', '2'); // this is more correct but the only thing I have found that supports it is the nvidia photoshop plugin
else
ddsHeader.PixelFormat.dwFourCC = DDS.MAKEFOURCC('D', 'X', 'T', '5');
ddsHeader.PixelFormat.dwFourCC = DDS.MAKEFOURCC('B', 'C', '5', 'U');
ddsHeader.dwPitchOrLinearSize = (uint)(_width * _height); // 8bpp
break;
case DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM_SRGB:

View File

@ -11,7 +11,7 @@ using Path = Alphaleonis.Win32.Filesystem.Path;
namespace Compression.BSA
{
public class BSABuilder : IDisposable
public class BSABuilder : IDisposable, IBSABuilder
{
internal uint _archiveFlags;
internal uint _fileCount;
@ -32,6 +32,13 @@ namespace Compression.BSA
_offset = 0x24;
}
public BSABuilder(BSAStateObject bsaStateObject) : this()
{
_version = bsaStateObject.Version;
_fileFlags = bsaStateObject.FileFlags;
_archiveFlags = bsaStateObject.ArchiveFlags;
}
public IEnumerable<FileEntry> Files => _files;
public ArchiveFlags ArchiveFlags
@ -85,6 +92,18 @@ namespace Compression.BSA
return r;
}
public void AddFile(FileStateObject state, Stream src)
{
var ostate = (BSAFileStateObject) state;
var r = new FileEntry(this, ostate.Path, src, ostate.FlipCompression);
lock (this)
{
_files.Add(r);
}
}
public void Build(string outputName)
{
RegenFolderRecords();

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using K4os.Compression.LZ4.Streams;
using File = Alphaleonis.Win32.Filesystem.File;
@ -48,19 +49,19 @@ namespace Compression.BSA
public class BSAReader : IDisposable, IBSAReader
{
private uint _archiveFlags;
private uint _fileCount;
private uint _fileFlags;
internal uint _archiveFlags;
internal uint _fileCount;
internal uint _fileFlags;
internal string _fileName;
private uint _folderCount;
private uint _folderRecordOffset;
internal uint _folderCount;
internal uint _folderRecordOffset;
private List<FolderRecord> _folders;
private string _magic;
internal string _magic;
private readonly BinaryReader _rdr;
private readonly Stream _stream;
private uint _totalFileNameLength;
private uint _totalFolderNameLength;
private uint _version;
internal uint _totalFileNameLength;
internal uint _totalFolderNameLength;
internal uint _version;
public BSAReader(string filename) : this(File.OpenRead(filename))
{
@ -84,7 +85,7 @@ namespace Compression.BSA
}
}
public ArchiveStateObject State { get; }
public ArchiveStateObject State => new BSAStateObject(this);
public VersionType HeaderType => (VersionType) _version;
@ -150,6 +151,29 @@ namespace Compression.BSA
}
}
public class BSAStateObject : ArchiveStateObject
{
public BSAStateObject() { }
public BSAStateObject(BSAReader bsaReader)
{
Magic = bsaReader._magic;
Version = bsaReader._version;
ArchiveFlags = bsaReader._archiveFlags;
FileFlags = bsaReader._fileFlags;
}
public override IBSABuilder MakeBuilder()
{
return new BSABuilder(this);
}
public string Magic { get; set; }
public uint Version { get; set; }
public uint ArchiveFlags { get; set; }
public uint FileFlags { get; set; }
}
public class FolderRecord
{
private readonly uint _fileCount;
@ -181,7 +205,8 @@ namespace Compression.BSA
if (bsa.HasFolderNames) Name = src.ReadStringLen(bsa.HeaderType);
_files = new List<FileRecord>();
for (var idx = 0; idx < _fileCount; idx += 1) _files.Add(new FileRecord(bsa, this, src));
for (var idx = 0; idx < _fileCount; idx += 1)
_files.Add(new FileRecord(bsa, this, src, idx));
}
}
@ -196,9 +221,11 @@ namespace Compression.BSA
private readonly uint _onDiskSize;
private readonly uint _originalSize;
private readonly uint _size;
internal readonly int _index;
public FileRecord(BSAReader bsa, FolderRecord folderRecord, BinaryReader src)
public FileRecord(BSAReader bsa, FolderRecord folderRecord, BinaryReader src, int index)
{
_index = index;
_bsa = bsa;
Hash = src.ReadUInt64();
var size = src.ReadUInt32();
@ -262,7 +289,7 @@ namespace Compression.BSA
}
public uint Size => _dataSize;
public FileStateObject State { get; }
public FileStateObject State => new BSAFileStateObject(this);
public ulong Hash { get; }
@ -314,4 +341,18 @@ namespace Compression.BSA
return ms.ToArray();
}
}
public class BSAFileStateObject : FileStateObject
{
public BSAFileStateObject() { }
public BSAFileStateObject(FileRecord fileRecord)
{
FlipCompression = fileRecord.FlipCompression;
Path = fileRecord.Path;
Index = fileRecord._index;
}
public bool FlipCompression { get; set; }
public string Path { get; set; }
}
}