mirror of
https://github.com/claunia/libexeinfo.git
synced 2025-12-16 19:14:24 +00:00
Add full support for Gem color icons.
This commit is contained in:
@@ -154,11 +154,12 @@ namespace exeinfo
|
||||
{
|
||||
recognized = true;
|
||||
Console.Write(mzExe.Information);
|
||||
if(((MZ)mzExe).resourceStream != null || ((MZ)mzExe).ResourceHeader.rsh_vrsn != 0 &&
|
||||
if(((MZ)mzExe).ResourceStream != null || ((MZ)mzExe).ResourceHeader.rsh_vrsn != 0 &&
|
||||
((MZ)mzExe).ResourceHeader.rsh_vrsn != 1 &&
|
||||
((MZ)mzExe).ResourceHeader.rsh_vrsn != 4 &&
|
||||
((MZ)mzExe).ResourceHeader.rsh_vrsn != 5)
|
||||
PrintGemResources(((MZ)mzExe).ResourceHeader, ((MZ)mzExe).ResourceObjectRoots);
|
||||
PrintGemResources(((MZ)mzExe).ResourceHeader, ((MZ)mzExe).ResourceObjectRoots,
|
||||
((MZ)mzExe).ResourceExtension, ((MZ)mzExe).GemColorIcons);
|
||||
|
||||
if(mzExe.Strings != null && mzExe.Strings.Any())
|
||||
{
|
||||
@@ -171,11 +172,12 @@ namespace exeinfo
|
||||
{
|
||||
recognized = true;
|
||||
Console.Write(stExe.Information);
|
||||
if(((AtariST)stExe).resourceStream != null || ((AtariST)stExe).ResourceHeader.rsh_vrsn != 0 &&
|
||||
if(((AtariST)stExe).ResourceStream != null || ((AtariST)stExe).ResourceHeader.rsh_vrsn != 0 &&
|
||||
((AtariST)stExe).ResourceHeader.rsh_vrsn != 1 &&
|
||||
((AtariST)stExe).ResourceHeader.rsh_vrsn != 4 &&
|
||||
((AtariST)stExe).ResourceHeader.rsh_vrsn != 5)
|
||||
PrintGemResources(((AtariST)stExe).ResourceHeader, ((AtariST)stExe).ResourceObjectRoots);
|
||||
PrintGemResources(((AtariST)stExe).ResourceHeader, ((AtariST)stExe).ResourceObjectRoots,
|
||||
((AtariST)stExe).ResourceExtension, ((AtariST)stExe).GemColorIcons);
|
||||
|
||||
if(stExe.Strings != null && stExe.Strings.Any())
|
||||
{
|
||||
@@ -199,7 +201,9 @@ namespace exeinfo
|
||||
if(!recognized) Console.WriteLine("Executable format not recognized");
|
||||
}
|
||||
|
||||
static void PrintGemResources(GEM.GemResourceHeader resourceHeader, IReadOnlyList<GEM.TreeObjectNode> roots)
|
||||
static void PrintGemResources(GEM.GemResourceHeader resourceHeader, IReadOnlyList<GEM.TreeObjectNode> roots,
|
||||
GEM.GemResourceExtension resourceExtension,
|
||||
GEM.ColorIcon[] colorIcons)
|
||||
{
|
||||
Console.WriteLine("\t\tGEM Resources:");
|
||||
Console.WriteLine("\t\t\t{0} OBJECTs start at {1}", resourceHeader.rsh_nobs, resourceHeader.rsh_object);
|
||||
@@ -215,17 +219,24 @@ namespace exeinfo
|
||||
Console.WriteLine("\t\t\tString data starts at {0}", resourceHeader.rsh_string);
|
||||
Console.WriteLine("\t\t\tImage data starts at {0}", resourceHeader.rsh_imdata);
|
||||
Console.WriteLine("\t\t\tStandard resource data is {0} bytes", resourceHeader.rsh_rssize);
|
||||
if(resourceHeader.rsh_vrsn >= 4)
|
||||
{
|
||||
Console.WriteLine("\t\t\tColor icon table starts at {0}", resourceExtension.color_ic);
|
||||
Console.WriteLine("\t\t\tThere are {0}more extensions",
|
||||
resourceExtension.end_extensions == 0 ? "no " : "");
|
||||
Console.WriteLine("\t\t\tExtended resource data is {0} bytes", resourceExtension.filesize);
|
||||
}
|
||||
|
||||
if(roots == null || roots.Count <= 0) return;
|
||||
|
||||
for(int i = 0; i < roots.Count; i++)
|
||||
{
|
||||
Console.WriteLine("\t\t\tObject tree {0}:", i);
|
||||
PrintGemResourceTree(roots[i], 4);
|
||||
PrintGemResourceTree(roots[i], 4, colorIcons);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintGemResourceTree(GEM.TreeObjectNode node, int level)
|
||||
static void PrintGemResourceTree(GEM.TreeObjectNode node, int level, GEM.ColorIcon[] colorIcons)
|
||||
{
|
||||
for(int i = 0; i < level; i++) Console.Write("\t");
|
||||
|
||||
@@ -235,7 +246,7 @@ namespace exeinfo
|
||||
{
|
||||
case GEM.ObjectTypes.G_BOX:
|
||||
case GEM.ObjectTypes.G_IBOX:
|
||||
Console.WriteLine("{0} ({1} {2}) {3} border, {4} text, {5} interior, {6} fill, {7} mode, coordinates ({8},{9}) size {10}x{11}",
|
||||
Console.WriteLine("{0} ({1} {2}) {3} border, {4} text, {5} interior, {6} fill, {7} mode," + " coordinates ({8},{9}) size {10}x{11}",
|
||||
node.type, node.flags, node.state,
|
||||
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.BorderColorMask) >> 12),
|
||||
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.TextColorMask) >> 8),
|
||||
@@ -262,9 +273,9 @@ namespace exeinfo
|
||||
})[0];
|
||||
|
||||
Console.WriteLine(
|
||||
"{0} ({1} {2}) {3} border, {4} text, {5} interior, {6} fill, {7} mode, {8}, '{9}' character, coordinates ({10},{11}) size {12}x{13}",
|
||||
node.type, node.flags, node.state,
|
||||
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.BorderColorMask) >> 12),
|
||||
"{0} ({1} {2}) {3} border, {4} text, {5} interior, {6} fill, {7} mode, {8}," +
|
||||
" '{9}' character, coordinates ({10},{11}) size {12}x{13}", node.type, node.flags,
|
||||
node.state, (GEM.ObjectColors)((node.data & 0xFFFF & GEM.BorderColorMask) >> 12),
|
||||
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.TextColorMask) >> 8),
|
||||
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.InsideColorMask) >> 8),
|
||||
(GEM.ObjectFillPattern)((node.data & 0xFFFF & GEM.FillPatternMask) >> 4),
|
||||
@@ -292,7 +303,7 @@ namespace exeinfo
|
||||
else
|
||||
thickStr = "no thickness";
|
||||
|
||||
Console.WriteLine("{0} ({1} {2}), coordinates ({3},{4}) size {5}x{6}, font {7}, {8}-justified, {9}," + " {10} border, {11} text, {12} interior, {13} fill, {14} mode, text: \"{15}\"," + " validation: \"{16}\", template: \"{17}\"",
|
||||
Console.WriteLine("{0} ({1} {2}), coordinates ({3},{4}) size {5}x{6}, font {7}, {8}-justified," + " {9}, {10} border, {11} text, {12} interior, {13} fill, {14} mode," + " text: \"{15}\", validation: \"{16}\", template: \"{17}\"",
|
||||
node.type, node.flags, node.state, node.x, node.y, node.width, node.height,
|
||||
node.TedInfo.Font, node.TedInfo.Justification, thickStr, node.TedInfo.BorderColor,
|
||||
node.TedInfo.TextColor, node.TedInfo.InsideColor, node.TedInfo.Fill,
|
||||
@@ -323,15 +334,42 @@ namespace exeinfo
|
||||
node.IconBlock.TextY, node.IconBlock.TextWidth, node.IconBlock.TextHeight);
|
||||
|
||||
break;
|
||||
case GEM.ObjectTypes.G_CICON:
|
||||
if(colorIcons == null || colorIcons.Length < node.data ||
|
||||
colorIcons[node.data] == null ||
|
||||
colorIcons[node.data].Monochrome == null)
|
||||
{
|
||||
Console.WriteLine("{0} ({1} {2}) with index {3} NOT FOUND", node.type, node.flags, node.state,
|
||||
node.data);
|
||||
break;
|
||||
}
|
||||
|
||||
Console.WriteLine(
|
||||
"{0} ({1} {2}), coordinates ({3},{4}) size {5}x{6}, {7} foreground," +
|
||||
" {8} background, char '{9}' at ({10},{11}), {12} bytes data, text \"{13}\" at" +
|
||||
" ({14},{15}) within a box {16}x{17} pixels, with {18} different planes",
|
||||
node.type, node.flags, node.state, colorIcons[node.data].Monochrome.X,
|
||||
colorIcons[node.data].Monochrome.Y, colorIcons[node.data].Monochrome.Width,
|
||||
colorIcons[node.data].Monochrome.Height,
|
||||
colorIcons[node.data].Monochrome.ForegroundColor,
|
||||
colorIcons[node.data].Monochrome.BackgroundColor,
|
||||
colorIcons[node.data].Monochrome.Character,
|
||||
colorIcons[node.data].Monochrome.CharX, colorIcons[node.data].Monochrome.CharY,
|
||||
colorIcons[node.data].Monochrome.Data?.Length,
|
||||
colorIcons[node.data].Monochrome.Text, colorIcons[node.data].Monochrome.TextX,
|
||||
colorIcons[node.data].Monochrome.TextY,
|
||||
colorIcons[node.data].Monochrome.TextWidth,
|
||||
colorIcons[node.data].Monochrome.TextHeight, colorIcons[node.data].Color.Length);
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("{0} ({1} {2}) data = {3}, coordinates ({4},{5}) size {6}x{7}", node.type,
|
||||
node.flags, node.state, node.data, node.x, node.y, node.width, node.height);
|
||||
break;
|
||||
}
|
||||
|
||||
if(node.child != null) PrintGemResourceTree(node.child, level + 1);
|
||||
if(node.child != null) PrintGemResourceTree(node.child, level + 1, colorIcons);
|
||||
|
||||
if(node.sibling != null) PrintGemResourceTree(node.sibling, level);
|
||||
if(node.sibling != null) PrintGemResourceTree(node.sibling, level, colorIcons);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
exeinfogui/GEM/GemColorIcon.cs
Normal file
19
exeinfogui/GEM/GemColorIcon.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Eto.Drawing;
|
||||
|
||||
namespace exeinfogui.GEM
|
||||
{
|
||||
public static class GemColorIcon
|
||||
{
|
||||
public static Bitmap GemColorIconToEto(libexeinfo.GEM.ColorIconPlane icon, int width, int height, bool selected)
|
||||
{
|
||||
if(selected && icon.SelectedData == null) return null;
|
||||
|
||||
byte[] data = selected ? icon.SelectedData : icon.Data;
|
||||
byte[] mask = selected ? icon.SelectedMask : icon.Mask;
|
||||
|
||||
int[] pixels = libexeinfo.GEM.PlaneToRaster(data, mask, width, height, icon.Planes);
|
||||
|
||||
return new Bitmap(width, height, PixelFormat.Format32bppRgba, pixels);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
exeinfogui/GEM/GemIcon.cs
Normal file
28
exeinfogui/GEM/GemIcon.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using Eto.Drawing;
|
||||
|
||||
namespace exeinfogui.GEM
|
||||
{
|
||||
public static class GemIcon
|
||||
{
|
||||
public static Bitmap GemIconToEto(libexeinfo.GEM.Icon icon)
|
||||
{
|
||||
const uint COLOR = 0x00000000;
|
||||
const uint BACKGROUND = 0x00FFFFFF;
|
||||
const uint ALPHAMASK = 0xFF000000;
|
||||
List<int> pixels = new List<int>();
|
||||
|
||||
byte[] data = libexeinfo.GEM.FlipPlane(icon.Data, icon.Width);
|
||||
byte[] mask = libexeinfo.GEM.FlipPlane(icon.Mask, icon.Width);
|
||||
|
||||
for(int pos = 0; pos < data.Length; pos++)
|
||||
{
|
||||
for(int i = 0; i < 8; i++)
|
||||
pixels.Add((int)(((data[pos] & (1 << i)) != 0 ? COLOR : BACKGROUND) +
|
||||
((mask[pos] & (1 << i)) != 0 ? ALPHAMASK : 0)));
|
||||
}
|
||||
|
||||
return new Bitmap(icon.Width, icon.Height, PixelFormat.Format32bppRgba, pixels);
|
||||
}
|
||||
}
|
||||
}
|
||||
125
exeinfogui/GEM/PanelGemColorIcon.xeto
Normal file
125
exeinfogui/GEM/PanelGemColorIcon.xeto
Normal file
@@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Panel xmlns="http://schema.picoe.ca/eto.forms" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="500" Height="500">
|
||||
<StackLayout Orientation="Vertical" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Top">
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<StackLayoutItem>
|
||||
<Label ID="lblFlags">Flags</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem Expand="True" HorizontalAlignment="Stretch">
|
||||
<TextBox ID="txtFlags" ReadOnly="True"/>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<StackLayoutItem>
|
||||
<Label ID="lblState">State</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem Expand="True" HorizontalAlignment="Stretch">
|
||||
<TextBox ID="txtState" ReadOnly="True"/>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<StackLayoutItem>
|
||||
<Label ID="lblCoordinates">Coordinates</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem Expand="True" HorizontalAlignment="Stretch">
|
||||
<TextBox ID="txtCoordinates" ReadOnly="True"/>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<StackLayoutItem>
|
||||
<Label ID="lblSize">Size</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem Expand="True" HorizontalAlignment="Stretch">
|
||||
<TextBox ID="txtSize" ReadOnly="True"/>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<StackLayoutItem>
|
||||
<Label ID="lblCharacter">Character</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem Expand="True" HorizontalAlignment="Stretch">
|
||||
<TextBox ID="txtCharater" ReadOnly="True"/>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<StackLayoutItem>
|
||||
<Label ID="lblCharCoordinates">Character coordinates</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem Expand="True" HorizontalAlignment="Stretch">
|
||||
<TextBox ID="txtCharCoordinates" ReadOnly="True"/>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<StackLayoutItem>
|
||||
<Label ID="lblFgColor">Character foreground color</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem Expand="True" HorizontalAlignment="Stretch">
|
||||
<TextBox ID="txtFgColor" ReadOnly="True"/>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<StackLayoutItem>
|
||||
<Label ID="lblBgColor">Character background color</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem Expand="True" HorizontalAlignment="Stretch">
|
||||
<TextBox ID="txtBgColor" ReadOnly="True"/>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<StackLayoutItem>
|
||||
<Label ID="lblTextCoordinates">Text coordinates</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem Expand="True" HorizontalAlignment="Stretch">
|
||||
<TextBox ID="txtTextCoordinates" ReadOnly="True"/>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<StackLayoutItem>
|
||||
<Label ID="lblTextBoxSize">Text box size</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem Expand="True" HorizontalAlignment="Stretch">
|
||||
<TextBox ID="txtTextBoxSize" ReadOnly="True"/>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<StackLayoutItem>
|
||||
<Label ID="lblText">Text</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem Expand="True" HorizontalAlignment="Stretch">
|
||||
<TextBox ID="txtText" ReadOnly="True"/>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
<StackLayoutItem HorizontalAlignment="Center">
|
||||
<Label ID="lblMonochrome">Monochrome icon</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem HorizontalAlignment="Center">
|
||||
<ImageView ID="imgIcon"/>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem HorizontalAlignment="Center">
|
||||
<Label ID="lblColor">Color icons</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Expand="True">
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<StackLayoutItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Expand="True">
|
||||
<GridView ID="treePlanes"/>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem HorizontalAlignment="Center" VerticalAlignment="Top" Expand="True">
|
||||
<StackLayout Orientation="Vertical">
|
||||
<StackLayoutItem HorizontalAlignment="Center">
|
||||
<Label ID="lblColorIcon">Normal</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem HorizontalAlignment="Center">
|
||||
<ImageView ID="imgColorIcon"/>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem HorizontalAlignment="Center">
|
||||
<Label ID="lblSelectedIcon">Selected</Label>
|
||||
</StackLayoutItem>
|
||||
<StackLayoutItem HorizontalAlignment="Center">
|
||||
<ImageView ID="imgSelectedIcon"/>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
</StackLayoutItem>
|
||||
</StackLayout>
|
||||
</Panel>
|
||||
88
exeinfogui/GEM/PanelGemColorIcon.xeto.cs
Normal file
88
exeinfogui/GEM/PanelGemColorIcon.xeto.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using Eto.Forms;
|
||||
using Eto.Serialization.Xaml;
|
||||
|
||||
namespace exeinfogui.GEM
|
||||
{
|
||||
public class PanelGemColorIcon : Panel
|
||||
{
|
||||
int iconHeight;
|
||||
|
||||
int iconWidth;
|
||||
ImageView imgColorIcon;
|
||||
ImageView imgIcon;
|
||||
ImageView imgSelectedIcon;
|
||||
GridView treePlanes;
|
||||
TextBox txtBgColor;
|
||||
TextBox txtCharater;
|
||||
TextBox txtCharCoordinates;
|
||||
TextBox txtCoordinates;
|
||||
TextBox txtFgColor;
|
||||
TextBox txtFlags;
|
||||
TextBox txtSize;
|
||||
TextBox txtState;
|
||||
TextBox txtText;
|
||||
TextBox txtTextBoxSize;
|
||||
TextBox txtTextCoordinates;
|
||||
|
||||
public PanelGemColorIcon()
|
||||
{
|
||||
XamlReader.Load(this);
|
||||
|
||||
treePlanes.Columns.Add(new GridColumn
|
||||
{
|
||||
DataCell = new TextBoxCell
|
||||
{
|
||||
Binding = Binding.Property<libexeinfo.GEM.ColorIconPlane, string>(i => $"{i.Planes}")
|
||||
},
|
||||
HeaderText = "Planes"
|
||||
});
|
||||
treePlanes.AllowMultipleSelection = false;
|
||||
treePlanes.SelectedItemsChanged += TreePlanesOnSelectedItemsChanged;
|
||||
}
|
||||
|
||||
void TreePlanesOnSelectedItemsChanged(object sender, EventArgs eventArgs)
|
||||
{
|
||||
if(!(treePlanes.SelectedItem is libexeinfo.GEM.ColorIconPlane cicon))
|
||||
{
|
||||
imgColorIcon.Image = null;
|
||||
imgSelectedIcon.Image = null;
|
||||
return;
|
||||
}
|
||||
|
||||
imgColorIcon.Image = GemColorIcon.GemColorIconToEto(cicon, iconWidth, iconHeight, false);
|
||||
imgSelectedIcon.Image = GemColorIcon.GemColorIconToEto(cicon, iconWidth, iconHeight, true);
|
||||
}
|
||||
|
||||
public void Update(libexeinfo.GEM.TreeObjectNode node, libexeinfo.GEM.ColorIcon colorIcon)
|
||||
{
|
||||
txtFlags.Text = node.flags == 0 ? "None" : node.flags.ToString();
|
||||
txtState.Text = node.state == 0 ? "Normal" : node.state.ToString();
|
||||
txtCoordinates.Text = $"{colorIcon.Monochrome.X},{colorIcon.Monochrome.Y}";
|
||||
txtSize.Text = $"{colorIcon.Monochrome.Width}x{colorIcon.Monochrome.Height} pixels";
|
||||
txtCharater.Text = $"{colorIcon.Monochrome.Character}";
|
||||
txtCharCoordinates.Text = $"{colorIcon.Monochrome.CharX},{colorIcon.Monochrome.CharY}";
|
||||
txtFgColor.Text = $"{colorIcon.Monochrome.ForegroundColor}";
|
||||
txtBgColor.Text = $"{colorIcon.Monochrome.BackgroundColor}";
|
||||
txtTextCoordinates.Text = $"{colorIcon.Monochrome.TextX},{colorIcon.Monochrome.TextY}";
|
||||
txtTextBoxSize.Text = $"{colorIcon.Monochrome.TextWidth}x{colorIcon.Monochrome.TextHeight} pixels";
|
||||
txtText.Text = colorIcon.Monochrome.Text;
|
||||
imgIcon.Image = GemIcon.GemIconToEto(colorIcon.Monochrome);
|
||||
treePlanes.DataStore = colorIcon.Color;
|
||||
iconWidth = colorIcon.Monochrome.Width;
|
||||
iconHeight = colorIcon.Monochrome.Height;
|
||||
treePlanes.SelectRow(0);
|
||||
if(colorIcon.Color != null && colorIcon.Color.Length >= 1 && colorIcon.Color[0] != null)
|
||||
{
|
||||
imgColorIcon.Image =
|
||||
GemColorIcon.GemColorIconToEto(colorIcon.Color[0], iconWidth, iconHeight, false);
|
||||
imgSelectedIcon.Image = GemColorIcon.GemColorIconToEto(colorIcon.Color[0], iconWidth, iconHeight, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
imgColorIcon.Image = null;
|
||||
imgSelectedIcon.Image = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using Eto.Drawing;
|
||||
using Eto.Forms;
|
||||
using Eto.Forms;
|
||||
using Eto.Serialization.Xaml;
|
||||
|
||||
namespace exeinfogui.GEM
|
||||
@@ -38,67 +36,7 @@ namespace exeinfogui.GEM
|
||||
txtTextCoordinates.Text = $"{node.IconBlock.TextX},{node.IconBlock.TextY}";
|
||||
txtTextBoxSize.Text = $"{node.IconBlock.TextWidth}x{node.IconBlock.TextHeight} pixels";
|
||||
txtText.Text = node.IconBlock.Text;
|
||||
imgIcon.Image = GemIconToEto(node);
|
||||
}
|
||||
|
||||
static Bitmap GemIconToEto(libexeinfo.GEM.TreeObjectNode node)
|
||||
{
|
||||
const uint COLOR = 0x00000000;
|
||||
const uint BACKGROUND = 0x00FFFFFF;
|
||||
const uint ALPHAMASK = 0xFF000000;
|
||||
List<int> pixels = new List<int>();
|
||||
|
||||
byte[] data = new byte[node.IconBlock.Data.Length];
|
||||
int pos = 0;
|
||||
int w = node.IconBlock.Width / 8;
|
||||
// This flips the image.
|
||||
while(pos < data.Length)
|
||||
{
|
||||
for(int i = 0; i < w; i++)
|
||||
{
|
||||
byte b = node.IconBlock.Data[pos + i];
|
||||
data[pos + i] = (byte)(b >> 7);
|
||||
data[pos + i] += (byte)((b >> 5) & 0x02);
|
||||
data[pos + i] += (byte)((b >> 3) & 0x04);
|
||||
data[pos + i] += (byte)((b >> 1) & 0x08);
|
||||
data[pos + i] += (byte)((b << 1) & 0x10);
|
||||
data[pos + i] += (byte)((b << 3) & 0x20);
|
||||
data[pos + i] += (byte)((b << 5) & 0x40);
|
||||
data[pos + i] += (byte)(b << 7);
|
||||
}
|
||||
|
||||
pos += w;
|
||||
}
|
||||
|
||||
byte[] mask = new byte[node.IconBlock.Mask.Length];
|
||||
pos = 0;
|
||||
// This flips the mask.
|
||||
while(pos < data.Length)
|
||||
{
|
||||
for(int i = 0; i < w; i++)
|
||||
{
|
||||
byte b = node.IconBlock.Mask[pos + i];
|
||||
mask[pos + i] = (byte)(b >> 7);
|
||||
mask[pos + i] += (byte)((b >> 5) & 0x02);
|
||||
mask[pos + i] += (byte)((b >> 3) & 0x04);
|
||||
mask[pos + i] += (byte)((b >> 1) & 0x08);
|
||||
mask[pos + i] += (byte)((b << 1) & 0x10);
|
||||
mask[pos + i] += (byte)((b << 3) & 0x20);
|
||||
mask[pos + i] += (byte)((b << 5) & 0x40);
|
||||
mask[pos + i] += (byte)(b << 7);
|
||||
}
|
||||
|
||||
pos += w;
|
||||
}
|
||||
|
||||
for(pos = 0; pos < data.Length; pos++)
|
||||
{
|
||||
for(int i = 0; i < 8; i++)
|
||||
pixels.Add((int)(((data[pos] & (1 << i)) != 0 ? COLOR : BACKGROUND) +
|
||||
((mask[pos] & (1 << i)) != 0 ? ALPHAMASK : 0)));
|
||||
}
|
||||
|
||||
return new Bitmap(node.IconBlock.Width, node.IconBlock.Height, PixelFormat.Format32bppRgba, pixels);
|
||||
imgIcon.Image = GemIcon.GemIconToEto(node.IconBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,9 @@ namespace exeinfogui.GEM
|
||||
{
|
||||
public class TabGemResources : TabPage
|
||||
{
|
||||
libexeinfo.GEM.ColorIcon[] colorIcons;
|
||||
PanelGemBox panelBox;
|
||||
PanelGemColorIcon panelColorIcon;
|
||||
PanelGemGeneric panelGeneric;
|
||||
PanelGemIcon panelIcon;
|
||||
PanelGemImage panelImage;
|
||||
@@ -31,9 +33,10 @@ namespace exeinfogui.GEM
|
||||
panelBox = new PanelGemBox();
|
||||
panelImage = new PanelGemImage();
|
||||
panelIcon = new PanelGemIcon();
|
||||
panelColorIcon = new PanelGemColorIcon();
|
||||
}
|
||||
|
||||
public void Update(libexeinfo.GEM.TreeObjectNode[] roots)
|
||||
public void Update(libexeinfo.GEM.TreeObjectNode[] roots, libexeinfo.GEM.ColorIcon[] cicons)
|
||||
{
|
||||
treeData = new TreeGridItemCollection();
|
||||
|
||||
@@ -47,6 +50,7 @@ namespace exeinfogui.GEM
|
||||
}
|
||||
|
||||
treeResources.DataStore = treeData;
|
||||
colorIcons = cicons;
|
||||
}
|
||||
|
||||
void TreeResourcesOnSelectionChanged(object sender, EventArgs eventArgs)
|
||||
@@ -86,8 +90,14 @@ namespace exeinfogui.GEM
|
||||
panelIcon.Update(node);
|
||||
pnlResource.Content = panelIcon;
|
||||
break;
|
||||
/* case libexeinfo.GEM.ObjectTypes.G_USERDEF: break;
|
||||
case libexeinfo.GEM.ObjectTypes.G_CICON: break;*/
|
||||
/* case libexeinfo.GEM.ObjectTypes.G_USERDEF: break;*/
|
||||
case libexeinfo.GEM.ObjectTypes.G_CICON:
|
||||
if(colorIcons == null || node.data >= colorIcons.Length || colorIcons[node.data] == null)
|
||||
goto default;
|
||||
|
||||
panelColorIcon.Update(node, colorIcons[node.data]);
|
||||
pnlResource.Content = panelColorIcon;
|
||||
break;
|
||||
default:
|
||||
panelGeneric.Update(node);
|
||||
pnlResource.Content = panelGeneric;
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace exeinfogui
|
||||
recognizedExe = mzExe;
|
||||
if(((MZ)mzExe).ResourceObjectRoots != null && ((MZ)mzExe).ResourceObjectRoots.Any())
|
||||
{
|
||||
tabGemResources.Update(((MZ)mzExe).ResourceObjectRoots);
|
||||
tabGemResources.Update(((MZ)mzExe).ResourceObjectRoots, ((MZ)mzExe).GemColorIcons);
|
||||
tabGemResources.Visible = true;
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ namespace exeinfogui
|
||||
recognizedExe = stExe;
|
||||
if(((AtariST)stExe).ResourceObjectRoots != null && ((AtariST)stExe).ResourceObjectRoots.Any())
|
||||
{
|
||||
tabGemResources.Update(((AtariST)stExe).ResourceObjectRoots);
|
||||
tabGemResources.Update(((AtariST)stExe).ResourceObjectRoots, ((AtariST)stExe).GemColorIcons);
|
||||
tabGemResources.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,9 +38,11 @@ namespace libexeinfo
|
||||
/// </summary>
|
||||
public partial class AtariST : IExecutable
|
||||
{
|
||||
public GEM.ColorIcon[] GemColorIcons;
|
||||
public GEM.GemResourceExtension ResourceExtension;
|
||||
public GEM.GemResourceHeader ResourceHeader;
|
||||
public GEM.TreeObjectNode[] ResourceObjectRoots;
|
||||
public Stream resourceStream;
|
||||
public Stream ResourceStream;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:libexeinfo.AtariST" /> class.
|
||||
@@ -72,7 +74,7 @@ namespace libexeinfo
|
||||
resourceFilePath = testPath + ".RSC";
|
||||
|
||||
if(resourceFilePath != null)
|
||||
resourceStream = File.Open(resourceFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
ResourceStream = File.Open(resourceFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
|
||||
Initialize();
|
||||
}
|
||||
@@ -126,27 +128,38 @@ namespace libexeinfo
|
||||
|
||||
Type = "Atari ST executable";
|
||||
|
||||
if(resourceStream == null) return;
|
||||
if(ResourceStream == null) return;
|
||||
|
||||
buffer = new byte[Marshal.SizeOf(typeof(GEM.GemResourceHeader))];
|
||||
resourceStream.Position = 0;
|
||||
resourceStream.Read(buffer, 0, buffer.Length);
|
||||
ResourceStream.Position = 0;
|
||||
ResourceStream.Read(buffer, 0, buffer.Length);
|
||||
ResourceHeader = BigEndianMarshal.ByteArrayToStructureBigEndian<GEM.GemResourceHeader>(buffer);
|
||||
|
||||
if(ResourceHeader.rsh_vrsn != 0 && ResourceHeader.rsh_vrsn != 1 && ResourceHeader.rsh_vrsn != 4 &&
|
||||
ResourceHeader.rsh_vrsn != 5) return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
List<string> strings = new List<string>();
|
||||
|
||||
if(ResourceHeader.rsh_ntree > 0)
|
||||
{
|
||||
resourceStream.Position = ResourceHeader.rsh_trindex;
|
||||
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);
|
||||
ResourceStream.Read(tmp, 0, 4);
|
||||
treeOffsets[i] = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
|
||||
}
|
||||
|
||||
@@ -154,15 +167,15 @@ namespace libexeinfo
|
||||
|
||||
for(int i = 0; i < ResourceHeader.rsh_ntree; i++)
|
||||
{
|
||||
if(treeOffsets[i] <= 0 || treeOffsets[i] >= resourceStream.Length) continue;
|
||||
if(treeOffsets[i] <= 0 || treeOffsets[i] >= ResourceStream.Length) continue;
|
||||
|
||||
resourceStream.Position = treeOffsets[i];
|
||||
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);
|
||||
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;
|
||||
@@ -170,7 +183,7 @@ namespace libexeinfo
|
||||
|
||||
List<short> knownNodes = new List<short>();
|
||||
ResourceObjectRoots[i] =
|
||||
GEM.ProcessResourceObject(nodes, ref knownNodes, 0, resourceStream, strings, true,
|
||||
GEM.ProcessResourceObject(nodes, ref knownNodes, 0, ResourceStream, strings, true,
|
||||
Encoding.AtariSTEncoding);
|
||||
}
|
||||
}
|
||||
@@ -178,18 +191,18 @@ namespace libexeinfo
|
||||
{
|
||||
GEM.ObjectNode[] nodes = new GEM.ObjectNode[ResourceHeader.rsh_nobs];
|
||||
|
||||
resourceStream.Position = ResourceHeader.rsh_object;
|
||||
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);
|
||||
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,
|
||||
GEM.ProcessResourceObject(nodes, ref knownNodes, 0, ResourceStream, strings, true,
|
||||
Encoding.AtariSTEncoding);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,10 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -40,7 +42,7 @@ namespace libexeinfo
|
||||
{
|
||||
TreeObjectNode node = new TreeObjectNode
|
||||
{
|
||||
type = (ObjectTypes)nodes[nodeNumber].ob_type,
|
||||
type = (ObjectTypes)(nodes[nodeNumber].ob_type & 0xff),
|
||||
flags = (ObjectFlags)nodes[nodeNumber].ob_flags,
|
||||
state = (ObjectStates)nodes[nodeNumber].ob_state,
|
||||
data = nodes[nodeNumber].ob_spec,
|
||||
@@ -51,7 +53,6 @@ namespace libexeinfo
|
||||
};
|
||||
|
||||
byte[] buffer;
|
||||
List<byte> chars;
|
||||
switch(node.type)
|
||||
{
|
||||
case ObjectTypes.G_TEXT:
|
||||
@@ -110,7 +111,6 @@ namespace libexeinfo
|
||||
}
|
||||
|
||||
break;
|
||||
// TODO: This is indeed a CUT from a bigger image, need to cut it out
|
||||
case ObjectTypes.G_IMAGE:
|
||||
if(node.data <= 0 || node.data >= resourceStream.Length) break;
|
||||
|
||||
@@ -166,87 +166,14 @@ namespace libexeinfo
|
||||
resourceStream.Position = node.data;
|
||||
buffer = new byte[Marshal.SizeOf(typeof(IconBlock))];
|
||||
resourceStream.Read(buffer, 0, buffer.Length);
|
||||
IconBlock iconBlock = bigEndian
|
||||
? BigEndianMarshal.ByteArrayToStructureBigEndian<IconBlock>(buffer)
|
||||
: BigEndianMarshal.ByteArrayToStructureLittleEndian<IconBlock>(buffer);
|
||||
|
||||
node.IconBlock = 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
|
||||
};
|
||||
node.IconBlock = GetIconBlock(resourceStream, buffer, bigEndian, encoding);
|
||||
|
||||
if(iconBlock.ib_ptext > 0 && iconBlock.ib_ptext < resourceStream.Length)
|
||||
{
|
||||
resourceStream.Position = iconBlock.ib_ptext;
|
||||
chars = new List<byte>();
|
||||
while(true)
|
||||
{
|
||||
int character = resourceStream.ReadByte();
|
||||
|
||||
if(character <= 0) break;
|
||||
|
||||
chars.Add((byte)character);
|
||||
}
|
||||
|
||||
node.IconBlock.Text = StringHandlers.CToString(chars.ToArray(), encoding);
|
||||
if(!string.IsNullOrWhiteSpace(node.IconBlock.Text)) strings.Add(node.IconBlock.Text.Trim());
|
||||
}
|
||||
|
||||
if(iconBlock.ib_pdata > 0 && iconBlock.ib_pdata < resourceStream.Length)
|
||||
{
|
||||
resourceStream.Position = iconBlock.ib_pdata;
|
||||
node.IconBlock.Data = new byte[node.IconBlock.Width * node.IconBlock.Height / 8];
|
||||
resourceStream.Read(node.IconBlock.Data, 0, node.IconBlock.Data.Length);
|
||||
|
||||
// Because the image is stored as words, they get reversed on PC GEM (Little-endian)
|
||||
if(!bigEndian)
|
||||
{
|
||||
byte[] data = new byte[node.IconBlock.Data.Length];
|
||||
for(int i = 0; i < data.Length; i += 2)
|
||||
{
|
||||
data[i] = node.IconBlock.Data[i + 1];
|
||||
data[i + 1] = node.IconBlock.Data[i];
|
||||
}
|
||||
|
||||
node.IconBlock.Data = data;
|
||||
}
|
||||
}
|
||||
|
||||
if(iconBlock.ib_pmask > 0 && iconBlock.ib_pmask < resourceStream.Length)
|
||||
{
|
||||
resourceStream.Position = iconBlock.ib_pmask;
|
||||
node.IconBlock.Mask = new byte[node.IconBlock.Width * node.IconBlock.Height / 8];
|
||||
resourceStream.Read(node.IconBlock.Mask, 0, node.IconBlock.Mask.Length);
|
||||
|
||||
// Because the mask is stored as words, they get reversed on PC GEM (Little-endian)
|
||||
if(!bigEndian)
|
||||
{
|
||||
byte[] mask = new byte[node.IconBlock.Mask.Length];
|
||||
for(int i = 0; i < mask.Length; i += 2)
|
||||
{
|
||||
mask[i] = node.IconBlock.Mask[i + 1];
|
||||
mask[i + 1] = node.IconBlock.Mask[i];
|
||||
}
|
||||
|
||||
node.IconBlock.Mask = mask;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case ObjectTypes.G_CICON:
|
||||
//Console.WriteLine("ColorIconBlock pointer {0}", node.data);
|
||||
// Do nothing, it is done separately...
|
||||
break;
|
||||
case ObjectTypes.G_BUTTON:
|
||||
case ObjectTypes.G_STRING:
|
||||
@@ -254,7 +181,7 @@ namespace libexeinfo
|
||||
if(node.data <= 0 || node.data >= resourceStream.Length) break;
|
||||
|
||||
resourceStream.Position = node.data;
|
||||
chars = new List<byte>();
|
||||
List<byte> chars = new List<byte>();
|
||||
while(true)
|
||||
{
|
||||
int character = resourceStream.ReadByte();
|
||||
@@ -281,5 +208,289 @@ namespace libexeinfo
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,6 +167,7 @@ namespace libexeinfo
|
||||
{
|
||||
public BitmapBlock BitBlock;
|
||||
public TreeObjectNode child;
|
||||
public ColorIcon ColorIcon;
|
||||
public int data;
|
||||
public ObjectFlags flags;
|
||||
public short height;
|
||||
@@ -228,6 +229,21 @@ namespace libexeinfo
|
||||
public short Y;
|
||||
}
|
||||
|
||||
public class ColorIconPlane
|
||||
{
|
||||
public byte[] Data;
|
||||
public byte[] Mask;
|
||||
public short Planes;
|
||||
public byte[] SelectedData;
|
||||
public byte[] SelectedMask;
|
||||
}
|
||||
|
||||
public class ColorIcon
|
||||
{
|
||||
public ColorIconPlane[] Color;
|
||||
public Icon Monochrome;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The TEDINFO structure lets a user edit formatted text. The object types G_TEXT, G_BOXTEXT, G_FTEXT and G_FBOXTEXT
|
||||
/// use their <see cref="ObjectNode.ob_spec" /> to point to TEDINFO structures.
|
||||
@@ -476,7 +492,7 @@ namespace libexeinfo
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ColorIcon
|
||||
public struct ColorIconBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of planes in the following data
|
||||
@@ -503,18 +519,5 @@ namespace libexeinfo
|
||||
/// </summary>
|
||||
public int next_res;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ColorIconBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Default monochrome icon
|
||||
/// </summary>
|
||||
IconBlock monoblk;
|
||||
/// <summary>
|
||||
/// List of color icons for diferent resolutions
|
||||
/// </summary>
|
||||
ColorIcon[] mainlist;
|
||||
}
|
||||
}
|
||||
}
|
||||
159
libexeinfo/GEM/Vdi.cs
Normal file
159
libexeinfo/GEM/Vdi.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using System;
|
||||
|
||||
namespace libexeinfo
|
||||
{
|
||||
public static partial class GEM
|
||||
{
|
||||
/// <summary>Palette for monochrome</summary>
|
||||
public static int[] Palette1 = {0x00FFFFFF, 0x00000000};
|
||||
|
||||
/// <summary>Palette for 2 planes (4 colors)</summary>
|
||||
public static int[] Palette2 = {0x00FFFFFF, 0x00FF0000, 0x0000FF00, 0x00000000};
|
||||
|
||||
/// <summary>Palette for 3 planes (8 colors)</summary>
|
||||
public static int[] Palette3 =
|
||||
{0x00FFFFFF, 0x00FF0000, 0x0000FF00, 0x00FFFF00, 0x000000FF, 0x00FF00FF, 0x0000FFFF, 0x00000000};
|
||||
|
||||
/// <summary>Palette for 4 planes (16 colors)</summary>
|
||||
public static int[] Palette4 =
|
||||
{
|
||||
// Atari TT palette
|
||||
0x00FFFFFF, 0x00FF0000, 0x0000FF00, 0x00FFFF00, 0x000000FF, 0x00FF00FF, 0x0000FFFF, 0x00AAAAAA, 0x00666666,
|
||||
0x00FF9999, 0x0099FF99, 0x00FFFF99, 0x009999FF, 0x00FF99FF, 0x0099FFFF, 0x00000000
|
||||
// Atari ST palette
|
||||
// 0x00FFFFFF, 0x00FF0000, 0x0000FF00, 0x00FFFF00, 0x000000FF, 0x00FF00FF, 0x0000FFFF, 0x00555555,
|
||||
// 0x00333333, 0x00FF3333, 0x0033FF33, 0x00FFFF33, 0x003333FF, 0x00FF33FF, 0x0033FFFF, 0x00000000
|
||||
};
|
||||
|
||||
/// <summary>Palette for 8 planes (256 colors), from Atari TT</summary>
|
||||
public static int[] Palette8 =
|
||||
{
|
||||
0x00FFFFFF, 0x00FF0000, 0x0000FF00, 0x00FFFF00, 0x000000FF, 0x00FF00FF, 0x0000FFFF, 0x00AAAAAA, 0x00666666,
|
||||
0x00FF9999, 0x0099FF99, 0x00FFFF99, 0x009999FF, 0x00FF99FF, 0x0099FFFF, 0x00000000, 0x00FFFFFF, 0x00EEEEEE,
|
||||
0x00DDDDDD, 0x00CCCCCC, 0x00BBBBBB, 0x00AAAAAA, 0x00999999, 0x00888888, 0x00777777, 0x00666666, 0x00555555,
|
||||
0x00444444, 0x00333333, 0x00222222, 0x00111111, 0x00000000, 0x00FF0000, 0x00FF0011, 0x00FF0022, 0x00FF0033,
|
||||
0x00FF0044, 0x00FF0055, 0x00FF0066, 0x00FF0077, 0x00FF0088, 0x00FF0099, 0x00FF00AA, 0x00FF00BB, 0x00FF00CC,
|
||||
0x00FF00DD, 0x00FF00EE, 0x00FF00FF, 0x00EE00FF, 0x00DD00FF, 0x00CC00FF, 0x00BB00FF, 0x00AA00FF, 0x009900FF,
|
||||
0x008800FF, 0x007700FF, 0x006600FF, 0x005500FF, 0x004400FF, 0x003300FF, 0x002200FF, 0x001100FF, 0x000000FF,
|
||||
0x000011FF, 0x000022FF, 0x000033FF, 0x000044FF, 0x000055FF, 0x000066FF, 0x000077FF, 0x000088FF, 0x000099FF,
|
||||
0x0000AAFF, 0x0000BBFF, 0x0000CCFF, 0x0000DDFF, 0x0000EEFF, 0x0000FFFF, 0x0000FFEE, 0x0000FFDD, 0x0000FFCC,
|
||||
0x0000FFBB, 0x0000FFAA, 0x0000FF99, 0x0000FF88, 0x0000FF77, 0x0000FF66, 0x0000FF55, 0x0000FF44, 0x0000FF33,
|
||||
0x0000FF22, 0x0000FF11, 0x0000FF00, 0x0011FF00, 0x0022FF00, 0x0033FF00, 0x0044FF00, 0x0055FF00, 0x0066FF00,
|
||||
0x0077FF00, 0x0088FF00, 0x0099FF00, 0x00AAFF00, 0x00BBFF00, 0x00CCFF00, 0x00DDFF00, 0x00EEFF00, 0x00FFFF00,
|
||||
0x00FFEE00, 0x00FFDD00, 0x00FFCC00, 0x00FFBB00, 0x00FFAA00, 0x00FF9900, 0x00FF8800, 0x00FF7700, 0x00FF6600,
|
||||
0x00FF5500, 0x00FF4400, 0x00FF3300, 0x00FF2200, 0x00FF1100, 0x00BB0000, 0x00BB0011, 0x00BB0022, 0x00BB0033,
|
||||
0x00BB0044, 0x00BB0055, 0x00BB0066, 0x00BB0077, 0x00BB0088, 0x00BB0099, 0x00BB00AA, 0x00BB00BB, 0x00AA00BB,
|
||||
0x009900BB, 0x008800BB, 0x007700BB, 0x006600BB, 0x005500BB, 0x004400BB, 0x003300BB, 0x002200BB, 0x001100BB,
|
||||
0x000000BB, 0x000011BB, 0x000022BB, 0x000033BB, 0x000044BB, 0x000055BB, 0x000066BB, 0x000077BB, 0x000088BB,
|
||||
0x000099BB, 0x0000AABB, 0x0000BBBB, 0x0000BBAA, 0x0000BB99, 0x0000BB88, 0x0000BB77, 0x0000BB66, 0x0000BB55,
|
||||
0x0000BB44, 0x0000BB33, 0x0000BB22, 0x0000BB11, 0x0000BB00, 0x0011BB00, 0x0022BB00, 0x0033BB00, 0x0044BB00,
|
||||
0x0055BB00, 0x0066BB00, 0x0077BB00, 0x0088BB00, 0x0099BB00, 0x00AABB00, 0x00BBBB00, 0x00BBAA00, 0x00BB9900,
|
||||
0x00BB8800, 0x00BB7700, 0x00BB6600, 0x00BB5500, 0x00BB4400, 0x00BB3300, 0x00BB2200, 0x00BB1100, 0x00770000,
|
||||
0x00770011, 0x00770022, 0x00770033, 0x00770044, 0x00770055, 0x00770066, 0x00770077, 0x00660077, 0x00550077,
|
||||
0x00440077, 0x00330077, 0x00220077, 0x00110077, 0x00000077, 0x00001177, 0x00002277, 0x00003377, 0x00004477,
|
||||
0x00005577, 0x00006677, 0x00007777, 0x00007766, 0x00007755, 0x00007744, 0x00007733, 0x00007722, 0x00007711,
|
||||
0x00007700, 0x00117700, 0x00227700, 0x00337700, 0x00447700, 0x00557700, 0x00667700, 0x00777700, 0x00776600,
|
||||
0x00775500, 0x00774400, 0x00773300, 0x00772200, 0x00771100, 0x00440000, 0x00440011, 0x00440022, 0x00440033,
|
||||
0x00440044, 0x00330044, 0x00220044, 0x00110044, 0x00000044, 0x00001144, 0x00002244, 0x00003344, 0x00004444,
|
||||
0x00004433, 0x00004422, 0x00004411, 0x00004400, 0x00114400, 0x00224400, 0x00334400, 0x00444400, 0x00443300,
|
||||
0x00442200, 0x00441100, 0x00FFFFFF, 0x00000000
|
||||
};
|
||||
|
||||
/// <summary>Palette for alpha mask</summary>
|
||||
public static int[] PaletteMask = {0x00000000, -16777216};
|
||||
|
||||
public static byte[] FlipPlane(byte[] data, int width)
|
||||
{
|
||||
byte[] flipped = new byte[data.Length];
|
||||
int pos = 0;
|
||||
int w = width / 8;
|
||||
|
||||
// This flips the image.
|
||||
while(pos < flipped.Length)
|
||||
{
|
||||
for(int i = 0; i < w; i++)
|
||||
{
|
||||
byte b = data[pos + i];
|
||||
flipped[pos + i] = (byte)(b >> 7);
|
||||
flipped[pos + i] += (byte)((b >> 5) & 0x02);
|
||||
flipped[pos + i] += (byte)((b >> 3) & 0x04);
|
||||
flipped[pos + i] += (byte)((b >> 1) & 0x08);
|
||||
flipped[pos + i] += (byte)((b << 1) & 0x10);
|
||||
flipped[pos + i] += (byte)((b << 3) & 0x20);
|
||||
flipped[pos + i] += (byte)((b << 5) & 0x40);
|
||||
flipped[pos + i] += (byte)(b << 7);
|
||||
}
|
||||
|
||||
pos += w;
|
||||
}
|
||||
|
||||
return flipped;
|
||||
}
|
||||
|
||||
public static int[] PlaneToRaster(byte[] data, byte[] mask, int width, int height, int planes)
|
||||
{
|
||||
int[] pixels = PlaneToRaster(data, width, height, planes);
|
||||
int[] masked = PlaneToRasterIndexed(mask, width, height, 1);
|
||||
|
||||
for(int i = 0; i < pixels.Length; i++) pixels[i] += PaletteMask[masked[i]];
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
public static int[] PlaneToRaster(byte[] data, int width, int height, int planes)
|
||||
{
|
||||
int[] pixels = PlaneToRasterIndexed(data, width, height, planes);
|
||||
int[] palette = null;
|
||||
|
||||
switch(planes)
|
||||
{
|
||||
case 1:
|
||||
palette = Palette1;
|
||||
break;
|
||||
case 2:
|
||||
palette = Palette2;
|
||||
break;
|
||||
case 3:
|
||||
palette = Palette3;
|
||||
break;
|
||||
case 4:
|
||||
palette = Palette4;
|
||||
break;
|
||||
case 8:
|
||||
palette = Palette8;
|
||||
break;
|
||||
// What to do with other pixel formats?
|
||||
default: return null;
|
||||
}
|
||||
|
||||
for(int i = 0; i < pixels.Length; i++) pixels[i] = palette[pixels[i]];
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
public static int[] PlaneToRasterIndexed(byte[] data, int width, int height, int planes)
|
||||
{
|
||||
// No more than 24-bit RGB
|
||||
if(planes > 24) return null;
|
||||
|
||||
int planeSize = width * height / 8;
|
||||
|
||||
int[] pixels = new int[width * height];
|
||||
for(int p = 0; p < planes; p++)
|
||||
{
|
||||
int pixNum = 0;
|
||||
|
||||
byte[] plane = new byte[planeSize];
|
||||
Array.Copy(data, p * planeSize, plane, 0, planeSize);
|
||||
plane = FlipPlane(plane, width);
|
||||
|
||||
for(int b = 0; b < planeSize; b++)
|
||||
{
|
||||
for(int i = 0; i < 8; i++) pixels[pixNum++] |= ((plane[b] & (1 << i)) >> i) << p;
|
||||
}
|
||||
}
|
||||
|
||||
return pixels;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,13 +38,15 @@ namespace libexeinfo
|
||||
/// </summary>
|
||||
public partial class MZ : IExecutable
|
||||
{
|
||||
public GEM.ColorIcon[] GemColorIcons;
|
||||
/// <summary>
|
||||
/// Header for this executable
|
||||
/// </summary>
|
||||
internal MZHeader Header;
|
||||
public GEM.GemResourceExtension ResourceExtension;
|
||||
public GEM.GemResourceHeader ResourceHeader;
|
||||
public GEM.TreeObjectNode[] ResourceObjectRoots;
|
||||
public Stream resourceStream;
|
||||
public Stream ResourceStream;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:libexeinfo.MZ" /> class.
|
||||
@@ -76,7 +78,7 @@ namespace libexeinfo
|
||||
resourceFilePath = testPath + ".RSC";
|
||||
|
||||
if(resourceFilePath != null)
|
||||
resourceStream = File.Open(resourceFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
ResourceStream = File.Open(resourceFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
|
||||
Initialize();
|
||||
}
|
||||
@@ -142,27 +144,37 @@ namespace libexeinfo
|
||||
|
||||
Type = "DOS Executable (MZ)";
|
||||
|
||||
if(resourceStream == null) return;
|
||||
if(ResourceStream == null) return;
|
||||
|
||||
buffer = new byte[Marshal.SizeOf(typeof(GEM.GemResourceHeader))];
|
||||
resourceStream.Position = 0;
|
||||
resourceStream.Read(buffer, 0, buffer.Length);
|
||||
ResourceStream.Position = 0;
|
||||
ResourceStream.Read(buffer, 0, buffer.Length);
|
||||
ResourceHeader = BigEndianMarshal.ByteArrayToStructureLittleEndian<GEM.GemResourceHeader>(buffer);
|
||||
|
||||
if(ResourceHeader.rsh_vrsn != 0 && ResourceHeader.rsh_vrsn != 1 && ResourceHeader.rsh_vrsn != 4 &&
|
||||
ResourceHeader.rsh_vrsn != 5) return;
|
||||
|
||||
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.ByteArrayToStructureLittleEndian<GEM.GemResourceExtension>(buffer);
|
||||
|
||||
GemColorIcons = GEM.GetColorIcons(ResourceStream, ResourceExtension.color_ic, false, encoding);
|
||||
}
|
||||
|
||||
List<string> strings = new List<string>();
|
||||
|
||||
if(ResourceHeader.rsh_ntree > 0)
|
||||
{
|
||||
resourceStream.Position = ResourceHeader.rsh_trindex;
|
||||
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);
|
||||
ResourceStream.Read(tmp, 0, 4);
|
||||
treeOffsets[i] = BitConverter.ToInt32(tmp, 0);
|
||||
}
|
||||
|
||||
@@ -170,15 +182,15 @@ namespace libexeinfo
|
||||
|
||||
for(int i = 0; i < ResourceHeader.rsh_ntree; i++)
|
||||
{
|
||||
if(treeOffsets[i] <= 0 || treeOffsets[i] >= resourceStream.Length) continue;
|
||||
if(treeOffsets[i] <= 0 || treeOffsets[i] >= ResourceStream.Length) continue;
|
||||
|
||||
resourceStream.Position = treeOffsets[i];
|
||||
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);
|
||||
ResourceStream.Read(buffer, 0, buffer.Length);
|
||||
GEM.ObjectNode node = BigEndianMarshal.ByteArrayToStructureLittleEndian<GEM.ObjectNode>(buffer);
|
||||
nodes.Add(node);
|
||||
if(((GEM.ObjectFlags)node.ob_flags).HasFlag(GEM.ObjectFlags.Lastob)) break;
|
||||
@@ -186,18 +198,18 @@ namespace libexeinfo
|
||||
|
||||
List<short> knownNodes = new List<short>();
|
||||
ResourceObjectRoots[i] =
|
||||
GEM.ProcessResourceObject(nodes, ref knownNodes, 0, resourceStream, strings, false, encoding);
|
||||
GEM.ProcessResourceObject(nodes, ref knownNodes, 0, ResourceStream, strings, false, encoding);
|
||||
}
|
||||
}
|
||||
else if(ResourceHeader.rsh_nobs > 0)
|
||||
{
|
||||
GEM.ObjectNode[] nodes = new GEM.ObjectNode[ResourceHeader.rsh_nobs];
|
||||
|
||||
resourceStream.Position = ResourceHeader.rsh_object;
|
||||
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);
|
||||
ResourceStream.Read(buffer, 0, buffer.Length);
|
||||
nodes[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian<GEM.ObjectNode>(buffer);
|
||||
}
|
||||
|
||||
@@ -205,7 +217,7 @@ namespace libexeinfo
|
||||
ResourceObjectRoots = new GEM.TreeObjectNode[1];
|
||||
// TODO: Correct encoding?
|
||||
ResourceObjectRoots[0] =
|
||||
GEM.ProcessResourceObject(nodes, ref knownNodes, 0, resourceStream, strings, false, encoding);
|
||||
GEM.ProcessResourceObject(nodes, ref knownNodes, 0, ResourceStream, strings, false, encoding);
|
||||
}
|
||||
|
||||
if(strings.Count > 0)
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<Compile Include="GEM\Enums.cs" />
|
||||
<Compile Include="GEM\Resources.cs" />
|
||||
<Compile Include="GEM\Structs.cs" />
|
||||
<Compile Include="GEM\Vdi.cs" />
|
||||
<Compile Include="IExecutable.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="MZ\Consts.cs" />
|
||||
|
||||
Reference in New Issue
Block a user