diff --git a/exeinfo/Program.cs b/exeinfo/Program.cs index 71c8651..af84407 100644 --- a/exeinfo/Program.cs +++ b/exeinfo/Program.cs @@ -27,7 +27,7 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; +using System.Linq; using System.Text; using libexeinfo; @@ -121,48 +121,88 @@ namespace exeinfo foreach(NE.ResidentName name in ((NE)neExe).NonResidentNames) 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) { recognized = true; 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) { recognized = true; 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) { recognized = true; 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) { recognized = true; Console.Write(stExe.Information); - 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)) + 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) { 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} 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\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); + 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); - } + if(((AtariST)stExe).ResourceObjectRoots != null && ((AtariST)stExe).ResourceObjectRoots.Length > 0) + for(int i = 0; i < ((AtariST)stExe).ResourceObjectRoots.Length; i++) + { + 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; 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"); @@ -177,11 +223,106 @@ namespace exeinfo static void PrintAtariResourceTree(AtariST.TreeObjectNode node, int level) { - for(int i = 0; i < level; i++) - Console.Write("\t"); + 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); + string thickStr; + + 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); diff --git a/exeinfo/packages.config b/exeinfo/packages.config new file mode 100644 index 0000000..2e764ff --- /dev/null +++ b/exeinfo/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/libexeinfo/AtariST/AtariST.cs b/libexeinfo/AtariST/AtariST.cs index 2911818..66c8158 100644 --- a/libexeinfo/AtariST/AtariST.cs +++ b/libexeinfo/AtariST/AtariST.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Runtime.InteropServices; namespace libexeinfo @@ -102,10 +103,10 @@ namespace libexeinfo public IEnumerable Architectures => new[] {Architecture.M68K}; public OperatingSystem RequiredOperatingSystem => new OperatingSystem {Name = Header.mint == MINT_SIGNATURE ? "MiNT" : "Atari TOS"}; - public IEnumerable Strings { get; } + public IEnumerable Strings { get; private set; } public Stream resourceStream; public AtariResourceHeader ResourceHeader; - public TreeObjectNode ResourceObjectRoot; + public TreeObjectNode[] ResourceObjectRoots; 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_nobs > 0) + List strings = new List(); + + 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 nodes = new List(); + while(true) + { + buffer = new byte[Marshal.SizeOf(typeof(ObjectNode))]; + resourceStream.Read(buffer, 0, buffer.Length); + ObjectNode node = BigEndianMarshal.ByteArrayToStructureBigEndian(buffer); + nodes.Add(node); + if(((ObjectFlags)node.ob_flags).HasFlag(ObjectFlags.Lastob)) break; + } + + List knownNodes = new List(); + ResourceObjectRoots[i] = ProcessResourceObject(nodes, ref knownNodes, 0, resourceStream, strings); + } + } + else 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))]; + 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); + ResourceObjectRoots = new TreeObjectNode[1]; + ResourceObjectRoots[0] = ProcessResourceObject(nodes, ref knownNodes, 0, resourceStream, strings); + } + + if(strings.Count > 0) + { + strings.Sort(); + Strings = strings.Distinct(); } } diff --git a/libexeinfo/AtariST/Enums.cs b/libexeinfo/AtariST/Enums.cs index d1783d8..8096948 100644 --- a/libexeinfo/AtariST/Enums.cs +++ b/libexeinfo/AtariST/Enums.cs @@ -102,7 +102,7 @@ namespace libexeinfo /// An object that describes a color icon. Its is a pointer to an /// structure. /// - G_CICON = 31, + G_CICON = 33, } [Flags] @@ -177,55 +177,68 @@ namespace libexeinfo public enum ObjectColors : byte { - White = 0, - Black = 1, - Red = 2, - Green = 3, - Blue = 4, - Cyan = 5, - Yellow = 6, - Magenta = 7, - White2 = 8, - Black2 = 9, - LightRed = 10, - LightGreen = 11, - LightBlue = 12, - LightCyan = 13, - LightYellow = 14, + White = 0, + Black = 1, + Red = 2, + Green = 3, + Blue = 4, + Cyan = 5, + Yellow = 6, + Magenta = 7, + White2 = 8, + Black2 = 9, + LightRed = 10, + LightGreen = 11, + LightBlue = 12, + LightCyan = 13, + LightYellow = 14, LightMagenta = 15 } public enum ObjectFillPattern : byte { - Hollow = 0, + Hollow = 0, Dither1 = 1, Dither2 = 2, Dither3 = 3, Dither4 = 4, Dither5 = 5, Dither6 = 6, - Solid = 7, + Solid = 7, } - + + public enum ObjectJustification : short + { + Left = 0, + Right = 1, + Center = 2 + } + + public enum ObjectFont : short + { + System = 3, + Small = 5 + } + /// /// Mask for border /// - const ushort BorderColorMask = 0xF000; + public const ushort BorderColorMask = 0xF000; /// /// Mask for text /// - const ushort TextColorMask = 0x0F00; + public const ushort TextColorMask = 0x0F00; /// /// If set text is in transparent mode. Replace mode otherwise. /// - const ushort TransparentColor = 0x0080; + public const ushort TransparentColor = 0x0080; /// /// Mask for /// - const ushort FillPatternMask = 0x0070; + public const ushort FillPatternMask = 0x0070; /// /// Mask for inside /// - const ushort InsideColorMask = 0x000F; + public const ushort InsideColorMask = 0x000F; } } \ No newline at end of file diff --git a/libexeinfo/AtariST/Resources.cs b/libexeinfo/AtariST/Resources.cs index b502eb8..9bc0a43 100644 --- a/libexeinfo/AtariST/Resources.cs +++ b/libexeinfo/AtariST/Resources.cs @@ -24,16 +24,18 @@ // 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; +using Claunia.Encoding; namespace libexeinfo { public partial class AtariST : IExecutable { - static TreeObjectNode ProcessResourceObject(IList nodes, ref List knownNodes, short nodeNumber) + static TreeObjectNode ProcessResourceObject(IList nodes, ref List knownNodes, + short nodeNumber, Stream resourceStream, + List strings) { TreeObjectNode node = new TreeObjectNode { @@ -47,13 +49,187 @@ namespace libexeinfo height = nodes[nodeNumber].ob_height }; + byte[] buffer; + List 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(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(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(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(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(); + 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(); + 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); 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)) - node.sibling = ProcessResourceObject(nodes, ref knownNodes, nodes[nodeNumber].ob_next); + node.sibling = + ProcessResourceObject(nodes, ref knownNodes, nodes[nodeNumber].ob_next, resourceStream, strings); return node; } diff --git a/libexeinfo/AtariST/Structs.cs b/libexeinfo/AtariST/Structs.cs index bab9682..803eb49 100644 --- a/libexeinfo/AtariST/Structs.cs +++ b/libexeinfo/AtariST/Structs.cs @@ -207,6 +207,57 @@ namespace libexeinfo public short y; public short width; 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; } ///