<commit_before>package invtweaks.forge.asm;

import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
import cpw.mods.fml.relauncher.FMLRelaunchLog;
import cpw.mods.fml.relauncher.IClassTransformer;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;

import java.util.HashMap;
import java.util.Map;


public class ContainerTransformer implements IClassTransformer {
    public static final String VALID_INVENTORY_METHOD = "invtweaks$validInventory";
    public static final String VALID_CHEST_METHOD = "invtweaks$validChest";
    public static final String STANDARD_INVENTORY_METHOD = "invtweaks$standardInventory";
    public static final String ROW_SIZE_METHOD = "invtweaks$rowSize";
    public static final String SLOT_MAP_METHOD = "invtweaks$slotMap";
    public static final String CONTAINER_CLASS_INTERNAL = "net/minecraft/inventory/Container";
    public static final String SLOT_MAPS_VANILLA_CLASS = "invtweaks/containers/VanillaSlotMaps";
    public static final String SLOT_MAPS_MODCOMPAT_CLASS = "invtweaks/containers/CompatibilitySlotMaps";

    private static Map<String, ContainerInfo> standardClasses = new HashMap<String, ContainerInfo>();
    private static Map<String, ContainerInfo> compatibilityClasses = new HashMap<String, ContainerInfo>();
    private String containerClassName;

    public ContainerTransformer() {
    }

    // This needs to have access to the FML remapper so it needs to run when we know it's been set up correctly.
    private void lateInit() {
        // TODO: ContainerCreative handling
        // Standard non-chest type
        standardClasses.put("net.minecraft.inventory.ContainerPlayer",
                            new ContainerInfo(true, true, false, getVanillaSlotMapInfo("containerPlayerSlots")));
        standardClasses.put("net.minecraft.inventory.ContainerMerchant", new ContainerInfo(true, true, false));
        standardClasses.put("net.minecraft.inventory.ContainerRepair",
                            new ContainerInfo(true, true, false, getVanillaSlotMapInfo("containerPlayerSlots")));
        standardClasses.put("net.minecraft.inventory.ContainerHopper", new ContainerInfo(true, true, false));
        standardClasses.put("net.minecraft.inventory.ContainerBeacon", new ContainerInfo(true, true, false));
        standardClasses.put("net.minecraft.inventory.ContainerBrewingStand",
                            new ContainerInfo(true, true, false, getVanillaSlotMapInfo("containerBrewingSlots")));
        standardClasses.put("net.minecraft.inventory.ContainerWorkbench",
                            new ContainerInfo(true, true, false, getVanillaSlotMapInfo("containerWorkbenchSlots")));
        standardClasses.put("net.minecraft.inventory.ContainerEnchantment",
                            new ContainerInfo(true, true, false, getVanillaSlotMapInfo("containerEnchantmentSlots")));
        standardClasses.put("net.minecraft.inventory.ContainerFurnace",
                            new ContainerInfo(true, true, false, getVanillaSlotMapInfo("containerFurnaceSlots")));

        // Chest-type
        standardClasses.put("net.minecraft.inventory.ContainerDispenser",
                            new ContainerInfo(false, false, true, (short) 3,
                                              getVanillaSlotMapInfo("containerChestDispenserSlots")));
        standardClasses.put("net.minecraft.inventory.ContainerChest", new ContainerInfo(false, false, true,
                                                                                        getVanillaSlotMapInfo(
                                                                                                "containerChestDispenserSlots")));

        // Mod compatibility
        compatibilityClasses.put("micdoodle8.mods.galacticraft.core.inventory.GCCoreContainerPlayer",
                                 new ContainerInfo(true, true, false,
                                                   getCompatiblitySlotMapInfo("galacticraftPlayerSlots")));
    }

    @Override
    public byte[] transform(String name, String transformedName, byte[] bytes) {
        if(containerClassName == null) {
            if(FMLPlugin.runtimeDeobfEnabled) {
                containerClassName = FMLDeobfuscatingRemapper.INSTANCE.unmap(CONTAINER_CLASS_INTERNAL);
            } else {
                containerClassName = CONTAINER_CLASS_INTERNAL;
            }
            lateInit();
        }

        ClassReader cr = new ClassReader(bytes);
        ClassNode cn = new ClassNode(Opcodes.ASM4);
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);

        cr.accept(cn, 0);

        if("net.minecraft.inventory.Container".equals(transformedName)) {
            FMLRelaunchLog.info("InvTweaks: %s", transformedName);

            transformBaseContainer(cn);

            cn.accept(cw);
            return cw.toByteArray();
        }

        // Transform classes with explicitly specified information
        ContainerInfo info = standardClasses.get(transformedName);
        if(info != null) {
            FMLRelaunchLog.info("InvTweaks: %s", transformedName);

            transformContainer(cn, info);

            cn.accept(cw);
            return cw.toByteArray();
        }

