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