using System.IO; using System.Threading; using System.Threading.Tasks; using ICSharpCode.SharpZipLib.Zip.Compression; using ICSharpCode.SharpZipLib.Zip.Compression.Streams; using Wabbajack.Common; using Wabbajack.DTOs.BSA.FileStates; namespace Wabbajack.Compression.BSA.FO4Archive; public class ChunkBuilder { private BA2Chunk _chunk; private Stream _dataSlab; private long _offsetOffset; private uint _packSize; public static async Task Create(BA2DX10File state, BA2Chunk chunk, Stream src, DiskSlabAllocator slab, CancellationToken token) { var builder = new ChunkBuilder {_chunk = chunk}; if (!chunk.Compressed) { builder._dataSlab = slab.Allocate(chunk.FullSz); await src.CopyToLimitAsync(builder._dataSlab, (int) chunk.FullSz, token); } else { var deflater = new Deflater(Deflater.BEST_COMPRESSION); await using var ms = new MemoryStream(); await using (var ds = new DeflaterOutputStream(ms, deflater)) { ds.IsStreamOwner = false; await src.CopyToLimitAsync(ds, (int) chunk.FullSz, token); } builder._dataSlab = slab.Allocate(ms.Length); ms.Position = 0; await ms.CopyToLimitAsync(builder._dataSlab, (int) ms.Length, token); builder._packSize = (uint) ms.Length; } builder._dataSlab.Position = 0; return builder; } public void WriteHeader(BinaryWriter bw) { _offsetOffset = bw.BaseStream.Position; bw.Write((ulong) 0); bw.Write(_packSize); bw.Write(_chunk.FullSz); bw.Write(_chunk.StartMip); bw.Write(_chunk.EndMip); bw.Write(_chunk.Align); } public async ValueTask WriteData(BinaryWriter bw, CancellationToken token) { var pos = bw.BaseStream.Position; bw.BaseStream.Position = _offsetOffset; bw.Write((ulong) pos); bw.BaseStream.Position = pos; await _dataSlab.CopyToLimitAsync(bw.BaseStream, (int) _dataSlab.Length, token); await _dataSlab.DisposeAsync(); } }