Merge pull request #10530 from pchote/remove-external-hashes

Index filesystem contents by filename instead of hash.
This commit is contained in:
Oliver Brakmann
2016-01-29 21:12:31 +01:00
22 changed files with 138 additions and 332 deletions

View File

@@ -15,11 +15,14 @@ namespace OpenRA
// Referenced from ModMetadata, so needs to be in OpenRA.Game :(
public class ContentInstaller : IGlobalModData
{
public enum FilenameCase { Input, ForceLower, ForceUpper }
public readonly string[] TestFiles = { };
public readonly string[] DiskTestFiles = { };
public readonly string PackageToExtractFromCD = null;
public readonly bool OverwriteFiles = true;
public readonly FilenameCase OutputFilenameCase = FilenameCase.ForceLower;
public readonly Dictionary<string, string[]> CopyFilesFromCD = new Dictionary<string, string[]>();
public readonly Dictionary<string, string[]> ExtractFilesFromCD = new Dictionary<string, string[]>();

View File

@@ -21,19 +21,15 @@ namespace OpenRA.FileSystem
{
public sealed class BagFile : IReadOnlyPackage
{
static readonly uint[] Nothing = { };
readonly string bagFilename;
readonly Stream s;
readonly int bagFilePriority;
readonly Dictionary<uint, IdxEntry> index;
readonly FileSystem context;
readonly Dictionary<string, IdxEntry> index;
public BagFile(FileSystem context, string filename, int priority)
{
bagFilename = filename;
bagFilePriority = priority;
this.context = context;
// A bag file is always accompanied with an .idx counterpart
// For example: audio.bag requires the audio.idx file
@@ -44,7 +40,7 @@ namespace OpenRA.FileSystem
using (var indexStream = context.Open(indexFilename))
entries = new IdxReader(indexStream).Entries;
index = entries.ToDictionaryWithConflictLog(x => x.Hash,
index = entries.ToDictionaryWithConflictLog(x => x.Filename,
"{0} (bag format)".F(filename),
null, x => "(offs={0}, len={1})".F(x.Offset, x.Length));
@@ -54,10 +50,10 @@ namespace OpenRA.FileSystem
public int Priority { get { return 1000 + bagFilePriority; } }
public string Name { get { return bagFilename; } }
public Stream GetContent(uint hash)
public Stream GetContent(string filename)
{
IdxEntry entry;
if (!index.TryGetValue(hash, out entry))
if (!index.TryGetValue(filename, out entry))
return null;
s.Seek(entry.Offset, SeekOrigin.Begin);
@@ -120,59 +116,14 @@ namespace OpenRA.FileSystem
return mergedStream;
}
uint? FindMatchingHash(string filename)
{
var hash = IdxEntry.HashFilename(filename, PackageHashType.CRC32);
if (index.ContainsKey(hash))
return hash;
// Maybe we were given a raw hash?
uint raw;
if (!uint.TryParse(filename, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out raw))
return null;
if ("{0:X}".F(raw) == filename && index.ContainsKey(raw))
return raw;
return null;
}
public Stream GetContent(string filename)
{
var hash = FindMatchingHash(filename);
return hash.HasValue ? GetContent(hash.Value) : null;
}
public bool Exists(string filename)
{
return FindMatchingHash(filename).HasValue;
}
public IEnumerable<uint> ClassicHashes()
{
return Nothing;
}
public IEnumerable<uint> CrcHashes()
{
return index.Keys;
return index.ContainsKey(filename);
}
public IEnumerable<string> AllFileNames()
{
var lookup = new Dictionary<uint, string>();
if (context.Exists("global mix database.dat"))
{
var db = new XccGlobalDatabase(context.Open("global mix database.dat"));
foreach (var e in db.Entries)
{
var hash = IdxEntry.HashFilename(e, PackageHashType.CRC32);
if (!lookup.ContainsKey(hash))
lookup.Add(hash, e);
}
}
return index.Keys.Select(k => lookup.ContainsKey(k) ? lookup[k] : "{0:X}".F(k));
return index.Keys;
}
public void Dispose()

View File

@@ -96,16 +96,6 @@ namespace OpenRA.FileSystem
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;

View File

@@ -10,18 +10,29 @@
using System.Collections.Generic;
using System.IO;
using OpenRA.Primitives;
namespace OpenRA.FileSystem
{
public sealed class D2kSoundResources : IReadOnlyPackage
{
struct Entry
{
public readonly uint Offset;
public readonly uint Length;
public Entry(uint offset, uint length)
{
Offset = offset;
Length = length;
}
}
readonly Stream s;
readonly string filename;
readonly List<string> filenames;
readonly int priority;
readonly Dictionary<uint, PackageEntry> index = new Dictionary<uint, PackageEntry>();
readonly Dictionary<string, Entry> index = new Dictionary<string, Entry>();
public D2kSoundResources(FileSystem context, string filename, int priority)
{
@@ -31,20 +42,13 @@ namespace OpenRA.FileSystem
s = context.Open(filename);
try
{
filenames = new List<string>();
var headerLength = s.ReadUInt32();
while (s.Position < headerLength + 4)
{
var name = s.ReadASCIIZ();
var offset = s.ReadUInt32();
var length = s.ReadUInt32();
var hash = PackageEntry.HashFilename(name, PackageHashType.Classic);
if (!index.ContainsKey(hash))
index.Add(hash, new PackageEntry(hash, offset, length));
filenames.Add(name);
index.Add(name, new Entry(offset, length));
}
}
catch
@@ -54,45 +58,30 @@ namespace OpenRA.FileSystem
}
}
public Stream GetContent(uint hash)
public Stream GetContent(string filename)
{
PackageEntry e;
if (!index.TryGetValue(hash, out e))
Entry e;
if (!index.TryGetValue(filename, out e))
return null;
s.Seek(e.Offset, SeekOrigin.Begin);
return new MemoryStream(s.ReadBytes((int)e.Length));
}
public Stream GetContent(string filename)
{
return GetContent(PackageEntry.HashFilename(filename, PackageHashType.Classic));
}
public bool Exists(string filename)
{
return index.ContainsKey(PackageEntry.HashFilename(filename, PackageHashType.Classic));
return index.ContainsKey(filename);
}
public IEnumerable<string> AllFileNames()
{
return filenames;
return index.Keys;
}
public string Name { get { return filename; } }
public int Priority { get { return 1000 + priority; } }
public IEnumerable<uint> ClassicHashes()
{
return index.Keys;
}
public IEnumerable<uint> CrcHashes()
{
yield break;
}
public void Dispose()
{
s.Dispose();

View File

@@ -19,14 +19,12 @@ namespace OpenRA.FileSystem
{
public class FileSystem
{
public readonly List<string> PackagePaths = new List<string>();
public readonly List<IReadOnlyPackage> MountedPackages = new List<IReadOnlyPackage>();
static readonly Dictionary<string, Assembly> AssemblyCache = new Dictionary<string, Assembly>();
int order;
Cache<uint, List<IReadOnlyPackage>> crcHashIndex = new Cache<uint, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
Cache<uint, List<IReadOnlyPackage>> classicHashIndex = new Cache<uint, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
Cache<string, List<IReadOnlyPackage>> fileIndex = new Cache<string, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
public IReadWritePackage CreatePackage(string filename, int order, Dictionary<string, byte[]> content)
{
@@ -93,7 +91,6 @@ namespace OpenRA.FileSystem
name = Platform.ResolvePath(name);
PackagePaths.Add(name);
Action a = () => MountInner(OpenPackage(name, annotation, order++));
if (optional)
@@ -107,27 +104,23 @@ namespace OpenRA.FileSystem
{
MountedPackages.Add(package);
foreach (var hash in package.ClassicHashes())
foreach (var filename in package.AllFileNames())
{
var packageList = classicHashIndex[hash];
if (!packageList.Contains(package))
packageList.Add(package);
}
foreach (var hash in package.CrcHashes())
{
var packageList = crcHashIndex[hash];
var packageList = fileIndex[filename];
if (!packageList.Contains(package))
packageList.Add(package);
}
}
public bool Unmount(IReadOnlyPackage mount)
public bool Unmount(IReadOnlyPackage package)
{
if (MountedPackages.Contains(mount))
mount.Dispose();
foreach (var packagesForFile in fileIndex.Values)
packagesForFile.RemoveAll(p => p == package);
return MountedPackages.RemoveAll(f => f == mount) > 0;
if (MountedPackages.Contains(package))
package.Dispose();
return MountedPackages.RemoveAll(p => p == package) > 0;
}
public void UnmountAll()
@@ -136,9 +129,7 @@ namespace OpenRA.FileSystem
package.Dispose();
MountedPackages.Clear();
PackagePaths.Clear();
classicHashIndex = new Cache<uint, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
crcHashIndex = new Cache<uint, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
fileIndex = new Cache<string, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
}
public void LoadFromManifest(Manifest manifest)
@@ -151,10 +142,9 @@ namespace OpenRA.FileSystem
Mount(pkg.Key, pkg.Value);
}
Stream GetFromCache(PackageHashType type, string filename)
Stream GetFromCache(string filename)
{
var index = type == PackageHashType.CRC32 ? crcHashIndex : classicHashIndex;
var package = index[PackageEntry.HashFilename(filename, type)]
var package = fileIndex[filename]
.Where(x => x.Exists(filename))
.MinByOrDefault(x => x.Priority);
@@ -191,11 +181,7 @@ namespace OpenRA.FileSystem
// TODO: This disables caching for explicit package requests
if (filename.IndexOfAny(new[] { '/', '\\' }) == -1 && !explicitPackage)
{
s = GetFromCache(PackageHashType.Classic, filename);
if (s != null)
return true;
s = GetFromCache(PackageHashType.CRC32, filename);
s = GetFromCache(filename);
if (s != null)
return true;
}

View File

@@ -43,17 +43,6 @@ namespace OpenRA.FileSystem
catch { return null; }
}
public IEnumerable<uint> ClassicHashes()
{
foreach (var filename in Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly))
yield return PackageEntry.HashFilename(Path.GetFileName(filename), PackageHashType.Classic);
}
public IEnumerable<uint> CrcHashes()
{
yield break;
}
public IEnumerable<string> AllFileNames()
{
foreach (var filename in Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly))

View File

@@ -18,8 +18,6 @@ namespace OpenRA.FileSystem
{
Stream GetContent(string filename);
bool Exists(string filename);
IEnumerable<uint> ClassicHashes();
IEnumerable<uint> CrcHashes();
IEnumerable<string> AllFileNames();
int Priority { get; }
string Name { get; }

View File

@@ -15,80 +15,31 @@ namespace OpenRA.FileSystem
{
public class IdxEntry
{
public const string DefaultExtension = "wav";
public readonly uint Hash;
public readonly string Name;
public readonly string Extension;
public readonly string Filename;
public readonly uint Offset;
public readonly uint Length;
public readonly uint SampleRate;
public readonly uint Flags;
public readonly uint ChunkSize;
public IdxEntry(uint hash, uint offset, uint length, uint sampleRate, uint flags, uint chuckSize)
{
Hash = hash;
Offset = offset;
Length = length;
SampleRate = sampleRate;
Flags = flags;
ChunkSize = chuckSize;
}
public IdxEntry(Stream s)
{
var asciiname = s.ReadASCII(16);
var pos = asciiname.IndexOf('\0');
var name = s.ReadASCII(16);
var pos = name.IndexOf('\0');
if (pos != 0)
asciiname = asciiname.Substring(0, pos);
name = name.Substring(0, pos);
Name = asciiname;
Extension = DefaultExtension;
Filename = string.Concat(name, ".wav");
Offset = s.ReadUInt32();
Length = s.ReadUInt32();
SampleRate = s.ReadUInt32();
Flags = s.ReadUInt32();
ChunkSize = s.ReadUInt32();
Hash = HashFilename(string.Concat(Name, ".", Extension), PackageHashType.CRC32);
}
public void Write(BinaryWriter w)
{
w.Write(Name.PadRight(16, '\0'));
w.Write(Offset);
w.Write(Length);
w.Write(SampleRate);
w.Write(Flags);
w.Write(ChunkSize);
}
public override string ToString()
{
string filename;
if (names.TryGetValue(Hash, out filename))
return "{0} - offset 0x{1:x8} - length 0x{2:x8}".F(filename, Offset, Length);
else
return "0x{0:x8} - offset 0x{1:x8} - length 0x{2:x8}".F(Hash, Offset, Length);
}
public static uint HashFilename(string name, PackageHashType type)
{
return PackageEntry.HashFilename(name, type);
}
static Dictionary<uint, string> names = new Dictionary<uint, string>();
public static void AddStandardName(string s)
{
// RA1 and TD
var hash = HashFilename(s, PackageHashType.Classic);
names.Add(hash, s);
// TS
var crcHash = HashFilename(s, PackageHashType.CRC32);
names.Add(crcHash, s);
return "{0} - offset 0x{1:x8} - length 0x{2:x8}".F(Filename, Offset, Length);
}
}
}

View File

@@ -451,11 +451,6 @@ namespace OpenRA.FileSystem
GetContentById(index, destfile);
}
public IEnumerable<uint> ClassicHashes()
{
return fileLookup.Keys.Select(k => PackageEntry.HashFilename(k, PackageHashType.Classic));
}
public Stream GetContentById(uint index)
{
var fileDes = fileDescriptors[index];
@@ -507,11 +502,6 @@ namespace OpenRA.FileSystem
return GetContentById(fileLookup[fileName]);
}
public IEnumerable<uint> CrcHashes()
{
yield break;
}
public IEnumerable<string> AllFileNames()
{
return fileLookup.Keys;

View File

@@ -17,8 +17,19 @@ namespace OpenRA.FileSystem
{
public sealed class InstallShieldPackage : IReadOnlyPackage
{
readonly Dictionary<uint, PackageEntry> index = new Dictionary<uint, PackageEntry>();
readonly List<string> filenames;
struct Entry
{
public readonly uint Offset;
public readonly uint Length;
public Entry(uint offset, uint length)
{
Offset = offset;
Length = length;
}
}
readonly Dictionary<string, Entry> index = new Dictionary<string, Entry>();
readonly Stream s;
readonly long dataStart = 255;
readonly int priority;
@@ -29,40 +40,45 @@ namespace OpenRA.FileSystem
this.filename = filename;
this.priority = priority;
filenames = new List<string>();
s = context.Open(filename);
try
{
// Parse package header
var reader = new BinaryReader(s);
var signature = reader.ReadUInt32();
var signature = s.ReadUInt32();
if (signature != 0x8C655D13)
throw new InvalidDataException("Not an Installshield package");
reader.ReadBytes(8);
/*var FileCount = */reader.ReadUInt16();
reader.ReadBytes(4);
/*var ArchiveSize = */reader.ReadUInt32();
reader.ReadBytes(19);
var tocAddress = reader.ReadInt32();
reader.ReadBytes(4);
var dirCount = reader.ReadUInt16();
s.Position += 8;
/*var FileCount = */s.ReadUInt16();
s.Position += 4;
/*var ArchiveSize = */s.ReadUInt32();
s.Position += 19;
var tocAddress = s.ReadInt32();
s.Position += 4;
var dirCount = s.ReadUInt16();
// Parse the directory list
s.Seek(tocAddress, SeekOrigin.Begin);
var tocReader = new BinaryReader(s);
var fileCountInDirs = new List<uint>();
s.Position = tocAddress;
// Parse directories
var directories = new Dictionary<string, uint>();
for (var i = 0; i < dirCount; i++)
fileCountInDirs.Add(ParseDirectory(tocReader));
{
// Parse directory header
var fileCount = s.ReadUInt16();
var chunkSize = s.ReadUInt16();
var nameLength = s.ReadUInt16();
var dirName = s.ReadASCII(nameLength);
// Skip to the end of the chunk
s.ReadBytes(chunkSize - nameLength - 6);
directories.Add(dirName, fileCount);
}
// Parse files
foreach (var fileCount in fileCountInDirs)
for (var i = 0; i < fileCount; i++)
ParseFile(reader);
foreach (var dir in directories)
for (var i = 0; i < dir.Value; i++)
ParseFile(s, dir.Key);
}
catch
{
@@ -71,44 +87,29 @@ namespace OpenRA.FileSystem
}
}
static uint ParseDirectory(BinaryReader reader)
{
// Parse directory header
var fileCount = reader.ReadUInt16();
var chunkSize = reader.ReadUInt16();
var nameLength = reader.ReadUInt16();
reader.ReadChars(nameLength); // var DirName = new String(reader.ReadChars(NameLength));
// Skip to the end of the chunk
reader.ReadBytes(chunkSize - nameLength - 6);
return fileCount;
}
uint accumulatedData = 0;
void ParseFile(BinaryReader reader)
void ParseFile(Stream s, string dirName)
{
reader.ReadBytes(7);
var compressedSize = reader.ReadUInt32();
reader.ReadBytes(12);
var chunkSize = reader.ReadUInt16();
reader.ReadBytes(4);
var nameLength = reader.ReadByte();
var fileName = new string(reader.ReadChars(nameLength));
s.Position += 7;
var compressedSize = s.ReadUInt32();
s.Position += 12;
var chunkSize = s.ReadUInt16();
s.Position += 4;
var nameLength = s.ReadByte();
var fileName = dirName + "\\" + s.ReadASCII(nameLength);
var hash = PackageEntry.HashFilename(fileName, PackageHashType.Classic);
if (!index.ContainsKey(hash))
index.Add(hash, new PackageEntry(hash, accumulatedData, compressedSize));
filenames.Add(fileName);
// Use index syntax to overwrite any duplicate entries with the last value
index[fileName] = new Entry(accumulatedData, compressedSize);
accumulatedData += compressedSize;
// Skip to the end of the chunk
reader.ReadBytes(chunkSize - nameLength - 30);
s.Position += chunkSize - nameLength - 30;
}
public Stream GetContent(uint hash)
public Stream GetContent(string filename)
{
PackageEntry e;
if (!index.TryGetValue(hash, out e))
Entry e;
if (!index.TryGetValue(filename, out e))
return null;
s.Seek(dataStart + e.Offset, SeekOrigin.Begin);
@@ -117,39 +118,19 @@ namespace OpenRA.FileSystem
return new MemoryStream(Blast.Decompress(data));
}
public Stream GetContent(string filename)
{
return GetContent(PackageEntry.HashFilename(filename, PackageHashType.Classic));
}
public IEnumerable<uint> ClassicHashes()
public IEnumerable<string> AllFileNames()
{
return index.Keys;
}
public IEnumerable<uint> CrcHashes()
{
yield break;
}
public IEnumerable<string> AllFileNames()
{
return filenames;
}
public bool Exists(string filename)
{
return index.ContainsKey(PackageEntry.HashFilename(filename, PackageHashType.Classic));
return index.ContainsKey(filename);
}
public int Priority { get { return 2000 + priority; } }
public string Name { get { return filename; } }
public void Write(Dictionary<string, byte[]> contents)
{
throw new NotImplementedException("Cannot save InstallShieldPackages.");
}
public void Dispose()
{
s.Dispose();

View File

@@ -170,23 +170,6 @@ namespace OpenRA.FileSystem
return hash.HasValue ? GetContent(hash.Value) : null;
}
static readonly uint[] Nothing = { };
public IEnumerable<uint> ClassicHashes()
{
if (type == PackageHashType.Classic)
return index.Keys;
return Nothing;
}
public IEnumerable<uint> CrcHashes()
{
if (type == PackageHashType.CRC32)
return index.Keys;
return Nothing;
}
public IEnumerable<string> AllFileNames()
{
var lookup = new Dictionary<uint, string>();

View File

@@ -70,17 +70,6 @@ namespace OpenRA.FileSystem
return new MemoryStream(data);
}
public IEnumerable<uint> ClassicHashes()
{
foreach (var filename in index.Keys)
yield return PackageEntry.HashFilename(filename, PackageHashType.Classic);
}
public IEnumerable<uint> CrcHashes()
{
yield break;
}
public IEnumerable<string> AllFileNames()
{
foreach (var filename in index.Keys)

View File

@@ -71,17 +71,6 @@ namespace OpenRA.FileSystem
}
}
public IEnumerable<uint> ClassicHashes()
{
foreach (ZipEntry entry in pkg)
yield return PackageEntry.HashFilename(entry.Name, PackageHashType.Classic);
}
public IEnumerable<uint> CrcHashes()
{
yield break;
}
public IEnumerable<string> AllFileNames()
{
foreach (ZipEntry entry in pkg)

View File

@@ -37,9 +37,26 @@ namespace OpenRA.Mods.Common
return volumes.FirstOrDefault(isValidDisk);
}
static string GetFileName(string path, ContentInstaller.FilenameCase caseModifier)
{
// Gets the file path, splitting on both / and \
var index = path.LastIndexOfAny(new[] { '\\', '/' });
var output = path.Substring(index + 1);
switch (caseModifier)
{
case ContentInstaller.FilenameCase.ForceLower:
return output.ToLowerInvariant();
case ContentInstaller.FilenameCase.ForceUpper:
return output.ToUpperInvariant();
default:
return output;
}
}
// TODO: The package should be mounted into its own context to avoid name collisions with installed files
public static bool ExtractFromPackage(string srcPath, string package, string annotation, Dictionary<string, string[]> filesByDirectory,
string destPath, bool overwrite, Action<string> onProgress, Action<string> onError)
string destPath, bool overwrite, ContentInstaller.FilenameCase caseModifier, Action<string> onProgress, Action<string> onError)
{
Directory.CreateDirectory(destPath);
@@ -55,7 +72,7 @@ namespace OpenRA.Mods.Common
foreach (var file in directory.Value)
{
var containingDir = Path.Combine(destPath, targetDir);
var dest = Path.Combine(containingDir, file.ToLowerInvariant());
var dest = Path.Combine(containingDir, GetFileName(file, caseModifier));
if (File.Exists(dest))
{
if (overwrite)
@@ -83,7 +100,7 @@ namespace OpenRA.Mods.Common
}
public static bool CopyFiles(string srcPath, Dictionary<string, string[]> files, string destPath,
bool overwrite, Action<string> onProgress, Action<string> onError)
bool overwrite, ContentInstaller.FilenameCase caseModifier, Action<string> onProgress, Action<string> onError)
{
Directory.CreateDirectory(destPath);
@@ -100,9 +117,9 @@ namespace OpenRA.Mods.Common
return false;
}
var destFile = Path.GetFileName(file);
var destFile = GetFileName(file, caseModifier);
var containingDir = Path.Combine(destPath, targetDir);
var dest = Path.Combine(containingDir, destFile.ToLowerInvariant());
var dest = Path.Combine(containingDir, destFile);
if (File.Exists(dest) && !overwrite)
{
Log.Write("debug", "Skipping {0}".F(dest));

View File

@@ -132,7 +132,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var destFile = Platform.ResolvePath("^", "Content", modId, filename.ToLowerInvariant());
cabExtractor.ExtractFile(uint.Parse(archive[0]), destFile);
var annotation = archive.Length > 1 ? archive[1] : null;
InstallUtils.ExtractFromPackage(source, destFile, annotation, extractFiles, destDir, overwrite, onProgress, onError);
InstallUtils.ExtractFromPackage(source, destFile, annotation, extractFiles, destDir, overwrite, installData.OutputFilenameCase, onProgress, onError);
progressBar.Percentage += installPercent;
}
}
@@ -183,7 +183,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
try
{
if (!InstallUtils.CopyFiles(source, copyFiles, dest, overwrite, onProgress, onError))
if (!InstallUtils.CopyFiles(source, copyFiles, dest, overwrite, installData.OutputFilenameCase, onProgress, onError))
{
onError("Copying files from CD failed.");
return;
@@ -191,7 +191,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (!string.IsNullOrEmpty(extractPackage))
{
if (!InstallUtils.ExtractFromPackage(source, extractPackage, annotation, extractFiles, dest, overwrite, onProgress, onError))
if (!InstallUtils.ExtractFromPackage(source, extractPackage, annotation, extractFiles, dest,
overwrite, installData.OutputFilenameCase, onProgress, onError))
{
onError("Extracting files from CD failed.");
return;

View File

@@ -146,13 +146,11 @@ LoadScreen: CncLoadScreen
ContentInstaller:
TestFiles: ^Content/cnc/conquer.mix, ^Content/cnc/desert.mix, ^Content/cnc/sounds.mix, ^Content/cnc/speech.mix, ^Content/cnc/temperat.mix, ^Content/cnc/tempicnh.mix, ^Content/cnc/winter.mix
FilesToCopy: CONQUER.MIX, DESERT.MIX, SCORES.MIX, SOUNDS.MIX, TEMPERAT.MIX, WINTER.MIX
FilesToExtract: speech.mix, tempicnh.mix, transit.mix
PackageMirrorList: http://www.openra.net/packages/cnc-mirrors.txt
DiskTestFiles: conquer.mix, desert.mix, install/setup.z
PackageToExtractFromCD: install/setup.z
ExtractFilesFromCD:
.: speech.mix, tempicnh.mix, transit.mix
.: C&C95\SPEECH.MIX, C&C95\TEMPICNH.MIX, C&C95\TRANSIT.MIX
CopyFilesFromCD:
.: conquer.mix, desert.mix, general.mix, scores.mix, sounds.mix, temperat.mix, winter.mix
ShippedSoundtracks: 4

View File

@@ -19,7 +19,7 @@ Visibility: MissionSelector
Type: Campaign
Videos:
Briefing: a_br01_e.vqa
Briefing: A_BR01_E.VQA
Options:
Crates: False

View File

@@ -19,7 +19,7 @@ Visibility: MissionSelector
Type: Campaign
Videos:
Briefing: a_br01_e.vqa
Briefing: A_BR01_E.VQA
Options:
Crates: False

View File

@@ -19,7 +19,7 @@ Visibility: MissionSelector
Type: Campaign
Videos:
Briefing: a_br02_e.vqa
Briefing: A_BR02_E.VQA
Options:
Crates: False

View File

@@ -19,7 +19,7 @@ Visibility: MissionSelector
Type: Campaign
Videos:
Briefing: a_br02_e.vqa
Briefing: A_BR02_E.VQA
Options:
Crates: False

View File

@@ -19,7 +19,7 @@ Visibility: MissionSelector
Type: Campaign
Videos:
Briefing: a_br03_e.vqa
Briefing: A_BR03_E.VQA
Options:
Crates: False

File diff suppressed because one or more lines are too long