001package cpw.mods.fml.common.discovery.asm;
002
003import java.io.IOException;
004import java.io.InputStream;
005import java.util.Collections;
006import java.util.LinkedList;
007import java.util.List;
008import java.util.logging.Level;
009
010import net.minecraft.src.BaseMod;
011
012import org.objectweb.asm.ClassReader;
013import org.objectweb.asm.Type;
014
015import com.google.common.base.Objects;
016import com.google.common.collect.Lists;
017
018import cpw.mods.fml.common.FMLLog;
019import cpw.mods.fml.common.LoaderException;
020import cpw.mods.fml.common.discovery.ASMDataTable;
021import cpw.mods.fml.common.discovery.ModCandidate;
022
023public 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}