- Moves Config --> Type
 - Moves Type -> TypeSpec
 - ResType -> ResTypeSpec
 - ResConfig -> ResType

 This is to match AOSP and ease the transitions/updates of new AOSP drops
This commit is contained in:
Connor Tumbleson 2015-12-07 20:48:57 -06:00
parent 1e5dc3006e
commit 6c4167fba4
8 changed files with 173 additions and 179 deletions

View File

@ -1,72 +0,0 @@
/**
* Copyright 2014 Ryszard Wiśniewski <brut.alll@gmail.com>
*
* 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 <brut.alll@gmail.com>
*/
public class ResConfig {
private final ResConfigFlags mFlags;
private final Map<ResResSpec, ResResource> mResources = new LinkedHashMap<ResResSpec, ResResource>();
public ResConfig(ResConfigFlags flags) {
this.mFlags = flags;
}
public Set<ResResource> listResources() {
return new LinkedHashSet<ResResource>(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<ResResSpec> 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();
}
}

View File

@ -33,8 +33,8 @@ public class ResPackage {
private final int mId;
private final String mName;
private final Map<ResID, ResResSpec> mResSpecs = new LinkedHashMap<ResID, ResResSpec>();
private final Map<ResConfigFlags, ResConfig> mConfigs = new LinkedHashMap<ResConfigFlags, ResConfig>();
private final Map<String, ResType> mTypes = new LinkedHashMap<String, ResType>();
private final Map<ResConfigFlags, ResType> mConfigs = new LinkedHashMap<ResConfigFlags, ResType>();
private final Map<String, ResTypeSpec> mTypes = new LinkedHashMap<String, ResTypeSpec>();
private final Set<ResID> mSynthesizedRes = new HashSet<ResID>();
private ResValueFactory mValueFactory;
@ -61,16 +61,16 @@ public class ResPackage {
return spec;
}
public List<ResConfig> getConfigs() {
return new ArrayList<ResConfig>(mConfigs.values());
public List<ResType> getConfigs() {
return new ArrayList<ResType>(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<ResType> listTypes() {
return new ArrayList<ResType>(mTypes.values());
public List<ResTypeSpec> listTypes() {
return new ArrayList<ResTypeSpec>(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<ResValuesFile> listValuesFiles() {
Map<Duo<ResType, ResConfig>, ResValuesFile> ret = new HashMap<Duo<ResType, ResConfig>, ResValuesFile>();
Map<Duo<ResTypeSpec, ResType>, ResValuesFile> ret = new HashMap<Duo<ResTypeSpec, ResType>, 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<ResType, ResConfig> key = new Duo<ResType, ResConfig>(
ResTypeSpec type = res.getResSpec().getType();
ResType config = res.getConfig();
Duo<ResTypeSpec, ResType> key = new Duo<ResTypeSpec, ResType>(
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 {

View File

@ -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<ResConfigFlags, ResResource> mResources = new LinkedHashMap<ResConfigFlags, ResResource>();
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<ResResource>(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;
}

View File

@ -23,11 +23,11 @@ import brut.androlib.res.data.value.ResValue;
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
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;
}

View File

@ -23,49 +23,50 @@ import java.util.*;
/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
public final class ResType {
private final String mName;
private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<String, ResResSpec>();
public class ResType {
private final ResConfigFlags mFlags;
private final Map<ResResSpec, ResResource> mResources = new LinkedHashMap<ResResSpec, ResResource>();
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<ResResource> listResources() {
return new LinkedHashSet<ResResource>(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<ResResSpec> listResSpecs() {
return new LinkedHashSet<ResResSpec>(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();
}
}

View File

@ -0,0 +1,71 @@
/**
* Copyright 2014 Ryszard Wiśniewski <brut.alll@gmail.com>
*
* 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 <brut.alll@gmail.com>
*/
public final class ResTypeSpec {
private final String mName;
private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<String, ResResSpec>();
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<ResResSpec> listResSpecs() {
return new LinkedHashSet<ResResSpec>(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;
}
}

View File

@ -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<ResResource> mResources = new LinkedHashSet<ResResource>();
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;
}

View File

@ -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;
}