Annotate CodeItems

This commit is contained in:
Ben Gruver 2013-03-02 14:04:51 -08:00
parent cd12f13ffc
commit 6d607ebe1d
6 changed files with 727 additions and 2 deletions

View File

@ -32,12 +32,14 @@
package org.jf.dexlib2.dexbacked.raw;
import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.dexbacked.DexReader;
import org.jf.dexlib2.util.AnnotatedBytes;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
public class ClassDataItem {
@ -159,4 +161,59 @@ public class ClassDataItem {
}
};
}
@Nullable public static Map<Integer, String> getCodeItemMethodMap(@Nonnull RawDexFile dexFile) {
MapItem classDataMap = dexFile.getMapItemForSection(ItemType.CLASS_DATA_ITEM);
if (classDataMap != null) {
HashMap<Integer, String> codeItemMethodMap = Maps.newHashMap();
int classDataOffset = classDataMap.getOffset();
DexReader reader = dexFile.readerAt(classDataOffset);
for (int i=0; i<classDataMap.getItemCount(); i++) {
int staticFieldsSize = reader.readSmallUleb128();
int instanceFieldsSize = reader.readSmallUleb128();
int directMethodsSize = reader.readSmallUleb128();
int virtualMethodsSize = reader.readSmallUleb128();
for (int j=0; j<staticFieldsSize; j++) {
reader.readSmallUleb128();
reader.readSmallUleb128();
}
for (int j=0; j<instanceFieldsSize; j++) {
reader.readSmallUleb128();
reader.readSmallUleb128();
}
int previousIndex = 0;
for (int j=0; j<directMethodsSize; j++) {
previousIndex = handleMethod(reader, previousIndex, codeItemMethodMap);
}
previousIndex = 0;
for (int j=0; j<virtualMethodsSize; j++) {
previousIndex = handleMethod(reader, previousIndex, codeItemMethodMap);
}
}
return codeItemMethodMap;
}
return null;
}
private static int handleMethod(@Nonnull DexReader reader, int previousIndex, Map<Integer, String> map) {
int methodIndexDelta = reader.readSmallUleb128();
int methodIndex = previousIndex + methodIndexDelta;
String methodString = MethodIdItem.asString(reader.dexBuf, methodIndex);
reader.readSmallUleb128();
int codeOffset = reader.readSmallUleb128();
if (codeOffset != 0) {
map.put(codeOffset, methodString);
}
return methodIndex;
}
}

View File

@ -0,0 +1,380 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.dexbacked.raw;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import org.jf.dexlib2.dexbacked.DexReader;
import org.jf.dexlib2.dexbacked.instruction.DexBackedInstruction;
import org.jf.dexlib2.iface.instruction.*;
import org.jf.dexlib2.iface.instruction.formats.*;
import org.jf.dexlib2.util.AnnotatedBytes;
import org.jf.dexlib2.util.ReferenceUtil;
import org.jf.util.NumberUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
public class CodeItem {
public static final int REGISTERS_OFFSET = 0;
public static final int INS_OFFSET = 2;
public static final int OUTS_OFFSET = 4;
public static final int TRIES_OFFSET = 6;
public static final int DEBUG_INFO_OFFSET = 8;
public static final int INSTRUCTION_COUNT_OFFSET = 12;
private abstract static class CodeItemAnnotator extends SectionAnnotator {
public CodeItemAnnotator() {
}
@Nonnull @Override public String getItemName() {
return "code_item";
}
@Override public int getItemAlignment() {
return 4;
}
@Override protected void annotateItem(@Nonnull AnnotatedBytes out, @Nonnull RawDexFile dexFile, int itemIndex) {
DexReader reader = dexFile.readerAt(out.getCursor());
int registers = reader.readUshort();
out.annotate(2, "registers_size = %d", registers);
int inSize = reader.readUshort();
out.annotate(2, "ins_size = %d", inSize);
int outSize = reader.readUshort();
out.annotate(2, "outs_size = %d", outSize);
int triesCount = reader.readUshort();
out.annotate(2, "tries_size = %d", triesCount);
int debugInfoOffset = reader.readSmallUint();
out.annotate(4, "debug_info_off = 0x%x", debugInfoOffset);
int instructionSize = reader.readSmallUint();
out.annotate(4, "insns_size = 0x%x", instructionSize);
out.annotate(0, "instructions:");
out.indent();
int end = reader.getOffset() + instructionSize*2;
while (reader.getOffset() < end) {
Instruction instruction = DexBackedInstruction.readFrom(reader);
switch (instruction.getOpcode().format) {
case Format10x:
annotateInstruction10x(out, instruction);
break;
case Format35c:
annotateInstruction35c(out, (Instruction35c)instruction);
break;
case Format3rc:
annotateInstruction3rc(out, (Instruction3rc)instruction);
break;
case ArrayPayload:
annotateArrayPayload(out, (ArrayPayload)instruction);
break;
case PackedSwitchPayload:
annotatePackedSwitchPayload(out, (PackedSwitchPayload)instruction);
break;
case SparseSwitchPayload:
annotateSparseSwitchPayload(out, (SparseSwitchPayload)instruction);
break;
default:
annotateDefaultInstruction(out, instruction);
break;
}
assert reader.getOffset() == out.getCursor();
}
out.deindent();
if (triesCount > 0) {
if ((reader.getOffset() % 4) != 0) {
reader.readUshort();
out.annotate(2, "padding");
}
out.annotate(0, "try_items:");
out.indent();
for (int i=0; i<triesCount; i++) {
out.annotate(0, "try_item[%d]:", i);
out.indent();
int startAddr = reader.readSmallUint();
out.annotate(4, "start_addr = 0x%x", startAddr);
int instructionCount = reader.readUshort();
out.annotate(2, "insn_count = 0x%x", instructionCount);
int handlerOffset = reader.readUshort();
out.annotate(2, "handler_off = 0x%x", handlerOffset);
out.deindent();
}
out.deindent();
int mark = reader.getOffset();
int handlerListCount = reader.readSmallUleb128();
out.annotate(0, "encoded_catch_handler_list:");
out.annotate(reader.getOffset() - mark, "size = %d", handlerListCount);
out.indent();
for (int i=0; i<handlerListCount; i++) {
out.annotate(0, "encoded_catch_handler[%d]", i);
out.indent();
mark = reader.getOffset();
int handlerCount = reader.readSleb128();
out.annotate(reader.getOffset() - mark, "size = %d", handlerCount);
boolean hasCatchAll = handlerCount <= 0;
handlerCount = Math.abs(handlerCount);
if (handlerCount != 0) {
out.annotate(0, "handlers:");
out.indent();
for (int j=0; j<handlerCount; j++) {
out.annotate(0, "encoded_type_addr_pair[%d]", i);
out.indent();
mark = reader.getOffset();
int typeIndex = reader.readSmallUleb128();
out.annotate(reader.getOffset() - mark,
TypeIdItem.getReferenceAnnotation(dexFile, typeIndex));
mark = reader.getOffset();
int handlerAddress = reader.readSmallUleb128();
out.annotate(reader.getOffset() - mark, "addr = 0x%x", handlerAddress);
out.deindent();
}
out.deindent();
}
if (hasCatchAll) {
mark = reader.getOffset();
int catchAllAddress = reader.readSmallUleb128();
out.annotate(reader.getOffset() - mark, "catch_all_addr = 0x%x", catchAllAddress);
}
out.deindent();
}
out.deindent();
}
}
private static void annotateInstruction10x(@Nonnull AnnotatedBytes out, @Nonnull Instruction instruction) {
out.annotate(2, instruction.getOpcode().name);
}
private static void annotateInstruction35c(@Nonnull AnnotatedBytes out, @Nonnull Instruction35c instruction) {
List<String> args = Lists.newArrayList();
int registerCount = instruction.getRegisterCount();
if (registerCount == 1) {
args.add(formatRegister(instruction.getRegisterC()));
} else if (registerCount == 2) {
args.add(formatRegister(instruction.getRegisterC()));
args.add(formatRegister(instruction.getRegisterD()));
} else if (registerCount == 3) {
args.add(formatRegister(instruction.getRegisterC()));
args.add(formatRegister(instruction.getRegisterD()));
args.add(formatRegister(instruction.getRegisterE()));
} else if (registerCount == 4) {
args.add(formatRegister(instruction.getRegisterC()));
args.add(formatRegister(instruction.getRegisterD()));
args.add(formatRegister(instruction.getRegisterE()));
args.add(formatRegister(instruction.getRegisterF()));
} else if (registerCount == 5) {
args.add(formatRegister(instruction.getRegisterC()));
args.add(formatRegister(instruction.getRegisterD()));
args.add(formatRegister(instruction.getRegisterE()));
args.add(formatRegister(instruction.getRegisterF()));
args.add(formatRegister(instruction.getRegisterG()));
}
String reference = ReferenceUtil.getReferenceString(instruction.getReference());
out.annotate(6, String.format("%s {%s}, %s",
instruction.getOpcode().name, Joiner.on(", ").join(args), reference));
}
private static void annotateInstruction3rc(@Nonnull AnnotatedBytes out, @Nonnull Instruction3rc instruction) {
int startRegister = instruction.getStartRegister();
int endRegister = startRegister + instruction.getRegisterCount() - 1;
String reference = ReferenceUtil.getReferenceString(instruction.getReference());
out.annotate(6, String.format("%s {%s .. %s}, %s",
instruction.getOpcode().name, formatRegister(startRegister), formatRegister(endRegister),
reference));
}
private static void annotateDefaultInstruction(@Nonnull AnnotatedBytes out, @Nonnull Instruction instruction) {
List<String> args = Lists.newArrayList();
if (instruction instanceof OneRegisterInstruction) {
args.add(formatRegister(((OneRegisterInstruction)instruction).getRegisterA()));
if (instruction instanceof TwoRegisterInstruction) {
args.add(formatRegister(((TwoRegisterInstruction)instruction).getRegisterB()));
if (instruction instanceof ThreeRegisterInstruction) {
args.add(formatRegister(((ThreeRegisterInstruction)instruction).getRegisterC()));
}
}
}
if (instruction instanceof ReferenceInstruction) {
args.add(ReferenceUtil.getReferenceString(
((ReferenceInstruction)instruction).getReference()));
}
if (instruction instanceof OffsetInstruction) {
int offset = ((OffsetInstruction)instruction).getCodeOffset();
String sign = offset>=0?"+":"-";
args.add(String.format("%s0x%x", sign, offset));
}
if (instruction instanceof NarrowLiteralInstruction) {
int value = ((NarrowLiteralInstruction)instruction).getNarrowLiteral();
if (NumberUtils.isLikelyFloat(value)) {
args.add(String.format("%d # %f", value, Float.intBitsToFloat(value)));
} else {
args.add(String.format("%d", value));
}
} else if (instruction instanceof WideLiteralInstruction) {
long value = ((WideLiteralInstruction)instruction).getWideLiteral();
if (NumberUtils.isLikelyDouble(value)) {
args.add(String.format("%d # %f", value, Double.longBitsToDouble(value)));
} else {
args.add(String.format("%d", value));
}
}
out.annotate(instruction.getCodeUnits()*2, "%s %s",
instruction.getOpcode().name, Joiner.on(", ").join(args));
}
private void annotateArrayPayload(@Nonnull AnnotatedBytes out, @Nonnull ArrayPayload instruction) {
List<Number> elements = instruction.getArrayElements();
int elementWidth = instruction.getElementWidth();
out.annotate(2, instruction.getOpcode().name);
out.indent();
out.annotate(2, "element_width = %d", elementWidth);
out.annotate(4, "size = %d", elements.size());
out.annotate(0, "elements:");
out.indent();
for (int i=0; i<elements.size(); i++) {
if (elementWidth == 8) {
long value = elements.get(i).longValue();
if (NumberUtils.isLikelyDouble(value)) {
out.annotate(elementWidth, "element[%d] = %d # %f", i, value, Double.longBitsToDouble(value));
} else {
out.annotate(elementWidth, "element[%d] = %d", i, value);
}
} else {
int value = elements.get(i).intValue();
if (NumberUtils.isLikelyFloat(value)) {
out.annotate(elementWidth, "element[%d] = %d # %f", i, value, Float.intBitsToFloat(value));
} else {
out.annotate(elementWidth, "element[%d] = %d", i, value);
}
}
}
if (out.getCursor() % 2 != 0) {
out.annotate(1, "padding");
}
out.deindent();
out.deindent();
}
private void annotatePackedSwitchPayload(@Nonnull AnnotatedBytes out,
@Nonnull PackedSwitchPayload instruction) {
List<? extends SwitchElement> elements = instruction.getSwitchElements();
out.annotate(2, instruction.getOpcode().name);
out.indent();
out.annotate(2, "size = %d", elements.size());
out.annotate(4, "first_key = %d", elements.get(0).getKey());
out.annotate(0, "targets:");
out.indent();
for (int i=0; i<elements.size(); i++) {
out.annotate(4, "target[%d] = %d", i, elements.get(i).getOffset());
}
out.deindent();
out.deindent();
}
private void annotateSparseSwitchPayload(@Nonnull AnnotatedBytes out,
@Nonnull SparseSwitchPayload instruction) {
List<? extends SwitchElement> elements = instruction.getSwitchElements();
out.annotate(2, instruction.getOpcode().name);
out.indent();
out.annotate(2, "size = %d", elements.size());
out.annotate(0, "keys:");
out.indent();
for (int i=0; i<elements.size(); i++) {
out.annotate(4, "key[%d] = %d", i, elements.get(i).getKey());
}
out.deindent();
out.annotate(0, "targets:");
out.indent();
for (int i=0; i<elements.size(); i++) {
out.annotate(4, "target[%d] = %d", i, elements.get(i).getOffset());
}
out.deindent();
out.deindent();
}
}
private static String formatRegister(int registerNum) {
return String.format("v%d", registerNum);
}
@Nonnull
public static SectionAnnotator getAnnotator() {
return new CodeItemAnnotator() {
@Override
public void annotateSection(@Nonnull AnnotatedBytes out, @Nonnull RawDexFile dexFile, int itemCount) {
final Map<Integer, String> methodMap = ClassDataItem.getCodeItemMethodMap(dexFile);
SectionAnnotator annotator = new CodeItemAnnotator() {
@Nullable @Override
public String getItemIdentity(@Nonnull RawDexFile dexFile, int itemIndex, int itemOffset) {
if (methodMap != null) {
return methodMap.get(itemOffset);
}
return null;
}
};
annotator.annotateSection(out, dexFile, itemCount);
}
};
}
}

