Make IFolder interface inherently IDisposable.
Fix up implementations to ensure they dispose any stream they acquire, and ensure the constructor will not leave a stream open if it fails. Dispose folders when unmounting them in GlobalFileSystem.
This commit is contained in:
@@ -19,7 +19,7 @@ using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class BagFile : IFolder, IDisposable
|
||||
public sealed class BagFile : IFolder
|
||||
{
|
||||
static readonly uint[] Nothing = { };
|
||||
|
||||
@@ -37,20 +37,16 @@ namespace OpenRA.FileSystem
|
||||
// For example: audio.bag requires the audio.idx file
|
||||
var indexFilename = Path.ChangeExtension(filename, ".idx");
|
||||
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
|
||||
// Build the index and dispose the stream, it is no longer needed after this
|
||||
List<IdxEntry> entries;
|
||||
using (var indexStream = GlobalFileSystem.Open(indexFilename))
|
||||
{
|
||||
var reader = new IdxReader(indexStream);
|
||||
|
||||
entries = reader.Entries;
|
||||
}
|
||||
entries = new IdxReader(indexStream).Entries;
|
||||
|
||||
index = entries.ToDictionaryWithConflictLog(x => x.Hash,
|
||||
"{0} (bag format)".F(filename),
|
||||
null, x => "(offs={0}, len={1})".F(x.Offset, x.Length));
|
||||
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
}
|
||||
|
||||
public int Priority { get { return 1000 + bagFilePriority; } }
|
||||
@@ -185,7 +181,6 @@ namespace OpenRA.FileSystem
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (s != null)
|
||||
s.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,19 +15,21 @@ using System.Linq;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public class BigFile : IFolder
|
||||
public sealed class BigFile : IFolder
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public int Priority { get; private set; }
|
||||
readonly Dictionary<string, Entry> entries = new Dictionary<string, Entry>();
|
||||
readonly Stream s;
|
||||
|
||||
public BigFile(string filename, int priority)
|
||||
{
|
||||
Name = filename;
|
||||
Priority = priority;
|
||||
|
||||
var s = GlobalFileSystem.Open(filename);
|
||||
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
try
|
||||
{
|
||||
if (s.ReadASCII(4) != "BIGF")
|
||||
throw new InvalidDataException("Header is not BIGF");
|
||||
|
||||
@@ -48,6 +50,12 @@ namespace OpenRA.FileSystem
|
||||
entries.Add(entry.Path, entry);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
class Entry
|
||||
{
|
||||
@@ -107,5 +115,10 @@ namespace OpenRA.FileSystem
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
s.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ using System.IO;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public class D2kSoundResources : IFolder
|
||||
public sealed class D2kSoundResources : IFolder
|
||||
{
|
||||
readonly Stream s;
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace OpenRA.FileSystem
|
||||
this.priority = priority;
|
||||
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
s.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
try
|
||||
{
|
||||
filenames = new List<string>();
|
||||
|
||||
var headerLength = s.ReadUInt32();
|
||||
@@ -48,6 +48,12 @@ namespace OpenRA.FileSystem
|
||||
filenames.Add(name);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetContent(uint hash)
|
||||
{
|
||||
@@ -92,5 +98,10 @@ namespace OpenRA.FileSystem
|
||||
{
|
||||
throw new NotImplementedException("Cannot save Dune 2000 Sound Resources.");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
s.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.IO;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public class Folder : IFolder
|
||||
public sealed class Folder : IFolder
|
||||
{
|
||||
readonly string path;
|
||||
readonly int priority;
|
||||
@@ -78,5 +78,7 @@ namespace OpenRA.FileSystem
|
||||
using (var writer = new BinaryWriter(dataStream))
|
||||
writer.Write(file.Value);
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public interface IFolder
|
||||
public interface IFolder : IDisposable
|
||||
{
|
||||
Stream GetContent(string filename);
|
||||
bool Exists(string filename);
|
||||
@@ -127,6 +127,9 @@ namespace OpenRA.FileSystem
|
||||
|
||||
public static void UnmountAll()
|
||||
{
|
||||
foreach (var folder in MountedFolders)
|
||||
folder.Dispose();
|
||||
|
||||
MountedFolders.Clear();
|
||||
FolderPaths.Clear();
|
||||
classicHashIndex = new Cache<uint, List<IFolder>>(_ => new List<IFolder>());
|
||||
@@ -135,6 +138,9 @@ namespace OpenRA.FileSystem
|
||||
|
||||
public static bool Unmount(IFolder mount)
|
||||
{
|
||||
if (MountedFolders.Contains(mount))
|
||||
mount.Dispose();
|
||||
|
||||
return MountedFolders.RemoveAll(f => f == mount) > 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public class InstallShieldPackage : IFolder
|
||||
public sealed class InstallShieldPackage : IFolder
|
||||
{
|
||||
readonly Dictionary<uint, PackageEntry> index = new Dictionary<uint, PackageEntry>();
|
||||
readonly List<string> filenames;
|
||||
@@ -28,9 +28,12 @@ namespace OpenRA.FileSystem
|
||||
{
|
||||
this.filename = filename;
|
||||
this.priority = priority;
|
||||
filenames = new List<string>();
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
|
||||
filenames = new List<string>();
|
||||
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
try
|
||||
{
|
||||
// Parse package header
|
||||
var reader = new BinaryReader(s);
|
||||
var signature = reader.ReadUInt32();
|
||||
@@ -61,6 +64,12 @@ namespace OpenRA.FileSystem
|
||||
for (var i = 0; i < fileCount; i++)
|
||||
ParseFile(reader);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
static uint ParseDirectory(BinaryReader reader)
|
||||
{
|
||||
@@ -140,5 +149,10 @@ namespace OpenRA.FileSystem
|
||||
{
|
||||
throw new NotImplementedException("Cannot save InstallShieldPackages.");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
s.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class MixFile : IFolder, IDisposable
|
||||
public sealed class MixFile : IFolder
|
||||
{
|
||||
readonly Dictionary<uint, PackageEntry> index;
|
||||
readonly long dataStart;
|
||||
@@ -37,20 +37,29 @@ namespace OpenRA.FileSystem
|
||||
File.Delete(filename);
|
||||
|
||||
s = File.Create(filename);
|
||||
try
|
||||
{
|
||||
index = new Dictionary<uint, PackageEntry>();
|
||||
contents.Add("local mix database.dat", new XccLocalDatabase(contents.Keys.Append("local mix database.dat")).Data());
|
||||
Write(contents);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public MixFile(string filename, PackageHashType type, int priority)
|
||||
{
|
||||
this.filename = filename;
|
||||
this.priority = priority;
|
||||
this.type = type;
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
|
||||
s = GlobalFileSystem.Open(filename);
|
||||
try
|
||||
{
|
||||
// Detect format type
|
||||
s.Seek(0, SeekOrigin.Begin);
|
||||
var isCncMix = s.ReadUInt16() != 0;
|
||||
|
||||
// The C&C mix format doesn't contain any flags or encryption
|
||||
@@ -71,6 +80,12 @@ namespace OpenRA.FileSystem
|
||||
"{0} ({1} format, Encrypted: {2}, DataStart: {3})".F(filename, isCncMix ? "C&C" : "RA/TS/RA2", isEncrypted, dataStart),
|
||||
null, x => "(offs={0}, len={1})".F(x.Offset, x.Length));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
static List<PackageEntry> ParseHeader(Stream s, long offset, out long headerEnd)
|
||||
{
|
||||
@@ -269,7 +284,6 @@ namespace OpenRA.FileSystem
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (s != null)
|
||||
s.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,20 +21,22 @@ namespace OpenRA.FileSystem
|
||||
public string Filename;
|
||||
}
|
||||
|
||||
public class PakFile : IFolder
|
||||
public sealed class PakFile : IFolder
|
||||
{
|
||||
string filename;
|
||||
int priority;
|
||||
Dictionary<string, Entry> index;
|
||||
Stream stream;
|
||||
readonly string filename;
|
||||
readonly int priority;
|
||||
readonly Dictionary<string, Entry> index;
|
||||
readonly Stream stream;
|
||||
|
||||
public PakFile(string filename, int priority)
|
||||
{
|
||||
this.filename = filename;
|
||||
this.priority = priority;
|
||||
index = new Dictionary<string, Entry>();
|
||||
stream = GlobalFileSystem.Open(filename);
|
||||
|
||||
stream = GlobalFileSystem.Open(filename);
|
||||
try
|
||||
{
|
||||
index = new Dictionary<string, Entry>();
|
||||
var offset = stream.ReadUInt32();
|
||||
while (offset != 0)
|
||||
@@ -51,6 +53,12 @@ namespace OpenRA.FileSystem
|
||||
offset = next;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
@@ -92,5 +100,10 @@ namespace OpenRA.FileSystem
|
||||
|
||||
public int Priority { get { return 1000 + priority; } }
|
||||
public string Name { get { return filename; } }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ using SZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile;
|
||||
|
||||
namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class ZipFile : IFolder, IDisposable
|
||||
public sealed class ZipFile : IFolder
|
||||
{
|
||||
string filename;
|
||||
readonly string filename;
|
||||
readonly int priority;
|
||||
SZipFile pkg;
|
||||
int priority;
|
||||
|
||||
static ZipFile()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user