package com.webcodepro.applecommander.storage.os.cpm; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; 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.storage.StorageBundle; import com.webcodepro.applecommander.storage.filters.BinaryFileFilter; import com.webcodepro.applecommander.storage.filters.TextFileFilter; import com.webcodepro.applecommander.util.AppleUtil; import com.webcodepro.applecommander.util.TextBundle; /** * Support the CP/M file entry. Note that this may actually contain references * to multiple file entries via the extent counter. *
* @author Rob Greene
*/
public class CpmFileEntry implements FileEntry {
private TextBundle textBundle = StorageBundle.getInstance();
/**
* The standard CP/M file entry length.
*/
public static final int ENTRY_LENGTH = 0x20;
/**
* The maximum number of extents per file entry record.
*/
public static final int MAX_EXTENTS_PER_ENTRY = 0x80;
/**
* The number of bytes used if all records in an extent are filled.
* (MAX_EXTENTS_PER_ENTRY * CPM_SECTOR_SIZE)
*/
public static final int ALL_RECORDS_FILLED_SIZE = 16384;
/**
* The user number (UU) field is to distinguish multiple files with the
* same filename. This appears to be primarily with deleted files?
*/
public static final int USER_NUMBER_OFFSET = 0;
/**
* Offset to beginning of the filename.
*/
public static final int FILENAME_OFFSET = 1;
/**
* Filename length (excluding extension).
*/
public static final int FILENAME_LENGTH = 8;
/**
* Offset to beginning of the filetype.
*/
public static final int FILETYPE_OFFSET = 9;
/**
* Filetype length.
*/
public static final int FILETYPE_LENGTH = 3;
/**
* Offset to the filetype "T1" entry.
* Indicates read-only.
*/
public static final int FILETYPE_T1_OFFSET = FILETYPE_OFFSET;
/**
* Offset to the filetype "T2" entry.
* Indicates system or hidden file.
*/
public static final int FILETYPE_T2_OFFSET = FILETYPE_OFFSET+1;
/**
* Offset to the filetype "T3" entry.
* Backup bit (CP/M 3.1 and later).
*/
public static final int FILETYPE_T3_OFFSET = FILETYPE_OFFSET+2;
/**
* Offset to the extent counter (EX) field.
*/
public static final int EXTENT_COUNTER_OFFSET = 0xc;
/**
* Offset to the record count (RC) field.
*/
public static final int RECORD_COUNT_OFFSET = 0xf;
/**
* Beginning of block allocations.
*/
public static final int ALLOCATION_OFFSET = 0x10;
/**
* A short collection of known text-type files.
*/
public static final String[] TEXT_FILETYPES = {
"TXT", "ASM", "MAC", "DOC", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
"PRN", "PAS", "ME", "INC", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
"HLP" //$NON-NLS-1$
};
/**
* Reference to the disk this FileEntry is attached to.
*/
private CpmFormatDisk disk;
/**
* The offset(s) into the block that the FileEntry is at.
*/
private List offsets = new ArrayList();
/**
* Construct a CP/M file entry.
*/
public CpmFileEntry(CpmFormatDisk disk, int offset) {
this.disk = disk;
addOffset(offset);
}
/**
* Add another directory offset to this file entry.
*/
public void addOffset(int offset) {
offsets.add(new Integer(offset));
}
/**
* Read the fileEntry bytes from the disk image.
*/
protected byte[] readFileEntry(int number) {
byte[] data = new byte[2 * CpmFormatDisk.CPM_BLOCKSIZE];
System.arraycopy(disk.readCpmBlock(0), 0, data,
0, CpmFormatDisk.CPM_BLOCKSIZE);
System.arraycopy(disk.readCpmBlock(1), 0, data,
CpmFormatDisk.CPM_BLOCKSIZE, CpmFormatDisk.CPM_BLOCKSIZE);
byte[] entry = new byte[ENTRY_LENGTH];
int offset = ((Integer)offsets.get(number)).intValue();
System.arraycopy(data, offset, entry, 0, ENTRY_LENGTH);
return entry;
}
/**
* Write the fileEntry bytes back to the disk image.
*/
protected void writeFileEntry(int number, byte[] data) {
byte[] block = new byte[CpmFormatDisk.CPM_BLOCKSIZE];
System.arraycopy(data, 0, block,
0, CpmFormatDisk.CPM_BLOCKSIZE);
disk.writeCpmBlock(0, block);
System.arraycopy(data, 0, block,
CpmFormatDisk.CPM_BLOCKSIZE, CpmFormatDisk.CPM_BLOCKSIZE);
disk.writeCpmBlock(1, block);
}
/**
* Answer with the name of the file.
* @see com.webcodepro.applecommander.storage.FileEntry#getFilename()
*/
public String getFilename() {
return AppleUtil.getString(readFileEntry(0),
FILENAME_OFFSET, FILENAME_LENGTH).trim();
}
/**
* Set the filename. Note that this assumes the file extension
* is completely separate and does not validate characters that
* are being set!
* @see com.webcodepro.applecommander.storage.FileEntry#setFilename(java.lang.String)
*/
public void setFilename(String filename) {
for (int i=0; i