    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}