Files
OpenRA/OpenRA.Mods.Common/InstallUtils.cs
Dan9550 a559f6d4ac Modified mod.yaml to respect case sensitive file names
Modified mod.yaml to respect case sensitive file names

Modified install logic to convert case of files on install

Revert initial changes
2015-08-21 23:42:10 +10:00

211 lines
6.0 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
* 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. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.SharpZipLib;
using ICSharpCode.SharpZipLib.Zip;
using OpenRA.FileSystem;
namespace OpenRA.Mods.Common
{
public class ContentInstaller : IGlobalModData
{
public readonly string MenuWidget = null;
public readonly string MusicMenuWidget = null;
public readonly string BackgroundWidget = null;
public readonly string[] TestFiles = { };
public readonly string[] DiskTestFiles = { };
public readonly string PackageToExtractFromCD = null;
public readonly bool OverwriteFiles = true;
[FieldLoader.LoadUsing("LoadFilesToExtract")]
public readonly Dictionary<string, string[]> ExtractFilesFromCD = new Dictionary<string, string[]>();
[FieldLoader.LoadUsing("LoadFilesToCopy")]
public readonly Dictionary<string, string[]> CopyFilesFromCD = new Dictionary<string, string[]>();
public readonly string PackageMirrorList = null;
public readonly string MusicPackageMirrorList = null;
public readonly int ShippedSoundtracks = 0;
/// <summary> InstallShield .cab File Ids, used to extract Mod specific files </summary>
public readonly int[] InstallShieldCABFileIds = { };
/// <summary> InstallShield .cab File Ids, used to extract Mod specific archives and extract contents of ExtractFilesFromCD </summary>
public readonly string[] InstallShieldCABFilePackageIds = { };
public static Dictionary<string, string[]> LoadFilesToExtract(MiniYaml yaml)
{
var md = yaml.ToDictionary();
return md.ContainsKey("ExtractFilesFromCD")
? md["ExtractFilesFromCD"].ToDictionary(my => FieldLoader.GetValue<string[]>("(value)", my.Value))
: new Dictionary<string, string[]>();
}
public static Dictionary<string, string[]> LoadFilesToCopy(MiniYaml yaml)
{
var md = yaml.ToDictionary();
return md.ContainsKey("CopyFilesFromCD")
? md["CopyFilesFromCD"].ToDictionary(my => FieldLoader.GetValue<string[]>("(value)", my.Value))
: new Dictionary<string, string[]>();
}
}
public static class InstallUtils
{
static IEnumerable<ZipEntry> GetEntries(this ZipInputStream z)
{
for (;;)
{
var e = z.GetNextEntry();
if (e != null) yield return e; else break;
}
}
public static string GetMountedDisk(Func<string, bool> isValidDisk)
{
var volumes = DriveInfo.GetDrives()
.Where(v => v.DriveType == DriveType.CDRom && v.IsReady)
.Select(v => v.RootDirectory.FullName);
return volumes.FirstOrDefault(isValidDisk);
}
// TODO: The package should be mounted into its own context to avoid name collisions with installed files
public static bool ExtractFromPackage(string srcPath, string package, string annotation, Dictionary<string, string[]> filesByDirectory,
string destPath, bool overwrite, Action<string> onProgress, Action<string> onError)
{
if (!Directory.Exists(destPath))
Directory.CreateDirectory(destPath);
Log.Write("debug", "Mounting {0}".F(srcPath));
GlobalFileSystem.Mount(srcPath);
Log.Write("debug", "Mounting {0}".F(package));
GlobalFileSystem.Mount(package, annotation);
foreach (var directory in filesByDirectory)
{
var targetDir = directory.Key;
foreach (var file in directory.Value)
{
var dest = Path.Combine(destPath, targetDir, file.ToLowerInvariant());
if (File.Exists(dest))
{
if (overwrite)
File.Delete(dest);
else
{
Log.Write("debug", "Skipping {0}".F(dest));
continue;
}
}
using (var sourceStream = GlobalFileSystem.Open(file))
using (var destStream = File.Create(dest))
{
Log.Write("debug", "Extracting {0} to {1}".F(file, dest));
onProgress("Extracting " + file);
destStream.Write(sourceStream.ReadAllBytes());
}
}
}
return true;
}
public static bool CopyFiles(string srcPath, Dictionary<string, string[]> files, string destPath,
bool overwrite, Action<string> onProgress, Action<string> onError)
{
foreach (var folder in files)
{
var targetDir = folder.Key;
foreach (var file in folder.Value)
{
var sourcePath = Path.Combine(srcPath, file);
if (!File.Exists(sourcePath))
{
onError("Cannot find " + file);
return false;
}
var destFile = Path.GetFileName(file);
var dest = Path.Combine(destPath, targetDir, destFile.ToLowerInvariant());
if (File.Exists(dest) && !overwrite)
{
Log.Write("debug", "Skipping {0}".F(dest));
continue;
}
onProgress("Copying " + destFile);
Log.Write("debug", "Copy {0} to {1}".F(sourcePath, dest));
File.Copy(sourcePath, dest, true);
}
}
return true;
}
public static bool ExtractZip(string zipFile, string dest, Action<string> onProgress, Action<string> onError)
{
if (!File.Exists(zipFile))
{
onError("Invalid path: " + zipFile);
return false;
}
var extracted = new List<string>();
try
{
using (var stream = File.OpenRead(zipFile))
using (var z = new ZipInputStream(stream))
z.ExtractZip(dest, extracted, s => onProgress("Extracting " + s));
}
catch (SharpZipBaseException)
{
foreach (var f in extracted)
File.Delete(f);
onError("Invalid archive");
return false;
}
return true;
}
// TODO: this belongs in FileSystem/ZipFile
static void ExtractZip(this ZipInputStream z, string destPath, List<string> extracted, Action<string> onProgress)
{
foreach (var entry in z.GetEntries())
{
if (!entry.IsFile) continue;
onProgress(entry.Name);
Directory.CreateDirectory(Path.Combine(destPath, Path.GetDirectoryName(entry.Name)));
var path = Path.Combine(destPath, entry.Name);
extracted.Add(path);
using (var f = File.Create(path))
z.CopyTo(f);
}
z.Close();
}
}
}