Files
SabreTools.Serialization/SabreTools.Serialization.Readers/WiseOverlayHeader.cs

156 lines
6.0 KiB
C#
Raw Normal View History

2025-09-01 16:43:21 -04:00
using System;
using System.IO;
using System.Text;
2025-09-26 13:06:18 -04:00
using SabreTools.Data.Models.WiseInstaller;
2025-09-01 16:43:21 -04:00
using SabreTools.IO.Extensions;
2026-03-24 19:17:25 -04:00
using SabreTools.Numerics.Extensions;
2025-09-01 16:43:21 -04:00
2026-01-27 12:03:01 -05:00
#pragma warning disable IDE0017 // Simplify object initialization
2025-09-26 14:57:20 -04:00
namespace SabreTools.Serialization.Readers
2025-09-01 16:43:21 -04:00
{
public class WiseOverlayHeader : BaseBinaryReader<OverlayHeader>
2025-09-01 16:43:21 -04:00
{
/// <inheritdoc/>
public override OverlayHeader? Deserialize(Stream? data)
{
// If the data is invalid
2026-01-25 14:30:18 -05:00
if (data is null || !data.CanRead)
2025-09-01 16:43:21 -04:00
return null;
try
{
// Cache the current offset
long initialOffset = data.Position;
var overlayHeader = ParseOverlayHeader(data);
2025-09-01 21:11:54 -04:00
// DllName
2026-01-25 14:32:49 -05:00
if (overlayHeader.DllName is not null && overlayHeader.DllName.IndexOfAny(Path.GetInvalidFileNameChars()) > 0)
2025-09-01 21:11:54 -04:00
return null;
2025-09-01 16:43:21 -04:00
// WiseColors.dib
if (overlayHeader.DibDeflatedSize >= data.Length)
return null;
else if (overlayHeader.DibDeflatedSize > overlayHeader.DibInflatedSize)
return null;
// WiseScript.bin
if (overlayHeader.WiseScriptDeflatedSize == 0)
return null;
else if (overlayHeader.WiseScriptDeflatedSize >= data.Length)
return null;
else if (overlayHeader.WiseScriptDeflatedSize > overlayHeader.WiseScriptInflatedSize)
return null;
// WISE0001.DLL
if (overlayHeader.WiseDllDeflatedSize >= data.Length)
return null;
// FILE00XX.DAT
if (overlayHeader.FinalFileDeflatedSize == 0)
return null;
else if (overlayHeader.FinalFileDeflatedSize >= data.Length)
return null;
else if (overlayHeader.FinalFileDeflatedSize > overlayHeader.FinalFileInflatedSize)
return null;
// Valid for older overlay headers
if (overlayHeader.Endianness == 0x0000 && overlayHeader.InitTextLen == 0)
return overlayHeader;
if (overlayHeader.Endianness != Endianness.LittleEndian && overlayHeader.Endianness != Endianness.BigEndian)
return null;
return overlayHeader;
}
catch
{
// Ignore the actual error
return null;
}
}
/// <summary>
/// Parse a Stream into an OverlayHeader
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled OverlayHeader on success, null on error</returns>
private static OverlayHeader ParseOverlayHeader(Stream data)
{
2025-09-08 21:13:34 -04:00
var obj = new OverlayHeader();
2025-09-01 16:43:21 -04:00
2025-09-08 21:13:34 -04:00
obj.DllNameLen = data.ReadByteValue();
if (obj.DllNameLen > 0)
2025-09-01 16:43:21 -04:00
{
2025-09-08 21:13:34 -04:00
byte[] dllName = data.ReadBytes(obj.DllNameLen);
obj.DllName = Encoding.ASCII.GetString(dllName);
obj.DllSize = data.ReadUInt32LittleEndian();
2025-09-01 16:43:21 -04:00
}
// Read as a single block
2025-09-08 21:13:34 -04:00
obj.Flags = (OverlayHeaderFlags)data.ReadUInt32LittleEndian();
2025-09-01 16:43:21 -04:00
// Read as a single block
2025-09-08 21:13:34 -04:00
obj.GraphicsData = data.ReadBytes(12);
2025-09-01 16:43:21 -04:00
// Read as a single block
2025-09-08 21:13:34 -04:00
obj.WiseScriptExitEventOffset = data.ReadUInt32LittleEndian();
obj.WiseScriptCancelEventOffset = data.ReadUInt32LittleEndian();
2025-09-01 16:43:21 -04:00
// Read as a single block
2025-09-08 21:13:34 -04:00
obj.WiseScriptInflatedSize = data.ReadUInt32LittleEndian();
obj.WiseScriptDeflatedSize = data.ReadUInt32LittleEndian();
obj.WiseDllDeflatedSize = data.ReadUInt32LittleEndian();
obj.Ctl3d32DeflatedSize = data.ReadUInt32LittleEndian();
obj.SomeData4DeflatedSize = data.ReadUInt32LittleEndian();
obj.RegToolDeflatedSize = data.ReadUInt32LittleEndian();
obj.ProgressDllDeflatedSize = data.ReadUInt32LittleEndian();
obj.SomeData7DeflatedSize = data.ReadUInt32LittleEndian();
obj.SomeData8DeflatedSize = data.ReadUInt32LittleEndian();
obj.SomeData9DeflatedSize = data.ReadUInt32LittleEndian();
obj.SomeData10DeflatedSize = data.ReadUInt32LittleEndian();
obj.FinalFileDeflatedSize = data.ReadUInt32LittleEndian();
obj.FinalFileInflatedSize = data.ReadUInt32LittleEndian();
obj.EOF = data.ReadUInt32LittleEndian();
2025-09-01 16:43:21 -04:00
// Newer installers read this and DibInflatedSize in the above block
2025-09-08 21:13:34 -04:00
obj.DibDeflatedSize = data.ReadUInt32LittleEndian();
2025-09-01 16:43:21 -04:00
// Handle older overlay data
2025-09-08 21:13:34 -04:00
if (obj.DibDeflatedSize > data.Length)
2025-09-01 16:43:21 -04:00
{
2025-09-08 21:13:34 -04:00
obj.DibDeflatedSize = 0;
2025-10-27 22:43:56 -04:00
data.SeekIfPossible(-4, SeekOrigin.Current);
2025-09-08 21:13:34 -04:00
return obj;
2025-09-01 16:43:21 -04:00
}
2025-09-08 21:13:34 -04:00
obj.DibInflatedSize = data.ReadUInt32LittleEndian();
2025-09-01 16:43:21 -04:00
// Peek at the next 2 bytes
2025-10-27 22:55:25 -04:00
ushort peek = data.PeekUInt16LittleEndian();
2025-09-01 16:43:21 -04:00
// If the next value is a known Endianness
if (Enum.IsDefined(typeof(Endianness), peek))
{
2025-09-08 21:13:34 -04:00
obj.Endianness = (Endianness)data.ReadUInt16LittleEndian();
2025-09-01 16:43:21 -04:00
}
else
{
// The first two values are part of the sizes block above
2025-09-08 21:13:34 -04:00
obj.InstallScriptDeflatedSize = data.ReadUInt32LittleEndian();
obj.CharacterSet = (CharacterSet)data.ReadUInt32LittleEndian();
obj.Endianness = (Endianness)data.ReadUInt16LittleEndian();
2025-09-01 16:43:21 -04:00
}
// Endianness and init text len are read in a single block
2025-09-08 21:13:34 -04:00
obj.InitTextLen = data.ReadByteValue();
if (obj.InitTextLen > 0)
2025-09-01 16:43:21 -04:00
{
2025-09-08 21:13:34 -04:00
byte[] initText = data.ReadBytes(obj.InitTextLen);
obj.InitText = Encoding.ASCII.GetString(initText);
2025-09-01 16:43:21 -04:00
}
2025-09-08 21:13:34 -04:00
return obj;
2025-09-01 16:43:21 -04:00
}
}
}