Merge pull request #10525 from pchote/split-package-interfaces
Split IPackage into IReadOnlyPackage and IReadWritePackage
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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; } }
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user