aboutsummaryrefslogtreecommitdiff
path: root/xfd2atr.c
diff options
context:
space:
mode:
Diffstat (limited to 'xfd2atr.c')
-rw-r--r--xfd2atr.c227
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;
+}