From 6c4167fba4db54ab7e9edf4712df6d41b7c3f5da Mon Sep 17 00:00:00 2001 From: Connor Tumbleson Date: Mon, 7 Dec 2015 20:48:57 -0600 Subject: [PATCH] Fixes #1099 - Moves Config --> Type - Moves Type -> TypeSpec - ResType -> ResTypeSpec - ResConfig -> ResType This is to match AOSP and ease the transitions/updates of new AOSP drops --- .../brut/androlib/res/data/ResConfig.java | 72 --------------- .../brut/androlib/res/data/ResPackage.java | 38 ++++---- .../brut/androlib/res/data/ResResSpec.java | 10 +- .../brut/androlib/res/data/ResResource.java | 6 +- .../java/brut/androlib/res/data/ResType.java | 53 +++++------ .../brut/androlib/res/data/ResTypeSpec.java | 71 ++++++++++++++ .../brut/androlib/res/data/ResValuesFile.java | 10 +- .../androlib/res/decoder/ARSCDecoder.java | 92 +++++++++---------- 8 files changed, 173 insertions(+), 179 deletions(-) delete mode 100644 brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfig.java create mode 100644 brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTypeSpec.java diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfig.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfig.java deleted file mode 100644 index 98e3b9b8..00000000 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfig.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright 2014 Ryszard Wiśniewski - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package brut.androlib.res.data; - -import brut.androlib.AndrolibException; -import brut.androlib.err.UndefinedResObject; -import java.util.*; - -/** - * @author Ryszard Wiśniewski - */ -public class ResConfig { - private final ResConfigFlags mFlags; - private final Map mResources = new LinkedHashMap(); - - public ResConfig(ResConfigFlags flags) { - this.mFlags = flags; - } - - public Set listResources() { - return new LinkedHashSet(mResources.values()); - } - - public ResResource getResource(ResResSpec spec) throws AndrolibException { - ResResource res = mResources.get(spec); - if (res == null) { - throw new UndefinedResObject(String.format( - "resource: spec=%s, config=%s", spec, this)); - } - return res; - } - - public Set listResSpecs() { - return mResources.keySet(); - } - - public ResConfigFlags getFlags() { - return mFlags; - } - - public void addResource(ResResource res) throws AndrolibException { - addResource(res, false); - } - - public void addResource(ResResource res, boolean overwrite) - throws AndrolibException { - ResResSpec spec = res.getResSpec(); - if (mResources.put(spec, res) != null && !overwrite) { - throw new AndrolibException(String.format( - "Multiple resources: spec=%s, config=%s", spec, this)); - } - } - - @Override - public String toString() { - return mFlags.toString(); - } -} diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResPackage.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResPackage.java index d9cfcc68..4ef9b94b 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResPackage.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResPackage.java @@ -33,8 +33,8 @@ public class ResPackage { private final int mId; private final String mName; private final Map mResSpecs = new LinkedHashMap(); - private final Map mConfigs = new LinkedHashMap(); - private final Map mTypes = new LinkedHashMap(); + private final Map mConfigs = new LinkedHashMap(); + private final Map mTypes = new LinkedHashMap(); private final Set mSynthesizedRes = new HashSet(); private ResValueFactory mValueFactory; @@ -61,16 +61,16 @@ public class ResPackage { return spec; } - public List getConfigs() { - return new ArrayList(mConfigs.values()); + public List getConfigs() { + return new ArrayList(mConfigs.values()); } public boolean hasConfig(ResConfigFlags flags) { return mConfigs.containsKey(flags); } - public ResConfig getConfig(ResConfigFlags flags) throws AndrolibException { - ResConfig config = mConfigs.get(flags); + public ResType getConfig(ResConfigFlags flags) throws AndrolibException { + ResType config = mConfigs.get(flags); if (config == null) { throw new UndefinedResObject("config: " + flags); } @@ -81,26 +81,26 @@ public class ResPackage { return mResSpecs.size(); } - public ResConfig getOrCreateConfig(ResConfigFlags flags) + public ResType getOrCreateConfig(ResConfigFlags flags) throws AndrolibException { - ResConfig config = mConfigs.get(flags); + ResType config = mConfigs.get(flags); if (config == null) { - config = new ResConfig(flags); + config = new ResType(flags); mConfigs.put(flags, config); } return config; } - public List listTypes() { - return new ArrayList(mTypes.values()); + public List listTypes() { + return new ArrayList(mTypes.values()); } public boolean hasType(String typeName) { return mTypes.containsKey(typeName); } - public ResType getType(String typeName) throws AndrolibException { - ResType type = mTypes.get(typeName); + public ResTypeSpec getType(String typeName) throws AndrolibException { + ResTypeSpec type = mTypes.get(typeName); if (type == null) { throw new UndefinedResObject("type: " + typeName); } @@ -120,13 +120,13 @@ public class ResPackage { } public Collection listValuesFiles() { - Map, ResValuesFile> ret = new HashMap, ResValuesFile>(); + Map, ResValuesFile> ret = new HashMap, ResValuesFile>(); for (ResResSpec spec : mResSpecs.values()) { for (ResResource res : spec.listResources()) { if (res.getValue() instanceof ResValuesXmlSerializable) { - ResType type = res.getResSpec().getType(); - ResConfig config = res.getConfig(); - Duo key = new Duo( + ResTypeSpec type = res.getResSpec().getType(); + ResType config = res.getConfig(); + Duo key = new Duo( type, config); ResValuesFile values = ret.get(key); if (values == null) { @@ -162,13 +162,13 @@ public class ResPackage { } } - public void addConfig(ResConfig config) throws AndrolibException { + public void addConfig(ResType config) throws AndrolibException { if (mConfigs.put(config.getFlags(), config) != null) { throw new AndrolibException("Multiple configs: " + config); } } - public void addType(ResType type) throws AndrolibException { + public void addType(ResTypeSpec type) throws AndrolibException { if (mTypes.containsKey(type.getName())) { LOGGER.warning("Multiple types detected! " + type + " ignored!"); } else { diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResResSpec.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResResSpec.java index 32f3296b..be81fb38 100755 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResResSpec.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResResSpec.java @@ -28,10 +28,10 @@ public class ResResSpec { private final ResID mId; private final String mName; private final ResPackage mPackage; - private final ResType mType; + private final ResTypeSpec mType; private final Map mResources = new LinkedHashMap(); - public ResResSpec(ResID id, String name, ResPackage pkg, ResType type) { + public ResResSpec(ResID id, String name, ResPackage pkg, ResTypeSpec type) { this.mId = id; this.mName = name; this.mPackage = pkg; @@ -42,7 +42,7 @@ public class ResResSpec { return new LinkedHashSet(mResources.values()); } - public ResResource getResource(ResConfig config) throws AndrolibException { + public ResResource getResource(ResType config) throws AndrolibException { return getResource(config.getFlags()); } @@ -56,7 +56,7 @@ public class ResResSpec { return res; } - public boolean hasResource(ResConfig config) { + public boolean hasResource(ResType config) { return hasResource(config.getFlags()); } @@ -97,7 +97,7 @@ public class ResResSpec { return mPackage; } - public ResType getType() { + public ResTypeSpec getType() { return mType; } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResResource.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResResource.java index 31fc7a3b..c89dd976 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResResource.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResResource.java @@ -23,11 +23,11 @@ import brut.androlib.res.data.value.ResValue; * @author Ryszard Wiśniewski */ public class ResResource { - private final ResConfig mConfig; + private final ResType mConfig; private final ResResSpec mResSpec; private final ResValue mValue; - public ResResource(ResConfig config, ResResSpec spec, ResValue value) { + public ResResource(ResType config, ResResSpec spec, ResValue value) { this.mConfig = config; this.mResSpec = spec; this.mValue = value; @@ -38,7 +38,7 @@ public class ResResource { + mConfig.getFlags().getQualifiers() + "/" + mResSpec.getName(); } - public ResConfig getConfig() { + public ResType getConfig() { return mConfig; } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResType.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResType.java index 1d22b848..627736b6 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResType.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResType.java @@ -23,49 +23,50 @@ import java.util.*; /** * @author Ryszard Wiśniewski */ -public final class ResType { - private final String mName; - private final Map mResSpecs = new LinkedHashMap(); +public class ResType { + private final ResConfigFlags mFlags; + private final Map mResources = new LinkedHashMap(); - private final ResTable mResTable; - private final ResPackage mPackage; - - public ResType(String name, ResTable resTable, ResPackage package_) { - this.mName = name; - this.mResTable = resTable; - this.mPackage = package_; + public ResType(ResConfigFlags flags) { + this.mFlags = flags; } - public String getName() { - return mName; + public Set listResources() { + return new LinkedHashSet(mResources.values()); } - public boolean isString() { - return mName.equalsIgnoreCase("string"); + public ResResource getResource(ResResSpec spec) throws AndrolibException { + ResResource res = mResources.get(spec); + if (res == null) { + throw new UndefinedResObject(String.format( + "resource: spec=%s, config=%s", spec, this)); + } + return res; } public Set listResSpecs() { - return new LinkedHashSet(mResSpecs.values()); + return mResources.keySet(); } - public ResResSpec getResSpec(String name) throws AndrolibException { - ResResSpec spec = mResSpecs.get(name); - if (spec == null) { - throw new UndefinedResObject(String.format("resource spec: %s/%s", - getName(), name)); - } - return spec; + public ResConfigFlags getFlags() { + return mFlags; } - public void addResSpec(ResResSpec spec) throws AndrolibException { - if (mResSpecs.put(spec.getName(), spec) != null) { + public void addResource(ResResource res) throws AndrolibException { + addResource(res, false); + } + + public void addResource(ResResource res, boolean overwrite) + throws AndrolibException { + ResResSpec spec = res.getResSpec(); + if (mResources.put(spec, res) != null && !overwrite) { throw new AndrolibException(String.format( - "Multiple res specs: %s/%s", getName(), spec.getName())); + "Multiple resources: spec=%s, config=%s", spec, this)); } } @Override public String toString() { - return mName; + return mFlags.toString(); } } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTypeSpec.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTypeSpec.java new file mode 100644 index 00000000..48fb8765 --- /dev/null +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTypeSpec.java @@ -0,0 +1,71 @@ +/** + * Copyright 2014 Ryszard Wiśniewski + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package brut.androlib.res.data; + +import brut.androlib.AndrolibException; +import brut.androlib.err.UndefinedResObject; +import java.util.*; + +/** + * @author Ryszard Wiśniewski + */ +public final class ResTypeSpec { + private final String mName; + private final Map mResSpecs = new LinkedHashMap(); + + private final ResTable mResTable; + private final ResPackage mPackage; + + public ResTypeSpec(String name, ResTable resTable, ResPackage package_) { + this.mName = name; + this.mResTable = resTable; + this.mPackage = package_; + } + + public String getName() { + return mName; + } + + public boolean isString() { + return mName.equalsIgnoreCase("string"); + } + + public Set listResSpecs() { + return new LinkedHashSet(mResSpecs.values()); + } + + public ResResSpec getResSpec(String name) throws AndrolibException { + ResResSpec spec = mResSpecs.get(name); + if (spec == null) { + throw new UndefinedResObject(String.format("resource spec: %s/%s", + getName(), name)); + } + return spec; + } + + 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())); + } + } + + @Override + public String toString() { + return mName; + } +} diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResValuesFile.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResValuesFile.java index 227dcb54..63b22a0c 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResValuesFile.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResValuesFile.java @@ -24,11 +24,11 @@ import java.util.Set; */ public class ResValuesFile { private final ResPackage mPackage; - private final ResType mType; - private final ResConfig mConfig; + private final ResTypeSpec mType; + private final ResType mConfig; private final Set mResources = new LinkedHashSet(); - public ResValuesFile(ResPackage pkg, ResType type, ResConfig config) { + public ResValuesFile(ResPackage pkg, ResTypeSpec type, ResType config) { this.mPackage = pkg; this.mType = type; this.mConfig = config; @@ -44,11 +44,11 @@ public class ResValuesFile { return mResources; } - public ResType getType() { + public ResTypeSpec getType() { return mType; } - public ResConfig getConfig() { + public ResType getConfig() { return mConfig; } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java index f30e7234..9e498ba4 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java @@ -44,7 +44,7 @@ public class ARSCDecoder { throws AndrolibException { try { ARSCDecoder decoder = new ARSCDecoder(arscStream, resTable, findFlagsOffsets, keepBroken); - ResPackage[] pkgs = decoder.readTable(); + ResPackage[] pkgs = decoder.readTableHeader(); return new ARSCData(pkgs, decoder.mFlagsOffsets == null ? null : decoder.mFlagsOffsets.toArray(new FlagsOffset[0]), resTable); @@ -66,7 +66,7 @@ public class ARSCDecoder { mKeepBroken = keepBroken; } - private ResPackage[] readTable() throws IOException, AndrolibException { + private ResPackage[] readTableHeader() throws IOException, AndrolibException { nextChunkCheckType(Header.TYPE_TABLE); int packageCount = mIn.readInt(); @@ -75,12 +75,12 @@ public class ARSCDecoder { nextChunk(); for (int i = 0; i < packageCount; i++) { - packages[i] = readPackage(); + packages[i] = readTablePackage(); } return packages; } - private ResPackage readPackage() throws IOException, AndrolibException { + private ResPackage readTablePackage() throws IOException, AndrolibException { checkChunkType(Header.TYPE_PACKAGE); int id = (byte) mIn.readInt(); @@ -96,10 +96,10 @@ public class ARSCDecoder { } String name = mIn.readNullEndedString(128, true); - /* typeStrings */mIn.skipInt(); - /* lastPublicType */mIn.skipInt(); - /* keyStrings */mIn.skipInt(); - /* lastPublicKey */mIn.skipInt(); + /* typeStrings */mIn.skipInt(); + /* lastPublicType */mIn.skipInt(); + /* keyStrings */mIn.skipInt(); + /* lastPublicKey */mIn.skipInt(); mTypeNames = StringBlock.read(mIn); mSpecNames = StringBlock.read(mIn); @@ -112,8 +112,8 @@ public class ARSCDecoder { readLibraryType(); } - while (mHeader.type == Header.TYPE_TYPE) { - readType(); + while (mHeader.type == Header.TYPE_SPEC_TYPE) { + readTableTypeSpec(); } return mPkg; @@ -132,13 +132,13 @@ public class ARSCDecoder { LOGGER.info(String.format("Decoding Shared Library (%s), pkgId: %d", packageName, packageId)); } - while(nextChunk().type == Header.TYPE_CONFIG) { - readConfig(); + while(nextChunk().type == Header.TYPE_TYPE) { + readTableTypeSpec(); } } - private ResType readType() throws AndrolibException, IOException { - checkChunkType(Header.TYPE_TYPE); + private ResTypeSpec readTableTypeSpec() throws AndrolibException, IOException { + checkChunkType(Header.TYPE_SPEC_TYPE); byte id = mIn.readByte(); mIn.skipBytes(3); int entryCount = mIn.readInt(); @@ -152,29 +152,30 @@ public class ARSCDecoder { /* flags */mIn.skipBytes(entryCount * 4); mResId = (0xff000000 & mResId) | id << 16; - mType = new ResType(mTypeNames.getString(id - 1), mResTable, mPkg); - mPkg.addType(mType); + mTypeSpec = new ResTypeSpec(mTypeNames.getString(id - 1), mResTable, mPkg); + mPkg.addType(mTypeSpec); - while (nextChunk().type == Header.TYPE_CONFIG) { - readConfig(); + while (nextChunk().type == Header.TYPE_TYPE) { + readTableType(); } addMissingResSpecs(); - return mType; + return mTypeSpec; } - private ResConfig readConfig() throws IOException, AndrolibException { - checkChunkType(Header.TYPE_CONFIG); - /* typeId */mIn.skipInt(); + private ResType readTableType() throws IOException, AndrolibException { + checkChunkType(Header.TYPE_TYPE); + /* typeId */mIn.skipBytes(1); + /* res0, res1 */mIn.skipBytes(3); int entryCount = mIn.readInt(); - /* entriesStart */mIn.skipInt(); + /* entriesStart */mIn.skipInt(); ResConfigFlags flags = readConfigFlags(); int[] entryOffsets = mIn.readIntArray(entryCount); if (flags.isInvalid) { - String resName = mType.getName() + flags.getQualifiers(); + String resName = mTypeSpec.getName() + flags.getQualifiers(); if (mKeepBroken) { LOGGER.warning("Invalid config flags detected: " + resName); } else { @@ -182,7 +183,7 @@ public class ARSCDecoder { } } - mConfig = flags.isInvalid && !mKeepBroken ? null : mPkg.getOrCreateConfig(flags); + mType = flags.isInvalid && !mKeepBroken ? null : mPkg.getOrCreateConfig(flags); for (int i = 0; i < entryOffsets.length; i++) { if (entryOffsets[i] != -1) { @@ -192,7 +193,7 @@ public class ARSCDecoder { } } - return mConfig; + return mType; } private void readEntry() throws IOException, AndrolibException { @@ -202,10 +203,10 @@ public class ARSCDecoder { ResValue value = (flags & ENTRY_FLAG_COMPLEX) == 0 ? readValue() : readComplexEntry(); - if (mType.isString() && value instanceof ResFileValue) { + if (mTypeSpec.isString() && value instanceof ResFileValue) { value = new ResStringValue(value.toString(), ((ResFileValue) value).getRawIntValue()); } - if (mConfig == null) { + if (mType == null) { return; } @@ -214,19 +215,18 @@ public class ARSCDecoder { if (mPkg.hasResSpec(resId)) { spec = mPkg.getResSpec(resId); } else { - spec = new ResResSpec(resId, mSpecNames.getString(specNamesId), mPkg, mType); + spec = new ResResSpec(resId, mSpecNames.getString(specNamesId), mPkg, mTypeSpec); mPkg.addResSpec(spec); - mType.addResSpec(spec); + mTypeSpec.addResSpec(spec); } - ResResource res = new ResResource(mConfig, spec, value); + ResResource res = new ResResource(mType, spec, value); - mConfig.addResource(res); + mType.addResource(res); spec.addResource(res); mPkg.addResource(res); } - private ResBagValue readComplexEntry() throws IOException, - AndrolibException { + private ResBagValue readComplexEntry() throws IOException, AndrolibException { int parent = mIn.readInt(); int count = mIn.readInt(); @@ -394,19 +394,19 @@ public class ARSCDecoder { continue; } - ResResSpec spec = new ResResSpec(new ResID(resId | i), String.format("APKTOOL_DUMMY_%04x", i), mPkg, mType); + ResResSpec spec = new ResResSpec(new ResID(resId | i), String.format("APKTOOL_DUMMY_%04x", i), mPkg, mTypeSpec); mPkg.addResSpec(spec); - mType.addResSpec(spec); + mTypeSpec.addResSpec(spec); - if (mConfig == null) { - mConfig = mPkg.getOrCreateConfig(new ResConfigFlags()); + if (mType == null) { + mType = mPkg.getOrCreateConfig(new ResConfigFlags()); } ResValue value = new ResBoolValue(false, 0, null); - ResResource res = new ResResource(mConfig, spec, value); + ResResource res = new ResResource(mType, spec, value); mPkg.addResource(res); - mConfig.addResource(res); + mType.addResource(res); spec.addResource(res); } } @@ -439,8 +439,8 @@ public class ARSCDecoder { private StringBlock mTypeNames; private StringBlock mSpecNames; private ResPackage mPkg; + private ResTypeSpec mTypeSpec; private ResType mType; - private ResConfig mConfig; private int mResId; private boolean[] mMissingResSpecs; @@ -468,8 +468,7 @@ public class ARSCDecoder { } public final static short TYPE_NONE = -1, TYPE_TABLE = 0x0002, - TYPE_PACKAGE = 0x0200, TYPE_TYPE = 0x0202, TYPE_LIBRARY = 0x0203, - TYPE_CONFIG = 0x0201; + TYPE_PACKAGE = 0x0200, TYPE_TYPE = 0x0201, TYPE_SPEC_TYPE = 0x0202, TYPE_LIBRARY = 0x0203; } public static class FlagsOffset { @@ -515,20 +514,15 @@ public class ARSCDecoder { } public int findPackageWithMostResSpecs() { - int count = -1; + int count = mPackages[0].getResSpecCount(); int id = 0; - // set starting point to package id 0. - count = mPackages[0].getResSpecCount(); - - // loop through packages looking for largest for (int i = 0; i < mPackages.length; i++) { if (mPackages[i].getResSpecCount() >= count) { count = mPackages[i].getResSpecCount(); id = i; } } - return id; }