2020-02-19 23:50:12 +00:00
|
|
|
using System.IO;
|
|
|
|
using System.Text;
|
2021-09-27 12:42:46 +00:00
|
|
|
using System.Threading;
|
2020-04-17 03:52:19 +00:00
|
|
|
using System.Threading.Tasks;
|
2020-03-25 22:30:43 +00:00
|
|
|
using Wabbajack.Common;
|
2021-09-27 12:42:46 +00:00
|
|
|
using Wabbajack.Compression.BSA.Interfaces;
|
|
|
|
using Wabbajack.DTOs.BSA.ArchiveStates;
|
|
|
|
using Wabbajack.DTOs.BSA.FileStates;
|
2020-02-19 23:50:12 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
namespace Wabbajack.Compression.BSA.TES3Archive;
|
|
|
|
|
|
|
|
public class Builder : IBuilder
|
2020-02-19 23:50:12 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
private readonly (TES3File state, Stream data)[] _files;
|
|
|
|
private readonly TES3State _state;
|
2020-02-19 23:50:12 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public Builder(TES3State state)
|
|
|
|
{
|
|
|
|
_state = state;
|
|
|
|
_files = new (TES3File state, Stream data)[_state.FileCount];
|
|
|
|
}
|
2020-02-19 23:50:12 +00:00
|
|
|
|
2022-10-07 22:14:01 +00:00
|
|
|
public ValueTask AddFile(AFile state, Stream src, CancellationToken token)
|
2021-10-23 16:51:17 +00:00
|
|
|
{
|
|
|
|
var tesState = (TES3File) state;
|
|
|
|
_files[state.Index] = (tesState, src);
|
2022-10-07 22:14:01 +00:00
|
|
|
return ValueTask.CompletedTask;
|
2021-10-23 16:51:17 +00:00
|
|
|
}
|
2020-02-19 23:50:12 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public async ValueTask Build(Stream file, CancellationToken token)
|
|
|
|
{
|
|
|
|
await using var bw = new BinaryWriter(file, Encoding.Default, true);
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
bw.Write(_state.VersionNumber);
|
|
|
|
bw.Write(_state.HashOffset);
|
|
|
|
bw.Write(_state.FileCount);
|
2020-02-19 23:50:12 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
foreach (var (state, _) in _files)
|
|
|
|
{
|
|
|
|
bw.Write(state.Size);
|
|
|
|
bw.Write(state.Offset);
|
|
|
|
}
|
2020-02-19 23:50:12 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
foreach (var (state, _) in _files) bw.Write(state.NameOffset);
|
2020-02-19 23:50:12 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
var orgPos = bw.BaseStream.Position;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
foreach (var (state, _) in _files)
|
|
|
|
{
|
|
|
|
if (bw.BaseStream.Position != orgPos + state.NameOffset)
|
|
|
|
throw new BSAException("Offsets don't match when writing TES3 BSA");
|
|
|
|
bw.Write(Encoding.ASCII.GetBytes((string) state.Path));
|
|
|
|
bw.Write((byte) 0);
|
|
|
|
}
|
2020-02-19 23:50:12 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
bw.BaseStream.Position = _state.HashOffset + 12;
|
|
|
|
foreach (var (state, _) in _files)
|
|
|
|
{
|
|
|
|
bw.Write(state.Hash1);
|
|
|
|
bw.Write(state.Hash2);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
if (bw.BaseStream.Position != _state.DataOffset)
|
|
|
|
throw new InvalidDataException("Data offset doesn't match when writing TES3 BSA");
|
2020-02-19 23:50:12 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
foreach (var (state, data) in _files)
|
|
|
|
{
|
|
|
|
bw.BaseStream.Position = _state.DataOffset + state.Offset;
|
|
|
|
await data.CopyToWithStatusAsync(data.Length, bw.BaseStream, token);
|
|
|
|
await data.DisposeAsync();
|
2020-02-19 23:50:12 +00:00
|
|
|
}
|
|
|
|
}
|
2022-06-08 03:48:13 +00:00
|
|
|
|
2022-10-07 22:57:12 +00:00
|
|
|
public ValueTask DisposeAsync()
|
2022-06-08 03:48:13 +00:00
|
|
|
{
|
2022-10-07 22:57:12 +00:00
|
|
|
return ValueTask.CompletedTask;
|
2022-06-08 03:48:13 +00:00
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|