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
58595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com    public InlineMethod lookupInlineMethod(AnalyzedInstruction instruction) {
59595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com        return inlineMethodResolver.resolveExecuteInline(instruction);
600c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
610c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
620c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    public FieldIdItem lookupField(ClassPath.ClassDef classDef, int fieldOffset) {
63a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        ClassPath.FieldDef field = classDef.getInstanceField(fieldOffset);
640c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (field == null) {
650c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
660c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
670c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
680c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        return parseAndResolveField(classDef, field);
690c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
700c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
710c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    private static final Pattern shortMethodPattern = Pattern.compile("([^(]+)\\(([^)]*)\\)(.+)");
720c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
730c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    public MethodIdItem lookupVirtualMethod(ClassPath.ClassDef classDef, int methodIndex) {
740c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        String method = classDef.getVirtualMethod(methodIndex);
7541265daa5aff0a6f9ce76bdf88fab4a900786088JesusFreke@JesusFreke.com        if (method == null) {
7641265daa5aff0a6f9ce76bdf88fab4a900786088JesusFreke@JesusFreke.com            return null;
7741265daa5aff0a6f9ce76bdf88fab4a900786088JesusFreke@JesusFreke.com        }
780c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
790c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        Matcher m = shortMethodPattern.matcher(method);
800c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (!m.matches()) {
810c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            assert false;
820c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            throw new RuntimeException("Invalid method descriptor: " + method);
830c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
840c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
850c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        String methodName = m.group(1);
860c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        String methodParams = m.group(2);
870c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        String methodRet = m.group(3);
880c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
890c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (classDef.isInterface()) {
900c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            classDef = classDef.getSuperclass();
910c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            assert classDef != null;
920c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
930c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
940c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        return parseAndResolveMethod(classDef, methodName, methodParams, methodRet);
950c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
960c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
970c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    private MethodIdItem parseAndResolveMethod(ClassPath.ClassDef classDef, String methodName, String methodParams,
980c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                                               String methodRet) {
990c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        StringIdItem methodNameItem = StringIdItem.lookupStringIdItem(dexFile, methodName);
1000c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (methodNameItem == null) {
1010c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
1020c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1030c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1040c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        LinkedList<TypeIdItem> paramList = new LinkedList<TypeIdItem>();
1050c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1060c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        for (int i=0; i<methodParams.length(); i++) {
1070c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            TypeIdItem typeIdItem;
1080c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1090c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            switch (methodParams.charAt(i)) {
1100c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'Z':
1110c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'B':
1120c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'S':
1130c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'C':
1140c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'I':
1150c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'J':
1160c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'F':
1170c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'D':
1180c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    typeIdItem = TypeIdItem.lookupTypeIdItem(dexFile, methodParams.substring(i,i+1));
1190c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    break;
1200c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case 'L':
1210c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                {
1220c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    int end = methodParams.indexOf(';', i);
1230c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    if (end == -1) {
1240c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        throw new RuntimeException("invalid parameter in the method");
1250c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    }
1260c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1270c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    typeIdItem = TypeIdItem.lookupTypeIdItem(dexFile, methodParams.substring(i, end+1));
1280c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    i = end;
1290c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    break;
1300c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                }
1310c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                case '[':
1320c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                {
1330c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    int end;
1340c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    int typeStart = i+1;
1350c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    while (typeStart < methodParams.length() && methodParams.charAt(typeStart) == '[') {
1360c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        typeStart++;
1370c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    }
1380c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    switch (methodParams.charAt(typeStart)) {
1390c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'Z':
1400c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'B':
1410c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'S':
1420c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'C':
1430c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'I':
1440c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'J':
1450c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'F':
1460c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'D':
1470c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            end = typeStart;
1480c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            break;
1490c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        case 'L':
1500c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            end = methodParams.indexOf(';', typeStart);
1510c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            if (end == -1) {
1520c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                                throw new RuntimeException("invalid parameter in the method");
1530c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            }
1540c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            break;
1550c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                        default:
1560c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                            throw new RuntimeException("invalid parameter in the method");
1570c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    }
1580c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1590c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    typeIdItem = TypeIdItem.lookupTypeIdItem(dexFile, methodParams.substring(i, end+1));
1600c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    i = end;
1610c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    break;
1620c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                }
1630c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                default:
1640c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    throw new RuntimeException("invalid parameter in the method");
1650c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
1660c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1670c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (typeIdItem == null) {
1680c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                return null;
1690c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
1700c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            paramList.add(typeIdItem);
1710c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1720c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1730c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        TypeListItem paramListItem = null;
1740c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (paramList.size() > 0) {
1750c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            paramListItem = TypeListItem.lookupTypeListItem(dexFile, paramList);
1760c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (paramListItem == null) {
1770c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                return null;
1780c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
1790c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1800c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1810c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        TypeIdItem retType = TypeIdItem.lookupTypeIdItem(dexFile, methodRet);
1820c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (retType == null) {
1830c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
1840c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1850c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1860c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        ProtoIdItem protoItem = ProtoIdItem.lookupProtoIdItem(dexFile, retType, paramListItem);
1870c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (protoItem == null) {
1880c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
1890c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
1900c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1910c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        ClassPath.ClassDef methodClassDef = classDef;
1920c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1930c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        do {
1940c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, methodClassDef.getClassType());
1950c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
1960c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (classTypeItem != null) {
1970c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                MethodIdItem methodIdItem = MethodIdItem.lookupMethodIdItem(dexFile, classTypeItem, protoItem, methodNameItem);
1980c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                if (methodIdItem != null) {
1990c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                    return methodIdItem;
2000c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                }
2010c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
2020c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2030c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            methodClassDef = methodClassDef.getSuperclass();
2040c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        } while (methodClassDef != null);
2050c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        return null;
2060c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
2070c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
208a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver    private FieldIdItem parseAndResolveField(ClassPath.ClassDef classDef, ClassPath.FieldDef field) {
209a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        String definingClass = field.definingClass;
210a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        String fieldName = field.name;
211a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        String fieldType = field.type;
2120c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2130c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        StringIdItem fieldNameItem = StringIdItem.lookupStringIdItem(dexFile, fieldName);
2140c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (fieldNameItem == null) {
2150c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
2160c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2170c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2180c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        TypeIdItem fieldTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, fieldType);
2190c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        if (fieldTypeItem == null) {
2200c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return null;
2210c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2220c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2230c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        ClassPath.ClassDef fieldClass = classDef;
2240c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
225a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        ArrayList<ClassPath.ClassDef> parents = new ArrayList<ClassPath.ClassDef>();
226a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        parents.add(fieldClass);
227a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver
228a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        while (fieldClass != null && !fieldClass.getClassType().equals(definingClass)) {
229a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver            fieldClass = fieldClass.getSuperclass();
230a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver            parents.add(fieldClass);
231a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        }
232a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver
233a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        for (int i=parents.size()-1; i>=0; i--) {
234a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver            fieldClass = parents.get(i);
235a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver
2360c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, fieldClass.getClassType());
2370c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (classTypeItem == null) {
2380c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                continue;
2390c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
2400c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2410c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            FieldIdItem fieldIdItem = FieldIdItem.lookupFieldIdItem(dexFile, classTypeItem, fieldTypeItem, fieldNameItem);
2420c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (fieldIdItem != null) {
2430c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                return fieldIdItem;
2440c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
245a91109b8a76def18c4d0342a44a87ad270d379abBen Gruver        }
2460c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        return null;
2470c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
2480c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2490c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    public class InlineMethod {
2500c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final int methodType;
2510c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final String classType;
2520c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final String methodName;
2530c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final String parameters;
2540c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public final String returnType;
2550c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2560c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        private MethodIdItem methodIdItem = null;
2570c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
258595cdad3d63d79e8d913a704e65f7785ff1bc104JesusFreke@JesusFreke.com        InlineMethod(int methodType, String classType, String methodName, String parameters,
2590c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                               String returnType) {
2600c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.methodType = methodType;
2610c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.classType = classType;
2620c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.methodName = methodName;
2630c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.parameters = parameters;
2640c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.returnType = returnType;
2650c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2660c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2670c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public MethodIdItem getMethodIdItem() {
2680c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            if (methodIdItem == null) {
2690c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com                loadMethod();
2700c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
2710c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return methodIdItem;
2720c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2730c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2740c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        private void loadMethod() {
2750c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            ClassPath.ClassDef classDef = ClassPath.getClassDef(classType);
2760c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2770c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            this.methodIdItem = parseAndResolveMethod(classDef, methodName, parameters, returnType);
2780c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2790c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
2800c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        public String getMethodString() {
2810c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            return String.format("%s->%s(%s)%s", classType, methodName, parameters, returnType);
2820c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com        }
2830c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com    }
2840c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com}
285