12bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson/*
22bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * Copyright (C) 2011 The Android Open Source Project
32bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson *
42bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
52bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * you may not use this file except in compliance with the License.
62bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * You may obtain a copy of the License at
72bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson *
82bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
92bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson *
102bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * Unless required by applicable law or agreed to in writing, software
112bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
122bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * See the License for the specific language governing permissions and
142bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * limitations under the License.
152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson */
162bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
172bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonpackage com.android.dex;
182bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1900a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarcheimport com.android.dex.Code.CatchHandler;
2000a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarcheimport com.android.dex.Code.Try;
212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport com.android.dex.util.ByteInput;
222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport com.android.dex.util.ByteOutput;
232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport com.android.dex.util.FileUtils;
2400a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche
252bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.io.ByteArrayOutputStream;
262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.io.File;
272bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.io.FileInputStream;
282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.io.FileOutputStream;
292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.io.IOException;
302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.io.InputStream;
312bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.io.OutputStream;
322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.io.UTFDataFormatException;
33c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstromimport java.nio.ByteBuffer;
34c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstromimport java.nio.ByteOrder;
35030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilsonimport java.security.MessageDigest;
36030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilsonimport java.security.NoSuchAlgorithmException;
372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.util.AbstractList;
382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.util.Collections;
392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.util.Iterator;
402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.util.List;
412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.util.NoSuchElementException;
42a34f79ba9d4983b96571bbde0a18d352d495f601Jesse Wilsonimport java.util.RandomAccess;
43030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilsonimport java.util.zip.Adler32;
442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.util.zip.ZipEntry;
452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonimport java.util.zip.ZipFile;
462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson/**
482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * The bytes of a dex file in memory for reading and writing. All int offsets
492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson * are unsigned.
502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson */
512bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilsonpublic final class Dex {
52030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    private static final int CHECKSUM_OFFSET = 8;
53030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    private static final int CHECKSUM_SIZE = 4;
54030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    private static final int SIGNATURE_OFFSET = CHECKSUM_OFFSET + CHECKSUM_SIZE;
55030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    private static final int SIGNATURE_SIZE = 20;
56d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers    // Provided as a convenience to avoid a memory allocation to benefit Dalvik.
57d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers    // Note: libcore.util.EmptyArray cannot be accessed when this code isn't run on Dalvik.
58d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers    static final short[] EMPTY_SHORT_ARRAY = new short[0];
59d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
60030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    private ByteBuffer data;
612bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    private final TableOfContents tableOfContents = new TableOfContents();
62030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    private int nextSectionStart = 0;
63d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final StringTable strings = new StringTable();
64d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final TypeIndexToDescriptorIndexTable typeIds = new TypeIndexToDescriptorIndexTable();
65d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final TypeIndexToDescriptorTable typeNames = new TypeIndexToDescriptorTable();
66d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final ProtoIdTable protoIds = new ProtoIdTable();
67d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final FieldIdTable fieldIds = new FieldIdTable();
68d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final MethodIdTable methodIds = new MethodIdTable();
692bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
71030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * Creates a new dex that reads from {@code data}. It is an error to modify
72030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * {@code data} after using it to create a dex buffer.
732bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
74030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public Dex(byte[] data) throws IOException {
75df60589435658db76be61708bfa66515ffba40afBrian Carlstrom        this(ByteBuffer.wrap(data));
76df60589435658db76be61708bfa66515ffba40afBrian Carlstrom    }
77df60589435658db76be61708bfa66515ffba40afBrian Carlstrom
78df60589435658db76be61708bfa66515ffba40afBrian Carlstrom    private Dex(ByteBuffer data) throws IOException {
79df60589435658db76be61708bfa66515ffba40afBrian Carlstrom        this.data = data;
80030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        this.data.order(ByteOrder.LITTLE_ENDIAN);
81030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        this.tableOfContents.readFrom(this);
822bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
832bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
842bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
85030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * Creates a new empty dex of the specified size.
862bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
87030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public Dex(int byteCount) throws IOException {
88030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        this.data = ByteBuffer.wrap(new byte[byteCount]);
89030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        this.data.order(ByteOrder.LITTLE_ENDIAN);
902bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
912bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
922bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
932bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * Creates a new dex buffer of the dex in {@code in}, and closes {@code in}.
942bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
952bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public Dex(InputStream in) throws IOException {
962bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        loadFrom(in);
972bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
982bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
992bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
1002bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * Creates a new dex buffer from the dex file {@code file}.
1012bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
1022bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public Dex(File file) throws IOException {
1032bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (FileUtils.hasArchiveSuffix(file.getName())) {
1042bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ZipFile zipFile = new ZipFile(file);
1052bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ZipEntry entry = zipFile.getEntry(DexFormat.DEX_IN_JAR_NAME);
1062bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            if (entry != null) {
1072bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                loadFrom(zipFile.getInputStream(entry));
1082bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                zipFile.close();
1092bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            } else {
1102bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                throw new DexException("Expected " + DexFormat.DEX_IN_JAR_NAME + " in " + file);
1112bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
1122bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        } else if (file.getName().endsWith(".dex")) {
1132bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            loadFrom(new FileInputStream(file));
1142bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        } else {
1152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            throw new DexException("unknown output extension: " + file);
1162bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1172bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1182bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
119c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom    /**
120c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom     * Creates a new dex from the contents of {@code bytes}. This API supports
121030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * both {@code .dex} and {@code .odex} input. Calling this constructor
122030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * transfers ownership of {@code bytes} to the returned Dex: it is an error
123030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * to access the buffer after calling this method.
124c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom     */
125df60589435658db76be61708bfa66515ffba40afBrian Carlstrom    public static Dex create(ByteBuffer data) throws IOException {
126df60589435658db76be61708bfa66515ffba40afBrian Carlstrom        data.order(ByteOrder.LITTLE_ENDIAN);
127030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson
128c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom        // if it's an .odex file, set position and limit to the .dex section
129df60589435658db76be61708bfa66515ffba40afBrian Carlstrom        if (data.get(0) == 'd'
130df60589435658db76be61708bfa66515ffba40afBrian Carlstrom                && data.get(1) == 'e'
131df60589435658db76be61708bfa66515ffba40afBrian Carlstrom                && data.get(2) == 'y'
132df60589435658db76be61708bfa66515ffba40afBrian Carlstrom                && data.get(3) == '\n') {
133df60589435658db76be61708bfa66515ffba40afBrian Carlstrom            data.position(8);
134df60589435658db76be61708bfa66515ffba40afBrian Carlstrom            int offset = data.getInt();
135df60589435658db76be61708bfa66515ffba40afBrian Carlstrom            int length = data.getInt();
136df60589435658db76be61708bfa66515ffba40afBrian Carlstrom            data.position(offset);
137df60589435658db76be61708bfa66515ffba40afBrian Carlstrom            data.limit(offset + length);
138df60589435658db76be61708bfa66515ffba40afBrian Carlstrom            data = data.slice();
139df60589435658db76be61708bfa66515ffba40afBrian Carlstrom        }
140df60589435658db76be61708bfa66515ffba40afBrian Carlstrom
141c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom        return new Dex(data);
142c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom    }
143c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom
1442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    private void loadFrom(InputStream in) throws IOException {
1452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
1462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        byte[] buffer = new byte[8192];
1472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int count;
1492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        while ((count = in.read(buffer)) != -1) {
1502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            bytesOut.write(buffer, 0, count);
1512bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1522bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        in.close();
1532bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
154030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        this.data = ByteBuffer.wrap(bytesOut.toByteArray());
155030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        this.data.order(ByteOrder.LITTLE_ENDIAN);
1562bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        this.tableOfContents.readFrom(this);
1572bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1582bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1592bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    private static void checkBounds(int index, int length) {
1602bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (index < 0 || index >= length) {
1612bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            throw new IndexOutOfBoundsException("index:" + index + ", length=" + length);
1622bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1632bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1642bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1652bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public void writeTo(OutputStream out) throws IOException {
166030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        byte[] buffer = new byte[8192];
167030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe
168030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.clear();
169030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        while (data.hasRemaining()) {
170030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int count = Math.min(buffer.length, data.remaining());
171030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.get(buffer, 0, count);
172030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            out.write(buffer, 0, count);
173030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
1742bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1752bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1762bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public void writeTo(File dexOut) throws IOException {
1772bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        OutputStream out = new FileOutputStream(dexOut);
1782bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        writeTo(out);
1792bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        out.close();
1802bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1812bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1822bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public TableOfContents getTableOfContents() {
1832bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return tableOfContents;
1842bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1852bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1862bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public Section open(int position) {
187030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        if (position < 0 || position >= data.capacity()) {
188030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            throw new IllegalArgumentException("position=" + position
189030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson                    + " length=" + data.capacity());
190030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
191030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        ByteBuffer sectionData = data.duplicate();
192030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        sectionData.order(ByteOrder.LITTLE_ENDIAN); // necessary?
193030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        sectionData.position(position);
194030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        sectionData.limit(data.capacity());
195030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        return new Section("section", sectionData);
1962bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1972bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1982bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public Section appendSection(int maxByteCount, String name) {
199030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        if ((maxByteCount & 3) != 0) {
200030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            throw new IllegalStateException("Not four byte aligned!");
201030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
202030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        int limit = nextSectionStart + maxByteCount;
203030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        ByteBuffer sectionData = data.duplicate();
204030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        sectionData.order(ByteOrder.LITTLE_ENDIAN); // necessary?
205030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        sectionData.position(nextSectionStart);
206030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        sectionData.limit(limit);
207030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        Section result = new Section(name, sectionData);
208030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        nextSectionStart = limit;
2092bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return result;
2102bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2112bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
212030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public int getLength() {
213030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        return data.capacity();
2142bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
216030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public int getNextSectionStart() {
217030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        return nextSectionStart;
2182bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
220030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    /**
221030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * Returns a copy of the the bytes of this dex.
222030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     */
2232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public byte[] getBytes() {
224030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe
225030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        byte[] result = new byte[data.capacity()];
226030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.position(0);
227030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.get(result);
228030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        return result;
2292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2312bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public List<String> strings() {
2322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return strings;
2332bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2352bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public List<Integer> typeIds() {
2362bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return typeIds;
2372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public List<String> typeNames() {
2402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return typeNames;
2412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2432bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public List<ProtoId> protoIds() {
2442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return protoIds;
2452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public List<FieldId> fieldIds() {
2482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return fieldIds;
2492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2512bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public List<MethodId> methodIds() {
2522bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return methodIds;
2532bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2542bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2552bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public Iterable<ClassDef> classDefs() {
256d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        return new ClassDefIterable();
2572bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2582bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2592bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public TypeList readTypeList(int offset) {
2602bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (offset == 0) {
2612bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return TypeList.EMPTY;
2622bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
2632bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return open(offset).readTypeList();
2642bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2652bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2662bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public ClassData readClassData(ClassDef classDef) {
2672bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int offset = classDef.getClassDataOffset();
2682bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (offset == 0) {
2692bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            throw new IllegalArgumentException("offset == 0");
2702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
2712bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return open(offset).readClassData();
2722bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2732bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2742bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public Code readCode(ClassData.Method method) {
2752bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int offset = method.getCodeOffset();
2762bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (offset == 0) {
2772bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            throw new IllegalArgumentException("offset == 0");
2782bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
2792bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return open(offset).readCode();
2802bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2812bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
282030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    /**
283030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * Returns the signature of all but the first 32 bytes of this dex. The
284030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * first 32 bytes of dex files are not specified to be included in the
285030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * signature.
286030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     */
287030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public byte[] computeSignature() throws IOException {
288030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        MessageDigest digest;
289030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        try {
290030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            digest = MessageDigest.getInstance("SHA-1");
291030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        } catch (NoSuchAlgorithmException e) {
292030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            throw new AssertionError();
293030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
294030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        byte[] buffer = new byte[8192];
295030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe
296030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.limit(data.capacity());
297030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.position(SIGNATURE_OFFSET + SIGNATURE_SIZE);
298030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        while (data.hasRemaining()) {
299030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int count = Math.min(buffer.length, data.remaining());
300030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.get(buffer, 0, count);
301030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            digest.update(buffer, 0, count);
302030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
303030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        return digest.digest();
304030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    }
305030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson
306030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    /**
307030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * Returns the checksum of all but the first 12 bytes of {@code dex}.
308030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     */
309030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public int computeChecksum() throws IOException {
310030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        Adler32 adler32 = new Adler32();
311030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        byte[] buffer = new byte[8192];
312030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe
313030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.limit(data.capacity());
314030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.position(CHECKSUM_OFFSET + CHECKSUM_SIZE);
315030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        while (data.hasRemaining()) {
316030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int count = Math.min(buffer.length, data.remaining());
317030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.get(buffer, 0, count);
318030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            adler32.update(buffer, 0, count);
319030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
320030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        return (int) adler32.getValue();
321030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    }
322030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson
323030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    /**
324030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * Generates the signature and checksum of the dex file {@code out} and
325030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * writes them to the file.
326030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     */
327030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public void writeHashes() throws IOException {
328030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        open(SIGNATURE_OFFSET).write(computeSignature());
329030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        open(CHECKSUM_OFFSET).writeInt(computeChecksum());
330030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    }
331030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson
332d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    /**
333d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     * Look up a field id name index from a field index. Cheaper than:
334d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     * {@code fieldIds().get(fieldDexIndex).getNameIndex();}
335d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     */
336d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    public int nameIndexFromFieldIndex(int fieldIndex) {
337d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        checkBounds(fieldIndex, tableOfContents.fieldIds.size);
338d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        int position = tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * fieldIndex);
339d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position += SizeOf.USHORT;  // declaringClassIndex
340d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position += SizeOf.USHORT;  // typeIndex
341d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        return data.getInt(position);  // nameIndex
342d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    }
343d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
344d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    public int findStringIndex(String s) {
345d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        return Collections.binarySearch(strings, s);
346d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    }
347d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
348d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    public int findTypeIndex(String descriptor) {
349d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        return Collections.binarySearch(typeNames, descriptor);
350d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    }
351d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
352d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    public int findFieldIndex(FieldId fieldId) {
353d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        return Collections.binarySearch(fieldIds, fieldId);
354d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    }
355d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
356d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    public int findMethodIndex(MethodId methodId) {
357d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        return Collections.binarySearch(methodIds, methodId);
358d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    }
359d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
360a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    public int findClassDefIndexFromTypeIndex(int typeIndex) {
361a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        checkBounds(typeIndex, tableOfContents.typeIds.size);
362a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        if (!tableOfContents.classDefs.exists()) {
363a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers            return -1;
364a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        }
365a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        for (int i = 0; i < tableOfContents.classDefs.size; i++) {
366a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers            if (typeIndexFromClassDefIndex(i) == typeIndex) {
367a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers                return i;
368a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers            }
369a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        }
370a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        return -1;
371a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    }
372a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers
373d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    /**
374d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     * Look up a field id type index from a field index. Cheaper than:
375d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     * {@code fieldIds().get(fieldDexIndex).getTypeIndex();}
376d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     */
377d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    public int typeIndexFromFieldIndex(int fieldIndex) {
378d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        checkBounds(fieldIndex, tableOfContents.fieldIds.size);
379d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        int position = tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * fieldIndex);
380d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position += SizeOf.USHORT;  // declaringClassIndex
381d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        return data.getShort(position) & 0xFFFF;  // typeIndex
382d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    }
383d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
384d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    /**
385a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers     * Look up a method id declaring class index from a method index. Cheaper than:
386a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers     * {@code methodIds().get(methodIndex).getDeclaringClassIndex();}
387a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers     */
388a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    public int declaringClassIndexFromMethodIndex(int methodIndex) {
389a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        checkBounds(methodIndex, tableOfContents.methodIds.size);
390a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex);
391a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        return data.getShort(position) & 0xFFFF;  // declaringClassIndex
392a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    }
393a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers
394a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    /**
395d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     * Look up a method id name index from a method index. Cheaper than:
396d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     * {@code methodIds().get(methodIndex).getNameIndex();}
397d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     */
398d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    public int nameIndexFromMethodIndex(int methodIndex) {
399d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        checkBounds(methodIndex, tableOfContents.methodIds.size);
400d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex);
401d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position += SizeOf.USHORT;  // declaringClassIndex
402d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position += SizeOf.USHORT;  // protoIndex
403d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        return data.getInt(position);  // nameIndex
404d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    }
405d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
406d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    /**
407d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     * Look up a parameter type ids from a method index. Cheaper than:
408d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     * {@code readTypeList(protoIds.get(methodIds().get(methodDexIndex).getProtoIndex()).getParametersOffset()).getTypes();}
409d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     */
410d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    public short[] parameterTypeIndicesFromMethodIndex(int methodIndex) {
411d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        checkBounds(methodIndex, tableOfContents.methodIds.size);
412d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex);
413d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position += SizeOf.USHORT;  // declaringClassIndex
414d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        int protoIndex = data.getShort(position) & 0xFFFF;
415d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        checkBounds(protoIndex, tableOfContents.protoIds.size);
416d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position = tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * protoIndex);
417d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position += SizeOf.UINT;  // shortyIndex
418d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position += SizeOf.UINT;  // returnTypeIndex
419d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        int parametersOffset = data.getInt(position);
420d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        if (parametersOffset == 0) {
421d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return EMPTY_SHORT_ARRAY;
422d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
423d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position = parametersOffset;
424d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        int size = data.getInt(position);
425d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        if (size <= 0) {
426d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            throw new AssertionError("Unexpected parameter type list size: " + size);
427d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
428d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position += SizeOf.UINT;
429d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        short[] types = new short[size];
430d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        for (int i = 0; i < size; i++) {
431d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            types[i] = data.getShort(position);
432d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            position += SizeOf.USHORT;
433d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
434d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        return types;
435d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    }
436d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
437d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    /**
438d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     * Look up a method id return type index from a method index. Cheaper than:
439d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     * {@code protoIds().get(methodIds().get(methodDexIndex).getProtoIndex()).getReturnTypeIndex();}
440d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     */
441d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    public int returnTypeIndexFromMethodIndex(int methodIndex) {
442d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        checkBounds(methodIndex, tableOfContents.methodIds.size);
443d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex);
444d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position += SizeOf.USHORT;  // declaringClassIndex
445d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        int protoIndex = data.getShort(position) & 0xFFFF;
446d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        checkBounds(protoIndex, tableOfContents.protoIds.size);
447d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position = tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * protoIndex);
448d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        position += SizeOf.UINT;  // shortyIndex
449d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        return data.getInt(position);  // returnTypeIndex
450d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    }
451d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
452d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    /**
453d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     * Look up a descriptor index from a type index. Cheaper than:
454d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     * {@code open(tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM)).readInt();}
455d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers     */
456a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    public int descriptorIndexFromTypeIndex(int typeIndex) {
457d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers       checkBounds(typeIndex, tableOfContents.typeIds.size);
458d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers       int position = tableOfContents.typeIds.off + (SizeOf.TYPE_ID_ITEM * typeIndex);
459d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers       return data.getInt(position);
460d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    }
461d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
462a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    /**
463a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers     * Look up a type index index from a class def index.
464a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers     */
465a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    public int typeIndexFromClassDefIndex(int classDefIndex) {
466a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        checkBounds(classDefIndex, tableOfContents.classDefs.size);
467a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        int position = tableOfContents.classDefs.off + (SizeOf.CLASS_DEF_ITEM * classDefIndex);
468a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        return data.getInt(position);
469a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    }
470a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers
471a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    /**
472a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers     * Look up a type index index from a class def index.
473a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers     */
474a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    public int annotationDirectoryOffsetFromClassDefIndex(int classDefIndex) {
475a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        checkBounds(classDefIndex, tableOfContents.classDefs.size);
476a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        int position = tableOfContents.classDefs.off + (SizeOf.CLASS_DEF_ITEM * classDefIndex);
477a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        position += SizeOf.UINT;  // type
478a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        position += SizeOf.UINT;  // accessFlags
479a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        position += SizeOf.UINT;  // superType
480a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        position += SizeOf.UINT;  // interfacesOffset
481a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        position += SizeOf.UINT;  // sourceFileIndex
482a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        return data.getInt(position);
483a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    }
484a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers
485a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    /**
486a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers     * Look up interface types indices from a  return type index from a method index. Cheaper than:
487a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers     * {@code ...getClassDef(classDefIndex).getInterfaces();}
488a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers     */
489a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    public short[] interfaceTypeIndicesFromClassDefIndex(int classDefIndex) {
490a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        checkBounds(classDefIndex, tableOfContents.classDefs.size);
491a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        int position = tableOfContents.classDefs.off + (SizeOf.CLASS_DEF_ITEM * classDefIndex);
492a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        position += SizeOf.UINT;  // type
493a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        position += SizeOf.UINT;  // accessFlags
494a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        position += SizeOf.UINT;  // superType
495a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        int interfacesOffset = data.getInt(position);
496a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        if (interfacesOffset == 0) {
497a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers            return EMPTY_SHORT_ARRAY;
498a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        }
499a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        position = interfacesOffset;
500a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        int size = data.getInt(position);
501a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        if (size <= 0) {
502a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers            throw new AssertionError("Unexpected interfaces list size: " + size);
503a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        }
504a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        position += SizeOf.UINT;
505a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        short[] types = new short[size];
506a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        for (int i = 0; i < size; i++) {
507a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers            types[i] = data.getShort(position);
508a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers            position += SizeOf.USHORT;
509a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        }
510a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers        return types;
511a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers    }
512a6e22fc9b70ebe39abd716ce37450bda935c0fb8Ian Rogers
5132bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public final class Section implements ByteInput, ByteOutput {
5142bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        private final String name;
515030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        private final ByteBuffer data;
5160436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson        private final int initialPosition;
5172bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
518030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        private Section(String name, ByteBuffer data) {
5192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            this.name = name;
520030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            this.data = data;
5210436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson            this.initialPosition = data.position();
5222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public int getPosition() {
525030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return data.position();
5262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5272bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public int readInt() {
529030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return data.getInt();
5302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5312bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public short readShort() {
533030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return data.getShort();
5342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5352bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5362bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public int readUnsignedShort() {
5372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return readShort() & 0xffff;
5382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public byte readByte() {
541030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return data.get();
5422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5432bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public byte[] readByteArray(int length) {
545030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            byte[] result = new byte[length];
546030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.get(result);
5472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return result;
5482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public short[] readShortArray(int length) {
551d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            if (length == 0) {
552d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                return EMPTY_SHORT_ARRAY;
553d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            }
5542bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            short[] result = new short[length];
5552bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (int i = 0; i < length; i++) {
5562bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                result[i] = readShort();
5572bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
5582bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return result;
5592bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5602bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5612bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public int readUleb128() {
5622bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return Leb128.readUnsignedLeb128(this);
5632bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5642bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
565dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes        public int readUleb128p1() {
566dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes            return Leb128.readUnsignedLeb128(this) - 1;
567dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes        }
568dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes
5692bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public int readSleb128() {
5702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return Leb128.readSignedLeb128(this);
5712bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5722bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
573dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes        public void writeUleb128p1(int i) {
574dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes            writeUleb128(i + 1);
575dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes        }
576dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes
5772bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public TypeList readTypeList() {
5782bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int size = readInt();
579d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            short[] types = readShortArray(size);
5802bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            alignToFourBytes();
5812bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return new TypeList(Dex.this, types);
5822bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5832bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5842bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public String readString() {
5852bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int offset = readInt();
586030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int savedPosition = data.position();
587030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int savedLimit = data.limit();
588030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.position(offset);
589030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.limit(data.capacity());
5902bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            try {
5912bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                int expectedLength = readUleb128();
5922bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                String result = Mutf8.decode(this, new char[expectedLength]);
5932bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                if (result.length() != expectedLength) {
5942bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    throw new DexException("Declared length " + expectedLength
5952bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                            + " doesn't match decoded length of " + result.length());
5962bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                }
5972bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                return result;
5982bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            } catch (UTFDataFormatException e) {
5992bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                throw new DexException(e);
6002bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            } finally {
601030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson                data.position(savedPosition);
602030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson                data.limit(savedLimit);
6032bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
6042bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
6052bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
6062bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public FieldId readFieldId() {
6072bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int declaringClassIndex = readUnsignedShort();
6082bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int typeIndex = readUnsignedShort();
6092bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int nameIndex = readInt();
6102bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return new FieldId(Dex.this, declaringClassIndex, typeIndex, nameIndex);
6112bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
6122bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
6132bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public MethodId readMethodId() {
6142bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int declaringClassIndex = readUnsignedShort();
6152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int protoIndex = readUnsignedShort();
6162bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int nameIndex = readInt();
6172bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return new MethodId(Dex.this, declaringClassIndex, protoIndex, nameIndex);
6182bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
6192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
6202bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public ProtoId readProtoId() {
6212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int shortyIndex = readInt();
6222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int returnTypeIndex = readInt();
6232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int parametersOffset = readInt();
6242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return new ProtoId(Dex.this, shortyIndex, returnTypeIndex, parametersOffset);
6252bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
6262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
6272bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public ClassDef readClassDef() {
6282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int offset = getPosition();
6292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int type = readInt();
6302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int accessFlags = readInt();
6312bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int supertype = readInt();
6322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int interfacesOffset = readInt();
6332bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int sourceFileIndex = readInt();
6342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int annotationsOffset = readInt();
6352bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int classDataOffset = readInt();
6362bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int staticValuesOffset = readInt();
6372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return new ClassDef(Dex.this, offset, type, accessFlags, supertype,
6382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    interfacesOffset, sourceFileIndex, annotationsOffset, classDataOffset,
6392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    staticValuesOffset);
6402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
6412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
6422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        private Code readCode() {
6432bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int registersSize = readUnsignedShort();
6442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int insSize = readUnsignedShort();
6452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int outsSize = readUnsignedShort();
6462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int triesSize = readUnsignedShort();
6472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int debugInfoOffset = readInt();
6482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int instructionsSize = readInt();
6492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            short[] instructions = readShortArray(instructionsSize);
65000a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            Try[] tries;
65100a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            CatchHandler[] catchHandlers;
6522bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            if (triesSize > 0) {
653d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                if (instructions.length % 2 == 1) {
654d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                    readShort(); // padding
655d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                }
656d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers
657d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                /*
658d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                 * We can't read the tries until we've read the catch handlers.
659d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                 * Unfortunately they're in the opposite order in the dex file
660d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                 * so we need to read them out-of-order.
661d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                 */
662d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                Section triesSection = open(data.position());
663d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                skip(triesSize * SizeOf.TRY_ITEM);
664d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                catchHandlers = readCatchHandlers();
665d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                tries = triesSection.readTries(triesSize, catchHandlers);
666d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            } else {
667d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                tries = new Try[0];
668d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                catchHandlers = new CatchHandler[0];
669d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            }
670d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            return new Code(registersSize, insSize, outsSize, debugInfoOffset, instructions,
671d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                            tries, catchHandlers);
67200a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        }
67300a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche
67400a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        private CatchHandler[] readCatchHandlers() {
675d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            int baseOffset = data.position();
676d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            int catchHandlersSize = readUleb128();
677d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            CatchHandler[] result = new CatchHandler[catchHandlersSize];
678d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            for (int i = 0; i < catchHandlersSize; i++) {
679d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                int offset = data.position() - baseOffset;
680d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                result[i] = readCatchHandler(offset);
681d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            }
682d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            return result;
68300a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        }
68400a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche
68500a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        private Try[] readTries(int triesSize, CatchHandler[] catchHandlers) {
686d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            Try[] result = new Try[triesSize];
687d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            for (int i = 0; i < triesSize; i++) {
688d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                int startAddress = readInt();
689d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                int instructionCount = readUnsignedShort();
690d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                int handlerOffset = readUnsignedShort();
691d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                int catchHandlerIndex = findCatchHandlerIndex(catchHandlers, handlerOffset);
692d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                result[i] = new Try(startAddress, instructionCount, catchHandlerIndex);
693d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            }
694d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            return result;
69500a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        }
69600a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche
69700a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        private int findCatchHandlerIndex(CatchHandler[] catchHandlers, int offset) {
698d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            for (int i = 0; i < catchHandlers.length; i++) {
699d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                CatchHandler catchHandler = catchHandlers[i];
700d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                if (catchHandler.getOffset() == offset) {
701d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                    return i;
702d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                }
7032bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
704d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            throw new IllegalArgumentException();
70500a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        }
70600a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche
70700a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        private CatchHandler readCatchHandler(int offset) {
708d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            int size = readSleb128();
709d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            int handlersCount = Math.abs(size);
710d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            int[] typeIndexes = new int[handlersCount];
711d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            int[] addresses = new int[handlersCount];
712d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            for (int i = 0; i < handlersCount; i++) {
713d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                typeIndexes[i] = readUleb128();
714d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                addresses[i] = readUleb128();
715d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            }
716d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            int catchAllAddress = size <= 0 ? readUleb128() : -1;
717d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            return new CatchHandler(typeIndexes, addresses, catchAllAddress, offset);
7182bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7202bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        private ClassData readClassData() {
7212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int staticFieldsSize = readUleb128();
7222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int instanceFieldsSize = readUleb128();
7232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int directMethodsSize = readUleb128();
7242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int virtualMethodsSize = readUleb128();
7252bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ClassData.Field[] staticFields = readFields(staticFieldsSize);
7262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ClassData.Field[] instanceFields = readFields(instanceFieldsSize);
7272bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ClassData.Method[] directMethods = readMethods(directMethodsSize);
7282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ClassData.Method[] virtualMethods = readMethods(virtualMethodsSize);
7292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return new ClassData(staticFields, instanceFields, directMethods, virtualMethods);
7302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7312bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        private ClassData.Field[] readFields(int count) {
7332bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ClassData.Field[] result = new ClassData.Field[count];
7342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int fieldIndex = 0;
7352bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (int i = 0; i < count; i++) {
7362bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                fieldIndex += readUleb128(); // field index diff
7372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                int accessFlags = readUleb128();
7382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                result[i] = new ClassData.Field(fieldIndex, accessFlags);
7392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
7402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return result;
7412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7432bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        private ClassData.Method[] readMethods(int count) {
7442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ClassData.Method[] result = new ClassData.Method[count];
7452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int methodIndex = 0;
7462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (int i = 0; i < count; i++) {
7472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                methodIndex += readUleb128(); // method index diff
7482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                int accessFlags = readUleb128();
7492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                int codeOff = readUleb128();
7502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                result[i] = new ClassData.Method(methodIndex, accessFlags, codeOff);
7512bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
7522bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return result;
7532bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7542bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
755030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        /**
756030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson         * Returns a byte array containing the bytes from {@code start} to this
757030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson         * section's current position.
758030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson         */
759030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        private byte[] getBytesFrom(int start) {
760030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int end = data.position();
761030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            byte[] result = new byte[end - start];
762030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.position(start);
763030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.get(result);
764030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return result;
765030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
766030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson
7672bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public Annotation readAnnotation() {
7682bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            byte visibility = readByte();
769030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int start = data.position();
7702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            new EncodedValueReader(this, EncodedValueReader.ENCODED_ANNOTATION).skipValue();
771030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return new Annotation(Dex.this, visibility, new EncodedValue(getBytesFrom(start)));
7722bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7732bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7742bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public EncodedValue readEncodedArray() {
775030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int start = data.position();
7762bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            new EncodedValueReader(this, EncodedValueReader.ENCODED_ARRAY).skipValue();
777030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return new EncodedValue(getBytesFrom(start));
7782bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7792bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
78000a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        public void skip(int count) {
781d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            if (count < 0) {
782d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers                throw new IllegalArgumentException();
783d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            }
784d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers            data.position(data.position() + count);
785d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers        }
78600a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche
7872bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        /**
788450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom         * Skips bytes until the position is aligned to a multiple of 4.
7892bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         */
7902bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void alignToFourBytes() {
791450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom            data.position((data.position() + 3) & ~3);
792450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom        }
793450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom
794450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom        /**
795450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom         * Writes 0x00 until the position is aligned to a multiple of 4.
796450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom         */
797450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom        public void alignToFourBytesWithZeroFill() {
798030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            while ((data.position() & 3) != 0) {
799030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson                data.put((byte) 0);
8002bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
8012bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8022bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
8032bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void assertFourByteAligned() {
804030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            if ((data.position() & 3) != 0) {
8052bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                throw new IllegalStateException("Not four byte aligned!");
8062bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
8072bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8082bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
8092bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void write(byte[] bytes) {
810030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            this.data.put(bytes);
8112bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8122bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
8132bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeByte(int b) {
814030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.put((byte) b);
8152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8162bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
8172bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeShort(short i) {
818030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.putShort(i);
8192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8202bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
8212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeUnsignedShort(int i) {
8222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            short s = (short) i;
8232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            if (i != (s & 0xffff)) {
8242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                throw new IllegalArgumentException("Expected an unsigned short: " + i);
8252bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
8262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            writeShort(s);
8272bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
8292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void write(short[] shorts) {
8302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (short s : shorts) {
8312bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                writeShort(s);
8322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
8332bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
8352bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeInt(int i) {
836030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.putInt(i);
8372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
8392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeUleb128(int i) {
8402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            try {
8412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                Leb128.writeUnsignedLeb128(this, i);
8422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            } catch (ArrayIndexOutOfBoundsException e) {
843030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson                throw new DexException("Section limit " + data.limit() + " exceeded by " + name);
8442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
8452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
8472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeSleb128(int i) {
8482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            try {
8492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                Leb128.writeSignedLeb128(this, i);
8502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            } catch (ArrayIndexOutOfBoundsException e) {
851030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson                throw new DexException("Section limit " + data.limit() + " exceeded by " + name);
8522bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
8532bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8542bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
8552bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeStringData(String value) {
8562bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            try {
8572bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                int length = value.length();
8582bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                writeUleb128(length);
8592bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                write(Mutf8.encode(value));
8602bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                writeByte(0);
8612bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            } catch (UTFDataFormatException e) {
8622bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                throw new AssertionError();
8632bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
8642bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8652bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
8662bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeTypeList(TypeList typeList) {
8672bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            short[] types = typeList.getTypes();
8682bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            writeInt(types.length);
8692bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (short type : types) {
8702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                writeShort(type);
8712bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
872450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom            alignToFourBytesWithZeroFill();
8732bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8742bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
8752bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        /**
8762bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * Returns the number of bytes remaining in this section.
8772bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         */
8782bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public int remaining() {
879030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return data.remaining();
8802bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
8810436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson
8820436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson        /**
8830436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson         * Returns the number of bytes used by this section.
8840436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson         */
8850436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson        public int used () {
8860436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson            return data.position() - initialPosition;
8870436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson        }
8882bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
889d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers
890d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final class StringTable extends AbstractList<String> implements RandomAccess {
891d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override public String get(int index) {
892d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            checkBounds(index, tableOfContents.stringIds.size);
893d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return open(tableOfContents.stringIds.off + (index * SizeOf.STRING_ID_ITEM))
894d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers                    .readString();
895d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
896d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override public int size() {
897d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return tableOfContents.stringIds.size;
898d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
899d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    };
900d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers
901d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final class TypeIndexToDescriptorIndexTable extends AbstractList<Integer>
902d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            implements RandomAccess {
903d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override public Integer get(int index) {
904d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return descriptorIndexFromTypeIndex(index);
905d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
906d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override public int size() {
907d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return tableOfContents.typeIds.size;
908d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
909d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    };
910d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers
911d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final class TypeIndexToDescriptorTable extends AbstractList<String>
912d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            implements RandomAccess {
913d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override public String get(int index) {
914d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return strings.get(descriptorIndexFromTypeIndex(index));
915d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
916d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override public int size() {
917d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return tableOfContents.typeIds.size;
918d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
919d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    };
920d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers
921d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final class ProtoIdTable extends AbstractList<ProtoId> implements RandomAccess {
922d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override public ProtoId get(int index) {
923d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            checkBounds(index, tableOfContents.protoIds.size);
924d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return open(tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * index))
925d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers                    .readProtoId();
926d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers        }
927d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override public int size() {
928d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return tableOfContents.protoIds.size;
929d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers        }
930d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    };
931d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
932d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final class FieldIdTable extends AbstractList<FieldId> implements RandomAccess {
933d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override public FieldId get(int index) {
934d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            checkBounds(index, tableOfContents.fieldIds.size);
935d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return open(tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * index))
936d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers                    .readFieldId();
937d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers        }
938d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override public int size() {
939d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return tableOfContents.fieldIds.size;
940d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
941d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    };
942d3e311496e0b08acd959c3ffa31d9930a71bae19Ian Rogers
943d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final class MethodIdTable extends AbstractList<MethodId> implements RandomAccess {
944d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override public MethodId get(int index) {
945d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            checkBounds(index, tableOfContents.methodIds.size);
946d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return open(tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * index))
947d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers                    .readMethodId();
948d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
949d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override public int size() {
950d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return tableOfContents.methodIds.size;
951d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
952d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    };
953d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
954d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final class ClassDefIterator implements Iterator<ClassDef> {
955d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        private final Dex.Section in = open(tableOfContents.classDefs.off);
956d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        private int count = 0;
957d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
958d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override
959d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        public boolean hasNext() {
960d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return count < tableOfContents.classDefs.size;
961d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
962d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override
963d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        public ClassDef next() {
964d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            if (!hasNext()) {
965d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers                throw new NoSuchElementException();
966d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            }
967d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            count++;
968d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return in.readClassDef();
969d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
970d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        @Override
971d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            public void remove() {
972d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            throw new UnsupportedOperationException();
973d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
974d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    };
975d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers
976d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    private final class ClassDefIterable implements Iterable<ClassDef> {
977d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        public Iterator<ClassDef> iterator() {
978d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers            return !tableOfContents.classDefs.exists()
979d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers               ? Collections.<ClassDef>emptySet().iterator()
980d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers               : new ClassDefIterator();
981d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers        }
982d4ec55c4e1acc3c3df937facbd367aff6618536cIan Rogers    };
9832bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson}
984