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
67ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver    public FieldIdItem lookupField(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass,
68ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver                                   int fieldOffset) {
69ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver        ClassPath.FieldDef field = instanceClass.getInstanceField(fieldOffset);
700c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (field == null) {
710c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
720c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
730c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
74ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver        return parseAndResolveField(accessingClass, instanceClass, field);
750c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
760c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
770c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    private static final Pattern shortMethodPattern = Pattern.compile("([^(]+)\\(([^)]*)\\)(.+)");
780c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
79ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver    public MethodIdItem lookupVirtualMethod(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass,
80650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver                                            int methodIndex) {
81ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver        String method = instanceClass.getVirtualMethod(methodIndex);
8241265daa5aff0a6f9ce76bdf88fab4a900786088JesusFreke@JesusFreke.com        if (method == null) {
8341265daa5aff0a6f9ce76bdf88fab4a900786088JesusFreke@JesusFreke.com            return null;
8441265daa5aff0a6f9ce76bdf88fab4a900786088JesusFreke@JesusFreke.com        }
850c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
860c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        Matcher m = shortMethodPattern.matcher(method);
870c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (!m.matches()) {
880c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            assert false;
890c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            throw new RuntimeException("Invalid method descriptor: " + method);
900c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
910c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
920c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        String methodName = m.group(1);
930c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        String methodParams = m.group(2);
940c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        String methodRet = m.group(3);
950c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
96ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver        if (instanceClass instanceof ClassPath.UnresolvedClassDef) {
97343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver            //if this is an unresolved class, the only way getVirtualMethod could have found a method is if the virtual
98343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver            //method being looked up was a method on java.lang.Object.
99ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver            instanceClass = ClassPath.getClassDef("Ljava/lang/Object;");
100ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver        } else if (instanceClass.isInterface()) {
101ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver            instanceClass = instanceClass.getSuperclass();
102ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver            assert instanceClass != null;
1030c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1040c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
105ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver        return parseAndResolveMethod(accessingClass, instanceClass, methodName, methodParams, methodRet);
1060c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
1070c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
108650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver    private MethodIdItem parseAndResolveMethod(ClassPath.ClassDef accessingClass, ClassPath.ClassDef definingClass,
109650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver                                               String methodName, String methodParams, String methodRet) {
1100c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        StringIdItem methodNameItem = StringIdItem.lookupStringIdItem(dexFile, methodName);
1110c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (methodNameItem == null) {
1120c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
1130c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1140c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1150c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        LinkedList<TypeIdItem> paramList = new LinkedList<TypeIdItem>();
1160c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1170c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        for (int i=0; i<methodParams.length(); i++) {
1180c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            TypeIdItem typeIdItem;
1190c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1200c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            switch (methodParams.charAt(i)) {
1210c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'Z':
1220c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'B':
1230c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'S':
1240c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'C':
1250c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'I':
1260c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'J':
1270c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'F':
1280c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'D':
1290c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    typeIdItem = TypeIdItem.lookupTypeIdItem(dexFile, methodParams.substring(i,i+1));
1300c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    break;
1310c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'L':
1320c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                {
1330c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    int end = methodParams.indexOf(';', i);
1340c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    if (end == -1) {
1350c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        throw new RuntimeException("invalid parameter in the method");
1360c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    }
1370c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1380c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    typeIdItem = TypeIdItem.lookupTypeIdItem(dexFile, methodParams.substring(i, end+1));
1390c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    i = end;
1400c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    break;
1410c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                }
1420c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case '[':
1430c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                {
1440c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    int end;
1450c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    int typeStart = i+1;
1460c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    while (typeStart < methodParams.length() && methodParams.charAt(typeStart) == '[') {
1470c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        typeStart++;
1480c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    }
1490c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    switch (methodParams.charAt(typeStart)) {
1500c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'Z':
1510c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'B':
1520c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'S':
1530c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'C':
1540c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'I':
1550c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'J':
1560c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'F':
1570c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'D':
1580c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            end = typeStart;
1590c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            break;
1600c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'L':
1610c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            end = methodParams.indexOf(';', typeStart);
1620c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            if (end == -1) {
1630c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                                throw new RuntimeException("invalid parameter in the method");
1640c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            }
1650c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            break;
1660c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        default:
1670c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            throw new RuntimeException("invalid parameter in the method");
1680c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    }
1690c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1700c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    typeIdItem = TypeIdItem.lookupTypeIdItem(dexFile, methodParams.substring(i, end+1));
1710c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    i = end;
1720c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    break;
1730c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                }
1740c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                default:
1750c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    throw new RuntimeException("invalid parameter in the method");
1760c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
1770c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1780c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (typeIdItem == null) {
1790c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                return null;
1800c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
1810c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            paramList.add(typeIdItem);
1820c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1830c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1840c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        TypeListItem paramListItem = null;
1850c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (paramList.size() > 0) {
1860c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            paramListItem = TypeListItem.lookupTypeListItem(dexFile, paramList);
1870c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (paramListItem == null) {
1880c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                return null;
1890c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
1900c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1910c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1920c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        TypeIdItem retType = TypeIdItem.lookupTypeIdItem(dexFile, methodRet);
1930c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (retType == null) {
1940c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
1950c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1960c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1970c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        ProtoIdItem protoItem = ProtoIdItem.lookupProtoIdItem(dexFile, retType, paramListItem);
1980c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (protoItem == null) {
1990c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
2000c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2010c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
202650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver        ClassPath.ClassDef methodClassDef = definingClass;
2030c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2040c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        do {
2050c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, methodClassDef.getClassType());
2060c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2070c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (classTypeItem != null) {
2080c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                MethodIdItem methodIdItem = MethodIdItem.lookupMethodIdItem(dexFile, classTypeItem, protoItem, methodNameItem);
209650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver                if (methodIdItem != null && checkClassAccess(accessingClass, methodClassDef)) {
2100c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    return methodIdItem;
2110c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                }
2120c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
2130c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2140c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            methodClassDef = methodClassDef.getSuperclass();
2150c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        } while (methodClassDef != null);
2160c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        return null;
2170c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
2180c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
219650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver    private static boolean checkClassAccess(ClassPath.ClassDef accessingClass, ClassPath.ClassDef definingClass) {
220650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver        return definingClass.isPublic() ||
221650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver                getPackage(accessingClass.getClassType()).equals(getPackage(definingClass.getClassType()));
222650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver    }
223650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver
224650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver    private static String getPackage(String classRef) {
225650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver        int lastSlash = classRef.lastIndexOf('/');
226650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver        if (lastSlash < 0) {
227650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver            return "";
228650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver        }
229650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver        return classRef.substring(1, lastSlash);
230650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver    }
231650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver
232ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver    /**
233ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver     *
234ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver     * @param accessingClass The class that contains the field reference. I.e. the class being deodexed
235ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver     * @param instanceClass The inferred class type  of the object that the field is being accessed on
236ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver     * @param field The field being accessed
237ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver     * @return The FieldIdItem of the resolved field
238ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver     */
239ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver    private FieldIdItem parseAndResolveField(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass,
240ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver                                             ClassPath.FieldDef field) {
241a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        String definingClass = field.definingClass;
242a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        String fieldName = field.name;
243a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        String fieldType = field.type;
2440c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2450c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        StringIdItem fieldNameItem = StringIdItem.lookupStringIdItem(dexFile, fieldName);
2460c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (fieldNameItem == null) {
2470c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
2480c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2490c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2500c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        TypeIdItem fieldTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, fieldType);
2510c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (fieldTypeItem == null) {
2520c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
2530c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2540c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
255ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver        ClassPath.ClassDef fieldClass = instanceClass;
2560c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
257a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        ArrayList<ClassPath.ClassDef> parents = new ArrayList<ClassPath.ClassDef>();
258a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        parents.add(fieldClass);
259a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver
260a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        while (fieldClass != null && !fieldClass.getClassType().equals(definingClass)) {
261a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver            fieldClass = fieldClass.getSuperclass();
262a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver            parents.add(fieldClass);
263a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        }
264a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver
265a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        for (int i=parents.size()-1; i>=0; i--) {
266a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver            fieldClass = parents.get(i);
267a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver
2680c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, fieldClass.getClassType());
2690c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (classTypeItem == null) {
2700c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                continue;
2710c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
2720c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2730c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            FieldIdItem fieldIdItem = FieldIdItem.lookupFieldIdItem(dexFile, classTypeItem, fieldTypeItem, fieldNameItem);
274ebd1b0e9c14f46cb55534cbd48084666afbdef21Ben Gruver            if (fieldIdItem != null && checkClassAccess(accessingClass, fieldClass)) {
2750c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                return fieldIdItem;
2760c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
277a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        }
2780c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        return null;
2790c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
2800c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2815967598d012839eb25d50d9fa63952ac802e05ddBen Gruver    public static class InlineMethod {
2820c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final int methodType;
2830c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final String classType;
2840c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final String methodName;
2850c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final String parameters;
2860c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final String returnType;
2870c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2880c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        private MethodIdItem methodIdItem = null;
2890c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
290595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com        InlineMethod(int methodType, String classType, String methodName, String parameters,
2910c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                               String returnType) {
2920c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.methodType = methodType;
2930c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.classType = classType;
2940c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.methodName = methodName;
2950c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.parameters = parameters;
2960c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.returnType = returnType;
2970c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2980c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2995967598d012839eb25d50d9fa63952ac802e05ddBen Gruver        public MethodIdItem getMethodIdItem(DeodexUtil deodexUtil) {
3000c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (methodIdItem == null) {
3015967598d012839eb25d50d9fa63952ac802e05ddBen Gruver                loadMethod(deodexUtil);
3020c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
3030c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return methodIdItem;
3040c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
3050c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
3065967598d012839eb25d50d9fa63952ac802e05ddBen Gruver        private void loadMethod(DeodexUtil deodexUtil) {
3070c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            ClassPath.ClassDef classDef = ClassPath.getClassDef(classType);
3080c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
309650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver            this.methodIdItem = deodexUtil.parseAndResolveMethod(classDef, classDef, methodName, parameters,
310650d426c120993fdee95d982e50faa6a5d70d9afBen Gruver                    returnType);
3110c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
3120c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
3130c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public String getMethodString() {
3140c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return String.format("%s->%s(%s)%s", classType, methodName, parameters, returnType);
3150c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
3160c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
3170c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com}
318