Implement the various primitive reading methods on DexFile and DexFileReader

This commit is contained in:
Ben Gruver 2012-10-20 14:17:43 -07:00
parent 779bf9bccb
commit a88239d92d
3 changed files with 460 additions and 122 deletions

View File

@ -31,14 +31,43 @@
package org.jf.dexlib2.dexbacked; package org.jf.dexlib2.dexbacked;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class DexFile { public class DexFile {
// TODO: consider using a direct ByteBuffer instead
protected final byte[] buf;
public DexFile(byte[] buf) {
this.buf = buf;
}
public String getString(int stringIndex) {
return null;
}
public int getFieldIdItemOffset(int fieldIndex) {
return 0;
}
public int getMethodIdItemOffset(int methodIndex) {
return 0;
}
public int getProtoIdItemOffset(int methodIndex) {
return 0;
}
public String getType(int typeIndex) { public String getType(int typeIndex) {
return null; return null;
} }
public String getString(int stringIndex) { public String getField(int fieldIndex) {
return null;
}
public String getMethod(int methodIndex) {
return null; return null;
} }
@ -47,20 +76,61 @@ public class DexFile {
return null; return null;
} }
public int getFieldIdItemOffset(int fieldIndex) { public String getReference(int referenceType, int referenceIndex) {
return 0; return null;
}
public int readSmallUleb128(int offset) {
return 0;
} }
public int readSmallUint(int offset) { public int readSmallUint(int offset) {
return 0; byte[] buf = this.buf;
int result = (buf[offset] & 0xff) |
((buf[offset+1] & 0xff) << 8) |
((buf[offset+2] & 0xff) << 16) |
((buf[offset+3] & 0xff) << 24); // TODO: can get rid of last & 0xff?
if (result < 0) {
throw new ExceptionWithContext("Encountered uint that is out of range at offset 0x%x", offset);
}
return result;
} }
public int readUshort(int offset) { public int readUshort(int offset) {
return 0; byte[] buf = this.buf;
return (buf[offset] & 0xff) |
((buf[offset+1] & 0xff) << 8);
}
public int readUbyte(int offset) {
return buf[offset] & 0xff;
}
public long readLong(int offset) {
// TODO: use | or +?
byte[] buf = this.buf;
return (buf[offset] & 0xffL) |
((buf[offset+1] & 0xff) << 8) |
((buf[offset+2] & 0xff) << 16) |
((buf[offset+3] & 0xff) << 24) |
((buf[offset+4] & 0xffL) << 32) |
((buf[offset+5] & 0xffL) << 40) |
((buf[offset+6] & 0xffL) << 48) |
(((long)buf[offset+7]) << 56);
}
public int readInt(int offset) {
byte[] buf = this.buf;
return (buf[offset] & 0xff) |
((buf[offset+1] & 0xff) << 8) |
((buf[offset+2] & 0xff) << 16) |
(buf[offset+3] << 24);
}
public int readShort(int offset) {
byte[] buf = this.buf;
return (buf[offset] & 0xff) |
(buf[offset+1] << 8);
}
public int readByte(int offset) {
return buf[offset];
} }
public DexFileReader readerAt(int offset) { public DexFileReader readerAt(int offset) {

View File

@ -31,150 +31,418 @@
package org.jf.dexlib2.dexbacked; package org.jf.dexlib2.dexbacked;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class DexFileReader { public class DexFileReader {
public DexFileReader(DexFile dexFile, int offset) { @Nonnull private final DexFile dexFile;
private int offset;
public DexFileReader(@Nonnull DexFile dexFile, int offset) {
this.dexFile = dexFile;
this.offset = offset;
} }
@Nonnull @Nonnull public DexFile getDexFile() { return dexFile; }
public DexFile getDexFile() { public int getOffset() { return offset; }
return null;
}
public int getOffset() { public String getString(int stringIndex) { return dexFile.getString(stringIndex); }
return 0; public int getFieldIdItemOffset(int fieldIndex) { return dexFile.getFieldIdItemOffset(fieldIndex); }
} public int getMethodIdItemOffset(int methodIndex) { return dexFile.getMethodIdItemOffset(methodIndex); }
public int getProtoIdItemOffset(int methodIndex) { return dexFile.getProtoIdItemOffset(methodIndex); }
public String getString(int stringIndex) { public String getType(int typeIndex) { return dexFile.getType(typeIndex); }
return null; public String getField(int fieldIndex) { return dexFile.getField(fieldIndex); }
} public String getMethod(int methodIndex) { return dexFile.getMethod(methodIndex); }
public String getReference(int type, int index) { return dexFile.getReference(type, index); }
public int getFieldIdItemOffset(int fieldIndex) {
return 0;
}
public int getMethodIdItemOffset(int methodIndex) {
return 0;
}
public int getProtoIdItemOffset(int methodIndex) {
return 0;
}
public String getType(int typeIndex) {
return null;
}
public String getField(int fieldIndex) {
return null;
}
public String getMethod(int fieldIndex) {
return null;
}
public String getReference(int referenceType, int referenceIndex) {
return null;
}
/** {@inheritDoc} */
public int readSleb128() { public int readSleb128() {
return 0; int end = offset;
int currentByteValue;
int result;
byte[] buf = dexFile.buf;
result = buf[end++] & 0xff;
if (result <= 0x7f) {
result = (result << 25) >> 25;
} else {
currentByteValue = buf[end++] & 0xff;
result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7);
if (currentByteValue <= 0x7f) {
result = (result << 18) >> 18;
} else {
currentByteValue = buf[end++] & 0xff;
result |= (currentByteValue & 0x7f) << 14;
if (currentByteValue <= 0x7f) {
result = (result << 11) >> 11;
} else {
currentByteValue = buf[end++] & 0xff;
result |= (currentByteValue & 0x7f) << 21;
if (currentByteValue <= 0x7f) {
result = (result << 4) >> 4;
} else {
currentByteValue = buf[end++] & 0xff;
if (currentByteValue > 0x0f) {
throw new ExceptionWithContext(
"Invalid sleb128 integer encountered at offset 0x%x", offset);
}
result |= currentByteValue << 28;
}
}
}
}
offset = end;
return result;
} }
public int readSmallUleb128() { public int readSmallUleb128() {
return 0; int end = offset;
int currentByteValue;
int result;
byte[] buf = dexFile.buf;
result = buf[end++] & 0xff;
if (result > 0x7f) {
currentByteValue = buf[end++] & 0xff;
result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7);
if (currentByteValue > 0x7f) {
currentByteValue = buf[end++] & 0xff;
result |= (currentByteValue & 0x7f) << 14;
if (currentByteValue > 0x7f) {
currentByteValue = buf[end++] & 0xff;
result |= (currentByteValue & 0x7f) << 21;
if (currentByteValue > 0x7f) {
currentByteValue = buf[end++] & 0xff;
// we assume the most significant bit will never be set
if (currentByteValue > 0x07) {
if (currentByteValue <= 0x0f) {
throw new ExceptionWithContext(
"Encountered valid uleb128 that is out of range at offset 0x%x", offset);
}
throw new ExceptionWithContext(
"Invalid uleb128 integer encountered at offset 0x%x", offset);
}
result |= currentByteValue << 28;
}
}
}
}
offset = end;
return result;
} }
public void skipUleb128() { public void skipUleb128() {
int end = offset;
byte currentByteValue;
byte[] buf = dexFile.buf;
currentByteValue = buf[end++];
if (currentByteValue < 0) { // if the MSB is set
currentByteValue = buf[end++];
if (currentByteValue < 0) { // if the MSB is set
currentByteValue = buf[end++];
if (currentByteValue < 0) { // if the MSB is set
currentByteValue = buf[end++];
if (currentByteValue < 0) { // if the MSB is set
currentByteValue = buf[end++];
if (currentByteValue < 0 || currentByteValue > 0x0f) {
throw new ExceptionWithContext(
"Invalid uleb128 integer encountered at offset 0x%x", offset);
}
}
}
}
}
offset = end;
} }
public int readSmallUint() { public int readSmallUint() {
return 0; int o = offset;
int result = dexFile.readSmallUint(o);
offset = o + 4;
return result;
} }
public int readUshort() { public int readUshort() {
return 0; int o = offset;
int result = dexFile.readUshort(offset);
offset = o + 2;
return result;
} }
public int readUbyte() { public int readUbyte() {
// returns an int between 0 and 255 int o = offset;
return 0; int result = dexFile.readUbyte(offset);
} offset = o + 1;
return result;
public int readByte() {
// returns an int between -128 and 127
return 0;
}
public int readUshort(int offset) {
return 0;
}
public int readShort() {
return 0;
}
public int readSizedInt(int bytes) {
// bytes must be from 1 to 4. reads and interprets that many bytes as a little-endian sign-extended integer
return 0;
}
public int readSizedSmallUint(int bytes) {
// bytes must be from 1 to 4. reads and interprets that many bytes as a little-endian zero-extended integer
return 0;
}
public int readSizedRightExtendedUint(int bytes) {
// bytes must be from 1 to 4. reads and interprets that many bytes as a little-endian zero-right-extended
// integer
return 0;
}
public int readSizedRightExtendedUlong(int bytes) {
// bytes must be from 1 to 8. reads and interprets that many bytes as a little-endian zero-right-extended
// long
return 0;
}
public long readSizedLong(int bytes) {
// bytes must be from 1 to 8. reads and interprets that many bytes as a little-endian sign-extended long
return 0;
}
public long readSizedUlong(int bytes) {
// bytes must be from 1 to 8. reads and interprets that many bytes as a little-endian zero-extended long
return 0;
}
public int readSmallUint(int offset) {
return 0;
}
public int readInt() {
return 0;
} }
public long readLong() { public long readLong() {
return 0; int o = offset;
long result = dexFile.readLong(offset);
offset = o + 2;
return result;
} }
public int readInt() {
int o = offset;
@Nonnull int result = dexFile.readInt(offset);
public DexFileReader atAbsolute(int offset) { offset = o + 4;
return null; return result;
} }
// returns copy of this DexFileReader public int readShort() {
@Nonnull int o = offset;
public DexFileReader copy() { int result = dexFile.readShort(offset);
return null; offset = o + 2;
return result;
} }
public void skipByte() { public int readByte() {
int o = offset;
int result = dexFile.readByte(offset);
offset = o + 1;
return result;
} }
public void skipBytes(int i) { public void skipByte() { offset++; }
public void skipBytes(int i) { offset += i; }
public int readSmallUint(int offset) { return dexFile.readSmallUint(offset); }
public int readUshort(int offset) { return dexFile.readUshort(offset); }
public int readUbyte(int offset) { return dexFile.readUbyte(offset); }
public long readLong(int offset) { return dexFile.readLong(offset); }
public int readInt(int offset) { return dexFile.readInt(offset); }
public int readShort(int offset) { return dexFile.readShort(offset); }
public int readByte(int offset) { return dexFile.readByte(offset); }
public int readSizedInt(int bytes) {
int o = offset;
byte[] buf = dexFile.buf;
int result;
switch (bytes) {
case 4:
result = (buf[o] & 0xff) |
((buf[o+1] & 0xff) << 8) |
((buf[o+2] & 0xff) << 16) |
(buf[o+3] << 24);
break;
case 3:
result = (buf[o] & 0xff) |
((buf[o+1] & 0xff) << 8) |
((buf[o+2]) << 16);
break;
case 2:
result = (buf[o] & 0xff) |
((buf[o+1]) << 8);
break;
case 1:
result = buf[o];
break;
default:
throw new ExceptionWithContext("Invalid size %d for sized int at offset 0x%x", bytes, offset);
}
offset = o + bytes;
return result;
}
public int readSizedSmallUint(int bytes) {
int o = offset;
byte[] buf = dexFile.buf;
int result = 0;
switch (bytes) {
case 4:
int b = buf[o+3];
if (b < 0) {
throw new ExceptionWithContext(
"Encountered valid sized uint that is out of range at offset 0x%x", offset);
}
result = (b & 0xff) << 24;
// fall-through
case 3:
result |= (buf[o+2] & 0xff) << 16;
// fall-through
case 2:
result |= (buf[o+1] & 0xff) << 8;
// fall-through
case 1:
result |= (buf[o] & 0xff);
break;
default:
throw new ExceptionWithContext("Invalid size %d for sized uint at offset 0x%x", bytes, offset);
}
offset = o + bytes;
return result;
}
public int readSizedRightExtendedInt(int bytes) {
int o = offset;
byte[] buf = dexFile.buf;
int result = 0;
switch (bytes) {
case 4:
result = (buf[o] & 0xff) |
((buf[o+1] & 0xff) << 8) |
((buf[o+2] & 0xff) << 16) |
(buf[o+3] << 24);
break;
case 3:
result = (buf[o] & 0xff) << 8 |
((buf[o+1] & 0xff) << 16) |
(buf[o+2] << 24);
break;
case 2:
result = (buf[o] & 0xff) << 16 |
(buf[o+1] << 24);
break;
case 1:
result = buf[o] << 24;
break;
default:
throw new ExceptionWithContext(
"Invalid size %d for sized, right extended int at offset 0x%x", bytes, offset);
}
offset = o + bytes;
return result;
}
public long readSizedRightExtendedLong(int bytes) {
int o = offset;
byte[] buf = dexFile.buf;
long result = 0;
switch (bytes) {
case 8:
result = (buf[o] & 0xff) |
((buf[o+1] & 0xff) << 8) |
((buf[o+2] & 0xff) << 16) |
((buf[o+3] & 0xff) << 24) |
((buf[o+4] & 0xffL) << 32) |
((buf[o+5] & 0xffL) << 40) |
((buf[o+6] & 0xffL) << 48) |
(((long)buf[o+7]) << 56);
break;
case 7:
result = ((buf[o] & 0xff)) << 8 |
((buf[o+1] & 0xff) << 16) |
((buf[o+2] & 0xff) << 24) |
((buf[o+3] & 0xffL) << 32) |
((buf[o+4] & 0xffL) << 40) |
((buf[o+5] & 0xffL) << 48) |
(((long)buf[o+6]) << 56);
break;
case 6:
result = ((buf[o] & 0xff)) << 16 |
((buf[o+1] & 0xff) << 24) |
((buf[o+2] & 0xffL) << 32) |
((buf[o+3] & 0xffL) << 40) |
((buf[o+4] & 0xffL) << 48) |
(((long)buf[o+5]) << 56);
break;
case 5:
result = ((buf[o] & 0xff)) << 24 |
((buf[o+1] & 0xffL) << 32) |
((buf[o+2] & 0xffL) << 40) |
((buf[o+3] & 0xffL) << 48) |
(((long)buf[o+4]) << 56);
break;
case 4:
result = ((buf[o] & 0xffL)) << 32 |
((buf[o+1] & 0xffL) << 40) |
((buf[o+2] & 0xffL) << 48) |
(((long)buf[o+3]) << 56);
break;
case 3:
result = ((buf[o] & 0xffL)) << 40 |
((buf[o+1] & 0xffL) << 48) |
(((long)buf[o+2]) << 56);
break;
case 2:
result = ((buf[o] & 0xffL)) << 48 |
(((long)buf[o+1]) << 56);
break;
case 1:
result = ((long)buf[o]) << 56;
break;
default:
throw new ExceptionWithContext(
"Invalid size %d for sized, right extended long at offset 0x%x", bytes, offset);
}
offset = o + bytes;
return result;
}
public long readSizedLong(int bytes) {
int o = offset;
byte[] buf = dexFile.buf;
long result = 0;
switch (bytes) {
case 8:
result = (buf[o] & 0xff) |
((buf[o+1] & 0xff) << 8) |
((buf[o+2] & 0xff) << 16) |
((buf[o+3] & 0xff) << 24) |
((buf[o+4] & 0xffL) << 32) |
((buf[o+5] & 0xffL) << 40) |
((buf[o+6] & 0xffL) << 48) |
(((long)buf[o+7]) << 56);
break;
case 7:
result = (buf[o] & 0xff) |
((buf[o+1] & 0xff) << 8) |
((buf[o+2] & 0xff) << 16) |
((buf[o+3] & 0xff) << 24) |
((buf[o+4] & 0xffL) << 32) |
((buf[o+5] & 0xffL) << 40) |
((long)(buf[o+6]) << 48);
break;
case 6:
result = (buf[o] & 0xff) |
((buf[o+1] & 0xff) << 8) |
((buf[o+2] & 0xff) << 16) |
((buf[o+3] & 0xff) << 24) |
((buf[o+4] & 0xffL) << 32) |
((long)(buf[o+5]) << 40);
break;
case 5:
result = (buf[o] & 0xff) |
((buf[o+1] & 0xff) << 8) |
((buf[o+2] & 0xff) << 16) |
((buf[o+3] & 0xff) << 24) |
((long)(buf[o+4]) << 32);
break;
case 4:
result = (buf[o] & 0xff) |
((buf[o+1] & 0xff) << 8) |
((buf[o+2] & 0xff) << 16) |
(buf[o+3] << 24);
break;
case 3:
result = (buf[o] & 0xff) << 8 |
((buf[o+1] & 0xff) << 16) |
(buf[o+2] << 24);
break;
case 2:
result = (buf[o] & 0xff) << 16 |
(buf[o+1] << 24);
break;
case 1:
result = buf[o] << 24;
break;
default:
throw new ExceptionWithContext("Invalid size %d for sized long at offset 0x%x", bytes, offset);
}
o += bytes;
return result;
} }
} }

