Support for InstallShield CAB version <= 5.
This commit is contained in:
@@ -42,10 +42,14 @@ namespace OpenRA.Mods.Common.FileFormats
|
|||||||
public readonly uint FirstFile;
|
public readonly uint FirstFile;
|
||||||
public readonly uint LastFile;
|
public readonly uint LastFile;
|
||||||
|
|
||||||
public FileGroup(Stream stream, long offset)
|
public FileGroup(Stream stream, long offset, uint version)
|
||||||
{
|
{
|
||||||
var nameOffset = stream.ReadUInt32();
|
var nameOffset = stream.ReadUInt32();
|
||||||
stream.Position += 18;
|
stream.Position += 18;
|
||||||
|
|
||||||
|
if (version <= 5)
|
||||||
|
stream.Position += 54;
|
||||||
|
|
||||||
FirstFile = stream.ReadUInt32();
|
FirstFile = stream.ReadUInt32();
|
||||||
LastFile = stream.ReadUInt32();
|
LastFile = stream.ReadUInt32();
|
||||||
|
|
||||||
@@ -105,7 +109,7 @@ namespace OpenRA.Mods.Common.FileFormats
|
|||||||
|
|
||||||
public readonly byte[] MD5;
|
public readonly byte[] MD5;
|
||||||
public readonly uint NameOffset;
|
public readonly uint NameOffset;
|
||||||
public readonly ushort DirectoryIndex;
|
public readonly uint DirectoryIndex;
|
||||||
public readonly uint LinkToPrevious;
|
public readonly uint LinkToPrevious;
|
||||||
|
|
||||||
public readonly uint LinkToNext;
|
public readonly uint LinkToNext;
|
||||||
@@ -113,33 +117,63 @@ namespace OpenRA.Mods.Common.FileFormats
|
|||||||
public readonly ushort Volume;
|
public readonly ushort Volume;
|
||||||
public readonly string Filename;
|
public readonly string Filename;
|
||||||
|
|
||||||
public FileDescriptor(Stream stream, uint index, long tableOffset)
|
public FileDescriptor(Stream stream, uint index, long tableOffset, uint version)
|
||||||
{
|
{
|
||||||
Index = index;
|
Index = index;
|
||||||
Flags = (CABFlags)stream.ReadUInt16();
|
|
||||||
ExpandedSize = stream.ReadUInt32();
|
|
||||||
stream.Position += 4;
|
|
||||||
CompressedSize = stream.ReadUInt32();
|
|
||||||
|
|
||||||
stream.Position += 4;
|
if (version <= 5)
|
||||||
DataOffset = stream.ReadUInt32();
|
{
|
||||||
stream.Position += 4;
|
NameOffset = stream.ReadUInt32();
|
||||||
MD5 = stream.ReadBytes(16);
|
DirectoryIndex = stream.ReadUInt32();
|
||||||
|
Flags = (CABFlags)stream.ReadUInt16();
|
||||||
|
ExpandedSize = stream.ReadUInt32();
|
||||||
|
CompressedSize = stream.ReadUInt32();
|
||||||
|
stream.Position += 20;
|
||||||
|
DataOffset = stream.ReadUInt32();
|
||||||
|
|
||||||
stream.Position += 16;
|
MD5 = new byte[16];
|
||||||
NameOffset = stream.ReadUInt32();
|
LinkToPrevious = 0;
|
||||||
DirectoryIndex = stream.ReadUInt16();
|
LinkToNext = 0;
|
||||||
stream.Position += 12;
|
LinkFlags = 0;
|
||||||
LinkToPrevious = stream.ReadUInt32();
|
Volume = 0;
|
||||||
LinkToNext = stream.ReadUInt32();
|
|
||||||
|
|
||||||
LinkFlags = (LinkFlags)stream.ReadUInt8();
|
if ((Flags & CABFlags.FileInvalid) == 0)
|
||||||
Volume = stream.ReadUInt16();
|
{
|
||||||
|
var pos = stream.Position;
|
||||||
|
stream.Position = tableOffset + NameOffset;
|
||||||
|
Filename = stream.ReadASCIIZ();
|
||||||
|
stream.Position = pos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Filename = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Flags = (CABFlags)stream.ReadUInt16();
|
||||||
|
ExpandedSize = stream.ReadUInt32();
|
||||||
|
stream.Position += 4;
|
||||||
|
CompressedSize = stream.ReadUInt32();
|
||||||
|
|
||||||
var pos = stream.Position;
|
stream.Position += 4;
|
||||||
stream.Position = tableOffset + NameOffset;
|
DataOffset = stream.ReadUInt32();
|
||||||
Filename = stream.ReadASCIIZ();
|
stream.Position += 4;
|
||||||
stream.Position = pos;
|
MD5 = stream.ReadBytes(16);
|
||||||
|
|
||||||
|
stream.Position += 16;
|
||||||
|
NameOffset = stream.ReadUInt32();
|
||||||
|
DirectoryIndex = stream.ReadUInt16();
|
||||||
|
stream.Position += 12;
|
||||||
|
LinkToPrevious = stream.ReadUInt32();
|
||||||
|
LinkToNext = stream.ReadUInt32();
|
||||||
|
|
||||||
|
LinkFlags = (LinkFlags)stream.ReadUInt8();
|
||||||
|
Volume = stream.ReadUInt16();
|
||||||
|
|
||||||
|
var pos = stream.Position;
|
||||||
|
stream.Position = tableOffset + NameOffset;
|
||||||
|
Filename = stream.ReadASCIIZ();
|
||||||
|
stream.Position = pos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,6 +374,7 @@ namespace OpenRA.Mods.Common.FileFormats
|
|||||||
|
|
||||||
readonly Dictionary<string, FileDescriptor> index = new Dictionary<string, FileDescriptor>();
|
readonly Dictionary<string, FileDescriptor> index = new Dictionary<string, FileDescriptor>();
|
||||||
readonly Dictionary<int, Stream> volumes;
|
readonly Dictionary<int, Stream> volumes;
|
||||||
|
readonly uint version;
|
||||||
|
|
||||||
public InstallShieldCABCompression(Stream header, Dictionary<int, Stream> volumes)
|
public InstallShieldCABCompression(Stream header, Dictionary<int, Stream> volumes)
|
||||||
{
|
{
|
||||||
@@ -348,7 +383,20 @@ namespace OpenRA.Mods.Common.FileFormats
|
|||||||
if (header.ReadUInt32() != 0x28635349)
|
if (header.ReadUInt32() != 0x28635349)
|
||||||
throw new InvalidDataException("Not an Installshield CAB package");
|
throw new InvalidDataException("Not an Installshield CAB package");
|
||||||
|
|
||||||
header.Position += 8;
|
var versionTmp = header.ReadUInt32();
|
||||||
|
|
||||||
|
// Logic taken from UnShield
|
||||||
|
// https://github.com/twogood/unshield/blob/1.5.1/lib/libunshield.c#L277-L288
|
||||||
|
if (versionTmp >> 24 == 1)
|
||||||
|
version = (versionTmp >> 12) & 0xf;
|
||||||
|
else if (versionTmp >> 24 == 2 || versionTmp >> 24 == 4)
|
||||||
|
{
|
||||||
|
version = versionTmp & 0xffff;
|
||||||
|
if (version != 0)
|
||||||
|
version /= 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.Position += 4;
|
||||||
var cabDescriptorOffset = header.ReadUInt32();
|
var cabDescriptorOffset = header.ReadUInt32();
|
||||||
header.Position = cabDescriptorOffset + 12;
|
header.Position = cabDescriptorOffset + 12;
|
||||||
var cabDescriptor = new CabDescriptor(header);
|
var cabDescriptor = new CabDescriptor(header);
|
||||||
@@ -374,7 +422,7 @@ namespace OpenRA.Mods.Common.FileFormats
|
|||||||
nextOffset = header.ReadUInt32();
|
nextOffset = header.ReadUInt32();
|
||||||
header.Position = cabDescriptorOffset + descriptorOffset;
|
header.Position = cabDescriptorOffset + descriptorOffset;
|
||||||
|
|
||||||
fileGroups.Add(new FileGroup(header, cabDescriptorOffset));
|
fileGroups.Add(new FileGroup(header, cabDescriptorOffset, version));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,8 +431,15 @@ namespace OpenRA.Mods.Common.FileFormats
|
|||||||
{
|
{
|
||||||
for (var i = fileGroup.FirstFile; i <= fileGroup.LastFile; i++)
|
for (var i = fileGroup.FirstFile; i <= fileGroup.LastFile; i++)
|
||||||
{
|
{
|
||||||
header.Position = cabDescriptorOffset + cabDescriptor.FileTableOffset + cabDescriptor.FileTableOffset2 + i * 0x57;
|
if (version <= 5)
|
||||||
var file = new FileDescriptor(header, i, cabDescriptorOffset + cabDescriptor.FileTableOffset);
|
{
|
||||||
|
header.Position = cabDescriptorOffset + cabDescriptor.FileTableOffset + cabDescriptor.FileTableOffset2 + i * 4;
|
||||||
|
header.Position = cabDescriptorOffset + cabDescriptor.FileTableOffset + header.ReadUInt32();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
header.Position = cabDescriptorOffset + cabDescriptor.FileTableOffset + cabDescriptor.FileTableOffset2 + i * 0x57;
|
||||||
|
|
||||||
|
var file = new FileDescriptor(header, i, cabDescriptorOffset + cabDescriptor.FileTableOffset, version);
|
||||||
var path = $"{fileGroup.Name}\\{directories[file.DirectoryIndex].Name}\\{file.Filename}";
|
var path = $"{fileGroup.Name}\\{directories[file.DirectoryIndex].Name}\\{file.Filename}";
|
||||||
index[path] = file;
|
index[path] = file;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user