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