wabbajack/Wabbajack.Compression.BSA/FO4Archive/FileEntry.cs
2021-10-23 10:51:17 -06:00

96 lines
2.6 KiB
C#

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;
namespace Wabbajack.Compression.BSA.FO4Archive;
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;
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();
}
public bool Compressed => _size != 0;
public string FullPath { get; set; }
public RelativePath Path => FullPath.ToRelativePath();
public uint Size => _realSize;
public AFile State => new BA2File
{
NameHash = _nameHash,
DirHash = _dirHash,
Flags = _flags,
Align = _align,
Compressed = Compressed,
Path = Path,
Extension = _extension,
Index = _index
};
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;
var bytes = new byte[len];
await fs.ReadAsync(bytes.AsMemory(0, (int) len), token);
if (!Compressed)
{
await output.WriteAsync(bytes, token);
}
else
{
var uncompressed = new byte[_realSize];
var inflater = new Inflater();
inflater.SetInput(bytes);
inflater.Inflate(uncompressed);
await output.WriteAsync(uncompressed, token);
}
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);
}
}