diff --git a/src/com/bytezone/diskbrowser/disk/DiskFactory.java b/src/com/bytezone/diskbrowser/disk/DiskFactory.java index 806564a..e68a496 100755 --- a/src/com/bytezone/diskbrowser/disk/DiskFactory.java +++ b/src/com/bytezone/diskbrowser/disk/DiskFactory.java @@ -152,7 +152,7 @@ public class DiskFactory System.out.println (" ** sdk **"); try { - NuFX nuFX = new NuFX (file); + NuFX nuFX = new NuFX (file.toPath ()); File tmp = File.createTempFile ("sdk", null); FileOutputStream fos = new FileOutputStream (tmp); fos.write (nuFX.getBuffer ()); diff --git a/src/com/bytezone/diskbrowser/utilities/Header.java b/src/com/bytezone/diskbrowser/utilities/Header.java new file mode 100644 index 0000000..5a1022c --- /dev/null +++ b/src/com/bytezone/diskbrowser/utilities/Header.java @@ -0,0 +1,96 @@ +package com.bytezone.diskbrowser.utilities; + +// -----------------------------------------------------------------------------------// +class Header +// -----------------------------------------------------------------------------------// +{ + private final int totalRecords; + private final int version; + private final int eof; + private final int crc; + private final DateTime created; + private final DateTime modified; + boolean bin2; + + // ---------------------------------------------------------------------------------// + public Header (byte[] buffer) throws FileFormatException + // ---------------------------------------------------------------------------------// + { + int ptr = 0; + + while (true) + { + if (isNuFile (buffer, ptr)) + break; + + if (isBin2 (buffer, ptr)) + { + ptr += 128; + bin2 = true; + continue; + } + + throw new FileFormatException ("NuFile not found"); + } + + crc = Utility.getWord (buffer, ptr + 6); + totalRecords = Utility.getLong (buffer, ptr + 8); + created = new DateTime (buffer, ptr + 12); + modified = new DateTime (buffer, ptr + 20); + version = Utility.getWord (buffer, ptr + 28); + eof = Utility.getLong (buffer, ptr + 38); + + byte[] crcBuffer = new byte[40]; + System.arraycopy (buffer, ptr + 8, crcBuffer, 0, crcBuffer.length); + if (crc != Utility.getCRC (crcBuffer, 0)) + { + System.out.println ("***** Master CRC mismatch *****"); + throw new FileFormatException ("Master CRC failed"); + } + } + + // ---------------------------------------------------------------------------------// + int getTotalRecords () + // ---------------------------------------------------------------------------------// + { + return totalRecords; + } + + // ---------------------------------------------------------------------------------// + private boolean isNuFile (byte[] buffer, int ptr) + // ---------------------------------------------------------------------------------// + { + if (buffer[ptr] == 0x4E && buffer[ptr + 1] == (byte) 0xF5 && buffer[ptr + 2] == 0x46 + && buffer[ptr + 3] == (byte) 0xE9 && buffer[ptr + 4] == 0x6C + && buffer[ptr + 5] == (byte) 0xE5) + return true; + return false; + } + + // ---------------------------------------------------------------------------------// + private boolean isBin2 (byte[] buffer, int ptr) + // ---------------------------------------------------------------------------------// + { + if (buffer[ptr] == 0x0A && buffer[ptr + 1] == 0x47 && buffer[ptr + 2] == 0x4C + && buffer[ptr + 18] == (byte) 0x02) + return true; + return false; + } + + // ---------------------------------------------------------------------------------// + @Override + public String toString () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + + text.append (String.format ("Master CRC ..... %,d (%04X)%n", crc, crc)); + text.append (String.format ("Records ........ %,d%n", totalRecords)); + text.append (String.format ("Created ........ %s%n", created.format ())); + text.append (String.format ("Modified ....... %s%n", modified.format ())); + text.append (String.format ("Version ........ %,d%n", version)); + text.append (String.format ("Master EOF ..... %,d", eof)); + + return text.toString (); + } +} diff --git a/src/com/bytezone/diskbrowser/utilities/LZW.java b/src/com/bytezone/diskbrowser/utilities/LZW.java index 4ca0cbf..01a41ec 100644 --- a/src/com/bytezone/diskbrowser/utilities/LZW.java +++ b/src/com/bytezone/diskbrowser/utilities/LZW.java @@ -118,7 +118,7 @@ class LZW for (byte[] track : chunks) System.arraycopy (track, 0, buffer, trackNumber++ * TRACK_LENGTH, TRACK_LENGTH); - if (crc != NuFX.getCRC (buffer, crcBase)) + if (crc != Utility.getCRC (buffer, crcBase)) System.out.println ("\n*** LZW CRC mismatch ***"); return buffer; diff --git a/src/com/bytezone/diskbrowser/utilities/NuFX.java b/src/com/bytezone/diskbrowser/utilities/NuFX.java index e786b4b..9c3a091 100644 --- a/src/com/bytezone/diskbrowser/utilities/NuFX.java +++ b/src/com/bytezone/diskbrowser/utilities/NuFX.java @@ -1,6 +1,5 @@ package com.bytezone.diskbrowser.utilities; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -11,10 +10,6 @@ import java.util.List; public class NuFX // -----------------------------------------------------------------------------------// { - private static String[] fileSystems = - { "", "ProDOS/SOS", "DOS 3.3", "DOS 3.2", "Apple II Pascal", "Macintosh HFS", - "Macintosh MFS", "Lisa File System", "Apple CP/M", "", "MS-DOS", "High Sierra", - "ISO 9660", "AppleShare" }; private Header header; private final byte[] buffer; private final boolean debug = false; @@ -30,14 +25,6 @@ public class NuFX readBuffer (); } - // ---------------------------------------------------------------------------------// - public NuFX (File file) throws FileFormatException, IOException - // ---------------------------------------------------------------------------------// - { - buffer = Files.readAllBytes (file.toPath ()); - readBuffer (); - } - // ---------------------------------------------------------------------------------// private void readBuffer () // ---------------------------------------------------------------------------------// @@ -51,19 +38,19 @@ public class NuFX if (debug) System.out.printf ("%s%n%n", header); - for (int rec = 0; rec < header.totalRecords; rec++) + for (int rec = 0; rec < header.getTotalRecords (); rec++) { - Record record = new Record (dataPtr); + Record record = new Record (buffer, dataPtr); records.add (record); if (debug) System.out.printf ("Record: %d%n%n%s%n%n", rec, record); - dataPtr += record.attributes + record.fileNameLength; + dataPtr += record.getAttributes () + record.getFileNameLength (); int threadsPtr = dataPtr; - dataPtr += record.totThreads * 16; + dataPtr += record.getTotalThreads () * 16; - for (int i = 0; i < record.totThreads; i++) + for (int i = 0; i < record.getTotalThreads (); i++) { Thread thread = new Thread (buffer, threadsPtr + i * 16, dataPtr); threads.add (thread); @@ -95,202 +82,4 @@ public class NuFX return thread.toString (); return "no disk"; } - - // ---------------------------------------------------------------------------------// - protected static int getCRC (final byte[] buffer, int base) - // ---------------------------------------------------------------------------------// - { - int crc = base; - for (int j = 0; j < buffer.length; j++) - { - crc = ((crc >>> 8) | (crc << 8)) & 0xFFFF; - crc ^= (buffer[j] & 0xFF); - crc ^= ((crc & 0xFF) >>> 4); - crc ^= (crc << 12) & 0xFFFF; - crc ^= ((crc & 0xFF) << 5) & 0xFFFF; - } - - crc &= 0xFFFF; - return crc; - } - - // ---------------------------------------------------------------------------------// - class Header - // ---------------------------------------------------------------------------------// - { - private final int totalRecords; - private final int version; - private final int eof; - private final int crc; - private final DateTime created; - private final DateTime modified; - boolean bin2; - - public Header (byte[] buffer) throws FileFormatException - { - int ptr = 0; - - while (true) - { - if (isNuFile (buffer, ptr)) - break; - - if (isBin2 (buffer, ptr)) - { - ptr += 128; - bin2 = true; - continue; - } - - throw new FileFormatException ("NuFile not found"); - } - - crc = Utility.getWord (buffer, ptr + 6); - totalRecords = Utility.getLong (buffer, ptr + 8); - created = new DateTime (buffer, ptr + 12); - modified = new DateTime (buffer, ptr + 20); - version = Utility.getWord (buffer, ptr + 28); - eof = Utility.getLong (buffer, ptr + 38); - - byte[] crcBuffer = new byte[40]; - System.arraycopy (buffer, ptr + 8, crcBuffer, 0, crcBuffer.length); - if (crc != getCRC (crcBuffer, 0)) - { - System.out.println ("***** Master CRC mismatch *****"); - throw new FileFormatException ("Master CRC failed"); - } - } - - private boolean isNuFile (byte[] buffer, int ptr) - { - if (buffer[ptr] == 0x4E && buffer[ptr + 1] == (byte) 0xF5 && buffer[ptr + 2] == 0x46 - && buffer[ptr + 3] == (byte) 0xE9 && buffer[ptr + 4] == 0x6C - && buffer[ptr + 5] == (byte) 0xE5) - return true; - return false; - } - - private boolean isBin2 (byte[] buffer, int ptr) - { - if (buffer[ptr] == 0x0A && buffer[ptr + 1] == 0x47 && buffer[ptr + 2] == 0x4C - && buffer[ptr + 18] == (byte) 0x02) - return true; - return false; - } - - @Override - public String toString () - { - StringBuilder text = new StringBuilder (); - - text.append (String.format ("Master CRC ..... %,d (%04X)%n", crc, crc)); - text.append (String.format ("Records ........ %,d%n", totalRecords)); - text.append (String.format ("Created ........ %s%n", created.format ())); - text.append (String.format ("Modified ....... %s%n", modified.format ())); - text.append (String.format ("Version ........ %,d%n", version)); - text.append (String.format ("Master EOF ..... %,d", eof)); - - return text.toString (); - } - } - - // ---------------------------------------------------------------------------------// - class Record - // ---------------------------------------------------------------------------------// - { - private final int totThreads; - private final int crc; - private final char separator; - private final int fileSystemID; - private final int attributes; - private final int version; - private final int access; - private final int fileType; - private final int auxType; - private final int storType; - private final DateTime created; - private final DateTime modified; - private final DateTime archived; - private final int optionSize; - private final int fileNameLength; - private final String fileName; - - public Record (int dataPtr) throws FileFormatException - { - // check for NuFX - if (!isNuFX (buffer, dataPtr)) - throw new FileFormatException ("NuFX not found"); - - crc = Utility.getWord (buffer, dataPtr + 4); - attributes = Utility.getWord (buffer, dataPtr + 6); - version = Utility.getWord (buffer, dataPtr + 8); - totThreads = Utility.getLong (buffer, dataPtr + 10); - fileSystemID = Utility.getWord (buffer, dataPtr + 14); - separator = (char) (buffer[dataPtr + 16] & 0x00FF); - access = Utility.getLong (buffer, dataPtr + 18); - fileType = Utility.getLong (buffer, dataPtr + 22); - auxType = Utility.getLong (buffer, dataPtr + 26); - storType = Utility.getWord (buffer, dataPtr + 30); - created = new DateTime (buffer, dataPtr + 32); - modified = new DateTime (buffer, dataPtr + 40); - archived = new DateTime (buffer, dataPtr + 48); - optionSize = Utility.getWord (buffer, dataPtr + 56); - fileNameLength = Utility.getWord (buffer, dataPtr + attributes - 2); - - int len = attributes + fileNameLength - 6; - byte[] crcBuffer = new byte[len + totThreads * 16]; - System.arraycopy (buffer, dataPtr + 6, crcBuffer, 0, crcBuffer.length); - - if (crc != getCRC (crcBuffer, 0)) - { - System.out.println ("***** Header CRC mismatch *****"); - throw new FileFormatException ("Header CRC failed"); - } - - if (fileNameLength > 0) - { - int start = dataPtr + attributes; - int end = start + fileNameLength; - for (int i = start; i < end; i++) - buffer[i] &= 0x7F; - fileName = new String (buffer, start, fileNameLength); - } - else - fileName = ""; - } - - private boolean isNuFX (byte[] buffer, int ptr) - { - if (buffer[ptr] == 0x4E && buffer[ptr + 1] == (byte) 0xF5 && buffer[ptr + 2] == 0x46 - && buffer[ptr + 3] == (byte) 0xD8) - return true; - return false; - } - - @Override - public String toString () - { - StringBuilder text = new StringBuilder (); - - text.append (String.format ("Header CRC ..... %,d (%04X)%n", crc, crc)); - text.append (String.format ("Attributes ..... %d%n", attributes)); - text.append (String.format ("Version ........ %d%n", version)); - text.append (String.format ("Threads ........ %d%n", totThreads)); - text.append (String.format ("File sys id .... %d (%s)%n", fileSystemID, - fileSystems[fileSystemID])); - text.append (String.format ("Separator ...... %s%n", separator)); - text.append (String.format ("Access ......... %,d%n", access)); - text.append (String.format ("File type ...... %,d%n", fileType)); - text.append (String.format ("Aux type ....... %,d%n", auxType)); - text.append (String.format ("Stor type ...... %,d%n", storType)); - text.append (String.format ("Created ........ %s%n", created.format ())); - text.append (String.format ("Modified ....... %s%n", modified.format ())); - text.append (String.format ("Archived ....... %s%n", archived.format ())); - text.append (String.format ("Option size .... %,d%n", optionSize)); - text.append (String.format ("Filename len ... %,d%n", fileNameLength)); - text.append (String.format ("Filename ....... %s", fileName)); - - return text.toString (); - } - } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/utilities/Record.java b/src/com/bytezone/diskbrowser/utilities/Record.java new file mode 100644 index 0000000..7879e6d --- /dev/null +++ b/src/com/bytezone/diskbrowser/utilities/Record.java @@ -0,0 +1,133 @@ +package com.bytezone.diskbrowser.utilities; + +// -----------------------------------------------------------------------------------// +class Record +// -----------------------------------------------------------------------------------// +{ + private static String[] fileSystems = + { "", "ProDOS/SOS", "DOS 3.3", "DOS 3.2", "Apple II Pascal", "Macintosh HFS", + "Macintosh MFS", "Lisa File System", "Apple CP/M", "", "MS-DOS", "High Sierra", + "ISO 9660", "AppleShare" }; + + private final int totThreads; + private final int crc; + private final char separator; + private final int fileSystemID; + private final int attributes; + private final int version; + private final int access; + private final int fileType; + private final int auxType; + private final int storType; + private final DateTime created; + private final DateTime modified; + private final DateTime archived; + private final int optionSize; + private final int fileNameLength; + private final String fileName; + + // ---------------------------------------------------------------------------------// + public Record (byte[] buffer, int dataPtr) throws FileFormatException + // ---------------------------------------------------------------------------------// + { + // check for NuFX + if (!isNuFX (buffer, dataPtr)) + throw new FileFormatException ("NuFX not found"); + + crc = Utility.getWord (buffer, dataPtr + 4); + attributes = Utility.getWord (buffer, dataPtr + 6); + version = Utility.getWord (buffer, dataPtr + 8); + totThreads = Utility.getLong (buffer, dataPtr + 10); + fileSystemID = Utility.getWord (buffer, dataPtr + 14); + separator = (char) (buffer[dataPtr + 16] & 0x00FF); + access = Utility.getLong (buffer, dataPtr + 18); + fileType = Utility.getLong (buffer, dataPtr + 22); + auxType = Utility.getLong (buffer, dataPtr + 26); + storType = Utility.getWord (buffer, dataPtr + 30); + created = new DateTime (buffer, dataPtr + 32); + modified = new DateTime (buffer, dataPtr + 40); + archived = new DateTime (buffer, dataPtr + 48); + optionSize = Utility.getWord (buffer, dataPtr + 56); + fileNameLength = Utility.getWord (buffer, dataPtr + attributes - 2); + + int len = attributes + fileNameLength - 6; + byte[] crcBuffer = new byte[len + totThreads * 16]; + System.arraycopy (buffer, dataPtr + 6, crcBuffer, 0, crcBuffer.length); + + if (crc != Utility.getCRC (crcBuffer, 0)) + { + System.out.println ("***** Header CRC mismatch *****"); + throw new FileFormatException ("Header CRC failed"); + } + + if (fileNameLength > 0) + { + int start = dataPtr + attributes; + int end = start + fileNameLength; + for (int i = start; i < end; i++) + buffer[i] &= 0x7F; + fileName = new String (buffer, start, fileNameLength); + } + else + fileName = ""; + } + + // ---------------------------------------------------------------------------------// + private boolean isNuFX (byte[] buffer, int ptr) + // ---------------------------------------------------------------------------------// + { + if (buffer[ptr] == 0x4E && buffer[ptr + 1] == (byte) 0xF5 && buffer[ptr + 2] == 0x46 + && buffer[ptr + 3] == (byte) 0xD8) + return true; + return false; + } + + // ---------------------------------------------------------------------------------// + int getAttributes () + // ---------------------------------------------------------------------------------// + { + return attributes; + } + + // ---------------------------------------------------------------------------------// + int getFileNameLength () + // ---------------------------------------------------------------------------------// + { + return fileNameLength; + } + + // ---------------------------------------------------------------------------------// + int getTotalThreads () + // ---------------------------------------------------------------------------------// + { + return totThreads; + } + + // ---------------------------------------------------------------------------------// + @Override + public String toString () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + + text.append (String.format ("Header CRC ..... %,d (%04X)%n", crc, crc)); + text.append (String.format ("Attributes ..... %d%n", attributes)); + text.append (String.format ("Version ........ %d%n", version)); + text.append (String.format ("Threads ........ %d%n", totThreads)); + text.append (String.format ("File sys id .... %d (%s)%n", fileSystemID, + fileSystems[fileSystemID])); + text.append (String.format ("Separator ...... %s%n", separator)); + text.append (String.format ("Access ......... %,d%n", access)); + text.append (String.format ("File type ...... %,d%n", fileType)); + text.append (String.format ("Aux type ....... %,d%n", auxType)); + text.append (String.format ("Stor type ...... %,d%n", storType)); + text.append (String.format ("Created ........ %s%n", created.format ())); + text.append (String.format ("Modified ....... %s%n", modified.format ())); + text.append (String.format ("Archived ....... %s%n", archived.format ())); + text.append (String.format ("Option size .... %,d%n", optionSize)); + text.append (String.format ("Filename len ... %,d%n", fileNameLength)); + text.append (String.format ("Filename ....... %s", fileName)); + + return text.toString (); + } +} diff --git a/src/com/bytezone/diskbrowser/utilities/Utility.java b/src/com/bytezone/diskbrowser/utilities/Utility.java index f008858..b8fbe0b 100644 --- a/src/com/bytezone/diskbrowser/utilities/Utility.java +++ b/src/com/bytezone/diskbrowser/utilities/Utility.java @@ -365,6 +365,24 @@ public class Utility return checksum.getValue (); } + // ---------------------------------------------------------------------------------// + protected static int getCRC (final byte[] buffer, int base) + // ---------------------------------------------------------------------------------// + { + int crc = base; + for (int j = 0; j < buffer.length; j++) + { + crc = ((crc >>> 8) | (crc << 8)) & 0xFFFF; + crc ^= (buffer[j] & 0xFF); + crc ^= ((crc & 0xFF) >>> 4); + crc ^= (crc << 12) & 0xFFFF; + crc ^= ((crc & 0xFF) << 5) & 0xFFFF; + } + + crc &= 0xFFFF; + return crc; + } + // ---------------------------------------------------------------------------------// public static int crc32 (byte[] buffer, int offset, int length) // ---------------------------------------------------------------------------------//