Merge pull request #6255 from ScottNZ/generals
Add support for C&C Generals .big archive files
This commit is contained in:
111
OpenRA.Game/FileSystem/BigFile.cs
Normal file
111
OpenRA.Game/FileSystem/BigFile.cs
Normal file
@@ -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<string, Entry> entries = new Dictionary<string, Entry>();
|
||||||
|
|
||||||
|
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<uint> ClassicHashes()
|
||||||
|
{
|
||||||
|
return entries.Keys.Select(filename => PackageEntry.HashFilename(filename, PackageHashType.Classic));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<uint> CrcHashes()
|
||||||
|
{
|
||||||
|
return Enumerable.Empty<uint>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> AllFileNames()
|
||||||
|
{
|
||||||
|
return entries.Keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(Dictionary<string, byte[]> contents)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,40 +62,46 @@ namespace OpenRA.FileSystem
|
|||||||
{
|
{
|
||||||
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
|
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
|
||||||
return new MixFile(filename, order, content);
|
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);
|
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);
|
return new ZipFile(filename, order, content);
|
||||||
else if (filename.EndsWith(".RS", StringComparison.InvariantCultureIgnoreCase))
|
if (filename.EndsWith(".RS", StringComparison.InvariantCultureIgnoreCase))
|
||||||
throw new NotImplementedException("Creating .RS archives is unsupported");
|
throw new NotImplementedException("The creation of .RS archives is unimplemented");
|
||||||
else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
|
if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
|
||||||
throw new NotImplementedException("Creating .Z archives is unsupported");
|
throw new NotImplementedException("The creation of .Z archives is unimplemented");
|
||||||
else if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase))
|
if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase))
|
||||||
throw new NotImplementedException("Creating .PAK archives is unsupported");
|
throw new NotImplementedException("The creation of .PAK archives is unimplemented");
|
||||||
else
|
if (filename.EndsWith(".big", StringComparison.InvariantCultureIgnoreCase))
|
||||||
return new Folder(filename, order, content);
|
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)
|
public static IFolder OpenPackage(string filename, string annotation, int order)
|
||||||
{
|
{
|
||||||
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
|
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
var type = string.IsNullOrEmpty(annotation) ? PackageHashType.Classic :
|
var type = string.IsNullOrEmpty(annotation)
|
||||||
FieldLoader.GetValue<PackageHashType>("(value)", annotation);
|
? PackageHashType.Classic
|
||||||
|
: FieldLoader.GetValue<PackageHashType>("(value)", annotation);
|
||||||
|
|
||||||
return new MixFile(filename, type, order);
|
return new MixFile(filename, type, order);
|
||||||
}
|
}
|
||||||
else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
|
if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
|
||||||
return new ZipFile(filename, order);
|
return new ZipFile(filename, order);
|
||||||
else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
|
if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
|
||||||
return new ZipFile(filename, order);
|
return new ZipFile(filename, order);
|
||||||
else if (filename.EndsWith(".RS", StringComparison.InvariantCultureIgnoreCase))
|
if (filename.EndsWith(".RS", StringComparison.InvariantCultureIgnoreCase))
|
||||||
return new D2kSoundResources(filename, order);
|
return new D2kSoundResources(filename, order);
|
||||||
else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
|
if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
|
||||||
return new InstallShieldPackage(filename, order);
|
return new InstallShieldPackage(filename, order);
|
||||||
else if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase))
|
if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase))
|
||||||
return new PakFile(filename, order);
|
return new PakFile(filename, order);
|
||||||
else
|
if (filename.EndsWith(".big", StringComparison.InvariantCultureIgnoreCase))
|
||||||
return new Folder(filename, order);
|
return new BigFile(filename, order);
|
||||||
|
|
||||||
|
return new Folder(filename, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mount(string name)
|
public static void Mount(string name)
|
||||||
|
|||||||
@@ -255,6 +255,7 @@
|
|||||||
<Compile Include="FileSystem\MixFile.cs" />
|
<Compile Include="FileSystem\MixFile.cs" />
|
||||||
<Compile Include="FileSystem\Pak.cs" />
|
<Compile Include="FileSystem\Pak.cs" />
|
||||||
<Compile Include="FileSystem\ZipFile.cs" />
|
<Compile Include="FileSystem\ZipFile.cs" />
|
||||||
|
<Compile Include="FileSystem\BigFile.cs" />
|
||||||
<Compile Include="Map\PlayerReference.cs" />
|
<Compile Include="Map\PlayerReference.cs" />
|
||||||
<Compile Include="Map\SmudgeReference.cs" />
|
<Compile Include="Map\SmudgeReference.cs" />
|
||||||
<Compile Include="Map\TileReference.cs" />
|
<Compile Include="Map\TileReference.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user