    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    }