wabbajack/Wabbajack.Compression.BSA/TES5Archive/FolderRecord.cs

85 lines
2.5 KiB
C#
Raw Normal View History

2020-08-11 12:15:03 +00:00
using System;
using System.Buffers.Binary;
2020-08-11 12:15:03 +00:00
using System.Collections.Generic;
using System.IO;
using Wabbajack.Common;
2020-08-11 12:15:03 +00:00
2021-10-23 16:51:17 +00:00
namespace Wabbajack.Compression.BSA.TES5Archive;
public class FolderRecord
2020-08-11 12:15:03 +00:00
{
2021-10-23 16:51:17 +00:00
private readonly ReadOnlyMemorySlice<byte> _data;
internal readonly Reader BSA;
internal Lazy<FileRecord[]> _files = null!;
private int _prevFileCount;
internal FileNameBlock FileNameBlock = null!;
internal FolderRecord(Reader bsa, ReadOnlyMemorySlice<byte> data, int index)
2020-08-11 12:15:03 +00:00
{
2021-10-23 16:51:17 +00:00
BSA = bsa;
_data = data;
Index = index;
}
2020-08-11 12:15:03 +00:00
2021-10-23 16:51:17 +00:00
internal int Index { get; }
public string? Name { get; private set; }
2021-10-23 16:51:17 +00:00
public IEnumerable<FileRecord> Files => _files.Value;
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
private bool IsLongform => BSA.HeaderType == VersionType.SSE;
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public ulong Hash => BinaryPrimitives.ReadUInt64LittleEndian(_data);
2021-10-23 16:51:17 +00:00
public int FileCount => checked((int) BinaryPrimitives.ReadUInt32LittleEndian(_data.Slice(0x8)));
2021-10-23 16:51:17 +00:00
public uint Unknown => IsLongform ? BinaryPrimitives.ReadUInt32LittleEndian(_data.Slice(0xC)) : 0;
2021-10-23 16:51:17 +00:00
public ulong Offset => IsLongform
? BinaryPrimitives.ReadUInt64LittleEndian(_data.Slice(0x10))
: BinaryPrimitives.ReadUInt32LittleEndian(_data.Slice(0xC));
2021-10-23 16:51:17 +00:00
public static int HeaderLength(VersionType version)
{
return version switch
{
VersionType.SSE => 0x18,
_ => 0x10
};
}
2021-10-23 16:51:17 +00:00
internal void ProcessFileRecordHeadersBlock(BinaryReader rdr, int fileCountTally)
{
_prevFileCount = fileCountTally;
var totalFileLen = checked(FileCount * FileRecord.HeaderLength);
ReadOnlyMemorySlice<byte> data;
if (BSA.HasFolderNames)
{
2021-10-23 16:51:17 +00:00
var len = rdr.ReadByte();
data = rdr.ReadBytes(len + totalFileLen);
Name = data.Slice(0, len).ReadStringTerm(BSA.HeaderType);
data = data.Slice(len);
}
2021-10-23 16:51:17 +00:00
else
2020-08-11 12:15:03 +00:00
{
2021-10-23 16:51:17 +00:00
data = rdr.ReadBytes(totalFileLen);
2020-08-11 12:15:03 +00:00
}
2021-10-23 16:51:17 +00:00
_files = new Lazy<FileRecord[]>(
isThreadSafe: true,
valueFactory: () => ParseFileRecords(data));
}
private FileRecord[] ParseFileRecords(ReadOnlyMemorySlice<byte> data)
{
var fileCount = FileCount;
var ret = new FileRecord[fileCount];
for (var idx = 0; idx < fileCount; idx += 1)
2020-08-11 12:15:03 +00:00
{
2021-10-23 16:51:17 +00:00
var fileData = data.Slice(idx * FileRecord.HeaderLength, FileRecord.HeaderLength);
ret[idx] = new FileRecord(this, fileData, idx, idx + _prevFileCount, FileNameBlock);
2020-08-11 12:15:03 +00:00
}
2021-10-23 16:51:17 +00:00
return ret;
2020-08-11 12:15:03 +00:00
}
2021-09-27 12:42:46 +00:00
}