package com.googlecode.d2j.smali;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.googlecode.d2j.DexConstants;
import com.googlecode.d2j.Field;
import com.googlecode.d2j.Method;
import com.googlecode.d2j.Visibility;
import com.googlecode.d2j.reader.Op;
import com.googlecode.d2j.visitors.DexAnnotationVisitor;
public class Utils implements DexConstants {
public static void doAccept(DexAnnotationVisitor dexAnnotationVisitor, String k, Object value) {
if (value instanceof ArrayList) {
DexAnnotationVisitor a = dexAnnotationVisitor.visitArray(k);
for (Object o : (ArrayList) value) {
doAccept(a, null, o);
}
a.visitEnd();
} else if (value instanceof Ann) {
Ann ann = (Ann) value;
DexAnnotationVisitor a = dexAnnotationVisitor.visitAnnotation(k, ann.name);
for (Map.Entry<String, Object> e : ann.elements) {
doAccept(a, e.getKey(), e.getValue());
}
a.visitEnd();
} else if (value instanceof Field) {
Field f = (Field) value;
dexAnnotationVisitor.visitEnum(k, f.getOwner(), f.getName());
} else {
dexAnnotationVisitor.visit(k, value);
}
}
public static int getAcc(String name) {
if (name.equals("public")) {
return ACC_PUBLIC;
} else if (name.equals("private")) {
return ACC_PRIVATE;
} else if (name.equals("protected")) {
return ACC_PROTECTED;
} else if (name.equals("static")) {
return ACC_STATIC;
} else if (name.equals("final")) {
return ACC_FINAL;
} else if (name.equals("synchronized")) {
return ACC_SYNCHRONIZED;
} else if (name.equals("volatile")) {
return ACC_VOLATILE;
} else if (name.equals("bridge")) {
return ACC_BRIDGE;
} else if (name.equals("varargs")) {
return ACC_VARARGS;
} else if (name.equals("transient")) {
return ACC_TRANSIENT;
} else if (name.equals("native")) {
return ACC_NATIVE;
} else if (name.equals("interface")) {
return ACC_INTERFACE;
} else if (name.equals("abstract")) {
return ACC_ABSTRACT;
} else if (name.equals("strict")) {
return ACC_STRICT;
} else if (name.equals("synthetic")) {
return ACC_SYNTHETIC;
} else if (name.equals("annotation")) {
return ACC_ANNOTATION;
} else if (name.equals("enum")) {
return ACC_ENUM;
} else if (name.equals("constructor")) {
return ACC_CONSTRUCTOR;
} else if (name.equals("declared-synchronized")) {
return ACC_DECLARED_SYNCHRONIZED;
}
return 0;
}
public static List<String> listDesc(String desc) {
List<String> list = new ArrayList(5);
if (desc == null) {
return list;
}
char[] chars = desc.toCharArray();
int i = 0;
while (i < chars.length) {
switch (chars[i]) {
case 'V':
case 'Z':
case 'C':
case 'B':
case 'S':
case 'I':
case 'F':
case 'J':
case 'D':
list.add(Character.toString(chars[i]));
i++;
break;
case '[': {
int count = 1;
while (chars[i + count] == '[') {
count++;
}
if (chars[i + count] == 'L') {
count++;
while (chars[i + count] != ';') {
count++;
}
}
count++;
list.add(new String(chars, i, count));
i += count;
break;
}
case 'L': {
int count = 1;
while (chars[i + count] != ';') {
++count;
}
count++;
list.add(new String(chars, i, count));
i += count;
break;
}
default:
throw new RuntimeException("can't parse type list: " + desc);
}
}
return list;
}
public static String[] toTypeList(String s) {
return listDesc(s).toArray(new String[0]);
}
static public Byte parseByte(String str) {
return Byte.valueOf((byte) parseInt(str.substring(0, str.length() - 1)));
}
static public Short parseShort(String str) {
return Short.valueOf((short) parseInt(str.substring(0, str.length() - 1)));
}
static public Long parseLong(String str) {
int sof = 0;
int end = str.length() - 1;
int x = 1;
if (str.charAt(sof) == '+') {
sof++;
} else if (str.charAt(sof) == '-') {
sof++;
x = -1;
}
BigInteger v;
if (str.charAt(sof) == '0') {
sof++;
if (sof >= end) {
return 0L;
}
char c = str.charAt(sof);
if (c == 'x' || c == 'X') {// hex
sof++;
v = new BigInteger(str.substring(sof, end), 16);
} else {// oct
v = new BigInteger(str.substring(sof, end), 8);
}
} else {
v = new BigInteger(str.substring(sof, end), 10);
}
if (x == -1) {
return v.negate().longValue();
} else {
return v.longValue();
}
}
static public float parseFloat(String str) {
str = str.toLowerCase();
int s = 0;
float x = 1f;
if (str.charAt(s) == '+') {
s++;
} else if (str.charAt(s) == '-') {
s++;
x = -1;
}
int e = str.length() - 1;
if (str.charAt(e) == 'f') {
e--;
}
str = str.substring(s, e + 1);
if (str.equals("nan")) {
return Float.NaN;
}
if (str.equals("infinity")) {
return x < 0 ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
}
return (float) x * Float.parseFloat(str);
}
static public double parseDouble(String str) {
str = str.toLowerCase();
int s = 0;
double x = 1;
if (str.charAt(s) == '+') {
s++;
} else if (str.charAt(s) == '-') {
s++;
x = -1;
}
int e = str.length() - 1;
if (str.charAt(e) == 'd') {
e--;
}
str = str.substring(s, e + 1);
if (str.equals("nan")) {
return Double.NaN;
}
if (str.equals("infinity")) {
return x < 0 ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
}
return x * Double.parseDouble(str);
}
static public int parseInt(String str, int start, int end) {
int sof = start;
int x = 1;
if (str.charAt(sof) == '+') {
sof++;
} else if (str.charAt(sof) == '-') {
sof++;
x = -1;
}
long v;
if (str.charAt(sof) == '0') {
sof++;
if (sof >= end) {
return 0;
}
char c = str.charAt(sof);
if (c == 'x' || c == 'X') {// hex
sof++;
v = Long.parseLong(str.substring(sof, end), 16);
} else {// oct
v = Long.parseLong(str.substring(sof, end), 8);
}
} else {
v = Long.parseLong(str.substring(sof, end), 10);
}
return (int) (v * x);
}
static public int parseInt(String str) {
return parseInt(str, 0, str.length());
}
public static String unescapeStr(String str) {
return unEscape(str);
}
public static Character unescapeChar(String str) {
return unEscape(str).charAt(0);
}
public static int[] toIntArray(List<String> ss) {
int vs[] = new int[ss.size()];
for (int i = 0; i < ss.size(); i++) {
vs[i] = parseInt(ss.get(i));
}
return vs;
}
public static byte[] toByteArray(List<Object> ss) {
byte vs[] = new byte[ss.size()];
for (int i = 0; i < ss.size(); i++) {
vs[i] = ((Number) (ss.get(i))).byteValue();
}
return vs;
}
static Map<String, Op> ops = new HashMap();
static {
for (Op op : Op.values()) {
ops.put(op.displayName, op);
}
}
static public Op getOp(String name) {
return ops.get(name);
}
public static String unEscape(String str) {
return unEscape0(str, 1, str.length() - 1);
}
public static String unEscapeId(String str) {
return unEscape0(str, 0, str.length());
}
public static String unEscape0(String str, int start, int end) {
StringBuilder sb = new StringBuilder();
for (int i = start; i < end;) {
char c = str.charAt(i);
if (c == '\\') {
char d = str.charAt(i + 1);
switch (d) {
// ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
case 'b':
sb.append('\b');
i += 2;
break;
case 't':
sb.append('\t');
i += 2;
break;
case 'n':
sb.append('\n');
i += 2;
break;
case 'f':
sb.append('\f');
i += 2;
break;
case 'r':
sb.append('\r');
i += 2;
break;
case '\"':
sb.append('\"');
i += 2;
break;
case '\'':
sb.append('\'');
i += 2;
break;
case '\\':
sb.append('\\');
i += 2;
break;
case 'u':
String sub = str.substring(i + 2, i + 6);
sb.append((char) Integer.parseInt(sub, 16));
i += 6;
break;
default:
int x = 0;
while (x < 3) {
char e = str.charAt(i + 1 + x);
if (e >= '0' && e <= '7') {
x++;
} else {
break;
}
}
if (x == 0) {
throw new RuntimeException("can't pase string");
}
sb.append((char) Integer.parseInt(str.substring(i + 1, i + 1 + x), 8));
i += 1 + x;
}
} else {
sb.append(c);
i++;
}
}
return sb.toString();
}
public static class Ann {
public String name;
public List<Map.Entry<String, Object>> elements = new ArrayList();
public void put(String name, Object value) {
elements.add(new java.util.AbstractMap.SimpleEntry(name, value));
}
}
public static Visibility getAnnVisibility(String name) {
return Visibility.valueOf(name.toUpperCase());
}
public static int methodIns(Method m, boolean isStatic) {
int a = isStatic ? 0 : 1;
for (String t : m.getParameterTypes()) {
switch (t.charAt(0)) {
case 'J':
case 'D':
a += 2;
break;
default:
a += 1;
break;
}
}
return a;
}
}