Sort Prodos folders

This commit is contained in:
Denis Molony 2019-09-13 15:32:35 +10:00
parent b7f9b73643
commit 1c53b291dd
9 changed files with 178 additions and 61 deletions

View File

@ -159,7 +159,7 @@ public class SHRPictureFile2 extends HiResImage
break; break;
default: default:
System.out.println ("PIC unknown aux " + auxType); System.out.printf ("PIC unknown aux: %04X%n ", auxType);
failureReason = "unknown PIC aux"; failureReason = "unknown PIC aux";
} }
} }

View File

@ -81,6 +81,8 @@ public class AppleDisk implements Disk
private ActionListener actionListenerList; private ActionListener actionListenerList;
private List<DiskAddress> blockList; private List<DiskAddress> blockList;
private WozFile wozFile;
private final boolean debug = false; private final boolean debug = false;
public AppleDisk (File file, int tracks, int sectors) throws FileFormatException public AppleDisk (File file, int tracks, int sectors) throws FileFormatException
@ -243,6 +245,7 @@ public class AppleDisk implements Disk
public AppleDisk (WozFile wozFile, int tracks, int sectors) public AppleDisk (WozFile wozFile, int tracks, int sectors)
{ {
this.wozFile = wozFile;
this.tracks = tracks; this.tracks = tracks;
this.sectors = sectors; this.sectors = sectors;
file = wozFile.file; file = wozFile.file;
@ -654,15 +657,21 @@ public class AppleDisk implements Disk
if (path.startsWith (home)) if (path.startsWith (home))
path = "~" + path.substring (home.length ()); path = "~" + path.substring (home.length ());
text.append (String.format ("Path............ %s%n", path)); text.append (String.format ("Path................. %s%n", path));
text.append (String.format ("File name....... %s%n", file.getName ())); text.append (String.format ("File name............ %s%n", file.getName ()));
text.append (String.format ("File size....... %,d%n", file.length ())); text.append (String.format ("File size............ %,d%n", file.length ()));
text.append (String.format ("Tracks.......... %d%n", tracks)); text.append (String.format ("Tracks............... %d%n", tracks));
text.append (String.format ("Sectors......... %d%n", sectors)); text.append (String.format ("Sectors.............. %d%n", sectors));
text.append (String.format ("Blocks.......... %,d%n", blocks)); text.append (String.format ("Blocks............... %,d%n", blocks));
text.append (String.format ("Track size...... %,d%n", trackSize)); text.append (String.format ("Track size........... %,d%n", trackSize));
text.append (String.format ("Sector size..... %d%n", sectorSize)); text.append (String.format ("Sector size.......... %d%n", sectorSize));
text.append (String.format ("Interleave...... %d", interleave)); text.append (String.format ("Interleave........... %d", interleave));
if (wozFile != null)
{
text.append ("\n\n");
text.append (wozFile);
}
return text.toString (); return text.toString ();
} }

View File

@ -2,8 +2,8 @@ package com.bytezone.diskbrowser.gui;
/*********************************************************************************************** /***********************************************************************************************
* Contains a single instance of FileSystemTab, and any number of AppleDiskTab instances. * Contains a single instance of FileSystemTab, and any number of AppleDiskTab instances.
* *
* *
***********************************************************************************************/ ***********************************************************************************************/
import java.awt.Dimension; import java.awt.Dimension;
@ -50,7 +50,6 @@ class CatalogPanel extends JTabbedPane
private Font font; private Font font;
private FileSystemTab fileTab; private FileSystemTab fileTab;
private final List<AppleDiskTab> diskTabs = new ArrayList<AppleDiskTab> (); private final List<AppleDiskTab> diskTabs = new ArrayList<AppleDiskTab> ();
// private final DocumentCreatorFactory lister;
private final DiskAndFileSelector selector = new DiskAndFileSelector (); private final DiskAndFileSelector selector = new DiskAndFileSelector ();
private final RedoHandler redoHandler; private final RedoHandler redoHandler;
private CloseTabAction closeTabAction; private CloseTabAction closeTabAction;
@ -390,7 +389,7 @@ class CatalogPanel extends JTabbedPane
// if (evt.getKey ().equals (PreferencesDialog.prefsCatalogFont)) // if (evt.getKey ().equals (PreferencesDialog.prefsCatalogFont))
// font = new Font (evt.getNewValue (), Font.PLAIN, font.getSize ()); // font = new Font (evt.getNewValue (), Font.PLAIN, font.getSize ());
// if (evt.getKey ().equals (PreferencesDialog.prefsCatalogFontSize)) // if (evt.getKey ().equals (PreferencesDialog.prefsCatalogFontSize))
// font = new Font (font.getFontName (), // font = new Font (font.getFontName (),
// Font.PLAIN, Integer.parseInt (evt.getNewValue ())); // Font.PLAIN, Integer.parseInt (evt.getNewValue ()));
// if (fileTab != null) // if (fileTab != null)
// fileTab.setTreeFont (font); // fileTab.setTreeFont (font);

