From 1887fdeaf4b97e68f6ef345b780782a3a0c758c3 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Tue, 12 May 2020 01:49:24 -0400 Subject: cuerecover: add -o option, detect MODE1/2048 --- cuerecover.c | 319 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 206 insertions(+), 113 deletions(-) (limited to 'cuerecover.c') diff --git a/cuerecover.c b/cuerecover.c index 34542d2..40698e3 100644 --- a/cuerecover.c +++ b/cuerecover.c @@ -5,6 +5,8 @@ https://en.wikipedia.org/wiki/CD-ROM */ #include #include +#include +#include #include #include #include @@ -25,6 +27,7 @@ int silence_frames; /* same as above in 1/75 sec frames */ int silence_thresh = 0; int multi_bin = 0; int verbose = 0; +char *outfile = NULL; void die(const char *msg) { if(!msg) msg = strerror(errno); @@ -39,13 +42,56 @@ void usage() { exit(0); } +int looks_like_filesystem(const char *filename, FILE *f) { + int have_apple_magic = 0, have_iso_magic = 0; + char buf[2048]; + + if(fseek(f, 0L, SEEK_SET) < 0) + die(NULL); + + if(!fread(buf, 2048, 1, f)) { + fprintf(stderr, "%s: file %s is too short to be a CD image file\n", self, filename); + return 0; + } + + if(buf[0] == 'E' && buf[1] == 'R' && buf[3] == 0 && (buf[2] == 0x02 || buf[2] == 0x08)) + { + have_apple_magic++; + } + + if(fseek(f, 16 * 2048L, SEEK_SET) < 0) + die(NULL); + + if(!fread(buf, 2048, 1, f)) { + fprintf(stderr, "%s: file %s is too short to be a CD image file\n", self, filename); + return 0; + } + + if(strncmp("\x01" "CD001", buf, 6) == 0) { + have_iso_magic++; + } + + if(fseek(f, 0L, SEEK_SET) < 0) + die(NULL); + + if(have_apple_magic && have_iso_magic) { + fprintf(stderr, "%s: file %s looks like hybrid ISO/HFS image\n", self, filename); + } else if(have_apple_magic) { + fprintf(stderr, "%s: file %s looks like Mac HFS image\n", self, filename); + } else if(have_iso_magic) { + fprintf(stderr, "%s: file %s looks like ISO9660 image\n", self, filename); + } + + return have_apple_magic || have_iso_magic; +} + int frame_is_silent(const char *data) { int i, nonzero = 0; for(i=0; iindex0 = sector; - t->index1 = sector; - t->mode = mode; - - /* skip over the data sectors */ - while(read_sector(f, buf) && (get_sector_mode(buf) == mode)) - sector++; - - /* now buf holds the first audio sector, which might or might not - begin with silence */ - t++; track++; - t->mode = 0; - t->index0 = sector; - t->index1 = sector; + if(verbose) fprintf(stderr, "track %d is data, mode %d\n", track, mode); + t->index0 = sector; + t->index1 = sector; + t->mode = mode; + + /* skip over the data sectors */ + while(read_sector(f, buf) && (get_sector_mode(buf) == mode)) + sector++; + + /* now buf holds the first audio sector, which might or might not + begin with silence */ + t++; track++; + t->mode = 0; + t->index0 = sector; + t->index1 = sector; } if(silence_frames) while(read_sector(f, buf)) { - if(frame_is_silent(buf)) { - if(in_silence) { - /* nothing */ - } else { - t->index0 = sector; - t->index1 = -1; - silence_start = sector; - in_silence = 1; - } - } else { - if(in_silence) { - if((sector - silence_start) >= silence_frames) { - in_silence = 0; - t->index1 = sector; - t++; - track++; - t->mode = 0; - } else { - /* nothing */ - } - } - } - sector++; + if(frame_is_silent(buf)) { + if(in_silence) { + /* nothing */ + } else { + t->index0 = sector; + t->index1 = -1; + silence_start = sector; + in_silence = 1; + } + } else { + if(in_silence) { + if((sector - silence_start) >= silence_frames) { + in_silence = 0; + t->index1 = sector; + t++; + track++; + if(track > 99) { + fprintf(stderr, "%s: too many tracks (>99), skipping rest of file\n", self); + break; + } + t->mode = 0; + } else { + /* nothing */ + } + } + } + sector++; } fclose(f); @@ -176,71 +240,79 @@ void process_single(char *filename) { t = tracklist; printf("FILE \"%s\" BINARY\r\n", filename); for(i=0; i<=track; t++, i++) { - if(verbose) { - fprintf(stderr, "track %d, mode %d, index0 %d, index1 %d\n", - i, t->mode, t->index0, t->index1); - } - if(t->index1 > -1) { - printf(" TRACK %02d %s\r\n", i + 1, mode_string(t->mode)); - if(t->index0 < t->index1) { - if(silence_frames && t->index1 - t->index0 > silence_frames) { - t->index0 = t->index1 - silence_frames; - if(verbose) - fprintf(stderr, " (index0 adjusted to %d)\n", t->index0); - } - printf(" INDEX 00 %s\r\n", frame2time(t->index0)); - } - printf(" INDEX 01 %s\r\n", frame2time(t->index1)); - } + if(verbose) { + fprintf(stderr, "track %d, mode %d, index0 %d, index1 %d\n", + i, t->mode, t->index0, t->index1); + } + if(t->index1 > -1) { + printf(" TRACK %02d %s\r\n", i + 1, mode_string(t->mode)); + if(t->index0 < t->index1) { + if(silence_frames && t->index1 - t->index0 > silence_frames) { + t->index0 = t->index1 - silence_frames; + if(verbose) + fprintf(stderr, " (index0 adjusted to %d)\n", t->index0); + } + printf(" INDEX 00 %s\r\n", frame2time(t->index0)); + } + printf(" INDEX 01 %s\r\n", frame2time(t->index1)); + } } } void process_multi(char **filenames) { - int track = 1; + char *filename; + int track = 0; char buf[RAW_SECTOR_SIZE]; FILE *f; - while(*filenames) { - int index0 = 0, index1 = -1; - int mode = -1; - int sector = 0; - - if(verbose) fprintf(stderr, "reading %s\n", *filenames); - if(!(f = fopen(*filenames, "rb"))) - die(NULL); - - printf("FILE \"%s\" BINARY\r\n", *filenames); - - while(read_sector(f, buf)) { - mode = get_sector_mode(buf); - - /* if first sector is data, there's no index 01, we're done */ - if(mode > 0) { - index0 = 0; - index1 = -1; - break; - } - - /* for audio, keep reading silence until we hit sound */ - if(mode == 0 && index1 == -1 && !frame_is_silent(buf)) { - index1 = (sector / 75) * 75; /* round to integer number of seconds */ - break; - } - - sector++; - } - fclose(f); - - printf(" TRACK %02d %s\r\n", track, mode_string(mode)); - if(index1 < 1) { - printf(" INDEX 01 %s\r\n", frame2time(index0)); - } else { - printf(" INDEX 00 %s\r\n", frame2time(index0)); - printf(" INDEX 01 %s\r\n", frame2time(index1)); - } - - track++; - filenames++; + while((filename = *filenames++)) { + int index0 = 0, index1 = -1; + int mode = -1; + int sector = 0; + + track++; + + if(verbose) fprintf(stderr, "reading %s\n", filename); + if(!(f = fopen(filename, "rb"))) + die(NULL); + + printf("FILE \"%s\" BINARY\r\n", filename); + + if(looks_like_filesystem(filename, f)) { + fprintf(stderr, "%s: %s looks like 'cooked' data, assuming MODE1/2048\n", + self, filename); + printf(" TRACK %02d MODE1/2048\r\n", track); + printf(" INDEX 01 00:00:00\r\n"); + continue; + } + + while(read_sector(f, buf)) { + mode = get_sector_mode(buf); + + /* if first sector is data, there's no index 01, we're done */ + if(mode > 0) { + index0 = 0; + index1 = -1; + break; + } + + /* for audio, keep reading silence until we hit sound */ + if(mode == 0 && index1 == -1 && !frame_is_silent(buf)) { + index1 = (sector / 75) * 75; /* round to integer number of seconds */ + break; + } + + sector++; + } + fclose(f); + + printf(" TRACK %02d %s\r\n", track, mode_string(mode)); + if(index1 < 1) { + printf(" INDEX 01 %s\r\n", frame2time(index0)); + } else { + printf(" INDEX 00 %s\r\n", frame2time(index0)); + printf(" INDEX 01 %s\r\n", frame2time(index1)); + } } } @@ -252,7 +324,15 @@ char **parse_args(int argc, char **argv) { if(argv[0][0] == '-') { char *nextarg = argv[1]; switch(argv[0][1]) { - case 'v': verbose++; break; + case 'v': + verbose++; break; + case 'o': + if(nextarg) + outfile = nextarg; + else + die("-o requires an output filename"); + argv++, argc--; + break; case 's': if(nextarg && ((*nextarg >= '0' && *nextarg <= '9') || (*nextarg == '.'))) { silence_sec = atof(nextarg); @@ -263,9 +343,9 @@ char **parse_args(int argc, char **argv) { break; case 't': if(nextarg && - (*nextarg >= '0' && *nextarg <= '9') && - (silence_thresh = atoi(nextarg) <= 100)) - { + (*nextarg >= '0' && *nextarg <= '9') && + (silence_thresh = atoi(nextarg) <= 100)) + { silence_thresh = (RAW_SECTOR_SIZE / 100.0) * atoi(nextarg); argv++, argc--; } else { @@ -278,7 +358,7 @@ char **parse_args(int argc, char **argv) { break; } } else { - break; + break; } } @@ -287,6 +367,16 @@ char **parse_args(int argc, char **argv) { return argv; } +void redirect_output(void) { + struct stat ss; + + if(lstat(outfile, &ss) >= 0) + die("output file exists, not overwriting"); + + if(!(freopen(outfile, "w", stdout))) + die(NULL); +} + void set_exe_name(const char *argv0) { const char *p; self = argv0; @@ -299,13 +389,16 @@ int main(int argc, char **argv) { argv = parse_args(argc, argv); - if(verbose) fprintf(stderr, "writing %s CUE file to stdout\n", - (multi_bin ? "multi-bin" : "single-bin")); + if(verbose) fprintf(stderr, "writing %s CUE file to %s\n", + (multi_bin ? "multi-bin" : "single-bin"), + (outfile ? outfile : "")); + + if(outfile) redirect_output(); if(multi_bin) - process_multi(argv); + process_multi(argv); else - process_single(*argv); + process_single(*argv); return 0; } -- cgit v1.2.3