com.googlecode.d2j.dex.DexFix Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle Show documentation
Show all versions of gradle Show documentation
fakeradnroid gradle builder
/*
* 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;
import java.util.HashMap;
import java.util.Map;
import com.googlecode.d2j.DexConstants;
import com.googlecode.d2j.Field;
import com.googlecode.d2j.node.DexClassNode;
import com.googlecode.d2j.node.DexFieldNode;
import com.googlecode.d2j.node.DexFileNode;
import com.googlecode.d2j.node.DexMethodNode;
import com.googlecode.d2j.reader.Op;
import com.googlecode.d2j.visitors.DexCodeVisitor;
/**
* 1. Dex omit the value of static-final filed if it is the default value.
*
* 2. static-final field init by zero, but assigned in clinit
*
* this method is try to fix the problems.
*/
public class DexFix {
private static final int ACC_STATIC_FINAL = DexConstants.ACC_STATIC | DexConstants.ACC_FINAL;
public static void fixStaticFinalFieldValue(final DexFileNode dex) {
if (dex.clzs != null) {
for (DexClassNode classNode : dex.clzs) {
fixStaticFinalFieldValue(classNode);
}
}
}
/**
* init value to default if the field is static and final, and the field is not init in clinit method
*
* erase the default value if the field is init in clinit method
*
* @param classNode
*/
public static void fixStaticFinalFieldValue(final DexClassNode classNode) {
if (classNode.fields == null) {
return;
}
final Map fs = new HashMap<>();
final Map shouldNotBeAssigned = new HashMap<>();
for (DexFieldNode fn : classNode.fields) {
if ((fn.access & ACC_STATIC_FINAL) == ACC_STATIC_FINAL) {
if (fn.cst == null) {
char t = fn.field.getType().charAt(0);
if (t == 'L' || t == '[') {
// ignore Object
continue;
}
fs.put(fn.field.getName() + ":" + fn.field.getType(), fn);
} else if (isPrimitiveZero(fn.field.getType(), fn.cst)) {
shouldNotBeAssigned.put(fn.field.getName() + ":" + fn.field.getType(), fn);
}
}
}
if (fs.isEmpty() && shouldNotBeAssigned.isEmpty()) {
return;
}
DexMethodNode node = null;
if (classNode.methods != null) {
for (DexMethodNode mn : classNode.methods) {
if (mn.method.getName().equals("")) {
node = mn;
break;
}
}
}
if (node != null) {
if (node.codeNode != null) {
node.codeNode.accept(new DexCodeVisitor() {
@Override
public void visitFieldStmt(Op op, int a, int b, Field field) {
switch (op) {
case SPUT:
case SPUT_BOOLEAN:
case SPUT_BYTE:
case SPUT_CHAR:
case SPUT_OBJECT:
case SPUT_SHORT:
case SPUT_WIDE:
if (field.getOwner().equals(classNode.className)) {
String key = field.getName() + ":" + field.getType();
fs.remove(key);
DexFieldNode dn = shouldNotBeAssigned.get(key);
if (dn != null) {
//System.out.println(field.getName() + ":" + field.getType());
dn.cst = null;
}
}
break;
default:
// ignored
break;
}
}
});
} else {
// has init but no code
return;
}
}
for (DexFieldNode fn : fs.values()) {
fn.cst = getDefaultValueOfType(fn.field.getType().charAt(0));
}
}
private static Object getDefaultValueOfType(char t) {
switch (t) {
case 'B':
return Byte.valueOf((byte) 0);
case 'Z':
return Boolean.FALSE;
case 'S':
return Short.valueOf((short) 0);
case 'C':
return Character.valueOf((char) 0);
case 'I':
return 0;
case 'F':
return Float.valueOf((float) 0.0);
case 'J':
return Long.valueOf((long) 0);
case 'D':
return Double.valueOf(0.0);
case '[':
case 'L':
default:
return null;
// impossible
}
}
static boolean isPrimitiveZero(String desc, Object value) {
if (value != null && desc != null && desc.length() > 0) {
switch (desc.charAt(0)) {
// case 'V':// VOID_TYPE
case 'Z':// BOOLEAN_TYPE
return ((Boolean) value).booleanValue() == false;
case 'C':// CHAR_TYPE
return ((Character) value).charValue() == (char) 0;
case 'B':// BYTE_TYPE
return ((Byte) value).byteValue() == 0;
case 'S':// SHORT_TYPE
return ((Short) value).shortValue() == 0;
case 'I':// INT_TYPE
return ((Integer) value).intValue() == 0;
case 'F':// FLOAT_TYPE
return ((Float) value).floatValue() == 0f;
case 'J':// LONG_TYPE
return ((Long) value).longValue() == 0L;
case 'D':// DOUBLE_TYPE
return ((Double) value).doubleValue() == 0.0;
}
}
return false;
}
}