mirror of
https://github.com/revanced/Apktool.git
synced 2025-04-30 14:14:25 +02:00
Reworks Attr/Array Handler (#3326)
* test: add example pkcs key * fix: rework towards ResScalarValue instead of ResIntValue * fix: prefer res name instead of "guessing" based on ids
This commit is contained in:
parent
c07e4a92e6
commit
515af4faf8
@ -23,9 +23,11 @@ import java.util.*;
|
|||||||
public final class ResTypeSpec {
|
public final class ResTypeSpec {
|
||||||
|
|
||||||
public static final String RES_TYPE_NAME_ARRAY = "array";
|
public static final String RES_TYPE_NAME_ARRAY = "array";
|
||||||
public static final String RES_TYPE_NAME_PLURALS = "plurals";
|
|
||||||
public static final String RES_TYPE_NAME_STYLES = "style";
|
|
||||||
public static final String RES_TYPE_NAME_ATTR = "attr";
|
public static final String RES_TYPE_NAME_ATTR = "attr";
|
||||||
|
public static final String RES_TYPE_NAME_ATTR_PRIVATE = "^attr-private";
|
||||||
|
public static final String RES_TYPE_NAME_PLURALS = "plurals";
|
||||||
|
public static final String RES_TYPE_NAME_STRING = "string";
|
||||||
|
public static final String RES_TYPE_NAME_STYLES = "style";
|
||||||
|
|
||||||
private final String mName;
|
private final String mName;
|
||||||
private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<>();
|
private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<>();
|
||||||
@ -46,7 +48,7 @@ public final class ResTypeSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isString() {
|
public boolean isString() {
|
||||||
return mName.equalsIgnoreCase("string");
|
return mName.equalsIgnoreCase(RES_TYPE_NAME_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResResSpec getResSpec(String name) throws AndrolibException {
|
public ResResSpec getResSpec(String name) throws AndrolibException {
|
||||||
|
@ -91,6 +91,4 @@ public class ResArrayValue extends ResBagValue implements ResValuesXmlSerializab
|
|||||||
|
|
||||||
private final ResScalarValue[] mItems;
|
private final ResScalarValue[] mItems;
|
||||||
private final String[] AllowedArrayTypes = {"string", "integer"};
|
private final String[] AllowedArrayTypes = {"string", "integer"};
|
||||||
|
|
||||||
public static final int BAG_KEY_ARRAY_START = 0x02000000;
|
|
||||||
}
|
}
|
||||||
|
@ -64,38 +64,39 @@ public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
|
|||||||
public static ResAttr factory(ResReferenceValue parent,
|
public static ResAttr factory(ResReferenceValue parent,
|
||||||
Duo<Integer, ResScalarValue>[] items, ResValueFactory factory,
|
Duo<Integer, ResScalarValue>[] items, ResValueFactory factory,
|
||||||
ResPackage pkg) throws AndrolibException {
|
ResPackage pkg) throws AndrolibException {
|
||||||
|
|
||||||
int type = ((ResIntValue) items[0].m2).getValue();
|
|
||||||
int scalarType = type & 0xffff;
|
|
||||||
Integer min = null, max = null;
|
Integer min = null, max = null;
|
||||||
Boolean l10n = null;
|
Boolean l10n = null;
|
||||||
int i;
|
int i;
|
||||||
for (i = 1; i < items.length; i++) {
|
for (i = 1; i < items.length; i++) {
|
||||||
switch (items[i].m1) {
|
switch (items[i].m1) {
|
||||||
case BAG_KEY_ATTR_MIN:
|
case BAG_KEY_ATTR_MIN:
|
||||||
min = ((ResIntValue) items[i].m2).getValue();
|
min = (items[i].m2).getRawIntValue();
|
||||||
continue;
|
continue;
|
||||||
case BAG_KEY_ATTR_MAX:
|
case BAG_KEY_ATTR_MAX:
|
||||||
max = ((ResIntValue) items[i].m2).getValue();
|
max = (items[i].m2).getRawIntValue();
|
||||||
continue;
|
continue;
|
||||||
case BAG_KEY_ATTR_L10N:
|
case BAG_KEY_ATTR_L10N:
|
||||||
l10n = ((ResIntValue) items[i].m2).getValue() != 0;
|
l10n = (items[i].m2).getRawIntValue() != 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #2806 - Make sure we handle int-based values and not just ResIntValue
|
||||||
|
int rawValue = items[0].m2.getRawIntValue();
|
||||||
|
int scalarType = rawValue & 0xffff;
|
||||||
|
|
||||||
if (i == items.length) {
|
if (i == items.length) {
|
||||||
return new ResAttr(parent, scalarType, min, max, l10n);
|
return new ResAttr(parent, scalarType, min, max, l10n);
|
||||||
}
|
}
|
||||||
Duo<ResReferenceValue, ResIntValue>[] attrItems = new Duo[items.length - i];
|
Duo<ResReferenceValue, ResScalarValue>[] attrItems = new Duo[items.length - i];
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (; i < items.length; i++) {
|
for (; i < items.length; i++) {
|
||||||
int resId = items[i].m1;
|
int resId = items[i].m1;
|
||||||
pkg.addSynthesizedRes(resId);
|
pkg.addSynthesizedRes(resId);
|
||||||
attrItems[j++] = new Duo<>(factory.newReference(resId, null), (ResIntValue) items[i].m2);
|
attrItems[j++] = new Duo<>(factory.newReference(resId, null), items[i].m2);
|
||||||
}
|
}
|
||||||
switch (type & 0xff0000) {
|
switch (rawValue & 0xff0000) {
|
||||||
case TYPE_ENUM:
|
case TYPE_ENUM:
|
||||||
return new ResEnumAttr(parent, scalarType, min, max, l10n, attrItems);
|
return new ResEnumAttr(parent, scalarType, min, max, l10n, attrItems);
|
||||||
case TYPE_FLAGS:
|
case TYPE_FLAGS:
|
||||||
@ -145,7 +146,6 @@ public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
|
|||||||
private final Integer mMax;
|
private final Integer mMax;
|
||||||
private final Boolean mL10n;
|
private final Boolean mL10n;
|
||||||
|
|
||||||
public static final int BAG_KEY_ATTR_TYPE = 0x01000000;
|
|
||||||
private static final int BAG_KEY_ATTR_MIN = 0x01000001;
|
private static final int BAG_KEY_ATTR_MIN = 0x01000001;
|
||||||
private static final int BAG_KEY_ATTR_MAX = 0x01000002;
|
private static final int BAG_KEY_ATTR_MAX = 0x01000002;
|
||||||
private static final int BAG_KEY_ATTR_L10N = 0x01000003;
|
private static final int BAG_KEY_ATTR_L10N = 0x01000003;
|
||||||
|
@ -29,7 +29,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
public class ResEnumAttr extends ResAttr {
|
public class ResEnumAttr extends ResAttr {
|
||||||
ResEnumAttr(ResReferenceValue parent, int type, Integer min, Integer max,
|
ResEnumAttr(ResReferenceValue parent, int type, Integer min, Integer max,
|
||||||
Boolean l10n, Duo<ResReferenceValue, ResIntValue>[] items) {
|
Boolean l10n, Duo<ResReferenceValue, ResScalarValue>[] items) {
|
||||||
super(parent, type, min, max, l10n);
|
super(parent, type, min, max, l10n);
|
||||||
mItems = items;
|
mItems = items;
|
||||||
}
|
}
|
||||||
@ -48,8 +48,8 @@ public class ResEnumAttr extends ResAttr {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void serializeBody(XmlSerializer serializer, ResResource res) throws AndrolibException, IOException {
|
protected void serializeBody(XmlSerializer serializer, ResResource res) throws AndrolibException, IOException {
|
||||||
for (Duo<ResReferenceValue, ResIntValue> duo : mItems) {
|
for (Duo<ResReferenceValue, ResScalarValue> duo : mItems) {
|
||||||
int intVal = duo.m2.getValue();
|
int intVal = duo.m2.getRawIntValue();
|
||||||
|
|
||||||
// #2836 - Support skipping items if the resource cannot be identified.
|
// #2836 - Support skipping items if the resource cannot be identified.
|
||||||
ResResSpec m1Referent = duo.m1.getReferent();
|
ResResSpec m1Referent = duo.m1.getReferent();
|
||||||
@ -72,8 +72,8 @@ public class ResEnumAttr extends ResAttr {
|
|||||||
String value2 = mItemsCache.get(value);
|
String value2 = mItemsCache.get(value);
|
||||||
if (value2 == null) {
|
if (value2 == null) {
|
||||||
ResReferenceValue ref = null;
|
ResReferenceValue ref = null;
|
||||||
for (Duo<ResReferenceValue, ResIntValue> duo : mItems) {
|
for (Duo<ResReferenceValue, ResScalarValue> duo : mItems) {
|
||||||
if (duo.m2.getValue() == value) {
|
if (duo.m2.getRawIntValue() == value) {
|
||||||
ref = duo.m1;
|
ref = duo.m1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ public class ResEnumAttr extends ResAttr {
|
|||||||
return value2;
|
return value2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Duo<ResReferenceValue, ResIntValue>[] mItems;
|
private final Duo<ResReferenceValue, ResScalarValue>[] mItems;
|
||||||
private final Map<Integer, String> mItemsCache = new HashMap<>();
|
private final Map<Integer, String> mItemsCache = new HashMap<>();
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(ResEnumAttr.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(ResEnumAttr.class.getName());
|
||||||
|
@ -29,12 +29,12 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
public class ResFlagsAttr extends ResAttr {
|
public class ResFlagsAttr extends ResAttr {
|
||||||
ResFlagsAttr(ResReferenceValue parent, int type, Integer min, Integer max,
|
ResFlagsAttr(ResReferenceValue parent, int type, Integer min, Integer max,
|
||||||
Boolean l10n, Duo<ResReferenceValue, ResIntValue>[] items) {
|
Boolean l10n, Duo<ResReferenceValue, ResScalarValue>[] items) {
|
||||||
super(parent, type, min, max, l10n);
|
super(parent, type, min, max, l10n);
|
||||||
|
|
||||||
mItems = new FlagItem[items.length];
|
mItems = new FlagItem[items.length];
|
||||||
for (int i = 0; i < items.length; i++) {
|
for (int i = 0; i < items.length; i++) {
|
||||||
mItems[i] = new FlagItem(items[i].m1, items[i].m2.getValue());
|
mItems[i] = new FlagItem(items[i].m1, items[i].m2.getRawIntValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,5 @@ public class ResPluralsValue extends ResBagValue implements
|
|||||||
private final ResScalarValue[] mItems;
|
private final ResScalarValue[] mItems;
|
||||||
|
|
||||||
public static final int BAG_KEY_PLURALS_START = 0x01000004;
|
public static final int BAG_KEY_PLURALS_START = 0x01000004;
|
||||||
public static final int BAG_KEY_PLURALS_END = 0x01000009;
|
|
||||||
private static final String[] QUANTITY_MAP = new String[] { "other", "zero", "one", "two", "few", "many" };
|
private static final String[] QUANTITY_MAP = new String[] { "other", "zero", "one", "two", "few", "many" };
|
||||||
}
|
}
|
||||||
|
@ -80,39 +80,29 @@ public class ResValueFactory {
|
|||||||
return new ResStringValue(value, rawValue);
|
return new ResStringValue(value, rawValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResBagValue bagFactory(int parent, Duo<Integer, ResScalarValue>[] items, ResTypeSpec resTypeSpec) throws AndrolibException {
|
public ResBagValue bagFactory(int parent, Duo<Integer, ResScalarValue>[] items, ResTypeSpec resTypeSpec)
|
||||||
|
throws AndrolibException {
|
||||||
ResReferenceValue parentVal = newReference(parent, null);
|
ResReferenceValue parentVal = newReference(parent, null);
|
||||||
|
|
||||||
if (items.length == 0) {
|
if (items.length == 0) {
|
||||||
return new ResBagValue(parentVal);
|
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();
|
String resTypeName = resTypeSpec.getName();
|
||||||
|
|
||||||
// Android O Preview added an unknown enum for c. This is hardcoded as 0 for now.
|
switch (resTypeName) {
|
||||||
if (ResTypeSpec.RES_TYPE_NAME_ARRAY.equals(resTypeName)
|
case ResTypeSpec.RES_TYPE_NAME_ATTR:
|
||||||
|| key == ResArrayValue.BAG_KEY_ARRAY_START || key == 0) {
|
case ResTypeSpec.RES_TYPE_NAME_ATTR_PRIVATE:
|
||||||
return new ResArrayValue(parentVal, items);
|
return ResAttr.factory(parentVal, items, this, mPackage);
|
||||||
|
case ResTypeSpec.RES_TYPE_NAME_ARRAY:
|
||||||
|
return new ResArrayValue(parentVal, items);
|
||||||
|
case ResTypeSpec.RES_TYPE_NAME_PLURALS:
|
||||||
|
return new ResPluralsValue(parentVal, items);
|
||||||
|
default:
|
||||||
|
if (resTypeName.startsWith(ResTypeSpec.RES_TYPE_NAME_STYLES)) {
|
||||||
|
return new ResStyleValue(parentVal, items, this);
|
||||||
|
}
|
||||||
|
throw new AndrolibException("unsupported res type name for bags. Found: " + resTypeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ResTypeSpec.RES_TYPE_NAME_PLURALS.equals(resTypeName) ||
|
|
||||||
(key >= ResPluralsValue.BAG_KEY_PLURALS_START && key <= ResPluralsValue.BAG_KEY_PLURALS_END)) {
|
|
||||||
return new ResPluralsValue(parentVal, items);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new AndrolibException("unsupported res type name for bags. Found: " + resTypeName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResReferenceValue newReference(int resID, String rawValue) {
|
public ResReferenceValue newReference(int resID, String rawValue) {
|
||||||
|
@ -35,4 +35,7 @@
|
|||||||
<item>res/</item>
|
<item>res/</item>
|
||||||
<item>view/</item>
|
<item>view/</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<string-array name="issue_2806">
|
||||||
|
<item>MIICXAIBAAKBgQCjcGqTkOq0CR3rTx0ZSQSIdTrDrFAYl29611xN8aVgMQIWtDB/lD0W5TpKPuU9iaiG/sSn/VYt6EzN7Sr332jj7cyl2WrrHI6ujRswNy4HojMuqtfab5FFDpRmCuvl35fge18OvoQTJELhhJ1EvJ5KUeZiuJ3u3YyMnxxXzLuKbQIDAQABAoGAPrNDz7TKtaLBvaIuMaMXgBopHyQd3jFKbT/tg2Fu5kYm3PrnmCoQfZYXFKCoZUFIS/G1FBVWWGpD/MQ9tbYZkKpwuH+t2rGndMnLXiTC296/s9uix7gsjnT4Naci5N6EN9pVUBwQmGrYUTHFc58ThtelSiPARX7LSU2ibtJSv8ECQQDWBRrrAYmbCUN7ra0DFT6SppaDtvvuKtb+mUeKbg0B8U4y4wCIK5GH8EyQSwUWcXnNBO05rlUPbifsDLv/u82lAkEAw39sTJ0KmJJyaChqvqAJ8guulKlgucQJ0Et9ppZyet9iVwNKX/aW9UlwGBMQdafQ36nd1QMEA8AbAw4D+hw/KQJBANJbHDUGQtk2hrSmZNoV5HXB9Uiq7v4N71k5ER8XwgM5yVGs2tX8dMM3RhnBEtQXXs9LW1uJZSOQcv7JGXNnhN0CQBZenzrJAWxh3XtznHtBfsHWelyCYRIAj4rpCHCmaGUM6IjCVKFUawOYKp5mmAyObkUZf8ue87emJLEdynC1CLkCQHduNjP1hemAGWrd6v8BHhE3kKtcK6KHsPvJR5dOfzbdHAqVePERhISfN6cwZt5p8B3/JUwSR8el66DF7Jm57BM=</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user