From 2b51a7469fa7726a4562ecc823121021e78735a5 Mon Sep 17 00:00:00 2001 From: Robert Greene Date: Mon, 22 Dec 2003 04:41:50 +0000 Subject: [PATCH] Began adding CP/M support. --- TODO | 1 + .../applecommander/storage/Disk.java | 39 +++ .../storage/cpm/CpmFileEntry.java | 212 ++++++++++++++ .../storage/cpm/CpmFormatDisk.java | 261 ++++++++++++++++++ 4 files changed, 513 insertions(+) create mode 100644 src/com/webcodepro/applecommander/storage/cpm/CpmFileEntry.java create mode 100644 src/com/webcodepro/applecommander/storage/cpm/CpmFormatDisk.java diff --git a/TODO b/TODO index c0c3129..e167d01 100644 --- a/TODO +++ b/TODO @@ -14,6 +14,7 @@ This is the internal list of items that need to be done. - Export - Compile * Added support for Finder Icons File ($CA or "ICN"). +o Adding CP/M support. --- FUTURE 1.3.x --- o Compile of BASIC programs diff --git a/src/com/webcodepro/applecommander/storage/Disk.java b/src/com/webcodepro/applecommander/storage/Disk.java index bfbf1b7..f3aee26 100644 --- a/src/com/webcodepro/applecommander/storage/Disk.java +++ b/src/com/webcodepro/applecommander/storage/Disk.java @@ -19,6 +19,8 @@ */ package com.webcodepro.applecommander.storage; +import com.webcodepro.applecommander.storage.cpm.CpmFileEntry; +import com.webcodepro.applecommander.storage.cpm.CpmFormatDisk; import com.webcodepro.applecommander.util.AppleUtil; import java.io.ByteArrayOutputStream; @@ -195,6 +197,9 @@ public class Disk { } else if (isRdosFormat()) { return new FormattedDisk[] { new RdosFormatDisk(filename, diskImage) }; + } else if (isCpmFormat()) { + return new FormattedDisk[] + { new CpmFormatDisk(filename, diskImage) }; } return null; } @@ -527,6 +532,40 @@ public class Disk { && directory[4] == 0 && directory[5] == 0; } + /** + * Test the disk format to see if this is a CP/M formatted disk. + * Check the first 256 bytes of the CP/M directory for validity. + */ + public boolean isCpmFormat() { + byte[] directory = readSector(3, 0); + int bytes[] = new int[256]; + for (int i=0; i 15 && bytes[offset] != 0xe5) return false; + // Validate filename has highbit off + for (int i=0; i<8; i++) { + if (bytes[offset+1+i] > 127) return false; + } + // Extent should be 0-31 (low = 0-31 and high = 0) + if (bytes[offset+0xc] > 31 || bytes[offset+0xe] > 0) return false; + // Number of used records cannot exceed 0x80 + if (bytes[offset+0xf] > 0x80) return false; + // Next entry + offset+= CpmFileEntry.ENTRY_LENGTH; + } + return true; + } + /** * Test the disk format to see if this is a RDOS formatted * disk. diff --git a/src/com/webcodepro/applecommander/storage/cpm/CpmFileEntry.java b/src/com/webcodepro/applecommander/storage/cpm/CpmFileEntry.java new file mode 100644 index 0000000..dcb3ef8 --- /dev/null +++ b/src/com/webcodepro/applecommander/storage/cpm/CpmFileEntry.java @@ -0,0 +1,212 @@ +package com.webcodepro.applecommander.storage.cpm; + +import com.webcodepro.applecommander.storage.DiskFullException; +import com.webcodepro.applecommander.storage.FileEntry; +import com.webcodepro.applecommander.storage.FileFilter; +import com.webcodepro.applecommander.storage.FormattedDisk; +import com.webcodepro.applecommander.util.AppleUtil; + +import java.util.List; + +/** + * @author Rob + */ +public class CpmFileEntry implements FileEntry { + /** + * The standard CP/M file entry length. + */ + public static final int ENTRY_LENGTH = 0x20; + /** + * Reference to the disk this FileEntry is attached to. + */ + private CpmFormatDisk disk; + /** + * The offset into the block that the FileEntry is at. + */ + private int offset; + + /** + * Construct a CP/M file entry. + */ + public CpmFileEntry(CpmFormatDisk disk, int offset) { + this.disk = disk; + this.offset = offset; + } + + /** + * Read the fileEntry bytes from the disk image. + */ + protected byte[] readFileEntry() { + byte[] data = new byte[2048]; + System.arraycopy(disk.readCpmBlock(0), 0, data, 0, 1024); + System.arraycopy(disk.readCpmBlock(1), 0, data, 1024, 1024); + byte[] entry = new byte[ENTRY_LENGTH]; + System.arraycopy(data, offset, entry, 0, ENTRY_LENGTH); + return entry; + } + + /** + * Answer with the name of the file. + * @see com.webcodepro.applecommander.storage.FileEntry#getFilename() + */ + public String getFilename() { + return AppleUtil.getString(readFileEntry(), 1, 8).trim(); + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#setFilename(java.lang.String) + */ + public void setFilename(String filename) { + // TODO Auto-generated method stub + + } + + /** + * Answer with the filetype. + * @see com.webcodepro.applecommander.storage.FileEntry#getFiletype() + */ + public String getFiletype() { + return AppleUtil.getString(readFileEntry(), 9, 3).trim(); + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#setFiletype(java.lang.String) + */ + public void setFiletype(String filetype) { + // TODO Auto-generated method stub + + } + + /** + * Indicates if this file is locked. + * @see com.webcodepro.applecommander.storage.FileEntry#isLocked() + */ + public boolean isLocked() { + return AppleUtil.isBitSet(readFileEntry()[0x9], 8); + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#setLocked(boolean) + */ + public void setLocked(boolean lock) { + // TODO Auto-generated method stub + + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#getSize() + */ + public int getSize() { + // TODO Auto-generated method stub + return 0; + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#isDirectory() + */ + public boolean isDirectory() { + // TODO Auto-generated method stub + return false; + } + + /** + * Indicates if this fileEntry is a deleted file. + * @see com.webcodepro.applecommander.storage.FileEntry#isDeleted() + */ + public boolean isDeleted() { + return 0xe5 == AppleUtil.getUnsignedByte(readFileEntry()[0]); + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#delete() + */ + public void delete() { + // TODO Auto-generated method stub + + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#getFileColumnData(int) + */ + public List getFileColumnData(int displayMode) { + // TODO Auto-generated method stub + return null; + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#getFileData() + */ + public byte[] getFileData() { + // TODO Auto-generated method stub + return null; + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#setFileData(byte[]) + */ + public void setFileData(byte[] data) throws DiskFullException { + // TODO Auto-generated method stub + + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#getSuggestedFilter() + */ + public FileFilter getSuggestedFilter() { + // TODO Auto-generated method stub + return null; + } + + /** + * Answer with the formatted disk. + * @see com.webcodepro.applecommander.storage.FileEntry#getFormattedDisk() + */ + public FormattedDisk getFormattedDisk() { + return disk; + } + + /** + * Answer with the maximum filename length. + * @see com.webcodepro.applecommander.storage.FileEntry#getMaximumFilenameLength() + */ + public int getMaximumFilenameLength() { + return 8; + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#needsAddress() + */ + public boolean needsAddress() { + // TODO Auto-generated method stub + return false; + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#setAddress(int) + */ + public void setAddress(int address) { + // TODO Auto-generated method stub + + } + + /** + * @see com.webcodepro.applecommander.storage.FileEntry#canCompile() + */ + public boolean canCompile() { + // TODO Auto-generated method stub + return false; + } + + /** + * Indicates if this is an empty file entry. + * An empty file entry contains all 0xE5. + */ + public boolean isEmpty() { + byte[] data = readFileEntry(); + for (int i=0; i + * @author Rob Greene + */ +public class CpmFormatDisk extends FormattedDisk { + /** + * Create a CP/M formatted disk. + */ + public CpmFormatDisk(String filename, byte[] diskImage) { + super(filename, diskImage); + } + + /** + * There apparantly is no corresponding CP/M disk name. + * @see com.webcodepro.applecommander.storage.FormattedDisk#getDiskName() + */ + public String getDiskName() { + return "CP/M Volume"; + } + + /** + * Identify the operating system format of this disk. + * @see com.webcodepro.applecommander.storage.FormattedDisk#getFormat() + */ + public String getFormat() { + return "CP/M"; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#getFreeSpace() + */ + public int getFreeSpace() { + // TODO Auto-generated method stub + return 0; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#getUsedSpace() + */ + public int getUsedSpace() { + // TODO Auto-generated method stub + return 0; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#getBitmapDimensions() + */ + public int[] getBitmapDimensions() { + // TODO Auto-generated method stub + return null; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#getBitmapLength() + */ + public int getBitmapLength() { + // TODO Auto-generated method stub + return 0; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#getDiskUsage() + */ + public DiskUsage getDiskUsage() { + // TODO Auto-generated method stub + return null; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#getBitmapLabels() + */ + public String[] getBitmapLabels() { + // TODO Auto-generated method stub + return null; + } + + /** + * Indicates if this disk format supports "deleted" files. + * @see com.webcodepro.applecommander.storage.FormattedDisk#supportsDeletedFiles() + */ + public boolean supportsDeletedFiles() { + return true; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#canReadFileData() + */ + public boolean canReadFileData() { + // TODO Auto-generated method stub + return false; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#canWriteFileData() + */ + public boolean canWriteFileData() { + // TODO Auto-generated method stub + return false; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#canHaveDirectories() + */ + public boolean canHaveDirectories() { + // TODO Auto-generated method stub + return false; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#canDeleteFile() + */ + public boolean canDeleteFile() { + // TODO Auto-generated method stub + return false; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#getFileData(com.webcodepro.applecommander.storage.FileEntry) + */ + public byte[] getFileData(FileEntry fileEntry) { + // TODO Auto-generated method stub + return null; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#format() + */ + public void format() { + // TODO Auto-generated method stub + + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#getLogicalDiskNumber() + */ + public int getLogicalDiskNumber() { + // TODO Auto-generated method stub + return 0; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#getSuggestedFilename(java.lang.String) + */ + public String getSuggestedFilename(String filename) { + // TODO Auto-generated method stub + return null; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#getSuggestedFiletype(java.lang.String) + */ + public String getSuggestedFiletype(String filename) { + // TODO Auto-generated method stub + return null; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#getFiletypes() + */ + public String[] getFiletypes() { + // TODO Auto-generated method stub + return null; + } + + /** + * @see com.webcodepro.applecommander.storage.FormattedDisk#needsAddress(java.lang.String) + */ + public boolean needsAddress(String filetype) { + // TODO Auto-generated method stub + return false; + } + + /** + * Answer with a list of file entries. + * @see com.webcodepro.applecommander.storage.DirectoryEntry#getFiles() + */ + public List getFiles() { + List files = new ArrayList(); + for (int i=0; i<64; i++) { + CpmFileEntry fileEntry = new CpmFileEntry(this, i*CpmFileEntry.ENTRY_LENGTH); + if (!fileEntry.isEmpty()) { + files.add(fileEntry); + } + } + return files; + } + + /** + * @see com.webcodepro.applecommander.storage.DirectoryEntry#createFile() + */ + public FileEntry createFile() throws DiskFullException { + // TODO Auto-generated method stub + return null; + } + + /** + * @see com.webcodepro.applecommander.storage.DirectoryEntry#canCreateDirectories() + */ + public boolean canCreateDirectories() { + // TODO Auto-generated method stub + return false; + } + + /** + * @see com.webcodepro.applecommander.storage.DirectoryEntry#canCreateFile() + */ + public boolean canCreateFile() { + // TODO Auto-generated method stub + return false; + } + + /** + * Read a CP/M block (1K in size). + *

+ * Apparantly, data block #0 starts at track 3, sector 0. + * There should be 64 directory entries. + * Each block is 1024 bytes (16 128-byte sectors). + * One block should be the entire directory... + */ + public byte[] readCpmBlock(int block) { + byte[] data = new byte[1024]; + int track = 3 + (block / 4); + int sector = block % 4; + for (int i=0; i<4; i++) { + System.arraycopy(readSector(track, sector+i), + 0, data, i*SECTOR_SIZE, SECTOR_SIZE); + } + return data; + } + +}