Add initial AccessWidener

This commit is contained in:
2026-06-11 12:22:44 +02:00
parent e176b3bca8
commit 786257ad0e
15 changed files with 979 additions and 6 deletions
@@ -0,0 +1,63 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar;
import org.objectweb.asm.*;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Uses ASM to patch class bytecode according to a list of access widener entries.
*
* Returns {@code null} if the class is not targeted by any entry (no-op signal
* to the caller so it can skip the write).
*/
public class ClassPatcher {
private final List<AccessWidenerEntry> entries;
/** Pre-computed set of targeted internal names for fast filtering. */
private final Set<String> targets;
public ClassPatcher(List<AccessWidenerEntry> entries) {
this.entries = entries;
this.targets = entries.stream()
.map(AccessWidenerEntry::target)
.collect(Collectors.toSet());
}
/**
* Patches {@code classBytes} if {@code internalName} is targeted.
*
* @return patched bytes, or {@code null} if no changes were needed
*/
public byte[] patch(String internalName, byte[] classBytes) {
if (!targets.contains(internalName)) return null;
ClassReader cr = new ClassReader(classBytes);
// COMPUTE_FRAMES would require the full classpath; we only touch flags so 0 is fine
ClassWriter cw = new ClassWriter(cr, 0);
cr.accept(new ClassTransformer(cw, internalName, entries), 0);
return cw.toByteArray();
}
}