initial shk support

This commit is contained in:
Denis Molony 2021-04-17 12:14:06 +10:00
parent 6aa882ecbd
commit 2cb40b84e4
8 changed files with 116 additions and 32 deletions

View File

@ -67,7 +67,7 @@ public interface ProdosConstants
"$48", "$49", "$4A", "$4B", "$4C", "$4D", "$4E", "$4F", // "$48", "$49", "$4A", "$4B", "$4C", "$4D", "$4E", "$4F", //
"GWP", "GSS", "GDB", "DRW", "GDP", "HMD", "EDU", "STN", // "GWP", "GSS", "GDB", "DRW", "GDP", "HMD", "EDU", "STN", //
"HLP", "COM", "CFG", "ANM", "MUM", "ENT", "DVU", "FIN", // "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", // "$68", "$69", "$6A", "BIO", "$6C", "TDR", "PRE", "HDV", //
"$70", "$71", "$72", "$73", "$74", "$75", "$76", "$77", // "$70", "$71", "$72", "$73", "$74", "$75", "$76", "$77", //
"$78", "$79", "$7A", "$7B", "$7C", "$7D", "$7E", "$7F", // "$78", "$79", "$7A", "$7B", "$7C", "$7D", "$7E", "$7F", //

View File

@ -0,0 +1,9 @@
package com.bytezone.diskbrowser.prodos.write;
public class DiskFullException extends Exception
{
public DiskFullException (String message)
{
super (message);
}
}

View File

@ -98,7 +98,7 @@ public class FileEntry
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
void writeFile (byte[] dataBuffer) void writeFile (byte[] dataBuffer) throws DiskFullException
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
this.eof = dataBuffer.length; 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 assert auxType > 0; // record length
@ -160,7 +160,7 @@ public class FileEntry
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
int allocateNextBlock () int allocateNextBlock () throws DiskFullException
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
blocksUsed++; blocksUsed++;
@ -168,7 +168,7 @@ public class FileEntry
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
int getActualBlockNo (int logicalBlockNo) int getActualBlockNo (int logicalBlockNo) throws DiskFullException
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int actualBlockNo = 0; 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 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); IndexBlock indexBlock = masterIndexBlock.get (position);

View File

@ -33,7 +33,7 @@ public class ProdosDisk
private Map<Integer, SubdirectoryHeader> subdirectoryHeaders = new HashMap<> (); private Map<Integer, SubdirectoryHeader> 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 () 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 // 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; String[] subdirectories;
@ -158,7 +159,10 @@ public class ProdosDisk
fileEntry.version = 0x00; fileEntry.version = 0x00;
fileEntry.minVersion = 0x00; fileEntry.minVersion = 0x00;
fileEntry.headerPointer = catalogBlockNo; fileEntry.headerPointer = catalogBlockNo;
fileEntry.fileType = 4; // text fileEntry.fileType = type;
fileEntry.auxType = auxType;
fileEntry.creationDate = created;
fileEntry.modifiedDate = modified;
fileEntry.writeFile (dataBuffer); 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); FileEntry fileEntry = findFreeSlot (blockNo);
@ -281,10 +285,15 @@ public class ProdosDisk
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
int allocateNextBlock () int allocateNextBlock () throws DiskFullException
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int nextBlock = getFreeBlock (); int nextBlock = getFreeBlock ();
if (nextBlock < 0)
{
throw new DiskFullException ("Full");
}
volumeBitMap.set (nextBlock, false); // mark as unavailable volumeBitMap.set (nextBlock, false); // mark as unavailable
return nextBlock; 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); SubdirectoryHeader subdirectoryHeader = subdirectoryHeaders.get (blockNo);

View File

@ -1,5 +1,7 @@
package com.bytezone.diskbrowser.utilities; package com.bytezone.diskbrowser.utilities;
import java.time.LocalDateTime;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
class DateTime class DateTime
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
@ -39,6 +41,14 @@ class DateTime
days[weekDay], day, months[month], year); 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 @Override
public String toString () public String toString ()

View File

