diff options
author | B. Watson <yalhcru@gmail.com> | 2020-05-13 02:54:46 -0400 |
---|---|---|
committer | B. Watson <yalhcru@gmail.com> | 2020-05-13 02:54:46 -0400 |
commit | ec835bdb21fd9621e5ba071a991229b7777289c3 (patch) | |
tree | 48d146880f2f0923f6a62de5e556eb09ac687d12 | |
parent | 510a4c1463ed2c46dac54ed91da7d42c4b2978be (diff) | |
download | miragextract-ec835bdb21fd9621e5ba071a991229b7777289c3.tar.gz |
split up huge process_track(), clean up -l output, add -L
-rw-r--r-- | miragextract.c | 250 |
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; } |