From 39e1a20741e3fac0dc623d4db2be95323b2b4a11 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Mon, 29 Jul 2019 15:24:05 -0600 Subject: [PATCH] more bug fixes, can recompress 3DNPCs and a bunch of other BSAs --- Compression.BSA.Test/Program.cs | 25 +++++++++++++++-- Compression.BSA/BSABuilder.cs | 49 +++++++++++++++++++++++++++++++-- Compression.BSA/BSAReader.cs | 28 ++++++++++++++++++- Compression.BSA/Utils.cs | 2 +- 4 files changed, 97 insertions(+), 7 deletions(-) diff --git a/Compression.BSA.Test/Program.cs b/Compression.BSA.Test/Program.cs index e035e6c5..72d4b882 100644 --- a/Compression.BSA.Test/Program.cs +++ b/Compression.BSA.Test/Program.cs @@ -45,6 +45,14 @@ namespace Compression.BSA.Test w.Build("c:\\tmp\\built.bsa"); + Equal(a.Files.Count(), w.Files.Count()); + Equal(a.Files.Select(f => f.Path).ToHashSet(), w.Files.Select(f => f.Path).ToHashSet()); + + foreach (var pair in Enumerable.Zip(a.Files, w.Files, (ai, bi) => (ai, bi))) + { + Equal(pair.ai.Path, pair.bi.Path); + } + } using (var b = new BSAReader("c:\\tmp\\built.bsa")) @@ -59,11 +67,11 @@ namespace Compression.BSA.Test foreach (var pair in Enumerable.Zip(a.Files, b.Files, (ai, bi) => (ai, bi))) { idx ++; - Console.WriteLine($" - {pair.ai.Path}"); + //Console.WriteLine($" - {pair.ai.Path}"); Equal(pair.ai.Path, pair.bi.Path); Equal(pair.ai.Compressed, pair.bi.Compressed); Equal(pair.ai.Size, pair.bi.Size); - //Equal(pair.ai.GetData(), pair.bi.GetData()); + Equal(pair.ai.GetData(), pair.bi.GetData()); } } @@ -72,6 +80,19 @@ namespace Compression.BSA.Test } } + private static void Equal(HashSet a, HashSet b) + { + Equal(a.Count, b.Count); + + foreach (var itm in a) + Equal(b.Contains(itm)); + + } + + private static void Equal(bool v) + { + if (!v) throw new InvalidDataException("False"); + } public static void Equal(uint a, uint b) { diff --git a/Compression.BSA/BSABuilder.cs b/Compression.BSA/BSABuilder.cs index 87ca1431..4139b087 100644 --- a/Compression.BSA/BSABuilder.cs +++ b/Compression.BSA/BSABuilder.cs @@ -30,6 +30,14 @@ namespace Compression.BSA _offset = 0x24; } + public IEnumerable Files + { + get + { + return _files; + } + } + public ArchiveFlags ArchiveFlags { get @@ -193,6 +201,7 @@ namespace Compression.BSA public class FolderRecordBuilder { internal IEnumerable _files; + private string _name; internal BSABuilder _bsa; internal ulong _hash; internal uint _fileCount; @@ -200,6 +209,22 @@ namespace Compression.BSA internal uint _recordSize; internal ulong _offset; + public ulong Hash + { + get + { + return _hash; + } + } + + public string Name + { + get + { + return _name; + } + } + public ulong SelfSize { get @@ -230,8 +255,10 @@ namespace Compression.BSA public FolderRecordBuilder(BSABuilder bsa, string folderName, IEnumerable files) { _files = files.OrderBy(f => f._hash); + _name = folderName.ToLowerInvariant(); _bsa = bsa; - _hash = folderName.GetBSAHash(); + // Folders don't have extensions, so let's make sure we cut it out + _hash = _name.GetBSAHash(""); _fileCount = (uint)files.Count(); _nameBytes = folderName.ToBZString(); _recordSize = sizeof(ulong) + sizeof(uint) + sizeof(uint); @@ -299,9 +326,11 @@ namespace Compression.BSA if (_bsa.HeaderType == VersionType.SSE) { var r = new MemoryStream(); - var w = LZ4Stream.Encode(r); - (new MemoryStream(_rawData)).CopyTo(w); + using (var w = LZ4Stream.Encode(r)) + (new MemoryStream(_rawData)).CopyTo(w); + _rawData = r.ToArray(); + } } @@ -336,6 +365,20 @@ namespace Compression.BSA } } + public ulong Hash { get + { + return _hash; + } + } + + public FolderRecordBuilder Folder + { + get + { + return _folder; + } + } + internal void WriteFileRecord(BinaryWriter wtr) { diff --git a/Compression.BSA/BSAReader.cs b/Compression.BSA/BSAReader.cs index e12d7b9e..88cbd141 100644 --- a/Compression.BSA/BSAReader.cs +++ b/Compression.BSA/BSAReader.cs @@ -218,6 +218,13 @@ namespace Compression.BSA } public string Name { get; private set; } + public ulong Hash + { + get + { + return _nameHash; + } + } internal void LoadFileRecordBlock(BSAReader bsa, BinaryReader src) { @@ -293,7 +300,22 @@ namespace Compression.BSA return _size; } } - + + public ulong Hash { + get + { + return _hash; + } + } + + public FolderRecord Folder + { + get + { + return _folder; + } + } + public void CopyDataTo(Stream output) { using (var in_file = File.OpenRead(_bsa._fileName)) @@ -314,6 +336,10 @@ namespace Compression.BSA var original_size = rdr.ReadUInt32(); if (_bsa.HeaderType == VersionType.SSE) { + var settings = new LZ4DecoderSettings() + { + ExtraMemory = 1024 * 1024 * 8 + }; var r = LZ4Stream.Decode(rdr.BaseStream); r.CopyTo(output); } diff --git a/Compression.BSA/Utils.cs b/Compression.BSA/Utils.cs index b917031e..dc225bc3 100644 --- a/Compression.BSA/Utils.cs +++ b/Compression.BSA/Utils.cs @@ -80,7 +80,7 @@ namespace Compression.BSA return GetBSAHash(Path.ChangeExtension(name, null), Path.GetExtension(name)); } - private static ulong GetBSAHash(string name, string ext) + public static ulong GetBSAHash(this string name, string ext) { name = name.ToLowerInvariant(); ext = ext.ToLowerInvariant();