Merged in John B. Matthews' changes for AppleCommander 1.3.3.9.

This commit is contained in:
Robert Greene 2006-04-16 03:28:36 +00:00
parent 18cb7e533e
commit 8b23db3d7d
13 changed files with 524 additions and 69 deletions

View File

@ -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);

View File

@ -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++;
}

View File

@ -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();

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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();

View File

@ -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$
}
}

View File

@ -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());

View File

@ -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);
}
/**

View 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;
}
}