Files
DroidDeck/tools/xbox/runtime.py
T

60 lines
2.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""Extract only pinned Windows GDK modules; Linux Wine stays ARM64."""
import hashlib
import json
from pathlib import Path
import shutil
import sys
import tarfile
import urllib.request
recipe = Path(__file__).resolve().parent
lock = json.loads((recipe / 'runtime.lock.json').read_text())
cache = Path(sys.argv[1]); output = Path(sys.argv[2])
cache.mkdir(parents=True, exist_ok=True)
output.mkdir(parents=True, exist_ok=True)
url = 'https://github.com/' + lock['repository'] + '/releases/download/' + lock['tag'] + '/'
def download(name, expected, algorithm):
target = cache / name
def matches():
if not target.is_file():
return False
digest = hashlib.new(algorithm)
with target.open('rb') as file:
for block in iter(lambda: file.read(1024 * 1024), b''):
digest.update(block)
return digest.hexdigest() == expected
if not matches():
part = target.with_suffix(target.suffix + '.part')
with urllib.request.urlopen(url + name, timeout=90) as response, part.open('wb') as file:
shutil.copyfileobj(response, file)
part.replace(target)
if not matches():
raise RuntimeError('Xbox runtime checksum mismatch: ' + name)
return target
archive = download(lock['archive'], lock['sha512'], 'sha512')
# Keep corresponding source available beside the build cache for redistribution.
source = lock['source']
download(source['name'], source['sha256'], 'sha256')
remaining = set(lock['dlls'])
with tarfile.open(archive) as tar:
for member in tar:
name = Path(member.name).name
if '/files/lib/wine/x86_64-windows/' not in member.name or name not in remaining:
continue
if not member.isfile() or member.size > 32 * 1024 * 1024:
raise RuntimeError('Invalid Xbox Windows runtime module')
data = tar.extractfile(member).read()
if hashlib.sha256(data).hexdigest() != lock['dlls'][name] or data[:2] != b'MZ':
raise RuntimeError('Xbox Windows runtime module checksum mismatch')
# Wine rejects builtin-tagged PE files when WINEDLLOVERRIDES selects native.
# These standalone Windows modules must use the native x64 loader on ARM64EC.
if data[64:80] == b'Wine builtin DLL':
data = data[:64] + b'DroidDeck native' + data[80:]
(output / name).write_bytes(data)
remaining.remove(name)
if remaining:
raise RuntimeError('Missing Xbox runtime modules')