wabbajack/Wabbajack.Compression.BSA/BA2Archive/FileEntryBuilder.cs
trawzified a545cb375a
Add Starfield support (#2589)
* Add support for new Starfield BA2 versions

* Add Starfield BA2 LZ4 texture compression support (WIP, not finished)

* Work on replacing DDS.cs with DirectXTexUtility

* Fix reading Starfield BA2s with new DirectXTexUtil

* Fix builder not exporting new Starfield header options

* Fix writing LZ4 chunks in frame format instead of block format

* Rename FO4Archive to BA2Archive, merge SFArchive and FO4Archive

* Clean up testing code & CLI launch settings

* Update changelog
2024-06-17 12:10:53 -06:00

76 lines
2.3 KiB
C#

using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using Wabbajack.Common;
using Wabbajack.DTOs.BSA.FileStates;
namespace Wabbajack.Compression.BSA.BA2Archive;
public class FileEntryBuilder : IFileBuilder
{
private Stream _dataSrc;
private long _offsetOffset;
private int _rawSize;
private int _size;
private BA2File _state;
public uint FileHash => _state.NameHash;
public uint DirHash => _state.DirHash;
public string FullName => (string) _state.Path;
public int Index => _state.Index;
public void WriteHeader(BinaryWriter wtr, CancellationToken token)
{
wtr.Write(_state.NameHash);
wtr.Write(Encoding.UTF8.GetBytes(_state.Extension));
wtr.Write(_state.DirHash);
wtr.Write(_state.Flags);
_offsetOffset = wtr.BaseStream.Position;
wtr.Write((ulong) 0);
wtr.Write(_size);
wtr.Write(_rawSize);
wtr.Write(_state.Align);
}
public async ValueTask WriteData(BinaryWriter wtr, CancellationToken token)
{
var pos = wtr.BaseStream.Position;
wtr.BaseStream.Position = _offsetOffset;
wtr.Write((ulong) pos);
wtr.BaseStream.Position = pos;
_dataSrc.Position = 0;
await _dataSrc.CopyToLimitAsync(wtr.BaseStream, (int) _dataSrc.Length, token);
await _dataSrc.DisposeAsync();
}
public static async ValueTask<FileEntryBuilder> Create(BA2File state, Stream src, DiskSlabAllocator slab,
CancellationToken token)
{
var builder = new FileEntryBuilder
{
_state = state,
_rawSize = (int) src.Length,
_dataSrc = src
};
if (!state.Compressed)
return builder;
await using var ms = new MemoryStream();
await using (var ds = new DeflaterOutputStream(ms))
{
ds.IsStreamOwner = false;
await builder._dataSrc.CopyToAsync(ds, token);
}
await builder._dataSrc.DisposeAsync();
builder._dataSrc = slab.Allocate(ms.Length);
ms.Position = 0;
await ms.CopyToAsync(builder._dataSrc, token);
builder._dataSrc.Position = 0;
builder._size = (int) ms.Length;
return builder;
}
}