Merge pull request #19 from Lisias/issues/18

Fixing https://github.com/AppleCommander/AppleCommander/issues/18
This commit is contained in:
A2 Geek 2018-01-29 21:00:33 -06:00 committed by GitHub
commit 24623b2c20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 611 additions and 159 deletions

View File

@ -28,6 +28,9 @@ import java.util.List;
* <p> * <p>
* Date Created: Mar 2, 2003 * Date Created: Mar 2, 2003
* @author Rob Greene * @author Rob Greene
*
* Changed at: Dec 1, 2017
* @author Lisias Toledo
*/ */
public interface DirectoryEntry { public interface DirectoryEntry {
/** /**
@ -37,17 +40,17 @@ public interface DirectoryEntry {
* return value should always be a list - a directory * return value should always be a list - a directory
* with 0 entries returns an empty list. * with 0 entries returns an empty list.
*/ */
public List<FileEntry> getFiles(); public List<FileEntry> getFiles() throws DiskException;
/** /**
* Create a new FileEntry. * Create a new FileEntry.
*/ */
public FileEntry createFile() throws DiskFullException; public FileEntry createFile() throws DiskException;
/** /**
* Create a new DirectoryEntry. * Create a new DirectoryEntry.
*/ */
public DirectoryEntry createDirectory(String name) throws DiskFullException; public DirectoryEntry createDirectory(String name) throws DiskException;
/** /**
* Identify if additional directories can be created. This * Identify if additional directories can be created. This
@ -56,7 +59,7 @@ public interface DirectoryEntry {
* to writing. * to writing.
*/ */
public boolean canCreateDirectories(); public boolean canCreateDirectories();
/** /**
* Indicates if this disk image can create a file. * Indicates if this disk image can create a file.
* If not, the reason may be as simple as it has not beem implemented * If not, the reason may be as simple as it has not beem implemented

View File

@ -369,10 +369,10 @@ public class Disk {
/** /**
* Determine type of disk, and return the appropriate * Determine type of disk, and return the appropriate
* FormattedDisk object. Returns null if none are * FormattedDisk object. Throws an Exception if none is recognized.
* recognized. * @throws DiskUnrecognizedException
*/ */
public FormattedDisk[] getFormattedDisks() { public FormattedDisk[] getFormattedDisks() throws DiskUnrecognizedException {
if (isProdosFormat()) { if (isProdosFormat()) {
return new FormattedDisk[] return new FormattedDisk[]
{ new ProdosFormatDisk(filename, imageOrder) }; { new ProdosFormatDisk(filename, imageOrder) };
@ -407,7 +407,7 @@ public class Disk {
return new FormattedDisk[] return new FormattedDisk[]
{ new GutenbergFormatDisk(filename, imageOrder) }; { new GutenbergFormatDisk(filename, imageOrder) };
} }
return null; throw new DiskUnrecognizedException(filename);
} }
/** /**

View File

@ -0,0 +1,62 @@
/*
* AppleCommander - An Apple ][ image utility.
* Copyright (C) 2002 by Robert Greene
* robgreene at users.sourceforge.net
*
* 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;
/**
* A DiskCorruptException is thrown during the disk's data structures are corrupted
* beyound hope of automatic recovering.
* <br>
* Created on Nov 30, 2017.
* @author Lisias Toledo
*/
public class DiskCorruptException extends DiskException {
private static final long serialVersionUID = 0xFFFFFFFF80000000L;
public enum Kind {
RECURSIVE_DIRECTORY_STRUCTURE {
public String toString() {
return "DiskCorruptException.RecursiveDirectoryStructure"; //$NON-NLS-1$
};
}
}
public final Kind kind;
public final Object offender;
private DiskCorruptException(final String description, final String imagepath) {
super(description, imagepath);
this.kind = null;
this.offender = null;
}
/**
* Constructor for DiskFullException.
*/
public DiskCorruptException(final String imagepath, final Kind kind, final Object offender) {
super(kind.toString(), imagepath);
this.kind = kind;
this.offender = offender;
}
public String toString() {
return super.toString() + " @ " + offender.toString();
}
}

View File

@ -0,0 +1,41 @@
/*
* AppleCommander - An Apple ][ image utility.
* Copyright (C) 2002 by Robert Greene
* robgreene at users.sourceforge.net
*
* 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;
/**
* A DiskException is the base class for Disk Exceptions.
* <br>
* Created on Nov 30, 2017.
* @author Lisias Toledo
*/
public abstract class DiskException extends Exception {
private static final long serialVersionUID = 0xFFFFFFFF80000000L;
public final String imagepath;
/**
* Constructor for DiskException.
*/
public DiskException(final String description, final String imagepath) {
super(description);
this.imagepath = imagepath;
}
}

View File

@ -25,15 +25,18 @@ package com.webcodepro.applecommander.storage;
* <br> * <br>
* Created on Dec 23, 2002. * Created on Dec 23, 2002.
* @author Rob Greene * @author Rob Greene
*
* Changed at: Dec 1, 2017
* @author Lisias Toledo
*/ */
public class DiskFullException extends Exception { public class DiskFullException extends DiskException {
private static final long serialVersionUID = 0xFFFFFFFF80000000L; private static final long serialVersionUID = 0xFFFFFFFF80000000L;
/** /**
* Constructor for DiskFullException. * Constructor for DiskFullException.
*/ */
public DiskFullException(String description) { public DiskFullException(final String description, final String imagepath) {
super(description); super(description, imagepath);
} }
} }

View File

@ -0,0 +1,38 @@
/*
* AppleCommander - An Apple ][ image utility.
* Copyright (C) 2002 by Robert Greene
* robgreene at users.sourceforge.net
*
* 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;
/**
* A DiskUnrecognizedException is thrown when the Disk Image being opened is not recognized by any image handler.
* <br>
* Created at: Jan 8, 2018
* @author Lisias Toledo
*/
public class DiskUnrecognizedException extends DiskException {
private static final long serialVersionUID = 0xFFFFFFFF80000000L;
/**
* Constructor for DiskFullException.
*/
public DiskUnrecognizedException(final String imagepath) {
super("DiskUnrecognizedException", imagepath);
}
}

View File

@ -267,7 +267,7 @@ public abstract class FormattedDisk extends Disk implements DirectoryEntry {
* Locate a specific file by filename. * Locate a specific file by filename.
* Returns a null if specific filename is not located. * Returns a null if specific filename is not located.
*/ */
public FileEntry getFile(String filename) { public FileEntry getFile(String filename) throws DiskException {
List files = getFiles(); List files = getFiles();
return getFile(files, filename.trim()); return getFile(files, filename.trim());
} }
@ -277,7 +277,7 @@ public abstract class FormattedDisk extends Disk implements DirectoryEntry {
* Note that in the instance of a system with directories (ie, ProDOS), * Note that in the instance of a system with directories (ie, ProDOS),
* this really returns the first file with the given filename. * this really returns the first file with the given filename.
*/ */
protected FileEntry getFile(List files, String filename) { protected FileEntry getFile(List files, String filename) throws DiskException {
FileEntry theFileEntry = null; FileEntry theFileEntry = null;
if (files != null) { if (files != null) {
for (int i=0; i<files.size(); i++) { for (int i=0; i<files.size(); i++) {

View File

@ -407,7 +407,9 @@ public class CpmFormatDisk extends FormattedDisk {
* @see com.webcodepro.applecommander.storage.DirectoryEntry#createFile() * @see com.webcodepro.applecommander.storage.DirectoryEntry#createFile()
*/ */
public FileEntry createFile() throws DiskFullException { public FileEntry createFile() throws DiskFullException {
throw new DiskFullException(textBundle.get("FileCreationNotSupported")); //$NON-NLS-1$ throw new DiskFullException(
textBundle.get("FileCreationNotSupported") //$NON-NLS-1$
, this.getFilename());
} }
/** /**

View File

@ -21,8 +21,12 @@ package com.webcodepro.applecommander.storage.os.dos33;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.HashSet;
import com.webcodepro.applecommander.storage.DirectoryEntry; import com.webcodepro.applecommander.storage.DirectoryEntry;
import com.webcodepro.applecommander.storage.DiskException;
import com.webcodepro.applecommander.storage.DiskCorruptException;
import com.webcodepro.applecommander.storage.DiskFullException; import com.webcodepro.applecommander.storage.DiskFullException;
import com.webcodepro.applecommander.storage.FileEntry; import com.webcodepro.applecommander.storage.FileEntry;
import com.webcodepro.applecommander.storage.FormattedDisk; import com.webcodepro.applecommander.storage.FormattedDisk;
@ -36,6 +40,9 @@ import com.webcodepro.applecommander.util.TextBundle;
* <p> * <p>
* Date created: Oct 4, 2002 12:29:23 AM * Date created: Oct 4, 2002 12:29:23 AM
* @author Rob Greene * @author Rob Greene
*
* Changed at: Dec 1, 2017
* @author Lisias Toledo
*/ */
public class DosFormatDisk extends FormattedDisk { public class DosFormatDisk extends FormattedDisk {
private TextBundle textBundle = StorageBundle.getInstance(); private TextBundle textBundle = StorageBundle.getInstance();
@ -132,14 +139,22 @@ public class DosFormatDisk extends FormattedDisk {
/** /**
* Retrieve a list of files. * Retrieve a list of files.
* @throws DiskException
* @see com.webcodepro.applecommander.storage.FormattedDisk#getFiles() * @see com.webcodepro.applecommander.storage.FormattedDisk#getFiles()
*/ */
public List<FileEntry> getFiles() { public List<FileEntry> getFiles() throws DiskException {
List<FileEntry> list = new ArrayList<>(); List<FileEntry> list = new ArrayList<>();
byte[] vtoc = readVtoc(); byte[] vtoc = readVtoc();
int track = AppleUtil.getUnsignedByte(vtoc[1]); int track = AppleUtil.getUnsignedByte(vtoc[1]);
int sector = AppleUtil.getUnsignedByte(vtoc[2]); int sector = AppleUtil.getUnsignedByte(vtoc[2]);
final Set<DosSectorAddress> visits = new HashSet<>();
while (sector != 0) { // bug fix: iterate through all catalog _sectors_ while (sector != 0) { // bug fix: iterate through all catalog _sectors_
// Prevents a recursive catalog crawling.
final DosSectorAddress address = new DosSectorAddress(track, sector);
if ( visits.contains(address)) throw new DiskCorruptException(this.getFilename(), DiskCorruptException.Kind.RECURSIVE_DIRECTORY_STRUCTURE, address);
else visits.add(address);
byte[] catalogSector = readSector(track, sector); byte[] catalogSector = readSector(track, sector);
int offset = 0x0b; int offset = 0x0b;
while (offset < 0xff) { // iterate through all entries while (offset < 0xff) { // iterate through all entries
@ -174,7 +189,9 @@ public class DosFormatDisk extends FormattedDisk {
track = catalogSector[1]; track = catalogSector[1];
sector = catalogSector[2]; sector = catalogSector[2];
} }
throw new DiskFullException(textBundle.get("DosFormatDisk.NoMoreSpaceError")); //$NON-NLS-1$ throw new DiskFullException(
textBundle.get("DosFormatDisk.NoMoreSpaceError") //$NON-NLS-1$
, this.getFilename());
} }
/** /**
@ -457,7 +474,8 @@ public class DosFormatDisk extends FormattedDisk {
if (numberOfSectors > getFreeSectors() + fileEntry.getSectorsUsed()) { if (numberOfSectors > getFreeSectors() + fileEntry.getSectorsUsed()) {
throw new DiskFullException( throw new DiskFullException(
textBundle.format("DosFormatDisk.NotEnoughSectorsError", //$NON-NLS-1$ textBundle.format("DosFormatDisk.NotEnoughSectorsError", //$NON-NLS-1$
numberOfSectors, getFreeSectors())); numberOfSectors, getFreeSectors())
, this.getFilename());
} }
// free "old" data and just rewrite stuff... // free "old" data and just rewrite stuff...
freeSectors(fileEntry); freeSectors(fileEntry);

View File

@ -0,0 +1,56 @@
/*
* AppleCommander - An Apple ][ image utility.
* Copyright (C) 2002 by Robert Greene
* robgreene at users.sourceforge.net
*
* 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.dos33;
/**
* A Container for DOS 3.3 Sector Addresses.
* <br>
* Created on Dec 13, 2017.
* @author Lisias Toledo
*/
public class DosSectorAddress {
public final Integer track;
public final Integer sector;
public DosSectorAddress(int track, int sector) {
this.track = track;
this.sector = sector;
}
public String toString() {
return "Track:" + this.track + ", Sector:" + this.sector;
}
public boolean equals(final Object other){
if(other == null) return false;
if(!(other instanceof DosSectorAddress)) return false;
final DosSectorAddress o = (DosSectorAddress) other;
return this.track == o.track && this.sector == o.sector;
}
public int hashCode() {
int result = 17;
result = 31 * result + this.track.hashCode();
result = 31 * result + this.sector.hashCode();
return result;
}
}

View File

@ -172,7 +172,9 @@ public class GutenbergFormatDisk extends FormattedDisk {
track = catalogSector[1]; track = catalogSector[1];
sector = catalogSector[2]; sector = catalogSector[2];
} }
throw new DiskFullException(textBundle.get("DosFormatDisk.NoMoreSpaceError")); //$NON-NLS-1$ throw new DiskFullException(
textBundle.get("DosFormatDisk.NoMoreSpaceError") //$NON-NLS-1$
, this.getFilename());
} }
/** /**
@ -436,7 +438,8 @@ public class GutenbergFormatDisk extends FormattedDisk {
if (numberOfSectors > getFreeSectors() + fileEntry.getSectorsUsed()) { if (numberOfSectors > getFreeSectors() + fileEntry.getSectorsUsed()) {
throw new DiskFullException( throw new DiskFullException(
textBundle.format("DosFormatDisk.NotEnoughSectorsError", //$NON-NLS-1$ textBundle.format("DosFormatDisk.NotEnoughSectorsError", //$NON-NLS-1$
numberOfSectors, getFreeSectors())); numberOfSectors, getFreeSectors())
, this.getFilename());
} }
// free "old" data and just rewrite stuff... // free "old" data and just rewrite stuff...
// freeSectors(fileEntry); (not going to work...) // freeSectors(fileEntry); (not going to work...)

View File

@ -351,7 +351,7 @@ public class PascalFileEntry implements FileEntry {
volEntry.setFileCount(count - 2); volEntry.setFileCount(count - 2);
dir.set(0, volEntry); dir.set(0, volEntry);
disk.putDirectory(dir); disk.putDirectory(dir);
throw new DiskFullException(s); throw new DiskFullException(s, this.disk.getFilename());
} }
} }

View File

@ -233,7 +233,9 @@ public class PascalFormatDisk extends FormattedDisk {
putDirectory(dir); putDirectory(dir);
return entry; return entry;
} else { } else {
throw new DiskFullException(textBundle.get("PascalFormatDisk.DiskFull")); //$NON-NLS-1$ throw new DiskFullException(
textBundle.get("PascalFormatDisk.DiskFull") //$NON-NLS-1$
, this.getFilename());
} }
} }

View File

@ -0,0 +1,39 @@
/*
* AppleCommander - An Apple ][ image utility.
* Copyright (C) 2002 by Robert Greene
* robgreene at users.sourceforge.net
*
* 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.prodos;
/**
* A Container for DOS 3.3 Sector Addresses.
* <br>
* Created on Dec 13, 2017.
* @author Lisias Toledo
*/
public class ProdosBlockAddress {
public final Integer number;
public ProdosBlockAddress(int number) {
this.number = number;
}
public String toString() {
return "Block:" + this.number;
}
}

View File

@ -22,6 +22,7 @@ package com.webcodepro.applecommander.storage.os.prodos;
import java.util.List; import java.util.List;
import com.webcodepro.applecommander.storage.DirectoryEntry; import com.webcodepro.applecommander.storage.DirectoryEntry;
import com.webcodepro.applecommander.storage.DiskException;
import com.webcodepro.applecommander.storage.DiskFullException; import com.webcodepro.applecommander.storage.DiskFullException;
import com.webcodepro.applecommander.storage.FileEntry; import com.webcodepro.applecommander.storage.FileEntry;
import com.webcodepro.applecommander.storage.StorageBundle; import com.webcodepro.applecommander.storage.StorageBundle;
@ -32,21 +33,24 @@ import com.webcodepro.applecommander.util.TextBundle;
* <p> * <p>
* Date Created: Mar 2, 2003 * Date Created: Mar 2, 2003
* @author Rob Greene * @author Rob Greene
*
* Changed at: Dec 1, 2017
* @author Lisias Toledo
*/ */
public class ProdosDirectoryEntry extends ProdosFileEntry implements DirectoryEntry { public class ProdosDirectoryEntry extends ProdosFileEntry implements DirectoryEntry {
private TextBundle textBundle = StorageBundle.getInstance(); private TextBundle textBundle = StorageBundle.getInstance();
private ProdosSubdirectoryHeader subdirectoryHeader; private ProdosSubdirectoryHeader subdirectoryHeader;
/** /**
* Constructor for ProdosDirectoryEntry. * Constructor for ProdosDirectoryEntry.
*/ */
public ProdosDirectoryEntry(ProdosFormatDisk disk, int block, int offset, public ProdosDirectoryEntry(ProdosFormatDisk disk, int block, int offset,
ProdosSubdirectoryHeader subdirectoryHeader) { ProdosSubdirectoryHeader subdirectoryHeader) {
super(disk, block, offset); super(disk, block, offset);
this.subdirectoryHeader = subdirectoryHeader; this.subdirectoryHeader = subdirectoryHeader;
subdirectoryHeader.setProdosDirectoryEntry(this); subdirectoryHeader.setProdosDirectoryEntry(this);
} }
/** /**
* Get the subdirectory header. * Get the subdirectory header.
*/ */
@ -60,8 +64,9 @@ public class ProdosDirectoryEntry extends ProdosFileEntry implements DirectoryEn
* value should be null. If this a directory, the * value should be null. If this a directory, the
* return value should always be a list - a directory * return value should always be a list - a directory
* with 0 entries returns an empty list. * with 0 entries returns an empty list.
* @throws DiskException
*/ */
public List<FileEntry> getFiles() { public List<FileEntry> getFiles() throws DiskException {
return getDisk().getFiles(getSubdirectoryHeader().getFileEntryBlock()); return getDisk().getFiles(getSubdirectoryHeader().getFileEntryBlock());
} }

View File

@ -37,7 +37,7 @@ public class ProdosDiskSizeDoesNotMatchException extends DiskFullException {
/** /**
* Constructor for ProdosDiskSizeDoesNotMatchException. * Constructor for ProdosDiskSizeDoesNotMatchException.
*/ */
public ProdosDiskSizeDoesNotMatchException(String description) { public ProdosDiskSizeDoesNotMatchException(String description, final String imagepath) {
super(description); super(description, imagepath);
} }
} }

View File

@ -25,8 +25,12 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.Set;
import java.util.HashSet;
import com.webcodepro.applecommander.storage.DirectoryEntry; import com.webcodepro.applecommander.storage.DirectoryEntry;
import com.webcodepro.applecommander.storage.DiskException;
import com.webcodepro.applecommander.storage.DiskCorruptException;
import com.webcodepro.applecommander.storage.DiskFullException; import com.webcodepro.applecommander.storage.DiskFullException;
import com.webcodepro.applecommander.storage.FileEntry; import com.webcodepro.applecommander.storage.FileEntry;
import com.webcodepro.applecommander.storage.FormattedDisk; import com.webcodepro.applecommander.storage.FormattedDisk;
@ -40,6 +44,9 @@ import com.webcodepro.applecommander.util.TextBundle;
* <p> * <p>
* Date created: Oct 3, 2002 11:45:25 PM * Date created: Oct 3, 2002 11:45:25 PM
* @author Rob Greene * @author Rob Greene
*
* Changed at: Dec 1, 2017
* @author Lisias Toledo
*/ */
public class ProdosFormatDisk extends FormattedDisk { public class ProdosFormatDisk extends FormattedDisk {
private TextBundle textBundle = StorageBundle.getInstance(); private TextBundle textBundle = StorageBundle.getInstance();
@ -250,14 +257,15 @@ public class ProdosFormatDisk extends FormattedDisk {
} }
blockNumber = nextBlockNumber; blockNumber = nextBlockNumber;
} }
throw new DiskFullException(textBundle.get("ProdosFormatDisk.UnableToAllocateSpaceError")); //$NON-NLS-1$ throw new DiskFullException(textBundle.get("ProdosFormatDisk.UnableToAllocateSpaceError"), this.getFilename()); //$NON-NLS-1$
} }
/** /**
* Retrieve a list of files. * Retrieve a list of files.
* @throws DiskException
* @see com.webcodepro.applecommander.storage.FormattedDisk#getFiles() * @see com.webcodepro.applecommander.storage.FormattedDisk#getFiles()
*/ */
public List<FileEntry> getFiles() { public List<FileEntry> getFiles() throws DiskException {
return getFiles(VOLUME_DIRECTORY_BLOCK); return getFiles(VOLUME_DIRECTORY_BLOCK);
} }
@ -265,9 +273,14 @@ public class ProdosFormatDisk extends FormattedDisk {
* Build a list of files, starting in the given block number. * Build a list of files, starting in the given block number.
* This works for the master as well as the subdirectories. * This works for the master as well as the subdirectories.
*/ */
protected List<FileEntry> getFiles(int blockNumber) { protected List<FileEntry> getFiles(int blockNumber) throws DiskException {
List<FileEntry> files = new ArrayList<>(); List<FileEntry> files = new ArrayList<>();
final Set<Integer> visits = new HashSet<>();
while (blockNumber != 0) { while (blockNumber != 0) {
// Prevents a recursive catalog crawling.
if ( visits.contains(blockNumber)) throw new DiskCorruptException(this.getFilename(), DiskCorruptException.Kind.RECURSIVE_DIRECTORY_STRUCTURE, new ProdosBlockAddress(blockNumber));
else visits.add(blockNumber);
byte[] block = readBlock(blockNumber); byte[] block = readBlock(blockNumber);
int offset = 4; int offset = 4;
while (offset+ProdosCommonEntry.ENTRY_LENGTH < BLOCK_SIZE) { while (offset+ProdosCommonEntry.ENTRY_LENGTH < BLOCK_SIZE) {
@ -643,7 +656,8 @@ public class ProdosFormatDisk extends FormattedDisk {
if (numberOfBlocks > getFreeBlocks() + fileEntry.getBlocksUsed()) { if (numberOfBlocks > getFreeBlocks() + fileEntry.getBlocksUsed()) {
throw new DiskFullException(textBundle. throw new DiskFullException(textBundle.
format("ProdosFormatDisk.NotEnoughSpaceOnDiskError", //$NON-NLS-1$ format("ProdosFormatDisk.NotEnoughSpaceOnDiskError", //$NON-NLS-1$
numberOfBlocks, getFreeBlocks())); numberOfBlocks, getFreeBlocks())
, this.getFilename());
} }
// free "old" data and just rewrite stuff... // free "old" data and just rewrite stuff...
freeBlocks(fileEntry); freeBlocks(fileEntry);
@ -748,7 +762,8 @@ public class ProdosFormatDisk extends FormattedDisk {
if (numberOfBlocks > getFreeBlocks() + fileEntry.getBlocksUsed()) { if (numberOfBlocks > getFreeBlocks() + fileEntry.getBlocksUsed()) {
throw new DiskFullException(textBundle. throw new DiskFullException(textBundle.
format("ProdosFormatDisk.NotEnoughSpaceOnDiskError", //$NON-NLS-1$ format("ProdosFormatDisk.NotEnoughSpaceOnDiskError", //$NON-NLS-1$
numberOfBlocks, getFreeBlocks())); numberOfBlocks, getFreeBlocks())
, this.getFilename());
} }
// free "old" data and just rewrite stuff... // free "old" data and just rewrite stuff...
freeBlocks(fileEntry); freeBlocks(fileEntry);
@ -915,7 +930,8 @@ public class ProdosFormatDisk extends FormattedDisk {
if (numberOfBlocks > getFreeBlocks() + fileEntry.getBlocksUsed()) { if (numberOfBlocks > getFreeBlocks() + fileEntry.getBlocksUsed()) {
throw new DiskFullException(textBundle. throw new DiskFullException(textBundle.
format("ProdosFormatDisk.NotEnoughSpaceOnDiskError", //$NON-NLS-1$ format("ProdosFormatDisk.NotEnoughSpaceOnDiskError", //$NON-NLS-1$
numberOfBlocks, getFreeBlocks())); numberOfBlocks, getFreeBlocks())
, this.getFilename());
} }
// free "old" data and just rewrite stuff... // free "old" data and just rewrite stuff...
freeBlocks(fileEntry); freeBlocks(fileEntry);
@ -1056,12 +1072,14 @@ public class ProdosFormatDisk extends FormattedDisk {
return block; return block;
} }
throw new ProdosDiskSizeDoesNotMatchException( throw new ProdosDiskSizeDoesNotMatchException(
textBundle.get("ProdosFormatDisk.ProdosDiskSizeDoesNotMatchError")); //$NON-NLS-1$ textBundle.get("ProdosFormatDisk.ProdosDiskSizeDoesNotMatchError") //$NON-NLS-1$
, this.getFilename());
} }
block++; block++;
} }
throw new DiskFullException( throw new DiskFullException(
textBundle.get("ProdosFormatDisk.NoFreeBlockAvailableError")); //$NON-NLS-1$ textBundle.get("ProdosFormatDisk.NoFreeBlockAvailableError") //$NON-NLS-1$
, this.getFilename());
} }
/** /**
@ -1410,6 +1428,8 @@ public class ProdosFormatDisk extends FormattedDisk {
} }
blockNumber = nextBlockNumber; blockNumber = nextBlockNumber;
} }
throw new DiskFullException(textBundle.get("ProdosFormatDisk.UnableToAllocateSpaceError")); //$NON-NLS-1$ throw new DiskFullException(
textBundle.get("ProdosFormatDisk.UnableToAllocateSpaceError") //$NON-NLS-1$
, this.getFilename());
} }
} }

View File

@ -202,7 +202,7 @@ public class RdosFormatDisk extends FormattedDisk {
* Create a new FileEntry. * Create a new FileEntry.
*/ */
public FileEntry createFile() throws DiskFullException { public FileEntry createFile() throws DiskFullException {
throw new DiskFullException(textBundle.get("FileCreationNotSupported")); //$NON-NLS-1$ throw new DiskFullException(textBundle.get("FileCreationNotSupported"), this.getFilename()); //$NON-NLS-1$
} }
/** /**

View File

@ -26,6 +26,7 @@ import java.io.PrintStream;
import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task; import org.apache.tools.ant.Task;
import com.webcodepro.applecommander.storage.Disk; import com.webcodepro.applecommander.storage.Disk;
import com.webcodepro.applecommander.storage.DiskException;
import com.webcodepro.applecommander.storage.FormattedDisk; import com.webcodepro.applecommander.storage.FormattedDisk;
public class AntTask extends Task public class AntTask extends Task
@ -107,7 +108,7 @@ public class AntTask extends Task
{ {
com.webcodepro.applecommander.ui.ac.deleteFile(_imageName, _fileName); com.webcodepro.applecommander.ui.ac.deleteFile(_imageName, _fileName);
} }
catch (IOException io) catch (IOException|DiskException io)
{ {
if (_failonerror) if (_failonerror)
throw new BuildException(io); throw new BuildException(io);
@ -121,7 +122,7 @@ public class AntTask extends Task
{ {
com.webcodepro.applecommander.ui.ac.setDiskName(_imageName, _volName); com.webcodepro.applecommander.ui.ac.setDiskName(_imageName, _volName);
} }
catch (IOException io) catch (IOException|DiskException io)
{ {
if (_failonerror) if (_failonerror)
throw new BuildException(io); throw new BuildException(io);
@ -138,7 +139,7 @@ public class AntTask extends Task
else // Assume unlock else // Assume unlock
com.webcodepro.applecommander.ui.ac.setFileLocked(_imageName, _fileName, false); com.webcodepro.applecommander.ui.ac.setFileLocked(_imageName, _fileName, false);
} }
catch (IOException io) catch (IOException|DiskException io)
{ {
if (_failonerror) if (_failonerror)
throw new BuildException(io); throw new BuildException(io);
@ -220,7 +221,7 @@ public class AntTask extends Task
{ {
com.webcodepro.applecommander.ui.ac.getFiles(_imageName, _outputPath); com.webcodepro.applecommander.ui.ac.getFiles(_imageName, _outputPath);
} }
catch (IOException io) catch (IOException|DiskException io)
{ {
if (_failonerror) if (_failonerror)
throw new BuildException(io); throw new BuildException(io);

View File

@ -34,7 +34,7 @@ import java.util.List;
import com.webcodepro.applecommander.storage.DirectoryEntry; import com.webcodepro.applecommander.storage.DirectoryEntry;
import com.webcodepro.applecommander.storage.Disk; import com.webcodepro.applecommander.storage.Disk;
import com.webcodepro.applecommander.storage.DiskFullException; import com.webcodepro.applecommander.storage.DiskException;
import com.webcodepro.applecommander.storage.FileEntry; import com.webcodepro.applecommander.storage.FileEntry;
import com.webcodepro.applecommander.storage.FileFilter; import com.webcodepro.applecommander.storage.FileFilter;
import com.webcodepro.applecommander.storage.FormattedDisk; import com.webcodepro.applecommander.storage.FormattedDisk;
@ -85,6 +85,9 @@ import com.webcodepro.applecommander.util.TextBundle;
* </pre> * </pre>
* *
* @author John B. Matthews * @author John B. Matthews
*
* Changed at: Dec 1, 2017
* @author Lisias Toledo
*/ */
public class ac { public class ac {
private static TextBundle textBundle = UiBundle.getInstance(); private static TextBundle textBundle = UiBundle.getInstance();
@ -154,7 +157,7 @@ public class ac {
* Put fileName from the local filesytem into the file named fileOnImageName on the disk named imageName; * Put fileName from the local filesytem into the file named fileOnImageName on the disk named imageName;
* Note: only volume level supported; input size unlimited. * Note: only volume level supported; input size unlimited.
*/ */
public static void putFile(String fileName, String imageName, String fileOnImageName, String fileType, String address) throws IOException, DiskFullException { public static void putFile(String fileName, String imageName, String fileOnImageName, String fileType, String address) throws IOException, DiskException {
Name name = new Name(fileOnImageName); Name name = new Name(fileOnImageName);
File file = new File(fileName); File file = new File(fileName);
if (!file.canRead()) if (!file.canRead())
@ -188,7 +191,7 @@ public class ac {
* Note: only volume level supported; input size unlimited. * Note: only volume level supported; input size unlimited.
*/ */
static void putFile(String imageName, Name name, String fileType, static void putFile(String imageName, Name name, String fileType,
String address) throws IOException, DiskFullException { String address) throws IOException, DiskException {
ByteArrayOutputStream buf = new ByteArrayOutputStream(); ByteArrayOutputStream buf = new ByteArrayOutputStream();
byte[] inb = new byte[1024]; byte[] inb = new byte[1024];
@ -225,7 +228,7 @@ public class ac {
* Assume a cc65 style four-byte header with start address in bytes 0-1. * Assume a cc65 style four-byte header with start address in bytes 0-1.
*/ */
public static void putCC65(String fileName, String imageName, String fileOnImageName, String fileType) public static void putCC65(String fileName, String imageName, String fileOnImageName, String fileType)
throws IOException, DiskFullException { throws IOException, DiskException {
byte[] header = new byte[4]; byte[] header = new byte[4];
if (System.in.read(header, 0, 4) == 4) { if (System.in.read(header, 0, 4) == 4) {
@ -239,7 +242,7 @@ public class ac {
* Assume a cc65 style four-byte header with start address in bytes 0-1. * Assume a cc65 style four-byte header with start address in bytes 0-1.
*/ */
static void putCC65(String imageName, Name name, String fileType) static void putCC65(String imageName, Name name, String fileType)
throws IOException, DiskFullException { throws IOException, DiskException {
byte[] header = new byte[4]; byte[] header = new byte[4];
if (System.in.read(header, 0, 4) == 4) { if (System.in.read(header, 0, 4) == 4) {
@ -253,7 +256,7 @@ public class ac {
* This would only make sense for a ProDOS-formatted disk. * This would only make sense for a ProDOS-formatted disk.
*/ */
static void putGEOS(String imageName) static void putGEOS(String imageName)
throws IOException, DiskFullException { throws IOException, DiskException {
putFile(imageName, new Name("GEOS-Should Be ProDOS"), "GEO", "0"); //$NON-NLS-2$ $NON-NLS-3$ putFile(imageName, new Name("GEOS-Should Be ProDOS"), "GEO", "0"); //$NON-NLS-2$ $NON-NLS-3$
} }
@ -261,7 +264,7 @@ public class ac {
* Delete the file named fileName from the disk named imageName. * Delete the file named fileName from the disk named imageName.
*/ */
static void deleteFile(String imageName, String fileName) static void deleteFile(String imageName, String fileName)
throws IOException { throws IOException, DiskException {
Disk disk = new Disk(imageName); Disk disk = new Disk(imageName);
Name name = new Name(fileName); Name name = new Name(fileName);
if (!disk.isSDK() && !disk.isDC42()) { if (!disk.isSDK() && !disk.isDC42()) {
@ -287,7 +290,7 @@ public class ac {
* filtered according to its type and sent to &lt;stdout>. * filtered according to its type and sent to &lt;stdout>.
*/ */
static void getFile(String imageName, String fileName, boolean filter, PrintStream out) static void getFile(String imageName, String fileName, boolean filter, PrintStream out)
throws IOException { throws IOException, DiskException {
Disk disk = new Disk(imageName); Disk disk = new Disk(imageName);
Name name = new Name(fileName); Name name = new Name(fileName);
FormattedDisk[] formattedDisks = disk.getFormattedDisks(); FormattedDisk[] formattedDisks = disk.getFormattedDisks();
@ -317,7 +320,7 @@ public class ac {
/** /**
* Extract all files in the image according to their respective filetype. * Extract all files in the image according to their respective filetype.
*/ */
static void getFiles(String imageName, String directory) throws IOException { static void getFiles(String imageName, String directory) throws IOException, DiskException {
Disk disk = new Disk(imageName); Disk disk = new Disk(imageName);
if ((directory != null) && (directory.length() > 0)) { if ((directory != null) && (directory.length() > 0)) {
// Add a final directory separator if the user didn't supply one // Add a final directory separator if the user didn't supply one
@ -327,16 +330,16 @@ public class ac {
directory = "."+File.separator; directory = "."+File.separator;
} }
FormattedDisk[] formattedDisks = disk.getFormattedDisks(); FormattedDisk[] formattedDisks = disk.getFormattedDisks();
for (int i = 0; i < formattedDisks.length; i++) { for (int i = 0; i < formattedDisks.length; i++) {
FormattedDisk formattedDisk = formattedDisks[i]; FormattedDisk formattedDisk = formattedDisks[i];
writeFiles(formattedDisk.getFiles(), directory); writeFiles(formattedDisk.getFiles(), directory);
} }
} }
/** /**
* Recursive routine to write directory and file entries. * Recursive routine to write directory and file entries.
*/ */
static void writeFiles(List files, String directory) throws IOException { static void writeFiles(List files, String directory) throws IOException, DiskException {
Iterator it = files.iterator(); Iterator it = files.iterator();
while (it.hasNext()) { while (it.hasNext()) {
FileEntry entry = (FileEntry) it.next(); FileEntry entry = (FileEntry) it.next();
@ -352,7 +355,7 @@ public class ac {
OutputStream output = new FileOutputStream(file); OutputStream output = new FileOutputStream(file);
output.write(buf, 0, buf.length); output.write(buf, 0, buf.length);
output.close(); output.close();
} else if (entry.isDirectory()) { } else if (entry.isDirectory()) {
writeFiles(((DirectoryEntry) entry).getFiles(),directory+entry.getFilename()+File.separator); writeFiles(((DirectoryEntry) entry).getFiles(),directory+entry.getFilename()+File.separator);
} }
} }
@ -364,7 +367,7 @@ public class ac {
* file with the given filename. * file with the given filename.
* @deprecated * @deprecated
*/ */
static FileEntry getEntry(List files, String fileName) { static FileEntry getEntry(List files, String fileName) throws DiskException {
FileEntry entry = null; FileEntry entry = null;
if (files != null) { if (files != null) {
for (int i = 0; i < files.size(); i++) { for (int i = 0; i < files.size(); i++) {
@ -406,6 +409,8 @@ public class ac {
new Integer(formattedDisk.getUsedSpace()) })); new Integer(formattedDisk.getUsedSpace()) }));
System.out.println(); System.out.println();
} }
} catch (DiskException e) {
throw new IOException(e);
} catch (RuntimeException e) { } catch (RuntimeException e) {
System.out.println(args[d] + ": " + e.getMessage()); //$NON-NLS-1$ System.out.println(args[d] + ": " + e.getMessage()); //$NON-NLS-1$
System.out.println(); System.out.println();
@ -418,7 +423,7 @@ public class ac {
* system with directories (e.g. ProDOS), this really returns the first file * system with directories (e.g. ProDOS), this really returns the first file
* with the given filename. * with the given filename.
*/ */
static void showFiles(List files, String indent, int display) { static void showFiles(List files, String indent, int display) throws DiskException {
for (int i = 0; i < files.size(); i++) { for (int i = 0; i < files.size(); i++) {
FileEntry entry = (FileEntry) files.get(i); FileEntry entry = (FileEntry) files.get(i);
if (!entry.isDeleted()) { if (!entry.isDeleted()) {
@ -440,7 +445,7 @@ public class ac {
/** /**
* Display information about each disk in args. * Display information about each disk in args.
*/ */
static void getDiskInfo(String[] args) throws IOException { static void getDiskInfo(String[] args) throws IOException, DiskException {
for (int d = 1; d < args.length; d++) { for (int d = 1; d < args.length; d++) {
Disk disk = new Disk(args[d]); Disk disk = new Disk(args[d]);
FormattedDisk[] formattedDisks = disk.getFormattedDisks(); FormattedDisk[] formattedDisks = disk.getFormattedDisks();
@ -460,7 +465,7 @@ public class ac {
* Set the lockState of the file named fileName on the disk named imageName. * Set the lockState of the file named fileName on the disk named imageName.
* Proposed by David Schmidt. * Proposed by David Schmidt.
*/ */
public static void setFileLocked(String imageName, String name, boolean lockState) throws IOException { public static void setFileLocked(String imageName, String name, boolean lockState) throws IOException, DiskException {
setFileLocked(imageName, new Name(name), lockState); setFileLocked(imageName, new Name(name), lockState);
} }
@ -469,7 +474,7 @@ public class ac {
* Proposed by David Schmidt. * Proposed by David Schmidt.
*/ */
static void setFileLocked(String imageName, Name name, static void setFileLocked(String imageName, Name name,
boolean lockState) throws IOException { boolean lockState) throws IOException, DiskException {
Disk disk = new Disk(imageName); Disk disk = new Disk(imageName);
if (!disk.isSDK() && !disk.isDC42()) { if (!disk.isSDK() && !disk.isDC42()) {
FormattedDisk[] formattedDisks = disk.getFormattedDisks(); FormattedDisk[] formattedDisks = disk.getFormattedDisks();
@ -494,7 +499,7 @@ public class ac {
* Pascal disks; others ignored. Proposed by David Schmidt. * Pascal disks; others ignored. Proposed by David Schmidt.
*/ */
public static void setDiskName(String imageName, String volName) public static void setDiskName(String imageName, String volName)
throws IOException { throws IOException, DiskException {
Disk disk = new Disk(imageName); Disk disk = new Disk(imageName);
if (!disk.isSDK() && !disk.isDC42()) { if (!disk.isSDK() && !disk.isDC42()) {
FormattedDisk[] formattedDisks = disk.getFormattedDisks(); FormattedDisk[] formattedDisks = disk.getFormattedDisks();
@ -601,7 +606,7 @@ public class ac {
this.name = path[path.length - 1]; this.name = path[path.length - 1];
} }
public FileEntry getEntry(FormattedDisk formattedDisk) { public FileEntry getEntry(FormattedDisk formattedDisk) throws DiskException {
List files = formattedDisk.getFiles(); List files = formattedDisk.getFiles();
FileEntry entry = null; FileEntry entry = null;
for (int i = 0; i < path.length - 1; i++) { for (int i = 0; i < path.length - 1; i++) {
@ -624,7 +629,7 @@ public class ac {
return null; return null;
} }
public FileEntry createEntry(FormattedDisk formattedDisk) throws DiskFullException { public FileEntry createEntry(FormattedDisk formattedDisk) throws DiskException {
if (path.length == 1) { if (path.length == 1) {
return formattedDisk.createFile(); return formattedDisk.createFile();
} }

View File

@ -26,6 +26,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
@ -71,6 +72,8 @@ import org.eclipse.swt.widgets.TreeItem;
import com.webcodepro.applecommander.compiler.ApplesoftCompiler; import com.webcodepro.applecommander.compiler.ApplesoftCompiler;
import com.webcodepro.applecommander.storage.DirectoryEntry; import com.webcodepro.applecommander.storage.DirectoryEntry;
import com.webcodepro.applecommander.storage.Disk; import com.webcodepro.applecommander.storage.Disk;
import com.webcodepro.applecommander.storage.DiskCorruptException;
import com.webcodepro.applecommander.storage.DiskException;
import com.webcodepro.applecommander.storage.FileEntry; import com.webcodepro.applecommander.storage.FileEntry;
import com.webcodepro.applecommander.storage.FileEntryComparator; import com.webcodepro.applecommander.storage.FileEntryComparator;
import com.webcodepro.applecommander.storage.FileFilter; import com.webcodepro.applecommander.storage.FileFilter;
@ -114,6 +117,9 @@ import com.webcodepro.applecommander.util.TextBundle;
* <p> * <p>
* Date created: Nov 17, 2002 9:46:53 PM * Date created: Nov 17, 2002 9:46:53 PM
* @author Rob Greene * @author Rob Greene
*
* Changed at: Dec 1, 2017
* @author Lisias Toledo
*/ */
public class DiskExplorerTab { public class DiskExplorerTab {
private static final char CTRL_C = 'C' - '@'; private static final char CTRL_C = 'C' - '@';
@ -224,7 +230,11 @@ public class DiskExplorerTab {
* Single-click handler. * Single-click handler.
*/ */
public void widgetSelected(SelectionEvent event) { public void widgetSelected(SelectionEvent event) {
changeCurrentFormat(getCurrentFormat()); // minor hack try {
changeCurrentFormat(getCurrentFormat()); // minor hack
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
/** /**
* Double-click handler. * Double-click handler.
@ -248,27 +258,35 @@ public class DiskExplorerTab {
diskItem.setText(disks[i].getDiskName()); diskItem.setText(disks[i].getDiskName());
diskItem.setData(disks[i]); diskItem.setData(disks[i]);
directoryTree.setSelection(new TreeItem[] { diskItem }); directoryTree.setSelection(new TreeItem[] { diskItem });
if (disks[i].canHaveDirectories()) { if (disks[i].canHaveDirectories()) {
Iterator files = disks[i].getFiles().iterator(); try {
while (files.hasNext()) { Iterator files = disks[i].getFiles().iterator();
FileEntry entry = (FileEntry) files.next(); while (files.hasNext()) {
if (entry.isDirectory()) { FileEntry entry = (FileEntry) files.next();
TreeItem item = new TreeItem(diskItem, SWT.BORDER); if (entry.isDirectory()) {
item.setText(entry.getFilename()); TreeItem item = new TreeItem(diskItem, SWT.BORDER);
item.setData(entry); item.setText(entry.getFilename());
addDirectoriesToTree(item, (DirectoryEntry)entry); item.setData(entry);
addDirectoriesToTree(item, (DirectoryEntry)entry);
}
} }
} } catch (DiskException e) {
this.diskWindow.handle(e);
}
} }
} }
computeColumnWidths(FormattedDisk.FILE_DISPLAY_STANDARD); computeColumnWidths(FormattedDisk.FILE_DISPLAY_STANDARD);
computeColumnWidths(FormattedDisk.FILE_DISPLAY_NATIVE); computeColumnWidths(FormattedDisk.FILE_DISPLAY_NATIVE);
computeColumnWidths(FormattedDisk.FILE_DISPLAY_DETAIL); computeColumnWidths(FormattedDisk.FILE_DISPLAY_DETAIL);
formatChanged = true; formatChanged = true;
fillFileTable(disks[0].getFiles()); try {
fillFileTable(disks[0].getFiles());
} catch (DiskException e) {
this.diskWindow.handle(e);
}
directoryTree.setSelection(new TreeItem[] { directoryTree.getItems()[0] }); directoryTree.setSelection(new TreeItem[] { directoryTree.getItems()[0] });
} }
/** /**
@ -338,11 +356,15 @@ public class DiskExplorerTab {
item.setImage(imageManager.get(ImageManager.ICON_IMPORT_FILE)); item.setImage(imageManager.get(ImageManager.ICON_IMPORT_FILE));
item.addSelectionListener(new SelectionAdapter() { item.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) { public void widgetSelected(SelectionEvent event) {
importFiles(); try {
importFiles();
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
}); });
item.setEnabled(disks[0].canCreateFile() && disks[0].canWriteFileData()); item.setEnabled(disks[0].canCreateFile() && disks[0].canWriteFileData());
return menu; return menu;
} }
/** /**
@ -389,7 +411,11 @@ public class DiskExplorerTab {
item.setImage(imageManager.get(ImageManager.ICON_VIEW_FILE)); item.setImage(imageManager.get(ImageManager.ICON_VIEW_FILE));
item.addSelectionListener(new SelectionAdapter() { item.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) { public void widgetSelected(SelectionEvent event) {
viewFile(null); try {
viewFile(null);
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
}); });
@ -444,7 +470,11 @@ public class DiskExplorerTab {
item.setText(textBundle.get("ViewAsTextMenuItem")); //$NON-NLS-1$ item.setText(textBundle.get("ViewAsTextMenuItem")); //$NON-NLS-1$
item.addSelectionListener(new SelectionAdapter() { item.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) { public void widgetSelected(SelectionEvent event) {
viewFile(TextFileFilter.class); try {
viewFile(TextFileFilter.class);
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
}); });
@ -452,7 +482,11 @@ public class DiskExplorerTab {
item.setText(textBundle.get("VeiwAsGraphicsMenuItem")); //$NON-NLS-1$ item.setText(textBundle.get("VeiwAsGraphicsMenuItem")); //$NON-NLS-1$
item.addSelectionListener(new SelectionAdapter() { item.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) { public void widgetSelected(SelectionEvent event) {
viewFile(GraphicsFileFilter.class); try {
viewFile(GraphicsFileFilter.class);
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
}); });
@ -879,7 +913,11 @@ public class DiskExplorerTab {
* Double-click handler. * Double-click handler.
*/ */
public void widgetDefaultSelected(SelectionEvent event) { public void widgetDefaultSelected(SelectionEvent event) {
viewFile(null); try {
viewFile(null);
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
}); });
TableColumn column = null; TableColumn column = null;
@ -1101,12 +1139,13 @@ public class DiskExplorerTab {
} }
/** /**
* Start the import wizard and import the selected files. * Start the import wizard and import the selected files.
* @throws DiskException
*/ */
protected void importFiles() { protected void importFiles() throws DiskException {
//FIXME: This code has become really ugly! //FIXME: This code has become really ugly!
TreeItem treeItem = directoryTree.getSelection()[0]; TreeItem treeItem = directoryTree.getSelection()[0];
DirectoryEntry directory = (DirectoryEntry) treeItem.getData(); DirectoryEntry directory = (DirectoryEntry) treeItem.getData();
ImportWizard wizard = new ImportWizard(shell, ImportWizard wizard = new ImportWizard(shell,
imageManager, directory.getFormattedDisk()); imageManager, directory.getFormattedDisk());
wizard.open(); wizard.open();
if (wizard.isWizardCompleted()) { if (wizard.isWizardCompleted()) {
@ -1201,8 +1240,9 @@ public class DiskExplorerTab {
} }
/** /**
* Helper function for building fileTree. * Helper function for building fileTree.
* @throws DiskException
*/ */
protected void addDirectoriesToTree(TreeItem directoryItem, DirectoryEntry directoryEntry) { protected void addDirectoriesToTree(TreeItem directoryItem, DirectoryEntry directoryEntry) throws DiskException {
Iterator files = directoryEntry.getFiles().iterator(); Iterator files = directoryEntry.getFiles().iterator();
while (files.hasNext()) { while (files.hasNext()) {
final FileEntry entry = (FileEntry) files.next(); final FileEntry entry = (FileEntry) files.next();
@ -1228,8 +1268,12 @@ public class DiskExplorerTab {
standardFormatToolItem.setToolTipText(textBundle.get("StandardViewHoverText")); //$NON-NLS-1$ standardFormatToolItem.setToolTipText(textBundle.get("StandardViewHoverText")); //$NON-NLS-1$
standardFormatToolItem.setSelection(true); standardFormatToolItem.setSelection(true);
standardFormatToolItem.addSelectionListener(new SelectionAdapter () { standardFormatToolItem.addSelectionListener(new SelectionAdapter () {
public void widgetSelected(SelectionEvent e) { public void widgetSelected(SelectionEvent event) {
changeCurrentFormat(FormattedDisk.FILE_DISPLAY_STANDARD); try {
changeCurrentFormat(FormattedDisk.FILE_DISPLAY_STANDARD);
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
}); });
nativeFormatToolItem = new ToolItem(toolBar, SWT.RADIO); nativeFormatToolItem = new ToolItem(toolBar, SWT.RADIO);
@ -1237,8 +1281,12 @@ public class DiskExplorerTab {
nativeFormatToolItem.setText(textBundle.get("NativeViewToolItem")); //$NON-NLS-1$ nativeFormatToolItem.setText(textBundle.get("NativeViewToolItem")); //$NON-NLS-1$
nativeFormatToolItem.setToolTipText(textBundle.get("NativeViewHoverText")); //$NON-NLS-1$ nativeFormatToolItem.setToolTipText(textBundle.get("NativeViewHoverText")); //$NON-NLS-1$
nativeFormatToolItem.addSelectionListener(new SelectionAdapter () { nativeFormatToolItem.addSelectionListener(new SelectionAdapter () {
public void widgetSelected(SelectionEvent e) { public void widgetSelected(SelectionEvent event) {
changeCurrentFormat(FormattedDisk.FILE_DISPLAY_NATIVE); try {
changeCurrentFormat(FormattedDisk.FILE_DISPLAY_NATIVE);
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
}); });
detailFormatToolItem = new ToolItem(toolBar, SWT.RADIO); detailFormatToolItem = new ToolItem(toolBar, SWT.RADIO);
@ -1246,13 +1294,17 @@ public class DiskExplorerTab {
detailFormatToolItem.setText(textBundle.get("DetailViewToolItem")); //$NON-NLS-1$ detailFormatToolItem.setText(textBundle.get("DetailViewToolItem")); //$NON-NLS-1$
detailFormatToolItem.setToolTipText(textBundle.get("DetailViewHoverText")); //$NON-NLS-1$ detailFormatToolItem.setToolTipText(textBundle.get("DetailViewHoverText")); //$NON-NLS-1$
detailFormatToolItem.addSelectionListener(new SelectionAdapter () { detailFormatToolItem.addSelectionListener(new SelectionAdapter () {
public void widgetSelected(SelectionEvent e) { public void widgetSelected(SelectionEvent event) {
changeCurrentFormat(FormattedDisk.FILE_DISPLAY_DETAIL); try {
changeCurrentFormat(FormattedDisk.FILE_DISPLAY_DETAIL);
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
}); });
new ToolItem(toolBar, SWT.SEPARATOR); new ToolItem(toolBar, SWT.SEPARATOR);
showDeletedFilesToolItem = new ToolItem(toolBar, SWT.CHECK); showDeletedFilesToolItem = new ToolItem(toolBar, SWT.CHECK);
showDeletedFilesToolItem.setImage(imageManager.get(ImageManager.ICON_SHOW_DELETED_FILES)); showDeletedFilesToolItem.setImage(imageManager.get(ImageManager.ICON_SHOW_DELETED_FILES));
showDeletedFilesToolItem.setText(textBundle.get("ShowDeletedFilesToolItem")); //$NON-NLS-1$ showDeletedFilesToolItem.setText(textBundle.get("ShowDeletedFilesToolItem")); //$NON-NLS-1$
@ -1274,11 +1326,15 @@ public class DiskExplorerTab {
importToolItem.setToolTipText(textBundle.get("ImportWizardHoverText")); //$NON-NLS-1$ importToolItem.setToolTipText(textBundle.get("ImportWizardHoverText")); //$NON-NLS-1$
importToolItem.setEnabled(disks[0].canCreateFile() && disks[0].canWriteFileData()); importToolItem.setEnabled(disks[0].canCreateFile() && disks[0].canWriteFileData());
importToolItem.addSelectionListener(new SelectionAdapter () { importToolItem.addSelectionListener(new SelectionAdapter () {
public void widgetSelected(SelectionEvent e) { public void widgetSelected(SelectionEvent event) {
importFiles(); try {
importFiles();
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
}); });
exportToolItem = new ToolItem(toolBar, SWT.DROP_DOWN); exportToolItem = new ToolItem(toolBar, SWT.DROP_DOWN);
exportToolItem.setImage(imageManager.get(ImageManager.ICON_EXPORT_FILE)); exportToolItem.setImage(imageManager.get(ImageManager.ICON_EXPORT_FILE));
exportToolItem.setText(textBundle.get("ExportWizardToolItem")); //$NON-NLS-1$ exportToolItem.setText(textBundle.get("ExportWizardToolItem")); //$NON-NLS-1$
@ -1315,8 +1371,12 @@ public class DiskExplorerTab {
viewFileItem.setEnabled(false); viewFileItem.setEnabled(false);
viewFileItem.addSelectionListener(new SelectionAdapter () { viewFileItem.addSelectionListener(new SelectionAdapter () {
public void widgetSelected(SelectionEvent event) { public void widgetSelected(SelectionEvent event) {
if (event.detail != SWT.ARROW) { if (event.detail != SWT.ARROW) {
viewFile(null); try {
viewFile(null);
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
} }
}); });
@ -1402,8 +1462,9 @@ public class DiskExplorerTab {
} }
/** /**
* Change the current format and refresh the display. * Change the current format and refresh the display.
* @throws DiskException
*/ */
protected void changeCurrentFormat(int newFormat) { protected void changeCurrentFormat(int newFormat) throws DiskException {
TreeItem selection = directoryTree.getSelection()[0]; TreeItem selection = directoryTree.getSelection()[0];
Object data = selection.getData(); Object data = selection.getData();
DirectoryEntry directory = (DirectoryEntry) data; DirectoryEntry directory = (DirectoryEntry) data;
@ -1522,8 +1583,9 @@ public class DiskExplorerTab {
} }
/** /**
* Open up the view file window for the currently selected file. * Open up the view file window for the currently selected file.
* @throws DiskException
*/ */
protected void viewFile(Class fileFilterClass) { protected void viewFile(Class fileFilterClass) throws DiskException {
FileEntry fileEntry = getSelectedFileEntry(); FileEntry fileEntry = getSelectedFileEntry();
if (fileEntry.isDeleted()) { if (fileEntry.isDeleted()) {
SwtUtil.showErrorDialog(shell, textBundle.get("DeleteFileErrorTitle"), //$NON-NLS-1$ SwtUtil.showErrorDialog(shell, textBundle.get("DeleteFileErrorTitle"), //$NON-NLS-1$
@ -1584,24 +1646,28 @@ public class DiskExplorerTab {
public void handleEvent(Event event) { public void handleEvent(Event event) {
FileEntry fileEntry = getSelectedFileEntry(); FileEntry fileEntry = getSelectedFileEntry();
if (fileEntry != null && event.type == SWT.KeyUp && (event.stateMask & SWT.CTRL) != 0) { if (fileEntry != null && event.type == SWT.KeyUp && (event.stateMask & SWT.CTRL) != 0) {
switch (event.character) { try {
case CTRL_C: // Compile Wizard switch (event.character) {
if (getCompileToolItem().isEnabled()) { case CTRL_C: // Compile Wizard
compileFileWizard(); if (getCompileToolItem().isEnabled()) {
} compileFileWizard();
break; }
case CTRL_D: // Delete file break;
if (getDeleteToolItem().isEnabled()) { case CTRL_D: // Delete file
deleteFile(); if (getDeleteToolItem().isEnabled()) {
} deleteFile();
break; }
case CTRL_E: // Export Wizard break;
exportFileWizard(); case CTRL_E: // Export Wizard
break; exportFileWizard();
case CTRL_V: // View file break;
viewFile(null); case CTRL_V: // View file
break; viewFile(null);
} break;
}
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
} }
}; };
@ -1625,39 +1691,46 @@ public class DiskExplorerTab {
break; break;
} }
} else { } else {
switch (event.character) { try {
case CTRL_I: // Import Wizard switch (event.character) {
importFiles(); case CTRL_I: // Import Wizard
break; importFiles();
case CTRL_P: // Print... break;
print(); case CTRL_P: // Print...
break; print();
case CTRL_S: // Save break;
if (getSaveToolItem().isEnabled()) { case CTRL_S: // Save
save(); if (getSaveToolItem().isEnabled()) {
} save();
break; }
} break;
}
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
} else { // No CTRL key } else { // No CTRL key
if ((event.stateMask & SWT.ALT) != SWT.ALT) { // Ignore ALT key combinations like alt-F4! if ((event.stateMask & SWT.ALT) != SWT.ALT) // Ignore ALT key combinations like alt-F4!
switch (event.keyCode) { try {
case SWT.F2: // Standard file display switch (event.keyCode) {
changeCurrentFormat(FormattedDisk.FILE_DISPLAY_STANDARD); case SWT.F2: // Standard file display
break; changeCurrentFormat(FormattedDisk.FILE_DISPLAY_STANDARD);
case SWT.F3: // Native file display break;
changeCurrentFormat(FormattedDisk.FILE_DISPLAY_NATIVE); case SWT.F3: // Native file display
break; changeCurrentFormat(FormattedDisk.FILE_DISPLAY_NATIVE);
case SWT.F4: // Detail file display break;
changeCurrentFormat(FormattedDisk.FILE_DISPLAY_DETAIL); case SWT.F4: // Detail file display
break; changeCurrentFormat(FormattedDisk.FILE_DISPLAY_DETAIL);
case SWT.F5: // Show deleted files break;
setShowDeletedFiles(!getShowDeletedFilesToolItem().getSelection()); case SWT.F5: // Show deleted files
getShowDeletedFilesToolItem().setSelection(isShowDeletedFiles()); setShowDeletedFiles(!getShowDeletedFilesToolItem().getSelection());
fillFileTable(getCurrentFileList()); getShowDeletedFilesToolItem().setSelection(isShowDeletedFiles());
break; fillFileTable(getCurrentFileList());
break;
} }
} } catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
} }
} }
@ -1728,7 +1801,11 @@ public class DiskExplorerTab {
printFileHeaders(); printFileHeaders();
gc.setFont(normalFont); gc.setFont(normalFont);
println(disk.getDiskName()); println(disk.getDiskName());
printFiles(disk, 1); try {
printFiles(disk, 1);
} catch (DiskException e) {
DiskExplorerTab.this.diskWindow.handle(e);
}
} }
if (y != clientArea.y) { // partial page if (y != clientArea.y) { // partial page
printFooter(); printFooter();
@ -1811,7 +1888,7 @@ public class DiskExplorerTab {
clientArea.y + clientArea.height + dpiY - point.y); clientArea.y + clientArea.height + dpiY - point.y);
page++; page++;
} }
protected void printFiles(DirectoryEntry directory, int level) { protected void printFiles(DirectoryEntry directory, int level) throws DiskException {
Iterator iterator = directory.getFiles().iterator(); Iterator iterator = directory.getFiles().iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
FileEntry fileEntry = (FileEntry) iterator.next(); FileEntry fileEntry = (FileEntry) iterator.next();
@ -2027,5 +2104,5 @@ public class DiskExplorerTab {
protected ToolItem getShowDeletedFilesToolItem() { protected ToolItem getShowDeletedFilesToolItem() {
return showDeletedFilesToolItem; return showDeletedFilesToolItem;
} }
} }

View File

@ -24,11 +24,15 @@ import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Shell;
import com.webcodepro.applecommander.storage.DiskCorruptException;
import com.webcodepro.applecommander.storage.DiskException;
import com.webcodepro.applecommander.storage.FormattedDisk; import com.webcodepro.applecommander.storage.FormattedDisk;
import com.webcodepro.applecommander.ui.UiBundle; import com.webcodepro.applecommander.ui.UiBundle;
import com.webcodepro.applecommander.ui.swt.util.ImageManager; import com.webcodepro.applecommander.ui.swt.util.ImageManager;
import com.webcodepro.applecommander.util.TextBundle;
/** /**
* Displays disk information on the screen. * Displays disk information on the screen.
@ -46,6 +50,8 @@ public class DiskWindow {
private DiskInfoTab diskInfoTab; private DiskInfoTab diskInfoTab;
private DiskMapTab[] diskMapTabs; private DiskMapTab[] diskMapTabs;
private TextBundle textBundle = UiBundle.getInstance();
/** /**
* Construct the disk window. * Construct the disk window.
*/ */
@ -84,6 +90,58 @@ public class DiskWindow {
shell.open(); shell.open();
} }
/**
* Warns user about a Disk Corrupt problem
*
* @param e
*/
protected void handle(final DiskCorruptException e) {
Shell finalShell = shell;
MessageBox box = new MessageBox(finalShell, SWT.ICON_ERROR | SWT.OK);
box.setText(textBundle.get("SwtAppleCommander." + e.kind + ".Title")); //$NON-NLS-1$
box.setMessage(
textBundle.format("SwtAppleCommander.DiskCorruptException.Message", //$NON-NLS-1$
e.imagepath
));
box.open();
}
/**
* Warns user about a Generic Disk Error problem
*
* @param e
*/
protected void handle(final DiskException e) {
if (e instanceof DiskCorruptException) {
this.handle((DiskCorruptException) e);
return;
}
final MessageBox box = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK | SWT.MODELESS);
box.setText(textBundle.get("SwtAppleCommander.DiskException.Title")); //$NON-NLS-1$
box.setMessage(
textBundle.format("SwtAppleCommander.DiskException.Message", //$NON-NLS-1$
new Object[]{e.imagepath, e.toString()}
));
box.open();
}
/**
* Warns user about an Application Error problem
*
* @param e
*/
public void handle(final Exception e) {
final TextBundle textBundle = UiBundle.getInstance();
Shell finalShell = shell;
MessageBox box = new MessageBox(finalShell, SWT.ICON_ERROR | SWT.OK);
box.setText(textBundle.get("SwtAppleCommander.UnexpectedErrorTitle")); //$NON-NLS-1$
box.setMessage(
textBundle.get("SwtAppleCommander.UnexpectedErrorMessage" //$NON-NLS-1$
));
box.open();
e.printStackTrace();
}
/** /**
* Set the standard AppleCommander disk window title. * Set the standard AppleCommander disk window title.
* This is referenced in DiskWindow as well as DiskExplorerTab. * This is referenced in DiskWindow as well as DiskExplorerTab.

View File

@ -39,6 +39,7 @@ import org.eclipse.swt.widgets.ToolItem;
import com.webcodepro.applecommander.storage.Disk; import com.webcodepro.applecommander.storage.Disk;
import com.webcodepro.applecommander.storage.FormattedDisk; import com.webcodepro.applecommander.storage.FormattedDisk;
import com.webcodepro.applecommander.storage.Disk.FilenameFilter; import com.webcodepro.applecommander.storage.Disk.FilenameFilter;
import com.webcodepro.applecommander.storage.DiskUnrecognizedException;
import com.webcodepro.applecommander.ui.AppleCommander; import com.webcodepro.applecommander.ui.AppleCommander;
import com.webcodepro.applecommander.ui.UiBundle; import com.webcodepro.applecommander.ui.UiBundle;
import com.webcodepro.applecommander.ui.UserPreferences; import com.webcodepro.applecommander.ui.UserPreferences;
@ -171,19 +172,31 @@ public class SwtAppleCommander implements Listener {
try { try {
Disk disk = new Disk(fullpath); Disk disk = new Disk(fullpath);
FormattedDisk[] formattedDisks = disk.getFormattedDisks(); FormattedDisk[] formattedDisks = disk.getFormattedDisks();
if (formattedDisks != null) { DiskWindow window = new DiskWindow(shell, formattedDisks, imageManager);
DiskWindow window = new DiskWindow(shell, formattedDisks, imageManager); window.open();
window.open(); } catch (DiskUnrecognizedException e) {
} else { showUnrecognizedDiskFormatMessage(fullpath);
showUnrecognizedDiskFormatMessage(fullpath);
}
} catch (Exception ignored) { } catch (Exception ignored) {
ignored.printStackTrace(); ignored.printStackTrace();
showUnrecognizedDiskFormatMessage(fullpath); showUnexpectedErrorMessage(fullpath);
} }
} }
} }
/**
* Displays the unrecognized disk format message.
* @param fullpath
*/
protected void showUnexpectedErrorMessage(String fullpath) {
Shell finalShell = shell;
MessageBox box = new MessageBox(finalShell, SWT.ICON_ERROR | SWT.OK);
box.setText(textBundle.get("SwtAppleCommander.UnexpectedErrorTitle")); //$NON-NLS-1$
box.setMessage(
textBundle.format("SwtAppleCommander.UnexpectedErrorMessage", //$NON-NLS-1$
fullpath));
box.open();
}
/** /**
* Displays the unrecognized disk format message. * Displays the unrecognized disk format message.
* @param fullpath * @param fullpath

View File

@ -270,13 +270,19 @@ GraphicsFilterAdapter.BadImageMessage=Unexpected graphic file encountered\!
# SwtAppleCommander # SwtAppleCommander
SwtAppleCommander.AppleCommander=AppleCommander SwtAppleCommander.AppleCommander=AppleCommander
SwtAppleCommander.UnrecognizedFormatTitle=Unrecognized Disk Format SwtAppleCommander.UnrecognizedFormatTitle=Unrecognized Disk Format
SwtAppleCommander.UnrecognizedFormatMessage=Unable to load "{0}".\n\nAppleCommander did not recognize the format\nof the disk. Either this is a new format\nor a protected disk.\n\nSorry\! SwtAppleCommander.UnrecognizedFormatMessage=Unable to load "{0}".\n\nAppleCommander did not recognize the format of the disk. Either this is a new format or a protected disk.\n\nSorry\!
SwtAppleCommander.OpenDiskImageTooltip=Open a disk image (Ctrl+O) SwtAppleCommander.OpenDiskImageTooltip=Open a disk image (Ctrl+O)
SwtAppleCommander.CreateDiskImageTooltip=Create a disk image (Ctrl+C) SwtAppleCommander.CreateDiskImageTooltip=Create a disk image (Ctrl+C)
SwtAppleCommander.CompareDiskImageTooltip=Compare two disk images (Ctrl+E) SwtAppleCommander.CompareDiskImageTooltip=Compare two disk images (Ctrl+E)
SwtAppleCommander.AboutTooltip=About AppleCommander (Ctrl+A) SwtAppleCommander.AboutTooltip=About AppleCommander (Ctrl+A)
SwtAppleCommander.AboutTitle=About AppleCommander SwtAppleCommander.AboutTitle=About AppleCommander
SwtAppleCommander.AboutMessage=AppleCommander\nVersion {0}\n{1}\n\nAppleCommander was created for the express\npurpose of assisting those-who-remember.\n\nI wish you many hours of vintage pleasure\!\n-Rob SwtAppleCommander.AboutMessage=AppleCommander\nVersion {0}\n{1}\n\nAppleCommander was created for the express\npurpose of assisting those-who-remember.\n\nI wish you many hours of vintage pleasure\!\n-Rob
SwtAppleCommander.UnexpectedErrorTitle=Application Error
SwtAppleCommander.UnexpectedErrorMessage=Unfortunately "{0}" triggered an unexpected application error.\n\nPlease report this to the developers.\n\nWe are terribly sorry for the inconvenience\!
SwtAppleCommander.DiskCorruptException.RecursiveDirectoryStructure.Title=Recursive Directory structure detected.
SwtAppleCommander.DiskCorruptException.Message=Unfortunately "{0}" is corrupted.\n\nYou can't use this disk safely. Please use a First Aid tool to recover your data.\n\nSorry\!
SwtAppleCommander.DiskException.Title="Disk Generic Error"
SwtAppleCommander.DiskException.Message=Unfortunately "{0}" has an unrecognizable but yet fatal error, internal code "{1}".\n\nYou can't use this disk safely.\n\nSorry\!
# SwingAppleCommander # SwingAppleCommander
SwingAppleCommander.MenuFile=File SwingAppleCommander.MenuFile=File