        if("invtweaks.InvTweaksObfuscation".equals(transformedName)) {
            FMLRelaunchLog.info("InvTweaks: %s", transformedName);

            Type containertype =
                    Type.getObjectType(containerClassName);
            for(MethodNode method : cn.methods) {
                if("isValidChest".equals(method.name)) {
                    ASMHelper.replaceSelfForwardingMethod(method, VALID_CHEST_METHOD, containertype);
                } else if("isValidInventory".equals(method.name)) {
                    ASMHelper.replaceSelfForwardingMethod(method, VALID_INVENTORY_METHOD, containertype);
                } else if("isStandardInventory".equals(method.name)) {
                    ASMHelper.replaceSelfForwardingMethod(method, STANDARD_INVENTORY_METHOD, containertype);
                } else if("getSpecialChestRowSize".equals(method.name)) {
                    ASMHelper.replaceSelfForwardingMethod(method, ROW_SIZE_METHOD, containertype);
                } else if("getContainerSlotMap".equals(method.name)) {
                    ASMHelper.replaceSelfForwardingMethod(method, SLOT_MAP_METHOD, containertype);
                }
            }

            cn.accept(cw);
            return cw.toByteArray();
        }

        // TODO: Check API annotations here<commit_msg>Add annotation detection for the main API annotations.<commit_after>package invtweaks.forge.asm;

import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
import cpw.mods.fml.relauncher.FMLRelaunchLog;
import cpw.mods.fml.relauncher.IClassTransformer;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;

import java.util.HashMap;
import java.util.Map;


public class ContainerTransformer implements IClassTransformer {
    public static final String VALID_INVENTORY_METHOD = "invtweaks$validInventory";
    public static final String VALID_CHEST_METHOD = "invtweaks$validChest";
    public static final String STANDARD_INVENTORY_METHOD = "invtweaks$standardInventory";
    public static final String ROW_SIZE_METHOD = "invtweaks$rowSize";
    public static final String SLOT_MAP_METHOD = "invtweaks$slotMap";
    public static final String CONTAINER_CLASS_INTERNAL = "net/minecraft/inventory/Container";
    public static final String SLOT_MAPS_VANILLA_CLASS = "invtweaks/containers/VanillaSlotMaps";
    public static final String SLOT_MAPS_MODCOMPAT_CLASS = "invtweaks/containers/CompatibilitySlotMaps";
    public static final String ANNOTATION_CHEST_CONTAINER = "Linvtweaks/api/container/ChestContainer;";
    public static final String ANNOTATION_INVENTORY_CONTAINER = "Linvtweaks/api/container/InventoryContainer;";
    public static final String ANNOTATION_CONTAINER_SECTION_CALLBACK = "Linvtweaks/api/container/ContainerSectionCallback;";

    private static Map<String, ContainerInfo> standardClasses = new HashMap<String, ContainerInfo>();
    private static Map<String, ContainerInfo> compatibilityClasses = new HashMap<String, ContainerInfo>();
    private String containerClassName;

    public ContainerTransformer() {
    }

    // This needs to have access to the FML remapper so it needs to run when we know it's been set up correctly.
    private void lateInit() {
        // TODO: ContainerCreative handling
        // Standard non-chest type
        standardClasses.put("net.minecraft.inventory.ContainerPlayer",
                            new ContainerInfo(true, true, false, getVanillaSlotMapInfo("containerPlayerSlots")));
        standardClasses.put("net.minecraft.inventory.ContainerMerchant", new ContainerInfo(true, true, false));
        standardClasses.put("net.minecraft.inventory.ContainerRepair",
                            new ContainerInfo(true, true, false, getVanillaSlotMapInfo("containerPlayerSlots")));
        standardClasses.put("net.minecraft.inventory.ContainerHopper", new ContainerInfo(true, true, false));
        standardClasses.put("net.minecraft.inventory.ContainerBeacon", new ContainerInfo(true, true, false));
        standardClasses.put("net.minecraft.inventory.ContainerBrewingStand",
                            new ContainerInfo(true, true, false, getVanillaSlotMapInfo("containerBrewingSlots")));
        standardClasses.put("net.minecraft.inventory.ContainerWorkbench",
                            new ContainerInfo(true, true, false, getVanillaSlotMapInfo("containerWorkbenchSlots")));
        standardClasses.put("net.minecraft.inventory.ContainerEnchantment",
                            new ContainerInfo(true, true, false, getVanillaSlotMapInfo("containerEnchantmentSlots")));
        standardClasses.put("net.minecraft.inventory.ContainerFurnace",
                            new ContainerInfo(true, true, false, getVanillaSlotMapInfo("containerFurnaceSlots")));

        // Chest-type
        standardClasses.put("net.minecraft.inventory.ContainerDispenser",
                            new ContainerInfo(false, false, true, (short) 3,
                                              getVanillaSlotMapInfo("containerChestDispenserSlots")));
        standardClasses.put("net.minecraft.inventory.ContainerChest", new ContainerInfo(false, false, true,
                                                                                        getVanillaSlotMapInfo(
                                                                                                "containerChestDispenserSlots")));

        // Mod compatibility
        compatibilityClasses.put("micdoodle8.mods.galacticraft.core.inventory.GCCoreContainerPlayer",
                                 new ContainerInfo(true, true, false,
                                                   getCompatiblitySlotMapInfo("galacticraftPlayerSlots")));
    }

