apple2js/js/formats/prodos/bit_map.ts

77 lines
2.4 KiB
TypeScript

import { word } from 'js/types';
import { ProDOSVolume } from '.';
import type { VDH } from './vdh';
const BLOCK_ENTRIES = 4096;
export class BitMap {
private vdh: VDH;
private blocks: Uint8Array[];
constructor(volume: ProDOSVolume) {
this.vdh = volume.vdh();
this.blocks = volume.blocks();
}
freeBlocks() {
const free: word[] = [];
let blockOffset = 0;
let byteOffset = 0;
let bitOffset = 0;
let bitMapBlock = this.blocks[this.vdh.bitMapPointer + blockOffset];
for (let idx = 0; idx < this.vdh.totalBlocks; idx++) {
const currentByte = bitMapBlock[byteOffset];
const mask = 1 << bitOffset;
if (currentByte & mask) {
free.push(idx);
}
bitOffset += 1;
if (bitOffset > 7) {
bitOffset = 0;
byteOffset += 1;
if (byteOffset > BLOCK_ENTRIES >> 3) {
byteOffset = 0;
blockOffset += 1;
bitMapBlock =
this.blocks[this.vdh.bitMapPointer + blockOffset];
}
}
}
return free;
}
allocBlock() {
for (let idx = 0; idx < this.vdh.totalBlocks; idx++) {
const blockOffset = Math.floor(idx / BLOCK_ENTRIES);
const bitMapBlock =
this.blocks[this.vdh.bitMapPointer + blockOffset];
const byteOffset = (idx - blockOffset * BLOCK_ENTRIES) >> 8;
const bits = bitMapBlock[byteOffset];
if (bits !== 0xff) {
let mask = 0x01;
for (let bitOffset = 0; bitOffset < 8; bitOffset++) {
if (!(bits & mask)) {
bitMapBlock[byteOffset] |= mask;
return idx;
}
mask <<= 1;
}
}
}
throw new Error('Disk full');
}
freeBlock(block: word) {
if (block >= this.vdh.totalBlocks) {
throw new Error('Block out of range');
}
const blockOffset = Math.floor(block / BLOCK_ENTRIES);
const byteOffset = (block - blockOffset * BLOCK_ENTRIES) >> 8;
const bitOffset = block & 0x7;
const bitMapBlock = this.blocks[this.vdh.bitMapPointer + blockOffset];
bitMapBlock[byteOffset] &= 0xff ^ (0x01 << bitOffset);
}
}