Merge pull request #10525 from pchote/split-package-interfaces

Split IPackage into IReadOnlyPackage and IReadWritePackage
This commit is contained in:
Matthias Mailänder
2016-01-16 14:19:54 +01:00
13 changed files with 40 additions and 128 deletions

View File

@@ -19,7 +19,7 @@ using OpenRA.Primitives;
namespace OpenRA.FileSystem namespace OpenRA.FileSystem
{ {
public sealed class BagFile : IPackage public sealed class BagFile : IReadOnlyPackage
{ {
static readonly uint[] Nothing = { }; static readonly uint[] Nothing = { };
@@ -175,12 +175,6 @@ namespace OpenRA.FileSystem
return index.Keys.Select(k => lookup.ContainsKey(k) ? lookup[k] : "{0:X}".F(k)); return index.Keys.Select(k => lookup.ContainsKey(k) ? lookup[k] : "{0:X}".F(k));
} }
public void Write(Dictionary<string, byte[]> contents)
{
context.Unmount(this);
throw new NotImplementedException("Updating bag files unsupported");
}
public void Dispose() public void Dispose()
{ {
s.Dispose(); s.Dispose();

View File

@@ -15,7 +15,7 @@ using System.Linq;
namespace OpenRA.FileSystem namespace OpenRA.FileSystem
{ {
public sealed class BigFile : IPackage public sealed class BigFile : IReadOnlyPackage
{ {
public string Name { get; private set; } public string Name { get; private set; }
public int Priority { get; private set; } public int Priority { get; private set; }
@@ -111,11 +111,6 @@ namespace OpenRA.FileSystem
return entries.Keys; return entries.Keys;
} }
public void Write(Dictionary<string, byte[]> contents)
{
throw new NotImplementedException();
}
public void Dispose() public void Dispose()
{ {
s.Dispose(); s.Dispose();

View File

@@ -14,7 +14,7 @@ using System.IO;
namespace OpenRA.FileSystem namespace OpenRA.FileSystem
{ {
public sealed class D2kSoundResources : IPackage public sealed class D2kSoundResources : IReadOnlyPackage
{ {
readonly Stream s; readonly Stream s;
@@ -94,11 +94,6 @@ namespace OpenRA.FileSystem
yield break; yield break;
} }
public void Write(Dictionary<string, byte[]> contents)
{
throw new NotImplementedException("Cannot save Dune 2000 Sound Resources.");
}
public void Dispose() public void Dispose()
{ {
s.Dispose(); s.Dispose();

View File

@@ -20,37 +20,25 @@ namespace OpenRA.FileSystem
public class FileSystem public class FileSystem
{ {
public readonly List<string> PackagePaths = new List<string>(); public readonly List<string> PackagePaths = new List<string>();
public readonly List<IPackage> MountedPackages = new List<IPackage>(); public readonly List<IReadOnlyPackage> MountedPackages = new List<IReadOnlyPackage>();
static readonly Dictionary<string, Assembly> AssemblyCache = new Dictionary<string, Assembly>(); static readonly Dictionary<string, Assembly> AssemblyCache = new Dictionary<string, Assembly>();
int order; int order;
Cache<uint, List<IPackage>> crcHashIndex = new Cache<uint, List<IPackage>>(_ => new List<IPackage>()); Cache<uint, List<IReadOnlyPackage>> crcHashIndex = new Cache<uint, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
Cache<uint, List<IPackage>> classicHashIndex = new Cache<uint, List<IPackage>>(_ => new List<IPackage>()); Cache<uint, List<IReadOnlyPackage>> classicHashIndex = new Cache<uint, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
public IPackage CreatePackage(string filename, int order, Dictionary<string, byte[]> content) public IReadWritePackage CreatePackage(string filename, int order, Dictionary<string, byte[]> content)
{ {
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
return new MixFile(this, filename, order, content);
if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(this, filename, order, content); return new ZipFile(this, filename, order, content);
if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(this, filename, order, content); return new ZipFile(this, filename, order, content);
if (filename.EndsWith(".RS", StringComparison.InvariantCultureIgnoreCase))
throw new NotImplementedException("The creation of .RS archives is unimplemented");
if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
throw new NotImplementedException("The creation of .Z archives is unimplemented");
if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase))
throw new NotImplementedException("The creation of .PAK archives is unimplemented");
if (filename.EndsWith(".big", StringComparison.InvariantCultureIgnoreCase))
throw new NotImplementedException("The creation of .big archives is unimplemented");
if (filename.EndsWith(".cab", StringComparison.InvariantCultureIgnoreCase))
throw new NotImplementedException("The creation of .cab archives is unimplemented");
return new Folder(filename, order, content); return new Folder(filename, order, content);
} }
public IPackage OpenPackage(string filename, string annotation, int order) public IReadOnlyPackage OpenPackage(string filename, string annotation, int order)
{ {
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase)) if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
{ {
@@ -81,7 +69,17 @@ namespace OpenRA.FileSystem
return new Folder(filename, order); return new Folder(filename, order);
} }
public void Mount(IPackage mount) public IReadWritePackage OpenWritablePackage(string filename, int order)
{
if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(this, filename, order);
if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(this, filename, order);
return new Folder(filename, order);
}
public void Mount(IReadOnlyPackage mount)
{ {
if (!MountedPackages.Contains(mount)) if (!MountedPackages.Contains(mount))
MountedPackages.Add(mount); MountedPackages.Add(mount);
@@ -105,7 +103,7 @@ namespace OpenRA.FileSystem
a(); a();
} }
void MountInner(IPackage package) void MountInner(IReadOnlyPackage package)
{ {
MountedPackages.Add(package); MountedPackages.Add(package);
@@ -124,7 +122,7 @@ namespace OpenRA.FileSystem
} }
} }
public bool Unmount(IPackage mount) public bool Unmount(IReadOnlyPackage mount)
{ {
if (MountedPackages.Contains(mount)) if (MountedPackages.Contains(mount))
mount.Dispose(); mount.Dispose();
@@ -139,8 +137,8 @@ namespace OpenRA.FileSystem
MountedPackages.Clear(); MountedPackages.Clear();
PackagePaths.Clear(); PackagePaths.Clear();
classicHashIndex = new Cache<uint, List<IPackage>>(_ => new List<IPackage>()); classicHashIndex = new Cache<uint, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
crcHashIndex = new Cache<uint, List<IPackage>>(_ => new List<IPackage>()); crcHashIndex = new Cache<uint, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
} }
public void LoadFromManifest(Manifest manifest) public void LoadFromManifest(Manifest manifest)
@@ -203,7 +201,7 @@ namespace OpenRA.FileSystem
} }
// Ask each package individually // Ask each package individually
IPackage package; IReadOnlyPackage package;
if (explicitPackage && !string.IsNullOrEmpty(packageName)) if (explicitPackage && !string.IsNullOrEmpty(packageName))
package = MountedPackages.Where(x => x.Name == packageName).MaxByOrDefault(x => x.Priority); package = MountedPackages.Where(x => x.Name == packageName).MaxByOrDefault(x => x.Priority);
else else

View File

@@ -13,7 +13,7 @@ using System.IO;
namespace OpenRA.FileSystem namespace OpenRA.FileSystem
{ {
public sealed class Folder : IPackage public sealed class Folder : IReadWritePackage
{ {
readonly string path; readonly string path;
readonly int priority; readonly int priority;

View File

@@ -14,15 +14,19 @@ using System.IO;
namespace OpenRA.FileSystem namespace OpenRA.FileSystem
{ {
public interface IPackage : IDisposable public interface IReadOnlyPackage : IDisposable
{ {
Stream GetContent(string filename); Stream GetContent(string filename);
bool Exists(string filename); bool Exists(string filename);
IEnumerable<uint> ClassicHashes(); IEnumerable<uint> ClassicHashes();
IEnumerable<uint> CrcHashes(); IEnumerable<uint> CrcHashes();
IEnumerable<string> AllFileNames(); IEnumerable<string> AllFileNames();
void Write(Dictionary<string, byte[]> contents);
int Priority { get; } int Priority { get; }
string Name { get; } string Name { get; }
} }
public interface IReadWritePackage : IReadOnlyPackage
{
void Write(Dictionary<string, byte[]> contents);
}
} }

View File

@@ -17,7 +17,7 @@ using ICSharpCode.SharpZipLib.Zip.Compression;
namespace OpenRA.FileSystem namespace OpenRA.FileSystem
{ {
public sealed class InstallShieldCABExtractor : IPackage public sealed class InstallShieldCABExtractor : IReadOnlyPackage
{ {
const uint FileSplit = 0x1; const uint FileSplit = 0x1;
const uint FileObfuscated = 0x2; const uint FileObfuscated = 0x2;
@@ -451,11 +451,6 @@ namespace OpenRA.FileSystem
GetContentById(index, destfile); GetContentById(index, destfile);
} }
public void Write(Dictionary<string, byte[]> input)
{
throw new NotImplementedException("Cannot Add Files To Cab");
}
public IEnumerable<uint> ClassicHashes() public IEnumerable<uint> ClassicHashes()
{ {
return fileLookup.Keys.Select(k => PackageEntry.HashFilename(k, PackageHashType.Classic)); return fileLookup.Keys.Select(k => PackageEntry.HashFilename(k, PackageHashType.Classic));

View File

@@ -15,7 +15,7 @@ using OpenRA.FileFormats;
namespace OpenRA.FileSystem namespace OpenRA.FileSystem
{ {
public sealed class InstallShieldPackage : IPackage public sealed class InstallShieldPackage : IReadOnlyPackage
{ {
readonly Dictionary<uint, PackageEntry> index = new Dictionary<uint, PackageEntry>(); readonly Dictionary<uint, PackageEntry> index = new Dictionary<uint, PackageEntry>();
readonly List<string> filenames; readonly List<string> filenames;

View File

@@ -18,7 +18,7 @@ using OpenRA.Primitives;
namespace OpenRA.FileSystem namespace OpenRA.FileSystem
{ {
public sealed class MixFile : IPackage public sealed class MixFile : IReadOnlyPackage
{ {
readonly Dictionary<uint, PackageEntry> index; readonly Dictionary<uint, PackageEntry> index;
readonly long dataStart; readonly long dataStart;
@@ -28,31 +28,6 @@ namespace OpenRA.FileSystem
readonly FileSystem context; readonly FileSystem context;
readonly PackageHashType type; readonly PackageHashType type;
// Save a mix to disk with the given contents
public MixFile(FileSystem context, string filename, int priority, Dictionary<string, byte[]> contents)
{
this.filename = filename;
this.priority = priority;
this.type = PackageHashType.Classic;
this.context = context;
if (File.Exists(filename))
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(FileSystem context, string filename, PackageHashType type, int priority) public MixFile(FileSystem context, string filename, PackageHashType type, int priority)
{ {
this.filename = filename; this.filename = filename;
@@ -248,45 +223,6 @@ namespace OpenRA.FileSystem
public int Priority { get { return 1000 + priority; } } public int Priority { get { return 1000 + priority; } }
public string Name { get { return filename; } } public string Name { get { return filename; } }
public void Write(Dictionary<string, byte[]> contents)
{
// Cannot modify existing mixfile - rename existing file and
// create a new one with original content plus modifications
context.Unmount(this);
// TODO: Add existing data to the contents list
if (index.Count > 0)
throw new NotImplementedException("Updating mix files unfinished");
// Construct a list of entries for the file header
uint dataSize = 0;
var items = new List<PackageEntry>();
foreach (var kv in contents)
{
var length = (uint)kv.Value.Length;
var hash = PackageEntry.HashFilename(Path.GetFileName(kv.Key), type);
items.Add(new PackageEntry(hash, dataSize, length));
dataSize += length;
}
// Write the new file
s.Seek(0, SeekOrigin.Begin);
using (var writer = new BinaryWriter(s))
{
// Write file header
writer.Write((ushort)items.Count);
writer.Write(dataSize);
foreach (var item in items)
item.Write(writer);
writer.Flush();
// Copy file data
foreach (var file in contents)
s.Write(file.Value);
}
}
public void Dispose() public void Dispose()
{ {
s.Dispose(); s.Dispose();

View File

@@ -21,7 +21,7 @@ namespace OpenRA.FileSystem
public string Filename; public string Filename;
} }
public sealed class PakFile : IPackage public sealed class PakFile : IReadOnlyPackage
{ {
readonly string filename; readonly string filename;
readonly int priority; readonly int priority;
@@ -93,11 +93,6 @@ namespace OpenRA.FileSystem
return index.ContainsKey(filename); return index.ContainsKey(filename);
} }
public void Write(Dictionary<string, byte[]> contents)
{
throw new NotImplementedException("Cannot save Pak archives.");
}
public int Priority { get { return 1000 + priority; } } public int Priority { get { return 1000 + priority; } }
public string Name { get { return filename; } } public string Name { get { return filename; } }

View File

@@ -17,7 +17,7 @@ using SZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile;
namespace OpenRA.FileSystem namespace OpenRA.FileSystem
{ {
public sealed class ZipFile : IPackage public sealed class ZipFile : IReadWritePackage
{ {
readonly string filename; readonly string filename;
readonly int priority; readonly int priority;

View File

@@ -157,7 +157,7 @@ namespace OpenRA
[FieldLoader.Ignore] public readonly WVec[] SubCellOffsets; [FieldLoader.Ignore] public readonly WVec[] SubCellOffsets;
public readonly SubCell DefaultSubCell; public readonly SubCell DefaultSubCell;
public readonly SubCell LastSubCell; public readonly SubCell LastSubCell;
[FieldLoader.Ignore] public IPackage Container; [FieldLoader.Ignore] public IReadWritePackage Container;
public string Path { get; private set; } public string Path { get; private set; }
// Yaml map data // Yaml map data
@@ -317,7 +317,7 @@ namespace OpenRA
public Map(string path) public Map(string path)
{ {
Path = path; Path = path;
Container = Game.ModData.ModFiles.OpenPackage(path, null, int.MaxValue); Container = Game.ModData.ModFiles.OpenWritablePackage(path, int.MaxValue);
AssertExists("map.yaml"); AssertExists("map.yaml");
AssertExists("map.bin"); AssertExists("map.bin");

View File

@@ -33,7 +33,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
ScrollPanelWidget assetList; ScrollPanelWidget assetList;
ScrollItemWidget template; ScrollItemWidget template;
IPackage assetSource = null; IReadOnlyPackage assetSource = null;
List<string> availableShps = new List<string>(); List<string> availableShps = new List<string>();
bool animateFrames = false; bool animateFrames = false;
@@ -334,7 +334,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
bool ShowSourceDropdown(DropDownButtonWidget dropdown) bool ShowSourceDropdown(DropDownButtonWidget dropdown)
{ {
Func<IPackage, ScrollItemWidget, ScrollItemWidget> setupItem = (source, itemTemplate) => Func<IReadOnlyPackage, ScrollItemWidget, ScrollItemWidget> setupItem = (source, itemTemplate) =>
{ {
var item = ScrollItemWidget.Setup(itemTemplate, var item = ScrollItemWidget.Setup(itemTemplate,
() => assetSource == source, () => assetSource == source,