core: fix encoded value parser for signed and floating point numbers

This commit is contained in:
Skylot 2013-10-23 23:27:53 +04:00
parent 1ba19d3600
commit d94087b939
4 changed files with 97 additions and 19 deletions

View File

@ -22,7 +22,7 @@ public class EncValueParser extends EncodedValueReader {
}
public Object parseValue() throws DecodeException {
int argAndType = in.readByte() & 0xFF;
int argAndType = readByte();
int type = argAndType & 0x1F;
int arg = (argAndType & 0xE0) >> 5;
int size = arg + 1;
@ -39,28 +39,29 @@ public class EncValueParser extends EncodedValueReader {
case ENCODED_SHORT:
return (short) parseNumber(size, true);
case ENCODED_CHAR:
return (char) parseNumber(size, false);
return (char) parseUnsignedInt(size);
case ENCODED_INT:
return (int) parseNumber(size, true);
case ENCODED_LONG:
return parseNumber(size, true);
case ENCODED_FLOAT:
return Float.intBitsToFloat((int) parseNumber(size, false));
return Float.intBitsToFloat((int) parseNumber(size, false, 4));
case ENCODED_DOUBLE:
return Double.longBitsToDouble(parseNumber(size, false));
return Double.longBitsToDouble(parseNumber(size, false, 8));
case ENCODED_STRING:
return dex.getString((int) parseNumber(size, false));
return dex.getString(parseUnsignedInt(size));
case ENCODED_TYPE:
return dex.getType((int) parseNumber(size, false));
return dex.getType(parseUnsignedInt(size));
case ENCODED_METHOD:
return MethodInfo.fromDex(dex, (int) parseNumber(size, false));
return MethodInfo.fromDex(dex, parseUnsignedInt(size));
case ENCODED_FIELD:
case ENCODED_ENUM:
return FieldInfo.fromDex(dex, (int) parseNumber(size, false));
return FieldInfo.fromDex(dex, parseUnsignedInt(size));
case ENCODED_ARRAY:
int count = Leb128Utils.readUnsignedLeb128(in);
@ -76,18 +77,36 @@ public class EncValueParser extends EncodedValueReader {
throw new DecodeException("Unknown encoded value type: 0x" + Integer.toHexString(type));
}
private int parseUnsignedInt(int byteCount) {
return (int) parseNumber(byteCount, false, 0);
}
private long parseNumber(int byteCount, boolean isSignExtended) {
return parseNumber(byteCount, isSignExtended, 0);
}
private long parseNumber(int byteCount, boolean isSignExtended, int fillOnRight) {
long result = 0;
int shift = 8;
int first = in.readByte() & 0xFF;
if (isSignExtended && (first & 0x80) != 0) {
result = ~result << shift;
long last = 0;
for (int i = 0; i < byteCount; i++) {
last = readByte();
result |= last << i * 8;
}
result |= (long) first;
for (int i = 1; i < byteCount; i++) {
result |= (long) (in.readByte() & 0xFF) << shift;
shift += 8;
if (fillOnRight != 0) {
for (int i = byteCount; i < fillOnRight; i++) {
result <<= 8;
}
} else {
if (isSignExtended && (last & 0x80) != 0) {
for (int i = byteCount; i < 8; i++) {
result |= (long) 0xFF << i * 8;
}
}
}
return result;
}
private int readByte() {
return in.readByte() & 0xFF;
}
}

View File

@ -17,7 +17,15 @@ public class TestAnnotations extends InternalJadxTest {
}
@A(a = -1)
public void method1() {
public void methodA1() {
}
@A(a = -253)
public void methodA2() {
}
@A(a = -11253)
public void methodA3() {
}
private static @interface V {
@ -25,7 +33,7 @@ public class TestAnnotations extends InternalJadxTest {
}
@V(false)
public void method2() {
public void methodV() {
}
private static @interface D {
@ -33,7 +41,7 @@ public class TestAnnotations extends InternalJadxTest {
}
@D
public void method3() {
public void methodD() {
}
}
@ -41,9 +49,12 @@ public class TestAnnotations extends InternalJadxTest {
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertThat(code, not(containsString("@A(a = 255)")));
assertThat(code, containsString("@A(a = -1)"));
assertThat(code, containsString("@A(a = -253)"));
assertThat(code, containsString("@A(a = -11253)"));
assertThat(code, containsString("@V(false)"));
assertThat(code, not(containsString("@D()")));
}

View File

@ -28,6 +28,12 @@ public abstract class AbstractTest {
}
}
public static void assertEquals(float a1, float a2) {
if (Float.compare(a1, a2) != 0) {
throw new AssertionError(a1 + " != " + a2);
}
}
public static void assertEquals(Object a1, Object a2) {
if (a1 == null) {
if (a2 != null)

View File

@ -0,0 +1,42 @@
package jadx.samples;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class TestAnnotationsParser extends AbstractTest {
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public static @interface A {
int i();
float f();
}
@A(i = -1, f = C1.FLOAT_CONST)
public static class C1 {
public static final float FLOAT_CONST = 3.14f;
}
@A(i = -1025, f = C2.FLOAT_CONST)
public static class C2 {
public static final float FLOAT_CONST = 0xFF0000;
}
public boolean testRun() {
A c1 = C1.class.getAnnotation(A.class);
assertEquals(c1.i(), -1);
assertEquals(c1.f(), C1.FLOAT_CONST);
A c2 = C2.class.getAnnotation(A.class);
assertEquals(c2.i(), -1025);
assertEquals(c2.f(), C2.FLOAT_CONST);
return true;
}
public static void main(String[] args) throws Exception {
new TestAnnotationsParser().testRun();
}
}