diff --git a/src/com/bytezone/diskbrowser/applefile/SHRPictureFile2.java b/src/com/bytezone/diskbrowser/applefile/SHRPictureFile2.java index 4243410..4627b29 100644 --- a/src/com/bytezone/diskbrowser/applefile/SHRPictureFile2.java +++ b/src/com/bytezone/diskbrowser/applefile/SHRPictureFile2.java @@ -159,7 +159,7 @@ public class SHRPictureFile2 extends HiResImage break; default: - System.out.println ("PIC unknown aux " + auxType); + System.out.printf ("PIC unknown aux: %04X%n ", auxType); failureReason = "unknown PIC aux"; } } diff --git a/src/com/bytezone/diskbrowser/disk/AppleDisk.java b/src/com/bytezone/diskbrowser/disk/AppleDisk.java index 3dbbb8d..494976b 100755 --- a/src/com/bytezone/diskbrowser/disk/AppleDisk.java +++ b/src/com/bytezone/diskbrowser/disk/AppleDisk.java @@ -81,6 +81,8 @@ public class AppleDisk implements Disk private ActionListener actionListenerList; private List blockList; + private WozFile wozFile; + private final boolean debug = false; 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) { + this.wozFile = wozFile; this.tracks = tracks; this.sectors = sectors; file = wozFile.file; @@ -654,15 +657,21 @@ public class AppleDisk implements Disk if (path.startsWith (home)) path = "~" + path.substring (home.length ()); - text.append (String.format ("Path............ %s%n", path)); - text.append (String.format ("File name....... %s%n", file.getName ())); - text.append (String.format ("File size....... %,d%n", file.length ())); - text.append (String.format ("Tracks.......... %d%n", tracks)); - text.append (String.format ("Sectors......... %d%n", sectors)); - text.append (String.format ("Blocks.......... %,d%n", blocks)); - text.append (String.format ("Track size...... %,d%n", trackSize)); - text.append (String.format ("Sector size..... %d%n", sectorSize)); - text.append (String.format ("Interleave...... %d", interleave)); + text.append (String.format ("Path................. %s%n", path)); + text.append (String.format ("File name............ %s%n", file.getName ())); + text.append (String.format ("File size............ %,d%n", file.length ())); + text.append (String.format ("Tracks............... %d%n", tracks)); + text.append (String.format ("Sectors.............. %d%n", sectors)); + text.append (String.format ("Blocks............... %,d%n", blocks)); + text.append (String.format ("Track size........... %,d%n", trackSize)); + text.append (String.format ("Sector size.......... %d%n", sectorSize)); + text.append (String.format ("Interleave........... %d", interleave)); + + if (wozFile != null) + { + text.append ("\n\n"); + text.append (wozFile); + } return text.toString (); } diff --git a/src/com/bytezone/diskbrowser/gui/CatalogPanel.java b/src/com/bytezone/diskbrowser/gui/CatalogPanel.java index 7a54fa3..d8cb6c7 100755 --- a/src/com/bytezone/diskbrowser/gui/CatalogPanel.java +++ b/src/com/bytezone/diskbrowser/gui/CatalogPanel.java @@ -2,8 +2,8 @@ package com.bytezone.diskbrowser.gui; /*********************************************************************************************** * Contains a single instance of FileSystemTab, and any number of AppleDiskTab instances. - * - * + * + * ***********************************************************************************************/ import java.awt.Dimension; @@ -50,7 +50,6 @@ class CatalogPanel extends JTabbedPane private Font font; private FileSystemTab fileTab; private final List diskTabs = new ArrayList (); - // private final DocumentCreatorFactory lister; private final DiskAndFileSelector selector = new DiskAndFileSelector (); private final RedoHandler redoHandler; private CloseTabAction closeTabAction; @@ -390,7 +389,7 @@ class CatalogPanel extends JTabbedPane // if (evt.getKey ().equals (PreferencesDialog.prefsCatalogFont)) // font = new Font (evt.getNewValue (), Font.PLAIN, font.getSize ()); // if (evt.getKey ().equals (PreferencesDialog.prefsCatalogFontSize)) - // font = new Font (font.getFontName (), + // font = new Font (font.getFontName (), // Font.PLAIN, Integer.parseInt (evt.getNewValue ())); // if (fileTab != null) // fileTab.setTreeFont (font); diff --git a/src/com/bytezone/diskbrowser/gui/DataPanel.java b/src/com/bytezone/diskbrowser/gui/DataPanel.java index 55d5c6a..277b4d2 100755 --- a/src/com/bytezone/diskbrowser/gui/DataPanel.java +++ b/src/com/bytezone/diskbrowser/gui/DataPanel.java @@ -24,6 +24,7 @@ class DataPanel extends JTabbedPane AssemblerPreferencesListener { private static final int TEXT_WIDTH = 65; + private static final int BACKGROUND = 245; JTextArea hexText; JTextArea disassemblyText; @@ -70,6 +71,9 @@ class DataPanel extends JTabbedPane imagePane = new JScrollPane (imagePanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + + imagePane.setBorder (null); + imagePane.getVerticalScrollBar ().setUnitIncrement (50); imagePane.getHorizontalScrollBar ().setUnitIncrement (25); @@ -321,7 +325,7 @@ class DataPanel extends JTabbedPane public ImagePanel () { - this.setBackground (Color.gray); + this.setBackground (new Color (BACKGROUND, BACKGROUND, BACKGROUND)); } private void setImage (BufferedImage image) diff --git a/src/com/bytezone/diskbrowser/gui/FileSystemTab.java b/src/com/bytezone/diskbrowser/gui/FileSystemTab.java index dfeb8e8..52099a8 100755 --- a/src/com/bytezone/diskbrowser/gui/FileSystemTab.java +++ b/src/com/bytezone/diskbrowser/gui/FileSystemTab.java @@ -30,10 +30,10 @@ class FileSystemTab extends AbstractTab { File rootFolder; - public FileSystemTab (File folder, DiskAndFileSelector selector, RedoHandler navMan, + public FileSystemTab (File folder, DiskAndFileSelector selector, RedoHandler redoHandler, Font font, DiskSelectedEvent diskEvent) { - super (navMan, selector, font); + super (redoHandler, selector, font); this.rootFolder = folder; TreeBuilder tb = new TreeBuilder (folder); @@ -52,7 +52,7 @@ class FileSystemTab extends AbstractTab } if (diskEvent != null) - navMan.diskSelected (diskEvent); + redoHandler.diskSelected (diskEvent); else System.out.println ("No disk event"); } diff --git a/src/com/bytezone/diskbrowser/nib/DiskReaderGCR.java b/src/com/bytezone/diskbrowser/nib/DiskReaderGCR.java index 8b5ff3d..cde4115 100644 --- a/src/com/bytezone/diskbrowser/nib/DiskReaderGCR.java +++ b/src/com/bytezone/diskbrowser/nib/DiskReaderGCR.java @@ -1,7 +1,7 @@ package com.bytezone.diskbrowser.nib; // -----------------------------------------------------------------------------------// -public class DiskReaderGCR extends DiskReader +class DiskReaderGCR extends DiskReader // -----------------------------------------------------------------------------------// { 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) while (true) { - // ROL checksum + // ROL checksum (also keep left-shifted hi bit) checksums[2] = (checksums[2] & 0xFF) << 1; // shift left if ((checksums[2] > 0xFF)) // check for overflow ++checksums[2]; // set bit 0 @@ -64,29 +64,29 @@ public class DiskReaderGCR extends DiskReader byte b2 = (byte) (d2 | (d3 << 6)); // compare disk checksums with calculated checksums - if ((checksums[0] & 0xFF) != (b0 & 0xFF) // - || (checksums[1] & 0xFF) != (b1 & 0xFF) // - || (checksums[2] & 0xFF) != (b2 & 0xFF)) + if ((byte) (checksums[0] & 0xFF) != b0 // + || (byte) (checksums[1] & 0xFF) != b1 // + || (byte) (checksums[2] & 0xFF) != b2) throw new DiskNibbleException ("Checksum failed"); 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 val = (diskByte ^ checksums[b]) & 0xFF; - checksums[a] += val; // prepare next checksum + int prev = (current + 2) % 3; + int val = (diskByte ^ checksums[prev]) & 0xFF; + 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[b] &= 0xFF; // back to 8 bits + ++checksums[current]; // add it to this checksum + checksums[prev] &= 0xFF; // reset previous carry } - return (byte) val; // converted data byte + return (byte) val; // converted data byte } // ---------------------------------------------------------------------------------// diff --git a/src/com/bytezone/diskbrowser/nib/WozFile.java b/src/com/bytezone/diskbrowser/nib/WozFile.java index de7d189..21f488f 100644 --- a/src/com/bytezone/diskbrowser/nib/WozFile.java +++ b/src/com/bytezone/diskbrowser/nib/WozFile.java @@ -36,6 +36,7 @@ public class WozFile public final File file; private Info info; + private Meta meta; private int diskSectors; private byte[] addressPrologue; @@ -70,6 +71,8 @@ public class WozFile int ptr = 12; while (ptr < buffer.length) { + validateChunk (buffer, ptr); + String chunkId = new String (buffer, ptr, 4); int size = val32 (buffer, ptr + 4); if (debug1) @@ -80,7 +83,7 @@ public class WozFile case "INFO": // 60 bytes info = new Info (buffer, ptr); if (info.wozVersion >= 2) - setSectors (info.bootSectorFormat == 2 ? 13 : 16); + setPrologue (info.bootSectorFormat == 2 ? 13 : 16); break; case "TMAP": // 160 bytes tmap (buffer, ptr); @@ -89,7 +92,7 @@ public class WozFile tracks = trks (buffer, ptr); break; case "META": - meta (buffer, ptr, size); + meta = new Meta (buffer, ptr, size); break; case "WRIT": 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 () // ---------------------------------------------------------------------------------// @@ -160,7 +190,7 @@ public class WozFile } // ---------------------------------------------------------------------------------// - private void setSectors (int diskSectors) + private void setPrologue (int diskSectors) // ---------------------------------------------------------------------------------// { this.diskSectors = diskSectors; @@ -174,27 +204,6 @@ public class WozFile 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 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) // ---------------------------------------------------------------------------------// @@ -314,7 +333,9 @@ public class WozFile int requiredRam; int largestTrack; + // ---------------------------------------------------------------------------------// Info (byte[] buffer, int ptr) + // ---------------------------------------------------------------------------------// { wozVersion = val8 (buffer, ptr + 8); @@ -343,7 +364,7 @@ public class WozFile public String toString () // ---------------------------------------------------------------------------------// { - StringBuilder text = new StringBuilder (); + StringBuilder text = new StringBuilder ("WOZ info:\n\n"); String diskTypeText = diskType == 1 ? "5.25" : "3.5"; @@ -374,6 +395,46 @@ public class WozFile } } + // -----------------------------------------------------------------------------------// + class Meta + // -----------------------------------------------------------------------------------// + { + List 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 // -----------------------------------------------------------------------------------// @@ -428,9 +489,9 @@ public class WozFile if (addressPrologue == null) // WOZ1 if (findNext (address16prologue, ptr) > 0) - setSectors (16); + setPrologue (16); else if (findNext (address13prologue, ptr) > 0) - setSectors (13); + setPrologue (13); else throw new DiskNibbleException ("No address prologue found"); diff --git a/src/com/bytezone/diskbrowser/prodos/FileEntry.java b/src/com/bytezone/diskbrowser/prodos/FileEntry.java index 03cd7ed..cd5fa87 100755 --- a/src/com/bytezone/diskbrowser/prodos/FileEntry.java +++ b/src/com/bytezone/diskbrowser/prodos/FileEntry.java @@ -100,7 +100,7 @@ class FileEntry extends CatalogEntry implements ProdosConstants { int storageType = buffer2[i] & 0x0F; 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); } } @@ -265,7 +265,7 @@ class FileEntry extends CatalogEntry implements ProdosConstants else if (endOfFile == 0x4000 && auxType == 0x4000) file = new DoubleHiResImage (name, exactBuffer); 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); else if (endOfFile == 38400 && name.startsWith ("LVL.")) file = new LodeRunner (name, exactBuffer); diff --git a/src/com/bytezone/diskbrowser/prodos/ProdosDisk.java b/src/com/bytezone/diskbrowser/prodos/ProdosDisk.java index 618777a..b7a7f88 100755 --- a/src/com/bytezone/diskbrowser/prodos/ProdosDisk.java +++ b/src/com/bytezone/diskbrowser/prodos/ProdosDisk.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.List; import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; import com.bytezone.diskbrowser.applefile.AppleFileSource; import com.bytezone.diskbrowser.applefile.BootSector; @@ -31,6 +32,7 @@ public class ProdosDisk extends AbstractFormattedDisk private final List headerEntries = new ArrayList (); protected VolumeDirectoryHeader vdh; + private final DefaultMutableTreeNode volumeNode; private static final boolean debug = false; @@ -56,7 +58,7 @@ public class ProdosDisk extends AbstractFormattedDisk bootSector = new BootSector (disk, buffer, "Prodos", da); DefaultMutableTreeNode root = getCatalogTreeRoot (); - DefaultMutableTreeNode volumeNode = new DefaultMutableTreeNode ("empty volume node"); + volumeNode = new DefaultMutableTreeNode ("empty volume node"); root.add (volumeNode); processDirectoryBlock (2, null, volumeNode); @@ -73,6 +75,48 @@ public class ProdosDisk extends AbstractFormattedDisk else if (stillAvailable (da2)) 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,