public static void SaveWithPreArchiveData(this MpqArchiveBuilder mpqArchiveBuilder, Stream stream, bool leaveOpen = false) { var mpqFiles = mpqArchiveBuilder.ToArray(); var campaignInfoFile = mpqFiles.SingleOrDefault(file => file.Name == CampaignInfoHashedFileName); if (campaignInfoFile is not null) { using var reader = new BinaryReader(campaignInfoFile.MpqStream, new UTF8Encoding(false, true), true); var campaignInfo = reader.ReadCampaignInfo(); campaignInfoFile.MpqStream.Position = 0; mpqArchiveBuilder.SaveWithPreArchiveData(stream, campaignInfo, leaveOpen); } else { var mapInfoFile = mpqFiles.SingleOrDefault(file => file.Name == MapInfoHashedFileName); if (mapInfoFile is not null) { using var reader = new BinaryReader(mapInfoFile.MpqStream, new UTF8Encoding(false, true), true); var mapInfo = reader.ReadMapInfo(); mapInfoFile.MpqStream.Position = 0; mpqArchiveBuilder.SaveWithPreArchiveData(stream, mapInfo, leaveOpen); } else { throw new FileNotFoundException($"Unable to find {CampaignInfo.FileName} or {MapInfo.FileName} file to use as source for pre-archive data."); } } }
private static void SaveArchiveBackgroundWork(object?sender, DoWorkEventArgs e) { var archiveBuilder = new MpqArchiveBuilder(_archive); var progress = new SaveArchiveProgress(); progress.Saving = false; for (var i = 0; i < _fileList.Items.Count; i++) { var tag = _fileList.Items[i].GetTag(); if (tag.Parent is not null) { continue; } if (tag.Status == MapFileStatus.Removed) { if (tag.TryGetHashedFileName(out var hashedFileName)) { archiveBuilder.RemoveFile(hashedFileName); } else { archiveBuilder.RemoveFile(_archive, tag.MpqEntry); } } else if (tag.Children is not null) { if (tag.Children.All(child => child.Status == MapFileStatus.Removed)) { throw new InvalidOperationException("Parent tag should have been removed since all child tags are removed, but was " + tag.Status); } else if (tag.Children.Any(child => child.IsModified || child.Status == MapFileStatus.Removed)) { // Assume at most one nested archive (for campaign archives), so no recursion. using var subArchive = MpqArchive.Open(_archive.OpenFile(tag.FileName)); foreach (var child in tag.Children) { if (child.FileName != null) { subArchive.AddFileName(child.FileName); } } var subArchiveBuilder = new MpqArchiveBuilder(subArchive); foreach (var child in tag.Children) { if (child.Status == MapFileStatus.Removed) { if (child.TryGetHashedFileName(out var hashedFileName)) { subArchiveBuilder.RemoveFile(hashedFileName); } else { subArchiveBuilder.RemoveFile(subArchive, child.MpqEntry); } } else if (child.TryGetModifiedMpqFile(out var subArchiveAdaptedFile)) { subArchiveBuilder.AddFile(subArchiveAdaptedFile); _saveArchiveWorker.ReportProgress(0, progress); } else { _saveArchiveWorker.ReportProgress(0, progress); } } var adaptedSubArchiveStream = new MemoryStream(); subArchiveBuilder.SaveWithPreArchiveData(adaptedSubArchiveStream, true); adaptedSubArchiveStream.Position = 0; var adaptedFile = MpqFile.New(adaptedSubArchiveStream, tag.FileName, false); adaptedFile.TargetFlags = tag.MpqEntry.Flags; archiveBuilder.AddFile(adaptedFile); _saveArchiveWorker.ReportProgress(0, progress); } else { _saveArchiveWorker.ReportProgress(tag.Children.Length, progress); } } else if (tag.TryGetModifiedMpqFile(out var adaptedFile)) { archiveBuilder.AddFile(adaptedFile); _saveArchiveWorker.ReportProgress(0, progress); } else { _saveArchiveWorker.ReportProgress(0, progress); } } progress.Saving = true; _saveArchiveWorker.ReportProgress(0, progress); using (var fileStream = File.Create((string)e.Argument)) { archiveBuilder.SaveWithPreArchiveData(fileStream); } }