Skip to content

Commit

Permalink
Revert "Remove Apktool Dummys. (#3258)"
Browse files Browse the repository at this point in the history
This reverts commit 0e22692.
  • Loading branch information
iBotPeaches committed Sep 4, 2023
1 parent f0ca6d1 commit a48e1b6
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ boolean isSynthesized(ResID resId) {
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ public ResTypeSpec getType() {
return mType;
}

public boolean isDummyResSpec() {
return getName().startsWith("APKTOOL_DUMMY_");
}

public void addResource(ResResource res) throws AndrolibException {
addResource(res, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,18 @@ 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, int id) {
public ResTypeSpec(String name, ResTable resTable, ResPackage package_, int id, int entryCount) {
this.mName = name;
this.mResTable = resTable;
this.mPackage = package_;
this.mId = id;
this.mEntryCount = entryCount;
}

public String getName() {
Expand All @@ -61,6 +68,10 @@ public ResResSpec getResSpecUnsafe(String name) {
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()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ public void serializeToResValuesXml(XmlSerializer serializer,
}
}

// 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ private ARSCDecoder(InputStream arscStream, ResTable resTable, boolean storeFlag

private ResPackage[] readResourceTable() throws IOException, AndrolibException {
Set<ResPackage> pkgs = new LinkedHashSet<>();

ResTypeSpec typeSpec;
int chunkNumber = 1;

Expand Down Expand Up @@ -118,6 +117,10 @@ private ResPackage[] readResourceTable() throws IOException, AndrolibException {
}
}

if (mPkg != null && mPkg.getResSpecCount() > 0) {
addMissingResSpecs();
}

return pkgs.toArray(new ResPackage[0]);
}

Expand Down Expand Up @@ -247,7 +250,7 @@ private ResTypeSpec readTableSpecType() throws AndrolibException, IOException {
mHeader.checkForUnreadHeader(mIn);

mIn.skipBytes(entryCount * 4); // flags
mTypeSpec = new ResTypeSpec(mTypeNames.getString(id - 1), id);
mTypeSpec = new ResTypeSpec(mTypeNames.getString(id - 1), mResTable, mPkg, id, entryCount);
mPkg.addType(mTypeSpec);

return mTypeSpec;
Expand All @@ -266,6 +269,7 @@ private ResType readTableType() throws IOException, AndrolibException {
int entryCount = mIn.readInt();
mIn.skipInt(); // entriesStart

mMissingResSpecMap = new LinkedHashMap<>();
ResConfigFlags flags = readConfigFlags();

mHeader.checkForUnreadHeader(mIn);
Expand Down Expand Up @@ -297,11 +301,12 @@ private ResType readTableType() throws IOException, AndrolibException {
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) {
Expand Down Expand Up @@ -368,6 +373,14 @@ private void readEntry(EntryData entryData) throws AndrolibException {
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);
Expand Down Expand Up @@ -589,6 +602,41 @@ private void addTypeSpec(ResTypeSpec 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 {
return mHeader = ARSCHeader.read(mIn);
}
Expand All @@ -614,6 +662,7 @@ private void checkChunkType(int expectedType) throws AndrolibException {
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;
Expand Down

0 comments on commit a48e1b6

Please sign in to comment.