using System; using System.IO; using System.Text; using SabreTools.Data.Models.WiseInstaller; using SabreTools.IO.Extensions; using SabreTools.Numerics.Extensions; #pragma warning disable IDE0017 // Simplify object initialization namespace SabreTools.Serialization.Readers { public class WiseOverlayHeader : BaseBinaryReader { /// public override OverlayHeader? Deserialize(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; try { // Cache the current offset long initialOffset = data.Position; var overlayHeader = ParseOverlayHeader(data); // DllName if (overlayHeader.DllName is not null && overlayHeader.DllName.IndexOfAny(Path.GetInvalidFileNameChars()) > 0) return null; // 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; } } /// /// Parse a Stream into an OverlayHeader /// /// Stream to parse /// Filled OverlayHeader on success, null on error private static OverlayHeader ParseOverlayHeader(Stream data) { var obj = new OverlayHeader(); obj.DllNameLen = data.ReadByteValue(); if (obj.DllNameLen > 0) { byte[] dllName = data.ReadBytes(obj.DllNameLen); obj.DllName = Encoding.ASCII.GetString(dllName); obj.DllSize = data.ReadUInt32LittleEndian(); } // Read as a single block obj.Flags = (OverlayHeaderFlags)data.ReadUInt32LittleEndian(); // Read as a single block obj.GraphicsData = data.ReadBytes(12); // Read as a single block obj.WiseScriptExitEventOffset = data.ReadUInt32LittleEndian(); obj.WiseScriptCancelEventOffset = data.ReadUInt32LittleEndian(); // Read as a single block 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(); // Newer installers read this and DibInflatedSize in the above block obj.DibDeflatedSize = data.ReadUInt32LittleEndian(); // Handle older overlay data if (obj.DibDeflatedSize > data.Length) { obj.DibDeflatedSize = 0; data.SeekIfPossible(-4, SeekOrigin.Current); return obj; } obj.DibInflatedSize = data.ReadUInt32LittleEndian(); // Peek at the next 2 bytes ushort peek = data.PeekUInt16LittleEndian(); // If the next value is a known Endianness if (Enum.IsDefined(typeof(Endianness), peek)) { obj.Endianness = (Endianness)data.ReadUInt16LittleEndian(); } else { // The first two values are part of the sizes block above obj.InstallScriptDeflatedSize = data.ReadUInt32LittleEndian(); obj.CharacterSet = (CharacterSet)data.ReadUInt32LittleEndian(); obj.Endianness = (Endianness)data.ReadUInt16LittleEndian(); } // Endianness and init text len are read in a single block obj.InitTextLen = data.ReadByteValue(); if (obj.InitTextLen > 0) { byte[] initText = data.ReadBytes(obj.InitTextLen); obj.InitText = Encoding.ASCII.GetString(initText); } return obj; } } }