use of org.robolectric.res.android.ResourceTypes.ResTable_type in project robolectric by robolectric.
the class CppAssetManager2 method FindEntry.
// Finds the best entry for `resid` from the set of ApkAssets. The entry can be a simple
// Res_value, or a complex map/bag type. If successful, it is available in `out_entry`.
// Returns kInvalidCookie on failure. Otherwise, the return value is the cookie associated with
// the ApkAssets in which the entry was found.
//
// `density_override` overrides the density of the current configuration when doing a search.
//
// When `stop_at_first_match` is true, the first match found is selected and the search
// terminates. This is useful for methods that just look up the name of a resource and don't
// care about the value. In this case, the value of `FindEntryResult::type_flags` is incomplete
// and should not be used.
//
// NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
// bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
// ApkAssetsCookie FindEntry(int resid, short density_override, boolean stop_at_first_match,
// LoadedArscEntry* out_entry, ResTable_config out_selected_config,
// int* out_flags);
private ApkAssetsCookie FindEntry(int resid, short density_override, boolean stop_at_first_match, final Ref<FindEntryResult> out_entry) {
ATRACE_CALL();
// Might use this if density_override != 0.
ResTable_config density_override_config;
// Select our configuration or generate a density override configuration.
ResTable_config desired_config = configuration_;
if (density_override != 0 && density_override != configuration_.density) {
density_override_config = configuration_;
density_override_config.density = density_override;
desired_config = density_override_config;
}
if (!is_valid_resid(resid)) {
System.err.println(String.format("Invalid ID 0x%08x.", resid));
return K_INVALID_COOKIE;
}
final int package_id = get_package_id(resid);
final int type_idx = (byte) (get_type_id(resid) - 1);
final int entry_idx = get_entry_id(resid);
final byte package_idx = package_ids_[package_id];
if (package_idx == (byte) 0xff) {
System.err.println(String.format("No package ID %02x found for ID 0x%08x.", package_id, resid));
return K_INVALID_COOKIE;
}
final PackageGroup package_group = package_groups_.get(package_idx);
final int package_count = package_group.packages_.size();
ApkAssetsCookie best_cookie = K_INVALID_COOKIE;
LoadedPackage best_package = null;
ResTable_type best_type = null;
ResTable_config best_config = null;
ResTable_config best_config_copy;
int best_offset = 0;
int type_flags = 0;
// If desired_config is the same as the set configuration, then we can use our filtered list
// and we don't need to match the configurations, since they already matched.
boolean use_fast_path = desired_config == configuration_;
for (int pi = 0; pi < package_count; pi++) {
ConfiguredPackage loaded_package_impl = package_group.packages_.get(pi);
LoadedPackage loaded_package = loaded_package_impl.loaded_package_;
ApkAssetsCookie cookie = package_group.cookies_.get(pi);
// If the type IDs are offset in this package, we need to take that into account when searching
// for a type.
TypeSpec type_spec = loaded_package.GetTypeSpecByTypeIndex(type_idx);
if (Util.UNLIKELY(type_spec == null)) {
continue;
}
int local_entry_idx = entry_idx;
// If there is an IDMAP supplied with this package, translate the entry ID.
if (type_spec.idmap_entries != null) {
if (!LoadedIdmap.Lookup(type_spec.idmap_entries, local_entry_idx, new Ref<>(local_entry_idx))) {
// There is no mapping, so the resource is not meant to be in this overlay package.
continue;
}
}
type_flags |= type_spec.GetFlagsForEntryIndex(local_entry_idx);
// If the package is an overlay, then even configurations that are the same MUST be chosen.
boolean package_is_overlay = loaded_package.IsOverlay();
FilteredConfigGroup filtered_group = loaded_package_impl.filtered_configs_.get(type_idx);
if (use_fast_path) {
List<ResTable_config> candidate_configs = filtered_group.configurations;
int type_count = candidate_configs.size();
for (int i = 0; i < type_count; i++) {
ResTable_config this_config = candidate_configs.get(i);
// configurations that do NOT match have been filtered-out.
if ((best_config == null || this_config.isBetterThan(best_config, desired_config)) || (package_is_overlay && this_config.compare(best_config) == 0)) {
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
ResTable_type type_chunk = filtered_group.types.get(i);
int offset = LoadedPackage.GetEntryOffset(type_chunk, local_entry_idx);
if (offset == ResTable_type.NO_ENTRY) {
continue;
}
best_cookie = cookie;
best_package = loaded_package;
best_type = type_chunk;
best_config = this_config;
best_offset = offset;
}
}
} else {
// for (auto iter = type_spec.types; iter != iter_end; ++iter) {
for (ResTable_type type : type_spec.types) {
ResTable_config this_config = ResTable_config.fromDtoH(type.config);
if (this_config.match(desired_config)) {
if ((best_config == null || this_config.isBetterThan(best_config, desired_config)) || (package_is_overlay && this_config.compare(best_config) == 0)) {
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
int offset = LoadedPackage.GetEntryOffset(type, local_entry_idx);
if (offset == ResTable_type.NO_ENTRY) {
continue;
}
best_cookie = cookie;
best_package = loaded_package;
best_type = type;
best_config_copy = this_config;
best_config = best_config_copy;
best_offset = offset;
}
}
}
}
}
if (Util.UNLIKELY(best_cookie.intValue() == kInvalidCookie)) {
return K_INVALID_COOKIE;
}
ResTable_entry best_entry = LoadedPackage.GetEntryFromOffset(best_type, best_offset);
if (Util.UNLIKELY(best_entry == null)) {
return K_INVALID_COOKIE;
}
FindEntryResult out_entry_ = new FindEntryResult();
out_entry_.entry = best_entry;
out_entry_.config = best_config;
out_entry_.type_flags = type_flags;
out_entry_.type_string_ref = new StringPoolRef(best_package.GetTypeStringPool(), best_type.id - 1);
out_entry_.entry_string_ref = new StringPoolRef(best_package.GetKeyStringPool(), best_entry.key.index);
out_entry_.dynamic_ref_table = package_group.dynamic_ref_table;
out_entry.set(out_entry_);
return best_cookie;
}
use of org.robolectric.res.android.ResourceTypes.ResTable_type in project robolectric by robolectric.
the class CppAssetManager2 method RebuildFilterList.
// Triggers the re-construction of lists of types that match the set configuration.
// This should always be called when mutating the AssetManager's configuration or ApkAssets set.
void RebuildFilterList() {
for (PackageGroup group : package_groups_) {
for (ConfiguredPackage impl : group.packages_) {
// // Destroy it.
// impl.filtered_configs_.~ByteBucketArray();
//
// // Re-create it.
// new (impl.filtered_configs_) ByteBucketArray<FilteredConfigGroup>();
impl.filtered_configs_ = new ByteBucketArray<FilteredConfigGroup>(new FilteredConfigGroup()) {
@Override
FilteredConfigGroup newInstance() {
return new FilteredConfigGroup();
}
};
// Create the filters here.
impl.loaded_package_.ForEachTypeSpec((TypeSpec spec, byte type_index) -> {
FilteredConfigGroup configGroup = impl.filtered_configs_.editItemAt(type_index);
// for (auto iter = spec->types; iter != iter_end; ++iter) {
for (ResTable_type iter : spec.types) {
ResTable_config this_config = ResTable_config.fromDtoH(iter.config);
if (this_config.match(configuration_)) {
configGroup.configurations.add(this_config);
configGroup.types.add(iter);
}
}
});
}
}
}
use of org.robolectric.res.android.ResourceTypes.ResTable_type in project robolectric by robolectric.
the class ResTable method findEntry.
int findEntry(PackageGroup group, int typeIndex, String name, Ref<Integer> outTypeSpecFlags) {
List<Type> typeList = getOrDefault(group.types, typeIndex, Collections.emptyList());
for (Type type : typeList) {
int ei = type._package_.keyStrings.indexOfString(name);
if (ei < 0) {
continue;
}
for (ResTable_type resTableType : type.configs) {
int entryIndex = resTableType.findEntryByResName(ei);
if (entryIndex >= 0) {
int resId = Res_MAKEID(group.id - 1, typeIndex, entryIndex);
if (outTypeSpecFlags != null) {
Entry result = new Entry();
if (getEntry(group, typeIndex, entryIndex, null, result) != NO_ERROR) {
ALOGW("Failed to find spec flags for 0x%08x", resId);
return 0;
}
outTypeSpecFlags.set(result.specFlags);
}
return resId;
}
}
}
return 0;
}
use of org.robolectric.res.android.ResourceTypes.ResTable_type in project robolectric by robolectric.
the class ResTable method getEntry.
private int getEntry(final PackageGroup packageGroup, int typeIndex, int entryIndex, final ResTable_config config, Entry outEntry) {
final List<Type> typeList = getOrDefault(packageGroup.types, typeIndex, Collections.emptyList());
if (typeList.isEmpty()) {
ALOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex);
return BAD_TYPE;
}
ResTable_type bestType = null;
int bestOffset = ResTable_type.NO_ENTRY;
Package bestPackage = null;
int specFlags = 0;
byte actualTypeIndex = (byte) typeIndex;
ResTable_config bestConfig = null;
// memset(&bestConfig, 0, sizeof(bestConfig));
// Iterate over the Types of each package.
final int typeCount = typeList.size();
for (int i = 0; i < typeCount; i++) {
final Type typeSpec = typeList.get(i);
int realEntryIndex = entryIndex;
int realTypeIndex = typeIndex;
boolean currentTypeIsOverlay = false;
// ID to package resource ID.
if (typeSpec.idmapEntries.hasEntries()) {
final Ref<Short> overlayEntryIndex = new Ref<>((short) 0);
if (typeSpec.idmapEntries.lookup(entryIndex, overlayEntryIndex) != NO_ERROR) {
// No such mapping exists
continue;
}
realEntryIndex = overlayEntryIndex.get();
realTypeIndex = typeSpec.idmapEntries.overlayTypeId() - 1;
currentTypeIsOverlay = true;
}
// entryCount do not need to match.
if (((int) realEntryIndex) >= typeSpec.entryCount) {
ALOGW("For resource 0x%08x, entry index(%d) is beyond type entryCount(%d)", Res_MAKEID(packageGroup.id - 1, typeIndex, entryIndex), entryIndex, ((int) typeSpec.entryCount));
// resources in the 'android' package (old bug in AAPT).
continue;
}
// Aggregate all the flags for each package that defines this entry.
if (typeSpec.typeSpecFlags != null) {
specFlags |= dtohl(typeSpec.typeSpecFlags[realEntryIndex]);
} else {
specFlags = -1;
}
List<ResTable_type> candidateConfigs = typeSpec.configs;
// List<ResTable_type> filteredConfigs;
// if (isTruthy(config) && Objects.equals(mParams, config)) {
// // Grab the lock first so we can safely get the current filtered list.
// synchronized (mFilteredConfigLock) {
// // This configuration is equal to the one we have previously cached for,
// // so use the filtered configs.
//
// final TypeCacheEntry cacheEntry = packageGroup.typeCacheEntries.get(typeIndex);
// if (i < cacheEntry.filteredConfigs.size()) {
// if (isTruthy(cacheEntry.filteredConfigs.get(i))) {
// // Grab a reference to the shared_ptr so it doesn't get destroyed while
// // going through this list.
// filteredConfigs = cacheEntry.filteredConfigs.get(i);
//
// // Use this filtered list.
// candidateConfigs = filteredConfigs;
// }
// }
// }
// }
final int numConfigs = candidateConfigs.size();
for (int c = 0; c < numConfigs; c++) {
final ResTable_type thisType = candidateConfigs.get(c);
if (thisType == NULL) {
continue;
}
final ResTable_config thisConfig;
// thisConfig.copyFromDtoH(thisType.config);
thisConfig = ResTable_config.fromDtoH(thisType.config);
// Check to make sure this one is valid for the current parameters.
if (config != NULL && !thisConfig.match(config)) {
continue;
}
// const uint32_t* const eindex = reinterpret_cast<const uint32_t*>(
// reinterpret_cast<const uint8_t*>(thisType) + dtohs(thisType->header.headerSize));
final int eindex = thisType.myOffset() + dtohs(thisType.header.headerSize);
int thisOffset;
// Check if there is the desired entry in this type.
if (isTruthy(thisType.flags & ResTable_type.FLAG_SPARSE)) {
// This is encoded as a sparse map, so perform a binary search.
final ByteBuffer buf = thisType.myBuf();
ResTable_sparseTypeEntry sparseIndices = new ResTable_sparseTypeEntry(buf, eindex);
ResTable_sparseTypeEntry result = lower_bound(sparseIndices, new ResTable_sparseTypeEntry(buf, sparseIndices.myOffset() + dtohl(thisType.entryCount)), new ResTable_sparseTypeEntry(buf, realEntryIndex), (a, b) -> dtohs(a.idxOrOffset) < dtohs(b.idxOrOffset));
// || dtohs(result.idx) != realEntryIndex) {
if (result.myOffset() == sparseIndices.myOffset() + dtohl(thisType.entryCount) || dtohs(result.idxOrOffset) != realEntryIndex) {
// No entry found.
continue;
}
// Extract the offset from the entry. Each offset must be a multiple of 4
// so we store it as the real offset divided by 4.
// thisOffset = dtohs(result->offset) * 4u;
thisOffset = dtohs(result.idxOrOffset) * 4;
} else {
if (realEntryIndex >= dtohl(thisType.entryCount)) {
// Entry does not exist.
continue;
}
// thisOffset = dtohl(eindex[realEntryIndex]);
thisOffset = thisType.entryOffset(realEntryIndex);
}
if (thisOffset == ResTable_type.NO_ENTRY) {
// There is no entry for this index and configuration.
continue;
}
if (bestType != NULL) {
// about to those we least care about.
if (!thisConfig.isBetterThan(bestConfig, config)) {
if (!currentTypeIsOverlay || thisConfig.compare(bestConfig) != 0) {
continue;
}
}
}
bestType = thisType;
bestOffset = thisOffset;
bestConfig = thisConfig;
bestPackage = typeSpec._package_;
actualTypeIndex = (byte) realTypeIndex;
// If no config was specified, any type will do, so skip
if (config == NULL) {
break;
}
}
}
if (bestType == NULL) {
return BAD_INDEX;
}
bestOffset += dtohl(bestType.entriesStart);
// if (bestOffset > (dtohl(bestType->header.size)-sizeof(ResTable_entry))) {
if (bestOffset > (dtohl(bestType.header.size) - ResTable_entry.SIZEOF)) {
ALOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x", bestOffset, dtohl(bestType.header.size));
return BAD_TYPE;
}
if ((bestOffset & 0x3) != 0) {
ALOGW("ResTable_entry at 0x%x is not on an integer boundary", bestOffset);
return BAD_TYPE;
}
// const ResTable_entry* const entry = reinterpret_cast<const ResTable_entry*>(
// reinterpret_cast<const uint8_t*>(bestType) + bestOffset);
final ResTable_entry entry = new ResTable_entry(bestType.myBuf(), bestType.myOffset() + bestOffset);
if (dtohs(entry.size) < ResTable_entry.SIZEOF) {
ALOGW("ResTable_entry size 0x%x is too small", dtohs(entry.size));
return BAD_TYPE;
}
if (outEntry != null) {
outEntry.entry = entry;
outEntry.config = bestConfig;
outEntry.type = bestType;
outEntry.specFlags = specFlags;
outEntry._package_ = bestPackage;
outEntry.typeStr = new StringPoolRef(bestPackage.typeStrings, actualTypeIndex - bestPackage.typeIdOffset);
outEntry.keyStr = new StringPoolRef(bestPackage.keyStrings, dtohl(entry.key.index));
}
return NO_ERROR;
}
use of org.robolectric.res.android.ResourceTypes.ResTable_type in project robolectric by robolectric.
the class ResTable method parsePackage.
int parsePackage(ResTable_package pkg, Header header, boolean appAsLib, boolean isSystemAsset) {
int base = pkg.myOffset();
int err = validate_chunk(pkg.header, ResTable_package.SIZEOF - 4, /*sizeof(pkg.typeIdOffset)*/
header.dataEnd, "ResTable_package");
if (err != NO_ERROR) {
return (mError = err);
}
final int pkgSize = dtohl(pkg.header.size);
if (dtohl(pkg.typeStrings) >= pkgSize) {
ALOGW("ResTable_package type strings at 0x%x are past chunk size 0x%x.", dtohl(pkg.typeStrings), pkgSize);
return (mError = BAD_TYPE);
}
if ((dtohl(pkg.typeStrings) & 0x3) != 0) {
ALOGW("ResTable_package type strings at 0x%x is not on an integer boundary.", dtohl(pkg.typeStrings));
return (mError = BAD_TYPE);
}
if (dtohl(pkg.keyStrings) >= pkgSize) {
ALOGW("ResTable_package key strings at 0x%x are past chunk size 0x%x.", dtohl(pkg.keyStrings), pkgSize);
return (mError = BAD_TYPE);
}
if ((dtohl(pkg.keyStrings) & 0x3) != 0) {
ALOGW("ResTable_package key strings at 0x%x is not on an integer boundary.", dtohl(pkg.keyStrings));
return (mError = BAD_TYPE);
}
int id = dtohl(pkg.id);
final Map<Byte, IdmapEntries> idmapEntries = new HashMap<>();
if (header.resourceIDMap != NULL) {
// byte targetPackageId = 0;
// int err = parseIdmap(header.resourceIDMap, header.resourceIDMapSize, &targetPackageId, &idmapEntries);
// if (err != NO_ERROR) {
// ALOGW("Overlay is broken");
// return (mError=err);
// }
// id = targetPackageId;
}
boolean isDynamic = false;
if (id >= 256) {
// LOG_ALWAYS_FATAL("Package id out of range");
throw new IllegalStateException("Package id out of range");
// return NO_ERROR;
} else if (id == 0 || (id == 0x7f && appAsLib) || isSystemAsset) {
// This is a library or a system asset, so assign an ID
id = mNextPackageId++;
isDynamic = true;
}
PackageGroup group = null;
Package _package = new Package(this, header, pkg);
if (_package == NULL) {
return (mError = NO_MEMORY);
}
// err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
// header->dataEnd-(base+dtohl(pkg->typeStrings)));
err = _package.typeStrings.setTo(pkg.myBuf(), base + dtohl(pkg.typeStrings), header.dataEnd - (base + dtohl(pkg.typeStrings)), false);
if (err != NO_ERROR) {
// delete _package;
return (mError = err);
}
// err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
// header->dataEnd-(base+dtohl(pkg->keyStrings)));
err = _package.keyStrings.setTo(pkg.myBuf(), base + dtohl(pkg.keyStrings), header.dataEnd - (base + dtohl(pkg.keyStrings)), false);
if (err != NO_ERROR) {
// delete _package;
return (mError = err);
}
int idx = mPackageMap[id];
if (idx == 0) {
idx = mPackageGroups.size() + 1;
// char[] tmpName = new char[pkg.name.length /*sizeof(pkg.name)/sizeof(pkg.name[0])*/];
// strcpy16_dtoh(tmpName, pkg.name, sizeof(pkg.name)/sizeof(pkg.name[0]));
group = new PackageGroup(this, new String(pkg.name), id, appAsLib, isSystemAsset, isDynamic);
if (group == NULL) {
// delete _package;
return (mError = NO_MEMORY);
}
mPackageGroups.put(group.id, group);
// if (err < NO_ERROR) {
// return (mError=err);
// }
mPackageMap[id] = (byte) idx;
// for (int i = 0; i < N; i++) {
for (PackageGroup packageGroup : mPackageGroups.values()) {
packageGroup.dynamicRefTable.addMapping(group.name, (byte) group.id);
}
} else {
group = mPackageGroups.get(idx - 1);
if (group == NULL) {
return (mError = UNKNOWN_ERROR);
}
}
group.packages.add(_package);
// if (err < NO_ERROR) {
// return (mError=err);
// }
// Iterate through all chunks.
ResChunk_header chunk = new ResChunk_header(pkg.myBuf(), pkg.myOffset() + dtohs(pkg.header.headerSize));
// const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
final int endPos = (pkg.myOffset()) + pkg.header.size;
// ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
while (chunk != null && (chunk.myOffset()) <= (endPos - ResChunk_header.SIZEOF) && (chunk.myOffset()) <= (endPos - dtohl(chunk.size))) {
if (kDebugTableNoisy) {
ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%s\n", dtohs(chunk.type), dtohs(chunk.headerSize), dtohl(chunk.size), ((chunk.myOffset()) - (header.header.myOffset())));
}
final int csize = dtohl(chunk.size);
final short ctype = dtohs(chunk.type);
if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
final ResTable_typeSpec typeSpec = new ResTable_typeSpec(chunk.myBuf(), chunk.myOffset());
err = validate_chunk(typeSpec.header, ResTable_typeSpec.SIZEOF, endPos, "ResTable_typeSpec");
if (err != NO_ERROR) {
return (mError = err);
}
final int typeSpecSize = dtohl(typeSpec.header.size);
final int newEntryCount = dtohl(typeSpec.entryCount);
if (kDebugLoadTableNoisy) {
ALOGI("TypeSpec off %s: type=0x%x, headerSize=0x%x, size=%s\n", (base - chunk.myOffset()), dtohs(typeSpec.header.type), dtohs(typeSpec.header.headerSize), typeSpecSize);
}
// look for block overrun or int overflow when multiplying by 4
if ((dtohl(typeSpec.entryCount) > (Integer.MAX_VALUE / 4) || dtohs(typeSpec.header.headerSize) + (4 * /*sizeof(int)*/
newEntryCount) > typeSpecSize)) {
ALOGW("ResTable_typeSpec entry index to %s extends beyond chunk end %s.", (dtohs(typeSpec.header.headerSize) + (4 * /*sizeof(int)*/
newEntryCount)), typeSpecSize);
return (mError = BAD_TYPE);
}
if (typeSpec.id == 0) {
ALOGW("ResTable_type has an id of 0.");
return (mError = BAD_TYPE);
}
if (newEntryCount > 0) {
boolean addToType = true;
byte typeIndex = (byte) (typeSpec.id - 1);
IdmapEntries idmapEntry = idmapEntries.get(typeSpec.id);
if (idmapEntry != null) {
typeIndex = (byte) (idmapEntry.targetTypeId() - 1);
} else if (header.resourceIDMap != NULL) {
// This is an overlay, but the types in this overlay are not
// overlaying anything according to the idmap. We can skip these
// as they will otherwise conflict with the other resources in the package
// without a mapping.
addToType = false;
}
if (addToType) {
List<Type> typeList = computeIfAbsent(group.types, (int) typeIndex, k -> new ArrayList<>());
if (!typeList.isEmpty()) {
final Type existingType = typeList.get(0);
if (existingType.entryCount != newEntryCount && idmapEntry == null) {
ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d", (int) newEntryCount, (int) existingType.entryCount);
// We should normally abort here, but some legacy apps declare
// resources in the 'android' package (old bug in AAPT).
}
}
Type t = new Type(header, _package, newEntryCount);
t.typeSpec = typeSpec;
t.typeSpecFlags = typeSpec.getSpecFlags();
if (idmapEntry != null) {
t.idmapEntries = idmapEntry;
}
typeList.add(t);
group.largestTypeId = max(group.largestTypeId, typeSpec.id);
}
} else {
ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec.id);
}
} else if (ctype == RES_TABLE_TYPE_TYPE) {
ResTable_type type = new ResTable_type(chunk.myBuf(), chunk.myOffset());
err = validate_chunk(type.header, ResTable_type.SIZEOF_WITHOUT_CONFIG + /*-sizeof(ResTable_config)*/
4, endPos, "ResTable_type");
if (err != NO_ERROR) {
return (mError = err);
}
final int typeSize = dtohl(type.header.size);
final int newEntryCount = dtohl(type.entryCount);
if (kDebugLoadTableNoisy) {
System.out.println(String.format("Type off 0x%x: type=0x%x, headerSize=0x%x, size=%d\n", base - chunk.myOffset(), dtohs(type.header.type), dtohs(type.header.headerSize), typeSize));
}
if (dtohs(type.header.headerSize) + (4 * /*sizeof(int)*/
newEntryCount) > typeSize) {
ALOGW("ResTable_type entry index to %s extends beyond chunk end 0x%x.", (dtohs(type.header.headerSize) + (4 * /*sizeof(int)*/
newEntryCount)), typeSize);
return (mError = BAD_TYPE);
}
if (newEntryCount != 0 && dtohl(type.entriesStart) > (typeSize - ResTable_entry.SIZEOF)) {
ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.", dtohl(type.entriesStart), typeSize);
return (mError = BAD_TYPE);
}
if (type.id == 0) {
ALOGW("ResTable_type has an id of 0.");
return (mError = BAD_TYPE);
}
if (newEntryCount > 0) {
boolean addToType = true;
byte typeIndex = (byte) (type.id - 1);
IdmapEntries idmapEntry = idmapEntries.get(type.id);
if (idmapEntry != null) {
typeIndex = (byte) (idmapEntry.targetTypeId() - 1);
} else if (header.resourceIDMap != NULL) {
// This is an overlay, but the types in this overlay are not
// overlaying anything according to the idmap. We can skip these
// as they will otherwise conflict with the other resources in the package
// without a mapping.
addToType = false;
}
if (addToType) {
List<Type> typeList = getOrDefault(group.types, (int) typeIndex, Collections.emptyList());
if (typeList.isEmpty()) {
ALOGE("No TypeSpec for type %d", type.id);
return (mError = BAD_TYPE);
}
Type t = typeList.get(typeList.size() - 1);
if (newEntryCount != t.entryCount) {
ALOGE("ResTable_type entry count inconsistent: given %d, previously %d", (int) newEntryCount, (int) t.entryCount);
return (mError = BAD_TYPE);
}
if (t._package_ != _package) {
ALOGE("No TypeSpec for type %d", type.id);
return (mError = BAD_TYPE);
}
t.configs.add(type);
if (kDebugTableGetEntry) {
ResTable_config thisConfig = ResTable_config.fromDtoH(type.config);
ALOGI("Adding config to type %d: %s\n", type.id, thisConfig.toString());
}
}
} else {
ALOGV("Skipping empty ResTable_type for type %d", type.id);
}
} else if (ctype == RES_TABLE_LIBRARY_TYPE) {
if (group.dynamicRefTable.entries().isEmpty()) {
throw new UnsupportedOperationException("libraries not supported yet");
// const ResTable_lib_header* lib = (const ResTable_lib_header*) chunk;
// status_t err = validate_chunk(&lib->header, sizeof(*lib),
// endPos, "ResTable_lib_header");
// if (err != NO_ERROR) {
// return (mError=err);
// }
//
// err = group->dynamicRefTable.load(lib);
// if (err != NO_ERROR) {
// return (mError=err);
// }
//
// // Fill in the reference table with the entries we already know about.
// size_t N = mPackageGroups.size();
// for (size_t i = 0; i < N; i++) {
// group.dynamicRefTable.addMapping(mPackageGroups[i].name, mPackageGroups[i].id);
// }
} else {
ALOGW("Found multiple library tables, ignoring...");
}
} else {
err = validate_chunk(chunk, ResChunk_header.SIZEOF, endPos, "ResTable_package:unknown");
if (err != NO_ERROR) {
return (mError = err);
}
}
chunk = chunk.myOffset() + csize < endPos ? new ResChunk_header(chunk.myBuf(), chunk.myOffset() + csize) : null;
}
return NO_ERROR;
}
Aggregations