Add Atari ST resource object tree walking.

This commit is contained in:
2018-02-27 04:41:20 +00:00
parent 9938058e96
commit 0737cc8645
4 changed files with 97 additions and 23 deletions

View File

@@ -143,20 +143,26 @@ namespace exeinfo
recognized = true; recognized = true;
Console.Write(stExe.Information); Console.Write(stExe.Information);
if(((AtariST)stExe).resourceStream != null || if(((AtariST)stExe).resourceStream != null ||
(((AtariST)stExe).Resource.rsh_vrsn != 0 && ((AtariST)stExe).Resource.rsh_vrsn != 1 && (((AtariST)stExe).ResourceHeader.rsh_vrsn != 0 && ((AtariST)stExe).ResourceHeader.rsh_vrsn != 1 &&
((AtariST)stExe).Resource.rsh_vrsn != 4 && ((AtariST)stExe).Resource.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).Resource.rsh_nobs, ((AtariST)stExe).Resource.rsh_object); 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).Resource.rsh_nted, ((AtariST)stExe).Resource.rsh_tedinfo); 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).Resource.rsh_nib, ((AtariST)stExe).Resource.rsh_iconblk); 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).Resource.rsh_nbb, ((AtariST)stExe).Resource.rsh_bitblk); 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).Resource.rsh_ntree, ((AtariST)stExe).Resource.rsh_trindex); 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).Resource.rsh_nstring, ((AtariST)stExe).Resource.rsh_frstr); 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).Resource.rsh_nimages, ((AtariST)stExe).Resource.rsh_frimg); 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).Resource.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).Resource.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).Resource.rsh_rssize); 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"); 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);
}
} }
} }

View File

@@ -24,6 +24,7 @@
// 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;
@@ -102,7 +103,8 @@ namespace libexeinfo
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 Stream resourceStream; public Stream resourceStream;
public AtariResource Resource; public AtariResourceHeader ResourceHeader;
public TreeObjectNode ResourceObjectRoot;
void Initialize() void Initialize()
{ {
@@ -122,10 +124,53 @@ namespace libexeinfo
if(resourceStream == null) return; if(resourceStream == null) return;
buffer = new byte[Marshal.SizeOf(typeof(AtariResource))]; buffer = new byte[Marshal.SizeOf(typeof(AtariResourceHeader))];
resourceStream.Position = 0; resourceStream.Position = 0;
resourceStream.Read(buffer, 0, buffer.Length); resourceStream.Read(buffer, 0, buffer.Length);
Resource = BigEndianMarshal.ByteArrayToStructureBigEndian<AtariResource>(buffer); ResourceHeader = BigEndianMarshal.ByteArrayToStructureBigEndian<AtariResourceHeader>(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<ObjectNode>(buffer);
}
List<short> knownNodes = new List<short>();
ResourceObjectRoot = ProcessResourceObject(nodes, ref knownNodes, 0);
}
}
static TreeObjectNode ProcessResourceObject(IList<ObjectNode> nodes, ref List<short> 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;
} }
/// <summary> /// <summary>

View File

@@ -108,10 +108,6 @@ namespace libexeinfo
[Flags] [Flags]
public enum ObjectFlags : short public enum ObjectFlags : short
{ {
/// <summary>
/// No flags
/// </summary>
None = 0x0000,
/// <summary> /// <summary>
/// Indicates that the user can select the object /// Indicates that the user can select the object
/// </summary> /// </summary>
@@ -153,10 +149,6 @@ namespace libexeinfo
[Flags] [Flags]
public enum ObjectStates : short public enum ObjectStates : short
{ {
/// <summary>
/// Indicates that the object is drawn in normal colors
/// </summary>
Normal = 0x0000,
/// <summary> /// <summary>
/// Indicates that the object is highlighted by being drawn with reversed colors /// Indicates that the object is highlighted by being drawn with reversed colors
/// </summary> /// </summary>

View File

@@ -191,6 +191,24 @@ namespace libexeinfo
public short ob_height; public short ob_height;
} }
/// <summary>
/// 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.
/// </summary>
[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;
}
/// <summary> /// <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. /// 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.
/// </summary> /// </summary>