Added MagiC resource format.

This commit is contained in:
2018-03-01 17:51:37 +00:00
parent e37b116029
commit 0f0f09ba27
6 changed files with 288 additions and 34 deletions

View File

@@ -201,7 +201,7 @@ namespace exeinfo
if(!recognized) Console.WriteLine("Executable format not recognized");
}
static void PrintGemResources(GEM.GemResourceHeader resourceHeader, IReadOnlyList<GEM.TreeObjectNode> roots,
static void PrintGemResources(GEM.MagiCResourceHeader resourceHeader, IReadOnlyList<GEM.TreeObjectNode> roots,
GEM.GemResourceExtension resourceExtension,
GEM.ColorIcon[] colorIcons)
{

View File

@@ -40,7 +40,7 @@ namespace libexeinfo
{
public GEM.ColorIcon[] GemColorIcons;
public GEM.GemResourceExtension ResourceExtension;
public GEM.GemResourceHeader ResourceHeader;
public GEM.MagiCResourceHeader ResourceHeader;
public GEM.TreeObjectNode[] ResourceObjectRoots;
public Stream ResourceStream;
@@ -133,10 +133,20 @@ namespace libexeinfo
buffer = new byte[Marshal.SizeOf(typeof(GEM.GemResourceHeader))];
ResourceStream.Position = 0;
ResourceStream.Read(buffer, 0, buffer.Length);
ResourceHeader = BigEndianMarshal.ByteArrayToStructureBigEndian<GEM.GemResourceHeader>(buffer);
GEM.GemResourceHeader gemResourceHeader =
BigEndianMarshal.ByteArrayToStructureBigEndian<GEM.GemResourceHeader>(buffer);
if(ResourceHeader.rsh_vrsn != 0 && ResourceHeader.rsh_vrsn != 1 && ResourceHeader.rsh_vrsn != 4 &&
ResourceHeader.rsh_vrsn != 5) return;
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);
}
else ResourceHeader = GEM.GemToMagiC(gemResourceHeader);
if((ResourceHeader.rsh_vrsn & 4) == 4)
{

View File

@@ -83,7 +83,7 @@ namespace libexeinfo
}
[Flags]
public enum ObjectFlags : short
public enum ObjectFlags : ushort
{
/// <summary>
/// Indicates that the user can select the object
@@ -123,7 +123,53 @@ namespace libexeinfo
/// <summary>
/// Indicates that the value in <see cref="ObjectNode.ob_spec" /> is a pointer to the actual value.
/// </summary>
Indirect = 0x0100
Indirect = 0x0100,
/// <summary>
/// Under MultiTOS this object creates a three-dimensional object.
/// </summary>
Fl3Dind = 0x0200,
/// <summary>
/// Pressing the [Esc] key corresponds to the selection of the object with this flag.
/// </summary>
EscCancel = 0x0200,
/// <summary>
/// In 3D operation this object will be treated as an AES background object.
/// </summary>
Fl3DBak = 0x0400,
/// <summary>
/// A button with this flag uses a bitmap instead of text.
/// </summary>
BitButton = 0x0400,
/// <summary>
/// In 3D operation this object will be treated as an activator.
/// </summary>
Fl3DAct = 0x0600,
/// <summary>
/// In MultiTOS and from MagiC 5.10 this flag indicates submenus.
/// </summary>
SubMenu = 0x0800,
/// <summary>
/// Pressing the [PAGEUP] key corresponds to the selection of the first object with this flag in the dialog. Pressing
/// the [PAGEDOWN] key corresponds to the selection of the last object with this flag.
/// </summary>
Scroller = 0x0800,
/// <summary>
/// An object with this flag will be drawn with a 3D border.
/// </summary>
Flag3D = 0x1000,
/// <summary>
/// The color of the object is not a color index of the VDI, but an entry in a table with colors for designated
/// categories.
/// </summary>
UseColorCat = 0x2000,
/// <summary>
/// Sunken 3D background
/// </summary>
Fl3DBak2 = 0x4000,
/// <summary>
/// Not implemented
/// </summary>
SubMenu2 = 0x8000
}
public enum ObjectFont : short
@@ -140,7 +186,7 @@ namespace libexeinfo
}
[Flags]
public enum ObjectStates : short
public enum ObjectStates : ushort
{
/// <summary>
/// Indicates that the object is highlighted by being drawn with reversed colors
@@ -165,7 +211,25 @@ namespace libexeinfo
/// <summary>
/// Indicates that the object (usually a box) is drawn with a drop shadow
/// </summary>
Shadowed = 0x0020
Shadowed = 0x0020,
/// <summary>
/// In PC-GEM ignores icon background. As of MagiC 3 controls the underscoring of character strings.
/// </summary>
Whitebak = 0x0040,
/// <summary>
/// Indicates that the object is to be drawn with a 3D effect.
/// </summary>
Draw3D = 0x0080,
/// <summary>
/// An object with this status will be surrounded by a dashed line.
/// </summary>
Highlighted = 0x0100,
/// <summary>
/// Setting this state undoes the line by <see cref="Highlighted" />
/// </summary>
Unhighlighted = 0x0200,
Underline = 0x0F00,
Xstate = 0xF000
}
public enum ObjectTypes : short
@@ -190,7 +254,8 @@ namespace libexeinfo
/// </summary>
G_IMAGE = 23,
/// <summary>
/// A programmed defined object. Its <see cref="ObjectNode.ob_spec" /> is a pointer to a <see cref="ApplicationBlock" />
/// A programmed defined object. Its <see cref="ObjectNode.ob_spec" /> is a pointer to a
/// <see cref="ApplicationBlock" />
/// structure.
/// </summary>
G_USERDEF = 24,
@@ -238,10 +303,36 @@ namespace libexeinfo
G_TITLE = 32,
/// <summary>
/// An object that describes a color icon. Its <see cref="ObjectNode.ob_spec" /> is a pointer to an
/// <see cref="ColorIconBlock" />
/// structure.
/// <see cref="ColorIconBlock" /> structure.
/// </summary>
G_CICON = 33
G_CICON = 33,
/// <summary>
/// An object that describes a cycle button (a button which alters its text cyclically when clicked on).
/// Its <see cref="ObjectNode.ob_spec" /> is a pointer to a <see cref="SwInfoBlock" /> structure.
/// </summary>
G_SWBUTTON = 34,
/// <summary>
/// An object that describes a popup menu. Its <see cref="ObjectNode.ob_spec" /> is a pointer to a
/// <see cref="PopInfoBlock" /> structure.
/// </summary>
G_POPUP = 35,
/// <summary>
/// This object is user internally by MagiC to depict window titles.
/// </summary>
G_WINTITLE = 36,
/// <summary>
/// As of MagiC 5.20 an editable object implemented in a shared library. Its <see cref="ObjectNode.ob_spec" /> is a
/// pointer to the object.
/// </summary>
G_EDIT = 37,
/// <summary>
/// Similar to <see cref="G_STRING" />, but any keyboard shortcut present is split off and output ranged right.
/// </summary>
G_SHORTCUT = 38,
/// <summary>
/// Scrolling list
/// </summary>
G_SLIST = 39
}
/// <summary>

