void Initialize() { Recognized = false; if (BaseStream == null) { return; } baseExecutable = new MZ(BaseStream); if (!baseExecutable.Recognized) { return; } if (baseExecutable.Header.new_offset >= BaseStream.Length) { return; } BaseStream.Seek(baseExecutable.Header.new_offset, SeekOrigin.Begin); byte[] buffer = new byte[Marshal.SizeOf(typeof(PEHeader))]; BaseStream.Read(buffer, 0, buffer.Length); IntPtr hdrPtr = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, hdrPtr, buffer.Length); header = (PEHeader)Marshal.PtrToStructure(hdrPtr, typeof(PEHeader)); Marshal.FreeHGlobal(hdrPtr); Recognized = header.signature == SIGNATURE; if (!Recognized) { return; } Type = "Portable Executable (PE)"; if (header.coff.optionalHeader.magic == PE32Plus) { BaseStream.Position -= 4; buffer = new byte[Marshal.SizeOf(typeof(WindowsHeader64))]; BaseStream.Read(buffer, 0, buffer.Length); hdrPtr = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, hdrPtr, buffer.Length); winHeader = (WindowsHeader64)Marshal.PtrToStructure(hdrPtr, typeof(WindowsHeader64)); Marshal.FreeHGlobal(hdrPtr); } else { buffer = new byte[Marshal.SizeOf(typeof(WindowsHeader))]; BaseStream.Read(buffer, 0, buffer.Length); hdrPtr = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, hdrPtr, buffer.Length); WindowsHeader hdr32 = (WindowsHeader)Marshal.PtrToStructure(hdrPtr, typeof(WindowsHeader)); Marshal.FreeHGlobal(hdrPtr); winHeader = ToPlus(hdr32); } OperatingSystem reqOs = new OperatingSystem(); switch (winHeader.subsystem) { case Subsystems.IMAGE_SUBSYSTEM_UNKNOWN: reqOs.Name = "Unknown"; break; case Subsystems.IMAGE_SUBSYSTEM_NATIVE: reqOs.Name = "Windows NT"; reqOs.Subsystem = "Native"; break; case Subsystems.IMAGE_SUBSYSTEM_WINDOWS_GUI: reqOs.Name = winHeader.majorSubsystemVersion <= 3 ? "Windows NT" : "Windows"; reqOs.Subsystem = "GUI"; break; case Subsystems.IMAGE_SUBSYSTEM_WINDOWS_CUI: reqOs.Name = winHeader.majorSubsystemVersion <= 3 ? "Windows NT" : "Windows"; reqOs.Subsystem = "Console"; break; case Subsystems.IMAGE_SUBSYSTEM_OS2_CUI: reqOs.Name = "Windows NT"; reqOs.Subsystem = "OS/2"; break; case Subsystems.IMAGE_SUBSYSTEM_POSIX_CUI: reqOs.Name = "Windows NT"; reqOs.Subsystem = "POSIX"; break; case Subsystems.IMAGE_SUBSYSTEM_NATIVE_WINDOWS: reqOs.Name = "Windows"; reqOs.Subsystem = "Native"; break; case Subsystems.IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: reqOs.Name = "Windows CE"; break; case Subsystems.IMAGE_SUBSYSTEM_EFI_APPLICATION: case Subsystems.IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: case Subsystems.IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: case Subsystems.IMAGE_SUBSYSTEM_EFI_ROM: reqOs.Name = "EFI"; break; case Subsystems.IMAGE_SUBSYSTEM_XBOX: reqOs.Name = "Xbox OS"; break; case Subsystems.IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: reqOs.Name = "Windows NT"; reqOs.Subsystem = "Boot environment"; break; default: reqOs.Name = $"Unknown code ${(ushort)winHeader.subsystem}"; break; } reqOs.MajorVersion = winHeader.majorSubsystemVersion; reqOs.MinorVersion = winHeader.minorSubsystemVersion; RequiredOperatingSystem = reqOs; buffer = new byte[Marshal.SizeOf(typeof(ImageDataDirectory))]; directoryEntries = new ImageDataDirectory[winHeader.numberOfRvaAndSizes]; for (int i = 0; i < directoryEntries.Length; i++) { BaseStream.Read(buffer, 0, buffer.Length); directoryEntries[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <ImageDataDirectory>(buffer); } buffer = new byte[Marshal.SizeOf(typeof(COFF.SectionHeader))]; sectionHeaders = new COFF.SectionHeader[header.coff.numberOfSections]; for (int i = 0; i < sectionHeaders.Length; i++) { BaseStream.Read(buffer, 0, buffer.Length); sectionHeaders[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <COFF.SectionHeader>(buffer); } Dictionary <string, COFF.SectionHeader> newSectionHeaders = sectionHeaders.ToDictionary(section => section.name); for (int i = 0; i < directoryEntries.Length; i++) { string tableName; switch (i) { case 0: tableName = ".edata"; break; case 1: tableName = ".idata"; break; case 2: tableName = ".rsrc"; break; case 3: tableName = ".pdata"; break; case 5: tableName = ".reloc"; break; case 6: tableName = ".debug"; break; case 9: tableName = ".tls"; break; case 14: tableName = ".cormeta"; break; default: continue; } if (newSectionHeaders.ContainsKey(tableName)) { continue; } if (directoryEntries[i].rva == 0) { continue; } newSectionHeaders.Add(tableName, new COFF.SectionHeader { characteristics = COFF.SectionFlags.IMAGE_SCN_CNT_INITIALIZED_DATA | COFF.SectionFlags.IMAGE_SCN_MEM_READ, name = tableName, pointerToRawData = RvaToReal(directoryEntries[i].rva, sectionHeaders), virtualAddress = directoryEntries[i].rva, sizeOfRawData = directoryEntries[i].size, virtualSize = directoryEntries[i].size }); } List <byte> chars; List <string> strings = new List <string>(); if (newSectionHeaders.TryGetValue(".edata", out COFF.SectionHeader edata)) { buffer = new byte[Marshal.SizeOf(typeof(ExportDirectoryTable))]; BaseStream.Position = edata.pointerToRawData; BaseStream.Read(buffer, 0, buffer.Length); ExportDirectoryTable edataTable = BigEndianMarshal.ByteArrayToStructureLittleEndian <ExportDirectoryTable>(buffer); BaseStream.Position = RvaToReal(edataTable.nameRva, sectionHeaders); chars = new List <byte>(); while (true) { int ch = BaseStream.ReadByte(); if (ch <= 0) { break; } chars.Add((byte)ch); } moduleName = Encoding.ASCII.GetString(chars.ToArray()); uint[] namePointers = new uint[edataTable.numberOfNamePointers]; exportedNames = new string[edataTable.numberOfNamePointers]; buffer = new byte[Marshal.SizeOf(typeof(uint)) * edataTable.numberOfNamePointers]; BaseStream.Position = RvaToReal(edataTable.namePointerRva, sectionHeaders); BaseStream.Read(buffer, 0, buffer.Length); for (int i = 0; i < edataTable.numberOfNamePointers; i++) { namePointers[i] = BitConverter.ToUInt32(buffer, i * 4); BaseStream.Position = RvaToReal(namePointers[i], sectionHeaders); chars = new List <byte>(); while (true) { int ch = BaseStream.ReadByte(); if (ch <= 0) { break; } chars.Add((byte)ch); } exportedNames[i] = Encoding.ASCII.GetString(chars.ToArray()); } } if (newSectionHeaders.TryGetValue(".idata", out COFF.SectionHeader idata)) { buffer = new byte[Marshal.SizeOf(typeof(ImportDirectoryTable))]; BaseStream.Position = idata.pointerToRawData; List <ImportDirectoryTable> importDirectoryEntries = new List <ImportDirectoryTable>(); while (true) { BaseStream.Read(buffer, 0, buffer.Length); if (buffer.All(b => b == 0)) { break; } importDirectoryEntries.Add(BigEndianMarshal .ByteArrayToStructureLittleEndian <ImportDirectoryTable>(buffer)); } importedNames = new string[importDirectoryEntries.Count]; for (int i = 0; i < importDirectoryEntries.Count; i++) { BaseStream.Position = RvaToReal(importDirectoryEntries[i].nameRva, sectionHeaders); chars = new List <byte>(); while (true) { int ch = BaseStream.ReadByte(); if (ch <= 0) { break; } chars.Add((byte)ch); } importedNames[i] = Encoding.ASCII.GetString(chars.ToArray()); // BeOS R3 uses PE with no subsystem if (importedNames[i].ToLower() == "libbe.so") { reqOs.MajorVersion = 3; reqOs.MinorVersion = 0; reqOs.Subsystem = null; reqOs.Name = "BeOS"; RequiredOperatingSystem = reqOs; } // Singularity appears as a native NT executable else if (importedNames[i].ToLower() == "singularity.v1.dll") { reqOs.MajorVersion = 1; reqOs.MinorVersion = 0; reqOs.Subsystem = null; reqOs.Name = "Singularity"; RequiredOperatingSystem = reqOs; } } } if (newSectionHeaders.TryGetValue(".debug", out COFF.SectionHeader debug) && debug.virtualAddress > 0) { buffer = new byte[Marshal.SizeOf(typeof(DebugDirectory))]; BaseStream.Position = debug.pointerToRawData; BaseStream.Read(buffer, 0, buffer.Length); debugDirectory = BigEndianMarshal.ByteArrayToStructureLittleEndian <DebugDirectory>(buffer); } if (newSectionHeaders.TryGetValue(".rsrc", out COFF.SectionHeader rsrc)) { if (reqOs.Name == "BeOS") { newSectionHeaders.Remove(".rsrc"); rsrc.pointerToRawData = rsrc.virtualAddress; long maxPosition = BaseStream.Length; foreach (KeyValuePair <string, COFF.SectionHeader> kvp in newSectionHeaders) { if (kvp.Value.pointerToRawData <= maxPosition && kvp.Value.pointerToRawData > rsrc.pointerToRawData) { maxPosition = kvp.Value.pointerToRawData; } } rsrc.sizeOfRawData = (uint)(maxPosition - rsrc.pointerToRawData); rsrc.virtualSize = rsrc.sizeOfRawData; newSectionHeaders.Add(".rsrc", rsrc); buffer = new byte[rsrc.sizeOfRawData]; BaseStream.Position = rsrc.pointerToRawData; BaseStream.Read(buffer, 0, buffer.Length); BeosResources = Resources.Decode(buffer); strings.AddRange(from type in BeosResources where type.type == Consts.B_VERSION_INFO_TYPE from resource in type.resources select BigEndianMarshal .ByteArrayToStructureLittleEndian <VersionInfo>(resource.data) into versionInfo select StringHandlers.CToString(versionInfo.long_info, Encoding.UTF8)); } else { WindowsResourcesRoot = GetResourceNode(BaseStream, rsrc.pointerToRawData, rsrc.virtualAddress, rsrc.pointerToRawData, 0, null, 0); Versions = GetVersions().ToArray(); strings.AddRange(from v in Versions from s in v.StringsByLanguage from k in s.Value select k.Value); foreach (ResourceNode rtype in WindowsResourcesRoot.children.Where(r => r.name == "RT_STRING")) { strings.AddRange(GetStrings(rtype)); } } } sectionHeaders = newSectionHeaders.Values.OrderBy(s => s.pointerToRawData).ToArray(); Segment[] segments = new Segment[sectionHeaders.Length]; for (int i = 0; i < segments.Length; i++) { segments[i] = new Segment { Flags = $"{sectionHeaders[i].characteristics}", Name = sectionHeaders[i].name, Offset = sectionHeaders[i].pointerToRawData, Size = sectionHeaders[i].sizeOfRawData } } ; Segments = segments; strings.Sort(); Strings = strings; }
void Initialize() { Recognized = false; if (BaseStream == null) { return; } byte[] buffer = new byte[Marshal.SizeOf(typeof(AtariHeader))]; BaseStream.Position = 0; BaseStream.Read(buffer, 0, buffer.Length); Header = BigEndianMarshal.ByteArrayToStructureBigEndian <AtariHeader>(buffer); Recognized = Header.signature == SIGNATURE; List <string> strings = new List <string>(); if (!Recognized) { return; } Type = "Atari ST executable"; if (Header.symb_len != 0) { BaseStream.Position = 0x1C + Header.text_len + Header.data_len; buffer = new byte[Marshal.SizeOf(typeof(SymbolEntry))]; symbols = new SymbolEntry[Header.symb_len / Marshal.SizeOf(typeof(SymbolEntry))]; for (int i = 0; i < symbols.Length; i++) { BaseStream.Read(buffer, 0, buffer.Length); symbols[i] = new SymbolEntry(); symbols[i] = BigEndianMarshal.ByteArrayToStructureBigEndian <SymbolEntry>(buffer); symbols[i].type = (SymbolType)Swapping.Swap((ushort)symbols[i].type); strings.Add(StringHandlers.CToString(symbols[i].name, Encoding.AtariSTEncoding)); } } Segments = new [] { new Segment { Name = ".text", Flags = $"{(PrgFlags)(Header.flags & 0xFFCF)} {(PrgSharing)(Header.flags & PF_SHARE_MASK)}", Offset = 0x1C, Size = Header.text_len }, new Segment { Name = ".data", Flags = "", Offset = 0x1C + Header.text_len, Size = Header.data_len }, new Segment { Name = ".bss", Flags = "", Offset = 0, Size = Header.bss_len } }; RequiredOperatingSystem = new OperatingSystem { Name = Header.mint == MINT_SIGNATURE ? "MiNT" : "Atari TOS" }; if (ResourceStream == null) { return; } buffer = new byte[Marshal.SizeOf(typeof(GEM.GemResourceHeader))]; ResourceStream.Position = 0; ResourceStream.Read(buffer, 0, buffer.Length); GEM.GemResourceHeader gemResourceHeader = BigEndianMarshal.ByteArrayToStructureBigEndian <GEM.GemResourceHeader>(buffer); if (gemResourceHeader.rsh_vrsn != 0 && gemResourceHeader.rsh_vrsn != 1 && gemResourceHeader.rsh_vrsn != 3 && gemResourceHeader.rsh_vrsn != 4 && gemResourceHeader.rsh_vrsn != 5) { return; } if (gemResourceHeader.rsh_vrsn == 3) { buffer = new byte[Marshal.SizeOf(typeof(GEM.MagiCResourceHeader))]; ResourceStream.Position = 0; ResourceStream.Read(buffer, 0, buffer.Length); ResourceHeader = BigEndianMarshal.ByteArrayToStructureBigEndian <GEM.MagiCResourceHeader>(buffer); RequiredOperatingSystem = new OperatingSystem { Name = "MagiC" }; } else { ResourceHeader = GEM.GemToMagiC(gemResourceHeader); } if ((ResourceHeader.rsh_vrsn & 4) == 4) { buffer = new byte[Marshal.SizeOf(typeof(GEM.GemResourceExtension))]; ResourceStream.Position = ResourceHeader.rsh_rssize; ResourceStream.Read(buffer, 0, buffer.Length); ResourceExtension = BigEndianMarshal.ByteArrayToStructureBigEndian <GEM.GemResourceExtension>(buffer); GemColorIcons = GEM.GetColorIcons(ResourceStream, ResourceExtension.color_ic, true, Encoding.AtariSTEncoding); } if (ResourceHeader.rsh_ntree > 0) { ResourceStream.Position = ResourceHeader.rsh_trindex; int[] treeOffsets = new int[ResourceHeader.rsh_ntree]; byte[] tmp = new byte[4]; for (int i = 0; i < ResourceHeader.rsh_ntree; i++) { ResourceStream.Read(tmp, 0, 4); treeOffsets[i] = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0); } ResourceObjectRoots = new GEM.TreeObjectNode[ResourceHeader.rsh_ntree]; for (int i = 0; i < ResourceHeader.rsh_ntree; i++) { if (treeOffsets[i] <= 0 || treeOffsets[i] >= ResourceStream.Length) { continue; } ResourceStream.Position = treeOffsets[i]; List <GEM.ObjectNode> nodes = new List <GEM.ObjectNode>(); while (true) { buffer = new byte[Marshal.SizeOf(typeof(GEM.ObjectNode))]; ResourceStream.Read(buffer, 0, buffer.Length); GEM.ObjectNode node = BigEndianMarshal.ByteArrayToStructureBigEndian <GEM.ObjectNode>(buffer); nodes.Add(node); if (((GEM.ObjectFlags)node.ob_flags).HasFlag(GEM.ObjectFlags.Lastob)) { break; } } List <short> knownNodes = new List <short>(); ResourceObjectRoots[i] = GEM.ProcessResourceObject(nodes, ref knownNodes, 0, ResourceStream, strings, true, Encoding.AtariSTEncoding); } } else if (ResourceHeader.rsh_nobs > 0) { GEM.ObjectNode[] nodes = new GEM.ObjectNode[ResourceHeader.rsh_nobs]; ResourceStream.Position = ResourceHeader.rsh_object; for (short i = 0; i < ResourceHeader.rsh_nobs; i++) { buffer = new byte[Marshal.SizeOf(typeof(GEM.ObjectNode))]; ResourceStream.Read(buffer, 0, buffer.Length); nodes[i] = BigEndianMarshal.ByteArrayToStructureBigEndian <GEM.ObjectNode>(buffer); } List <short> knownNodes = new List <short>(); ResourceObjectRoots = new GEM.TreeObjectNode[1]; ResourceObjectRoots[0] = GEM.ProcessResourceObject(nodes, ref knownNodes, 0, ResourceStream, strings, true, Encoding.AtariSTEncoding); } if (strings.Count > 0) { strings.Sort(); Strings = strings.Distinct(); } }
// TODO: How to know VxD structure offset void Initialize() { Recognized = false; if (BaseStream == null) { return; } BaseExecutable = new MZ(BaseStream); if (!BaseExecutable.Recognized) { return; } if (BaseExecutable.Header.new_offset >= BaseStream.Length) { return; } BaseStream.Seek(BaseExecutable.Header.new_offset, SeekOrigin.Begin); byte[] buffer = new byte[Marshal.SizeOf(typeof(LXHeader))]; BaseStream.Read(buffer, 0, buffer.Length); IntPtr hdrPtr = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, hdrPtr, buffer.Length); Header = (LXHeader)Marshal.PtrToStructure(hdrPtr, typeof(LXHeader)); Marshal.FreeHGlobal(hdrPtr); Recognized = Header.signature == SIGNATURE || Header.signature == SIGNATURE16; if (!Recognized) { return; } Type = Header.signature == SIGNATURE16 ? "Linear Executable (LE)" : "Linear eXecutable (LX)"; IsBigEndian = Header.byte_order == 1 || Header.word_order == 1; List <string> strings = new List <string>(); OperatingSystem reqOs = new OperatingSystem(); switch (Header.os_type) { case TargetOS.OS2: reqOs.Name = "OS/2"; if (Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && !Header.module_flags.HasFlag(ModuleFlags.PMCompatible) || !Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) { reqOs.Subsystem = "Console"; } else if (Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) { reqOs.Subsystem = "Presentation Manager"; } break; case TargetOS.Windows: case TargetOS.Win32: case TargetOS.Unknown: reqOs.Name = "Windows"; break; case TargetOS.DOS: reqOs.Name = "Windows"; break; default: reqOs.Name = $"Unknown code {(ushort)Header.os_type}"; break; } RequiredOperatingSystem = reqOs; if (Header.resident_names_off != 0) { ResidentNames = GetResidentStrings(BaseStream, BaseExecutable.Header.new_offset, Header.resident_names_off); if (ResidentNames.Length >= 1) { ModuleName = ResidentNames[0].name; if (ResidentNames.Length > 1) { NE.ResidentName[] newResidentNames = new NE.ResidentName[ResidentNames.Length - 1]; Array.Copy(ResidentNames, 1, newResidentNames, 0, ResidentNames.Length - 1); ResidentNames = newResidentNames; } else { ResidentNames = null; } } } if (Header.nonresident_name_table_len > 0) { NonResidentNames = GetResidentStrings(BaseStream, 0, Header.nonresident_name_table_off); if (NonResidentNames.Length >= 1) { ModuleDescription = NonResidentNames[0].name; if (NonResidentNames.Length > 1) { NE.ResidentName[] newNonResidentNames = new NE.ResidentName[NonResidentNames.Length - 1]; Array.Copy(NonResidentNames, 1, newNonResidentNames, 0, NonResidentNames.Length - 1); NonResidentNames = newNonResidentNames; } else { NonResidentNames = null; } } } if (Header.import_module_table_off != 0 && Header.import_module_entries > 0) { BaseStream.Position = Header.import_module_table_off + BaseExecutable.Header.new_offset; ImportedNames = new string[Header.import_module_entries]; for (int i = 0; i < Header.import_module_entries; i++) { int len = BaseStream.ReadByte(); buffer = new byte[len]; BaseStream.Read(buffer, 0, len); ImportedNames[i] = Encoding.ASCII.GetString(buffer); } } if (!string.IsNullOrEmpty(ModuleName)) { strings.Add(ModuleName); } if (!string.IsNullOrEmpty(ModuleDescription)) { strings.Add(ModuleDescription); } objectTableEntries = new ObjectTableEntry[Header.obj_no]; objectPageTableEntries = new ObjectPageTableEntry[Header.module_pages_no]; BaseStream.Position = Header.obj_table_off + BaseExecutable.Header.new_offset; buffer = new byte[Marshal.SizeOf(typeof(ObjectTableEntry))]; for (int i = 0; i < Header.obj_no; i++) { BaseStream.Read(buffer, 0, buffer.Length); objectTableEntries[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <ObjectTableEntry>(buffer); } BaseStream.Position = Header.obj_page_table_off + BaseExecutable.Header.new_offset; if (Header.signature == SIGNATURE16) { buffer = new byte[Marshal.SizeOf(typeof(ObjectPageTableEntry16))]; for (int i = 0; i < Header.module_pages_no; i++) { BaseStream.Read(buffer, 0, buffer.Length); ObjectPageTableEntry16 page16 = BigEndianMarshal.ByteArrayToStructureLittleEndian <ObjectPageTableEntry16>(buffer); int pageNo = (page16.High << 8) + page16.Low; objectPageTableEntries[i] = new ObjectPageTableEntry { DataSize = (ushort)Header.page_size, Flags = (PageTableAttributes)page16.Flags, PageDataOffset = (uint)((pageNo - 1) * Header.page_size) }; } } else { buffer = new byte[Marshal.SizeOf(typeof(ObjectPageTableEntry))]; for (int i = 0; i < Header.module_pages_no; i++) { BaseStream.Read(buffer, 0, buffer.Length); objectPageTableEntries[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <ObjectPageTableEntry>(buffer); } } int debugSections = 0; int winrsrcSections = 0; if (Header.debug_info_len > 0) { debugSections = 1; } if (Header.win_res_len > 0) { winrsrcSections = 1; } Segment[] sections = new Segment[objectTableEntries.Length + debugSections + winrsrcSections]; for (int i = 0; i < objectTableEntries.Length; i++) { sections[i] = new Segment { Flags = $"{objectTableEntries[i].ObjectFlags}" }; if (objectTableEntries[i].ObjectFlags.HasFlag(ObjectFlags.Resource)) { sections[i].Name = ".rsrc"; } else if (objectTableEntries[i].ObjectFlags.HasFlag(ObjectFlags.Executable)) { sections[i].Name = ".text"; } else if (!objectTableEntries[i].ObjectFlags.HasFlag(ObjectFlags.Writable)) { sections[i].Name = ".rodata"; } else if (StringHandlers.CToString(objectTableEntries[i].Name).ToLower() == "bss") { sections[i].Name = ".bss"; } else if (!string.IsNullOrWhiteSpace(StringHandlers.CToString(objectTableEntries[i].Name).Trim())) { sections[i].Name = StringHandlers.CToString(objectTableEntries[i].Name).Trim(); } else { sections[i].Name = ".data"; } if (objectTableEntries[i].PageTableEntries == 0 || objectTableEntries[i].PageTableIndex > objectPageTableEntries.Length) { sections[i].Size = objectTableEntries[i].VirtualSize; continue; } int shift = (int)(Header.signature == SIGNATURE16 ? 0 : Header.page_off_shift); if (objectPageTableEntries[objectTableEntries[i].PageTableIndex - 1] .Flags.HasFlag(PageTableAttributes.IteratedDataPage)) { sections[i].Offset = (objectPageTableEntries[objectTableEntries[i].PageTableIndex - 1].PageDataOffset << shift) + Header.obj_iter_pages_off; } else if (objectPageTableEntries[objectTableEntries[i].PageTableIndex - 1] .Flags.HasFlag(PageTableAttributes.LegalPhysicalPage)) { sections[i].Offset = (objectPageTableEntries[objectTableEntries[i].PageTableIndex - 1].PageDataOffset << shift) + Header.data_pages_off; } else { sections[i].Offset = 0; } sections[i].Size = 0; for (int j = 0; j < objectTableEntries[i].PageTableEntries; j++) { sections[i].Size += objectPageTableEntries[j + objectTableEntries[i].PageTableIndex - 1].DataSize; } if (sections[i].Offset + sections[i].Size > BaseStream.Length) { sections[i].Size = BaseStream.Length - sections[i].Offset; } } if (winrsrcSections > 0) { sections[sections.Length - debugSections - winrsrcSections] = new Segment { Name = ".rsrc", Size = Header.win_res_len, Offset = Header.win_res_off } } ; if (debugSections > 0) { sections[sections.Length - debugSections] = new Segment { Name = ".debug", Size = Header.debug_info_len, Offset = Header.debug_info_off } } ; // It only contains a RT_VERSION resource prefixed by some 12-byte header I can't find information about, so let's just skip it. if (winrsrcSections > 0) { buffer = new byte[Header.win_res_len]; BaseStream.Position = Header.win_res_off + 12; BaseStream.Read(buffer, 0, buffer.Length); WinVersion = new NE.Version(buffer); strings.AddRange(from s in WinVersion.StringsByLanguage from k in s.Value select k.Value); } resources = new ResourceTableEntry[Header.resource_entries]; BaseStream.Position = Header.resource_table_off + BaseExecutable.Header.new_offset; buffer = new byte[Marshal.SizeOf(typeof(ResourceTableEntry))]; for (int i = 0; i < resources.Length; i++) { BaseStream.Read(buffer, 0, buffer.Length); resources[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <ResourceTableEntry>(buffer); } SortedDictionary <ResourceTypes, List <NE.Resource> > os2Resources = new SortedDictionary <ResourceTypes, List <NE.Resource> >(); for (int i = 0; i < resources.Length; i++) { os2Resources.TryGetValue(resources[i].type, out List <NE.Resource> thisResourceType); if (thisResourceType == null) { thisResourceType = new List <NE.Resource>(); } NE.Resource thisResource = new NE.Resource { id = resources[i].id, name = $"{resources[i].id}", flags = 0, dataOffset = (uint)(sections[resources[i].obj_no - 1].Offset + resources[i].offset), length = resources[i].size }; thisResource.data = new byte[thisResource.length]; BaseStream.Position = thisResource.dataOffset; BaseStream.Read(thisResource.data, 0, thisResource.data.Length); thisResourceType.Add(thisResource); os2Resources.Remove(resources[i].type); os2Resources.Add(resources[i].type, thisResourceType); } if (os2Resources.Count > 0) { neFormatResourceTable = new NE.ResourceTable(); int counter = 0; neFormatResourceTable.types = new NE.ResourceType[os2Resources.Count]; foreach (KeyValuePair <ResourceTypes, List <NE.Resource> > kvp in os2Resources) { neFormatResourceTable.types[counter].count = (ushort)kvp.Value.Count; neFormatResourceTable.types[counter].id = (ushort)kvp.Key; neFormatResourceTable.types[counter].name = Resources.IdToName((ushort)kvp.Key); neFormatResourceTable.types[counter].resources = kvp.Value.OrderBy(r => r.id).ToArray(); counter++; } foreach (NE.ResourceType rtype in neFormatResourceTable.types) { if (rtype.name != "RT_STRING") { continue; } strings.AddRange(NE.GetOs2Strings(rtype)); } } Segments = sections; Strings = strings; }
void Initialize() { Recognized = false; if (BaseStream == null) { return; } BaseStream.Seek(0, SeekOrigin.Begin); byte[] buffer = new byte[Marshal.SizeOf(typeof(GeodeHeaderV2))]; BaseStream.Read(buffer, 0, buffer.Length); header = BigEndianMarshal.ByteArrayToStructureLittleEndian <GeodeHeader>(buffer); header2 = BigEndianMarshal.ByteArrayToStructureLittleEndian <GeodeHeaderV2>(buffer); Recognized = header.magic == GEOS_ID && header.type == FileType.GFT_EXECUTABLE || header2.magic == GEOS2_ID && header2.type == FileType2.GFT_EXECUTABLE; if (!Recognized) { return; } isNewHeader = header2.magic == GEOS2_ID; RequiredOperatingSystem = new OperatingSystem { Name = "GEOS", MajorVersion = isNewHeader ? 2 : 1 }; List <string> strings = new List <string> { StringHandlers.CToString(isNewHeader ? header2.name : header.name, geosEncoding), StringHandlers.CToString(isNewHeader ? header2.copyright : header.copyright, geosEncoding), StringHandlers.CToString(isNewHeader ? header2.info : header.info, geosEncoding) }; uint segmentBase = 0; if (isNewHeader) { BaseStream.Position = Marshal.SizeOf(typeof(GeodeHeaderV2)); buffer = new byte[Marshal.SizeOf(typeof(ApplicationHeaderV2))]; segmentBase = (uint)Marshal.SizeOf(typeof(GeodeHeaderV2)); BaseStream.Read(buffer, 0, buffer.Length); applicationHeader2 = BigEndianMarshal.ByteArrayToStructureLittleEndian <ApplicationHeaderV2>(buffer); imports = new Import[applicationHeader2.imports]; exports = new Export[applicationHeader2.exports]; segments = new SegmentDescriptor[applicationHeader2.segments]; strings.Add($"{StringHandlers.CToString(applicationHeader2.name, geosEncoding).Trim()}.{StringHandlers.CToString(applicationHeader2.extension, geosEncoding).Trim()}"); } else { BaseStream.Position = Marshal.SizeOf(typeof(GeodeHeader)); buffer = new byte[Marshal.SizeOf(typeof(ApplicationHeader))]; BaseStream.Read(buffer, 0, buffer.Length); applicationHeader = BigEndianMarshal.ByteArrayToStructureLittleEndian <ApplicationHeader>(buffer); imports = new Import[applicationHeader.imports]; exports = new Export[applicationHeader.exports]; segments = new SegmentDescriptor[applicationHeader.segments]; strings.Add($"{StringHandlers.CToString(applicationHeader.name, geosEncoding).Trim()}.{StringHandlers.CToString(applicationHeader.extension, geosEncoding).Trim()}"); } buffer = new byte[Marshal.SizeOf(typeof(Import))]; for (int i = 0; i < imports.Length; i++) { BaseStream.Read(buffer, 0, buffer.Length); imports[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <Import>(buffer); strings.Add(StringHandlers.CToString(imports[i].name, geosEncoding).Trim()); } buffer = new byte[Marshal.SizeOf(typeof(Export))]; for (int i = 0; i < exports.Length; i++) { BaseStream.Read(buffer, 0, buffer.Length); exports[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <Export>(buffer); } if (segments.Length > 0) { buffer = new byte[Marshal.SizeOf(typeof(SegmentDescriptor)) * segments.Length]; BaseStream.Read(buffer, 0, buffer.Length); Segment[] mySegments = new Segment[segments.Length]; for (int i = 0; i < segments.Length; i++) { segments[i].length = BitConverter.ToUInt16(buffer, 2 * i); segments[i].offset = BitConverter.ToUInt32(buffer, 2 * segments.Length + 4 * i) + segmentBase; segments[i].relocs_length = BitConverter.ToUInt16(buffer, 6 * segments.Length + 2 * i); segments[i].flags = (SegmentFlags)BitConverter.ToUInt16(buffer, 8 * segments.Length + 2 * i); mySegments[i] = new Segment { Flags = $"{segments[i].flags}", Offset = segments[i].offset, Size = segments[i].length }; if (i == 1) { mySegments[i].Name = ".idata"; } else if (segments[i].flags.HasFlag(SegmentFlags.HAF_CODE)) { mySegments[i].Name = ".text"; } else if (segments[i].flags.HasFlag(SegmentFlags.HAF_OBJECT_RESOURCE)) { mySegments[i].Name = ".rsrc"; } else if (segments[i].flags.HasFlag(SegmentFlags.HAF_ZERO_INIT)) { mySegments[i].Name = ".bss"; } else if (segments[i].flags.HasFlag(SegmentFlags.HAF_READ_ONLY)) { mySegments[i].Name = ".rodata"; } else { mySegments[i].Name = ".data"; } } Segments = mySegments; } strings.Remove(""); strings.Remove(null); Strings = strings; }
internal static TreeObjectNode ProcessResourceObject(IList <ObjectNode> nodes, ref List <short> knownNodes, short nodeNumber, Stream resourceStream, List <string> strings, bool bigEndian, Encoding encoding) { TreeObjectNode node = new TreeObjectNode { type = (ObjectTypes)(nodes[nodeNumber].ob_type & 0xff), flags = (ObjectFlags)nodes[nodeNumber].ob_flags, state = (ObjectStates)nodes[nodeNumber].ob_state, data = nodes[nodeNumber].ob_spec, x = nodes[nodeNumber].ob_x, y = nodes[nodeNumber].ob_y, width = nodes[nodeNumber].ob_width, height = nodes[nodeNumber].ob_height }; byte[] buffer; switch (node.type) { case ObjectTypes.G_TEXT: case ObjectTypes.G_BOXTEXT: case ObjectTypes.G_FTEXT: case ObjectTypes.G_FBOXTEXT: if (node.data <= 0 || node.data >= resourceStream.Length) { break; } resourceStream.Position = node.data; buffer = new byte[Marshal.SizeOf(typeof(TedInfo))]; resourceStream.Read(buffer, 0, buffer.Length); TedInfo ted = bigEndian ? BigEndianMarshal.ByteArrayToStructureBigEndian <TedInfo>(buffer) : BigEndianMarshal.ByteArrayToStructureLittleEndian <TedInfo>(buffer); node.TedInfo = new TextBlock { Font = (ObjectFont)ted.te_font, Justification = (ObjectJustification)ted.te_just, BorderColor = (ObjectColors)((ted.te_color & BorderColorMask) >> 12), TextColor = (ObjectColors)((ted.te_color & TextColorMask) >> 8), Transparency = (ted.te_color & TransparentColor) != TransparentColor, Fill = (ObjectFillPattern)((ted.te_color & FillPatternMask) >> 4), InsideColor = (ObjectColors)(ted.te_color & InsideColorMask), Thickness = ted.te_thickness }; byte[] tmpStr; if (ted.te_ptext > 0 && ted.te_ptext < resourceStream.Length && ted.te_txtlen > 0) { tmpStr = new byte[ted.te_txtlen]; resourceStream.Position = ted.te_ptext; resourceStream.Read(tmpStr, 0, ted.te_txtlen); node.TedInfo.Text = StringHandlers.CToString(tmpStr, encoding); if (!string.IsNullOrWhiteSpace(node.TedInfo.Text)) { strings.Add(node.TedInfo.Text.Trim()); } } if (ted.te_pvalid > 0 && ted.te_pvalid < resourceStream.Length && ted.te_txtlen > 0) { tmpStr = new byte[ted.te_txtlen]; resourceStream.Position = ted.te_pvalid; resourceStream.Read(tmpStr, 0, ted.te_txtlen); node.TedInfo.Validation = StringHandlers.CToString(tmpStr, encoding); if (!string.IsNullOrWhiteSpace(node.TedInfo.Validation)) { strings.Add(node.TedInfo.Validation.Trim()); } } if (ted.te_ptmplt > 0 && ted.te_ptmplt < resourceStream.Length && ted.te_tmplen > 0) { tmpStr = new byte[ted.te_tmplen]; resourceStream.Position = ted.te_ptmplt; resourceStream.Read(tmpStr, 0, ted.te_tmplen); node.TedInfo.Template = StringHandlers.CToString(tmpStr, encoding); if (!string.IsNullOrWhiteSpace(node.TedInfo.Template)) { strings.Add(node.TedInfo.Template.Trim()); } } break; case ObjectTypes.G_IMAGE: if (node.data <= 0 || node.data >= resourceStream.Length) { break; } resourceStream.Position = node.data; buffer = new byte[Marshal.SizeOf(typeof(BitBlock))]; resourceStream.Read(buffer, 0, buffer.Length); BitBlock bitBlock = bigEndian ? BigEndianMarshal.ByteArrayToStructureBigEndian <BitBlock>(buffer) : BigEndianMarshal.ByteArrayToStructureLittleEndian <BitBlock>(buffer); node.BitBlock = new BitmapBlock { Color = (ObjectColors)bitBlock.bi_color, Height = bitBlock.bi_hl, Width = (uint)(bitBlock.bi_wb * 8), X = bitBlock.bi_x, Y = bitBlock.bi_y }; if (bitBlock.bi_pdata == 0 || bitBlock.bi_pdata >= resourceStream.Length) { break; } node.BitBlock.Data = new byte[bitBlock.bi_wb * bitBlock.bi_hl]; resourceStream.Position = bitBlock.bi_pdata; resourceStream.Read(node.BitBlock.Data, 0, node.BitBlock.Data.Length); // Because the image is stored as words, they get reversed on PC GEM (Little-endian) if (!bigEndian) { byte[] data = new byte[node.BitBlock.Data.Length]; for (int i = 0; i < data.Length; i += 2) { data[i] = node.BitBlock.Data[i + 1]; data[i + 1] = node.BitBlock.Data[i]; } node.BitBlock.Data = data; } break; case ObjectTypes.G_USERDEF: if (node.data <= 0 || node.data >= resourceStream.Length) { break; } resourceStream.Position = node.data; buffer = new byte[Marshal.SizeOf(typeof(ApplicationBlock))]; resourceStream.Read(buffer, 0, buffer.Length); node.ApplicationBlock = bigEndian ? BigEndianMarshal .ByteArrayToStructureBigEndian <ApplicationBlock>(buffer) : BigEndianMarshal .ByteArrayToStructureLittleEndian <ApplicationBlock>(buffer); break; case ObjectTypes.G_ICON: if (node.data <= 0 || node.data >= resourceStream.Length) { break; } resourceStream.Position = node.data; buffer = new byte[Marshal.SizeOf(typeof(IconBlock))]; resourceStream.Read(buffer, 0, buffer.Length); node.IconBlock = GetIconBlock(resourceStream, buffer, bigEndian, encoding); if (!string.IsNullOrWhiteSpace(node.IconBlock.Text)) { strings.Add(node.IconBlock.Text.Trim()); } break; case ObjectTypes.G_CICON: // Do nothing, it is done separately... break; case ObjectTypes.G_BUTTON: case ObjectTypes.G_STRING: case ObjectTypes.G_TITLE: case ObjectTypes.G_SHORTCUT: if (node.data <= 0 || node.data >= resourceStream.Length) { break; } resourceStream.Position = node.data; List <byte> chars = new List <byte>(); while (true) { int character = resourceStream.ReadByte(); if (character <= 0) { break; } chars.Add((byte)character); } node.String = StringHandlers.CToString(chars.ToArray(), encoding); if (!string.IsNullOrWhiteSpace(node.String)) { strings.Add(node.String.Trim()); } break; } knownNodes.Add(nodeNumber); if (nodes[nodeNumber].ob_head > 0 && !knownNodes.Contains(nodes[nodeNumber].ob_head)) { node.child = ProcessResourceObject(nodes, ref knownNodes, nodes[nodeNumber].ob_head, resourceStream, strings, bigEndian, encoding); } if (nodes[nodeNumber].ob_next > 0 && !knownNodes.Contains(nodes[nodeNumber].ob_next)) { node.sibling = ProcessResourceObject(nodes, ref knownNodes, nodes[nodeNumber].ob_next, resourceStream, strings, bigEndian, encoding); } return(node); }
public static ColorIcon[] GetColorIcons(Stream resourceStream, int colorIc, bool bigEndian, Encoding encoding) { byte[] buffer; if (colorIc == -1 || colorIc >= resourceStream.Length) { return(null); } resourceStream.Position = colorIc; int cicons = 0; while (true) { buffer = new byte[4]; resourceStream.Read(buffer, 0, buffer.Length); if (BitConverter.ToInt32(buffer, 0) == -1) { break; } cicons++; } ColorIcon[] colorIcons = new ColorIcon[cicons]; for (int i = 0; i < cicons; i++) { buffer = new byte[Marshal.SizeOf(typeof(IconBlock))]; resourceStream.Read(buffer, 0, buffer.Length); IconBlock iconBlock = BigEndianMarshal.ByteArrayToStructureBigEndian <IconBlock>(buffer); int isize = iconBlock.ib_wicon * iconBlock.ib_hicon / 8; buffer = new byte[4]; resourceStream.Position -= 2; resourceStream.Read(buffer, 0, buffer.Length); int numRez = BitConverter.ToInt32(buffer.Reverse().ToArray(), 0); colorIcons[i] = new ColorIcon { Color = new ColorIconPlane[numRez], Monochrome = new Icon { Width = iconBlock.ib_wicon, Height = iconBlock.ib_hicon, X = iconBlock.ib_xicon, Y = iconBlock.ib_yicon, ForegroundColor = (ObjectColors)((iconBlock.ib_char >> 12) & 0x000F), BackgroundColor = (ObjectColors)((iconBlock.ib_char >> 8) & 0x000F), Character = encoding.GetString(new[] { (byte)(iconBlock.ib_char & 0xFF) })[0], CharX = iconBlock.ib_xchar, CharY = iconBlock.ib_ychar, TextX = iconBlock.ib_xtext, TextY = iconBlock.ib_ytext, TextWidth = iconBlock.ib_wtext, TextHeight = iconBlock.ib_htext, Data = new byte[isize], Mask = new byte[isize] } }; resourceStream.Read(colorIcons[i].Monochrome.Data, 0, isize); // Because the image is stored as words, they get reversed on PC GEM (Little-endian) if (!bigEndian) { byte[] data = new byte[colorIcons[i].Monochrome.Data.Length]; for (int d = 0; d < data.Length; d += 2) { data[d] = colorIcons[d].Monochrome.Data[d + 1]; data[d + 1] = colorIcons[d].Monochrome.Data[d]; } colorIcons[i].Monochrome.Data = data; } resourceStream.Read(colorIcons[i].Monochrome.Mask, 0, isize); // Because the mask is stored as words, they get reversed on PC GEM (Little-endian) if (!bigEndian) { byte[] mask = new byte[colorIcons[i].Monochrome.Mask.Length]; for (int m = 0; m < mask.Length; m += 2) { mask[m] = colorIcons[m].Monochrome.Mask[m + 1]; mask[m + 1] = colorIcons[m].Monochrome.Mask[m]; } colorIcons[i].Monochrome.Mask = mask; } if (iconBlock.ib_ptext > 0 && iconBlock.ib_ptext < resourceStream.Length) { long oldPosition = resourceStream.Position; resourceStream.Position = iconBlock.ib_ptext; List <byte> chars = new List <byte>(); while (true) { int character = resourceStream.ReadByte(); if (character <= 0) { break; } chars.Add((byte)character); } colorIcons[i].Monochrome.Text = StringHandlers.CToString(chars.ToArray(), encoding); resourceStream.Position = oldPosition + 12; } else { byte[] ptext = new byte[12]; resourceStream.Read(ptext, 0, 12); colorIcons[i].Monochrome.Text = StringHandlers.CToString(ptext, encoding); } colorIcons[i].Color = new ColorIconPlane[numRez]; for (int r = 0; r < numRez; r++) { byte[] data; byte[] mask; buffer = new byte[Marshal.SizeOf(typeof(ColorIconBlock))]; resourceStream.Read(buffer, 0, buffer.Length); ColorIconBlock cib = BigEndianMarshal.ByteArrayToStructureBigEndian <ColorIconBlock>(buffer); colorIcons[i].Color[r] = new ColorIconPlane { Planes = cib.num_planes, Data = new byte[isize * cib.num_planes], Mask = new byte[isize] }; resourceStream.Read(colorIcons[i].Color[r].Data, 0, isize * cib.num_planes); // Because the image is stored as words, they get reversed on PC GEM (Little-endian) if (!bigEndian) { data = new byte[colorIcons[i].Color[r].Data.Length]; for (int d = 0; d < data.Length; d += 2) { data[d] = colorIcons[d].Color[r].Data[d + 1]; data[d + 1] = colorIcons[d].Color[r].Data[d]; } colorIcons[i].Color[r].Data = data; } resourceStream.Read(colorIcons[i].Color[r].Mask, 0, isize); // Because the mask is stored as words, they get reversed on PC GEM (Little-endian) if (!bigEndian) { mask = new byte[colorIcons[i].Color[r].Mask.Length]; for (int m = 0; m < mask.Length; m += 2) { mask[m] = colorIcons[m].Color[r].Mask[m + 1]; mask[m + 1] = colorIcons[m].Color[r].Mask[m]; } colorIcons[i].Color[r].Mask = mask; } if (cib.sel_data == 0) { continue; } colorIcons[i].Color[r].SelectedData = new byte[isize * cib.num_planes]; colorIcons[i].Color[r].SelectedMask = new byte[isize]; resourceStream.Read(colorIcons[i].Color[r].SelectedData, 0, isize * cib.num_planes); // Because the image is stored as words, they get reversed on PC GEM (Little-endian) if (!bigEndian) { data = new byte[colorIcons[i].Color[r].SelectedData.Length]; for (int d = 0; d < data.Length; d += 2) { data[d] = colorIcons[d].Color[r].SelectedData[d + 1]; data[d + 1] = colorIcons[d].Color[r].SelectedData[d]; } colorIcons[i].Color[r].SelectedData = data; } resourceStream.Read(colorIcons[i].Color[r].SelectedMask, 0, isize); // Because the mask is stored as words, they get reversed on PC GEM (Little-endian) if (bigEndian) { continue; } mask = new byte[colorIcons[i].Color[r].SelectedMask.Length]; for (int m = 0; m < mask.Length; m += 2) { mask[m] = colorIcons[m].Color[r].SelectedMask[m + 1]; mask[m + 1] = colorIcons[m].Color[r].SelectedMask[m]; } colorIcons[i].Color[r].SelectedMask = mask; } } return(colorIcons); }
static Icon GetIconBlock(Stream resourceStream, byte[] buffer, bool bigEndian, Encoding encoding) { long oldPosition = resourceStream.Position; IconBlock iconBlock = bigEndian ? BigEndianMarshal.ByteArrayToStructureBigEndian <IconBlock>(buffer) : BigEndianMarshal.ByteArrayToStructureLittleEndian <IconBlock>(buffer); Icon icon = new Icon { Width = iconBlock.ib_wicon, Height = iconBlock.ib_hicon, X = iconBlock.ib_xicon, Y = iconBlock.ib_yicon, ForegroundColor = (ObjectColors)((iconBlock.ib_char >> 12) & 0x000F), BackgroundColor = (ObjectColors)((iconBlock.ib_char >> 8) & 0x000F), Character = encoding.GetString(new[] { (byte)(iconBlock.ib_char & 0xFF) })[0], CharX = iconBlock.ib_xchar, CharY = iconBlock.ib_ychar, TextX = iconBlock.ib_xtext, TextY = iconBlock.ib_ytext, TextWidth = iconBlock.ib_wtext, TextHeight = iconBlock.ib_htext }; if (iconBlock.ib_ptext > 0 && iconBlock.ib_ptext < resourceStream.Length) { resourceStream.Position = iconBlock.ib_ptext; List <byte> chars = new List <byte>(); while (true) { int character = resourceStream.ReadByte(); if (character <= 0) { break; } chars.Add((byte)character); } icon.Text = StringHandlers.CToString(chars.ToArray(), encoding); } if (iconBlock.ib_pdata > 0 && iconBlock.ib_pdata < resourceStream.Length) { resourceStream.Position = iconBlock.ib_pdata; icon.Data = new byte[icon.Width * icon.Height / 8]; resourceStream.Read(icon.Data, 0, icon.Data.Length); // Because the image is stored as words, they get reversed on PC GEM (Little-endian) if (!bigEndian) { byte[] data = new byte[icon.Data.Length]; for (int i = 0; i < data.Length; i += 2) { data[i] = icon.Data[i + 1]; data[i + 1] = icon.Data[i]; } icon.Data = data; } } if (iconBlock.ib_pmask > 0 && iconBlock.ib_pmask < resourceStream.Length) { resourceStream.Position = iconBlock.ib_pmask; icon.Mask = new byte[icon.Width * icon.Height / 8]; resourceStream.Read(icon.Mask, 0, icon.Mask.Length); // Because the mask is stored as words, they get reversed on PC GEM (Little-endian) if (!bigEndian) { byte[] mask = new byte[icon.Mask.Length]; for (int i = 0; i < mask.Length; i += 2) { mask[i] = icon.Mask[i + 1]; mask[i + 1] = icon.Mask[i]; } icon.Mask = mask; } } resourceStream.Position = oldPosition; return(icon); }