diff --git a/Compression.BSA.Test/Program.cs b/Compression.BSA.Test/Program.cs index 43515b27..8e55cd88 100644 --- a/Compression.BSA.Test/Program.cs +++ b/Compression.BSA.Test/Program.cs @@ -15,7 +15,7 @@ namespace Compression.BSA.Test private static void Main(string[] args) { - foreach (var bsa in Directory.EnumerateFiles(TestDir, "*.ba2", SearchOption.AllDirectories).Skip(0).Take(1)) + foreach (var bsa in Directory.EnumerateFiles(TestDir, "*.ba2", SearchOption.AllDirectories).Skip(0)) { Console.WriteLine($"From {bsa}"); Console.WriteLine("Cleaning Output Dir"); diff --git a/Compression.BSA/BA2Builder.cs b/Compression.BSA/BA2Builder.cs index 8563f0f3..f520ecdf 100644 --- a/Compression.BSA/BA2Builder.cs +++ b/Compression.BSA/BA2Builder.cs @@ -43,6 +43,10 @@ namespace Compression.BSA var result = new BA2FileEntryBuilder((BA2FileEntryState)state, src); lock(_entries) _entries.Add(result); break; + case EntryType.DX10: + var resultdx10 = new BA2DX10FileEntryBuilder((BA2DX10EntryState)state, src); + lock(_entries) _entries.Add(resultdx10); + break; } } @@ -92,6 +96,92 @@ namespace Compression.BSA } } + public class BA2DX10FileEntryBuilder : IFileBuilder + { + private BA2DX10EntryState _state; + private List _chunks; + + public BA2DX10FileEntryBuilder(BA2DX10EntryState state, Stream src) + { + _state = state; + _chunks = _state.Chunks.Select(ch => new ChunkBuilder(state, ch, src)).ToList(); + } + + public uint FileHash => _state.NameHash; + public uint DirHash => _state.DirHash; + public string FullName => _state.FullName; + public int Index => _state.Index; + + public void WriteHeader(BinaryWriter bw) + { + bw.Write(_state.NameHash); + bw.Write(Encoding.ASCII.GetBytes(_state.Extension)); + bw.Write(_state.DirHash); + bw.Write(_state.Unk8); + bw.Write((byte)_chunks.Count); + bw.Write(_state.ChunkHdrLen); + bw.Write(_state.Height); + bw.Write(_state.Width); + bw.Write(_state.NumMips); + bw.Write(_state.PixelFormat); + bw.Write(_state.Unk16); + + foreach (var chunk in _chunks) + chunk.WriteHeader(bw); + } + + public void WriteData(BinaryWriter wtr) + { + foreach (var chunk in _chunks) + chunk.WriteData(wtr); + } + + } + + public class ChunkBuilder + { + private ChunkState _chunk; + private byte[] _data; + private uint _packSize; + private long _offsetOffset; + + public ChunkBuilder(BA2DX10EntryState state, ChunkState ch, Stream src) + { + _chunk = ch; + _data = new byte[_chunk.FullSz]; + if (_chunk.Compressed) + { + using (var ms = new MemoryStream()) + using (var ds = new DeflaterOutputStream(ms)) + { + ds.Write(_data, 0, _data.Length); + } + _packSize = (uint)_data.Length; + } + } + + 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 void WriteData(BinaryWriter bw) + { + var pos = bw.BaseStream.Position; + bw.BaseStream.Position = _offsetOffset; + bw.Write((ulong)pos); + bw.BaseStream.Position = pos; + bw.Write(_data); + } + } + public class BA2FileEntryBuilder : IFileBuilder { private byte[] _data; diff --git a/Compression.BSA/BA2Reader.cs b/Compression.BSA/BA2Reader.cs index 7115d4b9..2498a337 100644 --- a/Compression.BSA/BA2Reader.cs +++ b/Compression.BSA/BA2Reader.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Drawing; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -10,6 +11,7 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Zip.Compression; +using Microsoft.SqlServer.Server; using File = Alphaleonis.Win32.Filesystem.File; namespace Compression.BSA @@ -85,7 +87,7 @@ namespace Compression.BSA files.Add(new BA2FileEntry(this, idx)); break; case EntryType.DX10: - files.Add(new BA2DX10Entry(this)); + files.Add(new BA2DX10Entry(this, idx)); break; case EntryType.GNMF: break; @@ -139,21 +141,22 @@ namespace Compression.BSA public class BA2DX10Entry : IFileEntry { - private uint _nameHash; - private string _extension; - private uint _dirHash; - private byte _unk8; - private byte _numChunks; - private ushort _chunkHdrLen; - private ushort _height; - private ushort _width; - private byte _numMips; - private byte _format; - private ushort _unk16; - private List _chunks; + internal uint _nameHash; + internal string _extension; + internal uint _dirHash; + internal byte _unk8; + internal byte _numChunks; + internal ushort _chunkHdrLen; + internal ushort _height; + internal ushort _width; + internal byte _numMips; + internal byte _format; + internal ushort _unk16; + internal List _chunks; private BA2Reader _bsa; + internal int _index; - public BA2DX10Entry(BA2Reader ba2Reader) + public BA2DX10Entry(BA2Reader ba2Reader, int idx) { _bsa = ba2Reader; var _rdr = ba2Reader._rdr; @@ -169,9 +172,10 @@ namespace Compression.BSA _numMips = _rdr.ReadByte(); _format = _rdr.ReadByte(); _unk16 = _rdr.ReadUInt16(); + _index = idx; _chunks = Enumerable.Range(0, _numChunks) - .Select(idx => new BA2TextureChunk(_rdr)) + .Select(_ => new BA2TextureChunk(_rdr)) .ToList(); } @@ -180,7 +184,7 @@ namespace Compression.BSA public string Path => FullPath; public uint Size => (uint)_chunks.Sum(f => f._fullSz) + HeaderSize + sizeof(uint); - public FileStateObject State { get; } + public FileStateObject State => new BA2DX10EntryState(this); public uint HeaderSize { @@ -344,6 +348,70 @@ namespace Compression.BSA } } + public class BA2DX10EntryState : FileStateObject + { + public BA2DX10EntryState() { } + public BA2DX10EntryState(BA2DX10Entry ba2Dx10Entry) + { + FullName = ba2Dx10Entry.FullPath; + NameHash = ba2Dx10Entry._nameHash; + Extension = ba2Dx10Entry._extension; + DirHash = ba2Dx10Entry._dirHash; + Unk8 = ba2Dx10Entry._unk8; + ChunkHdrLen = ba2Dx10Entry._chunkHdrLen; + Height = ba2Dx10Entry._height; + Width = ba2Dx10Entry._width; + NumMips = ba2Dx10Entry._numMips; + PixelFormat = ba2Dx10Entry._format; + Unk16 = ba2Dx10Entry._unk16; + Index = ba2Dx10Entry._index; + Chunks = ba2Dx10Entry._chunks.Select(ch => new ChunkState(ch)).ToList(); + } + + public string FullName { get; set; } + + public List Chunks { get; set; } + + public ushort Unk16 { get; set; } + + public byte PixelFormat { get; set; } + + public byte NumMips { get; set; } + + public ushort Width { get; set; } + + public ushort Height { get; set; } + + public ushort ChunkHdrLen { get; set; } + + public byte Unk8 { get; set; } + + public uint DirHash { get; set; } + + public string Extension { get; set; } + + public uint NameHash { get; set; } + } + + public class ChunkState + { + public ChunkState() {} + public ChunkState(BA2TextureChunk ch) + { + FullSz = ch._fullSz; + StartMip = ch._startMip; + EndMip = ch._endMip; + Align = ch._align; + Compressed = ch._packSz != null; + } + + public bool Compressed { get; set; } + public uint Align { get; set; } + public ushort EndMip { get; set; } + public ushort StartMip { get; set; } + public uint FullSz { get; set; } + } + public class BA2TextureChunk { internal ulong _offset; diff --git a/Compression.BSA/Compression.BSA.csproj b/Compression.BSA/Compression.BSA.csproj index 531e1e71..6d8c5470 100644 --- a/Compression.BSA/Compression.BSA.csproj +++ b/Compression.BSA/Compression.BSA.csproj @@ -74,6 +74,7 @@ ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll