apple2js/js/formats/2mg.ts

85 lines
2.1 KiB
TypeScript

import DOS from './do';
import Nibble from './nib';
import ProDOS from './po';
import { DiskOptions } from './types';
import { numToString, debug } from '../util';
const OFFSETS = {
CREATOR: 0x04,
FLAGS: 0x0A,
FORMAT: 0x0C,
BLOCKS: 0x14,
DATA_OFFSET: 0x18,
BYTES: 0x1C,
};
const FLAGS = {
READ_ONLY: 0x80000000,
VOLUME_VALID: 0x00000100,
VOLUME_MASK: 0x000000FF
};
export function read2MGHeader(rawData: ArrayBuffer) {
const prefix = new DataView(rawData);
const signature = numToString(prefix.getInt32(0x0, true));
if (signature !== '2IMG') {
throw new Error('Unrecognized 2mg signature: ' + signature);
}
const creator = numToString(prefix.getInt32(OFFSETS.CREATOR, true));
const format = prefix.getInt32(OFFSETS.FORMAT, true);
const bytes = prefix.getInt32(OFFSETS.BYTES, true);
const offset = prefix.getInt32(OFFSETS.DATA_OFFSET, true);
const flags = prefix.getInt32(OFFSETS.FLAGS, true);
const readOnly = (flags & FLAGS.READ_ONLY) !== 0;
let volume = 254;
if (flags & FLAGS.VOLUME_VALID) {
volume = flags & FLAGS.VOLUME_MASK;
}
debug('created by', creator);
return {
bytes,
creator,
format,
offset,
readOnly,
volume,
};
}
/**
* Returns a `Disk` object from a 2mg image.
* @param options the disk image and options
*/
export default function createDiskFrom2MG(options: DiskOptions) {
let { rawData } = options;
let disk;
if (!rawData) {
throw new Error('Requires rawData');
}
const { bytes, format, offset, readOnly, volume } = read2MGHeader(rawData);
rawData = rawData.slice(offset, offset + bytes);
options = { ...options, rawData, readOnly, volume };
// Check image format.
// Sure, it's really 64 bits. But only 2 are actually used.
switch (format) {
case 1: // PO
disk = ProDOS(options);
break;
case 2: // NIB
disk = Nibble(options);
break;
case 0: // dsk
default: // Something hinky, assume 'dsk'
disk = DOS(options);
break;
}
return disk;
}