xref: /aosp_15_r20/dalvik/dx/src/com/android/dex/Dex.java (revision 055d459012065f78d96b68be8421640240ddf631)
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