#region Copyright & License Information /* * Copyright (c) The OpenRA Developers and Contributors * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. For more * information, see COPYING. */ #endregion using System; using System.Collections.Generic; using System.IO; using OpenRA.Mods.Common.FileFormats; using OpenRA.Mods.Common.Widgets.Logic; using FS = OpenRA.FileSystem.FileSystem; namespace OpenRA.Mods.Common.Installer { public class ExtractIscabSourceAction : ISourceAction { public void RunActionOnSource(MiniYaml actionYaml, string path, ModData modData, List extracted, Action updateMessage) { // Yaml path may be specified relative to a named directory (e.g. ^SupportDir) or the detected source path var sourcePath = actionYaml.Value.StartsWith('^') ? Platform.ResolvePath(actionYaml.Value) : FS.ResolveCaseInsensitivePath(Path.Combine(path, actionYaml.Value)); var volumeNode = actionYaml.NodeWithKeyOrDefault("Volumes"); if (volumeNode == null) throw new InvalidDataException("extract-iscab entry doesn't define a Volumes node"); var extractNode = actionYaml.NodeWithKeyOrDefault("Extract"); if (extractNode == null) throw new InvalidDataException("extract-iscab entry doesn't define an Extract node"); var volumes = new Dictionary(); try { foreach (var node in volumeNode.Value.Nodes) { var volume = FieldLoader.GetValue("(key)", node.Key); var stream = File.OpenRead(FS.ResolveCaseInsensitivePath(Path.Combine(path, node.Value.Value))); volumes.Add(volume, stream); } using (var source = File.OpenRead(sourcePath)) { var reader = new InstallShieldCABCompression(source, volumes); foreach (var node in extractNode.Value.Nodes) { var targetPath = Platform.ResolvePath(node.Key); if (File.Exists(targetPath)) { Log.Write("install", "Skipping installed file " + targetPath); continue; } extracted.Add(targetPath); Directory.CreateDirectory(Path.GetDirectoryName(targetPath)); using (var target = File.OpenWrite(targetPath)) { Log.Write("install", $"Extracting {sourcePath} -> {targetPath}"); var displayFilename = Path.GetFileName(Path.GetFileName(targetPath)); void OnProgress(int percent) => updateMessage(FluentProvider.GetMessage( InstallFromSourceLogic.ExtractingProgress, "filename", displayFilename, "progress", percent)); reader.ExtractFile(node.Value.Value, target, OnProgress); } } } } finally { foreach (var kv in volumes) kv.Value.Dispose(); } } } }