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