#include #include #include #include #include #include #include #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; }