diff --git a/OpenRA.Game/FileSystem/BigFile.cs b/OpenRA.Game/FileSystem/BigFile.cs new file mode 100644 index 0000000000..d4819425e8 --- /dev/null +++ b/OpenRA.Game/FileSystem/BigFile.cs @@ -0,0 +1,111 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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; + +namespace OpenRA.FileSystem +{ + public class BigFile : IFolder + { + public string Name { get; private set; } + public int Priority { get; private set; } + readonly Dictionary entries = new Dictionary(); + + public BigFile(string filename, int priority) + { + Name = filename; + Priority = priority; + + var s = GlobalFileSystem.Open(filename); + + if (s.ReadASCII(4) != "BIGF") + throw new InvalidDataException("Header is not BIGF"); + + // Total archive size. + s.ReadUInt32(); + + var entryCount = s.ReadUInt32(); + if (BitConverter.IsLittleEndian) + entryCount = int2.Swap(entryCount); + + // First entry offset? This is apparently bogus for EA's .big files + // and we don't have to try seeking there since the entries typically start next in EA's .big files. + s.ReadUInt32(); + + for (var i = 0; i < entryCount; i++) + { + var entry = new Entry(s); + entries.Add(entry.Path, entry); + } + } + + class Entry + { + readonly Stream s; + readonly uint offset; + readonly uint size; + public readonly string Path; + + public Entry(Stream s) + { + this.s = s; + + offset = s.ReadUInt32(); + size = s.ReadUInt32(); + if (BitConverter.IsLittleEndian) + { + offset = int2.Swap(offset); + size = int2.Swap(size); + } + + Path = s.ReadASCIIZ(); + } + + public Stream GetData() + { + s.Position = offset; + return new MemoryStream(s.ReadBytes((int)size)); + } + } + + public Stream GetContent(string filename) + { + return entries[filename].GetData(); + } + + public bool Exists(string filename) + { + return entries.ContainsKey(filename); + } + + public IEnumerable ClassicHashes() + { + return entries.Keys.Select(filename => PackageEntry.HashFilename(filename, PackageHashType.Classic)); + } + + public IEnumerable CrcHashes() + { + return Enumerable.Empty(); + } + + public IEnumerable AllFileNames() + { + return entries.Keys; + } + + public void Write(Dictionary contents) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/OpenRA.Game/FileSystem/GlobalFileSystem.cs b/OpenRA.Game/FileSystem/GlobalFileSystem.cs index fd2dbbde6e..38b2030a88 100644 --- a/OpenRA.Game/FileSystem/GlobalFileSystem.cs +++ b/OpenRA.Game/FileSystem/GlobalFileSystem.cs @@ -62,40 +62,46 @@ namespace OpenRA.FileSystem { if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase)) return new MixFile(filename, order, content); - else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) + if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) return new ZipFile(filename, order, content); - else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) + if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) return new ZipFile(filename, order, content); - else if (filename.EndsWith(".RS", StringComparison.InvariantCultureIgnoreCase)) - throw new NotImplementedException("Creating .RS archives is unsupported"); - else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase)) - throw new NotImplementedException("Creating .Z archives is unsupported"); - else if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase)) - throw new NotImplementedException("Creating .PAK archives is unsupported"); - else - return new Folder(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"); + + return new Folder(filename, order, content); } public static IFolder OpenPackage(string filename, string annotation, int order) { if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase)) { - var type = string.IsNullOrEmpty(annotation) ? PackageHashType.Classic : - FieldLoader.GetValue("(value)", annotation); + var type = string.IsNullOrEmpty(annotation) + ? PackageHashType.Classic + : FieldLoader.GetValue("(value)", annotation); + return new MixFile(filename, type, order); } - else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) + if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) return new ZipFile(filename, order); - else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) + if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) return new ZipFile(filename, order); - else if (filename.EndsWith(".RS", StringComparison.InvariantCultureIgnoreCase)) + if (filename.EndsWith(".RS", StringComparison.InvariantCultureIgnoreCase)) return new D2kSoundResources(filename, order); - else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase)) + if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase)) return new InstallShieldPackage(filename, order); - else if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase)) + if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase)) return new PakFile(filename, order); - else - return new Folder(filename, order); + if (filename.EndsWith(".big", StringComparison.InvariantCultureIgnoreCase)) + return new BigFile(filename, order); + + return new Folder(filename, order); } public static void Mount(string name) diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 36eeea7787..c66c36231f 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -255,6 +255,7 @@ +