View File

@ -97,6 +97,7 @@ public class RawDexFile extends DexBackedDexFile.Impl {
builder.put(ItemType.ANNOTATION_SET_ITEM, AnnotationSetItem.getAnnotator());
builder.put(ItemType.ANNOTATION_ITEM, AnnotationItem.getAnnotator());
builder.put(ItemType.CLASS_DATA_ITEM, ClassDataItem.getAnnotator());
builder.put(ItemType.CODE_ITEM, CodeItem.getAnnotator());
annotators = builder.build();
}

View File

@ -31,9 +31,10 @@
package org.jf.dexlib2.util;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.iface.reference.*;
import org.jf.util.StringUtils;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.Writer;
@ -93,5 +94,22 @@ public final class ReferenceUtil {
writer.write(fieldReference.getType());
}
@Nullable
public static String getReferenceString(Reference reference) {
if (reference instanceof StringReference) {
return String.format("\"%s\"", StringUtils.escapeString(((StringReference)reference).getString()));
}
if (reference instanceof TypeReference) {
return ((TypeReference)reference).getType();
}
if (reference instanceof FieldReference) {
return getFieldDescriptor((FieldReference)reference);
}
if (reference instanceof MethodReference) {
return getMethodDescriptor((MethodReference)reference);
}
return null;
}
private ReferenceUtil() {}
}