View File

@ -24,6 +24,7 @@ class DataPanel extends JTabbedPane
AssemblerPreferencesListener AssemblerPreferencesListener
{ {
private static final int TEXT_WIDTH = 65; private static final int TEXT_WIDTH = 65;
private static final int BACKGROUND = 245;
JTextArea hexText; JTextArea hexText;
JTextArea disassemblyText; JTextArea disassemblyText;
@ -70,6 +71,9 @@ class DataPanel extends JTabbedPane
imagePane = imagePane =
new JScrollPane (imagePanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, new JScrollPane (imagePanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
imagePane.setBorder (null);
imagePane.getVerticalScrollBar ().setUnitIncrement (50); imagePane.getVerticalScrollBar ().setUnitIncrement (50);
imagePane.getHorizontalScrollBar ().setUnitIncrement (25); imagePane.getHorizontalScrollBar ().setUnitIncrement (25);
@ -321,7 +325,7 @@ class DataPanel extends JTabbedPane
public ImagePanel () public ImagePanel ()
{ {
this.setBackground (Color.gray); this.setBackground (new Color (BACKGROUND, BACKGROUND, BACKGROUND));
} }
private void setImage (BufferedImage image) private void setImage (BufferedImage image)

View File

@ -30,10 +30,10 @@ class FileSystemTab extends AbstractTab
{ {
File rootFolder; File rootFolder;
public FileSystemTab (File folder, DiskAndFileSelector selector, RedoHandler navMan, public FileSystemTab (File folder, DiskAndFileSelector selector, RedoHandler redoHandler,
Font font, DiskSelectedEvent diskEvent) Font font, DiskSelectedEvent diskEvent)
{ {
super (navMan, selector, font); super (redoHandler, selector, font);
this.rootFolder = folder; this.rootFolder = folder;
TreeBuilder tb = new TreeBuilder (folder); TreeBuilder tb = new TreeBuilder (folder);
@ -52,7 +52,7 @@ class FileSystemTab extends AbstractTab
} }
if (diskEvent != null) if (diskEvent != null)
navMan.diskSelected (diskEvent); redoHandler.diskSelected (diskEvent);
else else
System.out.println ("No disk event"); System.out.println ("No disk event");
} }

View File

@ -1,7 +1,7 @@
package com.bytezone.diskbrowser.nib; package com.bytezone.diskbrowser.nib;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
public class DiskReaderGCR extends DiskReader class DiskReaderGCR extends DiskReader
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
static final int TAG_SIZE = 12; static final int TAG_SIZE = 12;
@ -26,7 +26,7 @@ public class DiskReaderGCR extends DiskReader
// decode four disk bytes into three data bytes (174 * 3 + 2 = 524) // decode four disk bytes into three data bytes (174 * 3 + 2 = 524)
while (true) while (true)
{ {
// ROL checksum // ROL checksum (also keep left-shifted hi bit)
checksums[2] = (checksums[2] & 0xFF) << 1; // shift left checksums[2] = (checksums[2] & 0xFF) << 1; // shift left
if ((checksums[2] > 0xFF)) // check for overflow if ((checksums[2] > 0xFF)) // check for overflow
++checksums[2]; // set bit 0 ++checksums[2]; // set bit 0
@ -64,29 +64,29 @@ public class DiskReaderGCR extends DiskReader
byte b2 = (byte) (d2 | (d3 << 6)); byte b2 = (byte) (d2 | (d3 << 6));
// compare disk checksums with calculated checksums // compare disk checksums with calculated checksums
if ((checksums[0] & 0xFF) != (b0 & 0xFF) // if ((byte) (checksums[0] & 0xFF) != b0 //
|| (checksums[1] & 0xFF) != (b1 & 0xFF) // || (byte) (checksums[1] & 0xFF) != b1 //
|| (checksums[2] & 0xFF) != (b2 & 0xFF)) || (byte) (checksums[2] & 0xFF) != b2)
throw new DiskNibbleException ("Checksum failed"); throw new DiskNibbleException ("Checksum failed");
return outBuffer; return outBuffer;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private byte checksum (byte diskByte, int[] checksums, int a) private byte checksum (byte diskByte, int[] checksums, int current)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int b = (a + 2) % 3; int prev = (current + 2) % 3;
int val = (diskByte ^ checksums[b]) & 0xFF; int val = (diskByte ^ checksums[prev]) & 0xFF;
checksums[a] += val; // prepare next checksum checksums[current] += val; // add to this checksum
if (checksums[b] > 0xFF) // is there a carry? if (checksums[prev] > 0xFF) // was there a carry last time?
{ {
++checksums[a]; // pass it on ++checksums[current]; // add it to this checksum
checksums[b] &= 0xFF; // back to 8 bits checksums[prev] &= 0xFF; // reset previous carry
} }
return (byte) val; // converted data byte return (byte) val; // converted data byte
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//

View File

@ -36,6 +36,7 @@ public class WozFile
public final File file; public final File file;
private Info info; private Info info;
private Meta meta;
private int diskSectors; private int diskSectors;
private byte[] addressPrologue; private byte[] addressPrologue;
@ -70,6 +71,8 @@ public class WozFile
int ptr = 12; int ptr = 12;
while (ptr < buffer.length) while (ptr < buffer.length)
{ {
validateChunk (buffer, ptr);
String chunkId = new String (buffer, ptr, 4); String chunkId = new String (buffer, ptr, 4);
int size = val32 (buffer, ptr + 4); int size = val32 (buffer, ptr + 4);
if (debug1) if (debug1)
@ -80,7 +83,7 @@ public class WozFile
case "INFO": // 60 bytes case "INFO": // 60 bytes
info = new Info (buffer, ptr); info = new Info (buffer, ptr);
if (info.wozVersion >= 2) if (info.wozVersion >= 2)
setSectors (info.bootSectorFormat == 2 ? 13 : 16); setPrologue (info.bootSectorFormat == 2 ? 13 : 16);
break; break;
case "TMAP": // 160 bytes case "TMAP": // 160 bytes
tmap (buffer, ptr); tmap (buffer, ptr);
@ -89,7 +92,7 @@ public class WozFile
tracks = trks (buffer, ptr); tracks = trks (buffer, ptr);
break; break;
case "META": case "META":
meta (buffer, ptr, size); meta = new Meta (buffer, ptr, size);
break; break;
case "WRIT": case "WRIT":
break; break;
@ -124,6 +127,33 @@ public class WozFile
} }
} }
// ---------------------------------------------------------------------------------//
private boolean validateChunk (byte[] buffer, int ptr) throws DiskNibbleException
// ---------------------------------------------------------------------------------//
{
int size = val32 (buffer, ptr + 4);
if (size <= 0 || size + ptr + 8 > buffer.length)
{
if (info != null)
System.out.println (info);
throw new DiskNibbleException (String.format ("Invalid chunk size: %08X%n", size));
}
for (int i = 0; i < 4; i++)
{
int val = buffer[ptr + i] & 0xFF;
if (val < 'A' || val > 'Z') // not uppercase ascii
{
if (info != null)
System.out.println (info);
throw new DiskNibbleException (
String.format ("Invalid chunk name character: %02X%n", val));
}
}
return true;
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public byte[] getDiskBuffer () public byte[] getDiskBuffer ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -160,7 +190,7 @@ public class WozFile
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void setSectors (int diskSectors) private void setPrologue (int diskSectors)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
this.diskSectors = diskSectors; this.diskSectors = diskSectors;
@ -174,27 +204,6 @@ public class WozFile
ptr += 8; ptr += 8;
} }
// ---------------------------------------------------------------------------------//
private void meta (byte[] buffer, int ptr, int length)
// ---------------------------------------------------------------------------------//
{
ptr += 8;
if (debug1)
{
String metaData = new String (buffer, ptr, length);
String[] chunks = metaData.split ("\n");
for (String chunk : chunks)
{
String[] parts = chunk.split ("\t");
if (parts.length >= 2)
System.out.printf ("%-20s %s%n", parts[0], parts[1]);
else
System.out.printf ("%-20s%n", parts[0]);
}
}
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private List<Track> trks (byte[] rawBuffer, int ptr) private List<Track> trks (byte[] rawBuffer, int ptr)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -274,6 +283,16 @@ public class WozFile
} }
} }
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
if (meta != null)
return info.toString () + "\n\n" + meta.toString ();
return info.toString ();
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public static void main (String[] args) public static void main (String[] args)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -314,7 +333,9 @@ public class WozFile
int requiredRam; int requiredRam;
int largestTrack; int largestTrack;
// ---------------------------------------------------------------------------------//
Info (byte[] buffer, int ptr) Info (byte[] buffer, int ptr)
// ---------------------------------------------------------------------------------//
{ {
wozVersion = val8 (buffer, ptr + 8); wozVersion = val8 (buffer, ptr + 8);
@ -343,7 +364,7 @@ public class WozFile
public String toString () public String toString ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ("WOZ info:\n\n");
String diskTypeText = diskType == 1 ? "5.25" : "3.5"; String diskTypeText = diskType == 1 ? "5.25" : "3.5";
@ -374,6 +395,46 @@ public class WozFile
} }
} }
// -----------------------------------------------------------------------------------//
class Meta
// -----------------------------------------------------------------------------------//
{
List<String> lines = new ArrayList<> ();
// ---------------------------------------------------------------------------------//
Meta (byte[] buffer, int ptr, int length)
// ---------------------------------------------------------------------------------//
{
String dots = " ......................";
String metaData = new String (buffer, ptr + 8, length);
String[] chunks = metaData.split ("\n");
for (String chunk : chunks)
{
String[] parts = chunk.split ("\t");
if (parts.length >= 2)
lines.add (String.format ("%-21.21s %s", parts[0] + dots, parts[1]));
else
lines.add (String.format ("%-21.21s", parts[0] + dots));
}
}
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ("WOZ meta:\n\n");
for (String line : lines)
text.append (String.format ("%s%n", line));
if (text.length () > 0)
text.deleteCharAt (text.length () - 1);
return text.toString ();
}
}
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
class Track implements Iterable<Sector> class Track implements Iterable<Sector>
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
@ -428,9 +489,9 @@ public class WozFile
if (addressPrologue == null) // WOZ1 if (addressPrologue == null) // WOZ1
if (findNext (address16prologue, ptr) > 0) if (findNext (address16prologue, ptr) > 0)
setSectors (16); setPrologue (16);
else if (findNext (address13prologue, ptr) > 0) else if (findNext (address13prologue, ptr) > 0)
setSectors (13); setPrologue (13);
else else
throw new DiskNibbleException ("No address prologue found"); throw new DiskNibbleException ("No address prologue found");

