2021-09-27 12:42:46 +00:00
|
|
|
using System;
|
|
|
|
using System.IO;
|
|
|
|
using System.Text;
|
|
|
|
using System.Threading;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using ICSharpCode.SharpZipLib.Zip.Compression;
|
|
|
|
using Wabbajack.Common;
|
|
|
|
using Wabbajack.DTOs.BSA.FileStates;
|
|
|
|
using Wabbajack.DTOs.Streams;
|
|
|
|
using Wabbajack.Paths;
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
namespace Wabbajack.Compression.BSA.FO4Archive;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public class FileEntry : IBA2FileEntry
|
|
|
|
{
|
|
|
|
internal uint _align;
|
|
|
|
internal Reader _bsa;
|
|
|
|
internal uint _dirHash;
|
|
|
|
internal string _extension;
|
|
|
|
internal uint _flags;
|
|
|
|
internal int _index;
|
|
|
|
internal uint _nameHash;
|
|
|
|
internal ulong _offset;
|
|
|
|
internal uint _realSize;
|
|
|
|
internal uint _size;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public FileEntry(Reader ba2Reader, int index)
|
|
|
|
{
|
|
|
|
_index = index;
|
|
|
|
_bsa = ba2Reader;
|
|
|
|
var _rdr = ba2Reader._rdr;
|
|
|
|
_nameHash = _rdr.ReadUInt32();
|
|
|
|
FullPath = _nameHash.ToString("X");
|
|
|
|
_extension = Encoding.UTF8.GetString(_rdr.ReadBytes(4));
|
|
|
|
_dirHash = _rdr.ReadUInt32();
|
|
|
|
_flags = _rdr.ReadUInt32();
|
|
|
|
_offset = _rdr.ReadUInt64();
|
|
|
|
_size = _rdr.ReadUInt32();
|
|
|
|
_realSize = _rdr.ReadUInt32();
|
|
|
|
_align = _rdr.ReadUInt32();
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public bool Compressed => _size != 0;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public string FullPath { get; set; }
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public RelativePath Path => FullPath.ToRelativePath();
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public uint Size => _realSize;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public AFile State => new BA2File
|
|
|
|
{
|
|
|
|
NameHash = _nameHash,
|
|
|
|
DirHash = _dirHash,
|
|
|
|
Flags = _flags,
|
|
|
|
Align = _align,
|
|
|
|
Compressed = Compressed,
|
|
|
|
Path = Path,
|
|
|
|
Extension = _extension,
|
|
|
|
Index = _index
|
|
|
|
};
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public async ValueTask CopyDataTo(Stream output, CancellationToken token)
|
|
|
|
{
|
|
|
|
await using var fs = await _bsa._streamFactory.GetStream();
|
|
|
|
fs.Seek((long) _offset, SeekOrigin.Begin);
|
|
|
|
var len = Compressed ? _size : _realSize;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
var bytes = new byte[len];
|
|
|
|
await fs.ReadAsync(bytes.AsMemory(0, (int) len), token);
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
if (!Compressed)
|
|
|
|
{
|
|
|
|
await output.WriteAsync(bytes, token);
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
2021-10-23 16:51:17 +00:00
|
|
|
else
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
var uncompressed = new byte[_realSize];
|
|
|
|
var inflater = new Inflater();
|
|
|
|
inflater.SetInput(bytes);
|
|
|
|
inflater.Inflate(uncompressed);
|
|
|
|
await output.WriteAsync(uncompressed, token);
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
await output.FlushAsync(token);
|
|
|
|
}
|
|
|
|
|
|
|
|
public async ValueTask<IStreamFactory> GetStreamFactory(CancellationToken token)
|
|
|
|
{
|
|
|
|
var ms = new MemoryStream();
|
|
|
|
await CopyDataTo(ms, token);
|
|
|
|
ms.Position = 0;
|
|
|
|
return new MemoryStreamFactory(ms, Path, _bsa._streamFactory.LastModifiedUtc);
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
|
|
|
}
|