[Scummvm-git-logs] scummvm master -> fda3a8974c319bd6cbc90b82d523b6f4d6d107a9
moralrecordings
noreply at scummvm.org
Sun Jan 7 13:53:31 UTC 2024
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
921f636cf4 DEVTOOLS: Add MacBinary support to director-generate-xobj-stub
fda3a8974c DEVTOOLS: Blacken director-generate-xobj-stub.py
Commit: 921f636cf41f3834875c530e43d43d63ecadc8a8
https://github.com/scummvm/scummvm/commit/921f636cf41f3834875c530e43d43d63ecadc8a8
Author: Scott Percival (code at moral.net.au)
Date: 2024-01-07T21:53:27+08:00
Commit Message:
DEVTOOLS: Add MacBinary support to director-generate-xobj-stub
Changed paths:
devtools/director-generate-xobj-stub.py
diff --git a/devtools/director-generate-xobj-stub.py b/devtools/director-generate-xobj-stub.py
index 576a3238911..6e283450770 100755
--- a/devtools/director-generate-xobj-stub.py
+++ b/devtools/director-generate-xobj-stub.py
@@ -161,7 +161,72 @@ def read_uint8(data: bytes) -> int:
def read_uint16_le(data: bytes) -> int:
return struct.unpack('<H', data)[0]
-def extract_xmethtable_win16(file: BinaryIO, ne_offset: int) -> tuple[str, list[str]]:
+def read_uint16_be(data: bytes) -> int:
+ return struct.unpack('>H', data)[0]
+
+def read_uint32_le(data: bytes) -> int:
+ return struct.unpack('<L', data)[0]
+
+def read_uint32_be(data: bytes) -> int:
+ return struct.unpack('>L', data)[0]
+
+def extract_xmethtable_macbinary(file: BinaryIO, resource_offset: int, xobj_id: int|None = None) -> tuple[str, str, list[str]]:
+ file.seek(resource_offset)
+ resource_data_offset = read_uint32_be(file.read(4))
+ resource_map_offset = read_uint32_be(file.read(4))
+ resource_data_size = read_uint32_be(file.read(4))
+ resource_map_size = read_uint32_be(file.read(4))
+ file.seek(resource_offset + resource_map_offset + 24)
+ type_list_offset = read_uint16_be(file.read(2))
+ name_list_offset = read_uint16_be(file.read(2))
+ file.seek(resource_offset + resource_map_offset + type_list_offset)
+ type_count = read_uint16_be(file.read(2))
+ types = {}
+ for _ in range(type_count + 1):
+ key = file.read(4)
+ types[key] = (read_uint16_be(file.read(2)) + 1, read_uint16_be(file.read(2)))
+ if b'XCOD' in types:
+ print('Found XCOD resources!')
+ file.seek(resource_offset + resource_map_offset + type_list_offset + types[b'XCOD'][1])
+ resources = []
+ for _ in range(types[b'XCOD'][0]):
+ id = read_uint16_be(file.read(2))
+ name_offset = read_uint16_be(file.read(2))
+ file.read(1)
+ data_offset = (read_uint8(file.read(1)) << 16) + read_uint16_be(file.read(2))
+ file.read(4)
+ resources.append((id, data_offset, name_offset))
+ xobj = {}
+ for id, data_offset, name_offset in resources:
+ xobj[id] = {}
+ if name_offset != 0xffff:
+ file.seek(resource_offset + resource_map_offset + name_list_offset + name_offset)
+ name_size = read_uint8(file.read(1))
+ xobj[id]["name"] = file.read(name_size).decode("macroman")
+ else:
+ xobj[id]["name"] = "<unknown>"
+ file.seek(resource_offset + resource_data_offset + data_offset)
+ size = read_uint32_be(file.read(4)) - 12
+ file.read(12)
+ xobj[id]["xmethtable"] = []
+ while size > 0:
+ count = read_uint8(file.read(1))
+ if count == 0:
+ break
+ xobj[id]["xmethtable"].append(file.read(count).decode('macroman'))
+ size -= 1 + count
+ if xobj_id is None or xobj_id not in xobj:
+ print("Please re-run with one of the following XOBJ resource IDs:")
+ for id, data in xobj.items():
+ print(f"{id} - {data['name']}")
+ raise ValueError("Need to specify XOBJ resource ID")
+ for entry in xobj[xobj_id]["xmethtable"]:
+ print(entry)
+ return (xobj[xobj_id]["name"], xobj[xobj_id]["name"].lower(), xobj[xobj_id]["xmethtable"])
+
+ raise ValueError("No XCOD resources found!")
+
+def extract_xmethtable_win16(file: BinaryIO, ne_offset: int) -> tuple[str, str, list[str]]:
# get resource table
file.seek(ne_offset + 0x24, os.SEEK_SET)
restable_offset = read_uint16_le(file.read(0x2))
@@ -205,7 +270,7 @@ def extract_xmethtable_win16(file: BinaryIO, ne_offset: int) -> tuple[str, list[
xmethtable_exists = "XMETHTABLE" in resource_names
file.seek(ne_offset + resident_names_offset)
name_length = read_uint8(file.read(0x1))
- library_name = file.read(name_length).decode('ASCII')
+ file_name = file.read(name_length).decode('ASCII')
# Borland C++ can put the XMETHTABLE token into a weird nonstandard resource
for x in filter(lambda d: d["type_id"] == 0x800f, resources):
@@ -217,21 +282,22 @@ def extract_xmethtable_win16(file: BinaryIO, ne_offset: int) -> tuple[str, list[
if not xmethtable_exists:
raise ValueError("XMETHTABLE not found!")
+
resources = list(filter(lambda x: x["type_id"] == 0x800a, resources))
if len(resources) != 1:
raise ValueError("Expected a single matching resource type entry!")
- if len(resources[0]["entries"]) != 1:
- raise ValueError("Expected a single matching resource entry!")
xmethtable_offset = resources[0]["entries"][0]["offset"]
xmethtable_length = resources[0]["entries"][0]["length"]
- print(f"Found XMETHTABLE for XObject library {library_name}!")
+ print(f"Found XMETHTABLE for XObject library {file_name}!")
file.seek(xmethtable_offset, os.SEEK_SET)
xmethtable_raw = file.read(xmethtable_length)
xmethtable = [entry.decode('iso-8859-1') for entry in xmethtable_raw.strip(b"\x00").split(b"\x00")]
for entry in xmethtable:
print(entry)
- return library_name, xmethtable
+ library_name = xmethtable[1]
+ xmethtable[1] = "--" + library_name
+ return library_name, file_name, xmethtable
def extract_xmethtable_win32(file: BinaryIO, pe_offset: int) -> tuple[str, list[str]]:
@@ -245,7 +311,7 @@ def extract_xmethtable_win32(file: BinaryIO, pe_offset: int) -> tuple[str, list[
return ("", [])
-def extract_xmethtable(path: str):
+def extract_xmethtable(path: str, resid: int) -> tuple[str, str, list[str]]:
with open(path, 'rb') as file:
magic = file.read(0x2)
if magic == b'MZ':
@@ -258,14 +324,23 @@ def extract_xmethtable(path: str):
return extract_xmethtable_win16(file, header_offset)
elif magic == b'PE':
raise ValueError("No support yet for extracting from Win32 DLLs")
+ file.seek(0)
+ header = file.read(124)
+ if len(header) == 124 and header[0] == 0 and header[74] == 0 and header[82] == 0 and header[122] in [129, 130] and header[123] in [129, 130]:
+ print("Found MacBinary!")
+
+ data_size = read_uint32_be(header[83:87])
+ resource_size = read_uint32_be(header[87:91])
+ resource_offset = 128 + data_size + ((128 - (data_size % 128)) if (data_size % 128) else 0)
+ print(f"resource offset: {resource_offset}")
+ return extract_xmethtable_macbinary(file, resource_offset, resid)
+
raise ValueError("Unknown filetype")
def generate_stubs(xmethtable: list[str], slug: str, name: str, director_version: int=400, dry_run=False) -> None:
- entries = xmethtable[2:]
-
meths = []
- for e in entries:
+ for e in xmethtable:
if not e.strip():
break
elems = e.split()
@@ -335,15 +410,16 @@ def main() -> None:
description="Extract the method table from a Macromedia Director XObject/XLib and generate method stubs."
)
parser.add_argument("XOBJ_FILE", help="XObject/XLib file to test")
+ parser.add_argument("--resid", help="XOBJ resource ID (for MacBinary)", type=int, default=None)
parser.add_argument("--slug", help="Slug to use for files (e.g. {slug}.cpp, {slug}.h)")
parser.add_argument("--name", help="Base name to use for classes (e.g. {name}XObj, {name}XObject)")
parser.add_argument("--version", metavar="VER", help="Minimum Director version (default: 400)", default="400")
parser.add_argument("--dry-run", help="Test only, don't write files", action='store_true')
args = parser.parse_args()
- library_name, xmethtable = extract_xmethtable(args.XOBJ_FILE)
- slug = args.slug or library_name.lower()
- name = args.name or xmethtable[1]
+ library_name, file_name, xmethtable = extract_xmethtable(args.XOBJ_FILE, args.resid)
+ slug = args.slug or file_name
+ name = args.name or library_name
generate_stubs(xmethtable, slug, name, args.version, args.dry_run)
Commit: fda3a8974c319bd6cbc90b82d523b6f4d6d107a9
https://github.com/scummvm/scummvm/commit/fda3a8974c319bd6cbc90b82d523b6f4d6d107a9
Author: Scott Percival (code at moral.net.au)
Date: 2024-01-07T21:53:27+08:00
Commit Message:
DEVTOOLS: Blacken director-generate-xobj-stub.py
Changed paths:
devtools/director-generate-xobj-stub.py
diff --git a/devtools/director-generate-xobj-stub.py b/devtools/director-generate-xobj-stub.py
index 6e283450770..83df7c1f37f 100755
--- a/devtools/director-generate-xobj-stub.py
+++ b/devtools/director-generate-xobj-stub.py
@@ -1,12 +1,16 @@
#!/usr/bin/env python
+from __future__ import annotations
+
import argparse
import os
import re
import struct
-from typing import BinaryIO
+from typing import Any, BinaryIO
-DIRECTOR_SRC_PATH = os.path.abspath(os.path.join(__file__, "..", "..", "engines", "director"))
+DIRECTOR_SRC_PATH = os.path.abspath(
+ os.path.join(__file__, "..", "..", "engines", "director")
+)
MAKEFILE_PATH = os.path.join(DIRECTOR_SRC_PATH, "module.mk")
LINGO_XLIBS_PATH = os.path.join(DIRECTOR_SRC_PATH, "lingo", "xlibs")
LINGO_OBJECT_PATH = os.path.join(DIRECTOR_SRC_PATH, "lingo", "lingo-object.cpp")
@@ -155,273 +159,335 @@ XOBJ_STUB_TEMPLATE = """XOBJSTUB({xobj_class}::m_{methname}, {default})"""
XOBJ_NR_STUB_TEMPLATE = """XOBJSTUBNR({xobj_class}::m_{methname})"""
+
def read_uint8(data: bytes) -> int:
- return struct.unpack('B', data)[0]
+ return struct.unpack("B", data)[0]
+
def read_uint16_le(data: bytes) -> int:
- return struct.unpack('<H', data)[0]
+ return struct.unpack("<H", data)[0]
+
def read_uint16_be(data: bytes) -> int:
- return struct.unpack('>H', data)[0]
+ return struct.unpack(">H", data)[0]
+
def read_uint32_le(data: bytes) -> int:
- return struct.unpack('<L', data)[0]
+ return struct.unpack("<L", data)[0]
+
def read_uint32_be(data: bytes) -> int:
- return struct.unpack('>L', data)[0]
-
-def extract_xmethtable_macbinary(file: BinaryIO, resource_offset: int, xobj_id: int|None = None) -> tuple[str, str, list[str]]:
- file.seek(resource_offset)
- resource_data_offset = read_uint32_be(file.read(4))
- resource_map_offset = read_uint32_be(file.read(4))
- resource_data_size = read_uint32_be(file.read(4))
- resource_map_size = read_uint32_be(file.read(4))
- file.seek(resource_offset + resource_map_offset + 24)
- type_list_offset = read_uint16_be(file.read(2))
- name_list_offset = read_uint16_be(file.read(2))
- file.seek(resource_offset + resource_map_offset + type_list_offset)
- type_count = read_uint16_be(file.read(2))
- types = {}
- for _ in range(type_count + 1):
- key = file.read(4)
- types[key] = (read_uint16_be(file.read(2)) + 1, read_uint16_be(file.read(2)))
- if b'XCOD' in types:
- print('Found XCOD resources!')
- file.seek(resource_offset + resource_map_offset + type_list_offset + types[b'XCOD'][1])
- resources = []
- for _ in range(types[b'XCOD'][0]):
- id = read_uint16_be(file.read(2))
- name_offset = read_uint16_be(file.read(2))
- file.read(1)
- data_offset = (read_uint8(file.read(1)) << 16) + read_uint16_be(file.read(2))
- file.read(4)
- resources.append((id, data_offset, name_offset))
- xobj = {}
- for id, data_offset, name_offset in resources:
- xobj[id] = {}
- if name_offset != 0xffff:
- file.seek(resource_offset + resource_map_offset + name_list_offset + name_offset)
- name_size = read_uint8(file.read(1))
- xobj[id]["name"] = file.read(name_size).decode("macroman")
- else:
- xobj[id]["name"] = "<unknown>"
- file.seek(resource_offset + resource_data_offset + data_offset)
- size = read_uint32_be(file.read(4)) - 12
- file.read(12)
- xobj[id]["xmethtable"] = []
- while size > 0:
- count = read_uint8(file.read(1))
- if count == 0:
- break
- xobj[id]["xmethtable"].append(file.read(count).decode('macroman'))
- size -= 1 + count
- if xobj_id is None or xobj_id not in xobj:
- print("Please re-run with one of the following XOBJ resource IDs:")
- for id, data in xobj.items():
- print(f"{id} - {data['name']}")
- raise ValueError("Need to specify XOBJ resource ID")
- for entry in xobj[xobj_id]["xmethtable"]:
- print(entry)
- return (xobj[xobj_id]["name"], xobj[xobj_id]["name"].lower(), xobj[xobj_id]["xmethtable"])
-
- raise ValueError("No XCOD resources found!")
-
-def extract_xmethtable_win16(file: BinaryIO, ne_offset: int) -> tuple[str, str, list[str]]:
- # get resource table
- file.seek(ne_offset + 0x24, os.SEEK_SET)
- restable_offset = read_uint16_le(file.read(0x2))
- resident_names_offset = read_uint16_le(file.read(0x2))
- file.seek(ne_offset + restable_offset)
- shift_count = read_uint16_le(file.read(0x2))
- # read each resource
- resources = []
- while file.tell() < ne_offset + resident_names_offset:
- type_id = read_uint16_le(file.read(0x2)) # should be 0x800a for XMETHTABLE
- if type_id == 0:
- break
- count = read_uint16_le(file.read(0x2))
- file.read(0x4) # reserved
- entries = []
- for i in range(count):
- file_offset = read_uint16_le(file.read(0x2))
- file_length = read_uint16_le(file.read(0x2))
- entries.append(dict(
- offset=file_offset << shift_count,
- length=file_length << shift_count
- ))
- file.read(0x2) # flagword
- file.read(0x2) # resource_id
- file.read(0x2) # handle
- file.read(0x2) # usage
- resources.append(dict(
- type_id=type_id,
- entries=entries
- ))
- resource_names = []
- while file.tell() < ne_offset + resident_names_offset:
- length = read_uint8(file.read(0x1))
- if length == 0:
- break
- resource_names.append(file.read(length).decode('ASCII'))
-
- print("Resources found:")
- print(resources, resource_names)
-
- xmethtable_exists = "XMETHTABLE" in resource_names
- file.seek(ne_offset + resident_names_offset)
- name_length = read_uint8(file.read(0x1))
- file_name = file.read(name_length).decode('ASCII')
-
- # Borland C++ can put the XMETHTABLE token into a weird nonstandard resource
- for x in filter(lambda d: d["type_id"] == 0x800f, resources):
- for y in x["entries"]:
- file.seek(y["offset"], os.SEEK_SET)
- data = file.read(y["length"])
- xmethtable_exists |= b"XMETHTABLE" in data
-
- if not xmethtable_exists:
- raise ValueError("XMETHTABLE not found!")
-
-
- resources = list(filter(lambda x: x["type_id"] == 0x800a, resources))
- if len(resources) != 1:
- raise ValueError("Expected a single matching resource type entry!")
-
- xmethtable_offset = resources[0]["entries"][0]["offset"]
- xmethtable_length = resources[0]["entries"][0]["length"]
- print(f"Found XMETHTABLE for XObject library {file_name}!")
- file.seek(xmethtable_offset, os.SEEK_SET)
- xmethtable_raw = file.read(xmethtable_length)
- xmethtable = [entry.decode('iso-8859-1') for entry in xmethtable_raw.strip(b"\x00").split(b"\x00")]
- for entry in xmethtable:
- print(entry)
- library_name = xmethtable[1]
- xmethtable[1] = "--" + library_name
- return library_name, file_name, xmethtable
+ return struct.unpack(">L", data)[0]
+
+
+def extract_xmethtable_macbinary(
+ file: BinaryIO, resource_offset: int, xobj_id: int | None = None
+) -> tuple[str, str, list[str]]:
+ file.seek(resource_offset)
+ resource_data_offset = read_uint32_be(file.read(4))
+ resource_map_offset = read_uint32_be(file.read(4))
+ resource_data_size = read_uint32_be(file.read(4))
+ resource_map_size = read_uint32_be(file.read(4))
+ file.seek(resource_offset + resource_map_offset + 24)
+ type_list_offset = read_uint16_be(file.read(2))
+ name_list_offset = read_uint16_be(file.read(2))
+ file.seek(resource_offset + resource_map_offset + type_list_offset)
+ type_count = read_uint16_be(file.read(2))
+ types = {}
+ for _ in range(type_count + 1):
+ key = file.read(4)
+ types[key] = (read_uint16_be(file.read(2)) + 1, read_uint16_be(file.read(2)))
+ if b"XCOD" in types:
+ print("Found XCOD resources!")
+ file.seek(
+ resource_offset + resource_map_offset + type_list_offset + types[b"XCOD"][1]
+ )
+ resources = []
+ for _ in range(types[b"XCOD"][0]):
+ id = read_uint16_be(file.read(2))
+ name_offset = read_uint16_be(file.read(2))
+ file.read(1)
+ data_offset = (read_uint8(file.read(1)) << 16) + read_uint16_be(
+ file.read(2)
+ )
+ file.read(4)
+ resources.append((id, data_offset, name_offset))
+ xobj: dict[int, dict[str, Any]] = {}
+ for id, data_offset, name_offset in resources:
+ xobj[id] = {}
+ if name_offset != 0xFFFF:
+ file.seek(
+ resource_offset
+ + resource_map_offset
+ + name_list_offset
+ + name_offset
+ )
+ name_size = read_uint8(file.read(1))
+ xobj[id]["name"] = file.read(name_size).decode("macroman")
+ else:
+ xobj[id]["name"] = "<unknown>"
+ file.seek(resource_offset + resource_data_offset + data_offset)
+ size = read_uint32_be(file.read(4)) - 12
+ file.read(12)
+ xobj[id]["xmethtable"] = []
+ while size > 0:
+ count = read_uint8(file.read(1))
+ if count == 0:
+ break
+ xobj[id]["xmethtable"].append(file.read(count).decode("macroman"))
+ size -= 1 + count
+ if xobj_id is None or xobj_id not in xobj:
+ print("Please re-run with one of the following XOBJ resource IDs:")
+ for id, data in xobj.items():
+ print(f"{id} - {data['name']}")
+ raise ValueError("Need to specify XOBJ resource ID")
+ for entry in xobj[xobj_id]["xmethtable"]:
+ print(entry)
+ return (
+ xobj[xobj_id]["name"],
+ xobj[xobj_id]["name"].lower(),
+ xobj[xobj_id]["xmethtable"],
+ )
+
+ raise ValueError("No XCOD resources found!")
+
+
+def extract_xmethtable_win16(
+ file: BinaryIO, ne_offset: int
+) -> tuple[str, str, list[str]]:
+ # get resource table
+ file.seek(ne_offset + 0x24, os.SEEK_SET)
+ restable_offset = read_uint16_le(file.read(0x2))
+ resident_names_offset = read_uint16_le(file.read(0x2))
+ file.seek(ne_offset + restable_offset)
+ shift_count = read_uint16_le(file.read(0x2))
+ # read each resource
+ resources: list[dict[str, Any]] = []
+ while file.tell() < ne_offset + resident_names_offset:
+ type_id = read_uint16_le(file.read(0x2)) # should be 0x800a for XMETHTABLE
+ if type_id == 0:
+ break
+ count = read_uint16_le(file.read(0x2))
+ file.read(0x4) # reserved
+ entries = []
+ for i in range(count):
+ file_offset = read_uint16_le(file.read(0x2))
+ file_length = read_uint16_le(file.read(0x2))
+ entries.append(
+ dict(
+ offset=file_offset << shift_count, length=file_length << shift_count
+ )
+ )
+ file.read(0x2) # flagword
+ file.read(0x2) # resource_id
+ file.read(0x2) # handle
+ file.read(0x2) # usage
+ resources.append(dict(type_id=type_id, entries=entries))
+ resource_names = []
+ while file.tell() < ne_offset + resident_names_offset:
+ length = read_uint8(file.read(0x1))
+ if length == 0:
+ break
+ resource_names.append(file.read(length).decode("ASCII"))
+
+ print("Resources found:")
+ print(resources, resource_names)
+
+ xmethtable_exists = "XMETHTABLE" in resource_names
+ file.seek(ne_offset + resident_names_offset)
+ name_length = read_uint8(file.read(0x1))
+ file_name = file.read(name_length).decode("ASCII")
+
+ # Borland C++ can put the XMETHTABLE token into a weird nonstandard resource
+ for x in filter(lambda d: d["type_id"] == 0x800F, resources):
+ for y in x["entries"]:
+ file.seek(y["offset"], os.SEEK_SET)
+ data = file.read(y["length"])
+ xmethtable_exists |= b"XMETHTABLE" in data
+
+ if not xmethtable_exists:
+ raise ValueError("XMETHTABLE not found!")
+
+ resources = list(filter(lambda x: x["type_id"] == 0x800A, resources))
+ if len(resources) != 1:
+ raise ValueError("Expected a single matching resource type entry!")
+
+ xmethtable_offset = resources[0]["entries"][0]["offset"]
+ xmethtable_length = resources[0]["entries"][0]["length"]
+ print(f"Found XMETHTABLE for XObject library {file_name}!")
+ file.seek(xmethtable_offset, os.SEEK_SET)
+ xmethtable_raw = file.read(xmethtable_length)
+ xmethtable = [
+ entry.decode("iso-8859-1")
+ for entry in xmethtable_raw.strip(b"\x00").split(b"\x00")
+ ]
+ for entry in xmethtable:
+ print(entry)
+ library_name = xmethtable[1]
+ xmethtable[1] = "--" + library_name
+ return library_name, file_name, xmethtable
def extract_xmethtable_win32(file: BinaryIO, pe_offset: int) -> tuple[str, list[str]]:
- # get the .data section
- # find a string b"msgTable\x00", get the offset
- # get the .text section
- # find assembly:
- # 68 [ addr ] 6a 00 6a [ addr 2 ]
- # lookup addr2 in .data
- # get c string, split by \x0a
+ # get the .data section
+ # find a string b"msgTable\x00", get the offset
+ # get the .text section
+ # find assembly:
+ # 68 [ addr ] 6a 00 6a [ addr 2 ]
+ # lookup addr2 in .data
+ # get c string, split by \x0a
+
+ return ("", [])
- return ("", [])
def extract_xmethtable(path: str, resid: int) -> tuple[str, str, list[str]]:
- with open(path, 'rb') as file:
- magic = file.read(0x2)
- if magic == b'MZ':
- file.seek(0x3c, os.SEEK_SET)
- header_offset = read_uint16_le(file.read(0x2))
- file.seek(header_offset, os.SEEK_SET)
- magic = file.read(0x2)
- if magic == b'NE':
- print("Found Win16 NE DLL!")
- return extract_xmethtable_win16(file, header_offset)
- elif magic == b'PE':
- raise ValueError("No support yet for extracting from Win32 DLLs")
- file.seek(0)
- header = file.read(124)
- if len(header) == 124 and header[0] == 0 and header[74] == 0 and header[82] == 0 and header[122] in [129, 130] and header[123] in [129, 130]:
- print("Found MacBinary!")
-
- data_size = read_uint32_be(header[83:87])
- resource_size = read_uint32_be(header[87:91])
- resource_offset = 128 + data_size + ((128 - (data_size % 128)) if (data_size % 128) else 0)
- print(f"resource offset: {resource_offset}")
- return extract_xmethtable_macbinary(file, resource_offset, resid)
-
- raise ValueError("Unknown filetype")
-
-
-def generate_stubs(xmethtable: list[str], slug: str, name: str, director_version: int=400, dry_run=False) -> None:
- meths = []
- for e in xmethtable:
- if not e.strip():
- break
- elems = e.split()
- if not elems or elems[0].startswith('--'):
- continue
- returnval = elems[0][0]
- args = elems[0][1:]
- methname = elems[1].split(",")[0]
- if methname.startswith('+'):
- methname = methname[1:]
- if methname.startswith('m'):
- methname = methname[1].lower() + methname[2:]
- meths.append(dict(
- methname=methname,
- args=args,
- arg_count=len(args),
- returnval=returnval,
- default= '""' if returnval == "S" else "0"
- ))
-
- xobject_class = f"{name}XObject"
- xobj_class = f"{name}XObj"
-
- cpp_text = TEMPLATE.format(
- slug=slug,
- xmethtable="\n".join(xmethtable),
-
- xobject_class=xobject_class,
- xobj_class=xobj_class,
- xlib_methods="\n".join([XLIB_METHOD_TEMPLATE.format(
- xobj_class=xobj_class,
- director_version=director_version,
- **x
- ) for x in meths]),
- xobj_stubs="\n".join([
- XOBJ_NR_STUB_TEMPLATE.format(xobj_class=xobj_class, **x)
- if x["returnval"] == "X" else
- XOBJ_STUB_TEMPLATE.format(xobj_class=xobj_class, **x)
- for x in meths if x["methname"] != "new"
- ]),
- )
- if dry_run:
- print("C++ output:")
- print(cpp_text)
- print()
- else:
- with open(os.path.join(LINGO_XLIBS_PATH, f"{slug}.cpp"), "w") as cpp:
- cpp.write(cpp_text)
-
- header_text = TEMPLATE_H.format(
- slug_upper=slug.upper(),
- xobject_class=f"{name}XObject",
- xobj_class=f"{name}XObj",
- methlist="\n".join([TEMPLATE_HEADER_METH.format(**x) for x in meths]),
- )
- if dry_run:
- print("Header output:")
- print(header_text)
- print()
- else:
- with open(os.path.join(LINGO_XLIBS_PATH, f"{slug}.h"), "w") as header:
- header.write(header_text)
+ with open(path, "rb") as file:
+ magic = file.read(0x2)
+ if magic == b"MZ":
+ file.seek(0x3C, os.SEEK_SET)
+ header_offset = read_uint16_le(file.read(0x2))
+ file.seek(header_offset, os.SEEK_SET)
+ magic = file.read(0x2)
+ if magic == b"NE":
+ print("Found Win16 NE DLL!")
+ return extract_xmethtable_win16(file, header_offset)
+ elif magic == b"PE":
+ raise ValueError("No support yet for extracting from Win32 DLLs")
+ file.seek(0)
+ header = file.read(124)
+ if (
+ len(header) == 124
+ and header[0] == 0
+ and header[74] == 0
+ and header[82] == 0
+ and header[122] in [129, 130]
+ and header[123] in [129, 130]
+ ):
+ print("Found MacBinary!")
+
+ data_size = read_uint32_be(header[83:87])
+ resource_size = read_uint32_be(header[87:91])
+ resource_offset = (
+ 128
+ + data_size
+ + ((128 - (data_size % 128)) if (data_size % 128) else 0)
+ )
+ print(f"resource offset: {resource_offset}")
+ return extract_xmethtable_macbinary(file, resource_offset, resid)
+
+ raise ValueError("Unknown filetype")
+
+
+def generate_stubs(
+ xmethtable: list[str],
+ slug: str,
+ name: str,
+ director_version: int = 400,
+ dry_run=False,
+) -> None:
+ meths = []
+ for e in xmethtable:
+ if not e.strip():
+ break
+ elems = e.split()
+ if not elems or elems[0].startswith("--"):
+ continue
+ returnval = elems[0][0]
+ args = elems[0][1:]
+ methname = elems[1].split(",")[0]
+ if methname.startswith("+"):
+ methname = methname[1:]
+ if methname.startswith("m"):
+ methname = methname[1].lower() + methname[2:]
+ meths.append(
+ dict(
+ methname=methname,
+ args=args,
+ arg_count=len(args),
+ returnval=returnval,
+ default='""' if returnval == "S" else "0",
+ )
+ )
+
+ xobject_class = f"{name}XObject"
+ xobj_class = f"{name}XObj"
+
+ cpp_text = TEMPLATE.format(
+ slug=slug,
+ xmethtable="\n".join(xmethtable),
+ xobject_class=xobject_class,
+ xobj_class=xobj_class,
+ xlib_methods="\n".join(
+ [
+ XLIB_METHOD_TEMPLATE.format(
+ xobj_class=xobj_class, director_version=director_version, **x
+ )
+ for x in meths
+ ]
+ ),
+ xobj_stubs="\n".join(
+ [
+ XOBJ_NR_STUB_TEMPLATE.format(xobj_class=xobj_class, **x)
+ if x["returnval"] == "X"
+ else XOBJ_STUB_TEMPLATE.format(xobj_class=xobj_class, **x)
+ for x in meths
+ if x["methname"] != "new"
+ ]
+ ),
+ )
+ if dry_run:
+ print("C++ output:")
+ print(cpp_text)
+ print()
+ else:
+ with open(os.path.join(LINGO_XLIBS_PATH, f"{slug}.cpp"), "w") as cpp:
+ cpp.write(cpp_text)
+
+ header_text = TEMPLATE_H.format(
+ slug_upper=slug.upper(),
+ xobject_class=f"{name}XObject",
+ xobj_class=f"{name}XObj",
+ methlist="\n".join([TEMPLATE_HEADER_METH.format(**x) for x in meths]),
+ )
+ if dry_run:
+ print("Header output:")
+ print(header_text)
+ print()
+ else:
+ with open(os.path.join(LINGO_XLIBS_PATH, f"{slug}.h"), "w") as header:
+ header.write(header_text)
def main() -> None:
- parser = argparse.ArgumentParser(
- description="Extract the method table from a Macromedia Director XObject/XLib and generate method stubs."
- )
- parser.add_argument("XOBJ_FILE", help="XObject/XLib file to test")
- parser.add_argument("--resid", help="XOBJ resource ID (for MacBinary)", type=int, default=None)
- parser.add_argument("--slug", help="Slug to use for files (e.g. {slug}.cpp, {slug}.h)")
- parser.add_argument("--name", help="Base name to use for classes (e.g. {name}XObj, {name}XObject)")
- parser.add_argument("--version", metavar="VER", help="Minimum Director version (default: 400)", default="400")
- parser.add_argument("--dry-run", help="Test only, don't write files", action='store_true')
- args = parser.parse_args()
-
- library_name, file_name, xmethtable = extract_xmethtable(args.XOBJ_FILE, args.resid)
- slug = args.slug or file_name
- name = args.name or library_name
- generate_stubs(xmethtable, slug, name, args.version, args.dry_run)
+ parser = argparse.ArgumentParser(
+ description="Extract the method table from a Macromedia Director XObject/XLib and generate method stubs."
+ )
+ parser.add_argument("XOBJ_FILE", help="XObject/XLib file to test")
+ parser.add_argument(
+ "--resid", help="XOBJ resource ID (for MacBinary)", type=int, default=None
+ )
+ parser.add_argument(
+ "--slug", help="Slug to use for files (e.g. {slug}.cpp, {slug}.h)"
+ )
+ parser.add_argument(
+ "--name", help="Base name to use for classes (e.g. {name}XObj, {name}XObject)"
+ )
+ parser.add_argument(
+ "--version",
+ metavar="VER",
+ help="Minimum Director version (default: 400)",
+ default="400",
+ )
+ parser.add_argument(
+ "--dry-run", help="Test only, don't write files", action="store_true"
+ )
+ args = parser.parse_args()
+
+ library_name, file_name, xmethtable = extract_xmethtable(args.XOBJ_FILE, args.resid)
+ slug = args.slug or file_name
+ name = args.name or library_name
+ generate_stubs(xmethtable, slug, name, args.version, args.dry_run)
if __name__ == "__main__":
- main()
+ main()
More information about the Scummvm-git-logs
mailing list