|
|
@ -123,158 +123,128 @@ public class ConstExprent extends Exprent { |
|
|
|
if (constType.type != CodeConstants.TYPE_NULL && value == null) { |
|
|
|
if (constType.type != CodeConstants.TYPE_NULL && value == null) { |
|
|
|
return new TextBuffer(ExprProcessor.getCastTypeName(constType)); |
|
|
|
return new TextBuffer(ExprProcessor.getCastTypeName(constType)); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
|
|
|
|
switch (constType.type) { |
|
|
|
|
|
|
|
case CodeConstants.TYPE_BOOLEAN: |
|
|
|
|
|
|
|
return new TextBuffer(Boolean.toString(((Integer)value).intValue() != 0)); |
|
|
|
|
|
|
|
case CodeConstants.TYPE_CHAR: |
|
|
|
|
|
|
|
Integer val = (Integer)value; |
|
|
|
|
|
|
|
String ret = ESCAPES.get(val); |
|
|
|
|
|
|
|
if (ret == null) { |
|
|
|
|
|
|
|
char c = (char)val.intValue(); |
|
|
|
|
|
|
|
if (c >= 32 && c < 127 || !ascii && TextUtil.isPrintableUnicode(c)) { |
|
|
|
|
|
|
|
ret = String.valueOf(c); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
ret = TextUtil.charToUnicodeLiteral(c); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return new TextBuffer(ret).enclose("\'", "\'"); |
|
|
|
|
|
|
|
case CodeConstants.TYPE_BYTE: |
|
|
|
|
|
|
|
case CodeConstants.TYPE_BYTECHAR: |
|
|
|
|
|
|
|
case CodeConstants.TYPE_SHORT: |
|
|
|
|
|
|
|
case CodeConstants.TYPE_SHORTCHAR: |
|
|
|
|
|
|
|
case CodeConstants.TYPE_INT: |
|
|
|
|
|
|
|
int ival = ((Integer)value).intValue(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String intfield; |
|
|
|
|
|
|
|
if (literal) { |
|
|
|
|
|
|
|
return new TextBuffer(value.toString()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (ival == Integer.MAX_VALUE) { |
|
|
|
|
|
|
|
intfield = "MAX_VALUE"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (ival == Integer.MIN_VALUE) { |
|
|
|
|
|
|
|
intfield = "MIN_VALUE"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
return new TextBuffer(value.toString()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return new FieldExprent(intfield, "java/lang/Integer", true, null, FieldDescriptor.INTEGER_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
|
|
|
|
case CodeConstants.TYPE_LONG: |
|
|
|
|
|
|
|
long lval = ((Long)value).longValue(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String longfield; |
|
|
|
switch (constType.type) { |
|
|
|
if (literal) { |
|
|
|
case CodeConstants.TYPE_BOOLEAN: |
|
|
|
return new TextBuffer(value.toString()).append("L"); |
|
|
|
return new TextBuffer(Boolean.toString(((Integer)value).intValue() != 0)); |
|
|
|
} |
|
|
|
|
|
|
|
else if (lval == Long.MAX_VALUE) { |
|
|
|
case CodeConstants.TYPE_CHAR: |
|
|
|
longfield = "MAX_VALUE"; |
|
|
|
Integer val = (Integer)value; |
|
|
|
} |
|
|
|
String ret = ESCAPES.get(val); |
|
|
|
else if (lval == Long.MIN_VALUE) { |
|
|
|
if (ret == null) { |
|
|
|
longfield = "MIN_VALUE"; |
|
|
|
char c = (char)val.intValue(); |
|
|
|
|
|
|
|
if (c >= 32 && c < 127 || !ascii && TextUtil.isPrintableUnicode(c)) { |
|
|
|
|
|
|
|
ret = String.valueOf(c); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
return new TextBuffer(value.toString()).append("L"); |
|
|
|
ret = TextUtil.charToUnicodeLiteral(c); |
|
|
|
} |
|
|
|
|
|
|
|
return new FieldExprent(longfield, "java/lang/Long", true, null, FieldDescriptor.LONG_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
|
|
|
|
case CodeConstants.TYPE_DOUBLE: |
|
|
|
|
|
|
|
double dval = ((Double)value).doubleValue(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String doublefield; |
|
|
|
|
|
|
|
if (literal) { |
|
|
|
|
|
|
|
if (Double.isNaN(dval)) { |
|
|
|
|
|
|
|
return new TextBuffer("0.0D / 0.0"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (dval == Double.POSITIVE_INFINITY) { |
|
|
|
|
|
|
|
return new TextBuffer("1.0D / 0.0"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (dval == Double.NEGATIVE_INFINITY) { |
|
|
|
|
|
|
|
return new TextBuffer("-1.0D / 0.0"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
return new TextBuffer(value.toString()).append("D"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
else if (Double.isNaN(dval)) { |
|
|
|
} |
|
|
|
doublefield = "NaN"; |
|
|
|
return new TextBuffer().append('\'').append(ret).append('\''); |
|
|
|
} |
|
|
|
|
|
|
|
else if (dval == Double.POSITIVE_INFINITY) { |
|
|
|
case CodeConstants.TYPE_BYTE: |
|
|
|
doublefield = "POSITIVE_INFINITY"; |
|
|
|
case CodeConstants.TYPE_BYTECHAR: |
|
|
|
|
|
|
|
case CodeConstants.TYPE_SHORT: |
|
|
|
|
|
|
|
case CodeConstants.TYPE_SHORTCHAR: |
|
|
|
|
|
|
|
case CodeConstants.TYPE_INT: |
|
|
|
|
|
|
|
int intVal = ((Integer)value).intValue(); |
|
|
|
|
|
|
|
if (!literal) { |
|
|
|
|
|
|
|
if (intVal == Integer.MAX_VALUE) { |
|
|
|
|
|
|
|
return new FieldExprent("MAX_VALUE", "java/lang/Integer", true, null, FieldDescriptor.INTEGER_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (dval == Double.NEGATIVE_INFINITY) { |
|
|
|
else if (intVal == Integer.MIN_VALUE) { |
|
|
|
doublefield = "NEGATIVE_INFINITY"; |
|
|
|
return new FieldExprent("MIN_VALUE", "java/lang/Integer", true, null, FieldDescriptor.INTEGER_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (dval == Double.MAX_VALUE) { |
|
|
|
} |
|
|
|
doublefield = "MAX_VALUE"; |
|
|
|
return new TextBuffer(value.toString()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case CodeConstants.TYPE_LONG: |
|
|
|
|
|
|
|
long longVal = ((Long)value).longValue(); |
|
|
|
|
|
|
|
if (!literal) { |
|
|
|
|
|
|
|
if (longVal == Long.MAX_VALUE) { |
|
|
|
|
|
|
|
return new FieldExprent("MAX_VALUE", "java/lang/Long", true, null, FieldDescriptor.LONG_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (dval == Double.MIN_VALUE) { |
|
|
|
else if (longVal == Long.MIN_VALUE) { |
|
|
|
doublefield = "MIN_VALUE"; |
|
|
|
return new FieldExprent("MIN_VALUE", "java/lang/Long", true, null, FieldDescriptor.LONG_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
} |
|
|
|
return new TextBuffer(value.toString()).append("D"); |
|
|
|
return new TextBuffer(value.toString()).append('L'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case CodeConstants.TYPE_FLOAT: |
|
|
|
|
|
|
|
float floatVal = ((Float)value).floatValue(); |
|
|
|
|
|
|
|
if (!literal) { |
|
|
|
|
|
|
|
if (Float.isNaN(floatVal)) { |
|
|
|
|
|
|
|
return new FieldExprent("NaN", "java/lang/Float", true, null, FieldDescriptor.FLOAT_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
} |
|
|
|
} |
|
|
|
return new FieldExprent(doublefield, "java/lang/Double", true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
else if (floatVal == Float.POSITIVE_INFINITY) { |
|
|
|
case CodeConstants.TYPE_FLOAT: |
|
|
|
return new FieldExprent("POSITIVE_INFINITY", "java/lang/Float", true, null, FieldDescriptor.FLOAT_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
float fval = ((Float)value).floatValue(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String floatfield; |
|
|
|
|
|
|
|
if (literal) { |
|
|
|
|
|
|
|
if (Double.isNaN(fval)) { |
|
|
|
|
|
|
|
return new TextBuffer("0.0F / 0.0"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (fval == Double.POSITIVE_INFINITY) { |
|
|
|
|
|
|
|
return new TextBuffer("1.0F / 0.0"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (fval == Double.NEGATIVE_INFINITY) { |
|
|
|
|
|
|
|
return new TextBuffer("-1.0F / 0.0"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
return new TextBuffer(value.toString()).append("F"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
else if (Float.isNaN(fval)) { |
|
|
|
else if (floatVal == Float.NEGATIVE_INFINITY) { |
|
|
|
floatfield = "NaN"; |
|
|
|
return new FieldExprent("NEGATIVE_INFINITY", "java/lang/Float", true, null, FieldDescriptor.FLOAT_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (fval == Float.POSITIVE_INFINITY) { |
|
|
|
else if (floatVal == Float.MAX_VALUE) { |
|
|
|
floatfield = "POSITIVE_INFINITY"; |
|
|
|
return new FieldExprent("MAX_VALUE", "java/lang/Float", true, null, FieldDescriptor.FLOAT_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (fval == Float.NEGATIVE_INFINITY) { |
|
|
|
else if (floatVal == Float.MIN_VALUE) { |
|
|
|
floatfield = "NEGATIVE_INFINITY"; |
|
|
|
return new FieldExprent("MIN_VALUE", "java/lang/Float", true, null, FieldDescriptor.FLOAT_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (fval == Float.MAX_VALUE) { |
|
|
|
} |
|
|
|
floatfield = "MAX_VALUE"; |
|
|
|
else if (Float.isNaN(floatVal)) { |
|
|
|
|
|
|
|
return new TextBuffer("0.0F / 0.0"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (floatVal == Float.POSITIVE_INFINITY) { |
|
|
|
|
|
|
|
return new TextBuffer("1.0F / 0.0"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (floatVal == Float.NEGATIVE_INFINITY) { |
|
|
|
|
|
|
|
return new TextBuffer("-1.0F / 0.0"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return new TextBuffer(value.toString()).append('F'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case CodeConstants.TYPE_DOUBLE: |
|
|
|
|
|
|
|
double doubleVal = ((Double)value).doubleValue(); |
|
|
|
|
|
|
|
if (!literal) { |
|
|
|
|
|
|
|
if (Double.isNaN(doubleVal)) { |
|
|
|
|
|
|
|
return new FieldExprent("NaN", "java/lang/Double", true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (fval == Float.MIN_VALUE) { |
|
|
|
else if (doubleVal == Double.POSITIVE_INFINITY) { |
|
|
|
floatfield = "MIN_VALUE"; |
|
|
|
return new FieldExprent("POSITIVE_INFINITY", "java/lang/Double", true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else if (doubleVal == Double.NEGATIVE_INFINITY) { |
|
|
|
return new TextBuffer(value.toString()).append("F"); |
|
|
|
return new FieldExprent("NEGATIVE_INFINITY", "java/lang/Double", true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
} |
|
|
|
} |
|
|
|
return new FieldExprent(floatfield, "java/lang/Float", true, null, FieldDescriptor.FLOAT_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
else if (doubleVal == Double.MAX_VALUE) { |
|
|
|
case CodeConstants.TYPE_NULL: |
|
|
|
return new FieldExprent("MAX_VALUE", "java/lang/Double", true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
return new TextBuffer("null"); |
|
|
|
|
|
|
|
case CodeConstants.TYPE_OBJECT: |
|
|
|
|
|
|
|
if (constType.equals(VarType.VARTYPE_STRING)) { |
|
|
|
|
|
|
|
return new TextBuffer(convertStringToJava(value.toString(), ascii)).enclose("\"", "\""); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
else if (constType.equals(VarType.VARTYPE_CLASS)) { |
|
|
|
else if (doubleVal == Double.MIN_VALUE) { |
|
|
|
String strval = value.toString(); |
|
|
|
return new FieldExprent("MIN_VALUE", "java/lang/Double", true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer); |
|
|
|
|
|
|
|
|
|
|
|
VarType classtype; |
|
|
|
|
|
|
|
if (strval.startsWith("[")) { // array of simple type
|
|
|
|
|
|
|
|
classtype = new VarType(strval, false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { // class
|
|
|
|
|
|
|
|
classtype = new VarType(strval, true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new TextBuffer(ExprProcessor.getCastTypeName(classtype)).append(".class"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
else if (Double.isNaN(doubleVal)) { |
|
|
|
|
|
|
|
return new TextBuffer("0.0D / 0.0"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (doubleVal == Double.POSITIVE_INFINITY) { |
|
|
|
|
|
|
|
return new TextBuffer("1.0D / 0.0"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (doubleVal == Double.NEGATIVE_INFINITY) { |
|
|
|
|
|
|
|
return new TextBuffer("-1.0D / 0.0"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return new TextBuffer(value.toString()).append('D'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case CodeConstants.TYPE_NULL: |
|
|
|
|
|
|
|
return new TextBuffer("null"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case CodeConstants.TYPE_OBJECT: |
|
|
|
|
|
|
|
if (constType.equals(VarType.VARTYPE_STRING)) { |
|
|
|
|
|
|
|
return new TextBuffer().append('"').append(convertStringToJava(value.toString(), ascii)).append('"'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (constType.equals(VarType.VARTYPE_CLASS)) { |
|
|
|
|
|
|
|
String stringVal = value.toString(); |
|
|
|
|
|
|
|
VarType type = new VarType(stringVal, !stringVal.startsWith("[")); |
|
|
|
|
|
|
|
return new TextBuffer(ExprProcessor.getCastTypeName(type)).append(".class"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
throw new RuntimeException("invalid constant type"); |
|
|
|
throw new RuntimeException("invalid constant type: " + constType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static String convertStringToJava(String value, boolean ascii) { |
|
|
|
private static String convertStringToJava(String value, boolean ascii) { |
|
|
@ -339,9 +309,8 @@ public class ConstExprent extends Exprent { |
|
|
|
case CodeConstants.TYPE_SHORT: |
|
|
|
case CodeConstants.TYPE_SHORT: |
|
|
|
case CodeConstants.TYPE_SHORTCHAR: |
|
|
|
case CodeConstants.TYPE_SHORTCHAR: |
|
|
|
case CodeConstants.TYPE_INT: |
|
|
|
case CodeConstants.TYPE_INT: |
|
|
|
Integer ival = (Integer)value; |
|
|
|
int value = ((Integer)this.value).intValue(); |
|
|
|
return ival.intValue() == 0 || |
|
|
|
return value == 0 || (DecompilerContext.getOption(IFernflowerPreferences.BOOLEAN_TRUE_ONE) && value == 1); |
|
|
|
(DecompilerContext.getOption(IFernflowerPreferences.BOOLEAN_TRUE_ONE) && ival.intValue() == 1); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
return false; |
|
|
@ -380,7 +349,7 @@ public class ConstExprent extends Exprent { |
|
|
|
return new ConstExprent(VarType.VARTYPE_FLOAT, new Float(0), null); |
|
|
|
return new ConstExprent(VarType.VARTYPE_FLOAT, new Float(0), null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
throw new RuntimeException("Invalid argument!"); |
|
|
|
throw new RuntimeException("Invalid argument: " + type); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public VarType getConstType() { |
|
|
|
public VarType getConstType() { |
|
|
@ -407,28 +376,25 @@ public class ConstExprent extends Exprent { |
|
|
|
// IMatchable implementation
|
|
|
|
// IMatchable implementation
|
|
|
|
// *****************************************************************************
|
|
|
|
// *****************************************************************************
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
public boolean match(MatchNode matchNode, MatchEngine engine) { |
|
|
|
public boolean match(MatchNode matchNode, MatchEngine engine) { |
|
|
|
|
|
|
|
if (!super.match(matchNode, engine)) { |
|
|
|
if(!super.match(matchNode, engine)) { |
|
|
|
|
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for(Entry<MatchProperties, RuleValue> rule : matchNode.getRules().entrySet()) { |
|
|
|
for (Entry<MatchProperties, RuleValue> rule : matchNode.getRules().entrySet()) { |
|
|
|
RuleValue rule_value = rule.getValue(); |
|
|
|
RuleValue value = rule.getValue(); |
|
|
|
|
|
|
|
MatchProperties key = rule.getKey(); |
|
|
|
|
|
|
|
|
|
|
|
switch(rule.getKey()) { |
|
|
|
if (key == MatchProperties.EXPRENT_CONSTTYPE) { |
|
|
|
case EXPRENT_CONSTTYPE: |
|
|
|
if (!value.value.equals(this.constType)) { |
|
|
|
if(!rule_value.value.equals(this.constType)) { |
|
|
|
|
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case EXPRENT_CONSTVALUE: |
|
|
|
else if (key == MatchProperties.EXPRENT_CONSTVALUE) { |
|
|
|
if(rule_value.isVariable()) { |
|
|
|
if (value.isVariable() && !engine.checkAndSetVariableValue(value.value.toString(), this.value)) { |
|
|
|
if(!engine.checkAndSetVariableValue(rule_value.value.toString(), this.value)) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|