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:
Connor Tumbleson 2023-09-11 19:01:09 -04:00 committed by GitHub
parent c07e4a92e6
commit 515af4faf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 41 additions and 49 deletions

View File

@ -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 {

View File

@ -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;
} }

View File

@ -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;

View File

@ -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());

View File

@ -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());
} }
} }

View File

@ -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" };
} }

View File

@ -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) {

View File

@ -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>