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