use of org.robolectric.res.android.ResourceTypes.ResStringPool_span 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.ResStringPool_span in project robolectric by robolectric.
the class ShadowStringBlock method nativeGetStyle.
@Implementation(minSdk = LOLLIPOP)
protected static int[] nativeGetStyle(long obj, int idx) {
ResStringPool osb = ResStringPool.getNativeObject(obj);
ResStringPool_span spans = osb.styleAt(idx);
if (spans == null) {
return null;
}
ResStringPool_span pos = spans;
int num = 0;
while (pos.name.index != ResStringPool_span.END) {
num++;
// pos++;
pos = new ResStringPool_span(pos.myBuf(), pos.myOffset() + ResStringPool_span.SIZEOF);
}
if (num == 0) {
return null;
}
// jintArray array = env->NewIntArray((num*sizeof(ResStringPool_span))/sizeof(jint));
int[] array = new int[num * ResStringPool_span.SIZEOF / SIZEOF_INT];
if (array == null) {
// NewIntArray already threw OutOfMemoryError.
return null;
}
num = 0;
final int numInts = ResStringPool_span.SIZEOF / SIZEOF_INT;
while (spans.name.index != ResStringPool_span.END) {
// env->SetIntArrayRegion(array,
// num*numInts, numInts,
// (jint*)spans);
setIntArrayRegion(array, num, numInts, spans);
// spans++;
spans = new ResStringPool_span(spans.myBuf(), spans.myOffset() + ResStringPool_span.SIZEOF);
num++;
}
return array;
}
Aggregations