70 lines
2.0 KiB
Python
70 lines
2.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Removes MethodParameters attributes from .class files (in place).
|
|
|
|
JDK 21+ javac always emits them for inner-class constructors, and older d8 releases
|
|
crash on the nameless ones. They are only reflection metadata, so dropping them is safe.
|
|
usage: strip_method_params.py file.class...
|
|
"""
|
|
import struct
|
|
import sys
|
|
|
|
|
|
def strip(path):
|
|
d = open(path, "rb").read()
|
|
n = struct.unpack(">H", d[8:10])[0]
|
|
p, i, utf8 = 10, 1, {}
|
|
while i < n:
|
|
t = d[p]
|
|
if t == 1:
|
|
ln = struct.unpack(">H", d[p + 1:p + 3])[0]
|
|
utf8[i] = d[p + 3:p + 3 + ln]
|
|
p += 3 + ln
|
|
elif t in (3, 4, 9, 10, 11, 12, 17, 18):
|
|
p += 5
|
|
elif t in (5, 6):
|
|
p += 9
|
|
i += 1
|
|
elif t in (7, 8, 16, 19, 20):
|
|
p += 3
|
|
elif t == 15:
|
|
p += 4
|
|
else:
|
|
raise ValueError("bad constant tag %d in %s" % (t, path))
|
|
i += 1
|
|
out = bytearray(d[:p])
|
|
p_access = p
|
|
ifaces = struct.unpack(">H", d[p + 6:p + 8])[0]
|
|
p += 8 + 2 * ifaces
|
|
out += d[p_access:p]
|
|
|
|
def members(p, drop):
|
|
count = struct.unpack(">H", d[p:p + 2])[0]
|
|
buf = bytearray(d[p:p + 2])
|
|
p += 2
|
|
for _ in range(count):
|
|
buf += d[p:p + 6]
|
|
acount = struct.unpack(">H", d[p + 6:p + 8])[0]
|
|
p += 8
|
|
kept = []
|
|
for _ in range(acount):
|
|
name, ln = struct.unpack(">HI", d[p:p + 6])
|
|
if utf8.get(name) != drop:
|
|
kept.append(d[p:p + 6 + ln])
|
|
p += 6 + ln
|
|
buf += struct.pack(">H", len(kept)) + b"".join(kept)
|
|
return p, buf
|
|
|
|
p, fields = members(p, None)
|
|
out += fields
|
|
p, methods = members(p, b"MethodParameters")
|
|
out += methods
|
|
out += d[p:]
|
|
if bytes(out) != d:
|
|
open(path, "wb").write(bytes(out))
|
|
return 1
|
|
return 0
|
|
|
|
|
|
changed = sum(strip(f) for f in sys.argv[1:])
|
|
print("stripped MethodParameters from %d class files" % changed)
|