Apktool/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValueFactory.java

126 lines
5.1 KiB
Java
Raw Normal View History

2019-10-16 07:49:58 +02:00
/*
* Copyright (C) 2010 Ryszard Wiśniewski <brut.alll@gmail.com>
* Copyright (C) 2010 Connor Tumbleson <connor.tumbleson@gmail.com>
2012-09-20 03:27:35 +02:00
*
* 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
*
2021-08-24 15:31:41 +02:00
* https://www.apache.org/licenses/LICENSE-2.0
2012-09-20 03:27:35 +02:00
*
* 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 brut.androlib.res.data.value;
import android.util.TypedValue;
import brut.androlib.AndrolibException;
import brut.androlib.res.data.ResPackage;
import brut.androlib.res.data.ResTypeSpec;
2012-09-20 03:27:35 +02:00
import brut.util.Duo;
public class ResValueFactory {
2014-02-10 02:01:57 +01:00
private final ResPackage mPackage;
2012-09-20 03:27:35 +02:00
2015-12-14 14:10:14 +01:00
public ResValueFactory(ResPackage package_) {
this.mPackage = package_;
2014-02-10 02:01:57 +01:00
}
2012-09-20 03:27:35 +02:00
2015-12-14 14:10:14 +01:00
public ResScalarValue factory(int type, int value, String rawValue) throws AndrolibException {
2014-02-10 02:01:57 +01:00
switch (type) {
2015-03-12 23:43:17 +01:00
case TypedValue.TYPE_NULL:
if (value == TypedValue.DATA_NULL_UNDEFINED) { // Special case $empty as explicitly defined empty value
2015-12-14 14:00:12 +01:00
return new ResStringValue(null, value);
2016-06-10 14:21:50 +02:00
} else if (value == TypedValue.DATA_NULL_EMPTY) {
return new ResEmptyValue(value, rawValue, type);
}
2015-03-12 23:43:17 +01:00
return new ResReferenceValue(mPackage, 0, null);
2014-02-10 02:01:57 +01:00
case TypedValue.TYPE_REFERENCE:
Fix reference values not being resolved against frameworks This Apktool issue has existed for a long time and is especially prevalent with ROMs with multiple frameworks. The issue happens because Apktool treats reference values inside XMLs (like layouts) as raw text values, and doesn't resolve them during decompile time. This causes some values to be misformed, but more importantly, this causes values referencing to secondary frameworks to not be resolved with their source frameworks, which also means the framework ID won't be added to usesFramework.ids in apktool.yml, and that breaks recompiling. The interesting thing is that reference values are actually being resolved when they are located in value resources, like styles, thus presenting an inconsistent behavior. This simple mod eliminates the "rawValue" for reference values, and that forces the "value" (resource ID) to resolve against the respective frameworks, fixing misformed values in the process. BEFORE: I: Using Apktool 2.4.0-896569-SNAPSHOT on Notes.apk I: Loading resource table... I: Decoding Shared Library (miui), pkgId: 16 I: Decoding Shared Library (miui.system), pkgId: 18 I: Decoding AndroidManifest.xml with resources... I: Loading resource table from file: bin\framework\1.apk I: Regular manifest package... I: Decoding file-resources... I: Loading resource table from file: bin\framework\16.apk I: Decoding Shared Library (androidhwext), pkgId: 15 I: Decoding values */* XMLs... I: Baksmaling classes.dex... I: Copying assets and libs... I: Copying unknown files... I: Copying original files... Some comparisons before and after the fix: https://i.imgur.com/2gTllT0.png https://i.imgur.com/KzJUeQt.png AFTER: I: Using Apktool 2.4.0-896569-SNAPSHOT on Notes.apk I: Loading resource table... I: Decoding Shared Library (miui), pkgId: 16 I: Decoding Shared Library (miui.system), pkgId: 18 I: Decoding AndroidManifest.xml with resources... I: Loading resource table from file: bin\framework\1.apk I: Regular manifest package... I: Decoding file-resources... I: Loading resource table from file: bin\framework\16.apk I: Decoding Shared Library (androidhwext), pkgId: 15 I: Loading resource table from file: bin\framework\18.apk I: Decoding Shared Library (miui), pkgId: 16 I: Decoding Shared Library (android.miui), pkgId: 17 I: Decoding values */* XMLs... I: Baksmaling classes.dex... I: Copying assets and libs... I: Copying unknown files... I: Copying original files...
2019-02-15 13:55:56 +01:00
return newReference(value, null);
2014-02-10 02:01:57 +01:00
case TypedValue.TYPE_ATTRIBUTE:
case TypedValue.TYPE_DYNAMIC_ATTRIBUTE:
2014-02-10 02:01:57 +01:00
return newReference(value, rawValue, true);
case TypedValue.TYPE_STRING:
return new ResStringValue(rawValue, value);
2014-02-10 02:01:57 +01:00
case TypedValue.TYPE_FLOAT:
return new ResFloatValue(Float.intBitsToFloat(value), value, rawValue);
2014-02-10 02:01:57 +01:00
case TypedValue.TYPE_DIMENSION:
return new ResDimenValue(value, rawValue);
case TypedValue.TYPE_FRACTION:
return new ResFractionValue(value, rawValue);
case TypedValue.TYPE_INT_BOOLEAN:
return new ResBoolValue(value != 0, value, rawValue);
case TypedValue.TYPE_DYNAMIC_REFERENCE:
return newReference(value, rawValue);
2014-02-10 02:01:57 +01:00
}
2012-09-20 03:27:35 +02:00
2015-12-14 14:10:14 +01:00
if (type >= TypedValue.TYPE_FIRST_COLOR_INT && type <= TypedValue.TYPE_LAST_COLOR_INT) {
2014-02-10 02:01:57 +01:00
return new ResColorValue(value, rawValue);
}
2015-12-14 14:10:14 +01:00
if (type >= TypedValue.TYPE_FIRST_INT && type <= TypedValue.TYPE_LAST_INT) {
2014-02-10 02:01:57 +01:00
return new ResIntValue(value, rawValue, type);
}
2012-09-20 03:27:35 +02:00
2014-02-10 02:01:57 +01:00
throw new AndrolibException("Invalid value type: " + type);
}
2012-09-20 03:27:35 +02:00
public ResIntBasedValue factory(String value, int rawValue) {
if (value == null) {
return new ResFileValue("", rawValue);
}
if (value.startsWith("res/")) {
return new ResFileValue(value, rawValue);
2014-02-10 02:01:57 +01:00
}
if (value.startsWith("r/") || value.startsWith("R/")) { //AndroResGuard
return new ResFileValue(value, rawValue);
}
return new ResStringValue(value, rawValue);
2014-02-10 02:01:57 +01:00
}
2012-09-20 03:27:35 +02:00
public ResBagValue bagFactory(int parent, Duo<Integer, ResScalarValue>[] items, ResTypeSpec resTypeSpec) throws AndrolibException {
2014-02-10 02:01:57 +01:00
ResReferenceValue parentVal = newReference(parent, null);
2012-09-20 03:27:35 +02:00
2014-02-10 02:01:57 +01:00
if (items.length == 0) {
return new ResBagValue(parentVal);
}
int key = items[0].m1;
if (key == ResAttr.BAG_KEY_ATTR_TYPE) {
return ResAttr.factory(parentVal, items, this, mPackage);
}
String resTypeName = resTypeSpec.getName();
// Android O Preview added an unknown enum for c. This is hardcoded as 0 for now.
if (ResTypeSpec.RES_TYPE_NAME_ARRAY.equals(resTypeName)
|| key == ResArrayValue.BAG_KEY_ARRAY_START || key == 0) {
2014-02-10 02:01:57 +01:00
return new ResArrayValue(parentVal, items);
}
if (ResTypeSpec.RES_TYPE_NAME_PLURALS.equals(resTypeName) ||
(key >= ResPluralsValue.BAG_KEY_PLURALS_START && key <= ResPluralsValue.BAG_KEY_PLURALS_END)) {
2014-02-10 02:01:57 +01:00
return new ResPluralsValue(parentVal, items);
}
2019-07-03 01:23:33 +02:00
if (ResTypeSpec.RES_TYPE_NAME_ATTR.equals(resTypeName)) {
return new ResAttr(parentVal, 0, null, null, null);
}
if (resTypeName.startsWith(ResTypeSpec.RES_TYPE_NAME_STYLES)) {
return new ResStyleValue(parentVal, items, this);
}
2019-07-03 01:23:33 +02:00
throw new AndrolibException("unsupported res type name for bags. Found: " + resTypeName);
2014-02-10 02:01:57 +01:00
}
2012-09-20 03:27:35 +02:00
2014-02-10 02:01:57 +01:00
public ResReferenceValue newReference(int resID, String rawValue) {
return newReference(resID, rawValue, false);
}
2012-09-20 03:27:35 +02:00
2015-12-14 14:10:14 +01:00
public ResReferenceValue newReference(int resID, String rawValue, boolean theme) {
2014-02-10 02:01:57 +01:00
return new ResReferenceValue(mPackage, resID, rawValue, theme);
}
2016-06-10 14:21:50 +02:00
}