improvements to InstallShield CAB and header (HDR, PKG) DataFormats

This commit is contained in:
Michael Becker 2019-12-06 03:02:37 -05:00
parent 2a928d480c
commit c571b33b3d
No known key found for this signature in database
GPG Key ID: 389DFF5D73781A12
5 changed files with 302 additions and 38 deletions

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<UniversalEditor Version="4.0">
<Associations>
<Association>
<Filters>
<Filter Title="InstallShield archive index">
<FileNameFilters>
<FileNameFilter>*.pkg</FileNameFilter>
</FileNameFilters>
<MagicByteSequences>
<MagicByteSequence>
<MagicByte Type="HexString">4AA3</MagicByte>
</MagicByteSequence>
</MagicByteSequences>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.FileSystem.FileSystemObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.DataFormats.FileSystem.InstallShield.PKG.PKGDataFormat" />
</DataFormats>
</Association>
</Associations>
</UniversalEditor>

View File

@ -658,6 +658,7 @@
<Content Include="Extensions\GameDeveloper\Extensions\Sony\Database\PSFDataFormat.uexml" />
<Content Include="Editors\Multimedia3D\Model\Shaders\Default\default_vtx.glsl" />
<Content Include="Editors\Multimedia3D\Model\Shaders\Default\default_frg.glsl" />
<Content Include="Extensions\FileSystem\Associations\InstallShield\PKG.uexml" />
</ItemGroup>
<ItemGroup>
<Content Include="Configuration\Application.upl" />

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UniversalEditor.Accessors;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.FileSystem;
@ -37,13 +38,25 @@ namespace UniversalEditor.DataFormats.FileSystem.InstallShield.Cabinet
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
if (fsom == null) return;
Reader br = base.Accessor.Reader;
Reader br = Accessor.Reader;
br.Accessor.Seek(0, SeekOrigin.Begin);
br.Endianness = Endianness.LittleEndian;
string ISc_ = br.ReadFixedLengthString(4);
if (ISc_ != "ISc(") throw new InvalidDataFormatException();
string hdrfilename = System.IO.Path.ChangeExtension(Accessor.GetFileName(), ".hdr");
if (System.IO.File.Exists(hdrfilename))
{
FileAccessor fa = new FileAccessor(hdrfilename, false, false, true);
HDRDataFormat hdr = new HDRDataFormat();
hdr.IgnoreCabinet = true; // set this because WE are the cabinet
Document.Load(fsom, hdr, fa);
}
uint version = br.ReadUInt32();
int majorVersion = 0;
if (version >> 24 == 1)
@ -79,9 +92,10 @@ namespace UniversalEditor.DataFormats.FileSystem.InstallShield.Cabinet
uint unknown6 = br.ReadUInt32();
uint fileCount = br.ReadUInt32();
uint fileTableOffset2 = br.ReadUInt32();
return;
if (br.Accessor.Position != 0x30) throw new InvalidDataFormatException();
if (fileTableSize != fileTableSize2) throw new InvalidDataFormatException("File table sizes do not match");
// if (br.Accessor.Position != 0x30) throw new InvalidDataFormatException();
// if (fileTableSize != fileTableSize2) throw new InvalidDataFormatException("File table sizes do not match");
uint unknown7 = br.ReadUInt32();
uint unknown8 = br.ReadUInt32();
@ -98,9 +112,6 @@ namespace UniversalEditor.DataFormats.FileSystem.InstallShield.Cabinet
{
componentOffsets[i] = br.ReadUInt32();
}
}
protected override void SaveInternal(ObjectModel objectModel)

View File

