Remove Apktool Dummys. (#3258)

* refactor: properly parse dummy resources

* feat: remove dummys
This commit is contained in:
Connor Tumbleson 2023-08-09 06:15:57 -04:00 committed by GitHub
parent bb9519a2d0
commit 0e226928ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 4 additions and 77 deletions

View File

@ -127,10 +127,6 @@ public class ResPackage {
return mSynthesizedRes.contains(resId);
}
public void removeResSpec(ResResSpec spec) {
mResSpecs.remove(spec.getId());
}
public void addResSpec(ResResSpec spec) throws AndrolibException {
if (mResSpecs.put(spec.getId(), spec) != null) {
throw new AndrolibException("Multiple resource specs: " + spec);

View File

@ -105,10 +105,6 @@ public class ResResSpec {
return mType;
}
public boolean isDummyResSpec() {
return getName().startsWith("APKTOOL_DUMMY_");
}
public void addResource(ResResource res) throws AndrolibException {
addResource(res, false);
}

View File

@ -30,18 +30,11 @@ public final class ResTypeSpec {
private final String mName;
private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<>();
private final ResTable mResTable;
private final ResPackage mPackage;
private final int mId;
private final int mEntryCount;
public ResTypeSpec(String name, ResTable resTable, ResPackage package_, int id, int entryCount) {
public ResTypeSpec(String name, int id) {
this.mName = name;
this.mResTable = resTable;
this.mPackage = package_;
this.mId = id;
this.mEntryCount = entryCount;
}
public String getName() {
@ -68,10 +61,6 @@ public final class ResTypeSpec {
return mResSpecs.get(name);
}
public void removeResSpec(ResResSpec spec) {
mResSpecs.remove(spec.getName());
}
public void addResSpec(ResResSpec spec) throws AndrolibException {
if (mResSpecs.put(spec.getName(), spec) != null) {
throw new AndrolibException(String.format("Multiple res specs: %s/%s", getName(), spec.getName()));

View File

@ -81,11 +81,6 @@ public abstract class ResScalarValue extends ResIntBasedValue implements
}
}
// Dummy attributes should be <item> with type attribute
if (res.getResSpec().isDummyResSpec()) {
item = true;
}
// Android does not allow values (false) for ids.xml anymore
// https://issuetracker.google.com/issues/80475496
// But it decodes as a ResBoolean, which makes no sense. So force it to empty

View File

@ -63,6 +63,7 @@ public class ARSCDecoder {
private ResPackage[] readResourceTable() throws IOException, AndrolibException {
Set<ResPackage> pkgs = new LinkedHashSet<>();
ResTypeSpec typeSpec;
chunkLoop:
@ -112,10 +113,6 @@ public class ARSCDecoder {
}
}
if (mPkg != null && mPkg.getResSpecCount() > 0) {
addMissingResSpecs();
}
return pkgs.toArray(new ResPackage[0]);
}
@ -245,7 +242,7 @@ public class ARSCDecoder {
mHeader.checkForUnreadHeader(mIn);
mIn.skipBytes(entryCount * 4); // flags
mTypeSpec = new ResTypeSpec(mTypeNames.getString(id - 1), mResTable, mPkg, id, entryCount);
mTypeSpec = new ResTypeSpec(mTypeNames.getString(id - 1), id);
mPkg.addType(mTypeSpec);
return mTypeSpec;
@ -264,7 +261,6 @@ public class ARSCDecoder {
int entryCount = mIn.readInt();
mIn.skipInt(); // entriesStart
mMissingResSpecMap = new LinkedHashMap<>();
ResConfigFlags flags = readConfigFlags();
mHeader.checkForUnreadHeader(mIn);
@ -297,12 +293,11 @@ public class ARSCDecoder {
mType = flags.isInvalid && !mKeepBroken ? null : mPkg.getOrCreateConfig(flags);
for (int i : entryOffsetMap.keySet()) {
mResId = (mResId & 0xffff0000) | i;
int offset = entryOffsetMap.get(i);
if (offset == NO_ENTRY) {
continue;
}
mMissingResSpecMap.put(i, false);
mResId = (mResId & 0xffff0000) | i;
// As seen in some recent APKs - there are more entries reported than can fit in the chunk.
if (mIn.position() == mHeader.endPosition) {
@ -369,14 +364,6 @@ public class ARSCDecoder {
ResResSpec spec;
if (mPkg.hasResSpec(resId)) {
spec = mPkg.getResSpec(resId);
if (spec.isDummyResSpec()) {
removeResSpec(spec);
spec = new ResResSpec(resId, mSpecNames.getString(specNamesId), mPkg, mTypeSpec);
mPkg.addResSpec(spec);
mTypeSpec.addResSpec(spec);
}
} else {
spec = new ResResSpec(resId, mSpecNames.getString(specNamesId), mPkg, mTypeSpec);
mPkg.addResSpec(spec);
@ -598,41 +585,6 @@ public class ARSCDecoder {
mResTypeSpecs.put(resTypeSpec.getId(), resTypeSpec);
}
private void addMissingResSpecs() throws AndrolibException {
int resId = mResId & 0xffff0000;
for (int i : mMissingResSpecMap.keySet()) {
if (mMissingResSpecMap.get(i)) continue;
ResResSpec spec = new ResResSpec(new ResID(resId | i), "APKTOOL_DUMMY_" + Integer.toHexString(i), mPkg, mTypeSpec);
// If we already have this resID don't add it again.
if (! mPkg.hasResSpec(new ResID(resId | i))) {
mPkg.addResSpec(spec);
mTypeSpec.addResSpec(spec);
if (mType == null) {
mType = mPkg.getOrCreateConfig(new ResConfigFlags());
}
// We are going to make dummy attributes a null reference (@null) now instead of a boolean false.
// This is because aapt2 is much more strict when it comes to what we can put in an application.
ResValue value = new ResReferenceValue(mPkg, 0, "");
ResResource res = new ResResource(mType, spec, value);
mType.addResource(res);
spec.addResource(res);
}
}
}
private void removeResSpec(ResResSpec spec) {
if (mPkg.hasResSpec(spec.getId())) {
mPkg.removeResSpec(spec);
mTypeSpec.removeResSpec(spec);
}
}
private ARSCHeader nextChunk() throws IOException {
return mHeader = ARSCHeader.read(mIn);
}
@ -658,7 +610,6 @@ public class ARSCDecoder {
private ResType mType;
private int mResId;
private int mTypeIdOffset = 0;
private HashMap<Integer, Boolean> mMissingResSpecMap;
private final HashMap<Integer, ResTypeSpec> mResTypeSpecs = new HashMap<>();
private final static short ENTRY_FLAG_COMPLEX = 0x0001;