aboutsummaryrefslogtreecommitdiff
path: root/cuerecover.c
diff options
context:
space:
mode:
authorB. Watson <yalhcru@gmail.com>2020-05-12 01:49:24 -0400
committerB. Watson <yalhcru@gmail.com>2020-05-12 01:49:24 -0400
commit1887fdeaf4b97e68f6ef345b780782a3a0c758c3 (patch)
treec77ea0a438a4bbe11343d1a57957ae85684aa6c5 /cuerecover.c
parent37d219813e8c6d4370ee6cab4283b8f9cf7eebb9 (diff)
downloadmiragextract-1887fdeaf4b97e68f6ef345b780782a3a0c758c3.tar.gz
cuerecover: add -o option, detect MODE1/2048
Diffstat (limited to 'cuerecover.c')
-rw-r--r--cuerecover.c319
1 files changed, 206 insertions, 113 deletions
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 <stdio.h>
#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
@@ -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; i<RAW_SECTOR_SIZE; i++)
if(data[i]) nonzero++;
if(nonzero <= silence_thresh)
- return 1;
+ return 1;
return 0;
}
@@ -66,8 +112,8 @@ const char *frame2time(int frame) {
int read_sector(FILE *f, char *buf) {
/*
if(verbose)
- fprintf(stderr, "read_sector at pos %d\n", ftell(f));
- */
+ fprintf(stderr, "read_sector at pos %d\n", ftell(f));
+ */
return fread(buf, RAW_SECTOR_SIZE, 1, f);
}
@@ -77,7 +123,7 @@ int has_mode1_sync(char *buf) {
int get_sector_mode(char *buf) {
if(!has_mode1_sync(buf))
- return 0; /* audio, or something we don't grok */
+ return 0; /* audio, or something we don't grok */
return buf[15];
}
@@ -100,9 +146,9 @@ int get_sector_addr(char *buf) {
const char *mode_string(int mode) {
switch(mode) {
- case 1: return "MODE1/2352";
- case 2: return "MODE2/2352";
- default: return "AUDIO";
+ case 1: return "MODE1/2352";
+ case 2: return "MODE2/2352";
+ default: return "AUDIO";
}
}
@@ -124,51 +170,69 @@ void process_single(char *filename) {
struct track *t = tracklist;
if(!(f = fopen(filename, "rb")))
- die(NULL);
+ die(NULL);
+
+ if(looks_like_filesystem(filename, f)) {
+ fprintf(stderr, "%s: %s looks like 'cooked' data!\n", self, filename);
+ /*
+ // don't know all the details on how this works yet
+ int skipped_sectors = 0;
+ fprintf(stderr, "%s: %s looks like 'cooked' data, ", self, filename);
+ if((skipped_sectors = skip_fs(filename, f))) {
+ fprintf(stderr, "skipped %d 2048-byte sectors\n", skipped_sectors);
+ } else {
+ fprintf(stderr, "but not ISO9660, don't know how to skip it\n");
+ }
+ */
+ }
/* only the first track can be data */
if(read_sector(f, buf) && (mode = get_sector_mode(buf)) != 0) {
- 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(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 : "<standard output>"));
+
+ if(outfile) redirect_output();
if(multi_bin)
- process_multi(argv);
+ process_multi(argv);
else
- process_single(*argv);
+ process_single(*argv);
return 0;
}