package com.bytezone.diskbrowser.prodos; import java.util.ArrayList; import java.util.List; import com.bytezone.diskbrowser.disk.DiskAddress; import com.bytezone.diskbrowser.gui.DataSource; import com.bytezone.diskbrowser.utilities.HexFormatter; /* * There is only one of these - it is always the first entry in the first block. * Every other entry will be either a SubDirectoryHeader or a FileEntry. */ class VolumeDirectoryHeader extends DirectoryHeader { protected final int bitMapBlock; protected int totalBlocks; protected int freeBlocks; protected int usedBlocks; protected int totalBitMapBlocks; public VolumeDirectoryHeader (ProdosDisk parentDisk, byte[] entryBuffer) { super (parentDisk, entryBuffer); bitMapBlock = HexFormatter.unsignedShort (entryBuffer, 35); totalBlocks = HexFormatter.unsignedShort (entryBuffer, 37); // if (totalBlocks == 0xFFFF || totalBlocks == 0x7FFF) // totalBlocks = (int) disk.getFile ().length () / 4096 * 8;// ignore extra bytes totalBitMapBlocks = (totalBlocks - 1) / 512 + 1; int block = 2; do { dataBlocks.add (disk.getDiskAddress (block)); byte[] buffer = disk.readSector (block); block = HexFormatter.unsignedShort (buffer, 2); } while (block > 0); // convert the Free Sector Table // int bitMapBytes = totalBlocks / 8; // one bit per block int bitMapBytes = (totalBlocks - 1) / 8 + 1; // one bit per block byte[] buffer = new byte[bitMapBytes]; int bitMapBlocks = (bitMapBytes - 1) / disk.getSectorsPerTrack () + 1; int lastBitMapBlock = bitMapBlock + bitMapBlocks - 1; int ptr = 0; for (block = bitMapBlock; block <= lastBitMapBlock; block++) { byte[] temp = disk.readSector (block); int bytesToCopy = buffer.length - ptr; if (bytesToCopy > temp.length) bytesToCopy = temp.length; System.arraycopy (temp, 0, buffer, ptr, bytesToCopy); ptr += bytesToCopy; } block = 0; // nb1 dual-dos disk needs to use totalBlocks obtained from disk // int max1 = (totalBlocks - 1) / 8 + 1; // bytes required for sector map // nb2 hard disk may be truncated, so use actual number of blocks // int max2 = (disk.getTotalBlocks () - 1) / 8 + 1; // bytes required for sector map int max = (Math.min (totalBlocks, disk.getTotalBlocks ()) - 1) / 8 + 1; // System.out.printf ("total blocks %,d%n", totalBlocks); // System.out.printf ("disk blocks %,d%n", disk.getTotalBlocks ()); for (int i = 0; i < max; i++) { byte b = buffer[i]; for (int j = 0; j < 8; j++) { if ((b & 0x80) == 0x80) { freeBlocks++; parentDisk.setSectorFree (block++, true); } else { usedBlocks++; parentDisk.setSectorFree (block++, false); } b <<= 1; } } } @Override public DataSource getDataSource () { List blockList = new ArrayList<> (); int block = 2; do { byte[] buf = disk.readSector (block); blockList.add (buf); block = HexFormatter.intValue (buf[2], buf[3]); // next block } while (block > 0); byte[] fullBuffer = new byte[blockList.size () * 507]; int offset = 0; for (byte[] bfr : blockList) { System.arraycopy (bfr, 4, fullBuffer, offset, 507); offset += 507; } return new ProdosDirectory (parentDisk, name, fullBuffer, totalBlocks, freeBlocks, usedBlocks); } @Override public List getSectors () { List sectors = new ArrayList<> (); sectors.addAll (dataBlocks); return sectors; } @Override public String toString () { if (false) { String locked = (access == 0x01) ? "*" : " "; String timeC = created == null ? "" : parentDisk.df.format (created.getTime ()); return String.format (" %s%-42s %15s", locked, "/" + name, timeC); } return name; } }