apple2js/js/components/util/files.ts

303 lines
8.6 KiB
TypeScript
Raw Normal View History

2023-11-24 18:12:19 +00:00
import { Debugger } from '@whscullin/cpu6502';
Split disk data out into its own record (#158) * Harmonize drive and disk type hierarchies Before, the `XXXDrive` and `XXXDisk` type hierarchies were similar, but not exactly the same. For example, `encoding` and `format` were missing on some `XXXDisk` types where they existed on the `XXXDrive` type. This change attempts to bring the hierarchies closer together. However, the biggest visible consequence is the introduction of the `FLOPPY_FORMATS` array and its associated `FloppyFormat` type. This replaces `NIBBLE_FORMATS` in most places. A couple of new type guards for disk formats and disks have been added as well. All tests pass, everything compiles with no errors, and both WOZ and nibble format disks load in the emulator. * Move disk data to a `disk` field in the drive Before, disk data was mixed in with state about the drive itself (like track, motor phase, etc.). This made it hard to know exactly what data was necessary for different image formats. Now, the disk data is in a `disk` field whose type depends on the drive type. This makes responisbility a bit easier. One oddity, though, is that the `Drive` has metadata _and_ the `Disk` has metadata. When a disk is in the drive, these should be `===`, but when there is no disk in the drive, obviously only the drive metadata is set. All tests pass, everything compiles, and both WOZ and nibble disks work in the emulator (both preact and classic). * Squash the `Drive` type hierarchy Before, the type of the drive depended on the type of the disk in the drive. Thus, `NibbleDrive` contained a `NibbleDisk` and a `WozDrive` contained a `WozDisk`. With the extraction of the disk data to a single field, this type hierarchy makes no sense. Instead, it suffices to check the type of the disk. This change removes the `NibbleDrive` and `WozDrive` types and type guards, checking the disk type where necessary. This change also introduces the `NoFloppyDisk` type to represent the lack of a disk. This allows the drive to have metadata, for one. All tests pass, everything compiles, and both WOZ and nibble disks work locally. * Use more destructuring assignment Now, more places use constructs like: ```TypeScript const { metadata, readOnly, track, head, phase, dirty } = drive; return { disk: getDiskState(drive.disk), metadata: {...metadata}, readOnly, track, head, phase, dirty, }; ``` * Remove the `Disk` object from the `Drive` object This change splits out the disk objects into a record parallel to the drive objects. The idea is that the `Drive` structure becomes a representation of the state of the drive that is separate from the disk image actually in the drive. This helps in an upcoming refactoring. This also changes the default empty disks to be writable. While odd, the write protect switch should be in the "off" position since there is no disk pressing on it. Finally, `insertDisk` now resets the head position to 0 since there is no way of preserving the head position across disks. (Even in the real world, the motor-off delay plus spindle spin-down would make it impossible to know the disk head position with any accuracy.)
2022-09-17 13:41:35 +00:00
import Disk2 from 'js/cards/disk2';
import SmartPort from 'js/cards/smartport';
import {
BlockFormat,
BLOCK_FORMATS,
DISK_FORMATS,
DriveNumber,
Split disk data out into its own record (#158) * Harmonize drive and disk type hierarchies Before, the `XXXDrive` and `XXXDisk` type hierarchies were similar, but not exactly the same. For example, `encoding` and `format` were missing on some `XXXDisk` types where they existed on the `XXXDrive` type. This change attempts to bring the hierarchies closer together. However, the biggest visible consequence is the introduction of the `FLOPPY_FORMATS` array and its associated `FloppyFormat` type. This replaces `NIBBLE_FORMATS` in most places. A couple of new type guards for disk formats and disks have been added as well. All tests pass, everything compiles with no errors, and both WOZ and nibble format disks load in the emulator. * Move disk data to a `disk` field in the drive Before, disk data was mixed in with state about the drive itself (like track, motor phase, etc.). This made it hard to know exactly what data was necessary for different image formats. Now, the disk data is in a `disk` field whose type depends on the drive type. This makes responisbility a bit easier. One oddity, though, is that the `Drive` has metadata _and_ the `Disk` has metadata. When a disk is in the drive, these should be `===`, but when there is no disk in the drive, obviously only the drive metadata is set. All tests pass, everything compiles, and both WOZ and nibble disks work in the emulator (both preact and classic). * Squash the `Drive` type hierarchy Before, the type of the drive depended on the type of the disk in the drive. Thus, `NibbleDrive` contained a `NibbleDisk` and a `WozDrive` contained a `WozDisk`. With the extraction of the disk data to a single field, this type hierarchy makes no sense. Instead, it suffices to check the type of the disk. This change removes the `NibbleDrive` and `WozDrive` types and type guards, checking the disk type where necessary. This change also introduces the `NoFloppyDisk` type to represent the lack of a disk. This allows the drive to have metadata, for one. All tests pass, everything compiles, and both WOZ and nibble disks work locally. * Use more destructuring assignment Now, more places use constructs like: ```TypeScript const { metadata, readOnly, track, head, phase, dirty } = drive; return { disk: getDiskState(drive.disk), metadata: {...metadata}, readOnly, track, head, phase, dirty, }; ``` * Remove the `Disk` object from the `Drive` object This change splits out the disk objects into a record parallel to the drive objects. The idea is that the `Drive` structure becomes a representation of the state of the drive that is separate from the disk image actually in the drive. This helps in an upcoming refactoring. This also changes the default empty disks to be writable. While odd, the write protect switch should be in the "off" position since there is no disk pressing on it. Finally, `insertDisk` now resets the head position to 0 since there is no way of preserving the head position across disks. (Even in the real world, the motor-off delay plus spindle spin-down would make it impossible to know the disk head position with any accuracy.)
2022-09-17 13:41:35 +00:00
FloppyFormat,
FLOPPY_FORMATS,
JSONDisk,
MassStorage,
} from 'js/formats/types';
Split disk data out into its own record (#158) * Harmonize drive and disk type hierarchies Before, the `XXXDrive` and `XXXDisk` type hierarchies were similar, but not exactly the same. For example, `encoding` and `format` were missing on some `XXXDisk` types where they existed on the `XXXDrive` type. This change attempts to bring the hierarchies closer together. However, the biggest visible consequence is the introduction of the `FLOPPY_FORMATS` array and its associated `FloppyFormat` type. This replaces `NIBBLE_FORMATS` in most places. A couple of new type guards for disk formats and disks have been added as well. All tests pass, everything compiles with no errors, and both WOZ and nibble format disks load in the emulator. * Move disk data to a `disk` field in the drive Before, disk data was mixed in with state about the drive itself (like track, motor phase, etc.). This made it hard to know exactly what data was necessary for different image formats. Now, the disk data is in a `disk` field whose type depends on the drive type. This makes responisbility a bit easier. One oddity, though, is that the `Drive` has metadata _and_ the `Disk` has metadata. When a disk is in the drive, these should be `===`, but when there is no disk in the drive, obviously only the drive metadata is set. All tests pass, everything compiles, and both WOZ and nibble disks work in the emulator (both preact and classic). * Squash the `Drive` type hierarchy Before, the type of the drive depended on the type of the disk in the drive. Thus, `NibbleDrive` contained a `NibbleDisk` and a `WozDrive` contained a `WozDisk`. With the extraction of the disk data to a single field, this type hierarchy makes no sense. Instead, it suffices to check the type of the disk. This change removes the `NibbleDrive` and `WozDrive` types and type guards, checking the disk type where necessary. This change also introduces the `NoFloppyDisk` type to represent the lack of a disk. This allows the drive to have metadata, for one. All tests pass, everything compiles, and both WOZ and nibble disks work locally. * Use more destructuring assignment Now, more places use constructs like: ```TypeScript const { metadata, readOnly, track, head, phase, dirty } = drive; return { disk: getDiskState(drive.disk), metadata: {...metadata}, readOnly, track, head, phase, dirty, }; ``` * Remove the `Disk` object from the `Drive` object This change splits out the disk objects into a record parallel to the drive objects. The idea is that the `Drive` structure becomes a representation of the state of the drive that is separate from the disk image actually in the drive. This helps in an upcoming refactoring. This also changes the default empty disks to be writable. While odd, the write protect switch should be in the "off" position since there is no disk pressing on it. Finally, `insertDisk` now resets the head position to 0 since there is no way of preserving the head position across disks. (Even in the real world, the motor-off delay plus spindle spin-down would make it impossible to know the disk head position with any accuracy.)
2022-09-17 13:41:35 +00:00
import { includes, word } from 'js/types';
import { initGamepad } from 'js/ui/gamepad';
type ProgressCallback = (current: number, total: number) => void;
/**
* Routine to split a legacy hash into parts for disk loading
*
* @returns an padded array for 1 based indexing
*/
export const getHashParts = (hash: string) => {
const parts = hash.match(/^#([^|]*)\|?(.*)$/) || ['', '', ''];
return ['', parts[1], parts[2]];
};
/**
* Update the location hash to reflect the current disk state, if possible
*
* @param parts a padded array with values starting at index 1
*/
export const setHashParts = (parts: string[]) => {
window.location.hash = `#${parts[1]}` + (parts[2] ? `|${parts[2]}` : '');
};
export const getNameAndExtension = (url: string) => {
const urlParts = url.split('/');
const file = urlParts.pop() || url;
const fileParts = file.split('.');
const ext = fileParts.pop()?.toLowerCase() || '[none]';
const name = decodeURIComponent(fileParts.join('.'));
return { name, ext };
};
export const loadLocalFile = (
storage: MassStorage<FloppyFormat | BlockFormat>,
Split disk data out into its own record (#158) * Harmonize drive and disk type hierarchies Before, the `XXXDrive` and `XXXDisk` type hierarchies were similar, but not exactly the same. For example, `encoding` and `format` were missing on some `XXXDisk` types where they existed on the `XXXDrive` type. This change attempts to bring the hierarchies closer together. However, the biggest visible consequence is the introduction of the `FLOPPY_FORMATS` array and its associated `FloppyFormat` type. This replaces `NIBBLE_FORMATS` in most places. A couple of new type guards for disk formats and disks have been added as well. All tests pass, everything compiles with no errors, and both WOZ and nibble format disks load in the emulator. * Move disk data to a `disk` field in the drive Before, disk data was mixed in with state about the drive itself (like track, motor phase, etc.). This made it hard to know exactly what data was necessary for different image formats. Now, the disk data is in a `disk` field whose type depends on the drive type. This makes responisbility a bit easier. One oddity, though, is that the `Drive` has metadata _and_ the `Disk` has metadata. When a disk is in the drive, these should be `===`, but when there is no disk in the drive, obviously only the drive metadata is set. All tests pass, everything compiles, and both WOZ and nibble disks work in the emulator (both preact and classic). * Squash the `Drive` type hierarchy Before, the type of the drive depended on the type of the disk in the drive. Thus, `NibbleDrive` contained a `NibbleDisk` and a `WozDrive` contained a `WozDisk`. With the extraction of the disk data to a single field, this type hierarchy makes no sense. Instead, it suffices to check the type of the disk. This change removes the `NibbleDrive` and `WozDrive` types and type guards, checking the disk type where necessary. This change also introduces the `NoFloppyDisk` type to represent the lack of a disk. This allows the drive to have metadata, for one. All tests pass, everything compiles, and both WOZ and nibble disks work locally. * Use more destructuring assignment Now, more places use constructs like: ```TypeScript const { metadata, readOnly, track, head, phase, dirty } = drive; return { disk: getDiskState(drive.disk), metadata: {...metadata}, readOnly, track, head, phase, dirty, }; ``` * Remove the `Disk` object from the `Drive` object This change splits out the disk objects into a record parallel to the drive objects. The idea is that the `Drive` structure becomes a representation of the state of the drive that is separate from the disk image actually in the drive. This helps in an upcoming refactoring. This also changes the default empty disks to be writable. While odd, the write protect switch should be in the "off" position since there is no disk pressing on it. Finally, `insertDisk` now resets the head position to 0 since there is no way of preserving the head position across disks. (Even in the real world, the motor-off delay plus spindle spin-down would make it impossible to know the disk head position with any accuracy.)
2022-09-17 13:41:35 +00:00
formats: typeof FLOPPY_FORMATS | typeof BLOCK_FORMATS | typeof DISK_FORMATS,
driveNo: DriveNumber,
file: File
) => {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = function () {
const result = this.result as ArrayBuffer;
const { name, ext } = getNameAndExtension(file.name);
if (includes(formats, ext)) {
initGamepad();
if (storage.setBinary(driveNo, name, ext, result)) {
resolve(true);
} else {
reject(`Unable to load ${name}`);
}
} else {
reject(`Extension "${ext}" not recognized.`);
}
};
fileReader.readAsArrayBuffer(file);
});
};
/**
* Local file loading routine. Allows a File object from a file
* selection form element to be loaded.
*
* @param smartPort SmartPort object
* @param driveNo Drive number
* @param file Browser File object to load
* @returns true if successful
*/
export const loadLocalBlockFile = (
smartPort: SmartPort,
driveNo: DriveNumber,
file: File
) => {
return loadLocalFile(smartPort, BLOCK_FORMATS, driveNo, file);
};
/**
* Local file loading routine. Allows a File object from a file
* selection form element to be loaded.
*
* @param disk2 Disk2 object
* @param driveNo Drive number
* @param file Browser File object to load
* @returns true if successful
*/
export const loadLocalNibbleFile = (
disk2: Disk2,
driveNo: DriveNumber,
file: File
) => {
return loadLocalFile(disk2, FLOPPY_FORMATS, driveNo, file);
};
/**
* JSON loading routine, loads a JSON file at the given URL. Requires
* proper cross domain loading headers if the URL is not on the same server
* as the emulator.
*
* @param disk2 Disk2 object
* @param driveNo Drive number
* @param url URL, relative or absolute to JSON file
* @returns true if successful
*/
export const loadJSON = async (
disk2: Disk2,
driveNo: DriveNumber,
url: string
) => {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Error loading: ${response.statusText}`);
}
const data = (await response.json()) as JSONDisk;
Split disk data out into its own record (#158) * Harmonize drive and disk type hierarchies Before, the `XXXDrive` and `XXXDisk` type hierarchies were similar, but not exactly the same. For example, `encoding` and `format` were missing on some `XXXDisk` types where they existed on the `XXXDrive` type. This change attempts to bring the hierarchies closer together. However, the biggest visible consequence is the introduction of the `FLOPPY_FORMATS` array and its associated `FloppyFormat` type. This replaces `NIBBLE_FORMATS` in most places. A couple of new type guards for disk formats and disks have been added as well. All tests pass, everything compiles with no errors, and both WOZ and nibble format disks load in the emulator. * Move disk data to a `disk` field in the drive Before, disk data was mixed in with state about the drive itself (like track, motor phase, etc.). This made it hard to know exactly what data was necessary for different image formats. Now, the disk data is in a `disk` field whose type depends on the drive type. This makes responisbility a bit easier. One oddity, though, is that the `Drive` has metadata _and_ the `Disk` has metadata. When a disk is in the drive, these should be `===`, but when there is no disk in the drive, obviously only the drive metadata is set. All tests pass, everything compiles, and both WOZ and nibble disks work in the emulator (both preact and classic). * Squash the `Drive` type hierarchy Before, the type of the drive depended on the type of the disk in the drive. Thus, `NibbleDrive` contained a `NibbleDisk` and a `WozDrive` contained a `WozDisk`. With the extraction of the disk data to a single field, this type hierarchy makes no sense. Instead, it suffices to check the type of the disk. This change removes the `NibbleDrive` and `WozDrive` types and type guards, checking the disk type where necessary. This change also introduces the `NoFloppyDisk` type to represent the lack of a disk. This allows the drive to have metadata, for one. All tests pass, everything compiles, and both WOZ and nibble disks work locally. * Use more destructuring assignment Now, more places use constructs like: ```TypeScript const { metadata, readOnly, track, head, phase, dirty } = drive; return { disk: getDiskState(drive.disk), metadata: {...metadata}, readOnly, track, head, phase, dirty, }; ``` * Remove the `Disk` object from the `Drive` object This change splits out the disk objects into a record parallel to the drive objects. The idea is that the `Drive` structure becomes a representation of the state of the drive that is separate from the disk image actually in the drive. This helps in an upcoming refactoring. This also changes the default empty disks to be writable. While odd, the write protect switch should be in the "off" position since there is no disk pressing on it. Finally, `insertDisk` now resets the head position to 0 since there is no way of preserving the head position across disks. (Even in the real world, the motor-off delay plus spindle spin-down would make it impossible to know the disk head position with any accuracy.)
2022-09-17 13:41:35 +00:00
if (!includes(FLOPPY_FORMATS, data.type)) {
throw new Error(`Type "${data.type}" not recognized.`);
}
disk2.setDisk(driveNo, data);
initGamepad(data.gamepad);
};
export const loadHttpFile = async (
url: string,
signal?: AbortSignal,
onProgress?: ProgressCallback
): Promise<ArrayBuffer> => {
const response = await fetch(url, signal ? { signal } : {});
if (!response.ok) {
throw new Error(`Error loading: ${response.statusText}`);
}
if (!response.body) {
throw new Error('Error loading: no body');
}
const reader = response.body.getReader();
const contentLength = parseInt(
response.headers.get('content-length') || '0',
10
);
let received = 0;
const chunks: Uint8Array[] = [];
let result = await reader.read();
onProgress?.(1, contentLength);
while (!result.done) {
chunks.push(result.value);
received += result.value.length;
onProgress?.(received, contentLength);
result = await reader.read();
}
const data = new Uint8Array(received);
let offset = 0;
for (const chunk of chunks) {
data.set(chunk, offset);
offset += chunk.length;
}
return data.buffer;
};
/**
* HTTP loading routine, loads a file at the given URL. Requires
* proper cross domain loading headers if the URL is not on the same server
* as the emulator.
*
* @param smartPort SmartPort object
* @param driveNo Drive number
* @param url URL, relative or absolute to JSON file
* @returns true if successful
*/
export const loadHttpBlockFile = async (
smartPort: SmartPort,
driveNo: DriveNumber,
url: string,
signal?: AbortSignal,
onProgress?: ProgressCallback
): Promise<boolean> => {
const { name, ext } = getNameAndExtension(url);
if (!includes(BLOCK_FORMATS, ext)) {
throw new Error(`Extension "${ext}" not recognized.`);
}
const data = await loadHttpFile(url, signal, onProgress);
smartPort.setBinary(driveNo, name, ext, data);
initGamepad();
return true;
};
/**
* HTTP loading routine, loads a file at the given URL. Requires
* proper cross domain loading headers if the URL is not on the same server
* as the emulator.
*
* @param disk2 Disk2 object
* @param driveNo Drive number
* @param url URL, relative or absolute to JSON file
* @returns true if successful
*/
export const loadHttpNibbleFile = async (
disk2: Disk2,
driveNo: DriveNumber,
url: string,
signal?: AbortSignal,
onProgress?: ProgressCallback
) => {
if (url.endsWith('.json')) {
return loadJSON(disk2, driveNo, url);
}
const { name, ext } = getNameAndExtension(url);
Split disk data out into its own record (#158) * Harmonize drive and disk type hierarchies Before, the `XXXDrive` and `XXXDisk` type hierarchies were similar, but not exactly the same. For example, `encoding` and `format` were missing on some `XXXDisk` types where they existed on the `XXXDrive` type. This change attempts to bring the hierarchies closer together. However, the biggest visible consequence is the introduction of the `FLOPPY_FORMATS` array and its associated `FloppyFormat` type. This replaces `NIBBLE_FORMATS` in most places. A couple of new type guards for disk formats and disks have been added as well. All tests pass, everything compiles with no errors, and both WOZ and nibble format disks load in the emulator. * Move disk data to a `disk` field in the drive Before, disk data was mixed in with state about the drive itself (like track, motor phase, etc.). This made it hard to know exactly what data was necessary for different image formats. Now, the disk data is in a `disk` field whose type depends on the drive type. This makes responisbility a bit easier. One oddity, though, is that the `Drive` has metadata _and_ the `Disk` has metadata. When a disk is in the drive, these should be `===`, but when there is no disk in the drive, obviously only the drive metadata is set. All tests pass, everything compiles, and both WOZ and nibble disks work in the emulator (both preact and classic). * Squash the `Drive` type hierarchy Before, the type of the drive depended on the type of the disk in the drive. Thus, `NibbleDrive` contained a `NibbleDisk` and a `WozDrive` contained a `WozDisk`. With the extraction of the disk data to a single field, this type hierarchy makes no sense. Instead, it suffices to check the type of the disk. This change removes the `NibbleDrive` and `WozDrive` types and type guards, checking the disk type where necessary. This change also introduces the `NoFloppyDisk` type to represent the lack of a disk. This allows the drive to have metadata, for one. All tests pass, everything compiles, and both WOZ and nibble disks work locally. * Use more destructuring assignment Now, more places use constructs like: ```TypeScript const { metadata, readOnly, track, head, phase, dirty } = drive; return { disk: getDiskState(drive.disk), metadata: {...metadata}, readOnly, track, head, phase, dirty, }; ``` * Remove the `Disk` object from the `Drive` object This change splits out the disk objects into a record parallel to the drive objects. The idea is that the `Drive` structure becomes a representation of the state of the drive that is separate from the disk image actually in the drive. This helps in an upcoming refactoring. This also changes the default empty disks to be writable. While odd, the write protect switch should be in the "off" position since there is no disk pressing on it. Finally, `insertDisk` now resets the head position to 0 since there is no way of preserving the head position across disks. (Even in the real world, the motor-off delay plus spindle spin-down would make it impossible to know the disk head position with any accuracy.)
2022-09-17 13:41:35 +00:00
if (!includes(FLOPPY_FORMATS, ext)) {
throw new Error(`Extension "${ext}" not recognized.`);
}
const data = await loadHttpFile(url, signal, onProgress);
disk2.setBinary(driveNo, name, ext, data);
initGamepad();
return loadHttpFile(url, signal, onProgress);
};
export const loadHttpUnknownFile = async (
smartStorageBroker: SmartStorageBroker,
driveNo: DriveNumber,
url: string,
signal?: AbortSignal,
onProgress?: ProgressCallback
) => {
const data = await loadHttpFile(url, signal, onProgress);
const { name, ext } = getNameAndExtension(url);
smartStorageBroker.setBinary(driveNo, name, ext, data);
};
export class SmartStorageBroker implements MassStorage<unknown> {
constructor(
private disk2: Disk2,
private smartPort: SmartPort
2023-11-25 00:30:59 +00:00
) {}
setBinary(
driveNo: DriveNumber,
name: string,
ext: string,
data: ArrayBuffer
): boolean {
if (includes(DISK_FORMATS, ext)) {
if (data.byteLength >= 800 * 1024) {
if (includes(BLOCK_FORMATS, ext)) {
this.smartPort.setBinary(driveNo, name, ext, data);
} else {
throw new Error(`Unable to load "${name}"`);
}
Split disk data out into its own record (#158) * Harmonize drive and disk type hierarchies Before, the `XXXDrive` and `XXXDisk` type hierarchies were similar, but not exactly the same. For example, `encoding` and `format` were missing on some `XXXDisk` types where they existed on the `XXXDrive` type. This change attempts to bring the hierarchies closer together. However, the biggest visible consequence is the introduction of the `FLOPPY_FORMATS` array and its associated `FloppyFormat` type. This replaces `NIBBLE_FORMATS` in most places. A couple of new type guards for disk formats and disks have been added as well. All tests pass, everything compiles with no errors, and both WOZ and nibble format disks load in the emulator. * Move disk data to a `disk` field in the drive Before, disk data was mixed in with state about the drive itself (like track, motor phase, etc.). This made it hard to know exactly what data was necessary for different image formats. Now, the disk data is in a `disk` field whose type depends on the drive type. This makes responisbility a bit easier. One oddity, though, is that the `Drive` has metadata _and_ the `Disk` has metadata. When a disk is in the drive, these should be `===`, but when there is no disk in the drive, obviously only the drive metadata is set. All tests pass, everything compiles, and both WOZ and nibble disks work in the emulator (both preact and classic). * Squash the `Drive` type hierarchy Before, the type of the drive depended on the type of the disk in the drive. Thus, `NibbleDrive` contained a `NibbleDisk` and a `WozDrive` contained a `WozDisk`. With the extraction of the disk data to a single field, this type hierarchy makes no sense. Instead, it suffices to check the type of the disk. This change removes the `NibbleDrive` and `WozDrive` types and type guards, checking the disk type where necessary. This change also introduces the `NoFloppyDisk` type to represent the lack of a disk. This allows the drive to have metadata, for one. All tests pass, everything compiles, and both WOZ and nibble disks work locally. * Use more destructuring assignment Now, more places use constructs like: ```TypeScript const { metadata, readOnly, track, head, phase, dirty } = drive; return { disk: getDiskState(drive.disk), metadata: {...metadata}, readOnly, track, head, phase, dirty, }; ``` * Remove the `Disk` object from the `Drive` object This change splits out the disk objects into a record parallel to the drive objects. The idea is that the `Drive` structure becomes a representation of the state of the drive that is separate from the disk image actually in the drive. This helps in an upcoming refactoring. This also changes the default empty disks to be writable. While odd, the write protect switch should be in the "off" position since there is no disk pressing on it. Finally, `insertDisk` now resets the head position to 0 since there is no way of preserving the head position across disks. (Even in the real world, the motor-off delay plus spindle spin-down would make it impossible to know the disk head position with any accuracy.)
2022-09-17 13:41:35 +00:00
} else if (includes(FLOPPY_FORMATS, ext)) {
this.disk2.setBinary(driveNo, name, ext, data);
} else {
throw new Error(`Unable to load "${name}"`);
}
} else {
throw new Error(`Extension "${ext}" not recognized.`);
}
return true;
}
getBinary(_drive: number) {
return null;
}
}
/**
* Load binary file into memory.
*
* @param file File object to read into memory
* @param address Address at which to start load
* @param debug Debugger object
* @returns resolves to true if successful
*/
export const loadLocalBinaryFile = (
file: File,
address: word,
debug: Debugger
) => {
return new Promise((resolve, _reject) => {
const fileReader = new FileReader();
fileReader.onload = function () {
const result = this.result as ArrayBuffer;
const bytes = new Uint8Array(result);
debug.setMemory(address, bytes);
resolve(true);
};
fileReader.readAsArrayBuffer(file);
});
};