From 0737cc8645ea63fdf78fe22e73b48b40bcc151f1 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Tue, 27 Feb 2018 04:41:20 +0000 Subject: [PATCH] Add Atari ST resource object tree walking. --- exeinfo/Program.cs | 43 ++++++++++++++++++++--------- libexeinfo/AtariST/AtariST.cs | 51 ++++++++++++++++++++++++++++++++--- libexeinfo/AtariST/Enums.cs | 8 ------ libexeinfo/AtariST/Structs.cs | 18 +++++++++++++ 4 files changed, 97 insertions(+), 23 deletions(-) diff --git a/exeinfo/Program.cs b/exeinfo/Program.cs index 3aebaeb..71c8651 100644 --- a/exeinfo/Program.cs +++ b/exeinfo/Program.cs @@ -143,20 +143,26 @@ namespace exeinfo recognized = true; Console.Write(stExe.Information); if(((AtariST)stExe).resourceStream != null || - (((AtariST)stExe).Resource.rsh_vrsn != 0 && ((AtariST)stExe).Resource.rsh_vrsn != 1 && - ((AtariST)stExe).Resource.rsh_vrsn != 4 && ((AtariST)stExe).Resource.rsh_vrsn != 5)) + (((AtariST)stExe).ResourceHeader.rsh_vrsn != 0 && ((AtariST)stExe).ResourceHeader.rsh_vrsn != 1 && + ((AtariST)stExe).ResourceHeader.rsh_vrsn != 4 && ((AtariST)stExe).ResourceHeader.rsh_vrsn != 5)) { Console.WriteLine("\tResources:"); - Console.WriteLine("\t\t{0} OBJECTs start at {1}", ((AtariST)stExe).Resource.rsh_nobs, ((AtariST)stExe).Resource.rsh_object); - Console.WriteLine("\t\t{0} TEDINFOs start at {1}", ((AtariST)stExe).Resource.rsh_nted, ((AtariST)stExe).Resource.rsh_tedinfo); - Console.WriteLine("\t\t{0} ICONBLKs start at {1}", ((AtariST)stExe).Resource.rsh_nib, ((AtariST)stExe).Resource.rsh_iconblk); - Console.WriteLine("\t\t{0} BITBLKs start at {1}", ((AtariST)stExe).Resource.rsh_nbb, ((AtariST)stExe).Resource.rsh_bitblk); - Console.WriteLine("\t\t{0} object trees start at {1}", ((AtariST)stExe).Resource.rsh_ntree, ((AtariST)stExe).Resource.rsh_trindex); - Console.WriteLine("\t\t{0} free strings start at {1}", ((AtariST)stExe).Resource.rsh_nstring, ((AtariST)stExe).Resource.rsh_frstr); - Console.WriteLine("\t\t{0} free images start at {1}", ((AtariST)stExe).Resource.rsh_nimages, ((AtariST)stExe).Resource.rsh_frimg); - Console.WriteLine("\t\tString data starts at {0}", ((AtariST)stExe).Resource.rsh_string); - Console.WriteLine("\t\tImage data starts at {0}", ((AtariST)stExe).Resource.rsh_imdata); - Console.WriteLine("\t\tStandard resource data is {0} bytes", ((AtariST)stExe).Resource.rsh_rssize); + Console.WriteLine("\t\t{0} OBJECTs start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nobs, ((AtariST)stExe).ResourceHeader.rsh_object); + Console.WriteLine("\t\t{0} TEDINFOs start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nted, ((AtariST)stExe).ResourceHeader.rsh_tedinfo); + Console.WriteLine("\t\t{0} ICONBLKs start at {1}", ((AtariST)stExe).ResourceHeader.rsh_nib, ((AtariST)stExe).ResourceHeader.rsh_iconblk); + 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\tImage data starts at {0}", ((AtariST)stExe).ResourceHeader.rsh_imdata); + Console.WriteLine("\t\tStandard resource data is {0} bytes", ((AtariST)stExe).ResourceHeader.rsh_rssize); + + if(((AtariST)stExe).ResourceObjectRoot != null) + { + Console.WriteLine("\tObject tree:"); + PrintAtariResourceTree(((AtariST)stExe).ResourceObjectRoot, 2); + } } } @@ -168,5 +174,18 @@ namespace exeinfo if(!recognized) Console.WriteLine("Executable format not recognized"); } + + static void PrintAtariResourceTree(AtariST.TreeObjectNode node, int level) + { + for(int i = 0; i < level; i++) + Console.Write("\t"); + + 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); + + if(node.child != null) PrintAtariResourceTree(node.child, level + 1); + + if(node.sibling != null) PrintAtariResourceTree(node.sibling, level); + } } } \ No newline at end of file diff --git a/libexeinfo/AtariST/AtariST.cs b/libexeinfo/AtariST/AtariST.cs index 1a2c4f7..0192e50 100644 --- a/libexeinfo/AtariST/AtariST.cs +++ b/libexeinfo/AtariST/AtariST.cs @@ -24,6 +24,7 @@ // 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.Runtime.InteropServices; @@ -102,7 +103,8 @@ namespace libexeinfo public OperatingSystem RequiredOperatingSystem => new OperatingSystem {Name = Header.mint == MINT_SIGNATURE ? "MiNT" : "Atari TOS"}; public Stream resourceStream; - public AtariResource Resource; + public AtariResourceHeader ResourceHeader; + public TreeObjectNode ResourceObjectRoot; void Initialize() { @@ -122,10 +124,53 @@ namespace libexeinfo if(resourceStream == null) return; - buffer = new byte[Marshal.SizeOf(typeof(AtariResource))]; + buffer = new byte[Marshal.SizeOf(typeof(AtariResourceHeader))]; resourceStream.Position = 0; resourceStream.Read(buffer, 0, buffer.Length); - Resource = BigEndianMarshal.ByteArrayToStructureBigEndian(buffer); + ResourceHeader = BigEndianMarshal.ByteArrayToStructureBigEndian(buffer); + + if(ResourceHeader.rsh_vrsn != 0 && ResourceHeader.rsh_vrsn != 1 && ResourceHeader.rsh_vrsn != 4 && ResourceHeader.rsh_vrsn != 5) return; + + if(ResourceHeader.rsh_nobs > 0) + { + ObjectNode[] nodes = new ObjectNode[ResourceHeader.rsh_nobs]; + + resourceStream.Position = ResourceHeader.rsh_object; + for(short i = 0; i < ResourceHeader.rsh_nobs; i++) + { + buffer = new byte[Marshal.SizeOf(typeof(ObjectNode))]; + resourceStream.Read(buffer, 0, buffer.Length); + nodes[i] = BigEndianMarshal.ByteArrayToStructureBigEndian(buffer); + } + + List knownNodes = new List(); + ResourceObjectRoot = ProcessResourceObject(nodes, ref knownNodes, 0); + } + } + + static TreeObjectNode ProcessResourceObject(IList nodes, ref List knownNodes, short nodeNumber) + { + TreeObjectNode node = new TreeObjectNode + { + type = (ObjectTypes)nodes[nodeNumber].ob_type, + flags = (ObjectFlags)nodes[nodeNumber].ob_flags, + state = (ObjectStates)nodes[nodeNumber].ob_state, + data = nodes[nodeNumber].ob_spec, + x = nodes[nodeNumber].ob_x, + y = nodes[nodeNumber].ob_y, + width = nodes[nodeNumber].ob_width, + height = nodes[nodeNumber].ob_height + }; + + knownNodes.Add(nodeNumber); + + if(nodes[nodeNumber].ob_head > 0 && !knownNodes.Contains(nodes[nodeNumber].ob_head)) + node.child = ProcessResourceObject(nodes, ref knownNodes, nodes[nodeNumber].ob_head); + + if(nodes[nodeNumber].ob_next > 0 && !knownNodes.Contains(nodes[nodeNumber].ob_next)) + node.sibling = ProcessResourceObject(nodes, ref knownNodes, nodes[nodeNumber].ob_next); + + return node; } /// diff --git a/libexeinfo/AtariST/Enums.cs b/libexeinfo/AtariST/Enums.cs index 5a4f9fc..d1783d8 100644 --- a/libexeinfo/AtariST/Enums.cs +++ b/libexeinfo/AtariST/Enums.cs @@ -108,10 +108,6 @@ namespace libexeinfo [Flags] public enum ObjectFlags : short { - /// - /// No flags - /// - None = 0x0000, /// /// Indicates that the user can select the object /// @@ -153,10 +149,6 @@ namespace libexeinfo [Flags] public enum ObjectStates : short { - /// - /// Indicates that the object is drawn in normal colors - /// - Normal = 0x0000, /// /// Indicates that the object is highlighted by being drawn with reversed colors /// diff --git a/libexeinfo/AtariST/Structs.cs b/libexeinfo/AtariST/Structs.cs index c36493b..bab9682 100644 --- a/libexeinfo/AtariST/Structs.cs +++ b/libexeinfo/AtariST/Structs.cs @@ -191,6 +191,24 @@ namespace libexeinfo public short ob_height; } + /// + /// The OBJECT structure contains values that describe the object, its relationship to the other objects in the tree, and its location relative to its parent or (in the case of the root object) the screen. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class TreeObjectNode + { + public TreeObjectNode sibling; + public TreeObjectNode child; + public ObjectTypes type; + public ObjectFlags flags; + public ObjectStates state; + public int data; + public short x; + public short y; + public short width; + public short height; + } + /// /// The TEDINFO structure lets a user edit formatted text. The object types G_TEXT, G_BOXTEXT, G_FTEXT and G_FBOXTEXT use their to point to TEDINFO structures. ///