issue-4 - Can index nested archives

This commit is contained in:
Timothy Baldridge 2019-08-08 16:36:09 -06:00
parent e1d9cd335d
commit 4b036221b9
4 changed files with 87 additions and 6 deletions

View File

@ -251,7 +251,7 @@ namespace Compression.BSA
private int _offset;
private FolderRecord _folder;
private string _name;
private uint _originalSize;
private uint? _originalSize;
public FileRecord(BSAReader bsa, FolderRecord folderRecord, BinaryReader src)
{
@ -296,11 +296,36 @@ namespace Compression.BSA
{
get
{
if (Compressed) return (int)_originalSize;
if (Compressed)
{
if (_originalSize == null)
LoadOriginalSize();
return (int)_originalSize;
}
return _size;
}
}
private void LoadOriginalSize()
{
using (var in_file = File.OpenRead(_bsa._fileName))
using (var rdr = new BinaryReader(in_file))
{
rdr.BaseStream.Position = _offset;
string _name;
int file_size = _size;
if (_bsa.HasNameBlobs)
{
var name_size = rdr.ReadByte();
file_size -= name_size + 1;
rdr.BaseStream.Position = _offset + 1 + name_size;
}
_originalSize = rdr.ReadUInt32();
}
}
public ulong Hash {
get
{

View File

@ -194,7 +194,11 @@ namespace Wabbajack.Common
public class IndexedArchiveCache
{
public string Hash;
public int Version;
public List<IndexedEntry> Entries;
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public Dictionary<string, IndexedArchiveCache> InnerArchives;
}
public class IndexedArchive : IndexedArchiveCache

View File

@ -86,6 +86,10 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Compression.BSA\Compression.BSA.csproj">
<Project>{ff5d892f-8ff4-44fc-8f7f-cd58f307ad1b}</Project>
<Name>Compression.BSA</Name>
</ProjectReference>
<ProjectReference Include="..\SevenZipExtractor\SevenZipExtractor.csproj">
<Project>{8aa97f58-5044-4bba-b8d9-a74b6947a660}</Project>
<Name>SevenZipExtractor</Name>

View File

@ -100,17 +100,27 @@ namespace Wabbajack
.PMap(file => LoadArchive(file));
}
private const int ARCHIVE_CONTENTS_VERSION = 1;
private IndexedArchive LoadArchive(string file)
{
TOP:
string metaname = file + ".archive_contents";
if (metaname.FileExists() && new FileInfo(metaname).LastWriteTime >= new FileInfo(file).LastWriteTime)
{
Status("Loading Archive Index for {0}", Path.GetFileName(file));
var info = metaname.FromJSON<IndexedArchive>();
if (info.Version != ARCHIVE_CONTENTS_VERSION)
{
File.Delete(metaname);
goto TOP;
}
info.Name = Path.GetFileName(file);
info.AbsolutePath = file;
var ini_name = file + ".meta";
if (ini_name.FileExists())
{
@ -121,16 +131,44 @@ namespace Wabbajack
return info;
}
IndexArchive(file).ToJSON(metaname);
goto TOP;
}
private bool IsArchiveFile(string name)
{
var ext = Path.GetExtension(name);
if (ext == ".bsa" || Consts.SupportedArchives.Contains(ext))
return true;
return false;
}
private IndexedArchiveCache IndexArchive(string file)
{
Status("Indexing {0}", Path.GetFileName(file));
var streams = new Dictionary<string, (SHA256Managed, long)>();
FileExtractor.Extract(file, entry => {
var inner_archives = new Dictionary<string, string>();
FileExtractor.Extract(file, entry =>
{
Stream inner;
if (IsArchiveFile(entry.Name))
{
var name = Path.GetTempFileName() + Path.GetExtension(entry.Name);
inner_archives.Add(entry.Name, name);
inner = File.OpenWrite(name);
}
else
{
inner = Stream.Null;
}
var sha = new SHA256Managed();
var os = new CryptoStream(Stream.Null, sha, CryptoStreamMode.Write);
var os = new CryptoStream(inner, sha, CryptoStreamMode.Write);
streams.Add(entry.Name, (sha, (long)entry.Size));
return os;
});
var indexed = new IndexedArchiveCache();
indexed.Version = ARCHIVE_CONTENTS_VERSION;
indexed.Hash = file.FileSHA256();
indexed.Entries = streams.Select(entry =>
{
@ -144,8 +182,18 @@ namespace Wabbajack
streams.Do(e => e.Value.Item1.Dispose());
indexed.ToJSON(metaname);
return LoadArchive(file);
if (inner_archives.Count > 0)
{
var result = inner_archives.Select(archive =>
{
return (archive.Key, IndexArchive(archive.Value));
}).ToDictionary(e => e.Key, e => e.Item2);
indexed.InnerArchives = result;
inner_archives.Do(e => File.Delete(e.Value));
}
return indexed;
}
public void Compile()