wabbajack/Compression.BSA/TES3Builder.cs
2020-06-27 11:04:59 -06:00

80 lines
2.4 KiB
C#

using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Wabbajack.Common;
using File = Alphaleonis.Win32.Filesystem.File;
namespace Compression.BSA
{
public class TES3Builder : IBSABuilder
{
private TES3ArchiveState _state;
private (TES3FileState state, Stream data)[] _files;
public TES3Builder(TES3ArchiveState state)
{
_state = state;
_files = new (TES3FileState state, Stream data)[_state.FileCount];
}
public async Task AddFile(FileStateObject state, Stream src)
{
var cstate = (TES3FileState)state;
_files[state.Index] = (cstate, src);
}
public async Task Build(AbsolutePath filename)
{
await using var fs = await filename.Create();
await using var bw = new BinaryWriter(fs);
bw.Write(_state.VersionNumber);
bw.Write(_state.HashOffset);
bw.Write(_state.FileCount);
foreach (var (state, _) in _files)
{
bw.Write(state.Size);
bw.Write(state.Offset);
}
foreach (var (state, _) in _files)
{
bw.Write(state.NameOffset);
}
var orgPos = bw.BaseStream.Position;
foreach (var (state, _) in _files)
{
if (bw.BaseStream.Position != orgPos + state.NameOffset)
throw new InvalidDataException("Offsets don't match when writing TES3 BSA");
bw.Write(Encoding.ASCII.GetBytes((string)state.Path));
bw.Write((byte)0);
}
bw.BaseStream.Position = _state.HashOffset + 12;
foreach (var (state, _) in _files)
{
bw.Write(state.Hash1);
bw.Write(state.Hash2);
}
if (bw.BaseStream.Position != _state.DataOffset)
throw new InvalidDataException("Data offset doesn't match when writing TES3 BSA");
foreach (var (state, data) in _files)
{
bw.BaseStream.Position = _state.DataOffset + state.Offset;
await data.CopyToAsync(bw.BaseStream);
await data.DisposeAsync();
}
}
public async ValueTask DisposeAsync()
{
}
}
}