mirror of
https://github.com/whscullin/apple2js.git
synced 2024-01-12 14:14:38 +00:00
Port tools to node.
This commit is contained in:
parent
d5ab930935
commit
dbc2315552
@ -26,5 +26,18 @@
|
|||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"sourceType": "module"
|
"sourceType": "module"
|
||||||
},
|
},
|
||||||
"extends": "eslint:recommended"
|
"extends": "eslint:recommended",
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": [ "bin/*", "webpack.config.js" ],
|
||||||
|
"rules": {
|
||||||
|
"no-console": 0
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"node": true,
|
||||||
|
"jquery": false,
|
||||||
|
"browser": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
133
bin/dsk2json
Executable file
133
bin/dsk2json
Executable file
@ -0,0 +1,133 @@
|
|||||||
|
#!/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));
|
||||||
|
});
|
32
bin/index
Executable file
32
bin/index
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const diskPath = path.resolve('json/disks');
|
||||||
|
const dir = fs.readdirSync(diskPath);
|
||||||
|
|
||||||
|
const index = [];
|
||||||
|
|
||||||
|
for (const fileName of dir.sort()) {
|
||||||
|
if (/\.json$/.test(fileName)) {
|
||||||
|
const json = fs.readFileSync(path.resolve(diskPath, fileName));
|
||||||
|
const data = JSON.parse(json);
|
||||||
|
if (data.private) { continue; }
|
||||||
|
|
||||||
|
const entry = {
|
||||||
|
filename: `json/disks/${fileName}`,
|
||||||
|
e: data['2e'],
|
||||||
|
name: data.name,
|
||||||
|
disk: data.disk,
|
||||||
|
category: data.category,
|
||||||
|
};
|
||||||
|
index.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.resolve(diskPath, 'index.js'),
|
||||||
|
`disk_index = ${JSON.stringify(index, null, 2)};`
|
||||||
|
);
|
@ -1,132 +0,0 @@
|
|||||||
#!/usr/bin/perl -w
|
|
||||||
# Copyright 2010-2016 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.
|
|
||||||
|
|
||||||
use MIME::Base64 qw(encode_base64);
|
|
||||||
use Getopt::Std;
|
|
||||||
|
|
||||||
$Getopt::Std::STANDARD_HELP_VERSION = 1;
|
|
||||||
|
|
||||||
my %opts;
|
|
||||||
getopts('rn:c:t:', \%opts);
|
|
||||||
|
|
||||||
sub HELP_MESSAGE() {
|
|
||||||
my $fh = shift;
|
|
||||||
print $fh "dsk2js.pl [-c category] [-n name] [-t type] imagefile\n"
|
|
||||||
};
|
|
||||||
sub VERSION_MESSAGE() { my $fh = shift; print $fh "Version 1.0\n" };
|
|
||||||
|
|
||||||
open(DISK, $ARGV[0]) or die $!;
|
|
||||||
binmode(DISK);
|
|
||||||
|
|
||||||
my ($name, $ext) = $ARGV[0] =~ /([^\/]+)\.(dsk|po|2mg)$/i;
|
|
||||||
my $rv;
|
|
||||||
my $buffer;
|
|
||||||
my $readOnly = 0;
|
|
||||||
my $volume = 0;
|
|
||||||
|
|
||||||
my $category = "Misc";
|
|
||||||
|
|
||||||
$name = $opts{'n'} if ($opts{'n'});
|
|
||||||
$category = $opts{'c'} if ($opts{'c'});
|
|
||||||
$ext = $opts{'t'} if ($opts{'t'});
|
|
||||||
if ($opts{'r'}) {
|
|
||||||
$readOnly = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$ext = lc($ext);
|
|
||||||
|
|
||||||
my $tmp;
|
|
||||||
my $offset = 0;
|
|
||||||
|
|
||||||
if ($ext eq '2mg') {
|
|
||||||
# $rv = read(DISK, $buffer, 0x40);
|
|
||||||
# Format
|
|
||||||
$offset += read(DISK, $buffer, 0x04);
|
|
||||||
$tmp = unpack("a[4]", $buffer);
|
|
||||||
if ($tmp ne '2IMG') {
|
|
||||||
print STDERR "Invalid format";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Creator
|
|
||||||
$offset += read(DISK, $buffer, 0x04);
|
|
||||||
$tmp = unpack("a[4]", $buffer);
|
|
||||||
print STDERR "Creator: " . $tmp . "\n";
|
|
||||||
|
|
||||||
# Header Length
|
|
||||||
$offset += read(DISK, $buffer, 0x02);
|
|
||||||
my $header_length = unpack("v", $buffer);
|
|
||||||
|
|
||||||
# Version Number
|
|
||||||
$offset += read(DISK, $buffer, 0x02);
|
|
||||||
my $version_number = unpack("v", $buffer);
|
|
||||||
if ($version_number != 1) {
|
|
||||||
print STDERR "Unknown version: " . $version_number . "\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Image Format
|
|
||||||
$offset += read(DISK, $buffer, 0x04);
|
|
||||||
my $image_format = unpack("V", $buffer);
|
|
||||||
if ($image_format == 0) {
|
|
||||||
$ext = "dsk";
|
|
||||||
} elsif ($image_format == 1) {
|
|
||||||
$ext = "po";
|
|
||||||
} else {
|
|
||||||
print STDERR "Handled image format: " . $image_format;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
print STDERR "Format: " . $ext . "\n";
|
|
||||||
|
|
||||||
# Flags
|
|
||||||
$offset += read(DISK, $buffer, 0x04);
|
|
||||||
my $flags = unpack("V", $buffer);
|
|
||||||
if ($flags & 0x80000000) {
|
|
||||||
$readOnly = 1;
|
|
||||||
}
|
|
||||||
if ($flags & 0x100) {
|
|
||||||
$volume = $flags & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
$rv = read(DISK, $buffer, $header_length - $offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
my $sector = 0;
|
|
||||||
my $track = 0;
|
|
||||||
|
|
||||||
print "{\n";
|
|
||||||
print " \"name\": \"$name\",\n";
|
|
||||||
print " \"type\": \"$ext\",\n";
|
|
||||||
print " \"category\": \"$category\",\n";
|
|
||||||
print " \"encoding\": \"base64\",\n";
|
|
||||||
if ($readOnly) {
|
|
||||||
print " \"readOnly\": true,\n";
|
|
||||||
}
|
|
||||||
if ($volume) {
|
|
||||||
print " \"volume\": \"$volume\",\n";
|
|
||||||
}
|
|
||||||
print " \"data\":\n";
|
|
||||||
print "[\n";
|
|
||||||
for ($track = 0; $track < 0x23; $track++) {
|
|
||||||
print ",\n" if ($track != 0);
|
|
||||||
print " [\n";
|
|
||||||
for ($sector = 0; $sector < 0x10; $sector++) {
|
|
||||||
print ",\n" if ($sector != 0);
|
|
||||||
$rv = read(DISK, $buffer, 0x100);
|
|
||||||
print " \"";
|
|
||||||
print encode_base64($buffer, "");
|
|
||||||
print "\"";
|
|
||||||
}
|
|
||||||
print "\n ]";
|
|
||||||
}
|
|
||||||
print "\n]}\n";
|
|
||||||
|
|
||||||
close(DISK);
|
|
@ -1,61 +0,0 @@
|
|||||||
#!/usr/bin/env perl -w
|
|
||||||
# Copyright 2010-2016 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.
|
|
||||||
|
|
||||||
use MIME::Base64 qw(encode_base64);
|
|
||||||
use JSON qw(from_json);
|
|
||||||
use Data::Dumper;
|
|
||||||
use Getopt::Std;
|
|
||||||
|
|
||||||
my $disk;
|
|
||||||
my @disks = ();
|
|
||||||
|
|
||||||
my %opts;
|
|
||||||
getopts('pe', \%opts);
|
|
||||||
|
|
||||||
while (<json/disks/*.json>) {
|
|
||||||
my $json;
|
|
||||||
my $fn = $_;
|
|
||||||
print STDERR "$fn\n";
|
|
||||||
open(DISK, $fn) or die $!;
|
|
||||||
while (<DISK>) {
|
|
||||||
my $line = $_;
|
|
||||||
|
|
||||||
$json .= $line;
|
|
||||||
}
|
|
||||||
close(DISK);
|
|
||||||
|
|
||||||
$disk = from_json($json);
|
|
||||||
$disk->{'filename'} = $fn;
|
|
||||||
$disk->{'data'} = NULL;
|
|
||||||
|
|
||||||
push(@disks, $disk);
|
|
||||||
}
|
|
||||||
|
|
||||||
@disks = sort { $a->{'category'} . $a->{'name'} cmp $b->{'category'} . $b->{'name'} } @disks;
|
|
||||||
|
|
||||||
my $first = 1;
|
|
||||||
print "disk_index = [\n";
|
|
||||||
foreach $disk (@disks) {
|
|
||||||
next if $disk->{'private'} && !$opts{'p'};
|
|
||||||
next if $disk->{'2e'} && !$opts{'e'};
|
|
||||||
|
|
||||||
print ",\n" unless ($first);
|
|
||||||
print " {\n";
|
|
||||||
print " \"filename\": \"" . $disk->{'filename'} . "\",\n";
|
|
||||||
print " \"name\": \"" . $disk->{'name'} . "\",\n";
|
|
||||||
if ($disk->{'disk'}) {
|
|
||||||
print " \"disk\": \"" . $disk->{'disk'} . "\",\n";
|
|
||||||
}
|
|
||||||
print " \"category\": \"" . $disk->{'category'} . "\"\n";
|
|
||||||
print " }";
|
|
||||||
$first = 0;
|
|
||||||
}
|
|
||||||
print "\n];\n";
|
|
Loading…
x
Reference in New Issue
Block a user