View File

@ -100,7 +100,7 @@ class FileEntry extends CatalogEntry implements ProdosConstants
{ {
int storageType = buffer2[i] & 0x0F; int storageType = buffer2[i] & 0x0F;
int keyBlock = HexFormatter.unsignedShort (buffer2, i + 1); int keyBlock = HexFormatter.unsignedShort (buffer2, i + 1);
// int eof = HexFormatter.intValue (buffer2[i + 3], buffer2[i + 4], buffer2[i + 5]); int eof = HexFormatter.intValue (buffer2[i + 3], buffer2[i + 4], buffer2[i + 5]);
addDataBlocks (storageType, keyBlock); addDataBlocks (storageType, keyBlock);
} }
} }
@ -265,7 +265,7 @@ class FileEntry extends CatalogEntry implements ProdosConstants
else if (endOfFile == 0x4000 && auxType == 0x4000) else if (endOfFile == 0x4000 && auxType == 0x4000)
file = new DoubleHiResImage (name, exactBuffer); file = new DoubleHiResImage (name, exactBuffer);
else if (oneOf (endOfFile, 0x1FF8, 0x1FFF, 0x2000, 0x4000) else if (oneOf (endOfFile, 0x1FF8, 0x1FFF, 0x2000, 0x4000)
&& oneOf (auxType, 0x1FFF, 0x2000, 0x4000)) && oneOf (auxType, 0x1FFF, 0x2000, 0x4000, 0x6000))
file = new OriginalHiResImage (name, exactBuffer, auxType); file = new OriginalHiResImage (name, exactBuffer, auxType);
else if (endOfFile == 38400 && name.startsWith ("LVL.")) else if (endOfFile == 38400 && name.startsWith ("LVL."))
file = new LodeRunner (name, exactBuffer); file = new LodeRunner (name, exactBuffer);