View File

@ -0,0 +1,141 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.util;
import java.text.DecimalFormat;
public class NumberUtils {
private static final int canonicalFloatNaN = Float.floatToRawIntBits(Float.NaN);
private static final int maxFloat = Float.floatToRawIntBits(Float.MAX_VALUE);
private static final int piFloat = Float.floatToRawIntBits((float)Math.PI);
private static final int eFloat = Float.floatToRawIntBits((float)Math.E);
private static final long canonicalDoubleNaN = Double.doubleToRawLongBits(Double.NaN);
private static final long maxDouble = Double.doubleToLongBits(Double.MAX_VALUE);
private static final long piDouble = Double.doubleToLongBits(Math.PI);
private static final long eDouble = Double.doubleToLongBits(Math.E);
private static final DecimalFormat format = new DecimalFormat("0.####################E0");
public static boolean isLikelyFloat(int value) {
// Check for some common named float values
// We don't check for Float.MIN_VALUE, which has an integer representation of 1
if (value == canonicalFloatNaN ||
value == maxFloat ||
value == piFloat ||
value == eFloat) {
return true;
}
// Check for some named integer values
if (value == Integer.MAX_VALUE || value == Integer.MIN_VALUE) {
return false;
}
// Check for likely resource id
int packageId = value >> 24;
int resourceType = value >> 16 & 0xff;
int resourceId = value & 0xffff;
if ((packageId == 0x7f || packageId == 1) && resourceType < 0x1f && resourceId < 0xfff) {
return false;
}
// a non-canocical NaN is more likely to be an integer
float floatValue = Float.intBitsToFloat(value);
if (Float.isNaN(floatValue)) {
return false;
}
// Otherwise, whichever has a shorter scientific notation representation is more likely.
// Integer wins the tie
String asInt = format.format(value);
String asFloat = format.format(floatValue);
// try to strip off any small imprecision near the end of the mantissa
int decimalPoint = asFloat.indexOf('.');
int exponent = asFloat.indexOf("E");
int zeros = asFloat.indexOf("000");
if (zeros > decimalPoint && zeros < exponent) {
asFloat = asFloat.substring(0, zeros) + asFloat.substring(exponent);
} else {
int nines = asFloat.indexOf("999");
if (nines > decimalPoint && nines < exponent) {
asFloat = asFloat.substring(0, nines) + asFloat.substring(exponent);
}
}
return asFloat.length() < asInt.length();
}
public static boolean isLikelyDouble(long value) {
// Check for some common named double values
// We don't check for Double.MIN_VALUE, which has a long representation of 1
if (value == canonicalDoubleNaN ||
value == maxDouble ||
value == piDouble ||
value == eDouble) {
return true;
}
// Check for some named long values
if (value == Long.MAX_VALUE || value == Long.MIN_VALUE) {
return false;
}
// a non-canocical NaN is more likely to be an long
double doubleValue = Double.longBitsToDouble(value);
if (Double.isNaN(doubleValue)) {
return false;
}
// Otherwise, whichever has a shorter scientific notation representation is more likely.
// Long wins the tie
String asLong = format.format(value);
String asDouble = format.format(doubleValue);
// try to strip off any small imprecision near the end of the mantissa
int decimalPoint = asDouble.indexOf('.');
int exponent = asDouble.indexOf("E");
int zeros = asDouble.indexOf("000");
if (zeros > decimalPoint && zeros < exponent) {
asDouble = asDouble.substring(0, zeros) + asDouble.substring(exponent);
} else {
int nines = asDouble.indexOf("999");
if (nines > decimalPoint && nines < exponent) {
asDouble = asDouble.substring(0, nines) + asDouble.substring(exponent);
}
}
return asDouble.length() < asLong.length();
}
}

