Dex.java revision 00a2d1ee4cfee1f33344c3798940bbae22f96187
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;
56030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson
57030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    private ByteBuffer data;
582bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    private final TableOfContents tableOfContents = new TableOfContents();
59030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    private int nextSectionStart = 0;
602bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
61a34f79ba9d4983b96571bbde0a18d352d495f601Jesse Wilson    private static abstract class AbstractRandomAccessList<T>
62a34f79ba9d4983b96571bbde0a18d352d495f601Jesse Wilson            extends AbstractList<T> implements RandomAccess {
63a34f79ba9d4983b96571bbde0a18d352d495f601Jesse Wilson    }
64a34f79ba9d4983b96571bbde0a18d352d495f601Jesse Wilson
65a34f79ba9d4983b96571bbde0a18d352d495f601Jesse Wilson    private List<String> strings = new AbstractRandomAccessList<String>() {
662bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        @Override public String get(int index) {
672bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            checkBounds(index, tableOfContents.stringIds.size);
682bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return open(tableOfContents.stringIds.off + (index * SizeOf.STRING_ID_ITEM))
692bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    .readString();
702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
712bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        @Override public int size() {
722bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return tableOfContents.stringIds.size;
732bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
742bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    };
752bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
76a34f79ba9d4983b96571bbde0a18d352d495f601Jesse Wilson    private final List<Integer> typeIds = new AbstractRandomAccessList<Integer>() {
772bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        @Override public Integer get(int index) {
782bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            checkBounds(index, tableOfContents.typeIds.size);
792bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return open(tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM)).readInt();
802bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
812bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        @Override public int size() {
822bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return tableOfContents.typeIds.size;
832bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
842bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    };
852bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
86a34f79ba9d4983b96571bbde0a18d352d495f601Jesse Wilson    private final List<String> typeNames = new AbstractRandomAccessList<String>() {
872bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        @Override public String get(int index) {
882bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            checkBounds(index, tableOfContents.typeIds.size);
892bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return strings.get(typeIds.get(index));
902bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
912bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        @Override public int size() {
922bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return tableOfContents.typeIds.size;
932bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
942bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    };
952bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
96a34f79ba9d4983b96571bbde0a18d352d495f601Jesse Wilson    private final List<ProtoId> protoIds = new AbstractRandomAccessList<ProtoId>() {
972bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        @Override public ProtoId get(int index) {
982bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            checkBounds(index, tableOfContents.protoIds.size);
992bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return open(tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * index))
1002bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    .readProtoId();
1012bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1022bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        @Override public int size() {
1032bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return tableOfContents.protoIds.size;
1042bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1052bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    };
1062bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
107a34f79ba9d4983b96571bbde0a18d352d495f601Jesse Wilson    private final List<FieldId> fieldIds = new AbstractRandomAccessList<FieldId>() {
1082bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        @Override public FieldId get(int index) {
1092bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            checkBounds(index, tableOfContents.fieldIds.size);
1102bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return open(tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * index))
1112bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    .readFieldId();
1122bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1132bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        @Override public int size() {
1142bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return tableOfContents.fieldIds.size;
1152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1162bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    };
1172bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
118a34f79ba9d4983b96571bbde0a18d352d495f601Jesse Wilson    private final List<MethodId> methodIds = new AbstractRandomAccessList<MethodId>() {
1192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        @Override public MethodId get(int index) {
1202bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            checkBounds(index, tableOfContents.methodIds.size);
1212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return open(tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * index))
1222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    .readMethodId();
1232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        @Override public int size() {
1252bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return tableOfContents.methodIds.size;
1262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1272bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    };
1282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
130030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * Creates a new dex that reads from {@code data}. It is an error to modify
131030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * {@code data} after using it to create a dex buffer.
1322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
133030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public Dex(byte[] data) throws IOException {
134df60589435658db76be61708bfa66515ffba40afBrian Carlstrom        this(ByteBuffer.wrap(data));
135df60589435658db76be61708bfa66515ffba40afBrian Carlstrom    }
136df60589435658db76be61708bfa66515ffba40afBrian Carlstrom
137df60589435658db76be61708bfa66515ffba40afBrian Carlstrom    private Dex(ByteBuffer data) throws IOException {
138df60589435658db76be61708bfa66515ffba40afBrian Carlstrom        this.data = data;
139030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        this.data.order(ByteOrder.LITTLE_ENDIAN);
140030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        this.tableOfContents.readFrom(this);
1412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1432bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
144030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * Creates a new empty dex of the specified size.
1452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
146030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public Dex(int byteCount) throws IOException {
147030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        this.data = ByteBuffer.wrap(new byte[byteCount]);
148030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        this.data.order(ByteOrder.LITTLE_ENDIAN);
1492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1512bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
1522bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * Creates a new dex buffer of the dex in {@code in}, and closes {@code in}.
1532bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
1542bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public Dex(InputStream in) throws IOException {
1552bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        loadFrom(in);
1562bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1572bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
1582bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    /**
1592bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     * Creates a new dex buffer from the dex file {@code file}.
1602bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson     */
1612bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public Dex(File file) throws IOException {
1622bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (FileUtils.hasArchiveSuffix(file.getName())) {
1632bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ZipFile zipFile = new ZipFile(file);
1642bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ZipEntry entry = zipFile.getEntry(DexFormat.DEX_IN_JAR_NAME);
1652bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            if (entry != null) {
1662bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                loadFrom(zipFile.getInputStream(entry));
1672bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                zipFile.close();
1682bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            } else {
1692bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                throw new DexException("Expected " + DexFormat.DEX_IN_JAR_NAME + " in " + file);
1702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
1712bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        } else if (file.getName().endsWith(".dex")) {
1722bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            loadFrom(new FileInputStream(file));
1732bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        } else {
1742bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            throw new DexException("unknown output extension: " + file);
1752bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
1762bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
1772bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
178c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom    /**
179c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom     * Creates a new dex from the contents of {@code bytes}. This API supports
180030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * both {@code .dex} and {@code .odex} input. Calling this constructor
181030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * transfers ownership of {@code bytes} to the returned Dex: it is an error
182030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * to access the buffer after calling this method.
183c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom     */
184df60589435658db76be61708bfa66515ffba40afBrian Carlstrom    public static Dex create(ByteBuffer data) throws IOException {
185df60589435658db76be61708bfa66515ffba40afBrian Carlstrom        data.order(ByteOrder.LITTLE_ENDIAN);
186030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson
187c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom        // if it's an .odex file, set position and limit to the .dex section
188df60589435658db76be61708bfa66515ffba40afBrian Carlstrom        if (data.get(0) == 'd'
189df60589435658db76be61708bfa66515ffba40afBrian Carlstrom                && data.get(1) == 'e'
190df60589435658db76be61708bfa66515ffba40afBrian Carlstrom                && data.get(2) == 'y'
191df60589435658db76be61708bfa66515ffba40afBrian Carlstrom                && data.get(3) == '\n') {
192df60589435658db76be61708bfa66515ffba40afBrian Carlstrom            data.position(8);
193df60589435658db76be61708bfa66515ffba40afBrian Carlstrom            int offset = data.getInt();
194df60589435658db76be61708bfa66515ffba40afBrian Carlstrom            int length = data.getInt();
195df60589435658db76be61708bfa66515ffba40afBrian Carlstrom            data.position(offset);
196df60589435658db76be61708bfa66515ffba40afBrian Carlstrom            data.limit(offset + length);
197df60589435658db76be61708bfa66515ffba40afBrian Carlstrom            data = data.slice();
198df60589435658db76be61708bfa66515ffba40afBrian Carlstrom        }
199df60589435658db76be61708bfa66515ffba40afBrian Carlstrom
200c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom        return new Dex(data);
201c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom    }
202c69e85bfb7ddd6c4b0023ca29eeb0416087f9a8bBrian Carlstrom
2032bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    private void loadFrom(InputStream in) throws IOException {
2042bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
2052bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        byte[] buffer = new byte[8192];
2062bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2072bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int count;
2082bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        while ((count = in.read(buffer)) != -1) {
2092bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            bytesOut.write(buffer, 0, count);
2102bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
2112bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        in.close();
2122bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
213030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        this.data = ByteBuffer.wrap(bytesOut.toByteArray());
214030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        this.data.order(ByteOrder.LITTLE_ENDIAN);
2152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        this.tableOfContents.readFrom(this);
2162bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2172bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2182bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    private static void checkBounds(int index, int length) {
2192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (index < 0 || index >= length) {
2202bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            throw new IndexOutOfBoundsException("index:" + index + ", length=" + length);
2212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
2222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public void writeTo(OutputStream out) throws IOException {
225030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        byte[] buffer = new byte[8192];
226030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe
227030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.clear();
228030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        while (data.hasRemaining()) {
229030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int count = Math.min(buffer.length, data.remaining());
230030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.get(buffer, 0, count);
231030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            out.write(buffer, 0, count);
232030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
2332bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2352bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public void writeTo(File dexOut) throws IOException {
2362bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        OutputStream out = new FileOutputStream(dexOut);
2372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        writeTo(out);
2382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        out.close();
2392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public TableOfContents getTableOfContents() {
2422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return tableOfContents;
2432bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public Section open(int position) {
246030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        if (position < 0 || position >= data.capacity()) {
247030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            throw new IllegalArgumentException("position=" + position
248030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson                    + " length=" + data.capacity());
249030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
250030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        ByteBuffer sectionData = data.duplicate();
251030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        sectionData.order(ByteOrder.LITTLE_ENDIAN); // necessary?
252030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        sectionData.position(position);
253030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        sectionData.limit(data.capacity());
254030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        return new Section("section", sectionData);
2552bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2562bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2572bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public Section appendSection(int maxByteCount, String name) {
258030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        if ((maxByteCount & 3) != 0) {
259030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            throw new IllegalStateException("Not four byte aligned!");
260030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
261030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        int limit = nextSectionStart + maxByteCount;
262030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        ByteBuffer sectionData = data.duplicate();
263030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        sectionData.order(ByteOrder.LITTLE_ENDIAN); // necessary?
264030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        sectionData.position(nextSectionStart);
265030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        sectionData.limit(limit);
266030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        Section result = new Section(name, sectionData);
267030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        nextSectionStart = limit;
2682bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return result;
2692bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
271030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public int getLength() {
272030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        return data.capacity();
2732bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2742bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
275030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public int getNextSectionStart() {
276030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        return nextSectionStart;
2772bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2782bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
279030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    /**
280030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * Returns a copy of the the bytes of this dex.
281030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     */
2822bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public byte[] getBytes() {
283030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe
284030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        byte[] result = new byte[data.capacity()];
285030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.position(0);
286030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.get(result);
287030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        return result;
2882bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2892bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2902bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public List<String> strings() {
2912bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return strings;
2922bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2932bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2942bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public List<Integer> typeIds() {
2952bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return typeIds;
2962bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
2972bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
2982bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public List<String> typeNames() {
2992bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return typeNames;
3002bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
3012bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
3022bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public List<ProtoId> protoIds() {
3032bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return protoIds;
3042bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
3052bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
3062bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public List<FieldId> fieldIds() {
3072bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return fieldIds;
3082bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
3092bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
3102bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public List<MethodId> methodIds() {
3112bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return methodIds;
3122bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
3132bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
3142bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public Iterable<ClassDef> classDefs() {
3152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return new Iterable<ClassDef>() {
3162bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            public Iterator<ClassDef> iterator() {
3172bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                if (!tableOfContents.classDefs.exists()) {
3182bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    return Collections.<ClassDef>emptySet().iterator();
3192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                }
3202bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                return new Iterator<ClassDef>() {
3212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    private Dex.Section in = open(tableOfContents.classDefs.off);
3222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    private int count = 0;
3232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
3242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    public boolean hasNext() {
3252bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                        return count < tableOfContents.classDefs.size;
3262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    }
3272bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    public ClassDef next() {
3282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                        if (!hasNext()) {
3292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                            throw new NoSuchElementException();
3302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                        }
3312bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                        count++;
3322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                        return in.readClassDef();
3332bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    }
3342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    public void remove() {
3352bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                        throw new UnsupportedOperationException();
3362bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    }
3372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                };
3382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
3392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        };
3402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
3412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
3422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public TypeList readTypeList(int offset) {
3432bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (offset == 0) {
3442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return TypeList.EMPTY;
3452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
3462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return open(offset).readTypeList();
3472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
3482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
3492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public ClassData readClassData(ClassDef classDef) {
3502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int offset = classDef.getClassDataOffset();
3512bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (offset == 0) {
3522bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            throw new IllegalArgumentException("offset == 0");
3532bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
3542bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return open(offset).readClassData();
3552bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
3562bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
3572bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public Code readCode(ClassData.Method method) {
3582bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        int offset = method.getCodeOffset();
3592bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        if (offset == 0) {
3602bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            throw new IllegalArgumentException("offset == 0");
3612bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
3622bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        return open(offset).readCode();
3632bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
3642bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
365030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    /**
366030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * Returns the signature of all but the first 32 bytes of this dex. The
367030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * first 32 bytes of dex files are not specified to be included in the
368030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * signature.
369030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     */
370030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public byte[] computeSignature() throws IOException {
371030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        MessageDigest digest;
372030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        try {
373030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            digest = MessageDigest.getInstance("SHA-1");
374030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        } catch (NoSuchAlgorithmException e) {
375030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            throw new AssertionError();
376030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
377030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        byte[] buffer = new byte[8192];
378030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe
379030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.limit(data.capacity());
380030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.position(SIGNATURE_OFFSET + SIGNATURE_SIZE);
381030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        while (data.hasRemaining()) {
382030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int count = Math.min(buffer.length, data.remaining());
383030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.get(buffer, 0, count);
384030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            digest.update(buffer, 0, count);
385030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
386030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        return digest.digest();
387030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    }
388030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson
389030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    /**
390030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * Returns the checksum of all but the first 12 bytes of {@code dex}.
391030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     */
392030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public int computeChecksum() throws IOException {
393030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        Adler32 adler32 = new Adler32();
394030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        byte[] buffer = new byte[8192];
395030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe
396030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.limit(data.capacity());
397030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        data.position(CHECKSUM_OFFSET + CHECKSUM_SIZE);
398030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        while (data.hasRemaining()) {
399030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int count = Math.min(buffer.length, data.remaining());
400030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.get(buffer, 0, count);
401030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            adler32.update(buffer, 0, count);
402030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
403030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        return (int) adler32.getValue();
404030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    }
405030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson
406030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    /**
407030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * Generates the signature and checksum of the dex file {@code out} and
408030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     * writes them to the file.
409030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson     */
410030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    public void writeHashes() throws IOException {
411030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        open(SIGNATURE_OFFSET).write(computeSignature());
412030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        open(CHECKSUM_OFFSET).writeInt(computeChecksum());
413030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson    }
414030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson
4152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    public final class Section implements ByteInput, ByteOutput {
4162bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        private final String name;
417030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        private final ByteBuffer data;
4180436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson        private final int initialPosition;
4192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
420030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        private Section(String name, ByteBuffer data) {
4212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            this.name = name;
422030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            this.data = data;
4230436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson            this.initialPosition = data.position();
4242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
4252bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
4262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public int getPosition() {
427030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return data.position();
4282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
4292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
4302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public int readInt() {
431030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return data.getInt();
4322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
4332bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
4342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public short readShort() {
435030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return data.getShort();
4362bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
4372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
4382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public int readUnsignedShort() {
4392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return readShort() & 0xffff;
4402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
4412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
4422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public byte readByte() {
443030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return data.get();
4442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
4452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
4462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public byte[] readByteArray(int length) {
447030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            byte[] result = new byte[length];
448030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.get(result);
4492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return result;
4502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
4512bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
4522bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public short[] readShortArray(int length) {
4532bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            short[] result = new short[length];
4542bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (int i = 0; i < length; i++) {
4552bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                result[i] = readShort();
4562bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
4572bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return result;
4582bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
4592bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
4602bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public int readUleb128() {
4612bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return Leb128.readUnsignedLeb128(this);
4622bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
4632bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
464dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes        public int readUleb128p1() {
465dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes            return Leb128.readUnsignedLeb128(this) - 1;
466dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes        }
467dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes
4682bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public int readSleb128() {
4692bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return Leb128.readSignedLeb128(this);
4702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
4712bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
472dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes        public void writeUleb128p1(int i) {
473dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes            writeUleb128(i + 1);
474dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes        }
475dc5a528c10462726682b8f490772e0677b038c1fElliott Hughes
4762bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public TypeList readTypeList() {
4772bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int size = readInt();
4782bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            short[] types = new short[size];
4792bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (int i = 0; i < size; i++) {
4802bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                types[i] = readShort();
4812bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
4822bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            alignToFourBytes();
4832bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return new TypeList(Dex.this, types);
4842bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
4852bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
4862bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public String readString() {
4872bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int offset = readInt();
488030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int savedPosition = data.position();
489030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int savedLimit = data.limit();
490030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.position(offset);
491030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.limit(data.capacity());
4922bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            try {
4932bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                int expectedLength = readUleb128();
4942bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                String result = Mutf8.decode(this, new char[expectedLength]);
4952bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                if (result.length() != expectedLength) {
4962bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    throw new DexException("Declared length " + expectedLength
4972bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                            + " doesn't match decoded length of " + result.length());
4982bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                }
4992bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                return result;
5002bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            } catch (UTFDataFormatException e) {
5012bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                throw new DexException(e);
5022bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            } finally {
503030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson                data.position(savedPosition);
504030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson                data.limit(savedLimit);
5052bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
5062bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5072bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5082bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public FieldId readFieldId() {
5092bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int declaringClassIndex = readUnsignedShort();
5102bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int typeIndex = readUnsignedShort();
5112bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int nameIndex = readInt();
5122bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return new FieldId(Dex.this, declaringClassIndex, typeIndex, nameIndex);
5132bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5142bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public MethodId readMethodId() {
5162bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int declaringClassIndex = readUnsignedShort();
5172bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int protoIndex = readUnsignedShort();
5182bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int nameIndex = readInt();
5192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return new MethodId(Dex.this, declaringClassIndex, protoIndex, nameIndex);
5202bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public ProtoId readProtoId() {
5232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int shortyIndex = readInt();
5242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int returnTypeIndex = readInt();
5252bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int parametersOffset = readInt();
5262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return new ProtoId(Dex.this, shortyIndex, returnTypeIndex, parametersOffset);
5272bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public ClassDef readClassDef() {
5302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int offset = getPosition();
5312bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int type = readInt();
5322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int accessFlags = readInt();
5332bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int supertype = readInt();
5342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int interfacesOffset = readInt();
5352bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int sourceFileIndex = readInt();
5362bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int annotationsOffset = readInt();
5372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int classDataOffset = readInt();
5382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int staticValuesOffset = readInt();
5392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return new ClassDef(Dex.this, offset, type, accessFlags, supertype,
5402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    interfacesOffset, sourceFileIndex, annotationsOffset, classDataOffset,
5412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                    staticValuesOffset);
5422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
5432bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
5442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        private Code readCode() {
5452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int registersSize = readUnsignedShort();
5462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int insSize = readUnsignedShort();
5472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int outsSize = readUnsignedShort();
5482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int triesSize = readUnsignedShort();
5492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int debugInfoOffset = readInt();
5502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int instructionsSize = readInt();
5512bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            short[] instructions = readShortArray(instructionsSize);
55200a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            Try[] tries;
55300a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            CatchHandler[] catchHandlers;
5542bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            if (triesSize > 0) {
55500a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche              if (instructions.length % 2 == 1) {
55600a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche                  readShort(); // padding
55700a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche              }
55800a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche
55900a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche              /*
56000a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche               * We can't read the tries until we've read the catch handlers.
56100a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche               * Unfortunately they're in the opposite order in the dex file
56200a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche               * so we need to read them out-of-order.
56300a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche               */
56400a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche              Section triesSection = open(data.position());
56500a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche              skip(triesSize * SizeOf.TRY_ITEM);
56600a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche              catchHandlers = readCatchHandlers();
56700a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche              tries = triesSection.readTries(triesSize, catchHandlers);
56800a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          } else {
56900a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche              tries = new Try[0];
57000a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche              catchHandlers = new CatchHandler[0];
57100a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          }
57200a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          return new Code(registersSize, insSize, outsSize, debugInfoOffset, instructions,
57300a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche                  tries, catchHandlers);
57400a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        }
57500a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche
57600a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        private CatchHandler[] readCatchHandlers() {
57700a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          int baseOffset = data.position();
57800a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          int catchHandlersSize = readUleb128();
57900a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          CatchHandler[] result = new CatchHandler[catchHandlersSize];
58000a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          for (int i = 0; i < catchHandlersSize; i++) {
58100a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            int offset = data.position() - baseOffset;
58200a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            result[i] = readCatchHandler(offset);
58300a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          }
58400a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          return result;
58500a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        }
58600a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche
58700a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        private Try[] readTries(int triesSize, CatchHandler[] catchHandlers) {
58800a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          Try[] result = new Try[triesSize];
58900a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          for (int i = 0; i < triesSize; i++) {
59000a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            int startAddress = readInt();
59100a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            int instructionCount = readUnsignedShort();
59200a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            int handlerOffset = readUnsignedShort();
59300a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            int catchHandlerIndex = findCatchHandlerIndex(catchHandlers, handlerOffset);
59400a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            result[i] = new Try(startAddress, instructionCount, catchHandlerIndex);
59500a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          }
59600a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          return result;
59700a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        }
59800a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche
59900a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        private int findCatchHandlerIndex(CatchHandler[] catchHandlers, int offset) {
60000a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          for (int i = 0; i < catchHandlers.length; i++) {
60100a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            CatchHandler catchHandler = catchHandlers[i];
60200a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            if (catchHandler.getOffset() == offset) {
60300a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche              return i;
6042bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
60500a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          }
60600a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          throw new IllegalArgumentException();
60700a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        }
60800a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche
60900a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        private CatchHandler readCatchHandler(int offset) {
61000a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          int size = readSleb128();
61100a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          int handlersCount = Math.abs(size);
61200a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          int[] typeIndexes = new int[handlersCount];
61300a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          int[] addresses = new int[handlersCount];
61400a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          for (int i = 0; i < handlersCount; i++) {
61500a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            typeIndexes[i] = readUleb128();
61600a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche            addresses[i] = readUleb128();
61700a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          }
61800a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          int catchAllAddress = size <= 0 ? readUleb128() : -1;
61900a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          return new CatchHandler(typeIndexes, addresses, catchAllAddress, offset);
6202bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
6212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
6222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        private ClassData readClassData() {
6232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int staticFieldsSize = readUleb128();
6242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int instanceFieldsSize = readUleb128();
6252bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int directMethodsSize = readUleb128();
6262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int virtualMethodsSize = readUleb128();
6272bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ClassData.Field[] staticFields = readFields(staticFieldsSize);
6282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ClassData.Field[] instanceFields = readFields(instanceFieldsSize);
6292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ClassData.Method[] directMethods = readMethods(directMethodsSize);
6302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ClassData.Method[] virtualMethods = readMethods(virtualMethodsSize);
6312bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return new ClassData(staticFields, instanceFields, directMethods, virtualMethods);
6322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
6332bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
6342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        private ClassData.Field[] readFields(int count) {
6352bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ClassData.Field[] result = new ClassData.Field[count];
6362bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int fieldIndex = 0;
6372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (int i = 0; i < count; i++) {
6382bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                fieldIndex += readUleb128(); // field index diff
6392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                int accessFlags = readUleb128();
6402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                result[i] = new ClassData.Field(fieldIndex, accessFlags);
6412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
6422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return result;
6432bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
6442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
6452bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        private ClassData.Method[] readMethods(int count) {
6462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            ClassData.Method[] result = new ClassData.Method[count];
6472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            int methodIndex = 0;
6482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (int i = 0; i < count; i++) {
6492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                methodIndex += readUleb128(); // method index diff
6502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                int accessFlags = readUleb128();
6512bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                int codeOff = readUleb128();
6522bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                result[i] = new ClassData.Method(methodIndex, accessFlags, codeOff);
6532bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
6542bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            return result;
6552bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
6562bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
657030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        /**
658030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson         * Returns a byte array containing the bytes from {@code start} to this
659030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson         * section's current position.
660030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson         */
661030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        private byte[] getBytesFrom(int start) {
662030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int end = data.position();
663030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            byte[] result = new byte[end - start];
664030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.position(start);
665030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.get(result);
666030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return result;
667030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson        }
668030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson
6692bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public Annotation readAnnotation() {
6702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            byte visibility = readByte();
671030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int start = data.position();
6722bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            new EncodedValueReader(this, EncodedValueReader.ENCODED_ANNOTATION).skipValue();
673030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return new Annotation(Dex.this, visibility, new EncodedValue(getBytesFrom(start)));
6742bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
6752bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
6762bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public EncodedValue readEncodedArray() {
677030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            int start = data.position();
6782bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            new EncodedValueReader(this, EncodedValueReader.ENCODED_ARRAY).skipValue();
679030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return new EncodedValue(getBytesFrom(start));
6802bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
6812bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
68200a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche        public void skip(int count) {
68300a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          if (count < 0) {
68400a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche              throw new IllegalArgumentException();
68500a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          }
68600a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche          data.position(data.position() + count);
68700a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche      }
68800a2d1ee4cfee1f33344c3798940bbae22f96187Benoit Lamarche
6892bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        /**
690450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom         * Skips bytes until the position is aligned to a multiple of 4.
6912bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         */
6922bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void alignToFourBytes() {
693450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom            data.position((data.position() + 3) & ~3);
694450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom        }
695450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom
696450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom        /**
697450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom         * Writes 0x00 until the position is aligned to a multiple of 4.
698450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom         */
699450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom        public void alignToFourBytesWithZeroFill() {
700030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            while ((data.position() & 3) != 0) {
701030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson                data.put((byte) 0);
7022bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
7032bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7042bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7052bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void assertFourByteAligned() {
706030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            if ((data.position() & 3) != 0) {
7072bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                throw new IllegalStateException("Not four byte aligned!");
7082bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
7092bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7102bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7112bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void write(byte[] bytes) {
712030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            this.data.put(bytes);
7132bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7142bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7152bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeByte(int b) {
716030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.put((byte) b);
7172bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7182bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7192bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeShort(short i) {
720030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.putShort(i);
7212bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7222bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7232bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeUnsignedShort(int i) {
7242bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            short s = (short) i;
7252bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            if (i != (s & 0xffff)) {
7262bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                throw new IllegalArgumentException("Expected an unsigned short: " + i);
7272bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
7282bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            writeShort(s);
7292bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7302bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7312bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void write(short[] shorts) {
7322bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (short s : shorts) {
7332bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                writeShort(s);
7342bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
7352bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7362bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7372bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeInt(int i) {
738030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            data.putInt(i);
7392bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7402bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7412bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeUleb128(int i) {
7422bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            try {
7432bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                Leb128.writeUnsignedLeb128(this, i);
7442bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            } catch (ArrayIndexOutOfBoundsException e) {
745030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson                throw new DexException("Section limit " + data.limit() + " exceeded by " + name);
7462bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
7472bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7482bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7492bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeSleb128(int i) {
7502bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            try {
7512bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                Leb128.writeSignedLeb128(this, i);
7522bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            } catch (ArrayIndexOutOfBoundsException e) {
753030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson                throw new DexException("Section limit " + data.limit() + " exceeded by " + name);
7542bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
7552bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7562bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7572bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeStringData(String value) {
7582bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            try {
7592bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                int length = value.length();
7602bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                writeUleb128(length);
7612bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                write(Mutf8.encode(value));
7622bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                writeByte(0);
7632bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            } catch (UTFDataFormatException e) {
7642bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                throw new AssertionError();
7652bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
7662bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7672bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7682bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public void writeTypeList(TypeList typeList) {
7692bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            short[] types = typeList.getTypes();
7702bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            writeInt(types.length);
7712bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            for (short type : types) {
7722bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson                writeShort(type);
7732bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson            }
774450a197f09d35a07be12a924d4db1ecd2bee65feBrian Carlstrom            alignToFourBytesWithZeroFill();
7752bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7762bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson
7772bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        /**
7782bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         * Returns the number of bytes remaining in this section.
7792bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson         */
7802bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        public int remaining() {
781030bd62e38ba41b8f464f009382955c51bd72f04Jesse Wilson            return data.remaining();
7822bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson        }
7830436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson
7840436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson        /**
7850436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson         * Returns the number of bytes used by this section.
7860436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson         */
7870436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson        public int used () {
7880436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson            return data.position() - initialPosition;
7890436f436f122e7e74285faf32b8db2259f56ded7Jesse Wilson        }
7902bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson    }
7912bea5ee615b0f4add658d5660bd81c5145a0d05eJesse Wilson}
792