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    }