View File

@ -0,0 +1,128 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.util;
import junit.framework.Assert;
import org.junit.Test;
public class NumberUtilsTest {
@Test
public void isLikelyFloatTest() {
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(1.23f)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(1.0f)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(Float.NaN)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(Float.NEGATIVE_INFINITY)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(Float.POSITIVE_INFINITY)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(1e-30f)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(1000f)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(1f)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(-1f)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(-5f)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(1.3333f)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(4.5f)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(.1f)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(50000f)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(Float.MAX_VALUE)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits((float)Math.PI)));
Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits((float)Math.E)));
Assert.assertTrue(NumberUtils.isLikelyFloat(2139095039));
// Float.MIN_VALUE is equivalent to integer value 1 - this should be detected as an integer
//Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(Float.MIN_VALUE)));
// This one doesn't quite work. It has a series of 2 0's, but that is probably not enough to strip off normally
//Assert.assertTrue(NumberUtils.isLikelyFloat(Float.floatToRawIntBits(1.33333f)));
Assert.assertFalse(NumberUtils.isLikelyFloat(0));
Assert.assertFalse(NumberUtils.isLikelyFloat(1));
Assert.assertFalse(NumberUtils.isLikelyFloat(10));
Assert.assertFalse(NumberUtils.isLikelyFloat(100));
Assert.assertFalse(NumberUtils.isLikelyFloat(1000));
Assert.assertFalse(NumberUtils.isLikelyFloat(1024));
Assert.assertFalse(NumberUtils.isLikelyFloat(1234));
Assert.assertFalse(NumberUtils.isLikelyFloat(-5));
Assert.assertFalse(NumberUtils.isLikelyFloat(-13));
Assert.assertFalse(NumberUtils.isLikelyFloat(-123));
Assert.assertFalse(NumberUtils.isLikelyFloat(20000000));
Assert.assertFalse(NumberUtils.isLikelyFloat(2000000000));
Assert.assertFalse(NumberUtils.isLikelyFloat(-2000000000));
Assert.assertFalse(NumberUtils.isLikelyFloat(Integer.MAX_VALUE));
Assert.assertFalse(NumberUtils.isLikelyFloat(Integer.MIN_VALUE));
Assert.assertFalse(NumberUtils.isLikelyFloat(Short.MIN_VALUE));
Assert.assertFalse(NumberUtils.isLikelyFloat(Short.MAX_VALUE));
}
@Test
public void isLikelyDoubleTest() {
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(1.23f)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(1.0f)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(Double.NaN)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(Double.POSITIVE_INFINITY)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(1e-30f)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(1000f)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(1f)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(-1f)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(-5f)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(1.3333f)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(1.33333f)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(4.5f)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(.1f)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(50000f)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(Double.MAX_VALUE)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(Math.PI)));
Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(Math.E)));
// Double.MIN_VALUE is equivalent to integer value 1 - this should be detected as an integer
//Assert.assertTrue(NumberUtils.isLikelyDouble(Double.doubleToRawLongBits(Double.MIN_VALUE)));
Assert.assertFalse(NumberUtils.isLikelyDouble(0));
Assert.assertFalse(NumberUtils.isLikelyDouble(1));
Assert.assertFalse(NumberUtils.isLikelyDouble(10));
Assert.assertFalse(NumberUtils.isLikelyDouble(100));
Assert.assertFalse(NumberUtils.isLikelyDouble(1000));
Assert.assertFalse(NumberUtils.isLikelyDouble(1024));
Assert.assertFalse(NumberUtils.isLikelyDouble(1234));
Assert.assertFalse(NumberUtils.isLikelyDouble(-5));
Assert.assertFalse(NumberUtils.isLikelyDouble(-13));
Assert.assertFalse(NumberUtils.isLikelyDouble(-123));
Assert.assertFalse(NumberUtils.isLikelyDouble(20000000));
Assert.assertFalse(NumberUtils.isLikelyDouble(2000000000));
Assert.assertFalse(NumberUtils.isLikelyDouble(-2000000000));
Assert.assertFalse(NumberUtils.isLikelyDouble(Integer.MAX_VALUE));
Assert.assertFalse(NumberUtils.isLikelyDouble(Integer.MIN_VALUE));
Assert.assertFalse(NumberUtils.isLikelyDouble(Short.MIN_VALUE));
Assert.assertFalse(NumberUtils.isLikelyDouble(Short.MAX_VALUE));
}
}