package com.bytezone.diskbrowser.applefile; import com.bytezone.diskbrowser.HexFormatter; public class IntegerBasicProgram extends AbstractFile { private static String[] tokens = { "?", "?", "?", " : ", "?", "?", "?", "?", "?", "?", "?", "?", "CLR", "?", "?", "?", "HIMEM: ", "LOMEM: ", " + ", " - ", " * ", " / ", " = ", " # ", " >= ", " > ", " <= ", " <> ", " < ", " AND ", " OR ", " MOD ", "^", "+", "(", ",", " THEN ", " THEN ", ",", ",", "\"", "\"", "(", "!", "!", "(", "PEEK ", "RND ", "SGN", "ABS", "PDL", "RNDX", "(", "+", "-", "NOT ", "(", "=", "#", "LEN(", "ASC(", "SCRN(", ",", "(", "$", "$", "(", ", ", ",", ";", ";", ";", ",", ",", ",", "TEXT", "GR ", "CALL ", "DIM ", "DIM ", "TAB ", "END", "INPUT ", "INPUT ", "INPUT ", "FOR ", " = ", " TO ", " STEP ", "NEXT ", ",", "RETURN", "GOSUB ", "REM ", "LET ", "GOTO ", "IF ", "PRINT ", "PRINT ", "PRINT", "POKE ", ",", "COLOR=", "PLOT", ",", "HLIN", ",", " AT ", "VLIN ", ",", " AT ", "VTAB ", " = ", " = ", ")", ")", "LIST ", ",", "LIST ", "POP ", "NODSP ", "NODSP ", "NOTRACE ", "DSP ", "DSP ", "TRACE ", "PR#", "IN#", }; public IntegerBasicProgram (String name, byte[] buffer) { super (name, buffer); } public String getText () { StringBuilder pgm = new StringBuilder (); pgm.append ("Name : " + name + "\n"); pgm.append ("Length : $" + HexFormatter.format4 (buffer.length) + " (" + buffer.length + ")\n\n"); int ptr = 0; boolean looksLikeAssembler = checkForAssembler (); // this can probably go boolean looksLikeSCAssembler = checkForSCAssembler (); while (ptr < buffer.length) { int lineLength = HexFormatter.intValue (buffer[ptr]); /* * It appears that lines ending in 00 are S-C Assembler programs, and * lines ending in 01 are Integer Basic programs. */ int p2 = ptr + lineLength - 1; if (p2 < 0 || (buffer[p2] != 1 && buffer[p2] != 0)) { pgm.append ("\nPossible assembler code follows\n"); break; } if (lineLength <= 0) break; if (looksLikeSCAssembler) appendSCAssembler (pgm, ptr, lineLength); else if (looksLikeAssembler) appendAssembler (pgm, ptr, lineLength); else appendInteger (pgm, ptr, lineLength); pgm.append ("\n"); ptr += lineLength; } if (ptr < buffer.length) { int address = HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 3]); int remainingBytes = buffer.length - ptr - 5; byte[] newBuffer = new byte[remainingBytes]; System.arraycopy (buffer, ptr + 4, newBuffer, 0, remainingBytes); AssemblerProgram ap = new AssemblerProgram ("embedded", newBuffer, address); pgm.append ("\n" + ap.getText () + "\n"); } pgm.deleteCharAt (pgm.length () - 1); return pgm.toString (); } private void appendAssembler (StringBuilder pgm, int ptr, int lineLength) { for (int i = ptr + 3; i < ptr + lineLength - 1; i++) { if ((buffer[i] & 0x80) == 0x80) { int spaces = buffer[i] & 0x0F; for (int j = 0; j < spaces; j++) pgm.append (' '); continue; } int b = HexFormatter.intValue (buffer[i]); pgm.append ((char) b); } } private boolean checkForAssembler () { int ptr = 0; while (ptr < buffer.length) { int lineLength = HexFormatter.intValue (buffer[ptr]); int p2 = ptr + lineLength - 1; if (p2 < 0 || (buffer[p2] != 1 && buffer[p2] != 0)) break; if (lineLength <= 0) // in case of looping bug break; // check for comments if (buffer[ptr + 3] == 0x3B || buffer[ptr + 3] == 0x2A) return true; ptr += lineLength; } return false; } private boolean checkForSCAssembler () { int lineLength = HexFormatter.intValue (buffer[0]); if (lineLength <= 0) return false; return buffer[lineLength - 1] == 0; } private void appendSCAssembler (StringBuilder pgm, int ptr, int lineLength) { int lineNumber = HexFormatter.intValue (buffer[ptr + 2]) * 256 + HexFormatter.intValue (buffer[ptr + 1]); pgm.append (String.format ("%4d: ", lineNumber)); int p2 = ptr + 3; while (buffer[p2] != 0) { if (buffer[p2] == (byte) 0xC0) { int repeat = buffer[p2 + 1]; for (int i = 0; i < repeat; i++) pgm.append ((char) buffer[p2 + 2]); p2 += 2; } else if ((buffer[p2] & 0x80) != 0) { int spaces = buffer[p2] & 0x7F; for (int i = 0; i < spaces; i++) pgm.append (' '); } else pgm.append ((char) buffer[p2]); p2++; } } private void appendInteger (StringBuilder pgm, int ptr, int lineLength) { int lineNumber = HexFormatter.intValue (buffer[ptr + 1], buffer[ptr + 2]); boolean inString = false; boolean inRemark = false; String lineText = String.format ("%5d ", lineNumber); int lineTab = lineText.length (); pgm.append (lineText); for (int p = ptr + 3; p < ptr + lineLength - 1; p++) { int b = HexFormatter.intValue (buffer[p]); if (b == 0x03 // token for colon (:) && !inString && !inRemark && buffer[p + 1] != 1) // not end of // line { pgm.append (":\n" + " ".substring (0, lineTab)); continue; } if (b >= 0xB0 && b <= 0xB9 // numeric literal && (buffer[p - 1] & 0x80) == 0 // not a variable name && !inString && !inRemark) { pgm.append (HexFormatter.intValue (buffer[p + 1], buffer[p + 2])); p += 2; continue; } if (b >= 128) { b -= 128; if (b >= 32) pgm.append ((char) b); else pgm.append (""); } else if (!tokens[b].equals ("?")) { pgm.append (tokens[b]); if ((b == 40 || b == 41) && !inRemark) // double quotes inString = !inString; if (b == 0x5D) inRemark = true; } else pgm.append (" ." + HexFormatter.format2 (b) + ". "); } } public String getHexDump () { if (false) return super.getHexDump (); StringBuffer pgm = new StringBuffer (); pgm.append ("Name : " + name + "\n"); pgm.append ("Length : $" + HexFormatter.format4 (buffer.length) + " (" + buffer.length + ")\n\n"); int ptr = 0; while (ptr < buffer.length) { int lineLength = HexFormatter.intValue (buffer[ptr]); int p2 = ptr + lineLength - 1; if (p2 < 0 || buffer[p2] > 1) { System.out.println ("invalid line"); break; } pgm.append (HexFormatter.formatNoHeader (buffer, ptr, lineLength)); pgm.append ("\n"); if (lineLength <= 0) { System.out.println ("looping"); break; } ptr += lineLength; pgm.append ("\n"); } if (pgm.length () > 0) pgm.deleteCharAt (pgm.length () - 1); return pgm.toString (); } }