""" Parse ISO 9660 from a MODE1/2352 raw BIN file. Each sector = 2352 bytes; user data starts at byte 16 (after sync+header). """ import struct, sys, os BIN = sys.argv[1] if len(sys.argv) > 1 else r"Z:\Development\devl\Havoc\tmp_cd\Havoc (USA) (Game Disk).bin" SECTOR = 2352 DATA_OFF = 16 # within each sector: sync(12) + header(4) DATA_LEN = 2048 def read_sector(f, lba): f.seek(lba * SECTOR + DATA_OFF) return f.read(DATA_LEN) def read_u16_le(b, off): return struct.unpack_from(' 0: chunk = read_sector(f, cur_lba) data += chunk[:min(DATA_LEN, remaining)] remaining -= DATA_LEN cur_lba += 1 off = 0 while off < len(data): reclen = data[off] if reclen == 0: off = (off + 1 + 1) & ~1 # skip padding; advance if off >= len(data): break continue flags = data[off + 25] name_len = data[off + 32] name_raw = data[off+33:off+33+name_len] # Strip version suffix ;1 name = name_raw.decode('ascii', errors='replace').split(';')[0].rstrip('\x00') file_lba = read_u32_both(data, off + 2) file_size = read_u32_both(data, off + 10) is_dir = bool(flags & 0x02) if name not in ('', '\x01'): entries.append({'name': name, 'lba': file_lba, 'size': file_size, 'is_dir': is_dir, 'indent': indent}) if is_dir: parse_dir(f, file_lba, file_size, indent+1, entries) off += reclen return entries with open(BIN, 'rb') as f: # Check for ISO 9660 PVD at sector 16 pvd = read_sector(f, 16) if pvd[1:6] != b'CD001': print(f"No ISO 9660 PVD at sector 16. Got: {pvd[0:8].hex(' ')}") # Try sector 16 with different offset (some TOAST BINs have ISO 9660 elsewhere) # Check volume descriptor sequence starting at 16 for lba in [16, 17, 18, 32, 64]: s = read_sector(f, lba) print(f" Sector {lba}: type={s[0]} sig={s[1:6]} system_id={s[8:40].rstrip()}") sys.exit(1) vol_type = pvd[0] # 1 = PVD system_id = pvd[8:40].decode('ascii', errors='replace').strip() vol_id = pvd[40:72].decode('ascii', errors='replace').strip() vol_space = read_u32_both(pvd, 80) print(f"ISO 9660 PVD found:") print(f" System ID: {system_id!r}") print(f" Volume ID: {vol_id!r}") print(f" Vol sectors:{vol_space}") root_dir_lba = read_u32_both(pvd, 156 + 2) root_dir_size = read_u32_both(pvd, 156 + 10) print(f" Root dir LBA={root_dir_lba} size={root_dir_size}") print() entries = parse_dir(f, root_dir_lba, root_dir_size) print(f"Files ({len(entries)} entries):") for e in entries: prefix = ' ' * e['indent'] tag = '[DIR]' if e['is_dir'] else f"{e['size']:>10}" print(f" {prefix}{e['name']:<30} {tag}") print() # Look for specific files we need targets = ['HAVOCDAT.DAT', 'KEYSET.DAT', 'BIGFILE.DAT', 'GAMIMAGE.DAT'] print("Target file search:") for e in entries: if e['name'].upper() in targets: print(f" FOUND: {e['name']} at LBA {e['lba']} size {e['size']}")