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