package jadx.core.xmlgen.entry;
import jadx.core.xmlgen.ParserConstants;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ValuesParser extends ParserConstants {
private static final Logger LOG = LoggerFactory.getLogger(ValuesParser.class);
private final String[] strings;
private final Map<Integer, String> resMap;
public ValuesParser(String[] strings, Map<Integer, String> resMap) {
this.strings = strings;
this.resMap = resMap;
}
public String getValueString(ResourceEntry ri) {
RawValue simpleValue = ri.getSimpleValue();
if (simpleValue != null) {
return decodeValue(simpleValue);
}
List<RawNamedValue> namedValues = ri.getNamedValues();
List<String> strList = new ArrayList<String>(namedValues.size());
for (RawNamedValue value : namedValues) {
String nameStr = decodeNameRef(value.getNameRef());
String valueStr = decodeValue(value.getRawValue());
if (nameStr == null) {
strList.add(valueStr);
} else {
strList.add(nameStr + "=" + valueStr);
}
}
return strList.toString();
}
public String decodeValue(RawValue value) {
int dataType = value.getDataType();
int data = value.getData();
return decodeValue(dataType, data);
}
public String decodeValue(int dataType, int data) {
switch (dataType) {
case TYPE_NULL:
return null;
case TYPE_STRING:
return strings[data];
case TYPE_INT_DEC:
return Integer.toString(data);
case TYPE_INT_HEX:
return Integer.toHexString(data);
case TYPE_INT_BOOLEAN:
return data == 0 ? "false" : "true";
case TYPE_FLOAT:
return Float.toString(Float.intBitsToFloat(data));
case TYPE_INT_COLOR_ARGB8:
return String.format("#%08x", data);
case TYPE_INT_COLOR_RGB8:
return String.format("#%06x", data & 0xFFFFFF);
case TYPE_INT_COLOR_ARGB4:
return String.format("#%04x", data & 0xFFFF);
case TYPE_INT_COLOR_RGB4:
return String.format("#%03x", data & 0xFFF);
case TYPE_REFERENCE: {
String ri = resMap.get(data);
if (ri == null) {
return "?unknown_ref: " + Integer.toHexString(data);
}
return "@" + ri;
}
case TYPE_ATTRIBUTE: {
String ri = resMap.get(data);
if (ri == null) {
return "?unknown_attr_ref: " + Integer.toHexString(data);
}
return "?" + ri;
}
case TYPE_DIMENSION:
return decodeComplex(data, false);
case TYPE_FRACTION:
return decodeComplex(data, true);
default:
LOG.warn("Unknown data type: 0x{} {}", Integer.toHexString(dataType), data);
return " ?0x" + Integer.toHexString(dataType) + " " + data;
}
}
private String decodeNameRef(int nameRef) {
int ref = nameRef;
if (isResInternalId(nameRef)) {
ref = nameRef & ATTR_TYPE_ANY;
if (ref == 0) {
return null;
}
}
String ri = resMap.get(ref);
if (ri != null) {
return ri.replace('/', '.');
}
return "?0x" + Integer.toHexString(nameRef);
}
private String decodeComplex(int data, boolean isFraction) {
double value = (data & COMPLEX_MANTISSA_MASK << COMPLEX_MANTISSA_SHIFT)
* RADIX_MULTS[data >> COMPLEX_RADIX_SHIFT & COMPLEX_RADIX_MASK];
int unitType = data & COMPLEX_UNIT_MASK;
String unit;
if (isFraction) {
value *= 100;
switch (unitType) {
case COMPLEX_UNIT_FRACTION:
unit = "%";
break;
case COMPLEX_UNIT_FRACTION_PARENT:
unit = "%p";
break;
default:
unit = "?f" + Integer.toHexString(unitType);
}
} else {
switch (unitType) {
case COMPLEX_UNIT_PX:
unit = "px";
break;
case COMPLEX_UNIT_DIP:
unit = "dp";
break;
case COMPLEX_UNIT_SP:
unit = "sp";
break;
case COMPLEX_UNIT_PT:
unit = "pt";
break;
case COMPLEX_UNIT_IN:
unit = "in";
break;
case COMPLEX_UNIT_MM:
unit = "mm";
break;
default:
unit = "?d" + Integer.toHexString(unitType);
}
}
return doubleToString(value) + unit;
}
private static String doubleToString(double value) {
if (value == Math.ceil(value)) {
return Integer.toString((int) value);
} else {
// remove trailing zeroes
NumberFormat f = NumberFormat.getInstance();
f.setMaximumFractionDigits(4);
f.setMinimumIntegerDigits(1);
return f.format(value);
}
}
}