001/* 002 * Forge Mod Loader 003 * Copyright (c) 2012-2013 cpw. 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser Public License v2.1 006 * which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 008 * 009 * Contributors: 010 * cpw - implementation 011 */ 012 013package cpw.mods.fml.common.asm.transformers; 014 015import java.util.Iterator; 016import java.util.List; 017 018import org.objectweb.asm.ClassReader; 019import org.objectweb.asm.ClassWriter; 020import org.objectweb.asm.Type; 021import org.objectweb.asm.tree.AnnotationNode; 022import org.objectweb.asm.tree.ClassNode; 023import org.objectweb.asm.tree.FieldNode; 024import org.objectweb.asm.tree.MethodNode; 025 026import cpw.mods.fml.relauncher.FMLRelauncher; 027import cpw.mods.fml.relauncher.IClassTransformer; 028import cpw.mods.fml.relauncher.SideOnly; 029 030public class SideTransformer implements IClassTransformer 031{ 032 private static String SIDE = FMLRelauncher.side(); 033 private static final boolean DEBUG = false; 034 @SuppressWarnings("unchecked") 035 @Override 036 public byte[] transform(String name, String transformedName, byte[] bytes) 037 { 038 if (bytes == null) { return null; } 039 040 ClassNode classNode = new ClassNode(); 041 ClassReader classReader = new ClassReader(bytes); 042 classReader.accept(classNode, 0); 043 044 if (remove((List<AnnotationNode>)classNode.visibleAnnotations, SIDE)) 045 { 046 if (DEBUG) 047 { 048 System.out.println(String.format("Attempted to load class %s for invalid side %s", classNode.name, SIDE)); 049 } 050 throw new RuntimeException(String.format("Attempted to load class %s for invalid side %s", classNode.name, SIDE)); 051 } 052 053 Iterator<FieldNode> fields = classNode.fields.iterator(); 054 while(fields.hasNext()) 055 { 056 FieldNode field = fields.next(); 057 if (remove((List<AnnotationNode>)field.visibleAnnotations, SIDE)) 058 { 059 if (DEBUG) 060 { 061 System.out.println(String.format("Removing Field: %s.%s", classNode.name, field.name)); 062 } 063 fields.remove(); 064 } 065 } 066 Iterator<MethodNode> methods = classNode.methods.iterator(); 067 while(methods.hasNext()) 068 { 069 MethodNode method = methods.next(); 070 if (remove((List<AnnotationNode>)method.visibleAnnotations, SIDE)) 071 { 072 if (DEBUG) 073 { 074 System.out.println(String.format("Removing Method: %s.%s%s", classNode.name, method.name, method.desc)); 075 } 076 methods.remove(); 077 } 078 } 079 080 ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); 081 classNode.accept(writer); 082 return writer.toByteArray(); 083 } 084 085 private boolean remove(List<AnnotationNode> anns, String side) 086 { 087 if (anns == null) 088 { 089 return false; 090 } 091 for (AnnotationNode ann : anns) 092 { 093 if (ann.desc.equals(Type.getDescriptor(SideOnly.class))) 094 { 095 if (ann.values != null) 096 { 097 for (int x = 0; x < ann.values.size() - 1; x += 2) 098 { 099 Object key = ann.values.get(x); 100 Object value = ann.values.get(x+1); 101 if (key instanceof String && key.equals("value")) 102 { 103 if (value instanceof String[] ) 104 { 105 if (!((String[])value)[1].equals(side)) 106 { 107 return true; 108 } 109 } 110 } 111 } 112 } 113 } 114 } 115 return false; 116 } 117}