Reimplement InstallShieldCAB extraction.

This commit is contained in:
Paul Chote
2016-06-26 11:05:02 +01:00
parent 8c8fa2d258
commit bddae7314a
4 changed files with 540 additions and 0 deletions

View File

@@ -234,6 +234,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
break;
}
case "extract-iscab":
{
ExtractFromISCab(path, i.Value, extracted, m => message = m);
break;
}
default:
Log.Write("debug", "Unknown installation command {0} - ignoring", i.Key);
break;
@@ -370,6 +376,59 @@ namespace OpenRA.Mods.Common.Widgets.Logic
}
}
static void ExtractFromISCab(string path, MiniYaml actionYaml, List<string> extractedFiles, Action<string> updateMessage)
{
var sourcePath = Path.Combine(path, actionYaml.Value);
var volumeNode = actionYaml.Nodes.FirstOrDefault(n => n.Key == "Volumes");
if (volumeNode == null)
throw new InvalidDataException("extract-iscab entry doesn't define a Volumes node");
var extractNode = actionYaml.Nodes.FirstOrDefault(n => n.Key == "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(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;
}
extractedFiles.Add(targetPath);
Directory.CreateDirectory(Path.GetDirectoryName(targetPath));
using (var target = File.OpenWrite(targetPath))
{
Log.Write("install", "Extracting {0} -> {1}".F(sourcePath, targetPath));
var displayFilename = Path.GetFileName(Path.GetFileName(targetPath));
Action<int> onProgress = percent => updateMessage("Extracting {0} ({1}%)".F(displayFilename, percent));
reader.ExtractFile(node.Value.Value, target, onProgress);
}
}
}
}
finally
{
foreach (var kv in volumes)
kv.Value.Dispose();
}
}
string FindSourcePath(ModContent.ModSource source, IEnumerable<string> volumes)
{
if (source.Type == ModContent.SourceType.Install)