Overhaul InstallShieldPackage.

- Remove hashing
- Use full file paths
- Replace BinaryReader with stream extensions.
This commit is contained in:
Paul Chote
2016-01-16 20:28:44 +00:00
parent 7ed24ce6de
commit 314aba0861
3 changed files with 57 additions and 63 deletions

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,19 +118,14 @@ namespace OpenRA.FileSystem
return new MemoryStream(Blast.Decompress(data));
}
public Stream GetContent(string filename)
{
return GetContent(PackageEntry.HashFilename(filename, PackageHashType.Classic));
}
public IEnumerable<string> AllFileNames()
{
return filenames;
return index.Keys;
}
public bool Exists(string filename)
{
return index.ContainsKey(PackageEntry.HashFilename(filename, PackageHashType.Classic));
return index.ContainsKey(filename);
}
public int Priority { get { return 2000 + priority; } }

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

File diff suppressed because one or more lines are too long