1*055d4590SKeyi Gui /* 2*055d4590SKeyi Gui * Copyright (C) 2011 The Android Open Source Project 3*055d4590SKeyi Gui * 4*055d4590SKeyi Gui * Licensed under the Apache License, Version 2.0 (the "License"); 5*055d4590SKeyi Gui * you may not use this file except in compliance with the License. 6*055d4590SKeyi Gui * You may obtain a copy of the License at 7*055d4590SKeyi Gui * 8*055d4590SKeyi Gui * http://www.apache.org/licenses/LICENSE-2.0 9*055d4590SKeyi Gui * 10*055d4590SKeyi Gui * Unless required by applicable law or agreed to in writing, software 11*055d4590SKeyi Gui * distributed under the License is distributed on an "AS IS" BASIS, 12*055d4590SKeyi Gui * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*055d4590SKeyi Gui * See the License for the specific language governing permissions and 14*055d4590SKeyi Gui * limitations under the License. 15*055d4590SKeyi Gui */ 16*055d4590SKeyi Gui 17*055d4590SKeyi Gui package com.android.dex; 18*055d4590SKeyi Gui 19*055d4590SKeyi Gui import com.android.dex.Code.CatchHandler; 20*055d4590SKeyi Gui import com.android.dex.Code.Try; 21*055d4590SKeyi Gui import com.android.dex.MethodHandle.MethodHandleType; 22*055d4590SKeyi Gui import com.android.dex.util.ByteInput; 23*055d4590SKeyi Gui import com.android.dex.util.ByteOutput; 24*055d4590SKeyi Gui import com.android.dex.util.FileUtils; 25*055d4590SKeyi Gui import java.io.ByteArrayOutputStream; 26*055d4590SKeyi Gui import java.io.File; 27*055d4590SKeyi Gui import java.io.FileInputStream; 28*055d4590SKeyi Gui import java.io.FileOutputStream; 29*055d4590SKeyi Gui import java.io.IOException; 30*055d4590SKeyi Gui import java.io.InputStream; 31*055d4590SKeyi Gui import java.io.OutputStream; 32*055d4590SKeyi Gui import java.io.UTFDataFormatException; 33*055d4590SKeyi Gui import java.nio.ByteBuffer; 34*055d4590SKeyi Gui import java.nio.ByteOrder; 35*055d4590SKeyi Gui import java.security.MessageDigest; 36*055d4590SKeyi Gui import java.security.NoSuchAlgorithmException; 37*055d4590SKeyi Gui import java.util.AbstractList; 38*055d4590SKeyi Gui import java.util.Collections; 39*055d4590SKeyi Gui import java.util.Iterator; 40*055d4590SKeyi Gui import java.util.List; 41*055d4590SKeyi Gui import java.util.NoSuchElementException; 42*055d4590SKeyi Gui import java.util.RandomAccess; 43*055d4590SKeyi Gui import java.util.zip.Adler32; 44*055d4590SKeyi Gui import java.util.zip.ZipEntry; 45*055d4590SKeyi Gui import java.util.zip.ZipFile; 46*055d4590SKeyi Gui 47*055d4590SKeyi Gui /** 48*055d4590SKeyi Gui * The bytes of a dex file in memory for reading and writing. All int offsets 49*055d4590SKeyi Gui * are unsigned. 50*055d4590SKeyi Gui */ 51*055d4590SKeyi Gui public final class Dex { 52*055d4590SKeyi Gui private static final int CHECKSUM_OFFSET = 8; 53*055d4590SKeyi Gui private static final int CHECKSUM_SIZE = 4; 54*055d4590SKeyi Gui private static final int SIGNATURE_OFFSET = CHECKSUM_OFFSET + CHECKSUM_SIZE; 55*055d4590SKeyi Gui private static final int SIGNATURE_SIZE = 20; 56*055d4590SKeyi Gui // Provided as a convenience to avoid a memory allocation to benefit Dalvik. 57*055d4590SKeyi Gui // Note: libcore.util.EmptyArray cannot be accessed when this code isn't run on Dalvik. 58*055d4590SKeyi Gui static final short[] EMPTY_SHORT_ARRAY = new short[0]; 59*055d4590SKeyi Gui 60*055d4590SKeyi Gui private ByteBuffer data; 61*055d4590SKeyi Gui private final TableOfContents tableOfContents = new TableOfContents(); 62*055d4590SKeyi Gui private int nextSectionStart = 0; 63*055d4590SKeyi Gui private final StringTable strings = new StringTable(); 64*055d4590SKeyi Gui private final TypeIndexToDescriptorIndexTable typeIds = new TypeIndexToDescriptorIndexTable(); 65*055d4590SKeyi Gui private final TypeIndexToDescriptorTable typeNames = new TypeIndexToDescriptorTable(); 66*055d4590SKeyi Gui private final ProtoIdTable protoIds = new ProtoIdTable(); 67*055d4590SKeyi Gui private final FieldIdTable fieldIds = new FieldIdTable(); 68*055d4590SKeyi Gui private final MethodIdTable methodIds = new MethodIdTable(); 69*055d4590SKeyi Gui 70*055d4590SKeyi Gui /** 71*055d4590SKeyi Gui * Creates a new dex that reads from {@code data}. It is an error to modify 72*055d4590SKeyi Gui * {@code data} after using it to create a dex buffer. 73*055d4590SKeyi Gui */ Dex(byte[] data)74*055d4590SKeyi Gui public Dex(byte[] data) throws IOException { 75*055d4590SKeyi Gui this(ByteBuffer.wrap(data)); 76*055d4590SKeyi Gui } 77*055d4590SKeyi Gui Dex(ByteBuffer data)78*055d4590SKeyi Gui private Dex(ByteBuffer data) throws IOException { 79*055d4590SKeyi Gui this.data = data; 80*055d4590SKeyi Gui this.data.order(ByteOrder.LITTLE_ENDIAN); 81*055d4590SKeyi Gui this.tableOfContents.readFrom(this); 82*055d4590SKeyi Gui } 83*055d4590SKeyi Gui 84*055d4590SKeyi Gui /** 85*055d4590SKeyi Gui * Creates a new empty dex of the specified size. 86*055d4590SKeyi Gui */ Dex(int byteCount)87*055d4590SKeyi Gui public Dex(int byteCount) throws IOException { 88*055d4590SKeyi Gui this.data = ByteBuffer.wrap(new byte[byteCount]); 89*055d4590SKeyi Gui this.data.order(ByteOrder.LITTLE_ENDIAN); 90*055d4590SKeyi Gui } 91*055d4590SKeyi Gui 92*055d4590SKeyi Gui /** 93*055d4590SKeyi Gui * Creates a new dex buffer of the dex in {@code in}, and closes {@code in}. 94*055d4590SKeyi Gui */ Dex(InputStream in)95*055d4590SKeyi Gui public Dex(InputStream in) throws IOException { 96*055d4590SKeyi Gui try { 97*055d4590SKeyi Gui loadFrom(in); 98*055d4590SKeyi Gui } finally { 99*055d4590SKeyi Gui in.close(); 100*055d4590SKeyi Gui } 101*055d4590SKeyi Gui } 102*055d4590SKeyi Gui 103*055d4590SKeyi Gui /** 104*055d4590SKeyi Gui * Creates a new dex buffer from the dex file {@code file}. 105*055d4590SKeyi Gui */ Dex(File file)106*055d4590SKeyi Gui public Dex(File file) throws IOException { 107*055d4590SKeyi Gui if (FileUtils.hasArchiveSuffix(file.getName())) { 108*055d4590SKeyi Gui ZipFile zipFile = new ZipFile(file); 109*055d4590SKeyi Gui ZipEntry entry = zipFile.getEntry(DexFormat.DEX_IN_JAR_NAME); 110*055d4590SKeyi Gui if (entry != null) { 111*055d4590SKeyi Gui try (InputStream inputStream = zipFile.getInputStream(entry)) { 112*055d4590SKeyi Gui loadFrom(inputStream); 113*055d4590SKeyi Gui } 114*055d4590SKeyi Gui zipFile.close(); 115*055d4590SKeyi Gui } else { 116*055d4590SKeyi Gui throw new DexException("Expected " + DexFormat.DEX_IN_JAR_NAME + " in " + file); 117*055d4590SKeyi Gui } 118*055d4590SKeyi Gui } else if (file.getName().endsWith(".dex")) { 119*055d4590SKeyi Gui try (InputStream inputStream = new FileInputStream(file)) { 120*055d4590SKeyi Gui loadFrom(inputStream); 121*055d4590SKeyi Gui } 122*055d4590SKeyi Gui } else { 123*055d4590SKeyi Gui throw new DexException("unknown output extension: " + file); 124*055d4590SKeyi Gui } 125*055d4590SKeyi Gui } 126*055d4590SKeyi Gui 127*055d4590SKeyi Gui /** 128*055d4590SKeyi Gui * It is the caller's responsibility to close {@code in}. 129*055d4590SKeyi Gui */ loadFrom(InputStream in)130*055d4590SKeyi Gui private void loadFrom(InputStream in) throws IOException { 131*055d4590SKeyi Gui ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 132*055d4590SKeyi Gui byte[] buffer = new byte[8192]; 133*055d4590SKeyi Gui 134*055d4590SKeyi Gui int count; 135*055d4590SKeyi Gui while ((count = in.read(buffer)) != -1) { 136*055d4590SKeyi Gui bytesOut.write(buffer, 0, count); 137*055d4590SKeyi Gui } 138*055d4590SKeyi Gui 139*055d4590SKeyi Gui this.data = ByteBuffer.wrap(bytesOut.toByteArray()); 140*055d4590SKeyi Gui this.data.order(ByteOrder.LITTLE_ENDIAN); 141*055d4590SKeyi Gui this.tableOfContents.readFrom(this); 142*055d4590SKeyi Gui } 143*055d4590SKeyi Gui checkBounds(int index, int length)144*055d4590SKeyi Gui private static void checkBounds(int index, int length) { 145*055d4590SKeyi Gui if (index < 0 || index >= length) { 146*055d4590SKeyi Gui throw new IndexOutOfBoundsException("index:" + index + ", length=" + length); 147*055d4590SKeyi Gui } 148*055d4590SKeyi Gui } 149*055d4590SKeyi Gui writeTo(OutputStream out)150*055d4590SKeyi Gui public void writeTo(OutputStream out) throws IOException { 151*055d4590SKeyi Gui byte[] buffer = new byte[8192]; 152*055d4590SKeyi Gui ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe 153*055d4590SKeyi Gui data.clear(); 154*055d4590SKeyi Gui while (data.hasRemaining()) { 155*055d4590SKeyi Gui int count = Math.min(buffer.length, data.remaining()); 156*055d4590SKeyi Gui data.get(buffer, 0, count); 157*055d4590SKeyi Gui out.write(buffer, 0, count); 158*055d4590SKeyi Gui } 159*055d4590SKeyi Gui } 160*055d4590SKeyi Gui writeTo(File dexOut)161*055d4590SKeyi Gui public void writeTo(File dexOut) throws IOException { 162*055d4590SKeyi Gui try (OutputStream out = new FileOutputStream(dexOut)) { 163*055d4590SKeyi Gui writeTo(out); 164*055d4590SKeyi Gui } 165*055d4590SKeyi Gui } 166*055d4590SKeyi Gui getTableOfContents()167*055d4590SKeyi Gui public TableOfContents getTableOfContents() { 168*055d4590SKeyi Gui return tableOfContents; 169*055d4590SKeyi Gui } 170*055d4590SKeyi Gui open(int position)171*055d4590SKeyi Gui public Section open(int position) { 172*055d4590SKeyi Gui if (position < 0 || position >= data.capacity()) { 173*055d4590SKeyi Gui throw new IllegalArgumentException("position=" + position 174*055d4590SKeyi Gui + " length=" + data.capacity()); 175*055d4590SKeyi Gui } 176*055d4590SKeyi Gui ByteBuffer sectionData = data.duplicate(); 177*055d4590SKeyi Gui sectionData.order(ByteOrder.LITTLE_ENDIAN); // necessary? 178*055d4590SKeyi Gui sectionData.position(position); 179*055d4590SKeyi Gui sectionData.limit(data.capacity()); 180*055d4590SKeyi Gui return new Section("section", sectionData); 181*055d4590SKeyi Gui } 182*055d4590SKeyi Gui appendSection(int maxByteCount, String name)183*055d4590SKeyi Gui public Section appendSection(int maxByteCount, String name) { 184*055d4590SKeyi Gui if ((maxByteCount & 3) != 0) { 185*055d4590SKeyi Gui throw new IllegalStateException("Not four byte aligned!"); 186*055d4590SKeyi Gui } 187*055d4590SKeyi Gui int limit = nextSectionStart + maxByteCount; 188*055d4590SKeyi Gui ByteBuffer sectionData = data.duplicate(); 189*055d4590SKeyi Gui sectionData.order(ByteOrder.LITTLE_ENDIAN); // necessary? 190*055d4590SKeyi Gui sectionData.position(nextSectionStart); 191*055d4590SKeyi Gui sectionData.limit(limit); 192*055d4590SKeyi Gui Section result = new Section(name, sectionData); 193*055d4590SKeyi Gui nextSectionStart = limit; 194*055d4590SKeyi Gui return result; 195*055d4590SKeyi Gui } 196*055d4590SKeyi Gui getLength()197*055d4590SKeyi Gui public int getLength() { 198*055d4590SKeyi Gui return data.capacity(); 199*055d4590SKeyi Gui } 200*055d4590SKeyi Gui getNextSectionStart()201*055d4590SKeyi Gui public int getNextSectionStart() { 202*055d4590SKeyi Gui return nextSectionStart; 203*055d4590SKeyi Gui } 204*055d4590SKeyi Gui 205*055d4590SKeyi Gui /** 206*055d4590SKeyi Gui * Returns a copy of the the bytes of this dex. 207*055d4590SKeyi Gui */ getBytes()208*055d4590SKeyi Gui public byte[] getBytes() { 209*055d4590SKeyi Gui ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe 210*055d4590SKeyi Gui byte[] result = new byte[data.capacity()]; 211*055d4590SKeyi Gui data.position(0); 212*055d4590SKeyi Gui data.get(result); 213*055d4590SKeyi Gui return result; 214*055d4590SKeyi Gui } 215*055d4590SKeyi Gui strings()216*055d4590SKeyi Gui public List<String> strings() { 217*055d4590SKeyi Gui return strings; 218*055d4590SKeyi Gui } 219*055d4590SKeyi Gui typeIds()220*055d4590SKeyi Gui public List<Integer> typeIds() { 221*055d4590SKeyi Gui return typeIds; 222*055d4590SKeyi Gui } 223*055d4590SKeyi Gui typeNames()224*055d4590SKeyi Gui public List<String> typeNames() { 225*055d4590SKeyi Gui return typeNames; 226*055d4590SKeyi Gui } 227*055d4590SKeyi Gui protoIds()228*055d4590SKeyi Gui public List<ProtoId> protoIds() { 229*055d4590SKeyi Gui return protoIds; 230*055d4590SKeyi Gui } 231*055d4590SKeyi Gui fieldIds()232*055d4590SKeyi Gui public List<FieldId> fieldIds() { 233*055d4590SKeyi Gui return fieldIds; 234*055d4590SKeyi Gui } 235*055d4590SKeyi Gui methodIds()236*055d4590SKeyi Gui public List<MethodId> methodIds() { 237*055d4590SKeyi Gui return methodIds; 238*055d4590SKeyi Gui } 239*055d4590SKeyi Gui classDefs()240*055d4590SKeyi Gui public Iterable<ClassDef> classDefs() { 241*055d4590SKeyi Gui return new ClassDefIterable(); 242*055d4590SKeyi Gui } 243*055d4590SKeyi Gui readTypeList(int offset)244*055d4590SKeyi Gui public TypeList readTypeList(int offset) { 245*055d4590SKeyi Gui if (offset == 0) { 246*055d4590SKeyi Gui return TypeList.EMPTY; 247*055d4590SKeyi Gui } 248*055d4590SKeyi Gui return open(offset).readTypeList(); 249*055d4590SKeyi Gui } 250*055d4590SKeyi Gui readClassData(ClassDef classDef)251*055d4590SKeyi Gui public ClassData readClassData(ClassDef classDef) { 252*055d4590SKeyi Gui int offset = classDef.getClassDataOffset(); 253*055d4590SKeyi Gui if (offset == 0) { 254*055d4590SKeyi Gui throw new IllegalArgumentException("offset == 0"); 255*055d4590SKeyi Gui } 256*055d4590SKeyi Gui return open(offset).readClassData(); 257*055d4590SKeyi Gui } 258*055d4590SKeyi Gui readCode(ClassData.Method method)259*055d4590SKeyi Gui public Code readCode(ClassData.Method method) { 260*055d4590SKeyi Gui int offset = method.getCodeOffset(); 261*055d4590SKeyi Gui if (offset == 0) { 262*055d4590SKeyi Gui throw new IllegalArgumentException("offset == 0"); 263*055d4590SKeyi Gui } 264*055d4590SKeyi Gui return open(offset).readCode(); 265*055d4590SKeyi Gui } 266*055d4590SKeyi Gui 267*055d4590SKeyi Gui /** 268*055d4590SKeyi Gui * Returns the signature of all but the first 32 bytes of this dex. The 269*055d4590SKeyi Gui * first 32 bytes of dex files are not specified to be included in the 270*055d4590SKeyi Gui * signature. 271*055d4590SKeyi Gui */ computeSignature()272*055d4590SKeyi Gui public byte[] computeSignature() throws IOException { 273*055d4590SKeyi Gui MessageDigest digest; 274*055d4590SKeyi Gui try { 275*055d4590SKeyi Gui digest = MessageDigest.getInstance("SHA-1"); 276*055d4590SKeyi Gui } catch (NoSuchAlgorithmException e) { 277*055d4590SKeyi Gui throw new AssertionError(); 278*055d4590SKeyi Gui } 279*055d4590SKeyi Gui byte[] buffer = new byte[8192]; 280*055d4590SKeyi Gui ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe 281*055d4590SKeyi Gui data.limit(data.capacity()); 282*055d4590SKeyi Gui data.position(SIGNATURE_OFFSET + SIGNATURE_SIZE); 283*055d4590SKeyi Gui while (data.hasRemaining()) { 284*055d4590SKeyi Gui int count = Math.min(buffer.length, data.remaining()); 285*055d4590SKeyi Gui data.get(buffer, 0, count); 286*055d4590SKeyi Gui digest.update(buffer, 0, count); 287*055d4590SKeyi Gui } 288*055d4590SKeyi Gui return digest.digest(); 289*055d4590SKeyi Gui } 290*055d4590SKeyi Gui 291*055d4590SKeyi Gui /** 292*055d4590SKeyi Gui * Returns the checksum of all but the first 12 bytes of {@code dex}. 293*055d4590SKeyi Gui */ computeChecksum()294*055d4590SKeyi Gui public int computeChecksum() throws IOException { 295*055d4590SKeyi Gui Adler32 adler32 = new Adler32(); 296*055d4590SKeyi Gui byte[] buffer = new byte[8192]; 297*055d4590SKeyi Gui ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe 298*055d4590SKeyi Gui data.limit(data.capacity()); 299*055d4590SKeyi Gui data.position(CHECKSUM_OFFSET + CHECKSUM_SIZE); 300*055d4590SKeyi Gui while (data.hasRemaining()) { 301*055d4590SKeyi Gui int count = Math.min(buffer.length, data.remaining()); 302*055d4590SKeyi Gui data.get(buffer, 0, count); 303*055d4590SKeyi Gui adler32.update(buffer, 0, count); 304*055d4590SKeyi Gui } 305*055d4590SKeyi Gui return (int) adler32.getValue(); 306*055d4590SKeyi Gui } 307*055d4590SKeyi Gui 308*055d4590SKeyi Gui /** 309*055d4590SKeyi Gui * Generates the signature and checksum of the dex file {@code out} and 310*055d4590SKeyi Gui * writes them to the file. 311*055d4590SKeyi Gui */ writeHashes()312*055d4590SKeyi Gui public void writeHashes() throws IOException { 313*055d4590SKeyi Gui open(SIGNATURE_OFFSET).write(computeSignature()); 314*055d4590SKeyi Gui open(CHECKSUM_OFFSET).writeInt(computeChecksum()); 315*055d4590SKeyi Gui } 316*055d4590SKeyi Gui 317*055d4590SKeyi Gui /** 318*055d4590SKeyi Gui * Look up a descriptor index from a type index. Cheaper than: 319*055d4590SKeyi Gui * {@code open(tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM)).readInt();} 320*055d4590SKeyi Gui */ descriptorIndexFromTypeIndex(int typeIndex)321*055d4590SKeyi Gui public int descriptorIndexFromTypeIndex(int typeIndex) { 322*055d4590SKeyi Gui checkBounds(typeIndex, tableOfContents.typeIds.size); 323*055d4590SKeyi Gui int position = tableOfContents.typeIds.off + (SizeOf.TYPE_ID_ITEM * typeIndex); 324*055d4590SKeyi Gui return data.getInt(position); 325*055d4590SKeyi Gui } 326*055d4590SKeyi Gui 327*055d4590SKeyi Gui 328*055d4590SKeyi Gui public final class Section implements ByteInput, ByteOutput { 329*055d4590SKeyi Gui private final String name; 330*055d4590SKeyi Gui private final ByteBuffer data; 331*055d4590SKeyi Gui private final int initialPosition; 332*055d4590SKeyi Gui Section(String name, ByteBuffer data)333*055d4590SKeyi Gui private Section(String name, ByteBuffer data) { 334*055d4590SKeyi Gui this.name = name; 335*055d4590SKeyi Gui this.data = data; 336*055d4590SKeyi Gui this.initialPosition = data.position(); 337*055d4590SKeyi Gui } 338*055d4590SKeyi Gui getPosition()339*055d4590SKeyi Gui public int getPosition() { 340*055d4590SKeyi Gui return data.position(); 341*055d4590SKeyi Gui } 342*055d4590SKeyi Gui readInt()343*055d4590SKeyi Gui public int readInt() { 344*055d4590SKeyi Gui return data.getInt(); 345*055d4590SKeyi Gui } 346*055d4590SKeyi Gui readShort()347*055d4590SKeyi Gui public short readShort() { 348*055d4590SKeyi Gui return data.getShort(); 349*055d4590SKeyi Gui } 350*055d4590SKeyi Gui readUnsignedShort()351*055d4590SKeyi Gui public int readUnsignedShort() { 352*055d4590SKeyi Gui return readShort() & 0xffff; 353*055d4590SKeyi Gui } 354*055d4590SKeyi Gui 355*055d4590SKeyi Gui @Override readByte()356*055d4590SKeyi Gui public byte readByte() { 357*055d4590SKeyi Gui return data.get(); 358*055d4590SKeyi Gui } 359*055d4590SKeyi Gui readByteArray(int length)360*055d4590SKeyi Gui public byte[] readByteArray(int length) { 361*055d4590SKeyi Gui byte[] result = new byte[length]; 362*055d4590SKeyi Gui data.get(result); 363*055d4590SKeyi Gui return result; 364*055d4590SKeyi Gui } 365*055d4590SKeyi Gui readShortArray(int length)366*055d4590SKeyi Gui public short[] readShortArray(int length) { 367*055d4590SKeyi Gui if (length == 0) { 368*055d4590SKeyi Gui return EMPTY_SHORT_ARRAY; 369*055d4590SKeyi Gui } 370*055d4590SKeyi Gui short[] result = new short[length]; 371*055d4590SKeyi Gui for (int i = 0; i < length; i++) { 372*055d4590SKeyi Gui result[i] = readShort(); 373*055d4590SKeyi Gui } 374*055d4590SKeyi Gui return result; 375*055d4590SKeyi Gui } 376*055d4590SKeyi Gui readUleb128()377*055d4590SKeyi Gui public int readUleb128() { 378*055d4590SKeyi Gui return Leb128.readUnsignedLeb128(this); 379*055d4590SKeyi Gui } 380*055d4590SKeyi Gui readUleb128p1()381*055d4590SKeyi Gui public int readUleb128p1() { 382*055d4590SKeyi Gui return Leb128.readUnsignedLeb128(this) - 1; 383*055d4590SKeyi Gui } 384*055d4590SKeyi Gui readSleb128()385*055d4590SKeyi Gui public int readSleb128() { 386*055d4590SKeyi Gui return Leb128.readSignedLeb128(this); 387*055d4590SKeyi Gui } 388*055d4590SKeyi Gui writeUleb128p1(int i)389*055d4590SKeyi Gui public void writeUleb128p1(int i) { 390*055d4590SKeyi Gui writeUleb128(i + 1); 391*055d4590SKeyi Gui } 392*055d4590SKeyi Gui readTypeList()393*055d4590SKeyi Gui public TypeList readTypeList() { 394*055d4590SKeyi Gui int size = readInt(); 395*055d4590SKeyi Gui short[] types = readShortArray(size); 396*055d4590SKeyi Gui alignToFourBytes(); 397*055d4590SKeyi Gui return new TypeList(Dex.this, types); 398*055d4590SKeyi Gui } 399*055d4590SKeyi Gui readString()400*055d4590SKeyi Gui public String readString() { 401*055d4590SKeyi Gui int offset = readInt(); 402*055d4590SKeyi Gui int savedPosition = data.position(); 403*055d4590SKeyi Gui int savedLimit = data.limit(); 404*055d4590SKeyi Gui data.position(offset); 405*055d4590SKeyi Gui data.limit(data.capacity()); 406*055d4590SKeyi Gui try { 407*055d4590SKeyi Gui int expectedLength = readUleb128(); 408*055d4590SKeyi Gui String result = Mutf8.decode(this, new char[expectedLength]); 409*055d4590SKeyi Gui if (result.length() != expectedLength) { 410*055d4590SKeyi Gui throw new DexException("Declared length " + expectedLength 411*055d4590SKeyi Gui + " doesn't match decoded length of " + result.length()); 412*055d4590SKeyi Gui } 413*055d4590SKeyi Gui return result; 414*055d4590SKeyi Gui } catch (UTFDataFormatException e) { 415*055d4590SKeyi Gui throw new DexException(e); 416*055d4590SKeyi Gui } finally { 417*055d4590SKeyi Gui data.position(savedPosition); 418*055d4590SKeyi Gui data.limit(savedLimit); 419*055d4590SKeyi Gui } 420*055d4590SKeyi Gui } 421*055d4590SKeyi Gui readFieldId()422*055d4590SKeyi Gui public FieldId readFieldId() { 423*055d4590SKeyi Gui int declaringClassIndex = readUnsignedShort(); 424*055d4590SKeyi Gui int typeIndex = readUnsignedShort(); 425*055d4590SKeyi Gui int nameIndex = readInt(); 426*055d4590SKeyi Gui return new FieldId(Dex.this, declaringClassIndex, typeIndex, nameIndex); 427*055d4590SKeyi Gui } 428*055d4590SKeyi Gui readMethodId()429*055d4590SKeyi Gui public MethodId readMethodId() { 430*055d4590SKeyi Gui int declaringClassIndex = readUnsignedShort(); 431*055d4590SKeyi Gui int protoIndex = readUnsignedShort(); 432*055d4590SKeyi Gui int nameIndex = readInt(); 433*055d4590SKeyi Gui return new MethodId(Dex.this, declaringClassIndex, protoIndex, nameIndex); 434*055d4590SKeyi Gui } 435*055d4590SKeyi Gui readProtoId()436*055d4590SKeyi Gui public ProtoId readProtoId() { 437*055d4590SKeyi Gui int shortyIndex = readInt(); 438*055d4590SKeyi Gui int returnTypeIndex = readInt(); 439*055d4590SKeyi Gui int parametersOffset = readInt(); 440*055d4590SKeyi Gui return new ProtoId(Dex.this, shortyIndex, returnTypeIndex, parametersOffset); 441*055d4590SKeyi Gui } 442*055d4590SKeyi Gui readCallSiteId()443*055d4590SKeyi Gui public CallSiteId readCallSiteId() { 444*055d4590SKeyi Gui int offset = readInt(); 445*055d4590SKeyi Gui return new CallSiteId(Dex.this, offset); 446*055d4590SKeyi Gui } 447*055d4590SKeyi Gui readMethodHandle()448*055d4590SKeyi Gui public MethodHandle readMethodHandle() { 449*055d4590SKeyi Gui MethodHandleType methodHandleType = MethodHandleType.fromValue(readUnsignedShort()); 450*055d4590SKeyi Gui int unused1 = readUnsignedShort(); 451*055d4590SKeyi Gui int fieldOrMethodId = readUnsignedShort(); 452*055d4590SKeyi Gui int unused2 = readUnsignedShort(); 453*055d4590SKeyi Gui return new MethodHandle(Dex.this, methodHandleType, unused1, fieldOrMethodId, unused2); 454*055d4590SKeyi Gui } 455*055d4590SKeyi Gui readClassDef()456*055d4590SKeyi Gui public ClassDef readClassDef() { 457*055d4590SKeyi Gui int offset = getPosition(); 458*055d4590SKeyi Gui int type = readInt(); 459*055d4590SKeyi Gui int accessFlags = readInt(); 460*055d4590SKeyi Gui int supertype = readInt(); 461*055d4590SKeyi Gui int interfacesOffset = readInt(); 462*055d4590SKeyi Gui int sourceFileIndex = readInt(); 463*055d4590SKeyi Gui int annotationsOffset = readInt(); 464*055d4590SKeyi Gui int classDataOffset = readInt(); 465*055d4590SKeyi Gui int staticValuesOffset = readInt(); 466*055d4590SKeyi Gui return new ClassDef(Dex.this, offset, type, accessFlags, supertype, 467*055d4590SKeyi Gui interfacesOffset, sourceFileIndex, annotationsOffset, classDataOffset, 468*055d4590SKeyi Gui staticValuesOffset); 469*055d4590SKeyi Gui } 470*055d4590SKeyi Gui readCode()471*055d4590SKeyi Gui private Code readCode() { 472*055d4590SKeyi Gui int registersSize = readUnsignedShort(); 473*055d4590SKeyi Gui int insSize = readUnsignedShort(); 474*055d4590SKeyi Gui int outsSize = readUnsignedShort(); 475*055d4590SKeyi Gui int triesSize = readUnsignedShort(); 476*055d4590SKeyi Gui int debugInfoOffset = readInt(); 477*055d4590SKeyi Gui int instructionsSize = readInt(); 478*055d4590SKeyi Gui short[] instructions = readShortArray(instructionsSize); 479*055d4590SKeyi Gui Try[] tries; 480*055d4590SKeyi Gui CatchHandler[] catchHandlers; 481*055d4590SKeyi Gui if (triesSize > 0) { 482*055d4590SKeyi Gui if (instructions.length % 2 == 1) { 483*055d4590SKeyi Gui readShort(); // padding 484*055d4590SKeyi Gui } 485*055d4590SKeyi Gui 486*055d4590SKeyi Gui /* 487*055d4590SKeyi Gui * We can't read the tries until we've read the catch handlers. 488*055d4590SKeyi Gui * Unfortunately they're in the opposite order in the dex file 489*055d4590SKeyi Gui * so we need to read them out-of-order. 490*055d4590SKeyi Gui */ 491*055d4590SKeyi Gui Section triesSection = open(data.position()); 492*055d4590SKeyi Gui skip(triesSize * SizeOf.TRY_ITEM); 493*055d4590SKeyi Gui catchHandlers = readCatchHandlers(); 494*055d4590SKeyi Gui tries = triesSection.readTries(triesSize, catchHandlers); 495*055d4590SKeyi Gui } else { 496*055d4590SKeyi Gui tries = new Try[0]; 497*055d4590SKeyi Gui catchHandlers = new CatchHandler[0]; 498*055d4590SKeyi Gui } 499*055d4590SKeyi Gui return new Code(registersSize, insSize, outsSize, debugInfoOffset, instructions, 500*055d4590SKeyi Gui tries, catchHandlers); 501*055d4590SKeyi Gui } 502*055d4590SKeyi Gui readCatchHandlers()503*055d4590SKeyi Gui private CatchHandler[] readCatchHandlers() { 504*055d4590SKeyi Gui int baseOffset = data.position(); 505*055d4590SKeyi Gui int catchHandlersSize = readUleb128(); 506*055d4590SKeyi Gui CatchHandler[] result = new CatchHandler[catchHandlersSize]; 507*055d4590SKeyi Gui for (int i = 0; i < catchHandlersSize; i++) { 508*055d4590SKeyi Gui int offset = data.position() - baseOffset; 509*055d4590SKeyi Gui result[i] = readCatchHandler(offset); 510*055d4590SKeyi Gui } 511*055d4590SKeyi Gui return result; 512*055d4590SKeyi Gui } 513*055d4590SKeyi Gui readTries(int triesSize, CatchHandler[] catchHandlers)514*055d4590SKeyi Gui private Try[] readTries(int triesSize, CatchHandler[] catchHandlers) { 515*055d4590SKeyi Gui Try[] result = new Try[triesSize]; 516*055d4590SKeyi Gui for (int i = 0; i < triesSize; i++) { 517*055d4590SKeyi Gui int startAddress = readInt(); 518*055d4590SKeyi Gui int instructionCount = readUnsignedShort(); 519*055d4590SKeyi Gui int handlerOffset = readUnsignedShort(); 520*055d4590SKeyi Gui int catchHandlerIndex = findCatchHandlerIndex(catchHandlers, handlerOffset); 521*055d4590SKeyi Gui result[i] = new Try(startAddress, instructionCount, catchHandlerIndex); 522*055d4590SKeyi Gui } 523*055d4590SKeyi Gui return result; 524*055d4590SKeyi Gui } 525*055d4590SKeyi Gui findCatchHandlerIndex(CatchHandler[] catchHandlers, int offset)526*055d4590SKeyi Gui private int findCatchHandlerIndex(CatchHandler[] catchHandlers, int offset) { 527*055d4590SKeyi Gui for (int i = 0; i < catchHandlers.length; i++) { 528*055d4590SKeyi Gui CatchHandler catchHandler = catchHandlers[i]; 529*055d4590SKeyi Gui if (catchHandler.getOffset() == offset) { 530*055d4590SKeyi Gui return i; 531*055d4590SKeyi Gui } 532*055d4590SKeyi Gui } 533*055d4590SKeyi Gui throw new IllegalArgumentException(); 534*055d4590SKeyi Gui } 535*055d4590SKeyi Gui readCatchHandler(int offset)536*055d4590SKeyi Gui private CatchHandler readCatchHandler(int offset) { 537*055d4590SKeyi Gui int size = readSleb128(); 538*055d4590SKeyi Gui int handlersCount = Math.abs(size); 539*055d4590SKeyi Gui int[] typeIndexes = new int[handlersCount]; 540*055d4590SKeyi Gui int[] addresses = new int[handlersCount]; 541*055d4590SKeyi Gui for (int i = 0; i < handlersCount; i++) { 542*055d4590SKeyi Gui typeIndexes[i] = readUleb128(); 543*055d4590SKeyi Gui addresses[i] = readUleb128(); 544*055d4590SKeyi Gui } 545*055d4590SKeyi Gui int catchAllAddress = size <= 0 ? readUleb128() : -1; 546*055d4590SKeyi Gui return new CatchHandler(typeIndexes, addresses, catchAllAddress, offset); 547*055d4590SKeyi Gui } 548*055d4590SKeyi Gui readClassData()549*055d4590SKeyi Gui private ClassData readClassData() { 550*055d4590SKeyi Gui int staticFieldsSize = readUleb128(); 551*055d4590SKeyi Gui int instanceFieldsSize = readUleb128(); 552*055d4590SKeyi Gui int directMethodsSize = readUleb128(); 553*055d4590SKeyi Gui int virtualMethodsSize = readUleb128(); 554*055d4590SKeyi Gui ClassData.Field[] staticFields = readFields(staticFieldsSize); 555*055d4590SKeyi Gui ClassData.Field[] instanceFields = readFields(instanceFieldsSize); 556*055d4590SKeyi Gui ClassData.Method[] directMethods = readMethods(directMethodsSize); 557*055d4590SKeyi Gui ClassData.Method[] virtualMethods = readMethods(virtualMethodsSize); 558*055d4590SKeyi Gui return new ClassData(staticFields, instanceFields, directMethods, virtualMethods); 559*055d4590SKeyi Gui } 560*055d4590SKeyi Gui readFields(int count)561*055d4590SKeyi Gui private ClassData.Field[] readFields(int count) { 562*055d4590SKeyi Gui ClassData.Field[] result = new ClassData.Field[count]; 563*055d4590SKeyi Gui int fieldIndex = 0; 564*055d4590SKeyi Gui for (int i = 0; i < count; i++) { 565*055d4590SKeyi Gui fieldIndex += readUleb128(); // field index diff 566*055d4590SKeyi Gui int accessFlags = readUleb128(); 567*055d4590SKeyi Gui result[i] = new ClassData.Field(fieldIndex, accessFlags); 568*055d4590SKeyi Gui } 569*055d4590SKeyi Gui return result; 570*055d4590SKeyi Gui } 571*055d4590SKeyi Gui readMethods(int count)572*055d4590SKeyi Gui private ClassData.Method[] readMethods(int count) { 573*055d4590SKeyi Gui ClassData.Method[] result = new ClassData.Method[count]; 574*055d4590SKeyi Gui int methodIndex = 0; 575*055d4590SKeyi Gui for (int i = 0; i < count; i++) { 576*055d4590SKeyi Gui methodIndex += readUleb128(); // method index diff 577*055d4590SKeyi Gui int accessFlags = readUleb128(); 578*055d4590SKeyi Gui int codeOff = readUleb128(); 579*055d4590SKeyi Gui result[i] = new ClassData.Method(methodIndex, accessFlags, codeOff); 580*055d4590SKeyi Gui } 581*055d4590SKeyi Gui return result; 582*055d4590SKeyi Gui } 583*055d4590SKeyi Gui 584*055d4590SKeyi Gui /** 585*055d4590SKeyi Gui * Returns a byte array containing the bytes from {@code start} to this 586*055d4590SKeyi Gui * section's current position. 587*055d4590SKeyi Gui */ getBytesFrom(int start)588*055d4590SKeyi Gui private byte[] getBytesFrom(int start) { 589*055d4590SKeyi Gui int end = data.position(); 590*055d4590SKeyi Gui byte[] result = new byte[end - start]; 591*055d4590SKeyi Gui data.position(start); 592*055d4590SKeyi Gui data.get(result); 593*055d4590SKeyi Gui return result; 594*055d4590SKeyi Gui } 595*055d4590SKeyi Gui readAnnotation()596*055d4590SKeyi Gui public Annotation readAnnotation() { 597*055d4590SKeyi Gui byte visibility = readByte(); 598*055d4590SKeyi Gui int start = data.position(); 599*055d4590SKeyi Gui new EncodedValueReader(this, EncodedValueReader.ENCODED_ANNOTATION).skipValue(); 600*055d4590SKeyi Gui return new Annotation(Dex.this, visibility, new EncodedValue(getBytesFrom(start))); 601*055d4590SKeyi Gui } 602*055d4590SKeyi Gui readEncodedArray()603*055d4590SKeyi Gui public EncodedValue readEncodedArray() { 604*055d4590SKeyi Gui int start = data.position(); 605*055d4590SKeyi Gui new EncodedValueReader(this, EncodedValueReader.ENCODED_ARRAY).skipValue(); 606*055d4590SKeyi Gui return new EncodedValue(getBytesFrom(start)); 607*055d4590SKeyi Gui } 608*055d4590SKeyi Gui skip(int count)609*055d4590SKeyi Gui public void skip(int count) { 610*055d4590SKeyi Gui if (count < 0) { 611*055d4590SKeyi Gui throw new IllegalArgumentException(); 612*055d4590SKeyi Gui } 613*055d4590SKeyi Gui data.position(data.position() + count); 614*055d4590SKeyi Gui } 615*055d4590SKeyi Gui 616*055d4590SKeyi Gui /** 617*055d4590SKeyi Gui * Skips bytes until the position is aligned to a multiple of 4. 618*055d4590SKeyi Gui */ alignToFourBytes()619*055d4590SKeyi Gui public void alignToFourBytes() { 620*055d4590SKeyi Gui data.position((data.position() + 3) & ~3); 621*055d4590SKeyi Gui } 622*055d4590SKeyi Gui 623*055d4590SKeyi Gui /** 624*055d4590SKeyi Gui * Writes 0x00 until the position is aligned to a multiple of 4. 625*055d4590SKeyi Gui */ alignToFourBytesWithZeroFill()626*055d4590SKeyi Gui public void alignToFourBytesWithZeroFill() { 627*055d4590SKeyi Gui while ((data.position() & 3) != 0) { 628*055d4590SKeyi Gui data.put((byte) 0); 629*055d4590SKeyi Gui } 630*055d4590SKeyi Gui } 631*055d4590SKeyi Gui assertFourByteAligned()632*055d4590SKeyi Gui public void assertFourByteAligned() { 633*055d4590SKeyi Gui if ((data.position() & 3) != 0) { 634*055d4590SKeyi Gui throw new IllegalStateException("Not four byte aligned!"); 635*055d4590SKeyi Gui } 636*055d4590SKeyi Gui } 637*055d4590SKeyi Gui write(byte[] bytes)638*055d4590SKeyi Gui public void write(byte[] bytes) { 639*055d4590SKeyi Gui this.data.put(bytes); 640*055d4590SKeyi Gui } 641*055d4590SKeyi Gui 642*055d4590SKeyi Gui @Override writeByte(int b)643*055d4590SKeyi Gui public void writeByte(int b) { 644*055d4590SKeyi Gui data.put((byte) b); 645*055d4590SKeyi Gui } 646*055d4590SKeyi Gui writeShort(short i)647*055d4590SKeyi Gui public void writeShort(short i) { 648*055d4590SKeyi Gui data.putShort(i); 649*055d4590SKeyi Gui } 650*055d4590SKeyi Gui writeUnsignedShort(int i)651*055d4590SKeyi Gui public void writeUnsignedShort(int i) { 652*055d4590SKeyi Gui short s = (short) i; 653*055d4590SKeyi Gui if (i != (s & 0xffff)) { 654*055d4590SKeyi Gui throw new IllegalArgumentException("Expected an unsigned short: " + i); 655*055d4590SKeyi Gui } 656*055d4590SKeyi Gui writeShort(s); 657*055d4590SKeyi Gui } 658*055d4590SKeyi Gui write(short[] shorts)659*055d4590SKeyi Gui public void write(short[] shorts) { 660*055d4590SKeyi Gui for (short s : shorts) { 661*055d4590SKeyi Gui writeShort(s); 662*055d4590SKeyi Gui } 663*055d4590SKeyi Gui } 664*055d4590SKeyi Gui writeInt(int i)665*055d4590SKeyi Gui public void writeInt(int i) { 666*055d4590SKeyi Gui data.putInt(i); 667*055d4590SKeyi Gui } 668*055d4590SKeyi Gui writeUleb128(int i)669*055d4590SKeyi Gui public void writeUleb128(int i) { 670*055d4590SKeyi Gui try { 671*055d4590SKeyi Gui Leb128.writeUnsignedLeb128(this, i); 672*055d4590SKeyi Gui } catch (ArrayIndexOutOfBoundsException e) { 673*055d4590SKeyi Gui throw new DexException("Section limit " + data.limit() + " exceeded by " + name); 674*055d4590SKeyi Gui } 675*055d4590SKeyi Gui } 676*055d4590SKeyi Gui writeSleb128(int i)677*055d4590SKeyi Gui public void writeSleb128(int i) { 678*055d4590SKeyi Gui try { 679*055d4590SKeyi Gui Leb128.writeSignedLeb128(this, i); 680*055d4590SKeyi Gui } catch (ArrayIndexOutOfBoundsException e) { 681*055d4590SKeyi Gui throw new DexException("Section limit " + data.limit() + " exceeded by " + name); 682*055d4590SKeyi Gui } 683*055d4590SKeyi Gui } 684*055d4590SKeyi Gui writeStringData(String value)685*055d4590SKeyi Gui public void writeStringData(String value) { 686*055d4590SKeyi Gui try { 687*055d4590SKeyi Gui int length = value.length(); 688*055d4590SKeyi Gui writeUleb128(length); 689*055d4590SKeyi Gui write(Mutf8.encode(value)); 690*055d4590SKeyi Gui writeByte(0); 691*055d4590SKeyi Gui } catch (UTFDataFormatException e) { 692*055d4590SKeyi Gui throw new AssertionError(); 693*055d4590SKeyi Gui } 694*055d4590SKeyi Gui } 695*055d4590SKeyi Gui writeTypeList(TypeList typeList)696*055d4590SKeyi Gui public void writeTypeList(TypeList typeList) { 697*055d4590SKeyi Gui short[] types = typeList.getTypes(); 698*055d4590SKeyi Gui writeInt(types.length); 699*055d4590SKeyi Gui for (short type : types) { 700*055d4590SKeyi Gui writeShort(type); 701*055d4590SKeyi Gui } 702*055d4590SKeyi Gui alignToFourBytesWithZeroFill(); 703*055d4590SKeyi Gui } 704*055d4590SKeyi Gui 705*055d4590SKeyi Gui /** 706*055d4590SKeyi Gui * Returns the number of bytes used by this section. 707*055d4590SKeyi Gui */ used()708*055d4590SKeyi Gui public int used() { 709*055d4590SKeyi Gui return data.position() - initialPosition; 710*055d4590SKeyi Gui } 711*055d4590SKeyi Gui } 712*055d4590SKeyi Gui 713*055d4590SKeyi Gui private final class StringTable extends AbstractList<String> implements RandomAccess { 714*055d4590SKeyi Gui @Override get(int index)715*055d4590SKeyi Gui public String get(int index) { 716*055d4590SKeyi Gui checkBounds(index, tableOfContents.stringIds.size); 717*055d4590SKeyi Gui return open(tableOfContents.stringIds.off + (index * SizeOf.STRING_ID_ITEM)) 718*055d4590SKeyi Gui .readString(); 719*055d4590SKeyi Gui } 720*055d4590SKeyi Gui @Override size()721*055d4590SKeyi Gui public int size() { 722*055d4590SKeyi Gui return tableOfContents.stringIds.size; 723*055d4590SKeyi Gui } 724*055d4590SKeyi Gui } 725*055d4590SKeyi Gui 726*055d4590SKeyi Gui private final class TypeIndexToDescriptorIndexTable extends AbstractList<Integer> 727*055d4590SKeyi Gui implements RandomAccess { 728*055d4590SKeyi Gui @Override get(int index)729*055d4590SKeyi Gui public Integer get(int index) { 730*055d4590SKeyi Gui return descriptorIndexFromTypeIndex(index); 731*055d4590SKeyi Gui } 732*055d4590SKeyi Gui @Override size()733*055d4590SKeyi Gui public int size() { 734*055d4590SKeyi Gui return tableOfContents.typeIds.size; 735*055d4590SKeyi Gui } 736*055d4590SKeyi Gui } 737*055d4590SKeyi Gui 738*055d4590SKeyi Gui private final class TypeIndexToDescriptorTable extends AbstractList<String> 739*055d4590SKeyi Gui implements RandomAccess { 740*055d4590SKeyi Gui @Override get(int index)741*055d4590SKeyi Gui public String get(int index) { 742*055d4590SKeyi Gui return strings.get(descriptorIndexFromTypeIndex(index)); 743*055d4590SKeyi Gui } 744*055d4590SKeyi Gui @Override size()745*055d4590SKeyi Gui public int size() { 746*055d4590SKeyi Gui return tableOfContents.typeIds.size; 747*055d4590SKeyi Gui } 748*055d4590SKeyi Gui } 749*055d4590SKeyi Gui 750*055d4590SKeyi Gui private final class ProtoIdTable extends AbstractList<ProtoId> implements RandomAccess { 751*055d4590SKeyi Gui @Override get(int index)752*055d4590SKeyi Gui public ProtoId get(int index) { 753*055d4590SKeyi Gui checkBounds(index, tableOfContents.protoIds.size); 754*055d4590SKeyi Gui return open(tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * index)) 755*055d4590SKeyi Gui .readProtoId(); 756*055d4590SKeyi Gui } 757*055d4590SKeyi Gui @Override size()758*055d4590SKeyi Gui public int size() { 759*055d4590SKeyi Gui return tableOfContents.protoIds.size; 760*055d4590SKeyi Gui } 761*055d4590SKeyi Gui } 762*055d4590SKeyi Gui 763*055d4590SKeyi Gui private final class FieldIdTable extends AbstractList<FieldId> implements RandomAccess { 764*055d4590SKeyi Gui @Override get(int index)765*055d4590SKeyi Gui public FieldId get(int index) { 766*055d4590SKeyi Gui checkBounds(index, tableOfContents.fieldIds.size); 767*055d4590SKeyi Gui return open(tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * index)) 768*055d4590SKeyi Gui .readFieldId(); 769*055d4590SKeyi Gui } 770*055d4590SKeyi Gui @Override size()771*055d4590SKeyi Gui public int size() { 772*055d4590SKeyi Gui return tableOfContents.fieldIds.size; 773*055d4590SKeyi Gui } 774*055d4590SKeyi Gui } 775*055d4590SKeyi Gui 776*055d4590SKeyi Gui private final class MethodIdTable extends AbstractList<MethodId> implements RandomAccess { 777*055d4590SKeyi Gui @Override get(int index)778*055d4590SKeyi Gui public MethodId get(int index) { 779*055d4590SKeyi Gui checkBounds(index, tableOfContents.methodIds.size); 780*055d4590SKeyi Gui return open(tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * index)) 781*055d4590SKeyi Gui .readMethodId(); 782*055d4590SKeyi Gui } 783*055d4590SKeyi Gui @Override size()784*055d4590SKeyi Gui public int size() { 785*055d4590SKeyi Gui return tableOfContents.methodIds.size; 786*055d4590SKeyi Gui } 787*055d4590SKeyi Gui } 788*055d4590SKeyi Gui 789*055d4590SKeyi Gui private final class ClassDefIterator implements Iterator<ClassDef> { 790*055d4590SKeyi Gui private final Dex.Section in = open(tableOfContents.classDefs.off); 791*055d4590SKeyi Gui private int count = 0; 792*055d4590SKeyi Gui 793*055d4590SKeyi Gui @Override hasNext()794*055d4590SKeyi Gui public boolean hasNext() { 795*055d4590SKeyi Gui return count < tableOfContents.classDefs.size; 796*055d4590SKeyi Gui } 797*055d4590SKeyi Gui @Override next()798*055d4590SKeyi Gui public ClassDef next() { 799*055d4590SKeyi Gui if (!hasNext()) { 800*055d4590SKeyi Gui throw new NoSuchElementException(); 801*055d4590SKeyi Gui } 802*055d4590SKeyi Gui count++; 803*055d4590SKeyi Gui return in.readClassDef(); 804*055d4590SKeyi Gui } 805*055d4590SKeyi Gui @Override remove()806*055d4590SKeyi Gui public void remove() { 807*055d4590SKeyi Gui throw new UnsupportedOperationException(); 808*055d4590SKeyi Gui } 809*055d4590SKeyi Gui } 810*055d4590SKeyi Gui 811*055d4590SKeyi Gui private final class ClassDefIterable implements Iterable<ClassDef> { 812*055d4590SKeyi Gui @Override iterator()813*055d4590SKeyi Gui public Iterator<ClassDef> iterator() { 814*055d4590SKeyi Gui return !tableOfContents.classDefs.exists() 815*055d4590SKeyi Gui ? Collections.<ClassDef>emptySet().iterator() 816*055d4590SKeyi Gui : new ClassDefIterator(); 817*055d4590SKeyi Gui } 818*055d4590SKeyi Gui } 819*055d4590SKeyi Gui } 820