com.googlecode.d2j.dex.writer.item.ConstPool Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dex-writer Show documentation
Show all versions of dex-writer Show documentation
Dex/Dalvik writer for dex2jar
package com.googlecode.d2j.dex.writer.item;
import com.googlecode.d2j.CallSite;
import com.googlecode.d2j.DexConstants;
import com.googlecode.d2j.DexType;
import com.googlecode.d2j.Field;
import com.googlecode.d2j.Method;
import com.googlecode.d2j.MethodHandle;
import com.googlecode.d2j.Proto;
import com.googlecode.d2j.dex.writer.DexWriteException;
import com.googlecode.d2j.dex.writer.ev.EncodedArray;
import com.googlecode.d2j.dex.writer.ev.EncodedValue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.TreeMap;
public class ConstPool {
public int dexVersion = DexConstants.DEX_035;
public Map annotationSetRefListItems
= new HashMap<>();
public Map callSiteIdItems = new TreeMap<>();
public Map encodedArrayItems = new TreeMap<>();
public List codeItems = new ArrayList<>();
public List classDataItems = new ArrayList<>();
public List debugInfoItems = new ArrayList<>();
public Map annotationItems = new HashMap<>();
public List annotationsDirectoryItems = new ArrayList<>();
public Map annotationSetItems = new HashMap<>();
public Map fields = new TreeMap<>();
public Map methods = new TreeMap<>();
public Map protos = new TreeMap<>();
public List stringDatas = new ArrayList<>(100);
public Map strings = new TreeMap<>();
public Map typeLists = new TreeMap<>();
public Map types = new TreeMap<>();
public Map classDefs = new HashMap<>();
public Map methodHandlers = new TreeMap<>();
public Object wrapEncodedItem(Object value) {
if (value instanceof DexType) {
return uniqType(((DexType) value).desc);
} else if (value instanceof Field) {
return uniqField((Field) value);
} else if (value instanceof String) {
return uniqString((String) value);
} else if (value instanceof Method) {
return uniqMethod((Method) value);
} else if (value instanceof MethodHandle) {
return uniqMethodHandle((MethodHandle) value);
} else if (value instanceof Proto) {
return uniqProto((Proto) value);
}
return value;
}
private MethodHandleItem uniqMethodHandle(MethodHandle value) {
MethodHandleItem mh = new MethodHandleItem();
mh.type = value.getType();
Field field = value.getField();
Method method = value.getMethod();
if (field != null) {
mh.field = uniqField(field);
} else if (method != null) {
mh.method = uniqMethod(method);
}
MethodHandleItem result = methodHandlers.get(mh);
if (result == null) {
methodHandlers.put(mh, mh);
result = mh;
}
return result;
}
public void clean() {
encodedArrayItems.clear();
annotationSetRefListItems.clear();
codeItems.clear();
classDataItems.clear();
debugInfoItems.clear();
annotationItems.clear();
annotationsDirectoryItems.clear();
annotationSetItems.clear();
fields.clear();
methods.clear();
protos.clear();
stringDatas.clear();
typeLists.clear();
types.clear();
classDefs.clear();
}
private String buildShorty(String ret, String[] types2) {
StringBuilder sb = new StringBuilder();
if (ret.length() == 1) {
sb.append(ret);
} else {
sb.append("L");
}
for (String s : types2) {
if (s.length() == 1) {
sb.append(s);
} else {
sb.append("L");
}
}
return sb.toString();
}
PE iterateParent(ClassDefItem p) {
List list = new ArrayList<>(6);
list.add(p.superclazz);
if (p.interfaces != null) {
list.addAll(p.interfaces.items);
}
return new PE(p, list.iterator());
}
public void addDebugInfoItem(DebugInfoItem debugInfoItem) {
debugInfoItems.add(debugInfoItem);
}
public void dex039() {
if (dexVersion < DexConstants.DEX_039) {
dexVersion = DexConstants.DEX_039;
}
}
public void dex038() {
if (dexVersion < DexConstants.DEX_038) {
dexVersion = DexConstants.DEX_038;
}
}
static class PE {
final ClassDefItem owner;
final Iterator it;
PE(ClassDefItem owner, Iterator it) {
this.owner = owner;
this.it = it;
}
}
public List buildSortedClassDefItems() {
List added = new ArrayList<>();
Stack stack1 = new Stack<>();
Set children = new HashSet<>();
for (ClassDefItem c : classDefs.values()) {
if (added.contains(c)) {
continue;
}
children.add(c);
stack1.push(iterateParent(c));
while (!stack1.empty()) {
PE e = stack1.peek();
boolean canPop = true;
while (e.it.hasNext()) {
TypeIdItem tid = e.it.next();
if (tid == null) {
continue;
}
ClassDefItem superDef = classDefs.get(tid);
if (superDef != null && !added.contains(superDef)) {
if (children.contains(superDef)) {
System.err.println("WARN: dep-loop " + e.owner.clazz.descriptor.stringData.string + " -> "
+ superDef.clazz.descriptor.stringData.string);
} else {
canPop = false;
children.add(superDef);
stack1.push(iterateParent(superDef));
break;
}
}
}
if (canPop) {
stack1.pop();
added.add(e.owner);
children.remove(e.owner);
}
}
children.clear();
}
return added;
}
public AnnotationsDirectoryItem putAnnotationDirectoryItem() {
AnnotationsDirectoryItem aDirectoryItem = new AnnotationsDirectoryItem();
annotationsDirectoryItems.add(aDirectoryItem);
return aDirectoryItem;
}
public AnnotationItem uniqAnnotationItem(AnnotationItem key) {
AnnotationItem v = annotationItems.get(key);
if (v == null) {
annotationItems.put(key, key);
return key;
}
return v;
}
public ClassDefItem putClassDefItem(int accessFlag, String name, String superClass, String[] itfClass) {
TypeIdItem type = uniqType(name);
if (classDefs.containsKey(type)) {
throw new DexWriteException("dup clz: " + name);
}
ClassDefItem classDefItem = new ClassDefItem();
classDefItem.accessFlags = accessFlag;
classDefItem.clazz = type;
if (superClass != null) {
classDefItem.superclazz = uniqType(superClass);
}
if (itfClass != null && itfClass.length > 0) {
classDefItem.interfaces = putTypeList(Arrays.asList(itfClass));
}
classDefs.put(type, classDefItem);
return classDefItem;
}
public FieldIdItem uniqField(Field field) {
return uniqField(field.getOwner(), field.getName(), field.getType());
}
public FieldIdItem uniqField(String owner, String name, String type) {
FieldIdItem key = new FieldIdItem(uniqType(owner), uniqString(name), uniqType(type));
FieldIdItem item = fields.get(key);
if (item != null) {
return item;
}
fields.put(key, key);
return key;
}
public MethodIdItem uniqMethod(Method method) {
MethodIdItem key = new MethodIdItem(uniqType(method.getOwner()), uniqString(method.getName()),
uniqProto(method));
return uniqMethod(key);
}
public MethodIdItem uniqMethod(String owner, String name, String[] params, String ret) {
MethodIdItem key = new MethodIdItem(uniqType(owner), uniqString(name), uniqProto(params, ret));
return uniqMethod(key);
}
public MethodIdItem uniqMethod(MethodIdItem key) {
MethodIdItem item = methods.get(key);
if (item != null) {
return item;
}
methods.put(key, key);
return key;
}
public ProtoIdItem uniqProto(Proto method) {
return uniqProto(method.getParameterTypes(), method.getReturnType());
}
private ProtoIdItem uniqProto(Method method) {
return uniqProto(method.getProto());
}
public ProtoIdItem uniqProto(String[] types, String retDesc) {
TypeIdItem ret = uniqType(retDesc);
StringIdItem shorty = uniqString(buildShorty(retDesc, types));
TypeListItem params = putTypeList(types);
ProtoIdItem key = new ProtoIdItem(params, ret, shorty);
ProtoIdItem item = protos.get(key);
if (item != null) {
return item;
} else {
protos.put(key, key);
return key;
}
}
public StringIdItem uniqString(String data) {
StringIdItem item = strings.get(data);
if (item != null) {
return item;
}
StringDataItem sd = new StringDataItem(data);
stringDatas.add(sd);
item = new StringIdItem(sd);
strings.put(data, item);
return item;
}
public TypeIdItem uniqType(String type) {
TypeIdItem item = types.get(type);
if (item != null) {
return item;
}
item = new TypeIdItem(uniqString(type));
types.put(type, item);
return item;
}
private TypeListItem putTypeList(String... subList) {
if (subList.length == 0) {
return ZERO_SIZE_TYPE_LIST;
}
List idItems = new ArrayList<>(subList.length);
for (String s : subList) {
idItems.add(uniqType(s));
}
TypeListItem key = new TypeListItem(idItems);
TypeListItem item = typeLists.get(key);
if (item != null) {
return item;
}
typeLists.put(key, key);
return key;
}
private static final TypeListItem ZERO_SIZE_TYPE_LIST = new TypeListItem(new ArrayList<>());
static {
// make sure the offset is 0
ZERO_SIZE_TYPE_LIST.offset = 0;
}
private TypeListItem putTypeList(List subList) {
if (subList.isEmpty()) {
return ZERO_SIZE_TYPE_LIST;
}
List idItems = new ArrayList<>(subList.size());
for (String s : subList) {
idItems.add(uniqType(s));
}
TypeListItem key = new TypeListItem(idItems);
TypeListItem item = typeLists.get(key);
if (item != null) {
return item;
}
typeLists.put(key, key);
return key;
}
public ClassDataItem addClassDataItem(ClassDataItem dataItem) {
classDataItems.add(dataItem);
return dataItem;
}
public CallSiteIdItem uniqCallSite(CallSite callSite) {
EncodedArray e = new EncodedArray();
e.values.add(new EncodedValue(EncodedValue.VALUE_METHOD_HANDLE,
uniqMethodHandle(callSite.getBootstrapMethodHandler())));
e.values.add(new EncodedValue(EncodedValue.VALUE_STRING, uniqString(callSite.getMethodName())));
e.values.add(new EncodedValue(EncodedValue.VALUE_METHOD_TYPE, uniqProto(callSite.getMethodProto())));
for (Object arg : callSite.getExtraArguments()) {
e.values.add(EncodedValue.wrap(wrapEncodedItem(arg)));
}
CallSiteIdItem k = new CallSiteIdItem(callSite.getName(), uniqEncodedArrayItem(e));
CallSiteIdItem v = callSiteIdItems.get(k);
if (v == null) {
v = k;
callSiteIdItems.put(v, v);
}
return v;
}
public EncodedArray uniqEncodedArrayItem(EncodedArray k) {
EncodedArray v = encodedArrayItems.get(k);
if (v == null) {
v = k;
encodedArrayItems.put(v, v);
}
return v;
}
public AnnotationSetItem uniqAnnotationSetItem(AnnotationSetItem key) {
List copy = new ArrayList<>(key.annotations);
key.annotations.clear();
for (AnnotationItem annotationItem : copy) {
key.annotations.add(uniqAnnotationItem(annotationItem));
}
AnnotationSetItem v = annotationSetItems.get(key);
if (v != null) {
return v;
}
annotationSetItems.put(key, key);
return key;
}
public AnnotationSetRefListItem uniqAnnotationSetRefListItem(AnnotationSetRefListItem key) {
for (int i = 0; i < key.annotationSets.length; i++) {
AnnotationSetItem anno = key.annotationSets[i];
if (anno != null) {
key.annotationSets[i] = uniqAnnotationSetItem(anno);
}
}
AnnotationSetRefListItem v = annotationSetRefListItems.get(key);
if (v == null) {
annotationSetRefListItems.put(key, key);
return key;
}
return v;
}
public void addCodeItem(CodeItem code) {
codeItems.add(code);
}
}