mirror of
https://github.com/pxb1988/dex2jar.git
synced 2024-11-23 05:10:11 +00:00
support dex 038
This commit is contained in:
parent
caf241d635
commit
0862aaeb39
@ -175,8 +175,7 @@ sAnnotationValue
|
||||
:sSubannotation
|
||||
|sBaseValue
|
||||
|sArrayValue
|
||||
| ( '.iget' | '.iput' | '.sget' | '.sput' ) FIELD_FULL
|
||||
| ( '.invoke-instance' | '.invoke-static' ) METHOD_FULL
|
||||
| method_handler
|
||||
;// field,method,array,subannotation
|
||||
sBaseValue
|
||||
:STRING
|
||||
@ -199,6 +198,11 @@ method_handler
|
||||
| type=('invoke-static'|'invoke-instance'|'invoke-direct'|'invoke-interface'|'invoke-constructor') '@' mtd=METHOD_FULL
|
||||
;
|
||||
|
||||
// FIXME samli syntax only write out method_handler's method field
|
||||
call_site
|
||||
: name=sAnnotationKeyName '(' method_name=STRING ',' method_type=METHOD_PROTO (',' sBaseValue)* ')' '@' bsm=METHOD_FULL
|
||||
;
|
||||
|
||||
sInstruction
|
||||
:fline
|
||||
|flocal
|
||||
@ -415,9 +419,9 @@ fm45cc : op='invoke-polymorphic' '{' (REGISTER (',' REGISTER)* )? '}' ',' metho
|
||||
;
|
||||
fm4rcc : op='invoke-polymorphic/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' method=METHOD_FULL ',' proto=METHOD_PROTO
|
||||
;
|
||||
fmcustomc : op='invoke-custom' '{' (REGISTER (',' REGISTER)* )? '}' ',' sArrayValue
|
||||
fmcustomc : op='invoke-custom' '{' (REGISTER (',' REGISTER)* )? '}' ',' call_site
|
||||
;
|
||||
fmcustomrc : op='invoke-custom/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' sArrayValue
|
||||
fmcustomrc : op='invoke-custom/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' call_site
|
||||
;
|
||||
ftrc : op='filled-new-array/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' type=(OBJECT_TYPE|ARRAY_TYPE);
|
||||
f31t: op=('fill-array-data'|'packed-switch'|'sparse-switch') r1=REGISTER ',' label=LABEL;
|
||||
|
@ -431,6 +431,65 @@ public class AntlrSmaliUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitFm4rcc(SmaliParser.Fm4rccContext ctx) {
|
||||
if (ctx.rstart != null) {
|
||||
int start = m.pareReg(ctx.rstart.getText());
|
||||
int end = m.pareReg(ctx.rend.getText());
|
||||
int size = end - start + 1;
|
||||
int[] rs = new int[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
rs[i] = start + i;
|
||||
}
|
||||
scv.visitMethodStmt(getOp(ctx.op), rs, parseMethodAndUnescape(ctx.method.getText()), parseProtoAndUnescape(ctx.proto.getText()));
|
||||
} else {
|
||||
scv.visitMethodStmt(getOp(ctx.op), new int[0], parseMethodAndUnescape(ctx.method.getText()), parseProtoAndUnescape(ctx.proto.getText()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitFm45cc(SmaliParser.Fm45ccContext ctx) {
|
||||
Op op = getOp(ctx.op);
|
||||
List<TerminalNode> ts = ctx.REGISTER();
|
||||
int[] rs = new int[ts.size()];
|
||||
for (int i = 0; i < ts.size(); i++) {
|
||||
rs[i] = m.pareReg(ts.get(i).getSymbol().getText());
|
||||
}
|
||||
scv.visitMethodStmt(op, rs, parseMethodAndUnescape(ctx.method.getText()), parseProtoAndUnescape(ctx.proto.getText()));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitFmcustomc(SmaliParser.FmcustomcContext ctx) {
|
||||
Op op = getOp(ctx.op);
|
||||
|
||||
List<TerminalNode> ts = ctx.REGISTER();
|
||||
int[] rs = new int[ts.size()];
|
||||
for (int i = 0; i < ts.size(); i++) {
|
||||
rs[i] = m.pareReg(ts.get(i).getSymbol().getText());
|
||||
}
|
||||
scv.visitMethodStmt(op, rs, parseCallSite(ctx.call_site()));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitFmcustomrc(SmaliParser.FmcustomrcContext ctx) {
|
||||
if (ctx.rstart != null) {
|
||||
int start = m.pareReg(ctx.rstart.getText());
|
||||
int end = m.pareReg(ctx.rend.getText());
|
||||
int size = end - start + 1;
|
||||
int[] rs = new int[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
rs[i] = start + i;
|
||||
}
|
||||
scv.visitMethodStmt(getOp(ctx.op), rs, parseCallSite(ctx.call_site()));
|
||||
} else {
|
||||
scv.visitMethodStmt(getOp(ctx.op), new int[0], parseCallSite(ctx.call_site()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitFmrc(SmaliParser.FmrcContext ctx) {
|
||||
if (ctx.rstart != null) {
|
||||
@ -554,6 +613,25 @@ public class AntlrSmaliUtil {
|
||||
scv.visitEnd();
|
||||
}
|
||||
|
||||
private static CallSite parseCallSite(SmaliParser.Call_siteContext callSiteContext) {
|
||||
|
||||
List<SmaliParser.SBaseValueContext> sBaseValueContexts = callSiteContext.sBaseValue();
|
||||
Object[] args = new Object[sBaseValueContexts.size()];
|
||||
int i = 0;
|
||||
for (SmaliParser.SBaseValueContext baseValueContext : sBaseValueContexts) {
|
||||
args[i] = parseBaseValue(baseValueContext);
|
||||
i++;
|
||||
}
|
||||
|
||||
return new CallSite(
|
||||
unEscapeId(callSiteContext.name.getText()),
|
||||
new MethodHandle(MethodHandle.INVOKE_STATIC, parseMethodAndUnescape(callSiteContext.bsm.getText())),
|
||||
unescapeStr(callSiteContext.method_name.getText()),
|
||||
parseProtoAndUnescape(callSiteContext.method_type.getText()),
|
||||
args
|
||||
);
|
||||
}
|
||||
|
||||
private static MethodHandle parseMethodHandler(SmaliParser.Method_handlerContext methodHandlerContext) {
|
||||
MethodHandle value;
|
||||
switch (methodHandlerContext.type.getText()) {
|
||||
@ -781,6 +859,10 @@ public class AntlrSmaliUtil {
|
||||
Object value = parseBaseValue(baseValueContext);
|
||||
dexAnnotationVisitor.visit(name, value);
|
||||
break;
|
||||
case SmaliParser.RULE_method_handler:
|
||||
MethodHandle methodHandle = parseMethodHandler((SmaliParser.Method_handlerContext) t);
|
||||
dexAnnotationVisitor.visit(name, methodHandle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -385,14 +385,25 @@ import java.util.*;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodStmt(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object... bsmArgs) {
|
||||
public void visitMethodStmt(Op op, int[] args, CallSite callSite) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{ ").append( BaksmaliDumper.escapeValue(bsm)).append(", ").append(BaksmaliDumper.escapeValue(name)).append(", ").append(BaksmaliDumper.escapeMethodDesc(proto));
|
||||
for(Object o: bsmArgs) {
|
||||
sb.append(", ").append(BaksmaliDumper.escapeValue(o));
|
||||
}
|
||||
sb.append("}");
|
||||
Object[] extraArguments = callSite.getExtraArguments();
|
||||
|
||||
// invoke-custom/range {v0 .. v5}, call_site_1("runDynamic", (IIIIII)V, 0x378)@L038;->bsm(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;
|
||||
|
||||
sb
|
||||
.append(BaksmaliDumper.escapeId(callSite.getName()))
|
||||
.append('(')
|
||||
.append(BaksmaliDumper.escapeValue(callSite.getMethodName()))
|
||||
.append(", ")
|
||||
.append(BaksmaliDumper.escapeMethodDesc(callSite.getMethodProto()));
|
||||
if (extraArguments != null && extraArguments.length > 0) {
|
||||
for (Object o : extraArguments) {
|
||||
sb.append(", ").append(BaksmaliDumper.escapeValue(o));
|
||||
}
|
||||
}
|
||||
// FIXME samli syntax only write out method_handler's method field
|
||||
sb.append(")@").append(BaksmaliDumper.escapeMethod(callSite.getBootstrapMethodHandler().getMethod()));
|
||||
|
||||
if (args.length > 0) {
|
||||
if (op.format == InstructionFormat.kFmt3rc) { // invoke-x/range
|
||||
|
@ -72,14 +72,7 @@ public class SmaliTest {
|
||||
|
||||
private void dotest(File dexFile) throws IOException {
|
||||
int dexVersion = new DexFileReader(dexFile).getDexVersion();
|
||||
Opcodes opcodes;
|
||||
if (dexVersion >= DexConstants.DEX_039) {
|
||||
opcodes = Opcodes.forApi(28);
|
||||
} else if (dexVersion >= DexConstants.DEX_037) {
|
||||
opcodes = Opcodes.forApi(26);
|
||||
} else {
|
||||
opcodes = Opcodes.forApi(0);
|
||||
}
|
||||
Opcodes opcodes = Opcodes.forApi(DexConstants.toMiniAndroidApiLevel(dexVersion));
|
||||
DexBackedDexFile dex;
|
||||
try {
|
||||
dex = DexFileFactory.loadDexFile(dexFile, opcodes);
|
||||
|
@ -0,0 +1,37 @@
|
||||
package com.googlecode.d2j;
|
||||
|
||||
public class CallSite {
|
||||
private String name;
|
||||
private MethodHandle bootstrapMethodHandler;
|
||||
private String methodName;
|
||||
private Proto methodProto;
|
||||
private Object[] extraArguments;
|
||||
|
||||
public CallSite(String name, MethodHandle bootstrapMethodHandler, String methodName, Proto methodProto, Object... extraArguments) {
|
||||
this.name = name;
|
||||
this.bootstrapMethodHandler = bootstrapMethodHandler;
|
||||
this.methodName = methodName;
|
||||
this.methodProto = methodProto;
|
||||
this.extraArguments = extraArguments;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public MethodHandle getBootstrapMethodHandler() {
|
||||
return bootstrapMethodHandler;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
public Proto getMethodProto() {
|
||||
return methodProto;
|
||||
}
|
||||
|
||||
public Object[] getExtraArguments() {
|
||||
return extraArguments;
|
||||
}
|
||||
}
|
@ -52,10 +52,25 @@ public abstract interface DexConstants {
|
||||
String ANNOTATION_INNER_CLASS_TYPE = "Ldalvik/annotation/InnerClass;";
|
||||
String ANNOTATION_MEMBER_CLASSES_TYPE = "Ldalvik/annotation/MemberClasses;";
|
||||
|
||||
static int toMiniAndroidApiLevel(int dexVersion) {
|
||||
if (dexVersion <= DEX_035 || dexVersion <= DEX_036) {
|
||||
return 0;
|
||||
} else if (dexVersion == DEX_037) {
|
||||
return 24;
|
||||
} else if (dexVersion == DEX_038) {
|
||||
return 26;
|
||||
} else {
|
||||
return 28;
|
||||
}
|
||||
}
|
||||
int DEX_035 = 0x00303335;
|
||||
@Deprecated
|
||||
int DEX_036 = 0x00303336;
|
||||
// android 7.0, api 24
|
||||
int DEX_037 = 0x00303337;
|
||||
// android 8.0, api 26
|
||||
int DEX_038 = 0x00303338;
|
||||
// android 9.0, api 28
|
||||
int DEX_039 = 0x00303339;
|
||||
int DEX_040 = 0x00303340;
|
||||
}
|
||||
|
@ -110,8 +110,8 @@ public class DexCodeNode extends DexCodeVisitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodStmt(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object... bsmArgs) {
|
||||
add(new MethodCustomStmtNode(op, args, name, proto, bsm, bsmArgs));
|
||||
public void visitMethodStmt(Op op, int[] args, CallSite callSite) {
|
||||
add(new MethodCustomStmtNode(op, args, callSite));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -15,32 +15,26 @@
|
||||
*/
|
||||
package com.googlecode.d2j.node.insn;
|
||||
|
||||
import com.googlecode.d2j.MethodHandle;
|
||||
import com.googlecode.d2j.CallSite;
|
||||
import com.googlecode.d2j.Proto;
|
||||
import com.googlecode.d2j.reader.Op;
|
||||
import com.googlecode.d2j.visitors.DexCodeVisitor;
|
||||
|
||||
public class MethodCustomStmtNode extends AbstractMethodStmtNode {
|
||||
public final String name;
|
||||
public final Proto proto;
|
||||
public final MethodHandle bsm;
|
||||
public final Object[] bsmArgs;
|
||||
public final CallSite callSite;
|
||||
|
||||
public MethodCustomStmtNode(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object[] bsmArgs) {
|
||||
public MethodCustomStmtNode(Op op, int[] args, CallSite callSite) {
|
||||
super(op, args);
|
||||
this.proto = proto;
|
||||
this.name = name;
|
||||
this.bsm = bsm;
|
||||
this.bsmArgs = bsmArgs;
|
||||
this.callSite = callSite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DexCodeVisitor cv) {
|
||||
cv.visitMethodStmt(op, args, name, proto, bsm, bsmArgs);
|
||||
cv.visitMethodStmt(op, args, callSite);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Proto getProto() {
|
||||
return proto;
|
||||
return callSite.getMethodProto();
|
||||
}
|
||||
}
|
||||
|
@ -238,9 +238,9 @@ public class DexCodeVisitor {
|
||||
* OP_INVOKE_CUSTOM
|
||||
* </pre>
|
||||
*/
|
||||
public void visitMethodStmt(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object... bsmArgs) {
|
||||
public void visitMethodStmt(Op op, int[] args, CallSite callSite) {
|
||||
if (visitor != null) {
|
||||
visitor.visitMethodStmt(op, args, name, proto, bsm, bsmArgs);
|
||||
visitor.visitMethodStmt(op, args, callSite);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,7 +205,7 @@ public class DexFileReader implements BaseDexFileReader {
|
||||
int call_site_ids_size = 0;
|
||||
int method_handle_ids_off = 0;
|
||||
int method_handle_ids_size = 0;
|
||||
if (dex_version > DEX_037) {
|
||||
if (dex_version >= DEX_038) {
|
||||
in.position(map_off);
|
||||
int size = in.getInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
@ -1642,9 +1642,7 @@ public class DexFileReader implements BaseDexFileReader {
|
||||
if (op.indexType == InstructionIndexType.kIndexTypeRef) {
|
||||
dcv.visitFilledNewArrayStmt(op, regs, getType(b));
|
||||
} else if (op.indexType == InstructionIndexType.kIndexCallSiteRef) {
|
||||
Object[] callsite = getCallSite(b);
|
||||
Object[] constArgs = Arrays.copyOfRange(callsite, 3, callsite.length);
|
||||
dcv.visitMethodStmt(op, regs, (String) callsite[1], (Proto) callsite[2], (MethodHandle) callsite[0], constArgs);
|
||||
dcv.visitMethodStmt(op, regs, getCallSite(b));
|
||||
} else {
|
||||
dcv.visitMethodStmt(op, regs, getMethod(b));
|
||||
}
|
||||
@ -1661,9 +1659,7 @@ public class DexFileReader implements BaseDexFileReader {
|
||||
if (op.indexType == InstructionIndexType.kIndexTypeRef) {
|
||||
dcv.visitFilledNewArrayStmt(op, regs, getType(b));
|
||||
} else if (op.indexType == InstructionIndexType.kIndexCallSiteRef) {
|
||||
Object[] callsite = getCallSite(b);
|
||||
Object[] constArgs = Arrays.copyOfRange(callsite, 3, callsite.length - 3);
|
||||
dcv.visitMethodStmt(op, regs, (String) callsite[1], (Proto) callsite[2], (MethodHandle) callsite[0], constArgs);
|
||||
dcv.visitMethodStmt(op, regs, getCallSite(b));
|
||||
} else {
|
||||
dcv.visitMethodStmt(op, regs, getMethod(b));
|
||||
}
|
||||
@ -1785,11 +1781,24 @@ public class DexFileReader implements BaseDexFileReader {
|
||||
}
|
||||
}
|
||||
|
||||
private Object[] getCallSite(int b) {
|
||||
private CallSite getCallSite(int b) {
|
||||
callSiteIdIn.position(b * 4);
|
||||
int call_site_off = callSiteIdIn.getInt();
|
||||
|
||||
return read_encoded_array_item(call_site_off);
|
||||
Object[] call_site_items = read_encoded_array_item(call_site_off);
|
||||
Object[] constArgs;
|
||||
if (call_site_items.length > 3) {
|
||||
constArgs = Arrays.copyOfRange(call_site_items, 3, call_site_items.length);
|
||||
} else {
|
||||
constArgs = new Object[0];
|
||||
}
|
||||
|
||||
return new CallSite(
|
||||
String.format("call_site_%d", b),
|
||||
(MethodHandle) call_site_items[0],
|
||||
(String) call_site_items[1],
|
||||
(Proto) call_site_items[2],
|
||||
constArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,8 +135,8 @@ public class ASMifierCodeV extends DexCodeVisitor implements DexConstants {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodStmt(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object... bsmArgs) {
|
||||
m.s("code.visitMethodStmt(%s,%s,%s,%s,%s,%s);", op(op), Escape.v(args), Escape.v(name), Escape.v(proto), Escape.v(bsm), Escape.v(bsmArgs));
|
||||
public void visitMethodStmt(Op op, int[] args, CallSite callSite) {
|
||||
m.s("code.visitMethodStmt(%s,%s,%s);", op(op), Escape.v(args), Escape.v(callSite));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -263,6 +263,26 @@ public class Escape implements DexConstants {
|
||||
return sb.append("}").toString();
|
||||
}
|
||||
|
||||
public static String v(CallSite callSite) {
|
||||
StringBuilder sb = new StringBuilder()
|
||||
.append("new CallSite(")
|
||||
.append(v(callSite.getName()))
|
||||
.append(", ")
|
||||
.append(v(callSite.getBootstrapMethodHandler()))
|
||||
.append(", ")
|
||||
.append(v(callSite.getMethodName()))
|
||||
.append(", ")
|
||||
.append(v(callSite.getMethodProto()));
|
||||
Object[] extraArguments = callSite.getExtraArguments();
|
||||
if (extraArguments != null && extraArguments.length > 0) {
|
||||
for (Object arg : extraArguments) {
|
||||
sb.append(", ").append(v(arg));
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String v(Object obj) {
|
||||
if (obj == null) {
|
||||
return "null";
|
||||
@ -287,6 +307,9 @@ public class Escape implements DexConstants {
|
||||
if (obj instanceof MethodHandle) {
|
||||
return v((MethodHandle) obj);
|
||||
}
|
||||
if (obj instanceof CallSite) {
|
||||
return v((CallSite) obj);
|
||||
}
|
||||
|
||||
if (obj instanceof Integer) {
|
||||
return " Integer.valueOf(" + obj + ")";
|
||||
|
@ -1135,7 +1135,11 @@ public class Dex2IRConverter {
|
||||
vs[i] = getLocal(values.get(i));
|
||||
}
|
||||
MethodCustomStmtNode n = (MethodCustomStmtNode) insn;
|
||||
Value invoke = nInvokeCustom(vs, n.name, n.proto, n.bsm, n.bsmArgs);
|
||||
Value invoke = nInvokeCustom(vs,
|
||||
n.callSite.getMethodName(),
|
||||
n.callSite.getMethodProto(),
|
||||
n.callSite.getBootstrapMethodHandler(),
|
||||
n.callSite.getExtraArguments());
|
||||
if ("V".equals(n.getProto().getReturnType())) {
|
||||
emit(nVoidInvoke(invoke));
|
||||
return null;
|
||||
|
@ -47,12 +47,10 @@ import org.objectweb.asm.tree.analysis.AnalyzerException;
|
||||
import org.objectweb.asm.tree.analysis.BasicVerifier;
|
||||
import org.objectweb.asm.tree.analysis.Frame;
|
||||
import org.objectweb.asm.util.CheckClassAdapter;
|
||||
import org.objectweb.asm.util.Printer;
|
||||
import org.objectweb.asm.util.Textifier;
|
||||
import org.objectweb.asm.util.TraceMethodVisitor;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
@ -329,11 +327,7 @@ public abstract class TestUtils {
|
||||
cfOptions.strictNameCheck = false;
|
||||
DexOptions dexOptions = new DexOptions();
|
||||
if (fileNode != null) {
|
||||
if (fileNode.dexVersion >= DexConstants.DEX_039) {
|
||||
dexOptions.minSdkVersion = 28;
|
||||
} else if (fileNode.dexVersion >= DexConstants.DEX_037) {
|
||||
dexOptions.minSdkVersion = 26;
|
||||
}
|
||||
dexOptions.minSdkVersion = DexConstants.toMiniAndroidApiLevel(fileNode.dexVersion);
|
||||
}
|
||||
|
||||
DirectClassFile dcf = new DirectClassFile(data, rca.getClassName() + ".class", true);
|
||||
|
BIN
dex-translator/src/test/resources/dexes/dex038.dex
Normal file
BIN
dex-translator/src/test/resources/dexes/dex038.dex
Normal file
Binary file not shown.
@ -16,9 +16,11 @@
|
||||
*/
|
||||
package com.googlecode.d2j.dex.writer;
|
||||
|
||||
import com.googlecode.d2j.CallSite;
|
||||
import com.googlecode.d2j.DexLabel;
|
||||
import com.googlecode.d2j.Field;
|
||||
import com.googlecode.d2j.Method;
|
||||
import com.googlecode.d2j.Proto;
|
||||
import com.googlecode.d2j.dex.writer.insn.*;
|
||||
import com.googlecode.d2j.dex.writer.item.*;
|
||||
import com.googlecode.d2j.reader.Op;
|
||||
@ -390,6 +392,9 @@ public class CodeWriter extends DexCodeVisitor {
|
||||
*/
|
||||
@Override
|
||||
public void visitConstStmt(Op op, int ra, Object value) {
|
||||
if (op == CONST_METHOD_HANDLE || op == CONST_METHOD_TYPE) {
|
||||
cp.dex039();
|
||||
}
|
||||
switch (op.format) {
|
||||
case kFmt21c:// value is field,type,string,method_handle,proto
|
||||
case kFmt31c:// value is string,
|
||||
@ -494,6 +499,33 @@ public class CodeWriter extends DexCodeVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodStmt(Op op, int[] args, CallSite callSite) {
|
||||
cp.dex038();
|
||||
if (op.format == kFmt3rc) {
|
||||
ops.add(new CodeWriter.OP3rc(op, args, cp.uniqCallSite(callSite)));
|
||||
} else if (op.format == kFmt35c) {
|
||||
ops.add(new CodeWriter.OP35c(op, args, cp.uniqCallSite(callSite)));
|
||||
}
|
||||
if (args.length > max_out_reg_size) {
|
||||
max_out_reg_size = args.length;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodStmt(Op op, int[] args, Method bsm, Proto proto) {
|
||||
cp.dex038();
|
||||
if (op.format == kFmt4rcc) {
|
||||
ops.add(new CodeWriter.OP4rcc(op, args, cp.uniqMethod(bsm), cp.uniqProto(proto)));
|
||||
} else if (op.format == kFmt45cc) {
|
||||
ops.add(new CodeWriter.OP45cc(op, args, cp.uniqMethod(bsm), cp.uniqProto(proto)));
|
||||
}
|
||||
|
||||
if (args.length > max_out_reg_size) {
|
||||
max_out_reg_size = args.length;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPackedSwitchStmt(Op op, int aA, final int first_case, final DexLabel[] labels) {
|
||||
Label switch_data_location = new Label();
|
||||
@ -750,6 +782,95 @@ public class CodeWriter extends DexCodeVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
//A|G|op BBBB F|E|D|C HHHH
|
||||
public static class OP45cc extends OpInsn {
|
||||
final BaseItem mtd;
|
||||
final BaseItem proto;
|
||||
int A, C, D, E, F, G;
|
||||
|
||||
public OP45cc(Op op, int[] args, BaseItem mtd, BaseItem proto) {
|
||||
super(op);
|
||||
int A = args.length;
|
||||
if (A > 5) {
|
||||
throw new CantNotFixContentException(op, "A", A);
|
||||
}
|
||||
this.A = A;
|
||||
switch (A) { // [A=5] op {vC, vD, vE, vF, vG},
|
||||
case 5:
|
||||
G = args[4];
|
||||
checkContentU4bit(op, "vG", G);
|
||||
case 4:
|
||||
F = args[3];
|
||||
checkContentU4bit(op, "vF", F);
|
||||
case 3:
|
||||
E = args[2];
|
||||
checkContentU4bit(op, "vE", E);
|
||||
case 2:
|
||||
D = args[1];
|
||||
checkContentU4bit(op, "vD", D);
|
||||
case 1:
|
||||
C = args[0];
|
||||
checkContentU4bit(op, "vC", C);
|
||||
break;
|
||||
}
|
||||
this.mtd = mtd;
|
||||
this.proto = proto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer out) { // A|G|op BBBB F|E|D|C HHHH
|
||||
checkContentUShort(op, "@BBBB", mtd.index);
|
||||
checkContentUShort(op, "@HHHH", proto.index);
|
||||
out
|
||||
.put((byte) op.opcode).put((byte) ((A << 4) | (G & 0xF))) //
|
||||
.putShort((short) mtd.index) //
|
||||
.put((byte) ((D << 4) | (C & 0xF))).put((byte) ((F << 4) | (E & 0xF))) //
|
||||
.putShort((short) proto.index) //
|
||||
|
||||
;
|
||||
}
|
||||
}
|
||||
// AA|op BBBB CCCC HHHH
|
||||
public static class OP4rcc extends OpInsn {
|
||||
final BaseItem mtd;
|
||||
final BaseItem proto;
|
||||
final int length;
|
||||
final int start;
|
||||
|
||||
public OP4rcc(Op op, int[] args, BaseItem mtd, BaseItem proto) {
|
||||
super(op);
|
||||
this.mtd = mtd;
|
||||
this.proto = proto;
|
||||
length = args.length;
|
||||
checkContentUByte(op, "AA", length);
|
||||
if (length > 0) {
|
||||
start = args[0];
|
||||
checkContentUShort(op, "CCCC", start);
|
||||
for (int i = 1; i < args.length; i++) {
|
||||
if (start + i != args[i]) {
|
||||
throw new CantNotFixContentException(op, "a", args[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer out) {
|
||||
checkContentUShort(op, "@BBBB", mtd.index);
|
||||
checkContentUShort(op, "@HHHH", proto.index);
|
||||
out
|
||||
.put((byte) op.opcode).put((byte) length) //
|
||||
.putShort((short) mtd.index) //
|
||||
.putShort((short) start) //
|
||||
.putShort((short) proto.index) //
|
||||
;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// AA|op BBBB CCCC
|
||||
public static class OP3rc extends OpInsn {
|
||||
final BaseItem item;
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.googlecode.d2j.dex.writer;
|
||||
|
||||
import com.googlecode.d2j.dex.writer.ev.EncodedArray;
|
||||
import com.googlecode.d2j.dex.writer.io.ByteBufferOut;
|
||||
import com.googlecode.d2j.dex.writer.io.DataOut;
|
||||
import com.googlecode.d2j.dex.writer.item.*;
|
||||
@ -124,6 +125,7 @@ public class DexFileWriter extends DexFileVisitor {
|
||||
|
||||
mapItem = new MapListItem();
|
||||
headItem = new HeadItem();
|
||||
headItem.version = cp.dexVersion;
|
||||
SectionItem<HeadItem> headSection = new SectionItem<>(SectionType.TYPE_HEADER_ITEM);
|
||||
headSection.items.add(headItem);
|
||||
SectionItem<MapListItem> mapSection = new SectionItem<MapListItem>(SectionType.TYPE_MAP_LIST);
|
||||
@ -160,8 +162,10 @@ public class DexFileWriter extends DexFileVisitor {
|
||||
SectionType.TYPE_DEBUG_INFO_ITEM, cp.debugInfoItems);
|
||||
SectionItem<AnnotationItem> annotationItemSection = new SectionItem<>(
|
||||
SectionType.TYPE_ANNOTATION_ITEM, cp.annotationItems.values());
|
||||
SectionItem<EncodedArrayItem> encodedArrayItemSection = new SectionItem<>(
|
||||
SectionType.TYPE_ENCODED_ARRAY_ITEM, cp.encodedArrayItems);
|
||||
SectionItem<EncodedArray> encodedArrayItemSection = new SectionItem<>(
|
||||
SectionType.TYPE_ENCODED_ARRAY_ITEM, cp.encodedArrayItems.values());
|
||||
SectionItem<CallSiteIdItem> callSiteIdItemSectionItem = new SectionItem<>(
|
||||
SectionType.TYPE_CALL_SITE_ID_ITEM, cp.callSiteIdItems.values());
|
||||
SectionItem<AnnotationsDirectoryItem> annotationsDirectoryItemSection = new SectionItem<>(
|
||||
SectionType.TYPE_ANNOTATIONS_DIRECTORY_ITEM,
|
||||
cp.annotationsDirectoryItems);
|
||||
@ -202,8 +206,13 @@ public class DexFileWriter extends DexFileVisitor {
|
||||
items.add(protoIdSection);
|
||||
items.add(fieldIdSection);
|
||||
items.add(methodIdSection);
|
||||
items.add(methodHandlerSection);
|
||||
items.add(classDefSection);
|
||||
if (callSiteIdItemSectionItem.items.size() > 0) {
|
||||
items.add(callSiteIdItemSectionItem);
|
||||
}
|
||||
if (methodHandlerSection.items.size() > 0) {
|
||||
items.add(methodHandlerSection);
|
||||
}
|
||||
|
||||
items.addAll(dataSectionItems);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import com.googlecode.d2j.dex.writer.item.TypeIdItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class EncodedAnnotation {
|
||||
public class EncodedAnnotation implements Comparable<EncodedAnnotation> {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@ -46,7 +46,33 @@ public class EncodedAnnotation {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class AnnotationElement {
|
||||
@Override
|
||||
public int compareTo(EncodedAnnotation o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int x = type.compareTo(o.type);
|
||||
if (x != 0) {
|
||||
return x;
|
||||
}
|
||||
x = Integer.compare(elements.size(), o.elements.size());
|
||||
if (x != 0) {
|
||||
return x;
|
||||
}
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
AnnotationElement a = elements.get(i);
|
||||
AnnotationElement b = o.elements.get(i);
|
||||
|
||||
x = a.compareTo(b);
|
||||
if (x != 0) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static class AnnotationElement implements Comparable<AnnotationElement> {
|
||||
public StringIdItem name;
|
||||
public EncodedValue value;
|
||||
|
||||
@ -69,6 +95,18 @@ public class EncodedAnnotation {
|
||||
result = 31 * result + value.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(AnnotationElement o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
int x = name.compareTo(o.name);
|
||||
if (x != 0) {
|
||||
return x;
|
||||
}
|
||||
return value.compareTo(o.value);
|
||||
}
|
||||
}
|
||||
|
||||
@Idx
|
||||
|
@ -20,9 +20,10 @@ import com.googlecode.d2j.dex.writer.io.DataOut;
|
||||
import com.googlecode.d2j.dex.writer.item.BaseItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class EncodedArray {
|
||||
public class EncodedArray extends BaseItem implements Comparable<EncodedArray> {
|
||||
|
||||
public List<EncodedValue> values = new ArrayList<>(5);
|
||||
|
||||
@ -57,4 +58,24 @@ public class EncodedArray {
|
||||
ev.write(out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(EncodedArray o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
int x = Integer.compare(values.size(), o.values.size());
|
||||
if (x != 0) {
|
||||
return x;
|
||||
}
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
EncodedValue a = values.get(i);
|
||||
EncodedValue b = o.values.get(i);
|
||||
x = a.compareTo(b);
|
||||
if (x != 0) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,15 @@
|
||||
package com.googlecode.d2j.dex.writer.ev;
|
||||
|
||||
import com.googlecode.d2j.dex.writer.io.DataOut;
|
||||
import com.googlecode.d2j.dex.writer.item.*;
|
||||
import com.googlecode.d2j.dex.writer.item.BaseItem;
|
||||
import com.googlecode.d2j.dex.writer.item.FieldIdItem;
|
||||
import com.googlecode.d2j.dex.writer.item.MethodHandleItem;
|
||||
import com.googlecode.d2j.dex.writer.item.MethodIdItem;
|
||||
import com.googlecode.d2j.dex.writer.item.ProtoIdItem;
|
||||
import com.googlecode.d2j.dex.writer.item.StringIdItem;
|
||||
import com.googlecode.d2j.dex.writer.item.TypeIdItem;
|
||||
|
||||
public class EncodedValue {
|
||||
public class EncodedValue implements Comparable<EncodedValue> {
|
||||
|
||||
public final static int VALUE_ANNOTATION = 0x1d;
|
||||
public final static int VALUE_ARRAY = 0x1c;
|
||||
@ -32,6 +38,8 @@ public class EncodedValue {
|
||||
public final static int VALUE_FLOAT = 0x10;
|
||||
public final static int VALUE_INT = 0x04;
|
||||
public final static int VALUE_LONG = 0x06;
|
||||
public final static int VALUE_METHOD_TYPE = 0x15;
|
||||
public final static int VALUE_METHOD_HANDLE = 0x16;
|
||||
public final static int VALUE_METHOD = 0x1a;
|
||||
public final static int VALUE_NULL = 0x1e;
|
||||
public final static int VALUE_SHORT = 0x02;
|
||||
@ -118,6 +126,10 @@ public class EncodedValue {
|
||||
return new EncodedValue(VALUE_FIELD, v);
|
||||
} else if (v instanceof MethodIdItem) {
|
||||
return new EncodedValue(VALUE_METHOD, v);
|
||||
} else if (v instanceof MethodHandleItem) {
|
||||
return new EncodedValue(VALUE_METHOD_HANDLE, v);
|
||||
} else if (v instanceof ProtoIdItem) {
|
||||
return new EncodedValue(VALUE_METHOD_TYPE, v);
|
||||
}
|
||||
|
||||
|
||||
@ -258,6 +270,8 @@ public class EncodedValue {
|
||||
case VALUE_FIELD:
|
||||
case VALUE_METHOD:
|
||||
case VALUE_ENUM:
|
||||
case VALUE_METHOD_HANDLE:
|
||||
case VALUE_METHOD_TYPE:
|
||||
default:
|
||||
return offset + getValueArg() + 1;
|
||||
}
|
||||
@ -289,6 +303,8 @@ public class EncodedValue {
|
||||
case VALUE_FIELD:
|
||||
case VALUE_METHOD:
|
||||
case VALUE_ENUM:
|
||||
case VALUE_METHOD_HANDLE:
|
||||
case VALUE_METHOD_TYPE:
|
||||
BaseItem bi = (BaseItem) value;
|
||||
return lengthOfUint(bi.index) - 1;
|
||||
}
|
||||
@ -331,6 +347,8 @@ public class EncodedValue {
|
||||
case VALUE_FIELD:
|
||||
case VALUE_METHOD:
|
||||
case VALUE_ENUM:
|
||||
case VALUE_METHOD_HANDLE:
|
||||
case VALUE_METHOD_TYPE:
|
||||
out.bytes("value_xidx", encodeLong(valueArg + 1, ((BaseItem) value).index));
|
||||
break;
|
||||
case VALUE_ARRAY: {
|
||||
@ -363,4 +381,55 @@ public class EncodedValue {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(EncodedValue o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
int x = Integer.compare(valueType, o.valueType);
|
||||
if (x != 0) {
|
||||
return x;
|
||||
}
|
||||
switch (valueType) {
|
||||
case VALUE_NULL:
|
||||
return 0;
|
||||
case VALUE_BOOLEAN:
|
||||
return Boolean.compare((Boolean) value, (Boolean) o.value);
|
||||
case VALUE_SHORT:
|
||||
return ((Short) value).compareTo((Short) o.value);
|
||||
case VALUE_CHAR:
|
||||
return ((Character) value).compareTo((Character) o.value);
|
||||
case VALUE_INT:
|
||||
return ((Integer) value).compareTo((Integer) o.value);
|
||||
case VALUE_LONG:
|
||||
return ((Long) value).compareTo((Long) o.value);
|
||||
case VALUE_DOUBLE:
|
||||
return Long.compare(Double.doubleToLongBits((Double) value), Double.doubleToLongBits((Double) o.value));
|
||||
case VALUE_FLOAT:
|
||||
return Integer.compare(Float.floatToIntBits((Float) value), Float.floatToIntBits((Float) o.value));
|
||||
case VALUE_STRING:
|
||||
case VALUE_TYPE:
|
||||
case VALUE_FIELD:
|
||||
case VALUE_METHOD:
|
||||
case VALUE_ENUM:
|
||||
case VALUE_METHOD_HANDLE:
|
||||
case VALUE_METHOD_TYPE:
|
||||
if (value instanceof Comparable) {
|
||||
return ((Comparable) value).compareTo(value);
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
case VALUE_ARRAY: {
|
||||
return ((EncodedArray) value).compareTo((EncodedArray) o.value);
|
||||
}
|
||||
case VALUE_ANNOTATION: {
|
||||
return ((EncodedAnnotation) value).compareTo((EncodedAnnotation) o.value);
|
||||
}
|
||||
case VALUE_BYTE: {
|
||||
return Byte.compare((Byte) value, (Byte) o.value);
|
||||
}
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
package com.googlecode.d2j.dex.writer.item;
|
||||
|
||||
import com.googlecode.d2j.dex.writer.ev.EncodedArray;
|
||||
import com.googlecode.d2j.dex.writer.io.DataOut;
|
||||
|
||||
public class CallSiteIdItem extends BaseItem implements Comparable<CallSiteIdItem> {
|
||||
String name;
|
||||
EncodedArray encodedArrayItem;
|
||||
|
||||
public CallSiteIdItem(String name, EncodedArray encodedArrayItem) {
|
||||
this.name = name;
|
||||
this.encodedArrayItem = encodedArrayItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOut out) {
|
||||
out.uint("call_site_off", encodedArrayItem.offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int place(int offset) {
|
||||
return offset + 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(CallSiteIdItem o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
if (name != null) {
|
||||
if (o.name == null) {
|
||||
return 1;
|
||||
} else {
|
||||
int x = name.compareTo(o.name);
|
||||
if (x != 0) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (o.name != null) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return encodedArrayItem.compareTo(o.encodedArrayItem);
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ public class ClassDefItem extends BaseItem {
|
||||
@Off
|
||||
private AnnotationsDirectoryItem annotations;// Build later
|
||||
@Off
|
||||
private EncodedArrayItem staticValues; // Build later
|
||||
private EncodedArray staticValues; // Build later
|
||||
|
||||
@Override
|
||||
public int place(int offset) {
|
||||
@ -77,8 +77,7 @@ public class ClassDefItem extends BaseItem {
|
||||
}
|
||||
|
||||
if (count >= 0) {
|
||||
EncodedArrayItem encodedArrayItem = cp.putEnCodedArrayItem();
|
||||
EncodedArray array = encodedArrayItem.value;
|
||||
EncodedArray array = new EncodedArray();
|
||||
for (int i = 0; i <= count; i++) {
|
||||
EncodedField f = fs.get(i);
|
||||
EncodedValue ev = f.staticValue;
|
||||
@ -88,7 +87,7 @@ public class ClassDefItem extends BaseItem {
|
||||
array.values.add(ev);
|
||||
}
|
||||
}
|
||||
staticValues = encodedArrayItem;
|
||||
staticValues = cp.uniqEncodedArrayItem(array);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,17 +16,24 @@
|
||||
*/
|
||||
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.*;
|
||||
|
||||
public class ConstPool {
|
||||
public List<EncodedArrayItem> encodedArrayItems = new ArrayList<>();
|
||||
public int dexVersion = DexConstants.DEX_035;
|
||||
|
||||
public Map<CallSiteIdItem, CallSiteIdItem> callSiteIdItems = new TreeMap<>();
|
||||
public Map<EncodedArray, EncodedArray> encodedArrayItems = new TreeMap<>();
|
||||
public Map<AnnotationSetRefListItem, AnnotationSetRefListItem> annotationSetRefListItems = new HashMap<>();
|
||||
public List<CodeItem> codeItems = new ArrayList<>();
|
||||
public List<ClassDataItem> classDataItems = new ArrayList<>();
|
||||
@ -46,17 +53,17 @@ public class ConstPool {
|
||||
|
||||
public Object wrapEncodedItem(Object value) {
|
||||
if (value instanceof DexType) {
|
||||
value = uniqType(((DexType) value).desc);
|
||||
return uniqType(((DexType) value).desc);
|
||||
} else if (value instanceof Field) {
|
||||
value = uniqField((Field) value);
|
||||
return uniqField((Field) value);
|
||||
} else if (value instanceof String) {
|
||||
value = uniqString((String) value);
|
||||
return uniqString((String) value);
|
||||
} else if (value instanceof Method) {
|
||||
value = uniqMethod((Method) value);
|
||||
return uniqMethod((Method) value);
|
||||
} else if (value instanceof MethodHandle) {
|
||||
value = uniqMethodHandle((MethodHandle) value);
|
||||
return uniqMethodHandle((MethodHandle) value);
|
||||
} else if (value instanceof Proto) {
|
||||
value = uniqProto((Proto) value);
|
||||
return uniqProto((Proto) value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -129,6 +136,18 @@ public class ConstPool {
|
||||
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<TypeIdItem> it;
|
||||
@ -249,7 +268,7 @@ public class ConstPool {
|
||||
return key;
|
||||
}
|
||||
|
||||
private ProtoIdItem uniqProto(Proto method) {
|
||||
public ProtoIdItem uniqProto(Proto method) {
|
||||
return uniqProto(method.getParameterTypes(), method.getReturnType());
|
||||
}
|
||||
private ProtoIdItem uniqProto(Method method) {
|
||||
@ -337,11 +356,31 @@ public class ConstPool {
|
||||
return dataItem;
|
||||
}
|
||||
|
||||
// TODO change EncodedArrayItem to uniq
|
||||
public EncodedArrayItem putEnCodedArrayItem() {
|
||||
EncodedArrayItem arrayItem = new EncodedArrayItem();
|
||||
encodedArrayItems.add(arrayItem);
|
||||
return arrayItem;
|
||||
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) {
|
||||
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* dex2jar - Tools to work with android .dex and java .class files
|
||||
* Copyright (c) 2009-2013 Panxiaobo
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.googlecode.d2j.dex.writer.item;
|
||||
|
||||
import com.googlecode.d2j.dex.writer.ev.EncodedArray;
|
||||
import com.googlecode.d2j.dex.writer.io.DataOut;
|
||||
|
||||
public class EncodedArrayItem extends BaseItem {
|
||||
public EncodedArray value = new EncodedArray();
|
||||
|
||||
@Override
|
||||
public int place(int offset) {
|
||||
return value.place(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOut out) {
|
||||
value.write(out);
|
||||
}
|
||||
}
|
@ -16,13 +16,14 @@
|
||||
*/
|
||||
package com.googlecode.d2j.dex.writer.item;
|
||||
|
||||
import com.googlecode.d2j.DexConstants;
|
||||
import com.googlecode.d2j.dex.writer.io.DataOut;
|
||||
|
||||
public class HeadItem extends BaseItem {
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public static final int V035 = 0x00353330;
|
||||
public static final int V036 = 0x00363330;
|
||||
public int version = V035;
|
||||
public class HeadItem extends BaseItem {
|
||||
public int version = DexConstants.DEX_035;
|
||||
public SectionItem<MapListItem> mapSection;
|
||||
public SectionItem<StringIdItem> stringIdSection;
|
||||
public SectionItem<TypeIdItem> typeIdSection;
|
||||
@ -34,7 +35,9 @@ public class HeadItem extends BaseItem {
|
||||
|
||||
public void write(DataOut out) {
|
||||
out.uint("magic", 0x0A786564);
|
||||
out.uint("version", version);
|
||||
|
||||
// version in DexConstants is big endian
|
||||
out.bytes("version", writeBigEndian(version << 8));
|
||||
out.skip4("checksum");
|
||||
out.skip("signature", 20);
|
||||
out.uint("file_size", fileSize);
|
||||
@ -64,6 +67,11 @@ public class HeadItem extends BaseItem {
|
||||
|
||||
}
|
||||
|
||||
private static byte[] writeBigEndian(int value) {
|
||||
return ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN)
|
||||
.putInt(value).array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int place(int offset) {
|
||||
return offset + 0x70;
|
||||
|
@ -28,7 +28,6 @@ import java.util.List;
|
||||
public class SectionItem<T extends BaseItem> extends BaseItem {
|
||||
final public SectionType sectionType;
|
||||
public final List<T> items = new ArrayList<>();
|
||||
int size = 0;
|
||||
|
||||
public SectionItem(SectionType typeCode) {
|
||||
super();
|
||||
@ -52,10 +51,6 @@ public class SectionItem<T extends BaseItem> extends BaseItem {
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public int place(int offset) {
|
||||
final int startOffset = offset;
|
||||
int index = 0;
|
||||
@ -66,7 +61,6 @@ public class SectionItem<T extends BaseItem> extends BaseItem {
|
||||
index++;
|
||||
offset = t.place(offset);
|
||||
}
|
||||
size = offset - startOffset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user