diff options
author | B. Watson <urchlay@slackware.uk> | 2022-08-29 16:11:13 -0400 |
---|---|---|
committer | B. Watson <urchlay@slackware.uk> | 2022-08-29 16:11:13 -0400 |
commit | e2ba8458a5cfdfacfaf103e7ba97d610afa6c970 (patch) | |
tree | cd665e602e6e2b636578a7d3d7894380605dafcc /atr2xfd.c | |
download | bw-atari8-tools-e2ba8458a5cfdfacfaf103e7ba97d610afa6c970.tar.gz |
initial commit
Diffstat (limited to 'atr2xfd.c')
-rw-r--r-- | atr2xfd.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/atr2xfd.c b/atr2xfd.c new file mode 100644 index 0000000..c941266 --- /dev/null +++ b/atr2xfd.c @@ -0,0 +1,244 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +#ifndef VERSION +#define VERSION "???" +#endif + +#define SELF "atr2xfd" +#define CHECK "atrcheck" + +int main(int argc, char **argv) { + char *type; + char *self = SELF; + struct stat st; + char infile[4096], outfile[4096]; + unsigned char buf[16]; + FILE *in, *out; + int i, paras, hparas, secsize, seccount; + int checkonly = 0, bytes = 0; + + if(strstr(argv[0], CHECK)) { + self = CHECK; + checkonly = 1; + } + + if(argc < 2 || argc > 3) { + fprintf(stderr, + "%s v" VERSION " by B. Watson (WTFPL)\n", self); + fprintf(stderr, + "Usage: %s input.xfd%s\n", + self, + (checkonly ? "" : " [output.atr]")); + exit(1); + } + + strcpy(infile, argv[1]); + if(argc == 3) { + strcpy(outfile, argv[2]); + if(checkonly) + fprintf(stderr, + "%s: output file not used with %s (ignoring it).\n", + self, self); + } else if(strcmp(infile, "-") == 0) { + strcpy(outfile, "-"); + } else { + char *p; + strcpy(outfile, argv[1]); + + p = strstr(outfile, ".atr"); + if(!p) p = strstr(outfile, ".ATR"); + if(!p) p = outfile + strlen(outfile); + strcpy(p, ".xfd"); + } + + if(!checkonly) + fprintf(stderr, "%s: input '%s', output '%s'\n", self, infile, outfile); + + if(strcmp(infile, "-") == 0) { + in = stdin; + } else { + if( !(in = fopen(infile, "rb")) ) { + fprintf(stderr, "%s: (fatal) can't read %s: %s\n", + self, infile, strerror(errno)); + exit(1); + } + } + + if(fstat(fileno(in), &st)) { + fprintf(stderr, "%s: (fatal) can't stat %s: %s\n", + self, infile, strerror(errno)); + exit(1); + } + + /* A few sanity checks... */ + if(st.st_size < 400) { + fprintf(stderr, + "%s: (fatal) %s too small to be an ATR image (<400 bytes)\n", + self, infile); + exit(2); + } + + if(st.st_size % 128 == 0 ) { + fprintf(stderr, + "%s: (fatal) %s looks like an XFD image, not an ATR\n", + self, infile); + exit(2); + } + + if( (st.st_size - 16) % 128 != 0 ) { + fprintf(stderr, + "%s: (fatal) %s not a valid ATR image (not an even number " + "of sectors)\n", + self, infile); + exit(2); + } + + if(st.st_size > (65535 * 256)) { + fprintf(stderr, + "%s: (fatal) %s too large to be an ATR image (>16M)\n", + self, infile); + exit(2); + } + + paras = st.st_size / 16 - 1; + fprintf(stderr, "%s: size is %d 16-byte paragraphs\n", self, paras); + + if(fread(buf, 1, 16, in) != 16) { + fprintf(stderr, + "%s: (fatal) can't read ATR header from %s: %s\n", + self, infile, strerror(errno)); + exit(1); + } + + if( !(buf[0] == 0x96 && buf[1] == 0x02) ) { + fprintf(stderr, + "%s: (fatal) %s not an ATR file (no NICKATARI signature)!\n", + self, infile); + exit(2); + } + + secsize = buf[4] + (buf[5] << 8); + + if( !(secsize == 128 || secsize == 256) ) { + fprintf(stderr, + "%s: (fatal) %s has invalid sector size %d\n", + self, infile, secsize); + exit(2); + } + + if(secsize == 128) + seccount = (st.st_size - 16) / secsize; + else { + seccount = (st.st_size - 400) / secsize + 3; + if((st.st_size - 16) % 256 != 128) + fprintf(stderr, "%s: partial sector at end of DD image, might " + "be a truncated or bogus ATR.\n", self); + } + + fprintf(stderr, + "%s: sectors: %d, sector size: %d bytes", + self, seccount, secsize); + + if(secsize == 256) + fprintf(stderr, " (first 3 sectors are 128 bytes)"); + fputc('\n', stderr); + + if(secsize == 128) { + if(seccount < 720) + type = "short SS/SD image, <90K"; + else if(seccount == 720) + type = "standard SS/SD image, 90K"; + else if(seccount == 1040) + type = "1050 SS/ED image, 130K"; + else if(seccount == 1440) + type = "XF551 DS/SD image, 180K"; + else + type = "high-capacity floppy or hard disk image, SD"; + } else { + if(seccount < 720) + type = "short SS/DD image, <180K"; + else if(seccount == 720) + type = "standard SS/DD image, 180K"; + else if(seccount == 1440) + type = "XF551 DS/DD or ATR8000 SS/QD image, 360K"; + else if(seccount == 2880) + type = "ATR8000 DS/QD or SS/PC image, 720K"; + else if(seccount == 5760) + type = "ATR8000 PC 1.44M image, 1440K"; + else + type = "high-capacity floppy or hard disk image, DD"; + } + + fprintf(stderr, "%s: %s is a %s\n", self, infile, type); + + fprintf(stderr, "%s: ATR image OK (no fatal errors).\n", self); + + hparas = buf[2] + (buf[3] << 8) + (buf[6] << 16); + if(hparas != paras) { + /* this is only a fatal error if checkonly is true */ + fprintf(stderr, + "%s: (%s) %s file size (%d paragraphs) doesn't agree with " + "ATR header (%d paragraphs). File may be truncated or corrupt.\n", + self, + (checkonly ? "fatal" : "warning"), + infile, paras, hparas); + + if(checkonly) + exit(1); + + fprintf(stderr, + "%s: Using actual file size for XFD image; expect trouble.\n", + self); + } + + if(checkonly) + exit(0); + + /* Only open the output file after the ATR is known to be good */ + if(strcmp(outfile, "-") == 0) { + out = stdout; + } else { + if( !(out = fopen(outfile, "wb")) ) { + fprintf(stderr, + "%s: (fatal) can't write %s: %s\n", + self, outfile, strerror(errno)); + exit(1); + } + } + + /* copy the data */ + while( (i = fgetc(in)) != EOF ) { + fputc(i, out); + bytes++; + } + + /* fputc() returns EOF on error *or* EOF; + check for I/O errors, return 1 if so */ + i = 0; + + if(ferror(in)) { + i = 1; + fprintf(stderr, + "%s: error reading %s: %s\n", self, infile, strerror(errno)); + } + + if(ferror(out)) { + i = 1; + fprintf(stderr, + "%s: error writing %s: %s\n", self, outfile, strerror(errno)); + } + + fclose(in); + fclose(out); + + if(!i) + fprintf(stderr, "%s: XFD image OK, wrote %d bytes\n", self, bytes); + + return i; +} |