Skip to content

Instantly share code, notes, and snippets.

@aerosoul94
Created March 22, 2024 00:04
Show Gist options
  • Save aerosoul94/90b22cb94b629b557a7cd312e861d7e1 to your computer and use it in GitHub Desktop.
Save aerosoul94/90b22cb94b629b557a7cd312e861d7e1 to your computer and use it in GitHub Desktop.
import sys
def read_uint32(stream):
return int.from_bytes(stream.read(4), 'big')
def read_uint64(stream):
return int.from_bytes(stream.read(8), 'big')
class BDEmuImageDetail:
def __init__(self, stream):
self._stream = stream
self._load(self._stream)
def _load(self, stream):
self._image_name = stream.read(0x80)
self._image_size = read_uint64(stream)
self._unknown1 = stream.read(0x78)
self._title_id = stream.read(0x20)
self._copyright_holder = stream.read(0x20)
self._producer_name = stream.read(0x20)
self._unknown_date = stream.read(8)
self._disk_type = stream.read(0x19)
self._unknown2 = stream.read(0x17)
@property
def image_name(self) -> str:
return (self._image_name.split(b'\0')[0]).decode('ascii')
@property
def image_size(self):
return self._image_size
class BDEmuEntry:
def __init__(self, stream):
self._stream = stream
self._flags = None
self._unknown1 = None
self._image_size = None
self._unknown2 = None
self._load(self._stream)
def _load(self, stream):
self._flags = read_uint64(stream)
self._unknown1 = read_uint64(stream)
self._image_size = read_uint64(stream)
self._unknown2 = read_uint64(stream)
@property
def exists(self):
return ((self._flags >> 8) & 0xff) == 0xff
class BDEmuHeader:
def __init__(self, stream):
self._stream = stream
self._signature = None
self._entries = []
self._load(self._stream)
def _load(self, stream):
self._signature = stream.read(8)
if (self._signature != b'BD-EMU-1'):
raise Exception("Invalid signature at 0x20000")
stream.read(0x18)
for i in range(4):
entry = BDEmuEntry(stream)
self._entries.append(entry)
@property
def entries(self):
return self._entries
class BDEmu:
def __init__(self, path):
self._path = path
self._image_details = []
self._stream = open(self._path, 'rb')
self._IMAGE_START = 0x100000
self._IMAGE_SIZE = 0xBA7400000
self._load(self._stream)
def __fini__(self):
self._stream.close()
def _load(self, stream):
stream.seek(0x20000)
self._header = BDEmuHeader(stream)
self._stream.seek(0x40000)
for entry in self._header.entries:
details = BDEmuImageDetail(stream)
if not entry.exists:
break
self._image_details.append(details)
@property
def header(self):
return self._header
@property
def entries(self):
return self._header.entries
@property
def image_details(self):
return self._image_details
def list_games(self):
detail: BDEmuImageDetail
for (i, detail) in enumerate(self.image_details):
print(f"Index: {i}")
print(f"Image Name: {detail.image_name}")
print(f"Image Size: {detail.image_size} bytes")
def extract_game(self, index, path):
if index > len(self._image_details):
raise Exception(f"Invalid index: {index}")
details: BDEmuImageDetail = self._image_details[index]
ostream = open(path + "/" + details.image_name, 'wb')
self._stream.seek(self._IMAGE_START + (self._IMAGE_SIZE * index))
bytes_written = 0
for _ in range(0, details.image_size, 0x80000):
bytes_to_write = min(0x80000, details.image_size - bytes_written)
buffer = self._stream.read(bytes_to_write)
ostream.write(buffer)
bytes_written += bytes_to_write
print(f"{bytes_written} / {details.image_size}")
ostream.close()
def print_usage():
print(f"Usage: {sys.argv[0]} <command>\n"
f" Commands:\n"
f" list <bdemu image path>\n"
f" extract <bdemu image path> <image index> <output iso path>")
exit()
def main(args):
if len(args) < 2:
print_usage()
command = args[1]
path = args[2]
bdemu = BDEmu(path)
if (command == "list"):
if len(args) < 3:
print_usage()
bdemu.list_games()
elif (command == "extract"):
if len(args) < 5:
print_usage()
image_index = int(args[3])
output_path = args[4]
bdemu.extract_game(image_index, output_path)
if __name__ == '__main__':
args = sys.argv
#args = [sys.argv[0], "list", "dev.img"]
#args = [sys.argv[0], "extract", "dev.img", "0", "./"]
main(args)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment