forked from arti/vt1200
The TFTP font path loads through 3F96B850 and parses with the metadata reader 3F97EF00, which handles only PROPERTIES/ACCELERATORS/METRICS/ ENCODINGS and silently skips BITMAPS. A font with num_chars=0x40000001 therefore passes the loader (LOADER-A-SUCCESS) without the field ever being read, and pcfReadBitmaps (3F984970, multiply 3F985050) is never entered. pcfReadBitmaps has exactly one caller, 3F98BB70, in the X11 font-request reader 3F98AC20, not the TFTP fetch path. The 'refused after 1024 bytes' of evil-real.pcf is the METRICS table: its big-endian compressed count 0x00DF is read little-endian as 57088, so fosAlloc(57088*16) fails at ~906 bytes; BITMAPS (offset 2024) is never reached. Baseline.pcf fails the same way; baseline_le.pcf puts that one 2-byte field in the order the loader reads it, parses cleanly, and still ignores the crafted BITMAPS count. No ROM patch, no check disabled, no serve.py edit. Baselines unchanged: no env samples=198, stub samples=53.
55 lines
1.9 KiB
Python
55 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""pcfwork: serve a proper font index + one candidate font over TFTP.
|
|
|
|
Unlike serve_candidate.py (which serves the PCF bytes as the index, so the
|
|
terminal derives a garbage name), this serves a real `fonts.dir` naming the
|
|
candidate with its own internal XLFD, so the terminal's name check can pass and
|
|
the font can actually be registered/opened.
|
|
|
|
python3 serve_index.py <candidate.pcf> <XLFD-name> [font-file] [dir] [bind-ip]
|
|
"""
|
|
import os
|
|
import sys
|
|
import time
|
|
|
|
ROOT = "/home/arti/code/k-space/vt1200"
|
|
sys.path.insert(0, os.path.join(ROOT, "tools"))
|
|
import fontgen # noqa: E402
|
|
|
|
cand_path = sys.argv[1]
|
|
xlfd = sys.argv[2] if len(sys.argv) > 2 else "-misc-vt1200test-medium-r-normal--8-80-75-75-c-80-iso8859-1"
|
|
font_file = sys.argv[3] if len(sys.argv) > 3 else "v1200a.pcf"
|
|
fontdir = sys.argv[4] if len(sys.argv) > 4 else "69"
|
|
host = sys.argv[5] if len(sys.argv) > 5 else "192.168.99.1"
|
|
|
|
with open(cand_path, "rb") as fh:
|
|
cand = fh.read()
|
|
index = f"1\n{font_file} {xlfd}\n".encode()
|
|
print(f"index={index!r}", flush=True)
|
|
print(f"font {font_file} -> {os.path.basename(cand_path)} ({len(cand)}B)", flush=True)
|
|
|
|
|
|
def resolve(name):
|
|
if name == fontdir or name == fontdir + "/":
|
|
return cand # the path object: the terminal reads it first
|
|
if name.endswith("fonts.dir"):
|
|
return index
|
|
if name == font_file or name.endswith("/" + font_file) or name.endswith(font_file):
|
|
return cand
|
|
return None # anything else: honest "file not found"
|
|
|
|
|
|
srv = fontgen.TFTPServer((host, 69), {}, timeout=60.0, retries=10,
|
|
resolver=resolve).start()
|
|
try:
|
|
while True:
|
|
time.sleep(0.5)
|
|
while srv.log:
|
|
ts, name, addr = srv.log.pop(0)
|
|
stamp = time.strftime("%H:%M:%S", time.localtime(ts))
|
|
print(f"{stamp} {addr[0]}:{addr[1]} requested {name!r}", flush=True)
|
|
except KeyboardInterrupt:
|
|
pass
|
|
finally:
|
|
srv.stop()
|