From cdde71b158869ffb79eabca0ba19d6f2bbf7e588 Mon Sep 17 00:00:00 2001 From: Denis Molony Date: Wed, 21 Aug 2019 10:31:11 +1000 Subject: [PATCH] tweaks --- .../applefile/AssemblerBlocks.java | 81 +++++++ .../applefile/AssemblerProgram.java | 169 ++++++++++++--- .../applefile/AssemblerStatement.java | 199 +++++++++--------- .../diskbrowser/applefile/HiResImage.java | 70 +++--- .../diskbrowser/applefile/IconFile.java | 72 +++++-- .../applefile/SHRPictureFile1.java | 4 +- .../applefile/SHRPictureFile2.java | 1 + 7 files changed, 396 insertions(+), 200 deletions(-) create mode 100644 src/com/bytezone/diskbrowser/applefile/AssemblerBlocks.java diff --git a/src/com/bytezone/diskbrowser/applefile/AssemblerBlocks.java b/src/com/bytezone/diskbrowser/applefile/AssemblerBlocks.java new file mode 100644 index 0000000..2bbf1d7 --- /dev/null +++ b/src/com/bytezone/diskbrowser/applefile/AssemblerBlocks.java @@ -0,0 +1,81 @@ +package com.bytezone.diskbrowser.applefile; + +import java.util.ArrayList; +import java.util.List; + +public class AssemblerBlocks +{ + public AssemblerBlocks (byte[] buffer, int loadAddress) + { + int ptr = 0; + boolean inCode = true; + int address = loadAddress; + List loadTargets = new ArrayList<> (); + List branchTargets = new ArrayList<> (); + + while (ptr < buffer.length) + { + if (branchTargets.contains (address)) + inCode = true; + + if (inCode) + { + AssemblerStatement cmd = new AssemblerStatement (buffer[ptr]); + + if (cmd.size == 2 && ptr < buffer.length - 1) + cmd.addData (buffer[ptr + 1]); + else if (cmd.size == 3 && ptr < buffer.length - 2) + cmd.addData (buffer[ptr + 1], buffer[ptr + 2]); + else + cmd.size = 1; + + cmd.address = address; + + if (branchTargets.contains (address)) + System.out.print ("> "); + else + System.out.print (" "); + System.out.printf ("%s%n", cmd); + ptr += cmd.size; + address += cmd.size; + + // RTS, JMP + if (cmd.opcode == 0x60 || cmd.opcode == 0x4C) + inCode = false; + + // JMP, JMP, JSR + // System.out.printf ("%02X %02X %02X%n", cmd.opcode, cmd.operand1, cmd.operand2); + if (cmd.opcode == 0x4C || cmd.opcode == 0x6C || cmd.opcode == 0x20) + { + branchTargets.add (cmd.target); + } + + if (cmd.opcode == 0xB9) + { + int target = ((cmd.operand2 & 0xFF) << 8) | (cmd.operand1 & 0xFF); + loadTargets.add (target); + } + + // branch relative + if (cmd.offset != 0) + branchTargets.add (cmd.address + cmd.offset + 2); + } + else + { + if (loadTargets.contains (address)) + System.out.print ("* "); + else + System.out.print (" "); + System.out.printf ("%06X %02X %s%n", address, buffer[ptr], + (char) (buffer[ptr] & 0x7F)); + ptr += 1; + address += 1; + } + } + + for (int loadTarget : loadTargets) + System.out.printf ("load : $%04X%n", loadTarget); + for (int branchTarget : branchTargets) + System.out.printf ("branch: $%04X%n", branchTarget); + } +} diff --git a/src/com/bytezone/diskbrowser/applefile/AssemblerProgram.java b/src/com/bytezone/diskbrowser/applefile/AssemblerProgram.java index e4cfec1..fc051cd 100755 --- a/src/com/bytezone/diskbrowser/applefile/AssemblerProgram.java +++ b/src/com/bytezone/diskbrowser/applefile/AssemblerProgram.java @@ -8,7 +8,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.TreeMap; import com.bytezone.common.Utility; import com.bytezone.diskbrowser.gui.AssemblerPreferences; @@ -24,8 +23,17 @@ public class AssemblerProgram extends AbstractFile private byte[] extraBuffer = new byte[0]; + // private TreeMap strings; + private List entryPoints; + private List stringLocations; + static AssemblerPreferences assemblerPreferences; + public static void setAssemblerPreferences (AssemblerPreferences assemblerPreferences) + { + AssemblerProgram.assemblerPreferences = assemblerPreferences; + } + public AssemblerProgram (String name, byte[] buffer, int address) { super (name, buffer); @@ -33,6 +41,8 @@ public class AssemblerProgram extends AbstractFile if (equates == null) getEquates (); + + // AssemblerBlocks assemblerBlocks = new AssemblerBlocks (buffer, address); } public AssemblerProgram (String name, byte[] buffer, int address, int executeOffset) @@ -41,11 +51,6 @@ public class AssemblerProgram extends AbstractFile this.executeOffset = executeOffset; } - public static void setAssemblerPreferences (AssemblerPreferences assemblerPreferences) - { - AssemblerProgram.assemblerPreferences = assemblerPreferences; - } - public void setExtraBuffer (byte[] fullBuffer, int offset, int length) { if (length >= 0) @@ -114,8 +119,12 @@ public class AssemblerProgram extends AbstractFile private String getListing () { StringBuilder pgm = new StringBuilder (); + List lines = getLines (); + if (stringLocations == null) + getStrings (); + // if the assembly doesn't start at the beginning, just dump the bytes that // are skipped for (int i = 0; i < executeOffset; i++) @@ -138,6 +147,7 @@ public class AssemblerProgram extends AbstractFile line.append (" "); line.append (cmd.mnemonic + " " + cmd.operand); + if (cmd.offset != 0) { int branch = cmd.address + cmd.offset + 2; @@ -160,6 +170,7 @@ public class AssemblerProgram extends AbstractFile break; } } + pgm.append (line.toString () + "\n"); } @@ -169,6 +180,20 @@ public class AssemblerProgram extends AbstractFile return pgm.toString (); } + // private int showString (AssemblerStatement cmd, StringBuilder line) + // { + // int key = cmd.address - loadAddress; + // if (strings.containsKey (key)) + // { + // while (line.length () < 40) + // line.append (" "); + // String s = strings.get (key); + // line.append ("# " + s); + // return s.length () - cmd.size; + // } + // return 0; + // } + private List getLines () { List lines = new ArrayList (); @@ -193,9 +218,12 @@ public class AssemblerProgram extends AbstractFile else cmd.size = 1; + // JMP, JMP, JSR if (cmd.target >= loadAddress && cmd.target < (loadAddress + buffer.length) && (cmd.value == 0x4C || cmd.value == 0x6C || cmd.value == 0x20)) targets.add (cmd.target); + + // branch relative if (cmd.offset != 0) targets.add (cmd.address + cmd.offset + 2); @@ -215,18 +243,19 @@ public class AssemblerProgram extends AbstractFile private String getStringsText () { - Map strings = getStrings (); - if (strings.size () == 0) + if (stringLocations.size () == 0) return ""; - List entryPoints = getEntryPoints (); StringBuilder text = new StringBuilder ("\n\nPossible strings:\n\n"); - for (Integer key : strings.keySet ()) + for (StringLocation stringLocation : stringLocations) { - String s = strings.get (key); - int start = key + loadAddress; - text.append (String.format ("%s %04X - %04X %s %n", - entryPoints.contains (start) ? "*" : " ", start, start + s.length (), s)); + if (stringLocation.zeroTerminated) + text.append (String.format ("%s %04X - %04X %s %s %n", + entryPoints.contains (stringLocation.offset + loadAddress) ? "*" : " ", + stringLocation.offset, stringLocation.offset + stringLocation.length, + stringLocation.toStatisticsString (), stringLocation)); + else + System.out.println (stringLocation); } if (text.length () > 0) @@ -235,31 +264,17 @@ public class AssemblerProgram extends AbstractFile return text.toString (); } - private Map getStrings () + private void getStrings () { - TreeMap strings = new TreeMap<> (); + entryPoints = new ArrayList<> (); + stringLocations = new ArrayList<> (); int start = 0; for (int ptr = 0; ptr < buffer.length; ptr++) { - if ((buffer[ptr] & 0x80) != 0) // high bit set - continue; - - if (buffer[ptr] == 0 // possible end of string - && ptr - start > 5) - strings.put (start, HexFormatter.getString (buffer, start, ptr - start)); - - start = ptr + 1; - } - return strings; - } - - private List getEntryPoints () - { - List entryPoints = new ArrayList<> (); - - for (int ptr = 0; ptr < buffer.length; ptr++) - if ((buffer[ptr] == (byte) 0xBD || buffer[ptr] == (byte) 0xB9) + if ((buffer[ptr] == (byte) 0xBD // LDA Absolute,X + || buffer[ptr] == (byte) 0xB9 // LDA Absolute,Y + || buffer[ptr] == (byte) 0xAD) // LDA Absolute && (ptr + 2 < buffer.length)) { int address = Utility.getWord (buffer, ptr + 1); @@ -267,7 +282,17 @@ public class AssemblerProgram extends AbstractFile entryPoints.add (address); } - return entryPoints; + if ((buffer[ptr] & 0x80) != 0) // hi bit set + continue; + + if (ptr - start > 3) + stringLocations.add (new StringLocation (start, ptr - 1)); + + start = ptr + 1; + } + + if (buffer.length - start > 3) + stringLocations.add (new StringLocation (start, buffer.length - 1)); } private String getArrow (AssemblerStatement cmd) @@ -324,4 +349,78 @@ public class AssemblerProgram extends AbstractFile e.printStackTrace (); } } + + class StringLocation + { + int offset; + int length; + boolean zeroTerminated; + boolean hasLengthByte; + int digits; + int letters; + int punctuation; + int controlChars; + int spaces; + + public StringLocation (int first, int last) + { + offset = first; + length = last - offset + 1; + + zeroTerminated = ++last < buffer.length && buffer[last] == 0; + hasLengthByte = first > 0 && (buffer[first] & 0xFF) == length; + + for (int i = offset; i < offset + length; i++) + { + int val = buffer[i] & 0x7F; + if (val < 32 || val == 127) + ++controlChars; + else if (val == 32) + ++spaces; + else if (val >= 48 && val <= 57) + ++digits; + else if (val >= 65 && val <= 90) + ++letters; + else if (val >= 97 && val <= 122) + ++letters; + else + ++punctuation; + } + } + + boolean likelyString () + { + return spaces > 0 || letters > punctuation; + } + + public String toStatisticsString () + { + return String.format ("%2d, %2d, %2d, %2d, %2d", digits, letters, punctuation, + controlChars, spaces); + } + + @Override + public String toString () + { + StringBuilder text = new StringBuilder (); + + if (hasLengthByte) + text.append (""); + + for (int i = offset; i < offset + length; i++) + { + int val = buffer[i] & 0x7F; + if (val == 4) + text.append (""); + else if (val == 10) + text.append (""); + else if (val == 13) + text.append (""); + else + text.append ((char) val); + } + + return text.toString (); + } + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/applefile/AssemblerStatement.java b/src/com/bytezone/diskbrowser/applefile/AssemblerStatement.java index 8174145..e1241f0 100755 --- a/src/com/bytezone/diskbrowser/applefile/AssemblerStatement.java +++ b/src/com/bytezone/diskbrowser/applefile/AssemblerStatement.java @@ -19,7 +19,6 @@ public class AssemblerStatement public int address; public boolean isTarget; public byte operand1, operand2; - String ascii = ""; public static void print () { @@ -74,7 +73,6 @@ public class AssemblerStatement this.mnemonic = AssemblerConstants.mnemonics[this.opcode]; this.size = AssemblerConstants.sizes2[this.opcode]; this.operand = ""; - ascii = getChar (opcode); } String getChar (byte val) @@ -95,7 +93,7 @@ public class AssemblerStatement public void addData () { - switch (this.opcode) + switch (opcode) { case 0x00: // BRK case 0x08: // PHP @@ -147,119 +145,116 @@ public class AssemblerStatement { operand1 = b; String address = "$" + HexFormatter.format2 (b); - // if (this.mnemonic.equals ("JSR")) - // this.target = HexFormatter.intValue (b); - ascii += getChar (b); switch (this.opcode) { - case 0x09: // ORA - case 0x29: // AND - case 0x49: // EOR - case 0x69: // ADC - case 0x89: // NOP - 65c02 - case 0xA0: // LDY - case 0xA2: // LDX - case 0xA9: // LDA - case 0xC0: // CPY - case 0xC9: // CMP - case 0xE0: // CPX - case 0xE9: // SBC + case 0x09: // ORA + case 0x29: // AND + case 0x49: // EOR + case 0x69: // ADC + case 0x89: // NOP - 65c02 + case 0xA0: // LDY + case 0xA2: // LDX + case 0xA9: // LDA + case 0xC0: // CPY + case 0xC9: // CMP + case 0xE0: // CPX + case 0xE9: // SBC operand = "#" + address; - mode = 2; // Immediate + mode = 2; // Immediate break; - case 0x04: // NOP - 65c02 - case 0x05: // ORA - case 0x06: // ASL - case 0x14: // NOP - 65c02 - case 0x24: // BIT - case 0x25: // AND - case 0x26: // ROL - case 0x45: // EOR - case 0x46: // LSR - case 0x64: // NOP - 65c02 - case 0x65: // ADC - case 0x66: // ROR - case 0x84: // STY - case 0x85: // STA - case 0x86: // STX - case 0xA4: // LDY - case 0xA5: // LDA - case 0xA6: // LDX - case 0xC4: // CPY - case 0xC5: // CMP - case 0xC6: // DEC - case 0xE4: // CPX - case 0xE5: // SBC - case 0xE6: // INC + case 0x04: // NOP - 65c02 + case 0x05: // ORA + case 0x06: // ASL + case 0x14: // NOP - 65c02 + case 0x24: // BIT + case 0x25: // AND + case 0x26: // ROL + case 0x45: // EOR + case 0x46: // LSR + case 0x64: // NOP - 65c02 + case 0x65: // ADC + case 0x66: // ROR + case 0x84: // STY + case 0x85: // STA + case 0x86: // STX + case 0xA4: // LDY + case 0xA5: // LDA + case 0xA6: // LDX + case 0xC4: // CPY + case 0xC5: // CMP + case 0xC6: // DEC + case 0xE4: // CPX + case 0xE5: // SBC + case 0xE6: // INC target = b & 0xFF; operand = address; - mode = 8; // Zero page + mode = 8; // Zero page break; - case 0x15: // ORA - case 0x16: // ASL - case 0x34: // NOP - 65c02 - case 0x35: // AND - case 0x36: // ROL - case 0x55: // EOR - case 0x56: // LSR - case 0x74: // NOP - 65c02 - case 0x75: // ADC - case 0x76: // ROR - case 0x94: // STY - case 0x95: // STA - case 0xB4: // LDY - case 0xB5: // LDA - case 0xD5: // CMP - case 0xD6: // DEC - case 0xF5: // SBC - case 0xF6: // INC + case 0x15: // ORA + case 0x16: // ASL + case 0x34: // NOP - 65c02 + case 0x35: // AND + case 0x36: // ROL + case 0x55: // EOR + case 0x56: // LSR + case 0x74: // NOP - 65c02 + case 0x75: // ADC + case 0x76: // ROR + case 0x94: // STY + case 0x95: // STA + case 0xB4: // LDY + case 0xB5: // LDA + case 0xD5: // CMP + case 0xD6: // DEC + case 0xF5: // SBC + case 0xF6: // INC operand = address + ",X"; - mode = 9; // Zero page, X + mode = 9; // Zero page, X break; - case 0x96: // STX - case 0xB6: // LDX + case 0x96: // STX + case 0xB6: // LDX operand = address + ",Y"; - mode = 10; // Zero page, Y + mode = 10; // Zero page, Y break; - case 0x01: // ORA - case 0x21: // AND - case 0x41: // EOR - case 0x61: // ADC - case 0x81: // STA - case 0xA1: // LDA - case 0xC1: // CMP - case 0xE1: // SEC + case 0x01: // ORA + case 0x21: // AND + case 0x41: // EOR + case 0x61: // ADC + case 0x81: // STA + case 0xA1: // LDA + case 0xC1: // CMP + case 0xE1: // SEC operand = "(" + address + ",X)"; - mode = 11; // (Indirect, X) + mode = 11; // (Indirect, X) break; - case 0x11: // ORA - case 0x31: // AND - case 0x51: // EOR - case 0x71: // ADC - case 0x91: // STA - case 0xB1: // LDA - case 0xD1: // CMP - case 0xF1: // SBC + case 0x11: // ORA + case 0x31: // AND + case 0x51: // EOR + case 0x71: // ADC + case 0x91: // STA + case 0xB1: // LDA + case 0xD1: // CMP + case 0xF1: // SBC operand = "(" + address + "),Y"; - mode = 12; // (Indirect), Y + mode = 12; // (Indirect), Y break; - case 0x12: // NOP - case 0x32: // NOP - case 0x52: // NOP - case 0x72: // NOP - case 0x92: // NOP - case 0xB2: // NOP - case 0xD2: // NOP - case 0xF2: // NOP - operand = "(" + address + ")"; // all 65c02 - mode = 13; // (zero page) + case 0x12: // NOP + case 0x32: // NOP + case 0x52: // NOP + case 0x72: // NOP + case 0x92: // NOP + case 0xB2: // NOP + case 0xD2: // NOP + case 0xF2: // NOP + operand = "(" + address + ")"; // all 65c02 + mode = 13; // (zero page) break; case 0x10: // BPL @@ -272,7 +267,7 @@ public class AssemblerStatement case 0xD0: // BNE case 0xF0: // BEQ offset = b; - mode = 14; // relative + mode = 14; // relative this.target = b & 0xFF; break; @@ -286,11 +281,6 @@ public class AssemblerStatement operand1 = b1; operand2 = b2; String address = "$" + HexFormatter.format2 (b2) + HexFormatter.format2 (b1); - // if (this.mnemonic.equals ("JSR") || this.mnemonic.equals ("JMP") - // || this.mnemonic.equals ("BIT") || this.mnemonic.equals ("STA") - // || this.mnemonic.equals ("LDA")) - // this.target = HexFormatter.intValue (b1, b2); - ascii += getChar (b1) + getChar (b2); switch (this.opcode) { @@ -378,8 +368,11 @@ public class AssemblerStatement public String toString () { if (offset == 0) - return String.format ("%d %3s %-10s %02X", size, mnemonic, operand, value); - return String.format ("%d %3s %-10s %02X", size, mnemonic, operand + "+" + offset, - value); + return String.format ("%06X %d %3s %-10s %02X", address, size, mnemonic, operand, + value); + + String offsetText = String.format ("$%04X", address + offset + 2); + return String.format ("%06X %d %3s %-10s %02X", address, size, mnemonic, + operand + offsetText, value); } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/applefile/HiResImage.java b/src/com/bytezone/diskbrowser/applefile/HiResImage.java index 21c1f46..2a5adea 100644 --- a/src/com/bytezone/diskbrowser/applefile/HiResImage.java +++ b/src/com/bytezone/diskbrowser/applefile/HiResImage.java @@ -38,7 +38,7 @@ public abstract class HiResImage extends AbstractFile // $C0 PNT $0003 Packed IIGS QuickDraw II PICT File - SHRPictureFile2 * // * $C0 PNT $0004 Packed Super Hi-Res 3200 (Brooks) .3201 - SHRPictureFile2 // $C0 PNT $1000 - // $C0 PNT $8000 Drawplus ? + // $C0 PNT $8000 Drawplus? Paintworks Gold? // $C0 PNT $8001 GTv background picture // $C0 PNT $8005 DreamGraphix document // $C0 PNT $8006 GIF @@ -315,45 +315,11 @@ public abstract class HiResImage extends AbstractFile return newBuf; } - private int calculateBufferSize (byte[] buffer) - { - int ptr = 0; - int size = 0; - while (ptr < buffer.length) - { - int type = (buffer[ptr] & 0xC0) >> 6; // 0-3 - int count = (buffer[ptr++] & 0x3F) + 1; // 1-64 - - if (type == 0) - { - ptr += count; - size += count; - } - else if (type == 1) - { - ptr++; - size += count; - } - else if (type == 2) - { - ptr += 4; - size += count * 4; - } - else - { - ptr++; - size += count * 4; - } - } - return size; - } - // Super Hi-res IIGS (MAIN in $C0/02) int unpackLine (byte[] buffer, byte[] newBuf, int newPtr) { byte[] fourBuf = new byte[4]; - int oldPtr = newPtr; int ptr = 0; while (ptr < buffer.length) { @@ -397,11 +363,43 @@ public abstract class HiResImage extends AbstractFile break; } } - // System.out.println (HexFormatter.format (newBuf, oldPtr, newPtr - oldPtr)); return newPtr; } + private int calculateBufferSize (byte[] buffer) + { + int ptr = 0; + int size = 0; + while (ptr < buffer.length) + { + int type = (buffer[ptr] & 0xC0) >> 6; // 0-3 + int count = (buffer[ptr++] & 0x3F) + 1; // 1-64 + + if (type == 0) + { + ptr += count; + size += count; + } + else if (type == 1) + { + ptr++; + size += count; + } + else if (type == 2) + { + ptr += 4; + size += count * 4; + } + else + { + ptr++; + size += count * 4; + } + } + return size; + } + // Beagle Bros routine to expand a hi-res screen private byte[] unscrunch (byte[] src) { diff --git a/src/com/bytezone/diskbrowser/applefile/IconFile.java b/src/com/bytezone/diskbrowser/applefile/IconFile.java index 3a92107..2557f49 100644 --- a/src/com/bytezone/diskbrowser/applefile/IconFile.java +++ b/src/com/bytezone/diskbrowser/applefile/IconFile.java @@ -12,23 +12,24 @@ import com.bytezone.diskbrowser.utilities.HexFormatter; public class IconFile extends AbstractFile { - private static Palette palette = new Palette ("Virtual II", new int[] { 0x000000, // 0 black - 0xDD0033, // 1 magenta - 0x885500, // 2 brown (8) - 0xFF6600, // 3 orange (9) - 0x007722, // 4 dark green - 0x555555, // 5 grey1 - 0x11DD00, // 6 light green (C) - 0xFFFF00, // 7 yellow (D) - 0x000099, // 8 dark blue (2) - 0xDD22DD, // 9 purple (3) - 0xAAAAAA, // A grey2 - 0xFF9988, // B pink - 0x2222FF, // C med blue (6) - 0x66AAFF, // D light blue (7) - 0x44FF99, // E aqua - 0xFFFFFF // F white - }); + private static Palette palette = // + new Palette ("Virtual II", new int[] { 0x000000, // 0 black + 0xDD0033, // 1 magenta + 0x885500, // 2 brown (8) + 0xFF6600, // 3 orange (9) + 0x007722, // 4 dark green + 0x555555, // 5 grey1 + 0x11DD00, // 6 light green (C) + 0xFFFF00, // 7 yellow (D) + 0x000099, // 8 dark blue (2) + 0xDD22DD, // 9 purple (3) + 0xAAAAAA, // A grey2 + 0xFF9988, // B pink + 0x2222FF, // C med blue (6) + 0x66AAFF, // D light blue (7) + 0x44FF99, // E aqua + 0xFFFFFF // F white + }); // private static Palette palette = new Palette ("Icon palette", // new int[] { 0x000000, // 0 black // 0x2222FF, // C med blue (6) @@ -69,7 +70,8 @@ public class IconFile extends AbstractFile int dataLen = HexFormatter.unsignedShort (buffer, ptr); if (dataLen == 0 || (dataLen + ptr) > buffer.length) break; - icons.add (new Icon (buffer, ptr)); + Icon icon = new Icon (buffer, ptr); + icons.add (icon); ptr += dataLen; } @@ -165,8 +167,15 @@ public class IconFile extends AbstractFile iDataType = HexFormatter.unsignedShort (buffer, 82); iDataAux = HexFormatter.unsignedShort (buffer, 84); - largeImage = new Image (buffer, 86); - smallImage = new Image (buffer, 86 + largeImage.size ()); + try + { + largeImage = new Image (buffer, 86); + smallImage = new Image (buffer, 86 + largeImage.size ()); + } + catch (InvalidImageException e) + { + System.out.println (e.getMessage ()); + } } @Override @@ -196,18 +205,27 @@ public class IconFile extends AbstractFile boolean colour; private final BufferedImage image; - public Image (byte[] buffer, int ptr) + public Image (byte[] buffer, int ptr) throws InvalidImageException { iconType = HexFormatter.unsignedShort (buffer, ptr); iconSize = HexFormatter.unsignedShort (buffer, ptr + 2); iconHeight = HexFormatter.unsignedShort (buffer, ptr + 4); iconWidth = HexFormatter.unsignedShort (buffer, ptr + 6); + if (iconType != 0 && iconType != 0x8000) + throw new InvalidImageException (String.format ("Bad icon type: %04X", iconType)); + iconImage = new byte[iconSize]; iconMask = new byte[iconSize]; colour = (iconType & 0x80) != 0; + // System.out.printf ("Icon type %04X %