112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden/*
212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * Copyright (C) 2009 The Android Open Source Project
312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden *
412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * Licensed under the Apache License, Version 2.0 (the "License");
512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * you may not use this file except in compliance with the License.
612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * You may obtain a copy of the License at
712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden *
812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden *      http://www.apache.org/licenses/LICENSE-2.0
912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden *
1012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * Unless required by applicable law or agreed to in writing, software
1112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * distributed under the License is distributed on an "AS IS" BASIS,
1212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * See the License for the specific language governing permissions and
1412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * limitations under the License.
1512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden */
1612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
1712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenpackage com.android.dexdeps;
1812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
1912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenimport java.io.IOException;
2012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenimport java.io.RandomAccessFile;
2112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenimport java.util.Arrays;
2212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
2312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden/**
2412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * Data extracted from a DEX file.
2512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden */
2612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenpublic class DexData {
2712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    private RandomAccessFile mDexFile;
2812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    private HeaderItem mHeaderItem;
2912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    private String[] mStrings;              // strings from string_data_*
3012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    private TypeIdItem[] mTypeIds;
3112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    private ProtoIdItem[] mProtoIds;
3212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    private FieldIdItem[] mFieldIds;
3312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    private MethodIdItem[] mMethodIds;
3412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    private ClassDefItem[] mClassDefs;
3512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
3612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    private byte tmpBuf[] = new byte[4];
3712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    private boolean isBigEndian = false;
3812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
3912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
4012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Constructs a new DexData for this file.
4112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
4212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    public DexData(RandomAccessFile raf) {
4312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mDexFile = raf;
4412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
4512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
4612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
4712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Loads the contents of the DEX file into our data structures.
4812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     *
4912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * @throws IOException if we encounter a problem while reading
5012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * @throws DexDataException if the DEX contents look bad
5112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
5212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    public void load() throws IOException {
5312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        parseHeaderItem();
5412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
5512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        loadStrings();
5612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        loadTypeIds();
5712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        loadProtoIds();
5812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        loadFieldIds();
5912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        loadMethodIds();
6012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        loadClassDefs();
6112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
6212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        markInternalClasses();
6312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
6412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
6512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
6612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
6712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Parses the interesting bits out of the header.
6812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
6912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void parseHeaderItem() throws IOException {
7012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem = new HeaderItem();
7112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
7212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        seek(0);
7312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
7412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        byte[] magic = new byte[8];
7512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        readBytes(magic);
7612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        if (!Arrays.equals(magic, HeaderItem.DEX_FILE_MAGIC)) {
7712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            System.err.println("Magic number is wrong -- are you sure " +
7812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                "this is a DEX file?");
7912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            throw new DexDataException();
8012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
8112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
8212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*
8312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         * Read the endian tag, so we properly swap things as we read
8412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         * them from here on.
8512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         */
8612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        seek(8+4+20+4+4);
8712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.endianTag = readInt();
8812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        if (mHeaderItem.endianTag == HeaderItem.ENDIAN_CONSTANT) {
8912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            /* do nothing */
9012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        } else if (mHeaderItem.endianTag == HeaderItem.REVERSE_ENDIAN_CONSTANT){
9112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            /* file is big-endian (!), reverse future reads */
9212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            isBigEndian = true;
9312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        } else {
9412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            System.err.println("Endian constant has unexpected value " +
9512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                Integer.toHexString(mHeaderItem.endianTag));
9612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            throw new DexDataException();
9712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
9812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
9912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        seek(8+4+20);  // magic, checksum, signature
10012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.fileSize = readInt();
10112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.headerSize = readInt();
10212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*mHeaderItem.endianTag =*/ readInt();
10312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*mHeaderItem.linkSize =*/ readInt();
10412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*mHeaderItem.linkOff =*/ readInt();
10512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*mHeaderItem.mapOff =*/ readInt();
10612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.stringIdsSize = readInt();
10712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.stringIdsOff = readInt();
10812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.typeIdsSize = readInt();
10912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.typeIdsOff = readInt();
11012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.protoIdsSize = readInt();
11112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.protoIdsOff = readInt();
11212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.fieldIdsSize = readInt();
11312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.fieldIdsOff = readInt();
11412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.methodIdsSize = readInt();
11512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.methodIdsOff = readInt();
11612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.classDefsSize = readInt();
11712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mHeaderItem.classDefsOff = readInt();
11812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*mHeaderItem.dataSize =*/ readInt();
11912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*mHeaderItem.dataOff =*/ readInt();
12012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
12112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
12212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
12312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Loads the string table out of the DEX.
12412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     *
12512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * First we read all of the string_id_items, then we read all of the
12612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * string_data_item.  Doing it this way should allow us to avoid
12712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * seeking around in the file.
12812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
12912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void loadStrings() throws IOException {
13012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int count = mHeaderItem.stringIdsSize;
13112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int stringOffsets[] = new int[count];
13212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
13312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        //System.out.println("reading " + count + " strings");
13412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
13512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        seek(mHeaderItem.stringIdsOff);
13612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (int i = 0; i < count; i++) {
13712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            stringOffsets[i] = readInt();
13812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
13912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
14012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mStrings = new String[count];
14112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
14212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        seek(stringOffsets[0]);
14312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (int i = 0; i < count; i++) {
14412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            seek(stringOffsets[i]);         // should be a no-op
14512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mStrings[i] = readString();
14612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //System.out.println("STR: " + i + ": " + mStrings[i]);
14712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
14812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
14912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
15012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
15112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Loads the type ID list.
15212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
15312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void loadTypeIds() throws IOException {
15412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int count = mHeaderItem.typeIdsSize;
15512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mTypeIds = new TypeIdItem[count];
15612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
15712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        //System.out.println("reading " + count + " typeIds");
15812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        seek(mHeaderItem.typeIdsOff);
15912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (int i = 0; i < count; i++) {
16012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mTypeIds[i] = new TypeIdItem();
16112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mTypeIds[i].descriptorIdx = readInt();
16212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
16312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //System.out.println(i + ": " + mTypeIds[i].descriptorIdx +
16412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //    " " + mStrings[mTypeIds[i].descriptorIdx]);
16512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
16612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
16712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
16812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
16912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Loads the proto ID list.
17012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
17112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void loadProtoIds() throws IOException {
17212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int count = mHeaderItem.protoIdsSize;
17312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mProtoIds = new ProtoIdItem[count];
17412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
17512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        //System.out.println("reading " + count + " protoIds");
17612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        seek(mHeaderItem.protoIdsOff);
17712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
17812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*
17912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         * Read the proto ID items.
18012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         */
18112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (int i = 0; i < count; i++) {
18212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mProtoIds[i] = new ProtoIdItem();
18312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mProtoIds[i].shortyIdx = readInt();
18412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mProtoIds[i].returnTypeIdx = readInt();
18512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mProtoIds[i].parametersOff = readInt();
18612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
18712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //System.out.println(i + ": " + mProtoIds[i].shortyIdx +
18812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //    " " + mStrings[mProtoIds[i].shortyIdx]);
18912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
19012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
19112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*
19212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         * Go back through and read the type lists.
19312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         */
19412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (int i = 0; i < count; i++) {
19512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            ProtoIdItem protoId = mProtoIds[i];
19612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
19712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            int offset = protoId.parametersOff;
19812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
19912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            if (offset == 0) {
20012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                protoId.types = new int[0];
20112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                continue;
20212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            } else {
20312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                seek(offset);
20412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                int size = readInt();       // #of entries in list
20512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                protoId.types = new int[size];
20612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
20712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                for (int j = 0; j < size; j++) {
20812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                    protoId.types[j] = readShort() & 0xffff;
20912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                }
21012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            }
21112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
21212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
21312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
21412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
21512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Loads the field ID list.
21612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
21712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void loadFieldIds() throws IOException {
21812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int count = mHeaderItem.fieldIdsSize;
21912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mFieldIds = new FieldIdItem[count];
22012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
22112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        //System.out.println("reading " + count + " fieldIds");
22212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        seek(mHeaderItem.fieldIdsOff);
22312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (int i = 0; i < count; i++) {
22412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mFieldIds[i] = new FieldIdItem();
22512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mFieldIds[i].classIdx = readShort() & 0xffff;
22612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mFieldIds[i].typeIdx = readShort() & 0xffff;
22712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mFieldIds[i].nameIdx = readInt();
22812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
22912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //System.out.println(i + ": " + mFieldIds[i].nameIdx +
23012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //    " " + mStrings[mFieldIds[i].nameIdx]);
23112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
23212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
23312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
23412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
23512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Loads the method ID list.
23612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
23712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void loadMethodIds() throws IOException {
23812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int count = mHeaderItem.methodIdsSize;
23912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mMethodIds = new MethodIdItem[count];
24012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
24112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        //System.out.println("reading " + count + " methodIds");
24212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        seek(mHeaderItem.methodIdsOff);
24312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (int i = 0; i < count; i++) {
24412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mMethodIds[i] = new MethodIdItem();
24512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mMethodIds[i].classIdx = readShort() & 0xffff;
24612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mMethodIds[i].protoIdx = readShort() & 0xffff;
24712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mMethodIds[i].nameIdx = readInt();
24812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
24912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //System.out.println(i + ": " + mMethodIds[i].nameIdx +
25012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //    " " + mStrings[mMethodIds[i].nameIdx]);
25112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
25212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
25312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
25412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
25512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Loads the class defs list.
25612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
25712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void loadClassDefs() throws IOException {
25812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int count = mHeaderItem.classDefsSize;
25912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mClassDefs = new ClassDefItem[count];
26012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
26112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        //System.out.println("reading " + count + " classDefs");
26212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        seek(mHeaderItem.classDefsOff);
26312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (int i = 0; i < count; i++) {
26412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mClassDefs[i] = new ClassDefItem();
26512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mClassDefs[i].classIdx = readInt();
26612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
26712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            /* access_flags = */ readInt();
26812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            /* superclass_idx = */ readInt();
26912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            /* interfaces_off = */ readInt();
27012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            /* source_file_idx = */ readInt();
27112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            /* annotations_off = */ readInt();
27212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            /* class_data_off = */ readInt();
27312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            /* static_values_off = */ readInt();
27412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
27512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //System.out.println(i + ": " + mClassDefs[i].classIdx + " " +
27612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //    mStrings[mTypeIds[mClassDefs[i].classIdx].descriptorIdx]);
27712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
27812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
27912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
28012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
28112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Sets the "internal" flag on type IDs which are defined in the
28212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * DEX file or within the VM (e.g. primitive classes and arrays).
28312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
28412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void markInternalClasses() {
28512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (int i = mClassDefs.length -1; i >= 0; i--) {
28612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            mTypeIds[mClassDefs[i].classIdx].internal = true;
28712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
28812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
28912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (int i = 0; i < mTypeIds.length; i++) {
29012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            String className = mStrings[mTypeIds[i].descriptorIdx];
29112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
29212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            if (className.length() == 1) {
29312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                // primitive class
29412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                mTypeIds[i].internal = true;
29512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            } else if (className.charAt(0) == '[') {
29612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                mTypeIds[i].internal = true;
29712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            }
29812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
29912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //System.out.println(i + " " +
30012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //    (mTypeIds[i].internal ? "INTERNAL" : "external") + " - " +
30112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            //    mStrings[mTypeIds[i].descriptorIdx]);
30212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
30312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
30412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
30512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
30612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /*
30712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * =======================================================================
30812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     *      Queries
30912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * =======================================================================
31012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
31112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
31212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
313753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden     * Returns the class name, given an index into the type_ids table.
31412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
315753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden    private String classNameFromTypeIndex(int idx) {
316753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden        return mStrings[mTypeIds[idx].descriptorIdx];
31712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
31812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
31912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
320753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden     * Returns an array of method argument type strings, given an index
321753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden     * into the proto_ids table.
32212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
323753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden    private String[] argArrayFromProtoIndex(int idx) {
324753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden        ProtoIdItem protoId = mProtoIds[idx];
325753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden        String[] result = new String[protoId.types.length];
32612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
327753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden        for (int i = 0; i < protoId.types.length; i++) {
328753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden            result[i] = mStrings[mTypeIds[protoId.types[i]].descriptorIdx];
32912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
33012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
331753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden        return result;
33212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
33312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
33412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
335753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden     * Returns a string representing the method's return type, given an
336753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden     * index into the proto_ids table.
33712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
338753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden    private String returnTypeFromProtoIndex(int idx) {
33912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        ProtoIdItem protoId = mProtoIds[idx];
340753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden        return mStrings[mTypeIds[protoId.returnTypeIdx].descriptorIdx];
34112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
34212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
34312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
344837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden     * Returns an array with all of the class references that don't
345837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden     * correspond to classes in the DEX file.  Each class reference has
346837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden     * a list of the referenced fields and methods associated with
347837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden     * that class.
34812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
349837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden    public ClassRef[] getExternalReferences() {
350837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        // create a sparse array of ClassRef that parallels mTypeIds
351837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        ClassRef[] sparseRefs = new ClassRef[mTypeIds.length];
352837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden
353837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        // create entries for all externally-referenced classes
35412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int count = 0;
355837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        for (int i = 0; i < mTypeIds.length; i++) {
356837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden            if (!mTypeIds[i].internal) {
357837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                sparseRefs[i] =
358837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                    new ClassRef(mStrings[mTypeIds[i].descriptorIdx]);
35912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                count++;
360837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden            }
36112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
36212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
363837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        // add fields and methods to the appropriate class entry
364837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        addExternalFieldReferences(sparseRefs);
365837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        addExternalMethodReferences(sparseRefs);
36612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
367837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        // crunch out the sparseness
368837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        ClassRef[] classRefs = new ClassRef[count];
369837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        int idx = 0;
370837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        for (int i = 0; i < mTypeIds.length; i++) {
371837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden            if (sparseRefs[i] != null)
372837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                classRefs[idx++] = sparseRefs[i];
37312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
37412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
375837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        assert idx == count;
37612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
377837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        return classRefs;
37812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
37912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
38012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
381837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden     * Runs through the list of field references, inserting external
382837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden     * references into the appropriate ClassRef.
38312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
384837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden    private void addExternalFieldReferences(ClassRef[] sparseRefs) {
385837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden        for (int i = 0; i < mFieldIds.length; i++) {
386837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden            if (!mTypeIds[mFieldIds[i].classIdx].internal) {
387837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                FieldIdItem fieldId = mFieldIds[i];
388837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                FieldRef newFieldRef = new FieldRef(
389837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                        classNameFromTypeIndex(fieldId.classIdx),
390837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                        classNameFromTypeIndex(fieldId.typeIdx),
391837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                        mStrings[fieldId.nameIdx]);
392837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                sparseRefs[mFieldIds[i].classIdx].addField(newFieldRef);
393837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden            }
39412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
395837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden    }
39612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
397837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden    /**
398837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden     * Runs through the list of method references, inserting external
399837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden     * references into the appropriate ClassRef.
400837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden     */
401837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden    private void addExternalMethodReferences(ClassRef[] sparseRefs) {
40212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (int i = 0; i < mMethodIds.length; i++) {
40312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            if (!mTypeIds[mMethodIds[i].classIdx].internal) {
40412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                MethodIdItem methodId = mMethodIds[i];
405837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                MethodRef newMethodRef = new MethodRef(
406837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                        classNameFromTypeIndex(methodId.classIdx),
407837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                        argArrayFromProtoIndex(methodId.protoIdx),
408837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                        returnTypeFromProtoIndex(methodId.protoIdx),
409837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                        mStrings[methodId.nameIdx]);
410837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden                sparseRefs[mMethodIds[i].classIdx].addMethod(newMethodRef);
41112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            }
41212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
41312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
41412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
415753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden
41612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /*
41712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * =======================================================================
41812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     *      Basic I/O functions
41912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * =======================================================================
42012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
42112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
42212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
42312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Seeks the DEX file to the specified absolute position.
42412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
42512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void seek(int position) throws IOException {
42612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mDexFile.seek(position);
42712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
42812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
42912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
43012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Fills the buffer by reading bytes from the DEX file.
43112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
43212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void readBytes(byte[] buffer) throws IOException {
43312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mDexFile.readFully(buffer);
43412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
43512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
43612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
43712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Reads a single signed byte value.
43812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
43912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    byte readByte() throws IOException {
44012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mDexFile.readFully(tmpBuf, 0, 1);
44112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        return tmpBuf[0];
44212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
44312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
44412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
44512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Reads a signed 16-bit integer, byte-swapping if necessary.
44612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
44712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    short readShort() throws IOException {
44812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mDexFile.readFully(tmpBuf, 0, 2);
44912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        if (isBigEndian) {
45012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            return (short) ((tmpBuf[1] & 0xff) | ((tmpBuf[0] & 0xff) << 8));
45112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        } else {
45212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            return (short) ((tmpBuf[0] & 0xff) | ((tmpBuf[1] & 0xff) << 8));
45312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
45412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
45512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
45612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
45712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Reads a signed 32-bit integer, byte-swapping if necessary.
45812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
45912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    int readInt() throws IOException {
46012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        mDexFile.readFully(tmpBuf, 0, 4);
46112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
46212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        if (isBigEndian) {
46312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            return (tmpBuf[3] & 0xff) | ((tmpBuf[2] & 0xff) << 8) |
46412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                   ((tmpBuf[1] & 0xff) << 16) | ((tmpBuf[0] & 0xff) << 24);
46512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        } else {
46612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            return (tmpBuf[0] & 0xff) | ((tmpBuf[1] & 0xff) << 8) |
46712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                   ((tmpBuf[2] & 0xff) << 16) | ((tmpBuf[3] & 0xff) << 24);
46812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
46912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
47012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
47112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
47212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Reads a variable-length unsigned LEB128 value.  Does not attempt to
47312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * verify that the value is valid.
47412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     *
47512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * @throws EOFException if we run off the end of the file
47612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
47712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    int readUnsignedLeb128() throws IOException {
47812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int result = 0;
47912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        byte val;
48012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
48112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        do {
48212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            val = readByte();
48312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            result = (result << 7) | (val & 0x7f);
48412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        } while (val < 0);
48512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
48612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        return result;
48712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
48812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
48912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
49012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Reads a UTF-8 string.
49112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     *
49212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * We don't know how long the UTF-8 string is, so we have to read one
49312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * byte at a time.  We could make an educated guess based on the
49412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * utf16_size and seek back if we get it wrong, but seeking backward
49512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * may cause the underlying implementation to reload I/O buffers.
49612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
49712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    String readString() throws IOException {
49812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int utf16len = readUnsignedLeb128();
49912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        byte inBuf[] = new byte[utf16len * 3];      // worst case
50012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int idx;
50112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
50212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (idx = 0; idx < inBuf.length; idx++) {
50312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            byte val = readByte();
50412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            if (val == 0)
50512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                break;
50612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            inBuf[idx] = val;
50712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
50812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
50912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        return new String(inBuf, 0, idx, "UTF-8");
51012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
51112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
51212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
51312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /*
51412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * =======================================================================
51512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     *      Internal "structure" declarations
51612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * =======================================================================
51712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
51812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
51912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
52012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Holds the contents of a header_item.
52112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
52212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    static class HeaderItem {
52312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int fileSize;
52412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int headerSize;
52512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int endianTag;
52612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int stringIdsSize, stringIdsOff;
52712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int typeIdsSize, typeIdsOff;
52812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int protoIdsSize, protoIdsOff;
52912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int fieldIdsSize, fieldIdsOff;
53012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int methodIdsSize, methodIdsOff;
53112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int classDefsSize, classDefsOff;
53212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
53312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /* expected magic values */
53412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public static final byte[] DEX_FILE_MAGIC = {
53512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00 };
53612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public static final int ENDIAN_CONSTANT = 0x12345678;
53712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public static final int REVERSE_ENDIAN_CONSTANT = 0x78563412;
53812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
53912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
54012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
54112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Holds the contents of a type_id_item.
54212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     *
54312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * This is chiefly a list of indices into the string table.  We need
54412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * some additional bits of data, such as whether or not the type ID
54512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * represents a class defined in this DEX, so we use an object for
54612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * each instead of a simple integer.  (Could use a parallel array, but
54712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * since this is a desktop app it's not essential.)
54812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
54912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    static class TypeIdItem {
55012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int descriptorIdx;       // index into string_ids
55112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
55212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public boolean internal;        // defined within this DEX file?
55312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
55412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
55512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
55612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Holds the contents of a proto_id_item.
55712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
55812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    static class ProtoIdItem {
55912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int shortyIdx;           // index into string_ids
56012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int returnTypeIdx;       // index into type_ids
56112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int parametersOff;       // file offset to a type_list
56212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
56312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int types[];             // contents of type list
56412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
56512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
56612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
56712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Holds the contents of a field_id_item.
56812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
56912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    static class FieldIdItem {
57012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int classIdx;            // index into type_ids (defining class)
57112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int typeIdx;             // index into type_ids (field type)
57212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int nameIdx;             // index into string_ids
57312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
57412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
57512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
57612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Holds the contents of a method_id_item.
57712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
57812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    static class MethodIdItem {
57912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int classIdx;            // index into type_ids
58012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int protoIdx;            // index into proto_ids
58112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int nameIdx;             // index into string_ids
58212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
58312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
58412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
58512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Holds the contents of a class_def_item.
58612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     *
58712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * We don't really need a class for this, but there's some stuff in
58812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * the class_def_item that we might want later.
58912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
59012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    static class ClassDefItem {
59112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        public int classIdx;            // index into type_ids
59212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
59312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden}
59412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
595