#!/usr/bin/env node const fs = require('fs'); const argv = require('yargs').argv; function numToString(num) { let result = ''; for (let idx = 0; idx < 4; idx++) { result += String.fromCharCode(num & 0xff); num >>= 8; } return result; } function read2MG(fileData) { const dv = new DataView(fileData.buffer); // Magic const magic = dv.getUint32(0, true); console.error('Magic', numToString(magic)); // Creator const creator = dv.getUint32(4, true); console.error('Creator:', numToString(creator)); // Header Length const headerLength = dv.getUint16(8, true); console.error('Header length:', headerLength); // Version const version = dv.getUint16(10, true); console.error('Version:', version); // Image format const format = dv.getUint32(12, true); const type = format === 0 ? 'dsk' : 'po'; console.error('Format:', format, type); // Flags const flags = dv.getUint32(16, true); const readOnly = flags & 0x80000000 ? true : undefined; console.error('Flags:', flags.toString(2), readOnly); return { diskData: fileData.slice(headerLength), type: type, readOnly: readOnly, }; } function readTracks(type, diskData) { const tracks = []; if (type === 'nib') { let start = 0; let end = 0x1a00; while (start < diskData.length) { const trackData = diskData.slice(start, end); start += 0x1a00; end += 0x1a00; tracks.push(trackData.toString('base64')); } } else { let start = 0; let end = 0x100; const numSectors = type === 'd13' ? 13 : 16; for (let track = 0; track < 35; track++) { const sectors = []; for (let sector = 0; sector < numSectors; sector++) { const sectorData = diskData.slice(start, end); start += 0x100; end += 0x100; sectors.push(sectorData.toString('base64')); } tracks.push(sectors); } } return tracks; } const fileName = argv._[0]; let readOnly = argv.r || argv.readOnly ? true : undefined; const name = argv.n || argv.name; const category = argv.c || argv.category; const disk = argv.d || argv.disk; const e = argv.e ? true : undefined; if (!name || !category || !fileName || argv.h || argv.help) { console.error('dsk2json [-c category] [-n name] [-t type] imagefile'); process.exit(0); } let type = 'dsk'; const match = /\.([a-z0-9]+)$/.exec(fileName); if (match && match.length > 1) { type = match[1]; } type = argv.t || argv.type || type; fs.readFile(fileName, (err, fileData) => { if (err) { console.error('Unable to read disk image'); process.exit(1); } let diskData; if (type === '2mg') { ({ diskData, readOnly, type } = read2MG(fileData)); } else { diskData = fileData; } const entry = { name, type, category, encoding: 'base64', readOnly, disk, '2e': e, data: readTracks(type, diskData), }; Object.keys(entry).forEach((key) => { if (entry[key] === undefined) delete entry[key]; }); console.log(JSON.stringify(entry, null, 4)); });