com.googlecode.d2j.dex.DexFix Maven / Gradle / Ivy
The newest version!
/*
* 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;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy