Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Create CBM D71/D81/D82 from Commodore 64 D64 multidisk game archives for ease of use in emulator
# -*- coding: utf-8 -*-
# Creates D71/D81/D82 CBM disks from gamebase's C64 multidisk
# games archives (*.zip).
# Requires:
# Note: Stuffing the multidisks on one larger disc may or may not work in the
# emulator, but it is worth a try before you need to fiddle with disc
# flipping during gameplay.
# Note: Since the module cbmdisk is only available on Windows platform this
# script works only on Windows.
# Author: Gemba
# License: MIT
from __future__ import print_function
import os
import re
import shutil
import site
import sys
import tempfile
import zipfile
import cbmdisk
except ImportError:
print ("[!] Module cbmdisk is not present.")
print (" Please visit and")
print (" download package, deploy contained cbmdisk.pyd into:")
sp = next(p for p in site.getsitepackages() if 'site-packages' in p)
print (" %s" % sp)
# adjust the next two values to needs
# Where to find the flat directory structure with the gamebase zip archives?
ROM_HOME = "C:/temp/c64-multidisk/gamebase-multidisk-zips"
# Where to put the combined discs?
OUT_DIR = "C:/temp/c64-multidisk/d78x_out"
# used later to ignore VERSION.NFO within gamebase archives
types = {}
for t in ['D71', 'D81', 'D82']:
types[t] = cbmdisk.Disk(type=t).free_blocks
# get list of CBM files from all *.D64 files
def get_cbm_files(rom_file):
base_name = os.path.basename(rom_file)
with zipfile.ZipFile(rom_file, 'r') as zh:
zip_contents = [nn for nn in zh.namelist() if not PATTERN.match(nn)]
disk0_fn = None
cbmdisk_title = None
total_blocks = 0
cbm_files = []
if len(zip_contents) > 1:
print("[+] Processing %s ..." % base_name)
tmp = os.path.join(tempfile.gettempdir(), base_name)
shutil.rmtree(tmp, ignore_errors=True)
for idx, m in enumerate(sorted(zip_contents)):
zh.extract(m, tmp)
#print (m)
d64 = cbmdisk.Disk(os.path.join(tmp, m))
if idx == 0:
cbmdisk_title =
disk0_fn = m
for f in d64.files:
total_blocks = total_blocks + f.size
#print ("%s: %d" % (, f.size))
shutil.rmtree(tmp, ignore_errors=True)
print ("[-] Skipping %s. Not a multidisk game" % base_name)
return (disk0_fn, cbmdisk_title, total_blocks, cbm_files)
# determine target disk size
def get_cbm_disk_type(total_blocks):
type = 'D71'
if total_blocks > types['D71']:
type = 'D81'
if total_blocks > types['D81']:
if total_blocks <= types['D82']:
type = 'D82'
type = None
return type
if __name__ == "__main__":
if not os.path.exists(ROM_HOME):
print ("[!] Path %s does not exist. Please fix." % ROM_HOME)
if not os.path.exists(OUT_DIR):
for rom in [f for f in os.listdir(ROM_HOME)
if os.path.splitext(f)[1].lower() == ".zip"]:
rom_file = os.path.join(ROM_HOME, rom)
disk0_fn, cbm_dt, total_blocks, cbm_files = get_cbm_files(rom_file)
if not disk0_fn:
type = get_cbm_disk_type(total_blocks)
if not type:
print ("[!] Fileset too large: %d blocks. Does exceed D82 "
"maximum capacity (%d blocks)."
% (total_blocks, types['D82']))
print (" Skipping file %s" % os.path.basename(rom_file))
shutil.rmtree(tmp, ignore_errors=True)
# some exceptions
base_name = os.path.basename(rom_file)
if base_name == "":
type = 'D82'
cbmdisk_tgt = cbmdisk.Disk(type=type) = cbm_dt
# loop over all CBM files found in the *.D64 files
# and copy CBM files together
for f in cbm_files:
#print (f)
cbmdisk_tgt.files.copy(len(cbmdisk_tgt.files), f)
filename = os.path.splitext(disk0_fn)[0] + "." + type
outf = os.path.join(OUT_DIR, filename)
print ("[+] ... wrote '%s' disktype to: %s for %s" % (type, outf, rom))
print ("[+] Done.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.