Skip to content

Commit

Permalink
Add support for listing and extracting BAS2BOOT images.
Browse files Browse the repository at this point in the history
This is a single-file image that boots an Atari BASIC program.
  • Loading branch information
dmsc committed Apr 22, 2024
1 parent 81fe95c commit 323186c
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 4 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ SOURCES_lsatr=\
lsatr.c\
lssfs.c\
lsdos.c\
lsextra.c\
msg.c\

CFLAGS=-O2 -Wall
Expand Down
9 changes: 5 additions & 4 deletions src/lsatr.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "atr.h"
#include "compat.h"
#include "lsdos.h"
#include "lsextra.h"
#include "lssfs.h"
#include "msg.h"
#include <errno.h>
Expand Down Expand Up @@ -113,11 +114,11 @@ int main(int argc, char **argv)

int e = sfs_read(atr, atr_name, atari_list, lower_case, extract_files);
if( e )
{
e = dos_read(atr, atr_name, atari_list, lower_case, extract_files);
if( e )
show_msg("%s: ATR image format not supported.", atr_name);
}
if( e )
e = extra_read(atr, atr_name, atari_list, lower_case, extract_files);
if( e )
show_msg("%s: ATR image format not supported.", atr_name);
atr_free(atr);

return e;
Expand Down
186 changes: 186 additions & 0 deletions src/lsextra.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* Copyright (C) 2023 Daniel Serpell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>
*/
/*
* Extracts various simple boot formats.
*/
#include "lsextra.h"
#include "msg.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

static unsigned get_name(char *name, char *aname, const uint8_t *data, int max,
int lower_case)
{
unsigned l = 0;
unsigned a = 0;
int dot = 0;
memset(aname, ' ', max + 1);
aname[max + 1] = 0;
for( int i = 0; i < max; i++ )
{
uint8_t c = data[i];
if( c >= 'A' && c <= 'Z' && lower_case )
c = c - 'A' + 'a';
if( c == '.' )
{
// Store dot
dot = 1;
name[l++] = c;
while( a < 8 )
aname[a++] = ' ';
continue;
}
if( c < ' ' || c == '/' || c == '.' || c == '?' || c == '\\' || c == 96 ||
c > 'z' )
c = '_';
else if( c == ' ' )
continue;
if( i > 7 && !dot )
{
dot = 1;
name[l++] = '.';
aname[a++] = ' ';
}
name[l++] = c;
aname[a++] = c;
}
name[l] = 0;
return l;
}

static uint16_t read16(const uint8_t *p)
{
return (p == NULL) ? 0 : (p[0] | (p[1] << 8));
}

static int check_bas2boot(struct atr_image *atr)
{
// BAS2BOOT only supports 128 bytes per sector, and we must have
// at least one data sector
if( atr->sec_size != 128 || atr->sec_count < 2 )
return 0;

const uint8_t *sec1 = atr_data(atr, 1);
const uint8_t *sec2 = atr_data(atr, 2);

// Check boot count == 2 and load address == $700
if( read16(sec1) != 0x200 || read16(sec1 + 2) != 0x700 )
return 0;

// Check ID
if( memcmp(sec2 + 0x3C, "BAS2BOOT", 8) )
return 0;

// Ok, we have a BAS2BOOT file
return 1;
}

static void extract_bas2boot(struct atr_image *atr, int atari_list, int lower_case,
int extract_files)
{
// Get headers
const uint8_t *sec1 = atr_data(atr, 1);
const uint8_t *sec2 = atr_data(atr, 2);
// Get filename
char path[32], aname[32];
if( !get_name(path, aname, sec2 + 0x60, 12, lower_case) || !*path )
{
strcpy(path, "noname.bas");
strcpy(aname, "NONAME BAS");
}
// Adds '.BAS' if no extension is present
if( !strchr(path, '.') )
{
const char *ext = lower_case ? ".bas" : ".BAS";
strcat(path, ext);
memcpy(aname + 9, ext + 1, 3);
}

// Get data and length
unsigned fsize = read16(sec1 + 8);
uint8_t *fdata = check_malloc(fsize < 16 ? 16 : fsize);

// Read header and undo bad conversion for certain files
memcpy(fdata, sec2 + 0x72, 14);
for( int i = 2; i < 14; i += 2 )
{
int x = fdata[0] + fdata[1] * 256;
int y = fdata[i] + fdata[i + 1] * 256 + x;
fdata[i] = y & 0xFF;
fdata[i + 1] = y >> 8;
}
// Read rest of file
unsigned secnum = 3;
for( unsigned pos = 14; pos < fsize; pos += 128, secnum++ )
{
unsigned len = fsize - pos < 128 ? fsize - pos : 128;
const uint8_t *s = atr_data(atr, secnum);
if( !s )
memset(fdata + pos, 0, len);
else
memcpy(fdata + pos, s, len);
}

if( extract_files )
{
struct stat st;
fprintf(stderr, "%s\n", path);
// Check if file already exists:
if( 0 == stat(path, &st) )
show_error("%s: file already exists.", path);
// Create new file
int fd = creat(path, 0666);
if( fd == -1 )
show_error("%s: can´t create file, %s", path, strerror(errno));
if( fsize != write(fd, fdata, fsize) )
show_error("%s: can´t write file, %s", path, strerror(errno));
if( close(fd) )
show_error("%s: can´t write file, %s", path, strerror(errno));
}
else if( atari_list )
printf("%-12s %7u\n", aname, fsize);
else
printf("%8u\t\t%s\n", fsize, path);

free(fdata);
}

int extra_read(struct atr_image *atr, const char *atr_name, int atari_list,
int lower_case, int extract_files)
{
// Check BAS2BOOT
if( check_bas2boot(atr) )
{
if( atari_list )
printf("ATR image: %s\n"
"Image size: %u sectors of %u bytes\n"
"Volume: BAS2BOOT\n",
atr_name, atr->sec_count, atr->sec_size);
else
printf("%s: %u sectors of %u bytes, BAS2BOOT.\n", atr_name, atr->sec_count,
atr->sec_size);
extract_bas2boot(atr, atari_list, lower_case, extract_files);
return 0;
}

return 1;
}
24 changes: 24 additions & 0 deletions src/lsextra.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2024 Daniel Serpell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>
*/
/*
* Extracts various simple boot formats.
*/
#pragma once
#include "atr.h"

int extra_read(struct atr_image *atr, const char *atr_name, int atari_list,
int lower_case, int extract_files);

0 comments on commit 323186c

Please sign in to comment.