@ -4,9 +4,11 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.bytezone.diskbrowser.prodos.write.DiskFullException;
import com.bytezone.diskbrowser.prodos.write.ProdosDisk; import com.bytezone.diskbrowser.prodos.write.ProdosDisk;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
@ -55,11 +57,7 @@ public class NuFX
dataPtr += thread.getCompressedEOF (); dataPtr += thread.getCompressedEOF ();
if (debug) if (debug)
{
System.out.printf ("Thread: %d%n%n%s%n%n", i, thread); 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 ()) if (record.hasFile ())
@ -82,10 +80,9 @@ public class NuFX
} }
else if (totalFiles > 0) else if (totalFiles > 0)
{ {
// listFiles ();
try try
{ {
ProdosDisk disk = new ProdosDisk (1600, "DISKBROWSER"); ProdosDisk disk = new ProdosDisk (3200, "DISKBROWSER");
int count = 0; int count = 0;
for (Record record : records) for (Record record : records)
{ {
@ -93,15 +90,17 @@ public class NuFX
{ {
String fileName = record.getFileName (); String fileName = record.getFileName ();
int fileSize = record.getFileSize (); int fileSize = record.getFileSize ();
int fileType = record.getFileType (); byte fileType = (byte) record.getFileType ();
int eof = record.getUncompressedSize (); int eof = record.getUncompressedSize ();
int auxType = record.getAuxType ();
LocalDateTime created = record.getCreated ();
LocalDateTime modified = record.getModified ();
byte[] buffer = record.getData (); byte[] buffer = record.getData ();
System.out.printf ("%3d %-35s %,7d %d %,7d %d%n", ++count, fileName,
fileSize, fileType, eof, buffer.length); System.out.printf ("%3d %-35s %,7d %02X %,7d %,7d %,7d %s %s%n",
if (fileType == 4 && count > 10 && count < 16) ++count, fileName, fileSize, fileType, eof, auxType, buffer.length,
{ created, modified);
disk.addFile (fileName, fileType, buffer); disk.addFile (fileName, fileType, auxType, created, modified, buffer);
}
} }
} }
@ -113,6 +112,10 @@ public class NuFX
{ {
e.printStackTrace (); e.printStackTrace ();
} }
catch (DiskFullException e)
{
e.printStackTrace ();
}
} }
return null; return null;
@ -176,7 +179,7 @@ public class NuFX
public static void main (String[] args) throws FileFormatException, IOException 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 ()); NuFX nufx = new NuFX (file.toPath ());
System.out.println (nufx); System.out.println (nufx);

View File

@ -1,5 +1,6 @@
package com.bytezone.diskbrowser.utilities; package com.bytezone.diskbrowser.utilities;
import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -159,7 +160,12 @@ class Record
{ {
for (Thread thread : threads) for (Thread thread : threads)
if (thread.hasFileName ()) if (thread.hasFileName ())
{
String fileName = thread.getFileName ();
if (separator != '/')
return fileName.replace (separator, '/');
return thread.getFileName (); return thread.getFileName ();
}
return ""; return "";
} }
@ -171,6 +177,31 @@ class Record
return fileType; 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 () int getFileSize ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -214,7 +245,7 @@ class Record
bits = bits.substring (bits.length () - 8); bits = bits.substring (bits.length () - 8);
String decode = Utility.matchFlags (access, accessChars); 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 ("Attributes ..... %d%n", attributes));
text.append (String.format ("Version ........ %d%n", version)); text.append (String.format ("Version ........ %d%n", version));
text.append (String.format ("Threads ........ %d%n", totThreads)); text.append (String.format ("Threads ........ %d%n", totThreads));

View File

@ -195,12 +195,33 @@ public class Utility
int minute = buffer[offset + 2] & 0x3F; int minute = buffer[offset + 2] & 0x3F;
int hour = buffer[offset + 3] & 0x1F; 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) if (year < 70)
year += 2000; year += 2000;
else else
year += 1900; 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; return null;
} }
@ -249,14 +270,15 @@ public class Utility
public static int readShort (byte[] buffer, int ptr) 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) 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;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//