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 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; } }

View File

@@ -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