wabbajack/Compression.BSA/BSA/Reader/FolderRecord.cs

94 lines
3.0 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 System.Text;
using NativeImport;
using Wabbajack.Common;
2020-08-11 12:15:03 +00:00
using File = Alphaleonis.Win32.Filesystem.File;
namespace Compression.BSA
{
public class FolderRecord
{
internal readonly BSAReader BSA;
private readonly ReadOnlyMemorySlice<byte> _data;
internal Lazy<FileRecord[]> _files;
private ReadOnlyMemorySlice<byte>? _nameData;
private int _prevFileCount;
internal FileNameBlock FileNameBlock;
private readonly Lazy<string> _name;
2020-08-11 12:15:03 +00:00
public int Index { get; }
public string Name => _name.Value;
2020-08-11 12:15:03 +00:00
internal FolderRecord(BSAReader bsa, ReadOnlyMemorySlice<byte> data, int index)
{
BSA = bsa;
_data = data;
Index = index;
_name = new Lazy<string>(
() => _nameData.HasValue ? _nameData.Value.ReadStringTerm(BSA.HeaderType) : string.Empty,
isThreadSafe: true);
}
private bool IsLongform => BSA.HeaderType == VersionType.SSE;
public ulong Hash => BinaryPrimitives.ReadUInt64LittleEndian(_data);
public uint FileCount => BinaryPrimitives.ReadUInt32LittleEndian(_data.Slice(0x8));
public uint Unknown => IsLongform ?
BinaryPrimitives.ReadUInt32LittleEndian(_data.Slice(0xC)) :
0;
public ulong Offset => IsLongform ?
BinaryPrimitives.ReadUInt64LittleEndian(_data.Slice(0x10)) :
BinaryPrimitives.ReadUInt32LittleEndian(_data.Slice(0xC));
public static int HeaderLength(VersionType version)
{
return version switch
{
VersionType.SSE => 0x18,
_ => 0x10,
};
}
2020-08-11 12:15:03 +00:00
internal void ProcessFileRecordHeadersBlock(BinaryReader rdr, int fileCountTally)
2020-08-11 12:15:03 +00:00
{
_prevFileCount = fileCountTally;
var totalFileLen = checked((int)(FileCount * FileRecord.HeaderLength));
ReadOnlyMemorySlice<byte> data;
if (BSA.HasFolderNames)
2020-08-11 12:15:03 +00:00
{
var len = rdr.ReadByte();
data = rdr.ReadBytes(len + totalFileLen);
_nameData = data.Slice(0, len);
data = data.Slice(len);
2020-08-11 12:15:03 +00:00
}
else
{
data = rdr.ReadBytes(totalFileLen);
2020-08-11 12:15:03 +00:00
}
_files = new Lazy<FileRecord[]>(
isThreadSafe: true,
valueFactory: () => ParseFileRecords(data));
2020-08-11 12:15:03 +00:00
}
private FileRecord[] ParseFileRecords(ReadOnlyMemorySlice<byte> data)
2020-08-11 12:15:03 +00:00
{
var fileCount = FileCount;
var ret = new FileRecord[fileCount];
for (var idx = 0; idx < fileCount; idx += 1)
{
var fileData = data.Slice(idx * FileRecord.HeaderLength, FileRecord.HeaderLength);
ret[idx] = new FileRecord(this, fileData, idx, idx + _prevFileCount, FileNameBlock);
}
return ret;
2020-08-11 12:15:03 +00:00
}
}
}