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.discovery.asm; 014 015import java.io.IOException; 016import java.io.InputStream; 017import java.util.Collections; 018import java.util.LinkedList; 019import java.util.List; 020import java.util.logging.Level; 021 022import net.minecraft.src.BaseMod; 023 024import org.objectweb.asm.ClassReader; 025import org.objectweb.asm.Type; 026 027import com.google.common.base.Objects; 028import com.google.common.base.Strings; 029import com.google.common.collect.Lists; 030 031import cpw.mods.fml.common.FMLLog; 032import cpw.mods.fml.common.LoaderException; 033import cpw.mods.fml.common.discovery.ASMDataTable; 034import cpw.mods.fml.common.discovery.ModCandidate; 035 036public class ASMModParser 037{ 038 039 private Type asmType; 040 private int classVersion; 041 private Type asmSuperType; 042 private LinkedList<ModAnnotation> annotations = Lists.newLinkedList(); 043 private String baseModProperties; 044 045 static enum AnnotationType 046 { 047 CLASS, FIELD, METHOD, SUBTYPE; 048 } 049 050 public ASMModParser(InputStream stream) throws IOException 051 { 052 try 053 { 054 ClassReader reader = new ClassReader(stream); 055 reader.accept(new ModClassVisitor(this), 0); 056 } 057 catch (Exception ex) 058 { 059 FMLLog.log(Level.SEVERE, ex, "Unable to read a class file correctly"); 060 throw new LoaderException(ex); 061 } 062 } 063 064 public void beginNewTypeName(String typeQName, int classVersion, String superClassQName) 065 { 066 this.asmType = Type.getObjectType(typeQName); 067 this.classVersion = classVersion; 068 this.asmSuperType = !Strings.isNullOrEmpty(superClassQName) ? Type.getObjectType(superClassQName) : null; 069 } 070 071 public void startClassAnnotation(String annotationName) 072 { 073 ModAnnotation ann = new ModAnnotation(AnnotationType.CLASS, Type.getType(annotationName), this.asmType.getClassName()); 074 annotations.addFirst(ann); 075 } 076 077 public void addAnnotationProperty(String key, Object value) 078 { 079 annotations.getFirst().addProperty(key, value); 080 } 081 082 public void startFieldAnnotation(String fieldName, String annotationName) 083 { 084 ModAnnotation ann = new ModAnnotation(AnnotationType.FIELD, Type.getType(annotationName), fieldName); 085 annotations.addFirst(ann); 086 } 087 088 @Override 089 public String toString() 090 { 091 return Objects.toStringHelper("ASMAnnotationDiscoverer") 092 .add("className", asmType.getClassName()) 093 .add("classVersion", classVersion) 094 .add("superName", asmSuperType.getClassName()) 095 .add("annotations", annotations) 096 .add("isBaseMod", isBaseMod(Collections.<String>emptyList())) 097 .add("baseModProperties", baseModProperties) 098 .toString(); 099 } 100 101 public Type getASMType() 102 { 103 return asmType; 104 } 105 106 public int getClassVersion() 107 { 108 return classVersion; 109 } 110 111 public Type getASMSuperType() 112 { 113 return asmSuperType; 114 } 115 116 public LinkedList<ModAnnotation> getAnnotations() 117 { 118 return annotations; 119 } 120 121 public void validate() 122 { 123// if (classVersion > 50.0) 124// { 125// 126// throw new LoaderException(new RuntimeException("Mod compiled for Java 7 detected")); 127// } 128 } 129 130 public boolean isBaseMod(List<String> rememberedTypes) 131 { 132 return getASMSuperType().equals(Type.getType("LBaseMod;")) || getASMSuperType().equals(Type.getType("Lnet/minecraft/src/BaseMod;"))|| rememberedTypes.contains(getASMSuperType().getClassName()); 133 } 134 135 public void setBaseModProperties(String foundProperties) 136 { 137 this.baseModProperties = foundProperties; 138 } 139 140 public String getBaseModProperties() 141 { 142 return this.baseModProperties; 143 } 144 145 public void sendToTable(ASMDataTable table, ModCandidate candidate) 146 { 147 for (ModAnnotation ma : annotations) 148 { 149 table.addASMData(candidate, ma.asmType.getClassName(), this.asmType.getClassName(), ma.member, ma.values); 150 } 151 } 152 153 public void addAnnotationArray(String name) 154 { 155 annotations.getFirst().addArray(name); 156 } 157 158 public void addAnnotationEnumProperty(String name, String desc, String value) 159 { 160 annotations.getFirst().addEnumProperty(name, desc, value); 161 162 } 163 164 public void endArray() 165 { 166 annotations.getFirst().endArray(); 167 168 } 169 170 public void addSubAnnotation(String name, String desc) 171 { 172 ModAnnotation ma = annotations.getFirst(); 173 annotations.addFirst(ma.addChildAnnotation(name, desc)); 174 } 175 176 public void endSubAnnotation() 177 { 178 // take the child and stick it at the end 179 ModAnnotation child = annotations.removeFirst(); 180 annotations.addLast(child); 181 } 182}