diff options
Diffstat (limited to 'xfd2atr.c')
-rw-r--r-- | xfd2atr.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/xfd2atr.c b/xfd2atr.c new file mode 100644 index 0000000..3fad55e --- /dev/null +++ b/xfd2atr.c @@ -0,0 +1,227 @@ +#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 "xfd2atr" + +#define USAGE \ + SELF " v" VERSION " by B. Watson (WTFPL)\n" \ + "Usage: " SELF " -[sd] input.xfd [output.atr]\n" + +int main(int argc, char **argv) { + struct stat st; + char infile[4096], outfile[4096]; + FILE *in, *out; + int i, paras, secsize = 0, seccount; + + if(argc < 2 || argc > 4) { + fprintf(stderr, USAGE); + exit(1); + } + + if(argv[1][0] == '-') { + switch(argv[1][1]) { + case 's': + secsize = 128; + break; + + case 'd': + secsize = 256; + break; + + default: + fprintf(stderr, + SELF ": invalid option -'%c'\n" USAGE, argv[1][1]); + } + + argv++; argc--; + } + + strcpy(infile, argv[1]); + if(argc == 3) { + strcpy(outfile, argv[2]); + } else if(strcmp(infile, "-") == 0) { + strcpy(outfile, "-"); + } else { + char *p; + strcpy(outfile, argv[1]); + + p = strstr(outfile, ".xfd"); + if(!p) p = strstr(outfile, ".XFD"); + if(!p) p = outfile + strlen(outfile); + strcpy(p, ".atr"); + } + + fprintf(stderr, SELF ": input '%s', output '%s'\n", infile, outfile); + + if(strcmp(infile, "-") == 0) { + in = stdin; + } else { + if( !(in = fopen(infile, "rb")) ) { + fprintf(stderr, SELF ": (fatal) can't read %s: %s\n", + infile, strerror(errno)); + exit(1); + } + } + + if(fstat(fileno(in), &st)) { + fprintf(stderr, SELF ": (fatal) can't stat %s: %s\n", + infile, strerror(errno)); + exit(1); + } + + /* A few sanity checks... */ + if(st.st_size < 384) { + fprintf(stderr, + SELF ": (fatal) %s too small to be an XFD image (<384 bytes)\n", + infile); + exit(2); + } + + if(st.st_size % 128 == 16) { + fprintf(stderr, + SELF ": (fatal) %s looks like an ATR image, not an XFD\n", + infile); + exit(2); + } + + if(st.st_size % 128 != 0) { + fprintf(stderr, + SELF ": (fatal) %s not a valid XFD image (not an even number " + "of sectors)\n", infile); + exit(2); + } + + if(st.st_size > (65535 * 256)) { + fprintf(stderr, SELF ": (fatal) %s too large to be an XFD image (>16M)\n", + infile); + exit(2); + } + + if(!secsize) { + char *type; + fprintf(stderr, SELF ": guessing type; use -s or -d to set.\n"); + + /* Automagically figure out the sector size and count */ + if(st.st_size == 720 * 128) { + type = "90K SS/SD image"; + secsize = 128; + } else if(st.st_size == 1040 * 128) { + type = "130K SS/ED image"; + secsize = 128; + } else if(st.st_size == 720 * 256 - 128 * 3) { + type = "180K SS/DD image"; + secsize = 256; + } else if(st.st_size == 1440 * 256 - 128 * 3) { + type = "360K DS/DD image"; + secsize = 256; + } else if(st.st_size < 720 * 128) { + type = "<90K image, assuming SD"; + secsize = 128; + } else if(st.st_size > 720 * 128 && st.st_size < 1040 * 128) { + type = ">90K, <130K image, assuming SD sectors"; + secsize = 128; + } else if(st.st_size % 256 == 0) { + fprintf(stderr, SELF ": Non-standard %dK image, assuming SD sectors\n", + (int)st.st_size / 1024); + type = "Large floppy or hard disk, SD"; + secsize = 128; + } else { + fprintf(stderr, SELF ": Non-standard %dK image, assuming DD sectors\n", + (int)st.st_size / 1024); + type = "Large floppy or hard disk, DD"; + secsize = 256; + } + + fprintf(stderr, SELF ": guessed type: %s\n", type); + } + + if(secsize == 128) { + seccount = st.st_size / secsize; + if(seccount & 1) + fprintf(stderr, SELF ": odd number of sectors in SD image, might " + "actually be DD (try with -d?)\n"); + } else { + seccount = (st.st_size - 384) / secsize + 3; + if(st.st_size % 256 != 128) + fprintf(stderr, SELF ": partial sector at end of DD image, might " + "actually be SD (try with -s?)\n"); + } + + /* One last sanity check */ + if(seccount > 65535) { + fprintf(stderr, + SELF ": (fatal) %s too large to be an XFD image " + "at current density (>65535 sectors)\n", + infile); + if(secsize == 128) + fprintf(stderr, SELF ": Try forcing double density with -d\n"); + exit(2); + } + + fprintf(stderr, SELF ": sectors: %d, sector size: %d bytes", + seccount, secsize); + if(secsize == 256) + fprintf(stderr, " (first 3 sectors are 128 bytes)"); + fputc('\n', stderr); + + paras = st.st_size / 16; + fprintf(stderr, SELF ": %d 16-byte paragraphs\n", paras); + + /* Only open the output file after the XFD is known to be good */ + if(strcmp(outfile, "-") == 0) { + out = stdout; + } else { + if( !(out = fopen(outfile, "wb")) ) { + fprintf(stderr, SELF ": (fatal) can't write %s: %s\n", + outfile, strerror(errno)); + exit(1); + } + } + + /* output ATR header: */ + fputc(0x96, out); /* NICKATARI cksum, lo byte */ + fputc(0x02, out); /* NICKATARI cksum, hi byte */ + fputc(paras & 0xff, out); /* paragraphs, lo byte */ + fputc((paras >> 8) & 0xff, out); /* paragraphs, mid byte */ + fputc(secsize & 0xff, out); /* sector size, lo byte */ + fputc(secsize >> 8, out); /* sector size, hi byte */ + fputc((paras >> 16) & 0xff, out); /* paragraphs, hi byte */ + + /* unused ATR header bytes */ + for(i=0; i<9; i++) + fputc('\0', out); + + /* copy the data */ + while( (i = fgetc(in)) != EOF ) + fputc(i, out); + + /* fgetc() returns EOF on error *or* EOF; + check for I/O errors, return 1 if so */ + i = 0; + + if(ferror(in)) { + i = 1; + fprintf(stderr, + SELF ": error reading %s: %s\n", infile, strerror(errno)); + } + + if(ferror(out)) { + i = 1; + fprintf(stderr, + SELF ": error writing %s: %s\n", outfile, strerror(errno)); + } + + fclose(in); + fclose(out); + + return i; +} |