nl.hardijzer.fw.srgcollisions.Method.java Source code

Java tutorial

Introduction

Here is the source code for nl.hardijzer.fw.srgcollisions.Method.java

Source

/*
 * Copyright 2012 Frans-Willem Hardijzer
 * This file is part of SrgTools.
 *
 * SrgTools is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * SrgTools is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with SrgTools.  If not, see <http://www.gnu.org/licenses/>.
 */

package nl.hardijzer.fw.srgcollisions;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.objectweb.asm.*;

class Method implements Comparable<Method> {
    public String name;
    public String desc;

    public Method(String strName, String strArguments) {
        this.name = strName;
        this.desc = strArguments;
    }

    @Override
    public int compareTo(Method b) {
        int cmpName = name.compareTo(b.name);
        int cmpDesc = desc.compareTo(b.desc);
        if (cmpName != 0)
            return cmpName;
        return cmpDesc;
    }
}

class MappedClass {
    public String strNewName;
    public Map<String, String> mapFields;
    public Map<Method, Method> mapMethods;

    public MappedClass(String strNewName) {
        this.strNewName = strNewName;
        this.mapFields = new TreeMap<String, String>();
        this.mapMethods = new TreeMap<Method, Method>();
    }
}

class ClassInfo {
    public String strName;
    public Set<String> sFields;
    public Set<Method> sMethods;
    public Set<String> sImplements;
    public String strSuperName;

    public ClassInfo() {
        this.sFields = new TreeSet<String>();
        this.sMethods = new TreeSet<Method>();
        this.sImplements = new TreeSet<String>();
        this.strName = "";
        this.strSuperName = "";
    }
}

class ClassInfoCollector extends ClassVisitor {
    ClassInfo info;

    public ClassInfoCollector(int api) {
        super(api);
        info = new ClassInfo();
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName,
            String[] interfaces) {
        info.strName = name;
        info.strSuperName = superName;
        if (interfaces != null)
            for (String i : interfaces)
                info.sImplements.add(i);
    }

    @Override
    public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void visitAttribute(Attribute arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void visitEnd() {
        // TODO Auto-generated method stub

    }

    @Override
    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
        info.sFields.add(name);
        return null;
    }

    @Override
    public void visitInnerClass(String arg0, String arg1, String arg2, int arg3) {
        // TODO Auto-generated method stub

    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        info.sMethods.add(new Method(name, desc));
        return null;
    }

    @Override
    public void visitOuterClass(String arg0, String arg1, String arg2) {
        // TODO Auto-generated method stub

    }

    @Override
    public void visitSource(String arg0, String arg1) {
        // TODO Auto-generated method stub

    }

}

