dmolony-DiskBrowser/src/com/bytezone/diskbrowser/prodos/write/FileWriter.java

225 lines
7.1 KiB
Java
Raw Normal View History

2021-05-03 20:12:44 +00:00
package com.bytezone.diskbrowser.prodos.write;
import static com.bytezone.diskbrowser.prodos.ProdosConstants.BLOCK_SIZE;
import static com.bytezone.diskbrowser.prodos.ProdosConstants.SAPLING;
import static com.bytezone.diskbrowser.prodos.ProdosConstants.SEEDLING;
import static com.bytezone.diskbrowser.prodos.ProdosConstants.TREE;
2022-08-10 05:10:16 +00:00
// Assumptions:
// - file does not already exist
2022-08-10 08:06:43 +00:00
// - disk is not interleaved
// - blocks are 512 contiguous bytes
2021-05-03 20:12:44 +00:00
// -----------------------------------------------------------------------------------//
public class FileWriter
// -----------------------------------------------------------------------------------//
{
private final ProdosDisk disk;
private IndexBlock indexBlock = null;
private MasterIndexBlock masterIndexBlock = null;
byte storageType;
int keyPointer;
int blocksUsed;
int eof;
// ---------------------------------------------------------------------------------//
2021-05-03 21:24:08 +00:00
FileWriter (ProdosDisk disk)
2021-05-03 20:12:44 +00:00
// ---------------------------------------------------------------------------------//
{
this.disk = disk;
}
// ---------------------------------------------------------------------------------//
void writeFile (byte[] dataBuffer, int eof) throws DiskFullException
// ---------------------------------------------------------------------------------//
{
2021-05-05 03:10:33 +00:00
this.eof = Math.min (eof, dataBuffer.length);
2021-05-03 20:12:44 +00:00
int dataPtr = 0;
2021-05-05 03:10:33 +00:00
int remaining = this.eof;
2021-05-03 20:12:44 +00:00
2021-05-05 03:10:33 +00:00
while (dataPtr < this.eof)
2021-05-03 20:12:44 +00:00
{
2022-08-10 05:08:10 +00:00
int actualBlockNo = register (dataPtr / BLOCK_SIZE);
2021-05-03 20:12:44 +00:00
int bufferPtr = actualBlockNo * BLOCK_SIZE;
2021-05-05 03:10:33 +00:00
int transfer = Math.min (remaining, BLOCK_SIZE);
2021-05-03 20:12:44 +00:00
2021-05-05 03:10:33 +00:00
System.arraycopy (dataBuffer, dataPtr, disk.getBuffer (), bufferPtr, transfer);
2021-05-03 20:12:44 +00:00
2021-05-05 03:10:33 +00:00
dataPtr += transfer;
remaining -= transfer;
2021-05-03 20:12:44 +00:00
}
writeIndices ();
}
// ---------------------------------------------------------------------------------//
2022-08-10 05:08:10 +00:00
void writeRecord (int recordNo, byte[] dataBuffer, int recordLength) throws DiskFullException
2021-05-03 20:12:44 +00:00
// ---------------------------------------------------------------------------------//
{
assert recordLength > 0;
int destPtr = recordLength * recordNo;
int remaining = Math.min (recordLength, dataBuffer.length);
int max = destPtr + remaining;
int dataPtr = 0;
if (eof < max)
eof = max;
while (destPtr < max)
{
int logicalBlockNo = destPtr / BLOCK_SIZE;
int blockOffset = destPtr % BLOCK_SIZE;
int tfr = Math.min (BLOCK_SIZE - blockOffset, remaining);
int actualBlockNo = getActualBlockNo (logicalBlockNo);
int bufferPtr = actualBlockNo * BLOCK_SIZE + blockOffset;
2021-05-04 06:31:11 +00:00
System.arraycopy (dataBuffer, dataPtr, disk.getBuffer (), bufferPtr, tfr);
2021-05-03 20:12:44 +00:00
destPtr += tfr;
dataPtr += tfr;
remaining -= tfr;
}
writeIndices ();
}
// ---------------------------------------------------------------------------------//
private int allocateNextBlock () throws DiskFullException
// ---------------------------------------------------------------------------------//
{
blocksUsed++;
return disk.allocateNextBlock ();
}
// ---------------------------------------------------------------------------------//
private int getActualBlockNo (int logicalBlockNo) throws DiskFullException
// ---------------------------------------------------------------------------------//
{
switch (storageType)
{
case TREE:
2022-08-10 08:06:43 +00:00
return masterIndexBlock.get (logicalBlockNo / 0x100).getPosition (logicalBlockNo % 0x100);
2021-05-03 20:12:44 +00:00
case SAPLING:
2021-05-05 03:10:33 +00:00
if (logicalBlockNo < 0x100)
2022-08-10 08:06:43 +00:00
return indexBlock.getPosition (logicalBlockNo);
2021-05-03 20:12:44 +00:00
break;
case SEEDLING:
if (logicalBlockNo == 0)
2022-08-10 08:06:43 +00:00
return keyPointer;
2021-05-03 20:12:44 +00:00
break;
}
2022-08-10 08:06:43 +00:00
return register (logicalBlockNo);
2021-05-03 20:12:44 +00:00
}
// ---------------------------------------------------------------------------------//
private void writeIndices ()
// ---------------------------------------------------------------------------------//
{
if (storageType == TREE)
2021-05-04 06:31:11 +00:00
masterIndexBlock.write (disk.getBuffer ());
2021-05-03 20:12:44 +00:00
else if (storageType == SAPLING)
2021-05-04 06:31:11 +00:00
indexBlock.write (disk.getBuffer ());
2021-05-03 20:12:44 +00:00
}
// ---------------------------------------------------------------------------------//
2022-08-10 05:08:10 +00:00
private int register (int logicalBlockNo) throws DiskFullException
2021-05-03 20:12:44 +00:00
// ---------------------------------------------------------------------------------//
{
2022-08-10 05:08:10 +00:00
int nextBlockNo = allocateNextBlock ();
2021-05-05 03:10:33 +00:00
if (logicalBlockNo >= 0x100) // potential TREE
2021-05-03 20:12:44 +00:00
{
if (storageType != TREE)
{
2022-08-10 05:08:10 +00:00
masterIndexBlock = new MasterIndexBlock (nextBlockNo);
nextBlockNo = allocateNextBlock ();
2021-05-03 20:12:44 +00:00
if (storageType == SAPLING) // sapling -> tree
{
masterIndexBlock.set (0, indexBlock);
}
else if (storageType == SEEDLING) // seedling -> sapling -> tree
{
2022-08-10 05:08:10 +00:00
indexBlock = new IndexBlock (nextBlockNo);
nextBlockNo = allocateNextBlock ();
2021-05-04 06:31:11 +00:00
indexBlock.setPosition (0, keyPointer);
2021-05-03 20:12:44 +00:00
masterIndexBlock.set (0, indexBlock);
}
keyPointer = masterIndexBlock.blockNo;
storageType = TREE;
indexBlock = null;
}
2022-08-10 05:08:10 +00:00
getIndexBlock (logicalBlockNo / 0x100).setPosition (logicalBlockNo % 0x100, nextBlockNo);
2021-05-03 20:12:44 +00:00
}
else if (logicalBlockNo > 0) // potential SAPLING
{
if (storageType == TREE) // already a tree
{
2022-08-10 05:08:10 +00:00
getIndexBlock (0).setPosition (logicalBlockNo, nextBlockNo);
2021-05-03 20:12:44 +00:00
}
else if (storageType == SAPLING) // already a sapling
{
2022-08-10 05:08:10 +00:00
indexBlock.setPosition (logicalBlockNo, nextBlockNo);
2021-05-03 20:12:44 +00:00
}
else // new file or already a seedling
{
2022-08-10 05:08:10 +00:00
indexBlock = new IndexBlock (nextBlockNo);
nextBlockNo = allocateNextBlock ();
2021-05-03 20:12:44 +00:00
if (storageType == SEEDLING) // seedling -> sapling
2021-05-04 06:31:11 +00:00
indexBlock.setPosition (0, keyPointer);
2021-05-03 20:12:44 +00:00
keyPointer = indexBlock.blockNo;
storageType = SAPLING;
2022-08-10 05:08:10 +00:00
indexBlock.setPosition (logicalBlockNo, nextBlockNo);
2021-05-03 20:12:44 +00:00
}
}
else if (logicalBlockNo == 0) // potential SEEDLING
{
if (storageType == TREE) // already a tree
{
2022-08-10 05:08:10 +00:00
getIndexBlock (0).setPosition (0, nextBlockNo);
2021-05-03 20:12:44 +00:00
}
else if (storageType == SAPLING) // already a sapling
{
2022-08-10 05:08:10 +00:00
indexBlock.setPosition (0, nextBlockNo);
2021-05-03 20:12:44 +00:00
}
else
{
2022-08-10 05:08:10 +00:00
keyPointer = nextBlockNo;
2021-05-03 20:12:44 +00:00
storageType = SEEDLING;
}
}
else
2021-05-05 03:10:33 +00:00
System.out.println ("Error: " + logicalBlockNo);
2022-08-10 05:08:10 +00:00
return nextBlockNo;
2021-05-03 20:12:44 +00:00
}
// ---------------------------------------------------------------------------------//
private IndexBlock getIndexBlock (int position) throws DiskFullException
// ---------------------------------------------------------------------------------//
{
IndexBlock indexBlock = masterIndexBlock.get (position);
if (indexBlock == null)
{
indexBlock = new IndexBlock (allocateNextBlock ());
masterIndexBlock.set (position, indexBlock);
}
return indexBlock;
}
}