Files
OpenRA/OpenRA.Mods.Common/Installer/SourceActions/ExtractIscabSourceAction.cs
2024-07-29 21:56:36 +02:00

81 lines
2.8 KiB
C#

#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<string> extracted, Action<string> 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<int, Stream>();
try
{
foreach (var node in volumeNode.Value.Nodes)
{
var volume = FieldLoader.GetValue<int>("(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(TranslationProvider.GetString(
InstallFromSourceLogic.ExtractingProgress,
Translation.Arguments("filename", displayFilename, "progress", percent)));
reader.ExtractFile(node.Value.Value, target, OnProgress);
}
}
}
}
finally
{
foreach (var kv in volumes)
kv.Value.Dispose();
}
}
}
}