View File

@ -66,11 +66,11 @@ public abstract class DexBackedEncodedValue {
case ValueType.FLOAT: case ValueType.FLOAT:
Preconditions.checkValueArg(valueArg, 3); Preconditions.checkValueArg(valueArg, 3);
return new ImmutableFloatEncodedValue(Float.intBitsToFloat( return new ImmutableFloatEncodedValue(Float.intBitsToFloat(
reader.readSizedRightExtendedUint(valueArg + 1))); reader.readSizedRightExtendedInt(valueArg + 1)));
case ValueType.DOUBLE: case ValueType.DOUBLE:
Preconditions.checkValueArg(valueArg, 7); Preconditions.checkValueArg(valueArg, 7);
return new ImmutableDoubleEncodedValue(Double.longBitsToDouble( return new ImmutableDoubleEncodedValue(Double.longBitsToDouble(
reader.readSizedRightExtendedUlong(valueArg + 1))); reader.readSizedRightExtendedLong(valueArg + 1)));
case ValueType.STRING: case ValueType.STRING:
Preconditions.checkValueArg(valueArg, 3); Preconditions.checkValueArg(valueArg, 3);
return new ImmutableStringEncodedValue(reader.getString(reader.readSizedSmallUint(valueArg + 1))); return new ImmutableStringEncodedValue(reader.getString(reader.readSizedSmallUint(valueArg + 1)));