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