xref: /aosp_15_r20/dalvik/dx/src/com/android/dex/TableOfContents.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 java.io.IOException;
20*055d4590SKeyi Gui import java.io.UnsupportedEncodingException;
21*055d4590SKeyi Gui import java.util.Arrays;
22*055d4590SKeyi Gui 
23*055d4590SKeyi Gui /**
24*055d4590SKeyi Gui  * The file header and map.
25*055d4590SKeyi Gui  */
26*055d4590SKeyi Gui public final class TableOfContents {
27*055d4590SKeyi Gui 
28*055d4590SKeyi Gui     /*
29*055d4590SKeyi Gui      * TODO: factor out ID constants.
30*055d4590SKeyi Gui      */
31*055d4590SKeyi Gui 
32*055d4590SKeyi Gui     public final Section header = new Section(0x0000);
33*055d4590SKeyi Gui     public final Section stringIds = new Section(0x0001);
34*055d4590SKeyi Gui     public final Section typeIds = new Section(0x0002);
35*055d4590SKeyi Gui     public final Section protoIds = new Section(0x0003);
36*055d4590SKeyi Gui     public final Section fieldIds = new Section(0x0004);
37*055d4590SKeyi Gui     public final Section methodIds = new Section(0x0005);
38*055d4590SKeyi Gui     public final Section classDefs = new Section(0x0006);
39*055d4590SKeyi Gui     public final Section callSiteIds = new Section(0x0007);
40*055d4590SKeyi Gui     public final Section methodHandles = new Section(0x0008);
41*055d4590SKeyi Gui     public final Section mapList = new Section(0x1000);
42*055d4590SKeyi Gui     public final Section typeLists = new Section(0x1001);
43*055d4590SKeyi Gui     public final Section annotationSetRefLists = new Section(0x1002);
44*055d4590SKeyi Gui     public final Section annotationSets = new Section(0x1003);
45*055d4590SKeyi Gui     public final Section classDatas = new Section(0x2000);
46*055d4590SKeyi Gui     public final Section codes = new Section(0x2001);
47*055d4590SKeyi Gui     public final Section stringDatas = new Section(0x2002);
48*055d4590SKeyi Gui     public final Section debugInfos = new Section(0x2003);
49*055d4590SKeyi Gui     public final Section annotations = new Section(0x2004);
50*055d4590SKeyi Gui     public final Section encodedArrays = new Section(0x2005);
51*055d4590SKeyi Gui     public final Section annotationsDirectories = new Section(0x2006);
52*055d4590SKeyi Gui     public final Section[] sections = {
53*055d4590SKeyi Gui         header, stringIds, typeIds, protoIds, fieldIds, methodIds, classDefs, mapList, callSiteIds,
54*055d4590SKeyi Gui         methodHandles, typeLists, annotationSetRefLists, annotationSets, classDatas, codes,
55*055d4590SKeyi Gui         stringDatas, debugInfos, annotations, encodedArrays, annotationsDirectories
56*055d4590SKeyi Gui     };
57*055d4590SKeyi Gui 
58*055d4590SKeyi Gui     public int apiLevel;
59*055d4590SKeyi Gui     public int checksum;
60*055d4590SKeyi Gui     public byte[] signature;
61*055d4590SKeyi Gui     public int fileSize;
62*055d4590SKeyi Gui     public int linkSize;
63*055d4590SKeyi Gui     public int linkOff;
64*055d4590SKeyi Gui     public int dataSize;
65*055d4590SKeyi Gui     public int dataOff;
66*055d4590SKeyi Gui 
TableOfContents()67*055d4590SKeyi Gui     public TableOfContents() {
68*055d4590SKeyi Gui         signature = new byte[20];
69*055d4590SKeyi Gui     }
70*055d4590SKeyi Gui 
readFrom(Dex dex)71*055d4590SKeyi Gui     public void readFrom(Dex dex) throws IOException {
72*055d4590SKeyi Gui         readHeader(dex.open(0));
73*055d4590SKeyi Gui         readMap(dex.open(mapList.off));
74*055d4590SKeyi Gui         computeSizesFromOffsets();
75*055d4590SKeyi Gui     }
76*055d4590SKeyi Gui 
readHeader(Dex.Section headerIn)77*055d4590SKeyi Gui     private void readHeader(Dex.Section headerIn) throws UnsupportedEncodingException {
78*055d4590SKeyi Gui         byte[] magic = headerIn.readByteArray(8);
79*055d4590SKeyi Gui 
80*055d4590SKeyi Gui         if (!DexFormat.isSupportedDexMagic(magic)) {
81*055d4590SKeyi Gui             String msg =
82*055d4590SKeyi Gui                     String.format("Unexpected magic: [0x%02x, 0x%02x, 0x%02x, 0x%02x, "
83*055d4590SKeyi Gui                                   + "0x%02x, 0x%02x, 0x%02x, 0x%02x]",
84*055d4590SKeyi Gui                                   magic[0], magic[1], magic[2], magic[3],
85*055d4590SKeyi Gui                                   magic[4], magic[5], magic[6], magic[7]);
86*055d4590SKeyi Gui             throw new DexException(msg);
87*055d4590SKeyi Gui         }
88*055d4590SKeyi Gui 
89*055d4590SKeyi Gui         apiLevel = DexFormat.magicToApi(magic);
90*055d4590SKeyi Gui         checksum = headerIn.readInt();
91*055d4590SKeyi Gui         signature = headerIn.readByteArray(20);
92*055d4590SKeyi Gui         fileSize = headerIn.readInt();
93*055d4590SKeyi Gui         int headerSize = headerIn.readInt();
94*055d4590SKeyi Gui         if (headerSize != SizeOf.HEADER_ITEM) {
95*055d4590SKeyi Gui             throw new DexException("Unexpected header: 0x" + Integer.toHexString(headerSize));
96*055d4590SKeyi Gui         }
97*055d4590SKeyi Gui         int endianTag = headerIn.readInt();
98*055d4590SKeyi Gui         if (endianTag != DexFormat.ENDIAN_TAG) {
99*055d4590SKeyi Gui             throw new DexException("Unexpected endian tag: 0x" + Integer.toHexString(endianTag));
100*055d4590SKeyi Gui         }
101*055d4590SKeyi Gui         linkSize = headerIn.readInt();
102*055d4590SKeyi Gui         linkOff = headerIn.readInt();
103*055d4590SKeyi Gui         mapList.off = headerIn.readInt();
104*055d4590SKeyi Gui         if (mapList.off == 0) {
105*055d4590SKeyi Gui             throw new DexException("Cannot merge dex files that do not contain a map");
106*055d4590SKeyi Gui         }
107*055d4590SKeyi Gui         stringIds.size = headerIn.readInt();
108*055d4590SKeyi Gui         stringIds.off = headerIn.readInt();
109*055d4590SKeyi Gui         typeIds.size = headerIn.readInt();
110*055d4590SKeyi Gui         typeIds.off = headerIn.readInt();
111*055d4590SKeyi Gui         protoIds.size = headerIn.readInt();
112*055d4590SKeyi Gui         protoIds.off = headerIn.readInt();
113*055d4590SKeyi Gui         fieldIds.size = headerIn.readInt();
114*055d4590SKeyi Gui         fieldIds.off = headerIn.readInt();
115*055d4590SKeyi Gui         methodIds.size = headerIn.readInt();
116*055d4590SKeyi Gui         methodIds.off = headerIn.readInt();
117*055d4590SKeyi Gui         classDefs.size = headerIn.readInt();
118*055d4590SKeyi Gui         classDefs.off = headerIn.readInt();
119*055d4590SKeyi Gui         dataSize = headerIn.readInt();
120*055d4590SKeyi Gui         dataOff = headerIn.readInt();
121*055d4590SKeyi Gui     }
122*055d4590SKeyi Gui 
readMap(Dex.Section in)123*055d4590SKeyi Gui     private void readMap(Dex.Section in) throws IOException {
124*055d4590SKeyi Gui         int mapSize = in.readInt();
125*055d4590SKeyi Gui         Section previous = null;
126*055d4590SKeyi Gui         for (int i = 0; i < mapSize; i++) {
127*055d4590SKeyi Gui             short type = in.readShort();
128*055d4590SKeyi Gui             in.readShort(); // unused
129*055d4590SKeyi Gui             Section section = getSection(type);
130*055d4590SKeyi Gui             int size = in.readInt();
131*055d4590SKeyi Gui             int offset = in.readInt();
132*055d4590SKeyi Gui 
133*055d4590SKeyi Gui             if ((section.size != 0 && section.size != size)
134*055d4590SKeyi Gui                     || (section.off != -1 && section.off != offset)) {
135*055d4590SKeyi Gui                 throw new DexException("Unexpected map value for 0x" + Integer.toHexString(type));
136*055d4590SKeyi Gui             }
137*055d4590SKeyi Gui 
138*055d4590SKeyi Gui             section.size = size;
139*055d4590SKeyi Gui             section.off = offset;
140*055d4590SKeyi Gui 
141*055d4590SKeyi Gui             if (previous != null && previous.off > section.off) {
142*055d4590SKeyi Gui                 throw new DexException("Map is unsorted at " + previous + ", " + section);
143*055d4590SKeyi Gui             }
144*055d4590SKeyi Gui 
145*055d4590SKeyi Gui             previous = section;
146*055d4590SKeyi Gui         }
147*055d4590SKeyi Gui         Arrays.sort(sections);
148*055d4590SKeyi Gui     }
149*055d4590SKeyi Gui 
computeSizesFromOffsets()150*055d4590SKeyi Gui     public void computeSizesFromOffsets() {
151*055d4590SKeyi Gui         int end = dataOff + dataSize;
152*055d4590SKeyi Gui         for (int i = sections.length - 1; i >= 0; i--) {
153*055d4590SKeyi Gui             Section section = sections[i];
154*055d4590SKeyi Gui             if (section.off == -1) {
155*055d4590SKeyi Gui                 continue;
156*055d4590SKeyi Gui             }
157*055d4590SKeyi Gui             if (section.off > end) {
158*055d4590SKeyi Gui                 throw new DexException("Map is unsorted at " + section);
159*055d4590SKeyi Gui             }
160*055d4590SKeyi Gui             section.byteCount = end - section.off;
161*055d4590SKeyi Gui             end = section.off;
162*055d4590SKeyi Gui         }
163*055d4590SKeyi Gui     }
164*055d4590SKeyi Gui 
getSection(short type)165*055d4590SKeyi Gui     private Section getSection(short type) {
166*055d4590SKeyi Gui         for (Section section : sections) {
167*055d4590SKeyi Gui             if (section.type == type) {
168*055d4590SKeyi Gui                 return section;
169*055d4590SKeyi Gui             }
170*055d4590SKeyi Gui         }
171*055d4590SKeyi Gui         throw new IllegalArgumentException("No such map item: " + type);
172*055d4590SKeyi Gui     }
173*055d4590SKeyi Gui 
writeHeader(Dex.Section out, int api)174*055d4590SKeyi Gui     public void writeHeader(Dex.Section out, int api) throws IOException {
175*055d4590SKeyi Gui         out.write(DexFormat.apiToMagic(api).getBytes("UTF-8"));
176*055d4590SKeyi Gui         out.writeInt(checksum);
177*055d4590SKeyi Gui         out.write(signature);
178*055d4590SKeyi Gui         out.writeInt(fileSize);
179*055d4590SKeyi Gui         out.writeInt(SizeOf.HEADER_ITEM);
180*055d4590SKeyi Gui         out.writeInt(DexFormat.ENDIAN_TAG);
181*055d4590SKeyi Gui         out.writeInt(linkSize);
182*055d4590SKeyi Gui         out.writeInt(linkOff);
183*055d4590SKeyi Gui         out.writeInt(mapList.off);
184*055d4590SKeyi Gui         out.writeInt(stringIds.size);
185*055d4590SKeyi Gui         out.writeInt(stringIds.off);
186*055d4590SKeyi Gui         out.writeInt(typeIds.size);
187*055d4590SKeyi Gui         out.writeInt(typeIds.off);
188*055d4590SKeyi Gui         out.writeInt(protoIds.size);
189*055d4590SKeyi Gui         out.writeInt(protoIds.off);
190*055d4590SKeyi Gui         out.writeInt(fieldIds.size);
191*055d4590SKeyi Gui         out.writeInt(fieldIds.off);
192*055d4590SKeyi Gui         out.writeInt(methodIds.size);
193*055d4590SKeyi Gui         out.writeInt(methodIds.off);
194*055d4590SKeyi Gui         out.writeInt(classDefs.size);
195*055d4590SKeyi Gui         out.writeInt(classDefs.off);
196*055d4590SKeyi Gui         out.writeInt(dataSize);
197*055d4590SKeyi Gui         out.writeInt(dataOff);
198*055d4590SKeyi Gui     }
199*055d4590SKeyi Gui 
writeMap(Dex.Section out)200*055d4590SKeyi Gui     public void writeMap(Dex.Section out) throws IOException {
201*055d4590SKeyi Gui         int count = 0;
202*055d4590SKeyi Gui         for (Section section : sections) {
203*055d4590SKeyi Gui             if (section.exists()) {
204*055d4590SKeyi Gui                 count++;
205*055d4590SKeyi Gui             }
206*055d4590SKeyi Gui         }
207*055d4590SKeyi Gui 
208*055d4590SKeyi Gui         out.writeInt(count);
209*055d4590SKeyi Gui         for (Section section : sections) {
210*055d4590SKeyi Gui             if (section.exists()) {
211*055d4590SKeyi Gui                 out.writeShort(section.type);
212*055d4590SKeyi Gui                 out.writeShort((short) 0);
213*055d4590SKeyi Gui                 out.writeInt(section.size);
214*055d4590SKeyi Gui                 out.writeInt(section.off);
215*055d4590SKeyi Gui             }
216*055d4590SKeyi Gui         }
217*055d4590SKeyi Gui     }
218*055d4590SKeyi Gui 
219*055d4590SKeyi Gui     public static class Section implements Comparable<Section> {
220*055d4590SKeyi Gui         public final short type;
221*055d4590SKeyi Gui         public int size = 0;
222*055d4590SKeyi Gui         public int off = -1;
223*055d4590SKeyi Gui         public int byteCount = 0;
224*055d4590SKeyi Gui 
Section(int type)225*055d4590SKeyi Gui         public Section(int type) {
226*055d4590SKeyi Gui             this.type = (short) type;
227*055d4590SKeyi Gui         }
228*055d4590SKeyi Gui 
exists()229*055d4590SKeyi Gui         public boolean exists() {
230*055d4590SKeyi Gui             return size > 0;
231*055d4590SKeyi Gui         }
232*055d4590SKeyi Gui 
233*055d4590SKeyi Gui         @Override
compareTo(Section section)234*055d4590SKeyi Gui         public int compareTo(Section section) {
235*055d4590SKeyi Gui             if (off != section.off) {
236*055d4590SKeyi Gui                 return off < section.off ? -1 : 1;
237*055d4590SKeyi Gui             }
238*055d4590SKeyi Gui             return 0;
239*055d4590SKeyi Gui         }
240*055d4590SKeyi Gui 
241*055d4590SKeyi Gui         @Override
toString()242*055d4590SKeyi Gui         public String toString() {
243*055d4590SKeyi Gui             return String.format("Section[type=%#x,off=%#x,size=%#x]", type, off, size);
244*055d4590SKeyi Gui         }
245*055d4590SKeyi Gui     }
246*055d4590SKeyi Gui }
247