2021-09-27 12:42:46 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
|
|
|
using System.Text;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using Wabbajack.Compression.BSA.Interfaces;
|
|
|
|
using Wabbajack.DTOs.BSA.ArchiveStates;
|
|
|
|
using Wabbajack.DTOs.Streams;
|
|
|
|
|
2024-06-17 18:10:53 +00:00
|
|
|
namespace Wabbajack.Compression.BSA.BA2Archive;
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
public class Reader : IReader
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
private readonly Stream _stream;
|
|
|
|
internal string _headerMagic;
|
|
|
|
internal ulong _nameTableOffset;
|
|
|
|
internal uint _numFiles;
|
2024-06-17 18:10:53 +00:00
|
|
|
internal uint _unknown1;
|
|
|
|
internal uint _unknown2;
|
|
|
|
internal uint _compression;
|
2021-10-23 16:51:17 +00:00
|
|
|
internal BinaryReader _rdr;
|
|
|
|
public IStreamFactory _streamFactory;
|
|
|
|
internal BA2EntryType _type;
|
2024-06-17 18:10:53 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Fallout 4 - Version 1, 7 or 8
|
|
|
|
/// Starfield - Version 2 or 3
|
|
|
|
/// </summary>
|
2021-10-23 16:51:17 +00:00
|
|
|
internal uint _version;
|
|
|
|
|
|
|
|
private Reader(Stream stream)
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
_stream = stream;
|
|
|
|
_rdr = new BinaryReader(_stream, Encoding.UTF8);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public bool UseATIFourCC { get; set; } = false;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public bool HasNameTable => _nameTableOffset > 0;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public IEnumerable<IFile> Files { get; private set; }
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public IArchive State => new BA2State
|
|
|
|
{
|
|
|
|
Version = _version,
|
|
|
|
HeaderMagic = _headerMagic,
|
|
|
|
Type = _type,
|
2024-06-17 18:10:53 +00:00
|
|
|
HasNameTable = HasNameTable,
|
|
|
|
Unknown1 = _unknown1,
|
|
|
|
Unknown2 = _unknown2,
|
|
|
|
Compression = _compression,
|
2021-10-23 16:51:17 +00:00
|
|
|
};
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public static async Task<Reader> Load(IStreamFactory streamFactory)
|
|
|
|
{
|
|
|
|
var rdr = new Reader(await streamFactory.GetStream()) {_streamFactory = streamFactory};
|
|
|
|
await rdr.LoadHeaders();
|
|
|
|
return rdr;
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2022-10-07 22:57:12 +00:00
|
|
|
private Task LoadHeaders()
|
2021-10-23 16:51:17 +00:00
|
|
|
{
|
|
|
|
_headerMagic = Encoding.ASCII.GetString(_rdr.ReadBytes(4));
|
|
|
|
|
|
|
|
if (_headerMagic != "BTDX")
|
|
|
|
throw new InvalidDataException("Unknown header type: " + _headerMagic);
|
|
|
|
|
|
|
|
_version = _rdr.ReadUInt32();
|
|
|
|
|
|
|
|
var fourcc = Encoding.ASCII.GetString(_rdr.ReadBytes(4));
|
|
|
|
|
|
|
|
if (Enum.TryParse(fourcc, out BA2EntryType entryType))
|
|
|
|
_type = entryType;
|
|
|
|
else
|
|
|
|
throw new InvalidDataException($"Can't parse entry types of {fourcc}");
|
|
|
|
|
|
|
|
_numFiles = _rdr.ReadUInt32();
|
|
|
|
_nameTableOffset = _rdr.ReadUInt64();
|
|
|
|
|
2024-06-17 18:10:53 +00:00
|
|
|
_unknown1 = (_version == 2 || _version == 3) ? _rdr.ReadUInt32() : 0;
|
|
|
|
_unknown2 = (_version == 2 || _version == 3) ? _rdr.ReadUInt32() : 0;
|
|
|
|
_compression = (_version == 3) ? _rdr.ReadUInt32() : 0;
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
var files = new List<IBA2FileEntry>();
|
|
|
|
for (var idx = 0; idx < _numFiles; idx += 1)
|
|
|
|
switch (_type)
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
case BA2EntryType.GNRL:
|
|
|
|
files.Add(new FileEntry(this, idx));
|
|
|
|
break;
|
|
|
|
case BA2EntryType.DX10:
|
|
|
|
files.Add(new DX10Entry(this, idx));
|
|
|
|
break;
|
|
|
|
case BA2EntryType.GNMF:
|
|
|
|
break;
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
if (HasNameTable)
|
|
|
|
{
|
|
|
|
_rdr.BaseStream.Seek((long) _nameTableOffset, SeekOrigin.Begin);
|
|
|
|
foreach (var file in files)
|
|
|
|
file.FullPath = Encoding.UTF8.GetString(_rdr.ReadBytes(_rdr.ReadInt16()));
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
Files = files;
|
|
|
|
_stream?.Dispose();
|
|
|
|
_rdr.Dispose();
|
2022-10-07 22:57:12 +00:00
|
|
|
|
|
|
|
return Task.CompletedTask;
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
2024-06-17 18:10:53 +00:00
|
|
|
}
|