forked from SteamWar/SteamWar
72 lines
2.4 KiB
Java
72 lines
2.4 KiB
Java
/*
|
|
* 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.ClassReader;
|
|
import org.objectweb.asm.ClassWriter;
|
|
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.logging.Logger;
|
|
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 static final Logger LOG = Logger.getLogger("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 className} is targeted.
|
|
*
|
|
* @return patched bytes, or {@code null} if no changes were needed
|
|
*/
|
|
public byte[] patch(String className, byte[] classBytes) {
|
|
if (!targets.contains(className)) return null;
|
|
|
|
try {
|
|
ClassReader cr = new ClassReader(classBytes);
|
|
ClassWriter cw = new ClassWriter(cr, 0);
|
|
cr.accept(new ClassTransformer(cw, className, entries), ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
|
return cw.toByteArray();
|
|
} catch (Exception e) {
|
|
LOG.warning("[AccessWidener] Failed to transform " + className + ": " + e.getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|