#region Copyright & License Information /* * Copyright 2007-2021 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, either version 3 of * the License, or (at your option) any later version. For more * information, see COPYING. */ #endregion using System; using System.Collections.Generic; using System.IO; using OpenRA.FileSystem; using OpenRA.Primitives; using FS = OpenRA.FileSystem.FileSystem; namespace OpenRA.Mods.Cnc.FileSystem { public class BigLoader : IPackageLoader { sealed class BigFile : IReadOnlyPackage { public string Name { get; private set; } public IEnumerable Contents => index.Keys; readonly Dictionary index = new Dictionary(); readonly Stream s; public BigFile(Stream s, string filename) { Name = filename; this.s = s; try { /* var signature = */ s.ReadASCII(4); // 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); index.Add(entry.Path, entry); } } catch { Dispose(); throw; } } class Entry { public readonly uint Offset; public readonly uint Size; public readonly string Path; public Entry(Stream s) { Offset = s.ReadUInt32(); Size = s.ReadUInt32(); if (BitConverter.IsLittleEndian) { Offset = int2.Swap(Offset); Size = int2.Swap(Size); } Path = s.ReadASCIIZ(); } } public Stream GetStream(string filename) { var entry = index[filename]; return SegmentStream.CreateWithoutOwningStream(s, entry.Offset, (int)entry.Size); } public bool Contains(string filename) { return index.ContainsKey(filename); } public IReadOnlyPackage OpenPackage(string filename, FS context) { // Not implemented return null; } public void Dispose() { s.Dispose(); } } bool IPackageLoader.TryParsePackage(Stream s, string filename, FS context, out IReadOnlyPackage package) { // Take a peek at the file signature var signature = s.ReadASCII(4); s.Position -= 4; if (signature != "BIGF") { package = null; return false; } package = new BigFile(s, filename); return true; } } }