/// <summary> /// Extracts a collection of files from an archive and BLTE encodes them /// </summary> /// <param name="mpq"></param> /// <param name="filenames"></param> /// <param name="maxDegreeOfParallelism"></param> /// <returns></returns> private async Task ExportFiles(MpqArchive mpq, IEnumerable <string> filenames, bool applyTags = false, int maxDegreeOfParallelism = 150) { var block = new ActionBlock <string>(file => { using var fs = mpq.OpenFile(file); // ignore PTCH files if (fs.Flags.HasFlag(MPQFileAttributes.PatchFile)) { return; } // patch has marked file for deletion so remove from filelist if (fs.Flags.HasFlag(MPQFileAttributes.DeleteMarker)) { FileList.TryRemove(file, out _); return; } if (fs.CanRead && fs.Length > 0) { var map = BlockTableEncoder.GetEMapFromExtension(file, fs.Length); if (!EncodingCache.TryGetRecord(MD5Hash.Parse(fs.GetMD5Hash()), file, out var record)) { record = BlockTableEncoder.EncodeAndExport(fs, map, Options.TempDirectory, file); EncodingCache.AddOrUpdate(record); } if (applyTags) { record.Tags = TagGenerator.GetTags(file, fs); } record.EBlock.EncodingMap = map; FileList.TryAdd(file, record); } }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }); foreach (var file in filenames) { if (!FileList.ContainsKey(file)) { block.Post(file); } } block.Complete(); await block.Completion; }
/// <summary> /// Some alpha MPQs are hotswappable and only contain a single file and it's checksum /// </summary> /// <param name="mpq"></param> /// <param name="archivename"></param> private bool TryReadAlpha(MpqArchive mpq, string archivename) { // strip the local path and extension to get the filename var file = Path.ChangeExtension(GetInternalPath(archivename), null).WoWNormalise(); if (FileList.ContainsKey(file)) { return(true); } // add the filename as the listfile var internalname = Path.GetFileName(file); mpq.AddListFile(internalname); // read file if known if (mpq.HasFile(internalname)) { using var fs = mpq.OpenFile(internalname); if (fs.CanRead && fs.Length > 0) { var map = BlockTableEncoder.GetEMapFromExtension(file, fs.Length); if (!EncodingCache.TryGetRecord(MD5Hash.Parse(fs.GetMD5Hash()), file, out var record)) { record = BlockTableEncoder.EncodeAndExport(fs, map, Options.TempDirectory, file); EncodingCache.AddOrUpdate(record); } record.EBlock.EncodingMap = map; FileList.TryAdd(file, record); return(true); } } return(false); }