    @Override
    public byte[] transform(String name, String transformedName, byte[] bytes) {
        if(containerClassName == null) {
            if(FMLPlugin.runtimeDeobfEnabled) {
                containerClassName = FMLDeobfuscatingRemapper.INSTANCE.unmap(CONTAINER_CLASS_INTERNAL);
            } else {
                containerClassName = CONTAINER_CLASS_INTERNAL;
            }
            lateInit();
        }

        ClassReader cr = new ClassReader(bytes);
        ClassNode cn = new ClassNode(Opcodes.ASM4);
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);

        cr.accept(cn, 0);

        if("net.minecraft.inventory.Container".equals(transformedName)) {
            FMLRelaunchLog.info("InvTweaks: %s", transformedName);

            transformBaseContainer(cn);

            cn.accept(cw);
            return cw.toByteArray();
        }

        // Transform classes with explicitly specified information
        ContainerInfo info = standardClasses.get(transformedName);
        if(info != null) {
            FMLRelaunchLog.info("InvTweaks: %s", transformedName);

            transformContainer(cn, info);

            cn.accept(cw);
            return cw.toByteArray();
        }

        if("invtweaks.InvTweaksObfuscation".equals(transformedName)) {
            FMLRelaunchLog.info("InvTweaks: %s", transformedName);

            Type containertype =
                    Type.getObjectType(containerClassName);
            for(MethodNode method : cn.methods) {
                if("isValidChest".equals(method.name)) {
                    ASMHelper.replaceSelfForwardingMethod(method, VALID_CHEST_METHOD, containertype);
                } else if("isValidInventory".equals(method.name)) {
                    ASMHelper.replaceSelfForwardingMethod(method, VALID_INVENTORY_METHOD, containertype);
                } else if("isStandardInventory".equals(method.name)) {
                    ASMHelper.replaceSelfForwardingMethod(method, STANDARD_INVENTORY_METHOD, containertype);
                } else if("getSpecialChestRowSize".equals(method.name)) {
                    ASMHelper.replaceSelfForwardingMethod(method, ROW_SIZE_METHOD, containertype);
                } else if("getContainerSlotMap".equals(method.name)) {
                    ASMHelper.replaceSelfForwardingMethod(method, SLOT_MAP_METHOD, containertype);
                }
            }

            cn.accept(cw);
            return cw.toByteArray();
        }

        if(cn.visibleAnnotations != null) {
            for(AnnotationNode annotation : cn.visibleAnnotations) {
                if(annotation != null) {
                    ContainerInfo apiInfo = null;

                    if(ANNOTATION_CHEST_CONTAINER.equals(annotation.desc)) {
                        apiInfo = new ContainerInfo(false, false, true, (short)((Integer)annotation.values.get(0)).intValue());
                        // TODO: ChestContainer.RowSizeCallback annotation support
                    } else if(ANNOTATION_INVENTORY_CONTAINER.equals(annotation.desc)) {
                        apiInfo = new ContainerInfo((Boolean)annotation.values.get(0), true, false);
                    }

                    if(apiInfo != null) {
                        // Search methods to see if any have the ContainerSectionCallback attribute.
                        methodsearch:
                        for(MethodNode method : cn.methods) {
                            if(method.visibleAnnotations != null) {
                                for(AnnotationNode methodAnnotation : method.visibleAnnotations) {
                                    if(ANNOTATION_CONTAINER_SECTION_CALLBACK.equals(methodAnnotation.desc)) {
                                        apiInfo.slotMapMethod = new MethodInfo(Type.getMethodType(method.desc), Type.getObjectType(cn.name), method.name);
                                        break methodsearch;
                                    }
                                }
                            }
                        }

                        transformContainer(cn, apiInfo);
                    }
                }
            }
        }
{'fraction_non_alphanumeric': 0.08812434963579605, 'fraction_numerical': 0.0006503642039542144, 'mean_word_length': 2.4400447427293064, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 30, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1460731', 'n_tokens_mistral': 4034, 'n_tokens_neox': 3897, 'n_words': 686}