[Scummvm-git-logs] scummvm master -> 3f4203f8833f12615b0df5fa27f19d3c30d3e5d8
sev-
noreply at scummvm.org
Sun Oct 18 22:12:00 UTC 2026
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
e31863c3e8 DEVTOOLS: Add CUE/BIN support to dumper
3f4203f883 DEVTOOLS: Add 3DO support to dumper-companion
Commit: e31863c3e86c2b510d66aaae2bd563823f19b798
https://github.com/scummvm/scummvm/commit/e31863c3e86c2b510d66aaae2bd563823f19b798
Author: Onkar-Raskar (onkarraskar030 at gmail.com)
Date: 2026-10-19T00:11:55+02:00
Commit Message:
DEVTOOLS: Add CUE/BIN support to dumper
Implement a BIN/CUE parser in dumper-companion.py making it
self contained.
- implement parser_cue_sheet
- implement convert_cue_iso_to_iso
Changed paths:
devtools/dumper-companion.py
diff --git a/devtools/dumper-companion.py b/devtools/dumper-companion.py
index 3008cc71827..c2a0a89fbb9 100755
--- a/devtools/dumper-companion.py
+++ b/devtools/dumper-companion.py
@@ -23,20 +23,23 @@ import logging
import os
import re
import sys
+import struct
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "contrib/pycdlib"))
import unicodedata
import urllib.request
import zipfile
+import struct
from binascii import crc_hqx
from datetime import datetime, timezone, timedelta
from enum import Enum
from io import BytesIO, IOBase, StringIO
from pathlib import Path
from struct import pack, unpack
-from typing import Any, Optional
+from typing import Any, Optional, Dict, List
from pathlib import Path
+from dataclasses import dataclass, field
import machfs # type: ignore
import pycdlib # type: ignore
@@ -99,6 +102,10 @@ CCD_DATA_SIZE = 2048
CCD_MODE_OFFSET = 15
CCD_MODE1_DATA_OFFSET = 16
CCD_MODE2_DATA_OFFSET = 24
+BUFFERLEN = 102400
+SIZE_OF_BLOCK = 2048
+DIR_HEAD_TYPE = '>IIIII'
+FILE_ENTRY_TYPE = '>II4sIIIII32sII'
class FileSystem(Enum):
hybrid = "hybrid"
@@ -559,7 +566,180 @@ def convert_ccd_to_iso(img_path: Path, iso_path: Path) -> None:
raise ValueError(
f"Unsupported sector mode {mode}"
)
+SECTOR_SIZES = {
+ "AUDIO": 2352, "CDG": 2448, "MODE1_RAW": 2352,
+ "MODE1/2048": 2048, "MODE1/2352": 2352, "MODE2_RAW": 2352,
+ "MODE2/2048": 2048, "MODE2/2324": 2324, "MODE2/2336": 2336,
+ "MODE2/2352": 2352, "CDI/2336": 2336, "CDI/2352": 2352,
+}
+
+ at dataclass
+class CueTrack:
+ number: int
+ type: str
+ sector_size: int
+ file: str
+ indices: Dict[int, int] = field(default_factory=dict)
+
+def parse_msf(msf_str: str) -> int:
+ """Converts a 'MM:SS:FF' string into an integer LBA offset."""
+ m, s, f = [int(x) for x in msf_str.split(":")]
+ return f + 75 * (s + 60 * m)
+
+def tokenize(line: str) -> List[str]:
+ """Splits a line by spaces, keeping quoted strings intact."""
+ return [t.strip('"') for t in re.findall(r'"[^"]*"|\S+', line)]
+
+def parse_cue_sheet(cue_path: Path) -> List[CueTrack]:
+ """Parses structural track and file mapping from a CUE sheet."""
+ tracks: List[CueTrack] = []
+ current_file = ""
+ current_track: Optional[CueTrack] = None
+
+ with open(cue_path, "r", encoding="utf-8-sig", errors="replace") as f:
+ for line_num, line in enumerate(f, 1):
+ line = line.strip()
+ if not line or line.startswith((";", "//")):
+ continue
+
+ tokens = tokenize(line)
+ if not tokens:
+ continue
+
+ cmd = tokens[0].upper()
+
+ try:
+ if cmd == "FILE":
+ current_track = None
+ if len(tokens) < 3:
+ raise IndexError("FILE needs a name and a type")
+ current_file = " ".join(tokens[1:-1])
+
+ elif cmd == "TRACK":
+ current_track = None
+ track_num = int(tokens[1])
+ track_type = tokens[2].upper()
+
+ if track_type not in SECTOR_SIZES:
+ logging.warning(f"Line {line_num}: Unknown track type {track_type}, defaulting to 2352.")
+
+ current_track = CueTrack(
+ number=track_num,
+ type=track_type,
+ sector_size=SECTOR_SIZES.get(track_type, 2352),
+ file=current_file
+ )
+ tracks.append(current_track)
+
+ elif cmd == "INDEX" and current_track is not None:
+ current_track.indices[int(tokens[1])] = parse_msf(tokens[2])
+
+ except (ValueError, IndexError) as e:
+ logging.warning(f"Line {line_num}: Malformed line '{line}' - {e}")
+
+ return tracks
+def convert_cue_to_iso(cue_path: Path, iso_path: Path) -> None:
+ """
+ Converts a BIN/CUE image into an ISO image for the primary data track,
+ and extracts any audio tracks to WAV format in the same directory.
+ """
+ tracks = parse_cue_sheet(cue_path)
+ if not tracks:
+ raise ValueError("No valid tracks found in the CUE sheet.")
+
+ os.makedirs(iso_path.parent, exist_ok=True)
+ data_track_extracted = False
+
+ for i, track in enumerate(tracks):
+ bin_path = cue_path.parent / track.file
+ if not bin_path.exists():
+ logging.warning(f"Associated BIN file not found: {bin_path}")
+ continue
+
+ start_sector = track.indices.get(1, 0)
+
+ sector_size = track.sector_size
+
+ if i + 1 < len(tracks) and tracks[i+1].file == track.file:
+ next_track = tracks[i+1]
+ end_sector = next_track.indices.get(0, next_track.indices.get(1, start_sector))
+ else:
+ bin_size = os.path.getsize(bin_path)
+ end_sector = bin_size // sector_size
+
+ total_sectors = end_sector - start_sector
+ if total_sectors <= 0:
+ continue
+
+ is_audio = False
+ if "MODE1" in track.type:
+ # If the BIN is already cooked (2048), offset is 0. If raw (2352), offset is 16.
+ data_offset = 16 if sector_size == 2352 else 0
+ payload_size = 2048
+ out_path = iso_path
+ elif "MODE2" in track.type:
+ data_offset = 24 if sector_size == 2352 else 0
+ payload_size = 2048
+ out_path = iso_path
+ elif "AUDIO" in track.type:
+ data_offset = 0
+ payload_size = 2352
+ out_path = iso_path.parent / f"{cue_path.stem}_track_{track.number:02d}.wav"
+ is_audio = True
+ else:
+ logging.warning(f"Skipping unsupported track type: {track.type}")
+ continue
+
+ print(f"Extracting Track {track.number:02d} ({track.type}) -> {out_path.name}")
+
+ is_audio = False
+ if "MODE1" in track.type:
+ if data_track_extracted:
+ logging.warning(
+ f"skip additional data track {track.number:02d}; only primary data track is supported."
+ )
+ continue
+ data_offset = 16 if sector_size == 2352 else 0
+ payload_size = 2048
+ out_path = iso_path
+ data_track_extracted = True
+ elif "MODE2" in track.type:
+ if data_track_extracted:
+ logging.warning(
+ f"skip additional data track {track.number:02d}; only primary data track is supported."
+ )
+ continue
+ data_offset = 24 if sector_size == 2352 else 0
+ payload_size = 2048
+ out_path = iso_path
+ data_track_extracted = True
+ elif "AUDIO" in track.type:
+ if data_track_extracted:
+ logging.warning(
+ f"skip additional data track {track.number:02d}; only primary data track is supported."
+ )
+ continue
+ data_offset = 0
+ payload_size = 2352
+ out_path = iso_path.parent / f"{cue_path.stem}_track_{track.number:02d}.wav"
+ is_audio = True
+ else:
+ logging.warning(f"Skipping unsupported track type: {track.type}")
+ continue
+
+ src.seek(start_sector * sector_size)
+
+ for _ in range(total_sectors):
+ chunk = src.read(sector_size)
+
+ if not chunk or len(chunk) < sector_size:
+ logging.warning(f"Reached early EOF on track {track.number}.")
+ break
+
+ payload = chunk[data_offset : data_offset + payload_size]
+ dst.write(payload)
+
def extract_iso(args: argparse.Namespace) -> None:
temp_iso = None
try:
@@ -580,7 +760,15 @@ def extract_iso(args: argparse.Namespace) -> None:
)
args.src = temp_iso
-
+ elif args.src.suffix.lower() == ".cue":
+ temp_iso = args.dir / f"{args.src.stem}.iso"
+
+ convert_cue_to_iso(
+ args.src,
+ temp_iso
+ )
+
+ args.src = temp_iso
loglevel: str = args.log
numeric_level = getattr(logging, loglevel.upper(), None)
@@ -1229,6 +1417,113 @@ def check_pycdlib_version() -> bool:
doc_get_file_from_iso_fp
)
+def endianswap(x) :
+ value = struct.unpack('>I', x)
+ return value[0]
+
+def checkHeader(f, block, offset):
+ position = offset + block * SIZE_OF_BLOCK
+
+ f.seek(position)
+ data = f.read(7)
+ if data != b'\x01ZZZZZ\x01' :
+ return 0
+ f.seek(position + 0x28)
+ mark = f.read(6)
+ if mark != b"CD-ROM" :
+ return 0
+ return 1
+
+def expandDir(f, offset, block, out):
+ while True :
+
+ dirSize = struct.calcsize(DIR_HEAD_TYPE)
+ entrySize = struct.calcsize(FILE_ENTRY_TYPE)
+ position = offset + block * SIZE_OF_BLOCK
+
+ f.seek(position)
+ data = f.read(dirSize)
+ if len(data) != dirSize :
+ print("can't read header")
+ break
+ DirHead = struct.unpack(DIR_HEAD_TYPE, data)
+
+ attr = 0
+ while attr < 256 :
+ data = f.read(entrySize)
+ if len(data) != entrySize :
+ print("can't read File entry")
+ break
+ File_Entry = struct.unpack(FILE_ENTRY_TYPE, data)
+
+ attr = File_Entry[0]
+ fileSizeBytes = File_Entry[4]
+ numberCopies = File_Entry[9]
+ startBlock = File_Entry[10]
+
+ rawext = File_Entry[2]
+ RawFileName = File_Entry[8]
+
+ FileExt = rawext.split(b'\x00', 1)[0].decode('ascii', errors = 'replace')
+ FileName = os.path.basename(RawFileName.split(b'\x00', 1)[0].decode('ascii', errors='replace'))
+
+ if numberCopies > 0 :
+ f.seek(numberCopies * 4, 1)
+
+ saved_pos = f.tell()
+ if (attr & 255) == 7 :
+ dir_path = os.path.join(out , FileName)
+ os.makedirs(dir_path, exist_ok= True)
+ expandDir(f, offset, startBlock, dir_path)
+
+ elif (attr & 255) in (2,6) :
+ file_path = os.path.join(out , FileName)
+ print(f"Extracting : {file_path}")
+ with open(file_path,'wb') as nf :
+ f.seek(offset + startBlock*SIZE_OF_BLOCK)
+
+ totalLen = fileSizeBytes
+ while totalLen >= BUFFERLEN :
+ data = f.read(BUFFERLEN)
+ nf.write(data)
+
+ totalLen = totalLen - BUFFERLEN
+
+ if totalLen > 0 :
+ remainder = f.read(totalLen)
+
+ if len(remainder) == totalLen :
+ nf.write(remainder)
+
+ f.seek(saved_pos)
+ if (attr & 0xFF000000) == 0x40000000 :
+ block += 2048//SIZE_OF_BLOCK
+ else :
+ break
+
+def extract3do(args: argparse.Namespace) -> None :
+ header_found = False
+ with open(args.src, 'rb') as f :
+ f_size = f.seek(0,2)
+ totalBlocks = f_size // SIZE_OF_BLOCK
+ offset = 0
+
+ for block in range(totalBlocks):
+ if checkHeader(f, block, offset) :
+ header_found = True
+ offset = block * SIZE_OF_BLOCK
+ f.seek(offset + 0x64)
+ root = f.read(4)
+ root_block = endianswap(root)
+
+ os.makedirs(args.dir, exist_ok=True)
+ expandDir(f, offset, root_block, args.dir)
+ print("Done")
+ return
+
+ if not header_found :
+ print(f"Error: '{args.src}' is not a valid MODE1/2048 3DO CD-ROM image.")
+ return
def generate_parser() -> argparse.ArgumentParser:
"""
@@ -1318,6 +1613,22 @@ def generate_parser() -> argparse.ArgumentParser:
)
parser_str.set_defaults(func=encode_string)
+ parser_3do = subparsers.add_parser(
+ "3do",
+ help="Dump 3DO images"
+ )
+ parser_3do.add_argument("src",
+ metavar="INPUT",
+ type=Path,
+ help="3DO Disk image"
+ )
+ parser_3do.add_argument("dir",
+ metavar="OUTPUT",
+ type=Path,
+ help="Destination folder"
+ )
+ parser_3do.set_defaults(func=extract3do)
+
if sys.platform == "darwin":
parser_macbinary = subparsers.add_parser(
"mac",
Commit: 3f4203f8833f12615b0df5fa27f19d3c30d3e5d8
https://github.com/scummvm/scummvm/commit/3f4203f8833f12615b0df5fa27f19d3c30d3e5d8
Author: Onkar-Raskar (onkarraskar030 at gmail.com)
Date: 2026-10-19T00:11:55+02:00
Commit Message:
DEVTOOLS: Add 3DO support to dumper-companion
Integrate 3DO CD-ROM image detection into the existing iso command pipeline. Implement a parser for 3DO CD-ROM images (MODE1/2048) in the Python dumper companion script.
Changed paths:
devtools/dumper-companion.py
diff --git a/devtools/dumper-companion.py b/devtools/dumper-companion.py
index c2a0a89fbb9..0c5f9224d1e 100755
--- a/devtools/dumper-companion.py
+++ b/devtools/dumper-companion.py
@@ -23,7 +23,6 @@ import logging
import os
import re
import sys
-import struct
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "contrib/pycdlib"))
@@ -104,13 +103,14 @@ CCD_MODE1_DATA_OFFSET = 16
CCD_MODE2_DATA_OFFSET = 24
BUFFERLEN = 102400
SIZE_OF_BLOCK = 2048
-DIR_HEAD_TYPE = '>IIIII'
-FILE_ENTRY_TYPE = '>II4sIIIII32sII'
+DIR_HEAD_TYPE = ">IIIII"
+FILE_ENTRY_TYPE = ">II4sIIIII32sII"
class FileSystem(Enum):
hybrid = "hybrid"
hfs = "hfs"
iso9660 = "iso9660"
+ threedo = "3do"
class Extension(Enum):
@@ -491,6 +491,13 @@ def extract_prodos_image(image: bytes, destination_dir: Path) -> None:
def check_fs(iso: str) -> FileSystem:
disk_formats = []
f = open(iso, "rb")
+ # 3do
+ f_size = f.seek(0, 2)
+ blocks = f_size // SIZE_OF_BLOCK
+ for block in range(min(16, blocks)):
+ if checkHeader(f, block, 0):
+ disk_formats.append(FileSystem.threedo)
+ break
# ISO Primary Volume Descriptor
f.seek(64 * SECTOR_SIZE)
@@ -566,6 +573,7 @@ def convert_ccd_to_iso(img_path: Path, iso_path: Path) -> None:
raise ValueError(
f"Unsupported sector mode {mode}"
)
+
SECTOR_SIZES = {
"AUDIO": 2352, "CDG": 2448, "MODE1_RAW": 2352,
"MODE1/2048": 2048, "MODE1/2352": 2352, "MODE2_RAW": 2352,
@@ -605,7 +613,7 @@ def parse_cue_sheet(cue_path: Path) -> List[CueTrack]:
tokens = tokenize(line)
if not tokens:
continue
-
+
cmd = tokens[0].upper()
try:
@@ -614,15 +622,15 @@ def parse_cue_sheet(cue_path: Path) -> List[CueTrack]:
if len(tokens) < 3:
raise IndexError("FILE needs a name and a type")
current_file = " ".join(tokens[1:-1])
-
+
elif cmd == "TRACK":
current_track = None
track_num = int(tokens[1])
track_type = tokens[2].upper()
-
+
if track_type not in SECTOR_SIZES:
logging.warning(f"Line {line_num}: Unknown track type {track_type}, defaulting to 2352.")
-
+
current_track = CueTrack(
number=track_num,
type=track_type,
@@ -630,14 +638,15 @@ def parse_cue_sheet(cue_path: Path) -> List[CueTrack]:
file=current_file
)
tracks.append(current_track)
-
+
elif cmd == "INDEX" and current_track is not None:
current_track.indices[int(tokens[1])] = parse_msf(tokens[2])
-
+
except (ValueError, IndexError) as e:
logging.warning(f"Line {line_num}: Malformed line '{line}' - {e}")
return tracks
+
def convert_cue_to_iso(cue_path: Path, iso_path: Path) -> None:
"""
Converts a BIN/CUE image into an ISO image for the primary data track,
@@ -651,47 +660,26 @@ def convert_cue_to_iso(cue_path: Path, iso_path: Path) -> None:
data_track_extracted = False
for i, track in enumerate(tracks):
- bin_path = cue_path.parent / track.file
-
- if not bin_path.exists():
- logging.warning(f"Associated BIN file not found: {bin_path}")
- continue
+ bin_path = cue_path.parent / track.file
- start_sector = track.indices.get(1, 0)
+ if not bin_path.exists():
+ logging.warning(f"Associated BIN file not found: {bin_path}")
+ continue
- sector_size = track.sector_size
+ start_sector = track.indices.get(1, 0)
- if i + 1 < len(tracks) and tracks[i+1].file == track.file:
- next_track = tracks[i+1]
- end_sector = next_track.indices.get(0, next_track.indices.get(1, start_sector))
- else:
- bin_size = os.path.getsize(bin_path)
- end_sector = bin_size // sector_size
-
- total_sectors = end_sector - start_sector
- if total_sectors <= 0:
- continue
+ sector_size = track.sector_size
- is_audio = False
- if "MODE1" in track.type:
- # If the BIN is already cooked (2048), offset is 0. If raw (2352), offset is 16.
- data_offset = 16 if sector_size == 2352 else 0
- payload_size = 2048
- out_path = iso_path
- elif "MODE2" in track.type:
- data_offset = 24 if sector_size == 2352 else 0
- payload_size = 2048
- out_path = iso_path
- elif "AUDIO" in track.type:
- data_offset = 0
- payload_size = 2352
- out_path = iso_path.parent / f"{cue_path.stem}_track_{track.number:02d}.wav"
- is_audio = True
- else:
- logging.warning(f"Skipping unsupported track type: {track.type}")
- continue
+ if i + 1 < len(tracks) and tracks[i + 1].file == track.file:
+ next_track = tracks[i + 1]
+ end_sector = next_track.indices.get(0, next_track.indices.get(1, start_sector))
+ else:
+ bin_size = os.path.getsize(bin_path)
+ end_sector = bin_size // sector_size
- print(f"Extracting Track {track.number:02d} ({track.type}) -> {out_path.name}")
+ total_sectors = end_sector - start_sector
+ if total_sectors <= 0:
+ continue
is_audio = False
if "MODE1" in track.type:
@@ -728,17 +716,40 @@ def convert_cue_to_iso(cue_path: Path, iso_path: Path) -> None:
logging.warning(f"Skipping unsupported track type: {track.type}")
continue
- src.seek(start_sector * sector_size)
-
- for _ in range(total_sectors):
- chunk = src.read(sector_size)
+ print(f"Extracting Track {track.number:02d} ({track.type}) -> {out_path.name}")
+
+ with open(bin_path, "rb") as src, open(out_path, "wb") as dst:
+ if is_audio:
+ data_len = total_sectors * payload_size
+ wav_header = struct.pack(
+ "<4sI4s4sIHHIIHH4sI",
+ b"RIFF",
+ data_len + 36,
+ b"WAVE",
+ b"fmt ",
+ 16,
+ 1,
+ 2,
+ 44100,
+ 44100 * 4,
+ 4,
+ 16,
+ b"data",
+ data_len,
+ )
+ dst.write(wav_header)
+
+ src.seek(start_sector * sector_size)
- if not chunk or len(chunk) < sector_size:
- logging.warning(f"Reached early EOF on track {track.number}.")
- break
+ for _ in range(total_sectors):
+ chunk = src.read(sector_size)
- payload = chunk[data_offset : data_offset + payload_size]
- dst.write(payload)
+ if not chunk or len(chunk) < sector_size:
+ logging.warning(f"Reached early EOF on track {track.number}.")
+ break
+
+ payload = chunk[data_offset : data_offset + payload_size]
+ dst.write(payload)
def extract_iso(args: argparse.Namespace) -> None:
temp_iso = None
@@ -802,6 +813,8 @@ def extract_iso(args: argparse.Namespace) -> None:
extract_volume_iso(args)
elif args.fs == FileSystem.hfs:
extract_volume_hfs(args)
+ elif args.fs == FileSystem.threedo:
+ extract3do(args)
else:
extract_volume_hybrid(args)
@@ -1417,114 +1430,99 @@ def check_pycdlib_version() -> bool:
doc_get_file_from_iso_fp
)
-def endianswap(x) :
- value = struct.unpack('>I', x)
+def endianswap(x):
+ value = struct.unpack(">I", x)
return value[0]
def checkHeader(f, block, offset):
position = offset + block * SIZE_OF_BLOCK
-
f.seek(position)
data = f.read(7)
- if data != b'\x01ZZZZZ\x01' :
+ if data != b"\x01ZZZZZ\x01":
return 0
f.seek(position + 0x28)
mark = f.read(6)
- if mark != b"CD-ROM" :
+ if mark != b"CD-ROM":
return 0
return 1
def expandDir(f, offset, block, out):
- while True :
-
+ while True:
dirSize = struct.calcsize(DIR_HEAD_TYPE)
entrySize = struct.calcsize(FILE_ENTRY_TYPE)
position = offset + block * SIZE_OF_BLOCK
f.seek(position)
data = f.read(dirSize)
- if len(data) != dirSize :
+ if len(data) != dirSize:
print("can't read header")
break
DirHead = struct.unpack(DIR_HEAD_TYPE, data)
attr = 0
- while attr < 256 :
+ while attr < 256:
data = f.read(entrySize)
- if len(data) != entrySize :
+ if len(data) != entrySize:
print("can't read File entry")
break
File_Entry = struct.unpack(FILE_ENTRY_TYPE, data)
-
attr = File_Entry[0]
fileSizeBytes = File_Entry[4]
numberCopies = File_Entry[9]
startBlock = File_Entry[10]
-
rawext = File_Entry[2]
RawFileName = File_Entry[8]
- FileExt = rawext.split(b'\x00', 1)[0].decode('ascii', errors = 'replace')
- FileName = os.path.basename(RawFileName.split(b'\x00', 1)[0].decode('ascii', errors='replace'))
+ FileExt = rawext.split(b"\x00", 1)[0].decode("ascii", errors="replace")
+ FileName = os.path.basename(
+ RawFileName.split(b"\x00", 1)[0].decode("ascii", errors="replace")
+ )
- if numberCopies > 0 :
+ if numberCopies > 0:
f.seek(numberCopies * 4, 1)
saved_pos = f.tell()
- if (attr & 255) == 7 :
- dir_path = os.path.join(out , FileName)
- os.makedirs(dir_path, exist_ok= True)
+ if (attr & 255) == 7:
+ dir_path = os.path.join(out, FileName)
+ os.makedirs(dir_path, exist_ok=True)
expandDir(f, offset, startBlock, dir_path)
- elif (attr & 255) in (2,6) :
- file_path = os.path.join(out , FileName)
+ elif (attr & 255) in (2, 6):
+ file_path = os.path.join(out, FileName)
print(f"Extracting : {file_path}")
- with open(file_path,'wb') as nf :
- f.seek(offset + startBlock*SIZE_OF_BLOCK)
-
+ with open(file_path, "wb") as nf:
+ f.seek(offset + startBlock * SIZE_OF_BLOCK)
totalLen = fileSizeBytes
- while totalLen >= BUFFERLEN :
+ while totalLen >= BUFFERLEN:
data = f.read(BUFFERLEN)
nf.write(data)
-
totalLen = totalLen - BUFFERLEN
-
- if totalLen > 0 :
+ if totalLen > 0:
remainder = f.read(totalLen)
-
- if len(remainder) == totalLen :
+ if len(remainder) == totalLen:
nf.write(remainder)
-
f.seek(saved_pos)
- if (attr & 0xFF000000) == 0x40000000 :
- block += 2048//SIZE_OF_BLOCK
- else :
+ if (attr & 0xFF000000) == 0x40000000:
+ block += 2048 // SIZE_OF_BLOCK
+ else:
break
-def extract3do(args: argparse.Namespace) -> None :
- header_found = False
- with open(args.src, 'rb') as f :
- f_size = f.seek(0,2)
+def extract3do(args: argparse.Namespace) -> None:
+ with open(args.src, "rb") as f:
+ f_size = f.seek(0, 2)
totalBlocks = f_size // SIZE_OF_BLOCK
offset = 0
-
for block in range(totalBlocks):
- if checkHeader(f, block, offset) :
- header_found = True
+ if checkHeader(f, block, offset):
offset = block * SIZE_OF_BLOCK
f.seek(offset + 0x64)
root = f.read(4)
root_block = endianswap(root)
-
os.makedirs(args.dir, exist_ok=True)
expandDir(f, offset, root_block, args.dir)
print("Done")
return
- if not header_found :
- print(f"Error: '{args.src}' is not a valid MODE1/2048 3DO CD-ROM image.")
- return
-
def generate_parser() -> argparse.ArgumentParser:
"""
Generate the parser
@@ -1613,22 +1611,6 @@ def generate_parser() -> argparse.ArgumentParser:
)
parser_str.set_defaults(func=encode_string)
- parser_3do = subparsers.add_parser(
- "3do",
- help="Dump 3DO images"
- )
- parser_3do.add_argument("src",
- metavar="INPUT",
- type=Path,
- help="3DO Disk image"
- )
- parser_3do.add_argument("dir",
- metavar="OUTPUT",
- type=Path,
- help="Destination folder"
- )
- parser_3do.set_defaults(func=extract3do)
-
if sys.platform == "darwin":
parser_macbinary = subparsers.add_parser(
"mac",
More information about the Scummvm-git-logs
mailing list