Created
June 30, 2022 15:54
-
-
Save irismessage/d97b775c07ba6fcd90972a8f0049f084 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import argparse | |
| import io | |
| from pathlib import Path | |
| READ_PATH = Path('AUDIO001.002') | |
| WRITE_PATH = Path('AUDIO001-shifted.002') | |
| # windows displays kibibytes | |
| KB = 1024 | |
| SHIFT = KB * -62 | |
| ARG_HELP_DEFAULT = 'default: %(default)s' | |
| # Resource header | |
| # http://sci.sierrahelp.com/Documentation/SCISpecifications/09-SCI1Resources.html | |
| PRESERVE_BYTES = 9 | |
| # todo: determine if/how the different file size from the sierraoriginals version affects it | |
| def get_parser() -> argparse.ArgumentParser: | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument('-i', dest='read_path', type=Path, default=READ_PATH, help=ARG_HELP_DEFAULT) | |
| parser.add_argument('-o', dest='write_path', type=Path, default=WRITE_PATH, help=ARG_HELP_DEFAULT) | |
| parser.add_argument('-s', dest='shift', type=int, default=SHIFT, help=ARG_HELP_DEFAULT) | |
| parser.add_argument('-p', dest='file_header_size', type=int, default=PRESERVE_BYTES, help=ARG_HELP_DEFAULT) | |
| return parser | |
| def shift_file(read_path: Path, write_path: Path, shift: int = SHIFT, preserve: int = PRESERVE_BYTES): | |
| if 0 <= shift: | |
| positive_shift = True | |
| else: | |
| positive_shift = False | |
| with io.BytesIO() as buffer: | |
| with open(read_path, 'rb') as file: | |
| buffer.write(file.read(preserve)) | |
| if positive_shift: | |
| file.seek(shift + preserve) | |
| buffer.write(file.read()) | |
| file.seek(preserve) | |
| buffer.write(file.read(shift)) | |
| else: | |
| file.seek(shift, io.SEEK_END) | |
| shift_end = file.tell() | |
| buffer.write(file.read()) | |
| file.seek(preserve) | |
| buffer.write(file.read(shift_end - preserve)) | |
| buffer.seek(0) | |
| with open(write_path, 'wb') as file: | |
| file.write(buffer.read()) | |
| def append_stem(path: Path, string: str) -> Path: | |
| return path.with_stem(path.stem + string) | |
| def test(): | |
| read_path = Path('84-0.txt') | |
| shift_file(read_path, append_stem(read_path, '-shift-none'), 0) | |
| shift_file(read_path, append_stem(read_path, '-shift-pos'), SHIFT) | |
| shift_file(read_path, append_stem(read_path, '-shift-neg'), -SHIFT) | |
| def main(): | |
| parser = get_parser() | |
| args = parser.parse_args() | |
| print('shift_file.py: in:', args.read_path) | |
| print('shift_file.py: shift:', args.shift) | |
| print('shift_file.py: preserve:', args.file_header_size) | |
| shift_file(args.read_path, args.write_path, args.shift, args.file_header_size) | |
| print('shift_file.py: out:', args.write_path) | |
| if __name__ == '__main__': | |
| main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import argparse | |
| import io | |
| import shutil | |
| import struct | |
| from pathlib import Path | |
| # http://sci.sierrahelp.com/Documentation/SCISpecifications/09-SCI1Resources.html | |
| # todo: feature to re-shuffle in place every so often | |
| ENTRY_3_BYTE = struct.Struct('<sH') | |
| ENTRY_6_BYTE = struct.Struct('<HL') | |
| READ_PATH_DEFAULT = Path('AUDIO001.MAP') | |
| SHIFT_DEFAULT = 1024 * 256 | |
| ARG_HELP_DEFAULT = 'default: %(default)s' | |
| ABSOLUTE_OFFSET_MIN = 9 | |
| # ABSOLUTE_OFFSET_MAX = (2 ** 28) - 1 | |
| ABSOLUTE_OFFSET_MAX = 14179531 | |
| def get_parser() -> argparse.ArgumentParser: | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument('-i', dest='read_path', type=Path, default=READ_PATH_DEFAULT, help=ARG_HELP_DEFAULT) | |
| parser.add_argument('-o', dest='write_path', type=Path, default=READ_PATH_DEFAULT, help=ARG_HELP_DEFAULT) | |
| parser.add_argument('-s', dest='shift', type=int, default=SHIFT_DEFAULT, help=ARG_HELP_DEFAULT) | |
| return parser | |
| def overflow_add(a: int, b: int, floor: int, ceiling: int) -> int: | |
| c = a + b | |
| if c < floor: | |
| c += ceiling + 1 | |
| elif ceiling < c: | |
| c -= ceiling + 1 | |
| return c | |
| def edit_offset(unpacked: tuple, shift: int) -> tuple: | |
| # nasty little goblin ms-dos file specification using individual bits | |
| component = unpacked[1] | |
| component_binary = '{:>32b}'.format(component) | |
| offset_binary = component_binary[4:] | |
| offset = int(offset_binary, base=2) | |
| # the important part! | |
| offset_new = overflow_add(offset, shift, floor=ABSOLUTE_OFFSET_MIN, ceiling=ABSOLUTE_OFFSET_MAX) | |
| offset_binary_new = '{:0>28b}'.format(offset_new) | |
| component_binary_new = component_binary[:4] + offset_binary_new | |
| component_new = int(component_binary_new, base=2) | |
| to_pack = (unpacked[0], component_new) | |
| return to_pack | |
| def shift_map(read_path: Path, shift: int) -> bytes: | |
| with io.BytesIO() as buffer: | |
| with open(read_path, 'rb') as read_file: | |
| while True: | |
| read_3_bytes = read_file.read(3) | |
| unpacked = ENTRY_3_BYTE.unpack(read_3_bytes) | |
| buffer.write(read_3_bytes) | |
| if unpacked[0] == b'\xFF': # termination sequence | |
| break | |
| while True: | |
| read_6_bytes = read_file.read(6) | |
| unpacked = ENTRY_6_BYTE.unpack(read_6_bytes) | |
| if unpacked[0] == 65535: | |
| buffer.write(read_6_bytes) | |
| buffer.write(read_file.read()) | |
| break | |
| to_pack = edit_offset(unpacked, shift) | |
| write_6_bytes = ENTRY_6_BYTE.pack(*to_pack) | |
| buffer.write(write_6_bytes) | |
| buffer.seek(0) | |
| return buffer.read() | |
| def sanity_check(): | |
| parser = get_parser() | |
| args = parser.parse_args() | |
| new_bytes = shift_map(args.read_path, 0) | |
| # todo: debug this | |
| if new_bytes == args.read_path.read_bytes(): | |
| print('shift_map.py: sanity: pass') | |
| else: | |
| print('shift_map.py: sanity: fail') | |
| def main(): | |
| parser = get_parser() | |
| args = parser.parse_args() | |
| print('shift_map.py: in:', args.read_path) | |
| print('shift_map.py: shift:', args.shift) | |
| new_bytes = shift_map(args.read_path, args.shift) | |
| if args.write_path == args.read_path: | |
| backup_path = args.read_path.with_stem(args.read_path.stem + '-backup') | |
| shutil.copyfile(args.read_path, backup_path) | |
| print('shift_map.py: backup:', backup_path) | |
| with open(args.write_path, 'wb') as write_file: | |
| write_file.write(new_bytes) | |
| print('shift_map.py: out:', args.write_path) | |
| if __name__ == '__main__': | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment