apple2js/js/formats/format_utils.ts

464 lines
13 KiB
TypeScript
Raw Normal View History

/* Copyright 2010-2019 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. No representations are made about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*/
Convert `cards/disk2.js` to Typescript (#54) * Convert `cards/disk2.js` to Typescript This is mostly a straightforward conversion of `cards/disk2.js` to Typescript, with the following exceptions: * `setState()` did not restore the drive light state correctly because the callback was called with the old `on` value. * `setPhase()` did not work for WOZ images. * `getBinary()` did not work for `nib` files. * `getBase64()` did not work for `nib` files and maybe didn't work right at all. Even with these fixes, local storage still doesn't work correctly. I have also added several TODOs where methods don't support WOZ disks. * Convert most uses of `memory` to `Uint8Array` There are many places in the existing code where we use `Uint8Array` directly. This change merely makes the `memory` type equivalent to `Uint8Array`. This change also changes most ROM data to be read-only in Typescript to ensure that it is not modified by mistake. This can't be done just by applying `as const` to the declaration because `Uint8Array`s are can not be expressed as literals. Instead, we create a new type, `ReadonlyUint8Array` that drops the mutation methods and makes indexed access read-only. See https://www.growingwiththeweb.com/2020/10/typescript-readonly-typed-arrays.html for details. * Tighten types and document `disk2.ts` While trying to understand the Disk ][ emulation, I tighted the types and documented the parts that I could, including references to other sources, like _Understanding the Apple //e_ by Jim Sather. The one functional change is the addition of the P6 ROM of DOS 3.2 and earlier. This is automatically selected if the card is initialized for 13 sector disks.
2021-02-08 04:50:50 +00:00
import { byte, DiskFormat, memory } from '../types';
import { base64_decode, base64_encode } from '../base64';
import { bytify, debug, toHex } from '../util';
export type Disk = {
Convert `cards/disk2.js` to Typescript (#54) * Convert `cards/disk2.js` to Typescript This is mostly a straightforward conversion of `cards/disk2.js` to Typescript, with the following exceptions: * `setState()` did not restore the drive light state correctly because the callback was called with the old `on` value. * `setPhase()` did not work for WOZ images. * `getBinary()` did not work for `nib` files. * `getBase64()` did not work for `nib` files and maybe didn't work right at all. Even with these fixes, local storage still doesn't work correctly. I have also added several TODOs where methods don't support WOZ disks. * Convert most uses of `memory` to `Uint8Array` There are many places in the existing code where we use `Uint8Array` directly. This change merely makes the `memory` type equivalent to `Uint8Array`. This change also changes most ROM data to be read-only in Typescript to ensure that it is not modified by mistake. This can't be done just by applying `as const` to the declaration because `Uint8Array`s are can not be expressed as literals. Instead, we create a new type, `ReadonlyUint8Array` that drops the mutation methods and makes indexed access read-only. See https://www.growingwiththeweb.com/2020/10/typescript-readonly-typed-arrays.html for details. * Tighten types and document `disk2.ts` While trying to understand the Disk ][ emulation, I tighted the types and documented the parts that I could, including references to other sources, like _Understanding the Apple //e_ by Jim Sather. The one functional change is the addition of the P6 ROM of DOS 3.2 and earlier. This is automatically selected if the card is initialized for 13 sector disks.
2021-02-08 04:50:50 +00:00
format: DiskFormat,
name: string,
volume: byte,
tracks: memory[],
readOnly: boolean,
};
export type Drive = {
Convert `cards/disk2.js` to Typescript (#54) * Convert `cards/disk2.js` to Typescript This is mostly a straightforward conversion of `cards/disk2.js` to Typescript, with the following exceptions: * `setState()` did not restore the drive light state correctly because the callback was called with the old `on` value. * `setPhase()` did not work for WOZ images. * `getBinary()` did not work for `nib` files. * `getBase64()` did not work for `nib` files and maybe didn't work right at all. Even with these fixes, local storage still doesn't work correctly. I have also added several TODOs where methods don't support WOZ disks. * Convert most uses of `memory` to `Uint8Array` There are many places in the existing code where we use `Uint8Array` directly. This change merely makes the `memory` type equivalent to `Uint8Array`. This change also changes most ROM data to be read-only in Typescript to ensure that it is not modified by mistake. This can't be done just by applying `as const` to the declaration because `Uint8Array`s are can not be expressed as literals. Instead, we create a new type, `ReadonlyUint8Array` that drops the mutation methods and makes indexed access read-only. See https://www.growingwiththeweb.com/2020/10/typescript-readonly-typed-arrays.html for details. * Tighten types and document `disk2.ts` While trying to understand the Disk ][ emulation, I tighted the types and documented the parts that I could, including references to other sources, like _Understanding the Apple //e_ by Jim Sather. The one functional change is the addition of the P6 ROM of DOS 3.2 and earlier. This is automatically selected if the card is initialized for 13 sector disks.
2021-02-08 04:50:50 +00:00
format: DiskFormat,
volume: byte,
tracks: memory[],
Convert `cards/disk2.js` to Typescript (#54) * Convert `cards/disk2.js` to Typescript This is mostly a straightforward conversion of `cards/disk2.js` to Typescript, with the following exceptions: * `setState()` did not restore the drive light state correctly because the callback was called with the old `on` value. * `setPhase()` did not work for WOZ images. * `getBinary()` did not work for `nib` files. * `getBase64()` did not work for `nib` files and maybe didn't work right at all. Even with these fixes, local storage still doesn't work correctly. I have also added several TODOs where methods don't support WOZ disks. * Convert most uses of `memory` to `Uint8Array` There are many places in the existing code where we use `Uint8Array` directly. This change merely makes the `memory` type equivalent to `Uint8Array`. This change also changes most ROM data to be read-only in Typescript to ensure that it is not modified by mistake. This can't be done just by applying `as const` to the declaration because `Uint8Array`s are can not be expressed as literals. Instead, we create a new type, `ReadonlyUint8Array` that drops the mutation methods and makes indexed access read-only. See https://www.growingwiththeweb.com/2020/10/typescript-readonly-typed-arrays.html for details. * Tighten types and document `disk2.ts` While trying to understand the Disk ][ emulation, I tighted the types and documented the parts that I could, including references to other sources, like _Understanding the Apple //e_ by Jim Sather. The one functional change is the addition of the P6 ROM of DOS 3.2 and earlier. This is automatically selected if the card is initialized for 13 sector disks.
2021-02-08 04:50:50 +00:00
readOnly: boolean,
dirty: boolean,
}
/**
* DOS 3.3 Physical sector order (index is physical sector, value is DOS sector).
*/
export const DO = [
0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4,
0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF
];
/**
* DOS 3.3 Logical sector order (index is DOS sector, value is physical sector).
*/
export const _DO = [
0x0, 0xD, 0xB, 0x9, 0x7, 0x5, 0x3, 0x1,
0xE, 0xC, 0xA, 0x8, 0x6, 0x4, 0x2, 0xF
];
/**
* ProDOS Physical sector order (index is physical sector, value is ProDOS sector).
*/
export const PO = [
0x0, 0x8, 0x1, 0x9, 0x2, 0xa, 0x3, 0xb,
0x4, 0xc, 0x5, 0xd, 0x6, 0xe, 0x7, 0xf
];
/**
* ProDOS Logical sector order (index is ProDOS sector, value is physical sector).
*/
export const _PO = [
0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe,
0x1, 0x3, 0x5, 0x7, 0x9, 0xb, 0xd, 0xf
];
/**
* DOS 13-sector disk physical sector order (index is disk sector, value is
* physical sector).
*/
export const D13O = [
0x0, 0xa, 0x7, 0x4, 0x1, 0xb, 0x8, 0x5, 0x2, 0xc, 0x9, 0x6, 0x3
];
export const _D13O = [
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc
];
const _trans53 = [
0xab, 0xad, 0xae, 0xaf, 0xb5, 0xb6, 0xb7, 0xba,
0xbb, 0xbd, 0xbe, 0xbf, 0xd6, 0xd7, 0xda, 0xdb,
0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xed, 0xee, 0xef,
0xf5, 0xf6, 0xf7, 0xfa, 0xfb, 0xfd, 0xfe, 0xff
];
const _trans62 = [
0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6,
0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3,
0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc,
0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3,
0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde,
0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec,
0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
];
export const detrans62 = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x02, 0x03, 0x00, 0x04, 0x05, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08,
0x00, 0x00, 0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
0x00, 0x00, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13,
0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1B, 0x00, 0x1C, 0x1D, 0x1E,
0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x20, 0x21,
0x00, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x2A, 0x2B,
0x00, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
0x00, 0x00, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x00, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
];
/**
* From Beneath Apple DOS
*/
export function fourXfour(val: byte): [xx: byte, yy: byte] {
2020-11-24 16:53:43 +00:00
let xx = val & 0xaa;
let yy = val & 0x55;
xx >>= 1;
xx |= 0xaa;
yy |= 0xaa;
return [xx, yy];
}
export function defourXfour(xx: byte, yy: byte): byte {
return ((xx << 1) | 0x01) & yy;
}
export function explodeSector16(volume: byte, track: byte, sector: byte, data: memory) {
let buf = [];
let gap;
/*
* Gap 1/3 (40/0x28 bytes)
*/
if (sector === 0) // Gap 1
gap = 0x80;
else { // Gap 3
gap = track === 0 ? 0x28 : 0x26;
}
for (let idx = 0; idx < gap; idx++) {
buf.push(0xff);
}
/*
* Address Field
*/
2020-11-24 16:53:43 +00:00
const checksum = volume ^ track ^ sector;
buf = buf.concat([0xd5, 0xaa, 0x96]); // Address Prolog D5 AA 96
buf = buf.concat(fourXfour(volume));
buf = buf.concat(fourXfour(track));
buf = buf.concat(fourXfour(sector));
buf = buf.concat(fourXfour(checksum));
buf = buf.concat([0xde, 0xaa, 0xeb]); // Epilog DE AA EB
/*
* Gap 2 (5 bytes)
*/
for (let idx = 0; idx < 0x05; idx++) {
buf.push(0xff);
}
/*
* Data Field
*/
buf = buf.concat([0xd5, 0xaa, 0xad]); // Data Prolog D5 AA AD
2020-11-24 16:53:43 +00:00
const nibbles: byte[] = [];
const ptr2 = 0;
const ptr6 = 0x56;
for (let idx = 0; idx < 0x156; idx++) {
nibbles[idx] = 0;
}
let idx2 = 0x55;
for (let idx6 = 0x101; idx6 >= 0; idx6--) {
let val6 = data[idx6 % 0x100];
let val2: byte = nibbles[ptr2 + idx2];
val2 = (val2 << 1) | (val6 & 1);
val6 >>= 1;
val2 = (val2 << 1) | (val6 & 1);
val6 >>= 1;
nibbles[ptr6 + idx6] = val6;
nibbles[ptr2 + idx2] = val2;
if (--idx2 < 0)
idx2 = 0x55;
}
let last = 0;
for (let idx = 0; idx < 0x156; idx++) {
const val = nibbles[idx];
buf.push(_trans62[last ^ val]);
last = val;
}
buf.push(_trans62[last]);
buf = buf.concat([0xde, 0xaa, 0xeb]); // Epilog DE AA EB
/*
* Gap 3
*/
buf.push(0xff);
return buf;
}
export function explodeSector13(volume: byte, track: byte, sector: byte, data: byte[]) {
let buf = [];
let gap;
/*
* Gap 1/3 (40/0x28 bytes)
*/
if (sector === 0) // Gap 1
gap = 0x80;
else { // Gap 3
gap = track === 0 ? 0x28 : 0x26;
}
for (let idx = 0; idx < gap; idx++) {
buf.push(0xff);
}
/*
* Address Field
*/
2020-11-24 16:53:43 +00:00
const checksum = volume ^ track ^ sector;
buf = buf.concat([0xd5, 0xaa, 0xb5]); // Address Prolog D5 AA B5
buf = buf.concat(fourXfour(volume));
buf = buf.concat(fourXfour(track));
buf = buf.concat(fourXfour(sector));
buf = buf.concat(fourXfour(checksum));
buf = buf.concat([0xde, 0xaa, 0xeb]); // Epilog DE AA EB
/*
* Gap 2 (5 bytes)
*/
for (let idx = 0; idx < 0x05; idx++) {
buf.push(0xff);
}
/*
* Data Field
*/
buf = buf.concat([0xd5, 0xaa, 0xad]); // Data Prolog D5 AA AD
2020-11-24 16:53:43 +00:00
const nibbles = [];
let jdx = 0;
for (let idx = 0x32; idx >= 0; idx--) {
2020-11-24 16:53:43 +00:00
const a5 = data[jdx] >> 3;
const a3 = data[jdx] & 0x07;
jdx++;
2020-11-24 16:53:43 +00:00
const b5 = data[jdx] >> 3;
const b3 = data[jdx] & 0x07;
jdx++;
2020-11-24 16:53:43 +00:00
const c5 = data[jdx] >> 3;
const c3 = data[jdx] & 0x07;
jdx++;
2020-11-24 16:53:43 +00:00
const d5 = data[jdx] >> 3;
const d3 = data[jdx] & 0x07;
jdx++;
2020-11-24 16:53:43 +00:00
const e5 = data[jdx] >> 3;
const e3 = data[jdx] & 0x07;
jdx++;
nibbles[idx + 0x00] = a5;
nibbles[idx + 0x33] = b5;
nibbles[idx + 0x66] = c5;
nibbles[idx + 0x99] = d5;
nibbles[idx + 0xcc] = e5;
nibbles[idx + 0x100] = a3 << 2 | (d3 & 0x4) >> 1 | (e3 & 0x4) >> 2;
nibbles[idx + 0x133] = b3 << 2 | (d3 & 0x2) | (e3 & 0x2) >> 1;
nibbles[idx + 0x166] = c3 << 2 | (d3 & 0x1) << 1 | (e3 & 0x1);
}
nibbles[0xff] = data[jdx] >> 3;
nibbles[0x199] = data[jdx] & 0x07;
let last = 0;
for (let idx = 0x199; idx >= 0x100; idx--) {
const val = nibbles[idx];
buf.push(_trans53[last ^ val]);
last = val;
}
for (let idx = 0x0; idx < 0x100; idx++) {
const val = nibbles[idx];
buf.push(_trans53[last ^ val]);
last = val;
}
buf.push(_trans53[last]);
buf = buf.concat([0xde, 0xaa, 0xeb]); // Epilog DE AA EB
/*
* Gap 3
*/
buf.push(0xff);
return buf;
}
Convert `cards/disk2.js` to Typescript (#54) * Convert `cards/disk2.js` to Typescript This is mostly a straightforward conversion of `cards/disk2.js` to Typescript, with the following exceptions: * `setState()` did not restore the drive light state correctly because the callback was called with the old `on` value. * `setPhase()` did not work for WOZ images. * `getBinary()` did not work for `nib` files. * `getBase64()` did not work for `nib` files and maybe didn't work right at all. Even with these fixes, local storage still doesn't work correctly. I have also added several TODOs where methods don't support WOZ disks. * Convert most uses of `memory` to `Uint8Array` There are many places in the existing code where we use `Uint8Array` directly. This change merely makes the `memory` type equivalent to `Uint8Array`. This change also changes most ROM data to be read-only in Typescript to ensure that it is not modified by mistake. This can't be done just by applying `as const` to the declaration because `Uint8Array`s are can not be expressed as literals. Instead, we create a new type, `ReadonlyUint8Array` that drops the mutation methods and makes indexed access read-only. See https://www.growingwiththeweb.com/2020/10/typescript-readonly-typed-arrays.html for details. * Tighten types and document `disk2.ts` While trying to understand the Disk ][ emulation, I tighted the types and documented the parts that I could, including references to other sources, like _Understanding the Apple //e_ by Jim Sather. The one functional change is the addition of the P6 ROM of DOS 3.2 and earlier. This is automatically selected if the card is initialized for 13 sector disks.
2021-02-08 04:50:50 +00:00
// TODO(flan): Does not work on WOZ disks
export function readSector(drive: Drive, track: byte, sector: byte) {
2020-11-24 16:53:43 +00:00
const _sector = drive.format == 'po' ? _PO[sector] : _DO[sector];
let val, state = 0;
let idx = 0;
let retry = 0;
2020-11-24 16:53:43 +00:00
const cur = drive.tracks[track];
function _readNext() {
2020-11-24 16:53:43 +00:00
const result = cur[idx++];
if (idx >= cur.length) {
idx = 0;
retry++;
}
return result;
}
function _skipBytes(count: number) {
idx += count;
if (idx >= cur.length) {
idx %= cur.length;
retry++;
}
}
let t = 0, s = 0, v = 0, checkSum;
Convert `cards/disk2.js` to Typescript (#54) * Convert `cards/disk2.js` to Typescript This is mostly a straightforward conversion of `cards/disk2.js` to Typescript, with the following exceptions: * `setState()` did not restore the drive light state correctly because the callback was called with the old `on` value. * `setPhase()` did not work for WOZ images. * `getBinary()` did not work for `nib` files. * `getBase64()` did not work for `nib` files and maybe didn't work right at all. Even with these fixes, local storage still doesn't work correctly. I have also added several TODOs where methods don't support WOZ disks. * Convert most uses of `memory` to `Uint8Array` There are many places in the existing code where we use `Uint8Array` directly. This change merely makes the `memory` type equivalent to `Uint8Array`. This change also changes most ROM data to be read-only in Typescript to ensure that it is not modified by mistake. This can't be done just by applying `as const` to the declaration because `Uint8Array`s are can not be expressed as literals. Instead, we create a new type, `ReadonlyUint8Array` that drops the mutation methods and makes indexed access read-only. See https://www.growingwiththeweb.com/2020/10/typescript-readonly-typed-arrays.html for details. * Tighten types and document `disk2.ts` While trying to understand the Disk ][ emulation, I tighted the types and documented the parts that I could, including references to other sources, like _Understanding the Apple //e_ by Jim Sather. The one functional change is the addition of the P6 ROM of DOS 3.2 and earlier. This is automatically selected if the card is initialized for 13 sector disks.
2021-02-08 04:50:50 +00:00
const data = new Uint8Array(256);
while (retry < 4) {
switch (state) {
case 0:
val = _readNext();
state = (val === 0xd5) ? 1 : 0;
break;
case 1:
val = _readNext();
state = (val === 0xaa) ? 2 : 0;
break;
case 2:
val = _readNext();
state = (val === 0x96) ? 3 : (val === 0xad ? 4 : 0);
break;
case 3: // Address
v = defourXfour(_readNext(), _readNext()); // Volume
t = defourXfour(_readNext(), _readNext());
s = defourXfour(_readNext(), _readNext());
checkSum = defourXfour(_readNext(), _readNext());
if (checkSum != (v ^ t ^ s)) {
debug('Invalid header checksum:', toHex(v), toHex(t), toHex(s), toHex(checkSum));
}
_skipBytes(3); // Skip footer
state = 0;
break;
case 4: // Data
if (s === _sector && t === track) {
const data2 = [];
let last = 0;
for (let jdx = 0x55; jdx >= 0; jdx--) {
val = detrans62[_readNext() - 0x80] ^ last;
data2[jdx] = val;
last = val;
}
for (let jdx = 0; jdx < 0x100; jdx++) {
val = detrans62[_readNext() - 0x80] ^ last;
data[jdx] = val;
last = val;
}
checkSum = detrans62[_readNext() - 0x80] ^ last;
if (checkSum) {
debug('Invalid data checksum:', toHex(v), toHex(t), toHex(s), toHex(checkSum));
}
for (let kdx = 0, jdx = 0x55; kdx < 0x100; kdx++) {
data[kdx] <<= 1;
if ((data2[jdx] & 0x01) !== 0) {
data[kdx] |= 0x01;
}
data2[jdx] >>= 1;
data[kdx] <<= 1;
if ((data2[jdx] & 0x01) !== 0) {
data[kdx] |= 0x01;
}
data2[jdx] >>= 1;
if (--jdx < 0) jdx = 0x55;
}
return data;
}
else
_skipBytes(0x159); // Skip data, checksum and footer
state = 0;
break;
default:
break;
}
}
Convert `cards/disk2.js` to Typescript (#54) * Convert `cards/disk2.js` to Typescript This is mostly a straightforward conversion of `cards/disk2.js` to Typescript, with the following exceptions: * `setState()` did not restore the drive light state correctly because the callback was called with the old `on` value. * `setPhase()` did not work for WOZ images. * `getBinary()` did not work for `nib` files. * `getBase64()` did not work for `nib` files and maybe didn't work right at all. Even with these fixes, local storage still doesn't work correctly. I have also added several TODOs where methods don't support WOZ disks. * Convert most uses of `memory` to `Uint8Array` There are many places in the existing code where we use `Uint8Array` directly. This change merely makes the `memory` type equivalent to `Uint8Array`. This change also changes most ROM data to be read-only in Typescript to ensure that it is not modified by mistake. This can't be done just by applying `as const` to the declaration because `Uint8Array`s are can not be expressed as literals. Instead, we create a new type, `ReadonlyUint8Array` that drops the mutation methods and makes indexed access read-only. See https://www.growingwiththeweb.com/2020/10/typescript-readonly-typed-arrays.html for details. * Tighten types and document `disk2.ts` While trying to understand the Disk ][ emulation, I tighted the types and documented the parts that I could, including references to other sources, like _Understanding the Apple //e_ by Jim Sather. The one functional change is the addition of the P6 ROM of DOS 3.2 and earlier. This is automatically selected if the card is initialized for 13 sector disks.
2021-02-08 04:50:50 +00:00
return new Uint8Array();
}
export function jsonEncode(cur: Drive, pretty: boolean) {
// For 'nib', tracks are encoded as strings. For all other formats,
// tracks are arrays of sectors which are encoded as strings.
2020-11-24 16:53:43 +00:00
const data: string[] | string[][] = [];
let format = 'dsk';
for (let t = 0; t < cur.tracks.length; t++) {
data[t] = [];
if (cur.format === 'nib') {
format = 'nib';
data[t] = base64_encode(cur.tracks[t]);
} else {
2020-11-24 16:53:43 +00:00
for (let s = 0; s < 0x10; s++) {
(data[t] as string[])[s] = base64_encode(readSector(cur, t, s));
}
}
}
return JSON.stringify({
'type': format,
'encoding': 'base64',
'volume': cur.volume,
'data': data,
'readOnly': cur.readOnly,
}, undefined, pretty ? ' ' : undefined);
}
export function jsonDecode(data: string) {
2020-11-24 16:53:43 +00:00
const tracks: memory[] = [];
const json = JSON.parse(data);
const v = json.volume;
const readOnly = json.readOnly;
for (let t = 0; t < json.data.length; t++) {
let track: byte[] = [];
for (let s = 0; s < json.data[t].length; s++) {
2020-11-24 16:53:43 +00:00
const _s = 15 - s;
const sector: string = json.data[t][_s];
const d = base64_decode(sector);
track = track.concat(explodeSector16(v, t, s, d));
}
tracks[t] = bytify(track);
}
2020-11-24 16:53:43 +00:00
const cur: Drive = {
volume: v,
format: json.type,
tracks,
readOnly,
dirty: false,
};
return cur;
}