/* * 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 * 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.storage.os.pascal; import java.util.ArrayList; import java.util.BitSet; import java.util.Date; import java.util.Iterator; import java.util.List; import com.webcodepro.applecommander.storage.DirectoryEntry; import com.webcodepro.applecommander.storage.DiskFullException; import com.webcodepro.applecommander.storage.FileEntry; import com.webcodepro.applecommander.storage.FormattedDisk; import com.webcodepro.applecommander.storage.StorageBundle; import com.webcodepro.applecommander.storage.physical.ImageOrder; import com.webcodepro.applecommander.util.AppleUtil; import com.webcodepro.applecommander.util.TextBundle; /** * Manages a disk that is in the Pascal format. *

* Date created: Oct 4, 2002 11:56:50 PM * @author Rob Greene * @author John B. Matthews [getFiles(), get/putDirectory(), createFile()] */ public class PascalFormatDisk extends FormattedDisk { private TextBundle textBundle = StorageBundle.getInstance(); /** * The size of the Pascal file entry. */ public static final int ENTRY_SIZE = 26; /** * The number of Pascal blocks on a 140K disk. */ public static final int PASCAL_BLOCKS_ON_140K_DISK = 280; // filetypes used elsewhere in the code: 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 known filetypes for a Pascal disk. */ private static final String[] filetypes = { "xdskfile", //$NON-NLS-1$ CODEFILE, TEXTFILE, "INFO", //$NON-NLS-1$ DATAFILE, "GRAF", //$NON-NLS-1$ "FOTO", //$NON-NLS-1$ "securedir" }; //$NON-NLS-1$ /** * Use this inner interface for managing the disk usage data. * This offloads format-specific implementation to the implementing class. * A BitSet is used to track all blocks, as Pascal disks do not have a * bitmap stored on the disk. This is safe since we know the number of blocks * that exist. (BitSet length is of last set bit - unset bits at the end are * "lost".) */ private class PascalDiskUsage implements DiskUsage { private int location = -1; private BitSet bitmap = null; public boolean hasNext() { return location == -1 || location < getBlocksOnDisk() - 1; } public void next() { if (bitmap == null) { bitmap = new BitSet(getBlocksOnDisk()); // assume all blocks are unused for (int block=6; block 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"); //$NON-NLS-1$ entry.setFilename("x"); //$NON-NLS-1$ 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(textBundle.get("PascalFormatDisk.DiskFull")); //$NON-NLS-1$ } } /** * Identify if additional directories can be created. This * may indicate that directories are not available to this * operating system or simply that the disk image is "locked" * to writing. */ public boolean canCreateDirectories() { return false; } /** * Indicates if this disk image can create a file. * If not, the reason may be as simple as it has not beem implemented * to something specific about the disk. */ public boolean canCreateFile() { return true; } /** * Read directory blocks. These are always in blocks 2 - 5 and * are treated as a 2048 byte array. */ public byte[] readDirectory() { byte[] directory = new byte[4 * BLOCK_SIZE]; for (int i=0; i<4; i++) { System.arraycopy(readBlock(2+i), 0, directory, i*BLOCK_SIZE, BLOCK_SIZE); } return directory; } /** * Write directory blocks. */ public void writeDirectory(byte[] directory) { if (directory == null || directory.length != 2048) { throw new IllegalArgumentException(textBundle.get("PascalFormatDisk.InvalidPascalDirectory")); //$NON-NLS-1$ } for (int i=0; i<4; i++) { byte[] block = new byte[BLOCK_SIZE]; System.arraycopy(directory, i*BLOCK_SIZE, block, 0, BLOCK_SIZE); writeBlock(2+i, block); } } /** * Identify if this disk format is capable of having directories. * @see com.webcodepro.applecommander.storage.FormattedDisk#canHaveDirectories() */ public boolean canHaveDirectories() { return false; } /** * Return the amount of free space in bytes. * @see com.webcodepro.applecommander.storage.FormattedDisk#getFreeSpace() */ public int getFreeSpace() { return getFreeBlocks() * BLOCK_SIZE; } /** * Return the number of free blocks. */ public int getFreeBlocks() { List files = getFiles(); int blocksFree = getBlocksOnDisk() - 6; if (files != null) { for (int i=0; i 0) { String what = filename.substring(pos+1); if ("txt".equalsIgnoreCase(what)) { //$NON-NLS-1$ filetype = TEXTFILE; } else if ("pas".equalsIgnoreCase(what)) { //$NON-NLS-1$ filetype = CODEFILE; } } return filetype; } /** * Returns a list of possible file types. Since the filetype is * specific to each operating system, a simple String is used. */ public String[] getFiletypes() { return filetypes; } /** * Indicates if this filetype requires an address component. * No Pascal filetypes require or support an address. */ public boolean needsAddress(String filetype) { return false; } /** * Indicates if this FormattedDisk supports a disk map. */ public boolean supportsDiskMap() { return true; } /** * Change to a different ImageOrder. Remains in Pascal format but * the underlying order can chage. * @see ImageOrder */ public void changeImageOrder(ImageOrder imageOrder) { AppleUtil.changeImageOrderByBlock(getImageOrder(), imageOrder); setImageOrder(imageOrder); } /** * Writes the raw bytes into the file. This bypasses any special formatting * of the data (such as prepending the data with a length and/or an address). * Typically, the FileEntry.setFileData method should be used. */ public void setFileData(FileEntry fileEntry, byte[] fileData) throws DiskFullException { // TODO implement setFileData } /** * Create a new DirectoryEntry. * @see com.webcodepro.applecommander.storage.DirectoryEntry#createDirectory() */ public DirectoryEntry createDirectory() throws DiskFullException { throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$ } }