Download files comprising the current release candidate.
Visit the AppleCommander web site on Source Forge.
AppleCommander 1.3.5.x
AppleCommander is Rob Greene's Java based graphical tool for working with Apple II disk images. The latest version adds support for cross-development with cc65, execution on i386 Mac OS X, and bug fixes. As before, support for Apple UCSD Pascal has been expanded to include import and delete, as well as 800K disk images. Export and view have been improved for several file types. More details may be found on the project web site, as they become available. The latest sources may be found in the CVS section of the AppleCommander project page on SourceForge. The command-line jar requires Java 1.3+, while the GUI requires Java 1.4+. The default ant target builds everything. Due to limited resources, the download link above is limited to the current release candidate, until changes are integrated into the next stable release.
Command Line
"ac" is a command line interface to Rob Greene's AppleCommander, a Java based tool for working with Apple II disk images. Because it is written in Java, ac runs on numerous platforms including Mac OS X and GNU/Linux. It works with ProDOS, Pascal, DOS 3.3 and other disk images. The program is ideally suited to automate the transfer of externally managed files to/from an Apple II disk image. The most recent version of the guide to command-line options is inclued with the current release candidate; the most recent stable release has been integrated into the AppleCommander website. Note that the order of some command options has been changed to make them more consistent. Use the -h option to see the current format.
The program is provided under the GNU Public License, a copy of which is included. You should read the license before using ac, noting that there is NO WARRANTY OF ANY KIND. Because here is NO LIABILITY FOR DAMAGES, never use ac on an image for which you do not have a backup.
Changes to Apple Commander v1.3.5
The following changes were made to AppleCommander v1.3.5:
Changes to Apple Commander v1.3.4
The following changes were made to AppleCommander v1.3.4:
Changes to Apple Commander v1.3.3
The following changes were made to AppleCommander v1.3.3 to make it compatible with ac:
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);
}
setString(buffer, offset+1, string, len, false);
Changes to Apple Commander v1.2.3
The following changes were made to AppleCommander v1.2.3 to make it compatible with ac:
/**
* Extract a Pascal date from the buffer.
* Bits 0-3: month (1-12)
* Bits 4-8: day (1-31)
* Bits 9-15: year (0-99)
*/
public static Date getPascalDate(byte[] buffer, int offset) {
int pascalDate = getWordValue(buffer, offset);
int month = pascalDate & 0x000f - 1;
int day = (pascalDate & 0x01f0) >> 4;
int year = (pascalDate & 0xfe00) >> 9;
if (year < 50) year+= 2000;
if (year < 100) year+= 1900;
GregorianCalendar gc = new GregorianCalendar(year, month, day);
return gc.getTime();
}
/**
* Set a Pascal data to the buffer.
* Bits 0-3: month (1-12)
* Bits 4-8: day (1-31)
* Bits 9-15: year (0-99)
*/
public static void setPascalDate(byte[] buffer, int offset, Date date) {
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(date);
int month = gc.get(GregorianCalendar.MONTH) + 1;
int day = gc.get(GregorianCalendar.DAY_OF_MONTH);
int year = gc.get(GregorianCalendar.YEAR) % 100;
int pascalDate = (month & 0x000f)
| ((day << 4) & 0x01f0)
| ((year << 9) & 0xfe00);
setWordValue(buffer, offset, pascalDate);
}
int month = ((ymd & 0x01e0) >> 5) - 1; // bits 5-8
In setProdosDate add one and fix the year:
month = gc.get(GregorianCalendar.MONTH) + 1;
...
if (year >= 2000) {
year -= 2000;
} else {
year -= 1900;
}
fileEntry.setKeyPointer(0); //may have been recycled
/**
* Set the block number of the block for the directory
* that describes this file.
*/
public void setHeaderPointer(int headerPointer) {
byte[] entry = readFileEntry();
AppleUtil.setWordValue(entry, 0x25, headerPointer);
writeFileEntry(entry);
}
int headerBlock = blockNumber;
...
fileEntry.setHeaderPointer(headerBlock);
/**
* Delete the file.
*/
public void delete() {
getDisk().freeBlocks(this);
//decrement file count in header block
int headerBlock = getHeaderPointer();
byte[] data = getDisk().readBlock(headerBlock);
int fileCount = AppleUtil.getWordValue(data, 0x25);
if (fileCount != 0) fileCount--;
AppleUtil.setWordValue(data, 0x25, fileCount);
getDisk().writeBlock(headerBlock, data);
//clear storage type and name length
data = readFileEntry();
data[0] = 0;
writeFileEntry(data);
}
/**
* Process the given FileEntry and return a byte array
* with filtered data; use PrintWriter to get platform
* agnostic line endings.
*/
public byte[] filter(FileEntry fileEntry) {
byte[] fileData = fileEntry.getFileData();
int offset = 0;
ByteArrayOutputStream byteArray = new
ByteArrayOutputStream(fileData.length);
PrintWriter printWriter = new PrintWriter(byteArray, true);
while (offset < fileData.length) {
char c = (char)(fileData[offset] & 0x7f);
if (c != 0) {
if (c == 0x0d) { //Apple line end
printWriter.println();
} else {
printWriter.print(c);
}
}
offset++;
}
return byteArray.toByteArray();
}
filetype.fc.address=true