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", //
"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", //

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;
@ -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);

View File

@ -33,7 +33,7 @@ public class ProdosDisk
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 ()
@ -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);

View File

@ -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 ()

View File

@ -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);

View File

@ -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));

View File

@ -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;
}
// ---------------------------------------------------------------------------------//