use of org.robolectric.res.android.ResourceTypes.ResTable_typeSpec 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