Better disk recognition

This commit is contained in:
Denis Molony 2016-12-15 11:01:42 +11:00
parent 979e98eae5
commit 29a577839b
9 changed files with 221 additions and 140 deletions

View File

@ -161,19 +161,17 @@ public class CPMDisk extends AbstractFormattedDisk
{
disk.setInterleave (3);
byte[] buffer = disk.readSector (0, 8);
String text = new String (buffer, 16, 24);
if ("DIR ERA TYPESAVEREN USER".equals (text))
return true;
buffer = disk.readSector (0, 4);
text = new String (buffer, 16, 24);
if ("DIR ERA TYPESAVEREN USER".equals (text))
return true;
for (int i = 8; i >= 4; i -= 2)
{
byte[] buffer = disk.readSector (0, i);
String text = new String (buffer, 16, 24);
if ("DIR ERA TYPESAVEREN USER".equals (text))
return true;
}
for (int sector = 0; sector < 8; sector++)
{
buffer = disk.readSector (3, sector);
byte[] buffer = disk.readSector (3, sector);
for (int i = 0; i < buffer.length; i += 32)
{
int val = buffer[i] & 0xFF;

View File

@ -16,6 +16,7 @@ import com.bytezone.diskbrowser.pascal.PascalDisk;
import com.bytezone.diskbrowser.prodos.ProdosDisk;
import com.bytezone.diskbrowser.utilities.FileFormatException;
import com.bytezone.diskbrowser.utilities.NuFX;
import com.bytezone.diskbrowser.utilities.Utility;
import com.bytezone.diskbrowser.wizardry.Wizardry4BootDisk;
import com.bytezone.diskbrowser.wizardry.WizardryScenarioDisk;
@ -43,13 +44,41 @@ public class DiskFactory
String suffix = path.substring (path.lastIndexOf (".") + 1).toLowerCase ();
Boolean compressed = false;
Path p = Paths.get (path);
Path originalPath = Paths.get (path);
if (suffix.equals ("gz"))
{
try
{
InputStream in = new GZIPInputStream (new FileInputStream (path));
File tmp = File.createTempFile ("gzip", null);
FileOutputStream fos = new FileOutputStream (tmp);
int bytesRead;
byte[] buffer = new byte[1024];
while ((bytesRead = in.read (buffer)) > 0)
fos.write (buffer, 0, bytesRead);
fos.close ();
in.close ();
tmp.deleteOnExit ();
suffix = Utility.getSuffix (file.getName ()); // ignores the .gz
file = tmp;
compressed = true;
}
catch (IOException e) // can get EOFException: Unexpected end of ZLIB input stream
{
e.printStackTrace ();
return null;
}
}
if (suffix.equals ("sdk"))
{
try
{
NuFX nuFX = new NuFX (p);
NuFX nuFX = new NuFX (file);
File tmp = File.createTempFile ("sdk", null);
FileOutputStream fos = new FileOutputStream (tmp);
fos.write (nuFX.getBuffer ());
@ -69,32 +98,6 @@ public class DiskFactory
return null;
}
}
else if (suffix.equals ("gz")) // will be .dsk.gz
{
try
{
InputStream in = new GZIPInputStream (new FileInputStream (path));
File tmp = File.createTempFile ("gzip", null);
FileOutputStream fos = new FileOutputStream (tmp);
int bytesRead;
byte[] buffer = new byte[1024];
while ((bytesRead = in.read (buffer)) > 0)
fos.write (buffer, 0, bytesRead);
fos.close ();
in.close ();
tmp.deleteOnExit ();
file = tmp;
suffix = "dsk";
compressed = true;
}
catch (IOException e) // can get EOFException: Unexpected end of ZLIB input stream
{
e.printStackTrace ();
return null;
}
}
FormattedDisk disk = null;
FormattedDisk disk2 = null;
@ -132,7 +135,7 @@ public class DiskFactory
if (disk != null)
{
if (compressed)
disk.setOriginalPath (p);
disk.setOriginalPath (originalPath);
return disk;
}
@ -231,7 +234,7 @@ public class DiskFactory
if (disk != null)
{
if (compressed)
disk.setOriginalPath (p);
disk.setOriginalPath (originalPath);
return disk;
}
@ -283,7 +286,7 @@ public class DiskFactory
"Factory creating disk : " + disk.getDisk ().getFile ().getAbsolutePath ());
if (disk != null && compressed)
disk.setOriginalPath (p);
disk.setOriginalPath (originalPath);
return disk;
}

View File

@ -2,7 +2,6 @@ package com.bytezone.diskbrowser.duplicates;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.swing.table.AbstractTableModel;
@ -11,27 +10,34 @@ import com.bytezone.diskbrowser.utilities.Utility;
public class DiskTableModel extends AbstractTableModel
{
static final String[] headers =
{ "Path", "Name", "Type", "Size", "Dup name", "Dup data", "Checksum" };
{ "Path", "Name", "Type", "Size", "# names", "Checksum", "# checksums" };
Map<String, DiskDetails> fileNameMap;
Map<Long, DiskDetails> checkSumMap;
List<TableLine> lines = new ArrayList<DiskTableModel.TableLine> ();
// Map<String, DiskDetails> fileNameMap;
// Map<Long, DiskDetails> checkSumMap;
private final List<TableLine> lines = new ArrayList<DiskTableModel.TableLine> ();
private final RootFolderData rootFolderData;
public DiskTableModel (RootFolderData rootFolderData)
{
fileNameMap = rootFolderData.fileNameMap;
checkSumMap = rootFolderData.checksumMap;
// fileNameMap = rootFolderData.fileNameMap;
// checkSumMap = rootFolderData.checksumMap;
this.rootFolderData = rootFolderData;
for (String key : fileNameMap.keySet ())
for (String key : rootFolderData.fileNameMap.keySet ())
{
DiskDetails original = fileNameMap.get (key);
lines.add (new TableLine (original));
DiskDetails original = rootFolderData.fileNameMap.get (key);
lines.add (new TableLine (original, rootFolderData));
for (DiskDetails duplicate : original.getDuplicateNames ())
lines.add (new TableLine (duplicate));
lines.add (new TableLine (duplicate, rootFolderData));
}
}
public DiskDetails getDiskDetails (int rowIndex)
{
return lines.get (rowIndex).diskDetails;
}
@Override
public String getColumnName (int column)
{
@ -47,7 +53,10 @@ public class DiskTableModel extends AbstractTableModel
@Override
public int getColumnCount ()
{
return headers.length;
if (rootFolderData.doChecksums)
return headers.length;
else
return headers.length - 1;
}
@Override
@ -73,9 +82,9 @@ public class DiskTableModel extends AbstractTableModel
case 4:
return line.duplicateNames;
case 5:
return line.duplicateChecksums;
case 6:
return line.checksum;
case 6:
return line.duplicateChecksums;
default:
return "???";
}
@ -93,7 +102,7 @@ public class DiskTableModel extends AbstractTableModel
{
TableLine line = lines.get (rowIndex);
line.checksum = line.diskDetails.calculateChecksum ();
fireTableCellUpdated (rowIndex, 6);
fireTableCellUpdated (rowIndex, 5);
}
class TableLine
@ -107,7 +116,7 @@ public class DiskTableModel extends AbstractTableModel
private final String type;
private final long size;
public TableLine (DiskDetails diskDetails)
public TableLine (DiskDetails diskDetails, RootFolderData rootFolderData)
{
this.diskDetails = diskDetails;
shortName = diskDetails.getShortName ();
@ -118,17 +127,22 @@ public class DiskTableModel extends AbstractTableModel
String rootName = diskDetails.getRootName ();
path = rootName.substring (0, rootName.length () - shortName.length ());
if (diskDetails.isDuplicateChecksum ())
{
DiskDetails original = checkSumMap.get (diskDetails.getChecksum ());
duplicateChecksums = original.getDuplicateChecksums ().size () + 1;
}
if (rootFolderData.doChecksums)
if (diskDetails.isDuplicateChecksum ())
{
DiskDetails original =
rootFolderData.checksumMap.get (diskDetails.getChecksum ());
duplicateChecksums = original.getDuplicateChecksums ().size () + 1;
}
else
duplicateChecksums = diskDetails.getDuplicateChecksums ().size () + 1;
else
duplicateChecksums = diskDetails.getDuplicateChecksums ().size () + 1;
duplicateChecksums = 0;
if (diskDetails.isDuplicateName ())
{
DiskDetails original = fileNameMap.get (diskDetails.getShortName ());
DiskDetails original =
rootFolderData.fileNameMap.get (diskDetails.getShortName ());
duplicateNames = original.getDuplicateNames ().size () + 1;
}
else

View File

@ -29,10 +29,12 @@ public class DisksWindow extends JFrame
private final JButton btnHide = new JButton ("Close");
private final JButton btnTotals = new JButton ("Totals");
private final JPanel topPanel = new JPanel ();
private final List<JCheckBox> boxes = new ArrayList<JCheckBox> ();
private TableRowSorter<DiskTableModel> sorter;
private final CheckBoxActionListener checkBoxActionListener =
new CheckBoxActionListener ();
private DiskTableModel diskTableModel;
private final RootFolderData rootFolderData;
@ -40,6 +42,7 @@ public class DisksWindow extends JFrame
{
super ("Disk List - " + rootFolderData.getRootFolder ().getAbsolutePath ());
this.rootFolderData = rootFolderData;
// rootFolderData.progressPanel.cancelled = false;
table = new JTable ();
JScrollPane scrollPane =
@ -102,11 +105,15 @@ public class DisksWindow extends JFrame
diskTableModel = new DiskTableModel (rootFolderData);
table.setModel (diskTableModel);
int[] columnWidths = { 300, 300, 30, 40, 40, 40, 100 };
int[] columnWidths = { 300, 300, 30, 40, 40, 100 };
TableColumnModel tcm = table.getColumnModel ();
for (int i = 0; i < columnWidths.length; i++)
tcm.getColumn (i).setPreferredWidth (columnWidths[i]);
// extra column if doing checksums
if (rootFolderData.doChecksums)
tcm.getColumn (6).setPreferredWidth (40);
tcm.getColumn (3).setCellRenderer (NumberRenderer.getIntegerRenderer ());
sorter = new TableRowSorter<DiskTableModel> ((DiskTableModel) table.getModel ());
@ -131,7 +138,7 @@ public class DisksWindow extends JFrame
int actualRow = sorter.convertRowIndexToModel (selectedRow);
DiskTableModel diskTableModel = (DiskTableModel) table.getModel ();
DiskDetails diskDetails = diskTableModel.lines.get (actualRow).diskDetails;
DiskDetails diskDetails = diskTableModel.getDiskDetails (actualRow);
long checksum = diskDetails.getChecksum ();
if (checksum == 0)
@ -166,8 +173,7 @@ public class DisksWindow extends JFrame
setLocationRelativeTo (null);
btnExport.setEnabled (true);
if (!rootFolderData.showTotals)
setVisible (true);
setVisible (true);
}
private String getFilterText ()

View File

@ -14,31 +14,19 @@ public class DuplicateSwingWorker extends SwingWorker<Void, RootFolderData>
public DuplicateSwingWorker (RootFolderData rootFolderData)
{
this.rootFolderData = rootFolderData;
rootFolderData.dialogTotals.setVisible (true);
}
@Override
protected Void doInBackground () throws Exception
{
traverse (rootFolderData.getRootFolder ());
publish (rootFolderData);
rootFolderData.print ();
return null;
}
@Override
protected void done ()
{
try
{
if (!rootFolderData.showTotals)
rootFolderData.dialogTotals.setVisible (false);
rootFolderData.windowDisks.setTableData (rootFolderData);
}
catch (Exception e)
{
e.printStackTrace ();
}
rootFolderData.done ();
}
@Override
@ -49,6 +37,9 @@ public class DuplicateSwingWorker extends SwingWorker<Void, RootFolderData>
private void traverse (File directory)
{
if (rootFolderData.progressPanel.cancelled)
return;
File[] files = directory.listFiles ();
if (files == null || files.length == 0)
@ -59,6 +50,9 @@ public class DuplicateSwingWorker extends SwingWorker<Void, RootFolderData>
for (File file : files)
{
if (rootFolderData.progressPanel.cancelled)
return;
if (file.isDirectory ())
{
rootFolderData.incrementFolders ();
@ -70,7 +64,7 @@ public class DuplicateSwingWorker extends SwingWorker<Void, RootFolderData>
if (Utility.validFileType (fileName) && file.length () > 0)
{
rootFolderData.incrementType (file, fileName);
if ((rootFolderData.totalDisks % 500) == 0)
if ((rootFolderData.totalDisks % 250) == 0)
publish (rootFolderData);
}
}

View File

@ -1,10 +1,8 @@
package com.bytezone.diskbrowser.duplicates;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
@ -12,6 +10,7 @@ import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
@ -31,15 +30,12 @@ public class RootFolderData
final Map<Long, DiskDetails> checksumMap = new HashMap<Long, DiskDetails> ();
final Map<String, DiskDetails> fileNameMap = new TreeMap<String, DiskDetails> ();
final ProgressPanel progressPanel;
public JDialog dialogTotals;
public DisksWindow windowDisks;
public DisksWindow disksWindow;
public final List<DiskTableSelectionListener> listeners =
new ArrayList<DiskTableSelectionListener> ();
public boolean doChecksums;
public boolean showTotals;
int totalDisks;
int totalFolders;
@ -47,29 +43,109 @@ public class RootFolderData
// total files for each suffix (uncompressed, .gz, .zip, total)
int[][] typeTotals;
public RootFolderData ()
// Progress dialog
ProgressPanel progressPanel;
public JDialog dialogTotals;
JPanel southPanel;
JButton btnCancel;
JButton btnOK;
// public RootFolderData ()
// {
// }
private void createWindows ()
{
southPanel = new JPanel ();
btnCancel = new JButton ("Cancel");
btnOK = new JButton ("OK");
progressPanel = new ProgressPanel ();
progressPanel.setPreferredSize (new Dimension (560, 300));
dialogTotals = new JDialog (windowDisks);
dialogTotals.add (progressPanel);
dialogTotals = new JDialog (disksWindow);
dialogTotals.add (progressPanel, BorderLayout.CENTER);
southPanel.add (btnCancel);
dialogTotals.add (southPanel, BorderLayout.SOUTH);
dialogTotals.setTitle ("Disk Totals");
dialogTotals.pack ();
dialogTotals.setLocationRelativeTo (null);
// btnCancel.requestFocus ();
btnCancel.addActionListener (new ActionListener ()
{
@Override
public void actionPerformed (ActionEvent e)
{
progressPanel.cancelled = true;
dialogTotals.setVisible (false);
}
});
btnOK.addActionListener (new ActionListener ()
{
@Override
public void actionPerformed (ActionEvent e)
{
dialogTotals.setVisible (false);
}
});
}
public void count (boolean doChecksums)
{
if (dialogTotals == null)
createWindows ();
clear ();
setButton (btnCancel);
this.doChecksums = doChecksums;
progressPanel.cancelled = false;
disksWindow = new DisksWindow (this);
dialogTotals.setVisible (true);
new DuplicateSwingWorker (this).execute (); // start SwingWorker
}
public void done () // SwingWorker has completed
{
print ();
dialogTotals.repaint ();
dialogTotals.setVisible (false);
if (progressPanel.cancelled)
disksWindow = null;
else
{
disksWindow.setTableData (this);
setButton (btnOK);
}
}
private void setButton (JButton button)
{
southPanel.removeAll ();
southPanel.add (button);
dialogTotals.revalidate ();
dialogTotals.repaint ();
}
public void setRootFolder (File rootFolder)
{
this.rootFolder = rootFolder;
rootFolderNameLength = rootFolder.getAbsolutePath ().length ();
disksWindow = null; // force a recount
// clear ();
}
private void clear ()
{
typeTotals = new int[4][Utility.suffixes.size ()];
totalDisks = 0;
totalFolders = 0;
windowDisks = null;
checksumMap.clear ();
fileNameMap.clear ();
rootFolderNameLength = rootFolder.getAbsolutePath ().length ();
}
public File getRootFolder ()
@ -82,11 +158,6 @@ public class RootFolderData
++totalFolders;
}
public int getTotalType (int type)
{
return typeTotals[0][type] + typeTotals[1][type] + typeTotals[2][type];
}
public void incrementType (File file, String filename)
{
int pos = Utility.getSuffixNo (filename);
@ -127,6 +198,11 @@ public class RootFolderData
}
}
public int getTotalType (int type)
{
return typeTotals[0][type] + typeTotals[1][type] + typeTotals[2][type];
}
public void print ()
{
System.out.printf ("%nFolders ...... %,7d%n", totalFolders);
@ -151,10 +227,13 @@ public class RootFolderData
System.out.printf ("Total %,7d %,7d %,7d %,7d%n%n", grandTotal[0],
grandTotal[1], grandTotal[2], grandTotal[3]);
System.out.printf ("Unique checksums: %,d%n", checksumMap.size ());
System.out.printf ("Duplicate disks : %,d%n", totalDisks - checksumMap.size ());
}
class ProgressPanel extends JPanel
{
public volatile boolean cancelled;
@Override
protected void paintComponent (Graphics graphics)
{

View File

@ -10,8 +10,6 @@ import javax.swing.KeyStroke;
import com.bytezone.common.DefaultAction;
import com.bytezone.diskbrowser.duplicates.DiskDetails;
import com.bytezone.diskbrowser.duplicates.DuplicateSwingWorker;
import com.bytezone.diskbrowser.duplicates.DisksWindow;
import com.bytezone.diskbrowser.duplicates.RootFolderData;
import com.bytezone.diskbrowser.gui.RootDirectoryAction.RootDirectoryChangeListener;
@ -43,7 +41,7 @@ public class DuplicateAction extends DefaultAction implements RootDirectoryChang
@Override
public void actionPerformed (ActionEvent arg0)
{
if (rootFolderData.windowDisks == null)
if (rootFolderData.disksWindow == null)
{
Object[] options = { "Generate checksums", "Disk names only", "Cancel" };
int option = JOptionPane.showOptionDialog (null,
@ -54,14 +52,10 @@ public class DuplicateAction extends DefaultAction implements RootDirectoryChang
"Generate Disk Listing", JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE, null, options, options[1]); // just disk names
if (option < 2)
{
rootFolderData.doChecksums = option == 0;
rootFolderData.windowDisks = new DisksWindow (rootFolderData);
new DuplicateSwingWorker (rootFolderData).execute ();
}
rootFolderData.count (option == 0);
}
else
rootFolderData.windowDisks.setVisible (true);
rootFolderData.disksWindow.setVisible (true);
}
public void addTableSelectionListener (DiskTableSelectionListener listener)

View File

@ -1,5 +1,6 @@
package com.bytezone.diskbrowser.utilities;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@ -10,11 +11,12 @@ import com.bytezone.common.Utility;
public class NuFX
{
private static String[] fileSystems = {//
"", "ProDOS/SOS", "DOS 3.3", "DOS 3.2", "Apple II Pascal", "Macintosh HFS",
"Macintosh MFS", "Lisa File System", "Apple CP/M", "", "MS-DOS", "High Sierra",
"ISO 9660", "AppleShare" };
private final Header header;
private static String[] fileSystems =
{//
"", "ProDOS/SOS", "DOS 3.3", "DOS 3.2", "Apple II Pascal", "Macintosh HFS",
"Macintosh MFS", "Lisa File System", "Apple CP/M", "", "MS-DOS", "High Sierra",
"ISO 9660", "AppleShare" };
private Header header;
private final byte[] buffer;
private final boolean debug = false;
@ -24,6 +26,17 @@ public class NuFX
public NuFX (Path path) throws FileFormatException, IOException
{
buffer = Files.readAllBytes (path);
readBuffer ();
}
public NuFX (File file) throws FileFormatException, IOException
{
buffer = Files.readAllBytes (file.toPath ());
readBuffer ();
}
private void readBuffer ()
{
header = new Header (buffer);
int dataPtr = 48;
@ -138,8 +151,8 @@ public class NuFX
private boolean isNuFile (byte[] buffer, int ptr)
{
if (buffer[ptr] == 0x4E && buffer[ptr + 1] == (byte) 0xF5 && buffer[ptr + 2] == 0x46
&& buffer[ptr + 3] == (byte) 0xE9 && buffer[ptr + 4] == 0x6C
&& buffer[ptr + 5] == (byte) 0xE5)
&& buffer[ptr + 3] == (byte) 0xE9 && buffer[ptr + 4] == 0x6C
&& buffer[ptr + 5] == (byte) 0xE5)
return true;
return false;
}
@ -147,7 +160,7 @@ public class NuFX
private boolean isBin2 (byte[] buffer, int ptr)
{
if (buffer[ptr] == 0x0A && buffer[ptr + 1] == 0x47 && buffer[ptr + 2] == 0x4C
&& buffer[ptr + 18] == (byte) 0x02)
&& buffer[ptr + 18] == (byte) 0x02)
return true;
return false;
}
@ -234,7 +247,7 @@ public class NuFX
private boolean isNuFX (byte[] buffer, int ptr)
{
if (buffer[ptr] == 0x4E && buffer[ptr + 1] == (byte) 0xF5 && buffer[ptr + 2] == 0x46
&& buffer[ptr + 3] == (byte) 0xD8)
&& buffer[ptr + 3] == (byte) 0xD8)
return true;
return false;
}
@ -249,7 +262,7 @@ public class NuFX
text.append (String.format ("Version ........ %d%n", version));
text.append (String.format ("Threads ........ %d%n", totThreads));
text.append (String.format ("File sys id .... %d (%s)%n", fileSystemID,
fileSystems[fileSystemID]));
fileSystems[fileSystemID]));
text.append (String.format ("Separator ...... %s%n", separator));
text.append (String.format ("Access ......... %,d%n", access));
text.append (String.format ("File type ...... %,d%n", fileType));

View File

@ -80,26 +80,6 @@ public class Utility
public static boolean validFileType (String filename)
{
// String lcFilename = filename.toLowerCase ();
// if (lcFilename.endsWith (".gz"))
// lcFilename = lcFilename.substring (0, lcFilename.length () - 3);
// else if (lcFilename.endsWith (".zip"))
// lcFilename = lcFilename.substring (0, lcFilename.length () - 4);
//
// int dotPos = lcFilename.lastIndexOf ('.');
// if (dotPos < 0)
// return false;
//
// String suffix = lcFilename.substring (dotPos + 1);
// int dotPos2 = filename.lastIndexOf ('.', dotPos - 1);
// if (dotPos2 > 0)
// {
// String suffix2 = filename.substring (dotPos2 + 1, dotPos).toLowerCase ();
// if (suffix.equals ("gz"))
// return suffixes.contains (suffix2) && !"gz".equals (suffix2);
// }
return suffixes.contains (getSuffix (filename));
}
}