/external/android/utils/ResourceTypes.cpp
C++ | 1465 lines | 1210 code | 155 blank | 100 comment | 267 complexity | ed4d28525177b46eef3d1d4b21b5938f MD5 | raw file
- /*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #define LOG_TAG "ResourceType"
- //#define LOG_NDEBUG 0
- #include <utils/Atomic.h>
- #include <utils/ByteOrder.h>
- #include <utils/Debug.h>
- #include <utils/ResourceTypes.h>
- #include <utils/String16.h>
- #include <utils/String8.h>
- #include <utils/TextOutput.h>
- #include <utils/Log.h>
- #include <stdlib.h>
- #include <string.h>
- #include <memory.h>
- #include <ctype.h>
- #include <stdint.h>
- #ifndef INT32_MAX
- #define INT32_MAX ((int32_t)(2147483647))
- #endif
- #define POOL_NOISY(x) //x
- #define XML_NOISY(x) //x
- #define TABLE_NOISY(x) //x
- #define TABLE_GETENTRY(x) //x
- #define TABLE_SUPER_NOISY(x) //x
- #define LOAD_TABLE_NOISY(x) //x
- #define TABLE_THEME(x) //x
- namespace android {
- #ifdef HAVE_WINSOCK
- #undef nhtol
- #undef htonl
- #ifdef HAVE_LITTLE_ENDIAN
- #define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
- #define htonl(x) ntohl(x)
- #define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
- #define htons(x) ntohs(x)
- #else
- #define ntohl(x) (x)
- #define htonl(x) (x)
- #define ntohs(x) (x)
- #define htons(x) (x)
- #endif
- #endif
- #define IDMAP_MAGIC 0x706d6469
- // size measured in sizeof(uint32_t)
- #define IDMAP_HEADER_SIZE (ResTable::IDMAP_HEADER_SIZE_BYTES / sizeof(uint32_t))
- static void printToLogFunc(void* cookie, const char* txt)
- {
- LOGV("%s", txt);
- }
- // Standard C isspace() is only required to look at the low byte of its input, so
- // produces incorrect results for UTF-16 characters. For safety's sake, assume that
- // any high-byte UTF-16 code point is not whitespace.
- inline int isspace16(char16_t c) {
- return (c < 0x0080 && isspace(c));
- }
- // range checked; guaranteed to NUL-terminate within the stated number of available slots
- // NOTE: if this truncates the dst string due to running out of space, no attempt is
- // made to avoid splitting surrogate pairs.
- static void strcpy16_dtoh(uint16_t* dst, const uint16_t* src, size_t avail)
- {
- uint16_t* last = dst + avail - 1;
- while (*src && (dst < last)) {
- char16_t s = dtohs(*src);
- *dst++ = s;
- src++;
- }
- *dst = 0;
- }
- static status_t validate_chunk(const ResChunk_header* chunk,
- size_t minSize,
- const uint8_t* dataEnd,
- const char* name)
- {
- const uint16_t headerSize = dtohs(chunk->headerSize);
- const uint32_t size = dtohl(chunk->size);
- if (headerSize >= minSize) {
- if (headerSize <= size) {
- if (((headerSize|size)&0x3) == 0) {
- if ((ssize_t)size <= (dataEnd-((const uint8_t*)chunk))) {
- return NO_ERROR;
- }
- LOGW("%s data size %p extends beyond resource end %p.",
- name, (void*)size,
- (void*)(dataEnd-((const uint8_t*)chunk)));
- return BAD_TYPE;
- }
- LOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.",
- name, (int)size, (int)headerSize);
- return BAD_TYPE;
- }
- LOGW("%s size %p is smaller than header size %p.",
- name, (void*)size, (void*)(int)headerSize);
- return BAD_TYPE;
- }
- LOGW("%s header size %p is too small.",
- name, (void*)(int)headerSize);
- return BAD_TYPE;
- }
- inline void Res_value::copyFrom_dtoh(const Res_value& src)
- {
- size = dtohs(src.size);
- res0 = src.res0;
- dataType = src.dataType;
- data = dtohl(src.data);
- }
- void Res_png_9patch::deviceToFile()
- {
- for (int i = 0; i < numXDivs; i++) {
- xDivs[i] = htonl(xDivs[i]);
- }
- for (int i = 0; i < numYDivs; i++) {
- yDivs[i] = htonl(yDivs[i]);
- }
- paddingLeft = htonl(paddingLeft);
- paddingRight = htonl(paddingRight);
- paddingTop = htonl(paddingTop);
- paddingBottom = htonl(paddingBottom);
- for (int i=0; i<numColors; i++) {
- colors[i] = htonl(colors[i]);
- }
- }
- void Res_png_9patch::fileToDevice()
- {
- for (int i = 0; i < numXDivs; i++) {
- xDivs[i] = ntohl(xDivs[i]);
- }
- for (int i = 0; i < numYDivs; i++) {
- yDivs[i] = ntohl(yDivs[i]);
- }
- paddingLeft = ntohl(paddingLeft);
- paddingRight = ntohl(paddingRight);
- paddingTop = ntohl(paddingTop);
- paddingBottom = ntohl(paddingBottom);
- for (int i=0; i<numColors; i++) {
- colors[i] = ntohl(colors[i]);
- }
- }
- size_t Res_png_9patch::serializedSize()
- {
- // The size of this struct is 32 bytes on the 32-bit target system
- // 4 * int8_t
- // 4 * int32_t
- // 3 * pointer
- return 32
- + numXDivs * sizeof(int32_t)
- + numYDivs * sizeof(int32_t)
- + numColors * sizeof(uint32_t);
- }
- void* Res_png_9patch::serialize()
- {
- // Use calloc since we're going to leave a few holes in the data
- // and want this to run cleanly under valgrind
- void* newData = calloc(1, serializedSize());
- serialize(newData);
- return newData;
- }
- void Res_png_9patch::serialize(void * outData)
- {
- char* data = (char*) outData;
- memmove(data, &wasDeserialized, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors
- memmove(data + 12, &paddingLeft, 16); // copy paddingXXXX
- data += 32;
- memmove(data, this->xDivs, numXDivs * sizeof(int32_t));
- data += numXDivs * sizeof(int32_t);
- memmove(data, this->yDivs, numYDivs * sizeof(int32_t));
- data += numYDivs * sizeof(int32_t);
- memmove(data, this->colors, numColors * sizeof(uint32_t));
- }
- static void deserializeInternal(const void* inData, Res_png_9patch* outData) {
- char* patch = (char*) inData;
- if (inData != outData) {
- memmove(&outData->wasDeserialized, patch, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors
- memmove(&outData->paddingLeft, patch + 12, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors
- }
- outData->wasDeserialized = true;
- char* data = (char*)outData;
- data += sizeof(Res_png_9patch);
- outData->xDivs = (int32_t*) data;
- data += outData->numXDivs * sizeof(int32_t);
- outData->yDivs = (int32_t*) data;
- data += outData->numYDivs * sizeof(int32_t);
- outData->colors = (uint32_t*) data;
- }
- static bool assertIdmapHeader(const uint32_t* map, size_t sizeBytes)
- {
- if (sizeBytes < ResTable::IDMAP_HEADER_SIZE_BYTES) {
- LOGW("idmap assertion failed: size=%d bytes\n", sizeBytes);
- return false;
- }
- if (*map != htodl(IDMAP_MAGIC)) { // htodl: map data expected to be in correct endianess
- LOGW("idmap assertion failed: invalid magic found (is 0x%08x, expected 0x%08x)\n",
- *map, htodl(IDMAP_MAGIC));
- return false;
- }
- return true;
- }
- static status_t idmapLookup(const uint32_t* map, size_t sizeBytes, uint32_t key, uint32_t* outValue)
- {
- // see README for details on the format of map
- if (!assertIdmapHeader(map, sizeBytes)) {
- return UNKNOWN_ERROR;
- }
- map = map + IDMAP_HEADER_SIZE; // skip ahead to data segment
- // size of data block, in uint32_t
- const size_t size = (sizeBytes - ResTable::IDMAP_HEADER_SIZE_BYTES) / sizeof(uint32_t);
- const uint32_t type = Res_GETTYPE(key) + 1; // add one, idmap stores "public" type id
- const uint32_t entry = Res_GETENTRY(key);
- const uint32_t typeCount = *map;
- if (type > typeCount) {
- LOGW("Resource ID map: type=%d exceeds number of types=%d\n", type, typeCount);
- return UNKNOWN_ERROR;
- }
- if (typeCount > size) {
- LOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, size);
- return UNKNOWN_ERROR;
- }
- const uint32_t typeOffset = map[type];
- if (typeOffset == 0) {
- *outValue = 0;
- return NO_ERROR;
- }
- if (typeOffset + 1 > size) {
- LOGW("Resource ID map: type offset=%d exceeds reasonable value, size of map=%d\n",
- typeOffset, size);
- return UNKNOWN_ERROR;
- }
- const uint32_t entryCount = map[typeOffset];
- const uint32_t entryOffset = map[typeOffset + 1];
- if (entryCount == 0 || entry < entryOffset || entry - entryOffset > entryCount - 1) {
- *outValue = 0;
- return NO_ERROR;
- }
- const uint32_t index = typeOffset + 2 + entry - entryOffset;
- if (index > size) {
- LOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, size);
- *outValue = 0;
- return NO_ERROR;
- }
- *outValue = map[index];
- return NO_ERROR;
- }
- static status_t getIdmapPackageId(const uint32_t* map, size_t mapSize, uint32_t *outId)
- {
- if (!assertIdmapHeader(map, mapSize)) {
- return UNKNOWN_ERROR;
- }
- const uint32_t* p = map + IDMAP_HEADER_SIZE + 1;
- while (*p == 0) {
- ++p;
- }
- *outId = (map[*p + IDMAP_HEADER_SIZE + 2] >> 24) & 0x000000ff;
- return NO_ERROR;
- }
- Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
- {
- if (sizeof(void*) != sizeof(int32_t)) {
- LOGE("Cannot deserialize on non 32-bit system\n");
- return NULL;
- }
- deserializeInternal(inData, (Res_png_9patch*) inData);
- return (Res_png_9patch*) inData;
- }
- // --------------------------------------------------------------------
- // --------------------------------------------------------------------
- // --------------------------------------------------------------------
- ResStringPool::ResStringPool()
- : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL)
- {
- }
- ResStringPool::ResStringPool(const void* data, size_t size, bool copyData)
- : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL)
- {
- setTo(data, size, copyData);
- }
- ResStringPool::~ResStringPool()
- {
- uninit();
- }
- status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
- {
- if (!data || !size) {
- return (mError=BAD_TYPE);
- }
- uninit();
- const bool notDeviceEndian = htods(0xf0) != 0xf0;
- if (copyData || notDeviceEndian) {
- mOwnedData = malloc(size);
- if (mOwnedData == NULL) {
- return (mError=NO_MEMORY);
- }
- memcpy(mOwnedData, data, size);
- data = mOwnedData;
- }
- mHeader = (const ResStringPool_header*)data;
- if (notDeviceEndian) {
- ResStringPool_header* h = const_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) {
- LOGW("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 = (const uint32_t*)
- (((const uint8_t*)data)+mHeader->header.headerSize);
- if (mHeader->stringCount > 0) {
- if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount) // uint32 overflow?
- || (mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t)))
- > size) {
- LOGW("Bad string block: entry of %d items extends past data size %d\n",
- (int)(mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))),
- (int)size);
- return (mError=BAD_TYPE);
- }
- size_t charSize;
- if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
- charSize = sizeof(uint8_t);
- mCache = (char16_t**)malloc(sizeof(char16_t**)*mHeader->stringCount);
- memset(mCache, 0, sizeof(char16_t**)*mHeader->stringCount);
- } else {
- charSize = sizeof(char16_t);
- }
- mStrings = (const void*)
- (((const uint8_t*)data)+mHeader->stringsStart);
- if (mHeader->stringsStart >= (mHeader->header.size-sizeof(uint16_t))) {
- LOGW("Bad string block: string pool starts at %d, after total size %d\n",
- (int)mHeader->stringsStart, (int)mHeader->header.size);
- return (mError=BAD_TYPE);
- }
- if (mHeader->styleCount == 0) {
- mStringPoolSize =
- (mHeader->header.size-mHeader->stringsStart)/charSize;
- } else {
- // check invariant: styles starts before end of data
- if (mHeader->stylesStart >= (mHeader->header.size-sizeof(uint16_t))) {
- LOGW("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) {
- LOGW("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) {
- LOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader->stringCount);
- return (mError=BAD_TYPE);
- }
- if (notDeviceEndian) {
- size_t i;
- uint32_t* e = const_cast<uint32_t*>(mEntries);
- for (i=0; i<mHeader->stringCount; i++) {
- e[i] = dtohl(mEntries[i]);
- }
- if (!(mHeader->flags&ResStringPool_header::UTF8_FLAG)) {
- const char16_t* strings = (const char16_t*)mStrings;
- char16_t* s = const_cast<char16_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 &&
- ((char16_t*)mStrings)[mStringPoolSize-1] != 0)) {
- LOGW("Bad string block: last string is not 0-terminated\n");
- return (mError=BAD_TYPE);
- }
- } else {
- mStrings = NULL;
- mStringPoolSize = 0;
- }
- if (mHeader->styleCount > 0) {
- mEntryStyles = mEntries + mHeader->stringCount;
- // invariant: integer overflow in calculating mEntryStyles
- if (mEntryStyles < mEntries) {
- LOGW("Bad string block: integer overflow finding styles\n");
- return (mError=BAD_TYPE);
- }
- if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
- LOGW("Bad string block: entry of %d styles extends past data size %d\n",
- (int)((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader),
- (int)size);
- return (mError=BAD_TYPE);
- }
- mStyles = (const uint32_t*)
- (((const uint8_t*)data)+mHeader->stylesStart);
- if (mHeader->stylesStart >= mHeader->header.size) {
- LOGW("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 = const_cast<uint32_t*>(mEntryStyles);
- for (i=0; i<mHeader->styleCount; i++) {
- e[i] = dtohl(mEntryStyles[i]);
- }
- uint32_t* s = const_cast<uint32_t*>(mStyles);
- for (i=0; i<mStylePoolSize; i++) {
- s[i] = dtohl(mStyles[i]);
- }
- }
- const 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) {
- LOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
- return (mError=BAD_TYPE);
- }
- } else {
- mEntryStyles = NULL;
- mStyles = NULL;
- mStylePoolSize = 0;
- }
- return (mError=NO_ERROR);
- }
- status_t ResStringPool::getError() const
- {
- return mError;
- }
- void ResStringPool::uninit()
- {
- mError = NO_INIT;
- if (mOwnedData) {
- free(mOwnedData);
- mOwnedData = NULL;
- }
- if (mHeader != NULL && mCache != NULL) {
- for (size_t x = 0; x < mHeader->stringCount; x++) {
- if (mCache[x] != NULL) {
- free(mCache[x]);
- mCache[x] = NULL;
- }
- }
- free(mCache);
- mCache = NULL;
- }
- }
- /**
- * Strings in UTF-16 format have length indicated by a length encoded in the
- * stored data. It is either 1 or 2 characters of length data. This allows a
- * maximum length of 0x7FFFFFF (2147483647 bytes), but if you're storing that
- * much data in a string, you're abusing them.
- *
- * If the high bit is set, then there are two characters or 4 bytes of length
- * data encoded. In that case, drop the high bit of the first character and
- * add it together with the next character.
- */
- static inline size_t
- decodeLength(const char16_t** str)
- {
- size_t len = **str;
- if ((len & 0x8000) != 0) {
- (*str)++;
- len = ((len & 0x7FFF) << 16) | **str;
- }
- (*str)++;
- return len;
- }
- /**
- * Strings in UTF-8 format have length indicated by a length encoded in the
- * stored data. It is either 1 or 2 characters of length data. This allows a
- * maximum length of 0x7FFF (32767 bytes), but you should consider storing
- * text in another way if you're using that much data in a single string.
- *
- * If the high bit is set, then there are two characters or 2 bytes of length
- * data encoded. In that case, drop the high bit of the first character and
- * add it together with the next character.
- */
- static inline size_t
- decodeLength(const uint8_t** str)
- {
- size_t len = **str;
- if ((len & 0x80) != 0) {
- (*str)++;
- len = ((len & 0x7F) << 8) | **str;
- }
- (*str)++;
- return len;
- }
- const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
- {
- if (mError == NO_ERROR && idx < mHeader->stringCount) {
- const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
- const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t));
- if (off < (mStringPoolSize-1)) {
- if (!isUTF8) {
- const char16_t* strings = (char16_t*)mStrings;
- const char16_t* str = strings+off;
- *u16len = decodeLength(&str);
- if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) {
- return str;
- } else {
- LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
- (int)idx, (int)(str+*u16len-strings), (int)mStringPoolSize);
- }
- } else {
- const uint8_t* strings = (uint8_t*)mStrings;
- const uint8_t* u8str = strings+off;
- *u16len = decodeLength(&u8str);
- size_t u8len = decodeLength(&u8str);
- // encLen must be less than 0x7FFF due to encoding.
- if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) {
- AutoMutex lock(mDecodeLock);
- if (mCache[idx] != NULL) {
- return mCache[idx];
- }
- ssize_t actualLen = utf8_to_utf16_length(u8str, u8len);
- if (actualLen < 0 || (size_t)actualLen != *u16len) {
- LOGW("Bad string block: string #%lld decoded length is not correct "
- "%lld vs %llu\n",
- (long long)idx, (long long)actualLen, (long long)*u16len);
- return NULL;
- }
- char16_t *u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t));
- if (!u16str) {
- LOGW("No memory when trying to allocate decode cache for string #%d\n",
- (int)idx);
- return NULL;
- }
- utf8_to_utf16(u8str, u8len, u16str);
- mCache[idx] = u16str;
- return u16str;
- } else {
- LOGW("Bad string block: string #%lld extends to %lld, past end at %lld\n",
- (long long)idx, (long long)(u8str+u8len-strings),
- (long long)mStringPoolSize);
- }
- }
- } else {
- LOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
- (int)idx, (int)(off*sizeof(uint16_t)),
- (int)(mStringPoolSize*sizeof(uint16_t)));
- }
- }
- return NULL;
- }
- const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
- {
- if (mError == NO_ERROR && idx < mHeader->stringCount) {
- const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
- const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t));
- if (off < (mStringPoolSize-1)) {
- if (isUTF8) {
- const uint8_t* strings = (uint8_t*)mStrings;
- const uint8_t* str = strings+off;
- *outLen = decodeLength(&str);
- size_t encLen = decodeLength(&str);
- if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
- return (const char*)str;
- } else {
- LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
- (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
- }
- }
- } else {
- LOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
- (int)idx, (int)(off*sizeof(uint16_t)),
- (int)(mStringPoolSize*sizeof(uint16_t)));
- }
- }
- return NULL;
- }
- const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
- {
- return styleAt(ref.index);
- }
- const ResStringPool_span* ResStringPool::styleAt(size_t idx) const
- {
- if (mError == NO_ERROR && idx < mHeader->styleCount) {
- const uint32_t off = (mEntryStyles[idx]/sizeof(uint32_t));
- if (off < mStylePoolSize) {
- return (const ResStringPool_span*)(mStyles+off);
- } else {
- LOGW("Bad string block: style #%d entry is at %d, past end at %d\n",
- (int)idx, (int)(off*sizeof(uint32_t)),
- (int)(mStylePoolSize*sizeof(uint32_t)));
- }
- }
- return NULL;
- }
- ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
- {
- if (mError != NO_ERROR) {
- return mError;
- }
- size_t len;
- // TODO optimize searching for UTF-8 strings taking into account
- // the cache fill to determine when to convert the searched-for
- // string key to UTF-8.
- if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
- // Do a binary search for the string...
- ssize_t l = 0;
- ssize_t h = mHeader->stringCount-1;
- ssize_t mid;
- while (l <= h) {
- mid = l + (h - l)/2;
- const char16_t* s = stringAt(mid, &len);
- int c = s ? strzcmp16(s, len, str, strLen) : -1;
- POOL_NOISY(printf("Looking for %s, at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
- String8(str).string(),
- String8(s).string(),
- c, (int)l, (int)mid, (int)h));
- if (c == 0) {
- return mid;
- } else if (c < 0) {
- l = mid + 1;
- } else {
- h = mid - 1;
- }
- }
- } else {
- // It is unusual to get the ID from an unsorted string block...
- // most often this happens because we want to get IDs for style
- // span tags; since those always appear at the end of the string
- // block, start searching at the back.
- for (int i=mHeader->stringCount-1; i>=0; i--) {
- const char16_t* s = stringAt(i, &len);
- POOL_NOISY(printf("Looking for %s, at %s, i=%d\n",
- String8(str, strLen).string(),
- String8(s).string(),
- i));
- if (s && strzcmp16(s, len, str, strLen) == 0) {
- return i;
- }
- }
- }
- return NAME_NOT_FOUND;
- }
- size_t ResStringPool::size() const
- {
- return (mError == NO_ERROR) ? mHeader->stringCount : 0;
- }
- #ifndef HAVE_ANDROID_OS
- bool ResStringPool::isUTF8() const
- {
- return (mHeader->flags&ResStringPool_header::UTF8_FLAG)!=0;
- }
- #endif
- // --------------------------------------------------------------------
- // --------------------------------------------------------------------
- // --------------------------------------------------------------------
- ResXMLParser::ResXMLParser(const ResXMLTree& tree)
- : mTree(tree), mEventCode(BAD_DOCUMENT)
- {
- }
- void ResXMLParser::restart()
- {
- mCurNode = NULL;
- mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT;
- }
- const ResStringPool& ResXMLParser::getStrings() const
- {
- return mTree.mStrings;
- }
- ResXMLParser::event_code_t ResXMLParser::getEventType() const
- {
- return mEventCode;
- }
- ResXMLParser::event_code_t ResXMLParser::next()
- {
- if (mEventCode == START_DOCUMENT) {
- mCurNode = mTree.mRootNode;
- mCurExt = mTree.mRootExt;
- return (mEventCode=mTree.mRootCode);
- } else if (mEventCode >= FIRST_CHUNK_CODE) {
- return nextNode();
- }
- return mEventCode;
- }
- int32_t ResXMLParser::getCommentID() const
- {
- return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1;
- }
- const uint16_t* ResXMLParser::getComment(size_t* outLen) const
- {
- int32_t id = getCommentID();
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
- }
- uint32_t ResXMLParser::getLineNumber() const
- {
- return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1;
- }
- int32_t ResXMLParser::getTextID() const
- {
- if (mEventCode == TEXT) {
- return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index);
- }
- return -1;
- }
- const uint16_t* ResXMLParser::getText(size_t* outLen) const
- {
- int32_t id = getTextID();
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
- }
- ssize_t ResXMLParser::getTextValue(Res_value* outValue) const
- {
- if (mEventCode == TEXT) {
- outValue->copyFrom_dtoh(((const ResXMLTree_cdataExt*)mCurExt)->typedData);
- return sizeof(Res_value);
- }
- return BAD_TYPE;
- }
- int32_t ResXMLParser::getNamespacePrefixID() const
- {
- if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
- return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index);
- }
- return -1;
- }
- const uint16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const
- {
- int32_t id = getNamespacePrefixID();
- //printf("prefix=%d event=%p\n", id, mEventCode);
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
- }
- int32_t ResXMLParser::getNamespaceUriID() const
- {
- if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
- return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index);
- }
- return -1;
- }
- const uint16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const
- {
- int32_t id = getNamespaceUriID();
- //printf("uri=%d event=%p\n", id, mEventCode);
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
- }
- int32_t ResXMLParser::getElementNamespaceID() const
- {
- if (mEventCode == START_TAG) {
- return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index);
- }
- if (mEventCode == END_TAG) {
- return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->ns.index);
- }
- return -1;
- }
- const uint16_t* ResXMLParser::getElementNamespace(size_t* outLen) const
- {
- int32_t id = getElementNamespaceID();
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
- }
- int32_t ResXMLParser::getElementNameID() const
- {
- if (mEventCode == START_TAG) {
- return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index);
- }
- if (mEventCode == END_TAG) {
- return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->name.index);
- }
- return -1;
- }
- const uint16_t* ResXMLParser::getElementName(size_t* outLen) const
- {
- int32_t id = getElementNameID();
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
- }
- size_t ResXMLParser::getAttributeCount() const
- {
- if (mEventCode == START_TAG) {
- return dtohs(((const ResXMLTree_attrExt*)mCurExt)->attributeCount);
- }
- return 0;
- }
- int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
- {
- if (mEventCode == START_TAG) {
- const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
- if (idx < dtohs(tag->attributeCount)) {
- const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
- (((const uint8_t*)tag)
- + dtohs(tag->attributeStart)
- + (dtohs(tag->attributeSize)*idx));
- return dtohl(attr->ns.index);
- }
- }
- return -2;
- }
- const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) const
- {
- int32_t id = getAttributeNamespaceID(idx);
- //printf("attribute namespace=%d idx=%d event=%p\n", id, idx, mEventCode);
- //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id));
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
- }
- int32_t ResXMLParser::getAttributeNameID(size_t idx) const
- {
- if (mEventCode == START_TAG) {
- const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
- if (idx < dtohs(tag->attributeCount)) {
- const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
- (((const uint8_t*)tag)
- + dtohs(tag->attributeStart)
- + (dtohs(tag->attributeSize)*idx));
- return dtohl(attr->name.index);
- }
- }
- return -1;
- }
- const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const
- {
- int32_t id = getAttributeNameID(idx);
- //printf("attribute name=%d idx=%d event=%p\n", id, idx, mEventCode);
- //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id));
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
- }
- uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
- {
- int32_t id = getAttributeNameID(idx);
- if (id >= 0 && (size_t)id < mTree.mNumResIds) {
- return dtohl(mTree.mResIds[id]);
- }
- return 0;
- }
- int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
- {
- if (mEventCode == START_TAG) {
- const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
- if (idx < dtohs(tag->attributeCount)) {
- const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
- (((const uint8_t*)tag)
- + dtohs(tag->attributeStart)
- + (dtohs(tag->attributeSize)*idx));
- return dtohl(attr->rawValue.index);
- }
- }
- return -1;
- }
- const uint16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const
- {
- int32_t id = getAttributeValueStringID(idx);
- //XML_NOISY(printf("getAttributeValue 0x%x=0x%x\n", idx, id));
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
- }
- int32_t ResXMLParser::getAttributeDataType(size_t idx) const
- {
- if (mEventCode == START_TAG) {
- const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
- if (idx < dtohs(tag->attributeCount)) {
- const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
- (((const uint8_t*)tag)
- + dtohs(tag->attributeStart)
- + (dtohs(tag->attributeSize)*idx));
- return attr->typedValue.dataType;
- }
- }
- return Res_value::TYPE_NULL;
- }
- int32_t ResXMLParser::getAttributeData(size_t idx) const
- {
- if (mEventCode == START_TAG) {
- const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
- if (idx < dtohs(tag->attributeCount)) {
- const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
- (((const uint8_t*)tag)
- + dtohs(tag->attributeStart)
- + (dtohs(tag->attributeSize)*idx));
- return dtohl(attr->typedValue.data);
- }
- }
- return 0;
- }
- ssize_t ResXMLParser::getAttributeValue(size_t idx, Res_value* outValue) const
- {
- if (mEventCode == START_TAG) {
- const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
- if (idx < dtohs(tag->attributeCount)) {
- const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
- (((const uint8_t*)tag)
- + dtohs(tag->attributeStart)
- + (dtohs(tag->attributeSize)*idx));
- outValue->copyFrom_dtoh(attr->typedValue);
- return sizeof(Res_value);
- }
- }
- return BAD_TYPE;
- }
- ssize_t ResXMLParser::indexOfAttribute(const char* ns, const char* attr) const
- {
- String16 nsStr(ns != NULL ? ns : "");
- String16 attrStr(attr);
- return indexOfAttribute(ns ? nsStr.string() : NULL, ns ? nsStr.size() : 0,
- attrStr.string(), attrStr.size());
- }
- ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
- const char16_t* attr, size_t attrLen) const
- {
- if (mEventCode == START_TAG) {
- const size_t N = getAttributeCount();
- for (size_t i=0; i<N; i++) {
- size_t curNsLen, curAttrLen;
- const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
- const char16_t* curAttr = getAttributeName(i, &curAttrLen);
- //printf("%d: ns=%p attr=%p curNs=%p curAttr=%p\n",
- // i, ns, attr, curNs, curAttr);
- //printf(" --> attr=%s, curAttr=%s\n",
- // String8(attr).string(), String8(curAttr).string());
- if (attr && curAttr && (strzcmp16(attr, attrLen, curAttr, curAttrLen) == 0)) {
- if (ns == NULL) {
- if (curNs == NULL) return i;
- } else if (curNs != NULL) {
- //printf(" --> ns=%s, curNs=%s\n",
- // String8(ns).string(), String8(curNs).string());
- if (strzcmp16(ns, nsLen, curNs, curNsLen) == 0) return i;
- }
- }
- }
- }
- return NAME_NOT_FOUND;
- }
- ssize_t ResXMLParser::indexOfID() const
- {
- if (mEventCode == START_TAG) {
- const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->idIndex);
- if (idx > 0) return (idx-1);
- }
- return NAME_NOT_FOUND;
- }
- ssize_t ResXMLParser::indexOfClass() const
- {
- if (mEventCode == START_TAG) {
- const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->classIndex);
- if (idx > 0) return (idx-1);
- }
- return NAME_NOT_FOUND;
- }
- ssize_t ResXMLParser::indexOfStyle() const
- {
- if (mEventCode == START_TAG) {
- const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->styleIndex);
- if (idx > 0) return (idx-1);
- }
- return NAME_NOT_FOUND;
- }
- ResXMLParser::event_code_t ResXMLParser::nextNode()
- {
- if (mEventCode < 0) {
- return mEventCode;
- }
- do {
- const ResXMLTree_node* next = (const ResXMLTree_node*)
- (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size));
- //LOGW("Next node: prev=%p, next=%p\n", mCurNode, next);
-
- if (((const uint8_t*)next) >= mTree.mDataEnd) {
- mCurNode = NULL;
- return (mEventCode=END_DOCUMENT);
- }
- if (mTree.validateNode(next) != NO_ERROR) {
- mCurNode = NULL;
- return (mEventCode=BAD_DOCUMENT);
- }
- mCurNode = next;
- const uint16_t headerSize = dtohs(next->header.headerSize);
- const uint32_t totalSize = dtohl(next->header.size);
- mCurExt = ((const uint8_t*)next) + headerSize;
- size_t minExtSize = 0;
- event_code_t eventCode = (event_code_t)dtohs(next->header.type);
- switch ((mEventCode=eventCode)) {
- case RES_XML_START_NAMESPACE_TYPE:
- case RES_XML_END_NAMESPACE_TYPE:
- minExtSize = sizeof(ResXMLTree_namespaceExt);
- break;
- case RES_XML_START_ELEMENT_TYPE:
- minExtSize = sizeof(ResXMLTree_attrExt);
- break;
- case RES_XML_END_ELEMENT_TYPE:
- minExtSize = sizeof(ResXMLTree_endElementExt);
- break;
- case RES_XML_CDATA_TYPE:
- minExtSize = sizeof(ResXMLTree_cdataExt);
- break;
- default:
- LOGW("Unknown XML block: header type %d in node at %d\n",
- (int)dtohs(next->header.type),
- (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)));
- continue;
- }
-
- if ((totalSize-headerSize) < minExtSize) {
- LOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n",
- (int)dtohs(next->header.type),
- (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)),
- (int)(totalSize-headerSize), (int)minExtSize);
- return (mEventCode=BAD_DOCUMENT);
- }
-
- //printf("CurNode=%p, CurExt=%p, headerSize=%d, minExtSize=%d\n",
- // mCurNode, mCurExt, headerSize, minExtSize);
-
- return eventCode;
- } while (true);
- }
- void ResXMLParser::getPosition(ResXMLParser::ResXMLPosition* pos) const
- {
- pos->eventCode = mEventCode;
- pos->curNode = mCurNode;
- pos->curExt = mCurExt;
- }
- void ResXMLParser::setPosition(const ResXMLParser::ResXMLPosition& pos)
- {
- mEventCode = pos.eventCode;
- mCurNode = pos.curNode;
- mCurExt = pos.curExt;
- }
- // --------------------------------------------------------------------
- static volatile int32_t gCount = 0;
- ResXMLTree::ResXMLTree()
- : ResXMLParser(*this)
- , mError(NO_INIT), mOwnedData(NULL)
- {
- //LOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
- restart();
- }
- ResXMLTree::ResXMLTree(const void* data, size_t size, bool copyData)
- : ResXMLParser(*this)
- , mError(NO_INIT), mOwnedData(NULL)
- {
- //LOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
- setTo(data, size, copyData);
- }
- ResXMLTree::~ResXMLTree()
- {
- //LOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1);
- uninit();
- }
- status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
- {
- uninit();
- mEventCode = START_DOCUMENT;
- if (copyData) {
- mOwnedData = malloc(size);
- if (mOwnedData == NULL) {
- return (mError=NO_MEMORY);
- }
- memcpy(mOwnedData, data, size);
- data = mOwnedData;
- }
- mHeader = (const ResXMLTree_header*)data;
- mSize = dtohl(mHeader->header.size);
- if (dtohs(mHeader->header.headerSize) > mSize || mSize > size) {
- LOGW("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;
- restart();
- return mError;
- }
- mDataEnd = ((const uint8_t*)mHeader) + mSize;
- mStrings.uninit();
- mRootNode = NULL;
- mResIds = NULL;
- mNumResIds = 0;
- // First look for a couple interesting chunks: the string block
- // and first XML node.
- const ResChunk_header* chunk =
- (const ResChunk_header*)(((const uint8_t*)mHeader) + dtohs(mHeader->header.headerSize));
- const ResChunk_header* lastChunk = chunk;
- while (((const uint8_t*)chunk) < (mDataEnd-sizeof(ResChunk_header)) &&
- ((const uint8_t*)chunk) < (mDataEnd-dtohl(chunk->size))) {
- status_t err = validate_chunk(chunk, sizeof(ResChunk_header), mDataEnd, "XML");
- if (err != NO_ERROR) {
- mError = err;
- goto done;
- }
- const uint16_t type = dtohs(chunk->type);
- const size_t size = dtohl(chunk->size);
- XML_NOISY(printf("Scanning @ %p: type=0x%x, size=0x%x\n",
- (void*)(((uint32_t)chunk)-((uint32_t)mHeader)), type, size));
- if (type == RES_STRING_POOL_TYPE) {
- mStrings.setTo(chunk, size);
- } else if (type == RES_XML_RESOURCE_MAP_TYPE) {
- mResIds = (const uint32_t*)
- (((const uint8_t*)chunk)+dtohs(chunk->headerSize));
- mNumResIds = (dtohl(chunk->size)-dtohs(chunk->headerSize))/sizeof(uint32_t);
- } else if (type >= RES_XML_FIRST_CHUNK_TYPE
- && type <= RES_XML_LAST_CHUNK_TYPE) {
- if (validateNode((const ResXMLTree_node*)chunk) != NO_ERROR) {
- mError = BAD_TYPE;
- goto done;
- }
- mCurNode = (const ResXMLTree_node*)lastChunk;
- if (nextNode() == BAD_DOCUMENT) {
- mError = BAD_TYPE;
- goto done;
- }
- mRootNode = mCurNode;
- mRootExt = mCurExt;
- mRootCode = mEventCode;
- break;
- } else {
- XML_NOISY(printf("Skipping unknown chunk!\n"));
- }
- lastChunk = chunk;
- chunk = (const ResChunk_header*)
- (((const uint8_t*)chunk) + size);
- }
- if (mRootNode == NULL) {
- LOGW("Bad XML block: no root element node found\n");
- mError = BAD_TYPE;
- goto done;
- }
- mError = mStrings.getError();
- done:
- restart();
- return mError;
- }
- status_t ResXMLTree::getError() const
- {
- return mError;
- }
- void ResXMLTree::uninit()
- {
- mError = NO_INIT;
- mStrings.uninit();
- if (mOwnedData) {
- free(mOwnedData);
- mOwnedData = NULL;
- }
- restart();
- }
- status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const
- {
- const uint16_t eventCode = dtohs(node->header.type);
- status_t err = validate_chunk(
- &node->header, sizeof(ResXMLTree_node),
- mDataEnd, "ResXMLTree_node");
- if (err >= NO_ERROR) {
- // Only perform additional validation on START nodes
- if (eventCode != RES_XML_START_ELEMENT_TYPE) {
- return NO_ERROR;
- }
- const uint16_t headerSize = dtohs(node->header.headerSize);
- const uint32_t size = dtohl(node->header.size);
- const ResXMLTree_attrExt* attrExt = (const ResXMLTree_attrExt*)
- (((const uint8_t*)node) + headerSize);
- // check for sensical values pulled out of the stream so far...
- if ((size >= headerSize + sizeof(ResXMLTree_attrExt))
- && ((void*)attrExt > (void*)node)) {
- const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize))
- * dtohs(attrExt->attributeCount);
- if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) {
- return NO_ERROR;
- }
- LOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
- (unsigned int)(dtohs(attrExt->attributeStart)+attrSize),
- (unsigned int)(size-headerSize));
- }
- else {
- LOGW("Bad XML start block: node header size 0x%x, size 0x%x\n",
- (unsigned int)headerSize, (unsigned int)size);
- }
- return BAD_TYPE;
- }
- return err;
- #if 0
- const bool isStart = dtohs(node->header.type) == RES_XML_START_ELEMENT_TYPE;
- const uint16_t headerSize = dtohs(node->header.headerSize);
- const uint32_t size = dtohl(node->header.size);
- if (headerSize >= (isStart ? sizeof(ResXMLTree_attrNode) : sizeof(ResXMLTree_node))) {
- if (size >= headerSize) {
- if (((const uint8_t*)node) <= (mDataEnd-size)) {
- if (!isStart) {
- return NO_ERROR;
- }
- if ((((size_t)dtohs(node->attributeSize))*dtohs(node->attributeCount))
- <= (size-headerSize)) {
- return NO_ERROR;
- }
- LOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
- ((int)dtohs(node->attributeSize))*dtohs(node->attributeCount),
- (int)(size-headerSize));
- return BAD_TYPE;
- }
- LOGW("Bad XML block: node at 0x%x extends beyond data end 0x%x\n",
- (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), (int)mSize);
- return BAD_TYPE;
- }
- LOGW("Bad XML block: node at 0x%x header size 0x%x smaller than total size 0x%x\n",
- (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
- (int)headerSize, (int)size);
- return BAD_TYPE;
- }
- LOGW("Bad XML block: node at 0x%x header size 0x%x too small\n",
- (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
- (int)headerSize);
- return BAD_TYPE;
- #endif
- }
- // --------------------------------------------------------------------
- // --------------------------------------------------------------------
- // --------------------------------------------------------------------
- struct ResTable::Header
- {
- Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
- resourceIDMap(NULL), resourceIDMapSize(0) { }
- ~Header()
- {
- free(resourceIDMap);
- }
- ResTable* const owner;
- void* ownedData;
- const ResTable_header* header;
- size_t size;
- const uint8_t* dataEnd;
- size_t index;
- void* cookie;
- ResStringPool values;
- uint32_t* resourceIDMap;
- size_t resourceIDMapSize;
- };
- struct ResTable::Type
- {
- Type(const Header* _header, const Package* _package, size_t count)
- : header(_header), package(_package), entryCount(count),
- typeSpec(NULL), typeSpecFlags(NULL) { }
- const Header* const header;
- const Package* const package;
- const size_t entryCount;
- const ResTable_typeSpec* typeSpec;
- const uint32_t* typeSpecFlags;
- Vector<const ResTable_type*> configs;
- };
- struct ResTable::Package
- {
- Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
- : owner(_owner), header(_header), package(_package) { }
- ~Package()
- {
- size_t i = types.size();
- while (i > 0) {
- i--;
- delete types[i];
- }
- }
-
- ResTable* const owner;
- const Header* const header;
- const ResTable_package* const package;
- Vector<Type*> types;
- ResStringPool typeStrings;
- ResStringPool keyStrings;
-
- const Type* getType(size_t idx) const {
- return idx < types.size() ? types[idx] : NULL;
- }
- };
- // A group of objects describing a particular resource package.
- // The first in 'package' is always the root object (from the resource
- // table that defined the package); the ones after are skins on top of it.
- struct ResTable::PackageGroup
- {
- PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id)
- : owner(_owner), name(_name), id(_id), typeCount(0), bags(NULL) { }
- ~PackageGroup() {
- clearBagCache();
- const size_t N = packages.size();
- for (size_t i=0; i<N; i++) {
- Package* pkg = packages[i];
- if (pkg->owner == owner) {
- delete pkg;
- }
- }
- }
- void clearBagCache() {
- if (bags) {
- TABLE_NOISY(printf("bags=%p\n", bags));
- Package* pkg = packages[0];
- TABLE_NOISY(printf("typeCount=%x\n", typeCount));
- for (size_t i=0; i<typeCount; i++) {
- TABLE_NOISY(printf("type=%d\n", i));
- const Type* type = pkg->getType(i);
- if (type != NULL) {
- bag_set** typeBags = bags[i];
- TABLE_NOISY(printf("typeBags=%p\n", typeBags));
- if (typeBags) {
- TABLE_NOISY(printf("type->entryCount=%x\n", type->entryCount));
- const size_t N = type->entryCount;
- for (size_t j=0; j<N; j++) {
- if (typeBags[j] && typeBags[j] != (bag_set*)