jace/src/main/java/jace/hardware/massStorage/FileNode.java

200 lines
6.6 KiB
Java

/*
* Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package jace.hardware.massStorage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* Representation of a prodos file with a known file type and having a known
* size (either seedling, sapling or tree)
*
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
*/
public class FileNode extends DiskNode {
public enum FileType {
UNKNOWN(0x00, 0x0000),
ADB(0x019, 0x0000),
AWP(0x01a, 0x0000),
ASP(0x01b, 0x0000),
BAD(0x01, 0x0000),
BIN(0x06, 0x0300),
CLASS(0xED, 0x0000),
BAS(0xfc, 0x0801),
CMD(0x0f0, 0x0000),
INT(0xfa, 0x0801),
IVR(0xfb, 0x0000),
PAS(0xef, 0x0000),
REL(0x0Fe, 0x0000),
SHK(0x0e0, 0x08002),
SDK(0x0e0, 0x08002),
SYS(0x0ff, 0x02000),
SYSTEM(0x0ff, 0x02000),
TXT(0x04, 0x0000),
U01(0x0f1, 0x0000),
U02(0x0f2, 0x0000),
U03(0x0f3, 0x0000),
U04(0x0f4, 0x0000),
U05(0x0f5, 0x0000),
U06(0x0f6, 0x0000),
U07(0x0f7, 0x0000),
U08(0x0f8, 0x0000),
VAR(0x0FD, 0x0000);
public int code = 0;
public int defaultLoadAddress = 0;
FileType(int code, int addr) {
this.code = code;
this.defaultLoadAddress = addr;
}
}
public int fileType = 0x00;
public int loadAddress = 0x00;
public static int SEEDLING_MAX_SIZE = ProdosVirtualDisk.BLOCK_SIZE;
public static int SAPLING_MAX_SIZE = ProdosVirtualDisk.BLOCK_SIZE * 128;
@Override
public EntryType getType() {
long fileSize = getPhysicalFile().length();
if (fileSize <= SEEDLING_MAX_SIZE) {
setType(EntryType.SEEDLING);
return EntryType.SEEDLING;
} else if (fileSize <= SAPLING_MAX_SIZE) {
setType(EntryType.SAPLING);
return EntryType.SAPLING;
}
setType(EntryType.TREE);
return EntryType.TREE;
}
@Override
public void setName(String name) {
String[] parts = name.split("\\.");
FileType t = null;
int offset = 0;
if (parts.length > 1) {
String extension = parts[parts.length - 1].toUpperCase();
String[] extParts = extension.split("#");
if (extParts.length == 2) {
offset = Integer.parseInt(extParts[1], 16);
extension = extParts[0];
}
try {
t = FileType.valueOf(extension);
} catch (IllegalArgumentException ex) {
System.out.println("Not sure what extension " + extension + " is!");
}
name = "";
for (int i = 0; i < parts.length - 1; i++) {
name += (i > 0 ? "." + parts[i] : parts[i]);
}
if (extParts[extParts.length - 1].equals("SYSTEM")) {
name += ".SYSTEM";
}
}
if (t == null) {
t = FileType.UNKNOWN;
}
if (offset == 0) {
offset = t.defaultLoadAddress;
}
fileType = t.code;
loadAddress = offset;
// Pass usable name (stripped of file extension and other type info) as name
super.setName(name);
}
public FileNode(ProdosVirtualDisk ownerFilesystem, File file) throws IOException {
setOwnerFilesystem(ownerFilesystem);
setPhysicalFile(file);
}
@Override
public void doDeallocate() {
}
@Override
public void doAllocate() throws IOException {
int dataBlocks = (int) ((getPhysicalFile().length() / ProdosVirtualDisk.BLOCK_SIZE) + 1);
int treeBlocks = 0;
if (dataBlocks > 1 && dataBlocks < 257) {
treeBlocks = 1;
} else {
treeBlocks = 1 + (dataBlocks / 256);
}
for (int i = 1; i < dataBlocks + treeBlocks; i++) {
new SubNode(i, this);
}
}
@Override
public void doRefresh() {
}
@Override
public void readBlock(int block, byte[] buffer) throws IOException {
// System.out.println("Read block "+block+" of file "+getName());
switch (this.getType()) {
case SEEDLING:
readFile(buffer, 0);
break;
case SAPLING:
if (block > 0) {
readFile(buffer, (block - 1));
} else {
// Generate seedling index block
generateIndex(buffer, 0, 256);
}
break;
case TREE:
int dataBlocks = (int) ((getPhysicalFile().length() / ProdosVirtualDisk.BLOCK_SIZE) + 1);
int treeBlocks = (dataBlocks / 256);
if (block == 0) {
generateIndex(buffer, 0, treeBlocks);
} else if (block < treeBlocks) {
int start = treeBlocks + (block - 1 * 256);
int end = Math.min(start + 256, treeBlocks);
generateIndex(buffer, treeBlocks, end);
} else {
readFile(buffer, (block - treeBlocks));
}
break;
}
}
private void readFile(byte[] buffer, int start) throws IOException {
FileInputStream f = new FileInputStream(physicalFile);
f.skip(start * ProdosVirtualDisk.BLOCK_SIZE);
f.read(buffer, 0, ProdosVirtualDisk.BLOCK_SIZE);
f.close();
}
private void generateIndex(byte[] buffer, int indexStart, int indexLimit) {
int pos = 0;
for (int i = indexStart; pos < 256 && i < indexLimit && i < additionalNodes.size(); i++, pos++) {
buffer[pos] = (byte) (additionalNodes.get(i).baseBlock & 0x0ff);
buffer[pos + 256] = (byte) ((additionalNodes.get(i).baseBlock >> 8) & 0x0ff);
}
}
}