View File

@@ -157,8 +157,10 @@ namespace libexeinfo
buffer = new byte[Marshal.SizeOf(typeof(ApplicationBlock))];
resourceStream.Read(buffer, 0, buffer.Length);
node.ApplicationBlock = bigEndian
? BigEndianMarshal.ByteArrayToStructureBigEndian<ApplicationBlock>(buffer)
: BigEndianMarshal.ByteArrayToStructureLittleEndian<ApplicationBlock>(buffer);
? BigEndianMarshal
.ByteArrayToStructureBigEndian<ApplicationBlock>(buffer)
: BigEndianMarshal
.ByteArrayToStructureLittleEndian<ApplicationBlock>(buffer);
break;
case ObjectTypes.G_ICON:
if(node.data <= 0 || node.data >= resourceStream.Length) break;
@@ -178,6 +180,7 @@ namespace libexeinfo
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;
@@ -492,5 +495,30 @@ namespace libexeinfo
return colorIcons;
}
public static MagiCResourceHeader GemToMagiC(GemResourceHeader header)
{
return new MagiCResourceHeader
{
rsh_vrsn = header.rsh_vrsn,
rsh_object = header.rsh_object,
rsh_tedinfo = header.rsh_tedinfo,
rsh_iconblk = header.rsh_iconblk,
rsh_bitblk = header.rsh_bitblk,
rsh_frstr = header.rsh_frstr,
rsh_string = header.rsh_string,
rsh_imdata = header.rsh_imdata,
rsh_frimg = header.rsh_frimg,
rsh_trindex = header.rsh_trindex,
rsh_nobs = header.rsh_nobs,
rsh_ntree = header.rsh_ntree,
rsh_nted = header.rsh_nted,
rsh_nib = header.rsh_nib,
rsh_nbb = header.rsh_nbb,
rsh_nstring = header.rsh_nstring,
rsh_nimages = header.rsh_nimages,
rsh_rssize = header.rsh_rssize
};
}
}
}

