Inno Header v6 reading almost works
This commit is contained in:
84
IInnoHeader.cs
Normal file
84
IInnoHeader.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
|
||||
namespace InnoPatcher;
|
||||
|
||||
internal interface IInnoHeader : IInnoSerializable
|
||||
{
|
||||
string? AppName { get; set; }
|
||||
string? AppVerName { get; set; }
|
||||
string? AppId { get; set; }
|
||||
string? AppCopyright { get; set; }
|
||||
string? AppPublisher { get; set; }
|
||||
string? AppPublisherURL { get; set; }
|
||||
string? AppSupportPhone { get; set; }
|
||||
string? AppSupportURL { get; set; }
|
||||
string? AppUpdatesURL { get; set; }
|
||||
string? AppVersion { get; set; }
|
||||
string? DefaultDirName { get; set; }
|
||||
string? DefaultGroupName { get; set; }
|
||||
string? BaseFilename { get; set; }
|
||||
string? UninstallFilesDir { get; set; }
|
||||
string? UninstallDisplayName { get; set; }
|
||||
string? UninstallDisplayIcon { get; set; }
|
||||
string? AppMutex { get; set; }
|
||||
string? DefaultUserInfoName { get; set; }
|
||||
string? DefaultUserInfoOrg { get; set; }
|
||||
string? DefaultUserInfoSerial { get; set; }
|
||||
string? AppReadmeFile { get; set; }
|
||||
string? AppContact { get; set; }
|
||||
string? AppComments { get; set; }
|
||||
string? AppModifyPath { get; set; }
|
||||
string? CreateUninstallRegKey { get; set; }
|
||||
string? Uninstallable { get; set; }
|
||||
string? CloseApplicationsFilter { get; set; }
|
||||
string? SetupMutex { get; set; }
|
||||
string? ChangesEnvironment { get; set; }
|
||||
string? ChangesAssociations { get; set; }
|
||||
|
||||
ReadOnlySpan<byte> LicenseText { get; set; }
|
||||
ReadOnlySpan<byte> InfoBeforeText { get; set; }
|
||||
ReadOnlySpan<byte> InfoAfterText { get; set; }
|
||||
ReadOnlySpan<byte> CompiledCodeText { get; set; }
|
||||
|
||||
int NumLanguageEntries { get; set; }
|
||||
int NumCustomMessageEntries { get; set; }
|
||||
int NumPermissionEntries { get; set; }
|
||||
int NumTypeEntries { get; set; }
|
||||
int NumComponentEntries { get; set; }
|
||||
int NumTaskEntries { get; set; }
|
||||
int NumDirEntries { get; set; }
|
||||
int NumFileEntries { get; set; }
|
||||
int NumFileLocationEntries { get; set; }
|
||||
int NumIconEntries { get; set; }
|
||||
int NumIniEntries { get; set; }
|
||||
int NumRegistryEntries { get; set; }
|
||||
int NumInstallDeleteEntries { get; set; }
|
||||
int NumUninstallDeleteEntries { get; set; }
|
||||
int NumRunEntries { get; set; }
|
||||
int NumUninstallRunEntries { get; set; }
|
||||
InnoVersionData MinVersion { get; set; }
|
||||
InnoVersionData OnlyBelowVersion { get; set; }
|
||||
int BackColor { get; set; }
|
||||
int BackColor2 { get; set; }
|
||||
InnoWizardStyle WizardStyle { get; set; }
|
||||
int WizardSizePercentX { get; set; }
|
||||
int WizardSizePercentY { get; set; }
|
||||
InnoAlphaFormat WizardImageAlphaFormat { get; set; }
|
||||
InnoSha1Digest PasswordHash { get; set; }
|
||||
InnoSalt PasswordSalt { get; set; }
|
||||
long ExtraDiskSpaceRequired { get; set; }
|
||||
int SlicesPerDisk { get; set; }
|
||||
InnoLogMode UninstallLogMode { get; set; }
|
||||
InnoAutoNoYes DirExistsWarning { get; set; }
|
||||
InnoPrivilegesRequired PrivilegesRequired { get; set; }
|
||||
InnoPrivilegesRequiredOverride PrivilegesRequiredOverridesAllowed { get; set; }
|
||||
InnoYesNoAuto ShowLanguageDialog { get; set; }
|
||||
InnoLanguageDetectionMethod LanguageDetectionMethod { get; set; }
|
||||
InnoCompressMethod CompressMethod { get; set; }
|
||||
InnoProcessorArchitecture ArchitecturesAllowed { get; set; }
|
||||
InnoProcessorArchitecture ArchitecturesInstallIn64BitMode { get; set; }
|
||||
InnoDisablePage DisableDirPage { get; set; }
|
||||
InnoDisablePage DisableProgramGroupPage { get; set; }
|
||||
long UninstallDisplaySize { get; set; }
|
||||
InnoHeaderOption Options { get; set; }
|
||||
}
|
||||
21
IInnoSerializable.cs
Normal file
21
IInnoSerializable.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace InnoPatcher;
|
||||
|
||||
/// <summary>
|
||||
/// Serializable Inno structure.
|
||||
/// </summary>
|
||||
internal interface IInnoSerializable {
|
||||
int StringCount { get; }
|
||||
int ByteArrayCount { get; }
|
||||
int PrimitiveSize { get; }
|
||||
|
||||
string? GetString(int idx);
|
||||
void SetString(int idx, string? value);
|
||||
|
||||
ReadOnlySpan<byte> GetByteArray(int idx);
|
||||
void SetByteArray(int idx, ReadOnlySpan<byte> value);
|
||||
|
||||
ReadOnlySpan<byte> GetPrimitive();
|
||||
void SetPrimitive(ReadOnlySpan<byte> raw);
|
||||
}
|
||||
6
InnoAlphaFormat.cs
Normal file
6
InnoAlphaFormat.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace InnoPatcher;
|
||||
|
||||
internal enum InnoAlphaFormat {
|
||||
// Must be same as Graphics.TAlphaFormat
|
||||
Ignored, Defined, Premultiplied
|
||||
}
|
||||
5
InnoAutoNoYes.cs
Normal file
5
InnoAutoNoYes.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace InnoPatcher;
|
||||
|
||||
internal enum InnoAutoNoYes {
|
||||
Auto, No, Yes
|
||||
}
|
||||
13
InnoCompressMethod.cs
Normal file
13
InnoCompressMethod.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace InnoPatcher;
|
||||
|
||||
internal enum InnoCompressMethod {
|
||||
Stored, Zip, Bzip, LZMA, LZMA2
|
||||
}
|
||||
|
||||
internal enum InnoCompressMethod4205 {
|
||||
Stored, Bzip, LZMA
|
||||
}
|
||||
|
||||
internal enum InnoCompressMethodPre4205 {
|
||||
Zip, Bzip, LZMA
|
||||
}
|
||||
5
InnoDisablePage.cs
Normal file
5
InnoDisablePage.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace InnoPatcher;
|
||||
|
||||
internal enum InnoDisablePage {
|
||||
Auto, No, Yes
|
||||
}
|
||||
30
InnoHeaderOption.cs
Normal file
30
InnoHeaderOption.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace InnoPatcher;
|
||||
|
||||
[Flags]
|
||||
public enum InnoHeaderOption {
|
||||
DisableStartupPrompt = 0x000001,
|
||||
Uninstallable = 0x000002,
|
||||
CreateAppDir = 0x000004,
|
||||
DisableDirPage = 0x000008,
|
||||
DisableProgramGroupPage = 0x000010,
|
||||
AllowNoIcons = 0x000020,
|
||||
AlwaysRestart = 0x000040,
|
||||
AlwaysUsePersonalGroup = 0x000080,
|
||||
WindowVisible = 0x000100,
|
||||
WindowShowCaption = 0x000200,
|
||||
WindowResizable = 0x000400,
|
||||
WindowStartMaximized = 0x000800,
|
||||
EnableDirDoesntExistWarning = 0x001000,
|
||||
DisableAppendDir = 0x002000,
|
||||
Password = 0x004000,
|
||||
AllowRootDirectory = 0x008000,
|
||||
DisableFinishedPage = 0x010000,
|
||||
AdminPrivilegesRequired = 0x020000,
|
||||
AlwaysCreateUninstallIcon = 0x040000,
|
||||
ChangesAssociations = 0x080000,
|
||||
CreateUninstallRegKey = 0x100000,
|
||||
UsePreviousAppDir = 0x200000,
|
||||
BackColorHorizontal = 0x400000,
|
||||
UsePreviousGroup = 0x800000,
|
||||
UpdateUninstallLogAppName = 0x1000000,
|
||||
}
|
||||
236
InnoHeaderV6.cs
Normal file
236
InnoHeaderV6.cs
Normal file
@@ -0,0 +1,236 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace InnoPatcher;
|
||||
|
||||
sealed class InnoHeaderV6 : IInnoHeader, IInnoSerializable
|
||||
{
|
||||
public string? AppName { get; set; }
|
||||
public string? AppVerName { get; set; }
|
||||
public string? AppId { get; set; }
|
||||
public string? AppCopyright { get; set; }
|
||||
public string? AppPublisher { get; set; }
|
||||
public string? AppPublisherURL { get; set; }
|
||||
public string? AppSupportPhone { get; set; }
|
||||
public string? AppSupportURL { get; set; }
|
||||
public string? AppUpdatesURL { get; set; }
|
||||
public string? AppVersion { get; set; }
|
||||
public string? DefaultDirName { get; set; }
|
||||
public string? DefaultGroupName { get; set; }
|
||||
public string? BaseFilename { get; set; }
|
||||
public string? UninstallFilesDir { get; set; }
|
||||
public string? UninstallDisplayName { get; set; }
|
||||
public string? UninstallDisplayIcon { get; set; }
|
||||
public string? AppMutex { get; set; }
|
||||
public string? DefaultUserInfoName { get; set; }
|
||||
public string? DefaultUserInfoOrg { get; set; }
|
||||
public string? DefaultUserInfoSerial { get; set; }
|
||||
public string? AppReadmeFile { get; set; }
|
||||
public string? AppContact { get; set; }
|
||||
public string? AppComments { get; set; }
|
||||
public string? AppModifyPath { get; set; }
|
||||
public string? CreateUninstallRegKey { get; set; }
|
||||
public string? Uninstallable { get; set; }
|
||||
public string? CloseApplicationsFilter { get; set; }
|
||||
public string? SetupMutex { get; set; }
|
||||
public string? ChangesEnvironment { get; set; }
|
||||
public string? ChangesAssociations { get; set; }
|
||||
|
||||
private byte[]? _licenseText;
|
||||
public ReadOnlySpan<byte> LicenseText { get => _licenseText; set { _licenseText = value.ToArray(); } }
|
||||
private byte[]? _infoBeforeText;
|
||||
public ReadOnlySpan<byte> InfoBeforeText { get => _infoBeforeText; set { _infoBeforeText = value.ToArray(); } }
|
||||
private byte[]? _infoAfterText;
|
||||
public ReadOnlySpan<byte> InfoAfterText { get => _infoAfterText; set { _infoAfterText = value.ToArray(); } }
|
||||
private byte[]? _compiledCodeText;
|
||||
public ReadOnlySpan<byte> CompiledCodeText { get => _compiledCodeText; set { _compiledCodeText = value.ToArray(); } }
|
||||
|
||||
private Primitives _primitives;
|
||||
|
||||
public int NumLanguageEntries { get => _primitives.NumLanguageEntries; set => _primitives.NumLanguageEntries = value; }
|
||||
public int NumCustomMessageEntries { get => _primitives.NumCustomMessageEntries; set => _primitives.NumCustomMessageEntries = value; }
|
||||
public int NumPermissionEntries { get => _primitives.NumPermissionEntries; set => _primitives.NumPermissionEntries = value; }
|
||||
public int NumTypeEntries { get => _primitives.NumTypeEntries; set => _primitives.NumTypeEntries = value; }
|
||||
public int NumComponentEntries { get => _primitives.NumComponentEntries; set => _primitives.NumComponentEntries = value; }
|
||||
public int NumTaskEntries { get => _primitives.NumTaskEntries; set => _primitives.NumTaskEntries = value; }
|
||||
public int NumDirEntries { get => _primitives.NumDirEntries; set => _primitives.NumDirEntries = value; }
|
||||
public int NumFileEntries { get => _primitives.NumFileEntries; set => _primitives.NumFileEntries = value; }
|
||||
public int NumFileLocationEntries { get => _primitives.NumFileLocationEntries; set => _primitives.NumFileLocationEntries = value; }
|
||||
public int NumIconEntries { get => _primitives.NumIconEntries; set => _primitives.NumIconEntries = value; }
|
||||
public int NumIniEntries { get => _primitives.NumIniEntries; set => _primitives.NumIniEntries = value; }
|
||||
public int NumRegistryEntries { get => _primitives.NumRegistryEntries; set => _primitives.NumRegistryEntries = value; }
|
||||
public int NumInstallDeleteEntries { get => _primitives.NumInstallDeleteEntries; set => _primitives.NumInstallDeleteEntries = value; }
|
||||
public int NumUninstallDeleteEntries { get => _primitives.NumUninstallDeleteEntries; set => _primitives.NumUninstallDeleteEntries = value; }
|
||||
public int NumRunEntries { get => _primitives.NumRunEntries; set => _primitives.NumRunEntries = value; }
|
||||
public int NumUninstallRunEntries { get => _primitives.NumUninstallRunEntries; set => _primitives.NumUninstallRunEntries = value; }
|
||||
public InnoVersionData MinVersion { get => _primitives.MinVersion; set => _primitives.MinVersion = value; }
|
||||
public InnoVersionData OnlyBelowVersion { get => _primitives.OnlyBelowVersion; set => _primitives.OnlyBelowVersion = value; }
|
||||
public int BackColor { get => _primitives.BackColor; set => _primitives.BackColor = value; }
|
||||
public int BackColor2 { get => _primitives.BackColor2; set => _primitives.BackColor2 = value; }
|
||||
public InnoWizardStyle WizardStyle { get => _primitives.WizardStyle; set => _primitives.WizardStyle = value; }
|
||||
public int WizardSizePercentX { get => _primitives.WizardSizePercentX; set => _primitives.WizardSizePercentX = value; }
|
||||
public int WizardSizePercentY { get => _primitives.WizardSizePercentY; set => _primitives.WizardSizePercentY = value; }
|
||||
public InnoAlphaFormat WizardImageAlphaFormat { get => _primitives.WizardImageAlphaFormat; set => _primitives.WizardImageAlphaFormat = value; }
|
||||
public InnoSha1Digest PasswordHash { get => _primitives.PasswordHash; set => _primitives.PasswordHash = value; }
|
||||
public InnoSalt PasswordSalt { get => _primitives.PasswordSalt; set => _primitives.PasswordSalt = value; }
|
||||
public long ExtraDiskSpaceRequired { get => _primitives.ExtraDiskSpaceRequired; set => _primitives.ExtraDiskSpaceRequired = value; }
|
||||
public int SlicesPerDisk { get => _primitives.SlicesPerDisk; set => _primitives.SlicesPerDisk = value; }
|
||||
public InnoLogMode UninstallLogMode { get => _primitives.UninstallLogMode; set => _primitives.UninstallLogMode = value; }
|
||||
public InnoAutoNoYes DirExistsWarning { get => _primitives.DirExistsWarning; set => _primitives.DirExistsWarning = value; }
|
||||
public InnoPrivilegesRequired PrivilegesRequired { get => _primitives.PrivilegesRequired; set => _primitives.PrivilegesRequired = value; }
|
||||
public InnoPrivilegesRequiredOverride PrivilegesRequiredOverridesAllowed { get => _primitives.PrivilegesRequiredOverridesAllowed; set => _primitives.PrivilegesRequiredOverridesAllowed = value; }
|
||||
public InnoYesNoAuto ShowLanguageDialog { get => _primitives.ShowLanguageDialog; set => _primitives.ShowLanguageDialog = value; }
|
||||
public InnoLanguageDetectionMethod LanguageDetectionMethod { get => _primitives.LanguageDetectionMethod; set => _primitives.LanguageDetectionMethod = value; }
|
||||
public InnoCompressMethod CompressMethod { get => _primitives.CompressMethod; set => _primitives.CompressMethod = value; }
|
||||
public InnoProcessorArchitecture ArchitecturesAllowed { get => _primitives.ArchitecturesAllowed; set => _primitives.ArchitecturesAllowed = value; }
|
||||
public InnoProcessorArchitecture ArchitecturesInstallIn64BitMode { get => _primitives.ArchitecturesInstallIn64BitMode; set => _primitives.ArchitecturesInstallIn64BitMode = value; }
|
||||
public InnoDisablePage DisableDirPage { get => _primitives.DisableDirPage; set => _primitives.DisableDirPage = value; }
|
||||
public InnoDisablePage DisableProgramGroupPage { get => _primitives.DisableProgramGroupPage; set => _primitives.DisableProgramGroupPage = value; }
|
||||
public long UninstallDisplaySize { get => _primitives.UninstallDisplaySize; set => _primitives.UninstallDisplaySize = value; }
|
||||
public InnoHeaderOption Options { get => _primitives.Options; set => _primitives.Options = value; }
|
||||
|
||||
#region IInnoSerializable Members
|
||||
|
||||
public int StringCount => 30;
|
||||
public int ByteArrayCount => 4;
|
||||
public int PrimitiveSize => Marshal.SizeOf<Primitives>();
|
||||
|
||||
public string? GetString(int idx)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: return AppName;
|
||||
case 1: return AppVerName;
|
||||
case 2: return AppId;
|
||||
case 3: return AppCopyright;
|
||||
case 4: return AppPublisher;
|
||||
case 5: return AppPublisherURL;
|
||||
case 6: return AppSupportPhone;
|
||||
case 7: return AppSupportURL;
|
||||
case 8: return AppUpdatesURL;
|
||||
case 9: return AppVersion;
|
||||
case 10: return DefaultDirName;
|
||||
case 11: return DefaultGroupName;
|
||||
case 12: return BaseFilename;
|
||||
case 13: return UninstallFilesDir;
|
||||
case 14: return UninstallDisplayName;
|
||||
case 15: return UninstallDisplayIcon;
|
||||
case 16: return AppMutex;
|
||||
case 17: return DefaultUserInfoName;
|
||||
case 18: return DefaultUserInfoOrg;
|
||||
case 19: return DefaultUserInfoSerial;
|
||||
case 20: return AppReadmeFile;
|
||||
case 21: return AppContact;
|
||||
case 22: return AppComments;
|
||||
case 23: return AppModifyPath;
|
||||
case 24: return CreateUninstallRegKey;
|
||||
case 25: return Uninstallable;
|
||||
case 26: return CloseApplicationsFilter;
|
||||
case 27: return SetupMutex;
|
||||
case 28: return ChangesEnvironment;
|
||||
case 29: return ChangesAssociations;
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetString(int idx, string? value)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: AppName = value; break;
|
||||
case 1: AppVerName = value; break;
|
||||
case 2: AppId = value; break;
|
||||
case 3: AppCopyright = value; break;
|
||||
case 4: AppPublisher = value; break;
|
||||
case 5: AppPublisherURL = value; break;
|
||||
case 6: AppSupportPhone = value; break;
|
||||
case 7: AppSupportURL = value; break;
|
||||
case 8: AppUpdatesURL = value; break;
|
||||
case 9: AppVersion = value; break;
|
||||
case 10: DefaultDirName = value; break;
|
||||
case 11: DefaultGroupName = value; break;
|
||||
case 12: BaseFilename = value; break;
|
||||
case 13: UninstallFilesDir = value; break;
|
||||
case 14: UninstallDisplayName = value; break;
|
||||
case 15: UninstallDisplayIcon = value; break;
|
||||
case 16: AppMutex = value; break;
|
||||
case 17: DefaultUserInfoName = value; break;
|
||||
case 18: DefaultUserInfoOrg = value; break;
|
||||
case 19: DefaultUserInfoSerial = value; break;
|
||||
case 20: AppReadmeFile = value; break;
|
||||
case 21: AppContact = value; break;
|
||||
case 22: AppComments = value; break;
|
||||
case 23: AppModifyPath = value; break;
|
||||
case 24: CreateUninstallRegKey = value; break;
|
||||
case 25: Uninstallable = value; break;
|
||||
case 26: CloseApplicationsFilter = value; break;
|
||||
case 27: SetupMutex = value; break;
|
||||
case 28: ChangesEnvironment = value; break;
|
||||
case 29: ChangesAssociations = value; break;
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetByteArray(int idx)
|
||||
{
|
||||
switch (idx) {
|
||||
case 0: return _licenseText;
|
||||
case 1: return _infoBeforeText;
|
||||
case 2: return _infoAfterText;
|
||||
case 3: return _compiledCodeText;
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetByteArray(int idx, ReadOnlySpan<byte> value)
|
||||
{
|
||||
switch (idx) {
|
||||
case 0: _licenseText = value.ToArray(); break;
|
||||
case 1: _infoBeforeText = value.ToArray(); break;
|
||||
case 2: _infoAfterText = value.ToArray(); break;
|
||||
case 3: _compiledCodeText = value.ToArray(); break;
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetPrimitive()
|
||||
{
|
||||
return MemoryMarshal.Cast<Primitives, byte>(new ReadOnlySpan<Primitives>(ref _primitives));
|
||||
}
|
||||
|
||||
public void SetPrimitive(ReadOnlySpan<byte> raw)
|
||||
{
|
||||
_primitives = MemoryMarshal.Cast<byte, Primitives>(raw)[0];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Primitives {
|
||||
internal int NumLanguageEntries, NumCustomMessageEntries, NumPermissionEntries,
|
||||
NumTypeEntries, NumComponentEntries, NumTaskEntries, NumDirEntries,
|
||||
NumFileEntries, NumFileLocationEntries, NumIconEntries, NumIniEntries,
|
||||
NumRegistryEntries, NumInstallDeleteEntries, NumUninstallDeleteEntries,
|
||||
NumRunEntries, NumUninstallRunEntries; // Integer
|
||||
internal InnoVersionData MinVersion, OnlyBelowVersion;
|
||||
internal int BackColor, BackColor2; // Longint
|
||||
internal InnoWizardStyle WizardStyle;
|
||||
internal int WizardSizePercentX, WizardSizePercentY; // Integer
|
||||
internal InnoAlphaFormat WizardImageAlphaFormat;
|
||||
internal InnoSha1Digest PasswordHash;
|
||||
internal InnoSalt PasswordSalt; // TSetupSalt
|
||||
internal long ExtraDiskSpaceRequired; // Integer64
|
||||
internal int SlicesPerDisk; // Integer
|
||||
internal InnoLogMode UninstallLogMode;
|
||||
internal InnoAutoNoYes DirExistsWarning;
|
||||
internal InnoPrivilegesRequired PrivilegesRequired;
|
||||
internal InnoPrivilegesRequiredOverride PrivilegesRequiredOverridesAllowed;
|
||||
internal InnoYesNoAuto ShowLanguageDialog;
|
||||
internal InnoLanguageDetectionMethod LanguageDetectionMethod;
|
||||
internal InnoCompressMethod CompressMethod;
|
||||
internal InnoProcessorArchitecture ArchitecturesAllowed, ArchitecturesInstallIn64BitMode;
|
||||
internal InnoDisablePage DisableDirPage, DisableProgramGroupPage;
|
||||
internal long UninstallDisplaySize; // Integer64
|
||||
internal InnoHeaderOption Options;
|
||||
}
|
||||
}
|
||||
5
InnoLanguageDetectionMethod.cs
Normal file
5
InnoLanguageDetectionMethod.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace InnoPatcher;
|
||||
|
||||
internal enum InnoLanguageDetectionMethod {
|
||||
UILanguage, Locale, None
|
||||
}
|
||||
@@ -70,7 +70,7 @@ sealed class InnoLoader {
|
||||
|
||||
public Version Version => _version;
|
||||
|
||||
internal int Version2 => _version.Major * 1000 + _version.Minor * 100 + _version.Revision;
|
||||
internal int Version2 => _version.Major * 1000 + _version.Minor * 100 + _version.Build;
|
||||
|
||||
public bool IsUnicode => _isUnicode;
|
||||
|
||||
@@ -78,7 +78,7 @@ sealed class InnoLoader {
|
||||
|
||||
public InnoSetup GetSetup() {
|
||||
_file.Seek(_offsets.Offset0 + HeaderSize, SeekOrigin.Begin);
|
||||
if (!InnoSetup.TryParse(_file, Version2, out InnoSetup result))
|
||||
if (!InnoSetup.TryParse(_file, Version2, out InnoSetup? result))
|
||||
throw new FormatException("Failed to parse Inno Setup");
|
||||
return result;
|
||||
}
|
||||
@@ -199,7 +199,7 @@ sealed class InnoLoader {
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct InnoLoaderOffsetTableV6 {
|
||||
internal uint TotalSize; // Minimum expected size of setup.exe
|
||||
internal uint OffsetEXE; // Offset of compressed setup.e32
|
||||
@@ -224,7 +224,7 @@ sealed class InnoLoader {
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct InnoLoaderOffsetTableV7 {
|
||||
internal uint TotalSize; // Minimum expected size of setup.exe
|
||||
internal uint OffsetEXE; // Offset of compressed setup.e32
|
||||
@@ -248,7 +248,7 @@ sealed class InnoLoader {
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct InnoLoaderOffsetTableV8 {
|
||||
internal uint Version; // SetupLdrOffsetTableVersion
|
||||
internal uint TotalSize; // Minimum expected size of setup.exe
|
||||
|
||||
5
InnoLogMode.cs
Normal file
5
InnoLogMode.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace InnoPatcher;
|
||||
|
||||
internal enum InnoLogMode {
|
||||
Append, New, Overwrite
|
||||
}
|
||||
5
InnoPrivilegesRequired.cs
Normal file
5
InnoPrivilegesRequired.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace InnoPatcher;
|
||||
|
||||
internal enum InnoPrivilegesRequired {
|
||||
None, PowerUser, Admin, Lowest
|
||||
}
|
||||
7
InnoPrivilegesRequiredOverride.cs
Normal file
7
InnoPrivilegesRequiredOverride.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace InnoPatcher;
|
||||
|
||||
[Flags]
|
||||
internal enum InnoPrivilegesRequiredOverride {
|
||||
CommandLine = 0x01,
|
||||
Dialog = 0x02,
|
||||
}
|
||||
10
InnoProcessorArchitecture.cs
Normal file
10
InnoProcessorArchitecture.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace InnoPatcher;
|
||||
|
||||
[Flags]
|
||||
public enum InnoProcessorArchitecture {
|
||||
Unknown = 0x01,
|
||||
X86 = 0x02,
|
||||
X64 = 0x04,
|
||||
IA64 = 0x08,
|
||||
ARM64 = 0x10,
|
||||
}
|
||||
9
InnoSalt.cs
Normal file
9
InnoSalt.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace InnoPatcher;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct InnoSalt {
|
||||
internal ulong _x0;
|
||||
}
|
||||
327
InnoSetup.cs
327
InnoSetup.cs
@@ -1,18 +1,27 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using SevenZip.Compression.LZMA;
|
||||
|
||||
using StringBuilder = System.Text.StringBuilder;
|
||||
|
||||
namespace InnoPatcher;
|
||||
|
||||
sealed class InnoSetup {
|
||||
private const int BlockSize = 4096 + 4;
|
||||
private const int CompressionPropertiesLength = 5;
|
||||
|
||||
private readonly IInnoHeader _header;
|
||||
|
||||
private InnoSetup(IInnoHeader header) {
|
||||
this._header = header;
|
||||
}
|
||||
|
||||
internal static bool TryParse(Stream file, int innoVersion, [NotNullWhen(true)] out InnoSetup? result) {
|
||||
result = null;
|
||||
|
||||
byte[] headerB = new byte[Marshal.SizeOf<Header>()];
|
||||
byte[] headerB = new byte[Marshal.SizeOf<BlocksHeader>()];
|
||||
int read, offset = 0;
|
||||
while ((read = file.Read(headerB, offset, headerB.Length - offset)) != 0)
|
||||
offset += read;
|
||||
@@ -20,56 +29,294 @@ sealed class InnoSetup {
|
||||
return false;
|
||||
|
||||
// Read header
|
||||
Header header = MemoryMarshal.Cast<byte, Header>(headerB)[0];
|
||||
BlocksHeader blocksHeader = MemoryMarshal.Cast<byte, BlocksHeader>(headerB)[0];
|
||||
ReadOnlySpan<byte> headerB2 = headerB;
|
||||
if (!InnoLoader.VerifyCRC(headerB2.Slice(4), header.CRC))
|
||||
if (!InnoLoader.VerifyCRC(headerB2.Slice(4), blocksHeader.CRC))
|
||||
return false;
|
||||
|
||||
if (header.Compressed != 0 && innoVersion < 4105)
|
||||
if (blocksHeader.Compressed != 0 && innoVersion < 4105)
|
||||
throw new NotImplementedException("Zlib decompression not implemented.");
|
||||
|
||||
// Decode
|
||||
Decoder decoder = new Decoder();
|
||||
MemoryStream a = new MemoryStream();
|
||||
byte[] blockB = new byte[BlockSize];
|
||||
bool decoderInitialized = false;
|
||||
for (uint toRead = header.StoredSize; toRead > 0;) {
|
||||
int blockSize = toRead > BlockSize ? BlockSize : (int)toRead;
|
||||
offset = 0;
|
||||
while ((read = file.Read(blockB, offset, blockSize - offset)) != 0)
|
||||
offset += read;
|
||||
if (offset < blockSize)
|
||||
return false;
|
||||
Stream data = new FixedBlockReadStream(file, blocksHeader.StoredSize);
|
||||
if (blocksHeader.Compressed != 0)
|
||||
data = new CompressedReadStream(data);
|
||||
|
||||
ReadOnlySpan<byte> blockData = blockB;
|
||||
uint blockCRC = MemoryMarshal.Cast<byte, uint>(blockData.Slice(0, 4))[0];
|
||||
blockData = blockData.Slice(4);
|
||||
|
||||
if (!InnoLoader.VerifyCRC(blockData, blockCRC))
|
||||
return false;
|
||||
// Parse
|
||||
InnoSerializer ser = new InnoSerializer();
|
||||
IInnoHeader header = CreateHeader(innoVersion);
|
||||
ser.Deserialize(data, header);
|
||||
|
||||
if (header.Compressed != 0) {
|
||||
if (!decoderInitialized) {
|
||||
decoder.SetDecoderProperties(blockData.Slice(0, CompressionPropertiesLength).ToArray());
|
||||
blockData = blockData.Slice(CompressionPropertiesLength);
|
||||
decoderInitialized = true;
|
||||
}
|
||||
|
||||
decoder.Code(new MemoryStream(blockB, blockSize - blockData.Length, blockData.Length), a, blockData.Length, 84158, null);
|
||||
} else
|
||||
a.Write(blockData);
|
||||
|
||||
toRead -= (uint)blockSize;
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
result = new InnoSetup(header);
|
||||
return true;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Header {
|
||||
public string? AppName => _header.AppName;
|
||||
public string? AppVerName => _header.AppVerName;
|
||||
public string? AppId => _header.AppId;
|
||||
public string? AppCopyright => _header.AppCopyright;
|
||||
public string? AppPublisher => _header.AppPublisher;
|
||||
public string? AppPublisherURL => _header.AppPublisherURL;
|
||||
public string? AppSupportPhone => _header.AppSupportPhone;
|
||||
public string? AppSupportURL => _header.AppSupportURL;
|
||||
public string? AppUpdatesURL => _header.AppUpdatesURL;
|
||||
public string? AppVersion => _header.AppVersion;
|
||||
|
||||
private static IInnoHeader CreateHeader(int version) {
|
||||
if (version >= 6000 && version <= 7000)
|
||||
return new InnoHeaderV6();
|
||||
else
|
||||
throw new NotSupportedException($"Header format for version {version} is not supported.");
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct BlocksHeader {
|
||||
internal uint CRC;
|
||||
internal uint StoredSize; // Total bytes written, including the CRCs
|
||||
internal byte Compressed; // True if data is compressed, False if not
|
||||
}
|
||||
|
||||
sealed class InnoSerializer {
|
||||
private byte[] _buffer = new byte[512];
|
||||
|
||||
internal void Deserialize(Stream src, IInnoSerializable dst) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0, j = dst.StringCount; i < j; i++) {
|
||||
int byteLen = ReadInt32(src);
|
||||
sb.Clear();
|
||||
sb.EnsureCapacity(byteLen / 2);
|
||||
ReadString(src, sb, byteLen);
|
||||
dst.SetString(i, sb.ToString());
|
||||
}
|
||||
|
||||
for (int i = 0, j = dst.ByteArrayCount; i < j; i++) {
|
||||
int len = ReadInt32(src);
|
||||
byte[] value = new byte[len];
|
||||
ReadByteArray(src, value, len);
|
||||
dst.SetByteArray(i, value);
|
||||
}
|
||||
|
||||
int size = dst.PrimitiveSize;
|
||||
if (_buffer.Length < size) {
|
||||
int doubleSize = _buffer.Length * 2;
|
||||
_buffer = new byte[doubleSize >= size ? doubleSize : size];
|
||||
}
|
||||
ReadByteArray(src, _buffer, size);
|
||||
ReadOnlySpan<byte> buffer = _buffer;
|
||||
dst.SetPrimitive(buffer.Slice(0, size));
|
||||
}
|
||||
|
||||
private int ReadInt32(Stream a) {
|
||||
int read, offset = 0;
|
||||
byte[] buffer = _buffer;
|
||||
while (offset < 4 && (read = a.Read(buffer, offset, 4 - offset)) != 0)
|
||||
offset += read;
|
||||
if (offset < 4)
|
||||
throw new EndOfStreamException();
|
||||
ReadOnlySpan<byte> buffer2 = buffer;
|
||||
return MemoryMarshal.Cast<byte, int>(buffer2.Slice(0, 4))[0];
|
||||
}
|
||||
|
||||
private void ReadString(Stream src, StringBuilder dst, int byteLen) {
|
||||
int read;
|
||||
byte[] buffer = _buffer;
|
||||
ReadOnlySpan<char> bufferC = MemoryMarshal.Cast<byte, char>(buffer);
|
||||
bool splitChar = false;
|
||||
while (byteLen != 0 && (read = src.Read(buffer, splitChar ? 1 : 0, Math.Min(byteLen, buffer.Length))) != 0) {
|
||||
if (splitChar)
|
||||
read++;
|
||||
dst.Append(bufferC.Slice(0, read / 2));
|
||||
|
||||
splitChar = (read & 1) != 0;
|
||||
if (splitChar) {
|
||||
buffer[0] = buffer[read - 1];
|
||||
read--;
|
||||
}
|
||||
|
||||
byteLen -= read;
|
||||
}
|
||||
if (byteLen != 0)
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
private void ReadByteArray(Stream src, byte[] dst, int len) {
|
||||
int read, offset = 0;
|
||||
while (offset < len && (read = src.Read(dst, offset, len - offset)) != 0)
|
||||
offset += read;
|
||||
if (offset != len)
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads underlying stream composed of fixed-sized CRC protected blocks.
|
||||
/// </summary>
|
||||
sealed class FixedBlockReadStream : Stream {
|
||||
private readonly Stream _inner;
|
||||
private readonly byte[] _buffer;
|
||||
private int _bufferOffset;
|
||||
private int _bufferLeft;
|
||||
private uint _innerLeft;
|
||||
|
||||
internal FixedBlockReadStream(Stream inner, uint innerLength) {
|
||||
this._inner = inner;
|
||||
this._innerLeft = innerLength;
|
||||
this._buffer = new byte[BlockSize];
|
||||
}
|
||||
|
||||
public override bool CanRead => true;
|
||||
public override bool CanSeek => false;
|
||||
public override bool CanWrite => false;
|
||||
public override long Length => throw new NotSupportedException();
|
||||
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) {
|
||||
if (buffer == null)
|
||||
throw new ArgumentNullException();
|
||||
if (offset < 0 || count < 0 || buffer.Length - offset < count)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
int result = 0;
|
||||
while (count > 0) {
|
||||
if (_bufferLeft == 0) {
|
||||
if (_innerLeft == 0)
|
||||
return result;
|
||||
ReadBlock();
|
||||
}
|
||||
|
||||
int toCopy = count;
|
||||
if (toCopy > _bufferLeft)
|
||||
toCopy = _bufferLeft;
|
||||
Buffer.BlockCopy(_buffer, _bufferOffset, buffer, offset, toCopy);
|
||||
_bufferOffset += toCopy;
|
||||
_bufferLeft -= toCopy;
|
||||
offset += toCopy;
|
||||
count -= toCopy;
|
||||
result += toCopy;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public override int ReadByte() {
|
||||
if (_bufferLeft == 0) {
|
||||
if (_innerLeft == 0)
|
||||
return -1;
|
||||
ReadBlock();
|
||||
}
|
||||
|
||||
_bufferLeft--;
|
||||
return _buffer[_bufferOffset++];
|
||||
}
|
||||
|
||||
private void ReadBlock() {
|
||||
if (_bufferLeft != 0)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
int blockSize = _innerLeft > BlockSize ? BlockSize : (int)_innerLeft;
|
||||
int read, offset = 0;
|
||||
while ((read = _inner.Read(_buffer, offset, blockSize - offset)) != 0)
|
||||
offset += read;
|
||||
if (offset < blockSize)
|
||||
throw new IOException();
|
||||
|
||||
ReadOnlySpan<byte> blockData = _buffer;
|
||||
uint blockCRC = MemoryMarshal.Cast<byte, uint>(blockData.Slice(0, 4))[0];
|
||||
blockData = blockData.Slice(4);
|
||||
if (!InnoLoader.VerifyCRC(blockData, blockCRC))
|
||||
throw new IOException();
|
||||
|
||||
_bufferOffset = 4; // skip CRC
|
||||
_bufferLeft = blockSize - 4; // minus CRC
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Flush() {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads underlying LZMA compressed stream and decompresses it.
|
||||
/// </summary>
|
||||
sealed class CompressedReadStream : Stream {
|
||||
private readonly Stream _inner;
|
||||
private readonly Decoder _decoder;
|
||||
private byte[]? _singleByteBuffer;
|
||||
private MemoryStream? _singleByteStream;
|
||||
private long _outOffset;
|
||||
|
||||
internal CompressedReadStream(Stream inner) {
|
||||
this._inner = inner;
|
||||
this._decoder = new Decoder();
|
||||
|
||||
byte[] props = new byte[CompressionPropertiesLength];
|
||||
int read, offset = 0;
|
||||
while ((read = inner.Read(props, offset, props.Length - offset)) != 0)
|
||||
offset += read;
|
||||
if (offset != props.Length)
|
||||
throw new IOException();
|
||||
_decoder.SetDecoderProperties(props);
|
||||
|
||||
_decoder.Code(inner, Stream.Null, -1, 0, null, noInit: false, isLast: false);
|
||||
}
|
||||
|
||||
public override bool CanRead => true;
|
||||
public override bool CanSeek => false;
|
||||
public override bool CanWrite => false;
|
||||
public override long Length => throw new NotSupportedException();
|
||||
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) {
|
||||
if (buffer == null)
|
||||
throw new ArgumentNullException();
|
||||
if (offset < 0 || count < 0 || buffer.Length - offset < count)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
MemoryStream result = new MemoryStream(buffer, offset, count, writable: true);
|
||||
_decoder.Code(_inner, result, -1, _outOffset + count, null, noInit: true, isLast: false);
|
||||
int read = (int)result.Position;
|
||||
_outOffset += read;
|
||||
return read;
|
||||
}
|
||||
|
||||
public override int ReadByte() {
|
||||
if (_singleByteBuffer == null || _singleByteStream == null) {
|
||||
_singleByteBuffer = new byte[1];
|
||||
_singleByteStream = new MemoryStream(_singleByteBuffer, 0, 1, writable: true);
|
||||
}
|
||||
_singleByteStream.SetLength(0);
|
||||
|
||||
_decoder.Code(_inner, _singleByteStream, -1, _outOffset + 1, null, noInit: true, isLast: false);
|
||||
int read = (int)_singleByteStream.Position;
|
||||
_outOffset += read;
|
||||
|
||||
return read == 0 ? -1 : _singleByteBuffer[0];
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Flush() {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
9
InnoSha1Digest.cs
Normal file
9
InnoSha1Digest.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace InnoPatcher;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct InnoSha1Digest {
|
||||
internal uint _x0, _x1, _x2, _x3, _x4;
|
||||
}
|
||||
10
InnoVersionData.cs
Normal file
10
InnoVersionData.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace InnoPatcher;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct InnoVersionData {
|
||||
int WinVersion, NTVersion; // Cardinal
|
||||
ushort NTServicePack; // Word
|
||||
}
|
||||
5
InnoWizardStyle.cs
Normal file
5
InnoWizardStyle.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace InnoPatcher;
|
||||
|
||||
internal enum InnoWizardStyle {
|
||||
Classic, Modern
|
||||
}
|
||||
5
InnoYesNoAuto.cs
Normal file
5
InnoYesNoAuto.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace InnoPatcher;
|
||||
|
||||
internal enum InnoYesNoAuto {
|
||||
Yes, No, Auto
|
||||
}
|
||||
@@ -6,7 +6,8 @@ class Program {
|
||||
InnoLoader loader = InnoLoader.FromPE(exe);
|
||||
Console.WriteLine($"Inno Loader {loader.Version}" + (loader.IsUnicode ? " (Unicode)" : ""));
|
||||
|
||||
loader.GetSetup();
|
||||
InnoSetup setup = loader.GetSetup();
|
||||
Console.WriteLine($"Inno Setup {setup.AppName} [{setup.AppVersion}] ({setup.AppId})");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user