public class SrgCollisions {
    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        String strInputSrg = null;
        String strInputJar = null;
        for (int i = 0; i < args.length; i++) {
            if (args[i].equals("--srg"))
                strInputSrg = args[++i];
            else if (args[i].equals("--in"))
                strInputJar = args[++i];
            else
                System.err.println("Unknown option: " + args[i]);
        }
        if (strInputSrg == null || strInputJar == null) {
            System.err.println("Usage: java -jar srgtool.jar collisions --srg file.srg --in file.jar");
            return;
        }
        Map<String, MappedClass> mapClasses = new TreeMap<String, MappedClass>();
        BufferedReader brSrg = new BufferedReader(new InputStreamReader(new FileInputStream(strInputSrg)));
        String line;
        while ((line = brSrg.readLine()) != null) {
            String[] lineParts = line.split(" ");
            String tmp;
            if (lineParts[0].equals("PK:")) {
                //Package, ignoring for now. We're not actually using that anywhere
            } else if (lineParts[0].equals("CL:")) {
                String strFrom = lineParts[1];
                String strTo = lineParts[2];
                MappedClass mapped = mapClasses.get(strFrom);
                if (mapped != null) {
                    if (!mapped.strNewName.equals(strTo)) {
                        System.err.println("Inconsistent class mapping");
                        return;
                    }
                } else {
                    mapClasses.put(strFrom, new MappedClass(strTo));
                }
            } else if (lineParts[0].equals("FD:")) {
                String strFrom = lineParts[1];
                String strTo = lineParts[2];
                int nSplitFrom = strFrom.lastIndexOf('/');
                int nSplitTo = strTo.lastIndexOf('/');
                if (nSplitFrom == -1 || nSplitTo == -1) {
                    System.err.println("ERROR: Invalid field specification");
                    return;
                }
                String strFromClass = strFrom.substring(0, nSplitFrom);
                strFrom = strFrom.substring(nSplitFrom + 1);
                String strToClass = strTo.substring(0, nSplitTo);
                strTo = strTo.substring(nSplitTo + 1);

                MappedClass mappedClass = mapClasses.get(strFromClass);
                if (mappedClass != null) {
                    if (!mappedClass.strNewName.equals(strToClass)) {
                        System.err.println("Inconsistent class mapping");
                        return;
                    }
                } else {
                    mapClasses.put(strFromClass, mappedClass = new MappedClass(strToClass));
                }
                String mappedField = mappedClass.mapFields.get(strFrom);
                if (mappedField != null) {
                    if (!mappedField.equals(strTo)) {
                        System.err.println("Inconsistent field mapping");
                        return;
                    }
                } else {
                    mappedClass.mapFields.put(strFrom, strTo);
                }
            } else if (lineParts[0].equals("MD:")) {
                String strFrom = lineParts[1];
                String strTo = lineParts[3];
                int nSplitFrom = strFrom.lastIndexOf('/');
                int nSplitTo = strTo.lastIndexOf('/');
                if (nSplitFrom == -1 || nSplitTo == -1) {
                    System.err.println("ERROR: Invalid field specification");
                    return;
                }
                String strFromClass = strFrom.substring(0, nSplitFrom);
                strFrom = strFrom.substring(nSplitFrom + 1);
                String strToClass = strTo.substring(0, nSplitTo);
                strTo = strTo.substring(nSplitTo + 1);

                MappedClass mappedClass = mapClasses.get(strFromClass);
                if (mappedClass != null) {
                    if (!mappedClass.strNewName.equals(strToClass)) {
                        System.err.println("Inconsistent class mapping");
                        return;
                    }
                } else {
                    mapClasses.put(strFromClass, mappedClass = new MappedClass(strToClass));
                }
                Method mFrom = new Method(strFrom, lineParts[2]);
                Method mTo = new Method(strTo, lineParts[4]);

                Method mappedMethod = mappedClass.mapMethods.get(mFrom);
                if (mappedMethod != null) {
                    if (mappedMethod.compareTo(mTo) != 0) {
                        System.err.println("Inconsistent method mapping");
                        return;
                    }
                } else {
                    mappedClass.mapMethods.put(mFrom, mTo);
                }
            } else {
                System.err.println("Unknown command: '" + lineParts[0] + "', aborting");
                return;
            }
        }
        Map<String, ClassInfo> mapInfo = new TreeMap<String, ClassInfo>();

        ZipFile zipInput = new ZipFile(strInputJar);
        Enumeration<? extends ZipEntry> entries = zipInput.entries();
        while (entries.hasMoreElements()) {
            ZipEntry entry = entries.nextElement();
            if (entry.isDirectory())
                continue;
            if (entry.getName().endsWith(".class")) {
                ClassReader cr = new ClassReader(zipInput.getInputStream(entry));
                ClassInfoCollector cic = new ClassInfoCollector(Opcodes.ASM5);
                cr.accept(cic, ClassReader.SKIP_CODE);
                mapInfo.put(cic.info.strName, cic.info);
            }
        }
        zipInput.close();

        for (String strClass : mapInfo.keySet()) {
            ClassInfo info = mapInfo.get(strClass);
            MappedClass map = mapClasses.get(strClass);
            if (map == null)
                continue;
            Map<String, String> mapFields = new TreeMap<String, String>();
            Map<Method, Method> mapMethods = new TreeMap<Method, Method>();
            for (String strField : info.sFields) {
                String strMappedField = map.mapFields.get(strField);
                if (strMappedField == null)
                    strMappedField = strField;
                String strPrev = mapFields.get(strMappedField);
                if (strPrev != null) {
                    System.out.println(
                            "FD: " + strClass + "/" + strPrev + " " + map.strNewName + "/" + strMappedField);
                    System.out.println(
                            "FD: " + strClass + "/" + strField + " " + map.strNewName + "/" + strMappedField);
                    System.out.println("");
                } else {
                    mapFields.put(strMappedField, strField);
                }
            }
            for (Method mMethod : info.sMethods) {
                Method mMappedMethod = map.mapMethods.get(mMethod);
                if (mMappedMethod == null)
                    mMappedMethod = mMethod;
                Method mPrev = mapMethods.get(mMappedMethod);
                if (mPrev != null) {
                    System.out.println("MD: " + strClass + "/" + mPrev.name + " " + mPrev.desc + " "
                            + map.strNewName + "/" + mMappedMethod.name + " " + mMappedMethod.desc);
                    System.out.println("MD: " + strClass + "/" + mMethod.name + " " + mMethod.desc + " "
                            + map.strNewName + "/" + mMappedMethod.name + " " + mMappedMethod.desc);
                    System.out.println("");
                } else {
                    mapMethods.put(mMappedMethod, mMethod);
                }
            }
        }
    }

}