/* * 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 . */ 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 entries; /** Pre-computed set of targeted internal names for fast filtering. */ private final Set targets; public ClassPatcher(List 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; } } }