Implement mod-defined package loaders.
This commit is contained in:
@@ -34,80 +34,69 @@ namespace OpenRA.FileSystem
|
||||
// Mod packages that should not be disposed
|
||||
readonly List<IReadOnlyPackage> modPackages = new List<IReadOnlyPackage>();
|
||||
readonly IReadOnlyDictionary<string, Manifest> installedMods;
|
||||
readonly IPackageLoader[] packageLoaders;
|
||||
|
||||
Cache<string, List<IReadOnlyPackage>> fileIndex = new Cache<string, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
|
||||
|
||||
public FileSystem(IReadOnlyDictionary<string, Manifest> installedMods)
|
||||
public FileSystem(IReadOnlyDictionary<string, Manifest> installedMods, IPackageLoader[] packageLoaders)
|
||||
{
|
||||
this.installedMods = installedMods;
|
||||
this.packageLoaders = packageLoaders
|
||||
.Append(new ZipFileLoader())
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public bool TryParsePackage(Stream stream, string filename, out IReadOnlyPackage package)
|
||||
{
|
||||
package = null;
|
||||
foreach (var packageLoader in packageLoaders)
|
||||
if (packageLoader.TryParsePackage(stream, filename, this, out package))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public IReadOnlyPackage OpenPackage(string filename)
|
||||
{
|
||||
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new MixFile(this, filename);
|
||||
if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(this, filename);
|
||||
if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new ZipFile(this, filename);
|
||||
if (filename.EndsWith(".RS", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new D2kSoundResources(this, filename);
|
||||
if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new InstallShieldPackage(this, filename);
|
||||
if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new PakFile(this, filename);
|
||||
if (filename.EndsWith(".big", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new BigFile(this, filename);
|
||||
if (filename.EndsWith(".bag", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new BagFile(this, filename);
|
||||
// Raw directories are the easiest and one of the most common cases, so try these first
|
||||
var resolvedPath = Platform.ResolvePath(filename);
|
||||
if (!filename.Contains("|") && Directory.Exists(resolvedPath))
|
||||
return new Folder(resolvedPath);
|
||||
|
||||
// Children of another package require special handling
|
||||
IReadOnlyPackage parent;
|
||||
string subPath = null;
|
||||
if (TryGetPackageContaining(filename, out parent, out subPath))
|
||||
return OpenPackage(subPath, parent);
|
||||
return parent.OpenPackage(subPath, this);
|
||||
|
||||
return new Folder(Platform.ResolvePath(filename));
|
||||
}
|
||||
// Try and open it normally
|
||||
IReadOnlyPackage package;
|
||||
var stream = Open(filename);
|
||||
if (TryParsePackage(stream, filename, out package))
|
||||
return package;
|
||||
|
||||
public IReadOnlyPackage OpenPackage(string filename, IReadOnlyPackage parent)
|
||||
{
|
||||
// HACK: limit support to zip and folder until we generalize the PackageLoader support
|
||||
if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
using (var s = parent.GetStream(filename))
|
||||
return new ZipFile(s, filename, parent);
|
||||
}
|
||||
|
||||
if (parent is ZipFile)
|
||||
return new ZipFolder(this, (ZipFile)parent, filename, filename);
|
||||
|
||||
if (parent is ZipFolder)
|
||||
{
|
||||
var folder = (ZipFolder)parent;
|
||||
return new ZipFolder(this, folder.Parent, folder.Name + "/" + filename, filename);
|
||||
}
|
||||
|
||||
if (parent is Folder)
|
||||
{
|
||||
var subFolder = Platform.ResolvePath(Path.Combine(parent.Name, filename));
|
||||
if (Directory.Exists(subFolder))
|
||||
return new Folder(subFolder);
|
||||
}
|
||||
// No package loaders took ownership of the stream, so clean it up
|
||||
stream.Dispose();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IReadOnlyPackage OpenPackage(string filename, IReadOnlyPackage parent)
|
||||
{
|
||||
// TODO: Make legacy callers access the parent package directly
|
||||
return parent.OpenPackage(filename, this);
|
||||
}
|
||||
|
||||
public void Mount(string name, string explicitName = null)
|
||||
{
|
||||
var optional = name.StartsWith("~");
|
||||
var optional = name.StartsWith("~", StringComparison.Ordinal);
|
||||
if (optional)
|
||||
name = name.Substring(1);
|
||||
|
||||
try
|
||||
{
|
||||
IReadOnlyPackage package;
|
||||
if (name.StartsWith("$"))
|
||||
if (name.StartsWith("$", StringComparison.Ordinal))
|
||||
{
|
||||
name = name.Substring(1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user