diff --git a/OpenRA.Game/FileSystem/BagFile.cs b/OpenRA.Game/FileSystem/BagFile.cs index 67ee2fdfcf..2c24d232ac 100644 --- a/OpenRA.Game/FileSystem/BagFile.cs +++ b/OpenRA.Game/FileSystem/BagFile.cs @@ -19,7 +19,7 @@ using OpenRA.Primitives; namespace OpenRA.FileSystem { - public sealed class BagFile : IPackage + public sealed class BagFile : IReadOnlyPackage { 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)); } - public void Write(Dictionary contents) - { - context.Unmount(this); - throw new NotImplementedException("Updating bag files unsupported"); - } - public void Dispose() { s.Dispose(); diff --git a/OpenRA.Game/FileSystem/BigFile.cs b/OpenRA.Game/FileSystem/BigFile.cs index ec3dc977a4..8d8dc559ef 100644 --- a/OpenRA.Game/FileSystem/BigFile.cs +++ b/OpenRA.Game/FileSystem/BigFile.cs @@ -15,7 +15,7 @@ using System.Linq; namespace OpenRA.FileSystem { - public sealed class BigFile : IPackage + public sealed class BigFile : IReadOnlyPackage { public string Name { get; private set; } public int Priority { get; private set; } @@ -111,11 +111,6 @@ namespace OpenRA.FileSystem return entries.Keys; } - public void Write(Dictionary contents) - { - throw new NotImplementedException(); - } - public void Dispose() { s.Dispose(); diff --git a/OpenRA.Game/FileSystem/D2kSoundResources.cs b/OpenRA.Game/FileSystem/D2kSoundResources.cs index 852a5160b2..2e2bc35c96 100644 --- a/OpenRA.Game/FileSystem/D2kSoundResources.cs +++ b/OpenRA.Game/FileSystem/D2kSoundResources.cs @@ -14,7 +14,7 @@ using System.IO; namespace OpenRA.FileSystem { - public sealed class D2kSoundResources : IPackage + public sealed class D2kSoundResources : IReadOnlyPackage { readonly Stream s; @@ -94,11 +94,6 @@ namespace OpenRA.FileSystem yield break; } - public void Write(Dictionary contents) - { - throw new NotImplementedException("Cannot save Dune 2000 Sound Resources."); - } - public void Dispose() { s.Dispose(); diff --git a/OpenRA.Game/FileSystem/FileSystem.cs b/OpenRA.Game/FileSystem/FileSystem.cs index 1235d43ae8..3658ab36d2 100644 --- a/OpenRA.Game/FileSystem/FileSystem.cs +++ b/OpenRA.Game/FileSystem/FileSystem.cs @@ -20,37 +20,25 @@ namespace OpenRA.FileSystem public class FileSystem { public readonly List PackagePaths = new List(); - public readonly List MountedPackages = new List(); + public readonly List MountedPackages = new List(); static readonly Dictionary AssemblyCache = new Dictionary(); int order; - Cache> crcHashIndex = new Cache>(_ => new List()); - Cache> classicHashIndex = new Cache>(_ => new List()); + Cache> crcHashIndex = new Cache>(_ => new List()); + Cache> classicHashIndex = new Cache>(_ => new List()); - public IPackage CreatePackage(string filename, int order, Dictionary content) + public IReadWritePackage CreatePackage(string filename, int order, Dictionary content) { - if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase)) - return new MixFile(this, filename, order, content); if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) return new ZipFile(this, filename, order, content); if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) 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); } - public IPackage OpenPackage(string filename, string annotation, int order) + public IReadOnlyPackage OpenPackage(string filename, string annotation, int order) { if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase)) { @@ -81,7 +69,17 @@ namespace OpenRA.FileSystem 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)) MountedPackages.Add(mount); @@ -105,7 +103,7 @@ namespace OpenRA.FileSystem a(); } - void MountInner(IPackage package) + void MountInner(IReadOnlyPackage 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)) mount.Dispose(); @@ -139,8 +137,8 @@ namespace OpenRA.FileSystem MountedPackages.Clear(); PackagePaths.Clear(); - classicHashIndex = new Cache>(_ => new List()); - crcHashIndex = new Cache>(_ => new List()); + classicHashIndex = new Cache>(_ => new List()); + crcHashIndex = new Cache>(_ => new List()); } public void LoadFromManifest(Manifest manifest) @@ -203,7 +201,7 @@ namespace OpenRA.FileSystem } // Ask each package individually - IPackage package; + IReadOnlyPackage package; if (explicitPackage && !string.IsNullOrEmpty(packageName)) package = MountedPackages.Where(x => x.Name == packageName).MaxByOrDefault(x => x.Priority); else diff --git a/OpenRA.Game/FileSystem/Folder.cs b/OpenRA.Game/FileSystem/Folder.cs index 920948b22e..5fe419b2f9 100644 --- a/OpenRA.Game/FileSystem/Folder.cs +++ b/OpenRA.Game/FileSystem/Folder.cs @@ -13,7 +13,7 @@ using System.IO; namespace OpenRA.FileSystem { - public sealed class Folder : IPackage + public sealed class Folder : IReadWritePackage { readonly string path; readonly int priority; diff --git a/OpenRA.Game/FileSystem/IPackage.cs b/OpenRA.Game/FileSystem/IPackage.cs index 226ba0bd62..e336b0602e 100644 --- a/OpenRA.Game/FileSystem/IPackage.cs +++ b/OpenRA.Game/FileSystem/IPackage.cs @@ -14,15 +14,19 @@ using System.IO; namespace OpenRA.FileSystem { - public interface IPackage : IDisposable + public interface IReadOnlyPackage : IDisposable { Stream GetContent(string filename); bool Exists(string filename); IEnumerable ClassicHashes(); IEnumerable CrcHashes(); IEnumerable AllFileNames(); - void Write(Dictionary contents); int Priority { get; } string Name { get; } } + + public interface IReadWritePackage : IReadOnlyPackage + { + void Write(Dictionary contents); + } } diff --git a/OpenRA.Game/FileSystem/InstallShieldCABExtractor.cs b/OpenRA.Game/FileSystem/InstallShieldCABExtractor.cs index f4e8e22de0..ac9deb296c 100644 --- a/OpenRA.Game/FileSystem/InstallShieldCABExtractor.cs +++ b/OpenRA.Game/FileSystem/InstallShieldCABExtractor.cs @@ -17,7 +17,7 @@ using ICSharpCode.SharpZipLib.Zip.Compression; namespace OpenRA.FileSystem { - public sealed class InstallShieldCABExtractor : IPackage + public sealed class InstallShieldCABExtractor : IReadOnlyPackage { const uint FileSplit = 0x1; const uint FileObfuscated = 0x2; @@ -451,11 +451,6 @@ namespace OpenRA.FileSystem GetContentById(index, destfile); } - public void Write(Dictionary input) - { - throw new NotImplementedException("Cannot Add Files To Cab"); - } - public IEnumerable ClassicHashes() { return fileLookup.Keys.Select(k => PackageEntry.HashFilename(k, PackageHashType.Classic)); diff --git a/OpenRA.Game/FileSystem/InstallShieldPackage.cs b/OpenRA.Game/FileSystem/InstallShieldPackage.cs index 2355209ff4..dd28d1042d 100644 --- a/OpenRA.Game/FileSystem/InstallShieldPackage.cs +++ b/OpenRA.Game/FileSystem/InstallShieldPackage.cs @@ -15,7 +15,7 @@ using OpenRA.FileFormats; namespace OpenRA.FileSystem { - public sealed class InstallShieldPackage : IPackage + public sealed class InstallShieldPackage : IReadOnlyPackage { readonly Dictionary index = new Dictionary(); readonly List filenames; diff --git a/OpenRA.Game/FileSystem/MixFile.cs b/OpenRA.Game/FileSystem/MixFile.cs index 0faaeb0c55..25532a8ff5 100644 --- a/OpenRA.Game/FileSystem/MixFile.cs +++ b/OpenRA.Game/FileSystem/MixFile.cs @@ -18,7 +18,7 @@ using OpenRA.Primitives; namespace OpenRA.FileSystem { - public sealed class MixFile : IPackage + public sealed class MixFile : IReadOnlyPackage { readonly Dictionary index; readonly long dataStart; @@ -28,31 +28,6 @@ namespace OpenRA.FileSystem readonly FileSystem context; readonly PackageHashType type; - // Save a mix to disk with the given contents - public MixFile(FileSystem context, string filename, int priority, Dictionary 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(); - 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) { this.filename = filename; @@ -248,45 +223,6 @@ namespace OpenRA.FileSystem public int Priority { get { return 1000 + priority; } } public string Name { get { return filename; } } - public void Write(Dictionary 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(); - 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() { s.Dispose(); diff --git a/OpenRA.Game/FileSystem/Pak.cs b/OpenRA.Game/FileSystem/Pak.cs index d3c0d7e764..1e9f8727a2 100644 --- a/OpenRA.Game/FileSystem/Pak.cs +++ b/OpenRA.Game/FileSystem/Pak.cs @@ -21,7 +21,7 @@ namespace OpenRA.FileSystem public string Filename; } - public sealed class PakFile : IPackage + public sealed class PakFile : IReadOnlyPackage { readonly string filename; readonly int priority; @@ -93,11 +93,6 @@ namespace OpenRA.FileSystem return index.ContainsKey(filename); } - public void Write(Dictionary contents) - { - throw new NotImplementedException("Cannot save Pak archives."); - } - public int Priority { get { return 1000 + priority; } } public string Name { get { return filename; } } diff --git a/OpenRA.Game/FileSystem/ZipFile.cs b/OpenRA.Game/FileSystem/ZipFile.cs index 9699b0b216..bc8bb639cd 100644 --- a/OpenRA.Game/FileSystem/ZipFile.cs +++ b/OpenRA.Game/FileSystem/ZipFile.cs @@ -17,7 +17,7 @@ using SZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile; namespace OpenRA.FileSystem { - public sealed class ZipFile : IPackage + public sealed class ZipFile : IReadWritePackage { readonly string filename; readonly int priority; diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index c7060c8e6b..84c0db3cc4 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -157,7 +157,7 @@ namespace OpenRA [FieldLoader.Ignore] public readonly WVec[] SubCellOffsets; public readonly SubCell DefaultSubCell; public readonly SubCell LastSubCell; - [FieldLoader.Ignore] public IPackage Container; + [FieldLoader.Ignore] public IReadWritePackage Container; public string Path { get; private set; } // Yaml map data @@ -317,7 +317,7 @@ namespace OpenRA public Map(string 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.bin"); diff --git a/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs index b878bf343c..8de9d08930 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs @@ -33,7 +33,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic ScrollPanelWidget assetList; ScrollItemWidget template; - IPackage assetSource = null; + IReadOnlyPackage assetSource = null; List availableShps = new List(); bool animateFrames = false; @@ -334,7 +334,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic bool ShowSourceDropdown(DropDownButtonWidget dropdown) { - Func setupItem = (source, itemTemplate) => + Func setupItem = (source, itemTemplate) => { var item = ScrollItemWidget.Setup(itemTemplate, () => assetSource == source,