Skip to content

Commit 2086d80

Browse files
authored
tweak: filter redundant flags in flag attrs (#3849)
* tweak: filter redundant flags in flag attrs This trick gets rid of unneeded flags in flag attrs that even contextually don't make sense. Most commonly: android:layout_gravity="bottom|center|left" 000000000000000000000011 (left) 000000000000000000010001 (center) 000000000000000001010000 (bottom) 'left|bottom' already covers the bits set by 'center', and contextually something can't be left, bottom and center all at once. There are very few flag attrs like that, where certain flags overlap, but this fixes this annoyance when editing res XMLs. * micro-optimize * optimize: redundancy only possible with flags > 2
1 parent db0de9b commit 2086d80

File tree

3 files changed

+68
-33
lines changed

3 files changed

+68
-33
lines changed

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,34 +135,34 @@ protected void serializeBody(XmlSerializer serializer, ResResource res)
135135
}
136136

137137
protected String getTypeAsString() {
138-
String s = "";
138+
StringBuilder sb = new StringBuilder();
139139
if ((mType & TYPE_REFERENCE) != 0) {
140-
s += "|reference";
140+
sb.append("|reference");
141141
}
142142
if ((mType & TYPE_STRING) != 0) {
143-
s += "|string";
143+
sb.append("|string");
144144
}
145145
if ((mType & TYPE_INT) != 0) {
146-
s += "|integer";
146+
sb.append("|integer");
147147
}
148148
if ((mType & TYPE_BOOL) != 0) {
149-
s += "|boolean";
149+
sb.append("|boolean");
150150
}
151151
if ((mType & TYPE_COLOR) != 0) {
152-
s += "|color";
152+
sb.append("|color");
153153
}
154154
if ((mType & TYPE_FLOAT) != 0) {
155-
s += "|float";
155+
sb.append("|float");
156156
}
157157
if ((mType & TYPE_DIMEN) != 0) {
158-
s += "|dimension";
158+
sb.append("|dimension");
159159
}
160160
if ((mType & TYPE_FRACTION) != 0) {
161-
s += "|fraction";
161+
sb.append("|fraction");
162162
}
163-
if (s.isEmpty()) {
163+
if (sb.length() == 0) {
164164
return null;
165165
}
166-
return s.substring(1);
166+
return sb.substring(1);
167167
}
168168
}

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

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,28 +55,70 @@ public String convertToResXmlFormat(ResScalarValue value) throws AndrolibExcepti
5555
return super.convertToResXmlFormat(value);
5656
}
5757
loadFlags();
58-
int intVal = ((ResIntValue) value).getValue();
5958

59+
int intVal = ((ResIntValue) value).getValue();
6060
if (intVal == 0) {
6161
return renderFlags(mZeroFlags);
6262
}
6363

64-
FlagItem[] flagItems = new FlagItem[mFlags.length];
65-
int[] flags = new int[mFlags.length];
64+
FlagItem[] flags = new FlagItem[mFlags.length];
6665
int flagsCount = 0;
67-
for (FlagItem flagItem : mFlags) {
68-
int flag = flagItem.flag;
66+
int flagsInt = 0;
67+
68+
for (FlagItem item : mFlags) {
69+
int flag = item.flag;
6970

70-
if ((intVal & flag) != flag) {
71+
if ((intVal & flag) != flag || (flagsInt & flag) == flag) {
7172
continue;
7273
}
7374

74-
if (!isSubpartOf(flag, flags)) {
75-
flags[flagsCount] = flag;
76-
flagItems[flagsCount++] = flagItem;
75+
flags[flagsCount++] = item;
76+
flagsInt |= flag;
77+
78+
if (intVal == flagsInt) {
79+
break;
7780
}
7881
}
79-
return renderFlags(Arrays.copyOf(flagItems, flagsCount));
82+
83+
if (flagsCount == 0) {
84+
throw new AndrolibException(String.format("invalid flags in value: 0x%08x", intVal));
85+
}
86+
87+
// Filter out redundant flags
88+
if (flagsCount > 2) {
89+
FlagItem[] filtered = new FlagItem[flagsCount];
90+
int filteredCount = 0;
91+
92+
for (int i = 0; i < flagsCount; i++) {
93+
FlagItem item = flags[i];
94+
int mask = 0;
95+
96+
// Combine the other flags
97+
for (int j = 0; j < flagsCount; j++) {
98+
FlagItem other = flags[j];
99+
100+
if (j != i && other != null) {
101+
mask |= other.flag;
102+
}
103+
}
104+
105+
// Keep only if it adds at least one unique bit
106+
if ((item.flag & ~mask) != 0) {
107+
filtered[filteredCount++] = item;
108+
} else {
109+
flags[i] = null;
110+
}
111+
}
112+
113+
flags = filtered;
114+
flagsCount = filteredCount;
115+
}
116+
117+
if (flagsCount != flags.length) {
118+
flags = Arrays.copyOf(flags, flagsCount);
119+
}
120+
121+
return renderFlags(flags);
80122
}
81123

82124
@Override
@@ -98,15 +140,6 @@ protected void serializeBody(XmlSerializer serializer, ResResource res)
98140
}
99141
}
100142

101-
private boolean isSubpartOf(int flag, int[] flags) {
102-
for (int f : flags) {
103-
if ((f & flag) == flag) {
104-
return true;
105-
}
106-
}
107-
return false;
108-
}
109-
110143
private String renderFlags(FlagItem[] flags) throws AndrolibException {
111144
StringBuilder sb = new StringBuilder();
112145
for (FlagItem flag : flags) {
@@ -139,6 +172,8 @@ private void loadFlags() {
139172
mZeroFlags = Arrays.copyOf(zeroFlags, zeroFlagsCount);
140173
mFlags = Arrays.copyOf(flags, flagsCount);
141174

142-
Arrays.sort(mFlags, Comparator.comparingInt((FlagItem item) -> Integer.bitCount(item.flag)).reversed());
175+
Arrays.sort(mFlags,
176+
Comparator.comparingInt((FlagItem item) -> Integer.bitCount(item.flag)).reversed()
177+
.thenComparingInt((FlagItem item) -> item.flag));
143178
}
144179
}

brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/NetworkConfigTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ public void netSecConfGeneric() throws BrutException {
6565
Document doc = loadDocument(new File(sTestNewDir, "res/xml/network_security_config.xml"));
6666

6767
// Check if 'system' certificate exists
68-
String systemCertExpr = "//base-config//certificates[@src='system']";
68+
String systemCertExpr = "/network-security-config/base-config/trust-anchors/certificates[@src='system']";
6969
NodeList systemCertNodes = evaluateXPath(doc, systemCertExpr, NodeList.class);
7070
assertTrue(systemCertNodes.getLength() > 0);
7171

7272
// Check if 'user' certificate exists
73-
String userCertExpr = "//base-config//certificates[@src='user']";
73+
String userCertExpr = "/network-security-config/base-config/trust-anchors/certificates[@src='user']";
7474
NodeList userCertNodes = evaluateXPath(doc, userCertExpr, NodeList.class);
7575
assertTrue(userCertNodes.getLength() > 0);
7676
}

0 commit comments

Comments
 (0)