mirror of
https://github.com/revanced/Apktool.git
synced 2024-12-03 17:42:53 +01:00
Remove Apktool Dummys. (#3258)
* refactor: properly parse dummy resources * feat: remove dummys
This commit is contained in:
parent
bb9519a2d0
commit
0e226928ce
@ -127,10 +127,6 @@ public class ResPackage {
|
|||||||
return mSynthesizedRes.contains(resId);
|
return mSynthesizedRes.contains(resId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeResSpec(ResResSpec spec) {
|
|
||||||
mResSpecs.remove(spec.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addResSpec(ResResSpec spec) throws AndrolibException {
|
public void addResSpec(ResResSpec spec) throws AndrolibException {
|
||||||
if (mResSpecs.put(spec.getId(), spec) != null) {
|
if (mResSpecs.put(spec.getId(), spec) != null) {
|
||||||
throw new AndrolibException("Multiple resource specs: " + spec);
|
throw new AndrolibException("Multiple resource specs: " + spec);
|
||||||
|
@ -105,10 +105,6 @@ public class ResResSpec {
|
|||||||
return mType;
|
return mType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDummyResSpec() {
|
|
||||||
return getName().startsWith("APKTOOL_DUMMY_");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addResource(ResResource res) throws AndrolibException {
|
public void addResource(ResResource res) throws AndrolibException {
|
||||||
addResource(res, false);
|
addResource(res, false);
|
||||||
}
|
}
|
||||||
|
@ -30,18 +30,11 @@ public final class ResTypeSpec {
|
|||||||
private final String mName;
|
private final String mName;
|
||||||
private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<>();
|
private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<>();
|
||||||
|
|
||||||
private final ResTable mResTable;
|
|
||||||
private final ResPackage mPackage;
|
|
||||||
|
|
||||||
private final int mId;
|
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.mName = name;
|
||||||
this.mResTable = resTable;
|
|
||||||
this.mPackage = package_;
|
|
||||||
this.mId = id;
|
this.mId = id;
|
||||||
this.mEntryCount = entryCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -68,10 +61,6 @@ public final class ResTypeSpec {
|
|||||||
return mResSpecs.get(name);
|
return mResSpecs.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeResSpec(ResResSpec spec) {
|
|
||||||
mResSpecs.remove(spec.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addResSpec(ResResSpec spec) throws AndrolibException {
|
public void addResSpec(ResResSpec spec) throws AndrolibException {
|
||||||
if (mResSpecs.put(spec.getName(), spec) != null) {
|
if (mResSpecs.put(spec.getName(), spec) != null) {
|
||||||
throw new AndrolibException(String.format("Multiple res specs: %s/%s", getName(), spec.getName()));
|
throw new AndrolibException(String.format("Multiple res specs: %s/%s", getName(), spec.getName()));
|
||||||
|
@ -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
|
// Android does not allow values (false) for ids.xml anymore
|
||||||
// https://issuetracker.google.com/issues/80475496
|
// https://issuetracker.google.com/issues/80475496
|
||||||
// But it decodes as a ResBoolean, which makes no sense. So force it to empty
|
// But it decodes as a ResBoolean, which makes no sense. So force it to empty
|
||||||
|
@ -63,6 +63,7 @@ public class ARSCDecoder {
|
|||||||
|
|
||||||
private ResPackage[] readResourceTable() throws IOException, AndrolibException {
|
private ResPackage[] readResourceTable() throws IOException, AndrolibException {
|
||||||
Set<ResPackage> pkgs = new LinkedHashSet<>();
|
Set<ResPackage> pkgs = new LinkedHashSet<>();
|
||||||
|
|
||||||
ResTypeSpec typeSpec;
|
ResTypeSpec typeSpec;
|
||||||
|
|
||||||
chunkLoop:
|
chunkLoop:
|
||||||
@ -112,10 +113,6 @@ public class ARSCDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPkg != null && mPkg.getResSpecCount() > 0) {
|
|
||||||
addMissingResSpecs();
|
|
||||||
}
|
|
||||||
|
|
||||||
return pkgs.toArray(new ResPackage[0]);
|
return pkgs.toArray(new ResPackage[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,7 +242,7 @@ public class ARSCDecoder {
|
|||||||
mHeader.checkForUnreadHeader(mIn);
|
mHeader.checkForUnreadHeader(mIn);
|
||||||
|
|
||||||
mIn.skipBytes(entryCount * 4); // flags
|
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);
|
mPkg.addType(mTypeSpec);
|
||||||
|
|
||||||
return mTypeSpec;
|
return mTypeSpec;
|
||||||
@ -264,7 +261,6 @@ public class ARSCDecoder {
|
|||||||
int entryCount = mIn.readInt();
|
int entryCount = mIn.readInt();
|
||||||
mIn.skipInt(); // entriesStart
|
mIn.skipInt(); // entriesStart
|
||||||
|
|
||||||
mMissingResSpecMap = new LinkedHashMap<>();
|
|
||||||
ResConfigFlags flags = readConfigFlags();
|
ResConfigFlags flags = readConfigFlags();
|
||||||
|
|
||||||
mHeader.checkForUnreadHeader(mIn);
|
mHeader.checkForUnreadHeader(mIn);
|
||||||
@ -297,12 +293,11 @@ public class ARSCDecoder {
|
|||||||
mType = flags.isInvalid && !mKeepBroken ? null : mPkg.getOrCreateConfig(flags);
|
mType = flags.isInvalid && !mKeepBroken ? null : mPkg.getOrCreateConfig(flags);
|
||||||
|
|
||||||
for (int i : entryOffsetMap.keySet()) {
|
for (int i : entryOffsetMap.keySet()) {
|
||||||
|
mResId = (mResId & 0xffff0000) | i;
|
||||||
int offset = entryOffsetMap.get(i);
|
int offset = entryOffsetMap.get(i);
|
||||||
if (offset == NO_ENTRY) {
|
if (offset == NO_ENTRY) {
|
||||||
continue;
|
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.
|
// As seen in some recent APKs - there are more entries reported than can fit in the chunk.
|
||||||
if (mIn.position() == mHeader.endPosition) {
|
if (mIn.position() == mHeader.endPosition) {
|
||||||
@ -369,14 +364,6 @@ public class ARSCDecoder {
|
|||||||
ResResSpec spec;
|
ResResSpec spec;
|
||||||
if (mPkg.hasResSpec(resId)) {
|
if (mPkg.hasResSpec(resId)) {
|
||||||
spec = mPkg.getResSpec(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 {
|
} else {
|
||||||
spec = new ResResSpec(resId, mSpecNames.getString(specNamesId), mPkg, mTypeSpec);
|
spec = new ResResSpec(resId, mSpecNames.getString(specNamesId), mPkg, mTypeSpec);
|
||||||
mPkg.addResSpec(spec);
|
mPkg.addResSpec(spec);
|
||||||
@ -598,41 +585,6 @@ public class ARSCDecoder {
|
|||||||
mResTypeSpecs.put(resTypeSpec.getId(), resTypeSpec);
|
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 {
|
private ARSCHeader nextChunk() throws IOException {
|
||||||
return mHeader = ARSCHeader.read(mIn);
|
return mHeader = ARSCHeader.read(mIn);
|
||||||
}
|
}
|
||||||
@ -658,7 +610,6 @@ public class ARSCDecoder {
|
|||||||
private ResType mType;
|
private ResType mType;
|
||||||
private int mResId;
|
private int mResId;
|
||||||
private int mTypeIdOffset = 0;
|
private int mTypeIdOffset = 0;
|
||||||
private HashMap<Integer, Boolean> mMissingResSpecMap;
|
|
||||||
private final HashMap<Integer, ResTypeSpec> mResTypeSpecs = new HashMap<>();
|
private final HashMap<Integer, ResTypeSpec> mResTypeSpecs = new HashMap<>();
|
||||||
|
|
||||||
private final static short ENTRY_FLAG_COMPLEX = 0x0001;
|
private final static short ENTRY_FLAG_COMPLEX = 0x0001;
|
||||||
|
Loading…
Reference in New Issue
Block a user