Overhaul InstallShieldPackage.
- Remove hashing - Use full file paths - Replace BinaryReader with stream extensions.
This commit is contained in:
@@ -17,8 +17,19 @@ namespace OpenRA.FileSystem
|
|||||||
{
|
{
|
||||||
public sealed class InstallShieldPackage : IReadOnlyPackage
|
public sealed class InstallShieldPackage : IReadOnlyPackage
|
||||||
{
|
{
|
||||||
readonly Dictionary<uint, PackageEntry> index = new Dictionary<uint, PackageEntry>();
|
struct Entry
|
||||||
readonly List<string> filenames;
|
{
|
||||||
|
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 Stream s;
|
||||||
readonly long dataStart = 255;
|
readonly long dataStart = 255;
|
||||||
readonly int priority;
|
readonly int priority;
|
||||||
@@ -29,40 +40,45 @@ namespace OpenRA.FileSystem
|
|||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
|
|
||||||
filenames = new List<string>();
|
|
||||||
|
|
||||||
s = context.Open(filename);
|
s = context.Open(filename);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Parse package header
|
// Parse package header
|
||||||
var reader = new BinaryReader(s);
|
var signature = s.ReadUInt32();
|
||||||
var signature = reader.ReadUInt32();
|
|
||||||
if (signature != 0x8C655D13)
|
if (signature != 0x8C655D13)
|
||||||
throw new InvalidDataException("Not an Installshield package");
|
throw new InvalidDataException("Not an Installshield package");
|
||||||
|
|
||||||
reader.ReadBytes(8);
|
s.Position += 8;
|
||||||
/*var FileCount = */reader.ReadUInt16();
|
/*var FileCount = */s.ReadUInt16();
|
||||||
reader.ReadBytes(4);
|
s.Position += 4;
|
||||||
/*var ArchiveSize = */reader.ReadUInt32();
|
/*var ArchiveSize = */s.ReadUInt32();
|
||||||
reader.ReadBytes(19);
|
s.Position += 19;
|
||||||
var tocAddress = reader.ReadInt32();
|
var tocAddress = s.ReadInt32();
|
||||||
reader.ReadBytes(4);
|
s.Position += 4;
|
||||||
var dirCount = reader.ReadUInt16();
|
var dirCount = s.ReadUInt16();
|
||||||
|
|
||||||
// Parse the directory list
|
// Parse the directory list
|
||||||
s.Seek(tocAddress, SeekOrigin.Begin);
|
s.Position = tocAddress;
|
||||||
var tocReader = new BinaryReader(s);
|
|
||||||
|
|
||||||
var fileCountInDirs = new List<uint>();
|
|
||||||
|
|
||||||
// Parse directories
|
// Parse directories
|
||||||
|
var directories = new Dictionary<string, uint>();
|
||||||
for (var i = 0; i < dirCount; i++)
|
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
|
// Parse files
|
||||||
foreach (var fileCount in fileCountInDirs)
|
foreach (var dir in directories)
|
||||||
for (var i = 0; i < fileCount; i++)
|
for (var i = 0; i < dir.Value; i++)
|
||||||
ParseFile(reader);
|
ParseFile(s, dir.Key);
|
||||||
}
|
}
|
||||||
catch
|
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;
|
uint accumulatedData = 0;
|
||||||
void ParseFile(BinaryReader reader)
|
void ParseFile(Stream s, string dirName)
|
||||||
{
|
{
|
||||||
reader.ReadBytes(7);
|
s.Position += 7;
|
||||||
var compressedSize = reader.ReadUInt32();
|
var compressedSize = s.ReadUInt32();
|
||||||
reader.ReadBytes(12);
|
s.Position += 12;
|
||||||
var chunkSize = reader.ReadUInt16();
|
var chunkSize = s.ReadUInt16();
|
||||||
reader.ReadBytes(4);
|
s.Position += 4;
|
||||||
var nameLength = reader.ReadByte();
|
var nameLength = s.ReadByte();
|
||||||
var fileName = new string(reader.ReadChars(nameLength));
|
var fileName = dirName + "\\" + s.ReadASCII(nameLength);
|
||||||
|
|
||||||
var hash = PackageEntry.HashFilename(fileName, PackageHashType.Classic);
|
// Use index syntax to overwrite any duplicate entries with the last value
|
||||||
if (!index.ContainsKey(hash))
|
index[fileName] = new Entry(accumulatedData, compressedSize);
|
||||||
index.Add(hash, new PackageEntry(hash, accumulatedData, compressedSize));
|
|
||||||
filenames.Add(fileName);
|
|
||||||
accumulatedData += compressedSize;
|
accumulatedData += compressedSize;
|
||||||
|
|
||||||
// Skip to the end of the chunk
|
// 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;
|
Entry e;
|
||||||
if (!index.TryGetValue(hash, out e))
|
if (!index.TryGetValue(filename, out e))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
s.Seek(dataStart + e.Offset, SeekOrigin.Begin);
|
s.Seek(dataStart + e.Offset, SeekOrigin.Begin);
|
||||||
@@ -117,19 +118,14 @@ namespace OpenRA.FileSystem
|
|||||||
return new MemoryStream(Blast.Decompress(data));
|
return new MemoryStream(Blast.Decompress(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream GetContent(string filename)
|
|
||||||
{
|
|
||||||
return GetContent(PackageEntry.HashFilename(filename, PackageHashType.Classic));
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> AllFileNames()
|
public IEnumerable<string> AllFileNames()
|
||||||
{
|
{
|
||||||
return filenames;
|
return index.Keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Exists(string filename)
|
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 int Priority { get { return 2000 + priority; } }
|
||||||
|
|||||||
@@ -146,13 +146,11 @@ LoadScreen: CncLoadScreen
|
|||||||
|
|
||||||
ContentInstaller:
|
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
|
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
|
PackageMirrorList: http://www.openra.net/packages/cnc-mirrors.txt
|
||||||
DiskTestFiles: conquer.mix, desert.mix, install/setup.z
|
DiskTestFiles: conquer.mix, desert.mix, install/setup.z
|
||||||
PackageToExtractFromCD: install/setup.z
|
PackageToExtractFromCD: install/setup.z
|
||||||
ExtractFilesFromCD:
|
ExtractFilesFromCD:
|
||||||
.: speech.mix, tempicnh.mix, transit.mix
|
.: C&C95\SPEECH.MIX, C&C95\TEMPICNH.MIX, C&C95\TRANSIT.MIX
|
||||||
CopyFilesFromCD:
|
CopyFilesFromCD:
|
||||||
.: conquer.mix, desert.mix, general.mix, scores.mix, sounds.mix, temperat.mix, winter.mix
|
.: conquer.mix, desert.mix, general.mix, scores.mix, sounds.mix, temperat.mix, winter.mix
|
||||||
ShippedSoundtracks: 4
|
ShippedSoundtracks: 4
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user