Improve the interface for reading Dex files.
I'm planning on making this code reusable for grepping
dex files.
Change-Id: Iebf545ed6d6a4eb347ccc4a39fe40c02d75d69e4
diff --git a/dx/src/com/android/dx/dex/DexException.java b/dx/src/com/android/dx/dex/DexException.java
index 7e52a1a..6961209 100644
--- a/dx/src/com/android/dx/dex/DexException.java
+++ b/dx/src/com/android/dx/dex/DexException.java
@@ -16,13 +16,14 @@
package com.android.dx.dex;
-import java.io.IOException;
-
/**
- * Thrown when there's a format problem reading or writing a dex file.
+ * Thrown when there's a format problem reading a dex file.
*/
-public final class DexException extends IOException {
+public final class DexException extends RuntimeException {
public DexException(String message) {
super(message);
}
+ public DexException(Exception cause) {
+ super(cause);
+ }
}
diff --git a/dx/src/com/android/dx/dex/TableOfContents.java b/dx/src/com/android/dx/dex/TableOfContents.java
index 580241c..313ecad 100644
--- a/dx/src/com/android/dx/dex/TableOfContents.java
+++ b/dx/src/com/android/dx/dex/TableOfContents.java
@@ -16,9 +16,9 @@
package com.android.dx.dex;
-import com.android.dx.util.DexReader;
-import com.android.dx.util.DexWriter;
+import com.android.dx.io.DexBuffer;
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
@@ -66,51 +66,51 @@
signature = new byte[20];
}
- public TableOfContents(DexReader in) throws IOException {
- byte[] magic = in.readByteArray(8);
+ public void readFrom(DexBuffer buffer) throws IOException {
+ readHeader(buffer.open(0));
+ readMap(buffer.open(mapList.off));
+ }
+
+ private void readHeader(DexBuffer.Section headerIn) throws UnsupportedEncodingException {
+ byte[] magic = headerIn.readByteArray(8);
if (!Arrays.equals(DexFormat.MAGIC.getBytes("UTF-8"), magic)) {
throw new DexException("Unexpected magic: " + Arrays.toString(magic));
}
- checksum = in.readInt();
- signature = in.readByteArray(20);
- fileSize = in.readInt();
- int headerSize = in.readInt();
+ checksum = headerIn.readInt();
+ signature = headerIn.readByteArray(20);
+ fileSize = headerIn.readInt();
+ int headerSize = headerIn.readInt();
if (headerSize != SizeOf.HEADER_ITEM) {
throw new DexException("Unexpected header: 0x" + Integer.toHexString(headerSize));
}
- int endianTag = in.readInt();
+ int endianTag = headerIn.readInt();
if (endianTag != DexFormat.ENDIAN_TAG) {
throw new DexException("Unexpected endian tag: 0x" + Integer.toHexString(endianTag));
}
- linkSize = in.readInt();
- linkOff = in.readInt();
- mapList.off = in.readInt();
+ linkSize = headerIn.readInt();
+ linkOff = headerIn.readInt();
+ mapList.off = headerIn.readInt();
if (mapList.off == 0) {
throw new DexException("Cannot merge dex files that do not contain a map");
}
- stringIds.size = in.readInt();
- stringIds.off = in.readInt();
- typeIds.size = in.readInt();
- typeIds.off = in.readInt();
- protoIds.size = in.readInt();
- protoIds.off = in.readInt();
- fieldIds.size = in.readInt();
- fieldIds.off = in.readInt();
- methodIds.size = in.readInt();
- methodIds.off = in.readInt();
- classDefs.size = in.readInt();
- classDefs.off = in.readInt();
- dataSize = in.readInt();
- dataOff = in.readInt();
-
- int position = in.getPosition();
- in.seek(mapList.off);
- readMap(in);
- in.seek(position);
+ stringIds.size = headerIn.readInt();
+ stringIds.off = headerIn.readInt();
+ typeIds.size = headerIn.readInt();
+ typeIds.off = headerIn.readInt();
+ protoIds.size = headerIn.readInt();
+ protoIds.off = headerIn.readInt();
+ fieldIds.size = headerIn.readInt();
+ fieldIds.off = headerIn.readInt();
+ methodIds.size = headerIn.readInt();
+ methodIds.off = headerIn.readInt();
+ classDefs.size = headerIn.readInt();
+ classDefs.off = headerIn.readInt();
+ dataSize = headerIn.readInt();
+ dataOff = headerIn.readInt();
}
- private void readMap(DexReader in) throws IOException {
+ private void readMap(DexBuffer.Section in) throws IOException {
int mapSize = in.readInt();
Section previous = null;
@@ -157,7 +157,7 @@
throw new IllegalArgumentException("No such map item: " + type);
}
- public void writeHeader(DexWriter.Section out) throws IOException {
+ public void writeHeader(DexBuffer.Section out) throws IOException {
out.write(DexFormat.MAGIC.getBytes("UTF-8"));
out.writeInt(checksum);
out.write(signature);
@@ -183,7 +183,7 @@
out.writeInt(dataOff);
}
- public void writeMap(DexWriter.Section out) throws IOException {
+ public void writeMap(DexBuffer.Section out) throws IOException {
int count = 0;
for (Section s : sections) {
if (s.size > 0) {
diff --git a/dx/src/com/android/dx/io/ClassDef.java b/dx/src/com/android/dx/io/ClassDef.java
new file mode 100644
index 0000000..6837a07
--- /dev/null
+++ b/dx/src/com/android/dx/io/ClassDef.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+/**
+ * A type definition.
+ */
+public final class ClassDef {
+ public static final int NO_INDEX = -1;
+ private final DexBuffer buffer;
+ private final int offset;
+ private final int typeIndex;
+ private final int accessFlags;
+ private final int supertypeIndex;
+ private final int interfacesOffset;
+ private final short[] interfaces;
+ private final int sourceFileIndex;
+ private final int annotationsOffset;
+ private final int classDataOffset;
+ private final int staticValuesOffset;
+
+ public ClassDef(DexBuffer buffer, int offset, int typeIndex, int accessFlags,
+ int supertypeIndex, int interfacesOffset, short[] interfaces, int sourceFileIndex,
+ int annotationsOffset, int classDataOffset, int staticValuesOffset) {
+ this.buffer = buffer;
+ this.offset = offset;
+ this.typeIndex = typeIndex;
+ this.accessFlags = accessFlags;
+ this.supertypeIndex = supertypeIndex;
+ this.interfacesOffset = interfacesOffset;
+ this.interfaces = interfaces;
+ this.sourceFileIndex = sourceFileIndex;
+ this.annotationsOffset = annotationsOffset;
+ this.classDataOffset = classDataOffset;
+ this.staticValuesOffset = staticValuesOffset;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public int getTypeIndex() {
+ return typeIndex;
+ }
+
+ public int getSupertypeIndex() {
+ return supertypeIndex;
+ }
+
+ public int getInterfacesOffset() {
+ return interfacesOffset;
+ }
+
+ public short[] getInterfaces() {
+ return interfaces;
+ }
+
+ public int getAccessFlags() {
+ return accessFlags;
+ }
+
+ public int getSourceFileIndex() {
+ return sourceFileIndex;
+ }
+
+ public int getAnnotationsOffset() {
+ return annotationsOffset;
+ }
+
+ public int getClassDataOffset() {
+ return classDataOffset;
+ }
+
+ public int getStaticValuesOffset() {
+ return staticValuesOffset;
+ }
+
+ @Override public String toString() {
+ if (buffer == null) {
+ return typeIndex + " " + supertypeIndex;
+ }
+
+ StringBuilder result = new StringBuilder();
+ DexBuffer.Section in = buffer.open(0);
+ result.append(in.readTypeName(typeIndex));
+ if (supertypeIndex != NO_INDEX) {
+ result.append(" extends ").append(in.readTypeName(supertypeIndex));
+ }
+ return result.toString();
+ }
+}
diff --git a/dx/src/com/android/dx/io/DexBuffer.java b/dx/src/com/android/dx/io/DexBuffer.java
new file mode 100644
index 0000000..e3309cb
--- /dev/null
+++ b/dx/src/com/android/dx/io/DexBuffer.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.dex.DexException;
+import com.android.dx.dex.SizeOf;
+import com.android.dx.dex.TableOfContents;
+import com.android.dx.util.Leb128Utils;
+import com.android.dx.util.Mutf8;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+/**
+ * The bytes of a dex file in memory for reading and writing. All int offsets
+ * are unsigned.
+ */
+public final class DexBuffer {
+ private byte[] data;
+ private final TableOfContents tableOfContents = new TableOfContents();
+ private int length;
+
+ public void loadFrom(InputStream in) throws IOException {
+ ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
+ byte[] buffer = new byte[8192];
+
+ int count;
+ while ((count = in.read(buffer)) != -1) {
+ bytesOut.write(buffer, 0, count);
+ }
+
+ this.data = bytesOut.toByteArray();
+ tableOfContents.readFrom(this);
+ }
+
+ public void loadFrom(File file) throws IOException {
+ InputStream in = new FileInputStream(file);
+ loadFrom(in);
+ in.close();
+ }
+
+ public void writeTo(OutputStream out) throws IOException {
+ out.write(data);
+ }
+
+ public void writeTo(File dexOut) throws IOException {
+ OutputStream out = new FileOutputStream(dexOut);
+ writeTo(out);
+ out.close();
+ }
+
+ public TableOfContents getTableOfContents() {
+ return tableOfContents;
+ }
+
+ public Section open(int position) {
+ return new Section(position);
+ }
+
+ public Section appendSection(int maxByteCount, String name) throws IOException {
+ Section result = new Section(name, length, length + maxByteCount);
+ length = fourByteAlign(length + maxByteCount);
+ return result;
+ }
+
+ public void noMoreSections() {
+ data = new byte[length];
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ private static int fourByteAlign(int position) {
+ return (position + 3) & ~3;
+ }
+
+ public byte[] getBytes() {
+ return data;
+ }
+
+ public final class Section {
+ private final String name;
+ private int position;
+ private final int limit;
+
+ private Section(String name, int position, int limit) {
+ this.name = name;
+ this.position = position;
+ this.limit = limit;
+ }
+
+ private Section(int position) {
+ this("section", position, data.length);
+ }
+
+ private final DataInput asDataInput = new DataInputStub() {
+ public byte readByte() {
+ return Section.this.readByte();
+ }
+ };
+
+ public int getPosition() {
+ return position;
+ }
+
+ public int readInt() {
+ int result = (data[position] & 0xff)
+ | (data[position + 1] & 0xff) << 8
+ | (data[position + 2] & 0xff) << 16
+ | (data[position + 3] & 0xff) << 24;
+ position += 4;
+ return result;
+ }
+
+ public short readShort() {
+ int result = (data[position] & 0xff)
+ | (data[position + 1] & 0xff) << 8;
+ position += 2;
+ return (short) result;
+ }
+
+ public byte readByte() {
+ return (byte) (data[position++] & 0xff);
+ }
+
+ public byte[] readByteArray(int length) {
+ byte[] result = Arrays.copyOfRange(data, position, position + length);
+ position += length;
+ return result;
+ }
+
+ public short[] readShortArray(int length) {
+ short[] result = new short[length];
+ for (int i = 0; i < length; i++) {
+ result[i] = readShort();
+ }
+ return result;
+ }
+
+ public int readUleb128() {
+ try {
+ return Leb128Utils.readUnsignedLeb128(asDataInput);
+ } catch (IOException e) {
+ throw new DexException(e);
+ }
+ }
+
+ public int readSleb128() {
+ try {
+ return Leb128Utils.readSignedLeb128(asDataInput);
+ } catch (IOException e) {
+ throw new DexException(e);
+ }
+ }
+
+ public short[] readTypeList(int offset) {
+ if (offset == 0) {
+ return new short[0];
+ }
+ int savedPosition = position;
+ position = offset;
+ int size = readInt();
+ short[] parameters = new short[size];
+ for (int i = 0; i < size; i++) {
+ parameters[i] = readShort();
+ }
+ position = savedPosition;
+ return parameters;
+ }
+
+ public String readStringDataItem() {
+ try {
+ int expectedLength = readUleb128();
+ String result = Mutf8.decode(asDataInput, new char[expectedLength]);
+ if (result.length() != expectedLength) {
+ throw new DexException("Declared length " + expectedLength
+ + " doesn't match decoded length of " + result.length());
+ }
+ return result;
+ } catch (IOException e) {
+ throw new DexException(e);
+ }
+ }
+
+ /**
+ * Reads a string at the given index. This method does not disturb the position.
+ */
+ public String readString(int index) {
+ int savedPosition = position;
+ position = tableOfContents.stringIds.off + (index * SizeOf.STRING_ID_ITEM);
+ position = readInt();
+ String result = readStringDataItem();
+ position = savedPosition;
+ return result;
+ }
+
+ public int readType(int index) {
+ if (index < 0 || index >= tableOfContents.typeIds.size) {
+ throw new IllegalArgumentException("type index out of range: "
+ + index + " " + tableOfContents.typeIds.size);
+ }
+ int savedPosition = position;
+ position = tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM);
+ int result = readInt();
+ position = savedPosition;
+ return result;
+ }
+
+ public String readTypeName(int index) {
+ return readString(readType(index));
+ }
+
+ public FieldId readFieldId() {
+ short declaringClassIndex = readShort();
+ short typeIndex = readShort();
+ int nameIndex = readInt();
+ return new FieldId(DexBuffer.this, declaringClassIndex, typeIndex, nameIndex);
+ }
+
+ public MethodId readMethodId() {
+ short declaringClassIndex = readShort();
+ short protoIndex = readShort();
+ int nameIndex = readInt();
+ return new MethodId(DexBuffer.this, declaringClassIndex, protoIndex, nameIndex);
+ }
+
+ public ProtoId readProtoId(int index) {
+ int savedPosition = position;
+ position = tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * index);
+ ProtoId result = readProtoId();
+ position = savedPosition;
+ return result;
+ }
+
+ public ProtoId readProtoId() {
+ int shortyIndex = readInt();
+ int returnTypeIndex = readInt();
+ int parametersOff = readInt();
+ short[] parameters = readTypeList(parametersOff);
+ return new ProtoId(DexBuffer.this, shortyIndex, returnTypeIndex, parameters);
+ }
+
+ public ClassDef readClassDef() {
+ int offset = getPosition();
+ int type = readInt();
+ int accessFlags = readInt();
+ int supertype = readInt();
+ int interfacesOffset = readInt();
+ short[] interfaces = readTypeList(interfacesOffset);
+ int sourceFileIndex = readInt();
+ int annotationsOffset = readInt();
+ int classDataOffset = readInt();
+ int staticValuesOffset = readInt();
+ return new ClassDef(DexBuffer.this, offset, type, accessFlags, supertype,
+ interfacesOffset, interfaces, sourceFileIndex, annotationsOffset,
+ classDataOffset, staticValuesOffset);
+ }
+
+ private void checkPosition() {
+ if (position > limit) {
+ throw new DexException("Section limit " + limit + " exceeded by " + name);
+ }
+ }
+
+ /**
+ * Writes 0x00 until the position is aligned to a multiple of 4.
+ */
+ public void alignToFourBytes() throws IOException {
+ int unalignedCount = position;
+ position = DexBuffer.fourByteAlign(position);
+ for (int i = unalignedCount; i < position; i++) {
+ data[i] = 0;
+ }
+ }
+
+ public void assertFourByteAligned() throws IOException {
+ if ((position & 3) != 0) {
+ throw new IllegalStateException("Not four byte aligned!");
+ }
+ }
+
+ public void write(byte[] bytes) throws IOException {
+ System.arraycopy(bytes, 0, data, position, bytes.length);
+ position += bytes.length;
+ checkPosition();
+ }
+
+ public void writeByte(int b) throws IOException {
+ data[position++] = (byte) b;
+ checkPosition();
+ }
+
+ public void writeShort(short i) throws IOException {
+ data[position ] = (byte) i;
+ data[position + 1] = (byte) (i >>> 8);
+ position += 2;
+ checkPosition();
+ }
+
+ public void write(short[] shorts) throws IOException {
+ for (short s : shorts) {
+ writeShort(s);
+ }
+ }
+
+ public void writeInt(int i) throws IOException {
+ data[position ] = (byte) i;
+ data[position + 1] = (byte) (i >>> 8);
+ data[position + 2] = (byte) (i >>> 16);
+ data[position + 3] = (byte) (i >>> 24);
+ position += 4;
+ checkPosition();
+ }
+
+ public void writeUleb128(int i) throws IOException {
+ position += Leb128Utils.writeUnsignedLeb128(data, position, i);
+ checkPosition();
+ }
+
+ public void writeSleb128(int i) throws IOException {
+ position += Leb128Utils.writeSignedLeb128(data, position, i);
+ checkPosition();
+ }
+
+ public void writeStringDataItem(String value) throws IOException {
+ int length = value.length();
+ writeUleb128(length);
+ write(Mutf8.encode(value));
+ writeByte(0);
+ }
+
+ public Section open(int position) {
+ return new Section(position);
+ }
+ }
+
+ private static class DataInputStub implements DataInput {
+ public byte readByte() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public void readFully(byte[] buffer) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public void readFully(byte[] buffer, int offset, int count) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public int skipBytes(int i) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public boolean readBoolean() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public int readUnsignedByte() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public short readShort() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public int readUnsignedShort() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public char readChar() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public int readInt() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public long readLong() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public float readFloat() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public double readDouble() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public String readLine() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ public String readUTF() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/dx/src/com/android/dx/io/DexHasher.java b/dx/src/com/android/dx/io/DexHasher.java
new file mode 100644
index 0000000..416b3e2
--- /dev/null
+++ b/dx/src/com/android/dx/io/DexHasher.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.zip.Adler32;
+
+/**
+ * Generates and stores the checksum and signature of a dex file.
+ */
+public final class DexHasher {
+ private static final int CHECKSUM_OFFSET = 8;
+ private static final int CHECKSUM_SIZE = 4;
+ private static final int SIGNATURE_OFFSET = CHECKSUM_OFFSET + CHECKSUM_SIZE;
+ private static final int SIGNATURE_SIZE = 20;
+
+ /**
+ * Returns the signature of all but the first 32 bytes of {@code dex}. The
+ * first 32 bytes of dex files are not specified to be included in the
+ * signature.
+ */
+ public byte[] computeSignature(DexBuffer dex) throws IOException {
+ MessageDigest digest;
+ try {
+ digest = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError();
+ }
+ int offset = SIGNATURE_OFFSET + SIGNATURE_SIZE;
+
+ byte[] bytes = dex.getBytes();
+ digest.update(bytes, offset, bytes.length - offset);
+ return digest.digest();
+ }
+
+ /**
+ * Returns the checksum of all but the first 12 bytes of {@code dex}.
+ */
+ public int computeChecksum(DexBuffer dex) throws IOException {
+ Adler32 adler32 = new Adler32();
+ int offset = CHECKSUM_OFFSET + CHECKSUM_SIZE;
+
+ byte[] bytes = dex.getBytes();
+ adler32.update(bytes, offset, bytes.length - offset);
+ return (int) adler32.getValue();
+ }
+
+ /**
+ * Generates the signature and checksum of the dex file {@code out} and
+ * writes them to the file.
+ */
+ public void writeHashes(DexBuffer dex) throws IOException {
+ byte[] signature = computeSignature(dex);
+ dex.open(SIGNATURE_OFFSET).write(signature);
+
+ int checksum = computeChecksum(dex);
+ dex.open(CHECKSUM_OFFSET).writeInt(checksum);
+ }
+}
diff --git a/dx/src/com/android/dx/io/DexIndexPrinter.java b/dx/src/com/android/dx/io/DexIndexPrinter.java
new file mode 100644
index 0000000..e4996bd
--- /dev/null
+++ b/dx/src/com/android/dx/io/DexIndexPrinter.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.dex.TableOfContents;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Executable that prints all indices of a dex file.
+ */
+public final class DexIndexPrinter {
+ private final DexBuffer dexBuffer;
+ private final TableOfContents tableOfContents;
+
+ public DexIndexPrinter(File file) throws IOException {
+ this.dexBuffer = new DexBuffer();
+ this.dexBuffer.loadFrom(file);
+ this.tableOfContents = dexBuffer.getTableOfContents();
+ }
+
+ private void printMap() {
+ for (TableOfContents.Section section : tableOfContents.sections) {
+ if (section.off != -1) {
+ System.out.println("section " + Integer.toHexString(section.type)
+ + " off=" + Integer.toHexString(section.off)
+ + " size=" + Integer.toHexString(section.size)
+ + " byteCount=" + Integer.toHexString(section.byteCount));
+ }
+ }
+ }
+
+ private void printStrings() throws IOException {
+ DexBuffer.Section in = dexBuffer.open(tableOfContents.stringIds.off);
+ for (int i = 0; i < tableOfContents.stringIds.size; i++) {
+ String s = in.readString(i);
+ System.out.println("string " + i + ": " + s);
+ }
+ }
+
+ private void printTypeIds() throws IOException {
+ DexBuffer.Section in = dexBuffer.open(tableOfContents.typeIds.off);
+ for (int i = 0; i < tableOfContents.typeIds.size; i++) {
+ int stringIndex = in.readInt();
+ System.out.println("type " + i + ": " + in.readString(stringIndex));
+ }
+ }
+
+ private void printProtoIds() throws IOException {
+ DexBuffer.Section in = dexBuffer.open(tableOfContents.protoIds.off);
+ for (int i = 0; i < tableOfContents.protoIds.size; i++) {
+ System.out.println("proto " + i + ": " + in.readProtoId());
+ }
+ }
+
+ private void printFieldIds() throws IOException {
+ DexBuffer.Section in = dexBuffer.open(tableOfContents.fieldIds.off);
+ for (int i = 0; i < tableOfContents.fieldIds.size; i++) {
+ System.out.println("field " + i + ": " + in.readFieldId());
+ }
+ }
+
+ private void printMethodIds() throws IOException {
+ DexBuffer.Section in = dexBuffer.open(tableOfContents.methodIds.off);
+ for (int i = 0; i < tableOfContents.methodIds.size; i++) {
+ System.out.println("method " + i + ": " + in.readMethodId());
+ }
+ }
+
+ private void printTypeLists() throws IOException {
+ if (tableOfContents.typeLists.off == -1) {
+ System.out.println("No type lists");
+ return;
+ }
+ DexBuffer.Section in = dexBuffer.open(tableOfContents.typeLists.off);
+ for (int i = 0; i < tableOfContents.typeLists.size; i++) {
+ int size = in.readInt();
+ System.out.print("Type list i=" + i + ", size=" + size + ", elements=");
+ for (int t = 0; t < size; t++) {
+ System.out.print(" " + in.readTypeName((int) in.readShort()));
+ }
+ if (size % 2 == 1) {
+ in.readShort(); // retain alignment
+ }
+ System.out.println();
+ }
+ }
+
+ private void printClassDefs() {
+ DexBuffer.Section in = dexBuffer.open(tableOfContents.classDefs.off);
+ for (int i = 0; i < tableOfContents.classDefs.size; i++) {
+ System.out.println("class def " + i + ": " + in.readClassDef());
+ }
+ }
+
+ public static void main(String[] args) throws IOException {
+ DexIndexPrinter indexPrinter = new DexIndexPrinter(new File(args[0]));
+ indexPrinter.printMap();
+ indexPrinter.printStrings();
+ indexPrinter.printTypeIds();
+ indexPrinter.printProtoIds();
+ indexPrinter.printFieldIds();
+ indexPrinter.printMethodIds();
+ indexPrinter.printTypeLists();
+ indexPrinter.printClassDefs();
+ }
+}
diff --git a/dx/src/com/android/dx/io/FieldId.java b/dx/src/com/android/dx/io/FieldId.java
new file mode 100644
index 0000000..c0eeac3
--- /dev/null
+++ b/dx/src/com/android/dx/io/FieldId.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.util.Unsigned;
+import java.io.IOException;
+
+public final class FieldId implements Comparable<FieldId> {
+ private final DexBuffer buffer;
+ private final short declaringClassIndex;
+ private final short typeIndex;
+ private final int nameIndex;
+
+ public FieldId(DexBuffer buffer, short declaringClassIndex, short typeIndex, int nameIndex) {
+ this.buffer = buffer;
+ this.declaringClassIndex = declaringClassIndex;
+ this.typeIndex = typeIndex;
+ this.nameIndex = nameIndex;
+ }
+
+ public short getDeclaringClassIndex() {
+ return declaringClassIndex;
+ }
+
+ public short getTypeIndex() {
+ return typeIndex;
+ }
+
+ public int getNameIndex() {
+ return nameIndex;
+ }
+
+ public int compareTo(FieldId other) {
+ if (declaringClassIndex != other.declaringClassIndex) {
+ return Unsigned.compare(declaringClassIndex, other.declaringClassIndex);
+ }
+ if (nameIndex != other.nameIndex) {
+ return Unsigned.compare(nameIndex, other.nameIndex);
+ }
+ return Unsigned.compare(typeIndex, other.typeIndex); // should always be 0
+ }
+
+ public void writeTo(DexBuffer.Section out) throws IOException {
+ out.writeShort(declaringClassIndex);
+ out.writeShort(typeIndex);
+ out.writeInt(nameIndex);
+ }
+
+ @Override public String toString() {
+ if (buffer == null) {
+ return declaringClassIndex + " " + typeIndex + " " + nameIndex;
+ }
+ DexBuffer.Section in = buffer.open(0);
+ return in.readType(declaringClassIndex)
+ + " { " + in.readTypeName(typeIndex)
+ + " " + in.readString(nameIndex) + " }";
+ }
+}
diff --git a/dx/src/com/android/dx/io/MethodId.java b/dx/src/com/android/dx/io/MethodId.java
new file mode 100644
index 0000000..9498b68
--- /dev/null
+++ b/dx/src/com/android/dx/io/MethodId.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.util.Unsigned;
+import java.io.IOException;
+
+public final class MethodId implements Comparable<MethodId> {
+ private final DexBuffer buffer;
+ private final short declaringClassIndex;
+ private final short protoIndex;
+ private final int nameIndex;
+
+ public MethodId(DexBuffer buffer, short declaringClassIndex, short protoIndex, int nameIndex) {
+ this.buffer = buffer;
+ this.declaringClassIndex = declaringClassIndex;
+ this.protoIndex = protoIndex;
+ this.nameIndex = nameIndex;
+ }
+
+ public short getDeclaringClassIndex() {
+ return declaringClassIndex;
+ }
+
+ public short getProtoIndex() {
+ return protoIndex;
+ }
+
+ public int getNameIndex() {
+ return nameIndex;
+ }
+
+ public int compareTo(MethodId other) {
+ if (declaringClassIndex != other.declaringClassIndex) {
+ return Unsigned.compare(declaringClassIndex, other.declaringClassIndex);
+ }
+ if (nameIndex != other.nameIndex) {
+ return Unsigned.compare(nameIndex, other.nameIndex);
+ }
+ return Unsigned.compare(protoIndex, other.protoIndex);
+ }
+
+ public void writeTo(DexBuffer.Section out) throws IOException {
+ out.writeShort(declaringClassIndex);
+ out.writeShort(protoIndex);
+ out.writeInt(nameIndex);
+ }
+
+ @Override public String toString() {
+ if (buffer == null) {
+ return declaringClassIndex + " " + protoIndex + " " + nameIndex;
+ }
+ DexBuffer.Section in = buffer.open(0);
+ return in.readTypeName(declaringClassIndex)
+ + " " + in.readProtoId(protoIndex)
+ + " " + in.readString(nameIndex);
+ }
+}
diff --git a/dx/src/com/android/dx/io/ProtoId.java b/dx/src/com/android/dx/io/ProtoId.java
new file mode 100644
index 0000000..dcab90f
--- /dev/null
+++ b/dx/src/com/android/dx/io/ProtoId.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.util.Unsigned;
+import java.io.IOException;
+import java.util.Arrays;
+
+public final class ProtoId implements Comparable<ProtoId> {
+ private final DexBuffer buffer;
+ private final int shortyIndex;
+ private final int returnTypeIndex;
+ private final short[] parameters;
+
+ public ProtoId(DexBuffer buffer, int shortyIndex, int returnTypeIndex, short[] parameters) {
+ this.buffer = buffer;
+ this.shortyIndex = shortyIndex;
+ this.returnTypeIndex = returnTypeIndex;
+ this.parameters = parameters;
+ }
+
+ public int compareTo(ProtoId other) {
+ if (returnTypeIndex != other.returnTypeIndex) {
+ return Unsigned.compare(returnTypeIndex, other.returnTypeIndex);
+ }
+ for (int i = 0; i < parameters.length && i < other.parameters.length; i++) {
+ if (parameters[i] != other.parameters[i]) {
+ return Unsigned.compare(parameters[i], other.parameters[i]);
+ }
+ }
+ return Unsigned.compare(parameters.length, other.parameters.length);
+ }
+
+ public int getShortyIndex() {
+ return shortyIndex;
+ }
+
+ public int getReturnTypeIndex() {
+ return returnTypeIndex;
+ }
+
+ public short[] getParameters() {
+ return parameters;
+ }
+
+ public void writeTo(DexBuffer.Section out, int typeListOffset) throws IOException {
+ out.writeInt(shortyIndex);
+ out.writeInt(returnTypeIndex);
+ out.writeInt(typeListOffset);
+ }
+
+ @Override public String toString() {
+ if (buffer == null) {
+ return shortyIndex + " " + returnTypeIndex + " " + Arrays.toString(parameters);
+ }
+
+ DexBuffer.Section in = buffer.open(0);
+ StringBuilder result = new StringBuilder()
+ .append(in.readString(shortyIndex))
+ .append(": ")
+ .append(in.readTypeName(returnTypeIndex))
+ .append(" (");
+ int j = 0;
+ for (short parameter : parameters) {
+ if (j > 0) {
+ result.append(", ");
+ }
+ result.append(in.readTypeName(parameter));
+ j++;
+ }
+ result.append(")");
+ return result.toString();
+ }
+}
diff --git a/dx/src/com/android/dx/merge/DexHasher.java b/dx/src/com/android/dx/merge/DexHasher.java
deleted file mode 100644
index 43b0df4..0000000
--- a/dx/src/com/android/dx/merge/DexHasher.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dx.merge;
-
-import com.android.dx.dex.SizeOf;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.RandomAccessFile;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.zip.Adler32;
-
-/**
- * Generates and stores the checksum and signature of a dex file.
- */
-public final class DexHasher {
-
- /**
- * Returns the signature of all but the first 32 bytes of {@code dex}. The
- * first 32 bytes of dex files are not specified to be included in the
- * signature.
- */
- public byte[] computeSignature(File dex) throws IOException {
- MessageDigest digest;
- try {
- digest = MessageDigest.getInstance("SHA-1");
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError();
- }
-
- FileInputStream in = new FileInputStream(dex);
- skipFully(in, 32);
-
- byte[] buffer = new byte[8192];
- int count;
- while ((count = in.read(buffer)) != -1) {
- digest.update(buffer, 0, count);
- }
-
- return digest.digest();
- }
-
- /**
- * Returns the checksum of all but the first 12 bytes of {@code dex}.
- *
- * @param signature either a 20-byte signature of {@code dex}, or null. If
- * non-null, the checksum will be computed using {@code signature}
- * rather than the corresponding bytes in the file.
- */
- public int computeChecksum(File dex, byte[] signature) throws IOException {
- Adler32 adler32 = new Adler32();
-
- FileInputStream in = new FileInputStream(dex);
- skipFully(in, 12);
-
- if (signature != null) {
- adler32.update(signature);
- skipFully(in, SizeOf.SIGNATURE);
- }
-
- byte[] buffer = new byte[8192];
- int count;
- while ((count = in.read(buffer)) != -1) {
- adler32.update(buffer, 0, count);
- }
-
- return (int) adler32.getValue();
- }
-
- /**
- * Generates the signature and checksum of the dex file {@code out} and
- * writes them to the file.
- */
- public void writeHashes(File out) throws IOException {
- byte[] signature = computeSignature(out);
- int checksum = computeChecksum(out, signature);
-
- RandomAccessFile file = new RandomAccessFile(out, "rw");
- file.seek(8);
- file.writeInt(Integer.reverseBytes(checksum));
- file.write(signature);
- file.close();
- }
-
- private void skipFully(InputStream in, int count) throws IOException {
- int total = 0;
- while (total < count) {
- total += in.skip(count);
- }
- }
-}
diff --git a/dx/src/com/android/dx/merge/DexMerger.java b/dx/src/com/android/dx/merge/DexMerger.java
index 54adff2..7e8321a 100644
--- a/dx/src/com/android/dx/merge/DexMerger.java
+++ b/dx/src/com/android/dx/merge/DexMerger.java
@@ -18,8 +18,12 @@
import com.android.dx.dex.SizeOf;
import com.android.dx.dex.TableOfContents;
-import com.android.dx.util.DexReader;
-import com.android.dx.util.DexWriter;
+import com.android.dx.io.ClassDef;
+import com.android.dx.io.DexBuffer;
+import com.android.dx.io.DexHasher;
+import com.android.dx.io.FieldId;
+import com.android.dx.io.MethodId;
+import com.android.dx.io.ProtoId;
import com.android.dx.util.Uint;
import java.io.File;
import java.io.IOException;
@@ -30,30 +34,27 @@
* Combine two dex files into one.
*/
public final class DexMerger {
- public static final int NO_INDEX = -1;
private static final Logger logger = Logger.getLogger(DexMerger.class.getName());
private final File dexOut;
- private final DexWriter dexWriter;
- private final DexWriter.Section headerWriter;
- private final DexWriter.Section idsDefsWriter;
- private final DexWriter.Section mapListWriter;
- private final DexWriter.Section typeListWriter;
- private final DexWriter.Section annotationSetRefListWriter;
- private final DexWriter.Section annotationSetItemWriter;
- private final DexWriter.Section classDataItemWriter;
- private final DexWriter.Section codeItemWriter;
- private final DexWriter.Section stringDataItemWriter;
- private final DexWriter.Section debugInfoItemWriter;
- private final DexWriter.Section annotationItemWriter;
- private final DexWriter.Section encodedArrayItemWriter;
- private final DexWriter.Section annotationsDirectoryItemWriter;
- private final TableOfContents contentsOut = new TableOfContents();
- private final DexReader dexA;
- private final DexReader dexB;
- private final TableOfContents contentsA;
- private final TableOfContents contentsB;
+ private final DexBuffer dexWriter = new DexBuffer();
+ private final DexBuffer.Section headerWriter;
+ private final DexBuffer.Section idsDefsWriter;
+ private final DexBuffer.Section mapListWriter;
+ private final DexBuffer.Section typeListWriter;
+ private final DexBuffer.Section annotationSetRefListWriter;
+ private final DexBuffer.Section annotationSetItemWriter;
+ private final DexBuffer.Section classDataItemWriter;
+ private final DexBuffer.Section codeItemWriter;
+ private final DexBuffer.Section stringDataItemWriter;
+ private final DexBuffer.Section debugInfoItemWriter;
+ private final DexBuffer.Section annotationItemWriter;
+ private final DexBuffer.Section encodedArrayItemWriter;
+ private final DexBuffer.Section annotationsDirectoryItemWriter;
+ private final TableOfContents contentsOut;
+ private final DexBuffer dexA = new DexBuffer();
+ private final DexBuffer dexB = new DexBuffer();
private final IndexMap aIndexMap;
private final IndexMap bIndexMap;
@@ -64,34 +65,34 @@
this.dexOut = dexOut;
- dexWriter = new DexWriter(dexOut);
- dexA = new DexReader(a);
- dexB = new DexReader(b);
- contentsA = dexA.getTableOfContents();
- contentsB = dexB.getTableOfContents();
+ dexA.loadFrom(a);
+ dexB.loadFrom(b);
- aIndexMap = new IndexMap(contentsA);
- bIndexMap = new IndexMap(contentsB);
+ TableOfContents aContents = dexA.getTableOfContents();
+ TableOfContents bContents = dexB.getTableOfContents();
- // header
- headerWriter = dexWriter.newSection(SizeOf.HEADER_ITEM, "header");
+ aIndexMap = new IndexMap(dexWriter, aContents);
+ bIndexMap = new IndexMap(dexWriter, bContents);
+
+ headerWriter = dexWriter.appendSection(SizeOf.HEADER_ITEM, "header");
// All IDs and definitions sections
int idsDefsMaxSize
- = (contentsA.stringIds.size + contentsB.stringIds.size) * SizeOf.STRING_ID_ITEM
- + (contentsA.typeIds.size + contentsB.typeIds.size) * SizeOf.TYPE_ID_ITEM
- + (contentsA.protoIds.size + contentsB.protoIds.size) * SizeOf.PROTO_ID_ITEM
- + (contentsA.fieldIds.size + contentsB.fieldIds.size) * SizeOf.MEMBER_ID_ITEM
- + (contentsA.methodIds.size + contentsB.methodIds.size) * SizeOf.MEMBER_ID_ITEM
- + (contentsA.classDefs.size + contentsB.classDefs.size) * SizeOf.CLASS_DEF_ITEM;
- idsDefsWriter = dexWriter.newSection(idsDefsMaxSize, "ids defs");
+ = (aContents.stringIds.size + bContents.stringIds.size) * SizeOf.STRING_ID_ITEM
+ + (aContents.typeIds.size + bContents.typeIds.size) * SizeOf.TYPE_ID_ITEM
+ + (aContents.protoIds.size + bContents.protoIds.size) * SizeOf.PROTO_ID_ITEM
+ + (aContents.fieldIds.size + bContents.fieldIds.size) * SizeOf.MEMBER_ID_ITEM
+ + (aContents.methodIds.size + bContents.methodIds.size) * SizeOf.MEMBER_ID_ITEM
+ + (aContents.classDefs.size + bContents.classDefs.size) * SizeOf.CLASS_DEF_ITEM;
+ idsDefsWriter = dexWriter.appendSection(idsDefsMaxSize, "ids defs");
// data section
+ contentsOut = dexWriter.getTableOfContents();
contentsOut.dataOff = dexWriter.getLength();
contentsOut.mapList.off = dexWriter.getLength();
contentsOut.mapList.size = 1;
- mapListWriter = dexWriter.newSection(SizeOf.UINT
+ mapListWriter = dexWriter.appendSection(SizeOf.UINT
+ (contentsOut.sections.length * SizeOf.MAP_ITEM), "map list");
/*
@@ -110,58 +111,59 @@
contentsOut.typeLists.off = dexWriter.getLength();
contentsOut.typeLists.size = 0;
- int maxTypeListBytes = contentsA.typeLists.byteCount + contentsB.typeLists.byteCount;
- typeListWriter = dexWriter.newSection(maxTypeListBytes * 5, "type list");
+ int maxTypeListBytes = aContents.typeLists.byteCount + bContents.typeLists.byteCount;
+ typeListWriter = dexWriter.appendSection(maxTypeListBytes * 5, "type list");
contentsOut.annotationSetRefLists.off = dexWriter.getLength();
contentsOut.annotationSetRefLists.size = 0;
- annotationSetRefListWriter = dexWriter.newSection(SizeOf.UINT, "annotation set ref list");
+ annotationSetRefListWriter = dexWriter.appendSection(SizeOf.UINT, "annotation set ref list");
contentsOut.annotationSets.off = dexWriter.getLength();
contentsOut.annotationSets.size = 0;
- annotationSetItemWriter = dexWriter.newSection(SizeOf.UINT, "annotation set item");
+ annotationSetItemWriter = dexWriter.appendSection(SizeOf.UINT, "annotation set item");
contentsOut.classDatas.off = dexWriter.getLength();
contentsOut.classDatas.size = 0;
- int maxClassDataItemBytes = contentsA.classDatas.byteCount + contentsB.classDatas.byteCount;
- classDataItemWriter = dexWriter.newSection(maxClassDataItemBytes * 2, "class data");
+ int maxClassDataItemBytes = aContents.classDatas.byteCount + bContents.classDatas.byteCount;
+ classDataItemWriter = dexWriter.appendSection(maxClassDataItemBytes * 2, "class data");
contentsOut.codes.off = dexWriter.getLength();
contentsOut.codes.size = 0;
- int maxCodeItemBytes = contentsA.codes.byteCount + contentsB.codes.byteCount;
- codeItemWriter = dexWriter.newSection(maxCodeItemBytes, "code item");
+ int maxCodeItemBytes = aContents.codes.byteCount + bContents.codes.byteCount;
+ codeItemWriter = dexWriter.appendSection(maxCodeItemBytes, "code item");
contentsOut.stringDatas.off = dexWriter.getLength();
contentsOut.stringDatas.size = 0;
- int maxStringDataItemBytes = contentsA.stringDatas.byteCount
- + contentsB.stringDatas.byteCount;
- stringDataItemWriter = dexWriter.newSection(maxStringDataItemBytes * 2, "string data");
+ int maxStringDataItemBytes = aContents.stringDatas.byteCount
+ + bContents.stringDatas.byteCount;
+ stringDataItemWriter = dexWriter.appendSection(maxStringDataItemBytes * 2, "string data");
contentsOut.debugInfos.off = dexWriter.getLength();
contentsOut.debugInfos.size = 0;
- int maxDebugInfoItemBytes = contentsA.debugInfos.byteCount + contentsB.debugInfos.byteCount;
- debugInfoItemWriter = dexWriter.newSection(maxDebugInfoItemBytes, "debug info");
+ int maxDebugInfoItemBytes = aContents.debugInfos.byteCount + bContents.debugInfos.byteCount;
+ debugInfoItemWriter = dexWriter.appendSection(maxDebugInfoItemBytes, "debug info");
contentsOut.annotations.off = dexWriter.getLength();
contentsOut.annotations.size = 0;
- int maxAnnotationItemBytes = contentsA.annotations.byteCount
- + contentsB.annotations.byteCount;
- annotationItemWriter = dexWriter.newSection(maxAnnotationItemBytes, "annotation");
+ int maxAnnotationItemBytes = aContents.annotations.byteCount
+ + bContents.annotations.byteCount;
+ annotationItemWriter = dexWriter.appendSection(maxAnnotationItemBytes, "annotation");
contentsOut.encodedArrays.off = dexWriter.getLength();
contentsOut.encodedArrays.size = 0;
- int maxEncodedArrayItemBytes = contentsA.encodedArrays.byteCount
- + contentsB.encodedArrays.byteCount;
- encodedArrayItemWriter = dexWriter.newSection(
+ int maxEncodedArrayItemBytes = aContents.encodedArrays.byteCount
+ + bContents.encodedArrays.byteCount;
+ encodedArrayItemWriter = dexWriter.appendSection(
maxEncodedArrayItemBytes * 2, "encoded array");
contentsOut.annotationsDirectories.off = dexWriter.getLength();
contentsOut.annotationsDirectories.size = 0;
- int maxAnnotationsDirectoryItemBytes = contentsA.annotationsDirectories.byteCount
- + contentsB.annotationsDirectories.byteCount;
- annotationsDirectoryItemWriter = dexWriter.newSection(
+ int maxAnnotationsDirectoryItemBytes = aContents.annotationsDirectories.byteCount
+ + bContents.annotationsDirectories.byteCount;
+ annotationsDirectoryItemWriter = dexWriter.appendSection(
maxAnnotationsDirectoryItemBytes, "annotations");
+ dexWriter.noMoreSections();
contentsOut.dataSize = dexWriter.getLength() - contentsOut.dataOff;
}
@@ -183,8 +185,8 @@
contentsOut.writeMap(mapListWriter);
// close (and flush) the result, then reopen to generate and write the hashes
- dexWriter.close();
- new DexHasher().writeHashes(dexOut);
+ new DexHasher().writeHashes(dexWriter);
+ dexWriter.writeTo(dexOut);
long elapsed = System.nanoTime() - start;
logger.info(String.format("Merged. Result length=%.1fKiB. Took %.1fs",
@@ -197,24 +199,24 @@
*/
abstract class IdMerger<T extends Comparable<T>> {
public final void merge() throws IOException {
- dexA.seek(getSection(contentsA).off);
- dexB.seek(getSection(contentsB).off);
- getSection(contentsOut).off = idsDefsWriter.getCursor();
+ TableOfContents.Section aSection = getSection(dexA.getTableOfContents());
+ TableOfContents.Section bSection = getSection(dexB.getTableOfContents());
+ DexBuffer.Section aIn = dexA.open(aSection.off);
+ DexBuffer.Section bIn = dexB.open(bSection.off);
+ getSection(contentsOut).off = idsDefsWriter.getPosition();
int aIndex = 0;
int bIndex = 0;
int outCount = 0;
- int aCount = getSection(contentsA).size;
- int bCount = getSection(contentsB).size;
T a = null;
T b = null;
while (true) {
- if (a == null && aIndex < aCount) {
- a = read(dexA, aIndexMap, aIndex);
+ if (a == null && aIndex < aSection.size) {
+ a = read(aIn, aIndexMap, aIndex);
}
- if (b == null && bIndex < bCount) {
- b = read(dexB, bIndexMap, bIndex);
+ if (b == null && bIndex < bSection.size) {
+ b = read(bIn, bIndexMap, bIndex);
}
// Write the smaller of a and b. If they're equal, write only once
@@ -251,7 +253,7 @@
}
abstract TableOfContents.Section getSection(TableOfContents tableOfContents);
- abstract T read(DexReader in, IndexMap indexMap, int index) throws IOException;
+ abstract T read(DexBuffer.Section in, IndexMap indexMap, int index) throws IOException;
abstract void updateIndex(IndexMap indexMap, int oldIndex, int newIndex);
abstract void write(T value) throws IOException;
}
@@ -262,7 +264,8 @@
return tableOfContents.stringIds;
}
- @Override String read(DexReader in, IndexMap indexMap, int index) throws IOException {
+ @Override String read(DexBuffer.Section in, IndexMap indexMap, int index)
+ throws IOException {
return in.readString(index);
}
@@ -272,7 +275,7 @@
@Override void write(String value) throws IOException {
contentsOut.stringDatas.size++;
- idsDefsWriter.writeInt(stringDataItemWriter.getCursor());
+ idsDefsWriter.writeInt(stringDataItemWriter.getPosition());
stringDataItemWriter.writeStringDataItem(value);
}
}.merge();
@@ -284,12 +287,13 @@
return tableOfContents.typeIds;
}
- @Override Uint read(DexReader in, IndexMap indexMap, int index) throws IOException {
- return new Uint(indexMap.stringIds[in.readInt()]);
+ @Override Uint read(DexBuffer.Section in, IndexMap indexMap, int index)
+ throws IOException {
+ return new Uint(indexMap.adjustString(in.readInt()));
}
@Override void updateIndex(IndexMap indexMap, int oldIndex, int newIndex) {
- indexMap.typeIds[oldIndex] = newIndex;
+ indexMap.typeIds[oldIndex] = (short) newIndex;
}
@Override void write(Uint value) throws IOException {
@@ -304,14 +308,13 @@
return tableOfContents.protoIds;
}
- @Override ProtoId read(DexReader in, IndexMap indexMap, int index) throws IOException {
- ProtoId result = new ProtoId(in);
- result.adjust(indexMap);
- return result;
+ @Override ProtoId read(DexBuffer.Section in, IndexMap indexMap, int index)
+ throws IOException {
+ return indexMap.adjust(in.readProtoId());
}
@Override void updateIndex(IndexMap indexMap, int oldIndex, int newIndex) {
- indexMap.protoIds[oldIndex] = newIndex;
+ indexMap.protoIds[oldIndex] = (short) newIndex;
}
@Override void write(ProtoId value) throws IOException {
@@ -327,14 +330,13 @@
return tableOfContents.fieldIds;
}
- @Override FieldId read(DexReader in, IndexMap indexMap, int index) throws IOException {
- FieldId result = new FieldId(in);
- result.adjust(indexMap);
- return result;
+ @Override
+ FieldId read(DexBuffer.Section in, IndexMap indexMap, int index) throws IOException {
+ return indexMap.adjust(in.readFieldId());
}
@Override void updateIndex(IndexMap indexMap, int oldIndex, int newIndex) {
- indexMap.fieldIds[oldIndex] = newIndex;
+ indexMap.fieldIds[oldIndex] = (short) newIndex;
}
@Override void write(FieldId value) throws IOException {
@@ -349,14 +351,13 @@
return tableOfContents.methodIds;
}
- @Override MethodId read(DexReader in, IndexMap indexMap, int index) throws IOException {
- MethodId result = new MethodId(in);
- result.adjust(indexMap);
- return result;
+ @Override MethodId read(DexBuffer.Section in, IndexMap indexMap, int index)
+ throws IOException {
+ return indexMap.adjust(in.readMethodId());
}
@Override void updateIndex(IndexMap indexMap, int oldIndex, int newIndex) {
- indexMap.methodIds[oldIndex] = newIndex;
+ indexMap.methodIds[oldIndex] = (short) newIndex;
}
@Override void write(MethodId methodId) throws IOException {
@@ -367,13 +368,13 @@
private void mergeClassDefs() throws IOException {
SortableType[] types = getSortedTypes();
- contentsOut.classDefs.off = idsDefsWriter.getCursor();
+ contentsOut.classDefs.off = idsDefsWriter.getPosition();
contentsOut.classDefs.size = types.length;
for (SortableType type : types) {
- DexReader in = type.prepareReader();
+ DexBuffer in = type.getBuffer();
IndexMap indexMap = (in == dexA) ? aIndexMap : bIndexMap;
- transformClassDef(in, indexMap);
+ transformClassDef(in, type.getClassDef(), indexMap);
}
}
@@ -417,15 +418,15 @@
* Reads just enough data on each class so that we can sort it and then find
* it later.
*/
- private void readSortableTypes(SortableType[] sortableTypes, DexReader reader,
+ private void readSortableTypes(SortableType[] sortableTypes, DexBuffer buffer,
IndexMap indexMap) throws IOException {
- TableOfContents tableOfContents = reader.getTableOfContents();
- reader.seek(tableOfContents.classDefs.off);
+ TableOfContents tableOfContents = buffer.getTableOfContents();
+ DexBuffer.Section classDefsIn = buffer.open(tableOfContents.classDefs.off);
for (int i = 0; i < tableOfContents.classDefs.size; i++) {
- SortableType sortableType = new SortableType(reader);
- sortableType.adjust(indexMap);
- int t = sortableType.getType();
+ SortableType sortableType = indexMap.adjust(
+ new SortableType(buffer, classDefsIn.readClassDef()));
+ int t = sortableType.getTypeIndex();
if (sortableTypes[t] == null) {
sortableTypes[t] = sortableType;
}
@@ -436,60 +437,47 @@
* Reads a class_def_item beginning at {@code in} and writes the index and
* data.
*/
- private void transformClassDef(DexReader in, IndexMap indexMap) throws IOException {
+ private void transformClassDef(DexBuffer in, ClassDef classDef, IndexMap indexMap)
+ throws IOException {
idsDefsWriter.assertFourByteAligned();
- idsDefsWriter.writeInt(indexMap.typeIds[in.readInt()]); // class idx
- idsDefsWriter.writeInt(in.readInt()); // access flags
- int inSuperclassIndex = in.readInt(); // superclass idx
- int outSuperclassIndex = inSuperclassIndex != NO_INDEX
- ? indexMap.typeIds[inSuperclassIndex]
- : NO_INDEX;
- idsDefsWriter.writeInt(outSuperclassIndex);
+ idsDefsWriter.writeInt(classDef.getTypeIndex());
+ idsDefsWriter.writeInt(classDef.getAccessFlags());
+ idsDefsWriter.writeInt(classDef.getSupertypeIndex());
- int interfaceOff = in.readInt(); // interface off
- short[] interfaces = in.readTypeList(interfaceOff);
- indexMap.adjustTypeList(interfaces);
+ short[] interfaces = classDef.getInterfaces();
int typeListPosition = writeTypeList(interfaces);
idsDefsWriter.writeInt(typeListPosition);
- int sourceFileIndex = in.readInt(); // source file idx
- if (sourceFileIndex != NO_INDEX) {
- sourceFileIndex = indexMap.stringIds[sourceFileIndex];
- }
+ int sourceFileIndex = indexMap.adjustString(
+ classDef.getSourceFileIndex()); // source file idx
idsDefsWriter.writeInt(sourceFileIndex);
- int annotationsOff = in.readInt(); // annotations off
+ int annotationsOff = classDef.getAnnotationsOffset();
if (annotationsOff == 0) {
idsDefsWriter.writeInt(0);
} else {
- int position = in.getPosition();
- in.seek(annotationsOff);
+ DexBuffer.Section annotationsIn = in.open(annotationsOff);
annotationsDirectoryItemWriter.alignToFourBytes();
- idsDefsWriter.writeInt(annotationsDirectoryItemWriter.getCursor());
- transformAnnotations(in, indexMap);
- in.seek(position);
+ idsDefsWriter.writeInt(annotationsDirectoryItemWriter.getPosition());
+ transformAnnotations(annotationsIn, indexMap);
}
- int classDataOff = in.readInt(); // class data off
+ int classDataOff = classDef.getClassDataOffset();
if (classDataOff == 0) {
idsDefsWriter.writeInt(0);
} else {
- int position = in.getPosition();
- in.seek(classDataOff);
- idsDefsWriter.writeInt(classDataItemWriter.getCursor());
- transformClassData(in, indexMap);
- in.seek(position);
+ DexBuffer.Section classDataIn = in.open(classDataOff);
+ idsDefsWriter.writeInt(classDataItemWriter.getPosition());
+ transformClassData(classDataIn, indexMap);
}
- int staticValuesOff = in.readInt(); // static values off
+ int staticValuesOff = classDef.getStaticValuesOffset();
if (staticValuesOff == 0) {
idsDefsWriter.writeInt(0);
} else {
- int position = in.getPosition();
- in.seek(staticValuesOff);
- idsDefsWriter.writeInt(encodedArrayItemWriter.getCursor());
- transformStaticValues(in, indexMap);
- in.seek(position);
+ DexBuffer.Section staticValuesIn = in.open(staticValuesOff);
+ idsDefsWriter.writeInt(encodedArrayItemWriter.getPosition());
+ transformStaticValues(staticValuesIn, indexMap);
}
}
@@ -499,13 +487,13 @@
}
contentsOut.typeLists.size++;
typeListWriter.alignToFourBytes();
- int cursor = typeListWriter.getCursor();
+ int cursor = typeListWriter.getPosition();
typeListWriter.writeInt(interfaces.length);
typeListWriter.write(interfaces);
return cursor;
}
- private void transformAnnotations(DexReader in, IndexMap indexMap) throws IOException {
+ private void transformAnnotations(DexBuffer.Section in, IndexMap indexMap) throws IOException {
contentsOut.annotationsDirectories.size++;
// TODO: retain annotations
@@ -521,7 +509,7 @@
annotationsDirectoryItemWriter.writeInt(0);
}
- private void transformClassData(DexReader in, IndexMap indexMap) throws IOException {
+ private void transformClassData(DexBuffer.Section in, IndexMap indexMap) throws IOException {
contentsOut.classDatas.size++;
int staticFieldsSize = in.readUleb128();
@@ -543,13 +531,13 @@
transformEncodedMethods(in, indexMap, virtualMethodsSize);
}
- private void transformEncodedFields(DexReader in, IndexMap indexMap, int count)
+ private void transformEncodedFields(DexBuffer.Section in, IndexMap indexMap, int count)
throws IOException {
int inFieldIndex = 0;
int lastOutFieldIndex = 0;
for (int i = 0; i < count; i++) {
inFieldIndex += in.readUleb128(); // field idx diff
- int outFieldIndex = indexMap.fieldIds[inFieldIndex];
+ int outFieldIndex = indexMap.adjustField(inFieldIndex);
classDataItemWriter.writeUleb128(outFieldIndex - lastOutFieldIndex);
lastOutFieldIndex = outFieldIndex;
@@ -560,13 +548,13 @@
/**
* Transforms a list of encoded methods.
*/
- private void transformEncodedMethods(DexReader in, IndexMap indexMap, int count)
+ private void transformEncodedMethods(DexBuffer.Section in, IndexMap indexMap, int count)
throws IOException {
int inMethodIndex = 0;
int lastOutMethodIndex = 0;
for (int i = 0; i < count; i++) {
inMethodIndex += in.readUleb128(); // method idx diff
- int outMethodIndex = indexMap.methodIds[inMethodIndex];
+ int outMethodIndex = indexMap.adjustMethod(inMethodIndex);
classDataItemWriter.writeUleb128(outMethodIndex - lastOutMethodIndex);
lastOutMethodIndex = outMethodIndex;
@@ -576,18 +564,14 @@
if (codeOff == 0) {
classDataItemWriter.writeUleb128(0);
} else {
- int inPosition = in.getPosition();
codeItemWriter.alignToFourBytes();
- classDataItemWriter.writeUleb128(codeItemWriter.getCursor());
-
- in.seek(codeOff);
- transformCodeItem(in, indexMap);
- in.seek(inPosition);
+ classDataItemWriter.writeUleb128(codeItemWriter.getPosition());
+ transformCodeItem(in.open(codeOff), indexMap);
}
}
}
- private void transformCodeItem(DexReader in, IndexMap indexMap) throws IOException {
+ private void transformCodeItem(DexBuffer.Section in, IndexMap indexMap) throws IOException {
contentsOut.codes.size++;
codeItemWriter.assertFourByteAligned();
@@ -628,13 +612,13 @@
}
}
- private void transformTryItem(DexReader in, IndexMap indexMap) throws IOException {
+ private void transformTryItem(DexBuffer.Section in, IndexMap indexMap) throws IOException {
codeItemWriter.writeInt(in.readInt()); // start addr
codeItemWriter.writeShort(in.readShort()); // insn count
codeItemWriter.writeShort(in.readShort()); // handler off
}
- private void transformEncodedCatchHandlerList(DexReader in, IndexMap indexMap)
+ private void transformEncodedCatchHandlerList(DexBuffer.Section in, IndexMap indexMap)
throws IOException {
int size = in.readUleb128(); // size
codeItemWriter.writeUleb128(size);
@@ -644,13 +628,14 @@
}
}
- private void transformEncodedCatchHandler(DexReader in, IndexMap indexMap) throws IOException {
+ private void transformEncodedCatchHandler(DexBuffer.Section in, IndexMap indexMap)
+ throws IOException {
int size = in.readSleb128(); // size
codeItemWriter.writeSleb128(size);
int handlersCount = Math.abs(size);
for (int i = 0; i < handlersCount; i++) {
- codeItemWriter.writeUleb128(indexMap.typeIds[in.readUleb128()]); // type idx
+ codeItemWriter.writeUleb128(indexMap.adjustType(in.readUleb128())); // type idx
codeItemWriter.writeUleb128(in.readUleb128()); // addr
}
@@ -659,7 +644,7 @@
}
}
- private void transformStaticValues(DexReader in, IndexMap indexMap) throws IOException {
+ private void transformStaticValues(DexBuffer.Section in, IndexMap indexMap) throws IOException {
contentsOut.encodedArrays.size++;
new EncodedValueTransformer(indexMap, in, encodedArrayItemWriter).transformArray();
}
diff --git a/dx/src/com/android/dx/merge/EncodedValueTransformer.java b/dx/src/com/android/dx/merge/EncodedValueTransformer.java
index aed59e8..68a9cd6 100644
--- a/dx/src/com/android/dx/merge/EncodedValueTransformer.java
+++ b/dx/src/com/android/dx/merge/EncodedValueTransformer.java
@@ -16,18 +16,16 @@
package com.android.dx.merge;
-import com.android.dx.util.DexReader;
-import com.android.dx.util.DexWriter;
+import com.android.dx.io.DexBuffer;
import com.android.dx.util.Unsigned;
import java.io.IOException;
-public final class EncodedValueTransformer {
-
+final class EncodedValueTransformer {
private final IndexMap indexMap;
- private final DexReader in;
- private final DexWriter.Section out;
+ private final DexBuffer.Section in;
+ private final DexBuffer.Section out;
- public EncodedValueTransformer(IndexMap indexMap, DexReader in, DexWriter.Section out) {
+ public EncodedValueTransformer(IndexMap indexMap, DexBuffer.Section in, DexBuffer.Section out) {
this.indexMap = indexMap;
this.in = in;
this.out = out;
@@ -42,13 +40,13 @@
}
public void transformAnnotation() throws IOException {
- out.writeUleb128(indexMap.typeIds[in.readUleb128()]); // type idx
+ out.writeUleb128(indexMap.adjustType(in.readUleb128())); // type idx
int size = in.readUleb128(); // size
out.writeUleb128(size);
for (int i = 0; i < size; i++) {
- out.writeUleb128(indexMap.stringIds[in.readUleb128()]); // name idx
+ out.writeUleb128(indexMap.adjustString(in.readUleb128())); // name idx
transformValue();
}
}
@@ -73,23 +71,23 @@
case 0x17: // string
int indexIn = readIndex(in, size);
- int indexOut = indexMap.stringIds[indexIn];
+ int indexOut = indexMap.adjustString(indexIn);
writeTypeAndSizeAndIndex(type, indexOut, out);
break;
case 0x18: // type
indexIn = readIndex(in, size);
- indexOut = indexMap.typeIds[indexIn];
+ indexOut = indexMap.adjustType(indexIn);
writeTypeAndSizeAndIndex(type, indexOut, out);
break;
case 0x19: // field
case 0x1b: // enum
indexIn = readIndex(in, size);
- indexOut = indexMap.fieldIds[indexIn];
+ indexOut = indexMap.adjustField(indexIn);
writeTypeAndSizeAndIndex(type, indexOut, out);
break;
case 0x1a: // method
indexIn = readIndex(in, size);
- indexOut = indexMap.methodIds[indexIn];
+ indexOut = indexMap.adjustMethod(indexIn);
writeTypeAndSizeAndIndex(type, indexOut, out);
break;
@@ -110,7 +108,7 @@
}
}
- private int readIndex(DexReader in, int byteCount) throws IOException {
+ private int readIndex(DexBuffer.Section in, int byteCount) throws IOException {
int result = 0;
int shift = 0;
for (int i = 0; i < byteCount; i++) {
@@ -120,7 +118,7 @@
return result;
}
- private void writeTypeAndSizeAndIndex(int type, int index, DexWriter.Section out)
+ private void writeTypeAndSizeAndIndex(int type, int index, DexBuffer.Section out)
throws IOException {
int byteCount;
if (Unsigned.compare(index, 0xff) <= 0) {
@@ -141,7 +139,8 @@
}
}
- private void copyBytes(DexReader in, DexWriter.Section out, int size) throws IOException {
+ private void copyBytes(DexBuffer.Section in, DexBuffer.Section out, int size)
+ throws IOException {
for (int i = 0; i < size; i++) {
out.writeByte(in.readByte());
}
diff --git a/dx/src/com/android/dx/merge/FieldId.java b/dx/src/com/android/dx/merge/FieldId.java
deleted file mode 100644
index aae94db..0000000
--- a/dx/src/com/android/dx/merge/FieldId.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dx.merge;
-
-import com.android.dx.util.DexReader;
-import com.android.dx.util.DexWriter;
-import com.android.dx.util.Unsigned;
-import java.io.IOException;
-
-public final class FieldId implements Comparable<FieldId> {
- private short classIndex;
- private short typeIndex;
- private int nameIndex;
-
- public FieldId(DexReader in) throws IOException {
- classIndex = in.readShort();
- typeIndex = in.readShort();
- nameIndex = in.readInt();
- }
-
- /**
- * Maps from one set of indices to another.
- */
- public void adjust(IndexMap indexMap) {
- classIndex = (short) indexMap.typeIds[classIndex];
- typeIndex = (short) indexMap.typeIds[typeIndex];
- nameIndex = (short) indexMap.stringIds[nameIndex];
- }
-
- public int compareTo(FieldId other) {
- if (classIndex != other.classIndex) {
- return Unsigned.compare(classIndex, other.classIndex);
- }
- if (nameIndex != other.nameIndex) {
- return Unsigned.compare(nameIndex, other.nameIndex);
- }
- return Unsigned.compare(typeIndex, other.typeIndex); // should always be 0
- }
-
- public void writeTo(DexWriter.Section out) throws IOException {
- out.writeShort(classIndex);
- out.writeShort(typeIndex);
- out.writeInt(nameIndex);
- }
-}
diff --git a/dx/src/com/android/dx/merge/IndexMap.java b/dx/src/com/android/dx/merge/IndexMap.java
index 1449d94..f12adc7 100644
--- a/dx/src/com/android/dx/merge/IndexMap.java
+++ b/dx/src/com/android/dx/merge/IndexMap.java
@@ -17,6 +17,11 @@
package com.android.dx.merge;
import com.android.dx.dex.TableOfContents;
+import com.android.dx.io.ClassDef;
+import com.android.dx.io.DexBuffer;
+import com.android.dx.io.FieldId;
+import com.android.dx.io.MethodId;
+import com.android.dx.io.ProtoId;
/**
* Maps the index offsets from one dex file to those in another. For example, if
@@ -24,23 +29,81 @@
* {@code strings[5]}.
*/
public final class IndexMap {
+ private final DexBuffer target;
public final int[] stringIds;
- public final int[] typeIds;
- public final int[] protoIds;
- public final int[] fieldIds;
- public final int[] methodIds;
+ public final short[] typeIds;
+ public final short[] protoIds;
+ public final short[] fieldIds;
+ public final short[] methodIds;
- public IndexMap(TableOfContents tableOfContents) {
- stringIds = new int[tableOfContents.stringIds.size];
- typeIds = new int[tableOfContents.typeIds.size];
- protoIds = new int[tableOfContents.protoIds.size];
- fieldIds = new int[tableOfContents.fieldIds.size];
- methodIds = new int[tableOfContents.methodIds.size];
+ public IndexMap(DexBuffer target, TableOfContents tableOfContents) {
+ this.target = target;
+ this.stringIds = new int[tableOfContents.stringIds.size];
+ this.typeIds = new short[tableOfContents.typeIds.size];
+ this.protoIds = new short[tableOfContents.protoIds.size];
+ this.fieldIds = new short[tableOfContents.fieldIds.size];
+ this.methodIds = new short[tableOfContents.methodIds.size];
}
- public void adjustTypeList(short[] typeList) {
+ public int adjustString(int stringIndex) {
+ return stringIndex == ClassDef.NO_INDEX ? ClassDef.NO_INDEX : stringIds[stringIndex];
+ }
+
+ public short adjustType(int typeIndex) {
+ return (typeIndex == ClassDef.NO_INDEX) ? ClassDef.NO_INDEX : typeIds[typeIndex];
+ }
+
+ public short[] adjustTypeList(short[] typeList) {
+ short[] result = new short[typeList.length];
for (int i = 0; i < typeList.length; i++) {
- typeList[i] = (short) typeIds[typeList[i]];
+ result[i] = adjustType(typeList[i]);
}
+ return result;
+ }
+
+ public short adjustProto(int protoIndex) {
+ return protoIds[protoIndex];
+ }
+
+ public short adjustField(int fieldIndex) {
+ return fieldIds[fieldIndex];
+ }
+
+ public short adjustMethod(int methodIndex) {
+ return methodIds[methodIndex];
+ }
+
+ public MethodId adjust(MethodId methodId) {
+ return new MethodId(target,
+ adjustType(methodId.getDeclaringClassIndex()),
+ adjustProto(methodId.getProtoIndex()),
+ adjustString(methodId.getNameIndex()));
+ }
+
+ public FieldId adjust(FieldId fieldId) {
+ return new FieldId(target,
+ adjustType(fieldId.getDeclaringClassIndex()),
+ adjustType(fieldId.getTypeIndex()),
+ adjustString(fieldId.getNameIndex()));
+
+ }
+
+ public ProtoId adjust(ProtoId protoId) {
+ return new ProtoId(target,
+ adjustString(protoId.getShortyIndex()),
+ adjustType(protoId.getReturnTypeIndex()),
+ adjustTypeList(protoId.getParameters()));
+ }
+
+ public ClassDef adjust(ClassDef classDef) {
+ return new ClassDef(target, classDef.getOffset(), adjustType(classDef.getTypeIndex()),
+ classDef.getAccessFlags(), adjustType(classDef.getSupertypeIndex()),
+ classDef.getInterfacesOffset(), adjustTypeList(classDef.getInterfaces()),
+ classDef.getSourceFileIndex(), classDef.getAnnotationsOffset(),
+ classDef.getClassDataOffset(), classDef.getStaticValuesOffset());
+ }
+
+ public SortableType adjust(SortableType sortableType) {
+ return new SortableType(sortableType.getBuffer(), adjust(sortableType.getClassDef()));
}
}
diff --git a/dx/src/com/android/dx/merge/InstructionTransformer.java b/dx/src/com/android/dx/merge/InstructionTransformer.java
index c8b84dd..1e0aa49 100644
--- a/dx/src/com/android/dx/merge/InstructionTransformer.java
+++ b/dx/src/com/android/dx/merge/InstructionTransformer.java
@@ -22,7 +22,7 @@
/**
* Adjusts a block of instructions to a new index.
*/
-public final class InstructionTransformer {
+final class InstructionTransformer {
private static final Instruction[] INSTRUCTIONS = new Instruction[] {
// 0x00...0x0f
@@ -342,7 +342,7 @@
@Override public void transform(short[] instructions, int i, IndexMap indexMap,
BitSet skippedInstructions) throws DexException {
int stringIndex = instructions[i + 1] & 0xFFFF;
- int mappedIndex = indexMap.stringIds[stringIndex];
+ int mappedIndex = indexMap.adjustString(stringIndex);
if (mappedIndex > 0xFFFF) {
throw new DexException("Cannot convert string to jumbo string!");
}
@@ -369,7 +369,7 @@
@Override public void transform(short[] instructions, int i, IndexMap indexMap,
BitSet skippedInstructions) throws DexException {
short field = instructions[i + 1];
- instructions[i + 1] = (short) indexMap.fieldIds[field];
+ instructions[i + 1] = (short) indexMap.adjustField(field);
}
}
@@ -380,7 +380,7 @@
@Override public void transform(short[] instructions, int i, IndexMap indexMap,
BitSet skippedInstructions) throws DexException {
short type = instructions[i + 1];
- instructions[i + 1] = (short) indexMap.typeIds[type];
+ instructions[i + 1] = (short) indexMap.adjustType(type);
}
}
@@ -391,7 +391,7 @@
@Override public void transform(short[] instructions, int i, IndexMap indexMap,
BitSet skippedInstructions) throws DexException {
short method = instructions[i + 1];
- instructions[i + 1] = (short) indexMap.methodIds[method];
+ instructions[i + 1] = (short) indexMap.adjustMethod(method);
}
}
diff --git a/dx/src/com/android/dx/merge/MethodId.java b/dx/src/com/android/dx/merge/MethodId.java
deleted file mode 100644
index 0b28204..0000000
--- a/dx/src/com/android/dx/merge/MethodId.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dx.merge;
-
-import com.android.dx.util.DexReader;
-import com.android.dx.util.DexWriter;
-import com.android.dx.util.Unsigned;
-import java.io.IOException;
-
-public final class MethodId implements Comparable<MethodId> {
- private short classIndex;
- private short protoIndex;
- private int nameIndex;
-
- public MethodId(DexReader in) throws IOException {
- classIndex = in.readShort();
- protoIndex = in.readShort();
- nameIndex = in.readInt();
- }
-
- /**
- * Maps from one set of indices to another.
- */
- public void adjust(IndexMap indexMap) {
- classIndex = (short) indexMap.typeIds[classIndex];
- protoIndex = (short) indexMap.protoIds[protoIndex];
- nameIndex = (short) indexMap.stringIds[nameIndex];
- }
-
- public int compareTo(MethodId other) {
- if (classIndex != other.classIndex) {
- return Unsigned.compare(classIndex, other.classIndex);
- }
- if (nameIndex != other.nameIndex) {
- return Unsigned.compare(nameIndex, other.nameIndex);
- }
- return Unsigned.compare(protoIndex, other.protoIndex);
- }
-
- public void writeTo(DexWriter.Section out) throws IOException {
- out.writeShort(classIndex);
- out.writeShort(protoIndex);
- out.writeInt(nameIndex);
- }
-}
diff --git a/dx/src/com/android/dx/merge/ProtoId.java b/dx/src/com/android/dx/merge/ProtoId.java
deleted file mode 100644
index f18a292..0000000
--- a/dx/src/com/android/dx/merge/ProtoId.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dx.merge;
-
-import com.android.dx.util.DexReader;
-import com.android.dx.util.DexWriter;
-import com.android.dx.util.Unsigned;
-import java.io.IOException;
-
-public final class ProtoId implements Comparable<ProtoId> {
- private int shorty;
- private int returnType;
- private short[] parameters;
-
- public ProtoId(DexReader in) throws IOException {
- shorty = in.readInt();
- returnType = in.readInt();
- int parametersOff = in.readInt();
- parameters = in.readTypeList(parametersOff);
- }
-
- /**
- * Maps from one set of indices to another.
- */
- public void adjust(IndexMap indexMap) {
- shorty = indexMap.stringIds[shorty];
- returnType = indexMap.typeIds[returnType];
- for (int i = 0; i < parameters.length; i++) {
- parameters[i] = (short) indexMap.typeIds[parameters[i]];
- }
- }
-
- public int compareTo(ProtoId other) {
- if (returnType != other.returnType) {
- return Unsigned.compare(returnType, other.returnType);
- }
- for (int i = 0; i < parameters.length && i < other.parameters.length; i++) {
- if (parameters[i] != other.parameters[i]) {
- return Unsigned.compare(parameters[i], other.parameters[i]);
- }
- }
- return Unsigned.compare(parameters.length, other.parameters.length);
- }
-
- public short[] getParameters() {
- return parameters;
- }
-
- public void writeTo(DexWriter.Section out, int typeListOffset) throws IOException {
- out.writeInt(shorty);
- out.writeInt(returnType);
- out.writeInt(typeListOffset);
- }
-}
diff --git a/dx/src/com/android/dx/merge/SortableType.java b/dx/src/com/android/dx/merge/SortableType.java
index 0d8399e..838ea28 100644
--- a/dx/src/com/android/dx/merge/SortableType.java
+++ b/dx/src/com/android/dx/merge/SortableType.java
@@ -16,15 +16,15 @@
package com.android.dx.merge;
-import com.android.dx.util.DexReader;
-import java.io.IOException;
+import com.android.dx.io.ClassDef;
+import com.android.dx.io.DexBuffer;
import java.util.Comparator;
/**
* Name and structure of a type. Used to order types such that each type is
* preceded by its supertype and implemented interfaces.
*/
-public final class SortableType {
+final class SortableType {
public static final Comparator<SortableType> NULLS_LAST_ORDER = new Comparator<SortableType>() {
public int compare(SortableType a, SortableType b) {
if (a == b) {
@@ -39,46 +39,29 @@
if (a.depth != b.depth) {
return a.depth - b.depth;
}
- return a.type - b.type;
+ return a.getTypeIndex() - b.getTypeIndex();
}
};
- private final DexReader reader;
- private final int offset;
- private int type;
- private int supertype;
- private final short[] interfaces;
+ private final DexBuffer buffer;
+ private ClassDef classDef;
private int depth = -1;
- public SortableType(DexReader reader) throws IOException {
- this.reader = reader;
- this.offset = reader.getPosition();
- this.type = reader.readInt(); // class idx
- reader.readInt(); // access flags
- this.supertype = reader.readInt(); // superclass idx
- int interfacesOff = reader.readInt(); // interface off
- this.interfaces = reader.readTypeList(interfacesOff);
- reader.readInt(); // source file index
- reader.readInt(); // annotations off
- reader.readInt(); // class data off
- reader.readInt(); // static values off
+ public SortableType(DexBuffer buffer, ClassDef classDef) {
+ this.buffer = buffer;
+ this.classDef = classDef;
}
- public void adjust(IndexMap indexMap) {
- type = indexMap.typeIds[type];
- if (supertype != DexMerger.NO_INDEX) {
- supertype = indexMap.typeIds[supertype];
- }
- indexMap.adjustTypeList(interfaces);
+ public DexBuffer getBuffer() {
+ return buffer;
}
- public DexReader prepareReader() throws IOException {
- reader.seek(offset);
- return reader;
+ public ClassDef getClassDef() {
+ return classDef;
}
- public int getType() {
- return type;
+ public int getTypeIndex() {
+ return classDef.getTypeIndex();
}
/**
@@ -88,10 +71,10 @@
*/
public boolean tryAssignDepth(SortableType[] types) {
int max;
- if (supertype == DexMerger.NO_INDEX) {
+ if (classDef.getSupertypeIndex() == ClassDef.NO_INDEX) {
max = 0; // this is Object.class or an interface
} else {
- SortableType sortableSupertype = types[supertype];
+ SortableType sortableSupertype = types[classDef.getSupertypeIndex()];
if (sortableSupertype == null) {
max = 1; // unknown, so assume it's a root.
} else if (sortableSupertype.depth == -1) {
@@ -101,7 +84,7 @@
}
}
- for (short interfaceIndex : interfaces) {
+ for (short interfaceIndex : classDef.getInterfaces()) {
SortableType implemented = types[interfaceIndex];
if (implemented == null) {
max = Math.max(max, 1); // unknown, so assume it's a root.
diff --git a/dx/src/com/android/dx/print/DexIndexPrinter.java b/dx/src/com/android/dx/print/DexIndexPrinter.java
deleted file mode 100644
index 331f514..0000000
--- a/dx/src/com/android/dx/print/DexIndexPrinter.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dx.print;
-
-import com.android.dx.dex.SizeOf;
-import com.android.dx.util.DexReader;
-import com.android.dx.dex.TableOfContents;
-import java.io.Closeable;
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Executable that prints all indices of a dex file.
- */
-public final class DexIndexPrinter implements Closeable {
- private final DexReader dexReader;
- private final TableOfContents tableOfContents;
-
- public DexIndexPrinter(File file) throws IOException {
- this.dexReader = new DexReader(file);
- this.tableOfContents = dexReader.getTableOfContents();
- }
-
- private void printMap() {
- for (TableOfContents.Section section : tableOfContents.sections) {
- if (section.off != -1) {
- System.out.println("section " + Integer.toHexString(section.type)
- + " off=" + Integer.toHexString(section.off)
- + " size=" + Integer.toHexString(section.size)
- + " byteCount=" + Integer.toHexString(section.byteCount));
- }
- }
- }
-
- private void printStrings() throws IOException {
- for (int i = 0; i < tableOfContents.stringIds.size; i++) {
- String s = dexReader.readString(i);
- System.out.println("string " + i + ": " + s);
- }
- }
-
- private void printTypeIds() throws IOException {
- dexReader.seek(tableOfContents.typeIds.off);
- for (int i = 0; i < tableOfContents.typeIds.size; i++) {
- int stringIndex = dexReader.readInt();
- System.out.println("type " + i + ": " + dexReader.readString(stringIndex));
- }
- }
-
- private String readProto(int protoIndex) throws IOException {
- int position = dexReader.getPosition();
- dexReader.seek(tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * protoIndex));
- int shortyIdx = dexReader.readInt(); // string ID
- int returnTypeIdx = dexReader.readInt(); //type ID
- int parametersOff = dexReader.readInt(); // type list, or 0 for no parameters
- String shorty = dexReader.readString(shortyIdx);
- String returnType = readType(returnTypeIdx);
- StringBuilder result = new StringBuilder()
- .append(shorty)
- .append(": ")
- .append(returnType)
- .append(" (");
-
- if (parametersOff != 0) {
- dexReader.seek(parametersOff);
- int typeListSize = dexReader.readInt();
- for (int j = 0; j < typeListSize; j++) {
- if (j > 0) {
- result.append(", ");
- }
- dexReader.seek(parametersOff + 4 + (j * SizeOf.TYPE_ITEM));
- int typeIndex = dexReader.readShort();
- result.append(readType(typeIndex));
- }
- }
- result.append(")");
- dexReader.seek(position);
- return result.toString();
- }
-
- private void printProtoIds() throws IOException {
- for (int i = 0; i < tableOfContents.protoIds.size; i++) {
- String proto = readProto(i);
- System.out.println("proto " + i + ": " + proto);
- }
- dexReader.seek(tableOfContents.protoIds.off
- + (SizeOf.PROTO_ID_ITEM * tableOfContents.protoIds.size));
- }
-
- private void printFieldIds() throws IOException {
- for (int i = 0; i < tableOfContents.fieldIds.size; i++) {
- int declaringClass = dexReader.readShort();
- int type = dexReader.readShort();
- int nameIndex = dexReader.readInt();
- System.out.println("field " + i + ": " + readType(declaringClass)
- + " { " + readType(type) + " " + dexReader.readString(nameIndex) + " }");
- }
- }
-
- private void printMethodIds() throws IOException {
- for (int i = 0; i < tableOfContents.methodIds.size; i++) {
- int declaringClass = dexReader.readShort();
- int protoIndex = dexReader.readShort();
- int name = dexReader.readInt();
- String proto = readProto(protoIndex);
- System.out.println("method " + i + ": " + readType(declaringClass)
- + " " + proto + " " + dexReader.readString(name));
- }
- }
-
- private void printTypeLists() throws IOException {
- if (tableOfContents.typeLists.off == -1) {
- System.out.println("No type lists");
- return;
- }
- int position = dexReader.getPosition();
- dexReader.seek(tableOfContents.typeLists.off);
- for (int i = 0; i < tableOfContents.typeLists.size; i++) {
- int size = dexReader.readInt();
- System.out.print("Type list i=" + i + ", size=" + size + ", elements=");
- for (int t = 0; t < size; t++) {
- System.out.print(" " + readType(dexReader.readShort()));
- }
- if (size % 2 == 1) {
- dexReader.readShort(); // retain alignment
- }
- System.out.println();
- }
- dexReader.seek(position);
- }
-
- private String readType(int index) throws IOException {
- if (index < 0 || index >= tableOfContents.typeIds.size) {
- throw new IllegalArgumentException("type index out of range: "
- + index + " " + tableOfContents.typeIds.size);
- }
- int position = dexReader.getPosition();
- dexReader.seek(tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM));
- int stringIndex = dexReader.readInt();
- String result = dexReader.readString(stringIndex);
- dexReader.seek(position);
- return result;
- }
-
- public void close() throws IOException {
- dexReader.close();
- }
-
- public static void main(String[] args) throws IOException {
- DexIndexPrinter indexPrinter = new DexIndexPrinter(new File(args[0]));
- indexPrinter.printMap();
- indexPrinter.printStrings();
- indexPrinter.printTypeIds();
- indexPrinter.printProtoIds();
- indexPrinter.printFieldIds();
- indexPrinter.printMethodIds();
- indexPrinter.printTypeLists();
- }
-}
diff --git a/dx/src/com/android/dx/util/DexReader.java b/dx/src/com/android/dx/util/DexReader.java
deleted file mode 100644
index ed8a68a..0000000
--- a/dx/src/com/android/dx/util/DexReader.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dx.util;
-
-import com.android.dx.dex.DexException;
-import com.android.dx.dex.SizeOf;
-import com.android.dx.dex.TableOfContents;
-import java.io.Closeable;
-import java.io.DataInput;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Arrays;
-
-/**
- * All int offsets are unsigned.
- */
-public final class DexReader implements Closeable {
- private final String name;
- private final byte[] fileContents;
- private final TableOfContents tableOfContents;
- private int position = 0;
-
- private final DataInput asDataInput = new DataInputStub() {
- public byte readByte() throws IOException {
- return DexReader.this.readByte();
- }
- };
-
- /**
- * Creates a new DexReader that reads ints and shorts in little-endian byte
- * order.
- */
- public DexReader(File file) throws IOException {
- name = file.getPath();
-
- FileInputStream in = new FileInputStream(file);
- int length = (int) file.length();
- fileContents = new byte[length];
-
- int count = 0;
- while (count < length) {
- int bytesRead = in.read(fileContents, count, length - count);
- if (bytesRead == -1) {
- throw new IOException("Expected " + length + " bytes but was " + count);
- }
- count += bytesRead;
- }
- in.close();
-
- tableOfContents = new TableOfContents(this);
- }
-
- public TableOfContents getTableOfContents() {
- return tableOfContents;
- }
-
- public int getPosition() throws IOException {
- return position;
- }
-
- public void seek(int offset) throws IOException {
- position = offset;
- }
-
- public void close() throws IOException {}
-
- public int readInt() throws IOException {
- int result = (fileContents[position] & 0xff)
- | (fileContents[position + 1] & 0xff) << 8
- | (fileContents[position + 2] & 0xff) << 16
- | (fileContents[position + 3] & 0xff) << 24;
- position += 4;
- return result;
- }
-
- public short readShort() throws IOException {
- int result = (fileContents[position] & 0xff)
- | (fileContents[position + 1] & 0xff) << 8;
- position += 2;
- return (short) result;
- }
-
- public byte readByte() throws IOException {
- return (byte) (fileContents[position++] & 0xff);
- }
-
- public byte[] readByteArray(int length) throws IOException {
- byte[] result = Arrays.copyOfRange(fileContents, position, position + length);
- position += length;
- return result;
- }
-
- public short[] readShortArray(int length) throws IOException {
- short[] result = new short[length];
- for (int i = 0; i < length; i++) {
- result[i] = readShort();
- }
- return result;
- }
-
- public int readUleb128() throws IOException {
- return Leb128Utils.readUnsignedLeb128(asDataInput);
- }
-
- public int readSleb128() throws IOException {
- return Leb128Utils.readSignedLeb128(asDataInput);
- }
-
- public short[] readTypeList(int offset) throws IOException {
- if (offset == 0) {
- return new short[0];
- }
- int savedPosition = position;
- position = offset;
- int size = readInt();
- short[] parameters = new short[size];
- for (int i = 0; i < size; i++) {
- parameters[i] = readShort();
- }
- position = savedPosition;
- return parameters;
- }
-
- public String readStringDataItem() throws IOException {
- int expectedLength = readUleb128();
- String result = Mutf8.decode(asDataInput, new char[expectedLength]);
- if (result.length() != expectedLength) {
- throw new DexException("Declared length " + expectedLength + " doesn't match decoded "
- + "length of " + result.length());
- }
- return result;
- }
-
- /**
- * Reads a string at the given index. This method does not disturb the seek position.
- */
- public String readString(int index) throws IOException {
- int savedPosition = position;
- seek(tableOfContents.stringIds.off + (index * SizeOf.STRING_ID_ITEM));
- int stringDataOff = readInt();
- seek(stringDataOff);
- String result = readStringDataItem();
- position = savedPosition;
- return result;
- }
-
- @Override public String toString() {
- return name;
- }
-
- private static class DataInputStub implements DataInput {
- public byte readByte() throws IOException {
- throw new UnsupportedOperationException();
- }
- public void readFully(byte[] buffer) throws IOException {
- throw new UnsupportedOperationException();
- }
- public void readFully(byte[] buffer, int offset, int count) throws IOException {
- throw new UnsupportedOperationException();
- }
- public int skipBytes(int i) throws IOException {
- throw new UnsupportedOperationException();
- }
- public boolean readBoolean() throws IOException {
- throw new UnsupportedOperationException();
- }
- public int readUnsignedByte() throws IOException {
- throw new UnsupportedOperationException();
- }
- public short readShort() throws IOException {
- throw new UnsupportedOperationException();
- }
- public int readUnsignedShort() throws IOException {
- throw new UnsupportedOperationException();
- }
- public char readChar() throws IOException {
- throw new UnsupportedOperationException();
- }
- public int readInt() throws IOException {
- throw new UnsupportedOperationException();
- }
- public long readLong() throws IOException {
- throw new UnsupportedOperationException();
- }
- public float readFloat() throws IOException {
- throw new UnsupportedOperationException();
- }
- public double readDouble() throws IOException {
- throw new UnsupportedOperationException();
- }
- public String readLine() throws IOException {
- throw new UnsupportedOperationException();
- }
- public String readUTF() throws IOException {
- throw new UnsupportedOperationException();
- }
- }
-}
diff --git a/dx/src/com/android/dx/util/DexWriter.java b/dx/src/com/android/dx/util/DexWriter.java
deleted file mode 100644
index 2651d4d..0000000
--- a/dx/src/com/android/dx/util/DexWriter.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dx.util;
-
-import com.android.dx.dex.DexException;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Writes a dex file in sections.
- */
-public final class DexWriter implements Closeable {
- private final List<Section> sections = new ArrayList<Section>();
- private final RandomAccessFile randomAccessFile;
- private int length;
-
- /**
- * Creates a new DexWriter that writes ints and shorts in little-endian byte
- * order.
- */
- public DexWriter(File file) throws FileNotFoundException {
- this.randomAccessFile = new RandomAccessFile(file, "rw");
- }
-
- public Section newSection(int maxByteCount, String name) throws IOException {
- Section result = new Section(name, length, maxByteCount);
- sections.add(result);
- length = fourByteAlign(length + maxByteCount);
- return result;
- }
-
- public int getLength() {
- return length;
- }
-
- public void close() throws IOException {
- for (Section s : sections) {
- s.flush();
- }
- randomAccessFile.setLength(length);
- randomAccessFile.close();
- }
-
- public static int fourByteAlign(int position) {
- return (position + 3) & ~3;
- }
-
- public final class Section {
- private final String name;
- private final int offset;
- private final int maxByteCount;
- private final byte[] buffer;
- private int bufferedByteCount;
- private int byteCount;
-
- private Section(String name, int offset, int maxByteCount) {
- this.name = name;
- this.offset = offset;
- this.maxByteCount = maxByteCount;
- this.buffer = new byte[Math.min(8192, maxByteCount)];
- }
-
- public int getCursor() throws IOException {
- return offset + byteCount + bufferedByteCount;
- }
-
- public void flush() throws IOException {
- if (bufferedByteCount == 0) {
- return;
- }
- if (byteCount + bufferedByteCount > maxByteCount) {
- throw new DexException("Expected size " + maxByteCount
- + " exceeded by " + name + ": " + byteCount + bufferedByteCount);
- }
- randomAccessFile.seek(offset + byteCount);
- randomAccessFile.write(buffer, 0, bufferedByteCount);
- byteCount += bufferedByteCount;
- bufferedByteCount = 0;
- }
-
- private void ensureCapacity(int byteCount) throws IOException {
- if (bufferedByteCount + byteCount > buffer.length) {
- flush();
- }
- }
-
- /**
- * Writes 0x00 until the position is aligned to a multiple of 4.
- */
- public void alignToFourBytes() throws IOException {
- int unalignedCount = bufferedByteCount;
- bufferedByteCount = DexWriter.fourByteAlign(byteCount + bufferedByteCount) - byteCount;
- for (int i = unalignedCount; i < bufferedByteCount; i++) {
- buffer[i] = 0;
- }
- }
-
- public void assertFourByteAligned() throws IOException {
- if ((getCursor() & 3) != 0) {
- throw new IllegalStateException("Not four byte aligned!");
- }
- }
-
- public void write(byte[] bytes) throws IOException {
- int offset = 0;
- while (offset < bytes.length) {
- ensureCapacity(1);
- int toCopy = Math.min(bytes.length - offset, buffer.length - bufferedByteCount);
- System.arraycopy(bytes, offset, buffer, bufferedByteCount, toCopy);
- bufferedByteCount += toCopy;
- offset += toCopy;
- }
- }
-
- public void writeByte(int b) throws IOException {
- ensureCapacity(1);
- buffer[bufferedByteCount] = (byte) b;
- bufferedByteCount++;
- }
-
- public void writeShort(short i) throws IOException {
- ensureCapacity(2);
- buffer[bufferedByteCount ] = (byte) i;
- buffer[bufferedByteCount + 1] = (byte) (i >>> 8);
- bufferedByteCount += 2;
- }
-
- public void write(short[] shorts) throws IOException {
- for (short s : shorts) {
- writeShort(s);
- }
- }
-
- public void writeInt(int i) throws IOException {
- ensureCapacity(4);
- buffer[bufferedByteCount ] = (byte) i;
- buffer[bufferedByteCount + 1] = (byte) (i >>> 8);
- buffer[bufferedByteCount + 2] = (byte) (i >>> 16);
- buffer[bufferedByteCount + 3] = (byte) (i >>> 24);
- bufferedByteCount += 4;
- }
-
- public void writeUleb128(int i) throws IOException {
- ensureCapacity(5);
- bufferedByteCount += Leb128Utils.writeUnsignedLeb128(buffer, bufferedByteCount, i);
- }
-
- public void writeSleb128(int i) throws IOException {
- ensureCapacity(5);
- bufferedByteCount += Leb128Utils.writeSignedLeb128(buffer, bufferedByteCount, i);
- }
-
- public void writeStringDataItem(String value) throws IOException {
- int length = value.length();
- writeUleb128(length);
- write(Mutf8.encode(value));
- writeByte(0);
- }
- }
-}