    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}