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