- Almost all calls to Stream.Read were broken. These have been patched to all go through ReadBytes which itself has been fixed to function correctly. The key thing to note is that Stream.Read is very much allowed to return less than the requested number of bytes. If this happens and you're not checking the return result, you'll be working with partially initialized arrays and really bad stuff happens when you do that. - Call CopyTo rather than copying between streams manually. - Peek and ReadUInt8 have been changed to avoid a pointless array allocation which is significant overhead for such simple calls.
131 lines
3.5 KiB
C#
131 lines
3.5 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright 2007-2011 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
|
|
{
|
|
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(v => isValidDisk(v));
|
|
}
|
|
|
|
// 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[] files, string destPath, Action<string> onProgress, Action<string> onError)
|
|
{
|
|
if (!Directory.Exists(destPath))
|
|
Directory.CreateDirectory(destPath);
|
|
|
|
if (!GlobalFileSystem.Exists(srcPath)) { onError("Cannot find " + package); return false; }
|
|
GlobalFileSystem.Mount(srcPath);
|
|
if (!GlobalFileSystem.Exists(package)) { onError("Cannot find " + package); return false; }
|
|
GlobalFileSystem.Mount(package);
|
|
|
|
foreach (string s in files)
|
|
{
|
|
var destFile = Path.Combine(destPath, s);
|
|
using (var sourceStream = GlobalFileSystem.Open(s))
|
|
using (var destStream = File.Create(destFile))
|
|
{
|
|
onProgress("Extracting " + s);
|
|
destStream.Write(sourceStream.ReadAllBytes());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static bool CopyFiles(string srcPath, string[] files, string destPath, Action<string> onProgress, Action<string> onError)
|
|
{
|
|
foreach (var file in files)
|
|
{
|
|
var fromPath = Path.Combine(srcPath, file);
|
|
if (!File.Exists(fromPath))
|
|
{
|
|
onError("Cannot find " + file);
|
|
return false;
|
|
}
|
|
|
|
var destFile = Path.GetFileName(file).ToLowerInvariant();
|
|
onProgress("Extracting " + destFile);
|
|
File.Copy(fromPath, Path.Combine(destPath, destFile), 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;
|
|
}
|
|
|
|
List<string> extracted = new List<string>();
|
|
try
|
|
{
|
|
var z = new ZipInputStream(File.OpenRead(zipFile));
|
|
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();
|
|
}
|
|
}
|
|
} |