From aba1e23a63897df18fa048315c880c4b316990f2 Mon Sep 17 00:00:00 2001 From: CGarz <20268068+cgarz@users.noreply.github.com> Date: Fri, 11 Jan 2019 23:14:57 +0000 Subject: [PATCH] added ability to return merged bin to split bin format. --- binmerge | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/binmerge b/binmerge index 2b05faf..419fb18 100644 --- a/binmerge +++ b/binmerge @@ -66,6 +66,13 @@ def read_cue_file(cue_path): if m: this_track.indexes.append({'id': int(m.group(1)), 'stamp': m.group(2), 'file_offset':cuestamp_to_sectors(m.group(2))}) + if len(files) == 1: + # only 1 file, assume splitting, calc sectors of each + next_item_offset = files[0].size // Track.globalBlocksize + for t in reversed(files[0].tracks): + t.sectors = next_item_offset - t.indexes[0]["file_offset"] + next_item_offset = t.indexes[0]["file_offset"] + for f in files: print("-- File --") print("Filename: %s" % f.filename) @@ -76,6 +83,7 @@ def read_cue_file(cue_path): print(" -- Track --") print(" Num: %d" % t.num) print(" Type: %s" % t.track_type) + if t.sectors: print(" Sectors: %s" % t.sectors) print(" Indexes: %s" % repr(t.indexes)) return files @@ -98,7 +106,7 @@ def cuestamp_to_sectors(stamp): return fields + (seconds * 75) + (minutes * 60 * 75) -def generate_cuesheet(bin_filename, files): +def gen_merged_cuesheet(bin_filename, files): cuesheet = 'FILE "%s" BINARY\n' % bin_filename # One sector is (BLOCKSIZE) bytes sector_pos = 0 @@ -110,6 +118,17 @@ def generate_cuesheet(bin_filename, files): sector_pos += f.size / Track.globalBlocksize return cuesheet +def gen_split_cuesheet(bin_filename, merged_file): + # similar to merged, could have it do both, but separate arguably cleaner + cuesheet = "" + for t in merged_file.tracks: + cuesheet += 'FILE "%s (Track %02d).bin" BINARY\n' % (bin_filename, t.num) + cuesheet += ' TRACK %02d %s\n' % (t.num, t.track_type) + for i in t.indexes: + sector_pos = i['file_offset'] - t.indexes[0]['file_offset'] + cuesheet += ' INDEX %02d %s\n' % (i['id'], sectors_to_cuestamp(sector_pos)) + return cuesheet + def merge_files(merged_filename, files): # cat is actually faster, but I prefer multi-platform and no special-casing chunksize = 1024 * 1024 @@ -123,16 +142,39 @@ def merge_files(merged_filename, files): outfile.write(chunk) return True +def split_files(cue_dir, new_basename, merged_file): + # use calculated sectors, read the same amount, start new file when equal + with open(os.path.join(cue_dir, merged_file.filename), 'rb') as infile: + for t in merged_file.tracks: + chunksize = 1024 * 1024 + out_name = '%s (Track %02d).bin' % (new_basename, t.num) + tracksize = t.sectors * Track.globalBlocksize + written = 0 + with open(out_name, 'wb') as outfile: + while True: + if chunksize + written > tracksize: + chunksize = tracksize - written + chunk = infile.read(chunksize) + outfile.write(chunk) + written += chunksize + if written == tracksize: + break + return True + def main(): parser = argparse.ArgumentParser(description="Using a cuesheet, merges numerous bin files into a single bin file and produces a new cuesheet with corrected offsets. Works great with Redump. Supports all block modes, but only binary track types. Should work on any python3 platform.") parser.add_argument('cuefile', help='path to source cuefile with multiple referenced bin tracks') parser.add_argument('new_name', help='name (without extension) for your new bin/cue files') + parser.add_argument('--split', help='Change mode from merging to splitting to allow reconstruction of the split format.', required=False, action="store_true") parser.add_argument('-o', dest='outdir', required=False, default=False, help='output directory. defaults to the same directory as source cue') args = parser.parse_args() cue_map = read_cue_file(args.cuefile) - cuesheet = generate_cuesheet(args.new_name+'.bin', cue_map) + if args.split: + cuesheet = gen_split_cuesheet(args.new_name, cue_map[0]) + else: + cuesheet = gen_merged_cuesheet(args.new_name+'.bin', cue_map) outdir = os.path.dirname(args.cuefile) if args.outdir: @@ -146,10 +188,17 @@ def main(): f.write(cuesheet) print("Wrote %s" % args.new_name+'.cue') - print("Merging files...") - if merge_files(os.path.join(outdir, args.new_name+'.bin'), cue_map): - print("Wrote %s" % args.new_name+'.bin') + if args.split: + print("Splitting files...") + if split_files(os.path.dirname(args.cuefile), os.path.join(outdir, args.new_name), cue_map[0]): + print("Wrote %d bin files" % len(cue_map[0].tracks)) + else: + print("Unable to split bin files") else: - print("Unable to merge bin files") + print("Merging files...") + if merge_files(os.path.join(outdir, args.new_name+'.bin'), cue_map): + print("Wrote %s" % args.new_name+'.bin') + else: + print("Unable to merge bin files") main()