aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <yalhcru@gmail.com>2020-05-13 02:54:46 -0400
committerB. Watson <yalhcru@gmail.com>2020-05-13 02:54:46 -0400
commitec835bdb21fd9621e5ba071a991229b7777289c3 (patch)
tree48d146880f2f0923f6a62de5e556eb09ac687d12
parent510a4c1463ed2c46dac54ed91da7d42c4b2978be (diff)
downloadmiragextract-ec835bdb21fd9621e5ba071a991229b7777289c3.tar.gz
split up huge process_track(), clean up -l output, add -L
-rw-r--r--miragextract.c250
1 files changed, 179 insertions, 71 deletions
diff --git a/miragextract.c b/miragextract.c
index d9b4832..a28797d 100644
--- a/miragextract.c
+++ b/miragextract.c
@@ -29,6 +29,7 @@ int autoname = 0;
int want_data = 1;
int want_audio = 1;
char *password = NULL;
+int list_details = 0;
/* CD image state */
MirageContext *mirage = NULL;
@@ -36,6 +37,8 @@ MirageDisc *disc = NULL;
MirageSession *session = NULL;
int output_track_number = 0;
int total_bytes = 0;
+int total_sectors = 0;
+int session_count = 0;
/* libmirage errors set this */
GError *gerr = NULL;
@@ -93,6 +96,10 @@ char *human_mb(int bytes) {
return buf;
}
+/* decide what to name a data track's output file. currently
+ anything not recognized as Apple HFS/HFS+ is assumed to
+ be an ISO. These 2 cases cover all the images I've ever
+ run into in the wild. */
const char *get_data_extension(MirageTrack *track) {
MirageSector *sector;
const char *ext = "iso";
@@ -122,23 +129,130 @@ const char *get_data_extension(MirageTrack *track) {
return ext;
}
+void print_time(int sectors) {
+ int mm, ss, fr;
-/* list and (optionally) extract a track. this should be broken up into
- smaller functions for clarity. */
-void process_track(int t, int extract) {
+ mm = sectors / (60 * 75);
+ sectors %= 60 * 75;
+ ss = sectors / 75;
+ sectors %= 75;
+ fr = (int)((double)sectors / 75.0L * 10.0L);
+
+ printf("%d:%02d.%1d, ", mm, ss, fr);
+}
+
+/* list a track without reading the whole thing into memory */
+void list_track(int t) {
MirageTrack *track;
MirageSector *sector;
+ const guint8 *buf;
int sector_type, sec = 0;
+ int bytes;
+ gint len;
+ int tracklen;
+
+ if(session_count == 1)
+ printf(" %d: ", t + 1);
+ else
+ printf(" %d, -t %d: ", t + 1, output_track_number);
+
+ if(!(track = mirage_session_get_track_by_index(session, t, &gerr)))
+ die(NULL);
+
+ sector_type = mirage_track_get_sector_type(track);
+
+ switch(sector_type) {
+ case MIRAGE_SECTOR_MODE1:
+ case MIRAGE_SECTOR_MODE2_FORM1:
+ printf("data(%s): ", get_data_extension(track));
+ break;
+ case MIRAGE_SECTOR_AUDIO:
+ printf("audio: ");
+ break;
+ case MIRAGE_SECTOR_MODE2_FORM2:
+ case MIRAGE_SECTOR_MODE2_MIXED:
+ printf("video(?): ");
+ break;
+ default:
+ printf("<unknown %d>: ", sector_type);
+ break;
+ }
+
+ sec = mirage_track_get_track_start(track);
+ sector = mirage_track_get_sector(track, sec, 0, NULL);
+ if(!(mirage_sector_get_data(sector, &buf, &len, &gerr)))
+ die(NULL);
+ tracklen = mirage_track_layout_get_length(track);
+
+ bytes = len * tracklen;
+
+ if(sector_type == MIRAGE_SECTOR_AUDIO)
+ print_time(tracklen);
+
+ if(list_details)
+ printf("%sMB (%d = %d sectors of %d bytes)\n", human_mb(bytes), bytes, tracklen, len);
+ else
+ printf("%sMB\n", human_mb(bytes));
+
+ total_bytes += bytes;
+ total_sectors += tracklen;
+}
+
+/* helper for extract_track() */
+SNDFILE *open_sndfile_output(const char *outfile) {
+ SNDFILE *sfout = NULL;
+ struct SF_INFO sfi;
+
+ sfi.samplerate = 44100;
+ sfi.channels = 2;
+
+ switch(outfmt[0]) {
+ case 'o':
+ sfi.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS;
+ break;
+ case 'f':
+ sfi.format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16;
+ break;
+ case 'w':
+ sfi.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ break;
+ default:
+ /* this should never happen */
+ break;
+ }
+
+ if(!(sfout = sf_open(outfile, SFM_WRITE, &sfi))) {
+ putchar('\n');
+ die(sf_strerror(sfout));
+ }
+ sf_command(sfout, SFC_SET_VBR_ENCODING_QUALITY, &quality, sizeof(double));
+ return sfout;
+}
+
+/* helper for extract_track() */
+FILE *open_output(const char *outfile) {
+ FILE *out;
+
+ if(!(out = fopen(outfile, "wb"))) {
+ putchar('\n');
+ fprintf(stderr, "%s: %s: can't open output file\n", self, outfile);
+ die(NULL);
+ }
+
+ return out;
+}
+
+/* extract a track. meat and potatoes here. */
+void extract_track(int t) {
+ MirageTrack *track;
+ MirageSector *sector;
+ int sector_type, sec = 0, bytes = 0, use_sndfile = 0;
gint len;
const guint8 *buf;
const char *ext;
char outfile[PATH_MAX + 1];
FILE *out = NULL;
SNDFILE *sfout = NULL;
- struct SF_INFO sfi;
- int bytes = 0;
-
- printf(" %d (-t %d): ", t + 1, output_track_number);
if(!(track = mirage_session_get_track_by_index(session, t, &gerr)))
die(NULL);
@@ -149,80 +263,59 @@ void process_track(int t, int extract) {
case MIRAGE_SECTOR_MODE1:
case MIRAGE_SECTOR_MODE2_FORM1:
ext = get_data_extension(track);
- printf("data(%s): ", ext);
- if(!want_data) extract = 0;
+ if(!want_data) return;
break;
case MIRAGE_SECTOR_AUDIO:
- printf("audio: ");
- if(!want_audio) extract = 0;
+ if(!want_audio) return;
+ if(outfmt[0] != 'c')
+ use_sndfile = 1;
ext = outfmt;
break;
+ case MIRAGE_SECTOR_MODE2_FORM2:
+ case MIRAGE_SECTOR_MODE2_MIXED:
+ if(!want_data) return;
+ ext = "mpeg";
+ break;
default:
- printf("<unknown>: ");
+ if(!want_data) return;
ext = "raw";
- if(!want_data) extract = 0;
break;
}
sprintf(outfile, "%s%02d.%s", outfilebase, output_track_number, ext);
+ printf(" Extracting to %s...", outfile);
+ fflush(stdout);
- if(extract) {
- if((sector_type == MIRAGE_SECTOR_AUDIO) && (outfmt[0] != 'c')) {
- sfi.samplerate = 44100;
- sfi.channels = 2;
-
- switch(outfmt[0]) {
- case 'o':
- sfi.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS;
- break;
- case 'f':
- sfi.format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16;
- break;
- case 'w':
- sfi.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
- break;
- default:
- /* this should never happen */
- break;
- }
-
- if(!(sfout = sf_open(outfile, SFM_WRITE, &sfi)))
- die(sf_strerror(sfout));
- sf_command(sfout, SFC_SET_VBR_ENCODING_QUALITY, &quality, sizeof(double));
-
- } else {
- if(!(out = fopen(outfile, "wb"))) {
- die("can't open output file");
- }
- }
- }
+ if(use_sndfile)
+ sfout = open_sndfile_output(outfile);
+ else
+ out = open_output(outfile);
sec = mirage_track_get_track_start(track);
+
while((sector = mirage_track_get_sector(track, sec++, 0, NULL))) {
if(!(mirage_sector_get_data(sector, &buf, &len, &gerr)))
die(NULL);
+
bytes += len;
- if(extract) {
- if(sfout) {
- int items = len / 2;
- if(sf_write_short(sfout, (const short *)apply_s_opt(buf, len), items) != items)
- die(sf_strerror(sfout));
- } else {
- if(fwrite(buf, len, 1, out) != 1)
- die(strerror(errno));
- }
- if(isatty(1) && !(sec % 50)) spinner();
+
+ if(sfout) {
+ int items = len / 2;
+ if(sf_write_short(sfout, (const short *)apply_s_opt(buf, len), items) != items)
+ die(sf_strerror(sfout));
+ } else {
+ if(fwrite(buf, len, 1, out) != 1)
+ die(strerror(errno));
}
+
+ if(isatty(1) && !(sec % 50)) spinner();
g_object_unref(sector);
}
if(sfout) sf_close(sfout);
if(out) fclose(out);
- // printf("%d bytes (%sMB, %d sectors)\n", bytes, human_mb(bytes), sec);
- printf("%d bytes (%sMB)\n", bytes, human_mb(bytes));
- if(extract) printf(" Extracted to %s\n", outfile);
- total_bytes += bytes;
+ printf("OK\n");
return;
}
@@ -251,6 +344,12 @@ int outfmt_ok(char *outfmt) {
return 0;
}
+/* untested */
+gchar *password_callback(gpointer user_data) {
+ if(!password) return NULL;
+ return g_strdup(password);
+}
+
void usage(void) {
char spaces[42];
int i, count;
@@ -264,17 +363,12 @@ void usage(void) {
printf(
"miragextract v" VERSION " by B. Watson, WTFPL\n"
- "Usage: %s [-l] [-s] [-n] [-a] [-d] [-t track] [-b base]\n"
+ "Usage: %s [-l] [-L] [-s] [-n] [-a] [-d] [-t track] [-b base]\n"
"%s[-f fmt] [-q quality] [-p password] image-file\n"
"See man page for details\n", self, spaces);
exit(0);
}
-gchar *password_callback(gpointer user_data) {
- if(!password) return NULL;
- return g_strdup(password);
-}
-
/* this should probably use something like getopts(), but I'm trying
to avoid GNU extensions. */
void parse_args(int argc, char **argv) {
@@ -285,6 +379,10 @@ void parse_args(int argc, char **argv) {
if(argv[0][0] == '-') {
char *nextarg = argv[1];
switch(argv[0][1]) {
+ case 'L':
+ want_track = -1;
+ list_details = 1;
+ break;
case 'l':
want_track = -1;
break;
@@ -312,6 +410,8 @@ void parse_args(int argc, char **argv) {
if(nextarg) {
argv++, argc--;
outfilebase = nextarg;
+ if(strlen(outfilebase) > PATH_MAX - 6)
+ die("-b filename too long");
} else
die("-b option requires base filename argument");
break;
@@ -389,30 +489,38 @@ int main(int argc, char **argv) {
if(!(disc = mirage_context_load_image(mirage, fn, &gerr)))
die(NULL);
- for(s = 0; s < mirage_disc_get_number_of_sessions(disc); s++) {
+ session_count = mirage_disc_get_number_of_sessions(disc);
+ if(session_count > 1)
+ printf("This is a multi-session disc\n");
+
+ for(s = 0; s < session_count; s++) {
if(!(session = mirage_disc_get_session_by_index(disc, s, &gerr)))
die(NULL);
- printf("Session %d tracks:\n", s + 1);
+ if(session_count > 1)
+ printf("Session %d tracks:\n", s + 1);
for(t = 0; t < mirage_session_get_number_of_tracks(session); t++) {
- int extract = 0;
output_track_number++;
- if(want_track == 0 || want_track == output_track_number)
- extract = 1;
+ list_track(t);
- process_track(t, extract);
+ if(want_track == 0 || want_track == output_track_number)
+ extract_track(t);
}
if(!t) printf(" (no tracks in session)\n");
g_object_unref(session);
}
+ if(list_details) {
+ printf("Total size: %sMB (%d, %d sectors)\n", human_mb(total_bytes), total_bytes, total_sectors);
+ } else {
+ printf("Total size: %sMB\n", human_mb(total_bytes));
+ }
+
g_object_unref(disc);
g_object_unref(mirage);
mirage_shutdown(NULL);
- printf("Total size: %d bytes (%sMB)\n", total_bytes, human_mb(total_bytes));
-
return 0;
}