001package cpw.mods.fml.common.asm.transformers;
002
003import java.util.Iterator;
004import java.util.List;
005
006import org.objectweb.asm.ClassReader;
007import org.objectweb.asm.ClassWriter;
008import org.objectweb.asm.Type;
009import org.objectweb.asm.tree.AnnotationNode;
010import org.objectweb.asm.tree.ClassNode;
011import org.objectweb.asm.tree.FieldNode;
012import org.objectweb.asm.tree.MethodNode;
013
014import cpw.mods.fml.relauncher.FMLRelauncher;
015import cpw.mods.fml.relauncher.IClassTransformer;
016import cpw.mods.fml.relauncher.SideOnly;
017
018public class SideTransformer implements IClassTransformer
019{
020    private static String SIDE = FMLRelauncher.side();
021    private static final boolean DEBUG = false;
022    @SuppressWarnings("unchecked")
023    @Override
024    public byte[] transform(String name, byte[] bytes)
025    {
026        if (bytes == null) { return null; }
027
028        ClassNode classNode = new ClassNode();
029        ClassReader classReader = new ClassReader(bytes);
030        classReader.accept(classNode, 0);
031
032        if (remove((List<AnnotationNode>)classNode.visibleAnnotations, SIDE))
033        {
034            if (DEBUG)
035            {
036                System.out.println(String.format("Attempted to load class %s for invalid side %s", classNode.name, SIDE));
037            }
038            throw new RuntimeException(String.format("Attempted to load class %s for invalid side %s", classNode.name, SIDE));
039        }
040
041        Iterator<FieldNode> fields = classNode.fields.iterator();
042        while(fields.hasNext())
043        {
044            FieldNode field = fields.next();
045            if (remove((List<AnnotationNode>)field.visibleAnnotations, SIDE))
046            {
047                if (DEBUG)
048                {
049                    System.out.println(String.format("Removing Field: %s.%s", classNode.name, field.name));
050                }
051                fields.remove();
052            }
053        }
054        Iterator<MethodNode> methods = classNode.methods.iterator();
055        while(methods.hasNext())
056        {
057            MethodNode method = methods.next();
058            if (remove((List<AnnotationNode>)method.visibleAnnotations, SIDE))
059            {
060                if (DEBUG)
061                {
062                    System.out.println(String.format("Removing Method: %s.%s%s", classNode.name, method.name, method.desc));
063                }
064                methods.remove();
065            }
066        }
067
068        ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
069        classNode.accept(writer);
070        return writer.toByteArray();
071    }
072    
073    private boolean remove(List<AnnotationNode> anns, String side)
074    {
075        if (anns == null)
076        {
077            return false;
078        }
079        for (AnnotationNode ann : anns)
080        {
081            if (ann.desc.equals(Type.getDescriptor(SideOnly.class)))
082            {
083                if (ann.values != null)
084                {
085                    for (int x = 0; x < ann.values.size() - 1; x += 2)
086                    {
087                        Object key = ann.values.get(x);
088                        Object value = ann.values.get(x+1);
089                        if (key instanceof String && key.equals("value"))
090                        {
091                            if (value instanceof String[] )
092                            {
093                                if (!((String[])value)[1].equals(side))
094                                {
095                                    return true;
096                                }
097                            }
098                        }
099                    }
100                }
101            }
102        }
103        return false;
104    }
105}