View File

@ -7,6 +7,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import com.bytezone.diskbrowser.applefile.AppleFileSource; import com.bytezone.diskbrowser.applefile.AppleFileSource;
import com.bytezone.diskbrowser.applefile.BootSector; import com.bytezone.diskbrowser.applefile.BootSector;
@ -31,6 +32,7 @@ public class ProdosDisk extends AbstractFormattedDisk
private final List<DirectoryHeader> headerEntries = new ArrayList<DirectoryHeader> (); private final List<DirectoryHeader> headerEntries = new ArrayList<DirectoryHeader> ();
protected VolumeDirectoryHeader vdh; protected VolumeDirectoryHeader vdh;
private final DefaultMutableTreeNode volumeNode;
private static final boolean debug = false; private static final boolean debug = false;
@ -56,7 +58,7 @@ public class ProdosDisk extends AbstractFormattedDisk
bootSector = new BootSector (disk, buffer, "Prodos", da); bootSector = new BootSector (disk, buffer, "Prodos", da);
DefaultMutableTreeNode root = getCatalogTreeRoot (); DefaultMutableTreeNode root = getCatalogTreeRoot ();
DefaultMutableTreeNode volumeNode = new DefaultMutableTreeNode ("empty volume node"); volumeNode = new DefaultMutableTreeNode ("empty volume node");
root.add (volumeNode); root.add (volumeNode);
processDirectoryBlock (2, null, volumeNode); processDirectoryBlock (2, null, volumeNode);
@ -73,6 +75,48 @@ public class ProdosDisk extends AbstractFormattedDisk
else if (stillAvailable (da2)) else if (stillAvailable (da2))
falseNegatives++; falseNegatives++;
} }
sort (volumeNode);
((DefaultTreeModel) catalogTree.getModel ()).reload ();
}
public void sort (DefaultMutableTreeNode node)
{
for (int base = 0; base < node.getChildCount (); base++)
{
DefaultMutableTreeNode baseNode = (DefaultMutableTreeNode) node.getChildAt (base);
if (!baseNode.isLeaf ())
{
sort (baseNode);
continue;
}
String childName = ((FileEntry) baseNode.getUserObject ()).name;
DefaultMutableTreeNode smallestNode = null;
String smallestName = childName;
int smallestPos = -1;
for (int j = base + 1; j < node.getChildCount (); j++)
{
DefaultMutableTreeNode compareNode = (DefaultMutableTreeNode) node.getChildAt (j);
if (!compareNode.isLeaf ())
continue;
String compareName = ((FileEntry) compareNode.getUserObject ()).name;
if (smallestName.compareToIgnoreCase (compareName) > 0)
{
smallestNode = compareNode;
smallestName = compareName;
smallestPos = j;
}
}
if (smallestNode != null)
{
node.insert (baseNode, smallestPos);
node.insert (smallestNode, base);
}
}
} }
private void processDirectoryBlock (int block, FileEntry parent, private void processDirectoryBlock (int block, FileEntry parent,