use of org.robolectric.res.android.ResourceTypes.ResChunk_header in project robolectric by robolectric.
the class ResTable method addInternal.
// status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
// bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset=false);
int addInternal(byte[] data, int dataSize, final Object idmapData, int idmapDataSize, boolean appAsLib, final int cookie, boolean copyData, boolean isSystemAsset) {
if (!isTruthy(data)) {
return NO_ERROR;
}
if (dataSize < ResTable_header.SIZEOF) {
ALOGE("Invalid data. Size(%d) is smaller than a ResTable_header(%d).", (int) dataSize, (int) ResTable_header.SIZEOF);
return UNKNOWN_ERROR;
}
Header header = new Header(this);
header.index = mHeaders.size();
header.cookie = cookie;
if (idmapData != NULL) {
header.resourceIDMap = new int[idmapDataSize / 4];
if (header.resourceIDMap == NULL) {
// delete header;
return (mError = NO_MEMORY);
}
// memcpy(header.resourceIDMap, idmapData, idmapDataSize);
// header.resourceIDMapSize = idmapDataSize;
}
mHeaders.add(header);
final boolean notDeviceEndian = htods((short) 0xf0) != 0xf0;
if (kDebugLoadTableNoisy) {
ALOGV("Adding resources to ResTable: data=%s, size=0x%x, cookie=%d, copy=%d " + "idmap=%s\n", data, dataSize, cookie, copyData, idmapData);
}
if (copyData || notDeviceEndian) {
// malloc(dataSize);
header.ownedData = data;
if (header.ownedData == NULL) {
return (mError = NO_MEMORY);
}
// memcpy(header.ownedData, data, dataSize);
data = header.ownedData;
}
ByteBuffer buf = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
// header->header = (const ResTable_header*)data;
header.header = new ResTable_header(buf, 0);
header.size = dtohl(header.header.header.size);
if (kDebugLoadTableSuperNoisy) {
ALOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header.size, dtohl(header.header.header.size), header.header.header.size);
}
if (kDebugLoadTableNoisy) {
ALOGV("Loading ResTable @%s:\n", header.header);
}
if (dtohs(header.header.header.headerSize) > header.size || header.size > dataSize) {
ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n", (int) dtohs(header.header.header.headerSize), (int) header.size, (int) dataSize);
return (mError = BAD_TYPE);
}
if (((dtohs(header.header.header.headerSize) | header.size) & 0x3) != 0) {
ALOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n", (int) dtohs(header.header.header.headerSize), (int) header.size);
return (mError = BAD_TYPE);
}
// header->dataEnd = ((const uint8_t*)header->header) + header->size;
header.dataEnd = header.size;
// Iterate through all chunks.
int curPackage = 0;
// const ResChunk_header* chunk =
// (const ResChunk_header*)(((const uint8_t*)header->header)
// + dtohs(header->header->header.headerSize));
ResChunk_header chunk = new ResChunk_header(buf, dtohs(header.header.header.headerSize));
while (chunk != null && (chunk.myOffset()) <= (header.dataEnd - ResChunk_header.SIZEOF) && (chunk.myOffset()) <= (header.dataEnd - dtohl(chunk.size))) {
int err = validate_chunk(chunk, ResChunk_header.SIZEOF, header.dataEnd, "ResTable");
if (err != NO_ERROR) {
return (mError = err);
}
if (kDebugTableNoisy) {
ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%s\n", dtohs(chunk.type), dtohs(chunk.headerSize), dtohl(chunk.size), (Object) ((chunk.myOffset()) - (header.header.myOffset())));
}
final int csize = dtohl(chunk.size);
final int ctype = dtohs(chunk.type);
if (ctype == RES_STRING_POOL_TYPE) {
if (header.values.getError() != NO_ERROR) {
// Only use the first string chunk; ignore any others that
// may appear.
err = header.values.setTo(chunk.myBuf(), chunk.myOffset(), csize, false);
if (err != NO_ERROR) {
return (mError = err);
}
} else {
ALOGW("Multiple string chunks found in resource table.");
}
} else if (ctype == RES_TABLE_PACKAGE_TYPE) {
if (curPackage >= dtohl(header.header.packageCount)) {
ALOGW("More package chunks were found than the %d declared in the header.", dtohl(header.header.packageCount));
return (mError = BAD_TYPE);
}
if (parsePackage(new ResTable_package(chunk.myBuf(), chunk.myOffset()), header, appAsLib, isSystemAsset) != NO_ERROR) {
return mError;
}
curPackage++;
} else {
ALOGW("Unknown chunk type 0x%x in table at 0x%x.\n", ctype, (chunk.myOffset()) - (header.header.myOffset()));
}
chunk = chunk.myOffset() + csize < header.dataEnd ? new ResChunk_header(chunk.myBuf(), chunk.myOffset() + csize) : null;
}
if (curPackage < dtohl(header.header.packageCount)) {
ALOGW("Fewer package chunks (%d) were found than the %d declared in the header.", (int) curPackage, dtohl(header.header.packageCount));
return (mError = BAD_TYPE);
}
mError = header.values.getError();
if (mError != NO_ERROR) {
ALOGW("No string values found in resource table!");
}
if (kDebugTableNoisy) {
ALOGV("Returning from add with mError=%d\n", mError);
}
return mError;
}
use of org.robolectric.res.android.ResourceTypes.ResChunk_header in project robolectric by robolectric.
the class ResStringPool method setTo.
// status_t setTo(const void* data, size_t size, bool copyData=false);
public int setTo(ByteBuffer buf, int offset, int size, boolean copyData) {
if (!isTruthy(buf) || !isTruthy(size)) {
return (mError = BAD_TYPE);
}
uninit();
// The chunk must be at least the size of the string pool header.
if (size < ResStringPool_header.SIZEOF) {
ALOGW("Bad string block: data size %zu is too small to be a string block", size);
return (mError = BAD_TYPE);
}
// `data + size` is safe because the source of `size` comes from the kernel/filesystem.
if (validate_chunk(new ResChunk_header(buf, offset), ResStringPool_header.SIZEOF, size, "ResStringPool_header") != NO_ERROR) {
ALOGW("Bad string block: malformed block dimensions");
return (mError = BAD_TYPE);
}
// final boolean notDeviceEndian = htods((short) 0xf0) != 0xf0;
//
// if (copyData || notDeviceEndian) {
// mOwnedData = data;
// if (mOwnedData == null) {
// return (mError=NO_MEMORY);
// }
// // memcpy(mOwnedData, data, size);
// data = mOwnedData;
// }
// The size has been checked, so it is safe to read the data in the ResStringPool_header
// data structure.
mHeader = new ResStringPool_header(buf, offset);
if (mHeader.header.headerSize > mHeader.header.size || mHeader.header.size > size) {
ALOGW("Bad string block: header size %d or total size %d is larger than data size %d\n", (int) mHeader.header.headerSize, (int) mHeader.header.size, (int) size);
return (mError = BAD_TYPE);
}
mSize = mHeader.header.size;
mEntries = new IntArray(mHeader.myBuf(), mHeader.myOffset() + mHeader.header.headerSize);
if (mHeader.stringCount > 0) {
if (// uint32 overflow?
(mHeader.stringCount * 4 < /*sizeof(uint32_t)*/
mHeader.stringCount) || (mHeader.header.headerSize + (mHeader.stringCount * 4)) > size) {
ALOGW("Bad string block: entry of %d items extends past data size %d\n", (int) (mHeader.header.headerSize + (mHeader.stringCount * 4)), (int) size);
return (mError = BAD_TYPE);
}
int charSize;
if (isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG)) {
charSize = 1;
} else {
charSize = 2;
}
// (2 bytes length, null terminator).
if (mHeader.stringsStart >= (mSize - 2)) {
ALOGW("Bad string block: string pool starts at %d, after total size %d\n", (int) mHeader.stringsStart, (int) mHeader.header.size);
return (mError = BAD_TYPE);
}
mStrings = mHeader.stringsStart;
if (mHeader.styleCount == 0) {
mStringPoolSize = (mSize - mHeader.stringsStart) / charSize;
} else {
// check invariant: styles starts before end of data
if (mHeader.stylesStart >= (mSize - 2)) {
ALOGW("Bad style block: style block starts at %d past data size of %d\n", (int) mHeader.stylesStart, (int) mHeader.header.size);
return (mError = BAD_TYPE);
}
// check invariant: styles follow the strings
if (mHeader.stylesStart <= mHeader.stringsStart) {
ALOGW("Bad style block: style block starts at %d, before strings at %d\n", (int) mHeader.stylesStart, (int) mHeader.stringsStart);
return (mError = BAD_TYPE);
}
mStringPoolSize = (mHeader.stylesStart - mHeader.stringsStart) / charSize;
}
// check invariant: stringCount > 0 requires a string pool to exist
if (mStringPoolSize == 0) {
ALOGW("Bad string block: stringCount is %d but pool size is 0\n", (int) mHeader.stringCount);
return (mError = BAD_TYPE);
}
if ((isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG) && (mHeader.getByte(mStrings + mStringPoolSize - 1) != 0)) || (!isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG) && (mHeader.getShort(mStrings + mStringPoolSize * 2 - 2) != 0))) {
ALOGW("Bad string block: last string is not 0-terminated\n");
return (mError = BAD_TYPE);
}
} else {
mStrings = -1;
mStringPoolSize = 0;
}
if (mHeader.styleCount > 0) {
mEntryStyles = new IntArray(mEntries.myBuf(), mEntries.myOffset() + mHeader.stringCount * SIZEOF_INT);
// invariant: integer overflow in calculating mEntryStyles
if (mEntryStyles.myOffset() < mEntries.myOffset()) {
ALOGW("Bad string block: integer overflow finding styles\n");
return (mError = BAD_TYPE);
}
// if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
if ((mEntryStyles.myOffset() - mHeader.myOffset()) > (int) size) {
ALOGW("Bad string block: entry of %d styles extends past data size %d\n", (int) (mEntryStyles.myOffset()), (int) size);
return (mError = BAD_TYPE);
}
mStyles = mHeader.stylesStart;
if (mHeader.stylesStart >= mHeader.header.size) {
ALOGW("Bad string block: style pool starts %d, after total size %d\n", (int) mHeader.stylesStart, (int) mHeader.header.size);
return (mError = BAD_TYPE);
}
mStylePoolSize = (mHeader.header.size - mHeader.stylesStart);
// if (notDeviceEndian) {
// size_t i;
// uint32_t* e = final_cast<uint32_t*>(mEntryStyles);
// for (i=0; i<mHeader.styleCount; i++) {
// e[i] = dtohl(mEntryStyles[i]);
// }
// uint32_t* s = final_cast<uint32_t*>(mStyles);
// for (i=0; i<mStylePoolSize; i++) {
// s[i] = dtohl(mStyles[i]);
// }
// }
// final ResStringPool_span endSpan = {
// { htodl(ResStringPool_span.END) },
// htodl(ResStringPool_span.END), htodl(ResStringPool_span.END)
// };
// if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))],
// &endSpan, sizeof(endSpan)) != 0) {
ResStringPool_span endSpan = new ResStringPool_span(buf, mHeader.myOffset() + mStyles + (mStylePoolSize - ResStringPool_span.SIZEOF));
if (!endSpan.isEnd()) {
ALOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
return (mError = BAD_TYPE);
}
} else {
mEntryStyles = null;
mStyles = 0;
mStylePoolSize = 0;
}
return (mError = NO_ERROR);
}
use of org.robolectric.res.android.ResourceTypes.ResChunk_header 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;
}
use of org.robolectric.res.android.ResourceTypes.ResChunk_header in project robolectric by robolectric.
the class ResXMLTree method setTo.
public int setTo(byte[] data, int size, boolean copyData) {
uninit();
mParser.mEventCode = START_DOCUMENT;
if (!isTruthy(data) || !isTruthy(size)) {
return (mError = BAD_TYPE);
}
if (copyData) {
mOwnedData = new byte[size];
// if (mOwnedData == null) {
// return (mError=NO_MEMORY);
// }
// memcpy(mOwnedData, data, size);
System.arraycopy(data, 0, mOwnedData, 0, size);
data = mOwnedData;
}
mBuffer = new XmlBuffer(data);
mHeader = new ResXMLTree_header(mBuffer.buf, 0);
mSize = dtohl(mHeader.header.size);
if (dtohs(mHeader.header.headerSize) > mSize || mSize > size) {
ALOGW("Bad XML block: header size %d or total size %d is larger than data size %d\n", (int) dtohs(mHeader.header.headerSize), (int) dtohl(mHeader.header.size), (int) size);
mError = BAD_TYPE;
mParser.restart();
return mError;
}
// mDataEnd = ((final uint8_t*)mHeader) + mSize;
mDataLen = mSize;
mStrings.uninit();
mRootNode = null;
mResIds = null;
mNumResIds = 0;
// First look for a couple interesting chunks: the string block
// and first XML node.
ResChunk_header chunk = // (final ResChunk_header*)(((final uint8_t*)mHeader) + dtohs(mHeader.header.headerSize));
new ResChunk_header(mBuffer.buf, mHeader.header.headerSize);
ResChunk_header lastChunk = chunk;
while (chunk.myOffset() < /*((final uint8_t*)chunk)*/
(mDataLen - ResChunk_header.SIZEOF) && chunk.myOffset() < /*((final uint8_t*)chunk)*/
(mDataLen - dtohl(chunk.size))) {
int err = validate_chunk(chunk, ResChunk_header.SIZEOF, /*sizeof(ResChunk_header)*/
mDataLen, "XML");
if (err != NO_ERROR) {
mError = err;
// goto done;
mParser.restart();
return mError;
}
final short type = dtohs(chunk.type);
final int size1 = dtohl(chunk.size);
if (kDebugXMLNoisy) {
// System.out.println(String.format("Scanning @ %s: type=0x%x, size=0x%zx\n",
// (void*)(((uintptr_t)chunk)-((uintptr_t)mHeader)), type, size1);
}
if (type == RES_STRING_POOL_TYPE) {
mStrings.setTo(mBuffer.buf, chunk.myOffset(), size, false);
} else if (type == RES_XML_RESOURCE_MAP_TYPE) {
// mResIds = (final int*)
// (((final uint8_t*)chunk)+dtohs(chunk.headerSize()));
mNumResIds = (dtohl(chunk.size) - dtohs(chunk.headerSize)) / SIZEOF_INT;
mResIds = new int[mNumResIds];
for (int i = 0; i < mNumResIds; i++) {
mResIds[i] = mBuffer.buf.getInt(chunk.myOffset() + chunk.headerSize + i * SIZEOF_INT);
}
} else if (type >= RES_XML_FIRST_CHUNK_TYPE && type <= RES_XML_LAST_CHUNK_TYPE) {
if (validateNode(new ResXMLTree_node(mBuffer.buf, chunk)) != NO_ERROR) {
mError = BAD_TYPE;
// goto done;
mParser.restart();
return mError;
}
mParser.mCurNode = new ResXMLTree_node(mBuffer.buf, lastChunk.myOffset());
if (mParser.nextNode() == BAD_DOCUMENT) {
mError = BAD_TYPE;
// goto done;
mParser.restart();
return mError;
}
mRootNode = mParser.mCurNode;
mRootExt = mParser.mCurExt;
mRootCode = mParser.mEventCode;
break;
} else {
if (kDebugXMLNoisy) {
System.out.println("Skipping unknown chunk!\n");
}
}
lastChunk = chunk;
// chunk = (final ResChunk_header*)
// (((final uint8_t*)chunk) + size1);
chunk = new ResChunk_header(mBuffer.buf, chunk.myOffset() + size1);
}
if (mRootNode == null) {
ALOGW("Bad XML block: no root element node found\n");
mError = BAD_TYPE;
// goto done;
mParser.restart();
return mError;
}
mError = mStrings.getError();
done: mParser.restart();
return mError;
}
Aggregations