View File

@@ -110,6 +110,88 @@ namespace libexeinfo
public short rsh_rssize;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MagiCResourceHeader
{
/// <summary>
/// Must be version 3
/// </summary>
public short rsh_vrsn;
/// <summary>
/// Not used
/// </summary>
public short rsh_extvrsn;
/// <summary>
/// Contains an offset from the beginning of the file to the OBJECT structures.
/// </summary>
public int rsh_object;
/// <summary>
/// Contains an offset from the beginning of the file to the TEDINFO structures.
/// </summary>
public int rsh_tedinfo;
/// <summary>
/// Contains an offset from the beginning of the file to the ICONBLK structures.
/// </summary>
public int rsh_iconblk;
/// <summary>
/// Contains an offset from the beginning of the file to the BITBLK structures.
/// </summary>
public int rsh_bitblk;
/// <summary>
/// Contains an offset from the beginning of the file to the string pointer table.
/// </summary>
public int rsh_frstr;
/// <summary>
/// Contains an offset from the beginning of the file to the string data.
/// </summary>
public int rsh_string;
/// <summary>
/// Contains an offset from the beginning of the file to the image data.
/// </summary>
public int rsh_imdata;
/// <summary>
/// Contains an offset from the beginning of the file to the image pointer table.
/// </summary>
public int rsh_frimg;
/// <summary>
/// Contains an offset from the beginning of the file to the tree pointer table.
/// </summary>
public int rsh_trindex;
/// <summary>
/// Number of OBJECTs in the file.
/// </summary>
public int rsh_nobs;
/// <summary>
/// Number of object trees in the file.
/// </summary>
public int rsh_ntree;
/// <summary>
/// Number of TEDINFOs in the file.
/// </summary>
public int rsh_nted;
/// <summary>
/// Number of ICONBLKs in the file.
/// </summary>
public int rsh_nib;
/// <summary>
/// Number of BITBLKs in the file.
/// </summary>
public int rsh_nbb;
/// <summary>
/// Number of free strings in the file.
/// </summary>
public int rsh_nstring;
/// <summary>
/// Number of free images in the file.
/// </summary>
public int rsh_nimages;
/// <summary>
/// Size of the resource file (in bytes). Note that this is the size of the old format resource file. If the newer
/// format file is being used then this value can be used as an offset to the extension array.
/// </summary>
public int rsh_rssize;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct GemResourceExtension
{
@@ -191,6 +273,7 @@ namespace libexeinfo
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class TreeObjectNode
{
public ApplicationBlock ApplicationBlock;
public BitmapBlock BitBlock;
public TreeObjectNode child;
public ColorIcon ColorIcon;
@@ -204,7 +287,6 @@ namespace libexeinfo
public TextBlock TedInfo;
public ObjectTypes type;
public ApplicationBlock ApplicationBlock;
public short width;
public short x;
public short y;
@@ -432,7 +514,8 @@ namespace libexeinfo
/// <summary>
/// The APPLBLK structure is used to locate and call an application-defined routine that will draw and/or change an
/// object. The object type G_USERDEF points with its <see cref="ObjectNode.ob_spec" /> pointer to an USERBLK structure.
/// object. The object type G_USERDEF points with its <see cref="ObjectNode.ob_spec" /> pointer to an USERBLK
/// structure.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ApplicationBlock
@@ -442,7 +525,7 @@ namespace libexeinfo
/// </summary>
public int ab_code;
/// <summary>
/// A pointer to a <see cref="ParameterBlock"/>
/// A pointer to a <see cref="ParameterBlock" />
/// </summary>
public int ab_parm;
}
@@ -502,12 +585,14 @@ namespace libexeinfo
/// </summary>
public short pb_hc;
/// <summary>
/// A long value, identical to <see cref="ApplicationBlock.ab_parm" />, that is passed to the application when it is time for
/// A long value, identical to <see cref="ApplicationBlock.ab_parm" />, that is passed to the application when it is
/// time for
/// the application to draw or change the object. Low word.
/// </summary>
public short pb_parm_low;
/// <summary>
/// A long value, identical to <see cref="ApplicationBlock.ab_parm" />, that is passed to the application when it is time for
/// A long value, identical to <see cref="ApplicationBlock.ab_parm" />, that is passed to the application when it is
/// time for
/// the application to draw or change the object. High word.
/// </summary>
public short pb_parm_high;
@@ -545,5 +630,35 @@ namespace libexeinfo
/// </summary>
public int next_res;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PopInfoBlock
{
/// <summary>
/// Points to the start of an object tree that corresponds to the popup menu
/// </summary>
public int tree;
/// <summary>
/// Current object of
/// </summary>
public short obnum;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SwInfoBlock
{
/// <summary>
/// Points to the string
/// </summary>
public int str;
/// <summary>
/// Index of the current character string
/// </summary>
public short num;
/// <summary>
/// Maximum permitted number
/// </summary>
public short maxnum;
}
}
}

View File

@@ -44,7 +44,7 @@ namespace libexeinfo
/// </summary>
internal MZHeader Header;
public GEM.GemResourceExtension ResourceExtension;
public GEM.GemResourceHeader ResourceHeader;
public GEM.MagiCResourceHeader ResourceHeader;
public GEM.TreeObjectNode[] ResourceObjectRoots;
public Stream ResourceStream;
@@ -149,10 +149,20 @@ namespace libexeinfo
buffer = new byte[Marshal.SizeOf(typeof(GEM.GemResourceHeader))];
ResourceStream.Position = 0;
ResourceStream.Read(buffer, 0, buffer.Length);
ResourceHeader = BigEndianMarshal.ByteArrayToStructureLittleEndian<GEM.GemResourceHeader>(buffer);
GEM.GemResourceHeader gemResourceHeader =
BigEndianMarshal.ByteArrayToStructureLittleEndian<GEM.GemResourceHeader>(buffer);
if(ResourceHeader.rsh_vrsn != 0 && ResourceHeader.rsh_vrsn != 1 && ResourceHeader.rsh_vrsn != 4 &&
ResourceHeader.rsh_vrsn != 5) return;
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.ByteArrayToStructureLittleEndian<GEM.MagiCResourceHeader>(buffer);
}
else ResourceHeader = GEM.GemToMagiC(gemResourceHeader);
if((ResourceHeader.rsh_vrsn & 4) == 4)
{