in resources/src/main/java/org/robolectric/res/android/ResStringPool.java [112:310]
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);
}
// The data is at least as big as a ResChunk_header, so we can safely validate the other
// header fields.
// `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 (notDeviceEndian) {
// ResStringPool_header h = final_cast<ResStringPool_header*>(mHeader);
// h.header.headerSize = dtohs(mHeader.header.headerSize);
// h.header.type = dtohs(mHeader.header.type);
// h.header.size = dtohl(mHeader.header.size);
// h.stringCount = dtohl(mHeader.stringCount);
// h.styleCount = dtohl(mHeader.styleCount);
// h.flags = dtohl(mHeader.flags);
// h.stringsStart = dtohl(mHeader.stringsStart);
// h.stylesStart = dtohl(mHeader.stylesStart);
// }
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 ((mHeader.stringCount*4 /*sizeof(uint32_t)*/ < mHeader.stringCount) // uint32 overflow?
|| (mHeader.header.headerSize+(mHeader.stringCount*4 /*sizeof(uint32_t)*/))
> size) {
ALOGW("Bad string block: entry of %d items extends past data size %d\n",
(int)(mHeader.header.headerSize+(mHeader.stringCount*4/*sizeof(uint32_t)*/)),
(int)size);
return (mError=BAD_TYPE);
}
int charSize;
if (isTruthy(mHeader.flags & ResStringPool_header.UTF8_FLAG)) {
charSize = 1 /*sizeof(uint8_t)*/;
} else {
charSize = 2 /*sizeof(uint16_t)*/;
}
// There should be at least space for the smallest string
// (2 bytes length, null terminator).
if (mHeader.stringsStart >= (mSize - 2 /*sizeof(uint16_t)*/)) {
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 /*sizeof(uint16_t)*/)) {
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 (notDeviceEndian) {
// int i;
// uint32_t* e = final_cast<uint32_t*>(mEntries);
// for (i=0; i<mHeader.stringCount; i++) {
// e[i] = dtohl(mEntries[i]);
// }
// if (!(mHeader.flags&ResStringPool_header::UTF8_FLAG)) {
// final uint16_t* strings = (final uint16_t*)mStrings;
// uint16_t* s = final_cast<uint16_t*>(strings);
// for (i=0; i<mStringPoolSize; i++) {
// s[i] = dtohs(strings[i]);
// }
// }
// }
// if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
// ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
// (!(mHeader->flags&ResStringPool_header::UTF8_FLAG) &&
// ((uint16_t*)mStrings)[mStringPoolSize-1] != 0)) {
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) /* / sizeof(uint32_t)*/;
// 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 /* / 4 */));
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);
}