dmolony-DiskBrowser/src/com/bytezone/diskbrowser/disk/DiskFactory.java

515 lines
15 KiB
Java
Raw Normal View History

2015-06-01 09:35:51 +00:00
package com.bytezone.diskbrowser.disk;
2016-07-30 06:12:01 +00:00
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
2015-06-01 09:35:51 +00:00
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.GZIPInputStream;
import com.bytezone.diskbrowser.cpm.CPMDisk;
import com.bytezone.diskbrowser.dos.DosDisk;
import com.bytezone.diskbrowser.infocom.InfocomDisk;
import com.bytezone.diskbrowser.pascal.PascalDisk;
import com.bytezone.diskbrowser.prodos.ProdosDisk;
2016-02-24 21:11:14 +00:00
import com.bytezone.diskbrowser.utilities.FileFormatException;
import com.bytezone.diskbrowser.utilities.NuFX;
2016-08-08 04:53:29 +00:00
import com.bytezone.diskbrowser.wizardry.Wizardry4BootDisk;
2015-06-01 09:35:51 +00:00
import com.bytezone.diskbrowser.wizardry.WizardryScenarioDisk;
public class DiskFactory
{
2016-08-03 11:32:47 +00:00
private static boolean debug = false;
2015-06-01 09:35:51 +00:00
private DiskFactory ()
{
}
public static FormattedDisk createDisk (File file)
{
return createDisk (file.getAbsolutePath ());
}
public static FormattedDisk createDisk (String path)
{
if (debug)
System.out.println ("Factory : " + path);
File file = new File (path);
if (!file.exists ())
return null;
String suffix = path.substring (path.lastIndexOf (".") + 1).toLowerCase ();
Boolean compressed = false;
Path p = Paths.get (path);
2016-02-28 05:41:10 +00:00
if (suffix.equals ("sdk"))
2015-06-01 09:35:51 +00:00
{
try
{
NuFX nuFX = new NuFX (p);
File tmp = File.createTempFile ("sdk", null);
FileOutputStream fos = new FileOutputStream (tmp);
fos.write (nuFX.getBuffer ());
fos.close ();
tmp.deleteOnExit ();
file = tmp;
suffix = "dsk";
compressed = true;
}
catch (IOException e)
{
e.printStackTrace ();
return null;
}
catch (FileFormatException e)
{
return null;
}
}
2016-02-28 05:41:10 +00:00
else if (suffix.equals ("gz")) // will be .dsk.gz
2015-06-01 09:35:51 +00:00
{
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;
}
2016-12-12 07:43:19 +00:00
catch (IOException e) // can get EOFException: Unexpected end of ZLIB input stream
2015-06-01 09:35:51 +00:00
{
e.printStackTrace ();
return null;
}
}
FormattedDisk disk = null;
FormattedDisk disk2 = null;
if (suffix.equals ("hdv"))
2016-02-24 02:13:52 +00:00
{
ProdosDisk prodosDisk = checkHardDisk (file);
if (prodosDisk != null)
return prodosDisk;
disk2 = check2mgDisk (file);
if (disk2 != null)
return disk2;
AppleDisk appleDisk = new AppleDisk (file, (int) file.length () / 4096, 8);
return new DataDisk (appleDisk);
}
2015-06-01 09:35:51 +00:00
if (suffix.equals ("2mg"))
2016-02-24 02:13:52 +00:00
{
disk2 = check2mgDisk (file);
if (disk2 != null)
return disk2;
AppleDisk appleDisk = new AppleDisk (file, (int) file.length () / 4096, 8);
return new DataDisk (appleDisk);
}
2015-06-01 09:35:51 +00:00
if (((suffix.equals ("po") || suffix.equals ("dsk")) && file.length () > 143360))
{
2016-03-01 00:16:31 +00:00
if (debug)
System.out.println ("Checking po or dsk hard drive: " + file.length ());
2015-06-01 09:35:51 +00:00
disk = checkHardDisk (file);
if (disk != null)
{
if (compressed)
disk.setOriginalPath (p);
return disk;
}
2016-03-01 00:16:31 +00:00
if (debug)
System.out.println ("Creating a data disk from bad length");
2016-11-28 00:45:17 +00:00
2016-03-01 00:16:31 +00:00
try
2016-02-24 02:13:52 +00:00
{
AppleDisk appleDisk = new AppleDisk (file, (int) file.length () / 4096, 8);
2016-03-01 00:16:31 +00:00
if (debug)
System.out.println ("created");
2016-02-24 02:13:52 +00:00
return new DataDisk (appleDisk);
}
2016-03-01 00:16:31 +00:00
catch (FileFormatException e)
{
if (debug)
System.out.println ("Creating AppleDisk failed");
return null;
}
2015-06-01 09:35:51 +00:00
}
2016-11-28 00:45:17 +00:00
if (suffix.equals ("v2d"))
{
2016-11-29 21:27:44 +00:00
V2dDisk v2dDisk = new V2dDisk (file);
2016-11-28 06:26:26 +00:00
AppleDisk appleDisk16 = new AppleDisk (v2dDisk);
disk = checkDos (appleDisk16);
return disk;
2016-11-28 00:45:17 +00:00
}
2016-11-29 21:27:44 +00:00
if (suffix.equals ("nib"))
{
NibDisk nibDisk = new NibDisk (file);
AppleDisk appleDisk16 = new AppleDisk (nibDisk);
disk = checkDos (appleDisk16);
return null;
}
2015-06-01 09:35:51 +00:00
long length = file.length ();
2016-11-28 00:45:17 +00:00
if (length == 116480) // 13 sector disk
{
if (!suffix.equals ("d13"))
System.out.printf ("%s should have a d13 suffix%n", file.getName ());
AppleDisk appleDisk = new AppleDisk (file, 35, 13);
disk = checkDos (appleDisk);
return disk == null ? new DataDisk (appleDisk) : disk;
}
if (length != 143360)
2015-06-01 09:35:51 +00:00
{
2016-07-30 06:12:01 +00:00
System.out.printf ("%s: invalid file length : %,d%n", file.getName (),
2016-08-08 04:53:29 +00:00
file.length ());
2015-06-01 09:35:51 +00:00
return null;
}
2016-11-28 00:45:17 +00:00
AppleDisk appleDisk16 = new AppleDisk (file, 35, 16);
AppleDisk appleDisk8 = new AppleDisk (file, 35, 8);
2015-06-01 09:35:51 +00:00
if (true)
{
2016-11-28 00:45:17 +00:00
long checksum = appleDisk16.getBootChecksum ();
2015-06-01 09:35:51 +00:00
if (checksum == 3176296590L || checksum == 108825457L || checksum == 1439356606L
2016-07-30 06:12:01 +00:00
|| checksum == 1550012074L || checksum == 1614602459L || checksum == 940889336L
|| checksum == 990032697 || checksum == 2936955085L || checksum == 1348415927L
|| checksum == 3340889101L || checksum == 18315788L || checksum == 993895235L)
2015-06-01 09:35:51 +00:00
{
2016-11-28 00:45:17 +00:00
disk = checkDos (appleDisk16);
disk2 = checkProdos (appleDisk8);
2015-06-01 09:35:51 +00:00
if (disk2 != null && disk != null)
disk = new DualDosDisk (disk, disk2);
}
else if (checksum == 1737448647L || checksum == 170399908L)
{
2016-11-28 00:45:17 +00:00
disk = checkProdos (appleDisk8);
disk2 = checkDos (appleDisk16);
2015-06-01 09:35:51 +00:00
if (disk2 != null && disk != null)
disk = new DualDosDisk (disk, disk2);
}
2016-07-30 06:12:01 +00:00
else if (checksum == 2803644711L || checksum == 3317783349L
|| checksum == 1728863694L || checksum == 198094178L)
2016-11-28 00:45:17 +00:00
{
// disk = checkPascalDisk (file);
disk = checkPascalDisk (appleDisk8);
}
2015-06-01 09:35:51 +00:00
else if (checksum == 3028642627L || checksum == 2070151659L)
2016-11-28 00:45:17 +00:00
disk = checkInfocomDisk (appleDisk16);
2015-06-01 09:35:51 +00:00
2016-02-24 12:32:36 +00:00
// else if (checksum == 1212926910L || checksum == 1365043894L
// || checksum == 2128073918L)
// disk = checkCPMDisk (file);
2015-06-01 09:35:51 +00:00
2016-02-24 09:48:09 +00:00
// System.out.println (checksum);
2015-06-01 09:35:51 +00:00
if (disk != null)
{
if (compressed)
disk.setOriginalPath (p);
return disk;
}
// empty boot sector
if (checksum != 227968344L && false)
System.out.println ("Unknown checksum : " + checksum + " : " + path);
}
2016-11-28 00:45:17 +00:00
if (suffix.equals ("dsk") || suffix.equals ("do"))
2015-06-01 09:35:51 +00:00
{
2016-11-28 00:45:17 +00:00
disk = checkDos (appleDisk16);
2015-06-01 09:35:51 +00:00
if (disk == null)
2016-11-28 00:45:17 +00:00
disk = checkProdos (appleDisk8);
else
2015-06-01 09:35:51 +00:00
{
if (debug)
System.out.println ("Checking DualDos disk");
2016-11-28 00:45:17 +00:00
disk2 = checkProdos (appleDisk8);
2015-06-01 09:35:51 +00:00
if (disk2 != null)
disk = new DualDosDisk (disk, disk2);
}
}
else if (suffix.equals ("po"))
{
2016-11-28 00:45:17 +00:00
disk = checkProdos (appleDisk8);
2015-06-01 09:35:51 +00:00
if (disk == null)
2016-11-28 00:45:17 +00:00
disk = checkDos (appleDisk16);
2015-06-01 09:35:51 +00:00
}
if (disk == null)
2016-11-28 00:45:17 +00:00
disk = checkPascalDisk (appleDisk8);
2015-06-01 09:35:51 +00:00
2016-02-24 12:32:36 +00:00
if (disk == null)
2016-11-28 00:45:17 +00:00
disk = checkCPMDisk (appleDisk16);
2016-02-24 12:32:36 +00:00
2015-06-01 09:35:51 +00:00
if (disk == null)
{
2016-11-28 00:45:17 +00:00
disk2 = checkInfocomDisk (appleDisk16);
2015-06-01 09:35:51 +00:00
if (disk2 != null)
disk = disk2;
}
if (disk == null)
2016-11-28 00:45:17 +00:00
disk = new DataDisk (appleDisk16);
2015-06-01 09:35:51 +00:00
if (debug)
2016-08-08 04:53:29 +00:00
System.out.println (
"Factory creating disk : " + disk.getDisk ().getFile ().getAbsolutePath ());
2015-06-01 09:35:51 +00:00
if (disk != null && compressed)
disk.setOriginalPath (p);
return disk;
}
2016-11-28 00:45:17 +00:00
private static DosDisk checkDos (AppleDisk disk)
2015-06-01 09:35:51 +00:00
{
if (debug)
System.out.println ("Checking DOS disk");
2016-11-28 00:45:17 +00:00
2015-06-01 09:35:51 +00:00
try
{
if (DosDisk.isCorrectFormat (disk))
return new DosDisk (disk);
}
catch (Exception e)
{
}
if (debug)
System.out.println ("Not a DOS disk");
return null;
}
2016-11-28 00:45:17 +00:00
private static ProdosDisk checkProdos (AppleDisk disk)
2015-06-01 09:35:51 +00:00
{
if (debug)
System.out.println ("Checking Prodos disk");
2016-02-28 05:41:10 +00:00
2015-06-01 09:35:51 +00:00
try
{
if (ProdosDisk.isCorrectFormat (disk))
return new ProdosDisk (disk);
}
catch (Exception e)
{
}
if (debug)
System.out.println ("Not a Prodos disk");
return null;
}
private static ProdosDisk checkHardDisk (File file)
{
if (debug)
{
System.out.println ("\nChecking Prodos hard disk");
System.out.printf ("Total blocks : %f%n", (float) file.length () / 512);
System.out.printf ("Total tracks : %f%n", (float) file.length () / 4096);
System.out.printf ("File length : %d%n", file.length ());
System.out.println ();
}
// assumes a sector is 512 bytes
if ((file.length () % 512) != 0)
{
if (debug)
2016-03-01 00:16:31 +00:00
System.out.printf ("file length not divisible by 512 : %,d%n%n", file.length ());
return null;
2015-06-01 09:35:51 +00:00
}
try
{
// truncate the file if necessary
2015-06-01 09:35:51 +00:00
AppleDisk disk = new AppleDisk (file, (int) file.length () / 4096, 8);
if (ProdosDisk.isCorrectFormat (disk))
{
if (debug)
{
System.out.println ("Yay, it's a prodos hard disk");
System.out.println (disk);
}
return new ProdosDisk (disk);
}
}
catch (Exception e)
{
2016-07-30 06:12:01 +00:00
System.out.println (e);
2015-06-01 09:35:51 +00:00
}
if (debug)
2016-02-24 02:13:52 +00:00
System.out.println ("Not a Prodos hard disk\n");
2015-06-01 09:35:51 +00:00
return null;
}
/*
offset | size | description
------ | ---- | -----------
+$000 | Long | The integer constant '2IMG'. This integer should be little-endian, so on the Apple IIgs, this is equivalent to the four characters 'GMI2'; in ORCA/C 2.1, you can use the integer constant '2IMG'.
+$004 | Long | A four-character tag identifying the application that created the file.
+$008 | Word | The length of this header, in bytes. Should be 52.
+$00A | Word | The version number of the image file format. Should be 1.
+$00C | Long | The image format. See table below.
+$010 | Long | Flags. See table below.
+$014 | Long | The number of 512-byte blocks in the disk image. This value should be zero unless the image format is 1 (ProDOS order).
+$018 | Long | Offset to the first byte of the first block of the disk in the image file, from the beginning of the file. The disk data must come before the comment and creator-specific chunks.
+$01C | Long | Length of the disk data in bytes. This should be the number of blocks * 512.
+$020 | Long | Offset to the first byte of the image comment. Can be zero if there's no comment. The comment must come after the data chunk, but before the creator-specific chunk. The comment, if it exists, should be raw text; no length byte or C-style null terminator byte is required (that's what the next field is for).
+$024 | Long | Length of the comment chunk. Zero if there's no comment.
+$028 | Long | Offset to the first byte of the creator-specific data chunk, or zero if there is none.
+$02C | Long | Length of the creator-specific chunk; zero if there is no creator-specific data.
+$030 | 16 bytes | Reserved space; this pads the header to 64 bytes. These values must all be zero.
*/
2015-06-01 09:35:51 +00:00
private static FormattedDisk check2mgDisk (File file)
{
if (debug)
System.out.println ("Checking Prodos 2mg disk");
try
{
AppleDisk disk = new AppleDisk (file, 0, 0);
if (ProdosDisk.isCorrectFormat (disk))
return new ProdosDisk (disk);
}
catch (Exception e)
{
}
if (debug)
System.out.println ("Not a Prodos 2mg disk");
2016-02-24 02:13:52 +00:00
2015-06-01 09:35:51 +00:00
return null;
}
2016-11-28 00:45:17 +00:00
private static FormattedDisk checkPascalDisk (AppleDisk disk)
2015-06-01 09:35:51 +00:00
{
if (debug)
System.out.println ("Checking Pascal disk");
2016-08-08 04:53:29 +00:00
2016-11-28 00:45:17 +00:00
File file = disk.getFile ();
2016-08-08 04:53:29 +00:00
2015-06-01 09:35:51 +00:00
if (!PascalDisk.isCorrectFormat (disk, debug))
return null;
2016-08-08 04:53:29 +00:00
2015-06-01 09:35:51 +00:00
if (debug)
System.out.println ("Pascal disk OK - Checking Wizardry disk");
2016-08-08 04:53:29 +00:00
2015-06-01 09:35:51 +00:00
if (WizardryScenarioDisk.isWizardryFormat (disk, debug))
return new WizardryScenarioDisk (disk);
2016-08-08 04:53:29 +00:00
2015-06-01 09:35:51 +00:00
if (debug)
2016-08-08 04:53:29 +00:00
System.out.println ("Not a Wizardry 1-3 disk");
2016-08-14 08:41:19 +00:00
// check for compressed disk
if (file.getName ().endsWith (".tmp"))
return new PascalDisk (disk); // complicated joining up compressed disks
2016-08-08 04:53:29 +00:00
2016-08-14 08:41:19 +00:00
if (Wizardry4BootDisk.isWizardryIVorV (disk, debug))
{
String fileName = file.getAbsolutePath ().toLowerCase ();
int pos = file.getAbsolutePath ().indexOf ('.');
char c = fileName.charAt (pos - 1);
String suffix = fileName.substring (pos + 1);
int requiredDisks = c == '1' ? 6 : c == 'a' ? 10 : 0;
2016-08-09 04:15:44 +00:00
2016-08-14 08:41:19 +00:00
if (requiredDisks > 0)
2016-08-08 04:53:29 +00:00
{
2016-08-14 08:41:19 +00:00
// collect extra data disks
AppleDisk[] disks = new AppleDisk[requiredDisks];
disks[0] = new AppleDisk (file, 256, 8); // will become a PascalDisk
disks[0].setInterleave (1);
disks[1] = new AppleDisk (file, 256, 8); // will remain a DataDisk
disks[1].setInterleave (1);
if (pos > 0 && requiredDisks > 0)
2016-08-08 04:53:29 +00:00
{
2016-08-14 08:41:19 +00:00
if (collectDataDisks (file.getAbsolutePath (), pos, disks))
return new Wizardry4BootDisk (disks);
2016-08-08 04:53:29 +00:00
}
}
}
if (debug)
System.out.println ("Not a Wizardry IV disk");
PascalDisk pascalDisk = new PascalDisk (disk);
return pascalDisk;
2015-06-01 09:35:51 +00:00
}
2016-08-14 08:41:19 +00:00
private static boolean collectDataDisks (String fileName, int dotPos, AppleDisk[] disks)
{
char c = fileName.charAt (dotPos - 1);
String suffix = fileName.substring (dotPos + 1);
for (int i = 2; i < disks.length; i++)
{
String old = new String (c + "." + suffix);
String rep = new String ((char) (c + i - 1) + "." + suffix);
2016-12-07 10:42:01 +00:00
2016-08-14 08:41:19 +00:00
File f = new File (fileName.replace (old, rep));
if (!f.exists () || !f.isFile ())
return false;
AppleDisk dataDisk = new AppleDisk (f, 35, 8);
dataDisk.setInterleave (1);
disks[i] = dataDisk;
}
return true;
}
2016-11-28 00:45:17 +00:00
private static InfocomDisk checkInfocomDisk (AppleDisk disk)
2015-06-01 09:35:51 +00:00
{
if (debug)
System.out.println ("Checking Infocom disk");
2016-12-07 10:42:01 +00:00
2015-06-01 09:35:51 +00:00
if (InfocomDisk.isCorrectFormat (disk))
return new InfocomDisk (disk);
2016-12-07 10:42:01 +00:00
2015-06-01 09:35:51 +00:00
if (debug)
System.out.println ("Not an InfocomDisk disk");
2016-12-07 10:42:01 +00:00
2015-06-01 09:35:51 +00:00
return null;
}
2016-11-28 00:45:17 +00:00
private static CPMDisk checkCPMDisk (AppleDisk disk)
2015-06-01 09:35:51 +00:00
{
if (debug)
System.out.println ("Checking CPM disk");
2016-12-07 10:42:01 +00:00
2015-06-01 09:35:51 +00:00
if (CPMDisk.isCorrectFormat (disk))
return new CPMDisk (disk);
2016-12-07 10:42:01 +00:00
2015-06-01 09:35:51 +00:00
if (debug)
System.out.println ("Not a CPM disk");
2016-12-07 10:42:01 +00:00
2015-06-01 09:35:51 +00:00
return null;
}
}