diff --git a/BurnOutSharp.Builder/MSDOS.cs b/BurnOutSharp.Builder/MSDOS.cs index fd7d4be1..c615a7a2 100644 --- a/BurnOutSharp.Builder/MSDOS.cs +++ b/BurnOutSharp.Builder/MSDOS.cs @@ -79,7 +79,7 @@ namespace BurnOutSharp.Builder header.Magic = new char[2]; for (int i = 0; i < header.Magic.Length; i++) { - header.Magic[i] = (char)data[offset]; offset++; + header.Magic[i] = data.ReadChar(ref offset); } if (header.Magic[0] != 'M' || header.Magic[1] != 'Z') return null; diff --git a/BurnOutSharp.Builder/NewExecutable.cs b/BurnOutSharp.Builder/NewExecutable.cs index 0a0342a1..33826620 100644 --- a/BurnOutSharp.Builder/NewExecutable.cs +++ b/BurnOutSharp.Builder/NewExecutable.cs @@ -38,6 +38,14 @@ namespace BurnOutSharp.Builder // Set the MS-DOS stub executable.Stub = stub; + // Try to parse the executable header + var executableHeader = ParseExecutableHeader(data, offset); + if (executableHeader == null) + return null; + + // Set the executable header + executable.Header = executableHeader; + // TODO: Implement NE parsing return null; } @@ -50,8 +58,57 @@ namespace BurnOutSharp.Builder /// Filled executable header on success, null on error private static ExecutableHeader ParseExecutableHeader(byte[] data, int offset) { - // TODO: Implement NE header parsing - return null; + // If we don't have enough data + if (data.Length < 0x40) + return null; + + // If the offset means we don't have enough data + if (data.Length - offset < 0x40) + return null; + + // TODO: Use marshalling here instead of building + var header = new ExecutableHeader(); + + header.Magic = new char[2]; + for (int i = 0; i < header.Magic.Length; i++) + { + header.Magic[i] = data.ReadChar(ref offset); + } + if (header.Magic[0] != 'N' || header.Magic[1] != 'E') + return null; + + header.LinkerVersion = data.ReadByte(ref offset); + header.LinkerRevision = data.ReadByte(ref offset); + header.EntryTableOffset = data.ReadUInt16(ref offset); + header.EntryTableSize = data.ReadUInt16(ref offset); + header.CrcChecksum = data.ReadUInt32(ref offset); + header.FlagWord = (HeaderFlag)data.ReadUInt16(ref offset); + header.AutomaticDataSegmentNumber = data.ReadUInt16(ref offset); + header.InitialHeapAlloc = data.ReadUInt16(ref offset); + header.InitialStackAlloc = data.ReadUInt16(ref offset); + header.InitialCSIPSetting = data.ReadUInt32(ref offset); + header.InitialSSSPSetting = data.ReadUInt32(ref offset); + header.FileSegmentCount = data.ReadUInt16(ref offset); + header.ModuleReferenceTableSize = data.ReadUInt16(ref offset); + header.NonResidentNameTableSize = data.ReadUInt16(ref offset); + header.SegmentTableOffset = data.ReadUInt16(ref offset); + header.ResourceTableOffset = data.ReadUInt16(ref offset); + header.ResidentNameTableOffset = data.ReadUInt16(ref offset); + header.ModuleReferenceTableOffset = data.ReadUInt16(ref offset); + header.ImportedNamesTableOffset = data.ReadUInt16(ref offset); + header.NonResidentNamesTableOffset = data.ReadUInt32(ref offset); + header.MovableEntriesCount = data.ReadUInt16(ref offset); + header.SegmentAlignmentShiftCount = data.ReadUInt16(ref offset); + header.ResourceEntriesCount = data.ReadUInt16(ref offset); + header.TargetOperatingSystem = (OperatingSystem)data.ReadByte(ref offset); + header.AdditionalFlags = (OS2Flag)data.ReadByte(ref offset); + header.ReturnThunkOffset = data.ReadUInt16(ref offset); + header.SegmentReferenceThunkOffset = data.ReadUInt16(ref offset); + header.MinCodeSwapAreaSize = data.ReadUInt16(ref offset); + header.WindowsSDKRevision = data.ReadByte(ref offset); + header.WindowsSDKVersion = data.ReadByte(ref offset); + + return header; } #endregion @@ -87,6 +144,14 @@ namespace BurnOutSharp.Builder // Set the MS-DOS stub executable.Stub = stub; + // Try to parse the executable header + var executableHeader = ParseExecutableHeader(data); + if (executableHeader == null) + return null; + + // Set the executable header + executable.Header = executableHeader; + // TODO: Implement NE parsing return null; } @@ -98,8 +163,57 @@ namespace BurnOutSharp.Builder /// Filled executable header on success, null on error private static ExecutableHeader ParseExecutableHeader(Stream data) { - // TODO: Implement NE header parsing - return null; + // If we don't have enough data + if (data.Length < 0x40) + return null; + + // If the offset means we don't have enough data + if (data.Length - data.Position < 0x40) + return null; + + // TODO: Use marshalling here instead of building + var header = new ExecutableHeader(); + + header.Magic = new char[2]; + for (int i = 0; i < header.Magic.Length; i++) + { + header.Magic[i] = data.ReadChar(); + } + if (header.Magic[0] != 'N' || header.Magic[1] != 'E') + return null; + + header.LinkerVersion = data.ReadByteValue(); + header.LinkerRevision = data.ReadByteValue(); + header.EntryTableOffset = data.ReadUInt16(); + header.EntryTableSize = data.ReadUInt16(); + header.CrcChecksum = data.ReadUInt32(); + header.FlagWord = (HeaderFlag)data.ReadUInt16(); + header.AutomaticDataSegmentNumber = data.ReadUInt16(); + header.InitialHeapAlloc = data.ReadUInt16(); + header.InitialStackAlloc = data.ReadUInt16(); + header.InitialCSIPSetting = data.ReadUInt32(); + header.InitialSSSPSetting = data.ReadUInt32(); + header.FileSegmentCount = data.ReadUInt16(); + header.ModuleReferenceTableSize = data.ReadUInt16(); + header.NonResidentNameTableSize = data.ReadUInt16(); + header.SegmentTableOffset = data.ReadUInt16(); + header.ResourceTableOffset = data.ReadUInt16(); + header.ResidentNameTableOffset = data.ReadUInt16(); + header.ModuleReferenceTableOffset = data.ReadUInt16(); + header.ImportedNamesTableOffset = data.ReadUInt16(); + header.NonResidentNamesTableOffset = data.ReadUInt32(); + header.MovableEntriesCount = data.ReadUInt16(); + header.SegmentAlignmentShiftCount = data.ReadUInt16(); + header.ResourceEntriesCount = data.ReadUInt16(); + header.TargetOperatingSystem = (OperatingSystem)data.ReadByteValue(); + header.AdditionalFlags = (OS2Flag)data.ReadByteValue(); + header.ReturnThunkOffset = data.ReadUInt16(); + header.SegmentReferenceThunkOffset = data.ReadUInt16(); + header.MinCodeSwapAreaSize = data.ReadUInt16(); + header.WindowsSDKRevision = data.ReadByteValue(); + header.WindowsSDKVersion = data.ReadByteValue(); + + return header; } #endregion