@ -2,29 +2,236 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UniversalEditor.Compression;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.FileSystem;
namespace UniversalEditor.DataFormats.FileSystem.InstallShield.Cabinet
{
public class HDRDataFormat : DataFormat
{
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
{
if (_dfr == null)
{
_dfr = base.MakeReferenceInternal();
_dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All);
}
return _dfr;
}
public class HDRDataFormat : DataFormat
{
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
{
if (_dfr == null)
{
_dfr = base.MakeReferenceInternal();
_dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All);
}
return _dfr;
}
protected override void LoadInternal(ref ObjectModel objectModel)
{
}
private System.IO.FileStream cabfile = null;
/// <summary>
/// Gets or sets a value indicating whether this
/// <see cref="T:UniversalEditor.DataFormats.FileSystem.InstallShield.Cabinet.HDRDataFormat"/> should skip
/// attempting to load the respective cabinet. This should be set to FALSE when using this DataFormat interactively
/// so that the associated <see cref="FileSystemObjectModel" /> can retrieve data appropriately, but it should be
/// set to TRUE when using this DataFormat in conjunction with the <see cref="CABDataFormat" />, since that handles
/// data retrieval itself.
/// </summary>
/// <value><c>true</c> if the associated cabinet file should be ignored; otherwise, <c>false</c>.</value>
public bool IgnoreCabinet { get; set; } = false;
protected override void SaveInternal(ObjectModel objectModel)
{
}
}
protected override void LoadInternal(ref ObjectModel objectModel)
{
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
if (fsom == null)
throw new ObjectModelNotSupportedException();
Reader reader = Accessor.Reader;
// ZLibX compression (see aluigi's code from quickbms)
if (!IgnoreCabinet)
{
string cabfilename = System.IO.Path.ChangeExtension(Accessor.GetFileName(), ".cab");
if (System.IO.File.Exists(cabfilename))
{
cabfile = System.IO.File.Open(cabfilename, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
}
}
string signature = reader.ReadFixedLengthString(4);
if (signature != "ISc(")
throw new InvalidDataFormatException("invalid CAB or HDR file - does not begin with 'ISc('");
uint unknown1 = reader.ReadUInt32();
if (unknown1 != 16798209)
{
Console.WriteLine("ue: ISc: warning: magic value does not equal 16798209; this has not been tested");
}
uint unknown2 = reader.ReadUInt32();
uint stringDirectoryOffset = reader.ReadUInt32();
uint stringDirectoryLength = reader.ReadUInt32();
if (stringDirectoryLength == 0)
{
// proooooobably not a HDR, maybe a CAB?
throw new InvalidDataFormatException();
}
uint totalFileLength = reader.ReadUInt32();
// rest is padding to offset 512
// STRINGS DIRECTORY
reader.Seek(stringDirectoryOffset, SeekOrigin.Begin);
uint enStrTblOffset = reader.ReadUInt32();
uint unknownB1 = reader.ReadUInt32();
uint unknownB2 = reader.ReadUInt32();
uint strTblLength = reader.ReadUInt32();
uint unknownB3 = reader.ReadUInt32();
uint unknownB4 = reader.ReadUInt32(); // 4 - Unknown(337)
uint unknownB4_2 = reader.ReadUInt32(); // 4 - Unknown(337)
uint folderCount = reader.ReadUInt32();
uint unknownB6 = reader.ReadUInt32();
uint unknownB7 = reader.ReadUInt32();
uint fileCount = reader.ReadUInt32();
uint unknownB9 = reader.ReadUInt32();
uint unknownB10 = reader.ReadUInt32();
uint unknownB11 = reader.ReadUInt32();
// X - Unknown Stuff
reader.Seek(stringDirectoryOffset + strTblLength, SeekOrigin.Begin);
string[] folderNames = new string[folderCount];
for (uint i = 0; i < folderCount; i++)
{
uint folderNameOffset = reader.ReadUInt32();
reader.Accessor.SavePosition();
reader.Seek(stringDirectoryOffset + strTblLength + folderNameOffset, SeekOrigin.Begin);
string folderName = ReadName(reader, unknown1);
reader.Accessor.LoadPosition();
folderNames[i] = folderName;
}
ushort uver = reader.ReadUInt16();
reader.Seek(-2, SeekOrigin.Current);
if (uver <= 0x10)
{
long CHUNK_SIZE = 0x8000;
for (uint i = 0; i < fileCount; i++)
{
short type = reader.ReadInt16();
ulong decompressedLength = reader.ReadUInt64();
ulong compressedLength = reader.ReadUInt64();
ulong offset = reader.ReadUInt64();
string hash = reader.ReadFixedLengthString(16);
ushort dummy1 = reader.ReadUInt16(); // 0 or 1
ushort dummy2 = reader.ReadUInt16(); // 0 or 0xa
ushort dummy3 = reader.ReadUInt16(); // 0 or 0xee
ushort dummy4 = reader.ReadUInt16(); // 0
ulong zero = reader.ReadUInt64();
uint nameOffset = reader.ReadUInt32();
ushort folderIndex = reader.ReadUInt16();
uint flags = reader.ReadUInt32();
uint dummy5 = reader.ReadUInt32();
uint dataID = reader.ReadUInt32(); // duplicate but sometimes it's zero when a cab is not available
string dummy = reader.ReadFixedLengthString(9);
ushort dataID2 = reader.ReadUInt16();// yeah it's the same as before
reader.Accessor.SavePosition();
reader.Seek(stringDirectoryOffset + strTblLength + nameOffset, SeekOrigin.Begin);
string fileName = ReadName(reader, unknown1);
reader.Accessor.LoadPosition();
File file = fsom.AddFile(fileName);
file.Properties.Add("offset", offset);
file.Properties.Add("compressedLength", compressedLength);
file.Properties.Add("decompressedLength", decompressedLength);
}
}
else
{
ulong CHUNK_SIZE = 0x10000;
for (uint i = 0; i < fileCount; i++)
{
uint offset = reader.ReadUInt32();
reader.Accessor.SavePosition();
reader.Accessor.Seek(stringDirectoryOffset + strTblLength + offset, SeekOrigin.Begin);
uint nameOffset = reader.ReadUInt32();
uint folderIndex = reader.ReadUInt32();
ushort type = reader.ReadUInt16();
uint decompressedLength = reader.ReadUInt32();
uint compressedLength = reader.ReadUInt32();
uint dummy1 = reader.ReadUInt32();
uint dummy2 = reader.ReadUInt32();
uint dummy3 = reader.ReadUInt32();
ushort dummy4 = reader.ReadUInt16();
uint dummy5 = reader.ReadUInt32();
ushort dummy6 = reader.ReadUInt16();
uint offset2 = reader.ReadUInt32();
ulong dummt7 = reader.ReadUInt64();
ulong dummy8 = reader.ReadUInt64();
uint data_id = 1;
reader.Seek(stringDirectoryOffset + strTblLength + nameOffset, SeekOrigin.Begin);
string fileName = ReadName(reader, unknown1);
reader.Accessor.LoadPosition();
if (folderIndex > 0)
{
fileName = folderNames[folderIndex] + '/' + fileName;
}
File file = fsom.AddFile(fileName);
file.Properties.Add("offset", offset);
file.Properties.Add("compressedLength", compressedLength);
file.Properties.Add("decompressedLength", decompressedLength);
file.Size = decompressedLength;
file.DataRequest += File_DataRequest; ;
}
}
}
private void File_DataRequest(object sender, DataRequestEventArgs e)
{
if (cabfile == null)
return;
File file = (sender as File);
uint offset = (uint)file.Properties["offset"];
uint compressedLength = (uint)file.Properties["compressedLength"];
uint decompressedLength = (uint)file.Properties["decompressedLength"];
byte[] compressedData = new byte[compressedLength];
cabfile.Seek(offset, System.IO.SeekOrigin.Begin);
cabfile.Read(compressedData, 0, compressedData.Length);
CompressionModule deflatex = CompressionModule.FromKnownCompressionMethod(Compression.CompressionMethod.Deflate);
byte[] decompressedData = deflatex.Decompress(compressedData, (int)decompressedLength);
e.Data = decompressedData;
}
private string ReadName(Reader reader, uint flags)
{
string folderName = null;
if ((flags & 0x04000000) == 0x04000000)
{
folderName = reader.ReadNullTerminatedString(IO.Encoding.UTF16LittleEndian);
}
else
{
folderName = reader.ReadNullTerminatedString();
}
return folderName;
}
protected override void SaveInternal(ObjectModel objectModel)
{
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
if (fsom == null)
throw new ObjectModelNotSupportedException();
Writer writer = Accessor.Writer;
writer.WriteFixedLengthString("ISc(");
writer.WriteUInt32(16798209);
}
}
}

