mirror of
https://github.com/claunia/libexeinfo.git
synced 2025-12-16 19:14:24 +00:00
Add resource decoders for all GEM resources but the color icon.
This commit is contained in:
@@ -27,7 +27,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using libexeinfo;
|
using libexeinfo;
|
||||||
|
|
||||||
@@ -121,48 +121,88 @@ namespace exeinfo
|
|||||||
foreach(NE.ResidentName name in ((NE)neExe).NonResidentNames)
|
foreach(NE.ResidentName name in ((NE)neExe).NonResidentNames)
|
||||||
Console.WriteLine("\t\t{0} at index {1}", name.name, name.entryTableIndex);
|
Console.WriteLine("\t\t{0} at index {1}", name.name, name.entryTableIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(neExe.Strings != null && neExe.Strings.Any())
|
||||||
|
{
|
||||||
|
Console.WriteLine("\tStrings:");
|
||||||
|
foreach(string str in neExe.Strings) Console.WriteLine("\t\t{0}", str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(lxExe.Recognized)
|
else if(lxExe.Recognized)
|
||||||
{
|
{
|
||||||
recognized = true;
|
recognized = true;
|
||||||
Console.Write(lxExe.Information);
|
Console.Write(lxExe.Information);
|
||||||
|
|
||||||
|
if(lxExe.Strings != null && lxExe.Strings.Any())
|
||||||
|
{
|
||||||
|
Console.WriteLine("\tStrings:");
|
||||||
|
foreach(string str in lxExe.Strings) Console.WriteLine("\t\t{0}", str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(peExe.Recognized)
|
else if(peExe.Recognized)
|
||||||
{
|
{
|
||||||
recognized = true;
|
recognized = true;
|
||||||
Console.Write(peExe.Information);
|
Console.Write(peExe.Information);
|
||||||
|
|
||||||
|
if(peExe.Strings != null && peExe.Strings.Any())
|
||||||
|
{
|
||||||
|
Console.WriteLine("\tStrings:");
|
||||||
|
foreach(string str in peExe.Strings) Console.WriteLine("\t\t{0}", str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(mzExe.Recognized)
|
else if(mzExe.Recognized)
|
||||||
{
|
{
|
||||||
recognized = true;
|
recognized = true;
|
||||||
Console.Write(mzExe.Information);
|
Console.Write(mzExe.Information);
|
||||||
|
|
||||||
|
if(mzExe.Strings != null && mzExe.Strings.Any())
|
||||||
|
{
|
||||||
|
Console.WriteLine("\tStrings:");
|
||||||
|
foreach(string str in mzExe.Strings) Console.WriteLine("\t\t{0}", str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(stExe.Recognized)
|
if(stExe.Recognized)
|
||||||
{
|
{
|
||||||
recognized = true;
|
recognized = true;
|
||||||
Console.Write(stExe.Information);
|
Console.Write(stExe.Information);
|
||||||
if(((AtariST)stExe).resourceStream != null ||
|
if(((AtariST)stExe).resourceStream != null || ((AtariST)stExe).ResourceHeader.rsh_vrsn != 0 &&
|
||||||
(((AtariST)stExe).ResourceHeader.rsh_vrsn != 0 && ((AtariST)stExe).ResourceHeader.rsh_vrsn != 1 &&
|
((AtariST)stExe).ResourceHeader.rsh_vrsn != 1 &&
|
||||||
((AtariST)stExe).ResourceHeader.rsh_vrsn != 4 && ((AtariST)stExe).ResourceHeader.rsh_vrsn != 5))
|
((AtariST)stExe).ResourceHeader.rsh_vrsn != 4 &&
|
||||||
|
((AtariST)stExe).ResourceHeader.rsh_vrsn != 5)
|
||||||
{
|
{
|
||||||
Console.WriteLine("\tResources:");
|
Console.WriteLine("\tResources:");
|
||||||
Console.WriteLine("\t\t{0} OBJECTs start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nobs, ((AtariST)stExe).ResourceHeader.rsh_object);
|
Console.WriteLine("\t\t{0} OBJECTs start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nobs,
|
||||||
Console.WriteLine("\t\t{0} TEDINFOs start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nted, ((AtariST)stExe).ResourceHeader.rsh_tedinfo);
|
((AtariST)stExe).ResourceHeader.rsh_object);
|
||||||
Console.WriteLine("\t\t{0} ICONBLKs start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nib, ((AtariST)stExe).ResourceHeader.rsh_iconblk);
|
Console.WriteLine("\t\t{0} TEDINFOs start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nted,
|
||||||
Console.WriteLine("\t\t{0} BITBLKs start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nbb, ((AtariST)stExe).ResourceHeader.rsh_bitblk);
|
((AtariST)stExe).ResourceHeader.rsh_tedinfo);
|
||||||
Console.WriteLine("\t\t{0} object trees start at {1}", ((AtariST)stExe).ResourceHeader.rsh_ntree, ((AtariST)stExe).ResourceHeader.rsh_trindex);
|
Console.WriteLine("\t\t{0} ICONBLKs start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nib,
|
||||||
Console.WriteLine("\t\t{0} free strings start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nstring, ((AtariST)stExe).ResourceHeader.rsh_frstr);
|
((AtariST)stExe).ResourceHeader.rsh_iconblk);
|
||||||
Console.WriteLine("\t\t{0} free images start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nimages, ((AtariST)stExe).ResourceHeader.rsh_frimg);
|
Console.WriteLine("\t\t{0} BITBLKs start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nbb,
|
||||||
|
((AtariST)stExe).ResourceHeader.rsh_bitblk);
|
||||||
|
Console.WriteLine("\t\t{0} object trees start at {1}", ((AtariST)stExe).ResourceHeader.rsh_ntree,
|
||||||
|
((AtariST)stExe).ResourceHeader.rsh_trindex);
|
||||||
|
Console.WriteLine("\t\t{0} free strings start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nstring,
|
||||||
|
((AtariST)stExe).ResourceHeader.rsh_frstr);
|
||||||
|
Console.WriteLine("\t\t{0} free images start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nimages,
|
||||||
|
((AtariST)stExe).ResourceHeader.rsh_frimg);
|
||||||
Console.WriteLine("\t\tString data starts at {0}", ((AtariST)stExe).ResourceHeader.rsh_string);
|
Console.WriteLine("\t\tString data starts at {0}", ((AtariST)stExe).ResourceHeader.rsh_string);
|
||||||
Console.WriteLine("\t\tImage data starts at {0}", ((AtariST)stExe).ResourceHeader.rsh_imdata);
|
Console.WriteLine("\t\tImage data starts at {0}", ((AtariST)stExe).ResourceHeader.rsh_imdata);
|
||||||
Console.WriteLine("\t\tStandard resource data is {0} bytes", ((AtariST)stExe).ResourceHeader.rsh_rssize);
|
Console.WriteLine("\t\tStandard resource data is {0} bytes",
|
||||||
|
((AtariST)stExe).ResourceHeader.rsh_rssize);
|
||||||
|
|
||||||
if(((AtariST)stExe).ResourceObjectRoot != null)
|
if(((AtariST)stExe).ResourceObjectRoots != null && ((AtariST)stExe).ResourceObjectRoots.Length > 0)
|
||||||
{
|
for(int i = 0; i < ((AtariST)stExe).ResourceObjectRoots.Length; i++)
|
||||||
Console.WriteLine("\tObject tree:");
|
{
|
||||||
PrintAtariResourceTree(((AtariST)stExe).ResourceObjectRoot, 2);
|
Console.WriteLine("\tObject tree {0}:", i);
|
||||||
}
|
PrintAtariResourceTree(((AtariST)stExe).ResourceObjectRoots[i], 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stExe.Strings != null && stExe.Strings.Any())
|
||||||
|
{
|
||||||
|
Console.WriteLine("\tStrings:");
|
||||||
|
foreach(string str in stExe.Strings) Console.WriteLine("\t\t{0}", str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,6 +210,12 @@ namespace exeinfo
|
|||||||
{
|
{
|
||||||
recognized = true;
|
recognized = true;
|
||||||
Console.Write(coffExe.Information);
|
Console.Write(coffExe.Information);
|
||||||
|
|
||||||
|
if(coffExe.Strings != null && coffExe.Strings.Any())
|
||||||
|
{
|
||||||
|
Console.WriteLine("\tStrings:");
|
||||||
|
foreach(string str in coffExe.Strings) Console.WriteLine("\t\t{0}", str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!recognized) Console.WriteLine("Executable format not recognized");
|
if(!recognized) Console.WriteLine("Executable format not recognized");
|
||||||
@@ -177,11 +223,106 @@ namespace exeinfo
|
|||||||
|
|
||||||
static void PrintAtariResourceTree(AtariST.TreeObjectNode node, int level)
|
static void PrintAtariResourceTree(AtariST.TreeObjectNode node, int level)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < level; i++)
|
for(int i = 0; i < level; i++) Console.Write("\t");
|
||||||
Console.Write("\t");
|
|
||||||
|
|
||||||
Console.WriteLine("{0} ({1} {2}) data = {3}, coordinates ({4},{5}) size {6}x{7}", node.type, node.flags,
|
string thickStr;
|
||||||
node.state, node.data, node.x, node.y, node.width, node.height);
|
|
||||||
|
switch(node.type)
|
||||||
|
{
|
||||||
|
case AtariST.ObjectTypes.G_BOX:
|
||||||
|
case AtariST.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}",
|
||||||
|
node.type, node.flags, node.state,
|
||||||
|
(AtariST.ObjectColors)((node.data & 0xFFFF & AtariST.BorderColorMask) >> 12),
|
||||||
|
(AtariST.ObjectColors)((node.data & 0xFFFF & AtariST.TextColorMask) >> 8),
|
||||||
|
(AtariST.ObjectColors)((node.data & 0xFFFF & AtariST.InsideColorMask) >> 8),
|
||||||
|
(AtariST.ObjectFillPattern)((node.data & 0xFFFF & AtariST.FillPatternMask) >> 4),
|
||||||
|
(node.data & 0xFFFF & AtariST.TransparentColor) != 0
|
||||||
|
? "transparent"
|
||||||
|
: "replace",
|
||||||
|
node.x, node.y, node.width, node.height);
|
||||||
|
break;
|
||||||
|
case AtariST.ObjectTypes.G_BOXCHAR:
|
||||||
|
sbyte thickness = (sbyte)((node.data & 0xFF0000) >> 16);
|
||||||
|
|
||||||
|
if(thickness < 0) thickStr = $"{thickness * -1} pixels outward thickness";
|
||||||
|
else if(thickness > 0)
|
||||||
|
thickStr = $"{thickness} pixels inward thickness";
|
||||||
|
else
|
||||||
|
thickStr = "no thickness";
|
||||||
|
|
||||||
|
char character =
|
||||||
|
Claunia.Encoding.Encoding.AtariSTEncoding.GetString(new[]
|
||||||
|
{
|
||||||
|
(byte)((node.data & 0xFF000000) >> 24)
|
||||||
|
})[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,
|
||||||
|
(AtariST.ObjectColors)((node.data & 0xFFFF & AtariST.BorderColorMask) >> 12),
|
||||||
|
(AtariST.ObjectColors)((node.data & 0xFFFF & AtariST.TextColorMask) >> 8),
|
||||||
|
(AtariST.ObjectColors)((node.data & 0xFFFF & AtariST.InsideColorMask) >> 8),
|
||||||
|
(AtariST.ObjectFillPattern)((node.data & 0xFFFF & AtariST.FillPatternMask) >> 4),
|
||||||
|
(node.data & 0xFFFF & AtariST.TransparentColor) != 0
|
||||||
|
? "transparent"
|
||||||
|
: "replace",
|
||||||
|
thickStr, character, node.x, node.y, node.width, node.height);
|
||||||
|
break;
|
||||||
|
case AtariST.ObjectTypes.G_BUTTON:
|
||||||
|
case AtariST.ObjectTypes.G_STRING:
|
||||||
|
case AtariST.ObjectTypes.G_TITLE:
|
||||||
|
Console.WriteLine("{0} ({1} {2}), coordinates ({3},{4}) size {5}x{6}: {7}", node.type, node.flags,
|
||||||
|
node.state, node.x, node.y, node.width, node.height, node.String);
|
||||||
|
break;
|
||||||
|
case AtariST.ObjectTypes.G_TEXT:
|
||||||
|
case AtariST.ObjectTypes.G_BOXTEXT:
|
||||||
|
case AtariST.ObjectTypes.G_FTEXT:
|
||||||
|
case AtariST.ObjectTypes.G_FBOXTEXT:
|
||||||
|
if(node.TedInfo == null) goto default;
|
||||||
|
|
||||||
|
if(node.TedInfo.Thickness < 0)
|
||||||
|
thickStr = $"{node.TedInfo.Thickness * -1} pixels outward thickness";
|
||||||
|
else if(node.TedInfo.Thickness > 0)
|
||||||
|
thickStr = $"{node.TedInfo.Thickness} pixels inward thickness";
|
||||||
|
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}\"",
|
||||||
|
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,
|
||||||
|
node.TedInfo.Transparency ? "transparent" : "replace", node.TedInfo.Text,
|
||||||
|
node.TedInfo.Validation, node.TedInfo.Template);
|
||||||
|
break;
|
||||||
|
case AtariST.ObjectTypes.G_IMAGE:
|
||||||
|
if(node.BitBlock == null) goto default;
|
||||||
|
|
||||||
|
Console.WriteLine("{0} ({1} {2}), coordinates ({3},{4}) size {5}x{6}, colored {7}, {8} bytes", node.type,
|
||||||
|
node.flags, node.state, node.BitBlock.X, node.BitBlock.Y, node.BitBlock.Width,
|
||||||
|
node.BitBlock.Height, node.BitBlock.Color, node.BitBlock.Data?.Length);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
case AtariST.ObjectTypes.G_USERDEF: break;*/
|
||||||
|
case AtariST.ObjectTypes.G_ICON:
|
||||||
|
if(node.IconBlock == null) goto default;
|
||||||
|
|
||||||
|
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", node.type, node.flags, node.state,
|
||||||
|
node.IconBlock.X, node.IconBlock.Y, node.IconBlock.Width, node.IconBlock.Height,
|
||||||
|
node.IconBlock.ForegroundColor, node.IconBlock.BackgroundColor,
|
||||||
|
node.IconBlock.Character, node.IconBlock.CharX, node.IconBlock.CharY,
|
||||||
|
node.IconBlock.Data?.Length, node.IconBlock.Text, node.IconBlock.TextX,
|
||||||
|
node.IconBlock.TextY, node.IconBlock.TextWidth, node.IconBlock.TextHeight);
|
||||||
|
|
||||||
|
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) PrintAtariResourceTree(node.child, level + 1);
|
if(node.child != null) PrintAtariResourceTree(node.child, level + 1);
|
||||||
|
|
||||||
|
|||||||
4
exeinfo/packages.config
Normal file
4
exeinfo/packages.config
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Claunia.Encoding" version="1.4.0" targetFramework="net461" />
|
||||||
|
</packages>
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace libexeinfo
|
namespace libexeinfo
|
||||||
@@ -102,10 +103,10 @@ namespace libexeinfo
|
|||||||
public IEnumerable<Architecture> Architectures => new[] {Architecture.M68K};
|
public IEnumerable<Architecture> Architectures => new[] {Architecture.M68K};
|
||||||
public OperatingSystem RequiredOperatingSystem =>
|
public OperatingSystem RequiredOperatingSystem =>
|
||||||
new OperatingSystem {Name = Header.mint == MINT_SIGNATURE ? "MiNT" : "Atari TOS"};
|
new OperatingSystem {Name = Header.mint == MINT_SIGNATURE ? "MiNT" : "Atari TOS"};
|
||||||
public IEnumerable<string> Strings { get; }
|
public IEnumerable<string> Strings { get; private set; }
|
||||||
public Stream resourceStream;
|
public Stream resourceStream;
|
||||||
public AtariResourceHeader ResourceHeader;
|
public AtariResourceHeader ResourceHeader;
|
||||||
public TreeObjectNode ResourceObjectRoot;
|
public TreeObjectNode[] ResourceObjectRoots;
|
||||||
|
|
||||||
void Initialize()
|
void Initialize()
|
||||||
{
|
{
|
||||||
@@ -132,20 +133,63 @@ namespace libexeinfo
|
|||||||
|
|
||||||
if(ResourceHeader.rsh_vrsn != 0 && ResourceHeader.rsh_vrsn != 1 && ResourceHeader.rsh_vrsn != 4 && ResourceHeader.rsh_vrsn != 5) return;
|
if(ResourceHeader.rsh_vrsn != 0 && ResourceHeader.rsh_vrsn != 1 && ResourceHeader.rsh_vrsn != 4 && ResourceHeader.rsh_vrsn != 5) return;
|
||||||
|
|
||||||
if(ResourceHeader.rsh_nobs > 0)
|
List<string> strings = new List<string>();
|
||||||
|
|
||||||
|
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 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<ObjectNode> nodes = new List<ObjectNode>();
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
buffer = new byte[Marshal.SizeOf(typeof(ObjectNode))];
|
||||||
|
resourceStream.Read(buffer, 0, buffer.Length);
|
||||||
|
ObjectNode node = BigEndianMarshal.ByteArrayToStructureBigEndian<ObjectNode>(buffer);
|
||||||
|
nodes.Add(node);
|
||||||
|
if(((ObjectFlags)node.ob_flags).HasFlag(ObjectFlags.Lastob)) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<short> knownNodes = new List<short>();
|
||||||
|
ResourceObjectRoots[i] = ProcessResourceObject(nodes, ref knownNodes, 0, resourceStream, strings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(ResourceHeader.rsh_nobs > 0)
|
||||||
{
|
{
|
||||||
ObjectNode[] nodes = new ObjectNode[ResourceHeader.rsh_nobs];
|
ObjectNode[] nodes = new ObjectNode[ResourceHeader.rsh_nobs];
|
||||||
|
|
||||||
resourceStream.Position = ResourceHeader.rsh_object;
|
resourceStream.Position = ResourceHeader.rsh_object;
|
||||||
for(short i = 0; i < ResourceHeader.rsh_nobs; i++)
|
for(short i = 0; i < ResourceHeader.rsh_nobs; i++)
|
||||||
{
|
{
|
||||||
buffer = new byte[Marshal.SizeOf(typeof(ObjectNode))];
|
buffer = new byte[Marshal.SizeOf(typeof(ObjectNode))];
|
||||||
resourceStream.Read(buffer, 0, buffer.Length);
|
resourceStream.Read(buffer, 0, buffer.Length);
|
||||||
nodes[i] = BigEndianMarshal.ByteArrayToStructureBigEndian<ObjectNode>(buffer);
|
nodes[i] = BigEndianMarshal.ByteArrayToStructureBigEndian<ObjectNode>(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<short> knownNodes = new List<short>();
|
List<short> knownNodes = new List<short>();
|
||||||
ResourceObjectRoot = ProcessResourceObject(nodes, ref knownNodes, 0);
|
ResourceObjectRoots = new TreeObjectNode[1];
|
||||||
|
ResourceObjectRoots[0] = ProcessResourceObject(nodes, ref knownNodes, 0, resourceStream, strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strings.Count > 0)
|
||||||
|
{
|
||||||
|
strings.Sort();
|
||||||
|
Strings = strings.Distinct();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ namespace libexeinfo
|
|||||||
/// An object that describes a color icon. Its <see cref="ObjectNode.ob_spec" /> is a pointer to an <see cref="ColorIconBlock" />
|
/// An object that describes a color icon. Its <see cref="ObjectNode.ob_spec" /> is a pointer to an <see cref="ColorIconBlock" />
|
||||||
/// structure.
|
/// structure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
G_CICON = 31,
|
G_CICON = 33,
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
@@ -177,55 +177,68 @@ namespace libexeinfo
|
|||||||
|
|
||||||
public enum ObjectColors : byte
|
public enum ObjectColors : byte
|
||||||
{
|
{
|
||||||
White = 0,
|
White = 0,
|
||||||
Black = 1,
|
Black = 1,
|
||||||
Red = 2,
|
Red = 2,
|
||||||
Green = 3,
|
Green = 3,
|
||||||
Blue = 4,
|
Blue = 4,
|
||||||
Cyan = 5,
|
Cyan = 5,
|
||||||
Yellow = 6,
|
Yellow = 6,
|
||||||
Magenta = 7,
|
Magenta = 7,
|
||||||
White2 = 8,
|
White2 = 8,
|
||||||
Black2 = 9,
|
Black2 = 9,
|
||||||
LightRed = 10,
|
LightRed = 10,
|
||||||
LightGreen = 11,
|
LightGreen = 11,
|
||||||
LightBlue = 12,
|
LightBlue = 12,
|
||||||
LightCyan = 13,
|
LightCyan = 13,
|
||||||
LightYellow = 14,
|
LightYellow = 14,
|
||||||
LightMagenta = 15
|
LightMagenta = 15
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ObjectFillPattern : byte
|
public enum ObjectFillPattern : byte
|
||||||
{
|
{
|
||||||
Hollow = 0,
|
Hollow = 0,
|
||||||
Dither1 = 1,
|
Dither1 = 1,
|
||||||
Dither2 = 2,
|
Dither2 = 2,
|
||||||
Dither3 = 3,
|
Dither3 = 3,
|
||||||
Dither4 = 4,
|
Dither4 = 4,
|
||||||
Dither5 = 5,
|
Dither5 = 5,
|
||||||
Dither6 = 6,
|
Dither6 = 6,
|
||||||
Solid = 7,
|
Solid = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ObjectJustification : short
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Right = 1,
|
||||||
|
Center = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ObjectFont : short
|
||||||
|
{
|
||||||
|
System = 3,
|
||||||
|
Small = 5
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Mask for border <see cref="ObjectColors"/>
|
/// Mask for border <see cref="ObjectColors"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
const ushort BorderColorMask = 0xF000;
|
public const ushort BorderColorMask = 0xF000;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Mask for text <see cref="ObjectColors"/>
|
/// Mask for text <see cref="ObjectColors"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
const ushort TextColorMask = 0x0F00;
|
public const ushort TextColorMask = 0x0F00;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If set text is in transparent mode. Replace mode otherwise.
|
/// If set text is in transparent mode. Replace mode otherwise.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
const ushort TransparentColor = 0x0080;
|
public const ushort TransparentColor = 0x0080;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Mask for <see cref="ObjectFillPattern"/>
|
/// Mask for <see cref="ObjectFillPattern"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
const ushort FillPatternMask = 0x0070;
|
public const ushort FillPatternMask = 0x0070;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Mask for inside <see cref="ObjectColors"/>
|
/// Mask for inside <see cref="ObjectColors"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
const ushort InsideColorMask = 0x000F;
|
public const ushort InsideColorMask = 0x000F;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,16 +24,18 @@
|
|||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Claunia.Encoding;
|
||||||
|
|
||||||
namespace libexeinfo
|
namespace libexeinfo
|
||||||
{
|
{
|
||||||
public partial class AtariST : IExecutable
|
public partial class AtariST : IExecutable
|
||||||
{
|
{
|
||||||
static TreeObjectNode ProcessResourceObject(IList<ObjectNode> nodes, ref List<short> knownNodes, short nodeNumber)
|
static TreeObjectNode ProcessResourceObject(IList<ObjectNode> nodes, ref List<short> knownNodes,
|
||||||
|
short nodeNumber, Stream resourceStream,
|
||||||
|
List<string> strings)
|
||||||
{
|
{
|
||||||
TreeObjectNode node = new TreeObjectNode
|
TreeObjectNode node = new TreeObjectNode
|
||||||
{
|
{
|
||||||
@@ -47,13 +49,187 @@ namespace libexeinfo
|
|||||||
height = nodes[nodeNumber].ob_height
|
height = nodes[nodeNumber].ob_height
|
||||||
};
|
};
|
||||||
|
|
||||||
|
byte[] buffer;
|
||||||
|
List<byte> chars;
|
||||||
|
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 = BigEndianMarshal.ByteArrayToStructureBigEndian<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 > 1)
|
||||||
|
{
|
||||||
|
tmpStr = new byte[ted.te_txtlen - 1];
|
||||||
|
resourceStream.Position = ted.te_ptext;
|
||||||
|
resourceStream.Read(tmpStr, 0, ted.te_txtlen - 1);
|
||||||
|
node.TedInfo.Text = Encoding.AtariSTEncoding.GetString(tmpStr);
|
||||||
|
strings.Add(node.TedInfo.Text.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ted.te_pvalid > 0 && ted.te_pvalid < resourceStream.Length && ted.te_txtlen > 1)
|
||||||
|
{
|
||||||
|
tmpStr = new byte[ted.te_txtlen - 1];
|
||||||
|
resourceStream.Position = ted.te_pvalid;
|
||||||
|
resourceStream.Read(tmpStr, 0, ted.te_txtlen - 1);
|
||||||
|
node.TedInfo.Validation = Encoding.AtariSTEncoding.GetString(tmpStr);
|
||||||
|
strings.Add(node.TedInfo.Validation.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ted.te_ptmplt > 0 && ted.te_ptmplt < resourceStream.Length && ted.te_tmplen > 1)
|
||||||
|
{
|
||||||
|
tmpStr = new byte[ted.te_tmplen - 1];
|
||||||
|
resourceStream.Position = ted.te_ptmplt;
|
||||||
|
resourceStream.Read(tmpStr, 0, ted.te_tmplen - 1);
|
||||||
|
node.TedInfo.Template = Encoding.AtariSTEncoding.GetString(tmpStr);
|
||||||
|
strings.Add(node.TedInfo.Template.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
resourceStream.Position = node.data;
|
||||||
|
buffer = new byte[Marshal.SizeOf(typeof(BitBlock))];
|
||||||
|
resourceStream.Read(buffer, 0, buffer.Length);
|
||||||
|
BitBlock bitBlock = BigEndianMarshal.ByteArrayToStructureBigEndian<BitBlock>(buffer);
|
||||||
|
|
||||||
|
node.BitBlock = new BitmapBlock
|
||||||
|
{
|
||||||
|
Color = (ObjectColors)bitBlock.bi_color,
|
||||||
|
Height = bitBlock.bi_hl,
|
||||||
|
Width = 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);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ObjectTypes.G_USERDEF:
|
||||||
|
if(node.data <= 0 || node.data >= resourceStream.Length) break;
|
||||||
|
|
||||||
|
resourceStream.Position = node.data;
|
||||||
|
buffer = new byte[Marshal.SizeOf(typeof(UserBlock))];
|
||||||
|
resourceStream.Read(buffer, 0, buffer.Length);
|
||||||
|
node.UserBlock = BigEndianMarshal.ByteArrayToStructureBigEndian<UserBlock>(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);
|
||||||
|
IconBlock iconBlock = BigEndianMarshal.ByteArrayToStructureBigEndian<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.AtariSTEncoding.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;
|
||||||
|
chars = new List<byte>();
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
int character = resourceStream.ReadByte();
|
||||||
|
|
||||||
|
if(character <= 0) break;
|
||||||
|
|
||||||
|
chars.Add((byte)character);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.IconBlock.Text = Encoding.AtariSTEncoding.GetString(chars.ToArray());
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ObjectTypes.G_CICON:
|
||||||
|
//Console.WriteLine("ColorIconBlock pointer {0}", node.data);
|
||||||
|
break;
|
||||||
|
case ObjectTypes.G_BUTTON:
|
||||||
|
case ObjectTypes.G_STRING:
|
||||||
|
case ObjectTypes.G_TITLE:
|
||||||
|
if(node.data <= 0 || node.data >= resourceStream.Length) break;
|
||||||
|
|
||||||
|
resourceStream.Position = node.data;
|
||||||
|
chars = new List<byte>();
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
int character = resourceStream.ReadByte();
|
||||||
|
|
||||||
|
if(character <= 0) break;
|
||||||
|
|
||||||
|
chars.Add((byte)character);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.String = Encoding.AtariSTEncoding.GetString(chars.ToArray());
|
||||||
|
strings.Add(node.String.Trim());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
knownNodes.Add(nodeNumber);
|
knownNodes.Add(nodeNumber);
|
||||||
|
|
||||||
if(nodes[nodeNumber].ob_head > 0 && !knownNodes.Contains(nodes[nodeNumber].ob_head))
|
if(nodes[nodeNumber].ob_head > 0 && !knownNodes.Contains(nodes[nodeNumber].ob_head))
|
||||||
node.child = ProcessResourceObject(nodes, ref knownNodes, nodes[nodeNumber].ob_head);
|
node.child = ProcessResourceObject(nodes, ref knownNodes, nodes[nodeNumber].ob_head, resourceStream,
|
||||||
|
strings);
|
||||||
|
|
||||||
if(nodes[nodeNumber].ob_next > 0 && !knownNodes.Contains(nodes[nodeNumber].ob_next))
|
if(nodes[nodeNumber].ob_next > 0 && !knownNodes.Contains(nodes[nodeNumber].ob_next))
|
||||||
node.sibling = ProcessResourceObject(nodes, ref knownNodes, nodes[nodeNumber].ob_next);
|
node.sibling =
|
||||||
|
ProcessResourceObject(nodes, ref knownNodes, nodes[nodeNumber].ob_next, resourceStream, strings);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -207,6 +207,57 @@ namespace libexeinfo
|
|||||||
public short y;
|
public short y;
|
||||||
public short width;
|
public short width;
|
||||||
public short height;
|
public short height;
|
||||||
|
|
||||||
|
public TextBlock TedInfo;
|
||||||
|
public BitmapBlock BitBlock;
|
||||||
|
public UserBlock UserBlock;
|
||||||
|
public Icon IconBlock;
|
||||||
|
public string String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TextBlock
|
||||||
|
{
|
||||||
|
public string Text;
|
||||||
|
public string Template;
|
||||||
|
public string Validation;
|
||||||
|
public ObjectFont Font;
|
||||||
|
public ObjectJustification Justification;
|
||||||
|
public short Thickness;
|
||||||
|
public ObjectColors BorderColor;
|
||||||
|
public ObjectColors TextColor;
|
||||||
|
public ObjectColors InsideColor;
|
||||||
|
public bool Transparency;
|
||||||
|
public ObjectFillPattern Fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BitmapBlock
|
||||||
|
{
|
||||||
|
public byte[] Data;
|
||||||
|
public int Width;
|
||||||
|
public int Height;
|
||||||
|
public short X;
|
||||||
|
public short Y;
|
||||||
|
public ObjectColors Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Icon
|
||||||
|
{
|
||||||
|
public byte[] Mask;
|
||||||
|
public byte[] Data;
|
||||||
|
public int Width;
|
||||||
|
public int Height;
|
||||||
|
public short X;
|
||||||
|
public short Y;
|
||||||
|
public ObjectColors BackgroundColor;
|
||||||
|
public ObjectColors ForegroundColor;
|
||||||
|
public char Character;
|
||||||
|
public short CharX;
|
||||||
|
public short CharY;
|
||||||
|
public string Text;
|
||||||
|
public short TextX;
|
||||||
|
public short TextY;
|
||||||
|
public short TextWidth;
|
||||||
|
public short TextHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user