mirror of
https://github.com/whscullin/apple2js.git
synced 2024-01-12 14:14:38 +00:00
126 lines
4.6 KiB
TypeScript
126 lines
4.6 KiB
TypeScript
import type { ProDOSVolume } from '.';
|
|
import { ProDOSFile } from './base_file';
|
|
import { BitMap } from './bit_map';
|
|
import { BLOCK_SIZE, STORAGE_TYPES } from './constants';
|
|
import type { FileEntry } from './file_entry';
|
|
|
|
export class TreeFile extends ProDOSFile {
|
|
private bitMap: BitMap;
|
|
private blocks: Uint8Array[];
|
|
|
|
constructor(volume: ProDOSVolume, private fileEntry: FileEntry) {
|
|
super(volume);
|
|
this.blocks = volume.blocks();
|
|
this.bitMap = volume.bitMap();
|
|
}
|
|
|
|
getBlockPointers() {
|
|
const treeBlock = this.blocks[this.fileEntry.keyPointer];
|
|
const saplingPointers = new DataView(treeBlock);
|
|
const pointers = [];
|
|
for (let idx = 0; idx < 256; idx++) {
|
|
const saplingPointer =
|
|
saplingPointers.getUint8(idx) |
|
|
(saplingPointers.getUint8(0x100 + idx) << 8);
|
|
if (saplingPointer) {
|
|
pointers.push(saplingPointer);
|
|
const seedlingPointers = new DataView(this.blocks[saplingPointer]);
|
|
for (let jdx = 0; jdx < 256; jdx++) {
|
|
const seedlingPointer =
|
|
seedlingPointers.getUint8(idx) |
|
|
(seedlingPointers.getUint8(0x100 + idx) << 8);
|
|
if (seedlingPointer) {
|
|
pointers.push(seedlingPointer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return pointers;
|
|
}
|
|
|
|
// TODO(whscullin): Why did I not use getBlockPointers for these...
|
|
read() {
|
|
const treeBlock = this.blocks[this.fileEntry.keyPointer];
|
|
const saplingPointers = new DataView(treeBlock);
|
|
let remainingLength = this.fileEntry.eof;
|
|
const data = new Uint8Array(remainingLength);
|
|
let offset = 0;
|
|
let idx = 0;
|
|
|
|
while (remainingLength > 0) {
|
|
const saplingPointer =
|
|
saplingPointers.getUint8(idx) |
|
|
(saplingPointers.getUint8(0x100 + idx) << 8);
|
|
let jdx = 0;
|
|
if (saplingPointer) {
|
|
const saplingBlock = this.blocks[saplingPointer];
|
|
const seedlingPointers = new DataView(saplingBlock);
|
|
|
|
while (jdx < 256 && remainingLength > 0) {
|
|
const seedlingPointer =
|
|
seedlingPointers.getUint8(idx) |
|
|
(seedlingPointers.getUint8(0x100 + idx) << 8);
|
|
if (seedlingPointer) {
|
|
const seedlingBlock = this.blocks[seedlingPointer];
|
|
const bytes = seedlingBlock.slice(Math.min(BLOCK_SIZE, remainingLength));
|
|
|
|
data.set(bytes, offset);
|
|
}
|
|
jdx++;
|
|
offset += BLOCK_SIZE;
|
|
remainingLength -= BLOCK_SIZE;
|
|
}
|
|
} else {
|
|
offset += BLOCK_SIZE * 256;
|
|
remainingLength -= BLOCK_SIZE * 256;
|
|
}
|
|
idx++;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
write(data: Uint8Array) {
|
|
this.fileEntry.storageType = STORAGE_TYPES.TREE;
|
|
this.fileEntry.keyPointer = this.bitMap.allocBlock();
|
|
this.fileEntry.eof = data.byteLength;
|
|
|
|
const treeBlock = this.blocks[this.fileEntry.keyPointer];
|
|
const saplingPointers = new DataView(treeBlock);
|
|
|
|
let remainingLength = this.fileEntry.eof;
|
|
let offset = 0;
|
|
let idx = 0;
|
|
|
|
while (remainingLength > 0) {
|
|
const saplingPointer = this.bitMap.allocBlock();
|
|
const saplingBlock = this.blocks[saplingPointer];
|
|
saplingPointers.setUint8(idx, saplingPointer & 0xff);
|
|
saplingPointers.setUint8(0x100 + idx, saplingPointer >> 8);
|
|
const seedlingPointers = new DataView(saplingBlock);
|
|
|
|
let jdx = 0;
|
|
|
|
while (jdx < 256 && remainingLength > 0) {
|
|
const seedlingPointer = this.bitMap.allocBlock();
|
|
seedlingPointers.setUint8(idx, seedlingPointer & 0xff);
|
|
seedlingPointers.setUint8(0x100 + idx, seedlingPointer >> 8);
|
|
const seedlingBlock = this.blocks[seedlingPointer];
|
|
seedlingBlock.set(data.slice(offset, Math.min(BLOCK_SIZE, remainingLength)));
|
|
jdx++;
|
|
offset += BLOCK_SIZE;
|
|
remainingLength -= BLOCK_SIZE;
|
|
}
|
|
idx++;
|
|
}
|
|
this.fileEntry.write();
|
|
}
|
|
|
|
delete() {
|
|
const pointers = this.getBlockPointers();
|
|
for (let idx = 0; idx < pointers.length; idx++) {
|
|
this.bitMap.freeBlock(pointers[idx]);
|
|
}
|
|
}
|
|
}
|
|
|