View File

@ -33,7 +33,7 @@ namespace UniversalEditor.DataFormats.FileSystem.InstallShield.PKG
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
if (fsom == null) return;
Reader br = base.Accessor.Reader;
Reader br = Accessor.Reader;
ushort signature = br.ReadUInt16();
if (signature != 0xA34A) throw new InvalidDataFormatException("File does not begin with 0xA34A");
@ -41,28 +41,29 @@ namespace UniversalEditor.DataFormats.FileSystem.InstallShield.PKG
ushort unknown1b = br.ReadUInt16();
uint unknown2 = br.ReadUInt32();
uint unknown3 = br.ReadUInt32();
/*
uint unknown4 = br.ReadUInt32();
ushort unknown5 = br.ReadUInt16();
ushort unknown6 = br.ReadUInt16();
ushort unknown7 = br.ReadUInt16();
*/
ushort fileCount = br.ReadUInt16();
for (ushort i = 0; i < fileCount; i++)
{
string FileName = br.ReadLengthPrefixedString();
ushort FileNameLength = br.ReadUInt16();
string FileName = br.ReadFixedLengthString(FileNameLength);
/*
byte unknown8 = br.ReadByte();
uint unknown9 = br.ReadUInt32();
ushort unknown10 = br.ReadUInt16();
File file = new File();
file.Name = FileName;
file.Size = unknown10;
*/
ushort unknown8 = br.ReadUInt16();
ushort maybeLength = br.ReadUInt16();
ushort unknown9 = br.ReadUInt16();
File file = fsom.AddFile(FileName);
file.Size = maybeLength;
file.DataRequest += new DataRequestEventHandler(file_DataRequest);
fsom.Files.Add(file);
if (file.Name == "OP.Z")
{
}
}
}
@ -72,7 +73,26 @@ namespace UniversalEditor.DataFormats.FileSystem.InstallShield.PKG
protected override void SaveInternal(ObjectModel objectModel)
{
throw new NotImplementedException();
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
if (fsom == null) return;
Writer bw = Accessor.Writer;
bw.WriteUInt16(0xA34A);
bw.WriteUInt32(10);
bw.WriteUInt32(2);
bw.WriteUInt32(65536);
File[] files = fsom.GetAllFiles();
bw.WriteUInt16((ushort)files.Length);
for (ushort i = 0; i < (ushort)files.Length; i++)
{
bw.WriteUInt16((ushort)files[i].Name.Length);
bw.WriteFixedLengthString(files[i].Name, (ushort)files[i].Name.Length);
bw.WriteUInt16(2);
bw.WriteUInt16((ushort)files[i].Size);
bw.WriteUInt16(8);
}
}
}
}