diff --git a/src/com/bytezone/diskbrowser/prodos/ProdosConstants.java b/src/com/bytezone/diskbrowser/prodos/ProdosConstants.java index 922a4dd..806b988 100755 --- a/src/com/bytezone/diskbrowser/prodos/ProdosConstants.java +++ b/src/com/bytezone/diskbrowser/prodos/ProdosConstants.java @@ -67,7 +67,7 @@ public interface ProdosConstants "$48", "$49", "$4A", "$4B", "$4C", "$4D", "$4E", "$4F", // "GWP", "GSS", "GDB", "DRW", "GDP", "HMD", "EDU", "STN", // "HLP", "COM", "CFG", "ANM", "MUM", "ENT", "DVU", "FIN", // - "$60", "$61", "$62", "$63", "$64", "$65", "$66", "$67", // + "$60", "$61", "$62", "$63", "$64", "$65", "NCF", "$67", // "$68", "$69", "$6A", "BIO", "$6C", "TDR", "PRE", "HDV", // "$70", "$71", "$72", "$73", "$74", "$75", "$76", "$77", // "$78", "$79", "$7A", "$7B", "$7C", "$7D", "$7E", "$7F", // diff --git a/src/com/bytezone/diskbrowser/prodos/write/DiskFullException.java b/src/com/bytezone/diskbrowser/prodos/write/DiskFullException.java new file mode 100644 index 0000000..d86c360 --- /dev/null +++ b/src/com/bytezone/diskbrowser/prodos/write/DiskFullException.java @@ -0,0 +1,9 @@ +package com.bytezone.diskbrowser.prodos.write; + +public class DiskFullException extends Exception +{ + public DiskFullException (String message) + { + super (message); + } +} diff --git a/src/com/bytezone/diskbrowser/prodos/write/FileEntry.java b/src/com/bytezone/diskbrowser/prodos/write/FileEntry.java index 3b60871..4e12d18 100644 --- a/src/com/bytezone/diskbrowser/prodos/write/FileEntry.java +++ b/src/com/bytezone/diskbrowser/prodos/write/FileEntry.java @@ -98,7 +98,7 @@ public class FileEntry } // ---------------------------------------------------------------------------------// - void writeFile (byte[] dataBuffer) + void writeFile (byte[] dataBuffer) throws DiskFullException // ---------------------------------------------------------------------------------// { this.eof = dataBuffer.length; @@ -124,7 +124,7 @@ public class FileEntry } // ---------------------------------------------------------------------------------// - void writeRecord (int recordNo, byte[] dataBuffer) + void writeRecord (int recordNo, byte[] dataBuffer) throws DiskFullException // ---------------------------------------------------------------------------------// { assert auxType > 0; // record length @@ -160,7 +160,7 @@ public class FileEntry } // ---------------------------------------------------------------------------------// - int allocateNextBlock () + int allocateNextBlock () throws DiskFullException // ---------------------------------------------------------------------------------// { blocksUsed++; @@ -168,7 +168,7 @@ public class FileEntry } // ---------------------------------------------------------------------------------// - int getActualBlockNo (int logicalBlockNo) + int getActualBlockNo (int logicalBlockNo) throws DiskFullException // ---------------------------------------------------------------------------------// { int actualBlockNo = 0; @@ -211,7 +211,7 @@ public class FileEntry } // ---------------------------------------------------------------------------------// - void map (int logicalBlockNo, int actualBlockNo) + void map (int logicalBlockNo, int actualBlockNo) throws DiskFullException // ---------------------------------------------------------------------------------// { if (logicalBlockNo > 255) // potential TREE @@ -280,7 +280,7 @@ public class FileEntry } // ---------------------------------------------------------------------------------// - IndexBlock getIndexBlock (int position) + IndexBlock getIndexBlock (int position) throws DiskFullException // ---------------------------------------------------------------------------------// { IndexBlock indexBlock = masterIndexBlock.get (position); diff --git a/src/com/bytezone/diskbrowser/prodos/write/ProdosDisk.java b/src/com/bytezone/diskbrowser/prodos/write/ProdosDisk.java index a6a80b5..7f9ca5e 100644 --- a/src/com/bytezone/diskbrowser/prodos/write/ProdosDisk.java +++ b/src/com/bytezone/diskbrowser/prodos/write/ProdosDisk.java @@ -33,7 +33,7 @@ public class ProdosDisk private Map subdirectoryHeaders = new HashMap<> (); // ---------------------------------------------------------------------------------// - public ProdosDisk (int blocks, String volumeName) throws IOException + public ProdosDisk (int blocks, String volumeName) throws IOException, DiskFullException // ---------------------------------------------------------------------------------// { try (DataInputStream in = new DataInputStream (ProdosDisk.class.getClassLoader () @@ -63,7 +63,7 @@ public class ProdosDisk } // ---------------------------------------------------------------------------------// - void createCatalog (String volumeName) + void createCatalog (String volumeName) throws DiskFullException // ---------------------------------------------------------------------------------// { // reserve two boot blocks @@ -112,7 +112,8 @@ public class ProdosDisk } // ---------------------------------------------------------------------------------// - public FileEntry addFile (String path, int type, byte[] dataBuffer) + public FileEntry addFile (String path, byte type, int auxType, LocalDateTime created, + LocalDateTime modified, byte[] dataBuffer) throws DiskFullException // ---------------------------------------------------------------------------------// { String[] subdirectories; @@ -158,7 +159,10 @@ public class ProdosDisk fileEntry.version = 0x00; fileEntry.minVersion = 0x00; fileEntry.headerPointer = catalogBlockNo; - fileEntry.fileType = 4; // text + fileEntry.fileType = type; + fileEntry.auxType = auxType; + fileEntry.creationDate = created; + fileEntry.modifiedDate = modified; fileEntry.writeFile (dataBuffer); @@ -221,7 +225,7 @@ public class ProdosDisk } // ---------------------------------------------------------------------------------// - private FileEntry createSubdirectory (int blockNo, String name) + private FileEntry createSubdirectory (int blockNo, String name) throws DiskFullException // ---------------------------------------------------------------------------------// { FileEntry fileEntry = findFreeSlot (blockNo); @@ -281,10 +285,15 @@ public class ProdosDisk } // ---------------------------------------------------------------------------------// - int allocateNextBlock () + int allocateNextBlock () throws DiskFullException // ---------------------------------------------------------------------------------// { int nextBlock = getFreeBlock (); + if (nextBlock < 0) + { + throw new DiskFullException ("Full"); + } + volumeBitMap.set (nextBlock, false); // mark as unavailable return nextBlock; @@ -298,7 +307,7 @@ public class ProdosDisk } // ---------------------------------------------------------------------------------// - private FileEntry findFreeSlot (int blockNo) + private FileEntry findFreeSlot (int blockNo) throws DiskFullException // ---------------------------------------------------------------------------------// { SubdirectoryHeader subdirectoryHeader = subdirectoryHeaders.get (blockNo); diff --git a/src/com/bytezone/diskbrowser/utilities/DateTime.java b/src/com/bytezone/diskbrowser/utilities/DateTime.java index fceb8ee..ef842bd 100644 --- a/src/com/bytezone/diskbrowser/utilities/DateTime.java +++ b/src/com/bytezone/diskbrowser/utilities/DateTime.java @@ -1,5 +1,7 @@ package com.bytezone.diskbrowser.utilities; +import java.time.LocalDateTime; + // -----------------------------------------------------------------------------------// class DateTime // -----------------------------------------------------------------------------------// @@ -39,6 +41,14 @@ class DateTime days[weekDay], day, months[month], year); } + // ---------------------------------------------------------------------------------// + public LocalDateTime getLocalDateTime () + // ---------------------------------------------------------------------------------// + { + int adjustedYear = year + (year > 70 ? 1900 : 2000); + return LocalDateTime.of (adjustedYear, month + 1, day, hour, minute); + } + // ---------------------------------------------------------------------------------// @Override public String toString () diff --git a/src/com/bytezone/diskbrowser/utilities/NuFX.java b/src/com/bytezone/diskbrowser/utilities/NuFX.java index 488483c..b7d7c67 100644 --- a/src/com/bytezone/diskbrowser/utilities/NuFX.java +++ b/src/com/bytezone/diskbrowser/utilities/NuFX.java @@ -4,9 +4,11 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import com.bytezone.diskbrowser.prodos.write.DiskFullException; import com.bytezone.diskbrowser.prodos.write.ProdosDisk; // -----------------------------------------------------------------------------------// @@ -55,11 +57,7 @@ public class NuFX dataPtr += thread.getCompressedEOF (); if (debug) - { System.out.printf ("Thread: %d%n%n%s%n%n", i, thread); - // if (rec == 122 && thread.hasFile ()) - // System.out.println (HexFormatter.format (thread.getData ())); - } } if (record.hasFile ()) @@ -82,10 +80,9 @@ public class NuFX } else if (totalFiles > 0) { - // listFiles (); try { - ProdosDisk disk = new ProdosDisk (1600, "DISKBROWSER"); + ProdosDisk disk = new ProdosDisk (3200, "DISKBROWSER"); int count = 0; for (Record record : records) { @@ -93,15 +90,17 @@ public class NuFX { String fileName = record.getFileName (); int fileSize = record.getFileSize (); - int fileType = record.getFileType (); + byte fileType = (byte) record.getFileType (); int eof = record.getUncompressedSize (); + int auxType = record.getAuxType (); + LocalDateTime created = record.getCreated (); + LocalDateTime modified = record.getModified (); byte[] buffer = record.getData (); - System.out.printf ("%3d %-35s %,7d %d %,7d %d%n", ++count, fileName, - fileSize, fileType, eof, buffer.length); - if (fileType == 4 && count > 10 && count < 16) - { - disk.addFile (fileName, fileType, buffer); - } + + System.out.printf ("%3d %-35s %,7d %02X %,7d %,7d %,7d %s %s%n", + ++count, fileName, fileSize, fileType, eof, auxType, buffer.length, + created, modified); + disk.addFile (fileName, fileType, auxType, created, modified, buffer); } } @@ -113,6 +112,10 @@ public class NuFX { e.printStackTrace (); } + catch (DiskFullException e) + { + e.printStackTrace (); + } } return null; @@ -176,7 +179,7 @@ public class NuFX public static void main (String[] args) throws FileFormatException, IOException // ---------------------------------------------------------------------------------// { - File file = new File ("/Users/denismolony/Dropbox/Examples/SHK/Applenet20.shk"); + File file = new File ("/Users/denismolony/Dropbox/Examples/SHK/DiversiCopy.3.1.shk"); NuFX nufx = new NuFX (file.toPath ()); System.out.println (nufx); diff --git a/src/com/bytezone/diskbrowser/utilities/Record.java b/src/com/bytezone/diskbrowser/utilities/Record.java index 1df3388..4de4238 100644 --- a/src/com/bytezone/diskbrowser/utilities/Record.java +++ b/src/com/bytezone/diskbrowser/utilities/Record.java @@ -1,5 +1,6 @@ package com.bytezone.diskbrowser.utilities; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -159,7 +160,12 @@ class Record { for (Thread thread : threads) if (thread.hasFileName ()) + { + String fileName = thread.getFileName (); + if (separator != '/') + return fileName.replace (separator, '/'); return thread.getFileName (); + } return ""; } @@ -171,6 +177,31 @@ class Record return fileType; } + // ---------------------------------------------------------------------------------// + int getAuxType () + // ---------------------------------------------------------------------------------// + { + return auxType; + } + + // ---------------------------------------------------------------------------------// + LocalDateTime getCreated () + // ---------------------------------------------------------------------------------// + { + if (created == null) + return null; + return created.getLocalDateTime (); + } + + // ---------------------------------------------------------------------------------// + LocalDateTime getModified () + // ---------------------------------------------------------------------------------// + { + if (modified == null) + return null; + return modified.getLocalDateTime (); + } + // ---------------------------------------------------------------------------------// int getFileSize () // ---------------------------------------------------------------------------------// @@ -214,7 +245,7 @@ class Record bits = bits.substring (bits.length () - 8); String decode = Utility.matchFlags (access, accessChars); - text.append (String.format ("Header CRC ..... %,d (%04X)%n", crc, crc)); + text.append (String.format ("Header CRC ..... %,d (%<04X)%n", 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)); diff --git a/src/com/bytezone/diskbrowser/utilities/Utility.java b/src/com/bytezone/diskbrowser/utilities/Utility.java index 2617871..f45343f 100644 --- a/src/com/bytezone/diskbrowser/utilities/Utility.java +++ b/src/com/bytezone/diskbrowser/utilities/Utility.java @@ -195,12 +195,33 @@ public class Utility int minute = buffer[offset + 2] & 0x3F; int hour = buffer[offset + 3] & 0x1F; + if (month < 1 || month > 12) + { + System.out.printf ("Invalid month: %d%n", month); + return null; + } + + if (hour > 23) + { + System.out.printf ("Invalid hour: %d%n", hour); + return null; + } + if (year < 70) year += 2000; else year += 1900; - return LocalDateTime.of (year, month - 1, day, hour, minute); + + try + { + return LocalDateTime.of (year, month - 1, day, hour, minute); + } + catch (DateTimeException e) + { + System.out.println ("Bad date/time"); + } } + return null; } @@ -249,14 +270,15 @@ public class Utility public static int readShort (byte[] buffer, int ptr) // ---------------------------------------------------------------------------------// { - return buffer[ptr] | buffer[ptr + 1] << 8; + return (buffer[ptr] & 0xFF) | (buffer[ptr + 1] & 0xFF) << 8; } // ---------------------------------------------------------------------------------// public static int readTriple (byte[] buffer, int ptr) // ---------------------------------------------------------------------------------// { - return buffer[ptr] | buffer[ptr + 1] << 8 | buffer[ptr + 2] << 16; + return (buffer[ptr] & 0xFF) | (buffer[ptr + 1] & 0xFF) << 8 + | (buffer[ptr + 2] & 0xFF) << 16; } // ---------------------------------------------------------------------------------//