DeodexUtil.java revision 343df2f456f38c305ee7d6742f6601d9bde09715
100fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com/*
200fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * [The "BSD licence"]
300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * Copyright (c) 2010 Ben Gruver (JesusFreke)
400fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * All rights reserved.
500fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com *
600fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * Redistribution and use in source and binary forms, with or without
700fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * modification, are permitted provided that the following conditions
800fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * are met:
900fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * 1. Redistributions of source code must retain the above copyright
1000fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com *    notice, this list of conditions and the following disclaimer.
1100fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * 2. Redistributions in binary form must reproduce the above copyright
1200fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com *    notice, this list of conditions and the following disclaimer in the
1300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com *    documentation and/or other materials provided with the distribution.
1400fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * 3. The name of the author may not be used to endorse or promote products
1500fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com *    derived from this software without specific prior written permission.
1600fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com *
1700fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1800fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1900fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2000fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2100fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2200fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2400fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2500fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2600fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2700fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com */
2800fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com
290c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.compackage org.jf.dexlib.Code.Analysis;
300c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
310c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.comimport org.jf.dexlib.*;
320c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
33a91109b8a76def18c4d0342a44a87ad270d379abBen Gruverimport java.util.ArrayList;
340c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.comimport java.util.LinkedList;
350c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.comimport java.util.regex.Matcher;
360c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.comimport java.util.regex.Pattern;
370c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
380c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.compublic class DeodexUtil {
390c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    public static final int Virtual = 0;
400c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    public static final int Direct = 1;
410c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    public static final int Static = 2;
420c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
43595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com    private final InlineMethodResolver inlineMethodResolver;
442880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com
450c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    public final DexFile dexFile;
460c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
470c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    public DeodexUtil(DexFile dexFile) {
480c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        this.dexFile = dexFile;
492880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com        OdexHeader odexHeader = dexFile.getOdexHeader();
502880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com        if (odexHeader == null) {
512880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com            //if there isn't an odex header, why are we creating an DeodexUtil object?
522880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com            assert false;
532880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com            throw new RuntimeException("Cannot create a DeodexUtil object for a dex file without an odex header");
542880e1c625cd7615bf2433870177ed63434be6e2JesusFreke@JesusFreke.com        }
55595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com        inlineMethodResolver = InlineMethodResolver.createInlineMethodResolver(this, odexHeader.version);
560c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
570c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
585967598d012839eb25d50d9fa63952ac802e05ddBen Gruver    public DeodexUtil(DexFile dexFile, InlineMethodResolver inlineMethodResolver) {
595967598d012839eb25d50d9fa63952ac802e05ddBen Gruver        this.dexFile = dexFile;
605967598d012839eb25d50d9fa63952ac802e05ddBen Gruver        this.inlineMethodResolver = inlineMethodResolver;
615967598d012839eb25d50d9fa63952ac802e05ddBen Gruver    }
625967598d012839eb25d50d9fa63952ac802e05ddBen Gruver
63595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com    public InlineMethod lookupInlineMethod(AnalyzedInstruction instruction) {
64595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com        return inlineMethodResolver.resolveExecuteInline(instruction);
650c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
660c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
670c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    public FieldIdItem lookupField(ClassPath.ClassDef classDef, int fieldOffset) {
68a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        ClassPath.FieldDef field = classDef.getInstanceField(fieldOffset);
690c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (field == null) {
700c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
710c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
720c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
730c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        return parseAndResolveField(classDef, field);
740c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
750c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
760c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    private static final Pattern shortMethodPattern = Pattern.compile("([^(]+)\\(([^)]*)\\)(.+)");
770c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
780c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    public MethodIdItem lookupVirtualMethod(ClassPath.ClassDef classDef, int methodIndex) {
790c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        String method = classDef.getVirtualMethod(methodIndex);
8041265daa5aff0a6f9ce76bdf88fab4a900786088JesusFreke@JesusFreke.com        if (method == null) {
8141265daa5aff0a6f9ce76bdf88fab4a900786088JesusFreke@JesusFreke.com            return null;
8241265daa5aff0a6f9ce76bdf88fab4a900786088JesusFreke@JesusFreke.com        }
830c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
840c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        Matcher m = shortMethodPattern.matcher(method);
850c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (!m.matches()) {
860c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            assert false;
870c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            throw new RuntimeException("Invalid method descriptor: " + method);
880c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
890c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
900c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        String methodName = m.group(1);
910c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        String methodParams = m.group(2);
920c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        String methodRet = m.group(3);
930c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
94343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver        if (classDef instanceof ClassPath.UnresolvedClassDef) {
95343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver            //if this is an unresolved class, the only way getVirtualMethod could have found a method is if the virtual
96343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver            //method being looked up was a method on java.lang.Object.
97343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver            classDef = ClassPath.getClassDef("Ljava/lang/Object;");
98343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver        } else if (classDef.isInterface()) {
990c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            classDef = classDef.getSuperclass();
1000c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            assert classDef != null;
1010c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1020c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1030c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        return parseAndResolveMethod(classDef, methodName, methodParams, methodRet);
1040c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
1050c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1060c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    private MethodIdItem parseAndResolveMethod(ClassPath.ClassDef classDef, String methodName, String methodParams,
1070c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                                               String methodRet) {
1080c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        StringIdItem methodNameItem = StringIdItem.lookupStringIdItem(dexFile, methodName);
1090c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (methodNameItem == null) {
1100c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
1110c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1120c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1130c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        LinkedList<TypeIdItem> paramList = new LinkedList<TypeIdItem>();
1140c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1150c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        for (int i=0; i<methodParams.length(); i++) {
1160c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            TypeIdItem typeIdItem;
1170c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1180c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            switch (methodParams.charAt(i)) {
1190c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'Z':
1200c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'B':
1210c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'S':
1220c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'C':
1230c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'I':
1240c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'J':
1250c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'F':
1260c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'D':
1270c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    typeIdItem = TypeIdItem.lookupTypeIdItem(dexFile, methodParams.substring(i,i+1));
1280c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    break;
1290c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'L':
1300c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                {
1310c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    int end = methodParams.indexOf(';', i);
1320c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    if (end == -1) {
1330c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        throw new RuntimeException("invalid parameter in the method");
1340c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    }
1350c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1360c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    typeIdItem = TypeIdItem.lookupTypeIdItem(dexFile, methodParams.substring(i, end+1));
1370c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    i = end;
1380c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    break;
1390c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                }
1400c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case '[':
1410c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                {
1420c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    int end;
1430c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    int typeStart = i+1;
1440c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    while (typeStart < methodParams.length() && methodParams.charAt(typeStart) == '[') {
1450c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        typeStart++;
1460c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    }
1470c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    switch (methodParams.charAt(typeStart)) {
1480c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'Z':
1490c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'B':
1500c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'S':
1510c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'C':
1520c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'I':
1530c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'J':
1540c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'F':
1550c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'D':
1560c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            end = typeStart;
1570c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            break;
1580c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'L':
1590c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            end = methodParams.indexOf(';', typeStart);
1600c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            if (end == -1) {
1610c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                                throw new RuntimeException("invalid parameter in the method");
1620c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            }
1630c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            break;
1640c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        default:
1650c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            throw new RuntimeException("invalid parameter in the method");
1660c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    }
1670c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1680c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    typeIdItem = TypeIdItem.lookupTypeIdItem(dexFile, methodParams.substring(i, end+1));
1690c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    i = end;
1700c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    break;
1710c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                }
1720c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                default:
1730c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    throw new RuntimeException("invalid parameter in the method");
1740c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
1750c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1760c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (typeIdItem == null) {
1770c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                return null;
1780c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
1790c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            paramList.add(typeIdItem);
1800c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1810c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1820c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        TypeListItem paramListItem = null;
1830c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (paramList.size() > 0) {
1840c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            paramListItem = TypeListItem.lookupTypeListItem(dexFile, paramList);
1850c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (paramListItem == null) {
1860c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                return null;
1870c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
1880c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1890c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1900c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        TypeIdItem retType = TypeIdItem.lookupTypeIdItem(dexFile, methodRet);
1910c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (retType == null) {
1920c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
1930c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1940c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1950c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        ProtoIdItem protoItem = ProtoIdItem.lookupProtoIdItem(dexFile, retType, paramListItem);
1960c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (protoItem == null) {
1970c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
1980c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1990c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2000c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        ClassPath.ClassDef methodClassDef = classDef;
2010c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2020c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        do {
2030c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, methodClassDef.getClassType());
2040c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2050c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (classTypeItem != null) {
2060c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                MethodIdItem methodIdItem = MethodIdItem.lookupMethodIdItem(dexFile, classTypeItem, protoItem, methodNameItem);
2070c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                if (methodIdItem != null) {
2080c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    return methodIdItem;
2090c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                }
2100c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
2110c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2120c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            methodClassDef = methodClassDef.getSuperclass();
2130c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        } while (methodClassDef != null);
2140c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        return null;
2150c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
2160c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
217a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver    private FieldIdItem parseAndResolveField(ClassPath.ClassDef classDef, ClassPath.FieldDef field) {
218a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        String definingClass = field.definingClass;
219a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        String fieldName = field.name;
220a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        String fieldType = field.type;
2210c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2220c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        StringIdItem fieldNameItem = StringIdItem.lookupStringIdItem(dexFile, fieldName);
2230c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (fieldNameItem == null) {
2240c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
2250c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2260c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2270c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        TypeIdItem fieldTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, fieldType);
2280c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (fieldTypeItem == null) {
2290c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
2300c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2310c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2320c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        ClassPath.ClassDef fieldClass = classDef;
2330c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
234a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        ArrayList<ClassPath.ClassDef> parents = new ArrayList<ClassPath.ClassDef>();
235a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        parents.add(fieldClass);
236a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver
237a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        while (fieldClass != null && !fieldClass.getClassType().equals(definingClass)) {
238a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver            fieldClass = fieldClass.getSuperclass();
239a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver            parents.add(fieldClass);
240a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        }
241a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver
242a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        for (int i=parents.size()-1; i>=0; i--) {
243a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver            fieldClass = parents.get(i);
244a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver
2450c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, fieldClass.getClassType());
2460c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (classTypeItem == null) {
2470c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                continue;
2480c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
2490c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2500c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            FieldIdItem fieldIdItem = FieldIdItem.lookupFieldIdItem(dexFile, classTypeItem, fieldTypeItem, fieldNameItem);
2510c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (fieldIdItem != null) {
2520c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                return fieldIdItem;
2530c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
254a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        }
2550c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        return null;
2560c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
2570c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2585967598d012839eb25d50d9fa63952ac802e05ddBen Gruver    public static class InlineMethod {
2590c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final int methodType;
2600c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final String classType;
2610c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final String methodName;
2620c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final String parameters;
2630c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final String returnType;
2640c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2650c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        private MethodIdItem methodIdItem = null;
2660c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
267595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com        InlineMethod(int methodType, String classType, String methodName, String parameters,
2680c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                               String returnType) {
2690c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.methodType = methodType;
2700c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.classType = classType;
2710c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.methodName = methodName;
2720c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.parameters = parameters;
2730c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.returnType = returnType;
2740c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2750c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2765967598d012839eb25d50d9fa63952ac802e05ddBen Gruver        public MethodIdItem getMethodIdItem(DeodexUtil deodexUtil) {
2770c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (methodIdItem == null) {
2785967598d012839eb25d50d9fa63952ac802e05ddBen Gruver                loadMethod(deodexUtil);
2790c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
2800c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return methodIdItem;
2810c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2820c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2835967598d012839eb25d50d9fa63952ac802e05ddBen Gruver        private void loadMethod(DeodexUtil deodexUtil) {
2840c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            ClassPath.ClassDef classDef = ClassPath.getClassDef(classType);
2850c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2865967598d012839eb25d50d9fa63952ac802e05ddBen Gruver            this.methodIdItem = deodexUtil.parseAndResolveMethod(classDef, methodName, parameters, returnType);
2870c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2880c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2890c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public String getMethodString() {
2900c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return String.format("%s->%s(%s)%s", classType, methodName, parameters, returnType);
2910c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2920c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
2930c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com}
294