#include #include #include #include #include #include #include /* FIXME: This code is terrible. I should have written an ATR library for atrsize, atr2xfd, and xfd2atr to use, instead of the copy/paste mess I've created. */ #ifndef VERSION #define VERSION "???" #endif #define SELF "atrsize" #define USAGE \ SELF " v" VERSION " by B. Watson (WTFPL)\n" \ "Usage: " SELF " -[bB] image.atr [sectors]\n" \ " -b Create image.atr as a new, blank, single-density image\n" \ " -B Create image.atr as a new, blank, double-density image\n" \ "Original image.atr is backed up as image.atr~\n" \ "Without [sectors], size is rounded up to next 'standard' size\n" char *usage = USAGE; int main(int argc, char **argv) { struct stat st; int filesize = 0; int headersize = 0; int blank = 0; int len, sec; unsigned int secsize, seccount, paras, newseccount = 0, last_data_sec = 0; char *newsize, infile[4096], *outfile; unsigned char buf[384]; FILE *in, *out; if(argc < 2 || argc > 4) { fprintf(stderr, usage); exit(1); } if(strcmp(argv[1], "-b") == 0) { blank = 128; argv++; argc--; } else if(strcmp(argv[1], "-B") == 0) { blank = 256; argv++; argc--; } newsize = argv[2]; outfile = argv[1]; strcpy(infile, outfile); if( !(in = fopen(infile, "rb")) ) { if(!blank) { fprintf(stderr, SELF ": %s: %s\n", infile, strerror(errno)); exit(1); } fprintf(stderr, SELF ": %s does not exist, creating blank image\n", infile); secsize = blank; seccount = 720; memset(buf, 0, 16); buf[0] = 0x96; buf[1] = 0x02; buf[4] = secsize & 0xff; buf[5] = (secsize >> 8) & 0xff; filesize = headersize = 128 * 720 + (secsize - 128) * 717; newseccount = seccount = 720; paras = headersize / 16; buf[2] = paras & 0xff; buf[3] = (paras >> 8) & 0xff; buf[6] = (paras >> 16) & 0xff; } if(in) { if(blank) { fprintf(stderr, SELF ": won't create blank image %s: file exists\n", infile); exit(1); } if(fstat(fileno(in), &st)) { fprintf(stderr, "Can't determine size of %s: %s\n", infile, strerror(errno)); exit(1); } else { filesize = st.st_size - 16; if(filesize < 384) { fprintf(stderr, SELF ": %s is too small to be a valid ATR image\n", infile); exit(1); } } if(fread(buf, 1, 16, in) != 16) { fprintf(stderr, SELF ": %s: %s\n", infile, strerror(errno)); exit(1); } } if( !(buf[0] == 0x96 && buf[1] == 0x02) ) { fprintf(stderr, SELF ": (fatal) %s not an ATR file (no NICKATARI signature)!\n", infile); exit(2); } secsize = buf[4] + (buf[5] << 8); if( !(secsize == 128 || secsize == 256) ) { fprintf(stderr, SELF ": (fatal) %s has invalid sector size %d\n", infile, secsize); exit(2); } paras = buf[2] + (buf[3] << 8) + (buf[6] << 16); headersize = paras * 16; if(filesize && (filesize != headersize)) { fprintf(stderr, SELF ": warning: %s file size (%d bytes) doesn't agree with " "ATR header (%d bytes). File may be truncated or corrupt.\n", infile, filesize, headersize); } if(secsize == 128) { fprintf(stderr, SELF ": single density image (128 bytes/sector)\n"); seccount = filesize / secsize; } else { fprintf(stderr, SELF ": double density image (256 bytes/sector)\n"); seccount = (filesize - 128 * 3) / secsize + 3; } newseccount = seccount; if(newsize == NULL) { /* figure out appropriate new size for this image */ if(secsize == 128) { if(seccount < 720) newseccount = 720; else if(seccount > 720 && seccount < 1040) newseccount = 1040; else if(seccount >= 1040) { fprintf(stderr, SELF ": must specify a sector count " "for SD images >= 1040 sectors.\n"); exit(1); } } else { if(seccount < 720) newseccount = 720; else if(seccount > 720 && seccount < 1440) newseccount = 1440; else if(seccount >= 1440) { fprintf(stderr, SELF ": must specify a sector count " "for DD images >= 1440 sectors.\n"); exit(1); } } /* if(in) { if(newseccount == seccount) { fprintf(stderr, SELF ": image is already %d sectors, nothing to do\n", seccount); exit(0); } else if(!newseccount) { fprintf(stderr, SELF ": image is already standard size, nothing to do\n"); exit(0); } } */ } else { newseccount = atoi(newsize); if(newseccount < 3 || newseccount > 65535) { fprintf(stderr, SELF ": invalid sector count (must be 3 - 65535)\n"); exit(1); } } if(newseccount < 368) { fprintf(stderr, SELF ": warning: " "Output image will not have Atari/MyDOS directory sectors.\n"); } /* fix up ATR header */ if(secsize == 128) headersize = secsize * newseccount; else headersize = (128 * 3) + (newseccount - 3) * secsize; paras = headersize / 16; buf[2] = paras & 0xff; buf[3] = (paras >> 8) & 0xff; buf[6] = (paras >> 16) & 0xff; if(in) { /* make backup file */ len = strlen(infile); infile[len] = '~'; infile[len + 1] = '\0'; unlink(infile); if(link(outfile, infile)) { fprintf(stderr, SELF ": can't create %s: %s\n", infile, strerror(errno)); exit(1); } if(unlink(outfile)) { fprintf(stderr, SELF ": can't delete %s: %s\n", outfile, strerror(errno)); exit(1); } } if( !(out = fopen(outfile, "wb")) ) { fprintf(stderr, SELF ": %s: %s\n", outfile, strerror(errno)); exit(1); } /* write ATR header */ if(fwrite(buf, 1, 16, out) != 16) { fprintf(stderr, SELF ": %s: %s\n", outfile, strerror(errno)); exit(1); } /* read first 3 sectors (always present, always SD) */ if(in) { if(fread(buf, 1, 384, in) != 384) { fprintf(stderr, SELF ": %s: %s\n", infile, strerror(errno)); exit(1); } } else { memset(buf, 0, 384); } /* write first 3 sectors */ if(fwrite(buf, 1, 384, out) != 384) { fprintf(stderr, SELF ": %s: %s\n", outfile, strerror(errno)); exit(1); } for(sec = 4; (sec <= seccount) && (sec <= newseccount); sec++) { int i, has_data = 0; if(in) { if(fread(buf, 1, secsize, in) != secsize) { fprintf(stderr, SELF ": %s: %s\n", infile, strerror(errno)); exit(1); } } for(i=0; i