package de.take_weiland.mods.commons.asm; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import de.take_weiland.mods.commons.asm.info.ClassInfo; import net.minecraft.launchwrapper.IClassTransformer; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; import javax.annotation.Nullable; import java.util.List; import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; /** * <p>Implementation of {@link net.minecraft.launchwrapper.IClassTransformer}, which uses a number of * {@link de.take_weiland.mods.commons.asm.ASMClassTransformer ASMClassTransformers} to transform classes.</p> * <p>This class makes a best-effort to reuse ClassNodes so that the class bytes don't have to be parsed over and over again.</p> * * @author diesieben07 */ public abstract class ASMClassTransformerWrapper implements IClassTransformer { private final List<ASMClassTransformer> transformers; public ASMClassTransformerWrapper() { ImmutableList.Builder<ASMClassTransformer> b = ImmutableList.builder(); setup(b); transformers = b.build(); } @Override public final byte[] transform(String name, String transformedName, @Nullable byte[] bytes) { try { return transform0(transformedName, bytes); } catch (Throwable t) { System.err.println("Exception during transformation of " + transformedName + " [" + name + "]"); t.printStackTrace(); throw Throwables.propagate(t); } } private byte[] transform0(String transformedName, @Nullable byte[] bytes) { if (bytes == null) { return null; } String internalName = transformedName.replace('.', '/'); ClassNode clazz = null; ClassInfo classInfo = null; boolean changed = false; for (ASMClassTransformer transformer : transformers) { if (transformer.transforms(internalName)) { if (clazz == null) { ClassReader cr = new ClassReader(bytes); cr.accept((clazz = new ClassNode()), 0); classInfo = ClassInfo.of(clazz); } changed |= transformer.transform(clazz, classInfo); } } if (changed) { ClassWriter cw = new ClassInfoClassWriter(COMPUTE_FRAMES); clazz.accept(cw); return cw.toByteArray(); } return bytes; } /** * <p>Register your transformers here.</p> * * @param builder a builder to add your transformers to */ protected abstract void setup(ImmutableList.Builder<ASMClassTransformer> builder); }