mirror of
https://github.com/AppleCommander/AppleCommander.git
synced 2025-01-09 18:33:28 +00:00
Merged in John B. Matthews' changes for AppleCommander 1.3.3.9.
This commit is contained in:
parent
18cb7e533e
commit
8b23db3d7d
src/com/webcodepro/applecommander
@ -154,8 +154,12 @@ public class Disk {
|
||||
new ByteArrayOutputStream(diskSize);
|
||||
StreamUtil.copy(input, diskImageByteArray);
|
||||
byte[] diskImage = diskImageByteArray.toByteArray();
|
||||
if (diskImage.length >= APPLE_800KB_2IMG_DISK
|
||||
&& diskImage.length <= APPLE_800KB_2IMG_DISK + 10) {
|
||||
int offset = UniversalDiskImageLayout.OFFSET;
|
||||
if (diskImage.length == APPLE_800KB_DISK + offset ||
|
||||
diskImage.length == APPLE_5MB_HARDDISK + offset ||
|
||||
diskImage.length == APPLE_10MB_HARDDISK + offset ||
|
||||
diskImage.length == APPLE_20MB_HARDDISK + offset ||
|
||||
diskImage.length == APPLE_32MB_HARDDISK + offset) {
|
||||
diskImageManager = new UniversalDiskImageLayout(diskImage);
|
||||
} else {
|
||||
diskImageManager = new ByteArrayImageLayout(diskImage);
|
||||
|
@ -206,8 +206,8 @@ public class AppleWorksDataBaseFileFilter implements FileFilter {
|
||||
offset+= (reportCount * REPORT_LENGTH);
|
||||
// process data:
|
||||
for (int i=0; i<recordCount+1; i++) {
|
||||
int length = AppleUtil.getWordValue(fileData, offset)
|
||||
+ 2; // does not include this word!
|
||||
// length = record length + 2 bytes for the length word itself.
|
||||
int length = AppleUtil.getWordValue(fileData, offset) + 2;
|
||||
int data = offset + 2;
|
||||
int column = 0;
|
||||
while (AppleUtil.getUnsignedByte(fileData[data]) != DATA_CONTROL_END) {
|
||||
@ -236,6 +236,7 @@ public class AppleWorksDataBaseFileFilter implements FileFilter {
|
||||
printWriter.print("\",\""); //$NON-NLS-1$
|
||||
repeats--;
|
||||
}
|
||||
data++; // move on to the next column
|
||||
}
|
||||
column++;
|
||||
}
|
||||
|
@ -410,8 +410,7 @@ public class GraphicsFileFilter implements FileFilter {
|
||||
* Construct a series of icons based on the QuickDraw II Icon file format.
|
||||
* In ProDOS, this is the ICN ($Ca) file format.
|
||||
* <p>
|
||||
* See <a href='http://www.gno.org/pub/apple2/doc/apple/filetypes/ftn.ca.xxxx'>this
|
||||
* page</a> for details.
|
||||
* @see <a href="http://web.pdx.edu/~heiss/technotes/ftyp/ft.about.html">File Types</a>
|
||||
*/
|
||||
public AppleImage[] buildQuickDraw2Icons(FileEntry fileEntry) {
|
||||
List icons = new ArrayList();
|
||||
|
@ -77,6 +77,7 @@ public class IntegerBasicFileFilter implements FileFilter {
|
||||
/**
|
||||
* Process the given FileEntry and return a text image of the Integer BASIC file.
|
||||
* @see com.webcodepro.applecommander.storage.FileFilter#filter(FileEntry)
|
||||
* author John B. Matthews
|
||||
*/
|
||||
public byte[] filter(FileEntry fileEntry) {
|
||||
byte[] fileData = fileEntry.getFileData();
|
||||
|
@ -2,6 +2,8 @@
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2002 by Robert Greene
|
||||
* robgreene at users.sourceforge.net
|
||||
* Copyright (C) 2004 by John B. Matthews
|
||||
* jmatthews at wight dot edu
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@ -19,9 +21,11 @@
|
||||
*/
|
||||
package com.webcodepro.applecommander.storage.os.pascal;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@ -48,7 +52,9 @@ public class PascalFileEntry implements FileEntry {
|
||||
private TextBundle textBundle = StorageBundle.getInstance();
|
||||
private byte[] fileEntry;
|
||||
private PascalFormatDisk disk;
|
||||
|
||||
private int index = 0;
|
||||
private boolean deleted = false;
|
||||
|
||||
/**
|
||||
* Constructor for PascalFileEntry.
|
||||
*/
|
||||
@ -59,19 +65,33 @@ public class PascalFileEntry implements FileEntry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block number of the files 1st block.
|
||||
* Get the block number of the file's 1st block.
|
||||
*/
|
||||
public int getFirstBlock() {
|
||||
return AppleUtil.getWordValue(fileEntry, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the block number of the file's 1st block.
|
||||
*/
|
||||
public void setFirstBlock(int first) {
|
||||
AppleUtil.setWordValue(fileEntry, 0, first);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block number of the files last block +1.
|
||||
* Get the block number of the file's last block + 1.
|
||||
*/
|
||||
public int getLastBlock() {
|
||||
return AppleUtil.getWordValue(fileEntry, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the block number of the file's last block + 1.
|
||||
*/
|
||||
public void setLastBlock(int last) {
|
||||
AppleUtil.setWordValue(fileEntry, 2, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of this file.
|
||||
*/
|
||||
@ -83,7 +103,7 @@ public class PascalFileEntry implements FileEntry {
|
||||
* Set the name of this file.
|
||||
*/
|
||||
public void setFilename(String filename) {
|
||||
// FIXME: Need to implement!
|
||||
AppleUtil.setPascalString(fileEntry, 6, filename.toUpperCase(), 15);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,23 +127,40 @@ public class PascalFileEntry implements FileEntry {
|
||||
|
||||
/**
|
||||
* Set the filetype.
|
||||
* @author John B. Matthews
|
||||
*/
|
||||
public void setFiletype(String filetype) {
|
||||
// FIXME: Implement!
|
||||
if ("bad".equalsIgnoreCase(filetype)) {
|
||||
AppleUtil.setWordValue(fileEntry, 4, 1);
|
||||
} else if ("code".equalsIgnoreCase(filetype)) {
|
||||
AppleUtil.setWordValue(fileEntry, 4, 2);
|
||||
} else if ("text".equalsIgnoreCase(filetype)) {
|
||||
AppleUtil.setWordValue(fileEntry, 4, 3);
|
||||
} else if ("info".equalsIgnoreCase(filetype)) {
|
||||
AppleUtil.setWordValue(fileEntry, 4, 4);
|
||||
} else if ("data".equalsIgnoreCase(filetype)) {
|
||||
AppleUtil.setWordValue(fileEntry, 4, 5);
|
||||
} else if ("graf".equalsIgnoreCase(filetype)) {
|
||||
AppleUtil.setWordValue(fileEntry, 4, 6);
|
||||
} else if ("foto".equalsIgnoreCase(filetype)) {
|
||||
AppleUtil.setWordValue(fileEntry, 4, 7);
|
||||
} else {
|
||||
AppleUtil.setWordValue(fileEntry, 4, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify if this file is locked - not applicable in Pascal?
|
||||
* Identify if this file is locked
|
||||
*/
|
||||
public boolean isLocked() {
|
||||
return false;
|
||||
return false; // Not applicable to UCSD file system
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the lock indicator.
|
||||
*/
|
||||
public void setLocked(boolean lock) {
|
||||
// FIXME: Implement!
|
||||
// Not applicable to UCSD file system
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,6 +170,13 @@ public class PascalFileEntry implements FileEntry {
|
||||
return AppleUtil.getWordValue(fileEntry, 22);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of bytes used in files last block.
|
||||
*/
|
||||
public void setBytesUsedInLastBlock(int value) {
|
||||
AppleUtil.setWordValue(fileEntry, 22, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the size of this file (in bytes).
|
||||
*/
|
||||
@ -164,18 +208,38 @@ public class PascalFileEntry implements FileEntry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Pascal file entries are removed upon deletion.
|
||||
* Thus, a file entry cannot be marked as deleted.
|
||||
* Pascal file entries are removed upon deletion,
|
||||
* so a file entry need not be marked as deleted.
|
||||
* But the GUI still has a copy of the file list in
|
||||
* memory, so we mark it deleted in delete().
|
||||
*/
|
||||
public boolean isDeleted() {
|
||||
return false;
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the file.
|
||||
*/
|
||||
public void delete() {
|
||||
// FIXME: Need to implement!
|
||||
int index = 0;
|
||||
String dname = this.getFilename();
|
||||
List dir = disk.getDirectory();
|
||||
int count = dir.size();
|
||||
// find the index of the matching entry
|
||||
for (int i = 1; i < count; i++) {
|
||||
String fname = ((PascalFileEntry) dir.get(i)).getFilename();
|
||||
if (dname.equals(fname)) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
if (index != 0) {
|
||||
dir.remove(index);
|
||||
PascalFileEntry volEntry = (PascalFileEntry) dir.get(0);
|
||||
volEntry.setFileCount(count - 2); // inlcudes the volume entry
|
||||
dir.set(0, volEntry);
|
||||
disk.putDirectory(dir);
|
||||
deleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -185,6 +249,13 @@ public class PascalFileEntry implements FileEntry {
|
||||
return AppleUtil.getPascalDate(fileEntry, 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file modification date.
|
||||
*/
|
||||
public void setModificationDate(Date date) {
|
||||
AppleUtil.setPascalDate(fileEntry, 24, date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the standard file column header information.
|
||||
* This default implementation is intended only for standard mode.
|
||||
@ -236,11 +307,130 @@ public class PascalFileEntry implements FileEntry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file data. This, essentially, is saving data to disk using this
|
||||
* file entry.
|
||||
* Filter text: change CR/LF to CR; compress leading SP.
|
||||
* author John B. Matthews
|
||||
*/
|
||||
private byte[] filterText(byte[] data) {
|
||||
final byte LF = 0x0a; final byte CR = 0x0d;
|
||||
final byte DLE = 0x10; final byte SP = 0x20;
|
||||
ByteArrayOutputStream buf = new ByteArrayOutputStream(data.length);
|
||||
int index = 0;
|
||||
while (index < data.length) {
|
||||
byte b = data[index];
|
||||
if (b == CR || b == LF) {
|
||||
buf.write(CR);
|
||||
index++;
|
||||
if (b == CR && index < data.length && data[index] == LF) index++;
|
||||
byte spaceCount = SP;
|
||||
while (index < data.length && data[index] == SP) {
|
||||
spaceCount++; index++;
|
||||
}
|
||||
if (spaceCount > SP) {
|
||||
buf.write(DLE);
|
||||
buf.write(spaceCount);
|
||||
}
|
||||
} else {
|
||||
buf.write(b);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return buf.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this temporary entry, inserted by PascalFormatDisk.createFile(),
|
||||
* and exit via DiskFullException.
|
||||
* @author John B. Matthews
|
||||
*/
|
||||
private void storageError(String s) throws DiskFullException {
|
||||
if (this.index > 0) {
|
||||
List dir = disk.getDirectory();
|
||||
int count = dir.size();
|
||||
dir.remove(this.index);
|
||||
PascalFileEntry volEntry = (PascalFileEntry) dir.get(0);
|
||||
volEntry.setFileCount(count - 2);
|
||||
dir.set(0, volEntry);
|
||||
disk.putDirectory(dir);
|
||||
throw new DiskFullException(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find index of last CR < 1023 bytes from offset.
|
||||
* @author John B. Matthews
|
||||
*/
|
||||
private int findEOL(byte[] data, int offset) throws DiskFullException {
|
||||
int i = offset + 1022;
|
||||
while (i > offset) {
|
||||
if (data[i] == 13) {
|
||||
return i;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
storageError("Lines must be < 1024 characters.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file data for this file entry. Because the directory entry may
|
||||
* have been changed, use this.index to determine which entry to update.
|
||||
* author John B. Matthews.
|
||||
* @see #setEntryIndex
|
||||
* @see PascalFormatDisk#createFile
|
||||
*/
|
||||
public void setFileData(byte[] data) throws DiskFullException {
|
||||
// FIXME: Implement!
|
||||
int first = getFirstBlock();
|
||||
int last = getLastBlock();
|
||||
if (fileEntry[4] == 3) { // text
|
||||
data = filterText(data);
|
||||
byte[] buf = new byte[1024];
|
||||
int offset = 0;
|
||||
int pages = 0;
|
||||
disk.writeBlock(first, buf); pages++;
|
||||
while (offset + 1023 < data.length) {
|
||||
if ((pages * 2) > (last - first - 2)) {
|
||||
storageError("Not enough room.");
|
||||
}
|
||||
int crPtr = findEOL(data, offset);
|
||||
System.arraycopy(data, offset, buf, 0, crPtr - offset + 1);
|
||||
disk.writeBlock(first + pages * 2, buf); pages++;
|
||||
Arrays.fill(buf, (byte) 0);
|
||||
offset = crPtr + 1;
|
||||
}
|
||||
if (offset < data.length) {
|
||||
System.arraycopy(data, offset, buf, 0, data.length - offset);
|
||||
disk.writeBlock(first + pages * 2, buf); pages++;
|
||||
}
|
||||
setLastBlock(first + pages * 2);
|
||||
setBytesUsedInLastBlock(512);
|
||||
} else { // data or code
|
||||
if (data.length > (last - first) * 512) {
|
||||
storageError("Not enough room.");
|
||||
}
|
||||
byte[] buf = new byte[512];
|
||||
int blocks = data.length / 512;
|
||||
int bytes = data.length % 512;
|
||||
for (int i = 0; i < blocks; i++) {
|
||||
System.arraycopy(data, i * 512, buf, 0, 512);
|
||||
disk.writeBlock(first + i, buf);
|
||||
}
|
||||
if (bytes > 0) {
|
||||
Arrays.fill(buf, (byte) 0);
|
||||
System.arraycopy(data, blocks * 512, buf, 0, bytes);
|
||||
disk.writeBlock(first + blocks, buf);
|
||||
setLastBlock(first + blocks + 1);
|
||||
setBytesUsedInLastBlock(bytes);
|
||||
} else {
|
||||
setLastBlock(first + blocks);
|
||||
setBytesUsedInLastBlock(512);
|
||||
}
|
||||
}
|
||||
// update this directory entry
|
||||
if (this.index > 0) {
|
||||
List dir = disk.getDirectory();
|
||||
dir.set(this.index, this);
|
||||
disk.putDirectory(dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,12 +439,12 @@ public class PascalFileEntry implements FileEntry {
|
||||
* of guessing the appropriate filter.
|
||||
*/
|
||||
public FileFilter getSuggestedFilter() {
|
||||
if ("textfile".equals(getFiletype())) { //$NON-NLS-1$
|
||||
if ("TEXT".equals(getFiletype())) { //$NON-NLS-1$
|
||||
if (getFilename().toLowerCase().endsWith(".text")) { //$NON-NLS-1$
|
||||
return new PascalTextFileFilter();
|
||||
}
|
||||
return new TextFileFilter();
|
||||
} else if ("datafile".equals(getFiletype()) && getSize() >= 8184 && getSize() <= 8192) { //$NON-NLS-1$
|
||||
} else if ("DATA".equals(getFiletype()) && getSize() >= 8184 && getSize() <= 8192) { //$NON-NLS-1$
|
||||
GraphicsFileFilter filter = new GraphicsFileFilter();
|
||||
filter.setMode(GraphicsFileFilter.MODE_HGR_COLOR);
|
||||
return filter;
|
||||
@ -271,6 +461,14 @@ public class PascalFileEntry implements FileEntry {
|
||||
return disk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the byte[] associated with this FileEntry.
|
||||
* This is need to manipuate the directory as a whole.
|
||||
*/
|
||||
public byte[] toBytes() {
|
||||
return fileEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this filetype requires an address component.
|
||||
* Note that the FormattedDisk also has this method - normally,
|
||||
@ -294,4 +492,23 @@ public class PascalFileEntry implements FileEntry {
|
||||
public boolean canCompile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember the index of a newly created file entry.
|
||||
* Required to update the entry after setFileData,
|
||||
* which may change any or all of the new entry's fields.
|
||||
* author John B. Matthews
|
||||
*/
|
||||
public void setEntryIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file count in a volume entry.
|
||||
* Use only on the volume entry: dir.get(0).
|
||||
* author John B. Matthews
|
||||
*/
|
||||
public void setFileCount(int count) {
|
||||
AppleUtil.setWordValue(fileEntry, 16, count);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2002 by Robert Greene
|
||||
* robgreene at users.sourceforge.net
|
||||
* Copyright (C) 2004 by John B. Matthews
|
||||
* jmatthews at wight dot edu
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@ -52,22 +54,22 @@ public class PascalFormatDisk extends FormattedDisk {
|
||||
public static final int PASCAL_BLOCKS_ON_140K_DISK = 280;
|
||||
|
||||
// filetypes used elsewhere in the code:
|
||||
private static final String TEXTFILE = "textfile"; //$NON-NLS-1$
|
||||
private static final String CODEFILE = "codefile"; //$NON-NLS-1$
|
||||
private static final String DATAFILE = "datafile"; //$NON-NLS-1$
|
||||
private static final String TEXTFILE = "TEXT"; //$NON-NLS-1$
|
||||
private static final String CODEFILE = "CODE"; //$NON-NLS-1$
|
||||
private static final String DATAFILE = "DATA"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* The know filetypes for a Pascal disk.
|
||||
* The known filetypes for a Pascal disk.
|
||||
*/
|
||||
private static final String[] filetypes = {
|
||||
"xdskfile", //$NON-NLS-1$
|
||||
"xdskfile", //$NON-NLS-1$
|
||||
CODEFILE,
|
||||
TEXTFILE,
|
||||
"infofile", //$NON-NLS-1$
|
||||
"INFO", //$NON-NLS-1$
|
||||
DATAFILE,
|
||||
"graffile", //$NON-NLS-1$
|
||||
"fotofile", //$NON-NLS-1$
|
||||
"securedir" }; //$NON-NLS-1$
|
||||
"GRAF", //$NON-NLS-1$
|
||||
"FOTO", //$NON-NLS-1$
|
||||
"securedir" }; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Use this inner interface for managing the disk usage data.
|
||||
@ -146,8 +148,8 @@ public class PascalFormatDisk extends FormattedDisk {
|
||||
byte[] directory = readDirectory();
|
||||
// process directory blocks:
|
||||
int entrySize = ENTRY_SIZE;
|
||||
int offset = entrySize;
|
||||
int count = AppleUtil.getWordValue(directory, 16);
|
||||
int offset = entrySize;
|
||||
for (int i=0; i<count; i++) {
|
||||
byte[] entry = new byte[entrySize];
|
||||
System.arraycopy(directory, offset, entry, 0, entry.length);
|
||||
@ -157,11 +159,89 @@ public class PascalFormatDisk extends FormattedDisk {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the entire directory.
|
||||
* @author John B. Matthews
|
||||
*/
|
||||
public List getDirectory() {
|
||||
List list = new ArrayList();
|
||||
byte[] directory = readDirectory();
|
||||
int count = AppleUtil.getWordValue(directory, 16);
|
||||
int offset = 0;
|
||||
for (int i = 0; i <= count; i++) {
|
||||
byte[] entry = new byte[ENTRY_SIZE];
|
||||
System.arraycopy(directory, offset, entry, 0, entry.length);
|
||||
list.add(new PascalFileEntry(entry, this));
|
||||
offset += ENTRY_SIZE;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the revised directory.
|
||||
* @author John B. Matthews
|
||||
*/
|
||||
public void putDirectory(List list) {
|
||||
byte[] directory = new byte[2048];
|
||||
int count = list.size();
|
||||
int offset = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
byte[] entry = ((PascalFileEntry) list.get(i)).toBytes();
|
||||
System.arraycopy(entry, 0, directory, offset, entry.length);
|
||||
offset += ENTRY_SIZE;
|
||||
}
|
||||
writeDirectory(directory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new FileEntry.
|
||||
* @author John B. Matthews
|
||||
*/
|
||||
public FileEntry createFile() throws DiskFullException {
|
||||
throw new DiskFullException(textBundle.get("FileCreationNotSupported")); //$NON-NLS-1$
|
||||
public FileEntry createFile() throws DiskFullException {
|
||||
// find index of largest free space
|
||||
int count = 0; int index = 0; int max = 0;
|
||||
int last = 0; int first = 0; int free = 0;
|
||||
List dir = getDirectory();
|
||||
count = dir.size();
|
||||
for (int i = 1; i < count; i++) {
|
||||
last = ((PascalFileEntry) dir.get(i - 1)).getLastBlock();
|
||||
first = ((PascalFileEntry) dir.get(i)).getFirstBlock();
|
||||
free = first - last;
|
||||
if (free > max) {
|
||||
max = free; index = i;
|
||||
}
|
||||
}
|
||||
// check after last entry, too
|
||||
last = ((PascalFileEntry) dir.get(count - 1)).getLastBlock();
|
||||
first = getBlocksOnDisk();
|
||||
free = first - last;
|
||||
if (free > max) {
|
||||
max = free; index = count;
|
||||
}
|
||||
if (free > 0 && count < 78) {
|
||||
// update file count in the volume entry
|
||||
PascalFileEntry volEntry = (PascalFileEntry) dir.get(0);
|
||||
volEntry.setFileCount(count);
|
||||
dir.set(0, volEntry);
|
||||
// add new entry to list
|
||||
dir.add(index, new PascalFileEntry(new byte[ENTRY_SIZE], this));
|
||||
PascalFileEntry entry = (PascalFileEntry) dir.get(index);
|
||||
// fill in plausible values; will rely index, first and last
|
||||
first = ((PascalFileEntry) dir.get(index - 1)).getLastBlock();
|
||||
entry.setFirstBlock(first);
|
||||
entry.setLastBlock(first + max);
|
||||
entry.setFiletype("data");
|
||||
entry.setFilename("x");
|
||||
entry.setBytesUsedInLastBlock(512);
|
||||
entry.setModificationDate(new Date());
|
||||
entry.setEntryIndex(index);
|
||||
dir.set(index, entry);
|
||||
// write it back to disk
|
||||
putDirectory(dir);
|
||||
return entry;
|
||||
} else {
|
||||
throw new DiskFullException("Disk full.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -180,7 +260,7 @@ public class PascalFormatDisk extends FormattedDisk {
|
||||
* to something specific about the disk.
|
||||
*/
|
||||
public boolean canCreateFile() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -264,6 +344,13 @@ public class PascalFormatDisk extends FormattedDisk {
|
||||
return AppleUtil.getWordValue(getVolumeEntry(), 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fisrt block.
|
||||
*/
|
||||
public int getFirstBlock() {
|
||||
return AppleUtil.getWordValue(getVolumeEntry(), 18);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last access date.
|
||||
*/
|
||||
@ -363,6 +450,8 @@ public class PascalFormatDisk extends FormattedDisk {
|
||||
textBundle.get("PascalFormatDisk.LastAccessDate"), getLastAccessDate())); //$NON-NLS-1$
|
||||
list.add(new DiskInformation(
|
||||
textBundle.get("PascalFormatDisk.MostRecentDateSetting"), getMostRecentDateSetting())); //$NON-NLS-1$
|
||||
list.add(new DiskInformation("First Block", getFirstBlock()));
|
||||
list.add(new DiskInformation("Volume Date", getLastAccessDate()));
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -429,14 +518,14 @@ public class PascalFormatDisk extends FormattedDisk {
|
||||
* Indicates if this disk image can write data to a file.
|
||||
*/
|
||||
public boolean canWriteFileData() {
|
||||
return false; // FIXME - not implemented
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this disk image can delete a file.
|
||||
*/
|
||||
public boolean canDeleteFile() {
|
||||
return false; // FIXME - not implemented
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -479,7 +568,7 @@ public class PascalFormatDisk extends FormattedDisk {
|
||||
// volume name should have been set in constructor!
|
||||
AppleUtil.setWordValue(directory, 14, PASCAL_BLOCKS_ON_140K_DISK);
|
||||
AppleUtil.setWordValue(directory, 16, 0); // no files
|
||||
AppleUtil.setPascalDate(directory, 18, new Date()); // last access time
|
||||
AppleUtil.setWordValue(directory, 18, 0); // first block
|
||||
AppleUtil.setPascalDate(directory, 20, new Date()); // most recent date setting
|
||||
writeDirectory(directory);
|
||||
}
|
||||
|
@ -47,21 +47,21 @@ public class UniversalDiskImageLayout extends ByteArrayImageLayout {
|
||||
* Construct a UniversalDiskImageLayout.
|
||||
*/
|
||||
public UniversalDiskImageLayout(int size) {
|
||||
super(size + 0x40);
|
||||
super(size + OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a portion of the disk image.
|
||||
*/
|
||||
public byte[] readBytes(int start, int length) {
|
||||
return super.readBytes(start + 0x40, length);
|
||||
return super.readBytes(start + OFFSET, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to the disk image.
|
||||
*/
|
||||
public void writeBytes(int start, byte[] bytes) {
|
||||
super.writeBytes(start + 0x40, bytes);
|
||||
super.writeBytes(start + OFFSET, bytes);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -100,7 +100,8 @@ CreateDirectoryMenuItem=Create Directory...
|
||||
CommandLineErrorMessage = Error: {0}
|
||||
CommandLineNoMatchMessage = {0}: No match.
|
||||
CommandLineStatus = {0} format; {1} bytes free; {2} bytes used.
|
||||
CommandLineHelp = AppleCommander command line options:\n-l <imagename> list directory of image.\n-e <filename> <imagename> export file from image to stdout.\n-g <filename> <imagename> get raw file from image to stdout.\n-p <destname> <type> <addr> <imagename> put stdin\n in destname on image, using file type and address.\n-d <filename> <imagename> delete file from image.\n-p140 <imagename> <volname> create a 140K ProDOS image.\n-p800 <imagename> <volname> create a 800K ProDOS image.
|
||||
CommandLineHelp = AppleCommander command line options [{0}]:\n-i <imagename> display information about image.\n-ls <imagename> list brief directory of image.\n-l <imagename> list directory of image.\n-ll <imagename> list detailed directory of image.\n-e <filename> <imagename> export file from image to stdout.\n-g <filename> <imagename> get raw file from image to stdout.\n-p <destname> <type> <addr> <imagename> put stdin\n in destname on image, using file type and address.\n-d <filename> <imagename> delete file from image.\n-dos140 <imagename> create a 140K DOS 3.3 image.\n-pro140 <imagename> <volname> create a 140K ProDOS image.\n-pro800 <imagename> <volname> create a 800K ProDOS image.\n-pas140 <imagename> <volname> create a 140K Pascal image.
|
||||
|
||||
|
||||
# UserPreferences
|
||||
UserPreferencesComment = AppleCommander user preferences
|
||||
@ -216,7 +217,7 @@ OpenButton=Open...
|
||||
CreateButton=Create...
|
||||
CompareButton=Compare...
|
||||
AboutButton=About
|
||||
Copyright=Copyright (c) 2002-2004
|
||||
Copyright=Copyright (c) 2002-2006
|
||||
PrintButton=Print
|
||||
|
||||
# DiskImageNamePane
|
||||
|
@ -23,6 +23,8 @@ import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.webcodepro.applecommander.util.Host;
|
||||
|
||||
/**
|
||||
* Provide a generalized and common mechanism to handle user preferences throughout
|
||||
* all AppleCommander user interfaces.
|
||||
@ -60,7 +62,8 @@ public class UserPreferences {
|
||||
*/
|
||||
private void load() {
|
||||
try {
|
||||
FileInputStream inputStream = new FileInputStream(FILENAME);
|
||||
FileInputStream inputStream =
|
||||
new FileInputStream(Host.getPrefDir() + FILENAME);
|
||||
properties.load(inputStream);
|
||||
inputStream.close();
|
||||
} catch (Exception ignored) {
|
||||
@ -72,7 +75,8 @@ public class UserPreferences {
|
||||
*/
|
||||
public void save() {
|
||||
try {
|
||||
FileOutputStream outputStream = new FileOutputStream(FILENAME);
|
||||
FileOutputStream outputStream =
|
||||
new FileOutputStream(Host.getPrefDir() + FILENAME);
|
||||
properties.store(outputStream, UiBundle.getInstance().
|
||||
get("UserPreferencesComment")); //$NON-NLS-1$
|
||||
outputStream.close();
|
||||
|
@ -2,7 +2,7 @@
|
||||
* ac - an AppleCommander command line utility
|
||||
* Copyright (C) 2002 by Robert Greene
|
||||
* robgreene at users.sourceforge.net
|
||||
* Copyright (C) 2003 by John B. Matthews
|
||||
* Copyright (C) 2003, 2004 by John B. Matthews
|
||||
* jmatthews at wight dot edu
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@ -21,7 +21,9 @@
|
||||
*/
|
||||
package com.webcodepro.applecommander.ui;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.webcodepro.applecommander.storage.DirectoryEntry;
|
||||
@ -30,8 +32,12 @@ 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.FormattedDisk.DiskInformation;
|
||||
import com.webcodepro.applecommander.storage.os.dos33.DosFormatDisk;
|
||||
import com.webcodepro.applecommander.storage.os.pascal.PascalFormatDisk;
|
||||
import com.webcodepro.applecommander.storage.os.prodos.ProdosFormatDisk;
|
||||
import com.webcodepro.applecommander.storage.physical.ByteArrayImageLayout;
|
||||
import com.webcodepro.applecommander.storage.physical.DosOrder;
|
||||
import com.webcodepro.applecommander.storage.physical.ImageOrder;
|
||||
import com.webcodepro.applecommander.storage.physical.ProdosOrder;
|
||||
import com.webcodepro.applecommander.util.TextBundle;
|
||||
@ -43,8 +49,12 @@ public class ac {
|
||||
try {
|
||||
if (args.length == 0) {
|
||||
help();
|
||||
} else if ("-ls".equalsIgnoreCase(args[0])) {
|
||||
showDirectory(args[1], FormattedDisk.FILE_DISPLAY_STANDARD);
|
||||
} else if ("-l".equalsIgnoreCase(args[0])) { //$NON-NLS-1$
|
||||
showDirectory(args[1]);
|
||||
showDirectory(args[1], FormattedDisk.FILE_DISPLAY_NATIVE);
|
||||
} else if ("-ll".equalsIgnoreCase(args[0])) {
|
||||
showDirectory(args[1], FormattedDisk.FILE_DISPLAY_DETAIL);
|
||||
} else if ("-e".equalsIgnoreCase(args[0])) { //$NON-NLS-1$
|
||||
getFile(args[1], args[2], true);
|
||||
} else if ("-g".equalsIgnoreCase(args[0])) { //$NON-NLS-1$
|
||||
@ -53,10 +63,16 @@ public class ac {
|
||||
putFile(args[1], args[2], args[3], args[4]);
|
||||
} else if ("-d".equalsIgnoreCase(args[0])) { //$NON-NLS-1$
|
||||
deleteFile(args[1], args[2]);
|
||||
} else if ("-p140".equalsIgnoreCase(args[0])) { //$NON-NLS-1$
|
||||
createPDisk(args[1], args[2], Disk.APPLE_140KB_DISK);
|
||||
} else if ("-p800".equalsIgnoreCase(args[0])) { //$NON-NLS-1$
|
||||
createPDisk(args[1], args[2], Disk.APPLE_800KB_DISK);
|
||||
} else if ("-i".equalsIgnoreCase(args[0])) {
|
||||
getDiskInfo(args[1]);
|
||||
} else if ("-dos140".equalsIgnoreCase(args[0])) {
|
||||
createDosDisk(args[1], DosFormatDisk.APPLE_140KB_DISK);
|
||||
} else if ("-pas140".equalsIgnoreCase(args[0])) {
|
||||
createPasDisk(args[1], args[2], PascalFormatDisk.APPLE_140KB_DISK);
|
||||
} else if ("-pro140".equalsIgnoreCase(args[0])) {
|
||||
createProDisk(args[1], args[2], ProdosFormatDisk.APPLE_140KB_DISK);
|
||||
} else if ("-pro800".equalsIgnoreCase(args[0])) {
|
||||
createProDisk(args[1], args[2], ProdosFormatDisk.APPLE_800KB_DISK);
|
||||
} else {
|
||||
help();
|
||||
}
|
||||
@ -70,26 +86,28 @@ public class ac {
|
||||
|
||||
/**
|
||||
* Put <stdin> into the file named fileName on the disk named imageName;
|
||||
* Note: only volume level supported, 32K limit.
|
||||
* Note: only volume level supported; input size unlimited.
|
||||
*/
|
||||
static void putFile(String fileName, String fileType,
|
||||
String address, String imageName)
|
||||
throws IOException, DiskFullException {
|
||||
|
||||
byte[] buf = new byte[32768];
|
||||
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||
byte[] inb = new byte[1024];
|
||||
int byteCount = 0;
|
||||
while ((byteCount = System.in.read(inb)) > 0) {
|
||||
buf.write(inb, 0, byteCount);
|
||||
}
|
||||
Disk disk = new Disk(imageName);
|
||||
FormattedDisk[] formattedDisks = disk.getFormattedDisks();
|
||||
FormattedDisk formattedDisk = formattedDisks[0];
|
||||
int byteCount = System.in.read(buf);
|
||||
byte[] data = new byte[byteCount];
|
||||
System.arraycopy(buf, 0, data, 0, byteCount);
|
||||
FileEntry entry = formattedDisk.createFile();
|
||||
entry.setFilename(fileName);
|
||||
entry.setFiletype(fileType);
|
||||
if (entry.needsAddress()) {
|
||||
entry.setAddress(stringToInt(address));
|
||||
}
|
||||
entry.setFileData(data);
|
||||
entry.setFileData(buf.toByteArray());
|
||||
formattedDisk.save();
|
||||
}
|
||||
|
||||
@ -168,7 +186,7 @@ public class ac {
|
||||
/**
|
||||
* Display a directory listing of the disk named imageName.
|
||||
*/
|
||||
static void showDirectory(String imageName) throws IOException {
|
||||
static void showDirectory(String imageName, int display) throws IOException {
|
||||
Disk disk = new Disk(imageName);
|
||||
FormattedDisk[] formattedDisks = disk.getFormattedDisks();
|
||||
for (int i=0; i<formattedDisks.length; i++) {
|
||||
@ -177,7 +195,7 @@ public class ac {
|
||||
System.out.println(formattedDisk.getDiskName());
|
||||
List files = formattedDisk.getFiles();
|
||||
if (files != null) {
|
||||
showFiles(files, ""); //$NON-NLS-1$
|
||||
showFiles(files, "", display); //$NON-NLS-1$
|
||||
}
|
||||
System.out.println(textBundle.format(
|
||||
"CommandLineStatus", //$NON-NLS-1$
|
||||
@ -195,12 +213,11 @@ public class ac {
|
||||
* In the instance of a system with directories (e.g. ProDOS),
|
||||
* this really returns the first file with the given filename.
|
||||
*/
|
||||
static void showFiles(List files, String indent) {
|
||||
static void showFiles(List files, String indent, int display) {
|
||||
for (int i=0; i<files.size(); i++) {
|
||||
FileEntry entry = (FileEntry) files.get(i);
|
||||
if (!entry.isDeleted()) {
|
||||
List data = entry.getFileColumnData(
|
||||
FormattedDisk.FILE_DISPLAY_NATIVE);
|
||||
List data = entry.getFileColumnData(display);
|
||||
System.out.print(indent);
|
||||
for (int d=0; d<data.size(); d++) {
|
||||
System.out.print(data.get(d));
|
||||
@ -210,15 +227,55 @@ public class ac {
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
showFiles(((DirectoryEntry)entry).getFiles(),
|
||||
indent + " "); //$NON-NLS-1$
|
||||
indent + " ", display); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display information about the given disk image.
|
||||
*/
|
||||
static void getDiskInfo(String imageName) throws IOException {
|
||||
Disk disk = new Disk(imageName);
|
||||
FormattedDisk[] formattedDisks = disk.getFormattedDisks();
|
||||
for (int i=0; i<formattedDisks.length; i++) {
|
||||
FormattedDisk formattedDisk = formattedDisks[i];
|
||||
Iterator iterator = formattedDisk.getDiskInformation().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
DiskInformation diskinfo = (DiskInformation) iterator.next();
|
||||
System.out.println(diskinfo.getLabel() + ": " + diskinfo.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a DOS disk image.
|
||||
*/
|
||||
static void createDosDisk(String fileName, int imageSize)
|
||||
throws IOException {
|
||||
ByteArrayImageLayout layout = new ByteArrayImageLayout(imageSize);
|
||||
ImageOrder imageOrder = new DosOrder(layout);
|
||||
FormattedDisk[] disks =
|
||||
DosFormatDisk.create(fileName, imageOrder);
|
||||
disks[0].save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Pascal disk image.
|
||||
*/
|
||||
static void createPasDisk(String fileName, String volName, int imageSize)
|
||||
throws IOException {
|
||||
ByteArrayImageLayout layout = new ByteArrayImageLayout(imageSize);
|
||||
ImageOrder imageOrder = new ProdosOrder(layout);
|
||||
FormattedDisk[] disks =
|
||||
PascalFormatDisk.create(fileName, volName, imageOrder);
|
||||
disks[0].save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ProDOS disk image.
|
||||
*/
|
||||
static void createPDisk(String fileName, String volName, int imageSize)
|
||||
static void createProDisk(String fileName, String volName, int imageSize)
|
||||
throws IOException {
|
||||
ByteArrayImageLayout layout = new ByteArrayImageLayout(imageSize);
|
||||
ImageOrder imageOrder = new ProdosOrder(layout);
|
||||
@ -238,7 +295,7 @@ public class ac {
|
||||
}
|
||||
|
||||
static void help() {
|
||||
System.err.println(textBundle.get("CommandLineHelp")); //$NON-NLS-1$
|
||||
System.err.println(textBundle.format("CommandLineHelp", AppleCommander.VERSION)); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -103,6 +103,7 @@ import com.webcodepro.applecommander.ui.swt.wizard.compilefile.CompileWizard;
|
||||
import com.webcodepro.applecommander.ui.swt.wizard.exportfile.ExportWizard;
|
||||
import com.webcodepro.applecommander.ui.swt.wizard.importfile.ImportWizard;
|
||||
import com.webcodepro.applecommander.util.AppleUtil;
|
||||
import com.webcodepro.applecommander.util.Host;
|
||||
import com.webcodepro.applecommander.util.StreamUtil;
|
||||
import com.webcodepro.applecommander.util.TextBundle;
|
||||
|
||||
@ -1376,7 +1377,7 @@ public class DiskExplorerTab {
|
||||
protected void saveAs() {
|
||||
FileDialog fileDialog = new FileDialog(shell, SWT.SAVE);
|
||||
fileDialog.setFilterPath(userPreferences.getSaveDirectory());
|
||||
fileDialog.setFileName(disks[0].getFilename());
|
||||
fileDialog.setFileName(Host.getFileName(disks[0].getFilename()));
|
||||
fileDialog.setText(textBundle.get("SaveDiskImageAsPrompt")); //$NON-NLS-1$
|
||||
String fullpath = fileDialog.open();
|
||||
userPreferences.setSaveDirectory(fileDialog.getFilterPath());
|
||||
|
@ -214,7 +214,7 @@ public class AppleUtil {
|
||||
public static void setPascalString(byte[] buffer, int offset, String string, int maxLength) {
|
||||
int len = Math.min(string.length(), maxLength);
|
||||
buffer[offset] = (byte) (len & 0xff);
|
||||
setString(buffer, offset+1, string, len);
|
||||
setString(buffer, offset+1, string, len, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
81
src/com/webcodepro/applecommander/util/Host.java
Normal file
81
src/com/webcodepro/applecommander/util/Host.java
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2006 John B. Matthews
|
||||
* jmatthews at wright dot edu
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.webcodepro.applecommander.util;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Host contains static methods that return information
|
||||
* that varies from one host operating system to another.
|
||||
*
|
||||
* @author John B. Matthews
|
||||
*/
|
||||
|
||||
public class Host {
|
||||
|
||||
private static final boolean macOSX;
|
||||
private static final boolean linux;
|
||||
private static final boolean windows;
|
||||
private static final String userHome = System.getProperty("user.home");
|
||||
private static final String osName = System.getProperty("os.name");
|
||||
private static final String prefDir;
|
||||
|
||||
static {
|
||||
macOSX = (osName.indexOf("Mac OS X") >= 0);
|
||||
linux = (osName.indexOf("Linux") >= 0);
|
||||
windows = (osName.indexOf("Windows") >= 0);
|
||||
|
||||
if (macOSX) {
|
||||
prefDir = userHome + "/Library/Preferences/";
|
||||
}
|
||||
else if (linux){
|
||||
prefDir = "";
|
||||
}
|
||||
else {
|
||||
prefDir = "";
|
||||
}
|
||||
}
|
||||
|
||||
private Host() {}
|
||||
|
||||
/**
|
||||
* Get the host specific preferences directory.
|
||||
* On Mac OS X, this is ~/Library/Preferences/.
|
||||
* On other host systems, it is the empty string.
|
||||
* @return The empty string or the Mac OS X preferences directory with trailing '/'.
|
||||
*/
|
||||
public static String getPrefDir() {
|
||||
return prefDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the host specific form of a file name suitable for a file dialog.
|
||||
* On Mac OS X, this is just the file name portion of the path name.
|
||||
* On other systems, it is the unchanged path name.
|
||||
* @param pathName The full path name of a file.
|
||||
* @return The full path name or the file name for Mac OS X
|
||||
*/
|
||||
public static String getFileName(String pathName) {
|
||||
if (macOSX) {
|
||||
File file = new File(pathName);
|
||||
return file.getName();
|
||||
}
|
||||
return pathName;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user